:root {
  color-scheme: dark;
  --bg: #0A0713;
  --panel: #151029;
  --panel-2: #1C1536;
  --edge: #2A2048;
  --ink: #EFEAFF;
  --dim: #8B7CC4;
  --gold: #F5B74A;
  --green: #4BDD88;
  --red: #DD4B6B;
}
* { box-sizing: border-box; }

/* The browser's own [hidden] rule is display:none, but ANY author rule that sets display
   beats it — author styles win over user-agent styles whatever the specificity. That is how
   the countdown's "GO!" stayed painted over the race after it was supposedly hidden:
   .countdown sets display:grid, so node.hidden = true did nothing at all. One rule, once,
   so it cannot happen again to anything else on the page. */
[hidden] { display: none !important; }

/* The crash banner. Loud on purpose: a page where nothing works and nothing says why is the
   worst thing this app can do to somebody. */
#crash {
  position: fixed; inset: 0 0 auto 0; z-index: 999;
  padding: 12px 16px; background: #5B0F1F; color: #FFE3E8;
  font: 600 13px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
  border-bottom: 2px solid #FF6B8A; white-space: pre-wrap;
}
html, body { height: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  font: 14px/1.4 system-ui, -apple-system, "Segoe UI", sans-serif;
  overflow: hidden;                 /* the whole thing fits the screen; nothing scrolls */
}

/* Full-height column layout, so the course always fits the viewport and the name rail is
   never pushed below the fold. */
.app { height: 100dvh; display: flex; flex-direction: column; padding: 10px 14px 12px; gap: 10px; }

header { display: flex; align-items: baseline; gap: 12px; flex: 0 0 auto; }
h1 { margin: 0; font-size: 20px; letter-spacing: .4px; color: var(--gold); }
.sub { color: var(--dim); font-size: 12px; }
.spacer { flex: 1 1 auto; }
.clock { color: var(--dim); font-variant-numeric: tabular-nums; font-size: 13px; }

main { flex: 1 1 auto; min-height: 0; position: relative; }

/* ---------------------------------------------------------------- screens ---- */
/* Exactly one screen is live at a time. They fade rather than slide: a slide off the side
   gives an iPad a horizontal scrollbar, and this whole page is meant never to scroll. */
.screen {
  position: absolute; inset: 0;
  display: none; flex-direction: column; gap: 12px; min-height: 0;
}
.screen.is-live { display: flex; animation: fade .18s ease both; }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }

.screen-head { display: flex; align-items: center; gap: 12px; flex: 0 0 auto; }
.screen-head h2 { margin: 0; font-size: 19px; letter-spacing: .3px; }
.screen-head .ghost { margin-left: auto; }
.seedline { margin-left: auto; color: var(--dim); font-size: 11px; font-variant-numeric: tabular-nums; }

h2 { font-size: 26px; margin: 0 0 6px; }
.kicker { color: var(--gold); text-transform: uppercase; letter-spacing: 2px; font-size: 11px; margin: 0 0 10px; }
.lede { color: var(--dim); max-width: 62ch; margin: 0; line-height: 1.6; flex: 0 0 auto; }
.fineprint { color: var(--dim); font-size: 11px; margin: 0; }
.row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; flex: 0 0 auto; }

.hero {
  margin: auto; max-width: 640px; text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 14px;
}
.hero .lede { text-align: center; }

/* Six formats do not fit in a row of buttons, and a name alone does not tell you the
   difference between a Ladder and a Cup. Each one gets a card saying how many races it is,
   how long it takes and what shape it has. */
.hero.wide { max-width: 920px; }
#screen-home { overflow-y: auto; }
.formats {
  display: grid; gap: 10px; width: 100%;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
@media (max-width: 880px) { .formats { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .formats { grid-template-columns: 1fr; } }

button.format {
  display: flex; flex-direction: column; align-items: flex-start; gap: 5px;
  width: 100%; text-align: left; padding: 12px 14px; min-height: 0;
  border-color: var(--edge); background: var(--panel);
}
button.format:hover { border-color: var(--gold); background: var(--panel-2); }
.format .fname { font-size: 15px; font-weight: 700; letter-spacing: .2px; color: var(--gold); }
.format .fmeta {
  font-size: 10px; color: var(--dim); text-transform: uppercase; letter-spacing: 1.5px;
}
.format .fwhat { font-size: 12px; color: var(--dim); line-height: 1.5; white-space: normal; }

/* ---------------------------------------------------------------- buttons ---- */
button {
  font: inherit; font-size: 13px; padding: 8px 16px; min-height: 40px; border-radius: 9px;
  cursor: pointer; border: 1px solid var(--edge); background: var(--panel-2); color: var(--ink);
  transition: background .15s ease, border-color .15s ease;
}
button:hover { background: #241C45; border-color: var(--gold); }
button.big { font-size: 15px; padding: 12px 28px; min-height: 48px; border-color: var(--gold); color: var(--gold); }
button.big:hover { background: var(--gold); color: #1A1430; }
button.ghost { background: transparent; color: var(--dim); }
button.ghost:hover { color: var(--ink); }
button.wide { width: 100%; }
button.icon { padding: 4px 8px; min-height: 30px; font-size: 15px; line-height: 1; }
button:disabled { opacity: .4; cursor: default; border-color: var(--edge); color: var(--dim); }
button.big:disabled { background: transparent; color: var(--dim); }
.row.centred { justify-content: center; }

/* ------------------------------------------------------------------- draw ---- */
.groups {
  flex: 1 1 auto; min-height: 0; overflow: auto;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; align-content: start;
}
.group {
  background: var(--panel); border: 1px solid var(--edge); border-radius: 12px; padding: 10px;
  display: flex; flex-direction: column; gap: 6px; min-height: 0;
}
.group h3 {
  margin: 0 0 2px; font-size: 12px; letter-spacing: 1.5px; text-transform: uppercase;
  color: var(--gold);
}
.slot {
  display: flex; align-items: center; gap: 8px; min-height: 34px; border-radius: 8px;
  padding: 4px 6px; background: var(--panel-2); border: 1px dashed var(--edge);
}
.slot.filled { border-style: solid; animation: drop .28s cubic-bezier(.2,.9,.3,1.3) both; }
@keyframes drop { from { opacity: 0; transform: translateY(-14px) scale(.94); } to { opacity: 1; transform: none; } }
.slot .name { font-size: 12px; line-height: 1.2; flex: 1 1 auto; }
.slot .flag { font-size: 13px; opacity: .85; }

/* A meal's colour disc carrying its icon. Used on nearly every screen. */
/* The racing ball: its silk, drawn from the same path the course uses, with the number over
   the top when numbers are on. The round edge does the trimming, so a shape that runs past the
   rim needs no clip path of its own. */
.dot {
  width: 28px; height: 28px; border-radius: 50%; flex: 0 0 auto;
  position: relative; overflow: hidden; display: grid; place-items: center;
  box-shadow: 0 0 0 1.5px rgba(0,0,0,.6);
}
.dot svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.dot .no {
  position: relative; z-index: 1; color: #fff;
  font: 800 14px/1 system-ui, -apple-system, sans-serif; font-variant-numeric: tabular-nums;
  text-shadow:
    0 0 2px rgba(8,5,16,.98), 0 0 3px rgba(8,5,16,.9),
    1px 1px 0 rgba(8,5,16,.95), -1px -1px 0 rgba(8,5,16,.95),
    1px -1px 0 rgba(8,5,16,.95), -1px 1px 0 rgba(8,5,16,.95);
}
.rail.many .dot .no { font-size: 11px; }
.line .dot .no { font-size: 10px; }
.dot.xl .no { font-size: 38px; }
.dot.lg .no { font-size: 21px; }
.dot.xl { width: 84px; height: 84px; font-size: 38px; }
.dot.lg { width: 46px; height: 46px; font-size: 21px; }

/* The meal's icon, shown where there is room for it. */
.icon { font-size: 17px; line-height: 1; flex: 0 0 auto; }
.rail.many .icon { font-size: 13px; }
.line .icon { font-size: 12px; }
.slot .icon { font-size: 14px; }
.silkline { display: flex; align-items: center; gap: 10px; }
.icon.xl { font-size: 76px; }
.icon.lg { font-size: 40px; }

/* ------------------------------------------------------------------ intro ---- */
.introcards {
  flex: 1 1 auto; min-height: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px; align-content: center;
}
.racer {
  background: var(--panel); border: 1px solid var(--edge); border-radius: 14px; padding: 16px;
  display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center;
  opacity: 0;
}
.racer.shown { animation: enter .34s cubic-bezier(.2,.9,.3,1.3) both; }
@keyframes enter { from { opacity: 0; transform: translateY(18px) scale(.92); } to { opacity: 1; transform: none; } }
.racer .who { font-size: 15px; font-weight: 600; line-height: 1.25; }
.racer .from { color: var(--dim); font-size: 12px; }
.racer .form {
  color: var(--gold); font-size: 11px; letter-spacing: 1px; text-transform: uppercase;
  min-height: 14px;
}

/* A field of thirty-two will not fit as cards, so it arrives as chips instead. */
.introcards.many {
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 6px; align-content: start; overflow-y: auto;
}
.introcards.many .racer {
  flex-direction: row; align-items: center; gap: 8px; padding: 6px 8px;
  border-radius: 9px; text-align: left;
}
.introcards.many .racer .who { font-size: 12px; font-weight: 500; }
.introcards.many .racer .from, .introcards.many .racer .form { display: none; }
.introcards.many .dot.lg { width: 26px; height: 26px; font-size: 15px; }

/* ------------------------------------------------------------------- race ---- */
.racing { flex: 1 1 auto; min-height: 0; display: flex; gap: 12px; align-items: stretch; }
.stage {
  flex: 1 1 auto; min-width: 0; position: relative;
  display: flex; align-items: center; justify-content: center;
}

/* Three, two, one, go — laid straight over the starting grid, so you watch the marbles
   waiting rather than a separate screen. */
.countdown { position: absolute; inset: 0; display: grid; place-items: center; pointer-events: none; }
.countdown span {
  font-size: clamp(72px, 20vh, 210px); font-weight: 800; letter-spacing: -2px;
  color: var(--gold);
  text-shadow: 0 0 48px rgba(245,183,74,.6), 0 10px 34px rgba(0,0,0,.85);
  animation: countpop .42s cubic-bezier(.2,.9,.3,1.3) both;
}
@keyframes countpop {
  from { opacity: 0; transform: scale(.35); }
  60% { opacity: 1; transform: scale(1.14); }
  to { opacity: 1; transform: scale(1); }
}
canvas {
  /* Fit inside the stage WITHOUT distorting. `height: 100%` with `max-width: 100%` looks like
     it does that and does not: when both constraints bite, a replaced element is stretched to
     the box rather than scaled to it, and the course came out seventeen per cent narrower than
     it was drawn. Letting both dimensions be auto and capping them is what actually preserves
     the ratio; object-fit is the belt to that pair of braces. */
  width: auto; height: auto; max-width: 100%; max-height: 100%;
  object-fit: contain;
  display: block; border-radius: 12px; touch-action: none;
  box-shadow: 0 10px 40px rgba(0,0,0,.55);
  cursor: zoom-in;   /* hold the pointer over the course and a lens follows it */
}
.side { flex: 0 0 250px; min-height: 0; display: flex; flex-direction: column; gap: 8px; }
.speeds { display: flex; gap: 4px; flex: 0 0 auto; }
.speeds button { flex: 1 1 0; padding: 6px 0; min-height: 34px; font-size: 12px; }
.speeds button.on { border-color: var(--gold); color: var(--gold); background: var(--panel-2); }
.lap {
  flex: 0 0 auto; text-align: center; padding: 6px; border-radius: 8px;
  background: var(--panel-2); border: 1px solid var(--gold); color: var(--gold);
  font-size: 11px; letter-spacing: 2px; text-transform: uppercase;
}
.rail { flex: 1 1 auto; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 7px; }
.card {
  display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 10px;
  background: var(--panel); border: 1px solid var(--edge);
  transition: background .2s ease, border-color .2s ease, opacity .2s ease;
}
.card .pos { width: 30px; font-weight: 700; color: var(--dim); font-size: 12px; letter-spacing: .3px; }
.card .name { flex: 1 1 auto; font-size: 13px; line-height: 1.25; }
.card .flag { font-size: 15px; opacity: .85; }
.card .lapno { color: var(--gold); font-size: 10px; letter-spacing: 1px; }
.card .best { font-variant-numeric: tabular-nums; font-size: 12px; color: var(--ink); }
.rail.many .card .best { font-size: 11px; }
.rail .cutline { margin: 2px 0; }
/* A full-roster field: same rail, tighter rows, so all thirty-two are visible at once. */
.rail.many { gap: 3px; }
.rail.many .card { padding: 3px 7px; gap: 7px; border-radius: 7px; }
.rail.many .card .pos { width: 24px; font-size: 10px; }
.rail.many .card .dot { width: 21px; height: 21px; font-size: 11px; }
.rail.many .card .name { font-size: 11px; line-height: 1.15; }
.rail.many .card .flag { font-size: 11px; }

/* Lifted off the course in a battle royale. Still listed, because how long you lasted is the
   result, but plainly no longer racing. */
.card.out { opacity: .4; border-color: var(--red); }
.card.out .name { text-decoration: line-through; text-decoration-color: var(--red); }
.card.done { opacity: .55; }
.card.win { background: var(--panel-2); border-color: var(--gold); }
.card.win .pos { color: var(--gold); }

/* Paused. Deliberately at the top and out of the way: the whole reason to pause is to look
   at the course, so the badge must not sit on top of it. */
.paused {
  position: absolute; top: 14px; left: 50%; transform: translateX(-50%);
  padding: 7px 16px; border-radius: 999px; pointer-events: none; white-space: nowrap;
  background: rgba(10,7,19,.9); border: 1px solid var(--gold); color: var(--gold);
  font-size: 11px; letter-spacing: 1.5px; text-transform: uppercase;
}
#pause.on { border-color: var(--gold); color: var(--gold); background: var(--panel-2); }
#numbers.on { border-color: var(--gold); color: var(--gold); }

/* ----------------------------------------------------------------- result ---- */
.results {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  display: flex; flex-direction: column; gap: 6px;
}
.results.narrow { flex: 0 0 auto; max-height: 40vh; width: 100%; max-width: 520px; }
.place {
  display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-radius: 10px;
  background: var(--panel); border: 1px solid var(--edge);
  animation: enter .3s cubic-bezier(.2,.9,.3,1.3) both;
}
.place .pos { width: 34px; font-weight: 700; font-size: 13px; color: var(--dim); }
.place .name { flex: 1 1 auto; font-size: 14px; text-align: left; }
.place .flag { font-size: 15px; opacity: .85; }
.place .time { font-variant-numeric: tabular-nums; font-size: 13px; color: var(--ink); min-width: 62px; text-align: right; }
.place .gap { font-variant-numeric: tabular-nums; font-size: 11px; color: var(--dim); min-width: 52px; text-align: right; }
.place .splits { font-variant-numeric: tabular-nums; font-size: 10px; color: var(--dim); min-width: 96px; text-align: right; }
/* What a finish was worth, on a season's race sheet. */
.place .earned {
  font-variant-numeric: tabular-nums; font-size: 12px; font-weight: 700;
  min-width: 34px; text-align: right; color: var(--gold);
}
.place .earned.none { color: var(--dim); opacity: .5; font-weight: 400; }
.place.through { border-color: var(--green); background: #10261B; }
.place.through .pos { color: var(--green); }
.place.out { opacity: .5; }
.place.out .name { text-decoration: line-through; text-decoration-color: var(--red); }

/* The line across a timesheet where the cut falls. */
.cutline {
  display: flex; align-items: center; gap: 10px;
  margin: 4px 2px; color: var(--red); font-size: 10px;
  letter-spacing: 2px; text-transform: uppercase; white-space: nowrap;
}
.cutline::before, .cutline::after {
  content: ''; flex: 1 1 auto; height: 1px; background: var(--red); opacity: .55;
}

/* -------------------------------------------------------------- standings ---- */
/* The championship table reuses .place, so a row on this screen and a row on a result sheet
   are recognisably the same object. Only the columns a season needs are added. */
.place.leader { border-color: var(--gold); background: #241D08; }
.place.leader .pos, .place.leader .points { color: var(--gold); }
.place.blank { opacity: .55; }
.place .points {
  font-variant-numeric: tabular-nums; font-weight: 700; font-size: 14px;
  min-width: 38px; text-align: right; color: var(--ink);
}
.place .form { font-size: 11px; color: var(--dim); min-width: 52px; text-align: right; }
.place .moved {
  font-size: 10px; min-width: 30px; text-align: right;
  font-variant-numeric: tabular-nums; letter-spacing: .5px;
}
.place .moved.up { color: var(--green); }
.place .moved.down { color: var(--red); }

/* The row showing its own working: one cell per round, where it finished above what that was
   worth, then the plus signs, then the total. A total nobody can check is a total nobody
   believes. */
.place .rounds { display: flex; align-items: flex-end; gap: 3px; margin-left: auto; }
.place .rd {
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  min-width: 28px; line-height: 1.1;
}
.place .rdplace { font-size: 9px; color: var(--dim); opacity: .8; }
.place .rdpts { font-size: 13px; font-variant-numeric: tabular-nums; color: var(--ink); }
.place .rd.none .rdpts { color: var(--dim); opacity: .55; }
.place .plus { font-size: 10px; color: var(--dim); opacity: .5; padding-bottom: 2px; }
.place .rounds + .plus { padding: 0 2px 2px; }
/* With a breakdown in the row the form label stops pushing the numbers around. */
.place .rounds ~ .points { margin-left: 0; }

/* A phone cannot hold five round cells beside a name. The total and the movement still tell
   the story; the working is there on a bigger screen. */
@media (max-width: 700px) {
  .place .rounds, .place .rounds + .plus { display: none; }
  /* With the working gone the row still has one column too many for a phone, and it was the
     points-behind figure that slid off the edge. The total is what matters on a small screen. */
  #screen-standings .place .gap { display: none; }
  #screen-standings .place .form { min-width: 0; }
}

/* ---------------------------------------------------------------- bracket ---- */
.bracket {
  flex: 1 1 auto; min-height: 0; overflow: auto;
  display: grid; grid-template-columns: 1.6fr 1fr 1fr; gap: 12px; align-items: start;
}
.round h3 {
  margin: 0 0 8px; font-size: 11px; letter-spacing: 2px; text-transform: uppercase;
  color: var(--gold);
}
.round .ties { display: grid; gap: 8px; }
.round.groups-col .ties { grid-template-columns: 1fr 1fr; }
.tie {
  background: var(--panel); border: 1px solid var(--edge); border-radius: 10px; padding: 8px;
  display: flex; flex-direction: column; gap: 4px;
}
.tie.live { border-color: var(--gold); }
.tie h4 { margin: 0 0 2px; font-size: 10px; letter-spacing: 1.5px; text-transform: uppercase; color: var(--dim); }
.tie.live h4 { color: var(--gold); }
.line { display: flex; align-items: center; gap: 6px; font-size: 11px; line-height: 1.25; }
.line .dot { width: 19px; height: 19px; font-size: 10px; }
.line .who { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.line.through .who { color: var(--green); }
.line.out { opacity: .45; }
.line.out .who { text-decoration: line-through; }
.line.empty { color: var(--dim); font-style: italic; opacity: .5; }
.line.moved { animation: advance .5s cubic-bezier(.2,.9,.3,1.3) both; }
@keyframes advance {
  from { opacity: 0; transform: translateX(-22px); background: rgba(75,221,136,.25); }
  to { opacity: 1; transform: none; }
}

/* ------------------------------------------------------------------ field ---- */
.field {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 8px;
  align-content: start;
}
.runner {
  display: flex; align-items: center; gap: 9px; padding: 8px 10px; border-radius: 10px;
  background: var(--panel); border: 1px solid var(--edge);
}
.runner .who { flex: 1 1 auto; min-width: 0; }
.runner .name { font-size: 13px; line-height: 1.2; display: block; }
.runner .from { font-size: 11px; color: var(--dim); display: block; }

/* ---------------------------------------------------------------- builder ---- */
.builder { flex: 1 1 auto; min-height: 0; display: flex; gap: 14px; align-items: stretch; }
.slots {
  flex: 0 0 300px; min-height: 0; overflow-y: auto;
  display: flex; flex-direction: column; gap: 7px;
}
.slot-row {
  background: var(--panel); border: 1px solid var(--edge); border-radius: 10px; padding: 8px 10px;
  display: flex; flex-direction: column; gap: 5px;
}
.slot-row .top { display: flex; align-items: center; gap: 8px; }
.slot-row .num {
  width: 22px; height: 22px; border-radius: 6px; display: grid; place-items: center;
  background: var(--panel-2); color: var(--gold); font-size: 11px; font-weight: 700; flex: 0 0 auto;
}
.slot-row select {
  flex: 1 1 auto; min-width: 0; font: inherit; font-size: 13px; padding: 5px 7px;
  border-radius: 7px; border: 1px solid var(--edge); background: var(--panel-2); color: var(--ink);
}
.slot-row select:hover { border-color: var(--gold); }
.slot-row .blurb { color: var(--dim); font-size: 11px; line-height: 1.35; }
.preview {
  flex: 1 1 auto; min-width: 0; display: flex; align-items: center; justify-content: center;
}
#preview {
  height: 100%; width: auto; max-width: 100%; max-height: 100%;
  display: block; border-radius: 12px;
  box-shadow: 0 10px 40px rgba(0,0,0,.55);
}

/* ----------------------------------------------------------------- winner ---- */
.champion { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.champion .who { font-size: 30px; font-weight: 700; line-height: 1.15; }
.champion .from { color: var(--dim); font-size: 14px; }

/* Only stack on genuinely narrow screens, and even then keep the names visible without
   hunting for them. */
@media (max-width: 900px) {
  .bracket { grid-template-columns: 1fr; }
  .groups { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 900px) {
  .builder { flex-direction: column; }
  .slots { flex: 0 0 auto; max-height: 40vh; }
}
@media (max-width: 760px) {
  body { overflow: auto; }
  .app { height: auto; }
  main { position: static; }
  .screen { position: static; }
  .screen:not(.is-live) { display: none; }
  .racing { flex-direction: column; }
  canvas { width: 100%; height: auto; }
  .side { flex: 1 1 auto; width: 100%; }
  .rail { display: grid; grid-template-columns: repeat(2, 1fr); }
  .place .splits { display: none; }
  h2 { font-size: 21px; }
  .champion .who { font-size: 24px; }
}
