// Hero — variations: Conservador (tree 1), Conservador 2 (tree 2), Editorial, Techy const Hero = ({ variant = 'conservador' }) => { if (variant === 'conservador2') return ; if (variant === 'editorial') return ; if (variant === 'techy') return ; return ; }; // ——— VARIATION 1 — CONSERVADOR (matches mockup: full-bleed tree image, stats bar overlay) ——— const HeroConservador = ({ image = 'assets/hero-tree.png', thumbPos = '70% 50%', video = null }) => { const videoRef = React.useRef(null); const sectionRef = React.useRef(null); const [videoReady, setVideoReady] = React.useState(false); // Auto-snap: wheel/touch down inside zone → animate scroll to problema bottom // and play the video forward. Wheel/touch up → animate scroll to hero top and // simulate reverse playback by decrementing currentTime in rAF. React.useEffect(() => { if (!video) return; const v = videoRef.current; const hero = sectionRef.current; if (!v || !hero) return; window.__verosHeroVideo = v; let scrollRaf = null; let reverseRaf = null; let animating = false; let direction = 0; let animStartTime = 0; let animStartScroll = 0; let animEndScroll = 0; let reverseStartTs = 0; let reverseStartVt = 0; const DURATION_MS = 1800; const onMeta = () => setVideoReady(true); v.addEventListener('loadedmetadata', onMeta); if (v.readyState >= 1) onMeta(); const getZone = () => { const problema = document.getElementById('problema'); const heroRect = hero.getBoundingClientRect(); const startY = heroRect.top + window.scrollY; let endY = startY + hero.offsetHeight; if (problema) { const pRect = problema.getBoundingClientRect(); endY = pRect.top + window.scrollY; } return { startY, endY }; }; const easeInOut = (t) => t < 0.5 ? 2*t*t : 1 - Math.pow(-2*t + 2, 2) / 2; const stopReverse = () => { if (reverseRaf) { cancelAnimationFrame(reverseRaf); reverseRaf = null; } }; const reverseTick = (ts) => { const elapsed = (ts - reverseStartTs) / 1000; const t = Math.max(0, reverseStartVt - elapsed); v.currentTime = t; if (t <= 0.01) { reverseRaf = null; return; } reverseRaf = requestAnimationFrame(reverseTick); }; const animateScroll = (ts) => { if (!animating) { scrollRaf = null; return; } const elapsed = ts - animStartTime; const t = Math.max(0, Math.min(1, elapsed / DURATION_MS)); const e = easeInOut(t); const y = animStartScroll + (animEndScroll - animStartScroll) * e; window.scrollTo(0, y); updateOverlay(); if (t >= 1) { animating = false; scrollRaf = null; return; } scrollRaf = requestAnimationFrame(animateScroll); }; let overlayFading = false; const updateOverlay = () => { if (overlayFading) return; const problema = document.getElementById('problema'); if (!problema) return; const { startY, endY } = getZone(); const span = endY - startY; if (span <= 0) return; const y = window.scrollY; // Overlay only appears AFTER the section is fully on stage (scroll zone done). // Stays at 0 during the entire video play, then fades in once the user // is fully inside the problema section. const fullyIn = y >= endY - 2; problema.style.setProperty('--problema-overlay-opacity', fullyIn ? '1' : '0'); }; // Continuous rAF loop — more reliable than scroll events alone let overlayRafRunning = true; const overlayLoop = () => { if (!overlayRafRunning) return; updateOverlay(); requestAnimationFrame(overlayLoop); }; requestAnimationFrame(overlayLoop); const startAnimation = (dir) => { const { startY, endY } = getZone(); const cur = window.scrollY; if (cur < startY - 2 || cur > endY + 2) return; if (animating && direction === dir) return; animating = true; direction = dir; animStartScroll = cur; animEndScroll = dir > 0 ? endY : startY; animStartTime = performance.now(); if (dir > 0) { // forward play at 2x stopReverse(); v.playbackRate = 2; const p = v.play(); if (p && typeof p.catch === 'function') p.catch(()=>{}); } else { // reverse: crossfade to first frame try { v.pause(); } catch(e) {} stopReverse(); // fade out, jump to 0, fade in v.style.transition = 'opacity 0.35s ease'; v.style.opacity = '0'; setTimeout(() => { v.currentTime = 0; // force paint of first frame before fading back in requestAnimationFrame(() => { v.style.opacity = '1'; setTimeout(() => { v.style.transition = ''; }, 450); }); }, 370); // Fade out the dark overlay quickly const problema = document.getElementById('problema'); if (problema) { overlayFading = true; problema.classList.add('is-fading-out'); problema.style.setProperty('--problema-overlay-opacity', '0'); // Keep the fade lock until the scroll animation finishes // (so updateOverlay doesn't recompute mid-scroll) setTimeout(() => { problema.classList.remove('is-fading-out'); overlayFading = false; }, DURATION_MS + 50); } } if (scrollRaf) cancelAnimationFrame(scrollRaf); scrollRaf = requestAnimationFrame(animateScroll); }; const onWheel = (ev) => { const { startY, endY } = getZone(); const y = window.scrollY; const inZone = y >= startY - 2 && y <= endY + 2; if (!inZone) return; const dir = ev.deltaY > 0 ? 1 : -1; if (dir > 0 && y >= endY - 2) return; if (dir < 0 && y <= startY + 2) return; ev.preventDefault(); startAnimation(dir); }; let touchStartY = null; const onTouchStart = (ev) => { touchStartY = ev.touches[0].clientY; }; const onTouchMove = (ev) => { if (touchStartY == null) return; const { startY, endY } = getZone(); const y = window.scrollY; const inZone = y >= startY - 2 && y <= endY + 2; if (!inZone) return; const dy = touchStartY - ev.touches[0].clientY; if (Math.abs(dy) < 8) return; const dir = dy > 0 ? 1 : -1; if (dir > 0 && y >= endY - 2) return; if (dir < 0 && y <= startY + 2) return; ev.preventDefault(); touchStartY = ev.touches[0].clientY; startAnimation(dir); }; const onTouchEnd = () => { touchStartY = null; }; const onKey = (ev) => { const { startY, endY } = getZone(); const y = window.scrollY; const inZone = y >= startY - 2 && y <= endY + 2; if (!inZone) return; if (ev.key === 'PageDown' || ev.key === 'ArrowDown' || ev.key === ' ') { if (y < endY - 2) { ev.preventDefault(); startAnimation(1); } } else if (ev.key === 'PageUp' || ev.key === 'ArrowUp') { if (y > startY + 2) { ev.preventDefault(); startAnimation(-1); } } }; // Reset video when user returns to hero region (safety net) // Only fires when scroll lands at the very top, not during scrolling. let resetGuard = false; const checkResetVideo = () => { const { startY } = getZone(); const atTop = window.scrollY <= startY + 2; if (atTop && !resetGuard && !animating) { try { v.pause(); v.currentTime = 0; } catch(e) {} resetGuard = true; } else if (!atTop) { resetGuard = false; } }; window.addEventListener('wheel', onWheel, { passive: false }); window.addEventListener('touchstart', onTouchStart, { passive: true }); window.addEventListener('touchmove', onTouchMove, { passive: false }); window.addEventListener('touchend', onTouchEnd); window.addEventListener('keydown', onKey); window.addEventListener('scroll', updateOverlay, { passive: true }); window.addEventListener('scroll', checkResetVideo, { passive: true }); // initial updateOverlay(); checkResetVideo(); return () => { window.removeEventListener('wheel', onWheel); window.removeEventListener('touchstart', onTouchStart); window.removeEventListener('touchmove', onTouchMove); window.removeEventListener('touchend', onTouchEnd); window.removeEventListener('keydown', onKey); window.removeEventListener('scroll', updateOverlay); window.removeEventListener('scroll', checkResetVideo); v.removeEventListener('loadedmetadata', onMeta); overlayRafRunning = false; if (scrollRaf) cancelAnimationFrame(scrollRaf); stopReverse(); }; }, [video]); return (
{video ? (
) : (
)}
INFRAESTRUTURA DE CONFIANÇA GLOBAL

Tecnologia
para um futuro
sustentável.

Soluções inteligentes para validar, monitorar e automatizar sua jornada regulatória de ponta a ponta.

); }; // ——— VARIATION 2 — EDITORIAL (Oversized type, asymmetric, magazine) ——— const HeroEditorial = () => { return (
N.º 001 Infraestrutura de confiança global

De cadeias
fragmentadas
a sistemas
confiáveis
globais.

01

A Veros conecta empresas, dados e processos para construir cadeias auditáveis, transparentes e alinhadas às exigências regulatórias globais.

Brasil América Latina Europa Ásia-Pacífico América do Norte
); }; // ——— VARIATION 3 — TECHY (Terminal-ish, coordinates, data overlay, dark) ——— const HeroTechy = () => { const [tick, setTick] = React.useState(0); React.useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 1200); return () => clearInterval(id); }, []); const coords = [ 'LAT -23.5505 LNG -46.6333', 'LAT 40.7128 LNG -74.0060', 'LAT 51.5074 LNG -0.1278', 'LAT 35.6762 LNG 139.6503', 'LAT 1.3521 LNG 103.8198', ]; return (
SISTEMA OPERACIONAL · v4.2 · LIVE

A camada de confiança
das cadeias produtivas.

Rastreabilidade, conformidade e transparência em tempo real, operando como infraestrutura — não como projeto.

veros · chain-monitor
scan --global --compliance
{coords.slice(0, Math.min(coords.length, 1 + (tick % coords.length))).map((c, i) => (
node.{String(i+1).padStart(2,'0')} {c} COMPLIANT
))}
_
STATUS
ONLINE
NODES
1,284
LAT
24ms
UPTIME
99.99%
); }; window.Hero = Hero;