/* soccerarena.ai — shared visual atoms. */ function toSlug(name) { return (name || '').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, ''); } const SA = { turf: '#0a1f0f', turf2: '#0c2613', surface: '#0e2a16', surfaceHi: '#123420', line: 'rgba(200,245,58,0.10)', line2: 'rgba(255,255,255,0.07)', white: '#f4f7f2', dim: 'rgba(244,247,242,0.62)', faint: 'rgba(244,247,242,0.38)', lime: '#c8f53a', limeDim: 'rgba(200,245,58,0.55)', orange: '#ff9d3d', orangeDim: 'rgba(255,157,61,0.16)', mono: "'JetBrains Mono', ui-monospace, monospace", sans: "'Archivo', system-ui, sans-serif", }; function Sparkline({ data, w = 64, h = 22, color = SA.lime, strokeWidth = 1.5 }) { const min = Math.min(...data), max = Math.max(...data); const span = max - min || 1; const pts = data.map((v, i) => { const x = (i / (data.length - 1)) * (w - 2) + 1; const y = h - 1 - ((v - min) / span) * (h - 2); return `${x.toFixed(1)},${y.toFixed(1)}`; }); const last = data[data.length - 1]; const lx = w - 1; const ly = h - 1 - ((last - min) / span) * (h - 2); return ( ); } function FlipBadge({ label = 'FLIPPED', when, compact = false }) { return ( {label}{when ? ` ${when}` : ''} ); } function SplitBar({ split, height = 6 }) { const total = split.home + split.draw + split.away || 1; const seg = (n, color) => n > 0 ? (
) : null; return (
{seg(split.home, SA.lime)} {seg(split.draw, 'rgba(244,247,242,0.28)')} {seg(split.away, SA.white)}
); } function ConfBar({ value, w = 54 }) { return (
); } function Delta({ value }) { const up = value >= 0; return ( {up ? '▲' : '▼'} {Math.abs(value)} ); } function PitchMarkings() { const s = SA.line; return ( ); } function LiveDot() { return ( ); } function ProviderMark({ code, size = 26 }) { return (
{code}
); } function ShareBar({ m }) { const pageUrl = window.location.pathname.includes('/models/') ? window.location.href : window.location.href.replace(/[^/]*$/, '') + 'models/' + m.slug; const text = m.name + ' predicts ' + m.pick.name + ' to win the 2026 World Cup'; const tweetUrl = 'https://twitter.com/intent/tweet?text=' + encodeURIComponent(text) + '&url=' + encodeURIComponent(pageUrl); const waUrl = 'https://wa.me/?text=' + encodeURIComponent(text + ' \u2192 ' + pageUrl); const btn = (href, label, fg, bg, border) => ( e.stopPropagation()} style={{ display: 'inline-flex', alignItems: 'center', gap: 5, padding: '5px 11px', textDecoration: 'none', fontFamily: SA.mono, fontSize: 10, fontWeight: 500, letterSpacing: '0.04em', color: fg, background: bg, border: `1px solid ${border}`, whiteSpace: 'nowrap', lineHeight: 1, }}> {label} ); return (
{btn(tweetUrl, '\u2958 Share', '#1d9bf0', 'rgba(29,155,240,0.1)', 'rgba(29,155,240,0.28)')} {btn(waUrl, 'WhatsApp', '#25d366', 'rgba(37,211,102,0.08)', 'rgba(37,211,102,0.25)')}
); } // ── Dynamic relative-time widget ────────────────────────────────────────────── // Updates every minute; never stale regardless of when the page was built. const { useState: useStateR, useEffect: useEffectR } = React; function computeRelativeTime(isoString) { if (!isoString) return ''; const diff = new Date(isoString).getTime() - Date.now(); if (diff <= 0) return 'kicked off'; const totalMin = Math.round(diff / 60000); if (totalMin < 60) return `${totalMin}m`; const h = Math.floor(diff / 3600000); const m = Math.floor((diff % 3600000) / 60000); if (h < 24) return `${h}h ${m}m`; const days = Math.floor(h / 24); return `${days}d ${h % 24}h`; } function useRelativeTime(isoString) { const [val, setVal] = useStateR(() => computeRelativeTime(isoString)); useEffectR(() => { if (!isoString) return; const id = setInterval(() => setVal(computeRelativeTime(isoString)), 60000); return () => clearInterval(id); }, [isoString]); return val; } function RelativeTime({ kickoffAt, style }) { const t = useRelativeTime(kickoffAt); return {t}; } function useIsMobile(breakpoint = 768) { const [mobile, setMobile] = React.useState(() => typeof window !== 'undefined' && window.innerWidth < breakpoint); React.useEffect(() => { const handler = () => setMobile(window.innerWidth < breakpoint); window.addEventListener('resize', handler); return () => window.removeEventListener('resize', handler); }, [breakpoint]); return mobile; } Object.assign(window, { SA, Sparkline, FlipBadge, SplitBar, ConfBar, Delta, PitchMarkings, LiveDot, ProviderMark, ShareBar, useRelativeTime, RelativeTime, useIsMobile, toSlug, });