/* =============================================================================
 * SUPERMINE — style.css                        [OWNER: Agent 3 — presentation]
 * -----------------------------------------------------------------------------
 * Fullscreen canvas + a DOM overlay for the HUD.
 *
 * DESIGN LANGUAGE — "heavy industrial"
 *   * brushed dark metal panels with a hard top bevel and a black bottom edge
 *   * hazard/warning stripes as the accent on anything that means "machinery"
 *   * amber-gold for money, cyan for progress/tech, orange for overdrive,
 *     red for the clock running out
 *   * chunky monospace numerals (tabular) so counters never reflow
 *   * THE CENTRE OF THE SCREEN STAYS EMPTY. Everything is pinned to an edge
 *     except the upgrade announcement (upper third) and the end-of-run card.
 *     This matters more in portrait than it ever did in landscape: the camera
 *     frames the whole 1280-unit lane, so the machine is small and the strip
 *     of rock you are aiming at is the middle of the screen.
 *
 * THE TOP OF THE SCREEN, IN ORDER (portrait first — this is a phone game)
 *   row 1   THE SCORE, one line, FULL WIDTH. It is the point of the game and
 *           it reaches seven figures, so it gets the whole width instead of a
 *           corner, and it SHRINKS rather than wrapping — see --sm-cur-len.
 *   row 2   the COUNTDOWN, centred, with the zone name beneath it; and the
 *           two icon buttons (sound, pause) pinned to the right of that row.
 *   Both rows are placed off --sm-top-y / --sm-top-h, so re-tuning the strip
 *   height on a breakpoint moves everything below it in one edit.
 *
 * SCREEN EDGES
 *   left    upgrade rail (x=10..48), then the haul tally, bottom-anchored and
 *           lifted clear of the steering pads' thumb zone
 *   right   zone banner, icon buttons
 *   bottom  the two meters (overdrive / speed boost), centred and narrow
 *   left+right, full height: THE STEERING PADS. Transparent, and the only
 *           thing besides the buttons and the overlays that takes a tap.
 *
 * #ui-root is pointer-events:none so drags pass through to the canvas; only
 * the buttons, the steering pads and the overlays opt back in. Anything that
 * takes a tap is created AFTER the pads so it paints — and hit-tests — above.
 *
 * Class prefix convention: every UI class starts with `sm-`.
 * Layout switches, all toggled from ui.js on resize, no JS pixel maths:
 *   `.sm-compact`  <900px wide or <520px tall
 *   `.sm-tiny`     <420px wide
 *   `.sm-portrait` taller than it is wide — NOT a synonym for compact: a
 *                  tablet upright is portrait but roomy, a phone on its side
 *                  is compact but has no vertical room at all.
 * ========================================================================== */

:root {
  --sm-bg:        #0b0a0d;

  /* metal */
  --sm-panel:     linear-gradient(180deg, rgba(38,42,50,0.90) 0%, rgba(20,23,28,0.92) 42%, rgba(13,15,19,0.94) 100%);
  --sm-panel-flat: rgba(16, 18, 23, 0.88);
  --sm-edge-hi:   rgba(255, 255, 255, 0.16);
  --sm-edge-lo:   rgba(0, 0, 0, 0.72);
  --sm-border:    rgba(126, 140, 158, 0.26);

  /* type */
  --sm-text:      #eef3f8;
  --sm-dim:       #8e9bab;
  --sm-dimmer:    #5c6674;

  /* accents */
  --sm-gold:      #ffc21f;
  --sm-gold-hot:  #fff0a8;
  --sm-cyan:      #66e2ff;
  --sm-cyan-hot:  #c4f6ff;
  --sm-orange:    #ff8a1f;
  --sm-red:       #ff5a48;
  --sm-green:     #58e08a;

  --sm-radius:    6px;
  --sm-font:      ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --sm-mono:      ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Roboto Mono", monospace;

  --sm-hazard: repeating-linear-gradient(
      135deg,
      #f0b31b 0 8px,
      #171512 8px 16px
  );

  /* --- LAYOUT METRICS ---------------------------------------------------
   * The whole top of the HUD is placed off these two, so a breakpoint that
   * wants a shorter score strip moves the clock, the buttons and the upgrade
   * rail with one declaration instead of five.
   *
   * They are declared on :root rather than on #ui-root deliberately — the
   * layout classes (.sm-compact etc.) live ON #ui-root, and a class selector
   * cannot outrank an #id one. Defaults up here, overrides on the class.
   * ------------------------------------------------------------------- */
  --sm-top-y:      8px;      /* inset of the score strip from the top edge */
  --sm-top-h:     48px;      /* its height — ONE LINE, never two */
  --sm-gutter:    10px;      /* side inset shared by the strip and buttons  */
  --sm-btn-size:  42px;      /* icon button plate, 44px touch box in CSS    */
  /* The air between two icon plates in the corner. */
  --sm-plate-gap:  8px;

  /* Score shrink-to-fit. ui.js publishes only --sm-cur-len (the character
     count); the arithmetic is here. --sm-cur-chrome is the width the strip's
     own furniture eats (padding, the ◆, the multiplier chip). */
  --sm-cur-max:    36px;
  --sm-cur-vw:      5vw;
  --sm-cur-chrome: 300px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: var(--sm-bg);
  color: var(--sm-text);
  font-family: var(--sm-font);
  /* Stop mobile browsers hijacking drags / double-tap zoom. */
  touch-action: none;
  overscroll-behavior: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}

/* A game, not a document (hub CLAUDE.md §2). The block above already stops
   selection and the tap flash; the callout line stops iOS offering Copy /
   Look Up on a long press, and js/touch-guard.js is the half CSS cannot
   promise. Real text fields get selection back here, generically; the
   high-score initials also keep their own rule at .sm-hs-input. */
input,
textarea,
[contenteditable="true"] {
  -webkit-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
}

#game {
  display: block;
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  touch-action: none;
  cursor: grab;
}
#game:active { cursor: grabbing; }

/* ===========================================================================
 * OVERLAY ROOT
 * ======================================================================== */
#ui-root {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 10;
  padding: env(safe-area-inset-top, 0) env(safe-area-inset-right, 0)
           env(safe-area-inset-bottom, 0) env(safe-area-inset-left, 0);
}

/* --- the shared metal plate ------------------------------------------- */
.sm-panel {
  position: relative;
  background: var(--sm-panel);
  border: 1px solid var(--sm-border);
  border-radius: var(--sm-radius);
  /* hard bevel: light on top, black underneath, plus a drop shadow */
  box-shadow:
    inset 0 1px 0 var(--sm-edge-hi),
    inset 0 -2px 0 var(--sm-edge-lo),
    inset 1px 0 0 rgba(255,255,255,0.05),
    0 6px 18px rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(7px) saturate(1.1);
  -webkit-backdrop-filter: blur(7px) saturate(1.1);
  overflow: hidden;
}

/* Warning stripe welded to the top edge of a panel. */
.sm-stripe {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: var(--sm-hazard);
  opacity: 0.85;
}

/* ===========================================================================
 * TOP STRIP — THE SCORE, one line, full width
 * ---------------------------------------------------------------------------
 * This used to be a 208px panel in the top-left corner with the score, three
 * stat chips and the multiplier stacked inside it. On a phone that put the
 * one number the game is about in the smallest box on the screen, and a
 * seven-figure haul broke onto a second line.
 *
 * Now it is a single full-width plate exactly one line tall. The score is
 * absolutely centred inside it so the chips at either end can appear and
 * disappear per breakpoint without ever shifting the number.
 * ======================================================================== */
.sm-topbar {
  position: absolute;
  top: var(--sm-top-y);
  left: var(--sm-gutter);
  /* SHORT OF THE CORNER. The three plates own the top-right corner on every
     screen (hub CLAUDE.md §2), so the strip ends one plate-gap before them
     instead of running gutter to gutter under them. The score stays centred
     in what is left. Spelled out rather than kept in a --sm-corner-w on
     :root: a var() there would be resolved against :root's plate size and
     ignore the smaller one .sm-compact sets on #ui-root. */
  right: calc(var(--sm-gutter) + var(--sm-btn-size) * 3 + var(--sm-plate-gap) * 3);
  height: var(--sm-top-h);
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
  /* No backdrop blur here. The plate is now as wide as the screen, and
     blurring a full-width strip at DPR 3 is real fill rate spent on an effect
     nobody can see against dark rock. The gradient carries the metal alone. */
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  /* ABOVE the clock column (6). The "+10 s" float flies UP out of the clock
     and, now that the score sits where it used to fly into, would land on top
     of the one number that must always be readable. Putting the plate over it
     turns that collision into the right gesture: the reward rises and slides
     away UNDER the deck plate. */
  z-index: 7;
}

/* The slot centres; the group inside it is what the payout pop scales. Two
   elements, so the animation's transform can never fight the centring one. */
.sm-currency-slot {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  max-width: calc(100% - 24px);
}
.sm-currency {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.28em;
  line-height: 1;
  white-space: nowrap;
  transform-origin: center center;
  /* SHRINK-TO-FIT, NO MEASURING.
     ui.js writes the character count into --sm-cur-len on this element (about
     ten times in a run — once per digit gained). The width available is the
     viewport minus the strip's own furniture; dividing it by the character
     count, plus two characters' worth of slack for the ◆ and its gap, is the
     largest size that is guaranteed to fit on ONE line. The plain declaration
     above it is the fallback for engines that will not divide by a var() —
     its vw terms are already safe past fifteen characters.
     The size lives on the GROUP, not on the digits, so the ◆ can be sized in
     `em` and ride the number instead of being pinned to the root font. */
  font-size: min(var(--sm-cur-max), var(--sm-cur-vw));
  font-size: min(var(--sm-cur-max), var(--sm-cur-vw),
                 calc((100vw - var(--sm-cur-chrome)
                       - var(--sm-btn-size) * 3 - var(--sm-plate-gap) * 2) /
                      ((var(--sm-cur-len, 9) + 2) * 0.62)));
}
.sm-ico {
  color: var(--sm-gold);
  font-size: 0.58em;                 /* rides the score, whatever size it is */
  text-shadow: 0 0 14px rgba(255, 194, 31, 0.8);
}
.sm-currency-val {
  font-family: var(--sm-mono);
  font-size: 1em;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.5px;
  white-space: nowrap;
  color: var(--sm-gold);
  text-shadow:
    0 0 22px rgba(255, 194, 31, 0.45),
    0 2px 0 rgba(0, 0, 0, 0.7);
  font-variant-numeric: tabular-nums;
}

/* count-up "payout" pop */
@keyframes sm-pop-kf {
  0%   { transform: scale(1); }
  22%  { transform: scale(1.13); }
  100% { transform: scale(1); }
}
.sm-pop { animation: sm-pop-kf 0.22s cubic-bezier(0.2, 1.4, 0.4, 1); }

.sm-statrow {
  display: flex;
  align-items: center;
  gap: 6px;
}
/* Pinned to the right END of the strip, not to the chips: compact hides the
   chips entirely and the multiplier must not slide left when it does. */
.sm-stat-mult { margin-left: auto; }
.sm-stat {
  font-family: var(--sm-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.6px;
  color: var(--sm-dim);
  background: rgba(0, 0, 0, 0.42);
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 3px;
  padding: 4px 7px;
  font-variant-numeric: tabular-nums;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
}
.sm-stat-mult { color: var(--sm-dimmer); }
.sm-stat-hot {
  color: #0e1116;
  background: linear-gradient(180deg, var(--sm-gold-hot), var(--sm-gold));
  border-color: rgba(255, 240, 168, 0.6);
  text-shadow: none;
  box-shadow: 0 0 16px rgba(255, 194, 31, 0.5);
}

@keyframes sm-flash-kf {
  0%   { transform: scale(1);   filter: brightness(1); }
  25%  { transform: scale(1.28); filter: brightness(2.2); }
  100% { transform: scale(1);   filter: brightness(1); }
}
.sm-flash { animation: sm-flash-kf 0.42s ease-out; }

/* ===========================================================================
 * CENTRED COLUMN — countdown, then the zone line
 * ---------------------------------------------------------------------------
 * A flex column rather than two absolutely-placed blocks, because FREESTYLE
 * deletes the clock entirely (.sm-notimer). In a column the zone line simply
 * rises into the gap; with fixed offsets there would be a hole where the
 * countdown used to be, on the one mode that never has a countdown.
 * ======================================================================== */
.sm-center {
  position: absolute;
  top: calc(var(--sm-top-y) + var(--sm-top-h) + 7px);
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  /* BOUNDED, so a long zone line wraps rather than spreading edge to edge:
     "THE MOTHERLODE  CORE +1 250 m" is 219px of text, which on a 360px phone
     used to run straight into the plates that sat on this row. The corner
     moved up into the strip's row on 2026-10-11, so nothing sits beside the
     column any more — the bound stays because the upgrade rail runs down the
     left edge from here, and an unbounded line would print across it. */
  max-width: calc(100vw - 2 * (var(--sm-gutter) + var(--sm-btn-size) * 2 + 14px));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  z-index: 6;
  pointer-events: none;
}

/* The wrapper is the positioned element so the "+10s" float can escape the
   panel, which clips its overflow. The alarm animation lives on .sm-clock and
   the gain kick on .sm-clock-inner, so the two never fight over `transform`. */
.sm-clockwrap {
  position: relative;
  width: max-content;
  pointer-events: none;
}

.sm-clock {
  padding: 7px 20px 9px;
  /* min-width, not width: the panel must NOT resize as the digits go from
     "1:00" to "9.4" — a clock that twitches sideways is unreadable at speed. */
  min-width: 172px;
  text-align: center;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.sm-clock-label {
  font-family: var(--sm-mono);
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 5px;
  color: var(--sm-dimmer);
  text-indent: 5px;            /* balance the trailing letter-spacing */
}
.sm-clock-digits {
  font-family: var(--sm-mono);
  font-size: 40px;
  font-weight: 900;
  /* FIXED box. The urgent state uses bigger digits, and without a locked
     height the whole panel would grow at the ten-second mark and shove the
     progress gauge down mid-run. */
  height: 42px;
  line-height: 42px;
  letter-spacing: -1px;
  color: var(--sm-cyan-hot);
  font-variant-numeric: tabular-nums;
  text-shadow:
    0 0 24px rgba(102, 226, 255, 0.55),
    0 2px 0 rgba(0, 0, 0, 0.75);
}
.sm-clock-bar {
  height: 5px;
  margin-top: 7px;
  background: linear-gradient(180deg, #05070a, #10141a);
  border: 1px solid var(--sm-border);
  border-radius: 2px;
  overflow: hidden;
  box-shadow: inset 0 1px 3px rgba(0,0,0,0.9);
}
.sm-clock-fill {
  height: 100%;
  width: 100%;
  background: linear-gradient(90deg, #1e93c9, var(--sm-cyan) 55%, #c4f6ff);
  box-shadow: 0 0 12px rgba(102, 226, 255, 0.8);
  transition: width 0.1s linear;
}

/* --- stage 2: running short ------------------------------------------- */
.sm-clock-warn { border-color: rgba(255, 194, 31, 0.55); }
.sm-clock-warn .sm-clock-digits {
  color: var(--sm-gold-hot);
  text-shadow: 0 0 26px rgba(255, 194, 31, 0.65), 0 2px 0 rgba(0,0,0,0.75);
}
.sm-clock-warn .sm-clock-fill {
  background: linear-gradient(90deg, #c4771a, var(--sm-gold) 55%, var(--sm-gold-hot));
  box-shadow: 0 0 14px rgba(255, 194, 31, 0.85);
}
.sm-clock-warn .sm-clock-label { color: var(--sm-gold); }

/* --- stage 3: the last ten seconds ------------------------------------- */
.sm-clock-urgent {
  border-color: rgba(255, 90, 72, 0.75);
  box-shadow:
    inset 0 1px 0 var(--sm-edge-hi),
    inset 0 -2px 0 var(--sm-edge-lo),
    0 0 34px rgba(255, 90, 72, 0.55),
    0 6px 18px rgba(0, 0, 0, 0.55);
  animation: sm-clock-alarm 0.5s ease-in-out infinite;
}
.sm-clock-urgent .sm-clock-digits {
  font-size: 46px;              /* same 42px box — see .sm-clock-digits */
  color: #ffe2dc;
  text-shadow: 0 0 30px rgba(255, 90, 72, 0.95), 0 2px 0 rgba(0,0,0,0.8);
}
.sm-clock-urgent .sm-clock-label { color: var(--sm-red); }
.sm-clock-urgent .sm-clock-fill {
  background: linear-gradient(90deg, #8c1c12, var(--sm-red) 55%, #ffb0a4);
  box-shadow: 0 0 16px rgba(255, 90, 72, 0.95);
}
@keyframes sm-clock-alarm {
  0%, 100% { transform: scale(1);     filter: brightness(1); }
  50%      { transform: scale(1.045); filter: brightness(1.45); }
}

/* --- stage 4: stopped --------------------------------------------------- */
.sm-clock-dead { filter: grayscale(0.7) brightness(0.75); }
.sm-clock-dead .sm-clock-digits { color: var(--sm-dim); text-shadow: 0 2px 0 #000; }

/* --- the gain kick + the "+10s" float ------------------------------------ */
@keyframes sm-clock-kick-kf {
  0%   { transform: scale(1); }
  28%  { transform: scale(1.22); }
  100% { transform: scale(1); }
}
.sm-clock-kick { animation: sm-clock-kick-kf 0.42s cubic-bezier(0.2, 1.5, 0.4, 1); }

.sm-clock-gain {
  position: absolute;
  left: 50%;
  top: 6px;
  transform: translate(-50%, 0);
  font-family: var(--sm-mono);
  font-size: 30px;
  font-weight: 900;
  letter-spacing: 1px;
  color: var(--sm-green);
  text-shadow: 0 0 26px rgba(88, 224, 138, 0.95), 0 2px 4px #000;
  opacity: 0;
  pointer-events: none;
}
.sm-clock-gain-on { animation: sm-clock-gain-kf 1.05s cubic-bezier(0.2, 0.9, 0.3, 1); }
@keyframes sm-clock-gain-kf {
  0%   { opacity: 0; transform: translate(-50%, 8px)   scale(0.7); }
  18%  { opacity: 1; transform: translate(-50%, -6px)  scale(1.25); }
  55%  { opacity: 1; transform: translate(-50%, -34px) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -62px) scale(0.95); }
}

/* ===========================================================================
 * ZONE LINE (under the clock) — all that is left of the progress gauge
 * ---------------------------------------------------------------------------
 * The gauge itself is gone: a percentage through the map is not a decision
 * anybody makes at speed, and on a phone it was the widest element on screen.
 * Two things in it were worth keeping and both live on this one 13px line —
 * the zone NAME, which is the only persistent "where am I" the HUD has, and
 * the CORE counter, which past 100% is where the score is actually earned.
 * ======================================================================== */
/* Wraps rather than overflows: on a narrow phone in the core the name and the
   CORE counter are two lines, not one line halfway under the pause button.
   min-height keeps the 13px slot reserved so nothing twitches when a zone
   name arrives. */
.sm-zoneline {
  display: flex;
  align-items: baseline;
  justify-content: center;
  flex-wrap: wrap;
  gap: 2px 9px;
  min-height: 13px;
  max-width: 100%;
  white-space: nowrap;
}
.sm-zonelabel {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: var(--sm-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 2.4px;
  color: var(--sm-cyan);
  text-shadow: 0 0 12px rgba(102, 226, 255, 0.55), 0 1px 2px #000;
}

/* --- OVERTIME: past 100%, still digging ---------------------------------
 * Cyan is the colour of "how far through are you", and that question has no
 * answer down here — gold is the colour of "this is worth money", which is
 * the only thing the core is about. Hidden until there IS overtime, so the
 * line is just the zone name for the first three minutes of a run. */
.sm-zonecore {
  display: none;
  font-family: var(--sm-mono);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 1.6px;
  color: var(--sm-gold);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 14px rgba(255, 194, 31, 0.7), 0 1px 2px #000;
  animation: sm-core-breathe 1.6s ease-in-out infinite;
}
.sm-zone-core .sm-zonecore { display: block; }
.sm-zone-core .sm-zonelabel {
  color: var(--sm-gold);
  text-shadow: 0 0 12px rgba(255, 194, 31, 0.6), 0 1px 2px #000;
}
@keyframes sm-core-breathe { 50% { filter: brightness(1.35); } }

/* ===========================================================================
 * METERS (bottom centre) — overdrive + speed boost, hidden by default
 * ---------------------------------------------------------------------------
 * These used to hang off the bottom of the progress gauge. They cannot follow
 * the zone line under the clock: on a phone in landscape the top cluster is
 * already a third of the screen, and two more bars would push the upgrade
 * announcement into the middle of it. They are countdowns on a state you can
 * already SEE (effects.js grades the whole screen for overdrive), so the
 * bottom edge is the honest place for them — narrow, centred, between the
 * two steering pads, and invisible unless something is actually running.
 * ======================================================================== */
.sm-meters {
  position: absolute;
  left: 50%;
  bottom: max(12px, 2.4vh);
  transform: translateX(-50%);
  width: min(230px, 52vw);
  pointer-events: none;
}
.sm-od {
  width: 100%;
  margin-top: 3px;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.18s ease, transform 0.18s ease;
  pointer-events: none;
}
.sm-od-on { opacity: 1; transform: translateY(0); }

.sm-od-label {
  font-family: var(--sm-mono);
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 3px;
  color: var(--sm-orange);
  text-align: center;
  text-shadow: 0 0 12px rgba(255, 138, 31, 0.9);
  animation: sm-od-blink 0.5s steps(2, end) infinite;
}
@keyframes sm-od-blink { 50% { opacity: 0.45; } }

.sm-od-bar {
  height: 6px;
  background: #0a0705;
  border: 1px solid rgba(255, 138, 31, 0.35);
  border-radius: 2px;
  overflow: hidden;
}
.sm-od-fill {
  height: 100%;
  width: 100%;
  background: linear-gradient(90deg, #ff4d1a, var(--sm-orange) 60%, #ffd479);
  box-shadow: 0 0 14px rgba(255, 138, 31, 0.85);
}

/* ===========================================================================
 * BUTTONS
 * ---------------------------------------------------------------------------
 * RESTART used to be a word on the HUD, one mis-tap from throwing a run in
 * the bin. It lives inside the pause card now, behind the three bars in the
 * corner, which is a far better place to be asked than a confirm dialog.
 * ======================================================================== */
.sm-btn {
  position: relative;
  font-family: var(--sm-mono);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 1.6px;
  color: var(--sm-text);
  background: var(--sm-panel);
  border: 1px solid var(--sm-border);
  border-radius: 4px;
  /* 44px minimum touch target */
  min-height: 40px;
  min-width: 74px;
  padding: 10px 14px;
  cursor: pointer;
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
  box-shadow:
    inset 0 1px 0 var(--sm-edge-hi),
    inset 0 -2px 0 var(--sm-edge-lo),
    0 4px 12px rgba(0,0,0,0.5);
  transition: filter 0.12s, transform 0.06s, box-shadow 0.12s;
}
.sm-btn:hover { filter: brightness(1.35); }
.sm-btn:active {
  transform: translateY(2px);
  box-shadow: inset 0 2px 5px rgba(0,0,0,0.8);
}
.sm-btn-primary {
  color: #06131a;
  background: linear-gradient(180deg, var(--sm-cyan-hot), var(--sm-cyan) 45%, #2597c4 100%);
  border-color: rgba(196, 246, 255, 0.5);
  text-shadow: 0 1px 0 rgba(255,255,255,0.35);
}
.sm-btn-big {
  font-size: 14px;
  letter-spacing: 2.4px;
  min-height: 52px;
  padding: 16px 34px;
  margin-top: 20px;
  width: 100%;
}

/* --- the icon plate ---------------------------------------------------
 * Square, gold-on-dark, with the same hazard sliver the panels wear welded
 * to its top edge — that stripe is what says "machinery" everywhere else in
 * the game, and it is what keeps a 42px button from reading as a generic
 * mobile chrome control. */
.sm-iconbtn {
  width: var(--sm-btn-size);
  height: var(--sm-btn-size);
  min-width: 0;
  min-height: 0;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 5px;
  overflow: hidden;
  color: var(--sm-gold);
}
.sm-iconbtn::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: var(--sm-hazard);
  opacity: 0.8;
}
.sm-btn-svg {
  display: block;
  width: 20px;
  height: 20px;
  filter: drop-shadow(0 0 7px rgba(255, 194, 31, 0.5));
}
/* Muted: the same speaker, greyed and unlit. The glyph itself changes too
   (ui.js swaps in the crossed-out one) — colour alone is not a state. */
.sm-iconbtn.sm-btn-off { color: var(--sm-dimmer); }
.sm-iconbtn.sm-btn-off .sm-btn-svg { filter: none; }
.sm-iconbtn.sm-btn-off::before { opacity: 0.35; }
/* BOTH STATES ARE IN THE DRAWING, and aria-pressed picks one. ui.js writes
   aria-pressed and the label together, so the engraving cannot say one thing
   while a screen reader says another (hub CLAUDE.md §2). */
.sm-iconbtn[aria-pressed="true"] .sm-g-rest,
.sm-iconbtn:not([aria-pressed="true"]) .sm-g-pressed { display: none; }

/* ===========================================================================
 * PAUSE MENU
 * ---------------------------------------------------------------------------
 * Deliberately small and quick. It is not a settings screen; it is the two
 * things you can do with a run that is currently stopped.
 * ======================================================================== */
.sm-pause {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(ellipse at center, rgba(4,6,9,0.55), rgba(2,3,5,0.9));
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.22s ease;
  /* Above the summary (15) AND the start overlay (20), because the same card
     is the Settings face over both of them now. In a run neither is up.
     BELOW .sm-corner (30): the three bars that opened it stay lit above its
     scrim, which is what lets a second press close it. */
  z-index: 22;
}
.sm-pause-on { opacity: 1; pointer-events: auto; }

.sm-pause-card {
  width: min(380px, 90vw);
  /* A safety net on a very short viewport, not a plan — the landscape block
     at the end of this file is the plan. .sm-panel clips by default. */
  max-height: 94vh;
  overflow: auto;
  padding: 22px 22px 20px;
  text-align: center;
  transform: translateY(14px) scale(0.97);
  transition: transform 0.3s cubic-bezier(0.16, 1.5, 0.35, 1);
}
.sm-pause-on .sm-pause-card { transform: none; }

.sm-pause-kicker {
  font-family: var(--sm-mono);
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 5px;
  text-indent: 5px;
  color: var(--sm-dimmer);
}
.sm-pause-title {
  font-size: 34px;
  font-weight: 900;
  letter-spacing: 6px;
  text-indent: 6px;
  line-height: 1.1;
  margin-bottom: 16px;
  color: #fff;
  text-shadow: 0 0 26px rgba(255, 194, 31, 0.4), 0 3px 0 rgba(0, 0, 0, 0.6);
}
/* NO `pointer-events: auto` HERE, and this is not an oversight.
   The overlay is inset:0 and only opacity-0 while closed, so a child that
   opts back into hit-testing on its own is a full-size invisible button
   sitting in the dead centre of the screen — which is exactly where a
   desktop player puts the mouse down to drag-steer. Interactivity is
   inherited from .sm-pause-on instead, so it exists only while the menu
   does. (Same trap caught the high-score field below.) */
.sm-pause-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  min-height: 48px;
  margin-top: 9px;
}
.sm-pause-ico { display: block; width: 17px; height: 17px; }
/* THE TWO FACES. In a run: kicker, PAUSE, RESUME / RESTART / MAIN MENU. Off a
   run: SETTINGS and a plain BACK, because there is nothing to resume. The
   settings half underneath is the same in both. */
.sm-set-title,
.sm-pause:not(.sm-pause-settings) .sm-set-only,
.sm-pause-settings .sm-run-only,
.sm-pause-settings .sm-pause-kicker { display: none; }
.sm-pause-settings .sm-set-title { display: block; }
.sm-pause-settings .sm-pause-title:not(.sm-set-title) { display: none; }
/* The settings half: the volumes, the language and the way out, set off from
   the run's buttons by the same hairline the way out has always had, and
   left-aligned so every row's control starts on one gutter. */
.sm-pause-set {
  margin-top: 14px;
  padding-top: 2px;
  border-top: 1px solid rgba(142, 155, 171, 0.16);
  text-align: left;
}
.sm-pause-ico .sm-btn-svg { width: 100%; height: 100%; filter: none; }
.sm-pause-label { line-height: 1; }

/* LEAVING THE GAME ENTIRELY — the same object on the pause card and on the
   main menu (.sm-start-quit below borrows every line of this). The hub makes
   it one button in every cabinet (CLAUDE.md §2, "One button, and it looks and
   behaves the same in every game"): last in its column, full column width, a
   little more air above it than between the others, SECONDARY — and this is
   the mine's secondary: an empty plate, a brass hairline round it and brass
   words, where every other button on the card is filled metal. Never the
   primary cyan, because leaving is never the recommended action.

   SENTENCE CASE, and this is the one button in the game that is. The strings
   arrive as "Back to arcade" / "Tilbake til arkaden", nothing here raises
   them, and the tracking drops to suit lower case — the brass capitals
   everywhere else are this game's voice, and this one control is the hub's. */
.sm-btn-quit,
.sm-start-quit {
  margin-top: 18px;
  border: 1px solid rgba(255, 194, 31, 0.34);
  background: transparent;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  color: rgba(255, 194, 31, 0.86);
  font-size: 12px;
  letter-spacing: 0.4px;
}
.sm-btn-quit .sm-btn-svg,
.sm-start-quit .sm-btn-svg { filter: none; }
.sm-btn-quit:hover:not(:disabled),
.sm-btn-quit:focus-visible,
.sm-start-quit:hover:not(:disabled),
.sm-start-quit:focus-visible {
  color: var(--sm-gold);
  border-color: rgba(255, 194, 31, 0.66);
  background: rgba(255, 194, 31, 0.06);
  filter: none;
}
.sm-btn-quit:disabled,
.sm-start-quit:disabled { color: var(--sm-dimmer); border-color: var(--sm-border); cursor: default; }

/* ===========================================================================
 * LANGUAGE ROW (menu card)
 * ---------------------------------------------------------------------------
 * Two equal plates, Norsk first, each a flag and its endonym. `flex: 1 1 0`
 * so the pair is the same size whatever the two names measure — they are
 * alternatives, and the bigger one would read as the recommended one. The
 * chosen plate is lit the way the HUD lights a live readout: gold rim, gold
 * word, a glow. The other stays brushed metal with its flag dimmed, so the
 * state reads without colour alone. The DOM says "Norsk" / "English" and
 * CSS raises the case, so a screen reader hears a word and not letters.
 * ======================================================================== */
.sm-lang-seg {
  display: flex;
  gap: 8px;
  flex: 1 1 0;
  min-width: 0;
}
.sm-lang-btn {
  flex: 1 1 0;
  min-width: 0;
  min-height: 44px;
  padding: 8px 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  color: var(--sm-dim);
}
.sm-lang-name { text-transform: uppercase; line-height: 1; }
/* The row hides itself when i18n.js is missing; [hidden] loses to the
   display:flex that .sm-sound-row sets, so say it outright. */
.sm-lang[hidden] { display: none; }
.sm-flag {
  display: block;
  flex: 0 0 auto;
  width: 22px;
  height: 15px;
  border-radius: 2px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.7);
  opacity: 0.6;
  transition: opacity 0.15s;
}
.sm-lang-btn[aria-pressed="true"] {
  color: var(--sm-gold);
  border-color: rgba(255, 194, 31, 0.6);
  text-shadow: 0 0 10px rgba(255, 194, 31, 0.45);
  box-shadow:
    inset 0 0 0 1px rgba(255, 194, 31, 0.28),
    inset 0 1px 0 var(--sm-edge-hi),
    inset 0 -2px 0 var(--sm-edge-lo),
    0 0 14px rgba(255, 194, 31, 0.22);
}
.sm-lang-btn[aria-pressed="true"] .sm-flag { opacity: 1; }
.sm-lang-btn:focus-visible { outline: 2px solid var(--sm-cyan); outline-offset: 2px; }



/* A frozen run must LOOK frozen. main.js holds the fixed step but CSS
   animations are not part of it, so without this the clock keeps throbbing
   red and the OVERDRIVE label keeps blinking behind the menu — which reads
   as "the timer is still running", the one thing a pause has to disprove. */
.sm-paused .sm-clock-urgent,
.sm-paused .sm-od-label,
.sm-paused .sm-zonecore,
.sm-paused .sm-banner-final .sm-banner-text { animation: none; }

/* ===========================================================================
 * STEERING PADS (left + right, full height, transparent)
 * ---------------------------------------------------------------------------
 * Drag-steering is a laptop gesture. Held one-handed, a drag puts your thumb
 * in the middle of the screen — over the rock you are steering through — and
 * has no resting position. Two edge pads have both: your thumb is already
 * there, and the middle stays clear.
 *
 * They are TRANSPARENT on purpose. The chevrons are the only paint, they sit
 * low where the thumb is, and they light up while held so the control still
 * confirms itself. A solid button here would cover a fifth of the mine.
 *
 * Enabled by LAYOUT, not by sniffing: any compact viewport, anything taller
 * than it is wide, and anything with a coarse pointer. A mouse desktop never
 * gets them, so full-screen drag-steering there is completely untouched.
 * ======================================================================== */
.sm-pads {
  position: absolute;
  inset: 0;
  display: none;
  pointer-events: none;
}
.sm-compact .sm-pads,
.sm-portrait .sm-pads { display: block; }
@media (hover: none) and (pointer: coarse) {
  .sm-pads { display: block; }
}

.sm-pad {
  position: absolute;
  top: 0;
  bottom: 0;
  width: clamp(76px, 27vw, 230px);
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  color: rgba(255, 255, 255, 0.17);
  cursor: pointer;
  pointer-events: auto;
  touch-action: none;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.14s ease, color 0.14s ease;
}
.sm-pad-left  { left: 0; }
.sm-pad-right { right: 0; }
.sm-pad-svg {
  display: block;
  width: 30px;
  height: 30px;
  /* Low, in the thumb zone, and clear of the haul tally above it. */
  margin-bottom: max(16px, 3.6vh);
  filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.9));
}
.sm-pad-on { color: var(--sm-cyan-hot); }
.sm-pad-left.sm-pad-on {
  background: linear-gradient(90deg, rgba(102, 226, 255, 0.17), rgba(102, 226, 255, 0) 78%);
}
.sm-pad-right.sm-pad-on {
  background: linear-gradient(270deg, rgba(102, 226, 255, 0.17), rgba(102, 226, 255, 0) 78%);
}

/* ===========================================================================
 * UPGRADE ANNOUNCEMENT (upper third — never the dead centre)
 * ======================================================================== */
.sm-toast {
  position: absolute;
  /* Below the whole top cluster (strip + clock + zone line ~= 190px). On a
     short desktop window a flat percentage would land it on the clock. */
  top: max(21%, 200px);
  left: 50%;
  width: min(760px, 88vw);
  transform: translate(-50%, -18px) scale(0.9);
  text-align: center;
  opacity: 0;
  transition: opacity 0.2s ease, transform 0.34s cubic-bezier(0.16, 1.7, 0.35, 1);
  will-change: opacity, transform;
}
.sm-toast-on {
  opacity: 1;
  transform: translate(-50%, 0) scale(1);
}
.sm-toast-kicker {
  font-family: var(--sm-mono);
  font-size: clamp(9px, 1.1vw, 12px);
  font-weight: 800;
  letter-spacing: 6px;
  color: var(--sm-cyan);
  margin-bottom: 6px;
  text-shadow: 0 0 16px rgba(102, 226, 255, 0.9), 0 2px 3px #000;
}
.sm-toast-title {
  font-size: clamp(26px, 5.2vw, 62px);
  font-weight: 900;
  letter-spacing: 2px;
  line-height: 1.02;
  color: #fff;
  text-transform: uppercase;
  text-shadow:
    0 0 26px rgba(102, 226, 255, 0.9),
    0 0 70px rgba(102, 226, 255, 0.5),
    0 4px 0 rgba(0, 0, 0, 0.65),
    0 8px 22px rgba(0, 0, 0, 0.8);
}
.sm-toast-sub {
  margin-top: 8px;
  font-family: var(--sm-mono);
  font-size: clamp(11px, 1.5vw, 16px);
  font-weight: 700;
  letter-spacing: 1.4px;
  color: var(--sm-cyan-hot);
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.95);
}

/* ===========================================================================
 * POWER-UP SPLASH (mid screen — the one exception to "keep the centre empty")
 * ---------------------------------------------------------------------------
 * "+5 SEC" when a time cell shatters, "BOOST MODE" when a boost block does.
 * It breaks the centre-stays-empty rule on purpose and pays for it by being
 * brief: the whole thing is on and gone inside 1.1s, matching SPLASH_TIME in
 * ui.js. Everything about it is tuned for a player who is STEERING:
 *   * two words, no sentence — you parse the shape, not the text
 *   * sat at 41% rather than dead centre, so it is above the machine and out
 *     of the strip of rock you are actually aiming at
 *   * the material's own colour, so the splash and the thing you just drove
 *     through are obviously the same event
 * The wash is a deliberately weak echo of the overdrive colour grade in
 * effects.js — same gesture, ~a fifth of the alpha and half a second instead
 * of six, because boost mode has to stay legible as the LESSER of the two.
 * ======================================================================== */
/* The outer element is the whole viewport and is NEVER transformed: a
   transformed ancestor would become the containing block for the wash and
   shrink it to the width of the text. All the motion lives on -inner. */
.sm-splash {
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* The tint is set by the -time / -boost modifiers below and everything else
     in the block inherits from it, so a colour change is one line. */
  --sm-sp: var(--sm-cyan);
  --sm-sp-hot: var(--sm-cyan-hot);
  --sm-sp-rgb: 102, 226, 255;
}
/* Time keeps the GATE green (rgb 90,255,150) rather than the darker teal the
   time-cell casing was pushed to, because on the HUD green already means "the
   clock just went up" — the arch, the "+10s" float and this all have to agree.
   The casing colour is a WORLD-side readability fix, not a HUD one. */
.sm-splash-time  { --sm-sp: #5aff96; --sm-sp-hot: #ddffea; --sm-sp-rgb: 90, 255, 150; }
.sm-splash-boost { --sm-sp: #ff8a1f; --sm-sp-hot: #ffe3bd; --sm-sp-rgb: 255, 138, 31; }
/* 100% reached. Gold, because it is the same "you banked something big"
   language the currency and the final score already use. */
.sm-splash-core  { --sm-sp: #ffc21f; --sm-sp-hot: #fff0a8; --sm-sp-rgb: 255, 194, 31; }

/* Full-screen wash. Radial and centred on the text, so the edges of the
   screen never actually tint — it reads as the world flaring around the thing
   you just hit, not as a coloured pane dropped over the game. */
.sm-splash-wash {
  position: absolute;
  inset: 0;
  opacity: 0;
  background: radial-gradient(ellipse 70% 55% at 50% 46%,
              rgba(var(--sm-sp-rgb), 0.20) 0%,
              rgba(var(--sm-sp-rgb), 0.07) 42%,
              rgba(var(--sm-sp-rgb), 0) 72%);
}

.sm-splash-inner {
  position: absolute;
  top: 43%;
  left: 50%;
  width: min(720px, 92vw);
  transform: translate(-50%, -50%);
  text-align: center;
  opacity: 0;
}

.sm-splash-big {
  position: relative;
  font-size: clamp(42px, 8.4vw, 104px);
  font-weight: 900;
  letter-spacing: 3px;
  line-height: 0.98;
  color: #fff;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  /* Two tight shadows for legibility over bright rock, two wide ones for the
     glow. The hard black offset is what keeps it readable against a gold seam
     — colour alone loses that fight every time. */
  text-shadow:
    0 0 22px rgba(var(--sm-sp-rgb), 0.95),
    0 0 78px rgba(var(--sm-sp-rgb), 0.65),
    0 4px 0 rgba(0, 0, 0, 0.7),
    0 10px 26px rgba(0, 0, 0, 0.9);
}
.sm-splash-sub {
  position: relative;
  margin-top: 7px;
  font-family: var(--sm-mono);
  font-size: clamp(11px, 1.6vw, 17px);
  font-weight: 800;
  letter-spacing: 5px;
  text-indent: 5px;                 /* letter-spacing pads the right edge only */
  color: var(--sm-sp-hot);
  text-shadow: 0 0 14px rgba(var(--sm-sp-rgb), 0.9), 0 2px 5px rgba(0, 0, 0, 0.95);
}

/* One animation on the wrapper drives the whole thing. Punch in over 0.16s
   with an overshoot, hold for half a second, then leave UPWARD while fading —
   drifting up reads as "banked" and clears the machine's approach at the same
   time. Keyframe times are percentages of SPLASH_TIME (1.1s). */
.sm-splash-on .sm-splash-inner { animation: sm-splash-kf 1.1s cubic-bezier(0.2, 0.9, 0.3, 1) both; }
.sm-splash-on .sm-splash-wash  { animation: sm-splash-wash-kf 1.1s ease-out both; }

@keyframes sm-splash-kf {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.72); }
  14%  { opacity: 1; transform: translate(-50%, -50%) scale(1.06); }
  22%  { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  62%  { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, calc(-50% - 46px)) scale(0.97); }
}
@keyframes sm-splash-wash-kf {
  0%   { opacity: 0; }
  12%  { opacity: 1; }
  46%  { opacity: 0.55; }
  100% { opacity: 0; }
}

/* ===========================================================================
 * UPGRADE RAIL (left edge, under the stat panel)
 * A column of tiles, one per owned upgrade. `flex-wrap: column` against a
 * max-height means a 13-upgrade run spills into a SECOND column rather than
 * running off the bottom of a short screen — no JS pixel maths, no scroll.
 * ======================================================================== */
.sm-rail {
  position: absolute;
  left: 10px;
  /* Clears the score strip, and moves with it when a breakpoint shortens it. */
  top: calc(var(--sm-top-y) + var(--sm-top-h) + 14px);
  /* Reserves the bottom of the left edge for the haul tally (11 rows of 18px
     + head + its 46px bottom offset ~= 268px). A long run wraps into a second
     column instead of running down into the tally. */
  max-height: calc(100vh - 400px);
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: 7px;
  pointer-events: none;
  z-index: 4;
}

.sm-rail-tile {
  position: relative;
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--sm-cyan);
  background: var(--sm-panel);
  border: 1px solid var(--sm-border);
  border-left: 3px solid rgba(102, 226, 255, 0.75);
  border-radius: 4px;
  box-shadow:
    inset 0 1px 0 var(--sm-edge-hi),
    inset 0 -2px 0 var(--sm-edge-lo),
    0 4px 12px rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.sm-rail-ico {
  display: block;
  width: 22px;
  height: 22px;
  filter: drop-shadow(0 0 7px rgba(102, 226, 255, 0.55));
}
.sm-rail-svg { display: block; width: 100%; height: 100%; }

/* Level badge — only present above level 1, welded to the bottom-right. */
.sm-rail-lv {
  position: absolute;
  right: -4px;
  bottom: -4px;
  min-width: 15px;
  height: 15px;
  padding: 0 3px;
  font-family: var(--sm-mono);
  font-size: 10px;
  font-weight: 900;
  line-height: 15px;
  text-align: center;
  color: #14100a;
  background: linear-gradient(180deg, var(--sm-gold-hot), var(--sm-gold));
  border: 1px solid rgba(20, 16, 10, 0.85);
  border-radius: 8px;
  box-shadow: 0 0 12px rgba(255, 194, 31, 0.75);
}

@keyframes sm-rail-pop-kf {
  0%   { transform: scale(0.55) translateX(-10px); opacity: 0; filter: brightness(2.4); }
  45%  { transform: scale(1.22) translateX(0);     opacity: 1; filter: brightness(2.0); }
  100% { transform: scale(1)    translateX(0);     opacity: 1; filter: brightness(1); }
}
.sm-rail-pop { animation: sm-rail-pop-kf 0.44s cubic-bezier(0.16, 1.5, 0.35, 1); }

/* ===========================================================================
 * LIVE HAUL TALLY (left edge, below the rail)
 * A running count of every material gathered, most valuable at the top.
 *
 * BOTTOM-ANCHORED ON PURPOSE. Rows are revealed as materials are discovered,
 * so the block GROWS during a run. Anchoring it to the bottom means it grows
 * upward into the gap under the rail; anchoring it to the top would push the
 * last-discovered rows off the bottom of a short screen — exactly the rows
 * that just changed. The rail's max-height reserves the space above it.
 * ======================================================================== */
.sm-tally {
  position: absolute;
  left: 10px;
  bottom: 46px;
  /* 134 rather than 122 since the mine learned Norwegian: STJERNEKJERNE and
     MØRKESTEIN are the longest names it has, and they ellipsised at 122. */
  width: 134px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  pointer-events: none;
  z-index: 4;
}
.sm-tally-head {
  font-family: var(--sm-mono);
  font-size: 8px;
  font-weight: 800;
  letter-spacing: 3px;
  color: var(--sm-dimmer);
  padding-left: 2px;
  margin-bottom: 2px;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.9);
}
.sm-tally-row {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 16px;
  padding: 0 5px 0 4px;
  background: rgba(10, 12, 16, 0.52);
  border-left: 2px solid rgba(126, 140, 158, 0.3);
  border-radius: 2px;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
/* An actual payday reads brighter than spoil. */
.sm-tally-ore { background: rgba(14, 17, 22, 0.66); }

.sm-tally-sw {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 2px;
  transform: rotate(45deg);            /* reads as a gem, not a checkbox */
}
.sm-tally-name {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--sm-mono);
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--sm-dim);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.sm-tally-count {
  flex: 0 0 auto;
  font-family: var(--sm-mono);
  font-size: 10px;
  font-weight: 800;
  color: var(--sm-text);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
}
.sm-tally-ore .sm-tally-count { color: var(--sm-gold-hot); }

/* First find of a material only — see updateTally(). */
@keyframes sm-tally-pop-kf {
  0%   { transform: translateX(-14px); opacity: 0; filter: brightness(2.6); }
  55%  { transform: translateX(0);     opacity: 1; filter: brightness(2.2); }
  100% { transform: translateX(0);     opacity: 1; filter: brightness(1); }
}
.sm-tally-pop { animation: sm-tally-pop-kf 0.5s cubic-bezier(0.16, 1.5, 0.35, 1); }

/* ===========================================================================
 * ZONE BANNER (RIGHT edge — announces a new section)
 * It used to slide in from the left. The upgrade rail now owns the left edge
 * for the whole run, and the rail GROWS — on a short screen it wraps into a
 * second column — so no fixed left offset is safe in every layout. The right
 * edge is empty below the button cluster, so the banner moved there and
 * mirrored: same gesture, zero collision risk.
 * ======================================================================== */
.sm-banner {
  position: absolute;
  right: 0;
  top: 46%;
  opacity: 0;
  transform: translateX(60px);
  transition: opacity 0.22s ease, transform 0.42s cubic-bezier(0.16, 1.4, 0.3, 1);
  will-change: opacity, transform;
}
.sm-banner-on { opacity: 1; transform: translateX(0); }

.sm-banner-text {
  font-family: var(--sm-mono);
  font-size: clamp(12px, 1.7vw, 18px);
  font-weight: 800;
  letter-spacing: 4px;
  color: #0d1014;
  background: linear-gradient(180deg, var(--sm-cyan-hot), var(--sm-cyan) 55%, #2a9ac6);
  padding: 9px 16px 9px 20px;
  border-right: 5px solid #0d1014;
  border-radius: 4px 0 0 4px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.7), 0 0 30px rgba(102, 226, 255, 0.35);
  white-space: nowrap;
}
.sm-banner-final .sm-banner-text {
  background:
    var(--sm-hazard) left top / 100% 5px repeat-x,
    var(--sm-hazard) left bottom / 100% 5px repeat-x,
    linear-gradient(180deg, #23262c, #101318);
  color: #ffd257;
  padding-top: 12px;
  padding-bottom: 12px;
  border-right-color: #f0b31b;
  text-shadow: 0 2px 4px #000, 0 0 14px rgba(240,179,27,0.6);
  box-shadow: 0 6px 24px rgba(0,0,0,0.8), 0 0 44px rgba(240, 179, 27, 0.6);
  animation: sm-banner-throb 0.42s ease-in-out infinite alternate;
}
@keyframes sm-banner-throb { to { filter: brightness(1.35); } }

/* ===========================================================================
 * END OF RUN SUMMARY
 * ======================================================================== */
.sm-summary {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(ellipse at center, rgba(4,6,9,0.55), rgba(2,3,5,0.88));
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s ease;
  /* Above the clock (6) and the upgrade rail (4) so the whole HUD dims when
     the run ends, but below the start overlay (20). */
  z-index: 15;
}
.sm-summary-on { opacity: 1; pointer-events: auto; }

.sm-card {
  position: relative;
  width: min(560px, 92vw);
  max-height: 92vh;
  overflow: auto;
  /* <body> sets touch-action:none so a drag steers instead of scrolling the
     page. That also killed touch scrolling INSIDE this card — which on a
     phone put RUN IT AGAIN below the fold with no way to reach it. Re-arming
     vertical panning here is scoped to the card and cannot leak back out to
     the canvas. */
  touch-action: pan-y;
  padding: 26px 28px 24px;
  background: var(--sm-panel);
  border: 1px solid var(--sm-border);
  border-radius: 8px;
  box-shadow:
    inset 0 1px 0 var(--sm-edge-hi),
    inset 0 -3px 0 var(--sm-edge-lo),
    0 24px 70px rgba(0, 0, 0, 0.85);
  transform: translateY(24px) scale(0.96);
  transition: transform 0.42s cubic-bezier(0.16, 1.5, 0.35, 1);
}
.sm-summary-on .sm-card { transform: translateY(0) scale(1); }

.sm-card-kicker {
  font-family: var(--sm-mono);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 5px;
  color: var(--sm-gold);
  text-shadow: 0 0 14px rgba(255, 194, 31, 0.6);
  margin-bottom: 4px;
}
.sm-card-title {
  font-size: clamp(26px, 4vw, 40px);
  font-weight: 900;
  letter-spacing: 1.5px;
  line-height: 1.05;
  color: #fff;
  text-shadow: 0 0 28px rgba(255, 194, 31, 0.45), 0 3px 0 rgba(0,0,0,0.6);
  margin-bottom: 18px;
}
.sm-card-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.sm-cell {
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-left: 3px solid rgba(255, 194, 31, 0.55);
  border-radius: 3px;
  padding: 9px 12px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
}
.sm-cell-label {
  font-family: var(--sm-mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 2px;
  color: var(--sm-dimmer);
}
.sm-cell-value {
  font-family: var(--sm-mono);
  font-size: 21px;
  font-weight: 800;
  color: var(--sm-text);
  font-variant-numeric: tabular-nums;
  margin-top: 2px;
}

/* The haul IS the score in a time attack, so it gets the hero slot. */
.sm-score {
  margin-bottom: 12px;
  padding: 11px 14px 12px;
  background: linear-gradient(180deg, rgba(255, 194, 31, 0.16), rgba(0, 0, 0, 0.5));
  border: 1px solid rgba(255, 194, 31, 0.38);
  border-left: 4px solid var(--sm-gold);
  border-radius: 4px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
.sm-score-label {
  font-family: var(--sm-mono);
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 4px;
  color: var(--sm-gold);
}
.sm-score-value {
  font-family: var(--sm-mono);
  font-size: clamp(30px, 6vw, 46px);
  font-weight: 900;
  line-height: 1.05;
  letter-spacing: -1px;
  color: var(--sm-gold-hot);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 28px rgba(255, 194, 31, 0.6), 0 2px 0 rgba(0, 0, 0, 0.7);
}

/* ===========================================================================
 * HAUL BREAKDOWN (summary card) — what the score was made of.
 * Each row is a proportional bar in the material's own colour, so the run
 * reads as a shape before any of the numbers are actually parsed.
 * ======================================================================== */
.sm-haul {
  margin-bottom: 14px;
}
.sm-haul-head {
  font-family: var(--sm-mono);
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 3px;
  color: var(--sm-dimmer);
  margin-bottom: 6px;
}
.sm-haul-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  height: 24px;
  padding: 0 9px;
  margin-bottom: 3px;
  background: rgba(0, 0, 0, 0.42);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 3px;
  overflow: hidden;
}
/* The proportional fill sits behind the text, inside the row's own clip. */
.sm-haul-bar {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  z-index: 0;
  pointer-events: none;
}
.sm-haul-row > .sm-haul-sw,
.sm-haul-row > .sm-haul-name,
.sm-haul-row > .sm-haul-count,
.sm-haul-row > .sm-haul-val { position: relative; z-index: 1; }

.sm-haul-sw {
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  border: 1px solid rgba(255, 255, 255, 0.4);
  border-radius: 2px;
  transform: rotate(45deg);
}
.sm-haul-name {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--sm-mono);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 1.6px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.9);
}
.sm-haul-count {
  flex: 0 0 auto;
  font-family: var(--sm-mono);
  font-size: 10px;
  font-weight: 700;
  color: var(--sm-dim);
  font-variant-numeric: tabular-nums;
}
.sm-haul-val {
  flex: 0 0 auto;
  min-width: 62px;
  text-align: right;
  font-family: var(--sm-mono);
  font-size: 13px;
  font-weight: 800;
  color: var(--sm-text);
  font-variant-numeric: tabular-nums;
}
/* Dirt, stone, rubble and the barrier rock, folded into one line. */
.sm-haul-spoil .sm-haul-val { color: var(--sm-dim); }

/* Power-ups collected — a footnote, because they paid in seconds and speed
   rather than currency and are deliberately outside the column that has to
   add up to the score. */
.sm-haul-picks {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  margin-top: 7px;
  padding-top: 7px;
  border-top: 1px dashed rgba(255, 255, 255, 0.10);
}
.sm-haul-pick {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.sm-haul-pick-label {
  font-family: var(--sm-mono);
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 1.4px;
}
.sm-haul-empty {
  font-family: var(--sm-mono);
  font-size: 10px;
  letter-spacing: 2px;
  color: var(--sm-dimmer);
  padding: 6px 0 2px;
}

/* Ran out of time rather than reaching the bottom: recolour the header. */
.sm-summary-timeout .sm-card-kicker {
  color: var(--sm-red);
  text-shadow: 0 0 14px rgba(255, 90, 72, 0.7);
}
.sm-summary-timeout .sm-card-title {
  text-shadow: 0 0 28px rgba(255, 90, 72, 0.5), 0 3px 0 rgba(0, 0, 0, 0.6);
}
.sm-summary-timeout .sm-stripe {
  background: repeating-linear-gradient(135deg, var(--sm-red) 0 8px, #171512 8px 16px);
}

/* ===========================================================================
 * HIGH SCORES (inside the summary card)
 * ======================================================================== */
.sm-hs {
  margin-top: 16px;
  padding-top: 13px;
  border-top: 1px solid rgba(255, 255, 255, 0.09);
}
.sm-hs-head {
  font-family: var(--sm-mono);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 4px;
  color: var(--sm-dim);
}
.sm-hs-cta {
  margin-top: 9px;
  font-family: var(--sm-mono);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 2px;
  color: var(--sm-gold);
  text-shadow: 0 0 14px rgba(255, 194, 31, 0.55);
  animation: sm-hs-cta-kf 1.1s ease-in-out infinite;
}
@keyframes sm-hs-cta-kf { 50% { opacity: 0.5; } }

.sm-hs-form {
  display: flex;
  gap: 8px;
  margin-top: 8px;
  align-items: stretch;
}
.sm-hs-input {
  flex: 1 1 auto;
  min-width: 0;
  -webkit-user-select: text;
  user-select: text;
  font-family: var(--sm-mono);
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--sm-gold-hot);
  background: linear-gradient(180deg, #05070a, #0e1218);
  border: 1px solid rgba(255, 194, 31, 0.45);
  border-radius: 4px;
  padding: 10px 12px;
  min-height: 44px;
  outline: none;
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.85);
}
.sm-hs-input::placeholder { color: var(--sm-dimmer); letter-spacing: 2px; }
.sm-hs-input:focus {
  border-color: var(--sm-gold);
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.85), 0 0 0 2px rgba(255, 194, 31, 0.28);
}
.sm-hs-save {
  min-width: 88px;
  margin: 0;
}

/* This is the one text field in the whole game and it must never be
   un-clickable — but ONLY while the card it lives on is up. Scoped, because
   .sm-summary is inset:0 and merely opacity-0 when closed: an unscoped
   `pointer-events: auto` in here is an invisible input field parked in the
   middle of the mine, swallowing the mouse-down that starts a drag-steer.
   That was a real bug; it cost desktop drag-steering the centre of the
   screen and nothing about it was visible. */
.sm-summary-on .sm-hs-input,
.sm-summary-on .sm-hs-save { pointer-events: auto; }

.sm-hs-rows {
  margin-top: 10px;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.sm-hs-row {
  display: grid;
  grid-template-columns: 20px 1fr auto 76px;
  gap: 9px;
  align-items: baseline;
  padding: 5px 9px;
  font-family: var(--sm-mono);
  font-size: 12px;
  font-weight: 700;
  background: rgba(0, 0, 0, 0.38);
  border-left: 2px solid rgba(255, 255, 255, 0.10);
  border-radius: 3px;
}
.sm-hs-rank  { color: var(--sm-dimmer); font-weight: 800; }
.sm-hs-name  {
  color: var(--sm-text);
  font-weight: 800;
  letter-spacing: 1.4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sm-hs-score { color: var(--sm-gold); font-weight: 800; font-variant-numeric: tabular-nums; }
.sm-hs-depth { color: var(--sm-dimmer); text-align: right; font-variant-numeric: tabular-nums; }

.sm-hs-row-new {
  border-left-color: var(--sm-gold);
  background: linear-gradient(90deg, rgba(255, 194, 31, 0.26), rgba(0, 0, 0, 0.38));
  animation: sm-hs-new-kf 0.9s ease-out 2;
}
.sm-hs-row-new .sm-hs-rank { color: var(--sm-gold-hot); }
@keyframes sm-hs-new-kf { 50% { filter: brightness(1.6); } }

.sm-hs-note {
  margin-top: 10px;
  font-family: var(--sm-mono);
  font-size: 10px;
  letter-spacing: 1.6px;
  color: var(--sm-dimmer);
}

/* ===========================================================================
 * START OVERLAY
 * ======================================================================== */
.sm-start {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(ellipse at center, rgba(6,8,12,0.55) 0%, rgba(2,3,5,0.92) 78%);
  pointer-events: auto;
  cursor: pointer;
  opacity: 1;
  transition: opacity 0.45s ease;
  z-index: 20;
}
.sm-start-off { opacity: 0; pointer-events: none; }

/* The menu is a real panel, vertically centred with a fixed rhythm, rather
   than a stack of margins that drifted apart as copy was added. `gap` on a
   flex column keeps the spacing honest no matter which children exist. */
.sm-start-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 22px;
  width: min(880px, 92vw);
  max-height: 92vh;
  padding: 30px 26px;
  text-align: center;
  overflow: auto;
  touch-action: pan-y;          /* see .sm-card — same trap, same fix */
}
/* A flex column with a max-height SHRINKS its children when the content is
   too tall — on a 390x740 phone that squashed the mode cards to 30px instead
   of scrolling. Pin every direct child at its natural height and let the
   container's overflow do its job. */
.sm-start-inner > * { flex: 0 0 auto; }

.sm-start-head { display: flex; flex-direction: column; align-items: center; gap: 8px; }

.sm-start-logo {
  font-size: clamp(38px, 8.6vw, 92px);
  font-weight: 900;
  letter-spacing: clamp(4px, 1.3vw, 13px);
  /* The tracking is applied to the right of every glyph including the last,
     which visually shifts a centred word left. Pull it back by half. */
  text-indent: clamp(4px, 1.3vw, 13px);
  line-height: 1;
  color: #fff;
  text-shadow:
    0 0 40px rgba(255, 194, 31, 0.55),
    0 0 110px rgba(255, 138, 31, 0.35),
    0 6px 0 rgba(0,0,0,0.7);
}
.sm-start-sub {
  font-family: var(--sm-mono);
  font-size: clamp(10px, 1.4vw, 13px);
  font-weight: 800;
  letter-spacing: 6px;
  text-indent: 6px;
  color: var(--sm-gold);
  text-shadow: 0 0 16px rgba(255, 194, 31, 0.6);
}

.sm-start-pick {
  font-family: var(--sm-mono);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 5px;
  text-indent: 5px;
  color: var(--sm-dimmer);
}

/* --- mode cards ------------------------------------------------------- */
.sm-modes {
  display: flex;
  justify-content: center;
  align-items: stretch;      /* equal heights, whatever the blurb length */
  gap: 16px;
  width: 100%;
}

.sm-mode {
  position: relative;
  flex: 1 1 0;
  max-width: 340px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 7px;
  margin: 0;
  padding: 22px 20px 18px;
  text-align: left;
  font-family: var(--sm-font);
  background: var(--sm-panel);
  border: 1px solid var(--sm-border);
  border-radius: 7px;
  box-shadow:
    inset 0 1px 0 var(--sm-edge-hi),
    inset 0 -3px 0 var(--sm-edge-lo),
    0 14px 34px rgba(0,0,0,0.7);
  cursor: pointer;
  /* Interactivity inherits from .sm-start and stops with .sm-start-off — see
     the note on .sm-pause-btn. A dismissed menu is opacity-0, not gone, so an
     unscoped `pointer-events: auto` here leaves two invisible mode cards
     parked over the middle of the mine for the rest of the session. */
  overflow: hidden;
  transition: transform 0.16s ease, border-color 0.16s ease, box-shadow 0.16s ease;
}
.sm-mode:hover, .sm-mode:focus-visible {
  transform: translateY(-3px);
  border-color: rgba(255, 194, 31, 0.55);
  box-shadow:
    inset 0 1px 0 var(--sm-edge-hi),
    inset 0 -3px 0 var(--sm-edge-lo),
    0 18px 42px rgba(0,0,0,0.8),
    0 0 0 1px rgba(255,194,31,0.25);
  outline: none;
}
.sm-mode:active { transform: translateY(-1px); }

.sm-mode-badge {
  align-self: flex-end;
  font-family: var(--sm-mono);
  font-size: 8px;
  font-weight: 800;
  letter-spacing: 2.4px;
  color: #0e1116;
  background: linear-gradient(180deg, var(--sm-gold-hot), var(--sm-gold));
  border-radius: 2px;
  padding: 3px 6px;
}
.sm-mode-freestyle .sm-mode-badge {
  color: #06120e;
  background: linear-gradient(180deg, #b6ffe2, var(--sm-green));
}

.sm-mode-title {
  font-size: clamp(19px, 2.4vw, 25px);
  font-weight: 900;
  letter-spacing: 1px;
  color: #fff;
  text-shadow: 0 2px 0 rgba(0,0,0,0.6);
}
.sm-mode-tag {
  font-family: var(--sm-mono);
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 2.4px;
  color: var(--sm-gold);
}
.sm-mode-freestyle .sm-mode-tag { color: var(--sm-green); }

.sm-mode-blurb {
  font-family: var(--sm-mono);
  font-size: 10px;
  line-height: 1.65;
  letter-spacing: 0.7px;
  color: var(--sm-dim);
  flex: 1 1 auto;            /* pushes START to the bottom on both cards */
}

.sm-mode-go {
  margin-top: 4px;
  align-self: stretch;
  text-align: center;
  font-family: var(--sm-mono);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 3px;
  text-indent: 3px;
  color: #fff;
  background: linear-gradient(180deg, #1c2027, #0b0d11);
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 3px;
  padding: 10px 8px;
}
.sm-mode:hover .sm-mode-go, .sm-mode:focus-visible .sm-mode-go {
  color: #0e1116;
  background: linear-gradient(180deg, var(--sm-gold-hot), var(--sm-gold));
  border-color: rgba(255, 240, 168, 0.6);
}
.sm-mode-freestyle:hover .sm-mode-go,
.sm-mode-freestyle:focus-visible .sm-mode-go {
  color: #06120e;
  background: linear-gradient(180deg, #b6ffe2, var(--sm-green));
  border-color: rgba(182, 255, 226, 0.6);
}

/* Two control lines, one shown at a time: a phone player has no keyboard to
   be told about, and a desktop player has no steering pads to find. The swap
   follows the same rule the pads themselves use. */
.sm-start-keys {
  font-family: var(--sm-mono);
  font-size: 10px;
  line-height: 1.6;
  letter-spacing: 1.6px;
  color: var(--sm-dimmer);
}
.sm-keys-touch { display: none; }
.sm-compact .sm-keys-desk,
.sm-portrait .sm-keys-desk { display: none; }
.sm-compact .sm-keys-touch,
.sm-portrait .sm-keys-touch { display: block; }
@media (hover: none) and (pointer: coarse) {
  .sm-keys-desk  { display: none; }
  .sm-keys-touch { display: block; }
}

/* Build stamp, pinned to the overlay rather than the panel so it cannot be
   pushed around by however tall the copy happens to be. */
.sm-start-version {
  position: absolute;
  bottom: 14px;
  left: 0;
  right: 0;
  text-align: center;
  font-family: var(--sm-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 3px;
  text-indent: 3px;
  color: rgba(255,255,255,0.22);
}

/* THE WAY OUT on the main menu: the last row of the panel's column, as wide
   as the mode cards above it (two cards of 340 and their 16px gap side by
   side, one card's 380 once they stack — see the max-width: 700px block), so
   it reads as part of the menu and never as a third mode. Its look is the
   pause card's quit button above, shared selector and all. It used to be a
   small plate pinned to the overlay's top-left corner; ui.js says why it
   moved. Absent entirely unless ../arcade/exit.js answered. */
.sm-start-quit {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  max-width: 696px;
  min-height: 46px;
  /* The column's own 22px gap already separates it; this is the "little
     more" on top. */
  margin-top: 6px;
}

/* ===========================================================================
 * THE CORNER — THREE PLATES, ON EVERY SCREEN, FIXED TO THE PAGE
 * ---------------------------------------------------------------------------
 * Menu, sound, fullscreen (hub CLAUDE.md §2). The same gold-on-dark plate with
 * the same hazard sliver as every other control here — that is what keeps a
 * 42px button from reading as generic mobile chrome — but the glyphs are the
 * hub's, to the path data.
 *
 * THEY NEVER GO ANYWHERE. A child of #ui-root and `position: fixed`, so the
 * same three are in the same place on the menu, mid-run, over the pause card
 * and over the summary.
 *
 * Z-INDEX 30 IS THE WHOLE POINT. Above the pause card (22), the start overlay
 * (20) and the summary (15): these outlive every one of them, so nothing any
 * of them does may cover them. Sitting above the card it opens is what lets
 * the three bars be a real toggle.
 *
 * THE VERY TOP CORNER, on the strip's own row and centred on its height. The
 * strip yields — it stops short of these (see .sm-topbar) — because the
 * plates are the same in every cabinet and the strip is not.
 *
 * SAFE AREAS ARE ARITHMETIC, not inheritance: `fixed` positions against the
 * viewport, so #ui-root's padding does not apply and both insets are added
 * back here, landing the plates on exactly the strip's row.
 *
 * pointer-events: auto because #ui-root is pointer-events:none.
 * ======================================================================== */
.sm-corner {
  position: fixed;
  top: calc(env(safe-area-inset-top, 0px) + var(--sm-top-y)
            + (var(--sm-top-h) - var(--sm-btn-size)) / 2);
  right: calc(env(safe-area-inset-right, 0px) + var(--sm-gutter));
  display: flex;
  gap: var(--sm-plate-gap);
  pointer-events: auto;
  z-index: 30;
}
/* THE `hidden` ATTRIBUTE HAS TO WIN HERE, and on its own it does not: the UA
   sheet's `[hidden] { display: none }` is a type-less rule and .sm-iconbtn
   sets `display: flex`, which outranks it. Without this the screen plate would
   be visible on an iPhone — the one browser the attribute exists to hide it
   from — and pressing it would do nothing at all. */
.sm-corner .sm-iconbtn[hidden] { display: none; }

/* ===========================================================================
 * THE TWO VOLUMES — on the menu card
 * ---------------------------------------------------------------------------
 * Labelled rows, one gutter, a real range styled as one more gauge on this
 * HUD. They used to live on a panel of their own behind a second speaker in
 * the corner; the hub folded that into the one menu (CLAUDE.md §2).
 * ======================================================================== */
.sm-sound-row {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 12px;
}
/* ONE GUTTER FOR BOTH ROWS, so MUSIC and MACHINERY start their track at the
   same x (hub CLAUDE.md §2). 92px is MACHINERY's own width at this size and
   tracking — the longer of the two names sets it, and the shorter one simply
   has room. */
.sm-sound-label {
  flex: 0 0 92px;
  font-family: var(--sm-mono);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 2px;
  color: var(--sm-dim);
}
/* `1 1 0` and not `1 1 auto`: from a zero basis the two tracks are identical
   whatever their labels say, which is the point — these are two equals. */
.sm-sound-range {
  flex: 1 1 0;
  min-width: 0;
  -webkit-appearance: none;
  appearance: none;
  height: 44px;              /* the touch box; the visible gauge is the track */
  margin: 0;
  padding: 0;
  background: transparent;
  cursor: pointer;
  /* Vertical pans still scroll the card on a short screen; horizontal is ours,
     which is what makes the thumb draggable with a finger. */
  touch-action: pan-y;
}
.sm-sound-out {
  flex: 0 0 38px;
  text-align: right;
  font-family: var(--sm-mono);
  font-size: 14px;
  font-weight: 800;
  color: var(--sm-gold);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 10px rgba(255, 194, 31, 0.45);
}

/* --- the gauge ---------------------------------------------------------
 * A bare range input is an OS control and belongs to no game. This one is the
 * same cut channel with the same amber fill as the clock bar and the two
 * meters, and the thumb is a machined lever plate with the panels' own bevel.
 * --sm-fill is written by ui.js on drag and on open; the 100% fallback is
 * what a browser that never runs that code still shows.
 * Both vendor pseudo-elements are spelled out — there is no shared selector,
 * and a rule listing both is dropped by both.
 * ---------------------------------------------------------------------- */
.sm-sound-range::-webkit-slider-runnable-track {
  height: 10px;
  border-radius: 2px;
  background:
    linear-gradient(90deg, var(--sm-gold-hot), var(--sm-gold))
      0 0 / var(--sm-fill, 100%) 100% no-repeat,
    #0a0705;
  /* The amber rim is an inset ring rather than a border, so the track is
     exactly 10px tall whatever the UA thinks box-sizing means on a vendor
     pseudo-element — which is what makes the thumb's margin-top below an exact
     number instead of an approximation. */
  box-shadow:
    inset 0 0 0 1px rgba(255, 194, 31, 0.30),
    inset 0 1px 3px rgba(0, 0, 0, 0.9);
}
.sm-sound-range::-moz-range-track {
  height: 10px;
  border-radius: 2px;
  background: #0a0705;
  box-shadow:
    inset 0 0 0 1px rgba(255, 194, 31, 0.30),
    inset 0 1px 3px rgba(0, 0, 0, 0.9);
}
/* Firefox fills the track itself, so it needs no --sm-fill. */
.sm-sound-range::-moz-range-progress {
  height: 10px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--sm-gold-hot), var(--sm-gold));
}
.sm-sound-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 26px;
  margin-top: -8px;          /* (track 10 - thumb 26) / 2 */
  border-radius: 3px;
  border: 1px solid rgba(255, 255, 255, 0.34);
  background: linear-gradient(180deg, #5a636f 0%, #262a32 46%, #14171c 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.35),
    inset 0 -2px 0 rgba(0, 0, 0, 0.75),
    0 3px 8px rgba(0, 0, 0, 0.65);
}
.sm-sound-range::-moz-range-thumb {
  width: 16px;
  height: 26px;
  border-radius: 3px;
  border: 1px solid rgba(255, 255, 255, 0.34);
  background: linear-gradient(180deg, #5a636f 0%, #262a32 46%, #14171c 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.35),
    inset 0 -2px 0 rgba(0, 0, 0, 0.75),
    0 3px 8px rgba(0, 0, 0, 0.65);
}
.sm-sound-range:focus-visible {
  outline: 2px solid var(--sm-cyan);
  outline-offset: 2px;
  border-radius: 3px;
}

.sm-sound-hint {
  margin-top: 14px;
  font-family: var(--sm-mono);
  font-size: 9.5px;
  line-height: 1.7;
  letter-spacing: 1.2px;
  color: var(--sm-dimmer);
}
/* Freestyle: no countdown panel at all. The centred column closes the gap by
   itself — that is the whole reason it is a flex column. */
.sm-notimer .sm-clockwrap { display: none; }

/* While the menu is up it is the only thing on screen. */
.sm-menu .sm-hint { display: none; }
/* ...and the steering pads must not eat the mode cards' taps behind it. The
   overlay is pointer-events:auto and paints above them, so this is belt and
   braces — but a pad that swallowed a START tap would be unplayable. */
.sm-menu .sm-pads { display: none; }

/* --- opt-in update button (menu only) ---------------------------------
   Hidden unless a new build is precached and waiting. Deliberately reads as
   an offer rather than an alarm: nothing is broken, there is simply a newer
   version parked and ready whenever the player wants it. */
.sm-update {
  margin: 0;
  padding: 11px 18px;
  font-family: var(--sm-mono);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 2.4px;
  text-indent: 2.4px;
  color: #06120e;
  background: linear-gradient(180deg, #b6ffe2, var(--sm-green));
  border: 1px solid rgba(182, 255, 226, 0.7);
  border-radius: 4px;
  cursor: pointer;
  /* Inherits from .sm-start; see .sm-mode. */
  box-shadow: 0 0 22px rgba(88, 224, 138, 0.45), inset 0 1px 0 rgba(255,255,255,0.4);
  transition: transform 0.15s ease, filter 0.15s ease;
}
.sm-update:hover { transform: translateY(-2px); filter: brightness(1.08); }
.sm-update:active { transform: translateY(0); }
.sm-update:disabled { filter: grayscale(0.6) brightness(0.8); cursor: default; }

@keyframes sm-update-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.sm-update-on { animation: sm-update-in 0.4s cubic-bezier(0.16, 1.4, 0.3, 1); }

/* Two cards need ~700px to sit side by side without the blurbs going ragged.
   Below that they stack — a width question, not a "compact" one, which is why
   this is a media query and not another .sm-compact rule. */
@media (max-width: 700px) {
  .sm-modes { flex-direction: column; align-items: center; }
  /* `flex: 1 1 0` gives the cards equal WIDTHS in a row, but once the axis
     turns vertical that zero basis becomes a zero HEIGHT — and because the
     card sets overflow:hidden its automatic minimum size is 0 too, so it
     collapsed to just its padding. Height must come from content here. */
  .sm-mode { flex: 0 0 auto; width: 100%; max-width: 380px; }
  .sm-mode-blurb { flex: 0 0 auto; }
  .sm-start-quit { max-width: 380px; }
}
@media (max-height: 560px) {
  .sm-start-logo { font-size: clamp(30px, 6vw, 52px); }
  .sm-start-inner { gap: 12px; }
  .sm-mode-blurb { display: none; }   /* keep both cards fully on screen */
}

/* ===========================================================================
 * HINT + DEBUG (bottom)
 * ======================================================================== */
.sm-hint {
  position: absolute;
  bottom: 12px;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--sm-mono);
  font-size: 10px;
  letter-spacing: 1.4px;
  color: rgba(255, 255, 255, 0.24);
  white-space: nowrap;
  transition: opacity 1.2s ease 3s;
}
.sm-hint-fade { opacity: 0; }

.sm-debug {
  position: absolute;
  bottom: 9px;
  left: 12px;
  font-family: var(--sm-mono);
  font-size: 10px;
  letter-spacing: 0.4px;
  color: rgba(140, 210, 255, 0.40);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 2px #000;
}

/* ===========================================================================
 * COMPACT / TINY / PORTRAIT LAYOUTS — toggled from ui.js, no pixel maths in JS
 * Order matters: compact first, portrait after it (a phone is both, and the
 * portrait rules are the more specific intent), tiny last.
 * ======================================================================== */
.sm-compact {
  --sm-top-y: 6px;
  --sm-top-h: 38px;
  --sm-gutter: 7px;
  --sm-btn-size: 38px;
  /* Tightens the corner and the strip's clearance from it at once — both
     read this one variable. */
  --sm-plate-gap: 6px;
  --sm-cur-max: 30px;
  --sm-cur-vw: 7.6vw;
  --sm-cur-chrome: 130px;
}
/* THE TOP-STRIP BUDGET IS THE WHOLE ARGUMENT HERE.
   The strip is one line tall and the score owns the middle of it. The
   PWR / CUT / MAG chips are what gives, because the upgrade rail down the
   left edge says what is installed far better than three numbers did. The
   multiplier chip stays — nothing else reports it. */
.sm-compact .sm-stat { display: none; }
.sm-compact .sm-stat-mult {
  display: block;
  font-size: 9px;
  padding: 3px 5px;
  letter-spacing: 0.3px;
}
.sm-compact .sm-topbar { padding: 0 9px; }
.sm-compact .sm-clock { padding: 5px 12px 7px; min-width: 114px; }
.sm-compact .sm-clock-label { font-size: 8px; letter-spacing: 3px; text-indent: 3px; }
.sm-compact .sm-clock-digits { font-size: 27px; height: 29px; line-height: 29px; }
.sm-compact .sm-clock-urgent .sm-clock-digits { font-size: 31px; }
.sm-compact .sm-clock-bar { margin-top: 5px; height: 4px; }
.sm-compact .sm-clock-gain { font-size: 21px; }

/* The rail starts below the score strip and uses smaller tiles. Its ceiling
   has to leave room for the haul tally underneath it — otherwise a long run
   wraps a second column straight down into the tally. */
.sm-compact .sm-rail {
  left: 7px;
  gap: 5px;
  max-height: calc(100vh - 300px);
}

/* THE TALLY IS LIFTED OFF THE BOTTOM EDGE, and this is what "move HAUL up to
   make room for the buttons" means: the steering pads are full height, so the
   bottom-left corner now belongs to the left pad's chevron. The tally sits
   above it — it is pointer-events:none either way, so this is purely about
   not printing the haul on top of a control.
   It also narrows and shows ORES ONLY: on a short screen eleven rows is most
   of the left edge, and dirt/stone/rubble are the lines nobody reads mid-run.
   !important because updateTally() clears the inline display on reveal. */
.sm-compact .sm-tally {
  left: 7px;
  bottom: max(96px, 15vh);
  width: 104px;
  gap: 1px;
}
.sm-compact .sm-tally-row:not(.sm-tally-ore) { display: none !important; }
.sm-compact .sm-tally-row { height: 15px; gap: 5px; }
.sm-compact .sm-tally-name { font-size: 8px; letter-spacing: 0.3px; }
.sm-compact .sm-tally-count { font-size: 9px; }
.sm-compact .sm-haul-row { height: 21px; padding: 0 7px; gap: 6px; }
.sm-compact .sm-haul-val { font-size: 12px; min-width: 54px; }
.sm-compact .sm-rail-tile { width: 30px; height: 30px; border-left-width: 2px; }
.sm-compact .sm-rail-ico { width: 18px; height: 18px; }
.sm-compact .sm-rail-lv {
  min-width: 13px; height: 13px; line-height: 13px; font-size: 9px; right: -3px; bottom: -3px;
}
/* fps and particle counts printed across the middle of a phone screen is a
   development readout on a device with no keyboard to turn it off. */
.sm-compact .sm-debug { display: none; }
.sm-compact .sm-zonelabel,
.sm-compact .sm-zonecore { font-size: 9px; letter-spacing: 1.6px; }
/* :not() because an icon plate is sized by --sm-btn-size, and a min-width
   meant for a word would stretch it into a rectangle. */
.sm-compact .sm-btn:not(.sm-iconbtn) { min-width: 62px; padding: 9px 10px; font-size: 10px; letter-spacing: 1px; }
.sm-compact .sm-btn-svg { width: 18px; height: 18px; }
/* ...but the way out keeps its own size and tracking: the rule above is
   tuned for capitals, and sentence case at 10px with 1px tracking is the
   one label on the card that would get harder to read rather than smaller. */
.sm-compact .sm-btn-quit,
.sm-compact .sm-start-quit { font-size: 11px; letter-spacing: 0.3px; }
.sm-compact .sm-hint { display: none; }
/* The whole top cluster is ~135px on a phone in landscape, so the percentage
   alone is not enough — the floor is what keeps the announcement off it. */
.sm-compact .sm-toast { top: max(25%, 148px); }
.sm-compact .sm-banner { top: 62%; }
/* The toast drops to 25% in compact, so the splash drops with it to keep the
   same clear gap between the two when both happen to be up. */
.sm-compact .sm-splash-inner { top: 47%; }
.sm-compact .sm-splash-sub { letter-spacing: 3px; text-indent: 3px; }
.sm-compact .sm-card { padding: 18px 18px 16px; }
.sm-compact .sm-cell-value { font-size: 17px; }
.sm-compact .sm-pause-card { padding: 18px 18px 16px; }
.sm-compact .sm-pause-title { font-size: 28px; letter-spacing: 4px; text-indent: 4px; }
/* Compact can be short-and-wide (1280x600) as well as narrow, so this only
   tightens the rhythm — the side-by-side/stacked decision is a width call and
   lives in the media query below. */
.sm-compact .sm-start-inner { gap: 15px; padding: 18px 16px; }
.sm-compact .sm-mode { padding: 15px 16px 13px; gap: 5px; }
.sm-compact .sm-mode-title { font-size: 19px; }
.sm-compact .sm-mode-blurb { font-size: 9.5px; line-height: 1.55; }
.sm-compact .sm-mode-go { padding: 8px; }
.sm-compact .sm-hs { margin-top: 12px; padding-top: 10px; }
.sm-compact .sm-hs-row { font-size: 11px; padding: 4px 7px; gap: 7px; }
.sm-compact .sm-score { padding: 8px 11px 9px; }

/* ---------------------------------------------------------------------------
 * PORTRAIT — the shape the game is designed for.
 * Taller than it is wide, phone or tablet. The screen is narrow and long, the
 * camera frames the entire 1280-unit lane, and the machine is small: the HUD's
 * whole job here is to stay out of the vertical middle and off the thumbs.
 * ------------------------------------------------------------------------ */
.sm-portrait .sm-tally { bottom: max(104px, 15vh); }
/* A tall screen has room to push the announcement further from the clock. */
.sm-portrait .sm-toast { top: max(26%, 190px); }
.sm-portrait .sm-banner { top: 58%; }
/* Portrait tablets are NOT compact, but they are still held in two hands and
   still want the readouts small enough to leave the mine visible. */
.sm-portrait .sm-debug { display: none; }

/* At 390px the tagline's 6px tracking pushes it onto a second line, orphaning
   "DEEPER." under the centre. Tighten it just enough to stay on one. */
.sm-tiny .sm-start-sub { font-size: 9.5px; letter-spacing: 3px; text-indent: 3px; }
/* VELG HVORDAN DU VIL SPILLE is 26 characters; at 5px tracking it wraps. */
.sm-tiny .sm-start-pick { letter-spacing: 3px; text-indent: 3px; }
/* On the narrowest phones the sound card cannot fit a 78px gutter AND two
   flag plates with ENGLISH in one; the language caption takes its own line
   there and the pair gets the full width. */
.sm-tiny .sm-lang-inline { flex-wrap: wrap; row-gap: 6px; }
.sm-tiny .sm-lang-inline .sm-sound-label { flex-basis: 100%; }

.sm-tiny {
  --sm-top-h: 34px;
  --sm-btn-size: 36px;
  --sm-cur-max: 26px;
  --sm-cur-vw: 8.2vw;
  --sm-cur-chrome: 108px;
}
.sm-tiny .sm-statrow { gap: 4px; }
.sm-tiny .sm-card-grid { grid-template-columns: 1fr; }
.sm-tiny .sm-btn:not(.sm-iconbtn) { min-width: 52px; padding: 9px 6px; font-size: 9px; letter-spacing: 0.6px; }
.sm-tiny .sm-btn-svg { width: 17px; height: 17px; }
.sm-tiny .sm-clock { padding: 4px 9px 6px; min-width: 96px; }
.sm-tiny .sm-clock-label { display: none; }
.sm-tiny .sm-clock-digits { font-size: 23px; height: 25px; line-height: 25px; }
.sm-tiny .sm-clock-urgent .sm-clock-digits { font-size: 26px; }
.sm-tiny .sm-rail-tile { width: 26px; height: 26px; }
.sm-tiny .sm-rail-ico { width: 16px; height: 16px; }
/* Under 420px the swatch has to carry the identification on its own — the
   colours are the same ones the debris was drawn in, and the row keeps its
   title attribute. */
.sm-tiny .sm-tally { width: 52px; }
.sm-tiny .sm-tally-name { display: none; }
.sm-tiny .sm-tally-head { font-size: 7px; letter-spacing: 2px; }
.sm-tiny .sm-tally-count { font-size: 10px; margin-left: auto; }
.sm-tiny .sm-haul-count { display: none; }
.sm-tiny .sm-haul-name { font-size: 9px; letter-spacing: 1px; }
.sm-tiny .sm-hs-depth { display: none; }
.sm-tiny .sm-hs-row { grid-template-columns: 18px 1fr auto; }
.sm-tiny .sm-hs-form { flex-direction: column; }
.sm-tiny .sm-hs-save { width: 100%; }
/* Under 420px the gutter is eating the gauge rather than lining it up, so it
   tightens — both rows still share it, which is the only thing it is for. */
.sm-tiny .sm-sound-label { flex-basis: 78px; letter-spacing: 1.2px; }
.sm-tiny .sm-sound-row { gap: 9px; }

/* Users who ask for less motion get the information, not the theatre. */
@media (prefers-reduced-motion: reduce) {
  .sm-pop, .sm-flash, .sm-od-label, .sm-banner-final .sm-banner-text,
  .sm-clock-urgent, .sm-clock-kick, .sm-rail-pop, .sm-hs-cta, .sm-hs-row-new,
  .sm-zonecore {
    animation: none !important;
  }
  /* The steering pads still have to CONFIRM a press — that is feedback, not
     theatre — so they keep the state change and lose only the fade. */
  .sm-pad { transition-duration: 0.01ms !important; }
  /* The +10s float still has to be SEEN, so it keeps a short fade instead of
     the flight path. Losing it entirely would lose the information. */
  .sm-clock-gain-on { animation: sm-clock-gain-static 0.9s ease-out !important; }
  @keyframes sm-clock-gain-static {
    0%, 70% { opacity: 1; transform: translate(-50%, -34px); }
    100%    { opacity: 0; transform: translate(-50%, -34px); }
  }
  .sm-toast, .sm-banner, .sm-card, .sm-summary, .sm-start,
  .sm-pause, .sm-pause-card { transition-duration: 0.01ms !important; }
}

/* THE MENU CARD ON A SHORT SCREEN. The card carries the run's three buttons,
   the two volumes, the language and the way out since 2026-10-11, when the
   separate sound panel folded into it — far too much for one column on a
   360-390px-tall screen. Two moves, the second only where it is needed:

   1. Anything under 560px tall buys height back from the furniture: the
      flavour kicker and the hint line go, the title shrinks, and controls
      stop at 38px (this fires on a phone, where a finger is still the
      pointer).
   2. A phone ON ITS SIDE (landscape, under 500px — maxgear's query, which a
      tablet never meets either way up) stands the two halves next to each
      other: the run's buttons on the left, the settings on the right, and
      the title across both. Nothing moves in the DOM; .sm-pause-run and
      .sm-pause-set are already the two halves, so this is grid placement.

   The card's max-height and overflow are the safety net, not the plan. At
   the END of the file on purpose: the .sm-compact rules above have the same
   specificity and would otherwise win on source order. */
@media (max-height: 560px) {
  .sm-pause-card,
  .sm-compact .sm-pause-card { padding: 12px 16px 12px; }
  .sm-pause-kicker { display: none; }
  .sm-pause-title,
  .sm-compact .sm-pause-title { font-size: 22px; letter-spacing: 4px; text-indent: 4px; margin-bottom: 2px; }
  .sm-pause-btn { min-height: 38px; margin-top: 6px; }
  .sm-pause-set { margin-top: 10px; }
  .sm-sound-row { margin-top: 6px; }
  .sm-sound-range { height: 38px; }
  .sm-sound-hint { display: none; }
  .sm-btn-quit { margin-top: 12px; }
  .sm-lang-btn { min-height: 38px; padding: 6px 8px; }

  /* THE MAIN MENU ON A PHONE ON ITS SIDE, since the way out moved into its
     column (2026-10-11) and a 360-390px screen has no room for one more row
     unless something gives. What gives: the CHOOSE HOW TO PLAY caption,
     which the two cards below it say again in larger type; a little of the
     column's rhythm; and 6px of the door's own height, stopping at 40 like
     every other control here. That keeps the door clear of the build stamp
     pinned to the overlay's bottom edge, and the panel stops scrolling. */
  .sm-start-pick { display: none; }
  .sm-start-inner,
  .sm-compact .sm-start-inner { gap: 10px; padding-top: 10px; padding-bottom: 22px; }
  .sm-start-quit { min-height: 40px; margin-top: 4px; }
}
@media (orientation: landscape) and (max-height: 500px) {
  .sm-pause-card,
  .sm-compact .sm-pause-card {
    width: min(660px, 94vw);
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr);
    grid-template-areas: "head head" "run set";
    column-gap: 18px;
    align-content: start;
    align-items: start;
  }
  .sm-pause-head { grid-area: head; }
  .sm-pause-run { grid-area: run; }
  /* The hairline turns from a rule above the settings into one beside them. */
  .sm-pause-set {
    grid-area: set;
    margin-top: 0;
    padding: 0 0 0 16px;
    border-top: 0;
    border-left: 1px solid rgba(142, 155, 171, 0.16);
  }
  .sm-pause-set > .sm-sound-row:first-child { margin-top: 6px; }
}

/* ===========================================================================
 * THE OPENING STING (js/intro.js) — a canvas the script creates and removes.
 * Over everything, the corner plates at 30 included, because it is a
 * curtain: for its three seconds nothing under it is meant to be reachable,
 * and a tap anywhere on it is the skip.
 * ======================================================================== */
#intro {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 40;
  touch-action: none;
  cursor: pointer;
}
