// UR2D — Sub-pages: Standings, Results, Drivers (editorial), Calendar (full), Discord (join CTA).

// ─────────────────────────────────────────────────────────────────────────────
// SHARED — Page hero header (compact: big league logo + tight title)
const URPageHeader = ({ title, italic, league, right }) => {
  const L = league ? LEAGUE_BY_ID[league] : null;
  const accent = L ? L.accent : COLORS.red;
  return (
    <section style={{
      background: `linear-gradient(115deg, ${accent}33 0%, ${accent}12 28%, #000 60%)`,
      padding: '22px 40px 16px', position: 'relative', overflow: 'hidden', borderBottom: `1px solid ${accent}55`
    }}>
      <div aria-hidden style={{
        position: 'absolute', right: -160, top: -200, width: 520, height: 520, borderRadius: '50%',
        background: `radial-gradient(circle, ${accent}40 0%, transparent 62%)`, filter: 'blur(50px)'
      }} />
      <div aria-hidden style={{
        position: 'absolute', left: -120, bottom: -160, width: 360, height: 360, borderRadius: '50%',
        background: `radial-gradient(circle, ${accent}26 0%, transparent 60%)`, filter: 'blur(40px)'
      }} />
      <div style={{ position: 'relative', display: 'flex', alignItems: 'center', gap: 28, flexWrap: 'wrap' }}>
        {league && <div style={{ padding: '4px 8px 4px 0' }}><LeagueBadge league={league} height={100} showName={false} /></div>}
        <h1 style={{ margin: 0, fontFamily: 'Archivo', fontWeight: 900, fontSize: 48, color: COLORS.text, letterSpacing: '-0.025em', lineHeight: 1, textTransform: 'uppercase', flex: 1 }}>
          {title} <span style={{ color: L ? L.accent : COLORS.red, textTransform: 'none' }}>{italic}</span>
        </h1>
        {right && <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexShrink: 0 }}>{right}</div>}
      </div>
    </section>);

};

// Small band that sits just above content — holds the league switcher
const URLeagueBand = ({ league, setLeague, left }) => {
  const CTRL_H = 44;
  return (
    <div style={{ background: COLORS.base, padding: '20px 40px 0', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap' }}>
      {/* LHS: season + view controls */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>{left}</div>
      {/* RHS: logo-only league buttons */}
      <div style={{ display: 'inline-flex', border: `1px solid ${COLORS.hairline}`, background: COLORS.panel }}>
        {LEAGUES.map((Lg, i) => {
          const active = league === Lg.id;
          return (
            <button key={Lg.id} onClick={() => setLeague(Lg.id)} style={{
              all: 'unset', cursor: 'pointer',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              width: CTRL_H + 8, height: CTRL_H, boxSizing: 'border-box',
              background: active ? COLORS.surface : 'transparent',
              borderRight: i < LEAGUES.length - 1 ? `1px solid ${COLORS.hairline}` : 'none',
              position: 'relative', transition: 'background .12s ease'
            }}>
              {active && <span style={{ position: 'absolute', left: 0, right: 0, bottom: 0, height: 2, background: Lg.accent }} />}
              <img src={Lg.logo} alt={Lg.short} style={{ height: 28, width: 28, objectFit: 'contain', display: 'block', opacity: active ? 1 : 0.45, filter: active ? 'none' : 'grayscale(.5)' }} />
            </button>);

        })}
      </div>
    </div>);

};


// ─────────────────────────────────────────────────────────────────────────────
// STANDINGS PAGE — Constructors + Drivers tables
// UL team logos keyed by constructor acronym (store t.short)
const UR_TEAM_LOGO = {
  ONE: 'assets/teams/one-white.png', LSA: 'assets/teams/lsa.png', FLF: 'assets/teams/flf.png',
  RMC: 'assets/teams/rmc.png', MAY: 'assets/teams/may.png', RKA: 'assets/teams/rka.png',
  SCP: 'assets/teams/scp.png', SGP: 'assets/teams/sgp.png', LYR: 'assets/teams/lyr.png',
  KMP: 'assets/teams/kmp.png', VLP: 'assets/teams/vlp.png', MZM: 'assets/teams/mzm.png',
  ARR: 'assets/teams/arr.png', PRO: 'assets/teams/pro.png', HKB: 'assets/teams/hkb.png',
  CPR: 'assets/teams/cpr.png', RGT: 'assets/teams/rgt.png',
  RSR: 'assets/teams/rsr.png', SWR: 'assets/teams/swr.png', SPR: 'assets/teams/spr.png',
  '8SM': 'assets/teams/8sm.png', DCR: 'assets/teams/dcr.png', ALR: 'assets/teams/alr.png',
  ZIP: 'assets/teams/zip.png', TCR: 'assets/teams/tcr.png', FGR: 'assets/teams/fgr.png', // FGR: user 2026-10-09, white bg keyed out
  NTH: 'assets/teams/nth.png', NBZ: 'assets/teams/nbz.png', // 3XIE's versions (user 2026-10-09)
  LTE: 'assets/teams/lte.png', NSR: 'assets/teams/nsr.png', // cut from their banners (user 2026-10-09): LTE crest, NSR sun disc
  BBZ: 'assets/teams/bbz.png', RRT: 'assets/teams/rrt.png', // cut from banners — not DB teams, so unused for now
  SRA: 'assets/teams/sra.png', EDGE: 'assets/teams/edge.png', BCR: 'assets/teams/bcr.png', DSZ: 'assets/teams/dsz.png', DIA: 'assets/teams/dia.png', CRM: 'assets/teams/crm.png', ZEK: 'assets/teams/zek.png', HPF: 'assets/teams/hpf.png', FRV: 'assets/teams/frv.png', SOL: 'assets/teams/sol.png', /* SOL = the transparent master from #jl-media */ // from Media Sift (#cl-media), user 2026-10-09
  VEO: 'assets/teams/veo.png', // Vulpe e Oca fox + goose crest (≈200 px source — small; user 2026-10-09)
  '8SR': 'assets/teams/8sm.png', ASR: 'assets/minilogos/ASR.png', AJR: 'assets/teams/ajr.png', BRR: 'assets/teams/brr.png', ASN: 'assets/teams/rsr.png', ASX: 'assets/teams/asx.png' // ASX = 60px placeholder (only logo available), upscaled pixel-crisp
};
// Near-white logos that would vanish on the white badge — darken them.
const UR_TEAM_LOGO_DARK = new Set();
// Rectangular team BANNERS (wordmark lockups, not square marks) — STORED ONLY, not rendered anywhere yet (user 2026-10-09).
// Kept separate from UR_TEAM_LOGO so they never land in square logo slots. Note: may have opaque backgrounds.
const UR_TEAM_BANNER = {
  NSR: 'assets/teams/banners/nsr.png', // Neon Sunset Racing — 698×236, opaque #333 bg ("Powered by Neon Flow Engineering")
  VEO: 'assets/teams/banners/veo.png', // Vulpe e Oca — 652×268, opaque grey gradient bg
  BBZ: 'assets/teams/banners/bbz.png', // Black Blizzard (BBZ — CONFIRMED by user 2026-10-09; UL S1–S7 role) — 477×200, opaque dark bg; BBZ isn't a DB team (cars stored, unshown)
  RRT: 'assets/teams/banners/rrt.png', // "RRT" (Rapid Racing Team, UL S6 role) — 692×242, opaque orange bg; not a DB team
  LTE: 'assets/teams/banners/lte.png', // Leviosso Talenti Emergenti — 639×237, opaque orange bg, lion-crest + "LTE"
  'BAR:russo-british': 'assets/teams/banners/bar-russo-british.png', // Russo-British Racing — 650×213, opaque green gradient bg. Same Discord role
  // lineage as British Ariel Racing (UL BAR; the livery import mapped the "Russo British Racing" role → BAR). NOT AL's "BAR 1999".
};
Object.assign(window, { UR_TEAM_BANNER });
// ALTERNATE team marks (secondary logos / old crests) — STORED ONLY, not rendered yet (user 2026-10-09). All transparent PNGs.
const UR_TEAM_LOGO_ALT = {
  LSA: 'assets/teams/alt/lsa.png', // lion + "Leviosso Sports Art" wordmark lockup (965×707, red/grey)
  RMC: 'assets/teams/alt/rmc.png',
  EDGE: 'assets/teams/alt/edge.png', // three slanted bars (red / maroon / grey) — square-friendly mark from the same #cl-media post // "R" monogram, black + orange (black part vanishes on dark grounds)
};
Object.assign(window, { UR_TEAM_LOGO_ALT });
// Logos for codes SHARED by two DB teams (BAR, HAA, SPR, TUR) — keyed by normalized team name (lowercase a-z0-9) so the
// other team never borrows it. File naming: assets/teams/<code>-<name>.png. Consulted by fdtOldLogo before the shared-code block.
const UR_TEAM_LOGO_NAMED = {
  russobritishracing: 'assets/teams/bar-russo-british.png', // RU+UK flag cut from the banner — no DB team carries this name yet
  britisharielracing: 'assets/teams/bar-british-ariel.png', // UL — "ARIEL" green mark (user 2026-10-09); NOT AL's "BAR 1999"
};
Object.assign(window, { UR_TEAM_LOGO_NAMED });
// White-only logos → their BLACK artwork when drawn on a white/light ground (P1 plate, white badges).
const UR_TEAM_LOGO_ON_LIGHT = { ONE: 'assets/teams/one.png' };
const urTeamLogo = (short, onLight) => (onLight && UR_TEAM_LOGO_ON_LIGHT[short]) || UR_TEAM_LOGO[short];
Object.assign(window, { UR_TEAM_LOGO_ON_LIGHT, urTeamLogo });
// TCR's jockey-silhouette mark is solid dark green — reads fine on white as-is, no darken filter needed.
// 8SM's new logo (dark badge, orange outline) also reads fine on white — no darken filter needed.

// Car liveries — top-down renders, keyed by league → constructor acronym.
// AL is not team-based, so no liveries. (JL sheet uses 8SM; the file is named ESM.)
const UR_LIVERY = {
  ul: {
    ONE: 'assets/UL Liveries/car1_UL_S24_ONE.png', FLF: 'assets/UL Liveries/car2_UL_S24_FLF.png',
    LSA: 'assets/UL Liveries/car3_UL_S24_LSA.png', SGP: 'assets/UL Liveries/car4_UL_S24_SGP.png',
    RMC: 'assets/UL Liveries/car5_UL_S24_RMC.png', SCP: 'assets/UL Liveries/car6_UL_S24_SCP.png',
    RKA: 'assets/UL Liveries/car7_UL_S24_RKA.png', MAY: 'assets/UL Liveries/car8_UL_S24_MAY.png',
    LYR: 'assets/UL Liveries/car9_UL_S24_LYR.png'
  },
  // UL S25 — new-season liveries (KMP + MZM promoted up from HL). Note: this static
  // UR_LIVERY map has no per-season key, so S25 acronyms overwrite S24's ONE/LSA/FLF/
  // SCP/RKA/SGP/MAY entries above (RMC/LYR keys are simply unused once S25 is active).
  // The store's per-season `teamLiveries` (ur2d-store.jsx) is the season-correct source;
  // this map only feeds legacy `getLivery()` call sites.
  ulS25: {
    ONE: 'assets/UL S25 Liveries/UL_S25_ONE.png', LSA: 'assets/UL S25 Liveries/UL_S25_LSA.png',
    FLF: 'assets/UL S25 Liveries/UL_S25_FLF.png', MAY: 'assets/UL S25 Liveries/UL_S25_MAY.png',
    RKA: 'assets/UL S25 Liveries/UL_S25_RKA.png', SCP: 'assets/UL S25 Liveries/UL_S25_SCP.png',
    SGP: 'assets/UL S25 Liveries/UL_S25_SGP.png', KMP: 'assets/UL S25 Liveries/UL_S25_KMP.png',
    MZM: 'assets/UL S25 Liveries/UL_S25_MZM.png'
  },
  hl: {
    ARR: 'assets/HL Liveries/HL_S21_ARR.png', CPR: 'assets/HL Liveries/HL_S21_CPR.png',
    HKB: 'assets/HL Liveries/HL_S21_HKB.png', KMP: 'assets/HL Liveries/HL_S21_KMP.png',
    MZM: 'assets/HL Liveries/HL_S21_MZM.png', PRO: 'assets/HL Liveries/HL_S21_PRO.png',
    RGT: 'assets/HL Liveries/HL_S21_RGT.png', VLP: 'assets/HL Liveries/HL_S21_VLP.png'
  },
  jl: {
    ALR: 'assets/JL Liveries/JL_S20B_ALR.png', DCR: 'assets/JL Liveries/JL_S20B_DCR.png',
    '8SM': 'assets/JL Liveries/JL_S20B_ESM.png', RSR: 'assets/JL Liveries/JL_S20B_RSR.png',
    SPR: 'assets/JL Liveries/JL_S20B_SPR.png', SWR: 'assets/JL Liveries/JL_S20B_SWR.png',
    ZIP: 'assets/JL Liveries/JL_S20B_ZIP.png'
  }
};
const getLivery = (league, short) => (UR_LIVERY[league] || {})[short];

// ─── Championship clinch (golden laurel) ──────────────────────────────────────
// Max title points still winnable in a single round, per league (feature + fastest lap,
// plus the sprint for HL). Deliberately generous so a laurel never appears prematurely.
const UR_MAX_PTS_PER_ROUND = { ul: 26, hl: 34, jl: 26, al: 26 };

// Returns the name of the driver whose title is mathematically secured, else null.
// Secured when the season is finished/archived (no rounds left, or not the current season)
// OR the leader's gap to P2 already exceeds the points still winnable in the rounds left.
function getClinchedChampion(league, drivers, season) {
  if (!drivers || !drivers.length) return null;
  const p1 = drivers[0];
  const gap = drivers.length > 1 ? p1.pts - drivers[1].pts : p1.pts;
  let remaining = null;
  try {remaining = getCalendar(league).races.filter((r) => r.status !== 'done').length;} catch (e) {/* offline */}
  if (season && season.isCurrent === false || remaining === 0) return p1.name; // decided
  if (remaining == null) return null;
  return gap > remaining * (UR_MAX_PTS_PER_ROUND[league] || 26) ? p1.name : null;
}

// Golden laurel-wreath icon. Sized to sit inline with the driver name (no row-height change).
const LaurelIcon = ({ size = 24, title = 'Champion clinched' }) => {
  // Left-half leaves along a horseshoe arc (center 12,12). Each: [cx, cy, rotation].
  const leaves = [
  [12.0, 20.2, 90], [8.4, 19.0, 116], [5.6, 16.6, 142],
  [4.2, 13.0, 168], [4.4, 9.1, 196], [6.0, 5.8, 222], [8.8, 3.7, 248]];

  return (
    <svg width={size} height={size} viewBox="0 0 24 24" role="img" aria-label={title} style={{ flexShrink: 0, filter: 'drop-shadow(0 1px 1.5px rgba(120,80,0,0.45))' }}>
      <title>{title}</title>
      <defs>
        <linearGradient id="ur-laurel" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor="#FFEFA8" />
          <stop offset="0.5" stopColor="#F3C13F" />
          <stop offset="1" stopColor="#B8861B" />
        </linearGradient>
      </defs>
      <g fill="url(#ur-laurel)">
        {[1, -1].map((dir) =>
        <g key={dir} transform={dir === -1 ? 'translate(24,0) scale(-1,1)' : undefined}>
            {leaves.map(([cx, cy, rot], i) =>
          <ellipse key={i} cx={cx} cy={cy} rx="2.7" ry="1.35" transform={`rotate(${rot} ${cx} ${cy})`} />
          )}
          </g>
        )}
        <circle cx="12" cy="21.4" r="1.4" />
      </g>
    </svg>);

};

// ─── Driver nationality lookup ────────────────────────────────────────────────
// Nationalities live in UR_DRIVER_NATIONALITY in ur2d-store.jsx — edit there, not here.
const UR_DRIVER_FLAG = {
  // UL S24
  'Justin': 'nl', // Netherlands
  // HL S21
  'DiMartino': 'fr', // France
  'Glow': 'fr', // France
  'Juan': 'mx', // Mexico
  'juan': 'mx',
  'Peto': 'ge', // Georgia
  'peto': 'ge',
  'Kozeel': 'cz', // Czech Republic
  'kozeel': 'cz',
  'Sigmabob': 'it', // Italy
  'Dziuaura': 'pl', // Poland
  'Mika2Mika': 'et', // Ethiopia
  'mika2mika': 'et',
  'Lexus112': 'sk', // Slovakia
  'Mr. Krunk': 'ca', // Canada
  // HL S21
  'Finguala': 'tr', // Turkey
  'Coemsvel': 've', // Venezuela
  'Gaelprad': 'fr' // France






































  // UL S24 — fill in as nationalities are confirmed
  // 'Riven': 'usa',
};const getDriverFlag = (name) => {if (!name) return null;const n = name.toLowerCase();return window.UR_DRIVER_NATIONALITY && UR_DRIVER_NATIONALITY[n] || window.getRosterCountry && getRosterCountry(name) || null;};const URStandings = ({ league, setLeague, density }) => {const L = LEAGUE_BY_ID[league];const MEDAL = ['#FFD24A', '#C9CDD4', '#CD7F32']; // gold / silver / bronze for P1–P3
  // Row-density tweak — drives a SHARED row height + cell padding so the Teams and
  // Pilots tables always line up regardless of setting.
  const DENSITY = { compact: { rowH: 52, padY: 10 }, regular: { rowH: 72, padY: 16 }, large: { rowH: 98, padY: 26 } };const den = DENSITY[density] || DENSITY.regular;const seasons = getSeasons(league); // dropdown list for THIS league
  const [seasonId, setSeasonId] = React.useState(null); // Falls back to the league's current/first season when the picked id isn't in this league
  // (so switching leagues auto-resets the season selection).
  const activeId = seasons.some((s) => s.id === seasonId) ? seasonId : defaultDataSeasonId(seasons);const data = useStandings(league, activeId); // canonical standings from the shared store
  // Table styles — reusable across constructors/drivers
  const tableStyle = { width: '100%', borderCollapse: 'collapse', fontFamily: 'Archivo' };const thStyle = { textAlign: 'left', padding: '14px 20px', fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.22em', color: COLORS.textDim, textTransform: 'uppercase', borderBottom: `1px solid ${COLORS.hairline}`, background: COLORS.ink, fontWeight: 600 };const tdStyle = { padding: `${den.padY}px 20px`, borderBottom: `1px solid ${COLORS.hairline}`, verticalAlign: 'middle' };const [view, setView] = React.useState('both'); // 'both' | 'drivers' | 'constructors'
  const isTeamBased = !!data.season?.teamBased; // Shared style for both dropdowns — enforces identical 44px height.
  const CTRL_H = 44;const dropStyle = { appearance: 'none', WebkitAppearance: 'none', MozAppearance: 'none', height: CTRL_H, boxSizing: 'border-box', background: COLORS.surface, color: COLORS.text, border: `1px solid ${COLORS.hairline}`, borderRadius: 0, padding: '0 38px 0 16px', cursor: 'pointer', fontFamily: 'Archivo', fontWeight: 800, fontSize: 14, letterSpacing: '0.04em' };const Chevron = ({ c }) => <span aria-hidden style={{ position: 'absolute', right: 12, top: '50%', transform: 'translateY(-50%)', pointerEvents: 'none', color: c || L.accent, fontSize: 9 }}>▼</span>; // LHS control panel — season dropdown + view dropdown (view hidden for non-team leagues).
  const controls = <React.Fragment>
      <div style={{ position: 'relative' }}>
        <select value={activeId || ''} onChange={(e) => setSeasonId(e.target.value)} style={dropStyle}>
          {seasons.map((s) => <option key={s.id} value={s.id} style={{ background: COLORS.ink, color: COLORS.text }}>{s.label}{s.hasData ? '' : ' · soon'}</option>)}
        </select>
        <Chevron /></div>
      {isTeamBased && <div style={{ position: 'relative' }}>
          <select value={view} onChange={(e) => setView(e.target.value)} style={dropStyle}>
            <option value="both" style={{ background: COLORS.ink }}>Both</option>
            <option value="drivers" style={{ background: COLORS.ink }}>Drivers</option>
            <option value="constructors" style={{ background: COLORS.ink }}>Constructors</option>
          </select>
          <Chevron /></div>}
    </React.Fragment>; // Loading state — live fetch in flight; snapshot renders beneath but we show a shimmer bar.
  if (data.status === 'loading') {return <React.Fragment>
        <URPageHeader title="The" italic="standings." league={league} />
        <URLeagueBand league={league} setLeague={setLeague} left={controls} />
        <section style={{ background: COLORS.base, padding: '48px 40px 140px', display: 'flex', justifyContent: 'center', alignItems: 'flex-start' }}>
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 20, paddingTop: 60 }}>
            <div style={{ display: 'flex', gap: 8 }}>
              {[0, 1, 2].map((i) => <span key={i} style={{ width: 10, height: 10, background: L.accent, borderRadius: '50%', animation: `ur-pulse 1.2s ease-in-out ${i * 0.2}s infinite` }} />)}
            </div>
            <span style={{ fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.28em', color: COLORS.textMute, textTransform: 'uppercase' }}>Loading live data…</span>
          </div>
        </section>
      </React.Fragment>;
  }

  // Error state — fetch failed, snapshot is shown with a stale indicator.
  const isStale = data.status === 'error';

  // Empty state — no snapshot and no live source for this season.
  if (data.status !== 'ready' && data.status !== 'error' || !data.drivers.length) {
    return (
      <React.Fragment>
        <URPageHeader title="The" italic="standings." league={league} />
        <URLeagueBand league={league} setLeague={setLeague} left={controls} />
        <section style={{ background: COLORS.base, padding: '80px 40px 140px', display: 'flex', justifyContent: 'center' }}>
          <div style={{ maxWidth: 560, textAlign: 'center', background: COLORS.surface, border: `1px solid ${COLORS.hairline}`, padding: '64px 48px' }}>
            <div style={{ fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.3em', color: L.accent, textTransform: 'uppercase' }}>◆ {L.short}</div>
            <h3 style={{ margin: '18px 0 0', fontFamily: 'Archivo', fontWeight: 900, fontSize: 40, color: COLORS.text, letterSpacing: '-0.02em' }}>Season data coming soon</h3>
            <p style={{ marginTop: 14, color: COLORS.textMute, fontSize: 15, lineHeight: 1.6 }}>This league's standings haven't been wired to its sheet yet. Switch to <strong style={{ color: COLORS.text }}>UL</strong> to see live data.</p>
          </div>
        </section>
      </React.Fragment>);
  }

  // Store returns pre-sorted, positioned data. teams is null when not team-based (AL).
  const teamByShort = Object.fromEntries((data.teams || []).map((t) => [t.short, t]));
  // Build driver roster per team — used to show nationality flags in the constructors table.
  const driversByTeam = {};
  (data.drivers || []).forEach((d) => {
    if (!driversByTeam[d.team]) driversByTeam[d.team] = [];
    driversByTeam[d.team].push(d);
  });
  const sortedTeams = data.teams;
  const sortedDrivers = data.drivers;
  const showTeamCol = !!sortedTeams; // hide the driver-table Team column for non-team leagues (AL)
  const clinchedChampion = getClinchedChampion(league, sortedDrivers, data.season);

  return (
    <React.Fragment>
      <URPageHeader
        title="The"
        italic="standings."
        league={league} />
      <URLeagueBand league={league} setLeague={setLeague} left={controls} />

      <section style={{ background: COLORS.base, padding: '20px 40px 110px' }}>
        {/* Podium spotlight — hidden in constructors-only view */}
        {view !== 'constructors' &&
        <div style={{ marginBottom: 40, display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 18, alignItems: 'end' }}>
          {[1, 0, 2].map((rank) => {
            const s = sortedDrivers[rank];
            if (!s) return null;
            const team = teamByShort[s.team] || { color: L.accent, name: s.team, short: s.team };
            const medal = ['#FFD24A', '#C9CDD4', '#CD7F32'][rank];
            // P1 tallest → P2 → P3, bottoms align via alignItems:end.
            // Heights are tall enough that the giant background position number clears
            // the name block — content is bottom-aligned (justifyContent:flex-end), so
            // a taller box pushes the name further down, away from the number.
            const podiumH = [360, 310, 280][rank];
            // Medal glow: stronger on P1, taper for P2/P3. Layered radial fades +
            // bottom wash give the card a gold/silver/bronze atmosphere; box-shadow
            // adds a soft outer halo in the same hue.
            const glowAlpha = ['38', '2e', '24'][rank]; // P1 / P2 / P3, hex alpha
            const haloAlpha = ['55', '40', '32'][rank];
            const cardBg = `radial-gradient(circle at 88% 12%, ${medal}${glowAlpha} 0%, transparent 48%), radial-gradient(circle at 50% 100%, ${medal}1c 0%, transparent 60%), ${COLORS.surface}`;
            return (
              <div key={s.name} style={{ minHeight: podiumH, display: 'flex', flexDirection: 'column', justifyContent: 'flex-end', background: cardBg, border: `1px solid ${medal}44`, borderBottom: `3px solid ${medal || team.color}`, padding: '28px 32px', position: 'relative', overflow: 'hidden', boxShadow: `0 18px 50px -22px ${medal}${haloAlpha}, 0 0 0 1px ${medal}18 inset` }}>
                <div aria-hidden style={{ position: 'absolute', right: -10, top: -50, fontFamily: 'Archivo', fontWeight: 900, fontSize: 220, color: medal || team.color, letterSpacing: '-0.06em', lineHeight: 0.8, pointerEvents: 'none' }}>{rank + 1}</div>
                <div style={{ position: 'relative' }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 14 }}>
                    <span style={{ width: 14, height: 14, background: showTeamCol ? team.color : medal || L.accent, flexShrink: 0 }} />
                    <span style={{ fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.26em', color: COLORS.textMute, textTransform: 'uppercase' }}>P{rank + 1} OVERALL{showTeamCol && s.team ? ` · ${team.short}` : ''}</span>
                  </div>
                  <h3 style={{ margin: 0, fontFamily: 'Archivo', fontWeight: 900, fontSize: 56, color: COLORS.text, letterSpacing: '-0.025em', lineHeight: 0.95, textTransform: 'uppercase' }}>{s.name}</h3>
                  <div style={{ marginTop: 18, display: 'flex', gap: 26, paddingTop: 16 }}>
                    <div><div style={{ fontFamily: 'JetBrains Mono', fontSize: 10, color: COLORS.textMute, letterSpacing: '0.22em', textTransform: 'uppercase' }}>Pts</div><div style={{ fontFamily: 'Archivo', fontWeight: 900, fontSize: 28, color: L.accent, marginTop: 4 }}>{s.pts}</div></div>
                    <div><div style={{ fontFamily: 'JetBrains Mono', fontSize: 10, color: COLORS.textMute, letterSpacing: '0.22em', textTransform: 'uppercase' }}>Wins</div><div style={{ fontFamily: 'Archivo', fontWeight: 900, fontSize: 28, color: COLORS.text, marginTop: 4 }}>{s.wins}</div></div>
                    <div><div style={{ fontFamily: 'JetBrains Mono', fontSize: 10, color: COLORS.textMute, letterSpacing: '0.22em', textTransform: 'uppercase' }}>Podiums</div><div style={{ fontFamily: 'Archivo', fontWeight: 900, fontSize: 28, color: COLORS.text, marginTop: 4 }}>{s.podiums}</div></div>
                  </div>
                </div>
              </div>);

          })}
        </div>}

        <div style={{ display: 'grid', gridTemplateColumns: view === 'both' && sortedTeams ? '1fr 1.4fr' : '1fr', gap: 28, alignItems: 'start' }}>

          {/* CONSTRUCTORS — hidden when league isn't team-based OR view is drivers-only */}
          {sortedTeams && view !== 'drivers' &&
          <div style={{ background: COLORS.surface, border: `1px solid ${COLORS.hairline}` }}>
            <div style={{ height: 92, boxSizing: 'border-box', padding: '0 24px', borderBottom: `1px solid ${COLORS.hairline}`, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
              <div>
                <div style={{ fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.28em', color: L.accent, textTransform: 'uppercase' }}>◆ Constructors</div>
                <div style={{ fontFamily: 'Archivo', fontWeight: 900, color: COLORS.text, marginTop: 6, letterSpacing: '-0.01em', fontSize: "40px" }}>Teams</div>
              </div>
              <span style={{ fontFamily: 'JetBrains Mono', fontSize: 10, color: COLORS.textDim, letterSpacing: '0.22em' }}>{L.short} · {data.season.label}{isStale ? ' · cached' : ''}</span>
            </div>
            <table style={tableStyle}>
              <thead>
                <tr>
                  <th style={{ ...thStyle, width: 50 }}>Pos</th>
                  <th style={thStyle}>Team</th>
                  <th style={{ ...thStyle, width: 90, textAlign: 'right' }}>Pts</th>
                </tr>
              </thead>
              <tbody>
                {sortedTeams.map((t, i) =>
                <tr key={t.short} style={{ height: den.rowH, background: `linear-gradient(90deg, ${t.color}3d 0%, ${t.color}14 32%, transparent 72%)` }}>
                    <td style={{ ...tdStyle, position: 'relative' }}>
                      <span style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: 3, background: t.color }} />
                      <span style={{ ...{ fontWeight: 900, color: MEDAL[i] || COLORS.textDim, letterSpacing: '-0.02em', lineHeight: 1, textShadow: MEDAL[i] ? `0 0 14px ${MEDAL[i]}55` : 'none', fontFamily: "Archivo", fontSize: "22px" }, color: "rgb(255, 255, 255)" }}>{i + 1}</span>
                    </td>
                    <td style={{ ...tdStyle, position: 'relative', overflow: 'hidden' }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 14, minWidth: 0 }}>
                        {UR_TEAM_LOGO[t.short] ?
                      <span style={{ width: 38, height: 38, borderRadius: 8, background: 'transparent', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 4 }}>
                          <img src={UR_TEAM_LOGO[t.short]} alt={t.short} style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain', display: 'block' }} />
                        </span> :
                      <span style={{ width: 24, height: 24, background: t.color, display: 'inline-block', flexShrink: 0 }} />}
                        <div style={{ minWidth: 0 }}>
                          <div style={{ fontFamily: 'Archivo', fontWeight: 800, fontSize: 20, color: COLORS.text, lineHeight: 1, letterSpacing: '-0.02em', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{t.name}</div>
                          <div style={{ display: 'flex', alignItems: 'center', gap: 7, marginTop: 4, flexWrap: 'wrap' }}>
                            <span style={{ fontFamily: 'JetBrains Mono', fontSize: 10, color: COLORS.textMute, letterSpacing: '0.2em' }}>{t.short}</span>
                            {(driversByTeam[t.short] || []).map((d) => {
                            const flag = getDriverFlag(d.name);
                            return flag ? <FlagSvg key={d.name} kind={flag} w={20} h={13} radius={2} /> : null;
                          })}
                          </div>
                        </div>
                      </div>
                    </td>
                    <td style={{ ...tdStyle, textAlign: 'right' }}>
                      <span style={{ fontFamily: 'Archivo', fontWeight: 900, fontSize: 22, color: COLORS.text, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.02em' }}>{t.pts}</span>
                    </td>
                  </tr>
                )}
              </tbody>
            </table>
          </div>
          }

          {/* DRIVERS — hidden when view is constructors-only */}
          {view !== 'constructors' &&
          <div style={{ background: COLORS.surface, border: `1px solid ${COLORS.hairline}` }}>
            <div style={{ height: 92, boxSizing: 'border-box', padding: '0 24px', borderBottom: `1px solid ${COLORS.hairline}`, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
              <div>
                <div style={{ fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.28em', color: L.accent, textTransform: 'uppercase' }}>◆ Drivers</div>
                <div style={{ fontFamily: 'Archivo', fontWeight: 900, color: COLORS.text, marginTop: 6, letterSpacing: '-0.01em', fontSize: "40px" }}>Pilots</div>
              </div>
              <span style={{ fontFamily: 'JetBrains Mono', fontSize: 10, color: COLORS.textDim, letterSpacing: '0.22em' }}>TOP {sortedDrivers.length}</span>
            </div>
            <table style={tableStyle}>
              <thead>
                <tr>
                  <th style={{ ...thStyle, width: 44 }}>Pos</th>
                  <th style={thStyle}>Driver</th>
                  {showTeamCol && <th style={thStyle}>Team</th>}
                  <th style={{ ...thStyle, width: 50, textAlign: 'center' }}>W</th>
                  <th style={{ ...thStyle, width: 60, textAlign: 'center' }}>Pod</th>
                  <th style={{ ...thStyle, width: 80, textAlign: 'right' }}>Pts</th>
                </tr>
              </thead>
              <tbody>
                {sortedDrivers.map((s, i) => {
                  const team = teamByShort[s.team] || { color: L.accent, short: s.team };
                  return (
                    <tr key={s.name} style={{ height: den.rowH, background: `linear-gradient(90deg, ${team.color}33 0%, ${team.color}10 28%, transparent 64%)` }}>
                      <td style={{ ...tdStyle, position: 'relative' }}>
                        {i < 3 && <span style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: 3, background: L.accent }} />}
                        <span style={{ ...{ fontFamily: 'Archivo', fontWeight: 800, color: i < 3 ? L.accent : COLORS.textDim, letterSpacing: '-0.01em', fontSize: "17px" }, color: "rgb(255, 255, 255)" }}>{i + 1}</span>
                      </td>
                      <td style={{ ...tdStyle }}>
                        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                          {getDriverFlag(s.name) && <FlagSvg kind={getDriverFlag(s.name)} w={26} h={17} radius={2} />}
                          <span style={{ fontFamily: 'Archivo', fontWeight: 700, color: COLORS.text, fontSize: '20px' }}>{s.name}</span>
                          {clinchedChampion === s.name && <LaurelIcon />}
                        </div>
                      </td>
                      {showTeamCol && <td style={{ ...tdStyle }}>
                        {(team.livery || getLivery(league, team.short)) ?
                        <img src={team.livery || getLivery(league, team.short)} alt={team.short} title={team.name || team.short} style={{ height: 26, width: 'auto', maxWidth: 76, objectFit: 'contain', display: 'block', filter: 'drop-shadow(0 1px 3px rgba(0,0,0,0.5))' }} /> :
                        <span style={{ fontFamily: 'Archivo', fontWeight: 600, fontSize: 13, color: team.color, letterSpacing: '0.04em' }}>{team.short}</span>}
                      </td>}
                      <td style={{ ...tdStyle, textAlign: 'center', fontFamily: 'JetBrains Mono', fontSize: 13, color: s.wins > 0 ? COLORS.text : COLORS.textDim, fontVariantNumeric: 'tabular-nums' }}>{s.wins}</td>
                      <td style={{ ...tdStyle, textAlign: 'center', fontFamily: 'JetBrains Mono', fontSize: 13, color: s.podiums > 0 ? COLORS.text : COLORS.textDim, fontVariantNumeric: 'tabular-nums' }}>{s.podiums}</td>
                      <td style={{ ...tdStyle, textAlign: 'right', fontFamily: 'Archivo', fontWeight: 800, fontSize: 17, color: COLORS.text, fontVariantNumeric: 'tabular-nums' }}>{s.pts}</td>
                    </tr>);

                })}
              </tbody>
            </table>
          </div>
          }
        </div>
      </section>
    </React.Fragment>);

};

// ─────────────────────────────────────────────────────────────────────────────
// RESULTS PAGE — Past races, podium grids
const PosChip = ({ p, color }) =>
<span style={{
  fontFamily: 'Archivo', fontWeight: 900, fontSize: 16,
  padding: '8px 14px',
  background: color || COLORS.red,
  color: '#fff',
  letterSpacing: '0.04em'
}}>{p}</span>;


// ─────────────────────────────────────────────────────────────────────────────
// TRACK HERO — featured next-race banner (stat columns + schedule + track map)
const UR_GP_LOC3 = {
  'Qatar Grand Prix': 'QAT', 'South African Grand Prix': 'RSA', 'Spanish Grand Prix': 'ESP',
  'Ukrainian Grand Prix': 'UKR', 'German Grand Prix': 'GER', 'Indonesian Grand Prix': 'INA',
  'Slovakian Grand Prix': 'SVK', 'British Grand Prix': 'GBR', 'Malaysian Grand Prix': 'MAS',
  'Welsh Grand Prix': 'WAL',
  'Japanese Grand Prix': 'JPN', 'Belgian Grand Prix': 'BEL',
  'Swedish Grand Prix': 'SWE', 'Dutch Grand Prix': 'NED', 'Italian Grand Prix': 'ITA',
  'Gold Coast Grand Prix': 'QLD', 'Sapporo International Grand Prix': 'SAP',
  'Canadian Grand Prix': 'CAN', 'Australian Grand Prix': 'AUS',
  'Arcana East Flanders Grand Prix': 'AEF', 'French Grand Prix': 'FRA',
  'Russian Grand Prix': 'RUS', 'United States Grand Prix': 'USA', 'Romanian Grand Prix': 'ROU',
  'Canarian Grand Prix': 'CNR', 'Monaco Grand Prix': 'MON'
};
const UR_GP_MINIMAP = {
  'Qatar Grand Prix': 'assets/minimaps/sm/qatar.png',
  'South African Grand Prix': 'assets/minimaps/sm/southafrica.png',
  'Spanish Grand Prix': 'assets/minimaps/sm/spain.png',
  'Ukrainian Grand Prix': 'assets/minimaps/sm/ukraine.png',
  'German Grand Prix': 'assets/minimaps/sm/germany.png',
  'Indonesian Grand Prix': 'assets/minimaps/sm/batavia.png',
  'Slovakian Grand Prix': 'assets/minimaps/sm/fatra.png',
  'British Grand Prix': 'assets/minimaps/sm/britain.png',
  'Malaysian Grand Prix': 'assets/minimaps/sm/malaysia.png',
  'Welsh Grand Prix': 'assets/minimaps/sm/wales.png',
  'Japanese Grand Prix': 'assets/minimaps/sm/suzuka.png',
  'Belgian Grand Prix': 'assets/minimaps/sm/spa.png',
  'Swedish Grand Prix': 'assets/minimaps/sm/jakobsberg.png',
  'Sapporo International Grand Prix': 'assets/minimaps/sm/sapporo.png',
  'Canadian Grand Prix': 'assets/minimaps/sm/winnipeg.png',
  'Dutch Grand Prix': 'assets/minimaps/sm/friesland.png',
  'Italian Grand Prix': 'assets/minimaps/sm/imola.png',
  'Gold Coast Grand Prix': 'assets/minimaps/sm/highlands.png',
  'Australian Grand Prix': 'assets/minimaps/sm/albertpark.png',
  'Arcana East Flanders Grand Prix': 'assets/minimaps/sm/allenbeek.png',
  'French Grand Prix': 'assets/minimaps/sm/lutetia.png',
  'Russian Grand Prix': 'assets/minimaps/sm/nring.png',
  'United States Grand Prix': 'assets/minimaps/sm/niagara.png',
  'Romanian Grand Prix': 'assets/minimaps/sm/prejmer.png',
  'Canarian Grand Prix': 'assets/minimaps/sm/canary.png',
  'Monaco Grand Prix': 'assets/minimaps/sm/monaco.png'
};
// Prefer the race's own `minimap` (store calendar) — GP names repeat across seasons
// (Spanish = Jarama S24 / Barcelona S26 …), so the GP map is only a fallback.
const urRaceMinimap = (r) => (r && (r.minimap || UR_GP_MINIMAP[r.grandPrix])) || null;
const UR_HERO_SIDE = (track) => (track.startsWith('Circuit of') ? track.split(' ').pop() : track.split(' ')[0]).toUpperCase();
const UR_HERO_MAPS = [
"M70 200 C 90 120, 200 110, 260 150 C 300 176, 320 230, 380 232 C 460 234, 470 150, 540 140 C 600 132, 640 180, 700 168 C 770 154, 800 90, 840 70 L 856 92 C 812 120, 800 196, 720 210 C 650 222, 610 180, 548 188 C 492 195, 480 270, 384 270 C 300 270, 286 214, 250 196 C 214 178, 132 196, 110 240 Z",
"M90 170 C 90 90, 210 80, 280 130 C 340 172, 320 250, 400 250 C 500 250, 480 120, 580 120 C 680 120, 680 200, 760 200 C 830 200, 845 120, 810 86 C 778 55, 700 72, 636 72 C 536 72, 540 44, 440 54 C 344 64, 360 144, 280 156 C 206 167, 190 200, 130 200 C 106 200, 96 188, 90 170 Z",
"M120 150 C 120 70, 250 66, 312 110 C 366 148, 392 88, 470 92 C 572 96, 560 205, 662 205 C 742 205, 766 150, 824 162 C 866 171, 852 232, 800 244 C 716 263, 636 254, 556 254 C 452 254, 456 182, 376 182 C 298 182, 300 254, 220 252 C 150 250, 120 222, 120 150 Z",
"M80 210 C 120 120, 230 120, 300 160 C 360 194, 380 250, 470 246 C 560 242, 560 150, 650 150 C 740 150, 740 230, 820 210 C 868 198, 860 120, 812 96 C 760 70, 690 110, 610 108 C 510 105, 520 188, 430 196 C 350 203, 330 150, 250 150 C 168 150, 120 170, 96 232 Z"];

const UR_HERO_SCHEDULE = (() => {
  const t = typeof UR2D_CALENDAR !== 'undefined' && UR2D_CALENDAR.times || { ul: '17:50', hl: '16:10', jl: '15:15', al: '14:30' };
  return [
  { session: 'Apprentice League', day: 'Sun', time: t.al },
  { session: 'Journeyman League', day: 'Sun', time: t.jl },
  { session: 'Challenger League', day: 'Sun', time: t.hl },
  { session: 'Ultimate League', day: 'Sun', time: t.ul }];

})();
function fmtHeroWhen(iso) {
  const [, m, d] = iso.split('-').map(Number);
  return `${d} ${['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'][m - 1]}`;
}
const heroNavBtn = { all: 'unset', cursor: 'pointer', width: 30, height: 30, display: 'flex', alignItems: 'center', justifyContent: 'center', border: `1px solid ${COLORS.hairline}`, background: 'rgba(0,0,0,0.35)', color: COLORS.textMute, fontFamily: 'Archivo', fontWeight: 700, fontSize: 16, lineHeight: 1, transition: 'color 0.15s ease, border-color 0.15s ease' };

// Pre-race hero fillers: ticking countdown + race-day session times
const URHeroCountdown = ({ toIso }) => {
  const [, setTick] = React.useState(0);
  React.useEffect(() => { const id = setInterval(() => setTick((t) => t + 1), 60000); return () => clearInterval(id); }, []);
  if (!toIso) return null;
  const c = getCountdown(toIso);
  return (
    <div>
      <div style={{ fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.28em', color: COLORS.red, textTransform: 'uppercase' }}>Lights out in</div>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 14, marginTop: 14 }}>
        <span style={{ fontFamily: 'Archivo', fontWeight: 900, fontSize: 76, lineHeight: 0.9, letterSpacing: '-0.035em', color: COLORS.text, fontVariantNumeric: 'tabular-nums' }}>{c.d}</span>
        <span style={{ fontFamily: 'JetBrains Mono', fontSize: 12, letterSpacing: '0.3em', textTransform: 'uppercase', color: COLORS.textDim }}>{c.d === 1 ? 'Day' : 'Days'}</span>
      </div>
    </div>
  );
};
const URHeroSessions = ({ large }) => {
  const times = (typeof UR2D_CALENDAR !== 'undefined' && UR2D_CALENDAR.times) || { al: '14:30', jl: '15:15', hl: '16:10', ul: '17:50' };
  const order = ['al', 'jl', 'hl', 'ul'];
  return (
    <div>
      <div style={{ fontFamily: 'JetBrains Mono', fontSize: large ? 12 : 11, letterSpacing: '0.28em', color: COLORS.textMute, textTransform: 'uppercase' }}>Race day · four grids</div>
      <div style={{ marginTop: 16, display: 'flex', flexDirection: 'column' }}>
        {order.map((id) => {
          const L = LEAGUE_BY_ID[id];
          const top = id === 'ul';
          return (
            <div key={id} style={{ display: 'flex', alignItems: 'center', gap: large ? 16 : 12, padding: large ? '16px 0' : '11px 0', borderTop: `1px solid ${COLORS.hairline}` }}>
              <span style={{ display: 'inline-flex', width: large ? 36 : 26, height: large ? 36 : 26, background: COLORS.ink, padding: large ? 5 : 3, flexShrink: 0 }}>
                <img src={L.logo} alt={L.short} style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }} />
              </span>
              <span style={{ fontFamily: 'Archivo', fontWeight: 800, fontSize: large ? 22 : 15, letterSpacing: '0.04em', textTransform: 'uppercase', color: top ? COLORS.red : COLORS.text, whiteSpace: 'nowrap' }}>{L.name}</span>
              <span style={{ flex: 1 }}></span>
              <span style={{ fontFamily: 'Archivo', fontWeight: 800, fontSize: large ? 24 : 16, color: top ? COLORS.red : COLORS.text, fontVariantNumeric: 'tabular-nums' }}>{times[id]}</span>
              <span style={{ fontFamily: 'JetBrains Mono', fontSize: large ? 11 : 9, letterSpacing: '0.18em', color: COLORS.textDim }}>UTC</span>
            </div>
          );
        })}
      </div>
    </div>
  );
};

// resultsView: 'grid' = two half-columns (original) · 'list' = one full-width row per driver, all shown ·
// 'scroll' = one row per driver, 10 visible, scroll/arrows for the rest (UR2D2 in-game feel, youa's feedback).
const UR_RES_VISIBLE = 10, UR_RES_ROW = 44; // row height incl. 4px gap
const URTrackHero = ({ version = 'default', league = 'ul', season, seasonIdx = 0, podiumColors = 'medal', initialRound = null, resultsView = 'scroll' }) => {
  const slides = getCalendar('ul', season).races;
  const initIdx = initialRound != null ? slides.findIndex((s) => s.round === initialRound) : -1;
  const startIdx = initIdx >= 0 ? initIdx : Math.max(0, slides.findIndex((s) => s.status === 'next'));
  const [idx, setIdx] = React.useState(startIdx);
  // When the calendar season changes, jump to that season's next race (or round 1 if all done).
  // Skip the mount run — it would override an explicit initialRound.
  const seasonMounted = React.useRef(false);
  React.useEffect(() => {
    if (!seasonMounted.current) { seasonMounted.current = true; return; }
    setIdx(Math.max(0, slides.findIndex((s) => s.status === 'next')));
  }, [season]);
  const r = slides[idx] || slides[0];
  const go = (dir) => setIdx((i) => (i + dir + slides.length) % slides.length);
  const sideName = UR_HERO_SIDE(r.track);
  const loc3 = UR_GP_LOC3[r.grandPrix] || '';
  const mapPath = UR_HERO_MAPS[r.round % UR_HERO_MAPS.length];
  const minimap = urRaceMinimap(r);
  const trackImg = r.trackImage; // full aerial render (only some rounds have one)
  const [anim, setAnim] = React.useState(true);
  const firstRender = React.useRef(true);
  React.useLayoutEffect(() => {
    if (firstRender.current) {firstRender.current = false;return;}
    setAnim(false);
    let raf2;
    const raf1 = requestAnimationFrame(() => {raf2 = requestAnimationFrame(() => setAnim(true));});
    const fallback = setTimeout(() => setAnim(true), 80);
    return () => {cancelAnimationFrame(raf1);if (raf2) cancelAnimationFrame(raf2);clearTimeout(fallback);};
  }, [idx]);
  const fadeStyle = { opacity: anim ? 1 : 0, transition: 'opacity 0.5s ease' };

  // ── Pre/Post race state ──────────────────────────────────────────────
  const isDone = r.status === 'done';
  const [activeLeague, setActiveLeague] = React.useState(league);
  const [lgOpen, setLgOpen] = React.useState(false); // league picker slide-out
  const lgLinger = React.useRef(null); // hover-out close delay so the picker lingers open
  // Resolve the league-specific season for results/standings by the calendar-season index
  // (index N of each league's seasons[] aligns with calendar season N). Falls back to current.
  const _lgSeasons = getSeasons(activeLeague);
  const curSeason = (_lgSeasons.filter((s) => !s.dbOnly)[seasonIdx] || _lgSeasons.find((s) => s.isCurrent) || {}).id || 'S24';
  const resultsMap = useRaceResults(activeLeague, curSeason);
  const results = isDone ? resultsMap[r.round] || null : null;

  // Team liveries (cars) from the store, keyed by driver → team → livery image.
  const standings = useStandings(activeLeague, curSeason);
  const roundTeamMap = useRoundTeamMap(activeLeague, curSeason);
  const roundDriverTeams = useRoundDriverTeams(activeLeague, curSeason); // name-keyed per-round map (authoritative)

  // Team-keyed lookups (for round-aware resolution by finish position)
  const liveryByTeam = React.useMemo(() => {
    const m = {};
    (standings.teams || []).forEach((t) => {if (t.livery) m[t.short] = t.livery;});
    return m;
  }, [standings]);
  const logoByTeam = React.useMemo(() => {
    const m = {};
    (standings.teams || []).forEach((t) => {if (t.minilogo) m[t.short] = t.minilogo;});
    return m;
  }, [standings]);

  // Round-aware helpers: look up which team held a finish position in a specific round,
  // then resolve livery/logo/teamShort for that team.
  // Falls back to driver-name lookup (standings) when roundTeamMap isn't loaded yet.
  const norm = (s) => String(s || '').toLowerCase().replace(/[^a-z0-9]/g, '');
  const carByDriver = React.useMemo(() => {
    const m = {};
    (standings.drivers || []).forEach((d) => {const lv = d.livery || liveryByTeam[d.team];if (lv) m[norm(d.name)] = lv;});
    return m;
  }, [standings, liveryByTeam]);
  const logoByDriver = React.useMemo(() => {
    const m = {};const t = {};
    (standings.drivers || []).forEach((d) => {const lg = logoByTeam[d.team];if (lg) m[norm(d.name)] = lg;t[norm(d.name)] = d.team;});
    return { map: m, teams: t };
  }, [standings, logoByTeam]);

  const teamForRound = (name, finish, round) => (roundDriverTeams[round] && roundDriverTeams[round][norm(name)]) || (roundTeamMap[round] && roundTeamMap[round][finish - 1]) || null;
  const carForRound = (name, finish, round) => {
    const sh = teamForRound(name, finish, round);
    return sh && liveryByTeam[sh] || carByDriver[norm(name)] || 'assets/al-car.png';
  };
  const logoForRound = (name, finish, round) => {
    const sh = teamForRound(name, finish, round);
    return sh && logoByTeam[sh] || logoByDriver.map[norm(name)] || (sh && typeof UR_TEAM_LOGO !== 'undefined' && UR_TEAM_LOGO[sh]) || null; // no minilogo → the main logo, drawn mini
  };
  const teamShortForRound = (name, finish, round) => teamForRound(name, finish, round) || logoByDriver.teams[norm(name)] || null;

  // Legacy name-only helpers (used outside ResultRow where round isn't available)
  const carFor = (name) => carByDriver[norm(name)] || 'assets/al-car.png';
  const logoFor = (name) => logoByDriver.map[norm(name)] || null;
  const teamFor = (name) => logoByDriver.teams[norm(name)] || null;

  // Tweak versions — A: same layout + metric cycler · B: minimap under stats, table on the right + cycler.
  const vA = version === 'a';
  const vB = version === 'b';
  const cyclable = vA || vB;
  const [metricIdx, setMetricIdx] = React.useState(null); // null → default metric (Feature, last in RESULT_METRICS)
  const rowEls = React.useRef({});
  const prevTops = React.useRef({});
  const resScroll = React.useRef(null);
  const [resTop, setResTop] = React.useState(0);
  React.useEffect(() => { if (resScroll.current) resScroll.current.scrollTop = 0; setResTop(0); }, [idx, activeLeague, resultsView]);
  const resStep = (dir) => { const el = resScroll.current; if (el) el.scrollBy({ top: dir * (resultsView === 'scroll' ? 62 : UR_RES_ROW) * 4, behavior: 'smooth' }); };

  const cycleMetric = () => {
    // Snapshot current row positions BEFORE the state update causes a re-render
    const snap = {};
    Object.entries(rowEls.current).forEach(([name, el]) => {
      if (el) snap[name] = el.getBoundingClientRect().top;
    });
    prevTops.current = snap;
    setMetricIdx((i) => ((i == null ? RESULT_METRICS.length - 1 : i) + 1) % RESULT_METRICS.length);
  };

  // After each metric change, play FLIP animations from saved → new positions
  React.useLayoutEffect(() => {
    const prev = prevTops.current;
    if (!Object.keys(prev).length) return;
    Object.entries(rowEls.current).forEach(([name, el]) => {
      if (!el || prev[name] == null) return;
      const delta = prev[name] - el.getBoundingClientRect().top;
      if (Math.abs(delta) > 0.5) {
        el.animate(
          [{ transform: `translateY(${delta}px)`, opacity: 0.5 }, { transform: 'none', opacity: 1 }],
          { duration: 380, easing: 'cubic-bezier(0.22, 1, 0.36, 1)', fill: 'none' }
        );
      }
    });
    prevTops.current = {};
  }, [metricIdx]);

  // RESULT_METRICS — driven by store (hasSprints), consistent across all rounds.
  // Each entry carries a sortBy key so sortedResults can sort correctly.
  const hasSprints = !!(standings.season && standings.season.hasSprints);
  const RESULT_METRICS = [
  { key: 'quali', label: 'Quali', sortBy: 'quali',
    render: (res) => res.quali != null ? String(res.quali) : '—' },
  ...(hasSprints ? [{ key: 'sprint', label: 'Sprint', sortBy: 'sprint',
    render: (res) => res.sprint != null ? String(res.sprint) : '—' }] : []),
  { key: 'gained', label: 'Feature', sortBy: 'finish',
    render: (res) => {if (res.quali == null) return '—';const g = res.quali - res.finish;return g > 0 ? '+' + g : g < 0 ? String(g) : '=';} }];
  const effMetricIdx = (metricIdx == null ? RESULT_METRICS.length - 1 : metricIdx) % RESULT_METRICS.length;


  // Sort results by the active metric's sortBy field — same logic for every round/league.
  const sortedResults = React.useMemo(() => {
    if (!results) return null;
    const arr = [...results];
    const sortBy = RESULT_METRICS[effMetricIdx].sortBy;
    if (sortBy === 'quali') {
      arr.sort((a, b) => (a.quali ?? 99) - (b.quali ?? 99));
    } else if (sortBy === 'sprint') {
      arr.sort((a, b) => (a.sprint ?? 99) - (b.sprint ?? 99));
    } else if (sortBy === 'gained') {
      arr.sort((a, b) => {
        const ga = a.quali != null ? a.quali - a.finish : -99;
        const gb = b.quali != null ? b.quali - b.finish : -99;
        return gb - ga;
      });
    } else {
      arr.sort((a, b) => (a.finish ?? 99) - (b.finish ?? 99)); // finish order (Feature, Sprint, default)
    }
    return arr;
  }, [results, effMetricIdx]);

  // ── ROUND PODIUM (left column) — three rows, drivers or constructors ──────
  const [podiumView, setPodiumView] = React.useState('drivers');
  const UR_PODIUM_METAL = [['#F7DE7E', '#B8912F'], ['#E9EBF1', '#8F949E'], ['#E3A96F', '#8A5326']];
  const podiumDrivers = React.useMemo(() => results ? [...results].sort((a, b) => (a.finish ?? 99) - (b.finish ?? 99)).slice(0, 3) : null, [results]);
  const podiumTeams = React.useMemo(() => {
    if (!results) return null;
    const m = {};
    [...results].sort((a, b) => (a.finish ?? 99) - (b.finish ?? 99)).forEach((res) => {
      const sh = teamShortForRound(res.name, res.finish, r.round);
      if (!sh) return;
      if (!m[sh]) m[sh] = { short: sh, pts: 0, drivers: [] };
      m[sh].pts += res.points || 0;
      m[sh].drivers.push(res.name);
    });
    return Object.values(m).sort((a, b) => b.pts - a.pts).slice(0, 3);
  }, [results, roundTeamMap, standings]);
  const teamColorFor = (sh) => ((standings.teams || []).find((t) => t.short === sh) || {}).color || COLORS.red;
  const podiumRowStops = (i, sh) => {
    if (podiumColors === 'team') {const c = teamColorFor(sh);return [c, c];}
    return UR_PODIUM_METAL[i];
  };
  const podiumNode = !isDone || !podiumDrivers ? null :
  <div style={{ ...fadeStyle, marginTop: 22 }}>
    <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, marginBottom: 12, marginLeft: vB ? 0 : -46, paddingLeft: 16 }}>
      {[['drivers', 'Podium'], ['teams', 'Constructors']].map(([v, label], i) => (
        <React.Fragment key={v}>
          {i > 0 && <span style={{ fontFamily: 'JetBrains Mono', fontSize: 10, color: COLORS.textDim }}>/</span>}
          <button onClick={() => setPodiumView(v)} style={{
            all: 'unset', cursor: 'pointer', fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.24em', textTransform: 'uppercase',
            fontWeight: podiumView === v ? 700 : 400, color: podiumView === v ? COLORS.text : COLORS.textDim, transition: 'color 0.15s ease'
          }}>{label}</button>
        </React.Fragment>
      ))}
    </div>
    <div style={{ display: 'flex', flexDirection: 'column', gap: 6, width: vB ? 460 : 'calc(100% + 46px)', marginLeft: vB ? 0 : -46 }}>
      {(podiumView === 'drivers' ? podiumDrivers : podiumTeams || []).map((row, i) => {
        const sh = podiumView === 'drivers' ? teamShortForRound(row.name, row.finish, r.round) : row.short;
        const [c1, c2] = podiumRowStops(i, sh);
        const logo = podiumView === 'drivers' ? logoForRound(row.name, row.finish, r.round) : logoByTeam[sh];
        const isOne = sh === 'ONE';
        return (
          <div key={podiumView + i} style={{ position: 'relative', display: 'grid', gridTemplateColumns: podiumView === 'drivers' ? '40px 26px minmax(0,1fr) 70px' : '40px 26px minmax(0,1fr) auto', gap: 12, alignItems: 'center', padding: '11px 14px 11px 16px', background: `linear-gradient(90deg, ${c1}30 0%, ${c2}12 52%, transparent 100%)`, animation: 'ur-metric-in 0.2s ease both' }}>
            <span style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: 4, background: `linear-gradient(180deg, ${c1}, ${c2})` }} />
            <span style={{ fontFamily: 'Archivo', fontWeight: 900, fontSize: 25, letterSpacing: '-0.03em', background: `linear-gradient(180deg, ${c1}, ${c2})`, WebkitBackgroundClip: 'text', backgroundClip: 'text', color: 'transparent' }}>P{i + 1}</span>
            {logo ?
            <img src={logo} alt="" style={{ width: 26, height: 26, objectFit: 'contain', display: 'block', filter: isOne ? 'brightness(0) invert(1)' : 'none' }} /> :
            <div style={{ width: 26, height: 26, background: COLORS.hairline }} />}
            {podiumView === 'drivers' ?
            <React.Fragment>
              <span style={{ fontFamily: 'Archivo', fontWeight: 800, fontSize: 18, color: COLORS.text, textTransform: 'uppercase', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{row.name}</span>
              <img src={carForRound(row.name, row.finish, r.round)} alt="" style={{ width: 68, height: 'auto', display: 'block', justifySelf: 'end' }} />
            </React.Fragment> :
            <React.Fragment>
              <span style={{ fontFamily: 'Archivo', fontWeight: 800, fontSize: 15, color: COLORS.text, textTransform: 'uppercase', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{row.drivers.join(' / ')}</span>
              <span style={{ fontFamily: 'JetBrains Mono', fontSize: 13, color: COLORS.textMute, fontVariantNumeric: 'tabular-nums', letterSpacing: '0.04em', whiteSpace: 'nowrap' }}>{row.pts} pts</span>
            </React.Fragment>}
          </div>);
      })}
    </div>
  </div>;

  // Minimap node, reused in both states (right column post / centre pre).
  const minimapNode = minimap ?
  <img src={minimap} alt={r.track + ' circuit map'} style={{ height: 'auto', maxHeight: '100%', maxWidth: '100%', objectFit: 'contain', opacity: anim ? 0.96 : 0, transition: 'opacity 0.6s ease', width: "3000px" }} /> :
  <svg viewBox="0 0 900 300" width="100%" height="100%" style={{ maxWidth: 1000, overflow: 'visible', opacity: anim ? 0.95 : 0, transition: 'opacity 0.6s ease' }}>
      <defs><filter id="trk-glow" x="-20%" y="-20%" width="140%" height="140%"><feGaussianBlur stdDeviation="6" result="b" /><feMerge><feMergeNode in="b" /><feMergeNode in="SourceGraphic" /></feMerge></filter></defs>
      <path d={mapPath} fill="none" stroke={COLORS.red} strokeWidth="5" strokeLinejoin="round" strokeLinecap="round" filter="url(#trk-glow)" opacity="0.95" style={{ stroke: 'rgb(255, 4, 0)' }} />
    </svg>;

  // Post-race results table — transparent, two columns, lets the backdrop show through.
  const resultMedal = (p) => p === 1 ? '#F4CB45' : p === 2 ? '#C9C9D0' : p === 3 ? '#C57F45' : COLORS.text;
  const metric = RESULT_METRICS[effMetricIdx];
  const metricColor = (res) => {
    if (metric.key === 'gained' && res.quali != null) {
      const g = res.quali - res.finish;
      return g > 0 ? '#46C178' : g < 0 ? COLORS.red : COLORS.textMute;
    }
    return COLORS.textMute;
  };
  const wideRes = resultsView !== 'grid';
  const bigRes = resultsView === 'scroll'; // scroll = upsized rows (in-game feel), 9 visible
  const RES_ROW = bigRes ? 62 : UR_RES_ROW, RES_VIS = bigRes ? 9 : UR_RES_VISIBLE;
  const WIDE_COLS = bigRes ? '30px 44px minmax(110px,1.1fr) minmax(48px,68px) minmax(56px,80px) minmax(52px,76px) minmax(88px,140px) minmax(76px,116px) minmax(72px,100px)' : '22px 30px minmax(90px,1.4fr) minmax(36px,52px) minmax(40px,56px) minmax(40px,60px) minmax(64px,104px) minmax(56px,88px) minmax(52px,72px)';
  const RES_GAP = bigRes ? 'clamp(8px, 1.2vw, 18px)' : 'clamp(6px, 0.9vw, 12px)';
  const ResultRow = ({ res, round, rowRef }) =>
  {
    const isQualiMode = metric.sortBy === 'quali';
    const isSprintMode = metric.sortBy === 'sprint';
    const displayPos = isQualiMode ? res.quali ?? res.finish : isSprintMode ? res.sprint ?? res.finish : res.finish;
    const posColor = isQualiMode ? COLORS.textMute : resultMedal(isSprintMode ? res.sprint : res.finish);
    const hideMetric = isQualiMode || isSprintMode;
    const resolvedTeam = teamShortForRound(res.name, res.finish, round);
    const resolvedLogo = logoForRound(res.name, res.finish, round);
    const resolvedCar = carForRound(res.name, res.finish, round);
    const isOne = resolvedTeam === 'ONE';
    if (wideRes) {
      const g = res.quali != null && res.finish != null ? res.quali - res.finish : null;
      const mono = { fontFamily: 'JetBrains Mono', fontSize: bigRes ? 15 : 12, color: COLORS.textMute, fontVariantNumeric: 'tabular-nums', letterSpacing: '0.04em', textAlign: 'right' };
      return <div ref={rowRef} style={{ display: 'grid', gridTemplateColumns: WIDE_COLS, gap: RES_GAP, alignItems: 'center', height: RES_ROW - (bigRes ? 6 : 4), boxSizing: 'border-box', padding: bigRes ? '0 20px' : '0 14px', marginBottom: bigRes ? 6 : 4, background: 'rgba(255,255,255,0.04)', borderRadius: bigRes ? 10 : 8, scrollSnapAlign: 'start' }}>
        {resolvedLogo ?
        <img src={resolvedLogo} alt="" style={{ width: bigRes ? 30 : 22, height: bigRes ? 30 : 22, objectFit: 'contain', display: 'block', filter: isOne ? 'brightness(0) invert(1)' : 'none' }} /> :
        <div style={{ width: bigRes ? 30 : 22, height: bigRes ? 30 : 22, background: COLORS.hairline, borderRadius: 3 }} />}
        <span style={{ fontFamily: 'Archivo', fontWeight: 900, fontSize: bigRes ? 26 : 18, color: posColor, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.02em' }}>{String(displayPos).padStart(2, '0')}</span>
        <span style={{ fontFamily: 'Archivo', fontWeight: 800, fontSize: bigRes ? 21 : 16, color: COLORS.text, textTransform: 'uppercase', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{res.name}</span>
        <img src={resolvedCar} alt="" style={{ width: '100%', maxWidth: bigRes ? 62 : 44, height: 'auto', display: 'block', justifySelf: 'center' }} />
        <span style={mono}>{res.quali != null ? 'P' + res.quali : '—'}</span>
        <span style={{ ...mono, color: g == null ? COLORS.textMute : g > 0 ? '#46C178' : g < 0 ? COLORS.red : COLORS.textMute }}>{g == null ? '—' : g > 0 ? '+' + g : g < 0 ? String(g) : '='}</span>
        <span style={{ ...mono, color: COLORS.text }}>{res.time || '—'}</span>
        <span style={mono}>{res.gap || (res.time && res.finish === 1 ? 'Leader' : '—')}</span>
        <span style={mono}>{res.points != null ? '+' + res.points + ' pts' : '—'}</span>
      </div>;
    }
    return <div ref={rowRef} style={{ display: 'grid', gridTemplateColumns: '22px 32px 168px 64px 1fr auto 72px', gap: 10, alignItems: 'center', padding: '7px 12px', marginBottom: 4, background: 'rgba(255,255,255,0.04)', borderRadius: 8 }}>{/* same chrome as the Standings trophy cabinet / season-stats panels (user 2026-10-09) */}
      {/* team minilogo — round-aware: correct team even for ER/transfers */}
      {resolvedLogo ?
      <img src={resolvedLogo} alt="" style={{ width: 22, height: 22, objectFit: 'contain', flexShrink: 0, display: 'block', filter: isOne ? 'brightness(0) invert(1)' : 'none' }} /> :
      <div style={{ width: 22, height: 22, background: COLORS.hairline, borderRadius: 3, flexShrink: 0 }} />}
      <span style={{ fontFamily: 'Archivo', fontWeight: 900, fontSize: 18, color: posColor, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.02em' }}>{String(displayPos).padStart(2, '0')}</span>
      <span style={{ fontFamily: 'Archivo', fontWeight: 800, fontSize: 16, color: COLORS.text, textTransform: 'uppercase', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{res.name}</span>
      {/* car — round-aware livery: ER drivers show the team they actually raced for */}
      <img src={resolvedCar} alt="" style={{ width: 44, height: 'auto', flexShrink: 0, display: 'block', justifySelf: 'center' }} />
      <span></span>
      {!hideMetric && <span key={metric.key} style={{ fontFamily: 'JetBrains Mono', fontSize: 11, color: metricColor(res), letterSpacing: '0.1em', fontVariantNumeric: 'tabular-nums', animation: 'ur-metric-in 0.18s ease both' }}>{metric.render(res)}</span>}
      {hideMetric && <span></span>}
      {/* points gained from this race */}
      <span style={{ fontFamily: 'JetBrains Mono', fontSize: 11, color: COLORS.textMute, fontVariantNumeric: 'tabular-nums', textAlign: 'right', letterSpacing: '0.05em' }}>{res.points != null ? '+' + res.points + ' pts' : '—'}</span>
    </div>;
  };
  const ResultsHeader = () =>
  <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 14, flexWrap: 'wrap' }}>
      <span style={{ fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.26em', color: COLORS.red, textTransform: 'uppercase' }}>Race Result</span>
      {cyclable ?
    <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap', marginLeft: 'auto', justifyContent: 'flex-end' }}>
        {/* League pill (team-page .tp-swl style) — always open, fixed order, active = full opacity + soft fill, no hover effects */}
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 2, height: 34, padding: '0 4px', borderRadius: 999, border: '1px solid rgba(243,241,236,0.16)', background: 'rgba(7,7,7,0.45)', WebkitBackdropFilter: 'blur(8px)', backdropFilter: 'blur(8px)' }}>
          {LEAGUES.map((L) => {
            const on = L.id === activeLeague;
            return <button key={L.id} title={L.name} aria-pressed={on}
              onClick={() => { if (!on) { setActiveLeague(L.id); setMetricIdx(null); } }}
              style={{ all: 'unset', cursor: on ? 'default' : 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', height: 26, padding: '0 9px', borderRadius: 999, opacity: on ? 1 : 0.4, background: on ? 'rgba(243,241,236,0.1)' : 'transparent', transition: 'opacity 0.2s ease, background 0.2s ease' }}>
              <img src={L.logo} alt={L.short} style={{ height: 15, width: 'auto', display: 'block' }} />
            </button>;
          })}
        </span>
        {/* Metric chips (team-page season-chip style): one pill, active chip filled with the league accent */}
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 2, height: 34, padding: '0 4px', borderRadius: 999, border: '1px solid rgba(243,241,236,0.16)', background: 'rgba(7,7,7,0.45)', WebkitBackdropFilter: 'blur(8px)', backdropFilter: 'blur(8px)' }}>
          {RESULT_METRICS.map((m, i) => {
          const active = i === effMetricIdx;
          return <button key={m.key} onClick={() => {const snap = {};Object.entries(rowEls.current).forEach(([n, el]) => {if (el) snap[n] = el.getBoundingClientRect().top;});prevTops.current = snap;setMetricIdx(i);}}
            onMouseEnter={(e) => { if (!active) { e.currentTarget.style.color = COLORS.text; e.currentTarget.style.background = 'rgba(243,241,236,0.06)'; } }}
            onMouseLeave={(e) => { if (!active) { e.currentTarget.style.color = COLORS.textDim; e.currentTarget.style.background = 'transparent'; } }}
            style={{ all: 'unset', cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', height: 26, padding: '0 11px', borderRadius: 999, fontFamily: 'JetBrains Mono', fontSize: 12, letterSpacing: '0.06em', textTransform: 'uppercase', background: active ? (LEAGUE_BY_ID[activeLeague] || {}).accent || COLORS.red : 'transparent', color: active ? '#fff' : COLORS.textDim, transition: 'background 0.15s ease, color 0.15s ease' }}>
              {m.label}
            </button>;
        })}
        </span>
      </div> :
    <span style={{ fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.2em', color: COLORS.textDim, textTransform: 'uppercase' }}>Pos · Driver · Quali</span>
    }
    </div>;
  const buildResultsTable = (columns) => {
    if (!sortedResults) return <div style={{ marginTop: 20, fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.24em', color: COLORS.textMute, textTransform: 'uppercase' }}>Loading results…</div>;
    if (wideRes) {
      const scroll = resultsView === 'scroll' && sortedResults.length > RES_VIS;
      const n = sortedResults.length;
      const first = Math.min(n, Math.round(resTop / RES_ROW) + 1), last = Math.min(n, first + RES_VIS - 1);
      const atTop = first <= 1, atEnd = last >= n;
      const hd = { fontFamily: 'JetBrains Mono', fontSize: bigRes ? 12 : 10, letterSpacing: '0.12em', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'clip', color: COLORS.textDim, textTransform: 'uppercase', textAlign: 'right' };
      const arrowBtn = (dir, off) => <button onClick={() => resStep(dir)} disabled={off} aria-label={dir < 0 ? 'Scroll up' : 'Scroll down'} style={{ all: 'unset', cursor: off ? 'default' : 'pointer', width: 40, height: 40, borderRadius: 999, border: '1px solid rgba(243,241,236,0.16)', background: 'rgba(7,7,7,0.45)', display: 'grid', placeItems: 'center', color: COLORS.text, opacity: off ? 0.3 : 1, transition: 'opacity 0.2s ease' }}><svg width="12" height="12" viewBox="0 0 12 12" style={{ transform: dir < 0 ? 'rotate(180deg)' : 'none' }}><path d="M2 4l4 4 4-4" fill="none" stroke="currentColor" strokeWidth="1.8" /></svg></button>;
      return (
        <div style={{ marginTop: 16 }}>
          <ResultsHeader />
          <div style={{ display: 'grid', gridTemplateColumns: scroll ? 'minmax(0,1fr) 40px' : 'minmax(0,1fr)', gap: 14 }}>
            <div style={{ minWidth: 0 }}>
              <div style={{ display: 'grid', gridTemplateColumns: WIDE_COLS, gap: RES_GAP, padding: bigRes ? '0 20px 10px' : '0 14px 8px' }}>
                <span></span><span style={{ ...hd, textAlign: 'left' }}>Pos</span><span style={{ ...hd, textAlign: 'left' }}>Driver</span><span></span>
                <span style={hd}>Quali</span><span style={hd}>+/−</span><span style={hd}>Race time</span><span style={hd}>Gap</span><span style={hd}>Pts</span>
              </div>
              <div key={activeLeague} ref={resScroll} className="ur-res-scroll" onScroll={(e) => setResTop(Math.round(e.currentTarget.scrollTop / RES_ROW) * RES_ROW)}
                style={{ ...(scroll ? { height: RES_ROW * RES_VIS, overflowY: 'auto', scrollSnapType: 'y mandatory', overscrollBehavior: 'contain', scrollbarWidth: 'none', WebkitMaskImage: `linear-gradient(to bottom, ${atTop ? '#000' : 'transparent'} 0, #000 ${atTop ? 0 : 28}px, #000 calc(100% - ${atEnd ? 0 : 28}px), ${atEnd ? '#000' : 'transparent'} 100%)`, maskImage: `linear-gradient(to bottom, ${atTop ? '#000' : 'transparent'} 0, #000 ${atTop ? 0 : 28}px, #000 calc(100% - ${atEnd ? 0 : 28}px), ${atEnd ? '#000' : 'transparent'} 100%)` } : null), animation: 'ur-league-glide 0.42s cubic-bezier(0.22,1,0.36,1) both' }}>
                {sortedResults.map((res) => <ResultRow key={res.name} res={res} round={r.round} rowRef={(el) => {rowEls.current[res.name] = el;}} />)}
              </div>
            </div>
            {scroll &&
            <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 12, paddingTop: 26 }}>
                {arrowBtn(-1, atTop)}
                <span style={{ writingMode: 'vertical-rl', fontFamily: 'JetBrains Mono', fontSize: 12, letterSpacing: '0.2em', color: COLORS.textMute, fontVariantNumeric: 'tabular-nums' }}>{first}–{last} / {n}</span>
                {arrowBtn(1, atEnd)}
              </div>}
          </div>
          <style>{`.ur-res-scroll::-webkit-scrollbar{display:none}`}</style>
        </div>);
    }
    const half = Math.ceil(sortedResults.length / 2);
    const colsR = columns === 2 ? [sortedResults.slice(0, half), sortedResults.slice(half)] : [sortedResults];
    return (
      <div style={{ marginTop: 16 }}>
        <ResultsHeader />
        <div key={activeLeague} style={{ display: 'grid', gridTemplateColumns: columns === 2 ? '1fr 1fr' : '1fr', gap: '0 56px', animation: 'ur-league-glide 0.42s cubic-bezier(0.22,1,0.36,1) both' }}>
          {colsR.map((cc, ci) => <div key={ci}>{cc.map((res) => <ResultRow key={res.name} res={res} round={r.round} rowRef={(el) => {rowEls.current[res.name] = el;}} />)}</div>)}
        </div>
      </div>);
  };
  return (
    <section style={{ position: 'relative', background: '#000', overflow: 'hidden', ...(vB || (isDone && resultsView !== 'grid') ? { minHeight: 'calc(100vh - 72px)' } : { height: 'calc(100vh - 72px)' }), borderBottom: `1px solid ${COLORS.hairline}` }}>
      {/* Faint full-bleed track render (only for rounds with a trackImage) */}
      {trackImg &&
      <div aria-hidden style={{ position: 'absolute', inset: 0, backgroundImage: `url(${trackImg})`, backgroundSize: 'cover', backgroundPosition: 'center', opacity: anim ? isDone ? 0.2 : 0.08 : 0, transition: 'opacity 0.7s ease', pointerEvents: 'none' }} />}
      {/* BG glow removed (user 2026-10-09) */}

      {/* LEFT EDGE: vertical track name + flag */}
      <div style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: 132, borderRight: `1px solid ${COLORS.hairline}`, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'space-between', padding: '28px 0', zIndex: 3, height: "756px" }}>
        <div style={{ opacity: anim ? 1 : 0, transition: 'opacity 0.5s ease', transform: 'rotate(-90deg)', transformOrigin: 'center' }}><FlagSvg kind={UR_GP_FLAG[r.grandPrix] || 'pacific'} w={44} h={30} radius={3} /></div>
        <div style={{ flex: 1, minHeight: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{/* name centred between flag and rail bottom (user 2026-10-09) */}
        <div style={{ writingMode: 'vertical-rl', transform: 'rotate(180deg)', fontFamily: 'Archivo', fontWeight: 900, fontSize: `min(108px, calc((100vh - 300px) / ${(Math.max(sideName.length, 1) * 0.74).toFixed(2)}))`, whiteSpace: 'nowrap', lineHeight: 0.82, color: COLORS.text, letterSpacing: '-0.04em', textTransform: 'uppercase', opacity: anim ? 1 : 0, transition: 'opacity 0.55s ease' }}>{/* scales to fit the rail height (flag + round label reserved) — long names shrink (user 2026-10-09) */}
          {sideName}
        </div>
        </div>
      </div>

      {/* MAIN CONTENT */}
      <div style={{ position: 'relative', marginLeft: 132, padding: '40px 40px 48px', zIndex: 2, color: "rgb(255, 255, 255)", ...(!isDone ? { boxSizing: 'border-box', minHeight: '100%', display: 'flex', flexDirection: 'column', paddingTop: 112 } : !vB ? { boxSizing: 'border-box', height: '100%', display: 'flex', flexDirection: 'column', justifyContent: 'space-evenly', paddingTop: 24, paddingBottom: 24 } : null) }}>{/* post-race: stats + results spread evenly over the full hero height (user 2026-10-09) */}
        {/* Top stat row */}
        <div style={{ ...fadeStyle, display: 'grid', gridTemplateColumns: isDone && vB ? '1fr 1.18fr' : '1.4fr 1fr 1fr', gap: 40, alignItems: 'start' }}>
          {/* LEFT: WHEN + secondary stats (+ minimap below — version B) */}
          <div>
            <div style={{ fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.28em', color: COLORS.textMute, textTransform: 'uppercase' }}>When</div>
            <div style={{ fontFamily: 'Archivo', fontWeight: 900, fontSize: 76, color: COLORS.text, letterSpacing: '-0.035em', lineHeight: 0.92, marginTop: 6 }}>Round {r.round}</div>
            <div style={{ marginTop: 28, display: 'grid', gridTemplateColumns: 'repeat(2, max-content)', columnGap: 64, rowGap: 22 }}>
              {[['Date', r.date ? new Date(r.date + 'T12:00:00Z').toLocaleDateString('en-GB', { day: 'numeric', month: 'short', timeZone: 'UTC' }).toUpperCase() : 'TBA'], ['Laps', r.laps != null ? String(r.laps) : '—'], ['Grand Prix', UR_CAL_LOC(r.grandPrix)], ['Designer', r.creator || '—']].map(([k, v]) =>
              <div key={k}>
                  <div style={{ fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.24em', color: COLORS.textMute, textTransform: 'uppercase' }}>{k}</div>
                  <div style={{ fontFamily: 'Archivo', fontWeight: 900, fontSize: 34, color: COLORS.text, letterSpacing: '-0.02em', marginTop: 6, fontVariantNumeric: 'tabular-nums' }}>{v}</div>
                </div>
              )}
            </div>
            {vB && podiumNode}
            {isDone && vB &&
            <div style={{ marginTop: 36, height: 300, display: 'flex', alignItems: 'center', justifyContent: 'flex-start' }}>{minimapNode}</div>}
          </div>

          {isDone && vB ?
          /* RIGHT (version B): results table fills the right column */
          <div style={{ marginTop: -34 }}>{buildResultsTable(1)}</div> :
          <React.Fragment>
            {/* middle column: round podium once done · countdown pre-race */}
            <div>{isDone ? podiumNode : <div style={fadeStyle}><URHeroCountdown toIso={r.date ? `${r.date}T${(r.utcHHMM || (typeof UR2D_CALENDAR !== 'undefined' && UR2D_CALENDAR.times.ul) || '17:50').padStart(5, '0')}:00Z` : null} /></div>}</div>

            {/* RIGHT: minimap — post-race full height, pre-race smaller in the top-right third */}
            <div>{/* pre-race: whole content block clears the fixed round-nav bar via MAIN CONTENT paddingTop (user 2026-10-09) */}
              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: isDone ? 240 : 0, height: isDone ? '100%' : 220, pointerEvents: 'none' }}>{minimapNode}</div>
            </div>
          </React.Fragment>
          }
        </div>

        {/* BOTTOM: pre = track map · post (default/A) = results · post (B) = already on the right */}
        {isDone ?
        vB ? null :
        <div style={{ ...fadeStyle, position: 'relative' }}>{buildResultsTable(2)}</div> :
        <div style={{ ...fadeStyle, position: 'relative', marginTop: 26, flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{/* centred in the space between the stats ("Grand Prix") and the hero bottom (user 2026-10-09) */}
          <div style={{ width: '100%', maxWidth: 760 }}><URHeroSessions large={true} /></div>
        </div>
        }
      </div>

      {/* "Rest of the calendar" tab removed (user 2026-10-09); keyframes still used by the results metric / league glide */}
      <style>{`@keyframes ur-cal-bounce { 0%,100% { transform: translateY(0); } 50% { transform: translateY(3px); } } @keyframes ur-metric-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } } @keyframes ur-league-glide { from { opacity: 0; transform: translateX(22px); } to { opacity: 1; transform: none; } }`}</style>

      {/* TRACK SWITCHER — bottom right */}
      <URHeroNavSlot>
        <div style={{ fontFamily: 'JetBrains Mono', fontSize: 9, letterSpacing: '0.16em', color: COLORS.textDim, textTransform: 'uppercase', whiteSpace: 'nowrap' }}>
          <span style={{ color: COLORS.textMute, fontWeight: 700 }}>{String(idx + 1).padStart(2, '0')}</span> / {String(slides.length).padStart(2, '0')} · {sideName}
        </div>
        <div style={{ display: 'flex', gap: 6 }}>
          <button onClick={() => go(-1)} aria-label="Previous track" style={heroNavBtn}>‹</button>
          <button onClick={() => go(1)} aria-label="Next track" style={{ ...heroNavBtn, border: "1px solid rgb(0, 0, 0)" }}>›</button>
        </div>
      </URHeroNavSlot>
    </section>);

};

// Track-hero round nav ("01 / 10 · LUTETIA ‹ ›"): ONE line, portalled into the calendar gate's fixed top-right bar
// (#fdcal-tr-slot, next to "Full cal") when that bar exists; otherwise bottom-right of the hero as before (user 2026-10-09).
const URHeroNavSlot = ({ children }) => {
  const [slot, setSlot] = React.useState(null);
  React.useLayoutEffect(() => { setSlot(document.getElementById('fdcal-tr-slot')); }, []);
  const row = <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>{children}</div>;
  return slot ? ReactDOM.createPortal(row, slot) : <div style={{ position: 'absolute', right: 20, bottom: 20, zIndex: 4 }}>{row}</div>;
};

// Lando/F1-style calendar table — huge condensed rows, thin borders, red hover.
const UR_CAL_LOC = (gp) => (gp || 'TBA').replace(/ Grand Prix$/i, ' GP');
const UR_STATUS_LABEL = { done: 'Done', next: 'Next', upcoming: 'Soon' };
function fmtLandoDate(iso) {
  if (!iso) return 'TBA';
  const [y, m, d] = iso.split('-').map(Number);
  const mon = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'][m - 1];
  return `${d} ${mon} ${String(y).slice(2)}`;
}

const URLandoCalendar = ({ season, posterRows = false }) => {
  const races = getCalendar('ul', season).races;
  const [hover, setHover] = React.useState(-1);
  const cols = 'clamp(78px,7vw,140px) minmax(0,1fr) 48px clamp(80px,8vw,120px) clamp(110px,11vw,200px)';
  const headStyle = (right) => ({ fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.24em', color: COLORS.textMute, textTransform: 'uppercase', textAlign: right ? 'right' : 'left' });
  return (
    <div>
      <div style={{ display: 'grid', gridTemplateColumns: cols, gap: 22, padding: '0 40px 16px 22px', borderBottom: `2px solid ${COLORS.hairline}` }}>
        <span style={headStyle(false)}>Round</span>
        <span style={headStyle(false)}>Location</span>
        <span style={headStyle(false)}></span>
        <span style={headStyle(false)}>Laps</span>
        <span style={headStyle(true)}>When</span>
      </div>
      {races.map((r, i) => {
        const done = r.status === 'done';
        const isNext = r.status === 'next';
        const hot = hover === i;
        const pr = posterRows;
        const txt = hot && !pr ? '#000' : COLORS.text;
        const sub = hot && !pr ? '#000' : COLORS.textMute;
        const iso = pr && window.POSTER_GP_ISO ? window.POSTER_GP_ISO[r.grandPrix] : null;
        const bgK = done ? 0.5 : 0.85;
        const up = hot ? 1.3 : 1; // hover brighten via opacity (no CSS filter)
        return (
          <div
            key={r.round}
            onMouseEnter={() => setHover(i)}
            onMouseLeave={() => setHover(-1)}
            onClick={() => r.trackUrl && window.open(r.trackUrl, '_blank', 'noopener')}
            style={{
              display: 'grid', gridTemplateColumns: cols, gap: 22, alignItems: 'center',
              padding: pr ? '24px 40px 24px 22px' : '18px 40px 18px 22px', borderBottom: `1px solid ${COLORS.hairline}`,
              background: hot && !pr ? COLORS.red : 'transparent',
              boxShadow: pr ? (hot || isNext ? `inset 4px 0 0 ${COLORS.red}` : 'none') : (isNext && !hot ? `inset 4px 0 0 ${COLORS.red}` : 'none'),
              position: 'relative', overflow: 'hidden', textShadow: pr ? '0 2px 12px rgba(0,0,0,0.8)' : 'none',
              transition: 'background 0.12s ease', cursor: r.trackUrl ? 'pointer' : 'default'
            }}>
            {pr && iso ?
            <div aria-hidden style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: '62%', zIndex: 0, pointerEvents: 'none', WebkitMaskImage: 'linear-gradient(to right, #000 40%, transparent 100%)', maskImage: 'linear-gradient(to right, #000 40%, transparent 100%)' }}>
                <img src={urFlagImg(iso, 640)} alt="" loading="lazy" decoding="async" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block', opacity: Math.min(1, 0.76 * bgK * up), transition: 'opacity .25s ease' }} />
                <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(to right, rgba(10,10,12,0.3) 0%, rgba(10,10,12,0.55) 100%)' }} />
              </div> : null}
            {pr && r.trackImage ?
            <div aria-hidden style={{ position: 'absolute', right: 0, top: 0, bottom: 0, width: '60%', zIndex: 0, pointerEvents: 'none', WebkitMaskImage: 'linear-gradient(to left, #000 50%, transparent 100%)', maskImage: 'linear-gradient(to left, #000 50%, transparent 100%)' }}>
                <img src={r.trackImage} alt="" loading="lazy" decoding="async" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block', opacity: Math.min(1, 0.45 * bgK * up), transition: 'opacity .25s ease' }} />
                <div style={{ position: 'absolute', inset: 0, background: 'rgba(10,10,12,0.45)' }} />
              </div> : null}
            {/* Round (struck through when complete) */}
            <div style={{ position: 'relative', zIndex: 1, display: 'inline-block', justifySelf: 'start' }}>
              <span style={{ fontFamily: 'Archivo', fontWeight: 900, fontSize: 'clamp(34px,3.6vw,56px)', lineHeight: 1, letterSpacing: '-0.04em', color: done && !hot ? COLORS.textDim : txt, fontVariantNumeric: 'tabular-nums' }}>{String(r.round).padStart(2, '0')}</span>
              {done && <span style={{ position: 'absolute', left: -6, right: -6, top: '52%', height: 5, background: hot && !pr ? '#000' : COLORS.red, transform: 'rotate(-14deg)', borderRadius: 2 }} />}
            </div>
            {/* Location */}
            <div style={{ position: 'relative', zIndex: 1, display: 'flex', alignItems: 'center', gap: 16, minWidth: 0 }}>
              <span style={{ fontFamily: 'Archivo', fontWeight: 900, fontSize: 'clamp(20px,2.2vw,36px)', lineHeight: 1, letterSpacing: '-0.02em', textTransform: 'uppercase', color: txt, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{UR_CAL_LOC(r.grandPrix)}</span>
              {!(pr && iso) && <FlagSvg kind={UR_GP_FLAG[r.grandPrix] || 'pacific'} w={46} h={31} radius={3} />}
            </div>
            {/* Minimap */}
            <div style={{ position: 'relative', zIndex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
              {urRaceMinimap(r) ?
              <img
                src={urRaceMinimap(r)}
                alt={r.track}
                style={{
                  height: 44, width: 'auto', maxWidth: 44,
                  objectFit: 'contain',
                  filter: hot && !pr ?
                  'brightness(0)' :
                  'brightness(1.8) drop-shadow(0 0 7px rgba(225,6,0,0.55))'
                }} /> :

              null}
            </div>
            {/* Laps */}
            <span style={{ position: 'relative', zIndex: 1, fontFamily: 'Archivo', fontWeight: 700, fontSize: 'clamp(18px,1.6vw,28px)', lineHeight: 1, color: done && !hot ? COLORS.textDim : sub, fontVariantNumeric: 'tabular-nums', whiteSpace: 'nowrap' }}>{r.laps != null ? <React.Fragment>{r.laps}<span style={{ fontSize: 13, fontWeight: 600, marginLeft: 4, letterSpacing: '0.04em' }}>laps</span></React.Fragment> : <span style={{ fontSize: 13, fontWeight: 600, letterSpacing: '0.04em' }}>TBA</span>}</span>
            {/* When */}
            <span style={{ position: 'relative', zIndex: 1, textAlign: 'right', fontFamily: 'Archivo', fontWeight: 900, fontSize: 'clamp(26px,2.6vw,44px)', lineHeight: 1, letterSpacing: '-0.01em', color: txt, fontVariantNumeric: 'tabular-nums', whiteSpace: 'nowrap' }}>{fmtLandoDate(r.date)}</span>
          </div>);

      })}
    </div>);

};

// Calendar & Results combined page — track hero + result rows
const URCalendarResults = ({ version = 'default', podiumColors = 'medal', initialRound = null, posterRows = false, initialSeason = null, resultsView = 'scroll' }) => {
  const calSeasons = (typeof getCalendarSeasons !== 'undefined' ? getCalendarSeasons() : []).filter((s) => !s.fromDb); // results wired only for hand-entered seasons
  const [calSeasonId, setCalSeasonId] = React.useState(initialSeason);
  const activeCal = calSeasons.some((s) => s.id === calSeasonId) ? calSeasonId : (calSeasons.find((s) => s.isCurrent) || calSeasons[0] || {}).id;
  const calIdx = Math.max(0, calSeasons.findIndex((s) => s.id === activeCal));
  const activeMeta = calSeasons.find((s) => s.id === activeCal) || {};
  return (
    <React.Fragment>
      <URTrackHero version={version} league="ul" season={activeCal} seasonIdx={calIdx} podiumColors={podiumColors} initialRound={initialRound} resultsView={resultsView} />
      <section style={{ background: '#000', padding: '40px 32px 120px' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 16, marginBottom: 30, flexWrap: 'wrap' }}>
          <div style={{ fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.28em', color: COLORS.red, textTransform: 'uppercase' }}>◆ Ultimate League Calendar{activeMeta.period ? ` · ${activeMeta.period}` : ''}</div>
          <div style={{ flex: 1, height: 1, background: COLORS.hairline, minWidth: 40 }} />
          {calSeasons.length > 1 &&
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <span style={{ fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.24em', color: COLORS.textDim, textTransform: 'uppercase' }}>Season</span>
            <div style={{ position: 'relative' }}>
              <select value={activeCal || ''} onChange={(e) => setCalSeasonId(e.target.value)} style={{
                appearance: 'none', WebkitAppearance: 'none', MozAppearance: 'none', height: 38, boxSizing: 'border-box',
                background: COLORS.panel, color: COLORS.text, border: `1px solid ${COLORS.hairline}`, borderRadius: 0,
                padding: '0 34px 0 14px', cursor: 'pointer', fontFamily: 'Archivo', fontWeight: 800, fontSize: 13, letterSpacing: '0.04em'
              }}>
                {calSeasons.map((s) => <option key={s.id} value={s.id} style={{ background: COLORS.ink, color: COLORS.text }}>{s.label}{s.isCurrent ? ' · current' : ''}</option>)}
              </select>
              <span aria-hidden style={{ position: 'absolute', right: 12, top: '50%', transform: 'translateY(-50%)', pointerEvents: 'none', color: COLORS.red, fontSize: 8 }}>▼</span>
            </div>
          </div>}
        </div>
        <URLandoCalendar season={activeCal} posterRows={posterRows} />
      </section>
    </React.Fragment>);
};



const URResults = ({ league, setLeague }) =>
<React.Fragment>
    <URPageHeader
    title="The"
    italic="results."
    league={league} />
    <URLeagueBand league={league} setLeague={setLeague} label="Switch league" />

    <section style={{ background: COLORS.base, padding: '20px 40px 110px' }}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
        {URL_LEAGUE.results.map((r, i) =>
      <article key={r.r} style={{
        background: COLORS.surface, border: `1px solid ${COLORS.hairline}`,
        display: 'grid', gridTemplateColumns: '120px 60px 1.2fr 1.4fr 200px', alignItems: 'center',
        padding: '24px 32px', gap: 24, position: 'relative'
      }}>
            {/* Round + date */}
            <div>
              <div style={{ fontFamily: 'Archivo', fontWeight: 900, fontSize: 42, color: COLORS.red, letterSpacing: '-0.03em', lineHeight: 1 }}>{r.r}</div>
              <div style={{ marginTop: 6, fontFamily: 'JetBrains Mono', fontSize: 10, color: COLORS.textMute, letterSpacing: '0.22em', textTransform: 'uppercase' }}>{r.date}</div>
            </div>
            {/* Flag */}
            <FlagSvg kind={r.flag} w={48} h={32} radius={3} />
            {/* Race name + notes */}
            <div>
              <div style={{ fontFamily: 'Archivo', fontWeight: 800, fontSize: 24, color: COLORS.text, letterSpacing: '-0.01em' }}>{r.name}</div>
              <div style={{ marginTop: 6, fontSize: 14, color: COLORS.textMute, lineHeight: 1.45 }}>{r.notes}</div>
              <div style={{ marginTop: 10, fontFamily: 'JetBrains Mono', fontSize: 11, color: COLORS.red, letterSpacing: '0.18em', textTransform: 'uppercase' }}>FL · {r.fastLap}</div>
            </div>
            {/* Podium */}
            <div style={{ paddingLeft: 16, borderLeft: `1px solid ${COLORS.hairline}` }}>
              <div style={{ fontFamily: 'JetBrains Mono', fontSize: 10, color: COLORS.textMute, letterSpacing: '0.26em', textTransform: 'uppercase', marginBottom: 12 }}>Podium</div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                {r.podium.map(([drv, teamId], idx) => {
              const team = TEAM_BY_ID[teamId];
              const colors = [COLORS.red, '#D4D4D8', '#CD7F32'];
              return (
                <div key={drv} style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
                      <PosChip p={`P${idx + 1}`} color={colors[idx]} />
                      <span style={{ fontFamily: 'Archivo', fontWeight: 800, fontSize: 16, color: COLORS.text, flex: 1 }}>{drv}</span>
                      <span style={{ fontFamily: 'JetBrains Mono', fontSize: 11, color: team.color, fontWeight: 700, letterSpacing: '0.18em' }}>{team.short}</span>
                    </div>);

            })}
              </div>
            </div>
            {/* Action */}
            <div style={{ textAlign: 'right' }}>
              <a style={{ fontFamily: 'Archivo', fontWeight: 800, fontSize: 12, color: COLORS.text, letterSpacing: '0.22em', textTransform: 'uppercase', borderBottom: `1px solid ${COLORS.red}`, paddingBottom: 4, cursor: 'pointer' }}>Full report →</a>
            </div>
          </article>
      )}
      </div>
    </section>
  </React.Fragment>;


// ─────────────────────────────────────────────────────────────────────────────
// PODIUM CIRCUITS — track-outline glyphs tinted by finishing metal.
// The minimap PNG (transparent-bg silhouette) is used as a CSS mask so we can
// tint the circuit shape gold/silver/bronze. Round → track via the league calendar.
const UR_METAL = {
  1: { name: 'Gold', grad: 'linear-gradient(145deg, #FFF6D2 0%, #F7D24E 34%, #E0A81E 68%, #B07E14 100%)', glow: '#F0C53C', edge: '#E8B73C' },
  2: { name: 'Silver', grad: 'linear-gradient(145deg, #FFFFFF 0%, #E4E4E9 38%, #BFBFC6 70%, #99999F 100%)', glow: '#D6D6DD', edge: '#C9C9D0' },
  3: { name: 'Bronze', grad: 'linear-gradient(145deg, #FBDCB6 0%, #E29A5C 40%, #BC7038 72%, #97552A 100%)', glow: '#D68F52', edge: '#C57F45' }
};
const URPodiumGlyph = ({ round, pos, league, seasonLabel }) => {
  const race = (getCalendar(league, seasonLabel).races || []).find((r) => r.round === round);
  const minimap = urRaceMinimap(race);
  const metal = UR_METAL[pos] || UR_METAL[3];
  if (!minimap) return (
    <div title={`P${pos}${race ? ' · ' + race.grandPrix : ''} · R${String(round).padStart(2, '0')}`} style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '5px 6px 6px', borderBottom: `2.5px solid ${metal.edge}` }}>
      <div style={{ width: 46, height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <span style={{ width: 30, height: 30, borderRadius: '50%', background: metal.grad, display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'JetBrains Mono', fontWeight: 800, fontSize: 11, color: '#1a1408', boxShadow: '0 1px 2px rgba(0,0,0,0.55)' }}>P{pos}</span>
      </div>
    </div>);
  const maskStyle = {
    width: 46, height: 32, background: metal.grad,
    WebkitMaskImage: `url("${minimap}")`, maskImage: `url("${minimap}")`,
    WebkitMaskSize: 'contain', maskSize: 'contain',
    WebkitMaskRepeat: 'no-repeat', maskRepeat: 'no-repeat',
    WebkitMaskPosition: 'center', maskPosition: 'center',
    filter: `drop-shadow(0 1px 1px rgba(0,0,0,0.55))`
  };
  return (
    <div title={`P${pos} · ${race.grandPrix} · R${String(round).padStart(2, '0')}`}
    style={{
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: '5px 6px 6px', borderBottom: `2.5px solid ${metal.edge}`
    }}>
      <div style={maskStyle}></div>
    </div>);
};
const URPodiumCircuits = ({ podiums, league }) => {
  if (!podiums || !podiums.length) return null;
  const sorted = [...podiums].sort((a, b) => a.round - b.round);
  return (
    <div style={{ marginTop: 16 }}>
      <div style={{ fontFamily: 'JetBrains Mono', fontSize: 8.5, letterSpacing: '0.24em', color: COLORS.textMute, textTransform: 'uppercase', marginBottom: 10 }}>Podium Circuits</div>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
        {sorted.map((p) => <URPodiumGlyph key={p.round} round={p.round} pos={p.pos} league={league} />)}
      </div>
    </div>);
};

// ─────────────────────────────────────────────────────────────────────────────
// DRIVER CARD — single driver card, store-driven
const URDriverCard = ({ d, team, accent, champion, roleChip, carNumber, league, podiums, podiumGlyphs }) => {
  const accentColor = team ? team.color : accent || COLORS.red;
  const cardBg = team ?
  `linear-gradient(135deg, ${team.color}38 0%, ${team.color}12 30%, ${COLORS.surface} 68%)` :
  COLORS.surface;
  const slotId = `ur-drv-${d.name.toLowerCase().replace(/[^a-z0-9]/g, '-')}`;

  const sortedPodiums = podiums && podiums.length ? [...podiums].sort((a, b) => a.round - b.round) : null;
  // Wins/podiums DERIVED from this league+season's per-race finishes (the same source as the
  // glyphs) so the count always matches the circuits and is strictly league-specific. Falls back
  // to the standings aggregate only when no per-race data is present for this driver.
  const statWins = sortedPodiums ? sortedPodiums.filter((p) => p.pos === 1).length : d.wins ?? 0;
  const statPodiums = sortedPodiums ? sortedPodiums.length : d.podiums ?? 0;
  const glyphGrid = league && sortedPodiums ?
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, auto)', gap: 5 }}>
      {sortedPodiums.map((p) => <URPodiumGlyph key={p.round} round={p.round} pos={p.pos} league={league} />)}
    </div> : null;
  return (
    <article style={{
      background: cardBg, border: `1px solid ${COLORS.hairline}`,
      display: 'grid', gridTemplateColumns: '200px 1fr',
      position: 'relative', overflow: 'hidden', minHeight: 300
    }}>
      {/* Portrait */}
      <div style={{ position: 'relative', borderRight: `1px solid ${COLORS.hairline}` }}>
        <URImageSlot id={slotId} placeholder={`${d.name} portrait`} shape="rect" style={{ width: '100%', height: '100%', minHeight: 300 }} />
        <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, transparent 40%, rgba(0,0,0,0.88))', pointerEvents: 'none' }} />
        <div aria-hidden style={{
          position: 'absolute', right: -6, bottom: -24,
          fontFamily: 'Archivo', fontWeight: 900, fontSize: 160, color: COLORS.text,
          lineHeight: 0.8, letterSpacing: '-0.06em', opacity: 0.14, pointerEvents: 'none'
        }}>{carNumber != null ? carNumber : d.pos}</div>
      </div>
      {/* Info */}
      <div style={{ padding: '24px 26px', display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
        <div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 8 }}>
            <div style={{ fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.26em', color: accentColor, textTransform: 'uppercase' }}>◆ P{d.pos} OVERALL</div>
            {roleChip && <div style={{ fontFamily: 'JetBrains Mono', fontSize: 9, fontWeight: 700, letterSpacing: '0.22em', color: roleChip === 'MAIN' ? COLORS.text : COLORS.textMute, background: roleChip === 'MAIN' ? `${accentColor}55` : 'transparent', border: `1px solid ${roleChip === 'MAIN' ? accentColor : COLORS.hairline}`, padding: '3px 8px', textTransform: 'uppercase' }}>{roleChip}</div>}
            {champion && <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.2em', color: '#F3C13F', textTransform: 'uppercase', fontWeight: 700 }}><LaurelIcon size={20} /> Champion</div>}
          </div>
          <h3 style={{ margin: 0, fontFamily: 'Archivo', fontWeight: 900, fontSize: 46, color: COLORS.text, letterSpacing: '-0.025em', lineHeight: 0.95, textTransform: 'uppercase' }}>{d.name}</h3>
          {podiumGlyphs === 'right' ?
          <div style={{ display: 'flex', alignItems: 'flex-start', gap: 14, marginTop: 10 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, flex: 1 }}>
              {getDriverFlag(d.name) && <FlagSvg kind={getDriverFlag(d.name)} w={30} h={20} radius={3} />}
              {team && <div style={{ fontFamily: 'JetBrains Mono', fontSize: 10, color: team.color, letterSpacing: '0.18em', textTransform: 'uppercase' }}>{team.short}</div>}
              {carNumber != null && <div style={{ fontFamily: 'JetBrains Mono', fontSize: 10, color: COLORS.textMute, letterSpacing: '0.12em', fontWeight: 700 }}>#{carNumber}</div>}
            </div>
            {glyphGrid}
          </div> :
          <React.Fragment>
            <div style={{ marginTop: 10, display: 'flex', alignItems: 'center', gap: 10 }}>
              {getDriverFlag(d.name) && <FlagSvg kind={getDriverFlag(d.name)} w={30} h={20} radius={3} />}
              {team && <div style={{ fontFamily: 'JetBrains Mono', fontSize: 10, color: team.color, letterSpacing: '0.18em', textTransform: 'uppercase' }}>{team.short}</div>}
              {carNumber != null && <div style={{ fontFamily: 'JetBrains Mono', fontSize: 10, color: COLORS.textMute, letterSpacing: '0.12em', fontWeight: 700 }}>#{carNumber}</div>}
            </div>
            {glyphGrid && <div style={{ marginTop: 14 }}>{glyphGrid}</div>}
          </React.Fragment>
          }
        </div>
        <div style={{ marginTop: 24, display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12, paddingTop: 18, borderTop: `1px solid ${COLORS.hairline}` }}>
          {[['Pts', d.pts], ['Wins', statWins], ['Podiums', statPodiums]].map(([k, v]) =>
          <div key={k}>
              <div style={{ fontFamily: 'JetBrains Mono', fontSize: 9, color: COLORS.textMute, letterSpacing: '0.22em', textTransform: 'uppercase' }}>{k}</div>
              <div style={{ fontFamily: 'Archivo', fontWeight: 900, fontSize: 28, color: COLORS.text, marginTop: 4, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.01em' }}>{v}</div>
            </div>
          )}
        </div>
      </div>
    </article>);

};

// ─────────────────────────────────────────────────────────────────────────────
// TEAM SHOWCASE — one-team-at-a-time browser: livery rail → team bar → lineup
const UR_RAIL_TILE_W = 230;
const UR_RAIL_TILE_H = 124;
const UR_RAIL_GAP = 16;

const URShowcaseArrow = ({ dir, onClick, accent }) => {
  const [hover, setHover] = React.useState(false);
  return (
    <button onClick={onClick} aria-label={dir > 0 ? 'Next team' : 'Previous team'}
    onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
    style={{
      width: 56, height: 56, flexShrink: 0, cursor: 'pointer',
      background: hover ? accent : 'transparent',
      border: `1px solid ${hover ? accent : COLORS.hairline}`,
      color: COLORS.text, display: 'flex', alignItems: 'center', justifyContent: 'center',
      transition: 'background 0.15s ease, border-color 0.15s ease'
    }}>
      <svg width="18" height="18" viewBox="0 0 18 18" fill="none" aria-hidden="true" style={{ transform: dir > 0 ? 'none' : 'scaleX(-1)' }}>
        <polyline points="6,3 13,9 6,15" stroke="currentColor" strokeWidth="2" fill="none"></polyline>
      </svg>
    </button>);

};

const URTeamShowcase = ({ league, data, accent, clinchedChampion, podiumGlyphs }) => {
  const teams = data.teams;
  const podiumMap = typeof usePodiumMap !== 'undefined' ? usePodiumMap(league, data.season && data.season.label) : {};
  const [idx, setIdx] = React.useState(0);
  React.useEffect(() => {setIdx(0);}, [league, data.season && data.season.label]);
  const safeIdx = Math.min(idx, teams.length - 1);
  const team = teams[safeIdx];
  const teamDrivers = data.drivers.filter((d) => d.team === team.short);
  const step = (dir) => setIdx((i) => (i + dir + teams.length) % teams.length);

  // Rail is centered on the active tile: inner strip pinned at 50%, shifted by index.
  const shift = -(safeIdx * (UR_RAIL_TILE_W + UR_RAIL_GAP) + UR_RAIL_TILE_W / 2);

  return (
    <div>
      <style>{`
        @media (prefers-reduced-motion: no-preference) {
          @keyframes ur-lineup-in { from { transform: translateY(14px); } to { transform: none; } }
          .ur-lineup-anim { animation: ur-lineup-in 0.35s ease both; }
          @keyframes ur-hero-in { from { opacity: 0; transform: scale(1.03); } to { opacity: 1; transform: none; } }
          .ur-hero-anim { animation: ur-hero-in 0.45s cubic-bezier(0.22,1,0.36,1) both; }
        }
        .ur-ghost-arrow { opacity: 0; transition: opacity 0.2s ease, background 0.2s ease; }
        .ur-hero-banner:hover .ur-ghost-arrow { opacity: 1; }
        .ur-ghost-arrow:hover { background: rgba(255,255,255,0.06) !important; }
      `}</style>

      {/* ── Large team hero banner ── */}
      <div key={team.short + '-hero'} className="ur-hero-banner ur-hero-anim" style={{
        position: 'relative', width: '100%', height: 340, marginBottom: 28, overflow: 'hidden',
        background: `linear-gradient(105deg, ${team.color}40 0%, ${team.color}18 30%, ${COLORS.base} 60%)`,
        borderBottom: `2px solid ${team.color}66`,
        display: 'flex', alignItems: 'stretch'
      }}>
        {/* Ghost arrows */}
        <button aria-label="Previous team" onClick={() => step(-1)} className="ur-ghost-arrow" style={{
          position: 'absolute', left: 0, top: 0, bottom: 0, width: 60, zIndex: 10,
          background: 'transparent', border: 'none', cursor: 'pointer',
          display: 'flex', alignItems: 'center', justifyContent: 'center'
        }}>
          <svg width="22" height="40" viewBox="0 0 22 40" fill="none" aria-hidden="true">
            <polyline points="16,4 4,20 16,36" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" fill="none"></polyline>
          </svg>
        </button>
        <button aria-label="Next team" onClick={() => step(1)} className="ur-ghost-arrow" style={{
          position: 'absolute', right: 0, top: 0, bottom: 0, width: 60, zIndex: 10,
          background: 'transparent', border: 'none', cursor: 'pointer',
          display: 'flex', alignItems: 'center', justifyContent: 'center'
        }}>
          <svg width="22" height="40" viewBox="0 0 22 40" fill="none" aria-hidden="true">
            <polyline points="6,4 18,20 6,36" stroke="white" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" fill="none"></polyline>
          </svg>
        </button>

        {/* Content row */}
        <div style={{ flex: 1, display: 'flex', alignItems: 'stretch', margin: '0 60px' }}>

          {/* 1. Logo */}
          <div style={{ width: 200, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '24px 20px' }}>
            {UR_TEAM_LOGO[team.short] ?
            <img src={UR_TEAM_LOGO[team.short]} alt={team.name} style={{
              maxWidth: '100%', maxHeight: 160, objectFit: 'contain',
              filter: UR_TEAM_LOGO_DARK.has(team.short) ? 'brightness(0.4)' : `drop-shadow(0 0 20px ${team.color}99)`
            }} /> :
            <span style={{ fontFamily: 'Archivo', fontWeight: 900, fontSize: 52, color: team.color }}>{team.short}</span>
            }
          </div>

          {/* 2. Team name */}
          <div style={{ flex: 1, display: 'flex', alignItems: 'center', padding: '0 32px', minWidth: 0 }}>
            <h2 style={{
              margin: 0, fontFamily: 'Archivo', fontWeight: 900,
              fontSize: 'clamp(32px, 4.5vw, 72px)',
              color: COLORS.text, letterSpacing: '-0.04em', textTransform: 'uppercase',
              lineHeight: 0.88
            }}>{team.name}</h2>
          </div>

          {/* 3. Livery — rotated 90°, full banner height */}
          <div style={{ width: 320, flexShrink: 0, alignSelf: 'stretch', display: 'flex', alignItems: 'center', justifyContent: 'center', overflow: 'hidden', position: 'relative' }}>
            <div aria-hidden style={{ position: 'absolute', inset: 0, background: `radial-gradient(ellipse at center, ${team.color}33 0%, transparent 70%)`, pointerEvents: 'none' }}></div>
            {(team.livery || getLivery(league, team.short)) ?
            <img src={team.livery || getLivery(league, team.short)} alt={team.short} style={{
              position: 'absolute',
              top: '50%', left: '50%',
              width: '340px', height: 'auto',
              transform: 'translate(-50%, -50%) rotate(90deg)',
              transformOrigin: 'center center',
              zIndex: 1, padding: "20px"
            }} /> :
            <span style={{ fontFamily: 'JetBrains Mono', fontSize: 10, color: COLORS.hairline, letterSpacing: '0.2em' }}>NO LIVERY</span>
            }
          </div>

          {/* 4. Thin separator */}
          <div style={{ width: 1, background: COLORS.hairline, flexShrink: 0, alignSelf: 'stretch', margin: '20px 0' }}></div>

          {/* 5. Stats */}
          <div style={{ width: 180, flexShrink: 0, display: 'flex', flexDirection: 'column', justifyContent: 'center', padding: '0 28px' }}>
            {[
            ['Position', `P${team.pos}`],
            ['Points', team.pts],
            ['Wins', teamDrivers.reduce((s, d) => s + (d.wins || 0), 0)]].
            map(([k, v], i) =>
            <div key={k} style={{ padding: '14px 0', borderBottom: i < 2 ? `1px solid ${COLORS.hairline}` : 'none' }}>
              <div style={{ fontFamily: 'JetBrains Mono', fontSize: 9, color: COLORS.textMute, letterSpacing: '0.28em', textTransform: 'uppercase', marginBottom: 5 }}>{k}</div>
              <div style={{ fontFamily: 'Archivo', fontWeight: 900, fontSize: 30, color: team.color, fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.02em', lineHeight: 1 }}>{v}</div>
            </div>
            )}
          </div>

        </div>

        {/* Dot indicator */}
        <div style={{ position: 'absolute', bottom: 10, left: 0, right: 0, display: 'flex', justifyContent: 'center', gap: 6, zIndex: 5, pointerEvents: 'none' }}>
          {teams.map((t, i) =>
          <span key={t.short} style={{
            width: i === safeIdx ? 20 : 6, height: 4,
            background: i === safeIdx ? team.color : COLORS.hairline,
            transition: 'width 0.3s ease, background 0.3s ease', display: 'block'
          }}></span>
          )}
        </div>
      </div>

      {/* ── Lineup — roster-aware: mains + signed reserve, with standings stats joined by name ── */}
      {(() => {
        const roster = typeof getTeamRoster !== 'undefined' ? getTeamRoster(league, team.short, data.season && data.season.label) : null;
        if (!roster) {
          return (
            <React.Fragment>
              <div key={team.short} className="ur-lineup-anim" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 20 }}>
                {teamDrivers.map((d) => <URDriverCard key={d.name} d={d} team={team} accent={accent} champion={clinchedChampion === d.name} league={league} podiums={podiumMap[d.name]} podiumGlyphs={podiumGlyphs} />)}
              </div>
              {!teamDrivers.length &&
              <div style={{ border: `1px solid ${COLORS.hairline}`, background: COLORS.surface, padding: '48px 40px', textAlign: 'center', fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.24em', color: COLORS.textMute, textTransform: 'uppercase' }}>No lineup listed for {team.name}</div>
              }
            </React.Fragment>);
        }
        // Join roster people ↔ standings rows by sheetName (the explicit results key).
        const findStanding = (p) => data.drivers.find((d) => rosterNorm(d.name) === rosterNorm(p.sheetName || p.display)) || null;
        const rosterEntries = [
        ...roster.mains.map((p) => ({ p, role: 'MAIN' })),
        ...(roster.reserve ? [{ p: roster.reserve, role: 'RESERVE' }] : [])];
        const claimed = new Set(rosterEntries.map((e) => {const s = findStanding(e.p);return s ? rosterNorm(s.name) : null;}).filter(Boolean));
        // Sheet rows on this team that the roster doesn't list — display raw, unlabeled.
        const unlisted = teamDrivers.filter((d) => !claimed.has(rosterNorm(d.name)));
        return (
          <React.Fragment>
            <div key={team.short} className="ur-lineup-anim" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 20 }}>
              {rosterEntries.map(({ p, role }) => {
                const s = findStanding(p);
                const d = s || { pos: '–', name: p.sheetName || p.display, team: team.short, pts: 0, wins: 0, podiums: 0 };
                return <URDriverCard key={role + p.handle} d={d} team={team} accent={accent} champion={s ? clinchedChampion === s.name : false} roleChip={role} carNumber={p.carNumber != null ? p.carNumber : null} league={league} podiums={podiumMap[d.name]} podiumGlyphs={podiumGlyphs} />;
              })}
              {unlisted.map((d) => {
                const who = typeof resolvePerson !== 'undefined' ? resolvePerson(d.name) : null;
                return <URDriverCard key={'x' + d.name} d={d} team={team} accent={accent} champion={clinchedChampion === d.name} carNumber={who && who.carNumber != null ? who.carNumber : null} league={league} podiums={podiumMap[d.name]} podiumGlyphs={podiumGlyphs} />;
              })}
            </div>
            {!roster.reserve &&
            <div style={{ marginTop: 20, border: `1px dashed ${COLORS.hairline}`, padding: '18px 24px', fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.24em', color: COLORS.textDim, textTransform: 'uppercase' }}>Reserve seat vacant</div>
            }
          </React.Fragment>);
      })()}
    </div>);

};

// ─────────────────────────────────────────────────────────────────────────────
// DRIVERS PAGE — wired to the data store
const URDriversEditorial = ({ league, setLeague, podiumGlyphs }) => {
  const L = LEAGUE_BY_ID[league];
  const seasons = getSeasons(league);
  const [seasonId, setSeasonId] = React.useState(null);
  const activeId = seasons.some((s) => s.id === seasonId) ? seasonId : defaultDataSeasonId(seasons);
  const data = useStandings(league, activeId);
  // Podiums for the non-team (AL) flat grid; team leagues fetch inside URTeamShowcase (cached).
  // MUST run unconditionally (before the early returns below) so hook order stays stable when
  // switching between an empty season and one with data — otherwise React throws
  // "Rendered more hooks than during the previous render".
  const flatPodiumMap = typeof usePodiumMap !== 'undefined' ? usePodiumMap(league, data.season && data.season.label) : {};

  const CTRL_H = 44;
  const drvDropStyle = {
    appearance: 'none', WebkitAppearance: 'none', MozAppearance: 'none',
    height: CTRL_H, boxSizing: 'border-box',
    background: COLORS.surface, color: COLORS.text,
    border: `1px solid ${COLORS.hairline}`, borderRadius: 0,
    padding: '0 38px 0 16px', cursor: 'pointer',
    fontFamily: 'Archivo', fontWeight: 800, fontSize: 14, letterSpacing: '0.04em'
  };
  const DrvChevron = () =>
  <span aria-hidden style={{ position: 'absolute', right: 12, top: '50%', transform: 'translateY(-50%)', pointerEvents: 'none', color: L.accent, fontSize: 9 }}>▼</span>;

  const controls =
  <div style={{ position: 'relative' }}>
      <select value={activeId || ''} onChange={(e) => setSeasonId(e.target.value)} style={drvDropStyle}>
        {seasons.map((s) => <option key={s.id} value={s.id} style={{ background: COLORS.ink, color: COLORS.text }}>{s.label}{s.hasData ? '' : ' · soon'}</option>)}
      </select>
      <DrvChevron />
    </div>;


  const leagueSwitch =
  <div style={{ display: 'inline-flex', border: `1px solid ${COLORS.hairline}`, background: COLORS.panel }}>
      {LEAGUES.map((Lg, i) => {
      const active = league === Lg.id;
      return (
        <button key={Lg.id} onClick={() => setLeague(Lg.id)} style={{
          all: 'unset', cursor: 'pointer',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          width: 52, height: 44, boxSizing: 'border-box',
          background: active ? COLORS.surface : 'transparent',
          borderRight: i < LEAGUES.length - 1 ? `1px solid ${COLORS.hairline}` : 'none',
          position: 'relative', transition: 'background .12s ease'
        }}>
            {active && <span style={{ position: 'absolute', left: 0, right: 0, bottom: 0, height: 2, background: Lg.accent }} />}
            <img src={Lg.logo} alt={Lg.short} style={{ height: 26, width: 26, objectFit: 'contain', display: 'block', opacity: active ? 1 : 0.45, filter: active ? 'none' : 'grayscale(.5)' }} />
          </button>);

    })}
    </div>;

  const headerRight = <React.Fragment>{controls}{leagueSwitch}</React.Fragment>;

  // Loading
  if (data.status === 'loading') {
    return (
      <React.Fragment>
        <URPageHeader title="Meet the" italic="Teams" league={league} right={headerRight} />
        <section style={{ background: COLORS.base, padding: '80px 40px 140px', display: 'flex', justifyContent: 'center', alignItems: 'flex-start' }}>
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 20, paddingTop: 60 }}>
            <div style={{ display: 'flex', gap: 8 }}>
              {[0, 1, 2].map((i) => <span key={i} style={{ width: 10, height: 10, background: L.accent, borderRadius: '50%', animation: `ur-pulse 1.2s ease-in-out ${i * 0.2}s infinite` }} />)}
            </div>
            <span style={{ fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.28em', color: COLORS.textMute, textTransform: 'uppercase' }}>Loading live data…</span>
          </div>
        </section>
      </React.Fragment>);

  }

  // Empty
  if (!data.drivers.length) {
    return (
      <React.Fragment>
        <URPageHeader title="Meet the" italic="Teams" league={league} right={headerRight} />
        <section style={{ background: COLORS.base, padding: '80px 40px 140px', display: 'flex', justifyContent: 'center' }}>
          <div style={{ maxWidth: 560, textAlign: 'center', background: COLORS.surface, border: `1px solid ${COLORS.hairline}`, padding: '64px 48px' }}>
            <div style={{ fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.3em', color: L.accent, textTransform: 'uppercase' }}>◆ {L.short}</div>
            <h3 style={{ margin: '18px 0 0', fontFamily: 'Archivo', fontWeight: 900, fontSize: 40, color: COLORS.text, letterSpacing: '-0.02em' }}>Driver data coming soon</h3>
          </div>
        </section>
      </React.Fragment>);

  }

  const isTeamBased = !!data.season?.teamBased && !!(data.teams && data.teams.length);
  const clinchedChampion = getClinchedChampion(league, data.drivers, data.season);

  return (
    <React.Fragment>
      <URPageHeader title="Meet the" italic="Teams" league={league} right={headerRight} />
      <section style={{ background: COLORS.base, padding: '20px 40px 110px' }}>
        {isTeamBased ?
        <URTeamShowcase league={league} data={data} accent={L.accent} clinchedChampion={clinchedChampion} podiumGlyphs={podiumGlyphs} /> :

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 20 }}>
            {data.drivers.map((d) => <URDriverCard key={d.name} d={d} team={null} accent={L.accent} champion={clinchedChampion === d.name} league={league} podiums={flatPodiumMap[d.name]} podiumGlyphs={podiumGlyphs} />)}
          </div>
        }
      </section>
    </React.Fragment>);

};

// ─────────────────────────────────────────────────────────────────────────────
// CALENDAR PAGE — Full 16-round calendar with bigger detail
const UR_CAL_COLS = '64px 96px 1fr 168px 116px 120px';

const URCalendarPageRow = ({ e }) => {
  const isDone = e.status === 'done';
  const isNext = e.status === 'next';
  return (
    <div style={{
      display: 'grid', gridTemplateColumns: UR_CAL_COLS, gap: 24,
      alignItems: 'center', padding: '20px 28px',
      background: isNext ? `linear-gradient(90deg, ${COLORS.red}1a, transparent 70%)` : 'transparent',
      borderBottom: `1px solid ${COLORS.hairline}`, position: 'relative'
    }}>
      {isNext && <span style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: 3, background: COLORS.red }} />}
      <span style={{ fontFamily: 'JetBrains Mono', fontWeight: 700, fontSize: 14, color: isDone ? COLORS.textDim : COLORS.red, letterSpacing: '0.14em' }}>R{String(e.round).padStart(2, '0')}</span>
      <span style={{ fontFamily: 'JetBrains Mono', fontSize: 13, color: isDone ? COLORS.textMute : COLORS.text }}>{e.localDate}</span>
      <div>
        <div style={{ fontFamily: 'Archivo', fontWeight: 800, fontSize: 21, color: isDone ? COLORS.textMute : COLORS.text, letterSpacing: '-0.005em' }}>{e.grandPrix}</div>
        <div style={{ fontFamily: 'Archivo', fontSize: 13, color: COLORS.textDim, marginTop: 2 }}>{[e.track, e.laps != null ? `${e.laps} laps` : null, e.creator].filter(Boolean).join(' · ')}</div>
      </div>
      <div>
        <div style={{ fontFamily: 'JetBrains Mono', fontWeight: 700, fontSize: 14, color: isDone ? COLORS.textMute : COLORS.text }}>{e.localTime}</div>
        <div style={{ fontFamily: 'JetBrains Mono', fontSize: 11, color: COLORS.textDim, marginTop: 2 }}>{e.utcTime}</div>
      </div>
      <div>
        <span style={{
          fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.2em', textTransform: 'uppercase', padding: '4px 8px',
          background: isNext ? COLORS.red : isDone ? '#1a1a1d' : 'transparent',
          color: isNext ? '#fff' : isDone ? COLORS.textMute : COLORS.textDim,
          border: !isDone && !isNext ? `1px solid ${COLORS.hairline}` : 'none'
        }}>{isNext ? 'Next' : isDone ? 'Complete' : 'Upcoming'}</span>
      </div>
      <div style={{ textAlign: 'right' }}>
        <a href={e.trackUrl} target="_blank" rel="noopener" style={{ fontFamily: 'Archivo', fontWeight: 700, fontSize: 12, color: COLORS.text, letterSpacing: '0.2em', textTransform: 'uppercase', borderBottom: `1px solid ${isNext ? COLORS.red : COLORS.hairline}`, paddingBottom: 4, textDecoration: 'none' }}>Track →</a>
      </div>
    </div>);

};

const URCalendarPage = ({ league, setLeague }) => {
  const cal = getCalendar(league);
  return (
    <React.Fragment>
    <URPageHeader
        title="The"
        italic="calendar."
        league={league} />
    <URLeagueBand league={league} setLeague={setLeague} label="Switch league" />

    <section style={{ background: COLORS.base, padding: '20px 40px 110px' }}>
      <div style={{ border: `1px solid ${COLORS.hairline}`, background: COLORS.ink }}>
        <div style={{ display: 'grid', gridTemplateColumns: UR_CAL_COLS, gap: 24, padding: '14px 28px', borderBottom: `1px solid ${COLORS.hairline}`, fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.22em', color: COLORS.textDim, textTransform: 'uppercase' }}>
          <span>Round</span><span>Date</span><span>Grand Prix</span><span>Start (local)</span><span>Status</span><span style={{ textAlign: 'right' }}>Link</span>
        </div>
        {cal.races.map((e) =>
          <React.Fragment key={e.round}>
            <URCalendarPageRow e={e} />
            {cal.midSeasonBreakAfter === e.round &&
            <div style={{ display: 'flex', alignItems: 'center', gap: 16, padding: '14px 28px', background: '#0b0b0e', borderBottom: `1px solid ${COLORS.hairline}` }}>
                <span style={{ flex: 1, height: 1, background: COLORS.hairline }} />
                <span style={{ fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.28em', color: COLORS.textMute, textTransform: 'uppercase' }}>◆ Mid-season break</span>
                <span style={{ flex: 1, height: 1, background: COLORS.hairline }} />
              </div>}
          </React.Fragment>)}
      </div>

      {/* Bottom info band */}
      <div style={{ marginTop: 40, display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 18 }}>
        {[
          { k: 'Race start', v: 'Sun 19:00 UTC', sub: 'Pre-show 18:30' },
          { k: 'Format', v: '38 laps · sprint', sub: 'No mandatory pit · arcade physics' },
          { k: 'Broadcast', v: 'Twitch / YouTube', sub: 'Live commentary every round' }].
          map((it, i) =>
          <div key={i} style={{ background: COLORS.surface, border: `1px solid ${COLORS.hairline}`, padding: '24px 28px' }}>
            <div style={{ fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.26em', color: COLORS.red, textTransform: 'uppercase' }}>◆ {it.k}</div>
            <div style={{ marginTop: 10, fontFamily: 'Archivo', fontWeight: 900, fontSize: 28, color: COLORS.text, letterSpacing: '-0.01em' }}>{it.v}</div>
            <div style={{ marginTop: 6, fontSize: 15, color: COLORS.textMute }}>{it.sub}</div>
          </div>
          )}
      </div>
    </section>
  </React.Fragment>);

};


// ─────────────────────────────────────────────────────────────────────────────
// DISCORD PAGE — Join CTA + community stats
const URDiscordPage = () =>
<React.Fragment>
    <section style={{ background: '#000', padding: '120px 40px 100px', position: 'relative', overflow: 'hidden' }}>
      {/* BG glows */}
      <div aria-hidden style={{ position: 'absolute', right: -200, top: -200, width: 800, height: 800, borderRadius: '50%', background: `radial-gradient(circle, ${COLORS.red}44 0%, transparent 60%)`, filter: 'blur(40px)' }} />
      <div aria-hidden style={{ position: 'absolute', left: -200, bottom: -200, width: 700, height: 700, borderRadius: '50%', background: `radial-gradient(circle, ${COLORS.redLight}33 0%, transparent 60%)`, filter: 'blur(40px)' }} />
      {/* Huge bg word */}
      <div aria-hidden style={{
      position: 'absolute', left: -20, bottom: -80, fontFamily: 'Archivo', fontWeight: 900, fontSize: 480,
      color: 'transparent', WebkitTextStroke: `1.5px ${COLORS.red}33`,
      letterSpacing: '-0.06em', lineHeight: 0.8, pointerEvents: 'none', textTransform: 'uppercase'
    }}>JOIN</div>

      <div style={{ position: 'relative', maxWidth: 1080 }}>
        <div style={{ fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.3em', color: COLORS.red, textTransform: 'uppercase', marginBottom: 22 }}>◆ The community · 12,000+ members</div>
        <h1 style={{ margin: 0, fontFamily: 'Archivo', fontWeight: 900, fontSize: 172, color: COLORS.text, letterSpacing: '-0.045em', lineHeight: 0.86, textTransform: 'uppercase' }}>
          Join the<br /><span style={{ color: COLORS.red, textTransform: 'none' }}>Discord.</span>
        </h1>
        <p style={{ marginTop: 32, fontSize: 26, color: COLORS.text, lineHeight: 1.4, maxWidth: 760 }}>
          Race chat. Live timing. Setup sharing. Driver Q&amp;A. Tryouts and team scouting. Everything UR2D happens here first.
        </p>

        {/* CTA */}
        <div style={{ marginTop: 44, display: 'flex', gap: 14, flexWrap: 'wrap' }}>
          <a href={URL_LEAGUE.brand.discord} target="_blank" rel="noopener" style={{
          display: 'inline-flex', alignItems: 'center', gap: 14,
          background: COLORS.red, color: '#fff', padding: '22px 32px',
          fontFamily: 'Archivo', fontWeight: 900, fontSize: 16, letterSpacing: '0.22em', textTransform: 'uppercase',
          textDecoration: 'none'
        }}>
            <DiscordIcon size={24} />
            Open Discord invite →
          </a>
          <button style={{ all: 'unset', cursor: 'pointer', border: `1px solid ${COLORS.textMute}`, color: COLORS.text, padding: '21px 32px', fontFamily: 'Archivo', fontWeight: 900, fontSize: 16, letterSpacing: '0.22em', textTransform: 'uppercase' }}>
            Server rules
          </button>
        </div>

        {/* Stats band */}
        <div style={{ marginTop: 80, display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 0, border: `1px solid ${COLORS.hairline}` }}>
          {[
        ['Members', '12,000+', '◆ Online now: 2,840'],
        ['Channels', '48', '◆ Including 8 team chats'],
        ['Time zones', '24/7', '◆ Always someone racing'],
        ['Tryouts', 'Monthly', '◆ Next: Jun 12']].
        map(([k, v, sub], i) =>
        <div key={i} style={{ padding: '32px 28px', borderRight: i < 3 ? `1px solid ${COLORS.hairline}` : 'none' }}>
              <div style={{ fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.24em', color: COLORS.textMute, textTransform: 'uppercase' }}>{k}</div>
              <div style={{ fontFamily: 'Archivo', fontWeight: 900, fontSize: 48, color: COLORS.text, marginTop: 10, letterSpacing: '-0.025em', lineHeight: 1 }}>{v}</div>
              <div style={{ marginTop: 8, fontFamily: 'JetBrains Mono', fontSize: 10, color: COLORS.red, letterSpacing: '0.2em', textTransform: 'uppercase' }}>{sub}</div>
            </div>
        )}
        </div>
      </div>
    </section>

    {/* Channel list */}
    <section style={{ background: COLORS.base, padding: '100px 40px 120px' }}>
      <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', marginBottom: 40 }}>
        <h2 style={{ margin: 0, fontFamily: 'Archivo', fontWeight: 900, fontSize: 64, color: COLORS.text, letterSpacing: '-0.03em', lineHeight: 0.95 }}>
          What's <span style={{ color: COLORS.red }}>inside.</span>
        </h2>
        <div style={{ fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.26em', color: COLORS.textMute, textTransform: 'uppercase' }}>SERVER MAP</div>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 16 }}>
        {[
      { cat: 'LIVE RACING', items: ['# race-day-chat', '# live-timing', '# broadcast-link', '# steward-decisions'] },
      { cat: 'COMMUNITY', items: ['# announcements', '# rookie-lounge', '# setup-shares', '# clip-of-the-week'] },
      { cat: 'COMPETITIVE', items: ['# tryouts', '# free-agents', '# team-scouting', '# next-season'] }].
      map((g) =>
      <div key={g.cat} style={{ background: COLORS.surface, border: `1px solid ${COLORS.hairline}`, padding: '28px 26px' }}>
            <div style={{ fontFamily: 'JetBrains Mono', fontSize: 11, letterSpacing: '0.28em', color: COLORS.red, textTransform: 'uppercase', marginBottom: 18 }}>◆ {g.cat}</div>
            {g.items.map((ch) =>
        <div key={ch} style={{ padding: '10px 0', fontFamily: 'JetBrains Mono', fontSize: 14, color: COLORS.text, borderBottom: `1px solid ${COLORS.hairline}` }}>{ch}</div>
        )}
          </div>
      )}
      </div>
    </section>
  </React.Fragment>;


// ─────────────────────────────────────────────────────────────────────────────
// HALL OF CHAMPIONS — past season title winners
// Laurel wreath mark — open at top (horseshoe), leaves ringed around the bottom.
const URWreath = ({ size = 64, color = '#E10600' }) => {
  const cx = 50,cy = 54,R = 30,N = 11;
  const startDeg = 300,endDeg = 600;
  const leaves = [];
  for (let i = 0; i < N; i++) {
    const deg = startDeg + (endDeg - startDeg) * (i / (N - 1));
    const rad = deg * Math.PI / 180;
    leaves.push({ x: cx + R * Math.cos(rad), y: cy + R * Math.sin(rad), rot: deg + 90 });
  }
  return (
    <svg width={size} height={size} viewBox="0 0 100 100" fill="none" aria-hidden="true">
      {leaves.map((lf, i) =>
      <ellipse key={i} cx={lf.x} cy={lf.y} rx={7} ry={2.5} fill={color} fillOpacity={0.92} transform={`rotate(${lf.rot} ${lf.x} ${lf.y})`} />)}
    </svg>);
};

const URChampLogo = ({ short, size = 22, color }) => {
  const src = short && urTeamLogo(short);
  if (src) return <img src={src} alt={short} style={{ width: size, height: size, objectFit: 'contain', flexShrink: 0, display: 'block' }} />;
  return color ? <span style={{ width: Math.round(size * 0.55), height: Math.round(size * 0.55), background: color, display: 'inline-block', flexShrink: 0, borderRadius: '50%' }} /> : null;
};

const URHallOfChampions = () => {
  const { status, seasons: champs } = useChampions('ul');
  const reigning = champs[0] || null;
  const rTeam = reigning ? reigning.wdc.team : null;
  const rCons = reigning ? reigning.wcc || { short: '—', name: '—', color: COLORS.textDim } : null;
  const podiumMap = usePodiumMap('ul', reigning ? reigning.season : null);
  const rPodiums = React.useMemo(() => {
    if (!reigning) return [];
    const k = rosterNorm(reigning.wdc.name);
    const hit = Object.keys(podiumMap).find((n) => rosterNorm(n) === k);
    return hit ? [...podiumMap[hit]].sort((a, b) => a.round - b.round) : [];
  }, [podiumMap, reigning]);

  return (
    <React.Fragment>
      {/* ════ EDITORIAL HERO ════ */}
      <section style={{ position: 'relative', background: '#000', overflow: 'hidden', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 16, padding: '36px 40px 36px' }}>
        <div aria-hidden style={{ position: 'absolute', inset: 0, background: `radial-gradient(120% 80% at 50% 36%, ${COLORS.red}0f 0%, transparent 55%)`, pointerEvents: 'none' }} />
        <div style={{ position: 'relative', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 14 }}>
          <URWreath size={46} color={COLORS.red} />
          <div style={{ fontFamily: 'Cormorant', fontWeight: 400, fontStyle: 'italic', fontSize: 16, letterSpacing: '0.12em', color: COLORS.textMute, textAlign: 'center', lineHeight: 1.5 }}>
            Honour &amp; Prestige · UR2D Esports
          </div>
        </div>
        <h1 style={{ position: 'relative', margin: 0, fontFamily: 'Cormorant', fontWeight: 300, fontSize: 'clamp(34px, 6vw, 104px)', letterSpacing: '0.04em', color: COLORS.text, textTransform: 'uppercase', lineHeight: 0.95, textAlign: 'center', whiteSpace: 'nowrap' }}>Hall of Champions</h1>
      </section>

      {!reigning ?
      <section style={{ background: COLORS.base, padding: '56px 40px 110px', textAlign: 'center' }}>
          <span style={{ fontFamily: 'Cormorant', fontStyle: 'italic', fontSize: 20, color: COLORS.textMute, letterSpacing: '0.08em' }}>{status === 'error' ? 'The archive could not be loaded.' : 'Opening the archive…'}</span>
        </section> :
      <React.Fragment>
      {/* ════ REIGNING CHAMPION ════ */}
      <section style={{ background: COLORS.base, padding: '32px 40px 0', position: 'relative', overflow: 'hidden' }}>
        <div aria-hidden style={{ position: 'absolute', right: -40, top: -60, fontFamily: 'Cormorant', fontWeight: 300, fontSize: 380, color: 'transparent', WebkitTextStroke: `1px ${rTeam.color}28`, letterSpacing: '-0.02em', lineHeight: 0.8, pointerEvents: 'none', textTransform: 'uppercase' }}>{reigning.season}</div>

        {/* Section label */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 20, marginBottom: 24, position: 'relative' }}>
          <div style={{ height: 1, width: 48, background: COLORS.red }} />
          <span style={{ fontFamily: 'Cormorant', fontStyle: 'italic', fontSize: 18, color: COLORS.red, letterSpacing: '0.12em' }}>Reigning Champion</span>
          <div style={{ height: 1, flex: 1, background: COLORS.hairline }} />
        </div>

        <div style={{
          position: 'relative', overflow: 'hidden',
          border: `1px solid ${rTeam.color}44`,
          background: `linear-gradient(108deg, ${rTeam.color}22 0%, ${rTeam.color}0a 40%, ${COLORS.base} 72%)`,
          padding: '36px 48px 30px', rowGap: 26,
          display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 48, flexWrap: 'wrap'
        }}>
          <div>
            {/* Season + year */}
            <div style={{ fontFamily: 'Cormorant', fontWeight: 300, fontSize: 15, letterSpacing: '0.28em', color: COLORS.textDim, textTransform: 'uppercase', marginBottom: 16 }}>{[reigning.season, reigning.year].filter(Boolean).join(' · ')}</div>
            {/* Driver name + flag */}
            <div style={{ display: 'flex', alignItems: 'center', gap: 20, marginBottom: 14 }}>
              <FlagSvg kind={reigning.wdc.country} w={44} h={29} />
              <h2 style={{ margin: 0, fontFamily: 'Cormorant', fontWeight: 300, fontSize: 'clamp(48px, 6vw, 92px)', color: COLORS.text, letterSpacing: '0.03em', lineHeight: 0.9, textTransform: 'uppercase' }}>{reigning.wdc.name}</h2>
            </div>
            {/* Team */}
            <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
              <URChampLogo short={rTeam.short} size={34} />
              <span style={{ fontFamily: 'Cormorant', fontStyle: 'italic', fontSize: 22, color: rTeam.color, letterSpacing: '0.06em' }}>{rTeam.name}</span>
            </div>
          </div>

          {/* Stats */}
          <div style={{ display: 'flex', gap: 0, borderLeft: `1px solid ${COLORS.hairline}`, paddingLeft: 48 }}>
            {[['Points', reigning.wdc.pts], ['Wins', reigning.wdc.wins], ['Constructor', rCons.short]].map(([label, val], i) =>
            <div key={label} style={{ padding: '0 36px 0 0', borderRight: i < 2 ? `1px solid ${COLORS.hairline}` : 'none', paddingRight: i < 2 ? 36 : 0, marginRight: i < 2 ? 36 : 0 }}>
                <div style={{ fontFamily: 'Cormorant', fontWeight: 300, fontSize: 13, letterSpacing: '0.26em', color: COLORS.textDim, textTransform: 'uppercase', marginBottom: 10 }}>{label}</div>
                <div style={{ display: 'flex', alignItems: 'center', gap: 12, fontFamily: 'Cormorant', fontWeight: 300, fontSize: i === 2 ? 38 : 64, color: i === 2 ? rCons.color : COLORS.text, lineHeight: 0.9, letterSpacing: i === 2 ? '0.04em' : '-0.01em' }}>{i === 2 && UR_TEAM_LOGO[rCons.short] && <URChampLogo short={rCons.short} size={44} />}{val}</div>
              </div>
            )}
          </div>
          {rPodiums.length > 0 &&
          <div style={{ flexBasis: '100%', display: 'flex', alignItems: 'center', gap: 24, flexWrap: 'wrap', borderTop: `1px solid ${COLORS.hairline}`, paddingTop: 20 }}>
              <span style={{ fontFamily: 'Cormorant', fontStyle: 'italic', fontSize: 16, color: COLORS.textMute, letterSpacing: '0.12em' }}>Podium Circuits</span>
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
                {rPodiums.map((p) => <URPodiumGlyph key={p.round} round={p.round} pos={p.pos} league="ul" seasonLabel={reigning.season} />)}
              </div>
            </div>
          }
        </div>
      </section>

      {/* ════ ROLL OF HONOUR ════ */}
      <section style={{ background: COLORS.base, padding: '80px 40px 110px', position: 'relative' }}>
        {/* Section label */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 20, marginBottom: 48 }}>
          <div style={{ height: 1, width: 48, background: COLORS.red }} />
          <span style={{ fontFamily: 'Cormorant', fontStyle: 'italic', fontSize: 18, color: COLORS.red, letterSpacing: '0.12em' }}>Roll of Honour</span>
          <div style={{ height: 1, flex: 1, background: COLORS.hairline }} />
          <span style={{ fontFamily: 'Cormorant', fontWeight: 300, fontSize: 14, color: COLORS.textDim, letterSpacing: '0.22em', textTransform: 'uppercase', whiteSpace: 'nowrap', flexShrink: 0 }}>{champs[champs.length - 1].season} — {reigning.season}</span>
        </div>

        <div style={{ border: `1px solid ${COLORS.hairline}` }}>
          {/* Table header */}
          <div style={{ display: 'grid', gridTemplateColumns: '76px 30px minmax(0,1.3fr) minmax(0,1fr) 56px 76px minmax(0,1fr)', columnGap: 20, padding: '14px 24px', borderBottom: `1px solid ${COLORS.hairline}`, background: COLORS.panel }}>
            {['Season', '', 'Driver', 'Team', 'Wins', 'Pts', 'Constructor'].map((h, i) =>
            <div key={i} style={{ fontFamily: 'Cormorant', fontWeight: 400, fontStyle: 'italic', fontSize: 14, letterSpacing: '0.12em', color: COLORS.textDim, textAlign: i === 5 ? 'right' : i === 4 ? 'center' : 'left' }}>{h}</div>
            )}
          </div>

          {/* Rows */}
          {champs.map((c, i) => {
            const team = c.wdc.team;
            const cons = c.wcc || { name: '—', color: COLORS.textDim };
            // Titles won BY THIS SEASON (champs is newest-first → count this row + every older row with the same driver)
            const _k = String(c.wdc.name || '').trim().toLowerCase();
            const titles = champs.slice(i).filter((x) => String(x.wdc.name || '').trim().toLowerCase() === _k).length;
            const isReigning = i === 0;
            return (
              <div key={c.season} style={{
                display: 'grid', gridTemplateColumns: '76px 30px minmax(0,1.3fr) minmax(0,1fr) 56px 76px minmax(0,1fr)', columnGap: 20,
                padding: '20px 24px', alignItems: 'center',
                borderBottom: i < champs.length - 1 ? `1px solid ${COLORS.hairline}` : 'none',
                background: `linear-gradient(90deg, ${team.color}28 0%, ${team.color}0c 30%, transparent 65%)`,
                position: 'relative'
              }}>
                <span style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: 2, background: team.color }} />
                {/* Season */}
                <div>
                  <div style={{ fontFamily: 'Cormorant', fontWeight: isReigning ? 600 : 300, fontSize: 26, color: isReigning ? '#FFD24A' : COLORS.text, letterSpacing: '0.02em', lineHeight: 1 }}>{c.season}</div>
                  {c.year && <div style={{ fontFamily: 'Cormorant', fontStyle: 'italic', fontSize: 13, color: COLORS.textDim, letterSpacing: '0.1em', marginTop: 2 }}>{c.year}</div>}
                </div>
                {/* Flag */}
                <div><FlagSvg kind={c.wdc.country} w={22} h={14} /></div>
                {/* Driver */}
                <div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: '4px 10px', minWidth: 0 }}>
                  <span style={{ fontFamily: 'Cormorant', fontWeight: 300, fontSize: 'clamp(20px, 2.2vw, 28px)', color: COLORS.text, letterSpacing: '0.02em', textTransform: 'uppercase', lineHeight: 1, overflowWrap: 'anywhere' }}>{c.wdc.name}</span>
                  {isReigning && <span style={{ color: '#FFD24A', fontSize: 14, lineHeight: 1 }}>★</span>}
                  {titles > 1 && <span style={{ fontFamily: 'Cormorant', fontStyle: 'italic', fontSize: 15, color: COLORS.red, letterSpacing: '0.06em', lineHeight: 1 }}>×{titles}</span>}
                </div>
                {/* Team */}
                <div style={{ display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 }}>
                  <URChampLogo short={team.short} size={26} />
                  <span style={{ fontFamily: 'Cormorant', fontStyle: 'italic', fontSize: 17, color: team.color, letterSpacing: '0.06em', lineHeight: 1.2, minWidth: 0 }}>{team.name}</span>
                </div>
                {/* Wins */}
                <div style={{ fontFamily: 'Cormorant', fontWeight: 300, fontSize: 26, color: COLORS.text, textAlign: 'center', letterSpacing: '-0.01em' }}>{c.wdc.wins}</div>
                {/* Pts */}
                <div style={{ fontFamily: 'Cormorant', fontWeight: 300, fontSize: 26, color: COLORS.text, textAlign: 'right', letterSpacing: '-0.01em' }}>{c.wdc.pts}</div>
                {/* Constructor */}
                <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <URChampLogo short={cons.short} size={26} color={cons.color} />
                  <span style={{ fontFamily: 'Cormorant', fontStyle: 'italic', fontSize: 17, color: COLORS.textMute, letterSpacing: '0.04em', lineHeight: 1.2, minWidth: 0 }}>{cons.name}</span>
                </div>
              </div>);
          })}
        </div>
      </section>
      </React.Fragment>}
    </React.Fragment>);

};

// Simple Discord-ish icon (controller-shaped, generic — not the literal mark)
function DiscordIcon({ size = 24, color = '#fff' }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" style={{ display: 'block' }}>
      <path d="M5 8 Q5 5 8 5 H16 Q19 5 19 8 V14 Q19 17 16 17 H14 L12 19 L10 17 H8 Q5 17 5 14 Z" fill={color} fillOpacity="0.15" stroke={color} strokeWidth="1.6" />
      <circle cx="9.5" cy="11" r="1.4" fill={color} />
      <circle cx="14.5" cy="11" r="1.4" fill={color} />
    </svg>);

}

// ─────────────────────────────────────────────────────────────────────────────
// NEWS PAGE — latest videos from the channel
const URNewsPage = () => {
  const videos = URL_LEAGUE.videos;
  const lead = videos[0];
  return (
    <React.Fragment>
      <URPageHeader
        kicker="◆ Watch · UR2D eSports · 2026"
        title="Latest"
        italic="videos."
        blurb="Full race broadcasts from every Sunday across the four UR2D leagues — straight from the official YouTube channel." />

      <section style={{ background: COLORS.base, padding: '20px 40px 110px' }}>
        {/* Featured video */}
        <a href={`https://www.youtube.com/watch?v=${lead.id}`} target="_blank" rel="noopener noreferrer"
          style={{ display: 'block', position: 'relative', overflow: 'hidden', border: `1px solid ${COLORS.hairline}`, marginBottom: 28, textDecoration: 'none' }}>
          <div style={{ position: 'relative', aspectRatio: '16 / 9', background: '#000' }}>
            <img src={`https://i.ytimg.com/vi/${lead.id}/hqdefault.jpg`} alt={lead.title} loading="lazy"
            style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }} />
            <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, transparent 40%, rgba(0,0,0,0.94) 100%)' }} />
            <div style={{ position: 'absolute', top: 24, left: 24, display: 'flex', gap: 10 }}>
              <span style={{ background: COLORS.red, color: '#fff', padding: '6px 12px', fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.22em', textTransform: 'uppercase' }}>▶ Watch</span>
              <span style={{ background: 'rgba(0,0,0,.55)', backdropFilter: 'blur(4px)', color: COLORS.text, padding: '6px 12px', fontFamily: 'JetBrains Mono', fontSize: 10, letterSpacing: '0.22em', textTransform: 'uppercase' }}>{lead.date}</span>
            </div>
            <div style={{ position: 'absolute', bottom: 32, left: 32, right: 32, maxWidth: 900 }}>
              <h2 style={{ margin: 0, fontFamily: 'Archivo', fontWeight: 900, fontSize: 40, color: COLORS.text, lineHeight: 1.04, letterSpacing: '-0.02em' }}>{lead.title}</h2>
            </div>
          </div>
        </a>

        {/* Video grid */}
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 24 }}>
          {videos.slice(1).map((v) => <URVideoCard key={v.id} v={v} />)}
        </div>
      </section>
    </React.Fragment>);

};

Object.assign(window, { URWreath, URStandings, URResults, URDriversEditorial, URCalendarPage, URDiscordPage, URHallOfChampions, URTrackHero, URCalendarResults, URNewsPage, UR_GP_FLAG, UR_GP_LOC3, urRaceMinimap, UR_TEAM_LOGO, getLivery, UR_TEAM_LOGO_DARK, URDriverCard, getClinchedChampion, URPodiumGlyph, UR_METAL, UR_GP_MINIMAP });