1(() => { 2 const header = document.querySelector('[data-header]') 3 const toggle = document.querySelector('[data-menu-toggle]') 4 const menu = document.querySelector('[data-mobile-menu]') 5 const toggleLabel = toggle?.querySelector('.sr-only') 6 7 const closeMenu = (restoreFocus = false) => { 8 if (!toggle || !menu) 9 return 10 toggle.setAttribute('aria-expanded', 'false') 11 if (toggleLabel) 12 toggleLabel.textContent = 'Open navigation' 13 menu.hidden = true 14 document.body.classList.remove('menu-open') 15 if (restoreFocus) 16 toggle.focus() 17 } 18 19 toggle?.addEventListener('click', () => { 20 const opening = toggle.getAttribute('aria-expanded') !== 'true' 21 toggle.setAttribute('aria-expanded', String(opening)) 22 if (toggleLabel) 23 toggleLabel.textContent = opening ? 'Close navigation' : 'Open navigation' 24 menu.hidden = !opening 25 document.body.classList.toggle('menu-open', opening) 26 if (opening) 27 menu.querySelector('a')?.focus() 28 }) 29 30 menu?.querySelectorAll('a').forEach(link => link.addEventListener('click', () => closeMenu())) 31 document.addEventListener('keydown', (event) => { 32 if (event.key === 'Escape' && toggle?.getAttribute('aria-expanded') === 'true') 33 closeMenu(true) 34 }) 35 window.addEventListener('resize', () => { 36 if (window.innerWidth > 780) 37 closeMenu() 38 }) 39 window.addEventListener('scroll', () => header?.classList.toggle('scrolled', window.scrollY > 12), { passive: true }) 40 41 const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches 42 const reveals = document.querySelectorAll('.reveal:not(.is-visible)') 43 if (reducedMotion || !('IntersectionObserver' in window)) { 44 reveals.forEach(element => element.classList.add('is-visible')) 45 } 46 else { 47 const observer = new IntersectionObserver((entries) => { 48 entries.forEach((entry) => { 49 if (!entry.isIntersecting) 50 return 51 entry.target.classList.add('is-visible') 52 observer.unobserve(entry.target) 53 }) 54 }, { rootMargin: '0px 0px -8% 0px', threshold: 0.08 }) 55 reveals.forEach(element => observer.observe(element)) 56 } 57})()
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.