/* global React */
/* Per-page animated intros. Each exports a React component that plays once
   then calls onDone. Each links football → the page's subject matter. */
const { useState, useEffect, useRef } = React;

/* ====================================================================
   HOME — Pitch builds itself (existing)
   ==================================================================== */
function PitchIntro({ onDone }) {
  const [phase, setPhase] = useState(0);
  useEffect(() => {
    const t = [
      setTimeout(() => setPhase(1), 50),
      setTimeout(() => setPhase(2), 450),
      setTimeout(() => setPhase(3), 700),
      setTimeout(() => setPhase(4), 1000),
      setTimeout(() => setPhase(5), 1400),
      setTimeout(() => setPhase(6), 1700),
      setTimeout(() => onDone && onDone(), 2300),
    ];
    return () => t.forEach(clearTimeout);
  }, [onDone]);
  return (
    <div className={`intro intro-home intro-phase-${phase}`}>
      <div className="intro-spotlight" />
      <div className="intro-kickoff">
        <div className="intro-kickoff-dot" />
        <div className="intro-kickoff-ring" />
        <div className="intro-kickoff-ring intro-kickoff-ring-2" />
      </div>
      <svg className="intro-pitch" viewBox="0 0 1400 900" preserveAspectRatio="xMidYMid meet">
        <defs><filter id="introGlow"><feGaussianBlur stdDeviation="2.2" result="b" /><feMerge><feMergeNode in="b" /><feMergeNode in="SourceGraphic" /></feMerge></filter></defs>
        <g stroke="#6CABDD" strokeWidth="2" fill="none" filter="url(#introGlow)">
          <rect className="draw-line draw-outer" x="50" y="70" width="1300" height="760" pathLength="1000" />
          <line className="draw-line draw-halfway" x1="700" y1="70" x2="700" y2="830" pathLength="1000" />
          <circle className="draw-line draw-circle" cx="700" cy="450" r="110" pathLength="1000" />
          <rect className="draw-line draw-box-l" x="50" y="250" width="200" height="400" pathLength="1000" />
          <rect className="draw-line draw-six-l" x="50" y="335" width="70" height="230" pathLength="1000" />
          <path className="draw-line draw-arc-l" d="M 250 398 A 110 110 0 0 1 250 502" pathLength="1000" />
          <rect className="draw-line draw-box-r" x="1150" y="250" width="200" height="400" pathLength="1000" />
          <rect className="draw-line draw-six-r" x="1280" y="335" width="70" height="230" pathLength="1000" />
          <path className="draw-line draw-arc-r" d="M 1150 398 A 110 110 0 0 0 1150 502" pathLength="1000" />
          <path className="draw-line draw-corner" d="M 50 82 A 12 12 0 0 1 62 70" pathLength="1000" />
          <path className="draw-line draw-corner" d="M 1338 70 A 12 12 0 0 1 1350 82" pathLength="1000" />
          <path className="draw-line draw-corner" d="M 1350 818 A 12 12 0 0 1 1338 830" pathLength="1000" />
          <path className="draw-line draw-corner" d="M 62 830 A 12 12 0 0 1 50 818" pathLength="1000" />
        </g>
        <g className="intro-dots" fill="#6CABDD" filter="url(#introGlow)">
          {[[120,450],[260,220],[260,370],[260,530],[260,680],[490,330],[490,450],[490,570],[820,280],[860,450],[820,620]].map(([cx,cy],i)=>(
            <circle key={i} cx={cx} cy={cy} r="5" style={{animationDelay: `${i*40}ms`}} />
          ))}
        </g>
        <g className="intro-dots-away" fill="#FF6B8A" filter="url(#introGlow)">
          {[[1280,450],[1140,310],[1140,590],[1080,220],[1080,680]].map(([cx,cy],i)=>(
            <circle key={i} cx={cx} cy={cy} r="4.5" style={{animationDelay: `${(i+8)*40}ms`}} />
          ))}
        </g>
      </svg>
      <div className="intro-brand">
        <div className="intro-brand-mark" />
        <div className="intro-brand-name">Jaydon Coombs-Goodfellow</div>
        <div className="intro-brand-tag">Football Analysis Portfolio</div>
      </div>
      <div className="intro-flash" />
    </div>
  );
}

/* ====================================================================
   ABOUT — Player silhouette shapes in from dots,
   boot, ball roll, coach clipboard appears
   ==================================================================== */
function AboutIntro({ onDone }) {
  const [phase, setPhase] = useState(0);
  useEffect(() => {
    const t = [
      setTimeout(() => setPhase(1), 50),   // dots appear
      setTimeout(() => setPhase(2), 500),  // lines connect to form figure
      setTimeout(() => setPhase(3), 1100), // ball rolls in
      setTimeout(() => setPhase(4), 1500), // role labels spin on
      setTimeout(() => setPhase(5), 1900), // flash
      setTimeout(() => onDone && onDone(), 2400),
    ];
    return () => t.forEach(clearTimeout);
  }, [onDone]);

  // Stick figure via skeleton: head, shoulders, hips, knees, feet
  const joints = [
    {x:300, y:120, id:'head'},
    {x:300, y:170, id:'neck'},
    {x:260, y:200, id:'Lshoulder'},
    {x:340, y:200, id:'Rshoulder'},
    {x:230, y:260, id:'Lelbow'},
    {x:370, y:260, id:'Relbow'},
    {x:215, y:320, id:'Lhand'},
    {x:385, y:320, id:'Rhand'},
    {x:275, y:300, id:'Lhip'},
    {x:325, y:300, id:'Rhip'},
    {x:270, y:400, id:'Lknee'},
    {x:330, y:400, id:'Rknee'},
    {x:265, y:490, id:'Lfoot'},
    {x:340, y:490, id:'Rfoot'},
  ];
  const bones = [
    ['head','neck'],['neck','Lshoulder'],['neck','Rshoulder'],
    ['Lshoulder','Lelbow'],['Lelbow','Lhand'],
    ['Rshoulder','Relbow'],['Relbow','Rhand'],
    ['Lshoulder','Lhip'],['Rshoulder','Rhip'],['Lhip','Rhip'],
    ['Lhip','Lknee'],['Lknee','Lfoot'],
    ['Rhip','Rknee'],['Rknee','Rfoot'],
  ];
  const pos = Object.fromEntries(joints.map(j=>[j.id,j]));

  return (
    <div className={`intro intro-about intro-phase-${phase}`}>
      <div className="intro-spotlight" />
      <svg viewBox="0 0 900 600" className="intro-about-svg" preserveAspectRatio="xMidYMid meet">
        <defs><filter id="aboutGlow"><feGaussianBlur stdDeviation="2" result="b" /><feMerge><feMergeNode in="b" /><feMergeNode in="SourceGraphic" /></feMerge></filter></defs>

        {/* bones connecting dots */}
        <g stroke="#6CABDD" strokeWidth="2" strokeLinecap="round" filter="url(#aboutGlow)" opacity="0.95">
          {bones.map(([a,b],i)=>(
            <line key={i} className="about-bone" x1={pos[a].x} y1={pos[a].y} x2={pos[b].x} y2={pos[b].y}
              pathLength="1000" style={{animationDelay:`${i*50}ms`}} />
          ))}
        </g>

        {/* head circle */}
        <circle className="about-head" cx="300" cy="120" r="30" fill="none" stroke="#A5D8FF" strokeWidth="2.5" filter="url(#aboutGlow)" pathLength="1000" />

        {/* joints */}
        <g filter="url(#aboutGlow)">
          {joints.map((j,i)=>(
            <circle key={j.id} className="about-joint" cx={j.x} cy={j.y} r="4.5" fill="#A5D8FF"
              style={{animationDelay:`${i*45}ms`}} />
          ))}
        </g>

        {/* football — rolls from left to right foot */}
        <g className="about-ball" filter="url(#aboutGlow)">
          <circle cx="0" cy="0" r="14" fill="#6CABDD" stroke="#0B1426" strokeWidth="2" />
          <path d="M -5 -8 L 5 -8 L 7 0 L 0 6 L -7 0 Z" fill="#0B1426" opacity="0.6" />
        </g>

        {/* Role labels: ANALYST / COACH / PLAYER — spin on */}
        <g className="about-labels">
          <g transform="translate(560, 160)">
            <rect className="about-chip" x="-70" y="-18" width="140" height="36" rx="18" fill="rgba(108,171,221,0.08)" stroke="#6CABDD" strokeWidth="1.4" />
            <text className="about-chip-text" x="0" y="5" textAnchor="middle" fill="#A5D8FF" fontSize="14" fontWeight="600" letterSpacing="3">ANALYST</text>
          </g>
          <g transform="translate(600, 240)">
            <rect className="about-chip" x="-65" y="-18" width="130" height="36" rx="18" fill="rgba(108,171,221,0.08)" stroke="#6CABDD" strokeWidth="1.4" />
            <text className="about-chip-text" x="0" y="5" textAnchor="middle" fill="#A5D8FF" fontSize="14" fontWeight="600" letterSpacing="3">COACH</text>
          </g>
          <g transform="translate(560, 320)">
            <rect className="about-chip" x="-65" y="-18" width="130" height="36" rx="18" fill="rgba(108,171,221,0.08)" stroke="#6CABDD" strokeWidth="1.4" />
            <text className="about-chip-text" x="0" y="5" textAnchor="middle" fill="#A5D8FF" fontSize="14" fontWeight="600" letterSpacing="3">PLAYER</text>
          </g>
        </g>
      </svg>

      <div className="intro-brand intro-brand-bottom">
        <div className="intro-brand-tag">About</div>
        <div className="intro-brand-name">Manchester City supporter, data analyst, coach.</div>
      </div>
      <div className="intro-flash" />
    </div>
  );
}

/* ====================================================================
   PHILOSOPHY — Neural network grows, nodes light up,
   signals propagate, network forms tactical pattern
   ==================================================================== */
function PhilosophyIntro({ onDone }) {
  const [phase, setPhase] = useState(0);
  useEffect(() => {
    const t = [
      setTimeout(() => setPhase(1), 50),
      setTimeout(() => setPhase(2), 500),
      setTimeout(() => setPhase(3), 1000),
      setTimeout(() => setPhase(4), 1500),
      setTimeout(() => setPhase(5), 2000),
      setTimeout(() => onDone && onDone(), 2500),
    ];
    return () => t.forEach(clearTimeout);
  }, [onDone]);

  // Brain outline — two hemispheres, side view, stem.
  // viewBox 900x700, centered around (450, 350)
  // Nodes distributed along the brain's cortex + deep structures
  const nodes = [
    // LEFT hemisphere cortex (outer)
    [298, 208], [262, 245], [238, 290], [222, 340], [226, 390], [248, 438], [280, 475], [322, 498],
    // RIGHT hemisphere cortex (outer) — mirrored
    [602, 208], [638, 245], [662, 290], [678, 340], [674, 390], [652, 438], [620, 475], [578, 498],
    // Top arch nodes
    [370, 178], [450, 168], [530, 178],
    // Deep / central nodes (both hemispheres)
    [370, 278], [410, 320], [450, 290], [490, 320], [530, 278],
    [370, 380], [420, 400], [450, 370], [480, 400], [530, 380],
    // Brain stem / lower
    [420, 530], [450, 560], [480, 530],
  ];

  // Indices layout:
  // 0-7 left cortex, 8-15 right cortex, 16-18 top arch,
  // 19-23 deep row 1, 24-28 deep row 2, 29-31 stem
  const E = [
    // LEFT cortex chain
    [0,1],[1,2],[2,3],[3,4],[4,5],[5,6],[6,7],
    // RIGHT cortex chain
    [8,9],[9,10],[10,11],[11,12],[12,13],[13,14],[14,15],
    // Top arch
    [0,16],[16,17],[17,18],[18,8],
    // Corpus callosum — midline crossings
    [17,21],[17,22],[21,24],[22,24],
    // Left hemisphere inner web
    [0,19],[16,19],[19,20],[20,23],[23,24],[3,23],[4,25],[25,26],[5,26],
    // Right hemisphere inner web
    [8,22],[18,22],[22,23],[11,23],[23,28],[12,28],[13,27],[27,28],
    // Lower/stem connections
    [7,29],[29,30],[30,31],[31,15],
    [26,29],[28,31],[20,29],[27,31],
    // Cross-hemisphere deep
    [19,22],[21,23],[24,25],[24,27],
  ];

  // Traveling synapse pulses — pick a handful of edges
  const pulses = [
    {a:0, b:1, d:'0.1s'},
    {a:17, b:21, d:'0.3s'},
    {a:22, b:24, d:'0.55s'},
    {a:24, b:25, d:'0.75s'},
    {a:8, b:9, d:'0.2s'},
    {a:23, b:28, d:'0.9s'},
    {a:29, b:30, d:'1.05s'},
    {a:20, b:23, d:'0.4s'},
  ];

  return (
    <div className={`intro intro-philosophy intro-phase-${phase}`}>
      <div className="intro-spotlight" />
      <svg viewBox="0 0 900 700" className="intro-philo-svg" preserveAspectRatio="xMidYMid meet">
        <defs>
          <filter id="philoGlow"><feGaussianBlur stdDeviation="2.5" result="b" /><feMerge><feMergeNode in="b" /><feMergeNode in="SourceGraphic" /></feMerge></filter>
          <radialGradient id="philoNode">
            <stop offset="0%" stopColor="#A5D8FF" />
            <stop offset="100%" stopColor="#6CABDD" />
          </radialGradient>
        </defs>

        {/* Brain outline — two hemispheres, sulcus down the middle, stem */}
        <g fill="none" stroke="#6CABDD" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" opacity="0.55">
          {/* Left hemisphere outer silhouette */}
          <path className="philo-outline philo-outline-l"
            d="M 450 165
               C 380 155, 300 175, 255 225
               C 210 275, 200 360, 230 435
               C 255 495, 310 530, 380 540
               C 395 542, 405 544, 410 555
               L 410 558"
            pathLength="1000" />
          {/* Right hemisphere outer silhouette */}
          <path className="philo-outline philo-outline-r"
            d="M 450 165
               C 520 155, 600 175, 645 225
               C 690 275, 700 360, 670 435
               C 645 495, 590 530, 520 540
               C 505 542, 495 544, 490 555
               L 490 558"
            pathLength="1000" />
          {/* Central sulcus / midline */}
          <path className="philo-outline philo-outline-m"
            d="M 450 165 L 450 555"
            pathLength="1000" opacity="0.35" />
          {/* Cortex folds — left */}
          <path className="philo-fold"
            d="M 270 250 C 300 255, 320 265, 340 280"
            pathLength="1000" />
          <path className="philo-fold"
            d="M 245 320 C 285 325, 320 330, 360 340"
            pathLength="1000" />
          <path className="philo-fold"
            d="M 260 400 C 300 405, 340 410, 380 420"
            pathLength="1000" />
          {/* Cortex folds — right */}
          <path className="philo-fold"
            d="M 630 250 C 600 255, 580 265, 560 280"
            pathLength="1000" />
          <path className="philo-fold"
            d="M 655 320 C 615 325, 580 330, 540 340"
            pathLength="1000" />
          <path className="philo-fold"
            d="M 640 400 C 600 405, 560 410, 520 420"
            pathLength="1000" />
          {/* Brain stem */}
          <path className="philo-outline philo-outline-s"
            d="M 410 558 C 415 585, 440 605, 450 620
               C 460 605, 485 585, 490 558"
            pathLength="1000" />
        </g>

        {/* synapses — neural connections */}
        <g opacity="0.5" stroke="#6CABDD" strokeWidth="0.8" filter="url(#philoGlow)">
          {E.map(([a,b],i)=>{
            const [x1,y1] = nodes[a]; const [x2,y2] = nodes[b];
            return (
              <line key={i} className="philo-conn"
                x1={x1} y1={y1} x2={x2} y2={y2}
                pathLength="1000"
                style={{animationDelay:`${400 + (i%12)*40}ms`}} />
            );
          })}
        </g>

        {/* signal pulses — travel along selected synapses */}
        <g className="philo-signals" fill="#A5D8FF" filter="url(#philoGlow)">
          {pulses.map((s,i)=>{
            const [x1,y1] = nodes[s.a]; const [x2,y2] = nodes[s.b];
            return (
              <circle key={i} r="3.5" className="philo-pulse" style={{
                '--x1': x1+'px', '--y1': y1+'px',
                '--x2': x2+'px', '--y2': y2+'px',
                animationDelay: `calc(1200ms + ${s.d})`
              }} />
            );
          })}
        </g>

        {/* neurons / nodes */}
        <g filter="url(#philoGlow)">
          {nodes.map(([x,y],i)=>(
            <circle key={i} className="philo-node" cx={x} cy={y}
              r={i < 16 ? 6 : (i < 21 ? 5 : 4.5)}
              fill="url(#philoNode)"
              style={{animationDelay:`${i*25}ms`}} />
          ))}
        </g>

        {/* Single label */}
        <g className="philo-labels" fill="#6CABDD" fontSize="11" fontWeight="600" letterSpacing="3" textAnchor="middle" opacity="0.7">
          <text x="450" y="660">THINKING THE GAME</text>
        </g>
      </svg>

      <div className="intro-brand intro-brand-bottom">
        <div className="intro-brand-tag">Philosophy</div>
        <div className="intro-brand-name">Proactive football. Structure on the ball.</div>
      </div>
      <div className="intro-flash" />
    </div>
  );
}

/* ====================================================================
   ANALYSIS — Notebook writes itself. Pen draws lines of tactical notes,
   underline accent, diagram sketch.
   ==================================================================== */
function AnalysisIntro({ onDone }) {
  const [phase, setPhase] = useState(0);
  useEffect(() => {
    const t = [
      setTimeout(() => setPhase(1), 50),
      setTimeout(() => setPhase(2), 400),
      setTimeout(() => setPhase(3), 900),
      setTimeout(() => setPhase(4), 1500),
      setTimeout(() => setPhase(5), 2000),
      setTimeout(() => onDone && onDone(), 2500),
    ];
    return () => t.forEach(clearTimeout);
  }, [onDone]);

  return (
    <div className={`intro intro-analysis intro-phase-${phase}`}>
      <div className="intro-spotlight" />

      <div className="notebook">
        <div className="notebook-header">
          <div className="notebook-date">22 · 03 · 2026 — WEMBLEY</div>
          <div className="notebook-rings">
            <span></span><span></span><span></span><span></span><span></span><span></span>
          </div>
        </div>

        <div className="notebook-page">
          {/* Title line with underline sweep */}
          <div className="nb-title">
            <span className="nb-title-text">Arsenal 0 – 2 City</span>
            <span className="nb-title-underline"></span>
          </div>

          {/* Lines of handwriting */}
          <div className="nb-line nb-line-1">
            <span className="nb-handwrite">City in 4-2-4 press. Arsenal's build-up suffocated.</span>
          </div>
          <div className="nb-line nb-line-2">
            <span className="nb-handwrite">Hincapié always the target — forced onto weak foot.</span>
          </div>
          <div className="nb-line nb-line-3">
            <span className="nb-handwrite">O'Reilly: not playing like a left-back → 2 goals.</span>
          </div>

          {/* Small tactical diagram */}
          <svg className="nb-diagram" viewBox="0 0 260 120">
            <g stroke="#6CABDD" strokeWidth="1.8" fill="none" strokeLinecap="round">
              <rect x="6" y="6" width="248" height="108" rx="4" pathLength="1000" className="nb-draw nb-draw-1" />
              <line x1="130" y1="6" x2="130" y2="114" pathLength="1000" className="nb-draw nb-draw-2" />
              <circle cx="130" cy="60" r="20" pathLength="1000" className="nb-draw nb-draw-3" />
            </g>
            <g fill="#6CABDD" className="nb-dots">
              <circle cx="40" cy="30" r="4" />
              <circle cx="40" cy="60" r="4" />
              <circle cx="40" cy="90" r="4" />
              <circle cx="80" cy="45" r="4" />
              <circle cx="80" cy="75" r="4" />
            </g>
            <g stroke="#A5D8FF" strokeWidth="1.4" fill="none" strokeDasharray="4 4" className="nb-arrow" opacity="0">
              <path d="M 80 45 Q 140 20 200 35" />
              <path d="M 195 30 L 200 35 L 196 40" fill="#A5D8FF" />
            </g>
          </svg>
        </div>

        {/* Pen cursor */}
        <div className="pen-cursor"></div>
      </div>

      <div className="intro-brand intro-brand-bottom">
        <div className="intro-brand-tag">Analysis</div>
        <div className="intro-brand-name">Full written pieces, match by match.</div>
      </div>
      <div className="intro-flash" />
    </div>
  );
}

/* ====================================================================
   VISUALS — Tactical pitch drawn with arrows, zones, heat bubbles.
   ==================================================================== */
function VisualsIntro({ onDone }) {
  const [phase, setPhase] = useState(0);
  useEffect(() => {
    const t = [
      setTimeout(() => setPhase(1), 50),
      setTimeout(() => setPhase(2), 400),   // pitch outline
      setTimeout(() => setPhase(3), 800),   // zones fill
      setTimeout(() => setPhase(4), 1200),  // dots
      setTimeout(() => setPhase(5), 1500),  // arrows
      setTimeout(() => setPhase(6), 2000),  // flash
      setTimeout(() => onDone && onDone(), 2500),
    ];
    return () => t.forEach(clearTimeout);
  }, [onDone]);

  return (
    <div className={`intro intro-visuals intro-phase-${phase}`}>
      <div className="intro-spotlight" />
      <svg viewBox="0 0 1200 800" className="intro-vis-svg" preserveAspectRatio="xMidYMid meet">
        <defs>
          <filter id="visGlow"><feGaussianBlur stdDeviation="2.2" result="b" /><feMerge><feMergeNode in="b" /><feMergeNode in="SourceGraphic" /></feMerge></filter>
          <radialGradient id="heatHot">
            <stop offset="0%" stopColor="rgba(255,107,138,0.85)" />
            <stop offset="100%" stopColor="rgba(255,107,138,0)" />
          </radialGradient>
          <radialGradient id="heatMed">
            <stop offset="0%" stopColor="rgba(246,200,75,0.7)" />
            <stop offset="100%" stopColor="rgba(246,200,75,0)" />
          </radialGradient>
          <radialGradient id="heatCold">
            <stop offset="0%" stopColor="rgba(108,171,221,0.65)" />
            <stop offset="100%" stopColor="rgba(108,171,221,0)" />
          </radialGradient>
        </defs>

        {/* Pitch outline — draws in */}
        <g stroke="#6CABDD" strokeWidth="2" fill="none" filter="url(#visGlow)">
          <rect className="vis-draw vis-draw-pitch" x="60" y="60" width="1080" height="680" pathLength="1000" />
          <line className="vis-draw vis-draw-halfway" x1="600" y1="60" x2="600" y2="740" pathLength="1000" />
          <circle className="vis-draw vis-draw-circle" cx="600" cy="400" r="80" pathLength="1000" />
          <rect className="vis-draw vis-draw-box-l" x="60" y="250" width="150" height="300" pathLength="1000" />
          <rect className="vis-draw vis-draw-box-r" x="990" y="250" width="150" height="300" pathLength="1000" />
        </g>

        {/* Zone grid — thirds */}
        <g className="vis-zones" stroke="rgba(108,171,221,0.25)" strokeWidth="1" strokeDasharray="4 6" fill="none">
          <line x1="420" y1="60" x2="420" y2="740" />
          <line x1="780" y1="60" x2="780" y2="740" />
        </g>

        {/* Heat bubbles */}
        <g className="vis-heat" filter="url(#visGlow)">
          <circle cx="250" cy="400" r="90" fill="url(#heatCold)" className="vis-bubble" style={{animationDelay:'0ms'}} />
          <circle cx="500" cy="320" r="70" fill="url(#heatMed)" className="vis-bubble" style={{animationDelay:'80ms'}} />
          <circle cx="600" cy="500" r="80" fill="url(#heatMed)" className="vis-bubble" style={{animationDelay:'150ms'}} />
          <circle cx="850" cy="280" r="75" fill="url(#heatHot)" className="vis-bubble" style={{animationDelay:'250ms'}} />
          <circle cx="920" cy="420" r="95" fill="url(#heatHot)" className="vis-bubble" style={{animationDelay:'340ms'}} />
          <circle cx="1000" cy="550" r="55" fill="url(#heatMed)" className="vis-bubble" style={{animationDelay:'420ms'}} />
        </g>

        {/* Player dots */}
        <g className="vis-dots" fill="#A5D8FF" filter="url(#visGlow)">
          {[[180,250],[180,400],[180,550],[380,200],[380,400],[380,600],[620,300],[620,500],[820,250],[820,550],[980,400]].map(([x,y],i)=>(
            <circle key={i} cx={x} cy={y} r="6" style={{animationDelay:`${i*50}ms`}} />
          ))}
        </g>

        {/* Pass arrows — draw in with arrowheads */}
        <g className="vis-arrows" stroke="#6CABDD" strokeWidth="2" fill="none" filter="url(#visGlow)">
          <path className="vis-arrow vis-arrow-1" d="M 180 400 Q 300 330 380 400" pathLength="1000" strokeDasharray="0" />
          <path className="vis-arrow vis-arrow-2" d="M 380 400 Q 500 340 620 300" pathLength="1000" />
          <path className="vis-arrow vis-arrow-3" d="M 620 300 Q 720 260 820 250" pathLength="1000" />
          <path className="vis-arrow vis-arrow-4" d="M 820 250 Q 900 280 920 420" pathLength="1000" />
          <path className="vis-arrow vis-arrow-5" d="M 920 420 L 980 400" pathLength="1000" />
        </g>

        {/* Shot */}
        <g className="vis-shot" filter="url(#visGlow)">
          <line x1="980" y1="400" x2="1100" y2="400" stroke="#FF6B8A" strokeWidth="2.5" strokeDasharray="2 4" className="vis-shot-line" pathLength="1000" />
          <circle cx="1100" cy="400" r="8" fill="#FF6B8A" className="vis-shot-hit" />
          <text x="1050" y="385" fill="#FF6B8A" fontSize="11" fontWeight="700" letterSpacing="2" className="vis-shot-label" opacity="0">GOAL</text>
        </g>
      </svg>

      <div className="intro-brand intro-brand-bottom">
        <div className="intro-brand-tag">Visual Work</div>
        <div className="intro-brand-name">A selection from the portfolio.</div>
      </div>
      <div className="intro-flash" />
    </div>
  );
}

/* ====================================================================
   DATA — Terminal / code loads. Lines of Python scroll in.
   ==================================================================== */
function DataIntro({ onDone }) {
  const [lineCount, setLineCount] = useState(0);
  const [phase, setPhase] = useState(0);

  const codeLines = [
    { n: '  1', c: [['kw','import'], ['sp',' pandas '], ['kw','as'], ['sp',' pd']] },
    { n: '  2', c: [['kw','import'], ['sp',' matplotlib.pyplot '], ['kw','as'], ['sp',' plt']] },
    { n: '  3', c: [['kw','from'], ['sp',' mplsoccer '], ['kw','import'], ['sp',' Pitch, VerticalPitch']] },
    { n: '  4', c: [['kw','from'], ['sp',' statsbombpy '], ['kw','import'], ['sp',' sb']] },
    { n: '  5', c: [] },
    { n: '  6', c: [['co','# Pull touch locations — EFL Cup Final']] },
    { n: '  7', c: [['va','events'], ['op',' = '], ['fn','sb.events'], ['op','('], ['nu','3895302'], ['op',')']] },
    { n: '  8', c: [['va','passes'], ['op',' = '], ['va','events'], ['op','['], ['va','events'], ['op','.type '], ['op','== '], ['st','"Pass"'], ['op',']']] },
    { n: '  9', c: [['va','shots'],  ['op',' = '], ['va','events'], ['op','['], ['va','events'], ['op','.type '], ['op','== '], ['st','"Shot"'], ['op',']']] },
    { n: ' 10', c: [] },
    { n: ' 11', c: [['co','# Build xT grid from end coords']] },
    { n: ' 12', c: [['va','xt'], ['op',' = '], ['fn','build_xt_grid'], ['op','('], ['va','passes'], ['op',', '], ['nu','bins=(16,12)'], ['op',')']] },
    { n: ' 13', c: [['fn','print'], ['op','('], ['st','f"total xT added: "'], ['op',' + '], ['fn','str'], ['op','('], ['va','xt'], ['op','.sum())']] },
    { n: ' 14', c: [['co','> total xT added: 3.412'], { cls:'stdout' }] },
    { n: ' 15', c: [] },
    { n: ' 16', c: [['va','pitch'], ['op',' = '], ['fn','Pitch'], ['op','('], ['kw','pitch_type='], ['st','"statsbomb"'], ['op',', '], ['kw','line_color='], ['st','"#6CABDD"'], ['op',')']] },
    { n: ' 17', c: [['va','fig'], ['op',', '], ['va','ax'], ['op',' = '], ['va','pitch'], ['op','.'], ['fn','draw'], ['op','('], ['kw','figsize='], ['op','('], ['nu','12'], ['op',', '], ['nu','8'], ['op','))']] },
    { n: ' 18', c: [['va','pitch'], ['op','.'], ['fn','heatmap'], ['op','('], ['va','xt'], ['op',', '], ['va','ax'], ['op','='], ['va','ax'], ['op',', '], ['kw','cmap='], ['st','"Blues"'], ['op',')']] },
    { n: ' 19', c: [['fn','plt.savefig'], ['op','('], ['st','"10_xt_zones.png"'], ['op',', '], ['kw','dpi='], ['nu','300'], ['op',')']] },
    { n: ' 20', c: [['co','✓ saved — 10_xt_zones.png (2.1MB)'], { cls:'stdout-ok' }] },
  ];

  useEffect(() => {
    setPhase(1);
    let i = 0;
    const interval = setInterval(() => {
      i++;
      setLineCount(i);
      if (i >= codeLines.length) {
        clearInterval(interval);
        setTimeout(() => setPhase(2), 300);
        setTimeout(() => onDone && onDone(), 900);
      }
    }, 85);
    return () => clearInterval(interval);
  }, [onDone]);

  return (
    <div className={`intro intro-data intro-phase-${phase}`}>
      <div className="intro-spotlight" />

      <div className="terminal">
        <div className="terminal-bar">
          <div className="terminal-dots"><span></span><span></span><span></span></div>
          <div className="terminal-title">build_visuals.py — python 3.11</div>
          <div className="terminal-meta">~/analysis/efl-cup-final</div>
        </div>
        <div className="terminal-body">
          {codeLines.slice(0, lineCount).map((line, i) => {
            const cls = line.c.find(x => x && x.cls);
            return (
              <div key={i} className={`code-line ${cls ? cls.cls : ''}`}>
                <span className="ln">{line.n}</span>
                <span className="lc">
                  {line.c.filter(c => Array.isArray(c)).map((tok, j) => (
                    <span key={j} className={`tok tok-${tok[0]}`}>{tok[1]}</span>
                  ))}
                  {i === lineCount - 1 && <span className="caret">▋</span>}
                </span>
              </div>
            );
          })}
        </div>
      </div>

      <div className="intro-brand intro-brand-bottom">
        <div className="intro-brand-tag">Data Methodology</div>
        <div className="intro-brand-name">Free, public data. Processed in Python.</div>
      </div>
      <div className="intro-flash" />
    </div>
  );
}

Object.assign(window, {
  PitchIntro, AboutIntro, PhilosophyIntro, AnalysisIntro, VisualsIntro, DataIntro
});
