/* global React */
const { useState, useEffect, useRef } = React;

// ===== Playbook (4 phases) — light, embossed visual language =====
// Shared SVG defs: soft drop shadow + blue glow filters for embossed-card feel.
function SvgDefs({ id }) {
  return (
    <defs>
      <filter id={`shadow-${id}`} x="-30%" y="-30%" width="160%" height="160%">
        <feDropShadow dx="0" dy="2" stdDeviation="2" floodColor="#000" floodOpacity="0.10"/>
      </filter>
      <filter id={`glow-${id}`} x="-50%" y="-50%" width="200%" height="200%">
        <feGaussianBlur stdDeviation="3" result="b"/>
        <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
      </filter>
      <linearGradient id={`pad-${id}`} x1="0" y1="0" x2="0" y2="1">
        <stop offset="0%" stopColor="#ffffff"/>
        <stop offset="100%" stopColor="#f4f4f1"/>
      </linearGradient>
    </defs>
  );
}

// Reusable embossed pad (white card with LED + label inside it)
function SvgPad({ x, y, w = 120, h = 30, label, lit = true, padId }) {
  return (
    <g className="sv-pad">
      <rect x={x} y={y} width={w} height={h} rx="6"
        fill={`url(#pad-${padId})`}
        stroke="rgba(0,0,0,0.06)" strokeWidth="0.5"
        filter={`url(#shadow-${padId})`}/>
      <circle cx={x + 12} cy={y + h/2} r="3.2" fill={lit ? '#2f6ff0' : '#d6d6d2'}/>
      {lit && <circle cx={x + 12} cy={y + h/2} r="5" fill="none" stroke="#2f6ff0" strokeOpacity="0.18" strokeWidth="2"/>}
      <text x={x + 22} y={y + h/2 + 3.5} fontSize="9.5" fontFamily="Inter, sans-serif" fontWeight="500" fill="#2a2a28">{label}</text>
    </g>
  );
}

function StepVisual({ kind, isActive }) {
  // 01 DATA — three input pads merge to STYLE GUIDE pad
  if (kind === 'data') {
    return (
      <svg viewBox="0 0 320 160" width="100%" style={{display:'block', aspectRatio:'320 / 160'}} className={`sv sv--data ${isActive ? 'is-active' : ''}`}>
        <title>Data phase diagram</title>
        <desc>Three input pads (past winners, competitor intel, brief) converge into a single style guide.</desc>
        <SvgDefs id="d"/>
        <SvgPad x={6}  y={16}  w={104} h={26} label="Past winners" padId="d"/>
        <SvgPad x={6}  y={66}  w={104} h={26} label="Comp. intel"  padId="d"/>
        <SvgPad x={6}  y={116} w={104} h={26} label="Brief"        padId="d"/>
        <g stroke="rgba(0,0,0,0.18)" strokeWidth="0.8" fill="none" strokeDasharray="2 3">
          <path className="sv-path" d="M110 29 C 140 29, 160 60, 178 80"/>
          <path className="sv-path" d="M110 79 C 140 79, 160 79, 178 80"/>
          <path className="sv-path" d="M110 129 C 140 129, 160 100, 178 80"/>
        </g>
        <g className="sv-target">
          <rect x="184" y="40" width="130" height="80" rx="14"
            fill="#2f6ff0"
            filter="url(#shadow-d)"/>
          <rect x="184" y="40" width="130" height="80" rx="14"
            fill="none" stroke="rgba(255,255,255,0.25)" strokeWidth="1"/>
          <circle cx="201" cy="60" r="4.5" fill="#fff" opacity="0.95"/>
          <circle cx="201" cy="60" r="7" fill="none" stroke="#fff" strokeOpacity="0.35" strokeWidth="1.5"/>
          <text x="249" y="86" textAnchor="middle" fontSize="14" fontWeight="600" fontFamily="Inter, sans-serif" fill="#fff" letterSpacing="-0.01em">Style guide</text>
          <text x="249" y="103" textAnchor="middle" fontSize="9" fontFamily="JetBrains Mono, monospace" fill="rgba(255,255,255,0.75)" letterSpacing="0.04em">+47 axes tagged</text>
        </g>
      </svg>
    );
  }

  // 02 SYNTHESIS — 5 concept pads fan into 5×10 matrix; winners glow
  if (kind === 'synthesis') {
    const winners = new Set([4, 17, 23, 31, 42]);
    return (
      <svg viewBox="0 0 320 160" width="100%" style={{display:'block', aspectRatio:'320 / 160'}} className={`sv sv--synthesis ${isActive ? 'is-active' : ''}`}>
        <title>Synthesis phase diagram</title>
        <desc>Five concept pads fan into a 5 by 10 matrix of variations. Five winners glow blue.</desc>
        <SvgDefs id="s"/>
        <text x="6" y="12" fontSize="9" fontFamily="JetBrains Mono, monospace" fill="#a6a6a2" letterSpacing="0.06em">5 CONCEPTS</text>
        <text x="312" y="12" textAnchor="end" fontSize="9" fontFamily="JetBrains Mono, monospace" fill="#a6a6a2" letterSpacing="0.06em">50 VARIATIONS · 5 WINNERS</text>
        {[0,1,2,3,4].map(i => (
          <SvgPad key={i} x={6} y={20 + i*22} w={56} h={18} label={`C-0${i+1}`} padId="s"/>
        ))}
        <g stroke="rgba(0,0,0,0.14)" strokeWidth="0.7" fill="none" strokeDasharray="2 2">
          {[0,1,2,3,4].map(i => (
            <path key={i} className="sv-path" d={`M62 ${29 + i*22} C 90 ${29 + i*22}, 102 80, 124 80`}/>
          ))}
        </g>
        <g className="sv-matrix">
          {Array.from({length: 50}).map((_, i) => {
            const col = i % 5;
            const row = Math.floor(i / 5);
            const filled = winners.has(i);
            return (
              <rect
                key={i}
                className={`sv-cell ${filled ? 'sv-cell--win' : ''}`}
                x={128 + col * 38}
                y={22 + row * 12}
                width="34"
                height="9"
                rx="2"
                fill={filled ? '#2f6ff0' : '#ececea'}
                stroke={filled ? 'none' : 'rgba(0,0,0,0.04)'}
                strokeWidth="0.5"
              />
            );
          })}
        </g>
        <text x="6" y="155" fontSize="8.5" fontFamily="JetBrains Mono, monospace" fill="#a6a6a2" letterSpacing="0.05em">human gate before render</text>
      </svg>
    );
  }

  // 03 PRODUCTION — 4 source pads → engine ring → blue "50" output
  if (kind === 'production') {
    return (
      <svg viewBox="0 0 320 160" width="100%" style={{display:'block', aspectRatio:'320 / 160'}} className={`sv sv--production ${isActive ? 'is-active' : ''}`}>
        <title>Production phase diagram</title>
        <desc>Four asset streams converge into a render engine, producing fifty MP4s.</desc>
        <SvgDefs id="p"/>
        <defs>
          <marker id="arrP" markerWidth="6" markerHeight="6" refX="5" refY="3" orient="auto">
            <path d="M0,0 L6,3 L0,6 Z" fill="#2f6ff0"/>
          </marker>
        </defs>
        {['Gameplay','AI voice','AI persona','Motion gfx'].map((label, i) => (
          <SvgPad key={label} x={6} y={16 + i*30} w={108} h={22} label={label} padId="p"/>
        ))}
        <g stroke="rgba(0,0,0,0.14)" strokeWidth="0.7" fill="none" strokeDasharray="2 2">
          {[0,1,2,3].map(i => (
            <path key={i} className="sv-path" d={`M114 ${27 + i*30} C 140 ${27 + i*30}, 160 80, 174 80`}/>
          ))}
        </g>
        <g className="sv-target">
          <rect x="174" y="50" width="76" height="60" rx="14"
            fill="url(#pad-p)" stroke="rgba(0,0,0,0.06)" strokeWidth="0.5"
            filter="url(#shadow-p)"/>
          <circle cx="212" cy="76" r="11" fill="#fafaf8" stroke="rgba(0,0,0,0.06)" strokeWidth="0.5"/>
          <circle cx="212" cy="76" r="4" fill="#2f6ff0"/>
          <circle cx="212" cy="76" r="6.5" fill="none" stroke="#2f6ff0" strokeOpacity="0.18" strokeWidth="2"/>
          <text x="212" y="100" textAnchor="middle" fontSize="9" fontWeight="500" fontFamily="Inter, sans-serif" fill="#2a2a28">Render engine</text>
        </g>
        <path className="sv-path" d="M250 80 L266 80" stroke="#2f6ff0" strokeWidth="1.4" fill="none" markerEnd="url(#arrP)"/>
        <g className="sv-output">
          <rect x="266" y="50" width="48" height="60" rx="14"
            fill="#2f6ff0"
            filter="url(#shadow-p)"/>
          <text x="290" y="86" textAnchor="middle" fontSize="22" fontWeight="700" fontFamily="Inter, sans-serif" fill="#fff" letterSpacing="-0.02em">50</text>
          <text x="290" y="98" textAnchor="middle" fontSize="7" fontFamily="JetBrains Mono, monospace" fill="rgba(255,255,255,0.8)" letterSpacing="0.05em">MP4 · 9:16</text>
        </g>
        <text x="160" y="155" textAnchor="middle" fontSize="8.5" fontFamily="JetBrains Mono, monospace" fill="#a6a6a2" letterSpacing="0.05em">30–90 min · parallel render</text>
      </svg>
    );
  }

  // 04 LOOP — Run N pad → curved feedback → Run N+1 pad. Right: exploit/explore split
  if (kind === 'loop') {
    return (
      <svg viewBox="0 0 320 160" width="100%" style={{display:'block', aspectRatio:'320 / 160'}} className={`sv sv--loop ${isActive ? 'is-active' : ''}`}>
        <title>Loop phase diagram</title>
        <desc>KPIs from Run N feed forward to Run N+1, biasing 16 exploit + 4 explore slots.</desc>
        <SvgDefs id="l"/>
        <defs>
          <marker id="arrL" markerWidth="6" markerHeight="6" refX="5" refY="3" orient="auto">
            <path d="M0,0 L6,3 L0,6 Z" fill="#2f6ff0"/>
          </marker>
          <linearGradient id="loopGrad" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0%" stopColor="rgba(0,0,0,0.18)"/>
            <stop offset="100%" stopColor="#2f6ff0"/>
          </linearGradient>
        </defs>
        <SvgPad x={6} y={22} w={70} h={26} label="Run N"   padId="l"/>
        <SvgPad x={6} y={112} w={70} h={26} label="Run N+1" padId="l"/>
        <path className="sv-path" d="M76 35 C 120 35, 130 65, 100 85 C 70 105, 90 120, 76 125"
          stroke="url(#loopGrad)" strokeWidth="1.4" fill="none" markerEnd="url(#arrL)" strokeDasharray="2 2"/>
        <text x="106" y="58" fontSize="8" fontFamily="JetBrains Mono, monospace" fill="#a6a6a2" letterSpacing="0.04em">KPIs IN</text>
        <text x="78" y="103" fontSize="8" fontFamily="JetBrains Mono, monospace" fill="#a6a6a2" letterSpacing="0.04em">AXIS TAGS</text>
        <g className="sv-target">
          <rect x="170" y="16" width="146" height="60" rx="14"
            fill="url(#pad-l)" stroke="rgba(0,0,0,0.06)" strokeWidth="0.5"
            filter="url(#shadow-l)"/>
          <text x="184" y="35" fontSize="11" fontWeight="600" fontFamily="Inter, sans-serif" fill="#2a2a28" letterSpacing="-0.01em">16 exploit</text>
          <text x="184" y="50" fontSize="8" fontFamily="JetBrains Mono, monospace" fill="#6e6e6a" letterSpacing="0.04em">CLONE WINNING HOOKS</text>
          <text x="184" y="63" fontSize="8" fontFamily="JetBrains Mono, monospace" fill="#a6a6a2" letterSpacing="0.04em">vary motion only</text>
        </g>
        <g className="sv-output">
          <rect x="170" y="88" width="146" height="38" rx="14"
            fill="#2f6ff0"
            filter="url(#shadow-l)"/>
          <circle cx="184" cy="107" r="3.5" fill="#fff" opacity="0.95"/>
          <circle cx="184" cy="107" r="6" fill="none" stroke="#fff" strokeOpacity="0.4" strokeWidth="1.5"/>
          <text x="198" y="105" fontSize="11" fontWeight="600" fontFamily="Inter, sans-serif" fill="#fff" letterSpacing="-0.01em">4 explore</text>
          <text x="198" y="118" fontSize="8" fontFamily="JetBrains Mono, monospace" fill="rgba(255,255,255,0.8)" letterSpacing="0.04em">FLIP ONE UNUSED AXIS</text>
        </g>
        <text x="160" y="155" textAnchor="middle" fontSize="8.5" fontFamily="JetBrains Mono, monospace" fill="#a6a6a2" letterSpacing="0.05em">every cycle, more signal than the last</text>
      </svg>
    );
  }
  return null;
}

// ===== Step card with reveal + hover =====
function StepCard({ step, index }) {
  const ref = useRef(null);
  const [revealed, setRevealed] = useState(false);
  const [hover, setHover] = useState(false);

  useEffect(() => {
    if (!ref.current) return;
    if (typeof IntersectionObserver === 'undefined') {
      setRevealed(true);
      return;
    }
    const io = new IntersectionObserver(
      ([e]) => { if (e.isIntersecting) { setRevealed(true); io.disconnect(); } },
      { threshold: 0.4 }
    );
    io.observe(ref.current);
    return () => io.disconnect();
  }, []);

  return (
    <div
      ref={ref}
      className={`step ${revealed ? 'is-revealed' : ''}`}
      style={{'--step-delay': `${index * 120}ms`}}
      tabIndex={0}
      aria-label={`Phase ${step.num}: ${step.title}`}
    >
      <h3>{step.title}</h3>
      <p>{step.body}</p>
    </div>
  );
}

function Loop() {
  const steps = [
    {
      num: '01',
      kind: 'data',
      title: 'Data',
      body: 'Your winners go in. So does the competitive landscape. Hooks, pacing, the beats that actually converted. Velo distills it into a living style guide that compounds every run.',
    },
    {
      num: '02',
      kind: 'synthesis',
      title: 'Synthesis',
      body: 'Most concepts variations what\u2019s already winning. The rest stress test fresh territory. Each one fans across hook, voice, persona, and style into a concept matrix. Human gate before a single pixel renders.',
    },
    {
      num: '03',
      kind: 'production',
      title: 'Production',
      body: 'Asset streams render in parallel. Gameplay capture. AI voice. AI persona on camera. Motion graphics. A sample drops first, the batch follows. Always-on output, ready to push live.',
    },
    {
      num: '04',
      kind: 'loop',
      title: 'Loop',
      body: 'KPIs come back tagged by axis. The next run leans into what won, with room for what the winners never tried. Every cycle carries more signal than the last. Sharper every loop.',
    },
  ];
  return (
    <section id="how" data-screen-label="Playbook">
      <div className="container">
        <div className="section-head">
          <div className="section-marker">
            <span className="section-marker__tag">Mechanism</span>
          </div>
          <div>
            <h2>Four phases. One loop. <em>Sharper every run.</em></h2>
            <p className="lede">Data feeds Synthesis. Synthesis feeds Production. Production feeds the Loop. The Loop feeds Data, sharper than before. Markets shift. Hooks fatigue. Velo finds the next winner before the current one burns out.</p>
          </div>
        </div>
        <div className="steps">
          {steps.map((s, i) => (
            <StepCard key={s.num} step={s} index={i} />
          ))}
        </div>
        <MechanismDiagram />
      </div>
    </section>
  );
}

// ===== Mechanism diagram (inlined, scroll-tied) =====
const MECH_INPUTS = [
  'Your Assets',
  'KPI targets',
  'Current winner',
  'Competitor winners',
  'New trends',
];
const MECH_OUT_CELLS = (() => {
  // 5 rows × 13 cols. The mid cell of row 3 is the swan.
  const cells = [];
  const palette = ['dim', 'lit', '', 'dim', 'lit', '', 'dim', 'lit', '', 'dim', 'lit', '', 'dim'];
  for (let r = 0; r < 5; r++) {
    for (let c = 0; c < 13; c++) {
      if (r === 2 && c === 4) { cells.push('swan'); continue; }
      const i = (r * 13 + c) % palette.length;
      cells.push(palette[i]);
    }
  }
  return cells;
})();

function MechanismDiagram() {
  const wrapRef = useRef(null);
  const stageInnerRef = useRef(null);
  const fieldRef = useRef(null);
  const inputsRef = useRef(null);
  const engineRef = useRef(null);

  useEffect(() => {
    const wrap = wrapRef.current;
    const stageInner = stageInnerRef.current;
    const field = fieldRef.current;
    const inputs = inputsRef.current;
    const engine = engineRef.current;
    if (!wrap || !stageInner || !field || !engine) return;

    const reduceMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    const TWEAKS = { count: 51, videoShare: 60, playableShare: 20, imageShare: 20 };
    const ICO = {
      video:    '<svg viewBox="0 0 12 12" fill="currentColor" aria-hidden="true"><path d="M3.5 2.5 L9.5 6 L3.5 9.5 Z"/></svg>',
      image:    '<svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round" aria-hidden="true"><rect x="1.5" y="2.5" width="9" height="7" rx="1"/><circle cx="4" cy="5" r="0.8" fill="currentColor" stroke="none"/><path d="M2 8.5 L4.5 6 L7 7.5 L10 5"/></svg>',
      playable: '<svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="3.5" width="8" height="5" rx="1.6"/><path d="M3.8 6 H5.4 M4.6 5.2 V6.8"/><circle cx="7.7" cy="6" r="0.6" fill="currentColor" stroke="none"/></svg>'
    };
    const TAG = { video: 'VID', image: 'IMG', playable: 'PLAY' };

    const srand = (i, s) => ((Math.sin(i * s) + 1) * 0.5);
    const seededType = (i, tw) => {
      const total = Math.max(1, tw.videoShare + tw.playableShare + tw.imageShare);
      const r = ((Math.sin(i * 91.13) + 1) * 0.5) * total;
      if (r < tw.videoShare) return 'video';
      if (r < tw.videoShare + tw.playableShare) return 'playable';
      return 'image';
    };

    function render() {
      field.innerHTML = '';
      const fieldRect = field.getBoundingClientRect();
      const er = engine.getBoundingClientRect();
      const cx = er.left + er.width / 2 - fieldRect.left;
      const cy = er.top  + er.height / 2 - fieldRect.top;
      const w = fieldRect.width, h = fieldRect.height;
      const N = TWEAKS.count;
      const isMobile = window.innerWidth <= 1100;
      // Desktop: scatter scales with width so creatives reach into the right
      // margin past the out-card. Mobile keeps the tighter min-based fan.
      const rMax = isMobile ? Math.min(w, h) * 0.62 : Math.max(w, h) * 0.46;
      const LANES = [-55, -30, -15, 25, 50].map(d => (isMobile ? d + 90 : d) * Math.PI / 180);

      for (let i = 0; i < N; i++) {
        const laneI = i % LANES.length;
        const laneIdx = Math.floor(i / LANES.length);
        const laneN = Math.ceil(N / LANES.length);
        const lt = (laneIdx + 0.5) / laneN;
        const theta = LANES[laneI];
        const engR = 100;
        const dist = (rMax * 2 - engR) * Math.pow(lt, 0.95) + (srand(i, 17.3) - 0.5) * 14;
        const ox = cx + Math.cos(theta) * engR;
        const oy = cy + Math.sin(theta) * engR * 0.92;
        const perp = (srand(i, 31.1) - 0.5) * 38;
        const px = -Math.sin(theta) * perp;
        const py =  Math.cos(theta) * perp;
        const x = ox + Math.cos(theta) * dist + px;
        const y = oy + Math.sin(theta) * dist * 0.92 + py;

        const size = 1 - Math.pow(lt, 1.1);
        const W = 28 + size * 28;
        const H = W * 1.7;
        const opacity = 0.32 + size * 0.65;

        const type = seededType(i + 100, TWEAKS);
        const lit = (i % 9 === 2 && size > 0.55);
        const showTag = size > 0.45;

        const el = document.createElement('div');
        el.className = 'ft' + (lit ? ' lit' : '');
        el.style.left = (cx - W / 2) + 'px';
        el.style.top  = (cy - H / 2) + 'px';
        el.style.width = W + 'px';
        el.style.height = H + 'px';
        el.style.zIndex = String(Math.round(size * 100));
        el.style.setProperty('--fop', opacity.toFixed(2));
        el.style.setProperty('--rot', ((srand(i, 11.7) - 0.5) * 14).toFixed(1) + 'deg');
        el.style.setProperty('--dx', (x - cx).toFixed(1) + 'px');
        el.style.setProperty('--dy', (y - cy).toFixed(1) + 'px');

        const isz = (10 + size * 10);
        let inner = '<span class="ico" style="width:' + isz + 'px;height:' + isz + 'px">' + ICO[type] + '</span>';
        if (showTag) inner = '<span class="corner-tag">' + TAG[type] + '</span>' + inner;
        el.innerHTML = inner;
        field.appendChild(el);
      }
    }

    function sizeEngine() {
      if (!inputs || !engine) return;
      const h = inputs.offsetHeight;
      if (h > 0) {
        engine.style.width  = h + 'px';
        engine.style.height = h + 'px';
      }
    }

    function measureGaps() {
      const pad = stageInner.querySelector('.pad');
      if (!pad || !engine) return;
      const padR = pad.getBoundingClientRect();
      const engR = engine.getBoundingClientRect();
      const gap1 = Math.max(0, engR.left - padR.right);
      stageInner.style.setProperty('--gap1', gap1.toFixed(1) + 'px');
    }

    let raf = null;
    function update() {
      if (reduceMotion) {
        stageInner.style.setProperty('--p1', '1');
        stageInner.style.setProperty('--p2', '1');
        stageInner.style.setProperty('--pCard', '1');
        return;
      }
      // Map the diagram's position-in-viewport to t ∈ [0, 1]:
      //   t = 0 when the element's top hits viewport bottom (just entering)
      //   t = 1 when the element's bottom hits viewport top (leaving)
      const r = stageInner.getBoundingClientRect();
      const vh = window.innerHeight;
      const total = r.height + vh;
      const traveled = vh - r.top;
      // Same entry trigger, but 3× faster — reach final state after ~1/3 of the
      // scroll range, so the animation finishes well before the diagram leaves.
      const raw = total > 0 ? traveled / total : 0;
      const t = Math.max(0, Math.min(1, raw * 3));
      const p1 = Math.max(0, Math.min(1, t / 0.5));
      const p2 = Math.max(0, Math.min(1, (t - 0.4) / 0.6));
      const pCard = Math.max(0, Math.min(1, (t - 0.55) / 0.45));
      stageInner.style.setProperty('--p1', p1.toFixed(3));
      stageInner.style.setProperty('--p2', p2.toFixed(3));
      stageInner.style.setProperty('--pCard', pCard.toFixed(3));
      raf = null;
    }
    function onScroll() { if (!raf) raf = requestAnimationFrame(update); }

    let resizeTimer;
    function onResize() {
      clearTimeout(resizeTimer);
      resizeTimer = setTimeout(() => { sizeEngine(); measureGaps(); render(); update(); }, 120);
    }

    sizeEngine();
    measureGaps();
    render();
    update();
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onResize);

    return () => {
      window.removeEventListener('scroll', onScroll);
      window.removeEventListener('resize', onResize);
      clearTimeout(resizeTimer);
      if (raf) cancelAnimationFrame(raf);
    };
  }, []);

  return (
    <div ref={wrapRef} className="mechanism-stage">
      <div ref={stageInnerRef} className="stage-inner">
        <div ref={fieldRef} className="field" aria-hidden="true"></div>
        <div className="row">
          <div ref={inputsRef} className="inputs">
            {MECH_INPUTS.map(label => (
              <div className="pad on" key={label}>
                <span className="led"></span>
                <span className="lbl">{label}</span>
              </div>
            ))}
            <div className="pad more">
              <span className="led"></span>
              <span className="lbl">and <b>+12 more</b><span className="dots"><i></i><i></i><i></i></span></span>
            </div>
          </div>
          <div className="engine-col">
            <div ref={engineRef} className="engine" role="img" aria-label="Velo synth and render engine">
              <div className="ring"><span className="core-led"></span></div>
              <h2>Synth + Render</h2>
              <div className="sub">Velo engine</div>
            </div>
          </div>
          <div className="outputs">
            <div className="out-card">
              <div className="swan-line">Most are mid. <em>One breaks the pattern.</em></div>
              <div className="grid" aria-hidden="true">
                {MECH_OUT_CELLS.map((cls, i) => <i key={i} className={cls}></i>)}
              </div>
              <div className="legend">
                <i className="legend-swatch" aria-hidden="true"></i>
                <span className="legend-text">black swan creative</span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ===== Case study =====
function CaseStudy() {
  return (
    <section id="case" data-screen-label="Case study">
      <div className="container">
        <div className="section-head">
          <div className="section-marker">
            <span className="section-marker__tag">Case study</span>
          </div>
          <div>
            <h2>A puzzle studio, <em>one run, fifty ads.</em></h2>
            <p className="lede">Mid-size publisher running a Match-3 title. ~$420k/mo on AppLovin and Unity. One Velo run delivered fifty ads in under four hours, and performance fed the next run two weeks later.</p>
          </div>
        </div>
        <div className="case">
          <div className="case-stats">
            <div className="stat">
              <div className="label mono">IPM lift</div>
              <div className="value up">+47<span className="unit">%</span></div>
              <div className="desc">Top-quartile creatives only, weighted by spend.</div>
            </div>
            <div className="stat">
              <div className="label mono">CPI</div>
              <div className="value">−22<span className="unit">%</span></div>
              <div className="desc">Blended across AppLovin and Unity, US/UK/CA.</div>
            </div>
            <div className="stat">
              <div className="label mono">Ads per run</div>
              <div className="value">8<span className="unit">→50</span></div>
              <div className="desc">Same UA team, same creative budget.</div>
            </div>
            <div className="stat">
              <div className="label mono">Run cycle time</div>
              <div className="value">3<span className="unit">wk→4h</span></div>
              <div className="desc">Brief to delivered MP4s, gates included.</div>
            </div>
          </div>
          <div>
            <p className="case-quote">
              "We were shipping eight concepts a week and calling it 'velocity.' <em>Velo gets us fifty per run with the same team, and the loser-kill is the part that actually moved CPI.</em>"
            </p>
            <div className="case-attrib">
              <div className="av mono">M·K</div>
              <div className="who">
                Head of UA, Top-50 publisher
                <div className="role">Pilot, Q1 2026 · name on request</div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

// ===== CTA =====
function CTA() {
  return (
    <section className="cta-banner" data-screen-label="CTA">
      <div className="container cta-inner">
        <h2>Stop shipping in drips. <em>Start shipping in runs.</em></h2>
        <div style={{display:'flex', flexDirection:'column', gap: 12, alignItems:'flex-start'}}>
          <span className="cta-tip">
            <a className="btn btn--primary" href="#signup">Request access <span className="arrow">→</span></a>
            <span className="cta-tip__label mono" role="tooltip">closed beta. few users. lots of care.</span>
          </span>
        </div>
      </div>
    </section>
  );
}

// ===== Footer =====
function Footer({ logo = 'arrow' }) {
  return (
    <footer data-screen-label="Footer">
      <div className="container">
        <div className="footer-grid">
          <div>
            <a href="#" className="brand" style={{display: 'inline-flex'}}>
              <VeloMark variant={logo} />
            </a>
            <p style={{marginTop: 20, maxWidth: '32ch', color: 'var(--mute)'}}>
              Winning ads, shipped at the cadence your spend deserves.
            </p>
          </div>
          <div>
            <h5>Product</h5>
            <a href="#how">How it works</a>
            <a href="#networks">Networks</a>
            <a href="#case">Case study</a>
            <a href="#docs">Docs</a>
            <a href="#changelog">Changelog</a>
          </div>
          <div>
            <h5>Company</h5>
            <a href="#about">About</a>
            <a href="#careers">Careers</a>
            <a href="#contact">Contact</a>
          </div>
          <div>
            <h5>Legal</h5>
            <a href="#terms">Terms</a>
            <a href="#privacy">Privacy</a>
            <a href="#dpa">DPA</a>
          </div>
        </div>
        <div className="footer-bottom">
          <span>velo.ad · 2026</span>
          <span>Built for UA teams who'd rather ship than sit in standups.</span>
        </div>
      </div>
    </footer>
  );
}

window.Loop = Loop;
window.CaseStudy = CaseStudy;
window.CTA = CTA;
window.Footer = Footer;
