// JARVIS v3 — all page components

// ── FinancesPage ─────────────────────────────────────────────────────────────
function FinancesPage({ navigate }) {
  const D = window.JARVIS_DATA;
  const [tab, setTab] = React.useState("overview");
  return (
    <div className="main-inner">
      <div className="page-head">
        <div>
          <div className="eyebrow">PORTFOLIO · {(D.metrics || {}).accounts || 38} LINKED ACCOUNTS · MAY {new Date().getDate()}</div>
          <h1>Finances</h1>
        </div>
        <div className="actions">
          <SyncButton
            label="Plaid"
            sources={[
              { id: "plaid-accounts", label: "Plaid · Accounts linked", status: "ok" },
              { id: "plaid-tx", label: "Plaid · Transactions", status: "ok" }
            ]}
            defaultLastSyncMin={4}
          />
          <div className="seg">
            {["overview","assets","liabilities","cashflow"].map(k => (
              <button key={k} className={tab === k ? "active" : ""} onClick={() => setTab(k)}>
                {k[0].toUpperCase()+k.slice(1)}
              </button>
            ))}
          </div>
        </div>
      </div>
      {tab === "overview"    && <FinancesOverview />}
      {tab === "assets"      && <FinancesAssets />}
      {tab === "liabilities" && <FinancesLiabilities />}
      {tab === "cashflow"    && <FinancesCashflow />}
    </div>
  );
}

function FinancesOverview() {
  const D = window.JARVIS_DATA;
  const m = D.metrics || {};
  return (
    <>
      <div className="kpi-strip finance-kpis" style={{gridTemplateColumns: "repeat(4, 1fr)"}}>
        <div className="kpi"><div className="lbl">Net worth</div><div className={"val" + (m.netWorth < 0 ? " neg" : "")}>{fmtMoneyFull(m.netWorth || 0)}</div><div className="sub neg">−$320 · 30d</div></div>
        <div className="kpi"><div className="lbl">Total assets</div><div className="val">{fmtMoneyFull(m.assets || 0)}</div><div className="sub pos">+$2,140 · 30d</div></div>
        <div className="kpi"><div className="lbl">Total liabilities</div><div className="val">{fmtMoneyFull(m.liab || 0)}</div><div className="sub pos">−$1,820 · 30d</div></div>
        <div className="kpi"><div className="lbl">Cash runway</div><div className="val">{(m.cashRunwayMo || 0).toFixed(1)} mo</div><div className="sub">at $18.6k / mo burn</div></div>
      </div>

      <div className="finance-overview-grid" style={{display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12}}>
        <div className="card">
          <div className="card-h">
            <div className="left">
              <div className="eyebrow">Cash flow · trailing 8 mo</div>
              <div className="title">Income vs expense</div>
            </div>
            <div className="right"><span className="pill green">+$14.9k net 12mo</span></div>
          </div>
          <div className="card-b">
            <CashFlowChart data={D.cashflow || []} />
            <div style={{display: "flex", gap: 16, marginTop: 8, fontSize: 11, color: "var(--fg-soft)", fontFamily: "var(--font-mono)"}}>
              <span><span style={{display: "inline-block", width: 10, height: 10, background: "oklch(0.62 0.15 145)", verticalAlign: "middle", marginRight: 6}}/>In</span>
              <span><span style={{display: "inline-block", width: 10, height: 10, background: "#1c1c20", verticalAlign: "middle", marginRight: 6}}/>Out</span>
            </div>
          </div>
        </div>

        <div className="card">
          <div className="card-h">
            <div className="left">
              <div className="eyebrow">Liabilities · {fmtMoneyFull(m.liab || 0)}</div>
              <div className="title">Debt stack</div>
            </div>
            <div className="right"><span className="pill amber">AVALANCHE · CC FIRST</span></div>
          </div>
          <div className="card-b">
            <div style={{marginBottom: 12}}>
              <StackedBar segments={(D.liabilities || []).map(l => ({label: l.name, value: l.bal, color: l.color}))} h={8} />
            </div>
            <table className="tbl">
              <thead><tr><th>Liability</th><th className="num">Balance</th><th className="num">Rate</th><th className="num">Share</th></tr></thead>
              <tbody>
                {(D.liabilities || []).map(l => (
                  <tr key={l.name}>
                    <td><span className="dot" style={{background: l.color, marginRight: 8}}/>{l.name}</td>
                    <td className="num">${l.bal.toLocaleString()}</td>
                    <td className="num">{l.rate.toFixed(2)}%</td>
                    <td className="num">{l.share}%</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      </div>

      <div className="finance-secondary-grid" style={{display: "grid", gridTemplateColumns: "1.6fr 1fr", gap: 12, marginTop: 12}}>
        <div className="card">
          <div className="card-h">
            <div className="left">
              <div className="eyebrow">Assets · {(D.assetsList || []).length} accounts</div>
              <div className="title">Holdings — {fmtMoney(m.assets || 0)}</div>
            </div>
            <div className="right"><span className="pill green">YTD +5.4%</span></div>
          </div>
          <div className="card-b flush">
            <table className="tbl">
              <thead><tr><th>Account</th><th>Institution</th><th className="num">Balance</th><th className="num">Alloc</th><th className="num">YTD</th></tr></thead>
              <tbody>
                {(D.assetsList || []).slice(0, 10).map(a => (
                  <tr key={a.name}>
                    <td>{a.name}</td>
                    <td><span className="sub">{a.inst}</span></td>
                    <td className="num">${a.bal.toLocaleString()}</td>
                    <td className="num">{a.alloc.toFixed(1)}%</td>
                    <td className="num" style={{color: a.ytd > 0 ? "oklch(0.5 0.14 145)" : a.ytd < 0 ? "var(--red)" : "var(--fg-soft)"}}>{a.ytd > 0 ? "+" : ""}{a.ytd.toFixed(1)}%</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>

        <div className="card">
          <div className="card-h">
            <div className="left">
              <div className="eyebrow">Credit-card payoff · Dec 2026</div>
              <div className="title">Glide path on track</div>
            </div>
            <div className="right"><span className="pill green">$486 AHEAD</span></div>
          </div>
          <div className="card-b">
            <div style={{display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: 10, marginBottom: 12}}>
              <Kpi tiny lbl="Balance" val={fmtMoneyFull(m.cc || 0)} />
              <Kpi tiny lbl="Req / wk" val="$701" />
              <Kpi tiny lbl="APR" val={(m.ccApr || 0).toFixed(1) + "%"} />
              <Kpi tiny lbl="Days left" val="227" />
            </div>
            <CCPayoffMini />
          </div>
        </div>
      </div>
    </>
  );
}

function FinancesAssets() {
  const D = window.JARVIS_DATA;
  return (
    <div className="card">
      <div className="card-h">
        <div className="left">
          <div className="eyebrow">All holdings · {(D.assetsList || []).length}</div>
          <div className="title">Asset register — {fmtMoneyFull((D.metrics || {}).assets || 0)}</div>
        </div>
        <div className="right">
          <span className="pill green">YTD +5.4%</span>
          <span className="pill">+$2,140 · 30d</span>
        </div>
      </div>
      <div className="card-b flush">
        <table className="tbl">
          <thead><tr><th>Account</th><th>Institution</th><th>Type</th><th className="num">Balance</th><th className="num">Alloc</th><th className="num">YTD</th></tr></thead>
          <tbody>
            {(D.assetsList || []).map(a => (
              <tr key={a.name}>
                <td style={{fontWeight: 500}}>{a.name}</td>
                <td><span className="sub">{a.inst}</span></td>
                <td><span className="sub">{a.inst && a.inst.includes("Fidelity") ? "Retirement" : a.name && a.name.includes("Audi") ? "Vehicle" : a.name && a.name.includes("Residence") ? "Real estate" : "Cash"}</span></td>
                <td className="num">${a.bal.toLocaleString()}</td>
                <td className="num">{a.alloc.toFixed(1)}%</td>
                <td className="num" style={{color: a.ytd > 0 ? "oklch(0.5 0.14 145)" : a.ytd < 0 ? "var(--red)" : "var(--fg-soft)"}}>{a.ytd > 0 ? "+" : ""}{a.ytd.toFixed(1)}%</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

function FinancesLiabilities() {
  const D = window.JARVIS_DATA;
  return (
    <>
      <div className="card">
        <div className="card-h">
          <div className="left">
            <div className="eyebrow">Outstanding · {(D.liabilities || []).length} categories</div>
            <div className="title">Debt portfolio — {fmtMoneyFull((D.metrics || {}).liab || 0)}</div>
          </div>
          <div className="right"><span className="pill amber">AVALANCHE · CC FIRST</span></div>
        </div>
        <div className="card-b">
          <StackedBar segments={(D.liabilities || []).map(l => ({label: l.name, value: l.bal, color: l.color}))} h={12} />
          <table className="tbl" style={{marginTop: 14}}>
            <thead><tr><th>Liability</th><th className="num">Balance</th><th className="num">Rate</th><th className="num">Share</th><th className="num">Priority</th></tr></thead>
            <tbody>
              {(D.liabilities || []).map((l, i) => (
                <tr key={l.name}>
                  <td><span className="dot" style={{background: l.color, marginRight: 8}}/>{l.name}</td>
                  <td className="num">${l.bal.toLocaleString()}</td>
                  <td className="num" style={{color: l.rate > 10 ? "var(--red)" : "var(--fg)"}}>{l.rate.toFixed(2)}%</td>
                  <td className="num">{l.share}%</td>
                  <td className="num">{l.rate > 10 ? <span className="pill red">P1</span> : <span className="pill">P{i+2}</span>}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
      <div className="card" style={{marginTop: 12}}>
        <div className="card-h">
          <div className="left">
            <div className="eyebrow">Credit-card payoff · projected Dec 2026</div>
            <div className="title">{fmtMoneyFull((D.metrics || {}).cc || 0)} → $0 in 227 days</div>
          </div>
          <div className="right">
            <span className="pill green">$486 AHEAD</span>
            <span className="pill amber">{(D.metrics || {}).ccApr || 0}% APR</span>
          </div>
        </div>
        <div className="card-b">
          <div style={{display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 10, marginBottom: 14}}>
            <Kpi tiny lbl="Current balance" val={fmtMoneyFull((D.metrics || {}).cc || 0)} />
            <Kpi tiny lbl="Ahead of plan" val="$486" />
            <Kpi tiny lbl="Req / month" val="$3,247" />
            <Kpi tiny lbl="Req / week" val="$701" />
          </div>
          <CCPayoffMini />
        </div>
      </div>
    </>
  );
}

function FinancesCashflow() {
  const D = window.JARVIS_DATA;
  return (
    <>
      <div className="kpi-strip" style={{gridTemplateColumns: "repeat(3, 1fr)"}}>
        <div className="kpi"><div className="lbl">Inflow · 12mo</div><div className="val">$229,000</div><div className="sub">$19.1k / mo avg</div></div>
        <div className="kpi"><div className="lbl">Outflow · 12mo</div><div className="val">$214,100</div><div className="sub">$17.8k / mo avg</div></div>
        <div className="kpi"><div className="lbl">Net</div><div className="val pos">+$14,900</div><div className="sub pos">trailing 12mo</div></div>
      </div>
      <div className="card">
        <div className="card-h">
          <div className="left">
            <div className="eyebrow">Cash flow · last 8 months</div>
            <div className="title">Income vs expense</div>
          </div>
        </div>
        <div className="card-b">
          <CashFlowChart data={D.cashflow || []} />
        </div>
      </div>
      <div className="card" style={{marginTop: 12}}>
        <div className="card-h">
          <div className="left">
            <div className="eyebrow">Recent transactions · today</div>
            <div className="title">Live activity</div>
          </div>
          <div className="right"><span className="pill green">LIVE</span></div>
        </div>
        <div className="card-b flush">
          {(D.activity || []).map(a => (
            <div className="act-row" key={a.id}>
              <div className="time">{a.time}</div>
              <div className="body">{a.text}</div>
              <div className={"amt " + a.level}>{a.amt}</div>
            </div>
          ))}
        </div>
      </div>
    </>
  );
}

// ── AcademicsPage ─────────────────────────────────────────────────────────────
function AcademicsPage({ navigate }) {
  const D = window.JARVIS_DATA;
  const m = D.metrics || {};
  return (
    <div className="main-inner">
      <div className="page-head">
        <div>
          <div className="eyebrow">PENN STATE · M.S. ARTIFICIAL INTELLIGENCE · BETWEEN TERMS</div>
          <h1>Academic load</h1>
        </div>
        <div className="actions">
          <SyncButton
            label="Canvas"
            sources={[{ id: "canvas", label: "Penn State · Canvas LMS", status: "ok" }]}
            defaultLastSyncMin={12}
          />
          <span className="pill green">GPA {(m.gpa || 0).toFixed(2)}</span>
          <span className="pill">FALL 26 · 2 UPCOMING</span>
        </div>
      </div>

      <div className="kpi-strip" style={{gridTemplateColumns: "repeat(4, 1fr)"}}>
        <div className="kpi"><div className="lbl">GPA</div><div className="val">{(m.gpa || 0).toFixed(2)}</div><div className="sub pos">+0.04 · 30d</div></div>
        <div className="kpi"><div className="lbl">Passed</div><div className="val">{(D.courses || []).filter(c => c.status === "passed").length} / {(D.courses || []).length}</div><div className="sub pos">all A or A−</div></div>
        <div className="kpi"><div className="lbl">Remaining credits</div><div className="val">6</div><div className="sub">to graduation</div></div>
        <div className="kpi"><div className="lbl">Next milestone</div><div className="val">Jun 2</div><div className="sub">Fall 26 enrollment opens</div></div>
      </div>

      <div style={{display: "grid", gridTemplateColumns: "1.5fr 1fr", gap: 12}}>
        <div className="card">
          <div className="card-h">
            <div className="left">
              <div className="eyebrow">Term · {(D.courses || []).length} courses</div>
              <div className="title">Course progress</div>
            </div>
            <div className="right">
              <span className="pill green">{(D.courses || []).filter(c => c.status === "passed").length} PASSED</span>
              <span className="pill">{(D.courses || []).filter(c => c.status === "not-started" || c.status === "scheduled").length} UPCOMING</span>
            </div>
          </div>
          <div className="card-b flush">
            <table className="tbl">
              <thead><tr><th>Code</th><th>Course</th><th style={{width: 200}}>Progress</th><th>Grade</th><th>Status</th></tr></thead>
              <tbody>
                {(D.courses || []).map(c => (
                  <tr key={c.code}>
                    <td className="mono" style={{fontWeight: 500}}>{c.code}</td>
                    <td>{c.name}</td>
                    <td>
                      <div style={{display: "flex", alignItems: "center", gap: 8}}>
                        <Progress value={c.progress} color={c.progress === 0 ? "var(--fg-mute)" : "oklch(0.62 0.15 145)"} height={5} />
                        <span className="mono" style={{fontSize: 11, color: "var(--fg-mid)", minWidth: 32}}>{c.progress}%</span>
                      </div>
                    </td>
                    <td className="mono" style={{fontWeight: 600}}>{c.grade}</td>
                    <td><StatusPill status={c.status} /></td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>

        <div className="card">
          <div className="card-h">
            <div className="left">
              <div className="eyebrow">Upcoming · next {(D.upcomingDeadlines || []).length}</div>
              <div className="title">Deadlines</div>
            </div>
          </div>
          <div className="card-b flush">
            {(D.upcomingDeadlines || []).map((d, i) => (
              <div key={i} style={{padding: "12px 14px", borderBottom: i < (D.upcomingDeadlines.length - 1) ? "1px solid var(--border-soft)" : "none"}}>
                <div style={{display: "flex", justifyContent: "space-between", alignItems: "start"}}>
                  <div className="mono" style={{fontSize: 10.5, color: "var(--fg-soft)", letterSpacing: "0.08em"}}>{d.course}</div>
                  <span className={"pill " + (d.lvl || "")}>{d.due}</span>
                </div>
                <div style={{marginTop: 4, fontSize: 13, fontWeight: 500}}>{d.title}</div>
              </div>
            ))}
          </div>
        </div>
      </div>

      <div className="card" style={{marginTop: 12}}>
        <div className="card-h">
          <div className="left">
            <div className="eyebrow">Trajectory · 4 terms</div>
            <div className="title">GPA over time</div>
          </div>
        </div>
        <div className="card-b">
          <LineChart
            series={[{ values: (D.sparks || {}).gpa || [3.62, 3.71, 3.74, 3.80, 3.82, 3.85, 3.86, 3.88, 3.88, 3.90, 3.91, 3.92], color: "oklch(0.62 0.15 145)", strokeWidth: 2 }]}
            w={1000} h={160}
            yFmt={v => v.toFixed(2)}
            xLabels={["F23","S24","F24","M","M","M","M","M","M","M","M","M19"]}
          />
        </div>
      </div>
    </div>
  );
}

// ── VenturesPage ──────────────────────────────────────────────────────────────
function VenturesPage({ navigate }) {
  const D = window.JARVIS_DATA;
  const m = D.metrics || {};
  return (
    <div className="main-inner">
      <div className="page-head">
        <div>
          <div className="eyebrow">PORTFOLIO · {(D.ventures || []).length} ENTITIES · MAY {new Date().getDate()}</div>
          <h1>Ventures</h1>
        </div>
        <div className="actions">
          <span className="pill red">{(D.ventures || []).filter(v => v.status === "stalled").length} STALLED</span>
        </div>
      </div>

      <div className="kpi-strip" style={{gridTemplateColumns: "repeat(4, 1fr)"}}>
        <div className="kpi"><div className="lbl">Combined MTD</div><div className={"val" + ((m.mtdRev || 0) === 0 ? " neg" : "")}>{fmtMoney(m.mtdRev || 0)}</div><div className="sub neg">May · stalled across both</div></div>
        <div className="kpi"><div className="lbl">Combined YTD</div><div className="val">{fmtMoney(m.yrRev || 0)}</div><div className="sub">+$1,920 vs LY</div></div>
        <div className="kpi"><div className="lbl">Avg MRR (12mo)</div><div className="val">{fmtMoney((D.ventures || []).reduce((s, v) => s + (v.mrrAvg || 0), 0))}</div><div className="sub">{(D.ventures || []).map(v => v.key + " $" + (v.mrrAvg/1000).toFixed(1) + "k").join(" · ")}</div></div>
        <div className="kpi"><div className="lbl">Pipeline value</div><div className="val">$50,000</div><div className="sub">6 active leads</div></div>
      </div>

      <div style={{display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12}}>
        {(D.ventures || []).map(v => (
          <div className="card" key={v.key}>
            <div className="card-h">
              <div className="left">
                <div className="eyebrow">{v.key} · {v.stage}</div>
                <div className="title">{v.name}</div>
              </div>
              <div className="right"><StatusPill status={v.status} /></div>
            </div>
            <div className="card-b">
              <div style={{display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 10, marginBottom: 14}}>
                <Kpi tiny lbl="MTD" val={"$" + v.mtd.toLocaleString()} />
                <Kpi tiny lbl="YTD" val={"$" + v.ytd.toLocaleString()} />
                <Kpi tiny lbl="MRR avg" val={"$" + v.mrrAvg.toLocaleString()} />
              </div>
              <div style={{marginBottom: 10}}>
                <div style={{fontSize: 10.5, color: "var(--fg-soft)", fontFamily: "var(--font-mono)", letterSpacing: "0.08em", marginBottom: 6, textTransform: "uppercase"}}>Revenue · trailing 12mo</div>
                <Sparkline values={v.trend} w={420} h={48} color={v.mtd === 0 ? "var(--red)" : "oklch(0.62 0.15 145)"} fill={v.mtd === 0 ? "oklch(0.94 0.06 25)" : "oklch(0.93 0.06 145)"} strokeWidth={1.8} />
              </div>
              <div style={{marginTop: 12}}>
                <div style={{fontSize: 10.5, color: "var(--fg-soft)", fontFamily: "var(--font-mono)", letterSpacing: "0.08em", marginBottom: 8, textTransform: "uppercase"}}>Pipeline</div>
                <div style={{display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 8}}>
                  {(v.pipeline || []).map(p => (
                    <div key={p.stage} style={{background: "var(--bg-sunken)", border: "1px solid var(--border-soft)", borderRadius: 6, padding: 8}}>
                      <div style={{fontSize: 10, color: "var(--fg-soft)", textTransform: "uppercase", fontFamily: "var(--font-mono)", letterSpacing: "0.06em"}}>{p.stage}</div>
                      <div style={{fontWeight: 600, fontSize: 15, marginTop: 4, fontVariantNumeric: "tabular-nums"}}>{p.n}</div>
                      {p.val > 0 && <div style={{fontSize: 11, color: "var(--fg-mid)", fontFamily: "var(--font-mono)"}}>${(p.val/1000).toFixed(0)}k</div>}
                    </div>
                  ))}
                </div>
              </div>
              <hr className="div"/>
              <div style={{fontSize: 10.5, color: "var(--fg-soft)", fontFamily: "var(--font-mono)", letterSpacing: "0.08em", marginBottom: 8, textTransform: "uppercase"}}>Clients · top {(v.clients || []).length}</div>
              {(v.clients || []).map(c => (
                <div key={c.name} style={{display: "flex", alignItems: "center", justifyContent: "space-between", padding: "8px 0", borderTop: "1px dashed var(--border-soft)"}}>
                  <div style={{fontSize: 13, fontWeight: 500}}>{c.name}</div>
                  <div style={{display: "flex", gap: 8, alignItems: "center"}}>
                    <StatusPill status={c.status} />
                    <div className="mono" style={{fontSize: 12, color: c.mrr ? "var(--fg)" : "var(--fg-soft)"}}>${c.mrr.toLocaleString()}</div>
                  </div>
                </div>
              ))}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ── HealthPage ────────────────────────────────────────────────────────────────
function HealthPage({ navigate }) {
  const D = window.JARVIS_DATA;
  return (
    <div className="main-inner">
      <div className="page-head">
        <div>
          <div className="eyebrow">WHOOP · LAST 24H · STREAK 7 DAYS</div>
          <h1>Wellness</h1>
        </div>
        <div className="actions">
          <span className="pill green">RECOVERY HIGH</span>
        </div>
      </div>

      <div className="card">
        <div className="card-h">
          <div className="left">
            <div className="eyebrow">Today · readiness signals</div>
            <div className="title">Wellness rings</div>
          </div>
        </div>
        <div className="card-b">
          <div style={{display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 12}}>
            {D.health && (
              <>
                <Ring value={D.health.sleep.val} label="Sleep" sub={D.health.sleep.sub} color={D.health.sleep.color} size={96} />
                <Ring value={D.health.recovery.val} label="Recovery" sub={D.health.recovery.sub} color={D.health.recovery.color} size={96} />
                <Ring value={D.health.strain.val} label="Strain" sub={D.health.strain.sub} color={D.health.strain.color} size={96} />
                <Ring value={D.health.calories.val} label="Calories" sub={D.health.calories.sub} color={D.health.calories.color} size={96} />
              </>
            )}
          </div>
        </div>
      </div>

      <div style={{display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginTop: 12}}>
        <div className="card">
          <div className="card-h">
            <div className="left">
              <div className="eyebrow">5 weeks · 4 metrics</div>
              <div className="title">Wellness trajectory</div>
            </div>
          </div>
          <div className="card-b">
            <LineChart
              series={[
                { values: (D.healthHistory || []).map(d => d.sleep), color: "#3b6bd6" },
                { values: (D.healthHistory || []).map(d => d.rec), color: "#3f9d6d" },
                { values: (D.healthHistory || []).map(d => d.strain), color: "#c99041" },
                { values: (D.healthHistory || []).map(d => d.cal), color: "#d14545" }
              ]}
              w={560} h={180}
              xLabels={(D.healthHistory || []).map(d => d.d)}
              yFmt={v => v}
            />
            <div style={{display: "flex", flexWrap: "wrap", gap: 14, marginTop: 8, fontSize: 11, color: "var(--fg-soft)", fontFamily: "var(--font-mono)"}}>
              {[["#3b6bd6","Sleep"],["#3f9d6d","Recovery"],["#c99041","Strain"],["#d14545","Calories"]].map(([c,l]) => (
                <span key={l}><span style={{display: "inline-block", width: 10, height: 10, background: c, verticalAlign: "middle", marginRight: 6}}/>{l}</span>
              ))}
            </div>
          </div>
        </div>

        <div className="card">
          <div className="card-h">
            <div className="left">
              <div className="eyebrow">Today · 24h baseline</div>
              <div className="title">Composite signals</div>
            </div>
          </div>
          <div className="card-b">
            <div style={{display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14}}>
              <SignalRow lbl="HRV" val="64 ms" delta="+8 / 7d" pos />
              <SignalRow lbl="RHR" val="52 bpm" delta="−2 / 7d" pos />
              <SignalRow lbl="REM sleep" val="1h 48m" delta="+12m" pos />
              <SignalRow lbl="Deep sleep" val="1h 22m" delta="−6m" />
              <SignalRow lbl="Steps" val="9,840" delta="+1,200" pos />
              <SignalRow lbl="Active min" val="74 min" delta="+18m" pos />
              <SignalRow lbl="Resting cal" val="1,720" delta="—" />
              <SignalRow lbl="Active cal" val="420" delta="+60" pos />
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

function SignalRow({ lbl, val, delta, pos, neg }) {
  return (
    <div style={{paddingBottom: 12, borderBottom: "1px dashed var(--border-soft)"}}>
      <div className="mono" style={{fontSize: 10.5, color: "var(--fg-soft)", letterSpacing: "0.08em", textTransform: "uppercase"}}>{lbl}</div>
      <div style={{fontSize: 19, fontWeight: 600, letterSpacing: "-0.01em", marginTop: 2, fontVariantNumeric: "tabular-nums"}}>{val}</div>
      <div className="mono" style={{fontSize: 11, color: pos ? "oklch(0.5 0.14 145)" : neg ? "var(--red)" : "var(--fg-soft)", marginTop: 2}}>{delta}</div>
    </div>
  );
}

// ── FamilyPage ────────────────────────────────────────────────────────────────
function FamilyPage({ navigate }) {
  const D = window.JARVIS_DATA;
  const f = D.family || {};
  const m = D.metrics || {};
  return (
    <div className="main-inner">
      <div className="page-head">
        <div>
          <div className="eyebrow">CHILD DEVELOPMENT · {f.child ? f.child.name.toUpperCase() + ", " + f.child.age.toUpperCase() : "MASON, 2Y 7M"}</div>
          <h1>Family</h1>
        </div>
        <div className="actions">
          <span className="pill green">{m.milestones ? m.milestones.done + " / " + m.milestones.total : "26 / 26"} MILESTONES</span>
        </div>
      </div>

      <div className="kpi-strip">
        <div className="kpi"><div className="lbl">Milestones met</div><div className="val">{m.milestones ? m.milestones.done + " / " + m.milestones.total : "26 / 26"}</div><div className="sub pos">100% · all on track</div></div>
        <div className="kpi"><div className="lbl">Last logged</div><div className="val">{f.milestones && f.milestones[0] ? f.milestones[0].date : "May 04"}</div><div className="sub">{f.milestones && f.milestones[0] ? f.milestones[0].text : "—"}</div></div>
        <div className="kpi"><div className="lbl">Next appt</div><div className="val">{f.next ? f.next.date : "Wed 9:30"}</div><div className="sub">{f.next ? f.next.title : "Pediatrician"}</div></div>
        <div className="kpi"><div className="lbl">529 plan</div><div className="val">$614</div><div className="sub pos">+$50 / mo</div></div>
      </div>

      <div style={{display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12}}>
        <div className="card">
          <div className="card-h">
            <div className="left">
              <div className="eyebrow">Recent · last 90 days</div>
              <div className="title">Milestones</div>
            </div>
          </div>
          <div className="card-b flush">
            {(f.milestones || []).map((ms, i) => (
              <div key={i} style={{display: "grid", gridTemplateColumns: "70px 1fr auto", gap: 10, padding: "10px 14px", borderBottom: i < f.milestones.length - 1 ? "1px solid var(--border-soft)" : "none", alignItems: "center"}}>
                <div className="mono" style={{fontSize: 11, color: "var(--fg-mid)"}}>{ms.date}</div>
                <div style={{fontSize: 13}}>{ms.text}</div>
                <span className="pill">{ms.area}</span>
              </div>
            ))}
          </div>
        </div>

        <div className="card">
          <div className="card-h">
            <div className="left">
              <div className="eyebrow">By domain · 5 areas tracked</div>
              <div className="title">Development radar</div>
            </div>
          </div>
          <div className="card-b">
            <div style={{display: "flex", flexDirection: "column", gap: 12}}>
              <DomainBar lbl="Language"  pct={100} ctx="At 3y level · 4 milestones ahead" />
              <DomainBar lbl="Numeracy"  pct={92}  ctx="Counts to 30 · early shapes" />
              <DomainBar lbl="Motor"     pct={88}  ctx="Tied left shoe · half cycling" />
              <DomainBar lbl="Social"    pct={95}  ctx="Sharing · empathy emerging" />
              <DomainBar lbl="Sleep"     pct={100} ctx="14 nights consecutive" />
            </div>
            <hr className="div" />
            <div style={{display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10}}>
              {f.next && (
                <div style={{background: "var(--bg-sunken)", borderRadius: 6, padding: 10}}>
                  <div className="mono" style={{fontSize: 10, color: "var(--fg-soft)", textTransform: "uppercase", letterSpacing: "0.08em"}}>Next event</div>
                  <div style={{fontWeight: 500, marginTop: 4}}>{f.next.title}</div>
                  <div style={{fontSize: 11, color: "var(--fg-soft)", marginTop: 2}}>{f.next.date} · {f.next.time}</div>
                </div>
              )}
              <div style={{background: "var(--bg-sunken)", borderRadius: 6, padding: 10}}>
                <div className="mono" style={{fontSize: 10, color: "var(--fg-soft)", textTransform: "uppercase", letterSpacing: "0.08em"}}>Tracking source</div>
                <div style={{fontWeight: 500, marginTop: 4}}>Penn State Health portal</div>
                <div style={{fontSize: 11, color: "var(--fg-soft)", marginTop: 2}}>Last sync 04:12 ET</div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

function DomainBar({ lbl, pct, ctx }) {
  return (
    <div>
      <div style={{display: "flex", justifyContent: "space-between", marginBottom: 4, fontSize: 12}}>
        <span style={{fontWeight: 500}}>{lbl}</span>
        <span className="mono" style={{color: "var(--fg-soft)"}}>{pct}%</span>
      </div>
      <Progress value={pct} color="oklch(0.55 0.15 255)" height={5} />
      <div style={{fontSize: 11, color: "var(--fg-soft)", marginTop: 4}}>{ctx}</div>
    </div>
  );
}

// ── CalendarPage ──────────────────────────────────────────────────────────────
function CalendarPage({ navigate }) {
  const D = window.JARVIS_DATA;
  const days = ["May 19","May 20","May 21","May 22","May 23","May 24","May 25"];
  const hours = ["8a","9a","10a","11a","12p","1p","2p","3p","4p","5p"];
  const events = [
    { day: 0, h: 1.42, dur: 0.5, title: "JARVIS midday check",   color: "#3b6bd6" },
    { day: 2, h: 1.5,  dur: 1,   title: "Mason · wellness check", color: "oklch(0.55 0.15 255)" },
    { day: 2, h: 6,    dur: 1,   title: "Brennan strategy",       color: "#3f9d6d" },
    { day: 3, h: 0,    dur: 1.5, title: "A-I 801 kickoff",        color: "#c99041" },
    { day: 3, h: 5,    dur: 1.5, title: "Date night · Tamedrea",  color: "#d14545" },
    { day: 4, h: 3,    dur: 0.75,title: "Mortgage escrow",        color: "#3b6bd6" },
    { day: 4, h: 9,    dur: 0.5, title: "Whoop weekly review",    color: "#3f9d6d" }
  ];

  return (
    <div className="main-inner">
      <div className="page-head">
        <div>
          <div className="eyebrow">WEEK · MAY 19 – MAY 25</div>
          <h1>Calendar</h1>
        </div>
        <div className="actions">
          <SyncButton
            label="Calendars"
            sources={[
              { id: "gcal",    label: "Google Calendar · personal", status: "ok" },
              { id: "outlook", label: "Outlook · work + RCG",       status: "ok" },
              { id: "icloud",  label: "iCloud · family shared",     status: "ok" }
            ]}
            defaultLastSyncMin={6}
          />
          <div className="seg">
            <button>Day</button>
            <button className="active">Week</button>
            <button>Month</button>
          </div>
        </div>
      </div>

      <div className="card">
        <div className="card-h">
          <div className="left">
            <div className="eyebrow">Schedule · {events.length} events</div>
            <div className="title">Week ahead</div>
          </div>
        </div>
        <div className="card-b">
          <div style={{display: "grid", gridTemplateColumns: "56px repeat(7, 1fr)", gap: 0, border: "1px solid var(--border-soft)", borderRadius: 6, overflow: "hidden"}}>
            <div></div>
            {days.map((d, i) => (
              <div key={d} style={{padding: "8px 10px", borderBottom: "1px solid var(--border-soft)", borderLeft: "1px solid var(--border-soft)", background: i === 0 ? "var(--bg-sunken)" : "var(--bg-elev)"}}>
                <div className="mono" style={{fontSize: 10, color: "var(--fg-soft)", letterSpacing: "0.06em"}}>{d.split(" ")[0].toUpperCase()}</div>
                <div style={{fontWeight: 600, fontSize: 13, marginTop: 2}}>{d.split(" ")[1]}{i === 0 ? " ·" : ""}</div>
              </div>
            ))}
            {hours.map((h, hi) => (
              <React.Fragment key={h}>
                <div style={{padding: "16px 10px", borderTop: hi > 0 ? "1px solid var(--border-soft)" : "none", fontSize: 10, color: "var(--fg-soft)", fontFamily: "var(--font-mono)", textAlign: "right"}}>{h}</div>
                {days.map((d, di) => {
                  const cellEvents = events.filter(e => e.day === di && Math.floor(e.h) === hi);
                  return (
                    <div key={di} style={{borderTop: hi > 0 ? "1px solid var(--border-soft)" : "none", borderLeft: "1px solid var(--border-soft)", padding: 4, minHeight: 44, position: "relative", background: di === 0 ? "rgba(245,242,236,0.4)" : "var(--bg-elev)"}}>
                      {cellEvents.map((ev, ei) => (
                        <div key={ei} style={{background: ev.color, color: "white", fontSize: 10.5, padding: "4px 6px", borderRadius: 3, marginBottom: 2, fontWeight: 500, lineHeight: 1.2, cursor: "pointer"}}>{ev.title}</div>
                      ))}
                    </div>
                  );
                })}
              </React.Fragment>
            ))}
          </div>
        </div>
      </div>

      <div className="card" style={{marginTop: 12}}>
        <div className="card-h">
          <div className="left">
            <div className="eyebrow">Daily breakdown</div>
            <div className="title">By day · Mon to Sun</div>
          </div>
        </div>
        <div className="card-b flush">
          {(D.weekAhead || []).map((d, i) => (
            <div key={i} style={{padding: "12px 14px", borderBottom: i < D.weekAhead.length - 1 ? "1px solid var(--border-soft)" : "none"}}>
              <div style={{display: "flex", alignItems: "center", gap: 12, marginBottom: 8}}>
                <div className="mono" style={{fontSize: 11, color: "var(--fg-soft)", letterSpacing: "0.08em", textTransform: "uppercase", minWidth: 90}}>{d.day}</div>
                <div style={{flex: 1, height: 1, background: "var(--border-soft)"}}/>
                <div className="mono" style={{fontSize: 10.5, color: "var(--fg-soft)"}}>{d.events.length} event{d.events.length === 1 ? "" : "s"}</div>
              </div>
              {d.events.map((ev, ei) => (
                <div key={ei} style={{display: "grid", gridTemplateColumns: "80px 1fr auto", gap: 10, alignItems: "center", padding: "6px 0"}}>
                  <div className="mono" style={{fontSize: 11.5, color: "var(--fg-mid)"}}>{ev.time}</div>
                  <div style={{fontSize: 13, fontWeight: 500}}>{ev.title}</div>
                  <span className="pill">{ev.ctx}</span>
                </div>
              ))}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

// ── ProjectsPage ──────────────────────────────────────────────────────────────
function ProjectsPage({ navigate }) {
  const D = window.JARVIS_DATA;
  const m = D.metrics || {};
  const blocked = (D.projects || []).filter(p => p.status === "blocked").length;
  const onTrack = (D.projects || []).filter(p => p.status !== "blocked").length;
  return (
    <div className="main-inner">
      <div className="page-head">
        <div>
          <div className="eyebrow">ACTIVE PORTFOLIO · {(D.projects || []).length} PROJECTS · {m.openTasks || 14} OPEN TASKS</div>
          <h1>Projects</h1>
        </div>
        <div className="actions">
          <SyncButton
            label="Projects"
            sources={[
              { id: "linear", label: "Linear · JARVIS workspace", status: "ok" },
              { id: "notion", label: "Notion · personal",         status: "ok" },
              { id: "github", label: "GitHub · issues + PRs",     status: "ok" }
            ]}
            defaultLastSyncMin={9}
          />
          {blocked > 0 && <span className="pill red">{blocked} BLOCKED</span>}
          {onTrack > 0 && <span className="pill green">{onTrack} ON TRACK</span>}
        </div>
      </div>

      <div className="kpi-strip">
        <div className="kpi"><div className="lbl">Active</div><div className="val">{onTrack}</div><div className="sub pos">all on schedule</div></div>
        <div className="kpi"><div className="lbl">Blocked</div><div className={"val" + (blocked > 0 ? " neg" : "")}>{blocked}</div><div className="sub neg">{(D.projects || []).find(p => p.status === "blocked")?.name || "—"}</div></div>
        <div className="kpi"><div className="lbl">Open tasks</div><div className="val">{m.openTasks || 14}</div><div className="sub">5 priority</div></div>
        <div className="kpi"><div className="lbl">Next deadline</div><div className="val">{(D.tasks || [])[0]?.due || "Today"}</div><div className="sub neg">{(D.tasks || [])[0]?.title || "—"}</div></div>
      </div>

      <div className="card">
        <div className="card-h">
          <div className="left">
            <div className="eyebrow">All projects · {(D.projects || []).length}</div>
            <div className="title">Portfolio status</div>
          </div>
        </div>
        <div className="card-b flush">
          <table className="tbl">
            <thead><tr><th>Project</th><th>Status</th><th>Health</th><th className="num">Tasks</th><th>Next due</th></tr></thead>
            <tbody>
              {(D.projects || []).map(p => (
                <tr key={p.name}>
                  <td style={{fontWeight: 500}}>{p.name}</td>
                  <td><StatusPill status={p.status} /></td>
                  <td><span className={"dot " + p.health}/></td>
                  <td className="num">{p.tasks}</td>
                  <td className="mono" style={{fontSize: 12, color: p.due === "Today" ? "var(--red)" : "var(--fg-mid)"}}>{p.due}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>

      <div className="card" style={{marginTop: 12}}>
        <div className="card-h">
          <div className="left">
            <div className="eyebrow">All open tasks · {m.openTasks || 14}</div>
            <div className="title">Full task list</div>
          </div>
          <div className="right">
            <div className="seg">
              <button className="active">All</button>
              <button>Priority</button>
            </div>
          </div>
        </div>
        <div className="card-b flush">
          {(D.tasks || []).map(t => <TaskRow key={t.id} task={t} />)}
        </div>
      </div>
    </div>
  );
}

// ── InboxPage ─────────────────────────────────────────────────────────────────
function InboxPage({ navigate }) {
  const D = window.JARVIS_DATA;
  const unread = (D.inboxItems || []).filter(i => !i.read).length;
  return (
    <div className="main-inner">
      <div className="page-head">
        <div>
          <div className="eyebrow">{unread} UNREAD · {(D.inboxItems || []).length} TOTAL</div>
          <h1>Action Inbox</h1>
        </div>
        <div className="actions">
          <div className="seg">
            <button className="active">All</button>
            <button>Unread</button>
            <button>Flagged</button>
          </div>
        </div>
      </div>

      <div className="card">
        <div className="card-b flush">
          {(D.inboxItems || []).map(it => (
            <div key={it.id} style={{display: "grid", gridTemplateColumns: "12px 90px 90px 1fr 80px", gap: 12, padding: "12px 14px", borderBottom: "1px solid var(--border-soft)", alignItems: "center", cursor: "pointer", background: !it.read ? "rgba(245,245,240,0.6)" : "transparent"}}>
              {!it.read ? <span className={"dot " + (it.lvl || "blue")}/> : <span/>}
              <div className="mono" style={{fontSize: 11, color: "var(--fg-mid)"}}>{it.from}</div>
              <span className="pill">{it.area}</span>
              <div style={{fontWeight: !it.read ? 600 : 400, fontSize: 13}}>{it.subj}</div>
              <div className="mono" style={{fontSize: 11, color: "var(--fg-soft)", textAlign: "right"}}>{it.time}</div>
            </div>
          ))}
        </div>
      </div>

      <div className="section-h">
        <h2>Recent activity feed</h2>
        <span className="meta">today · {(D.activity || []).length} events</span>
      </div>
      <div className="card">
        <div className="card-b flush">
          {(D.activity || []).map(a => (
            <div className="act-row" key={a.id}>
              <div className="time">{a.time}</div>
              <div className="body">{a.text}</div>
              <div className={"amt " + a.level}>{a.amt}</div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

// ── ChatPage ──────────────────────────────────────────────────────────────────
function ChatPage({ navigate }) {
  const D = window.JARVIS_DATA;
  const [msgs, setMsgs] = React.useState(D.chat || []);
  const [draft, setDraft] = React.useState("");
  const bottomRef = React.useRef(null);

  React.useEffect(() => {
    if (bottomRef.current) bottomRef.current.scrollIntoView({ behavior: "smooth" });
  }, [msgs]);

  const send = async () => {
    const text = draft.trim();
    if (!text) return;
    setDraft("");
    const userMsg = { who: "Stephen", body: text };
    setMsgs(m => [...m, userMsg]);

    try {
      const token = sessionStorage.getItem("jarvis.mobile.token") || sessionStorage.getItem("jarvis_token");
      const headers = { "Content-Type": "application/json" };
      if (token) headers["x-jarvis-auth"] = token;
      const res = await fetch("/api/chat", {
        method: "POST",
        headers,
        body: JSON.stringify({ message: text })
      });
      if (res.ok) {
        const data = await res.json();
        setMsgs(m => [...m, { who: "JARVIS", body: data.reply || data.message || "—" }]);
      } else {
        setMsgs(m => [...m, { who: "JARVIS", body: "Synthesizing — drawing from latest " + ((D.metrics || {}).accounts || 38) + " accounts, Whoop, and Penn State portal." }]);
      }
    } catch {
      setMsgs(m => [...m, { who: "JARVIS", body: "Synthesizing — drawing from latest data sources. One moment." }]);
    }
  };

  return (
    <div className="main-inner" style={{display: "flex", flexDirection: "column", height: "calc(100vh - 80px)"}}>
      <div className="page-head">
        <div>
          <div className="eyebrow">CONVERSATION · MIDDAY CHECK</div>
          <h1>JARVIS Chat</h1>
        </div>
        <div className="actions">
          <span className="pill green">ONLINE</span>
        </div>
      </div>

      <div className="card" style={{flex: 1, display: "flex", flexDirection: "column", minHeight: 0}}>
        <div style={{flex: 1, overflowY: "auto", padding: "4px 0"}}>
          {msgs.map((m, i) => (
            <div key={i} className={"chat-msg " + (m.who === "Stephen" ? "user" : "")}>
              <div className="who">{m.who}</div>
              <div className="body">{m.body}</div>
            </div>
          ))}
          <div ref={bottomRef} />
        </div>
        <div style={{borderTop: "1px solid var(--border-soft)", padding: 12, display: "flex", gap: 8}}>
          <input
            type="text"
            value={draft}
            onChange={e => setDraft(e.target.value)}
            onKeyDown={e => e.key === "Enter" && send()}
            placeholder="Ask JARVIS about anything in your life..."
            style={{flex: 1, padding: "10px 12px", border: "1px solid var(--border)", borderRadius: 6, fontSize: 13, fontFamily: "var(--font-sans)", background: "var(--bg)", color: "var(--fg)", outline: "none"}}
          />
          <button onClick={send} style={{padding: "10px 18px", background: "var(--fg)", color: "var(--bg-elev)", border: "none", borderRadius: 6, fontSize: 13, fontWeight: 500, cursor: "pointer", fontFamily: "var(--font-sans)"}}>Send</button>
        </div>
      </div>
    </div>
  );
}

// ── HomeValuePage ─────────────────────────────────────────────────────────────
function HomeValuePage({ navigate }) {
  const D = window.JARVIS_DATA;
  const m = D.metrics || {};
  return (
    <div className="main-inner">
      <div className="page-head">
        <div>
          <div className="eyebrow">PRIMARY RESIDENCE · ESTIMATED FAIR MARKET</div>
          <h1>Home value</h1>
        </div>
        <div className="actions"><span className="pill green">+2.5% 90D</span></div>
      </div>
      <div className="kpi-strip">
        <div className="kpi"><div className="lbl">Estimated value</div><div className="val">{fmtMoneyFull(m.homeValue || 412000)}</div><div className="sub pos">+$10k · 90d</div></div>
        <div className="kpi"><div className="lbl">Mortgage owed</div><div className="val">$356,471</div><div className="sub">3.25% fixed</div></div>
        <div className="kpi"><div className="lbl">Equity</div><div className="val">{fmtMoneyFull(m.homeEquity || 55129)}</div><div className="sub pos">+$11k YTD</div></div>
        <div className="kpi"><div className="lbl">LTV</div><div className="val">86.5%</div><div className="sub">target 80%</div></div>
      </div>
      <div className="card">
        <div className="card-h">
          <div className="left">
            <div className="eyebrow">Value trend · 12 months</div>
            <div className="title">Estimated FMV</div>
          </div>
        </div>
        <div className="card-b">
          <LineChart
            series={[{ values: ((D.sparks || {}).home || []).map(v => v * 1000), color: "oklch(0.55 0.15 255)", strokeWidth: 2 }]}
            w={1000} h={180}
            yFmt={v => "$" + Math.round(v/1000) + "k"}
            xLabels={["Jun","Jul","Aug","Sep","Oct","Nov","Dec","Jan","Feb","Mar","Apr","May"]}
          />
        </div>
      </div>
      <div className="card" style={{marginTop: 12}}>
        <div className="card-h">
          <div className="left">
            <div className="eyebrow">Mortgage · 27 years remaining</div>
            <div className="title">Amortization snapshot</div>
          </div>
        </div>
        <div className="card-b">
          <div style={{display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 12}}>
            <Kpi tiny lbl="Monthly P&I" val="$2,184" />
            <Kpi tiny lbl="Escrow" val="$486" />
            <Kpi tiny lbl="Year-1 interest" val="$11,470" />
            <Kpi tiny lbl="Year-1 principal" val="$15,930" />
          </div>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, {
  FinancesPage, AcademicsPage, VenturesPage, HealthPage, FamilyPage,
  CalendarPage, ProjectsPage, InboxPage, ChatPage, HomeValuePage
});
