/* =========================================================
   Tools / Toolkit — INTEGRATION (marquee)
   Two infinite marquee rows of brand tool tiles + a centered
   eyebrow badge, title and subtitle below.
   Logos are pulled from Simple Icons CDN and theme-tinted
   via CSS `filter`. Light / Dark via [data-theme="dark"].
   ========================================================= */

/* ---------- Logo set ----------
   Each entry maps a display name to a Simple Icons slug
   (https://cdn.simpleicons.org/<slug>/000000 — forced black
   so our `filter: invert(...)` tints them as neutral greys).

   `inline` is an optional local fallback for brands Simple
   Icons no longer publishes (Adobe was pulled from their
   catalogue — likely a brand-legal request). The fallback
   is a generic monochrome glyph and uses the same `.frt-logo`
   filter pipeline as the CDN images. */
const AdobeMark = () => (
  <svg className="frt-logo" viewBox="0 0 32 32" width="32" height="32"
       aria-hidden="true" fill="#000">
    {/* Adobe corporate "A" — stylized triangle with crossbar cutout.
        Public-domain geometry; tinted by `.frt-logo` filter like the rest. */}
    <path fillRule="evenodd" clipRule="evenodd"
          d="M16 4
             L29 28
             H20.4
             L18.2 23.4
             H13.8
             L11.6 28
             H3
             L16 4 Z
             M16 13.6
             L13.2 19.2
             H18.8
             L16 13.6 Z"/>
  </svg>
);

/* Claude — user-supplied brand mark. Drawn in solid black so the same
   `.frt-logo` filter pipeline (invert 0.4 light / 0.7 dark) tints it to
   the neutral grey shared with every other tool tile. The `viewBox="0 0 24 24"`
   matches the source SVG; sizing is handled by `.frt-logo` (32×32). */
const ClaudeMark = () => (
  <svg className="frt-logo" viewBox="0 0 24 24" width="32" height="32"
       aria-hidden="true" fill="#000">
    <path fillRule="nonzero"
          d="M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z"/>
  </svg>
);

const TOOL_LOGOS = [
  /* Row 1 — scrolls left */
  { n: "Figma",     slug: "figma" },
  { n: "Webflow",   slug: "webflow" },
  { n: "WordPress", slug: "wordpress" },
  { n: "Framer",    slug: "framer" },
  { n: "Google",    slug: "google" },
  { n: "Make",      slug: "make" },
  /* Row 2 — scrolls right */
  { n: "n8n",       slug: "n8n" },
  { n: "Elementor", slug: "elementor" },
  { n: "Zapier",    slug: "zapier" },
  { n: "Stripe",    slug: "stripe" },
  { n: "Claude",    inline: ClaudeMark },
  { n: "DaVinci",   slug: "davinciresolve" },
];

/* ---------- Styles (scoped with frt- prefix) ---------- */
const STYLE = `
.frt-section {
  position: relative;
  background: var(--bg);
  padding: clamp(72px, 9vw, 128px) 0;
}
[data-theme="dark"] .frt-section { background: var(--bg); }

.frt-marquee {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: center;
}
/* Central light bleed — a soft elliptical highlight behind both rows so
   the tiles in the middle pick up a hint of glow while the ones near
   the edges sit in shadow. Sits above the tiles (z-index 2) but is
   purely decorative.

   Width is clamped to the same envelope as .frt-row (5 tiles + 4 gaps)
   and the same edge mask is applied so the glow fades cleanly to the
   section background instead of bleeding out as a wide oval halo.
   mix-blend-mode: overlay keeps the effect concentrated on the tile
   surfaces (light pixels) and not the surrounding section colour. */
.frt-marquee::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: calc(5 * 84px + 4 * 14px);
  pointer-events: none;
  z-index: 2;
  background: radial-gradient(ellipse 40% 80% at 50% 50%, rgba(0,0,0,0.05) 0%, transparent 70%);
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 12%, #000 88%, transparent 100%);
          mask-image: linear-gradient(to right, transparent 0%, #000 12%, #000 88%, transparent 100%);
  mix-blend-mode: multiply;
}
[data-theme="dark"] .frt-marquee::after {
  background: radial-gradient(ellipse 40% 80% at 50% 50%, rgba(255,255,255,0.18) 0%, transparent 70%);
  mix-blend-mode: overlay;
}

.frt-row {
  width: 100%;
  /* On wider screens cap the row at exactly 5 tiles + 4 gaps so the
     marquee is the same crisp size everywhere it has room. On narrow
     viewports the row collapses to 100% of available width so the
     left/right mask fades (and the bg-coloured ::before/::after
     overlays) align with the visible edges instead of falling off
     screen — otherwise the right side cuts hard while the left
     looks soft. */
  max-width: calc(5 * 84px + 4 * 14px);
  overflow: hidden;
  margin: 0 auto;
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 12%, #000 88%, transparent 100%);
          mask-image: linear-gradient(to right, transparent 0%, #000 12%, #000 88%, transparent 100%);
  position: relative;
}
/* Side fade backstop — solid background gradient on top of the masked
   strip so the edge fades to the section color even where mask-image is fuzzy. */
.frt-row::before,
.frt-row::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 56px;
  pointer-events: none;
  z-index: 2;
}
.frt-row::before {
  left: 0;
  background: linear-gradient(to right, #f5f2ec 0%, rgba(245, 242, 236, 0) 100%);
}
.frt-row::after {
  right: 0;
  background: linear-gradient(to left, #f5f2ec 0%, rgba(245, 242, 236, 0) 100%);
}
[data-theme="dark"] .frt-row::before {
  background: linear-gradient(to right, #14130f 0%, rgba(20,19,15,0) 100%);
}
[data-theme="dark"] .frt-row::after {
  background: linear-gradient(to left, #14130f 0%, rgba(20,19,15,0) 100%);
}

.frt-track {
  display: flex;
  gap: 14px;
  width: max-content;
  will-change: transform;
}
.frt-track-1 {
  animation: frt-scroll-left 26s linear infinite;
}
.frt-track-2 {
  animation: frt-scroll-right 30s linear infinite;
}

@keyframes frt-scroll-left {
  from { transform: translateX(0); }
  to   { transform: translateX(calc(-6 * 98px)); }
}
@keyframes frt-scroll-right {
  from { transform: translateX(calc(-6 * 98px)); }
  to   { transform: translateX(0); }
}

.frt-tile {
  flex: 0 0 84px;
  width: 84px;
  height: 84px;
  border-radius: 18px;
  background: var(--surface);
  border: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background .25s ease, border-color .25s ease;
}
[data-theme="dark"] .frt-tile {
  background: #18181a;
  border: 1px solid rgba(255, 255, 255, 0.06);
}

/* Brand logo image — Simple Icons returns a solid-black SVG.
   We tint it via filter (grey on light, lighter grey on dark)
   and shift to the accent terracotta on hover. */
.frt-logo {
  width: 32px;
  height: 32px;
  display: block;
  filter: invert(0.4);
  transition: filter 0.3s ease;
}
[data-theme="dark"] .frt-logo {
  filter: invert(0.7);
}
.frt-tile:hover .frt-logo {
  /* Approximates #e8624a via hue rotation from black source */
  filter: invert(0) sepia(1) saturate(2) hue-rotate(340deg);
}

.frt-content {
  margin-top: clamp(40px, 5vw, 64px);
  text-align: center;
  padding: 0 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}

.frt-badge {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding: 7px 14px;
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-mute);
  border: 1px solid var(--line);
  cursor: pointer;
  user-select: none;
  transition: all 0.25s ease;
}
.frt-badge:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(232, 98, 74, 0.28);
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
[data-theme="dark"] .frt-badge {
  background: #1a1a1a;
  color: #f3ede2;
  border-color: rgba(255, 255, 255, 0.06);
}
[data-theme="dark"] .frt-badge:hover {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
  box-shadow: 0 6px 20px rgba(232, 98, 74, 0.45);
}

.frt-title {
  font-family: var(--font-display);
  font-size: clamp(40px, 5.5vw, 72px);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.025em;
  color: var(--text);
  margin: 0;
  text-wrap: balance;
  /* Wrap whole words to the next line, never split mid-word. */
  word-break: normal;
  overflow-wrap: break-word;
  hyphens: none;
}
[data-theme="dark"] .frt-title { color: #f3ede2; }

/* Word groups — each word's letters live inside a .frt-title-word
   that never breaks internally. Real spaces between word groups are the
   only line-break opportunities, so the title can never split mid-word
   (the previous nbsp-everywhere render forced the browser to break
   mid-word at overflow). */
.frt-title-word {
  display: inline-block;
  white-space: nowrap;
}

/* Title "decode" animation — each letter renders as a span. While the
   letter is still scrambling it carries no .resolved class and is tinted
   with the accent color. When it locks onto its target char the class is
   added and the color transitions back to the title color (0.15s).
   The actual character switching is driven from JS (refs + setInterval). */
.frt-title-letter {
  display: inline-block;
  color: var(--accent);
  transition: color 0.15s ease;
}
.frt-title-letter.resolved {
  color: inherit;
}

.frt-sub {
  max-width: 52ch;
  margin: 0;
  font-size: clamp(15px, 1.15vw, 18px);
  line-height: 1.55;
  color: var(--text-2);
  text-wrap: pretty;
}
[data-theme="dark"] .frt-sub { color: #9b9a96; }

@media (prefers-reduced-motion: reduce) {
  .frt-track-1, .frt-track-2 { animation: none; }
}

/* Mobile tweaks — symmetric side fade + title scaled to match the
   neighbouring section headlines (.pricing-head h2 in particular)
   so the toolkit title doesn't read as a smaller sibling. */
@media (max-width: 600px) {
  .frt-row {
    -webkit-mask-image: linear-gradient(to right, transparent 0%, black 15%, black 85%, transparent 100%);
            mask-image: linear-gradient(to right, transparent 0%, black 15%, black 85%, transparent 100%);
  }
  .frt-title {
    font-size: clamp(32px, 8vw, 48px);
  }
}
`;

/* ---------- INTEGRATION section ---------- */
const { useRef: useRefTT, useEffect: useEffectTT, useState: useStateTT } = React;

/* Pool of glyphs the title shuffles through during the decode animation. */
const SCRAMBLE_CHARS = "0123456789#@$%&*!?ABCDEFabcdef";
const randomScrambleChar = () =>
  SCRAMBLE_CHARS.charAt(Math.floor(Math.random() * SCRAMBLE_CHARS.length));

/* Phrases the badge cycles through on click. Index 0 mirrors `t.tech.title`
   (the default copy). 1–5 are rotated random-no-repeat, then 6 (the “extra”),
   then the pool resets. Lang detection prefers `window.__lang__` and falls
   back to `<html lang>`. */
const TITLE_PHRASES = {
  en: [
    "Connected systems, not more tools.",
    "Automate once. Work less forever.",
    "Your site works. Even while you sleep.",
    "Design that converts. Systems that scale.",
    "From idea to client in less time.",
    "Fewer tools. Better results.",
    "Still clicking? We've run out of ideas.",
  ],
  de: [
    "Verbundene Systeme, nicht mehr Tools.",
    "Einmal einrichten. Für immer sparen.",
    "Deine Site arbeitet. Auch wenn du schläfst.",
    "Design das konvertiert. Systeme die skalieren.",
    "Von der Idee zum Kunden in weniger Zeit.",
    "Weniger Tools. Bessere Ergebnisse.",
    "Noch am Klicken? Uns sind die Ideen ausgegangen.",
  ],
  es: [
    "Sistemas que trabajan. Resultados que se ven.",
    "Automatiza una vez. Trabaja menos siempre.",
    "Tu web no es un folleto. Es tu presencia digital.",
    "Diseño que convierte. Sistemas que escalan.",
    "De la idea al cliente en menos tiempo.",
    "Menos herramientas. Más resultados.",
    "¿Sigues pulsando? Se nos han acabado las ideas.",
  ],
};

/* Resolve the active language at the moment of the click — NOT at mount.
   Priority (first non-empty wins):
     1. window.__lang__
     2. <html lang="…"> attribute
     3. document.documentElement.lang property
     4. fallback 'en'
   The result is lowercased, trimmed, and truncated to 2 chars so values
   like 'es-ES', 'en-US', 'de-DE' all normalise correctly. */
function getActiveLang() {
  try {
    const candidates = [
      typeof window !== "undefined" ? window.__lang__ : null,
      typeof document !== "undefined"
        ? document.documentElement.getAttribute("lang")
        : null,
      typeof document !== "undefined" ? document.documentElement.lang : null,
      "en",
    ];
    for (const v of candidates) {
      if (v == null) continue;
      const s = String(v).toLowerCase().trim();
      if (!s) continue;
      return s.slice(0, 2);
    }
    return "en";
  } catch (e) {
    return "en";
  }
}

function shuffleInPlace(arr) {
  for (let i = arr.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [arr[i], arr[j]] = [arr[j], arr[i]];
  }
  return arr;
}

const TechTools = ({ t }) => {
  const eyebrowRaw = (t.tech.eyebrow || "Integration").replace(/^\s*\/\s*/, "");
  const eyebrowText = eyebrowRaw.toUpperCase();

  // First 6 tools → row 1 (scrolls left)
  // Next 6 tools  → row 2 (scrolls right)
  const row1Tools = TOOL_LOGOS.slice(0, 6);
  const row2Tools = TOOL_LOGOS.slice(6, 12);

  // Repeat each row 3× so the linear loop has enough material to feel seamless.
  const row1 = [...row1Tools, ...row1Tools, ...row1Tools];
  const row2 = [...row2Tools, ...row2Tools, ...row2Tools];

  // ──────── Title decode state ───────────────────────────────────────────
  // letters[i] = { target, revealed, display }
  //   target   = real character (' ' for a space)
  //   revealed = whether it has locked onto its target glyph
  //   display  = the glyph we render right now
  // Spaces start as `revealed: true` so they never tint accent and never
  // get swapped for random characters by the ticker.
  const defaultTitle = String(t.tech.title || "");

  const buildLetters = (text) =>
    [...text].map((ch) => ({
      target: ch,
      revealed: ch === " ",
      display: ch === " " ? " " : randomScrambleChar(),
    }));

  const [letters, setLetters] = useStateTT(() => buildLetters(defaultTitle));

  const titleRef = useRefTT(null);
  const currentTargetRef = useRefTT(defaultTitle); // text we're currently decoding toward
  const revealTimeoutsRef = useRefTT([]);          // pending per-letter reveal timeouts
  const sequenceRef = useRefTT([]);                // phrase pool for badge clicks

  function clearReveals() {
    revealTimeoutsRef.current.forEach((id) => clearTimeout(id));
    revealTimeoutsRef.current = [];
  }

  function startDecode(text) {
    clearReveals();
    currentTargetRef.current = text;
    const fresh = buildLetters(text);
    setLetters(fresh);

    // Schedule each non-space letter to lock onto its target.
    // Letter i starts decoding at i*40ms; resolution lasts 300ms,
    // so it locks at (i*40 + 300)ms relative to the call.
    fresh.forEach((L, i) => {
      if (L.target === " ") return;
      const id = setTimeout(() => {
        // Bail if a newer decode has superseded this one.
        if (currentTargetRef.current !== text) return;
        setLetters((prev) => {
          if (i >= prev.length) return prev;
          const next = prev.slice();
          next[i] = { ...next[i], revealed: true, display: text[i] };
          return next;
        });
      }, i * 40 + 300);
      revealTimeoutsRef.current.push(id);
    });
  }

  function resetToScramble(text) {
    clearReveals();
    currentTargetRef.current = text;
    setLetters(buildLetters(text));
  }

  // Random-glyph ticker — refreshes every unrevealed letter every 55ms.
  // Returns `prev` (no-op) when nothing is scrambling so we don't re-render.
  useEffectTT(() => {
    const id = setInterval(() => {
      setLetters((prev) => {
        let dirty = false;
        for (const L of prev) {
          if (!L.revealed) { dirty = true; break; }
        }
        if (!dirty) return prev;
        return prev.map((L) =>
          L.revealed ? L : { ...L, display: randomScrambleChar() }
        );
      });
    }, 55);
    return () => clearInterval(id);
  }, []);

  // When the i18n-driven title changes (language switch), re-target
  // the decode to the new copy and reset the phrase cycler.
  useEffectTT(() => {
    sequenceRef.current = [];
    startDecode(defaultTitle);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [defaultTitle]);

  // IntersectionObserver — decode on enter, scramble-reset when the
  // title scrolls *above* the viewport (its top edge passes 0).
  useEffectTT(() => {
    const el = titleRef.current;
    if (!el) return;
    if (typeof IntersectionObserver === "undefined") {
      startDecode(currentTargetRef.current);
      return;
    }
    // Run the decode animation exactly once — the first time the title
    // enters the viewport. After that we disconnect the observer so the
    // animation never replays on subsequent scroll-ins.
    const io = new IntersectionObserver(
      (entries) => {
        for (const entry of entries) {
          if (entry.isIntersecting) {
            startDecode(currentTargetRef.current);
            io.disconnect();
            break;
          }
        }
      },
      { threshold: 0.2 }
    );
    io.observe(el);
    return () => {
      io.disconnect();
      clearReveals();
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // ──────── Badge click → next phrase ───────────────────────────────────
  function refillSequence() {
    // 1..5 in random order, then the extra (6).
    sequenceRef.current = shuffleInPlace([1, 2, 3, 4, 5]);
    sequenceRef.current.push(6);
  }
  function pickNextPhrase() {
    if (sequenceRef.current.length === 0) refillSequence();
    const idx = sequenceRef.current.shift();
    // Resolve the active language INLINE, at the moment of the click —
    // not at mount, not from state. This way switching language with the
    // header toggle is picked up by the very next badge press.
    const lang = (
      window.__lang__ ||
      document.documentElement.lang ||
      "en"
    )
      .toLowerCase()
      .trim()
      .slice(0, 2);
    const phrases = TITLE_PHRASES[lang] || TITLE_PHRASES.en;
    return phrases[idx] || phrases[1] || defaultTitle;
  }
  function handleBadgeClick() {
    const next = pickNextPhrase();
    startDecode(next);
  }

  // ──────── Render ──────────────────────────────────────────────────────
  const renderTile = (tool, key) => (
    <div key={key} className="frt-tile">
      {tool.inline ? (
        <tool.inline />
      ) : (
        <img
          className="frt-logo"
          src={`https://cdn.simpleicons.org/${tool.slug}/000000`}
          width="32"
          height="32"
          alt={tool.n}
          loading="lazy"
          draggable="false"
        />
      )}
    </div>
  );

  return (
    <section className="section frt-section" id="tools">
      <style dangerouslySetInnerHTML={{ __html: STYLE }} />

      <div className="frt-marquee">
        <div className="frt-row">
          <div className="frt-track frt-track-1">
            {row1.map((tool, i) => renderTile(tool, `r1-${i}`))}
          </div>
        </div>

        <div className="frt-row">
          <div className="frt-track frt-track-2">
            {row2.map((tool, i) => renderTile(tool, `r2-${i}`))}
          </div>
        </div>
      </div>

      <div className="frt-content">
        <div
          className="frt-badge"
          role="button"
          tabIndex={0}
          onClick={handleBadgeClick}
          onKeyDown={(e) => {
            if (e.key === "Enter" || e.key === " ") {
              e.preventDefault();
              handleBadgeClick();
            }
          }}
        >
          {eyebrowText}
        </div>

        <h2
          ref={titleRef}
          className="frt-title"
          aria-label={currentTargetRef.current}
        >
          {(() => {
            // Group letters into words separated by space tokens so the
            // browser only ever breaks BETWEEN words. Each word is its own
            // inline-block with white-space: nowrap; spaces are rendered as
            // literal text nodes (real break opportunities).
            const groups = [];
            let buf = [];
            letters.forEach((L, i) => {
              if (L.target === " ") {
                if (buf.length) { groups.push({ kind: "word", letters: buf }); buf = []; }
                groups.push({ kind: "space" });
              } else {
                buf.push({ L, i });
              }
            });
            if (buf.length) groups.push({ kind: "word", letters: buf });

            return groups.map((g, gi) => {
              if (g.kind === "space") return " ";
              return (
                <span key={`w-${gi}`} className="frt-title-word">
                  {g.letters.map(({ L, i }) => (
                    <span
                      key={i}
                      className={"frt-title-letter" + (L.revealed ? " resolved" : "")}
                    >
                      {L.display}
                    </span>
                  ))}
                </span>
              );
            });
          })()}
        </h2>

        <p className="frt-sub">{t.tech.sub}</p>
      </div>
    </section>
  );
};

window.Tech = TechTools;
window.TOOL_LOGOS = TOOL_LOGOS;
