/* global React, ReactDOM, Icon, Wordmark */ // ============================================================ // Coming soon — standalone marketing page template. // Reuses the shared design tokens (styles.css) + Wordmark/Icon so it // stays on-brand. Swap copy / launch date freely; this is a template. // ============================================================ const { useState: useStateCS } = React; // Launch target — change this date to drive the countdown. const LAUNCH_TS = new Date('2026-08-15T17:00:00Z').getTime(); function useCountdown(target) { const [now, setNow] = useStateCS(Date.now()); React.useEffect(() => { const id = setInterval(() => setNow(Date.now()), 1000); return () => clearInterval(id); }, []); const diff = Math.max(0, target - now); const d = Math.floor(diff / 86400000); const h = Math.floor((diff % 86400000) / 3600000); const m = Math.floor((diff % 3600000) / 60000); const s = Math.floor((diff % 60000) / 1000); return { d, h, m, s, done: diff === 0 }; } function CountUnit({ value, label }) { return (
{String(value).padStart(2, '0')}
{label}
); } function ComingSoon() { const t = useCountdown(LAUNCH_TS); const [email, setEmail] = useStateCS(''); const [sent, setSent] = useStateCS(false); const valid = /.+@.+\..+/.test(email); function submit(e) { e.preventDefault(); if (!valid) return; setSent(true); } return (
Beta coming soon

A calmer home for your
characters, grinds & static.

Crystaltide ties together what's scattered across spreadsheets and single-purpose sites; synced from public data, tracked the way your group actually plays. We're putting on the finishing touches.

); } ReactDOM.createRoot(document.getElementById('root')).render();