:root {
  color-scheme: dark;
  --bg: #0f1115;
  --panel: #1a1d24;
  --panel-2: #232733;
  --text: #f4f5f7;
  --muted: #8b93a3;
  --accent: #ffb020;
  --danger: #ff5f5f;
  /* Wall-display signal colors: CLIMBING green, NEXT red, everyone else
     grey. Green is bright with dark text and red is darker with white text,
     so the two also differ in brightness (red/green colour-blind viewers
     still tell them apart), and every card keeps its CLIMBING/NEXT label. */
  --go: #34d36b;
  --go-text: #052e14;
  --next: #d92d2d;
  --next-text: #ffffff;
  --queue: #b7bdc9;
  --preview: #7a8294;
  --ti: #3b82f6; /* technical incident highlight (6.48): blue, distinct from go/next for red-green colour blindness */
  --ti-bg: #17315c;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  min-height: 100dvh;
}

.setup {
  max-width: 720px;
  margin: 0 auto;
  padding: 2rem 1.5rem 3rem;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

h1 {
  font-size: 1.6rem;
  margin: 0 0 1.5rem;
}

.setup-row {
  display: flex;
  gap: 1rem;
  align-items: end;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}

.setup-row label {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  font-size: 0.85rem;
  color: var(--muted);
}

.setup-row label.grow { flex: 1; min-width: 260px; }

.checkbox-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1rem;
  font-size: 0.9rem;
  cursor: pointer;
}
.checkbox-row input { width: 1.1rem; height: 1.1rem; cursor: pointer; }

.mode-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1rem;
}

.mode-tab {
  padding: 0.5rem 1.1rem;
  border-radius: 999px;
  border: 1px solid #333846;
  background: var(--panel);
  color: var(--text);
  font-weight: 600;
  font-size: 0.9rem;
}

.mode-tab.active {
  background: var(--accent);
  color: #1a1305;
  border-color: var(--accent);
}

.sequence-row {
  margin: 0 0 1.5rem;
  max-width: 560px;
}

.sequence-label {
  font-size: 0.85rem;
  color: var(--muted);
  margin-bottom: 0.6rem;
}

/* Explains what "+ Add paired entry" actually does (6.12) - without this,
   the button alone gives no hint that it interleaves two Speed finals
   rather than adding one more plain round. Deliberately a permanent,
   visible label rather than a `title` tooltip - this app runs on tablets,
   where hover tooltips are effectively undiscoverable. */
.paired-entry-hint {
  font-size: 0.85rem;
  color: var(--muted);
  align-self: center;
}

.sequence-list {
  list-style: decimal;
  padding-left: 1.4rem;
  margin: 0 0 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.sequence-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
  background: var(--panel);
  border: 1px solid #333846;
  border-radius: 10px;
  padding: 0.55rem 0.8rem;
  cursor: grab;
}
.sequence-item.dragging { opacity: 0.4; }
.sequence-item span { overflow-wrap: anywhere; }
/* Every sequence entry (Sequence mode, 6.10, and Multimode's per-column
   steps, 6.23) is a live <select> now rather than a static label - flex so
   a long round name doesn't force the row wider than its list. A 140px
   floor (rather than 0) plus `flex-wrap` on `.sequence-item` above means a
   narrow phone wraps the ▲/▼/× control group onto its own line below
   instead of continuing to shrink the select past readable - confirmed
   live at ~375-410px this used to compress the select down to ~30px wide,
   cutting the round name off with no visual indicator; the ellipsis rule
   below now also shows "…" instead of a bare hard clip whenever it's
   narrower than the full name even before wrapping kicks in. */
.sequence-item select {
  flex: 1;
  min-width: 140px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* A paired ("interleave two Speed finals", 6.12) entry's two sides sit in
   their own inner flex row so the outer .sequence-item still only has two
   top-level children (this wrapper, the remove button) - same
   space-between layout a plain entry's single select + button already
   use, just with two selects grouped inside the first slot. */
.sequence-pair {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex: 1;
  min-width: 0;
}
/* No separate `.sequence-pair select` rule needed - .sequence-pair is
   always a direct child of a .sequence-item <li>, so the descendant
   selector above already matches both selects inside it. */
.sequence-pair-sep { color: var(--muted); flex-shrink: 0; }

.sequence-remove {
  /* 0.55rem vertical padding (was 0 - the single biggest offender: a
     ~19px-tall tap target with no vertical padding at all) brings this to
     a real ~34-36px touch target, in line with the usual 32-40px
     guideline for something meant to be tapped on a tablet/phone. */
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 1.2rem;
  line-height: 1;
  padding: 0.55rem 0.5rem;
  cursor: pointer;
}
.sequence-remove:hover { color: var(--danger); }

/* Groups the up/down/remove buttons as one flex-shrink-proof unit, so
   .sequence-item's own space-between layout still only ever has two
   top-level children (the select/pair, and this group) - unchanged since
   before these move buttons were added. Gap widened from 0.15rem (~2.4px)
   to 0.35rem - the three buttons sat close enough together to make
   mis-tapping the wrong one (or the remove button) an easy touchscreen
   mistake. */
.sequence-controls {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  flex-shrink: 0;
}
.sequence-move {
  /* Same touch-target sizing reasoning as .sequence-remove above - was a
     ~21x21px box, now ~32-34px. */
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 0.85rem;
  line-height: 1;
  padding: 0.55rem 0.5rem;
  cursor: pointer;
}
.sequence-move:hover:not(:disabled) { color: var(--accent); }
.sequence-move:disabled { opacity: 0.3; cursor: default; }

/* Not draggable, unlike the plain sequence-item it otherwise matches -
   Multimode's per-column round lists (6.23) don't support reordering. */
.sequence-item--static { cursor: default; }

/* Multimode setup (6.23): one config card per column, side by side on a
   wide screen (same spirit as the board's own lanes-grid), stacking on
   narrow ones. */
.multi-columns-config {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1rem;
  margin: 0.5rem 0 1.25rem;
}

.multi-column-config {
  background: var(--panel);
  border: 1px solid #333846;
  border-radius: 14px;
  padding: 1rem;
}

/* A split-view row of the Sequence builder (6.50): the column editor nested in
   the row, full width, not draggable (the ▲▼ buttons move it). */
.sequence-item--split { cursor: default; align-items: flex-start; }
.sequence-split { flex: 1 1 100%; min-width: 0; }
.sequence-split .sequence-pair { margin-bottom: 0.4rem; }
.sequence-split-count { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.85rem; color: var(--muted); }
.sequence-split-count select { flex: none; min-width: 0; padding: 0.35rem 0.6rem; }
.sequence-split-hint { margin: 0 0 0.5rem; font-size: 0.8rem; color: var(--muted); }
.sequence-split .sequence-pair { flex-wrap: wrap; }
.sequence-split .sequence-badge { white-space: nowrap; flex: none; }
.sequence-split-merge { padding: 0.35rem 0.7rem; font-size: 0.85rem; white-space: nowrap; flex: none; }
.sequence-split .multi-column-config { padding: 0.75rem; }
.sequence-split .multi-columns-config { margin-bottom: 0.25rem; }

.multi-column-config .sequence-list { margin-bottom: 0.75rem; }
.multi-column-config > button { width: 100%; }

input, select, button {
  font-size: 1rem;
  padding: 0.65rem 0.8rem;
  border-radius: 10px;
  border: 1px solid #333846;
  background: var(--panel);
  color: var(--text);
}

input { min-width: 160px; }
select { min-width: 220px; }

button {
  background: var(--accent);
  color: #1a1305;
  font-weight: 700;
  border: none;
  cursor: pointer;
}
button:disabled { opacity: 0.6; cursor: default; }
button.ghost {
  background: transparent;
  color: var(--text);
  border: 1px solid #333846;
  font-weight: 500;
}

.error {
  color: var(--danger);
  margin: 0.5rem 0 1rem;
}

.training-hint {
  color: var(--muted);
  font-size: 0.85rem;
  margin: -0.5rem 0 1rem;
}

.setup-footer {
  margin-top: auto; /* pushes the footer to the bottom of the viewport
    when the setup screen's own content doesn't fill it - see .setup's
    flex column above; naturally becomes 0 and the footer just follows
    the content when there's enough of it to fill the screen anyway */
  padding-top: 1rem;
  /* Clears the Ko-fi floating "Support me" button (6.27), which is
     `position: fixed` near the bottom-left corner of the viewport and
     therefore not part of this element's own layout flow at all - nothing
     here pushes it out of the way on its own. Confirmed live on a narrow
     phone (~375-410px): the footer's centered text sits close enough to
     the bottom-left corner there that "Legal Information" rendered
     directly underneath/behind the button, unreadable. This padding is
     harmless dead space on a wide screen (where the button sits far from
     the centered footer text horizontally) - simpler and more robust than
     a narrow-viewport-only media query. */
  padding-bottom: 4.5rem;
  border-top: 1px solid #333846;
  text-align: center;
}

.setup-footer a {
  color: var(--muted);
  font-size: 0.85rem;
  text-decoration: none;
}
.setup-footer a:hover,
.setup-footer a:focus-visible {
  color: var(--accent);
  text-decoration: underline;
}

.legal {
  margin-top: 0.5rem;
}
.legal summary {
  color: var(--muted);
  font-size: 0.85rem;
  cursor: pointer;
  list-style: none;
}
.legal summary::-webkit-details-marker {
  display: none;
}
.legal summary:hover,
.legal summary:focus-visible,
.legal[open] summary {
  color: var(--accent);
  text-decoration: underline;
}
.legal-body {
  margin: 0.75rem auto 0;
  max-width: 480px;
  color: var(--muted);
  font-size: 0.8rem;
  line-height: 1.5;
  text-align: left;
}
.legal-body h4 {
  margin: 1.25rem 0 0.4rem;
  color: var(--text);
  font-size: 0.85rem;
}
.legal-body h4:first-child {
  margin-top: 0;
}
.legal-body p {
  margin: 0 0 0.6rem;
}
.legal-body code {
  font-size: 0.75rem;
  background: rgba(255, 255, 255, 0.06);
  padding: 0.05rem 0.3rem;
  border-radius: 3px;
}
.legal-body a {
  color: var(--muted);
  text-decoration: underline;
}
.legal-body a:hover,
.legal-body a:focus-visible {
  color: var(--accent);
}

.board {
  padding: 1rem 1.25rem 2rem;
}

.board-topbar {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
}

.round-title {
  font-size: 1.3rem;
  font-weight: 700;
  flex: 1;
  /* iOS Safari overlays its own fullscreen-exit "X" in the top-left corner
     while requestFullscreen() is active (see kiosk mode in app.js) - left-
     aligned text there gets hidden underneath it, so center instead. */
  text-align: center;
}

.status-line {
  color: var(--muted);
  font-size: 0.85rem;
}
/* Deliberately more than just a color swap - this is the only signal that
   something's wrong, and the app's whole design principle otherwise is
   large, at-a-glance cards (the lane cards themselves never change
   appearance when data goes stale). A background pill + bold weight makes
   it noticeable from a few meters away, not just on close inspection of
   small corner text. */
.status-line.stale {
  color: var(--danger);
  font-weight: 700;
  background: rgba(255, 95, 95, 0.15);
  padding: 0.2rem 0.55rem;
  border-radius: 6px;
}

.paired-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
  padding: 0.75rem 1rem;
  background: var(--panel);
  border: 1px solid #333846;
  border-radius: 12px;
  font-size: 0.9rem;
  color: var(--muted);
}

.training-controls {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
  padding: 0.75rem 1rem;
  background: var(--panel);
  border: 1px solid #333846;
  border-radius: 12px;
}

.training-label {
  flex: 1;
  color: var(--muted);
  font-size: 0.9rem;
  text-align: center;
}

.training-controls button {
  font-size: 1.1rem;
  padding: 0.75rem 1.5rem;
}

.share-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
}

.share-label {
  color: var(--muted);
  font-size: 0.85rem;
  white-space: nowrap;
}

.share-input {
  flex: 1;
  min-width: 0;
  font-size: 0.85rem;
  color: var(--muted);
}

.qr-code {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: 6px;
  overflow: hidden;
  background: #fff;
  padding: 3px;
}
.qr-code svg {
  display: block;
  width: 100%;
  height: 100%;
}

.group-tabs {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1.25rem;
  flex-wrap: wrap;
}

.group-tab {
  padding: 0.5rem 1.1rem;
  border-radius: 999px;
  border: 1px solid #333846;
  background: var(--panel);
  color: var(--text);
  font-weight: 600;
  font-size: 0.9rem;
}

.group-tab.active {
  background: var(--accent);
  color: #1a1305;
  border-color: var(--accent);
}

/* Lead/Boulder route order (6.53): ◀ ▶ around each route tab while "Order" is on */
.route-tab-wrap { display: inline-flex; align-items: center; gap: 0.25rem; }
.tab-arrow { padding: 0.4rem 0.65rem; border-radius: 999px; font-size: 0.8rem; line-height: 1; }
.tab-arrow:disabled { opacity: 0.3; }
.route-chip { cursor: default; }

.lanes-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 1.5rem;
  margin-bottom: 1.5rem;
}

.group-heading {
  color: var(--text);
  font-weight: 700;
  font-size: 1.05rem;
  margin: 0 0 0.75rem;
}

.next-in-sequence {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 0.5rem;
  padding-top: 0.9rem;
  border-top: 1px solid #333846;
  color: var(--muted);
  font-size: 0.85rem;
}
.next-in-sequence strong {
  color: var(--text);
}

.lane {
  background: var(--panel);
  border-radius: 16px;
  padding: 1.25rem;
  /* Each lane is its own size container: text sizes below are derived from
     THIS lane's own width (cqi), so a lane in a 5-column Split View sizes
     its text as if it owned the whole screen. */
  container-type: inline-size;
  /* Width rule: 30 characters fit on one line (~18 x font-size for the bold
     names), minus the card's own horizontal padding. Height rule: caps the
     size so ~11 text lines (2 cards + up to 7 queue rows) still fit below
     the page chrome; longer names simply wrap. Overflow is never clipped,
     the page just scrolls. */
  --lane-fs-w: calc((100cqi - 2.5rem) / 18);
  --lane-fs-h: calc((100dvh - 22rem) / 11);
  --lane-fs: max(1rem, min(var(--lane-fs-w), var(--lane-fs-h)));
}

.lane-heading {
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.85rem;
  margin-bottom: 0.75rem;
  overflow-wrap: anywhere;
}

.lane-finished {
  padding: 2rem 0;
  text-align: center;
  color: var(--muted);
  font-size: 1.1rem;
}

.card {
  border-radius: 14px;
  padding: 1rem 1.25rem;
  margin-bottom: 0.75rem;
}

.card-label {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.75rem;
  font-weight: 700;
  opacity: 0.85;
  margin-bottom: 0.3rem;
}

.card-athlete {
  font-weight: 800;
  line-height: 1.15;
  /* A long, unbreakable athlete/route name from live results.info data
     could otherwise force a Multimode column past its grid track's
     minmax() floor and visibly overflow the column border - the same
     overflow class of bug already fixed for the grid track width itself,
     just not for the text content until now. */
  overflow-wrap: anywhere;
}

.card--at-wall {
  background: var(--go);
  color: var(--go-text);
}

.card--on-deck {
  background: var(--next);
  color: var(--next-text);
}

.queue-list {
  list-style: decimal;
  margin: 0.75rem 0 0;
  /* em, not rem: the list numbers grow with the fitted text size (6.52) and
     must stay inside the lane box */
  padding-left: 1.7em;
  color: var(--muted);
  font-size: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}
.queue-list li { color: var(--queue); overflow-wrap: anywhere; }
.queue-list li.queue-item--preview { color: var(--preview); font-style: italic; }

/* "Next Category: U 13 m — Finale" under "Round finished" (6.55) */
.next-category-title {
  color: var(--text);
  font-weight: 700;
  font-size: max(1rem, calc(var(--lane-fs, 1.3rem) * 0.8));
  margin-top: 0.5rem;
}
.next-category-list { margin-top: 0.4rem; }
/* "Next: U 13 m — Finale": heading in front of the next category's names */
.queue-list li.queue-item--next-title {
  list-style: none;
  color: var(--text);
  font-style: normal;
  font-weight: 700;
  margin: 0.35em 0 0.1em -1.7em;
}

/* Technical incident (6.48): the re-starting athlete is a normal card/list
   row with its own colour and a "TI" badge in the corner. The card keeps its
   CLIMBING/NEXT colour and label; the blue frame and badge carry "TI". */
.is-ti { position: relative; }
.card.is-ti { box-shadow: 0 0 0 0.25rem var(--ti); }
.queue-list li.is-ti {
  color: #fff;
  background: var(--ti-bg);
  border-left: 0.3rem solid var(--ti);
  border-radius: 0.4rem;
  padding: 0.2rem 3.2rem 0.2rem 0.5rem;
}
.queue-list li.is-ti-gap {
  font-style: italic;
  background: transparent;
  color: var(--ti-text, #9ec1ff);
  border-left-style: dashed;
  padding-right: 0.5rem;
}
.card.is-ti-gap .card-athlete { font-style: italic; }
.ti-badge {
  position: absolute;
  top: 0.35rem;
  right: 0.35rem;
  padding: 0.05rem 0.55rem;
  border-radius: 0.4rem;
  background: var(--ti);
  color: #fff;
  font-weight: 800;
  font-size: max(0.7rem, calc(var(--lane-fs, 1.3rem) * 0.5));
  letter-spacing: 0.05em;
  line-height: 1.3;
}
.queue-list li.is-ti .ti-badge { top: 50%; transform: translateY(-50%); font-size: 0.8rem; }

@media (max-width: 640px) {
  .lanes-grid { grid-template-columns: 1fr; }
}

/* One route/boulder selected via the route tabs (6.22) - a tablet parked
   next to a single wall gets a bigger, more legible display instead of the
   same card size used in the multi-lane grid. */
.lanes-grid--single .lane {
  padding: 2rem;
  /* Roomier padding + bigger heading eat more height than a normal lane. */
  --lane-fs-h: calc((100dvh - 33rem) / 11);
}
.lanes-grid--single .lane-heading { font-size: 1.3rem; }

/* Multimode (6.23) - every column side by side, wrapping onto further rows
   only once the screen is too narrow to fit them all on one - the point is
   seeing every category at once on a big enough display. minmax's 320px
   floor matches .lanes-grid's own (5.6/6.6) so a column never gets so
   narrow its own lane cards would have to squeeze below their normal
   minimum width. */
.multi-columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 1.5rem;
  /* Default (stretch), not "start" - columns rarely have exactly the same
     amount of content (a Boulder round with 4 boulders next to one with 3,
     a column with a "Next: …" line next to one without, etc.). "start"
     let each .multi-block size to only its own content, so the bottom
     borders across one row landed at different heights - the row's gutter
     was only bordered on one side below the shortest column, reading as a
     misaligned/uneven margin. Stretching lets every card in a row share
     the tallest one's height instead, with the extra space just trailing
     empty inside the shorter ones - a normal, clean card-grid look. */
}

/* One block per column, each with its own heading/tabs/lanes - a bordered
   card (not the same fill as the .lane cards it contains, so those still
   stand out against it) rather than the plain stacked-with-a-divider look
   the single-column version used, since separation now has to work in two
   dimensions once columns wrap. */
.multi-block {
  border: 1px solid #333846;
  border-radius: 16px;
  padding: 1.25rem;
}

@media (max-width: 640px) {
  .multi-columns { grid-template-columns: 1fr; }
}

/* Smaller text inside Multimode columns only - a column can be as narrow
   as the 320px grid floor above, and the normal card sizing (tuned for one
   lane owning the full screen width) wraps far too early there. Sized so
   at least ~25 characters fit on one line even at that 320px floor.
   Deliberately fixed rem sizes, not the vw-based clamp() the normal cards
   use - vw is relative to the whole viewport, which has no relation to
   how wide one column actually renders at when several sit side by side.
   Selectors are one level more specific than .lanes-grid--single's own
   (6.22) so this always wins regardless of source order, and a single
   filtered route within a Multimode column doesn't blow back up to that
   bonus size meant for a lane owning the whole screen. */
/* .lanes-grid's own 320px-per-track floor (above) is sized for a lane
   owning the whole page width - reused as-is inside a Multimode column,
   its content (minus the column's own 1.25rem padding + 1px border each
   side) can be narrower than 320px even for a single track, so the grid
   demanded more width than the column actually had and visibly overflowed
   past the column's own border (reported live with a screenshot). Lowered
   to a floor that always fits within `.multi-block`'s own 320px minimum
   (320 - 2*20px padding - 2*1px border = 278px available, 260px leaves
   margin) - still wide enough for the smaller Multimode card sizes below
   to render cleanly, and still lets several boulders/routes sit side by
   side within one column once it's wide enough for that. */
.multi-block .lanes-grid { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

.multi-block .lane { padding: 0.85rem; }
.multi-block .lane .lane-heading { font-size: 0.7rem; margin-bottom: 0.5rem; }
.multi-block .lane .card { padding: 0.55rem 0.7rem; margin-bottom: 0.5rem; }
.multi-block .lane .card-label { margin-bottom: 0.15rem; }
.multi-block .lane .queue-list { margin-top: 0.5rem; gap: 0.25rem; }
/* Inside a Split View column the page chrome is taller (column heading +
   tabs) and the card padding is smaller. */
.multi-block .lane {
  --lane-fs-w: calc((100cqi - 1.6rem) / 18);
  --lane-fs-h: calc((100dvh - 26rem) / 11);
}
.multi-block .next-in-sequence { font-size: 0.75rem; padding-top: 0.6rem; margin-top: 0.4rem; }

/* "Training" marker in front of a training row of the sequence builder (6.47) */
.sequence-badge {
  align-self: center;
  padding: 0.2rem 0.6rem;
  border-radius: 999px;
  background: var(--accent);
  color: #1a1305;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* Group/route choice of a Split View column on the setup screen (6.46) */
.multi-view-controls {
  margin: 0.6rem 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  font-size: 0.85rem;
  color: var(--muted);
}
.multi-view-routes { display: flex; flex-wrap: wrap; gap: 0.4rem 0.9rem; align-items: center; }
.multi-view-route { display: inline-flex; align-items: center; gap: 0.25rem; color: var(--text); cursor: pointer; }
/* Global `input` rules (padding, min-width) are meant for text fields. */
.multi-view-route input { min-width: 0; width: 1.1rem; height: 1.1rem; padding: 0; cursor: pointer; }
.multi-view-group select { min-width: 0; }

/* Shared session panel on the setup screen (6.46) */
.session-panel {
  margin: 1.25rem 0 0;
  border: 1px solid #333846;
  border-radius: 12px;
  background: var(--panel);
}
.session-panel > summary {
  cursor: pointer;
  padding: 0.85rem 1rem;
  font-weight: 700;
  font-size: 0.95rem;
}
.session-body { padding: 0 1rem 1rem; }
.session-hint { color: var(--muted); font-size: 0.85rem; margin: 0 0 1rem; }
.session-status { margin-bottom: 0.75rem; font-size: 0.95rem; }
.session-summary { margin: 0 0 0.75rem; color: var(--text); font-weight: 700; overflow-wrap: anywhere; }
.session-summary:empty { display: none; }
.session-dirty {
  margin: 0 0 0.75rem;
  padding: 0.5rem 0.75rem;
  border-radius: 8px;
  background: #3a2e12;
  color: var(--accent);
  font-size: 0.85rem;
}
.session-msg {
  margin-top: 0.75rem;
  padding: 0.6rem 0.8rem;
  border-radius: 8px;
  background: var(--panel-2);
  font-size: 0.9rem;
  overflow-wrap: anywhere;
}
.session-msg--error { background: #3a1818; color: var(--danger); }

.controller {
  max-width: 480px;
  margin: 0 auto;
  padding: 1.5rem 1.25rem 2rem;
}

.controller-lanes {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin: 1.5rem 0;
}

.controller-lane {
  background: var(--panel);
  border-radius: 16px;
  padding: 1rem 1.25rem;
}

.controller-lane .lane-name {
  display: block;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.75rem;
  margin-bottom: 0.3rem;
}

.controller-lane .lane-athlete {
  font-weight: 800;
  font-size: clamp(1.3rem, 5vw, 1.8rem);
}

.controller-buttons {
  display: flex;
  gap: 1rem;
}

.controller-gate {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin: 1rem 0;
}
.controller-entry {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin: 1rem 0 0;
  font-size: 0.85rem;
  color: var(--muted);
}
.controller-extra { margin-top: 1rem; }
#controllerMsg { margin: 0.75rem 0; }

.jury-panel { margin: 0.75rem 0; }
.jury-panel > summary { cursor: pointer; font-weight: 700; font-size: 0.9rem; padding: 0.4rem 0; }
.jury-form { display: flex; flex-direction: column; gap: 0.9rem; margin: 1rem 0; }
.jury-form label {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  font-size: 0.85rem;
  color: var(--muted);
}
.jury-form select, .jury-form input[type="text"] { font-size: 1rem; padding: 0.7rem; }
.jury-form button { font-size: 1.2rem; padding: 1rem; }
.jury-preview { min-height: 1.4em; font-weight: 700; overflow-wrap: anywhere; }
.jury-preview.is-warning { color: var(--danger); }
.jury-form .jury-check { flex-direction: row; align-items: center; gap: 0.6rem; font-size: 0.95rem; color: var(--text); }
.jury-form .jury-check input { width: 1.4rem; height: 1.4rem; }
.jury-heading { margin: 1.5rem 0 0.5rem; font-size: 1rem; }
.jury-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.6rem; }
.jury-list li {
  background: var(--panel);
  border-radius: 12px;
  padding: 0.8rem 1rem;
  overflow-wrap: anywhere;
}
.jury-list li.is-done { opacity: 0.55; }
.jury-list .jury-item-meta { color: var(--muted); font-size: 0.8rem; }
.jury-list .jury-item-text { font-weight: 700; margin: 0.15rem 0 0.5rem; }
.jury-list .jury-item-buttons { display: flex; gap: 0.6rem; }
.jury-list .jury-item-buttons button { flex: 1; padding: 0.7rem; font-size: 1rem; }
.jury-empty { color: var(--muted); font-size: 0.9rem; }

.controller-buttons button {
  flex: 1;
  font-size: 1.2rem;
  padding: 1rem;
}

/* Text sizes (Stage 1 display rework): derived from each lane's own width via
   container query units - see .lane. CLIMBING and NEXT share one size, the
   queue is 0.8x of it and the next-category preview rows (same size as the
   queue) are only dimmer. Browsers without container query units (Safari
   < 16) keep the previous fixed/viewport-based sizes. */
@supports (width: 1cqi) {
  .card--at-wall .card-athlete,
  .card--on-deck .card-athlete { font-size: var(--lane-fs); }
  .card-label { font-size: max(0.7rem, calc(var(--lane-fs) * 0.35)); }
  .queue-list { font-size: max(0.9rem, calc(var(--lane-fs) * 0.8)); }
}
@supports not (width: 1cqi) {
  .card--at-wall .card-athlete { font-size: clamp(1.6rem, 4vw, 2.6rem); }
  .card--on-deck .card-athlete { font-size: clamp(1.2rem, 2.6vw, 1.6rem); }
  .lanes-grid--single .card--at-wall .card-athlete { font-size: clamp(2.4rem, 8vw, 5rem); }
  .lanes-grid--single .card--on-deck .card-athlete { font-size: clamp(1.8rem, 5vw, 3rem); }
  .lanes-grid--single .queue-list { font-size: 1.3rem; }
  .multi-block .lane .card-label { font-size: 0.6rem; }
  .multi-block .lane .card--at-wall .card-athlete { font-size: 1rem; }
  .multi-block .lane .card--on-deck .card-athlete { font-size: 0.9rem; }
  .multi-block .lane .queue-list { font-size: 0.8rem; }
}

/* "Advanced" Sequence tab and the hint in the simple modes (6.50). */
.mode-tab-badge {
  margin-left: 0.35rem;
  padding: 0.05rem 0.4rem;
  border-radius: 0.4rem;
  background: var(--panel-2);
  color: var(--accent);
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.session-mode-hint {
  margin: 0.25rem 0 1rem;
  padding: 0.6rem 0.8rem;
  border-radius: 10px;
  background: var(--panel);
  color: var(--muted);
  font-size: 0.9rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
}

/* While the text size is measured (6.52): single-line texts and only the probe
   queue, so neither names nor the number of athletes left change the result. */
.fit-measure .card-athlete,
.fit-measure .queue-list li { white-space: nowrap; }
.fit-measure .queue-list:not(.fit-probe) { display: none; }
