/* 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 ( HLiD {t('nav.product')} {t('nav.workflow')} {t('nav.observability')} {t('nav.integrations')} {t('nav.customers')} {t('nav.live')} {['EN','DE'].map(l => ( setLocale(l)} className={`px-2 py-1.5 transition-colors focus-ring ${locale === l ? 'text-fg bg-bg-elevated' : 'text-fg-subtle hover:text-fg'}`}> {l} ))} {t('nav.cta')} ); } /* ------------ 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 ( aria-label="HLiD brand film" > {/* 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 */} {muted ? ( ) : ( )} {muted ? t('hero.soundOff') : t('hero.soundOn')} {/* 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 });
{d}