/* global React, window */
const { useEffect: V5useEffect, useRef: V5useRef, useState: V5useState } = React;

// =====================================================================
// Helper — split a string into <span class="v5-char"> per character.
// Renders inside a .v5-line wrapper; gets reveal class via IntersectionObserver
// (see V5SplitLine below).
// =====================================================================
window.V5Chars = function V5Chars({ text }) {
  // Split into tokens: words + whitespace. Each word is its own inline-block
  // so chars inside never break mid-word. Whitespace is emitted as plain
  // text so the browser collapses it at line breaks (no leading-space indent).
  const tokens = String(text).split(/(\s+)/);
  let charIdx = 0;
  const out = [];
  tokens.forEach((tok, ti) => {
    if (tok === "") return;
    if (/^\s+$/.test(tok)) {
      // Plain text space — wraps naturally and disappears at line breaks.
      out.push(tok);
      return;
    }
    const chars = [];
    for (let j = 0; j < tok.length; j++) {
      const c = tok[j];
      chars.push(
        <span
          key={`c-${ti}-${j}`}
          className="v5-char"
          style={{ transitionDelay: `${charIdx * 0.022}s` }}
        >{c}</span>
      );
      charIdx++;
    }
    out.push(
      <span key={`w-${ti}`} className="v5-word">{chars}</span>
    );
  });
  return React.Children.toArray(out);
};

// =====================================================================
// V5SplitLine — wraps text in <span class="v5-line"> with chars inside.
// IntersectionObserver toggles .is-in on the line.
// =====================================================================
window.V5SplitLine = function V5SplitLine({ children, delay = 0, as: Tag = "span", className = "", style }) {
  const ref = V5useRef(null);
  V5useEffect(() => {
    const el = ref.current; if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) {
          setTimeout(() => el.classList.add("is-in"), delay);
          // Unclip after entry animation completes so descenders are visible
          setTimeout(() => el.classList.add("is-done"), delay + 1600);
          io.unobserve(el);
        }
      });
    }, { threshold: 0.2 });
    io.observe(el);
    return () => io.disconnect();
  }, [delay]);
  return (
    <Tag ref={ref} className={`v5-line ${className}`} style={style}>
      {typeof children === "string" ? <window.V5Chars text={children} /> : children}
    </Tag>
  );
};

// =====================================================================
// V5WipeWord — outline → glauco fill + underline draw.
// =====================================================================
window.V5WipeWord = function V5WipeWord({ children }) {
  const ref = V5useRef(null);
  V5useEffect(() => {
    const el = ref.current; if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) {
          el.classList.add("is-in");
          io.unobserve(el);
        }
      });
    }, { threshold: 0.4 });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return (
    <span ref={ref} className="v5-wipe">
      {children}
      <span className="v5-wipe__rule" aria-hidden="true" />
    </span>
  );
};

// =====================================================================
// V5Section — wraps a section with the color-veil curtain transition.
// The veil runs once when the section first enters viewport.
// =====================================================================
window.V5Section = function V5Section({ tone = "accent", children, className = "", style, id }) {
  const ref = V5useRef(null);
  V5useEffect(() => {
    const el = ref.current; if (!el) return;
    // If user prefers reduced motion, just mark ready and skip animation
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
      el.classList.add("is-ready");
      return;
    }
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) {
          el.classList.add("is-running");
          io.unobserve(el);
        }
      });
    }, { threshold: 0.18, rootMargin: "0px 0px -10% 0px" });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  const toneCls = tone === "dark" ? "v5-section--dark"
    : tone === "mist" ? "v5-section--mist"
    : tone === "teal" ? "v5-section--teal"
    : "";
  return (
    <section id={id} ref={ref} className={`section v5-section ${toneCls} ${className}`} style={style}>
      <div className="v5-section__content">
        {children}
      </div>
    </section>
  );
};

// =====================================================================
// V5SectionHead — editorial section header (num + eyebrow / title)
// =====================================================================
window.V5SectionHead = function V5SectionHead({ num, eyebrow, title }) {
  return (
    <div className="v5-shead">
      <div className="v5-shead__left">
        {num && <div className="v5-shead__num">{num}</div>}
        <div className="v5-shead__eyebrow">{eyebrow}</div>
      </div>
      <h2 className="v5-shead__title">{title}</h2>
    </div>
  );
};

// =====================================================================
// HERO — cinematic, mask-wipe on key phrase
// =====================================================================
window.V5Hero = function V5Hero() {
  const { t } = window.useV4();
  const canvasRef = V5useRef(null);
  const heroRef = V5useRef(null);

  V5useEffect(() => {
    if (!canvasRef.current || !window.ParticleNet) return;
    const isMobile = window.matchMedia("(max-width: 720px)").matches;
    if (canvasRef.current) {
      // Lower opacity so the headline keeps visual priority while reading.
      // Mobile: even softer since the canvas is also more cramped.
      canvasRef.current.style.opacity = isMobile ? "0.18" : "0.55";
    }
    const net = window.ParticleNet({
      canvas: canvasRef.current,
      mode: "breath",
      density: 0.0036,    // ~2x base
      cap: 2200,
      edgeBias: 0.5,
      xRightBias: isMobile ? 0 : 0.7, // mobile: uniform distribution
      nodeSize: 1.82,
      silhouette: {
        src: "assets/icon-inteli-k.svg",
        size: isMobile ? 0.5 : 0.62,
        x: isMobile ? 0.5 : 0.72,     // mobile: centered
        y: 0.5,
      },
      // No auto-cycle: morph is driven by viewport visibility (below) so the
      // K forms once on first view and stays put while the hero is in frame.
      morphCycle: { formIn: 1800, formOut: 2200 },
    });

    // Drive morph from hero visibility + activity:
    //   visible + active     → K forms and HOLDS (breathing keeps it alive)
    //   visible + 60s idle   → K disperses; next mouse/scroll re-forms it
    //   leaves viewport      → K disperses
    let inView = false;
    let firstFormScheduled = false;
    let idleSeparated = false;
    let idleTimer = 0;

    const IDLE_MS = 60000;

    const formK = () => {
      idleSeparated = false;
      net.morphTo(1);
    };
    const armIdle = () => {
      if (idleTimer) clearTimeout(idleTimer);
      idleTimer = setTimeout(() => {
        if (inView) {
          idleSeparated = true;
          net.morphTo(0);
        }
      }, IDLE_MS);
    };
    const onActivity = () => {
      if (!inView) return;
      if (idleSeparated) formK();
      armIdle();
    };

    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        inView = e.isIntersecting;
        if (inView) {
          if (!firstFormScheduled) {
            firstFormScheduled = true;
            // Wait for the brand intro splash before the first form-in.
            // Intro now runs ~2.5s on first visit, and is skipped on
            // subsequent visits within the same session (v5-no-intro class).
            const introSkipped = document.documentElement.classList.contains("v5-no-intro");
            const delay = introSkipped ? 200 : 2700;
            setTimeout(() => { if (inView) { formK(); armIdle(); } }, delay);
          } else {
            formK();
            armIdle();
          }
        } else {
          if (idleTimer) { clearTimeout(idleTimer); idleTimer = 0; }
          idleSeparated = false;
          net.morphTo(0);
        }
      });
    }, { threshold: 0.25 });
    if (heroRef.current) io.observe(heroRef.current);

    window.addEventListener("mousemove", onActivity, { passive: true });
    window.addEventListener("scroll", onActivity, { passive: true });
    window.addEventListener("keydown", onActivity);
    window.addEventListener("touchstart", onActivity, { passive: true });

    return () => {
      io.disconnect();
      if (idleTimer) clearTimeout(idleTimer);
      window.removeEventListener("mousemove", onActivity);
      window.removeEventListener("scroll", onActivity);
      window.removeEventListener("keydown", onActivity);
      window.removeEventListener("touchstart", onActivity);
      net.dispose();
    };
  }, []);

  // Find a key phrase to wipe inside hero_t2 — for "con inteligencia artificial."
  // We hardcode the split: leading "con " + wipe word + trailing punctuation.
  // For EN: "with artificial intelligence." — leading "with " + wipe + "."
  const renderT2 = () => {
    const t2 = t.home.hero_t2;
    // Spanish path
    if (t2.toLowerCase().includes("inteligencia artificial")) {
      const idx = t2.toLowerCase().indexOf("inteligencia artificial");
      const before = t2.slice(0, idx);
      const phrase = t2.slice(idx, idx + "inteligencia artificial".length);
      const after = t2.slice(idx + "inteligencia artificial".length);
      return (
        <>
          {before}
          <window.V5WipeWord>{phrase}</window.V5WipeWord>
          <span style={{ color: "var(--accent)" }}>{after}</span>
        </>
      );
    }
    // English path
    if (t2.toLowerCase().includes("artificial intelligence")) {
      const idx = t2.toLowerCase().indexOf("artificial intelligence");
      const before = t2.slice(0, idx);
      const phrase = t2.slice(idx, idx + "artificial intelligence".length);
      const after = t2.slice(idx + "artificial intelligence".length);
      return (
        <>
          {before}
          <window.V5WipeWord>{phrase}</window.V5WipeWord>
          <span style={{ color: "var(--accent)" }}>{after}</span>
        </>
      );
    }
    return t2;
  };

  return (
    <section className="v5-hero" ref={heroRef}>
      <canvas
        ref={canvasRef}
        aria-hidden="true"
        style={{ position: "absolute", inset: 0, width: "100%", height: "100%", pointerEvents: "none", zIndex: 0 }}
      />
      <div className="wrap v5-hero__inner">
        <div data-reveal style={{ marginBottom: 48 }}>
          <div className="v5-hero__meta">
            <span className="v5-hero__meta-tick" />
            <span>{t.home.hero_eyebrow}</span>
          </div>
        </div>

        <h1 className="v5-h-display" style={{ marginBottom: 44 }}>
          <window.V5SplitLine delay={150}>{t.home.hero_t1}</window.V5SplitLine>
          <window.V5SplitLine delay={350} style={{ display: "block" }}>
            {renderT2()}
          </window.V5SplitLine>
          <window.V5SplitLine delay={700}>{t.home.hero_t3}</window.V5SplitLine>
        </h1>

        <p className="v5-lead" data-reveal style={{ marginBottom: 40 }}>
          {t.home.hero_lead}
        </p>

        <div data-reveal style={{ display: "flex", gap: 14, flexWrap: "wrap", marginBottom: 80 }}>
          <a href={window.IK_CALENDAR_URL} target="_blank" rel="noopener" className="btn btn-primary">
            {t.home.hero_cta1} <span className="arr">→</span>
          </a>
          <a href="servicios.html" className="btn btn-ghost">
            {t.home.hero_cta2}
          </a>
        </div>

        <div data-reveal style={{
          paddingTop: 28,
          borderTop: "1px solid var(--rule)",
          color: "var(--ink-mute)",
          fontSize: 13.5,
          fontFamily: "var(--font-mono)",
          letterSpacing: ".06em",
          textTransform: "uppercase",
        }}>
          {t.home.hero_proof}
        </div>
      </div>

      <div className="v5-hero__scroll" aria-hidden="true">
        <span>{t.common.scroll}</span>
        <span className="v5-hero__scroll-arrow" />
      </div>
    </section>
  );
};

// =====================================================================
// PROBLEM — 3 cards, calm
// =====================================================================
window.V5Problem = function V5Problem() {
  const { t } = window.useV4();
  return (
    <window.V5Section tone="mist" style={{ background: "var(--bg-2)" }}>
      <div className="wrap">
        <window.V5SectionHead
          num={"01 / " + t.home.sec_context}
          eyebrow={t.home.problem_eyebrow}
          title={t.home.problem_title}
        />
        <div data-stagger className="v5-problem-grid">
          {[1,2,3].map((i) => (
            <div key={i} className="card-lift v5-problem-card">
              <div style={{
                fontFamily: "var(--font-mono)",
                fontSize: 12,
                color: "var(--ink-mute)",
                letterSpacing: ".14em",
                marginBottom: 22,
              }}>0{i}</div>
              <h3 className="h-card">{t.home["problem_p"+i+"t"]}</h3>
              <p style={{ color: "var(--ink-soft)", margin: 0, fontSize: 15.5, lineHeight: 1.6 }}>{t.home["problem_p"+i+"d"]}</p>
            </div>
          ))}
        </div>
      </div>
    </window.V5Section>
  );
};

// =====================================================================
// HELP — services preview rows with editorial hover
// =====================================================================
window.V5Help = function V5Help() {
  const { t } = window.useV4();
  return (
    <window.V5Section tone="accent">
      <div className="wrap">
        <window.V5SectionHead
          num={"02 / " + t.home.sec_services}
          eyebrow={t.home.help_eyebrow}
          title={t.home.help_title}
        />
        <div data-stagger className="v5-help-list">
          {[1,2,3,4].map((i) => (
            <a key={i} href={"servicios.html#s"+i} className="v5-help-row">
              <div className="v5-help-row__num">{t.home["help_s"+i+"n"]}</div>
              <h3 className="v5-help-row__title">{t.home["help_s"+i+"t"]}</h3>
              <p className="v5-help-row__desc">{t.home["help_s"+i+"d"]}</p>
              <div className="v5-help-row__arrow">↗</div>
            </a>
          ))}
        </div>
        <div data-reveal style={{ marginTop: 48 }}>
          <a href="servicios.html" className="btn btn-ghost">{t.home.help_cta} <span className="arr">→</span></a>
        </div>
      </div>
    </window.V5Section>
  );
};

// =====================================================================
// WHY — dark editorial slab, 3 reasons in a column-rule grid
// =====================================================================
window.V5Why = function V5Why() {
  const { t } = window.useV4();
  return (
    <window.V5Section tone="dark" style={{ background: "var(--invert-bg)", color: "var(--invert-ink)" }}>
      <div className="wrap">
        <div className="v5-shead" style={{ borderBottom: "1px solid rgba(255,255,255,.14)" }}>
          <div className="v5-shead__left">
            <div className="v5-shead__num" style={{ color: "rgba(255,255,255,.55)" }}>{"03 / " + t.home.sec_why}</div>
            <div className="v5-shead__eyebrow" style={{ color: "rgba(255,255,255,.72)" }}>{t.home.why_eyebrow}</div>
          </div>
          <h2 className="v5-shead__title">{t.home.why_title}</h2>
        </div>
        <p data-reveal style={{
          fontSize: "clamp(17px, 1.4vw, 21px)",
          lineHeight: 1.55,
          color: "rgba(255,255,255,.72)",
          maxWidth: "62ch",
          margin: "-32px 0 64px",
          textWrap: "pretty",
        }}>
          {t.home.why_lead}
        </p>
        <div data-stagger className="v5-why-grid">
          {[1,2,3,4].map((i) => (
            <div key={i} className="v5-why-cell">
              <div style={{
                fontFamily: "var(--font-mono)",
                fontSize: 12,
                color: "rgba(255,255,255,.5)",
                letterSpacing: ".14em",
                marginBottom: 22,
              }}>0{i}</div>
              <div style={{
                width: 28, height: 3,
                background: "var(--accent)",
                marginBottom: 22,
              }} />
              <h3 className="h-card" style={{ color: "var(--invert-ink)", marginBottom: 12 }}>
                {t.home["why_p"+i+"t"]}
              </h3>
              <p style={{
                color: "rgba(255,255,255,.66)",
                margin: 0,
                fontSize: 15.5,
                lineHeight: 1.6,
              }}>
                {t.home["why_p"+i+"d"]}
              </p>
            </div>
          ))}
        </div>
      </div>
    </window.V5Section>
  );
};

// =====================================================================
// PROCESS — 4-step "Cómo trabajamos" + supporting metrics
// Sits between Why and Platforms; gets the soft teal tone to break the
// pale-on-pale rhythm of the surrounding sections.
// =====================================================================
window.V5Process = function V5Process() {
  const { t } = window.useV4();
  const steps = [1, 2, 3, 4].map((i) => ({
    n: t.home["proc_s" + i + "n"],
    t: t.home["proc_s" + i + "t"],
    d: t.home["proc_s" + i + "d"],
  }));
  const metrics = [
    { n: t.home.proc_m1n, l: t.home.proc_m1l },
    { n: t.home.proc_m2n, l: t.home.proc_m2l },
    { n: t.home.proc_m3n, l: t.home.proc_m3l },
  ];
  return (
    <window.V5Section tone="teal" style={{ background: "var(--bg-teal)" }}>
      <div className="wrap">
        <window.V5SectionHead
          num={"04 / " + t.home.sec_process}
          eyebrow={t.home.proc_eyebrow}
          title={t.home.proc_title}
        />
        <p data-reveal className="v5-process-lead">{t.home.proc_lead}</p>
        <div data-stagger className="v5-process-grid">
          {steps.map((s, i) => (
            <div key={i} className="v5-process-step">
              <div className="v5-process-step__rule" aria-hidden="true">
                <span className="v5-process-step__dot" />
              </div>
              <div className="v5-process-step__num">{s.n}</div>
              <h3 className="v5-process-step__title">{s.t}</h3>
              <p className="v5-process-step__desc">{s.d}</p>
            </div>
          ))}
        </div>
        <div data-stagger className="v5-process-metrics">
          {metrics.map((m, i) => (
            <div key={i} className="v5-process-metric">
              <div className="v5-process-metric__n">{m.n}</div>
              <div className="v5-process-metric__l">{m.l}</div>
            </div>
          ))}
        </div>
      </div>
    </window.V5Section>
  );
};

// =====================================================================
// PLATFORMS — 4-up detail grid. Each card reveals its specific
// capabilities on hover/focus so the section earns its slot instead of
// scrolling 4 logos past at speed.
// =====================================================================
window.V5Platforms = function V5Platforms() {
  const { t } = window.useV4();
  const items = [
    { name: t.home.platforms_p1, tag: t.home.platforms_p1t, logo: "assets/partner-monday.svg", alt: "monday.com",
      caps: [t.home.platforms_p1c1, t.home.platforms_p1c2, t.home.platforms_p1c3] },
    { name: t.home.platforms_p2, tag: t.home.platforms_p2t, logo: "assets/partner-freshworks.svg", alt: "Freshworks",
      caps: [t.home.platforms_p2c1, t.home.platforms_p2c2, t.home.platforms_p2c3] },
    { name: t.home.platforms_p3, tag: t.home.platforms_p3t, logo: "assets/partner-aircall.svg", alt: "Aircall",
      caps: [t.home.platforms_p3c1, t.home.platforms_p3c2, t.home.platforms_p3c3] },
    { name: t.home.platforms_p4, tag: t.home.platforms_p4t, logo: "assets/partner-make.svg", alt: "Make",
      caps: [t.home.platforms_p4c1, t.home.platforms_p4c2, t.home.platforms_p4c3] },
  ];
  return (
    <window.V5Section tone="accent">
      <div className="wrap">
        <window.V5SectionHead
          num={"05 / " + t.home.sec_platforms}
          eyebrow={t.home.platforms_eyebrow}
          title={t.home.platforms_title}
        />
        <div data-stagger className="v5-plat-grid">
          {items.map((it, i) => (
            <a key={i} href="plataformas.html" className="v5-plat-card">
              <div className="v5-plat-card__head">
                <img className="v5-plat-card__logo" src={it.logo} alt={it.alt} />
              </div>
              <div className="v5-plat-card__tag">{it.tag}</div>
              <div className="v5-plat-card__caps-label">Lo que activamos</div>
              <ul className="v5-plat-card__caps">
                {it.caps.map((c, j) => (
                  <li key={j} style={{ transitionDelay: `${j * 0.06}s` }}>
                    <span className="v5-plat-card__caps-mark" aria-hidden="true" />
                    <span>{c}</span>
                  </li>
                ))}
              </ul>
              <div className="v5-plat-card__arrow" aria-hidden="true">↗</div>
            </a>
          ))}
        </div>
      </div>
    </window.V5Section>
  );
};

// =====================================================================
// PROOF — testimonial carousel + metrics
// Subtle cross-fade between 4 real testimonials. Auto-advance every 7s,
// pause on hover, click dots / arrows to jump. Quote-log style: a small
// counter "01 / 04" anchors the cadence; the active card cross-fades.
// =====================================================================
window.V5Proof = function V5Proof() {
  const { t } = window.useV4();
  const quotes = [1,2,3,4].map((i) => ({
    q: t.home["proof_q"+i],
    n: t.home["proof_a"+i+"n"],
    r: t.home["proof_a"+i+"r"],
  })).filter(x => x.q);

  const [idx, setIdx] = V5useState(0);
  const [paused, setPaused] = V5useState(false);
  const carRef = V5useRef(null);

  // Auto-advance every 7s unless paused (hover) or reduced motion.
  V5useEffect(() => {
    if (paused) return;
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
    if (quotes.length <= 1) return;
    const id = setInterval(() => {
      setIdx((i) => (i + 1) % quotes.length);
    }, 7000);
    return () => clearInterval(id);
  }, [paused, quotes.length]);

  // Initials for the avatar circle. For single-word company names
  // (e.g. "ILSSG", "Travelling") fall back to the first two letters
  // so the avatar never collapses to a single glyph.
  const initials = (name) => {
    const raw = String(name || "").trim();
    const parts = raw.split(/\s+/);
    if (parts.length > 1) {
      const a = parts[0]?.[0] || "";
      const b = parts[parts.length - 1]?.[0] || "";
      return (a + b).toUpperCase();
    }
    return raw.slice(0, 2).toUpperCase();
  };

  const pad2 = (n) => String(n).padStart(2, "0");
  const active = quotes[idx] || quotes[0];

  return (
    <window.V5Section tone="mist" style={{ background: "var(--bg-2)" }} id="proof">
      <div className="wrap">
        <window.V5SectionHead
          num={"06 / " + t.home.sec_results}
          eyebrow={t.home.proof_eyebrow}
          title={t.home.proof_title}
        />

        <div
          data-reveal
          ref={carRef}
          className="v5-proof-car"
          onMouseEnter={() => setPaused(true)}
          onMouseLeave={() => setPaused(false)}
          style={{
            background: "var(--bg-2)",
            border: "1px solid var(--rule)",
            borderRadius: "var(--r-xl)",
            padding: "clamp(40px, 6vw, 72px)",
            position: "relative",
          }}
        >
          {/* Top meta row: counter + dots */}
          <div style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "space-between",
            marginBottom: 28,
            paddingBottom: 22,
            borderBottom: "1px solid var(--rule)",
            fontFamily: "var(--font-mono)",
            fontSize: 12,
            letterSpacing: ".14em",
            textTransform: "uppercase",
            color: "var(--ink-mute)",
          }}>
            <div>
              <span style={{ color: "var(--ink)" }}>{pad2(idx + 1)}</span>
              <span style={{ margin: "0 8px", opacity: .5 }}>/</span>
              <span>{pad2(quotes.length)}</span>
              <span style={{ marginLeft: 14, color: "var(--ink-mute)" }}>· {t.home.sec_testimonials}</span>
            </div>
            <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
              {quotes.map((_, i) => (
                <button
                  key={i}
                  type="button"
                  aria-label={t.common.view_testimonial + " " + (i+1)}
                  onClick={() => setIdx(i)}
                  className="v5-proof-dot"
                  data-active={i === idx ? "true" : "false"}
                />
              ))}
            </div>
          </div>

          {/* Stacked slides; only active is visible */}
          <div className="v5-proof-stack" aria-live="polite">
            {quotes.map((it, i) => (
              <div
                key={i}
                className={"v5-proof-slide" + (i === idx ? " is-active" : "")}
                aria-hidden={i === idx ? "false" : "true"}
              >
                <p style={{
                  fontFamily: "var(--font-display)",
                  fontSize: "clamp(20px, 2vw, 28px)",
                  lineHeight: 1.4,
                  letterSpacing: "-0.012em",
                  color: "var(--ink)",
                  margin: "0 0 36px",
                  fontWeight: 500,
                  textWrap: "pretty",
                  maxWidth: "44ch",
                }}>
                  "{it.q}"
                </p>
                <div style={{ display: "flex", gap: 16, alignItems: "center", paddingTop: 28, borderTop: "1px solid var(--rule)" }}>
                  <div style={{
                    width: 48, height: 48, borderRadius: "50%",
                    background: "var(--accent)",
                    display: "grid", placeItems: "center",
                    fontWeight: 600, color: "var(--ink)",
                    fontSize: 15,
                    letterSpacing: ".02em",
                  }}>{initials(it.n)}</div>
                  <div>
                    <div style={{ fontWeight: 500, fontSize: 15.5 }}>{it.n}</div>
                    {it.r ? <div style={{ color: "var(--ink-mute)", fontSize: 13.5 }}>{it.r}</div> : null}
                  </div>
                </div>
              </div>
            ))}
          </div>

          {/* Prev / Next */}
          <div style={{
            position: "absolute",
            right: "clamp(20px, 3vw, 36px)",
            bottom: "clamp(20px, 3vw, 36px)",
            display: "flex",
            gap: 8,
          }}>
            <button
              type="button"
              aria-label={t.common.prev}
              className="v5-proof-nav"
              onClick={() => setIdx((i) => (i - 1 + quotes.length) % quotes.length)}
            >←</button>
            <button
              type="button"
              aria-label={t.common.next}
              className="v5-proof-nav"
              onClick={() => setIdx((i) => (i + 1) % quotes.length)}
            >→</button>
          </div>
        </div>

        <div data-stagger style={{
          display: "grid",
          gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))",
          gap: 0,
          marginTop: 64,
          borderTop: "1px solid var(--rule)",
        }}>
          {[
            { n: t.home.proof_m1n, l: t.home.proof_m1l },
            { n: t.home.proof_m2n, l: t.home.proof_m2l },
            { n: t.home.proof_m3n, l: t.home.proof_m3l },
          ].map((m, i, arr) => (
            <div key={i} style={{
              padding: "40px 28px 40px 0",
              borderRight: i < arr.length - 1 ? "1px solid var(--rule)" : "none",
            }}>
              <div className="h-display" style={{ fontSize: "clamp(36px, 4.4vw, 60px)", marginBottom: 8, color: "var(--accent)" }}>{m.n}</div>
              <div style={{ color: "var(--ink-soft)", fontSize: 14.5 }}>{m.l}</div>
            </div>
          ))}
        </div>
      </div>
    </window.V5Section>
  );
};

// =====================================================================
// FAQ — accordion of 6 Q&A. Plain semantic HTML (<details>/<summary>)
// so AI crawlers can extract Q&A pairs cleanly. Mirrors the FAQPage
// schema in <head>.
// =====================================================================
window.V5FAQ = function V5FAQ() {
  const { t } = window.useV4();
  const items = [1, 2, 3, 4, 5, 6].map((i) => ({
    q: t.home["faq_q" + i],
    a: t.home["faq_a" + i],
  })).filter(x => x.q && x.a);
  return (
    <window.V5Section tone="accent" id="faq">
      <div className="wrap">
        <window.V5SectionHead
          num={"07 / " + t.home.sec_faq}
          eyebrow={t.home.faq_eyebrow}
          title={t.home.faq_title}
        />
        <div data-stagger className="v5-faq-list" itemScope itemType="https://schema.org/FAQPage">
          {items.map((it, i) => (
            <details
              key={i}
              className="v5-faq-item"
              itemScope
              itemProp="mainEntity"
              itemType="https://schema.org/Question"
            >
              <summary className="v5-faq-q">
                <span className="v5-faq-q-num">{String(i + 1).padStart(2, "0")}</span>
                <span className="v5-faq-q-text" itemProp="name">{it.q}</span>
                <span className="v5-faq-q-icon" aria-hidden="true">
                  <span className="v5-faq-q-icon-h" />
                  <span className="v5-faq-q-icon-v" />
                </span>
              </summary>
              <div
                className="v5-faq-a"
                itemScope
                itemProp="acceptedAnswer"
                itemType="https://schema.org/Answer"
              >
                <p itemProp="text">{it.a}</p>
              </div>
            </details>
          ))}
        </div>
      </div>
    </window.V5Section>
  );
};
window.V5CTA = function V5CTA() {
  const { t } = window.useV4();
  const starCanvasRef = V5useRef(null);
  const ctaSectionRef = V5useRef(null);

  // ---- Constelación quieta — eco silencioso del hero.
  // Partículas dispersas que respiran ligeramente, sin formar logo.
  V5useEffect(() => {
    const canvas = starCanvasRef.current;
    if (!canvas) return;

    // Reduced motion: draw one still frame and bail — calm sky, no animation.
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
      const ctxs = canvas.getContext("2d");
      const dpr2 = Math.min(2, window.devicePixelRatio || 1);
      const rect = canvas.getBoundingClientRect();
      const ww = rect.width, hh = rect.height;
      if (ww > 0 && hh > 0) {
        canvas.width = Math.round(ww * dpr2);
        canvas.height = Math.round(hh * dpr2);
        ctxs.setTransform(dpr2, 0, 0, dpr2, 0, 0);
        const isMobile = window.matchMedia("(max-width: 720px)").matches;
        const target = Math.max(28, Math.min(isMobile ? 48 : 110, Math.round((ww * hh) / 14000)));
        for (let i = 0; i < target; i++) {
          const accent = Math.random() < 0.22;
          const a = 0.12 + Math.random() * 0.28;
          ctxs.beginPath();
          ctxs.fillStyle = accent ? `rgba(150, 195, 210, ${a})` : `rgba(225, 232, 240, ${a})`;
          ctxs.arc(Math.random() * ww, Math.random() * hh, 0.6 + Math.random() * 1.4, 0, Math.PI * 2);
          ctxs.fill();
        }
      }
      return;
    }

    const ctx = canvas.getContext("2d");
    const dpr = Math.min(2, window.devicePixelRatio || 1);
    let w = 0, h = 0;
    let stars = [];
    let raf = 0;
    let visible = false;
    const t0 = performance.now();

    function seed() {
      const isMobile = window.matchMedia("(max-width: 720px)").matches;
      // density per 1000px²: very sparse
      const target = Math.max(28, Math.min(isMobile ? 48 : 110, Math.round((w * h) / 14000)));
      stars = new Array(target);
      for (let i = 0; i < target; i++) {
        // ~20% pick up a hint of brand accent (glauco); rest stay pale white
        const accent = Math.random() < 0.22;
        stars[i] = {
          ox: Math.random() * w,           // home position
          oy: Math.random() * h,
          r: 0.55 + Math.random() * 1.45,
          phase: Math.random() * Math.PI * 2,
          // breath rate — slow, varied. Full cycle ~5–11s.
          speed: 0.55 + Math.random() * 0.65,
          baseAlpha: 0.10 + Math.random() * 0.34,
          // drift amplitude in px — each star sways gently around its home.
          driftX: 4 + Math.random() * 14,
          driftY: 3 + Math.random() * 10,
          // slow lateral wander phase, independent from the breath phase
          driftPhaseX: Math.random() * Math.PI * 2,
          driftPhaseY: Math.random() * Math.PI * 2,
          driftSpeedX: 0.10 + Math.random() * 0.22,
          driftSpeedY: 0.08 + Math.random() * 0.18,
          accent,
        };
      }
    }

    function resize() {
      const rect = canvas.getBoundingClientRect();
      w = rect.width; h = rect.height;
      if (w === 0 || h === 0) return;
      canvas.width = Math.round(w * dpr);
      canvas.height = Math.round(h * dpr);
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      seed();
    }

    function draw() {
      raf = requestAnimationFrame(draw);
      if (!visible || w === 0 || h === 0) return;
      const time = (performance.now() - t0) / 1000;
      ctx.clearRect(0, 0, w, h);
      for (let i = 0; i < stars.length; i++) {
        const s = stars[i];
        // breath: smooth 0..1 sine — deeper modulation so it visibly inhales/exhales
        const breath = Math.sin(time * s.speed + s.phase) * 0.5 + 0.5;
        const alpha = s.baseAlpha * (0.25 + breath * 1.05);
        const radius = s.r * (0.70 + breath * 0.65);
        // slow positional sway — chest rising/falling, not just brightness pulse
        const x = s.ox + Math.sin(time * s.driftSpeedX + s.driftPhaseX) * s.driftX;
        const y = s.oy + Math.sin(time * s.driftSpeedY + s.driftPhaseY) * s.driftY;
        ctx.beginPath();
        ctx.fillStyle = s.accent
          ? `rgba(150, 195, 210, ${alpha})`   // glauco hint
          : `rgba(225, 232, 240, ${alpha})`;  // pale white
        ctx.arc(x, y, radius, 0, Math.PI * 2);
        ctx.fill();
      }
    }

    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => { visible = e.isIntersecting; });
    }, { threshold: 0 });
    if (ctaSectionRef.current) io.observe(ctaSectionRef.current);

    const ro = new ResizeObserver(resize);
    ro.observe(canvas);

    resize();
    raf = requestAnimationFrame(draw);

    return () => {
      io.disconnect();
      ro.disconnect();
      cancelAnimationFrame(raf);
    };
  }, []);

  return (
    <window.V5Section tone="dark" className="v5-cta" id="contact">
      <div className="v5-cta__bg" aria-hidden="true" ref={ctaSectionRef}>
        <canvas ref={starCanvasRef} className="v5-cta__stars" />
        <img src="assets/icon-inteli-k-white.svg" alt="" className="v5-cta__mark" />
      </div>
      <div className="wrap v5-cta__inner">
        <h2 data-reveal>
          {t.home.cta_t1} <span style={{ color: "rgba(255,255,255,.4)" }}>{t.home.cta_t2}</span> <span style={{ color: "var(--accent)" }}>{t.home.cta_t3}</span>
        </h2>
        <div data-reveal style={{ display: "flex", flexDirection: "column", gap: 18, alignItems: "flex-start" }}>
          <a href={window.IK_CALENDAR_URL} target="_blank" rel="noopener" className="btn btn-accent btn--xl">{t.home.cta_cta} <span className="arr">→</span></a>
          <p style={{ color: "rgba(255,255,255,.55)", margin: 0, fontSize: 14.5 }}>{t.home.cta_foot}</p>
        </div>
      </div>
    </window.V5Section>
  );
};

// =====================================================================
// PAGE composer
// =====================================================================
window.V5HomePage = function V5HomePage() {
  window.useReveal();
  return (
    <React.Fragment>
      <window.V4Nav active="home" />
      <window.V5Hero />
      <window.V5Problem />
      <window.V5Help />
      <window.V5Why />
      <window.V5Process />
      <window.V5Platforms />
      <window.V5Proof />
      <window.V5FAQ />
      <window.V5CTA />
      <window.V5Contact />
      <window.V4Footer />
    </React.Fragment>
  );
};
