/* =========================================================================
   Luonnollinen karsinta, /luonnollinen-karsinta/
   =========================================================================

   Loaded after site.css, which supplies the tokens, fonts, focus ring and
   base type. This file makes the race a standalone night page: the controls
   bar on top, a stage of E3d cover rows merged with E3c bars, full page mode,
   and the fixed capture stages for the MP4s.

   Rules that are easy to erode:

     - Motion is script-driven. Rows move by the --y custom property that
       stage.js sets every frame. A CSS transition here would make a frame
       depend on the frame before it, and the capture would stop being
       repeatable.

     - The static top 20 in index.html and the live rows share every class and
       every size. The loader hands over from one to the other, and if their
       row heights differ by a pixel the whole stage jumps.

     - No radius and no shadows, as everywhere on the site. The one exception
       is the round Martti loader, styled inline in index.html.

     - --gold is text and fill on the night ground only. The focus ring uses
       --gold-rule, as the rest of the site does.

   Row metrics are tokens on .race, set per band below, and per stage layout
   (capture and full page) from --row-h, which main.js computes from race.json.
   ========================================================================= */

/* ---------- page ----------
   Standalone: the night ground runs the whole page, and past it when a phone
   overscrolls, and the race section is the page. site.css centres .wrap and
   pads .page-full .full, both undone here. */
html:has(> body.race-page) { background: var(--night); }
.race-page { background: var(--night); color: var(--on-dark); min-height: 100vh; }
.race-page .wrap.full { max-width: none; padding: 0; }

/* Present for screen readers and search engines, never drawn. */
.race-title {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* ---------- stage tokens: desktop, above 900px ---------- */
.race {
  --rows: 20;
  --row-h: 64px;
  --cover: 54px;
  --col-gap: 18px;
  --bar-min: 140px;
  --cols: 2.4rem var(--cover) minmax(0, 1.3fr) minmax(var(--bar-min), 1fr) 4.2rem 6.6rem;
  --fs-rank: 24px;
  --fs-name: 20px;
  --fs-album: 14px;
  --fs-avg: 17px;
  --fs-n: 14px;

  background: var(--night);
  color: var(--on-dark);
}

/* hidden has to win over the display values below. */
.race [hidden] { display: none !important; }

.race :focus-visible {
  outline: 2px solid var(--gold-rule);
  outline-offset: 3px;
}

.race__stage {
  position: relative;
  padding: clamp(18px, 2.6vw, 30px) clamp(14px, 2.8vw, 34px) clamp(16px, 2vw, 22px);
}

/* ---------- head: the moment on screen ---------- */
.race__head {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 24px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--night-rule);
}
.race__brand { display: none; }
.race__when {
  margin: 0;
  font: 500 clamp(26px, 3.4vw, 40px)/1.05 var(--display);
  color: var(--on-dark);
  letter-spacing: -.01em;
  font-variant-numeric: tabular-nums lining-nums;
}
/* A key for the two figure columns, which lose their unit on narrow rows. */
.race__legend {
  margin: 0 0 0 auto;
  font: 600 11px/1.2 var(--text);
  text-transform: uppercase; letter-spacing: .16em;
  color: var(--on-dark-3);
}

/* ---------- rows: E3d cover rows with E3c bars ---------- */
.race__rows { list-style: none; margin: 0; padding: 0; }

.race__row {
  display: grid;
  grid-template-columns: var(--cols);
  column-gap: var(--col-gap);
  align-items: center;
  height: var(--row-h);
  border-bottom: 1px solid var(--night-rule-2);
  /* Opaque, so a row sliding past another covers it instead of mixing text. */
  background: var(--night);
}

.race__rank {
  font: 500 var(--fs-rank)/1 var(--display);
  color: var(--gold);
  text-align: right;
  font-variant-numeric: tabular-nums lining-nums;
}

.race__cover {
  width: var(--cover); height: var(--cover); max-width: none;
  object-fit: cover;
  border: 1px solid var(--night-rule);
  /* Also the placeholder: a cover that fails to load shows this square. */
  background: var(--night-2);
}

.race__title {
  min-width: 0;
  display: flex; flex-direction: column; justify-content: center; gap: 3px;
}
.race__name {
  font: 500 var(--fs-name)/1.15 var(--display);
  color: var(--on-dark);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.race__album {
  font-size: var(--fs-album); line-height: 1.25;
  color: var(--on-dark-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* The rating scale, 4 to 10. The fill is a width so the static rows can carry
   it inline without script. */
.race__bar {
  position: relative; display: block;
  height: 8px;
  background: var(--night-rule);
}
.race__fill {
  position: absolute; top: 0; bottom: 0; left: 0;
  background: var(--gold);
}

.race__avg {
  font: 600 var(--fs-avg)/1 var(--text);
  color: var(--on-dark);
  text-align: right;
}
.race__n {
  font-size: var(--fs-n); line-height: 1;
  color: var(--on-dark-3);
  text-align: right;
  white-space: nowrap;
}

/* ---------- static list and live rows ----------
   Before ready the static list holds the stage open under the loader. After
   it the live rows take the same height, and the static list stays in the
   document, visually hidden, as the text version of the final result. */
.race__rows--live {
  display: none;
  position: relative;
  height: calc(var(--rows) * var(--row-h));
  overflow: hidden;
  /* Row stacking stays inside the list, so no row can draw over the intro
     card or the loader whatever its --z. */
  isolation: isolate;
}
.race.is-ready .race__rows--live { display: block; }
.race.is-ready .race__rows--static {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.race__rows--live .race__row {
  position: absolute; top: 0; left: 0; right: 0;
  transform: translateY(calc(var(--y, 0) * var(--row-h)));
}
/* Stacking comes from the frame state (timeline.js drawOrder): a song appearing
   for the first time on top, then the rows travelling furthest. */
.race__rows--live .race__row { z-index: var(--z, 0); }

/* ---------- foot ---------- */
.race__foot { padding-top: 14px; }
.race__population { margin: 0; font-size: 14px; color: var(--on-dark-3); }
.race__credit, .race__card { display: none; }

/* ---------- controls, above the stage ---------- */
.race__controls {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 14px 22px;
  padding: 16px clamp(14px, 2.8vw, 34px);
  border-bottom: 1px solid var(--night-rule);
}

.race__button {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  min-height: 44px; min-width: 44px; margin: 0; padding: 0 18px;
  border: 1px solid var(--night-rule); border-radius: 0;
  background: transparent; color: var(--on-dark);
  font: 600 12px/1 var(--text); text-transform: uppercase; letter-spacing: .1em;
  text-decoration: none; cursor: pointer;
}
.race__button:hover { background: var(--on-dark); border-color: var(--on-dark); color: var(--night); }

.race__play { min-width: 9.5rem; border-color: var(--gold); color: var(--gold); }
.race__play:hover { background: var(--gold); border-color: var(--gold); color: var(--night); }
.race__icon { flex: 0 0 auto; display: block; }
.race__icon--pause, .race__play.is-playing .race__icon--play { display: none; }
.race__play.is-playing .race__icon--pause { display: block; }

/* Speed: one strip of five buttons, the chosen one inverted. */
.race__speed { display: flex; align-items: center; margin: 0; }
.race__speed-label {
  margin-right: 12px;
  font: 600 11px/1.2 var(--text);
  text-transform: uppercase; letter-spacing: .16em;
  color: var(--on-dark-3);
}
.race__speed-option { padding: 0 10px; letter-spacing: 0; text-transform: none; font-size: 13px; }
.race__speed-option + .race__speed-option { margin-left: -1px; }
.race__speed-option[aria-pressed="true"] { background: var(--on-dark); border-color: var(--on-dark); color: var(--night); }

/* The date label rides above the thumb. Its anchor moves from its left edge at
   the start to its right edge at the end, so it never leaves the track. */
.race__scrub {
  position: relative;
  flex: 1 1 18rem; min-width: 0;
  padding-top: 22px;
}
.race__thumb {
  position: absolute; top: 0;
  left: calc(var(--progress, 1) * (100% - 16px) + 8px);
  transform: translateX(calc(var(--progress, 1) * -100%));
  font: 400 13px/1 var(--text);
  color: var(--on-dark-3);
  white-space: nowrap;
  pointer-events: none;
}

.race__range {
  -webkit-appearance: none; appearance: none;
  display: block; width: 100%; height: 44px; margin: 0;
  background: transparent; cursor: pointer;
}
.race__range::-webkit-slider-runnable-track {
  height: 4px;
  background: linear-gradient(to right,
    var(--gold) calc(var(--progress, 1) * 100%),
    var(--night-rule) calc(var(--progress, 1) * 100%));
}
.race__range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 16px; height: 24px; margin-top: -10px;
  background: var(--on-dark); border: 0; border-radius: 0;
}
.race__range::-moz-range-track { height: 4px; background: var(--night-rule); }
.race__range::-moz-range-progress { height: 4px; background: var(--gold); }
.race__range::-moz-range-thumb {
  width: 16px; height: 24px;
  background: var(--on-dark); border: 0; border-radius: 0;
}
.race__range:focus-visible { outline-offset: 0; }

.race__end {
  display: flex; flex-wrap: wrap; gap: 10px;
  margin: 0;
}

/* ---------- tablet, 600 to 900px ---------- */
@media (max-width: 900px) {
  .race {
    --row-h: 44px;
    --cover: 36px;
    --col-gap: 12px;
    --bar-min: 80px;
    --cols: 1.8rem var(--cover) minmax(0, 1.5fr) minmax(var(--bar-min), 1fr) 3.4rem 5.4rem;
    --fs-rank: 18px;
    --fs-name: 16px;
    --fs-album: 12px;
    --fs-avg: 15px;
    --fs-n: 13px;
  }
  html:not(.is-stage) .race__title { gap: 1px; }
}

/* ---------- phone, below 600px ----------
   Rows are short, so the album line and the word "arviota" go, and a long
   title wraps to two lines instead of running into the bar. None of this
   applies to a stage layout, which has its own sizes whatever the window. */
@media (max-width: 599px) {
  .race {
    --row-h: 34px;
    --cover: 24px;
    --col-gap: 8px;
    --bar-min: 36px;
    --cols: 1.3rem var(--cover) minmax(0, 1fr) minmax(var(--bar-min), .42fr) 2.5rem 1.7rem;
    --fs-rank: 14px;
    --fs-name: 13px;
    --fs-avg: 13px;
    --fs-n: 11px;
  }
  .race__stage { padding-left: 12px; padding-right: 12px; }
  .race__controls { padding-left: 12px; padding-right: 12px; gap: 12px 16px; }
  .race__scrub { flex-basis: 9rem; }
  .race__speed-label { display: none; }
  .race__legend { font-size: 10px; letter-spacing: .12em; }
  html:not(.is-stage) .race__album, html:not(.is-stage) .race__unit { display: none; }
  html:not(.is-stage) .race__name {
    white-space: normal; line-height: 1.08;
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  }
  html:not(.is-stage) .race__bar { height: 6px; }
  .race__play { min-width: 44px; }
}

/* =========================================================================
   Stage layouts: ?capture=landscape|portrait, and full page mode
   =========================================================================
   The stage is exactly a video frame, 1920x1080 or 1080x1920 CSS pixels.
   main.js sets --stage-w, --stage-h, the two bands and the insets from
   race.json, and --row-h from what is left between the bands. Every size
   below derives from --row-h, so a change to a layout in race.config.json
   needs no CSS. The capture pins the stage to the top-left corner. Full page
   mode scales the same stage to fit under the controls bar. */

.is-capture body { overflow: hidden; }
.is-capture .race__controls,
.is-capture .race-loader,
.is-capture .race__rows--static { display: none !important; }

.is-stage .race {
  --cover: calc(var(--row-h) * .78);
  --col-gap: calc(var(--row-h) * .34);
  --fs-rank: calc(var(--row-h) * .5);
  --fs-name: calc(var(--row-h) * .44);
  --fs-album: calc(var(--row-h) * .29);
  --fs-avg: calc(var(--row-h) * .4);
  --fs-n: calc(var(--row-h) * .31);
  --cols: calc(var(--row-h) * 1.1) var(--cover) minmax(0, 1.15fr) minmax(0, 1fr) calc(var(--row-h) * 2) calc(var(--row-h) * 2.9);
}

.is-stage .race__stage {
  position: fixed; top: 0; left: 0;
  width: var(--stage-w); height: var(--stage-h);
  padding: 0; overflow: hidden;
  background: var(--night);
}

.is-stage .race__head {
  position: absolute; top: 0; left: var(--inset-left); right: var(--inset-right);
  height: var(--band-top);
  flex-wrap: wrap; align-content: flex-end; align-items: baseline; justify-content: space-between;
  gap: calc(var(--row-h) * .12) 24px;
  padding-bottom: calc(var(--row-h) * .3);
}
.is-stage .race__legend { font-size: calc(var(--row-h) * .24); }
.is-stage .race__brand {
  flex-basis: 100%;
  display: block; margin: 0;
  font: 600 calc(var(--row-h) * .27)/1.2 var(--text);
  text-transform: uppercase; letter-spacing: .2em;
  color: var(--gold);
}
.is-stage .race__when { font-size: calc(var(--row-h) * .92); }

.is-stage .race__rows--live {
  display: block;
  position: absolute; top: var(--band-top); left: var(--inset-left); right: var(--inset-right);
}

.is-stage .race__foot {
  position: absolute; left: var(--inset-left); right: var(--inset-right);
  top: calc(var(--band-top) + var(--rows) * var(--row-h));
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px 32px;
  padding-top: calc(var(--row-h) * .3);
}
.is-stage .race__population,
.is-stage .race__credit {
  display: block; margin: 0;
  font-size: calc(var(--row-h) * .3); line-height: 1.3;
  color: var(--on-dark-3);
}
.is-stage .race__credit { color: var(--on-dark-2); }

/* The title card over the empty chart during the intro hold. */
.is-stage .race.is-intro .race__card {
  display: flex; flex-direction: column; justify-content: center; align-items: flex-start;
  position: absolute; z-index: 2;
  top: var(--band-top); left: var(--inset-left); right: var(--inset-right);
  height: calc(var(--rows) * var(--row-h));
}
.race__card p { margin: 0; }
.race__card-eyebrow {
  font: 600 calc(var(--row-h) * .32)/1.2 var(--text);
  text-transform: uppercase; letter-spacing: .2em;
  color: var(--gold);
}
.race__card-title {
  font: 500 calc(var(--row-h) * 2.6)/1 var(--display);
  letter-spacing: -.015em;
  color: var(--on-dark);
  margin-top: calc(var(--row-h) * .35) !important;
  padding-bottom: calc(var(--row-h) * .5);
  border-bottom: 1px solid var(--gold);
}
.race__card-deck {
  font: 400 calc(var(--row-h) * .44)/1.3 var(--text);
  color: var(--on-dark-2);
  margin-top: calc(var(--row-h) * .5) !important;
}

/* Portrait rows are tall and narrow: titles wrap to two lines, the album line
   goes, and the count drops its unit to keep the bar a useful length. */
.is-stage--portrait .race {
  --cover: calc(var(--row-h) * .8);
  --col-gap: calc(var(--row-h) * .24);
  --fs-name: calc(var(--row-h) * .36);
  --fs-avg: calc(var(--row-h) * .36);
  --fs-n: calc(var(--row-h) * .28);
  --cols: calc(var(--row-h) * .7) var(--cover) minmax(0, 1fr) minmax(0, .6fr) calc(var(--row-h) * 1.35) calc(var(--row-h) * .8);
}
.is-stage--portrait .race__album,
.is-stage--portrait .race__unit { display: none; }
.is-stage--portrait .race__name {
  white-space: normal; line-height: 1.08;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
}
.is-stage--portrait .race__foot { flex-direction: column; }
/* "Luonnollinen karsinta" is twice the length of the old one-word title, so
   the narrow frame sets it smaller, on two lines. */
.is-stage--portrait .race__card-title { font-size: calc(var(--row-h) * 1.55); }

/* ---------- full page mode ----------
   main.js adds is-stage and is-full to <html>, picks the landscape or portrait
   stage by the window's shape, and sets --stage-scale, --stage-top and
   --stage-left so the stage is as big as fits under the controls bar, centred.
   It also asks the browser for full screen. Where that is refused or missing
   (iPhone Safari), this same fixed layout fills the window instead. */
.is-full body { overflow: hidden; }
.is-full .race { position: fixed; inset: 0; z-index: 10; }
.is-full .race__controls {
  position: fixed; top: 0; left: 0; right: 0; z-index: 3;
  background: var(--night);
}
.is-full .race__stage {
  top: var(--stage-top, 0px); left: var(--stage-left, 0px);
  transform: scale(var(--stage-scale, 1)); transform-origin: 0 0;
}
