// Shared design tokens + shell components for Konecta v2
// Brutalist / y2k · Archivo Black + JetBrains Mono

const K = {
  ink: '#0a0a0a',
  paper: '#f4f1ea',
  paperAlt: '#ece8de',
  dim: '#8a8680',
  accent: '#ff2d6f',   // publicidad / primary hot pink
  cyan:   '#00d4ff',
  lime:   '#c8ff2e',
  yellow: '#ffd400',
  pink:   '#ff9ed8',
  violet: '#a78bff',
  electric: '#0066ff', // sitios web
  amber:    '#ff9500', // identidad visual
  mono:    '"JetBrains Mono", "IBM Plex Mono", "Courier New", monospace',
  display: '"Archivo Black", "Anton", Impact, sans-serif',
  sans:    '"Inter", system-ui, sans-serif',
};

// ── WhatsApp — número + helper para generar links con mensajes personalizados.
// CAMBIAR NÚMERO AQUÍ si rota; todos los links lo usan vía waLink().
const WA_NUMBER = '5667727583'; // 56 6772 7583
function waLink(msg = 'Hola Konecta, vi su página. Me late lo que hacen, ¿cómo arrancamos?') {
  return `https://wa.me/${WA_NUMBER}?text=${encodeURIComponent(msg)}`;
}
window.WA_NUMBER = WA_NUMBER;
window.waLink = waLink;

// ─── Cross-page section routing ────────────────────────
// Map every section id to the page it lives on. If a link points to a section
// not on the current page, we prefix it with the right page URL.
const SECTION_PAGE = {
  // Home (/)
  hub:         '/',
  services:    '/',
  nosotros:    '/',
  resultados:  '/',
  contacto:    '/',
  // Publicidad (/publicidad)
  paquetes:      '/publicidad',
  casos:         '/publicidad',
  enterprise:    '/enterprise',
  reels:         '/publicidad',
  'faq-pub':     '/publicidad',
  'contacto-b2b':'/publicidad',
  // 'proceso' exists on both — leave as local anchor on whichever page we're on
};

function kLink(id) {
  // Si el id empieza con '/', es una ruta absoluta directa (ej: '/casos.html')
  if (id && id.charAt(0) === '/') return id;
  if (typeof window === 'undefined') return '#' + id;
  const here = decodeURIComponent(window.location.pathname.split('/').pop() || '').toLowerCase();
  const target = SECTION_PAGE[id];
  if (!target) return '#' + id; // ambiguous (e.g. 'proceso') — same-page anchor
  if (here === target.toLowerCase()) return '#' + id;
  return target + '#' + id;
}
window.kLink = kLink;

const SERVICES = [
  { id: 'pub',  num: '01', name: 'Publicidad',   tag: 'ACTIVO',   status: 'active',  hue: K.accent, fg: '#fff',
    kicker: 'Alcance 100% orgánico',
    teaser: '3 paquetes · desde $7,500',
    desc:   'Videos + stories distribuidos en nuestra red de 695K+ seguidores reales.' },
  { id: 'ases', num: '02', name: 'Asesorías',    tag: 'PRONTO',   status: 'soon',    hue: K.cyan,   fg: K.ink,
    kicker: 'Te leemos las redes en 90 minutos',
    teaser: 'diagnóstico brutal · pronto',
    desc:   'Una sesión puntual: auditamos tus redes y te llevas un plan claro para aplicar tú mismo.' },
  { id: 'cur',  num: '03', name: 'Cursos',       tag: 'PRONTO',   status: 'soon',    hue: K.yellow, fg: K.ink,
    kicker: 'Aprende lo que cobramos',
    teaser: 'sin teoría inflada · pronto',
    desc:   'Aprende a crear, editar y vender con contenido a tu tiempo, desde donde estés.' },
  { id: 'acel', num: '04', name: 'Aceleradora',  tag: 'PRONTO',   status: 'soon',    hue: K.lime,   fg: K.ink,
    kicker: 'Tu marca · nosotros todo',
    teaser: '3–6 meses · pronto',
    desc:   'Programa integral de 3 a 6 meses: estrategia, producción, edición, manejo de redes y medición. Nosotros operamos, tú ves cómo crece tu marca.' },
  { id: 'prod', num: '05', name: 'Producción',   tag: 'PRONTO',   status: 'soon',    hue: K.pink,   fg: K.ink,
    kicker: 'Grabamos y editamos · tú diriges',
    teaser: 'equipo a tu medida · pronto',
    desc:   'Servicio de producción audiovisual a demanda: tú llegas con la idea, nosotros llegamos con el equipo. Grabación y edición profesional. La estrategia la pones tú.' },
  { id: 'inf',  num: '06', name: 'Influencers',  tag: 'PRONTO',   status: 'soon',    hue: K.violet, fg: '#fff',
    kicker: 'Match real, no base de datos',
    teaser: 'talento curado · pronto',
    desc:   'Conectamos creadores con las marcas indicadas. Una plataforma para que ambos lados encajen de verdad.' },
  { id: 'ent',  num: '07', name: 'Enterprise',   tag: 'ACTIVO B2B', status: 'active', hue: K.ink,    fg: K.lime,
    kicker: 'Marcas grandes en la conversación cultural',
    teaser: 'cotización a la medida · 48h',
    desc:   'Para CMOs y Brand Managers de marcas grandes. Tu marca aparece en la conversación cultural sin parecer anuncio. Garantía de impacto cualitativo, no vistas crudas.' },
  { id: 'web',  num: '08', name: 'Sitios web',   tag: 'PRONTO',   status: 'soon',    hue: K.electric, fg: '#fff',
    kicker: 'Sitios para lugares con identidad propia',
    teaser: 'restaurantes, hoteles, experiencias · pronto',
    desc:   'Sitios para restaurantes, hoteles y experiencias que no quieren plantilla genérica. Construidos con insight de cómo se comporta tu audiencia real.' },
  { id: 'iden', num: '09', name: 'Identidad visual', tag: 'PRONTO', status: 'soon',  hue: K.amber, fg: K.ink,
    kicker: 'Marcas que se ven propias, no genéricas',
    teaser: 'antes del sitio, antes del feed · pronto',
    desc:   'Identidad visual para marcas en CDMX que quieren verse propias. Construida conociendo el feed donde la marca tiene que vivir.' },
];

// ─── Sticky WhatsApp (global floating CTA) ──────────────
function StickyWA({ href = waLink('Hola Konecta, me interesa publicidad para mi lugar. ¿Cómo arrancamos?'), dataCta = 'sticky-default' }) {
  const [open, setOpen] = React.useState(false);
  const [visible, setVisible] = React.useState(false);
  const isMobile = useIsMobile(720);
  React.useEffect(() => {
    const on = () => {
      const y = window.scrollY;
      const docH = document.documentElement.scrollHeight;
      const viewH = window.innerHeight;
      const distFromBottom = docH - (y + viewH);
      // show after 320px, but hide in last 600px so it doesn't compete with the final CTA
      setVisible(y > 320 && distFromBottom > 600);
    };
    on(); window.addEventListener('scroll', on, { passive: true });
    window.addEventListener('resize', on);
    const pop = setTimeout(() => setOpen(!isMobile), 2600);
    const hide = setTimeout(() => setOpen(false), 8200);
    return () => { window.removeEventListener('scroll', on); window.removeEventListener('resize', on); clearTimeout(pop); clearTimeout(hide); };
  }, [isMobile]);
  if (!visible) return null;
  return (
    <div style={{
      position: 'fixed',
      right: isMobile ? 14 : 22,
      bottom: isMobile ? 14 : 22,
      zIndex: 180, display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 10, fontFamily: K.mono,
      maxWidth: isMobile ? 'calc(100vw - 28px)' : 'auto',
    }}>
      {open && !isMobile && (
        <div style={{ maxWidth: 260, background: K.paper, border: `3px solid ${K.ink}`, boxShadow: `5px 5px 0 ${K.ink}`, padding: '12px 14px', fontSize: 12, lineHeight: 1.5, position: 'relative', transform: 'rotate(-1deg)' }}>
          <button onClick={() => setOpen(false)} aria-label="cerrar" style={{ position: 'absolute', top: 4, right: 6, background: 'transparent', border: 'none', fontFamily: K.mono, fontSize: 14, cursor: 'pointer', color: K.ink }}>×</button>
          <div style={{ fontSize: 10, textTransform: 'uppercase', letterSpacing: 1.5, color: K.dim, marginBottom: 4 }}>/ respondemos en &lt; 2h</div>
          <div>¿Tienes un lugar que vale la pena contar? <b>Escríbenos.</b></div>
        </div>
      )}
      <a href={href} target="_blank" rel="noreferrer" data-k-cursor="whatsapp" data-cta={dataCta} onClick={() => setOpen(false)} onMouseEnter={() => !isMobile && setOpen(true)} style={{
        display: 'flex', alignItems: 'center', gap: isMobile ? 8 : 10,
        padding: isMobile ? '11px 14px' : '14px 18px',
        background: '#22c55e', color: '#fff', border: `3px solid ${K.ink}`,
        boxShadow: `${isMobile ? 4 : 5}px ${isMobile ? 4 : 5}px 0 ${K.ink}`, textDecoration: 'none',
        fontSize: isMobile ? 11 : 12, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 1.5,
      }}>
        <span style={{ width: isMobile ? 20 : 24, height: isMobile ? 20 : 24, borderRadius: '50%', background: '#fff', color: '#22c55e', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', fontFamily: K.display, fontSize: isMobile ? 12 : 14 }}>W</span>
        whatsapp ↗
      </a>
    </div>
  );
}

// ─── Mobile detection ─────────────────────────────────────
function useIsMobile(bp = 720) {
  const [m, setM] = React.useState(() => typeof window !== 'undefined' && window.innerWidth <= bp);
  React.useEffect(() => {
    const mq = window.matchMedia(`(max-width: ${bp}px)`);
    const on = () => setM(mq.matches);
    on();
    if (mq.addEventListener) mq.addEventListener('change', on);
    else mq.addListener(on);
    return () => {
      if (mq.removeEventListener) mq.removeEventListener('change', on);
      else mq.removeListener(on);
    };
  }, [bp]);
  return m;
}
window.useIsMobile = useIsMobile;

// ─── Live counter hook ────────────────────────────────────
// Returns [formattedCount, ref, meta]. Attach `ref` to the visible counter element
// so el setInterval solo tickea cuando el counter está en viewport (CPU-friendly).
// El base AHORA viene del JSON `konecta/follower-counts.json` (auto-generado por
// Apify cron 1x/día). Si fetch falla, usa el `fallbackBase` del callsite.
// `meta` devuelve { ig: total, tt: total, accounts: {...}, updated_at } para
// que el callsite muestre los splits IG/TT desde la misma fuente.
function useLiveCounter(fallbackBase = 692400, perMin = 18) {
  const [base, setBase] = React.useState(fallbackBase);
  const [meta, setMeta] = React.useState(null);
  const [n, setN] = React.useState(fallbackBase);
  const ref = React.useRef(null);

  // Fetch JSON al cargar
  React.useEffect(() => {
    fetch('/konecta/follower-counts.json', { cache: 'no-store' })
      .then(r => r.ok ? r.json() : null)
      .then(data => {
        if (!data) return;
        if (data.combined && typeof data.combined === 'number') {
          setBase(data.combined);
          setN(data.combined);
        }
        setMeta({
          ig_total: data.ig?.total ?? null,
          tt_total: data.tt?.total ?? null,
          ig_accounts: data.ig?.accounts ?? {},
          tt_accounts: data.tt?.accounts ?? {},
          updated_at: data.updated_at ?? null,
        });
      })
      .catch(() => {/* silent — fallbackBase ya está */});
  }, []);

  // Drift simulado (efecto visual)
  React.useEffect(() => {
    const start = Date.now();
    let id = null;
    const tick = () => {
      const elapsedMin = (Date.now() - start) / 60000;
      setN(Math.floor(base + elapsedMin * perMin + Math.random() * 3));
    };
    const startTicking = () => { if (id == null) id = setInterval(tick, 1800); };
    const stopTicking  = () => { if (id != null) { clearInterval(id); id = null; } };

    const supportsIO = typeof IntersectionObserver !== 'undefined';
    if (!supportsIO || !ref.current) {
      startTicking();
      return stopTicking;
    }
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) startTicking(); else stopTicking(); });
    }, { threshold: 0 });
    io.observe(ref.current);
    return () => { io.disconnect(); stopTicking(); };
  }, [base, perMin]);

  return [n.toLocaleString('en-US'), ref, meta];
}

// ─── Top nav (OS-style) ───────────────────────────────────
const NAV_ITEMS = [
  ['inicio', 'hub'],
  ['servicios', 'services'],
  ['casos', '/casos.html'],   // página separada (no anchor)
  ['proceso', 'proceso'],
  ['resultados', 'resultados'],
  ['paquetes', 'paquetes'],
  ['contacto', 'contacto'],
];

function TopBar({ onCmdK }) {
  const [t, setT] = React.useState('');
  const [open, setOpen] = React.useState(false);
  const isMobile = useIsMobile(820);
  React.useEffect(() => {
    const id = setInterval(() => setT(new Date().toLocaleTimeString('es-MX', { hour12: false })), 1000);
    setT(new Date().toLocaleTimeString('es-MX', { hour12: false }));
    return () => clearInterval(id);
  }, []);
  // close drawer on resize-up
  React.useEffect(() => { if (!isMobile) setOpen(false); }, [isMobile]);
  // lock body scroll while drawer is open
  React.useEffect(() => {
    if (open) {
      const prev = document.body.style.overflow;
      document.body.style.overflow = 'hidden';
      return () => { document.body.style.overflow = prev; };
    }
  }, [open]);

  return (
    <div style={{
      height: 44, background: K.ink, color: K.paper,
      borderBottom: `3px solid ${K.ink}`,
      display: 'flex', alignItems: 'center', padding: isMobile ? '0 14px' : '0 20px', gap: isMobile ? 10 : 18,
      position: 'sticky', top: 0, zIndex: 50,
    }}>
      <div style={{ fontFamily: K.display, fontSize: isMobile ? 18 : 22, letterSpacing: -0.4, display: 'inline-flex', alignItems: 'center', gap: 6 }}>
        KONECTA
        <span style={{
          display: 'inline-block', width: isMobile ? 8 : 10, height: isMobile ? 8 : 10, borderRadius: '50%',
          background: K.accent, border: `2px solid ${K.paper}`,
          boxShadow: `0 0 0 2px ${K.accent}`,
        }} />
      </div>
      <div style={{ flex: 1 }} />

      {!isMobile && NAV_ITEMS.map(([l, id]) => (
        <a key={l} href={kLink(id)} data-k-cursor={l} style={{ fontFamily: K.mono, fontSize: 11, textTransform: 'uppercase', letterSpacing: 1.5, color: K.paper, textDecoration: 'none' }}>[{l}]</a>
      ))}

      {!isMobile && (
        <button onClick={onCmdK} style={{
          fontFamily: K.mono, fontSize: 11, padding: '5px 10px',
          background: 'transparent', color: K.paper, border: `1.5px solid ${K.paper}`,
          cursor: 'pointer', letterSpacing: 1,
        }}>⌘ K</button>
      )}

      {!isMobile && <div style={{ fontFamily: K.mono, fontSize: 11, opacity: 0.7 }}>{t}</div>}
      <div style={{ fontFamily: K.mono, fontSize: 11, padding: '4px 10px', background: K.accent, border: `2px solid ${K.paper}` }}>● LIVE</div>

      {isMobile && (
        <button
          onClick={() => setOpen(o => !o)}
          aria-label={open ? 'cerrar menú' : 'abrir menú'}
          style={{
            width: 36, height: 30, marginLeft: 4,
            background: K.paper, color: K.ink, border: `2px solid ${K.paper}`,
            display: 'inline-flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
            gap: 4, cursor: 'pointer', padding: 0,
          }}
        >
          {open ? (
            <span style={{ fontFamily: K.display, fontSize: 18, lineHeight: 1 }}>×</span>
          ) : (
            <>
              <span style={{ width: 18, height: 2, background: K.ink }} />
              <span style={{ width: 18, height: 2, background: K.ink }} />
              <span style={{ width: 18, height: 2, background: K.ink }} />
            </>
          )}
        </button>
      )}

      {/* Mobile drawer */}
      {isMobile && open && (
        <div
          onClick={() => setOpen(false)}
          style={{
            position: 'fixed', top: 44, left: 0, right: 0, bottom: 0,
            background: 'rgba(10,10,10,0.55)', zIndex: 49,
          }}
        >
          <div
            className="k-drawer"
            onClick={e => e.stopPropagation()}
            style={{
              background: K.ink, color: K.paper,
              borderBottom: `3px solid ${K.accent}`,
              padding: '18px 18px 24px',
              display: 'flex', flexDirection: 'column',
              maxHeight: 'calc(100vh - 44px)', overflowY: 'auto',
            }}
          >
            <div style={{ fontFamily: K.mono, fontSize: 10, letterSpacing: 2, opacity: 0.55, marginBottom: 10 }}>
              / NAVEGACIÓN
            </div>
            {NAV_ITEMS.map(([l, id]) => (
              <a
                key={l}
                className="k-drawer-link"
                href={kLink(id)}
                onClick={() => setOpen(false)}
                style={{
                  fontFamily: K.display, fontSize: 28, color: K.paper,
                  textDecoration: 'none', textTransform: 'uppercase', letterSpacing: -0.5,
                  padding: '10px 0', borderBottom: `1px dashed rgba(244,241,234,0.18)`,
                  display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                }}
              >
                <span>{l}</span>
                <span style={{ fontFamily: K.mono, fontSize: 11, opacity: 0.4 }}>↗</span>
              </a>
            ))}
            <div style={{ display: 'flex', gap: 10, marginTop: 18, alignItems: 'center' }}>
              <button onClick={() => { setOpen(false); onCmdK && onCmdK(); }} style={{
                fontFamily: K.mono, fontSize: 11, padding: '8px 12px',
                background: 'transparent', color: K.paper, border: `1.5px solid ${K.paper}`,
                cursor: 'pointer', letterSpacing: 1,
              }}>⌘ K · buscar</button>
              <div style={{ flex: 1 }} />
              <div style={{ fontFamily: K.mono, fontSize: 11, opacity: 0.6 }}>{t}</div>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// ─── Marquee ────────────────────────────────────────────
function Marquee({ bg = K.lime, items }) {
  const content = [...items, ...items, ...items];
  return (
    <div data-k-marquee="outer" style={{ height: 38, background: bg, borderBottom: `3px solid ${K.ink}`, overflow: 'hidden', display: 'flex', alignItems: 'center', flexWrap: 'nowrap' }}>
      <div data-k-marquee="inner" style={{ display: 'flex', gap: 32, whiteSpace: 'nowrap', animation: 'kmarquee 40s linear infinite', paddingLeft: 30, flexWrap: 'nowrap' }}>
        {content.map((t, i) => (
          <span key={i} style={{ fontFamily: K.mono, fontSize: 13, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 1 }}>★ {t}</span>
        ))}
      </div>
      <style>{`@keyframes kmarquee { from { transform: translateX(0) } to { transform: translateX(-33.33%) } }`}</style>
    </div>
  );
}

// ─── Command palette (⌘K) ────────────────────────────
function Palette({ open, onClose, onNav }) {
  const [q, setQ] = React.useState('');
  const inputRef = React.useRef(null);
  React.useEffect(() => { if (open && inputRef.current) inputRef.current.focus(); }, [open]);
  React.useEffect(() => {
    const h = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', h); return () => window.removeEventListener('keydown', h);
  }, [onClose]);
  if (!open) return null;
  const filtered = SERVICES.filter(s => (s.name+s.id+s.num).toLowerCase().includes(q.toLowerCase()));
  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, background: 'rgba(10,10,10,0.5)',
      zIndex: 200, display: 'flex', alignItems: 'flex-start', justifyContent: 'center', paddingTop: 120,
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: 560, background: K.paper, border: `3px solid ${K.ink}`,
        boxShadow: `10px 10px 0 ${K.ink}`,
      }}>
        <div style={{ padding: 14, borderBottom: `2px solid ${K.ink}`, display: 'flex', gap: 10, alignItems: 'center' }}>
          <span style={{ fontFamily: K.mono, fontSize: 14 }}>&gt;</span>
          <input ref={inputRef} value={q} onChange={e=>setQ(e.target.value)} placeholder="saltar a..." style={{
            flex: 1, border: 'none', outline: 'none', background: 'transparent',
            fontFamily: K.mono, fontSize: 14, color: K.ink,
          }} />
          <kbd style={{ fontFamily: K.mono, fontSize: 10, padding: '2px 6px', border: `1.5px solid ${K.ink}` }}>ESC</kbd>
        </div>
        {filtered.map((s) => (
          <div key={s.id} onClick={() => { onNav(s.id); onClose(); }} style={{
            padding: '12px 16px', borderBottom: `1px dashed ${K.dim}`, cursor: 'pointer',
            display: 'flex', justifyContent: 'space-between', alignItems: 'center',
            fontFamily: K.mono, fontSize: 13,
          }}
          onMouseEnter={e => e.currentTarget.style.background = s.hue}
          onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
            <span><b>K/{s.num}</b> · {s.name}</span>
            <span style={{ fontSize: 10, opacity: 0.7 }}>{s.tag}</span>
          </div>
        ))}
        <div style={{ padding: 10, fontFamily: K.mono, fontSize: 10, color: K.dim, background: K.paperAlt }}>
          tip: escribe <b>"konecta"</b> en cualquier parte (o <b>↑↑↓↓←→←→BA</b>) para activar el modo fiesta
        </div>
      </div>
    </div>
  );
}

// ─── Custom cursor ───────────────────────────────────
function CustomCursor() {
  const dot = React.useRef(null);
  const ring = React.useRef(null);
  const [label, setLabel] = React.useState('');
  // Skip on touch / coarse-pointer devices entirely
  const [enabled] = React.useState(() => {
    if (typeof window === 'undefined') return false;
    return !window.matchMedia('(pointer: coarse)').matches && window.innerWidth > 820;
  });
  React.useEffect(() => {
    if (!enabled) return;
    // Marca el <html> con la clase para que el CSS pueda aplicar `cursor: none`
    // SOLO cuando el custom cursor está activo. Sin la clase, el SO cursor queda
    // visible como fallback defensivo (evita el bug de "cursor invisible" cuando
    // JS no se monta o falla por cualquier razón).
    document.documentElement.classList.add('k-custom-cursor-active');

    let x = 0, y = 0, rx = 0, ry = 0;
    const onMove = (e) => { x = e.clientX; y = e.clientY;
      if (dot.current) dot.current.style.transform = `translate(${x-5}px, ${y-5}px)`;
    };
    const raf = () => {
      rx += (x - rx) * 0.18; ry += (y - ry) * 0.18;
      if (ring.current) ring.current.style.transform = `translate(${rx-20}px, ${ry-20}px)`;
      requestAnimationFrame(raf);
    };
    window.addEventListener('mousemove', onMove);
    const id = requestAnimationFrame(raf);

    const onOver = (e) => {
      const el = e.target.closest('[data-k-cursor]');
      setLabel(el ? el.getAttribute('data-k-cursor') : '');
      if (ring.current) ring.current.style.background = el ? K.accent : 'transparent';
    };
    window.addEventListener('mouseover', onOver);
    return () => {
      document.documentElement.classList.remove('k-custom-cursor-active');
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseover', onOver);
      cancelAnimationFrame(id);
    };
  }, [enabled]);
  if (!enabled) return null;
  return (
    <>
      <div ref={ring} style={{
        position: 'fixed', top: 0, left: 0, width: 40, height: 40,
        border: `2px solid ${K.ink}`, pointerEvents: 'none', zIndex: 9999,
        mixBlendMode: 'difference', transition: 'background 0.15s, width 0.2s, height 0.2s',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        fontFamily: K.mono, fontSize: 9, textTransform: 'uppercase', letterSpacing: 1,
        color: K.paper,
      }}>{label}</div>
      <div ref={dot} style={{
        position: 'fixed', top: 0, left: 0, width: 10, height: 10, background: K.ink,
        pointerEvents: 'none', zIndex: 9999, borderRadius: '50%',
      }} />
    </>
  );
}

// ─── Easter Egg ── escribe "konecta" o usa el Konami Code para activar party mode
function EasterEgg() {
  const [active, setActive] = React.useState(false);
  const buf = React.useRef('');
  const konami = React.useRef([]);
  const KONAMI = ['ArrowUp','ArrowUp','ArrowDown','ArrowDown','ArrowLeft','ArrowRight','ArrowLeft','ArrowRight','b','a'];

  React.useEffect(() => {
    const onKey = (e) => {
      // skip if typing in an input
      const t = e.target;
      if (t && (t.tagName === 'INPUT' || t.tagName === 'TEXTAREA' || t.isContentEditable)) return;

      // word detector: "konecta"
      const ch = e.key.toLowerCase();
      if (/^[a-z]$/.test(ch)) {
        buf.current = (buf.current + ch).slice(-10);
        if (buf.current.endsWith('konecta')) {
          setActive(true);
          buf.current = '';
        }
      }

      // konami code
      konami.current = [...konami.current, e.key].slice(-KONAMI.length);
      if (konami.current.join(',').toLowerCase() === KONAMI.join(',').toLowerCase()) {
        setActive(true);
        konami.current = [];
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);

  // auto-dismiss after the party
  React.useEffect(() => {
    if (!active) return;
    const t = setTimeout(() => setActive(false), 6500);
    return () => clearTimeout(t);
  }, [active]);

  if (!active) return null;

  // Confetti — stickers caen y rotan, en colores y glifos de Konecta
  const stickers = Array.from({ length: 70 }, (_, i) => ({
    id: i,
    x: Math.random() * 100,
    y: -10 - Math.random() * 30,
    rot: (Math.random() - 0.5) * 80,
    delay: Math.random() * 1.2,
    dur: 3 + Math.random() * 3,
    size: 16 + Math.random() * 36,
    glyph: ['★','◆','●','▲','◉','✦','◈','○','K','★','+','/'][i % 12],
    color: [K.accent, K.lime, K.cyan, K.yellow, K.pink, K.violet][i % 6],
    rotEnd: 360 + Math.random() * 540,
  }));

  // Banderines latitudinales — barras de color cruzan la pantalla
  const bands = [K.accent, K.lime, K.cyan, K.yellow, K.violet];

  // Palabras festivas que aparecen y desaparecen
  const words = ['¡konectaste!', 'fiesta', '★ ★ ★', 'orgánico', 'cdmx', 'real', 'K/01'];

  return (
    <>
      <style>{`
        @keyframes k-rain { to { transform: translateY(115vh) rotate(var(--r-end, 720deg)); } }
        @keyframes k-pulse { 0%,100% { transform: translate(-50%,-50%) scale(1) rotate(-2deg); } 50% { transform: translate(-50%,-50%) scale(1.06) rotate(-1deg); } }
        @keyframes k-band-l { from { transform: translateX(-110%); } to { transform: translateX(110%); } }
        @keyframes k-band-r { from { transform: translateX(110%); } to { transform: translateX(-110%); } }
        @keyframes k-pop { 0% { transform: scale(0) rotate(-12deg); opacity: 0; } 30% { transform: scale(1.15) rotate(-4deg); opacity: 1; } 70% { transform: scale(1) rotate(2deg); opacity: 1; } 100% { transform: scale(0.9) rotate(8deg); opacity: 0; } }
        @keyframes k-flash { 0%,100% { opacity: 0; } 50% { opacity: 0.18; } }
        @keyframes k-shake { 0%,100% { transform: translate(-50%,-50%) rotate(-2deg); } 25% { transform: translate(-49.4%,-50.4%) rotate(-3deg); } 75% { transform: translate(-50.6%,-49.6%) rotate(-1deg); } }
      `}</style>

      {/* Flash de fondo — pulso de color sutil */}
      <div style={{ position: 'fixed', inset: 0, background: K.accent, zIndex: 9990, pointerEvents: 'none', animation: 'k-flash 0.8s ease-out 2', mixBlendMode: 'multiply' }} />

      {/* Banderines diagonales — barras de color cruzando */}
      <div style={{ position: 'fixed', inset: 0, pointerEvents: 'none', zIndex: 9991, overflow: 'hidden' }}>
        {bands.map((c, i) => (
          <div key={i} style={{
            position: 'absolute', top: `${12 + i * 16}%`, left: 0, width: '120%', height: 22,
            background: c, border: `3px solid ${K.ink}`,
            transform: `translateX(${i % 2 ? '110%' : '-110%'}) rotate(${i % 2 ? -4 : 3}deg)`,
            animation: `${i % 2 ? 'k-band-r' : 'k-band-l'} ${1.6 + i * 0.18}s cubic-bezier(.2,.8,.2,1) ${0.05 * i}s forwards`,
            display: 'flex', alignItems: 'center', gap: 18, paddingLeft: 30, color: K.ink,
            fontFamily: K.display, fontSize: 16, textTransform: 'uppercase', letterSpacing: 2, whiteSpace: 'nowrap',
          }}>
            {Array.from({ length: 20 }).map((_, j) => (
              <span key={j}>★ konecta · {i % 2 ? 'K/01' : 'cdmx'} · ★</span>
            ))}
          </div>
        ))}
      </div>

      {/* Confetti cayendo — más denso, rotación variable */}
      <div style={{ position: 'fixed', inset: 0, pointerEvents: 'none', zIndex: 9998, overflow: 'hidden' }}>
        {stickers.map(s => (
          <div key={s.id} style={{
            position: 'absolute', left: `${s.x}%`, top: 0,
            fontSize: s.size, color: s.color, fontFamily: K.display, fontWeight: 900,
            transform: `translateY(${s.y}vh) rotate(${s.rot}deg)`,
            animation: `k-rain ${s.dur}s ${s.delay}s linear forwards`,
            textShadow: `2px 2px 0 ${K.ink}`,
            ['--r-end']: `${s.rotEnd}deg`,
          }}>{s.glyph}</div>
        ))}
      </div>

      {/* Palabras pop-up dispersas */}
      <div style={{ position: 'fixed', inset: 0, pointerEvents: 'none', zIndex: 9997 }}>
        {words.map((w, i) => {
          const palette = [K.lime, K.cyan, K.yellow, K.pink, K.accent, K.violet, K.lime];
          return (
            <div key={i} style={{
              position: 'absolute',
              top: `${15 + (i * 13) % 70}%`,
              left: `${8 + (i * 23) % 80}%`,
              transform: `rotate(${(i % 2 ? -1 : 1) * (4 + i * 2)}deg)`,
              background: palette[i % palette.length], color: K.ink,
              fontFamily: K.display, fontSize: 22 + (i % 3) * 8, textTransform: 'uppercase', letterSpacing: -1,
              padding: '6px 14px', border: `3px solid ${K.ink}`, boxShadow: `4px 4px 0 ${K.ink}`,
              animation: `k-pop 2.2s ${0.4 + i * 0.25}s cubic-bezier(.4,1.4,.6,1) forwards`,
              opacity: 0,
            }}>{w}</div>
          );
        })}
      </div>

      {/* Mensaje principal — sin descuento, solo celebración */}
      <div
        onClick={() => setActive(false)}
        style={{
          position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%,-50%) rotate(-2deg)',
          background: K.lime, color: K.ink,
          border: `5px solid ${K.ink}`, boxShadow: `12px 12px 0 ${K.ink}, 0 0 0 14px ${K.accent}`,
          padding: '32px 44px', zIndex: 9999, textAlign: 'center', cursor: 'pointer',
          fontFamily: K.display, maxWidth: 460,
          animation: 'k-pulse 1.6s ease-in-out infinite, k-shake 0.4s ease-in-out 3',
        }}
      >
        <div style={{ fontFamily: K.mono, fontSize: 11, letterSpacing: 3, textTransform: 'uppercase', marginBottom: 6 }}>
          ● modo fiesta activado
        </div>
        <div style={{ fontSize: 76, lineHeight: 0.88, textTransform: 'uppercase', letterSpacing: -3 }}>
          ¡konectaste!
        </div>
        <div style={{ fontFamily: K.sans, fontSize: 14, marginTop: 14, fontWeight: 500, lineHeight: 1.45 }}>
          encontraste el easter egg.<br/>
          gracias por <b style={{ background: K.ink, color: K.lime, padding: '2px 8px' }}>jugar con nosotros</b>.
        </div>
        <div style={{ fontFamily: K.mono, fontSize: 9, color: K.dim, marginTop: 16, letterSpacing: 1 }}>
          (click para cerrar · se va sola en 6s)
        </div>
      </div>
    </>
  );
}

Object.assign(window, { K, SERVICES, useLiveCounter, TopBar, Marquee, Palette, CustomCursor, StickyWA, EasterEgg });
