// Operational pages: Signals, Trades, Risk, Backtester, Alerts, Logs.
const { useState: upS, useEffect: upE, useMemo: upM } = React;

// =====================================================================
// SIGNALS PAGE — TradingView webhook log
// =====================================================================
function SignalsPage({ accent }) {
  const [filter, setFilter] = upS("All");
  const filtered = SIGNALS.filter((s) => filter === "All" || s.status === filter.toLowerCase().replace(" ", "_"));

  // Stats
  const total = SIGNALS.length;
  const executed = SIGNALS.filter((s) => s.status === "executed").length;
  const rejected = SIGNALS.filter((s) => s.status === "rejected").length;
  const dedup = SIGNALS.filter((s) => s.status === "deduplicated").length;
  const stopped = SIGNALS.filter((s) => s.status === "stopped_out").length;
  const avgLat = Math.round(SIGNALS.reduce((a, s) => a + s.latencyMs, 0) / SIGNALS.length);

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--row-gap)" }}>
      {/* KPI strip */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(5, 1fr)", gap: "var(--row-gap)" }}>
        <Kpi label="Signals 24h" value={total.toString()} sub="webhook hits" />
        <Kpi label="Executed" value={executed.toString()} sub={Math.round(executed/total*100) + "% of total"} tone="profit" />
        <Kpi label="Rejected" value={rejected.toString()} sub="risk-gated" tone="loss" />
        <Kpi label="Deduplicated" value={dedup.toString()} sub="< 60s window" tone="warn" />
        <Kpi label="Avg latency" value={avgLat + "ms"} sub="webhook → fill" />
      </div>

      {/* Funnel + latency */}
      <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr)", gap: "var(--row-gap)" }}>
        <Card title="Signal funnel" subtitle="Last 24h pipeline drop-off">
          <SignalFunnel stages={[
            { label: "Received from TradingView", value: total, color: "var(--info)" },
            { label: "Passed deduplication",       value: total - dedup, color: "var(--text)" },
            { label: "Passed risk checks",          value: total - dedup - rejected, color: "var(--accent)" },
            { label: "Executed on exchange",        value: executed, color: "var(--profit)" },
            { label: "Closed at profit",            value: executed - stopped, color: "var(--profit)" },
          ]} />
        </Card>

        <Card title="Latency distribution" subtitle="webhook receipt → exchange ack">
          <LatencyHistogram samples={SIGNALS.map((s) => s.latencyMs)} h={140} />
          <div className="mono" style={{ fontSize: 10, color: "var(--text-3)", marginTop: 6, textAlign: "center", letterSpacing: 0.5 }}>milliseconds · target &lt; 2000ms</div>
          <div style={{ display: "flex", justifyContent: "space-between", marginTop: 12, paddingTop: 12, borderTop: "1px solid var(--line)", fontSize: 12 }}>
            <div><span style={{ color: "var(--text-3)" }}>p50: </span><span className="mono" style={{ color: "var(--profit)" }}>461ms</span></div>
            <div><span style={{ color: "var(--text-3)" }}>p95: </span><span className="mono" style={{ color: "var(--warn)" }}>689ms</span></div>
            <div><span style={{ color: "var(--text-3)" }}>p99: </span><span className="mono">812ms</span></div>
          </div>
        </Card>

        <Card title="Webhook endpoint" subtitle="POST /webhook · TradingView alerts">
          <CodeBlock>
            <span style={{ color: "var(--text-3)" }}>POST</span> <span style={{ color: "var(--accent)" }}>https://api.helix.trade/webhook</span>{"\n"}
            <span style={{ color: "var(--text-3)" }}>X-Webhook-Secret:</span> <span style={{ color: "var(--info)" }}>••••••••••</span>{"\n\n"}
            {"{\n"}
            {"  "}<span style={{ color: "#FCD34D" }}>"signal"</span>: <span style={{ color: "var(--profit)" }}>"BUY"</span>,{"\n"}
            {"  "}<span style={{ color: "#FCD34D" }}>"symbol"</span>: <span style={{ color: "var(--profit)" }}>"BTC/USDT"</span>,{"\n"}
            {"  "}<span style={{ color: "#FCD34D" }}>"price"</span>: <span style={{ color: "var(--info)" }}>{"{{close}}"}</span>,{"\n"}
            {"  "}<span style={{ color: "#FCD34D" }}>"signal_id"</span>: <span style={{ color: "var(--info)" }}>{"{{strategy.order.id}}"}</span>{"\n"}
            {"}"}
          </CodeBlock>
          <div style={{ display: "flex", gap: 8, marginTop: 12 }}>
            <PrimaryBtn ghost icon={<IconCopy size={14} />} style={{ flex: 1, justifyContent: "center" }}>Copy URL</PrimaryBtn>
            <PrimaryBtn ghost icon={<IconRefresh size={14} />} style={{ flex: 1, justifyContent: "center" }}>Rotate secret</PrimaryBtn>
          </div>
        </Card>
      </div>

      {/* Signal log table */}
      <Card title="Signal log" subtitle="Last 12 webhook events · live"
        right={
          <div style={{ display: "flex", gap: 4, background: "rgba(255,255,255,0.04)", borderRadius: 8, padding: 3 }}>
            {["All", "Executed", "Rejected", "Deduplicated", "Stopped out"].map((f) => (
              <button key={f} onClick={() => setFilter(f)} style={{
                padding: "5px 12px", borderRadius: 6, fontSize: 11, fontWeight: 500, border: 0,
                background: filter === f ? "rgba(255,255,255,0.08)" : "transparent",
                color: filter === f ? "var(--text)" : "var(--text-2)",
              }}>{f}</button>
            ))}
          </div>
        }
        padded={false}>
        <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13 }}>
          <thead>
            <tr style={{ color: "var(--text-3)", fontSize: 11, letterSpacing: 0.5, textTransform: "uppercase" }}>
              <th style={th()}>Received</th>
              <th style={th()}>Signal ID</th>
              <th style={th()}>Side</th>
              <th style={th("right")}>Price</th>
              <th style={th()}>Status</th>
              <th style={th()}>Reason</th>
              <th style={th("right")}>Latency</th>
              <th style={th("right")}></th>
            </tr>
          </thead>
          <tbody>
            {filtered.map((s, i) => {
              const statusCfg = {
                executed:     { c: "var(--profit)", lbl: "Executed" },
                deduplicated: { c: "var(--text-3)", lbl: "Deduplicated" },
                rejected:     { c: "var(--loss)",   lbl: "Rejected" },
                stopped_out:  { c: "var(--warn)",   lbl: "Stopped out" },
              }[s.status];
              return (
                <tr key={s.id} style={{ borderTop: "1px solid var(--line)", background: i % 2 === 0 ? "transparent" : "rgba(255,255,255,0.012)" }}>
                  <td style={td()}><span className="mono" style={{ color: "var(--text-3)", fontSize: 12 }}>{fmtRel(s.t)}</span></td>
                  <td style={td()}><span className="mono" style={{ fontSize: 12, color: "var(--text-2)" }}>{s.id}</span></td>
                  <td style={td()}>
                    <span className="mono" style={{
                      fontSize: 10.5, padding: "2px 7px", borderRadius: 4, fontWeight: 700,
                      background: s.side === "BUY" ? "rgba(25,229,166,0.10)" : "rgba(242,63,92,0.10)",
                      color: s.side === "BUY" ? "var(--profit)" : "var(--loss)",
                    }}>{s.side}</span>
                  </td>
                  <td style={td("right")}><span className="mono">${s.price.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span></td>
                  <td style={td()}>
                    <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: 12 }}>
                      <span style={{ width: 6, height: 6, borderRadius: 999, background: statusCfg.c }} />
                      <span style={{ color: statusCfg.c }}>{statusCfg.lbl}</span>
                    </span>
                  </td>
                  <td style={td()}><span style={{ fontSize: 12, color: "var(--text-3)" }}>{s.reason || "—"}</span></td>
                  <td style={td("right")}>
                    <span className="mono" style={{ fontSize: 12, color: s.latencyMs > 700 ? "var(--warn)" : "var(--text-2)" }}>{s.latencyMs}ms</span>
                  </td>
                  <td style={td("right")}><IconBtn title="View payload"><IconEye size={14} /></IconBtn></td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </Card>
    </div>
  );
}

function CodeBlock({ children }) {
  return (
    <pre style={{
      margin: 0, padding: "14px 16px", borderRadius: 8,
      background: "#06080F", border: "1px solid var(--line)",
      fontFamily: "JetBrains Mono", fontSize: 11.5, lineHeight: 1.65,
      color: "var(--text-2)", overflow: "auto", whiteSpace: "pre-wrap",
    }}>{children}</pre>
  );
}

// =====================================================================
// TRADES PAGE
// =====================================================================
function TradesPage({ accent, activeExchange }) {
  const [side, setSide] = upS("All");
  const [status, setStatus] = upS("All");
  const [exch, setExch] = upS("All");
  const filtered = TRADES.filter((t) =>
    (side === "All" || t.side === side) &&
    (status === "All" || t.status === status.toLowerCase().replace(" ", "_")) &&
    (exch === "All" || t.exchange === exch.toLowerCase())
  );
  const closed = TRADES.filter((t) => t.pnl != null);
  const wins = closed.filter((t) => t.pnl > 0).length;
  const losses = closed.filter((t) => t.pnl < 0).length;
  const totalPnL = closed.reduce((a, t) => a + t.pnl, 0);
  const avgWin = closed.filter((t) => t.pnl > 0).reduce((a, t) => a + t.pnl, 0) / Math.max(1, wins);
  const avgLoss = closed.filter((t) => t.pnl < 0).reduce((a, t) => a + t.pnl, 0) / Math.max(1, losses);
  const profitFactor = Math.abs(closed.filter((t) => t.pnl > 0).reduce((a, t) => a + t.pnl, 0) / closed.filter((t) => t.pnl < 0).reduce((a, t) => a + t.pnl, 0) || 1);

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--row-gap)" }}>
      {/* KPIs */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(6, 1fr)", gap: "var(--row-gap)" }}>
        <Kpi label="Total trades" value={closed.length.toString()} sub={`${wins}W / ${losses}L`} />
        <Kpi label="Net P&L" value={fmtUsd(totalPnL, { sign: true })} sub="all closed" tone={totalPnL >= 0 ? "profit" : "loss"} />
        <Kpi label="Win rate" value={Math.round((wins / closed.length) * 100) + "%"} sub="last 30d" tone="profit" />
        <Kpi label="Avg win" value={fmtUsd(avgWin, { sign: true })} tone="profit" />
        <Kpi label="Avg loss" value={fmtUsd(avgLoss, { sign: true })} tone="loss" />
        <Kpi label="Profit factor" value={profitFactor.toFixed(2)} sub="gross W / L" tone="accent" />
      </div>

      {/* P&L distribution + Hourly heatmap */}
      <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1fr) minmax(0, 1.6fr)", gap: "var(--row-gap)" }}>
        <Card title="P&L distribution" subtitle="Per-trade outcomes">
          <PnLHistogram trades={TRADES} h={180} />
          <div className="mono" style={{ fontSize: 10, color: "var(--text-3)", marginTop: 8, letterSpacing: 0.4, textAlign: "center" }}>USD per trade</div>
        </Card>
        <Card title="Performance by hour of day" subtitle="UTC · last 30d · net P&L per hour bucket">
          <HourlyHeatmap data={HOURLY} h={64} />
          <div className="mono" style={{ fontSize: 10, color: "var(--text-3)", marginTop: 8, display: "flex", justifyContent: "space-between", letterSpacing: 0.4 }}>
            <span>00:00 UTC</span>
            <span style={{ color: "var(--profit)" }}>peak window: 13:00–17:00 (London/NY overlap)</span>
            <span>23:00 UTC</span>
          </div>
        </Card>
      </div>

      {/* Trades table */}
      <Card title="All trades" subtitle={filtered.length + " of " + TRADES.length + " trades"}
        right={
          <div style={{ display: "flex", gap: 8 }}>
            <Select value={exch}   onChange={setExch}   options={["All", "Binance", "Kraken"]} />
            <Select value={side}   onChange={setSide}   options={["All", "BUY", "SELL"]} />
            <Select value={status} onChange={setStatus} options={["All", "open", "closed", "stopped out"]} />
            <PrimaryBtn ghost icon={<IconDown size={14} />}>Export CSV</PrimaryBtn>
          </div>
        }
        padded={false}>
        <div style={{ overflowX: "auto" }}>
          <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13, minWidth: 900 }}>
            <thead>
              <tr style={{ color: "var(--text-3)", fontSize: 11, letterSpacing: 0.5, textTransform: "uppercase" }}>
                <th style={th()}>Opened</th>
                <th style={th()}>Exchange</th>
                <th style={th()}>Side</th>
                <th style={th("right")}>Qty</th>
                <th style={th("right")}>Entry</th>
                <th style={th("right")}>Exit</th>
                <th style={th("right")}>Stop</th>
                <th style={th("right")}>P&L</th>
                <th style={th("right")}>%</th>
                <th style={th()}>Closed by</th>
                <th style={th()}>Status</th>
              </tr>
            </thead>
            <tbody>
              {filtered.map((t, i) => {
                const statusBadge = {
                  open:        { c: "var(--accent)", lbl: "open" },
                  closed:      { c: "var(--text-2)", lbl: "closed" },
                  stopped_out: { c: "var(--warn)",   lbl: "stopped" },
                }[t.status];
                return (
                  <tr key={i} style={{ borderTop: "1px solid var(--line)", background: i % 2 === 0 ? "transparent" : "rgba(255,255,255,0.012)" }}>
                    <td style={td()}><span className="mono" style={{ fontSize: 12, color: "var(--text-3)" }}>{fmtRel(t.t)}</span></td>
                    <td style={td()}>
                      {(() => {
                        const ex = EXCHANGES[t.exchange] || EXCHANGES.binance;
                        return (
                          <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: 12 }}>
                            <ex.Icon size={13} />
                            <span style={{ color: "var(--text-2)" }}>{ex.name}</span>
                          </span>
                        );
                      })()}
                    </td>
                    <td style={td()}>
                      <span className="mono" style={{
                        fontSize: 10.5, padding: "2px 7px", borderRadius: 4, fontWeight: 700,
                        background: t.side === "BUY" ? "rgba(25,229,166,0.10)" : "rgba(242,63,92,0.10)",
                        color: t.side === "BUY" ? "var(--profit)" : "var(--loss)",
                      }}>{t.side}</span>
                    </td>
                    <td style={td("right")}><span className="mono" style={{ fontSize: 12 }}>{t.qty.toFixed(4)}</span></td>
                    <td style={td("right")}><span className="mono" style={{ fontSize: 12 }}>${t.entry.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span></td>
                    <td style={td("right")}><span className="mono" style={{ fontSize: 12, color: t.exit ? "var(--text)" : "var(--text-3)" }}>{t.exit ? "$" + t.exit.toLocaleString(undefined, { minimumFractionDigits: 2 }) : "—"}</span></td>
                    <td style={td("right")}><span className="mono" style={{ fontSize: 12, color: "var(--text-3)" }}>{t.stop ? "$" + t.stop.toLocaleString(undefined, { minimumFractionDigits: 2 }) : "—"}</span></td>
                    <td style={td("right")}>
                      <span className="mono" style={{ color: t.pnl == null ? "var(--text-3)" : t.pnl >= 0 ? "var(--profit)" : "var(--loss)", fontWeight: 500 }}>
                        {t.pnl == null ? "—" : fmtUsd(t.pnl, { sign: true })}
                      </span>
                    </td>
                    <td style={td("right")}><span className="mono" style={{ fontSize: 12, color: t.pnlPct == null ? "var(--text-3)" : t.pnlPct >= 0 ? "var(--profit)" : "var(--loss)" }}>{t.pnlPct == null ? "—" : fmtPct(t.pnlPct)}</span></td>
                    <td style={td()}><span style={{ fontSize: 12, color: "var(--text-3)" }}>{t.closedBy || "—"}</span></td>
                    <td style={td()}><Badge variant={t.status === "open" ? "accent" : t.status === "stopped_out" ? "warn" : "default"}>{statusBadge.lbl}</Badge></td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </Card>
    </div>
  );
}

function Select({ value, onChange, options }) {
  return (
    <select value={value} onChange={(e) => onChange(e.target.value)} className="focus-ring"
      style={{
        padding: "7px 28px 7px 12px", borderRadius: 8, border: "1px solid var(--line-strong)",
        background: "rgba(255,255,255,0.03)", color: "var(--text)", fontSize: 12,
        fontFamily: "inherit", outline: "none", appearance: "none",
        backgroundImage: "url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%2398A1B8' stroke-width='2.5' stroke-linecap='round'><path d='m6 9 6 6 6-6'/></svg>\")",
        backgroundRepeat: "no-repeat", backgroundPosition: "right 10px center",
      }}>
      {options.map((o) => <option key={o} value={o} style={{ background: "#0F1320" }}>{o}</option>)}
    </select>
  );
}

// =====================================================================
// RISK PAGE — drawdown, daily loss, circuit breaker, kill switches
// =====================================================================
function RiskPage({ accent, scenario, activeExchange = "binance" }) {
  const s = SCENARIOS[scenario] || SCENARIOS.winning;
  const ex = EXCHANGES[activeExchange] || EXCHANGES.binance;
  const checks = [
    { name: "Max concurrent positions",   value: "1 of 1",       status: "ok",   detail: "No pyramiding — new signals queue while open" },
    { name: "Daily loss limit",            value: `−${s.dailyLoss}% / −3.0%`, status: s.dailyLoss >= 2.4 ? "warn" : "ok", detail: "Resets 00:00 UTC · trips circuit breaker" },
    { name: "Signal deduplication",        value: "60s window",   status: "ok",   detail: "Drops same signal_id seen within window" },
    { name: "Min account balance",         value: "$10,000 / $50", status: "ok",  detail: "Rejects trades when below threshold" },
    { name: "Active exchange reachable",   value: ex.name + " · " + ex.rttMs + "ms", status: "ok", detail: "Health check against ACTIVE_EXCHANGE before every order" },
    { name: "Pair available on " + ex.name, value: "BTC/USDT",     status: "ok",   detail: "Symbol catalogue cached at boot · " + ex.nativeSymbol + " native" },
    { name: "Min notional ($10)",          value: "$54.30 avg",   status: "ok",   detail: ex.name + " minimum order value · queried at startup" },
    { name: "Max consecutive losses",      value: "1 of 5",       status: "ok",   detail: "Auto-pauses bot when threshold hit" },
    { name: "Max drawdown (kill switch)",  value: `−${s.drawdown}% / −15.0%`, status: s.drawdown >= 10 ? "warn" : "ok", detail: "Permanent halt — requires manual restart" },
    { name: "Stop-loss placement",         value: ex.stopLoss,    status: ex.oco ? "ok" : "warn", detail: ex.oco ? "OCO survives bot crashes" : "Conditional close — Kraken's OCO equivalent" },
  ];

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--row-gap)" }}>
      {/* Top gauges */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: "var(--row-gap)" }}>
        <Card title="Drawdown" subtitle="Peak-to-trough · kill switch @ −15%">
          <DrawdownGauge value={s.drawdown} max={15} />
          <div className="mono" style={{ textAlign: "center", fontSize: 28, fontWeight: 600, marginTop: -6, color: s.drawdown < 10 ? "var(--profit)" : "var(--warn)" }}>
            −{s.drawdown.toFixed(1)}%
          </div>
          <div style={{ fontSize: 11, color: "var(--text-3)", textAlign: "center", marginTop: 4 }}>peak equity $11,940 · current ${s.equity.toLocaleString()}</div>
        </Card>

        <Card title="Daily loss budget" subtitle="Resets 00:00 UTC · in 11h 42m">
          <div style={{ height: 100, position: "relative" }}>
            <DailyLossMeter used={s.dailyLoss} cap={3.0} />
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginTop: 14, paddingTop: 14, borderTop: "1px solid var(--line)" }}>
            <Metric label="Used" value={"−$" + (s.dailyLoss * 100).toFixed(2)} hint={"−" + s.dailyLoss + "%"} />
            <Metric label="Remaining" value={"$" + ((3 - s.dailyLoss) * 100).toFixed(2)} hint={"−" + (3 - s.dailyLoss).toFixed(2) + "% headroom"} />
          </div>
        </Card>

        <Card title="Circuit breaker" subtitle="Auto-halt triggers">
          <div style={{ padding: 16, borderRadius: 10, background: "rgba(25,229,166,0.06)", border: "1px solid rgba(25,229,166,0.2)", display: "flex", alignItems: "center", gap: 14 }}>
            <div style={{
              width: 48, height: 48, borderRadius: 12, background: "rgba(25,229,166,0.14)",
              display: "flex", alignItems: "center", justifyContent: "center", color: "var(--profit)",
            }}><IconShield size={24} /></div>
            <div>
              <div style={{ fontSize: 13, fontWeight: 600, color: "var(--profit)" }}>● Armed · monitoring</div>
              <div style={{ fontSize: 11, color: "var(--text-3)", marginTop: 2 }}>No trip events in last 7 days</div>
            </div>
          </div>
          <div style={{ marginTop: 14, display: "flex", flexDirection: "column", gap: 8 }}>
            <TripRow label="Daily loss > 3.0%"      armed />
            <TripRow label="Consec losses ≥ 5"      armed count="1/5" />
            <TripRow label="Max drawdown > 15%"     armed />
            <TripRow label="Exchange unreachable"   armed />
          </div>
          <div style={{ marginTop: 14, display: "flex", gap: 8 }}>
            <PrimaryBtn danger icon={<IconBolt size={14} />} style={{ flex: 1, justifyContent: "center" }}>Manual halt</PrimaryBtn>
            <PrimaryBtn ghost icon={<IconRefresh size={14} />} style={{ flex: 1, justifyContent: "center" }}>Reset</PrimaryBtn>
          </div>
        </Card>
      </div>

      {/* Pre-trade checks table */}
      <Card title="Pre-trade validation" subtitle="Runs on every signal · all must pass before order is placed">
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
          {checks.map((c) => {
            const cfg = { ok: { c: "var(--profit)", icon: <IconCheck size={14} /> }, warn: { c: "var(--warn)", icon: <IconAlert size={14} /> }, err: { c: "var(--loss)", icon: <IconX size={14} /> } }[c.status];
            return (
              <div key={c.name} style={{
                padding: 12, borderRadius: 10, background: "rgba(255,255,255,0.02)",
                border: "1px solid var(--line)", display: "flex", alignItems: "flex-start", gap: 12,
              }}>
                <div style={{
                  width: 26, height: 26, borderRadius: 7, flex: "0 0 26px",
                  background: c.status === "ok" ? "rgba(25,229,166,0.12)" : c.status === "warn" ? "rgba(245,166,35,0.12)" : "rgba(242,63,92,0.12)",
                  color: cfg.c, display: "flex", alignItems: "center", justifyContent: "center", marginTop: 1,
                }}>{cfg.icon}</div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ display: "flex", justifyContent: "space-between", gap: 8 }}>
                    <span style={{ fontSize: 13, fontWeight: 500 }}>{c.name}</span>
                    <span className="mono" style={{ fontSize: 11, color: cfg.c, fontWeight: 500 }}>{c.value}</span>
                  </div>
                  <div style={{ fontSize: 11.5, color: "var(--text-3)", marginTop: 3, lineHeight: 1.4 }}>{c.detail}</div>
                </div>
              </div>
            );
          })}
        </div>
      </Card>

      {/* Position sizing */}
      <Card title="Position sizing" subtitle="Fixed-fraction · 1% equity per trade">
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 32 }}>
          <div>
            <div style={{ fontSize: 11, color: "var(--text-3)", letterSpacing: 0.5, textTransform: "uppercase", marginBottom: 10 }}>Formula</div>
            <CodeBlock>
              <span style={{ color: "var(--accent)" }}>position_size</span> = <span style={{ color: "var(--text-2)" }}>(</span>account_balance × risk_pct<span style={{ color: "var(--text-2)" }}>)</span>{"\n"}
              {"               "}÷ stop_loss_distance_pct{"\n\n"}
              <span style={{ color: "var(--text-3)" }}># Current values</span>{"\n"}
              account_balance = <span style={{ color: "var(--profit)" }}>10000.00</span>{"\n"}
              risk_pct        = <span style={{ color: "var(--profit)" }}>0.01</span>  <span style={{ color: "var(--text-3)" }}># 1%</span>{"\n"}
              stop_loss_pct   = <span style={{ color: "var(--profit)" }}>0.02</span>  <span style={{ color: "var(--text-3)" }}># 2%</span>{"\n"}
              position_size   = <span style={{ color: "var(--accent)" }}>$5000.00</span>  <span style={{ color: "var(--text-3)" }}># ~0.078 BTC</span>
            </CodeBlock>
          </div>
          <div>
            <div style={{ fontSize: 11, color: "var(--text-3)", letterSpacing: 0.5, textTransform: "uppercase", marginBottom: 10 }}>Risk per trade</div>
            <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
              <RiskBar label="$ at risk per trade" value={100} cap={100} unit="$" color="var(--accent)" />
              <RiskBar label="Position size cap"   value={5000} cap={8000} unit="$" color="var(--info)" />
              <RiskBar label="Min notional"        value={54}   cap={10} reverse unit="$" color="var(--text-2)" />
              <RiskBar label="Stop distance"       value={2.0}  cap={3.0} unit="%" color="var(--warn)" />
            </div>
            <div style={{ marginTop: 16, padding: 12, borderRadius: 8, background: "rgba(96,165,250,0.06)", border: "1px solid rgba(96,165,250,0.2)", fontSize: 11.5, color: "var(--text-2)", lineHeight: 1.5 }}>
              At 1% risk and 2% stop, you can lose <strong>50 consecutive trades</strong> before hitting the 15% drawdown kill switch. Mathematically robust for noise-driven false signals.
            </div>
          </div>
        </div>
      </Card>
    </div>
  );
}

function DailyLossMeter({ used, cap }) {
  const pct = Math.min(1, used / cap);
  const color = pct < 0.5 ? "var(--profit)" : pct < 0.8 ? "var(--warn)" : "var(--loss)";
  return (
    <div style={{ height: "100%", position: "relative", display: "flex", flexDirection: "column", justifyContent: "center" }}>
      <div style={{ position: "relative", height: 16, background: "rgba(255,255,255,0.05)", borderRadius: 8, overflow: "hidden" }}>
        <div style={{
          position: "absolute", left: 0, top: 0, bottom: 0, width: (pct * 100) + "%",
          background: `linear-gradient(90deg, ${pct < 0.5 ? "var(--profit)" : "var(--warn)"}, ${color})`,
          borderRadius: 8, transition: "width .5s",
        }} />
        {[0.25, 0.5, 0.75].map((t) => (
          <div key={t} style={{ position: "absolute", left: (t * 100) + "%", top: -2, bottom: -2, width: 1, background: "rgba(255,255,255,0.15)" }} />
        ))}
      </div>
      <div className="mono" style={{ display: "flex", justifyContent: "space-between", marginTop: 6, fontSize: 10, color: "var(--text-3)", letterSpacing: 0.4 }}>
        <span>0%</span>
        <span>1.5%</span>
        <span style={{ color: "var(--loss)" }}>3.0% halt</span>
      </div>
    </div>
  );
}

function TripRow({ label, armed, count }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "6px 0", fontSize: 12 }}>
      <span style={{ width: 6, height: 6, borderRadius: 999, background: armed ? "var(--profit)" : "var(--text-3)" }} />
      <span style={{ flex: 1, color: "var(--text-2)" }}>{label}</span>
      {count && <span className="mono" style={{ fontSize: 11, color: "var(--text-3)" }}>{count}</span>}
    </div>
  );
}

function RiskBar({ label, value, cap, unit, color, reverse }) {
  const pct = reverse ? Math.min(1, cap / value) : Math.min(1, value / cap);
  return (
    <div>
      <div style={{ display: "flex", justifyContent: "space-between", fontSize: 11.5, marginBottom: 4 }}>
        <span style={{ color: "var(--text-2)" }}>{label}</span>
        <span className="mono" style={{ color: "var(--text)" }}>{unit === "$" ? unit : ""}{value}{unit !== "$" ? unit : ""} <span style={{ color: "var(--text-3)" }}>/ {unit === "$" ? unit : ""}{cap}{unit !== "$" ? unit : ""} {reverse ? "min" : "max"}</span></span>
      </div>
      <div style={{ height: 6, background: "rgba(255,255,255,0.05)", borderRadius: 3 }}>
        <div style={{ width: (pct * 100) + "%", height: "100%", background: color, borderRadius: 3, transition: "width .4s" }} />
      </div>
    </div>
  );
}

// =====================================================================
// BACKTESTER (v2 feature — preview)
// =====================================================================
function BacktesterPage({ accent }) {
  const equity = upM(() => generateSeries(180, { seed: 5, start: 10000, drift: 0.0024, vol: 0.014 }), []);
  const benchmark = upM(() => generateSeries(180, { seed: 99, start: 10000, drift: 0.0010, vol: 0.018 }), []);
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--row-gap)" }}>
      <div style={{ padding: 14, borderRadius: 10, background: "rgba(96,165,250,0.06)", border: "1px solid rgba(96,165,250,0.2)", display: "flex", alignItems: "center", gap: 12 }}>
        <Badge variant="info">v2 PREVIEW</Badge>
        <div style={{ fontSize: 12, color: "var(--text-2)" }}>
          Backtesting is on the v2 roadmap. This is a preview of what historical strategy validation will look like.
        </div>
      </div>

      {/* Config strip */}
      <Card title="Backtest configuration" subtitle="EMA(9/21) + RSI(14) · 5m timeframe">
        <div style={{ display: "grid", gridTemplateColumns: "repeat(6, 1fr)", gap: 16 }}>
          <ConfigPill label="Pair"        value="BTC/USDT" />
          <ConfigPill label="Period"      value="2025-01-01 → 2026-05-15" />
          <ConfigPill label="Initial"     value="$10,000" />
          <ConfigPill label="Fees"        value="0.10% taker" />
          <ConfigPill label="Slippage"    value="2 bps" />
          <ConfigPill label="Bars"        value="146,520" />
        </div>
      </Card>

      {/* KPI strip */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(6, 1fr)", gap: "var(--row-gap)" }}>
        <Kpi label="Net return"    value="+38.4%" sub="14 months" tone="profit" />
        <Kpi label="vs BTC HODL"   value="+12.1%" sub="alpha" tone="profit" />
        <Kpi label="Sharpe"        value="1.94"  sub="annualized" tone="accent" />
        <Kpi label="Max drawdown"  value="−8.2%" sub="2025-09-14" tone="loss" />
        <Kpi label="Win rate"      value="61%"   sub="248 trades" />
        <Kpi label="Profit factor" value="2.14"  sub="gross W/L" tone="profit" />
      </div>

      {/* Equity */}
      <Card title="Equity curve" subtitle="Strategy vs buy-and-hold BTC">
        <EquityCurve portfolio={equity} benchmark={benchmark} accent={accent.base} h={280}
          yLabel={(v) => "$" + (v / 1000).toFixed(1) + "k"} />
      </Card>

      {/* Monthly + drawdown */}
      <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.4fr) minmax(0, 1fr)", gap: "var(--row-gap)" }}>
        <Card title="Monthly returns" subtitle="Heatmap · greener = better">
          <MonthlyHeatmap data={MONTHLY} />
        </Card>
        <Card title="Run another backtest" subtitle="Quick parameter sweep">
          <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
            <ParamSlider label="Risk per trade" value={1.0} min={0.5} max={3} unit="%" />
            <ParamSlider label="Stop loss"      value={2.0} min={1.0} max={4} unit="%" />
            <ParamSlider label="EMA fast"       value={9}   min={5}   max={20} unit="bars" />
            <ParamSlider label="EMA slow"       value={21}  min={15}  max={50} unit="bars" />
            <PrimaryBtn icon={<IconBolt size={14} />} style={{ marginTop: 8, justifyContent: "center" }}>Run backtest</PrimaryBtn>
          </div>
        </Card>
      </div>
    </div>
  );
}

function ConfigPill({ label, value }) {
  return (
    <div>
      <div style={{ fontSize: 10, color: "var(--text-3)", letterSpacing: 0.5, textTransform: "uppercase", marginBottom: 4 }}>{label}</div>
      <div className="mono" style={{ fontSize: 13, fontWeight: 500 }}>{value}</div>
    </div>
  );
}

function ParamSlider({ label, value, min, max, unit }) {
  const pct = ((value - min) / (max - min)) * 100;
  return (
    <div>
      <div style={{ display: "flex", justifyContent: "space-between", fontSize: 12, marginBottom: 6 }}>
        <span style={{ color: "var(--text-2)" }}>{label}</span>
        <span className="mono" style={{ color: "var(--accent)" }}>{value}{unit}</span>
      </div>
      <div style={{ position: "relative", height: 6, background: "rgba(255,255,255,0.05)", borderRadius: 3 }}>
        <div style={{ width: pct + "%", height: "100%", background: "var(--accent)", borderRadius: 3 }} />
        <div style={{ position: "absolute", left: `calc(${pct}% - 6px)`, top: -4, width: 14, height: 14, borderRadius: 999, background: "var(--accent)", border: "2px solid var(--bg)" }} />
      </div>
    </div>
  );
}

// =====================================================================
// ALERTS / TELEGRAM PAGE
// =====================================================================
function AlertsPage({ accent }) {
  const events = [
    { evt: "trade_opened",       enabled: true,  preview: "🟢 OPENED: LONG BTC/USDT @ 64210.50 | Size: 0.0084 | SL: 62926.30" },
    { evt: "trade_closed",       enabled: true,  preview: "🔴 CLOSED: BTC/USDT @ 64055.40 | P&L: +$28.97 (+0.55%)" },
    { evt: "stop_loss_triggered",enabled: true,  preview: "⛔ STOP LOSS: BTC/USDT @ 63812.50 | Loss: −$101.82" },
    { evt: "daily_limit_hit",    enabled: true,  preview: "🚨 DAILY LOSS LIMIT HIT: −3.02% | Trading halted" },
    { evt: "signal_rejected",    enabled: true,  preview: "⚠️ SIGNAL REJECTED: Position already open" },
    { evt: "error",              enabled: true,  preview: "❌ ERROR: ccxt.NetworkError — connection reset" },
    { evt: "daily_summary",      enabled: true,  preview: "📊 DAILY SUMMARY: Trades: 7 | P&L: +$132.18 | Win rate: 86%" },
    { evt: "bot_startup",        enabled: true,  preview: "🤖 BOT STARTED: Mode: TESTNET | Exchange: Binance | Balance: $10,000.00" },
  ];
  const cmds = [
    { cmd: "/status",  desc: "Bot state, open positions, daily P&L" },
    { cmd: "/balance", desc: "Current account balance from exchange" },
    { cmd: "/today",   desc: "Today's trade summary" },
    { cmd: "/stop",    desc: "Emergency halt — closes positions, stops trading" },
    { cmd: "/resume",  desc: "Resume trading after manual halt" },
  ];

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--row-gap)" }}>
      {/* Connection status */}
      <Card title="Telegram connection" subtitle="@AutoTraderBot · receiving on chat ID 487291**"
        right={<Badge variant="profit">● Connected</Badge>}>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }}>
          <Field2 label="Bot username"  value="@AutoTraderBot" />
          <Field2 label="Chat ID"       value="487291**" mono />
          <Field2 label="Last message"  value="6s ago · trade_opened" />
          <Field2 label="Messages today" value="14" />
        </div>
        <div style={{ marginTop: 16, display: "flex", gap: 8 }}>
          <PrimaryBtn ghost icon={<IconBolt size={14} />}>Send test message</PrimaryBtn>
          <PrimaryBtn ghost icon={<IconRefresh size={14} />}>Reconnect</PrimaryBtn>
          <PrimaryBtn ghost icon={<IconExternal size={14} />} style={{ marginLeft: "auto" }}>Open chat</PrimaryBtn>
        </div>
      </Card>

      {/* Events */}
      <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.6fr) minmax(0, 1fr)", gap: "var(--row-gap)" }}>
        <Card title="Event subscriptions" subtitle="Which events trigger Telegram notifications">
          <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
            {events.map((e) => (
              <div key={e.evt} style={{
                display: "flex", alignItems: "center", gap: 14, padding: "10px 12px",
                background: "rgba(255,255,255,0.02)", border: "1px solid var(--line)", borderRadius: 10,
              }}>
                <Toggle value={e.enabled} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div className="mono" style={{ fontSize: 12, fontWeight: 500, color: "var(--text-2)" }}>{e.evt}</div>
                  <div className="mono" style={{ fontSize: 11, color: "var(--text-3)", marginTop: 3, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{e.preview}</div>
                </div>
                <IconBtn title="Edit template"><IconEdit size={13} /></IconBtn>
              </div>
            ))}
          </div>
        </Card>

        <Card title="Bot commands" subtitle="Telegram → bot via /commands">
          <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
            {cmds.map((c) => (
              <div key={c.cmd} style={{ display: "flex", alignItems: "center", gap: 12, padding: "10px 12px", background: "rgba(255,255,255,0.02)", border: "1px solid var(--line)", borderRadius: 10 }}>
                <code className="mono" style={{ fontSize: 12, padding: "3px 8px", borderRadius: 5, background: "var(--accent-soft)", color: "var(--accent)", fontWeight: 600 }}>{c.cmd}</code>
                <div style={{ fontSize: 12, color: "var(--text-2)" }}>{c.desc}</div>
              </div>
            ))}
          </div>
          <div style={{ marginTop: 14, padding: 12, borderRadius: 8, background: "rgba(245,166,35,0.06)", border: "1px solid rgba(245,166,35,0.2)", fontSize: 11.5, color: "var(--text-2)", display: "flex", gap: 10, alignItems: "flex-start" }}>
            <IconAlert size={14} style={{ color: "var(--warn)", marginTop: 1 }} />
            <span>Only the configured <code className="mono">TELEGRAM_CHAT_ID</code> can execute commands. All others are silently ignored.</span>
          </div>
        </Card>
      </div>

      {/* Daily summary preview */}
      <Card title="Daily summary preview" subtitle="Sent automatically at 23:59 UTC">
        <div style={{
          maxWidth: 480, margin: "0 auto",
          background: "#FFFFFF", borderRadius: 16, padding: 14,
          boxShadow: "0 8px 30px -10px rgba(0,0,0,0.5)", color: "#0A0E1A",
        }}>
          <div style={{ display: "flex", alignItems: "center", gap: 10, paddingBottom: 10, borderBottom: "1px solid #E5E7EB" }}>
            <div style={{ width: 36, height: 36, borderRadius: 999, background: "#26A5E4", display: "flex", alignItems: "center", justifyContent: "center", color: "#fff", fontWeight: 700 }}>AT</div>
            <div style={{ flex: 1 }}>
              <div style={{ fontWeight: 600, fontSize: 14 }}>Auto-Trader Bot</div>
              <div style={{ fontSize: 11, color: "#6B7280" }}>bot · last seen now</div>
            </div>
          </div>
          <div style={{ paddingTop: 14, fontSize: 13, lineHeight: 1.6, fontFamily: "system-ui" }}>
            📊 <strong>DAILY SUMMARY</strong><br/>
            <span style={{ color: "#6B7280" }}>2026-05-15 · UTC</span><br/><br/>
            Trades: <strong>7</strong><br/>
            Wins: <strong style={{ color: "#15A672" }}>6</strong> · Losses: <strong style={{ color: "#E03E58" }}>1</strong><br/>
            Win rate: <strong>86%</strong><br/>
            Net P&amp;L: <strong style={{ color: "#15A672" }}>+$132.18 (+1.13%)</strong><br/>
            Max drawdown: −0.42%
          </div>
        </div>
      </Card>
    </div>
  );
}

function Field2({ label, value, mono }) {
  return (
    <div>
      <div style={{ fontSize: 11, color: "var(--text-3)", letterSpacing: 0.5, textTransform: "uppercase" }}>{label}</div>
      <div className={mono ? "mono" : ""} style={{ fontSize: 14, fontWeight: 500, marginTop: 4 }}>{value}</div>
    </div>
  );
}

// =====================================================================
// LOGS PAGE — structured JSON viewer
// =====================================================================
function LogsPage({ accent }) {
  const [level, setLevel] = upS("All");
  const [type, setType]   = upS("All");
  const types = [...new Set(LOGS.map((l) => l.type))];
  const filtered = LOGS.filter((l) =>
    (level === "All" || l.level === level.toUpperCase()) &&
    (type === "All" || l.type === type)
  );

  // Mock hourly volume data
  const vol = upM(() => Array.from({ length: 24 }, () => Math.floor(Math.random() * 80) + 20), []);

  const counts = {
    INFO:  LOGS.filter((l) => l.level === "INFO").length,
    DEBUG: LOGS.filter((l) => l.level === "DEBUG").length,
    WARN:  LOGS.filter((l) => l.level === "WARN").length,
    ERROR: LOGS.filter((l) => l.level === "ERROR").length,
  };

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--row-gap)" }}>
      {/* Stats + volume */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr) minmax(0, 2fr)", gap: "var(--row-gap)" }}>
        <Kpi label="INFO"  value={counts.INFO.toString()}  sub="last 24h" tone="profit" />
        <Kpi label="DEBUG" value={counts.DEBUG.toString()} sub="API calls" />
        <Kpi label="WARN"  value={counts.WARN.toString()}  sub="dedup, rejects" tone="warn" />
        <Kpi label="ERROR" value={counts.ERROR.toString()} sub="halts, failures" tone="loss" />
        <Card title="Log volume" subtitle="Last 24h · hourly" style={{ gridColumn: "auto" }}>
          <LogVolumeChart data={vol} h={70} accent={accent.base} />
        </Card>
      </div>

      {/* Filters */}
      <Card title="Log stream" subtitle="Structured JSON · stored locally · rotates @ 50MB / 30 days"
        right={
          <div style={{ display: "flex", gap: 8 }}>
            <Select value={level} onChange={setLevel} options={["All", "INFO", "DEBUG", "WARN", "ERROR"]} />
            <Select value={type}  onChange={setType}  options={["All", ...types]} />
            <PrimaryBtn ghost icon={<IconDown size={14} />}>Download log</PrimaryBtn>
          </div>
        }
        padded={false}>
        <div style={{ background: "#06080F", padding: "12px 0", maxHeight: 480, overflowY: "auto", fontFamily: "JetBrains Mono", fontSize: 12 }}>
          {filtered.map((l, i) => <LogLine key={i} log={l} />)}
        </div>
      </Card>
    </div>
  );
}

function LogLine({ log }) {
  const [open, setOpen] = upS(false);
  const levelCfg = {
    INFO:  { c: "#60A5FA", bg: "rgba(96,165,250,0.10)" },
    DEBUG: { c: "var(--text-3)", bg: "rgba(255,255,255,0.03)" },
    WARN:  { c: "var(--warn)", bg: "rgba(245,166,35,0.10)" },
    ERROR: { c: "var(--loss)", bg: "rgba(242,63,92,0.10)" },
  }[log.level];
  const t = fmtTime(log.t);
  return (
    <div onClick={() => setOpen(!open)} style={{ padding: "6px 24px", display: "flex", gap: 12, cursor: "pointer", borderLeft: "2px solid " + levelCfg.c, lineHeight: 1.5 }}>
      <span style={{ color: "var(--text-3)", flex: "0 0 80px" }}>{t}</span>
      <span style={{ color: levelCfg.c, flex: "0 0 50px", fontWeight: 600, fontSize: 10.5, padding: "1px 6px", borderRadius: 3, background: levelCfg.bg, textAlign: "center", height: 18 }}>{log.level}</span>
      <span style={{ color: "var(--accent)", flex: "0 0 180px" }}>{log.type}</span>
      <span style={{ color: "var(--text-2)", flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: open ? "normal" : "nowrap" }}>
        {log.msg}
        {open && Object.keys(log.ctx).length > 0 && (
          <div style={{ marginTop: 6, paddingLeft: 16, color: "var(--text-3)" }}>
            {Object.entries(log.ctx).map(([k, v]) => (
              <div key={k}>{k}: <span style={{ color: "#FCD34D" }}>{JSON.stringify(v)}</span></div>
            ))}
          </div>
        )}
      </span>
    </div>
  );
}

// =====================================================================
// ROADMAP / BUILD PAGE — project task board, v1/v2/v3 timeline, changelog
// =====================================================================
function RoadmapPage({ accent }) {
  const total = TASKS.length;
  const done = TASKS.filter((t) => t.status === "done").length;
  const wip  = TASKS.filter((t) => t.status === "in-progress").length;
  const pend = TASKS.filter((t) => t.status === "pending").length;
  const pct  = Math.round((done / total) * 100);

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "var(--row-gap)" }}>
      {/* Spec banner */}
      <div style={{ display: "flex", alignItems: "center", gap: 14, padding: "14px 18px", borderRadius: 12, background: "linear-gradient(90deg, rgba(124,92,255,0.10), rgba(0,212,170,0.06))", border: "1px solid var(--line)" }}>
        <div style={{ width: 40, height: 40, borderRadius: 10, background: "rgba(124,92,255,0.18)", color: "#A78BFA", display: "flex", alignItems: "center", justifyContent: "center" }}>
          <IconLayers size={20} />
        </div>
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 13.5, fontWeight: 600 }}>spec v3.0 · MVP V1.1 · Dubai</div>
          <div style={{ fontSize: 11.5, color: "var(--text-3)", marginTop: 3 }}>
            <span className="mono">aminbassam/Auto-Trader</span> · last updated 2026-05-15 · {total} tasks across {TASK_CATEGORIES.length} categories
          </div>
        </div>
        <PrimaryBtn ghost icon={<IconExternal size={13} />}>Open repo</PrimaryBtn>
        <PrimaryBtn ghost icon={<IconDown size={13} />}>Download spec.json</PrimaryBtn>
      </div>

      {/* KPI strip with progress card */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(4, minmax(0, 1fr)) minmax(0, 2.6fr)", gap: "var(--row-gap)" }}>
        <Kpi label="Done"        value={done.toString()} sub={pct + "% complete"} tone="profit" />
        <Kpi label="In progress" value={wip.toString()}  sub="open work" tone="accent" />
        <Kpi label="Pending"     value={pend.toString()} sub="not started" />
        <Kpi label="Total tasks" value={total.toString()} sub="v3.0 plan" />
        <Card title="Overall progress" subtitle={done + " of " + total + " complete · " + wip + " in flight"}>
          <CategoryProgressStack />
        </Card>
      </div>

      {/* Task board grouped by category */}
      <Card title="Task board" subtitle="37-task v1.1 build plan · grouped by module">
        <div style={{ display: "flex", flexDirection: "column", gap: 22 }}>
          {TASK_CATEGORIES.map((cat) => {
            const tasks = TASKS.filter((t) => t.cat === cat.id);
            if (!tasks.length) return null;
            const catDone = tasks.filter((t) => t.status === "done").length;
            return (
              <div key={cat.id}>
                <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 10 }}>
                  <span style={{ width: 10, height: 10, borderRadius: 3, background: cat.color }} />
                  <span style={{ fontSize: 13, fontWeight: 600 }}>{cat.label}</span>
                  <span className="mono" style={{ fontSize: 11, color: "var(--text-3)" }}>{catDone} / {tasks.length}</span>
                  <div style={{ flex: 1, height: 4, background: "rgba(255,255,255,0.04)", borderRadius: 2, overflow: "hidden", maxWidth: 240 }}>
                    <div style={{ width: ((catDone / tasks.length) * 100) + "%", height: "100%", background: cat.color, borderRadius: 2 }} />
                  </div>
                </div>
                <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(320px, 1fr))", gap: 8 }}>
                  {tasks.map((t) => <TaskCard key={t.id} task={t} color={cat.color} />)}
                </div>
              </div>
            );
          })}
        </div>
      </Card>

      {/* Roadmap timeline v1/v2/v3 */}
      <Card title="Roadmap" subtitle="Three-phase delivery plan from spec v3.0">
        <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 14 }}>
          {ROADMAP.map((r) => <RoadmapColumn key={r.v} phase={r} />)}
        </div>
      </Card>

      {/* Changelog */}
      <Card title="Spec changelog" subtitle="Newest first · sourced from spec _changelog">
        <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
          {CHANGELOG.map((c, i) => (
            <div key={i} style={{ display: "grid", gridTemplateColumns: "180px 1fr", gap: 18, paddingBottom: i === CHANGELOG.length - 1 ? 0 : 18, borderBottom: i === CHANGELOG.length - 1 ? 0 : "1px solid var(--line)" }}>
              <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
                <span className="mono" style={{ fontSize: 12, color: "var(--text)", fontWeight: 600 }}>{c.version}</span>
                <span className="mono" style={{ fontSize: 10.5, color: "var(--text-3)" }}>{c.date}</span>
                <span><Badge variant="info">{c.agent}</Badge></span>
              </div>
              <div>
                <div style={{ fontSize: 13, fontWeight: 500, marginBottom: 8 }}>{c.summary}</div>
                <ul style={{ margin: 0, padding: 0, listStyle: "none", display: "flex", flexDirection: "column", gap: 6 }}>
                  {c.highlights.map((h, j) => (
                    <li key={j} style={{ fontSize: 12, color: "var(--text-2)", display: "flex", gap: 10, lineHeight: 1.55 }}>
                      <span style={{ color: "var(--accent)", flex: "0 0 8px", marginTop: 7 }}>·</span>
                      <span>{h}</span>
                    </li>
                  ))}
                </ul>
              </div>
            </div>
          ))}
        </div>
      </Card>
    </div>
  );
}

function CategoryProgressStack() {
  const total = TASKS.length;
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
      <div style={{ display: "flex", height: 12, borderRadius: 6, overflow: "hidden", background: "rgba(255,255,255,0.04)" }}>
        {TASK_CATEGORIES.map((cat) => {
          const done = TASKS.filter((t) => t.cat === cat.id && t.status === "done").length;
          const w = (done / total) * 100;
          if (w === 0) return null;
          return <div key={cat.id} title={cat.label + ": " + done + " done"} style={{ width: w + "%", background: cat.color }} />;
        })}
      </div>
      <div style={{ display: "flex", flexWrap: "wrap", gap: 12 }}>
        {TASK_CATEGORIES.map((cat) => {
          const tasks = TASKS.filter((t) => t.cat === cat.id);
          if (!tasks.length) return null;
          const done = tasks.filter((t) => t.status === "done").length;
          return (
            <span key={cat.id} style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: 11, color: "var(--text-2)" }}>
              <span style={{ width: 8, height: 8, borderRadius: 2, background: cat.color }} />
              {cat.label} <span className="mono" style={{ color: "var(--text-3)" }}>{done}/{tasks.length}</span>
            </span>
          );
        })}
      </div>
    </div>
  );
}

function TaskCard({ task, color }) {
  const statusCfg = {
    "done":        { c: "var(--profit)", bg: "rgba(25,229,166,0.06)", lbl: "done",   icon: <IconCheck size={12} /> },
    "in-progress": { c: "var(--accent)", bg: "rgba(0,212,170,0.08)",  lbl: "in flight", icon: <IconBolt size={11} /> },
    "pending":     { c: "var(--text-3)", bg: "rgba(255,255,255,0.025)", lbl: "pending", icon: <span style={{ width: 7, height: 7, borderRadius: 999, border: "1.4px solid currentColor" }} /> },
  }[task.status];
  return (
    <div style={{
      padding: "10px 12px", borderRadius: 9, background: statusCfg.bg,
      border: "1px solid var(--line)", borderLeft: "2px solid " + color,
      display: "flex", alignItems: "flex-start", gap: 10, minWidth: 0,
    }}>
      <div style={{
        width: 22, height: 22, borderRadius: 6, flex: "0 0 22px", color: statusCfg.c,
        background: "rgba(255,255,255,0.04)", display: "flex", alignItems: "center", justifyContent: "center",
      }}>{statusCfg.icon}</div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <code className="mono" style={{ fontSize: 10, color: "var(--text-3)", letterSpacing: 0.4 }}>{task.id}</code>
          <span style={{ fontSize: 9.5, color: statusCfg.c, fontWeight: 700, letterSpacing: 0.5, textTransform: "uppercase" }}>{statusCfg.lbl}</span>
        </div>
        <div style={{ fontSize: 12.5, color: task.status === "pending" ? "var(--text-2)" : "var(--text)", marginTop: 3, lineHeight: 1.4 }}>{task.task}</div>
      </div>
    </div>
  );
}

function RoadmapColumn({ phase }) {
  const accentColor = phase.status === "in-progress" ? "var(--accent)" : phase.status === "planned" ? "#60A5FA" : "#A78BFA";
  return (
    <div style={{
      padding: 16, borderRadius: 12,
      background: phase.current ? "rgba(0,212,170,0.04)" : "rgba(255,255,255,0.02)",
      border: "1px solid " + (phase.current ? "rgba(0,212,170,0.25)" : "var(--line)"),
      display: "flex", flexDirection: "column", gap: 14,
    }}>
      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
        <span className="mono" style={{
          padding: "3px 10px", borderRadius: 6, fontSize: 12, fontWeight: 700, letterSpacing: 0.4,
          background: accentColor, color: "#06150F",
        }}>{phase.v.toUpperCase()}</span>
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 13, fontWeight: 600 }}>{phase.name}</div>
          <div style={{ fontSize: 11, color: "var(--text-3)", marginTop: 2 }}>{phase.timeline}</div>
        </div>
        {phase.current && <Badge variant="accent">● NOW</Badge>}
      </div>
      <ul style={{ margin: 0, padding: 0, listStyle: "none", display: "flex", flexDirection: "column", gap: 7 }}>
        {phase.features.map((f, i) => (
          <li key={i} style={{ fontSize: 12, color: "var(--text-2)", display: "flex", gap: 8, lineHeight: 1.5 }}>
            <span style={{ color: accentColor, flex: "0 0 10px", marginTop: 7, fontWeight: 700 }}>·</span>
            <span>{f}</span>
          </li>
        ))}
      </ul>
    </div>
  );
}

Object.assign(window, {
  SignalsPage, TradesPage, RiskPage, BacktesterPage, AlertsPage, LogsPage, RoadmapPage,
});
