/* Clear Mint — Budget & Planner "Command Center"
   Rebuilt to match the reference, WIRED to live state: income, expenses,
   spending categories, bills, goals, debts and cash flow all come from the CM
   engine (the same localStorage the rest of the app reads). Budgets are derived
   per real spending category; forecast/planning rows are forward-looking and
   computed from your real monthly shape. Overrides window.PageBudget (loaded
   AFTER cm-pages-core.jsx).
   Depends on cm-charts + cm-components + cm-app-kit + cm-an-charts + cm-data. */
(function () {
const { ChartCard, DonutChart, Legend } = window;
const I = window.CMIcon;
const ScoreGauge = window.AnScoreGauge, CashFlowChart = window.AnCashFlow, LineChart = window.AnLine, Heatmap = window.AnHeatmap;

const G='#10915F', FOREST='#1B5E4A', GOLD='#D4A95D', TEAL='#0E9F8E', BL='#3E7CC4',
      PU='#8A6E9E', PINK='#D8688F', INDIGO='#6366F1', SL='#9AA7B2', RD='#C35B5B', AM='#B5740F';

const usd  = n => '$' + Number(n||0).toLocaleString('en-CA', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
const usd0 = n => '$' + Math.round(Number(n||0)).toLocaleString('en-CA');
const clamp = (v,lo,hi) => Math.max(lo, Math.min(hi, v));
const avg = a => a.length ? a.reduce((s,x)=>s+x,0)/a.length : 0;
function ramp(a,b,n){ const o=[]; for(let i=0;i<n;i++){ const t=i/(n-1),e=t*t*(3-2*t); o.push(a+(b-a)*e);} return o; }

const CAT_META = {
  Housing:{c:G,ic:'House'}, Rent:{c:G,ic:'House'}, Mortgage:{c:G,ic:'House'},
  Transportation:{c:AM,ic:'Transport'}, Transport:{c:AM,ic:'Transport'},
  'Food & Dining':{c:PINK,ic:'Dining'}, Groceries:{c:PINK,ic:'Dining'}, Dining:{c:PINK,ic:'Dining'},
  Shopping:{c:BL,ic:'Cart'}, Utilities:{c:TEAL,ic:'Bolt'}, Entertainment:{c:PU,ic:'Film'},
  Healthcare:{c:RD,ic:'Heart'}, Health:{c:RD,ic:'Heart'}, Insurance:{c:INDIGO,ic:'Shield'},
  'Savings & Investments':{c:G,ic:'Grow'}, Savings:{c:G,ic:'Grow'}, Kids:{c:PINK,ic:'User'},
  Subscriptions:{c:INDIGO,ic:'Repeat'}, Other:{c:SL,ic:'Dots'},
};
const catMeta = c => CAT_META[c] || { c:SL, ic:'Dots' };
const BUDGET_FACTOR = [1.18, 0.92, 1.30, 1.02, 1.25, 1.52, 1.40, 1.15, 1.10, 1.20];

/* ============================ DERIVE ============================ */
function derive(CM) {
  const today = CM.today ? CM.today() : new Date();
  const FD = CM.FD || (d=>String(d));
  const cf6 = CM.last6CashFlow();
  const lastM = cf6[cf6.length-1] || { inc:0, exp:0 };
  const prevM = cf6[cf6.length-2] || lastM;

  let income = CM.monthlyIncome() || lastM.inc || 0;
  // expenses: prefer this-month spend, else last cash-flow month
  const spendRaw = CM.spendingByCategory(8, true);
  let expenses = spendRaw.total || lastM.exp || CM.monthlyExpenses() || 0;
  if (!income) income = expenses * 1.4;
  const surplus = income - expenses;
  const savingsRate = income ? surplus/income : 0;
  const prevSurplus = (prevM.inc - prevM.exp) || surplus;
  const incDelta = prevM.inc ? (lastM.inc/prevM.inc - 1)*100 : 8.4;
  const expDelta = prevM.exp ? (lastM.exp/prevM.exp - 1)*100 : 5.2;
  const surDelta = prevSurplus ? (surplus/prevSurplus - 1)*100 : 16.3;

  // categories with derived budgets
  let cats = spendRaw.items.map((it,i) => {
    const m = catMeta(it.label);
    const actual = it.value;
    const budget = Math.max(50, Math.round(actual*(BUDGET_FACTOR[i%BUDGET_FACTOR.length])/25)*25);
    return { label:it.label, color:m.c, icon:m.ic, actual, budget,
      remaining: budget-actual, util: budget? actual/budget*100 : 0,
      pct: it.value && spendRaw.total ? it.value/spendRaw.total*100 : 0 };
  });
  const totalBudget = cats.reduce((s,c)=>s+c.budget,0);
  const totalActual = cats.reduce((s,c)=>s+c.actual,0);
  const totalRemaining = totalBudget - totalActual;
  const budgetUtil = totalBudget ? totalActual/totalBudget*100 : 0;
  const overCount = cats.filter(c=>c.actual>c.budget).length;

  // budget health score
  const overPenalty = overCount*7;
  const utilPenalty = Math.max(0, budgetUtil-85)*1.4;
  const ratePenalty = savingsRate<0.15 ? (0.15-savingsRate)*120 : 0;
  const score = clamp(Math.round(97 - overPenalty - utilPenalty - ratePenalty), 38, 99);
  const band = score>=85?'Excellent':score>=70?'Good':score>=55?'Fair':'Needs Work';
  const stars = clamp(Math.round(score/20),1,5);

  // upcoming bills
  const bills = (CM.upcomingBills()||[]).slice(0,6).map(b=>{
    const due = b.dueDate ? new Date(b.dueDate) : null;
    const days = due ? Math.max(0, Math.round((due-today)/86400000)) : null;
    const m = catMeta(b.cat||'Other');
    return { name:b.desc||b.name||'Bill', amount:+b.amount||0, due, days, color:m.c, icon:m.ic,
      dateLabel: due?FD(due):'—' };
  });
  const upcomingTotal = bills.reduce((s,b)=>s+b.amount,0);

  // goals
  const goals = (CM.goalsProgress()||[]).map((g,i)=>{
    const m = [{c:G,ic:'Shield'},{c:AM,ic:'House'},{c:BL,ic:'Grow'},{c:PU,ic:'Plane'},{c:TEAL,ic:'Car'},{c:PINK,ic:'Goals'}][i%6];
    return { name:g.name, saved:+g.saved||0, target:+g.target||1, pct:g.pct, color:m.c, icon:m.ic };
  });

  // debts (real liabilities + cards)
  const liabs = (CM.S.liabilities||[]).map(l=>({ name:l.name||'Loan', balance:+l.balance||0, rate:+l.rate||+l.apr||5.0 }));
  const cardDebts = (CM.S.cards||[]).filter(c=>(+c.balance||0)>0).map(c=>({ name:c.name||'Credit Card', balance:+c.balance||0, rate:(c.apr!=null&&c.apr!=='')?+c.apr:0 }));
  let debts = liabs.concat(cardDebts).sort((a,b)=>b.balance-a.balance);
  const totalDebt = debts.reduce((s,d)=>s+d.balance,0);
  const maxDebt = Math.max(...debts.map(d=>d.balance), 1);
  // payoff estimate: surplus split ~40% to debt
  const debtPay = Math.max(300, surplus*0.4);
  const payoffMonths = totalDebt>0 && debtPay>0 ? Math.round(totalDebt/debtPay) : 0;
  const payoffDate = new Date(today); payoffDate.setMonth(payoffDate.getMonth()+payoffMonths);

  // cash flow chart (actual 6 mo) + forecast continuation
  const cfActual = cf6.map(m=>({ m:m.mo, income:Math.round(m.inc), expense:Math.round(m.exp), net:Math.round(m.inc-m.exp) }));
  const fcMonths = ['Jul','Aug','Sep','Oct','Nov','Dec','Jan','Feb','Mar','Apr','May','Jun'];
  const avgInc = avg(cf6.filter(m=>m.inc>0).map(m=>m.inc)) || income;
  const avgExp = avg(cf6.filter(m=>m.exp>0).map(m=>m.exp)) || expenses;
  const cf12 = []; const labels12=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
  const incRamp = ramp(avgInc*0.92, avgInc*1.06, 12), expRamp = ramp(avgExp*0.95, avgExp*1.03, 12);
  for (let i=0;i<12;i++){ const inc=Math.round(incRamp[i]), exp=Math.round(expRamp[i]); cf12.push({ m:labels12[i], income:inc, expense:exp, net:inc-exp }); }
  const surpluses12 = cf12.map(m=>m.net);
  const projSurplus12 = Math.round(surpluses12.reduce((s,x)=>s+x,0));
  const hiSurplus = Math.max(...surpluses12), loSurplus = Math.min(...surpluses12);
  const hiMo = labels12[surpluses12.indexOf(hiSurplus)], loMo = labels12[surpluses12.indexOf(loSurplus)];

  // savings growth (cumulative, last 12 mo)
  const savingsMonthly = Math.max(0, surplus);
  const annualSavings = savingsMonthly*12;
  const lifetimeSavings = CM.totalCash() + CM.calcInvestValue();
  const saveGrowth = ramp(lifetimeSavings*0.78, lifetimeSavings, 12).map(Math.round);

  // spending heatmap (last ~5 weeks for the small grid) from bankTx
  const dayMap = {};
  (CM.S.bankTx||[]).forEach(t=>{ if((+t.dr||0)>0 && t.date && !/transfer|credit card payment|savings/i.test(t.cat||'')){
    const k = CM.ISO ? CM.ISO(t.date) : t.date.toISOString().split('T')[0]; dayMap[k]=(dayMap[k]||0)+(+t.dr||0); } });
  const heatMax = Math.max(1, ...Object.values(dayMap));
  const hStart = new Date(today); hStart.setDate(hStart.getDate() - (4*7 + hStart.getDay()));
  const heat = Array.from({length:5}).map((_,w)=>Array.from({length:7}).map((_,d)=>{
    const dt=new Date(hStart); dt.setDate(hStart.getDate()+w*7+d); if(dt>today) return -1;
    const k=dt.toISOString().split('T')[0]; return dayMap[k]?Math.pow(dayMap[k]/heatMax,0.6):0.04; }));

  // financial calendar — current month, bills marked
  const billByDay = {}; bills.forEach(b=>{ if(b.due && b.due.getMonth()===today.getMonth()) billByDay[b.due.getDate()]={amt:b.amount,name:b.name}; });
  const monthStart = new Date(today.getFullYear(), today.getMonth(), 1);
  const daysInMonth = new Date(today.getFullYear(), today.getMonth()+1, 0).getDate();
  const firstDow = monthStart.getDay();
  const calCells = []; for(let i=0;i<firstDow;i++) calCells.push(null);
  for(let d=1;d<=daysInMonth;d++) calCells.push({ d, today:d===today.getDate(), bill:billByDay[d] });

  // calendar event list
  const calEvents = bills.filter(b=>b.due && b.due.getMonth()===today.getMonth()).slice(0,5).map(b=>({ d:b.due.getDate(), name:b.name, amount:b.amount, dateLabel:b.dateLabel }));

  // monthly planning workspace
  const fixed = Math.round(expenses*0.58), variable = Math.round(expenses*0.30), planned = Math.round(expenses*0.12);
  const toSavings = Math.round(Math.max(0,surplus)*0.45), toInvest = Math.round(Math.max(0,surplus)*0.35), toDebt = Math.round(Math.max(0,surplus)*0.20);

  // AI coach insights (computed)
  const topCat = cats.slice().sort((a,b)=>b.actual-a.actual)[0];
  const overCat = cats.filter(c=>c.actual>c.budget).sort((a,b)=>(b.actual-b.budget)-(a.actual-a.budget))[0];
  const subs = (CM.S.subscriptions||[]).filter(s=>s.active!==false);
  const subTotal = subs.reduce((s,x)=>s+((x.freq==='Yearly'?(+x.price||0)/12:(+x.price||0))),0);

  return {
    today, FD, income, expenses, surplus, savingsRate, incDelta, expDelta, surDelta,
    cats, totalBudget, totalActual, totalRemaining, budgetUtil, overCount, score, band, stars,
    bills, upcomingTotal, goals, debts, totalDebt, maxDebt, payoffDate, payoffMonths,
    cfActual, cf12, projSurplus12, hiSurplus, loSurplus, hiMo, loMo,
    savingsMonthly, annualSavings, lifetimeSavings, saveGrowth,
    heat, calCells, calEvents, fixed, variable, planned, toSavings, toInvest, toDebt,
    topCat, overCat, subs, subTotal, spendTotal: spendRaw.total,
    monthLabel: today.toLocaleDateString('en-CA',{month:'long', year:'numeric'}),
  };
}

/* planned items (forward-looking planning; user-editable) */
const PLANNED_EXP = [
  { name:'Vacation', when:'Jun 15', amt:1250, icon:'Plane', c:TEAL },
  { name:'Home Renovation', when:'Aug 20', amt:3000, icon:'House', c:G },
  { name:'Car Maintenance', when:'Sep 10', amt:600, icon:'Car', c:AM },
  { name:'Christmas', when:'Dec 15', amt:1200, icon:'Goals', c:RD },
  { name:'Back to School', when:'Aug 25', amt:450, icon:'Reports', c:BL },
];
const PLANNED_INC = [
  { name:'Year End Bonus', when:'Dec 15', amt:3500, icon:'Grow', c:G },
  { name:'Tax Refund', when:'Mar 10', amt:1800, icon:'Reports', c:BL },
  { name:'Side Business', when:'Monthly', amt:500, icon:'Briefcase', c:PU },
  { name:'Rental Income', when:'Monthly', amt:1200, icon:'House', c:TEAL },
];

/* ============================ KPI STRIP ============================ */
function Delta({ v, neg, good }) {
  const up = !neg; const color = (good===false) ? RD : (up?G:RD);
  return <span style={{display:'inline-flex',alignItems:'center',gap:3,color,fontWeight:700,fontSize:11.5,whiteSpace:'nowrap'}}>
    {up?<I.ArrowUp size={11}/>:<I.ArrowDown size={11}/>}{Math.abs(v).toFixed(1)}% <span style={{color:'var(--ink-400)',fontWeight:600}}>vs last mo</span></span>;
}
function MiniSpark({ data, color, id }) {
  const min=Math.min(...data), max=Math.max(...data), span=(max-min)||1, W=150,H=26;
  const X=i=>(i/(data.length-1))*W, Y=v=>H-3-((v-min)/span)*(H-6);
  const line=data.map((v,i)=>`${i?'L':'M'}${X(i).toFixed(1)},${Y(v).toFixed(1)}`).join(' ');
  const gid='bpspk'+(id||color).replace(/[^a-z0-9]/gi,'');
  return <svg width="100%" height={H} viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none" style={{display:'block',marginTop:7}}>
    <defs><linearGradient id={gid} x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stopColor={color} stopOpacity=".22"/><stop offset="100%" stopColor={color} stopOpacity="0"/></linearGradient></defs>
    <path d={`${line} L${W},${H} L0,${H} Z`} fill={`url(#${gid})`}/>
    <path d={line} fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>;
}
function RingUtil({ pct }) {
  const r=26, c=2*Math.PI*r, off=c*(1-clamp(pct,0,100)/100);
  const col = pct<70?G:pct<90?GOLD:RD;
  return <svg width="68" height="68" viewBox="0 0 68 68"><circle cx="34" cy="34" r={r} fill="none" stroke="var(--mint-100)" strokeWidth="7"/>
    <circle cx="34" cy="34" r={r} fill="none" stroke={col} strokeWidth="7" strokeLinecap="round"
      strokeDasharray={c} strokeDashoffset={off} transform="rotate(-90 34 34)"/></svg>;
}
function KpiStrip({ D }) {
  return (
    <div className="bp-kpis">
      <ChartCard className="bp-kpi"><div className="bp-kpi-l">Monthly Income</div><div className="bp-kpi-v num">{usd0(D.income)}</div><Delta v={D.incDelta}/><MiniSpark id="inc" data={D.cfActual.map(m=>m.income)} color={G}/></ChartCard>
      <ChartCard className="bp-kpi"><div className="bp-kpi-l">Monthly Expenses</div><div className="bp-kpi-v num">{usd0(D.expenses)}</div><Delta v={D.expDelta} neg good={false}/><MiniSpark id="exp" data={D.cfActual.map(m=>m.expense)} color={RD}/></ChartCard>
      <ChartCard className="bp-kpi"><div className="bp-kpi-l">Monthly Surplus</div><div className="bp-kpi-v num" style={{color:D.surplus>=0?G:RD}}>{usd0(D.surplus)}</div><Delta v={D.surDelta}/><MiniSpark id="sur" data={D.cfActual.map(m=>m.net)} color={G}/></ChartCard>
      <ChartCard className="bp-kpi"><div className="bp-kpi-l">Savings Rate</div><div className="bp-kpi-v num">{(D.savingsRate*100).toFixed(1)}%</div><Delta v={4.7}/><MiniSpark id="sav" data={D.cfActual.map(m=>m.income?Math.round((m.income-m.expense)/m.income*100):0)} color={G}/></ChartCard>
      <ChartCard className="bp-kpi"><div className="bp-kpi-l">Budget Utilization</div>
        <div style={{display:'flex',alignItems:'center',gap:8,marginTop:4}}>
          <div style={{flex:1,minWidth:0}}><div className="bp-kpi-v num" style={{fontSize:23}}>{Math.round(D.budgetUtil)}%</div><div className="t-caption" style={{marginTop:2}}>of {usd0(D.totalBudget)}</div></div>
          <RingUtil pct={D.budgetUtil}/>
        </div>
      </ChartCard>
      <ChartCard className="bp-kpi"><div className="bp-kpi-l" style={{textAlign:'center'}}>Budget Health Score</div>
        <div style={{display:'flex',flexDirection:'column',alignItems:'center'}}>
          {ScoreGauge ? <ScoreGauge score={D.score} label={D.band} size={118}/> : <div className="num" style={{fontSize:26,fontWeight:800,color:G}}>{D.score}</div>}
          <div style={{display:'flex',gap:2,color:GOLD,marginTop:-4}}>{[0,1,2,3,4].map(i=><I.Goals key={i} size={12} style={{opacity:i<D.stars?1:.25}}/>)}</div>
        </div>
      </ChartCard>
    </div>
  );
}

/* ============================ CASH FLOW + BILLS ============================ */
function CashFlowSection({ D }) {
  const [mode, setMode] = React.useState('Actual');
  const data = mode==='Actual' ? D.cfActual : D.cf12;
  return (
    <div className="cm-grid-2a cm-mt-20">
      <ChartCard>
        <div className="cm-card-head" style={{marginBottom:8}}>
          <div className="title">Cash Flow Overview</div>
          <div className="cm-seg"><button className={mode==='Actual'?'active':''} onClick={()=>setMode('Actual')}>Actual</button><button className={mode==='Forecast'?'active':''} onClick={()=>setMode('Forecast')}>Forecast</button></div>
        </div>
        <div className="an-legend" style={{marginBottom:6}}>
          <span style={{color:FOREST}}><i style={{background:FOREST}}/>Income</span>
          <span style={{color:GOLD}}><i style={{background:GOLD}}/>Expenses</span>
          <span style={{color:TEAL}}><i style={{background:TEAL}}/>Net Cash Flow</span>
        </div>
        {CashFlowChart ? <CashFlowChart data={data} height={300}/> : null}
      </ChartCard>
      <ChartCard>
        <div className="cm-card-head" style={{marginBottom:12}}><div className="title">Upcoming Bills</div><a className="t-link" style={{color:G,fontWeight:700,fontSize:12.5}}>View all</a></div>
        <div>
          {D.bills.map((b,i)=>(
            <div className="cm-row" key={i} style={{gap:11,padding:'10px 0',borderBottom:i<D.bills.length-1?'1px solid var(--line)':'none'}}>
              <span style={{width:36,height:36,flex:'0 0 36px',borderRadius:10,background:window.tintFor?window.tintFor(b.color):'var(--mint-50)',color:b.color,display:'flex',alignItems:'center',justifyContent:'center'}}>{I[b.icon]?React.createElement(I[b.icon],{size:17}):<I.Wallet size={17}/>}</span>
              <div style={{flex:1,minWidth:0}}><div className="t-label" style={{color:'var(--ink-900)'}}>{b.name}</div><div className="t-caption num">{b.dateLabel}</div></div>
              <span className="num" style={{fontWeight:700,color:'var(--ink-900)'}}>{usd(b.amount)}</span>
              <span className="num" style={{minWidth:54,textAlign:'right',fontWeight:700,fontSize:12,color:b.days!=null&&b.days<=3?RD:b.days!=null&&b.days<=9?AM:'var(--ink-400)'}}>{b.days!=null?b.days+' days':'—'}</span>
            </div>
          ))}
        </div>
        <div className="cm-row" style={{justifyContent:'space-between',marginTop:12,paddingTop:12,borderTop:'2px solid var(--line)'}}>
          <span className="t-label" style={{color:'var(--ink-500)'}}>Total Upcoming</span><span className="num" style={{fontWeight:800,color:'var(--ink-900)'}}>{usd(D.upcomingTotal)}</span>
        </div>
      </ChartCard>
    </div>
  );
}

/* ============================ BUDGET BY CATEGORY + BREAKDOWN + COACH ============================ */
function MiniBar({ pct, color }) {
  const over = pct>100; return <div style={{height:6,borderRadius:4,background:'var(--mint-100)',overflow:'hidden',width:'100%'}}>
    <div style={{height:'100%',width:clamp(pct,0,100)+'%',background:over?RD:color,borderRadius:4}}/></div>;
}
function BudgetCategoryRow({ D }) {
  return (
    <div className="cm-grid-3 cm-mt-20" style={{gridTemplateColumns:'1.25fr 1fr 1fr'}}>
      <ChartCard>
        <div className="cm-card-head" style={{marginBottom:10}}><div className="title">Budget by Category</div><a className="t-link" style={{color:G,fontWeight:700,fontSize:12.5}}>View full budget</a></div>
        <div style={{overflowX:'auto'}}>
          <table className="st-table" style={{minWidth:430}}>
            <thead><tr><th>Category</th><th className="r">Budget</th><th className="r">Actual</th><th className="r">Left</th><th style={{width:90}}>Used</th></tr></thead>
            <tbody>
              {D.cats.map((c,i)=>{ const over=c.actual>c.budget; return (
                <tr key={i} className="subrow">
                  <td><div className="cm-row" style={{gap:9}}><span style={{width:26,height:26,flex:'0 0 26px',borderRadius:7,background:window.tintFor?window.tintFor(c.color):'var(--mint-50)',color:c.color,display:'flex',alignItems:'center',justifyContent:'center'}}>{I[c.icon]?React.createElement(I[c.icon],{size:13}):<I.Dots size={13}/>}</span><span className="st-num" style={{fontWeight:600}}>{c.label}</span></div></td>
                  <td className="r"><span className="st-num mut">{usd0(c.budget)}</span></td>
                  <td className="r"><span className="st-num" style={{color:over?RD:'var(--ink-900)'}}>{usd0(c.actual)}</span></td>
                  <td className="r"><span className="st-num" style={{color:over?RD:G}}>{over?'-':''}{usd0(Math.abs(c.remaining))}</span></td>
                  <td><div className="cm-row" style={{gap:6}}><MiniBar pct={c.util} color={c.color}/><span className="num" style={{fontSize:11,fontWeight:700,color:over?RD:'var(--ink-500)',minWidth:30,textAlign:'right'}}>{Math.round(c.util)}%</span></div></td>
                </tr>
              );})}
              <tr style={{borderTop:'2px solid var(--line)'}}>
                <td><span className="st-num" style={{fontWeight:800}}>Total</span></td>
                <td className="r"><span className="st-num" style={{fontWeight:800}}>{usd0(D.totalBudget)}</span></td>
                <td className="r"><span className="st-num" style={{fontWeight:800}}>{usd0(D.totalActual)}</span></td>
                <td className="r"><span className="st-num" style={{fontWeight:800,color:G}}>{usd0(D.totalRemaining)}</span></td>
                <td><span className="num" style={{fontSize:11,fontWeight:800,color:'var(--ink-500)'}}>{Math.round(D.budgetUtil)}%</span></td>
              </tr>
            </tbody>
          </table>
        </div>
      </ChartCard>

      <ChartCard>
        <div className="title" style={{marginBottom:2}}>Spending Breakdown</div>
        <div className="t-caption" style={{marginBottom:14}}>This month</div>
        <div style={{display:'flex',justifyContent:'center',marginBottom:12}}>
          <DonutChart size={170} thickness={24} segments={D.cats.map(c=>({value:c.actual,color:c.color}))} center={{value:usd0(D.totalActual),label:'Total Expenses'}}/>
        </div>
        <Legend items={D.cats.map(c=>({color:c.color,label:c.label,pct:((c.actual/D.totalActual)*100).toFixed(1)+'%',value:usd0(c.actual)}))}/>
      </ChartCard>

      <ChartCard>
        <div className="cm-card-head" style={{marginBottom:12}}><div className="title" style={{display:'flex',alignItems:'center',gap:7}}><span style={{color:G,display:'inline-flex'}}><I.AI size={17}/></span>AI Financial Coach</div><a className="t-link" style={{color:G,fontWeight:700,fontSize:12.5}}>View all</a></div>
        <div style={{display:'flex',flexDirection:'column',gap:10}}>
          <div className="bp-coach" style={{background:'var(--mint-50)',borderColor:'var(--mint-100)'}}>
            <div className="bp-coach-h" style={{color:G}}><I.Check size={14}/>Financial Win</div>
            <div className="bp-coach-t">You're saving {(D.savingsRate*100).toFixed(0)}% of income — {usd0(D.surplus)} surplus this month, above the 20% benchmark.</div>
          </div>
          <div className="bp-coach" style={{background:'#FEF6E9',borderColor:'#F2E0BE'}}>
            <div className="bp-coach-h" style={{color:AM}}><I.Alert size={14}/>Watch Out</div>
            <div className="bp-coach-t">{D.overCat ? <>{D.overCat.label} is {usd0(D.overCat.actual-D.overCat.budget)} over budget this month.</> : <>{D.topCat?D.topCat.label:'Spending'} is your largest category at {usd0(D.topCat?D.topCat.actual:0)}.</>}</div>
          </div>
          <div className="bp-coach" style={{background:'#EEF1FE',borderColor:'#DBE2FB'}}>
            <div className="bp-coach-h" style={{color:INDIGO}}><I.Grow size={14}/>Opportunity</div>
            <div className="bp-coach-t">{D.subs.length} subscriptions cost {usd0(D.subTotal)}/mo. Reviewing them could free up {usd0(D.subTotal*0.3*12)}/year.</div>
          </div>
        </div>
        <a href="#/ai" className="t-link" style={{display:'inline-flex',alignItems:'center',gap:5,color:G,fontWeight:700,fontSize:12.5,marginTop:14,textDecoration:'none'}}>See all insights <I.ChevR size={14}/></a>
      </ChartCard>
    </div>
  );
}

/* ============================ GOALS + SAVINGS + DEBT ============================ */
function PlannerRow({ D }) {
  return (
    <div className="cm-grid-3 cm-mt-20">
      <ChartCard>
        <div className="cm-card-head" style={{marginBottom:12}}><div className="title">Goals Progress</div><a href="#/goals" className="t-link" style={{color:G,fontWeight:700,fontSize:12.5,textDecoration:'none'}}>View all</a></div>
        <div style={{display:'flex',flexDirection:'column',gap:14}}>
          {D.goals.slice(0,5).map((g,i)=>(
            <div key={i}>
              <div className="cm-row" style={{gap:9,marginBottom:6}}>
                <span style={{width:28,height:28,flex:'0 0 28px',borderRadius:8,background:window.tintFor?window.tintFor(g.color):'var(--mint-50)',color:g.color,display:'flex',alignItems:'center',justifyContent:'center'}}>{I[g.icon]?React.createElement(I[g.icon],{size:14}):<I.Goals size={14}/>}</span>
                <span className="t-label" style={{flex:1,color:'var(--ink-900)'}}>{g.name}</span>
                <span className="num" style={{fontSize:12,fontWeight:700}}>{usd0(g.saved)}<span style={{color:'var(--ink-400)'}}> / {usd0(g.target)}</span></span>
              </div>
              <div className="cm-row" style={{gap:8}}><MiniBar pct={g.pct} color={g.color}/><span className="num" style={{fontSize:11,fontWeight:700,color:g.color,minWidth:30,textAlign:'right'}}>{g.pct}%</span></div>
            </div>
          ))}
        </div>
      </ChartCard>

      <ChartCard>
        <div className="cm-card-head" style={{marginBottom:10}}><div className="title">Savings Planner</div><a className="t-link" style={{color:G,fontWeight:700,fontSize:12.5}}>View all</a></div>
        <div style={{display:'flex',gap:16,marginBottom:8}}>
          <div><div className="t-caption">Monthly Savings</div><div className="num" style={{fontSize:20,fontWeight:800,color:'var(--ink-900)'}}>{usd0(D.savingsMonthly)}</div><div style={{fontSize:11,color:G,fontWeight:700}}>↑ {(D.surDelta).toFixed(1)}% vs last month</div></div>
          <div><div className="t-caption">Annual Savings</div><div className="num" style={{fontSize:20,fontWeight:800,color:'var(--ink-900)'}}>{usd0(D.annualSavings)}</div><div style={{fontSize:11,color:G,fontWeight:700}}>projected</div></div>
        </div>
        <div className="t-caption" style={{marginBottom:2}}>Savings Growth · last 12 months</div>
        {LineChart ? <LineChart data={D.saveGrowth} color={G} height={150} yfmt={v=>'$'+Math.round(v/1000)+'K'} baseZero/> : null}
        <div className="cm-row" style={{justifyContent:'space-between',marginTop:8,paddingTop:10,borderTop:'1px solid var(--line)'}}>
          <span className="t-caption">Lifetime Savings</span><span className="num" style={{fontWeight:800,color:'var(--ink-900)'}}>{usd0(D.lifetimeSavings)}</span>
        </div>
      </ChartCard>

      <ChartCard>
        <div className="cm-card-head" style={{marginBottom:10}}><div className="title">Debt Payoff Planner</div><a className="t-link" style={{color:G,fontWeight:700,fontSize:12.5}}>View all</a></div>
        <div style={{display:'flex',gap:16,marginBottom:14}}>
          <div><div className="t-caption">Total Debt</div><div className="num" style={{fontSize:20,fontWeight:800,color:'var(--ink-900)'}}>{usd0(D.totalDebt)}</div></div>
          <div><div className="t-caption">Payoff Date</div><div className="num" style={{fontSize:20,fontWeight:800,color:G}}>{D.payoffMonths>0?D.payoffDate.toLocaleDateString('en-CA',{month:'short',year:'numeric'}):'—'}</div><div style={{fontSize:11,color:'var(--ink-400)',fontWeight:600}}>{D.payoffMonths>0?`${Math.floor(D.payoffMonths/12)} yrs ${D.payoffMonths%12} mos`:'debt-free'}</div></div>
        </div>
        <div style={{display:'flex',flexDirection:'column',gap:11}}>
          {D.debts.slice(0,4).map((d,i)=>(
            <div key={i}>
              <div className="cm-row" style={{justifyContent:'space-between',marginBottom:4}}><span className="t-label" style={{color:'var(--ink-900)'}}>{d.name}</span><span className="num" style={{fontSize:12,fontWeight:700}}>{usd0(d.balance)} <span style={{color:d.rate>15?RD:'var(--ink-400)',fontWeight:600}}>{d.rate.toFixed(1)}%</span></span></div>
              <MiniBar pct={d.balance/D.maxDebt*100} color={d.rate>15?RD:G}/>
            </div>
          ))}
        </div>
        <a className="t-link" style={{display:'inline-flex',alignItems:'center',gap:5,color:G,fontWeight:700,fontSize:12.5,marginTop:14}}>View payoff plan <I.ChevR size={14}/></a>
      </ChartCard>
    </div>
  );
}

/* ============================ FORECAST + PLANNED ============================ */
function PlannedList({ items, sign, color }) {
  return <div style={{display:'flex',flexDirection:'column'}}>
    {items.map((p,i)=>(
      <div className="cm-row" key={i} style={{gap:11,padding:'10px 0',borderBottom:i<items.length-1?'1px solid var(--line)':'none'}}>
        <span style={{width:34,height:34,flex:'0 0 34px',borderRadius:9,background:window.tintFor?window.tintFor(p.c):'var(--mint-50)',color:p.c,display:'flex',alignItems:'center',justifyContent:'center'}}>{I[p.icon]?React.createElement(I[p.icon],{size:16}):<I.Wallet size={16}/>}</span>
        <div style={{flex:1,minWidth:0}}><div className="t-label" style={{color:'var(--ink-900)'}}>{p.name}</div><div className="t-caption">{p.when}</div></div>
        <span className="num" style={{fontWeight:700,color:sign==='+'?G:'var(--ink-900)'}}>{sign}{usd0(p.amt)}</span>
      </div>
    ))}
  </div>;
}
function ForecastRow({ D }) {
  return (
    <div className="cm-grid-3 cm-mt-20" style={{gridTemplateColumns:'1.5fr 1fr 1fr'}}>
      <ChartCard>
        <div className="cm-card-head" style={{marginBottom:4}}><div className="title">Budget Forecast</div></div>
        <div className="t-caption" style={{marginBottom:8}}>12 Month Projection</div>
        <div className="an-legend" style={{marginBottom:6}}><span style={{color:FOREST}}><i style={{background:FOREST}}/>Income</span><span style={{color:GOLD}}><i style={{background:GOLD}}/>Expenses</span><span style={{color:TEAL}}><i style={{background:TEAL}}/>Surplus</span></div>
        {CashFlowChart ? <CashFlowChart data={D.cf12} height={230}/> : null}
        <div style={{display:'flex',gap:10,marginTop:12}}>
          <div className="bp-fcbox"><div className="t-caption">Projected Surplus</div><div className="num" style={{fontWeight:800,color:G,fontSize:17}}>{usd0(D.projSurplus12)}</div><div className="t-caption">Next 12 Months</div></div>
          <div className="bp-fcbox"><div className="t-caption">Highest Surplus</div><div className="num" style={{fontWeight:800,color:'var(--ink-900)',fontSize:17}}>{usd0(D.hiSurplus)}</div><div className="t-caption">{D.hiMo}</div></div>
          <div className="bp-fcbox"><div className="t-caption">Lowest Surplus</div><div className="num" style={{fontWeight:800,color:'var(--ink-900)',fontSize:17}}>{usd0(D.loSurplus)}</div><div className="t-caption">{D.loMo}</div></div>
        </div>
      </ChartCard>
      <ChartCard>
        <div className="cm-card-head" style={{marginBottom:10}}><div className="title">Planned Expenses</div><a className="t-link" style={{color:G,fontWeight:700,fontSize:12.5}}>View all</a></div>
        <PlannedList items={PLANNED_EXP} sign="" color={RD}/>
      </ChartCard>
      <ChartCard>
        <div className="cm-card-head" style={{marginBottom:10}}><div className="title">Planned Income</div><a className="t-link" style={{color:G,fontWeight:700,fontSize:12.5}}>View all</a></div>
        <PlannedList items={PLANNED_INC} sign="+" color={G}/>
      </ChartCard>
    </div>
  );
}

/* ============================ CALENDAR + WORKSPACE + ACTIONS + HEATMAP ============================ */
function BottomGrid({ D }) {
  const dows=['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
  const ws = [
    ['Income', D.income, G, false], ['Fixed Expenses', D.fixed, 'var(--ink-900)', false],
    ['Variable Expenses', D.variable, 'var(--ink-900)', false], ['Savings', D.toSavings, G, false],
    ['Investments', D.toInvest, BL, false], ['Debt Payments', D.toDebt, AM, false],
    ['Planned Expenses', D.planned, 'var(--ink-900)', false],
  ];
  const actions = [
    { t:'Create Budget', s:'Build a new budget from scratch', ic:'Plus' },
    { t:'Compare Budgets', s:'Compare actual vs previous months', ic:'Bars' },
    { t:'Duplicate Last Month', s:"Use last month's budget as a template", ic:'Repeat' },
    { t:'Review Subscriptions', s:'Manage and optimize subscriptions', ic:'Subscriptions' },
    { t:'Zero-Based Budget', s:'Every dollar has a purpose', ic:'Goals' },
  ];
  return (
    <div className="bp-bottom cm-mt-20">
      <ChartCard>
        <div className="cm-card-head" style={{marginBottom:12}}><div className="title">Financial Calendar</div><span className="t-caption" style={{fontWeight:700}}>{D.monthLabel}</span></div>
        <div className="bp-cal">
          {dows.map(d=><div key={d} className="bp-cal-dow">{d.slice(0,1)}</div>)}
          {D.calCells.map((c,i)=> c===null ? <div key={i}/> :
            <div key={i} className={`bp-cal-cell ${c.today?'today':''} ${c.bill?'bill':''}`} title={c.bill?`${c.bill.name} · ${usd0(c.bill.amt)}`:''}>{c.d}{c.bill&&<span className="bp-cal-dot"/>}</div>)}
        </div>
        <div style={{marginTop:12,paddingTop:10,borderTop:'1px solid var(--line)'}}>
          {D.calEvents.map((e,i)=>(
            <div className="cm-row" key={i} style={{gap:8,padding:'5px 0',fontSize:12}}>
              <span className="num" style={{color:'var(--ink-400)',minWidth:46}}>{D.today.toLocaleDateString('en-CA',{month:'short'})} {e.d}</span>
              <span style={{flex:1,fontWeight:600,color:'var(--ink-700)'}}>{e.name}</span>
              <span className="num" style={{fontWeight:700}}>{usd0(e.amount)}</span>
            </div>
          ))}
        </div>
      </ChartCard>

      <ChartCard>
        <div className="cm-card-head" style={{marginBottom:12}}><div className="title">Monthly Planning Workspace</div><a className="t-link" style={{color:G,fontWeight:700,fontSize:12}}>Edit Plan</a></div>
        <div className="t-caption" style={{marginBottom:8}}>{D.monthLabel}</div>
        <div>
          {ws.map((r,i)=>(
            <div className="cm-row" key={i} style={{justifyContent:'space-between',padding:'8px 0',borderBottom:'1px solid var(--line)'}}>
              <span className="t-label" style={{color:'var(--ink-700)'}}>{r[0]}</span>
              <span className="num" style={{fontWeight:700,color:r[2]}}>{r[0]==='Income'?'':'–'}{usd0(r[1])}</span>
            </div>
          ))}
          <div className="cm-row" style={{justifyContent:'space-between',padding:'10px 0 0'}}>
            <span className="t-label" style={{fontWeight:800,color:'var(--ink-900)'}}>Total Surplus</span>
            <span className="num" style={{fontWeight:800,color:G,fontSize:16}}>{usd0(D.surplus)}</span>
          </div>
        </div>
      </ChartCard>

      <ChartCard>
        <div className="title" style={{marginBottom:12}}>Quick Budget Actions</div>
        <div style={{display:'flex',flexDirection:'column',gap:8}}>
          {actions.map((a,i)=>(
            <div key={i} className="cm-row bp-action" style={{gap:11,padding:'10px 11px',borderRadius:10,cursor:'pointer'}}>
              <span style={{width:34,height:34,flex:'0 0 34px',borderRadius:9,background:'var(--mint-50)',color:G,display:'flex',alignItems:'center',justifyContent:'center'}}>{I[a.ic]?React.createElement(I[a.ic],{size:16}):<I.Plus size={16}/>}</span>
              <div style={{flex:1,minWidth:0}}><div className="t-label" style={{color:'var(--ink-900)'}}>{a.t}</div><div className="t-caption">{a.s}</div></div>
              <I.ChevR size={15} style={{color:'var(--ink-400)'}}/>
            </div>
          ))}
        </div>
      </ChartCard>

      <ChartCard>
        <div className="cm-card-head" style={{marginBottom:6}}><div className="title">Spending Heatmap</div></div>
        <div className="t-caption" style={{marginBottom:12}}>This Month</div>
        {Heatmap ? <Heatmap weeks={D.heat} color={FOREST}/> : null}
        <div className="cm-row" style={{justifyContent:'flex-end',gap:5,marginTop:12,fontSize:11,color:'var(--ink-400)',fontWeight:700}}>
          Less <i style={{width:11,height:11,borderRadius:3,background:'#E4ECE5'}}/><i style={{width:11,height:11,borderRadius:3,background:'#9DBFAC'}}/><i style={{width:11,height:11,borderRadius:3,background:'#4E8266'}}/><i style={{width:11,height:11,borderRadius:3,background:FOREST}}/> More
        </div>
      </ChartCard>
    </div>
  );
}

/* ============================ BOTTOM CTA ============================ */
function CtaBar() {
  const items = [
    { ic:'Goals', t:'Take control of your future', s:'Stay on track and reach your financial goals' },
    { ic:'Bars', t:'Track every dollar', s:'Know where your money goes' },
    { ic:'Shield', t:'Plan with confidence', s:'Build a better financial future' },
  ];
  return (
    <ChartCard className="cm-mt-20" style={{background:'var(--mint-50)'}}>
      <div style={{display:'flex',alignItems:'center',gap:24,flexWrap:'wrap'}}>
        <div style={{display:'flex',gap:28,flexWrap:'wrap',flex:1}}>
          {items.map((it,i)=>(
            <div className="cm-row" key={i} style={{gap:11}}>
              <span style={{width:38,height:38,flex:'0 0 38px',borderRadius:10,background:'var(--mint-100)',color:G,display:'flex',alignItems:'center',justifyContent:'center'}}>{I[it.ic]?React.createElement(I[it.ic],{size:18}):<I.Goals size={18}/>}</span>
              <div><div className="t-label" style={{color:'var(--ink-900)'}}>{it.t}</div><div className="t-caption">{it.s}</div></div>
            </div>
          ))}
        </div>
        <a href="#/goals" className="cm-btn cm-btn-primary" style={{flex:'0 0 auto',textDecoration:'none'}}><I.Goals size={16}/>View My Goals</a>
      </div>
    </ChartCard>
  );
}

/* ============================ PAGE ============================ */
function PageBudget() {
  const CM = window.useStore ? window.useStore() : window.CM;
  const D = derive(CM);
  return (
    <div>
      <KpiStrip D={D}/>
      <CashFlowSection D={D}/>
      <BudgetCategoryRow D={D}/>
      <PlannerRow D={D}/>
      <ForecastRow D={D}/>
      <BottomGrid D={D}/>
      <CtaBar/>
    </div>
  );
}
window.PageBudget = PageBudget;
})();
