/* Settings — connected accounts (bank, YouTube), profile, categories */

const Settings = ({ goTo, accountState, setAccountState, channelState, setChannelState, rulesState, setRulesState, txState, setTxState, appearance, setAppearance, profileState, setProfileState, onReplayOnboarding, backendOnline, initialSection }) => {
  const [section, setSection] = React.useState(() => {
    const stored = localStorage.getItem("cb_settings_section");
    if (stored) { localStorage.removeItem("cb_settings_section"); return stored; }
    return initialSection || "accounts";
  });
  const [connectOpen, setConnectOpen] = React.useState(false);

  const accounts = accountState;
  const setAccounts = setAccountState;

  const disconnect = (id) => {
    setAccounts(as => as.map(a => a.id === id ? { ...a, status: "disconnected" } : a));
  };
  const reconnect = (id) => {
    setAccounts(as => as.map(a => a.id === id ? { ...a, status: "connected" } : a));
  };

  return (
    <div className="page-fade">
      <div className="page-head">
        <div>
          <h1 className="page-title">Settings</h1>
          <div className="page-sub">Manage connections, categories, and your CreatorBoard account</div>
        </div>
      </div>

      <div className="settings-cols" style={{ display: "grid", gridTemplateColumns: "200px 1fr", gap: 28 }}>
        {/* Side nav */}
        <div style={{ display: "flex", flexDirection: "column", gap: 2 }}>
          {[
            { id: "accounts", name: "Connected accounts", icon: "link" },
            { id: "appearance", name: "Appearance", icon: "sun" },
            { id: "categories", name: "Categories", icon: "tag" },
            { id: "rules", name: "Auto-rules", icon: "sparkles" },
            { id: "tax", name: "Tax setup", icon: "file" },
            { id: "channel", name: "Channel", icon: "youtube" },
            { id: "profile", name: "Profile", icon: "user" },
            { id: "billing", name: "Billing", icon: "card" },
          ].map(s => (
            <button key={s.id} className={"nav-item " + (section === s.id ? "active" : "")} onClick={() => setSection(s.id)}>
              <Icon name={s.icon} size={16} />
              <span className="label" style={{ fontSize: 13.5 }}>{s.name}</span>
            </button>
          ))}
        </div>

        {/* Content */}
        <div>
          {section === "accounts" && (
            <>
              <div className="card">
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "start", marginBottom: 4 }}>
                  <div>
                    <div style={{ fontFamily: "var(--font-display)", fontSize: 22 }}>Banks & cards</div>
                    <div style={{ fontSize: 13, color: "var(--muted)", marginTop: 2 }}>
                      Connect via Plaid · transactions sync hourly
                    </div>
                  </div>
                  <button className="btn btn-primary" onClick={() => setConnectOpen(true)}>
                    <Icon name="plus" size={14} /> Connect account
                  </button>
                </div>
                <div style={{ marginTop: 12 }}>
                  {accounts.filter(a => a.kind === "bank" || a.kind === "card").map(a => (
                    <AccountRow key={a.id} acc={a} onDisconnect={() => disconnect(a.id)} onReconnect={() => reconnect(a.id)} />
                  ))}
                </div>
              </div>

              <div className="card" style={{ marginTop: 16 }}>
                <div>
                  <div style={{ fontFamily: "var(--font-display)", fontSize: 22 }}>Platforms</div>
                  <div style={{ fontSize: 13, color: "var(--muted)", marginTop: 2 }}>
                    Pull income directly from creator platforms
                  </div>
                </div>
                <div style={{ marginTop: 12 }}>
                  {accounts.filter(a => a.kind === "platform").map(a => (
                    <AccountRow key={a.id} acc={a} onDisconnect={() => disconnect(a.id)} onReconnect={() => reconnect(a.id)} />
                  ))}
                </div>
              </div>

              <div className="card-quiet" style={{ marginTop: 16, padding: 16 }}>
                <div style={{ display: "flex", gap: 12, alignItems: "start" }}>
                  <Icon name="sparkles" size={18} />
                  <div>
                    <div style={{ fontWeight: 500, fontSize: 13 }}>Don't see your platform?</div>
                    <div style={{ fontSize: 12.5, color: "var(--ink-soft)", marginTop: 2 }}>
                      We're adding TikTok, Twitch, Substack, Gumroad, and Instagram Reels soon. Tell us what you need.
                    </div>
                  </div>
                </div>
              </div>
            </>
          )}

          {section === "categories" && <CategoriesSection />}
          {section === "appearance" && <AppearanceSection appearance={appearance} setAppearance={setAppearance} />}
          {section === "rules" && <RulesSection rules={rulesState} setRules={setRulesState} txState={txState} setTxState={setTxState} />}
          {section === "tax" && <TaxSection profile={profileState} setProfile={setProfileState} txState={txState} backendOnline={backendOnline} />}
          {section === "channel" && <ChannelSection backendOnline={backendOnline} channelState={channelState} setChannelState={setChannelState} />}
          {section === "profile" && <ProfileSection profile={profileState} setProfile={setProfileState} onReplayOnboarding={onReplayOnboarding} />}
          {section === "billing" && <BillingSection />}
        </div>
      </div>

      <ConnectAccountModal
        open={connectOpen}
        onClose={() => setConnectOpen(false)}
        onConnect={(newAcc) => {
          setAccounts(as => [...as, newAcc]);
          setConnectOpen(false);
        }}
      />
    </div>
  );
};

const AccountRow = ({ acc, onDisconnect, onReconnect }) => {
  // Prefer the persisted brand glyph; fall back to initials of the first
  // significant word so older accounts still render something sensible.
  const initials = acc.name
    .replace(/[^A-Za-z0-9 ]/g, "")
    .split(" ")
    .filter(Boolean)[0]
    ?.slice(0, 2)
    .toUpperCase() || "?";
  const glyph = acc.logo || initials;
  const bg = acc.color || "#777";
  const connected = acc.status === "connected";

  return (
    <div className="account-row">
      <div className="account-logo" style={{ background: bg }}>
        {glyph}
      </div>
      <div>
        <div style={{ fontWeight: 500, display: "flex", alignItems: "center", gap: 8 }}>
          {acc.name}
          {acc.currency && acc.currency !== "USD" && (
            <span style={{ fontSize: 10.5, padding: "1px 6px", background: "var(--surface-2)", borderRadius: 6, color: "var(--ink-soft)", fontFamily: "var(--font-mono)", fontWeight: 600 }}>
              {acc.currency}
            </span>
          )}
        </div>
        <div style={{ fontSize: 12, color: "var(--muted)" }}>
          {acc.last4 !== "—" && `Account ending ${acc.last4} · `}
          {connected ? (
            <span style={{ color: "var(--income-text)" }}>● Connected · synced 12 min ago</span>
          ) : (
            <span style={{ color: "var(--expense)" }}>● Disconnected</span>
          )}
        </div>
      </div>
      <div style={{ fontFamily: "var(--font-mono)", fontSize: 13, color: "var(--ink-soft)", textAlign: "right" }}>
        {acc.balance !== null ? (
          <>
            <div>{CB.fmtCur(acc.balance, acc.currency || "USD")}</div>
            {acc.currency && acc.currency !== "USD" && (
              <div style={{ fontSize: 11, color: "var(--muted)" }}>
                ≈ {CB.fmt(CB.convert(acc.balance, acc.currency, "USD"), { cents: false })}
              </div>
            )}
          </>
        ) : ""}
      </div>
      <div>
        {connected ? (
          <button className="btn btn-ghost btn-sm" onClick={onDisconnect}>Disconnect</button>
        ) : (
          <button className="btn btn-sm" onClick={onReconnect}>Reconnect</button>
        )}
      </div>
    </div>
  );
};

const AppearanceSection = ({ appearance, setAppearance }) => {
  const options = [
    {
      id: "light",
      name: "Light",
      sub: "Bright surfaces, warm neutrals",
      preview: { bg: "oklch(0.972 0.012 75)", surface: "oklch(1 0 0)", ink: "oklch(0.22 0.018 60)", primary: "oklch(0.64 0.16 35)" },
    },
    {
      id: "dark",
      name: "Dark",
      sub: "Deep neutrals, easy on the eyes at night",
      preview: { bg: "oklch(0.18 0.014 60)", surface: "oklch(0.23 0.014 60)", ink: "oklch(0.95 0.012 70)", primary: "oklch(0.7 0.16 35)" },
    },
    {
      id: "auto",
      name: "Auto",
      sub: "Follow your operating system preference",
      preview: null,
    },
  ];

  return (
    <div>
      <div className="card">
        <div style={{ fontFamily: "var(--font-display)", fontSize: 22 }}>Appearance</div>
        <div style={{ fontSize: 13, color: "var(--muted)", marginTop: 2 }}>
          Choose how CreatorBoard looks. Auto matches your operating system.
        </div>

        <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 12, marginTop: 20 }}>
          {options.map(o => (
            <button key={o.id}
              onClick={() => setAppearance(o.id)}
              style={{
                padding: 16, borderRadius: 14, cursor: "pointer", textAlign: "left",
                border: "1.5px solid " + (appearance === o.id ? "var(--primary)" : "var(--hairline)"),
                background: appearance === o.id ? "var(--primary-soft)" : "var(--surface)",
                display: "flex", flexDirection: "column", gap: 12,
              }}>
              {/* Preview */}
              <div style={{
                height: 70, borderRadius: 8, overflow: "hidden",
                background: o.preview ? o.preview.bg : "linear-gradient(90deg, oklch(0.972 0.012 75) 50%, oklch(0.18 0.014 60) 50%)",
                position: "relative", border: "1px solid var(--hairline)",
              }}>
                {o.preview ? (
                  <div style={{
                    position: "absolute", left: 8, right: 8, top: 8, bottom: 8,
                    background: o.preview.surface, borderRadius: 4,
                    display: "flex", alignItems: "center", padding: 6, gap: 4,
                  }}>
                    <div style={{ width: 14, height: 14, borderRadius: 3, background: o.preview.primary }} />
                    <div style={{ height: 4, background: o.preview.ink, opacity: 0.7, borderRadius: 2, width: 50 }} />
                  </div>
                ) : (
                  <div style={{ position: "absolute", inset: 8, display: "flex", gap: 8 }}>
                    <div style={{ flex: 1, background: "oklch(1 0 0)", borderRadius: 4, display: "flex", alignItems: "center", padding: 4 }}>
                      <div style={{ width: 12, height: 12, borderRadius: 3, background: "oklch(0.64 0.16 35)" }} />
                    </div>
                    <div style={{ flex: 1, background: "oklch(0.23 0.014 60)", borderRadius: 4, display: "flex", alignItems: "center", padding: 4 }}>
                      <div style={{ width: 12, height: 12, borderRadius: 3, background: "oklch(0.7 0.16 35)" }} />
                    </div>
                  </div>
                )}
              </div>

              <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                <div style={{
                  width: 18, height: 18, borderRadius: "50%",
                  border: "1.5px solid " + (appearance === o.id ? "var(--primary)" : "var(--hairline-strong)"),
                  background: appearance === o.id ? "var(--primary)" : "transparent",
                  display: "grid", placeItems: "center", flexShrink: 0,
                }}>
                  {appearance === o.id && <Icon name="check" size={10} color="white" />}
                </div>
                <div>
                  <div style={{ fontWeight: 500, fontSize: 14 }}>{o.name}</div>
                  <div style={{ fontSize: 11.5, color: "var(--muted)", marginTop: 2 }}>{o.sub}</div>
                </div>
              </div>
            </button>
          ))}
        </div>
      </div>

      <div className="card-quiet" style={{ marginTop: 16, padding: 14, display: "flex", gap: 12, alignItems: "start" }}>
        <Icon name="sun" size={16} />
        <div style={{ fontSize: 12.5, color: "var(--ink-soft)" }}>
          <b style={{ color: "var(--ink)" }}>Tip:</b> use the quick toggle in the sidebar to flip between light and dark with one click.
          The color theme (Clay, Forest, Indigo, etc.) is set separately in Tweaks.
        </div>
      </div>
    </div>
  );
};

const PRESET_COLORS = [
  "#6366f1","#8b5cf6","#ec4899","#ef4444","#f97316",
  "#eab308","#22c55e","#14b8a6","#3b82f6","#06b6d4",
  "#84cc16","#a855f7","#f43f5e","#64748b","#10b981",
];

const CategoriesSection = () => {
  const [allCats, setAllCats] = React.useState(() => [
    ...CB_DATA.categories.income,
    ...CB_DATA.categories.expense,
  ]);
  const [modal, setModal] = React.useState(null); // null | { mode: "add" } | { mode: "edit", cat }

  // Load user-created categories from backend on mount
  React.useEffect(() => {
    if (!window.CB_API) return;
    window.CB_API.getCategories().then(res => {
      if (res?.income && res?.expense) {
        setAllCats([...res.income, ...res.expense]);
      }
    }).catch(() => {});
  }, []);

  const openAdd  = () => setModal({ mode: "add" });
  const openEdit = (c) => setModal({ mode: "edit", cat: c });
  const closeModal = () => setModal(null);

  const handleSave = async (data) => {
    if (!window.CB_API) { closeModal(); return; }
    try {
      if (modal.mode === "add") {
        const saved = await window.CB_API.createCategory(data);
        setAllCats(cs => [...cs, saved]);
        window.toast?.({ message: `Category "${saved.name}" added` });
      } else {
        const saved = await window.CB_API.updateCategory(modal.cat.id, data);
        setAllCats(cs => cs.map(c => c.id === saved.id ? saved : c));
        window.toast?.({ message: `Category "${saved.name}" updated` });
      }
      closeModal();
    } catch (e) {
      window.toast?.({ type: "error", message: e?.data?.error || "Failed to save category" });
    }
  };

  const handleDelete = async (catId, name) => {
    if (!window.CB_API) return;
    if (!confirm(`Delete "${name}"? Transactions using it will become uncategorized.`)) return;
    try {
      await window.CB_API.deleteCategory(catId);
      setAllCats(cs => cs.filter(c => c.id !== catId));
      window.toast?.({ message: `Category "${name}" deleted` });
    } catch (e) {
      window.toast?.({ type: "error", message: e?.data?.error || "Cannot delete — may be a system category" });
    }
  };

  const income  = allCats.filter(c => c.kind === "income");
  const expense = allCats.filter(c => c.kind === "expense");

  return (
    <div className="card">
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 4 }}>
        <div>
          <div style={{ fontFamily: "var(--font-display)", fontSize: 22 }}>Categories</div>
          <div style={{ fontSize: 13, color: "var(--muted)", marginTop: 2 }}>
            Manage income and expense categories. System categories can't be deleted.
          </div>
        </div>
        <button className="btn btn-primary" onClick={openAdd}>
          <Icon name="plus" size={14} /> Add category
        </button>
      </div>

      {[{ label: "Income", cats: income }, { label: "Expense", cats: expense }].map(({ label, cats }) => (
        <div key={label} style={{ marginTop: 18 }}>
          <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--muted)", marginBottom: 6 }}>
            {label}
          </div>
          <table className="tbl">
            <thead>
              <tr><th>Category</th><th style={{ width: 200 }}>Schedule C / Tax line</th><th style={{ width: 80 }}></th></tr>
            </thead>
            <tbody>
              {cats.map(c => {
                const isSystem = !c.userId;
                return (
                  <tr key={c.id}>
                    <td>
                      <span style={{ display: "inline-flex", alignItems: "center", gap: 8 }}>
                        <span className="cat-swatch" style={{ background: c.color }} />
                        {c.name}
                        {isSystem && <span style={{ fontSize: 10, color: "var(--muted)", background: "var(--surface-2)", padding: "1px 6px", borderRadius: 4 }}>system</span>}
                      </span>
                    </td>
                    <td style={{ color: "var(--ink-soft)", fontSize: 13 }}>{c.tax || "—"}</td>
                    <td>
                      <div style={{ display: "flex", gap: 4 }}>
                        {!isSystem && (
                          <>
                            <button className="btn btn-ghost btn-sm" onClick={() => openEdit(c)}>Edit</button>
                            <button className="btn btn-ghost btn-sm" style={{ color: "var(--expense-text)" }} onClick={() => handleDelete(c.id, c.name)}>Delete</button>
                          </>
                        )}
                        {isSystem && (
                          <button className="btn btn-ghost btn-sm" disabled style={{ opacity: 0.4 }}>System</button>
                        )}
                      </div>
                    </td>
                  </tr>
                );
              })}
              {cats.length === 0 && <tr><td colSpan="3" className="empty">No {label.toLowerCase()} categories yet.</td></tr>}
            </tbody>
          </table>
        </div>
      ))}

      {modal && (
        <CategoryModal
          mode={modal.mode}
          initial={modal.cat}
          onSave={handleSave}
          onClose={closeModal}
        />
      )}
    </div>
  );
};

const CategoryModal = ({ mode, initial, onSave, onClose }) => {
  const [name,  setName]  = React.useState(initial?.name  || "");
  const [kind,  setKind]  = React.useState(initial?.kind  || "expense");
  const [color, setColor] = React.useState(initial?.color || PRESET_COLORS[0]);
  const [tax,   setTax]   = React.useState(initial?.tax   || "");
  const [saving, setSaving] = React.useState(false);

  const submit = async () => {
    if (!name.trim()) return;
    setSaving(true);
    await onSave({ name: name.trim(), kind, color, tax: tax.trim() || undefined });
    setSaving(false);
  };

  return (
    <Modal open onClose={onClose} maxWidth={440}
      title={mode === "add" ? "Add category" : "Edit category"}
      footer={<>
        <button className="btn" onClick={onClose}>Cancel</button>
        <button className="btn btn-primary" onClick={submit} disabled={!name.trim() || saving}>
          {saving ? "Saving…" : mode === "add" ? "Add category" : "Save changes"}
        </button>
      </>}>

      <div style={{ display: "grid", gap: 14 }}>
        <div>
          <label className="label">Name</label>
          <input className="input" value={name} onChange={e => setName(e.target.value)}
            placeholder="e.g. Coaching, Licensing…" autoFocus />
        </div>

        {mode === "add" && (
          <div>
            <label className="label">Type</label>
            <div style={{ display: "flex", gap: 8 }}>
              {["expense", "income"].map(k => (
                <button key={k} className={"chip" + (kind === k ? " on" : "")} onClick={() => setKind(k)}
                  style={{ textTransform: "capitalize" }}>{k}</button>
              ))}
            </div>
          </div>
        )}

        <div>
          <label className="label">Color</label>
          <div style={{ display: "flex", flexWrap: "wrap", gap: 8, marginTop: 4 }}>
            {PRESET_COLORS.map(col => (
              <button key={col} onClick={() => setColor(col)}
                style={{
                  width: 28, height: 28, borderRadius: "50%", background: col, border: "none",
                  cursor: "pointer", outline: color === col ? "3px solid var(--primary)" : "3px solid transparent",
                  outlineOffset: 2,
                }} />
            ))}
          </div>
        </div>

        <div>
          <label className="label">Schedule C / Tax line <span style={{ fontWeight: 400, color: "var(--muted)" }}>(optional)</span></label>
          <input className="input" value={tax} onChange={e => setTax(e.target.value)}
            placeholder="e.g. Line 26 — Wages, Line 18 — Office" />
        </div>

        <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 14px", background: "var(--surface-2)", borderRadius: 10 }}>
          <span className="cat-swatch" style={{ background: color, width: 18, height: 18, borderRadius: 5 }} />
          <span style={{ fontWeight: 500 }}>{name || "Category name"}</span>
          <Pill kind={kind === "income" ? "income" : "expense"} style={{ marginLeft: "auto" }}>{kind}</Pill>
        </div>
      </div>
    </Modal>
  );
};

// ─────────────────────────────────────────────────────────────
// Country-aware tax data. Rates are realistic approximations
// based on publicly-known headline rates as of 2025-2026; users
// should confirm with a local accountant.

window.COUNTRIES = [
  {
    code: "US", name: "United States", flag: "🇺🇸", currency: "USD",
    regionLabel: "State",
    regions: ["California", "Texas", "New York", "Florida", "Illinois", "Washington", "Georgia", "Colorado", "Other"],
    filing: ["Single", "Married filing jointly", "Married filing separately", "Head of household"],
    entities: [
      { id: "sole",        name: "Sole proprietorship (Schedule C)",                   rate: 0.27, rateNote: "~12-22% federal + 15.3% SE tax (net ~27% blended)" },
      { id: "llc_single",  name: "LLC — single-member (disregarded)",                   rate: 0.27, rateNote: "Pass-through to Schedule C, same as sole prop" },
      { id: "llc_multi",   name: "LLC — multi-member (partnership)",                    rate: 0.27, rateNote: "Pass-through via K-1, partner pays personal + SE" },
      { id: "scorp",       name: "S-Corp (LLC or Inc. with S election)",                rate: 0.22, rateNote: "Reasonable salary + distributions; saves SE tax on distributions" },
      { id: "ccorp",       name: "C-Corp",                                              rate: 0.21, rateNote: "21% flat federal corporate; plus state + dividend tax on payouts" },
    ],
    schedule: {
      label: "IRS quarterly estimated tax (Form 1040-ES)",
      payments: [
        { q: "Q1", due: "Apr 15", note: "Jan-Mar income" },
        { q: "Q2", due: "Jun 15", note: "Apr-May income" },
        { q: "Q3", due: "Sep 15", note: "Jun-Aug income" },
        { q: "Q4", due: "Jan 15 (next year)", note: "Sep-Dec income" },
      ],
    },
  },
  {
    code: "CA", name: "Canada", flag: "🇨🇦", currency: "CAD",
    regionLabel: "Province",
    regions: ["Ontario", "Quebec", "British Columbia", "Alberta", "Manitoba", "Saskatchewan", "Nova Scotia", "New Brunswick", "Other"],
    filing: ["Single", "Married / common-law", "Separated", "Widowed"],
    entities: [
      { id: "sole",       name: "Sole proprietorship",                       rate: 0.30, rateNote: "Federal 15-33% + provincial 5-21%; pay CPP both halves" },
      { id: "partner",    name: "Partnership",                               rate: 0.30, rateNote: "Pass-through to each partner's personal return" },
      { id: "ccpc_small", name: "CCPC — small business deduction",            rate: 0.12, rateNote: "9% federal + ~3% provincial on first $500k active income" },
      { id: "corp",       name: "Corporation (general rate)",                 rate: 0.265, rateNote: "15% federal + 8-12% provincial on income above small-biz limit" },
    ],
    schedule: {
      label: "CRA instalment payments",
      payments: [
        { q: "Q1", due: "Mar 15", note: "" },
        { q: "Q2", due: "Jun 15", note: "" },
        { q: "Q3", due: "Sep 15", note: "" },
        { q: "Q4", due: "Dec 15", note: "" },
      ],
    },
  },
  {
    code: "RO", name: "Romania", flag: "🇷🇴", currency: "RON",
    regionLabel: "Județ",
    regions: ["București", "Cluj", "Timiș", "Iași", "Brașov", "Constanța", "Bihor", "Sibiu", "Mureș", "Other"],
    filing: ["Individual", "Family unit"],
    entities: [
      { id: "pfa_real",   name: "PFA — sistem real (actual income)",          rate: 0.35, rateNote: "10% income tax + 25% CAS pension + 10% CASS health (within thresholds)" },
      { id: "pfa_norm",   name: "PFA — norme de venit (income norms)",        rate: 0.20, rateNote: "10% on fixed annual norm + CAS/CASS if income > 6/12/24 minimum wages" },
      { id: "ii",         name: "Întreprindere Individuală (II)",             rate: 0.30, rateNote: "Same as PFA real, taxed as individual income" },
      { id: "srl_micro1", name: "SRL — micro-enterprise (1%)",                rate: 0.082, rateNote: "1% on turnover (1+ employee, < €500k revenue) + 8% dividend tax" },
      { id: "srl_micro3", name: "SRL — micro-enterprise (3%)",                rate: 0.102, rateNote: "3% on turnover (no employee or restricted CAEN codes) + 8% dividend tax" },
      { id: "srl_std",    name: "SRL — standard profit tax",                  rate: 0.227, rateNote: "16% corporate profit tax + 8% dividend tax (~22.7% effective on distributed profit)" },
    ],
    schedule: {
      label: "ANAF — Declarația Unică & advance payments",
      payments: [
        { q: "DU",   due: "May 25", note: "Declarația Unică (annual income + estimate)" },
        { q: "CAS",  due: "May 25", note: "Annual CAS / CASS contributions" },
        { q: "Micro", due: "Apr 25 / Jul 25 / Oct 25 / Jan 25", note: "Quarterly micro-enterprise tax (SRL)" },
      ],
    },
  },
  {
    code: "RS", name: "Serbia", flag: "🇷🇸", currency: "RSD",
    regionLabel: "City / region",
    regions: ["Belgrade", "Novi Sad", "Niš", "Kragujevac", "Subotica", "Other"],
    filing: ["Single", "Married"],
    entities: [
      { id: "ent_lump",   name: "Preduzetnik — paušalac (lump-sum)",          rate: 0.22, rateNote: "10% income tax on assumed income + ~26% social contributions on base" },
      { id: "ent_real",   name: "Preduzetnik — actual income",                 rate: 0.32, rateNote: "10% personal income tax + ~36% combined social contributions" },
      { id: "doo",        name: "DOO (limited liability company)",             rate: 0.235, rateNote: "15% corporate income tax + ~10% withholding on dividends (~23.5% effective)" },
    ],
    schedule: {
      label: "Poreska uprava — monthly / annual",
      payments: [
        { q: "Monthly", due: "15th of next month", note: "Advance income & social contribution payments" },
        { q: "Annual",  due: "May 15",             note: "Annual personal income tax return" },
      ],
    },
  },
  {
    code: "ES", name: "Spain", flag: "🇪🇸", currency: "EUR",
    regionLabel: "Autonomous community",
    regions: ["Madrid", "Cataluña", "Andalucía", "Comunidad Valenciana", "País Vasco", "Galicia", "Castilla y León", "Other"],
    filing: ["Individual (declaración individual)", "Joint (declaración conjunta)"],
    entities: [
      { id: "autonomo",   name: "Autónomo (self-employed)",                    rate: 0.30, rateNote: "Progressive IRPF 19-47% + monthly autónomo cuota by income bracket" },
      { id: "sl",         name: "SL — Sociedad Limitada",                      rate: 0.25, rateNote: "25% Impuesto sobre Sociedades (15% reduced rate for new entities, first 2 profitable years)" },
      { id: "sa",         name: "SA — Sociedad Anónima",                       rate: 0.25, rateNote: "25% corporate tax; same rules as SL for new-entity reduction" },
      { id: "cooperativa", name: "Cooperativa fiscalmente protegida",          rate: 0.20, rateNote: "20% reduced corporate rate for qualifying cooperatives" },
    ],
    schedule: {
      label: "AEAT — Modelo 130 / 303 trimestrales",
      payments: [
        { q: "T1", due: "Apr 20", note: "IRPF fraccionado + IVA Q1" },
        { q: "T2", due: "Jul 20", note: "IRPF fraccionado + IVA Q2" },
        { q: "T3", due: "Oct 20", note: "IRPF fraccionado + IVA Q3" },
        { q: "T4", due: "Jan 30", note: "IRPF fraccionado + IVA Q4 + annual" },
      ],
    },
  },
  {
    code: "DE", name: "Germany", flag: "🇩🇪", currency: "EUR",
    regionLabel: "Bundesland",
    regions: ["Berlin", "Bayern", "Hamburg", "Nordrhein-Westfalen", "Hessen", "Baden-Württemberg", "Sachsen", "Other"],
    filing: ["Single (ledig)", "Married — joint assessment (Zusammenveranlagung)", "Married — separate (Einzelveranlagung)"],
    entities: [
      { id: "einzel",       name: "Einzelunternehmer (sole prop)",             rate: 0.32, rateNote: "Progressive Einkommensteuer 14-45% + solidarity (5.5% of tax) + Gewerbesteuer if profit > €24,500" },
      { id: "freiberufler", name: "Freiberufler (liberal profession)",         rate: 0.30, rateNote: "Progressive Einkommensteuer 14-45% + solidarity; exempt from Gewerbesteuer" },
      { id: "gbr",          name: "GbR (partnership)",                         rate: 0.32, rateNote: "Pass-through to partners + Gewerbesteuer on entity (offset partially via §35 EStG)" },
      { id: "ug",           name: "UG (haftungsbeschränkt) — mini-GmbH",       rate: 0.30, rateNote: "15% Körperschaftsteuer + 5.5% solidarity on KSt + ~14% Gewerbesteuer (~30% combined)" },
      { id: "gmbh",         name: "GmbH",                                      rate: 0.30, rateNote: "Same combined rate as UG; corporate tax + solidarity + Gewerbesteuer" },
    ],
    schedule: {
      label: "Finanzamt — Vorauszahlungen (advance payments)",
      payments: [
        { q: "Q1", due: "Mar 10", note: "Einkommensteuer-Vorauszahlung" },
        { q: "Q2", due: "Jun 10", note: "Einkommensteuer-Vorauszahlung" },
        { q: "Q3", due: "Sep 10", note: "Einkommensteuer-Vorauszahlung" },
        { q: "Q4", due: "Dec 10", note: "Einkommensteuer-Vorauszahlung" },
      ],
    },
  },
  {
    code: "FR", name: "France", flag: "🇫🇷", currency: "EUR",
    regionLabel: "Région",
    regions: ["Île-de-France", "Auvergne-Rhône-Alpes", "Provence-Alpes-Côte d'Azur", "Occitanie", "Nouvelle-Aquitaine", "Hauts-de-France", "Other"],
    filing: ["Single", "Married / PACS — joint", "Single parent (parent isolé)"],
    entities: [
      { id: "micro",     name: "Micro-entrepreneur (auto-entrepreneur)",        rate: 0.24, rateNote: "Social charges ~22% (services) or ~12% (sales) + optional flat IR 1-2.2% on revenue" },
      { id: "ei",        name: "EI — Entreprise individuelle",                  rate: 0.30, rateNote: "Progressive IR 11-45% on profit + ~45% social charges (SSI)" },
      { id: "eurl",      name: "EURL (single-member SARL)",                     rate: 0.25, rateNote: "IR by default OR 25% IS election (15% on first €42,500)" },
      { id: "sasu",      name: "SASU / SAS",                                    rate: 0.25, rateNote: "25% corporate tax (15% on first €42,500); president on salaried regime" },
      { id: "sarl",      name: "SARL",                                          rate: 0.25, rateNote: "25% corporate tax (15% on first €42,500)" },
    ],
    schedule: {
      label: "DGFiP — acomptes IS / IR",
      payments: [
        { q: "Acompte 1", due: "Mar 15", note: "" },
        { q: "Acompte 2", due: "Jun 15", note: "" },
        { q: "Acompte 3", due: "Sep 15", note: "" },
        { q: "Acompte 4", due: "Dec 15", note: "" },
      ],
    },
  },
  {
    code: "UK", name: "United Kingdom", flag: "🇬🇧", currency: "GBP",
    regionLabel: "Nation",
    regions: ["England", "Scotland", "Wales", "Northern Ireland"],
    filing: ["Single", "Married / civil partnership"],
    entities: [
      { id: "sole",  name: "Sole trader",                                       rate: 0.30, rateNote: "Income tax 20-45% + Class 2 & Class 4 NICs on profits" },
      { id: "ltd",   name: "Ltd company",                                       rate: 0.25, rateNote: "25% Corporation Tax (19% small profits rate up to £50k, marginal up to £250k)" },
      { id: "llp",   name: "LLP (limited liability partnership)",               rate: 0.30, rateNote: "Pass-through to partners' Self Assessment" },
    ],
    schedule: {
      label: "HMRC — Self Assessment + Payments on Account",
      payments: [
        { q: "Balancing + POA 1", due: "Jan 31", note: "Balance for previous year + first payment on account" },
        { q: "POA 2",             due: "Jul 31", note: "Second payment on account" },
      ],
    },
  },
];

const TaxSection = ({ profile, setProfile, txState, backendOnline }) => {
  const countryCode = profile?.countryCode || profile?.country;
  const [country, setCountry] = React.useState(() => {
    const known = window.COUNTRIES.find(x => x.code === countryCode);
    return known ? countryCode : "RO";
  });
  const c = window.COUNTRIES.find(x => x.code === country);
  const [region,  setRegion]  = React.useState(() => profile?.region       || c.regions[0]);
  const [filing,  setFiling]  = React.useState(() => profile?.filingStatus || c.filing[0]);
  const [entity,  setEntity]  = React.useState(() => {
    const saved = profile?.businessEntityId;
    return (saved && c.entities.find(e => e.id === saved)) ? saved : c.entities[0].id;
  });
  const [saving,  setSaving]  = React.useState(false);
  const [dirty,   setDirty]   = React.useState(false);

  const mark = (fn) => { fn(); setDirty(true); };

  // Reset dependent dropdowns when country changes (skip initial mount)
  const mountedRef = React.useRef(false);
  React.useEffect(() => {
    if (!mountedRef.current) { mountedRef.current = true; return; }
    setRegion(c.regions[0]);
    setFiling(c.filing[0]);
    setEntity(c.entities[0].id);
  }, [country]);

  const handleSave = async () => {
    setSaving(true);
    try {
      const updated = await window.CB_API.updateMe({
        countryCode: country,
        region,
        filingStatus: filing,
        businessEntityId: entity,
      });
      setProfile(p => ({ ...p, ...updated }));
      setDirty(false);
      window.toast?.({ message: "Tax setup saved" });
    } catch (e) {
      window.toast?.({ type: "error", message: "Failed to save" });
    }
    setSaving(false);
  };

  const selectedEntity = c.entities.find(e => e.id === entity) || c.entities[0];
  const ratePct = (selectedEntity.rate * 100).toFixed(1) + "%";

  // Compute quarterly tax estimate from real transactions.
  // Returns null when backend is online but no transactions exist yet.
  const quarterlyEst = React.useMemo(() => {
    if (!backendOnline) return null; // offline — caller passes no txState
    if (!txState || txState.length === 0) return null; // no data yet
    const year = new Date().getFullYear().toString();
    let income = 0, expense = 0;
    txState.forEach(t => {
      if (!t.date || !t.date.startsWith(year)) return;
      const usd = CB.txToUSD(t);
      if (t.type === "income") income += usd;
      else if (t.type === "expense") expense += usd;
    });
    const net = income - expense;
    if (net <= 0) return null;
    const paymentsCount = c.schedule.payments.length || 4;
    return (net * selectedEntity.rate) / paymentsCount;
  }, [txState, backendOnline, selectedEntity, c]);

  return (
    <div>
      <div className="card">
        <div style={{ display: "flex", alignItems: "start", justifyContent: "space-between", gap: 12 }}>
          <div>
            <div style={{ fontFamily: "var(--font-display)", fontSize: 22 }}>Tax setup</div>
            <div style={{ fontSize: 13, color: "var(--muted)", marginTop: 2 }}>
              Drives quarterly estimates and your Schedule C / annual reports
            </div>
          </div>
          <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
            {dirty && (
              <span style={{ fontSize: 12, color: "var(--muted)" }}>Unsaved changes</span>
            )}
            <button className="btn btn-primary" onClick={handleSave} disabled={!dirty || saving}>
              {saving ? "Saving…" : "Save"}
            </button>
          </div>
        </div>

        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16, marginTop: 18 }}>
          <div>
            <label className="label">Country / jurisdiction</label>
            <select className="input" value={country} onChange={(e) => mark(() => setCountry(e.target.value))}>
              {window.COUNTRIES.map(co => (
                <option key={co.code} value={co.code}>{co.flag} {co.name}</option>
              ))}
            </select>
          </div>
          <div>
            <label className="label">{c.regionLabel}</label>
            <select className="input" value={region} onChange={(e) => mark(() => setRegion(e.target.value))}>
              {c.regions.map(r => <option key={r} value={r}>{r}</option>)}
            </select>
          </div>
          <div>
            <label className="label">Filing status</label>
            <select className="input" value={filing} onChange={(e) => mark(() => setFiling(e.target.value))}>
              {c.filing.map(f => <option key={f} value={f}>{f}</option>)}
            </select>
          </div>
          <div>
            <label className="label">Business entity</label>
            <select className="input" value={entity} onChange={(e) => mark(() => setEntity(e.target.value))}>
              {c.entities.map(en => <option key={en.id} value={en.id}>{en.name}</option>)}
            </select>
          </div>
        </div>

        {/* Rate explanation panel */}
        <div style={{ marginTop: 18, padding: 16, background: "var(--surface-2)", borderRadius: 12, border: "1px solid var(--hairline)" }}>
          <div style={{ display: "flex", alignItems: "baseline", gap: 12 }}>
            <div style={{ fontFamily: "var(--font-display)", fontSize: 32, color: "var(--primary-ink)" }}>
              {ratePct}
            </div>
            <div>
              <div style={{ fontWeight: 500 }}>Blended effective rate for {selectedEntity.name}</div>
              <div style={{ fontSize: 12, color: "var(--muted)" }}>Used to project your tax reserve each month</div>
            </div>
          </div>
          <div style={{ marginTop: 10, fontSize: 13, color: "var(--ink-soft)", lineHeight: 1.5 }}>
            {selectedEntity.rateNote}
          </div>
        </div>

        <div style={{ marginTop: 14, fontSize: 11.5, color: "var(--muted)", display: "flex", gap: 6, alignItems: "start" }}>
          <Icon name="sparkles" size={12} />
          <div>
            Rates are 2025-2026 headline approximations. Always confirm with a local accountant —
            CreatorBoard uses these for estimates, not for filing.
          </div>
        </div>
      </div>

      {/* Scheduled tax payments */}
      <div className="card" style={{ marginTop: 16 }}>
        <div style={{ fontFamily: "var(--font-display)", fontSize: 22 }}>Scheduled tax payments</div>
        <div style={{ fontSize: 13, color: "var(--muted)", marginTop: 2 }}>
          {c.schedule.label}
        </div>
        <table className="tbl" style={{ marginTop: 12 }}>
          <thead>
            <tr>
              <th style={{ width: 140 }}>Period</th>
              <th style={{ width: 200 }}>Due</th>
              <th>Notes</th>
              <th style={{ width: 120, textAlign: "right" }}>Estimated</th>
              <th style={{ width: 120 }}>Status</th>
            </tr>
          </thead>
          <tbody>
            {c.schedule.payments.map((p) => (
              <tr key={p.q}>
                <td><b>{p.q}</b></td>
                <td style={{ color: "var(--ink-soft)" }}>{p.due}</td>
                <td style={{ color: "var(--muted)", fontSize: 12.5 }}>{p.note || "—"}</td>
                <td className="num" style={{ color: quarterlyEst ? undefined : "var(--muted)" }}>
                  {quarterlyEst ? CB.fmt(quarterlyEst, { cents: false }) : "—"}
                </td>
                <td>
                  {quarterlyEst
                    ? <Pill>Upcoming</Pill>
                    : <Pill style={{ color: "var(--muted)" }}>No data yet</Pill>}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
};

const ChannelSection = ({ backendOnline, channelState, setChannelState }) => {
  // Use real channel data from backend when online, otherwise mock data
  const channels = backendOnline ? (channelState || []) : window.CB_DATA.channels;
  const setChannels = backendOnline ? setChannelState : () => {};
  const [syncing, setSyncing] = React.useState(null);
  const [lookupInput, setLookupInput] = React.useState("");
  const [lookupLoading, setLookupLoading] = React.useState(false);
  const lookupInputRef = React.useRef(null);

  const remove = async (id) => {
    if (!confirm("Disconnect this channel?")) return;
    // Optimistic: remove from UI immediately
    const removed = channels.find(c => c.id === id);
    setChannels(cs => cs.filter(c => c.id !== id));
    // Remember handle so reconnecting can auto-link the same channel
    if (removed?.handle) {
      localStorage.setItem("yt_last_handle", removed.handle);
    }
    try {
      if (backendOnline && window.CB_API) await window.CB_API.disconnectYouTubeChannel(id);
      window.toast?.({ message: "Channel disconnected" });
    } catch (e) {
      // If the DB delete actually failed, put the channel back
      if (e?.status >= 500) {
        setChannels(cs => [...cs, removed].filter(Boolean));
        window.toast?.({ type: "error", message: "Failed to disconnect — try again" });
      } else {
        // 404 means it was already gone — fine
        window.toast?.({ message: "Channel disconnected" });
      }
    }
  };

  const syncChannel = async (id) => {
    setSyncing(id);
    try {
      const res = await window.CB_API.syncYouTubeChannel(id);
      setChannels(cs => cs.map(c => c.id === id ? {
        ...c,
        subs: res.subs,
        videos: res.videos,
        ...(res.ytdRevenueCents != null ? { ytdRevenue: res.ytdRevenueCents / 100 } : {}),
        ...(res.monthRevenueCents != null ? { monthRevenue: res.monthRevenueCents / 100 } : {}),
      } : c));
      window.toast?.({ message: "Channel stats updated" });
    } catch (e) {
      window.toast?.({ type: "error", message: "Sync failed — try reconnecting" });
    } finally {
      setSyncing(null);
    }
  };

  const connectYouTube = () => {
    if (!window.CB_API) return;
    window.location.href = window.CB_API.getYouTubeConnectUrl();
  };

  const lookupChannel = async (e) => {
    e.preventDefault();
    if (!lookupInput.trim() || !window.CB_API) return;
    setLookupLoading(true);
    try {
      const res = await window.CB_API.lookupYouTubeChannel(lookupInput.trim());
      if (res?.ok) {
        // Refresh channels from backend
        const chs = await window.CB_API.getChannels();
        setChannels(chs || []);
        setLookupInput("");
        window.toast?.({ message: `Channel "${res.channel?.name}" connected!` });
      }
    } catch (e) {
      const msg = e?.data?.error || "Channel not found. Double-check the URL or handle.";
      window.toast?.({ type: "error", message: msg });
    } finally {
      setLookupLoading(false);
    }
  };

  const totalSubs = channels.reduce((s, c) => s + (c.subs || 0), 0);
  const totalVideos = channels.reduce((s, c) => s + (c.videos || 0), 0);
  const totalYTD = channels.reduce((s, c) => s + (c.ytdRevenue || 0), 0);
  const totalMonth = channels.reduce((s, c) => s + (c.monthRevenue || 0), 0);
  const connectedCount = channels.filter(c => c.status === "connected").length;

  return (
    <div>
      <div className="card">
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "start", gap: 12 }}>
          <div>
            <div style={{ fontFamily: "var(--font-display)", fontSize: 22 }}>YouTube channels</div>
            <div style={{ fontSize: 13, color: "var(--muted)", marginTop: 2 }}>
              Connect multiple channels — each can live under a different Google account
            </div>
          </div>
          <button className="btn btn-primary" onClick={connectYouTube}>
            <Icon name="plus" size={14} /> Connect YouTube
          </button>
        </div>

        {/* Manual lookup — works for ALL account types including Brand Accounts */}
        {backendOnline && (
          <div style={{ marginTop: 16, padding: "14px 16px", background: "var(--surface-2)", borderRadius: 12, border: "1px solid var(--hairline)" }}>
            <div style={{ fontSize: 12.5, color: "var(--ink-soft)", marginBottom: 8 }}>
              <b style={{ color: "var(--ink)" }}>Add by URL or @handle</b> — paste your channel URL or handle below. Works for all account types.
            </div>
            <form onSubmit={lookupChannel} style={{ display: "flex", gap: 8 }}>
              <input
                className="input"
                style={{ flex: 1 }}
                placeholder="https://youtube.com/@yourchannel  or  @yourchannel"
                value={lookupInput}
                onChange={e => setLookupInput(e.target.value)}
              />
              <button className="btn btn-primary" type="submit" disabled={lookupLoading || !lookupInput.trim()}>
                {lookupLoading ? "Looking up…" : "Add channel"}
              </button>
            </form>
          </div>
        )}

        {/* Summary strip */}
        <div style={{ display: "grid", gridTemplateColumns: "repeat(5, 1fr)", gap: 12, marginTop: 18 }}>
          <div className="card-quiet" style={{ padding: 14 }}>
            <div style={{ fontSize: 11, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.05em" }}>Channels</div>
            <div style={{ fontFamily: "var(--font-display)", fontSize: 22, marginTop: 4 }}>
              {connectedCount}<span style={{ color: "var(--muted)", fontSize: 14 }}> / {channels.length}</span>
            </div>
          </div>
          <div className="card-quiet" style={{ padding: 14 }}>
            <div style={{ fontSize: 11, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.05em" }}>Total subs</div>
            <div style={{ fontFamily: "var(--font-display)", fontSize: 22, marginTop: 4 }}>{(totalSubs / 1000).toFixed(1)}k</div>
          </div>
          <div className="card-quiet" style={{ padding: 14 }}>
            <div style={{ fontSize: 11, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.05em" }}>Total videos</div>
            <div style={{ fontFamily: "var(--font-display)", fontSize: 22, marginTop: 4 }}>{totalVideos}</div>
          </div>
          <div className="card-quiet" style={{ padding: 14 }}>
            <div style={{ fontSize: 11, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.05em" }}>This month</div>
            <div style={{ fontFamily: "var(--font-display)", fontSize: 22, marginTop: 4 }}>
              {totalMonth > 0 ? CB.fmt(totalMonth, { cents: false }) : <span style={{ color: "var(--muted)", fontSize: 16 }}>—</span>}
            </div>
          </div>
          <div className="card-quiet" style={{ padding: 14, gridColumn: "span 1" }}>
            <div style={{ fontSize: 11, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.05em" }}>YTD revenue</div>
            <div style={{ fontFamily: "var(--font-display)", fontSize: 22, marginTop: 4 }}>
              {totalYTD > 0 ? CB.fmt(totalYTD, { cents: false }) : <span style={{ color: "var(--muted)", fontSize: 16 }}>—</span>}
            </div>
          </div>
        </div>
      </div>

      {/* Channel cards */}
      {channels.length === 0 && backendOnline && (
        <div className="card" style={{ marginTop: 16, textAlign: "center", padding: "32px 24px", color: "var(--muted)" }}>
          <div style={{ fontSize: 32, marginBottom: 8 }}>▶</div>
          <div style={{ fontWeight: 500, color: "var(--ink)", marginBottom: 4 }}>No channels connected yet</div>
          <div style={{ fontSize: 13, marginBottom: 16, lineHeight: 1.6 }}>
            Click <b>Connect YouTube</b> and sign in with your Google account. If your channel isn't detected automatically, paste its URL or @handle in the field above.
          </div>
          <button className="btn btn-primary" onClick={connectYouTube}><Icon name="plus" size={14} /> Connect YouTube</button>
        </div>
      )}
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginTop: 16 }}>
        {channels.map(c => (
          <ChannelCard key={c.id} ch={c}
            syncing={syncing === c.id}
            onSync={backendOnline ? () => syncChannel(c.id) : null}
            onRemove={() => remove(c.id)} />
        ))}
      </div>

      <div className="card-quiet" style={{ marginTop: 16, padding: 14, display: "flex", gap: 12, alignItems: "start" }}>
        <Icon name="sparkles" size={16} />
        <div style={{ fontSize: 12.5, color: "var(--ink-soft)" }}>
          <b style={{ color: "var(--ink)" }}>About multi-account access:</b> each channel signs in
          with its own Google account so AdSense payouts land under the right channel.
          We use Google's OAuth flow — no shared credentials and no read access beyond YouTube Analytics.
        </div>
      </div>
    </div>
  );
};


const ChannelCard = ({ ch, onSync, onRemove, syncing }) => {
  const connected = ch.status === "connected";
  const avatarSrc = ch.avatar || ch.avatarUrl;
  return (
    <div className="card" style={{ padding: 18 }}>
      <div style={{ display: "flex", gap: 14, alignItems: "start" }}>
        {avatarSrc
          ? <img src={avatarSrc} alt="" style={{ width: 52, height: 52, borderRadius: "50%", objectFit: "cover", flexShrink: 0 }} />
          : <div style={{
              width: 52, height: 52, borderRadius: "50%",
              background: `linear-gradient(135deg, ${ch.color || "var(--primary)"}, oklch(0.55 0.16 320))`,
              color: "white", display: "grid", placeItems: "center",
              fontFamily: "var(--font-display)", fontSize: 20, flexShrink: 0,
            }}>▶</div>
        }
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
            <span style={{ fontFamily: "var(--font-display)", fontSize: 19, lineHeight: 1.2 }}>{ch.name}</span>
            {ch.primary && <Pill kind="primary">Primary</Pill>}
          </div>
          <div style={{ fontSize: 12.5, color: "var(--muted)", marginTop: 2, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
            {ch.handle || ch.channelId} · {ch.kind || "YouTube"}
          </div>
          <div style={{ marginTop: 6, fontSize: 12, color: "var(--ink-soft)" }}>
            {connected
              ? <span style={{ color: "var(--income-text)" }}>● Connected via {ch.googleAccount}</span>
              : <span style={{ color: "var(--expense)" }}>● Disconnected</span>}
          </div>
        </div>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 8, marginTop: 14 }}>
        {[
          { l: "Subs",       v: ch.subs >= 1000 ? (ch.subs / 1000).toFixed(1) + "k" : (ch.subs || 0).toString() },
          { l: "Videos",     v: ch.videos || 0 },
          { l: "This month", v: ch.monthRevenue > 0 ? CB.fmtCompact(ch.monthRevenue) : "—" },
          { l: "YTD",        v: ch.ytdRevenue > 0 ? CB.fmtCompact(ch.ytdRevenue) : "—" },
        ].map(s => (
          <div key={s.l} style={{ padding: 8, background: "var(--surface-2)", borderRadius: 8 }}>
            <div style={{ fontSize: 10, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.05em" }}>{s.l}</div>
            <div style={{ fontFamily: "var(--font-mono)", fontSize: 13, fontWeight: 500, marginTop: 2 }}>{s.v}</div>
          </div>
        ))}
      </div>

      <div style={{ marginTop: 14, display: "flex", gap: 6, flexWrap: "wrap" }}>
        {onSync && connected && (
          <button className="btn btn-sm" onClick={onSync} disabled={syncing}>
            {syncing ? "Syncing…" : "Sync now"}
          </button>
        )}
        <button className="btn btn-sm btn-ghost" onClick={onRemove} style={{ marginLeft: "auto", color: "var(--expense)" }}>
          <Icon name="close" size={11} /> Disconnect
        </button>
      </div>
    </div>
  );
};

const AddChannelModal = ({ open, onClose, onAdd }) => {
  // Mock Google OAuth — picks an account, then a channel under that account
  const [step, setStep] = React.useState(1);
  const [account, setAccount] = React.useState(null);
  const [accountInput, setAccountInput] = React.useState("");
  const [pickedChannel, setPickedChannel] = React.useState(null);

  React.useEffect(() => { if (open) { setStep(1); setAccount(null); setPickedChannel(null); setAccountInput(""); } }, [open]);

  // Sample accounts to pick from (mock OAuth chooser)
  const KNOWN_ACCOUNTS = [
    { email: "jordan@lumenlab.tv",       name: "Jordan Lane",     avatar: "J", color: "#D97757" },
    { email: "jordan.lane@gmail.com",    name: "Jordan Lane",     avatar: "J", color: "#34A853" },
    { email: "lumenlab.shorts@gmail.com", name: "Lumen Shorts",   avatar: "L", color: "#4285F4" },
  ];

  // Fake channels Claude could discover under the picked account
  const CHANNELS_FOR = (email) => {
    const map = {
      "jordan@lumenlab.tv": [
        { id: "ch_lumen2", name: "Lumen Lab — Behind the Scenes", handle: "@lumenlab.bts", subs: 12400, videos: 38, avatar: "LB", color: "#A86040", kind: "BTS · Vlog" },
      ],
      "jordan.lane@gmail.com": [
        { id: "ch_garage", name: "Garage Sessions", handle: "@garagesessions", subs: 5200, videos: 22, avatar: "GS", color: "#3E5B7A", kind: "Music · Acoustic" },
        { id: "ch_review", name: "Tool Reviews Weekly", handle: "@toolreviewsweekly", subs: 28900, videos: 76, avatar: "TR", color: "#6B7A4F", kind: "Reviews · Tools" },
      ],
      "lumenlab.shorts@gmail.com": [
        { id: "ch_micro", name: "Micro Builds", handle: "@microbuilds", subs: 67000, videos: 124, avatar: "MB", color: "#7A5AE0", kind: "Shorts · Builds" },
      ],
    };
    return map[email] || [
      { id: "ch_" + Date.now(), name: "Your channel", handle: "@yourhandle", subs: 0, videos: 0, avatar: "?", color: "#999", kind: "Channel" },
    ];
  };

  const finish = () => {
    if (!pickedChannel || !account) return;
    onAdd({
      ...pickedChannel,
      id: pickedChannel.id + "_" + Date.now(),
      googleAccount: account.email,
      monetizedSince: "—",
      rpm: 2 + Math.random() * 4,
      status: "connected",
      primary: false,
      ytdRevenue: 0,
    });
  };

  return (
    <Modal open={open} onClose={onClose}
      title={step === 1 ? "Sign in with Google" : step === 2 ? "Pick a channel" : ""}
      subtitle={step === 1 ? "Choose the Google account that owns the channel" : "Channels we found under this account"}
      maxWidth={520}
      footer={
        step === 1
          ? <button className="btn" onClick={onClose}>Cancel</button>
          : <>
              <button className="btn" onClick={() => setStep(1)}>Back</button>
              <button className="btn btn-primary" disabled={!pickedChannel} onClick={finish}>
                Connect channel
              </button>
            </>
      }>

      {step === 1 && (
        <>
          <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
            {KNOWN_ACCOUNTS.map(a => (
              <button key={a.email}
                onClick={() => { setAccount(a); setStep(2); }}
                style={{
                  display: "flex", alignItems: "center", gap: 12, padding: 12,
                  border: "1px solid var(--hairline)", borderRadius: 12,
                  background: "var(--surface)", cursor: "pointer", textAlign: "left",
                }}>
                <div style={{
                  width: 36, height: 36, borderRadius: "50%",
                  background: a.color, color: "white",
                  display: "grid", placeItems: "center", fontWeight: 600,
                }}>{a.avatar}</div>
                <div style={{ flex: 1 }}>
                  <div style={{ fontWeight: 500, fontSize: 13.5 }}>{a.name}</div>
                  <div style={{ fontSize: 12, color: "var(--muted)" }}>{a.email}</div>
                </div>
                <Icon name="chevronRight" size={14} color="var(--muted)" />
              </button>
            ))}
          </div>
          <div style={{ marginTop: 14, padding: 12, background: "var(--surface-2)", borderRadius: 10, fontSize: 12, color: "var(--ink-soft)" }}>
            <b style={{ color: "var(--ink)" }}>Use a different Google account</b>
            <div style={{ marginTop: 6, display: "flex", gap: 6 }}>
              <input className="input" placeholder="email@gmail.com" value={accountInput} onChange={(e) => setAccountInput(e.target.value)} />
              <button className="btn btn-sm" disabled={!accountInput.includes("@")}
                onClick={() => { setAccount({ email: accountInput, name: accountInput.split("@")[0], avatar: accountInput[0].toUpperCase(), color: "#5B6BD8" }); setStep(2); }}>
                Continue
              </button>
            </div>
          </div>
          <div style={{ marginTop: 12, fontSize: 11.5, color: "var(--muted)", display: "flex", gap: 6, alignItems: "start" }}>
            <Icon name="link" size={12} />
            <div>OAuth via Google — we only request read access to YouTube Analytics. Disconnect any time.</div>
          </div>
        </>
      )}

      {step === 2 && account && (
        <>
          <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 14, padding: "10px 12px", background: "var(--surface-2)", borderRadius: 10 }}>
            <div style={{
              width: 28, height: 28, borderRadius: "50%",
              background: account.color, color: "white",
              display: "grid", placeItems: "center", fontWeight: 600, fontSize: 12,
            }}>{account.avatar}</div>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 12, color: "var(--muted)" }}>Signed in as</div>
              <div style={{ fontWeight: 500, fontSize: 13 }}>{account.email}</div>
            </div>
            <button className="btn btn-ghost btn-sm" onClick={() => setStep(1)}>Switch</button>
          </div>

          <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
            {CHANNELS_FOR(account.email).map(c => (
              <button key={c.id}
                onClick={() => setPickedChannel(c)}
                style={{
                  display: "flex", alignItems: "center", gap: 12, padding: 12,
                  border: "1.5px solid " + (pickedChannel?.id === c.id ? "var(--primary)" : "var(--hairline)"),
                  background: pickedChannel?.id === c.id ? "var(--primary-soft)" : "var(--surface)",
                  borderRadius: 12, cursor: "pointer", textAlign: "left",
                }}>
                <div style={{
                  width: 40, height: 40, borderRadius: "50%",
                  background: `linear-gradient(135deg, ${c.color}, oklch(0.55 0.16 320))`,
                  color: "white", display: "grid", placeItems: "center",
                  fontFamily: "var(--font-display)", fontSize: 16,
                }}>{c.avatar}</div>
                <div style={{ flex: 1 }}>
                  <div style={{ fontWeight: 500, fontSize: 13.5 }}>{c.name}</div>
                  <div style={{ fontSize: 11.5, color: "var(--muted)" }}>{c.handle} · {(c.subs / 1000).toFixed(1)}k subs · {c.videos} videos</div>
                </div>
                {pickedChannel?.id === c.id && <Icon name="check" size={16} color="var(--primary)" />}
              </button>
            ))}
          </div>
        </>
      )}
    </Modal>
  );
};

// Small status line + Refresh button for live FX rates. Re-renders when
// CB_FX state changes (via subscribe). Source can be live / cached / static.
const FxStatusLine = () => {
  const [, force] = React.useReducer(x => x + 1, 0);
  React.useEffect(() => window.CB_FX.subscribe(force), []);
  const s = window.CB_FX.state;
  const dot = s.source === "live"   ? "var(--income-text)" :
              s.source === "cached" ? "var(--primary)"     :
                                      "var(--muted)";
  const label = s.loading           ? "Fetching today's rates…" :
                s.source === "live"   ? "Live rates · updated " + new Date(s.updatedAt).toLocaleString("en-US", { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" }) :
                s.source === "cached" ? "Cached for today · updated " + new Date(s.updatedAt).toLocaleString("en-US", { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" }) :
                                      "Using fallback rates (couldn't reach FX provider)";
  return (
    <div style={{ marginTop: 6, fontSize: 11.5, color: "var(--muted)", display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
      <span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
        <span style={{ width: 7, height: 7, borderRadius: "50%", background: dot }} />
        {label}
      </span>
      <button className="btn btn-ghost btn-sm" disabled={s.loading}
        style={{ padding: "2px 8px", fontSize: 11 }}
        onClick={() => window.CB_FX.refresh(true)}>
        <Icon name="refresh" size={11} /> Refresh
      </button>
    </div>
  );
};

const ProfileSection = ({ profile, setProfile, onReplayOnboarding }) => {
  const update = (key, value) => setProfile({ ...profile, [key]: value });
  const [saving, setSaving] = React.useState(false);
  const [savedMsg, setSavedMsg] = React.useState("");
  // Common tax-ID labels per common country
  const taxLabels = ["EIN", "VAT", "GST", "ABN", "CUI", "PIB", "NIF", "Tax ID"];

  const saveProfile = async () => {
    if (!window.CB_API) return;
    setSaving(true);
    try {
      await window.CB_API.updateMe({
        fullName: profile.ownerName,
        businessName: profile.businessName,
        addressLine1: profile.addressLine1,
        addressLine2: profile.addressLine2,
        countryCode: profile.country,
        taxIdLabel: profile.taxIdLabel,
        taxId: profile.taxId,
        website: profile.website,
        phone: profile.phone,
        baseCurrency: profile.baseCurrency,
        bankDetails: profile.bankDetails,
      });
      setSavedMsg("Saved");
      setTimeout(() => setSavedMsg(""), 2500);
    } catch(e) {
      window.toast?.({ type: "error", message: "Failed to save profile" });
    } finally {
      setSaving(false);
    }
  };

  return (
    <div>
      <div className="card">
        <div style={{ fontFamily: "var(--font-display)", fontSize: 22 }}>Personal</div>
        <div style={{ fontSize: 13, color: "var(--muted)", marginTop: 2, marginBottom: 14 }}>
          Who you are
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
          <div><label className="label">Full name</label>
            <input className="input" value={profile.ownerName || ""} onChange={(e) => update("ownerName", e.target.value)} /></div>
          <div><label className="label">Email</label>
            <input className="input" value={profile.email || ""} onChange={(e) => update("email", e.target.value)} /></div>
          <div><label className="label">Phone</label>
            <input className="input" value={profile.phone || ""} onChange={(e) => update("phone", e.target.value)} /></div>
          <div><label className="label">Website</label>
            <input className="input" value={profile.website || ""} onChange={(e) => update("website", e.target.value)} /></div>
        </div>
      </div>

      <div className="card" style={{ marginTop: 16 }}>
        <div style={{ fontFamily: "var(--font-display)", fontSize: 22 }}>Business</div>
        <div style={{ fontSize: 13, color: "var(--muted)", marginTop: 2, marginBottom: 14 }}>
          These details appear as the <b>seller</b> on every invoice
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
          <div style={{ gridColumn: "1 / -1" }}>
            <label className="label">Business / legal name</label>
            <input className="input" value={profile.businessName || ""} onChange={(e) => update("businessName", e.target.value)} />
          </div>
          <div style={{ gridColumn: "1 / -1" }}>
            <label className="label">Address line 1</label>
            <input className="input" value={profile.addressLine1 || ""} onChange={(e) => update("addressLine1", e.target.value)}
              placeholder="Street, suite, unit" />
          </div>
          <div style={{ gridColumn: "1 / -1" }}>
            <label className="label">Address line 2 (city, state, ZIP)</label>
            <input className="input" value={profile.addressLine2 || ""} onChange={(e) => update("addressLine2", e.target.value)} />
          </div>
          <div><label className="label">Country</label>
            <input className="input" value={profile.country || ""} onChange={(e) => update("country", e.target.value)} /></div>
          <div style={{ display: "grid", gridTemplateColumns: "100px 1fr", gap: 8 }}>
            <div>
              <label className="label">Tax label</label>
              <select className="input" value={profile.taxIdLabel || "EIN"} onChange={(e) => update("taxIdLabel", e.target.value)}>
                {taxLabels.map(t => <option key={t} value={t}>{t}</option>)}
              </select>
            </div>
            <div>
              <label className="label">Tax ID</label>
              <input className="input" value={profile.taxId || ""} onChange={(e) => update("taxId", e.target.value)}
                placeholder="e.g. 87-2913045" />
            </div>
          </div>
          <div style={{ gridColumn: "1 / -1" }}>
            <label className="label">Base currency</label>
            <select className="input" value={profile.baseCurrency || "USD"} onChange={(e) => update("baseCurrency", e.target.value)}>
              {Object.values(window.CB_DATA.currencies).map(c => (
                <option key={c.code} value={c.code}>{c.symbol} {c.code} — {c.name}</option>
              ))}
            </select>
            <FxStatusLine />
          </div>
          <div style={{ gridColumn: "1 / -1" }}>
            <label className="label">Tax reporting currency</label>
            {(() => {
              const code = profile?.countryCode || profile?.country;
              const found = window.COUNTRIES?.find(c => c.code === code);
              return (
                <div style={{
                  display: "flex", alignItems: "center", gap: 10,
                  padding: "10px 12px",
                  background: "var(--surface-2)",
                  border: "1px solid var(--hairline)",
                  borderRadius: 8,
                  cursor: "default",
                }}>
                  {found ? (
                    <>
                      <span style={{ fontFamily: "var(--font-mono)", fontWeight: 600, fontSize: 14, color: "var(--ink)" }}>
                        {found.currency}
                      </span>
                      <span style={{ fontSize: 12.5, color: "var(--ink-soft)" }}>
                        {found.flag} {found.name}
                      </span>
                    </>
                  ) : (
                    <span style={{ fontSize: 12.5, color: "var(--muted)" }}>
                      Set your country in Tax Setup to enable this
                    </span>
                  )}
                  <span style={{ marginLeft: "auto", display: "inline-flex", alignItems: "center", gap: 4, fontSize: 11.5, color: "var(--muted)" }}>
                    <Icon name="lock" size={12} /> auto-set from Tax Setup
                  </span>
                </div>
              );
            })()}
            <div style={{ fontSize: 11.5, color: "var(--muted)", marginTop: 5, lineHeight: 1.5 }}>
              Used as the secondary currency in P&L reports and exports. Automatically reflects your country selection in Tax Setup.
            </div>
          </div>
          <div style={{ gridColumn: "1 / -1" }}>
            <label className="label">Payment details (shown on invoices)</label>
            <input className="input" value={profile.bankDetails || ""} onChange={(e) => update("bankDetails", e.target.value)}
              placeholder="Bank · routing/SWIFT · account ending" />
          </div>
        </div>
      </div>

      <div style={{ marginTop: 16, display: "flex", justifyContent: "flex-end", alignItems: "center", gap: 12 }}>
        {savedMsg && <span style={{ fontSize: 13, color: "var(--income)" }}>{savedMsg}</span>}
        <button className="btn btn-primary" onClick={saveProfile} disabled={saving || !window.CB_API}>
          {saving ? "Saving…" : "Save profile"}
        </button>
      </div>

      <div className="card" style={{ marginTop: 16 }}>
        <div style={{ fontFamily: "var(--font-display)", fontSize: 22 }}>Re-run setup</div>
        <div style={{ fontSize: 13, color: "var(--muted)", marginTop: 4, marginBottom: 14 }}>
          Walk through onboarding again to change country, entity, or reconnect accounts
        </div>
        <button className="btn" onClick={onReplayOnboarding}>
          <Icon name="refresh" size={14} /> Replay onboarding
        </button>
      </div>
    </div>
  );
};


// ─── Rules section ─────────────────────────────────────────────────
const RulesSection = ({ rules, setRules, txState, setTxState }) => {
  const [addOpen, setAddOpen] = React.useState(false);
  const [runResult, setRunResult] = React.useState(null);

  const deleteRule = async (id) => {
    try {
      if (window.CB_API) await window.CB_API.deleteRule(id);
      setRules(rs => rs.filter(r => r.id !== id));
    } catch(e) {
      window.toast?.({ type: "error", message: "Failed to delete rule" });
    }
  };

  const runRules = async () => {
    setRunResult({ loading: true });
    const result = window.CB_INTEL.runRulesOverLedger(rules, txState);
    setTxState(result.updated);
    setRunResult(result);
    window.toast?.({ message: `Rules applied · ${result.categorized} categorized, ${result.reviewCleared} cleared from review` });
    setTimeout(() => setRunResult(null), 4000);
    if (window.CB_API && result.categorized > 0) {
      const changed = result.updated.filter((t, i) => t.category !== txState[i]?.category || t.needsReview !== txState[i]?.needsReview);
      await Promise.allSettled(changed.map(t =>
        window.CB_API.updateTransaction(t.id, { categoryId: t.category, needsReview: t.needsReview })
      ));
    }
  };

  // Count matches in current ledger
  const ruleMatchCounts = React.useMemo(() => {
    const counts = {};
    rules.forEach(r => {
      counts[r.id] = txState.filter(t => window.CB_INTEL.ruleMatches(r, t)).length;
    });
    return counts;
  }, [rules, txState]);

  return (
    <div>
      <div className="card">
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "start" }}>
          <div>
            <div style={{ fontFamily: "var(--font-display)", fontSize: 22 }}>Auto-categorization rules</div>
            <div style={{ fontSize: 13, color: "var(--muted)", marginTop: 2 }}>
              Run on every incoming transaction · top-to-bottom priority
            </div>
          </div>
          <div style={{ display: "flex", gap: 8 }}>
            <button className="btn" onClick={runRules}>
              <Icon name="sparkles" size={14} /> Run on ledger
            </button>
            <button className="btn btn-primary" onClick={() => setAddOpen(true)}>
              <Icon name="plus" size={14} /> New rule
            </button>
          </div>
        </div>

        {runResult && runResult.loading && (
          <div style={{
            marginTop: 14, padding: 12, borderRadius: 10,
            background: "var(--surface-2)", color: "var(--ink-soft)",
            display: "flex", alignItems: "center", gap: 10, fontSize: 13,
          }}>
            <span style={{
              display: "inline-block", width: 14, height: 14,
              border: "2px solid var(--hairline-strong)", borderTopColor: "var(--primary)",
              borderRadius: "50%", animation: "spin 0.7s linear infinite",
            }} />
            Applying rules to every transaction in your ledger…
          </div>
        )}
        {runResult && !runResult.loading && (
          <div style={{
            marginTop: 14, padding: 12, borderRadius: 10,
            background: "var(--income-soft)", color: "var(--income-text-strong)",
            display: "flex", alignItems: "center", gap: 8, fontSize: 13,
          }}>
            <Icon name="check" size={14} />
            Categorized {runResult.categorized} · cleared {runResult.reviewCleared} from review
          </div>
        )}

        <table className="tbl" style={{ marginTop: 14 }}>
          <thead>
            <tr>
              <th style={{ width: 30 }}>#</th>
              <th>When</th>
              <th>Set category</th>
              <th style={{ width: 100, textAlign: "right" }}>Matches</th>
              <th style={{ width: 40 }}></th>
            </tr>
          </thead>
          <tbody>
            {rules.map((r, i) => {
              const cat = CB.catById(r.category);
              return (
                <tr key={r.id}>
                  <td style={{ color: "var(--muted)", fontFamily: "var(--font-mono)", fontSize: 12 }}>{i + 1}</td>
                  <td style={{ fontSize: 13 }}>{r.description}</td>
                  <td>
                    <span className="pill" style={{ background: "var(--surface-2)" }}>
                      <span className="cat-swatch" style={{ background: cat?.color }} />
                      {cat?.name}
                    </span>
                  </td>
                  <td className="num" style={{ color: "var(--ink-soft)" }}>{ruleMatchCounts[r.id] || 0}</td>
                  <td>
                    <button className="btn btn-ghost btn-sm" onClick={() => deleteRule(r.id)} aria-label="Delete rule">
                      <Icon name="close" size={12} />
                    </button>
                  </td>
                </tr>
              );
            })}
            {rules.length === 0 && (
              <tr><td colSpan="5" className="empty">No rules yet. Create one to auto-categorize transactions.</td></tr>
            )}
          </tbody>
        </table>
      </div>

      <div className="card-quiet" style={{ marginTop: 16, padding: 14, display: "flex", gap: 12, alignItems: "start" }}>
        <Icon name="sparkles" size={16} />
        <div style={{ fontSize: 12.5, color: "var(--ink-soft)" }}>
          <b style={{ color: "var(--ink)" }}>How rules work:</b> when a new transaction is imported,
          rules run in order. The first match wins and sets the category.
          You can also create rules directly from the Review inbox by accepting a suggestion with "Accept + make rule".
        </div>
      </div>

      <AddRuleModal
        open={addOpen}
        onClose={() => setAddOpen(false)}
        onAdd={async (rule) => {
          try {
            if (window.CB_API) {
              const saved = await window.CB_API.createRule({ match: rule.match, categoryId: rule.category, description: rule.description });
              setRules(rs => [...rs, { id: saved.id, match: saved.match, category: saved.category, description: saved.description, priority: saved.priority }]);
            } else {
              setRules(rs => [...rs, rule]);
            }
            setAddOpen(false);
          } catch(e) {
            window.toast?.({ type: "error", message: "Failed to create rule" });
          }
        }}
      />
    </div>
  );
};

const AddRuleModal = ({ open, onClose, onAdd }) => {
  const [vendor, setVendor] = React.useState("");
  const [category, setCategory] = React.useState("software");
  const [type, setType] = React.useState("expense");

  React.useEffect(() => { if (open) { setVendor(""); setCategory("software"); setType("expense"); } }, [open]);

  const cats = type === "income" ? window.CB_DATA.categories.income : window.CB_DATA.categories.expense;
  React.useEffect(() => { if (open) setCategory(cats[0].id); }, [type, open]);

  const submit = () => {
    if (!vendor.trim()) return;
    const rule = {
      id: "r_" + Date.now(),
      match: { vendorContains: vendor.trim() },
      category,
      description: `Match: vendor contains "${vendor.trim()}"`,
    };
    onAdd(rule);
  };

  return (
    <Modal open={open} onClose={onClose}
      title="New auto-rule"
      subtitle="Future transactions matching this pattern will be auto-categorized"
      footer={<><button className="btn" onClick={onClose}>Cancel</button>
              <button className="btn btn-primary" onClick={submit} disabled={!vendor.trim()}>Create rule</button></>}>
      <div style={{ display: "flex", gap: 8, marginBottom: 16 }}>
        <button type="button"
          className={"chip" + (type === "expense" ? " on" : "")}
          style={{ flex: 1, justifyContent: "center", padding: 10 }}
          onClick={() => setType("expense")}>Expenses</button>
        <button type="button"
          className={"chip" + (type === "income" ? " on" : "")}
          style={{ flex: 1, justifyContent: "center", padding: 10 }}
          onClick={() => setType("income")}>Income</button>
      </div>

      <label className="label">When vendor contains</label>
      <input className="input" value={vendor} onChange={(e) => setVendor(e.target.value)}
        placeholder='e.g. "Adobe" or "B&H"' autoFocus />

      <label className="label" style={{ marginTop: 14 }}>Then categorize as</label>
      <div className="tag-grid" style={{ marginTop: 6 }}>
        {cats.map(c => (
          <button key={c.id} type="button"
            className={"chip" + (category === c.id ? " on" : "")}
            onClick={() => setCategory(c.id)}>
            <span className="cat-swatch" style={{ background: c.color }} />
            {c.name}
          </button>
        ))}
      </div>
    </Modal>
  );
};

const BillingSection = () => (
  <div className="card">
    <div style={{ fontFamily: "var(--font-display)", fontSize: 22 }}>CreatorBoard plan</div>
    <div style={{ display: "flex", alignItems: "center", gap: 12, marginTop: 14 }}>
      <Pill kind="primary">Creator · $12 / mo</Pill>
      <span style={{ fontSize: 13, color: "var(--muted)" }}>Renews Jun 14, 2026 on Amex ··1003</span>
    </div>
    <div style={{ marginTop: 14, display: "flex", gap: 8 }}>
      <button className="btn">Manage plan</button>
      <button className="btn btn-ghost">View invoices</button>
    </div>
  </div>
);

window.Settings = Settings;
