/* global React, Icons, PlugBot, Wordmark */ const { useState } = React; /* ========================================================================= Shared atomic components ========================================================================= */ const Badge = ({ kind, children, dot = false }) => ( {dot && } {children} ); const Pill = ({ on, onClick, children }) => ( ); const Btn = ({ kind = 'ghost', size, onClick, children, href, icon, iconRight }) => { const cls = `btn btn-${kind} ${size === 'sm' ? 'btn-sm' : ''}`; const inner = ( <> {icon} {children} {iconRight} ); if (href) return {inner}; return ; }; const Meter = ({ value, max = 100, tone = '' }) => (
); const Score = ({ value }) => ( {value.toFixed(1)}/ 10 ); const Stat = ({ label, value, unit, tone }) => (
{value}{unit && {unit}}
{label}
); const Eyebrow = ({ children, dot = true }) => (
{dot && } {children}
); // LastVerified — appears on every perishable surface (plans, gear, policy). // Pass a date string and an optional `staleAfterDays` (default 120) to flip // the stamp into warn-mode when content drifts past the threshold. const LastVerified = ({ date, staleAfterDays = 120, prefix = 'Last verified' }) => { const d = new Date(date); const ageDays = Number.isFinite(d.getTime()) ? Math.floor((Date.now() - d.getTime()) / 86400000) : null; const stale = ageDays !== null && ageDays > staleAfterDays; return ( {prefix} · {date}{stale ? ' · STALE' : ''} ); }; /* ========================================================================= Top navigation ========================================================================= */ const NAV = [ { id: 'home', label: 'Start' }, { id: 'build', label: 'Builds' }, { id: 'gear', label: 'Gear Lab' }, { id: 'data', label: 'Data' }, { id: 'bonding', label: 'Bonding' }, { id: 'platforms', label: 'Platforms' }, { id: 'safety', label: 'Safety' }, { id: 'streamer', label: 'Streamers' }, { id: 'toolkit', label: 'Toolkit' }, { id: 'deals', label: 'Deals' }, ]; const TopNav = ({ page, onNav }) => (
onNav('home')} style={{ cursor: 'pointer' }}>
{/* Search button removed for Phase 1 — search lands in Phase 2 once content collections exist to search over. Keeping the button visible without a destination would just be more dead UI. */} onNav('build')}> Build mine
); /* ========================================================================= Footer Every link is now honest: - In-site nav uses with preventDefault so keyboard focus + screen-reader semantics work; onNav is passed in from app.jsx. - mailto: for actionable email surfaces (Contact, early-list newsletter, Submit a setup). - Soon tag on items that don't have a destination yet — visibly tagged instead of silently dead. ========================================================================= */ const Soon = () => soon; const Footer = ({ onNav }) => { const link = (id) => (e) => { e.preventDefault(); onNav?.(id); }; return ( ); }; /* ========================================================================= Live signal strip (data ticker) ========================================================================= */ // SignalStrip — single live data ticker across the top of the home page. // Numbers reflect Streams Charts Q1 2026 (hours-watched basis); Twitch +4.46% // QoQ vs TikTok Live -11.92% — narrative is no-longer-Twitch-in-decline. const SignalStrip = () => (
● LIVE TWITCH Q1·26+4.46% QoQ TIKTOK LIVE Q1·26−11.92% QoQ TWITCH MONETIZATION-FOR-ALLlive · May 26 VERIFIED BUILDS247 PLANS TRACKED34 carriers SOURCE · STREAMS CHARTS Q1 ’26
); /* ========================================================================= Mobile frame (for paired view) ========================================================================= */ const PhoneFrame = ({ children, page }) => (
9:41 78
{children}
); window.Badge = Badge; window.Pill = Pill; window.Btn = Btn; window.Meter = Meter; window.Score = Score; window.Stat = Stat; window.Eyebrow = Eyebrow; window.LastVerified = LastVerified; window.TopNav = TopNav; window.Footer = Footer; window.SignalStrip = SignalStrip; window.PhoneFrame = PhoneFrame;