// product-islands.jsx — mounts the REAL Ground Truth product UI into the marketing
// page. The hero is a faithful fork of the shipped Rep Home (rep-home.tsx →
// KPI tiles + 3-column item-list / focus-signal / account-context + recent
// activity), translated from the repo's Tailwind to kit CSS. Uses the real
// Sidebar / Header / primitives and the canonical GT_DATA verbatim.

const { useState: useStatePI } = React;

const PI = window.GT_DATA;
const PI_ACCT = {};
PI.ACCOUNTS.forEach((a) => { PI_ACCT[a.id] = a; });
const noop = () => {};

const CAT_LABEL = { risk: "Risk", upsell: "Upsell", crosssell: "Cross-sell", action: "Action" };
const CAT_VAR = { risk: "--signal-risk", upsell: "--signal-upsell", crosssell: "--signal-crosssell", action: "--signal-action" };
const CAT_PILL = { risk: "pill-risk", upsell: "pill-upsell", crosssell: "pill-crosssell", action: "pill-action" };
const SEV_VAR = { critical: "--severity-critical", high: "--severity-high", medium: "--severity-medium", low: "--severity-low" };
const DOMAINS = { acme: "acme.com", gamma: "gamma.io", beta: "beta-inc.com", epsilon: "epsilonhealth.com", zeta: "zeta-ind.com", kappa: "kappafoods.com" };
const truncate = (t, n) => (t && t.length > n ? t.slice(0, n - 1) + "…" : t || "");

/* ---------------- KPI tile ---------------- */
function KpiTile({ label, value, sub, icon, tone }) {
  return (
    <div className="rhx-kpi">
      <div className="rhx-kpi-top">
        <span className="rhx-kpi-lab">{label}</span>
        <Icon name={icon} size={14} className="rhx-kpi-ic" />
      </div>
      <div className={"rhx-kpi-val num" + (tone === "destructive" ? " dest" : "")}>{value}</div>
      <div className="rhx-kpi-sub">{sub}</div>
    </div>
  );
}

/* ---------------- Left: home item row ---------------- */
function HomeItemRow({ s, active, onClick }) {
  const a = PI_ACCT[s.accountId];
  const ev = truncate(s.why, 48);
  return (
    <button type="button" className={"rhx-item" + (active ? " active" : "")} onClick={onClick}>
      <div className="rhx-item-top">
        <span className="rhx-sev" style={{ background: "var(" + SEV_VAR[s.severity] + ")" }}></span>
        <div className="rhx-item-hl">{s.headline}<sup style={{ color: "var(" + CAT_VAR[s.category] + ")" }}>{CAT_LABEL[s.category]}</sup></div>
      </div>
      <div className="rhx-item-sub">{a.name}{ev ? " · " : ""}<span className="ev">{ev}</span></div>
      {(s.due || s.amount != null) && (
        <div className="rhx-item-bot"><span>{s.due}</span>{s.amount != null && <span className="num">{fmtCurrency(s.amount)}</span>}</div>
      )}
    </button>
  );
}

/* ---------------- Draft email content (per email-type signal) ---------------- */
const DRAFTS = {
  s1: {
    to: "Maria Soto · VP Operations", email: "maria.soto@acme.com", cc: "Diego Ramos · COO",
    subject: "Picking the Q3 RFP back up before renewal",
    body: [
      "Hi Maria,",
      "I wanted to check in before the renewal lands on June 28. We never fully closed the loop on the Q3 RFP, and I want to make sure it's reflected in what you're renewing.",
      "Would 15 minutes this week work? I'll bring a short summary of where things stand so finance has what it needs.",
      "Best,\nJen",
    ],
  },
  s3: {
    to: "Sarah Lin · CFO", email: "sarah.lin@beta-inc.com",
    subject: "A quick path forward on the proposal",
    body: [
      "Hi Sarah,",
      "Following up on the pricing questions from a couple of weeks back — I'd rather work through them directly than let the proposal stall.",
      "Could we grab 20 minutes this week? Happy to bring options that fit the budget you outlined.",
      "Best,\nJen",
    ],
  },
  s4: {
    to: "Daniel Reyes · Head of Ops", email: "daniel.reyes@epsilonhealth.com",
    subject: "Intro for your Marketing team",
    body: [
      "Hi Daniel,",
      "You mentioned Marketing is looking at this too — I'd be glad to set up a short intro and share a one-pager scoped to their use case.",
      "Want me to reach out, or would you rather make the introduction?",
      "Best,\nJen",
    ],
  },
};

/* ---------------- Middle (compose state): AI-drafted email ---------------- */
function DraftComposer({ draft, onSend, onDiscard }) {
  return (
    <div className="rhx-focus rhx-compose">
      <div className="rhx-compose-head">
        <span className="rhx-compose-eyebrow"><Icon name="sparkles" size={13} />AI-drafted email</span>
        <button type="button" className="rhx-compose-x" onClick={onDiscard} aria-label="Discard draft"><Icon name="x" size={14} /></button>
      </div>
      <div className="rhx-compose-fields">
        <div className="rhx-compose-row"><span className="k">To</span><span className="v">{draft.to} <span className="addr">&lt;{draft.email}&gt;</span></span></div>
        {draft.cc && <div className="rhx-compose-row"><span className="k">Cc</span><span className="v">{draft.cc}</span></div>}
        <div className="rhx-compose-row"><span className="k">Subject</span><span className="v subj">{draft.subject}</span></div>
      </div>
      <div className="rhx-compose-body">
        {draft.body.map((p, i) => <p key={i}>{p}</p>)}
      </div>
      <div className="rhx-compose-foot">
        <Button size="sm" onClick={onSend}><Icon name="send" size={13} />Send email</Button>
        <Button size="sm" variant="outline"><Icon name="fileText" size={12} />Edit</Button>
        <Button size="sm" variant="ghost" onClick={onDiscard}><Icon name="x" size={12} />Discard</Button>
      </div>
    </div>
  );
}

/* ---------------- Middle (sent state): confirmation ---------------- */
function SentCard({ s }) {
  return (
    <div className="rhx-focus rhx-sent">
      <div className="rhx-sent-inner">
        <span className="rhx-sent-check"><Icon name="check" size={26} strokeWidth={2.6} /></span>
        <h3 className="rhx-sent-title">Email sent to {s.contact.split(" ")[0]}</h3>
        <p className="rhx-sent-sub">{s.headline} resolved. Ground Truth will watch for a reply and follow up if it goes quiet.</p>
      </div>
    </div>
  );
}

/* ---------------- Middle: focus signal ---------------- */
function HomeFocus({ s, phase = "idle", draft, onDraft, onSend, onDiscard }) {
  const a = PI_ACCT[s.accountId];
  if (phase === "compose" && draft) return <DraftComposer draft={draft} onSend={onSend} onDiscard={onDiscard} />;
  if (phase === "sent") return <SentCard s={s} />;
  return (
    <div className="rhx-focus">
      <div className="rhx-focus-head">
        <div className="rhx-meta">
          <span className={"pill " + CAT_PILL[s.category]}>{CAT_LABEL[s.category]}</span>
          <span className="rhx-due">{s.due}</span>
          <span className="rhx-upd">Updated {s.updated}</span>
        </div>
        <h2 className="rhx-focus-hl">{s.headline}</h2>
        <div className="rhx-focus-acct">
          <span className="rhx-ic"><Icon name="building" size={12} /> {a.name}</span>
          <span>·</span><span>{s.contact}, {s.contactRole}</span>
          <span>·</span><span className="num">{fmtCurrency(s.amount)} · Proposal</span>
        </div>
      </div>
      <div className="rhx-focus-body">
        <div className="rhx-why"><Icon name="sparkles" size={16} /><div className="rhx-why-t">{s.why}</div></div>
        <div>
          <div className="rhx-lbl">Recommended next step</div>
          <p className="rhx-p">{s.recommended}</p>
        </div>
        <div>
          <div className="rhx-lbl">Evidence</div>
          <ul className="rhx-ev">
            {s.evidence.slice(0, 2).map((e, i) => (
              <li key={i}><Icon name={e.ic} size={14} /><span>{e.t}</span></li>
            ))}
          </ul>
        </div>
      </div>
      <div className="rhx-focus-foot">
        <Button size="sm" onClick={draft ? onDraft : undefined}><Icon name={s.verbIcon || "send"} size={13} />{s.verbLabel}</Button>
        <Button size="sm" variant="outline"><Icon name="clock" size={12} />Later</Button>
        <Button size="sm" variant="ghost"><Icon name="x" size={12} />Not relevant</Button>
        <span className="spacer"></span>
        <Button size="sm" variant="ai"><Icon name="sparkles" size={13} />Ask AI</Button>
      </div>
    </div>
  );
}

/* ---------------- Right: account context ---------------- */
const STAKE = [
  { i: "MS", c: "oklch(0.55 0.15 264)" },
  { i: "DR", c: "oklch(0.55 0.17 155)" },
  { i: "JL", c: "oklch(0.55 0.18 245)" },
];
function AccountPanel({ s }) {
  const a = PI_ACCT[s.accountId];
  return (
    <div className="rhx-acct">
      <div className="rhx-acct-top">
        <div className="rhx-avatar">{a.name[0]}</div>
        <div className="rhx-acct-id">
          <div className="rhx-acct-name">{a.name} <Icon name="externalLink" size={12} /></div>
          <div className="rhx-acct-dom">{DOMAINS[a.id]}</div>
        </div>
      </div>
      <div>
        <div className="rhx-lbl">Health</div>
        <div className="rhx-health-row">
          <span className="rhx-hbadge badge-risk">At Risk</span>
          <span className="rhx-health-score num">25</span>
        </div>
        <div className="rhx-health-bar"><i style={{ width: "25%", background: "var(--health-at-risk)" }}></i></div>
      </div>
      <div className="rhx-pred"><Icon name="alertTri" size={14} /><span>Likely to slip without re-engagement this week.</span></div>
      <div>
        <div className="rhx-lbl">Active deal</div>
        <div className="rhx-deal-name">{a.name} renewal</div>
        <div className="rhx-deal-sub"><span className="num">{fmtCurrency(s.amount)}</span> · Proposal · Closes Jun 28</div>
      </div>
      <div>
        <div className="rhx-lbl">Stakeholders</div>
        <div className="rhx-stake">
          {STAKE.map((st, i) => <span key={i} className="rhx-savatar" style={{ background: st.c }}>{st.i}</span>)}
        </div>
      </div>
      <div>
        <div className="rhx-lbl">Last activity</div>
        <div className="rhx-last">Maria Soto replied — "Let me check internally."</div>
        <div className="rhx-last-t">today</div>
      </div>
      <Button size="sm" variant="outline" className="rhx-askai"><Icon name="sparkles" size={12} />Ask AI about {a.name}</Button>
    </div>
  );
}

/* ---------------- Rep Home ---------------- */
function RepHomeBody() {
  const all = PI.SIGNALS;
  const [activeId, setActiveId] = useStatePI("s1");
  const [resolved, setResolved] = useStatePI([]);            // signals removed from the list (demo payoff)
  const [flow, setFlow] = useStatePI({ id: null, phase: "idle" }); // idle | compose | sent
  const [cursor, setCursor] = useStatePI({ x: 0, y: 0, pressed: false, shown: false, glide: false });
  const [clicks, setClicks] = useStatePI(0);
  const rhxRef = React.useRef(null);

  const active = all.find((s) => s.id === activeId) || all[0];
  const listItems = all.filter((s) => !resolved.includes(s.id));
  const remaining = Math.max(0, 6 - resolved.length);
  const phase = flow.id === active.id ? flow.phase : "idle";

  const selectSignal = (id) => { setActiveId(id); setFlow({ id: null, phase: "idle" }); };
  const openDraft = () => setFlow({ id: active.id, phase: "compose" });
  const discard = () => setFlow({ id: null, phase: "idle" });
  const send = () => {
    const id = active.id;
    setFlow({ id, phase: "sent" });
    setResolved([id]);                 // signal leaves the list + counters tick down
    setTimeout(() => {                 // reset to the pristine state so the demo can repeat
      setResolved([]);
      setFlow({ id: null, phase: "idle" });
    }, 2200);
  };

  // Re-fit the shot scaler whenever the demo changes the focus-pane height
  // (compose / sent), so the frame never clips or leaves a gap.
  React.useEffect(() => {
    const t1 = setTimeout(fitAll, 60);
    const t2 = setTimeout(fitAll, 340);
    return () => { clearTimeout(t1); clearTimeout(t2); };
  }, [flow.phase, resolved.length]);

  // Autoplay: a synthetic cursor + cinematic zoom run the Draft email flow on a loop.
  React.useEffect(() => {
    if (typeof window !== "undefined" && window.matchMedia &&
        window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
      return; // respect reduced motion — leave the static idle view, no cursor/zoom
    }
    let cancelled = false;
    const timers = [];
    const placed = { done: false };
    const wait = (ms) => new Promise((res) => { const t = setTimeout(res, ms); timers.push(t); });
    const appEl = () => rhxRef.current && rhxRef.current.closest(".app");
    const aim = (sel) => {
      const root = rhxRef.current; if (!root) return;
      const el = root.querySelector(sel); if (!el) return;
      const a = root.getBoundingClientRect();
      const r = el.getBoundingClientRect();
      const scale = (a.width / root.offsetWidth) || 1;     // total visual scale (fit × zoom)
      const x = (r.left + r.width / 2 - a.left) / scale;
      const y = (r.top + r.height / 2 - a.top) / scale;
      const glide = placed.done; placed.done = true;       // first placement instant, then glides
      setCursor((c) => ({ ...c, shown: true, glide, x, y }));
    };
    const zoomIn = (sel, z) => {
      const root = rhxRef.current, app = appEl(); if (!root || !app) return;
      const el = root.querySelector(sel); if (!el) return;
      const ar = app.getBoundingClientRect();
      const r = el.getBoundingClientRect();
      const S = (ar.width / app.offsetWidth) || 1;         // current fit-scale
      const fx = (r.left + r.width / 2 - ar.left) / S;     // focus-pane center in app layout coords
      const fy = (r.top + r.height / 2 - ar.top) / S;
      const tx = app.offsetWidth / 2 - z * fx;             // translate so the focus pane centers in-frame
      const ty = app.offsetHeight / 2 - z * fy;
      app.style.transform = "translate(" + tx + "px, " + ty + "px) scale(" + z + ")";
    };
    const zoomOut = () => { const app = appEl(); if (app) app.style.transform = ""; };
    const press = async () => {
      setCursor((c) => ({ ...c, pressed: true }));
      setClicks((n) => n + 1);
      await wait(170);
      setCursor((c) => ({ ...c, pressed: false }));
    };
    async function loop() {
      await wait(700);                                 // let the UI mount + scaler fit
      while (!cancelled) {
        setActiveId("s1"); setResolved([]); setFlow({ id: null, phase: "idle" }); zoomOut();
        await wait(220); if (cancelled) return;
        aim(".rhx-item.active");                        // cursor onto the signal card (left)
        await wait(850); if (cancelled) return;
        zoomIn(".rhx-item.active", 1.7);                // push into the left card — "here's the signal"
        await wait(1900); if (cancelled) return;        // read the signal
        zoomOut();                                      // back to full view (card + its detail both visible)
        await wait(1000); if (cancelled) return;
        aim(".rhx-focus-foot .btn");                    // glide to "Draft email" (middle = same signal)
        await wait(1000); if (cancelled) return;
        await press(); if (cancelled) return;
        setFlow({ id: "s1", phase: "compose" });        // composer opens
        await wait(180); if (cancelled) return;
        zoomIn(".rhx-focus", 1.3);                      // push in on the draft
        await wait(2600); if (cancelled) return;        // read the AI-written draft (zoomed)
        aim(".rhx-compose-foot .btn");                  // nudge to "Send email"
        await wait(950); if (cancelled) return;
        await press(); if (cancelled) return;
        setFlow({ id: "s1", phase: "sent" }); setResolved(["s1"]); // sent → signal clears + KPI ticks
        zoomOut();                                      // pull back to reveal the resolution
        await wait(2800); if (cancelled) return;
      }
    }
    loop();
    return () => { cancelled = true; timers.forEach(clearTimeout); zoomOut(); };
  }, []);

  return (
    <div className="rhx" ref={rhxRef}>
      <div className="rhx-greet">
        <div>
          <h1 className="rhx-hi">Good morning, Jen.</h1>
          <p className="rhx-sub">Your moves this week. <span className="fg">{remaining} signals</span> · <span className="due">2 due today</span></p>
        </div>
        <div className="rhx-chips">
          <span className="rhx-chip active">All <b>{remaining}</b></span>
          <span className="rhx-chip purple">Due today <b>2</b></span>
          <span className="rhx-chip">This week <b>5</b></span>
        </div>
      </div>

      <div className="rhx-kpis">
        <KpiTile label="Pipeline" value="$229K" sub="Open deals" icon="trending" />
        <KpiTile label="At Risk" value="$112K" sub="Accounts with risk signals" icon="trending" tone="destructive" />
        <KpiTile label="Signals Due" value={String(remaining)} sub="This week" icon="zap" />
        <KpiTile label="Customer Value in Book" value="$399K" sub="8 accounts" icon="building" />
      </div>

      <div className="rhx-cols">
        <div className="rhx-list">
          {listItems.slice(0, 5).map((s) => (
            <HomeItemRow key={s.id} s={s} active={s.id === active.id} onClick={() => selectSignal(s.id)} />
          ))}
          <a className="rhx-viewall">View all signals <Icon name="arrowRight" size={13} /></a>
        </div>
        <HomeFocus s={active} phase={phase} draft={DRAFTS[active.id]} onDraft={openDraft} onSend={send} onDiscard={discard} />
        <AccountPanel s={active} />
      </div>

      <div className="rhx-cursor" data-shown={cursor.shown ? 1 : 0} data-glide={cursor.glide ? 1 : 0} style={{ left: cursor.x, top: cursor.y }}>
        <svg className="rhx-cursor-arrow" data-pressed={cursor.pressed ? 1 : 0} viewBox="0 0 24 24" width="21" height="21" aria-hidden="true">
          <path d="M5 3 L5 20 L9.6 15.6 L12.4 22 L15.2 20.8 L12.4 14.6 L18.5 14.6 Z" fill="#fff" stroke="rgba(0,0,0,0.45)" strokeWidth="1.2" strokeLinejoin="round" />
        </svg>
      </div>
      {clicks > 0 && <span key={clicks} className="rhx-ripple" style={{ left: cursor.x, top: cursor.y }} />}
    </div>
  );
}

function RepHome() {
  return (
    <div className="app">
      <Sidebar activeView="home" onNavigate={noop} suggestionsCount={3} />
      <div className="main">
        <Header title="Home" chatOpen={false} onChatToggle={noop} onNotifToggle={noop} notifCount={2} />
        <div className="content"><RepHomeBody /></div>
      </div>
    </div>
  );
}

/* ---------------- Champion Gone Silent — expanded real SignalRow (Signals section) ---------------- */
function FocusSignal({ id = "s1" }) {
  const signal = PI.SIGNALS.find((s) => s.id === id);
  const [expanded, setExpanded] = useStatePI(true);
  const [selected, setSelected] = useStatePI(false);
  return (
    <div className="card list-card">
      <SignalRow
        signal={signal}
        account={PI_ACCT[signal.accountId]}
        selected={selected}
        expanded={expanded}
        onToggleSel={() => setSelected((v) => !v)}
        onToggleExp={() => setExpanded((v) => !v)}
        onOpenAccount={noop}
        onAskAI={noop}
        onDismiss={noop}
      />
    </div>
  );
}

/* ---------------- Goals — faithful fork of the real Goals page ----------------
   Two-pane: goal list (GoalCard + status filters) + GoalDetail
   (header, milestone funnel + stats, tabs, Overview strip cards + target rows). */

// Milestone funnel segments (real MILESTONE_COLORS order + tokens)
function FunnelBar({ segments, h = 8 }) {
  const total = segments.reduce((s, x) => s + x.n, 0) || 1;
  return (
    <div className="gl-funnel" style={{ height: h }}>
      {segments.map((s, i) => (
        <span key={i} style={{ width: (s.n / total) * 100 + "%", background: s.c }} title={s.k}></span>
      ))}
    </div>
  );
}

const GOAL_LIST = [
  {
    id: "g1", title: "Recover at-risk renewals", status: "active",
    objective: "Re-engage 12 accounts with stalled renewals before quarter close",
    targets: 12, contacted: 9, response: 42,
    seg: [
      { k: "contacted", n: 4, c: "var(--severity-high, oklch(0.68 0.15 245))" },
      { k: "replied", n: 3, c: "var(--health-growing, oklch(0.72 0.16 158))" },
      { k: "meeting", n: 2, c: "var(--signal-action, oklch(0.80 0.14 78))" },
      { k: "proposal", n: 1, c: "oklch(0.72 0.17 50)" },
      { k: "pending", n: 2, c: "oklch(0.5 0.02 264)" },
    ],
    review: 4,
  },
  {
    id: "g2", title: "Expand into logistics", status: "planning",
    objective: "Open 20 new accounts in freight & logistics this quarter",
    targets: 20, contacted: 3, response: 0,
    seg: [
      { k: "contacted", n: 3, c: "var(--severity-high, oklch(0.68 0.15 245))" },
      { k: "pending", n: 17, c: "oklch(0.5 0.02 264)" },
    ],
    review: 0,
  },
  {
    id: "g3", title: "Win back churned SMBs", status: "active",
    objective: "Reactivate 30 accounts that lapsed in the last 6 months",
    targets: 30, contacted: 22, response: 27,
    seg: [
      { k: "contacted", n: 12, c: "var(--severity-high, oklch(0.68 0.15 245))" },
      { k: "replied", n: 6, c: "var(--health-growing, oklch(0.72 0.16 158))" },
      { k: "won", n: 2, c: "oklch(0.62 0.17 150)" },
      { k: "pending", n: 10, c: "oklch(0.5 0.02 264)" },
    ],
    review: 2,
  },
];

const GOAL_STATUS = {
  active: { label: "Active", icon: "check", cls: "gl-badge-active" },
  planning: { label: "Planning", icon: "sparkles", cls: "gl-badge-plan" },
};

function GoalListCard({ g, selected, onSelect }) {
  const st = GOAL_STATUS[g.status] || GOAL_STATUS.planning;
  return (
    <button className={"gl-card" + (selected ? " sel" : "")} onClick={() => onSelect(g.id)}>
      <div className="gl-card-top">
        <span className="gl-card-title"><Icon name="target" size={14} />{g.title}</span>
        <span className="gl-card-badges">
          <span className={"gl-badge " + st.cls}><Icon name={st.icon} size={10} />{st.label}</span>
          {g.review > 0 && <span className="gl-badge gl-badge-rev">{g.review}</span>}
        </span>
      </div>
      <p className="gl-card-obj">{g.objective}</p>
      <FunnelBar segments={g.seg} />
      <div className="gl-card-stats">
        <span>{g.targets} targets</span><span>{g.contacted} contacted</span>
        {g.contacted > 0 && <span>{g.response}% response</span>}
      </div>
    </button>
  );
}

const FILTERS = ["All", "Active", "Planning", "Paused", "Completed"];

function GoalsBody() {
  const [sel, setSel] = useStatePI("g1");
  const [filter, setFilter] = useStatePI("All");
  const [tab, setTab] = useStatePI("Overview");
  const g = GOAL_LIST.find((x) => x.id === sel) || GOAL_LIST[0];

  const blocked = [
    { acct: "Cedar Health", reason: "Procurement asked for SOC 2 report — needs your sign-off before I can send." },
  ];
  const replies = [
    { acct: "Acme Corp", who: "Maria Soto", txt: "Re: renewal — \"Let's reconnect after the board meeting on the 14th.\"" },
    { acct: "Atlas Freight", who: "Devin Park", txt: "Re: expansion — \"Send the proposal and I'll loop in finance.\"" },
  ];
  const drafts = [
    { acct: "Beta Inc", txt: "Intro email drafted — references their Q3 hiring spike." },
  ];

  return (
    <div className="gl">
      {/* left: goal list */}
      <div className="gl-list">
        <div className="gl-list-head">
          <div className="gl-list-titlerow">
            <span className="gl-list-title"><Icon name="target" size={17} className="muted" />Goals</span>
            <Button size="sm"><Icon name="check" size={13} />New Goal</Button>
          </div>
          <div className="gl-filters">
            {FILTERS.map((f) => (
              <button key={f} className={"gl-filter" + (filter === f ? " on" : "")} onClick={() => setFilter(f)}>{f}</button>
            ))}
          </div>
        </div>
        <div className="gl-list-body">
          {GOAL_LIST.map((x) => <GoalListCard key={x.id} g={x} selected={x.id === sel} onSelect={setSel} />)}
        </div>
      </div>

      {/* right: goal detail */}
      <div className="gl-detail">
        <div className="gl-detail-head">
          <div className="gl-dh-top">
            <div>
              <h2 className="gl-dh-title">{g.title}</h2>
              <p className="gl-dh-obj">{g.objective}</p>
            </div>
            <div className="gl-dh-actions">
              <Button size="sm" variant="outline"><Icon name="message" size={13} />Chat</Button>
              <Button size="sm" variant="outline"><Icon name="check" size={13} />Complete</Button>
              <Button size="sm" variant="ghost" className="gl-danger"><Icon name="x" size={13} />Abandon</Button>
            </div>
          </div>
          <FunnelBar segments={g.seg} />
          <div className="gl-dh-stats">
            <span>{g.targets} targets</span><span>{g.contacted} contacted</span>
            <span>{Math.round(g.targets * g.response / 100)} replied</span>
            <span>{g.response}% response rate</span>
            {g.review > 0 && <span className="gl-attn">{g.review} need attention</span>}
          </div>
          <div className="gl-tabs">
            {["Overview", "Accounts", "Activity", "Strategy"].map((t) => (
              <button key={t} className={"gl-tab" + (tab === t ? " on" : "")} onClick={() => setTab(t)}>
                {t}{t === "Overview" && g.review > 0 && <span className="gl-tab-badge">{g.review}</span>}
              </button>
            ))}
          </div>
        </div>

        <div className="gl-detail-body">
          {/* Overview strip cards */}
          <div className="gl-strips">
            <div className="gl-strip"><span className="gl-strip-bar" style={{ background: "var(--health-growing, oklch(0.72 0.16 158))" }}></span><div className="gl-strip-n">{replies.length}</div><div className="gl-strip-l">💬 Replies to approve</div></div>
            <div className="gl-strip"><span className="gl-strip-bar" style={{ background: "oklch(0.62 0.22 264)" }}></span><div className="gl-strip-n">{drafts.length}</div><div className="gl-strip-l">✉ Outreach drafts to approve</div></div>
            <div className="gl-strip"><span className="gl-strip-bar" style={{ background: "var(--signal-risk, oklch(0.70 0.18 30))" }}></span><div className="gl-strip-n">{blocked.length}</div><div className="gl-strip-l">🚩 Blocked — need a human</div></div>
          </div>

          {/* Replies section */}
          <section className="gl-sec">
            <div className="gl-sec-head"><Icon name="chevronDown" size={15} /><span>↩</span><h3>Replies to approve</h3><span className="gl-sec-n">{replies.length}</span><span className="gl-sec-sub">— AI drafted a reply</span></div>
            <div className="gl-rows">
              {replies.map((r, i) => (
                <div className="gl-row" key={i}>
                  <div className="gl-row-main"><span className="gl-row-acct">{r.acct}</span><p className="gl-row-meta">{r.txt}</p></div>
                  <button className="gl-row-btn prime">Approve &amp; send</button>
                  <button className="gl-row-btn">Edit</button>
                </div>
              ))}
            </div>
          </section>

          {/* Blocked section */}
          <section className="gl-sec">
            <div className="gl-sec-head"><Icon name="chevronDown" size={15} /><span>🚩</span><h3>Blocked — needs you</h3><span className="gl-sec-n">{blocked.length}</span><span className="gl-sec-sub">— here's why · chat opens with full context</span></div>
            <div className="gl-rows">
              {blocked.map((b, i) => (
                <div className="gl-row blocked" key={i}>
                  <div className="gl-row-main"><span className="gl-row-acct">{b.acct}</span><p className="gl-row-meta risk">🚩 {b.reason}</p></div>
                  <button className="gl-row-btn">Resolve</button>
                </div>
              ))}
            </div>
          </section>
        </div>
      </div>
    </div>
  );
}

function GoalsApp() {
  return (
    <div className="app">
      <Sidebar activeView="goals" onNavigate={noop} suggestionsCount={3} />
      <div className="main">
        <Header title="Goals" chatOpen={false} onChatToggle={noop} onNotifToggle={noop} notifCount={2} />
        <div className="content" style={{ padding: 0 }}><GoalsBody /></div>
      </div>
    </div>
  );
}

/* ---------------- shot scaler + mounts ---------------- */
function fitShot(shot) {
  const stage = shot.querySelector(".shot-stage");
  if (!stage) return;
  const dw = +shot.dataset.designWidth || 1320;
  stage.style.width = dw + "px";
  const scale = Math.min(1, shot.clientWidth / dw);
  stage.style.transform = "scale(" + scale + ")";
  shot.style.height = stage.offsetHeight * scale + "px";
}
function fitAll() { document.querySelectorAll(".shot").forEach(fitShot); }

function mount(id, el) {
  const node = document.getElementById(id);
  if (node) ReactDOM.createRoot(node).render(el);
}

mount("island-hero", (
  <div className="shot-stage">
    <div className="frame glow">
      <div className="frame-bar">
        <div className="dots"><i></i><i></i><i></i></div>
        <div className="frame-url"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>ground-truth.ai</div>
      </div>
      <div className="gt-frame" style={{ "--gt-h": "684px" }}><RepHome /></div>
    </div>
  </div>
));
mount("island-signals", <FocusSignal id="s1" />);
mount("island-goals", (
  <div className="shot-stage">
    <div className="frame glow">
      <div className="frame-bar">
        <div className="dots"><i></i><i></i><i></i></div>
        <div className="frame-url"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>ground-truth.ai/goals</div>
      </div>
      <div className="gt-frame" style={{ "--gt-h": "600px" }}><GoalsApp /></div>
    </div>
  </div>
));

setTimeout(fitAll, 60);
setTimeout(fitAll, 300);
setTimeout(fitAll, 900);
if (document.fonts && document.fonts.ready) document.fonts.ready.then(fitAll);
window.addEventListener("resize", fitAll, { passive: true });
if ("ResizeObserver" in window) {
  const ro = new ResizeObserver(fitAll);
  document.querySelectorAll(".shot").forEach((s) => ro.observe(s));
}
