// Shared site chrome behavior: sticky header, accessible mobile menu, hero parallax. (function () { "use strict"; // ── Sticky header ────────────────────────────────────────────── const header = document.getElementById("site-header"); if (header) { const onScroll = () => header.classList.toggle("scrolled", window.scrollY > 40); window.addEventListener("scroll", onScroll, { passive: true }); onScroll(); } // ── Accessible mobile menu (dialog semantics) ────────────────── const hamburger = document.getElementById("hamburger"); const mobileMenu = document.getElementById("mobile-menu"); const menuClose = document.getElementById("menu-close"); if (hamburger && mobileMenu && menuClose) { const focusable = () => mobileMenu.querySelectorAll('a[href], button:not([disabled])'); const openMenu = () => { mobileMenu.classList.add("open"); hamburger.setAttribute("aria-expanded", "true"); menuClose.focus(); document.addEventListener("keydown", onKeydown); }; const closeMenu = () => { mobileMenu.classList.remove("open"); hamburger.setAttribute("aria-expanded", "false"); document.removeEventListener("keydown", onKeydown); hamburger.focus(); }; const onKeydown = (e) => { if (e.key === "Escape") { closeMenu(); return; } if (e.key !== "Tab") return; // Focus trap const items = focusable(); if (!items.length) return; const first = items[0]; const last = items[items.length - 1]; if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); } else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); } }; hamburger.addEventListener("click", openMenu); menuClose.addEventListener("click", closeMenu); mobileMenu.querySelectorAll("a").forEach((a) => a.addEventListener("click", closeMenu) ); } // ── Hero parallax (homepage only), rAF-throttled ─────────────── const heroBg = document.getElementById("hero-bg"); if (heroBg) { let ticking = false; const update = () => { if (window.scrollY < window.innerHeight) { heroBg.style.transform = `scale(1.03) translateY(${window.scrollY * 0.18}px)`; } ticking = false; }; window.addEventListener( "scroll", () => { if (!ticking) { window.requestAnimationFrame(update); ticking = true; } }, { passive: true } ); } })();