/* Dashboard — KPIs, income/expense chart, category breakdown, recent transactions */

const Dashboard = ({ goTo, profile, txState, accountState, payoutsState, channelState, backendOnline }) => {
  // When backend is online use real data; fall back to mock data for offline/demo mode
  const transactions = (backendOnline && txState) ? txState : window.CB_DATA.transactions;
  const allChannels = backendOnline ? (channelState || []) : (window.CB_DATA.channel ? [window.CB_DATA.channel] : []);
  const [selectedChannelId, setSelectedChannelId] = React.useState(() => localStorage.getItem("cb_dash_channel") || null);
  const channel = React.useMemo(() => {
    if (allChannels.length === 0) return null;
    if (selectedChannelId) { const found = allChannels.find(c => c.id === selectedChannelId); if (found) return found; }
    const primary = allChannels.find(c => c.primary);
    return primary || allChannels[0];
  }, [allChannels, selectedChannelId]);
  const switchChannel = (id) => { setSelectedChannelId(id); localStorage.setItem("cb_dash_channel", id); };
  const [channelInsightsOpen, setChannelInsightsOpen] = React.useState(false);
  const [taxBreakdownOpen, setTaxBreakdownOpen] = React.useState(false);

  // ── Tax computation from profile ──
  const taxInfo = React.useMemo(() => {
    const countries = window.COUNTRIES || [];
    const code = profile?.countryCode || profile?.country || "US";
    const c = countries.find(x => x.code === code) || countries[0];
    if (!c) return null;
    const entId = profile?.businessEntityId;
    const entity = (entId && c.entities.find(e => e.id === entId)) || c.entities[0];
    const rate = entity.rate;

    // Find next upcoming deadline
    const today = new Date();
    const year = today.getFullYear();
    let nextPayment = null;
    for (const p of (c.schedule?.payments || [])) {
      // Parse due date like "Jun 15", "Apr 25 / Jul 25 / Oct 25 / Jan 25", "Jan 31"
      const dues = p.due.split("/").map(s => s.trim());
      for (const d of dues) {
        const parsed = new Date(d + ", " + year);
        if (isNaN(parsed.getTime())) continue;
        if (parsed >= today && (!nextPayment || parsed < nextPayment.date)) {
          nextPayment = { date: parsed, label: p.q, due: d, note: p.note };
        }
      }
      // Also try next year for wrap-around (e.g. "Jan 15 (next year)")
      for (const d of dues) {
        const clean = d.replace(/\(.*\)/, "").trim();
        const parsed = new Date(clean + ", " + (year + 1));
        if (isNaN(parsed.getTime())) continue;
        if (parsed >= today && (!nextPayment || parsed < nextPayment.date)) {
          nextPayment = { date: parsed, label: p.q, due: clean, note: p.note };
        }
      }
    }

    const paymentsCount = c.schedule?.payments?.length || 4;
    const totalTax = ytdNet > 0 ? ytdNet * rate : 0;
    const perPayment = totalTax / paymentsCount;

    return { country: c, entity, rate, ratePct: (rate * 100).toFixed(1) + "%", rateNote: entity.rateNote, nextPayment, totalTax, perPayment, paymentsCount, schedule: c.schedule };
  }, [profile, ytdNet]);

  // Compute monthly buckets from real transactions when online
  const monthly = React.useMemo(() => {
    if (!backendOnline || !txState) return window.CB_DATA.monthly;
    const result = {};
    transactions.forEach(t => {
      const m = t.date ? t.date.slice(0, 7) : null;
      if (!m) return;
      if (!result[m]) result[m] = { income: 0, expense: 0, byCat: {} };
      // Normalize to USD using stored historical rate (or live fallback)
      const usdAmt = CB.txToUSD(t);
      result[m][t.type] = (result[m][t.type] || 0) + usdAmt;
      if (t.category) {
        result[m].byCat[t.category] = (result[m].byCat[t.category] || 0) + usdAmt;
      }
    });
    return result;
  }, [transactions, backendOnline]);

  const months = CB.monthRange(7);

  // First name pulled from profile — falls back to "there"
  const firstName = (profile?.ownerName || "").trim().split(/\s+/)[0] || "there";

  // ── Customizable dashboard state ──
  // Order + hidden set are persisted to localStorage so they survive reloads.
  const DEFAULT_ORDER = ["kpis", "chart", "pendingPayouts", "donut", "recent", "incomeMix", "channel", "taxCallout"];
  const [editing, setEditing] = React.useState(false);
  const [order, setOrder] = React.useState(() => {
    try {
      const raw = localStorage.getItem("cb_dash_order");
      if (raw) {
        const parsed = JSON.parse(raw);
        // Filter out unknown IDs (handles old saves with removed cards).
        const known = parsed.filter(id => DEFAULT_ORDER.includes(id));
        // For any DEFAULT_ORDER card the user doesn't have yet, insert it at
        // its default-order position rather than appending at the end — so
        // adding a new card (e.g. "pendingPayouts") slots into the intended
        // layout, not the bottom of a customized list.
        const out = [...known];
        for (const id of DEFAULT_ORDER) {
          if (out.includes(id)) continue;
          const defaultIdx = DEFAULT_ORDER.indexOf(id);
          // Find the position to insert at — after the last known card that
          // precedes this one in DEFAULT_ORDER.
          let insertAt = out.length;
          for (let i = defaultIdx - 1; i >= 0; i--) {
            const prevId = DEFAULT_ORDER[i];
            const pos = out.indexOf(prevId);
            if (pos >= 0) { insertAt = pos + 1; break; }
          }
          out.splice(insertAt, 0, id);
        }
        return out;
      }
    } catch {}
    return DEFAULT_ORDER;
  });
  const [hidden, setHidden] = React.useState(() => {
    try { return new Set(JSON.parse(localStorage.getItem("cb_dash_hidden") || "[]")); }
    catch { return new Set(); }
  });
  React.useEffect(() => { localStorage.setItem("cb_dash_order", JSON.stringify(order)); }, [order]);
  React.useEffect(() => { localStorage.setItem("cb_dash_hidden", JSON.stringify([...hidden])); }, [hidden]);

  const moveCard = (fromId, toId) => {
    if (fromId === toId) return;
    setOrder(o => {
      const a = [...o];
      const fi = a.indexOf(fromId);
      const ti = a.indexOf(toId);
      if (fi < 0 || ti < 0) return o;
      a.splice(fi, 1);
      a.splice(ti, 0, fromId);
      return a;
    });
  };
  const hide = (id) => setHidden(h => { const n = new Set(h); n.add(id); return n; });
  const show = (id) => setHidden(h => { const n = new Set(h); n.delete(id); return n; });
  const resetLayout = () => { setOrder(DEFAULT_ORDER); setHidden(new Set()); };

  // Base currency for display. All amounts in the data set are stored in USD,
  // so we convert at render time so flipping the setting refreshes everything.
  const baseCur = profile?.baseCurrency || "USD";
  const fc = (n, opts) => CB.fmtCur(CB.convert(n, "USD", baseCur), baseCur, opts || {});
  const fcNoCents = (n) => CB.fmtCur(CB.convert(n, "USD", baseCur), baseCur, { cents: false });

  // Current month + previous month
  const curKey = months[months.length - 1];
  const prevKey = months[months.length - 2];
  const cur = monthly[curKey] || { income: 0, expense: 0, byCat: {} };
  const prev = monthly[prevKey] || { income: 0, expense: 0, byCat: {} };
  const curLabel = CB.monthLabel(curKey, true); // e.g. "May"

  const netCur = cur.income - cur.expense;
  const netPrev = prev.income - prev.expense;

  const delta = (a, b) => (b === 0 ? 0 : ((a - b) / b) * 100);

  const incomeData = months.map(m => monthly[m]?.income || 0);
  const expenseData = months.map(m => monthly[m]?.expense || 0);
  const netData = months.map(m => (monthly[m]?.income || 0) - (monthly[m]?.expense || 0));

  // YTD
  const yearStart = curKey.slice(0, 4) + "-01";
  const ytdMonths = Object.keys(monthly).filter(k => k >= yearStart).sort();
  const ytdIncome = ytdMonths.reduce((s, k) => s + monthly[k].income, 0);
  const ytdExpense = ytdMonths.reduce((s, k) => s + monthly[k].expense, 0);
  const ytdNet = ytdIncome - ytdExpense;

  // Top income categories this month
  const incomeCats = CB_DATA.categories.income.map(c => ({
    ...c,
    value: cur.byCat[c.id] || 0,
  })).filter(c => c.value > 0).sort((a, b) => b.value - a.value);

  const expenseCats = CB_DATA.categories.expense.map(c => ({
    ...c,
    value: cur.byCat[c.id] || 0,
  })).filter(c => c.value > 0).sort((a, b) => b.value - a.value);

  const expenseTotal = expenseCats.reduce((s, c) => s + c.value, 0) || 1;

  // Recent transactions
  const recent = transactions.slice(0, 6);

  // Hero net (current month)
  const heroDelta = delta(netCur, netPrev);

  // ── Simple computed greeting line ──
  // Skips the AI roundtrip; deterministic, fast, in the user's base currency.
  const insightLine =
    netPrev === 0
      ? `Your net profit this month is ${fc(netCur, { cents: false })}.`
      : heroDelta >= 0
        ? `Your net profit jumped ${heroDelta.toFixed(0)}% to ${fc(netCur, { cents: false })} this month.`
        : `Your net profit is down ${Math.abs(heroDelta).toFixed(0)}% to ${fc(netCur, { cents: false })} this month.`;

  return (
    <div className="page-fade">
      <div className="page-head">
        <div style={{ flex: 1 }}>
          <h1 className="page-title">
            Hey {firstName}, here's the month
          </h1>
          <div className="page-sub" style={{ display: "flex", alignItems: "center", gap: 8 }}>
            <Icon name="sparkles" size={13} color="var(--primary)" />
            <span>{insightLine}</span>
          </div>
        </div>
        <div className="page-actions">
          <button className="btn"><Icon name="refresh" size={14} /> Sync now</button>
          <button className="btn" onClick={() => goTo("reports")}>
            <Icon name="reports" size={14} /> View reports
          </button>
          <button className={"btn " + (editing ? "btn-primary" : "")} onClick={() => setEditing(e => !e)}>
            <Icon name={editing ? "check" : "sliders"} size={14} /> {editing ? "Done" : "Customize"}
          </button>
          <button className="btn btn-primary" onClick={() => goTo("ledger", { addTx: true })}>
            <Icon name="plus" size={14} /> Add transaction
          </button>
        </div>
      </div>

      {editing && (
        <div style={{
          background: "var(--primary-soft)", color: "var(--primary-ink)",
          border: "1px solid var(--primary)", borderRadius: 12,
          padding: "12px 16px", marginBottom: 16,
          display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap",
        }}>
          <Icon name="sliders" size={16} />
          <div style={{ flex: 1, fontSize: 13 }}>
            <b>Customizing your dashboard.</b> Drag any card to reorder. Click ✕ to hide a card. Hidden cards appear at the bottom — click + to bring them back.
          </div>
          <button className="btn btn-sm" onClick={resetLayout}>
            <Icon name="refresh" size={11} /> Reset
          </button>
          <button className="btn btn-sm btn-primary" onClick={() => setEditing(false)}>Done</button>
        </div>
      )}

      <DashCanvas
        editing={editing}
        order={order}
        hidden={hidden}
        onMove={moveCard}
        onHide={hide}
        onShow={show}
        cardLabels={{
          kpis: "KPI cards",
          chart: "Income vs expenses chart",
          pendingPayouts: "Pending payouts",
          donut: "Expense breakdown donut",
          recent: "Recent transactions",
          incomeMix: "Income mix",
          channel: "Channel info",
          taxCallout: "Tax callout",
        }}
        renderCard={(id) => {
          if (id === "kpis") return (
            <div className="kpi-grid" style={{ marginBottom: 0 }}>
              <div className="kpi hero">
                <div className="kpi-label">Net this month</div>
                <div>
                  <div className="bignum">
                    {fc(netCur).split(".")[0]}<span className="cents">.{fc(netCur).split(".")[1] || "00"}</span>
                  </div>
                  <span className={"delta " + (heroDelta >= 0 ? "up" : "down")}
                        style={{ marginTop: 6, color: heroDelta >= 0 ? "oklch(0.8 0.14 155)" : "oklch(0.75 0.16 28)" }}>
                    <Icon name={heroDelta >= 0 ? "arrowUp" : "arrowDown"} size={12} />
                    {Math.abs(heroDelta).toFixed(1)}% vs {CB.monthLabel(prevKey, true)}
                  </span>
                </div>
                <div style={{ color: "oklch(0.78 0.01 70)", fontSize: 12, marginTop: "auto", paddingTop: 12 }}>
                  Last month net: {fc(netPrev)}
                </div>
                <Sparkline values={netData} color="oklch(0.85 0.12 80)" height={40} />
              </div>
              <div className="kpi">
                <div className="kpi-label">Income · {curLabel}</div>
                <div className="bignum-sm">{fcNoCents(cur.income)}</div>
                <span className={"delta " + (delta(cur.income, prev.income) >= 0 ? "up" : "down")}>
                  <Icon name={delta(cur.income, prev.income) >= 0 ? "arrowUp" : "arrowDown"} size={11} />
                  {Math.abs(delta(cur.income, prev.income)).toFixed(1)}% MoM
                </span>
                <Sparkline values={incomeData} color="var(--income)" height={32} />
              </div>
              <div className="kpi">
                <div className="kpi-label">Expenses · {curLabel}</div>
                <div className="bignum-sm">{fcNoCents(cur.expense)}</div>
                <span className={"delta " + (delta(cur.expense, prev.expense) <= 0 ? "up" : "down")}>
                  <Icon name={delta(cur.expense, prev.expense) <= 0 ? "arrowDown" : "arrowUp"} size={11} />
                  {Math.abs(delta(cur.expense, prev.expense)).toFixed(1)}% MoM
                </span>
                <Sparkline values={expenseData} color="var(--expense)" height={32} />
              </div>
              <div className="kpi">
                <div className="kpi-label">YTD Net · {curKey.slice(0, 4)}</div>
                <div className="bignum-sm">{fcNoCents(ytdNet)}</div>
                <span className="delta up">
                  <Icon name="arrowUp" size={11} />
                  Margin {((ytdNet / Math.max(ytdIncome, 1)) * 100).toFixed(0)}%
                </span>
                <div style={{ fontSize: 11, color: "var(--muted)", marginTop: 6 }}>
                  Est. quarterly tax due: <b style={{ color: "var(--ink)" }}>{fcNoCents(ytdNet * 0.27)}</b>
                </div>
              </div>
            </div>
          );

          if (id === "chart") return <ChartCard transactions={transactions} baseCur={baseCur} backendOnline={backendOnline} />;

          if (id === "pendingPayouts") return <PendingPayoutsCard fc={fc} fcNoCents={fcNoCents} backendOnline={backendOnline} payoutsState={payoutsState} />;

          if (id === "donut") return (
            <div className="card">
              <div className="kpi-label">Where it went</div>
              <div style={{ fontFamily: "var(--font-display)", fontSize: 22, margin: "4px 0 16px" }}>
                Expenses this month
              </div>
              <div style={{ display: "flex", gap: 18, alignItems: "center" }}>
                <Donut size={150} slices={expenseCats.map(c => ({ value: c.value, color: c.color }))} />
                <div style={{ flex: 1 }}>
                  <div className="bignum-sm" style={{ color: "var(--expense)" }}>{fcNoCents(cur.expense)}</div>
                  <div style={{ fontSize: 11, color: "var(--muted)", marginTop: 2 }}>
                    across {expenseCats.length} categories
                  </div>
                </div>
              </div>
              <div style={{ marginTop: 14 }}>
                {expenseCats.slice(0, 5).map(c => (
                  <div key={c.id} style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "5px 0", fontSize: 13 }}>
                    <span style={{ display: "flex", alignItems: "center", gap: 8 }}>
                      <span className="cat-swatch" style={{ background: c.color }} />
                      {c.name}
                    </span>
                    <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--ink-soft)" }}>
                      {((c.value / expenseTotal) * 100).toFixed(0)}% · {fcNoCents(c.value)}
                    </span>
                  </div>
                ))}
              </div>
            </div>
          );

          if (id === "recent") return (
            <div className="card">
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
                <div>
                  <div className="kpi-label">Recent activity</div>
                  <div style={{ fontFamily: "var(--font-display)", fontSize: 22, margin: "4px 0 14px" }}>
                    Latest transactions
                  </div>
                </div>
                <button className="btn btn-ghost btn-sm" onClick={() => goTo("ledger")}>
                  View all <Icon name="chevronRight" size={12} />
                </button>
              </div>
              <table className="tbl">
                <tbody>
                  {recent.map(tx => {
                    const cat = CB.catById(tx.category);
                    return (
                      <tr key={tx.id} className="row-clickable" onClick={() => goTo("ledger")}>
                        <td style={{ width: 40, paddingRight: 0 }}>
                          <span style={{
                            display: "inline-flex", width: 32, height: 32, borderRadius: 10,
                            background: tx.type === "income" ? "var(--income-soft)" : "var(--surface-2)",
                            alignItems: "center", justifyContent: "center",
                            color: tx.type === "income" ? "var(--income-text-strong)" : "var(--ink-soft)",
                          }}>
                            <Icon name={tx.type === "income" ? "arrowDown" : "arrowUp"} size={14} />
                          </span>
                        </td>
                        <td>
                          <div style={{ fontWeight: 500 }}>{tx.vendor}</div>
                          <div style={{ fontSize: 12, color: "var(--muted)" }}>
                            {cat?.name ?? "Uncategorized"} · {new Date(tx.date).toLocaleDateString("en-US", { month: "short", day: "numeric" })}
                          </div>
                        </td>
                        <td className="num">
                          <span className={tx.type === "income" ? "amt-income" : "amt-expense"}>
                            {tx.type === "income" ? "+" : "−"}{fc(CB.txToUSD(tx))}
                          </span>
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          );

          if (id === "incomeMix") return (
            <div className="card">
              <div className="kpi-label">Income mix</div>
              <div style={{ fontFamily: "var(--font-display)", fontSize: 22, margin: "4px 0 14px" }}>This month</div>
              {incomeCats.map(c => {
                const pct = (c.value / cur.income) * 100;
                return (
                  <div key={c.id} style={{ marginBottom: 12 }}>
                    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 4 }}>
                      <span style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 13.5 }}>
                        <span className="cat-swatch" style={{ background: c.color }} />
                        {c.name}
                      </span>
                      <span style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--ink-soft)" }}>
                        {fcNoCents(c.value)}
                      </span>
                    </div>
                    <div className="cat-bar">
                      <div style={{ background: c.color, width: pct + "%" }} />
                    </div>
                  </div>
                );
              })}
              <div style={{ borderTop: "1px solid var(--hairline)", paddingTop: 12, marginTop: 14, display: "flex", justifyContent: "space-between" }}>
                <span style={{ fontSize: 13, color: "var(--ink-soft)" }}>Total income</span>
                <span style={{ fontFamily: "var(--font-display)", fontSize: 20 }}>{fcNoCents(cur.income)}</span>
              </div>
            </div>
          );

          if (id === "channel") {
            if (!channel) return (
              <div className="card" style={{ background: "var(--surface-2)", textAlign: "center", padding: "28px 20px" }}>
                <Icon name="youtube" size={28} style={{ opacity: 0.3, marginBottom: 10 }} />
                <div style={{ fontWeight: 600, marginBottom: 6 }}>No channel connected</div>
                <div style={{ fontSize: 13, color: "var(--muted)", marginBottom: 14 }}>Connect your YouTube channel to see analytics here</div>
                <button className="btn btn-sm" onClick={() => { localStorage.setItem("yt_open_channel_tab", "1"); goTo("settings"); }}>Connect channel</button>
              </div>
            );
            const avatarSrc = channel.avatarUrl || (channel.avatar && channel.avatar.startsWith("http") ? channel.avatar : null);
            const avatarInitials = (() => {
              if (channel.avatar && !channel.avatar.startsWith("http")) return channel.avatar;
              const p = (channel.name || "").trim().split(/\s+/).filter(Boolean);
              if (p.length >= 2) return (p[0][0] + p[p.length - 1][0]).toUpperCase();
              if (p.length === 1) return p[0].slice(0, 2).toUpperCase();
              return "YT";
            })();
            return (
              <React.Fragment>
              <div className="card" style={{ background: "var(--surface-2)" }}>
                <div style={{ display: "flex", alignItems: "center", gap: 16 }}>
                  {avatarSrc ? (
                    <img src={avatarSrc} alt="" style={{ width: 56, height: 56, borderRadius: 16, objectFit: "cover" }} />
                  ) : (
                    <div style={{
                      width: 56, height: 56, borderRadius: 16,
                      background: "linear-gradient(135deg, var(--primary), oklch(0.55 0.16 320))",
                      display: "grid", placeItems: "center", color: "white", fontFamily: "var(--font-display)", fontSize: 22,
                    }}>
                      {avatarInitials}
                    </div>
                  )}
                  <div style={{ flex: 1 }}>
                    <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                      <span style={{ fontFamily: "var(--font-display)", fontSize: 22 }}>{channel.name}</span>
                      <Pill kind="primary" dot>Connected</Pill>
                    </div>
                    <div style={{ color: "var(--muted)", fontSize: 13 }}>
                      {channel.handle} · {channel.kind} · {(channel.subs / 1000).toFixed(1)}k subscribers · {channel.videos} videos
                    </div>
                  </div>
                  <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                    {allChannels.length > 1 && (
                      <select
                        value={channel.id}
                        onChange={e => switchChannel(e.target.value)}
                        style={{
                          background: "var(--surface)", border: "1px solid var(--border,#e8e0d8)",
                          borderRadius: 8, padding: "6px 10px", fontSize: 12.5,
                          color: "var(--ink)", cursor: "pointer", fontFamily: "var(--font-ui)",
                        }}
                      >
                        {allChannels.map(ch => (
                          <option key={ch.id} value={ch.id}>{ch.name}</option>
                        ))}
                      </select>
                    )}
                    <button className="btn btn-sm" onClick={() => setChannelInsightsOpen(true)}>Channel insights <Icon name="chevronRight" size={12} /></button>
                  </div>
                </div>
              </div>
              {channelInsightsOpen && ReactDOM.createPortal(<ChannelInsightsModal channel={channel} fc={fc} fcNoCents={fcNoCents} onClose={() => setChannelInsightsOpen(false)} />, document.body)}
              </React.Fragment>
            );
          }

          if (id === "taxCallout") {
            if (!taxInfo) return null;
            const np = taxInfo.nextPayment;
            const headline = np
              ? `${np.label} tax due ${np.due}`
              : `Estimated tax — ${taxInfo.country.name}`;
            return (
              <React.Fragment>
              <div className="card" style={{ borderColor: "var(--primary)", background: "var(--primary-soft)" }}>
                <div style={{ display: "flex", alignItems: "start", gap: 14 }}>
                  <Icon name="sparkles" size={20} />
                  <div style={{ flex: 1 }}>
                    <div style={{ fontFamily: "var(--font-display)", fontSize: 19, color: "var(--primary-ink)" }}>
                      {headline}
                    </div>
                    <div style={{ fontSize: 13, color: "var(--primary-ink)", opacity: 0.85, marginTop: 4 }}>
                      Set aside <b>{fcNoCents(taxInfo.perPayment)}</b> based on YTD net at {taxInfo.ratePct} rate
                      <span style={{ opacity: 0.7 }}> · {taxInfo.entity.name}</span>
                    </div>
                    <button className="btn btn-sm" style={{ marginTop: 10 }} onClick={() => setTaxBreakdownOpen(true)}>
                      See breakdown <Icon name="chevronRight" size={12} />
                    </button>
                  </div>
                </div>
              </div>
              {taxBreakdownOpen && ReactDOM.createPortal(
                <TaxBreakdownModal
                  taxInfo={taxInfo}
                  ytdIncome={ytdIncome}
                  ytdExpense={ytdExpense}
                  ytdNet={ytdNet}
                  fc={fc}
                  fcNoCents={fcNoCents}
                  onClose={() => setTaxBreakdownOpen(false)}
                  goTo={goTo}
                />, document.body
              )}
              </React.Fragment>
            );
          }

          return null;
        }}
      />
    </div>
  );
};

// ChartCard — Income vs expenses with monthly/weekly/daily toggle.
// Buckets transactions by the selected granularity and renders via
// IncomeExpenseChart.
// Local-time date helpers — avoids toISOString() UTC-shift bugs in UTC+ timezones
function localYM(d) {
  return d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0");
}
function localYMD(d) {
  return d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0");
}

const ChartCard = ({ transactions, baseCur }) => {
  const [gran, setGran] = React.useState("monthly"); // monthly | weekly | daily
  const today = window.CB_DATA.today;

  const buckets = React.useMemo(() => {
    if (gran === "monthly") {
      const out = [];
      for (let i = 6; i >= 0; i--) {
        const d = new Date(today.getFullYear(), today.getMonth() - i, 1);
        const key = localYM(d);
        out.push({
          key, label: d.toLocaleDateString("en-US", { month: "short" }),
          income: 0, expense: 0,
        });
      }
      transactions.forEach(t => {
        const k = t.date.slice(0, 7);
        const b = out.find(x => x.key === k);
        if (b) {
          const usd = CB.txToUSD(t);
          b[t.type] += usd;
        }
      });
      return out;
    }
    if (gran === "weekly") {
      // Last 12 weeks ending with the week containing today (Mon–Sun).
      const out = [];
      const dow = (today.getDay() + 6) % 7;
      const monday = new Date(today.getFullYear(), today.getMonth(), today.getDate() - dow);
      for (let i = 11; i >= 0; i--) {
        const start = new Date(monday); start.setDate(monday.getDate() - i * 7);
        const end = new Date(start); end.setDate(start.getDate() + 6);
        out.push({
          startKey: localYMD(start),
          endKey: localYMD(end),
          label: start.toLocaleDateString("en-US", { month: "short", day: "numeric" }),
          income: 0, expense: 0,
        });
      }
      transactions.forEach(t => {
        const b = out.find(x => t.date >= x.startKey && t.date <= x.endKey);
        if (b) {
          const usd = CB.txToUSD(t);
          b[t.type] += usd;
        }
      });
      return out;
    }
    // daily — last 30 days
    const out = [];
    for (let i = 29; i >= 0; i--) {
      const d = new Date(today.getFullYear(), today.getMonth(), today.getDate() - i);
      out.push({
        key: localYMD(d),
        label: String(d.getDate()),
        income: 0, expense: 0,
      });
    }
    transactions.forEach(t => {
      const b = out.find(x => x.key === t.date);
      if (b) {
        b[t.type] += CB.txToUSD(t);
      }
    });
    return out;
  }, [gran, transactions, today]);

  const subtitle =
    gran === "monthly" ? "Last 7 months" :
    gran === "weekly"  ? "Last 12 weeks"  :
                         "Last 30 days";
  const avgUnit =
    gran === "monthly" ? "/mo" :
    gran === "weekly"  ? "/wk" :
                         "/day";
  const totalNet = buckets.reduce((s, b) => s + b.income - b.expense, 0);
  const avgNet = totalNet / Math.max(1, buckets.length);

  return (
    <div className="card">
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "start", marginBottom: 4, gap: 12, flexWrap: "wrap" }}>
        <div>
          <div className="kpi-label">Income vs expenses</div>
          <div style={{ fontFamily: "var(--font-display)", fontSize: 22, marginTop: 4 }}>
            {subtitle}
          </div>
        </div>
        <div className="segmented">
          <button className={gran === "monthly" ? "on" : ""} onClick={() => setGran("monthly")}>Monthly</button>
          <button className={gran === "weekly" ? "on" : ""} onClick={() => setGran("weekly")}>Weekly</button>
          <button className={gran === "daily" ? "on" : ""} onClick={() => setGran("daily")}>Daily</button>
        </div>
      </div>
      <div className="chart-wrap">
        <IncomeExpenseChart buckets={buckets} />
      </div>
      <div className="chart-legend">
        <div><span className="swatch" style={{ background: "var(--income)" }} />Income</div>
        <div><span className="swatch" style={{ background: "var(--expense)", opacity: 0.75 }} />Expenses</div>
        <div style={{ marginLeft: "auto", color: "var(--muted)", fontSize: 12 }}>
          Avg net: <b style={{ color: "var(--ink)" }}>{CB.fmtCur(CB.convert(avgNet, "USD", baseCur || "USD"), baseCur || "USD", { cents: false })}</b> {avgUnit}
        </div>
      </div>
    </div>
  );
};

// PendingPayoutsCard — surfaces money on its way to the user's bank
// from platforms with delayed payout schedules (YouTube AdSense, Amazon
// Associates, Patreon, Stripe). Lives on the dashboard alongside actuals.
const PendingPayoutsCard = ({ fc, fcNoCents, backendOnline, payoutsState }) => {
  const payouts = backendOnline ? (payoutsState || []) : (window.CB_DATA.pendingPayouts || []);
  const today = window.CB_DATA.today;
  const total = payouts.reduce((s, p) => s + p.amount, 0);

  // Group by platform name so multiple Amazon entries collapse visually
  const grouped = [];
  for (const p of payouts) {
    const last = grouped[grouped.length - 1];
    if (last && last.platform === p.platform && last.color === p.color) {
      last.items.push(p);
      last.subtotal += p.amount;
    } else {
      grouped.push({ platform: p.platform, color: p.color, glyph: p.glyph, cadence: p.cadence, items: [p], subtotal: p.amount });
    }
  }

  const daysFromNow = (dateStr) => {
    const days = Math.ceil((new Date(dateStr) - today) / 86400000);
    if (days <= 0) return "any day now";
    if (days === 1) return "tomorrow";
    if (days < 14) return `in ${days} days`;
    if (days < 60) return `in ~${Math.round(days / 7)} wk`;
    return `in ~${Math.round(days / 30)} mo`;
  };

  return (
    <div className="card">
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "start", marginBottom: 4 }}>
        <div>
          <div className="kpi-label">Pending payouts</div>
          <div style={{ fontFamily: "var(--font-display)", fontSize: 22, marginTop: 4 }}>
            {fcNoCents(total)}
            <span style={{ fontSize: 13, color: "var(--muted)", fontFamily: "var(--font-ui)", fontWeight: 400, marginLeft: 8 }}>
              on the way
            </span>
          </div>
        </div>
        <Pill kind="">{payouts.length} payouts</Pill>
      </div>

      <div style={{ marginTop: 14 }}>
        {grouped.map((g, gi) => (
          <div key={gi} style={{ paddingTop: gi > 0 ? 12 : 0, borderTop: gi > 0 ? "1px solid var(--hairline)" : "none" }}>
            <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
              <div style={{
                width: 36, height: 36, borderRadius: 10,
                background: g.color, color: "white",
                display: "grid", placeItems: "center",
                fontWeight: 700, fontSize: 14, flexShrink: 0,
              }}>{g.glyph}</div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontWeight: 500, fontSize: 13.5 }}>{g.platform}</div>
                <div style={{ fontSize: 11, color: "var(--muted)" }}>{g.cadence}</div>
              </div>
              <div style={{ fontFamily: "var(--font-mono)", fontWeight: 500, fontSize: 14, textAlign: "right" }}>
                {fc(g.subtotal)}
              </div>
            </div>
            <div style={{ marginTop: 8, paddingLeft: 48 }}>
              {g.items.map((it, i) => (
                <div key={i} style={{
                  display: "flex", justifyContent: "space-between", alignItems: "center",
                  padding: "4px 0", fontSize: 12, color: "var(--ink-soft)",
                }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 8, minWidth: 0 }}>
                    <span style={{
                      display: "inline-flex", alignItems: "center", gap: 5,
                      background: it.method.includes("Projected") || it.method.includes("Analytics")
                        ? "var(--primary-soft)" : "var(--income-soft)",
                      color: it.method.includes("Projected") || it.method.includes("Analytics")
                        ? "var(--primary-ink)" : "var(--income-text-strong)",
                      padding: "1px 7px", borderRadius: 8, fontSize: 10.5, fontWeight: 500,
                      flexShrink: 0,
                    }}>
                      {it.method.includes("Projected") ? "Projected" :
                       it.method.includes("Analytics") ? "Forecast" : "Confirmed"}
                    </span>
                    <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                      {it.method.replace(/^(Confirmed by [^—]+ — |From [^(]+ \(|Projected from )/, "").replace(/\)$/, "")}
                    </span>
                  </div>
                  <span style={{ fontFamily: "var(--font-mono)", color: "var(--ink)", marginLeft: 8, flexShrink: 0 }}>
                    {new Date(it.expectedDate).toLocaleDateString("en-US", { month: "short", day: "numeric" })}
                    <span style={{ color: "var(--muted)", marginLeft: 6 }}>· {daysFromNow(it.expectedDate)}</span>
                  </span>
                </div>
              ))}
            </div>
          </div>
        ))}
      </div>

      <div style={{ marginTop: 14, padding: 12, background: "var(--surface-2)", borderRadius: 10, fontSize: 12, color: "var(--ink-soft)", display: "flex", gap: 8 }}>
        <Icon name="sparkles" size={13} />
        <div>
          These are <b style={{ color: "var(--ink)" }}>not</b> in your ledger yet — they're forecasted from each platform's API.
          Money only counts as income once it lands in your bank.
        </div>
      </div>
    </div>
  );
};

// ── DashCanvas ────────────────────────────────────────────────
// Renders each card in `order` (skipping hidden) into a 2-column
// CSS grid. Some cards span both columns (kpis, chart). In edit
// mode each card gets a drag handle + hide button, and hidden
// cards appear in an "Add back" tray at the bottom.
const FULL_SPAN_CARDS = new Set(["kpis", "chart"]);

const DashCanvas = ({ editing, order, hidden, onMove, onHide, onShow, renderCard, cardLabels }) => {
  const [dragId, setDragId] = React.useState(null);
  const [overId, setOverId] = React.useState(null);

  const visible = order.filter(id => !hidden.has(id));
  const hiddenIds = order.filter(id => hidden.has(id));

  return (
    <>
      <div style={{
        display: "grid",
        gridTemplateColumns: "1fr 1fr",
        gap: 16,
      }}>
        {visible.map(id => {
          const fullSpan = FULL_SPAN_CARDS.has(id);
          const isOver = overId === id && dragId && dragId !== id;
          return (
            <div key={id}
              draggable={editing}
              onDragStart={editing ? (e) => { setDragId(id); e.dataTransfer.effectAllowed = "move"; } : undefined}
              onDragEnd={editing ? () => { setDragId(null); setOverId(null); } : undefined}
              onDragOver={editing ? (e) => { e.preventDefault(); if (dragId && dragId !== id) setOverId(id); } : undefined}
              onDragLeave={editing ? () => setOverId(o => (o === id ? null : o)) : undefined}
              onDrop={editing ? (e) => {
                e.preventDefault();
                if (dragId && dragId !== id) onMove(dragId, id);
                setDragId(null); setOverId(null);
              } : undefined}
              style={{
                gridColumn: fullSpan ? "1 / -1" : "auto",
                position: "relative",
                outline: isOver ? "2px dashed var(--primary)" : (editing ? "1px dashed var(--hairline-strong)" : "none"),
                outlineOffset: editing ? 6 : 0,
                borderRadius: 14,
                opacity: dragId === id ? 0.55 : 1,
                transition: "outline-color 0.12s, opacity 0.12s",
                cursor: editing ? "grab" : "default",
              }}>
              {editing && (
                <div style={{
                  position: "absolute", top: 8, right: 8, zIndex: 5,
                  display: "flex", gap: 4, alignItems: "center",
                }}>
                  <div style={{
                    background: "var(--ink)", color: "var(--bg)",
                    padding: "4px 8px", borderRadius: 8,
                    fontSize: 11, fontWeight: 500,
                    display: "flex", alignItems: "center", gap: 5,
                    boxShadow: "var(--shadow-2)",
                  }}>
                    <Icon name="dots" size={12} />
                    {cardLabels[id] || id}
                  </div>
                  <button
                    onClick={() => onHide(id)}
                    style={{
                      background: "var(--surface)", color: "var(--expense)",
                      border: "1px solid var(--hairline)", borderRadius: 8,
                      padding: 4, cursor: "pointer",
                      boxShadow: "var(--shadow-2)",
                    }}
                    title="Hide card">
                    <Icon name="close" size={12} />
                  </button>
                </div>
              )}
              {renderCard(id)}
            </div>
          );
        })}
      </div>

      {editing && hiddenIds.length > 0 && (
        <div style={{
          marginTop: 18, padding: 16, borderRadius: 14,
          background: "var(--surface-2)", border: "1px dashed var(--hairline-strong)",
        }}>
          <div style={{ fontSize: 11.5, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.05em", marginBottom: 10 }}>
            Hidden cards
          </div>
          <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
            {hiddenIds.map(id => (
              <button key={id} className="chip" onClick={() => onShow(id)}>
                <Icon name="plus" size={11} /> {cardLabels[id] || id}
              </button>
            ))}
          </div>
        </div>
      )}
    </>
  );
};

// ── Tax Breakdown Modal ─────────────────────────────────────
const TaxBreakdownModal = ({ taxInfo, ytdIncome, ytdExpense, ytdNet, fc, fcNoCents, onClose, goTo }) => {
  const { country, entity, rate, ratePct, rateNote, totalTax, perPayment, schedule } = taxInfo;
  const today = new Date();
  const year = today.getFullYear();

  // Parse each payment's due dates to determine status
  const payments = (schedule?.payments || []).map(p => {
    const dues = p.due.split("/").map(s => s.trim());
    let earliest = null;
    for (const d of dues) {
      const clean = d.replace(/\(.*\)/, "").trim();
      // Try current year first, then next year for wrap-around
      let parsed = new Date(clean + ", " + year);
      if (isNaN(parsed.getTime())) {
        parsed = new Date(clean + ", " + (year + 1));
      }
      if (!isNaN(parsed.getTime()) && (!earliest || parsed < earliest)) {
        earliest = parsed;
      }
    }
    const isPast = earliest && earliest < today;
    const isSoon = earliest && !isPast && (earliest - today) < 30 * 86400000;
    return { ...p, date: earliest, isPast, isSoon };
  });

  return (
    <div className="modal-veil" onClick={onClose}>
      <div className="modal" style={{ maxWidth: 560 }} onClick={e => e.stopPropagation()}>
        <div className="modal-head">
          <div style={{ display: "flex", alignItems: "start", justifyContent: "space-between", gap: 12 }}>
            <h2 className="modal-title">Tax Breakdown — {year}</h2>
            <button className="btn btn-ghost btn-sm" onClick={onClose} aria-label="Close"><Icon name="close" size={16} /></button>
          </div>
        </div>
        <div className="modal-body" style={{ padding: "0 24px 24px" }}>

          {/* Entity + rate banner */}
          <div style={{
            background: "var(--primary-soft)", border: "1px solid var(--primary)",
            borderRadius: 12, padding: "14px 16px", marginBottom: 20,
          }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 4 }}>
              <span style={{ fontSize: 18 }}>{country.flag}</span>
              <span style={{ fontWeight: 600, fontSize: 14 }}>{country.name}</span>
              <span style={{ color: "var(--primary-ink)", opacity: 0.7, fontSize: 13 }}>·</span>
              <span style={{ fontSize: 13, color: "var(--primary-ink)" }}>{entity.name}</span>
            </div>
            <div style={{ fontSize: 12.5, color: "var(--primary-ink)", opacity: 0.8 }}>
              {rateNote}
            </div>
          </div>

          {/* YTD summary */}
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 12, marginBottom: 20 }}>
            <div style={{ background: "var(--surface-2)", borderRadius: 12, padding: "14px 12px" }}>
              <div style={{ fontSize: 11, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: 4 }}>YTD Income</div>
              <div style={{ fontFamily: "var(--font-display)", fontSize: 18, color: "var(--income-text-strong)" }}>{fcNoCents(ytdIncome)}</div>
            </div>
            <div style={{ background: "var(--surface-2)", borderRadius: 12, padding: "14px 12px" }}>
              <div style={{ fontSize: 11, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: 4 }}>YTD Expenses</div>
              <div style={{ fontFamily: "var(--font-display)", fontSize: 18, color: "var(--expense)" }}>{fcNoCents(ytdExpense)}</div>
            </div>
            <div style={{ background: "var(--surface-2)", borderRadius: 12, padding: "14px 12px" }}>
              <div style={{ fontSize: 11, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: 4 }}>YTD Net Profit</div>
              <div style={{ fontFamily: "var(--font-display)", fontSize: 18 }}>{fcNoCents(ytdNet)}</div>
            </div>
          </div>

          {/* Tax calculation */}
          <div style={{ background: "var(--surface-2)", borderRadius: 12, padding: "16px", marginBottom: 20 }}>
            <div style={{ fontSize: 11, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: 12 }}>Estimated tax calculation</div>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "6px 0", fontSize: 13.5 }}>
              <span>Net profit</span>
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 13 }}>{fcNoCents(ytdNet)}</span>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "6px 0", fontSize: 13.5 }}>
              <span>× Blended rate</span>
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 13 }}>{ratePct}</span>
            </div>
            <div style={{ height: 1, background: "var(--hairline)", margin: "8px 0" }} />
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "6px 0" }}>
              <span style={{ fontWeight: 600, fontSize: 14 }}>Total estimated tax</span>
              <span style={{ fontFamily: "var(--font-display)", fontSize: 20 }}>{fcNoCents(totalTax)}</span>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "4px 0", fontSize: 13, color: "var(--muted)" }}>
              <span>Per payment ({payments.length} payments)</span>
              <span style={{ fontFamily: "var(--font-mono)" }}>{fcNoCents(perPayment)}</span>
            </div>
          </div>

          {/* Payment schedule */}
          <div style={{ marginBottom: 20 }}>
            <div style={{ fontSize: 11, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: 8 }}>
              {schedule?.label || "Payment schedule"}
            </div>
            {payments.map((p, i) => (
              <div key={i} style={{
                display: "flex", alignItems: "center", gap: 12,
                padding: "10px 12px", borderRadius: 10, marginBottom: 4,
                background: p.isSoon ? "var(--primary-soft)" : "var(--surface-2)",
                border: p.isSoon ? "1px solid var(--primary)" : "1px solid transparent",
              }}>
                <div style={{
                  width: 28, height: 28, borderRadius: 8,
                  background: p.isPast ? "var(--income-soft)" : p.isSoon ? "var(--primary)" : "var(--surface)",
                  color: p.isPast ? "var(--income-text-strong)" : p.isSoon ? "white" : "var(--muted)",
                  display: "grid", placeItems: "center", fontSize: 11, fontWeight: 600, flexShrink: 0,
                }}>
                  {p.isPast ? <Icon name="check" size={13} /> : p.q.slice(0, 2)}
                </div>
                <div style={{ flex: 1 }}>
                  <div style={{ fontWeight: 500, fontSize: 13.5 }}>{p.q}{p.note ? ` — ${p.note}` : ""}</div>
                  <div style={{ fontSize: 12, color: "var(--muted)" }}>Due {p.due}</div>
                </div>
                <div style={{ fontFamily: "var(--font-mono)", fontSize: 13, fontWeight: 500 }}>
                  {fcNoCents(perPayment)}
                </div>
                {p.isPast && <Pill kind="income">Passed</Pill>}
                {p.isSoon && <Pill kind="primary">Upcoming</Pill>}
              </div>
            ))}
          </div>

          {/* Disclaimer */}
          <div style={{
            padding: "12px 14px", background: "var(--surface-2)", borderRadius: 10,
            fontSize: 12, color: "var(--muted)", display: "flex", gap: 8, marginBottom: 8,
          }}>
            <Icon name="sparkles" size={13} style={{ flexShrink: 0, marginTop: 1 }} />
            <div>
              This is an <b style={{ color: "var(--ink)" }}>estimate only</b> based on your YTD net income and a blended tax rate.
              Actual liability depends on deductions, credits, and other income. Consult a tax professional.
            </div>
          </div>

          {/* Link to tax settings */}
          <button className="btn btn-ghost btn-sm" style={{ width: "100%" }} onClick={() => { onClose(); localStorage.setItem("cb_settings_section", "tax"); goTo("settings"); }}>
            <Icon name="settings" size={13} /> Change tax setup in settings
          </button>
        </div>
      </div>
    </div>
  );
};

// ── Channel Insights Modal ──────────────────────────────────
const ChannelInsightsModal = ({ channel, fc, fcNoCents, onClose }) => {
  const avatarSrc = channel.avatarUrl || (channel.avatar && channel.avatar.startsWith("http") ? channel.avatar : null);
  const avatarInitials = (() => {
    if (channel.avatar && !channel.avatar.startsWith("http")) return channel.avatar;
    const p = (channel.name || "").trim().split(/\s+/).filter(Boolean);
    if (p.length >= 2) return (p[0][0] + p[p.length - 1][0]).toUpperCase();
    if (p.length === 1) return p[0].slice(0, 2).toUpperCase();
    return "YT";
  })();

  const statCards = [
    { label: "Subscribers", value: channel.subs >= 1000000 ? (channel.subs / 1000000).toFixed(2) + "M" : channel.subs >= 1000 ? (channel.subs / 1000).toFixed(1) + "K" : String(channel.subs || 0), icon: "users" },
    { label: "Videos", value: String(channel.videos || 0), icon: "receipt" },
    { label: "RPM", value: channel.rpm != null ? "$" + channel.rpm.toFixed(2) : "N/A", icon: "dollar" },
    { label: "YTD Revenue", value: channel.ytdRevenue != null ? fcNoCents(channel.ytdRevenue) : "N/A", icon: "arrowUp" },
    { label: "This month", value: channel.monthRevenue != null ? fcNoCents(channel.monthRevenue) : "N/A", icon: "arrowUp" },
    { label: "Monetized since", value: channel.monetizedSince || "N/A", icon: "calendar" },
  ];

  return (
    <div className="modal-veil" onClick={onClose}>
      <div className="modal" style={{ maxWidth: 560 }} onClick={e => e.stopPropagation()}>
        <div className="modal-head">
          <div style={{ display: "flex", alignItems: "start", justifyContent: "space-between", gap: 12 }}>
            <h2 className="modal-title">Channel Insights</h2>
            <button className="btn btn-ghost btn-sm" onClick={onClose} aria-label="Close"><Icon name="close" size={16} /></button>
          </div>
        </div>
        <div className="modal-body" style={{ padding: "0 24px 24px" }}>
          {/* Channel identity */}
          <div style={{ display: "flex", alignItems: "center", gap: 16, marginBottom: 24 }}>
            {avatarSrc ? (
              <img src={avatarSrc} alt="" style={{ width: 64, height: 64, borderRadius: 16, objectFit: "cover" }} />
            ) : (
              <div style={{
                width: 64, height: 64, borderRadius: 16,
                background: "linear-gradient(135deg, var(--primary), oklch(0.55 0.16 320))",
                display: "grid", placeItems: "center", color: "white", fontFamily: "var(--font-display)", fontSize: 24,
              }}>
                {avatarInitials}
              </div>
            )}
            <div>
              <div style={{ fontFamily: "var(--font-display)", fontSize: 24 }}>{channel.name}</div>
              <div style={{ color: "var(--muted)", fontSize: 13, marginTop: 2 }}>
                {channel.handle}{channel.kind ? ` · ${channel.kind}` : ""}{channel.googleAccount ? ` · ${channel.googleAccount}` : ""}
              </div>
              <div style={{ marginTop: 6 }}>
                <Pill kind={channel.status === "connected" ? "primary" : ""} dot>{channel.status === "connected" ? "Connected" : channel.status || "Unknown"}</Pill>
              </div>
            </div>
          </div>

          {/* Stats grid */}
          <div style={{
            display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 12,
          }}>
            {statCards.map(s => (
              <div key={s.label} style={{
                background: "var(--surface-2)", borderRadius: 12, padding: "16px 14px",
                display: "flex", flexDirection: "column", gap: 4,
              }}>
                <div style={{ display: "flex", alignItems: "center", gap: 6, fontSize: 11.5, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.04em" }}>
                  <Icon name={s.icon} size={12} />
                  {s.label}
                </div>
                <div style={{ fontFamily: "var(--font-display)", fontSize: 20 }}>
                  {s.value}
                </div>
              </div>
            ))}
          </div>

          {/* Last synced */}
          {channel.lastSyncedAt && (
            <div style={{ marginTop: 16, fontSize: 12, color: "var(--muted)", textAlign: "center" }}>
              Last synced: {new Date(channel.lastSyncedAt).toLocaleString()}
            </div>
          )}
        </div>
      </div>
    </div>
  );
};

window.Dashboard = Dashboard;
