// Finance (FRM) — journal entries, invoicing, and statements. No setup screens.

const FIN_TODAY = new Date('2026-05-15');

// Reusable pagination hook + control for finance lists
function usePaged(rows, pageSize = 8) {
  const [page, setPage] = useState(1);
  const total = rows.length;
  const pages = Math.max(1, Math.ceil(total / pageSize));
  const cur = Math.min(page, pages);
  const start = (cur - 1) * pageSize;
  const slice = rows.slice(start, start + pageSize);
  useEffect(() => { setPage(1); }, [total]);
  return { slice, page: cur, pages, setPage, total, start, end: Math.min(start + pageSize, total) };
}

function Pagination({ pg }) {
  if (!pg || pg.total === 0) return null;
  return (
    <div className="pager">
      <span className="pager-info">Showing {pg.start + 1}–{pg.end} of {pg.total}</span>
      <div className="pager-ctrls">
        <button className="pager-btn" disabled={pg.page <= 1} onClick={() => pg.setPage(pg.page - 1)} aria-label="Previous page"><Icon name="chev_l" size={13} /></button>
        {Array.from({ length: pg.pages }, (_, i) => i + 1).map(n => (
          <button key={n} className={`pager-btn ${n === pg.page ? 'active' : ''}`} onClick={() => pg.setPage(n)}>{n}</button>
        ))}
        <button className="pager-btn" disabled={pg.page >= pg.pages} onClick={() => pg.setPage(pg.page + 1)} aria-label="Next page"><Icon name="chev_r" size={13} /></button>
      </div>
    </div>
  );
}

// ─── Overview ──────────────────────────────────────────────
function FinanceOverview({ onNavigate }) {
  const D = window.HitcentsData;
  const p = D.FIN_PNL;
  const totalRev = p.revenue.reduce((s, r) => s + r.amount, 0);
  const netIncome = totalRev - p.cogs.reduce((s, r) => s + r.amount, 0) - p.opex.reduce((s, r) => s + r.amount, 0);
  const cash = D.FIN_BANK_ACCOUNTS.filter(a => a.type !== 'Credit card').reduce((s, a) => s + a.balance, 0);
  const ar = D.FIN_INVOICES.filter(i => i.status === 'Sent' || i.status === 'Overdue').reduce((s, i) => s + window.invoiceTotal(i), 0);
  const ap = D.FIN_BILLS.filter(b => b.status === 'Open' || b.status === 'Overdue').reduce((s, b) => s + b.amount, 0);
  const overdueInv = D.FIN_INVOICES.filter(i => i.status === 'Overdue');
  const overdueBills = D.FIN_BILLS.filter(b => b.status === 'Overdue');

  return (
    <div data-screen-label="Finance">
      <div className="page-head">
        <div>
          <h1>Finance</h1>
          <div className="sub">Financial overview · {p.period} · accrual basis</div>
        </div>
        <div className="row gap-2">
          <Button variant="secondary" icon="doc" onClick={() => onNavigate('fin-reports')}>Reports</Button>
          <Button variant="primary" icon="plus" onClick={() => onNavigate('fin-invoices')}>New invoice</Button>
        </div>
      </div>

      <div className="grid g-4" style={{ marginBottom: 16, gap: 12 }}>
        <Kpi label="Cash on hand" value={fmtMoney(cash)} delta={`${D.FIN_BANK_ACCOUNTS.filter(a => a.type !== 'Credit card').length} accounts`} tone="up" />
        <Kpi label="Accounts receivable" value={fmtMoney(ar)} delta={`${overdueInv.length} overdue`} tone={overdueInv.length ? 'down' : undefined} />
        <Kpi label="Accounts payable" value={fmtMoney(ap)} delta={`${overdueBills.length} overdue`} tone={overdueBills.length ? 'down' : undefined} />
        <Kpi label={`Net income — ${p.period}`} value={fmtMoney(netIncome)} delta={netIncome >= 0 ? 'profit' : 'net loss'} tone={netIncome >= 0 ? 'up' : 'down'} />
      </div>

      <div className="grid" style={{ gridTemplateColumns: '1.5fr 1fr', gap: 16 }}>
        <div className="col" style={{ gap: 16 }}>
          <div className="card">
            <div className="card-h"><div><h3>Cash accounts</h3></div><Button size="sm" variant="ghost" iconRight="arrow_r" onClick={() => onNavigate('fin-banking')}>Banking</Button></div>
            <div className="col" style={{ gap: 8 }}>
              {D.FIN_BANK_ACCOUNTS.map(a => (
                <div key={a.id} className="row gap-3" style={{ padding: '10px 12px', background: 'var(--bg-elev)', borderRadius: 9 }}>
                  <div className="lic-glyph" style={{ background: a.type === 'Credit card' ? 'var(--purple)' : 'var(--brand-wine)' }}><Icon name="card" size={15} /></div>
                  <div style={{ flex: 1 }}>
                    <div style={{ fontWeight: 500, fontSize: 13 }}>{a.name}</div>
                    <div className="dim mono" style={{ fontSize: 11 }}>{a.bank} ··{a.last4}</div>
                  </div>
                  <div className="mono" style={{ fontWeight: 600, color: a.balance < 0 ? 'var(--red)' : 'var(--text)' }}>{a.balance < 0 ? `(${fmtMoneyFull(Math.abs(a.balance))})` : fmtMoneyFull(a.balance)}</div>
                </div>
              ))}
            </div>
          </div>

          <div className="card">
            <div className="card-h"><div><h3>Recent transactions</h3></div><Button size="sm" variant="ghost" iconRight="arrow_r" onClick={() => onNavigate('fin-banking')}>All</Button></div>
            <div className="col">
              {D.FIN_TRANSACTIONS.slice(0, 6).map(t => (
                <div key={t.id} className="row gap-3" style={{ padding: '8px 0', borderTop: '1px solid var(--border)' }}>
                  <span className="muted mono" style={{ fontSize: 11, width: 44 }}>{fmtDateShort(t.date)}</span>
                  <span style={{ flex: 1, fontSize: 13 }}>{t.desc}</span>
                  <span className="mono" style={{ fontWeight: 500, color: t.amount < 0 ? 'var(--red)' : 'var(--green)' }}>{t.amount < 0 ? '−' : '+'}{fmtMoneyFull(Math.abs(t.amount))}</span>
                </div>
              ))}
            </div>
          </div>
        </div>

        <div className="col" style={{ gap: 16 }}>
          <div className="card">
            <div className="card-h"><div><h3>Needs attention</h3></div></div>
            <div className="col" style={{ gap: 8 }}>
              {overdueInv.map(i => {
                const c = getCustomer(i.customer);
                return (
                  <div key={i.id} className="row gap-2" style={{ padding: '9px 11px', background: 'var(--red-tint)', borderRadius: 8, cursor: 'pointer' }} onClick={() => onNavigate('fin-invoices')}>
                    <Icon name="arrow_u" size={13} style={{ color: 'var(--red)' }} />
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 12.5, fontWeight: 500 }}>{c?.name}</div>
                      <div className="dim" style={{ fontSize: 11 }}>{i.id} overdue</div>
                    </div>
                    <span className="mono" style={{ fontSize: 12, fontWeight: 600, color: '#832E1C' }}>{fmtMoneyFull(window.invoiceTotal(i))}</span>
                  </div>
                );
              })}
              {overdueBills.map(b => (
                <div key={b.id} className="row gap-2" style={{ padding: '9px 11px', background: 'var(--amber-tint)', borderRadius: 8, cursor: 'pointer' }} onClick={() => onNavigate('fin-bills')}>
                  <Icon name="arrow_d" size={13} style={{ color: 'var(--amber)' }} />
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 12.5, fontWeight: 500 }}>{b.vendor}</div>
                    <div className="dim" style={{ fontSize: 11 }}>{b.id} past due</div>
                  </div>
                  <span className="mono" style={{ fontSize: 12, fontWeight: 600, color: '#8A5713' }}>{fmtMoneyFull(b.amount)}</span>
                </div>
              ))}
            </div>
          </div>

          <div className="card">
            <div className="card-h"><div><h3>This month</h3></div></div>
            <div className="col" style={{ gap: 0 }}>
              <div className="fin-row"><span className="muted">Revenue</span><span className="mono">{fmtMoneyFull(totalRev)}</span></div>
              <div className="fin-row"><span className="muted">Expenses</span><span className="mono">{fmtMoneyFull(totalRev - netIncome)}</span></div>
              <div className="fin-row" style={{ borderTop: '1px solid var(--border)', marginTop: 4, paddingTop: 8, fontWeight: 600 }}>
                <span>Net income</span><span className="mono" style={{ color: netIncome >= 0 ? 'var(--green)' : 'var(--red)' }}>{netIncome < 0 ? `(${fmtMoneyFull(Math.abs(netIncome))})` : fmtMoneyFull(netIncome)}</span>
              </div>
            </div>
            <Button variant="ghost" size="sm" iconRight="arrow_r" style={{ marginTop: 10, width: '100%', justifyContent: 'center' }} onClick={() => onNavigate('fin-reports')}>View P&amp;L</Button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ─── Invoices (A/R) screen ─────────────────────────────────
function FinanceInvoices() {
  return (
    <div data-screen-label="Invoices">
      <div className="page-head">
        <div><h1>Invoices</h1><div className="sub">Accounts receivable · customer billing</div></div>
      </div>
      <InvoicesView />
    </div>
  );
}

// ─── Bills (A/P) screen ────────────────────────────────────
function FinanceBills() {
  return (
    <div data-screen-label="Bills">
      <div className="page-head">
        <div><h1>Bills</h1><div className="sub">Accounts payable · vendor bills & expenses</div></div>
      </div>
      <BillsView />
    </div>
  );
}

// ─── Banking screen ────────────────────────────────────────
function FinanceBanking() {
  return (
    <div data-screen-label="Banking">
      <div className="page-head">
        <div><h1>Banking</h1><div className="sub">Cash accounts & transaction reconciliation</div></div>
      </div>
      <BankingView />
    </div>
  );
}

// ─── General Ledger screen ─────────────────────────────────
function FinanceLedger() {
  const [view, setView] = useState('journal');
  return (
    <div data-screen-label="General Ledger">
      <div className="page-head">
        <div><h1>General ledger</h1><div className="sub">Journal · chart of accounts · trial balance</div></div>
      </div>
      <div className="tabs" style={{ marginBottom: 16 }}>
        {[['journal', 'Journal'], ['coa', 'Chart of accounts'], ['tb', 'Trial balance']].map(([id, label]) => (
          <button key={id} className={`tab ${view === id ? 'active' : ''}`} onClick={() => setView(id)}>{label}</button>
        ))}
      </div>
      {view === 'journal' && <JournalView />}
      {view === 'coa' && <ChartOfAccountsView />}
      {view === 'tb' && <TrialBalanceView />}
    </div>
  );
}

// ─── Reporting periods ─────────────────────────────────────
// `factor` scales the base monthly flow figures (P&L, cash flow).
// `asOf` drives point-in-time reports (balance sheet, aging).
// `begin` is opening cash for the cash-flow statement.
const FIN_PERIODS = [
  { id: 'this-month', label: 'This month',     sub: 'May 2026',          flow: 'May 2026',            factor: 1.00,  asOf: '2026-05-31', begin: 1259734 },
  { id: 'last-month', label: 'Last month',     sub: 'April 2026',        flow: 'April 2026',          factor: 0.92,  asOf: '2026-04-30', begin: 1196400 },
  { id: 'q2',         label: 'Q2 2026',        sub: 'Apr – Jun 2026',    flow: 'Q2 2026',             factor: 2.96,  asOf: '2026-06-30', begin: 1196400 },
  { id: 'q1',         label: 'Q1 2026',        sub: 'Jan – Mar 2026',    flow: 'Q1 2026',             factor: 2.74,  asOf: '2026-03-31', begin: 1042000 },
  { id: 'ytd',        label: 'Year to date',   sub: 'Jan – May 2026',    flow: 'YTD 2026',            factor: 5.69,  asOf: '2026-05-31', begin: 1042000 },
  { id: 'fy2025',     label: 'FY 2025',        sub: 'Full year 2025',    flow: 'FY 2025',             factor: 10.4,  asOf: '2025-12-31', begin: 612000 },
];

function monthsBetween(a, b) {
  const d1 = new Date(a), d2 = new Date(b);
  return Math.max(1, (d2.getFullYear() - d1.getFullYear()) * 12 + (d2.getMonth() - d1.getMonth()) + 1);
}

// Deterministic ±6% wobble so scaled line items don't look uniform.
function finWobble(name, k) {
  const seed = [...String(name)].reduce((s, c) => s + c.charCodeAt(0), 0);
  return 1 + ((((seed * (k + 1)) % 13) - 6) / 100);
}
function finScale(amount, name, period) {
  return Math.round(amount * period.factor * finWobble(name, period.k) / 100) * 100;
}

function PeriodPicker({ period, setPeriod, custom, setCustom }) {
  const isCustom = period.id === 'custom';
  return (
    <div className="fin-period">
      <Icon name="cal" size={14} style={{ color: 'var(--text-muted)' }} />
      <select
        value={period.id}
        onChange={e => {
          if (e.target.value === 'custom') {
            setPeriod(makeCustomPeriod(custom.start, custom.end));
          } else {
            setPeriod({ ...FIN_PERIODS.find(p => p.id === e.target.value), k: FIN_PERIODS.findIndex(p => p.id === e.target.value) });
          }
        }}>
        {FIN_PERIODS.map(p => <option key={p.id} value={p.id}>{p.label} · {p.sub}</option>)}
        <option value="custom">Custom range…</option>
      </select>
      {isCustom && (
        <div className="fin-period-custom">
          <input type="date" value={custom.start} max={custom.end}
                 onChange={e => { const c = { ...custom, start: e.target.value }; setCustom(c); setPeriod(makeCustomPeriod(c.start, c.end)); }} />
          <span className="dim">→</span>
          <input type="date" value={custom.end} min={custom.start}
                 onChange={e => { const c = { ...custom, end: e.target.value }; setCustom(c); setPeriod(makeCustomPeriod(c.start, c.end)); }} />
        </div>
      )}
    </div>
  );
}

function makeCustomPeriod(start, end) {
  const months = monthsBetween(start, end);
  return {
    id: 'custom', k: 7,
    flow: `${fmtDateShort(start)} – ${fmtDateShort(end)}`,
    sub: `${months} month${months > 1 ? 's' : ''}`,
    factor: months * 0.97,
    asOf: end,
    begin: 1042000,
  };
}

// ─── Reports screen ────────────────────────────────────────
function FinanceReports() {
  const [view, setView] = useState('pnl');
  const [period, setPeriod] = useState({ ...FIN_PERIODS[0], k: 0 });
  const [custom, setCustom] = useState({ start: '2026-01-01', end: '2026-05-31' });

  const pointInTime = view === 'balance' || view === 'aging' || view === 'apaging';

  return (
    <div data-screen-label="Reports">
      <div className="page-head">
        <div><h1>Reports</h1><div className="sub">Financial statements & analysis</div></div>
        <PeriodPicker period={period} setPeriod={setPeriod} custom={custom} setCustom={setCustom} />
      </div>
      <div className="tabs" style={{ marginBottom: 16 }}>
        {[['pnl', 'P&L'], ['balance', 'Balance sheet'], ['cashflow', 'Cash flow'], ['aging', 'A/R aging'], ['apaging', 'A/P aging']].map(([id, label]) => (
          <button key={id} className={`tab ${view === id ? 'active' : ''}`} onClick={() => setView(id)}>{label}</button>
        ))}
      </div>
      <div className="fin-period-note">
        {pointInTime
          ? <><Icon name="clock" size={12} /> As of <strong>{fmtDate(period.asOf)}</strong></>
          : <><Icon name="chart" size={12} /> Reporting period: <strong>{period.flow}</strong></>}
      </div>
      {view === 'pnl' && <PnLView period={period} />}
      {view === 'balance' && <BalanceSheetView period={period} />}
      {view === 'cashflow' && <CashFlowView period={period} />}
      {view === 'aging' && <AgingView asOf={period.asOf} />}
      {view === 'apaging' && <APAgingView asOf={period.asOf} />}
    </div>
  );
}

// ─── Journal ───────────────────────────────────────────────
function JournalView() {
  const D = window.HitcentsData;
  const [entries, setEntries] = useState(D.FIN_JOURNAL);
  const [open, setOpen] = useState(null);
  const [addOpen, setAddOpen] = useState(false);
  const [q, setQ] = useState('');

  const rows = entries.filter(e => !q || `${e.id} ${e.ref} ${e.memo}`.toLowerCase().includes(q.toLowerCase()));
  const pg = usePaged(rows, 8);

  return (
    <>
      <div className="toolbar">
        <div className="search-inline">
          <Icon name="search" size={14} />
          <input placeholder="Search entries…" value={q} onChange={e => setQ(e.target.value)} />
        </div>
        <div style={{ marginLeft: 'auto' }}>
          <Button variant="primary" icon="plus" onClick={() => setAddOpen(true)}>New entry</Button>
        </div>
      </div>

      <div className="card flush">
        <table className="table">
          <thead><tr><th>Entry</th><th>Date</th><th>Reference</th><th>Memo</th><th>Amount</th><th>Status</th></tr></thead>
          <tbody>
            {pg.slice.map(e => {
              const amt = e.lines.reduce((s, l) => s + l.debit, 0);
              return (
                <tr key={e.id} className="clickable" onClick={() => setOpen(e)}>
                  <td className="mono" style={{ fontSize: 12, fontWeight: 500 }}>{e.id}</td>
                  <td className="muted mono" style={{ fontSize: 11.5 }}>{fmtDateShort(e.date)}</td>
                  <td><Badge>{e.ref}</Badge></td>
                  <td style={{ maxWidth: 320, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{e.memo}</td>
                  <td className="mono" style={{ fontWeight: 500 }}>{fmtMoneyFull(amt)}</td>
                  <td><Badge tone={e.posted ? 'green' : 'amber'}>{e.posted ? 'Posted' : 'Draft'}</Badge></td>
                </tr>
              );
            })}
          </tbody>
        </table>
        <div style={{ padding: '0 14px 8px' }}><Pagination pg={pg} /></div>
      </div>

      <Drawer open={!!open} onClose={() => setOpen(null)} title="Journal entry" width={560}>
        {open && <JournalDetail entry={open} />}
      </Drawer>
      {addOpen && <JournalEntryModal onClose={() => setAddOpen(false)} onCreate={(je) => { D.FIN_JOURNAL.unshift(je); setEntries([je, ...entries]); setAddOpen(false); setOpen(je); }} />}
    </>
  );
}

function JournalDetail({ entry }) {
  const totalDr = entry.lines.reduce((s, l) => s + l.debit, 0);
  const totalCr = entry.lines.reduce((s, l) => s + l.credit, 0);
  return (
    <div>
      <div className="row spread" style={{ marginBottom: 14 }}>
        <div>
          <h2 style={{ margin: 0, fontSize: 19, fontWeight: 600 }}>{entry.id}</h2>
          <div className="muted" style={{ fontSize: 13 }}>{fmtDate(entry.date)} · {entry.ref}</div>
        </div>
        <Badge tone={entry.posted ? 'green' : 'amber'}>{entry.posted ? 'Posted' : 'Draft'}</Badge>
      </div>
      <p style={{ marginTop: 0, fontSize: 13.5 }}>{entry.memo}</p>

      <div className="card flush" style={{ marginTop: 8 }}>
        <table className="table">
          <thead><tr><th>Account</th><th style={{ textAlign: 'right' }}>Debit</th><th style={{ textAlign: 'right' }}>Credit</th></tr></thead>
          <tbody>
            {entry.lines.map((l, i) => {
              const a = window.finAccount(l.code);
              return (
                <tr key={i}>
                  <td><span className="mono dim" style={{ fontSize: 11 }}>{l.code}</span> {a?.name}</td>
                  <td className="mono" style={{ textAlign: 'right' }}>{l.debit ? fmtMoneyFull(l.debit) : ''}</td>
                  <td className="mono" style={{ textAlign: 'right' }}>{l.credit ? fmtMoneyFull(l.credit) : ''}</td>
                </tr>
              );
            })}
            <tr style={{ borderTop: '2px solid var(--border-strong)' }}>
              <td style={{ fontWeight: 600 }}>Total</td>
              <td className="mono" style={{ textAlign: 'right', fontWeight: 600 }}>{fmtMoneyFull(totalDr)}</td>
              <td className="mono" style={{ textAlign: 'right', fontWeight: 600 }}>{fmtMoneyFull(totalCr)}</td>
            </tr>
          </tbody>
        </table>
      </div>
      <div className="row gap-2" style={{ marginTop: 10, fontSize: 12, color: totalDr === totalCr ? 'var(--green)' : 'var(--red)' }}>
        <Icon name={totalDr === totalCr ? 'check' : 'x'} size={13} />
        {totalDr === totalCr ? 'Balanced' : 'Out of balance'}
      </div>
    </div>
  );
}

// ─── Invoices ──────────────────────────────────────────────
function InvoicesView() {
  const D = window.HitcentsData;
  const [invoices, setInvoices] = useState(D.FIN_INVOICES);
  const [open, setOpen] = useState(null);
  const [addOpen, setAddOpen] = useState(false);
  const [statusFilter, setStatusFilter] = useState('all');

  const rows = invoices.filter(i => statusFilter === 'all' || i.status === statusFilter);
  const pg = usePaged(rows, 6);
  const outstanding = invoices.filter(i => i.status === 'Sent' || i.status === 'Overdue').reduce((s, i) => s + window.invoiceTotal(i), 0);
  const overdue = invoices.filter(i => i.status === 'Overdue').reduce((s, i) => s + window.invoiceTotal(i), 0);

  return (
    <>
      <div className="grid g-4" style={{ marginBottom: 18, gap: 12 }}>
        <Kpi label="Outstanding" value={fmtMoney(outstanding)} delta={`${invoices.filter(i => i.status === 'Sent' || i.status === 'Overdue').length} open invoices`} />
        <Kpi label="Overdue" value={fmtMoney(overdue)} delta={`${invoices.filter(i => i.status === 'Overdue').length} past due`} tone={overdue > 0 ? 'down' : 'up'} />
        <Kpi label="Paid (30d)" value={fmtMoney(invoices.filter(i => i.status === 'Paid').reduce((s, i) => s + window.invoiceTotal(i), 0))} delta="collected" tone="up" />
        <Kpi label="Drafts" value={invoices.filter(i => i.status === 'Draft').length} delta="not yet sent" />
      </div>

      <div className="toolbar">
        <select value={statusFilter} onChange={e => setStatusFilter(e.target.value)}
                style={{ padding: '7px 10px', border: '1px solid var(--border)', borderRadius: 8, background: 'var(--bg-card)', fontSize: 13 }}>
          {['all', 'Draft', 'Sent', 'Overdue', 'Paid'].map(s => <option key={s} value={s}>{s === 'all' ? 'All statuses' : s}</option>)}
        </select>
        <div style={{ marginLeft: 'auto' }}>
          <Button variant="primary" icon="plus" onClick={() => setAddOpen(true)}>New invoice</Button>
        </div>
      </div>

      <div className="card flush">
        <table className="table">
          <thead><tr><th>Invoice</th><th>Customer</th><th>Issued</th><th>Due</th><th>Amount</th><th>Status</th></tr></thead>
          <tbody>
            {pg.slice.map(inv => {
              const c = getCustomer(inv.customer);
              const tone = inv.status === 'Paid' ? 'green' : inv.status === 'Overdue' ? 'red' : inv.status === 'Sent' ? 'blue' : 'neutral';
              return (
                <tr key={inv.id} className="clickable" onClick={() => setOpen(inv)}>
                  <td className="mono" style={{ fontSize: 12, fontWeight: 500 }}>{inv.id}</td>
                  <td>
                    <div className="row gap-2"><div className="company-mark sm">{c?.name[0]}</div>{c?.name}</div>
                  </td>
                  <td className="muted mono" style={{ fontSize: 11.5 }}>{fmtDateShort(inv.issued)}</td>
                  <td className="muted mono" style={{ fontSize: 11.5 }}>{fmtDateShort(inv.due)}</td>
                  <td className="mono" style={{ fontWeight: 500 }}>{fmtMoneyFull(window.invoiceTotal(inv))}</td>
                  <td><Badge tone={tone}>{inv.status}</Badge></td>
                </tr>
              );
            })}
          </tbody>
        </table>
        <div style={{ padding: '0 14px 8px' }}><Pagination pg={pg} /></div>
      </div>

      <Drawer open={!!open} onClose={() => setOpen(null)} title="Invoice" width={580}>
        {open && <InvoiceDetail invoice={open} onStatus={(status) => { open.status = status; setInvoices([...invoices]); setOpen({ ...open, status }); }} />}
      </Drawer>
      {addOpen && <InvoiceModal onClose={() => setAddOpen(false)} onCreate={(inv) => { D.FIN_INVOICES.unshift(inv); setInvoices([inv, ...invoices]); setAddOpen(false); setOpen(inv); }} />}
    </>
  );
}

function InvoiceDetail({ invoice: inv, onStatus }) {
  const c = getCustomer(inv.customer);
  const total = window.invoiceTotal(inv);
  return (
    <div>
      <div className="row spread" style={{ marginBottom: 16 }}>
        <div>
          <h2 style={{ margin: 0, fontSize: 19, fontWeight: 600 }}>{inv.id}</h2>
          <div className="muted" style={{ fontSize: 13 }}>{c?.name} · {c?.hq}</div>
        </div>
        <Badge tone={inv.status === 'Paid' ? 'green' : inv.status === 'Overdue' ? 'red' : inv.status === 'Sent' ? 'blue' : 'neutral'}>{inv.status}</Badge>
      </div>

      <div className="grid g-2" style={{ gap: 10, marginBottom: 16 }}>
        <InfoRow icon="cal" label="Issued" value={fmtDate(inv.issued)} />
        <InfoRow icon="clock" label="Due" value={fmtDate(inv.due)} />
      </div>

      <div className="card flush">
        <table className="table">
          <thead><tr><th>Description</th><th>Account</th><th style={{ textAlign: 'right' }}>Qty</th><th style={{ textAlign: 'right' }}>Price</th><th style={{ textAlign: 'right' }}>Amount</th></tr></thead>
          <tbody>
            {inv.lines.map((l, i) => {
              const acct = l.code ? window.finAccount(l.code) : null;
              return (
                <tr key={i}>
                  <td>{l.desc}</td>
                  <td className="muted" style={{ fontSize: 12 }}>{acct ? <span className="mono" style={{ fontSize: 11.5 }}>{acct.code}</span> : '—'}{acct ? ` · ${acct.name}` : ''}</td>
                  <td className="mono" style={{ textAlign: 'right' }}>{l.qty}</td>
                  <td className="mono" style={{ textAlign: 'right' }}>{fmtMoneyFull(l.price)}</td>
                  <td className="mono" style={{ textAlign: 'right' }}>{fmtMoneyFull(l.qty * l.price)}</td>
                </tr>
              );
            })}
            <tr style={{ borderTop: '2px solid var(--border-strong)' }}>
              <td colSpan={4} style={{ fontWeight: 600, textAlign: 'right' }}>Total due</td>
              <td className="mono" style={{ textAlign: 'right', fontWeight: 700, fontSize: 15 }}>{fmtMoneyFull(total)}</td>
            </tr>
          </tbody>
        </table>
      </div>

      {inv.notes && <p className="muted" style={{ fontSize: 12.5, marginTop: 12 }}>{inv.notes}</p>}

      <div className="row gap-2" style={{ marginTop: 16, paddingTop: 14, borderTop: '1px solid var(--border)' }}>
        {inv.status === 'Draft' && <Button variant="primary" icon="send" onClick={() => onStatus('Sent')}>Send invoice</Button>}
        {(inv.status === 'Sent' || inv.status === 'Overdue') && <Button variant="primary" icon="check" onClick={() => onStatus('Paid')}>Mark paid</Button>}
        <Button variant="secondary" icon="download">Download PDF</Button>
      </div>
    </div>
  );
}

// ─── P&L ───────────────────────────────────────────────────
function PnLView({ period }) {
  const p = window.HitcentsData.FIN_PNL;
  const revenue = p.revenue.map(r => ({ ...r, amount: finScale(r.amount, r.name, period) }));
  const cogs = p.cogs.map(r => ({ ...r, amount: finScale(r.amount, r.name, period) }));
  const opex = p.opex.map(r => ({ ...r, amount: finScale(r.amount, r.name, period) }));
  const totalRev = revenue.reduce((s, r) => s + r.amount, 0);
  const totalCogs = cogs.reduce((s, r) => s + r.amount, 0);
  const grossProfit = totalRev - totalCogs;
  const totalOpex = opex.reduce((s, r) => s + r.amount, 0);
  const netIncome = grossProfit - totalOpex;

  return (
    <div className="card" style={{ maxWidth: 720, padding: 0 }}>
      <div className="fin-stmt-head">
        <div>
          <h3 style={{ margin: 0 }}>Profit &amp; Loss</h3>
          <div className="sub">{period.flow} · accrual basis</div>
        </div>
        <Button size="sm" variant="ghost" icon="download">Export</Button>
      </div>
      <div className="fin-stmt">
        <FinGroup label="Revenue" rows={revenue} total={totalRev} />
        <FinGroup label="Cost of revenue" rows={cogs} total={totalCogs} muted />
        <FinTotal label="Gross profit" value={grossProfit} sub={`${Math.round(grossProfit / totalRev * 100)}% margin`} />
        <FinGroup label="Operating expenses" rows={opex} total={totalOpex} muted />
        <FinTotal label="Net income" value={netIncome} strong positive={netIncome >= 0} />
      </div>
    </div>
  );
}

function FinGroup({ label, rows, total, muted }) {
  return (
    <div className="fin-group">
      <div className="fin-group-h">{label}</div>
      {rows.map((r, i) => (
        <div key={i} className="fin-row">
          <span className={muted ? 'muted' : ''}>{r.name}</span>
          <span className="mono">{fmtMoneyFull(r.amount)}</span>
        </div>
      ))}
      <div className="fin-row fin-subtotal">
        <span>Total {label.toLowerCase()}</span>
        <span className="mono">{fmtMoneyFull(total)}</span>
      </div>
    </div>
  );
}

function FinTotal({ label, value, sub, strong, positive = true }) {
  return (
    <div className={`fin-total ${strong ? 'strong' : ''}`}>
      <div>
        <span>{label}</span>
        {sub && <span className="dim" style={{ fontSize: 11.5, marginLeft: 8 }}>{sub}</span>}
      </div>
      <span className="mono" style={{ color: strong ? (positive ? 'var(--green)' : 'var(--red)') : 'var(--text)' }}>
        {value < 0 ? `(${fmtMoneyFull(Math.abs(value))})` : fmtMoneyFull(value)}
      </span>
    </div>
  );
}

// ─── Balance sheet ─────────────────────────────────────────
function BalanceSheetView({ period }) {
  const b = window.HitcentsData.FIN_BALANCE;
  // Balance sheet grows toward the "as of" date; use a stock factor (~half the flow factor, floored).
  const sf = { k: period.k, factor: Math.max(0.78, Math.min(1.25, 0.86 + period.factor * 0.035)) };
  const assets = b.assets.map(r => ({ ...r, amount: finScale(r.amount, r.name, sf) }));
  const liabilities = b.liabilities.map(r => ({ ...r, amount: finScale(r.amount, r.name, sf) }));
  const totalAssets = assets.reduce((s, r) => s + r.amount, 0);
  const totalLiab = liabilities.reduce((s, r) => s + r.amount, 0);
  // Common stock is fixed; retained earnings plugs to keep the sheet balanced.
  const commonStock = b.equity.find(e => /common/i.test(e.name))?.amount || 500000;
  const retained = totalAssets - totalLiab - commonStock;
  const equity = [{ name: 'Common stock', amount: commonStock }, { name: 'Retained earnings', amount: retained }];
  const totalEquity = commonStock + retained;
  const balanced = totalAssets === totalLiab + totalEquity;

  return (
    <div className="card" style={{ maxWidth: 720, padding: 0 }}>
      <div className="fin-stmt-head">
        <div>
          <h3 style={{ margin: 0 }}>Balance Sheet</h3>
          <div className="sub">As of {fmtDate(period.asOf)}</div>
        </div>
        <Button size="sm" variant="ghost" icon="download">Export</Button>
      </div>
      <div className="fin-stmt">
        <FinGroup label="Assets" rows={assets} total={totalAssets} />
        <FinGroup label="Liabilities" rows={liabilities} total={totalLiab} muted />
        <FinGroup label="Equity" rows={equity} total={totalEquity} muted />
        <FinTotal label="Total liabilities + equity" value={totalLiab + totalEquity} strong />
        <div className="row gap-2" style={{ padding: '10px 18px', fontSize: 12, color: balanced ? 'var(--green)' : 'var(--red)' }}>
          <Icon name={balanced ? 'check' : 'x'} size={13} /> {balanced ? 'Assets = Liabilities + Equity' : 'Out of balance'}
        </div>
      </div>
    </div>
  );
}

// ─── A/R Aging ─────────────────────────────────────────────
function AgingView({ asOf }) {
  const D = window.HitcentsData;
  const ref = asOf ? new Date(asOf) : FIN_TODAY;
  const open = D.FIN_INVOICES.filter(i => i.status === 'Sent' || i.status === 'Overdue');

  function daysPastDue(due) {
    return Math.floor((ref - new Date(due)) / 86400000);
  }
  const buckets = ['Current', '1–30', '31–60', '61–90', '90+'];
  function bucketOf(due) {
    const d = daysPastDue(due);
    if (d <= 0) return 'Current';
    if (d <= 30) return '1–30';
    if (d <= 60) return '31–60';
    if (d <= 90) return '61–90';
    return '90+';
  }

  // group by customer
  const byCust = {};
  open.forEach(inv => {
    const cid = inv.customer;
    byCust[cid] = byCust[cid] || { Current: 0, '1–30': 0, '31–60': 0, '61–90': 0, '90+': 0, total: 0 };
    const amt = window.invoiceTotal(inv);
    byCust[cid][bucketOf(inv.due)] += amt;
    byCust[cid].total += amt;
  });
  const totals = buckets.reduce((acc, b) => { acc[b] = Object.values(byCust).reduce((s, c) => s + c[b], 0); return acc; }, {});
  const grand = Object.values(byCust).reduce((s, c) => s + c.total, 0);

  return (
    <>
      <div className="grid g-4" style={{ marginBottom: 18, gap: 12 }}>
        {buckets.map(b => (
          <Kpi key={b} label={b === 'Current' ? 'Current' : `${b} days`} value={fmtMoney(totals[b])}
               delta={`${Math.round((totals[b] / grand) * 100) || 0}% of A/R`} tone={b === '90+' && totals[b] > 0 ? 'down' : undefined} />
        )).slice(0, 4)}
      </div>

      <div className="card flush">
        <table className="table">
          <thead>
            <tr>
              <th>Customer</th>
              {buckets.map(b => <th key={b} style={{ textAlign: 'right' }}>{b === 'Current' ? 'Current' : b}</th>)}
              <th style={{ textAlign: 'right' }}>Total</th>
            </tr>
          </thead>
          <tbody>
            {Object.entries(byCust).sort((a, b) => b[1].total - a[1].total).map(([cid, row]) => {
              const c = getCustomer(cid);
              return (
                <tr key={cid}>
                  <td><div className="row gap-2"><div className="company-mark sm">{c?.name[0]}</div>{c?.name}</div></td>
                  {buckets.map(b => (
                    <td key={b} className="mono" style={{ textAlign: 'right', color: b === '90+' && row[b] > 0 ? 'var(--red)' : b === '61–90' && row[b] > 0 ? 'var(--amber)' : 'var(--text)' }}>
                      {row[b] ? fmtMoneyFull(row[b]) : <span className="dim">—</span>}
                    </td>
                  ))}
                  <td className="mono" style={{ textAlign: 'right', fontWeight: 600 }}>{fmtMoneyFull(row.total)}</td>
                </tr>
              );
            })}
            <tr style={{ borderTop: '2px solid var(--border-strong)' }}>
              <td style={{ fontWeight: 600 }}>Total</td>
              {buckets.map(b => <td key={b} className="mono" style={{ textAlign: 'right', fontWeight: 600 }}>{fmtMoneyFull(totals[b])}</td>)}
              <td className="mono" style={{ textAlign: 'right', fontWeight: 700 }}>{fmtMoneyFull(grand)}</td>
            </tr>
          </tbody>
        </table>
      </div>
    </>
  );
}

function JournalEntryModal({ onClose, onCreate }) {
  const D = window.HitcentsData;
  const [date, setDate] = useState('2026-05-15');
  const [ref, setRef] = useState('');
  const [memo, setMemo] = useState('');
  const [lines, setLines] = useState([
    { code: '1000', debit: 0, credit: 0 },
    { code: '4000', debit: 0, credit: 0 },
  ]);

  function setLine(i, patch) { setLines(ls => ls.map((l, idx) => idx === i ? { ...l, ...patch } : l)); }
  function addLine() { setLines(ls => [...ls, { code: '1000', debit: 0, credit: 0 }]); }
  function removeLine(i) { setLines(ls => ls.length > 2 ? ls.filter((_, idx) => idx !== i) : ls); }

  const totalDr = lines.reduce((s, l) => s + (+l.debit || 0), 0);
  const totalCr = lines.reduce((s, l) => s + (+l.credit || 0), 0);
  const balanced = totalDr === totalCr && totalDr > 0;

  function submit(posted) {
    if (!balanced) return;
    const id = `JE-${1043 + Math.floor(Math.random() * 900)}`;
    onCreate({ id, date, ref: ref.trim() || 'Manual', memo: memo.trim() || 'Manual journal entry', posted, lines: lines.map(l => ({ code: l.code, debit: +l.debit || 0, credit: +l.credit || 0 })) });
  }

  return (
    <div className="cmdk-scrim" onClick={onClose} style={{ paddingTop: '6vh', alignItems: 'flex-start' }}>
      <div onClick={e => e.stopPropagation()} style={{ width: 720, maxWidth: '94vw', maxHeight: '88vh', background: 'var(--bg-card)', borderRadius: 14, border: '1px solid var(--border)', boxShadow: 'var(--shadow-lg)', overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
        <div style={{ padding: '16px 24px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div>
            <h2 style={{ margin: 0, fontSize: 18, fontWeight: 600 }}>New journal entry</h2>
            <div className="muted" style={{ fontSize: 12.5, marginTop: 2 }}>Debits must equal credits before posting.</div>
          </div>
          <button className="icon-btn" onClick={onClose}><Icon name="x" size={16} /></button>
        </div>

        <div style={{ padding: 24, overflowY: 'auto', flex: 1 }}>
          <div className="add-emp-row2" style={{ gridTemplateColumns: '160px 1fr' }}>
            <div className="field" style={{ margin: 0 }}>
              <label>Date</label>
              <input type="date" value={date} onChange={e => setDate(e.target.value)} />
            </div>
            <div className="field" style={{ margin: 0 }}>
              <label>Reference</label>
              <input placeholder="e.g. Payroll, INV-2050" value={ref} onChange={e => setRef(e.target.value)} />
            </div>
          </div>
          <div className="field" style={{ margin: 0, marginTop: 14 }}>
            <label>Memo</label>
            <input placeholder="What is this entry for?" value={memo} onChange={e => setMemo(e.target.value)} />
          </div>

          <div className="add-emp-sech">Lines</div>
          <div className="je-line je-line-head">
            <span>Account</span><span style={{ textAlign: 'right' }}>Debit</span><span style={{ textAlign: 'right' }}>Credit</span><span></span>
          </div>
          {lines.map((l, i) => (
            <div key={i} className="je-line">
              <select value={l.code} onChange={e => setLine(i, { code: e.target.value })}>
                {D.FIN_ACCOUNTS.map(a => <option key={a.code} value={a.code}>{a.code} · {a.name}</option>)}
              </select>
              <input type="number" min="0" className="mono je-amt" value={l.debit || ''} placeholder="0"
                     onChange={e => setLine(i, { debit: +e.target.value, credit: 0 })} />
              <input type="number" min="0" className="mono je-amt" value={l.credit || ''} placeholder="0"
                     onChange={e => setLine(i, { credit: +e.target.value, debit: 0 })} />
              <button className="icon-btn" onClick={() => removeLine(i)} disabled={lines.length <= 2}><Icon name="trash" size={13} /></button>
            </div>
          ))}
          <button className="je-addline" onClick={addLine}><Icon name="plus" size={12} /> Add line</button>

          <div className="je-balance">
            <div className="row gap-3">
              <span className="muted" style={{ fontSize: 12 }}>Debits <strong className="mono" style={{ color: 'var(--text)' }}>{fmtMoneyFull(totalDr)}</strong></span>
              <span className="muted" style={{ fontSize: 12 }}>Credits <strong className="mono" style={{ color: 'var(--text)' }}>{fmtMoneyFull(totalCr)}</strong></span>
            </div>
            <span className="row gap-2" style={{ fontSize: 12, fontWeight: 600, color: balanced ? 'var(--green)' : 'var(--red)' }}>
              <Icon name={balanced ? 'check' : 'x'} size={13} />{balanced ? 'Balanced' : `Off by ${fmtMoneyFull(Math.abs(totalDr - totalCr))}`}
            </span>
          </div>
        </div>

        <div style={{ padding: '14px 24px', borderTop: '1px solid var(--border)', display: 'flex', justifyContent: 'flex-end', gap: 8, background: 'var(--bg-elev)' }}>
          <Button variant="ghost" onClick={onClose}>Cancel</Button>
          <Button variant="secondary" disabled={!balanced} onClick={() => submit(false)}>Save draft</Button>
          <Button variant="primary" icon="check" disabled={!balanced} onClick={() => submit(true)}>Post entry</Button>
        </div>
      </div>
    </div>
  );
}

function InvoiceModal({ onClose, onCreate }) {
  const D = window.HitcentsData;
  const [customer, setCustomer] = useState('c1');
  const [issued, setIssued] = useState('2026-05-15');
  const [due, setDue] = useState('2026-06-14');
  const [notes, setNotes] = useState('Net 30');
  const [lines, setLines] = useState([{ desc: '', qty: 1, price: 0, code: '4000' }]);

  function setLine(i, patch) { setLines(ls => ls.map((l, idx) => idx === i ? { ...l, ...patch } : l)); }
  function addLine() { setLines(ls => [...ls, { desc: '', qty: 1, price: 0, code: '4000' }]); }
  function removeLine(i) { setLines(ls => ls.length > 1 ? ls.filter((_, idx) => idx !== i) : ls); }

  const total = lines.reduce((s, l) => s + (+l.qty || 0) * (+l.price || 0), 0);
  const canCreate = total > 0 && lines.some(l => l.desc.trim());

  function submit(status) {
    const id = `INV-${2049 + Math.floor(Math.random() * 900)}`;
    onCreate({ id, customer, issued, due, status, notes: notes.trim(), lines: lines.filter(l => l.desc.trim()).map(l => ({ desc: l.desc.trim(), qty: +l.qty || 1, price: +l.price || 0, code: l.code })) });
  }

  const c = getCustomer(customer);
  const revenueAccounts = D.FIN_ACCOUNTS.filter(a => a.type === 'Revenue' || a.type === 'Asset');

  return (
    <div className="cmdk-scrim" onClick={onClose} style={{ paddingTop: '6vh', alignItems: 'flex-start' }}>
      <div onClick={e => e.stopPropagation()} style={{ width: 720, maxWidth: '94vw', maxHeight: '88vh', background: 'var(--bg-card)', borderRadius: 14, border: '1px solid var(--border)', boxShadow: 'var(--shadow-lg)', overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
        <div style={{ padding: '16px 24px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div>
            <h2 style={{ margin: 0, fontSize: 18, fontWeight: 600 }}>New invoice</h2>
            <div className="muted" style={{ fontSize: 12.5, marginTop: 2 }}>Bill a customer for products or services.</div>
          </div>
          <button className="icon-btn" onClick={onClose}><Icon name="x" size={16} /></button>
        </div>

        <div style={{ padding: 24, overflowY: 'auto', flex: 1 }}>
          <div className="add-emp-row2">
            <div className="field" style={{ margin: 0 }}>
              <label>Customer</label>
              <select value={customer} onChange={e => setCustomer(e.target.value)}>
                {D.CUSTOMERS.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
              </select>
            </div>
            <div className="field" style={{ margin: 0 }}>
              <label>Terms / notes</label>
              <input value={notes} onChange={e => setNotes(e.target.value)} placeholder="Net 30" />
            </div>
          </div>
          <div className="add-emp-row2" style={{ marginTop: 14 }}>
            <div className="field" style={{ margin: 0 }}>
              <label>Issue date</label>
              <input type="date" value={issued} onChange={e => setIssued(e.target.value)} />
            </div>
            <div className="field" style={{ margin: 0 }}>
              <label>Due date</label>
              <input type="date" value={due} onChange={e => setDue(e.target.value)} />
            </div>
          </div>

          <div className="add-emp-sech">Line items</div>
          <div className="inv-line inv-line-head">
            <span>Description</span><span>Income account</span><span style={{ textAlign: 'right' }}>Qty</span><span style={{ textAlign: 'right' }}>Price</span><span style={{ textAlign: 'right' }}>Amount</span><span></span>
          </div>
          {lines.map((l, i) => (
            <div key={i} className="inv-line">
              <input placeholder="e.g. SaaS platform — May" value={l.desc} onChange={e => setLine(i, { desc: e.target.value })} />
              <select value={l.code} onChange={e => setLine(i, { code: e.target.value })} title="Chart of accounts">
                {revenueAccounts.map(a => <option key={a.code} value={a.code}>{a.code} · {a.name}</option>)}
              </select>
              <input type="number" min="1" className="mono je-amt" value={l.qty} onChange={e => setLine(i, { qty: +e.target.value })} />
              <input type="number" min="0" className="mono je-amt" value={l.price || ''} placeholder="0" onChange={e => setLine(i, { price: +e.target.value })} />
              <span className="mono" style={{ textAlign: 'right', fontSize: 12.5, alignSelf: 'center' }}>{fmtMoneyFull((+l.qty || 0) * (+l.price || 0))}</span>
              <button className="icon-btn" onClick={() => removeLine(i)} disabled={lines.length <= 1}><Icon name="trash" size={13} /></button>
            </div>
          ))}
          <button className="je-addline" onClick={addLine}><Icon name="plus" size={12} /> Add line</button>

          <div className="je-balance">
            <span className="muted" style={{ fontSize: 12 }}>{c?.name}</span>
            <span style={{ fontSize: 14, fontWeight: 600 }}>Total <span className="mono">{fmtMoneyFull(total)}</span></span>
          </div>
        </div>

        <div style={{ padding: '14px 24px', borderTop: '1px solid var(--border)', display: 'flex', justifyContent: 'flex-end', gap: 8, background: 'var(--bg-elev)' }}>
          <Button variant="ghost" onClick={onClose}>Cancel</Button>
          <Button variant="secondary" disabled={!canCreate} onClick={() => submit('Draft')}>Save draft</Button>
          <Button variant="primary" icon="send" disabled={!canCreate} onClick={() => submit('Sent')}>Create &amp; send</Button>
        </div>
      </div>
    </div>
  );
}

// ─── Bills (A/P) ───────────────────────────────────────────
function BillsView() {
  const D = window.HitcentsData;
  const [bills, setBills] = useState(D.FIN_BILLS);
  const [open, setOpen] = useState(null);
  const [addOpen, setAddOpen] = useState(false);
  const [statusFilter, setStatusFilter] = useState('all');

  const rows = bills.filter(b => statusFilter === 'all' || b.status === statusFilter);
  const pg = usePaged(rows, 6);
  const outstanding = bills.filter(b => b.status === 'Open' || b.status === 'Overdue').reduce((s, b) => s + b.amount, 0);
  const overdue = bills.filter(b => b.status === 'Overdue').reduce((s, b) => s + b.amount, 0);

  return (
    <>
      <div className="grid g-4" style={{ marginBottom: 18, gap: 12 }}>
        <Kpi label="Total payable" value={fmtMoney(outstanding)} delta={`${bills.filter(b => b.status === 'Open' || b.status === 'Overdue').length} open bills`} />
        <Kpi label="Overdue" value={fmtMoney(overdue)} delta={`${bills.filter(b => b.status === 'Overdue').length} past due`} tone={overdue > 0 ? 'down' : 'up'} />
        <Kpi label="Paid (30d)" value={fmtMoney(bills.filter(b => b.status === 'Paid').reduce((s, b) => s + b.amount, 0))} delta="settled" tone="up" />
        <Kpi label="Due this week" value={fmtMoney(bills.filter(b => { const d = (new Date(b.due) - FIN_TODAY) / 86400000; return (b.status === 'Open') && d >= 0 && d <= 7; }).reduce((s, b) => s + b.amount, 0))} delta="upcoming" />
      </div>

      <div className="toolbar">
        <select value={statusFilter} onChange={e => setStatusFilter(e.target.value)}
                style={{ padding: '7px 10px', border: '1px solid var(--border)', borderRadius: 8, background: 'var(--bg-card)', fontSize: 13 }}>
          {['all', 'Open', 'Overdue', 'Paid'].map(s => <option key={s} value={s}>{s === 'all' ? 'All statuses' : s}</option>)}
        </select>
        <div style={{ marginLeft: 'auto' }}>
          <Button variant="primary" icon="plus" onClick={() => setAddOpen(true)}>New bill</Button>
        </div>
      </div>

      <div className="card flush">
        <table className="table">
          <thead><tr><th>Bill</th><th>Vendor</th><th>Category</th><th>Issued</th><th>Due</th><th>Amount</th><th>Status</th></tr></thead>
          <tbody>
            {pg.slice.map(b => {
              const tone = b.status === 'Paid' ? 'green' : b.status === 'Overdue' ? 'red' : 'blue';
              return (
                <tr key={b.id} className="clickable" onClick={() => setOpen(b)}>
                  <td className="mono" style={{ fontSize: 12, fontWeight: 500 }}>{b.id}</td>
                  <td style={{ fontWeight: 500 }}>{b.vendor}</td>
                  <td className="muted">{b.category}</td>
                  <td className="muted mono" style={{ fontSize: 11.5 }}>{fmtDateShort(b.issued)}</td>
                  <td className="muted mono" style={{ fontSize: 11.5 }}>{fmtDateShort(b.due)}</td>
                  <td className="mono" style={{ fontWeight: 500 }}>{fmtMoneyFull(b.amount)}</td>
                  <td><Badge tone={tone}>{b.status}</Badge></td>
                </tr>
              );
            })}
          </tbody>
        </table>
        <div style={{ padding: '0 14px 8px' }}><Pagination pg={pg} /></div>
      </div>

      <Drawer open={!!open} onClose={() => setOpen(null)} title="Bill" width={520}>
        {open && (
          <div>
            <div className="row spread" style={{ marginBottom: 16 }}>
              <div><h2 style={{ margin: 0, fontSize: 19, fontWeight: 600 }}>{open.vendor}</h2><div className="muted mono" style={{ fontSize: 12.5 }}>{open.id}</div></div>
              <Badge tone={open.status === 'Paid' ? 'green' : open.status === 'Overdue' ? 'red' : 'blue'}>{open.status}</Badge>
            </div>
            {open.vendorId && getVendor(open.vendorId) && (
              <button className="link-btn" style={{ marginBottom: 12 }} onClick={() => window.dispatchEvent(new CustomEvent('hitcents:navigate', { detail: { section: 'vendors', target: { type: 'vendor', id: open.vendorId } } }))}>View vendor →</button>
            )}
            <div className="grid g-2" style={{ gap: 10, marginBottom: 16 }}>
              <InfoRow icon="layers" label="Category" value={open.category} />
              <InfoRow icon="card" label="Amount" value={fmtMoneyFull(open.amount)} />
              <InfoRow icon="cal" label="Issued" value={fmtDate(open.issued)} />
              <InfoRow icon="clock" label="Due" value={fmtDate(open.due)} />
            </div>

            {open.splits && open.splits.length > 0 && (
              <>
                <SectionTitle>Account allocation</SectionTitle>
                <div className="card flush" style={{ marginBottom: 16 }}>
                  <table className="table">
                    <tbody>
                      {open.splits.map((s, i) => {
                        const a = window.finAccount(s.code);
                        return (
                          <tr key={i}>
                            <td className="mono dim" style={{ fontSize: 12 }}>{s.code}</td>
                            <td style={{ fontWeight: 500 }}>{a?.name || '—'}</td>
                            <td className="mono" style={{ textAlign: 'right' }}>{fmtMoneyFull(s.amount)}</td>
                          </tr>
                        );
                      })}
                      {open.splits.length > 1 && (
                        <tr style={{ borderTop: '2px solid var(--border-strong)' }}>
                          <td colSpan={2} style={{ fontWeight: 600, textAlign: 'right' }}>Total</td>
                          <td className="mono" style={{ textAlign: 'right', fontWeight: 700 }}>{fmtMoneyFull(open.amount)}</td>
                        </tr>
                      )}
                    </tbody>
                  </table>
                </div>
              </>
            )}

            {open.files && open.files.length > 0 && (
              <>
                <SectionTitle>Attachments</SectionTitle>
                <div className="col" style={{ gap: 6, marginBottom: 16 }}>
                  {open.files.map((f, i) => (
                    <div key={i} className="row gap-2" style={{ padding: '8px 10px', background: 'var(--bg-elev)', borderRadius: 6 }}>
                      <span className="file-glyph" style={{ background: '#C2452C', width: 24, height: 24, fontSize: 9 }}>PDF</span>
                      <span style={{ flex: 1, fontSize: 12.5, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{f.name}</span>
                      <span className="dim" style={{ fontSize: 11 }}>{fileBytes(f.size)}</span>
                    </div>
                  ))}
                </div>
              </>
            )}

            {open.status !== 'Paid' && (
              <div className="row gap-2" style={{ paddingTop: 14, borderTop: '1px solid var(--border)' }}>
                <Button variant="primary" icon="check" onClick={() => { open.status = 'Paid'; setBills([...bills]); setOpen({ ...open, status: 'Paid' }); }}>Mark paid</Button>
                <Button variant="secondary" icon="cal">Schedule payment</Button>
              </div>
            )}
          </div>
        )}
      </Drawer>
      {addOpen && <BillModal onClose={() => setAddOpen(false)} onCreate={(bill) => { D.FIN_BILLS.unshift(bill); setBills([bill, ...bills]); setAddOpen(false); setOpen(bill); }} />}
    </>
  );
}

function BillModal({ onClose, onCreate }) {
  const D = window.HitcentsData;
  const expenseAccts = D.FIN_ACCOUNTS.filter(a => a.type === 'Expense');
  const vendors = D.VENDORS || [];
  const [draft, setDraft] = useState({
    vendorId: '', vendor: '', otherVendor: false,
    issued: '2026-05-15', due: '2026-06-14',
  });
  const [splits, setSplits] = useState([{ code: expenseAccts[0]?.code || '5000', amount: 0 }]);
  const [files, setFiles] = useState([]);
  const [dragOver, setDragOver] = useState(false);
  const fileRef = useRef(null);

  function set(p) { setDraft(d => ({ ...d, ...p })); }
  function setSplit(i, patch) { setSplits(s => s.map((x, idx) => idx === i ? { ...x, ...patch } : x)); }
  function addSplit() { setSplits(s => [...s, { code: expenseAccts[0]?.code || '5000', amount: 0 }]); }
  function removeSplit(i) { setSplits(s => s.length > 1 ? s.filter((_, idx) => idx !== i) : s); }
  function addFiles(list) {
    const next = Array.from(list || []).map(f => ({ name: f.name, size: f.size }));
    if (next.length) setFiles(fs => [...next, ...fs]);
  }

  const total = splits.reduce((s, x) => s + (+x.amount || 0), 0);
  const vendorName = draft.otherVendor ? draft.vendor.trim() : (getVendor(draft.vendorId)?.name || '');
  const canCreate = vendorName && total > 0;

  function submit() {
    const firstAcct = window.finAccount(splits[0].code);
    onCreate({
      id: `BILL-${7013 + Math.floor(Math.random() * 900)}`,
      vendorId: draft.otherVendor ? null : (draft.vendorId || null),
      vendor: vendorName,
      category: splits.length > 1 ? 'Split allocation' : (firstAcct?.name || '—'),
      issued: draft.issued, due: draft.due,
      amount: total, status: 'Open',
      splits: splits.filter(s => +s.amount > 0).map(s => ({ code: s.code, amount: +s.amount })),
      files,
    });
  }

  return (
    <div className="cmdk-scrim" onClick={onClose} style={{ paddingTop: '6vh', alignItems: 'flex-start' }}>
      <div onClick={e => e.stopPropagation()} style={{ width: 600, maxWidth: '94vw', maxHeight: '88vh', background: 'var(--bg-card)', borderRadius: 14, border: '1px solid var(--border)', boxShadow: 'var(--shadow-lg)', overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
        <div style={{ padding: '16px 24px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div>
            <h2 style={{ margin: 0, fontSize: 18, fontWeight: 600 }}>New bill</h2>
            <div className="muted" style={{ fontSize: 12.5, marginTop: 2 }}>Record a payable, allocate it to accounts, attach the invoice.</div>
          </div>
          <button className="icon-btn" onClick={onClose}><Icon name="x" size={16} /></button>
        </div>

        <div style={{ padding: 24, overflowY: 'auto', flex: 1 }}>
          <div className="field" style={{ margin: 0, marginBottom: 14 }}>
            <label>Vendor</label>
            {draft.otherVendor ? (
              <div className="row gap-2">
                <input autoFocus placeholder="Vendor name" value={draft.vendor} onChange={e => set({ vendor: e.target.value })} style={{ flex: 1 }} />
                <Button size="sm" variant="ghost" onClick={() => set({ otherVendor: false, vendor: '' })}>Pick from list</Button>
              </div>
            ) : (
              <select value={draft.vendorId} onChange={e => { e.target.value === '__other' ? set({ otherVendor: true, vendorId: '' }) : set({ vendorId: e.target.value }); }}>
                <option value="">— Select a vendor —</option>
                {vendors.map(v => <option key={v.id} value={v.id}>{v.name}</option>)}
                <option value="__other">+ Other vendor…</option>
              </select>
            )}
          </div>

          <div className="add-emp-row2" style={{ marginBottom: 14 }}>
            <div className="field" style={{ margin: 0 }}>
              <label>Issue date</label>
              <input type="date" value={draft.issued} onChange={e => set({ issued: e.target.value })} />
            </div>
            <div className="field" style={{ margin: 0 }}>
              <label>Due date</label>
              <input type="date" value={draft.due} onChange={e => set({ due: e.target.value })} />
            </div>
          </div>

          <div className="add-emp-sech">Account allocation{splits.length > 1 && <span className="dim" style={{ textTransform: 'none', letterSpacing: 0, fontWeight: 400, marginLeft: 6 }}>· split across {splits.length}</span>}</div>
          {splits.map((s, i) => (
            <div key={i} className="row gap-2" style={{ marginBottom: 8 }}>
              <select value={s.code} onChange={e => setSplit(i, { code: e.target.value })}
                      style={{ flex: 1, border: '1px solid var(--border-strong)', borderRadius: 7, padding: '7px 9px', fontSize: 12.5, background: 'var(--bg-card)' }}>
                {expenseAccts.map(a => <option key={a.code} value={a.code}>{a.code} · {a.name}</option>)}
              </select>
              <div style={{ position: 'relative', width: 130 }}>
                <span style={{ position: 'absolute', left: 10, top: 8, color: 'var(--text-muted)', fontSize: 13 }}>$</span>
                <input type="number" min="0" step="100" className="mono" value={s.amount || ''} placeholder="0" onChange={e => setSplit(i, { amount: +e.target.value })}
                       style={{ width: '100%', paddingLeft: 22, border: '1px solid var(--border-strong)', borderRadius: 7, padding: '7px 9px 7px 22px', fontSize: 12.5, textAlign: 'right' }} />
              </div>
              <button className="icon-btn" onClick={() => removeSplit(i)} disabled={splits.length <= 1}><Icon name="trash" size={13} /></button>
            </div>
          ))}
          <button className="je-addline" onClick={addSplit}><Icon name="plus" size={12} /> Split across another account</button>

          <div className="je-balance" style={{ marginTop: 12 }}>
            <span className="muted" style={{ fontSize: 12 }}>{vendorName || 'Vendor'}</span>
            <span style={{ fontSize: 14, fontWeight: 600 }}>Bill total <span className="mono">{fmtMoneyFull(total)}</span></span>
          </div>

          <div className="add-emp-sech" style={{ marginTop: 18 }}>Attachment</div>
          <input ref={fileRef} type="file" accept="application/pdf,image/*" multiple style={{ display: 'none' }}
                 onChange={e => { addFiles(e.target.files); e.target.value = ''; }} />
          <div className={`nc-drop ${dragOver ? 'over' : ''}`} style={{ padding: '16px 14px' }}
               onClick={() => fileRef.current?.click()}
               onDragOver={e => { e.preventDefault(); setDragOver(true); }}
               onDragLeave={() => setDragOver(false)}
               onDrop={e => { e.preventDefault(); setDragOver(false); addFiles(e.dataTransfer.files); }}>
            <Icon name="upload" size={18} />
            <div style={{ fontSize: 12.5, fontWeight: 500, marginTop: 5 }}>Attach the bill PDF</div>
            <div className="dim" style={{ fontSize: 11 }}>Drag a file here or click to browse</div>
          </div>
          {files.length > 0 && (
            <div className="col" style={{ gap: 6, marginTop: 8 }}>
              {files.map((f, i) => (
                <div key={i} className="row gap-2" style={{ padding: '7px 10px', background: 'var(--bg-elev)', borderRadius: 6 }}>
                  <span className="file-glyph" style={{ background: '#C2452C', width: 22, height: 22, fontSize: 8 }}>PDF</span>
                  <span style={{ flex: 1, fontSize: 12.5, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{f.name}</span>
                  <span className="dim" style={{ fontSize: 11 }}>{fileBytes(f.size)}</span>
                  <button className="icon-btn" style={{ width: 22, height: 22 }} onClick={() => setFiles(fs => fs.filter((_, j) => j !== i))}><Icon name="x" size={11} /></button>
                </div>
              ))}
            </div>
          )}
        </div>

        <div style={{ padding: '14px 24px', borderTop: '1px solid var(--border)', display: 'flex', justifyContent: 'flex-end', gap: 8, background: 'var(--bg-elev)' }}>
          <Button variant="ghost" onClick={onClose}>Cancel</Button>
          <Button variant="primary" icon="check" disabled={!canCreate} onClick={submit}>Add bill</Button>
        </div>
      </div>
    </div>
  );
}

// ─── Banking ───────────────────────────────────────────────
function BankingView() {
  const D = window.HitcentsData;
  const [txns, setTxns] = useState(D.FIN_TRANSACTIONS);
  const [acctFilter, setAcctFilter] = useState('all');
  const [stmt, setStmt] = useState({}); // statement ending balance per account id

  function toggleRec(id) { setTxns(ts => ts.map(t => t.id === id ? { ...t, reconciled: !t.reconciled } : t)); }
  const rows = txns.filter(t => acctFilter === 'all' || t.account === acctFilter);
  const pg = usePaged(rows, 8);
  const unrec = txns.filter(t => !t.reconciled).length;

  // Reconciliation math for one account (book vs. bank, cleared vs. outstanding)
  function reconFor(acctId) {
    const acct = D.FIN_BANK_ACCOUNTS.find(a => a.id === acctId);
    const all = txns.filter(t => t.account === acctId);
    const sumAll = all.reduce((s, t) => s + t.amount, 0);
    const begin = acct.balance - sumAll;
    const clearedDep = all.filter(t => t.reconciled && t.amount > 0).reduce((s, t) => s + t.amount, 0);
    const clearedPay = all.filter(t => t.reconciled && t.amount < 0).reduce((s, t) => s + t.amount, 0);
    const clearedBalance = begin + clearedDep + clearedPay;
    const outstanding = all.filter(t => !t.reconciled);
    const outstandingTotal = outstanding.reduce((s, t) => s + t.amount, 0);
    const statement = stmt[acctId] != null ? stmt[acctId] : clearedBalance;
    return { acct, begin, clearedDep, clearedPay, clearedBalance, outstanding, outstandingTotal, statement, bookBalance: acct.balance };
  }

  const selected = acctFilter !== 'all' ? reconFor(acctFilter) : null;

  return (
    <>
      <div className="grid g-3" style={{ marginBottom: 18, gap: 12 }}>
        {D.FIN_BANK_ACCOUNTS.map(a => {
          const r = reconFor(a.id);
          const balanced = Math.abs((stmt[a.id] != null ? stmt[a.id] : r.clearedBalance) - r.clearedBalance) < 0.5;
          return (
            <div key={a.id} className="card" style={{ padding: 16, cursor: 'pointer', borderColor: acctFilter === a.id ? 'var(--brand-orange)' : 'var(--border)' }} onClick={() => setAcctFilter(acctFilter === a.id ? 'all' : a.id)}>
              <div className="row gap-2" style={{ marginBottom: 10 }}>
                <div className="lic-glyph" style={{ background: a.type === 'Credit card' ? 'var(--purple)' : 'var(--brand-wine)' }}><Icon name="card" size={15} /></div>
                <div style={{ flex: 1 }}>
                  <div style={{ fontWeight: 600, fontSize: 13.5 }}>{a.name}</div>
                  <div className="dim mono" style={{ fontSize: 11 }}>{a.bank} ··{a.last4}</div>
                </div>
                <Badge tone="neutral">{a.type}</Badge>
              </div>
              <div className="mono" style={{ fontSize: 24, fontWeight: 600, letterSpacing: '-0.02em', color: a.balance < 0 ? 'var(--red)' : 'var(--brand-wine)' }}>
                {a.balance < 0 ? `(${fmtMoneyFull(Math.abs(a.balance))})` : fmtMoneyFull(a.balance)}
              </div>
              <div className="row gap-2" style={{ marginTop: 8, fontSize: 11 }}>
                {r.outstanding.length > 0
                  ? <span className="dim">{r.outstanding.length} uncleared · {fmtMoneyFull(Math.abs(r.outstandingTotal))}</span>
                  : <span style={{ color: 'var(--green)', display: 'inline-flex', alignItems: 'center', gap: 4 }}><Icon name="check" size={11} stroke={3} /> All cleared</span>}
              </div>
            </div>
          );
        })}
      </div>

      {selected && (
        <div className="card recon-panel" style={{ marginBottom: 18 }}>
          <div className="row spread" style={{ marginBottom: 14 }}>
            <div>
              <h3 style={{ margin: 0, fontSize: 15, fontWeight: 600 }}>Reconcile · {selected.acct.name}</h3>
              <div className="dim" style={{ fontSize: 11.5 }}>Match your ledger to the bank statement</div>
            </div>
            <Button size="sm" variant="ghost" icon="x" onClick={() => setAcctFilter('all')}>Done</Button>
          </div>
          <div className="recon-grid">
            <div className="recon-col">
              <div className="recon-row"><span>Beginning balance</span><span className="mono">{fmtMoneyFull(selected.begin)}</span></div>
              <div className="recon-row"><span>+ Cleared deposits</span><span className="mono" style={{ color: 'var(--green)' }}>{fmtMoneyFull(selected.clearedDep)}</span></div>
              <div className="recon-row"><span>− Cleared payments</span><span className="mono" style={{ color: 'var(--red)' }}>{fmtMoneyFull(Math.abs(selected.clearedPay))}</span></div>
              <div className="recon-row strong"><span>Cleared balance</span><span className="mono">{fmtMoneyFull(selected.clearedBalance)}</span></div>
            </div>
            <div className="recon-col">
              <div className="recon-row">
                <span>Statement ending balance</span>
                <span style={{ position: 'relative', width: 130 }}>
                  <span style={{ position: 'absolute', left: 8, top: 7, color: 'var(--text-muted)', fontSize: 12 }}>$</span>
                  <input type="number" className="mono" value={selected.statement}
                         onChange={e => setStmt(s => ({ ...s, [acctFilter]: +e.target.value }))}
                         style={{ width: '100%', textAlign: 'right', padding: '6px 8px 6px 18px', border: '1px solid var(--border-strong)', borderRadius: 7, fontSize: 12.5 }} />
                </span>
              </div>
              <div className="recon-row"><span>Outstanding items</span><span className="mono dim">{selected.outstanding.length} · {fmtMoneyFull(Math.abs(selected.outstandingTotal))}</span></div>
              {(() => {
                const diff = selected.statement - selected.clearedBalance;
                const ok = Math.abs(diff) < 0.5;
                return (
                  <div className={`recon-diff ${ok ? 'ok' : 'off'}`}>
                    {ok
                      ? <><Icon name="check" size={14} stroke={3} /> Reconciled — difference $0</>
                      : <><Icon name="flag" size={14} /> Out of balance by {fmtMoneyFull(Math.abs(diff))}</>}
                  </div>
                );
              })()}
            </div>
          </div>
        </div>
      )}

      <div className="toolbar">
        <div className="row gap-2">
          <strong style={{ fontSize: 13 }}>Transactions</strong>
          {unrec > 0 && <Badge tone="amber">{unrec} to reconcile</Badge>}
        </div>
        <div style={{ marginLeft: 'auto' }} className="row gap-2">
          {acctFilter !== 'all' && <Button size="sm" variant="ghost" icon="x" onClick={() => setAcctFilter('all')}>Clear filter</Button>}
          <Button size="sm" variant="secondary" icon="upload">Import statement</Button>
        </div>
      </div>

      <div className="card flush">
        <table className="table">
          <thead><tr><th>Date</th><th>Description</th><th>Account</th><th>Category</th><th style={{ textAlign: 'right' }}>Amount</th><th>Reconciled</th></tr></thead>
          <tbody>
            {pg.slice.map(t => {
              const a = D.FIN_BANK_ACCOUNTS.find(x => x.id === t.account);
              return (
                <tr key={t.id}>
                  <td className="muted mono" style={{ fontSize: 11.5 }}>{fmtDateShort(t.date)}</td>
                  <td style={{ fontWeight: 500 }}>{t.desc}</td>
                  <td className="dim" style={{ fontSize: 12 }}>{a?.name}</td>
                  <td>{t.category === 'Transfer' ? <Badge tone="neutral">Transfer</Badge> : <span className="muted" style={{ fontSize: 12.5 }}>{t.category}</span>}</td>
                  <td className="mono" style={{ textAlign: 'right', fontWeight: 500, color: t.amount < 0 ? 'var(--red)' : 'var(--green)' }}>{t.amount < 0 ? '−' : '+'}{fmtMoneyFull(Math.abs(t.amount))}</td>
                  <td>
                    <button className={`recon-toggle ${t.reconciled ? 'on' : ''}`} onClick={() => toggleRec(t.id)}>
                      <Icon name={t.reconciled ? 'check' : 'clock'} size={11} stroke={t.reconciled ? 3 : 1.7} />
                      {t.reconciled ? 'Reconciled' : 'Pending'}
                    </button>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
        <div style={{ padding: '0 14px 8px' }}><Pagination pg={pg} /></div>
      </div>
    </>
  );
}

// ─── Chart of accounts (editable) ──────────────────────────
function ChartOfAccountsView() {
  const D = window.HitcentsData;
  const types = ['Asset', 'Liability', 'Equity', 'Revenue', 'Expense'];
  const [, bump] = useState(0);
  const [modal, setModal] = useState(null); // { mode:'add'|'edit', account }
  const rerender = () => bump(n => n + 1);

  function saveAccount(orig, draft) {
    if (orig) {
      orig.name = draft.name; orig.type = draft.type; orig.code = draft.code;
    } else {
      D.FIN_ACCOUNTS.push({ code: draft.code, name: draft.name, type: draft.type });
      D.FIN_ACCOUNTS.sort((a, b) => a.code.localeCompare(b.code));
    }
    rerender();
  }
  function removeAccount(acct) {
    if (!confirm(`Delete account ${acct.code} · ${acct.name}?`)) return;
    const i = D.FIN_ACCOUNTS.indexOf(acct);
    if (i >= 0) D.FIN_ACCOUNTS.splice(i, 1);
    rerender();
  }

  return (
    <>
      <div className="toolbar">
        <div className="muted" style={{ fontSize: 12.5 }}>{D.FIN_ACCOUNTS.length} accounts</div>
        <div style={{ marginLeft: 'auto' }}>
          <Button variant="primary" size="sm" icon="plus" onClick={() => setModal({ mode: 'add', account: null })}>Add account</Button>
        </div>
      </div>

      <div className="card flush">
        <table className="table">
          <thead><tr><th>Code</th><th>Account</th><th>Type</th><th style={{ textAlign: 'right' }}>Balance</th><th style={{ width: 80 }}></th></tr></thead>
          <tbody>
            {types.map(type => {
              const accts = D.FIN_ACCOUNTS.filter(a => a.type === type);
              return (
                <React.Fragment key={type}>
                  <tr style={{ background: 'var(--bg-elev)' }}>
                    <td colSpan={5} style={{ fontWeight: 600, fontSize: 11.5, textTransform: 'uppercase', letterSpacing: '0.05em', color: 'var(--text-muted)' }}>{type}</td>
                  </tr>
                  {accts.map(a => (
                    <tr key={a.code} className="coa-row">
                      <td className="mono dim" style={{ fontSize: 12 }}>{a.code}</td>
                      <td style={{ fontWeight: 500 }}>{a.name}</td>
                      <td><Badge tone={a.type === 'Asset' ? 'blue' : a.type === 'Liability' ? 'amber' : a.type === 'Equity' ? 'purple' : a.type === 'Revenue' ? 'green' : 'neutral'}>{a.type}</Badge></td>
                      <td className="mono" style={{ textAlign: 'right' }}>{fmtMoneyFull(D.FIN_BALANCES[a.code] || 0)}</td>
                      <td>
                        <div className="row gap-1 coa-actions">
                          <button className="icon-btn" title="Edit account" onClick={() => setModal({ mode: 'edit', account: a })}><Icon name="pencil" size={13} /></button>
                          <button className="icon-btn" title="Delete account" onClick={() => removeAccount(a)}><Icon name="trash" size={13} /></button>
                        </div>
                      </td>
                    </tr>
                  ))}
                </React.Fragment>
              );
            })}
          </tbody>
        </table>
      </div>

      {modal && <AccountModal mode={modal.mode} account={modal.account} types={types}
                              onClose={() => setModal(null)}
                              onSave={(draft) => { saveAccount(modal.account, draft); setModal(null); }} />}
    </>
  );
}

function AccountModal({ mode, account, types, onClose, onSave }) {
  const D = window.HitcentsData;
  const [draft, setDraft] = useState(account
    ? { code: account.code, name: account.name, type: account.type }
    : { code: '', name: '', type: 'Expense' });
  function set(p) { setDraft(d => ({ ...d, ...p })); }
  const codeTaken = D.FIN_ACCOUNTS.some(a => a.code === draft.code && a !== account);
  const canSave = draft.code.trim() && draft.name.trim() && !codeTaken;

  // Suggest the next available code in the chosen type's band
  function suggestCode(type) {
    const band = { Asset: '1', Liability: '2', Equity: '3', Revenue: '4', Expense: '6' }[type] || '9';
    const inBand = D.FIN_ACCOUNTS.filter(a => a.code.startsWith(band)).map(a => +a.code).sort((x, y) => x - y);
    const next = (inBand.length ? inBand[inBand.length - 1] + 10 : +(band + '000'));
    return String(next);
  }

  return (
    <div className="cmdk-scrim" onClick={onClose} style={{ paddingTop: '10vh', alignItems: 'flex-start' }}>
      <div onClick={e => e.stopPropagation()} style={{ width: 460, maxWidth: '94vw', background: 'var(--bg-card)', borderRadius: 14, border: '1px solid var(--border)', boxShadow: 'var(--shadow-lg)', overflow: 'hidden' }}>
        <div style={{ padding: '16px 24px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <h2 style={{ margin: 0, fontSize: 18, fontWeight: 600 }}>{mode === 'edit' ? 'Edit account' : 'New account'}</h2>
          <button className="icon-btn" onClick={onClose}><Icon name="x" size={16} /></button>
        </div>
        <div style={{ padding: 24 }}>
          <div className="field" style={{ margin: 0, marginBottom: 14 }}>
            <label>Account type</label>
            <select value={draft.type} onChange={e => { const type = e.target.value; set({ type, code: draft.code || suggestCode(type) }); }}>
              {types.map(t => <option key={t} value={t}>{t}</option>)}
            </select>
          </div>
          <div className="add-emp-row2">
            <div className="field" style={{ margin: 0 }}>
              <label>Code</label>
              <input className="mono" placeholder={suggestCode(draft.type)} value={draft.code} onChange={e => set({ code: e.target.value })} />
              {codeTaken && <div style={{ color: 'var(--red)', fontSize: 11, marginTop: 4 }}>Code already in use</div>}
            </div>
            <div className="field" style={{ margin: 0 }}>
              <label>Account name</label>
              <input autoFocus placeholder="e.g. Travel & entertainment" value={draft.name} onChange={e => set({ name: e.target.value })} />
            </div>
          </div>
        </div>
        <div style={{ padding: '14px 24px', borderTop: '1px solid var(--border)', display: 'flex', justifyContent: 'flex-end', gap: 8, background: 'var(--bg-elev)' }}>
          <Button variant="ghost" onClick={onClose}>Cancel</Button>
          <Button variant="primary" icon="check" disabled={!canSave} onClick={() => onSave({ code: draft.code.trim(), name: draft.name.trim(), type: draft.type })}>{mode === 'edit' ? 'Save changes' : 'Add account'}</Button>
        </div>
      </div>
    </div>
  );
}

// ─── Trial balance ─────────────────────────────────────────
function TrialBalanceView() {
  const D = window.HitcentsData;
  const debitTypes = ['Asset', 'Expense'];
  const rows = D.FIN_ACCOUNTS.map(a => {
    const bal = D.FIN_BALANCES[a.code] || 0;
    const isDebit = debitTypes.includes(a.type);
    return { ...a, debit: isDebit ? bal : 0, credit: isDebit ? 0 : bal };
  });
  const totalDr = rows.reduce((s, r) => s + r.debit, 0);
  const totalCr = rows.reduce((s, r) => s + r.credit, 0);
  const balanced = totalDr === totalCr;
  return (
    <div className="card flush">
      <div className="fin-stmt-head" style={{ borderBottom: '1px solid var(--border)' }}>
        <div><h3 style={{ margin: 0 }}>Trial balance</h3><div className="sub">As of {fmtDate('2026-05-31')}</div></div>
        <Badge tone={balanced ? 'green' : 'red'}>{balanced ? 'In balance' : 'Out of balance'}</Badge>
      </div>
      <table className="table">
        <thead><tr><th>Code</th><th>Account</th><th style={{ textAlign: 'right' }}>Debit</th><th style={{ textAlign: 'right' }}>Credit</th></tr></thead>
        <tbody>
          {rows.map(r => (
            <tr key={r.code}>
              <td className="mono dim" style={{ fontSize: 12 }}>{r.code}</td>
              <td>{r.name}</td>
              <td className="mono" style={{ textAlign: 'right' }}>{r.debit ? fmtMoneyFull(r.debit) : ''}</td>
              <td className="mono" style={{ textAlign: 'right' }}>{r.credit ? fmtMoneyFull(r.credit) : ''}</td>
            </tr>
          ))}
          <tr style={{ borderTop: '2px solid var(--border-strong)' }}>
            <td colSpan={2} style={{ fontWeight: 600 }}>Total</td>
            <td className="mono" style={{ textAlign: 'right', fontWeight: 700 }}>{fmtMoneyFull(totalDr)}</td>
            <td className="mono" style={{ textAlign: 'right', fontWeight: 700 }}>{fmtMoneyFull(totalCr)}</td>
          </tr>
        </tbody>
      </table>
    </div>
  );
}

// ─── Cash flow statement ───────────────────────────────────
function CashFlowView({ period }) {
  const cf = window.HitcentsData.FIN_CASHFLOW;
  const operating = cf.operating.map(r => ({ ...r, amount: finScale(r.amount, r.name, period) }));
  const investing = cf.investing.map(r => ({ ...r, amount: finScale(r.amount, r.name, period) }));
  const financing = cf.financing.map(r => ({ ...r, amount: finScale(r.amount, r.name, period) }));
  const op = operating.reduce((s, r) => s + r.amount, 0);
  const inv = investing.reduce((s, r) => s + r.amount, 0);
  const fin = financing.reduce((s, r) => s + r.amount, 0);
  const net = op + inv + fin;
  const begin = period.begin || cf.beginningCash;
  return (
    <div className="card" style={{ maxWidth: 720, padding: 0 }}>
      <div className="fin-stmt-head">
        <div><h3 style={{ margin: 0 }}>Statement of Cash Flows</h3><div className="sub">{period.flow} · indirect method</div></div>
        <Button size="sm" variant="ghost" icon="download">Export</Button>
      </div>
      <div className="fin-stmt">
        <FinGroup label="Operating activities" rows={operating} total={op} muted />
        <FinGroup label="Investing activities" rows={investing} total={inv} muted />
        <FinGroup label="Financing activities" rows={financing} total={fin} muted />
        <FinTotal label="Net change in cash" value={net} strong positive={net >= 0} />
        <div className="fin-row" style={{ padding: '8px 18px' }}><span className="muted">Beginning cash</span><span className="mono">{fmtMoneyFull(begin)}</span></div>
        <FinTotal label="Ending cash" value={begin + net} strong />
      </div>
    </div>
  );
}

// ─── A/P aging ─────────────────────────────────────────────
function APAgingView({ asOf }) {
  const D = window.HitcentsData;
  const ref = asOf ? new Date(asOf) : FIN_TODAY;
  const open = D.FIN_BILLS.filter(b => b.status === 'Open' || b.status === 'Overdue');
  const buckets = ['Current', '1–30', '31–60', '61–90', '90+'];
  function bucketOf(due) {
    const d = Math.floor((ref - new Date(due)) / 86400000);
    if (d <= 0) return 'Current';
    if (d <= 30) return '1–30';
    if (d <= 60) return '31–60';
    if (d <= 90) return '61–90';
    return '90+';
  }
  const byVendor = {};
  open.forEach(b => {
    byVendor[b.vendor] = byVendor[b.vendor] || { Current: 0, '1–30': 0, '31–60': 0, '61–90': 0, '90+': 0, total: 0 };
    byVendor[b.vendor][bucketOf(b.due)] += b.amount;
    byVendor[b.vendor].total += b.amount;
  });
  const totals = buckets.reduce((acc, bk) => { acc[bk] = Object.values(byVendor).reduce((s, v) => s + v[bk], 0); return acc; }, {});
  const grand = Object.values(byVendor).reduce((s, v) => s + v.total, 0);
  return (
    <div className="card flush">
      <table className="table">
        <thead><tr><th>Vendor</th>{buckets.map(b => <th key={b} style={{ textAlign: 'right' }}>{b}</th>)}<th style={{ textAlign: 'right' }}>Total</th></tr></thead>
        <tbody>
          {Object.entries(byVendor).sort((a, b) => b[1].total - a[1].total).map(([v, row]) => (
            <tr key={v}>
              <td style={{ fontWeight: 500 }}>{v}</td>
              {buckets.map(b => <td key={b} className="mono" style={{ textAlign: 'right', color: b === '90+' && row[b] > 0 ? 'var(--red)' : 'var(--text)' }}>{row[b] ? fmtMoneyFull(row[b]) : <span className="dim">—</span>}</td>)}
              <td className="mono" style={{ textAlign: 'right', fontWeight: 600 }}>{fmtMoneyFull(row.total)}</td>
            </tr>
          ))}
          <tr style={{ borderTop: '2px solid var(--border-strong)' }}>
            <td style={{ fontWeight: 600 }}>Total</td>
            {buckets.map(b => <td key={b} className="mono" style={{ textAlign: 'right', fontWeight: 600 }}>{fmtMoneyFull(totals[b])}</td>)}
            <td className="mono" style={{ textAlign: 'right', fontWeight: 700 }}>{fmtMoneyFull(grand)}</td>
          </tr>
        </tbody>
      </table>
    </div>
  );
}

Object.assign(window, {
  FinanceOverview, FinanceInvoices, FinanceBills, FinanceBanking, FinanceLedger, FinanceReports,
});
