/* Clear Mint — Financial Outlook (future forecasting & planning).
   Separate from Cash Flow (which is current/historical). 10 tabs, wired to real
   CM.S data: earnings, bills, subscriptions, cards, accounts, goals, investments,
   liabilities. Planned Expenses persist in localStorage (cm_planned_expenses). */
(function(){
const { MetricCard, ChartCard, DonutChart, TrendChart, ProgressBar, Legend, KpiRow, StatusPill, CategoryBar, Tabs } = window;
const CMC = window.CMC || {};
const G=CMC.G||'#10915F', BL=CMC.BL||'#3E7CC4', RD=CMC.RD||'#C35B5B', AM=CMC.AM||'#C99A2E', PU=CMC.PU||'#8A6E9E', TEAL=CMC.TEAL||'#0E9F8E', SL=CMC.SL||'#94A29B', PINK=CMC.PINK||'#C56B86';
const GOLD='#C99A2E';
const I = window.CMIcon || {};

const M0 = n => (n<0?'-':'')+'$'+Math.abs(Math.round(+n||0)).toLocaleString('en-US');
const M2 = n => (n<0?'-':'')+'$'+Math.abs(+n||0).toLocaleString('en-US',{minimumFractionDigits:2,maximumFractionDigits:2});
const clamp=(v,a,b)=>Math.max(a,Math.min(b,v));
const pad2=n=>(n<10?'0':'')+n;
const isoOf=d=>{ d=new Date(d); return d.getFullYear()+'-'+pad2(d.getMonth()+1)+'-'+pad2(d.getDate()); };
const FD=d=>{ var t=window.CM&&window.CM.toTs?window.CM.toTs(d):new Date(d).getTime(); return (t&&!isNaN(t))?new Date(t).toLocaleDateString('en-CA',{month:'short',day:'numeric',year:'numeric'}):'—'; };
const FDshort=d=>{ var t=window.CM&&window.CM.toTs?window.CM.toTs(d):new Date(d).getTime(); return (t&&!isNaN(t))?new Date(t).toLocaleDateString('en-US',{month:'short',day:'numeric'}):'—'; };

function moAmt(amount, recur){
  amount=+amount||0; var r=String(recur||'monthly').toLowerCase();
  if(/one.?time|once/.test(r)) return 0;
  if(/biweek|bi.?week|every other/.test(r)) return amount*26/12;
  if(/week/.test(r)) return amount*52/12;
  if(/semi.?month|twice/.test(r)) return amount*2;
  if(/quarter/.test(r)) return amount/3;
  if(/year|annual/.test(r)) return amount/12;
  return amount;
}
function subMonthly(s){ var p=+(s.price||s.amount||0); return /year|annual/i.test(String(s.freq||s.cycle||''))?p/12:p; }

function Section({ title, sub, children, action }){
  return <ChartCard title={title} action={action} className="cm-mb-24">
    {sub?<div className="t-caption" style={{marginTop:-6,marginBottom:14}}>{sub}</div>:null}
    {children}
  </ChartCard>;
}
function Pill({ tone, children }){ return <StatusPill tone={tone}>{children}</StatusPill>; }
function Empty({ children }){ return <div className="t-caption" style={{textAlign:'center',padding:'30px 0'}}>{children}</div>; }

/* simple forecasted-balance area line */
function BalanceLine({ data, fmt }){
  var R=React, n=data.length; if(!n) return null;
  var H=240, W=Math.max(560, n*60+60), padL=60, padR=16, padT=16, padB=34, ih=H-padT-padB;
  var vals=data.map(d=>d.bal), mn=Math.min.apply(null,vals.concat([0])), mx=Math.max.apply(null,vals.concat([0]));
  var span=(mx-mn)||1, y=v=>padT+(mx-v)/span*ih, x=i=>padL+(n<=1?0:i*(W-padL-padR)/(n-1));
  var els=[];
  for(var g=0;g<=4;g++){ var gy=padT+ih*g/4, gv=mx-span*g/4; els.push(R.createElement('line',{key:'g'+g,x1:padL,x2:W-padR,y1:gy,y2:gy,stroke:'#EFEAE0',strokeWidth:1})); els.push(R.createElement('text',{key:'t'+g,x:padL-8,y:gy+3,textAnchor:'end',fontSize:10,fill:'#98A39B'},fmt(Math.round(gv)))); }
  if(mn<0){ var zy=y(0); els.push(R.createElement('line',{key:'z',x1:padL,x2:W-padR,y1:zy,y2:zy,stroke:'#E0655F',strokeDasharray:'4 4',strokeWidth:1})); }
  var path=data.map((d,i)=>(i?'L':'M')+x(i).toFixed(1)+' '+y(d.bal).toFixed(1)).join(' ');
  var area=path+' L'+x(n-1).toFixed(1)+' '+(padT+ih)+' L'+padL+' '+(padT+ih)+' Z';
  els.push(R.createElement('path',{key:'ar',d:area,fill:'rgba(16,145,95,.10)'}));
  els.push(R.createElement('path',{key:'ln',d:path,fill:'none',stroke:G,strokeWidth:2.5,strokeLinejoin:'round'}));
  data.forEach((d,i)=>{ els.push(R.createElement('circle',{key:'c'+i,cx:x(i),cy:y(d.bal),r:3,fill:G},R.createElement('title',null,d.label+' · '+fmt(d.bal)))); els.push(R.createElement('text',{key:'x'+i,x:x(i),y:H-12,textAnchor:'middle',fontSize:10,fill:'#98A39B'},d.label)); });
  return R.createElement('svg',{viewBox:'0 0 '+W+' '+H,width:W,height:H,style:{fontFamily:'inherit'},preserveAspectRatio:'xMinYMid meet'},els);
}

function PageFinancialOutlook(){
  const CM = window.useStore ? window.useStore() : window.CM;
  const S = CM.S;
  const today = CM.today ? CM.today() : new Date();
  const today0 = new Date(today.getFullYear(),today.getMonth(),today.getDate()).getTime();
  const [tab,setTab] = React.useState('Overview');
  const TABS=['Overview','Income Forecast','Recurring Bills Forecast','Planned Expenses','Forecast Calendar','Future Cash Flow','Savings Opportunities','Goal Forecasting','Scenario Planning','AI Outlook'];

  // ---- foundation ----
  const TRANSFER={'Transfer':1,'Credit Card Payment':1,'Savings':1};
  const startBal = (S.accounts||[]).reduce((s,a)=>s+(+a.balance||0),0) || (CM.totalCash?CM.totalCash():0);
  const moIncome = Math.round(CM.monthlyIncome ? CM.monthlyIncome() : (S.earnings||[]).reduce((s,e)=>s+moAmt(e.amount,e.recur),0));
  const _seenBill={};
  const moBills = Math.round((S.bills||[]).reduce((s,b)=>{ if(b.paid) return s; var key=(b.desc||b.name||'Bill')+'|'+(+b.amount||0); if(_seenBill[key]) return s; _seenBill[key]=1; return s+moAmt(b.amount,b.recur); },0));
  const moSubs = Math.round((S.subscriptions||[]).filter(s=>s.active!==false).reduce((s,x)=>s+subMonthly(x),0));
  const debits90 = (S.bankTx||[]).filter(r=>r.dr>0 && !TRANSFER[r.cat] && CM.toTs(r.date)>=today0-90*864e5).reduce((s,r)=>s+r.dr,0);
  const avgMoOut = debits90 ? Math.round(debits90/3) : (moBills+moSubs);
  const moOut = debits90 ? avgMoOut : (moBills+moSubs);
  const moNet = moIncome - moOut;
  const sr = moIncome ? moNet/moIncome : 0;
  const cardDebt = (S.cards||[]).reduce((s,c)=>s+(+c.balance||0),0);
  const netWorth = CM.netWorth ? CM.netWorth() : startBal;

  // outlook score
  let score=50;
  score += moNet>0?20:-15;
  score += clamp(Math.round(sr*100),-20,25);
  if(cardDebt>moIncome*3) score-=12; else if(cardDebt<moIncome && cardDebt>=0) score+=8;
  if(startBal>moOut*6) score+=12; else if(startBal<moOut) score-=10;
  score = clamp(Math.round(score),5,99);

  // 12-month projection
  const proj=[]; let bal=startBal;
  for(let i=1;i<=12;i++){ const d=new Date(today.getFullYear(),today.getMonth()+i,1); bal+=moNet; proj.push({k:d,label:d.toLocaleDateString('en-US',{month:'short'}),bal:Math.round(bal),inc:moIncome,out:moOut,net:moNet}); }
  const bal30=Math.round(startBal+moNet), bal90=Math.round(startBal+moNet*3), bal12=Math.round(startBal+moNet*12);
  const expSavings=Math.max(0,moNet)*12;

  // planned expenses (localStorage)
  const PE_KEY='cm_planned_expenses';
  const [plannedExpenses,setPlannedExpenses]=React.useState(()=>{ try{ return JSON.parse(localStorage.getItem(PE_KEY))||[]; }catch(e){ return []; } });
  const savePE=arr=>{ setPlannedExpenses(arr); try{ localStorage.setItem(PE_KEY, JSON.stringify(arr)); }catch(e){} };
  const [pe,setPe]=React.useState({desc:'',cat:'General',amount:'',date:'',priority:'Medium',notes:''});
  const addPE=()=>{ if(!pe.desc||!pe.amount) return; const row={id:'pe'+Date.now(),desc:pe.desc,cat:pe.cat,amount:+pe.amount||0,date:pe.date||isoOf(today),priority:pe.priority,notes:pe.notes}; savePE(plannedExpenses.concat([row])); setPe({desc:'',cat:'General',amount:'',date:'',priority:'Medium',notes:''}); };
  const delPE=id=>savePE(plannedExpenses.filter(p=>p.id!==id));

  // forecast events (income, bills, cc, planned, subs) within horizon days
  const buildForecast=(days)=>{
    const end=today0+days*864e5; const evs=[];
    (S.earnings||[]).forEach(e=>{ const t=CM.toTs(e.date); if(t>=today0&&t<=end) evs.push({ts:t,type:'income',label:e.desc||e.source||'Income',amt:+e.amount||0}); });
    (S.bills||[]).forEach(b=>{ if(b.paid) return; const t=CM.toTs(b.dueDate||b.date); if(t>=today0&&t<=end) evs.push({ts:t,type:'bill',label:b.desc||b.name||'Bill',amt:-(+b.amount||0)}); });
    (S.cards||[]).forEach(c=>{ if(!c.dueDate) return; const t=CM.toTs(c.dueDate); if(t>=today0&&t<=end){ const a=c.minPayment!=null?+c.minPayment:Math.max(25,Math.round((+c.balance||0)*0.02)); evs.push({ts:t,type:'cc',label:(c.name||'Card')+' payment',amt:-a}); } });
    plannedExpenses.forEach(p=>{ const t=CM.toTs(p.date); if(t>=today0&&t<=end) evs.push({ts:t,type:'planned',label:p.desc||'Planned',amt:-(+p.amount||0)}); });
    (S.subscriptions||[]).filter(s=>s.active!==false).forEach(s=>{ const due=s.nextDate||s.renewal||s.dueDate; if(!due) return; const t=CM.toTs(due); if(t>=today0&&t<=end) evs.push({ts:t,type:'sub',label:s.name||'Subscription',amt:-subMonthly(s)}); });
    evs.sort((a,b)=>a.ts-b.ts); return evs;
  };

  // calendar state
  const [cal,setCal]=React.useState({y:today.getFullYear(),m:today.getMonth()});
  // scenario state
  const [scn,setScn]=React.useState('Salary Increase');
  const [scnVal,setScnVal]=React.useState(10);

  const kpi=(label,value,color,sub)=> <MetricCard label={label} labelColor={color} value={value} sub={sub}/>;

  return (
    <div>
      <div style={{overflowX:'auto',marginBottom:4}}><Tabs tabs={TABS} value={tab} onChange={setTab}/></div>
      <div style={{height:16}}/>

      {tab==='Overview' && (<React.Fragment>
        <div className="cm-grid-3 cm-mb-24" style={{display:'grid',gridTemplateColumns:'repeat(auto-fit,minmax(220px,1fr))',gap:14}}>
          {kpi('30-Day Forecast', M0(bal30), bal30>=0?'var(--green-600)':'var(--red-500)','projected balance')}
          {kpi('90-Day Forecast', M0(bal90), bal90>=0?'var(--green-600)':'var(--red-500)','projected balance')}
          {kpi('12-Month Forecast', M0(bal12), bal12>=0?'var(--green-600)':'var(--red-500)','projected balance')}
          {kpi('Expected Savings', M0(expSavings), 'var(--green-600)','next 12 months')}
          {kpi('Monthly Surplus', (moNet>=0?'+':'')+M0(moNet), moNet>=0?'var(--green-600)':'var(--red-500)', moNet>=0?'surplus':'deficit')}
          {kpi('Outlook Score', String(score), score>=70?'var(--green-600)':(score>=45?'var(--gold)':'var(--red-500)'), score>=70?'strong':(score>=45?'fair':'needs work'))}
        </div>
        <Section title="Forecasted Balance" sub="12-month projection from your current accounts, recurring income and spending">
          <div style={{overflowX:'auto'}}><BalanceLine data={proj} fmt={M0}/></div>
        </Section>
        <div className="cm-grid-2a cm-mb-24">
          <ChartCard title="Future Income vs Expenses">
            <div style={{display:'flex',gap:24,marginBottom:10}}>
              <span className="t-caption" style={{display:'flex',alignItems:'center',gap:6}}><span style={{width:9,height:9,borderRadius:2,background:G}}/>Income</span>
              <span className="t-caption" style={{display:'flex',alignItems:'center',gap:6}}><span style={{width:9,height:9,borderRadius:2,background:'#FBD0D2'}}/>Expenses</span>
            </div>
            <div className="cm-vbars" style={{height:200}}>
              {proj.slice(0,12).map((m,i)=>{ const mx=Math.max(moIncome,moOut)||1; return (
                <div className="cm-vbar" key={i} style={{justifyContent:'flex-end'}}>
                  <div style={{display:'flex',gap:4,alignItems:'flex-end',width:'100%',justifyContent:'center',height:'100%'}}>
                    <div style={{width:11,borderRadius:'5px 5px 2px 2px',background:G,height:`${m.inc/mx*100}%`}}/>
                    <div style={{width:11,borderRadius:'5px 5px 2px 2px',background:'#FBD0D2',height:`${m.out/mx*100}%`}}/>
                  </div>
                  <div className="lbl">{m.label}</div>
                </div>); })}
            </div>
          </ChartCard>
          <ChartCard title="Future Net Worth">
            <TrendChart data={proj.map((m,i)=>Math.round(netWorth+moNet*(i+1)))} width={360} height={200} color={G} xLabels={proj.map(m=>m.label)}/>
            <div className="t-caption" style={{marginTop:8}}>Projected from today's net worth of <b>{M0(netWorth)}</b> plus expected monthly savings.</div>
          </ChartCard>
        </div>
        <Section title="Forecast Accuracy" sub="Last 6 months actual net cash flow vs the steady forecast">
          <TrendChart data={(function(){ const a=[]; for(let i=5;i>=0;i--){ const mk=new Date(today.getFullYear(),today.getMonth()-i,1); const key=mk.getFullYear()+'-'+pad2(mk.getMonth()+1); const inc=(S.bankTx||[]).filter(r=>r.cr>0&&!TRANSFER[r.cat]&&isoOf(new Date(CM.toTs(r.date))).slice(0,7)===key).reduce((s,r)=>s+r.cr,0); const exp=(S.bankTx||[]).filter(r=>r.dr>0&&!TRANSFER[r.cat]&&isoOf(new Date(CM.toTs(r.date))).slice(0,7)===key).reduce((s,r)=>s+r.dr,0); a.push(Math.round(inc-exp)); } return a.length?a:[0]; })()} width={720} height={180} color={BL}/>
          <div className="t-caption" style={{marginTop:8}}>Steady forecast: <b>{(moNet>=0?'+':'')+M0(moNet)}</b> / month.</div>
        </Section>
      </React.Fragment>)}

      {tab==='Income Forecast' && (function(){
        const TYPES=[['employ','Employment',/payroll|salary|wage|employ|pay ?cheque|paycheck/i],['bonus','Bonuses',/bonus|commission/i],['child','Child Benefits',/child|ccb|benefit/i],['pension','Pension',/pension|cpp|oas|retire/i],['rental','Rental Income',/rent|tenant|lease/i],['invest','Investment Income',/dividend|interest|invest|capital/i]];
        const classify=(e)=>{ const t=(e.desc||e.source||'')+' '+(e.cat||''); for(const x of TYPES){ if(x[2].test(t)) return x[1]; } return 'Other Income'; };
        const groups={}; const _seenInc={};
        (S.earnings||[]).forEach(e=>{ const g=classify(e); (groups[g]=groups[g]||{mo:0,next:null,last:null}); const key=g+'|'+(e.desc||e.source||'')+'|'+(+e.amount||0); if(!_seenInc[key]){ _seenInc[key]=1; groups[g].mo+=moAmt(e.amount,e.recur); } const t=CM.toTs(e.date); if(t>=today0 && (groups[g].next==null||t<groups[g].next)) groups[g].next=t; if(t<today0 && (groups[g].last==null||t>groups[g].last)) groups[g].last=t; });
        const rows=Object.keys(groups).map(k=>({type:k,mo:Math.round(groups[k].mo),next:groups[k].next,last:groups[k].last})).sort((a,b)=>b.mo-a.mo);
        const totalMo=rows.reduce((s,r)=>s+r.mo,0);
        const missing=rows.filter(r=>r.next==null && r.last!=null && (today0-r.last)>45*864e5);
        return (<React.Fragment>
          <div className="cm-grid-3 cm-mb-24" style={{display:'grid',gridTemplateColumns:'repeat(auto-fit,minmax(220px,1fr))',gap:14}}>
            {kpi('Forecast Monthly Income', M0(totalMo),'var(--green-600)','all sources')}
            {kpi('Annualized', M0(totalMo*12),'var(--green-600)','next 12 months')}
            {kpi('Income Sources', String(rows.length), 'var(--ink-700)', rows.length===1?'source':'sources')}
          </div>
          {missing.length?<Section title="Missing Income Alerts" sub="Recurring income we haven't seen recently">
            {missing.map((r,i)=><div key={i} style={{display:'flex',alignItems:'center',gap:10,padding:'10px 0',borderBottom:i<missing.length-1?'1px solid var(--line)':'none'}}><span style={{color:AM}}><I.Clock size={16}/></span><div style={{flex:1}}><b>{r.type}</b> — last seen {FD(r.last)}</div><Pill tone="amber">Check</Pill></div>)}
          </Section>:null}
          <Section title="Income Forecast by Source">
            {rows.length?<div style={{overflowX:'auto'}}><table className="cm-table" style={{minWidth:620}}>
              <thead><tr><th>Source</th><th className="right">Monthly</th><th className="right">Annual</th><th>Next Pay</th></tr></thead>
              <tbody>{rows.map((r,i)=>(<tr key={i}>
                <td><span style={{fontWeight:700,color:'var(--ink-900)'}}>{r.type}</span></td>
                <td style={{textAlign:'right'}}><span className="num" style={{color:G,fontWeight:700}}>{M0(r.mo)}</span></td>
                <td style={{textAlign:'right'}}><span className="num">{M0(r.mo*12)}</span></td>
                <td>{r.next?FD(r.next):<span className="t-caption">—</span>}</td>
              </tr>))}</tbody>
            </table></div>:<Empty>No income sources recorded yet.</Empty>}
          </Section>
          <Section title="12-Month Income Projection">
            <TrendChart data={proj.map(()=>totalMo)} width={720} height={180} color={G} xLabels={proj.map(m=>m.label)}/>
          </Section>
        </React.Fragment>);
      })()}

      {tab==='Recurring Bills Forecast' && (function(){
        const CAT=[['Mortgage',/mortgage/i],['Rent',/rent/i],['Property Taxes',/property tax|prop tax/i],['Utilities',/hydro|electric|water|gas|utility|energy/i],['Internet',/internet|wifi|fibre|fiber/i],['Cell Phone',/phone|mobile|cell|rogers|bell|telus|fido|koodo/i],['Insurance',/insur/i],['Student Loan',/student|osap|nslsc/i],['Car Loan',/car|auto|vehicle|lease/i]];
        const classify=n=>{ for(const c of CAT){ if(c[1].test(n)) return c[0]; } return 'Other'; };
        const rows=[]; const _seenRb={};
        (S.bills||[]).forEach(b=>{ const nm=b.desc||b.name||'Bill'; const key=nm+'|'+(+b.amount||0); if(_seenRb[key]){ const t=CM.toTs(b.dueDate||b.date); if(t>=today0 && (_seenRb[key].next==null||t<CM.toTs(_seenRb[key].next))) _seenRb[key].next=b.dueDate||b.date; return; } const row={name:nm,cat:classify(nm),amt:+b.amount||0,freq:b.recur||'Monthly',next:b.dueDate||b.date}; _seenRb[key]=row; rows.push(row); });
        (S.insurance||[]).forEach(p=>{ rows.push({name:(p.name||p.type||'Insurance')+' premium',cat:'Insurance',amt:+p.premium||0,freq:p.frequency||'Monthly',next:p.renewal||null}); });
        (S.liabilities||[]).forEach(l=>{ if(+l.payment>0) rows.push({name:l.name||l.type||'Loan',cat:classify(l.name||l.type||''),amt:+l.payment||0,freq:'Monthly',next:l.dueDate||null}); });
        rows.sort((a,b)=>moAmt(b.amt,b.freq)-moAmt(a.amt,a.freq));
        const totalMo=Math.round(rows.reduce((s,r)=>s+moAmt(r.amt,r.freq),0));
        return (<React.Fragment>
          <div className="cm-grid-3 cm-mb-24" style={{display:'grid',gridTemplateColumns:'repeat(auto-fit,minmax(220px,1fr))',gap:14}}>
            {kpi('Recurring Monthly', M0(totalMo),'var(--red-500)','fixed obligations')}
            {kpi('Annualized', M0(totalMo*12),'var(--red-500)','next 12 months')}
            {kpi('Bills Tracked', String(rows.length),'var(--ink-700)', rows.length===1?'bill':'bills')}
          </div>
          <Section title="Recurring Bills Forecast">
            {rows.length?<div style={{overflowX:'auto'}}><table className="cm-table" style={{minWidth:680}}>
              <thead><tr><th>Bill</th><th>Category</th><th className="right">Amount</th><th>Frequency</th><th>Next Payment</th></tr></thead>
              <tbody>{rows.map((r,i)=>(<tr key={i}>
                <td><span style={{fontWeight:700,color:'var(--ink-900)'}}>{r.name}</span></td>
                <td><Pill tone="slate">{r.cat}</Pill></td>
                <td style={{textAlign:'right'}}><span className="num" style={{fontWeight:700}}>{M0(r.amt)}</span></td>
                <td><span className="t-caption" style={{fontWeight:600}}>{r.freq}</span></td>
                <td>{r.next?FD(r.next):<span className="t-caption">—</span>}</td>
              </tr>))}</tbody>
            </table></div>:<Empty>No recurring bills recorded yet.</Empty>}
          </Section>
        </React.Fragment>);
      })()}

      {tab==='Planned Expenses' && (function(){
        const inp={fontFamily:'inherit',fontSize:13,border:'1px solid var(--line)',borderRadius:9,padding:'8px 10px',background:'#fff',color:'var(--ink-900)',outline:'none',boxSizing:'border-box'};
        const suggestions=['Vacation','Home Renovation','New Vehicle','Christmas Budget','Appliance Purchase','Emergency Repair'];
        const totalPlanned=plannedExpenses.reduce((s,p)=>s+(+p.amount||0),0);
        return (<React.Fragment>
          <Section title="Add Planned Expense" sub="One-time future expenses to factor into your forecast">
            <div style={{display:'grid',gridTemplateColumns:'1.4fr 1fr 0.8fr 1fr 0.9fr auto',gap:10,alignItems:'end'}}>
              <div><div className="t-label" style={{marginBottom:5}}>Description</div><input style={{...inp,width:'100%'}} value={pe.desc} onChange={e=>setPe({...pe,desc:e.target.value})} placeholder="e.g. Europe trip"/></div>
              <div><div className="t-label" style={{marginBottom:5}}>Category</div><select style={{...inp,width:'100%'}} value={pe.cat} onChange={e=>setPe({...pe,cat:e.target.value})}>{['General','Travel','Home','Vehicle','Holiday','Health','Education','Other'].map(c=><option key={c}>{c}</option>)}</select></div>
              <div><div className="t-label" style={{marginBottom:5}}>Amount</div><input type="number" style={{...inp,width:'100%'}} value={pe.amount} onChange={e=>setPe({...pe,amount:e.target.value})} placeholder="0"/></div>
              <div><div className="t-label" style={{marginBottom:5}}>Date</div><input type="date" style={{...inp,width:'100%'}} value={pe.date} onChange={e=>setPe({...pe,date:e.target.value})}/></div>
              <div><div className="t-label" style={{marginBottom:5}}>Priority</div><select style={{...inp,width:'100%'}} value={pe.priority} onChange={e=>setPe({...pe,priority:e.target.value})}>{['High','Medium','Low'].map(c=><option key={c}>{c}</option>)}</select></div>
              <button className="cm-btn cm-btn-primary" onClick={addPE}>Add</button>
            </div>
            <div style={{display:'flex',gap:8,flexWrap:'wrap',marginTop:12}}>
              {suggestions.map(s=><span key={s} onClick={()=>setPe({...pe,desc:s})} style={{cursor:'pointer',fontSize:12,fontWeight:600,color:'var(--ink-600)',background:'var(--mint-50)',border:'1px solid var(--line)',borderRadius:20,padding:'5px 12px'}}>+ {s}</span>)}
            </div>
          </Section>
          <Section title="Planned Expenses" action={<span className="t-caption">Total <b>{M0(totalPlanned)}</b></span>}>
            {plannedExpenses.length?<div style={{overflowX:'auto'}}><table className="cm-table" style={{minWidth:680}}>
              <thead><tr><th>Description</th><th>Category</th><th>Priority</th><th>Date</th><th className="right">Amount</th><th className="right">Action</th></tr></thead>
              <tbody>{plannedExpenses.slice().sort((a,b)=>CM.toTs(a.date)-CM.toTs(b.date)).map(p=>(<tr key={p.id}>
                <td><span style={{fontWeight:700,color:'var(--ink-900)'}}>{p.desc}</span>{p.notes?<div className="t-caption">{p.notes}</div>:null}</td>
                <td><Pill tone="slate">{p.cat}</Pill></td>
                <td><Pill tone={p.priority==='High'?'red':(p.priority==='Low'?'slate':'amber')}>{p.priority}</Pill></td>
                <td>{FD(p.date)}</td>
                <td style={{textAlign:'right'}}><span className="num" style={{fontWeight:700}}>{M0(p.amount)}</span></td>
                <td style={{textAlign:'right'}}><a className="t-label" style={{cursor:'pointer',color:'var(--red-500)'}} onClick={()=>delPE(p.id)}>Delete</a></td>
              </tr>))}</tbody>
            </table></div>:<Empty>No planned expenses yet — add one above or tap a suggestion.</Empty>}
          </Section>
        </React.Fragment>);
      })()}

      {tab==='Forecast Calendar' && (function(){
        const first=new Date(cal.y,cal.m,1); const startDow=first.getDay(); const days=new Date(cal.y,cal.m+1,0).getDate();
        const monthEvents={};
        const add=(dnum,ev)=>{ (monthEvents[dnum]=monthEvents[dnum]||[]).push(ev); };
        const inMonth=t=>{ const d=new Date(t); return d.getFullYear()===cal.y&&d.getMonth()===cal.m; };
        (S.earnings||[]).forEach(e=>{ const t=CM.toTs(e.date); if(inMonth(t)) add(new Date(t).getDate(),{c:G,label:e.desc||e.source||'Income',amt:+e.amount||0}); });
        (S.bills||[]).forEach(b=>{ if(b.paid)return; const t=CM.toTs(b.dueDate||b.date); if(inMonth(t)) add(new Date(t).getDate(),{c:RD,label:b.desc||b.name||'Bill',amt:-(+b.amount||0)}); });
        (S.cards||[]).forEach(c=>{ if(!c.dueDate)return; const t=CM.toTs(c.dueDate); if(inMonth(t)) add(new Date(t).getDate(),{c:AM,label:(c.name||'Card')+' payment',amt:-(c.minPayment!=null?+c.minPayment:Math.max(25,Math.round((+c.balance||0)*0.02)))}); });
        plannedExpenses.forEach(p=>{ const t=CM.toTs(p.date); if(inMonth(t)) add(new Date(t).getDate(),{c:PU,label:p.desc||'Planned',amt:-(+p.amount||0)}); });
        (S.subscriptions||[]).filter(s=>s.active!==false).forEach(s=>{ const due=s.nextDate||s.renewal||s.dueDate; if(!due)return; const t=CM.toTs(due); if(inMonth(t)) add(new Date(t).getDate(),{c:TEAL,label:s.name||'Subscription',amt:-subMonthly(s)}); });
        const cells=[]; for(let i=0;i<startDow;i++) cells.push(null); for(let d=1;d<=days;d++) cells.push(d);
        const monthLabel=first.toLocaleDateString('en-US',{month:'long',year:'numeric'});
        const shift=delta=>setCal(c=>{ let m=c.m+delta,y=c.y; if(m<0){m=11;y--;} if(m>11){m=0;y++;} return {y,m}; });
        return (<Section title="Forecast Calendar" action={<div style={{display:'inline-flex',alignItems:'center',gap:8}}>
            <button onClick={()=>shift(-1)} style={{border:0,background:'var(--mint-50)',width:30,height:30,borderRadius:8,cursor:'pointer',fontSize:18,color:'var(--green-600)'}}>‹</button>
            <span style={{fontWeight:700,minWidth:140,textAlign:'center'}}>{monthLabel}</span>
            <button onClick={()=>shift(1)} style={{border:0,background:'var(--mint-50)',width:30,height:30,borderRadius:8,cursor:'pointer',fontSize:18,color:'var(--green-600)'}}>›</button>
          </div>}>
          <div style={{display:'flex',gap:14,flexWrap:'wrap',marginBottom:12}}>
            {[['Income',G],['Bills',RD],['Card Payment',AM],['Planned',PU],['Subscription',TEAL]].map(l=><span key={l[0]} className="t-caption" style={{display:'flex',alignItems:'center',gap:6}}><span style={{width:9,height:9,borderRadius:2,background:l[1]}}/>{l[0]}</span>)}
          </div>
          <div style={{display:'grid',gridTemplateColumns:'repeat(7,1fr)',gap:6}}>
            {['Sun','Mon','Tue','Wed','Thu','Fri','Sat'].map(d=><div key={d} className="t-label" style={{textAlign:'center',padding:'4px 0'}}>{d}</div>)}
            {cells.map((d,i)=>{ const evs=d?(monthEvents[d]||[]):[]; const isToday=d&&cal.y===today.getFullYear()&&cal.m===today.getMonth()&&d===today.getDate();
              return <div key={i} onClick={()=>{ if(evs.length){ window.alert(monthLabel.split(' ')[0]+' '+d+'\n\n'+evs.map(e=>(e.amt>=0?'+':'')+M0(e.amt)+'  '+e.label).join('\n')); } }}
                style={{minHeight:84,border:'1px solid var(--line)',borderRadius:10,padding:'6px 7px',background:d?'#fff':'transparent',cursor:evs.length?'pointer':'default',outline:isToday?'2px solid var(--green-600)':'none'}}>
                {d?<div style={{fontSize:12,fontWeight:700,color:isToday?'var(--green-600)':'var(--ink-600)',marginBottom:4}}>{d}</div>:null}
                {evs.slice(0,3).map((e,j)=><div key={j} style={{fontSize:10.5,fontWeight:600,color:'#fff',background:e.c,borderRadius:5,padding:'1px 5px',marginBottom:3,whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}}>{(e.amt>=0?'+':'')+M0(e.amt)}</div>)}
                {evs.length>3?<div className="t-caption" style={{fontSize:10}}>+{evs.length-3} more</div>:null}
              </div>; })}
          </div>
        </Section>);
      })()}

      {tab==='Future Cash Flow' && (function(){
        const evs=buildForecast(90); let run=startBal; const rows=evs.map(e=>{ run+=e.amt; return {ts:e.ts,label:e.label,type:e.type,amt:e.amt,bal:Math.round(run)}; });
        const minBal=rows.reduce((m,r)=>Math.min(m,r.bal),startBal);
        const negDay=rows.find(r=>r.bal<0);
        const lowDay=rows.find(r=>r.bal<Math.max(500,moOut*0.25));
        const tone=t=>t==='income'?'green':(t==='cc'?'amber':'slate');
        return (<React.Fragment>
          <div className="cm-grid-3 cm-mb-24" style={{display:'grid',gridTemplateColumns:'repeat(auto-fit,minmax(220px,1fr))',gap:14}}>
            {kpi('Starting Balance', M0(startBal),'var(--ink-700)','today')}
            {kpi('Lowest Projected', M0(minBal), minBal<0?'var(--red-500)':(minBal<500?'var(--gold)':'var(--green-600)'),'next 90 days')}
            {kpi('Scheduled Events', String(rows.length),'var(--ink-700)','next 90 days')}
          </div>
          {(negDay||lowDay)?<Section title="Liquidity Alerts">
            {negDay?<div style={{display:'flex',alignItems:'center',gap:10,padding:'10px 12px',background:'var(--red-100)',borderRadius:12,marginBottom:negDay&&lowDay?10:0}}><span style={{color:RD}}><I.Wallet size={16}/></span><div style={{flex:1,fontWeight:600}}>Projected negative balance around {FD(negDay.ts)} ({M0(negDay.bal)})</div><Pill tone="red">Negative</Pill></div>:null}
            {lowDay&&(!negDay||lowDay.ts!==negDay.ts)?<div style={{display:'flex',alignItems:'center',gap:10,padding:'10px 12px',background:'#FBE7CF',borderRadius:12}}><span style={{color:AM}}><I.Clock size={16}/></span><div style={{flex:1,fontWeight:600}}>Low balance around {FD(lowDay.ts)} ({M0(lowDay.bal)})</div><Pill tone="amber">Watch</Pill></div>:null}
          </Section>:null}
          <Section title="Projected Balance" sub="Running balance from today through the next 90 days">
            <TrendChart data={rows.length?rows.map(r=>r.bal):[startBal]} width={720} height={200} color={minBal<0?RD:G} xLabels={rows.filter((r,i)=>i%Math.ceil(Math.max(1,rows.length)/8)===0).map(r=>FDshort(r.ts))}/>
          </Section>
          <Section title="Future Cash Flow Ledger">
            {rows.length?<div style={{overflowX:'auto'}}><table className="cm-table" style={{minWidth:640}}>
              <thead><tr><th>Date</th><th>Event</th><th className="right">Amount</th><th className="right">Projected Balance</th></tr></thead>
              <tbody>{rows.map((r,i)=>(<tr key={i}>
                <td><span className="num" style={{fontWeight:600,whiteSpace:'nowrap'}}>{FDshort(r.ts)}</span></td>
                <td><span style={{display:'inline-flex',gap:8,alignItems:'center'}}><Pill tone={tone(r.type)}>{r.type==='cc'?'Card':r.type[0].toUpperCase()+r.type.slice(1)}</Pill><span style={{fontWeight:600,color:'var(--ink-900)'}}>{r.label}</span></span></td>
                <td style={{textAlign:'right'}}><span className="num" style={{fontWeight:700,color:r.amt>=0?G:'var(--ink-900)'}}>{(r.amt>=0?'+':'')+M0(r.amt)}</span></td>
                <td style={{textAlign:'right'}}><span className="num" style={{fontWeight:800,color:r.bal<0?'var(--red-500)':'var(--ink-900)'}}>{M0(r.bal)}</span></td>
              </tr>))}</tbody>
            </table></div>:<Empty>No scheduled transactions in the next 90 days.</Empty>}
          </Section>
        </React.Fragment>);
      })()}

      {tab==='Savings Opportunities' && (function(){
        const recs=[];
        if(moSubs>40) recs.push({ic:'Subscriptions',c:TEAL,title:'Trim subscriptions',mo:Math.round(moSubs*0.3),impact:'+4 pts',desc:'You spend '+M0(moSubs)+'/mo on subscriptions. Cancelling unused ones could recover ~30%.'});
        if(cardDebt>0) recs.push({ic:'Card',c:RD,title:'Consolidate credit card debt',mo:Math.round(cardDebt*0.1899/12*0.4),impact:'+6 pts',desc:'Carrying '+M0(cardDebt)+' on cards. A lower-rate consolidation loan cuts interest.'});
        const mort=(S.liabilities||[]).find(l=>/mortgage/i.test(l.name||l.type||''));
        if(mort) recs.push({ic:'House',c:G,title:'Review mortgage renewal',mo:Math.round((+mort.balance||0)*0.005/12),impact:'+3 pts',desc:'Shopping your '+M0(+mort.balance||0)+' mortgage at renewal could lower your rate.'});
        if(startBal>moOut*3) recs.push({ic:'Grow',c:GOLD,title:'Move idle cash to a HISA',mo:Math.round(startBal*0.04/12),impact:'+2 pts',desc:M0(startBal)+' is sitting in low-interest accounts. A HISA at ~4% earns more.'});
        if(moNet>200) recs.push({ic:'Investments',c:BL,title:'Increase investment contributions',mo:Math.round(moNet*0.3),impact:'+3 pts',desc:'You have '+M0(moNet)+'/mo of surplus — automating more into investments compounds faster.'});
        if(!recs.length) recs.push({ic:'Spark',c:G,title:'You\u2019re optimized',mo:0,impact:'',desc:'No major savings opportunities detected — your plan looks healthy.'});
        const totalMo=recs.reduce((s,r)=>s+r.mo,0);
        return (<React.Fragment>
          <div className="cm-grid-3 cm-mb-24" style={{display:'grid',gridTemplateColumns:'repeat(auto-fit,minmax(220px,1fr))',gap:14}}>
            {kpi('Potential Monthly Savings', M0(totalMo),'var(--green-600)','across all opportunities')}
            {kpi('Potential Annual Savings', M0(totalMo*12),'var(--green-600)','if all actioned')}
          </div>
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:16}}>
            {recs.map((r,i)=>{ const Glyph=I[r.ic]||I.Spark; return (
              <div key={i} className="cm-card" style={{padding:'18px 20px'}}>
                <div style={{display:'flex',alignItems:'center',gap:12,marginBottom:10}}>
                  <span style={{width:40,height:40,borderRadius:11,background:'var(--mint-50)',display:'flex',alignItems:'center',justifyContent:'center',color:r.c}}><Glyph size={20}/></span>
                  <div style={{flex:1}}><div style={{fontWeight:800,fontSize:15,color:'var(--ink-900)'}}>{r.title}</div></div>
                  {r.mo>0?<div style={{textAlign:'right'}}><div className="num" style={{fontWeight:800,color:G}}>{M0(r.mo)}/mo</div>{r.impact?<div className="t-caption" style={{color:G}}>{r.impact}</div>:null}</div>:null}
                </div>
                <div className="t-caption" style={{lineHeight:1.6}}>{r.desc}</div>
                {r.mo>0?<div className="t-caption" style={{marginTop:8}}>Annual: <b style={{color:G}}>{M0(r.mo*12)}</b></div>:null}
              </div>); })}
          </div>
        </React.Fragment>);
      })()}

      {tab==='Goal Forecasting' && (function(){
        const goals=(S.goals||[]);
        const perGoal=goals.length?Math.max(0,moNet)/goals.length:0;
        const rows=goals.map(g=>{ const cur=+g.current||+g.saved||0, tgt=+g.target||0; const pct=tgt?clamp(Math.round(cur/tgt*100),0,100):0; const monthly=+g.monthly|| (perGoal||50); const remain=Math.max(0,tgt-cur); const months=monthly>0?Math.ceil(remain/monthly):null; const eta=months!=null?new Date(today.getFullYear(),today.getMonth()+months,1):null; return {name:g.name||'Goal',cat:g.category||'Savings',cur,tgt,pct,monthly,eta,months}; });
        return (<React.Fragment>
          <div className="cm-grid-3 cm-mb-24" style={{display:'grid',gridTemplateColumns:'repeat(auto-fit,minmax(220px,1fr))',gap:14}}>
            {kpi('Active Goals', String(goals.length),'var(--ink-700)', goals.length===1?'goal':'goals')}
            {kpi('Total Saved', M0(rows.reduce((s,r)=>s+r.cur,0)),'var(--green-600)','across goals')}
            {kpi('Total Target', M0(rows.reduce((s,r)=>s+r.tgt,0)),'var(--ink-700)','combined')}
          </div>
          {rows.length?<div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:16}}>
            {rows.map((r,i)=>(<div key={i} className="cm-card" style={{padding:'18px 20px'}}>
              <div style={{display:'flex',justifyContent:'space-between',alignItems:'flex-start',marginBottom:10}}>
                <div><div style={{fontWeight:800,fontSize:15,color:'var(--ink-900)'}}>{r.name}</div><div className="t-caption">{r.cat}</div></div>
                <Pill tone={r.pct>=100?'green':'slate'}>{r.pct}%</Pill>
              </div>
              <ProgressBar pct={r.pct} showPct={false} color={r.pct>=100?G:GOLD}/>
              <div style={{display:'flex',justifyContent:'space-between',marginTop:10}}>
                <span className="t-caption">{M0(r.cur)} of {M0(r.tgt)}</span>
                <span className="t-caption" style={{fontWeight:700,color:'var(--ink-700)'}}>{M0(r.monthly)}/mo</span>
              </div>
              <div style={{marginTop:10,paddingTop:10,borderTop:'1px solid var(--line)',display:'flex',justifyContent:'space-between',alignItems:'center'}}>
                <span className="t-caption">Forecast completion</span>
                <span style={{fontWeight:800,color:r.pct>=100?G:'var(--ink-900)'}}>{r.pct>=100?'Reached 🎉':(r.eta?r.eta.toLocaleDateString('en-US',{month:'short',year:'numeric'}):'—')}</span>
              </div>
            </div>))}
          </div>:<Empty>No goals yet. Add goals to see completion forecasts.</Empty>}
        </React.Fragment>);
      })()}

      {tab==='Scenario Planning' && (function(){
        const SCN={
          'Salary Increase':{unit:'%',min:0,max:30,def:10,apply:v=>({inc:moIncome*(1+v/100),out:moOut})},
          'Job Loss (months)':{unit:'mo',min:0,max:12,def:3,apply:v=>({inc:moIncome,out:moOut,runway:v})},
          'Interest Rate +':{unit:'%',min:0,max:5,def:1,apply:v=>({inc:moIncome,out:moOut+ (cardDebt+(S.liabilities||[]).reduce((s,l)=>s+(+l.balance||0),0))*(v/100)/12})},
          'New Vehicle (monthly)':{unit:'$',min:0,max:1200,def:450,apply:v=>({inc:moIncome,out:moOut+v})},
          'Extra Childcare (monthly)':{unit:'$',min:0,max:2000,def:800,apply:v=>({inc:moIncome,out:moOut+v})}
        };
        const cfg=SCN[scn]; const res=cfg.apply(scnVal);
        const newNet=Math.round((res.inc||moIncome)-(res.out||moOut));
        const newSr=res.inc?Math.round(((res.inc-res.out)/res.inc)*100):0;
        let s2=50; s2+= newNet>0?20:-15; s2+=clamp(Math.round((res.inc?(newNet/res.inc):0)*100),-20,25); if(cardDebt>moIncome*3)s2-=12; else if(cardDebt<moIncome)s2+=8; if(startBal>res.out*6)s2+=12; else if(startBal<res.out)s2-=10; s2=clamp(Math.round(s2),5,99);
        const newNW=Math.round(netWorth+newNet*12);
        const runway = scn==='Job Loss (months)' ? (moOut>0?(startBal/moOut).toFixed(1):'∞') : null;
        return (<React.Fragment>
          <Section title="Scenario Planning" sub="Simulate a what-if and see the impact on your forecast">
            <div style={{display:'flex',gap:8,flexWrap:'wrap',marginBottom:16}}>
              {Object.keys(SCN).map(k=><span key={k} onClick={()=>{ setScn(k); setScnVal(SCN[k].def); }} style={{cursor:'pointer',fontSize:13,fontWeight:700,padding:'8px 14px',borderRadius:10,background:scn===k?'var(--mint-100)':'var(--mint-50)',color:scn===k?'var(--green-600)':'var(--ink-600)',border:'1px solid '+(scn===k?'var(--green-600)':'var(--line)')}}>{k}</span>)}
            </div>
            <div style={{display:'flex',alignItems:'center',gap:16,marginBottom:6}}>
              <div style={{flex:1}}>
                <div className="t-label" style={{marginBottom:8}}>{scn} — {cfg.unit==='$'?M0(scnVal):scnVal+cfg.unit}</div>
                <input type="range" min={cfg.min} max={cfg.max} value={scnVal} onChange={e=>setScnVal(+e.target.value)} style={{width:'100%',accentColor:'var(--green-600)'}}/>
              </div>
            </div>
          </Section>
          <div className="cm-grid-3" style={{display:'grid',gridTemplateColumns:'repeat(auto-fit,minmax(220px,1fr))',gap:14}}>
            {kpi('New Cash Flow', (newNet>=0?'+':'')+M0(newNet), newNet>=0?'var(--green-600)':'var(--red-500)', (moNet>=0?'+':'')+M0(moNet)+' now')}
            {kpi('New Net Worth (12mo)', M0(newNW),'var(--ink-700)', M0(netWorth)+' today')}
            {kpi('New Savings Rate', newSr+'%', newSr>=0?'var(--green-600)':'var(--red-500)', Math.round(sr*100)+'% now')}
            {kpi(runway?'Cash Runway':'New Outlook Score', runway?runway+' mo':String(s2), s2>=70?'var(--green-600)':(s2>=45?'var(--gold)':'var(--red-500)'), runway?'on current savings':('was '+score))}
          </div>
        </React.Fragment>);
      })()}

      {tab==='AI Outlook' && (function(){
        const big=[...(S.cards||[]).map(c=>({n:c.name||'Card',v:+c.balance||0})), ...(S.liabilities||[]).map(l=>({n:l.name||l.type||'Loan',v:+l.balance||0}))].sort((a,b)=>b.v-a.v)[0];
        const text=`Based on your current income of ${M0(moIncome)}/month and spending of ${M0(moOut)}/month, your household is projected to ${moNet>=0?('save approximately '+M0(moNet*12)):('run a deficit of about '+M0(-moNet*12))} over the next 12 months. ${cardDebt>0?('Credit card balances ('+M0(cardDebt)+') remain the largest cash flow pressure. '):''}${moNet>=0?('Maintaining your current savings rate of '+Math.round(sr*100)+'% keeps you on track to reach a projected balance of '+M0(bal12)+'. '):('Reducing discretionary spending would help close the monthly gap. ')}Automating additional savings contributions could improve your Financial Outlook Score, currently ${score}.`;
        const bullets=[];
        bullets.push({c:moNet>=0?G:RD,t:(moNet>=0?'Surplus':'Deficit')+' of '+M0(Math.abs(moNet))+'/month',s:moNet>=0?'You\u2019re spending less than you earn.':'You\u2019re spending more than you earn.'});
        if(big&&big.v>0) bullets.push({c:RD,t:'Largest balance: '+big.n,s:M0(big.v)+' — prioritizing this reduces interest drag.'});
        bullets.push({c:GOLD,t:'Projected 12-month balance '+M0(bal12),s:'From '+M0(startBal)+' today at '+(moNet>=0?'+':'')+M0(moNet)+'/mo.'});
        bullets.push({c:BL,t:'Outlook score '+score+'/100',s:score>=70?'Strong financial trajectory.':(score>=45?'Fair — a few moves would strengthen it.':'Needs attention — see Savings Opportunities.')});
        return (<React.Fragment>
          <Section title="AI Financial Outlook" sub="Generated from your income, spending, debt, savings and goals">
            <div style={{display:'flex',gap:14,alignItems:'flex-start'}}>
              <span style={{width:42,height:42,flexShrink:0,borderRadius:12,background:'var(--mint-100)',display:'flex',alignItems:'center',justifyContent:'center',color:G}}><I.AI size={22}/></span>
              <div style={{fontSize:15,lineHeight:1.7,color:'var(--ink-800)'}}>{text}</div>
            </div>
          </Section>
          <Section title="Key Insights">
            <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:14}}>
              {bullets.map((b,i)=><div key={i} style={{display:'flex',gap:12,padding:'14px 16px',border:'1px solid var(--line)',borderRadius:12}}>
                <span style={{width:8,height:8,borderRadius:'50%',background:b.c,marginTop:6,flexShrink:0}}/>
                <div><div style={{fontWeight:700,color:'var(--ink-900)'}}>{b.t}</div><div className="t-caption" style={{marginTop:2}}>{b.s}</div></div>
              </div>)}
            </div>
          </Section>
        </React.Fragment>);
      })()}
    </div>
  );
}
window.PageFinancialOutlook = PageFinancialOutlook;
})();
