(() => { "use strict"; const counters = Array.from(document.querySelectorAll(".counter")); if (!counters.length) return; const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches; const showFinalValue = (element) => { const value = Number(element.dataset.count || 0); const suffix = element.dataset.suffix || ""; element.textContent = `${Math.round(value)}${suffix}`; }; const animateCounter = (element) => { if (element.dataset.counted === "true") return; element.dataset.counted = "true"; const target = Number(element.dataset.count || 0); const suffix = element.dataset.suffix || ""; const duration = Number(element.dataset.duration || 1450); if (!Number.isFinite(target) || reducedMotion) { showFinalValue(element); return; } const start = performance.now(); const easeOutCubic = (progress) => 1 - Math.pow(1 - progress, 3); const tick = (now) => { const progress = Math.min(1, (now - start) / duration); const current = Math.round(target * easeOutCubic(progress)); element.textContent = `${current}${suffix}`; if (progress < 1) requestAnimationFrame(tick); }; requestAnimationFrame(tick); }; if (!("IntersectionObserver" in window)) { counters.forEach(animateCounter); return; } const observer = new IntersectionObserver( (entries, currentObserver) => { entries.forEach((entry) => { if (!entry.isIntersecting) return; animateCounter(entry.target); currentObserver.unobserve(entry.target); }); }, { threshold: 0.45 } ); counters.forEach((counter) => observer.observe(counter)); })();