// chrome.jsx — shared site chrome (nav, footer, ambient layers, page wrapper) // for every adult-side page. Uses CSS vars for theming. const { useState: useStateChr, useEffect: useEffectChr, useRef: useRefChr } = React; // ────────────────────────────────────────────────────────────────────── // PageShell — sets up the dark/light mode, ambient layers, mounts nav + // footer + mascot peeks + scroll reveal. // // // ...content // // ────────────────────────────────────────────────────────────────────── function PageShell({ active = 'home', dark = false, children, hideNav = false, footer = true }){ const rootRef = useRefChr(null); useReveal(rootRef); const [secret, setSecret] = useStateChr(false); return (
{/* Ambient background pieces */} {!hideNav && { setSecret(true); setTimeout(() => setSecret(false), 2400); }} />}
{children}
{footer && } {secret && (
♟ → 🐆 — you've unlocked nothing, but Amigo saw you
)}
); } // ────────────────────────────────────────────────────────────────────── // SiteNav — sticky pill nav with dark/light awareness // ────────────────────────────────────────────────────────────────────── function SiteNav({ active = 'home', dark = false, onSecret }){ const links = [ { id:'home', label:'Home', href:'index.html' }, { id:'training', label:'Training', href:'training.html' }, { id:'play', label:'Play Maia', href:'play.html' }, { id:'analysis', label:'Analysis', href:'analysis.html' }, { id:'kids', label:'Kids', href:'kids.html' }, { id:'pricing', label:'Pricing', href:'pricing.html' }, ]; const navBg = dark ? 'rgba(20,16,12,.72)' : 'rgba(255,250,242,.86)'; const navBorder = dark ? 'rgba(255,243,217,.18)' : 'var(--line-strong)'; const linkColor = dark ? 'rgba(255,247,230,.7)' : 'var(--ink-soft)'; return (
); } // ────────────────────────────────────────────────────────────────────── // SiteFooter — editorial colophon // ────────────────────────────────────────────────────────────────────── function SiteFooter({ dark = false }){ const muted = dark ? 'rgba(255,247,230,.5)' : 'var(--ink-muted)'; const text = dark ? 'rgba(255,247,230,.8)' : 'var(--ink-soft)'; const border = dark ? 'rgba(255,247,230,.12)' : 'var(--line-strong)'; const hover = dark ? '#fff7e6' : 'var(--ink)'; const sections = [ { h:'Product', links:[ ['Training', 'training.html'], ['Play Maia', 'play.html'], ['Analysis', 'analysis.html'], ['Kids', 'kids.html'], ['Pricing', 'pricing.html'], ] }, { h:'Exercises', links:[ ['Square Color', 'exercises/square-color.html'], ['Tap the Square', 'exercises/tap-square.html'], ['Knight Pathfinder', 'exercises/knight-pathfinder.html'], ['Position Memory', 'exercises/position-memory.html'], ['Notation', 'exercises/notation.html'], ['Blind Tactics', 'exercises/blind-tactics.html'], ['Blindfold', 'exercises/blindfold.html'], ] }, { h:'Pawnther', links:[ ['Join waitlist', 'pricing.html'], ['support@pawntherchess.com','mailto:support@pawntherchess.com'], ['About', 'about.html'], ] }, ]; return ( ); } // ────────────────────────────────────────────────────────────────────── // AmbientPieces — drifting chess piece silhouettes for the page background // ────────────────────────────────────────────────────────────────────── function AmbientPieces({ dark = false }){ // Static placement, but each piece has its own pwBgFloat animation const pieces = [ { glyph:'♞', x:'8%', y:'14%', size: 92, rot: -8, dur: 24 }, { glyph:'♛', x:'78%', y:'22%', size: 84, rot: 6, dur: 28 }, { glyph:'♟', x:'12%', y:'62%', size: 64, rot: 12, dur: 18 }, { glyph:'♝', x:'88%', y:'76%', size: 72, rot: -6, dur: 22 }, { glyph:'♜', x:'42%', y:'92%', size: 68, rot: 3, dur: 26 }, ]; const col = dark ? 'rgba(255,247,230,.06)' : 'rgba(25,23,20,.05)'; return (
{pieces.map((p, i) => ( {p.glyph} ))}
); } // ────────────────────────────────────────────────────────────────────── // CinematicHero — the locked direction's hero treatment // ────────────────────────────────────────────────────────────────────── function CinematicHero({ children, height = 'auto' }){ return (
{children}
); } // ────────────────────────────────────────────────────────────────────── // Folio — eyebrow text with line accent // ────────────────────────────────────────────────────────────────────── function Folio({ children, dark = false }){ return ( {children} ); } // ────────────────────────────────────────────────────────────────────── // Kicker — orange eyebrow used in section heads // ────────────────────────────────────────────────────────────────────── function Kicker({ children, color = 'var(--gold)' }){ return ( {children} ); } // ────────────────────────────────────────────────────────────────────── // CTAButton — primary CTA, theme aware // ────────────────────────────────────────────────────────────────────── function CTAButton({ children, variant = 'gold', size = 'md', ...rest }){ const sizes = { md: { padding: '12px 18px', fontSize: 13.5 }, lg: { padding: '14px 22px', fontSize: 14 }, }; const variants = { gold: { background:'var(--gold)', color:'#1a120a', shadow:'0 12px 30px -10px rgba(227,155,68,.5)' }, ink: { background:'var(--ink)', color:'var(--paper-100)', shadow:'0 8px 22px -12px rgba(0,0,0,.45)' }, ghost: { background:'rgba(255,253,248,.7)', color:'var(--ink)', shadow:'none', border:'1px solid var(--line)' }, dark: { background:'rgba(255,247,230,.07)', color:'#fff7e6', shadow:'none', border:'1px solid rgba(255,247,230,.2)' }, }; const v = variants[variant]; return ( ); } Object.assign(window, { PageShell, SiteNav, SiteFooter, AmbientPieces, CinematicHero, Folio, Kicker, CTAButton, });