/* Randometrics stats pages. Loaded after z1rracing.com's styles.css, whose
   :root variables (--ink, --surface, --raised, --edge, --moss, --gold,
   --parchment, --muted, --display, --body, --mono) this file builds on. */

main.wrap { padding-block: clamp(22px, 4vw, 40px) clamp(30px, 5vw, 56px); }

.crumbs { margin: 0 0 18px; color: var(--muted); font-size: 0.9rem; }
.crumbs a { color: var(--gold); text-decoration: none; }
.crumbs a:hover { text-decoration: underline; }

.stats-page h1 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.45rem, 2.4vw, 1.95rem);
  letter-spacing: 0.02em;
  margin: 0 0 6px;
}

.stats-page .lede { color: var(--muted); margin: 0 0 16px; }

/* Each h2 opens a part of the page, so it gets room above it — except the
   first, which already has the header above. */
.stats-page .section-head { margin-top: 34px; }

/* An anchor lands under the site's own top bar without this. */
.stats-page .section-head[id], .stats-page .panel[id] { scroll-margin-top: 84px; }
.stats-page .stats-hero + .section-head,
.stats-page .crumbs + .section-head { margin-top: 0; }

/* Every section break is the same size. The stat cards are part of the page
   head rather than a section of their own, but the gap after them is still a
   section break, and one at 22px beside others at 34px reads as a mistake. */
.stats-page .stat-row + .section-head { margin-top: 34px; }

/* The name sits above the page's own title, the way a masthead does. */
.kicker {
  margin: -2px 0 10px;
  color: var(--moss-bright);
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.stats-page .accounts { color: var(--muted); font-size: 0.86rem; margin: 0 0 20px; }
.stats-page .accounts code { font-family: var(--mono); font-size: 0.8rem; color: var(--muted); }

/* ------------------------------------------------------------ stat cards */

.stat-row {
  display: grid;
  gap: 12px;
  align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(min(168px, 100%), 1fr));
  margin-bottom: 18px;
}

.stat {
  display: grid;
  gap: 3px;
  padding: 14px 16px;
  border: 1px solid var(--edge);
  border-left: 3px solid var(--moss);
  background: var(--surface);
}

.stat-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
}

.stat-value {
  font-family: var(--display);
  font-size: 1.5rem;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}

.stat-note { color: var(--muted); font-size: 0.85rem; }

/* A seed or a flag string is a reference number, never a headline: it goes
   in mono at reading size wherever it appears, including inside a stat card
   whose value would otherwise be set in display type at 1.5rem. */
.stat-value .mono, .stat-value code, .mono.seed { font-family: var(--mono); font-size: 0.82rem; letter-spacing: 0; }

/* Which way a rating moved. */
.delta { font-family: var(--mono); font-size: 0.78rem; }
.delta.up { color: var(--moss-bright); }
.delta.down { color: var(--dodongo); }

/* ------------------------------------------------------------- race head */

.race-head { margin-bottom: 18px; }
.race-head h1 { margin-bottom: 6px; }
.race-meta { margin: 0 0 8px; color: var(--muted); font-size: 0.95rem; }
.race-meta .when { color: var(--gold); font-family: var(--mono); font-size: 0.82rem; }
.race-meta a { color: var(--gold); text-decoration: none; }
.race-meta a:hover { text-decoration: underline; }
.race-ids { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0; }
.race-ids .mono { color: var(--muted); font-size: 0.76rem; }
.room-info { white-space: pre-wrap; overflow-wrap: anywhere; font-family: var(--mono); font-size: 0.8rem; color: var(--muted); }
.result td.mono { font-size: 0.82rem; }

/* Rating and its movement are two columns under one heading, so each lines
   up with its own kind rather than with a string of both. */
.result th[title] { cursor: help; }

/* What a racer said about their own run, under their name. */
.said {
  display: block;
  margin-top: 2px;
  color: var(--muted);
  font-size: 0.84rem;
  font-style: italic;
  overflow-wrap: anywhere;
}

/* The card's time line is a link, and reads as one only on hover. */
a.when { text-decoration: none; }
a.when:hover { color: var(--moss-bright); text-decoration: underline; }
.race-card-foot a { color: var(--gold); text-decoration: none; }
.race-card-foot a:hover { text-decoration: underline; }
.stat.gold { border-left-color: var(--gold); }
.stat.warm { border-left-color: var(--dodongo); }

/* ---------------------------------------------------------------- panels */

/* The site styles its own page sections with room to breathe —
   section { padding-block: clamp(34px, 5vw, 58px) } — and a panel is a
   <section> too, which was putting 58px of empty ground above and below
   every table on these pages. A panel carries its own spacing. */
.panel { border: 1px solid var(--edge); background: var(--surface); margin: 0 0 16px; padding: 0; }

.panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 16px;
  border-bottom: 1px solid var(--edge);
  background: var(--raised);
}

.panel-head h3 { margin: 0; font-size: 1.02rem; min-width: 0; }

/* The note on the right is short by design and never wraps the head onto two
   lines: a title long enough to need the room takes it from the note. */
.panel-head span, .panel-head a { flex: none; white-space: nowrap; color: var(--muted); font-family: var(--mono); font-size: 0.75rem; }
.panel-head a { color: var(--gold); text-decoration: none; }
.panel-head a:hover { text-decoration: underline; }
.panel > p, .panel > ol, .panel > ul { padding: 12px 16px; margin: 0; }
.panel > ol, .panel > ul { padding-left: 34px; }
/* A row of panels sits in the page's rhythm like a single panel does. It
   carried no margin of its own, so a grid followed by a panel touched, while
   panel-to-panel kept its 16px -- most visible on a phone, where every grid
   collapses to one column and the spacing between otherwise identical cards
   alternated 16, 0, 16, 0. */
.panel-grid { display: grid; gap: 16px 18px; align-items: start; grid-template-columns: repeat(auto-fit, minmax(min(330px, 100%), 1fr)); margin-bottom: 16px; }
/* Inside the grid the gap does the spacing; the panel's own margin would be
   added to it, which is how two stacked cards ended up 34px apart while two
   plain ones were 16px. */
.panel-grid > .panel { margin-bottom: 0; }

/* A panel in this grid is sized minmax(min(330px, 100%), 1fr), so it can be 330px
   wide while the window is 1400px. Anything inside it that has to give way has
   to do so on the panel's width, not the window's -- the viewport rule further
   down only fires below 620px, which is why Compare kept its word and
   overflowed a narrow column on a wide screen. */
.panel-grid > .panel { container-type: inline-size; }

@container (max-width: 420px) {
  /* Same reasoning as the phone rule below: Behind is Together minus Ahead,
     and the whole cell is a link, so the arrow is label enough. */
  table.rivals .c-behind { display: none; }
  table.rivals .go-word { display: none; }
  table.rivals th, table.rivals td { padding-inline: 8px; }
}

.panel td a, .panel th a { color: inherit; text-decoration: none; }
.panel td a:hover { color: var(--moss-bright); text-decoration: underline; }
.panel .dnf { color: var(--dodongo); }
.panel .win { color: var(--moss-bright); font-weight: 600; }
td.mono, .mono { font-family: var(--mono); font-size: 0.82rem; }
td.flags { max-width: 16rem; overflow-wrap: anywhere; }

/* --------------------------------------------------------------- filters */

.pill-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 12px; }

.pill {
  padding: 6px 13px;
  border: 1px solid var(--edge);
  background: var(--surface);
  color: var(--muted);
  font-size: 0.86rem;
  text-decoration: none;
}

.pill:hover { color: var(--parchment); }
.pill[aria-current="true"] { border-color: var(--moss); color: var(--parchment); background: var(--raised); }

.pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  color: var(--muted);
  font-size: 0.9rem;
  border-top: 1px solid var(--edge-soft);
}

.pager a { color: var(--gold); text-decoration: none; }
.pager a:hover { text-decoration: underline; }

[data-page-section] { position: relative; }

[data-page-section].loading::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 30;
  background: rgba(7, 11, 7, 0.62);
}

[data-page-section].loading::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 31;
  width: 30px;
  height: 32px;
  transform: translate(-50%, -50%);
  background: url("data:image/gif;base64,R0lGODlhHgAgAJkAAORcEP+gRACI/7j4GCH/C05FVFNDQVBFMi4wAwEAAAAh+QQJGQACACwAAAAAHgAgAAACqpSPo8uKD0+bI1pBc71JTx4EhgKU5lk6Qgix2IDGgOoirowDRn3cebwTPUKhUkhBDCADRmKL2FweB0VA8lnNQq1MLi+obYa9QmzyjK5a0uxzycJInpKMdyS+FSsXdsOPXYfilwPIR9gV41EVs4iiiGiCNgeJJxfpdnlSmZeJMoUj2TlJIhPaxEhJ4XPqmTqxeugB8ROlsdbWJwAU0daFsMsxeBJMrCtYbFAAACH5BAkZAAIALAIAAAAaACAAAAKjlG+jy4r/mhwQzktrwhKGsAHiSIqO8BmpoJQucK7rSwMqiOL1e9+f+FF8goMfYIhDAgPCYXMpGy6hgelx6KteqVYkAgkOg0VfsVlpixSlI2RrZFkbqW+yYBeWzGr5xnz7wvH3RyKoFUbyx2BHNahlssDY9jhZN3KSSLlkCWmQ6aLY4DkJStlxt3MlYTeKx9TAenCG0wr3MIvgorF7oMu762tQAAA7") center / 30px 32px no-repeat;
  image-rendering: pixelated;
  pointer-events: none;
}

/* ---------------------------------------------------------------- search */

.stats-search {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px;
  padding: 12px 14px;
  border: 1px solid var(--edge);
  background: var(--surface);
  margin: 0 0 26px;
}

.stats-search label { display: grid; gap: 5px; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.1em; color: var(--muted); }

.stats-search input {
  min-width: 13rem;
  padding: 9px 11px;
  border: 1px solid var(--edge);
  background: var(--ink);
  color: var(--parchment);
  font-family: var(--body);
  font-size: 1rem;
}

/* A suggestion has to read as a suggestion. This is the colour the front
   page uses in its own lookup box, so the two forms match. */
.stats-search input::placeholder { color: #6f7a63; opacity: 1; }
.stats-search .hint { font-weight: 400; text-transform: none; letter-spacing: 0; opacity: 0.75; }
.stats-search input:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }

.stats-search button {
  padding: 10px 18px;
  border: 1px solid var(--moss-bright);
  background: linear-gradient(180deg, var(--moss), #3d7222);
  color: #f2f7ec;
  font-family: var(--body);
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
}

.stats-search button:hover { background: linear-gradient(180deg, var(--moss-bright), var(--moss)); }

/* ---------------------------------------------------------------- charts */

.chart { margin: 0; padding: 10px 16px 6px; }
.chart svg { width: 100%; height: auto; overflow: visible; }

/* A calendar grid is drawn at the size its squares should be, so it is not
   stretched to the width of the page like a plot is. */
.chart svg.fit { width: auto; max-width: 100%; }
.chart figcaption { color: var(--muted); font-size: 0.85rem; margin-top: 6px; }
.chart-empty { color: var(--muted); padding: 14px 16px; margin: 0; }

.flagset-legend { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); gap: 8px 22px; list-style: none; margin: 0; padding: 12px 16px; }
.flagset-legend li { display: flex; align-items: center; gap: 8px; min-width: 0; font-size: 0.8rem; }
.flagset-legend .flag-swatch { width: 28px; height: 8px; flex: 0 0 28px; }
.flagset-legend a, .flagset-legend li > span:not(.flag-total) { overflow-wrap: anywhere; min-width: 0; }
.flagset-legend .flag-total { margin-left: auto; color: var(--muted); font-variant-numeric: tabular-nums; }
.flag-series:hover polyline { stroke-width: 3.5; }
.flag-series circle:hover { r: 5; }

.chart .line { fill: none; stroke: var(--moss-bright); stroke-width: 2; }
.chart .area { fill: rgba(126, 200, 80, 0.14); stroke: none; }
.chart .dot { fill: var(--moss-bright); }
.chart .dot.win { fill: var(--gold); }
.chart .dot.side-a { fill: var(--moss-bright); }
.chart .dot.side-b { fill: var(--gold); }
.chart .dot:hover { r: 4.5; }
.chart-race { cursor: pointer; }
.chart-hit { fill: transparent; stroke: none; }
.chart-race:hover .dot, .chart-race:focus .dot { r: 4.5; fill: var(--gold); opacity: 1; }
.chart-race:focus-visible .chart-hit { stroke: var(--gold); stroke-width: 1; }
.chart a .dot { cursor: pointer; }
.chart a:focus-visible .dot { stroke: var(--gold); stroke-width: 2; }
.chart .dot.dense { fill-opacity: 0.7; }
.chart .trend { stroke: var(--gold); stroke-width: 1.6; stroke-dasharray: 5 4; }
.chart .bar { fill: var(--moss); }
.chart .bar:hover { fill: var(--moss-bright); }
.chart .median { stroke: var(--gold); stroke-width: 2; }
.chart .box { fill: rgba(79, 143, 44, 0.3); stroke: var(--moss); }
.chart .whisker, .chart .whisker-cap, .chart .axis-line { stroke: var(--edge); stroke-width: 1.5; }
.chart .axis { fill: var(--muted); font-family: var(--body); font-size: 10px; }
.chart .axis.side-a { fill: var(--moss-bright); }
.chart .axis.side-b { fill: var(--gold); }

.chart .cell { fill: var(--raised); stroke: var(--edge); }
.chart .cell.level-1 { fill: rgba(79, 143, 44, 0.3); }
.chart .cell.level-2 { fill: rgba(79, 143, 44, 0.55); }
.chart .cell.level-3 { fill: var(--moss); }
.chart .cell.level-4 { fill: var(--moss-bright); }

.spark { width: 84px; height: 22px; vertical-align: middle; }
.spark polyline { fill: none; stroke: var(--moss-bright); stroke-width: 1.5; }
.spark-empty { color: var(--muted); }

.podium { width: 100%; height: 10px; display: block; margin-top: 4px; }
.podium .win { fill: var(--gold); }
.podium .second { fill: var(--moss-bright); }
.podium .third { fill: var(--moss); }
.podium .rest { fill: var(--edge); }
.podium .dnf { fill: var(--dodongo); }

.legend { display: flex; flex-wrap: wrap; gap: 12px; padding: 0 16px 14px; margin: 0; color: var(--muted); font-size: 0.82rem; }
.legend span::before { content: ""; display: inline-block; width: 10px; height: 10px; margin-right: 5px; vertical-align: baseline; }
/* A strip swatch keeps its own shape and edge inside a .legend, which is
   otherwise round-cornered squares with no border. */
.legend .k-won::before,
.legend .k-ran::before,
.legend .k-out::before { width: 10px; height: 12px; vertical-align: -1px; }
.legend .k-win::before { background: var(--gold); }
.legend .k-second::before { background: var(--moss-bright); }
.legend .k-third::before { background: var(--moss); }
.legend .k-rest::before { background: var(--edge); }
.legend .k-dnf::before { background: var(--dodongo); }

/* ------------------------------------------------------------- landing */

.leader-grid { display: grid; gap: 18px; align-items: start; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); }
.archive-note { color: var(--muted); margin: 0 0 24px; }

.stats-foot { padding-block: 26px 40px; border-top: 1px solid var(--edge); color: var(--muted); font-size: 0.9rem; }
.stats-foot p { margin: 0 0 6px; }
.stats-foot a { color: var(--gold); text-decoration: none; }
.stats-foot a:hover { text-decoration: underline; }

/* ------------------------------------------------------- the stats header

   The front page draws its hero on the 8x8 room grid every Z1R dungeon map
   uses. These pages are part of the same site, so the header wears it too —
   masked away at the edges so it reads as texture, not as a table. */

.stats-hero {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--edge);
  border-left: 3px solid var(--moss);
  background: var(--surface);
  padding: clamp(14px, 2vw, 20px) clamp(16px, 2.4vw, 22px);
  margin-bottom: 18px;
}

.stats-hero::before {
  content: "";
  position: absolute;
  inset: -2px;
  background-image:
    linear-gradient(to right, rgba(79, 143, 44, 0.15) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(79, 143, 44, 0.15) 1px, transparent 1px);
  background-size: 56px 56px;
  mask-image: radial-gradient(120% 100% at 15% 10%, #000 25%, transparent 80%);
  pointer-events: none;
}

.stats-hero > * { position: relative; }
.stats-hero h1 { margin-bottom: 2px; }
.stats-hero .lede { margin-bottom: 14px; max-width: 62ch; }
.stats-hero .stats-search { margin: 0; border-color: var(--edge-soft); background: rgba(10, 12, 9, 0.55); }

/* --------------------------------------------------------------- tables */

.panel table { table-layout: auto; }
.panel tbody tr + tr { border-top: 1px solid var(--edge-soft); }
.panel tbody tr:hover { background: rgba(79, 143, 44, 0.07); }
.panel td { padding: 7px 16px; vertical-align: middle; }
.panel th { padding: 8px 16px; }
.panel td.num, .panel th.num { text-align: right; font-variant-numeric: tabular-nums; }
.panel td.clock { font-family: var(--mono); font-size: 0.86rem; font-variant-numeric: tabular-nums; }

/* The rank column reads as furniture, not as data: mono, quiet, narrow. */
.panel td.rank, .panel th.rank { width: 2.4rem; color: var(--muted); font-family: var(--mono); font-size: 0.8rem; }
.panel tr.first td.rank { color: var(--gold); }

/* A placing is worth a glance without reading the number. */
.place-1 { color: var(--gold); font-weight: 600; }
.place-2 { color: var(--parchment); }
.place-3 { color: var(--moss-bright); }
.place-dnf { color: var(--dodongo); }

/* Second of eight is a result; second of two is a coin toss. */
.of { color: var(--muted); font-weight: 400; }

/* The racer whose page this is, highlighted in their own tables the way the
   standings mark a qualifying team. */
.panel tr.self { background: rgba(217, 164, 65, 0.08); }
.panel tr.self td:first-child { box-shadow: inset 3px 0 0 var(--gold); }

/* --------------------------------------------------------- chips and tags */

.badge {
  display: inline-block;
  padding: 1px 7px;
  border: 1px solid var(--edge);
  background: var(--raised);
  color: var(--muted);
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  vertical-align: 1px;
}

.badge.rt { border-color: rgba(79, 143, 44, 0.6); color: var(--moss-bright); }
.badge.srl { border-color: rgba(217, 164, 65, 0.5); color: var(--gold); }

/* A flag string is what somebody pastes into a randomizer, so it is shown
   whole and wraps rather than being cut off with an ellipsis that hides the
   half that matters. */
.chip {
  display: inline-block;
  max-width: 100%;
  overflow-wrap: anywhere;
  padding: 1px 8px;
  border: 1px solid var(--edge);
  background: var(--ink);
  color: var(--muted);
  font-family: var(--mono);
  font-size: 0.76rem;
  text-decoration: none;
  vertical-align: 1px;
}

a.chip:hover { border-color: var(--moss); color: var(--parchment); }

/* ------------------------------------------------------------ form strip

   The last dozen races, newest last, as one block each: won, finished, or
   did not finish. Hovering names the race; the shape is the point. */

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.form { display: flex; gap: 3px; flex-wrap: wrap; padding: 12px 16px; }

.form { gap: 2px; padding: 10px 16px; }

.form a {
  width: 11px;
  height: 16px;
  border: 1px solid var(--edge);
  background: var(--raised);
  text-decoration: none;
}

/* Gold, because that is what a win is everywhere else on the page.
   It was --moss-bright, which the Placings chart two panels along uses for
   SECOND -- so a won race was painted in the colour its neighbour reserves for
   not quite winning, and the legend above it said gold. Shatty caught it from
   the two charts disagreeing. */
.form a.won { background: var(--gold); border-color: var(--gold); }
.form a.finished { background: rgba(79, 143, 44, 0.45); border-color: var(--moss); }
.form a.dnf { background: transparent; border-color: var(--dodongo); }
.form a:hover { outline: 1px solid var(--gold); }

/* ----------------------------------------------------------- race rows

   Head to head, laid out the way the front page lays out a League game:
   name, time, time, name, with the winner in moss and the loser muted. */

.races { padding: 2px 16px 10px; }

/* A list of head-to-head races is read down the column of times, so the rows
   sit close together and the line under each one carries the rest. */
.races .race-grid { margin-top: 6px; padding-top: 6px; row-gap: 1px; border-top: 1px solid var(--edge-soft); }
.races .race-grid .cell { font-size: 0.9rem; }
.races .race-grid:first-child { border-top: 0; }
.races .meta { grid-column: 1 / -1; color: var(--muted); font-size: 0.74rem; display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline; }
.races .meta a { color: var(--muted); text-decoration: none; }
.races .meta a:hover { color: var(--parchment); text-decoration: underline; }

/* A day of racing, on the recent page. */
.day-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin: 22px 0 0;
  padding: 10px 16px;
  border: 1px solid var(--edge);
  border-bottom: 0;
  background: var(--raised);
  font-family: var(--display);
  font-size: 1rem;
}

/* The heading over a day of racing is a label, not a page title: the site
   sets h3 in display type at a size that suits a panel head, which over a
   list of cards reads as a shout. */
.day-head h3 { margin: 0; font-size: 0.96rem; font-weight: 500; letter-spacing: 0.02em; }
.day-head span { font-family: var(--mono); font-size: 0.75rem; color: var(--muted); }
.day-head time { color: inherit; }
.day-head + .panel { margin-top: 0; }

/* --------------------------------------------------------------- charts */

.chart .line.thin { stroke: var(--gold); stroke-width: 1.4; opacity: 0.85; }
.chart .bar { fill: rgba(79, 143, 44, 0.75); }
.chart figcaption { font-family: var(--mono); font-size: 0.78rem; }
.chart .axis { font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.02em; }

/* ------------------------------------------------------------ race cards

   A race the way the schedule cards on the front page show a fixture: what
   it was called, when it ran, and who was in it. The result sits behind a
   fold, so the list works for somebody catching up on races they have not
   watched. */

.race-list {
  display: grid;
  gap: 12px;
  align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(min(330px, 100%), 1fr));
  padding: 14px 16px;
}

.race-card {
  display: grid;
  gap: 7px;
  padding: 13px 15px;
  border: 1px solid var(--edge);
  border-left: 3px solid var(--moss);
  background: var(--ink);
}

.race-card-head { display: grid; gap: 3px; }
.race-card-head h3 { margin: 0; font-size: 1rem; font-family: var(--display); letter-spacing: 0.01em; }
.race-card-head h3 a { color: var(--parchment); text-decoration: none; }
.race-card-head h3 a:hover { color: var(--moss-bright); text-decoration: underline; }
.race-card-head .when { color: var(--gold); font-family: var(--mono); font-size: 0.76rem; }
.race-card-head .race-note { color: var(--muted); font-size: 0.84rem; }

.race-card .field { margin: 0; font-size: 0.92rem; line-height: 1.5; }
.race-card .field a { color: var(--parchment); text-decoration: none; }
.race-card .field a:hover { color: var(--moss-bright); text-decoration: underline; }
.race-card .muted { color: var(--muted); }

.race-card-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  color: var(--muted);
  font-size: 0.76rem;
}

.race-card-foot .mono { font-size: 0.76rem; }

/* The fold. <details> needs no script, and the marker is the affordance. */
.spoiler { border-top: 1px solid var(--edge-soft); padding-top: 8px; }

.spoiler summary {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 0.76rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  list-style: none;
}

.spoiler summary::-webkit-details-marker { display: none; }

/* One marker, drawn at a fixed size, turned in place — the browser's own
   swaps glyphs when the fold opens and the text steps sideways. */
.spoiler summary::before {
  content: "";
  flex: none;
  width: 0;
  height: 0;
  border-left: 5px solid currentColor;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  transform-origin: 2px 50%;
  transition: transform 0.12s ease-out;
}

.spoiler[open] summary::before { transform: rotate(90deg); }

.spoiler summary:hover { color: var(--gold); }
.spoiler[open] summary { color: var(--gold); margin-bottom: 4px; }
.spoiler table { font-size: 0.88rem; }
.spoiler td { padding: 3px 8px 3px 0; vertical-align: middle; }
.spoiler td:first-child { width: 2.2rem; }
.spoiler td.clock { text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* -------------------------------------------------------- sortable tables */

.panel th a { color: inherit; text-decoration: none; }
.panel th a:hover { color: var(--parchment); text-decoration: underline; }
.panel th[aria-sort] { color: var(--gold); }
.panel th[aria-sort] a { color: var(--gold); }

/* A note under a table that explains what a column means. */
.table-note { padding: 0 16px 12px; margin: 0; color: var(--muted); font-size: 0.8rem; }

/* What a block in a form strip looks like, said once.
   These are the .form a colours above and nothing else, because a legend for
   that strip has exactly one correct answer. They were written out a second
   time scoped to .table-note, which left the racer page's "Last ten races"
   panel with no swatches of its own -- so its legend reached for the Placings
   palette instead and told everybody a win was gold while the strip beside it
   drew wins green. Shatty spotted it from the two charts disagreeing on one
   page. Unscoped, so the next legend that labels a strip cannot repeat it. */
.k-won::before,
.k-ran::before,
.k-out::before {
  content: "";
  display: inline-block;
  width: 10px;
  height: 12px;
  margin-right: 5px;
  vertical-align: -1px;
  border: 1px solid var(--edge);
}
.k-won::before { background: var(--gold); border-color: var(--gold); }
.k-ran::before { background: rgba(79, 143, 44, 0.45); border-color: var(--moss); }
/* Transparent with a red edge, exactly as .form a.dnf draws it -- a solid red
   block is a different thing on this page and belongs to Placings. */
.k-out::before { background: transparent; border-color: var(--dodongo); }

/* ---------------------------------------------------------- chart legends */

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  padding: 0 16px 12px;
  margin: 0;
  color: var(--muted);
  font-size: 0.8rem;
}

.chart-legend span::before { content: ""; display: inline-block; width: 12px; height: 10px; margin-right: 6px; vertical-align: 0; }
.chart-legend .k-bar::before { background: rgba(79, 143, 44, 0.75); }
.chart-legend .k-line::before { height: 2px; background: var(--gold); vertical-align: 4px; }
.chart-legend .k-dot::before { width: 10px; height: 10px; border-radius: 50%; background: var(--moss-bright); }
.chart-legend .k-win::before { width: 10px; height: 10px; border-radius: 50%; background: var(--gold); }
.chart-legend .k-trend::before { height: 2px; background: var(--gold); vertical-align: 4px; }
.chart-legend .k-median::before { width: 3px; height: 12px; background: var(--gold); }
.chart-legend .k-side-a::before { background: var(--moss-bright); }
.chart-legend .k-side-b::before { background: var(--gold); }
.chart-legend .k-heat::before, .chart-legend [class^="k-heat-"]::before { width: 12px; height: 12px; border: 1px solid var(--edge); }
.chart-legend .k-heat::before { background: var(--raised); }
.chart-legend .k-heat-1::before { background: rgba(79, 143, 44, 0.3); }
.chart-legend .k-heat-2::before { background: rgba(79, 143, 44, 0.55); }
.chart-legend .k-heat-3::before { background: var(--moss); }
.chart-legend .k-heat-4::before { background: var(--moss-bright); }
.chart-legend [class^="k-heat-"] { margin-left: -10px; }
.chart-legend .k-heat-4 { margin-right: 0; }

/* A hovered month lifts a card out of the chart rather than waiting on the
   browser's own tooltip, which arrives late and says the wrong thing. */
/* Anything with a hover card is a hit target, and the card sits over the
   chart rather than waiting on the browser own tooltip. */
.chart .hit rect.hit-area { fill: transparent; }
.chart .hit:hover .dot { r: 4; }
.chart .hit:hover rect.hit-area { fill: rgba(126, 200, 80, 0.08); }
.chart .hit rect.hit-cell { transition: stroke 0.08s ease-out; }
.chart .hit:hover rect.hit-cell { stroke: var(--gold); }
.chart .callout { opacity: 0; transition: opacity 0.08s ease-out; pointer-events: none; }
.chart .hit:hover .callout { opacity: 1; }
.chart .callout rect { fill: var(--raised); stroke: var(--moss); }
.chart .callout text { fill: var(--parchment); font-family: var(--mono); font-size: 9px; }
.chart .callout text.sub { fill: var(--muted); }

/* ---------------------------------------------------- seeds and flagsets

   The two things people take from a race to run it themselves. Shown whole,
   in mono, with a button that copies them — the button is revealed by the
   one script the shell carries, so it never appears dead. */

.race-refs { display: grid; gap: 6px; margin: 0; padding: 0; }

/* In a table the refs are a second line of the row rather than a block of
   their own, so they sit tighter and lose their labels’ width. */
.c-refs .race-refs { gap: 2px; }
.c-refs .ref dt { min-width: 2.6rem; font-size: 10px; }
.c-refs .ref-value { font-size: 0.72rem; }
.c-refs .chip { font-size: 0.7rem; }
.c-refs .copy, .c-refs .reveal { width: 18px; height: 18px; }
.c-refs .copy .icon, .c-refs .reveal .icon { width: 11px; height: 11px; }
table.race-rows .c-refs-head { white-space: nowrap; }
table.race-rows .c-refs .ref-value, table.race-rows .c-refs .chip { white-space: nowrap; }
table.race-rows .c-race { overflow-wrap: anywhere; }
table.race-rows .c-time { white-space: nowrap; vertical-align: top; }
.time-place { display: block; margin-top: 2px; font-size: 0.78rem; }
.ref { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; }
.ref dt { color: var(--muted); font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.1em; min-width: 3.1rem; }
.ref dd { display: flex; align-items: center; gap: 6px; margin: 0; min-width: 0; flex: 1 1 14rem; }
.ref-value { font-family: var(--mono); font-size: 0.78rem; color: var(--parchment); overflow-wrap: anywhere; }

.copy, .reveal {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 1px solid var(--edge);
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
}

.copy:hover, .reveal:hover { border-color: var(--moss); color: var(--moss-bright); }
.copy:focus-visible, .reveal:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }
.copy .icon, .reveal .icon { width: 13px; height: 13px; }

/* Pressed, the eye is showing the string rather than the name -- gold, because
   what is in the box is no longer the friendly thing. */
.reveal.on { border-color: var(--gold); color: var(--gold); }
.copy.done { border-color: var(--moss-bright); color: var(--moss-bright); }
.copy.done .icon { display: none; }
.copy.done::after { content: "✓"; font-size: 12px; }

/* When the clipboard refuses, the value beside the button is selected
   instead, and the button says so rather than appearing to do nothing. */
.copy.picked { border-color: var(--gold); color: var(--gold); }
.copy.picked .icon { display: none; }
.copy.picked::after { content: "⌘"; font-size: 11px; }
.ref-value::selection, .chip::selection { background: var(--moss); color: #f2f7ec; }

/* racetime's own mark on a link to their room. */
.rt-link { text-decoration: none; }
.rt-link .icon { width: 14px; height: 14px; vertical-align: -0.2em; margin-right: 3px; }

/* ------------------------------------------------------ filtering a list */

.filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px;
  padding: 14px 16px;
  border: 1px solid var(--edge);
  background: var(--surface);
  margin: 0 0 14px;
}

.filters label { display: grid; gap: 4px; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.1em; color: var(--muted); }

.filters input, .filters select {
  min-width: 11rem;
  padding: 7px 9px;
  border: 1px solid var(--edge);
  background: var(--ink);
  color: var(--parchment);
  font-family: var(--body);
  font-size: 0.95rem;
}

.filters input:focus-visible, .filters select:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }

.filters button {
  padding: 8px 16px;
  border: 1px solid var(--moss-bright);
  background: linear-gradient(180deg, var(--moss), #3d7222);
  color: #f2f7ec;
  font-family: var(--body);
  font-weight: 600;
  cursor: pointer;
}

.filter-actions { display: flex; align-items: center; gap: 10px; }
.filters .clear { color: var(--gold); font-size: 0.88rem; text-decoration: none; }
.filters .clear:hover { text-decoration: underline; }

/* A plain dropdown below the focus outline; no native popup notch or arrow. */
.stats-autocomplete { position: relative; min-width: 0; max-width: 100%; }
.stats-autocomplete input { box-sizing: border-box; width: 100%; }
.filters .flags-autocomplete { flex: 1 1 18rem; max-width: 26rem; }
.autocomplete-options {
  position: absolute; top: calc(100% + 7px); left: 0; right: 0; z-index: 20;
  max-height: min(18rem, 35dvh); overflow-y: auto; overscroll-behavior: contain;
  margin: 0; padding: 4px; list-style: none;
  border: 1px solid var(--edge); background: var(--surface);
  box-shadow: 0 8px 20px #0008; color: var(--parchment);
  font: 0.95rem var(--body); letter-spacing: normal; text-transform: none;
}
.autocomplete-options[hidden] { display: none; }
.autocomplete-options.above { top: auto; bottom: calc(100% + 7px); }
.autocomplete-options li { display: grid; gap: 3px; padding: 9px 8px; cursor: pointer; overflow-wrap: anywhere; }
.autocomplete-options li:hover, .autocomplete-options li[aria-selected="true"] { background: var(--raised); color: var(--gold); }
.autocomplete-options small { color: var(--muted); font-size: 0.75rem; }
.flags-autocomplete .autocomplete-options small { font-family: var(--mono); }
@media (max-width: 620px) {
  .filters .stats-autocomplete { flex: 1 1 100%; max-width: none; }
  .stats-autocomplete input { font-size: 16px; }
}

/* ------------------------------------------------------- compact tables

   A leaderboard and the who-is-racing table are read at a glance and hold
   short values, so they lose a line of leading and some of their gutters.
   Everything else keeps the roomier default. */

.panel table.compact { font-size: 0.92rem; }
.panel table.compact td { padding: 3px 12px; }
.panel table.compact th { padding: 6px 12px; }
.panel table.compact td.rank, .panel table.compact th.rank { width: 2rem; padding-right: 4px; }
.panel table.compact .form { padding: 0; gap: 2px; flex-wrap: nowrap; }

/* The last race's name is a label here, held to one line so it cannot push
   the columns beside it around. */
.last-raced { max-width: 17rem; }
.last-raced .stat-note { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.panel table.compact .form a { width: 9px; height: 13px; }
.panel table.compact .stat-note { font-size: 0.76rem; }
.panel table.compact time { font-size: 0.86rem; }

/* --------------------------------------------------------- trend charts

   Three views of the same months, read against each other, so they sit in
   a row at the size of the calendar beside them rather than filling the
   page one under the other. */

.trend-grid {
  display: grid;
  gap: 6px 14px;
  align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  padding: 4px 4px 8px;
}

.trend-grid .chart { padding: 6px 10px; }

/* Each of the three says which it is, above the line it draws. */
.chart-head {
  display: block;
  margin-bottom: 2px;
  color: var(--parchment);
  font-family: var(--display);
  font-size: 0.9rem;
  letter-spacing: 0.02em;
}
.trend-grid figcaption { font-size: 0.74rem; }

/* ------------------------------------------------------------- a phone

   A table with five columns of race names and times is wider than a phone
   however tightly it is set, so the table scrolls inside its panel rather
   than taking the page sideways with it. */

/* ------------------------------------------------------- seeds and names

   A race name, a twenty-digit seed and a forty-character flag string do not
   sit across a page in three columns, so each race is a block: what it was,
   then the two things somebody copies to run it. */

.seed-list { display: grid; gap: 10px; padding: 12px 16px; }
.seed-row { display: grid; gap: 5px; padding-bottom: 10px; border-bottom: 1px solid var(--edge-soft); }
.seed-row:last-child { padding-bottom: 0; border-bottom: 0; }
.seed-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; font-size: 0.92rem; }
.seed-head .when { color: var(--muted); font-family: var(--mono); font-size: 0.76rem; }

/* A flagset is known by a name where it has one; the string stays under it,
   because the string is what gets copied. */
.flagset-cell { display: grid; gap: 2px; }
.flagset-cell .ref-value { font-size: 0.72rem; color: var(--muted); overflow-wrap: anywhere; }

/* The short form of a timestamp, and of anything else that carries both.
   The site does this with its own nav labels; these follow it. */
.short { display: none; }

/* ------------------------------------------------------- the racer card

   A name with a card behind it. No script: the card is in the markup and
   the hover opens it, which also means the keyboard opens it, because
   focus-within counts. It is drawn where a reader is choosing between
   racers — a board, a table — not beside every name in a race's field. */

.has-card { position: relative; display: inline-block; }

/* The main site's legacy card styles also arrive via /styles.css.
   Keep the fallback hidden until the later, shared card.css opts it in. */
.racer-card[hidden] { display: none; }

.racer-card {
  position: absolute;
  z-index: 20;
  top: calc(100% + 6px);
  left: 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.1s ease-out 0.12s, visibility 0s linear 0.22s;
}

/* The six pixels between the name and the card would close it as the
   pointer crossed them. */
.racer-card::before { content: ""; position: absolute; left: 0; right: 0; top: -8px; height: 8px; }

.has-card:hover .racer-card, .has-card:focus-within .racer-card { opacity: 1; visibility: visible; transition-delay: 0.04s, 0s; }

/* Near the right edge a card would hang off the page, so the last column
   opens its card leftwards. */
td:last-child .racer-card, .leader-grid .racer-card { left: auto; right: 0; }

/* Where else a racer is: Twitch in its own purple, racetime in the moss
   the rest of the page uses, SRL as a badge because it is not a link. */
/* A racer’s own page leads with the picture they race under. */
.racer-hero { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; margin-bottom: 4px; }
.racer-hero .portrait { width: 96px; height: 96px; object-fit: cover; border-radius: 50%; flex: none; background: var(--ink-soft); }
.racer-hero .racer-who { min-width: 0; }
.racer-hero h1 { margin: 0; }
.racer-hero .pronouns { margin: 2px 0 0; color: var(--muted); font-size: 0.84rem; }
.racer-hero .where { margin: 10px 0 0; }
@media (max-width: 560px) {
  .racer-hero { gap: 12px; }
  .racer-hero .portrait { width: 64px; height: 64px; }
}

/* A race in a row: its name, then the room and date, then recordings. */
.race-call { display: block; color: var(--parchment); }
.race-where { display: block; margin-top: 2px; font-size: 0.78rem; color: var(--muted); }
.race-where a { color: var(--muted); }
.race-where a:hover { color: var(--moss-bright); }
.race-where time { white-space: nowrap; }
.race-vods { display: block; margin-top: 2px; font-size: 0.78rem; }

/* “Compare →” is a whole phrase; a narrow column may not break it. */
.c-go { white-space: nowrap; }

.where { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 18px; }

.where-pill {
  padding: 3px 10px;
  border: 1px solid var(--edge);
  background: var(--surface);
  color: var(--muted);
  font-family: var(--mono);
  font-size: 0.74rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}

a.where-pill:hover { border-color: currentColor; }
.where-pill.twitch { border-color: rgba(145, 70, 255, 0.55); color: #a970ff; }
.where-pill.twitch:hover { background: rgba(145, 70, 255, 0.12); }
.where-pill.rt { border-color: rgba(79, 143, 44, 0.6); color: var(--moss-bright); }
.where-pill.rt:hover { background: rgba(79, 143, 44, 0.12); }
.where-pill.srl { border-color: rgba(217, 164, 65, 0.5); color: var(--gold); }
a.where-pill.srl:hover { background: rgba(217, 164, 65, 0.12); }
/* A recording, beside the room it was raced in. */
.yt-link { color: #ff6b6b; text-decoration: none; white-space: nowrap; }
.yt-link:hover { text-decoration: underline; }
/* Panel and race-meta link rules are more specific than .yt-link, so the
   recording needs to win explicitly: it should pop beside the gray room. */
.panel td a.yt-link, .race-meta a.yt-link, .race-card-foot a.yt-link { color: #ff6b6b; }
.panel td a.yt-link:hover, .race-meta a.yt-link:hover, .race-card-foot a.yt-link:hover { color: #ff8a8a; }
.yt-link .icon { width: 15px; height: 15px; vertical-align: -0.2em; margin-right: 2px; }
.card-vods { flex-basis: 100%; }
.card-vods .yt-link { font-size: 0.78rem; }

/* The line under the title can run to two rows once it carries a room and
   a recording or two, so what follows it keeps its distance. */
.race-meta { line-height: 1.9; }
.race-head .race-refs { margin-top: 10px; }

@media (max-width: 720px) {
  .panel td, .panel th { padding-inline: 10px; }
  .race-list { padding: 10px; }

  /* A table that still will not fit scrolls inside the panel, with its
     head and body together so the columns stay lined up. */
  .panel { overflow-x: auto; }
}

@media (max-width: 620px) {
  .full { display: none; }
  .short { display: inline; }

  /* Who is racing lately has seven columns, which is four too many for a
     phone however small the type. Each row becomes two lines: who they are
     and when they last raced, then their races, their wins and their last
     ten. The win rate goes — it is the one number a reader can work out
     from the two beside it. */
  table.stacked, table.stacked tbody, table.stacked tr, table.stacked td { display: block; }
  table.stacked thead { display: none; }
  table.stacked tbody { display: grid; }
  table.stacked tbody tr + tr { border-top: 0; }

  table.stacked tr {
    display: grid;
    grid-template-columns: 1.5rem auto auto 1fr;
    grid-template-areas: "rank racer racer last" "rank races wins form";
    gap: 2px 8px;
    padding: 8px 12px;
    align-items: center;
  }

  table.stacked td { padding: 0; border-top: 0; }
  table.stacked .c-rank { grid-area: rank; }
  table.stacked .c-racer { grid-area: racer; font-size: 0.98rem; }
  table.stacked .c-races { grid-area: races; }
  table.stacked .c-wins { grid-area: wins; }
  table.stacked .c-rate { display: none; }
  table.stacked .c-form { grid-area: form; justify-self: end; }
  table.stacked .c-last { grid-area: last; text-align: right; max-width: none; }

  table.stacked .c-races, table.stacked .c-wins {
    text-align: left;
    color: var(--muted);
    font-size: 0.78rem;
  }

  table.stacked .c-races::after, table.stacked .c-wins::after { content: " " attr(data-label); }
  table.stacked .c-last .stat-note { display: none; }
  table.stacked .c-last a { font-family: var(--mono); font-size: 0.76rem; }
  table.stacked .form { flex-wrap: nowrap; gap: 1px; }
  table.stacked .form a { width: 8px; height: 12px; }

  /* A racer’s own races: the three-line race label and its compact result,
     then the seed and flags at the full row width. */
  table.race-rows, table.race-rows tbody, table.race-rows tr, table.race-rows td { display: block; }
  table.race-rows thead { display: none; }
  table.race-rows tbody { display: grid; }

  table.race-rows tr {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas: "race time" "refs refs";
    gap: 1px 10px;
    padding: 8px 12px;
    border-top: 1px solid var(--edge-soft);
  }

  table.race-rows td { padding: 0; }
  table.race-rows .c-race { grid-area: race; overflow-wrap: anywhere; }
  table.race-rows .c-time { grid-area: time; text-align: right; }
  table.race-rows .c-field { display: none; }

  /* The seed and flags take the width of the row, under the rest of it:
     they are the longest thing here and the reason somebody scrolled to
     this list. */
  table.race-rows .c-refs { grid-area: refs; padding-top: 4px; }
  /* A leaderboard is three columns and fits as it is; anything else that
     still does not keeps the panel scroll from the rule above, so the page
     itself never goes sideways. */
  .panel > table:not(.stacked) { font-size: 0.86rem; }

  table.race-rows .time-place .of { font-size: 0.9em; }
}

@media (max-width: 620px) {
  /* Nothing here should scroll sideways. A table that does is a table with
     one column too many for the screen, so the columns give way rather than
     the reader having to drag the panel about.

     Behind goes: it is Together minus Ahead, the same reasoning that drops
     the win rate from the stacked table above. And Compare keeps its arrow
     and loses its word -- the whole row is a link to that comparison, so the
     arrow is label enough beside four numbers. */
  table.rivals .c-behind { display: none; }
  table.rivals .go-word { display: none; }
  table.rivals th, table.rivals td { padding-inline: 8px; }

  /* The seed and the flag string are each held on one line so they can be
     copied in one go. On a phone either line is wider than the phone -- a
     flag string runs to thirty characters and more -- so both wrap. The copy
     button beside them is how anybody sane takes either one anyway. */
  table.race-rows .c-refs .ref-value,
  table.race-rows .c-refs .chip { white-space: normal; overflow-wrap: anywhere; }

  .stat-value { font-size: 1.28rem; }
  table { font-size: 0.92rem; }
  th, td { padding-inline: 10px; }
  .hide-narrow { display: none; }
  .races .race-grid { grid-template-columns: minmax(0, 1fr) 4.4rem 4.4rem minmax(0, 1fr); column-gap: 8px; }
  .races .race-grid .name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .stats-hero { padding-inline: 16px; }
}
