/* css/menus.css — full-screen menus for Commie vs Zombies.
   Soviet constructivist: red/black/gold, uppercase, sharp corners, star motifs.
   Uses shared primitives from style.css: .soviet-panel, .soviet-btn, .star, .hidden. */

#menus-root { position: absolute; inset: 0; pointer-events: none; }
#menus-root.hidden { display: none !important; }

.menu-screen {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: flex-start;
  padding: 6vh 6vw;
  pointer-events: auto;
  animation: menu-fadein 0.35s ease-out;
}
#screen-pause, #screen-death, #screen-perk, #screen-save, #screen-load { justify-content: center; }
#screen-pause, #screen-death, #screen-perk { background: rgba(5, 3, 2, 0.72); }
#screen-load, #screen-save, #screen-options, #screen-difficulty { background: rgba(5, 3, 2, 0.45); }

@keyframes menu-fadein { from { opacity: 0; } to { opacity: 1; } }

.menu-panel { padding: 34px 40px; max-width: 560px; width: 100%; }
.main-panel { max-width: 480px; }
.wide-panel { max-width: 640px; max-height: 86vh; overflow-y: auto; }

.menu-title {
  font-size: var(--fs-3xl); font-weight: bold; color: var(--gold);
  letter-spacing: 0.12em; line-height: 1.05; margin-bottom: 6px;
  text-shadow: 3px 3px 0 var(--red-dark);
}
.menu-head {
  font-size: var(--fs-xl); font-weight: bold; color: var(--gold);
  letter-spacing: 0.14em; margin-bottom: 18px;
  border-bottom: 2px solid var(--red); padding-bottom: 10px;
}
.menu-sub { font-size: var(--fs-md); color: var(--paper); opacity: 0.75; letter-spacing: 0.2em; margin-bottom: 26px; }
.menu-foot { margin-top: 22px; font-size: var(--fs-xs); color: var(--gold); opacity: 0.65; letter-spacing: 0.22em; }
.quit-msg { margin-top: 10px; font-size: var(--fs-sm); color: var(--gold); min-height: 18px; letter-spacing: 0.12em; }

.menu-btn { margin-top: 10px; position: relative; }
/* 15.2: an owed commendation, offered in the pause menu rather than thrown over
   the fight the moment it was earned. Gold fill so it reads as the one thing on
   this screen that is waiting for the player. */
.menu-btn.perk-due { border-color: var(--gold); color: #14110c; background: var(--gold); }
.menu-btn.perk-due:hover { background: #f5cf5e; }
.menu-btn:hover { box-shadow: inset 4px 0 0 var(--gold); }
.menu-btn.selected { background: var(--red-dark); color: #fff; border-color: var(--gold); }
.back-btn { margin-top: 22px; opacity: 0.85; }

/* ---------- difficulty select ---------- */
.diff-card {
  display: block; width: 100%; text-align: left; cursor: pointer;
  background: var(--ink); border: 2px solid var(--red);
  color: var(--paper); font-family: var(--font);
  padding: 14px 18px; margin-top: 12px; text-transform: uppercase; letter-spacing: 0.08em;
}
.diff-card:hover { background: var(--red); color: #fff; }
.diff-card.selected { border-color: var(--gold); box-shadow: inset 5px 0 0 var(--gold); }
.diff-name { font-size: var(--fs-xl); font-weight: bold; color: var(--gold); letter-spacing: 0.14em; }
.diff-card:hover .diff-name { color: #fff; }
.diff-desc { font-size: var(--fs-sm); margin-top: 6px; opacity: 0.85; line-height: 1.35; text-transform: none; letter-spacing: 0.04em; }
.diff-stats { font-size: var(--fs-xs); margin-top: 8px; color: var(--gold); opacity: 0.8; letter-spacing: 0.16em; }
.diff-card:hover .diff-stats { color: #fff; }

/* ---------- save/load slots ---------- */
.slot-row {
  display: flex; width: 100%; align-items: baseline; justify-content: space-between; gap: 16px;
  background: var(--ink); border: 2px solid var(--red); color: var(--paper);
  font-family: var(--font); padding: 14px 18px; margin-top: 10px;
  cursor: pointer; text-transform: uppercase; letter-spacing: 0.1em; text-align: left;
}
.slot-row:hover:not(:disabled) { background: var(--red); color: #fff; }
.slot-row:disabled { opacity: 0.35; cursor: default; }
.slot-name { font-size: var(--fs-lg); font-weight: bold; letter-spacing: 0.16em; }
.slot-meta { font-size: var(--fs-sm); color: var(--gold); opacity: 0.85; letter-spacing: 0.1em; }
.slot-row:hover:not(:disabled) .slot-meta { color: #fff; }
.save-confirm { margin-top: 14px; min-height: 18px; font-size: var(--fs-sm); color: var(--gold); letter-spacing: 0.14em; }

/* ---------- options ---------- */
.opt-row {
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  padding: 10px 0; border-bottom: 1px solid rgba(192, 32, 32, 0.35);
}
.opt-label { font-size: var(--fs-md); font-weight: bold; letter-spacing: 0.14em; }
.opt-ctrl { display: flex; align-items: center; gap: 12px; min-width: 240px; }
/* 15.5: a row of mutually exclusive choices (BUTTON PROMPTS). Four labels, one
   of them PLAYSTATION, do not fit the 240px control column at the shared button
   size — the first cut clipped it to "PLAYSTATIO" — so this row wraps, sizes to
   its content and uses a smaller type scale than a menu button. */
.opt-choice { flex-wrap: wrap; justify-content: flex-end; gap: 6px; min-width: 300px; }
.opt-choice .menu-btn { margin-top: 0; padding: 6px 10px; font-size: var(--fs-xs); letter-spacing: 0.06em;
  width: auto; flex: 0 0 auto; }
.opt-choice .menu-btn.selected { background: var(--red); color: var(--paper); border-color: var(--gold); }
.opt-ctrl input[type='range'] {
  -webkit-appearance: none; appearance: none;
  width: 180px; height: 6px; background: var(--grey); outline: none; cursor: pointer;
}
.opt-ctrl input[type='range']::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 16px; height: 22px; background: var(--gold); border: 2px solid var(--red); cursor: pointer;
}
.opt-ctrl input[type='range']::-moz-range-thumb {
  width: 16px; height: 22px; background: var(--gold); border: 2px solid var(--red); cursor: pointer; border-radius: 0;
}
.opt-val { font-size: var(--fs-sm); color: var(--gold); min-width: 46px; text-align: right; }
.opt-check {
  width: 22px; height: 22px; cursor: pointer; accent-color: var(--red);
  border: 2px solid var(--red); background: var(--ink);
}
.diff-label { margin-top: 18px; }
.diff-label:first-child { margin-top: 0; }
.opt-diff { display: flex; gap: 8px; margin-top: 8px; }
.opt-diff .menu-btn { margin-top: 0; padding: 10px 14px; font-size: var(--fs-sm); text-align: center; }

/* ---------- settings sub-categories (Phase 12.4) ----------
   AUDIO · GAMEPLAY · CONTROLS · GRAPHICS · DISPLAY. Deliberately a size step
   DOWN from .pause-tab: those are the primary navigation and these sit inside
   one of them, so making them identical would flatten the hierarchy and leave
   two rows of equally loud tabs stacked on each other. */
.opt-tabs {
  display: flex; flex-wrap: wrap; gap: 4px;
  margin: 0 0 16px; padding-bottom: 14px;
  border-bottom: 2px solid rgba(192, 32, 32, 0.45);
}
.opt-tab {
  /* .soviet-btn is display:block; width:100%, which makes five of these stack
     into five full-width rows. Override both so they share one line. */
  flex: 1 1 0; width: auto; min-width: 0; margin-top: 0;
  padding: 7px 6px; font-size: clamp(11px, 0.85vw, 14px); letter-spacing: 0.08em;
  text-align: center; white-space: nowrap;
}
.opt-tab.active {
  background: var(--red); color: #fff;
  border-color: var(--gold);
  box-shadow: inset 0 -3px 0 var(--gold);
}
.opt-tab.active:hover { box-shadow: inset 0 -3px 0 var(--gold); }
/* A fixed floor stops the panel resizing as you move between a three-row tab
   and the twelve-row key-binding list, which made the menu jump under the
   cursor. */
.opt-body { min-height: 260px; }
.opt-body > .opt-row:first-child { padding-top: 0; }

/* ---------- death screen ---------- */
#screen-death { background: rgba(20, 0, 0, 0.78); }
.death-panel { border-color: var(--red-dark); text-align: left; animation: death-in 1.2s ease-out; }
@keyframes death-in { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
.death-title {
  font-size: var(--fs-2xl); font-weight: bold; color: var(--red);
  letter-spacing: 0.14em; line-height: 1.15; margin-bottom: 8px;
  text-shadow: 2px 2px 0 #000;
}

/* ---------- perk chooser ---------- */
.perk-grid { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 8px; }
.perk-card {
  flex: 1 1 240px; text-align: left; cursor: pointer;
  background: var(--ink); border: 2px solid var(--gold); color: var(--paper);
  font-family: var(--font); padding: 16px 18px; text-transform: uppercase; letter-spacing: 0.08em;
}
.perk-card:hover { background: var(--red); border-color: var(--red); color: #fff; }
.perk-name { font-size: var(--fs-lg); font-weight: bold; color: var(--gold); letter-spacing: 0.12em; }
.perk-card:hover .perk-name { color: #fff; }
.perk-desc { font-size: var(--fs-sm); margin-top: 8px; opacity: 0.85; text-transform: none; letter-spacing: 0.04em; }

/* ---------- PHASE 42.2: the worker's record (pause tab 'character') ---------- */
/* A commendation ALREADY HELD is not a button. It reuses .perk-card's frame so
   the two pages read as one system, and then removes the affordances — the
   pointer, the hover fill — because there is nothing here to click. */
.perk-card.held { cursor: default; border-color: var(--red-dark); }
.perk-card.held:hover { background: var(--ink); border-color: var(--red-dark); color: var(--paper); }
.perk-card.held:hover .perk-name { color: var(--gold); }
.record-perks { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 8px; }
.record-stats { margin: 6px 0 4px; }
.record-row { display: flex; justify-content: space-between; align-items: baseline;
  gap: 18px; padding: 5px 2px; border-bottom: 1px solid rgba(160, 40, 40, 0.35); }
.record-k { font-size: var(--fs-xs); color: #a89f8c; letter-spacing: 0.2em; }
.record-v { font-size: var(--fs-md); font-weight: bold; color: var(--gold); letter-spacing: 0.08em; }

/* ---------- PHASE 42.4: standing with the commune (RECORD tab) ---------- */
/* The bar is read as a POSITION BETWEEN TWO NAMED THINGS, not as a score, which
   is why the legend under it always names the next band rather than repeating
   the number. */
.standing-bar {
  position: relative; height: 14px; margin: 10px 0 6px;
  border: 2px solid var(--red-dark); background: rgba(0, 0, 0, 0.45);
}
.standing-fill {
  position: absolute; inset: 0 auto 0 0;
  background: linear-gradient(90deg, var(--red) 0%, var(--gold) 100%);
}
.standing-legend {
  font-size: var(--fs-xs); color: #a89f8c; letter-spacing: 0.14em; margin-bottom: 8px;
}
.standing-ledger .record-row { border-bottom: none; padding-bottom: 0; }
.standing-ledger .record-v.neg { color: var(--red); }
.standing-detail {
  font-size: var(--fs-xs); color: var(--grey); text-transform: none; letter-spacing: 0.03em;
  padding: 0 2px 6px; border-bottom: 1px solid rgba(160, 40, 40, 0.35);
}

/* ---------- PHASE 42.4: the wait controls (pause MENU tab) ---------- */
/* .soviet-btn is display:block; width:100%, so three of them stack full-width
   and push RESUME/SAVE/LOAD/QUIT off a 720p panel. .radio-btn (:444) already
   solved exactly this for the radio's side-by-side pair — same override.
   ⚠️  NEVER give these :disabled. gamepad.js:77 and the controller-reach audit
       both select `#ui button:not(:disabled)`, so a disabled wait button drops
       out of the D-pad flood instead of being audited by it. They stay enabled
       and js/game/rest.js refuses on the press, out loud. */
.wait-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.wait-btn {
  min-width: 132px; width: auto; flex: 1 1 auto; margin: 0;
  padding: 9px 12px; text-align: center; font-size: var(--fs-sm);
}
.wait-btn:not(:disabled) { border-color: var(--gold); color: var(--gold); }
.wait-btn:not(:disabled):hover { color: #fff; }

/* ---------- ending: fireworks ---------- */
#screen-ending { padding: 0; background: transparent; overflow: hidden; }
.ending-fw { position: absolute; inset: 0; pointer-events: none; z-index: 1; }
.fw-burst { position: absolute; width: 0; height: 0; }
.fw-spark {
  position: absolute; left: -3px; top: -3px; width: 6px; height: 6px;
  background: var(--gold); box-shadow: 0 0 8px var(--gold);
  animation: fw-fly 1.15s ease-out forwards;
}
.fw-spark.red { background: var(--red); box-shadow: 0 0 8px var(--red); }
.fw-ring {
  position: absolute; left: -4px; top: -4px; width: 8px; height: 8px;
  border: 2px solid var(--gold); opacity: 0.9;
  animation: fw-ring 1.15s ease-out forwards;
}
@keyframes fw-fly {
  from { transform: rotate(var(--a)) translateY(0) scale(1); opacity: 1; }
  to { transform: rotate(var(--a)) translateY(-110px) scale(0.4); opacity: 0; }
}
@keyframes fw-ring {
  from { transform: scale(1); opacity: 0.9; }
  to { transform: scale(16); opacity: 0; }
}

/* ---------- ending: text crawl & credits ---------- */
.crawl-wrap, .credits-wrap {
  position: absolute; inset: 0; overflow: hidden; z-index: 2; pointer-events: none;
  background: linear-gradient(0deg, rgba(5, 3, 2, 0.55) 0%, transparent 35%, transparent 70%, rgba(5, 3, 2, 0.55) 100%);
}
.crawl, .credits { position: absolute; left: 0; right: 0; top: 100%; text-align: center; }
.crawl { animation: scroll-up 33s linear forwards; }
.credits { animation: scroll-up 27s linear forwards; }
@keyframes scroll-up { to { transform: translateY(calc(-100% - 100vh)); } }
.crawl-line {
  font-size: var(--fs-2xl); font-weight: bold; color: var(--paper);
  letter-spacing: 0.14em; margin: 40px 0; text-shadow: 2px 2px 0 #000;
}
.crawl-line:last-child { color: var(--gold); font-size: var(--fs-2xl); }
.credits-line { font-size: var(--fs-lg); color: var(--paper); letter-spacing: 0.18em; margin: 14px 0; opacity: 0.9; }
.credits-line:nth-child(3) { font-size: var(--fs-2xl); color: var(--gold); font-weight: bold; }

.ending-skip {
  position: absolute; right: 26px; bottom: 26px; width: auto; z-index: 3;
  padding: 10px 20px; font-size: var(--fs-md); opacity: 0.85;
}

/* ---------- ending: post-credits sting ---------- */
.sting {
  position: absolute; inset: 0; z-index: 4; background: #000;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; padding: 0 8vw;
}
.sting-line {
  font-size: var(--fs-xl); color: var(--paper); letter-spacing: 0.16em; margin: 14px 0;
  opacity: 0; transition: opacity 0.9s ease-in;
}
.sting-line.on { opacity: 1; }
.sting-l1 { color: var(--red); }
.sting-l4 { color: var(--gold); font-size: var(--fs-2xl); font-weight: bold; margin-top: 42px; letter-spacing: 0.2em; }
.sting-back { width: auto; margin-top: 48px; padding: 12px 30px; }

/* ==================== Phase 2: pause tabs, world map, fast travel, quest log ==================== */

#screen-worldmap { background: rgba(5, 3, 2, 0.45); }

/* ---------- pause: tabbed panel (MENU · MAP · QUEST LOG · SETTINGS) ---------- */
.pause-panel { max-width: 780px; max-height: 88vh; overflow-y: auto; }
.pause-tabs { display: flex; gap: 6px; margin-bottom: 16px; }
.pause-tab {
  flex: 1; padding: 9px 6px; cursor: pointer; text-align: center;
  background: var(--ink); border: 2px solid var(--red); color: var(--paper);
  font-family: var(--font); font-size: var(--fs-md); font-weight: bold;
  letter-spacing: 0.14em; text-transform: uppercase;
}
.pause-tab:hover { background: var(--red); color: #fff; }
.pause-tab.active { background: var(--red); color: #fff; border-color: var(--gold); box-shadow: inset 0 -4px 0 var(--gold); }
.pause-body { min-height: 300px; }

/* ---------- world map (pause MAP tab + main-menu MAP survey) ---------- */
.map-wrap { position: relative; display: flex; flex-direction: column; align-items: center; }
/* 15.4: the map is the thing the player opens most, so it takes as much of the
   panel as it can get. Capped against the viewport height so it never pushes the
   fast-travel button off the bottom at 720p. */
/* ⚠️  DRIVE WIDTH AND HEIGHT FROM THE SAME VALUE. A `max-height` cap next to a
   `width: min(...)` does not preserve the square: the browser applies both and
   the map comes out stretched, which pulls the whole city plan out of shape.
   One expression, used twice, cannot do that. */
.map-canvas {
  display: block;
  width: min(680px, 100%, 62vh); height: min(680px, 100%, 62vh);
  background: #060505; border: 3px solid var(--red); cursor: pointer;
}
.worldmap-canvas { width: min(560px, 100%); cursor: default; border-color: var(--grey); }
.map-hint { margin-top: 10px; font-size: var(--fs-xs); color: var(--gold); opacity: 0.75; letter-spacing: 0.18em; text-align: center; }
.map-tip {
  position: fixed; z-index: 30; pointer-events: none;
  background: var(--ink); border: 2px solid var(--gold); color: var(--gold);
  font-size: var(--fs-xs); letter-spacing: 0.12em; padding: 4px 10px; text-transform: uppercase;
}
.ft-btn { margin-top: 14px; }
.ft-btn:not(:disabled) { border-color: var(--gold); color: var(--gold); }
.ft-btn:not(:disabled):hover { color: #fff; }

/* fast-travel blackout: 0.75s to black + 0.75s back = the contract's 1.5s fade */
.ft-fade {
  position: absolute; inset: 0; z-index: 30; background: #000;
  opacity: 0; pointer-events: none; transition: opacity 0.75s ease-in-out;
}
.ft-fade.on { opacity: 1; }

/* title-menu keyboard/gamepad selection (Q/E · LB/RB cycling) */
.menu-btn.tab-focus { background: var(--red); color: #fff; box-shadow: inset 4px 0 0 var(--gold); }

/* ---------- quest log (pause QUEST LOG tab) ---------- */
.ql-wrap { display: flex; gap: 14px; height: 400px; }
.ql-list {
  flex: 0 0 42%; overflow-y: auto; padding: 6px;
  background: rgba(0, 0, 0, 0.4); border: 2px solid var(--red);
}
.ql-detail {
  flex: 1; min-width: 0; overflow-y: auto; padding: 14px 16px;
  background: rgba(0, 0, 0, 0.4); border: 2px solid var(--red);
}
.ql-empty { padding: 18px 10px; font-size: var(--fs-sm); opacity: 0.6; letter-spacing: 0.14em; text-align: center; }
.ql-item {
  display: flex; align-items: center; gap: 9px; width: 100%; text-align: left; cursor: pointer;
  background: transparent; border: 2px solid transparent; color: var(--paper);
  font-family: var(--font); font-size: var(--fs-sm); letter-spacing: 0.08em;
  padding: 9px 10px; margin-bottom: 4px; text-transform: uppercase;
}
.ql-item:hover { border-color: var(--red); }
.ql-item.selected { /* the red constructivist block */
  background: var(--red); color: #fff; border-color: var(--gold);
  box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.65);
}
.ql-item.done { opacity: 0.6; }
.ql-ico { flex: 0 0 16px; display: flex; align-items: center; justify-content: center; color: var(--gold); font-size: var(--fs-sm); }
.ql-item.main .ql-ico { color: var(--red); } /* main quests: red star (sides carry the gold wheat svg) */
.ql-item.selected .ql-ico { color: #fff; }
.ql-item-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ql-title { font-size: var(--fs-xl); font-weight: bold; color: var(--gold); letter-spacing: 0.12em; line-height: 1.15; }
.ql-title.done { opacity: 0.7; }
.ql-kind { font-size: var(--fs-xs); color: var(--red); letter-spacing: 0.22em; margin: 5px 0 12px; }
.ql-title.done + .ql-kind { color: var(--gold); }
.ql-objective { font-size: var(--fs-md); line-height: 1.4; letter-spacing: 0.04em; text-transform: none; margin-bottom: 12px; }
.ql-check { border-top: 1px solid rgba(192, 32, 32, 0.4); padding-top: 10px; margin-bottom: 12px; }
.ql-check-row { display: flex; gap: 9px; padding: 3px 0; font-size: var(--fs-sm); letter-spacing: 0.05em; }
.ql-check-row.done { color: var(--gold); opacity: 0.7; }
.ql-check-row.current { color: #fff; font-weight: bold; }
.ql-check-row.locked { color: var(--grey); }
.ql-check-mark { flex: 0 0 14px; text-align: center; }
.ql-check-text { flex: 1; min-width: 0; text-transform: none; line-height: 1.35; }
.ql-thumb { display: block; width: 200px; height: 200px; background: #060505; border: 2px solid var(--gold); }
.ql-thumb-cap { margin-top: 6px; font-size: var(--fs-xs); color: var(--gold); letter-spacing: 0.18em; }

/* ---------- save/load slots: thumbnail + meta body (Phase 2 meta fields) ---------- */
.slot-row { align-items: center; }
.slot-thumb {
  flex: 0 0 96px; width: 96px; height: 54px; object-fit: cover;
  background: #000; border: 2px solid var(--red);
}
.slot-thumb-empty { display: flex; align-items: center; justify-content: center; color: var(--gold); font-size: var(--fs-xl); }
.slot-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.slot-extra { font-size: var(--fs-xs); opacity: 0.75; }

/* ==================== Phase 12.5 — GUI MODERNISATION ====================
   The brief is "modernise the execution, not the style", so nothing here
   changes the constructivist language: still red/black/gold, still uppercase,
   still sharp corners and hard offset shadows. What it fixes is craft.

   1. KEYBOARD AND GAMEPAD FOCUS WAS INVISIBLE. Every interactive element had a
      :hover state and nothing else, so anyone navigating with the D-pad or Tab
      could not see where they were. That is the single biggest usability defect
      in these menus and it costs one rule to fix.
   2. TYPE DID NOT SCALE. Sizes were fixed pixels tuned at one window size; the
      title was cramped at 720p and small at 1440p. The headline sizes are now
      fluid between those two, which is where the brief says it must be readable.
   3. SPACING WAS AD HOC. A shared scale keeps panels from drifting apart.
   ======================================================================== */

/* --- 1. focus states ------------------------------------------------------ */
/* :focus-visible, not :focus — a mouse click should not leave a ring behind. */
.soviet-btn:focus-visible,
.diff-card:focus-visible,
.slot-row:focus-visible,
.ql-item:focus-visible,
.perk-card:focus-visible,
.opt-ctrl input:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 2px;
  /* The ring alone can vanish against the gold-on-red active tab, so pair it
     with a shadow that reads on every background this UI has. */
  box-shadow: 0 0 0 1px #000, 4px 4px 0 rgba(0, 0, 0, 0.6);
}
.opt-tab.active:focus-visible { box-shadow: inset 0 -3px 0 var(--gold), 0 0 0 1px #000; }

/* --- 2. fluid headline type ---------------------------------------------- */
/* min at 720p, max at 1440p. The letter-spacing goes with it, otherwise wide
   tracking that looks deliberate at 46px looks broken at 30px. */
.menu-title { font-size: clamp(30px, 3.2vw, 52px); }
.menu-head { font-size: clamp(19px, 1.7vw, 28px); }
.diff-name { font-size: clamp(17px, 1.4vw, 23px); }
.ql-title { font-size: clamp(17px, 1.4vw, 23px); }

/* --- 3. spacing and rhythm ----------------------------------------------- */
.menu-panel { padding: clamp(20px, 2.2vw, 36px) clamp(22px, 2.6vw, 42px); }
/* Panels scroll. An unstyled scrollbar is the one piece of default chrome that
   survives in this UI and it looks like a browser, not like the game. */
.wide-panel, .pause-panel, .ql-list, .ql-detail {
  scrollbar-width: thin;
  scrollbar-color: var(--red) rgba(0, 0, 0, 0.4);
}
.wide-panel::-webkit-scrollbar,
.pause-panel::-webkit-scrollbar,
.ql-list::-webkit-scrollbar,
.ql-detail::-webkit-scrollbar { width: 10px; }
.wide-panel::-webkit-scrollbar-track,
.pause-panel::-webkit-scrollbar-track,
.ql-list::-webkit-scrollbar-track,
.ql-detail::-webkit-scrollbar-track { background: rgba(0, 0, 0, 0.4); }
.wide-panel::-webkit-scrollbar-thumb,
.pause-panel::-webkit-scrollbar-thumb,
.ql-list::-webkit-scrollbar-thumb,
.ql-detail::-webkit-scrollbar-thumb { background: var(--red); border: 2px solid #000; }
.wide-panel::-webkit-scrollbar-thumb:hover,
.pause-panel::-webkit-scrollbar-thumb:hover { background: var(--gold); }

/* Hover feedback that does not shift layout (a border change would reflow). */
.opt-row { transition: background 0.12s steps(2); }
.opt-row:hover { background: rgba(192, 32, 32, 0.10); }

/* Respect the OS reduced-motion preference for the menu entrance animations.
   The in-game "REDUCE CAMERA MOTION" setting covers the camera, not the UI. */
@media (prefers-reduced-motion: reduce) {
  .menu-screen, .death-panel { animation: none; }
  .opt-row { transition: none; }
}

/* ---------- colorblind adjustments ---------- */
body.colorblind .diff-card:hover,
body.colorblind .slot-row:hover:not(:disabled),
body.colorblind .menu-btn:hover { background: #1a3a6a; }
body.colorblind .death-title { color: var(--cb-enemy); }
body.colorblind .pause-tab:hover,
body.colorblind .pause-tab.active,
body.colorblind .ql-item:hover,
body.colorblind .ql-item.selected,
body.colorblind .menu-btn.tab-focus { background: #1a3a6a; }

/* ---- PHASE 18: the People's Radio tab -------------------------------------
   Constructivist, like everything else here: gold rules, red accents, letter-
   spaced caps. Nothing new in the palette — it reads as part of the same menu. */
.opt-note {
  font-size: var(--fs-sm); line-height: 1.55; color: var(--paper); opacity: 0.72;
  max-width: 62ch; margin: 14px auto 0; text-align: left;
}
.radio-head { border-bottom: 1px solid rgba(232, 184, 58, 0.35); padding-bottom: 12px; margin-bottom: 14px; }
.radio-head .menu-sub { margin-bottom: 8px; }
.radio-now {
  font-size: var(--fs-md); letter-spacing: 0.16em; color: var(--gold);
  min-height: 22px; text-transform: uppercase;
}
.radio-controls { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; margin-bottom: 8px; }
/* .menu-btn is a full-width block elsewhere in this menu; inside the control row
   the three buttons sit side by side, so the width rule has to be overridden. */
.radio-btn { min-width: 132px; width: auto; flex: 0 1 auto; margin: 0; }
.radio-list {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 6px; margin-top: 16px;
}
.radio-track { text-align: left; padding-left: 14px; font-size: var(--fs-sm); letter-spacing: 0.06em; }
.radio-track.active { box-shadow: inset 3px 0 0 var(--gold); color: var(--gold); }
@media (max-width: 900px) {
  .radio-list { grid-template-columns: 1fr 1fr; }
  .radio-btn { min-width: 96px; }
}

/* ---- PHASE 19(B): the two states the sweep was actually missing ------------
   Focus was already handled (a gold ring on :focus-visible, plus .gp-focus for
   the pad navigator). DISABLED was not: only two controls in the whole UI had a
   disabled treatment, so a control that cannot be used looked exactly like one
   that can. One rule, every control. */
.soviet-btn:disabled,
.menu-btn:disabled,
.diff-card:disabled,
.pause-tab:disabled,
.opt-tab:disabled,
.radio-btn:disabled,
.radio-track:disabled,
.soviet-btn.disabled,
.menu-btn.disabled {
  opacity: 0.34;
  cursor: default;
  border-color: var(--grey);
  color: var(--paper);
  background: var(--ink);
}
.soviet-btn:disabled:hover,
.menu-btn:disabled:hover,
.radio-btn:disabled:hover,
.radio-track:disabled:hover { box-shadow: none; background: var(--ink); color: var(--paper); }

/* The pause tabs and the settings sub-tabs were the two navigation surfaces the
   focus list did not name, which is exactly where a controller starts. */
.pause-tab:focus-visible,
.opt-tab:focus-visible,
.radio-btn:focus-visible,
.radio-track:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 2px;
  box-shadow: 0 0 0 1px #000, 4px 4px 0 rgba(0, 0, 0, 0.6);
}

/* ===========================================================================
   PHASE 27.3 — "A MODERN TOUCH", AND WHAT IT DELIBERATELY IS NOT
   ---------------------------------------------------------------------------
   THE PLAYER: "I like the colour and style of the GUI ... but it's not as
   responsive as I would like it to be ... something tells me it's missing
   something, like a modern touch."

   THE ART DIRECTION DOES NOT MOVE. The player named what they like — the
   colour, the constructivist style, the hammer and sickle by the health bar —
   so nothing here changes a colour, a typeface, a border or a layout.

   ⚠️  TWO OF THE FOUR THINGS THE PLAN LISTED WERE ALREADY DONE, and measuring
       first is what showed it. NOT ADDED, because they exist:
         * "a focus ring that is unmistakable under a controller" — PHASE 19(B)
           did that sweep; see the :focus-visible rules above.
         * "a settings row that shows its value while it changes rather than
           after" — sliderRow() has listened on 'input', not 'change', all
           along, so the value already tracks the drag.
       ADDED, because they were the real gap: MOTION ON STATE CHANGE, and PRESS
       FEEDBACK. There were four transitions in this entire stylesheet.

   ⚠️  EVERYTHING HERE IS COMPOSITOR-ONLY — opacity and transform, never a
       property that lays out. The game pauses on a loaded frame and the whole
       point of 27.3 is that the menu ends up FASTER, not prettier and slower.
       Measured after: open 2.7 ms, worst tab switch 26.7 ms, worst category
       switch 10.4 ms — unchanged, because none of this costs layout.
   ======================================================================== */

/* The body of a tab eases in when it is rebuilt, so switching tabs reads as a
   change of view rather than a hard cut. 110ms: long enough to see, short
   enough that it is over before the hand leaves the key. */
@keyframes panel-swap {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}
.pause-body, .opt-body {
  animation: panel-swap 110ms ease-out both;
  will-change: opacity, transform;
}

/* Press feedback. Hover states existed; the moment of the click did not
   acknowledge itself at all, which is most of what "not responsive" means when
   the thing on screen is already fast. */
.soviet-btn:active:not(:disabled),
.menu-btn:active:not(:disabled),
.pause-tab:active,
.opt-tab:active,
.diff-card:active,
.radio-btn:active:not(:disabled) {
  transform: translateY(1px);
  transition: transform 40ms ease-out;
}

/* The active settings category gets its underline as a wipe rather than a
   blink. transform on a pseudo-element: no layout, no repaint of the label. */
.opt-tab { position: relative; overflow: hidden; }
.opt-tab::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 3px;
  background: var(--gold);
  transform: scaleX(0); transform-origin: left center;
  transition: transform 140ms ease-out;
}
.opt-tab.active::after { transform: scaleX(1); }
/* the box-shadow underline above would double it up */
.opt-tab.active, .opt-tab.active:hover { box-shadow: none; }

@media (prefers-reduced-motion: reduce) {
  .pause-body, .opt-body { animation: none; }
  .opt-tab::after { transition: none; }
  .soviet-btn:active:not(:disabled),
  .menu-btn:active:not(:disabled),
  .pause-tab:active,
  .opt-tab:active,
  .diff-card:active,
  .radio-btn:active:not(:disabled) { transform: none; }
}

/* ---------------------------------------------------------------------------
   PHASE 27.3(b) — THE ONE THING THE VIEWPORT SWEEP ACTUALLY FOUND.
   test/screenshot-phase27.mjs measures every pause tab at 1280x720 and
   2560x1440. Nine of the ten combinations were clean. The tenth was the MAP at
   720p, which overflowed its panel by 120 px vertically — the plan and the
   fast-travel button did not fit together, so the panel grew a scrollbar and
   the button sat below the fold.

   ⚠️  THE MAP DOES NOT SHRINK TO PAY FOR THIS, or not much. 15.4 made it big on
       purpose ("I think it probably should be bigger too, so the player can
       actually see all of it") and a 720p laptop is exactly the machine that
       player is on. So the CHROME gives way first — panel padding, the head,
       the hint margin — and the plan gives up the remainder.
   ------------------------------------------------------------------------ */
@media (max-height: 820px) {
  .pause-panel { padding-top: 18px; padding-bottom: 18px; max-height: 92vh; }
  .pause-panel .menu-head { margin-bottom: 10px; }
  .pause-panel .pause-tabs { margin-bottom: 10px; }
  .map-hint { margin-top: 6px; }
  .map-canvas { width: min(680px, 100%, 54vh); height: min(680px, 100%, 54vh); }
}

/* ===========================================================================
   PHASE 27.2 (REVISED BY THE PLAYER MID-PHASE) — THE SETTINGS RAIL
   ---------------------------------------------------------------------------
   THE WRITTEN REQUEST said "the list should be shown horizontally, and then the
   options beside that". THE CLARIFICATION, given while this phase was being
   worked, is the specification that wins:
     "the settings screen should have one column on the left hand side that you
      can go down from and then on the right of it, it should show the unique
      settings for that thing ... but keep the main menu options horizontal but
      the unique settings options will display on the left vertically in one
      column."
   So: .pause-tabs stays a horizontal strip. THIS list becomes a vertical rail
   on the left with the category's settings beside it.

   ⚠️  MEASURED FIRST, AND THE PLAN'S PREMISE DID NOT HOLD. The plan said five
       tabs wrap onto a second row inside the narrower pause panel. They did not
       — test/screenshot-phase27.mjs measured 5 tabs on 1 row at BOTH 1280x720
       and 2560x1440 before anything was changed. The wrap was not the problem;
       the shape was.
   ======================================================================== */
.opt-split { display: flex; align-items: flex-start; gap: 18px; }
.opt-tabs {
  flex: 0 0 auto;
  flex-direction: column;
  flex-wrap: nowrap;
  width: clamp(120px, 22%, 180px);
  gap: 2px;
  margin: 0;
  padding: 0 14px 0 0;
  border-bottom: none;
  border-right: 2px solid rgba(192, 32, 32, 0.45);
}
.opt-tab {
  flex: 0 0 auto;
  width: 100%;
  text-align: left;
  padding: 9px 10px;
}
.opt-body { flex: 1 1 auto; min-width: 0; }

/* The active marker follows the rail: a bar down the left edge instead of an
   underline. Same gold, same wipe, same compositor-only transform. */
.opt-tab::after {
  left: 0; right: auto; top: 0; bottom: 0;
  width: 3px; height: auto;
  transform: scaleY(0); transform-origin: center top;
  transition: transform 140ms ease-out;
}
.opt-tab.active::after { transform: scaleY(1); }

/* At 720p the rail plus the key-binding list is the tightest thing in the menu,
   so the rail gives up its padding first. */
@media (max-height: 820px) {
  .opt-tabs { width: clamp(104px, 20%, 150px); padding-right: 10px; }
  .opt-tab { padding: 7px 8px; }
  .opt-split { gap: 12px; }
}

@media (prefers-reduced-motion: reduce) {
  .opt-tab::after { transition: none; }
}
