// Shared public-site behavior: scroll-reveal animations and the mobile // nav toggle. Loaded by both index.php and menu.php. // Reveal-on-scroll (() => { if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; const els = document.querySelectorAll('.reveal'); if (!('IntersectionObserver' in window)) { els.forEach((el) => el.classList.add('is-visible')); return; } const io = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { entry.target.classList.add('is-visible'); io.unobserve(entry.target); } }); }, { threshold: 0.15 }); els.forEach((el) => io.observe(el)); })(); // Mobile nav toggle (() => { const toggle = document.getElementById('nav-toggle'); const nav = document.getElementById('primary-nav'); if (!toggle || !nav) return; function closeNav() { nav.classList.remove('is-open'); toggle.setAttribute('aria-expanded', 'false'); } function openNav() { nav.classList.add('is-open'); toggle.setAttribute('aria-expanded', 'true'); } toggle.addEventListener('click', () => { if (nav.classList.contains('is-open')) { closeNav(); } else { openNav(); } }); // Close after following a link nav.querySelectorAll('a').forEach((link) => { link.addEventListener('click', closeNav); }); // Close on Escape window.addEventListener('keydown', (e) => { if (e.key === 'Escape') closeNav(); }); // Close on outside click document.addEventListener('click', (e) => { if (!nav.classList.contains('is-open')) return; if (nav.contains(e.target) || toggle.contains(e.target)) return; closeNav(); }); })();