/* global React */ function Icon({ name, size = 20, stroke = 1.75, style }) { const paths = { 'arrow-right': <>, 'arrow-up-right': <>, 'arrow-down-right': <>, 'check': <>, 'target': <>, 'chart': <>, 'zap': <>, 'users': <>, 'mail': <>, 'calendar': <>, 'play': <>, 'menu': <>, 'sparkles': <>, 'brain': <>, 'megaphone': <>, 'search': <>, 'graduation': <>, 'film': <>, 'home': <>, 'shopping': <>, 'credit-card': <>, 'heart': <>, 'scale': <>, 'server': <>, 'rocket': <>, 'globe': <>, 'briefcase': <>, 'compass': <>, 'message': <>, 'clipboard': <>, 'quote': <>, }; return ( {paths[name]} ); } function Button({ variant = 'primary', size = 'md', children, icon, iconLeft, ...p }) { const base = { fontFamily: 'var(--font-body)', fontWeight: 600, border: 0, cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 8, lineHeight: 1, borderRadius: 999, letterSpacing: '-0.005em', transition: 'transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out)', whiteSpace: 'nowrap', }; const sizes = { sm: { padding: '9px 16px', fontSize: 13 }, md: { padding: '13px 22px', fontSize: 15 }, lg: { padding: '16px 28px', fontSize: 16 }, }; const variants = { cta: { background: 'var(--cta)', color: 'var(--teal-900)', boxShadow: 'var(--shadow-cta)' }, primary: { background: 'var(--brand)', color: '#fff', boxShadow: 'var(--shadow-brand)' }, ghost: { background: 'transparent', color: 'var(--brand)', border: '1px solid var(--teal-200)' }, text: { background: 'transparent', color: 'var(--brand)', padding: '8px 4px' }, inverse: { background: '#fff', color: 'var(--teal-800)' }, dark: { background: 'var(--teal-900)', color: '#fff' }, }; return ( ); } function Eyebrow({ children, dark, color }) { return ( {children} ); } function Badge({ children, tone = 'brand' }) { const tones = { brand: { bg: 'var(--teal-50)', fg: 'var(--teal-700)' }, accent: { bg: 'var(--cyan-50)', fg: 'var(--cyan-800)' }, cta: { bg: 'var(--yellow-50)', fg: 'var(--yellow-800)' }, neutral: { bg: 'var(--ink-100)', fg: 'var(--ink-700)' }, dark: { bg: 'rgba(255,255,255,0.1)', fg: 'rgba(255,255,255,0.92)' }, }; const t = tones[tone]; return {children}; } function Droplets({ color = 'var(--teal-100)', opacity = 0.55, style, size = 180 }) { return (
); } // Container shorthand function Container({ children, style = {}, className, maxW = 1200, ...p }) { const defaultPadding = className ? {} : { padding: '0 32px' }; return (
{children}
); } function useWindowWidth() { const [width, setWidth] = React.useState( typeof window !== 'undefined' ? window.innerWidth : 1200 ); React.useEffect(() => { const handler = () => setWidth(window.innerWidth); window.addEventListener('resize', handler, { passive: true }); return () => window.removeEventListener('resize', handler); }, []); return width; } /* ------------------------------------------------------------------ * * useInView — fires callback once when element crosses viewport edge * * ------------------------------------------------------------------ */ function useInView(ref, { threshold = 0.12, once = true } = {}) { const [visible, setVisible] = React.useState(false); React.useEffect(() => { if (!ref.current) return; if (typeof IntersectionObserver === 'undefined') { setVisible(true); return; } const obs = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) { setVisible(true); if (once) obs.disconnect(); } }, { threshold } ); obs.observe(ref.current); return () => obs.disconnect(); }, []); return visible; } /* ------------------------------------------------------------------ * * Reveal — scroll-triggered entrance wrapper * * * * Props: * * dir 'up' | 'left' | 'right' default 'up' * * delay 0-6 (maps to rv-d1…rv-d6 CSS classes) * * scale bool use rv-scale variant instead of translate * * fast bool shorter 360ms transition * * tag string wrapper element type, default 'div' * * className / style forwarded to wrapper * * ------------------------------------------------------------------ */ function Reveal({ children, dir = 'up', delay = 0, scale = false, fast = false, tag = 'div', className = '', style = {} }) { const ref = React.useRef(null); const visible = useInView(ref); const dirClass = dir === 'left' ? 'rv-left' : dir === 'right' ? 'rv-right' : ''; const delayClass = delay > 0 ? `rv-d${delay}` : ''; const scaleClass = scale ? 'rv-scale' : ''; const fastClass = fast ? 'rv-fast' : ''; const cls = ['rv', dirClass, scaleClass, fastClass, delayClass, visible ? 'is-visible' : '', className] .filter(Boolean).join(' '); return React.createElement(tag, { ref, className: cls, style }, children); } Object.assign(window, { Icon, Button, Eyebrow, Badge, Droplets, Container, useWindowWidth, useInView, Reveal });