// ─── RACE ANALYSIS (2/2) — tyre strategy + the section under the round results ───────────────
const fraCss = `
.fra{background:#000;border-bottom:1px solid ${COLORS.hairline};padding:64px clamp(18px,4vw,56px) 80px;overflow:clip}
.fra-in{position:relative;z-index:1;max-width:1500px;margin:0 auto;display:grid;gap:28px}
.fra-tex{position:sticky;top:0;z-index:0;height:100vh;margin:-64px calc(-1 * clamp(18px,4vw,56px)) calc(64px - 100vh);pointer-events:none;background:url("assets/textures/checker-flag.jpg") center/cover;opacity:var(--fd-tex-op,.05);will-change:transform}
.fra-head{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:20px 32px}
.fra-k{font:500 12px/1 'JetBrains Mono',monospace;letter-spacing:.3em;text-transform:uppercase;color:${COLORS.red}}
.fra-h{margin:14px 0 0;font:900 clamp(36px,4.6vw,64px)/.92 'Archivo',sans-serif;letter-spacing:-.03em;text-transform:uppercase;color:${COLORS.text}}
.fra-sub{margin-top:12px;max-width:560px;font:400 15px/1.55 'Archivo',sans-serif;color:${COLORS.textMute}}
.fra-acts{display:flex;flex-wrap:wrap;gap:10px}
.fra-btn{all:unset;cursor:pointer;display:inline-flex;align-items:center;gap:10px;font:800 13px/1 'Archivo',sans-serif;letter-spacing:.12em;text-transform:uppercase;padding:15px 22px;background:${COLORS.red};color:#fff;text-decoration:none}
.fra-btn:hover{background:#ff1a12;color:#fff}
.fra-btn.ghost{background:transparent;border:1px solid rgba(255,255,255,.28)}
.fra-btn.ghost:hover{border-color:#fff}
.fra-btn .tri{width:0;height:0;border-left:10px solid currentColor;border-top:6px solid transparent;border-bottom:6px solid transparent}
.fra-panel{border:1px solid ${COLORS.hairline};background:rgba(255,255,255,.015);padding:22px clamp(14px,2vw,26px) 24px;min-width:0}
.fra-ph{display:flex;flex-wrap:wrap;align-items:center;gap:12px 18px;margin-bottom:18px}
.fra-pt{font:900 22px/1 'Archivo',sans-serif;text-transform:uppercase;letter-spacing:-.01em;color:${COLORS.text}}
.fra-tabs{display:inline-flex;gap:2px;padding:3px;border:1px solid rgba(243,241,236,.16);border-radius:999px}
.fra-tab{all:unset;cursor:pointer;font:500 12px/1 'JetBrains Mono',monospace;letter-spacing:.08em;text-transform:uppercase;padding:8px 12px;border-radius:999px;color:${COLORS.textDim}}
.fra-tab:hover{color:${COLORS.text}}
.fra-tab[aria-pressed="true"]{background:${COLORS.red};color:#fff}
.fra-cap{margin-left:auto;font:500 12px/1.4 'JetBrains Mono',monospace;letter-spacing:.1em;text-transform:uppercase;color:${COLORS.textMute}}
.fra-cap b{color:${COLORS.text}}
.fra-tick{font:500 12px 'JetBrains Mono',monospace;fill:${COLORS.textDim}}
.fra-end{font:700 12px 'Archivo Narrow','Archivo',sans-serif;text-transform:uppercase;letter-spacing:.02em}
.fra-tip{position:absolute;pointer-events:none;display:grid;gap:3px;min-width:170px;padding:9px 12px;background:rgba(8,8,10,.94);border:1px solid rgba(255,255,255,.18);font:500 12px/1.35 'JetBrains Mono',monospace;color:${COLORS.textMute};z-index:2}
.fra-tip b{font:800 14px/1.1 'Archivo',sans-serif;text-transform:uppercase}
.fra-leg{display:flex;align-items:stretch;gap:8px;margin-top:16px;min-width:0}
.fra-sel{min-width:0;max-width:100%}
.fra-leg>.fra-chip.all{flex:0 0 auto;justify-content:center;padding:0 14px;max-width:96px;white-space:normal;text-align:center;line-height:1.2}
.fra-lgrid{flex:1 1 auto;min-width:0;display:grid;grid-template-columns:repeat(10,minmax(0,1fr));gap:6px}
.fra-mc{all:unset;box-sizing:border-box;cursor:pointer;display:grid;gap:6px;padding:7px 8px 8px;min-width:0;border:1px solid ${COLORS.hairline};background:rgba(255,255,255,.02);transition:border-color .15s,background .15s}
.fra-mc:hover,.fra-mc:focus-visible{border-color:rgba(255,255,255,.45)}
.fra-mc[aria-pressed="true"]{border-color:#fff;background:rgba(255,255,255,.08)}
.fra-mc img,.fra-mc .gh{display:block;width:100%;height:26px;object-fit:contain;image-rendering:pixelated}
.fra-mc .gh{background:rgba(255,255,255,.12);-webkit-mask:url("assets/al-car.png") center/contain no-repeat;mask:url("assets/al-car.png") center/contain no-repeat}
.fra-mc .ln{display:flex;align-items:center;gap:6px;min-width:0;font:700 12px/1 'Archivo Narrow','Archivo',sans-serif;text-transform:uppercase;letter-spacing:.03em;color:${COLORS.text}}
.fra-mc .ln i{flex:0 0 auto;width:9px;height:9px;border-radius:50%}
.fra-mc .ln i.dash{background:transparent!important;box-shadow:inset 0 0 0 2px var(--c)}
.fra-mc .ln em{flex:0 0 auto;font-style:normal;font:900 12px/1 'Archivo',sans-serif;color:${COLORS.textMute};font-variant-numeric:tabular-nums}
.fra-mc .ln span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media (max-width:1000px){.fra-lgrid{display:flex;overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:thin;padding-bottom:4px}.fra-mc{flex:0 0 108px}}
.fra-chip{all:unset;cursor:pointer;display:inline-flex;align-items:center;gap:8px;padding:6px 10px;border:1px solid ${COLORS.hairline};font:700 12px/1 'Archivo Narrow','Archivo',sans-serif;text-transform:uppercase;letter-spacing:.03em;color:${COLORS.text}}
.fra-chip[aria-pressed="true"]{border-color:#fff}
.fra-chip i{display:block;width:18px;height:0;border-top:3px solid}
.fra-ty{display:grid;gap:5px}
.fra-row{display:grid;grid-template-columns:28px 48px minmax(76px,150px) minmax(0,1fr) 78px;align-items:center;gap:10px;cursor:default;transition:opacity .15s}
.fra-row .p{font:900 15px/1 'Archivo',sans-serif;color:${COLORS.textMute};text-align:right;font-variant-numeric:tabular-nums}
.fra-row .n{font:800 14px/1 'Archivo',sans-serif;text-transform:uppercase;color:${COLORS.text};white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fra-row .g{font:500 12px/1 'JetBrains Mono',monospace;color:${COLORS.textMute};text-align:right;font-variant-numeric:tabular-nums}
.fra-row img{width:46px;height:auto;display:block}
.fra-track{position:relative;height:22px}
.fra-st{position:absolute;top:0;bottom:0;display:grid;place-items:center;font:800 11px/1 'Archivo',sans-serif;border-right:2px solid #000;box-sizing:border-box;overflow:hidden}
.fra-axis{position:relative;height:18px;font:500 12px/1 'JetBrains Mono',monospace;color:${COLORS.textDim}}
.fra-axis span{position:absolute;transform:translateX(-50%)}
.fra-grid{position:absolute;top:0;bottom:0;width:1px;background:rgba(255,255,255,.06)}
.fra-wx{height:12px;border:1px solid ${COLORS.hairline}}
.fra-keys{display:flex;flex-wrap:wrap;gap:8px 16px;margin-left:auto;font:500 12px/1 'JetBrains Mono',monospace;letter-spacing:.06em;text-transform:uppercase;color:${COLORS.textMute}}
.fra-keys span{display:inline-flex;align-items:center;gap:6px}
.fra-keys i{display:inline-block;width:12px;height:12px}
.fra-note{font:500 12px/1.6 'JetBrains Mono',monospace;letter-spacing:.04em;color:${COLORS.textDim}}
`;

function FRATyres({ S, drv, foc = [] }) {
  const L = S.cars[0].done,pct = (l) => Math.max(0, Math.min(L, l)) / L * 100;
  const ticks = [];const xs = L > 30 ? 5 : L > 14 ? 2 : 1;for (let n = xs; n <= L; n += xs) ticks.push(n);
  const used = [...new Set(S.cars.flatMap((c) => c.stints.map((s) => s.c)).filter(Boolean))].sort((a, b) => 'SMHIW'.indexOf(a) - 'SMHIW'.indexOf(b));
  const wxStops = S.wx.filter((_, i) => i % 3 === 0).map((w) => `rgba(47,127,216,${Math.min(0.95, w.wet * 1.4 + w.rain * 0.5).toFixed(2)}) ${pct(w.l).toFixed(2)}%`);
  const wetAny = S.wx.some((w) => w.wet > 0.02 || w.rain > 0);
  return (
    <div className="fra-ty">
      <div className="fra-row" style={{ cursor: 'default' }}><span></span><span></span><span className="g" style={{ textAlign: 'left' }}>Lap</span>
        <div className="fra-axis">{ticks.map((n) => <span key={n} style={{ left: pct(n) + '%' }}>{n}</span>)}</div><span></span></div>
      {wetAny && <div className="fra-row"><span></span><span></span><span className="g" style={{ textAlign: 'left' }}>Track wet</span>
        <div className="fra-wx" style={{ background: wxStops.length > 1 ? `linear-gradient(90deg, ${wxStops.join(', ')})` : 'none' }} title="Track wetness from the replay (darker = wetter)"></div><span></span></div>}
      {S.cars.map((c) => {
        const d = drv[c.id];
        return (
          <div key={c.id} className="fra-row" style={{ opacity: !foc.length || foc.includes(c.id) ? 1 : 0.3 }}>
            <span className="p">{c.dnf ? '—' : c.pos}</span>
            {d.car ? <img src={d.car} alt=""></img> : <span></span>}
            <span className="n" style={{ boxShadow: `inset 3px 0 0 ${d.color}`, paddingLeft: 9 }}>{d.label}</span>
            <div className="fra-track">
              {ticks.map((n) => <span key={n} className="fra-grid" style={{ left: pct(n) + '%' }}></span>)}
              {c.stints.map((s, i) => {const t = FRA_TYRE[s.c] || ['#444', '#fff', '?'],w = pct(s.to) - pct(s.from),pit = c.pits.find((p) => Math.abs(p.at - s.to) < 0.08);
                return <span key={i} className="fra-st" title={`${t[2]} · laps ${Math.floor(s.from) + 1}–${Math.ceil(s.to)}${pit ? ` · stop ${pit.dur.toFixed(1)}s in the pit lane` : ''}`}
                style={{ left: pct(s.from) + '%', width: w + '%', background: t[0], color: t[1] }}>{w > 3.2 ? s.c : ''}</span>;})}
              {c.pits.filter((p) => !p.tyres).map((p, i) => <span key={'p' + i} title={`Stop on lap ${p.lap} · ${p.dur.toFixed(1)}s in the pit lane · no tyre change`} style={{ position: 'absolute', top: -3, bottom: -3, width: 3, left: `calc(${pct(p.at)}% - 1.5px)`, background: '#000', boxShadow: '0 0 0 1px #fff' }}></span>)}
            </div>
            <span className="g">{c.dnf ? 'DNF' : c.pos === 1 ? fraFmt(c.time) : typeof c.gap === 'string' ? c.gap : '+' + c.gap.toFixed(3)}</span>
          </div>);
      })}
    </div>);
}

function FDRaceAnalysis({ ctx }) {
  const _rl = typeof useReplayList === 'function' ? useReplayList() : window.UR2D_REPLAYS || [];
  const here = _rl.filter((x) => x.session !== 'sprint' && x.calSeason === ctx.calSeason && x.calRound === ctx.round);
  const r = here.find((x) => x.league === ctx.league) || null;
  const st = useReplayStats(r);
  const box = React.useRef(null);
  React.useEffect(() => {// deep link from the Replays page: bring the analysis into view once it's drawn
    if (!window.__fdScrollAnalysis || st.status !== 'ready' || !box.current) return;
    window.__fdScrollAnalysis = false;
    const navH = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--fd-nav-h')) || 72;
    setTimeout(() => window.scrollTo({ top: box.current.getBoundingClientRect().top + window.scrollY - navH, behavior: 'smooth' }), 120);
  }, [st.status]);
  const [mode, setMode] = React.useState('gap');
  const [pin, setPin] = React.useState([]);
  const drv = React.useMemo(() => st.data ? fraIdentify(st.data, ctx) : null, [st.data, ctx.league, ctx.season, ctx.rdt, ctx.std]);
  const lgPick = here.length && ctx.setLeague ? <span className="fra-tabs" role="group" aria-label="League">{here.slice().sort((a, b) => ['ul', 'hl', 'jl', 'al'].indexOf(a.league) - ['ul', 'hl', 'jl', 'al'].indexOf(b.league)).map((x) => {const L = LEAGUES.find((l) => l.id === x.league) || {};return <button key={x.league} className="fra-tab" aria-pressed={x.league === ctx.league ? 'true' : 'false'} onClick={() => ctx.setLeague(x.league)} style={{ display: 'inline-flex', alignItems: 'center', gap: 7 }}><img src={L.logo} alt="" style={{ height: 13, width: 'auto', display: 'block' }}></img>{L.short}</button>;})}</span> : null;
  if (!r) return here.length && ctx.setLeague ?
  <section className="fra" style={{ padding: '26px clamp(18px,4vw,56px)' }}><style>{fraCss}</style>
      <div className="fra-in"><div className="fra-ph" style={{ margin: 0 }}><span className="fra-k">◆ Race analysis + replay</span><span className="fra-cap" style={{ marginLeft: 0 }}>Available for this round in</span>{lgPick}</div></div>
    </section> : null;
  const S = st.data,foc = pin;
  const pick = (id, jump) => {setPin(pin.includes(id) ? pin.filter((x) => x !== id) : [...pin, id]);if (jump && box.current) {const navH = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--fd-nav-h')) || 72;window.scrollTo({ top: box.current.getBoundingClientRect().top + window.scrollY - navH, behavior: 'smooth' });}};
  const selCars = S ? pin.map((id) => S.cars.find((c) => c.id === id)).filter(Boolean) : [];
  const panel = (title, extra, body) => <div className="fra-panel"><div className="fra-ph"><span className="fra-pt">{title}</span>{extra}</div>{body}</div>;
  const openReplay = () => {if (window.fdGo) window.fdGo('replay/' + r.id);else window.location.hash = 'replay/' + r.id;};
  const fl = S && S.fastest && S.cars.find((c) => c.id === S.fastest.id);
  const m = mode === 'wet' && !(S && S.wet) ? 'gap' : mode;
  return (
    <section ref={box} className="fra" id="fd-race-analysis" data-screen-label="Final — Race analysis" style={typeof window.fdHomeBody === 'function' ? window.fdHomeBody() : undefined}>
      <style>{fraCss + fra3Css + fraWetCss + '.fra-sel{position:sticky;top:var(--fd-nav-h,72px);z-index:20;margin:0;padding:12px 0;max-width:none;border:0;background:none;border-image:linear-gradient(180deg,rgba(0,0,0,.9) calc(100% - 1px),' + COLORS.hairline + ' calc(100% - 1px)) 0 fill / 0 / 0 100vmax;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.fra-sel .fra-leg{margin:0}.fra-chip.all{font-family:JetBrains Mono,monospace;font-weight:600;letter-spacing:.12em}.fra-chip em{font:500 12px/1 JetBrains Mono,monospace;font-style:normal;color:' + COLORS.textMute + '}.fra-chip[aria-pressed="true"]{background:rgba(255,255,255,.1)}'}</style>
      <div className="fra-tex" aria-hidden="true"></div>
      <div className="fra-in">
        <div className="fra-head">
          <div>
            <div className="fra-k">◆ Race analysis · from the replay</div>
            <h2 className="fra-h">RACE <span style={{ color: COLORS.red }}>ANALYTICS</span></h2>
            <div className="fra-sub">Every lap of the race, worked out from the car positions in Bituko's replay.</div>
            {here.length > 1 && <div style={{ marginTop: 14 }}>{lgPick}</div>}
          </div>
          <div className="fra-acts">
            <button className="fra-btn" onClick={openReplay}><span className="tri"></span>Watch the replay</button>
            <a className="fra-btn ghost" href={encodeURI(r.file)} target="_blank" rel="noopener">Full page ↗</a>
          </div>
        </div>
        {!S ? <div className="fra-panel fra-note">{st.status === 'error' ? 'Couldn’t read the replay data.' : 'Reading the replay…'}</div> :
        <React.Fragment>
          <div className="fra-sel">
            <div className="fra-leg" role="group" aria-label="Driver">
              <button className="fra-chip all" aria-pressed={!pin.length ? 'true' : 'false'} onClick={() => setPin([])}>All drivers</button>
              <div className="fra-lgrid">{S.cars.map((c) => {const d = drv[c.id];return <button key={c.id} className="fra-mc" aria-pressed={pin.includes(c.id) ? 'true' : 'false'} onClick={() => pick(c.id)} title={d.label + (d.team ? ' · ' + d.team : '') + (c.dnf ? ' · DNF' : ' · P' + c.pos)}>
                {d.car ? <img src={d.car} alt="" loading="lazy" /> : <span className="gh"></span>}
                <span className="ln"><i className={d.dash ? 'dash' : ''} style={{ '--c': d.color, background: d.stripe && d.color2 && !d.dash ? `repeating-linear-gradient(90deg, ${d.color} 0 3px, ${d.color2} 3px 6px)` : d.color }}></i><em>{c.dnf ? '—' : c.pos}</em><span>{d.label}</span></span>
              </button>;})}</div>
            </div>
          </div>
          {selCars.length === 1 && <FRADriverCard S={S} c={selCars[0]} d={drv[selCars[0].id]} big={true} />}
          {selCars.length > 1 && <div className="fra-cards">{selCars.map((c) => <FRADriverCard key={c.id} S={S} c={c} d={drv[c.id]} onClick={() => pick(c.id)} />)}</div>}
          <div className="fra-panel">
            <div className="fra-ph">
              <span className="fra-pt">Race trace</span>
              <span className="fra-tabs" role="group" aria-label="Chart">
                {[['gap', 'Gap'], ['pos', 'Positions'], ['laps', 'Lap times'], ...(S.wet ? [['wet', 'Wet pace']] : [])].map(([k, l]) => <button key={k} className="fra-tab" aria-pressed={m === k ? 'true' : 'false'} onClick={() => setMode(k)} style={k === 'wet' && m === k ? { background: FRA_WET } : null}>{l}</button>)}
              </span>
              <span className="fra-cap">{m === 'gap' ? 'Gap to the winner’s average pace · up = ahead' : m === 'pos' ? 'Running order at the end of every lap' : m === 'wet' ? 'Average clean lap on a wet track · fastest first' : fl ? <span>Fastest lap <b style={{ color: '#C98BFF' }}>{drv[fl.id].label} {fraFmt(S.fastest.t)}</b> · L{S.fastest.lap}</span> : ''}</span>
            </div>
            {m === 'wet' ? <React.Fragment><FRAWetCard S={S} drv={drv} /><FRAWetPace S={S} drv={drv} foc={foc} /></React.Fragment> : <FRARaceTrace S={S} drv={drv} mode={m} foc={foc} />}
          </div>
          {panel('Lap times', <span className="fra-cap">Every lap, coloured by how far off the fastest lap it was</span>, <FRAHeatmap S={S} drv={drv} foc={foc} onPick={(id) => pick(id)} />)}
          {typeof FRALapCompare === 'function' && S.tele && <FRALapCompare key={r.id} S={S} drv={drv} pin={pin} />}
          {panel('Stint analysis', <span className="fra-cap">{selCars.length ? selCars.map((c) => drv[c.id].label).join(' · ') : 'Pace against tyre age, every stint'}</span>, <FRAStints S={S} drv={drv} foc={foc} />)}
          <div className="fra-panel">
            <div className="fra-ph">
              <span className="fra-pt">Tyre strategy</span>
              <span className="fra-keys">{['S', 'M', 'H', 'I', 'W'].filter((k) => S.cars.some((c) => c.stints.some((s) => s.c === k))).map((k) => <span key={k}><i style={{ background: FRA_TYRE[k][0] }}></i>{FRA_TYRE[k][2]}</span>)}</span>
            </div>
            <FRATyres S={S} drv={drv} foc={foc} />
          </div>
          {!selCars.length && panel('Driver summaries', <span className="fra-cap">Click a driver to focus the whole page on them</span>, <FRADriverCards S={S} drv={drv} onPick={(id) => pick(id, true)} />)}
          <div className="fra-note">Lap times and gaps come from each car’s progress around the lap, so they can differ by a few tenths from the official timing. Blue shading = wet track.{S.wet ? ' A lap counts as wet once the track averaged 5% wetness or more across it — already enough to cost slick tyres seconds a lap.' : ''}</div>
        </React.Fragment>}
      </div>
    </section>);
}

Object.assign(window, { FDRaceAnalysis });