/* ============================================================ main.js — Scroll animations, counters, FAQ, BA slider ============================================================ */ (function () { 'use strict'; /* --- Scroll animation (IntersectionObserver) ------------ */ function initScrollAnimations() { const els = document.querySelectorAll('[data-animate]'); if (!els.length) return; const obs = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('in-view'); obs.unobserve(entry.target); } }); }, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' }); els.forEach(el => obs.observe(el)); } /* --- Animated counters ---------------------------------- */ function animateCounter(el) { const target = parseFloat(el.dataset.count); const suffix = el.dataset.suffix || ''; const prefix = el.dataset.prefix || ''; const decimals = (target % 1 !== 0) ? 1 : 0; const duration = 1600; const start = performance.now(); function tick(now) { const elapsed = now - start; const progress = Math.min(elapsed / duration, 1); const ease = 1 - Math.pow(1 - progress, 3); const value = target * ease; el.textContent = prefix + value.toFixed(decimals) + suffix; if (progress < 1) requestAnimationFrame(tick); } requestAnimationFrame(tick); } function initCounters() { const counters = document.querySelectorAll('[data-count]'); if (!counters.length) return; const obs = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { animateCounter(entry.target); obs.unobserve(entry.target); } }); }, { threshold: 0.3 }); counters.forEach(el => obs.observe(el)); } /* --- FAQ accordion -------------------------------------- */ function initFAQ() { document.querySelectorAll('.faq-item').forEach(item => { const q = item.querySelector('.faq-question'); if (!q) return; q.addEventListener('click', () => { const isOpen = item.classList.contains('open'); // close all document.querySelectorAll('.faq-item.open').forEach(i => { i.classList.remove('open'); }); if (!isOpen) item.classList.add('open'); }); }); } /* --- Before / After slider ------------------------------ */ function initBASlider(slider) { const handle = slider.querySelector('.ba-handle'); const beforeWrap = slider.querySelector('.ba-before-wrap'); if (!handle || !beforeWrap) return; let dragging = false; function setPosition(clientX) { const rect = slider.getBoundingClientRect(); const rawPct = (clientX - rect.left) / rect.width; const pct = Math.min(Math.max(rawPct, 0.02), 0.98); beforeWrap.style.width = (pct * 100) + '%'; handle.style.left = (pct * 100) + '%'; } handle.addEventListener('mousedown', () => { dragging = true; }); handle.addEventListener('touchstart', () => { dragging = true; }, { passive: true }); window.addEventListener('mousemove', e => { if (dragging) setPosition(e.clientX); }); window.addEventListener('touchmove', e => { if (dragging) setPosition(e.touches[0].clientX); }, { passive: true }); window.addEventListener('mouseup', () => { dragging = false; }); window.addEventListener('touchend', () => { dragging = false; }); slider.addEventListener('click', e => setPosition(e.clientX)); } function initBASliders() { document.querySelectorAll('.ba-slider').forEach(initBASlider); } /* --- Smooth scroll for anchor links --------------------- */ function initSmoothScroll() { document.querySelectorAll('a[href^="#"]').forEach(a => { a.addEventListener('click', e => { const id = a.getAttribute('href').slice(1); const target = document.getElementById(id); if (!target) return; e.preventDefault(); const headerH = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--header-h')) || 72; const top = target.getBoundingClientRect().top + window.scrollY - headerH - 16; window.scrollTo({ top, behavior: 'smooth' }); }); }); } /* --- Video hero fallback -------------------------------- */ function initHeroVideo() { const video = document.querySelector('.hero-video-wrap video'); if (!video) return; video.play().catch(() => { // autoplay blocked — poster image is visible; nothing to do }); } /* --- Testimonial auto-scroll (on mobile) ---------------- */ function initTestimonialScroll() { const track = document.querySelector('.testimonial-track'); if (!track) return; let isPaused = false; track.addEventListener('mouseenter', () => { isPaused = true; }); track.addEventListener('mouseleave', () => { isPaused = false; }); // keyboard scroll within track track.setAttribute('tabindex', '0'); } /* --- Boot ---------------------------------------------- */ function boot() { initScrollAnimations(); initCounters(); initFAQ(); initBASliders(); initSmoothScroll(); initHeroVideo(); initTestimonialScroll(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', boot); } else { boot(); } })();