// Shared components & utilities for JaStocks
const { useState, useEffect, useMemo, useRef, useCallback } = React;

// ---------- Live FX rate ----------
// Returns the current USD→JMD rate from JASTOCKS_DATA, or null if unavailable
window.getJMDRate = () => window.JASTOCKS_DATA?.fxRate ?? null;

// Refresh FX rate every 30 minutes (runs after app is loaded)
window._fxRefreshInterval = null;
window.startFXRefresh = () => {
  if (window._fxRefreshInterval) return;
  window._fxRefreshInterval = setInterval(async () => {
    try {
      const res = await fetch('/api/fx');
      if (!res.ok) return;
      const data = await res.json();
      if (data?.usd_to_jmd && window.JASTOCKS_DATA) {
        window.JASTOCKS_DATA.fxRate = data.usd_to_jmd;
      }
    } catch (_) {}
  }, 30 * 60 * 1000);
};

// ---------- Formatters ----------
window.fmtMoney = (v, currency = 'JMD', decimals = 2) => {
  if (currency === 'USD') {
    const rate = getJMDRate();
    if (!rate) return `J$${Number(v).toLocaleString('en-US', { maximumFractionDigits: decimals, minimumFractionDigits: decimals })} (JMD)`;
    const val = v / rate;
    const abs = Math.abs(val);
    if (abs >= 1_000_000_000) return `US$${(val / 1_000_000_000).toFixed(2)}B`;
    if (abs >= 1_000_000) return `US$${(val / 1_000_000).toFixed(2)}M`;
    return `US$${val.toLocaleString('en-US', { maximumFractionDigits: decimals, minimumFractionDigits: decimals })}`;
  }
  const abs = Math.abs(v);
  if (abs >= 1_000_000_000) return `J$${(v / 1_000_000_000).toFixed(2)}B`;
  if (abs >= 1_000_000) return `J$${(v / 1_000_000).toFixed(2)}M`;
  return `J$${Number(v).toLocaleString('en-US', { maximumFractionDigits: decimals, minimumFractionDigits: decimals })}`;
};
window.fmtPrice = (v, currency = 'JMD') => {
  if (currency === 'USD') {
    const rate = getJMDRate();
    if (!rate) return `J$${Number(v).toLocaleString('en-US', { maximumFractionDigits: 2, minimumFractionDigits: 2 })}`;
    return `US$${(v / rate).toLocaleString('en-US', { maximumFractionDigits: 2, minimumFractionDigits: 2 })}`;
  }
  return `J$${Number(v).toLocaleString('en-US', { maximumFractionDigits: 2, minimumFractionDigits: 2 })}`;
};
window.fmtNum = (v, decimals = 0) =>
  Number(v).toLocaleString('en-US', { maximumFractionDigits: decimals, minimumFractionDigits: decimals });
window.fmtPct = (v, withSign = true) =>
  `${withSign && v > 0 ? '+' : ''}${Number(v).toFixed(2)}%`;
window.fmtDate = (d) => {
  const x = typeof d === 'string' ? new Date(d + 'T12:00:00') : d;
  return x.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
};
window.fmtDateFull = (d) => {
  const x = typeof d === 'string' ? new Date(d + 'T12:00:00') : d;
  return x.toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' });
};

// ---------- Loading screen ----------
window.LoadingScreen = ({ error }) => (
  <div style={{
    position: 'fixed', inset: 0,
    background: 'var(--bg)',
    display: 'flex', flexDirection: 'column',
    alignItems: 'center', justifyContent: 'center', gap: 20,
  }}>
    <div style={{
      width: 48, height: 48, borderRadius: 14,
      background: 'linear-gradient(135deg, var(--accent), var(--accent-2))',
      display: 'grid', placeItems: 'center',
      color: '#0a0b0d', fontWeight: 800, fontSize: 20,
      fontFamily: 'Geist Mono, monospace',
      boxShadow: '0 0 40px var(--accent-dim)',
    }}>JS</div>
    {error ? (
      <div style={{ textAlign: 'center' }}>
        <div style={{ color: 'var(--down)', fontWeight: 600, marginBottom: 8 }}>Failed to load market data</div>
        <div style={{ color: 'var(--text-3)', fontSize: 12, maxWidth: 320 }}>{error}</div>
      </div>
    ) : (
      <div style={{ textAlign: 'center' }}>
        <div style={{ fontWeight: 600, marginBottom: 6 }}>Loading JSE market data…</div>
        <div style={{ color: 'var(--text-3)', fontSize: 12 }}>Connecting to Stacks API</div>
        <div style={{ marginTop: 16, display: 'flex', gap: 6, justifyContent: 'center' }}>
          {[0,1,2].map(i => (
            <div key={i} style={{
              width: 6, height: 6, borderRadius: '50%', background: 'var(--accent)',
              animation: `pulse ${0.8 + i * 0.15}s ease-in-out infinite`,
              animationDelay: `${i * 0.15}s`,
            }}/>
          ))}
        </div>
      </div>
    )}
  </div>
);

// ---------- Inline loading skeleton ----------
window.Skeleton = ({ h = 16, w = '100%', radius = 6 }) => (
  <div style={{
    height: h, width: w, borderRadius: radius,
    background: 'var(--bg-3)',
    animation: 'shimmer 1.4s ease-in-out infinite',
  }}/>
);

// ---------- Icons (Lucide-style stroke) ----------
const I = ({ d, fill, size = 16, sw = 1.8 }) => (
  <svg className="ic" width={size} height={size} viewBox="0 0 24 24" fill={fill || 'none'}
       stroke="currentColor" strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round">
    {d}
  </svg>
);
const Icons = {
  Home: () => <I d={<><path d="M3 10.5 12 3l9 7.5V20a1 1 0 0 1-1 1h-5v-7h-6v7H4a1 1 0 0 1-1-1z"/></>}/>,
  Calendar: () => <I d={<><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 10h18M8 3v4M16 3v4"/></>}/>,
  Stocks: () => <I d={<><path d="M3 17l5-5 4 4 8-8"/><path d="M14 8h6v6"/></>}/>,
  Portfolio: () => <I d={<><rect x="3" y="7" width="18" height="13" rx="2"/><path d="M8 7V5a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M3 13h18"/></>}/>,
  Watchlist: () => <I d={<><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></>}/>,
  Search: () => <I d={<><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></>}/>,
  Bell: () => <I d={<><path d="M6 8a6 6 0 1 1 12 0c0 7 3 9 3 9H3s3-2 3-9zM10 21a2 2 0 0 0 4 0"/></>}/>,
  Settings: () => <I d={<><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3h.1a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8v.1a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z"/></>}/>,
  Sun: () => <I d={<><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.2 4.2l1.4 1.4M18.4 18.4l1.4 1.4M2 12h2M20 12h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4"/></>}/>,
  Moon: () => <I d={<><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></>}/>,
  Plus: () => <I d={<><path d="M12 5v14M5 12h14"/></>}/>,
  ArrowUp: () => <I d={<><path d="M7 17 17 7M9 7h8v8"/></>}/>,
  ArrowDown: () => <I d={<><path d="M7 7l10 10M17 9v8H9"/></>}/>,
  Dollar: () => <I d={<><path d="M12 2v20M17 6H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></>}/>,
  Chart: () => <I d={<><path d="M3 3v18h18"/><path d="M7 14l4-4 4 4 5-6"/></>}/>,
  Star: () => <I d={<><path d="m12 2 3 7 7 .6-5.3 4.8 1.6 7.1L12 17.8 5.7 21.5l1.6-7.1L2 9.6 9 9z"/></>}/>,
  Clock: () => <I d={<><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></>}/>,
  Filter: () => <I d={<><path d="M3 5h18M6 12h12M10 19h4"/></>}/>,
  X: () => <I d={<><path d="M18 6 6 18M6 6l12 12"/></>}/>,
  ChevronDown: () => <I d={<><path d="m6 9 6 6 6-6"/></>}/>,
  ChevronRight: () => <I d={<><path d="m9 6 6 6-6 6"/></>}/>,
  Info: () => <I d={<><circle cx="12" cy="12" r="9"/><path d="M12 8h.01M11 12h1v4h1"/></>}/>,
  Refresh: () => <I d={<><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M8 16H3v5"/></>}/>,
};
window.Icons = Icons;

// ---------- Sym badge ----------
const SYM_COLORS = ['green', 'pink', 'blue', 'amber', 'cyan', 'violet'];
window.symColor = (sym) => {
  let h = 0;
  for (let i = 0; i < sym.length; i++) h = (h * 31 + sym.charCodeAt(i)) >>> 0;
  return SYM_COLORS[h % SYM_COLORS.length];
};
window.SymBadge = ({ sym, size = 30 }) => (
  <div className={`sym-badge ${symColor(sym)}`}
       style={{ width: size, height: size, fontSize: size < 26 ? 9 : 10 }}>
    {sym.slice(0, 4)}
  </div>
);

// ---------- Sparkline ----------
window.Sparkline = ({ values, width = 160, height = 40, color, fill = true }) => {
  if (!values || values.length < 2) return null;
  const min = Math.min(...values);
  const max = Math.max(...values);
  const pad = (max - min) * 0.1 || 1;
  const range = (max - min) + pad * 2;
  const stepX = width / (values.length - 1);
  const up = values[values.length - 1] >= values[0];
  const col = color || (up ? 'var(--up)' : 'var(--down)');
  const pts = values.map((v, i) =>
    `${(i * stepX).toFixed(1)},${(height - ((v - min + pad) / range) * height).toFixed(1)}`
  );
  const line = `M${pts.join(' L')}`;
  const area = `${line} L${width},${height} L0,${height} Z`;
  const gid = 'spark-' + Math.random().toString(36).slice(2, 8);
  return (
    <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`}>
      <defs>
        <linearGradient id={gid} x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%" stopColor={col} stopOpacity="0.35"/>
          <stop offset="100%" stopColor={col} stopOpacity="0"/>
        </linearGradient>
      </defs>
      {fill && <path d={area} fill={`url(#${gid})`}/>}
      <path d={line} fill="none" stroke={col} strokeWidth="1.5" strokeLinejoin="round"/>
    </svg>
  );
};

// ---------- Candlestick / Line chart ----------
window.Candlestick = ({ data, height = 380, volumeHeight = 70, showVolume = true, mode = 'line' }) => {
  const wrapRef = useRef(null);
  const [hover, setHover] = useState(null);
  const [w, setW] = useState(800);
  useEffect(() => {
    if (!wrapRef.current) return;
    const ro = new ResizeObserver(([e]) => setW(e.contentRect.width));
    ro.observe(wrapRef.current);
    return () => ro.disconnect();
  }, []);

  if (!data || data.length < 2) return (
    <div ref={wrapRef} style={{ height, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
      <span style={{ color: 'var(--text-3)', fontSize: 13 }}>No chart data available</span>
    </div>
  );

  const padL = 56, padR = 12, padT = 14, padB = 28;
  const chartW = w - padL - padR;
  const chartH = height - padT - padB - (showVolume ? volumeHeight + 14 : 0);
  const volTop = padT + chartH + 14;

  const hi = Math.max(...data.map(d => d.h || d.c));
  const lo = Math.min(...data.map(d => d.l || d.c));
  const pad = (hi - lo) * 0.08 || 1;
  const yMax = hi + pad, yMin = lo - pad;
  const yRange = yMax - yMin;
  const yFor = (v) => padT + ((yMax - v) / yRange) * chartH;
  const n = data.length;
  const stepX = chartW / Math.max(n - 1, 1);
  const candleW = Math.max(2, (chartW / n) * 0.65);
  const xFor = (i) => padL + i * stepX;

  const vMax = Math.max(...data.map(d => d.v || 0), 1);
  const vBarH = (v) => ((v || 0) / vMax) * volumeHeight;

  const yTicks = 5;
  const ticks = Array.from({ length: yTicks }, (_, i) => yMin + (yRange * i) / (yTicks - 1));

  const handleMove = (e) => {
    const rect = e.currentTarget.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const i = Math.min(n - 1, Math.max(0, Math.round((x - padL) / stepX)));
    if (x >= padL && x <= w - padR) setHover({ i, x: xFor(i), y: e.clientY - rect.top });
    else setHover(null);
  };

  const last = data[data.length - 1].c;
  const first = data[0].c;
  const lineCol = last >= first ? 'var(--up)' : 'var(--down)';

  return (
    <div ref={wrapRef} className="candle-wrap" style={{ width: '100%' }}>
      <svg width={w} height={height} onMouseMove={handleMove} onMouseLeave={() => setHover(null)}>
        {ticks.map((t, i) => (
          <g key={i}>
            <line x1={padL} x2={w - padR} y1={yFor(t)} y2={yFor(t)} stroke="var(--grid)" strokeDasharray="2 3"/>
            <text x={padL - 8} y={yFor(t) + 3} fontSize="10" textAnchor="end" fill="var(--text-3)" fontFamily="Geist Mono, monospace">
              {t.toFixed(2)}
            </text>
          </g>
        ))}

        {mode === 'candle' ? data.map((d, i) => {
          const up = d.c >= d.o;
          const col = up ? 'var(--up)' : 'var(--down)';
          const x = padL + i * (chartW / n) + (chartW / n) / 2;
          return (
            <g key={i}>
              <line x1={x} x2={x} y1={yFor(d.h)} y2={yFor(d.l)} stroke={col} strokeWidth="1"/>
              <rect x={x - candleW / 2} y={yFor(Math.max(d.o, d.c))}
                    width={candleW} height={Math.max(1, Math.abs(yFor(d.o) - yFor(d.c)))}
                    fill={col} opacity={up ? 0.95 : 1}/>
            </g>
          );
        }) : (() => {
          const pts = data.map((d, i) => `${xFor(i)},${yFor(d.c)}`).join(' L');
          const area = `M${xFor(0)},${yFor(first)} L${pts} L${xFor(n-1)},${padT + chartH} L${padL},${padT + chartH} Z`;
          return (
            <g>
              <defs>
                <linearGradient id="ch-area" x1="0" x2="0" y1="0" y2="1">
                  <stop offset="0%" stopColor={lineCol} stopOpacity="0.28"/>
                  <stop offset="100%" stopColor={lineCol} stopOpacity="0"/>
                </linearGradient>
              </defs>
              <path d={area} fill="url(#ch-area)"/>
              <path d={`M${xFor(0)},${yFor(first)} L${pts}`} fill="none" stroke={lineCol} strokeWidth="2"/>
            </g>
          );
        })()}

        {showVolume && data.map((d, i) => {
          const up = d.c >= (d.o || d.c);
          const x = padL + i * (chartW / n) + (chartW / n) / 2;
          return <rect key={i} x={x - candleW / 2} y={volTop + volumeHeight - vBarH(d.v)}
                       width={candleW} height={Math.max(1, vBarH(d.v))}
                       fill={up ? 'var(--up)' : 'var(--down)'} opacity="0.35"/>;
        })}
        {showVolume && (
          <text x={padL} y={volTop - 2} fontSize="9.5" fill="var(--text-3)" fontFamily="Geist Mono, monospace">VOL</text>
        )}

        {[0, Math.floor(n * 0.25), Math.floor(n * 0.5), Math.floor(n * 0.75), n - 1].map(i => (
          <text key={i} x={xFor(i)} y={height - 8} fontSize="10" textAnchor="middle" fill="var(--text-3)" fontFamily="Geist Mono, monospace">
            {fmtDate(data[i].date)}
          </text>
        ))}

        {hover && (
          <g>
            <line x1={hover.x} x2={hover.x} y1={padT} y2={padT + chartH} stroke="var(--text-3)" strokeDasharray="2 3" opacity="0.5"/>
            <circle cx={hover.x} cy={yFor(data[hover.i].c)} r="3" fill="var(--accent)"/>
          </g>
        )}
      </svg>
      {hover && (() => {
        const d = data[hover.i];
        const pos = hover.x > w - 180 ? hover.x - 160 : hover.x + 12;
        return (
          <div className="chart-tooltip" style={{ left: pos, top: padT }}>
            <div style={{ color: 'var(--text-3)', marginBottom: 4 }}>{fmtDate(d.date)}</div>
            {d.o !== undefined && <div>O <span style={{ float: 'right' }}>{d.o.toFixed(2)}</span></div>}
            {d.h !== undefined && <div>H <span style={{ float: 'right' }}>{d.h.toFixed(2)}</span></div>}
            {d.l !== undefined && <div>L <span style={{ float: 'right' }}>{d.l.toFixed(2)}</span></div>}
            <div>C <span style={{ float: 'right', color: d.c >= (d.o || d.c) ? 'var(--up)' : 'var(--down)' }}>{d.c.toFixed(2)}</span></div>
            {d.v > 0 && <div style={{ color: 'var(--text-3)', marginTop: 4 }}>V <span style={{ float: 'right' }}>{(d.v / 1000).toFixed(1)}k</span></div>}
          </div>
        );
      })()}
    </div>
  );
};

// ---------- Change badge ----------
window.ChangeBadge = ({ change, pct, size = 'md' }) => {
  const up = change >= 0;
  return (
    <span className={`mono ${up ? 'up' : 'down'}`} style={{ fontSize: size === 'sm' ? 11.5 : 12.5 }}>
      {up ? '▲' : '▼'} {fmtPct(pct)}
    </span>
  );
};

// ---------- Sidebar ----------
window.Sidebar = ({ page, setPage }) => {
  const items = [
    { id: 'home', label: 'Home', icon: Icons.Home },
    { id: 'dividends', label: 'Dividends', icon: Icons.Calendar },
    { id: 'stocks', label: 'Stocks', icon: Icons.Stocks },
    { id: 'portfolio', label: 'Portfolio', icon: Icons.Portfolio },
    { id: 'watchlist', label: 'Watchlist', icon: Icons.Watchlist },
  ];
  const tools = [
    { id: 'alerts', label: 'Alerts', icon: Icons.Bell },
  ];
  return (
    <aside className="sidebar">
      <div className="brand">
        <div className="brand-mark">JS</div>
        <div className="brand-name">Ja<span>Stocks</span></div>
      </div>
      <div className="nav-section">Market</div>
      {items.map(it => {
        const Ic = it.icon;
        return (
          <div key={it.id} className={`nav-item ${page === it.id ? 'active' : ''}`} onClick={() => setPage(it.id)}>
            <Ic/>
            <span>{it.label}</span>
          </div>
        );
      })}
      <div className="nav-section">Tools</div>
      {tools.map(it => {
        const Ic = it.icon;
        return (
          <div key={it.id} className={`nav-item ${page === it.id ? 'active' : ''}`} onClick={() => setPage(it.id)}>
            <Ic/>
            <span>{it.label}</span>
          </div>
        );
      })}
      <div className="sidebar-footer">
        <div className="user-chip">
          <div className="user-avatar">JA</div>
          <div className="user-meta">
            <div className="nm">JaStocks</div>
            <div className="em">Live JSE Data</div>
          </div>
        </div>
      </div>
    </aside>
  );
};

// ---------- Topbar with live search ----------
window.Topbar = ({ theme, setTheme, currency, setCurrency, setPage, setSelectedStock, livePrices }) => {
  const [q, setQ] = useState('');
  const [results, setResults] = useState([]);
  const [searching, setSearching] = useState(false);
  const inputRef = useRef(null);
  const debounceRef = useRef(null);

  const doSearch = useCallback(async (val) => {
    if (!val.trim()) { setResults([]); return; }
    setSearching(true);
    try {
      const res = await JaAPI.search(val);
      setResults((res.results || []).slice(0, 8));
    } catch (_) { setResults([]); }
    setSearching(false);
  }, []);

  const onChange = (e) => {
    const val = e.target.value;
    setQ(val);
    clearTimeout(debounceRef.current);
    debounceRef.current = setTimeout(() => doSearch(val), 350);
  };

  const pickResult = (r) => {
    setSelectedStock(r.symbol);
    setPage('stock');
    setQ('');
    setResults([]);
  };

  // Keyboard shortcut ⌘K
  useEffect(() => {
    const handler = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
        e.preventDefault();
        inputRef.current?.focus();
      }
    };
    window.addEventListener('keydown', handler);
    return () => window.removeEventListener('keydown', handler);
  }, []);

  const stocks = (window.JASTOCKS_DATA?.stocks || []).filter(s => s.price > 0).slice(0, 30);
  const mktStatus = window.JASTOCKS_DATA?.stocks?.[0]?.marketStatus || 'closed';
  const isLive = mktStatus === 'open';

  return (
    <header className="topbar">
      <div className="search" style={{ position: 'relative', flex: 1 }}>
        <Icons.Search/>
        <input
          ref={inputRef}
          placeholder="Search symbols, companies…"
          value={q}
          onChange={onChange}
          onBlur={() => setTimeout(() => setResults([]), 200)}
        />
        <kbd>⌘K</kbd>
        {(results.length > 0) && (
          <div style={{
            position: 'absolute', top: 'calc(100% + 6px)', left: 0, right: 0,
            background: 'var(--bg-elev)', border: '1px solid var(--border-strong)',
            borderRadius: 10, boxShadow: 'var(--shadow)', zIndex: 50, overflow: 'hidden',
          }}>
            {results.map(r => (
              <div key={r.symbol} onMouseDown={() => pickResult(r)}
                   style={{ padding: '10px 14px', cursor: 'pointer', display: 'flex', gap: 10, alignItems: 'center' }}>
                <SymBadge sym={r.symbol} size={26}/>
                <div>
                  <div style={{ fontWeight: 600, fontSize: 13 }}>{r.symbol}</div>
                  <div style={{ fontSize: 11, color: 'var(--text-3)' }}>{r.company_name}</div>
                </div>
              </div>
            ))}
          </div>
        )}
      </div>

      <div className="ticker-tape">
        <div className="tt-inner">
          {[...stocks, ...stocks].map((s, i) => {
            const live = livePrices[s.sym];
            const price = live ? live.price : s.price;
            const pct = live ? live.changePct : s.changePct;
            return (
              <div key={i} style={{ display: 'flex', gap: 6 }}>
                <span className="sym">{s.sym}</span>
                <span>{price.toFixed(2)}</span>
                <span className={pct >= 0 ? 'up' : 'down'}>
                  {pct >= 0 ? '+' : ''}{pct.toFixed(2)}%
                </span>
              </div>
            );
          })}
        </div>
      </div>

      <div className="topbar-actions">
        <div className="live-dot" style={{ color: isLive ? 'var(--up)' : 'var(--text-2)' }}>
          {isLive ? 'LIVE · JSE OPEN' : 'JSE CLOSED'}
        </div>
        <button className="icon-btn" onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
          {theme === 'dark' ? <Icons.Sun/> : <Icons.Moon/>}
        </button>
        <button className="icon-btn"><Icons.Bell/></button>
      </div>
    </header>
  );
};

// genSpark removed — all trend charts now use real API price history
