/* Clear Mint — Analytics Command Center charts & icons
   Depends on cm-charts (CMIcon) + cm-components. Exposes window.AN* helpers.
   Pure presentation — no app data/APIs touched. */
(function () {

/* ---------- palette ---------- */
const A = {
  G:'#10915F', forest:'#1B5E4A', gold:'#D4A95D', teal:'#0E9F8E', blue:'#3E7CC4',
  plum:'#8A6E9E', pink:'#D8688F', slate:'#9AA7B2', red:'#C35B5B', amber:'#D4A95D',
  line:'#EAE5DA', ink:'#1E2A24', mut:'#98A39B',
};
window.ANC = A;

/* ---------- local icons (24 grid, stroke) ---------- */
const si = (paths, fill=false) => ({ size=18, ...p }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill={fill?'currentColor':'none'}
       stroke={fill?'none':'currentColor'} strokeWidth="1.8" strokeLinecap="round"
       strokeLinejoin="round" {...p}>{paths}</svg>
);
const ANI = {
  brain : si(<><path d="M9 3a3 3 0 0 0-3 3 3 3 0 0 0-1 5 3 3 0 0 0 2 5 3 3 0 0 0 5 1V4a3 3 0 0 0-3-1z"/><path d="M15 3a3 3 0 0 1 3 3 3 3 0 0 1 1 5 3 3 0 0 1-2 5 3 3 0 0 1-5 1"/></>),
  spark : si(<><path d="M12 3v3M12 18v3M3 12h3M18 12h3M6 6l2 2M16 16l2 2M18 6l-2 2M8 16l-2 2"/><circle cx="12" cy="12" r="2.4"/></>),
  gauge : si(<><path d="M12 13l4-3"/><path d="M5 18a8 8 0 1 1 14 0"/><circle cx="12" cy="13" r="1" fill="currentColor" stroke="none"/></>),
  scale : si(<><path d="M12 3v18M5 7h14"/><path d="M5 7 2.5 13a3 3 0 0 0 5 0zM19 7l-2.5 6a3 3 0 0 0 5 0z"/><path d="M8 21h8"/></>),
  trend : si(<><path d="M4 17 10 11l3 3 7-7"/><path d="M16 7h4v4"/></>),
  trendDn: si(<><path d="M4 7 10 13l3-3 7 7"/><path d="M16 17h4v-4"/></>),
  flow  : si(<><path d="M4 7h13l-3-3M20 17H7l3 3"/></>),
  pie   : si(<><path d="M12 3v9h9a9 9 0 1 0-9-9z"/><path d="M21 12a9 9 0 0 1-9 9"/></>),
  flame : si(<path d="M12 3c2 3 .5 4.5 2 6.5 1-1 1.2-2 1-3.5 2 1.5 3 4 3 6.5a6 6 0 1 1-12 0c0-2 1-3.5 2.5-4.5C12 8.5 10.5 6 12 3z"/>),
  trophy: si(<><path d="M7 4h10v4a5 5 0 0 1-10 0z"/><path d="M7 5H4v2a3 3 0 0 0 3 3M17 5h3v2a3 3 0 0 1-3 3M9 14h6M10 18h4M9 21h6"/></>),
  alert : si(<><path d="M12 3 2 20h20z"/><path d="M12 10v4M12 17h.01"/></>),
  bulb  : si(<><path d="M9 18h6M10 21h4"/><path d="M12 3a6 6 0 0 0-4 10c1 1 1.5 1.5 1.5 3h5c0-1.5.5-2 1.5-3a6 6 0 0 0-4-10z"/></>),
  rocket: si(<><path d="M5 15c-1 1-2 4-2 4s3-1 4-2M12 4c3 1 6 4 6 9 0 2-1 4-2 5l-5-5c1-1 3-2 5-2"/><path d="M9 11l-5 1 3 3 1-5z"/><circle cx="15" cy="9" r="1.4"/></>),
  target: si(<><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.4" fill="currentColor" stroke="none"/></>),
  flag  : si(<><path d="M5 21V4M5 4h11l-2 4 2 4H5"/></>),
  cal   : si(<><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 9h18M8 3v4M16 3v4"/></>),
  download: si(<><path d="M12 4v12M8 12l4 4 4-4"/><path d="M5 20h14"/></>),
  share : si(<><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><path d="m8.5 13.5 7 4M15.5 6.5l-7 4"/></>),
  filter: si(<path d="M3 5h18l-7 8v6l-4-2v-4z"/>),
  refresh: si(<><path d="M4 8a8 8 0 0 1 14-3M20 16a8 8 0 0 1-14 3"/><path d="M18 3v3h-3M6 21v-3h3"/></>),
  chev  : si(<path d="m6 9 6 6 6-6"/>),
  chevR : si(<path d="m9 6 6 6-6 6"/>),
  arrUp : si(<path d="M12 19V5M6 11l6-6 6 6"/>),
  arrDn : si(<path d="M12 5v14M6 13l6 6 6-6"/>),
  wallet: si(<><rect x="3" y="6" width="18" height="13" rx="2"/><path d="M3 10h18M17 14h.01"/></>),
  bank  : si(<><path d="M3 9 12 4l9 5"/><path d="M5 9v9M9 9v9M15 9v9M19 9v9M3 18h18"/></>),
  home  : si(<><path d="M3 10.5 12 3l9 7.5"/><path d="M5 9.5V21h14V9.5"/></>),
  car   : si(<><path d="M3 16v-3l2-5h14l2 5v3z"/><circle cx="7.5" cy="16" r="1.3"/><circle cx="16.5" cy="16" r="1.3"/></>),
  card  : si(<><rect x="3" y="6" width="18" height="12" rx="2"/><path d="M3 10h18"/></>),
  shield: si(<><path d="M12 3 5 6v5c0 4 3 7.5 7 9 4-1.5 7-5 7-9V6z"/><path d="m9 12 2 2 4-4"/></>),
  grad  : si(<><path d="M3 9l9-4 9 4-9 4z"/><path d="M7 11v5c0 1 2.5 3 5 3s5-2 5-3v-5M21 9v6"/></>),
  plane : si(<path d="M10 14 3 12l1-2 6 .5L14 4l2 .5-2 7 6 2v2l-6-1-2 5-1.5-.5z"/>),
  check : si(<path d="M20 6 9 17l-5-5"/>),
  clock : si(<><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></>),
  info  : si(<><circle cx="12" cy="12" r="9"/><path d="M12 11v5M12 8h.01"/></>),
  dollar: si(<><path d="M12 3v18M16 7.5C16 5.6 14.2 4 12 4S8 5.6 8 7.5 9.8 11 12 11s4 1.6 4 3.5S14.2 18 12 18s-4-1.6-4-3.5"/></>),
  percent: si(<><circle cx="7" cy="7" r="2.5"/><circle cx="17" cy="17" r="2.5"/><path d="M19 5 5 19"/></>),
  layers: si(<><path d="M12 3 3 8l9 5 9-5z"/><path d="M3 13l9 5 9-5M3 17l9 5 9-5"/></>),
  star  : ({ size=14, ...p }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor" {...p}>
      <path d="M12 2.5 14.85 8.3l6.4.93-4.63 4.5 1.1 6.37L12 17.1 6.28 20.1l1.1-6.37L2.75 9.23l6.4-.93z"/>
    </svg>),
};
window.ANI = ANI;

/* ================= ScoreGauge (0–100 semicircle) ================= */
function ScoreGauge({ score=87, max=100, label='Excellent', size=300 }) {
  const W=size, H=size*0.62, cx=W/2, cy=H-12, r=W*0.42, stroke=W*0.072;
  const arc = `M ${cx-r} ${cy} A ${r} ${r} 0 0 1 ${cx+r} ${cy}`;
  const f = Math.max(0,Math.min(1,score/max)), ang=Math.PI*(1-f);
  const mx=cx+r*Math.cos(ang), my=cy-r*Math.sin(ang);
  return (
    <div style={{position:'relative', width:'100%', maxWidth:W, margin:'0 auto'}}>
      <svg width="100%" viewBox={`0 0 ${W} ${H}`} style={{display:'block'}}>
        <defs>
          <linearGradient id="anScoreGrad" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0%" stopColor="#C9554F"/><stop offset="32%" stopColor="#DB8A4A"/>
            <stop offset="55%" stopColor="#E0A94E"/><stop offset="78%" stopColor="#7FB45C"/>
            <stop offset="100%" stopColor="#2E8B57"/>
          </linearGradient>
        </defs>
        <path d={arc} fill="none" stroke="var(--line)" strokeWidth={stroke} strokeLinecap="round"/>
        <path d={arc} fill="none" stroke="url(#anScoreGrad)" strokeWidth={stroke} strokeLinecap="round"/>
        <circle cx={mx} cy={my} r={stroke*0.42} fill="#fff" stroke="#2E8B57" strokeWidth="3"/>
      </svg>
      <div style={{position:'absolute', left:0, right:0, bottom:'2%', textAlign:'center'}}>
        <div className="num" style={{fontFamily:'var(--font-serif)', fontSize:W*0.18, fontWeight:700, color:'var(--ink-900)', lineHeight:1}}>{score}</div>
        <div style={{fontSize:13, fontWeight:800, color:'var(--green-600)', marginTop:2}}>{label}</div>
        <div style={{display:'flex', gap:3, justifyContent:'center', marginTop:6, color:'var(--gold)'}}>
          {[0,1,2,3,4].map(i=><ANI.star key={i} size={14}/>)}
        </div>
      </div>
    </div>
  );
}
window.AnScoreGauge = ScoreGauge;

/* ================= HalfGauge (compact, value%) ================= */
function HalfGauge({ pct=78, big, sub, color='#10915F', track='var(--mint-100)', size=190 }) {
  const W=size, H=size*0.6, cx=W/2, cy=H-6, r=W*0.42, stroke=W*0.085;
  const arc = `M ${cx-r} ${cy} A ${r} ${r} 0 0 1 ${cx+r} ${cy}`;
  const len=Math.PI*r, frac=Math.max(0,Math.min(1,pct/100));
  return (
    <div style={{position:'relative', width:'100%', maxWidth:W, margin:'0 auto'}}>
      <svg width="100%" viewBox={`0 0 ${W} ${H}`} style={{display:'block'}}>
        <path d={arc} fill="none" stroke={track} strokeWidth={stroke} strokeLinecap="round"/>
        <path d={arc} fill="none" stroke={color} strokeWidth={stroke} strokeLinecap="round"
              strokeDasharray={`${frac*len} ${len}`}/>
      </svg>
      <div style={{position:'absolute', left:0, right:0, bottom:'0%', textAlign:'center'}}>
        <div className="num" style={{fontFamily:'var(--font-serif)', fontSize:W*0.17, fontWeight:700, color:'var(--ink-900)', lineHeight:1}}>{big}</div>
        {sub && <div style={{fontSize:11.5, fontWeight:800, color, marginTop:2}}>{sub}</div>}
      </div>
    </div>
  );
}
window.AnHalfGauge = HalfGauge;

/* ================= MiniSpark ================= */
function MiniSpark({ data, color='#10915F', w=160, h=38, fill=true, light=false }) {
  const min=Math.min(...data), max=Math.max(...data), span=(max-min)||1;
  const X=i=>(i/(data.length-1))*w, Y=v=>h-4-((v-min)/span)*(h-8);
  const line=data.map((v,i)=>`${i?'L':'M'}${X(i).toFixed(1)},${Y(v).toFixed(1)}`).join(' ');
  const area=`${line} L${w},${h} L0,${h} Z`;
  const id='sp'+Math.round(Math.random()*1e6);
  const c = light ? 'rgba(255,255,255,.85)' : color;
  return (
    <svg width="100%" viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" style={{display:'block', height:h}}>
      {fill && <defs><linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
        <stop offset="0%" stopColor={c} stopOpacity={light?'.30':'.20'}/><stop offset="100%" stopColor={c} stopOpacity="0"/>
      </linearGradient></defs>}
      {fill && <path d={area} fill={`url(#${id})`}/>}
      <path d={line} fill="none" stroke={c} strokeWidth="2" strokeLinejoin="round" strokeLinecap="round"/>
    </svg>
  );
}
window.AnMiniSpark = MiniSpark;

/* ================= NetWorthChart (assets/liab/net + forecast) ================= */
function NetWorthChart({ points, height=300 }) {
  // points: [{x, assets, liab, net, fc?}]  fc=true marks forecast region
  const W=900, H=height, P={l:52,r:58,t:18,b:30};
  const all=points.flatMap(p=>[p.assets,p.liab,p.net]);
  const lo=0, hi=Math.max(...all)*1.12;
  const X=i=>P.l+(i/(points.length-1))*(W-P.l-P.r);
  const Y=v=>P.t+(1-(v-lo)/(hi-lo))*(H-P.t-P.b);
  const fcStart=points.findIndex(p=>p.fc);
  const seg=(key,solid)=>{
    const pts=points.map((p,i)=>({i,v:p[key],fc:p.fc}));
    const filt=pts.filter(p=> solid ? (!p.fc || (fcStart>=0 && p.i===fcStart-1)) : (p.fc || (fcStart>=0 && p.i===fcStart-1)));
    if(filt.length<2) return '';
    return filt.map((p,k)=>`${k?'L':'M'}${X(p.i).toFixed(1)},${Y(p.v).toFixed(1)}`).join(' ');
  };
  const netSolid=seg('net',true), netDash=seg('net',false);
  const netArea=(()=>{ const sp=points.filter((p,i)=> !p.fc || (fcStart>=0&&i===fcStart-1));
    if(sp.length<2) return ''; const l=sp.map((p)=>{const i=points.indexOf(p);return `${X(i).toFixed(1)},${Y(p.net).toFixed(1)}`;});
    return `M${l[0]} ${l.slice(1).map(s=>'L'+s).join(' ')} L${X(fcStart>=0?fcStart-1:points.length-1).toFixed(1)},${H-P.b} L${X(0).toFixed(1)},${H-P.b} Z`; })();
  const yTicks=5;
  const fmt=v=> v>=1e6?('$'+(v/1e6).toFixed(2)+'M') : v>=1e3?('$'+Math.round(v/1e3)+'K') : '$'+v;
  const last=points[points.length-1];
  return (
    <svg width="100%" viewBox={`0 0 ${W} ${H}`} style={{display:'block'}}>
      <defs><linearGradient id="anNwFill" x1="0" y1="0" x2="0" y2="1">
        <stop offset="0%" stopColor={A.gold} stopOpacity=".22"/><stop offset="100%" stopColor={A.gold} stopOpacity="0"/>
      </linearGradient></defs>
      {Array.from({length:yTicks}).map((_,i)=>{
        const v=lo+(hi-lo)*(i/(yTicks-1)); const y=Y(v);
        return <g key={i}><line x1={P.l} y1={y} x2={W-P.r} y2={y} stroke="var(--line)" strokeWidth="1"/>
          <text x={P.l-10} y={y+4} textAnchor="end" fontSize="11" fontWeight="600" fill="var(--ink-400)">{fmt(v)}</text></g>;
      })}
      {fcStart>=0 && <>
        <rect x={X(fcStart-1)} y={P.t} width={W-P.r-X(fcStart-1)} height={H-P.t-P.b} fill="#FBF7EE" opacity=".7"/>
        <line x1={X(fcStart-1)} y1={P.t} x2={X(fcStart-1)} y2={H-P.b} stroke={A.gold} strokeWidth="1.4" strokeDasharray="3 4"/>
        <text x={X(fcStart-1)+8} y={P.t+14} fontSize="10.5" fontWeight="800" fill="#A9772A" letterSpacing=".06em">FORECAST</text>
      </>}
      {netArea && <path d={netArea} fill="url(#anNwFill)"/>}
      {/* assets + liabilities lines */}
      {['assets','liab'].map(k=>{
        const col=k==='assets'?A.G:A.red;
        const s=seg(k,true), d=seg(k,false);
        return <g key={k}>
          <path d={s} fill="none" stroke={col} strokeWidth="2" strokeLinejoin="round" opacity=".9"/>
          {d && <path d={d} fill="none" stroke={col} strokeWidth="2" strokeDasharray="4 4" strokeLinejoin="round" opacity=".6"/>}
        </g>;
      })}
      <path d={netSolid} fill="none" stroke={A.gold} strokeWidth="3" strokeLinejoin="round"/>
      {netDash && <path d={netDash} fill="none" stroke={A.gold} strokeWidth="3" strokeDasharray="5 5" strokeLinejoin="round"/>}
      {points.map((p,i)=> (i%Math.ceil(points.length/9)===0 || i===points.length-1) &&
        <text key={i} x={X(i)} y={H-8} textAnchor="middle" fontSize="11" fontWeight="600" fill="var(--ink-400)">{p.x}</text>)}
      {/* end value badge */}
      <g>
        <circle cx={X(points.length-1)} cy={Y(last.net)} r="4.5" fill={A.gold} stroke="#fff" strokeWidth="2"/>
        <rect x={X(points.length-1)-2} y={Y(last.net)-30} width="56" height="22" rx="6" fill={A.forest}/>
        <text x={X(points.length-1)+26} y={Y(last.net)-15} textAnchor="middle" fontSize="11.5" fontWeight="800" fill="#fff">{fmt(last.net)}</text>
      </g>
    </svg>
  );
}
window.AnNetWorth = NetWorthChart;

/* ================= CashFlowChart (income/expense bars + net line) ================= */
function CashFlowChart({ data, height=280 }) {
  // data: [{m, income, expense, net}]
  const W=820, H=height, P={l:50,r:16,t:18,b:30};
  const maxBar=Math.max(...data.map(d=>Math.max(d.income,d.expense)))*1.15;
  const X=i=>P.l+(i+0.5)/data.length*(W-P.l-P.r);
  const bw=Math.min(20,(W-P.l-P.r)/data.length/3.2);
  const Y=v=>P.t+(1-v/maxBar)*(H-P.t-P.b);
  const netLine=data.map((d,i)=>`${i?'L':'M'}${X(i).toFixed(1)},${Y(d.net).toFixed(1)}`).join(' ');
  const yTicks=5;
  const fmt=v=> v>=1e3?('$'+Math.round(v/1e3)+'K'):'$'+Math.round(v);
  return (
    <svg width="100%" viewBox={`0 0 ${W} ${H}`} style={{display:'block'}}>
      {Array.from({length:yTicks}).map((_,i)=>{
        const v=maxBar*(i/(yTicks-1)); const y=Y(v);
        return <g key={i}><line x1={P.l} y1={y} x2={W-P.r} y2={y} stroke="var(--line)" strokeWidth="1"/>
          <text x={P.l-9} y={y+4} textAnchor="end" fontSize="11" fontWeight="600" fill="var(--ink-400)">{fmt(v)}</text></g>;
      })}
      {data.map((d,i)=>{
        const cx=X(i);
        return <g key={i}>
          <rect x={cx-bw-2} y={Y(d.income)} width={bw} height={H-P.b-Y(d.income)} rx="4" fill={A.forest}/>
          <rect x={cx+2} y={Y(d.expense)} width={bw} height={H-P.b-Y(d.expense)} rx="4" fill={A.gold}/>
          <text x={cx} y={H-8} textAnchor="middle" fontSize="11" fontWeight="600" fill="var(--ink-400)">{d.m}</text>
        </g>;
      })}
      <path d={netLine} fill="none" stroke={A.teal} strokeWidth="2.6" strokeLinejoin="round"/>
      {data.map((d,i)=><circle key={i} cx={X(i)} cy={Y(d.net)} r="3.4" fill="#fff" stroke={A.teal} strokeWidth="1.8"/>)}
    </svg>
  );
}
window.AnCashFlow = CashFlowChart;

/* ================= LineChart (single series, generic) ================= */
function LineChart({ data, color='#10915F', height=200, yfmt=v=>v, xLabels=[], fill=true, dots=true, baseZero=false }) {
  const W=560, H=height, P={l:44,r:14,t:16,b:26};
  const min=baseZero?0:Math.min(...data), max=Math.max(...data);
  const lo=baseZero?0:min-(max-min)*0.18, hi=max+(max-min)*0.14||max*1.1;
  const X=i=>P.l+(i/(data.length-1))*(W-P.l-P.r);
  const Y=v=>P.t+(1-(v-lo)/((hi-lo)||1))*(H-P.t-P.b);
  const line=data.map((v,i)=>`${i?'L':'M'}${X(i).toFixed(1)},${Y(v).toFixed(1)}`).join(' ');
  const area=`${line} L${X(data.length-1)},${H-P.b} L${X(0)},${H-P.b} Z`;
  const id='ln'+Math.round(Math.random()*1e6); const rows=4;
  return (
    <svg width="100%" viewBox={`0 0 ${W} ${H}`} style={{display:'block'}}>
      {fill && <defs><linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
        <stop offset="0%" stopColor={color} stopOpacity=".16"/><stop offset="100%" stopColor={color} stopOpacity="0"/>
      </linearGradient></defs>}
      {Array.from({length:rows+1}).map((_,i)=>{
        const v=lo+(hi-lo)*(1-i/rows); const y=P.t+i*((H-P.t-P.b)/rows);
        return <g key={i}><line x1={P.l} y1={y} x2={W-P.r} y2={y} stroke="var(--line)" strokeWidth="1"/>
          <text x={P.l-8} y={y+4} textAnchor="end" fontSize="10.5" fontWeight="600" fill="var(--ink-400)">{yfmt(v)}</text></g>;
      })}
      {fill && <path d={area} fill={`url(#${id})`}/>}
      <path d={line} fill="none" stroke={color} strokeWidth="2.4" strokeLinejoin="round"/>
      {dots && data.map((v,i)=> i%2===0 && <circle key={i} cx={X(i)} cy={Y(v)} r="2.6" fill="#fff" stroke={color} strokeWidth="1.6"/>)}
      {xLabels.map((lb,i)=>{ const x=X(i*(data.length-1)/(xLabels.length-1));
        return <text key={i} x={x} y={H-7} textAnchor="middle" fontSize="10.5" fontWeight="600" fill="var(--ink-400)">{lb}</text>; })}
    </svg>
  );
}
window.AnLine = LineChart;

/* ================= BenchmarkChart (portfolio vs index) ================= */
function BenchmarkChart({ series, height=230 }) {
  // series: [{name,color,data}]
  const W=600, H=height, P={l:44,r:14,t:16,b:26};
  const all=series.flatMap(s=>s.data); const min=Math.min(...all), max=Math.max(...all);
  const lo=min-(max-min)*0.12, hi=max+(max-min)*0.12;
  const n=series[0].data.length;
  const X=i=>P.l+(i/(n-1))*(W-P.l-P.r);
  const Y=v=>P.t+(1-(v-lo)/((hi-lo)||1))*(H-P.t-P.b);
  return (
    <svg width="100%" viewBox={`0 0 ${W} ${H}`} style={{display:'block'}}>
      {[0,1,2,3].map(i=>{ const y=P.t+i*((H-P.t-P.b)/3);
        const v=hi-(hi-lo)*(i/3);
        return <g key={i}><line x1={P.l} y1={y} x2={W-P.r} y2={y} stroke="var(--line)" strokeWidth="1"/>
          <text x={P.l-8} y={y+4} textAnchor="end" fontSize="10.5" fontWeight="600" fill="var(--ink-400)">{'+'+Math.round(v)+'%'}</text></g>; })}
      {series.map((s,si)=>{
        const line=s.data.map((v,i)=>`${i?'L':'M'}${X(i).toFixed(1)},${Y(v).toFixed(1)}`).join(' ');
        return <path key={si} d={line} fill="none" stroke={s.color} strokeWidth={si===0?'2.8':'2'} strokeDasharray={si===0?'':'5 4'} strokeLinejoin="round"/>;
      })}
      {['Jan','Mar','May','Jul','Sep','Nov'].map((lb,i)=>{ const x=X(i*(n-1)/5);
        return <text key={i} x={x} y={H-7} textAnchor="middle" fontSize="10.5" fontWeight="600" fill="var(--ink-400)">{lb}</text>; })}
    </svg>
  );
}
window.AnBenchmark = BenchmarkChart;

/* ================= RadarChart (health components) ================= */
function RadarChart({ axes, size=300 }) {
  // axes: [{label, value(0-100)}]
  const pad=42;
  const W=size, H=size, cx=W/2, cy=H/2, R=W*0.32, n=axes.length;
  const ang=i=>(-Math.PI/2)+(i/n)*2*Math.PI;
  const pt=(i,r)=>[cx+Math.cos(ang(i))*r, cy+Math.sin(ang(i))*r];
  const rings=[0.25,0.5,0.75,1];
  const poly=axes.map((a,i)=>pt(i,R*a.value/100).join(',')).join(' ');
  return (
    <svg width="100%" viewBox={`${-pad} ${-pad} ${W+pad*2} ${H+pad*2}`} style={{display:'block', maxWidth:size+pad*1.4, margin:'0 auto'}}>
      {rings.map((r,ri)=>(
        <polygon key={ri} points={axes.map((_,i)=>pt(i,R*r).join(',')).join(' ')}
          fill="none" stroke="var(--line)" strokeWidth="1"/>
      ))}
      {axes.map((_,i)=>{ const [x,y]=pt(i,R); return <line key={i} x1={cx} y1={cy} x2={x} y2={y} stroke="var(--line)" strokeWidth="1"/>; })}
      <polygon points={poly} fill="rgba(46,139,87,.16)" stroke={A.G} strokeWidth="2.2" strokeLinejoin="round"/>
      {axes.map((a,i)=>{ const [x,y]=pt(i,R*a.value/100);
        return <circle key={i} cx={x} cy={y} r="3.4" fill="#fff" stroke={A.G} strokeWidth="1.8"/>; })}
      {axes.map((a,i)=>{ const [x,y]=pt(i,R+16);
        const anchor=Math.abs(x-cx)<6?'middle':(x>cx?'start':'end');
        return <text key={i} x={x} y={y+3} textAnchor={anchor} fontSize="11" fontWeight="700" fill="var(--ink-500)">{a.label}</text>; })}
    </svg>
  );
}
window.AnRadar = RadarChart;

/* ================= Heatmap (spending calendar) ================= */
function Heatmap({ weeks, color='#1B5E4A' }) {
  // weeks: array of arrays(7) values 0..1
  const days=['S','M','T','W','T','F','S'];
  return (
    <div style={{display:'flex', gap:10}}>
      <div style={{display:'flex', flexDirection:'column', gap:5, paddingTop:2}}>
        {days.map((d,i)=><div key={i} style={{height:0, flex:1, fontSize:9.5, fontWeight:700, color:'var(--ink-400)', display:'flex', alignItems:'center', minHeight:14}}>{d}</div>)}
      </div>
      <div style={{display:'flex', gap:5, flex:1}}>
        {weeks.map((wk,wi)=>(
          <div key={wi} style={{display:'flex', flexDirection:'column', gap:5, flex:1}}>
            {wk.map((v,di)=>(
              <div key={di} title={Math.round(v*100)+''} style={{aspectRatio:'1', borderRadius:4, flex:1,
                background: v<0 ? 'var(--mint-50)' : `color-mix(in srgb, ${color} ${Math.round(12+v*88)}%, #F0F3EE)`}}/>
            ))}
          </div>
        ))}
      </div>
    </div>
  );
}
window.AnHeatmap = Heatmap;

/* ================= ProjectionChart (interactive lab) ================= */
function ProjectionChart({ series, years, height=300 }) {
  // series: {nw:[..], invest:[..], debt:[..]} length = years+1
  const W=820, H=height, P={l:54,r:60,t:18,b:30};
  const n=series.nw.length;
  const all=[...series.nw,...series.invest];
  const lo=0, hi=Math.max(...all)*1.1||1;
  const X=i=>P.l+(i/(n-1))*(W-P.l-P.r);
  const Y=v=>P.t+(1-(v-lo)/(hi-lo))*(H-P.t-P.b);
  const mkPath=arr=>arr.map((v,i)=>`${i?'L':'M'}${X(i).toFixed(1)},${Y(v).toFixed(1)}`).join(' ');
  const nwArea=`${mkPath(series.nw)} L${X(n-1)},${H-P.b} L${X(0)},${H-P.b} Z`;
  const fmt=v=> v>=1e6?('$'+(v/1e6).toFixed(2)+'M') : v>=1e3?('$'+Math.round(v/1e3)+'K') : '$'+Math.round(v);
  const yTicks=5;
  const lbl=(arr,col,txt)=>{ const v=arr[n-1], y=Y(v);
    return <g><rect x={X(n-1)+4} y={y-11} width="52" height="22" rx="6" fill={col}/>
      <text x={X(n-1)+30} y={y+4} textAnchor="middle" fontSize="11" fontWeight="800" fill="#fff">{txt}</text></g>; };
  return (
    <svg width="100%" viewBox={`0 0 ${W} ${H}`} style={{display:'block'}}>
      <defs><linearGradient id="anPjFill" x1="0" y1="0" x2="0" y2="1">
        <stop offset="0%" stopColor={A.G} stopOpacity=".18"/><stop offset="100%" stopColor={A.G} stopOpacity="0"/>
      </linearGradient></defs>
      {Array.from({length:yTicks}).map((_,i)=>{ const v=lo+(hi-lo)*(i/(yTicks-1)); const y=Y(v);
        return <g key={i}><line x1={P.l} y1={y} x2={W-P.r} y2={y} stroke="var(--line)" strokeWidth="1"/>
          <text x={P.l-10} y={y+4} textAnchor="end" fontSize="11" fontWeight="600" fill="var(--ink-400)">{fmt(v)}</text></g>; })}
      <path d={nwArea} fill="url(#anPjFill)"/>
      <path d={mkPath(series.debt)} fill="none" stroke={A.red} strokeWidth="2.2" strokeLinejoin="round"/>
      <path d={mkPath(series.invest)} fill="none" stroke={A.blue} strokeWidth="2.2" strokeLinejoin="round"/>
      <path d={mkPath(series.nw)} fill="none" stroke={A.G} strokeWidth="3.2" strokeLinejoin="round"/>
      {Array.from({length:n}).map((_,i)=> (i%Math.ceil(n/8)===0||i===n-1) &&
        <text key={i} x={X(i)} y={H-8} textAnchor="middle" fontSize="11" fontWeight="600" fill="var(--ink-400)">{years[i]}</text>)}
      {lbl(series.nw,A.forest,fmt(series.nw[n-1]))}
    </svg>
  );
}
window.AnProjection = ProjectionChart;

})();
