* { margin: 0; padding: 0; box-sizing: border-box; }

:root {
  --paper: #1a1512;
  --paper-lift: #231c17;
  --ink: #f2e8d5;
  --red: #e8432f;
  --blue: #4f86d6;
  --yellow: #eeae19;
  /* Same tan placard tags already baked onto the canvas (Theme.js's
     "INSPECTION NOTE"/"M-17A"/corridor-plate tags): notePaper is
     Theme._mix(yellow, ink, 0.54), noteInk is Theme.colors.paperShadow --
     computed to the identical rgb values so the DOM HUD reads as the same
     object as those tags, not an approximation of them. */
  --note-paper: rgb(240, 205, 127);
  --note-ink: #282019;
  /* The truly-background layer (Theme.js's faint "SECTOR M-17A"/"STAND
     CLEAR" floor text: no box, no border, just text at low alpha directly
     on the paper) -- Theme._mix(yellow, ink, 0.3). */
  --bg-text: rgb(239, 191, 81);

  /* Condensed grotesque stack, mirrored in Theme.FONT_STACK for canvas type so
     DOM and canvas headlines match. Keep the two in sync. */
  --font: 'Arial Narrow', 'Helvetica Neue Condensed', 'Liberation Sans Narrow',
          'Roboto Condensed', 'Oswald', Impact, Arial, sans-serif;

  --hud-gap: 14px;
  /* How far each HUD block/buffs stack sits off the center line, flanking
     the top-center "ACCESS CORRIDOR" plate. Shrinks at narrow viewports
     (see media queries below) so the blocks have room to render without
     running off a 320px-wide screen. */
  --hud-center-offset: 104px;
  --tick-w: 7px;
  --tick-h: 10px;
}

html, body {
  width: 100%;
  height: 100%;
  background: var(--paper);
  overflow: hidden;
  font-family: var(--font);
  /* Stop the page rubber-banding / pinch-zooming when the canvas is dragged on
     a touch screen. Touch *input* for the game is not implemented (see
     DEFERRED_COMPLEXITY.md); this only keeps the layout from being mangled. */
  touch-action: none;
  -webkit-text-size-adjust: 100%;
}

#game {
  display: block;
  background: var(--paper);
  /* The reticle is drawn on the canvas so it can carry lock state, so the
     native cursor would just be a second, less informative crosshair. */
  cursor: none;
}

/* --------------------------------------------------------------------------
   HUD
   -------------------------------------------------------------------------- */

#hud {
  pointer-events: none;
  user-select: none;
  z-index: 3;
}

.chrome-hidden {
  opacity: 0 !important;
  visibility: hidden !important;
}

/* Flanking the TOP-CENTER "ACCESS CORRIDOR" plate (js/theme.js
   corridorPlate(centroid.x, inset+18, laneW, 24, ..., vertical=false) --
   a horizontal plate up to 188px wide, centered on screen, sitting at
   roughly y:[24,48]) -- not the vertical side bars. Each block positions
   itself independently (not as flex children of one spanning row) so it
   can grow outward from a fixed offset off the center line regardless of
   its own content width. */
.hud-block {
  position: fixed;
  top: var(--hud-gap);
  left: calc(50% - var(--hud-center-offset));
  transform: translateX(-100%);
  /* Same technique as the truly-background canvas text (Theme.js's faint
     "SECTOR M-17A"/"STAND CLEAR" floor labels, globalAlpha 0.28, no box,
     no border) -- not the tan tag objects, which are still distinct
     placards. This is meant to read as part of the scene, not an object
     sitting on top of it, which is the explicit ask: legibility during
     fast combat is a real, accepted tradeoff here, not an oversight. */
  padding: 6px 0;
  flex-shrink: 0;
}

.hud-block-right {
  left: calc(50% + var(--hud-center-offset));
  transform: none;
  text-align: right;
}

#hud.hud-critical .stat-label,
#hud.hud-critical .stat-value {
  animation: hud-pulse 0.9s ease-in-out infinite;
}

@keyframes hud-pulse {
  0%, 100%  { color: var(--red); opacity: 0.85; }
  50%       { color: var(--yellow); opacity: 0.85; }
}

.stat-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  line-height: 1.15;
}

.hud-block-right .stat-row { justify-content: flex-end; }

.stat-label {
  font-weight: 900;
  font-size: 10px;
  letter-spacing: 1.1px;
  color: var(--bg-text);
  text-transform: uppercase;
  opacity: 0.6;
  white-space: nowrap;
}

/* HP/Shield/Boost/Score etc. are read at a glance mid-combat -- confirmed
   by testing that 0.4-0.55 opacity in --bg-text (matching the truly
   decorative floor text) made these functionally invisible against a busy
   arena, not just subtle. Full ink color/opacity restores legibility;
   the label above it can stay quieter since it's not the number itself. */
.stat-value {
  font-weight: 900;
  font-size: 13px;
  color: var(--ink);
  letter-spacing: 0.3px;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9), 0 0 4px rgba(0, 0, 0, 0.7);
  white-space: nowrap;
}

.stat-value-sm { font-size: 11px; opacity: 0.8; }

.stat-value-boss {
  color: var(--red);
  animation: boss-flicker 0.7s steps(2, end) infinite;
}

@keyframes boss-flicker {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}

/* Score "stamp": a quick overshoot when the value changes, which is only
   possible because the node now persists between frames. */
.stat-value.stamped { animation: stamp 0.18s ease-out; }

@keyframes stamp {
  0%   { transform: scale(1.28); color: var(--yellow); }
  100% { transform: scale(1); color: var(--ink); }
}

.tick-row {
  display: flex;
  gap: 1px;
  flex-shrink: 0;
  justify-content: flex-end;
}

.tick {
  width: var(--tick-w);
  height: var(--tick-h);
  background: transparent;
  border: 1px solid var(--ink);
  transition: background-color 0.12s linear;
}

.tick.filled.tick-red { background: var(--red); }
.tick.filled.tick-blue { background: var(--blue); }
.tick.filled.tick-yellow { background: var(--yellow); }

/* --------------------------------------------------------------------------
   Boss banner
   -------------------------------------------------------------------------- */

#boss {
  position: fixed;
  top: var(--hud-gap);
  left: 50%;
  transform: translateX(-50%) translateY(-14px);
  width: min(420px, calc(100vw - 32px));
  background: rgba(35, 28, 23, 0.72);
  backdrop-filter: blur(3px);
  border: 1.5px solid rgba(242, 232, 213, 0.88);
  box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.24);
  padding: 7px 12px 9px;
  opacity: 0;
  transition: opacity 0.25s ease, transform 0.25s ease;
  pointer-events: none;
  user-select: none;
}

#boss.visible { opacity: 1; transform: translateX(-50%) translateY(0); }

.boss-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 6px;
}

.boss-name {
  font-size: 15px;
  font-weight: 900;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--ink);
}

.boss-tag {
  font-size: 10px;
  font-weight: 900;
  letter-spacing: 2px;
  color: var(--red);
  background: rgba(232, 67, 47, 0.08);
  border: 1px solid rgba(232, 67, 47, 0.48);
  padding: 2px 7px;
}

.boss-track {
  position: relative;
  height: 12px;
  border: 1.5px solid var(--ink);
  overflow: hidden;
}

.boss-fill {
  height: 100%;
  width: 100%;
  background: var(--red);
  transition: width 0.18s linear, background-color 0.3s linear;
}

#boss.boss-wounded .boss-fill { background: var(--yellow); }

/* Notches over the gauge so a long fight shows measurable progress. */
.boss-segments {
  position: absolute;
  inset: 0;
  display: flex;
  pointer-events: none;
}

.boss-segments span {
  flex: 1;
  border-right: 1.5px solid var(--paper);
}

.boss-segments span:last-child { border-right: none; }

/* --------------------------------------------------------------------------
   Buffs
   -------------------------------------------------------------------------- */

#buffs {
  position: fixed;
  /* Anchored under the left HUD block, same left offset it uses now that
     both flank the top-center "ACCESS CORRIDOR" plate. */
  top: calc(var(--hud-gap) + 60px);
  left: calc(50% - var(--hud-center-offset));
  transform: translateX(-100%);
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: flex-start;
  pointer-events: none;
  user-select: none;
}

.buff-chip {
  background: rgba(242, 232, 213, 0.04);
  border: 1px solid rgba(242, 232, 213, 0.7);
  box-shadow: none;
  padding: 3px 7px 4px;
  min-width: 104px;
  animation: chip-in 0.18s ease-out;
}

@keyframes chip-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}

.buff-head {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* The glyph the player actually picked up off the floor, so pickup and buff
   are connected without the player having to read a label. */
.buff-icon {
  width: 13px;
  height: 13px;
  flex-shrink: 0;
  image-rendering: auto;
}

.buff-label {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
}

.buff-bar {
  margin-top: 2px;
  height: 3px;
  border: 1px solid var(--ink);
  background: transparent;
}

.buff-bar-fill {
  height: 100%;
  background: var(--yellow);
  transition: width 0.1s linear;
}

.buff-chip.buff-expiring {
  animation: chip-expiring 0.4s steps(2, end) infinite;
}

.buff-chip.buff-expiring .buff-bar-fill { background: var(--red); }

@keyframes chip-expiring {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.5; }
}

/* --------------------------------------------------------------------------
   Overlay
   -------------------------------------------------------------------------- */

#overlay {
  position: fixed;
  inset: 0;
  display: none;
  /* Phase 10. `center` alone is the bug behind "the title and Start button are
     never visible together at 907x510": a flex item taller than its container
     overflows in BOTH directions, so the top of the panel sits above the scroll
     origin and no scroll gesture can reach it — the button is not merely below
     the fold, it is unreachable. `safe center` degrades to flex-start exactly
     when overflow would occur, which turns this back into an ordinary scroll.
     The unprefixed `center` stays first as the fallback for browsers that do
     not parse the `safe` keyword; they simply ignore the second declaration. */
  align-items: center;
  align-items: safe center;
  justify-content: center;
  padding: 20px;
  background: rgba(0, 0, 0, 0.6);
  text-align: center;
  overflow-y: auto;
}

#overlay.visible { display: flex; }

.poster-panel {
  background: var(--paper);
  border: 3px solid var(--ink);
  box-shadow: 10px 10px 0 rgba(0, 0, 0, 0.38);
  padding: 32px 40px 34px;
  max-width: 520px;
  width: 100%;
  position: relative;
}

.poster-panel::before,
.poster-panel::after {
  content: '+';
  position: absolute;
  color: var(--ink);
  font-size: 18px;
  opacity: 0.5;
}
.poster-panel::before { top: 8px; left: 10px; }
.poster-panel::after { bottom: 8px; right: 10px; }

.poster-kicker {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 3px;
  color: var(--ink);
  opacity: 0.5;
  margin-bottom: 12px;
}

#overlay h1 {
  font-size: clamp(30px, 8vw, 46px);
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--ink);
  font-weight: 900;
  line-height: 1;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.28);
  margin-bottom: 14px;
}

/* Three-colour rule under the headline: the print control strip again. */
.poster-rule {
  display: flex;
  gap: 4px;
  margin: 0 auto 16px;
  width: 120px;
}

.poster-rule span { flex: 1; height: 5px; }

#overlay p {
  font-size: 15px;
  color: var(--ink);
  max-width: 440px;
  margin: 0 auto;
  line-height: 1.6;
  font-weight: 600;
  opacity: 0.9;
}

.poster-legend {
  margin: 20px auto 0;
  max-width: 400px;
  border-top: 1.5px solid rgba(242, 232, 213, 0.25);
  padding-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.legend-row {
  display: flex;
  align-items: center;
  gap: 10px;
  text-align: left;
}

.legend-key {
  flex: 0 0 96px;
  font-size: 10px;
  font-weight: 900;
  letter-spacing: 1.2px;
  color: var(--ink);
  background: rgba(242, 232, 213, 0.06);
  border: 1px solid rgba(242, 232, 213, 0.3);
  padding: 3px 6px;
  text-align: center;
  white-space: nowrap;
}

.legend-desc {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.4px;
  color: var(--ink);
  opacity: 0.8;
}

#overlay button {
  margin-top: 22px;
  padding: 12px 34px;
  font-family: var(--font);
  font-size: 15px;
  font-weight: 900;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  background: rgba(242, 232, 213, 0.08);
  color: var(--ink);
  border: 1.5px solid rgba(242, 232, 213, 0.88);
  box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.24);
  cursor: pointer;
  transition: transform 0.1s ease, background-color 0.1s ease, border-color 0.1s ease;
}

#overlay button:hover,
#overlay button:focus-visible {
  background: rgba(242, 232, 213, 0.14);
  transform: translate(-1px, -1px);
  border-color: var(--ink);
  box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.24);
  outline: none;
}

/* Secondary button (Phase 3): routes to the Print Shop from the title and
   run-over screens without competing with the primary Start/Try Again
   action for attention. */
#overlay button.poster-btn-secondary {
  display: block;
  margin: 10px auto 0;
  background: transparent;
  color: var(--ink);
  box-shadow: none;
  border-color: rgba(242, 232, 213, 0.4);
  opacity: 0.75;
}

#overlay button.poster-btn-secondary:hover,
#overlay button.poster-btn-secondary:focus-visible {
  background: transparent;
  color: var(--ink);
  opacity: 1;
  border-color: var(--ink);
  box-shadow: none;
  transform: none;
}

/* --------------------------------------------------------------------------
   Mode-select screen (Phase 8) — reached only once Meta.owned.campaignCleared
   (see main.js#showStartOverlay); a first-time player never loads this CSS
   into their visible layout.
   -------------------------------------------------------------------------- */

.mode-block {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1.5px solid rgba(242, 232, 213, 0.25);
}

.mode-block:first-of-type { margin-top: 22px; border-top: none; padding-top: 0; }

.mode-desc { max-width: 420px; }

.mode-hardmode-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 12px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.4px;
  color: var(--ink);
  opacity: 0.85;
  cursor: pointer;
}

/* --------------------------------------------------------------------------
   Level-up choice overlay (Phase 2) — same #overlay/.poster-panel chrome as
   the start/run-over screens, widened for a row of upgrade cards instead of
   a single message + button.
   -------------------------------------------------------------------------- */

.poster-panel-levelup { max-width: 760px; }

.levelup-choices {
  display: flex;
  gap: 14px;
  margin-top: 18px;
  flex-wrap: wrap;
  justify-content: center;
}

/* Scoped as `#overlay button.levelup-card`, not just `.levelup-card`: the
   base `#overlay button` rule above is an ID selector and always outranks a
   plain class regardless of declaration order, so an unscoped class here
   silently loses every property the two rules share (padding, box-shadow,
   etc.) back to the generic Start/Try-Again button metrics. Found while
   building Phase 3's Print Shop buttons, which hit the exact same collision
   — see SPEC.md Phase 3 changelog. */
#overlay button.levelup-card {
  flex: 1 1 200px;
  max-width: 220px;
  background: rgba(35, 28, 23, 0.8);
  border: 1.5px solid rgba(242, 232, 213, 0.82);
  box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.24);
  padding: 16px 14px 14px;
  font-family: var(--font);
  color: var(--ink);
  cursor: pointer;
  text-align: center;
  transition: transform 0.1s ease, box-shadow 0.1s ease, background-color 0.1s ease;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  margin-top: 0;
}

#overlay button.levelup-card:hover,
#overlay button.levelup-card:focus-visible {
  background: rgba(35, 28, 23, 0.92);
  transform: translate(-2px, -2px);
  border-color: var(--ink);
  box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.24);
  outline: none;
}

.levelup-card-icon { width: 40px; height: 40px; margin-bottom: 4px; }

.levelup-card-line {
  font-size: 9px;
  font-weight: 900;
  letter-spacing: 1.5px;
  color: var(--yellow);
  opacity: 0.8;
}

.levelup-card-label {
  font-size: 15px;
  font-weight: 900;
  letter-spacing: 0.6px;
  text-transform: uppercase;
}

.levelup-card-desc {
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.4;
  opacity: 0.85;
  min-height: 44px;
}

.levelup-card-owned {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--yellow);
  margin-top: 2px;
}

/* Second Plate reroll button (Phase 3) — deliberately styled like the
   secondary overlay button (low emphasis) rather than the primary
   Start/Try Again style, since it's a one-time-per-event convenience, not
   the main action of this screen. */
/* Scoped under `#overlay button` for the same specificity reason as
   `#overlay button.levelup-card` above. */
#overlay button.levelup-reroll-btn {
  display: block;
  margin: 16px auto 0;
  padding: 9px 22px;
  font-family: var(--font);
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 1px;
  text-transform: uppercase;
  background: transparent;
  color: var(--ink);
  border: 2px solid rgba(242, 232, 213, 0.4);
  box-shadow: none;
  cursor: pointer;
  opacity: 0.8;
  transition: opacity 0.1s ease, border-color 0.1s ease;
}

#overlay button.levelup-reroll-btn:hover,
#overlay button.levelup-reroll-btn:focus-visible {
  background: transparent;
  opacity: 1;
  border-color: var(--ink);
  box-shadow: none;
  transform: none;
  outline: none;
}

@media (max-width: 520px) {
  .poster-panel-levelup { max-width: 100%; }
  .levelup-choices { flex-direction: column; align-items: stretch; }
  .levelup-card { max-width: none; }
}

/* --------------------------------------------------------------------------
   Print Shop (Phase 3) — same #overlay/.poster-panel chrome as every other
   screen, widened for a grid of unlock cards.
   -------------------------------------------------------------------------- */

.poster-panel-shop { max-width: 780px; }

.shop-balance {
  font-size: 15px;
  font-weight: 800;
  color: var(--ink);
  opacity: 0.88;
  margin: 0 0 4px;
}

.shop-grid {
  display: flex;
  gap: 14px;
  margin-top: 14px;
  flex-wrap: wrap;
  justify-content: center;
}

.shop-card {
  flex: 1 1 200px;
  max-width: 220px;
  background: rgba(35, 28, 23, 0.8);
  border: 1.5px solid rgba(242, 232, 213, 0.82);
  box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.24);
  padding: 14px 14px 12px;
  color: var(--ink);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}

.shop-card-owned {
  border-color: rgba(238, 174, 25, 0.92);
  box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.24);
  opacity: 0.9;
}

.shop-card-icon { width: 34px; height: 34px; }

/* Phase 12 paper-stock swatch: the three tones a palette actually assigns
   (paper / lift / shadow), in that order, so the card shows what is being
   bought rather than naming it. No PLATE_BLEND here — these are DOM elements
   showing raw stock colour, not ink printed onto paper. */
.shop-card-swatch { display: flex; gap: 3px; height: 34px; align-items: center; }
.shop-card-swatch span {
  width: 18px; height: 34px;
  border: 1px solid rgba(242, 232, 213, 0.22);
}

.shop-card-label {
  font-size: 14px;
  font-weight: 900;
  letter-spacing: 0.5px;
  text-transform: uppercase;
}

.shop-card-desc {
  font-size: 11px;
  font-weight: 600;
  line-height: 1.4;
  opacity: 0.85;
  min-height: 44px;
}

.shop-card-cost {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ink);
  opacity: 0.74;
}

/* Scoped under `#overlay button` for the same specificity reason as
   `#overlay button.levelup-card` above — an unscoped `.shop-buy-btn` class
   loses every shared property (padding, background, and critically the
   :disabled state) back to the base Start/Try-Again button rule. */
#overlay button.shop-buy-btn {
  margin-top: 4px;
  padding: 7px 18px;
  font-family: var(--font);
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 1px;
  text-transform: uppercase;
  background: rgba(242, 232, 213, 0.08);
  color: var(--ink);
  border: 1.5px solid rgba(242, 232, 213, 0.82);
  box-shadow: none;
  cursor: pointer;
}

#overlay button.shop-buy-btn:hover,
#overlay button.shop-buy-btn:focus-visible {
  background: rgba(242, 232, 213, 0.14);
  box-shadow: none;
  transform: none;
  outline: none;
}

#overlay button.shop-buy-btn:disabled {
  background: transparent;
  color: var(--ink);
  opacity: 0.4;
  cursor: not-allowed;
}

.shop-warmpress-picker {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
  margin-top: 4px;
}

#overlay button.shop-warmpress-option {
  margin-top: 0;
  padding: 5px 8px;
  font-family: var(--font);
  font-size: 11px;
  font-weight: 700;
  background: transparent;
  color: var(--ink);
  border: 1.5px solid rgba(242, 232, 213, 0.4);
  box-shadow: none;
  cursor: pointer;
}

#overlay button.shop-warmpress-option:hover,
#overlay button.shop-warmpress-option:focus-visible {
  background: transparent;
  border-color: var(--ink);
  box-shadow: none;
  transform: none;
  outline: none;
}

#overlay button.shop-warmpress-option.selected {
  border-color: var(--yellow);
  color: var(--yellow);
}

@media (max-width: 520px) {
  .poster-panel-shop { max-width: 100%; }
  .shop-grid { flex-direction: column; align-items: stretch; }
  .shop-card { max-width: none; }
}

/* --------------------------------------------------------------------------
   Toast — bottom centre, so it never collides with the boss banner or the
   oversized wave numeral drawn at the centre of the canvas.
   -------------------------------------------------------------------------- */

#toast {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, calc(-50% + 10px));
  max-width: min(340px, calc(100vw - 32px));
  background: rgba(35, 28, 23, 0.74);
  backdrop-filter: blur(3px);
  border: 1.5px solid rgba(242, 232, 213, 0.82);
  box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.26);
  color: var(--ink);
  padding: 8px 16px;
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  text-align: center;
  opacity: 0;
  transition: opacity 0.25s ease, transform 0.25s ease;
  pointer-events: none;
}

/* The #mute-btn rules that sat here are gone with the button. Audio is
   Settings-only now (Music / Sound effects sliders, either at 0 = silence),
   reachable from the title screen and the pause overlay. */

#toast.visible {
  opacity: 1;
  transform: translate(-50%, -50%);
}

#toast.toast-boss {
  max-width: min(420px, calc(100vw - 32px));
  padding: 12px 22px;
  font-size: 18px;
  letter-spacing: 2.4px;
  border-color: rgba(232, 67, 47, 0.9);
  background: rgba(35, 28, 23, 0.86);
  box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.3);
}

/* Phase 6: weapon evolution announcement — blue, the player's own colour
   (§3.5's allegiance rule), since this is the player's own build reaching a
   milestone, not a hostile event. Same sizing as .toast-boss. */
#toast.toast-evolution {
  max-width: min(420px, calc(100vw - 32px));
  padding: 12px 22px;
  font-size: 18px;
  letter-spacing: 2.4px;
  border-color: rgba(79, 134, 214, 0.9);
  background: rgba(35, 28, 23, 0.86);
  box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.3);
}

/* Phase 6: boss phase-2 transition — yellow, the hazard-accent spot colour
   (§3.5), distinct from both the red boss-wave toast and the blue evolution
   one. Same sizing as .toast-boss. */
#toast.toast-bossphase {
  max-width: min(420px, calc(100vw - 32px));
  padding: 12px 22px;
  font-size: 18px;
  letter-spacing: 2.4px;
  border-color: rgba(238, 174, 25, 0.9);
  background: rgba(35, 28, 23, 0.86);
  box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.3);
}

/* --------------------------------------------------------------------------
   Responsive. The old HUD was fixed-pixel only: the two blocks have a combined
   intrinsic width of ~349px plus 32px of margin, so below ~381px they collide.
   These breakpoints shrink the gauges and type instead of letting that happen.
   Layout only — the game still needs a keyboard and mouse, see
   DEFERRED_COMPLEXITY.md.
   -------------------------------------------------------------------------- */

/* Phase 10: found by verify.sh § HUD LAYOUT the first run after the harness
   was repaired — `bossBannerCollidesHud: true` at 1280x800 AND 907x510, i.e.
   the default desktop size and a common portal iframe. The banner is centred at
   `top: var(--hud-gap)` and 420px wide; the HUD's centre-flanking blocks sit on
   the same line (at 1280: banner x430-850 against a block at x401-536, both at
   y14). The max-width:900 rule below has always moved the banner to the bottom
   lane on narrow screens for exactly this reason — nobody checked that the wide
   case had the same problem, because until now nothing measured a collision
   above 900px. Drop it below the HUD row instead of moving it, so the banner
   keeps its top-centre position on the screens where there is room for it. */
@media (min-width: 901px) {
  /* 90, not the 76 this first tried: #boss carries translateY(-14px) in its
     hidden state, so its measured top is 14px above its CSS top, and the
     lower HUD block's bottom edge is at 69. 76 left a 7px overlap in exactly
     the hidden state the probe (correctly) measures as the worst case. */
  #boss { top: 90px; }
}

/* On narrower screens the boss banner drops to the bottom lane so it stays
   clear of the split corner HUD. */
@media (max-width: 900px) {
  #boss {
    top: auto;
    bottom: 74px;
    width: calc(100vw - 20px);
    transform: translateX(-50%) translateY(14px);
  }
  #boss.visible { transform: translateX(-50%) translateY(0); }
}

@media (max-width: 720px) {
  :root { --hud-gap: 10px; --hud-center-offset: 80px; --tick-w: 6px; --tick-h: 10px; }
  .hud-block { padding: 5px 8px; }
  .stat-label { font-size: 10px; letter-spacing: 1px; }
  .stat-value { font-size: 14px; }
  .buff-chip { min-width: 116px; }
  .boss-name { font-size: 13px; letter-spacing: 2px; }
}

@media (max-width: 520px) {
  :root { --tick-w: 5px; --tick-h: 9px; --hud-center-offset: 38px; }
  .stat-label { font-size: 9px; letter-spacing: 0.5px; }
  .stat-value { font-size: 12px; }
  .stat-row { gap: 6px; line-height: 1.1; }
  .hud-block { padding: 4px 7px; }
  .buff-chip { min-width: 0; padding: 3px 7px 4px; }
  .buff-label { font-size: 10px; letter-spacing: 0.4px; }
  .legend-key { flex-basis: 78px; font-size: 9px; }
  .legend-desc { font-size: 11px; }
  #toast {
    font-size: 11px;
    padding: 6px 12px;
    max-width: min(260px, calc(100vw - 24px));
  }
  #toast.toast-boss,
  #toast.toast-evolution,
  #toast.toast-bossphase {
    max-width: min(300px, calc(100vw - 24px));
    padding: 8px 14px;
    font-size: 14px;
    letter-spacing: 1.8px;
  }

}

/* Compact poster panel. Phase 10 moved these rules out of the max-width block
   above and gave them BOTH axes as triggers.
   Original note, still true: the panel measured 602px against a 568px screen
   (an iPhone SE in portrait); a start screen that needs scrolling to reach its
   own button is a bad first impression, so tighten it to fit instead.
   What was wrong: a 740x400 landscape phone — and a 907x510 portal iframe,
   which is the shape that actually matters for embedding — matches only a
   height condition, so it received none of this and kept the full-size kicker,
   padding and type. Either axis being tight now compacts the panel. */
@media (max-width: 520px), (max-height: 560px) {
  .poster-panel { padding: 18px 18px 20px; }
  .poster-kicker { display: none; }
  #overlay h1 { margin-bottom: 10px; letter-spacing: 2px; }
  .poster-rule { margin-bottom: 10px; width: 96px; }
  #overlay p { font-size: 13px; line-height: 1.45; }
  .poster-legend { margin-top: 12px; padding-top: 8px; gap: 4px; }
  #overlay button { margin-top: 14px; padding: 10px 26px; font-size: 14px; }
}

/* Short viewports only: the five-row control legend is the largest remaining
   block once the intro copy is one line, so lay it out in two columns rather
   than five stacked rows. Grid (not the flex row default) because the key and
   description need to stay on one line together per entry. */
@media (max-height: 560px) {
  .poster-legend {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2px 14px;
    text-align: left;
  }
  .legend-key { flex-basis: 66px; font-size: 9px; }
  .legend-desc { font-size: 10px; line-height: 1.25; }
}

/* Short/landscape viewports: the boss banner and the buff strip are the first
   things to crowd a 400px-tall window. */
@media (max-height: 460px) {
  :root { --hud-gap: 8px; }
  #buffs { flex-direction: row; flex-wrap: wrap; max-width: 60vw; }
  #toast {
    top: 54%;
    font-size: 11px;
  }
  #toast.toast-boss,
  #toast.toast-evolution,
  #toast.toast-bossphase {
    font-size: 14px;
  }
  .poster-panel { padding: 18px 22px 20px; }
  .poster-legend { margin-top: 12px; padding-top: 8px; }
  #overlay h1 { font-size: clamp(24px, 6vh, 34px); margin-bottom: 8px; }
  #overlay p { font-size: 13px; }
  /* Phase 3's secondary button is the newest addition to this panel and the
     first thing a short landscape viewport can afford to shrink. */
  #overlay button.poster-btn-secondary { margin-top: 6px; padding: 6px 16px; font-size: 11px; }
  /* Phase 8: the mode-select screen only reaches players who've already
     cleared Campaign once, but it still has to fit — not measured against a
     real device yet, see DEFERRED_COMPLEXITY.md. */
  .mode-block { margin-top: 8px; padding-top: 6px; }
  .mode-block:first-of-type { margin-top: 12px; }
  .mode-hardmode-row { margin-top: 6px; font-size: 11px; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* Phase 10 settings panel. Deliberately plain: this is the accessibility and
   comfort floor reviewers dock for, not a design surface. Range inputs keep
   their native behaviour (keyboard-operable, screen-reader-labelled) rather
   than being restyled into something custom and worse. */
.settings-list {
  margin-top: 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  text-align: left;
}

.settings-row {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas: "label value" "control control";
  align-items: center;
  gap: 4px 10px;
}

.settings-label {
  grid-area: label;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--ink);
}

.settings-value {
  grid-area: value;
  font-size: 11px;
  font-weight: 700;
  color: var(--ink);
  opacity: 0.7;
  font-variant-numeric: tabular-nums;
}

.settings-slider {
  grid-area: control;
  width: 100%;
  accent-color: var(--blue);
  cursor: pointer;
}

/* Phase 12 House Style picker. Stacks under its label rather than sitting
   beside it like the sliders and the shake toggle: with six stocks owned this
   row holds seven buttons, which will not fit a settings row at a 320px
   viewport. */
.settings-row-stack { flex-direction: column; align-items: flex-start; gap: 8px; }
.settings-stock-picker { display: flex; flex-wrap: wrap; gap: 6px; }
.settings-stock-opt {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px;
  font: inherit; font-size: 0.78rem; letter-spacing: 0.04em;
  color: var(--ink);
  background: transparent;
  border: 1px solid rgba(242, 232, 213, 0.28);
  cursor: pointer;
}
.settings-stock-opt.selected { border-color: var(--yellow); color: var(--yellow); }
.settings-stock-dot {
  width: 13px; height: 13px;
  border: 1px solid rgba(242, 232, 213, 0.4);
}

.settings-toggle {
  grid-area: value;
  font-family: inherit;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 1.4px;
  padding: 3px 12px;
  min-width: 58px;
  color: var(--paper);
  background: var(--blue);
  border: 2px solid var(--ink);
  cursor: pointer;
}

.settings-toggle.is-off {
  background: transparent;
  color: var(--ink);
  opacity: 0.65;
}

@media (max-height: 560px) {
  .settings-list { margin-top: 10px; gap: 7px; }
  .settings-row { grid-template-areas: "label value" "control control"; }
  .settings-label, .settings-value { font-size: 10px; }
}

/* Phase 10: what a level-up card is building toward. Sits under the owned
   count, visually subordinate to the card's own name and description — it is
   context for the pick, not the pick itself. */
/* Phase 12: the six .levelup-card-evo / .levelup-evo-* rules were deleted
   here. They styled the recipe readout on level-up cards, which SPEC.md
   Phase 12 § 3 removes — verify.sh § EVOLUTION DISCOVERY now asserts those
   nodes are absent from the DOM, so the rules had nothing left to match. */

/* Print Shop evolution catalogue — a reference sheet, nothing buyable. */
.shop-evolutions {
  margin-top: 22px;
  padding-top: 14px;
  border-top: 2px solid var(--ink);
  text-align: left;
}

.shop-evo-head {
  font-size: 10px;
  font-weight: 900;
  letter-spacing: 2px;
  color: var(--yellow);
  margin-bottom: 4px;
}

/* ID selector, not a bare class: #overlay p (max-width 440px, margin 0 auto)
   outranks .shop-evo-note on specificity and kept re-indenting this note even
   with text-align set. The section is a reference sheet and reads as a column,
   so heading, note and rows must share one left edge. */
#overlay .shop-evo-note {
  text-align: left;
  max-width: none;
  margin: 0 0 12px;
  font-size: 11px;
  line-height: 1.4;
  color: var(--ink);
  opacity: 0.62;
}

.shop-evo-row {
  margin-bottom: 11px;
  padding-left: 9px;
  border-left: 3px solid var(--blue);
}

.shop-evo-name {
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--ink);
}

.shop-evo-recipe {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.4px;
  color: var(--blue);
  margin: 2px 0 3px;
}

.shop-evo-desc {
  font-size: 11px;
  line-height: 1.4;
  color: var(--ink);
  opacity: 0.75;
}

@media (max-height: 560px) {
  .shop-evolutions { margin-top: 14px; padding-top: 9px; }
  .shop-evo-note { margin-bottom: 8px; }
  .shop-evo-row { margin-bottom: 7px; }
}
