// app.jsx — main App with Tweaks const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "accent": "cyan", "fontPair": "geist", "density": "regular", "grid": true }/*EDITMODE-END*/; const ACCENT_PRESETS = { cyan: { a: "oklch(0.82 0.14 200)", b: "oklch(0.74 0.16 285)" }, violet: { a: "oklch(0.74 0.17 290)", b: "oklch(0.78 0.16 340)" }, amber: { a: "oklch(0.82 0.16 70)", b: "oklch(0.74 0.18 30)" }, mint: { a: "oklch(0.84 0.14 160)", b: "oklch(0.78 0.13 200)" }, }; const FONT_PAIRS = { geist: { sans: '"Geist", system-ui, sans-serif', mono: '"Geist Mono", ui-monospace, monospace' }, manrope: { sans: '"Manrope", system-ui, sans-serif', mono: '"JetBrains Mono", ui-monospace, monospace' }, satoshi: { sans: '"Plus Jakarta Sans", system-ui, sans-serif', mono: '"IBM Plex Mono", ui-monospace, monospace' }, }; const DENSITY = { compact: { container: 1180, gutter: '40px', section: '90px', radius: 12 }, regular: { container: 1240, gutter: 'clamp(20px, 4vw, 56px)', section: 'clamp(80px, 11vw, 140px)', radius: 16 }, comfy: { container: 1320, gutter: 'clamp(28px, 5vw, 72px)', section: 'clamp(100px, 13vw, 180px)', radius: 20 }, }; function App() { const [t, setTweak] = useTweaks(TWEAK_DEFAULTS); // Apply tweaks as CSS vars on :root React.useEffect(() => { const root = document.documentElement; const acc = ACCENT_PRESETS[t.accent] || ACCENT_PRESETS.cyan; root.style.setProperty('--accent', acc.a); root.style.setProperty('--accent-2', acc.b); const f = FONT_PAIRS[t.fontPair] || FONT_PAIRS.geist; root.style.setProperty('--font-sans', f.sans); root.style.setProperty('--font-mono', f.mono); const d = DENSITY[t.density] || DENSITY.regular; root.style.setProperty('--container', d.container + 'px'); root.style.setProperty('--gutter', d.gutter); document.body.classList.toggle('no-grid', !t.grid); }, [t.accent, t.fontPair, t.density, t.grid]); // Reveal-on-scroll observer (run once on mount) React.useEffect(() => { const els = document.querySelectorAll('.reveal'); // Above-the-fold reveals: show immediately so first paint isn't blank const vh = window.innerHeight; els.forEach(el => { const r = el.getBoundingClientRect(); if (r.top < vh * 0.9) el.classList.add('in'); }); const io = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); } }); }, { threshold: 0.08, rootMargin: '0px 0px -40px 0px' }); els.forEach(el => { if (!el.classList.contains('in')) io.observe(el); }); return () => io.disconnect(); }, []); return ( <>