// App entry const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "glass": "subtle", "grain": true }/*EDITMODE-END*/; function App() { const [t, setTweak] = useTweaks(TWEAK_DEFAULTS); const [openSvc, setOpenSvc] = React.useState(null); const contactRef = React.useRef(null); useReveal(); React.useEffect(() => { document.body.dataset.glass = t.glass; document.querySelector('.grain').style.display = t.grain ? '' : 'none'; }, [t]); React.useEffect(() => { if (!window.location.hash) return; history.scrollRestoration = 'manual'; const id = window.location.hash.slice(1); const go = () => { const el = document.getElementById(id); if (el) { const top = el.getBoundingClientRect().top + window.scrollY - 90; window.scrollTo({ top, behavior: 'smooth' }); } }; // double rAF: fires after the browser calculates layout and paints requestAnimationFrame(() => requestAnimationFrame(go)); }, []); const scrollContact = () => { const el = document.querySelector('section:nth-last-of-type(2)') || document.querySelector('form'); if (el) window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - 80, behavior: 'smooth' }); }; return (