// ui.jsx — 樂睦公司端 元件與圖表（專業 SaaS 風，手繪 SVG 圖表）
const { useState } = React;

function Icon({ n, s = 18, fill = false, style = {} }) {
  return <i className={(fill ? 'ph-fill ph-' : 'ph ph-') + n} style={{ fontSize: s, lineHeight: 1, display: 'inline-flex', ...style }} />;
}

// ---- sidebar ----
const NAV_GROUPS = [
  { label: '營運', items: [
    { k: 'overview', label: '營運總覽', icon: 'squares-four' },
    { k: 'institutions', label: '合作機構', icon: 'buildings' },
    { k: 'analytics', label: '數據分析', icon: 'chart-line' },
  ] },
  { label: '智慧服務', items: [
    { k: 'integrations', label: '整合工具', icon: 'plugs-connected' },
    { k: 'llm', label: 'AI 報告品質', icon: 'robot' },
    { k: 'reports', label: '報告中心', icon: 'file-text' },
    { k: 'cost', label: 'AI 成本', icon: 'coins' },
  ] },
];
function SidebarInner({ active, go }) {
  return (
    <>
      <div onClick={() => go('overview')} style={{ display: 'flex', alignItems: 'center', gap: 9, padding: '6px 8px 16px', cursor: 'pointer' }}>
        <span style={{ width: 26, height: 26, borderRadius: 8, background: 'linear-gradient(145deg,var(--accent),var(--accent-deep))', flex: '0 0 auto', boxShadow: 'inset 0 1px 0 rgba(255,255,255,.3)' }} />
        <div style={{ lineHeight: 1.1 }}>
          <div style={{ fontWeight: 800, fontSize: 15 }}>樂睦 <span style={{ color: 'var(--accent)' }}>Lumo</span></div>
          <div style={{ fontSize: 11, color: 'var(--ink-3)' }}>公司端控制台</div>
        </div>
      </div>
      {NAV_GROUPS.map((g, gi) => (
        <div key={g.label} style={{ marginTop: gi ? 10 : 0 }}>
          <div style={{ fontSize: 11, color: 'var(--ink-3)', fontWeight: 600, letterSpacing: '.08em', padding: '8px 10px 6px' }}>{g.label}</div>
          {g.items.map((n) => {
            const on = active === n.k;
            return (
              <button key={n.k} className="navi" onClick={() => go(n.k)} style={{
                display: 'flex', alignItems: 'center', gap: 11, textAlign: 'left', width: '100%', border: 'none', cursor: 'pointer',
                background: on ? 'var(--accent-soft)' : 'transparent', color: on ? 'var(--accent-deep)' : 'var(--ink-2)',
                borderRadius: 10, padding: '10px 11px', fontSize: 14, fontWeight: on ? 700 : 500, marginBottom: 2 }}>
                <Icon n={n.icon} s={19} fill={on} /> {n.label}
              </button>
            );
          })}
        </div>
      ))}
      <div style={{ flex: 1 }} />
      <div style={{ borderTop: '1px solid var(--line)', paddingTop: 12, display: 'flex', alignItems: 'center', gap: 10 }}>
        <span style={{ width: 32, height: 32, borderRadius: '50%', background: 'var(--accent-soft)', color: 'var(--accent-deep)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 700, flex: '0 0 auto' }}>姚</span>
        <div style={{ lineHeight: 1.2, minWidth: 0 }}>
          <div style={{ fontWeight: 600, fontSize: 13, whiteSpace: 'nowrap' }}>姚絜歆</div>
          <div style={{ fontSize: 11, color: 'var(--ink-3)' }}>平台管理員</div>
        </div>
      </div>
    </>
  );
}
function Sidebar({ active, go }) {
  return (
    <aside className="sidebar-desk" style={{ width: 'var(--sidebar-w)', flex: '0 0 var(--sidebar-w)', height: '100vh', position: 'sticky', top: 0,
      background: 'var(--surface)', borderRight: '1px solid var(--line)', display: 'flex', flexDirection: 'column', padding: '16px 14px' }}>
      <SidebarInner active={active} go={go} />
    </aside>
  );
}
// 行動裝置：抽屜式導覽（桌機 sidebar 在 ≤860px 隱藏，靠這個返回各頁/主頁）
function MobileNav({ open, active, go, onClose }) {
  if (!open) return null;
  return (
    <div onClick={onClose} style={{ position: 'fixed', inset: 0, zIndex: 70, background: 'rgba(20,28,40,.40)' }}>
      <div onClick={(e) => e.stopPropagation()} style={{ width: 264, maxWidth: '82vw', height: '100%', background: 'var(--surface)', borderRight: '1px solid var(--line)', boxShadow: '6px 0 30px rgba(20,30,50,.18)', display: 'flex', flexDirection: 'column', padding: '16px 14px', animation: 'slideleft .24s cubic-bezier(.2,.7,.3,1)' }}>
        <SidebarInner active={active} go={(k) => { go(k); onClose(); }} />
      </div>
    </div>
  );
}

function NotifPanel({ list, cleared, onMarkRead, onClose }) {
  return (
    <div onClick={(e) => e.stopPropagation()} style={{ position: 'absolute', top: 46, right: 0, width: 348, maxWidth: '90vw', background: 'var(--surface)', border: '1px solid var(--line)', borderRadius: 12, boxShadow: 'var(--shadow-pop)', zIndex: 50, overflow: 'hidden', animation: 'popin .16s ease' }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '13px 15px', borderBottom: '1px solid var(--line)' }}>
        <span style={{ fontWeight: 700, fontSize: 14 }}>通知</span>
        <span onClick={onMarkRead} style={{ fontSize: 12, color: 'var(--accent)', fontWeight: 600, cursor: 'pointer' }}>全部標為已讀</span>
      </div>
      <div id="scroll" style={{ maxHeight: 400, overflowY: 'auto' }}>
        {list.map((n, i) => {
          const col = { data: 'var(--c-green)', llm: 'var(--accent)', tool: 'var(--c-teal)', inst: 'var(--c-blue)', report: 'var(--c-violet)', warn: 'var(--warn)' }[n.kind] || 'var(--ink-3)';
          const unread = n.unread && !cleared;
          return (
            <div key={i} className="hoverrow clickable" onClick={() => { onClose(); if (n.go) window.__go(n.go); }} style={{ display: 'flex', gap: 11, padding: '11px 14px', borderBottom: '1px solid var(--line)', background: unread ? 'rgba(194,98,43,.04)' : 'transparent' }}>
              <span style={{ width: 30, height: 30, borderRadius: 8, background: 'var(--panel)', color: col, display: 'flex', alignItems: 'center', justifyContent: 'center', flex: '0 0 auto' }}><Icon n={n.icon} s={16} /></span>
              <div style={{ minWidth: 0, flex: 1 }}>
                <div style={{ fontSize: 13, lineHeight: 1.45 }}>{n.text}</div>
                <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 1 }}>{n.t}</div>
              </div>
              {unread && <span style={{ width: 7, height: 7, borderRadius: '50%', background: 'var(--accent)', flex: '0 0 auto', marginTop: 6 }} />}
            </div>
          );
        })}
      </div>
      <div onClick={() => { onClose(); window.__go('overview'); }} style={{ textAlign: 'center', padding: '11px', fontSize: 12.5, color: 'var(--ink-2)', fontWeight: 600, cursor: 'pointer', background: 'var(--panel)' }} className="navi">查看全部動態</div>
    </div>
  );
}

function Topbar({ title, sub, onMenu }) {
  const [open, setOpen] = useState(false);
  const [cleared, setCleared] = useState(false);
  const list = window.NOTIFS || [];
  const unread = cleared ? 0 : list.filter((n) => n.unread).length;
  return (
    <div style={{ height: 'var(--topbar-h)', position: 'sticky', top: 0, zIndex: 5, background: 'rgba(255,255,255,.86)', backdropFilter: 'blur(8px)',
      borderBottom: '1px solid var(--line)', display: 'flex', alignItems: 'center', gap: 14, padding: '0 18px' }}>
      <button className="only-mobile" onClick={onMenu} aria-label="選單" style={{ width: 38, height: 38, borderRadius: 9, border: '1px solid var(--line)', background: 'var(--surface)', color: 'var(--ink-2)', cursor: 'pointer', alignItems: 'center', justifyContent: 'center', flex: '0 0 auto' }}>
        <Icon n="list" s={20} />
      </button>
      <div style={{ minWidth: 0 }}>
        <div style={{ fontWeight: 700, fontSize: 16, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{title}</div>
        {sub && <div className="hide-mobile" style={{ fontSize: 12, color: 'var(--ink-3)', marginTop: 1 }}>{sub}</div>}
      </div>
      <div style={{ flex: 1 }} />
      <div className="hide-mobile" onClick={() => window.__go && window.__go('institutions')} style={{ display: 'flex', alignItems: 'center', gap: 8, background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 9, padding: '7px 12px', width: 240, color: 'var(--ink-3)', cursor: 'pointer' }}>
        <Icon n="magnifying-glass" s={16} /> <span style={{ fontSize: 13 }}>搜尋機構、教具…</span>
      </div>
      <button onClick={() => window.__loadfail && window.__loadfail('報表匯出中…')} style={{ display: 'inline-flex', alignItems: 'center', gap: 7, background: 'var(--accent)', color: '#fff', border: 'none', borderRadius: 9, padding: '8px 14px', fontWeight: 600, fontSize: 13, cursor: 'pointer', boxShadow: 'inset 0 1px 0 rgba(255,255,255,.25)' }}>
        <Icon n="export" s={16} /> 匯出報表
      </button>
      <div style={{ position: 'relative' }}>
        <button onClick={() => setOpen((v) => !v)} style={{ width: 38, height: 38, borderRadius: 9, border: '1px solid ' + (open ? 'var(--accent)' : 'var(--line)'), background: open ? 'var(--accent-soft)' : 'var(--surface)', color: open ? 'var(--accent-deep)' : 'var(--ink-2)', cursor: 'pointer', position: 'relative' }}>
          <Icon n="bell" s={17} fill={open} />
          {unread > 0 && <span className="num" style={{ position: 'absolute', top: -5, right: -5, minWidth: 17, height: 17, padding: '0 4px', borderRadius: 999, background: 'var(--accent)', color: '#fff', fontSize: 10.5, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center', border: '2px solid var(--surface)' }}>{unread}</span>}
        </button>
        {open && <>
          <div onClick={() => setOpen(false)} style={{ position: 'fixed', inset: 0, zIndex: 40 }} />
          <NotifPanel list={list} cleared={cleared} onMarkRead={() => { setCleared(true); window.__toast && window.__toast('已全部標為已讀'); }} onClose={() => setOpen(false)} />
        </>}
      </div>
    </div>
  );
}

function DeltaPill({ delta, kind }) {
  const c = kind === 'down' ? 'var(--bad)' : 'var(--good)';
  return <span className="num" style={{ display: 'inline-flex', alignItems: 'center', gap: 3, color: c, fontSize: 12, fontWeight: 700 }}>
    <Icon n={kind === 'down' ? 'trend-down' : 'trend-up'} s={14} />{delta}</span>;
}
function Badge({ label, kind }) {
  const map = { good: ['var(--good)', 'rgba(46,158,107,.12)'], warn: ['var(--warn)', 'rgba(224,161,43,.14)'], bad: ['var(--bad)', 'rgba(210,80,60,.12)'], info: ['var(--c-blue)', 'rgba(59,111,224,.12)'] };
  const [c, bg] = map[kind] || map.info;
  return <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, color: c, background: bg, borderRadius: 999, padding: '3px 10px', fontSize: 12, fontWeight: 600, whiteSpace: 'nowrap' }}>
    <span style={{ width: 6, height: 6, borderRadius: '50%', background: c }} />{label}</span>;
}
function Trend({ t }) {
  if (t === 'up') return <Icon n="trend-up" s={16} style={{ color: 'var(--good)' }} />;
  if (t === 'down') return <Icon n="trend-down" s={16} style={{ color: 'var(--bad)' }} />;
  return <Icon n="minus" s={16} style={{ color: 'var(--ink-3)' }} />;
}

function Card({ title, action, pad = 18, children, style = {} }) {
  return (
    <div className="cardh" style={{ background: 'var(--surface)', border: '1px solid var(--line)', borderRadius: 'var(--radius)', boxShadow: 'var(--shadow)', ...style }}>
      {title && <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '15px 18px', borderBottom: '1px solid var(--line)' }}>
        <h3 style={{ fontSize: 14.5 }}>{title}</h3>{action}</div>}
      <div style={{ padding: pad }}>{children}</div>
    </div>
  );
}

// ---- charts ----
function Sparkline({ data, color = 'var(--accent)', w = 110, h = 32 }) {
  const mn = Math.min(...data), mx = Math.max(...data), rng = mx - mn || 1;
  const pts = data.map((v, i) => [(i / (data.length - 1)) * w, h - 4 - ((v - mn) / rng) * (h - 8)]);
  const d = pts.map((p, i) => (i ? 'L' : 'M') + p[0].toFixed(1) + ' ' + p[1].toFixed(1)).join(' ');
  return <svg width={w} height={h} style={{ display: 'block', overflow: 'visible' }}>
    <path d={d} fill="none" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
    <circle cx={pts[pts.length - 1][0]} cy={pts[pts.length - 1][1]} r="2.4" fill={color} />
  </svg>;
}

function Kpi({ k, onClick }) {
  const val = k.fmt === 'big' ? window.fmtK(k.value) : window.fmt(k.value);
  return (
    <div className="cardh" onClick={onClick} style={{ background: 'var(--surface)', border: '1px solid var(--line)', borderRadius: 'var(--radius)', boxShadow: 'var(--shadow)', padding: 16, cursor: onClick ? 'pointer' : 'default' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
        <div style={{ fontSize: 12.5, color: 'var(--ink-2)', fontWeight: 600 }}>{k.label}</div>
        {k.delta && <DeltaPill delta={k.delta} kind={k.deltaKind} />}
      </div>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 5, marginTop: 8 }}>
        <span className="num" style={{ fontSize: 30, fontWeight: 700, color: 'var(--ink)', lineHeight: 1 }}>{val}</span>
        {k.unit && <span style={{ fontSize: 13, color: 'var(--ink-3)', fontWeight: 600 }}>{k.unit}</span>}
      </div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', marginTop: 12 }}>
        <span style={{ fontSize: 11.5, color: 'var(--ink-3)' }}>{k.sub || '近 8 期'}</span>
        <Sparkline data={k.spark} color={k.color} />
      </div>
    </div>
  );
}

function AreaLine({ data, labels, color = 'var(--accent)', h = 230 }) {
  const W = 760, P = { l: 38, r: 12, t: 14, b: 26 };
  const mx = Math.max(...data) * 1.08, mn = Math.min(...data) * 0.9;
  const rng = mx - mn || 1;
  const x = (i) => P.l + (i / (data.length - 1)) * (W - P.l - P.r);
  const y = (v) => P.t + (1 - (v - mn) / rng) * (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 ticks = 4;
  return (
    <svg viewBox={`0 0 ${W} ${h}`} width="100%" style={{ display: 'block' }}>
      <defs><linearGradient id="ag" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stopColor={color} stopOpacity="0.18" /><stop offset="1" stopColor={color} stopOpacity="0" /></linearGradient></defs>
      {Array.from({ length: ticks + 1 }).map((_, i) => { const yy = P.t + (i / ticks) * (h - P.t - P.b); const v = mx - (i / ticks) * rng; return <g key={i}><line x1={P.l} y1={yy} x2={W - P.r} y2={yy} stroke="var(--line)" strokeWidth="1" /><text x={P.l - 7} y={yy + 3} textAnchor="end" fontSize="10" fill="var(--ink-3)" className="num">{window.fmtK(Math.round(v))}</text></g>; })}
      <path d={area} fill="url(#ag)" />
      <path d={line} fill="none" stroke={color} strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" />
      {data.map((v, i) => i % 2 === 1 ? <text key={i} x={x(i)} y={h - 8} textAnchor="middle" fontSize="10" fill="var(--ink-3)" className="num">{labels[i]}</text> : null)}
      <circle cx={x(data.length - 1)} cy={y(data[data.length - 1])} r="3.5" fill={color} stroke="#fff" strokeWidth="1.5" />
    </svg>
  );
}

function Donut({ data, total, centerLabel = '總長者數' }) {
  const sum = total || data.reduce((a, d) => a + d.value, 0);
  const R = 52, C = 2 * Math.PI * R; let off = 0;
  return (
    <div style={{ display: 'flex', gap: 22, alignItems: 'center', flexWrap: 'wrap' }}>
      <svg width="140" height="140" viewBox="0 0 140 140" style={{ flex: '0 0 auto' }}>
        <g transform="rotate(-90 70 70)">
          {data.map((d, i) => { const frac = d.value / sum; const len = frac * C; const seg = <circle key={i} cx="70" cy="70" r={R} fill="none" stroke={d.color} strokeWidth="16" strokeDasharray={`${len} ${C - len}`} strokeDashoffset={-off} />; off += len; return seg; })}
        </g>
        <text x="70" y="66" textAnchor="middle" fontSize="22" fontWeight="700" fill="var(--ink)" className="num">{window.fmt(sum)}</text>
        <text x="70" y="84" textAnchor="middle" fontSize="11" fill="var(--ink-3)">{centerLabel}</text>
      </svg>
      <div style={{ flex: 1, minWidth: 150 }}>
        {data.map((d, i) => (
          <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 9, padding: '5px 0' }}>
            <span style={{ width: 9, height: 9, borderRadius: 3, background: d.color, flex: '0 0 auto' }} />
            <span style={{ fontSize: 13, color: 'var(--ink-2)', flex: 1 }}>{d.label}</span>
            <span className="num" style={{ fontSize: 13, fontWeight: 600 }}>{d.value}</span>
            <span className="num" style={{ fontSize: 11.5, color: 'var(--ink-3)', width: 38, textAlign: 'right' }}>{Math.round(d.value / sum * 100)}%</span>
          </div>
        ))}
      </div>
    </div>
  );
}

function BarRows({ data, color = 'var(--accent)' }) {
  const mx = Math.max(...data.map((d) => d.value));
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 11 }}>
      {data.map((d, i) => (
        <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <span style={{ width: 64, fontSize: 12.5, color: 'var(--ink-2)', flex: '0 0 auto', textAlign: 'right' }}>{d.label}</span>
          <div style={{ flex: 1, height: 10, background: 'var(--panel)', borderRadius: 999, overflow: 'hidden' }}>
            <div style={{ width: (d.value / mx * 100) + '%', height: '100%', background: color, borderRadius: 999 }} />
          </div>
          <span className="num" style={{ width: 40, textAlign: 'right', fontSize: 12.5, fontWeight: 600 }}>{d.value}</span>
        </div>
      ))}
    </div>
  );
}

// 六力 初評→近期 改善條
function ImproveBars({ rows }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
      {rows.map((r, i) => (
        <div key={i}>
          <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, marginBottom: 5 }}>
            <span style={{ color: 'var(--ink-2)', fontWeight: 600 }}>{r.k}</span>
            <span className="num" style={{ color: 'var(--ink-3)' }}>{r.b} → <b style={{ color: 'var(--ink)' }}>{r.r}</b> <span style={{ color: 'var(--good)' }}>+{r.r - r.b}</span></span>
          </div>
          <div style={{ position: 'relative', height: 8, background: 'var(--panel)', borderRadius: 999 }}>
            <div style={{ position: 'absolute', left: 0, top: 0, height: '100%', width: r.b + '%', background: 'var(--line-2)', borderRadius: 999 }} />
            <div style={{ position: 'absolute', left: 0, top: 0, height: '100%', width: r.r + '%', background: 'var(--accent)', borderRadius: 999, opacity: .92 }} />
          </div>
        </div>
      ))}
    </div>
  );
}

function MiniStat({ icon, label, value, sub, accent = 'var(--accent)' }) {
  return (
    <div className="cardh" style={{ background: 'var(--surface)', border: '1px solid var(--line)', borderRadius: 'var(--radius)', boxShadow: 'var(--shadow)', padding: 16, display: 'flex', alignItems: 'center', gap: 13 }}>
      <span style={{ width: 42, height: 42, borderRadius: 11, background: 'var(--accent-soft)', color: 'var(--accent-deep)', display: 'flex', alignItems: 'center', justifyContent: 'center', flex: '0 0 auto' }}><Icon n={icon} s={21} /></span>
      <div style={{ minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 5 }}>
          <span className="num" style={{ fontSize: 24, fontWeight: 700, lineHeight: 1, color: accent }}>{value}</span>
          {sub && <span style={{ fontSize: 12, color: 'var(--ink-3)' }}>{sub}</span>}
        </div>
        <div style={{ fontSize: 12.5, color: 'var(--ink-2)', marginTop: 4 }}>{label}</div>
      </div>
    </div>
  );
}

function Drawer({ open, title, sub, onClose, width = 468, children }) {
  React.useEffect(() => {
    function esc(e) { if (e.key === 'Escape') onClose(); }
    if (open) window.addEventListener('keydown', esc);
    return () => window.removeEventListener('keydown', esc);
  }, [open]);
  if (!open) return null;
  return (
    <div onClick={onClose} style={{ position: 'fixed', inset: 0, zIndex: 80, background: 'rgba(20,28,40,.34)', display: 'flex', justifyContent: 'flex-end' }}>
      <div onClick={(e) => e.stopPropagation()} style={{ width, maxWidth: '94vw', height: '100%', background: 'var(--surface)', boxShadow: '-12px 0 44px rgba(20,30,50,.20)', display: 'flex', flexDirection: 'column', animation: 'slidein .26s cubic-bezier(.2,.7,.3,1)' }}>
        <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12, padding: '18px 20px', borderBottom: '1px solid var(--line)' }}>
          <div style={{ minWidth: 0 }}><h3 style={{ fontSize: 16 }}>{title}</h3>{sub && <div style={{ fontSize: 12.5, color: 'var(--ink-3)', marginTop: 3 }}>{sub}</div>}</div>
          <button onClick={onClose} aria-label="關閉" style={{ width: 34, height: 34, borderRadius: 9, border: '1px solid var(--line)', background: 'var(--surface)', color: 'var(--ink-2)', cursor: 'pointer', flex: '0 0 auto', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon n="x" s={16} /></button>
        </div>
        <div id="scroll" style={{ padding: 20, overflowY: 'auto', flex: 1 }}>{children}</div>
      </div>
    </div>
  );
}
// 抽屜用：小標籤列、區塊標題
function DRow({ k, v }) { return <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, padding: '9px 0', borderBottom: '1px solid var(--line)', fontSize: 13.5 }}><span style={{ color: 'var(--ink-3)' }}>{k}</span><span style={{ color: 'var(--ink)', fontWeight: 500, textAlign: 'right' }}>{v}</span></div>; }
function DHead({ children }) { return <div style={{ fontSize: 12, color: 'var(--ink-3)', fontWeight: 700, letterSpacing: '.06em', margin: '22px 0 10px' }}>{children}</div>; }

// 垂直時間軸（成本/模型導入里程碑）
function Timeline({ items }) {
  const col = { data: 'var(--c-green)', llm: 'var(--accent)', tool: 'var(--c-teal)', inst: 'var(--c-blue)', report: 'var(--c-violet)' };
  return (
    <div>
      {items.map((it, i) => {
        const c = col[it.kind] || 'var(--ink-3)';
        const last = i === items.length - 1;
        return (
          <div key={i} style={{ display: 'flex', gap: 14 }}>
            <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', flex: '0 0 auto' }}>
              <span style={{ width: 12, height: 12, borderRadius: '50%', background: c, border: '2px solid var(--surface)', boxShadow: '0 0 0 2px ' + c, marginTop: 4 }} />
              {!last && <span style={{ width: 2, flex: 1, background: 'var(--line)', margin: '4px 0' }} />}
            </div>
            <div style={{ paddingBottom: last ? 0 : 20, minWidth: 0 }}>
              <div className="num" style={{ fontSize: 11.5, color: c, fontWeight: 700, letterSpacing: '.03em' }}>{it.date}</div>
              <div style={{ fontSize: 13.5, fontWeight: 600, margin: '2px 0 3px' }}>{it.title}</div>
              <div style={{ fontSize: 12.5, color: 'var(--ink-3)', lineHeight: 1.55 }}>{it.desc}</div>
            </div>
          </div>
        );
      })}
    </div>
  );
}

Object.assign(window, { Icon, Sidebar, MobileNav, Topbar, Kpi, Card, MiniStat, DeltaPill, Badge, Trend, Sparkline, AreaLine, Donut, BarRows, ImproveBars, Drawer, DRow, DHead, Timeline });
