/* global React, SparkyIcons */
const { useState, useEffect, useRef } = React;
const I = window.SparkyIcons;

// ─────────────────────────── shared bits ───────────────────────────
function useClock() {
  const fmt = () => new Date().toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' });
  const [time, setTime] = useState(fmt);
  useEffect(() => {
    const t = setInterval(() => setTime(fmt()), 30000);
    return () => clearInterval(t);
  }, []);
  return time;
}

const StatusBar = ({ dark = false }) => {
  const time = useClock();
  return (
  <React.Fragment>
    <div className={`ios-status ${dark ? "dark" : ""}`}>
      <span>{time}</span>
      <span/>
    </div>
    <div className="ios-island"/>
  </React.Fragment>
  );
};
const HomeBar = ({ dark = false }) => <div className={`ios-home ${dark?"dark":""}`}/>;

const Wave = ({ count = 23, color, style }) => {
  const bars = Array.from({ length: count }, (_, i) => {
    const delay = (i * 0.07) % 0.8;
    const dur = 0.6 + ((i * 0.13) % 0.6);
    return <i key={i} style={{ animationDelay: `${delay}s`, animationDuration: `${dur}s` }}/>;
  });
  return <div className="wave" style={{ color, ...style }}>{bars}</div>;
};

const TabBar = ({ active, onNav, dark = false }) => {
  const tabs = [
    { id: "main", label: "Home", icon: I.IconHome },
    { id: "schedule", label: "Schedule", icon: I.IconCalendar },
    { id: "usage", label: "Usage", icon: I.IconClock },
    { id: "settings", label: "Settings", icon: I.IconSettings },
  ];
  return (
    <div className={`tabbar ${dark?"dark":""}`}>
      {tabs.map(t => {
        const Ic = t.icon;
        return (
          <div key={t.id} className={`tab ${active===t.id?"active":""}`} onClick={()=>onNav(t.id)}>
            <Ic size={22} />
            <span>{t.label}</span>
          </div>
        );
      })}
    </div>
  );
};

// ───────────────────── 1. ONBOARDING (Hero) ─────────────────────
const Onboarding = ({ onNext }) => (
  <div className="screen dark">
    <StatusBar dark />
    <div className="scroll screen-fade" style={{ display: "flex", flexDirection: "column", padding: "80px 28px 40px" }}>
      <div className="row" style={{ marginBottom: 32 }}>
        <I.LoopLogo wordSize={24} tile={40} dark/>
      </div>
      <div style={{ flex: 1, display: "flex", flexDirection: "column", justifyContent: "center", gap: 18 }}>
        <span className="pill dark" style={{ alignSelf: "flex-start" }}><span className="dot pulse" style={{ color: "var(--teal)" }}/>built for ServiceM8</span>
        <h1 className="serif" style={{ fontSize: 56, lineHeight: 1.0, margin: 0, color: "var(--paper)" }}>
          Run your day<br/><em style={{ color: "var(--accent-light)" }}>by voice.</em>
        </h1>
        <p style={{ color: "rgba(255,255,255,0.65)", fontSize: 16, lineHeight: 1.5, margin: 0, maxWidth: 320 }}>
          Quote, dispatch, log time and book customers — hands-free. Connect ServiceM8 in one tap.
        </p>
        <div className="row gap-12" style={{ marginTop: 16 }}>
          <div className="col gap-4">
            <div className="serif" style={{ fontSize: 32, color: "white" }}>20</div>
            <div className="micro" style={{ color: "rgba(255,255,255,0.5)" }}>min free</div>
          </div>
          <div style={{ width: 1, height: 36, background: "rgba(255,255,255,0.15)" }}/>
          <div className="col gap-4">
            <div className="serif" style={{ fontSize: 32, color: "white" }}>0</div>
            <div className="micro" style={{ color: "rgba(255,255,255,0.5)" }}>cards</div>
          </div>
          <div style={{ width: 1, height: 36, background: "rgba(255,255,255,0.15)" }}/>
          <div className="col gap-4">
            <div className="serif" style={{ fontSize: 32, color: "white" }}>1-tap</div>
            <div className="micro" style={{ color: "rgba(255,255,255,0.5)" }}>connect</div>
          </div>
        </div>
      </div>
      <button className="btn accent lg full" onClick={onNext}>
        Start free trial <I.IconArrowRight size={18}/>
      </button>
      <div className="row center" style={{ marginTop: 14, gap: 6, color: "rgba(255,255,255,0.5)", fontSize: 12 }}>
        <I.IconShield size={14}/> SOC 2 · OAuth · no passwords stored
      </div>
    </div>
    <HomeBar dark/>
  </div>
);

// ───────────────────── 2. CONNECT (OAuth) ─────────────────────
const Connect = ({ onNext, onBack, oauthUrl }) => {
  const [stage, setStage] = useState("intro"); // intro → authorizing → done

  const handleAuthorize = () => {
    if (oauthUrl) {
      window.location.href = oauthUrl;
    } else {
      setStage("authorizing");
      setTimeout(() => { setStage("done"); setTimeout(onNext, 600); }, 1500);
    }
  };

  return (
    <div className="screen">
      <StatusBar/>
      <div className="scroll screen-fade" style={{ padding: "70px 24px 30px", display: "flex", flexDirection: "column" }}>
        <div className="row between">
          <button className="btn ghost" style={{ padding: "8px 14px", fontSize: 13 }} onClick={onBack}><I.IconArrowLeft size={16}/></button>
          <div className="micro">Step 1 of 1</div>
          <div style={{ width: 40 }}/>
        </div>
        <div style={{ flex: 1, display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", gap: 22, padding: "20px 0" }}>
          <div className="row gap-12" style={{ alignItems: "center" }}>
            <I.LoopMark size={34} variant="gradient"/>
            <div style={{ display: "flex", gap: 4, color: "var(--accent)" }}>
              {[0,1,2].map(i => <div key={i} style={{ width: 5, height: 5, borderRadius: "50%", background: "currentColor", animation: `dotpulse 1.4s infinite ${i*0.2}s` }}/>)}
            </div>
            <div style={{ width: 56, height: 56, borderRadius: 16, background: "white", border: "1px solid var(--line-2)", display: "grid", placeItems: "center", fontWeight: 700, color: "#1f5fa8", fontSize: 14 }}>SM8</div>
          </div>
          <div className="col" style={{ alignItems: "center", gap: 10, textAlign: "center" }}>
            <h2 className="serif" style={{ fontSize: 30, margin: 0, lineHeight: 1.1, whiteSpace: "nowrap" }}>Connect ServiceM8</h2>
            <p style={{ color: "var(--mute)", fontSize: 14, margin: 0, maxWidth: 280, lineHeight: 1.5 }}>One tap. We'll redirect to ServiceM8 to authorise — takes about 10 seconds.</p>
          </div>
          <div className="card" style={{ width: "100%", padding: 18 }}>
            <div className="micro" style={{ marginBottom: 10 }}>What we'll access</div>
            {[
              [I.IconCalendar, "Read jobs & schedule"],
              [I.IconUser, "Read & manage clients"],
              [I.IconZap, "Create & update jobs"],
              [I.IconChat, "Add notes to jobs"],
            ].map(([Ic, t], i) => (
              <div key={i} className="row gap-10" style={{ padding: "8px 0", fontSize: 14 }}>
                <Ic size={18} color="var(--ink-2)"/>
                <span style={{ flex: 1 }}>{t}</span>
                <I.IconCheck size={16} color="var(--good)"/>
              </div>
            ))}
            <div className="row gap-10" style={{ padding: "8px 0", fontSize: 14, color: "var(--mute)", borderTop: "1px solid var(--line)", marginTop: 4 }}>
              <I.IconShield size={18}/>
              <span style={{ flex: 1 }}>Your payment data is never accessed or stored — billing is handled securely by Stripe</span>
            </div>
          </div>
          <div style={{ fontSize: 11, color: "var(--mute)", textAlign: "center", lineHeight: 1.5, marginTop: 4, padding: "0 4px" }}>
            LoopTradie is an independent add-on and is not affiliated with or endorsed by ServiceM8&#8482;.
          </div>
        </div>
        <button
          className="btn accent lg full"
          disabled={stage === "authorizing"}
          onClick={handleAuthorize}
        >
          {stage === "intro" && <>Authorise with ServiceM8 <I.IconArrowRight size={18}/></>}
          {stage === "authorizing" && <>Connecting…</>}
          {stage === "done" && <><I.IconCheck size={18}/> Connected</>}
        </button>
        <button className="btn ghost full" style={{ marginTop: 10 }}>Use API key instead</button>
      </div>
      <HomeBar/>
    </div>
  );
};

// ───────────────────── 3. MAIN (Voice-first home) ─────────────────────
const Main = ({ isDesktop = false, onNav, onCall, onStartJob, onSuggest, secondsLeft = null, userName, jobsToday, unreadMessages, nextJob = null, checkoutBanner, onDismissBanner, callActive = false, onReturnToCall, tenantTz = null }) => {
  const balanceLoaded = secondsLeft !== null;
  const totalSec = Math.max(0, Math.floor(secondsLeft ?? 0));
  const mins = Math.floor(totalSec / 60);
  const secs = totalSec % 60;
  const greeting = userName ? `Hi, ${userName}` : "Good morning";

  const jobsHeading = (() => {
    if (jobsToday === null && unreadMessages === null)
      return <em style={{ color: "var(--mute)" }}>Loading your day…</em>;
    const jobPart = jobsToday === null ? '' : `${jobsToday} job${jobsToday !== 1 ? 's' : ''} today`;
    if (unreadMessages > 0)
      return <>{jobPart}, <em style={{ color: "var(--accent)" }}>{unreadMessages} unread</em> messages.</>;
    return <>{jobPart || 'No jobs scheduled today'}.</>;
  })();

  return (
    <div className="screen">
      <StatusBar/>
      <div className="scroll screen-fade" style={{ padding: isDesktop ? "40px 40px 40px" : "60px 22px 110px" }}>
        <div style={{ maxWidth: isDesktop ? 660 : "none", margin: "0 auto" }}>
        {callActive && (
          <div onClick={onReturnToCall} style={{ marginBottom: 14, padding: "12px 14px", borderRadius: 12, background: "rgba(26,167,196,0.1)", border: "1px solid rgba(26,167,196,0.35)", display: "flex", alignItems: "center", gap: 10, cursor: "pointer" }}>
            <span className="dot pulse" style={{ color: "var(--accent)", flexShrink: 0 }}/>
            <span style={{ flex: 1, fontSize: 13, color: "var(--accent)", fontWeight: 500 }}>Call in progress — tap to return</span>
            <I.IconChev size={16} color="var(--accent)"/>
          </div>
        )}
        {checkoutBanner === 'success' && (
          <div style={{ marginBottom: 14, padding: "12px 14px", borderRadius: 12, background: "rgba(34,197,94,0.1)", border: "1px solid rgba(34,197,94,0.3)", display: "flex", alignItems: "center", gap: 10 }}>
            <I.IconCheck size={16} color="var(--good)"/>
            <span style={{ flex: 1, fontSize: 13, color: "var(--good)", fontWeight: 500 }}>You're subscribed — your balance has been topped up.</span>
            <button onClick={onDismissBanner} style={{ background: "none", border: "none", cursor: "pointer", color: "var(--mute)", fontSize: 16, padding: 0, lineHeight: 1 }}>×</button>
          </div>
        )}
        <div className="row between" style={{ marginBottom: 18 }}>
          <div className="row gap-8">
            <I.LoopLogo wordSize={19} tile={32}/>
          </div>
          <span className="pill"><I.IconClock size={12}/>{balanceLoaded ? `${mins}:${String(secs).padStart(2,"0")} left` : "…"}</span>
        </div>

        <div style={{ marginBottom: 20 }}>
          <div className="micro" style={{ marginBottom: 4 }}>{greeting}</div>
          <h1 className="serif" style={{ fontSize: 32, margin: 0, lineHeight: 1.1 }}>
            {jobsHeading}
          </h1>
        </div>

        {/* Big mic */}
        <div className="col center" style={{ gap: 16, padding: "16px 0 24px" }}>
          <div className="mic-orb" onClick={balanceLoaded && totalSec > 0 ? onCall : undefined}
               style={{ opacity: balanceLoaded ? 1 : 0.4, cursor: balanceLoaded && totalSec > 0 ? "pointer" : "default" }}>
            <I.IconMicSolid size={64}/>
          </div>
          <div className="col center" style={{ gap: 4 }}>
            <div style={{ fontSize: 15, fontWeight: 500 }}>Tap to talk</div>
            <div className="muted" style={{ fontSize: 12 }}>or try a suggestion below</div>
          </div>
        </div>

        {/* Suggestions */}
        <div className="micro" style={{ marginBottom: 8 }}>Try saying</div>
        <div style={{ display: isDesktop ? "grid" : "flex", gridTemplateColumns: isDesktop ? "1fr 1fr" : undefined, flexDirection: isDesktop ? undefined : "column", gap: isDesktop ? 10 : 8, marginBottom: 22 }}>
          {[
            ["What jobs do I have today?", "📅"],
            ["Create a new job for a leaking tap", "🔧"],
            ["Add a call-out fee to my last job", "💵"],
            ["Mark my current job as completed", "✅"],
          ].map(([t, e], i) => (
            <div key={i} className="card row gap-12" style={{ padding: "12px 14px", cursor: balanceLoaded && totalSec > 0 ? "pointer" : "default", opacity: balanceLoaded && totalSec === 0 ? 0.4 : 1 }}
              onClick={balanceLoaded && totalSec > 0 ? () => onSuggest ? onSuggest(t) : onCall() : undefined}>
              <span style={{ fontSize: 18 }}>{e}</span>
              <span style={{ flex: 1, fontSize: 14 }}>{t}</span>
              <I.IconChev size={16} color="var(--mute-2)"/>
            </div>
          ))}
        </div>

        {/* Up next — only shown when a job is scheduled */}
        {nextJob && (
          <div className="card" style={{ padding: 16 }}>
            {(() => {
              const isCompleted = (nextJob.status || '').toLowerCase() === 'completed';
              const statusLabel = isCompleted ? 'completed'
                : nextJob.minutes_until <= 0 ? 'in progress' : 'en route';
              const timeLabel = isCompleted ? `Up next · ${nextJob.status}`
                : nextJob.minutes_until <= 0 ? 'Up next · in progress'
                : `Up next · ${nextJob.minutes_until} min`;
              return (
                <div className="row between" style={{ marginBottom: 6 }}>
                  <div className="micro">{timeLabel}</div>
                  <span className={`pill${isCompleted ? '' : ' live'}`}>
                    {!isCompleted && <span className="dot pulse"/>}
                    {statusLabel}
                  </span>
                </div>
              );
            })()}
            <div className="serif" style={{ fontSize: 22, lineHeight: 1.2, marginBottom: 4 }}>
              {nextJob.customer_name || "Unknown customer"}{nextJob.job_description ? ` — ${nextJob.job_description}` : ""}
            </div>
            <div className="muted" style={{ fontSize: 13, marginBottom: 12 }}>
              {nextJob.job_address || "No address"}
              {nextJob.start_date ? ` · arrive ${new Date(nextJob.start_date).toLocaleTimeString('en-AU', { hour: 'numeric', minute: '2-digit', timeZone: tenantTz || Intl.DateTimeFormat().resolvedOptions().timeZone })}` : ""}
            </div>
            <div className="row gap-8">
              {(nextJob.status || '').toLowerCase() !== 'completed' && (
                <button className="btn primary" style={{ flex: 1, padding: "10px 14px", fontSize: 13 }} onClick={() => onStartJob && onStartJob(nextJob.job_uuid)}>Start job</button>
              )}
              {nextJob.job_address && (
                <button className="btn ghost" style={{ padding: "10px 14px", fontSize: 13 }}
                  onClick={() => window.open(`https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(nextJob.job_address)}`, '_blank')}>
                  Directions
                </button>
              )}
            </div>
          </div>
        )}
        </div>{/* /max-width wrapper */}
      </div>
      {!isDesktop && <TabBar active="main" onNav={onNav}/>}
      {!isDesktop && <HomeBar/>}
    </div>
  );
};

// ───────────────────── 4. CALL (active voice) — living conversation ─────────────────────
// State-aware orb: listening → thinking → speaking → acting
const STATE_LABEL = { listening: "Listening", thinking: "Thinking", speaking: "Speaking", acting: "Working" };

const StateOrb = ({ state, size = 76 }) => (
  <div className={`orb-c s-${state}`} style={{ width: size, height: size }}>
    {state === "speaking"
      ? <div className="eq">{[0,1,2,3,4].map(i => <i key={i} style={{ animationDelay: `${i*0.12}s` }}/>)}</div>
      : state === "thinking"
      ? <div className="row gap-4">{[0,1,2].map(i => <span key={i} style={{ width: 7, height: 7, borderRadius: "50%", background: "white", animation: `dotpulse 1.2s infinite ${i*0.18}s` }}/>)}</div>
      : <I.IconMicSolid size={size*0.4}/>}
  </div>
);

// Inline action card that fills in live (pending → done)
const ActionCard = ({ kind, status }) => {
  if (kind === "booking") {
    const done = status === "done";
    return (
      <div className={`action-card stream-item ${done ? "done" : "pending"}`} style={{ width: "100%" }}>
        <div className="row between" style={{ marginBottom: 8 }}>
          <span className="micro" style={{ color: "rgba(255,255,255,0.55)" }}>{done ? "Job created" : "Creating job…"}</span>
          {done
            ? <span className="check-pop" style={{ width: 22, height: 22, borderRadius: "50%", background: "var(--good)", display: "grid", placeItems: "center" }}><I.IconCheck size={13} color="white"/></span>
            : <span style={{ width: 18, height: 18, borderRadius: "50%", border: "2px solid rgba(255,255,255,0.2)", borderTopColor: "white", display: "block", animation: "spin 0.9s linear infinite" }}/>}
        </div>
        <div className="row gap-10">
          <div style={{ width: 40, height: 40, borderRadius: 12, background: "rgba(var(--accent-rgb),0.18)", display: "grid", placeItems: "center", flexShrink: 0 }}>
            <I.IconCalendar size={20} color="var(--accent-light)"/>
          </div>
          <div className="grow">
            <div style={{ color: "white", fontWeight: 600, fontSize: 15 }}>Mrs Lee — leaking tap</div>
            <div style={{ color: "rgba(255,255,255,0.55)", fontSize: 12 }}>Thu 2:00 PM · 15 Park St {done && "· #4429"}</div>
          </div>
        </div>
        {done && (
          <React.Fragment>
            <div className="row gap-8" style={{ marginTop: 10, paddingTop: 10, borderTop: "1px solid rgba(255,255,255,0.08)" }}>
              <span style={{ fontSize: 12, color: "var(--good)" }}>✓ SMS sent to client</span>
            </div>
            <div className="row gap-8" style={{ marginTop: 10 }}>
              <button className="btn ghost dark-mode" style={{ flex: 1, fontSize: 12, padding: "9px 12px" }}>Undo</button>
              <button className="btn ghost dark-mode" style={{ flex: 1, fontSize: 12, padding: "9px 12px" }}>View job</button>
            </div>
          </React.Fragment>
        )}
      </div>
    );
  }
  return null;
};

// Self-contained ticking clock — isolated so the call screen's message
// stream doesn't re-render (and restart entrance animations) every second.
const CallTimer = () => {
  const [elapsed, setElapsed] = useState(0);
  useEffect(() => {
    const t = setInterval(() => setElapsed(e => e + 1), 1000);
    return () => clearInterval(t);
  }, []);
  const mm = String(Math.floor(elapsed / 60)).padStart(2, "0");
  const ss = String(elapsed % 60).padStart(2, "0");
  return <span className="pill dark mono">{mm}:{ss}</span>;
};

const Call = ({ isDesktop = false, onEnd, onNav, live = false, stream: extStream = [], callState: extState = "listening", caption: extCaption = "Listening…", onSendText, secondsLeft = 1200, error = null, onDismissError, isMuted = false, onToggleMute }) => {
  const [view, setView] = useState("convo"); // convo | voice | visual | inbound
  const [state, setState] = useState(live ? extState : "listening");
  const [caption, setCaption] = useState(live ? extCaption : "Listening…");
  const [textVal, setTextVal] = useState("");
  const streamRef = useRef(null);
  const textInputRef = useRef(null);

  // Stream comes entirely from parent — typed messages are inserted there too,
  // so chronological order is maintained alongside transcription bubbles.
  const stream = extStream;

  // sync live props into local state
  useEffect(() => {
    if (!live) return;
    setState(extState);
    setCaption(extCaption);
  }, [live, extState, extCaption]);


  // autoscroll stream
  useEffect(() => {
    if (streamRef.current) streamRef.current.scrollTop = streamRef.current.scrollHeight;
  }, [stream, state]);

  const MicOffIcon = ({ size = 20 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <rect x="9" y="2" width="6" height="11" rx="3"/>
      <path d="M5 10v1a7 7 0 0 0 14 0v-1M12 18v3M2 2l20 20"/>
    </svg>
  );

  const Controls = () => (
    <div className="col center gap-8" style={{ marginTop: 14, flexShrink: 0 }}>
      <div className="row gap-10" style={{ justifyContent: "center" }}>
        <button className="btn ghost dark-mode" style={{ padding: 14, borderRadius: "50%", aspectRatio: "1" }} title="Type instead" onClick={() => { setView("convo"); setTimeout(() => textInputRef.current?.focus(), 50); }}><I.IconKeyboard size={20}/></button>
        <button className="btn accent" style={{ padding: 18, borderRadius: "50%", aspectRatio: "1" }} onClick={onEnd} title="End call"><I.IconStop size={22}/></button>
        <button
          onClick={live ? onToggleMute : undefined}
          title={isMuted ? "Unmute" : "Mute mic"}
          style={{
            padding: 14, borderRadius: "50%", aspectRatio: "1", border: "none", cursor: live ? "pointer" : "default",
            background: isMuted ? "rgba(255,80,80,0.25)" : "rgba(255,255,255,0.08)",
            color: isMuted ? "#ff5050" : "rgba(255,255,255,0.7)",
            transition: "background 0.15s, color 0.15s",
          }}
        >
          {isMuted ? <MicOffIcon size={20}/> : <I.IconMic size={20}/>}
        </button>
      </div>
      {isMuted && (
        <div style={{ fontSize: 11, color: "#ff5050", fontWeight: 500, letterSpacing: "0.04em" }}>
          Mic muted — type to send a message
        </div>
      )}
    </div>
  );

  if (error) return (
    <div className="screen dark" style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: "40px 28px" }}>
      <StatusBar dark/>
      <div style={{ width: 56, height: 56, borderRadius: "50%", background: "rgba(255,80,80,0.15)", border: "1px solid rgba(255,80,80,0.3)", display: "grid", placeItems: "center", marginBottom: 20 }}>
        <I.IconX size={24} color="#ff5050"/>
      </div>
      <div className="serif" style={{ color: "var(--paper)", fontSize: 22, marginBottom: 10, textAlign: "center" }}>Couldn't connect</div>
      <div style={{ color: "rgba(255,255,255,0.55)", fontSize: 14, lineHeight: 1.55, textAlign: "center", marginBottom: 32, maxWidth: 280 }}>
        {error}
      </div>
      <button className="btn" style={{ background: "var(--paper)", color: "var(--ink)", padding: "14px 32px" }} onClick={onDismissError}>
        Go back
      </button>
    </div>
  );

  return (
    <div className="screen dark">
      <StatusBar dark/>
      <div className="scroll" style={{ padding: isDesktop ? "28px 32px 28px" : "58px 18px 26px", display: "flex", flexDirection: "column" }}>
        {/* top bar */}
        <div className="row between" style={{ flexShrink: 0 }}>
          <span className="pill dark"><span className="dot pulse" style={{ color: state === "listening" ? "var(--teal)" : "var(--accent-light)" }}/>{STATE_LABEL[state]}</span>
          <CallTimer/>
        </div>

        {/* mode tabs */}
        <div className="row gap-6" style={{ margin: "14px 0 6px", justifyContent: "center", flexWrap: "wrap", flexShrink: 0 }}>
          {[["convo","Conversation"],["voice","Voice"],["visual","Visual"],["inbound","Inbound"]].map(([id, label]) => (
            <button key={id} onClick={() => setView(id)}
              style={{
                background: view === id ? "var(--paper)" : "rgba(255,255,255,0.08)",
                color: view === id ? "var(--ink)" : "rgba(255,255,255,0.7)",
                border: "none", padding: "6px 12px", fontSize: 11, borderRadius: 99, fontFamily: "inherit", fontWeight: 500, cursor: "pointer",
              }}
            >{label}</button>
          ))}
        </div>

        {/* ── CONVERSATION (new default: living stream) ── */}
        {view === "convo" && (
          <div className="col" style={{ flex: 1, minHeight: 420 }}>
            {/* compact orb header + caption */}
            <div className="col center gap-8" style={{ padding: "8px 0 14px", flexShrink: 0 }}>
              <StateOrb state={state}/>
              <div className="row gap-6" style={{ minHeight: 20, padding: "0 10px" }}>
                <span className={state === "listening" ? "caption-live" : ""} style={{ fontSize: 13, color: state === "listening" ? undefined : "rgba(255,255,255,0.7)", textAlign: "center", fontWeight: 500 }}>{caption}</span>
              </div>
            </div>
            {/* stream */}
            <div ref={streamRef} className="col gap-8" style={{ flex: 1, overflowY: "auto", paddingBottom: 4 }}>
              {stream.map((m, i) => m.type === "action"
                ? <ActionCard key={i} kind={m.kind} status={m.status}/>
                : (
                  <div key={i} className={`stream-item ${m.who === "you" ? "" : ""}`} style={{ alignSelf: m.who === "you" ? "flex-end" : "flex-start", maxWidth: "86%" }}>
                    <div style={{ fontSize: 9, letterSpacing: "0.06em", textTransform: "uppercase", color: "rgba(255,255,255,0.4)", marginBottom: 3, textAlign: m.who === "you" ? "right" : "left", padding: "0 4px" }}>{m.who === "you" ? "You" : "Loop"}</div>
                    <div style={{
                      padding: "11px 14px", fontSize: 14, lineHeight: 1.4, borderRadius: 18,
                      background: m.who === "you" ? "var(--accent)" : "var(--bg-soft)",
                      color: "white",
                      borderBottomRightRadius: m.who === "you" ? 5 : 18,
                      borderBottomLeftRadius: m.who === "you" ? 18 : 5,
                    }}>{m.text}</div>
                  </div>
                ))}
            </div>
            {live && onSendText && (
              <div className="row gap-8" style={{ marginTop: 8, flexShrink: 0 }}>
                <input
                  style={{ flex: 1, padding: "10px 14px", fontSize: 14, borderRadius: 12, background: "rgba(255,255,255,0.08)", border: "1px solid rgba(255,255,255,0.18)", color: "white", fontFamily: "inherit", outline: "none" }}
                  placeholder="Type a message…"
                  value={textVal}
                  ref={textInputRef}
                  onChange={e => setTextVal(e.target.value)}
                  onKeyDown={e => {
                    if (e.key === "Enter" && !e.shiftKey && textVal.trim()) {
                      e.preventDefault();
                      onSendText(textVal.trim());
                      setTextVal("");
                    }
                  }}
                />
              </div>
            )}
            <div className="row center" style={{ marginTop: 8, flexShrink: 0 }}>
              <span style={{ fontSize: 11, color: "rgba(255,255,255,0.35)" }}>{live ? `Say "close chat" or "close call" · or tap ⏹ to end` : `Just speak to interrupt · say "close chat" or tap ⏹ to end`}</span>
            </div>
          </div>
        )}

        {/* ── VOICE (big immersive orb) ── */}
        {view === "voice" && (
          <div className="col center" style={{ flex: 1, gap: 24, justifyContent: "center", minHeight: 420 }}>
            <StateOrb state={state} size={200}/>
            <Wave count={28} color="rgba(255,255,255,0.5)"/>
            <div className="serif" style={{ fontSize: 24, color: "white", textAlign: "center", maxWidth: 290, minHeight: 64 }}>
              {(() => { const last = [...stream].reverse().find(s => s.text); return last ? `"${last.text}"` : "Listening…"; })()}
            </div>
          </div>
        )}

        {/* ── VISUAL (live quote draft) ── */}
        {view === "visual" && (
          <div className="col gap-14" style={{ flex: 1, justifyContent: "center", minHeight: 420 }}>
            <div className="row center gap-10">
              <StateOrb state="acting" size={72}/>
              <Wave count={16} color="rgba(255,255,255,0.6)"/>
            </div>
            <div className="micro" style={{ color: "rgba(255,255,255,0.5)", textAlign: "center" }}>Drafting live as you speak</div>
            <div className="card dark" style={{ background: "var(--bg-soft)", color: "white", padding: 18 }}>
              <div className="row between" style={{ marginBottom: 8 }}>
                <span className="micro">Quote · Q-2204 · draft</span>
                <span className="pill" style={{ background: "rgba(var(--accent-rgb),0.15)", color: "var(--accent-light)" }}><span className="dot pulse"/>live</span>
              </div>
              <div className="serif" style={{ fontSize: 22, marginBottom: 10 }}>Wong — kitchen tap</div>
              <div className="col gap-6" style={{ fontSize: 13 }}>
                <div className="row between"><span style={{ opacity: 0.7 }}>Mixer tap (Reece SKU 8821)</span><span>$180</span></div>
                <div className="row between"><span style={{ opacity: 0.7 }}>Labour (2h @ $80)</span><span>$160</span></div>
                <div style={{ height: 1, background: "rgba(255,255,255,0.1)", margin: "4px 0" }}/>
                <div className="row between" style={{ fontWeight: 600 }}><span>Subtotal</span><span>$340</span></div>
              </div>
              <div className="row gap-8" style={{ marginTop: 14 }}>
                <button className="btn ghost dark-mode" style={{ flex: 1, fontSize: 13, padding: "10px 14px" }}>Redo</button>
                <button className="btn accent" style={{ flex: 2, fontSize: 13, padding: "10px 14px" }}>Send to Sarah</button>
              </div>
            </div>
          </div>
        )}

        {/* ── INBOUND (customer-facing) ── */}
        {view === "inbound" && (
          <div className="col gap-12" style={{ flex: 1, justifyContent: "center", minHeight: 420 }}>
            <div className="row between">
              <span className="pill dark"><I.IconPhone size={12}/>Incoming · live</span>
              <span className="pill dark mono">01:34</span>
            </div>
            <div className="card dark" style={{ background: "var(--bg-soft)", color: "white", padding: 16 }}>
              <div className="micro" style={{ color: "rgba(255,255,255,0.5)" }}>Caller — matched to client</div>
              <div className="serif" style={{ fontSize: 22, marginBottom: 4 }}>Tom Henderson</div>
              <div style={{ fontSize: 12, opacity: 0.6 }}>+61 400 123 456 · client since 2021 · 8 jobs</div>
            </div>
            <div className="col gap-6">
              <div className="stream-item" style={{ alignSelf: "flex-start", maxWidth: "86%", padding: "11px 14px", fontSize: 13, borderRadius: 18, borderBottomLeftRadius: 5, background: "rgba(255,255,255,0.06)", color: "white" }}>
                "hot water's been out since this morning"
              </div>
              <div className="stream-item" style={{ alignSelf: "flex-start", maxWidth: "86%", padding: "11px 14px", fontSize: 13, borderRadius: 18, borderBottomLeftRadius: 5, background: "rgba(var(--accent-rgb),0.14)", color: "white", border: "1px solid rgba(var(--accent-rgb),0.3)" }}>
                <div className="micro" style={{ color: "var(--accent-light)", marginBottom: 3 }}>Loop</div>
                Sorry to hear that, Tom. I can get Jamie to you Tuesday at 4 PM — shall I lock it in?
              </div>
            </div>
            <button className="btn accent full"><I.IconPhone size={16}/>Take the call myself</button>
          </div>
        )}

        {live && secondsLeft <= 30 && secondsLeft > 0 && (
          <div style={{ margin: "0 18px 4px", padding: "8px 14px", borderRadius: 12, background: "rgba(255,176,32,0.15)", border: "1px solid rgba(255,176,32,0.35)", textAlign: "center" }}>
            <span style={{ fontSize: 12, color: "#ffb020", fontWeight: 600 }}>
              {secondsLeft}s left — upgrade to keep talking
            </span>
          </div>
        )}
        {Controls()}
      </div>
      {!isDesktop && <HomeBar dark/>}
    </div>
  );
};

// ───────────────────── 5. USAGE ─────────────────────
const Usage = ({ isDesktop = false, onNav, secondsLeft = 0, secondsUsed = 0, planSeconds = 1200, callCount = 0, isTrial = true, onChoosePlan }) => {
  const [loadingPlan, setLoadingPlan] = React.useState(null);

  const balance   = Math.max(0, Math.floor(secondsLeft));
  const total     = planSeconds || 1200;
  // Derive used from plan - balance when seconds_used_total is missing/zero but balance was consumed
  const rawUsed   = Math.max(0, Math.floor(secondsUsed));
  const derived   = Math.max(0, total - balance);
  const used      = rawUsed > 0 ? rawUsed : derived;
  const pct       = Math.min(100, (balance / total) * 100);
  const low       = balance < 60;
  const poolLabel = isTrial ? `Trial · ${Math.floor(total / 60)}-min pool` : `Prepaid · ${Math.floor(total / 60)}-min pool`;
  const subLabel  = isTrial ? 'Free trial — upgrade to keep going' : 'Your prepaid pool';

  const fmtSec = (s) => {
    const mm = Math.floor(s / 60);
    const ss = s % 60;
    return `${mm}:${String(ss).padStart(2, "0")}`;
  };

  const handleChoose = async (planKey) => {
    if (!onChoosePlan || loadingPlan) return;
    setLoadingPlan(planKey);
    try {
      await onChoosePlan(planKey);
    } finally {
      setLoadingPlan(null);
    }
  };

  return (
    <div className="screen">
      <StatusBar/>
      <div className="scroll screen-fade" style={{ padding: isDesktop ? "40px 40px 40px" : "60px 22px 110px" }}>
        <div className="serif" style={{ fontSize: 32, marginBottom: 4 }}>Usage</div>
        <div className="muted" style={{ fontSize: 13, marginBottom: 20 }}>{subLabel}</div>

        <div className="card" style={{ padding: 20, marginBottom: 14, background: "linear-gradient(140deg, #fff, #fff5f1)" }}>
          <div className="micro">{poolLabel}</div>
          <div className="serif" style={{ fontSize: 56, lineHeight: 1, color: low ? "var(--accent)" : "var(--ink)", marginTop: 4 }}>
            {fmtSec(balance)}
          </div>
          <div className="muted" style={{ fontSize: 13, marginTop: 2 }}>seconds left</div>
          <div className="meter accent" style={{ marginTop: 12 }}><i style={{ width: `${pct}%`, background: low ? "var(--accent)" : undefined }}/></div>
          <div className="row between" style={{ marginTop: 6, fontSize: 11, color: "var(--mute)" }}>
            <span>{fmtSec(used)} used</span>
            <span>{fmtSec(total)} total</span>
          </div>
        </div>

        {balance <= 0 && (
          <div className="card" style={{ padding: 14, marginBottom: 14, background: "rgba(var(--accent-rgb),0.06)", border: "1px solid rgba(var(--accent-rgb),0.25)" }}>
            <div style={{ fontWeight: 600, fontSize: 14, color: "var(--accent)" }}>Trial time used up</div>
            <div className="muted" style={{ fontSize: 12, marginTop: 2 }}>Choose a plan below to keep talking to your AI assistant.</div>
          </div>
        )}

        <div className="row gap-10" style={{ marginBottom: 18 }}>
          <div className="card grow" style={{ padding: 14 }}>
            <div className="micro">Voice used</div>
            <div className="serif" style={{ fontSize: 26 }}>{fmtSec(used)}</div>
            <div className="muted" style={{ fontSize: 11 }}>{callCount} call{callCount !== 1 ? 's' : ''}</div>
          </div>
          <div className="card grow" style={{ padding: 14 }}>
            <div className="micro">Remaining</div>
            <div className="serif" style={{ fontSize: 26, color: low ? "var(--accent)" : undefined }}>{fmtSec(balance)}</div>
            <div className="muted" style={{ fontSize: 11 }}>{low ? "running low" : "available"}</div>
          </div>
        </div>

        <div className="micro" style={{ marginBottom: 8 }}>Plans</div>
        <div className="col gap-10">
          {[
            ["starter",  "Starter",  "$29", "50 min · solo operator",           false],
            ["pro",      "Pro",      "$59", "150 min · 1–3 person crew",        true],
            ["business", "Business", "$99", "350 min · multi-truck team",       false],
          ].map(([key, name, price, desc, hot]) => (
            <div key={key} className="card" style={{ padding: 16, border: hot ? "2px solid var(--accent)" : "1px solid var(--line-2)", position: "relative" }}>
              {hot && <span className="pill accent" style={{ position: "absolute", top: -10, right: 14 }}>most popular</span>}
              <div className="row between">
                <div className="serif" style={{ fontSize: 20 }}>{name}</div>
                <div><span className="serif" style={{ fontSize: 22 }}>{price}</span><span className="muted" style={{ fontSize: 12 }}>/mo</span></div>
              </div>
              <div className="muted" style={{ fontSize: 12, marginTop: 4 }}>{desc}</div>
              <button
                className={`btn ${hot ? "accent" : "ghost"} full`}
                style={{ marginTop: 12, padding: "10px 14px", fontSize: 13 }}
                disabled={!!loadingPlan}
                onClick={() => handleChoose(key)}
              >
                {loadingPlan === key ? "Redirecting…" : `Choose ${name}`}
              </button>
            </div>
          ))}
        </div>
      </div>
      {!isDesktop && <TabBar active="usage" onNav={onNav}/>}
      {!isDesktop && <HomeBar/>}
    </div>
  );
};

// ───────────────────── 6. SETTINGS ─────────────────────
const Settings = ({ isDesktop = false, onNav, onSignOut, tenantName, isTrial, secondsLeft }) => (
  <div className="screen">
    <StatusBar/>
    <div className="scroll screen-fade" style={{ padding: isDesktop ? "40px 40px 40px" : "60px 22px 110px" }}>
      <div className="serif" style={{ fontSize: 32, marginBottom: 4 }}>Settings</div>
      <div className="muted" style={{ fontSize: 13, marginBottom: 20 }}>Tune your agent.</div>

      <div className="card" style={{ padding: 16, marginBottom: 18 }}>
        <div className="row gap-12">
          <div style={{ width: 48, height: 48, borderRadius: "50%", background: "var(--grad)", display: "grid", placeItems: "center", color: "white", fontWeight: 600 }}>
            {tenantName ? tenantName.charAt(0).toUpperCase() : "?"}
          </div>
          <div className="grow">
            <div style={{ fontWeight: 600 }}>{tenantName || "Your business"}</div>
            <div className="muted" style={{ fontSize: 12 }}>ServiceM8 account</div>
          </div>
          <I.IconChev size={16} color="var(--mute-2)"/>
        </div>
      </div>

      <div className="micro" style={{ marginBottom: 8 }}>Connection</div>
      <div className="list" style={{ marginBottom: 18 }}>
        <div className="list-row">
          <div className="icon-box" style={{ background: "#1f5fa8" }}><I.IconLink size={16}/></div>
          <div className="grow">
            <div style={{ fontSize: 14, fontWeight: 500 }}>ServiceM8</div>
            <div className="muted" style={{ fontSize: 11 }}>
              <span style={{ color: "var(--good)" }}>● connected</span>
              {tenantName ? ` · ${tenantName}` : ""}
            </div>
          </div>
          <I.IconChev size={16} color="var(--mute-2)"/>
        </div>
      </div>

      <div className="micro" style={{ marginBottom: 8 }}>Voice</div>
      <div className="list" style={{ marginBottom: 18 }}>
        {[
          [I.IconWaveform, "#7c3aed", "Voice",         "Mara (en-AU, female)"],
          [I.IconStar,    "var(--accent)", "Wake word", '"Hey Loop" · off'],
          [I.IconBell,    "var(--good)",   "Notifications", "SMS · push"],
        ].map(([Ic, color, t, sub], i) => (
          <div key={i} className="list-row" style={{ cursor: "default" }}>
            <div className="icon-box" style={{ background: color }}><Ic size={16}/></div>
            <div className="grow">
              <div style={{ fontSize: 14, fontWeight: 500 }}>{t}</div>
              <div className="muted" style={{ fontSize: 11 }}>{sub}</div>
            </div>
            <span style={{ fontSize: 10, color: "var(--mute)", background: "var(--bg-3)", borderRadius: 4, padding: "2px 6px", whiteSpace: "nowrap" }}>Coming soon</span>
          </div>
        ))}
      </div>

      <div className="micro" style={{ marginBottom: 8 }}>Privacy & plan</div>
      <div className="list" style={{ marginBottom: 18 }}>
        <div className="list-row" onClick={() => onNav("privacy")}>
          <div className="icon-box" style={{ background: "var(--ink-2)" }}><I.IconShield size={16}/></div>
          <div className="grow">
            <div style={{ fontSize: 14, fontWeight: 500 }}>Terms & Privacy</div>
            <div className="muted" style={{ fontSize: 11 }}>Terms of use · transcripts kept 30 days</div>
          </div>
          <I.IconChev size={16} color="var(--mute-2)"/>
        </div>
        <div className="list-row" onClick={() => onNav("usage")}>
          <div className="icon-box" style={{ background: "var(--warn)" }}><I.IconClock size={16}/></div>
          <div className="grow">
            <div style={{ fontSize: 14, fontWeight: 500 }}>Plan</div>
            <div className="muted" style={{ fontSize: 11 }}>
              {isTrial
                ? (secondsLeft !== null && secondsLeft <= 0 ? "Trial ended · tap to choose a plan" : "Trial · tap to view plans")
                : "Active plan · tap to manage"}
            </div>
          </div>
          <I.IconChev size={16} color="var(--mute-2)"/>
        </div>
      </div>

      <button className="btn ghost full" style={{ color: "var(--accent)", borderColor: "rgba(var(--accent-rgb),0.3)" }} onClick={onSignOut}>Sign out</button>
      <div className="muted" style={{ fontSize: 11, textAlign: "center", marginTop: 16 }}>Loop v1.0 · made for ServiceM8</div>
    </div>
    {!isDesktop && <TabBar active="settings" onNav={onNav}/>}
    {!isDesktop && <HomeBar/>}
  </div>
);

// ───────────────────── 7. PRIVACY / TERMS ─────────────────────
const Privacy = ({ isDesktop = false, onNav }) => (
  <div className="screen">
    <StatusBar/>
    <div className="scroll screen-fade" style={{ padding: "60px 22px 40px" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 20 }}>
        <button onClick={() => onNav("settings")} style={{ background: "none", border: "none", cursor: "pointer", padding: 0, display: "grid", placeItems: "center" }}>
          <I.IconArrowLeft size={22} color="var(--ink)"/>
        </button>
        <div className="serif" style={{ fontSize: 26 }}>Terms &amp; Privacy</div>
      </div>

      <div style={{ fontSize: 13, color: "var(--mute)", marginBottom: 20 }}>Last updated: June 2026</div>

      <div style={{ fontSize: 14, lineHeight: 1.7, color: "var(--ink-2)" }}>

        <p style={{ fontWeight: 600, color: "var(--ink)", marginBottom: 4 }}>1. Agreement to Terms</p>
        <p style={{ marginBottom: 16 }}>By accessing or using the Looptradie service ("Service"), you agree to be bound by these Terms and Conditions ("Terms"). If you do not agree, you must not use the Service. Continued use of the Service after any changes to these Terms constitutes your acceptance of the revised Terms.</p>

        <p style={{ fontWeight: 600, color: "var(--ink)", marginBottom: 4 }}>2. About the Service</p>
        <p style={{ marginBottom: 16 }}>Looptradie provides an AI-powered voice assistant that connects to your ServiceM8 account to help manage jobs, scheduling, and customer communications. The Service is operated by Looptradie ("we", "us", "our").</p>

        <p style={{ fontWeight: 600, color: "var(--ink)", marginBottom: 4 }}>3. No Professional Advice</p>
        <p style={{ marginBottom: 16 }}>All responses generated by the AI assistant are for informational and operational convenience only. They do not constitute professional, legal, financial, or trade advice. You are solely responsible for verifying any information provided by the AI before acting on it. We make no warranty that the AI's responses are accurate, complete, or suitable for your specific circumstances.</p>

        <p style={{ fontWeight: 600, color: "var(--ink)", marginBottom: 4 }}>4. Limitation of Liability</p>
        <p style={{ marginBottom: 16 }}>To the maximum extent permitted by law, Looptradie and its directors, employees, and agents shall not be liable for any direct, indirect, incidental, special, consequential, or punitive damages arising from: (a) your use of or inability to use the Service; (b) errors, inaccuracies, or omissions in AI-generated content; (c) any action or decision taken in reliance on the Service; or (d) unauthorised access to or use of our servers or any personal information stored therein.</p>

        <p style={{ fontWeight: 600, color: "var(--ink)", marginBottom: 4 }}>5. ServiceM8 Data</p>
        <p style={{ marginBottom: 16 }}>Looptradie accesses your ServiceM8 account data solely on your behalf and only to the extent necessary to operate the Service. We do not sell your data to third parties. Voice transcripts are retained for up to 30 days to enable session review, after which they are permanently deleted.</p>

        <p style={{ fontWeight: 600, color: "var(--ink)", marginBottom: 4 }}>6. Accuracy of AI Responses</p>
        <p style={{ marginBottom: 16 }}>The AI assistant may occasionally produce incorrect, outdated, or incomplete information. You acknowledge that AI technology has inherent limitations and agree not to rely solely on the Service for critical business decisions. Always confirm important details directly within ServiceM8 or with the relevant parties.</p>

        <p style={{ fontWeight: 600, color: "var(--ink)", marginBottom: 4 }}>7. Acceptable Use</p>
        <p style={{ marginBottom: 16 }}>You agree not to use the Service for any unlawful purpose, to harass or harm others, to transmit malicious code, or to attempt to gain unauthorised access to any systems. We reserve the right to suspend or terminate your access immediately for breach of these Terms.</p>

        <p style={{ fontWeight: 600, color: "var(--ink)", marginBottom: 4 }}>8. Service Availability &amp; Suspension</p>
        <p style={{ marginBottom: 16 }}>We do not guarantee uninterrupted availability of the Service. Access may be suspended or terminated at any time for non-payment, misuse, or maintenance. We will endeavour to provide reasonable notice where practicable.</p>

        <p style={{ fontWeight: 600, color: "var(--ink)", marginBottom: 4 }}>9. Intellectual Property</p>
        <p style={{ marginBottom: 16 }}>All intellectual property in the Looptradie Service, including software, design, and content (excluding your ServiceM8 data), remains the property of Looptradie. Nothing in these Terms grants you any rights in that intellectual property.</p>

        <p style={{ fontWeight: 600, color: "var(--ink)", marginBottom: 4 }}>10. Changes to the Service</p>
        <p style={{ marginBottom: 16 }}>We may modify, suspend, or discontinue any part of the Service at any time. We may also update these Terms at any time. Continued use of the Service after changes are posted constitutes acceptance of the updated Terms.</p>

        <p style={{ fontWeight: 600, color: "var(--ink)", marginBottom: 4 }}>11. Governing Law</p>
        <p style={{ marginBottom: 16 }}>These Terms are governed by the laws of Australia. Any disputes arising from these Terms or your use of the Service shall be subject to the exclusive jurisdiction of the courts of Australia.</p>

        <p style={{ fontWeight: 600, color: "var(--ink)", marginBottom: 4 }}>12. Contact</p>
        <p style={{ marginBottom: 32 }}>For questions about these Terms, contact us at <span style={{ color: "var(--accent)" }}>support@looptradie.com</span>.</p>

        <div style={{ padding: "14px 16px", borderRadius: 12, background: "rgba(26,167,196,0.07)", border: "1px solid rgba(26,167,196,0.2)", fontSize: 12, color: "var(--mute)", lineHeight: 1.6 }}>
          By using Looptradie, you acknowledge that you have read, understood, and agree to be bound by these Terms and Conditions.
        </div>
      </div>

      <button className="btn ghost full" style={{ marginTop: 28 }} onClick={() => onNav("settings")}>Back to Settings</button>
    </div>
  </div>
);

// ───────────────────── 7. TIME EXPIRED ─────────────────────
const TimeExpired = ({ onNav }) => (
  <div className="screen dark" style={{ background: "var(--bg-deep)" }}>
    <StatusBar dark/>
    <div className="col center" style={{ flex: 1, padding: "0 28px", gap: 20, textAlign: "center" }}>
      <div style={{ width: 72, height: 72, borderRadius: "50%", background: "rgba(255,176,32,0.15)", border: "1px solid rgba(255,176,32,0.3)", display: "grid", placeItems: "center" }}>
        <I.IconClock size={32} color="#ffb020"/>
      </div>
      <div>
        <div className="serif" style={{ fontSize: 28, color: "white", marginBottom: 6 }}>Time's up</div>
        <div style={{ fontSize: 14, color: "rgba(255,255,255,0.55)", lineHeight: 1.5, maxWidth: 280 }}>
          Your free trial has ended. Choose a plan to keep using your AI assistant.
        </div>
      </div>
      <button className="btn accent full" style={{ padding: "14px 20px", fontSize: 15 }} onClick={() => onNav("usage")}>
        View Plans
      </button>
      <button className="btn ghost" style={{ color: "rgba(255,255,255,0.5)", borderColor: "rgba(255,255,255,0.12)", padding: "12px 20px", fontSize: 14, width: "100%" }} onClick={() => onNav("main")}>
        Back to home
      </button>
    </div>
    <HomeBar dark/>
  </div>
);

// ───────────────────── SCHEDULE ─────────────────────
const Schedule = ({ isDesktop = false, onNav, schedule = [], tenantTz = null }) => {
  const tz      = tenantTz || Intl.DateTimeFormat().resolvedOptions().timeZone;
  const today    = new Date().toLocaleDateString('en-CA', { timeZone: tz });
  const tomorrow = new Date(Date.now() + 86400000).toLocaleDateString('en-CA', { timeZone: tz });

  const dayLabel = (dateStr) => {
    if (dateStr === today)    return "Today";
    if (dateStr === tomorrow) return "Tomorrow";
    return new Date(dateStr + 'T12:00:00').toLocaleDateString('en-AU', { weekday: 'short', day: 'numeric', month: 'short' });
  };

  const grouped = schedule.reduce((acc, item) => {
    const key = item.date || (item.start_date || '').slice(0, 10);
    if (!acc[key]) acc[key] = [];
    acc[key].push(item);
    return acc;
  }, {});

  const sortedDates = Object.keys(grouped).sort();

  return (
    <div className="screen">
      <StatusBar/>
      <div className="scroll screen-fade" style={{ padding: isDesktop ? "40px 40px 40px" : "60px 22px 110px" }}>
        <div className="serif" style={{ fontSize: 32, marginBottom: 4 }}>Schedule</div>
        <div className="muted" style={{ fontSize: 13, marginBottom: 20 }}>Next 7 days.</div>

        {sortedDates.length === 0 && (
          <div className="muted" style={{ textAlign: "center", paddingTop: 60, fontSize: 14 }}>
            No jobs scheduled in the next 7 days.
          </div>
        )}

        {sortedDates.map(dateKey => (
          <div key={dateKey} style={{ marginBottom: 20 }}>
            <div className="micro" style={{ marginBottom: 8 }}>{dayLabel(dateKey)}</div>
            <div className="col gap-8">
              {grouped[dateKey].map((item, i) => {
                const startTime = item.start_date
                  ? new Date(item.start_date).toLocaleTimeString('en-AU', { hour: 'numeric', minute: '2-digit', timeZone: tz })
                  : null;
                const endTime = item.end_date
                  ? new Date(item.end_date).toLocaleTimeString('en-AU', { hour: 'numeric', minute: '2-digit', timeZone: tz })
                  : null;
                return (
                  <div key={i} className="card" style={{ padding: 14 }}>
                    <div className="row between" style={{ marginBottom: 4 }}>
                      <div style={{ fontSize: 12, color: "var(--accent)", fontWeight: 600 }}>
                        {startTime}{endTime ? ` – ${endTime}` : ""}
                      </div>
                      {item.status && <span className="pill">{item.status}</span>}
                    </div>
                    <div style={{ fontSize: 15, fontWeight: 600, marginBottom: 2 }}>
                      {item.customer_name || "Unknown"}{item.job_description ? ` — ${item.job_description}` : ""}
                    </div>
                    <div className="muted" style={{ fontSize: 12 }}>{item.job_address || "No address"}</div>
                  </div>
                );
              })}
            </div>
          </div>
        ))}
      </div>
      {!isDesktop && <TabBar active="schedule" onNav={onNav}/>}
      {!isDesktop && <HomeBar/>}
    </div>
  );
};

// ───────────────────── DESKTOP COMPONENTS ─────────────────────

const DesktopNav = ({ screen, onNav, userName, tenantName }) => {
  const tabs = [
    { id:"main",     label:"Home",     Icon:I.IconHome },
    { id:"schedule", label:"Schedule", Icon:I.IconCalendar },
    { id:"usage",    label:"Usage",    Icon:I.IconClock },
    { id:"settings", label:"Settings", Icon:I.IconSettings },
  ];
  return (
    <div className="dnav">
      <div className="dnav-logo"><I.LoopLogo wordSize={20} tile={36} dark/></div>
      <div className="dnav-items">
        {tabs.map(({ id, label, Icon }) => (
          <div key={id} className={`dnav-item ${screen===id?"active":""}`} onClick={() => onNav(id)}>
            <Icon size={20} color="currentColor"/>
            <span>{label}</span>
          </div>
        ))}
      </div>
      <div className="dnav-footer">
        <strong>{tenantName || "Your business"}</strong>
        <span>{userName ? `Hi, ${userName}` : "ServiceM8 account"}</span>
      </div>
    </div>
  );
};

const DesktopSchedulePanel = ({ schedule = [], nextJob, onNav, tenantTz = null }) => {
  const tz = tenantTz || Intl.DateTimeFormat().resolvedOptions().timeZone;
  const today = new Date().toLocaleDateString('en-CA', { timeZone: tz });
  const todayJobs = schedule.filter(j => (j.date || (j.start_date||'').slice(0,10)) === today);
  return (
    <div>
      <div className="micro" style={{ marginBottom: 16 }}>Today's schedule</div>
      {nextJob && (
        <div className="card" style={{ marginBottom:12, padding:14,
          background:"rgba(26,167,196,0.06)", border:"1px solid rgba(26,167,196,0.2)" }}>
          <div className="micro" style={{ color:"var(--accent)", marginBottom:4 }}>
            {nextJob.minutes_until<=0 ? "In progress" : `In ${nextJob.minutes_until} min`}
          </div>
          <div style={{ fontSize:14, fontWeight:600, marginBottom:2 }}>
            {nextJob.customer_name}{nextJob.job_description?` — ${nextJob.job_description}`:""}
          </div>
          <div className="muted" style={{ fontSize:12 }}>{nextJob.job_address}</div>
        </div>
      )}
      {todayJobs.length === 0 && !nextJob
        ? <div className="muted" style={{ fontSize:13, paddingTop:8 }}>No jobs scheduled today.</div>
        : todayJobs.map((item, i) => {
          const t = item.start_date
            ? new Date(item.start_date).toLocaleTimeString('en-AU', { hour: 'numeric', minute: '2-digit', timeZone: tz })
            : null;
          return (
            <div key={i} className="card" style={{ marginBottom:8, padding:12 }}>
              {t && <div style={{ fontSize:11, color:"var(--accent)", fontWeight:600, marginBottom:2 }}>{t}</div>}
              <div style={{ fontSize:13, fontWeight:600 }}>{item.customer_name}</div>
              <div className="muted" style={{ fontSize:12 }}>{item.job_description||item.job_address}</div>
            </div>
          );
        })
      }
      <button className="btn ghost full" style={{ marginTop:14, fontSize:13 }}
        onClick={() => onNav('schedule')}>Full schedule →</button>
    </div>
  );
};

const DesktopTranscriptPanel = ({ stream = [] }) => {
  const ref = useRef(null);
  useEffect(() => { if (ref.current) ref.current.scrollTop = ref.current.scrollHeight; }, [stream]);
  return (
    <div style={{ height:"100%", display:"flex", flexDirection:"column" }}>
      <div className="micro" style={{ marginBottom:16 }}>Live transcript</div>
      <div ref={ref} style={{ flex:1, overflowY:"auto", display:"flex", flexDirection:"column", gap:12 }}>
        {stream.filter(m=>m.text).map((m,i) => (
          <div key={i}>
            <div style={{ fontSize:10, textTransform:"uppercase", letterSpacing:"0.06em",
              color: m.who==="you" ? "var(--accent)" : "var(--mute)", marginBottom:2 }}>
              {m.who==="you" ? "You" : "Loop"}
            </div>
            <div style={{ fontSize:13, lineHeight:1.5, color:"var(--ink)" }}>{m.text}</div>
          </div>
        ))}
        {stream.length === 0 && (
          <div className="muted" style={{ fontSize:13 }}>Transcript will appear here once the call starts.</div>
        )}
      </div>
    </div>
  );
};

window.SparkyScreens = { Onboarding, Connect, Main, Call, Usage, Settings, Privacy, TimeExpired, Schedule, DesktopNav, DesktopSchedulePanel, DesktopTranscriptPanel };
