1const navToggle = document.querySelector("[data-nav-toggle]"); 2const nav = document.querySelector("[data-nav]"); 3const header = document.querySelector("[data-header]"); 4const scrollProgress = document.querySelector(".scroll-progress"); 5const root = document.documentElement; 6 7if (navToggle && nav) { 8 navToggle.addEventListener("click", () => { 9 const isOpen = nav.classList.toggle("is-open"); 10 navToggle.setAttribute("aria-expanded", String(isOpen)); 11 navToggle.setAttribute("aria-label", isOpen ? "Fermer le menu" : "Ouvrir le menu"); 12 }); 13 14 nav.addEventListener("click", (event) => { 15 if (event.target instanceof HTMLAnchorElement) { 16 nav.classList.remove("is-open"); 17 navToggle.setAttribute("aria-expanded", "false"); 18 navToggle.setAttribute("aria-label", "Ouvrir le menu"); 19 } 20 }); 21 22 document.addEventListener("click", (event) => { 23 if (!nav.classList.contains("is-open")) return; 24 const target = event.target; 25 if (!(target instanceof Node)) return; 26 if (nav.contains(target) || navToggle.contains(target)) return; 27 nav.classList.remove("is-open"); 28 navToggle.setAttribute("aria-expanded", "false"); 29 navToggle.setAttribute("aria-label", "Ouvrir le menu"); 30 }); 31 32 document.addEventListener("keydown", (event) => { 33 if (event.key !== "Escape" || !nav.classList.contains("is-open")) return; 34 nav.classList.remove("is-open"); 35 navToggle.setAttribute("aria-expanded", "false"); 36 navToggle.setAttribute("aria-label", "Ouvrir le menu"); 37 navToggle.focus(); 38 }); 39} 40 41const updateHeaderState = () => { 42 if (!header) return; 43 header.classList.toggle("is-scrolled", window.scrollY > 8); 44}; 45 46updateHeaderState(); 47window.addEventListener("scroll", updateHeaderState, { passive: true }); 48 49const updateScrollEffects = () => { 50 const maxScroll = Math.max(1, document.documentElement.scrollHeight - window.innerHeight); 51 const progress = Math.min(1, Math.max(0, window.scrollY / maxScroll)); 52 root.style.setProperty("--scroll-progress", progress.toFixed(4)); 53 root.style.setProperty("--hero-shift", `${Math.min(42, window.scrollY * 0.08).toFixed(2)}px`); 54}; 55 56updateScrollEffects(); 57window.addEventListener("scroll", updateScrollEffects, { passive: true }); 58 59if (scrollProgress) { 60 scrollProgress.setAttribute("role", "presentation"); 61} 62 63const revealTargets = document.querySelectorAll( 64 ".section, .hero-metrics div, .section-heading, .info-card, .feature-card, .photo-story-card, .sticky-photo, .employee-portal-band, .benefit-list article, .screenshot-card, .pricing-card, .implementation-list, .statement" 65); 66 67if ("IntersectionObserver" in window) { 68 const observer = new IntersectionObserver( 69 (entries) => { 70 entries.forEach((entry) => { 71 if (entry.isIntersecting) { 72 entry.target.classList.add("is-visible"); 73 observer.unobserve(entry.target); 74 } 75 }); 76 }, 77 { threshold: 0.16, rootMargin: "0px 0px -70px 0px" } 78 ); 79 80 revealTargets.forEach((target, index) => { 81 target.classList.add("reveal"); 82 target.style.setProperty("--reveal-delay", `${Math.min(index % 4, 3) * 70}ms`); 83 if (target.classList.contains("section")) { 84 target.classList.add(index % 2 === 0 ? "reveal-from-left" : "reveal-from-right"); 85 } 86 observer.observe(target); 87 }); 88} else { 89 revealTargets.forEach((target) => { 90 target.classList.add("is-visible"); 91 }); 92}
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.