// ============================================================================
// KoiFi Dashboard prototype — WIDGET REGISTRY (S / M / L variants) — ELEVATED
// Warm, premium, restrained. Gradient-accented data viz; clean white cards;
// one gradient "moment" (Add / Mascot). Cormorant display + Inter utility.
// Depends on: primitives.jsx (Icon, Pill), tokens.js (window.KOI)
// ============================================================================
const PC = () => window.KOI[window.__koiTheme || 'light'];
const PSERIF = "'Cormorant Garamond', serif";
const PSANS = "'Inter', system-ui, sans-serif";
const PGRAD = 'linear-gradient(135deg,#DFBBA1 0%,#C9987E 52%,#B0855F 100%)';
const fmt = (v) => v.toLocaleString('en-US');
let _uid = 0; const uid = () => `k${++_uid}`;

// one-time keyframes for tasteful motion
(function injectKeyframes() {
  if (document.getElementById('koi-kf')) return;
  const s = document.createElement('style');
  s.id = 'koi-kf';
  s.textContent = `
    @keyframes koiSheen { 0%{transform:translateX(-120%)} 60%,100%{transform:translateX(220%)} }
    @keyframes koiPulse { 0%,100%{opacity:.55;transform:scale(1)} 50%{opacity:.9;transform:scale(1.06)} }
    @keyframes koiRise { from{transform:translateY(12px)} to{transform:none} }
    @keyframes koiWiggle { 0%,86%,100%{transform:rotate(0)} 90%{transform:rotate(-9deg)} 94%{transform:rotate(9deg)} }
    .koi-press { transition: transform .12s ease, box-shadow .12s ease; }
    .koi-press:active { transform: scale(.975); }
    .koi-private .koi-fig { filter: blur(8px); transition: filter .2s; }
    @media (prefers-reduced-motion: no-preference) {
      .koi-stagger > * { animation: koiRise .5s cubic-bezier(0.2,0,0,1) both; }
      .koi-stagger > *:nth-child(1){animation-delay:.03s}
      .koi-stagger > *:nth-child(2){animation-delay:.07s}
      .koi-stagger > *:nth-child(3){animation-delay:.12s}
      .koi-stagger > *:nth-child(4){animation-delay:.17s}
      .koi-stagger > *:nth-child(5){animation-delay:.22s}
      .koi-stagger > *:nth-child(6){animation-delay:.27s}
      .koi-stagger > *:nth-child(7){animation-delay:.32s}
      .koi-stagger > *:nth-child(8){animation-delay:.37s}
      .koi-stagger > *:nth-child(n+9){animation-delay:.42s}
    }
  `;
  document.head.appendChild(s);
})();

// —— card shell: hairline + warm layered shadow + faint top sheen ——
const PCard = ({ children, pad = 16, style = {}, glow = false }) => {
  const c = PC();
  return (
    <div className="koi-press" style={{
      position: 'relative', background: c.surfaceElevated, borderRadius: 16,
      border: `1px solid ${c.border}`,
      boxShadow: glow
        ? '0 1px 2px rgba(80,60,40,0.05), 0 10px 24px -12px rgba(176,133,95,0.35)'
        : '0 1px 2px rgba(80,60,40,0.04), 0 8px 20px -14px rgba(80,60,40,0.30)',
      padding: pad, height: '100%', overflow: 'hidden', ...style,
    }}>
      <div style={{ position: 'absolute', inset: 0, borderRadius: 16, boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.6)', pointerEvents: 'none' }} />
      {children}
    </div>
  );
};

const PLabel = ({ children, icon, accent = false }) => {
  const c = PC();
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11, fontWeight: 600, letterSpacing: '0.09em', color: accent ? c.koiGoldDark : c.ts, fontFamily: PSANS, textTransform: 'uppercase' }}>
      {icon && <Icon name={icon} size={13} color={accent ? c.koiGoldDark : c.ts} />}{children}
    </div>
  );
};

// delta chip with soft tint
const Delta = ({ up = true, children, size = 12 }) => {
  const c = PC();
  const col = up ? c.success : c.danger;
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 3, padding: '3px 8px', borderRadius: 99, background: up ? 'rgba(74,155,111,0.10)' : 'rgba(201,74,74,0.10)', color: col, fontSize: size, fontWeight: 600, fontVariantNumeric: 'tabular-nums' }}>
      <span style={{ fontSize: size - 2 }}>{up ? '▲' : '▼'}</span>{children}
    </span>
  );
};

// gradient ring with soft glow + rounded cap
const PRing = ({ pct, size = 56, stroke = 5, from = '#D8B098', to = '#B0855F', track, children }) => {
  const c = PC();
  const id = uid();
  const r = size / 2 - stroke;
  const circ = 2 * Math.PI * r;
  return (
    <div style={{ position: 'relative', width: size, height: size, flexShrink: 0 }}>
      <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ overflow: 'visible' }}>
        <defs>
          <linearGradient id={id} x1="0" y1="0" x2="1" y2="1">
            <stop offset="0%" stopColor={from} /><stop offset="100%" stopColor={to} />
          </linearGradient>
        </defs>
        <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke={track || c.n200} strokeWidth={stroke} />
        <circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke={`url(#${id})`} strokeWidth={stroke}
          strokeDasharray={`${pct * circ} ${circ}`} strokeLinecap="round"
          transform={`rotate(-90 ${size / 2} ${size / 2})`}
          style={{ filter: `drop-shadow(0 1px 3px ${to}66)` }} />
      </svg>
      <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{children}</div>
    </div>
  );
};

// area sparkline with gradient fill + glowing endpoint
const PSpark = ({ from = '#4A9B6F', h = 44, area = true, glow = true, pts }) => {
  const id = uid();
  const line = pts || 'M0 38 C40 36 70 30 110 27 S190 18 300 8';
  const endM = (pts || line).match(/([\d.]+)\s+([\d.]+)\s*$/);
  const ex = endM ? parseFloat(endM[1]) : 300;
  const ey = endM ? parseFloat(endM[2]) : 8;
  return (
    <svg width="100%" height={h} viewBox={`0 0 300 ${h}`} preserveAspectRatio="none" style={{ overflow: 'visible' }}>
      <defs>
        <linearGradient id={id} x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%" stopColor={from} stopOpacity="0.26" /><stop offset="100%" stopColor={from} stopOpacity="0" />
        </linearGradient>
      </defs>
      {area && <path d={`${line} L300 ${h} L0 ${h} Z`} fill={`url(#${id})`} />}
      <path d={line} fill="none" stroke={from} strokeWidth="2" strokeLinecap="round" />
      {glow && <circle cx={ex} cy={ey} r="3.2" fill={from} style={{ filter: `drop-shadow(0 0 5px ${from})` }} />}
      {glow && <circle cx={ex} cy={ey} r="6" fill={from} opacity="0.18" />}
    </svg>
  );
};

const PPeriods = ({ sel = 2 }) => {
  const c = PC();
  return (
    <div style={{ display: 'flex', gap: 4 }}>
      {['1D', '1W', '1M', '3M', '6M', '1Y'].map((p, i) => (
        <div key={p} style={{ flex: 1, textAlign: 'center', fontSize: 11.5, padding: '6px 0', borderRadius: 8, background: i === sel ? 'rgba(201,152,126,0.14)' : 'transparent', color: i === sel ? c.koiGoldDark : c.ts, fontWeight: i === sel ? 700 : 500 }}>{p}</div>
      ))}
    </div>
  );
};

// count-up animation for money figures (ease-out cubic)
const Count = ({ value, dur = 950, decimals = 0 }) => {
  // Init to target so an off-screen/throttled iframe (website hero) never shows a stuck 0.
  // When on-screen, the rAF below fires and animates 0→value normally.
  const [v, setV] = React.useState(value);
  React.useEffect(() => {
    let raf; const t0 = performance.now();
    const tick = (t) => { const p = Math.min(1, (t - t0) / dur); const e = 1 - Math.pow(1 - p, 3); setV(value * e); if (p < 1) raf = requestAnimationFrame(tick); };
    raf = requestAnimationFrame(tick); return () => cancelAnimationFrame(raf);
  }, [value]);
  return <span>{v.toLocaleString('en-US', { minimumFractionDigits: decimals, maximumFractionDigits: decimals })}</span>;
};

// ============================================================================
// ADD TRANSACTION — hero launchpad (the gradient moment)
// ============================================================================
const brandBg = () => window.__koiTheme === 'dark'
  ? 'linear-gradient(135deg,#B58A64 0%,#8A6547 52%,#664A34 100%)'
  : PGRAD;
const wAddExpense = (size) => {
  const compact = size === 'S';
  const GB = brandBg();
  const Plus = ({ s }) => (
    <div style={{ position: 'relative', width: s, height: s, borderRadius: 99, flexShrink: 0, background: 'radial-gradient(120% 120% at 30% 20%, rgba(255,255,255,0.42), rgba(255,255,255,0.14))', display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: 'inset 0 1px 1px rgba(255,255,255,0.6), inset 0 -2px 4px rgba(120,80,50,0.25)' }}>
      <div style={{ position: 'absolute', inset: -3, borderRadius: 99, border: '1.5px solid rgba(255,255,255,0.28)', animation: 'koiPulse 3.4s ease-in-out infinite' }} />
      <Icon name="plus" size={s * 0.5} color="#fff" strokeWidth={2.4} />
    </div>
  );
  if (compact) return (
    <div style={{ position: 'relative', height: '100%', borderRadius: 16, background: GB, overflow: 'hidden', boxShadow: '0 8px 22px -10px rgba(176,133,95,0.6)', padding: '14px', display: 'flex', alignItems: 'center', gap: 12 }}>
      <div style={{ position: 'absolute', top: -30, right: -30, width: 90, height: 90, borderRadius: 99, border: '1px solid rgba(255,255,255,0.18)' }} />
      <Plus s={38} />
      <div style={{ color: '#fff', fontSize: 15, fontWeight: 700, letterSpacing: '-0.01em' }}>Add</div>
    </div>
  );
  return (
    <div style={{ position: 'relative', borderRadius: 18, background: GB, overflow: 'hidden', boxShadow: '0 14px 30px -12px rgba(176,133,95,0.65)' }}>
      {/* decorative koi ripples */}
      <div style={{ position: 'absolute', top: -46, right: -34, width: 150, height: 150, borderRadius: 99, border: '1px solid rgba(255,255,255,0.16)' }} />
      <div style={{ position: 'absolute', top: -20, right: -8, width: 96, height: 96, borderRadius: 99, border: '1px solid rgba(255,255,255,0.13)' }} />
      {/* sheen sweep */}
      <div style={{ position: 'absolute', inset: 0, overflow: 'hidden' }}>
        <div style={{ position: 'absolute', top: 0, bottom: 0, width: 60, background: 'linear-gradient(90deg,transparent,rgba(255,255,255,0.22),transparent)', animation: 'koiSheen 6s ease-in-out infinite', animationDelay: '1s' }} />
      </div>
      <div style={{ position: 'relative', padding: '15px 16px' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 13 }}>
          <Plus s={46} />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 16, fontWeight: 700, color: '#fff', letterSpacing: '-0.01em' }}>Add a transaction</div>
            <div style={{ fontSize: 12.5, color: 'rgba(255,255,255,0.82)', marginTop: 1 }}>Log spending in a tap</div>
          </div>
          <Icon name="mic" size={18} color="rgba(255,255,255,0.9)" />
        </div>
        {/* quick actions */}
        <div style={{ display: 'flex', gap: 8, marginTop: 13 }}>
          {[['arrowD', 'Expense'], ['arrowU', 'Income'], ['camera', 'Scan']].map(([ic, t]) => (
            <div key={t} style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 5, padding: '9px 0', borderRadius: 11, background: 'rgba(255,255,255,0.16)', border: '1px solid rgba(255,255,255,0.14)', color: '#fff', fontSize: 12.5, fontWeight: 600, backdropFilter: 'blur(4px)' }}>
              <Icon name={ic} size={13} color="#fff" strokeWidth={2.2} />{t}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
};

// ============================================================================
// NET WORTH  (Large = live period pills)
// ============================================================================
const NW_PERIODS = [
  { k: '1D', label: 'today', delta: '0.3%', up: true, pts: 'M0 30 L50 34 L100 26 L150 33 L200 23 L250 29 L300 21' },
  { k: '1W', label: '7 days', delta: '1.1%', up: true, pts: 'M0 40 L60 37 L120 39 L180 31 L240 27 L300 24' },
  { k: '1M', label: '30 days', delta: '₴4,280', up: true, pts: 'M0 46 C40 44 70 36 110 32 S190 20 300 10' },
  { k: '3M', label: '3 months', delta: '5.8%', up: true, pts: 'M0 50 C60 48 120 40 180 30 S260 14 300 8' },
  { k: '6M', label: '6 months', delta: '9.2%', up: true, pts: 'M0 52 C70 50 130 44 190 28 S270 12 300 6' },
  { k: '1Y', label: '1 year', delta: '14.6%', up: true, pts: 'M0 54 C80 52 140 42 200 22 S280 8 300 4' },
];
const NetWorthLive = () => {
  const c = PC();
  const [pi, setPi] = React.useState(2);
  const p = NW_PERIODS[pi];
  return (
    <PCard pad={18}>
      <div style={{ display: 'flex', alignItems: 'center' }}><PLabel>Net worth</PLabel><div style={{ flex: 1 }} /><Icon name="info" size={14} color={c.n300} /></div>
      <div style={{ display: 'flex', alignItems: 'flex-end', gap: 10, marginTop: 6 }}>
        <div style={{ fontFamily: PSERIF, fontSize: 54, fontWeight: 300, lineHeight: 0.92, color: c.n900, letterSpacing: '-0.015em', fontVariantNumeric: 'tabular-nums' }}>
          <span style={{ fontSize: 30, color: c.ts, marginRight: 6 }}>₴</span><span className="koi-fig"><Count value={142800} /></span>
        </div>
        <div style={{ paddingBottom: 4 }}><Delta up={p.up}>{p.delta}</Delta></div>
      </div>
      <div style={{ marginTop: 14, marginLeft: -2, marginRight: -2 }}><PSpark from={c.success} h={56} pts={p.pts} /></div>
      <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: c.n300, margin: '2px 2px 12px' }}><span>past {p.label}</span><span>today</span></div>
      <div style={{ display: 'flex', gap: 4 }}>
        {NW_PERIODS.map((x, i) => (
          <div key={x.k} onClick={() => setPi(i)} className="koi-press" style={{ cursor: 'pointer', flex: 1, textAlign: 'center', fontSize: 11.5, padding: '6px 0', borderRadius: 8, background: i === pi ? 'rgba(201,152,126,0.16)' : 'transparent', color: i === pi ? c.koiGoldDark : c.ts, fontWeight: i === pi ? 700 : 500 }}>{x.k}</div>
        ))}
      </div>
    </PCard>
  );
};
const wNetWorth = (size) => {
  const c = PC();
  if (size === 'L') return <NetWorthLive />;
  if (size === 'S') return (
    <PCard pad={15}>
      <PLabel>Net worth</PLabel>
      <div style={{ fontFamily: PSERIF, fontSize: 30, fontWeight: 300, color: c.n900, marginTop: 6, lineHeight: 0.95, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.01em' }}><span className="koi-fig">₴142.8<span style={{ fontSize: 18, color: c.ts }}>k</span></span></div>
      <div style={{ marginTop: 8 }}><Delta up>2.4%</Delta></div>
    </PCard>
  );
  return (
    <PCard pad={18}>
      <div style={{ display: 'flex', alignItems: 'center' }}><PLabel>Net worth</PLabel><div style={{ flex: 1 }} /><Icon name="info" size={14} color={c.n300} /></div>
      <div style={{ display: 'flex', alignItems: 'flex-end', gap: 10, marginTop: 6 }}>
        <div style={{ fontFamily: PSERIF, fontSize: 40, fontWeight: 300, lineHeight: 0.92, color: c.n900, letterSpacing: '-0.015em', fontVariantNumeric: 'tabular-nums' }}>
          <span style={{ fontSize: 24, color: c.ts, marginRight: 6 }}>₴</span><span className="koi-fig"><Count value={142800} /></span>
        </div>
        <div style={{ paddingBottom: 4 }}><Delta up>2.4%</Delta></div>
      </div>
      <div style={{ fontSize: 12, color: c.ts, marginTop: 6 }}>▲ ₴4,280 over 30 days</div>
      <div style={{ marginTop: 10, marginLeft: -2, marginRight: -2 }}><PSpark from={c.success} h={40} /></div>
    </PCard>
  );
};

// ============================================================================
// CASH FLOW
// ============================================================================
const wCashFlow = (size) => {
  const c = PC();
  if (size === 'S') return (
    <PCard pad={15}>
      <PLabel>Cash flow</PLabel>
      <div style={{ fontFamily: PSERIF, fontSize: 28, fontWeight: 400, color: c.success, marginTop: 6, lineHeight: 1 }}>+₴21.9<span style={{ fontSize: 17 }}>k</span></div>
      <div style={{ fontSize: 11, color: c.ts, marginTop: 5 }}>net this month</div>
    </PCard>
  );
  const flowRow = (
    <div style={{ display: 'flex', gap: 10, marginTop: 12 }}>
      {[['Income', '₴54,000', c.success, 'arrowU'], ['Expenses', '₴32,140', c.danger, 'arrowD']].map(([l, v, col, ic]) => (
        <div key={l} style={{ flex: 1, padding: '10px 12px', borderRadius: 12, background: c.n50, border: `1px solid ${c.border}` }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11.5, color: c.ts }}>
            <span style={{ width: 16, height: 16, borderRadius: 99, background: col + '22', display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}><Icon name={ic} size={10} color={col} strokeWidth={2.4} /></span>{l}
          </div>
          <div style={{ fontSize: 18, fontWeight: 700, marginTop: 5, color: c.n900, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.01em' }}>{v}</div>
        </div>
      ))}
    </div>
  );
  return (
    <PCard pad={16}>
      <div style={{ display: 'flex', alignItems: 'center' }}><PLabel>Cash flow</PLabel><div style={{ flex: 1 }} /><span style={{ fontSize: 12, fontWeight: 700, color: c.success, fontVariantNumeric: 'tabular-nums' }}>+₴21,860</span></div>
      {flowRow}
      {size === 'L' && (
        <div style={{ display: 'flex', gap: 10, alignItems: 'flex-end', height: 96, marginTop: 16, paddingBottom: 18, position: 'relative' }}>
          {[[3200, 2400], [3400, 2800], [4100, 2600], [5100, 3400], [4800, 2900], [5400, 3120]].map(([inc, exp], i) => (
            <div key={i} style={{ flex: 1, display: 'flex', justifyContent: 'center', gap: 3, alignItems: 'flex-end', position: 'relative' }}>
              <div style={{ width: 9, height: inc / 62, background: 'linear-gradient(180deg,#5FB68A,#4A9B6F)', borderRadius: 3 }} />
              <div style={{ width: 9, height: exp / 62, background: 'linear-gradient(180deg,#D66A6A,#C94A4A)', borderRadius: 3 }} />
              <div style={{ position: 'absolute', bottom: -16, fontSize: 9.5, color: c.n400 }}>{['Nov', 'Dec', 'Jan', 'Feb', 'Mar', 'Apr'][i]}</div>
            </div>
          ))}
        </div>
      )}
    </PCard>
  );
};

// ============================================================================
// BUDGET
// ============================================================================
const wBudget = (size) => {
  const c = PC();
  if (size === 'S') return (
    <PCard pad={15}>
      <PLabel>Budget</PLabel>
      <div style={{ display: 'flex', alignItems: 'center', gap: 11, marginTop: 8 }}>
        <PRing pct={0.72} size={42} stroke={5} from="#5FB68A" to="#3A9B6F"><span style={{ fontSize: 13, fontWeight: 700, color: c.success }}>72</span></PRing>
        <div><div style={{ fontSize: 13, fontWeight: 700, color: c.n900 }}>Good</div><div style={{ fontSize: 11, color: c.ts }}>3 of 6 on track</div></div>
      </div>
    </PCard>
  );
  return (
    <PCard pad={16}>
      <PLabel>Quick budget</PLabel>
      <div style={{ display: 'flex', alignItems: 'center', gap: 16, marginTop: 12 }}>
        <PRing pct={0.72} size={62} stroke={6} from="#5FB68A" to="#3A9B6F"><div style={{ textAlign: 'center' }}><div style={{ fontFamily: PSERIF, fontSize: 22, color: c.success, lineHeight: 1 }}>72</div></div></PRing>
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 15, fontWeight: 700, color: c.n900 }}>Good shape</div>
          <div style={{ display: 'flex', gap: 6, marginTop: 8, flexWrap: 'wrap' }}>
            <Pill size="sm" bg="rgba(74,155,111,0.12)" color={c.success} bold>3 on track</Pill>
            <Pill size="sm" bg="rgba(212,133,58,0.12)" color="#C9872A" bold>2 close</Pill>
            <Pill size="sm" bg="rgba(201,74,74,0.12)" color={c.danger} bold>1 over</Pill>
          </div>
        </div>
      </div>
      {size === 'L' && (
        <div style={{ marginTop: 16, display: 'flex', flexDirection: 'column', gap: 11 }}>
          {[['Groceries', 0.92, c.danger], ['Transport', 0.78, '#C9872A'], ['Dining', 0.45, c.success]].map(([n, p, col]) => (
            <div key={n}>
              <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12, color: c.n700, fontWeight: 500 }}><span>{n}</span><span style={{ color: col, fontWeight: 700, fontVariantNumeric: 'tabular-nums' }}>{Math.round(p * 100)}%</span></div>
              <div style={{ height: 6, borderRadius: 99, background: c.n100, marginTop: 5, overflow: 'hidden' }}><div style={{ width: `${p * 100}%`, height: '100%', borderRadius: 99, background: `linear-gradient(90deg,${col}bb,${col})` }} /></div>
            </div>
          ))}
        </div>
      )}
    </PCard>
  );
};

// ============================================================================
// PORTFOLIO
// ============================================================================
const ALLOC = [['Stocks', 50, '#B0855F'], ['Crypto', 25, '#5E9E86'], ['Bonds', 15, '#7A95B8'], ['Other', 10, '#9B84C4']];
const wPortfolio = (size) => {
  const c = PC();
  if (size === 'S') return (
    <PCard pad={15}>
      <PLabel>Portfolio</PLabel>
      <div style={{ fontFamily: PSERIF, fontSize: 24, color: c.n900, marginTop: 6, lineHeight: 1 }}>₴284.5<span style={{ fontSize: 15, color: c.ts }}>k</span></div>
      <div style={{ marginTop: 8 }}><Delta up>12.4%</Delta></div>
    </PCard>
  );
  const bar = (
    <div style={{ display: 'flex', height: 12, borderRadius: 99, overflow: 'hidden', marginTop: 13, gap: 2, boxShadow: 'inset 0 1px 2px rgba(0,0,0,0.06)' }}>
      {ALLOC.map(([n, p, col]) => <div key={n} style={{ flex: p, background: `linear-gradient(180deg,${col}dd,${col})` }} />)}
    </div>
  );
  return (
    <PCard pad={16}>
      <div style={{ display: 'flex', alignItems: 'baseline' }}><PLabel>Portfolio</PLabel><div style={{ flex: 1 }} /><Delta up>12.4%</Delta></div>
      <div style={{ fontFamily: PSERIF, fontSize: 26, fontWeight: 400, color: c.n900, marginTop: 6, letterSpacing: '-0.01em' }}><span className="koi-fig">₴284,500</span></div>
      {size === 'L' && <div style={{ marginTop: 8, marginLeft: -2, marginRight: -2 }}><PSpark from="#B0855F" h={44} /></div>}
      {bar}
      <div style={{ display: 'flex', gap: 12, marginTop: 11, flexWrap: 'wrap' }}>
        {ALLOC.map(([n, p, col]) => (
          <span key={n} style={{ fontSize: 11, color: c.ts, display: 'inline-flex', alignItems: 'center', gap: 5 }}><span style={{ width: 7, height: 7, borderRadius: 99, background: col }} />{n} {p}%</span>
        ))}
      </div>
    </PCard>
  );
};

// ============================================================================
// GOALS
// ============================================================================
const GOALS = [['Emergency Fund', 4200, 10000, 0.42, 'on track'], ['Vacation', 1200, 3000, 0.40, 'on track'], ['New Laptop', 800, 2500, 0.32, 'behind']];
const wGoals = (size) => {
  const c = PC();
  if (size === 'S') {
    const rings = [[0.42, '#B0855F'], [0.40, '#C9987E'], [0.32, '#D8B098']];
    return (
      <PCard pad={15}>
        <PLabel>Goals</PLabel>
        <div style={{ display: 'flex', alignItems: 'center', gap: 11, marginTop: 8 }}>
          <div style={{ position: 'relative', width: 46, height: 46, flexShrink: 0 }}>
            <svg width={46} height={46} viewBox="0 0 46 46">
              {rings.map(([pp, col], i) => { const r = 21 - i * 7; const circ = 2 * Math.PI * r; return (
                <g key={i} transform="rotate(-90 23 23)">
                  <circle cx="23" cy="23" r={r} fill="none" stroke={c.n200} strokeWidth="3.5" />
                  <circle cx="23" cy="23" r={r} fill="none" stroke={col} strokeWidth="3.5" strokeLinecap="round" strokeDasharray={`${pp * circ} ${circ}`} />
                </g>
              ); })}
            </svg>
            <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 12, fontWeight: 700, color: c.n900 }}>3</div>
          </div>
          <div style={{ minWidth: 0 }}>
            <div style={{ fontSize: 13, fontWeight: 600, color: c.n900 }}>3 goals</div>
            <div style={{ fontSize: 11, color: c.ts }}>38% funded</div>
          </div>
        </div>
      </PCard>
    );
  }
  return (
    <PCard pad={16}>
      <PLabel>Goals</PLabel>
      <div style={{ marginTop: 8, display: 'flex', flexDirection: 'column', gap: 4 }}>
        {GOALS.map(([n, cur, tgt, p, tag], i) => (
          <div key={n}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 13, padding: '8px 0' }}>
              <PRing pct={p} size={46} stroke={4}><span style={{ fontSize: 11, fontWeight: 700, color: c.n900 }}>{Math.round(p * 100)}%</span></PRing>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <div style={{ fontSize: 14, fontWeight: 600, color: c.n900 }}>{n}</div>
                  <Pill size="sm" bg={tag === 'behind' ? 'rgba(201,135,42,0.12)' : 'rgba(74,155,111,0.12)'} color={tag === 'behind' ? '#C9872A' : c.success} bold>{tag}</Pill>
                </div>
                <div style={{ fontSize: 12, color: c.ts, marginTop: 3, fontVariantNumeric: 'tabular-nums' }}>₴{fmt(cur)} <span style={{ color: c.n300 }}>/ ₴{fmt(tgt)}</span></div>
              </div>
            </div>
            {i < GOALS.length - 1 && <div style={{ height: 1, background: c.border, opacity: 0.7 }} />}
          </div>
        ))}
      </div>
    </PCard>
  );
};

// ============================================================================
// FINANCIAL HEALTH
// ============================================================================
const DIMS = [['Emergency fund', 38, '#C94A4A'], ['Debt', 55, '#C9872A'], ['Spending', 72, '#8FB339'], ['Savings', 80, '#4A9B6F'], ['Goals', 84, '#3A9B6F']];
const wHealth = (size) => {
  const c = PC();
  if (size === 'S') return (
    <PCard pad={15}>
      <PLabel>Health</PLabel>
      <div style={{ display: 'flex', alignItems: 'center', gap: 11, marginTop: 6 }}>
        <PRing pct={0.78} size={46} stroke={6} from="#A7C34F" to="#6E9E2E"><span style={{ fontFamily: PSERIF, fontSize: 18, color: '#7DA82E' }}>78</span></PRing>
        <div style={{ fontSize: 12, color: c.n700, lineHeight: 1.25, fontWeight: 500 }}>On the right<br />track</div>
      </div>
    </PCard>
  );
  return (
    <PCard pad={16}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
        <PRing pct={0.78} size={66} stroke={8} from="#A7C34F" to="#6E9E2E"><span style={{ fontFamily: PSERIF, fontSize: 26, color: '#7DA82E' }}>78</span></PRing>
        <div style={{ flex: 1 }}>
          <PLabel icon="heart">Financial health</PLabel>
          <div style={{ fontFamily: PSERIF, fontSize: 22, color: c.n900, marginTop: 2, letterSpacing: '-0.01em' }}>On the right track</div>
        </div>
      </div>
      <div style={{ marginTop: 15, display: 'flex', flexDirection: 'column', gap: 9 }}>
        {DIMS.map(([n, v, col]) => (
          <div key={n} style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <div style={{ width: 92, fontSize: 11, color: c.ts, fontWeight: 600, letterSpacing: '0.02em' }}>{n}</div>
            <div style={{ flex: 1, height: 6, borderRadius: 99, background: c.n100, overflow: 'hidden' }}><div style={{ width: `${v}%`, height: '100%', borderRadius: 99, background: `linear-gradient(90deg,${col}aa,${col})` }} /></div>
            <div style={{ width: 30, textAlign: 'right', fontSize: 11, color: c.n900, fontWeight: 700, fontVariantNumeric: 'tabular-nums' }}>{v}%</div>
          </div>
        ))}
      </div>
    </PCard>
  );
};

// ============================================================================
// WATCHLIST
// ============================================================================
const WL = [['AAPL', 'NASDAQ', '$228.40', 1.2, 'M8 20 L14 15 L20 17 L26 9 L32 12'], ['BTC', 'crypto', '$68,120', -2.4, 'M8 10 L14 13 L20 11 L26 16 L32 18'], ['TSLA', 'NASDAQ', '$251.10', 3.1, 'M8 19 L14 16 L20 14 L26 11 L32 6'], ['ETH', 'crypto', '$3,540', 0.8, 'M8 14 L14 13 L20 15 L26 11 L32 12']];
const wWatchlist = (size) => {
  const c = PC();
  if (size === 'S') {
    const [s, k, p, ch] = WL[0];
    return (
      <PCard pad={15}>
        <PLabel icon="eye">Watchlist</PLabel>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginTop: 8 }}>
          <div style={{ fontSize: 15, fontWeight: 700, color: c.n900 }}>{s}</div>
          <div style={{ fontSize: 12, color: c.ts, flex: 1, fontVariantNumeric: 'tabular-nums' }}>{p}</div>
        </div>
        <div style={{ marginTop: 6 }}><Delta up={ch >= 0} size={11}>{Math.abs(ch)}%</Delta></div>
      </PCard>
    );
  }
  return (
    <PCard pad={16}>
      <div style={{ display: 'flex', alignItems: 'center' }}><PLabel icon="eye">Watchlist</PLabel><div style={{ flex: 1 }} /><Icon name="chevR" size={16} color={c.n300} /></div>
      <div style={{ marginTop: 8 }}>
        {WL.map(([s, k, p, ch, spark], i) => {
          const up = ch >= 0; const col = up ? c.success : c.danger;
          return (
            <div key={s} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '9px 0', borderTop: i ? `1px solid ${c.border}` : 'none' }}>
              <div style={{ width: 40 }}><div style={{ fontSize: 14, fontWeight: 700, color: c.n900 }}>{s}</div><div style={{ fontSize: 10, color: c.n400 }}>{k}</div></div>
              <svg width="40" height="26" viewBox="0 0 40 26" style={{ overflow: 'visible' }}><path d={spark} fill="none" stroke={col} strokeWidth="1.6" strokeLinecap="round" /></svg>
              <div style={{ flex: 1, textAlign: 'right', fontSize: 13.5, color: c.n900, fontVariantNumeric: 'tabular-nums', fontWeight: 500 }}>{p}</div>
              <div style={{ width: 58, textAlign: 'right' }}><Delta up={up} size={11}>{Math.abs(ch)}%</Delta></div>
            </div>
          );
        })}
      </div>
    </PCard>
  );
};

// ============================================================================
// WISDOM
// ============================================================================
const wWisdom = () => {
  const c = PC();
  const dark = (window.__koiTheme === 'dark');
  return (
    <PCard pad={18} style={{ background: dark ? 'linear-gradient(160deg,#262220,#2C2622)' : 'linear-gradient(160deg,#FFFDFA,#FBF5EE)' }}>
      <div style={{ position: 'absolute', top: 4, left: 14, fontFamily: PSERIF, fontSize: 60, color: 'rgba(201,152,126,0.22)', lineHeight: 1 }}>&ldquo;</div>
      <div style={{ display: 'flex' }}><PLabel accent>Wisdom of the day</PLabel><div style={{ flex: 1 }} /><Icon name="bookmark" size={15} color={c.koiGold} /></div>
      <div style={{ fontFamily: PSERIF, fontStyle: 'italic', fontSize: 19, color: c.n900, marginTop: 10, lineHeight: 1.4, position: 'relative' }}>Do not save what is left after spending, but spend what is left after saving.</div>
      <div style={{ fontSize: 12, color: c.ts, marginTop: 10, fontWeight: 500 }}>— Warren Buffett</div>
    </PCard>
  );
};

// ============================================================================
// NEWS BRIEF
// ============================================================================
const wNews = (size) => {
  const c = PC();
  if (size === 'S') return (
    <PCard pad={15}>
      <PLabel icon="compass">Today's brief</PLabel>
      <div style={{ fontSize: 13, color: c.n900, marginTop: 8, lineHeight: 1.4, fontWeight: 600 }}>Markets edge up; UAH steady</div>
      <div style={{ fontSize: 11, color: c.koiGoldDark, marginTop: 5, fontWeight: 600 }}>Read →</div>
    </PCard>
  );
  return (
    <PCard pad={16}>
      <div style={{ display: 'flex', alignItems: 'center' }}><PLabel icon="compass">Today's brief</PLabel><div style={{ flex: 1 }} /><Pill size="sm" bg={c.n100} color={c.ts}>Markets</Pill></div>
      <div style={{ fontSize: 14.5, color: c.n900, marginTop: 9, lineHeight: 1.45, fontWeight: 600 }}>Markets edge up on rate-cut hopes; the hryvnia holds steady against the dollar.</div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 12, color: c.ts, marginTop: 8 }}>3 stories · 2 min read <div style={{ flex: 1 }} /><span style={{ color: c.koiGoldDark, fontWeight: 600 }}>Read →</span></div>
    </PCard>
  );
};

// ============================================================================
// REPORTS
// ============================================================================
// warm heat scale n100 → koiGold-dark
const heatCol = (t) => {
  const dark = (window.__koiTheme === 'dark');
  const a = dark ? [48, 44, 40] : [243, 235, 225], b = [176, 133, 95];
  const l = (i) => Math.round(a[i] + (b[i] - a[i]) * t);
  return `rgb(${l(0)},${l(1)},${l(2)})`;
};
const wReports = (size) => {
  const c = PC();
  if (size === 'S') return (
    <PCard pad={15}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <div style={{ width: 36, height: 36, borderRadius: 12, background: 'linear-gradient(150deg,#FBF1E8,#F3E2D2)', border: `1px solid ${c.border}`, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><Icon name="chart" size={17} color={c.koiGoldDark} /></div>
        <div style={{ flex: 1, minWidth: 0 }}><div style={{ fontSize: 13, fontWeight: 700, color: c.n900 }}>Reports</div></div>
        <Icon name="chevR" size={18} color={c.n300} />
      </div>
    </PCard>
  );
  // Insight card: a headline auto-insight + supporting mini chart + report shortcuts
  return (
    <PCard pad={16}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <div style={{ width: 40, height: 40, borderRadius: 12, background: 'linear-gradient(150deg,#FBF1E8,#F3E2D2)', border: `1px solid ${c.border}`, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><Icon name="bulb" size={19} color={c.koiGoldDark} /></div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 15, fontWeight: 700, color: c.n900 }}>Reports &amp; insights</div>
          <div style={{ fontSize: 12, color: c.ts, marginTop: 1 }}>this month's highlight · 12 reports</div>
        </div>
        <Icon name="chevR" size={18} color={c.n300} />
      </div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginTop: 14 }}>
        <div style={{ flex: 1 }}>
          <div style={{ fontFamily: PSERIF, fontSize: 19, fontStyle: 'italic', color: c.n900, lineHeight: 1.3 }}>Groceries is up <span style={{ color: c.danger, fontStyle: 'normal', fontWeight: 600 }}>16%</span> vs March.</div>
          <div style={{ fontSize: 12, color: c.ts, marginTop: 6, fontVariantNumeric: 'tabular-nums' }}><span className="koi-fig">₴11,200</span> · your biggest category</div>
        </div>
        <div style={{ width: 76, height: 44, flexShrink: 0 }}><svg width="76" height="44" viewBox="0 0 76 44" style={{ overflow: 'visible' }}><defs><linearGradient id="rpf" x1="0" x2="0" y1="0" y2="1"><stop offset="0%" stopColor="#C94A4A" stopOpacity="0.24" /><stop offset="100%" stopColor="#C94A4A" stopOpacity="0" /></linearGradient></defs><path d="M0 34 L19 30 L38 32 L57 22 L76 10 L76 44 L0 44Z" fill="url(#rpf)" /><path d="M0 34 L19 30 L38 32 L57 22 L76 10" fill="none" stroke="#C94A4A" strokeWidth="2" strokeLinecap="round" /><circle cx="76" cy="10" r="3" fill="#C94A4A" style={{ filter: 'drop-shadow(0 0 4px #C94A4A)' }} /></svg></div>
      </div>
      <div style={{ display: 'flex', gap: 6, marginTop: 14, overflowX: 'auto' }}>
        {[['chart', 'Spending'], ['wallet', 'Net worth'], ['trendingUp', 'Gains'], ['piggy', 'Cash flow']].map(([ic, t]) => (
          <div key={t} className="koi-press" style={{ display: 'flex', alignItems: 'center', gap: 5, padding: '7px 11px', borderRadius: 99, background: c.n50, border: `1px solid ${c.border}`, fontSize: 12, fontWeight: 600, color: c.n700, whiteSpace: 'nowrap', flexShrink: 0, cursor: 'pointer' }}><Icon name={ic} size={12} color={c.koiGoldDark} />{t}</div>
        ))}
      </div>
    </PCard>
  );
};

// ============================================================================
// MASCOT / COACH — the second gradient moment (soft)
// ============================================================================
const wMascot = () => {
  const c = PC();
  const dark = (window.__koiTheme === 'dark');
  return (
    <div style={{ position: 'relative', padding: 16, borderRadius: 24, overflow: 'hidden', background: dark ? 'linear-gradient(140deg,#2B2420 0%,#352A22 100%)' : 'linear-gradient(140deg,#FDF3EA 0%,#F8E7D6 100%)', border: dark ? '1px solid rgba(201,152,126,0.38)' : '1px solid rgba(201,152,126,0.28)', boxShadow: '0 10px 24px -16px rgba(176,133,95,0.5)' }}>
      <div style={{ position: 'absolute', top: -26, right: -26, width: 96, height: 96, borderRadius: 99, background: 'radial-gradient(circle,rgba(201,152,126,0.22),transparent 70%)' }} />
      <div style={{ display: 'flex', gap: 13, position: 'relative' }}>
        <div style={{ position: 'relative', width: 50, height: 50, flexShrink: 0 }}>
          <div style={{ position: 'absolute', inset: -3, borderRadius: 99, background: 'conic-gradient(from 120deg,#D8B098,#C9987E,#B0855F,#D8B098)', opacity: 0.5, animation: 'koiPulse 4s ease-in-out infinite' }} />
          <div style={{ position: 'absolute', inset: 0, borderRadius: 99, background: dark ? 'rgba(255,255,255,0.12)' : 'rgba(255,255,255,0.7)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 27, overflow: 'hidden' }}>{window.KOI_MASCOT_SRC ? <img src={window.KOI_MASCOT_SRC} alt="KoiFi" style={{ width: '86%', height: '86%', objectFit: 'contain' }} /> : <span style={{ display: 'inline-block', animation: 'koiWiggle 5s ease-in-out infinite' }}>🐟</span>}</div>
        </div>
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 10, fontWeight: 700, letterSpacing: '0.12em', color: c.koiGoldDark }}>KOIFI · LV 3</div>
          <div style={{ fontSize: 13.5, lineHeight: 1.5, color: c.n900, marginTop: 3 }}>You stayed under your Dining budget 3 weeks running. Nice work!</div>
          <div style={{ marginTop: 9, display: 'inline-flex', alignItems: 'center', gap: 5, fontSize: 13, fontWeight: 700, color: c.koiGoldDark }}>See details <Icon name="arrowR" size={13} color={c.koiGoldDark} strokeWidth={2.2} /></div>
        </div>
      </div>
    </div>
  );
};

// ============================================================================
// REGISTRY
// ============================================================================
const WIDGETS = {
  add_expense:      { title: 'Add a transaction', icon: 'plus',       sizes: ['S', 'M'],       render: wAddExpense },
  net_worth:        { title: 'Net worth',          icon: 'wallet',     sizes: ['S', 'M', 'L'],  render: wNetWorth },
  cash_flow:        { title: 'Cash flow',          icon: 'arrowU',     sizes: ['S', 'M', 'L'],  render: wCashFlow },
  budget:           { title: 'Budget pulse',       icon: 'piggy',      sizes: ['S', 'M', 'L'],  render: wBudget },
  portfolio:        { title: 'Portfolio',          icon: 'trendingUp', sizes: ['S', 'M', 'L'],  render: wPortfolio },
  goals:            { title: 'Goals',              icon: 'target',     sizes: ['S', 'M'],       render: wGoals },
  financial_health: { title: 'Financial health',   icon: 'heart',      sizes: ['S', 'M'],       render: wHealth },
  mascot:           { title: 'Mascot insight',     icon: 'smile',      sizes: ['M'],            render: wMascot },
  watchlist:        { title: 'Watchlist',          icon: 'eye',        sizes: ['S', 'M'],       render: wWatchlist },
  wisdom:           { title: 'Wisdom of the day',  icon: 'book',       sizes: ['M'],            render: wWisdom },
  news_brief:       { title: 'News brief',         icon: 'compass',    sizes: ['S', 'M'],       render: wNews },
  reports:          { title: 'Reports',            icon: 'chart',      sizes: ['S', 'M'],       render: wReports },
};

Object.assign(window, { WIDGETS, PCard, PRing, PSpark, PGRAD, PSERIF, PSANS });
