const { useState, useEffect } = React; function App() { const [activeSection, setActiveSection] = useState(''); useEffect(() => { const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; if (prefersReducedMotion) return; gsap.registerPlugin(ScrollTrigger); // ── Page load sequence + hero word-split ── const wordSpans = document.querySelectorAll('.h1-word'); wordSpans.forEach(s => s.style.willChange = 'transform'); gsap.set('nav', { opacity: 0, y: -16 }); gsap.set('.hero-eyebrow', { opacity: 0, y: 12 }); gsap.set(wordSpans, { opacity: 0, y: 50 }); gsap.set('.hero-bottom', { opacity: 0, y: 20 }); const tl = gsap.timeline({ delay: 0.1 }); tl.to('nav', { opacity: 1, y: 0, duration: 0.5, ease: 'power2.out' }, 0.0) .to('.hero-eyebrow', { opacity: 1, y: 0, duration: 0.4, ease: 'power2.out' }, 0.2) .to(wordSpans, { opacity: 1, y: 0, duration: 0.7, ease: 'power3.out', stagger: 0.07, onComplete: () => wordSpans.forEach(s => s.style.willChange = 'auto') }, 0.4) .to('.hero-bottom', { opacity: 1, y: 0, duration: 0.5, ease: 'power2.out' }, 1.0); // ── Sectiekoppen: subtiele reveal ── gsap.utils.toArray('section .section-label, section h2, section .section-intro').forEach(el => { if (el.closest('.hero')) return; gsap.from(el, { y: 24, opacity: 0, duration: 0.6, ease: 'power2.out', immediateRender: false, scrollTrigger: { trigger: el, start: 'top 88%', once: true } }); }); // ── Calculator reveal ── gsap.from('.calculator', { y: 40, opacity: 0, duration: 0.7, ease: 'power2.out', immediateRender: false, scrollTrigger: { trigger: '.calculator', start: 'top 85%', once: true } }); // ── Contactform reveal ── gsap.from('.contact-form', { y: 30, opacity: 0, duration: 0.6, delay: 0.15, ease: 'power2.out', immediateRender: false, scrollTrigger: { trigger: '.cta-section', start: 'top 75%', once: true } }); // ── Guarantees ── gsap.from('.guarantee-item', { y: 30, opacity: 0, duration: 0.5, ease: 'power2.out', stagger: 0.1, immediateRender: false, scrollTrigger: { trigger: '.guarantees-grid', start: 'top 85%', once: true } }); gsap.from('.guarantee-ip', { y: 30, opacity: 0, duration: 0.6, ease: 'power2.out', immediateRender: false, scrollTrigger: { trigger: '.guarantee-ip', start: 'top 88%', once: true } }); // ── Value cards ── gsap.from('.value-card', { y: 30, opacity: 0, duration: 0.5, ease: 'power2.out', stagger: 0.08, immediateRender: false, scrollTrigger: { trigger: '.values-grid', start: 'top 85%', once: true } }); // ── Process steps ── gsap.from('.step', { x: -20, opacity: 0, duration: 0.4, ease: 'power2.out', stagger: 0.1, immediateRender: false, scrollTrigger: { trigger: '.process-steps', start: 'top 85%', once: true } }); // ── Service cards ── gsap.from('.service-card', { y: 20, opacity: 0, duration: 0.4, ease: 'power2.out', stagger: 0.07, immediateRender: false, scrollTrigger: { trigger: '.service-cards', start: 'top 85%', once: true } }); // ── Case card ── gsap.from('.case-info', { x: -40, opacity: 0, duration: 0.7, ease: 'power2.out', immediateRender: false, scrollTrigger: { trigger: '.case-card', start: 'top 80%', once: true } }); gsap.from('.mockup', { x: 40, opacity: 0, duration: 0.7, delay: 0.15, ease: 'power2.out', immediateRender: false, scrollTrigger: { trigger: '.case-card', start: 'top 80%', once: true } }); // ── Stat counter ── ScrollTrigger.create({ trigger: '.case-stats', start: 'top 80%', once: true, onEnter: () => { const el = document.getElementById('stat-cloud'); if (!el) return; const obj = { val: 0 }; anime({ targets: obj, val: 100, duration: 1200, easing: 'easeOutQuart', update: () => { el.textContent = Math.round(obj.val) + '%'; } }); } }); // ── Mockup parallax ── gsap.to('.mockup', { yPercent: -6, ease: 'none', scrollTrigger: { trigger: '.case-card', scrub: 2 } }); // ── Chart bars ── const bars = document.querySelectorAll('.bar'); ScrollTrigger.create({ trigger: '.mock-chart', start: 'top 85%', once: true, onEnter: () => { bars.forEach((bar, i) => { anime({ targets: bar, height: bar.dataset.height, duration: 600, delay: i * 60, easing: 'easeOutElastic(1, .8)' }); }); } }); // ── Magnetic buttons ── document.querySelectorAll('.magnetic').forEach(btn => { btn.addEventListener('mousemove', (e) => { const r = btn.getBoundingClientRect(); const dx = (e.clientX - (r.left + r.width / 2)) / (r.width / 2); const dy = (e.clientY - (r.top + r.height / 2)) / (r.height / 2); gsap.to(btn, { x: dx * 6, y: dy * 6, duration: 0.3, ease: 'power2.out' }); }); btn.addEventListener('mouseleave', () => { gsap.to(btn, { x: 0, y: 0, duration: 0.5, ease: 'elastic.out(1, 0.3)' }); }); }); // ── Nav active indicator ── ['#services', '#cases', '#pricing', '#contact'].forEach(id => { const el = document.querySelector(id); if (!el) return; ScrollTrigger.create({ trigger: el, start: 'top 60%', end: 'bottom 60%', onEnter: () => setActiveSection(id), onEnterBack: () => setActiveSection(id), onLeave: () => setActiveSection(s => s === id ? '' : s), onLeaveBack: () => setActiveSection(s => s === id ? '' : s), }); }); requestAnimationFrame(() => ScrollTrigger.refresh()); return () => { ScrollTrigger.getAll().forEach(t => t.kill()); }; }, []); return ( <>