/* RADAR1 — rails, info bar, ticker stacks (the L-shaped furniture) */ const DSr = window.Radar1DesignSystem_1f4661; /* ================= SIDE RAIL — editorial card deck ================= */ /* abstract still-image placeholders (gradient washes, no illustration) */ const RAIL_ART = { lunar: { base: "linear-gradient(150deg, #1A2436 0%, #0B1220 60%, #060C17 100%)", glow: "radial-gradient(circle at 72% 30%, rgba(203,211,222,0.32), rgba(203,211,222,0.05) 45%, transparent 62%)" }, heat: { base: "linear-gradient(150deg, #3A1420 0%, #1A0F1A 55%, #0A0A14 100%)", glow: "radial-gradient(circle at 30% 35%, rgba(255,140,0,0.4), rgba(228,3,46,0.12) 50%, transparent 68%)" }, harbor: { base: "linear-gradient(170deg, #0E2233 0%, #0A1524 55%, #071019 100%)", glow: "radial-gradient(ellipse at 50% 78%, rgba(31,168,224,0.28), transparent 60%)" }, community: { base: "linear-gradient(150deg, #2A2314 0%, #171507 55%, #0C0B06 100%)", glow: "radial-gradient(circle at 65% 40%, rgba(255,176,0,0.28), transparent 58%)" }, wildlife: { base: "linear-gradient(160deg, #10281E 0%, #0A1A14 55%, #060F0B 100%)", glow: "radial-gradient(circle at 40% 45%, rgba(23,178,106,0.26), transparent 60%)" }, }; const railInk = (accent) => (/cyan|amber|green/.test(accent) ? "#04121C" : "#fff"); function CardKicker({ text, accent }) { return ( {text} ); } function RailPhotoCard({ card }) { const art = RAIL_ART[card.art] || RAIL_ART.harbor; /* real image (live /media/ asset) when present + loadable; gradient art otherwise */ const [imgOk, setImgOk] = React.useState(true); React.useEffect(() => { setImgOk(true); if (!card.image) return; const probe = new Image(); probe.onerror = () => setImgOk(false); probe.src = card.image; return () => { probe.onerror = null; }; }, [card.image]); const photo = !!card.image && imgOk; return (
{!photo &&
}
{card.credit && ( {card.credit} )} {card.loc && ( ▸ {card.loc} )}
{card.headline}
{card.dek}
); } function RailChartCard({ card }) { const pts = card.chart.points; const max = Math.max(...pts.map((p) => p.v)); return (
{card.headline}
{card.sub}
{pts.map((p, i) => { const hot = i === pts.length - 1; return (
{p.v}
{p.l}
); })}
{card.source}
); } function RailQuoteCard({ card }) { return (
“{card.quote}”
{card.name} {card.loc}
); } function RailStatCard({ card }) { return (
{card.stat} {card.unit}
{card.headline}
{card.sub}
); } const RAIL_CARD_TYPES = { photo: RailPhotoCard, chart: RailChartCard, quote: RailQuoteCard, stat: RailStatCard }; function RailCard({ card }) { const Body = RAIL_CARD_TYPES[card.type] || RailPhotoCard; return (
); } /* ---- Live cams: rail card holding 1–2 remote feeds (severe weather / watch-and-wait) ---- */ function CamCell({ scene, h24, showTime = true }) { const def = window.HERO_SCENES[scene] || {}; const now = useNow(); const W = 466, H = Math.round(W * 9 / 16); return (
{def.locator} {showTime && {fmtTime(now, def.tz, h24)}}
{/* clean chroma hole — cam video keyed in downstream (magenta, same as hero) */}
); } function RailCamsCard({ cams, h24, camTimes = {} }) { return (
LIVE
{cams.map((c) => )}
); } /* ---- Rail countdown: card addendum — the card appears to extend down past its divider ---- */ function RailCountdown({ label = "TOP OF THE HOUR", target = null, accent = "var(--signal-cyan)" }) { const now = useNow(500); /* director-supplied absolute target (RFC3339); default: top of the hour */ let tgt = null; if (target) { const d = new Date(target); if (!isNaN(d.getTime())) tgt = d; } if (!tgt) { tgt = new Date(now); tgt.setMinutes(60, 0, 0); } const s = Math.max(0, Math.floor((tgt - now) / 1000)); const pad2 = (n) => String(n).padStart(2, "0"); const disp = s >= 172800 ? `${Math.floor(s / 86400)}D ${pad2(Math.floor((s % 86400) / 3600))}H` /* long-horizon (elections) */ : s >= 3600 ? `${pad2(Math.floor(s / 3600))}:${pad2(Math.floor((s % 3600) / 60))}:${pad2(s % 60)}` : `${pad2(Math.floor(s / 60))}:${pad2(s % 60)}`; /* flush under the card: shares the card's bottom hairline, paints over its shadow */ return (
{label} {disp}
); } function SideRail({ mode, h24, dwell = 18000, cams = [], camTimes }) { const cards = window.R1DATA.railCards; const idx = useCycle(cards.length, dwell, mode === "situation" || cams.length > 0); if (cams.length > 0) return ; if (mode === "situation") return ; if (!cards.length) return null; /* empty rail — show nothing, never crash */ const card = cards[idx % cards.length]; return (
); } /* ---- Situation rail: one static card — the timeline of what we know ---- */ function SituationRail() { const C = window.R1DATA.situation; if (!C || !(C.timeline || []).length) return null; /* no live situation content */ return (
DEVELOPING
{C.topic}
WHAT WE KNOW · TIMELINE
{C.timeline.map((t, i) => (
{t.t} {t.text}
))}
RADAR1 VERIFIED · ALL TIMES GMT
); } /* ================= INFO BAR — Now/Next · world city feature bar · animated logo ================= */ /* weather-type ambient animations — miniature broadcast weather FX, behind cell content */ function wxSeed(str) { let s = 0; for (let i = 0; i < str.length; i++) s = (s * 31 + str.charCodeAt(i)) % 2147483647; return s || 7; } function wxRand(seed) { let s = seed % 2147483647; if (s <= 0) s += 2147483646; return () => (s = (s * 16807) % 2147483647) / 2147483647; } function WxAnim({ type, seed = 7 }) { const layers = { position: "absolute", inset: 0, pointerEvents: "none" }; const vMask = { WebkitMaskImage: "linear-gradient(to bottom, transparent 0, black 18%, black 80%, transparent 100%)", maskImage: "linear-gradient(to bottom, transparent 0, black 18%, black 80%, transparent 100%)" }; const hMask = { WebkitMaskImage: "linear-gradient(to right, transparent 0, black 12%, black 88%, transparent 100%)", maskImage: "linear-gradient(to right, transparent 0, black 12%, black 88%, transparent 100%)" }; /* deterministic per-city randomization (no re-roll on re-render) */ const R = React.useMemo(() => { const r = wxRand(seed * 7919 + 13); return { drops: Array.from({ length: 16 }, () => ({ left: 4 + r() * 92, dur: 0.65 + r() * 0.75, delay: -r() * 2.2, op: 0.30 + r() * 0.38, h: 12 + r() * 12 })), clouds: Array.from({ length: 3 }, () => ({ top: 4 + r() * 30, dur: 26 + r() * 22, delay: -r() * 40, sc: 0.8 + r() * 0.7, op: 0.10 + r() * 0.08 })), }; }, [seed]); if (type === "sun") return (