/**
 * Server injects window.__PACEMAKER__ = { races, raceExtra } (see views/pacemaker.html).
 */
const __PM = typeof window !== "undefined" && window.__PACEMAKER__ ? window.__PACEMAKER__ : {};
const RACES = Array.isArray(__PM.races) ? __PM.races : [];
const RACE_EXTRA = __PM.raceExtra && typeof __PM.raceExtra === "object" ? __PM.raceExtra : {};
const FILTERS_DIST = ["All", "5K", "10K", "Half", "Full", "Ultra"];
const GLOBAL_MAX_GAIN = 2000;
const PROFILE_MAX_H = 68;
const PROFILE_MIN_H = 5;
const TODAY = new Date();

function weeksUntil(dateStr) {
  const parts = dateStr.match(/(\d+)\s(\w+)\s(\d+)/);
  if (!parts) return null;
  const d = new Date(`${parts[2]} ${parts[1]}, ${parts[3]}`);
  if (Number.isNaN(d.getTime())) return null;
  return Math.round((d - TODAY) / (7 * 24 * 60 * 60 * 1000));
}

function planStart(weeks) {
  const d = new Date(TODAY.getTime() + (weeks - 14) * 7 * 24 * 60 * 60 * 1000);
  return d.toLocaleDateString("en-GB", { day: "numeric", month: "short" });
}

function ElevationProfile({ points, gain, width = 320 }) {
  const scaledH = Math.max(PROFILE_MIN_H, (gain / GLOBAL_MAX_GAIN) * PROFILE_MAX_H);
  const totalH = PROFILE_MAX_H + 6;
  const baselineY = totalH - 2;
  const max = Math.max(...points), range = max || 1;
  const pts = points.map((v, i) => {
    const x = (i / (points.length - 1)) * width;
    const y = baselineY - (v / range) * scaledH;
    return `${x},${y}`;
  });
  const polyline = pts.join(" ");
  const area = `${pts[0]} ${polyline} ${width},${baselineY} 0,${baselineY}`;
  const uid = `eg${gain}w${width}`;
  return (
    <div style={{ position:"relative" }}>
      <div style={{ position:"absolute", left:0, top:0, bottom:0, display:"flex", flexDirection:"column", justifyContent:"space-between", pointerEvents:"none", paddingBottom:2 }}>
        <span style={{ fontFamily:"var(--mono)", fontSize:8, color:"var(--track)", opacity:0.85, letterSpacing:"0.05em" }}>{gain}m</span>
        <span style={{ fontFamily:"var(--mono)", fontSize:8, color:"var(--mist)", opacity:0.7, letterSpacing:"0.05em" }}>0</span>
      </div>
      <svg width={width} height={totalH} viewBox={`0 0 ${width} ${totalH}`} style={{ display:"block" }}>
        <defs>
          <linearGradient id={uid} x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="var(--track)" stopOpacity="0.22" />
            <stop offset="100%" stopColor="var(--track)" stopOpacity="0.03" />
          </linearGradient>
        </defs>
        <line x1="0" y1={baselineY} x2={width} y2={baselineY} stroke="var(--rule-mid)" strokeWidth="1" />
        <polygon points={area} fill={`url(#${uid})`} />
        <polyline points={polyline} fill="none" stroke="var(--track)" strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="round" />
      </svg>
    </div>
  );
}

function DiffBar({ val, max = 10, color = "var(--track)" }) {
  return (
    <div style={{ display:"flex", gap:2 }}>
      {Array.from({ length: max }).map((_, i) => (
        <div key={i} style={{ width:11, height:3, borderRadius:1, background: i < val ? color : "var(--surface-3)" }} />
      ))}
    </div>
  );
}

function Nav({ onBack, showBack }) {
  return (
    <nav style={{ borderBottom:"1px solid var(--rule-str)", position:"sticky", top:0, zIndex:100, background:"var(--ink)" }}>
      <div style={{ maxWidth:1280, margin:"0 auto", padding:"0 32px", display:"flex", alignItems:"center", height:54, gap:24 }}>
        {showBack && (
          <button onClick={onBack} style={{ fontFamily:"var(--mono)", fontSize:10, textTransform:"uppercase", letterSpacing:"0.14em", color:"var(--mist)", display:"flex", alignItems:"center", gap:8, padding:"6px 0", borderRight:"1px solid var(--rule)", paddingRight:20, marginRight:4, flexShrink:0 }}>
            ← Back
          </button>
        )}
        <a href="#" onClick={e => { e.preventDefault(); if (onBack) onBack(); }} style={{ display:"flex", alignItems:"center", gap:9, flexShrink:0 }}>
          <svg width="20" height="20" viewBox="0 0 20 20" fill="none">
            <circle cx="10" cy="10" r="9" stroke="var(--track)" strokeWidth="1.5" />
            <circle cx="10" cy="10" r="3.5" fill="var(--track)" />
            <line x1="10" y1="1" x2="10" y2="4.5" stroke="var(--track)" strokeWidth="1.5" />
          </svg>
          <span style={{ fontFamily:"var(--mono)", fontSize:13, fontWeight:600, letterSpacing:"-0.01em", color:"var(--paper)" }}>startlist.run</span>
        </a>
        <div style={{ marginLeft:"auto" }}>
          <button style={{ fontFamily:"var(--mono)", fontSize:10, textTransform:"uppercase", letterSpacing:"0.12em", padding:"8px 16px", background:"var(--track)", color:"var(--ink)", borderRadius:2, fontWeight:700, display:"flex", alignItems:"center", gap:7 }}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M15.076 7.454c-.29.195-.643.378-1.054.537-1.11.43-2.576.684-4.022.684s-2.912-.253-4.022-.684c-.41-.16-.764-.342-1.054-.537C6.7 7.02 8.194 6.5 10 6.5s3.3.52 5.076.954zM5 12.5V9.15c.18.1.375.197.576.285 1.294.502 2.888.765 4.424.765s3.13-.263 4.424-.765c.2-.088.396-.185.576-.285V12.5c-.18.1-.375.197-.576.285-1.294.502-2.888.765-4.424.765s-3.13-.263-4.424-.765A5.5 5.5 0 0 1 5 12.5zM5 14.65c.18.1.375.197.576.285 1.294.502 2.888.765 4.424.765s3.13-.263 4.424-.765c.2-.088.396-.185.576-.285v2.85c0 .978-1.79 2-5 2s-5-1.022-5-2v-2.85z"/></svg>
            Connect Strava
          </button>
        </div>
      </div>
    </nav>
  );
}

/* ─── RACE CARD ─────────────────────────────────────────────────── */
function RaceCard({ race, onSelect }) {
  const [tracked, setTracked] = React.useState(false);
  const distLabel = race.distance >= 45 ? "Ultra" : race.distance >= 30 ? "30K+" : race.distance >= 21 ? "Half" : race.distance >= 8 ? "10K" : "5K";
  return (
    <article style={{ background:"var(--surface)", border:"1px solid var(--rule)", display:"flex", flexDirection:"column", position:"relative", transition:"background 0.15s" }}
      onMouseEnter={e => e.currentTarget.style.background = "var(--surface-2)"}
      onMouseLeave={e => e.currentTarget.style.background = "var(--surface)"}
    >
      <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center", padding:"14px 18px 0" }}>
        <div style={{ display:"flex", gap:6, alignItems:"center", flexWrap:"wrap" }}>
          <span style={{ fontFamily:"var(--mono)", fontSize:9, textTransform:"uppercase", letterSpacing:"0.14em", color:"var(--mist)" }}>{race.city_area}</span>
          <span style={{ width:3, height:3, borderRadius:"50%", background:"var(--rule-mid)", display:"inline-block" }} />
          <span style={{ fontFamily:"var(--mono)", fontSize:9, textTransform:"uppercase", letterSpacing:"0.12em", background:"var(--surface-3)", color:"var(--paper)", padding:"2px 7px", borderRadius:2 }}>{distLabel}</span>
          {race.surface === "Trail" && <span style={{ fontFamily:"var(--mono)", fontSize:9, textTransform:"uppercase", letterSpacing:"0.12em", background:"#14532d", color:"#86efac", padding:"2px 7px", borderRadius:2 }}>Trail</span>}
          {race.pbPotential >= 8 && <span style={{ fontFamily:"var(--mono)", fontSize:9, textTransform:"uppercase", letterSpacing:"0.12em", background:"var(--track)", color:"var(--ink)", padding:"2px 7px", borderRadius:2, fontWeight:600 }}>PB Course</span>}
        </div>
        <span style={{ fontFamily:"var(--mono)", fontSize:12, color:"#d97706" }}>★ {(Number(race.rating) || 0).toFixed(1)}</span>
      </div>

      <div style={{ padding:"10px 18px 0" }}>
        <h3 style={{ fontFamily:"var(--sans)", fontSize:22, fontWeight:700, lineHeight:1.06, letterSpacing:"-0.03em", color:"var(--paper)", marginBottom:5 }}>{race.name}</h3>
        <div style={{ fontFamily:"var(--mono)", fontSize:10, color:"var(--mist)", textTransform:"uppercase", letterSpacing:"0.1em" }}>{race.date} · {race.time}</div>
      </div>

      <div style={{ padding:"14px 18px 0" }}>
        <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center", marginBottom:6 }}>
          <span style={{ fontFamily:"var(--mono)", fontSize:9, textTransform:"uppercase", letterSpacing:"0.14em", color:"var(--mist)" }}>Elevation profile</span>
          <div style={{ display:"flex", gap:10 }}>
            <span style={{ fontFamily:"var(--mono)", fontSize:10, color:"var(--track)", fontWeight:600 }}>↑ {race.elevGain}m</span>
            <span style={{ fontFamily:"var(--mono)", fontSize:10, color:"var(--mist)" }}>{race.terrain}</span>
          </div>
        </div>
        <div style={{ background:"var(--surface-3)", padding:"6px 0 0", borderRadius:2 }}>
          <ElevationProfile points={race.elevProfile} gain={race.elevGain} width={316} />
          <div style={{ display:"flex", justifyContent:"space-between", padding:"2px 0 5px", fontFamily:"var(--mono)", fontSize:8, color:"var(--mist)", textTransform:"uppercase" }}>
            <span>0km</span><span>{(race.distance/2).toFixed(0)}km</span><span>{race.distance}km</span>
          </div>
        </div>
      </div>

      <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr 1fr", margin:"14px 18px 0", border:"1px solid var(--rule)", borderRadius:2 }}>
        {[
          { label:"Difficulty", val:race.difficulty, bar:true, color: race.difficulty > 7 ? "#ef4444" : race.difficulty > 4 ? "#f59e0b" : "#4ade80" },
          { label:"PB potential", val:race.pbPotential, bar:true, color:"var(--track)" },
          { label:"Reviews", val:(Number(race.reviews) || 0).toLocaleString(), bar:false },
        ].map((s, i) => (
          <div key={i} style={{ padding:"10px 12px", borderRight: i < 2 ? "1px solid var(--rule)" : "none" }}>
            <div style={{ fontFamily:"var(--mono)", fontSize:8, textTransform:"uppercase", letterSpacing:"0.14em", color:"var(--mist)", marginBottom:5 }}>{s.label}</div>
            {s.bar ? (<>
              <div style={{ fontFamily:"var(--mono)", fontSize:15, fontWeight:600, color:s.color, marginBottom:5 }}>{s.val}<span style={{ fontSize:9, color:"var(--mist)", fontWeight:400 }}>/10</span></div>
              <DiffBar val={s.val} color={s.color} />
            </>) : (
              <div>
                <div style={{ fontFamily:"var(--mono)", fontSize:15, fontWeight:600, color:"var(--paper)" }}>{s.val}</div>
                <div style={{ fontFamily:"var(--mono)", fontSize:8, color:"var(--mist)", marginTop:2 }}>★{(Number(race.rating) || 0).toFixed(1)} avg</div>
              </div>
            )}
          </div>
        ))}
      </div>

      <div style={{ display:"flex", gap:16, padding:"10px 18px", borderTop:"1px solid var(--rule)", marginTop:12 }}>
        <div>
          <div style={{ fontFamily:"var(--mono)", fontSize:8, textTransform:"uppercase", letterSpacing:"0.14em", color:"var(--mist)" }}>Avg finish ({race.avgFinish.label})</div>
          <div style={{ fontFamily:"var(--mono)", fontSize:14, fontWeight:600, color:"var(--paper)", marginTop:2 }}>{race.avgFinish.time}</div>
        </div>
        <div style={{ width:1, background:"var(--rule)" }} />
        <div>
          <div style={{ fontFamily:"var(--mono)", fontSize:8, textTransform:"uppercase", letterSpacing:"0.14em", color:"var(--mist)" }}>Tracking</div>
          <div style={{ fontFamily:"var(--mono)", fontSize:14, fontWeight:600, color:"var(--track)", marginTop:2 }}>{race.tracking.toLocaleString()}</div>
        </div>
        <div style={{ marginLeft:"auto", display:"flex", alignItems:"center" }}>
          {race.chipTimed && <span style={{ fontFamily:"var(--mono)", fontSize:9, color:"#4ade80", display:"flex", gap:5, alignItems:"center", textTransform:"uppercase", letterSpacing:"0.1em" }}><span style={{ width:6, height:6, borderRadius:"50%", background:"#4ade80", display:"inline-block" }} />Chip</span>}
        </div>
      </div>

      <div style={{ padding:"0 18px", display:"flex", gap:5, flexWrap:"wrap" }}>
        {race.tags.map(t => <span key={t} style={{ fontFamily:"var(--mono)", fontSize:8, textTransform:"uppercase", letterSpacing:"0.1em", padding:"3px 7px", border:"1px solid var(--rule-mid)", borderRadius:2, color:"var(--mist)" }}>{t}</span>)}
      </div>

      <div style={{ display:"flex", gap:8, padding:"12px 18px 14px", marginTop:"auto" }}>
        <button onClick={() => setTracked(t => !t)} style={{ fontFamily:"var(--mono)", fontSize:9, textTransform:"uppercase", letterSpacing:"0.12em", padding:"9px 14px", borderRadius:2, border: tracked ? "1.5px solid var(--track)" : "1.5px solid var(--rule-str)", background: tracked ? "var(--track)" : "transparent", color: tracked ? "var(--ink)" : "var(--paper)", fontWeight: tracked ? 700 : 400, transition:"all 0.15s", flexShrink:0 }}>
          {tracked ? "✓ Tracking" : "+ Track"}
        </button>
        <button onClick={() => onSelect(race)} style={{ fontFamily:"var(--mono)", fontSize:10, textTransform:"uppercase", letterSpacing:"0.12em", padding:"9px 18px", background:"var(--track)", color:"var(--ink)", borderRadius:2, flexGrow:1, fontWeight:700, transition:"opacity 0.15s" }}
          onMouseEnter={e => e.currentTarget.style.opacity="0.85"} onMouseLeave={e => e.currentTarget.style.opacity="1"}>
          More Info →
        </button>
      </div>
    </article>
  );
}

/* ─── FILTER BAR ─────────────────────────────────────────────────── */
function FilterBar({ cities, city, setCity, distFilter, setDistFilter, sortBy, setSortBy }) {
  return (
    <div style={{ borderTop:"1px solid var(--rule-str)", borderBottom:"1px solid var(--rule)", background:"var(--surface)" }}>
      {/* Row 1: City + Distance */}
      <div style={{ display:"flex", alignItems:"stretch", borderBottom:"1px solid var(--rule)" }}>
        <span style={{ fontFamily:"var(--mono)", fontSize:9, textTransform:"uppercase", letterSpacing:"0.14em", color:"var(--mist)", display:"flex", alignItems:"center", padding:"0 14px", borderRight:"1px solid var(--rule)", whiteSpace:"nowrap" }}>Region</span>
        {cities.map(c => (
          <button key={c} onClick={() => setCity(c)} style={{ padding:"11px 18px", fontFamily:"var(--mono)", fontSize:10, textTransform:"uppercase", letterSpacing:"0.14em", borderRight:"1px solid var(--rule)", color: city === c ? "var(--track)" : "var(--mist)", fontWeight: city === c ? 600 : 400, borderBottom: city === c ? "2px solid var(--track)" : "2px solid transparent", background:"none", transition:"all 0.12s", whiteSpace:"nowrap" }}>{c}</button>
        ))}
        <div style={{ marginLeft:"auto", display:"flex", alignItems:"stretch" }}>
          <span style={{ fontFamily:"var(--mono)", fontSize:9, textTransform:"uppercase", letterSpacing:"0.14em", color:"var(--mist)", display:"flex", alignItems:"center", padding:"0 14px", borderLeft:"1px solid var(--rule)" }}>Sort</span>
          {["Date","Rating","Elevation","Price"].map(s => (
            <button key={s} onClick={() => setSortBy(s)} style={{ padding:"11px 14px", fontFamily:"var(--mono)", fontSize:9, textTransform:"uppercase", letterSpacing:"0.1em", borderLeft:"1px solid var(--rule)", color: sortBy === s ? "var(--paper)" : "var(--mist)", fontWeight: sortBy === s ? 600 : 400, borderBottom: sortBy === s ? "2px solid var(--paper)" : "2px solid transparent", background:"none", transition:"all 0.12s" }}>{s}</button>
          ))}
        </div>
      </div>
      {/* Row 2: Distance */}
      <div style={{ display:"flex", alignItems:"stretch" }}>
        <span style={{ fontFamily:"var(--mono)", fontSize:9, textTransform:"uppercase", letterSpacing:"0.14em", color:"var(--mist)", display:"flex", alignItems:"center", padding:"0 14px", borderRight:"1px solid var(--rule)", whiteSpace:"nowrap" }}>Distance</span>
        {FILTERS_DIST.map(f => (
          <button key={f} onClick={() => setDistFilter(f)} style={{ padding:"10px 16px", fontFamily:"var(--mono)", fontSize:10, textTransform:"uppercase", letterSpacing:"0.14em", borderRight:"1px solid var(--rule)", color: distFilter === f ? "var(--track)" : "var(--mist)", fontWeight: distFilter === f ? 600 : 400, borderBottom: distFilter === f ? "2px solid var(--track)" : "2px solid transparent", background:"none", transition:"all 0.12s" }}>{f}</button>
        ))}
      </div>
    </div>
  );
}

/* ─── RACE DETAIL PAGE ──────────────────────────────────────────── */
function RaceDetailPage({ race, onBack }) {
  const [tracked, setTracked] = React.useState(false);
  const [search, setSearch] = React.useState("");
  const [expandAll, setExpandAll] = React.useState(false);
  const detailsRef = React.useRef([]);

  const capN = Math.max(0, Number(race.cap) || 0);
  const enteredN = Math.max(0, Number(race.entered) || 0);
  const placesLeftN = Math.max(0, capN - enteredN);
  const orgHandle = String(race.organizer || "organiser")
    .replace(/\s/g, "")
    .toLowerCase();

  // Elevation SVG
  const rawPts = race.elevProfile;
  const pts =
    Array.isArray(rawPts) && rawPts.length > 1 ? rawPts : [0, Math.max(0, Number(race.elevGain) || 0)];
  const maxElev = Math.max(...pts);
  const svgW = 600, svgH = 68;
  const coords = pts.map((v, i) => ({
    x: (i / (pts.length - 1)) * svgW,
    y: svgH - (v / (maxElev || 1)) * (svgH - 8) - 2,
  }));
  const polylineStr = coords.map(c => `${c.x},${c.y}`).join(" ");
  const areaPath = `M 0,${svgH} L ${coords.map(c=>`${c.x},${c.y}`).join(" L ")} L ${svgW},${svgH} Z`;
  const peakIdx = pts.indexOf(maxElev);
  const peakKm = ((peakIdx / (pts.length - 1)) * race.distance).toFixed(0);
  const peakX = coords[peakIdx]?.x ?? 0;
  const peakY = coords[peakIdx]?.y ?? 0;

  // Smart links
  const mapsUrl = `https://www.google.com/maps/search/${encodeURIComponent(race.logistics.hq)}`;
  const trainlineUrl = `https://www.trainline.com/search/${encodeURIComponent(race.logistics.station?.split("—")[0]?.trim() ?? "")}`;
  const windyUrl = `https://www.windy.com/?${encodeURIComponent(race.logistics.hq)}`;
  const calDate = race.date.replace(/Sun |Sat |Mon /,"").replace(" ","").replace(" ","-");

  // Calendar link (Google Calendar)
  function calUrl() {
    const d = new Date(`${race.date.replace(/^(Sun|Sat|Mon|Tue|Wed|Thu|Fri) /,"")} ${race.time}`);
    const pad = n => String(n).padStart(2,"0");
    const fmt = d => `${d.getFullYear()}${pad(d.getMonth()+1)}${pad(d.getDate())}T${pad(d.getHours())}${pad(d.getMinutes())}00`;
    const end = new Date(d.getTime() + (race.distance >= 40 ? 8 : race.distance >= 21 ? 3 : 2) * 3600000);
    return `https://calendar.google.com/calendar/render?action=TEMPLATE&text=${encodeURIComponent(race.name)}&dates=${fmt(d)}/${fmt(end)}&details=${encodeURIComponent(`startlist.run race brief`)}&location=${encodeURIComponent(race.logistics.hq)}`;
  }

  // Search filtering
  const handleSearch = (e) => setSearch(e.target.value.toLowerCase());
  const handleExpand = () => {
    const next = !expandAll;
    setExpandAll(next);
    detailsRef.current.forEach(el => { if (el) el.open = next; });
  };

  const weeks = weeksUntil(race.date);
  const extra = RACE_EXTRA[race.id];
  const baseWeeks = weeks ? Math.max(0, weeks - 14) : 0;
  const pct = weeks ? Math.max(0, Math.min(100, ((52 - weeks) / 52) * 100)) : 0;

  // Helper: section icon SVGs
  const Icon = ({ d }) => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" width="15" height="15" strokeWidth="1.5">
      <path d={d} />
    </svg>
  );

  // Helper: linked row value
  const L = ({ href, children }) => <a href={href} target="_blank" rel="noopener" className="dp-link">{children} ↗</a>;

  // Accordion section
  const Sec = ({ icon, title, summary, children, warn: isWarn, idx }) => (
    <details className="dp-acc" ref={el => detailsRef.current[idx] = el}>
      <summary>
        <div className={`dp-acc-icon${isWarn ? " warn-icon" : ""}`} style={isWarn ? { background:"rgba(255,61,0,0.08)", color:"#ff8056", borderColor:"rgba(255,61,0,0.2)" } : {}}>
          {icon}
        </div>
        <div className="dp-acc-text">
          <div className="dp-acc-h" style={isWarn ? { color:"#ff8056" } : {}}>{title}</div>
          {summary && <div className="dp-acc-sub">{summary}</div>}
        </div>
        <span className="dp-chev">▾</span>
      </summary>
      <div className="dp-content">{children}</div>
    </details>
  );

  const Row = ({ label, val, link }) => (
    <div className="dp-row">
      <span>{label}</span>
      <span className="dp-val">{link ? <L href={link}>{val}</L> : val}</span>
    </div>
  );

  return (
    <div style={{ minHeight:"100vh", background:"#050505" }}>
      <Nav showBack={true} onBack={onBack} />

      {/* Sticky bottom CTA */}
      <div style={{ position:"fixed", bottom:0, left:0, right:0, zIndex:50, background:"var(--surface-2)", borderTop:"1px solid var(--rule-str)", padding:"12px 32px", display:"flex", justifyContent:"space-between", alignItems:"center", gap:20 }}>
        <div style={{ fontFamily:"var(--mono)", fontSize:12, color:"var(--mist)" }}>
          <span style={{ color:"var(--paper)", fontWeight:600 }}>{enteredN.toLocaleString()} / {capN.toLocaleString()}</span> entered
        </div>
        <div style={{ display:"flex", gap:8 }}>
          <button onClick={() => setTracked(t => !t)} className="dp-btn dp-btn-secondary" style={{ border: tracked ? "1px solid var(--track)" : undefined, color: tracked ? "var(--track)" : undefined }}>
            {tracked ? "✓ Tracking" : "★ Track"}
          </button>
          <button className="dp-btn dp-btn-primary">Enter — £{race.price}</button>
        </div>
      </div>

      {/* Page body */}
      <div style={{ padding:"32px 16px 120px", display:"flex", justifyContent:"center" }}>
        <div className="dp-wrap">

          {/* Hero */}
          <div className="dp-hero">
            <div className="dp-crumbs">Race / {race.surface} · {race.city_area}</div>
            <h1 className="dp-h1">{race.name}</h1>
            <div className="dp-subhead">
              <a href={calUrl()} target="_blank" rel="noopener" className="dp-link">{race.date} · {race.time} start</a>
              {" · "}{race.edition} edition · {race.organizer}
              {weeks && <span style={{ marginLeft:8, fontFamily:"var(--mono)", fontSize:11, color:"var(--track)" }}>· {weeks} weeks away</span>}
            </div>
            <div className="dp-pills">
              <span className="dp-tag hot">★ {(Number(race.rating) || 0).toFixed(1)} from {(Number(race.reviews) || 0).toLocaleString()} finishers</span>
              {race.chipTimed && <span className="dp-tag">Chip-timed</span>}
              {race.pbPotential >= 8 && <span className="dp-tag hot">PB Course</span>}
              {race.difficulty >= 9 && <span className="dp-tag warn">Tough — plan ahead</span>}
              <span className="dp-tag">{placesLeftN.toLocaleString()} places left</span>
            </div>
            <div className="dp-cta-row">
              <button className="dp-btn dp-btn-primary">Enter — £{race.price}</button>
              <button className="dp-btn dp-btn-secondary" onClick={() => setTracked(t => !t)} style={{ borderColor: tracked ? "var(--track)" : undefined, color: tracked ? "var(--track)" : undefined }}>{tracked ? "✓ Tracking" : "★ Track"}</button>
              <button className="dp-btn dp-btn-secondary">↓ GPX</button>
              <button className="dp-btn dp-btn-secondary">Share</button>
            </div>
          </div>

          {/* Key stats */}
          <div className="dp-keystats">
            <div><div className="dp-sn">{race.distance}<small> km</small></div><div className="dp-sl">Distance</div></div>
            <div><div className="dp-sn">{race.elevGain}<small> m</small></div><div className="dp-sl">Elevation</div></div>
            <div><div className="dp-sn">{race.difficulty}<small> /10</small></div><div className="dp-sl">Difficulty</div></div>
            <div><div className="dp-sn">{race.pbPotential}<small> /10</small></div><div className="dp-sl">PB potential</div></div>
          </div>

          {/* Your fit — Strava teaser */}
          <div className="dp-fit">
            <div className="dp-fit-h">Your fit · connect Strava to unlock</div>
            <div className="dp-fit-grid" style={{ opacity:0.35, filter:"blur(4px)", userSelect:"none" }}>
              <div><div className="dp-fit-num">–:––</div><div className="dp-fit-lbl">Predicted finish</div></div>
              <div><div className="dp-fit-num">Top –%</div><div className="dp-fit-lbl">Likely placement</div></div>
              <div><div className="dp-fit-num">+– min</div><div className="dp-fit-lbl">vs. road PB</div></div>
            </div>
            <div className="dp-fit-callout">
              Connect Strava to see your predicted finish, likely placement, and a personalised training plan starting <strong>{weeks && weeks > 14 ? planStart(weeks) : "now"}</strong>.
              {" "}<button className="dp-btn dp-btn-primary" style={{ fontSize:11, padding:"6px 12px", display:"inline-block", marginTop:8 }}>Connect Strava →</button>
            </div>
          </div>

          {/* Search + expand */}
          <div className="dp-search">
            <input type="text" placeholder="Search — toilets, parking, gels, refunds…" value={search} onChange={handleSearch} />
            <button className="dp-search-toggle" onClick={handleExpand}>{expandAll ? "Collapse all ▴" : "Expand all ▾"}</button>
          </div>

          {/* ── ACCORDIONS ── */}

          {/* 1. The course */}
          <Sec idx={0}
            icon={<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" width="15" height="15"><path d="M3 6l6-3 6 3 6-3v15l-6 3-6-3-6 3V6z"/><path d="M9 3v15"/><path d="M15 6v15"/></svg>}
            title="The course"
            summary={`${race.distance}km · ↑${race.elevGain}m · ${race.terrain} · ${race.surfaceMix.map(s=>s.label+" "+s.pct+"%").join(" / ")}`}
          >
            <svg viewBox={`0 0 ${svgW} ${svgH}`} className="dp-elev" role="img">
              <defs>
                <linearGradient id="dpg" x1="0" y1="0" x2="0" y2="1">
                  <stop offset="0%" stopColor="var(--track)" stopOpacity="0.2" />
                  <stop offset="100%" stopColor="var(--track)" stopOpacity="0.02" />
                </linearGradient>
              </defs>
              <path d={areaPath} fill="url(#dpg)" />
              <polyline points={polylineStr} fill="none" stroke="var(--track)" strokeWidth="1.5" strokeLinejoin="round" />
              {maxElev > 0 && <>
                <circle cx={peakX} cy={peakY} r="3" fill="var(--track)" />
                <text x={Math.min(peakX, svgW - 130)} y={Math.max(peakY - 6, 10)} fontSize="8" fill="var(--track)" fontFamily="var(--mono)" letterSpacing="0.1em">PEAK · KM {peakKm} · {maxElev}M</text>
              </>}
            </svg>
            <div className="dp-bar-stack">
              {race.surfaceMix.map(s => <span key={s.label} style={{ width:`${s.pct}%`, background:s.color }} />)}
            </div>
            <div className="dp-bar-labels">
              {race.surfaceMix.map(s => <span key={s.label}>{s.label} {s.pct}%</span>)}
            </div>
            <Row label="Distance" val={`${race.distance} km`} />
            <Row label="Elevation gain" val={`${race.elevGain}m`} />
            <Row label="Terrain" val={race.terrain} />
            <Row label="Difficulty" val={`${race.difficulty}/10 — ${race.difficulty >= 9 ? "Extreme" : race.difficulty >= 7 ? "Hard" : race.difficulty >= 5 ? "Moderate" : "Accessible"}`} />
            <Row label="PB potential" val={`${race.pbPotential}/10 — ${race.pbPotential >= 8 ? "Excellent flat PB course" : race.pbPotential >= 5 ? "Moderate" : "Trail PB likely, not road"}`} />
          </Sec>

          {/* 2. Getting there */}
          <Sec idx={1}
            icon={<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" width="15" height="15"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z"/><circle cx="12" cy="10" r="3"/></svg>}
            title="Getting there"
            summary={`${race.logistics.station} · ${race.logistics.parking}`}
          >
            <Row label="Race HQ" val={race.logistics.hq} link={mapsUrl} />
            <Row label="Start line" val={race.logistics.startWalk} />
            <div className="dp-row">
              <span>Nearest station</span>
              <span className="dp-val"><L href={trainlineUrl}>{race.logistics.station}</L></span>
            </div>
            {race.logistics.shuttle && <Row label="Race-day shuttle" val={race.logistics.shuttle} />}
            <Row label="Parking" val={race.logistics.parking} />
            <Row label="Bag drop" val={race.logistics.bagDrop} />
            <Row label="Number collection" val={race.logistics.numberCollection} />
            <Row label="Toilets" val={race.logistics.toilets} />
            <div className="dp-callout">
              <strong>Add to calendar:</strong>{" "}
              <a href={calUrl()} target="_blank" rel="noopener" className="dp-link">Add {race.name} to Google Calendar ↗</a>
            </div>
          </Sec>

          {/* 3. Race morning */}
          <Sec idx={2}
            icon={<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" width="15" height="15"><path d="M17 18a5 5 0 00-10 0"/><line x1="12" y1="2" x2="12" y2="9"/><line x1="4.22" y1="10.22" x2="5.64" y2="11.64"/><line x1="1" y1="18" x2="3" y2="18"/><line x1="21" y1="18" x2="23" y2="18"/><line x1="18.36" y1="11.64" x2="19.78" y2="10.22"/></svg>}
            title="Race morning"
            summary={`Number pickup · bag drop · ${race.weather.temp} avg · check official socials for live updates`}
          >
            <Row label="Number collection" val={race.logistics.numberCollection} />
            <Row label="Bag drop" val={race.logistics.bagDrop} />
            <Row label="Toilets at HQ" val={race.logistics.toilets} />
            <div className="dp-row">
              <span>Weather (10-yr avg)</span>
              <span className="dp-val"><L href={`https://www.windy.com/?${encodeURIComponent(race.logistics.hq)}`}>{race.weather.temp} · {race.weather.rain} rain · {race.weather.wind}</L></span>
            </div>
            <Row label="Headphones" val={race.onCourse.headphones} />
            <div className="dp-callout">
              <strong>Race morning updates:</strong> Follow{" "}
              <a href={`https://twitter.com/search?q=${encodeURIComponent(race.name)}`} target="_blank" rel="noopener" className="dp-link">@{orgHandle} on X/Twitter ↗</a>{" "}
              and{" "}
              <a href={`https://www.instagram.com/${orgHandle}/`} target="_blank" rel="noopener" className="dp-link">Instagram ↗</a>{" "}
              for live start-line updates, road closures and last-minute kit requirements.
            </div>
          </Sec>

          {/* 4. On the course */}
          <Sec idx={3}
            icon={<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" width="15" height="15"><path d="M8 3L4 9h4l-3 5h4l-2 4h7l-2-4h4l-3-5h4l-4-6"/></svg>}
            title="On the course"
            summary={`${race.onCourse.aidStations} · Pacers: ${race.onCourse.pacers} · Cut-off: ${race.onCourse.cutoff}`}
          >
            <Row label="Aid stations" val={race.onCourse.aidStations} />
            <Row label="Water" val={race.onCourse.water} />
            <div className="dp-row">
              <span>Nutrition</span>
              <span className="dp-val">
                <a href="https://www.amazon.co.uk/s?tag=startlist-21&k=running+gels" target="_blank" rel="noopener" className="dp-link">{race.onCourse.nutrition}</a>
              </span>
            </div>
            <Row label="Pacers" val={race.onCourse.pacers} />
            <Row label="Cut-off" val={race.onCourse.cutoff} />
          </Sec>

          {/* 5. Field & history */}
          <Sec idx={4}
            icon={<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" width="15" height="15"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>}
            title="Field & edition history"
            summary={`Cap ${capN.toLocaleString()} · ${enteredN.toLocaleString()} entered · median ${race.median}`}
          >
            {extra && (
              <>
                <div style={{ display:"grid", gridTemplateColumns:"repeat(3,1fr)", gap:1, background:"var(--rule)", borderRadius:4, overflow:"hidden", marginBottom:14 }}>
                  <div style={{ background:"var(--surface)", padding:"11px 13px" }}><div className="dp-sn">{capN.toLocaleString()}</div><div className="dp-sl">Cap</div></div>
                  <div style={{ background:"var(--surface)", padding:"11px 13px" }}><div className="dp-sn">{enteredN.toLocaleString()}</div><div className="dp-sl">Entered</div></div>
                  <div style={{ background:"var(--surface)", padding:"11px 13px" }}><div className="dp-sn">{race.dnfRate}</div><div className="dp-sl">DNF avg</div></div>
                </div>
                <div style={{ overflowX:"auto" }}>
                  <table style={{ width:"100%", borderCollapse:"collapse", fontSize:12, fontFamily:"var(--mono)" }}>
                    <thead>
                      <tr>{["Year","Entered","Finished","DNF %","Median","Cut-off"].map(h => (
                        <th key={h} style={{ textAlign: h==="Year"?"left":"right", padding:"7px 5px 9px", fontSize:9, letterSpacing:"0.12em", textTransform:"uppercase", color:"rgba(244,241,234,0.4)", fontWeight:500, borderBottom:"0.5px solid rgba(244,241,234,0.16)" }}>{h}</th>
                      ))}</tr>
                    </thead>
                    <tbody>
                      {extra.history.map((row, i) => row.cancelled ? (
                        <tr key={i}><td style={{ padding:"8px 5px", color:"rgba(244,241,234,0.45)", borderBottom:"0.5px solid rgba(244,241,234,0.05)", fontSize:11 }}>{row.year} <span style={{ fontSize:9, padding:"1px 6px", borderRadius:99, background:"rgba(244,241,234,0.07)", marginLeft:4, textTransform:"uppercase" }}>{row.cancelled}</span></td><td colSpan={5} style={{ color:"rgba(244,241,234,0.35)", padding:"8px 5px", borderBottom:"0.5px solid rgba(244,241,234,0.05)", fontSize:11 }}>Did not run</td></tr>
                      ) : (
                        <tr key={i} style={{ background: row.pill ? "rgba(212,255,0,0.04)" : "transparent" }}>
                          <td style={{ padding:"8px 5px", borderBottom:"0.5px solid rgba(244,241,234,0.05)", fontWeight:600, color: row.pill ? "var(--track)" : "var(--paper)", whiteSpace:"nowrap" }}>
                            {row.year}{row.pill && <span style={{ fontSize:9, padding:"1px 6px", borderRadius:99, background:"rgba(212,255,0,0.15)", color:"var(--track)", marginLeft:5, textTransform:"uppercase" }}>{row.pill}</span>}
                          </td>
                          <td style={{ textAlign:"right", padding:"8px 5px", borderBottom:"0.5px solid rgba(244,241,234,0.05)", color: row.pill ? "var(--track)" : "var(--mist)" }}>{row.entered}{row.cap ? <span style={{ opacity:0.5 }}> /{row.cap}</span> : ""}</td>
                          <td style={{ textAlign:"right", padding:"8px 5px", borderBottom:"0.5px solid rgba(244,241,234,0.05)", color: row.pill ? "var(--track)" : "var(--mist)" }}>{row.finished || "—"}</td>
                          <td style={{ textAlign:"right", padding:"8px 5px", borderBottom:"0.5px solid rgba(244,241,234,0.05)", color: row.pill ? "var(--track)" : row.dnf ? (row.dnf.cls==="up"?"#f87171":"#4ade80") : "var(--mist)" }}>{row.dnf ? row.dnf.v : "—"}</td>
                          <td style={{ textAlign:"right", padding:"8px 5px", borderBottom:"0.5px solid rgba(244,241,234,0.05)", color: row.pill ? "var(--track)" : "var(--mist)" }}>{row.median || "—"}</td>
                          <td style={{ textAlign:"right", padding:"8px 5px", borderBottom:"0.5px solid rgba(244,241,234,0.05)", color: row.pill ? "var(--track)" : "var(--mist)" }}>{row.cutoff}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
                <div className="dp-callout" style={{ marginTop:12 }}><strong>Reading this:</strong> {extra.callout}</div>
              </>
            )}
          </Sec>

          {/* 6. What's included */}
          <Sec idx={5}
            icon={<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" width="15" height="15"><path d="M7.21 15L2.66 7.14a2 2 0 010-2.04L4.5 1.5h15l1.84 3.6a2 2 0 010 2.04L16.79 15"/><circle cx="12" cy="17" r="5"/></svg>}
            title="What's included"
            summary={`${race.extras.medal} · ${race.extras.tshirt} · ${race.extras.postFood}`}
          >
            <Row label="Medal" val={race.extras.medal} />
            <Row label="T-shirt" val={race.extras.tshirt} />
            <Row label="Post-race food" val={race.extras.postFood} />
            <Row label="Photos" val={race.extras.photos} />
            <Row label="Live tracking" val={race.extras.liveTracking} />
            <div className="dp-callout">
              <strong>Nutrition on Amazon:</strong>{" "}
              <a href="https://www.amazon.co.uk/s?tag=startlist-21&k=running+gels+energy" target="_blank" rel="noopener" className="dp-link">Browse race-day gels & nutrition ↗</a>
              {" · "}
              <a href="https://www.amazon.co.uk/s?tag=startlist-21&k=trail+running+shoes" target="_blank" rel="noopener" className="dp-link">Trail shoes ↗</a>
              {" · "}
              <a href="https://www.amazon.co.uk/s?tag=startlist-21&k=running+vest+hydration" target="_blank" rel="noopener" className="dp-link">Hydration vests ↗</a>
              <div style={{ marginTop:5, fontSize:11, color:"rgba(244,241,234,0.4)" }}>Affiliate links · startlist.run earns a small commission at no cost to you.</div>
            </div>
          </Sec>

          {/* 7. Pricing */}
          <Sec idx={6}
            icon={<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" width="15" height="15"><path d="M20.59 13.41l-7.17 7.17a2 2 0 01-2.83 0L2 12V2h10l8.59 8.59a2 2 0 010 2.82z"/><line x1="7" y1="7" x2="7.01" y2="7"/></svg>}
            title="Pricing & entry"
            summary={`From £${race.pricing.find(p=>p.current)?.price ?? race.price} now · defer free · transfer £5`}
          >
            {race.pricing.map((p, i) => (
              <div key={i} className="dp-row" style={p.current ? { background:"rgba(212,255,0,0.06)", margin:"0 -11px", padding:"8px 11px" } : {}}>
                <span style={{ color: p.current ? "var(--track)" : undefined, fontWeight: p.current ? 600 : 400 }}>{p.label} <span style={{ fontWeight:400, color:"var(--mist)", fontSize:11 }}>{p.when}</span></span>
                <span className="dp-val" style={{ color: p.crossed ? "rgba(244,241,234,0.3)" : p.current ? "var(--paper)" : undefined, textDecoration: p.crossed ? "line-through" : "none", fontFamily:"var(--mono)", fontWeight: p.current ? 700 : 400 }}>{p.price}</span>
              </div>
            ))}
            <Row label="Refund" val="No cash refund after entry" />
            <Row label="Defer" val="Free to next year · request before race" />
            <Row label="Transfer" val="£5 admin · runner-to-runner" />
            <div className="dp-warn"><strong>Worth knowing:</strong> most organisers offer no cash refund. Optional insurance (often ~£3–5 at checkout) is the only route to a refund and requires medical evidence. Read the small print before paying.</div>
          </Sec>

          {/* 8. Countdown */}
          {weeks && weeks > 0 && (
            <Sec idx={7}
              icon={<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" width="15" height="15"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>}
              title="Countdown & training"
              summary={`${weeks} weeks to race day · ${baseWeeks > 0 ? `start plan ~${planStart(weeks)}` : "start training now"}`}
            >
              <div style={{ display:"grid", gridTemplateColumns:"auto 1fr", gap:16, alignItems:"center", marginBottom:14 }}>
                <div>
                  <div style={{ fontFamily:"var(--serif)", fontSize:52, fontWeight:300, letterSpacing:"-0.04em", lineHeight:1, color:"var(--track)", fontStyle:"italic" }}>{weeks}</div>
                  <div style={{ fontFamily:"var(--mono)", fontSize:9, color:"var(--mist)", textTransform:"uppercase", letterSpacing:"0.1em", marginTop:4 }}>weeks · {race.date}</div>
                </div>
                <div className="dp-callout">
                  Typical plan: <strong>14 weeks</strong> for a {race.distance >= 40 ? "marathon/ultra" : race.distance >= 21 ? "half" : "10K"}.{" "}
                  {baseWeeks > 0 ? <>You have <strong>{baseWeeks} weeks</strong> of base-build runway. <strong>Start plan ~{planStart(weeks)}</strong>.</> : "Start training now."}
                </div>
              </div>
              <div style={{ height:4, background:"rgba(244,241,234,0.08)", borderRadius:2, position:"relative", margin:"4px 0 8px" }}>
                <div style={{ position:"absolute", left:0, top:0, bottom:0, background:"rgba(244,241,234,0.18)", borderRadius:2, width:`${pct}%` }} />
                <div style={{ position:"absolute", top:-4, left:`${pct}%`, width:12, height:12, borderRadius:"50%", background:"var(--track)", border:"2px solid var(--ink)", transform:"translateX(-50%)" }} />
              </div>
              <div style={{ display:"flex", justifyContent:"space-between", fontFamily:"var(--mono)", fontSize:9, color:"rgba(244,241,234,0.4)", textTransform:"uppercase", letterSpacing:"0.1em" }}>
                <span>Today · {weeks} wks out</span><span>Plan starts</span><span>Race day</span>
              </div>
            </Sec>
          )}

          {/* 9. Organiser */}
          {extra && (
            <Sec idx={8}
              icon={<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" width="15" height="15"><path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 00-3-3.87"/><path d="M16 3.13a4 4 0 010 7.75"/></svg>}
              title="Organised by"
              summary={`${extra.org.name} · ${extra.org.races} races/yr · ${extra.org.rating}★`}
            >
              <div style={{ display:"grid", gridTemplateColumns:"52px 1fr", gap:13, alignItems:"start", marginBottom:14 }}>
                <div style={{ width:52, height:52, borderRadius:8, background:"linear-gradient(135deg,#2c2c2a,#444441)", display:"flex", alignItems:"center", justifyContent:"center", fontSize:16, fontWeight:700, color:"var(--track)", fontFamily:"var(--mono)" }}>{extra.org.initials}</div>
                <div>
                  <div style={{ fontSize:16, fontWeight:700, letterSpacing:"-0.02em", marginBottom:4 }}>{extra.org.name}</div>
                  <div style={{ fontSize:12, color:"rgba(244,241,234,0.6)", lineHeight:1.55 }}>{extra.org.bio}</div>
                  <div style={{ display:"flex", gap:16, marginTop:9, flexWrap:"wrap" }}>
                    {[{v:extra.org.races,l:"races/yr"},{v:`${extra.org.rating}★`,l:"avg rating"},{v:extra.org.finishers.toLocaleString(),l:"finishers/yr"},{v:extra.org.founded,l:"founded"}].map(s=>(
                      <div key={s.l} style={{ display:"flex", flexDirection:"column" }}>
                        <span style={{ fontFamily:"var(--mono)", fontSize:14, fontWeight:600, color:"var(--paper)", marginBottom:2 }}>{s.v}</span>
                        <span style={{ fontFamily:"var(--mono)", fontSize:9, textTransform:"uppercase", letterSpacing:"0.12em", color:"var(--mist)" }}>{s.l}</span>
                      </div>
                    ))}
                  </div>
                </div>
              </div>
              <div style={{ display:"flex", flexDirection:"column", gap:1, background:"rgba(244,241,234,0.08)", borderRadius:4, overflow:"hidden" }}>
                {extra.org.others.map(r => (
                  <div key={r.name} style={{ background:"var(--ink)", padding:"9px 13px", display:"grid", gridTemplateColumns:"1fr auto auto", gap:11, alignItems:"center", fontSize:12 }}>
                    <div><div style={{ fontWeight:600, marginBottom:2 }}>{r.name}</div><div style={{ fontSize:11, color:"rgba(244,241,234,0.45)" }}>{r.loc}</div></div>
                    <span style={{ fontFamily:"var(--mono)", fontSize:9, padding:"2px 7px", border:"0.5px solid rgba(244,241,234,0.18)", borderRadius:99, textTransform:"uppercase", color:"rgba(244,241,234,0.65)", whiteSpace:"nowrap" }}>{r.dist}</span>
                    <span style={{ fontFamily:"var(--mono)", fontSize:10, color:"rgba(244,241,234,0.45)", whiteSpace:"nowrap" }}>{r.date}</span>
                  </div>
                ))}
              </div>
            </Sec>
          )}

          {/* Footer CTA */}
          <div className="dp-footer-cta">
            <div className="dp-footer-cta-text">
              {enteredN.toLocaleString()} / {capN.toLocaleString()} entered
              <small>Standard entry £{race.price} · closes {race.pricing.find(p=>p.current)?.when ?? "soon"}</small>
            </div>
            <button className="dp-btn dp-btn-primary">Enter — £{race.price}</button>
          </div>

          {/* AI Disclaimer */}
          <div className="dp-ai-disclaimer">
            <p>
              ⚠ This information is AI-assisted and may be incomplete or out of date. Race details, logistics, pricing and policies change — always verify with the official organiser before travelling or entering.{" "}
              <a href={`https://www.google.com/search?q=${encodeURIComponent(race.name + " " + new Date().getFullYear())}`} target="_blank" rel="noopener">Find official source ↗</a>
            </p>
          </div>

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

/* ─── INDEX PAGE ─────────────────────────────────────────────────── */
function IndexPage({ onSelect }) {
  const cityOptions = React.useMemo(() => {
    const u = [...new Set(RACES.map((r) => r.city))].filter(Boolean).sort();
    return u.length ? u : ["UK"];
  }, []);

  const [city, setCity] = React.useState(() => cityOptions[0] || "UK");
  const [distFilter, setDistFilter] = React.useState("All");
  const [sortBy, setSortBy] = React.useState("Date");

  React.useEffect(() => {
    if (!cityOptions.includes(city) && cityOptions.length) setCity(cityOptions[0]);
  }, [cityOptions, city]);

  const filtered = React.useMemo(() => {
    let races = RACES.filter((r) => r.city === city);
    if (distFilter !== "All") {
      races = races.filter((r) => {
        if (distFilter === "5K") return r.distance < 8;
        if (distFilter === "10K") return r.distance >= 8 && r.distance < 15;
        if (distFilter === "Half") return r.distance >= 15 && r.distance < 30;
        if (distFilter === "Full") return r.distance >= 30 && r.distance < 45;
        if (distFilter === "Ultra") return r.distance >= 45;
        return true;
      });
    }
    return [...races].sort((a, b) => {
      if (sortBy === "Rating") return (Number(b.rating) || 0) - (Number(a.rating) || 0);
      if (sortBy === "Elevation") return (b.elevGain || 0) - (a.elevGain || 0);
      if (sortBy === "Price") return (Number(a.price) || 0) - (Number(b.price) || 0);
      return (Number(a.startTs) || 0) - (Number(b.startTs) || 0);
    });
  }, [city, distFilter, sortBy]);

  return (
    <div style={{ minHeight:"100vh", display:"flex", flexDirection:"column" }}>
      {/* Nav */}
      <nav style={{ borderBottom:"1px solid var(--rule-str)", position:"sticky", top:0, zIndex:100, background:"var(--ink)" }}>
        <div style={{ maxWidth:1280, margin:"0 auto", padding:"0 32px", display:"flex", alignItems:"center", height:54, gap:32 }}>
          <a href="#" style={{ display:"flex", alignItems:"center", gap:9, flexShrink:0 }}>
            <svg width="20" height="20" viewBox="0 0 20 20" fill="none"><circle cx="10" cy="10" r="9" stroke="var(--track)" strokeWidth="1.5" /><circle cx="10" cy="10" r="3.5" fill="var(--track)" /><line x1="10" y1="1" x2="10" y2="4.5" stroke="var(--track)" strokeWidth="1.5" /></svg>
            <span style={{ fontFamily:"var(--mono)", fontSize:13, fontWeight:600, color:"var(--paper)" }}>startlist.run</span>
          </a>
          <div style={{ marginLeft:"auto" }}>
            <button style={{ fontFamily:"var(--mono)", fontSize:10, textTransform:"uppercase", letterSpacing:"0.12em", padding:"8px 16px", background:"var(--track)", color:"var(--ink)", borderRadius:2, fontWeight:700, display:"flex", alignItems:"center", gap:7 }}>
              <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M15.076 7.454c-.29.195-.643.378-1.054.537-1.11.43-2.576.684-4.022.684s-2.912-.253-4.022-.684c-.41-.16-.764-.342-1.054-.537C6.7 7.02 8.194 6.5 10 6.5s3.3.52 5.076.954zM5 12.5V9.15c.18.1.375.197.576.285 1.294.502 2.888.765 4.424.765s3.13-.263 4.424-.765c.2-.088.396-.185.576-.285V12.5c-.18.1-.375.197-.576.285-1.294.502-2.888.765-4.424.765s-3.13-.263-4.424-.765A5.5 5.5 0 0 1 5 12.5zM5 14.65c.18.1.375.197.576.285 1.294.502 2.888.765 4.424.765s3.13-.263 4.424-.765c.2-.088.396-.185.576-.285v2.85c0 .978-1.79 2-5 2s-5-1.022-5-2v-2.85z"/></svg>
              Connect Strava
            </button>
          </div>
        </div>
      </nav>

      {/* Hero */}
      <header style={{ borderBottom:"1px solid var(--rule-str)", background:"var(--ink)", position:"relative", overflow:"hidden" }}>
        <div style={{ position:"absolute", inset:0, pointerEvents:"none", backgroundImage:"repeating-linear-gradient(0deg, transparent 0px, transparent 38px, rgba(244,241,234,0.025) 38px, rgba(244,241,234,0.025) 39px)" }} />
        <div style={{ position:"absolute", top:"-40%", right:"-10%", width:500, height:500, background:"radial-gradient(circle, rgba(212,255,0,0.07) 0%, transparent 65%)", pointerEvents:"none" }} />
        <div style={{ maxWidth:1280, margin:"0 auto", padding:"60px 32px 56px", position:"relative" }}>
          <div style={{ fontFamily:"var(--mono)", fontSize:10, textTransform:"uppercase", letterSpacing:"0.2em", color:"var(--track)", display:"flex", alignItems:"center", gap:12, marginBottom:18 }}>
            <span style={{ width:24, height:1, background:"var(--track)", display:"inline-block" }} />Race discovery — London · Manchester · Bristol/SW
          </div>
          <h1 style={{ fontFamily:"var(--sans)", fontSize:"clamp(48px, 6.5vw, 98px)", fontWeight:800, lineHeight:0.92, letterSpacing:"-0.04em", maxWidth:"14ch", marginBottom:22, color:"var(--paper)", textTransform:"uppercase" }}>
            Your next race,<br /><em style={{ color:"var(--track)", fontStyle:"normal" }}>properly briefed.</em>
          </h1>
          <p style={{ fontFamily:"var(--serif)", fontSize:18, fontWeight:300, fontStyle:"italic", lineHeight:1.5, maxWidth:"50ch", color:"rgba(244,241,234,0.7)" }}>
            Every race. Every detail — elevation profile, average finish time, what your club is entering. Not a registration link. An actual brief.
          </p>
        </div>
      </header>

      <FilterBar cities={cityOptions} city={city} setCity={setCity} distFilter={distFilter} setDistFilter={setDistFilter} sortBy={sortBy} setSortBy={setSortBy} />

      <main style={{ maxWidth:1280, margin:"0 auto", padding:"36px 32px 80px", flex:1 }}>
        <div style={{ display:"flex", alignItems:"baseline", justifyContent:"space-between", marginBottom:24, gap:16 }}>
          <div style={{ display:"flex", alignItems:"baseline", gap:14 }}>
            <h2 style={{ fontFamily:"var(--serif)", fontSize:38, fontWeight:400, letterSpacing:"-0.025em", fontVariationSettings:"'opsz' 72", lineHeight:1, color:"var(--paper)" }}>{city}</h2>
            <span style={{ fontFamily:"var(--mono)", fontSize:10, textTransform:"uppercase", letterSpacing:"0.14em", color:"var(--mist)" }}>{filtered.length} race{filtered.length !== 1 ? "s" : ""}</span>
          </div>
          <div style={{ fontFamily:"var(--mono)", fontSize:9, textTransform:"uppercase", letterSpacing:"0.14em", color:"var(--mist)", display:"flex", alignItems:"center", gap:7 }}>
            <span style={{ width:7, height:7, borderRadius:"50%", background:"#4ade80", display:"inline-block" }} />Updated daily
          </div>
        </div>

        {filtered.length === 0 ? (
          <div style={{ padding:"80px 40px", textAlign:"center", fontFamily:"var(--mono)", fontSize:11, textTransform:"uppercase", letterSpacing:"0.18em", color:"var(--mist)", border:"1px dashed var(--rule-mid)" }}>No races match this filter in {city}</div>
        ) : (
          <div style={{ display:"grid", gridTemplateColumns:"repeat(auto-fill, minmax(336px, 1fr))", gap:1, background:"var(--rule)" }}>
            {filtered.map(race => <RaceCard key={race.id} race={race} onSelect={onSelect} />)}
          </div>
        )}

        <div style={{ marginTop:40, background:"var(--surface)", border:"1px solid var(--rule-mid)", padding:"36px 44px", display:"flex", gap:48, alignItems:"center", position:"relative", overflow:"hidden" }}>
          <div style={{ position:"absolute", top:0, left:0, right:0, height:2, background:"var(--track)" }} />
          <div style={{ position:"absolute", top:"-60%", right:"-5%", width:400, height:400, background:"radial-gradient(circle, rgba(212,255,0,0.06) 0%, transparent 65%)", pointerEvents:"none" }} />
          <div style={{ flex:1, position:"relative" }}>
            <div style={{ fontFamily:"var(--mono)", fontSize:9, textTransform:"uppercase", letterSpacing:"0.2em", color:"var(--track)", marginBottom:10 }}>Connect Strava — unlock everything</div>
            <h3 style={{ fontFamily:"var(--serif)", fontSize:28, fontWeight:400, fontVariationSettings:"'opsz' 72", letterSpacing:"-0.02em", lineHeight:1.15, marginBottom:10, color:"var(--paper)" }}>See your predicted finish.<br />See what your club is entering.</h3>
            <p style={{ fontFamily:"var(--sans)", fontSize:13, lineHeight:1.65, color:"var(--mist)", maxWidth:"48ch" }}>Once connected, every race page shows a predicted finish based on your recent training, flags which of your Strava contacts are entered, and surfaces your training readiness score.</p>
          </div>
          <button style={{ fontFamily:"var(--mono)", fontSize:10, textTransform:"uppercase", letterSpacing:"0.14em", padding:"13px 28px", background:"#fc4c02", color:"#fff", borderRadius:2, flexShrink:0, fontWeight:600 }}>Connect Strava →</button>
        </div>
      </main>

      <footer style={{ borderTop:"1px solid var(--rule-str)", padding:"22px 32px", display:"flex", justifyContent:"space-between", alignItems:"center", flexWrap:"wrap", gap:16 }}>
        <span style={{ fontFamily:"var(--mono)", fontSize:11, fontWeight:600, color:"var(--paper)" }}>startlist.run</span>
        <div style={{ display:"flex", gap:24, fontFamily:"var(--mono)", fontSize:9, textTransform:"uppercase", letterSpacing:"0.14em", color:"var(--mist)" }}>
          <a href="#">London</a><a href="#">Manchester</a><a href="#">Bristol/SW</a><a href="#">About</a>
        </div>
      </footer>
    </div>
  );
}

/* ─── ROOT ──────────────────────────────────────────────────────── */
function App() {
  const [selectedRace, setSelectedRace] = React.useState(null);

  const handleSelect = (race) => {
    setSelectedRace(race);
    window.scrollTo(0, 0);
  };

  const handleBack = () => {
    setSelectedRace(null);
    window.scrollTo(0, 0);
  };

  if (selectedRace) {
    return <RaceDetailPage race={selectedRace} onBack={handleBack} />;
  }
  return <IndexPage onSelect={handleSelect} />;
}

const rootEl = document.getElementById("root");
if (rootEl && typeof ReactDOM !== "undefined" && ReactDOM.createRoot) {
  ReactDOM.createRoot(rootEl).render(<App />);
}

