/**
 * Realm of Dominion - Material 3 Expressive stylesheet
 * Vanilla CSS, no framework, no web font, no external resource of any kind.
 * The --md-sys-color-* role sets below are static fallbacks for the default seed;
 * M3Theme.apply() overwrites them at runtime in <style id="dyn">, which wins on
 * source order. System fonts only.
 */

:root[data-theme="light"] {
  --md-sys-color-primary: #003ea7;
  --md-sys-color-on-primary: #eeffff;
  --md-sys-color-primary-container: #b5e1ff;
  --md-sys-color-on-primary-container: #000025;
  --md-sys-color-secondary: #324869;
  --md-sys-color-on-secondary: #f9ffff;
  --md-sys-color-secondary-container: #d1dff5;
  --md-sys-color-on-secondary-container: #00030d;
  --md-sys-color-tertiary: #632c74;
  --md-sys-color-on-tertiary: #fff9ff;
  --md-sys-color-tertiary-container: #f1d0fc;
  --md-sys-color-on-tertiary-container: #0b0011;
  --md-sys-color-error: #960000;
  --md-sys-color-on-error: #fff5ef;
  --md-sys-color-error-container: #ffc4b9;
  --md-sys-color-on-error-container: #1b0000;
  --md-sys-color-background: #f8f8fa;
  --md-sys-color-on-background: #030304;
  --md-sys-color-surface: #f8f8fa;
  --md-sys-color-on-surface: #030304;
  --md-sys-color-surface-dim: #d3d4d6;
  --md-sys-color-surface-bright: #feffff;
  --md-sys-color-surface-variant: #dadee4;
  --md-sys-color-on-surface-variant: #292e36;
  --md-sys-color-surface-container-lowest: #feffff;
  --md-sys-color-surface-container-low: #f1f2f3;
  --md-sys-color-surface-container: #eaebed;
  --md-sys-color-surface-container-high: #e3e5e6;
  --md-sys-color-surface-container-highest: #dddee0;
  --md-sys-color-inverse-surface: #151618;
  --md-sys-color-inverse-on-surface: #edeef0;
  --md-sys-color-inverse-primary: #82bfff;
  --md-sys-color-outline: #5d646e;
  --md-sys-color-outline-variant: #b8bec7;
  --md-sys-color-scrim: #000000;
  --md-sys-color-shadow: #000000;
}

:root[data-theme="dark"] {
  --md-sys-color-primary: #82bfff;
  --md-sys-color-on-primary: #000453;
  --md-sys-color-primary-container: #00207f;
  --md-sys-color-on-primary-container: #b5e1ff;
  --md-sys-color-secondary: #abbfdd;
  --md-sys-color-on-secondary: #07162b;
  --md-sys-color-secondary-container: #1b2e4a;
  --md-sys-color-on-secondary-container: #d1dff5;
  --md-sys-color-tertiary: #d8aae7;
  --md-sys-color-on-tertiary: #270032;
  --md-sys-color-tertiary-container: #441253;
  --md-sys-color-on-tertiary-container: #f1d0fc;
  --md-sys-color-error: #ff9589;
  --md-sys-color-on-error: #440000;
  --md-sys-color-error-container: #6e0000;
  --md-sys-color-on-error-container: #ffc4b9;
  --md-sys-color-background: #010101;
  --md-sys-color-on-background: #dddee0;
  --md-sys-color-surface: #010101;
  --md-sys-color-on-surface: #dddee0;
  --md-sys-color-surface-dim: #010101;
  --md-sys-color-surface-bright: #1e1f22;
  --md-sys-color-surface-variant: #292e36;
  --md-sys-color-on-surface-variant: #b8bec7;
  --md-sys-color-surface-container-lowest: #000000;
  --md-sys-color-surface-container-low: #030304;
  --md-sys-color-surface-container: #050607;
  --md-sys-color-surface-container-high: #0e0f11;
  --md-sys-color-surface-container-highest: #191b1d;
  --md-sys-color-inverse-surface: #dddee0;
  --md-sys-color-inverse-on-surface: #151618;
  --md-sys-color-inverse-primary: #003ea7;
  --md-sys-color-outline: #7a818b;
  --md-sys-color-outline-variant: #292e36;
  --md-sys-color-scrim: #000000;
  --md-sys-color-shadow: #000000;
}

:root[data-theme="black"] {
  --md-sys-color-primary: #82bfff;
  --md-sys-color-on-primary: #000453;
  --md-sys-color-primary-container: #00207f;
  --md-sys-color-on-primary-container: #b5e1ff;
  --md-sys-color-secondary: #abbfdd;
  --md-sys-color-on-secondary: #07162b;
  --md-sys-color-secondary-container: #1b2e4a;
  --md-sys-color-on-secondary-container: #d1dff5;
  --md-sys-color-tertiary: #d8aae7;
  --md-sys-color-on-tertiary: #270032;
  --md-sys-color-tertiary-container: #441253;
  --md-sys-color-on-tertiary-container: #f1d0fc;
  --md-sys-color-error: #ff9589;
  --md-sys-color-on-error: #440000;
  --md-sys-color-error-container: #6e0000;
  --md-sys-color-on-error-container: #ffc4b9;
  --md-sys-color-background: #000000;
  --md-sys-color-on-background: #dddee0;
  --md-sys-color-surface: #000000;
  --md-sys-color-on-surface: #dddee0;
  --md-sys-color-surface-dim: #000000;
  --md-sys-color-surface-bright: #050607;
  --md-sys-color-surface-variant: #292e36;
  --md-sys-color-on-surface-variant: #b8bec7;
  --md-sys-color-surface-container-lowest: #000000;
  --md-sys-color-surface-container-low: #000000;
  --md-sys-color-surface-container: #010101;
  --md-sys-color-surface-container-high: #020203;
  --md-sys-color-surface-container-highest: #050607;
  --md-sys-color-inverse-surface: #dddee0;
  --md-sys-color-inverse-on-surface: #151618;
  --md-sys-color-inverse-primary: #003ea7;
  --md-sys-color-outline: #7a818b;
  --md-sys-color-outline-variant: #292e36;
  --md-sys-color-scrim: #000000;
  --md-sys-color-shadow: #000000;
}

:root {
  /* Shape scale */
  --r-none: 0px;
  --r-xs: 4px;
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-lgi: 20px;
  --r-xl: 28px;
  --r-xli: 32px;
  --r-full: 9999px;

  /* Elevation */
  --e1: 0 1px 2px rgb(0 0 0 / .30), 0 1px 3px 1px rgb(0 0 0 / .15);
  --e2: 0 1px 2px rgb(0 0 0 / .30), 0 2px 6px 2px rgb(0 0 0 / .15);
  --e3: 0 4px 8px 3px rgb(0 0 0 / .15), 0 1px 3px rgb(0 0 0 / .30);

  /* Expressive spring motion */
  --m-spatial-fast: 350ms cubic-bezier(.42, 1.67, .21, .9);
  --m-spatial: 500ms cubic-bezier(.38, 1.21, .22, 1);
  --m-effects: 200ms cubic-bezier(.34, .8, .34, 1);

  /* Window size class breakpoints (compact / medium / expanded / large / xl) */
  --bp-medium: 600px;
  --bp-expanded: 840px;
  --bp-large: 1200px;
  --bp-xl: 1600px;

  /* Semantic bridge - every legacy var resolves to an M3 role, so the whole
     sheet is seed-driven without rewriting each rule. */
  --bg: var(--md-sys-color-background);
  --surface: var(--md-sys-color-surface-container-low);
  --panel-bg: var(--md-sys-color-surface-container);
  --panel-border: var(--md-sys-color-outline-variant);
  --accent-color: var(--md-sys-color-primary);
  --text-main: var(--md-sys-color-on-surface);
  --text-muted: var(--md-sys-color-on-surface-variant);
  --shadow: color-mix(in srgb, var(--md-sys-color-shadow) 45%, transparent);

  --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", "Noto Sans TC", system-ui, sans-serif;

  /* Type scale */
  --t-title-l: 22px;
  --t-title-m: 16px;
  --t-title-s: 14px;
  --t-body-m: 14px;
  --t-label-l: 14px;
  --t-label-m: 12px;
  --t-label-s: 11px;

  /* HUD metrics, widened by size class below */
  --hud-gap: 12px;
  /* THE DISPLAY CUTOUT (v5.18.5). index.html asks for `viewport-fit=cover`, so the page owns
     the whole panel including the strip under the status bar and the rounded corners — and
     until now every HUD layer anchored at `--hud-gap` from the raw viewport edge, which put
     the resource bar underneath the clock and the battery. A screenshot does not show this:
     it captures the page, and the page really is that tall. Only the device hides it.
     Each edge gets its own inset, because a phone in landscape has one on ONE side. */
  --edge-t: calc(var(--hud-gap) + env(safe-area-inset-top, 0px));
  --edge-b: calc(var(--hud-gap) + env(safe-area-inset-bottom, 0px));
  --edge-l: calc(var(--hud-gap) + env(safe-area-inset-left, 0px));
  --edge-r: calc(var(--hud-gap) + env(safe-area-inset-right, 0px));
  /* Vertical space the resource bar claims at the very top. 0 while it is a centred pill
     (it sits between the left and right columns); a real height on narrow screens, where
     the bar becomes a full-width strip and everything below has to start under it
     (v3.6.12). Every top-anchored HUD layer adds it. */
  --bar-h: 0px;
  --build-w: 190px;
  --minimap: 140px;
  /* The FAB's edge length. The Epoch-speed pill reserves it plus a gap so the two read
     as one horizontal exclamation mark; the short-screen tier shrinks both together. */
  --fab-w: 56px;
  /* The speed pill is a FIXED width (v5.18.0), not content-width, so the top-right corner
     can be measured rather than guessed. The resource bar is bounded by these two corners,
     which is what keeps it off them: it used to be centred on the whole viewport and, on a
     915px landscape phone, its right edge landed on the pill. */
  --hud-speed-w: 168px;
  --hud-corner-l: min(var(--minimap), calc(var(--hud-top-h) - var(--hud-gap) - var(--bar-h)));
  --hud-corner-r: calc(var(--fab-w) + 8px + var(--hud-speed-w));

  /* --- HUD LAYOUT GRID (v5.18.0) ---------------------------------------------------
     David's ruling. PORTRAIT divides top-to-bottom into FIVE bands: 1 = minimap +
     Epoch speed + the FAB, 2 = bare board, 3 = the virtual pad, 4-5 = every dialog.
     LANDSCAPE divides into THREE rows by SEVEN columns: minimap top-left, speed +
     FAB top-right, the pad's two clusters in the bottom row's outer columns, and the
     dialog dock filling the columns between them.

     The division only holds on a PHONE. On a tablet or a desktop each region stops
     growing at the size it would have on a 1280x720 reference screen - "UI 元件會太大"
     otherwise - and every pixel past the cap goes to the board, which is why the top
     band is anchored to the top and the pad and dock to the bottom.

     1280x720 is measured in CSS pixels, and that is what makes it the right line: a
     1080-device-pixel phone reports ~360-430 CSS px in portrait and ~800 in landscape,
     so phones always fall under the cap and desktops always over it. Nothing sits in
     between. */
  --hud-band-p: min(20vh, 256px);      /* portrait: one fifth, capped at 1280/5 */
  --hud-row-l: min(33.3333vh, 240px);  /* landscape: one third, capped at 720/3 */
  --hud-col-l: min(14.2857vw, 183px);  /* landscape: one seventh, capped at 1280/7 */

  /* Resolved per orientation; every HUD region is placed against these six. */
  --hud-top-h: var(--hud-band-p);             /* the minimap / speed / FAB band */
  --hud-dock-h: calc(var(--hud-band-p) * 2);  /* the dialog dock */
  --hud-dock-l: 0px;                          /* space reserved left of the dock */
  --hud-dock-r: 0px;                          /* ...and right of it */
  /* (The pad had a band of its own until v5.18.2; it now tracks the focused square, so the
     bands describe the top corners and the dialog dock only.) */
}

@media (orientation: landscape) {
  :root {
    --hud-top-h: var(--hud-row-l);
    /* The dock shares the bottom row with the pad rather than owning bands of its own,
       so it is one row tall and gives up the outer columns: one to the left cluster,
       two to the right (cluster + the cancel / full-screen strip). */
    --hud-dock-h: var(--hud-row-l);
    --hud-dock-l: var(--hud-col-l);
    --hud-dock-r: calc(var(--hud-col-l) * 2);
  }
}

*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  user-select: none;
  -webkit-user-select: none;
}

/* touch-action: none belongs on the BOARD only. Applying it to every element
   (as this sheet used to) silently disabled touch scrolling in every HUD
   container — on a phone the wall buttons below the fold and most of the build
   icon grid simply could not be reached. */
html, body { touch-action: none; }

#bp-icons, .sel-actions, #gamepad-hints, .dlg-card, #fab-menu, #start-body {
  touch-action: pan-y;
  -webkit-overflow-scrolling: touch;
}

::selection { background: transparent; color: inherit; }

html, body {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: var(--bg);
  font-family: var(--font-family);
  color: var(--text-main);
  -webkit-font-smoothing: antialiased;
}

body {
  transition: background var(--m-effects), color var(--m-effects);
}

#renderCanvas {
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
}

/* --- Shared surface treatment --- */

.m3-surface {
  background: var(--panel-bg);
  border: 1px solid var(--panel-border);
  box-shadow: var(--e2);
}

/* --- Sprite legibility ---------------------------------------------------
   The PNG sprites are baked WHITE (the canvas blits them onto saturated faction
   colours and dark resource discs). In the DOM they land on light surfaces in the
   light scheme, where white-on-light is unreadable — so invert them there. The
   exception is any chip whose own background is already a dark accent, where the
   sprite must stay white. ---------------------------------------------------- */

:root[data-theme="light"] .fa-icon-img { filter: invert(1); }

:root[data-theme="light"] .bp-icon.armed .fa-icon-img,
:root[data-theme="light"] .btn-job-option.active-job .fa-icon-img { filter: none; }

/* --- Roving UI focus ring (WASD / left stick) --- */

.ui-focus {
  outline: 3px solid var(--md-sys-color-tertiary);
  outline-offset: 2px;
  position: relative;
  z-index: 1;
}

.ui-focus::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--md-sys-color-tertiary);
  opacity: .12;
  pointer-events: none;
}

/* --- Resource bar --- */

/* THE BAR KEEPS THE TOP LINE, AND THE TWO CORNERS SIT UNDER IT (v5.18.0). `--bar-h` is
   measured for every shape of bar now, not only a full-width strip - see
   `HUDManager.syncBarHeight`. The alternative was squeezing the bar between the corners,
   which means capping its width, and a mode with enough resources wraps it into a tall
   block anyway; stacking costs one row of band 1, which band 1 has. The screenshot gate
   has asserted "the bar must not cover the things a player taps" since v3.6.12. */
#resource-bar {
  position: absolute;
  top: var(--edge-t);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  max-width: calc(100vw - 2 * var(--hud-gap));
  gap: 16px;
  background: var(--md-sys-color-surface-container);
  border: 1px solid var(--panel-border);
  box-shadow: var(--e2);
  padding: 8px 20px;
  border-radius: var(--r-full);
  z-index: 100;
  transition: background var(--m-effects);
}

.res-item {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
  font-size: var(--t-title-s);
  white-space: nowrap;
}

.res-icon {
  width: 18px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.res-item.pop-item { color: var(--md-sys-color-primary); }

/* Per-Epoch net income beside each resource (v3.5.1). Smaller and dimmer than the
   figure itself, so the amount stays the thing you read first; a shortfall goes to the
   error role, because "you are losing Food every Epoch" is the one case that must catch
   the eye. Never a hex value — these are M3 roles like everything else. */
.res-rate {
  font-size: var(--t-label-s);
  font-weight: 600;
  opacity: 0.85;
  margin-left: -2px;
  color: var(--md-sys-color-on-surface-variant);
}
.res-rate.pos { color: var(--md-sys-color-primary); }
.res-rate.neg { color: var(--md-sys-color-error); opacity: 1; }
body[data-size="compact"] .res-rate { font-size: 0.62rem; }

/* WHY Food is falling (v5.5.0): a briefcase for food posts standing empty, a hammer for a
   ceiling too low — either, or both, inside the Food chip. Error role like the negative rate
   it explains, because it is that same warning said in a way that can be acted on. */
.res-warn {
  display: inline-flex;
  align-items: center;
  margin-left: 1px;
  color: var(--md-sys-color-error);
}
.res-warn img { width: 0.8em; height: 0.8em; }

/* --- Minimap --- */

/* TOP-LEFT (v5.18.0). It used to sit top-right, where the Epoch speed now lives: the
   layout grid gives the minimap the first band's left end and the speed pill its right.
   Sized to the band so it can never grow past the region it was given. */
#minimap-container {
  position: absolute;
  top: calc(var(--edge-t) + var(--bar-h));
  left: var(--edge-l);
  width: var(--hud-corner-l);
  height: var(--hud-corner-l);
  background: var(--md-sys-color-surface-container);
  border: 1px solid var(--panel-border);
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--e2);
  z-index: 100;
  cursor: pointer;
}

#minimapCanvas { width: 100%; height: 100%; display: block; }

/* The Epoch-length readout: not a button, so it never takes a turn in the roving focus —
   the two buttons beside it are what a player acts on (v4.2.0). It keeps the countdown rim the
   button used to carry. */
.fold-read {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 3.2em;
  height: 34px;
  padding: 0 8px;
  font-weight: 700;
  font-size: var(--t-label-l);
  color: var(--md-sys-color-on-surface);
  background: var(--md-sys-color-surface-container);
  border: 1px solid var(--panel-border);
  border-radius: var(--r-full);
  box-shadow: var(--e1);
}
.fold-read.paused { color: var(--md-sys-color-error); }

/* The seed picker in the FAB menu keeps the row shape of the buttons around it. */
#fab-seed {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
}
#fab-seed input[type="color"] {
  margin-left: auto;
  width: 28px;
  height: 22px;
  border: 1px solid var(--panel-border);
  border-radius: 6px;
  background: none;
  padding: 0;
}

/* --- Theme bar (scheme cycle + seed picker) --- */

/* THE EPOCH COUNTDOWN IS THIS RECTANGLE'S BACKGROUND (v4.2.1). It used to be a conic ring
   masked into the readout's rim, which at 34px read as a distorted circle sitting behind the
   buttons rather than as progress. Now the three controls sit inside one rounded rectangle and
   the rectangle FILLS: solid at the start of an Epoch, a soft gradient edge sweeping across the
   middle, fully transparent as it runs out. `--epoch-left` (1 -> 0) is written by HUDManager
   each frame; the 9% either side of the edge is what makes it a gradient rather than a hard
   wipe. Never a literal colour — the fill is the primary-container role at low alpha, mixed
   through color-mix so it works in all four schemes. */
/* TOP-RIGHT (v5.18.0), with the FAB immediately to its right: David asked for the pill
   and the round button to read as "一個橫躺的感嘆號" - the bar, then the dot. The FAB's
   own width plus one gap is therefore reserved here, and the FAB is placed against the
   same edge below. It used to hang under the minimap on the right. */
#theme-bar {
  position: absolute;
  top: calc(var(--edge-t) + var(--bar-h));
  right: calc(var(--hud-gap) + var(--fab-w) + 8px);
  width: var(--hud-speed-w);
  justify-content: space-between;
  display: flex;
  gap: 8px;
  align-items: center;
  z-index: 100;
  padding: 6px 10px;
  border-radius: var(--r-full);
  border: 1px solid var(--panel-border);
  box-shadow: var(--e1);
  background-color: var(--md-sys-color-surface-container);
  background-image: linear-gradient(90deg,
    var(--epoch-fill) 0%,
    var(--epoch-fill) calc(var(--epoch-left, 1) * 100% - 9%),
    transparent calc(var(--epoch-left, 1) * 100% + 9%),
    transparent 100%);
  transition: background-color var(--m-effects);
}

:root {
  /* The sweep's colour: the primary container, softened so the buttons on top stay readable. */
  --epoch-fill: color-mix(in srgb, var(--md-sys-color-primary-container) 72%, transparent);
}

.icon-btn {
  position: relative;
  width: 44px;
  height: 44px;
  border-radius: var(--r-full);
  border: 1px solid var(--panel-border);
  background: var(--md-sys-color-surface-container);
  color: var(--md-sys-color-on-surface-variant);
  font-size: var(--t-label-m);
  font-weight: 700;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  box-shadow: var(--e1);
  transition: background var(--m-effects), border-radius var(--m-spatial-fast);
}

.icon-btn::before {
  content: "";
  position: absolute;
  inset: 0;
  background: currentColor;
  opacity: 0;
  transition: opacity var(--m-effects);
}

.icon-btn:hover::before { opacity: .08; }
.icon-btn:active::before { opacity: .12; }
.icon-btn:active { border-radius: var(--r-md); }

#seed-swatch {
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--panel-border);
  border-radius: var(--r-full);
  background: none;
  cursor: pointer;
  overflow: hidden;
}

#seed-swatch::-webkit-color-swatch-wrapper { padding: 3px; }
#seed-swatch::-webkit-color-swatch { border: none; border-radius: var(--r-full); }

/* --- Version tag --- */

#version-tag {
  position: absolute;
  bottom: 8px;
  left: var(--edge-l);
  font-size: var(--t-label-s);
  font-weight: 600;
  color: var(--text-muted);
  background: var(--md-sys-color-surface-container-low);
  padding: 2px 10px;
  border-radius: var(--r-full);
  border: 1px solid var(--panel-border);
  pointer-events: none;
  z-index: 150;
}

/* --- Floating action button + menu --- */

/* The dot of the exclamation mark (v5.18.0): top-right, hard against the Epoch-speed
   pill. It used to live bottom-right, which the layout grid now hands to the virtual
   pad's right cluster. */
#fab {
  position: absolute;
  right: var(--edge-r);
  top: calc(var(--edge-t) + var(--bar-h));
  width: var(--fab-w);
  height: var(--fab-w);
  border: none;
  border-radius: var(--r-lg);
  background: var(--md-sys-color-primary-container);
  color: var(--md-sys-color-on-primary-container);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--e3);
  z-index: 300;
  transition: border-radius var(--m-spatial-fast), transform var(--m-effects);
}

#fab:hover { transform: translateY(-2px); }
#fab:active { border-radius: var(--r-full); }

/* Opens DOWNWARD now (v5.18.0), because the FAB moved to the top edge. Right-aligned to
   the same edge as the dot it hangs from, and capped so a long menu scrolls instead of
   running off the bottom of a short screen. */
#fab-menu {
  position: absolute;
  right: var(--edge-r);
  top: calc(var(--edge-t) + var(--bar-h) + var(--fab-w) + 10px);
  max-height: calc(100vh - var(--hud-gap) * 2 - var(--bar-h) - var(--fab-w) - 10px);
  overflow-y: auto;
  display: none;
  flex-direction: column;
  gap: 6px;
  z-index: 300;
}

#fab-menu button {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 18px;
  border: 1px solid var(--panel-border);
  border-radius: var(--r-full);
  background: var(--md-sys-color-surface-container-high);
  color: var(--text-main);
  font-family: inherit;
  font-size: var(--t-label-l);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: var(--e2);
  transition: background var(--m-effects);
}

#fab-menu button:hover { background: var(--md-sys-color-surface-container-highest); }

#fab-menu button.on {
  background: var(--md-sys-color-primary-container);
  color: var(--md-sys-color-on-primary-container);
  border-color: transparent;
}

.fab-ico { font-size: 16px; }

/* --- Dialog (privacy) --- */

/* Docked like every other dialog (v5.18.0); it keeps the top z-index because it is
   reached from the FAB menu, which can be open over anything. */
#privacy-dialog {
  z-index: 1100;
}

.dlg-card {
  background: var(--md-sys-color-surface-container-high);
  border: 1px solid var(--panel-border);
  border-radius: var(--r-xl);
  padding: 24px;
  width: 100%;
  max-width: 460px;
  box-shadow: var(--e3);
  max-height: 90vh;
  overflow-y: auto;
}

.dlg-title {
  font-size: var(--t-title-l);
  font-weight: 700;
  margin-bottom: 14px;
}

.dlg-body {
  font-size: var(--t-body-m);
  color: var(--text-muted);
  line-height: 1.5;
  margin: 14px 0 18px;
}

#privacy-note {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.pv-row {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 8px 12px;
  border-radius: var(--r-sm);
  background: var(--md-sys-color-surface-container);
  font-size: var(--t-label-l);
}

.pv-row b { color: var(--md-sys-color-primary); }
#privacy-close { width: 100%; justify-content: center; }

/* --- Virtual gamepad (semitransparent, mirrors the two-domain model) --- */

/* The pad owns a BAND of the layout grid now (v5.18.0) rather than floating over the
   board's bottom edge: portrait band 3, landscape the bottom row's outer columns. It no
   longer has to dodge the build panel or the FAB, because neither is beside it any more -
   the build panel went into the dialog dock and the FAB went to the top-right corner. */
#vpad {
  position: absolute;
  /* The pad's box IS the safe area (v5.18.5) — `placeVpad` measures its inset off this
     rather than trying to read an env() out of a custom property. */
  top: 0;
  bottom: 0;
  left: var(--edge-l);
  right: var(--edge-r);
  display: none;
  z-index: 250;
  pointer-events: none;
  opacity: .55;
}

/* The three groups are placed by `HUDManager.placeVpad` each frame, in CSS pixels, so that
   they flank the FOCUSED square: same centre line, at least two Small Squares clear on each
   side. `top` is that centre line, hence the -50% (v5.18.2). */
#vpad-left, #vpad-right, #vpad-extra {
  position: absolute;
  transform: translateY(-50%);
}

/* ONE ARRANGEMENT IN BOTH ORIENTATIONS (v5.18.1), David's ruling: 「q組方向組靠左／u組方向
   組靠右／額外鍵組在u組右側」. Portrait used to sit the extra keys BETWEEN the clusters,
   which put Cancel in the middle of the board and left the two pads reaching inward; now
   the row reads left-to-right as UI pad, gap, map pad, extra keys. Since v5.18.2 the order
   is carried by the placement, not by grid columns. */
#vpad-extra {
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: auto;
}

#vpad:hover { opacity: .8; }

/* Bigger keys, and NO gap between them (v5.18.2): 「q鍵組和u鍵組各自的按鈕變大但按鈕間的
   間距歸零」. A cluster now reads as one block of keys rather than five floating pills, which
   is also why it can afford the extra 10px per cell without taking more room than before. */
.vpad-cluster {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, 56px);
  grid-template-rows: repeat(3, 56px);
  gap: 0;
  pointer-events: auto;
}

.vpad-cluster button {
  border: 1px solid var(--panel-border);
  border-radius: var(--r-md);
  background: var(--md-sys-color-surface-container-high);
  color: var(--text-main);
  font-family: inherit;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  touch-action: none;
  transition: background var(--m-effects), transform var(--m-effects);
}

.vpad-cluster button.pressed {
  background: var(--md-sys-color-primary);
  color: var(--md-sys-color-on-primary);
  transform: scale(.92);
}

.vp-u { grid-area: 1 / 2; }
.vp-l { grid-area: 2 / 1; }
.vp-c { grid-area: 2 / 2; background: var(--md-sys-color-primary-container) !important;
  color: var(--md-sys-color-on-primary-container) !important; border-radius: var(--r-full); }
.vp-r { grid-area: 2 / 3; }
.vp-d { grid-area: 3 / 2; }

.vpad-label {
  position: absolute;
  top: -18px;
  left: 0;
  font-size: var(--t-label-s);
  font-weight: 700;
  letter-spacing: .08em;
  color: var(--text-muted);
}

#vpad-cancel, #vpad-fullscreen {
  width: 52px;
  height: 52px;
  border: 1px solid var(--panel-border);
  border-radius: var(--r-full);
  font-family: inherit;
  font-weight: 800;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  pointer-events: auto;
  touch-action: none;
}

#vpad-cancel {
  background: var(--md-sys-color-error-container);
  color: var(--md-sys-color-on-error-container);
}

/* Not an error colour: full screen is a view toggle, not a way out of something. */
#vpad-fullscreen {
  background: var(--md-sys-color-surface-container-high);
  color: var(--text-main);
}

body[data-size="compact"] .vpad-cluster {
  grid-template-columns: repeat(3, 52px);
  grid-template-rows: repeat(3, 52px);
}

/* On a narrow screen the build panel would leave no room for the pad, so the pad
   sits above it instead of beside it. */
body[data-size="compact"] #vpad,
body[data-size="medium"] #vpad {
  padding-left: var(--hud-gap);
  padding-right: calc(var(--hud-gap) + 62px);
}

/* --- Selection panel --- */

/* IN THE DOCK (v5.18.0). It used to float above the board's bottom-left corner and grow
   upward with its content, which is exactly the complaint this release answers: choosing
   where to send a corps means reading the board, and the panel was standing on it. The
   dock is a fixed region of the layout grid, so the panel's content scrolls inside a
   height the board has already been told about. */
#selection-panel {
  position: absolute;
  left: calc(var(--hud-dock-l) + var(--edge-l));
  right: calc(var(--hud-dock-r) + var(--edge-r));
  bottom: var(--edge-b);
  height: calc(var(--hud-dock-h) - var(--hud-gap) * 2);
  display: flex;
  align-items: center;
  gap: 16px;
  background: var(--md-sys-color-surface-container);
  border: 1px solid var(--panel-border);
  border-radius: var(--r-xl);
  padding: 14px 20px;
  box-shadow: var(--e3);
  z-index: 100;
  overflow: hidden;
}

.sel-icon {
  width: 48px;
  height: 48px;
  background: var(--md-sys-color-primary-container);
  color: var(--md-sys-color-on-primary-container);
  border-radius: var(--r-lg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  flex-shrink: 0;
}

.sel-info { flex: 1; min-width: 0; }
.sel-title { font-size: var(--t-title-m); font-weight: 700; }
.sel-sub { font-size: var(--t-label-m); color: var(--text-muted); margin-top: 2px; }
.sel-stats { font-size: var(--t-label-s); color: var(--text-muted); margin-top: 4px; }

.hp-bar-wrap {
  width: 100%;
  height: 6px;
  background: var(--md-sys-color-surface-container-highest);
  border-radius: var(--r-full);
  overflow: hidden;
  margin-top: 6px;
}

.hp-bar-fill {
  height: 100%;
  background: var(--md-sys-color-primary);
  border-radius: var(--r-full);
  transition: width var(--m-effects);
}

/* --- Building detail panel --- */

/* The dock fixes the width, so the old max-width cap is gone (v5.18.0); both columns
   scroll inside the region instead of the panel growing to fit them. */
#selection-panel { align-items: flex-start; }

/* Dominion shows the build panel at the dock's left end while the selection panel is up,
   so the selection panel starts after it. Realms hides the build panel entirely
   (v5.15.1), and then the class is absent and the panel takes the whole dock. */
body.build-docked #selection-panel {
  left: calc(var(--hud-dock-l) + var(--edge-l) + var(--build-w) + var(--hud-gap));
}
/* Left column: what this Small Square IS, and the things you can do about it. Right column:
   the options belonging to whichever of those you chose (v5.18.5). Both scroll in their own
   half, so neither can push the other out of the dock. */
#selection-panel .sel-info { align-self: stretch; overflow-y: auto; flex: 1 1 45%; min-width: 0; }
#selection-panel .sel-actions { flex: 1 1 55%; }

.sel-stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 2px 10px;
  margin-top: 8px;
}

.st {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: var(--t-label-s);
  color: var(--text-muted);
  padding: 2px 6px;
  border-radius: var(--r-xs);
  background: var(--md-sys-color-surface-container-low);
}

.st b { color: var(--md-sys-color-on-surface); font-weight: 700; }

.sel-walls {
  margin-top: 8px;
  font-size: var(--t-label-s);
  color: var(--text-muted);
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
}

.wall {
  padding: 2px 8px;
  border-radius: var(--r-full);
  background: var(--md-sys-color-tertiary-container);
  color: var(--md-sys-color-on-tertiary-container);
  font-weight: 700;
}

.wall.none { background: none; color: var(--text-muted); font-weight: 400; padding: 0; }

.sel-actions {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex-shrink: 0;
  /* Bounded by the dock (v5.18.0) rather than a fixed 190px: the region is the budget,
     and whatever does not fit scrolls. */
  align-self: stretch;
  max-height: 100%;
  overflow-y: auto;
}

.btn-up, .btn-wall {
  border: none;
  cursor: pointer;
  font-family: inherit;
  font-weight: 700;
  font-size: var(--t-label-s);
  padding: 7px 12px;
  border-radius: var(--r-full);
  white-space: nowrap;
  transition: border-radius var(--m-spatial-fast), filter var(--m-effects);
}

.btn-up {
  background: var(--md-sys-color-primary);
  color: var(--md-sys-color-on-primary);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
}

.btn-up span { font-weight: 400; opacity: .85; }

/* A wall states its price on the button, like the upgrade does (v3.6.0). */
.btn-wall {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
}
.btn-wall span { font-weight: 400; opacity: .85; }

.btn-wall {
  background: var(--md-sys-color-secondary-container);
  color: var(--md-sys-color-on-secondary-container);
  text-align: left;
}

.btn-up:hover, .btn-wall:hover { filter: brightness(1.1); }
.btn-up:active, .btn-wall:active { border-radius: var(--r-sm); }

/* --- M3 buttons --- */

.m3-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: none;
  cursor: pointer;
  padding: 10px 18px;
  border-radius: var(--r-full);
  font-family: inherit;
  font-size: var(--t-label-l);
  font-weight: 600;
  overflow: hidden;
  transition: border-radius var(--m-spatial-fast), background var(--m-effects);
}

.m3-btn::before {
  content: "";
  position: absolute;
  inset: 0;
  background: currentColor;
  opacity: 0;
  transition: opacity var(--m-effects);
}

.m3-btn:hover::before { opacity: .08; }
.m3-btn:active::before { opacity: .12; }
.m3-btn:active { border-radius: var(--r-md); }

.m3-btn.filled {
  background: var(--md-sys-color-primary);
  color: var(--md-sys-color-on-primary);
}

.m3-btn.tonal {
  background: var(--md-sys-color-secondary-container);
  color: var(--md-sys-color-on-secondary-container);
}

.m3-btn.danger {
  background: var(--md-sys-color-error-container);
  color: var(--md-sys-color-on-error-container);
}

.btn-job-assign {
  position: relative;
  border: none;
  padding: 10px 16px;
  border-radius: var(--r-full);
  background: var(--md-sys-color-error-container);
  color: var(--md-sys-color-on-error-container);
  font-family: inherit;
  font-weight: 600;
  font-size: var(--t-label-m);
  cursor: pointer;
  flex-shrink: 0;
  transition: border-radius var(--m-spatial-fast);
}

.btn-job-assign:active { border-radius: var(--r-md); }

/* --- Build panel ---------------------------------------------------------
   Grid per the agreed shape:

     +---------------+----+
     | icons  (r1)   | go |
     |        (r2)   +----+
     +---------------+ x  |
     | building name +----+

   The icon grid shows 1-4 rows depending on viewport height (--bp-rows, set by
   HUDManager.applyBuildRows) and scrolls beyond that. -------------------- */

/* INTO THE DOCK (v5.18.0), at its left end. It used to sit top-left, which the layout
   grid now gives to the minimap - and it is a dialog by David's reckoning ("各種對話框"),
   so this is where it belongs anyway. Docking it also freed the virtual pad from having
   to reserve a build-panel-wide margin on its left. */
#build-panel {
  position: absolute;
  bottom: var(--edge-b);
  left: calc(var(--hud-dock-l) + var(--edge-l));
  max-height: calc(var(--hud-dock-h) - var(--hud-gap) * 2);
  overflow-y: auto;
  display: grid;
  grid-template-columns: 1fr 54px;
  /* The name/cost row spans the FULL width (v3.6.4). It used to share row 3 with the
     cancel button, so at 132px (a landscape phone) it had ~86px to render "100 Wood,
     30 Ore" in and simply ellipsised the requirement away — the cost of a building was
     unreadable on the device most likely to be short of it. */
  grid-template-areas:
    "icons go"
    "icons x"
    "name  name";
  gap: 6px;
  width: var(--build-w);
  z-index: 100;
  padding: 8px;
  background: var(--md-sys-color-surface-container);
  border: 1px solid var(--panel-border);
  border-radius: var(--r-lg);
  box-shadow: var(--e2);
}

#bp-icons {
  grid-area: icons;
  --bp-cell: 44px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--bp-cell), 1fr));
  /* Definite row height: as a grid ITEM of #build-panel this box gets stretched to the
     parent's track, and with auto rows the cells then compress and overlap each other.
     Pinning grid-auto-rows and an explicit height makes the row pitch match the cell. */
  grid-auto-rows: var(--bp-cell);
  gap: 4px;
  height: calc(var(--bp-rows, 4) * var(--bp-cell) + (var(--bp-rows, 4) - 1) * 4px);
  min-height: 0;
  align-self: start;
  overflow-y: auto;
  overscroll-behavior: contain;
}

#bp-icons::-webkit-scrollbar { width: 4px; }
#bp-icons::-webkit-scrollbar-thumb {
  background: var(--md-sys-color-outline-variant);
  border-radius: var(--r-full);
}

.bp-icon {
  position: relative;
  min-width: 0;
  height: var(--bp-cell);
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--panel-border);
  border-radius: var(--r-md);
  background: var(--md-sys-color-surface-container-high);
  color: var(--text-main);
  font-size: 17px;
  cursor: pointer;
  overflow: hidden;
  transition: background var(--m-effects), border-radius var(--m-spatial-fast);
}

.bp-icon::before {
  content: "";
  position: absolute;
  inset: 0;
  background: currentColor;
  opacity: 0;
  transition: opacity var(--m-effects);
}

.bp-icon:hover::before { opacity: .08; }
.bp-icon:active { border-radius: var(--r-sm); }

.bp-icon.is-tower {
  background: var(--md-sys-color-tertiary-container);
  color: var(--md-sys-color-on-tertiary-container);
}

.bp-icon.armed {
  background: var(--md-sys-color-primary);
  color: var(--md-sys-color-on-primary);
  border-color: transparent;
}

#bp-name {
  grid-area: name;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1px;
  min-width: 0;
  padding: 4px 6px;
  border-radius: var(--r-sm);
  background: var(--md-sys-color-surface-container-low);
}

.bp-title {
  font-size: var(--t-label-m);
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.bp-cost {
  font-size: var(--t-label-s);
  color: var(--text-muted);
  /* A MARQUEE, not an ellipsis (v3.6.4): the row slides to reveal its tail, so the full
     requirement is legible even on a 132px panel. The slide is a ping-pong over exactly
     the overflow (`--bp-shift`), set by HUDManager from the measured widths — no wrapping,
     no duplicated text, no clipped requirement. */
  overflow: hidden;
  white-space: nowrap;
}
.bp-cost > span { display: inline-block; will-change: transform; }
.bp-cost.scroll > span {
  animation: bp-marquee var(--bp-marquee, 5s) ease-in-out infinite alternate;
}
@keyframes bp-marquee {
  from { transform: translateX(0); }
  to { transform: translateX(var(--bp-shift, 0)); }
}
/* Cannot afford it: the shortfall is named, in the error role. */
.bp-cost.short { color: var(--md-sys-color-error); font-weight: 700; }
@media (prefers-reduced-motion: reduce) {
  .bp-cost.scroll > span { animation-duration: 12s; }
}

#bp-go, #bp-x {
  border: none;
  cursor: pointer;
  font-family: inherit;
  font-weight: 800;
  border-radius: var(--r-md);
  transition: border-radius var(--m-spatial-fast), filter var(--m-effects);
}

#bp-go {
  grid-area: go;
  height: 42px;
  background: var(--md-sys-color-primary);
  color: var(--md-sys-color-on-primary);
  font-size: var(--t-label-l);
}

#bp-x {
  grid-area: x;
  /* The area spans two rows to keep the panel's shape, but the button itself sits at
     the top of it — stretched full height it reads as a heavy red slab. */
  align-self: start;
  height: 34px;
  background: var(--md-sys-color-error-container);
  color: var(--md-sys-color-on-error-container);
  font-size: 15px;
}

#bp-go:active, #bp-x:active { border-radius: var(--r-full); }
#bp-go:hover, #bp-x:hover { filter: brightness(1.08); }

/* GO only lights up once the focus border is on a square that will accept the build. */
#bp-go:disabled {
  background: var(--md-sys-color-surface-container-highest);
  color: var(--md-sys-color-on-surface-variant);
  cursor: not-allowed;
  filter: none;
}

#bp-go.ready { animation: goPulse 1.4s ease-in-out infinite; }

@keyframes goPulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--md-sys-color-primary) 55%, transparent); }
  50% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--md-sys-color-primary) 0%, transparent); }
}

/* --- Job assignment overlay --- */

/* Docked (v5.18.0). It used to open at the pointer; the dock is one fixed place, which
   is also one fewer way for it to land on the board. */
#job-menu-overlay {
  z-index: 1000;
}

.job-card {
  background: var(--md-sys-color-surface-container-high);
  border: 1px solid var(--panel-border);
  border-radius: var(--r-xl);
  padding: 24px;
  width: 90%;
  max-width: 540px;
  box-shadow: var(--e3);
}

.job-card-title {
  font-size: var(--t-title-l);
  font-weight: 700;
  margin-bottom: 16px;
  text-align: center;
}

.job-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  margin-bottom: 20px;
}

.btn-job-option {
  position: relative;
  background: var(--md-sys-color-surface-container-highest);
  border: 1px solid var(--panel-border);
  border-radius: var(--r-lg);
  padding: 14px;
  color: var(--text-main);
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  transition: background var(--m-effects), border-color var(--m-effects);
}

.btn-job-option::before {
  content: "";
  position: absolute;
  inset: 0;
  background: currentColor;
  opacity: 0;
  transition: opacity var(--m-effects);
}

.btn-job-option:hover::before { opacity: .08; }

.btn-job-option.active-job {
  border-color: var(--md-sys-color-primary);
  background: var(--md-sys-color-primary-container);
  color: var(--md-sys-color-on-primary-container);
}

.j-icon { font-size: 20px; margin-bottom: 6px; }
.j-name { font-weight: 700; font-size: var(--t-title-s); }
.j-desc { font-size: var(--t-label-s); color: var(--text-muted); margin-top: 4px; }
.btn-job-option.active-job .j-desc { color: var(--md-sys-color-on-primary-container); }

.btn-close-modal {
  width: 100%;
  padding: 12px;
  background: var(--md-sys-color-secondary-container);
  color: var(--md-sys-color-on-secondary-container);
  border: none;
  border-radius: var(--r-full);
  font-family: inherit;
  font-weight: 600;
  cursor: pointer;
  transition: border-radius var(--m-spatial-fast);
}

.btn-close-modal:active { border-radius: var(--r-md); }

/* --- Snackbar toasts --- */

#toast-container {
  position: absolute;
  top: 70px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  z-index: 200;
  pointer-events: none;
  max-width: 90vw;
}

.toast-msg {
  background: var(--md-sys-color-inverse-surface);
  color: var(--md-sys-color-inverse-on-surface);
  padding: 10px 18px;
  border-radius: var(--r-sm);
  font-size: var(--t-body-m);
  box-shadow: var(--e3);
  animation: toastIn var(--m-spatial-fast) both;
}

@keyframes toastIn {
  from { opacity: 0; transform: translateY(-12px) scale(.96); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

.toast-msg.fade-out { opacity: 0; transition: opacity var(--m-effects); }

/* --- Gamepad hints --- */

#gamepad-hints {
  /* Reference material only: never intercept a tap meant for the board or a panel
     underneath it (v3.5.2). Its own scrolling is re-enabled on the pills below. */
  pointer-events: none;
  position: absolute;
  /* Clears the Epoch-speed pill and the FAB, which now share the top-right corner
     (v5.18.0); it used to hang off the minimap, which has moved to the left. */
  top: calc(var(--edge-t) + var(--bar-h) + var(--fab-w) + 64px);
  bottom: calc(var(--hud-dock-h) + var(--hud-gap));
  right: var(--edge-r);
  display: none;
  flex-direction: column;
  justify-content: flex-start;
  overflow-y: auto;
  max-height: calc(100vh - var(--hud-gap) * 2 - var(--bar-h) - var(--fab-w) - 64px
                   - var(--hud-dock-h));
  gap: 6px;
  background: var(--md-sys-color-surface-container);
  padding: 10px 14px;
  border-radius: var(--r-lg);
  border: 1px solid var(--panel-border);
  box-shadow: var(--e1);
  font-size: var(--t-label-m);
  z-index: 100;
}

.gp-pill {
  /* The container is pointer-events: none so it cannot block the board; the pills take
     events back, which is what lets the list scroll when the player opens it. */
  pointer-events: auto; display: flex; align-items: center; gap: 8px; flex-shrink: 0; white-space: nowrap; }

.gp-btn {
  background: var(--md-sys-color-secondary-container);
  color: var(--md-sys-color-on-secondary-container);
  font-weight: 800;
  border-radius: var(--r-full);
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--t-label-s);
}

/* --- Start screen (v3.3.0) -----------------------------------------------
   The screen the game opens on. Opaque and above every HUD layer, but BELOW the
   privacy dialog (z-index 1100), which its Settings page links to. Nothing
   simulates behind it — see main.js's pauseGame(). Colours are roles only, and the
   card scrolls internally so it survives a 915x412 landscape phone. ---------- */

#start-screen {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: var(--md-sys-color-surface);
  z-index: 1000;
  overflow: hidden;
}

/* The HUD is behind an opaque sheet: hide it outright so nothing bleeds through a
   translucent edge and no stray tap reaches a panel nobody can see. !important
   because the HUD sets display inline on several of these. */
body.start-open #resource-bar,
body.start-open #minimap-container,
body.start-open #theme-bar,
body.start-open #build-panel,
body.start-open #selection-panel,
body.start-open #gamepad-hints,
body.start-open #version-tag,
body.start-open #vpad,
body.start-open #fab,
body.start-open #fab-menu { display: none !important; }

.start-card {
  width: 100%;
  max-width: 520px;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 22px;
  border-radius: var(--r-xl);
  background: var(--md-sys-color-surface-container);
  border: 1px solid var(--panel-border);
  box-shadow: var(--e3);
  overflow: hidden;
}

.start-brand { display: flex; align-items: center; gap: 12px; flex-shrink: 0; }
/* The sprite is sized in em, so one font-size drives the crest. */
.start-crest { font-size: 30px; line-height: 1; display: flex; }
.start-names { flex: 1; min-width: 0; }
.start-title { font-size: var(--t-title-l); font-weight: 700; }
.start-tag { font-size: var(--t-label-m); color: var(--text-muted); }

.start-ver {
  flex-shrink: 0;
  padding: 4px 10px;
  border-radius: var(--r-full);
  background: var(--md-sys-color-primary-container);
  color: var(--md-sys-color-on-primary-container);
  font-size: var(--t-label-s);
  font-weight: 700;
}

/* The only scroller: the card itself never grows past the viewport. */
#start-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow-y: auto;
  min-height: 0;
}

.start-entry {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  text-align: left;
  padding: 12px 16px;
  border: 1px solid var(--panel-border);
  border-radius: var(--r-lg);
  background: var(--md-sys-color-surface-container-high);
  color: var(--text-main);
  font-family: inherit;
  cursor: pointer;
  flex-shrink: 0;
  transition: border-radius var(--m-spatial-fast), background var(--m-effects);
}

.start-entry:hover { background: var(--md-sys-color-surface-container-highest); }
.start-entry:active { border-radius: var(--r-sm); }

.start-entry.primary {
  background: var(--md-sys-color-primary-container);
  color: var(--md-sys-color-on-primary-container);
  border-color: transparent;
}

.start-entry[disabled] { opacity: .45; cursor: not-allowed; }
.se-label { font-size: var(--t-title-s); font-weight: 700; }
.se-sub { font-size: var(--t-label-s); opacity: .8; }

.start-h { font-size: var(--t-title-m); font-weight: 700; flex-shrink: 0; }
.start-note {
  font-size: var(--t-label-s);
  color: var(--text-muted);
  line-height: 1.45;
  flex-shrink: 0;
}

.start-field { display: flex; flex-direction: column; gap: 6px; flex-shrink: 0; }
.start-field > span { font-size: var(--t-label-m); color: var(--text-muted); }

#start-seed,
#export-fps {
  width: 100%;
  padding: 10px 14px;
  border-radius: var(--r-md);
  border: 1px solid var(--panel-border);
  background: var(--md-sys-color-surface-container-lowest);
  color: var(--text-main);
  font-family: inherit;
  font-size: var(--t-body-m);
  /* The sheet turns selection off globally; a field you type a seed into needs it. */
  user-select: text;
  -webkit-user-select: text;
}

#start-seed:focus,
#export-fps:focus {
  outline: 2px solid var(--md-sys-color-primary);
  border-color: transparent;
}

/* --- Video export (v3.4.0) -------------------------------------------------
   Lives on the start screen, so it inherits the card's scrolling and both the
   width and HEIGHT classes below. The preview is a real canvas — the one being
   recorded — so it is constrained on both axes with width/height auto, which is how
   a replaced element keeps its aspect ratio instead of stretching. ---------- */

.export-bar {
  flex-shrink: 0;
  height: 8px;
  border-radius: var(--r-full);
  background: var(--md-sys-color-surface-container-highest);
  overflow: hidden;
}

.export-bar > i {
  display: block;
  height: 100%;
  width: 0;
  border-radius: var(--r-full);
  background: var(--md-sys-color-primary);
  transition: width var(--m-effects);
}

.export-stat {
  flex-shrink: 0;
  font-family: ui-monospace, monospace;
  font-size: var(--t-label-m);
  color: var(--text-main);
  overflow-wrap: anywhere;
}

.export-shot { flex-shrink: 0; display: flex; justify-content: center; min-height: 0; }

.export-preview {
  max-width: 100%;
  max-height: 30vh;
  width: auto;
  height: auto;
  border-radius: var(--r-md);
  border: 1px solid var(--panel-border);
  background: var(--md-sys-color-surface-container-lowest);
}

.export-bad {
  flex-shrink: 0;
  padding: 8px 12px;
  border-radius: var(--r-md);
  background: var(--md-sys-color-error-container);
  color: var(--md-sys-color-on-error-container);
  font-size: var(--t-label-m);
  line-height: 1.4;
}

/* A landscape phone has no 30vh to spare for a preview once the bar, the stat line
   and the Cancel button are in. */
body[data-h="short"] .export-preview,
body[data-h="xshort"] .export-preview { max-height: 22vh; }
body[data-h="xshort"] .export-shot { display: none; }

.start-run {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px 14px;
  border-radius: var(--r-lg);
  border: 1px solid var(--panel-border);
  background: var(--md-sys-color-surface-container-high);
  flex-shrink: 0;
}

.sr-main { flex: 1 1 180px; min-width: 0; }
.sr-title { font-size: var(--t-title-s); font-weight: 700; }
.sr-sub { font-size: var(--t-label-s); color: var(--text-muted); overflow-wrap: anywhere; }
/* A note beside a setting: the difficulty's one-line description, and the reminder that a run
   in progress cannot change its own (v4.3.0). */
.sr-note {
  font-size: var(--t-label-s);
  font-style: normal;
  color: var(--md-sys-color-on-surface-variant);
  display: block;
}

.sr-actions { display: flex; gap: 6px; flex-wrap: wrap; }
.sr-actions .m3-btn { padding: 8px 14px; font-size: var(--t-label-m); }

.start-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 6px 2px;
  flex-shrink: 0;
}

.sr-key { font-size: var(--t-label-l); }
.start-seg { display: flex; gap: 4px; flex-wrap: wrap; }

.start-seg-btn {
  padding: 7px 12px;
  border-radius: var(--r-full);
  border: 1px solid var(--panel-border);
  background: transparent;
  color: var(--text-main);
  font-family: inherit;
  font-size: var(--t-label-m);
  font-weight: 600;
  text-transform: capitalize;
  cursor: pointer;
  transition: background var(--m-effects);
}

.start-seg-btn.on {
  background: var(--md-sys-color-primary);
  color: var(--md-sys-color-on-primary);
  border-color: transparent;
}

#start-colour {
  width: 52px;
  height: 32px;
  border: none;
  border-radius: var(--r-full);
  background: transparent;
  cursor: pointer;
}

#start-colour::-webkit-color-swatch-wrapper { padding: 0; }
#start-colour::-webkit-color-swatch { border: none; border-radius: var(--r-full); }

.start-busy {
  padding: 26px 8px;
  text-align: center;
  font-size: var(--t-title-s);
  color: var(--text-muted);
}

.start-foot {
  flex-shrink: 0;
  text-align: center;
  font-size: var(--t-label-s);
  color: var(--text-muted);
}

body[data-size="compact"] #start-screen { padding: 12px; }
body[data-size="xl"] .start-card { max-width: 600px; }

/* A landscape phone is wide AND short: 915x412 lands here, and the card has to give
   up its padding and blurbs rather than push its entries off the bottom. */
body[data-h="short"] #start-screen,
body[data-h="xshort"] #start-screen { padding: 10px; }

body[data-h="short"] .start-card,
body[data-h="xshort"] .start-card {
  padding: 12px 14px;
  gap: 8px;
  border-radius: var(--r-lg);
  max-width: 640px;
}

body[data-h="short"] .start-crest,
body[data-h="xshort"] .start-crest { font-size: 22px; }
body[data-h="short"] #start-body,
body[data-h="xshort"] #start-body { gap: 6px; }
body[data-h="short"] .start-entry,
body[data-h="xshort"] .start-entry { padding: 8px 12px; border-radius: var(--r-md); }
body[data-h="short"] .start-run,
body[data-h="xshort"] .start-run { padding: 8px 12px; border-radius: var(--r-md); }
body[data-h="short"] .start-row,
body[data-h="xshort"] .start-row { padding: 2px; }
body[data-h="xshort"] .start-tag { display: none; }
body[data-h="xshort"] .start-foot { display: none; }

/* --- Window size classes --- */

body[data-size="compact"] {
  --build-w: 146px;
  --minimap: 96px;
  --hud-gap: 8px;
  /* SMALL BY WIDTH TOO (v5.18.4). These two sized off HEIGHT alone (`data-h`), so a tall
     narrow phone — 412 CSS px across, 805 down — counted as a large screen and kept the
     desktop chrome: minimap 96 + pill 168 + FAB 56 + gaps filled 408px of a 412px row.
     Nothing overlapped; it simply had no air in it, which is what David saw.
     The boundary is the one his M3 theme reference draws, and the only one it draws:
     600px, M3's compact/medium line (`@media (min-width:600px)` there). */
  --fab-w: 44px;
  --hud-speed-w: 132px;
}


/* THE BAR IS A STRIP, NOT A PILL, ON A NARROW SCREEN (v3.6.12). Wrapping was the old
   answer, and on a portrait phone it grew to four rows: a centred block that reached down
   over the build panel on the left and the minimap on the right, so the two things a player
   taps most were behind the thing that only reports numbers. It now spans the full width in
   ONE row and scrolls sideways for the overflow, and `--bar-h` reserves its height so every
   top-anchored layer starts underneath it. */
body[data-size="compact"] #resource-bar,
body[data-size="medium"] #resource-bar {
  top: 0;
  left: 0;
  right: 0;
  transform: none;
  width: 100%;
  max-width: none;
  /* It still WRAPS — a sideways-scrolling bar would hide the population count behind a
     swipe, and this is the one HUD element a player reads without thinking. What changed is
     that it now claims its rows at the top of the screen instead of floating over the
     panels; `HUDManager.syncBarHeight()` measures the rows and writes `--bar-h`. */
  justify-content: center;
  border-radius: 0 0 var(--r-lg) var(--r-lg);
  border-width: 0 0 1px 0;
}

/* First-paint estimate for one row; the measured value replaces it on the first frame. */
body[data-size="compact"] { --bar-h: 34px; }
body[data-size="medium"] { --bar-h: 38px; }

body[data-size="compact"] #resource-bar {
  gap: 6px 10px;
  padding: 6px 12px;
  font-size: var(--t-label-m);
}

body[data-size="compact"] .res-item { font-size: var(--t-label-m); }
body[data-size="compact"] .res-icon { width: 14px; height: 14px; }
/* No `top` here any more (v5.18.0): the build panel is bottom-anchored in the dock, and
   setting both edges would stretch it to the full height of the screen. */
body[data-size="compact"] #bp-icons { --bp-cell: 38px; }
body[data-size="compact"] .job-grid { grid-template-columns: 1fr; }
body[data-size="compact"] #selection-panel { min-width: 0; max-width: calc(100vw - 16px); }
/* Realms V3's build options are one long button each. The action column cannot shrink, so on a
   compact screen it squeezed the info column into a one-character ribbon that ran the panel up to
   the top of the screen (v5.15.1). The actions drop below the info instead, and their text wraps. */
body[data-size="compact"] #selection-panel { flex-wrap: wrap; }
body[data-size="compact"] #selection-panel .sel-info { flex: 1 1 120px; }
body[data-size="compact"] #selection-panel .sel-actions { flex: 1 1 100%; max-width: 100%; }
body[data-size="compact"] .btn-up, body[data-size="compact"] .btn-wall { white-space: normal; text-align: left; }

body[data-size="medium"] {
  --build-w: 168px;
  --minimap: 118px;
}

body[data-size="medium"] #privacy-note { max-width: 60vw; }

body[data-size="expanded"] {
  --build-w: 190px;
  --minimap: 140px;
}

/* lg - large: roomier chrome, three-column job grid */
body[data-size="large"] {
  --build-w: 232px;
  --minimap: 172px;
  --hud-gap: 16px;
  --t-label-m: 13px;
  --t-title-m: 17px;
}

body[data-size="large"] .job-grid { grid-template-columns: repeat(3, 1fr); }
body[data-size="large"] .job-card { max-width: 720px; }

/* lg+ - extra large: two-column build list, largest chrome */
body[data-size="xl"] {
  --build-w: 300px;
  --minimap: 208px;
  --hud-gap: 20px;
  --t-label-m: 13px;
  --t-title-m: 18px;
  --t-title-l: 24px;
}

body[data-size="xl"] .job-grid { grid-template-columns: repeat(3, 1fr); }
body[data-size="xl"] .job-card { max-width: 820px; }
body[data-size="xl"] #selection-panel { min-width: 420px; }

/* --- Height tiers -------------------------------------------------------
   Size classes are width-based, but a landscape phone is wide AND short: at
   915x435 it read as "expanded" and got desktop chrome, so the selection panel
   collided with the building panel. These scale the whole HUD down by height and
   move the selection panel out of the left column entirely. ---------------- */

body[data-h="short"] {
  --hud-gap: 8px;
  --minimap: 104px;
  --t-title-l: 18px;
  --t-title-m: 15px;
  --t-title-s: 13px;
  --t-body-m: 13px;
  --t-label-l: 13px;
  --t-label-m: 11px;
  --t-label-s: 10px;
}

body[data-h="xshort"] {
  --hud-gap: 6px;
  --minimap: 84px;
  --t-title-l: 16px;
  --t-title-m: 13px;
  --t-title-s: 12px;
  --t-body-m: 12px;
  --t-label-l: 12px;
  --t-label-m: 10px;
  --t-label-s: 9px;
}

body[data-h="short"] #build-panel,
body[data-h="xshort"] #build-panel {
  padding: 6px;
  gap: 4px;
  width: 152px;
  grid-template-columns: 1fr 44px;
}

body[data-h="short"] #bp-icons { --bp-cell: 36px; }
body[data-h="xshort"] #bp-icons { --bp-cell: 32px; }
body[data-h="xshort"] #build-panel { width: 132px; grid-template-columns: 1fr 40px; }
body[data-h="short"] #bp-go, body[data-h="xshort"] #bp-go { height: 34px; }
body[data-h="short"] #bp-x, body[data-h="xshort"] #bp-x { height: 28px; }

/* Both of the rules that used to live here are GONE (v5.18.0), and their absence is the
   point of this release. One pulled the selection panel out of the left column so it
   would not land on the build panel; the other lifted it 156px so it would clear the
   virtual pad's clusters, because an overlap silently ate taps meant for its buttons
   (v3.5.3). The layout grid gives each of the three a region of its own, so there is
   nothing left to dodge — and the panel no longer grows upward over the board, which was
   the complaint that started this: "我打算移動，但我看不到地圖". Only the short-screen
   trims below remain, and they are about text size, not position. */
body[data-h="short"] #selection-panel,
body[data-h="xshort"] #selection-panel {
  padding: 8px 14px;
  gap: 10px;
  border-radius: var(--r-lg);
}

body[data-h="short"] .sel-icon,
body[data-h="xshort"] .sel-icon { width: 34px; height: 34px; font-size: 17px; border-radius: var(--r-md); }
body[data-h="xshort"] .sel-icon { width: 28px; height: 28px; font-size: 14px; }

body[data-h="short"] .sel-stats-grid,
body[data-h="xshort"] .sel-stats-grid {
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  margin-top: 5px;
}

body[data-h="short"] .sel-walls,
body[data-h="xshort"] .sel-walls { margin-top: 5px; }
body[data-h="xshort"] .sel-walls { display: none; }
body[data-h="short"] .sel-actions,
body[data-h="xshort"] .sel-actions { max-height: 108px; }

body[data-h="short"] #resource-bar,
body[data-h="xshort"] #resource-bar { padding: 5px 12px; gap: 4px 10px; }

/* Shrink through the VARIABLES (v5.18.0) so the resource bar's reservation shrinks with
   them; setting width/height here alone would leave it reserving the desktop corner. */
/* The same two values off the height tier, so "small" means one size whichever dimension
   is short: a landscape phone is 800px across (not compact) but 360 down. */
body[data-h="short"], body[data-h="xshort"] { --fab-w: 44px; --hud-speed-w: 132px; }
body[data-h="short"] #fab, body[data-h="xshort"] #fab { font-size: 18px; }
/* (The menu hangs off the FAB's top-right home now, so there is no bottom offset to
   re-tune here; the base rule's `top` already follows --fab-w.) */
body[data-h="short"] #fab-menu button,
body[data-h="xshort"] #fab-menu button { padding: 9px 14px; }

body[data-h="short"] .vpad-cluster { grid-template-columns: repeat(3, 38px); grid-template-rows: repeat(3, 38px); }
body[data-h="xshort"] .vpad-cluster { grid-template-columns: repeat(3, 34px); grid-template-rows: repeat(3, 34px); }
body[data-h="short"] #vpad, body[data-h="xshort"] #vpad { padding-bottom: calc(var(--hud-gap) + 76px); }

/* --- Reduced motion --- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    transition-duration: .001ms !important;
  }
}

/* --- MODAL SURFACES, DOCKED (v5.18.0) ---------------------------------------------
   All six used to be a full-screen scrim with the card floating in the middle. David's
   ruling puts "各種對話框" in the dock, and a 55-70% scrim would have defeated the point
   of moving them there - the board would still be invisible behind them. So the overlay
   keeps its job of swallowing stray taps, and gives up its job of dimming the board:
   the backdrop is transparent, and the card sits in the dock like every other panel.
   The scrim's OTHER purpose, saying "this is modal", is carried by the card's elevation
   and by the focus contract in ui-focus.js, which was always what actually enforced it. */
.dlg-dock {
  position: fixed;
  left: calc(var(--hud-dock-l) + var(--edge-l));
  right: calc(var(--hud-dock-r) + var(--edge-r));
  bottom: var(--edge-b);
  height: calc(var(--hud-dock-h) - var(--hud-gap) * 2);
  display: none;
  align-items: stretch;
  justify-content: center;
  background: transparent;
}

.dlg-dock > .dlg-card, .dlg-dock > .job-card {
  max-width: 100%;
  max-height: 100%;
  width: 100%;
  overflow-y: auto;
  touch-action: pan-y;
}

/* --- Action confirm (v3.6.1): Before / Undergoing / After ------------------ */
#confirm-dialog {
  z-index: 400;
}

/* Milestones (v3.6.13): the first win criterion, and the auto-stop when nothing is left to
   gain. Same card as the confirm dialog — it is the same kind of moment, a question the run
   cannot continue past — but it sits ABOVE it in the focus order and pauses the loop. */
#milestone-dialog {
  z-index: 450;
}
#milestone-card { text-align: center; }

/* Declare war (v4.0.0): one row per target — weight, the force it draws, what the scouts
   found, and the projected outcome. Wide, because the projection is the point of the dialog. */
#war-dialog {
  z-index: 440;
}

/* Forces (v4.1.0): the army on one side, the garrison on the other. Read-only, so its only
   control is Close — everything else is a list. */
#forces-dialog {
  z-index: 430;
}

/* Work allocation (v4.1.0): the same list treatment as Forces, opened from a hall. */
#work-dialog {
  z-index: 430;
}
.fc-bar {
  height: 4px;
  border-radius: 2px;
  background: var(--md-sys-color-surface-variant);
  overflow: hidden;
  margin: 2px 0 6px;
}
.fc-bar span { display: block; height: 100%; background: var(--md-sys-color-primary); }
.fc-cols { display: flex; flex-wrap: wrap; gap: 12px; margin: 8px 0; }
.fc-col { flex: 1 1 240px; min-width: 0; }
.fc-head {
  font-weight: 700;
  font-size: var(--t-title-s);
  display: flex; align-items: center; gap: 8px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--panel-border);
}
.fc-head .res-icon { width: 18px; height: 18px; }
.fc-line {
  display: flex; justify-content: space-between; gap: 10px;
  font-size: var(--t-label-m);
  padding: 3px 0;
}
.fc-line b { font-variant-numeric: tabular-nums; }
.fc-sub { font-size: var(--t-label-s); color: var(--md-sys-color-on-surface-variant); }
.fc-empty { font-size: var(--t-label-m); color: var(--md-sys-color-on-surface-variant);
  padding: 6px 0; }
.wr-row {
  display: grid;
  /* Three columns since v4.13.0: the report, the board, the weight. The board is a fixed
     108px, so it never squeezes the report on a narrow phone — it wraps below instead. */
  grid-template-columns: 1fr auto auto;
  gap: 8px 12px;
  align-items: center;
  padding: 8px 0;
  border-top: 1px solid var(--panel-border);
}
/* The target board (v4.13.0): 9x9 Small Squares with the target Big Square as the middle 3x3,
   so a row says WHERE it is and not only what it is called. */
.wr-map {
  width: 108px;
  height: 108px;
  border-radius: var(--r-sm);
  background: var(--md-sys-color-surface-container-high);
  border: 1px solid var(--panel-border);
  image-rendering: pixelated;
}
@media (max-width: 480px) {
  .wr-row { grid-template-columns: 1fr auto; }
  .wr-map { grid-column: 1 / -1; justify-self: center; }
}
.wr-head { font-weight: 700; font-size: var(--t-title-s); }
.wr-meta { font-size: var(--t-label-m); color: var(--md-sys-color-on-surface-variant); }
.wr-k { display: flex; align-items: center; gap: 6px; }
.wr-k b { min-width: 1.6em; text-align: center; }
.wr-win { color: var(--md-sys-color-primary); font-weight: 700; }
.wr-lose { color: var(--md-sys-color-error); font-weight: 700; }
/* A losing front's fix-it line (v4.10.0) — advisory, so tertiary rather than error. */
.wr-advice { color: var(--md-sys-color-tertiary); }
.wr-none { font-size: var(--t-label-m); color: var(--md-sys-color-on-surface-variant); }
#milestone-card .cf-actions { justify-content: center; }
.dlg-title.win { color: var(--md-sys-color-primary); }

.cf-sub { font-size: var(--t-label-m); color: var(--md-sys-color-on-surface-variant);
  margin-bottom: 8px; }
.cf-cost { font-size: var(--t-title-s); font-weight: 700; margin-bottom: 12px;
  color: var(--md-sys-color-primary); }
.cf-cost.neg { color: var(--md-sys-color-error); }
.cf-cols { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.cf-col {
  background: var(--md-sys-color-surface-container-high);
  border: 1px solid var(--panel-border);
  border-radius: var(--r-md);
  padding: 10px;
}
.cf-head { font-weight: 700; font-size: var(--t-label-l); margin-bottom: 2px; }
.cf-why, .cf-people { font-size: var(--t-label-s);
  color: var(--md-sys-color-on-surface-variant); }
.cf-people { margin-bottom: 6px; }
.cf-rate { font-size: var(--t-label-m); font-weight: 600; display: flex; gap: 6px; }
.cf-rate.neg { color: var(--md-sys-color-error); }
.cf-rate b { font-weight: 700; opacity: .8; }
.cf-actions { display: flex; gap: 10px; margin-top: 14px; }
/* A landscape phone is wide AND short: stack the sections rather than squeezing them. */
body[data-h="xshort"] .cf-cols, body[data-size="compact"] .cf-cols {
  grid-template-columns: 1fr;
  gap: 6px;
}
body[data-h="xshort"] .cf-col { display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline; }

/* A wall add-on still going up (v3.6.2). */
.wall.wip {
  background: var(--md-sys-color-tertiary-container);
  color: var(--md-sys-color-on-tertiary-container);
}


/* Storage ceiling beside each amount (v3.6.6). Quieter than the figure itself; the whole
   chip turns to the error role once a resource is full and its income is being lost. */
.res-val i { font-style: normal; font-weight: 600; font-size: var(--t-label-s); opacity: .6; }
.res-val.full { color: var(--md-sys-color-error); }
.res-val.full i { opacity: .9; }

/* The dominion chip counts Big Squares held out of the board (v3.6.13). `full` means the
   first win criterion is MET, so it takes the primary role — after the storage rule above,
   where a full bar is a warning in the error role. */
.res-item.dom-item .res-val.full { color: var(--md-sys-color-primary); }

/* The import collision warning (v3.6.9): replacing a run on this device is destructive, so
   it reads like it. Error role, never a hardcoded colour. */
.start-warn {
  background: var(--md-sys-color-error-container);
  color: var(--md-sys-color-on-error-container);
  border-radius: var(--r-md);
  padding: 10px 12px;
  margin: 8px 0;
  font-size: var(--t-label-m);
  line-height: 1.35;
}

/* Realms V4's duties page (v5.16.0): nine rows, each a label plus four nudge buttons. `.btn-up` is
   itself `display: flex`, so in a plain block row every button becomes a block-level box on its own
   line — nine duties then cost thirty-six lines of scrolling inside `.sel-actions`, which is what
   the first phone shot of this page showed. The row is a flex line instead: the label takes the
   slack, the four buttons stay together and wrap as a group only when they must. */
.sel-duty { display: flex; align-items: center; flex-wrap: wrap; gap: 4px; }
.sel-duty .sel-duty-name { flex: 1 1 8ch; min-width: 0; }
.sel-duty .sel-duty-n { font-weight: 700; color: var(--md-sys-color-on-surface); }
.sel-duty .btn-up { flex: 0 0 auto; padding: 5px 9px; }
body[data-size="compact"] .sel-duty .btn-up { white-space: nowrap; text-align: center; }
