/* KPI Ribbon ======================================================== */ function KPICard({ def, value, delta, sparkData, tone, format, live }){ const [hover, setHover] = useState(false); const positive = delta > 0; const goodIsUp = def.good === 'up'; const deltaGood = goodIsUp ? positive : !positive; const deltaColor = deltaGood ? 'text-emerald-600 dark:text-emerald-400' : 'text-rose-600 dark:text-rose-400'; return (
setHover(true)} onMouseLeave={()=>setHover(false)} className="group relative rounded-xl border border-ink-200/80 dark:border-white/10 bg-white dark:bg-ink-900/60 shadow-card p-4 transition hover:shadow-float hover:border-ink-300/80 dark:hover:border-white/20 cursor-default overflow-hidden"> {/* Top: label + live dot */}
{def.label}
{live && }
{/* Value */}
{Math.abs(delta).toFixed(1)}%
{/* Sparkline that appears on hover (slides in) */}
24h {def.label.split(' ').slice(-1)[0]}
{/* Hover overlay accent */}
); } function KPIRibbon({ accountId, platformId, customCols=[], onAddCustomCol }){ const snap = useMemo(()=>kpiSnapshot(accountId, platformId), [accountId, platformId]); const tone = (PLATFORMS.find(p=>p.id===platformId)||PLATFORMS[0]).tone; const colors = ['#8351ff', '#06b6d4', '#10b981', '#f59e0b', '#ec4899', '#3b82f6']; /* Real values only — no synthetic drift. */ const liveValues = snap; return (
{KPI_DEFS.map((def, i) => ( ))} {/* Custom column add slot */}
); } Object.assign(window, { KPIRibbon });