/* =============================================================================
 * SUPERMINE ADVENTURE — style-adventure.css
 * -----------------------------------------------------------------------------
 * All in-game styling above the base layer. style.css owns that base layer —
 * the palette, the metal-plate treatment, the type scale, .sm-panel, .sm-btn,
 * .sm-cell, .sm-stripe, the title overlay and every --sm-* custom property —
 * and nothing in this file requires a change there.
 *
 * TWO RULES THAT MATTER MORE THAN THE REST
 *
 * 1. #ui-root carries the class `sm-adv` PERMANENTLY (js/ui.js adds it once,
 *    in build(), and never removes it). EVERYTHING here is scoped to it, so
 *    losing that class hides the entire interface.
 *
 * 2. MOBILE FIRST, and portrait is not an afterthought. The in-mine panel used
 *    to be a stack pinned to the TOP on every viewport, on the grounds that the
 *    bottom of the screen belongs to the thumb. Half of that is still true —
 *    the joystick's origin floats to wherever it lands — but THE MINE MOUTH IS
 *    UP, and a 210 px full-width stack on an 844 px phone sat squarely over the
 *    shaft the player climbs to get home. So on anything compact the
 *    instruments now hug the two SIDE edges instead, with one readout line
 *    along the bottom: see §3b. The wide layout is unchanged, because at
 *    1440x900 the stack is a column top-LEFT and the shaft is centred.
 *    Every meta screen is header / scrolling body / FIXED FOOTER, so
 *    the primary button is reachable without a scroll on any screen size.
 *
 * The palette, the metal-plate treatment and the type scale come from
 * style.css and are reused, not re-invented: .sm-panel, .sm-stripe, .sm-btn,
 * .sm-cell and the --sm-* custom properties are all shared. Adventure mode is
 * the same machine in a bigger world, not a different game.
 *
 * ORDER OF THIS FILE
 *   1. classic chrome, hidden
 *   2. the joystick
 *   3. the in-mine HUD (wide layout) + the adventure pause card
 *   3b. the RAIL layout — the same instruments moved to the screen edges on
 *       anything compact, so the top of the screen stays the mine
 *   4. the meta screens (shell, slots, map, garage, prep, results)
 *   5. responsive: compact / portrait / tiny / short-landscape
 * ========================================================================== */

/* ===========================================================================
 * 1. THE SCOPE GUARD  (and one gravestone)
 * ---------------------------------------------------------------------------
 * ui.js used to build a whole time-attack HUD at startup and leave it in the
 * DOM underneath the campaign, so this section took it down wholesale. That
 * HUD no longer exists — ui.js builds the title gate and the fps readout and
 * nothing else — so the second block below now matches nothing at all.
 *
 * IT STAYS ANYWAY, and this is not sentiment: style.css still DEFINES every
 * one of those classes, and the branding pass is about to build a splash
 * screen out of that same base layer. If any of those names is reused for
 * something that must not appear over a mine, the guard is already written.
 * Delete it only together with the style.css rules it names.
 *
 * The first block is live and load-bearing: it hides this file's own layers
 * whenever `sm-adv` is absent, which is the state a build has before ui.js
 * has run.
 * ======================================================================== */
#ui-root:not(.sm-adv) .sm-av,
#ui-root:not(.sm-adv) .sm-ah,
#ui-root:not(.sm-adv) .sm-ah-pause,
#ui-root:not(.sm-adv) .sm-stick-layer {
  display: none !important;
}

.sm-adv .sm-topbar,          /* the score strip                         */
.sm-adv .sm-center,          /* countdown + zone line column            */
.sm-adv .sm-meters,          /* overdrive / speed boost                 */
.sm-adv .sm-rail,            /* upgrade icon rail                       */
.sm-adv .sm-tally,           /* live haul tally                         */
.sm-adv .sm-pads,            /* the two steering pads                   */
.sm-adv .sm-hint,            /* keyboard hint line                      */
.sm-adv .sm-banner,          /* zone banner                             */
.sm-adv .sm-toast,           /* upgrade announcement                    */
.sm-adv .sm-splash,          /* power-up splash                         */
.sm-adv .sm-buttons,         /* classic sound + pause (advhud has its own) */
.sm-adv .sm-pause,           /* classic pause card (refused in adventure) */
.sm-adv .sm-summary {        /* classic end-of-run summary              */
  display: none !important;
}

/* ===========================================================================
 * 2. THE JOYSTICK
 * ---------------------------------------------------------------------------
 * A full-bleed FIXED layer so client coordinates map straight through with no
 * rect measuring (#ui-root carries the safe-area padding; an input surface
 * wants the whole viewport). It sits UNDER the HUD panels' z-index, so a tap
 * that lands on a control is a control press and everything else is a drive.
 *
 * The base is only painted once a pointer has actually used it — a desktop
 * player driving on WASD is never shown a thumb control they did not ask for.
 * ======================================================================== */
.sm-stick-layer {
  position: fixed;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}
.sm-adv .sm-stick-layer.sm-stick-armed { pointer-events: auto; }

.sm-stick-base {
  position: absolute;
  left: 0;
  top: 0;
  width: 148px;                 /* 2 x RADIUS in js/joystick.js */
  height: 148px;
  margin-left: -74px;
  margin-top: -74px;
  opacity: 0;
  transition: opacity 0.34s ease;
  will-change: transform, opacity;
}
/* Visible but translucent when idle, brighter while a thumb is on it. It sits
   on top of the mine the player is trying to read, so it never gets solid. */
.sm-stick-base.sm-stick-on { opacity: 0.5; }
.sm-stick-base.sm-stick-hold { opacity: 0.92; transition: opacity 0.08s ease; }

.sm-stick-ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2px solid rgba(150, 200, 235, 0.34);
  background:
    radial-gradient(circle,
      rgba(10, 14, 20, 0.34) 0%,
      rgba(10, 14, 20, 0.16) 62%,
      rgba(10, 14, 20, 0) 100%);
  box-shadow:
    inset 0 0 20px rgba(0, 0, 0, 0.55),
    0 0 16px rgba(0, 0, 0, 0.40);
}
/* The DEAD ZONE, drawn. 42% inset of a 74px radius is ~11.8px, which is the
   0.16 dead zone in js/joystick.js — the ring literally shows the band where
   the machine does not move. */
.sm-stick-ring::after {
  content: '';
  position: absolute;
  inset: 42%;
  border-radius: 50%;
  border: 1px dashed rgba(160, 205, 240, 0.30);
}

.sm-stick-knob {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 60px;                  /* 2 x KNOB_R in js/joystick.js */
  height: 60px;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background: linear-gradient(180deg,
      rgba(150, 226, 255, 0.92), rgba(46, 128, 172, 0.82) 68%, rgba(24, 74, 104, 0.86));
  border: 1px solid rgba(196, 246, 255, 0.62);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.45),
    inset 0 -3px 6px rgba(0, 0, 0, 0.45),
    0 5px 16px rgba(0, 0, 0, 0.55);
  transition: transform 0.16s cubic-bezier(0.2, 1.3, 0.4, 1);
}
/* No transition while a finger is on it, or the knob lags behind the thumb. */
.sm-stick-hold .sm-stick-knob { transition: none; }

/* ===========================================================================
 * 3. THE IN-MINE HUD — THE WIDE LAYOUT
 * ---------------------------------------------------------------------------
 * One column top-LEFT: where am I, how much fuel, what is in the hold. At
 * 1440x900 that column is 560 px of a 1440 px window and the machine is
 * centred, so it never covers the shaft — this layout was never the problem
 * and it is untouched. §3b moves the same elements to the screen edges on
 * anything compact, where a top stack IS the problem.
 *
 * The panel itself does NOT take pointer events — only the two icon buttons,
 * the manifest rows and the drawer handle do — so a drag that starts over the
 * gauges still drives. That holds in both layouts and it is load-bearing: in
 * the rail layout .sm-ah covers the WHOLE window, and it is only harmless
 * because it is transparent to pointers all the way down.
 * ======================================================================== */
.sm-ah {
  position: absolute;
  top: var(--sm-top-y);
  left: var(--sm-gutter);
  right: var(--sm-gutter);
  max-width: 560px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.28s ease, filter 0.28s ease;
  z-index: 6;
}
.sm-ah.sm-ah-on { opacity: 1; }
/* The pause card sits above; the instruments dim behind it. */
.sm-ah.sm-ah-paused { filter: grayscale(0.6) brightness(0.55); }

.sm-ah-lbl {
  font-family: var(--sm-mono);
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 2.4px;
  text-indent: 2.4px;
  color: var(--sm-dimmer);
}
.sm-ah-val {
  font-family: var(--sm-mono);
  font-size: 17px;
  font-weight: 800;
  line-height: 1.05;
  color: var(--sm-text);
  font-variant-numeric: tabular-nums;
}
.sm-ah-sub {
  font-family: var(--sm-mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.8px;
  color: var(--sm-dim);
  margin-top: 5px;
  font-variant-numeric: tabular-nums;
}
/* THE SEPARATORS ARE CSS, NOT STRING CONCATENATION. advhud.js writes the three
   halves of the sub line into three spans so the rail can drop the last two;
   the interpuncts belong to the spans that follow, and :not(:empty) means a
   dropped or zeroed span never leaves an orphaned dot behind it. */
.sm-ah-sub-burn:not(:empty)::before,
.sm-ah-sub-left:not(:empty)::before { content: ' · '; color: var(--sm-dimmer); }
.sm-ah-sub-k { color: var(--sm-dimmer); }

/* --- row 1: depth, the company balance, and the two conditional gauges -- */
.sm-ah-strip {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 7px 12px 8px;
  padding-right: 96px;          /* clear of the icon buttons */
  min-height: 44px;
}
.sm-ah-cell { min-width: 0; }
/* The company balance, reading as money rather than as another measurement —
   it replaced TO SURFACE, which was DEPTH printed a second time. */
.sm-ah-funds .sm-ah-val { color: var(--sm-gold, #ffbe46); }
/* HEAT and INTEGRITY are ABSENT until they mean something. A dead gauge in the
   starter mine teaches the player to ignore that corner of the screen. */
.sm-ah-heat, .sm-ah-integ { display: none; }
.sm-ah-heat.sm-ah-live, .sm-ah-integ.sm-ah-live { display: block; }

.sm-ah-mini {
  width: 54px;
  height: 4px;
  margin-top: 4px;
  border-radius: 2px;
  background: rgba(0, 0, 0, 0.6);
  overflow: hidden;
}
.sm-ah-mini-fill {
  height: 100%;
  width: 100%;
  transform-origin: left center;
  transform: scaleX(var(--sm-ah-fill, 0));
  background: linear-gradient(90deg, var(--sm-cyan), var(--sm-cyan-hot));
  transition: transform 0.14s linear;
}
.sm-ah-heat .sm-ah-mini-fill { background: linear-gradient(90deg, #ff8a1f, #ffd9a0); }
.sm-ah-integ .sm-ah-mini-fill { background: linear-gradient(90deg, var(--sm-green), #d8ffe6); }
.sm-ah-cell.sm-ah-hot .sm-ah-val { color: var(--sm-red); }
.sm-ah-cell.sm-ah-hot .sm-ah-mini-fill { background: linear-gradient(90deg, var(--sm-red), #ffc7bf); }

/* --- the bars ---------------------------------------------------------- */
.sm-ah-bar {
  position: relative;
  height: 12px;
  border-radius: 3px;
  background:
    linear-gradient(180deg, rgba(0, 0, 0, 0.72), rgba(0, 0, 0, 0.5));
  border: 1px solid rgba(255, 255, 255, 0.07);
  overflow: hidden;
}
.sm-ah-bar-fill {
  position: absolute;
  inset: 0;
  transform-origin: left center;
  transform: scaleX(var(--sm-ah-fill, 0));
  /* scaleX on a gradient would smear it, so the gradient is authored to be
     read from the LEFT edge only — it is a level, not a picture. */
  background: linear-gradient(90deg, #ffb01f, #ffe08a);
  transition: transform 0.12s linear;
}
.sm-ah-bar-cargo .sm-ah-bar-fill { background: linear-gradient(90deg, #35c7ff, #c4f6ff); }

/* THE RESERVE MARK. This is the whole fuel instrument: it turns a percentage
   into "that much of the tank is the way home". */
.sm-ah-bar-mark {
  position: absolute;
  top: -2px;
  bottom: -2px;
  left: 0;
  width: 2px;
  margin-left: calc(var(--sm-ah-mark, 0) * 100%);
  background: var(--sm-text);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.8), 0 0 8px rgba(255, 255, 255, 0.5);
  opacity: 0;
  transition: margin-left 0.2s ease, opacity 0.2s ease;
}
.sm-ah-bar-mark.sm-ah-bar-mark-on { opacity: 0.85; }

/* --- FUEL: the primary gauge ------------------------------------------- */
.sm-ah-fuel { padding: 8px 12px 10px; }
.sm-ah-fuel-head {
  display: flex;
  align-items: baseline;
  gap: 9px;
  margin-bottom: 6px;
}
.sm-ah-fuel-head .sm-ah-lbl { align-self: center; }
.sm-ah-fuel-pct {
  font-family: var(--sm-mono);
  font-size: 30px;
  font-weight: 800;
  line-height: 0.95;
  letter-spacing: -0.5px;
  color: var(--sm-gold);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 2px 0 #000, 0 0 18px rgba(255, 194, 31, 0.30);
}
.sm-ah-fuel-note {
  margin-left: auto;
  font-family: var(--sm-mono);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 2px;
  color: var(--sm-dim);
}

/* Amber: what is left is close to what getting home costs. */
.sm-ah-fuel.sm-ah-warn { border-color: rgba(255, 194, 31, 0.5); }
.sm-ah-fuel.sm-ah-warn .sm-ah-fuel-note { color: var(--sm-gold); }
.sm-ah-fuel.sm-ah-warn .sm-ah-bar-fill { background: linear-gradient(90deg, #ff8a1f, #ffd08a); }
/* Red and pulsing: the reserve is spent. This is the failure state arriving. */
.sm-ah-fuel.sm-ah-crit {
  border-color: rgba(255, 90, 72, 0.7);
  animation: sm-ah-alarm 1.05s ease-in-out infinite;
}
.sm-ah-fuel.sm-ah-crit .sm-ah-fuel-pct { color: var(--sm-red); text-shadow: 0 2px 0 #000, 0 0 20px rgba(255, 90, 72, 0.5); }
.sm-ah-fuel.sm-ah-crit .sm-ah-fuel-note { color: var(--sm-red); }
.sm-ah-fuel.sm-ah-crit .sm-ah-bar-fill { background: linear-gradient(90deg, #ff4a36, #ffb3a8); }
@keyframes sm-ah-alarm {
  0%, 100% { box-shadow: inset 0 1px 0 var(--sm-edge-hi), inset 0 -2px 0 var(--sm-edge-lo), 0 6px 18px rgba(0,0,0,0.55); }
  50%      { box-shadow: inset 0 1px 0 var(--sm-edge-hi), inset 0 -2px 0 var(--sm-edge-lo), 0 6px 18px rgba(0,0,0,0.55), 0 0 22px rgba(255,90,72,0.55); }
}

/* --- the hold ---------------------------------------------------------- */
.sm-ah-cargo { padding: 8px 12px 9px; }
.sm-ah-cargo-val {
  font-family: var(--sm-mono);
  font-size: 19px;
  font-weight: 800;
  line-height: 1;
  color: var(--sm-cyan-hot);
  font-variant-numeric: tabular-nums;
}
.sm-ah-cargo.sm-ah-full { border-color: rgba(102, 226, 255, 0.6); }
.sm-ah-cargo.sm-ah-full .sm-ah-cargo-val { color: var(--sm-cyan); }

/* The drawer wrapper is layout-NEUTRAL here: a plain block around two blocks
   that already carry their own margins, so the wide stack looks exactly as it
   did before it existed. §3b is where it becomes a drawer. The handle beside it
   has nothing to unfold on a wide screen, so it is not rendered at all. */
.sm-ah-holdbtn { display: none; }

.sm-ah-manifest {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: 6px;
}
.sm-ah-manifest.sm-ah-manifest-empty { margin-top: 0; }
/* A manifest row IS a button: tap once to arm, twice to tip that material onto
   the floor. "Dump the coal" is the decision the manifest exists to support. */
.sm-ah-mrow {
  display: flex;
  align-items: center;
  gap: 7px;
  height: 19px;
  padding: 0 6px;
  border: 1px solid transparent;
  border-radius: 2px;
  background: rgba(10, 13, 17, 0.55);
  font-family: var(--sm-mono);
  color: var(--sm-text);
  pointer-events: auto;
  cursor: pointer;
  text-align: left;
}
.sm-ah-mrow:hover { background: rgba(30, 38, 48, 0.7); }
.sm-ah-msw {
  width: 8px;
  height: 8px;
  border-radius: 1px;
  flex: 0 0 auto;
  background: var(--sm-ah-sw, #8e9bab);
  box-shadow: 0 0 6px var(--sm-ah-sw, #8e9bab);
}
.sm-ah-mname {
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 1px;
  color: var(--sm-dim);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  flex: 1 1 auto;
}
.sm-ah-munits {
  font-size: 9.5px;
  font-weight: 800;
  color: var(--sm-text);
  font-variant-numeric: tabular-nums;
  flex: 0 0 auto;
}
.sm-ah-mval {
  font-size: 9.5px;
  font-weight: 800;
  color: var(--sm-gold);
  min-width: 46px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  flex: 0 0 auto;
}
.sm-ah-mrow-armed {
  border-color: rgba(255, 90, 72, 0.75);
  background: rgba(70, 18, 14, 0.75);
}
.sm-ah-mrow-armed .sm-ah-munits { color: var(--sm-red); }
.sm-ah-more {
  display: none;
  font-family: var(--sm-mono);
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 1.6px;
  color: var(--sm-dimmer);
  margin-top: 4px;
}
.sm-ah-more.sm-ah-more-on { display: block; }

/* --- the scanner line -------------------------------------------------- */
.sm-ah-scan {
  display: none;
  align-items: center;
  gap: 8px;
  padding: 5px 10px;
  border-left: 3px solid var(--sm-ah-sw, var(--sm-cyan));
  background: rgba(8, 12, 17, 0.72);
  border-radius: 2px;
}
.sm-ah-scan.sm-ah-scan-on { display: flex; }
.sm-ah-scan-arrow {
  width: 15px;
  height: 15px;
  color: var(--sm-ah-sw, var(--sm-cyan));
  transform: rotate(var(--sm-ah-bearing, 0deg));
  transition: transform 0.18s ease;
}
.sm-ah-scan-arrow svg { display: block; width: 100%; height: 100%; }
.sm-ah-scan-text {
  font-family: var(--sm-mono);
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 1.6px;
  color: var(--sm-text);
}
.sm-ah-scan-dist {
  margin-left: auto;
  font-family: var(--sm-mono);
  font-size: 11px;
  font-weight: 800;
  color: var(--sm-ah-sw, var(--sm-cyan));
  font-variant-numeric: tabular-nums;
}

/* --- the alert banner --------------------------------------------------
 * Directly under the stack (top:100%), centred. Short, loud, and gone.
 *
 * IT SIZES TO ITS SENTENCE. An absolutely positioned box with `left` and no
 * `width` shrinks to fit the space between `left` and the edge of its
 * containing block — which here is half of .sm-ah, i.e. 280px on a desktop. Every
 * banner in the game used to be short enough not to notice, and then
 * "SILVER — TOO HARD FOR THIS DRILL" arrived and broke across two lines in the
 * middle of a phrase. `width: max-content` lets a banner be as wide as the thing
 * it has to say, and the max-width keeps it inside the window on a phone; short
 * banners are unchanged, because min-width was already doing the work for them.
 * There is nothing to the right of the stack to collide with — the two icon
 * buttons are pinned to the far corner. */
.sm-ah-alert {
  position: absolute;
  top: 100%;
  left: 50%;
  margin-top: 12px;
  transform: translateX(-50%) translateY(-8px);
  min-width: 210px;
  width: max-content;
  max-width: min(540px, calc(100vw - var(--sm-gutter) * 2));
  padding: 8px 18px 9px;
  text-align: center;
  background: linear-gradient(180deg, rgba(48, 20, 14, 0.92), rgba(20, 9, 7, 0.94));
  border: 1px solid rgba(255, 138, 31, 0.55);
  border-radius: 4px;
  box-shadow: 0 8px 26px rgba(0, 0, 0, 0.6);
  opacity: 0;
}
.sm-ah-alert.sm-ah-alert-on { animation: sm-ah-alert-kf 2.4s cubic-bezier(0.16, 1, 0.3, 1) both; }
@keyframes sm-ah-alert-kf {
  0%   { opacity: 0; transform: translateX(-50%) translateY(-16px) scale(0.96); }
  9%   { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
  82%  { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
  100% { opacity: 0; transform: translateX(-50%) translateY(-6px) scale(0.99); }
}
.sm-ah-alert-title {
  font-family: var(--sm-mono);
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 3px;
  text-indent: 3px;
  color: var(--sm-gold-hot);
  text-shadow: 0 2px 0 #000;
}
.sm-ah-alert-sub {
  font-family: var(--sm-mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.4px;
  color: var(--sm-dim);
  margin-top: 3px;
}

/* --- the adventure pause card ----------------------------------------- */
.sm-ah-pause {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(ellipse at center, rgba(4, 6, 9, 0.6), rgba(2, 3, 5, 0.92));
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.22s ease;
  z-index: 17;
}
.sm-ah-pause.sm-ah-pause-on { opacity: 1; pointer-events: auto; }
.sm-ah-pause-card {
  width: min(340px, 86vw);
  padding: 20px 20px 18px;
  text-align: center;
  transform: translateY(10px);
  transition: transform 0.24s cubic-bezier(0.16, 1, 0.3, 1);
}
.sm-ah-pause-on .sm-ah-pause-card { transform: none; }
.sm-ah-pause-stats {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 6px;
  margin: 12px 0 14px;
  text-align: left;
}
.sm-ah-pause-stats .sm-cell { padding: 6px 8px; }
/* The card centres its text; its ENGINE / EFFECTS captions must not, or they
   float in their gutter instead of starting at the x SPRÅK starts at. */
.sm-ah-pause-card .sm-sound-label { text-align: left; }
.sm-ah-pause-stats .sm-cell-value { font-size: 15px; }
.sm-ah-pause-note {
  font-family: var(--sm-mono);
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: 1px;
  line-height: 1.5;
  color: var(--sm-dimmer);
  margin-top: 10px;
}
.sm-btn.sm-ah-danger { color: #ffd8d2; border-color: rgba(255, 90, 72, 0.42); }
.sm-btn.sm-ah-armed {
  color: #1a0603;
  background: linear-gradient(180deg, #ff9b8c, var(--sm-red) 55%, #b3271a);
  border-color: rgba(255, 200, 190, 0.6);
}

/* Leaving the game itself: last on the card, with a little more air above it
   than between the others. Only the geometry is here — its look is shared
   with the title's copy and lives beside .sm-start-quit further down, where
   it can win the specificity tie that a rule up here loses. */
.sm-btn.sm-ah-quit { margin-top: 16px; }

/* THE PAUSE CARD ON A PHONE ON ITS SIDE (hub CLAUDE.md §2: a menu must not
   scroll sideways). The language row made a tall card taller — kicker, title,
   stats, SPRÅK, three actions, the note and the way out come to ~510px against
   a sideways phone's ~330 — so here it becomes maxgear's shape: two columns
   laid over the existing markup, nothing moved in the DOM. What the player
   reads goes left (PAUSE, the stats, the language), what they press goes right
   (RESUME, END RUN, TITLE SCREEN, the note, the way out). `dense` packing
   is what lets the right column start at the top again rather than below the
   last left-hand row. The kicker is flavour, so it is what goes. Controls stop
   at 40px: this fires on a phone, where a finger is still the pointer. The
   overflow is a safety net, not the plan. */
@media (orientation: landscape) and (max-height: 500px) {
  .sm-ah-pause-card {
    width: min(660px, 94vw);
    max-height: 94vh;
    overflow: auto;
    padding: 12px 16px 10px;
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-auto-flow: row dense;
    column-gap: 18px;
    align-content: start;
    align-items: start;
  }
  .sm-ah-pause-card > * { grid-column: 1; }
  .sm-ah-pause-card > .sm-pause-btn,
  .sm-ah-pause-card > .sm-ah-pause-note { grid-column: 2; }
  .sm-ah-pause-card .sm-pause-kicker { display: none; }
  .sm-ah-pause-card .sm-pause-title { font-size: 24px; margin-bottom: 4px; }
  .sm-ah-pause-card .sm-ah-pause-stats { margin: 4px 0 0; }
  .sm-ah-pause-card .sm-lang { margin-top: 8px; }
  .sm-ah-pause-card .sm-pause-btn { min-height: 40px; margin-top: 6px; }
  .sm-ah-pause-card .sm-pause-btn:first-of-type { margin-top: 0; }
  .sm-ah-pause-card .sm-ah-pause-note { margin-top: 6px; }
  .sm-btn.sm-ah-quit { margin-top: 10px; }
}

/* ===========================================================================
 * 3b. THE RAIL LAYOUT — COMPACT AND PORTRAIT
 * ---------------------------------------------------------------------------
 * THE ARGUMENT, because this overturns what §3 used to say.
 *
 * The old layout was a stack pinned to the top on EVERY viewport, and the
 * reason given was the thumb: the joystick's origin floats to wherever it
 * lands, so the bottom of the screen is under the player's own hand. That is
 * true, and nothing here disputes it.
 *
 * What it missed is that -y is the SURFACE. The mine mouth is UP. Getting home
 * means driving towards the top of the screen, and you do it with the tank at
 * its lowest, in the dark, deciding second by second whether you will make it.
 * On a 390x844 phone the stack was 210 px tall and full width — a quarter of
 * the glass, opaque, over the one part of the screen the player is steering
 * towards. Shrinking it would not have helped: a smaller panel in the same
 * place is the same mistake, quieter.
 *
 * So: the top belongs to the mine, the bottom belongs to the thumb, and the
 * instruments go where neither of them is. THE TWO SIDE EDGES. The machine is
 * ~75 px wide in the middle of a 390 px screen; the outer 48 px on each side is
 * peripheral rock you never drill and never look at.
 *
 *   LEFT RAIL     FUEL — percentage, state word, a tall bar that fills from the
 *                 BOTTOM like a tank, the reserve mark struck across it, and
 *                 what the trip home costs underneath. A long thin bar is the
 *                 RIGHT shape for this gauge: the taller it is, the finer you
 *                 can read the level against the mark.
 *   RIGHT RAIL    HOLD — units, capacity, worth and fill, always visible. The
 *                 manifest is behind the handle at its foot.
 *   BOTTOM EDGE   one line: DEPTH · FUNDS · HULL · HEAT. Inside #ui-root's
 *                 safe-area padding (an absolutely positioned child resolves
 *                 `bottom` against the PADDING box, so the home indicator is
 *                 already accounted for) and below where a thumb sits on the
 *                 stick.
 *   BETWEEN THEM  the scanner contact, just above that line.
 *   TOP EDGE      the sound and pause plates in the right corner, and nothing
 *                 else. The shaft is clear from the machine to the daylight.
 *
 * NO BACKDROP BLUR ON ANY OF IT. style.css makes the same call for the classic
 * score strip and the reason is identical: these plates are full-height and
 * full-width, and blurring them at DPR 3 is real fill rate spent on an effect
 * nobody can see against dark rock.
 *
 * .sm-ah COVERS THE WHOLE WINDOW in this layout, because its children are
 * pinned to four different edges. That is only safe because the container and
 * every gauge in it are pointer-events: none — a drag that starts over a rail
 * still falls through to the stick layer and drives. The three exceptions are
 * real controls: the two icon plates, the drawer handle, and the manifest rows.
 * ======================================================================== */
.sm-adv.sm-compact {
  --sm-ah-rail:  48px;   /* width of one edge rail                          */
  --sm-ah-foot:  30px;   /* height of the bottom readout line               */
  /* Rails clear the icon plates above and the readout line below. */
  --sm-ah-railtop: calc(var(--sm-top-y) + var(--sm-btn-size) + 10px);
  --sm-ah-railbot: calc(var(--sm-top-y) + var(--sm-ah-foot) + 8px);
}

/* The stack stops being a stack: the container becomes the window and every
   instrument is positioned against an edge from here down. */
.sm-adv.sm-compact .sm-ah {
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  max-width: none;
  display: block;
  gap: 0;
}

/* --- the two rails ----------------------------------------------------- */
.sm-adv.sm-compact .sm-ah-fuel,
.sm-adv.sm-compact .sm-ah-cargo {
  position: absolute;
  top: var(--sm-ah-railtop);
  bottom: var(--sm-ah-railbot);
  width: var(--sm-ah-rail);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 6px 2px 7px;
  border-radius: 5px;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow:
    inset 0 1px 0 var(--sm-edge-hi),
    inset 0 -2px 0 var(--sm-edge-lo),
    0 0 16px rgba(0, 0, 0, 0.5);
}
/* Each rail is darkest at the screen edge and fades towards the rock, so the
   plate reads as a bezel round the window rather than a lid over it. */
.sm-adv.sm-compact .sm-ah-fuel {
  left: var(--sm-gutter);
  background: linear-gradient(90deg, rgba(9, 12, 17, 0.90), rgba(12, 16, 22, 0.62));
}
.sm-adv.sm-compact .sm-ah-cargo {
  right: var(--sm-gutter);
  background: linear-gradient(270deg, rgba(9, 12, 17, 0.90), rgba(12, 16, 22, 0.62));
  /* The drawer opens OUT of this plate, so it cannot be clipped by it. The
     bars keep their own overflow:hidden, so nothing else escapes. */
  overflow: visible;
}

/* --- the head of a rail: label, number, state word, stacked ------------- */
.sm-adv.sm-compact .sm-ah-fuel-head {
  flex-direction: column;
  align-items: center;
  gap: 0;
  width: 100%;
  margin-bottom: 3px;
}
.sm-adv.sm-compact .sm-ah-fuel-head .sm-ah-lbl { align-self: center; }
.sm-adv.sm-compact .sm-ah-lbl {
  font-size: 7px;
  letter-spacing: 1.4px;
  text-indent: 1.4px;
}
.sm-adv.sm-compact .sm-ah-fuel-pct {
  font-size: 16px;
  letter-spacing: -0.4px;
  margin-top: 1px;
}
/* 'TURN BACK' and 'RESERVE SPENT' are allowed to wrap: two short lines in a
   48 px column is exactly how a real gauge would letter them. */
.sm-adv.sm-compact .sm-ah-fuel-note {
  margin-left: 0;
  margin-top: 1px;
  font-size: 8px;
  letter-spacing: 0.4px;
  line-height: 1.12;
  text-align: center;
}
/* The hold's worth is money, not a state word, so it keeps its size and goes
   gold — it is the number the dump decision is actually weighed against. */
.sm-adv.sm-compact .sm-ah-cargo .sm-ah-fuel-note {
  font-size: 9.5px;
  letter-spacing: 0.6px;
  color: var(--sm-gold);
}
.sm-adv.sm-compact .sm-ah-cargo-val {
  font-size: 15px;
  line-height: 1.02;
  text-align: center;
  margin-top: 1px;
}
/* '0 / 48' is inline on a wide screen and two lines here. */
.sm-adv.sm-compact .sm-ah-cargo-cap {
  display: block;
  font-size: 10px;
  color: var(--sm-dim);
}

/* --- THE BARS, TURNED ON THEIR SIDE -----------------------------------
 * Same --sm-ah-fill, same guarded write in advhud.js, no measuring: only the
 * axis changes. transform-origin moves to the bottom edge and the gradients
 * are re-authored to run ACROSS the bar rather than along it, because a
 * gradient on the scaled axis smears — the wide layout's left-to-right ramp
 * would stretch and squash as the tank drains. Across the width it is a
 * lengthwise sheen that scaleY cannot touch. */
.sm-adv.sm-compact .sm-ah-bar {
  width: 15px;
  height: auto;
  flex: 1 1 auto;
  min-height: 54px;
  margin: 3px 0 4px;
  border-radius: 4px;
}
.sm-adv.sm-compact .sm-ah-bar-fill {
  transform-origin: center bottom;
  transform: scaleY(var(--sm-ah-fill, 0));
  background: linear-gradient(90deg, #c8830c, #ffe08a 48%, #d4900f);
}
.sm-adv.sm-compact .sm-ah-bar-cargo .sm-ah-bar-fill {
  background: linear-gradient(90deg, #1b86b4, #c4f6ff 48%, #2295c6);
}
.sm-adv.sm-compact .sm-ah-fuel.sm-ah-warn .sm-ah-bar-fill {
  background: linear-gradient(90deg, #b85406, #ffd08a 48%, #c25c07);
}
.sm-adv.sm-compact .sm-ah-fuel.sm-ah-crit .sm-ah-bar-fill {
  background: linear-gradient(90deg, #a8281a, #ffb3a8 48%, #b62c1d);
}
/* THE RESERVE MARK, struck across the bar at the height the trip home costs.
   `bottom` and not `margin-bottom`: a percentage MARGIN resolves against the
   containing block's WIDTH, which on a 15 px bar would put the mark 7 px up and
   silently lie about the one thing this instrument exists to say. */
.sm-adv.sm-compact .sm-ah-bar-mark {
  top: auto;
  left: -3px;
  right: -3px;
  width: auto;
  height: 2px;
  margin-left: 0;
  bottom: calc(var(--sm-ah-mark, 0) * 100%);
  transition: bottom 0.2s ease, opacity 0.2s ease;
}

/* --- what the trip home costs, under the bar --------------------------- */
.sm-adv.sm-compact .sm-ah-sub {
  margin-top: 2px;
  font-size: 8px;
  letter-spacing: 0.2px;
  line-height: 1.15;
  text-align: center;
}
.sm-adv.sm-compact .sm-ah-sub-k { display: block; }
/* BURN and SECONDS LEFT are the two halves that do not fit and do not have to:
   the reserve mark on the bar already answers "can I get home", which is what
   they were arithmetic for. They come back the moment there is room. */
.sm-adv.sm-compact .sm-ah-sub-burn,
.sm-adv.sm-compact .sm-ah-sub-left { display: none; }

/* --- THE DRAWER HANDLE, at the foot of the hold rail -------------------
 * At the FOOT deliberately, not the head. Dumping spoil is done under pressure
 * with one hand, so the handle has to be inside thumb reach; the head of the
 * rail is a stretch away on an 844 px phone. It is the only pointer target in
 * the lower half of the screen and it is 48 px wide at the extreme edge, where
 * a driving thumb does not sit — a thumb on the stick needs travel room on all
 * four sides of itself. */
.sm-adv.sm-compact .sm-ah-holdbtn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 3px;
  width: 100%;
  min-height: 27px;
  margin: 3px 0 0;
  padding: 0;
  appearance: none;
  -webkit-appearance: none;
  border: 1px solid rgba(126, 140, 158, 0.34);
  border-radius: 3px;
  background: rgba(8, 11, 15, 0.78);
  color: var(--sm-cyan);
  font-family: var(--sm-mono);
  font-size: 10px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  pointer-events: auto;
  cursor: pointer;
}
.sm-adv.sm-compact .sm-ah-holdico { display: block; width: 13px; height: 13px; }
.sm-adv.sm-compact .sm-ah-holdico svg { display: block; width: 100%; height: 100%; }
.sm-adv.sm-compact .sm-ah-holdbtn-on {
  border-color: var(--sm-cyan);
  background: rgba(18, 62, 82, 0.86);
  color: var(--sm-cyan-hot);
}
/* Nothing aboard: still tappable (it says so when you open it), just not
   asking for a tap. */
.sm-adv.sm-compact .sm-ah-holdbtn-empty { color: var(--sm-dimmer); border-color: rgba(126, 140, 158, 0.2); }
/* A full hold is the moment the manifest matters, so the handle says so. */
.sm-adv.sm-compact .sm-ah-cargo.sm-ah-full .sm-ah-holdbtn {
  border-color: rgba(102, 226, 255, 0.7);
  color: var(--sm-cyan-hot);
}

/* --- THE DRAWER ITSELF, opening inwards over the rock ------------------ */
.sm-adv.sm-compact .sm-ah-drawer {
  display: none;
  position: absolute;
  right: calc(100% + 7px);
  bottom: 0;
  width: min(250px, 58vw);
  padding: 7px 8px 8px;
  border: 1px solid var(--sm-border);
  border-radius: 4px;
  background: linear-gradient(180deg, rgba(17, 21, 27, 0.96), rgba(8, 10, 14, 0.97));
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.65);
}
.sm-adv.sm-compact .sm-ah-drawer.sm-ah-drawer-on { display: block; }
.sm-adv.sm-compact .sm-ah-manifest { margin-top: 0; }
/* A 19 px row is a mouse target. Tapping one twice is how a player dumps the
   coal, so in the drawer it becomes a finger target. */
.sm-adv.sm-compact .sm-ah-mrow { height: 30px; gap: 8px; padding: 0 8px; }
.sm-adv.sm-compact .sm-ah-mname { font-size: 9.5px; }
.sm-adv.sm-compact .sm-ah-munits { font-size: 10.5px; }
.sm-adv.sm-compact .sm-ah-mval { font-size: 10.5px; min-width: 52px; }
/* An empty hold has to SAY it is empty, or an opened drawer with nothing in it
   reads as a bug. */
.sm-adv.sm-compact .sm-ah-manifest.sm-ah-manifest-empty::before {
  content: 'HOLD EMPTY';
  display: block;
  padding: 7px 2px 6px;
  text-align: center;
  font-family: var(--sm-mono);
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 2px;
  color: var(--sm-dimmer);
}
/* Words in CSS still speak the page's language: <html lang> is rewritten live
   by js/i18n.js, so :lang() follows a switch with no script here. */
.sm-adv.sm-compact .sm-ah-manifest.sm-ah-manifest-empty:lang(nb)::before { content: 'TOMT LASTEROM'; }

/* --- THE BOTTOM READOUT LINE ------------------------------------------
 * DEPTH, the balance, the hull and — once it means anything — the heat. Four
 * label/value pairs turned on their side, because a stacked cell needs 30 px of
 * height and this line has 30 px in total. */
.sm-adv.sm-compact .sm-ah-strip {
  position: absolute;
  top: auto;
  bottom: var(--sm-top-y);
  left: var(--sm-gutter);
  right: var(--sm-gutter);
  height: var(--sm-ah-foot);
  min-height: 0;
  gap: 10px;
  padding: 0 10px;
  justify-content: space-between;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
/* The hazard stripe belongs on the edge that faces the play area. */
.sm-adv.sm-compact .sm-ah-strip .sm-stripe { top: auto; bottom: 0; }
.sm-adv.sm-compact .sm-ah-cell { align-items: center; gap: 5px; }
/* display is set per CELL, never on .sm-ah-cell: HEAT and INTEGRITY switch
   themselves on with .sm-ah-live, and a blanket display on the shared class
   would outrank the `display:none` that keeps a dead HEAT gauge off the
   screen. */
.sm-adv.sm-compact .sm-ah-depth,
.sm-adv.sm-compact .sm-ah-funds { display: flex; }
.sm-adv.sm-compact .sm-ah-heat.sm-ah-live,
.sm-adv.sm-compact .sm-ah-integ.sm-ah-live { display: flex; }
.sm-adv.sm-compact .sm-ah-strip .sm-ah-lbl {
  font-size: 7px;
  letter-spacing: 1.2px;
  text-indent: 0;
  flex: 0 0 auto;
}
.sm-adv.sm-compact .sm-ah-val { font-size: 13px; }
.sm-adv.sm-compact .sm-ah-mini { width: 22px; margin-top: 0; flex: 0 0 auto; }

/* --- the scanner contact, between the rails ---------------------------- */
.sm-adv.sm-compact .sm-ah-scan {
  position: absolute;
  bottom: calc(var(--sm-top-y) + var(--sm-ah-foot) + 6px);
  left: calc(var(--sm-gutter) + var(--sm-ah-rail) + 8px);
  right: calc(var(--sm-gutter) + var(--sm-ah-rail) + 8px);
  padding: 4px 8px;
}

/* --- the alert banner --------------------------------------------------
 * It used to hang off the bottom of the stack (top: 100%), which in this layout
 * is off the bottom of the screen. It moves to just above the scanner line: a
 * banner is loud, short and gone, and putting it back at the top would be
 * putting back the thing this whole section exists to remove. */
.sm-adv.sm-compact .sm-ah-alert {
  top: auto;
  bottom: calc(var(--sm-top-y) + var(--sm-ah-foot) + 38px);
  margin-top: 0;
  min-width: 0;
  /* Was a flat `width: min(320px, ...)`. 320 is exactly one pixel short of
   * "SILVER — TOO HARD FOR THIS DRILL" at this size (measured: 321px), which
   * orphaned DRILL onto a line of its own — the worst possible break in the one
   * sentence the banner exists to say. Sizing to the content and clamping at the
   * viewport keeps every short banner exactly where it was and gives the long
   * ones the last thirty pixels of the screen. The SUB may still wrap on a phone
   * and that is fine: it is a comma list, and it breaks between clauses. */
  width: max-content;
  max-width: calc(100vw - 2 * var(--sm-gutter));
  padding: 7px 12px 8px;
}
.sm-adv.sm-compact .sm-ah-alert-title { font-size: 13px; letter-spacing: 2.2px; text-indent: 2.2px; }
.sm-adv.sm-compact .sm-ah-alert-sub { font-size: 8.5px; letter-spacing: 1.1px; }

/* ===========================================================================
 * 4. THE META SCREENS
 * ---------------------------------------------------------------------------
 * One shell: a ledger strip, a stage holding all five screens, and a toast.
 * Every screen is header / scrolling body / FIXED FOOTER — the footer is where
 * the primary action lives, so it can never be scrolled out of reach.
 * ======================================================================== */
.sm-av {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: max(8px, var(--sm-top-y)) var(--sm-gutter) 10px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.26s ease;
  z-index: 14;
}
.sm-av.sm-av-on { opacity: 1; pointer-events: auto; }

/* --- the ledger strip -------------------------------------------------- */
.sm-av-ledger {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 40px;
  padding: 6px 12px 7px;
  /* THE CORNER CLUSTER LANDS HERE. ui.js's sound and fullscreen plates are
     fixed to the page at the same inset this strip's own right edge uses, and
     the cash balance is pinned to that edge by .sm-av-led-right's auto margin
     — so without this the two most-read characters on five screens would sit
     under a button. One plate pair plus air, measured off the plate size so it
     tracks the compact breakpoint by itself. */
  padding-right: calc(var(--sm-btn-size) * 2 + 20px);
}
.sm-av.sm-av-noledger .sm-av-ledger { display: none; }
.sm-av-led-co {
  font-family: var(--sm-mono);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 2.4px;
  color: var(--sm-text);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.sm-av-led-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 0 0 auto;
}
.sm-av-led-cell {
  font-family: var(--sm-mono);
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 1.8px;
  color: var(--sm-dim);
  font-variant-numeric: tabular-nums;
}
.sm-av-led-cash {
  font-family: var(--sm-mono);
  font-size: 17px;
  font-weight: 800;
  color: var(--sm-gold);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 2px 0 #000, 0 0 14px rgba(255, 194, 31, 0.28);
}

/* --- the stage and one screen ------------------------------------------ */
.sm-av-stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
}
.sm-av-screen {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateY(8px);
  transition: opacity 0.22s ease, transform 0.26s cubic-bezier(0.16, 1, 0.3, 1);
}
.sm-av-screen.sm-av-screen-on {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: none;
}
.sm-av-head { flex: 0 0 auto; }
.sm-av-kicker {
  font-family: var(--sm-mono);
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 3px;
  text-indent: 3px;
  color: var(--sm-gold);
}
.sm-av-title {
  font-family: var(--sm-mono);
  font-size: 22px;
  font-weight: 800;
  letter-spacing: 3.4px;
  text-indent: 3.4px;
  line-height: 1.1;
  color: var(--sm-text);
  text-shadow: 0 2px 0 #000;
  margin-top: 2px;
}
.sm-av-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-right: 2px;
}
.sm-av-body::-webkit-scrollbar { width: 4px; }
.sm-av-body::-webkit-scrollbar-thumb { background: rgba(126, 140, 158, 0.35); border-radius: 2px; }

/* A SCROLLING COLUMN HAS TO SCROLL, NOT SQUASH.
 * These three screens are lists of .sm-panel rows, and a flex child's default
 * flex-shrink is 1 — so when the rows do not fit, the browser shrinks each one
 * below its own content instead of overflowing, the body never gets anything
 * to scroll, and .sm-panel's overflow:hidden quietly clips whatever fell off
 * the bottom of each row. On a 390px-tall landscape phone that was CONTINUE
 * and ERASE on all three company slots: visible as two slivers of yellow,
 * reachable by nothing. Pin them at their natural height and the body scrolls,
 * which is what it was built to do. (The map and the garage are deliberately
 * NOT in this list: above 760px their bodies turn into a ROW and the two
 * columns there are meant to shrink — see the wide-screen block below.) */
.sm-av-slots > .sm-av-body > *,
.sm-av-prep > .sm-av-body > *,
.sm-av-results > .sm-av-body > * { flex-shrink: 0; }
.sm-av-foot {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding-top: 2px;
}
.sm-av-foot .sm-btn { flex: 1 1 0; margin-top: 0; }
/* The primary action gets its own line on a phone: it is the one thing that
   must be unmissable and comfortably thumb-sized. */
.sm-av-foot .sm-btn-big { flex: 1 1 100%; margin-top: 0; min-height: 52px; }
.sm-btn.sm-av-quiet {
  color: var(--sm-dim);
  font-size: 10px;
  min-height: 42px;
}
.sm-btn.sm-av-cant {
  filter: grayscale(0.75) brightness(0.7);
  cursor: default;
}
.sm-btn.sm-av-armed {
  color: #1a0603;
  background: linear-gradient(180deg, #ff9b8c, var(--sm-red) 55%, #b3271a);
  border-color: rgba(255, 200, 190, 0.6);
}
.sm-av-sub {
  font-family: var(--sm-mono);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 1.1px;
  line-height: 1.6;
  color: var(--sm-dim);
  font-variant-numeric: tabular-nums;
}
.sm-av-warn {
  font-family: var(--sm-mono);
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 1px;
  line-height: 1.5;
  color: #ffcfa8;
  background: rgba(90, 44, 10, 0.5);
  border-left: 3px solid var(--sm-orange);
  padding: 7px 10px;
  margin-top: 9px;
  border-radius: 2px;
}
.sm-av-good { color: var(--sm-green) !important; }
.sm-av-bad { color: var(--sm-red) !important; }

.sm-av-card-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}
.sm-av-card-name {
  font-family: var(--sm-mono);
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 2.2px;
  color: var(--sm-text);
}
.sm-av-card-region {
  font-family: var(--sm-mono);
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 2px;
  color: var(--sm-gold);
  margin-left: auto;
}
.sm-av-card-blurb {
  font-family: var(--sm-font);
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--sm-dim);
  margin-top: 7px;
}
.sm-av-card-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 7px;
  margin-top: 10px;
}
.sm-av-card-grid .sm-cell { padding: 7px 10px; }
.sm-av-card-grid .sm-cell-value { font-size: 15px; }

/* --- chips (materials, hazards) --------------------------------------- */
.sm-av-chips { margin-top: 10px; display: flex; flex-direction: column; gap: 6px; }
.sm-av-chiprow { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.sm-av-chiplabel {
  font-family: var(--sm-mono);
  font-size: 8px;
  font-weight: 800;
  letter-spacing: 2px;
  color: var(--sm-dimmer);
  min-width: 52px;
}
.sm-av-chip {
  font-family: var(--sm-mono);
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 1.2px;
  padding: 3px 7px 4px;
  border-radius: 2px;
  color: var(--sm-text);
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-left: 3px solid var(--sm-av-chip, #8e9bab);
}
.sm-av-haz {
  font-family: var(--sm-mono);
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 1.6px;
  color: #ffb98a;
  margin-top: 9px;
}

/* ---------------------------------------------------------------------------
 * SLOTS
 * ------------------------------------------------------------------------ */
.sm-av-slot { padding: 10px 12px 11px; }
.sm-av-slot-top { display: flex; align-items: baseline; gap: 10px; }
.sm-av-slot-no {
  font-family: var(--sm-mono);
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 2.4px;
  color: var(--sm-dimmer);
}
.sm-av-slot-name {
  font-family: var(--sm-mono);
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 2px;
  color: var(--sm-text);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.sm-av-slot-empty .sm-av-slot-name { color: var(--sm-dimmer); }
.sm-av-slot-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  margin: 9px 0 10px;
}
.sm-av-slot-stats .sm-cell { padding: 5px 8px 6px; }
.sm-av-slot-stats .sm-cell-value { font-size: 13px; }
.sm-av-slot-acts { display: flex; gap: 8px; margin-top: 9px; }
.sm-av-slot-acts .sm-btn { flex: 1 1 0; }
.sm-av-slot-acts .sm-av-quiet { flex: 0 0 88px; }
/* The name editor. advui.js toggles the inline display, so the rule here is
   what an un-inlined ('') display resolves to. */
.sm-av-slot-form { display: flex; gap: 8px; margin-top: 9px; }
.sm-av-input {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--sm-mono);
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 2px;
  color: var(--sm-text);
  background: rgba(0, 0, 0, 0.55);
  border: 1px solid rgba(126, 140, 158, 0.4);
  border-radius: 3px;
  padding: 10px 12px;
  outline: none;
}
.sm-av-input:focus { border-color: var(--sm-cyan); box-shadow: 0 0 0 2px rgba(102, 226, 255, 0.18); }
.sm-av-input::placeholder { color: var(--sm-dimmer); letter-spacing: 2px; }

/* ---------------------------------------------------------------------------
 * MAP
 * The artwork is CSS: layered gradients that read as a surveyed plateau cut by
 * a valley, plus a faint contour grid. No image assets, nothing to load.
 * `.sm-av-map` is the SCREEN; `.sm-av-mapart` is the artwork inside it.
 * ------------------------------------------------------------------------ */
.sm-av-mapart {
  position: relative;
  flex: 1 1 auto;
  min-height: 210px;
  border: 1px solid var(--sm-border);
  border-radius: var(--sm-radius);
  overflow: hidden;
  background: #07101a;
  box-shadow: inset 0 0 70px rgba(0, 0, 0, 0.8);
}
/* The land, the sea and the terrain are DRAWN — see drawMapArt() in advui.js.
   Everything else on this screen is DOM on top of that one canvas. */
.sm-av-map-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}
/* THE SURVEY LAMP. One soft light drifting across the plate — the only
   ambient motion on this screen. Transform-only (compositor-bound, never a
   repaint), and it sits UNDER the region labels and pins by DOM order. */
.sm-av-maplight {
  position: absolute;
  left: -35%;
  top: -35%;
  width: 170%;
  height: 170%;
  pointer-events: none;
  background: radial-gradient(42% 34% at 38% 40%,
    rgba(255, 236, 190, 0.075),
    rgba(255, 236, 190, 0.028) 55%,
    rgba(0, 0, 0, 0) 72%);
  animation: sm-av-lamp 26s ease-in-out infinite alternate;
}
@keyframes sm-av-lamp {
  0%   { transform: translate3d(-6%, -4%, 0); }
  100% { transform: translate3d(7%, 5%, 0); }
}
/* Screens hide with opacity/visibility, not display — pause the ambience
   whenever the map is not the screen that is up, or the lamp and the pin
   breathe tick through every mine run for the whole session. */
.sm-av-screen:not(.sm-av-screen-on) .sm-av-maplight,
.sm-av-screen:not(.sm-av-screen-on) .sm-av-pin-owned::after {
  animation-play-state: paused;
}
/* A paper-chart vignette over the artwork, so the edges of the plate darken
   instead of the coastline running into the border. */
.sm-av-mapart::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(120% 110% at 50% 45%, rgba(0,0,0,0) 55%, rgba(0,0,0,0.55) 100%);
}
.sm-av-map-empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--sm-mono);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 3px;
  color: var(--sm-dimmer);
}
.sm-av-regions, .sm-av-pins { position: absolute; inset: 0; }

/* The region box itself is now invisible: it exists to position the name and
   the reveal sweep over the drawn land. */
.sm-av-region {
  position: absolute;
  pointer-events: none;
  border-radius: 18px;
}
/* The name sits OUTSIDE the top of the region box. Inside it, a single-mine
   region puts the region name a few pixels above the mine name and the two
   read as one clump — which is exactly what the first draft of this screen
   did wrong. `overflow` is deliberately not hidden here either, or a long
   region name gets guillotined by a small island. */
.sm-av-region-label {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translate(-50%, -118%);
  font-family: var(--sm-mono);
  font-size: 8px;
  font-weight: 800;
  letter-spacing: 2.6px;
  color: rgba(222, 236, 250, 0.62);
  white-space: nowrap;
  text-shadow: 0 1px 3px #000, 0 0 8px #000;
}
/* Held ground is named in gold. Unsurveyed ground is named 'UNSURVEYED'. */
.sm-av-region-label.sm-av-region-held { color: var(--sm-gold); }
.sm-av-region-label.sm-av-region-fog {
  color: rgba(160, 176, 196, 0.55);
  letter-spacing: 3.4px;
  font-size: 7px;
}

/* THE SURVEY SWEEP. A new region joining the chart is the campaign's
   milestone — a bar of light crossing the new ground, once, on reveal.
   TWO elements, because the bar has to be CLIPPED TO THE LAND: an unclipped
   gradient over the region's bounding box reads as a bright rectangle sitting
   on the sea, which is what the first cut of this looked like. The ellipse is
   inset to roughly the coastline drawn on the canvas underneath. */
.sm-av-reveal {
  position: absolute;
  inset: 12%;
  border-radius: 50%;
  overflow: hidden;
  opacity: 0;
}
.sm-av-reveal::before {
  content: '';
  position: absolute;
  inset: -20% -70%;
  background:
    linear-gradient(105deg,
      rgba(255, 226, 140, 0) 40%,
      rgba(255, 240, 190, 0.62) 50%,
      rgba(255, 226, 140, 0) 60%);
}
.sm-av-reveal.sm-av-reveal-on {
  animation: sm-av-survey-fade 1.5s ease-in-out both;
  box-shadow: inset 0 0 22px rgba(255, 226, 140, 0.45);
}
.sm-av-reveal.sm-av-reveal-on::before {
  animation: sm-av-survey-sweep 1.5s cubic-bezier(0.35, 0.7, 0.25, 1) both;
}
@keyframes sm-av-survey-fade {
  0%   { opacity: 0; }
  14%  { opacity: 1; }
  76%  { opacity: 1; }
  100% { opacity: 0; }
}
@keyframes sm-av-survey-sweep {
  0%   { transform: translateX(-46%); }
  100% { transform: translateX(46%); }
}

/* A pin you own reads differently from one you can buy, and one you cannot
   afford differently again. */
.sm-av-pin {
  position: absolute;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 8px;
  background: none;
  border: 0;
  box-shadow: none;
  min-width: 0;
  min-height: 0;
  pointer-events: auto;
  cursor: pointer;
}
.sm-av-pin-dot {
  position: relative;      /* the rivet core and headframe anchor to the DOT */
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: var(--sm-dimmer);
  border: 2px solid rgba(0, 0, 0, 0.7);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.12);
  transition: transform 0.14s ease, box-shadow 0.14s ease;
}
.sm-av-pin-name {
  font-family: var(--sm-mono);
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 1.2px;
  color: var(--sm-dim);
  white-space: nowrap;
  text-shadow: 0 1px 3px #000, 0 0 6px #000;
}
.sm-av-pin-tag {
  font-family: var(--sm-mono);
  font-size: 7.5px;
  font-weight: 800;
  letter-spacing: 0.6px;
  color: var(--sm-dimmer);
  font-variant-numeric: tabular-nums;
}
/* What the ground IS: known mines carry their depth under the price... */
.sm-av-pin-sub {
  font-family: var(--sm-mono);
  font-size: 6.5px;
  font-weight: 800;
  letter-spacing: 1.4px;
  color: rgba(190, 205, 222, 0.55);
  text-shadow: 0 1px 3px #000;
  font-variant-numeric: tabular-nums;
}
/* ...and held mines carry the lift: how much of it the company has bought. */
.sm-av-pin-levels {
  width: 26px;
  height: 3px;
  margin-top: 1px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.16);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
  overflow: hidden;
}
.sm-av-pin-levels-fill {
  display: block;
  height: 100%;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--sm-gold), var(--sm-gold-hot));
}
/* THREE STATES, THREE SHAPES — not three shades of the same dot, because the
   difference between "mine", "for sale" and "not yet" has to survive a glance
   on a phone in daylight:
     OWNED        a solid gold rivet with a dark core, name in gold, tag HELD
     FOR SALE     a cyan DIAMOND, name in cyan, tag showing the price
     UNAFFORDABLE a hollow grey ring, dimmed, price still shown */
.sm-av-pin-owned .sm-av-pin-dot {
  background: radial-gradient(circle at 50% 40%, #fff3c4 0%, var(--sm-gold) 45%, #a97a06 100%);
  box-shadow: 0 0 14px rgba(255, 194, 31, 0.75), 0 0 0 1px rgba(0, 0, 0, 0.7);
}
.sm-av-pin-owned .sm-av-pin-dot::after {
  content: '';
  position: absolute;
  inset: 4px;
  border-radius: 50%;
  background: rgba(30, 20, 0, 0.65);
}
/* The headframe: the A-frame over the shaft, the universal "working mine"
   silhouette, raised over the rivet. */
.sm-av-pin-owned .sm-av-pin-dot::before {
  content: '';
  position: absolute;
  left: 50%;
  top: -8px;
  width: 0;
  height: 0;
  margin-left: -5px;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-bottom: 8px solid var(--sm-gold);
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.8));
}
.sm-av-pin-owned .sm-av-pin-name { color: var(--sm-gold-hot); }
.sm-av-pin-owned .sm-av-pin-tag { color: var(--sm-gold); letter-spacing: 1.6px; }
/* A slow breathe on held ground — opacity only, so it never repaints. */
.sm-av-pin-owned::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 14.5px;
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle, rgba(255, 194, 31, 0.5), rgba(255, 194, 31, 0) 70%);
  opacity: 0.3;
  animation: sm-av-breathe 3.6s ease-in-out infinite alternate;
}
@keyframes sm-av-breathe {
  0%   { opacity: 0.12; }
  100% { opacity: 0.5; }
}

.sm-av-pin-buy .sm-av-pin-dot {
  background: linear-gradient(180deg, var(--sm-cyan-hot), var(--sm-cyan) 55%, #2597c4);
  border-radius: 2px;
  transform: rotate(45deg);
  box-shadow: 0 0 14px rgba(102, 226, 255, 0.65), 0 0 0 1px rgba(0, 0, 0, 0.7);
}
.sm-av-pin-buy .sm-av-pin-name { color: var(--sm-cyan-hot); }
.sm-av-pin-buy .sm-av-pin-tag { color: var(--sm-cyan); }

.sm-av-pin-far { opacity: 0.72; }
.sm-av-pin-far .sm-av-pin-dot {
  background: rgba(10, 14, 20, 0.6);
  border-color: rgba(150, 165, 185, 0.7);
}
/* On unsurveyed ground a pin is a rumour: no colour, no name, no price. */
.sm-av-pin-fog { opacity: 0.5; }
.sm-av-pin-fog .sm-av-pin-dot {
  background: rgba(8, 11, 16, 0.8);
  border-color: rgba(150, 170, 200, 0.45);
  border-style: dashed;
  transform: none;
  border-radius: 50%;
  box-shadow: none;
}
.sm-av-pin-fog .sm-av-pin-dot::after { display: none; }
.sm-av-pin-fog .sm-av-pin-name { color: rgba(170, 186, 206, 0.6); letter-spacing: 1.8px; }
.sm-av-pin-fog .sm-av-pin-tag { color: rgba(170, 186, 206, 0.5); }
/* Fogged ground leaks NOTHING: no depth, no lift bar, no headframe, no glow —
   JS blanks these too, but the fog class is the belt to that braces. */
.sm-av-pin-fog .sm-av-pin-sub,
.sm-av-pin-fog .sm-av-pin-levels,
.sm-av-pin-fog .sm-av-pin-dot::before,
.sm-av-pin-fog::after { display: none !important; }

.sm-av-pin-sel .sm-av-pin-dot { transform: scale(1.5); }
.sm-av-pin-buy.sm-av-pin-sel .sm-av-pin-dot { transform: rotate(45deg) scale(1.5); }
.sm-av-pin-sel::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 8px;
  width: 34px;
  height: 34px;
  margin: -10px 0 0 -17px;
  border: 1px solid rgba(255, 255, 255, 0.4);
  border-radius: 50%;
  animation: sm-av-ping 1.9s ease-out infinite;
}
@keyframes sm-av-ping {
  0%   { transform: scale(0.5); opacity: 0.9; }
  100% { transform: scale(1.35); opacity: 0; }
}

.sm-av-minecard {
  flex: 0 0 auto;
  padding: 11px 12px 12px;
  display: none;
}
.sm-av-minecard.sm-av-minecard-on { display: block; }

/* ---------------------------------------------------------------------------
 * GARAGE
 * ------------------------------------------------------------------------ */
.sm-av-rig {
  position: relative;
  flex: 1 1 auto;
  min-height: 210px;
  border: 1px solid var(--sm-border);
  border-radius: var(--sm-radius);
  overflow: hidden;
  box-shadow: inset 0 0 50px rgba(0, 0, 0, 0.7);
}
.sm-av-rig-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.sm-av-hots { position: absolute; inset: 0; }
.sm-av-hot {
  position: absolute;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 7px;
  background: none;
  border: 0;
  box-shadow: none;
  min-width: 0;
  min-height: 0;
  pointer-events: auto;
  cursor: pointer;
}
.sm-av-hot-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: rgba(18, 22, 28, 0.9);
  border: 2px solid rgba(180, 200, 220, 0.6);
  box-shadow: 0 0 8px rgba(0, 0, 0, 0.8);
  transition: transform 0.14s ease, border-color 0.14s ease, background 0.14s ease;
}
.sm-av-hot-lbl {
  font-family: var(--sm-mono);
  font-size: 7px;
  font-weight: 800;
  letter-spacing: 1.4px;
  color: var(--sm-dim);
  text-shadow: 0 1px 3px #000, 0 0 6px #000;
  white-space: nowrap;
}
.sm-av-hot-lv {
  font-family: var(--sm-mono);
  font-size: 7px;
  font-weight: 800;
  letter-spacing: 0.8px;
  color: var(--sm-gold);
  text-shadow: 0 1px 3px #000;
}
/* Affordable upgrades announce themselves ON the machine. */
.sm-av-hot-buy .sm-av-hot-dot {
  border-color: var(--sm-cyan);
  background: rgba(20, 70, 92, 0.9);
  box-shadow: 0 0 12px rgba(102, 226, 255, 0.55);
}
.sm-av-hot-max .sm-av-hot-dot { border-color: rgba(255, 194, 31, 0.75); background: rgba(70, 52, 8, 0.9); }
.sm-av-hot-sel .sm-av-hot-dot { transform: scale(1.45); border-color: #fff; }
.sm-av-hot-sel .sm-av-hot-lbl { color: var(--sm-text); }

.sm-av-part { flex: 0 0 auto; padding: 11px 12px 12px; }
.sm-av-pips { display: flex; gap: 4px; margin-top: 9px; }
.sm-av-pip {
  width: 22px;
  height: 5px;
  border-radius: 1px;
  background: rgba(255, 255, 255, 0.10);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
.sm-av-pip.sm-av-pip-on {
  background: linear-gradient(180deg, var(--sm-gold-hot), var(--sm-gold));
  box-shadow: 0 0 8px rgba(255, 194, 31, 0.5);
}

/* ---------------------------------------------------------------------------
 * PREP
 * ------------------------------------------------------------------------ */
.sm-av-prep-mine, .sm-av-prep-lift {
  flex: 0 0 auto;
  padding: 11px 12px 12px;
}
.sm-av-strata { margin-top: 9px; display: flex; flex-direction: column; gap: 3px; }
.sm-av-stratum {
  display: grid;
  grid-template-columns: 10px 1fr 74px 1fr;
  align-items: center;
  gap: 8px;
  height: 21px;
  padding: 0 7px;
  background: rgba(10, 13, 17, 0.55);
  border-radius: 2px;
  font-family: var(--sm-mono);
}
.sm-av-stratum-sw {
  width: 8px;
  height: 8px;
  border-radius: 1px;
  background: var(--sm-av-chip, #8e9bab);
  box-shadow: 0 0 6px var(--sm-av-chip, #8e9bab);
}
.sm-av-stratum-name {
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 1.4px;
  color: var(--sm-text);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.sm-av-stratum-depth {
  font-size: 8.5px;
  font-weight: 800;
  color: var(--sm-dim);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.sm-av-stratum-ore {
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.8px;
  color: var(--sm-gold);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* ---------------------------------------------------------------------------
 * THE LEVEL PICKER  (and the fuel widget that used to be here)
 * ---------------------------------------------------------------------------
 * The fuel slider is GONE, along with EMPTY / HALF / FILL THE TANK and the line
 * of arithmetic under them — about seventy lines of stylesheet for a control
 * that only ever had one correct setting. The descent buys the tank out and
 * DESCEND carries the bill.
 *
 * What takes its place is the decision that IS worth a panel: which station the
 * lift drops you at. Rows, not cells, because they are a list of places in
 * depth order and the order is the whole point — the shaft reads top to bottom
 * exactly as it is dug.
 *
 * A row is `[grid] tag | name | depth | state`, and it negotiates: the NAME
 * yields (min-width: 0, ellipsis) and the two numbers never do. Every other box
 * in this file learned that lesson on real Android, where --sm-mono resolves to
 * a font wider than SF Mono at the same px size; tuning a column to the metrics
 * of one font is how a picker that looks perfect here clips "GRANITE FLOOR" to
 * "GRANI…" there.
 * ------------------------------------------------------------------------ */
.sm-av-levels {
  margin-top: 9px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.sm-av-level {
  display: flex;
  align-items: stretch;
  gap: 6px;
  min-width: 0;
}
/* The row's own body: everything except BUY, and the whole of it is the tap
   target for riding/selecting. */
.sm-av-level-go {
  flex: 1 1 auto;
  min-width: 0;
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 9px;
  min-height: 34px;
  padding: 0 9px;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-left: 3px solid rgba(126, 140, 158, 0.35);
  border-radius: 3px;
  background: rgba(10, 13, 17, 0.6);
  font-family: var(--sm-mono);
  color: var(--sm-text);
  text-align: left;
  cursor: pointer;
}
.sm-av-level-go:hover { background: rgba(30, 38, 48, 0.72); }
.sm-av-level-i {
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 1.2px;
  color: var(--sm-dimmer);
  font-variant-numeric: tabular-nums;
}
.sm-av-level-name {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 1.4px;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.sm-av-level-depth {
  font-size: 10px;
  font-weight: 800;
  color: var(--sm-dim);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.sm-av-level-tag {
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 1.4px;
  color: var(--sm-dimmer);
  min-width: 40px;
  text-align: right;
  white-space: nowrap;
}

/* HELD ground is live and green-edged; the SELECTED one wears the gold plate,
   because it is the one the DESCEND button is about to act on. */
.sm-av-level-owned .sm-av-level-go { border-left-color: var(--sm-green); }
.sm-av-level-owned .sm-av-level-tag { color: var(--sm-green); }
.sm-av-level-sel .sm-av-level-go {
  border-color: rgba(255, 240, 168, 0.45);
  border-left-color: var(--sm-gold);
  background: linear-gradient(90deg, rgba(90, 66, 8, 0.55), rgba(14, 18, 24, 0.6) 70%);
}
.sm-av-level-sel .sm-av-level-tag { color: var(--sm-gold); }
.sm-av-level-sel .sm-av-level-name { color: #fff3cf; }

/* The one purchasable station: gold price, and its own BUY beside it. */
.sm-av-level-next .sm-av-level-go {
  border-left-color: var(--sm-gold);
  cursor: default;
}
.sm-av-level-next .sm-av-level-go:hover { background: rgba(10, 13, 17, 0.6); }
.sm-av-level-next .sm-av-level-tag { color: var(--sm-gold); }
.sm-av-level-next .sm-av-level-name { color: var(--sm-text); }

/* Ground below it is not for sale at any price — a shaft is cut downwards. */
.sm-av-level-locked .sm-av-level-go {
  cursor: default;
  opacity: 0.42;
  border-left-color: rgba(126, 140, 158, 0.2);
}
.sm-av-level-locked .sm-av-level-go:hover { background: rgba(10, 13, 17, 0.6); }

/* BUY is a real plate, sized to the row rather than to the footer. */
.sm-btn.sm-av-level-buy {
  flex: 0 0 auto;
  min-height: 34px;
  min-width: 58px;
  padding: 0 12px;
  font-size: 9px;
  letter-spacing: 1.6px;
  margin: 0;
}

/* Where the descent starts, and — when BUY is greyed — why. `pre-line` because
   the reason is written on its own line under the selection. */
.sm-av-lift-note {
  margin-top: 9px;
  white-space: pre-line;
}

/* ---------------------------------------------------------------------------
 * THE HULL, WHEN IT IS BROKEN
 * ---------------------------------------------------------------------------
 * One row, and only present under 100%. It used to be a full panel with a
 * heading, a percentage, a bar and a button, which on most visits was four
 * pieces of furniture around the word "fine".
 *
 * The bar is the flexible column and the two numbers and the button are not, so
 * a wider font eats the bar rather than the reading — the same negotiation the
 * level rows and the in-mine info bar use.
 * ------------------------------------------------------------------------ */
.sm-av-repair {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px 9px;
}
.sm-av-repair-lbl {
  font-family: var(--sm-mono);
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 2.4px;
  color: var(--sm-dimmer);
  flex: 0 0 auto;
}
.sm-av-repair-pct {
  font-family: var(--sm-mono);
  font-size: 15px;
  font-weight: 800;
  color: var(--sm-text);
  font-variant-numeric: tabular-nums;
  flex: 0 0 auto;
}
.sm-av-repair-bar {
  flex: 1 1 auto;
  min-width: 24px;
  margin: 0;
}
.sm-btn.sm-av-repair-btn {
  flex: 0 0 auto;
  min-height: 34px;
  min-width: 96px;
  padding: 0 12px;
  font-size: 9px;
  letter-spacing: 1.4px;
  margin: 0;
}
.sm-av-repair.sm-av-repair-bad .sm-av-repair-pct { color: var(--sm-red); }

.sm-av-bar {
  position: relative;
  height: 10px;
  margin: 9px 0 10px;
  border-radius: 3px;
  background: linear-gradient(180deg, rgba(0, 0, 0, 0.72), rgba(0, 0, 0, 0.5));
  border: 1px solid rgba(255, 255, 255, 0.07);
  overflow: hidden;
}
.sm-av-bar-fill {
  position: absolute;
  inset: 0;
  transform-origin: left center;
  transform: scaleX(var(--sm-av-fill, 0));
  background: linear-gradient(90deg, var(--sm-green), #d8ffe6);
}
.sm-av-bar-fill.sm-av-bar-bad { background: linear-gradient(90deg, var(--sm-red), #ffc7bf); }

/* ===========================================================================
 * THE DESCEND BUTTON'S LOOK — ON EVERY ADVENTURE BUTTON
 * ---------------------------------------------------------------------------
 * The gold plate with the hazard stripe started as DESCEND's own treatment, and
 * it is the one this machinery deserves, so it is now the default for the whole
 * mode. That deliberately flattens the colour hierarchy: `sm-btn-primary` stops
 * meaning "cyan" and just means "the one you probably want", with emphasis
 * carried by SIZE (`sm-btn-big`) and position instead of hue.
 *
 * `.sm-iconbtn` is excluded on purpose — sound and pause are small square glyph
 * plates, and a gold hazard-striped speaker reads as a warning, not a toggle.
 * ======================================================================== */
.sm-adv .sm-btn:not(.sm-iconbtn) {
  color: #150b02;
  background: linear-gradient(180deg, #ffd979, var(--sm-gold) 45%, #c98a06 100%);
  border-color: rgba(255, 240, 168, 0.6);
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.30);
  overflow: hidden;
}
.sm-adv .sm-btn:not(.sm-iconbtn)::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: var(--sm-hazard);
  opacity: 0.9;
}

/* --- UNAVAILABLE = GREYED OUT, never renamed ----------------------------
 * There was no disabled styling in this mode at all, which is exactly why
 * buttons used to rename themselves ("BANKED", "TANK FULL") to say they had
 * nothing left to do. A control whose text changes under your thumb is harder
 * to learn than one that is simply dim, so the label now stays put and this
 * does the talking. */
.sm-adv .sm-btn:not(.sm-iconbtn):disabled,
.sm-adv .sm-btn:not(.sm-iconbtn)[disabled] {
  filter: grayscale(0.9) brightness(0.62);
  opacity: 0.5;
  cursor: default;
  pointer-events: none;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    0 2px 6px rgba(0, 0, 0, 0.45);
}
.sm-adv .sm-btn:not(.sm-iconbtn):disabled::before,
.sm-adv .sm-btn:not(.sm-iconbtn)[disabled]::before {
  opacity: 0.25;
}

/* --- and the ONE button that opts out of it ----------------------------
 * THE WAY OUT — "Back to arcade", on the title and at the foot of the pause
 * card — is the one control here that is not the game: it leaves. The hub
 * makes it the same object in every cabinet (CLAUDE.md §2, "One button, and
 * it looks and behaves the same in every game"), so both copies share this
 * one look: SECONDARY, which in this game means the plate's shape and the
 * mine's gold as an outline on the dark it sits on, never the filled gold
 * hazard plate every other button wears. Leaving is never the recommended
 * action, and a filled plate in the title's column would shout as loudly as
 * PLAY. No hazard sliver either: that stripe says "machinery", and a door is
 * not machinery.
 *
 * It lives HERE rather than beside its geometry in style.css because the rule
 * above is `.sm-adv .sm-btn:not(.sm-iconbtn)` — three classes, in the later of
 * the two stylesheets — so a colour written in style.css never gets a look in.
 * `.sm-adv .sm-btn.sm-start-quit` ties on specificity and wins on order. The
 * pause card's copy used to be styled at two classes in §3 and lost that tie
 * outright — it was drawn as a full gold plate, the loudest thing on the card,
 * under a comment calling it the quietest. This is where it is styled now. */
.sm-adv .sm-btn.sm-start-quit,
.sm-adv .sm-btn.sm-ah-quit {
  color: rgba(255, 194, 31, 0.88);
  background: transparent;
  border: 1px solid rgba(255, 194, 31, 0.36);
  border-radius: 4px;
  box-shadow: none;
  text-shadow: none;
  font-size: 12px;
  letter-spacing: 0.4px;
  text-indent: 0;
}
.sm-adv .sm-btn.sm-start-quit::before,
.sm-adv .sm-btn.sm-ah-quit::before { content: none; }
.sm-adv .sm-btn.sm-start-quit:hover:not(:disabled),
.sm-adv .sm-btn.sm-start-quit:focus-visible,
.sm-adv .sm-btn.sm-ah-quit:hover:not(:disabled),
.sm-adv .sm-btn.sm-ah-quit:focus-visible {
  color: var(--sm-gold);
  border-color: rgba(255, 194, 31, 0.66);
  background: rgba(255, 194, 31, 0.07);
}
/* Armed (the pause card's copy is two-tap, because quitting mid-descent drops
   the hold exactly as aborting does): the same outline, in the abort red. */
.sm-adv .sm-btn.sm-ah-quit.sm-ah-armed,
.sm-adv .sm-btn.sm-menu-quit.sm-ah-armed {
  color: #ffd8d2;
  border-color: rgba(255, 90, 72, 0.6);
  background: rgba(255, 90, 72, 0.16);
}
/* The adventure-wide disabled rule greys a GOLD plate; this one is already
   dark, so it says its piece in the text instead. */
.sm-adv .sm-btn.sm-start-quit:disabled,
.sm-adv .sm-btn.sm-ah-quit:disabled {
  filter: none;
  opacity: 1;
  color: var(--sm-dimmer);
  border-color: var(--sm-border);
}
/* As wide as PLAY at every size: the generic compact and tiny button rules in
   style.css shrink every word-button for the mine's crowded controls, and
   PLAY's own overrides there put it back; these are the door's. */
.sm-adv.sm-compact .sm-btn.sm-start-quit {
  min-width: min(300px, 78vw);
  min-height: 44px;
  padding: 10px 18px;
  font-size: 12px;
  letter-spacing: 0.4px;
}
.sm-adv.sm-tiny .sm-btn.sm-start-quit { min-width: min(280px, 84vw); }

/* DESCEND keeps its own rule as the canonical source of the treatment above. */
.sm-btn.sm-av-descend {
  color: #150b02;
  background: linear-gradient(180deg, #ffd979, var(--sm-gold) 45%, #c98a06 100%);
  border-color: rgba(255, 240, 168, 0.6);
  overflow: hidden;
}
.sm-btn.sm-av-descend::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: var(--sm-hazard);
  opacity: 0.9;
}

/* ---------------------------------------------------------------------------
 * RESULTS — the payoff
 * ------------------------------------------------------------------------ */
.sm-av-res { flex: 0 0 auto; padding: 13px 14px 14px; }
.sm-av-res-headline {
  font-family: var(--sm-font);
  font-size: 12px;
  line-height: 1.6;
  color: var(--sm-dim);
}
.sm-av-res-hero {
  margin: 11px 0 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-radius: 4px;
  text-align: center;
}
.sm-av-res-hero-label {
  font-family: var(--sm-mono);
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 3px;
  text-indent: 3px;
  color: var(--sm-gold);
}
.sm-av-res-total {
  font-family: var(--sm-mono);
  font-size: clamp(30px, 11vw, 46px);
  font-weight: 800;
  line-height: 1.05;
  color: var(--sm-gold-hot);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 3px 0 #000, 0 0 28px rgba(255, 194, 31, 0.4);
  margin-top: 2px;
}
.sm-av-res-total-pop { animation: sm-av-pop 0.42s cubic-bezier(0.2, 1.5, 0.4, 1); }
@keyframes sm-av-pop {
  0% { transform: scale(1); }
  40% { transform: scale(1.09); }
  100% { transform: scale(1); }
}
.sm-av-res-lines { display: flex; flex-direction: column; gap: 3px; }
.sm-av-res-row {
  display: flex;
  align-items: center;
  gap: 9px;
  height: 26px;
  padding: 0 9px;
  background: rgba(10, 13, 17, 0.6);
  border-radius: 2px;
  border-left: 3px solid var(--sm-av-chip, #8e9bab);
  font-family: var(--sm-mono);
  opacity: 0;
  transform: translateX(-9px);
}
/* Each line lands in turn — the count-up in advui.js adds this class as that
   row's number starts rolling. */
.sm-av-res-row.sm-av-res-row-in {
  animation: sm-av-row-in 0.34s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes sm-av-row-in {
  from { opacity: 0; transform: translateX(-9px); }
  to   { opacity: 1; transform: none; }
}
.sm-av-res-sw {
  width: 9px;
  height: 9px;
  border-radius: 1px;
  background: var(--sm-av-chip, #8e9bab);
  box-shadow: 0 0 7px var(--sm-av-chip, #8e9bab);
  flex: 0 0 auto;
}
.sm-av-res-name {
  flex: 1 1 auto;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 1.4px;
  color: var(--sm-text);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.sm-av-res-units {
  font-size: 9.5px;
  font-weight: 800;
  color: var(--sm-dim);
  font-variant-numeric: tabular-nums;
}
.sm-av-res-val {
  min-width: 82px;
  text-align: right;
  font-size: 13px;
  font-weight: 800;
  color: var(--sm-gold);
  font-variant-numeric: tabular-nums;
}
.sm-av-res-empty {
  font-family: var(--sm-mono);
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 2px;
  color: var(--sm-dimmer);
  padding: 10px 0;
  text-align: center;
}
/* A strand is a different screen wearing the same bones. */
.sm-av-res-strand .sm-av-kicker { color: var(--sm-red); }
.sm-av-res-strand .sm-av-res-hero {
  background: linear-gradient(180deg, rgba(255, 90, 72, 0.16), rgba(0, 0, 0, 0.5));
  border-color: rgba(255, 90, 72, 0.42);
}
.sm-av-res-strand .sm-av-res-hero-label { color: var(--sm-red); }
.sm-av-res-strand .sm-av-res-hero-label::after { content: ' — LOST'; }
.sm-av-res-strand .sm-av-res-hero-label:lang(nb)::after { content: ' — TAPT'; }
.sm-av-res-strand .sm-av-res-total { color: #ffb3a8; text-shadow: 0 3px 0 #000, 0 0 28px rgba(255, 90, 72, 0.35); }
.sm-av-res-strand .sm-av-res-val { color: #ffb3a8; }

/* ...EXCEPT WHEN THE HERO IS THE MONEY YOU KEPT.
   A strand's big number is the SECURED ledger whenever the run deposited
   anything — that is the payout, not a loss — and the strand dress would
   otherwise print "SECURED — LOST" over it and turn a green figure red. advui.js
   puts this class on the card when the hero is the secured total; everything
   else about the strand's dress stays. */
.sm-av-res-strand.sm-av-res-kept .sm-av-res-hero-label { color: var(--sm-green); }
.sm-av-res-strand.sm-av-res-kept .sm-av-res-hero-label::after { content: ' — BANKABLE'; }
.sm-av-res-strand.sm-av-res-kept .sm-av-res-hero-label:lang(nb)::after { content: ' — KAN SETTES INN'; }
.sm-av-res-strand.sm-av-res-kept .sm-av-res-hero {
  background: linear-gradient(180deg, rgba(88, 224, 138, 0.14), rgba(0, 0, 0, 0.5));
  border-color: rgba(88, 224, 138, 0.42);
}
.sm-av-res-strand.sm-av-res-kept .sm-av-res-total {
  color: #d8ffe6;
  text-shadow: 0 3px 0 #000, 0 0 28px rgba(88, 224, 138, 0.3);
}
.sm-av-res-strand.sm-av-res-kept .sm-av-res-val { color: #d8ffe6; }
.sm-av-res-strand .sm-stripe { background: linear-gradient(90deg, var(--sm-red), #7a1d13); }

/* --- the toast -------------------------------------------------------- */
.sm-av-toast {
  position: absolute;
  left: 50%;
  bottom: 92px;
  transform: translateX(-50%) translateY(10px);
  min-width: 230px;
  max-width: min(420px, 88vw);
  padding: 9px 18px 10px;
  text-align: center;
  background: linear-gradient(180deg, rgba(28, 34, 42, 0.95), rgba(12, 15, 19, 0.96));
  border: 1px solid rgba(255, 194, 31, 0.45);
  border-radius: 4px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.22s ease, transform 0.28s cubic-bezier(0.16, 1, 0.3, 1);
  z-index: 19;
}
.sm-av-toast.sm-av-toast-on { opacity: 1; transform: translateX(-50%) translateY(0); }
.sm-av-toast-title {
  font-family: var(--sm-mono);
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 2.6px;
  text-indent: 2.6px;
  color: var(--sm-gold-hot);
}
.sm-av-toast-sub {
  font-family: var(--sm-mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.2px;
  color: var(--sm-dim);
  margin-top: 3px;
}

/* ===========================================================================
 * 5. RESPONSIVE
 * ---------------------------------------------------------------------------
 * ui.js already publishes .sm-compact / .sm-portrait / .sm-tiny on #ui-root on
 * every resize, for both modes, so adventure mode reuses those switches rather
 * than inventing a second set of breakpoints.
 * ======================================================================== */

/* --- WIDE: two columns, so nothing has to scroll at all ---------------- */
@media (min-width: 760px) {
  .sm-adv .sm-ah-strip { padding-right: 12px; }
  .sm-adv .sm-av { padding-left: max(var(--sm-gutter), 3vw); padding-right: max(var(--sm-gutter), 3vw); }
  .sm-adv .sm-av-foot { justify-content: flex-end; }
  .sm-adv .sm-av-foot .sm-btn { flex: 0 1 200px; }
  .sm-adv .sm-av-foot .sm-btn-big { flex: 0 1 320px; }

  /* MAP and GARAGE become side-by-side: the artwork on the left, the card on
     the right, and neither one scrolls the other out of view. */
  .sm-adv .sm-av-map > .sm-av-body,
  .sm-adv .sm-av-garage > .sm-av-body {
    flex-direction: row;
    align-items: flex-start;         /* the card hugs its content, not the frame */
    overflow: hidden;                /* each column scrolls itself */
  }
  .sm-adv .sm-av-mapart,
  .sm-adv .sm-av-rig { flex: 1 1 58%; min-height: 0; align-self: stretch; }
  .sm-adv .sm-av-minecard,
  .sm-adv .sm-av-part {
    flex: 0 0 384px;
    min-height: 0;
    max-height: 100%;
    overflow-y: auto;
  }

  /* THE SINGLE-COLUMN SCREENS GET A COLUMN, NOT A WALL.
     Slots, prep and results are lists of rows; stretched across 1440 px the
     label ends up a foot away from its value and a manifest line reads as two
     unrelated numbers. Cap them and centre them — footer included, so the
     primary button stays directly under the card it belongs to. */
  .sm-adv .sm-av-slots > .sm-av-body > *,
  .sm-adv .sm-av-prep > .sm-av-body > *,
  .sm-adv .sm-av-results > .sm-av-body > *,
  .sm-adv .sm-av-slots > .sm-av-foot,
  .sm-adv .sm-av-prep > .sm-av-foot,
  .sm-adv .sm-av-results > .sm-av-foot {
    width: 100%;
    max-width: 720px;
    margin-left: auto;
    margin-right: auto;
  }
  /* Centre the three slots in the empty height rather than pinning them to the
     top of a very tall screen. Auto margins, not justify-content: a scrolling
     flex column with centred content clips its first child when it overflows. */
  .sm-adv .sm-av-slots > .sm-av-body > .sm-av-slot:first-child { margin-top: auto; }
  .sm-adv .sm-av-slots > .sm-av-body > .sm-av-slot:last-child { margin-bottom: auto; }
  /* CONTINUE / NEW COMPANY does not need to be a metre wide. */
  .sm-adv .sm-av-slot-acts .sm-btn { flex: 0 1 260px; }
  .sm-adv .sm-av-slot-acts { justify-content: flex-start; }
  .sm-adv .sm-av-title { font-size: 26px; }
  .sm-adv .sm-av-pin-name { font-size: 9.5px; }
  .sm-adv .sm-av-hot-lbl { font-size: 8px; }
}

/* --- COMPACT (phone landscape, small windows) -------------------------- */
.sm-adv.sm-compact .sm-ah { gap: 5px; max-width: 460px; }
.sm-adv.sm-compact .sm-ah-strip { min-height: 38px; padding: 5px 10px 6px; }
.sm-adv.sm-compact .sm-ah-val { font-size: 15px; }
.sm-adv.sm-compact .sm-ah-fuel-pct { font-size: 26px; }
.sm-adv.sm-compact .sm-ah-fuel { padding: 6px 10px 8px; }
.sm-adv.sm-compact .sm-ah-cargo { padding: 6px 10px 7px; }
.sm-adv.sm-compact .sm-ah-mrow { height: 17px; }
.sm-adv.sm-compact .sm-av { gap: 6px; }
.sm-adv.sm-compact .sm-av-title { font-size: 18px; letter-spacing: 2.6px; }
/* padding-right restated, because the shorthand above it would otherwise put
   the cash back under the corner plates — see the base rule. */
.sm-adv.sm-compact .sm-av-ledger {
  min-height: 34px;
  padding: 4px 10px 5px;
  padding-right: calc(var(--sm-btn-size) * 2 + 18px);
}
.sm-adv.sm-compact .sm-av-led-cash { font-size: 15px; }
.sm-adv.sm-compact .sm-av-slot { padding: 8px 10px 9px; }
.sm-adv.sm-compact .sm-av-slot-stats { margin: 7px 0 8px; }
.sm-adv.sm-compact .sm-av-res { padding: 10px 11px 11px; }

/* Phone landscape has almost no vertical room: collapse the strata report and
   the machine blurb rather than let the primary button drift off-screen. */
@media (max-height: 520px) and (orientation: landscape) {
  .sm-adv .sm-av-strata { display: none; }
  .sm-adv .sm-av-card-blurb { display: none; }
  .sm-adv .sm-av-res-hero { margin: 8px 0 8px; padding: 7px 10px 8px; }
  .sm-adv .sm-av-title { font-size: 16px; }
  /* The manifest is NOT hidden here any more — see revision 2's note on the
     hold box. It is capped and scrollable instead, so the whole hold is
     always reachable even on a 520 px-tall landscape phone. */
  .sm-adv .sm-ah-manifest { max-height: 84px; overflow-y: auto; }
}

/* THE COMPANY SLOTS ON A PHONE ON ITS SIDE (hub CLAUDE.md §2: a menu must not
   scroll on a landscape phone). Stacked, three companies come to ~420px of
   rows against the ~280 a 390px-tall phone leaves between title and footer,
   so the third company sat half under the fold and was reached only by a
   scroll nobody expects on a picker. Sideways there is width to spare and no
   height, so this is maxgear's shape: the same three cards stood side by side
   as three equal columns, nothing moved in the DOM. The cards are peers, so
   they share one size (the equal rule); their four figures go two by two to
   fit a third of the glass. Placed after the wide block on purpose — at
   844x390 both match, and this must undo its centring auto margins and its
   720px cap, or the three columns would huddle in the middle of the screen.
   The body's overflow stays behind it as the safety net, not the plan. */
@media (orientation: landscape) and (max-height: 500px) {
  .sm-adv .sm-av-slots > .sm-av-body {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
    align-content: start;
  }
  /* :first-child and :last-child named outright, because the wide block's
     auto margins carry them and would otherwise win the specificity tie —
     leaving the third card at its natural height beside two stretched ones. */
  .sm-adv .sm-av-slots > .sm-av-body > .sm-av-slot,
  .sm-adv .sm-av-slots > .sm-av-body > .sm-av-slot:first-child,
  .sm-adv .sm-av-slots > .sm-av-body > .sm-av-slot:last-child {
    max-width: none;
    margin: 0;
  }
  .sm-adv .sm-av-slots > .sm-av-foot { max-width: none; }
  .sm-adv .sm-av-slot-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .sm-adv .sm-av-slot-acts .sm-btn { flex: 1 1 0; }
  .sm-adv .sm-av-slot-acts .sm-av-quiet { flex: 0 0 88px; }
}

/* --- PORTRAIT (the default phone case) --------------------------------- */
.sm-adv.sm-portrait .sm-ah { max-width: none; }
/* The plate itself needs the height floor: .sm-av-map is the absolutely
   positioned SCREEN (inset 0), so a min-height there was a no-op. */
.sm-adv.sm-portrait .sm-av-mapart { min-height: 34vh; }
.sm-adv.sm-portrait .sm-av-rig { min-height: 30vh; }
.sm-adv.sm-portrait .sm-av-slot-stats { grid-template-columns: repeat(2, 1fr); }
.sm-adv.sm-portrait .sm-av-toast { bottom: 108px; }
/* The joystick's throw is a thumb rotation, not a screen fraction, so it does
   not scale with the viewport — but the base does get a touch smaller on a
   phone so it covers less of the rock. */
.sm-adv.sm-portrait .sm-stick-base { opacity: 0; }
.sm-adv.sm-portrait .sm-stick-base.sm-stick-on { opacity: 0.44; }
.sm-adv.sm-portrait .sm-stick-base.sm-stick-hold { opacity: 0.86; }

/* --- TINY (narrow phones) ---------------------------------------------
 * The card grid deliberately stays TWO columns here. One column per cell was
 * tried and it pushed the material chips and the hazard line a whole screen
 * further down; the values are all short ('$18 000', '21+ YOURS 13') and two
 * 175 px cells hold them comfortably. */
.sm-adv.sm-tiny .sm-av-slot-stats { grid-template-columns: repeat(2, 1fr); }
.sm-adv.sm-tiny .sm-av-title { font-size: 16px; }
.sm-adv.sm-tiny .sm-ah-fuel-pct { font-size: 24px; }
.sm-adv.sm-tiny .sm-ah-strip { gap: 9px; }
/* The label is the whole point of a hotspot; it is the TIER BADGE that goes on
   a narrow screen. Eight tags reading "MK II" name nothing. */
.sm-adv.sm-tiny .sm-av-hot-lv { display: none; }
.sm-adv.sm-tiny .sm-av-hot-sel .sm-av-hot-lv { display: block; }
.sm-adv.sm-tiny .sm-av-hot-lbl { font-size: 6.5px; letter-spacing: 0.8px; }
/* Region washes stay; their LABELS collide with the pin names at this width,
   and the mine card names the region anyway. The depth sub-line goes with
   them — seven pins of three-line text is a wall on a narrow phone. */
.sm-adv.sm-tiny .sm-av-region-label { display: none; }
.sm-adv.sm-tiny .sm-av-pin-sub { display: none; }
.sm-adv.sm-tiny .sm-av-stratum { grid-template-columns: 10px 1fr 62px; }
.sm-adv.sm-tiny .sm-av-stratum-ore { display: none; }
.sm-adv.sm-tiny .sm-av-res-val { min-width: 66px; font-size: 12px; }

/* --- reduced motion --------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .sm-adv .sm-av-screen,
  .sm-adv .sm-av-res-row,
  .sm-adv .sm-stick-knob,
  .sm-adv .sm-ah-bar-fill,
  .sm-adv .sm-ah-mini-fill { transition: none; animation: none; }
  .sm-adv .sm-av-pin-sel::before,
  .sm-adv .sm-av-maplight,
  .sm-adv .sm-av-pin-owned::after,
  .sm-adv .sm-ah-fuel.sm-ah-crit { animation: none; }
  .sm-adv .sm-av-res-row { opacity: 1; transform: none; }
}

/* --- workshop: the pitch and the arithmetic (added with the real part table) */
.sm-av-sell { margin-top: 10px; }
.sm-av-delta { margin-top: 8px; letter-spacing: 1.4px; color: var(--sm-cyan); }

/* ===========================================================================
 * THE MINE CARD'S PROFILE ROW
 * ---------------------------------------------------------------------------
 * HEAT · GROUND · PAYS FOR, read off the layer table (see paintProfile()).
 * This is what makes two mines at the same price legibly different
 * propositions — one with no heat anywhere, one that is a gamble all the way
 * down — so the three cells are colour-coded rather than merely listed.
 * ======================================================================== */
.sm-av-profile {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}
.sm-av-prof {
  display: flex;
  align-items: baseline;
  gap: 6px;
  padding: 5px 9px 6px;
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-left: 3px solid var(--sm-dimmer);
  font-family: var(--sm-mono);
}
.sm-av-prof-label {
  font-size: 8px;
  font-weight: 800;
  letter-spacing: 2px;
  color: var(--sm-dimmer);
}
.sm-av-prof-value {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 1.4px;
  color: var(--sm-text);
}
.sm-av-prof-good { border-left-color: var(--sm-green); }
.sm-av-prof-good .sm-av-prof-value { color: var(--sm-green); }
.sm-av-prof-warn { border-left-color: var(--sm-gold); }
.sm-av-prof-warn .sm-av-prof-value { color: var(--sm-gold); }
.sm-av-prof-bad { border-left-color: var(--sm-red); }
.sm-av-prof-bad .sm-av-prof-value { color: #ff8f80; }
.sm-av-prof-ore { border-left-color: var(--sm-av-chip, var(--sm-gold)); }
.sm-av-prof-ore .sm-av-prof-value { color: var(--sm-av-chip, var(--sm-gold)); }

/* --- HOW FAR THE LIFT HAS BEEN CUT -------------------------------------
 * One line on the mine card, under the profile row. It is the difference
 * between a mine you have to climb out of and a mine with a station at the
 * bottom, which is the largest single difference between two entries in the
 * catalogue — and it costs one call to getLevels() to say. */
.sm-av-liftline {
  font-family: var(--sm-mono);
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 1.6px;
  color: var(--sm-gold);
  margin-top: 9px;
}

/* ===========================================================================
 * THE MOTHERLODE BANNER
 * The in-mine HUD's one celebration: hitting a real formation is the payoff
 * the whole mode is built to deliver, so the banner changes dress for it
 * instead of announcing it in the same amber as a low tank.
 * ======================================================================== */
.sm-ah-alert.sm-ah-alert-lode {
  background: linear-gradient(180deg, rgba(72, 54, 8, 0.94), rgba(28, 20, 4, 0.95));
  border-color: rgba(255, 214, 120, 0.85);
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.65), 0 0 26px rgba(255, 200, 90, 0.35);
}
.sm-ah-alert-lode .sm-ah-alert-title {
  color: #fff6d0;
  text-shadow: 0 2px 0 #000, 0 0 18px rgba(255, 210, 110, 0.75);
}
.sm-ah-alert-lode .sm-ah-alert-sub { color: #ffe6a8; }

/* ===========================================================================
 * 6. COMPACT HUD — REVISION 2: A TOP HALF-BAR AND A BOX OVER THE READOUT
 * ---------------------------------------------------------------------------
 * Revision 1 put FUEL and HOLD on two full-height edge rails. That did solve
 * the original problem — it cleared the top of the screen so the shaft and the
 * daylight at the mine mouth were visible while climbing out — but it solved it
 * too hard: a 48 px plate running the whole height of the glass is a lot of
 * furniture for one number, and it framed the playfield on both sides.
 *
 * So the instruments come back off the edges:
 *
 *   FUEL   returns to the TOP BAR, but only about HALF the width, running from
 *          the left gutter towards the sound and pause plates in the right
 *          corner. The other half of the top stays empty, and the machine is
 *          centred, so the shaft above it is still clear — which was the point
 *          of moving it in the first place.
 *   HOLD   becomes a compact translucent BOX sitting directly on top of the
 *          bottom readout line, over DEPTH and FUNDS. Translucent because it
 *          overlaps the rock and the readout beneath it; rectangular because it
 *          holds a fill bar and two numbers, not a column.
 *
 * Everything here RESETS the rail geometry explicitly rather than relying on
 * the earlier rules not applying, because they are still in the cascade above.
 * Both layouts remain the same DOM and the same guarded writes in advhud.js —
 * this is a stylesheet change and nothing else.
 * ======================================================================== */
.sm-adv.sm-compact {
  /* Height reserved for the hold box, so the scanner line clears it. */
  --sm-ah-hold-h: 42px;
}

/* --- FUEL: the top half-bar -------------------------------------------- */
.sm-adv.sm-compact .sm-ah-fuel {
  position: absolute;
  top: var(--sm-top-y);
  left: var(--sm-gutter);
  right: auto;
  bottom: auto;
  /* Stops well short of the icon plates in the right corner. */
  width: 52%;
  max-width: 300px;
  min-width: 168px;
  flex-direction: column;
  align-items: stretch;
  padding: 5px 9px 6px;
  border-radius: 5px;
  background: linear-gradient(180deg, rgba(9, 12, 17, 0.88), rgba(12, 16, 22, 0.66));
}

/* Label, percentage and state word back on ONE line, as they are when wide. */
.sm-adv.sm-compact .sm-ah-fuel .sm-ah-fuel-head {
  flex-direction: row;
  align-items: baseline;
  gap: 7px;
  width: auto;
  margin-bottom: 3px;
}
.sm-adv.sm-compact .sm-ah-fuel .sm-ah-fuel-pct {
  font-size: 17px;
  margin-top: 0;
}
.sm-adv.sm-compact .sm-ah-fuel .sm-ah-fuel-note {
  margin-top: 0;
  margin-left: auto;          /* the state word rides the right edge */
  font-size: 8.5px;
  text-align: right;
  line-height: 1.1;
}

/* --- HOLD: the box over the readout line -------------------------------- */
.sm-adv.sm-compact .sm-ah-cargo {
  position: absolute;
  left: var(--sm-gutter);
  right: auto;
  top: auto;
  /* Sits ON the readout line's own band, hence "over the counter". */
  bottom: var(--sm-ah-railbot);
  width: 52%;
  max-width: 300px;
  min-width: 168px;
  flex-direction: column;
  align-items: stretch;
  padding: 5px 9px 6px;
  border-radius: 5px;
  /* MORE TRANSLUCENT THAN ANY OTHER PLATE, deliberately: it is the only one
     that overlaps both the rock and another instrument, so the rock has to
     stay readable through it. */
  background: rgba(9, 12, 17, 0.52);
  border: 1px solid rgba(126, 140, 158, 0.20);
  overflow: visible;
}
.sm-adv.sm-compact .sm-ah-cargo .sm-ah-fuel-head {
  flex-direction: row;
  align-items: baseline;
  gap: 7px;
  width: auto;
  margin-bottom: 3px;
}
.sm-adv.sm-compact .sm-ah-cargo .sm-ah-cargo-val {
  font-size: 15px;
  margin-top: 0;
  text-align: left;
}
/* '20 / 192' inline again — there is width for it now. */
.sm-adv.sm-compact .sm-ah-cargo .sm-ah-cargo-cap {
  display: inline;
  font-size: 11px;
}
.sm-adv.sm-compact .sm-ah-cargo .sm-ah-fuel-note {
  margin-top: 0;
  margin-left: auto;
  font-size: 10px;
  text-align: right;
}

/* --- THE BARS GO BACK TO HORIZONTAL ------------------------------------
 * Undoing revision 1's turned-on-its-side bar: same --sm-ah-fill, same write,
 * only the axis. The gradients go back to being read from the LEFT edge, and
 * the reserve mark back to a vertical stroke positioned with margin-left. */
.sm-adv.sm-compact .sm-ah-bar {
  width: auto;
  height: 10px;
  flex: 0 0 auto;
  min-height: 0;
  margin: 0;
  border-radius: 3px;
}
.sm-adv.sm-compact .sm-ah-bar-fill {
  transform-origin: left center;
  transform: scaleX(var(--sm-ah-fill, 0));
  background: linear-gradient(90deg, #ffb01f, #ffe08a);
}
.sm-adv.sm-compact .sm-ah-bar-cargo .sm-ah-bar-fill {
  background: linear-gradient(90deg, #35c7ff, #c4f6ff);
}
.sm-adv.sm-compact .sm-ah-fuel.sm-ah-warn .sm-ah-bar-fill {
  background: linear-gradient(90deg, #ff8c1a, #ffd08a);
}
.sm-adv.sm-compact .sm-ah-fuel.sm-ah-crit .sm-ah-bar-fill {
  background: linear-gradient(90deg, #ff3b22, #ffb3a8);
}
.sm-adv.sm-compact .sm-ah-bar-mark {
  top: -2px;
  bottom: -2px;
  left: 0;
  right: auto;
  width: 2px;
  height: auto;
  margin-left: calc(var(--sm-ah-mark, 0) * 100%);
  transition: margin-left 0.2s ease, opacity 0.2s ease;
}

/* --- what the trip home costs: back to one line under the bar ----------- */
.sm-adv.sm-compact .sm-ah-sub {
  margin-top: 3px;
  font-size: 8.5px;
  text-align: left;
}
.sm-adv.sm-compact .sm-ah-sub-k { display: inline; }
/* There is room for the burn rate again; SECONDS LEFT is the one that would
   push the line to two rows on a 390 px screen, so it stays out. */
.sm-adv.sm-compact .sm-ah-sub-burn { display: inline; }
.sm-adv.sm-compact .sm-ah-sub-left { display: none; }

/* --- the drawer handle, now inside the box's own row -------------------- */
.sm-adv.sm-compact .sm-ah-holdbtn {
  position: absolute;
  top: 4px;
  right: 5px;
  width: auto;
  min-width: 40px;
  min-height: 22px;
  margin: 0;
  padding: 0 6px;
  border-radius: 3px;
}

/* The scanner line clears the hold box instead of the old rail gap. */
.sm-adv.sm-compact .sm-ah-scan {
  left: var(--sm-gutter);
  right: var(--sm-gutter);
  bottom: calc(var(--sm-ah-railbot) + var(--sm-ah-hold-h) + 6px);
}

/* The hold's WORTH shares its row with the absolutely-positioned drawer handle,
   so the row has to reserve the handle's width or the money disappears under
   it — which is the one number the dump decision is weighed against. */
.sm-adv.sm-compact .sm-ah-cargo .sm-ah-fuel-head { padding-right: 48px; }

/* ===========================================================================
 * 7. THE WHOLE HOLD, ALWAYS OPEN
 * ---------------------------------------------------------------------------
 * The manifest used to live behind a handle on the hold box, opening sideways
 * over the rock on a tap. That was the wrong trade: the manifest is not a detail
 * view, it IS the hold — deciding what to dump means comparing every line at
 * once, under fuel pressure, and a drawer makes you tap to find out whether it
 * is worth tapping.
 *
 * So the drawer stops being a drawer: it is always laid out inside the hold box,
 * the handle goes away, and the box grows upward off the readout line to fit
 * however many minerals are aboard. A max-height with overflow keeps a freak
 * twelve-mineral hold from reaching the top of the screen — it is a scroll, not
 * a collapse, and it is not normally reachable.
 * ======================================================================== */
.sm-adv.sm-compact .sm-ah-drawer,
.sm-adv.sm-compact .sm-ah-drawer.sm-ah-drawer-on {
  display: block;
  position: static;
  right: auto;
  bottom: auto;
  width: auto;
  margin-top: 5px;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
}

/* Rows stay comfortably tappable — a two-tap DUMP confirm is done one-handed
   under pressure, so they must not shrink to a hairline just because there are
   more of them now. */
.sm-adv.sm-compact .sm-ah-mrow {
  height: 22px;
  gap: 8px;
  padding: 0 7px;
}
.sm-adv.sm-compact .sm-ah-manifest {
  gap: 2px;
  /* Room for about eight rows before it scrolls; a real hold rarely passes four. */
  max-height: 196px;
  overflow-y: auto;
}

/* The handle has nothing left to open. */
.sm-adv.sm-compact .sm-ah-holdbtn { display: none; }
/* ...so the worth no longer has to dodge it. */
.sm-adv.sm-compact .sm-ah-cargo .sm-ah-fuel-head { padding-right: 0; }

/* ===========================================================================
 * 8. COMPACT HUD — REVISION 3: ONE TOP ROW, THE HOLD ALONE AT THE BOTTOM
 * ---------------------------------------------------------------------------
 * Everything that is a READING goes to the top and reads left to right in
 * descending order of how often it is needed:
 *
 *     FUEL % + bar   HULL   DEPTH   ·   funds (smaller)   ·   menu sound screen
 *
 * The HOLD keeps the bottom to itself, because it is the only instrument that
 * is also a CONTROL — its rows are the two-tap dump — so it belongs in thumb
 * reach, and it is the one that changes height as minerals come aboard.
 *
 * The company balance is deliberately a size down: it matters when deciding
 * whether a haul is worth pushing for, not while threading a seam, and giving
 * it the same weight as fuel made the row read as four equal numbers with no
 * hierarchy at all.
 *
 * The strip and the fuel panel stay two separate elements — no DOM change —
 * laid side by side in the top band, with the strip's cells re-ordered by flex
 * `order` rather than by moving anything in advhud.js.
 * ======================================================================== */
/* THE THREE CORNER PLATES ARE ONE ROW, IN BOTH ORIENTATIONS, and the bar stops
 * short of them. They are ui.js's — menu, sound, fullscreen — and they are the
 * only plates up here: until 2026-10-11 a run added its own mute and PAUSE,
 * which made four across a landscape top edge and a second row under the
 * corner in portrait. The hub's corner is three plates and nothing else, so
 * this is one number for every phone: three plates, the two gaps between
 * them, the gutter and 6px of air. The lift panel's clear lane along the top
 * (54 px, bottom-anchored further down) already assumes a single row.
 * ======================================================================== */
.sm-adv.sm-compact {
  --sm-ah-icons: calc(var(--sm-btn-size) * 3 + 16px + var(--sm-gutter) + 6px);
}

/* --- FUEL: top-left, narrow enough to leave room for three more readings -- */
.sm-adv.sm-compact .sm-ah-fuel {
  width: 44%;
  max-width: 210px;
  min-width: 132px;
  padding: 4px 8px 5px;
}
.sm-adv.sm-compact .sm-ah-fuel .sm-ah-fuel-pct { font-size: 15px; }
/* The arithmetic under the bar does not fit beside three other cells; the
   reserve MARK on the bar is what actually answers "can I get home". */
.sm-adv.sm-compact .sm-ah-sub { display: none; }

/* --- THE STRIP JOINS THE TOP ROW ---------------------------------------
 * It was pinned to the bottom edge in revisions 1 and 2. It now sits to the
 * RIGHT of the fuel panel and stops short of the icon plates. */
.sm-adv.sm-compact .sm-ah-strip {
  top: var(--sm-top-y);
  bottom: auto;
  left: auto;
  /* Starts where the fuel panel ends. */
  right: var(--sm-ah-icons);
  width: auto;
  max-width: calc(100% - var(--sm-ah-icons) - 46% - var(--sm-gutter) - 6px);
  height: auto;
  min-height: 0;
  gap: 9px;
  padding: 4px 9px 5px;
  justify-content: flex-end;
  border-radius: 5px;
  background: linear-gradient(180deg, rgba(9, 12, 17, 0.88), rgba(12, 16, 22, 0.66));
}
.sm-adv.sm-compact .sm-ah-strip .sm-stripe { top: 0; bottom: auto; }

/* HULL, DEPTH, then FUNDS — set by `order`, so advhud.js still builds the DOM
   in its own order and nothing in the JS has to know about this. */
.sm-adv.sm-compact .sm-ah-strip .sm-ah-integ { order: 1; }
.sm-adv.sm-compact .sm-ah-strip .sm-ah-depth { order: 2; }
.sm-adv.sm-compact .sm-ah-strip .sm-ah-heat  { order: 3; }
.sm-adv.sm-compact .sm-ah-strip .sm-ah-funds { order: 4; }

.sm-adv.sm-compact .sm-ah-strip .sm-ah-val { font-size: 13px; }
/* A size down, and dimmer: useful, not urgent. */
.sm-adv.sm-compact .sm-ah-strip .sm-ah-funds .sm-ah-val {
  font-size: 11px;
  color: var(--sm-gold);
  opacity: 0.9;
}
/* The mini bars under HEAT and HULL have no room in a single row. */
.sm-adv.sm-compact .sm-ah-strip .sm-ah-mini { display: none; }

/* --- the hold now owns the bottom, so it sits on the safe-area edge ----- */
.sm-adv.sm-compact .sm-ah-cargo {
  bottom: var(--sm-top-y);
  width: 62%;
  max-width: 320px;
}
/* ...and the scanner line clears the hold box from its new position. */
.sm-adv.sm-compact .sm-ah-scan {
  bottom: calc(var(--sm-top-y) + var(--sm-ah-hold-h) + 6px);
}

/* --- revision 3a: the balance gets its own line ------------------------
 * Measured at 390 px: fuel 172 + strip 105 + icons 80 left the strip 105 px for
 * three readings, and FUNDS was clipped to a bare "$". Three numbers do not fit
 * on one line beside the fuel bar on a phone, and the balance is the one that
 * can wait — so it drops to a second, smaller line under HULL and DEPTH. That is
 * also the hierarchy asked for: fuel, hull, depth, then the balance a size down.
 * ------------------------------------------------------------------ */
.sm-adv.sm-compact .sm-ah-fuel {
  width: 38%;
  max-width: 156px;
  min-width: 120px;
}
.sm-adv.sm-compact .sm-ah-strip {
  flex-wrap: wrap;
  align-content: center;
  row-gap: 1px;
  max-width: calc(100% - var(--sm-ah-icons) - 38% - var(--sm-gutter) - 6px);
}
/* HULL and DEPTH share the first line... */
.sm-adv.sm-compact .sm-ah-strip .sm-ah-integ,
.sm-adv.sm-compact .sm-ah-strip .sm-ah-depth {
  flex: 0 0 auto;
}
/* ...and the balance takes the whole second one, right-aligned under them. */
.sm-adv.sm-compact .sm-ah-strip .sm-ah-funds {
  flex: 0 0 100%;
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  gap: 5px;
}
.sm-adv.sm-compact .sm-ah-strip .sm-ah-funds .sm-ah-val {
  font-size: 11.5px;
  white-space: nowrap;
}

/* --- revision 3b: the strip is a GRID, not a wrapping flex row ---------
 * Flex wrap could not be trusted here. Measured at 390 px, HULL and DEPTH ended
 * up on separate lines despite fitting side by side (50 + 63 + 9 = 122 in a
 * 136 px strip), because `.sm-stripe` — the decorative hazard rule — was in flow
 * as a full-width block and consumed the first line, so every reading wrapped
 * below it and the strip silently became three rows tall.
 *
 * A grid with NAMED AREAS removes the ambiguity: HULL and DEPTH share row one,
 * the balance spans row two, and no amount of content can re-flow them. The
 * stripe is forced out of flow so it can never claim a cell again.
 * ------------------------------------------------------------------ */
.sm-adv.sm-compact .sm-ah-strip {
  display: grid;
  grid-template-columns: auto auto;
  grid-template-areas:
    "hull  depth"
    "heat  funds";
  justify-content: end;
  align-content: center;
  column-gap: 9px;
  row-gap: 0;
  flex-wrap: nowrap;
}
.sm-adv.sm-compact .sm-ah-strip > .sm-stripe {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: auto;
}
.sm-adv.sm-compact .sm-ah-strip .sm-ah-integ { grid-area: hull;  justify-self: end; }
.sm-adv.sm-compact .sm-ah-strip .sm-ah-depth { grid-area: depth; justify-self: end; }
.sm-adv.sm-compact .sm-ah-strip .sm-ah-heat  { grid-area: heat;  justify-self: end; }
.sm-adv.sm-compact .sm-ah-strip .sm-ah-funds {
  grid-area: funds;
  justify-self: end;
  flex: none;
}
/* HEAT is still absent until it means something — it simply leaves its cell
   empty, and the balance keeps its place on the right. */
.sm-adv.sm-compact .sm-ah-strip .sm-ah-heat.sm-ah-live { display: flex; }
/* HULL carries a (hidden) mini bar and DEPTH does not, so their boxes are
   different heights and the two numbers sat 7 px apart. Centre every cell in
   its row so the top line reads as one line. */
.sm-adv.sm-compact .sm-ah-strip > .sm-ah-cell { align-self: center; }

/* ===========================================================================
 * 9. COMPACT HUD — REVISION 4: ONE INFO BAR
 * ---------------------------------------------------------------------------
 *      +----------------------------------------+  +---+ +---+
 *      | FUEL 61% ====        HULL 100%         |  | ) | | # |
 *      |                     DEPTH  19 m        |  +---+ +---+
 *      +----------------------------------------+   FUNDS $19 211
 *
 * Revision 3 left two visibly separate plates with a gap between them. This is
 * one bar: FUEL takes a fixed slice on the left, HULL and DEPTH sit beside it,
 * and the two panels are butted together with their facing corners squared so
 * the seam disappears. They stay two ELEMENTS — advhud.js builds them
 * separately and the wide stack still wants them apart — but they read as one.
 *
 * FUEL is narrower than before: the percentage and the bar are all it needs
 * here, and the arithmetic under it (BURN, SECONDS LEFT) is already hidden on a
 * phone because the reserve mark on the bar says the same thing.
 *
 * The BALANCE gets its own line under the icon plates, out of the bar entirely.
 * It is the number you consult between decisions, not during one.
 * ======================================================================== */
.sm-adv.sm-compact {
  --sm-ah-fuelw: 136px;   /* the fuel slice of the info bar (fixed, so the
                             strip can butt against it with a calc) */
  --sm-ah-barh:  42px;    /* one bar height for both halves */
}

/* --- left half: FUEL --------------------------------------------------- */
.sm-adv.sm-compact .sm-ah-fuel {
  left: var(--sm-gutter);
  width: var(--sm-ah-fuelw);
  min-width: 0;
  max-width: none;
  height: var(--sm-ah-barh);
  justify-content: center;
  padding: 0 9px;
  border-radius: 5px 0 0 5px;
}
.sm-adv.sm-compact .sm-ah-fuel .sm-ah-fuel-head { margin-bottom: 3px; }
.sm-adv.sm-compact .sm-ah-fuel .sm-ah-fuel-pct { font-size: 14px; }
/* The state word would not fit beside a 14 px percentage in 136 px; the bar
   turns amber and then red, and the mark says where home is. */
.sm-adv.sm-compact .sm-ah-fuel .sm-ah-fuel-note { display: none; }
.sm-adv.sm-compact .sm-ah-bar { height: 8px; }

/* --- right half: HULL and DEPTH ---------------------------------------- */
.sm-adv.sm-compact .sm-ah-strip {
  /* Butted against the fuel slice — no gap, so the two read as one bar. */
  left: calc(var(--sm-gutter) + var(--sm-ah-fuelw));
  right: var(--sm-ah-icons);
  width: auto;
  max-width: none;
  height: var(--sm-ah-barh);
  padding: 0 10px;
  border-radius: 0 5px 5px 0;
  /* HULL over DEPTH, both right-aligned: two short labelled numbers stack more
     legibly in this width than they sit side by side. */
  grid-template-columns: auto;
  grid-template-areas:
    "hull"
    "depth";
  align-content: center;
  row-gap: 0;
}
.sm-adv.sm-compact .sm-ah-strip .sm-ah-integ,
.sm-adv.sm-compact .sm-ah-strip .sm-ah-depth {
  display: flex;
  align-items: baseline;
  gap: 6px;
  justify-self: end;
}
.sm-adv.sm-compact .sm-ah-strip .sm-ah-val { font-size: 13px; }
/* HEAT joins the same column when it wakes up. */
.sm-adv.sm-compact .sm-ah-strip .sm-ah-heat {
  grid-area: auto;
  justify-self: end;
  align-items: baseline;
  gap: 6px;
}

/* --- the balance, on its own line under the icon plates ----------------- */
.sm-adv.sm-compact .sm-ah-funds {
  position: absolute;
  top: calc(var(--sm-top-y) + var(--sm-btn-size) + 6px);
  right: var(--sm-gutter);
  left: auto;
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  gap: 5px;
  padding: 0;
  background: none;
  border: 0;
  white-space: nowrap;
}
.sm-adv.sm-compact .sm-ah-funds .sm-ah-val {
  font-size: 12px;
  color: var(--sm-gold);
}

/* --- WIDE: the balance was a cell in the strip and is now a sibling ------
 * Put it back where it was, at the right-hand end of the top strip's row,
 * clear of the icon plates that strip already reserves 96 px for. */
.sm-adv:not(.sm-compact) .sm-ah-funds {
  position: absolute;
  top: 9px;
  right: 104px;
  display: flex;
  align-items: baseline;
  gap: 7px;
}

/* --- revision 4a: HULL and DEPTH side by side --------------------------
 * They were stacked in one column. Side by side is what was asked for, and it
 * now fits: the strip runs 143 -> 297 at 390 px, and HULL 100% plus DEPTH 19 m
 * measure about 115 px together. One row also lets the whole bar be shallower,
 * which is the point of putting the balance somewhere else. */
.sm-adv.sm-compact .sm-ah-strip {
  grid-template-columns: auto auto;
  grid-template-areas: "hull depth";
  column-gap: 12px;
  justify-content: end;
  height: var(--sm-ah-barh);
}
.sm-adv.sm-compact .sm-ah-strip .sm-ah-integ { grid-area: hull; }
.sm-adv.sm-compact .sm-ah-strip .sm-ah-depth { grid-area: depth; }
/* HEAT has nowhere in a single row, and it is the one reading that is genuinely
   optional — the alert banner shouts when it matters. */
.sm-adv.sm-compact .sm-ah-strip .sm-ah-heat,
.sm-adv.sm-compact .sm-ah-strip .sm-ah-heat.sm-ah-live { display: none; }
/* Label above value, so each reading is a narrow two-line column. */
.sm-adv.sm-compact .sm-ah-strip .sm-ah-integ,
.sm-adv.sm-compact .sm-ah-strip .sm-ah-depth {
  display: block;
  text-align: right;
}
.sm-adv.sm-compact .sm-ah-strip .sm-ah-lbl { display: block; }
.sm-adv.sm-compact .sm-ah-strip .sm-ah-val { font-size: 14px; line-height: 1.05; }

/* The scanner's HUD line is gone — it spoke over the hold, and the arrows out of
   the machine say the same thing where the ore is. Hidden in CSS as well as
   skipped in JS so a stale cached script cannot resurrect it. */
.sm-adv .sm-ah-scan { display: none !important; }

/* ===========================================================================
 * 10. THE INFO BAR NEGOTIATES ITS OWN WIDTH  (the real-Android squash)
 * ---------------------------------------------------------------------------
 * HULL and DEPTH squashed on an actual phone while Chrome's device emulation
 * looked correct. The cause was not the viewport, it was the FONT: --sm-mono
 * resolves to SF Mono on macOS and to Roboto Mono / Droid Sans Mono on Android,
 * which are wider at the same px size — and DevTools emulation swaps the screen
 * but keeps the host's fonts, so the overflow could not be seen there.
 *
 * Tuning px values against one font's metrics would just move the bug to the
 * next device. Instead the bar is a flex row that lets the two halves negotiate:
 *
 *   STRIP  flex: 0 0 auto  — takes exactly what its text needs, never shrinks,
 *                            never wraps. Whatever font is in play, the numbers
 *                            are whole.
 *   FUEL   flex: 1 1 auto; min-width: 0  — gives up the remainder. A shorter
 *                            fuel bar is a graceful loss; a clipped readout is
 *                            not.
 *
 * `min-width: 0` is load-bearing: a flex item's default `min-width: auto`
 * refuses to shrink below its content, which is exactly how a row overflows
 * instead of redistributing.
 * ======================================================================== */
.sm-adv.sm-compact .sm-ah-top {
  position: absolute;
  top: var(--sm-top-y);
  left: var(--sm-gutter);
  right: var(--sm-ah-icons);
  display: flex;
  flex-direction: row;
  align-items: stretch;
  height: var(--sm-ah-barh);
  pointer-events: none;
}
/* The two halves stop positioning themselves and become flex items. */
.sm-adv.sm-compact .sm-ah-top > .sm-ah-fuel,
.sm-adv.sm-compact .sm-ah-top > .sm-ah-strip {
  position: static;
  top: auto;
  left: auto;
  right: auto;
  bottom: auto;
  height: auto;
}
.sm-adv.sm-compact .sm-ah-top > .sm-ah-fuel {
  order: 1;
  flex: 1 1 auto;
  min-width: 64px;          /* below this the bar is not a gauge any more */
  width: auto;
  max-width: none;
}
.sm-adv.sm-compact .sm-ah-top > .sm-ah-strip {
  order: 2;
  flex: 0 0 auto;           /* text width wins, on any font */
  width: auto;
  max-width: none;
}
/* Nothing in the bar may wrap or hyphenate its way out of trouble. */
.sm-adv.sm-compact .sm-ah-top .sm-ah-val,
.sm-adv.sm-compact .sm-ah-top .sm-ah-lbl { white-space: nowrap; }

/* WIDE: the wrapper vanishes and the stack sees its original children. */
.sm-adv:not(.sm-compact) .sm-ah-top { display: contents; }

/* ===========================================================================
 * 11. WARNINGS SIT BETWEEN THE MACHINE AND THE HOLD
 * ---------------------------------------------------------------------------
 * The banner was pinned just above the bottom readout, which put it straight
 * over the hold — so CARGO FULL, the one message whose whole purpose is to send
 * you to the manifest, covered the manifest.
 *
 * It now floats in the empty band between the machine (centred) and the hold box
 * (bottom-left). `max()` guarantees the clearance rather than trusting a
 * percentage: on a short landscape phone 24% of the height is less than the hold
 * is tall, and the banner would land back on top of it.
 *
 * The scanner's own banners are gone entirely (see advhud.js) — what is left here
 * is CARGO FULL, the fuel reserve warning, hull damage, heat and a new stratum,
 * all of which are worth interrupting for.
 * ======================================================================== */
.sm-adv.sm-compact .sm-ah-alert {
  bottom: max(24%, calc(var(--sm-ah-hold-h) + 54px));
  left: 50%;
  top: auto;
}

/* ===========================================================================
 * 12. THE LIFT PANEL — IN THE BAND BETWEEN THE MACHINE AND THE HOLD
 * ---------------------------------------------------------------------------
 * The mine mouth is a lift with stations cut at the strata boundaries, and this
 * is the panel that appears when the machine is standing on one: SURFACE at the
 * top (which is the sale and the end of the run), then the stations the company
 * holds, then the one it can buy.
 *
 * TWO THINGS DECIDE WHERE IT GOES, and the third one that used to is gone.
 *
 * 1. IT IS A PLACE, SO IT SITS IN THE MIDDLE. The machine is inside the cage
 *    while this is up — hidden, parked, undriveable — so there is nothing
 *    behind the panel worth seeing and no reason to squeeze it into a strip.
 *    See the .sm-ah-lift rule for the full argument.
 *
 *    (IT USED TO DODGE THE HOLD. The manifest was what the "ride up and sell"
 *    decision was weighed against, so the panel was pinned above the hold box by
 *    adding a published row count to its `bottom`. Both reasons expired: the
 *    panel no longer appears while driving, and SELL now states the hold's whole
 *    worth on its own plate. --sm-ah-hold-rows and --sm-ah-hold-base went with
 *    the rule, and so did the setVar() that fed them.)
 *
 * 2. IT MAY NOT EAT THE BANNER. CARGO FULL and the fuel reserve warning live in
 *    this same band, so while the panel is up the banner moves to just under the
 *    info bar. advhud.js puts .sm-ah-lift-on on the HUD root as well as on the
 *    panel for exactly this — one class, two jobs, no measuring.
 *
 * 3. ONLY THE CONTROLS TAKE POINTERS. The container is pointer-events:none and
 *    the rows, BUY, the plates and the cross opt back in. That mattered when a
 *    drag on the panel had to reach the stick layer; it is kept because it still
 *    costs nothing and still means a tap that lands between plates does nothing
 *    rather than something. z-index 7 puts the buttons above the stick layer, so
 *    a tap that lands on a row is a row press and not a lurch sideways.
 *
 * The panel is a SIBLING of .sm-ah in #ui-root, not a child, because in the wide
 * layout .sm-ah is a content-height column pinned top-left and an absolute child
 * of it cannot reach the bottom of the window. One containing block, both
 * layouts. Same reason the pause card is a sibling.
 * ======================================================================== */
/* ======================================================================== */
/* CLASSIC CANNOT SEE THESE. MEASURED, and it was a real leak.
 *
 * The door menu and the ride overlay are siblings of .sm-ah in #ui-root (they
 * have to be — see the panel note below), and EVERY rule that positions or hides
 * them is scoped to .sm-adv. In classic mode that class is absent, so both were
 * plain block divs sitting in the MENU's flow: v1.8 leaked a 1440x16 strip of
 * the panel's own head, and the four door plates turned that into 1440x94 with
 * OUT and MAP legible over the mode cards at 1440x900.
 *
 * The A/B was otherwise clean (identical particle histogram, identical play and
 * pause), so this is presentation only — but it is exactly the kind of leak that
 * gets worse every time the panel grows. Two rules, and the panels do not exist
 * outside adventure mode.
 * ======================================================================== */
.sm-ah-lift, .sm-ah-ride { display: none; }
.sm-adv .sm-ah-lift { display: block; }
.sm-adv .sm-ah-ride { display: flex; }

/* ========================================================================
   THE LIFT IS A PLACE, NOT A POPUP — and this rule is where that is decided.

   IT USED TO BE A 340 px CARD hugging the bottom edge, clearing the hold box
   by arithmetic, because it could appear while the player was merely NEAR the
   doors and might want to carry on drilling around it. That is no longer true
   of anything: the panel opens only when the machine is INSIDE the cage
   (adv.isInLift()), where it is hidden, parked and undriveable. There is
   nothing to drill around and nothing to see behind it — so the old card was
   squeezing a room's worth of decisions into a strip for a reason that had
   already been engineered away.

   SO IT IS CENTRED AND IT IS BIG. Middle of the glass, up to 560 px wide, up
   to 86% of the height, laid out as a column: the trade at the top, the ladder
   in the middle taking whatever room is left, the way out at the bottom under
   the thumb. The list is the only part that scrolls, so the two things a
   player reaches for — the SELL number and RETURN TO MINE — never move.

   THE SCRIM IS A BOX-SHADOW, not an element. A 100vmax spread paints the rest
   of the window down without a second div to build, position, show and hide;
   it costs one composited layer and it is what makes the panel read as
   somewhere you ARE rather than something on top of where you were.
   ==================================================================== */
.sm-adv .sm-ah-lift {
  position: absolute;
  left: 50%;
  top: 50%;
  width: min(560px, calc(100% - var(--sm-gutter) * 2 - 4px));
  max-height: min(86%, 760px);
  display: flex;
  flex-direction: column;
  padding: 12px 14px 13px;
  border-radius: 6px;
  /* No backdrop blur, for the reason given in §3b: these plates sit over dark
     rock at DPR 3 and the blur is fill rate spent on an effect nobody sees. */
  /* Near-opaque: the HUD is dimmed behind this by the scrim below, but the hold
     box reaches into the panel's top corner and 6% of a bright manifest row was
     legible through it. */
  background: linear-gradient(180deg, rgba(9, 12, 17, 0.99), rgba(12, 16, 22, 0.975));
  border: 1px solid rgba(255, 194, 31, 0.46);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    0 18px 50px rgba(0, 0, 0, 0.7),
    0 0 0 100vmax rgba(3, 5, 8, 0.58);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translate(-50%, -50%) translateY(12px);
  transition: opacity 0.18s ease, transform 0.24s cubic-bezier(0.16, 1, 0.3, 1);
  z-index: 7;
}
.sm-adv .sm-ah-lift.sm-ah-lift-on {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, -50%);
}

.sm-ah-lift-head {
  flex: 0 0 auto;
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 10px;
  padding-bottom: 8px;
  padding-right: 30px;           /* clear of the cross */
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
/* The head is the room's nameplate now, so it carries the weight a title has:
   LIFT on the left, and where you are standing on the right, in gold. */
.sm-ah-lift-head .sm-ah-lbl {
  font-size: 10px;
  letter-spacing: 2.6px;
  color: var(--sm-gold);
}
.sm-ah-lift-where {
  margin-left: auto;
  font-family: var(--sm-mono);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 1.6px;
  color: var(--sm-text);
  font-variant-numeric: tabular-nums;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* THE CROSS. The panel is an offer, not a mode: a player parked at a station may
   simply want to keep drilling, and driving off the platform also dismisses it. */
.sm-ah-lift-close {
  position: absolute;
  top: 7px;
  right: 7px;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 3px;
  background: none;
  color: var(--sm-dim);
  pointer-events: auto;
  cursor: pointer;
}
.sm-ah-lift-close svg { display: block; width: 13px; height: 13px; }
.sm-ah-lift-close:hover { color: var(--sm-text); background: rgba(255, 255, 255, 0.07); }

/* THE LADDER TAKES WHAT IS LEFT, AND IT IS THE ONLY THING THAT SCROLLS.
   A mine sells up to five levels and a phone in landscape is short, so the list
   is the give in the column — the trade plates above and the call to action
   below keep their positions whatever the list does, which is what stops the
   two most-tapped controls in the panel from moving under the thumb. */
.sm-ah-lift-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  gap: 4px;
  pointer-events: auto;
}

.sm-ah-liftrow {
  display: flex;
  align-items: stretch;
  gap: 6px;
  min-width: 0;
}
/* The ride target. Same negotiation as everything else in this stylesheet: the
   NAME yields and the depth and the tag never do, so a wider font on real
   hardware shortens "GRANITE FLOOR" instead of clipping "240 m". */
.sm-ah-liftgo {
  flex: 1 1 auto;
  min-width: 0;
  display: grid;
  grid-template-columns: 8px minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 10px;
  min-height: 40px;
  padding: 0 11px;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-left: 3px solid rgba(126, 140, 158, 0.35);
  border-radius: 2px;
  background: rgba(10, 13, 17, 0.72);
  font-family: var(--sm-mono);
  color: var(--sm-text);
  text-align: left;
  pointer-events: auto;
  cursor: pointer;
}
.sm-ah-liftgo:hover { background: rgba(30, 38, 48, 0.78); }
/* A disabled row is the one you are STANDING on, or one that is a price rather
   than a destination — neither is "broken", so neither is greyed. Only the
   cursor changes; the row's own dress says what it is. */
.sm-ah-liftgo:disabled { cursor: default; }
.sm-ah-liftgo:disabled:hover { background: rgba(10, 13, 17, 0.72); }

/* The station marker. Green is the default because a HELD station is the common
   case; the surface, the current platform and the one for sale each override it
   BELOW this rule, which is the only reason they win — every one of them is two
   classes deep, so the cascade is decided by order here, not by specificity. */
.sm-ah-liftsw {
  width: 8px;
  height: 8px;
  border-radius: 1px;
  background: var(--sm-green);
  box-shadow: 0 0 6px rgba(90, 226, 140, 0.5);
}
.sm-ah-liftname {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 1.4px;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* ONE DEPTH, NOT A BAND. A level map is endless south (ARCHITECTURE.md §7), so
   this is where its lift sits and nothing else — "0 m", "135 m", "300 m". It is
   deliberately quiet: the NAME is what identifies a level and the depth is the
   supporting fact, not the headline. */
.sm-ah-liftdep {
  font-size: 10px;
  font-weight: 800;
  color: var(--sm-dim);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.sm-ah-lifttag {
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 1.2px;
  color: var(--sm-dimmer);
  min-width: 44px;
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* SURFACE leads and wears the gold, because it is the one row that ends the
   expedition — it should never be mistaken for one more station. */
.sm-ah-liftrow-surface .sm-ah-liftgo {
  border-left-color: var(--sm-gold);
  background: linear-gradient(90deg, rgba(94, 68, 8, 0.62), rgba(14, 18, 24, 0.74) 72%);
}
.sm-ah-liftrow-surface .sm-ah-liftsw { background: var(--sm-gold); box-shadow: 0 0 6px var(--sm-gold); }
.sm-ah-liftrow-surface .sm-ah-liftname { color: #fff3cf; }
.sm-ah-liftrow-surface .sm-ah-liftdep { color: #e6cf95; }
.sm-ah-liftrow-surface .sm-ah-lifttag { color: var(--sm-gold); }

/* The station under the machine is cyan and reads HERE, so "where am I on this
   shaft" is answered without reading a number. */
.sm-ah-liftrow-here .sm-ah-liftgo {
  border-left-color: var(--sm-cyan);
  background: rgba(16, 34, 44, 0.82);
}
.sm-ah-liftrow-here .sm-ah-liftsw { background: var(--sm-cyan); box-shadow: 0 0 6px var(--sm-cyan); }
.sm-ah-liftrow-here .sm-ah-lifttag { color: var(--sm-cyan-hot); }

/* The one station for sale. Dimmer than the held ones — it is not somewhere you
   can go yet — with its price where the other rows carry their state. */
.sm-ah-liftrow-next .sm-ah-liftgo {
  border-left-color: var(--sm-gold);
  opacity: 0.8;
}
.sm-ah-liftrow-next .sm-ah-liftsw {
  background: none;
  border: 1px solid var(--sm-gold);
  box-shadow: none;
}
.sm-ah-liftrow-next .sm-ah-lifttag { color: var(--sm-gold); }

/* BUY IS HAND-ROLLED, NOT AN .sm-btn. The shared plate carries a 40px minimum
   height, a 74px minimum width and a backdrop blur, none of which belong on a
   30px row inside the mine. The gold treatment and the disabled greying are
   copied from §"THE DESCEND BUTTON'S LOOK" so it still reads as the same
   family — and the label stays BUY whatever happens. */
.sm-ah-liftbuy {
  flex: 0 0 auto;
  min-width: 68px;
  min-height: 40px;
  padding: 0 14px;
  border-radius: 2px;
  border: 1px solid rgba(255, 240, 168, 0.6);
  background: linear-gradient(180deg, #ffd979, var(--sm-gold) 45%, #c98a06 100%);
  color: #150b02;
  font-family: var(--sm-mono);
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 1.6px;
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.3);
  pointer-events: auto;
  cursor: pointer;
}
.sm-ah-liftbuy:hover { filter: brightness(1.2); }
.sm-ah-liftbuy:disabled {
  filter: grayscale(0.9) brightness(0.62);
  opacity: 0.5;
  cursor: default;
  pointer-events: none;
}

/* A SEALED LEVEL IS A READ, NOT A CONTROL. It is in the list because knowing the
   mine is six levels deep is the reason to buy the next one — but it is not
   somewhere you can go and it is not somewhere you can pay for yet, so it is
   flat, grey and has no marker glow. */
.sm-ah-liftrow-sealed .sm-ah-liftgo {
  border-left-color: rgba(126, 140, 158, 0.22);
  background: rgba(8, 10, 14, 0.6);
  opacity: 0.5;
}
.sm-ah-liftrow-sealed .sm-ah-liftsw {
  background: none;
  border: 1px solid rgba(126, 140, 158, 0.5);
  box-shadow: none;
}
.sm-ah-liftrow-sealed .sm-ah-liftname { color: var(--sm-dim); }

/* ========================================================================
   THE DOOR MENU'S THREE PLATES — SELL / REFUEL / MAP
   ------------------------------------------------------------------------
   These are the surface, and they sit at the TOP of the panel because they are
   why the player drove back. Each is a fixed LABEL over a live VALUE, in a
   three-column grid that gives every plate the same width: the numbers change
   ($0 to $12 400), and a row whose columns resize under the thumb is a row you
   mis-tap. `1fr` each, `min-width: 0`, and the value line ellipsises rather than
   pushing its neighbours around — the Android font lesson from §3.

   POINTER-EVENTS: AUTO, on the plates only. The panel container is
   pointer-events:none so a drag that starts on its background still reaches the
   stick layer and drives (see the panel's own note above).
   ==================================================================== */
/* THE TRADE. Two plates, half the panel each, and they are the biggest type in
   here on purpose: standing in the lift the player is weighing ONE PAIR OF
   NUMBERS — what the hold banks and what a tank costs — and everything else on
   this panel is downstream of that answer. A grid rather than wrapping flex,
   because there are exactly two and they must never reflow to a stack. */
/* THREE PLATES NOW: SELL, REFUEL, WORKSHOP — the three things the surface is
 * for. The grid is EXPLICIT and three-valued for the same reason it was
 * explicit and two-valued: a wrapping flex would drop the third plate onto a
 * second row, and the height for that row comes out of the level ladder, which
 * on a landscape phone has about fifty pixels to give. Three columns costs
 * width, and width is what this panel has spare. */
.sm-ah-door-acts {
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 8px;
  margin-bottom: 10px;
}
.sm-ah-doorbtn {
  min-width: 0;
  min-height: 40px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 5px 6px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 3px;
  background: rgba(14, 18, 24, 0.86);
  font-family: var(--sm-mono);
  color: var(--sm-text);
  pointer-events: auto;
  cursor: pointer;
}
.sm-ah-door-acts .sm-ah-doorbtn { min-height: 62px; }
.sm-ah-doorbtn:hover { background: rgba(30, 38, 48, 0.9); }
.sm-ah-doorlbl {
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 1.8px;
  color: var(--sm-dim);
  white-space: nowrap;
}
.sm-ah-doorval {
  max-width: 100%;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.6px;
  color: var(--sm-dim);
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* THE NUMBER IS THE PLATE. On the trade plates the value line is the thing
   being read at a glance, so the hierarchy inverts: the label goes quiet and
   small above it and the money is set large.
   STEPPED DOWN FROM 20 px WITH THE THIRD COLUMN. Each plate lost a third of its
   width when WORKSHOP joined the row, and `$12 400` still has to sit on one line
   without ellipsising — `.sm-ah-doorval` truncates rather than pushing its
   neighbours, so the failure would have been silent. */
.sm-ah-door-acts .sm-ah-doorval {
  font-size: 17px;
  letter-spacing: 0.2px;
  line-height: 1.15;
}
/* SELL is the loop's payday, so it wears the gold — the same plate family as
   BUY and DESCEND, at HUD scale. */
.sm-ah-door-sell {
  border-color: rgba(255, 240, 168, 0.5);
  background: linear-gradient(180deg, rgba(94, 68, 8, 0.72), rgba(14, 18, 24, 0.86) 74%);
}
.sm-ah-door-sell .sm-ah-doorlbl { color: #e6cf95; }
.sm-ah-door-sell .sm-ah-doorval { color: var(--sm-gold); }
.sm-ah-door-fuel { border-color: rgba(90, 226, 140, 0.34); }
.sm-ah-door-fuel .sm-ah-doorval { color: var(--sm-green); }
/* The workshop is the MACHINE, so it wears the machine's cyan — the same colour
   as RETURN TO MINE and every rig readout in the game. Deliberately not gold:
   nothing is banked at this plate, something is spent. */
.sm-ah-door-shop { border-color: rgba(122, 214, 255, 0.34); }
.sm-ah-door-shop .sm-ah-doorval { color: var(--sm-cyan); }

/* ========================================================================
   THE FOOT — THE CALL TO ACTION, AND THE WAY OUT
   ------------------------------------------------------------------------
   RETURN TO MINE gets two thirds of the width, the cyan the machine wears and
   the lowest position in the panel, because it is what the player wants nine
   times out of ten and because the bottom of a panel is where a thumb already
   is. LEAVE gets the remaining third, no colour and no weight: it ends the
   expedition, which is the rare choice, and it still takes two taps.
   ==================================================================== */
.sm-ah-door-foot {
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 8px;
  margin-top: 10px;
}
.sm-ah-door-return {
  min-height: 54px;
  border-color: rgba(122, 214, 255, 0.6);
  background: linear-gradient(180deg, rgba(18, 62, 82, 0.92), rgba(12, 26, 36, 0.9) 78%);
}
.sm-ah-door-return .sm-ah-doorlbl {
  font-size: 13px;
  letter-spacing: 2.6px;
  color: #dff4ff;
}
.sm-ah-door-return .sm-ah-doorval {
  font-size: 9.5px;
  letter-spacing: 1.4px;
  color: var(--sm-cyan);
}
.sm-ah-door-return:hover {
  background: linear-gradient(180deg, rgba(24, 82, 108, 0.95), rgba(16, 34, 46, 0.92) 78%);
}
.sm-ah-door-map { min-height: 54px; }
.sm-ah-door-map .sm-ah-doorlbl { color: var(--sm-dimmer); }
.sm-ah-door-map .sm-ah-doorval { color: var(--sm-dimmer); font-size: 8.5px; }

/* ========================================================================
   THE UNLOCK NOTICE — the progression gate's one piece of teaching
   ------------------------------------------------------------------------
   It appears ONCE, in the lift, directly above the list it is talking about,
   and it is gold because gold is this game's colour for "money may now change
   hands". It is a BOX and not a banner: banners here expire on a timer, and
   this one has to survive being read slowly. js/advhud.js takes it from
   SM.adv.getUnlockNotice() and drops it when the player leaves the cage.
   ==================================================================== */
.sm-ah-unlock {
  flex: 0 0 auto;
  display: none;
  margin-bottom: 10px;
  padding: 9px 11px;
  border: 1px solid rgba(255, 194, 31, 0.55);
  border-left: 3px solid var(--sm-gold);
  border-radius: 3px;
  background: linear-gradient(90deg, rgba(94, 68, 8, 0.5), rgba(14, 18, 24, 0.72) 76%);
}
.sm-ah-unlock.sm-ah-unlock-on { display: block; }
.sm-ah-unlock-title {
  font-family: var(--sm-mono);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 2.2px;
  color: var(--sm-gold);
}
.sm-ah-unlock-body {
  margin-top: 4px;
  font-family: var(--sm-mono);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.7px;
  line-height: 1.55;
  color: #e8dcc0;
}
/* ARMED. LEAVE is one tap from ending the expedition, so the second tap is the
   one that does it — and the plate says so in its VALUE line, never by renaming
   itself (see the results footer's rule). */
.sm-ah-door-armed {
  border-color: rgba(255, 108, 92, 0.85);
  background: rgba(58, 14, 12, 0.9);
}
.sm-ah-door-armed .sm-ah-doorval { color: #ff9a8c; }
/* UNAVAILABLE. One mechanism for every dim control in this file: :disabled. */
.sm-ah-doorbtn:disabled {
  filter: grayscale(0.9) brightness(0.7);
  opacity: 0.45;
  cursor: default;
  pointer-events: none;
}

.sm-ah-lift-note {
  flex: 0 0 auto;
  font-family: var(--sm-mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.2px;
  line-height: 1.5;
  color: var(--sm-dimmer);
  margin-top: 9px;
}

/* ========================================================================
   THE RIDE TRANSITION — dip to black, then the level announces itself
   ------------------------------------------------------------------------
   A level is its own map, so a ride has to read as a LOAD and not as a
   teleport. The mechanics, and why they are what they are:

   IT IS A DIP, NOT A FADE. .sm-ah-ride-on lands together with
   .sm-ah-ride-cut, which sets `transition: none` — so the black is up in the
   same frame as the world swap and no frame of the new level is ever shown
   un-covered. Both classes come off together ~0.4 s later, and the transition
   (restored the instant -cut goes) fades the black away over 0.6 s.

   IT IS DOM, NOT js/effects.js. effects.screenFlash() composites 'lighter' —
   additive — so it can only brighten; a black flash there is a no-op. Measured,
   not assumed.

   POINTER-EVENTS: NONE, ALWAYS. The machine is parked in a doorway and the
   player may already be pushing the stick; a transition that swallowed a drag
   would be a transition that stalls the machine.
   ==================================================================== */
.sm-adv .sm-ah-ride {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #05070a;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.6s ease, visibility 0s linear 0.6s;
  z-index: 9;
}
.sm-adv .sm-ah-ride.sm-ah-ride-on {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.6s ease, visibility 0s;
}
/* The cut: no transition in either direction while this is on. */
.sm-adv .sm-ah-ride.sm-ah-ride-cut { transition: none; }

.sm-ah-ride-inner {
  text-align: center;
  padding: 0 24px;
}
.sm-ah-ride-kicker {
  font-family: var(--sm-mono);
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 3.4px;
  color: var(--sm-gold);
}
.sm-ah-ride-title {
  margin-top: 8px;
  font-family: var(--sm-font, var(--sm-mono));
  font-size: clamp(22px, 5vw, 40px);
  font-weight: 900;
  letter-spacing: 4px;
  color: var(--sm-text);
  text-transform: uppercase;
}
.sm-ah-ride-sub {
  margin-top: 6px;
  font-family: var(--sm-mono);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 2.4px;
  color: var(--sm-dim);
  font-variant-numeric: tabular-nums;
}

/* --- COMPACT / PORTRAIT: the same room, tightened -----------------------
 * THE HOLD ARITHMETIC IS GONE, AND ITS ABSENCE IS THE POINT. This panel used to
 * be pinned above the hold box by adding up --sm-ah-hold-base and a published
 * row count, because it could appear while the player was still driving and it
 * was not allowed to cover the manifest the sell decision was weighed against.
 * Neither half of that is true any more: the panel opens only when the machine
 * is INSIDE the cage, and SELL now states the hold's whole worth on its own
 * plate in 20 px type — so the number the manifest was being consulted for is
 * on the panel itself. Centred, and nothing to measure.
 *
 * WHAT CHANGES ON A PHONE is only the fit: full width inside the gutters, a
 * little less padding, and the type steps down a point where it can afford to.
 * The list scrolls (see .sm-ah-lift-list), so a five-level mine on a 667 px
 * landscape phone loses nothing — and RETURN TO MINE stays pinned to the foot
 * where the thumb is. */
/* ON A PHONE IT HANGS FROM THE BOTTOM, NOT THE MIDDLE — and that is a fix, not
 * a preference. Centred on a 844x390 landscape phone the panel is 830x343 in a
 * 390 px window, which put its head (and the dismiss cross in the head's right
 * corner) directly underneath the sound and pause buttons: those sit at z-index
 * 8, this at 7, so they drew straight over the cross. Measured on the shot.
 *
 * Anchoring to the bottom edge fixes it by construction — the head can never
 * reach the top strip whatever the panel's height — and it is the better phone
 * layout anyway: RETURN TO MINE ends up exactly where the thumb already rests,
 * which is the same argument the joystick is placed by. The max-height keeps a
 * clear lane along the top on the shortest screens.
 *
 * The wide layout stays centred: there is room for everything, and a panel this
 * size hanging off one edge of a 1280 px window reads as a drawer. */
.sm-adv.sm-compact .sm-ah-lift {
  width: calc(100% - var(--sm-gutter) * 2);
  top: auto;
  bottom: calc(var(--sm-gutter) + env(safe-area-inset-bottom, 0px));
  max-height: calc(100% - 68px);
  padding: 10px 11px 11px;
  transform: translateX(-50%) translateY(12px);
}
.sm-adv.sm-compact .sm-ah-lift.sm-ah-lift-on { transform: translateX(-50%); }
.sm-adv.sm-compact .sm-ah-door-acts { gap: 6px; margin-bottom: 8px; }
.sm-adv.sm-compact .sm-ah-door-acts .sm-ah-doorbtn { min-height: 54px; }
.sm-adv.sm-compact .sm-ah-door-acts .sm-ah-doorval { font-size: 14px; }
.sm-adv.sm-compact .sm-ah-liftgo { min-height: 36px; gap: 8px; padding: 0 9px; }
.sm-adv.sm-compact .sm-ah-liftbuy { min-height: 36px; min-width: 60px; }
.sm-adv.sm-compact .sm-ah-door-return { min-height: 48px; }
.sm-adv.sm-compact .sm-ah-door-return .sm-ah-doorlbl { font-size: 11.5px; letter-spacing: 2px; }
.sm-adv.sm-compact .sm-ah-door-map { min-height: 48px; }
.sm-adv.sm-compact .sm-ah-unlock { padding: 8px 9px; margin-bottom: 8px; }
.sm-adv.sm-compact .sm-ah-unlock-body { font-size: 9px; line-height: 1.5; }

/* --- A PHONE ON ITS SIDE IS THE TIGHT CASE, and it has its own budget ---
 * `.sm-compact:not(.sm-portrait)` IS the landscape phone — ui.js publishes both
 * classes and this file may not invent a fourth (ARCHITECTURE.md §4: the whole
 * phone layout hangs off those three and nothing else sets them), so a height
 * media query is out and this selector is exactly right anyway.
 *
 * WHY IT NEEDS ONE. Measured at 844x390 with the unlock box up: the fixed parts
 * of the column — head, trade plates, notice, note, foot — came to 272 px of a
 * 322 px panel, leaving 50 px for the ladder. That is one row and a sliver of
 * the next, and a row sliced through the middle reads as a rendering fault
 * rather than as "scroll for more". Every number below buys height back for the
 * list; nothing here changes what is on screen, only how tightly it is set. */
.sm-adv.sm-compact:not(.sm-portrait) .sm-ah-lift { max-height: calc(100% - 54px); }
.sm-adv.sm-compact:not(.sm-portrait) .sm-ah-lift-head { margin-bottom: 7px; padding-bottom: 6px; }
.sm-adv.sm-compact:not(.sm-portrait) .sm-ah-door-acts { margin-bottom: 7px; }
.sm-adv.sm-compact:not(.sm-portrait) .sm-ah-door-acts .sm-ah-doorbtn { min-height: 44px; }
.sm-adv.sm-compact:not(.sm-portrait) .sm-ah-door-acts .sm-ah-doorval { font-size: 13px; }
.sm-adv.sm-compact:not(.sm-portrait) .sm-ah-unlock { padding: 6px 9px; margin-bottom: 7px; }
.sm-adv.sm-compact:not(.sm-portrait) .sm-ah-unlock-title { font-size: 10px; }
.sm-adv.sm-compact:not(.sm-portrait) .sm-ah-unlock-body { font-size: 8.5px; line-height: 1.45; }
/* TWO FULL ROWS, ALWAYS. Below this the list stops being a list. */
.sm-adv.sm-compact:not(.sm-portrait) .sm-ah-lift-list { min-height: 80px; }
.sm-adv.sm-compact:not(.sm-portrait) .sm-ah-lift-note { margin-top: 6px; }
.sm-adv.sm-compact:not(.sm-portrait) .sm-ah-door-foot { margin-top: 7px; }
.sm-adv.sm-compact:not(.sm-portrait) .sm-ah-door-return,
.sm-adv.sm-compact:not(.sm-portrait) .sm-ah-door-map { min-height: 42px; }

/* TINY (a very short or very narrow phone). One more step down, and the two
 * trade plates keep their grid — a stacked SELL and REFUEL would push the
 * ladder off the bottom, which is worse than smaller numbers. */
.sm-adv.sm-tiny .sm-ah-lift { padding: 9px 10px 10px; }
.sm-adv.sm-tiny .sm-ah-door-acts .sm-ah-doorbtn { min-height: 48px; }
.sm-adv.sm-tiny .sm-ah-door-acts .sm-ah-doorval { font-size: 12.5px; }
.sm-adv.sm-tiny .sm-ah-liftname { font-size: 10px; }
.sm-adv.sm-tiny .sm-ah-liftgo { min-height: 34px; }
.sm-adv.sm-tiny .sm-ah-liftbuy { min-height: 34px; }
.sm-adv.sm-tiny .sm-ah-door-return { min-height: 44px; }
.sm-adv.sm-tiny .sm-ah-door-return .sm-ah-doorlbl { font-size: 10.5px; }
.sm-adv.sm-tiny .sm-ah-door-map { min-height: 44px; }

/* --- ...and the banner gets out of its way ------------------------------
 * Under the info bar rather than over the panel. A banner is on screen for two
 * seconds; the panel is a decision being made. */
.sm-adv.sm-compact .sm-ah.sm-ah-lift-on .sm-ah-alert {
  top: calc(var(--sm-top-y) + var(--sm-ah-barh) + 10px);
  bottom: auto;
}
