/* RADAR1 — full-frame tile packages (fill the hero inset) */ const DSt = window.Radar1DesignSystem_1f4661; /* Shared package chrome: header band + washed backdrop */ function TileShell({ kicker, title, accent = "var(--signal-cyan)", right = null, children }) { return (
{kicker}
{title}
{right}
{children}
); } /* ---------- WEATHER ---------- */ function TileWeather({ h24 }) { const now = useNow(); const L = window.R1DATA.locales || []; const featIdx = useCycle(L.length, 7000); const feat = L[featIdx]; if (!feat) return null; /* no live locales yet */ const grid = Array.from({ length: 6 }, (_, k) => L[(featIdx + 1 + k) % L.length]); useLucide([featIdx]); return ( {L.length} CITIES · UPDATED {fmtTime(now, "UTC", true)} UTC}>
{/* featured locale */}
{feat.city.toUpperCase()}
LOCAL {fmtTime(now, feat.tz, h24)}
{feat.temp}°
{feat.cond}
H {feat.hi}°L {feat.lo}° {feat.alert && ▲ ADVISORY IN EFFECT}
{/* grid of others */}
{grid.map((l, i) => (
{l.city.toUpperCase()}
{l.temp}° {l.cond}
))}
); } /* ---------- SPORTS ---------- */ function TileSports() { const S = window.R1DATA.sports; if (!S || !S.board || !(S.board.games || []).length) return null; /* nothing on the board — stand down */ return ( {S.board.league}}>
{S.board.games.map((g, i) => (
{g.a}
g.bs ? "var(--text-strong)" : "var(--text-muted)", fontVariantNumeric: "tabular-nums" }}>{g.as}
g.as ? "var(--text-strong)" : "var(--text-muted)", fontVariantNumeric: "tabular-nums" }}>{g.bs}
{g.b}
{g.live && }{g.status}
))}
AROUND THE WORLD {S.fixtures.map((f, i) => (
{f.label}
{f.text}
))}
); } /* ---------- NEWS ---------- */ function TileNews() { const stories = window.R1DATA.stories || []; if (!stories.length) return null; /* nothing to report — stand down */ const feat = stories[0], rest = stories.slice(1, 5); return (
{feat.kicker}
{feat.text}
{rest.map((s, i) => (
{String(i + 2).padStart(2, "0")}
{s.kicker} · {s.time}
{s.text}
))}
); } /* ---------- STUDIO — ambient network scene, full frame ---------- */ /* No TileShell chrome and nothing overlaid: the scene carries its own faint RADAR1 wall brand, and HeroInset already draws the standard hairline. */ function TileStudio() { return ; } /* ---------- ELECTIONS ---------- */ function BoPBar({ label, d, r, und, forControl, total }) { const pct = (n) => (n / total) * 100; return (
{label} {forControl} FOR CONTROL
{d}
{r}
DEM {und} UNDECIDED GOP
); } function TileElections() { const E = window.R1DATA.election; if (!E || !(E.races || []).length) return null; /* no live election content */ return ( LIVE RESULTS}>
RADAR1 DECISION DESK · PROJECTIONS UPDATE AS VOTES COUNT
SENATE RACEINDEMGOPCALL
{E.races.map((r, i) => { const dLead = r.d.pct > r.r.pct; return (
{r.state}
{r.pctIn}%
{r.d.name} {r.d.pct}%
{r.r.name} {r.r.pct}%
{r.call ? {r.call === "D" ? "DEM" : "GOP"} : }
); })}
); } /* ---------- SOCIAL / VIEWER DESK ---------- */ function TileSocial() { const msgs = window.R1DATA.social; const shown = useCycle(1000, 5000); if (!msgs || !msgs.length) return null; /* guard AFTER hooks so the hook order stays stable */ const list = Array.from({ length: 4 }, (_, k) => msgs[(shown + k) % msgs.length]); return ( MODERATED · GLOBAL FEED}>
{list.map((m, i) => (
{m.handle[1].toUpperCase()}
{m.handle} {m.loc.toUpperCase()} · {m.time}
{m.msg}
))}
); } /* ---------- CUT SPOT — produced storyboard, plays window.R1DATA.cutspot ---------- */ const CUTSPOT_FRAME = { position: "absolute", inset: 0, overflow: "hidden", background: "radial-gradient(130% 120% at 22% 0%, #10233C 0%, #081120 70%)", }; /* "41 CHICKS — a record season" -> { stat, unit, body } when the slide carries only `text`; explicit slide.stat / slide.unit always win */ function cutspotStatParts(slide) { if (slide.stat) return { stat: slide.stat, unit: slide.unit || "", body: slide.text || "" }; const text = String(slide.text || ""); const sep = text.search(/[—–:·]/); const head = (sep >= 0 ? text.slice(0, sep) : text).trim(); const body = sep >= 0 ? text.slice(sep + 1).trim() : ""; const m = head.match(/^([~$+\-]?[\d][\d.,]*%?)\s*([\s\S]*)$/); if (!m) return null; const unit = m[2].trim(); if (unit.length > 24) return { stat: m[1], unit: "", body: body ? unit + " — " + body : unit }; return { stat: m[1], unit, body }; } function CutSpotSlide({ slide, accent }) { const type = slide.type; if (type === "image" && slide.src) { return (
{slide.text && (
{slide.text}
)} {slide.credit && (
{slide.credit}
)}
); } if (type === "stat") { const parts = cutspotStatParts(slide); if (parts) { return (
{parts.stat} {parts.unit && {parts.unit}}
{parts.body &&
{parts.body}
}
); } /* un-parseable stat — fall through to the title treatment */ } if (type === "quote") { return (
“{slide.text}”
{slide.credit && (
{slide.credit}
)}
); } if (type === "list") { const items = (Array.isArray(slide.items) ? slide.items : String(slide.text || "").split(/\n+/)) .map((s) => String(s).trim()).filter(Boolean).slice(0, 5); return (
{items.map((it, i) => (
{it}
))}
); } /* "title" and anything unrecognized: the big display card */ return (
{slide.text}
); } function TileCutSpot() { const spot = window.R1DATA.cutspot; const slides = spot && Array.isArray(spot.slides) && spot.slides.length ? spot.slides : null; /* content signature, not object identity — SSE re-sends must not restart the deck */ const sig = React.useMemo(() => { try { return spot ? JSON.stringify(spot) : ""; } catch (e) { return ""; } }, [spot]); const [idx, setIdx] = React.useState(0); React.useEffect(() => { setIdx(0); }, [sig]); React.useEffect(() => { const list = (window.R1DATA.cutspot || {}).slides; if (!Array.isArray(list) || !list.length) return; const cur = list[idx % list.length] || {}; const ms = Math.max(2, Number(cur.duration_s) || 8) * 1000; const t = setTimeout(() => setIdx((i) => i + 1), ms); /* modulo below — the deck loops */ return () => clearTimeout(t); }, [sig, idx]); if (!slides) return null; const shown = idx % slides.length; const slide = slides[shown]; const accent = spot.accent || "var(--signal-cyan)"; const sources = (spot.sources || []).map((s) => String(s).toUpperCase()).filter(Boolean); return ( SPOT · {shown + 1} / {slides.length}}>
{sources.length > 0 && ( SOURCES · {sources.join(" · ")} )}
{slides.map((_, i) => ( ))}
); } const TILES = { weather: { label: "WEATHER", comp: TileWeather }, sports: { label: "SPORTS", comp: TileSports }, news: { label: "NEWS", comp: TileNews }, studio: { label: "STUDIO", comp: TileStudio }, elections: { label: "ELECTIONS", comp: TileElections }, social: { label: "SOCIAL", comp: TileSocial }, cutspot: { label: "SPOT", comp: TileCutSpot }, }; Object.assign(window, { TILES, TileWeather, TileSports, TileNews, TileStudio, TileElections, TileSocial, TileCutSpot, BoPBar, TileShell });