@layer components {
  /* ---- Type roles ------------------------------------------------------
     Three roles, two families. Archivo carries display and body at different
     widths — using the variable width axis for the role split is the reason to
     choose it, and a second family for body would leave the axis idle. */

  .display {
    font-family: var(--font-display);
    font-weight: 800;
    font-stretch: var(--wdth-display);
    letter-spacing: var(--track-display);
    line-height: 1.02;
  }

  .headline {
    font-family: var(--font-display);
    font-weight: 700;
    font-stretch: var(--wdth-headline);
    letter-spacing: -0.01em;
    line-height: 1.12;
  }

  /* The mono utility role: clocks, scores, codes, micro-labels. Word Race has no
     monospace by explicit decision, so this is both a point of sibling difference
     and genuinely earned — a clock whose digits change width is a clock that
     jitters. */
  .label {
    font-family: var(--font-data);
    font-weight: 500;
    font-size: var(--text-2xs);
    letter-spacing: var(--track-caps);
    text-transform: uppercase;
    color: var(--bone-label);
  }

  .data {
    font-family: var(--font-data);
    font-variant-numeric: tabular-nums;
    letter-spacing: var(--track-data);
  }

  .muted {
    color: var(--bone-label);
  }

  .faint {
    color: var(--bone-faint);
  }

  small {
    font-size: var(--text-sm);
    letter-spacing: var(--track-body-sm);
  }

  /* ---- Wordmark -------------------------------------------------------- */

  .wordmark {
    display: inline-flex;
    align-items: center;
    gap: 0.1em;
    font-family: var(--font-display);
    font-weight: 800;
    font-stretch: 118%;
    font-size: var(--text-lg);
    letter-spacing: 0.01em;
    text-transform: uppercase;
    text-decoration: none;
    line-height: 1;
  }

  /* The multiplication sign as the join: the wordmark states the subject. */
  .wordmark__x {
    color: var(--signal);
    font-size: 0.82em;
    transform: translateY(-0.02em);
  }

  /* ---- Controls -------------------------------------------------------
     One key face, reused by every button in the game — the keypad, the settings
     toggles, the lobby actions. A machined console has one kind of button. */

  .btn,
  .key {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: 2.75rem;
    padding: 0.55rem 1rem;
    background: var(--rail);
    color: var(--bone);
    border: var(--hair) solid var(--edge-control);
    border-radius: var(--radius-sm);
    box-shadow: var(--bevel-raised);
    font-family: var(--font-display);
    font-weight: 700;
    font-stretch: 104%;
    font-size: var(--text-sm);
    letter-spacing: 0.01em;
    transition:
      box-shadow var(--dur-instant) var(--ease-out),
      background-color var(--dur-fast) var(--ease-out),
      color var(--dur-fast) var(--ease-out);
  }

  .btn:hover:not(:disabled),
  .key:hover:not(:disabled) {
    box-shadow: var(--bevel-hover);
  }

  /* The press. This is the interaction a player performs a hundred times a match,
     so it carries the weight Word Race's squash-into-its-own-shadow carries: the
     lit edge moves to the bottom and the face sinks. */
  .btn:active:not(:disabled),
  .key:active:not(:disabled),
  .key[data-flash="true"] {
    box-shadow: var(--bevel-pressed);
    background: color-mix(in oklab, var(--rail) 84%, black);
  }

  .btn:disabled,
  .key:disabled {
    color: var(--bone-faint);
    border-color: var(--edge);
    box-shadow: var(--bevel-inset);
    background: color-mix(in oklab, var(--panel) 70%, var(--well));
  }

  .btn--primary {
    background: var(--bone);
    color: #111725;
    border-color: transparent;
  }

  .btn--primary:hover:not(:disabled) {
    background: #fffdf8;
  }

  .btn--primary:active:not(:disabled) {
    background: color-mix(in oklab, var(--bone) 88%, black);
  }

  .btn--danger {
    color: var(--danger);
    border-color: color-mix(in oklab, var(--danger) 45%, var(--edge));
  }

  .btn--ghost {
    background: none;
    border-color: var(--edge-control);
    box-shadow: none;
    font-weight: 450;
    font-family: var(--font-body);
    color: var(--bone-label);
  }

  .btn--ghost:hover:not(:disabled) {
    color: var(--bone);
    box-shadow: none;
    border-color: var(--bone-faint);
  }

  .btn--wide {
    width: 100%;
  }

  /* ---- Text input ------------------------------------------------------
     Used only on the landing page, for a name and a room code. The game itself
     has no text field — see the readout. */

  .field {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
  }

  .input {
    width: 100%;
    padding: 0.7rem 0.85rem;
    background: var(--well);
    color: var(--bone);
    border: var(--hair) solid var(--edge-control);
    border-radius: var(--radius-sm);
    box-shadow: var(--bevel-inset);
  }

  .input::placeholder {
    color: var(--bone-faint);
  }

  .input--code {
    font-family: var(--font-data);
    font-size: var(--text-2xl);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.3em;
    text-align: center;
    text-indent: 0.3em; /* balance the trailing letter-space */
  }

  /* ---- The chronograph -------------------------------------------------
     THE SIGNATURE. The operator disc is also the stopwatch: the randomizer's
     choice sits in the middle of the face, and the race clock sweeps its rim.
     One object doing both jobs, rather than a spinner next to a progress bar. */

  .chrono {
    position: relative;
    display: grid;
    place-items: center;
    width: var(--disc-size);
    height: var(--disc-size);
    flex: 0 0 auto;
    border-radius: var(--radius-round);
    background: var(--rail);
    background-image: var(--dial-brush);
    box-shadow:
      var(--bevel-raised),
      inset 0 0 0 var(--hair) rgb(242 237 227 / 10%);
  }

  /* The 60 index ticks, generated. A watch dial's markings, and they give the
     sweep something to be measured against. */
  .chrono::before {
    content: "";
    position: absolute;
    inset: 6%;
    border-radius: var(--radius-round);
    background: var(--dial-ticks);
    mask: radial-gradient(circle, transparent 76%, black 77%);
    opacity: 0.55;
  }

  .chrono__arc {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    /* Start the sweep at 12 o'clock, running clockwise. */
    transform: rotate(-90deg);
    overflow: visible;
  }

  .chrono__arc circle {
    fill: none;
    stroke-width: var(--arc-width);
    stroke-linecap: round;
    stroke-dasharray: var(--arc-length);
    /* The clock is DATA, not animation: the dash offset is recomputed per tick from
       an absolute deadline. That is why it needs no transition and is unaffected by
       prefers-reduced-motion — and why a throttled background tab is correct on its
       very next tick rather than lagging. */
    stroke-dashoffset: calc(var(--arc-length) * (1 - var(--arc-fraction)));
    stroke: var(--bone);
    transition: stroke var(--dur-base) var(--ease-out);
  }

  .chrono[data-urgent="true"] .chrono__arc circle {
    stroke: var(--signal);
  }

  .chrono[data-frozen="true"] .chrono__arc circle {
    stroke: var(--seat);
  }

  .chrono__track {
    fill: none;
    stroke: var(--edge);
    stroke-width: var(--arc-width);
    stroke-dasharray: none;
    stroke-dashoffset: 0;
  }

  /* The operator glyph. Rotates a quarter turn into a detent at the reveal —
     a click into position, not a slot machine, because the operator was chosen by
     the host and received here. Pretending to roll it would be a lie about where
     the decision happened. */
  .chrono__op {
    position: relative;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--text-operator);
    line-height: 1;
    color: var(--bone);
    transition: transform var(--dur-detent) var(--ease-detent);
  }

  /* During PICK the disc carries every enabled operator around its rim, so the
     instrument states the rules of the match by existing — and the reveal's
     rotation becomes the selection rather than decoration. */
  .chrono__ring {
    position: absolute;
    inset: 12%;
    display: grid;
    place-items: center;
    pointer-events: none;
  }

  .chrono__ring span {
    position: absolute;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: calc(var(--text-operator) * 0.44);
    color: var(--bone-faint);
    transform: rotate(var(--at)) translateY(calc(var(--disc-size) * -0.31))
      rotate(calc(var(--at) * -1));
  }

  .chrono__clock {
    position: absolute;
    bottom: 12%;
    font-family: var(--font-data);
    font-variant-numeric: tabular-nums;
    font-size: calc(var(--text-clock) * 0.62);
    letter-spacing: var(--track-data);
    color: var(--bone-label);
  }

  /* ---- The dial: operands and the disc --------------------------------- */

  .dial {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: clamp(var(--space-2), 2vw, var(--space-4));
    width: 100%;
  }

  .bezel {
    position: relative;
    display: grid;
    place-items: center;
    width: var(--dial-size);
    height: var(--dial-size);
    flex: 0 0 auto;
    border-radius: var(--radius-round);
    background: var(--well);
    background-image: var(--dial-brush);
    box-shadow:
      var(--bevel-inset-deep),
      0 0 0 var(--stroke) var(--rail),
      0 0 0 calc(var(--stroke) + 1px) rgb(0 0 0 / 35%);
  }

  /* The owner's ring. Colour is never the only signal — the engraved seat numeral
     below carries the same information for anyone who cannot use the hue. */
  .bezel[data-owned="true"] {
    box-shadow:
      var(--bevel-inset-deep),
      0 0 0 var(--stroke) var(--seat),
      0 0 0 calc(var(--stroke) + 1px) rgb(0 0 0 / 35%);
  }

  .bezel__value {
    font-family: var(--font-display);
    font-weight: 800;
    font-stretch: var(--wdth-operand);
    font-size: var(--text-operand);
    letter-spacing: var(--track-operand);
    line-height: 1;
    color: var(--bone);
    font-variant-numeric: tabular-nums;
  }

  /* An applied index at 12 o'clock, exactly as a watch dial marks its hours. */
  .bezel__seat {
    position: absolute;
    top: 8%;
    font-family: var(--font-data);
    font-size: var(--text-2xs);
    font-weight: 500;
    letter-spacing: 0.08em;
    color: var(--seat);
  }

  .bezel[data-owned="false"] .bezel__seat {
    color: var(--house);
  }

  .bezel--blank .bezel__value {
    color: var(--bone-faint);
    font-size: calc(var(--text-operand) * 0.6);
  }

  .owners {
    display: flex;
    align-items: flex-start;
    justify-content: center;
    gap: clamp(var(--space-2), 2vw, var(--space-4));
    width: 100%;
  }

  .owners__slot {
    width: var(--dial-size);
    flex: 0 0 auto;
    text-align: center;
    font-family: var(--font-data);
    font-size: var(--text-2xs);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--bone-label);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .owners__slot--disc {
    width: var(--disc-size);
  }

  .owners__slot[data-owned="true"] {
    color: var(--seat);
  }

  /* ---- Chain layout ---------------------------------------------------
     At four or more operands a ring of bezels stops being readable, so the
     expression becomes one row per step. Rows show operators and operands only —
     never the running totals, which would hand over most of the answer. */

  .chain {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-1);
    width: 100%;
    max-width: 26rem;
  }

  .chain__row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 0.35rem 0.75rem;
    background: var(--well);
    border-radius: var(--radius-sm);
    box-shadow: var(--bevel-inset);
  }

  .chain__op {
    width: 1.4em;
    flex: 0 0 auto;
    text-align: center;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--text-xl);
    line-height: 1;
    color: var(--bone-label);
  }

  .chain__op[data-forced="true"] {
    color: var(--bone-faint);
  }

  .chain__value {
    font-family: var(--font-display);
    font-weight: 800;
    font-stretch: var(--wdth-operand);
    font-size: var(--text-xl);
    font-variant-numeric: tabular-nums;
    color: var(--bone);
  }

  .chain__owner {
    margin-left: auto;
    font-family: var(--font-data);
    font-size: var(--text-2xs);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--seat);
  }

  .chain__row[data-owned="false"] .chain__owner {
    color: var(--house);
  }

  /* ---- The readout ---------------------------------------------------
     NOT A TEXT FIELD. Painted digit cells in a recessed window: no caret from the
     browser, no inputmode, and therefore no OS keyboard that can ever cover the
     equation on a phone — which is a bug every phone quiz game has. It also solves
     a real problem, since iOS offers no minus key on a numeric keyboard and answers
     here can be negative. */

  .readout {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.06em;
    width: 100%;
    max-width: 26rem;
    min-height: calc(var(--text-readout) * 1.24);
    padding: 0.1em 0.5em;
    background: var(--well);
    border-radius: var(--radius-md);
    box-shadow: var(--bevel-inset-deep);
    font-family: var(--font-display);
    font-weight: 800;
    font-stretch: var(--wdth-operand);
    font-size: var(--text-readout);
    line-height: 1.1;
    color: var(--bone);
    font-variant-numeric: tabular-nums;
    overflow: hidden;
  }

  .readout__digit {
    display: inline-block;
    min-width: 0.58em;
    text-align: center;
  }

  .readout__digit--point {
    min-width: 0.26em;
  }

  .readout__digit--sign {
    min-width: 0.42em;
  }

  /* A block caret, because a calculator has one and a hairline would vanish at
     this weight. */
  .readout__caret {
    display: inline-block;
    width: 0.1em;
    height: 0.68em;
    background: var(--bone-faint);
    border-radius: 1px;
  }

  .readout__placeholder {
    color: var(--bone-faint);
    font-size: 0.42em;
    font-family: var(--font-data);
    font-weight: 400;
    letter-spacing: var(--track-caps);
    text-transform: uppercase;
  }

  .readout[data-state="correct"] {
    color: var(--seat);
  }

  .readout[data-state="wrong"],
  .readout[data-state="locked"] {
    color: var(--signal);
  }

  /* The rules that apply to this round, stated permanently rather than inferred.
     "left to right" is here every round so the convention is never guessed at from
     the presence of brackets; "2 dp" appears only when a divide is on the dial. */
  .hints {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    min-height: 1.1rem;
    font-family: var(--font-data);
    font-size: var(--text-2xs);
    letter-spacing: var(--track-caps);
    text-transform: uppercase;
    color: var(--bone-faint);
  }

  .hints__mark {
    color: var(--bone-label);
  }

  .phase-line {
    min-height: 1.4rem;
    font-family: var(--font-data);
    font-size: var(--text-2xs);
    letter-spacing: var(--track-caps);
    text-transform: uppercase;
    color: var(--bone-label);
    text-align: center;
  }

  .phase-line[data-tone="bad"] {
    color: var(--signal);
  }

  /* ---- The keypad -----------------------------------------------------
     Fifteen keys in a 4x4 grid. Shown on desktop too, not gated behind a coarse
     pointer: the visible press state for physical keys is the point, and hiding
     the signature element on the bigger screen would be perverse. */

  .keypad {
    display: grid;
    grid-template-columns: repeat(4, var(--key-size));
    grid-auto-rows: var(--key-size);
    gap: var(--space-2);
    padding: var(--space-3);
    background: var(--panel);
    background-image: var(--panel-brush);
    border-radius: var(--radius-md);
    box-shadow: var(--bevel-raised);
  }

  .keypad .key {
    min-height: 0;
    padding: 0;
    font-size: var(--text-xl);
    font-weight: 700;
    border-radius: var(--radius-sm);
  }

  .key--enter {
    grid-row: span 2;
    font-size: var(--text-2xl);
  }

  /* No key label may wrap or overflow its face. The digits cannot, but the utility
     glyphs are set in a display face at large sizes and a font fallback can make one
     wider than expected — so this is a guarantee rather than a hope. */
  .keypad .key,
  .ops-row .key {
    overflow: hidden;
    white-space: nowrap;
    line-height: 1;
  }

  .key--util {
    font-size: var(--text-lg);
    color: var(--bone-label);
  }

  /* The decimal key is unlit whenever divide is off in this match. Same idea as the
     operator ring: the console states the rules by existing, and a key that can
     never do anything is worse than no key. */
  .key--point:disabled {
    color: var(--bone-faint);
    opacity: 0.55;
  }

  .keypad[data-locked="true"] {
    box-shadow: var(--bevel-raised), var(--ring-live);
  }

  .keypad__legend {
    font-family: var(--font-data);
    font-size: var(--text-2xs);
    letter-spacing: var(--track-caps);
    text-transform: uppercase;
    color: var(--bone-faint);
    text-align: center;
  }

  /* Once a round is settled the keypad gives up its space on a phone. The keys are
     disabled at that point, so four rows of inert buttons would be pushing the result
     and the host's next control below the fold for nothing.
     This has to live here rather than in the layout layer: `display: grid` above is
     in this layer, and a later layer wins whatever the selectors say. */
  @media (width < 64rem) {
    .board[data-settled="true"] .keypad,
    .board[data-settled="true"] .keypad__legend {
      display: none;
    }
  }

  /* On a short phone the explanatory copy and the physical-keyboard legend are the
     first things to go: there is no physical keyboard on a phone, and the pick note
     says something a player learns once. Both are in this layer for the same cascade
     reason as the rule above. */
  @media (height <= 40rem) and (orientation: portrait) {
    .keypad__legend,
    .pick-note {
      display: none;
    }

    /* Tighter key spacing, without touching the 44px key faces themselves. */
    .keypad {
      padding: var(--space-2);
      gap: var(--space-1);
    }

    .readout {
      min-height: calc(var(--text-readout) * 1.1);
      padding-block: 0;
    }

    .hints,
    .owners__slot,
    .rail__name {
      line-height: 1.2;
    }

    .rail {
      padding-top: var(--space-2);
    }
  }

  /* ---- Pick prompt ---------------------------------------------------- */

  .pick-note {
    max-width: 22rem;
    text-align: center;
    font-size: var(--text-sm);
    letter-spacing: var(--track-body-sm);
    color: var(--bone-label);
  }

  /* ---- Seats ----------------------------------------------------------- */

  .roster {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
    gap: var(--space-2);
  }

  .seat-plate {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 0.6rem 0.7rem;
    background: var(--rail);
    border-radius: var(--radius-sm);
    box-shadow: var(--bevel-raised);
  }

  .seat-plate[data-connected="false"] {
    box-shadow: var(--bevel-inset);
    background: var(--panel);
  }

  .seat-plate[data-connected="false"] .seat-plate__name {
    color: var(--bone-faint);
  }

  /* The applied index. Dark ink on the hue, never bone: bone on these six colours
     measures 1.33–2.71:1 and fails badly. */
  .seat-plate__index {
    display: grid;
    place-items: center;
    width: 1.75rem;
    height: 1.75rem;
    flex: 0 0 auto;
    border-radius: var(--radius-round);
    background: var(--seat);
    color: var(--seat-ink);
    font-family: var(--font-data);
    font-size: var(--text-xs);
    font-weight: 500;
  }

  .seat-plate[data-connected="false"] .seat-plate__index {
    background: none;
    color: var(--bone-faint);
    box-shadow: inset 0 0 0 var(--hair) var(--edge-control);
  }

  .seat-plate__body {
    min-width: 0;
    flex: 1;
  }

  .seat-plate__name {
    display: block;
    font-family: var(--font-display);
    font-weight: 700;
    font-stretch: 104%;
    font-size: var(--text-sm);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .seat-plate__meta {
    display: block;
    font-family: var(--font-data);
    font-size: var(--text-2xs);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--bone-faint);
  }

  .seat-plate__score {
    font-family: var(--font-data);
    font-variant-numeric: tabular-nums;
    font-size: var(--text-lg);
    color: var(--bone);
  }

  .seat-plate__kick {
    display: grid;
    place-items: center;
    width: 1.6rem;
    height: 1.6rem;
    min-height: 0;
    padding: 0;
    flex: 0 0 auto;
    font-size: var(--text-sm);
    color: var(--bone-faint);
    border-radius: var(--radius-xs);
  }

  .seat-plate__kick:hover {
    color: var(--danger);
  }

  .seat-plate__confirm {
    display: flex;
    gap: var(--space-1);
  }

  .seat-plate__confirm .btn {
    min-height: 1.7rem;
    padding: 0.1rem 0.45rem;
    font-size: var(--text-2xs);
  }

  .badge {
    display: inline-block;
    padding: 0.05rem 0.35rem;
    border-radius: var(--radius-xs);
    background: var(--well);
    font-family: var(--font-data);
    font-size: var(--text-2xs);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--bone-faint);
  }

  /* ---- The score rail -------------------------------------------------
     Six seats on a phone is answered by showing different information at
     different phases, not the same information squeezed: during a race you need
     scores, not names, so the rail collapses to indices and totals. At the result
     there is room to expand. */

  .rail {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--space-2) var(--space-3);
    padding-top: var(--space-3);
    border-top: var(--hair) solid var(--edge);
  }

  .rail__seat {
    display: flex;
    align-items: center;
    gap: var(--space-2);
  }

  .rail__dot {
    display: grid;
    place-items: center;
    width: 1.35rem;
    height: 1.35rem;
    border-radius: var(--radius-round);
    background: var(--seat);
    color: var(--seat-ink);
    font-family: var(--font-data);
    font-size: 0.625rem;
    font-weight: 500;
  }

  .rail__seat[data-connected="false"] .rail__dot {
    background: none;
    color: var(--bone-faint);
    box-shadow: inset 0 0 0 var(--hair) var(--edge-control);
  }

  .rail__name {
    font-family: var(--font-data);
    font-size: var(--text-2xs);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--bone-label);
  }

  .rail__score {
    font-family: var(--font-data);
    font-variant-numeric: tabular-nums;
    font-size: var(--text-sm);
    color: var(--bone);
  }

  .rail__seat[data-leader="true"] .rail__score {
    color: var(--seat);
  }

  /* A cooling-down player is shown to everyone. That reverses a decision the
     sibling game made — it hid attempt counts as a real tell — and the reversal is
     deliberate: a wrong guess reveals nothing about a single numeric answer, so
     what was competitive intelligence there is pure drama here. */
  .rail__seat[data-locked="true"] .rail__dot {
    box-shadow: var(--ring-live);
  }

  /* ---- Settings ------------------------------------------------------
     The summary IS the control. Same rows, order, labels and geometry for host and
     guest: the host's row has live affordances, the guest's renders the value as
     static text in the identical slot. One component, two modes, and no separate
     read-only layout to drift out of sync. */

  .settings {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
  }

  .setting {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    min-height: 2.5rem;
    padding: 0.25rem 0;
    border-bottom: var(--hair) solid var(--edge);
  }

  .setting:last-child {
    border-bottom: 0;
  }

  .setting__label {
    font-family: var(--font-data);
    font-size: var(--text-2xs);
    letter-spacing: var(--track-caps);
    text-transform: uppercase;
    color: var(--bone-label);
    white-space: nowrap;
  }

  .setting__value {
    font-family: var(--font-data);
    font-variant-numeric: tabular-nums;
    font-size: var(--text-sm);
    color: var(--bone);
    text-align: right;
  }

  .setting__control {
    display: flex;
    align-items: center;
    gap: var(--space-1);
  }

  /* Four operation keys, sharing the keypad's face. A guest gets them disabled and
     unlit, which doubles as the read-only summary at zero extra height. */
  .ops-row {
    display: flex;
    gap: var(--space-1);
  }

  .ops-row .key {
    width: 2.4rem;
    min-height: 2.4rem;
    padding: 0;
    font-size: var(--text-lg);
  }

  .ops-row .key[aria-pressed="true"] {
    color: var(--bone);
    border-color: var(--bone-faint);
  }

  .ops-row .key[aria-pressed="false"] {
    color: var(--bone-faint);
    box-shadow: var(--bevel-inset);
    background: color-mix(in oklab, var(--panel) 70%, var(--well));
  }

  /* A crown with detents: a fixed option list, stepped through, so there is no
     slider inviting anyone to choose seven seconds. An off state is simply a
     detent past the end of the range, which is how "no pick limit" is expressed. */
  .stepper {
    display: flex;
    align-items: center;
    gap: var(--space-1);
  }

  .stepper .btn {
    width: 1.9rem;
    min-height: 1.9rem;
    padding: 0;
    font-size: var(--text-base);
    color: var(--bone-label);
  }

  .stepper__value {
    min-width: 5.5rem;
    text-align: center;
    font-family: var(--font-data);
    font-variant-numeric: tabular-nums;
    font-size: var(--text-sm);
    color: var(--bone);
  }

  .tiers {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    justify-content: flex-end;
  }

  .tiers .btn {
    min-height: 2rem;
    padding: 0.2rem 0.55rem;
    font-size: var(--text-2xs);
    font-family: var(--font-data);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--bone-label);
  }

  .tiers .btn[aria-pressed="true"] {
    color: var(--bone);
    border-color: var(--bone-faint);
  }

  .warning {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    background: var(--signal-dim);
    color: var(--bone);
    font-size: var(--text-sm);
    letter-spacing: var(--track-body-sm);
  }

  .warning::before {
    content: "!";
    font-family: var(--font-display);
    font-weight: 800;
    color: var(--signal);
  }

  /* ---- Room code and invite ------------------------------------------- */

  .code {
    display: flex;
    gap: var(--space-2);
  }

  .code__digit {
    display: grid;
    place-items: center;
    width: 2.6rem;
    height: 3.2rem;
    background: var(--well);
    border-radius: var(--radius-sm);
    box-shadow: var(--bevel-inset);
    font-family: var(--font-data);
    font-variant-numeric: tabular-nums;
    font-size: var(--text-2xl);
    color: var(--bone);
  }

  /* ---- Countdown ------------------------------------------------------ */

  .countdown {
    display: grid;
    place-items: center;
    width: min(60vmin, 22rem);
    aspect-ratio: 1;
    border-radius: var(--radius-round);
    box-shadow: inset 0 0 0 var(--stroke) var(--signal);
  }

  .countdown__number {
    font-family: var(--font-display);
    font-weight: 800;
    font-stretch: 112%;
    font-size: var(--text-count);
    line-height: 1;
    color: var(--bone);
    font-variant-numeric: tabular-nums;
  }

  .countdown__label {
    position: absolute;
    bottom: 18%;
    font-family: var(--font-data);
    font-size: var(--text-2xs);
    letter-spacing: var(--track-caps);
    text-transform: uppercase;
    color: var(--bone-label);
  }

  /* ---- Result --------------------------------------------------------- */

  .verdict {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-1);
    text-align: center;
  }

  .verdict__answer {
    font-family: var(--font-display);
    font-weight: 800;
    font-stretch: var(--wdth-operand);
    font-size: var(--text-2xl);
    font-variant-numeric: tabular-nums;
    color: var(--seat);
  }

  .verdict__exact {
    font-family: var(--font-data);
    font-size: var(--text-xs);
    letter-spacing: var(--track-data);
    color: var(--bone-faint);
  }

  /* The game's most characteristic sentence. The margin is measured, not invented:
     the host already resolves the coalesced batch by offset-corrected client time,
     so "40ms ahead" is a real number. */
  .verdict__line {
    font-size: var(--text-sm);
    letter-spacing: var(--track-body-sm);
    color: var(--bone-label);
  }

  .verdict__line b {
    color: var(--bone);
    font-weight: 700;
  }

  /* ---- Toasts --------------------------------------------------------- */

  .toast {
    max-width: min(28rem, 100%);
    padding: 0.55rem 0.85rem;
    background: var(--rail);
    border-radius: var(--radius-sm);
    box-shadow: var(--bevel-raised), 0 10px 24px -14px rgb(0 0 0 / 70%);
    font-size: var(--text-sm);
    letter-spacing: var(--track-body-sm);
    color: var(--bone);
    pointer-events: auto;
  }

  .toast[data-tone="good"] {
    box-shadow: var(--bevel-raised), inset 3px 0 0 var(--seat-3);
  }

  .toast[data-tone="bad"] {
    box-shadow: var(--bevel-raised), inset 3px 0 0 var(--danger);
  }

  .toast[data-tone="info"] {
    box-shadow: var(--bevel-raised), inset 3px 0 0 var(--edge-control);
  }

  /* ---- Landing page --------------------------------------------------- */

  .hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-4);
    padding-block: var(--space-6) var(--space-5);
    text-align: center;
  }

  .hero__title {
    font-family: var(--font-display);
    font-weight: 800;
    font-stretch: 116%;
    font-size: var(--text-3xl);
    letter-spacing: var(--track-display);
    line-height: 0.98;
    text-transform: uppercase;
  }

  .hero__lede {
    max-width: 32rem;
    color: var(--bone-label);
    font-size: var(--text-lg);
  }

  .rules {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: var(--space-3);
  }

  .rule {
    padding: var(--space-3);
    background: var(--panel);
    border-radius: var(--radius-md);
    box-shadow: var(--bevel-raised);
  }

  .rule dt {
    font-family: var(--font-data);
    font-size: var(--text-2xs);
    letter-spacing: var(--track-caps);
    text-transform: uppercase;
    color: var(--signal);
  }

  .rule dd {
    margin: var(--space-2) 0 0;
    font-size: var(--text-sm);
    letter-spacing: var(--track-body-sm);
    color: var(--bone-label);
  }

  .colophon {
    padding-top: var(--space-5);
    margin-top: var(--space-6);
    border-top: var(--hair) solid var(--edge);
    font-size: var(--text-sm);
    color: var(--bone-faint);
  }

  .colophon a {
    color: var(--bone-label);
  }
}
