// ===== SHARED UI COMPONENTS ===== const { useState, useEffect, useRef } = React; function Card({ t, children, style, onClick, pad = 16 }) { return (
{children}
); } function Badge({ t, color, children, style }) { return ( {children} ); } // Slightly lighten a hex color for legibility on dark bg function lighten(hex) { try { const n = parseInt(hex.slice(1), 16); let r = (n >> 16) & 255, g = (n >> 8) & 255, b = n & 255; r = Math.min(255, Math.round(r + (255 - r) * 0.35)); g = Math.min(255, Math.round(g + (255 - g) * 0.35)); b = Math.min(255, Math.round(b + (255 - b) * 0.35)); return `rgb(${r},${g},${b})`; } catch (e) { return hex; } } function ProgressRing({ pct, size = 120, stroke = 12, color = '#2556a8', track = '#e6eaf2', children, animate = true }) { const r = (size - stroke) / 2; const circ = 2 * Math.PI * r; const [shown, setShown] = useState(animate ? 0 : pct); useEffect(() => { if (!animate) { setShown(pct); return; } const id = requestAnimationFrame(() => setShown(pct)); return () => cancelAnimationFrame(id); }, [pct, animate]); const offset = circ - (shown / 100) * circ; return (
{children}
); } function Pill({ active, color, t, children, onClick, style }) { const c = color || t.mid; return ( ); } function ProgressBar({ pct, color, t, height = 8 }) { const [w, setW] = useState(0); useEffect(() => { const id = requestAnimationFrame(() => setW(pct)); return () => cancelAnimationFrame(id); }, [pct]); return (
); } // Screen wrapper: title + scrollable body function ScreenHeader({ t, title, subtitle, right }) { return (

{title}

{subtitle &&

{subtitle}

}
{right}
); } function SectionTitle({ t, children, action }) { return (

{children}

{action}
); } // Icon tile with soft tinted background function IconTile({ icon, color, t, size = 44, radius = 14, fontSize = 22 }) { return (
{icon}
); } // Primary action button function Btn({ t, children, onClick, color, full, variant = 'solid', style, icon }) { const c = color || t.mid; const base = { border: 'none', borderRadius: 14, padding: '14px 18px', fontSize: 15, fontWeight: 700, minHeight: 48, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8, width: full ? '100%' : 'auto', transition: 'transform 0.12s ease, opacity 0.2s', }; const variants = { solid: { background: c, color: '#fff' }, soft: { background: c + (t.dark ? '33' : '1c'), color: t.dark ? lighten(c) : c }, outline: { background: 'transparent', color: t.text, border: `1.5px solid ${t.border}` }, }; return ( ); } function Divider({ t }) { return
; } Object.assign(window, { Card, Badge, ProgressRing, ProgressBar, Pill, ScreenHeader, SectionTitle, IconTile, Btn, Divider, lighten });