// BEAKEN — primitivos compartidos const { useState, useEffect, useRef, useMemo } = React; // ---- Router (hash-based) ---- const useRoute = () => { const [route, setRoute] = useState(() => (window.location.hash || '#/').replace('#', '') || '/'); useEffect(() => { const onHash = () => { setRoute((window.location.hash || '#/').replace('#', '') || '/'); window.scrollTo({ top: 0, behavior: 'instant' }); }; window.addEventListener('hashchange', onHash); return () => window.removeEventListener('hashchange', onHash); }, []); return route; }; const navigate = (path) => { window.location.hash = path; }; // ---- Reveal on scroll ---- const Reveal = ({ children, delay = 0, as: Tag = 'div', className = '', ...rest }) => { const ref = useRef(null); const [vis, setVis] = useState(false); useEffect(() => { const el = ref.current; if (!el) return; const io = new IntersectionObserver(([e]) => { if (e.isIntersecting) { setVis(true); io.unobserve(el); } }, { threshold: 0.12, rootMargin: '-40px 0px' }); io.observe(el); return () => io.disconnect(); }, []); const delayClass = delay ? ` reveal-delay-${delay}` : ''; return ( {children} ); }; // ---- SVG icons ---- const Arr = ({ className = '' }) => ( ); const ArrRight = ({ size = 14 }) => ( ); const Plus = ({ size = 12 }) => ( ); const Check = ({ size = 18 }) => ( ); const Cross = ({ size = 14 }) => ( ); // ---- Nav ---- const Nav = ({ route }) => { const primary = [ { to: '/', label: 'Agency' }, { to: '/lab', label: 'Lab' }, { to: '/academy', label: 'Academy' }, ]; const secondary = [ { to: '/origo', label: 'Origo Beaken', desc: 'Joint Venture · Estrategia + IA' }, { to: '/aliados', label: 'Aliados', desc: 'Instituciones y Empresas Impulsoras' }, { to: '/mentores', label: 'Mentores', desc: 'Comunidad de especialistas' }, ]; const isActive = (to) => to === '/' ? (route === '/' || route === '' || route === '/agency') : route === to; const secondaryActive = secondary.some(s => s.to === route); const [open, setOpen] = useState(false); useEffect(() => { if (!open) return; const close = () => setOpen(false); document.addEventListener('click', close); return () => document.removeEventListener('click', close); }, [open]); return ( ); }; // ---- Mexico Central Time ---- const useClock = () => { const [now, setNow] = useState(() => new Date()); useEffect(() => { const id = setInterval(() => setNow(new Date()), 60000); return () => clearInterval(id); }, []); return now; }; const getMexicoTime = (date) => date.toLocaleString('es-MX', { timeZone: 'America/Mexico_City', hour: '2-digit', minute: '2-digit', hour12: false, }); const isOpen = (date) => { const local = new Date(date.toLocaleString('en-US', { timeZone: 'America/Mexico_City' })); const d = local.getDay(), t = local.getHours() * 60 + local.getMinutes(); return d >= 1 && d <= 5 && t >= 540 && t < 1080; }; // ---- Ticker ---- const Ticker = () => { const now = useClock(); const mxTime = getMexicoTime(now); const open = isOpen(now); const items = [ { k: 'STATUS', v: 'AGENDANDO Q2 2026', live: true }, { k: 'PROMESA', v: 'DIAGNÓSTICO EN 2 HORAS' }, { k: 'HORA CST', v: `${mxTime} · ${open ? 'ABIERTO' : 'CERRADO'}`, live: true }, { k: 'METODOLOGÍA', v: 'BLUEPRINT + SPRINT' }, { k: 'COBERTURA', v: 'MX · LATAM · REMOTO' }, { k: 'TICKET ENTRADA', v: 'DESDE $1,000 MXN' }, { k: 'INCUBADORA', v: 'COMMUNITY 2026 ABIERTO' }, { k: 'ACADEMY', v: 'TALLERES IA · PRÓXIMA FECHA' }, { k: 'BASE', v: 'LEÓN GTO · MX' }, ]; const loop = [...items, ...items]; return (
{loop.map((it, i) => ( {it.k} // {it.v} ))}
); }; // ---- Section header ---- const SecHead = ({ num, title, sub, right }) => (
{num}

{sub &&

{sub}

} {right}
); // ---- Image block with HUD ---- const ImgBlock = ({ src, caption, code = "BK-001", label = "HERO" }) => (
{caption}
LIVE · {code} {label}
{caption}
); // ---- Big CTA ---- const BigCTA = ({ title, sub, cta, eyebrow }) => (
{eyebrow || 'LLAMADA DE 15 MIN · GRATIS'}

{title}

{sub}

{e.preventDefault();navigate('/contacto');}} className="btn btn-primary"> {cta || 'Agenda tu llamada'}
); // ---- Section anchor (numbered subsection heading) ---- const SectionAnchor = ({ num, label, title }) => (
{num}
{label}

{title}

); // ---- Footer ---- const Footer = () => ( ); // Export Object.assign(window, { useRoute, navigate, Reveal, Arr, ArrRight, Plus, Check, Cross, Nav, Ticker, SecHead, ImgBlock, BigCTA, SectionAnchor, Footer, useClock, getMexicoTime, isOpen, });