/* ============================================================ ALWISP – main.js ============================================================ */ 'use strict'; // ── NAV: scroll shadow + mobile toggle ────────────────────── (function () { const header = document.getElementById('site-header'); const toggle = document.getElementById('nav-toggle'); const menu = document.getElementById('nav-menu'); const navLinks = menu ? menu.querySelectorAll('.nav__link') : []; // Scroll shadow if (header) { const onScroll = () => header.classList.toggle('scrolled', window.scrollY > 10); window.addEventListener('scroll', onScroll, { passive: true }); onScroll(); } // Mobile toggle if (toggle && menu) { toggle.addEventListener('click', () => { const isOpen = menu.classList.toggle('is-open'); toggle.setAttribute('aria-expanded', isOpen); }); // Close on nav link click navLinks.forEach(link => { link.addEventListener('click', () => { menu.classList.remove('is-open'); toggle.setAttribute('aria-expanded', 'false'); }); }); // Close on outside click document.addEventListener('click', e => { if (!header.contains(e.target)) { menu.classList.remove('is-open'); toggle.setAttribute('aria-expanded', 'false'); } }); } // Active nav link const currentPath = window.location.pathname.replace(/\/$/, '') || '/'; navLinks.forEach(link => { const href = link.getAttribute('href').replace(/\/$/, '') || '/'; if (href === currentPath) link.classList.add('nav__link--active'); }); }()); // ── COUNTER ANIMATION (stats bar) ─────────────────────────── (function () { const counters = document.querySelectorAll('.stat__value[data-count]'); if (!counters.length) return; const easeOut = t => 1 - Math.pow(1 - t, 3); function animateCounter(el) { const target = parseInt(el.dataset.count, 10); const duration = 1400; const start = performance.now(); function step(now) { const elapsed = now - start; const progress = Math.min(elapsed / duration, 1); el.textContent = Math.floor(easeOut(progress) * target); if (progress < 1) requestAnimationFrame(step); else el.textContent = target; } requestAnimationFrame(step); } const observer = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { animateCounter(entry.target); observer.unobserve(entry.target); } }); }, { threshold: 0.4 }); counters.forEach(c => observer.observe(c)); }()); // ── SCROLL REVEAL (cards, sections) ───────────────────────── (function () { const revealEls = document.querySelectorAll( '.card, .stat, .why__text, .section__header, .cta-band__content' ); if (!revealEls.length || !('IntersectionObserver' in window)) return; revealEls.forEach((el, i) => { el.style.opacity = '0'; el.style.transform = 'translateY(22px)'; el.style.transition = `opacity 0.55s ease ${i * 0.07}s, transform 0.55s ease ${i * 0.07}s`; }); const observer = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.style.opacity = '1'; entry.target.style.transform = 'translateY(0)'; observer.unobserve(entry.target); } }); }, { threshold: 0.12 }); revealEls.forEach(el => observer.observe(el)); }());