// Telemetry + Circuit + Surfaces sections — F1-authentic visuals

// ==============================================================
// TELEMETRY SECTION — actual (solid) vs predicted (dashed)
// ==============================================================
function TelemetrySection() {
  const [channel, setChannel] = useState('pace');
  const [hover, setHover] = useState(null);
  const [drawn, setDrawn] = useState(false);
  const svgRef = useRef(null);
  const sectionRef = useRef(null);

  useEffect(() => {
    if (drawn) return;
    const el = sectionRef.current;
    if (!el) return;
    const obs = new IntersectionObserver((entries) => {
      for (const e of entries) {
        if (e.isIntersecting) {
          setDrawn(true);
          obs.disconnect();
          return;
        }
      }
    }, { threshold: 0.3 });
    obs.observe(el);
    return () => obs.disconnect();
  }, [drawn]);

  const channels = {
    pace: {
      label: 'Pace · lap time',
      unit: 's',
      yMin: 86.4, yMax: 90.2,
      color: '#a29bfe',
      domain: 'Lap',
      xTicks: [1, 10, 20, 30, 40, 50, 60],
      // actual series (48 laps) + predicted future (laps 49..66)
      actual: Array.from({ length: 48 }, (_, i) => {
        const n = i + 1;
        let t = 87.2;
        if (n <= 21) t += (n - 1) * 0.08;
        else if (n <= 37) t += 0.35 + (n - 22) * 0.07;
        else t += 0.2 + (n - 38) * 0.05;
        t += Math.sin(n * 0.6) * 0.15 + Math.cos(n * 1.3) * 0.08;
        return { x: n, y: t };
      }),
      predicted: Array.from({ length: 66 - 48 + 1 }, (_, i) => {
        const n = 48 + i;
        return { x: n, y: 88.1 + Math.sin(n * 0.4) * 0.12 + (n - 48) * 0.03 };
      }),
      band: 0.25,
    },
    tire: {
      label: 'Tire degradation · wear',
      unit: '%',
      yMin: 0, yMax: 100,
      color: '#ff2d3a',
      domain: 'Lap',
      xTicks: [1, 10, 20, 30, 40, 50, 60],
      actual: Array.from({ length: 48 }, (_, i) => {
        const n = i + 1;
        // resets at pit stops lap 21, 37
        let base = n <= 21 ? (n - 1) * 4.2 : n <= 37 ? (n - 22) * 3.3 : (n - 38) * 3.0;
        return { x: n, y: Math.min(98, base + Math.sin(n * 0.7) * 1.2) };
      }),
      predicted: Array.from({ length: 66 - 48 + 1 }, (_, i) => {
        const n = 48 + i;
        const base = (n - 38) * 3.0;
        return { x: n, y: Math.min(100, base + i * 0.5) };
      }),
      band: 4.5,
    },
  };

  const ch = channels[channel];
  const W = 900, H = 320, pad = { l: 48, r: 32, t: 24, b: 40 };
  const iw = W - pad.l - pad.r, ih = H - pad.t - pad.b;
  const allX = [...ch.actual, ...ch.predicted];
  const xMin = Math.min(...allX.map(p => p.x));
  const xMax = Math.max(...allX.map(p => p.x));
  const xs = x => pad.l + ((x - xMin) / (xMax - xMin)) * iw;
  const ys = y => pad.t + (1 - (y - ch.yMin) / (ch.yMax - ch.yMin)) * ih;

  const pathOf = (pts) => pts.map((p, i) => `${i === 0 ? 'M' : 'L'}${xs(p.x).toFixed(1)},${ys(p.y).toFixed(1)}`).join(' ');
  const bandPath = (pts, b) => {
    const up = pts.map(p => `${xs(p.x).toFixed(1)},${ys(p.y + b).toFixed(1)}`);
    const dn = pts.slice().reverse().map(p => `${xs(p.x).toFixed(1)},${ys(p.y - b).toFixed(1)}`);
    return `M${up.join('L')}L${dn.join('L')}Z`;
  };

  const onMove = (e) => {
    const rect = svgRef.current.getBoundingClientRect();
    const mx = ((e.clientX - rect.left) / rect.width) * W;
    if (mx < pad.l || mx > W - pad.r) { setHover(null); return; }
    const xv = xMin + ((mx - pad.l) / iw) * (xMax - xMin);
    // nearest point
    const all = [...ch.actual, ...ch.predicted];
    let best = all[0], bd = Infinity;
    for (const p of all) {
      const d = Math.abs(p.x - xv);
      if (d < bd) { bd = d; best = p; }
    }
    const isPred = ch.predicted.includes(best);
    setHover({ ...best, isPred });
  };

  return (
    <section ref={sectionRef} className={`section ${drawn ? 'telemetry-drawn' : ''}`} id="telemetry" style={{ background: 'var(--bg-1)', borderTop: '1px solid var(--hairline)', borderBottom: '1px solid var(--hairline)' }}>
      <div className="container-wide">
        <div className="section-head left telemetry-head" style={{ display: 'grid', gridTemplateColumns: '1fr auto', alignItems: 'end', marginBottom: 40, maxWidth: '100%', gap: 24 }}>
          <div>
            <span className="eyebrow"><span className="eyebrow-bar"/>Telemetry</span>
            <h2 style={{ marginTop: 20 }}>What happened. What's next.</h2>
          </div>
          <div style={{ display: 'flex', gap: 6, padding: 4, background: 'var(--bg-2)', border: '1px solid var(--divider)', borderRadius: 10 }}>
            {[['pace', 'Pace'], ['tire', 'Tire']].map(([k, l]) => (
              <button key={k} onClick={() => setChannel(k)} style={{
                padding: '8px 14px', fontSize: 12, fontFamily: 'var(--font-mono)',
                background: channel === k ? 'var(--purple-600)' : 'transparent',
                color: channel === k ? '#fff' : 'var(--fg-2)',
                border: 'none', borderRadius: 6, cursor: 'pointer', transition: 'all 0.15s'
              }}>{l}</button>
            ))}
          </div>
        </div>

        <div style={{
          background: 'var(--bg-2)',
          border: '1px solid var(--divider)',
          borderRadius: 16,
          overflow: 'hidden',
          boxShadow: '0 20px 50px rgba(0,0,0,0.3)'
        }}>
          {/* header */}
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '16px 22px', borderBottom: '1px solid var(--hairline)', background: 'var(--bg-3)', flexWrap: 'wrap', gap: 12 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
              <span style={{ fontFamily: 'var(--font-display)', fontSize: 15, fontWeight: 500, letterSpacing: '-0.01em' }}>{ch.label}</span>
              <span className="pill pill-live"><span className="pill-dot"/>lap 48/66</span>
            </div>
            <div style={{ display: 'flex', gap: 18, fontFamily: 'var(--font-mono)', fontSize: 11 }}>
              <span style={{ display: 'flex', alignItems: 'center', gap: 6, color: 'var(--fg-2)' }}>
                <svg width="24" height="2"><line x1="0" x2="24" y1="1" y2="1" stroke={ch.color} strokeWidth="2"/></svg> actual
              </span>
              {ch.predicted.length > 0 && (
                <span style={{ display: 'flex', alignItems: 'center', gap: 6, color: 'var(--fg-2)' }}>
                  <svg width="24" height="2"><line x1="0" x2="24" y1="1" y2="1" stroke={ch.color} strokeWidth="2" strokeDasharray="4 3"/></svg> predicted
                </span>
              )}
              {ch.band > 0 && (
                <span style={{ display: 'flex', alignItems: 'center', gap: 6, color: 'var(--fg-2)' }}>
                  <span style={{ width: 24, height: 10, background: ch.color, opacity: 0.2, borderRadius: 2 }}/> P10/P90
                </span>
              )}
            </div>
          </div>

          {/* chart */}
          <div style={{ position: 'relative', padding: 8 }}>
            <svg ref={svgRef} viewBox={`0 0 ${W} ${H}`} style={{ width: '100%', height: 'auto', display: 'block', cursor: 'crosshair' }}
                 onMouseMove={onMove} onMouseLeave={() => setHover(null)}>
              <defs>
                <linearGradient id="areaFill" x1="0" y1="0" x2="0" y2="1">
                  <stop offset="0%" stopColor={ch.color} stopOpacity="0.22"/>
                  <stop offset="100%" stopColor={ch.color} stopOpacity="0"/>
                </linearGradient>
              </defs>

              {/* gridlines */}
              {[0, 0.25, 0.5, 0.75, 1].map((p, i) => (
                <line key={i} x1={pad.l} x2={W - pad.r}
                      y1={pad.t + p * ih} y2={pad.t + p * ih}
                      stroke="rgba(255,255,255,0.05)" strokeWidth="1"/>
              ))}
              {/* y labels */}
              {[0, 0.25, 0.5, 0.75, 1].map((p, i) => {
                const v = ch.yMin + (1 - p) * (ch.yMax - ch.yMin);
                return (
                  <text key={i} x={pad.l - 10} y={pad.t + p * ih + 4} textAnchor="end"
                        fontFamily="var(--font-mono)" fontSize="10" fill="rgba(255,255,255,0.35)">
                    {v.toFixed(channel === 'pace' ? 1 : 0)}
                  </text>
                );
              })}
              {/* x ticks */}
              {ch.xTicks.map(t => (
                <g key={t}>
                  <line x1={xs(t)} x2={xs(t)} y1={pad.t + ih} y2={pad.t + ih + 4} stroke="rgba(255,255,255,0.2)"/>
                  <text x={xs(t)} y={pad.t + ih + 18} textAnchor="middle"
                        fontFamily="var(--font-mono)" fontSize="10" fill="rgba(255,255,255,0.4)">{t}</text>
                </g>
              ))}
              <text x={pad.l + iw / 2} y={H - 6} textAnchor="middle"
                    fontFamily="var(--font-mono)" fontSize="10" fill="rgba(255,255,255,0.4)"
                    letterSpacing="0.14em">
                {ch.domain.toUpperCase()}
              </text>

              {/* stint dividers for pace/tire */}
              {[21, 37].map(lap => (
                <g key={lap}>
                  <line x1={xs(lap)} x2={xs(lap)} y1={pad.t} y2={pad.t + ih}
                        stroke="rgba(255,255,255,0.14)" strokeDasharray="2 3"/>
                  <text x={xs(lap) + 4} y={pad.t + 12} fontFamily="var(--font-mono)"
                        fontSize="9" fill="rgba(255,255,255,0.35)">PIT</text>
                </g>
              ))}

              {/* area under actual */}
              {(() => {
                const area = ch.actual.map((p, i) => `${i === 0 ? 'M' : 'L'}${xs(p.x).toFixed(1)},${ys(p.y).toFixed(1)}`).join(' ')
                  + ` L${xs(ch.actual[ch.actual.length - 1].x).toFixed(1)},${(pad.t + ih).toFixed(1)} L${xs(ch.actual[0].x).toFixed(1)},${(pad.t + ih).toFixed(1)} Z`;
                return <path className="telemetry-fade" d={area} fill="url(#areaFill)"/>;
              })()}

              {/* prediction uncertainty band — uses fillOpacity so the CSS
                  reveal animation (which sets the element's opacity 0→1)
                  doesn't clobber the 12% band transparency. */}
              {ch.band > 0 && ch.predicted.length > 0 && (
                <path className="telemetry-fade" d={bandPath(ch.predicted, ch.band)} fill={ch.color} fillOpacity="0.18"/>
              )}

              {/* actual line (continuous) */}
              <path className="telemetry-actual" d={pathOf(ch.actual)} pathLength="1"
                    fill="none" stroke={ch.color} strokeWidth="2" strokeLinecap="round"
                    style={{ filter: `drop-shadow(0 0 8px ${ch.color}80)` }}/>

              {/* predicted line (dashed) — starts from the NOW point so the dash
                  pattern is continuous from last-actual into the forecast.
                  No drop-shadow here: a same-color glow bleeds into the 4-5 px
                  gaps between dashes and makes the line read as solid. */}
              {ch.predicted.length > 0 && (
                <g className="telemetry-post">
                  <path d={pathOf([ch.actual[ch.actual.length - 1], ...ch.predicted])}
                        fill="none" stroke={ch.color} strokeWidth="2"
                        strokeDasharray="7 5" strokeLinecap="butt" opacity="1"/>
                </g>
              )}

              {/* "now" marker */}
              <g className="telemetry-post">
                <line x1={xs(ch.actual[ch.actual.length - 1].x)} x2={xs(ch.actual[ch.actual.length - 1].x)}
                      y1={pad.t} y2={pad.t + ih} stroke="rgba(255,255,255,0.3)" strokeDasharray="1 3"/>
                <circle cx={xs(ch.actual[ch.actual.length - 1].x)} cy={ys(ch.actual[ch.actual.length - 1].y)}
                        r="4" fill="#fff" stroke={ch.color} strokeWidth="2"/>
                <text x={xs(ch.actual[ch.actual.length - 1].x) + 8} y={pad.t + 14}
                      fontFamily="var(--font-mono)" fontSize="9" fill="rgba(255,255,255,0.55)"
                      letterSpacing="0.14em">NOW</text>
              </g>

              {/* hover crosshair */}
              {hover && (() => {
                const hx = xs(hover.x), hy = ys(hover.y);
                return (
                  <g pointerEvents="none">
                    <line x1={hx} x2={hx} y1={pad.t} y2={pad.t + ih} stroke="rgba(255,255,255,0.4)" strokeWidth="1"/>
                    <circle cx={hx} cy={hy} r="5" fill={ch.color} stroke="#0c0d14" strokeWidth="2"/>
                    <g transform={`translate(${Math.min(hx + 10, W - pad.r - 130)}, ${Math.max(hy - 38, pad.t + 6)})`}>
                      <rect width="120" height="42" rx="6" fill="#0c0d14" stroke="rgba(255,255,255,0.18)"/>
                      <text x="12" y="18" fontFamily="var(--font-mono)" fontSize="10" fill="rgba(255,255,255,0.5)">
                        {ch.domain} {hover.x.toFixed(0)}{hover.isPred ? ' · PRED' : ''}
                      </text>
                      <text x="12" y="34" fontFamily="var(--font-display)" fontSize="14" fill="#fff" fontWeight="500">
                        {hover.y.toFixed(channel === 'pace' ? 3 : 1)}{ch.unit}
                      </text>
                    </g>
                  </g>
                );
              })()}
            </svg>
          </div>

          {/* readout strip */}
          <div className="telemetry-readout" style={{
            display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)',
            borderTop: '1px solid var(--hairline)', background: 'var(--bg-1)'
          }}>
            {[
              ['Compound', 'Hard'],
              ['Lap', '48 / 66'],
              ['Delta', channel === 'pace' ? '+0.284s' : '33.0%'],
              ['Model conf.', '0.87'],
            ].map(([k, v], i) => (
              <div key={k} style={{
                padding: '14px 18px',
                borderLeft: i > 0 ? '1px solid var(--hairline)' : 'none'
              }}>
                <div className="mono" style={{ fontSize: 10, color: 'var(--fg-4)', letterSpacing: '0.12em', textTransform: 'uppercase', marginBottom: 4 }}>{k}</div>
                <div style={{ fontFamily: 'var(--font-display)', fontSize: 16, fontWeight: 500, color: '#fff' }}>{v}</div>
              </div>
            ))}
          </div>
        </div>
      </div>
      <style>{`
        @media (max-width: 780px) {
          #telemetry .telemetry-head { grid-template-columns: 1fr !important; gap: 16px; }
        }
        @media (max-width: 640px) {
          #telemetry .telemetry-readout { grid-template-columns: repeat(2, 1fr) !important; }
        }
        #telemetry .telemetry-actual {
          stroke-dasharray: 1;
          stroke-dashoffset: 1;
        }
        #telemetry.telemetry-drawn .telemetry-actual {
          stroke-dashoffset: 0;
          transition: stroke-dashoffset 1.3s cubic-bezier(0.4, 0, 0.2, 1);
        }
        #telemetry .telemetry-fade { opacity: 0; }
        #telemetry.telemetry-drawn .telemetry-fade {
          opacity: 1;
          transition: opacity 0.6s ease 0.3s;
        }
        #telemetry .telemetry-post { opacity: 0; }
        #telemetry.telemetry-drawn .telemetry-post {
          opacity: 1;
          transition: opacity 0.55s ease 1.1s;
        }
        @media (prefers-reduced-motion: reduce) {
          #telemetry .telemetry-actual { stroke-dasharray: none; stroke-dashoffset: 0; }
          #telemetry .telemetry-fade, #telemetry .telemetry-post { opacity: 1; transition: none; }
        }
      `}</style>
    </section>
  );
}

// ==============================================================
// CIRCUIT SECTION — animated track + moving cars
// ==============================================================
// Albert Park — Australian GP, Melbourne (official 2022 layout).
// Paths extracted from Wikimedia SVG (assets/albert-park-2022.svg).
// Original viewBox: 0 0 607.8 385.1.
// The st0 path is drawn in RACING DIRECTION: it starts at (455.8, 309.4)
// on the bottom straight just past T14, heads left through T1 (226.5,
// 328.5), up through T2 (237.8, 275.1), T3 (39.9, 273.6), T4 (96.1,
// 230.5), T5 (16.7, 195.9), up and right through T6/T7/T8 at the top,
// down through T9/T10 to the right, around the T11 hairpin, back through
// T12/T13/T14 and closes to the start. Increasing f = racing direction.
const TRACK_PATH = "M455.8,309.4c-7.8,0.6-207.3,5.5-209.8,5.7c-2.5,0.2-5.5-0.5-6.2-1.4c-0.7-0.9-2.1-5.3-2.7-8.2c-0.7-3-5.7-11.2-12.1-14.9c-6.4-3.7-14.9-6.6-29-4.8c-14.2,1.8-48.9,1.6-62.4,0.2c-13.5-1.4-38.6-5.9-46.9-8c-8.2-2.1-18.1-4.6-20.3-5.7c-2.3-1.1-5.7-1.6-6.4-5.9c-0.7-4.3,0.9-5,2.5-7.8c1.6-2.7,11.4-16.2,12.8-18.3c1.4-2.1,1.8-3.2,1.8-5.7s-0.7-4.1-3-6.2c-2.3-2.1-31.7-28.8-34.3-31.5c-3-3.2-5.3-5.7-4.8-12.6c0.5-6.9,2.5-18.3,3-23.8c0.5-5.5,1.8-13.3,3.4-18.1c1.6-4.8,3.9-9.4,7.3-17.6c3.4-8.2,7.5-17.1,8.7-21.7c1.1-4.6,3.2-14.2,3.7-17.6c0.5-3.4,1.6-7.3,7.5-6.9c5.9,0.5,16.9-0.5,24.5-6.4c7.5-5.9,20.6-22.2,42.3-22.2s33.6,9.8,41.4,15.1s21.5,15.3,26.5,20.3c5,5,12.8,12.3,26.3,45.5c10.6,26.1,19.3,38.9,40.7,53.2c26.3,17.6,43.2,15.1,71.1,13.7c9.4-0.5,20.8-1.6,25.6-2.1s7.1-2.3,9.4-5.5c2.3-3.2,12.3-16.9,13.7-19c1.4-2.1,2.5-4.1,9.1-4.6c6.6-0.5,53.5-4.8,60.3-5c6.9-0.2,18.7-0.2,33.4,6.6c14.6,6.9,62.4,32.2,66.3,34.3c3.9,2.1,10.3,6.4,11.7,7.8c1.4,1.4,3.2,3.7,1.4,7.3c-1.8,3.7-16.5,26.7-18.7,32.5c-2.3,5.7-5.7,12.1-8.5,16.5c-2.7,4.3-9.1,13-21.3,10.1c-12.1-3-43-11-45.7-11.4c-2.7-0.5-7.1-1.1-7.1,3.9c0,5,1.4,18.5,1.6,25.4C472.7,301.7,465.4,308.7,455.8,309.4z";

// Official F1 sector breakdown (from the Wikimedia SVG overlays):
//   S1 (red,    st3): S/F → T1 → T2 → T3 → T4 → T5 → part of T6 approach
//   S2 (blue,   st2): from end of S1 up through T6/T7/T8 to just before T9
//   S3 (yellow, st1): T9 → T10 → T11 → T12 → T13 → T14 → S/F
const SECTOR_PATHS = {
  s1: "M344.5,312.5c-49.6,1.3-97.3,2.5-98.5,2.6c-2.5,0.2-5.5-0.5-6.2-1.4c-0.7-0.9-2.1-5.3-2.7-8.2c-0.7-3-5.7-11.2-12.1-14.9c-6.4-3.7-14.9-6.6-29-4.8c-14.2,1.8-48.9,1.6-62.4,0.2c-13.5-1.4-38.6-5.9-46.9-8c-8.2-2.1-18.1-4.6-20.3-5.7c-2.3-1.1-5.7-1.6-6.4-5.9c-0.7-4.3,0.9-5,2.5-7.8c1.6-2.7,11.4-16.2,12.8-18.3c1.4-2.1,1.8-3.2,1.8-5.7s-0.7-4.1-3-6.2c-2.3-2.1-31.7-28.8-34.3-31.5c-3-3.2-5.3-5.7-4.8-12.6c0.5-6.9,2.5-18.3,3-23.8c0.5-5.5,1.8-13.3,3.4-18.1c1.6-4.8,3.9-9.4,7.3-17.6c3.4-8.2,7.5-17.1,8.7-21.7",
  s2: "M57.4,103.3c1.1-4.6,3.2-14.2,3.7-17.6c0.5-3.4,1.6-7.3,7.5-6.9c5.9,0.5,16.9-0.5,24.5-6.4c7.5-5.9,20.6-22.2,42.3-22.2s33.6,9.8,41.4,15.1s21.5,15.3,26.5,20.3c5,5,12.8,12.3,26.3,45.5c10.6,26.1,19.3,38.9,40.7,53.2c26.3,17.6,43.2,15.1,71.1,13.7",
  s3: "M341.3,198.1c9.4-0.5,20.8-1.6,25.6-2.1s7.1-2.3,9.4-5.5c2.3-3.2,12.3-16.9,13.7-19c1.4-2.1,2.5-4.1,9.1-4.6c6.6-0.5,53.5-4.8,60.3-5c6.9-0.2,18.7-0.2,33.4,6.6c14.6,6.9,62.4,32.2,66.3,34.3c3.9,2.1,10.3,6.4,11.7,7.8c1.4,1.4,3.2,3.7,1.4,7.3c-1.8,3.7-16.5,26.7-18.7,32.5c-2.3,5.7-5.7,12.1-8.5,16.5c-2.7,4.3-9.1,13-21.3,10.1c-12.1-3-43-11-45.7-11.4c-2.7-0.5-7.1-1.1-7.1,3.9c0,5,1.4,18.5,1.6,25.4c0.2,6.9-7.1,13.9-16.7,14.6c-4,0.3-58.7,1.7-111.3,3.1",
};

// Official Albert Park 2022 corner positions in SVG natural coords
// (extracted from <g id="コーナー番号"> circles in the source SVG).
const CORNERS = [
  { n: 1,  x: 226.5, y: 328.5 },
  { n: 2,  x: 237.8, y: 275.1 },
  { n: 3,  x:  39.9, y: 273.6 },
  { n: 4,  x:  96.1, y: 230.5 },
  { n: 5,  x:  16.7, y: 195.9 },
  { n: 6,  x:  49.2, y:  66.7 },
  { n: 7,  x: 106.3, y:  89.0 },
  { n: 8,  x: 141.8, y:  30.8 },
  { n: 9,  x: 380.6, y: 212.5 },
  { n: 10, x: 380.5, y: 154.4 },
  { n: 11, x: 591.1, y: 210.0 },
  { n: 12, x: 540.3, y: 295.3 },
  { n: 13, x: 458.8, y: 252.8 },
  { n: 14, x: 479.0, y: 320.9 },
];

// Fit 607.8 × 385.1 into 1020 × 520 with 4% padding.
const TRACK_NAT_W = 607.8, TRACK_NAT_H = 385.1;
const FIT = Math.min(1020 / TRACK_NAT_W, 520 / TRACK_NAT_H) * 0.96;
const TRACK_TX = (1020 - TRACK_NAT_W * FIT) / 2;
const TRACK_TY = (520 - TRACK_NAT_H * FIT) / 2;
const TRACK_TRANSFORM = `translate(${TRACK_TX}, ${TRACK_TY}) scale(${FIT})`;
// Helper to transform natural corner coords into 1020×520 viewBox coords.
const toViewBox = (x, y) => ({ x: TRACK_TX + x * FIT, y: TRACK_TY + y * FIT });


function CircuitSection() {
  const pathRef = useRef(null);
  const [len, setLen] = useState(0);
  const [t, setT] = useState(0);
  const [focus, setFocus] = useState('LEC');
  const rafRef = useRef();

  useEffect(() => {
    if (pathRef.current) setLen(pathRef.current.getTotalLength());
  }, []);

  useEffect(() => {
    let last = performance.now();
    const loop = (now) => {
      const dt = (now - last) / 1000; last = now;
      // The official Albert Park path is drawn in racing direction, so
      // INCREASING t follows the racing line (T14 → T1 → T2 → ...).
      setT(x => (x + dt * 0.06) % 1); // ~17s lap
      rafRef.current = requestAnimationFrame(loop);
    };
    rafRef.current = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(rafRef.current);
  }, []);

  const cars = [
    { code: 'VER', team: 'Red Bull',  color: '#1e5bc6', gap: 0.00, label: 'P1' },
    { code: 'HAM', team: 'Mercedes',  color: '#00d7b5', gap: 0.04, label: 'P2' },
    { code: 'LEC', team: 'Ferrari',   color: '#ff2d3a', gap: 0.075, label: 'P3', highlight: true },
    { code: 'SAI', team: 'Ferrari',   color: '#ff2d3a', gap: 0.092, label: 'P4' },
    { code: 'NOR', team: 'McLaren',   color: '#ff8000', gap: 0.12, label: 'P5' },
    { code: 'RUS', team: 'Mercedes',  color: '#00d7b5', gap: 0.15, label: 'P6' },
  ];

  const pointAt = (frac) => {
    if (!pathRef.current || !len) return { x: 0, y: 0, angle: 0 };
    const p1 = pathRef.current.getPointAtLength(frac * len);
    const p2 = pathRef.current.getPointAtLength(((frac + 0.001) % 1) * len);
    const angle = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
    return { x: p1.x, y: p1.y, angle };
  };

  // Sector colors (match the Wikimedia reference: red S1, blue S2, yellow S3).
  const SECTOR_COLORS = { s1: '#ff2d3a', s2: '#2d8fff', s3: '#ffcf2d' };

  return (
    <section className="section" id="circuit">
      <div className="container-wide">
        <div className="section-head left circuit-head" style={{ display: 'grid', gridTemplateColumns: '1fr auto', alignItems: 'end', marginBottom: 40, maxWidth: '100%', gap: 24 }}>
          <div>
            <span className="eyebrow"><span className="eyebrow-bar"/>Track model</span>
            <h2 style={{ marginTop: 20 }}>The field, in real time.</h2>
          </div>
          <p style={{ maxWidth: 420, margin: 0 }}>
            The orchestrator sees every car's sector pace, gap delta, and compound — and recomputes every lap.
          </p>
        </div>

        <div style={{
          display: 'grid', gridTemplateColumns: '1fr 320px', gap: 20,
          background: 'var(--bg-2)', border: '1px solid var(--divider)',
          borderRadius: 18, overflow: 'hidden',
          boxShadow: '0 30px 70px rgba(0,0,0,0.35)'
        }} className="circuit-layout">

          {/* TRACK CANVAS */}
          <div style={{ padding: 24, borderRight: '1px solid var(--hairline)', position: 'relative' }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
              <div>
                <div className="mono" style={{ fontSize: 10, color: 'var(--fg-4)', letterSpacing: '0.14em', textTransform: 'uppercase' }}>Melbourne · Albert Park</div>
                <div style={{ fontFamily: 'var(--font-display)', fontSize: 20, fontWeight: 500, letterSpacing: '-0.01em', marginTop: 4 }}>Lap 32 / 58</div>
              </div>
              <span className="pill pill-live"><span className="pill-dot"/>live replay</span>
            </div>

            <svg viewBox="0 0 1020 520" style={{ width: '100%', height: 'auto', display: 'block' }}>
              <defs>
                <linearGradient id="trackGlow" x1="0%" y1="0%" x2="100%" y2="100%">
                  <stop offset="0%" stopColor="rgba(108,92,231,0.18)"/>
                  <stop offset="100%" stopColor="rgba(51,133,255,0.1)"/>
                </linearGradient>
              </defs>

              <g transform={TRACK_TRANSFORM}>
              {/* Track outline — dark base that receives the sector overlays. */}
              <path d={TRACK_PATH} fill="none" stroke="rgba(255,255,255,0.12)"
                    strokeWidth="8" strokeLinecap="round" strokeLinejoin="round"/>
              {/* Hidden reference copy used for measuring car positions. */}
              <path ref={pathRef} d={TRACK_PATH} fill="none" stroke="transparent" strokeWidth="0"/>

              {/* Sector 3 — yellow (T9 → S/F) */}
              <path d={SECTOR_PATHS.s3} fill="none" stroke={SECTOR_COLORS.s3}
                    strokeWidth="4" strokeLinecap="round" strokeLinejoin="round" opacity="0.92"/>
              {/* Sector 2 — blue (T6 → T9) */}
              <path d={SECTOR_PATHS.s2} fill="none" stroke={SECTOR_COLORS.s2}
                    strokeWidth="4" strokeLinecap="round" strokeLinejoin="round" opacity="0.92"/>
              {/* Sector 1 — red (S/F → T6) */}
              <path d={SECTOR_PATHS.s1} fill="none" stroke={SECTOR_COLORS.s1}
                    strokeWidth="4" strokeLinecap="round" strokeLinejoin="round" opacity="0.92"/>
              </g>

              {/* Start/finish line — midpoint between T14 and T1, drawn in
                  viewBox coords so stroke width is not distorted by the scale. */}
              {(() => {
                const c1 = CORNERS.find(c => c.n === 1);
                const c14 = CORNERS.find(c => c.n === 14);
                const midX = (c1.x + c14.x) / 2, midY = (c1.y + c14.y) / 2;
                const p = toViewBox(midX, midY);
                return (
                  <g>
                    <line x1={p.x} y1={p.y - 14} x2={p.x} y2={p.y + 14}
                          stroke="#fff" strokeWidth="2"/>
                    <text x={p.x} y={p.y - 20} textAnchor="middle"
                          fontFamily="var(--font-mono)" fontSize="10"
                          fill="rgba(255,255,255,0.85)" letterSpacing="0.14em">S/F</text>
                  </g>
                );
              })()}

              {/* Corner markers — official positions from the 2022 layout. */}
              {CORNERS.map(c => {
                const p = toViewBox(c.x, c.y);
                return (
                  <g key={c.n}>
                    <circle cx={p.x} cy={p.y} r="11" fill="var(--bg-1)"
                            stroke="rgba(255,255,255,0.55)" strokeWidth="1"/>
                    <text x={p.x} y={p.y + 3} textAnchor="middle"
                          fontFamily="var(--font-mono)" fontSize="9.5" fill="#fff">
                      {String(c.n).padStart(2, '0')}
                    </text>
                  </g>
                );
              })}

              <g transform={TRACK_TRANSFORM}>
              {/* cars */}
              {len > 0 && cars.map(c => {
                const frac = (t + 1 - c.gap) % 1;
                const p = pointAt(frac);
                const isFocus = focus === c.code;
                return (
                  <g key={c.code} transform={`translate(${p.x} ${p.y})`} style={{ cursor: 'pointer' }}
                     onMouseEnter={() => setFocus(c.code)}>
                    {/* trail — sits at lower raw-frac because cars advance with
                        increasing t along the new racing-direction path. */}
                    {[0.012, 0.024, 0.036].map((back, i) => {
                      const pp = pointAt((frac - back + 1) % 1);
                      return (
                        <circle key={i} cx={pp.x - p.x} cy={pp.y - p.y}
                                r={6 - i * 1.4} fill={c.color}
                                opacity={0.35 - i * 0.1}/>
                      );
                    })}
                    {isFocus && (
                      <circle r="16" fill="none" stroke={c.color} strokeWidth="1.5" opacity="0.6">
                        <animate attributeName="r" values="12;22;12" dur="2s" repeatCount="indefinite"/>
                        <animate attributeName="opacity" values="0.7;0;0.7" dur="2s" repeatCount="indefinite"/>
                      </circle>
                    )}
                    <circle r={isFocus ? 9 : 7} fill={c.color}
                            stroke="#fff" strokeWidth={isFocus ? 2 : 1.5}
                            style={{ filter: `drop-shadow(0 0 ${isFocus ? 12 : 4}px ${c.color})` }}/>
                    <text y="3" textAnchor="middle" fontFamily="var(--font-mono)"
                          fontSize="8" fill="#fff" fontWeight="600" pointerEvents="none">{c.code.slice(0,1)}</text>
                    {isFocus && (
                      <text y="-14" textAnchor="middle" fontFamily="var(--font-mono)"
                            fontSize="10" fill="#fff" letterSpacing="0.1em">{c.code}</text>
                    )}
                  </g>
                );
              })}
              </g>
            </svg>
          </div>

          {/* SIDE: standings */}
          <div style={{ padding: '24px 20px', display: 'flex', flexDirection: 'column', gap: 14 }}>
            <div>
              <div className="mono" style={{ fontSize: 10, color: 'var(--fg-4)', letterSpacing: '0.14em', textTransform: 'uppercase', marginBottom: 10 }}>Timing tower</div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
                {cars.map((c, i) => {
                  const gap = i === 0 ? 'LEADER' : '+' + (c.gap * 80).toFixed(1) + 's';
                  const isFocus = focus === c.code;
                  return (
                    <button key={c.code}
                            onMouseEnter={() => setFocus(c.code)}
                            style={{
                              all: 'unset',
                              cursor: 'pointer',
                              display: 'grid',
                              gridTemplateColumns: '24px 14px 1fr auto',
                              gap: 10,
                              padding: '10px 10px',
                              alignItems: 'center',
                              borderRadius: 8,
                              background: isFocus ? 'rgba(108,92,231,0.12)' : 'transparent',
                              border: `1px solid ${isFocus ? 'rgba(108,92,231,0.35)' : 'transparent'}`,
                              transition: 'all 0.2s'
                            }}>
                      <span className="mono" style={{ fontSize: 11, color: 'var(--fg-3)' }}>{c.label}</span>
                      <span style={{ width: 4, height: 16, background: c.color, borderRadius: 1 }}/>
                      <span style={{ fontFamily: 'var(--font-display)', fontSize: 13, fontWeight: 500, color: isFocus ? '#fff' : 'var(--fg-1)' }}>{c.code}</span>
                      <span className="mono" style={{ fontSize: 11, color: 'var(--fg-3)' }}>{gap}</span>
                    </button>
                  );
                })}
              </div>
            </div>

            <div style={{ marginTop: 8, padding: 14, background: 'var(--bg-3)', border: '1px solid var(--divider)', borderRadius: 10 }}>
              <div className="mono" style={{ fontSize: 10, color: 'var(--fg-4)', letterSpacing: '0.14em', textTransform: 'uppercase', marginBottom: 6 }}>Focus · {focus}</div>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, fontSize: 12 }}>
                <div><div style={{ color: 'var(--fg-4)', marginBottom: 2 }}>Last lap</div><div style={{ fontFamily: 'var(--font-mono)', color: '#fff' }}>1:27.482</div></div>
                <div><div style={{ color: 'var(--fg-4)', marginBottom: 2 }}>Best</div><div style={{ fontFamily: 'var(--font-mono)', color: '#c64aff' }}>1:26.991</div></div>
                <div><div style={{ color: 'var(--fg-4)', marginBottom: 2 }}>Compound</div><div style={{ color: '#fff' }}><span className="tire medium"><span className="tire-swatch"/>MED</span></div></div>
                <div><div style={{ color: 'var(--fg-4)', marginBottom: 2 }}>Tire age</div><div style={{ fontFamily: 'var(--font-mono)', color: '#fff' }}>14 laps</div></div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <style>{`
        @media (max-width: 1000px) {
          #circuit .circuit-layout { grid-template-columns: 1fr !important; }
        }
        @media (max-width: 780px) {
          #circuit .circuit-head { grid-template-columns: 1fr !important; gap: 16px; }
        }
      `}</style>
    </section>
  );
}

// ==============================================================
// SURFACES SECTION — CLI / Arcade / Streamlit
// ==============================================================
function SurfacesSection() {
  const [surface, setSurface] = useState('cli');

  const surfaces = {
    cli: {
      title: 'Command line',
      tag: 'Terminal first',
      desc: 'Three console scripts ship with the package. f1-strat is a Rich interactive launcher that walks you through mode, race, driver, lap range and LLM provider. f1-sim is the headless runner that iterates the race lap-by-lap and streams a live per-lap table with action, confidence and MC scores. f1-arcade opens the 2D replay window.',
      cmd: 'uv run f1-strat',
      feature: <CliPreview/>
    },
    arcade: {
      title: 'Arcade',
      tag: 'Desktop replay',
      desc: 'A three-window desktop app: a pyglet race replay with track, car icons, DRS zones, weather and leaderboard; a PySide6 strategy dashboard with orchestrator card, six agent cards and reasoning tabs; and a pyqtgraph live-telemetry window. Playback runs at 25 FPS with 0.25×–8× scrubbing.',
      cmd: 'python -m src.arcade.main',
      feature: <ArcadePreview/>
    },
    streamlit: {
      title: 'Streamlit',
      tag: 'Analysis workbench',
      desc: 'A six-page browser workbench for post-race analysis. Dashboard renders speed, throttle, brake, RPM, gear, DRS and delta telemetry; Comparison aligns two drivers\' fastest laps; Race Analysis groups degradation, gaps, radio and regulations; Model Lab runs each sub-agent in isolation; Strategy runs the full orchestrator. Chat is the multimodal LLM Q&A layer on top of all of it.',
      cmd: 'streamlit run src/telemetry/frontend/app/main.py',
      feature: <StreamlitPreview/>
    }
  };
  const s = surfaces[surface];

  return (
    <section className="section" id="surfaces" style={{ background: 'var(--bg-1)', borderTop: '1px solid var(--hairline)' }}>
      <div className="container-wide">
        <div className="section-head left surfaces-head" style={{ display: 'grid', gridTemplateColumns: '1fr auto', alignItems: 'end', marginBottom: 40, maxWidth: '100%', gap: 24 }}>
          <div>
            <span className="eyebrow"><span className="eyebrow-bar"/>Three surfaces · one brain</span>
            <h2 style={{ marginTop: 20 }}>Use it how you race.</h2>
          </div>
          <p style={{ maxWidth: 420, margin: 0 }}>
            Same orchestrator. Same models. Pick the front-end that matches the moment — pit wall, lab, or Twitch stream.
          </p>
        </div>

        <div className="surface-tabs" style={{ display: 'flex', gap: 8, marginBottom: 24, padding: 6, background: 'var(--bg-2)', border: '1px solid var(--divider)', borderRadius: 12, width: 'fit-content' }}>
          {Object.entries(surfaces).map(([k, v]) => (
            <button key={k} onClick={() => setSurface(k)} style={{
              padding: '10px 18px',
              display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: 2,
              background: surface === k ? 'var(--purple-600)' : 'transparent',
              color: surface === k ? '#fff' : 'var(--fg-2)',
              border: 'none', borderRadius: 8, cursor: 'pointer',
              transition: 'all 0.2s'
            }}>
              <span className="mono" style={{ fontSize: 9, letterSpacing: '0.14em', textTransform: 'uppercase', opacity: 0.65 }}>{v.tag}</span>
              <span style={{ fontFamily: 'var(--font-display)', fontSize: 14, fontWeight: 500 }}>{v.title}</span>
            </button>
          ))}
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '360px 1fr', gap: 32, alignItems: 'start' }} className="surfaces-grid">
          <div>
            <h3 style={{ fontFamily: 'var(--font-display)', fontSize: 32, fontWeight: 600, letterSpacing: '-0.025em', lineHeight: 1.1, marginBottom: 16 }}>{s.title}</h3>
            <p style={{ fontSize: 15, color: 'var(--fg-2)', lineHeight: 1.6, marginBottom: 24 }}>{s.desc}</p>
            <div className="code-wrap" style={{ marginBottom: 16 }}>
              <div className="code-chrome">
                <span className="dot"/><span className="dot"/><span className="dot"/>
                <span className="label">zsh</span>
              </div>
              <pre className="codeblock" style={{ padding: '14px 16px' }}>
<span className="c-cmd">$</span> {s.cmd}
              </pre>
            </div>
            <div style={{ display: 'flex', gap: 12, fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--fg-3)' }}>
              <span>↵ live reload</span>
              <span>·</span>
              <span>OPENAI_API_KEY optional</span>
            </div>
          </div>
          <div key={surface} style={{ animation: 'surfaceIn 0.4s cubic-bezier(0.2,0,0,1)' }}>{s.feature}</div>
        </div>
      </div>
      <style>{`
        @keyframes surfaceIn {
          from { opacity: 0; transform: translateY(12px); }
          to { opacity: 1; transform: none; }
        }
        @media (max-width: 900px) {
          #surfaces .surfaces-grid { grid-template-columns: 1fr !important; }
        }
        @media (max-width: 780px) {
          #surfaces .surfaces-head { grid-template-columns: 1fr !important; gap: 16px; }
        }
        @media (max-width: 780px) {
          #surfaces .surface-tabs { width: 100% !important; display: flex !important; gap: 4px !important; }
          #surfaces .surface-tabs > * { flex: 1 1 0 !important; min-width: 0 !important; padding: 8px 6px !important; }
          #surfaces .surface-tabs > * > span:first-child { font-size: 8px !important; }
          #surfaces .surface-tabs > * > span:last-child { font-size: 12px !important; }
        }
      `}</style>
    </section>
  );
}

function CliPreview() {
  // Progressive-reveal of the real f1-strat CLI boot + run.
  // Driven by a step counter set by a chain of setTimeouts, kicked off
  // once the preview enters the viewport. Holds 30s at the end, then loops.
  const [step, setStep] = useState(0);
  const [promptTyped, setPromptTyped] = useState([0, 0, 0]); // chars typed per prompt
  const [initTyped, setInitTyped] = useState([0, 0]);        // chars typed per loading line
  const frameRef = useRef(null);
  const startedRef = useRef(false);
  const timersRef = useRef([]);

  const PROMPTS = [
    { label: 'Available races (2025):', select: 'Melbourne' },
    { label: 'Driver code (e.g. NOR):', value: 'NOR' },
    { label: 'Lap range (e.g. 15-40, or Enter for all) (all):', value: '15-40' },
  ];
  const INIT_LINES = [
    'Initializing engine — NLP models loading, this may take a few seconds…',
    'radio corpus : 14 radios + 90 rcms loaded for australia',
  ];
  const ROWS = [
    { lap: 15, tyre: 'INTE', age: 15, pos: 1, lapS: '90.226', dec: 'STAY_OUT·MNGR·BAL', conf: '0.86', stay: '0.000', pit: '-1.089', ucut: '-0.776', ocut: '0.537' },
    { lap: 16, tyre: 'INTE', age: 16, pos: 1, lapS: '89.952', dec: 'STAY_OUT·MNGR·DEF', conf: '0.82', stay: '0.000', pit: '-1.084', ucut: '-0.771', ocut: '0.543' },
    { lap: 17, tyre: 'INTE', age: 17, pos: 1, lapS: '90.003', dec: 'STAY_OUT·MNGR·BAL', conf: '0.84', stay: '0.000', pit: '-1.090', ucut: '-0.778', ocut: '0.541' },
  ];
  const AGENTS = [
    { dot: '●', name: 'Pace',      state: 'Δnext -0.008s',  detail: 'pred 90.26s · ±2.55s · CI [87.9–93.1s]', color: '#4ade80' },
    { dot: '●', name: 'Tire',      state: 'cliff in ~30 laps', detail: 'range 20–40 · deg 0.030s/lap · OK', color: '#eab308' },
    { dot: '●', name: 'Situation', state: 'threat LOW',     detail: 'overtake 0% · safety car 9%', color: '#4ade80' },
    { dot: '●', name: 'Radio',     state: 'no alerts',      detail: '0 radios · 1 rcm', color: '#4ade80' },
  ];

  useEffect(() => {
    const clearAll = () => { timersRef.current.forEach(t => clearTimeout(t)); timersRef.current = []; };
    const schedule = (fn, ms) => { const t = setTimeout(fn, ms); timersRef.current.push(t); };

    const typePrompt = (idx, text, baseDelay) => {
      for (let i = 1; i <= text.length; i++) {
        schedule(() => setPromptTyped(p => { const n = [...p]; n[idx] = i; return n; }), baseDelay + i * 35);
      }
      return baseDelay + text.length * 35;
    };
    const typeInit = (idx, text, baseDelay) => {
      for (let i = 1; i <= text.length; i++) {
        schedule(() => setInitTyped(p => { const n = [...p]; n[idx] = i; return n; }), baseDelay + i * 10);
      }
      return baseDelay + text.length * 10;
    };

    const run = () => {
      setStep(0); setPromptTyped([0, 0, 0]); setInitTyped([0, 0]);
      // 1 — banner
      schedule(() => setStep(1), 300);
      // 2 — prompts
      schedule(() => setStep(2), 1400);
      let t = 1600;
      t = typePrompt(0, PROMPTS[0].select, t) + 250;
      schedule(() => setStep(3), t);
      t = typePrompt(1, PROMPTS[1].value, t) + 200;
      schedule(() => setStep(4), t);
      t = typePrompt(2, PROMPTS[2].value, t) + 400;
      // 3 — LLM menu
      schedule(() => setStep(5), t); t += 1800;
      // 4 — red separator + init logs
      schedule(() => setStep(6), t); t += 400;
      t = typeInit(0, INIT_LINES[0], t) + 500;
      t = typeInit(1, INIT_LINES[1], t) + 400;
      // 5 — table header
      schedule(() => setStep(7), t); t += 800;
      // 6..8 — table rows
      for (let i = 0; i < ROWS.length; i++) {
        schedule(() => setStep(7 + i + 1), t);
        t += 700;
      }
      t += 300;
      // 9..12 — Lap 17 agent bullets
      for (let i = 0; i < AGENTS.length; i++) {
        schedule(() => setStep(10 + i + 1), t);
        t += 550;
      }
      t += 300;
      schedule(() => setStep(15), t);
      // hold 30s, then restart
      schedule(run, t + 30000);
    };

    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting && !startedRef.current) {
          startedRef.current = true;
          run();
        }
      });
    }, { threshold: 0.2 });
    if (frameRef.current) io.observe(frameRef.current);
    return () => { io.disconnect(); clearAll(); };
  }, []);

  // Color tokens that mirror Rich's default terminal theme in the real CLI
  const C = {
    red:   '#ff3a3a',
    cyan:  '#5ec4e6',
    orange:'#ff8c38',
    green: '#4ade80',
    yellow:'#eab308',
    gray:  'rgba(255,255,255,0.4)',
    dim:   'rgba(255,255,255,0.55)',
    text:  '#e5e7eb',
  };

  // ─── Helpers ───
  const Cursor = () => <span className="cli-caret">▍</span>;
  const line = (content) => <div style={{ whiteSpace: 'pre' }}>{content}</div>;

  return (
    <div ref={frameRef} style={{
      background: '#0a0b10', border: '1px solid var(--divider)',
      borderRadius: 14, overflow: 'hidden',
      boxShadow: '0 30px 70px rgba(0,0,0,0.4)',
      fontFamily: 'var(--font-mono)', fontSize: 12,
      lineHeight: 1.6,
      minHeight: 560
    }}>
      <div className="code-chrome">
        <span className="dot"/><span className="dot"/><span className="dot"/>
        <span className="label">f1-strat · interactive</span>
      </div>
      <div style={{ padding: '16px 20px', color: C.text }}>

        {/* 1. Banner */}
        {step >= 1 && (
          <div className="cli-banner" style={{
            border: `1px solid ${C.red}`, borderRadius: 8, padding: '10px 14px',
            marginBottom: 14, fontSize: 10.5, lineHeight: 1.1,
            animation: 'cliFadeIn 0.45s cubic-bezier(0.2,0,0,1)'
          }}>
            <pre style={{ margin: 0, whiteSpace: 'pre' }}>
              <span style={{ color: C.red }}>{' _____ _  '}</span><span style={{ color: C.text }}>{'    _____ _____ ____      _  _____'}</span>{'\n'}
              <span style={{ color: C.red }}>{'|  ___| |  '}</span><span style={{ color: C.text }}>{'  / ____|_   _|  _ \\    / \\|_   _|'}</span>{'\n'}
              <span style={{ color: C.red }}>{'| |_  | |  '}</span><span style={{ color: C.text }}>{'  \\___ \\  | | | |_) |  / _ \\ | |  '}</span>{'\n'}
              <span style={{ color: C.red }}>{'|  _| | |  '}</span><span style={{ color: C.text }}>{'   ___) | | | |  _ <  / ___ \\| |  '}</span>{'\n'}
              <span style={{ color: C.red }}>{'|_|   |_|  '}</span><span style={{ color: C.text }}>{'  |____/  |_| |_| \\_\\/_/   \\_\\_|  '}</span>
            </pre>
            <div style={{ marginTop: 8, color: C.dim, fontSize: 11 }}>
              <strong style={{ color: C.text, fontWeight: 600 }}>Formula 1 Strategy Manager</strong>{'  '}
              <span style={{ color: C.gray }}>Multi-Agent Race Intelligence System · v0.9</span>
            </div>
          </div>
        )}

        {/* 2a. Race select */}
        {step >= 2 && (
          <div style={{ marginBottom: 8, animation: 'cliFadeIn 0.35s ease' }}>
            <div style={{ color: C.gray }}>{PROMPTS[0].label}</div>
            <div>
              <span style={{ color: C.red }}>❯</span>{' '}
              <span style={{ color: C.text, fontWeight: 600 }}>{PROMPTS[0].select.slice(0, promptTyped[0])}</span>
              {step === 2 && promptTyped[0] < PROMPTS[0].select.length && <Cursor/>}
            </div>
          </div>
        )}

        {/* 2b. Driver code */}
        {step >= 3 && (
          <div style={{ animation: 'cliFadeIn 0.35s ease' }}>
            <span style={{ color: C.red }}>›</span>{' '}
            <span style={{ color: C.gray }}>{PROMPTS[1].label}</span>{' '}
            <span style={{ color: C.orange, fontWeight: 600 }}>{PROMPTS[1].value.slice(0, promptTyped[1])}</span>
            {step === 3 && promptTyped[1] < PROMPTS[1].value.length && <Cursor/>}
          </div>
        )}

        {/* 2c. Lap range */}
        {step >= 4 && (
          <div style={{ animation: 'cliFadeIn 0.35s ease' }}>
            <span style={{ color: C.red }}>›</span>{' '}
            <span style={{ color: C.gray }}>{PROMPTS[2].label}</span>{' '}
            <span style={{ color: C.text }}>{PROMPTS[2].value.slice(0, promptTyped[2])}</span>
            {step === 4 && promptTyped[2] < PROMPTS[2].value.length && <Cursor/>}
          </div>
        )}

        {/* 3. LLM mode */}
        {step >= 5 && (
          <div style={{ marginTop: 14, animation: 'cliFadeIn 0.4s ease' }}>
            <div style={{ color: C.text, marginBottom: 4 }}>LLM mode:</div>
            <div style={{ color: C.gray, paddingLeft: 16 }}>  No LLM      <span style={{ color: C.dim }}>Fast · ML models only, no synthesis</span>   <span style={{ color: C.gray }}>[recommended]</span></div>
            <div style={{ paddingLeft: 0 }}>
              <span style={{ color: C.red }}>❯</span>{'   '}
              <span style={{ color: C.text, fontWeight: 600 }}>OpenAI</span>{'     '}
              <span style={{ color: C.text }}>GPT-4.1-mini</span>{' · '}
              <span style={{ color: C.dim }}>needs OPENAI_API_KEY in .env</span>
            </div>
            <div style={{ color: C.gray, paddingLeft: 16 }}>  LM Studio   <span style={{ color: C.dim }}>Local model at localhost:1234</span></div>
          </div>
        )}

        {/* 4. Red separator + init lines */}
        {step >= 6 && (
          <>
            <div className="cli-hr" style={{ margin: '14px 0 10px' }}/>
            <div style={{ color: C.gray, minHeight: '1.5em' }}>
              {INIT_LINES[0].slice(0, initTyped[0])}
              {step === 6 && initTyped[0] < INIT_LINES[0].length && <Cursor/>}
            </div>
            <div style={{ color: C.gray, minHeight: '1.5em' }}>
              {initTyped[1] > 0 && (
                <>
                  <span>radio corpus : </span>
                  <span style={{ color: C.cyan, fontWeight: 600 }}>14</span>
                  <span> radios + </span>
                  <span style={{ color: C.cyan, fontWeight: 600 }}>90</span>
                  <span> rcms loaded for australia</span>
                  {step === 6 && initTyped[1] < INIT_LINES[1].length && <Cursor/>}
                </>
              )}
            </div>
          </>
        )}

        {/* 5. Header panel */}
        {step >= 7 && (
          <div style={{
            marginTop: 12,
            padding: '8px 12px',
            border: `1px solid ${C.cyan}`,
            borderRadius: 6,
            position: 'relative',
            animation: 'cliFadeIn 0.5s ease'
          }}>
            <div style={{ position: 'absolute', top: -8, left: 16, background: '#0a0b10', padding: '0 8px', color: C.cyan, fontWeight: 600, fontSize: 11 }}>F1 Strategy Manager</div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '2px 18px', marginTop: 4 }}>
              <div><span style={{ color: C.gray }}>GP     </span><span style={{ color: C.text, fontWeight: 600 }}>Melbourne</span></div>
              <div><span style={{ color: C.gray }}>Mode   </span><span style={{ color: C.text }}>LLM · </span><span style={{ color: C.text }}>openai</span><span style={{ color: C.gray }}> · radios=14</span></div>
              <div><span style={{ color: C.gray }}>Driver </span><span style={{ color: C.orange, fontWeight: 600 }}>NOR</span>{' '}<span style={{ color: C.gray }}>McLaren</span></div>
              <div><span style={{ color: C.gray }}>Laps   </span><span style={{ color: C.text }}>15–40</span><span style={{ color: C.gray }}>  / 57 total</span></div>
            </div>
            <div style={{ marginTop: 6 }}>
              <span style={{ color: C.gray }}>Actions  </span>
              <span style={{ color: C.green }}>STAY_OUT</span><span style={{ color: C.gray }}> · </span>
              <span style={{ color: C.red }}>PIT_NOW</span><span style={{ color: C.gray }}> · </span>
              <span style={{ color: C.yellow }}>UNDERCUT</span><span style={{ color: C.gray }}> · </span>
              <span style={{ color: C.cyan }}>OVERCUT</span><span style={{ color: C.gray }}> · </span>
              <span style={{ color: C.orange }}>ALERT</span>
            </div>
          </div>
        )}

        {/* 6. Table rows */}
        {step >= 7 && (
          <div style={{ marginTop: 10, fontSize: 11, whiteSpace: 'pre', overflow: 'hidden' }}>
            <div style={{ color: C.gray, borderBottom: '1px solid rgba(255,255,255,0.06)', paddingBottom: 2, marginBottom: 4 }}>
              {'Lap  Tyre  Age  Pos  Lap(s)    Decision             Conf  Stay   Pit     Ucut    Ocut'}
            </div>
            {ROWS.map((r, i) => (
              step >= 8 + i && (
                <div key={r.lap} style={{ animation: 'cliRowIn 0.35s cubic-bezier(0.2,0,0,1)' }}>
                  <span style={{ color: C.text }}>{String(r.lap).padEnd(5)}</span>
                  <span style={{ color: C.green, fontWeight: 600 }}>{r.tyre.padEnd(6)}</span>
                  <span style={{ color: C.text }}>{String(r.age).padEnd(5)}</span>
                  <span style={{ color: C.orange }}>{String(r.pos).padEnd(5)}</span>
                  <span style={{ color: C.text }}>{r.lapS.padEnd(10)}</span>
                  <span style={{ color: C.green }}>{r.dec.padEnd(22)}</span>
                  <span style={{ color: C.text }}>{r.conf.padEnd(6)}</span>
                  <span style={{ color: C.gray }}>{r.stay.padEnd(7)}</span>
                  <span style={{ color: C.red }}>{r.pit.padEnd(8)}</span>
                  <span style={{ color: C.red }}>{r.ucut.padEnd(8)}</span>
                  <span style={{ color: C.yellow }}>{r.ocut}</span>
                </div>
              )
            ))}
          </div>
        )}

        {/* 7. Lap 17 agent panel */}
        {step >= 11 && (
          <div style={{
            marginTop: 14, paddingTop: 8,
            borderTop: '1px dashed rgba(255,255,255,0.15)',
            animation: 'cliFadeIn 0.45s ease'
          }}>
            <div style={{ color: C.gray, textAlign: 'center', marginBottom: 6, fontSize: 11 }}>── Lap 17 ──</div>
            {AGENTS.map((a, i) => (
              step >= 11 + i && (
                <div key={a.name} style={{
                  display: 'grid', gridTemplateColumns: '18px 100px 1fr 2fr',
                  gap: 10, padding: '2px 0', fontSize: 11,
                  animation: 'cliRowIn 0.4s cubic-bezier(0.2,0,0,1)'
                }}>
                  <span style={{ color: a.color }}>{a.dot}</span>
                  <span style={{ color: C.text }}>{a.name}</span>
                  <span style={{ color: a.color, fontWeight: 600 }}>{a.state}</span>
                  <span style={{ color: C.gray }}>{a.detail}</span>
                </div>
              )
            ))}
          </div>
        )}

        {/* Footer tick */}
        {step >= 15 && (
          <div style={{ marginTop: 12, color: C.gray, fontSize: 11, animation: 'cliFadeIn 0.4s ease' }}>
            <span style={{ color: C.cyan }}>.:</span> lap <span style={{ color: C.text }}>18 / 40</span> — running agents…<Cursor/>
          </div>
        )}

      </div>
      <style>{`
        @media (max-width: 640px) {
          .cli-banner pre { font-size: 8.5px !important; }
          .cli-banner { padding: 8px 10px !important; }
        }
        @media (max-width: 380px) {
          .cli-banner pre { font-size: 7.5px !important; }
        }
        .cli-caret {
          display: inline-block;
          background: ${C.cyan};
          width: 7px; height: 12px;
          margin-left: 3px;
          vertical-align: -1px;
          animation: blink 1s step-end infinite;
        }
        .cli-hr {
          height: 1px;
          background: linear-gradient(90deg, ${C.red} 0%, rgba(255,58,58,0.5) 70%, transparent 100%);
          animation: cliHrDraw 0.6s cubic-bezier(0.2,0,0,1) both;
        }
        @keyframes blink { 50% { opacity: 0; } }
        @keyframes cliFadeIn {
          from { opacity: 0; transform: translateY(4px); }
          to   { opacity: 1; transform: none; }
        }
        @keyframes cliRowIn {
          from { opacity: 0; transform: translateX(-6px); }
          to   { opacity: 1; transform: none; }
        }
        @keyframes cliHrDraw {
          from { transform: scaleX(0); transform-origin: left; }
          to   { transform: scaleX(1); transform-origin: left; }
        }
      `}</style>
    </div>
  );
}

function ArcadePreview() {
  // Animation loop
  const [t, setT] = useState(0); // 0..1 lap fraction, loops
  useEffect(() => {
    let raf, start = performance.now();
    const loop = (now) => {
      setT(((now - start) / 1000 / 12) % 1); // 12s lap
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, []);

  // Closed-loop track path as a parametric curve so we can animate cars smoothly.
  // Uses an SVG path with ref to measure total length.
  const outerPathRef = useRef(null);
  const [trackLen, setTrackLen] = useState(0);
  useEffect(() => {
    if (outerPathRef.current) setTrackLen(outerPathRef.current.getTotalLength());
  }, []);

  const pointAt = (frac) => {
    if (!outerPathRef.current || !trackLen) return { x: 0, y: 0 };
    return outerPathRef.current.getPointAtLength(((frac % 1) + 1) % 1 * trackLen);
  };

  // Per-car phase offsets (fraction of lap). NOR ahead of LEC by ~0.012.
  const norFrac = t;
  const lecFrac = (t - 0.012 + 1) % 1;

  // Slight field of other cars spread around the lap
  const fieldCars = [
    { code: 'SAI', color: '#ff2d3a', off: 0.18 },
    { code: 'VER', color: '#1e5bc6', off: 0.30 },
    { code: 'PIA', color: '#ff8c38', off: 0.46 },
    { code: 'RUS', color: '#00d7b5', off: 0.62 },
    { code: 'PER', color: '#1e5bc6', off: 0.78 },
  ];

  // Speed profile around the lap — slower in corners (near t ≈ 0.15/0.35/0.55/0.75/0.92)
  const corners = [0.15, 0.35, 0.55, 0.75, 0.92];
  const speedAt = (frac, base) => {
    let penalty = 0;
    for (const c of corners) {
      let d = Math.min(Math.abs(frac - c), 1 - Math.abs(frac - c));
      if (d < 0.05) penalty += Math.exp(-(d * d) * 900) * 150;
    }
    return Math.round(Math.max(80, base - penalty));
  };
  const gearAt = (spd) => spd < 120 ? 3 : spd < 170 ? 5 : spd < 220 ? 6 : spd < 260 ? 7 : 8;
  const drsAt = (frac) => {
    // DRS on along 5 straights (mid-segment between corners)
    const straights = [0.03, 0.24, 0.44, 0.65, 0.84];
    return straights.some(s => Math.abs(frac - s) < 0.04) ? 'ON' : 'OFF';
  };

  const norSpeed = speedAt(norFrac, 305);
  const lecSpeed = speedAt(lecFrac, 308);
  const norGear = gearAt(norSpeed);
  const lecGear = gearAt(lecSpeed);
  const norDRS = drsAt(norFrac);
  const lecDRS = drsAt(lecFrac);

  // Gap between NOR ahead and LEC behind = ~0.5-0.9s, sinusoidal
  const norLecGap = (0.51 + 0.25 * Math.sin(t * Math.PI * 2 * 3)).toFixed(2);
  const verNorGap = (0.71 + 0.15 * Math.sin(t * Math.PI * 2 * 2 + 1)).toFixed(2);
  const piaLecGap = (0.95 + 0.2 * Math.sin(t * Math.PI * 2 * 2.3 + 2)).toFixed(2);

  // Lap counter — advances slowly so we can see it tick
  const currentLap = 4 + Math.floor(t * 2); // 4 → 5 across the lap
  const simTime = 4 * 60 + 44 + t * 90; // grows with t
  const fmtClock = (s) => `00:${String(Math.floor(s / 60)).padStart(2, '0')}:${String(Math.floor(s % 60)).padStart(2, '0')}`;

  const leaderboard = [
    { pos: 1, code: 'SAI', tire: 'M', tireColor: '#e6e6e6', teamColor: '#ff2d3a' },
    { pos: 2, code: 'VER', tire: 'M', tireColor: '#e6e6e6', teamColor: '#1e5bc6' },
    { pos: 3, code: 'NOR', tire: 'M', tireColor: '#e6e6e6', teamColor: '#ff8c38', active: true },
    { pos: 4, code: 'LEC', tire: 'M', tireColor: '#e6e6e6', teamColor: '#ff2d3a' },
    { pos: 5, code: 'PIA', tire: 'M', tireColor: '#e6e6e6', teamColor: '#ff8c38' },
    { pos: 6, code: 'RUS', tire: 'M', tireColor: '#e6e6e6', teamColor: '#00d7b5' },
    { pos: 7, code: 'PER', tire: 'M', tireColor: '#e6e6e6', teamColor: '#1e5bc6' },
    { pos: 8, code: 'TSU', tire: 'M', tireColor: '#e6e6e6', teamColor: '#2d8fff' },
    { pos: 9, code: 'BOT', tire: 'M', tireColor: '#e6e6e6', teamColor: '#0abf7b' },
    { pos: 10, code: 'STR', tire: 'M', tireColor: '#e6e6e6', teamColor: '#0abf7b' },
    { pos: 11, code: 'MAG', tire: 'M', tireColor: '#e6e6e6', teamColor: '#ffffff' },
    { pos: 12, code: 'OCO', tire: 'M', tireColor: '#e6e6e6', teamColor: '#ff70a0' },
    { pos: 13, code: 'HUL', tire: 'H', tireColor: '#ffffff', teamColor: '#ffffff' },
    { pos: 14, code: 'ALB', tire: 'M', tireColor: '#e6e6e6', teamColor: '#2d8fff' },
    { pos: 15, code: 'GAS', tire: 'M', tireColor: '#e6e6e6', teamColor: '#ff70a0' },
    { pos: 16, code: 'RIC', tire: 'S', tireColor: '#ff2d3a', teamColor: '#2d8fff' },
    { pos: 17, code: 'HAM', tire: 'S', tireColor: '#ff2d3a', teamColor: '#00d7b5' },
    { pos: 18, code: 'ZHO', tire: 'S', tireColor: '#ff2d3a', teamColor: '#0abf7b' },
    { pos: 19, code: 'ALO', tire: 'H', tireColor: '#ffffff', teamColor: '#0abf7b' },
  ];

  const norP = pointAt(norFrac);
  const lecP = pointAt(lecFrac);

  return (
    <div className="arcade-preview-frame" style={{
      background: '#0a0b10', border: '1px solid var(--divider)',
      borderRadius: 14, overflow: 'hidden',
      boxShadow: '0 30px 70px rgba(0,0,0,0.4)',
      position: 'relative',
      aspectRatio: '16/10'
    }}>
      <style>{`
        @media (max-width: 640px) {
          .arcade-preview-frame { overflow-x: auto; -webkit-overflow-scrolling: touch; }
          .arcade-preview-frame svg { min-width: 520px; }
        }
      `}</style>
      <div className="code-chrome">
        <span className="dot"/><span className="dot"/><span className="dot"/>
        <span className="label">arcade · 60 fps</span>
      </div>
      <div style={{ position: 'relative', height: 'calc(100% - 37px)', background: '#050610', fontFamily: 'var(--font-mono)', color: '#fff', fontSize: 9 }}>
        <svg viewBox="0 0 800 470" preserveAspectRatio="xMidYMid meet" style={{ width: '100%', height: '100%', display: 'block' }}>
          {/* LAP */}
          <g transform="translate(14, 18)">
            <text fontSize="8" fill="#3385ff" letterSpacing="0.14em" fontWeight="700">LAP</text>
            <text y="16" fontSize="16" fill="#ffffff" fontFamily="var(--font-display)" fontWeight="700">{currentLap}/58</text>
            <text y="28" fontSize="7" fill="rgba(255,255,255,0.55)">{fmtClock(simTime)} &#160;&#160;x8.0 &#160;LIVE</text>
          </g>

          {/* WEATHER */}
          <g transform="translate(14, 60)">
            <text fontSize="8" fill="#3385ff" letterSpacing="0.14em" fontWeight="700">WEATHER</text>
            <line x1="0" y1="7" x2="170" y2="7" stroke="rgba(255,255,255,0.18)" strokeWidth="0.5"/>
            {[
              ['Track', (45.0 + 0.8 * Math.sin(t * 6.28)).toFixed(1) + ' C'],
              ['Air',   (18.0 + 0.3 * Math.sin(t * 6.28 + 1)).toFixed(1) + ' C'],
              ['Humidity', '55%'],
              ['Wind', '12.0 km/h S'],
              ['Rain', 'DRY'],
            ].map(([k, v], i) => (
              <g key={k} transform={`translate(0, ${18 + i * 11})`}>
                <text fontSize="7" fill="rgba(255,255,255,0.6)">{k}</text>
                <text x="170" textAnchor="end" fontSize="7" fill="#fff" fontWeight="600">{v}</text>
              </g>
            ))}
          </g>

          {/* NOR driver card */}
          <g transform="translate(14, 150)">
            <text fontSize="10" fill="#ff8c38" fontWeight="700" letterSpacing="0.08em" fontFamily="var(--font-display)">NOR</text>
            <text x="170" textAnchor="end" fontSize="7" fill="rgba(255,255,255,0.5)" letterSpacing="0.1em">DRIVER</text>
            <line x1="0" y1="6" x2="170" y2="6" stroke="rgba(255,255,255,0.18)" strokeWidth="0.5"/>
            {[
              ['Speed', `${norSpeed} km/h`],
              ['Gear', `${norGear}`],
              ['DRS', norDRS],
              ['Compound', 'M'],
              ['Ahead', `VER +${verNorGap}s`],
              ['Behind', `LEC -${norLecGap}s`],
            ].map(([k, v], i) => (
              <g key={k} transform={`translate(0, ${17 + i * 10})`}>
                <text fontSize="7" fill="rgba(255,255,255,0.6)">{k}</text>
                <text x="170" textAnchor="end" fontSize="7" fill={k === 'DRS' && v === 'ON' ? '#43ff64' : '#fff'} fontWeight="600">{v}</text>
              </g>
            ))}
          </g>

          {/* LEC driver card */}
          <g transform="translate(14, 248)">
            <text fontSize="10" fill="#ff2d3a" fontWeight="700" letterSpacing="0.08em" fontFamily="var(--font-display)">LEC</text>
            <text x="170" textAnchor="end" fontSize="7" fill="rgba(255,255,255,0.5)" letterSpacing="0.1em">DRIVER</text>
            <line x1="0" y1="6" x2="170" y2="6" stroke="rgba(255,255,255,0.18)" strokeWidth="0.5"/>
            {[
              ['Speed', `${lecSpeed} km/h`],
              ['Gear', `${lecGear}`],
              ['DRS', lecDRS],
              ['Compound', 'M'],
              ['Ahead', `NOR +${norLecGap}s`],
              ['Behind', `PIA -${piaLecGap}s`],
            ].map(([k, v], i) => (
              <g key={k} transform={`translate(0, ${17 + i * 10})`}>
                <text fontSize="7" fill="rgba(255,255,255,0.6)">{k}</text>
                <text x="170" textAnchor="end" fontSize="7" fill={k === 'DRS' && v === 'ON' ? '#43ff64' : '#fff'} fontWeight="600">{v}</text>
              </g>
            ))}
          </g>

          {/* CONTROLS */}
          <g transform="translate(14, 352)">
            <text fontSize="8" fill="#3385ff" letterSpacing="0.14em" fontWeight="700">CONTROLS</text>
            <line x1="0" y1="7" x2="170" y2="7" stroke="rgba(255,255,255,0.18)" strokeWidth="0.5"/>
            {[
              ['SPACE', 'Pause / Resume'],
              ['< / >', 'Rewind / Fast-Forward'],
              ['Up / Down', 'Speed +/-'],
              ['1 - 4', '0.5 / 1 / 2 / 4 x'],
              ['R', 'Restart'],
              ['D', 'Toggle DRS zones'],
              ['B', 'Toggle progress bar'],
              ['ESC', 'Close'],
            ].map(([k, v], i) => (
              <g key={k} transform={`translate(0, ${17 + i * 9.5})`}>
                <text fontSize="6.5" fill="rgba(255,255,255,0.85)" fontWeight="600">{k}</text>
                <text x="60" fontSize="6.5" fill="rgba(255,255,255,0.55)">{v}</text>
              </g>
            ))}
          </g>

          {/* TRACK — Albert Park 2022 official layout (natural 607.8 × 385.1).
              Fit into the arcade's centre panel (approx 460 × 360). */}
          {(() => {
            const ARCADE_REGION_W = 470, ARCADE_REGION_H = 360;
            const ARCADE_FIT = Math.min(ARCADE_REGION_W / 607.8, ARCADE_REGION_H / 385.1) * 0.94;
            const ARCADE_TX = 195 + (ARCADE_REGION_W - 607.8 * ARCADE_FIT) / 2;
            const ARCADE_TY = 55 + (ARCADE_REGION_H - 385.1 * ARCADE_FIT) / 2;
            return (
              <g transform={`translate(${ARCADE_TX}, ${ARCADE_TY}) scale(${ARCADE_FIT})`}>
                {/* Outer track — measured path for car positions. */}
                <path ref={outerPathRef}
                      d={TRACK_PATH}
                      fill="none" stroke="#8c92a8" strokeWidth="6" strokeLinejoin="round" strokeLinecap="round"/>
                {/* Sector overlays */}
                <path d={SECTOR_PATHS.s3} fill="none" stroke="#ffcf2d" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" opacity="0.9"/>
                <path d={SECTOR_PATHS.s2} fill="none" stroke="#2d8fff" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" opacity="0.9"/>
                <path d={SECTOR_PATHS.s1} fill="none" stroke="#ff2d3a" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" opacity="0.9"/>
                {/* Inner hairline */}
                <path d={TRACK_PATH}
                      fill="none" stroke="rgba(255,255,255,0.18)" strokeWidth="0.8" strokeDasharray="2 4"/>

                {/* Field cars (smaller, no labels, looped offsets) */}
                {trackLen > 0 && fieldCars.map(c => {
                  const p = pointAt((t + c.off) % 1);
                  return (
                    <circle key={c.code} cx={p.x} cy={p.y} r="4" fill={c.color}
                            stroke="#fff" strokeWidth="0.8" opacity="0.85"/>
                  );
                })}

                {/* NOR */}
                {trackLen > 0 && (
                  <g>
                    <circle cx={norP.x} cy={norP.y} r="5.5" fill="#ff8c38" stroke="#fff" strokeWidth="1.2"
                            style={{ filter: 'drop-shadow(0 0 6px #ff8c38)' }}/>
                    <text x={norP.x + 7} y={norP.y - 7} fontSize="8" fill="#ff8c38" fontWeight="700">NOR</text>
                  </g>
                )}
                {/* LEC */}
                {trackLen > 0 && (
                  <g>
                    <circle cx={lecP.x} cy={lecP.y} r="5.5" fill="#ff2d3a" stroke="#fff" strokeWidth="1.2"
                            style={{ filter: 'drop-shadow(0 0 6px #ff2d3a)' }}/>
                    <text x={lecP.x - 5} y={lecP.y + 14} fontSize="8" fill="#ff2d3a" fontWeight="700">LEC</text>
                  </g>
                )}
              </g>
            );
          })()}

          {/* Start/finish line — midpoint between T14 and T1 in viewBox coords. */}
          {(() => {
            const ARCADE_REGION_W = 470, ARCADE_REGION_H = 360;
            const ARCADE_FIT = Math.min(ARCADE_REGION_W / 607.8, ARCADE_REGION_H / 385.1) * 0.94;
            const ARCADE_TX = 195 + (ARCADE_REGION_W - 607.8 * ARCADE_FIT) / 2;
            const ARCADE_TY = 55 + (ARCADE_REGION_H - 385.1 * ARCADE_FIT) / 2;
            const c1 = CORNERS.find(c => c.n === 1);
            const c14 = CORNERS.find(c => c.n === 14);
            const x = ARCADE_TX + ((c1.x + c14.x) / 2) * ARCADE_FIT;
            const y = ARCADE_TY + ((c1.y + c14.y) / 2) * ARCADE_FIT;
            return (
              <g>
                <line x1={x} y1={y - 8} x2={x} y2={y + 8} stroke="#fff" strokeWidth="1.4"/>
              </g>
            );
          })()}

          {/* LEADERBOARD */}
          <g transform="translate(660, 18)">
            <text fontSize="8" fill="#3385ff" letterSpacing="0.14em" fontWeight="700">LEADERBOARD</text>
            <line x1="0" y1="7" x2="126" y2="7" stroke="rgba(255,255,255,0.18)" strokeWidth="0.5"/>
            {leaderboard.map((d, i) => (
              <g key={d.code} transform={`translate(0, ${14 + i * 13.2})`}>
                {d.active && <rect x="-4" y="-4" width="134" height="13" fill="rgba(108,92,231,0.3)" stroke="rgba(108,92,231,0.6)" strokeWidth="0.5"/>}
                <text x="0" fontSize="7" fill="rgba(255,255,255,0.55)" fontWeight="600">{String(d.pos).padStart(2, ' ')}</text>
                <rect x="14" y="-5" width="2" height="8" fill={d.teamColor}/>
                <text x="22" fontSize="8" fill={d.teamColor} fontWeight="700" fontFamily="var(--font-display)" letterSpacing="0.04em">{d.code}</text>
                <text x="122" textAnchor="end" fontSize="7" fill={d.tireColor} fontWeight="700">{d.tire}</text>
              </g>
            ))}
          </g>

          {/* FOOTER — LAP PROGRESS */}
          <g transform="translate(210, 440)">
            {Array.from({ length: 58 }).map((_, i) => (
              <rect
                key={i}
                x={i * 8.2}
                y={0}
                width={7}
                height={8}
                fill={i < currentLap ? '#a29bfe' : 'rgba(255,255,255,0.10)'}
                stroke="rgba(255,255,255,0.15)"
                strokeWidth="0.3"
              />
            ))}
            {/* moving play-head within current lap */}
            <rect
              x={(currentLap - 1) * 8.2 + t * 8.2 * 2 % 8.2}
              y={-2}
              width={1.5}
              height={12}
              fill="#fff"
              opacity="0.8"
            />
            {[1, 10, 20, 30, 40, 50, 58].map(n => (
              <text
                key={n}
                x={(n - 1) * 8.2 + 3.5}
                y={20}
                fontSize="6.5"
                fill="rgba(255,255,255,0.55)"
                textAnchor="middle"
              >{n}</text>
            ))}
          </g>
        </svg>
      </div>
    </div>
  );
}

function StreamlitPreview() {
  // Timing (ms)
  const TYPE_MS = 3500;          // message streams in
  const BTN_DELAY = 400;         // pause after message before button
  const BTN_HOLD = 700;          // then chart appears
  const SWEEP_MS = 4500;         // crosshair auto-sweep
  const HOLD_MS = 2500;          // hold at end before restart
  const TOTAL = TYPE_MS + BTN_DELAY + BTN_HOLD + SWEEP_MS + HOLD_MS;

  const fullMessage = "LEC's lap 30 telemetry at Monza shows a long, high-speed lap profile with repeated heavy-braking zones and short acceleration bursts, which is exactly where tyre performance and brake stability matter most. The key strategic insight is that Monza rewards track position heavily, so if Leclerc is on a tyre age cliff, the undercut window is likely more valuable than waiting for an overcut. Recommended action: pit only if the tyre delta is clearly fading versus the car ahead/behind; otherwise protect track position and avoid losing time in traffic, since clean-air pace is critical here.";

  const [elapsed, setElapsed] = useState(0);
  const [hoverX, setHoverX] = useState(null); // user-driven crosshair (normalized 0..1) or null
  useEffect(() => {
    let raf, start = performance.now();
    const loop = (now) => {
      setElapsed((now - start) % TOTAL);
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, []);

  // Derived phase values
  const charsShown = Math.min(fullMessage.length, Math.round((elapsed / TYPE_MS) * fullMessage.length));
  const messageText = fullMessage.slice(0, charsShown);
  const showTypingCursor = elapsed < TYPE_MS;
  const showBtn = elapsed > TYPE_MS + BTN_DELAY;
  const btnActive = elapsed > TYPE_MS + BTN_DELAY && elapsed < TYPE_MS + BTN_DELAY + 250;
  const showChart = elapsed > TYPE_MS + BTN_DELAY + BTN_HOLD;
  // Auto-sweep only when chart has appeared and user not hovering
  const sweepStart = TYPE_MS + BTN_DELAY + BTN_HOLD;
  const autoX = elapsed > sweepStart
    ? Math.max(0, Math.min(1, (elapsed - sweepStart) / SWEEP_MS))
    : null;
  const crosshairX = hoverX != null ? hoverX : (elapsed > sweepStart && elapsed < sweepStart + SWEEP_MS ? autoX : null);

  const W = 780;
  const H = 340;

  // Generate telemetry
  const N = 240;
  const brakeZones = [0.08, 0.22, 0.40, 0.55, 0.70, 0.88];
  const speedPts = [], throttlePts = [], brakePts = [];
  for (let i = 0; i < N; i++) {
    const x = i / (N - 1);
    let speed = 305;
    for (const bz of brakeZones) {
      const d = Math.abs(x - bz);
      if (d < 0.05) speed -= Math.exp(-(d * d) * 1400) * (160 + 30 * Math.sin(bz * 20));
    }
    speed = Math.max(70, Math.min(310, speed + Math.sin(x * 60) * 2));
    speedPts.push([x, speed]);
    let thr = 100;
    for (const bz of brakeZones) {
      const d = Math.abs(x - bz);
      if (d < 0.04) thr = Math.min(thr, 0 + d * 400);
      else if (d < 0.06) thr = Math.min(thr, 30 + (d - 0.04) * 3500);
    }
    throttlePts.push([x, Math.max(0, Math.min(100, thr))]);
    let br = 0;
    for (const bz of brakeZones) {
      const d = Math.abs(x - bz);
      if (d < 0.015) br = 100;
      else if (d < 0.025) br = 100 - (d - 0.015) * 8000;
    }
    brakePts.push([x, Math.max(0, Math.min(100, br))]);
  }

  const chartL = 56, chartR = W - 24, chartW = chartR - chartL;
  const chartBands = [
    { y: 24, h: 54, label: 'Speed (km/h)', min: 0, max: 350, ticks: [100, 200, 300], color: '#ff3a5a', fill: 'rgba(255,58,90,0.06)' },
    { y: 102, h: 54, label: 'Throttle (%)', min: 0, max: 100, ticks: [0, 50, 100], color: '#00d7b5', fill: 'rgba(0,215,181,0.15)' },
    { y: 180, h: 36, label: 'Brake (%)', min: 0, max: 100, ticks: ['false', 'true'], color: '#ff3a5a', fill: 'rgba(255,58,90,0.18)' },
  ];
  const toPath = (pts, band) => pts.map(([x, v], i) => {
    const px = chartL + x * chartW;
    const py = band.y + band.h - ((v - band.min) / (band.max - band.min)) * band.h;
    return `${i === 0 ? 'M' : 'L'}${px.toFixed(1)},${py.toFixed(1)}`;
  }).join(' ');
  const toAreaPath = (pts, band) => {
    const base = band.y + band.h;
    return `M${chartL},${base} ` + pts.map(([x, v]) => {
      const px = chartL + x * chartW;
      const py = band.y + band.h - ((v - band.min) / (band.max - band.min)) * band.h;
      return `L${px.toFixed(1)},${py.toFixed(1)}`;
    }).join(' ') + ` L${chartR},${base} Z`;
  };

  // Lookup value at fraction
  const valueAt = (pts, frac) => {
    const i = Math.max(0, Math.min(pts.length - 1, Math.round(frac * (pts.length - 1))));
    return pts[i][1];
  };

  const crossPx = crosshairX != null ? chartL + crosshairX * chartW : null;
  const crossDist = crosshairX != null ? Math.round(crosshairX * 5000) : null;
  const crossSpeed = crosshairX != null ? Math.round(valueAt(speedPts, crosshairX)) : null;
  const crossThr = crosshairX != null ? Math.round(valueAt(throttlePts, crosshairX)) : null;
  const crossBr = crosshairX != null ? Math.round(valueAt(brakePts, crosshairX)) : null;

  const handleMove = (e) => {
    const svg = e.currentTarget;
    const rect = svg.getBoundingClientRect();
    const svgX = ((e.clientX - rect.left) / rect.width) * W;
    const frac = (svgX - chartL) / chartW;
    if (frac >= 0 && frac <= 1) setHoverX(frac);
    else setHoverX(null);
  };

  // Tooltip positioning (avoid right edge overflow)
  let tipX = 0, tipAnchor = 'start';
  if (crossPx != null) {
    if (crossPx > chartR - 110) { tipX = crossPx - 6; tipAnchor = 'end'; }
    else { tipX = crossPx + 6; tipAnchor = 'start'; }
  }

  return (
    <div style={{
      background: '#0d0e1a', border: '1px solid var(--divider)',
      borderRadius: 14, overflow: 'hidden',
      boxShadow: '0 30px 70px rgba(0,0,0,0.4)',
      fontFamily: 'Inter, sans-serif',
      color: '#e5e7f0',
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 14px', background: '#0a0b14', borderBottom: '1px solid rgba(255,255,255,0.08)' }}>
        <span style={{ width: 11, height: 11, borderRadius: '50%', background: '#ff5a52' }}/>
        <span style={{ width: 11, height: 11, borderRadius: '50%', background: '#ffb84b' }}/>
        <span style={{ width: 11, height: 11, borderRadius: '50%', background: '#2cc93f' }}/>
        <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'rgba(255,255,255,0.45)', marginLeft: 10 }}>localhost:8501 · f1-strat post-race analysis</span>
      </div>

      <div style={{ padding: '18px 22px 20px', background: '#0d0e1a' }}>
        {/* Chat bubble — streams in */}
        <div style={{ display: 'flex', gap: 10, marginBottom: 14 }}>
          <div style={{
            width: 24, height: 24, flexShrink: 0,
            borderRadius: '50%',
            background: 'linear-gradient(135deg, #6c5ce7, #a29bfe)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            fontSize: 10, fontWeight: 700, color: '#fff',
            fontFamily: 'var(--font-display)'
          }}>F1</div>
          <div style={{
            flex: 1,
            background: 'rgba(108,92,231,0.10)',
            border: '1px solid rgba(108,92,231,0.35)',
            borderRadius: 10,
            padding: '10px 14px',
            fontSize: 11.5,
            lineHeight: 1.55,
            color: 'rgba(255,255,255,0.88)',
            minHeight: 60
          }}>
            {messageText}
            {showTypingCursor && <span className="sl-cursor">▍</span>}
          </div>
        </div>

        {/* Button — fades in */}
        <div style={{ opacity: showBtn ? 1 : 0, transform: showBtn ? 'none' : 'translateY(4px)', transition: 'all 0.3s' }}>
          <button style={{
            background: btnActive ? '#8574ff' : '#6c5ce7',
            color: '#fff', border: 'none',
            padding: '5px 12px', borderRadius: 6,
            fontSize: 11, fontWeight: 500,
            fontFamily: 'Inter, sans-serif',
            marginBottom: 12, cursor: 'default',
            boxShadow: btnActive ? '0 0 0 4px rgba(108,92,231,0.25)' : 'none',
            transition: 'all 0.2s'
          }}>Get Telemetry</button>
        </div>

        {/* Chart card — fades in, with hover crosshair */}
        <div style={{
          background: 'rgba(255,255,255,0.02)',
          border: '1px solid rgba(108,92,231,0.35)',
          borderRadius: 10,
          padding: '12px 8px 8px 8px',
          marginBottom: 12,
          opacity: showChart ? 1 : 0,
          transform: showChart ? 'none' : 'translateY(6px)',
          transition: 'opacity 0.45s, transform 0.45s'
        }}>
          <div style={{ fontSize: 10, color: '#fff', fontFamily: 'var(--font-mono)', marginLeft: 10, marginBottom: 2, fontWeight: 600 }}>LEC — lap 30 telemetry</div>
          <svg viewBox={`0 0 ${W} ${H - 80}`}
               style={{ width: '100%', height: 'auto', display: 'block', cursor: 'crosshair' }}
               onMouseMove={handleMove}
               onMouseLeave={() => setHoverX(null)}>
            {chartBands.map((band, bi) => (
              <g key={bi}>
                {band.ticks.map((t, ti) => {
                  const v = typeof t === 'number' ? t : (ti === 0 ? band.min : band.max);
                  const py = band.y + band.h - ((v - band.min) / (band.max - band.min)) * band.h;
                  return (
                    <g key={ti}>
                      <line x1={chartL} y1={py} x2={chartR} y2={py} stroke="rgba(255,255,255,0.06)" strokeWidth="0.5"/>
                      <text x={chartL - 6} y={py + 3} textAnchor="end" fontSize="8" fill="rgba(255,255,255,0.45)" fontFamily="Inter, sans-serif">{t}</text>
                    </g>
                  );
                })}
                <text x={(chartL + chartR) / 2} y={band.y - 3} textAnchor="middle" fontSize="8.5" fill="rgba(255,255,255,0.55)" fontFamily="Inter, sans-serif">{band.label}</text>
                <line x1={chartL} y1={band.y + band.h} x2={chartR} y2={band.y + band.h} stroke="rgba(255,255,255,0.12)" strokeWidth="0.5"/>
              </g>
            ))}

            <path d={toAreaPath(speedPts, chartBands[0])} fill={chartBands[0].fill}/>
            <path d={toPath(speedPts, chartBands[0])} stroke={chartBands[0].color} strokeWidth="1.3" fill="none"/>
            <path d={toAreaPath(throttlePts, chartBands[1])} fill={chartBands[1].fill}/>
            <path d={toPath(throttlePts, chartBands[1])} stroke={chartBands[1].color} strokeWidth="1.3" fill="none"/>
            <path d={toAreaPath(brakePts, chartBands[2])} fill={chartBands[2].fill}/>
            <path d={toPath(brakePts, chartBands[2])} stroke={chartBands[2].color} strokeWidth="1.3" fill="none"/>

            <line x1={chartL} y1={240} x2={chartR} y2={240} stroke="rgba(255,255,255,0.25)" strokeWidth="0.5"/>
            {[0, 1000, 2000, 3000, 4000, 5000].map((d) => {
              const px = chartL + (d / 5000) * chartW;
              return (
                <g key={d}>
                  <line x1={px} y1={240} x2={px} y2={244} stroke="rgba(255,255,255,0.35)" strokeWidth="0.5"/>
                  <text x={px} y={254} textAnchor="middle" fontSize="8" fill="rgba(255,255,255,0.55)" fontFamily="Inter, sans-serif">{d}</text>
                </g>
              );
            })}
            <text x={(chartL + chartR) / 2} y={265} textAnchor="middle" fontSize="8.5" fill="rgba(255,255,255,0.55)" fontFamily="Inter, sans-serif">Distance (m)</text>

            {/* Crosshair + markers + tooltip */}
            {crossPx != null && (
              <g pointerEvents="none">
                <line x1={crossPx} y1={16} x2={crossPx} y2={240} stroke="rgba(255,255,255,0.45)" strokeWidth="0.8" strokeDasharray="2 2"/>
                {/* dot on each band */}
                {chartBands.map((band, bi) => {
                  const pts = [speedPts, throttlePts, brakePts][bi];
                  const v = valueAt(pts, crosshairX);
                  const py = band.y + band.h - ((v - band.min) / (band.max - band.min)) * band.h;
                  return <circle key={bi} cx={crossPx} cy={py} r="2.5" fill={band.color} stroke="#fff" strokeWidth="0.7"/>;
                })}
                {/* tooltip */}
                <g transform={`translate(${tipX}, 28)`}>
                  <rect x={tipAnchor === 'end' ? -102 : 0} y="0" width="102" height="54"
                        rx="4" fill="#12131e" stroke="rgba(108,92,231,0.5)" strokeWidth="0.8"/>
                  <g transform={`translate(${tipAnchor === 'end' ? -96 : 6}, 0)`}>
                    <text y="11" fontSize="7.5" fill="rgba(255,255,255,0.55)" fontFamily="var(--font-mono)">dist</text>
                    <text x="88" y="11" textAnchor="end" fontSize="7.5" fill="#fff" fontFamily="var(--font-mono)" fontWeight="700">{crossDist} m</text>
                    <text y="23" fontSize="7.5" fill="#ff3a5a" fontFamily="var(--font-mono)">speed</text>
                    <text x="88" y="23" textAnchor="end" fontSize="7.5" fill="#fff" fontFamily="var(--font-mono)" fontWeight="700">{crossSpeed} km/h</text>
                    <text y="35" fontSize="7.5" fill="#00d7b5" fontFamily="var(--font-mono)">thr</text>
                    <text x="88" y="35" textAnchor="end" fontSize="7.5" fill="#fff" fontFamily="var(--font-mono)" fontWeight="700">{crossThr}%</text>
                    <text y="47" fontSize="7.5" fill="#ff3a5a" fontFamily="var(--font-mono)">brake</text>
                    <text x="88" y="47" textAnchor="end" fontSize="7.5" fill="#fff" fontFamily="var(--font-mono)" fontWeight="700">{crossBr}%</text>
                  </g>
                </g>
              </g>
            )}
          </svg>
        </div>

        {/* Attach image */}
        <div style={{
          border: '1px solid rgba(108,92,231,0.35)', borderRadius: 8,
          padding: '7px 12px', fontSize: 11, color: 'rgba(255,255,255,0.7)',
          marginBottom: 8, display: 'flex', alignItems: 'center', gap: 8,
          opacity: showChart ? 1 : 0, transition: 'opacity 0.5s'
        }}>
          <span style={{ fontSize: 9, color: 'rgba(255,255,255,0.45)' }}>▸</span>
          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" style={{ color: 'rgba(255,255,255,0.55)' }}>
            <path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/>
          </svg>
          <span>Attach image</span>
        </div>

        {/* Input */}
        <div style={{
          background: 'rgba(255,255,255,0.04)',
          border: '1px solid rgba(255,255,255,0.10)',
          borderRadius: 8,
          padding: '9px 12px',
          fontSize: 11.5,
          color: 'rgba(255,255,255,0.45)',
          display: 'flex', alignItems: 'center', justifyContent: 'space-between'
        }}>
          <span>Ask me anything about F1…</span>
          <button style={{
            width: 26, height: 20, background: '#6c5ce7', border: 'none', borderRadius: 4,
            display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'default'
          }}>
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="2.5">
              <path d="M12 19V5 M5 12l7-7 7 7"/>
            </svg>
          </button>
        </div>
      </div>
      <style>{`
        .sl-cursor {
          display: inline-block; width: 2px; margin-left: 2px;
          color: #a29bfe; animation: slBlink 0.9s step-end infinite;
        }
        @keyframes slBlink { 50% { opacity: 0; } }
      `}</style>
    </div>
  );
}

Object.assign(window, { TelemetrySection, CircuitSection, SurfacesSection });
