/* ===========================================================
   1 A 1 — Componentes (rediseño minimal / líneas / lightbox)
   =========================================================== */
const I = {
  shop: "M3 9l1.5-4.5A2 2 0 0 1 6.4 3h11.2a2 2 0 0 1 1.9 1.5L21 9M3 9v9a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V9M3 9h18M8 9v2a2 2 0 0 1-2 2 2 2 0 0 1-2-2M16 9v2a2 2 0 0 0 2 2 2 2 0 0 0 2-2M12 9v2a2 2 0 0 1-2 2 2 2 0 0 1-2-2m8 0v2a2 2 0 0 1-2 2 2 2 0 0 1-2-2",
  wrench: "M14.7 6.3a4 4 0 0 0-5.4 5l-6 6a1.5 1.5 0 0 0 2 2l6-6a4 4 0 0 0 5-5.4l-2.3 2.3-2-.5-.5-2 2.6-2.4z",
  migrate: "M4 7h11M4 7l3-3M4 7l3 3M20 17H9m11 0l-3-3m3 3l-3 3",
  ai: "M12 3v3m0 12v3m9-9h-3M6 12H3m13.5-6.5L14.5 7.5m-5 9l-2 2m11 0l-2-2m-9-9l-2-2M9 9h6v6H9z",
  ads: "M3 11v2a1 1 0 0 0 1 1h2l4 4V6L6 10H4a1 1 0 0 0-1 1zM15 8a4 4 0 0 1 0 8M18 5a8 8 0 0 1 0 14",
  chart: "M4 20V10m5 10V4m5 16v-7m5 7V8M3 20h18",
  check: "M5 12l5 5L20 6",
  whatsapp: "M12 3a9 9 0 0 0-7.7 13.6L3 21l4.5-1.2A9 9 0 1 0 12 3zm0 2a7 7 0 0 1 5.9 10.8l-.3.5.6 2-2.1-.6-.5.3A7 7 0 1 1 12 5zm-2.2 3.3c-.2 0-.5.1-.7.4-.2.3-.8.8-.8 1.9s.9 2.2 1 2.4c.1.2 1.6 2.6 4 3.5 2 .8 2.4.6 2.8.6.4 0 1.3-.5 1.5-1.1.2-.6.2-1 .1-1.1l-.6-.3-1.3-.6c-.2 0-.3-.1-.5.1l-.6.8c-.1.1-.2.2-.4.1-.2-.1-.9-.4-1.7-1-.6-.6-1-1.2-1.2-1.4-.1-.2 0-.3.1-.4l.3-.4.2-.4v-.3l-.6-1.5c-.2-.4-.3-.4-.5-.4h-.6z",
  mail: "M3 6h18v12H3zM3 7l9 6 9-6",
  pin: "M12 21s-6-5.3-6-10a6 6 0 1 1 12 0c0 4.7-6 10-6 10zm0-7.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z",
  lock: "M7 11V8a5 5 0 0 1 10 0v3M5.5 11h13v9h-13z",
  arrow: "M5 12h14M13 6l6 6-6 6",
  "arrow-left": "M19 12H5M11 18l-6-6 6-6",
  "arrow-ne": "M7 17L17 7M8 7h9v9",
  "arrow-up": "M12 19V5M6 11l6-6 6 6",
  x: "M6 6l12 12M18 6L6 18",
  menu: "M3 12h18M3 6h18M3 18h18"
};

function Icon({ name, w = 24, cls }) {
  return (
    <svg className={cls} viewBox="0 0 24 24" width={w} height={w} fill="none" stroke="currentColor"
      strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
      <path d={I[name]} />
    </svg>
  );
}

/* Título de sección con mask-reveal: el texto sube desde detrás de la línea.
   El JS de reveal (app.jsx) le agrega .in al entrar en pantalla. */
function SectionTitle({ children, className }) {
  return (
    <h2 className={"display reveal-title" + (className ? " " + className : "")}>
      <span className="title-clip"><span className="title-rise-inner">{children}</span></span>
    </h2>
  );
}

const WA_LINK = "https://wa.me/526640000000";
const MAIL_LINK = "mailto:diego@1a1.mx";
const MAPS_LINK = "https://www.google.com/maps/place/SERCONTAD/@32.520156,-116.9926145,19z/";
const BRAND = (
  <span className="brand-mark">1<span className="dot">·</span>A<span className="dot">·</span>1</span>
);

/* ---------------- NAV ---------------- */
function Nav({ t, lang, setLang, route }) {
  const [scrolled, setScrolled] = React.useState(false);
  const [menuOpen, setMenuOpen] = React.useState(false);
  const progRef = React.useRef(null);
  React.useEffect(() => {
    const onScroll = () => {
      setScrolled(window.scrollY > 12);
      const el = progRef.current;
      if (el) {
        const max = document.documentElement.scrollHeight - window.innerHeight;
        el.style.transform = `scaleX(${max > 0 ? Math.min(1, window.scrollY / max).toFixed(4) : 0})`;
      }
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  const toggleMenu = () => setMenuOpen(!menuOpen);
  const closeMenu = () => setMenuOpen(false);

  React.useEffect(() => {
    document.body.style.overflow = menuOpen ? "hidden" : "";
    return () => { document.body.style.overflow = ""; };
  }, [menuOpen]);

  const routes = ["/trabajo", "/industrias", "/herramientas-gratuitas"];
  return (
    <header className={"nav" + (scrolled ? " scrolled" : "") + (menuOpen ? " menu-open" : "")}>
      <div className="shell nav-in">
        <a className="brand" href="/" onClick={closeMenu}>
          {BRAND}
          <span className="brand-sub">
            <span className="bs-name">{t.nav.sub}</span>
            {t.nav.subRole && <span className="bs-role">{t.nav.subRole}</span>}
          </span>
        </a>
        <nav className="nav-links">
          {t.nav.links.map((l, i) => <a key={i} href={routes[i]} className={route === routes[i] ? "active" : ""} aria-current={route === routes[i] ? "page" : undefined}>{l}</a>)}
        </nav>
        <div className="nav-right">
          <div className="lang" role="group" aria-label="Language">
            <button className={lang === "es" ? "on" : ""} onClick={() => setLang("es")}>ES</button>
            <button className={lang === "en" ? "on" : ""} onClick={() => setLang("en")}>EN</button>
          </div>
          <a className="nav-cta-link" href="/#contact">{t.nav.cta}</a>
          <button className="nav-toggle" onClick={toggleMenu} aria-label="Toggle navigation" aria-expanded={menuOpen}>
            <Icon name={menuOpen ? "x" : "menu"} w={20} />
          </button>
        </div>
      </div>
      <div className={"nav-drawer" + (menuOpen ? " open" : "")}>
        <nav className="nav-drawer-links">
          {t.nav.links.map((l, i) => (
            <a key={i} href={routes[i]} className={route === routes[i] ? "active" : ""} aria-current={route === routes[i] ? "page" : undefined} onClick={closeMenu}>
              {l}
              <Icon name="arrow" w={16} cls="drawer-arrow" />
            </a>
          ))}
          <div className="nav-drawer-bottom">
            <div className="lang" role="group" aria-label="Language">
              <button className={lang === "es" ? "on" : ""} onClick={() => { setLang("es"); closeMenu(); }}>ES</button>
              <button className={lang === "en" ? "on" : ""} onClick={() => { setLang("en"); closeMenu(); }}>EN</button>
            </div>
            <a className="btn btn-primary" href="/#contact" onClick={closeMenu}>{t.nav.cta}</a>
          </div>
        </nav>
      </div>
      <span className="nav-progress" ref={progRef} aria-hidden="true"></span>
    </header>
  );
}

/* ---------------- HERO ---------------- */
function Hero({ t }) {
  const h = t.hero;
  const cardRef = React.useRef(null);

  const onMouseMove = (e) => {
    const card = cardRef.current;
    if (!card) return;
    const rect = card.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    const xc = rect.width / 2;
    const yc = rect.height / 2;

    // Tilt the card away from the mouse
    const rotateX = ((yc - y) / yc) * 8;  // max 8deg
    const rotateY = ((x - xc) / xc) * -8; // max -8deg
    card.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) translateY(-4px) scale(1.02)`;
    card.style.boxShadow = `0 54px 100px -40px rgba(0,0,0,.75)`;

    // Pan the image slot inside in the opposite direction
    const imgX = ((x - xc) / xc) * -12; // max -12px
    const imgY = ((y - yc) / yc) * -12; // max -12px
    const img = card.querySelector("image-slot");
    if (img) {
      img.style.transform = `scale(1.12) translate(${imgX}px, ${imgY}px)`;
    }
  };

  const onMouseLeave = () => {
    const card = cardRef.current;
    if (!card) return;
    card.style.transform = "";
    card.style.boxShadow = "";
    const img = card.querySelector("image-slot");
    if (img) {
      img.style.transform = "";
    }
  };

  return (
    <section className="hero" id="top">
      <div className="hero-vlines"></div>
      <div className="pageframe"></div>
      <span className="crosshair tl"></span><span className="crosshair tr"></span>
      <span className="crosshair bl"></span><span className="crosshair br"></span>

      <div className="shell hero-inner">
        <div className="hero-main">
          <h1 className="display">
            {(() => {
              const titleText = h.title || "";
              const dotIndex = titleText.indexOf(". ");
              if (dotIndex !== -1) {
                return (
                  <React.Fragment>
                    <span className="title-part-1">{titleText.slice(0, dotIndex + 1)}</span>
                    <span className="title-part-2">{titleText.slice(dotIndex + 2)}</span>
                  </React.Fragment>
                );
              }
              return <span className="title-part-2">{titleText}</span>;
            })()}
          </h1>
          <div className="hero-sweep"></div>
          <div className="hero-row">
            <p className="lead hero-lead">{h.lead}</p>
            <div className="hero-ctas">
              <a className="btn btn-primary" href="#contact">
                {h.ctaPrimary} <Icon name="arrow" w={16} cls="arrow" />
              </a>
              <a className="hero-link" href={WA_LINK} target="_blank" rel="noopener">
                {h.ctaSecondary} <Icon name="arrow-ne" w={13} />
              </a>
            </div>
          </div>
        </div>
        <div className="hero-visual">
          <figure
            className="hero-shot"
            ref={cardRef}
            onMouseMove={onMouseMove}
            onMouseLeave={onMouseLeave}
          >
            <div className="hero-shot-bar">
              <span className="hero-shot-dots"><i></i><i></i><i></i></span>
              <span className="hero-shot-url"><Icon name="lock" w={11} />{h.shotUrl}</span>
            </div>
            <div className="hero-shot-media">
              <image-slot id="hero-shot" shape="rect" fit="cover" placeholder={h.shot} src="assets/hero-dashboard.png"></image-slot>
            </div>
          </figure>
        </div>
      </div>

      <div className="ticker ticker--logos" aria-label="Empresas afines">
        <div className="ticker-track">
          {[...h.partners, ...h.partners].map((p, i) => (
            <span className="logo-cell" key={i} aria-hidden={i >= h.partners.length ? "true" : undefined}>
              <image-slot id={p.id} shape="rect" fit="contain" placeholder={p.label}></image-slot>
            </span>
          ))}
        </div>
      </div>

    </section>
  );
}

/* ---------------- SHOWCASE (tarjetas en movimiento) ---------------- */
function Showcase({ t }) {
  const s = t.showcase;
  const stageRef = React.useRef(null);
  const cardsRef = React.useRef([]);
  const state = React.useRef({ rx: 0, ry: 0, drift: [0, 0, 0] });

  // Intensidad de tilt por tarjeta: la central reacciona más
  const TILT = [0.55, 1, 0.75];

  const apply = () => {
    const { rx, ry, drift } = state.current;
    cardsRef.current.forEach((el, i) => {
      if (!el) return;
      el.style.transform =
        `perspective(1100px) rotateX(${(rx * TILT[i]).toFixed(2)}deg) rotateY(${(ry * TILT[i]).toFixed(2)}deg) translateY(${drift[i].toFixed(1)}px)`;
    });
  };

  React.useEffect(() => {
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
    const stage = stageRef.current;
    if (!stage) return;

    const onMove = (e) => {
      const r = stage.getBoundingClientRect();
      state.current.rx = -((e.clientY - r.top) / r.height - 0.5) * 7;
      state.current.ry = ((e.clientX - r.left) / r.width - 0.5) * 7;
      apply();
    };
    const onLeave = () => { state.current.rx = 0; state.current.ry = 0; apply(); };

    // Parallax: cada tarjeta deriva a distinta velocidad respecto al centro del viewport
    const SPEED = [0.05, 0.11, 0.08];
    let raf = null;
    const onScroll = () => {
      if (raf) return;
      raf = requestAnimationFrame(() => {
        raf = null;
        const r = stage.getBoundingClientRect();
        const offset = r.top + r.height / 2 - window.innerHeight / 2;
        state.current.drift = SPEED.map((v) => -offset * v);
        apply();
      });
    };

    stage.addEventListener("mousemove", onMove);
    stage.addEventListener("mouseleave", onLeave);
    window.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => {
      stage.removeEventListener("mousemove", onMove);
      stage.removeEventListener("mouseleave", onLeave);
      window.removeEventListener("scroll", onScroll);
      if (raf) cancelAnimationFrame(raf);
    };
  }, []);

  const card = (i, cls) => (
    <div className={"show-pos " + cls}>
      <figure className="show-card" ref={(el) => (cardsRef.current[i] = el)}>
        <div className="hero-shot-bar">
          <span className="hero-shot-dots"><i></i><i></i><i></i></span>
          <span className="hero-shot-url"><Icon name="lock" w={11} />{s.cards[i].url}</span>
        </div>
        <div className="hero-shot-media">
          <image-slot id={"show-card-" + i} shape="rect" fit="cover" placeholder={s.cards[i].ph}></image-slot>
        </div>
        <figcaption className="show-cap">
          <span className="cap-top"><em>{s.cards[i].num}</em> {s.cards[i].name} · {s.cards[i].loc}</span>
          <span className="cap-desc">{s.cards[i].desc}</span>
        </figcaption>
      </figure>
    </div>
  );

  const titleText = s.title || "";
  const dotIndex = titleText.indexOf(". ");

  return (
    <section className="showcase" id="motion">
      <div className="shell">
        <div className="showcase-head" data-reveal>
          <h2 className="display">
            {dotIndex !== -1 ? (
              <React.Fragment>
                <span className="title-part-1">{titleText.slice(0, dotIndex + 1)}</span>
                <span className="title-part-2">{titleText.slice(dotIndex + 2)}</span>
              </React.Fragment>
            ) : titleText}
          </h2>
          <div className="showcase-micro">
            <span className="eyebrow"><i className="sec-no">01</i>{s.eyebrow}</span>
            <p className="showcase-para">{s.para}</p>
            <p className="showcase-note">{s.note}</p>
          </div>
        </div>
        <div className="showcase-stage" ref={stageRef} data-reveal>
          {card(0, "pos-l")}
          {card(1, "pos-c")}
          {card(2, "pos-r")}
        </div>
      </div>

      <a className="chat-fab" href={WA_LINK} target="_blank" rel="noopener" aria-label="WhatsApp">
        <Icon name="whatsapp" w={22} />
      </a>
    </section>
  );
}

/* ---------------- POR QUÉ ---------------- */
function Why({ t }) {
  return (
    <section className="band invert why" id="why">
      <div className="shell">
        <div className="sec-head">
          <span className="eyebrow"><i className="sec-no">01</i>{t.why.eyebrow}</span>
          <SectionTitle>{t.why.title}</SectionTitle>
          <p className="lead">{t.why.lead}</p>
        </div>
        <div className="why-list">
          {t.why.items.map((it, i) => (
            <div className="why-row" data-reveal key={i}>
              <div className="why-row-head">
                <span className="why-n">{it.num}</span>
                <p className="why-fear">{it.quote}</p>
              </div>
              <div className="why-row-body">
                <h3 className="display">{it.h}</h3>
                <p>{it.p}</p>
              </div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ---------------- SERVICIOS — split editorial (aside fija + lista) ---------------- */
function Services({ t }) {
  const s = t.services;
  return (
    <section className="band services" id="services">
      <div className="shell svc-split">
        <aside className="svc-aside">
          <span className="eyebrow"><i className="sec-no">02</i>{s.eyebrow}</span>
          <SectionTitle>{s.title}</SectionTitle>
          <p className="lead">{s.lead}</p>
          <a className="btn btn-primary svc-aside-cta" href="#contact">
            {t.hero.ctaPrimary}<Icon name="arrow" w={16} cls="arrow" />
          </a>
        </aside>
        <div className="svc-list">
          {s.items.map((it, i) => (
            <a className="svc-row" href="#contact" data-reveal key={i}>
              <span className="svc-row-num">{it.num}</span>
              <span className="svc-row-ico"><Icon name={it.icon} w={20} /></span>
              <div className="svc-row-main">
                <h3 className="display">{it.h}</h3>
                <p>{it.p}</p>
                <ul className="svc-row-tags">
                  {it.bullets.map((b, j) => <li key={j}>{b}</li>)}
                </ul>
              </div>
              <span className="svc-row-go"><Icon name="arrow-ne" w={16} /></span>
            </a>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ---------------- ÍNDICE WEB — tarjetas estilo Showcase con preview flotante ---------------- */
function WebIndex({ t }) {
  const w = t.webIndex;
  const stageRef = React.useRef(null);
  const cardsRef = React.useRef([]);
  const state = React.useRef({ rx: 0, ry: 0, drift: [0, 0, 0] });

  const TILT = [0.55, 1, 0.75];

  const apply = () => {
    const { rx, ry, drift } = state.current;
    cardsRef.current.forEach((el, i) => {
      if (!el) return;
      el.style.transform =
        `perspective(1100px) rotateX(${(rx * TILT[i]).toFixed(2)}deg) rotateY(${(ry * TILT[i]).toFixed(2)}deg) translateY(${drift[i].toFixed(1)}px)`;
    });
  };

  React.useEffect(() => {
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
    const stage = stageRef.current;
    if (!stage) return;

    const onMove = (e) => {
      const r = stage.getBoundingClientRect();
      state.current.rx = -((e.clientY - r.top) / r.height - 0.5) * 7;
      state.current.ry = ((e.clientX - r.left) / r.width - 0.5) * 7;
      apply();
    };
    const onLeave = () => { state.current.rx = 0; state.current.ry = 0; apply(); };

    const SPEED = [0.05, 0.11, 0.08];
    let raf = null;
    const onScroll = () => {
      if (raf) return;
      raf = requestAnimationFrame(() => {
        raf = null;
        const r = stage.getBoundingClientRect();
        const offset = r.top + r.height / 2 - window.innerHeight / 2;
        state.current.drift = SPEED.map((v) => -offset * v);
        apply();
      });
    };

    stage.addEventListener("mousemove", onMove);
    stage.addEventListener("mouseleave", onLeave);
    window.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => {
      stage.removeEventListener("mousemove", onMove);
      stage.removeEventListener("mouseleave", onLeave);
      window.removeEventListener("scroll", onScroll);
      if (raf) cancelAnimationFrame(raf);
    };
  }, []);

  const card = (i, cls) => (
    <div className={"wix-pos " + cls}>
      <a className="wix-card" href="/trabajo" ref={(el) => (cardsRef.current[i] = el)} onClick={() => {
        window.pendingProjectOpen = i;
        window.dispatchEvent(new CustomEvent('openproject', { detail: { index: i } }));
      }}>
        <div className="hero-shot-bar">
          <span className="hero-shot-dots"><i></i><i></i><i></i></span>
          <span className="hero-shot-url"><Icon name="lock" w={11} />{w.cards[i].url}</span>
        </div>
        <div className="hero-shot-media">
          <image-slot id={"wix-card-" + i} shape="rect" fit="cover" placeholder={w.cards[i].slot} src={w.cards[i].src}></image-slot>
        </div>
        <figcaption className="wix-cap">
          <span className="wix-type">{w.cards[i].type}</span>
          <span className="wix-title">{w.cards[i].title} <Icon name="arrow" w={14} /></span>
          <span className="wix-company">{w.cards[i].company}</span>
        </figcaption>
      </a>
    </div>
  );

  return (
    <section className="web-index" id="web" ref={stageRef}>
      <div className="shell">
        <div className="wix-head" data-reveal>
          <div className="sec-head">
            <span className="eyebrow"><i className="sec-no">03</i>{w.eyebrow}</span>
            <SectionTitle>{w.title}</SectionTitle>
            <p className="lead">{w.lead}</p>
          </div>
          <p className="wix-note">{w.note}</p>
        </div>
        <div className="wix-stage" data-reveal>
          {card(0, "pos-l")}
          {card(1, "pos-c")}
          {card(2, "pos-r")}
        </div>
        <div className="wix-footer" data-reveal>
          <a className="btn btn-primary" href="/trabajo">
            {w.cta}<Icon name="arrow" w={16} cls="arrow" />
          </a>
        </div>
      </div>
    </section>
  );
}

/* ---------------- ÍNDICE WEB — listado estilo sección 01 con preview flotante ---------------- */
function WebListIndex({ t }) {
  const w = t.webListIndex;
  const allProjects = [t.gallery.featured, ...t.gallery.items];
  const previewRef = React.useRef(null);
  const [activeIndex, setActiveIndex] = React.useState(null);

  const onMouseMove = (e) => {
    const el = previewRef.current;

    const cx = e.clientX;
    const cy = e.clientY;

    // Position preview centered on cursor
    if (el) {
      const width = 520;
      const height = 340;
      let x = cx - width / 2;
      let y = cy - height / 2;

      // Clamp to viewport edges with 12px margin
      x = Math.max(12, Math.min(x, window.innerWidth - width - 12));
      y = Math.max(12, Math.min(y, window.innerHeight - height - 12));

      el.style.left = `${x}px`;
      el.style.top = `${y}px`;
    }
  };

  const handleProjectClick = (i) => {
    window.pendingProjectOpen = i;
    window.dispatchEvent(new CustomEvent('openproject', { detail: { index: i } }));
  };

  return (
    <section className="band web-index web-list-section" id="web-list" onMouseMove={onMouseMove}>
      <div className="shell">
        <div className="wix-head" data-reveal>
          <div className="sec-head">
            <span className="eyebrow"><i className="sec-no">04</i>{w.eyebrow}</span>
            <SectionTitle>{w.title}</SectionTitle>
            <p className="lead">{w.lead}</p>
          </div>
          <p className="wix-note">{w.note}</p>
        </div>

        <div className="wix-list" data-reveal>
          {allProjects.map((p, i) => (
            <a
              key={p.idx}
              className="wix-row"
              href="/trabajo"
              onMouseEnter={() => setActiveIndex(i)}
              onMouseLeave={() => setActiveIndex(null)}
              onClick={() => handleProjectClick(i)}
            >
              <div className="wix-row-head">
                <span className="wix-n">{p.idx}</span>
                <span className="wix-meta">{p.type}</span>
              </div>
              <div className="wix-row-body">
                <h3 className="display">
                  {p.title} <Icon name="arrow-ne" w={15} />
                </h3>
                <p>{p.desc}</p>
              </div>
            </a>
          ))}
        </div>

        <div className="wix-footer" data-reveal>
          <a className="btn btn-primary" href="/trabajo">
            {w.cta}<Icon name="arrow" w={16} cls="arrow" />
          </a>
        </div>
      </div>

      {/* Backdrop blur overlay – brings preview to the front */}
      <div className={`wix-backdrop-blur ${activeIndex !== null ? 'active' : ''}`} />

      <div
        ref={previewRef}
        className={`wix-hover-preview ${activeIndex !== null ? 'visible' : ''}`}
        style={{ pointerEvents: 'none' }}
      >
        <div className="hero-shot-media" style={{ position: 'relative', width: '100%', height: '100%' }}>
          {allProjects.map((p, idx) => (
            <div
              key={p.idx}
              className={`preview-image-wrap ${activeIndex === idx ? 'active' : ''}`}
              style={{
                position: 'absolute',
                top: 0,
                left: 0,
                width: '100%',
                height: '100%',
                opacity: activeIndex === idx ? 1 : 0,
                transition: 'opacity 0.4s cubic-bezier(0.25, 1, 0.5, 1)',
              }}
            >
              <image-slot
                id={`wix-prev-${p.idx}`}
                shape="rect"
                fit="cover"
                placeholder={p.slot}
                src={p.src}
              ></image-slot>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}


/* ---------------- TRABAJO — exposición editorial (catálogo curatorial impreso) ---------------- */
function WorkExhibition({ t }) {
  const g = t.gallery;
  const all = [g.featured, ...g.items];
  const [cat, setCat] = React.useState("all");
  const inCat = (p) => cat === "all" || p.cat === cat;

  // Abre la pieza en el lightbox de la galería (montada en la misma página).
  const openPiece = (i) => {
    window.pendingProjectOpen = null;
    window.dispatchEvent(new CustomEvent("openproject", { detail: { index: i } }));
  };

  // Tamaño curatorial por posición en la retícula de 12 columnas (composición asimétrica).
  const layout = ["exh-c-7", "exh-c-5 exh-drop", "exh-c-6", "exh-c-6 exh-drop", "exh-c-12 exh-protagonist"];

  return (
    <section className="work-exhibition" id="exhibition">
      <div className="shell">
        {/* HERO editorial */}
        <header className="exh-hero" data-reveal>
          <div className="exh-hero-top">
            <span className="exh-index">05</span>
            <span className="exh-eyebrow">{g.eyebrow}</span>
            <span className="exh-room">{g.room}</span>
          </div>
          <h1 className="exh-title-main display">{g.title}</h1>
          <p className="exh-lead">{g.lead}</p>
          <hr className="exh-rule" />
        </header>

        {/* Filtros editoriales */}
        <div className="exh-filters" role="tablist" aria-label="Filtros de portafolio" data-reveal>
          {g.filters.map((f, i) => (
            <React.Fragment key={f.id}>
              {i > 0 && <span className="exh-filter-sep" aria-hidden="true">·</span>}
              <button role="tab" aria-selected={cat === f.id}
                className={"exh-filter" + (cat === f.id ? " on" : "")}
                onClick={() => setCat(f.id)}>{f.l}</button>
            </React.Fragment>
          ))}
        </div>

        {/* Catálogo asimétrico — cada proyecto es una "pieza expuesta" */}
        <div className="exh-grid">
          {all.map((p, i) => (
            <article key={p.idx} className={"exh-piece " + layout[i] + (inCat(p) ? "" : " exh-hide")} data-reveal>
              <button className="exh-open" onClick={() => openPiece(i)} aria-label={p.title}>
                <span className="exh-plate">{g.pieceLabel} {p.idx}</span>
                <div className="exh-frame">
                  <div className="exh-img">
                    <image-slot id={"exh-" + p.idx} shape="rect" fit="cover" placeholder={p.slot} src={p.src}></image-slot>
                  </div>
                </div>
              </button>
              <div className="exh-meta">
                <span className="exh-cat">{p.type}</span>
                <h3 className="exh-piece-title display">{p.title}</h3>
                <p className="exh-desc">{p.desc}</p>
                <div className="exh-cols">
                  {p.services ? (
                    <div className="exh-col">
                      <span className="exh-col-h">{g.servicesLabel}</span>
                      <ul>{p.services.map((s, k) => <li key={k}>{s}</li>)}</ul>
                    </div>
                  ) : null}
                  {p.tags ? (
                    <div className="exh-col">
                      <span className="exh-col-h">{g.stackLabel}</span>
                      <ul>{p.tags.map((s, k) => <li key={k}>{s}</li>)}</ul>
                    </div>
                  ) : null}
                </div>
              </div>
            </article>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ---------------- DESARROLLO WEB — sala de galería (pin + scroll horizontal) ---------------- */
function Gallery({ t }) {
  const g = t.gallery;
  const all = [g.featured, ...g.items];
  const [cat, setCat] = React.useState("all");
  const [open, setOpen] = React.useState(false);
  const [idx, setIdx] = React.useState(0);
  const [slide, setSlide] = React.useState(0);
  const [glActive, setGlActive] = React.useState(false);
  const [closing, setClosing] = React.useState(false);
  const closeTimer = React.useRef(null);
  const sectionRef = React.useRef(null);
  const stageRef = React.useRef(null);
  const trackRef = React.useRef(null);
  const barRef = React.useRef(null);
  const countRef = React.useRef(null);
  const glCanvasRef = React.useRef(null);
  const glRef = React.useRef(null);
  const inCat = (p) => cat === "all" || p.cat === cat;
  const visible = all.filter(inCat);

  React.useEffect(() => {
    const checkPending = () => {
      if (typeof window.pendingProjectOpen === 'number') {
        const i = window.pendingProjectOpen;
        window.pendingProjectOpen = null;
        setTimeout(() => {
          setIdx(i);
          setOpen(true);
          setSlide((s) => s + 1);
        }, 150);
      }
    };
    checkPending();

    const handleOpen = (e) => {
      if (e.detail && typeof e.detail.index === 'number') {
        const i = e.detail.index;
        setIdx(i);
        setOpen(true);
        setSlide((s) => s + 1);
      }
    };
    window.addEventListener('openproject', handleOpen);
    return () => {
      window.removeEventListener('openproject', handleOpen);
    };
  }, []);

  // En táctil / pantallas chicas / reduced-motion la sala no se pinea:
  // el muro se recorre con scroll horizontal nativo (CSS).
  const STATIC_MQ = "(max-width: 880px), (pointer: coarse), (prefers-reduced-motion: reduce)";

  // Pin + traducción: la sección mide 100vh + el recorrido del muro;
  // al bajar, el muro avanza hacia la derecha.
  React.useEffect(() => {
    const section = sectionRef.current, stage = stageRef.current, track = trackRef.current;
    if (!section || !stage || !track) return;
    const mq = window.matchMedia(STATIC_MQ);
    const n = visible.length;
    let dist = 0, raf = null;

    const apply = () => {
      raf = null;
      if (mq.matches || !dist) return;
      const top = section.getBoundingClientRect().top;
      const p = Math.min(1, Math.max(0, -top / dist));
      track.style.transform = `translate3d(${(-p * dist).toFixed(1)}px, 0, 0)`;
      if (barRef.current) barRef.current.style.transform = `scaleX(${p.toFixed(4)})`;
      if (countRef.current) {
        const cur = Math.min(n, Math.floor(p * n) + 1);
        countRef.current.textContent = String(cur).padStart(2, "0") + " — " + String(n).padStart(2, "0");
      }
    };

    const measure = () => {
      if (mq.matches) {
        section.style.height = "";
        track.style.transform = "";
        return;
      }
      dist = Math.max(0, track.scrollWidth - stage.clientWidth);
      section.style.height = `calc(100vh + ${Math.round(dist)}px)`;
      apply();
    };

    const onScroll = () => { if (!raf) raf = requestAnimationFrame(apply); };
    measure();
    const timers = [120, 450].map((ms) => setTimeout(measure, ms)); // fuentes / layout tardío
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", measure);
    mq.addEventListener && mq.addEventListener("change", measure);
    return () => {
      timers.forEach(clearTimeout);
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", measure);
      mq.removeEventListener && mq.removeEventListener("change", measure);
      if (raf) cancelAnimationFrame(raf);
      section.style.height = "";
    };
  }, [cat, visible.length]);

  // Revelado cinematográfico por pieza (blur→foco + slice + número kinético)
  React.useEffect(() => {
    const section = sectionRef.current;
    if (!section) return;
    const pieces = Array.from(section.querySelectorAll(".gw-piece"));
    if (!pieces.length) return;
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches
      || document.documentElement.classList.contains("motion-off");
    section.classList.add("cine");

    if (reduce || !window.anime) {
      pieces.forEach((p) => {
        p.classList.add("in-view");
        p.querySelectorAll(".gw-plaque > *, .gw-index").forEach((el) => { el.style.opacity = 1; });
      });
      return;
    }

    const reveal = (piece) => {
      const lines = piece.querySelectorAll(".gw-plaque > *");
      const index = piece.querySelector(".gw-index");
      anime({ targets: lines, opacity: [0, 1], translateY: [16, 0], duration: 620, delay: anime.stagger(80, { start: 240 }), easing: "easeOutExpo" });
      if (index) anime({ targets: index, opacity: [0, 1], translateY: [28, 0], duration: 1000, easing: "easeOutExpo" });
    };
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting && !e.target.classList.contains("in-view")) {
          e.target.classList.add("in-view");
          reveal(e.target);
          io.unobserve(e.target);
        }
      });
    }, { threshold: 0.25 });
    pieces.forEach((p) => io.observe(p));
    return () => io.disconnect();
  }, [cat]);

  const changeCat = (id) => setCat(id);

  const openAt = (p) => {
    const i = all.indexOf(p);
    setIdx(i); setOpen(true); setSlide((s) => s + 1);
    if (glRef.current) glRef.current.focus(i); // "la pieza se vuelve un mundo"
  };
  const close = () => {
    setOpen(false);
    if (glRef.current) {
      glRef.current.unfocus();
      // mantiene el lienzo a pantalla completa mientras la pieza se reduce, luego lo libera
      setClosing(true);
      clearTimeout(closeTimer.current);
      closeTimer.current = setTimeout(() => setClosing(false), 520);
    }
  };
  const go = (dir) => {
    if (glRef.current) { // en GL recorremos todas las piezas
      const ni = (idx + dir + all.length) % all.length;
      setIdx(ni); setSlide((s) => s + 1); glRef.current.focus(ni);
      return;
    }
    const list = all.filter(inCat);
    const cur = Math.max(0, list.findIndex((p) => all.indexOf(p) === idx));
    const ni = (cur + dir + list.length) % list.length;
    setIdx(all.indexOf(list[ni]));
    setSlide((s) => s + 1);
  };

  React.useEffect(() => {
    const onKey = (e) => {
      if (!open) return;
      if (e.key === "Escape") close();
      else if (e.key === "ArrowRight") go(1);
      else if (e.key === "ArrowLeft") go(-1);
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  });
  React.useEffect(() => {
    document.body.style.overflow = open ? "hidden" : "";
    return () => { document.body.style.overflow = ""; };
  }, [open]);

  // Capa WebGL (Three.js) — sólo en el modo pineado de escritorio y con motion.
  // El DOM sigue siendo accesible (opacity:0, focusable); este canvas es lo visual.
  React.useEffect(() => {
    const canvas = glCanvasRef.current, stage = stageRef.current, section = sectionRef.current;
    if (!canvas || !stage || !section) return;
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches
      || document.documentElement.classList.contains("motion-off");
    if (reduce || !window.galleryGLSupported || !window.galleryGLSupported() || !window.createGalleryGL) return;

    const staticMq = window.matchMedia(STATIC_MQ);
    // Usa la imagen que el image-slot resuelve: la subida por el autor (_userUrl) o el src del asset.
    const resolveSrc = (p) => {
      const el = document.getElementById("lb-" + p.idx);
      return (el && (el._userUrl || el.getAttribute("src"))) || p.src;
    };
    const items = all.map((p) => ({ src: resolveSrc(p), idx: p.idx, title: p.title }));
    const getProgress = () => {
      const top = section.getBoundingClientRect().top;
      const dist = section.offsetHeight - window.innerHeight;
      return dist > 0 ? Math.min(1, Math.max(0, -top / dist)) : 0;
    };
    const build = () => {
      if (glRef.current || staticMq.matches) return;
      const gl = window.createGalleryGL({ canvas, items, getProgress, onPick: (i) => openAt(all[i]) });
      if (gl) { glRef.current = gl; stage.classList.add("gl-on"); setGlActive(true); }
    };
    const teardown = () => {
      if (glRef.current) { glRef.current.destroy(); glRef.current = null; }
      stage.classList.remove("gl-on"); setGlActive(false);
    };
    const onMq = () => { staticMq.matches ? teardown() : build(); };
    build();
    staticMq.addEventListener && staticMq.addEventListener("change", onMq);
    // Imagen soltada en un slot → recarga esa textura en el WebGL al vuelo
    const onSlotChange = (e) => {
      if (!glRef.current || !e.detail || !e.detail.id) return;
      const pi = all.findIndex((p) => "lb-" + p.idx === e.detail.id);
      if (pi >= 0) glRef.current.updateTexture(pi, e.detail.url);
    };
    document.addEventListener("imageslotchange", onSlotChange);
    // Pausa el render WebGL cuando la sala sale de pantalla (ahorro de batería/CPU)
    const vis = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (!glRef.current) return;
        e.isIntersecting ? glRef.current.resume() : glRef.current.pause();
      });
    }, { rootMargin: "120px" });
    vis.observe(section);
    return () => {
      vis.disconnect();
      document.removeEventListener("imageslotchange", onSlotChange);
      teardown();
      staticMq.removeEventListener && staticMq.removeEventListener("change", onMq);
    };
  }, []);

  // Tipografía kinética del case-study (GL)
  React.useEffect(() => {
    if (!glActive || !open || !window.anime) return;
    const els = document.querySelectorAll(".gw-case-body > *");
    if (els.length) anime({ targets: els, opacity: [0, 1], translateY: [26, 0], duration: 720, delay: anime.stagger(70), easing: "easeOutExpo" });
  }, [open, slide, glActive]);

  // Filtro en GL: las piezas fuera de categoría salen volando, las visibles se recolocan
  React.useEffect(() => {
    if (!glActive || !glRef.current) return;
    const indices = all.map((p, i) => i).filter((i) => cat === "all" || all[i].cat === cat);
    glRef.current.setVisible(indices);
  }, [cat, glActive]);

  const proj = all[idx];
  const total = String(all.length).padStart(2, "0");
  const pieceKey = (p) => (e) => {
    if (e.key === "Enter" || e.key === " ") { e.preventDefault(); openAt(p); }
  };

  return (
    <section className={"band bg-2 gallery gwall" + (glActive && (open || closing) ? " focused" : "")} id="portafolio" ref={sectionRef}>
      <div className="gwall-sticky">
        <div className="shell gwall-head gwall-head-slim" data-reveal>
          <span className="eyebrow">{g.quick}</span>
          <div className="gwall-meta">
            <span className="gwall-room">{g.room}</span>
            <span className="gwall-hint">{g.hint} <Icon name="arrow" w={14} /></span>
          </div>
        </div>

        <div className="shell gwall-bar-row gwall-bar-slim">
          <div className="gwall-progress" aria-hidden="true">
            <span className="gwall-count" ref={countRef}>{"01 — " + String(visible.length).padStart(2, "0")}</span>
            <span className="gwall-bar"><i ref={barRef}></i></span>
          </div>
        </div>

        <div className="gwall-stage" ref={stageRef}>
          <canvas className="gwall-gl" ref={glCanvasRef} aria-hidden="true"></canvas>
          <div className="gwall-track" key={cat} ref={trackRef}>
            {all.map((p) => (
              <figure key={p.idx} className={"gw-piece" + (inCat(p) ? "" : " hide")} role="button" tabIndex={0}
                onClick={() => openAt(p)} onKeyDown={pieceKey(p)} aria-label={p.title}>
                <span className="gw-index" aria-hidden="true">{p.idx}</span>
                <div className="gw-frame">
                  <span className="gw-no">{g.pieceLabel} {p.idx}</span>
                  <div className="gw-art">
                    <image-slot id={"lb-" + p.idx} shape="rect" fit="cover" placeholder={p.slot} src={p.src}></image-slot>
                  </div>
                </div>
                <figcaption className="gw-plaque">
                  <span className="gw-piece-label">{p.type}</span>
                  <span className="gw-title">{p.title} <Icon name="arrow-ne" w={15} /></span>
                  <span className="gw-tags">{p.tags ? p.tags.join(" · ") : p.url}</span>
                </figcaption>
              </figure>
            ))}
            <div className="gw-end">
              <span className="gwall-room">{g.room}</span>
              <h3 className="display">{g.endTitle}</h3>
              <a className="btn btn-primary" href="/#contact">{g.endCta}<Icon name="arrow" w={16} cls="arrow" /></a>
            </div>
          </div>
        </div>
      </div>

      {glActive && (
        <div className={"gw-case" + (open ? " open" : "")} aria-hidden={!open} onClick={close}>
          <div className="gw-case-scrim"></div>
          <button className="gw-case-close" onClick={(e) => { e.stopPropagation(); close(); }} aria-label={g.close}>
            <Icon name="x" w={18} />
          </button>
          <div className="gw-case-body" key={slide} onClick={(e) => e.stopPropagation()}>
            <span className="gw-case-idx">{proj.idx} — {total}</span>
            <span className="gw-case-type">{proj.type}</span>
            <h3 className="display">{proj.title}</h3>
            <p>{proj.desc}</p>
            {proj.tags ? <div className="gw-case-tags">{proj.tags.map((tg, i) => <span className="gw-case-tag" key={i}>{tg}</span>)}</div> : null}
            <div className="gw-case-actions">
              <a className="btn btn-primary" href="/#contact" onClick={close}>{g.endCta}<Icon name="arrow" w={16} cls="arrow" /></a>
              <span className="gw-case-count">{proj.url}</span>
              <div className="gw-case-arrows">
                <button onClick={(e) => { e.stopPropagation(); go(-1); }} aria-label="prev"><Icon name="arrow-left" w={18} /></button>
                <button onClick={(e) => { e.stopPropagation(); go(1); }} aria-label="next"><Icon name="arrow" w={18} /></button>
              </div>
            </div>
          </div>
        </div>
      )}

      <div className={"lightbox" + (open && !glActive ? " open" : "")} onClick={close} aria-hidden={!open || glActive} style={glActive ? { display: "none" } : null}>
        <div className="lb-panel" onClick={(e) => e.stopPropagation()}>
          <button className="lb-close" onClick={close} aria-label={g.close}><Icon name="x" w={18} /></button>
          <div className="lb-media">
            <div className="lb-bar">
              <span className="lb-dots"><i></i><i></i><i></i></span>
              <span className="lb-url"><Icon name="lock" w={11} />{proj.url}</span>
            </div>
            <div className="lb-slot-wrap">
              <div className="lb-slide" key={slide}>
                <image-slot id={"lb-" + proj.idx} shape="rect" placeholder={proj.slot} src={proj.src}></image-slot>
              </div>
            </div>
          </div>
          <div className="lb-info">
            <span className="lb-idx">{proj.idx} — {total}</span>
            <span className="lb-type">{proj.type}</span>
            <h3>{proj.title}</h3>
            <p>{proj.desc}</p>
            {proj.tags ? <div className="lb-tags">{proj.tags.map((tg, i) => <span className="lb-tag" key={i}>{tg}</span>)}</div> : null}
            <div className="lb-nav">
              <span className="lb-count">{proj.url}</span>
              <div className="lb-arrows">
                <button onClick={() => go(-1)} aria-label="prev"><Icon name="arrow-left" w={18} /></button>
                <button onClick={() => go(1)} aria-label="next"><Icon name="arrow" w={18} /></button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ---------------- AUDITORÍA — diagnóstico que se ensambla al scroll ---------------- */
function Audit({ t }) {
  const a = t.audit;
  const secRef = React.useRef(null);
  const bigRef = React.useRef(null);
  const zeroRef = React.useRef(null);
  const scanRef = React.useRef(null);
  const diagRef = React.useRef(null);

  React.useEffect(() => {
    const sec = secRef.current;
    if (!sec) return;
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    const motionOff = document.documentElement.classList.contains("motion-off");
    if (reduce || motionOff || !window.anime) return; // sin motion: estado final por CSS

    const items = diagRef.current ? Array.from(diagRef.current.querySelectorAll("li")) : [];
    sec.classList.add("arm"); // oculta estados iniciales sólo si vamos a animar

    let played = false;
    const play = () => {
      if (played) return;
      played = true;
      const tl = anime.timeline({ easing: "easeOutExpo" });
      tl.add({ targets: scanRef.current, translateY: ["-40%", "130%"], opacity: [0, 1, 1, 0], duration: 1300, easing: "easeInOutQuad" }, 0)
        .add({ targets: items, opacity: [0, 1], translateX: [-22, 0], duration: 560, delay: anime.stagger(85) }, 260)
        .add({ targets: bigRef.current, opacity: [0, 1], scale: [0.7, 1], duration: 1000, easing: "easeOutElastic(1, .55)" }, 520);
      if (zeroRef.current) {
        const obj = { v: 9 };
        anime({
          targets: obj, v: 0, round: 1, duration: 900, delay: 660, easing: "easeOutExpo",
          update: () => { if (zeroRef.current) zeroRef.current.textContent = String(obj.v); }
        });
      }
      sec.classList.add("played");
    };
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) { play(); io.disconnect(); } });
    }, { threshold: 0.35 });
    io.observe(sec);
    return () => io.disconnect();
  }, []);

  // Imán sobre el $0 (sólo puntero fino)
  const onBigMove = (e) => {
    const el = bigRef.current;
    if (!el || !window.matchMedia("(hover: hover) and (pointer: fine)").matches) return;
    const r = el.getBoundingClientRect();
    const dx = (e.clientX - (r.left + r.width / 2)) * 0.16;
    const dy = (e.clientY - (r.top + r.height / 2)) * 0.16;
    el.style.transform = `translate(${dx.toFixed(1)}px, ${dy.toFixed(1)}px)`;
  };
  const onBigLeave = () => { if (bigRef.current) bigRef.current.style.transform = ""; };

  return (
    <section className="band audit" id="audit" ref={secRef}>
      <span className="crosshair tl"></span><span className="crosshair tr"></span>
      <span className="crosshair bl"></span><span className="crosshair br"></span>
      <div className="shell">
        <div className="audit-grid" data-reveal>
          <div className="audit-pitch">
            <span className="eyebrow"><i className="sec-no">06</i>{a.eyebrow}</span>
            <SectionTitle>{a.title}</SectionTitle>
            <p>{a.p}</p>
            <div className="audit-free" onMouseMove={onBigMove} onMouseLeave={onBigLeave}>
              <span className="big" ref={bigRef} aria-label={a.freeBig}>
                <span className="cur">$</span><span className="zero" ref={zeroRef}>0</span>
              </span>
              <span className="sm">{a.freeSm}</span>
            </div>
            <a className="btn btn-primary" href="#contact">{a.cta}<Icon name="arrow" w={16} cls="arrow" /></a>
          </div>
          <div className="audit-diag" ref={diagRef}>
            <span className="audit-diag-tag">{a.eyebrow}</span>
            <span className="audit-scan" ref={scanRef} aria-hidden="true"></span>
            <ul className="audit-list">
              {a.list.map((li, i) => (
                <li key={i}><span className="chk"><Icon name="check" w={13} /></span>{li}</li>
              ))}
            </ul>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ---------------- CONTACTO ---------------- */
function Contact({ t }) {
  const [sent, setSent] = React.useState(false);
  const ch = { wa: "whatsapp", mail: "mail", pin: "pin" };
  const href = { wa: WA_LINK, mail: MAIL_LINK, pin: MAPS_LINK };
  return (
    <section className="band contact" id="contact">
      <div className="shell">
        <div className="sec-head">
          <span className="eyebrow"><i className="sec-no">07</i>{t.contact.eyebrow}</span>
          <SectionTitle>{t.contact.title}</SectionTitle>
          <p className="lead">{t.contact.lead}</p>
        </div>
        <div className="contact-grid">
          <div className="contact-info">
            {t.contact.channels.map((c, i) => {
              const inner = (
                <React.Fragment>
                  <span className="ci"><Icon name={ch[c.k]} w={20} /></span>
                  <span><span className="lbl" style={{ display: "block" }}>{c.lbl}</span><span className="val" style={{ display: "block" }}>{c.val}</span></span>
                </React.Fragment>
              );
              return href[c.k]
                ? <a className="contact-channel" key={i} href={href[c.k]} target="_blank" rel="noopener">{inner}</a>
                : <div className="contact-channel" key={i}>{inner}</div>;
            })}
            <div className="sede" data-reveal>
              <div className="sede-map">
                <div className="sede-img" aria-label="Baja California, México"></div>
                <span className="sede-marker"></span>
              </div>
              <div className="sede-text">
                <span className="sede-label">{t.contact.sede.label}</span>
                <span className="sede-title">{t.contact.sede.title}</span>
                <p className="sede-note">{t.contact.sede.note}</p>
              </div>
            </div>
          </div>
          <form className="form" onSubmit={(e) => { e.preventDefault(); setSent(true); }}>
            <div className="field-row">
              <div className="field"><label>{t.contact.form.name}</label><input type="text" required /></div>
              <div className="field"><label>{t.contact.form.company}</label><input type="text" /></div>
            </div>
            <div className="field"><label>{t.contact.form.email}</label><input type="email" required /></div>
            <div className="field">
              <label>{t.contact.form.interest}</label>
              <select>{t.contact.form.options.map((o, i) => <option key={i}>{o}</option>)}</select>
            </div>
            <div className="field"><label>{t.contact.form.message}</label><textarea></textarea></div>
            <button className="btn btn-primary" type="submit">{t.contact.form.submit}<Icon name="arrow" w={16} cls="arrow" /></button>
            <p className="form-ok">{sent ? t.contact.form.ok : ""}</p>
            <p className="form-note">{t.contact.form.note}</p>
          </form>
        </div>
      </div>
    </section>
  );
}

/* ---------------- FOOTER ---------------- */
/* ---------------- Página "Próximamente" (Industrias / Herramientas) ---------------- */
function ComingSoon({ soon, data }) {
  return (
    <section className="band coming-soon">
      <div className="shell">
        <div className="sec-head center" data-reveal>
          <span className="eyebrow center">{soon.eyebrow}</span>
          <h2 className="display">{data.title}</h2>
          <p className="lead">{data.text}</p>
          <div className="coming-soon-actions">
            <a className="btn btn-primary" href="/#audit">{soon.cta}<Icon name="arrow" w={16} cls="arrow" /></a>
            <a className="hero-link" href="/">{soon.back}</a>
          </div>
        </div>
      </div>
    </section>
  );
}

function Footer({ t }) {
  return (
    <footer className="footer">
      <div className="shell">
        <div className="footer-mega" aria-hidden="true">1<span>·</span>A<span>·</span>1</div>
        <div className="footer-top">
          <div>
            <div className="brand">{BRAND}<span className="brand-sub"><span className="bs-name">{t.nav.sub}</span>{t.nav.subRole && <span className="bs-role">{t.nav.subRole}</span>}</span></div>
            <p className="footer-tag">{t.footer.tag}</p>
          </div>
          <div className="footer-cols">
            <div className="footer-col">
              <h4>{t.footer.colA.h}</h4>
              {t.footer.colA.links.map((l, i) => <a key={i} href="/#services">{l}</a>)}
            </div>
            <div className="footer-col">
              <h4>{t.footer.colB.h}</h4>
              {t.footer.colB.links.map((l, i) => <a key={i} href="/#contact">{l}</a>)}
            </div>
            <div className="footer-col">
              <h4>Directo</h4>
              <a href={WA_LINK} target="_blank" rel="noopener">WhatsApp</a>
              <a href={MAIL_LINK}>diego@1a1.mx</a>
            </div>
          </div>
        </div>
        <div className="footer-bottom">
          <span>{t.footer.rights}</span>
          <span className="footer-built">{t.footer.built}</span>
          <a className="totop" href="/#top" aria-label="Volver arriba"><Icon name="arrow-up" w={16} /></a>
        </div>
      </div>
    </footer>
  );
}

/* ---------------- FAB de chat (WhatsApp) ---------------- */
function ChatFab() {
  return (
    <a className="chat-fab" href={WA_LINK} target="_blank" rel="noopener" aria-label="WhatsApp">
      <Icon name="whatsapp" w={22} />
    </a>
  );
}

Object.assign(window, { Icon, Nav, Hero, Showcase, Why, Services, WebIndex, WebListIndex, Gallery, Audit, Contact, Footer, ChatFab });
