// 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" }) => (
LIVE · {code}
{label}
{caption}
);
// ---- Big CTA ----
const BigCTA = ({ title, sub, cta, eyebrow }) => (
);
// ---- Section anchor (numbered subsection heading) ----
const SectionAnchor = ({ num, label, title }) => (
{num}
);
// ---- 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,
});