/* arcade-shell.css — one way of presenting every game on a phone.
 *
 * THE PROBLEM, IN MEASUREMENTS RATHER THAN ADJECTIVES.
 *
 * On a 375x812 phone, Grave Stakes today spends 150px on a header and wallet strip,
 * 361px on the board, and 226px on controls. The board gets 44% of the screen and is
 * already 96% of the available WIDTH — so "make the canvas bigger" cannot be done by
 * resizing it. The only space left to win is the 47% spent on everything else.
 *
 * THE SHELL. Three bands, fixed to the viewport, no page scroll:
 *
 *   ┌─────────────────────────┐  BAR   ~44px: back, balance, sound. One line.
 *   ├─────────────────────────┤
 *   │                         │  GAME  everything else. The board lives here and is
 *   │          GAME           │        the only thing that grows.
 *   │                         │
 *   ├─────────────────────────┤
 *   └─────────────────────────┘  DOCK  ~92px: stake, the action button, and a button
 *                                      that opens the paytable as a sheet.
 *
 * That is 136px of chrome instead of 376, and the game takes the other 82%.
 *
 * WHY THE GAME BAND IS A GRID ROW AND NOT A max-height.
 *
 * The first attempt at this capped the play surface with max-height and collapsed
 * Bonefall's canvas from 298px to 78px. That canvas is sized in JavaScript from its
 * container, so the cap shrank the container, the JS shrank the canvas to match, and
 * the next measurement was smaller again.
 *
 * The loop only exists when the container's size depends on its CONTENT while the
 * content depends on the CONTAINER. `minmax(0, 1fr)` breaks it: the row's height comes
 * from the viewport, so a canvas measuring its parent gets the same answer every time
 * however small it makes itself. Same intent as before, no feedback path.
 *
 * WHY dvh. The address bar slides away as you scroll, so `vh` is the height the
 * viewport reaches at its TALLEST — meaning a 100vh element runs underneath the
 * browser chrome. `dvh` tracks the height that is actually visible now.
 */

/* Phones in EITHER orientation. `max-width` alone is a portrait test: the same handset
   turned sideways is 863px wide and got the desktop layout on a 388px-tall screen. */
@media (max-width: 760px), (max-height: 560px) {

  html.arcade-shell,
  html.arcade-shell body {
    margin: 0;
    padding: 0;
    /* The page IS the screen. Nothing scrolls; the game does not run off the bottom. */
    overflow: hidden;
    overscroll-behavior: none;
  }

  html.arcade-shell body {
    position: fixed;
    inset: 0;
    /* Belt and braces against sideways growth: a phone layout that scrolls
       horizontally is broken however tidy the vertical arrangement is. */
    max-width: 100vw;
    overflow-x: hidden;
    height: 100vh;
    height: 100dvh;
    display: grid;
    /* bar / status / GAME / dock. Only the game row is flexible — the other three
       are as small as their contents allow, so every pixel the chrome does not need
       goes to the board rather than to padding. */
    /* bar / wallet / status / GAME / dock. Only the game row is flexible. */
    grid-template-rows: auto auto auto minmax(0, 1fr) auto;
    /* ONE COLUMN, THE FULL WIDTH OF THE SCREEN.
     *
     * Without this the implicit column is `auto`, which means "as wide as the widest
     * band" — and on Grave Stakes the dock happens to be full width, so the column was
     * 360px and the omission never showed. On Bonefall, Last Breath, Dead Reckoning and
     * Buried Fortune nothing is intrinsically wide, so the whole shell shrink-wrapped to
     * 267px and sat in a 93px gutter: a phone layout using three-quarters of the phone.
     *
     * minmax(0, 1fr) rather than 1fr because a bare 1fr has an `auto` minimum, so a
     * single wide child (a canvas, a long status line) can still push the column past
     * the screen and reintroduce the sideways scroll the rule above is guarding. */
    grid-template-columns: minmax(0, 1fr);
    /* Notches and the home indicator. Without this the dock sits under the bar at the
       bottom of an iPhone and the action button is genuinely unreachable. */
    padding-top: env(safe-area-inset-top);
    padding-bottom: env(safe-area-inset-bottom);
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
    box-sizing: border-box;
  }

  /* ── BAND 1: the bar ──────────────────────────────────────────────────────── */
  .shell-bar {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 4px 10px;
    min-height: 40px;
    border-bottom: 1px solid rgba(255, 255, 255, .07);
    background: rgba(4, 10, 8, .72);
    backdrop-filter: blur(6px);
  }
  .shell-bar .shell-back {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 32px; height: 32px;
    border-radius: 9px;
    border: 1px solid rgba(255, 255, 255, .12);
    background: rgba(255, 255, 255, .05);
    color: inherit;
    font-size: 16px;
    text-decoration: none;
  }
  .shell-bar .shell-title {
    flex: 1 1 auto;
    min-width: 0;
    font-weight: 800;
    font-size: 12px;
    letter-spacing: .14em;
    text-transform: uppercase;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    opacity: .8;
  }
  /* Balances stay visible at all times: it is the number a player checks before every
     decision, and burying it in a menu means opening the menu before every decision. */
  .shell-bar .shell-balances {
    flex: 0 0 auto;
    display: flex;
    gap: 10px;
    font-size: 11px;
    font-weight: 800;
    white-space: nowrap;
  }
  .shell-bar .shell-balances b { font-weight: 900; font-size: 12px; }
  /* THE REAL WALLET, compacted for the bar.
     Every cell is a control — Get Credits, the Prize Counter, the coins and loyalty
     panels — so it is moved in whole rather than rebuilt, and only its SIZE is
     changed here. Outranked with html.arcade-shell because the cabinet's own inline
     styles load after this file and would otherwise win. */
  /* The wallet's own row: full width, cells evenly spread, comfortable targets. */
  .shell-wallet-row {
    display: flex;
    justify-content: center;
    padding: 4px 8px 0;
    overflow: hidden;
  }
  html.arcade-shell .shell-wallet {
    display: flex !important;
    align-items: center;
    gap: 6px !important;
    padding: 0 !important;
    margin: 0 !important;
    background: none !important;
    border: 0 !important;
    max-width: 100%;
  }
  /* ALL FOUR THE SAME SIZE.
     The cabinet marks server coins and loyalty as `secondary` and styles them
     smaller, which is right in its own layout and reads as broken in a row of four:
     two cells 44px tall and two 35px, sitting at different heights with their values
     on different lines. In a row they are peers, so they are sized as peers. */
  html.arcade-shell .shell-wallet { align-items: stretch !important; }
  html.arcade-shell .shell-wallet .wallet-cell,
  html.arcade-shell .shell-wallet .wallet-cell.secondary {
    display: flex !important;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0 !important;
    min-width: 0;
    flex: 1 1 0;
    height: auto !important;
    min-height: 0 !important;
    font-size: inherit !important;
    padding: 4px 6px !important;
    margin: 0 !important;
    border-radius: 8px;
    line-height: 1.12;
    white-space: nowrap;
    /* Still obviously tappable — these open panels and the buy flow, and a control
       that looks like a label does not get pressed. */
    border: 1px solid rgba(255,255,255,.10) !important;
    background: rgba(255,255,255,.04) !important;
  }
  html.arcade-shell .shell-wallet .wallet-icon { display: none !important; }
  html.arcade-shell .shell-wallet .wallet-cell.secondary .wallet-label,
  html.arcade-shell .shell-wallet .wallet-label {
    font-size: 7px !important; letter-spacing: .05em; opacity: .6;
    overflow: hidden; text-overflow: ellipsis; max-width: 100%;
  }
  html.arcade-shell .shell-wallet .wallet-cell.secondary .wallet-value,
  html.arcade-shell .shell-wallet .wallet-value { font-size: 12px !important; font-weight: 900; }
  html.arcade-shell .shell-wallet { width: 100%; justify-content: space-between; }

  /* The action button and the info button, on one line. */
  .shell-action-row {
    display: flex;
    align-items: stretch;
    gap: 8px;
    width: 100%;
  }
  .shell-action-row > .action,
  .shell-action-row > button:not(.shell-info) { flex: 1 1 auto; min-width: 0; }
  .shell-action-row .shell-info {
    flex: 0 0 auto;
    width: 52px;
    border-radius: 12px;
    border: 1px solid rgba(255,255,255,.14);
    background: rgba(255,255,255,.06);
    color: inherit;
    font-size: 17px;
    font-weight: 900;
  }

  /* Two bare numbers behind two symbols is a puzzle. A three-letter caption above each
     costs 8px of height in a bar that already exists and removes the guesswork. */
  .shell-bar .shell-balances span {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    line-height: 1.15;
  }
  .shell-bar .shell-balances i {
    font-style: normal;
    font-size: 8px;
    letter-spacing: .08em;
    opacity: .55;
  }
  /* Four values in a 360px bar is tight, so they centre rather than right-align and
     the gaps close up. Tight is fine; missing is not. */
  .shell-bar .shell-balances { gap: 9px; }
  .shell-bar .shell-balances span { align-items: center; }
  @media (max-width: 420px) {
    .shell-bar .shell-balances { gap: 7px; }
    .shell-bar .shell-balances i { font-size: 7px; }
    .shell-bar .shell-balances b { font-size: 11px; }
  }

  /* THE BACKGROUND COMES BACK UP.
   *
   * Baffles: "it's still a little boring. maybe the background could be brighter since
   * we lost the frame?"
   *
   * `.scene::after` lays a vignette that reaches 77% black. That earns its place on a
   * desktop, where it darkens the artwork so a framed board stands out against it.
   * With the frame gone on phones there is nothing to separate, so all it does is
   * bury the art — which is why the screen reads as flat.
   *
   * Softened rather than removed: some darkening still keeps the tiles legible against
   * a busy scene, and a board you cannot read is a worse problem than a dull one. */
  html.arcade-shell .scene::after { opacity: .42 !important; }
  html.arcade-shell .scene { filter: brightness(1.18) saturate(1.12); }

  /* The tiles need their own contrast now the scene behind them is livelier. */
  .shell-game .board-stage {
    background: rgba(3, 10, 8, .34);
    backdrop-filter: blur(1px);
  }

  /* NOTHING IN THE BAR MAY WIDEN THE PAGE.
     Adding the fullscreen and Install buttons pushed the bar past 360px, and because a
     flex row will happily exceed its container, the whole grid grew with it: the board
     was cut off on the right, the "12" mine button vanished, and Install was sliced in
     half. A bar is a fixed-width strip and must behave like one. */
  .shell-bar { overflow: hidden; max-width: 100%; }
  .shell-bar > * { min-width: 0; }

  /* On a genuinely narrow screen the game's name is the first thing to go. The player
     tapped it in the lobby ten seconds ago and the board is right there; the balances
     and the controls are worth more than the reminder. */
  @media (max-width: 420px) {
    /* The title stays now — the bar lost two buttons and gained the room. */
    .shell-bar .shell-title { font-size: 11px; }
    .shell-bar .fs-install { padding: 0 7px; font-size: 10px; }
  }

  /* ── BAND 2: the status line ──────────────────────────────────────────────── */
  /* One line, always visible. What the game is telling you right now — "1 safe tile,
     keep going?" — is read constantly during a round, so it cannot live behind a
     button; but it also does not need the 51px the cabinets give it. */
  .shell-status {
    padding: 2px 12px;
    min-height: 20px;
    font-size: 12px;
    line-height: 1.4;
    text-align: center;
    color: #a9c4b4;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .shell-status .statusbar {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 0 !important;
    margin: 0 !important;
    min-height: 0 !important;
    background: none !important;
    border: 0 !important;
  }
  /* Cabinets stack a label above each value. Side by side on one line here — the
     labels are short and the vertical space is worth more than the tidiness. */
  .shell-status .statusbar > * {
    display: flex !important;
    align-items: baseline;
    gap: 5px;
    padding: 0 !important;
    margin: 0 !important;
    border: 0 !important;
    background: none !important;
    font-size: 11px !important;
  }

  /* The live readout, once lifted out of the board. It was absolutely positioned in
     there and covered the bottom row of tiles at phone sizes. */
  .shell-metrics {
    position: static !important;
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: 10px;
    margin: 0 !important;
    padding: 0 !important;
    transform: none !important;
    inset: auto !important;
    background: none !important;
    border: 0 !important;
  }
  .shell-metrics > * {
    display: flex !important;
    align-items: baseline;
    gap: 4px;
    padding: 0 !important;
    margin: 0 !important;
    border: 0 !important;
    background: none !important;
    font-size: 11px !important;
    white-space: nowrap;
  }
  /* Upright there is width to spare, so the status line and the readout share a row. */
  /* The status items and the live readout share a row, and between them they can run
     wider than the screen — the screenshot showed "MULTIPLIER 1.00x" sliding off the
     right edge. The row clips instead of growing, and the labels shrink before the
     values do, because the value is the part being read. */
  /* Just the message now. With the numbers moved under the board there is room for it
     to be read rather than truncated to "Choose(". */
  .shell-status {
    display: flex; align-items: center; justify-content: center;
    gap: 8px; overflow: hidden; max-width: 100%;
    font-size: 13px;
  }
  .shell-status .statusbar { flex-wrap: wrap; justify-content: center; }
  /* "DIG STATUS" as a caption above the sentence it introduces is a label for a label.
     The sentence says what it is. */
  /* `<span class="label">Dig status</span>` above `<strong>Choose your risk</strong>`
     is a caption for a sentence that already explains itself. Targeted by its real
     class — guessing at "first child" left it on screen. */
  /* The game's name above the status message. Quiet, because it never changes — the
     message underneath it is the part that does. */
  .shell-caption {
    display: block;
    font-size: 9px;
    font-weight: 800;
    letter-spacing: .16em;
    text-transform: uppercase;
    opacity: .5;
    white-space: nowrap;
  }
  .shell-status { flex-direction: column; gap: 1px; padding: 3px 12px; }

  .shell-status .label { display: none !important; }
  .shell-status .status { display: flex; align-items: center; }
  .shell-status strong { font-size: 13px !important; font-weight: 700; }
  .shell-status > * { min-width: 0; }
  .shell-status .statusbar > *,
  .shell-metrics > * { overflow: hidden; }

  /* ── BAND 2: the game ─────────────────────────────────────────────────────── */
  .shell-game {
    position: relative;
    min-height: 0;          /* without this a grid row refuses to shrink below content */
    overflow: hidden;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 6px;
  }

  /* The live numbers, in the gap a square board always leaves on a tall screen.
     Three cards rather than a cramped line — they have room here, and this space was
     doing nothing. */
  .shell-readouts {
    display: flex;
    align-items: stretch;
    justify-content: center;
    gap: 8px;
    flex: 0 0 auto;
    width: 100%;
    max-width: 100%;
  }
  .shell-readouts > * {
    flex: 1 1 0;
    min-width: 0;
    display: flex !important;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1px;
    padding: 6px 4px !important;
    margin: 0 !important;
    border: 1px solid rgba(255,255,255,.07) !important;
    border-radius: 10px;
    background: rgba(255,255,255,.03) !important;
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
  }
  /* Label small and quiet, value large and bright — the value is what is glanced at
     mid-round, the label only explains it the first time. */
  .shell-readout small,
  .shell-readout .label { display: block !important; font-size: 9px !important; opacity: .62; letter-spacing: .09em; }
  .shell-readout b,
  .shell-readout strong { font-size: 15px !important; font-weight: 900; }
  /* Anything the game puts in here is centred and may use the whole band, but may not
     force it taller — the band's height belongs to the viewport, not to the content.
   *
   * The cap is VIEWPORT-derived, not `100%`. Two reasons, and the second is the one
   * that cost a day:
   *
   * `max-height: 100%` needs a parent with a definite height to resolve against, and
   * a grid item does not reliably provide one — so a square board with aspect-ratio
   * kept its width-driven height, overflowed its row, and sat underneath the dock.
   *
   * And `100dvh minus the fixed bands` cannot start a shrink loop, because it does not
   * depend on the content at all. That is exactly what the earlier attempt got wrong:
   * capping against something the content influenced made Bonefall's canvas chase
   * itself down to 78px. The number below is the viewport and nothing else.
   *
   * --shell-chrome is the bar, the status line and the dock added up. */
  html.arcade-shell { --shell-chrome: 250px; }
  .shell-game > * {
    max-width: 100%;
    max-height: calc(100dvh - var(--shell-chrome));
  }
  /* NOT canvas. Bonefall and Last Breath measure their OWN bounding box in JavaScript
     and resize themselves to match, so any CSS cap on the canvas is read back as the
     new size and shrinks again on the next frame. They size themselves from the band,
     which is already correct, and are left alone. */
  .shell-game > canvas { max-height: none; }

  /* The emptied original layout. See `shell-retired` in arcade-shell.js — it is a grid
     row of body, and an empty row carrying `min-height: 100vh` starves the board. */
  html.arcade-shell body > main.shell-retired { display: none !important; }

  /* See `fit` in arcade-shell.js. These wrappers have no size of their own — the board
     is an inner element sized by aspect-ratio alone — so the wrapper is given the whole
     band and the board centres inside it. Flagged per cabinet, never applied broadly,
     for the canvas reason directly above. */
  .shell-game > .shell-fit {
    width: 100%;
    height: 100%;
    min-width: 0;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .shell-game > .shell-fit > * { max-width: 100%; max-height: 100%; }

  /* `fit: 'fill'` — the same problem, the opposite remedy. Midnight Doors' board is a
     six-column `1fr` grid, and a grid gets its track sizes from a DEFINITE width; give
     it a shrink-to-fit box and every track resolves to zero. So it is stretched rather
     than centred, and left as a block so the grid inside behaves normally. */
  .shell-game > .shell-fill {
    width: 100%;
    height: 100%;
    min-width: 0;
    min-height: 0;
    display: block;
  }

  /* SQUARE BOARDS SHRINK SQUARELY.
     Capping only the height left Grave Stakes at 348 wide by 250 tall — it fitted, and
     every tile on it was an oblong. These boards carry an explicit width, which
     aspect-ratio cannot override, so the width has to be capped by the same number.
     Listed by name rather than applied to everything: a WIDE game capped by the height
     budget would be needlessly squeezed. */
  .shell-game > .board-stage,
  .shell-game > .crate-stage,
  .shell-game > .card-shell,
  /* `.wheel-wrap` for one commit — a class Misfortune does not have. The wheel is
     `.wheel-stage`, and being square it is exactly what this rule is for. */
  .shell-game > .wheel-stage {
    max-width: min(100%, calc(100dvh - var(--shell-chrome)));
  }

  /* THE DOCK, TIGHTENED. It came out at 166px against a 96px budget, and every pixel
     it takes comes straight off the board. Cabinet controls are built for a desktop
     panel: generous padding, a label above every value, buttons sized for a mouse.
     Tap targets stay at 44px, which is the one dimension not worth reclaiming. */
  .shell-dock .controls {
    display: flex !important;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px !important;
    padding: 0 !important;
    margin: 0 !important;
    background: none !important;
    border: 0 !important;
  }
  .shell-dock .controls > * { margin: 0 !important; }
  /* The stepper's number was clipped to "5(" — it needs room for three digits plus a
     comma, because 500 is a legal stake. */
  .shell-dock .betbox { min-width: 132px; }

  /* NOTE FOR WHOEVER PICKS THIS UP.
   *
   * The dock is crowded upright: the stepper and four mine buttons share one 360px
   * row. Giving them a row each is the right fix and I could not land it blind.
   *
   * What was tried and why each failed, so it is not repeated:
   *   - flex on the children: `.controls` is a GRID, so flex properties do nothing
   *   - `display: flex !important`: lost to the cabinet's own inline <style>, which
   *     comes after this <link> and wins at equal specificity
   *   - `html.arcade-shell` prefix: DID win, betbox grew from 116 to 223 — but
   *   - `grid-template-columns: 1fr !important` still produced three columns, and
   *   - `grid-auto-flow: row !important` did not change that either
   *
   * So the three columns are declared somewhere still unfound — most likely
   * grid-template-areas, or an explicit grid-column on the children. Find that first;
   * every rule above is treating a symptom. The last attempt squeezed the mine
   * buttons to 11px, which is why this is reverted rather than left in. */  /* Headings inside the controls name things the buttons already say. */
  /* Headings inside the controls name things the buttons already say — EXCEPT the
     ones inside a control-head, which are the half that says WHAT is being chosen.
     Hiding those left the picker captioned "LOW RISK" with nothing anywhere saying
     the numbers were mine counts. */
  .shell-dock .controls h2,
  .shell-dock .controls h3,
  .shell-dock .controls .hint,
  .shell-dock .controls .label:not(.control-head .label) { display: none !important; }
  html.arcade-shell .shell-dock .control-head .label { display: inline !important; }
  .shell-dock .controls button { min-height: 44px; }

  /* The mine picker wraps its four buttons onto two rows in a narrow dock, costing
     81px for what is one row of choices. Forced onto one line: four buttons at 44px
     across 168px is comfortable, and the row it saves goes to the board. */
  .shell-dock .minepick {
    display: flex !important;
    flex-wrap: nowrap !important;
    gap: 4px !important;
  }
  .shell-dock .minepick button { flex: 1 1 0; min-width: 0; padding-inline: 0 !important; }

  /* THE CONTROL CAPTIONS COME BACK.
   *
   * I hid these to save 14px each, on the reasoning that a stepper showing "50" and a
   * picker showing which button is lit explain themselves. That is true of the
   * stepper and WRONG of the picker: 3, 5, 8, 12 are mine counts, and without the
   * caption nothing on screen says so. Baffles: "we aren't telling people in the
   * controls what those are for."
   *
   * A number with no unit is not a control, it is a riddle. 14px is a cheap price for
   * knowing what you are choosing, and the dock has the room now that the action
   * button has moved to its own row. */
  html.arcade-shell .shell-dock .control-head {
    display: flex !important;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    padding: 0 2px 2px !important;
    margin: 0 !important;
    font-size: 9px !important;
    letter-spacing: .08em;
    text-transform: uppercase;
    opacity: .62;
    line-height: 1.2;
  }
  /* The right-hand half is the live one — "LOW RISK", "EXTREME" — so it keeps its
     colour and weight while the name beside it stays quiet. */
  html.arcade-shell .shell-dock .control-head > *:last-child {
    opacity: 1;
    font-weight: 800;
  }

  /* The cabinets already carry their own info button. Mine would be a second one
     doing the same job, side by side. */
  .shell-dock .arcade-info-button + .shell-info,
  .shell-dock .controls .arcade-info-button ~ .shell-info { display: none !important; }

  /* THE DECORATIVE FRAME COMES OFF.
   *
   * Baffles: "maybe we should remove the frame? there is dead space around the canvas".
   * He is right, and it is worse than it looks. The board measures 348px but the tile
   * grid inside it is only 277 — the ornate pipework is eating 20% of the play area,
   * so every tile is a fifth smaller than it needs to be.
   *
   * On a desktop that frame is lovely and costs nothing, because there is space to
   * spare. On a phone it is 71px of screen spent on scenery while the thing you tap
   * shrinks. The tiles grow from 53px to about 66 without it.
   *
   * PHONES ONLY — this whole file is inside a phone media query, so the desktop
   * cabinet keeps its frame exactly as designed. */
  /* EVERY cabinet has one; they just disagree on what to call it. `.frame` on Grave
     Stakes and the two workspace cabinets, `.frame-art` on the reels, Bonefall, Last
     Breath and Buried Fortune, `.stage-frame` on the packs and the doors, `.wheel-frame`
     on Misfortune. Naming them one at a time is how four of them survived the last pass. */
  .shell-game .frame,
  .shell-game .frame-art,
  .shell-game .stage-frame,
  .shell-game .wheel-frame,
  .shell-game .mobile-frame { display: none !important; }

  /* AND THE SPACE THE FRAME WAS RESERVING.
   *
   * Hiding the art alone changes nothing you can measure: the padding that held it is on
   * the CONTAINER and survives its removal, so the board keeps the hole and loses only
   * the decoration in it. These three are the cabinets that pad for their frame —
   *
   *   Reanimated Reels  43/40/42/40  reel window  267x147 -> 348x232   (+30% wide)
   *   Buried Fortune    32/25/33/25  playfield    273x153 -> 323x218   (+18% wide)
   *   Midnight Doors    28/17/35/17  doors        314x329 -> 348x392
   *
   * — and in each case the inner surface already fills the content box, so it simply
   * grows into what it is given. */
  /* `html.arcade-shell` because Buried Fortune declares `padding: 9.3% 7.2% 9.5%
     !important` in its own inline <style>, which loads AFTER this file — at equal
     specificity the later !important wins, and the playfield sat unchanged at 273x153
     while the frame it was making room for had already gone. */
  html.arcade-shell .shell-game .machine,
  html.arcade-shell .shell-game .card-shell,
  html.arcade-shell .shell-game .shell-fill.stage { padding: 0 !important; }

  /* Buried Fortune again, with an ID in the selector.
     Its own rule is `body.arcade-game-document:has(#newCard) .card-shell`, and :has()
     inherits the specificity of its argument — so that `#newCard` outranks any number of
     classes I add. Matching the ID is the only thing that wins; more classes never would. */
  html.arcade-shell body:has(#newCard) .shell-game .card-shell { padding: 0 !important; }

  /* THE CANVAS GAMES' INSET. Bonefall and Last Breath position their canvas absolutely,
     about 24px in on every side, to sit within the frame art. The art is gone, so the
     canvas takes the whole box — 299x287 to 348x334 on Bonefall.
     Safe by the same argument as the wheel: these canvases read their box to choose a
     RESOLUTION, they never write a size back into the layout, so there is no loop. */
  html.arcade-shell .shell-game .canvas-wrap > canvas,
  html.arcade-shell .shell-game .stage > canvas {
    inset: 0 !important;
    /* 100%, NOT auto. A canvas is a replaced element: `width: auto` resolves to its
       INTRINSIC size — the width/height attributes, which these set to 571 for a
       high-DPI backing store — and a replaced element does not stretch to fill `inset`
       the way a div does. `auto` here blew the board up to 571px inside a 348px box. */
    width: 100% !important;
    height: 100% !important;
  }

  /* THE BEZEL, TOO. Heads Will Roll, Dead Reckoning and The Ascent inset their screen by
     16-19px on every side to sit within the frame art. With the art gone that inset is
     just a margin around the only part anybody looks at. */
  html.arcade-shell .shell-game .display,
  html.arcade-shell .shell-game .cabinet > .screen {
    inset: 0 !important;
    width: auto !important;
    height: auto !important;
  }

  /* MISFORTUNE'S WHEEL GROWS INTO THE SPACE THE RIM LEFT.
   *
   * `#wheel` is pinned at 63.1% and nudged to top 52.43% — numbers chosen to seat it
   * inside the rim art, not to size the game. Hide the rim and the wheel is a small disc
   * floating in an empty 305px box: removing the frame would have made Misfortune LOOK
   * worse while technically doing as asked. At 92% it fills the stage and the pointer
   * still meets the rim.
   *
   * Safe against the canvas rule elsewhere in this file: the wheel's JS reads its box to
   * pick a RESOLUTION (`r.width * dpr`), it does not feed a size back into the layout, so
   * there is no loop to start. */
  html.arcade-shell .shell-game #wheel {
    width: 92% !important;
    height: 92% !important;
    top: 50% !important;
  }
  /* The backing disc sat at inset 16% to ring a 63% wheel; it would now be buried. */
  html.arcade-shell .shell-game .wheel-stage:before { inset: 2% !important; }
  .shell-game .grid {
    inset: 0 !important;
    width: auto !important;
    height: auto !important;
  }
  /* Without the frame the grid needs its own edge, or it floats on the background
     with nothing to say where the board stops. */
  .shell-game .board-stage {
    border-radius: 14px;
    outline: 1px solid rgba(156, 255, 0, .16);
    outline-offset: -1px;
  }
  .shell-game .board-glow { inset: 0 !important; }

  /* ── BAND 3: the dock ─────────────────────────────────────────────────────── */
  .shell-dock {
    display: flex;
    /* A COLUMN, so the controls and the action row stack. As a row the action row sat
       BESIDE the controls and START DIGGING was squeezed to 92px. */
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    padding: 8px 10px;
    border-top: 1px solid rgba(255, 255, 255, .07);
    background: rgba(4, 10, 8, .82);
    backdrop-filter: blur(6px);
  }
  .shell-dock > .shell-dock-main { flex: 1 1 auto; min-width: 0; }
  .shell-dock button { touch-action: manipulation; }
  /* 44px is the smallest target most people hit reliably with a thumb; below that the
     miss rate climbs fast, and a mis-tap on a staking button costs a round. */
  /* Upright the dock holds it and the bar copy stays out of the way. */
  .shell-bar .shell-info { display: none; }
  .shell-dock .shell-info {
    flex: 0 0 auto;
    width: 44px; height: 44px;
    border-radius: 12px;
    border: 1px solid rgba(255, 255, 255, .14);
    background: rgba(255, 255, 255, .06);
    color: inherit;
    font-size: 17px;
    font-weight: 900;
  }

  /* Panels the shell emptied out. Their contents moved into the bands; what is left
     is a rounded box with nothing in it. */
  .shell-orphan { display: none !important; }

  /* The cabinet's own info button and drawer, hidden by RULE rather than by a class.
     Adding a class was not enough: the cabinet re-docks its button into the controls
     after the shell has built, so the class was applied and then bypassed and two
     buttons appeared side by side. A rule it never touches cannot be undone by code
     that runs later. */
  html.arcade-shell .arcade-info-button,
  html.arcade-shell .arcade-info-drawer { display: none !important; }

  /* The fullscreen and Install buttons, once moved into the bar. As position:fixed
     they sat on top of the action button — the screenshot showed "Install" printed
     across START DIGGING, which is both ugly and a mis-tap waiting to happen. */
  .shell-bar .fs-toggle,
  .shell-bar .fs-install {
    position: static;
    right: auto; bottom: auto;
    flex: 0 0 auto;
    height: 30px;
    margin: 0;
    font-size: 13px;
  }
  .shell-bar .fs-install { padding: 0 9px; font-size: 11px; }

  /* ── LANDSCAPE: side by side, not stacked ─────────────────────────────────────
   *
   * Stacking four bands works upright and falls apart turned sideways: on an 863x388
   * landscape phone the bar, status and dock leave barely 150px for the board, and the
   * screenshot showed the multiplier panel sitting on top of what little was left.
   *
   * Landscape trades height for width, so the layout should too. The game takes the
   * full height on the left; the status line and dock stack in a column on the right,
   * where the width they need is cheap and the height they were eating is not. */
  @media (orientation: landscape) and (max-height: 560px) {
    html.arcade-shell body {
      /* Status and dock had the SAME grid area, so they stacked ON TOP of each other
         and the readout printed straight across the bet stepper. They get a row each,
         with the game spanning both down the left. */
      grid-template-rows: auto auto minmax(0, 1fr);
      grid-template-columns: minmax(0, 1fr) minmax(150px, 34%);
      /* The wallet shares ROW ONE with the bar rather than taking a slot in the
         controls column. Sideways there is 863px of width and the bar uses barely a
         third of it, while the right-hand column is the scarce thing — it holds the
         status, the stake, the picker and the action. Putting the balances up top
         gives that column back to the controls and costs nothing. */
      grid-template-rows: auto auto minmax(0, 1fr);
      grid-template-areas:
        "bar  wallet"
        "game status"
        "game dock";
    }
    .shell-bar  { grid-area: bar; }
    .shell-game { grid-area: game; }
    /* The status line and dock share the right-hand column, stacked. */
    .shell-wallet-row {
      grid-area: wallet;
      align-items: center;
      justify-content: flex-end;
      padding: 4px 10px;
      border-bottom: 1px solid rgba(255, 255, 255, .07);
      background: rgba(4, 10, 8, .72);
    }
    /* SHARE the column, do not size to content.
       Four content-sized cells want about 330px and the column is 293, so three of
       them were clipped straight off the left edge and only LOYALTY survived — a
       wallet showing one of four balances. Sharing the width gives roughly 70px each,
       which fits, and every cell stays a real tap target. */
    html.arcade-shell .shell-wallet {
      width: 100%;
      justify-content: space-between;
      gap: 4px !important;
    }
    html.arcade-shell .shell-wallet .wallet-cell {
      flex: 1 1 0;
      min-width: 0;
      padding: 3px 2px !important;
    }
    html.arcade-shell .shell-wallet .wallet-label { font-size: 6px !important; letter-spacing: 0; }
    html.arcade-shell .shell-wallet .wallet-value { font-size: 10px !important; }
    .shell-status { grid-area: status; }
    .shell-dock   { grid-area: dock; }
    .shell-status,
    .shell-dock {
      align-self: start;
      border-top: 0;
      background: none;
      backdrop-filter: none;
    }
    /* In the narrow right-hand column the status items collided with each other and
       with the stepper below — "Choose your risk" was cut to "Choose". Stacked, with
       each label above its value, they read cleanly in a third of the width. */
    .shell-status { padding: 8px 10px 0; white-space: normal; }
    .shell-status .statusbar {
      flex-direction: column;
      align-items: flex-start;
      gap: 3px;
    }
    .shell-status .statusbar > * { font-size: 10px !important; }
    /* The right-hand column is narrow, so the two readouts stack rather than sharing
       a row with the status items. */
    .shell-status { flex-direction: column; align-items: flex-start; gap: 4px; }
    .shell-metrics { justify-content: flex-start; }
    .shell-dock {
      align-self: end;
      flex-wrap: wrap;
      justify-content: center;
    }
    /* The controls stack rather than sitting in a row: the column is narrow, and the
       mine picker squeezed into four vertical slivers is what the screenshot showed. */
    .shell-dock .controls {
      flex-direction: column;
      align-items: stretch;
      width: 100%;
    }
    /* Landscape uses the same single column; nothing extra needed. */
    .shell-dock .minepick { width: 100%; }

    /* THE INFO BUTTON MOVES TO THE BAR IN LANDSCAPE.
       In the dock it was landing on top of the mine picker — present, measurable, and
       to a player simply not there. The dock has no spare row here (stepper, picker
       and action already fill 146 of its 176px), but the bar has clear space beside
       the fullscreen button, and that is where a player looks for help anyway. */
    .shell-dock .shell-info { display: none; }
    .shell-bar .shell-info {
      display: grid;
      place-items: center;
      flex: 0 0 auto;
      width: 30px; height: 30px;
      border-radius: 9px;
      border: 1px solid rgba(255,255,255,.14);
      background: rgba(255,255,255,.06);
      color: inherit;
      font-size: 13px;
      font-weight: 900;
    }

    /* THE DEAD SPACE ON THE LEFT.
     *
     * Baffles: "since we have dead space on landscape, perhaps we can center the game
     * canvas and add one of our characters to the opposite side of the screen from
     * the controls."
     *
     * The cabinets already carry two character images, sitting behind everything at
     * z-index -1 as faint scenery. In landscape the controls take the right, so the
     * LEFT character comes forward to fill the gap and the board centres between
     * them — the screen reads as a scene with a game in it rather than a board shoved
     * against one edge.
     *
     * The right-hand one is hidden: that side is now controls, and a character behind
     * the stake buttons is just noise. */
    .shell-game { justify-content: center; }

    /* Unearthed's page-level 860px breakpoint gives the pack stage a 440px
       min-height. A landscape phone is wider than the portrait breakpoint but only
       375px tall, so that minimum wins over the shell's viewport cap and cuts the
       bottom 118px off the pack. This cabinet has no self-measuring canvas; it is
       therefore safe to remove only its stale desktop minimum and size the stage to
       the shell's measured viewport budget. The five reveal cards stay in one row at
       this width, so they shrink with the stage instead of overflowing it. */
    html.arcade-shell body:has(#ripBtn) .shell-game > .pack-stage {
      min-height: 0 !important;
      height: calc(100dvh - var(--shell-chrome)) !important;
      max-height: calc(100dvh - var(--shell-chrome)) !important;
    }
    html.arcade-shell body:has(#ripBtn) .pack-stage > .pack {
      width: min(220px, 55vw) !important;
      height: 74% !important;
    }
    html.arcade-shell body:has(#ripBtn) .pack-stage > .pack-logo {
      width: min(145px, 37vw) !important;
    }

    html.arcade-shell .host.left {
      display: block !important;
      position: fixed !important;
      left: 0 !important;
      bottom: 0 !important;
      height: 88dvh !important;
      max-width: 26vw !important;
      object-fit: contain;
      object-position: left bottom;
      opacity: .92;
      z-index: 0 !important;
      pointer-events: none;
    }
    html.arcade-shell .host.right { display: none !important; }

    /* The character gets its own strip and the board centres in what remains, so the
       two sit SIDE BY SIDE. A margin on the board was not enough — at 12vw the board
       still started at x110 while the character ran to x224, so the art was simply
       hidden behind the tiles. Reserving the width on the container is what actually
       separates them. */
    .shell-game { padding-left: 27vw; }
    .shell-game .board-stage,
    .shell-game .crate-stage,
    .shell-game > canvas { position: relative; z-index: 1; }
  }

  /* Upright there is no spare width, so the characters stay where they were — faint
     scenery behind the board. */
  @media (orientation: portrait) {
    html.arcade-shell .host { z-index: -1 !important; }
  }

  /* ── THE SHEET: everything that is reference, not action ──────────────────── */
  /* Paytables, odds, fairness notes and rules are read ONCE and then never again in a
     session. On a phone they were taking permanent space for occasional information. */
  .shell-sheet {
    position: fixed;
    inset: 0;
    z-index: 60;
    display: none;
    background: rgba(2, 6, 5, .62);
    backdrop-filter: blur(3px);
  }
  .shell-sheet[open] { display: block; }
  .shell-sheet-panel {
    position: absolute;
    left: 0; right: 0; bottom: 0;
    max-height: 78%;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 14px 14px calc(14px + env(safe-area-inset-bottom));
    border-radius: 18px 18px 0 0;
    border-top: 1px solid rgba(255, 255, 255, .12);
    background: #0b1512;
  }
  .shell-sheet-close {
    position: sticky;
    top: 0;
    float: right;
    width: 36px; height: 36px;
    border-radius: 10px;
    border: 1px solid rgba(255, 255, 255, .14);
    background: rgba(255, 255, 255, .06);
    color: inherit;
    font-size: 18px;
  }

  /* Things that earn their space on a desktop and do not on a phone. Hidden here
     rather than deleted: the same markup still serves the desktop layout. */
  html.arcade-shell .intro,
  html.arcade-shell .fair,
  html.arcade-shell .panel > h1,
  html.arcade-shell .arcade-header-unified,
  html.arcade-shell header { display: none !important; }
}

/* Above 760px nothing here applies and the cabinets lay out exactly as they do today.
   The shell is a phone presentation, not a redesign of the desktop game. */
