/* Axon.ps website kit — ProductSheet A single premium product-detail surface, on-system with the manuscript/orbital language. Desktop: a floating "folio" panel with a structural orbital header and a crimson signal rule. Mobile: a native-feeling bottom sheet. Driven by the decoupled 'axon:product' event (works across all script files). Accessible: ESC + backdrop close, focus move-in / restore, focus trap, visible focus states, aria-modal, body scroll lock, reduced-motion aware. */ function ProductSheet() { const [active, setActive] = React.useState(null); // product id or null const originRef = React.useRef(null); const panelRef = React.useRef(null); const closeRef = React.useRef(null); const [closing, setClosing] = React.useState(false); const close = React.useCallback(() => { setClosing(true); setTimeout(() => { setClosing(false); setActive(null); const o = originRef.current; if (o && typeof o.focus === 'function') o.focus(); originRef.current = null; }, 240); }, []); // listen for open requests from any product lens React.useEffect(() => { const onOpen = (e) => { const id = e.detail && e.detail.id; if (!id || !PRODUCT_DETAIL[id]) return; originRef.current = (e.detail && e.detail.origin) || document.activeElement; setClosing(false); setActive(id); }; window.addEventListener('axon:product', onOpen); return () => window.removeEventListener('axon:product', onOpen); }, []); // open side-effects: scroll lock, focus move, ESC, focus trap React.useEffect(() => { if (!active) return; const prevOverflow = document.body.style.overflow; document.body.style.overflow = 'hidden'; const t = setTimeout(() => { if (closeRef.current) closeRef.current.focus(); }, 60); const onKey = (e) => { if (e.key === 'Escape') { e.preventDefault(); close(); return; } if (e.key === 'Tab') { const panel = panelRef.current; if (!panel) return; const focusable = panel.querySelectorAll('a[href], button:not([disabled]), input, [tabindex]:not([tabindex="-1"])'); if (!focusable.length) return; const first = focusable[0], last = focusable[focusable.length - 1]; if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); } else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); } } }; document.addEventListener('keydown', onKey); return () => { document.body.style.overflow = prevOverflow; clearTimeout(t); document.removeEventListener('keydown', onKey); }; }, [active, close]); if (!active) return null; const p = PRODUCT_DETAIL[active]; const state = closing ? 'closing' : 'open'; return (
{ if (e.target === e.currentTarget) close(); }}>
{/* structural orbital header — echoes the hero diagram */}
{p.reveal ? : {p.category}} {p.reveal ? Awaiting reveal : (p.soon && In development)}

{p.name}

{p.reveal ? (
{/* redacted manuscript lines — details held under seal */} {/* wax-seal node with the product initial */}

This system is sealed for now — kept under wraps until its unveiling.
Details will be revealed when {p.name} is ready.

Reveal pending axon.ps{p.href}
) : ( <>

{p.desc}

{p.href && !p.href.startsWith('/products/') ? ( Open product ) : ( In development )} {p.href && !p.href.startsWith('/products/') && axon.ps{p.href}}
)}
); } Object.assign(window, { ProductSheet });