/* ============================================================
   Chrome and the menu. Everything inside the board is drawn on the
   canvas.
   ============================================================ */

/* The same values as COL in src/config.js. The DOM cannot read a JS
   module, so these are a copy and the two have to move together. */
/* How much the CSS-pixel chrome shrinks on a small viewport, 0.6 to 1.

   **Written by resize() in render.js**, which needs the same number to reserve
   the strip at the top of the canvas. Declared here so the page is laid out
   sensibly for the frame or two before the first resize() lands, and so this
   file is readable without the other one. */
:root {
  --ui: 1;

  --void:   #04060d;
  --panel:  rgba(8, 14, 28, 0.72);
  --ink:    #dceeff;
  --dim:    rgba(190, 220, 255, 0.42);
  --mute:   #8fb4cc;

  --carrot: #ff7a1a;   /* the brand, and player 1 */
  --ember:  #ffb066;   /* the pale core of the tube */
  --deep:   #e0620b;   /* the bottom of the wordmark gradient */
  --ice:    #22e7ff;   /* player 2, and every focus ring */
  --win:    #8affc1;
  --danger: #ff5252;   /* the band at full pull, and LOSE */
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  height: 100%;
  overflow: hidden;
  background: var(--void);
  color: var(--ink);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* mobile browsers must not select, magnify or scroll the canvas */
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  touch-action: none;
  overscroll-behavior: none;
}

#board {
  display: block;
  width: 100%;
  height: 100%;
  touch-action: none;
}

/* A tap must not wait 300ms to find out it was not a double tap. */
button { touch-action: manipulation; }

button:focus-visible {
  outline: 2px solid var(--ice);
  outline-offset: 3px;
}

/* ---------------- the boot splash ---------------- */

/* On top of everything, opaque, and styled entirely in this file so it is
   correct on the first paint — see the note in index.html.

   The wordmark is the title screen's, at two thirds the size: the same object
   arriving, not a second logo. Under it one thin ice line with a bright segment
   travelling along it, which is the board's two neon tubes reduced to their one
   essential gesture. Nothing else — a splash that has to be read is a splash that
   is too slow. */
#boot {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: clamp(18px, 3.4vmin, 30px);
  background: var(--void);
  transition: opacity .3s ease-out;
}

/* Faded out rather than hidden, then taken out of the layer entirely. Without
   the second rule it stays a full-screen element over the game forever, eating
   every pointer event — invisible and completely broken. */
#boot.done { opacity: 0; pointer-events: none; }
#boot[hidden] { display: none; }

.bootMark {
  --markSize: clamp(22px, 6.4vmin, 64px);
}

/* The sitelock screen — see the loader at the bottom of index.html.

   Laid out exactly like #boot, because it is the boot splash that never
   finishes: same void, same centring, same wordmark. What replaces the loading
   bar is one line saying where the game actually lives, which is the only thing
   this page is for. */
#locked {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: clamp(18px, 3.4vmin, 30px);
  padding: 24px;
  text-align: center;
  background: var(--void);
}

#locked[hidden] { display: none; }

.lockLine {
  font: 500 clamp(13px, 2.1vmin, 17px)/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: rgba(226, 238, 255, 0.62);
}

.lockLine b { color: var(--ice); font-weight: 700; }

.bootBar {
  position: relative;
  overflow: hidden;
  width: clamp(120px, 30vmin, 260px);
  height: 2px;
  background: rgba(34, 231, 255, 0.14);
  border-radius: 2px;
}

/* The travelling segment. A tube lighting along its length, not a bar filling:
   filling implies a measurement, and there is nothing here being measured. */
.bootBar i {
  position: absolute;
  inset: 0 auto 0 0;
  width: 38%;
  background: var(--ice);
  border-radius: 2px;
  box-shadow: 0 0 10px rgba(34, 231, 255, 0.75), 0 0 22px rgba(34, 231, 255, 0.4);
  animation: bootSweep 1.05s cubic-bezier(.55,.1,.45,.9) infinite;
}

@keyframes bootSweep {
  from { transform: translateX(-105%); }
  to   { transform: translateX(268%); }
}

/* Reduced motion keeps the tube, lit and still: the splash is short enough that
   a steady line reads as "on" rather than as stuck. */
@media (prefers-reduced-motion: reduce) {
  .bootBar i { animation: none; width: 100%; }
}

/* ---------------- in-game chrome ---------------- */

/* The top strip, above the score bars.

   The two belong to different owners and the order says so: the controls are
   the page's furniture, the score is the game's, and the game's is the one
   that gets to sit against the board. Everything the player looks at while
   playing is then in one block — bars, board — with the things they press only
   between rallies above it. */
#chrome {
  position: fixed;
  z-index: 14;      /* above the count-in overlay, which blocks the board */
  align-items: center;
  justify-content: flex-end;
  left: calc(env(safe-area-inset-left, 0px) + 10px * var(--ui));
  top: calc(env(safe-area-inset-top, 0px) + 8px * var(--ui));
  right: calc(env(safe-area-inset-right, 0px) + 8px * var(--ui));
  display: flex;
  gap: calc(6px * var(--ui));
}

/* Square icon buttons, sized for a thumb from the start rather than grown for
   one in a media query. Four of them fit any phone without wrapping, which is
   most of the reason they are icons. */
#chrome button {
  display: grid;
  place-items: center;
  width: calc(40px * var(--ui));
  height: calc(40px * var(--ui));
  padding: 0;
  color: var(--mute);
  background: var(--panel);
  border: 1px solid rgba(255, 122, 26, 0.2);
  border-radius: 10px;
  cursor: pointer;
  backdrop-filter: blur(6px);
  /* The cast shadow every control now carries — see the note on `#btnPlay`.
     These are the smallest of them and get the tightest one. The in-game row
     needs it most of all: it is the one set of buttons sitting over a board
     that is *not* blurred, because the menu is not up behind it. */
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.42);
  transition: color .12s, border-color .12s, box-shadow .12s;
}

#chrome button svg {
  width: calc(21px * var(--ui));
  height: calc(21px * var(--ui));
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* `el.hidden = true` does nothing to an SVG element: `hidden` is an IDL
   property of HTMLElement, and SVGElement has no such property, so the
   assignment lands as a harmless expando and no attribute is ever written. The
   pause icon stayed a pause icon for exactly that reason. Everything that
   swaps an SVG toggles this class instead. */
#chrome button svg[hidden],
svg.gone { display: none !important; }

#chrome button:hover {
  color: var(--ink);
  border-color: rgba(255, 122, 26, 0.55);
}

/* Lit when the thing it controls is on: sound playing, or the game held. Carrot
   on the icon itself rather than a filled button — these are five identical
   squares in a row, and filling one turns it into a different kind of control
   instead of the same control in a different state. */
#chrome button.on {
  color: var(--carrot);
  border-color: rgba(255, 122, 26, 0.55);
  box-shadow: 0 0 13px rgba(255, 122, 26, 0.22);
}

#chrome button[hidden] { display: none; }

/* A thumb still wants 44 px, and still gets it wherever there is room — but
   scaled by `--ui` like everything else, because on the viewport where `--ui`
   is at its floor there is no room, and a 44 px row that refuses to shrink is a
   row that pushes the board off the bottom of the screen.

   This replaced a `max-height: 470px` step that set 36 px and then never moved
   again. A step is the wrong shape for this: it is correct at one height and
   wrong either side of it, and it left the canvas and the DOM disagreeing about
   how tall the chrome was at every height in between. */
@media (pointer: coarse) {
  #chrome button {
    width: calc(44px * var(--ui));
    height: calc(44px * var(--ui));
  }
}

/* ---------------- modals ---------------- */

/* A screen that interrupts is a panel, not a wash.

   The menu's screens are deliberately edgeless: the title sits over a live
   board and the board is the picture. That is exactly wrong for a screen that
   is asking a question or changing a setting mid-round — a translucent block of
   text over moving pucks reads as an overlay you can play through, and the
   first thing a player does is try to. A modal has to look like it stopped
   the game, because it did. */
/* The title screen's own icon row does not belong on a modal. Those three are
   for a player standing at the front door — how to play, settings, mute — and
   on a screen that has interrupted a round they are three more things to hit by
   accident next to the two buttons that matter. Every modal carries its own way
   out. */
#menu.solid #menuTop { display: none; }

/* There was a third scrim here, `#menu.veiled`, at 6 px of blur against 9 and a
   veil of 0.42 against 0.72: the rule-set screen, where the board was meant to be
   softened rather than covered because it was still the thing you were choosing.
   That screen is gone — the rule cards sit on the title now, for CrazyGames'
   one-click rule — and the title screen wants no scrim of its own at all. */
#menu.solid #scrim {
  /* Enough that the board cannot be read, little enough that it is still
     there. The blur does most of the work — it is what makes the pucks
     unreadable — so the veil over it can stay light, and the room keeps its
     depth instead of going flat black.

     14 against the title screen's 8. A modal has interrupted something and
     should say so; the title screen has not interrupted anything, so its board
     stays legible-but-soft rather than going to fog. */
  background: rgba(3, 5, 11, 0.72);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

/* The result is the one interrupting screen that is *not* a card. It is the end
   of the round, not a question asked during one, and it should read as the game
   having stopped and handed the screen back — so it keeps the blurred, darkened
   backdrop and drops the panel. Nothing shows through; there is just nothing
   framing it either. */
#menu.solid #scrOver {
  padding: 0;
  background: none;
  border: 0;
  box-shadow: none;
}

#menu.solid .screen {
  padding: clamp(20px, 4vmin, 34px) clamp(18px, 4vmin, 34px) clamp(18px, 3.4vmin, 28px);
  background: #080d19;
  border: 1px solid rgba(190, 220, 255, 0.16);
  border-radius: 16px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(0, 0, 0, 0.4);
}

/* ---------------- the result ---------------- */

/* The old canvas result, brought back as type.

   It used to be drawn on the board: the winner's name huge, in the winner's
   own colour, with the tube glow around it — and that is the right design, it
   just could not carry a button. So the look moves into the DOM instead of the
   look being replaced by a dialog. Same size, same colour rule, same glow, and
   now there is somewhere to press.

   No panel behind it. The backdrop is blurred and dark so the board cannot be
   read, and the words sit straight on it, which is how they sat before. */
#scrOver h2 {
  font: 900 clamp(30px, 9vmin, 82px)/1 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  letter-spacing: 0.02em;
  padding-right: 0.02em;
  text-transform: uppercase;
}

/* Which colour the heading takes depends on which game is being reported, and
   that split is the whole reason these are separate classes.

   **Against a bot the heading says WIN or LOSE, so the colour is the mood.** Win
   is ice, lose is carrot — the reverse of what it was, and asked for directly. It
   is also the better reading: carrot is the hot end of this palette and lands as
   an alarm, ice is the cool end and lands as settled, and a result screen is
   telling you how to feel rather than who you are.

   **In two-player the heading names a player, so it takes that player's own
   colour** — P1 carrot, P2 ice. There the question is *who*, and those two have
   been carrot and ice everywhere in the game since the palette turned over.
   Swapping them along with the others would have printed the winner's name in
   the loser's colour, which is the regression a blanket swap would have shipped.

   Every rule sets colour and glow together: a heading in one colour wearing
   another's bloom is the thing that looks broken. */
#scrOver.win h2,
#scrOver.p2 h2 {
  color: var(--ice);
  filter:
    drop-shadow(0 0 1px rgba(190, 245, 255, 0.85))
    drop-shadow(0 0 14px rgba(34, 231, 255, 0.55))
    drop-shadow(0 0 48px rgba(34, 231, 255, 0.32));
}

/* LOSE is red, not carrot, and the distinction matters more than it looks.
   Carrot is the *player's own colour* — the brand, the wordmark, their pucks —
   so a loss printed in it says "you" where it should say "no". Red is the one
   colour on this board already reserved for a warning: `COL.danger` is the band
   at full pull and the end wall a puck has just been put through. */
#scrOver.lose h2 {
  color: var(--danger);
  filter:
    drop-shadow(0 0 1px rgba(255, 190, 190, 0.85))
    drop-shadow(0 0 14px rgba(255, 82, 82, 0.6))
    drop-shadow(0 0 48px rgba(255, 82, 82, 0.34));
}

/* Two-player, where the heading is a name and takes its owner's colour. */
#scrOver.p1 h2 {
  color: var(--carrot);
  filter:
    drop-shadow(0 0 1px rgba(255, 176, 102, 0.85))
    drop-shadow(0 0 14px rgba(255, 122, 26, 0.55))
    drop-shadow(0 0 48px rgba(255, 122, 26, 0.32));
}

/* Just the number. "Side cleared in 11.4s" is a sentence explaining a number
   to someone who watched it happen; the number on its own says the same thing
   and gets out of the way of the result above it. A record turns green rather
   than announcing itself in words. */
#scrOver .lede {
  margin: clamp(6px, 1.2vmin, 12px) 0 clamp(20px, 3.6vmin, 34px);
  font: 700 clamp(22px, 5.4vmin, 46px)/1.15 ui-monospace, monospace;
  letter-spacing: 0.1em;
  padding-right: 0.14em;
  color: var(--ink);
  opacity: 0.55;
}

/* A record gets the one animation on this screen.

   Scale from 0.86 with the glow coming up behind it, once, over 0.5 s. Everything
   else here appears; this arrives. It is the only place in the game where the type
   moves after it is on screen, which is what makes it read as an event rather than
   as a style — and it is why there is exactly one of them. */
#scrOver.best h2 {
  animation: recordPop 0.52s cubic-bezier(.16, 1.1, .3, 1) both;
}

@keyframes recordPop {
  from { transform: scale(0.86); opacity: 0; filter: none; }
  60%  { transform: scale(1.03); opacity: 1; }
  to   { transform: scale(1); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  #scrOver.best h2 { animation: none; }
}

#scrOver.best .lede {
  color: var(--win);
  opacity: 1;
  text-shadow: 0 0 16px rgba(138, 255, 193, 0.4);
}

/* ---------------- confirm ---------------- */

#scrAsk h2 {
  font: 800 clamp(15px, 2.9vmin, 23px)/1.25 ui-monospace, monospace;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--carrot);
  text-shadow: 0 0 18px rgba(255, 122, 26, 0.45);
}

.askRow {
  display: flex;
  /* Air between the question and the answers. They were tight under the
     heading, which made the pair read as part of the sentence rather than as
     the thing you press to answer it. */
  margin-top: clamp(16px, 3vmin, 26px);
  gap: 12px;
  flex-wrap: wrap;
  justify-content: center;
}

/* The destructive one is the one that looks destructive, and it is second, so
   the thumb travelling from the left lands on "keep playing" first. */
.danger {
  margin-top: clamp(20px, 3.6vmin, 32px);
  min-height: 44px;
  padding: 12px 27px;
  font: 700 clamp(11px, 1.9vmin, 13px)/1 ui-monospace, monospace;
  letter-spacing: 0.18em;
  padding-right: calc(27px + 0.18em);
  text-transform: uppercase;
  color: var(--void);
  background: var(--carrot);
  border: 1px solid var(--carrot);
  border-radius: 999px;
  cursor: pointer;
  box-shadow: 0 0 16px rgba(255, 122, 26, 0.4);
}

.danger:hover { filter: brightness(1.08); }

/* The restart on the result screen: the chrome's glyph, and the chrome's
   treatment — dark, outlined, the icon itself the only bright thing.

   It was a filled carrot disc, and filled carrot is the pucks. Nothing that is
   not a puck should be that colour at that size, or the eye spends a moment
   deciding whether the board has one more counter on it than it should.
   Outlined, it belongs with the five icons at the top of the screen, which is
   exactly what it is: the restart, in a bigger size because here it is the
   thing you came to press. */
.roundIco {
  display: grid;
  place-items: center;
  width: 58px;
  height: 58px;
  padding: 0;
  color: var(--ink);
  background: var(--panel);
  border: 1px solid rgba(255, 122, 26, 0.45);
  border-radius: 50%;
  cursor: pointer;
  box-shadow: 0 0 18px rgba(255, 122, 26, 0.16);
  transition: color .12s, border-color .12s, box-shadow .12s, transform .12s;
}

.roundIco:hover {
  border-color: rgba(255, 122, 26, 0.8);
  box-shadow: 0 0 24px rgba(255, 122, 26, 0.3);
  transform: translateY(-1px);
}

.roundIco svg {
  width: 27px;
  height: 27px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.askRow { align-items: center; }

/* Two answers to one question, so two identical buttons.

   Same height, same minimum width, same radius — only the colour differs, and
   only because one of them ends the round. A play triangle stood in for
   "resume" here for a while and it was the wrong glyph twice over: it is the
   symbol for *starting* something, and next to an exit icon it made the pair
   read as two functions rather than as yes and no. The word says it exactly. */
#scrAsk .pill {
  display: grid;
  place-items: center;
  /* Both margins zeroed, and this is the whole reason they sat at different
     heights: `.danger` carries a top margin for its use on the result screen,
     where it is the only button and needs air above it. Inherited here it
     pushed the leave button a third of an inch below its own pair. A shared
     class is a shared spacing decision, and this row makes its own. */
  margin: 0;
  min-width: 116px;
  height: 48px;
  padding: 0 20px;
  font: 700 12px/1 ui-monospace, "SF Mono", Consolas, monospace;
  letter-spacing: 0.16em;
  padding-right: calc(20px + 0.16em);
  text-transform: uppercase;
  color: var(--mute);
  background: var(--panel);
  border: 1px solid rgba(190, 220, 255, 0.2);
  border-radius: 999px;
  cursor: pointer;
  transition: color .12s, border-color .12s, box-shadow .12s;
}

#scrAsk .pill:hover { color: var(--ink); border-color: rgba(190, 220, 255, 0.4); }

#scrAsk .pill.danger {
  color: var(--carrot);
  border-color: rgba(255, 122, 26, 0.7);
  background: var(--panel);
  box-shadow: 0 0 18px rgba(255, 122, 26, 0.22);
}

#scrAsk .pill.danger:hover { border-color: var(--carrot); filter: none; }

#scrAsk .pill svg {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Two icons, level, on both screens. They are the same two ideas everywhere in
   the game — go again, or leave — and the top of the board says them with the
   same two glyphs. A screen that ends a round is not the place to invent a
   third vocabulary. */
#scrOver .askRow { gap: clamp(12px, 2.4vmin, 20px); }

/* Does not belong on the title screen: the title screen has its own chrome.
   The record does belong there, so it is the buttons that go, not the row. */
body.menu-open #chrome button { display: none; }

/* ---------------- the count-in ---------------- */

/* Sized to the board by main.js, not to the viewport.

   `inset: 0` centred it on the screen, and the board is not in the middle of
   the screen — it is biased upwards so the scoreboard can sit above it. The
   count read low every time, against a board whose own centre is the divider
   the player is looking at. The inset here is only the fallback for a frame
   before the first layout. */
#countdown {
  position: fixed;
  inset: 0;
  z-index: 13;
  display: grid;
  place-items: center;

  /* It swallows every touch on the board, and that is its second job.

     Gating the shot in input.js stopped a puck being fired, but the puck still
     came to the finger and the cord still bent — the board answered and then
     refused, which is worse than not answering. One overlay over the play area
     is a single declarative rule where a scatter of `if (frozen)` checks would
     be several, and it cannot be forgotten in a code path added later.

     The chrome sits above it, so pause, restart and the rest stay reachable
     through the count: those belong to the player, not to the round. */
  pointer-events: auto;
  touch-action: none;
}

/* The veil, and it is a pseudo-element for a reason worth reading before
   touching either of them.

   `#countdown` itself is **pinned to the board's rect**, not the viewport —
   `placeCount()` in main.js sets its left, top, width and height every relayout,
   because the board is not centred on screen (it sits high, so the score bars can
   have the strip above it) and a number centred on the *screen* lands below the
   middle of the thing it belongs to. That pinning is what makes the count read as
   being on the table.

   But the dimming wants the whole screen: the board softening while the room
   around it stays sharp draws a rectangle round the table, which is the one thing
   a veil must not do. `position: fixed` on a pseudo-element resolves against the
   viewport rather than its parent, so this covers everything while the number it
   sits under stays exactly where the board put it. One element, two frames of
   reference, no second element and no JavaScript.

   `z-index: -1` keeps it behind `#countNum`, which is not positioned and would
   otherwise be painted *under* a positioned pseudo-element. It stays inside
   `#countdown`'s own stacking context, so -1 cannot escape behind the canvas.

   4 px of blur over a veil of 0.16 — the modal scrim is 9 and 0.72, the rule
   screen 6 and 0.42. Still the lightest of the three, and the split matters: the
   *blur* went up and the *veil* did not. Softening reads as depth and the board
   stays fully lit behind it; darkening reads as the game being taken away, and
   this is the one overlay of the three the player is meant to keep watching,
   because the board underneath is what they are about to play. */
#countdown::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  background: rgba(4, 6, 13, 0.16);
  backdrop-filter: blur(4px);
}

#countdown[hidden] { display: none; }

/* Each number arrives big and settles rather than fading in. A count-in is a
   rhythm, and a shape that lands on the beat is the only way type can keep
   time. The last beat is a word, not a fourth number, and it is carrot: the
   three are the clock, GO is the player. */
#countNum {
  /* Light, not heavy. At this size a 900 weight is a slab across the board and
     the pucks disappear behind it; a hairline the same height reads just as
     clearly and lets the board show through, which is the point of counting in
     over it rather than in place of it. The glow does the work a heavy weight
     was doing. */
  font: 200 clamp(58px, 20vmin, 158px)/1 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  letter-spacing: 0.04em;
  padding-right: 0.04em;
  color: var(--ice);
  filter:
    drop-shadow(0 0 2px rgba(190, 245, 255, 0.9))
    drop-shadow(0 0 22px rgba(34, 231, 255, 0.6))
    drop-shadow(0 0 70px rgba(34, 231, 255, 0.35));
  /* One beat long, so the number is gone before the next arrives — the jerk
     was the old curve finishing at 15% opacity and then being replaced, which
     is a cut dressed as a fade. It ends at nothing now. */
  animation: countIn 0.9s ease-in-out both;
}

/* The escalation line under a round announcement.

   Ice against the round's own carrot, small, and letterspaced like every other
   readout on this board. It is only ever one word — the beat is 620 ms and a
   sentence cannot be read in that. */
#countSub {
  margin-top: clamp(6px, 1.2vmin, 11px);
  font: 700 clamp(9px, 1.7vmin, 13px)/1 ui-monospace, "SF Mono", Consolas, monospace;
  letter-spacing: 0.22em;
  padding-right: 0.22em;
  text-transform: uppercase;
  color: var(--ice);
  text-shadow: 0 0 14px rgba(34, 231, 255, 0.55);
}

#countSub:empty { display: none; }

/* The countdown box stacks now that it can carry two lines. It was a grid with a
   single centred child; `place-items` alone would put them side by side. */
#countdown {
  grid-auto-flow: row;
  align-content: center;
  justify-items: center;
}

/* `ROUND 4` in place of a single digit.

   The count-in's numeral is up to 158 px tall because it is one character; seven
   characters at that size is wider than a phone. Two thirds the height and the
   monospace face the rest of the game's readouts use, so it reads as the board
   announcing something rather than as the countdown having grown a word. */
#countdown.round #countNum {
  font: 700 clamp(20px, 6.4vmin, 52px)/1 ui-monospace, "SF Mono", Consolas, monospace;
  letter-spacing: 0.16em;
  padding-right: 0.16em;
}

#countdown.go #countNum {
  font-weight: 300;
  font-size: clamp(34px, 11.5vmin, 92px);
  letter-spacing: 0.14em;
  padding-right: 0.14em;
  color: var(--carrot);
  filter:
    drop-shadow(0 0 2px rgba(255, 205, 160, 0.9))
    drop-shadow(0 0 24px rgba(255, 122, 26, 0.62))
    drop-shadow(0 0 76px rgba(255, 122, 26, 0.36));
}

/* In, hold, out — with the hold doing most of the work.

   The first version spent its whole length moving, from 185% down to 94%, and
   a shape that never stops is a shape you cannot read. A count-in has to be
   legible for most of its beat and in motion only at the ends of it: a third
   of the time arriving, a third still, a third leaving. The scale barely
   changes now, because at this size a small move is a large one. */
@keyframes countIn {
  0%   { opacity: 0; transform: scale(1.3); }
  30%  { opacity: 1; transform: scale(1); }
  66%  { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(0.9); }
}

@media (prefers-reduced-motion: reduce) {
  #countNum { animation: none; }
}

/* ---------------- paused ---------------- */

#pauseVeil {
  position: fixed;
  inset: 0;
  z-index: 12;
  display: grid;
  place-items: center;
  padding: 0;
  background: rgba(4, 6, 13, 0.42);
  /* The whole screen, not just the board: `inset: 0` already covers the viewport,
     so the blur takes the room with it and the board stops being the one sharp
     thing on a soft page.

     8 px, between the rule screen's 6 and a modal's 9, and the veil stays light at
     0.42. Pausing is holding, not interrupting — the board should still be visibly
     there, waiting — so the *softening* does the work and the darkening does not. */
  backdrop-filter: blur(5px);
  border: 0;
  cursor: pointer;
  animation: veilIn 0.16s ease-out;
}

#pauseVeil[hidden] { display: none; }

/* A ring around it. Two bars alone read as part of the board — there is a
   steel divider behind them at almost the same weight — and the ring is what
   makes the shape a *symbol* rather than another thing drawn on the deck. It is
   also the only round thing on screen that is not a puck, which is why it reads
   as a control. */
/* Lit, in the board's own ice, rather than the pale grey ghost it was.
   Everything on this table that means something is a tube — the two side rails,
   the divider's chevron, the score bars, the ring on a held puck — and a symbol
   at 0.30 opacity in near-white belonged to none of that. It read as a
   watermark, which is the one thing a control must not look like.

   The glow lives on the <svg>, not on the two children, and that is not a style
   choice. `filter` lengths on an SVG child are in *user units* — this viewBox is
   24 wide drawn at 168 px, so one unit is seven pixels and a 10-unit blur is 70
   of them. On the root the same numbers are CSS pixels and mean what they say. */
#pauseVeil svg {
  width: min(30vmin, 168px);
  height: min(30vmin, 168px);
  fill: none;
  stroke-linecap: round;
  filter:
    drop-shadow(0 0 2px rgba(147, 240, 255, 0.9))
    drop-shadow(0 0 10px rgba(34, 231, 255, 0.6))
    drop-shadow(0 0 28px rgba(34, 231, 255, 0.34));
}

/* The ring is the tube and the bars are the hot core inside it — the same split
   the held puck's ring uses, where the bloom carries the colour and the core is
   near-white. Two weights as well as two colours: the bars are the figure and
   the ring is what makes it a symbol instead of another thing on the deck. */
#pauseVeil circle {
  stroke: var(--ice);
  stroke-width: 0.9;
  opacity: 0.62;
}

#pauseVeil path {
  stroke: #eaffff;
  stroke-width: 1.8;
  opacity: 0.95;
}

@keyframes veilIn { from { opacity: 0 } }

@media (prefers-reduced-motion: reduce) { #pauseVeil { animation: none } }

/* ============================================================
   Menu
   ============================================================ */

#menu {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  place-items: center;
  padding:
    calc(env(safe-area-inset-top, 0px) + 62px)
    calc(env(safe-area-inset-right, 0px) + 16px)
    calc(env(safe-area-inset-bottom, 0px) + 56px)
    calc(env(safe-area-inset-left, 0px) + 16px);
}

#menu[hidden] { display: none; }

/* Dark at the top and bottom where the type sits, open through the
   middle so the board stays the picture.

   Fixed, not absolute: #menu carries the safe-area padding, so an
   absolute child would be inset by it and leave the top 60-odd pixels
   of the screen unscrimmed — which is exactly where the wordmark's
   glow needs something to sit against. */
#scrim {
  position: fixed;
  inset: 0;
  background:
    /* The two dark bands are where the type goes, and they have to be
       dark enough to kill a puck: the board parks its back rows at 14%
       and 28% in from each end, which is exactly where a title screen
       wants to put a wordmark. The open band in the middle is the
       divider and the gap through it. */
    linear-gradient(180deg,
      rgba(4, 6, 13, 0.95) 0%,
      rgba(4, 6, 13, 0.87) 20%,
      rgba(4, 6, 13, 0.34) 40%,
      rgba(4, 6, 13, 0.34) 57%,
      rgba(4, 6, 13, 0.86) 72%,
      rgba(4, 6, 13, 0.96) 100%),
    radial-gradient(126% 74% at 50% 46%,
      rgba(4, 6, 13, 0) 0%,
      rgba(4, 6, 13, 0.52) 64%,
      rgba(4, 6, 13, 0.84) 100%);

  /* **The title screen is blurred too**, and it did not used to be.

     The gradients above darken the board but leave every edge on it sharp — the
     deck's own SLINGPUCK wordmark, the rails, ten hard-edged pucks — and sharp
     detail behind a control is what stops the control reading as being in
     front. Darker did not fix it and was tried: the bands went to a composited
     0.99 alpha, which is flat black with a whole board behind it doing nothing,
     and the buttons still sat *on* the picture rather than over it.

     Blur is what actually separates them, because it takes the competing detail
     out rather than turning the lights off. The middle band stays open at 0.34
     so the divider and its lit gap are still the composition; they are simply
     out of focus now, which is what a background is.

     8 px is chosen against the puck: a puck is about 40 px across at a typical
     frame, so this is enough to take its edge without dissolving the board into
     a colour field. `#menu.solid` takes it further for the modals. */
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.screen {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  max-width: min(560px, 92vw);
  max-height: 100%;
}

.screen[hidden] { display: none; }

/* The title screen pushes its two blocks apart instead of stacking them
   in the middle, which is what keeps the divider band clear. */
/* `space-between` pins the lockup to the top and the start block to the bottom,
   leaving the board's own divider and its lit gap in the middle — which is the
   composition, and the reason nothing is drawn there.

   The bottom padding is `5.5vh - 20px` rather than a plain `5.5vh`: the start
   block sits 20 px lower than it used to, on request, now that it carries the
   rule cards as well as the two buttons. Written as the subtraction it is so
   the next person can see both the original figure and what was taken off it.
   The `clamp` floor means a short landscape phone, where 5.5vh is under 20 px
   to begin with, simply lands on the 4 px minimum instead of going negative. */
#scrTitle {
  height: 100%;
  justify-content: space-between;
  padding: clamp(4px, 3.4vh, 38px) 0 clamp(4px, calc(5.5vh - 20px), 38px);
}

/* Its own soft backdrop, on top of the scrim.

   The scrim can only darken by height, and the board's back rows land at
   whatever fraction the viewport gives them, so at some sizes a puck
   still reads through the tagline. This darkens behind the type itself
   instead, which holds at every size. Edgeless on purpose: a panel with
   a boundary would turn the title into a dialog box. */
.lockup {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: clamp(10px, 2.2vh, 24px) clamp(20px, 5vw, 64px) clamp(13px, 2.8vh, 30px);
  background: radial-gradient(58% 128% at 50% 46%,
    rgba(4, 6, 13, 0.92) 0%,
    rgba(4, 6, 13, 0.74) 44%,
    rgba(4, 6, 13, 0) 100%);
}

/* ---------------- wordmark ----------------
   No font file ships with this game, so the display face has to be the
   system one. What makes it a wordmark instead of a heading is the
   treatment: a real neon tube is pale at the core and saturated at the
   halo, so the fill runs ember -> carrot and the glow is two stacked
   drop-shadows rather than a single flat blur. */

/* Two lines, and the split carries the meaning rather than just fitting.
   SLING PUCK is the object on the board and wears the neon; ARENA is the word
   that makes it a name instead of the bare product noun CrazyGames' branding
   rule rejects, so it sits under, quieter, in the tubes' own ice.

   It was one line of ten characters. Sixteen at 9.4vmin overruns a 380 px
   phone — measured, not guessed — and the fix is not a smaller wordmark: the
   title screen is the one place this game gets to be loud.

   `--markSize` is set by each mark's own rule (#mark, .bootMark) and everything
   below is expressed against it, so the boot splash is literally the title
   screen's lockup at two thirds, which is what the note in index.html claims. */
#mark {
  --markSize: clamp(30px, 9.4vmin, 96px);
}

#mark, .bootMark {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-transform: uppercase;
}

/* **Lit like a tube, not filled like a letter.**

   It was orange type with an orange glow behind it, which is a *sign* of neon
   rather than neon. Two things make the difference and both are here now.

   **The core goes white.** A real tube is argon burning at a temperature the eye
   cannot assign a hue to; the colour is the phosphor and the gas around it, not
   the middle. `--ember` was already commented "the pale core of the tube" and
   was sitting at 4% of the gradient doing nothing — it is a genuinely pale
   ember now with white-hot above it, and the orange starts below.

   **The halo is tight, and that was learned the hard way.** It ran four
   falloffs at 2 / 8 / 24 / 60 px on the theory that real light fades unevenly,
   and the wide two were the mistake: at this size a 60 px bloom is not a halo,
   it is fog sitting on top of the letterforms, and the whole wordmark went
   soft. Neon looks *sharp* — the tube is a hard bright edge and the spill is
   what happens to the wall behind it, not to the glass.

   So: one 1 px white-hot rim right at the glass, one 7 px carrot bloom just off
   it, and nothing beyond. The letters stay crisp and the colour still comes off
   them. The pale core in the gradient below is what does most of the work of
   reading as lit; the glow only has to confirm it. */
.markTop {
  white-space: nowrap;
  font: 900 var(--markSize)/0.94 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  letter-spacing: 0.015em;
  padding-right: 0.015em;      /* tracking adds space after the last letter */
  color: var(--ember);
  filter:
    drop-shadow(0 0 1px rgba(255, 240, 220, 0.9))
    drop-shadow(0 0 7px rgba(255, 138, 44, 0.5));
}

@supports (background-clip: text) or (-webkit-background-clip: text) {
  .markTop {
    background: linear-gradient(177deg,
      #fff3e4 0%,
      var(--ember) 26%,
      var(--carrot) 62%,
      var(--deep) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
  }
}

/* Tracked out to sit under SLING PUCK at roughly its width — 0.42em across
   five characters is what lands there, and the matching padding-right takes
   back the trailing gap tracking adds so the word stays optically centred.

   Ice rather than carrot, at a third of the size: two neon words stacked would
   be one wordmark shouted twice, and the board's second tube is already this
   colour. The glow is a single shadow because at this size the three-stack the
   line above uses reads as a smudge. */
/* The same tube in the board's other colour — see the note above.

   Pale core here too: it was flat `--ice`, which at this size and weight read as
   cyan text with a soft shadow rather than as a lit thing. `#dcfbff` is ice with
   the temperature taken up, and the cyan is entirely in the halo now.

   Tighter still than the line above, because it is a third the size: a bloom
   scaled for 96 px letters laid over 33 px ones closes up the counters and the
   word turns into a smear of cyan. */
.markSub {
  white-space: nowrap;
  margin-top: calc(var(--markSize) * 0.20);
  font: 700 calc(var(--markSize) * 0.34)/1 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  letter-spacing: 0.42em;
  padding-right: 0.42em;
  color: #dcfbff;
  filter:
    drop-shadow(0 0 1px rgba(214, 250, 255, 0.85))
    drop-shadow(0 0 6px rgba(34, 231, 255, 0.5));
}

.tag {
  margin-top: clamp(8px, 1.7vmin, 15px);
  font: 600 clamp(9px, 1.85vmin, 14px)/1 ui-monospace, "SF Mono", Consolas, monospace;
  letter-spacing: 0.26em;
  padding-right: 0.26em;
  text-transform: uppercase;
  color: var(--ice);
  opacity: 0.72;
}

/* ---------------- play ---------------- */

/* Centred two ways, and it needed both.

   `min-width` makes the button wider than its contents on a narrow screen, and
   an inline-flex defaults to packing them at the start — so on a phone the
   arrow and the word sat left while the button looked symmetrical. And the
   0.2em of tracking is added *after* the last letter as well as between, so
   even packed centrally the text reads a fifth of an em left of centre. The
   padding on the right pays that back. */
#btnPlay {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.68em;
  margin-top: clamp(24px, 5.4vmin, 54px);
  min-height: 48px;
  min-width: 186px;
  padding: clamp(13px, 2.3vmin, 19px) clamp(30px, 5.6vmin, 54px);
  padding-right: calc(clamp(30px, 5.6vmin, 54px) + 0.2em);
  font: 800 clamp(13px, 2.5vmin, 19px)/1 ui-monospace, "SF Mono", Consolas, monospace;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--void);
  background: linear-gradient(180deg, var(--ember) 0%, var(--carrot) 46%, var(--deep) 100%);
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  /* Four layers, and the first one is the new one.

     **A cast shadow, because glow alone does not lift anything.** Everything on
     this screen had light spreading *outward* — PLAY's carrot halo, the icon
     buttons' rims — and nothing had darkness *underneath*, which is the only
     cue that says a thing is above a surface rather than printed on it. Against
     a blurred board the glow just read as more glow.

     Offset down and generously soft: `0 10px 30px` is a shape floating well
     clear of its background, not a border with a bevel. It goes first so the
     carrot halos composite over it rather than under. */
  box-shadow:
    0 10px 30px rgba(0, 0, 0, 0.55),
    inset 0 0 0 1px rgba(255, 205, 160, 0.5),
    0 0 19px rgba(255, 122, 26, 0.45),
    0 0 56px rgba(255, 122, 26, 0.2);
  transition: transform .13s cubic-bezier(.2,.85,.25,1), box-shadow .13s, filter .13s;
}

#btnPlay svg { flex: none; width: 1.18em; height: 1.18em; fill: var(--void); }
#btnPlay span { padding-right: 0.2em; }

#btnPlay:hover {
  filter: brightness(1.07);
  box-shadow:
    inset 0 0 0 1px rgba(255, 220, 180, 0.72),
    0 0 27px rgba(255, 122, 26, 0.6),
    0 0 76px rgba(255, 122, 26, 0.28);
}

#btnPlay:active { transform: translateY(1px) scale(0.985); }

/* ---------------- corners ---------------- */

#menuTop {
  position: absolute;
  z-index: 2;
  top: calc(env(safe-area-inset-top, 0px) + 12px);
  right: calc(env(safe-area-inset-right, 0px) + 12px);
  display: flex;
  gap: 8px;
}

/* The same button as the in-game chrome row, deliberately.

   These were 44 px circles and the chrome's are 40 px rounded squares, which
   made the four controls at the top of the title screen and the five at the top
   of a live round read as two different kinds of thing — and they are not, they
   are the same controls in the same corner doing the same jobs. A player learns
   one shape or two, and there was never a reason for two.

   The circle also cost legibility it had no business costing: a round button
   gives an icon less room in its corners than a squircle of the same width, so
   the glyphs were drawn smaller to fit and came out fainter than the chrome's. */
.ico {
  display: grid;
  place-items: center;
  width: calc(40px * var(--ui));
  height: calc(40px * var(--ui));
  padding: 0;
  color: var(--mute);
  background: var(--panel);
  border: 1px solid rgba(255, 122, 26, 0.2);
  border-radius: 10px;
  cursor: pointer;
  backdrop-filter: blur(6px);
  /* The cast shadow every control now carries — see the note on `#btnPlay`.
     These are the smallest of them and get the tightest one. The in-game row
     needs it most of all: it is the one set of buttons sitting over a board
     that is *not* blurred, because the menu is not up behind it. */
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.42);
  transition: color .12s, border-color .12s, box-shadow .12s;
}

@media (pointer: coarse) {
  .ico { width: calc(44px * var(--ui)); height: calc(44px * var(--ui)); }
}

.ico svg {
  width: calc(21px * var(--ui));
  height: calc(21px * var(--ui));
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.ico svg[hidden] { display: none; }

.ico:hover {
  color: var(--ink);
  border-color: rgba(255, 122, 26, 0.55);
}

/* A chip, under the board, beside the chrome.

   Small, bordered and self-contained, because it is a label rather than part
   of the HUD: it says what the record is, not what is happening. Green only
   once there is one — an empty slot says so in words instead of showing a dash
   nobody can interpret. */
/* The record button, first in the chrome row, has **no rules of its own**.

   It is `#chrome button` and `.ico`, exactly like the five beside it and like the
   Records button on the title screen — and that is now literally true: resolving
   every declaration that lands on this one and on `#btnRecs` gives nineteen
   properties, and before this they differed in exactly one, the colour.

   It was green once there was a record, on the argument that `on` means a control
   is switched on while green would mean *you have one*. Two arguments against it,
   and the second is the one that settled it. The row already has a colour
   language — grey for a control, carrot for a control that is currently on — and a
   third colour on a button that is not a toggle is a word in a language of two.
   And it made this the one icon in the row that does not match the same icon on
   the title screen, which reads as a bug rather than as a state.

   The record is a number on the Records screen. A button does not need to be a
   different colour to say it has something behind it. */

/* Nothing else. The box was never the problem — `#chrome button` centres its
   child with a grid and `#best` is one of those, structurally identical to the
   five beside it. Two rules guessing at line-height and self-alignment lived here
   for a version and changed nothing, which was the evidence: it was the glyph,
   and it is fixed in the markup. See the note on its viewBox in index.html. */

/* ---------------- choose the rules ---------------- */

/* Two cards, and the diagram is the content. Both draw the same board so the
   one gesture that differs is the only thing the eye has to compare — the
   carrot slide arrow on the right card is the entire difference between the
   two games, and it is the only carrot on either. */

.cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(10px, 2vmin, 18px);
  margin-top: clamp(16px, 3.2vmin, 28px);
  width: 100%;
}

/* Player two's keys, on How to play.

   **One gate now, and it is not JavaScript.** It used to have two: `#menu.duo`
   for the mode plus the media query below. The mode gate went with the rule-set
   screen — two-player starts on a single click from the title, so there is no
   longer a screen between choosing it and playing it, and How to play is not
   mode-specific. It documents the game, and player two's keys are part of the
   game whether or not player two is currently sitting there.

   The device gate stays, and stays in CSS. `(hover: hover) and (pointer: fine)`
   asks whether the *primary* input is a mouse or trackpad that can hover —
   which is a computer, and a tablet with a trackpad attached, and both of those
   have a keyboard. A phone answers no and the block does not exist there at
   all, which is right: two people at a phone both use the screen, and a picture
   of four key caps is a puzzle rather than a help.

   Deliberately not `(any-pointer: fine)`, which the on-board coach uses: `any-`
   is true of a phone with a stylus, and a stylus is not a keyboard.

   No JS test for it because a media query costs nothing, cannot go stale when the
   window moves to another screen, and needs no listener to notice. */
#p2keys { display: none; }

@media (hover: hover) and (pointer: fine) {
  #scrHow #p2keys { display: block; }
}

.p2row {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: clamp(5px, 1vmin, 9px);
  margin-top: clamp(15px, 2.8vmin, 26px);
}

/* A key cap: square, the size of the glyph on it, and outlined rather than
   filled — a filled one reads as a button on this screen, where every filled
   thing is something to press and none of these are. */
.kcap {
  display: grid;
  place-items: center;
  min-width: 24px;
  height: 24px;
  padding: 0 4px;
  font: 700 13px/1 ui-monospace, monospace;
  color: var(--ice);
  background: rgba(34, 231, 255, 0.07);
  border: 1px solid rgba(34, 231, 255, 0.34);
  border-radius: 6px;
}

/* The word each group is for, with air after it so the groups read as groups
   rather than as one long row of caps and labels. */
.p2row em {
  margin-right: clamp(7px, 1.5vmin, 15px);
  font: 700 clamp(9px, 1.6vmin, 11px)/1 ui-monospace, monospace;
  font-style: normal;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--mute);
  white-space: nowrap;
}

.p2row em:last-child { margin-right: 0; }

.p2note {
  margin-top: clamp(7px, 1.3vmin, 11px);
  font-size: clamp(10px, 1.6vmin, 12px);
  line-height: 1.45;
  color: var(--ink);
  opacity: 0.42;
}

/* How strong the opponent is, on the rule screen: the bare segmented control,
   with no label and no card around it.

   The Settings version keeps both, and should — a row in a list has to say which
   setting it is, and a card is what separates one row from the next. Neither
   applies here. There is one control, the heading already says what the screen is
   for, and `.screen` centres its children, so the segment sits on its own and
   reads as part of the sentence rather than as a settings row that wandered in.

   Tight under the heading it belongs to and a card's gap above the cards, which
   are what start the round: the gap is the break between "who" and "go". */
#segDiff {
  margin-top: clamp(13px, 2.4vmin, 21px);
}

/* `.seg` sets `display: flex`, which beats the `hidden` attribute's own UA rule —
   so hiding it from JS needs this or the control stays on screen in two-player. */
#segDiff[hidden] { display: none; }

/* Opaque enough to be a card. The scrim behind it is deliberately thin at the
   middle of the screen so the board's own divider shows through the title
   screen, and a translucent panel sitting right on that band read as a smudge
   rather than as something you press. */
.card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(8px, 1.5vmin, 13px);
  padding: clamp(14px, 2.6vmin, 23px) clamp(10px, 2vmin, 18px);
  text-align: center;
  color: var(--ink);
  background: rgba(7, 12, 25, 0.93);
  border: 1px solid rgba(190, 220, 255, 0.16);
  border-radius: 14px;
  cursor: pointer;
  transition: transform .13s cubic-bezier(.2,.85,.25,1), border-color .13s, box-shadow .13s;
}

.card:hover, .card:focus-visible {
  transform: translateY(-2px);
  border-color: rgba(255, 122, 26, 0.5);
  box-shadow: 0 0 22px rgba(255, 122, 26, 0.18);
}

.card:active { transform: translateY(0); }

/* The one that is selected.

   These used to *start* a round, so there was nothing to select — you pressed
   one and the game began. Now they choose which board PLAY will open, which
   means one of them is always the answer and the card has to say which.

   Carrot, and the same carrot the segmented controls use for `.on`, so "lit
   means chosen" means the same thing everywhere in the menu. Border and glow
   rather than a filled panel: the diagram inside is the content, and a solid
   carrot ground would take the ice strokes with it. */
.card.on {
  border-color: var(--carrot);
  background: rgba(24, 13, 6, 0.93);
  box-shadow: 0 0 24px rgba(255, 122, 26, 0.28), inset 0 0 30px rgba(255, 122, 26, 0.07);
}

.card.on b { color: var(--carrot); }

/* The unselected one steps back rather than the selected one shouting. Its
   diagram is still perfectly readable — that is the point of it being there —
   just not competing with the answer. */
.card:not(.on) svg { opacity: 0.62; }

/* The cards arrive rather than appear, one just behind the other, so the eye
   is walked left to right across the choice instead of being handed both at
   once.

   Deliberately without `animation-fill-mode: backwards`. The menu's entrance
   used it and a browser that never ran the keyframes left PLAY invisible and
   the game unstartable; here the worst a non-running animation can do is show
   the cards immediately, which is the correct fallback anyway. */
#menu.intro .card {
  animation: cardIn 0.34s cubic-bezier(.2, .85, .25, 1);
}
/* The second card waits its turn inside its own keyframes rather than on an
   `animation-delay`, and that is not a style choice — it is the fix for a
   visible flicker.

   With a delay and no `backwards` fill, the element spends the delay at its
   normal state and then snaps to the animation's first frame: it appears,
   vanishes, and slides in. `backwards` would fix that and reintroduce a worse
   fault — the menu's entrance once used it and a browser that never ran the
   keyframes left PLAY invisible and the game unstartable. Holding the start
   state inside the timeline costs nothing and cannot fail that way. */
#menu.intro .card:nth-child(2) {
  animation-name: cardIn2;
  animation-duration: 0.44s;
}

@keyframes cardIn2 {
  0%, 22% { opacity: 0; transform: translateY(14px) scale(0.975); }
  100%    { opacity: 1; transform: none; }
}

@keyframes cardIn {
  from { opacity: 0; transform: translateY(14px) scale(0.975); }
}

@media (prefers-reduced-motion: reduce) {
  #menu.intro .card { animation: none; }
}

/* The diagram is the content, so it gets the room. Both cards draw the same
   board — rails, the bar and its gap, one puck below — and the shot through
   the gap. The only thing that differs is what is behind the puck: nothing but
   a spent pull-back arrow on the left, and on the right the cord, bowed into a
   V around the puck. That cord is the entire difference between the two games
   and the only carrot stroke on either card. */
.card svg {
  width: 100%;
  max-width: 156px;
  height: auto;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.card .rail  { stroke: rgba(190, 220, 255, 0.30); stroke-width: 2; }
.card .bar   { fill: rgba(190, 220, 255, 0.40); stroke: none; }
.card .shot  { stroke: var(--ice); stroke-width: 2.6; stroke-dasharray: 4 5; }
.card .head  { stroke: var(--ice); stroke-width: 2.6; }
.card .pull  { stroke: rgba(190, 220, 255, 0.42); stroke-width: 2.2; }
.card .cord  { stroke: var(--carrot); stroke-width: 2.6; }
.card .puck  { fill: #fc6d1f; stroke: none; }

.card > div {
  display: flex;
  flex-direction: column;
  gap: clamp(4px, 0.9vmin, 8px);
}

.card b {
  font: 800 clamp(11px, 1.95vmin, 14px)/1.2 ui-monospace, monospace;
  letter-spacing: 0.13em;
  padding-right: 0.13em;
  text-transform: uppercase;
  color: var(--carrot);
}

/* `.card span` was the description line under each name and it is gone from the
   markup — the cards are a control above PLAY now, not a screen, and the
   diagram either explains itself at this size or it is not doing its job. Its
   breakpoints went with it: everything the cards need at every width is in the
   `#segRules` clamps further down, which is also why the two `.card` steps that
   used to live here at 560 px and 400 px are not here either. They were
   shadowed by those clamps and doing nothing. */

/* ---------------- segmented controls ---------------- */

/* The Settings screen's own styles were here — `#scrSet`, its heading, and the
   `.sets` / `.set` rows that laid each control out as a labelled card. Screen
   and rows are gone; see the note in `index.html` where the section used to be.

   `.seg` below survived because `#segDiff` still uses it — the Easy / Normal /
   Hard control, hidden but wired, kept so putting difficulty back is a CSS
   change rather than a re-integration.

   Segmented rather than a dropdown: every one of these sets is two or three
   items, all of them worth seeing, and a select would hide the choice behind
   a tap and lose the fact that the options are few. */
.seg {
  display: flex;
  gap: 4px;
  padding: 3px;
  background: rgba(4, 6, 13, 0.7);
  border-radius: 9px;
}

.seg button {
  min-height: 34px;
  padding: 7px clamp(8px, 1.6vmin, 14px);
  font: 700 clamp(10px, 1.65vmin, 12px)/1 ui-monospace, monospace;
  letter-spacing: 0.08em;
  white-space: nowrap;
  color: var(--mute);
  background: none;
  border: 0;
  border-radius: 7px;
  cursor: pointer;
  transition: color .12s, background .12s;
}

.seg button:hover { color: var(--ink); }

.seg button.on {
  color: var(--void);
  background: var(--carrot);
  box-shadow: 0 0 13px rgba(255, 122, 26, 0.4);
}

/* A phone on its side has about 390 px of height for a screen that assumed a
   portrait one. Everything gets to scroll, and the two screens that stack the
   most — the rule cards and Settings — go to the row layout early. */
@media (max-height: 470px) {
  #menu {
    padding-top: calc(env(safe-area-inset-top, 0px) + 8px);
    padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 8px);
  }
  .screen {
    overflow-y: auto;
    touch-action: pan-y;
    overscroll-behavior: contain;
    max-width: min(620px, 94vw);
  }
  #scrTitle { justify-content: center; gap: clamp(10px, 3vh, 22px); }
  /* On `.startBlock`, not on `#btnPlay`. It is the gap between the lockup and
     the start of the screen, and PLAY used to be the first thing in that block
     so the two were the same edge. The rule cards are first now, and left on
     the button this pushed PLAY away from the cards it belongs to — the one
     gap that is meant to stay tight. */
  .startBlock { margin-top: clamp(12px, 3.5vh, 26px); }
  /* Landscape on a phone is short, not narrow, so the cards keep their two
     columns and lose height instead — the diagram does the shrinking because it
     is the part that survives being small.

     Carrying `#menu` on the front is not decoration. This block sits ~200 lines
     *above* the base `#segRules` rules, and at equal specificity the later rule
     wins — so a plain `#segRules .card` here would lose to its own base and do
     nothing at all. The extra id puts it ahead regardless of order. */
  #menu #segRules { margin-bottom: 6px; }
  #menu #segRules .card { padding: 8px; gap: 5px; }
  #menu #segRules .card svg { max-width: 74px; }
  .ghost { margin-top: 12px; }
}

/* ---------------- how to play ---------------- */

#scrHow { touch-action: pan-y; overflow-y: auto; overscroll-behavior: contain; }

#scrHow h2 {
  font: 800 clamp(15px, 2.9vmin, 23px)/1 ui-monospace, monospace;
  letter-spacing: 0.22em;
  padding-right: 0.22em;
  text-transform: uppercase;
  color: var(--carrot);
  text-shadow: 0 0 18px rgba(255, 122, 26, 0.45);
}

#scrHow .lede {
  margin: clamp(13px, 2.5vmin, 21px) 0 clamp(17px, 3vmin, 27px);
  max-width: 42ch;
  font-size: clamp(12px, 2.1vmin, 15px);
  line-height: 1.55;
  color: var(--ink);
  opacity: 0.76;
}

#scrHow dl {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: clamp(8px, 1.7vmin, 14px) clamp(13px, 2.4vmin, 22px);
  text-align: left;
  font-size: clamp(11px, 1.95vmin, 14px);
  line-height: 1.5;
}

#scrHow dt {
  font: 700 0.86em/1.62 ui-monospace, monospace;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--carrot);
  white-space: nowrap;
}

#scrHow dd { color: var(--ink); opacity: 0.8; }
#scrHow dd b { color: var(--ice); font-weight: 700; }

@media (max-width: 430px) {
  #scrHow dl { grid-template-columns: 1fr; gap: 2px 0; }
  #scrHow dt { margin-top: 11px; }
}

/* Records is one number, so it is typeset as one: the same weight and glow as the
   result screen's headline, because it is the same fact — how well a run went —
   read at a different moment. */
#recBest {
  margin: clamp(18px, 3.4vmin, 30px) 0 clamp(20px, 3.8vmin, 34px);
  font: 700 clamp(30px, 7vmin, 58px)/1 ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  padding-right: 0.04em;
  color: var(--ice);
  text-shadow: 0 0 18px rgba(34, 231, 255, 0.45);
}

/* PLAY and its second player are one block, not two children.

   #scrTitle spaces its children apart so the lockup goes to the top and the
   start goes to the bottom, with the board's divider left clear between them.
   Adding the two-player button made that three children, and space-between
   duly spread all three — PLAY landed in the middle of the board, on the
   divider, with its partner far below. Wrapped, they are one thing again. */
.startBlock {
  display: flex;
  flex-direction: column;
  align-items: center;

  /* One height for both, and only the height.

     Each keeps its own width — PLAY is wider because PLAY is the button, and a
     secondary that matches the primary edge for edge stops being secondary.
     What cannot differ is how tall they are: 48 against 44 is near enough to
     read as a mistake rather than a choice, which is the worst distance two
     stacked buttons can be apart.

     Set as a variable and applied as `height` rather than left to each one's
     padding and font size, which are deliberately different and would drift
     apart again at the next size. */
  --startH: clamp(48px, 8.4vmin, 62px);
}

.startBlock #btnPlay,
.startBlock #btnDuo {
  height: var(--startH);
  min-height: 0;
  padding-top: 0;
  padding-bottom: 0;
}

/* The rule set, above PLAY rather than on a screen of its own — see the note in
   index.html for why the screen went.

   Above and not below, because it is read before the button is pressed and
   because below would put it between PLAY and Two players, splitting the one
   block `.startBlock` exists to keep together.

   **Smaller than the cards were**, and everything under here is that and only
   that. When they filled a screen of their own they could take 156 px of
   diagram and a line of prose each; as a control sitting above the button they
   are competing with PLAY for the eye, and PLAY has to win. The diagram is kept
   legible and the rest is cut: no description line at all (it is gone from the
   markup), tighter padding, a smaller name.

   Width is capped rather than left to the grid. `.cards` is `1fr 1fr` across
   the full width of the screen, which on a wide desktop frame would have
   stretched two small diagrams into two very large panels. */
#segRules {
  max-width: clamp(240px, 44vmin, 340px);
  margin-top: 0;                 /* `.cards` carries one; nothing is above this */
  gap: clamp(8px, 1.4vmin, 12px);

  /* Close to PLAY on purpose. The pair is one thing — *which board*, then
     *go* — and a gap wide enough to read as a section break makes the cards
     look like a screen the button happens to sit under. Tight enough that the
     eye runs straight from the lit card into the button. */
  margin-bottom: clamp(6px, 1.1vmin, 11px);
}

#segRules .card {
  gap: clamp(5px, 0.9vmin, 8px);
  padding: clamp(9px, 1.5vmin, 13px) clamp(8px, 1.4vmin, 12px);
  border-radius: 11px;
}

#segRules .card svg { max-width: clamp(78px, 15vmin, 108px); }

#segRules .card b {
  font-size: clamp(9px, 1.5vmin, 11px);
  letter-spacing: 0.1em;
  padding-right: 0.1em;
}

/* The two-player button under PLAY: a ghost like every other secondary, with
   room for its icon. */
#btnDuo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  margin-top: clamp(10px, 1.8vmin, 16px);
}

#btnDuo svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

#btnDuo:hover { color: var(--ink); border-color: rgba(255, 122, 26, 0.5); }

.ghost {
  margin-top: clamp(20px, 3.6vmin, 32px);
  min-height: 44px;
  padding: 12px 27px;
  font: 700 clamp(11px, 1.9vmin, 13px)/1 ui-monospace, monospace;
  letter-spacing: 0.18em;
  padding-right: calc(27px + 0.18em);
  text-transform: uppercase;
  color: var(--mute);
  background: var(--panel);
  border: 1px solid rgba(255, 122, 26, 0.24);
  border-radius: 999px;
  cursor: pointer;
  backdrop-filter: blur(6px);
  /* Same cast shadow as PLAY, lighter — see the note there. A secondary should
     sit above the background too, just not as far above as the primary. */
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.45);
  transition: color .12s, border-color .12s;
}

.ghost:hover { color: var(--ember); border-color: rgba(255, 122, 26, 0.55); }

/* ---------------- entrance ----------------
   One sequence, on the first open only. After that the moving thing on
   the title screen is the board behind the scrim, which is motion the
   game already had. */

/* The entrance, and the delays are the whole of what was wrong with it.

   `backwards` holds each element at opacity 0 through its delay, so with PLAY at
   0.24s and the icon row at 0.34s the first third of a second after a refresh was
   a lit board with nothing on it. That does not read as a title screen loading —
   it reads as **the game having started**, and then a menu appearing over the top
   of it, which is exactly what it was reported as.

   The stagger is kept because it is what makes the screen assemble rather than
   appear, but it is now over before it can be mistaken for anything: everything
   is moving by 0.09s and the last of it has landed by 0.42s. The scrim is not
   animated at all and never was, so the board is dimmed on the very first frame;
   what was missing was anything *on* the dimming. */
#menu.intro #mark    { animation: rise .30s 0s    cubic-bezier(.2,.85,.25,1) backwards; }
#menu.intro .tag     { animation: rise .30s .04s  cubic-bezier(.2,.85,.25,1) backwards; }
#menu.intro #btnPlay { animation: rise .30s .075s cubic-bezier(.2,.85,.25,1) backwards; }

#menu.intro #menuTop,

@keyframes rise { from { opacity: 0; transform: translateY(13px); } }
