/* helpers.jsx — shared icon set (inline Lucide paths) + scroll reveal */ const { useEffect, useRef, useState } = React; /* Lucide-style outline icons, 2px stroke, currentColor */ const ICON_PATHS = { search: '', code: '', bot: '', arrowUpRight: '', arrowRight: '', check: '', play: '', star: '', trendingUp: '', target: '', link: '', gauge: '', mail: '', phone: '', mapPin: '', clock: '', zap: '', shield: '', fileSearch: '', layers: '', workflow: '', penTool: '', menu: '', x: '', linkedin: '', twitter: '', github: '', crown: '', award: '', building: '', }; function Icon({ name, size = 20, stroke = 1.75, fill, style, ...rest }) { return ( ); } /* Scroll-reveal: opt into the hidden start-state (html.reveal-ready), then add .is-in to elements as they enter the viewport. Uses setTimeout throttling (rAF can be frozen in background/throttled iframes). */ function useReveal() { const ref = useRef(null); useEffect(() => { const motionOk = !window.matchMedia('(prefers-reduced-motion: reduce)').matches; if (!motionOk) return; const root = document.documentElement; let pending = false, settle = []; const mark = () => { pending = false; const vh = window.innerHeight || document.documentElement.clientHeight; const els = ref.current ? ref.current.querySelectorAll('.reveal:not(.is-in)') : []; let stagger = 0; els.forEach((el) => { const r = el.getBoundingClientRect(); if (r.top < vh * 0.92 && r.bottom > -40) { el.style.transitionDelay = (Math.min(stagger++, 5) * 70) + 'ms'; el.classList.add('is-in'); } }); }; const onScroll = () => { if (!pending) { pending = true; setTimeout(mark, 60); } }; // enable hidden start-state, then reveal what's already on-screen root.classList.add('reveal-ready'); requestAnimationFrame(() => requestAnimationFrame(mark)); [80, 300, 700].forEach((t) => settle.push(setTimeout(mark, t))); window.addEventListener('scroll', onScroll, { passive: true }); window.addEventListener('resize', onScroll, { passive: true }); return () => { settle.forEach(clearTimeout); window.removeEventListener('scroll', onScroll); window.removeEventListener('resize', onScroll); }; }, []); return ref; } Object.assign(window, { Icon, useReveal });