/* HLiD — Hero & Pillar sections */ const { useState, useEffect, useRef } = React; /* Minimal in-view hook */ function useInView(threshold = 0.2) { const ref = useRef(null); const [inView, setInView] = useState(false); useEffect(() => { if (!ref.current) return; const io = new IntersectionObserver(([e]) => e.isIntersecting && setInView(true), { threshold }); io.observe(ref.current); return () => io.disconnect(); }, [threshold]); return [ref, inView]; } /* Number tick-up */ function Counter({ to, suffix = '', prefix = '', duration = 1600 }) { const [ref, inView] = useInView(0.4); const [n, setN] = useState(0); useEffect(() => { if (!inView) return; const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches; if (prefersReduced) { setN(to); return; } const start = performance.now(); let raf; const tick = (now) => { const p = Math.min(1, (now - start) / duration); const eased = 1 - Math.pow(1 - p, 3); setN(Math.floor(to * eased)); if (p < 1) raf = requestAnimationFrame(tick); else setN(to); }; raf = requestAnimationFrame(tick); return () => cancelAnimationFrame(raf); }, [inView, to, duration]); return {prefix}{n.toLocaleString('en-US')}{suffix}; } /* Reveal wrapper */ function Reveal({ children, delay = 0, as: Tag = 'div', className = '' }) { const [ref, inView] = useInView(0.15); return ( {children} ); } /* ------------ NAV ------------ */ function TopNav() { const { locale, setLocale, t } = useT(); return ( ); } /* ------------ HERO ------------ */ function Hero() { const { t } = useT(); const videoRef = useRef(null); const [muted, setMuted] = useState(true); const [chromeVisible, setChromeVisible] = useState(false); useEffect(() => { // Reveal overlay text after 4s OR on first scroll — whichever first. const tRef = setTimeout(() => setChromeVisible(true), 4000); const onScroll = () => { if (window.scrollY > 30) setChromeVisible(true); }; window.addEventListener('scroll', onScroll, { passive: true }); return () => { clearTimeout(tRef); window.removeEventListener('scroll', onScroll); }; }, []); const toggleMute = () => { if (!videoRef.current) return; videoRef.current.muted = !videoRef.current.muted; setMuted(videoRef.current.muted); }; return (
{/* Protection gradient bottom-up */}
{/* Top micro-caption */}
{t('hero.caption')}
{/* Wordmark bottom-left */}
HLiD.
{t('hero.tagline')}
{/* CTA bottom-right */}
{t('hero.stamps')}
{t('hero.cta')}
{/* Mute toggle — top right, always visible */} {/* Scroll cue */}
{t('hero.scroll')}
); } /* ------------ THREE PILLARS BAR ------------ */ function Pillars() { const { t } = useT(); const items = [ ['01', t('pillars.01.title'), t('pillars.01.body')], ['02', t('pillars.02.title'), t('pillars.02.body')], ['03', t('pillars.03.title'), t('pillars.03.body')], ]; return (
{items.map(([n, t, d], i) => (
{n}
{t}

{d}

))}
); } Object.assign(window, { Hero, TopNav, Pillars, Counter, Reveal, useInView });