/* Single external script (no inline JS anywhere → strict script-src 'self'). Loaded blocking in so the theme is set before first paint (no flash). */ (function () { // --- Pre-paint theme ----------------------------------------------------- try { var stored = localStorage.getItem("theme"); var theme = stored || (window.matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark"); document.documentElement.dataset.theme = theme; } catch (e) { document.documentElement.dataset.theme = "dark"; } // Mark JS as live BEFORE first paint. CSS only hides the pre-reveal animation // state under `html.js`, so with JS off every element stays visible (the // Motion layer in /_astro reveals them once it runs). Progressive enhancement. document.documentElement.classList.add("js"); function onReady(fn) { if (document.readyState !== "loading") fn(); else document.addEventListener("DOMContentLoaded", fn); } onReady(function () { // --- Theme toggle ------------------------------------------------------ var btn = document.getElementById("theme-toggle"); if (btn) { btn.addEventListener("click", function () { var root = document.documentElement; var next = root.dataset.theme === "light" ? "dark" : "light"; root.dataset.theme = next; try { localStorage.setItem("theme", next); } catch (e) { /* ignore */ } }); } // Scroll reveals, hero entrance, backdrop parallax, scroll-progress bar, // nav underline and button springs all live in the Motion layer // (src/scripts/anim.ts → bundled /_astro/*.js). This file owns only the // pre-paint theme so it can stay a tiny blocking script. }); })();