1document.addEventListener('DOMContentLoaded', function () { 2 const btn = document.querySelector('.mobile-toggle'); 3 const nav = document.querySelector('.nav-links'); 4 if (btn && nav) { 5 function setMenu(open) { 6 nav.classList.toggle('open',open); 7 btn.setAttribute('aria-expanded',open ? 'true' : 'false'); 8 btn.setAttribute('aria-label',open ? 'Close navigation' : 'Open navigation'); 9 } 10 btn.addEventListener('click',()=>setMenu(!nav.classList.contains('open'))); 11 document.addEventListener('keydown',event=>{ 12 if(event.key==='Escape' && nav.classList.contains('open')) {setMenu(false);btn.focus();} 13 }); 14 document.addEventListener('click',event=>{ 15 if(!nav.contains(event.target) && !btn.contains(event.target)) setMenu(false); 16 }); 17 nav.addEventListener('click',event=>{if(event.target.closest('a'))setMenu(false);}); 18 window.matchMedia('(min-width: 1101px)').addEventListener('change',()=>setMenu(false)); 19 } 20 21 document.querySelectorAll('[data-rotator]').forEach(function(rotator) { 22 const slides = Array.from(rotator.querySelectorAll('[data-slide]')); 23 if (slides.length < 2) return; 24 const dotsWrap = rotator.querySelector('[data-dots]'); 25 let index = Math.max(0, slides.findIndex(s => s.classList.contains('is-active'))); 26 let timer; 27 const interval = parseInt(rotator.dataset.interval || '6500', 10); 28 const dots = slides.map(function(_, i) { 29 const dot = document.createElement('button'); 30 dot.type = 'button'; dot.className = 'rotator-dot'; 31 dot.setAttribute('aria-label', 'Show item ' + (i + 1)); 32 dot.addEventListener('click', function(){ show(i, true); }); 33 if (dotsWrap) dotsWrap.appendChild(dot); 34 return dot; 35 }); 36 function show(next, restart) { 37 slides[index].classList.remove('is-active'); 38 if (dots[index]) dots[index].classList.remove('is-active'); 39 index = (next + slides.length) % slides.length; 40 slides[index].classList.add('is-active'); 41 if (dots[index]) dots[index].classList.add('is-active'); 42 if (restart) start(); 43 } 44 function start() { 45 clearInterval(timer); 46 if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) timer = setInterval(() => show(index + 1, false), interval); 47 } 48 const prev = rotator.querySelector('[data-prev]'); 49 const next = rotator.querySelector('[data-next]'); 50 if (prev) prev.addEventListener('click', () => show(index - 1, true)); 51 if (next) next.addEventListener('click', () => show(index + 1, true)); 52 show(index, false); start(); 53 rotator.addEventListener('mouseenter', () => clearInterval(timer)); 54 rotator.addEventListener('mouseleave', start); 55 }); 56 57 document.querySelectorAll('[data-agent-conveyor]').forEach(function(conveyor) { 58 const track = conveyor.querySelector('[data-agent-track]'); 59 if (!track || track.dataset.cloned === 'true') return; 60 const originals = Array.from(track.children); 61 if (!originals.length) return; 62 originals.forEach(function(card) { 63 const clone = card.cloneNode(true); 64 clone.setAttribute('aria-hidden', 'true'); 65 clone.querySelectorAll('a').forEach(function(link){ link.setAttribute('tabindex','-1'); }); 66 track.appendChild(clone); 67 }); 68 track.dataset.cloned = 'true'; 69 }); 70 71});
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.