/* Geek n Wine — Editorial Home: presentational components */ const { useState, useEffect, useRef } = React; const ASSET = "assets/"; /* ============ Brand SVGs — inlined so the build has zero external image requests ============ */ function Mark({ size = 40, paper = false }) { const id = React.useId().replace(/:/g, ""); return ( ); } function VoltDrop({ size = 13 }) { return ( ); } function GoldStar({ size = 13 }) { return ( ); } function Wordmark({ width = 186, paper = false, className }) { const id = React.useId().replace(/:/g, ""); const fg = paper ? "#1B0B11" : "#FBF6EC"; const nClr = paper ? "#8A0F33" : "#CDFF4A"; const drop = paper ? "#8A0F33" : "#CDFF4A"; const stroke = paper ? "#6E0B2A" : "#A11A45"; const sub = paper ? "rgba(27,11,17,0.42)" : "rgba(251,246,236,0.46)"; return ( GEEK n WINE WINE, DROPPED. ); } /* The sealed box — brand hero object, pure CSS */ function BoxVisual({ size = 168, sku = "GW-014", hint = true, hintText = "1 in 11 hides a Reserve", sealed = true }) { return (
{hint && ( {hintText} )} {sku} · {sealed ? "SEALED" : "OPEN"}
); } function LiveDot() { return ; } /* The wine crate — six bottles, one gold = the possible Reserve. Pure CSS, the new hero object */ function WineCrate({ size = 360, sku = "GW-014", hint = true, hintText = "1 in 11 hides a Reserve", sealed = true }) { const goldIdx = 3; return (
{hint && ( {hintText} )}
{[0, 1, 2, 3, 4, 5].map((i) => (
))}
{sku} · {sealed ? "SEALED" : "OPEN"}
); } function useCountdown(seconds) { const [t, setT] = useState(seconds); useEffect(() => { const id = setInterval(() => setT((v) => (v > 0 ? v - 1 : 0)), 1000); return () => clearInterval(id); }, []); const h = String(Math.floor(t / 3600)).padStart(2, "0"); const m = String(Math.floor((t % 3600) / 60)).padStart(2, "0"); const s = String(t % 60).padStart(2, "0"); return { h, m, s, str: `${h}:${m}:${s}` }; } function TimerBar({ h, m, s, center }) { return (
{[["hrs", h], ["min", m], ["sec", s]].map(([l, v]) => (
{v}{l}
))}
); } /* Reserve bar — boxes REMAINING, draining down. readout: 'Boxes left' | 'Percent' | 'Both' */ function ReserveBar({ claimed, total, readout = "Boxes left" }) { const left = total - claimed; const pctLeft = Math.round((left / total) * 100); const low = pctLeft <= 20; const leftStr = `${left} / ${total}`; return (
Boxes remaining · this drop {readout !== "Percent" && {leftStr} left} {readout === "Both" && · } {readout !== "Boxes left" && {pctLeft}%}
{claimed} claimed {low ? "ALMOST GONE — DRAINING FAST" : "DRAINING"}
); } /* Odds grid — N boxes, one glowing volt = the hidden bottle */ function OddsGrid({ n = 11 }) { const hit = Math.floor(n / 2); // glow roughly mid-grid return (
{Array.from({ length: n }).map((_, i) => (
{i === hit && }
))}
); } function Step({ n, title, children }) { return (
{n}

{title}

{children}

); } /* Wine accordion row */ function WineRow({ wine, idx, open, onToggle }) { return (
{wine.code} {wine.name} {wine.region} · {wine.grape}

{wine.note}

{wine.body} {wine.grape} {wine.abv} Pairs with {wine.pair}
); } function Footer() { return ( ); } Object.assign(window, { Mark, VoltDrop, GoldStar, Wordmark, BoxVisual, WineCrate, LiveDot, useCountdown, TimerBar, ReserveBar, OddsGrid, Step, WineRow, Footer, ASSET });