/* Clear Mint — Money pages: Bills, Subscriptions, Goals (wired to engine).
   Investments here is overridden by cm-pages-investments.jsx (kept as fallback). */
const { MetricCard, ChartCard, DataTable, DonutChart, TrendChart, ProgressBar, Legend } = window;
const { KpiRow, ChangeCell, StatusPill, ActivityList, Tabs, CMC } = window;
const Im = window.CMIcon;
const { G, PU, AM, BL, SL, RD, TEAL, PINK, INDIGO } = CMC;

const MCATICON = { Housing:<Im.House size={18}/>, Utilities:<Im.Bolt size={18}/>, Insurance:<Im.Shield size={18}/>,
  'Credit Card Payment':<Im.Card size={18}/>, Kids:<Im.Heart size={18}/>, 'Food & Dining':<Im.Dining size={18}/>,
  Transportation:<Im.Transport size={18}/>, Subscriptions:<Im.Repeat size={18}/>, Debt:<Im.Card size={18}/>, Other:<Im.Wallet size={18}/> };
function mcatIcon(c){ return MCATICON[c] || <Im.Wallet size={18}/>; }

/* ============================ BILLS & EXPENSES ============================ */
function BField({ label, children, full }){
  return <div style={full?{gridColumn:'1 / -1'}:undefined}><div style={{fontSize:11,fontWeight:700,letterSpacing:'.06em',textTransform:'uppercase',color:'var(--ink-400)',margin:'0 0 5px'}}>{label}</div>{children}</div>;
}
const BILL_CATS=['Housing','Utilities','Insurance','Debt','Food & Dining','Transportation','Subscriptions','Kids','Healthcare','Other'];
const BILL_REC=['One-time','Weekly','Biweekly','Monthly','Quarterly','Yearly'];
function BillModal({ CM, idx, oneTime, onClose }){
  const adding = idx==null||idx<0;
  const b = adding?{}:((CM.S.bills||[])[idx]||{});
  const dval = v => (typeof v==='string'&&/^\d{4}-\d{2}-\d{2}/.test(v))?v.slice(0,10):'';
  const [f,setF]=React.useState(()=>({ name:b.desc||b.name||'', cat:b.cat||'Utilities', amount:b.amount!=null?String(b.amount):'', dueDate:dval(b.dueDate), recur:b.recur||(oneTime?'One-time':'Monthly'), account:b.account||'', autopay:!!b.autopay, notes:b.notes||'' }));
  const isRecur = !/one.?time/i.test(String(f.recur));
  const isRecurEdit = !adding && isRecur;            // only recurring edits can fan out to future months
  const [applyFuture,setApplyFuture]=React.useState(true);
  const set=k=>ev=>{ const v=ev.target.type==='checkbox'?ev.target.checked:ev.target.value; setF(s=>({...s,[k]:v})); };
  const inp={width:'100%',fontFamily:'inherit',fontSize:13.5,color:'var(--ink-900)',border:'1px solid var(--line)',borderRadius:10,padding:'9px 11px',background:'#fff',outline:'none',boxSizing:'border-box'};
  const save=()=>{ const rec={ desc:f.name||'Bill', name:f.name||'Bill', cat:f.cat, amount:parseFloat(f.amount)||0, dueDate:f.dueDate||null, recur:f.recur, account:f.account||'', autopay:!!f.autopay, notes:f.notes||'' };
    if(adding){ rec.paid=false; CM.mutate(function(){ (CM.S.bills=CM.S.bills||[]).push(rec); });
      try{ window.CMrecurring && window.CMrecurring.generateProjections && window.CMrecurring.generateProjections(); }catch(e){}
    } else if(window.cmSeriesEdit){
      const changes={ desc:rec.desc, name:rec.name, cat:rec.cat, amount:rec.amount, dueDate:rec.dueDate, recur:rec.recur, account:rec.account, autopay:rec.autopay, notes:rec.notes };
      window.cmSeriesEdit('bills', idx, changes, isRecurEdit && applyFuture);
    } else { rec.paid=!!b.paid; CM.mutate(function(){ Object.assign(CM.S.bills[idx], rec); });
      try{ window.CMrecurring && window.CMrecurring.generateProjections && window.CMrecurring.generateProjections(); }catch(e){} }
    try{ CM.logActivity&&CM.logActivity(adding?'added a bill':'updated a bill', rec.desc, {cat:'bills'}); }catch(e){}
    onClose(); };
  const del=()=>{ if(adding){ onClose(); return; } if(!window.confirm('Delete "'+(b.desc||b.name||'this bill')+'"?')) return; CM.mutate(function(){ CM.S.bills.splice(idx,1); }); onClose(); };
  return (<div onClick={onClose} style={{position:'fixed',inset:0,zIndex:1000,background:'rgba(13,33,26,.45)',display:'flex',alignItems:'center',justifyContent:'center',padding:20}}>
    <div onClick={ev=>ev.stopPropagation()} className="cm-card" style={{width:560,maxWidth:'100%',maxHeight:'92vh',overflowY:'auto',borderRadius:18,padding:'22px 24px',boxShadow:'0 24px 64px rgba(13,42,33,.28)'}}>
      <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:4}}><div className="t-h2" style={{fontSize:18}}>{adding?'Add Bill / Expense':'Edit Bill'}</div><button onClick={onClose} aria-label="Close" style={{border:0,background:'none',cursor:'pointer',color:'var(--ink-400)',fontSize:20,lineHeight:1,padding:4}}>×</button></div>
      <div className="t-caption" style={{marginBottom:16}}>{adding?'Add a recurring bill or one-time expense.':'Update this bill — changes apply everywhere.'}</div>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:14}}>
        <BField label="Name" full={true}><input style={inp} value={f.name} onChange={set('name')} placeholder="e.g. Hydro One"/></BField>
        <BField label="Category"><select style={inp} value={f.cat} onChange={set('cat')}>{BILL_CATS.map(c=><option key={c} value={c}>{c}</option>)}</select></BField>
        <BField label="Amount ($)"><input style={inp} type="number" value={f.amount} onChange={set('amount')}/></BField>
        <BField label="Due Date"><input style={inp} type="date" value={f.dueDate} onChange={set('dueDate')}/></BField>
        <BField label="Recurrence"><select style={inp} value={f.recur} onChange={set('recur')}>{BILL_REC.map(c=><option key={c} value={c}>{c}</option>)}</select></BField>
        <BField label="Account"><input style={inp} value={f.account} onChange={set('account')} placeholder="e.g. TD Chequing"/></BField>
        <BField label="Auto-pay"><label style={{display:'flex',alignItems:'center',gap:8,fontSize:13.5,color:'var(--ink-700)',padding:'9px 0'}}><input type="checkbox" checked={f.autopay} onChange={set('autopay')} style={{width:16,height:16}}/>Paid automatically</label></BField>
        <BField label="Notes" full={true}><textarea style={{...inp,minHeight:56,resize:'vertical'}} value={f.notes} onChange={set('notes')}/></BField>
      </div>
      {isRecurEdit && <label style={{display:'flex',gap:9,alignItems:'flex-start',marginTop:16,padding:'11px 13px',background:'var(--mint-50)',border:'1px solid var(--line)',borderRadius:11,cursor:'pointer'}}>
        <input type="checkbox" checked={applyFuture} onChange={e=>setApplyFuture(e.target.checked)} style={{width:16,height:16,marginTop:1}}/>
        <span style={{fontSize:13,color:'var(--ink-700)',lineHeight:1.4}}><b style={{color:'var(--ink-900)'}}>Apply to all future occurrences</b><br/>Update every upcoming month of this bill — amount, name, category and more. Leave unchecked to change only this month.</span>
      </label>}
      <div style={{display:'flex',gap:10,marginTop:20,alignItems:'center'}}>{!adding&&<button className="cm-btn cm-btn-ghost" style={{color:'var(--red-500)'}} onClick={del}>Delete</button>}<div style={{flex:1}}></div><button className="cm-btn cm-btn-soft" onClick={onClose}>Cancel</button><button className="cm-btn cm-btn-primary" onClick={save}>{adding?'Add Bill':'Save Changes'}</button></div>
    </div></div>);
}
window.addBillPrompt = function(){ try{ window.dispatchEvent(new CustomEvent('cm-add-bill')); }catch(e){} };
function PageBills() {
  const CM = window.useStore ? window.useStore() : window.CM;
  const fmt = CM.M, fmt0 = CM.M0;
  const monthKey = ()=>{ var n=new Date(); return n.getFullYear()+'-'+String(n.getMonth()+1).padStart(2,'0'); };
  const [tab, setTab] = React.useState('All Bills');
  const [period, setPeriod] = React.useState(monthKey()); // start in the current month (matches Earnings)
  const [bModal, setBModal] = React.useState(null);
  React.useEffect(()=>{ const h=()=>setBModal({idx:-1}); window.addEventListener('cm-add-bill',h); return ()=>window.removeEventListener('cm-add-bill',h); },[]);
  const navLabel = /^\d{4}-\d{2}$/.test(period)? new Date(period+'-01T00:00').toLocaleDateString('en-US',{month:'long',year:'numeric'}) : 'All Periods';
  const shiftMonth=(d)=>{ var k=(/^\d{4}-\d{2}$/.test(period)?period:monthKey()).split('-'); var y=+k[0],m=+k[1]+d; while(m<1){m+=12;y--;} while(m>12){m-=12;y++;} setPeriod(y+'-'+String(m).padStart(2,'0')); };
  // Recurring bills and one-time expenses share CM.S.bills — split by the recur field into two sub-tabs.
  const [section,setSection]=React.useState('Recurring Bills');
  const isRecurring = b => b.recur && !/one.?time/i.test(String(b.recur));
  const allRows = (CM.S.bills||[]).map(function(b,i){ return Object.assign({_i:i}, b); });
  const periodLabel = window.cmPeriodLabel?window.cmPeriodLabel(period):navLabel;
  const inPer = (b)=> !window.cmInPeriod || window.cmInPeriod(b.dueDate||b.date, period);
  // — recurring bills —
  const bills = allRows.filter(isRecurring);
  const billsP = bills.filter(inPer);
  const dueThis = billsP.filter(b=>!b.paid);
  const paid = billsP.filter(b=>b.paid);
  const totalDue = dueThis.reduce((s,b)=>s+(+b.amount||0),0);
  const totalPaid = paid.reduce((s,b)=>s+(+b.amount||0),0);
  const autopay = billsP.filter(b=>b.autopay||/auto/i.test(b.recur||''));
  const filtered = (tab==='All Bills'?billsP : tab==='Paid'?paid : tab==='Autopay'?autopay : dueThis);
  // — one-time expenses —
  const oneTime = allRows.filter(b=>!isRecurring(b));
  const oneTimeP = oneTime.filter(inPer);
  const oneTimeTotal = oneTimeP.reduce((s,b)=>s+(+b.amount||0),0);
  const oneTimeLargest = oneTimeP.reduce((m,b)=>Math.max(m,+b.amount||0),0);
  const oneTimePaid = oneTimeP.filter(b=>b.paid).length;
  const pill = b => b.paid?<StatusPill tone="green" icon={<Im.Check size={12}/>}>Paid</StatusPill>
    : (b.autopay?<StatusPill tone="blue" icon={<Im.Repeat size={12}/>}>Autopay</StatusPill>
    : <StatusPill tone="amber" icon={<Im.Clock size={12}/>}>Upcoming</StatusPill>);
  const togglePaid = (i)=> CM.mutate(function(){ var b=CM.S.bills[i]; if(b) b.paid=!b.paid; });
  const editBill = (i)=>{ if(i<0||i>=(CM.S.bills||[]).length) return; setBModal({idx:i}); };
  const delBill = (i)=>{ var b=CM.S.bills[i]; if(!b) return; if(!window.confirm('Delete "'+(b.desc||b.name)+'"?')) return; CM.mutate(function(){ CM.S.bills.splice(i,1); }); };
  const cols = [
    {header:'Bill', cell:r=><DataTable.Lead thumb={window.BrandIcon ? <window.BrandIcon name={r.desc||r.name} size={36} radius={9}/> : <span style={{color:CM.catColor(r.cat)}}>{mcatIcon(r.cat)}</span>} primary={r.desc||r.name} sub={r.cat||'Other'}/>},
    {header:'Recurrence', cell:r=><span className="cm-cell-meta" style={{fontSize:13,color:'var(--ink-500)',fontWeight:600}}>{r.recur||'Monthly'}</span>},
    {header:'Amount', cell:r=><span className="cm-cell-strong num">{fmt(r.amount)}</span>},
    {header:'Due Date', cell:r=><span className="cm-cell-meta num" style={{fontSize:13,color:'var(--ink-500)'}}>{r.dueDate?CM.FD(new Date(r.dueDate)):'—'}</span>},
    {header:'Status', cell:r=>pill(r)},
    {header:'', align:'right', cell:r=><span style={{display:'inline-flex',gap:12,whiteSpace:'nowrap'}}>
      <a className="t-label text-green" style={{cursor:'pointer'}} onClick={()=>togglePaid(r._i)}>{r.paid?'Unpay':'Mark paid'}</a>
      <a className="t-label" style={{cursor:'pointer',color:'var(--ink-500)'}} onClick={()=>editBill(r._i)}>Edit</a>
      <a className="t-label" style={{cursor:'pointer',color:'var(--red-500)'}} onClick={()=>delBill(r._i)}>Delete</a></span>},
  ];
  const oneCols = [
    {header:'Expense', cell:r=><DataTable.Lead thumb={window.BrandIcon ? <window.BrandIcon name={r.desc||r.name} size={36} radius={9}/> : <span style={{color:CM.catColor(r.cat)}}>{mcatIcon(r.cat)}</span>} primary={r.desc||r.name} sub={r.cat||'Other'}/>},
    {header:'Amount', cell:r=><span className="cm-cell-strong num">{fmt(r.amount)}</span>},
    {header:'Date', cell:r=><span className="cm-cell-meta num" style={{fontSize:13,color:'var(--ink-500)'}}>{(r.dueDate||r.date)?CM.FD(new Date(r.dueDate||r.date)):'—'}</span>},
    {header:'Status', cell:r=>pill(r)},
    {header:'', align:'right', cell:r=><span style={{display:'inline-flex',gap:12,whiteSpace:'nowrap'}}>
      <a className="t-label text-green" style={{cursor:'pointer'}} onClick={()=>togglePaid(r._i)}>{r.paid?'Unpay':'Mark paid'}</a>
      <a className="t-label" style={{cursor:'pointer',color:'var(--ink-500)'}} onClick={()=>editBill(r._i)}>Edit</a>
      <a className="t-label" style={{cursor:'pointer',color:'var(--red-500)'}} onClick={()=>delBill(r._i)}>Delete</a></span>},
  ];
  return (
    <div>
      {/* Sub-tabs: recurring bills vs one-time expenses */}
      <div style={{display:'flex',justifyContent:'center',marginBottom:14}}>
        <div className="cm-seg">
          {['Recurring Bills','One-Time Expenses'].map(t=><button key={t} type="button" className={t===section?'active':''} onClick={()=>setSection(t)}>{t}</button>)}
        </div>
      </div>
      {/* Month stepper + period filter — mirrors the Earnings tab. */}
      <div style={{display:'grid',gridTemplateColumns:'1fr auto 1fr',alignItems:'center',gap:12,marginBottom:14}}>
        <div/>
        <div style={{display:'inline-flex',alignItems:'center',gap:8,justifySelf:'center',background:'#fff',border:'1px solid var(--line)',borderRadius:12,padding:'6px 8px'}}>
          <button onClick={()=>shiftMonth(-1)} aria-label="Previous month" style={{border:0,background:'var(--mint-50)',width:30,height:30,borderRadius:8,cursor:'pointer',fontSize:18,lineHeight:1,color:'var(--green-600)'}}>‹</button>
          <div style={{minWidth:140,textAlign:'center',fontWeight:700,fontSize:14,color:'var(--ink-900)'}}>{navLabel}</div>
          <button onClick={()=>shiftMonth(1)} aria-label="Next month" style={{border:0,background:'var(--mint-50)',width:30,height:30,borderRadius:8,cursor:'pointer',fontSize:18,lineHeight:1,color:'var(--green-600)'}}>›</button>
        </div>
        <div style={{justifySelf:'end'}}>{window.PeriodBar ? <window.PeriodBar value={period} onChange={setPeriod}/> : null}</div>
      </div>
      {section==='Recurring Bills' ? (
        <React.Fragment>
          <KpiRow>
            <MetricCard label="Outstanding" labelColor="var(--red-500)" value={fmt0(totalDue)} sub={dueThis.length+' bill'+(dueThis.length!==1?'s':'')+' · '+periodLabel}/>
            <MetricCard label="Paid" labelColor="var(--green-600)" value={fmt0(totalPaid)} sub={paid.length+' of '+billsP.length}/>
            <MetricCard label="Recurring / month" value={fmt0(totalDue+totalPaid)} sub={periodLabel}/>
          </KpiRow>
          <ChartCard title="Recurring Bills" action={<button className="cm-btn cm-btn-ghost" onClick={()=>setBModal({idx:-1})}><Im.Plus size={16}/>Add Bill</button>}>
            <div style={{display:'flex',justifyContent:'space-between',alignItems:'center',gap:10,flexWrap:'wrap'}}><Tabs tabs={['All Bills','Upcoming','Paid','Autopay']} value={tab} onChange={setTab}/><span className="t-caption">{periodLabel}</span></div>
            <div style={{height:18}}/>
            {filtered.length?<DataTable columns={cols} rows={filtered} minWidth={720}/>:<div className="t-caption" style={{textAlign:'center',padding:'30px 0'}}>No recurring bills in {periodLabel}.</div>}
          </ChartCard>
        </React.Fragment>
      ) : (
        <React.Fragment>
          <KpiRow>
            <MetricCard label="Total Spent" labelColor="var(--red-500)" value={fmt0(oneTimeTotal)} sub={oneTimeP.length+' expense'+(oneTimeP.length!==1?'s':'')+' · '+periodLabel}/>
            <MetricCard label="Largest" value={fmt0(oneTimeLargest)} sub={periodLabel}/>
            <MetricCard label="Marked Paid" labelColor="var(--green-600)" value={oneTimePaid+' of '+oneTimeP.length} sub="this period"/>
          </KpiRow>
          <ChartCard title="One-Time Expenses" action={<button className="cm-btn cm-btn-ghost" onClick={()=>setBModal({idx:-1,oneTime:true})}><Im.Plus size={16}/>Add Expense</button>}>
            <div style={{display:'flex',justifyContent:'flex-end',alignItems:'center'}}><span className="t-caption">{periodLabel}</span></div>
            <div style={{height:18}}/>
            {oneTimeP.length?<DataTable columns={oneCols} rows={oneTimeP} minWidth={680}/>:<div className="t-caption" style={{textAlign:'center',padding:'30px 0'}}>No one-time expenses in {periodLabel}. Use “Add Expense” to record a single charge.</div>}
          </ChartCard>
        </React.Fragment>
      )}
      {bModal!=null && <BillModal CM={CM} idx={bModal.idx} oneTime={bModal.oneTime} onClose={()=>setBModal(null)}/>}
    </div>
  );
}
window.PageBills = PageBills;

/* ============================ SUBSCRIPTIONS ============================ */
function moCost(s){ var p=+s.price||0; switch(String(s.freq||'Monthly')){ case 'Annual':return p/12; case 'Bi-Annual':return p/24; case 'Quarterly':return p/3; case 'Semi-Annual':return p/6; case 'Weekly':return p*52/12; case 'Bi-Weekly':return p*26/12; default:return p; } }
function addSubPrompt(){
  const name = window.prompt('Subscription name (e.g. Netflix)'); if(!name) return;
  const price = parseFloat(window.prompt('Price','0'))||0;
  const cat = window.prompt('Category (Streaming / Music / Software / Fitness / Shopping / Other)','Streaming')||'Other';
  window.CM.mutate(function(){ window.S.subscriptions.push({ name:name, price:price, freq:'Monthly', active:true, cat:cat, color:'#3ECF8E', initials:name.slice(0,2).toUpperCase() }); });
}
function PageSubscriptions() {
  const CM = window.useStore ? window.useStore() : window.CM;
  const BrandIcon = window.BrandIcon, fmt = CM.M;
  const subs = (CM.S.subscriptions||[]).filter(s=>s.active!==false);
  const monthly = subs.reduce((s,x)=>s+moCost(x),0);
  const byCat = {};
  subs.forEach(s=>{ var c=s.cat||'Other'; byCat[c]=(byCat[c]||0)+moCost(s); });
  const catPalette = [BL,PINK,RD,AM,G,PU,TEAL,INDIGO];
  const catArr = Object.keys(byCat).map((c,i)=>({label:c,value:byCat[c],color:catPalette[i%catPalette.length]})).sort((a,b)=>b.value-a.value);
  const cols = [
    {header:'Service', cell:r=>(<div className="cm-cell-lead"><BrandIcon name={r.name} size={38} radius={9}/><div><div className="cm-cell-primary">{r.name}</div><div className="cm-cell-sub">{r.cat||''}</div></div></div>)},
    {header:'Billing', cell:r=><span className="cm-cell-meta" style={{fontSize:13,color:'var(--ink-500)',fontWeight:600}}>{r.freq||'Monthly'}</span>},
    {header:'Monthly', cell:r=><span className="cm-cell-meta num" style={{fontSize:13,color:'var(--ink-500)'}}>{fmt(moCost(r))}</span>},
    {header:'Cost', align:'right', cell:r=><span className="cm-cell-strong num">{fmt(r.price)}</span>},
  ];
  return (
    <div>
      <KpiRow>
        <MetricCard label="Monthly Total" labelColor="var(--green-600)" value={fmt(monthly)} sub="normalized"/>
        <MetricCard label="Active" value={String(subs.length)} sub="subscriptions"/>
        <MetricCard label="Annual Cost" value={CM.M0(monthly*12)} sub="projected"/>
        <MetricCard label="Categories" value={String(catArr.length)} sub="tracked"/>
      </KpiRow>
      <div className="cm-grid-2a">
        <ChartCard title="Subscriptions" action={<button className="cm-btn cm-btn-ghost" onClick={addSubPrompt}><Im.Plus size={16}/>Add</button>}>
          {subs.length?<DataTable columns={cols} rows={subs} minWidth={620}/>:<div className="t-caption" style={{textAlign:'center',padding:'30px 0'}}>No subscriptions yet.</div>}
        </ChartCard>
        <div className="cm-stack">
          <ChartCard title="By Category">
            <div className="cm-donut-card" style={{justifyContent:'center'}}>
              <DonutChart size={150} thickness={20} center={{value:CM.M0(monthly),label:'/ month'}} segments={catArr}/>
            </div>
            <div style={{marginTop:14}}><Legend items={catArr.map(c=>({color:c.color,label:c.label,pct:Math.round(c.value/(monthly||1)*100)+'%',value:fmt(c.value)}))}/></div>
          </ChartCard>
        </div>
      </div>
    </div>
  );
}
window.PageSubscriptions = PageSubscriptions;

/* ============================ GOALS ============================ */
function addGoalPrompt(){
  const name = window.prompt('Goal name (e.g. Dream Vacation)'); if(!name) return;
  const target = parseFloat(window.prompt('Target amount','10000'))||0;
  const saved = parseFloat(window.prompt('Saved so far','0'))||0;
  window.CM.mutate(function(){ window.S.goals.push({ name:name, target:target, saved:saved, color:'#1B5E4A', cat:'Goal' }); });
}
function PageGoals() {
  const CM = window.useStore ? window.useStore() : window.CM;
  const fmt0 = CM.M0;
  const goals = (CM.S.goals||[]).map(g=>Object.assign({pct:Math.min(100,Math.round((+g.saved||0)/(+g.target||1)*100))}, g));
  const totalSaved = goals.reduce((s,g)=>s+(+g.saved||0),0);
  const totalTarget = goals.reduce((s,g)=>s+(+g.target||0),0);
  const onTrack = goals.filter(g=>g.pct>=40).length;
  const avg = goals.length?Math.round(goals.reduce((s,g)=>s+g.pct,0)/goals.length):0;
  const ICONS=[<Im.Shield size={20}/>,<Im.Plane size={20}/>,<Im.House size={20}/>,<Im.Goals size={20}/>,<Im.User size={20}/>,<Im.Grow size={20}/>];
  return (
    <div>
      <KpiRow>
        <MetricCard label="Total Saved" labelColor="var(--green-600)" value={fmt0(totalSaved)} sub="across all goals"/>
        <MetricCard label="On Track" value={onTrack+' of '+goals.length} sub="goals"/>
        <MetricCard label="Total Target" value={fmt0(totalTarget)} sub="combined"/>
        <MetricCard label="Avg Progress" labelColor="var(--green-600)" value={avg+'%'} sub="completion"/>
      </KpiRow>
      <div className="cm-grid-3">
        {goals.map((g,i)=>{
          const c = g.color||G;
          return (
            <div className="cm-tile" key={i}>
              <div className="cm-tile-head">
                <span className="cm-tile-ic" style={{background:window.tintFor(c),color:c}}>{ICONS[i%ICONS.length]}</span>
                <div style={{flex:1,minWidth:0}}>
                  <div className="t-h2" style={{fontSize:16}}>{g.name}</div>
                  <div className="t-caption">{g.deadline?('Target '+CM.FD(new Date(g.deadline))):(g.cat||'Goal')}</div>
                </div>
                {g.pct>=40 ? <StatusPill tone="green">On track</StatusPill> : <StatusPill tone="amber">Behind</StatusPill>}
              </div>
              <div style={{display:'flex',alignItems:'baseline',justifyContent:'space-between',marginBottom:8}}>
                <span className="num" style={{fontSize:22,fontWeight:800,color:'var(--ink-900)'}}>{fmt0(g.saved)}</span>
                <span className="t-caption num">of {fmt0(g.target)}</span>
              </div>
              <ProgressBar pct={g.pct} color={c}/>
              <div style={{display:'flex',justifyContent:'space-between',marginTop:14,paddingTop:14,borderTop:'1px solid var(--line)'}}>
                <div className="cm-ministat"><div className="v num">{g.pct}%</div><div className="k">Complete</div></div>
                <div className="cm-ministat" style={{textAlign:'right'}}><div className="v num">{fmt0((+g.target||0)-(+g.saved||0))}</div><div className="k">Remaining</div></div>
              </div>
            </div>
          );
        })}
        <div className="cm-tile" style={{display:'flex',alignItems:'center',justifyContent:'center',cursor:'pointer',borderStyle:'dashed'}} onClick={addGoalPrompt}>
          <div style={{textAlign:'center',color:'var(--green-600)'}}><Im.Plus size={24}/><div className="t-h3" style={{marginTop:6,color:'var(--green-600)'}}>New Goal</div></div>
        </div>
      </div>
    </div>
  );
}
window.PageGoals = PageGoals;

/* ============================ INVESTMENTS (fallback; overridden) ============================ */
function PageInvestments() {
  const CM = window.useStore ? window.useStore() : window.CM;
  const fmt = CM.M0;
  const invs = CM.S.investments||[];
  const total = CM.calcInvestValue();
  const cost = invs.reduce((s,i)=>s+(+i.costBasis||0),0);
  const gain = total-cost;
  const cols = [
    {header:'Holding', cell:r=><DataTable.Lead thumb={<span style={{color:(CM.INV_COLORS&&CM.INV_COLORS[r.type])||G}}><Im.Investments size={18}/></span>} primary={r.symbol||r.name} sub={r.name}/>},
    {header:'Shares', cell:r=><span className="cm-cell-meta num">{r.shares}</span>},
    {header:'Price', cell:r=><span className="cm-cell-strong num">{CM.M(r.currentPrice)}</span>},
    {header:'Market Value', cell:r=><span className="cm-cell-strong num">{fmt(r.marketValue!=null?r.marketValue:(+r.shares||0)*(+r.currentPrice||0))}</span>},
  ];
  return (
    <div>
      <KpiRow>
        <MetricCard label="Portfolio Value" labelColor="var(--green-600)" value={fmt(total)} sub={invs.length+' holdings'}/>
        <MetricCard label="Total Cost" value={fmt(cost)} sub="invested"/>
        <MetricCard label="Total Gain" labelColor={gain>=0?'var(--green-600)':'var(--red-500)'} value={(gain>=0?'+':'-')+fmt(Math.abs(gain)).slice(1)} sub={cost?Math.round(gain/cost*100)+'%':''}/>
        <MetricCard label="Holdings" value={String(invs.length)} sub="positions"/>
      </KpiRow>
      <ChartCard title="Holdings">
        {invs.length?<DataTable columns={cols} rows={invs} minWidth={720}/>:<div className="t-caption" style={{textAlign:'center',padding:'30px 0'}}>No holdings yet.</div>}
      </ChartCard>
    </div>
  );
}
window.PageInvestments = PageInvestments;
