// screen-dashboard.jsx — Beranda / Home (priority screen)

function ScreenDashboard({ theme, accent, scenario, hideBalance, onToggleHide, onFab, onNavigate, onOpenSheet, auth }) {
  const [realTx, setRealTx] = React.useState(null);
  const [realBudgets, setRealBudgets] = React.useState(null);
  const familyId = auth && auth.family && auth.family.id;

  React.useEffect(function() {
    if (!familyId) return;
    function reload() {
      if (window.sbGetTransactions) sbGetTransactions(familyId).then(function(r) { if (!r.error) setRealTx(r.data || []); });
      if (window.sbGetBudgets)      sbGetBudgets(familyId).then(function(r) { if (!r.error) setRealBudgets(r.data || []); });
    }
    reload();
    window.addEventListener('tx-added', reload);
    return function() { window.removeEventListener('tx-added', reload); };
  }, [familyId]);

  const s = scenario;
  const isAuth = !!(auth && auth.family);

  // Ketika authenticated, JANGAN pakai dummy — pakai real data (bisa [] kalau kosong)
  const transactions = isAuth ? (realTx  || []) : s.transactions;
  const budgets      = isAuth ? (realBudgets || []) : s.budgets;

  const incomeTotal  = transactions.filter(function(t){ return (t.type||t.kind)==='income'; }).reduce(function(a,t){ return a+t.amount; }, 0);
  const expenseTotal = transactions.filter(function(t){ return (t.type||t.kind)==='expense'; }).reduce(function(a,t){ return a+t.amount; }, 0);
  const monthDelta   = isAuth ? incomeTotal - expenseTotal : s.monthlyIncome - s.monthlyExpense;
  const overBudgets  = isAuth
    ? budgets.filter(function(b){ return (b.used_pct||0) >= 90; })
    : s.budgets.filter(function(b){ return b.used/b.limit >= 0.9; });

  // Patch tx dari Supabase ke shape yang dipahami TxRow
  function patchTx(tx) {
    if (tx.kind) return tx;
    // Map category name to CATEGORIES key
    var catName = tx.category ? (tx.category.name||'').toLowerCase().replace(/\s+/g,'_') : 'lainnya_ex';
    // Try to find matching key in CATEGORIES
    var catKey = catName;
    if (!CATEGORIES[catKey]) {
      // Try with _ex or _in suffix
      catKey = catName + '_ex';
      if (!CATEGORIES[catKey]) catKey = catName + '_in';
      if (!CATEGORIES[catKey]) catKey = (tx.type==='income' ? 'lainnya_in' : 'lainnya_ex');
    }
    return Object.assign({}, tx, {
      kind: tx.type,
      cat:  catKey,
      by:   tx.user_id,
      profileObj: tx.profile,
    });
  }
  const recent       = transactions.slice(0, 5).map(patchTx);
  const patchedRecent = recent;

  // Build displayScenario — real data jika authenticated, dummy jika demo
  var memberShort = isAuth && auth.profile
    ? ((auth.profile.full_name || '').split(' ')[0] || 'Kamu')
    : s.members[0].short;

  var displayScenario = isAuth ? Object.assign({}, s, {
    family:        { name: auth.family.name, code: auth.family.invite_code },
    members:       [{ id: auth.profile && auth.profile.id, name: auth.profile && auth.profile.full_name || 'Kamu', short: memberShort, role: 'admin', color: '#10b981' }],
    balance:       monthDelta,
    monthlyIncome: incomeTotal,
    monthlyExpense: expenseTotal,
    transactions:  transactions.map(patchTx),
    budgets:       budgets,
    activity:      [],
    week:          [0,0,0,0,0,0,0],
    weekLabels:    ['Sen','Sel','Rab','Kam','Jum','Sab','Min'],
  }) : s;

  return (
    <div style={{
      background: theme.bg,
      paddingBottom: 24,
      display: 'flex', flexDirection: 'column', gap: 18,
    }}>
      <DashHeader theme={theme} accent={accent} scenario={displayScenario} />
      <BalanceCard theme={theme} accent={accent} scenario={displayScenario}
                   hide={hideBalance} onToggleHide={onToggleHide} auth={auth} />
      <QuickActions theme={theme} accent={accent} onOpenSheet={onOpenSheet} />
      <WeekChartCard theme={theme} accent={accent} scenario={displayScenario} />
      {overBudgets.length > 0 && (
        <BudgetAlerts theme={theme} accent={accent} budgets={overBudgets}
                      onSeeAll={() => onNavigate('budget')} />
      )}
      <RecentTransactions theme={theme} accent={accent} scenario={displayScenario}
                          items={recent}
                          onSeeAll={() => onNavigate('tx')} />
      <FireWidget theme={theme} accent={accent} auth={auth}
                   monthlyExpense={expenseTotal} onOpenFire={function(){onNavigate('fire');}} />
      <ActivityFeed theme={theme} accent={accent} scenario={Object.assign({}, displayScenario, {activity: displayScenario.activity || []})} />
      <div style={{ height: 80 }} />
    </div>
  );
}

// ─── Top app bar ────────────────────────────────────────────────
function DashHeader({ theme, accent, scenario }) {
  const me = scenario.members[0]; // assume "me" is first member
  return (
    <div style={{
      paddingTop: 56, // status bar clearance
      padding: '56px 20px 0',
      display: 'flex', alignItems: 'center', gap: 12,
    }}>
      <Avatar member={me} size={42} />
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{
          fontSize: 12, color: theme.fg3, fontWeight: 500,
          letterSpacing: '-0.005em',
        }}>Halo, {me?.short || me?.name?.split(' ')[0] || 'Bram'} 👋</div>
        <div style={{
          fontSize: 15, fontWeight: 700, color: theme.fg1,
          letterSpacing: '-0.01em', marginTop: 1,
          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
        }}>{scenario.family.name}</div>
      </div>
      <button style={iconBtn(theme)}>
        <Icon name="search" size={20} color={theme.fg1} stroke={1.8} />
      </button>
      <button style={iconBtn(theme)}>
        <Icon name="bell" size={20} color={theme.fg1} stroke={1.8} />
        <span style={{
          position: 'absolute', top: 8, right: 8,
          width: 8, height: 8, borderRadius: '50%',
          background: theme.accent[500], border: `2px solid ${theme.surface}`,
        }} />
      </button>
    </div>
  );
}

function iconBtn(theme) {
  return {
    appearance: 'none', border: 0, cursor: 'pointer',
    width: 40, height: 40, borderRadius: 12,
    background: theme.surface, position: 'relative',
    display: 'flex', alignItems: 'center', justifyContent: 'center',
    boxShadow: theme.shadow1,
    border: `0.5px solid ${theme.border}`,
  };
}

// ─── Balance card (gradient hero) ───────────────────────────────
function BalanceCard({ theme, accent, scenario, hide, onToggleHide, auth }) {
  const s = scenario;
  const monthDelta = s.monthlyIncome - s.monthlyExpense;
  const [breakdown, setBreakdown] = React.useState(null);
  const familyId = auth && auth.family && auth.family.id;

  React.useEffect(function() {
    if (!familyId || !window.SB) return;

    function loadBreakdown() {
      Promise.all([
        window.SB.from('accounts').select('balance,type,cost_basis,is_active,credit_limit').eq('family_id', familyId).eq('is_active', true),
        window.SB.from('savings_goals').select('current_amount,account_id').eq('family_id', familyId),
      ]).then(function(res) {
        var accs  = res[0].data || [];
        var goals = res[1].data || [];
        // totalPocket = sum current_amount semua goals aktif
        var totalPocket   = goals.reduce(function(s,g){return s+(g.current_amount||0);}, 0);
        var investasi     = accs.filter(function(a){return a.type==='investment';}).reduce(function(s,a){return s+a.balance;}, 0);
        var investasiCost = accs.filter(function(a){return a.type==='investment'&&a.cost_basis>0;}).reduce(function(s,a){return s+a.cost_basis;}, 0);
        var hutangKK      = accs.filter(function(a){return a.type==='credit';}).reduce(function(s,a){return s+a.balance;}, 0);
        // kasTotal = hanya rekening bank/cash/ewallet (bukan investasi, bukan kredit)
        var kasTotal      = accs.filter(function(a){return a.type==='bank'||a.type==='cash'||a.type==='ewallet';}).reduce(function(s,a){return s+a.balance;}, 0);
        // kasTotal = saldo fisik total (sudah include pocket di dalamnya)
        // tersedia = bebas dipakai = kasTotal - pocket
        var aktif     = kasTotal;
        var tersedia  = kasTotal - totalPocket;
        // netWorth = kas + investasi - hutang KK
        var netWorth  = kasTotal + investasi - hutangKK;
        setBreakdown({
          aktif, tersedia, pocket: totalPocket, investasi,
          investasiPnl: investasi - investasiCost,
          hutangKK, kasTotal, netWorth,
        });
      });
    }

    loadBreakdown();
    window.addEventListener('tx-added', loadBreakdown);
    return function() { window.removeEventListener('tx-added', loadBreakdown); };
  }, [familyId]);
  return (
    <div style={{ padding: '0 20px' }}>
      <div style={{
        position: 'relative',
        background: `linear-gradient(135deg, ${accent.grad[0]} 0%, ${accent.grad[1]} 100%)`,
        borderRadius: 22, padding: '20px 22px',
        color: '#fff',
        overflow: 'hidden',
        boxShadow: `0 10px 32px ${accent[500]}55`,
      }}>
        {/* decorative orbs */}
        <div style={{
          position: 'absolute', top: -40, right: -30,
          width: 160, height: 160, borderRadius: '50%',
          background: 'rgba(255,255,255,0.10)',
        }} />
        <div style={{
          position: 'absolute', bottom: -70, left: -40,
          width: 180, height: 180, borderRadius: '50%',
          background: 'rgba(255,255,255,0.06)',
        }} />

        <div style={{ position: 'relative', zIndex: 1 }}>
          <div style={{
            display: 'flex', alignItems: 'center', justifyContent: 'space-between',
            marginBottom: 6,
          }}>
            <div style={{
              fontSize: 12, fontWeight: 600, opacity: 0.85,
              letterSpacing: '0.04em', textTransform: 'uppercase',
              display: 'flex', alignItems: 'center', gap: 6,
            }}>
              <Icon name="wallet" size={14} color="#fff" stroke={2} />
              Saldo Keluarga
            </div>
            <button onClick={onToggleHide} style={{
              appearance: 'none', border: 0, background: 'rgba(255,255,255,0.18)',
              width: 30, height: 30, borderRadius: 10, cursor: 'pointer',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
            }}>
              <Icon name={hide ? 'eye-off' : 'eye'} size={15} color="#fff" stroke={2} />
            </button>
          </div>

          {/* Label saldo */}
          <div style={{ fontSize:11, opacity:0.75, marginBottom:2 }}>
            {breakdown ? 'Net Worth' : 'Saldo bulan ini'}
          </div>

          <div style={{
            fontSize: 32, fontWeight: 800,
            letterSpacing: '-0.02em', lineHeight: 1.1,
            fontVariantNumeric: 'tabular-nums',
            marginBottom: 14,
          }}>{fmtRp(breakdown ? breakdown.netWorth : s.balance, { hide })}</div>

          {/* Breakdown aktif / pocket / investasi */}
          {breakdown ? (
            <div style={{ marginBottom: 14 }}>
              <div style={{ display:'flex', gap:8 }}>
                {[
                  { label:'Bebas',     val: breakdown.tersedia,  icon:'✓',  note: 'diluar pocket' },
                  { label:'Pocket',    val: breakdown.pocket,    icon:'🔒', note: 'ada di rekening' },
                  { label:'Investasi', val: breakdown.investasi, icon:'📈', note: breakdown.investasiPnl !== 0 ? (breakdown.investasiPnl>0?'+':'')+fmtRp(breakdown.investasiPnl,{short:true})+' P&L' : 'portofolio' },
                ].map(function(item) {
                  return (
                    <div key={item.label} style={{
                      flex:1, background:'rgba(255,255,255,0.15)',
                      borderRadius:12, padding:'8px 10px',
                    }}>
                      <div style={{ fontSize:10, opacity:0.8, marginBottom:2 }}>{item.icon} {item.label}</div>
                      <div style={{ fontSize:13, fontWeight:800, letterSpacing:'-0.01em' }}>
                        {hide ? '••••' : fmtRp(item.val,{short:true})}
                      </div>
                      {item.note && <div style={{ fontSize:9, opacity:0.7, marginTop:1 }}>{item.note}</div>}
                    </div>
                  );
                })}
              </div>
              {breakdown.hutangKK > 0 && (
                <div style={{ marginTop:8, fontSize:11, opacity:0.8, textAlign:'right' }}>
                  💳 Tagihan KK: -{hide ? '••••' : fmtRp(breakdown.hutangKK,{short:true})}
                </div>
              )}
            </div>
          ) : null}

          <div style={{
            display: 'flex', alignItems: 'center', gap: 14,
            paddingTop: 12, borderTop: '1px solid rgba(255,255,255,0.2)',
          }}>
            <DeltaCol label="Bulan ini" amount={monthDelta} hide={hide} />
            <div style={{ width: 1, height: 28, background: 'rgba(255,255,255,0.2)' }} />
            <DeltaCol label="Pemasukan" amount={s.monthlyIncome} hide={hide} positive />
            <div style={{ width: 1, height: 28, background: 'rgba(255,255,255,0.2)' }} />
            <DeltaCol label="Pengeluaran" amount={-s.monthlyExpense} hide={hide} />
          </div>
        </div>
      </div>
    </div>
  );
}

function DeltaCol({ label, amount, hide, positive }) {
  const isPos = positive || amount > 0;
  return (
    <div style={{ flex: 1, minWidth: 0 }}>
      <div style={{ fontSize: 10, opacity: 0.75, fontWeight: 500, marginBottom: 2,
                    letterSpacing: '0.02em' }}>{label}</div>
      <div style={{
        fontSize: 13, fontWeight: 700, letterSpacing: '-0.01em',
        fontVariantNumeric: 'tabular-nums',
        whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
      }}>{fmtRp(amount, { short: true, sign: !positive && amount !== 0, hide })}</div>
    </div>
  );
}

// ─── Quick actions ──────────────────────────────────────────────
function QuickActions({ theme, accent, onOpenSheet }) {
  return (
    <div style={{ padding: '0 20px', display: 'flex', gap: 10 }}>
      <QuickAction kind="income" label="Pemasukan"
                   theme={theme} accent={accent}
                   onClick={() => onOpenSheet('income')} />
      <QuickAction kind="expense" label="Pengeluaran"
                   theme={theme} accent={accent}
                   onClick={() => onOpenSheet('expense')} />
    </div>
  );
}

// ─── 7-day chart card ───────────────────────────────────────────
function WeekChartCard({ theme, accent, scenario }) {
  const total = scenario.week.reduce((a, b) => a + b, 0);
  const avg = total / scenario.week.length;
  return (
    <div style={{ padding: '0 20px' }}>
      <Card theme={theme} padding={18}>
        <div style={{
          display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between',
          marginBottom: 10,
        }}>
          <div>
            <div style={{ fontSize: 12, color: theme.fg3, fontWeight: 600,
                          letterSpacing: '0.02em', marginBottom: 2 }}>
              Pengeluaran 7 hari
            </div>
            <div style={{
              fontSize: 20, fontWeight: 800, color: theme.fg1,
              letterSpacing: '-0.02em', fontVariantNumeric: 'tabular-nums',
            }}>{fmtRp(total)}</div>
          </div>
          <Badge theme={theme} color="accent">
            <Icon name="trending-down" size={11} stroke={2.4} />
            <span style={{ marginLeft: 2 }}>12% lebih hemat</span>
          </Badge>
        </div>
        <AreaChart7d data={scenario.week} labels={scenario.weekLabels}
                     theme={theme} accent={accent} height={90} width={340} />
        <div style={{
          marginTop: 10, paddingTop: 10,
          borderTop: `0.5px dashed ${theme.border}`,
          display: 'flex', justifyContent: 'space-between',
          fontSize: 11, color: theme.fg3, fontWeight: 500,
        }}>
          <span>Rata-rata · <strong style={{ color: theme.fg2 }}>{fmtRp(avg, { short: true })}/hari</strong></span>
          <span>Tertinggi · <strong style={{ color: theme.fg2 }}>{fmtRp(Math.max(...scenario.week), { short: true })}</strong></span>
        </div>
      </Card>
    </div>
  );
}

// ─── Budget alerts (over-budget chips) ──────────────────────────
function BudgetAlerts({ theme, accent, budgets, onSeeAll }) {
  return (
    <div>
      <SectionHeader title="Budget perlu perhatian" action="Lihat semua"
                     onAction={onSeeAll} theme={theme} />
      <div style={{
        padding: '0 20px', display: 'flex', gap: 10,
        overflowX: 'auto', scrollbarWidth: 'none',
      }}>
        {budgets.map((b) => {
          const c = CATEGORIES[b.cat];
          const pct = Math.min(100, Math.round((b.used / b.limit) * 100));
          const isOver = b.used > b.limit;
          const color = pct >= 100 ? theme.danger : pct >= 90 ? theme.warning : theme.accent[500];
          return (
            <div key={b.cat} style={{
              flex: '0 0 auto', width: 188,
              background: theme.surface,
              border: `0.5px solid ${theme.border}`,
              borderRadius: 16, padding: 14,
              boxShadow: theme.shadow1,
            }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
                <div style={{
                  width: 32, height: 32, borderRadius: 10,
                  background: c.color + '1a',
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                }}>
                  <Icon name={c.icon} size={16} color={c.color} stroke={1.85} />
                </div>
                <div style={{ flex: 1, fontSize: 13, fontWeight: 700, color: theme.fg1 }}>
                  {c.label}
                </div>
                {isOver && <Badge theme={theme} color="danger">Over</Badge>}
              </div>
              <ProgressBar value={b.used} max={b.limit} theme={theme} height={5} />
              <div style={{
                marginTop: 8, display: 'flex', justifyContent: 'space-between',
                fontSize: 11, color: theme.fg2, fontWeight: 600,
                fontVariantNumeric: 'tabular-nums',
              }}>
                <span style={{ color }}>{pct}%</span>
                <span>{fmtRp(b.used, { short: true })} / {fmtRp(b.limit, { short: true })}</span>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ─── Recent transactions ────────────────────────────────────────
function RecentTransactions({ theme, accent, scenario, items, onSeeAll }) {
  return (
    <div>
      <SectionHeader title="Transaksi terakhir" action="Semua"
                     onAction={onSeeAll} theme={theme} />
      <div style={{ padding: '0 20px' }}>
        <Card theme={theme} padding={4} radius={18}>
          {items.map((tx, i) => (
            <TxRow key={tx.id} tx={tx} scenario={scenario} theme={theme}
                   accent={accent} divider={i < items.length - 1} />
          ))}
        </Card>
      </div>
    </div>
  );
}

// Single transaction row — reused across Dashboard & Tx list
function TxRow({ tx, scenario, theme, accent, divider }) {
  const cat = CATEGORIES[tx.cat] || { label: tx.cat || 'Lainnya', color: '#94a3b8', icon: '📋', kind: tx.kind||'expense' };
  const m = getMember(scenario, tx.by) || {
    short: tx.profileObj?.full_name?.split(' ')[0] || tx.profile?.full_name?.split(' ')[0] || 'Kamu',
    name:  tx.profileObj?.full_name || tx.profile?.full_name || 'Anggota',
    color: '#10b981',
  };
  const isIncome = tx.kind === 'income';
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 12,
      padding: '12px 12px',
      borderBottom: divider ? `0.5px solid ${theme.border}` : 'none',
    }}>
      <CatDisc cat={cat} size={40} />
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{
          fontSize: 14, fontWeight: 600, color: theme.fg1,
          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
          letterSpacing: '-0.005em',
        }}>{tx.note || cat.label}</div>
        <div style={{
          display: 'flex', alignItems: 'center', gap: 6, marginTop: 3,
          fontSize: 11, color: theme.fg3, fontWeight: 500,
        }}>
          <Avatar member={m} size={14} />
          <span>{m.short}</span>
          <span>·</span>
          <span>{fmtRelDay(tx.date)}</span>
          <span>·</span>
          <span>{cat.label}</span>
        </div>
      </div>
      <div style={{
        fontSize: 14, fontWeight: 700,
        color: isIncome ? theme.success : theme.fg1,
        fontVariantNumeric: 'tabular-nums',
        letterSpacing: '-0.01em',
        whiteSpace: 'nowrap',
      }}>{fmtRp(tx.amount, { sign: true, short: tx.amount >= 1_000_000 })
            .replace('+', isIncome ? '+' : '')
            .replace('−', '−')}
        {!isIncome && !String(tx.amount).startsWith('−') && tx.kind === 'expense' &&
          /* fmtRp already handles negative; we keep formatting consistent */ ''}
      </div>
    </div>
  );
}

// ─── Activity feed (WhatsApp-style) ─────────────────────────────
function ActivityFeed({ theme, accent, scenario }) {
  return (
    <div>
      <SectionHeader title="Aktivitas keluarga" theme={theme} />
      <div style={{ padding: '0 20px' }}>
        <Card theme={theme} padding={4} radius={18}>
          {scenario.activity.map((a, i) => {
            const m = getMember(scenario, a.m) || {
              short: 'Kamu', name: 'Anggota', color: '#10b981',
            };
            const isLast = i === scenario.activity.length - 1;
            return (
              <div key={a.id} style={{
                display: 'flex', alignItems: 'flex-start', gap: 12,
                padding: '11px 12px',
                borderBottom: !isLast ? `0.5px solid ${theme.border}` : 'none',
              }}>
                <Avatar member={m} size={32} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{
                    fontSize: 13, color: theme.fg1, fontWeight: 500,
                    letterSpacing: '-0.005em', lineHeight: 1.35,
                  }}>
                    <strong style={{ fontWeight: 700 }}>{m.short}</strong>
                    {' '}{a.verb}{' '}
                    <span style={{ color: theme.fg2 }}>{a.what}</span>
                  </div>
                  <div style={{ fontSize: 11, color: theme.fg3, marginTop: 2 }}>
                    {fmtRelDay(a.ts)} · {fmtTime(a.ts)}
                  </div>
                </div>
              </div>
            );
          })}
        </Card>
      </div>
    </div>
  );
}

function FireWidget({ theme, accent, auth, monthlyExpense, onOpenFire }) {
  var T = theme;
  var _fw1 = React.useState(0), netWorth = _fw1[0], setNetWorth = _fw1[1];
  var familyId = auth && auth.family && auth.family.id;

  React.useEffect(function() {
    if (!familyId || !window.SB) return;
    window.SB.from('accounts').select('balance,type').eq('family_id', familyId).eq('is_active', true)
      .then(function(r) {
        if (!r.error && r.data) {
          var nw = r.data.filter(function(a){return a.type!=='credit';}).reduce(function(s,a){return s+a.balance;},0);
          setNetWorth(nw);
        }
      });
  }, [familyId]);

  var monthlyExp = monthlyExpense || 0;
  var annualExp  = monthlyExp * 12;
  var fireNum    = annualExp > 0 ? annualExp / 0.04 : 0;
  var pct        = fireNum > 0 ? Math.min(100, Math.round((netWorth / fireNum) * 100)) : 0;

  // Monthly savings needed (30yr horizon, 10% return)
  var r = 0.10 / 12, n = 30 * 12;
  var fvExisting = netWorth * Math.pow(1+r, n);
  var gap = Math.max(0, fireNum - fvExisting);
  var needPerMonth = gap > 0 ? Math.round(gap * r / (Math.pow(1+r, n) - 1)) : 0;

  if (!auth || !auth.family) return null;
  if (fireNum === 0 && netWorth === 0) return null;

  return (
    <div style={{ padding:'0 20px' }}>
      <button onClick={onOpenFire} style={{
        width:'100%', textAlign:'left', cursor:'pointer', appearance:'none',
        background:T.surface, border:'1px solid '+T.border,
        borderRadius:20, padding:16, boxShadow:'0 2px 8px rgba(0,0,0,0.04)',
      }}>
        <div style={{ display:'flex', justifyContent:'space-between', alignItems:'flex-start', marginBottom:10 }}>
          <div>
            <div style={{ display:'flex', alignItems:'center', gap:6, marginBottom:3 }}>
              <span style={{fontSize:14}}>🔥</span>
              <span style={{ fontSize:12, fontWeight:700, color:T.fg3, textTransform:'uppercase', letterSpacing:'0.06em' }}>FIRE Progress</span>
            </div>
            <div style={{ fontSize:26, fontWeight:800, color:T.fg1, letterSpacing:'-0.02em' }}>{pct}%</div>
            <div style={{ fontSize:11, color:T.fg3 }}>menuju Financial Independence</div>
          </div>
          <div style={{ textAlign:'right' }}>
            <div style={{ fontSize:10, color:T.fg3, marginBottom:2 }}>Target FIRE</div>
            <div style={{ fontSize:14, fontWeight:800, color:T.fg1 }}>{fmtRp(fireNum, {short:true})}</div>
            {netWorth > 0 && (
              <div style={{ fontSize:11, color:'#10b981', marginTop:2, fontWeight:600 }}>
                {fmtRp(netWorth, {short:true})} terkumpul
              </div>
            )}
          </div>
        </div>

        <div style={{ height:8, background:T.surfaceAlt, borderRadius:4, overflow:'hidden', marginBottom:10 }}>
          <div style={{ height:'100%', borderRadius:4, width:pct+'%', transition:'width 0.6s ease',
            background: pct>=100 ? '#10b981'
              : 'linear-gradient(90deg,'+accent.grad[0]+','+accent.grad[1]+')' }}/>
        </div>

        <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center' }}>
          {pct >= 100 ? (
            <div style={{ fontSize:12, color:'#10b981', fontWeight:700 }}>🎉 Kamu sudah bisa FIRE!</div>
          ) : needPerMonth > 0 ? (
            <div style={{ fontSize:12, color:T.fg2 }}>
              Nabung{' '}
              <span style={{ fontWeight:800, color:accent[600] }}>{fmtRp(needPerMonth,{short:true})}/bln</span>
              {' '}lagi selama 30 thn
            </div>
          ) : (
            <div style={{ fontSize:12, color:T.fg3 }}>Catat transaksi untuk kalkulasi</div>
          )}
          <div style={{ fontSize:11, color:accent[500], fontWeight:700 }}>Lihat detail →</div>
        </div>
      </button>
    </div>
  );
}

Object.assign(window, {
  ScreenDashboard, TxRow, FireWidget,
});
