/* style.css - Vibin' & Survivin' Stylesheet
   ---------------------------------------------------------------------
   GENERATED FILE - DO NOT EDIT DIRECTLY.

   This file is built by concatenating the modules in css/ in filename
   order. Edit the module, then run:

       npm run build:css

   Any edit made here is lost the next time that runs. `npm run build:css
   -- --check` verifies the built output matches the modules without
   writing, and is wired into `npm test`.

   The modules are plain concatenation, not an import graph: source order
   IS the cascade, so moving a rule between modules changes which rule
   wins. Reorder deliberately or not at all.
   --------------------------------------------------------------------- */

/* Bundled color-emoji subset (assets/fonts/AppEmoji.ttf, ~107KB, built from
   Noto Color Emoji, subset down to just the ~53 codepoints this UI actually
   uses -- see CHANGELOG). The game renders emoji-style icons directly as
   text characters throughout (ðŸ”¥âš¡ðŸ‘‘ðŸ† etc.) and previously relied entirely
   on whatever color emoji font happened to be installed at the OS level.
   That's a safe assumption on Windows (Segoe UI Emoji always present) but
   not on Steam Deck's SteamOS Game Mode, which has no system emoji font --
   every emoji-style icon rendered as blank/missing there. Self-hosting a
   subset removes the OS dependency entirely, on every platform. */
@font-face {
  font-family: 'AppEmoji';
  src: url('assets/fonts/AppEmoji.ttf') format('truetype');
  font-display: swap;
}

/* ==========================================================================
   DESIGN TOKENS
   --------------------------------------------------------------------------
   Phase 2 of the stylesheet refactor. This block is the single source of
   truth for colour, spacing, radius, blur and motion. The new scales are not
   consumed yet -- the literals scattered through the rest of the file are
   migrated in phase 6. The legacy token names below keep their exact values;
   they are simply expressed in terms of the channels now, so each hue is
   written down once.

   COLOUR CHANNELS are comma-separated RGB triplets rather than hex, so one
   hue can be composed at any opacity:

       border: 1px solid rgba(var(--c-primary), 0.35);
       color:  rgb(var(--c-primary));

   The comma form is deliberate. The modern `rgb(R G B / A)` slash syntax
   needs Chrome 65+, and this app ships to Android with minSdk 24 (Android
   7.0), where a device without an updated Play Store WebView can still be
   running Chrome ~51. `rgba(var(--x), a)` expands textually and works
   anywhere CSS custom properties do (Chrome 49+). Do NOT modernise these to
   the slash syntax.
   ========================================================================== */
:root {
  /* -- Colour channels ---------------------------------------------------
     Ordered by how often each hue appears in this stylesheet. The first six
     account for roughly 71% of every colour token in the file. */
  --c-ink:        255, 255, 255;  /* hairlines, text, inset highlights */
  --c-primary:    168, 85, 247;   /* #a855f7 purple -- the brand hue */
  --c-gold:       251, 191, 36;   /* #fbbf24 -- currency, rewards */
  --c-sky:        56, 189, 248;   /* #38bdf8 -- XP surge, overshield, platinum rank */
  --c-void:       0, 0, 0;        /* shadow, scrim */
  --c-danger:     239, 68, 68;    /* #ef4444 -- destructive, back, penalties */
  --c-secondary:  236, 72, 153;   /* #ec4899 pink */
  --c-info:       59, 130, 246;   /* #3b82f6 */
  --c-success:    16, 185, 129;   /* #10b981 */
  --c-cyan:       34, 211, 238;   /* #22d3ee -- decorative cyan */
  --c-slate:      148, 163, 184;  /* #94a3b8 -- muted label text */
  --c-amber:      251, 146, 60;   /* #fb923c -- milestone / major choice */
  --c-violet:     192, 132, 252;  /* #c084fc -- round modifier accent */
  --c-orange:     249, 115, 22;   /* #f97316 */
  --c-mint:       52, 211, 153;   /* #34d399 */
  --c-rose:       244, 63, 94;    /* #f43f5e -- glitch hunt */

  /* -- Item rarity ---------------------------------------------------------
     Aliases onto the channels above wherever one already holds the hue, so a
     rarity colour is never restated. RARITY_COLORS in js/gear.js is the single
     source of truth (basic white, magic #3b82f6, rare #fbbf24, legendary
     #f97316, ultimate #a855f7, anomalous #22d3ee) and these tokens mirror it
     exactly; "common" is the basic tier. js/init.js derives its game-over table
     from RARITY_COLORS. #06b6d4 is NOT the anomalous colour (it survives only in
     the glitch filter and a few mobile gradients).
     Consumed by the chamfer kit's --r channel (css/03b-chamfer-kit.css). */
  --c-rarity-common:     var(--c-ink);    /* white: decided 2026-10-06, js/gear.js is the source of truth */
  --c-rarity-magic:      var(--c-info);
  --c-rarity-rare:       var(--c-gold);
  --c-rarity-legendary:  var(--c-orange);
  --c-rarity-ultimate:   var(--c-primary);
  --c-rarity-anomalous:  var(--c-cyan);

  /* Surfaces and text. --c-accent-legacy is a DIFFERENT purple from
     --c-primary (#9333ea vs #a855f7); it predates the palette and is kept
     exact here rather than silently unified. */
  --c-bg:            11, 8, 19;     /* #0b0813 page ground */
  --c-panel:         22, 17, 39;    /* glass panel fill */
  --c-text-main:     243, 244, 246; /* #f3f4f6 */
  --c-text-muted:    156, 163, 175; /* #9ca3af */
  --c-accent-legacy: 147, 51, 234;  /* #9333ea -- see note above */

  /* -- Semantic aliases ------------------------------------------------
     --c-focus points AT a hue rather than restating one, so the gamepad
     focus ring can be restyled on its own line without disturbing the
     decorative uses of the same sky blue (XP bar surge, overshield, the
     platinum rank badge). Repoint this, don't edit --c-sky. */
  --c-focus: var(--c-sky);

  /* -- Legacy tokens: identical values, now derived from the channels ---- */
  --bg-color: rgb(var(--c-bg));
  --panel-bg: rgba(var(--c-panel), 0.65);
  --border-color: rgba(var(--c-ink), 0.08);
  --accent-glow: rgba(var(--c-accent-legacy), 0.3);

  --color-primary: rgb(var(--c-primary)); /* Purple */
  --color-primary-glow: rgba(var(--c-primary), 0.4);
  --color-secondary: rgb(var(--c-secondary)); /* Pink */
  --color-secondary-glow: rgba(var(--c-secondary), 0.4);
  --color-text-main: rgb(var(--c-text-main));
  --color-text-muted: rgb(var(--c-text-muted));
  --color-success: rgb(var(--c-success));
  --color-success-glow: rgba(var(--c-success), 0.4);

  --font-main: 'Outfit', 'AppEmoji', sans-serif;
  --font-display: 'Space Grotesk', 'AppEmoji', sans-serif;

  /* -- Spacing: the 2px ladder the file already uses ---------------------
     2/4/6/8/10/12/14/16 cover ~90% of every gap in the stylesheet. Odd
     one-off steps (1px, 3px, 5px, 7px) stay as literals on purpose. */
  --s-1: 2px;
  --s-2: 4px;
  --s-3: 6px;
  --s-4: 8px;
  --s-5: 10px;
  --s-6: 12px;
  --s-7: 14px;
  --s-8: 16px;

  /* -- Radius: 4/6/8/10/12/50%/999px cover ~92% of border-radius uses ---- */
  --r-xs: 3px;
  --r-sm: 4px;
  --r-md: 6px;
  --r-lg: 8px;
  --r-xl: 10px;
  --r-2xl: 12px;
  --r-3xl: 16px;
  --r-pill: 999px;
  --r-circle: 50%;

  /* -- Backdrop blur ----------------------------------------------------- */
  --blur-xs: blur(4px);
  --blur-sm: blur(8px);
  --blur-md: blur(12px);
  --blur-lg: blur(14px);
  --blur-xl: blur(16px);

  /* -- Motion ------------------------------------------------------------ */
  --t-fast: 0.15s;
  --t-base: 0.2s;
  --t-mid: 0.25s;
  --t-slow: 0.3s;
  --ease-ui: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-pop: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-spring: cubic-bezier(0.18, 0.9, 0.26, 1.1);
  --ease-glide: cubic-bezier(0.2, 0.9, 0.3, 1);
  --ease-overshoot: cubic-bezier(0.15, 0.9, 0.2, 1.25);

  /* -- Gamepad focus ring ------------------------------------------------
     Phase 5 collapses 68 near-identical .controller-focused rules onto
     these. #38bdf8 is reserved for focus: use --c-cyan for decorative
     cyan, never --c-focus. */
  --focus-color: rgb(var(--c-focus));
  --focus-ring: 0 0 14px rgba(var(--c-focus), 0.7);
  --focus-ring-strong: 0 0 0 2px rgba(var(--c-focus), 0.6),
                       0 0 20px rgba(var(--c-focus), 0.85);
}

/* Base Styles */
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  user-select: none;
}

/* ==========================================================================
   UNIFORM UI SCALING (1080p -> 4K)
   --------------------------------------------------------------------------
   The root font-size is deliberately FLAT again. It used to be
   `calc(16px * var(--ui-global-scale))`, which scaled every rem-sized TEXT
   measurement on large displays but scaled CONTAINERS only where somebody
   had hand-written a matching calc() into that specific rule. Every panel,
   sidebar and grid track that never got one kept its authored pixel width
   while its contents doubled -- which is exactly why at 4K the shop packed
   six 260px columns full of 144px icons, the settings sidebar truncated
   "Gamepl...", the achievements sidebar truncated "All Achiev...", and the
   equipment Total Stats column clipped its own numbers.

   The model now is layer-based instead of rule-based: the menu layer
   (.overlay), the HUD layer (#ui-container) and the loading screen LAY OUT
   at a virtual viewport of real-size / --ui-layer-scale -- i.e. exactly
   1920x1080 on a 4K screen -- and are then transform-scaled back up to fill
   the real viewport. Layout is therefore bit-for-bit the 1080p layout at
   every resolution, and because a scale transform re-rasterises text and
   vector borders at the composited resolution rather than upscaling a
   bitmap, 4K is genuinely sharper rather than merely bigger.

   Two properties make this safe to adopt wholesale:

   1. `--ui-global-scale: 1` is set on every scaled layer. Custom properties
      inherit, so all ~104 existing `calc(Npx * var(--ui-global-scale))`
      declarations in this file -- plus the ones js/shop.js and
      js/gear-card.js write as inline styles at runtime -- resolve to their
      authored 1x design value inside a layer, with no edit to any of them.
      The single transform on the layer becomes the only source of growth,
      so nothing double-counts.
   2. Everything here is gated behind `html.ui-upscaled`, which
      resizeGame() (js/resolution-manager.js) only adds when the layer scale
      actually exceeds 1. computeUiGlobalScale() returns exactly 1.0 for any
      viewport height <= 1080, so on a Steam Deck at 1280x800 these rules
      match nothing at all -- no transform, no containing block, no
      compositing layer, no measurable difference from before this change.
      The one intended exception is a player raising Settings > Display >
      UI Scale above 100%, which is opt-in and defaults off.
   ========================================================================== */
html {
  font-size: 16px;
}

/* Full-viewport scaled layers. width/height are divided by the scale so the
   layer lays out in virtual pixels; the transform puts it back. right/bottom
   are cleared because a layer may pin all four edges, and width/height would
   otherwise fight that. !important is needed to beat #ui-container's and
   #loading-screen's own id-level 100vw/100vh declarations.

   EXACTLY ONE ELEMENT PER SUBTREE MAY CARRY THIS RULE. Scales multiply down
   the tree, so two nested layers give 4x at 4K, not 2x. Every one of the 28
   `.overlay` screens is a CHILD of #ui-container (they are not siblings of
   it, despite how index.html's indentation reads), so #ui-container alone
   carries the whole menu layer and the overlays inherit it -- adding
   `.overlay` here as well was tried and produced a settings panel 3192px
   wide inside a 4320px-tall overlay on a 2160px screen. #loading-screen and
   #dev-panel live directly under <body>, outside #ui-container, so the
   loading screen needs its own entry here (and the dev panel deliberately
   gets none). Keep .ui-scale-layer as the opt-in hook for any FUTURE
   top-level layer -- do not put it on anything already inside another. */
html.ui-upscaled .ui-scale-layer,
html.ui-upscaled #ui-container,
html.ui-upscaled #loading-screen {
  width: calc(100% / var(--ui-layer-scale, 1)) !important;
  height: calc(100% / var(--ui-layer-scale, 1)) !important;
  right: auto !important;
  bottom: auto !important;
  transform: scale(var(--ui-layer-scale, 1));
  transform-origin: top left;
  --ui-global-scale: 1;
}

/* On the main menu (#start-screen.active), render #ui-container and the start screen
   at full native resolution (1440p / 4K) without transform downscaling, ensuring
   crystal-clear text and zero bilinear blur. When an overlay modal (instructions,
   settings, achievements, etc.) is opened over the start screen, #ui-container
   reverts to the base transform scale for modal layout; #start-screen is scoped to
   start-screen-active so it inherits --ui-global-scale: 1 and does not double-scale. */
html.ui-upscaled.start-screen-active #ui-container,
html.ui-upscaled body.start-screen-active #ui-container,
html.ui-upscaled #ui-container:has(#start-screen.active):not(:has(.overlay.active:not(#start-screen))),
html.ui-upscaled.start-screen-active #start-screen,
html.ui-upscaled body.start-screen-active #start-screen,
html.ui-upscaled #ui-container:has(#start-screen.active):not(:has(.overlay.active:not(#start-screen))) #start-screen {
  width: 100% !important;
  height: 100% !important;
  transform: none !important;
  --ui-global-scale: var(--ui-layer-scale, 1);
  --vvw: 1vw !important;
  --vvh: 1vh !important;
}


/* Small content-sized widgets that float over gameplay outside any layer
   (boss bar, round banner, achievement toast, control hints, perf readout).
   These are anchored by percentage offsets and sized by their content, so
   the width/height division above would be wrong for them; `zoom` scales the
   whole widget -- rem text included -- while leaving percentage anchoring
   resolving correctly. Excluded on purpose: #dev-panel (a dev tool whose
   drag-resize does its own rect math) and the #mobile-* clusters (the scale
   is 1.0 at every mobile viewport height anyway). */
html.ui-upscaled .ui-scale-widget,
html.ui-upscaled #boss-health-container,
html.ui-upscaled .round-complete-banner,
html.ui-upscaled .achievement-toast,
html.ui-upscaled .control-hints-panel,
html.ui-upscaled #perf-overlay,
/* .mmo-xp-bar .xp-bar-text used to be listed here: the XP bar was full-bleed
   outside #ui-container, so its caption needed the widget treatment. Since
   the HUD overhaul Phase 3 the XP line lives in #hud-vitals inside
   #ui-container and scales with the layer like the rest of the HUD. */
html.ui-upscaled #benchmark-running-banner {
  zoom: var(--ui-layer-scale, 1);
  --ui-global-scale: 1;
}

/* Mobile landscape downscaled layers (< 900px wide or < 420px high in landscape).
   Lays out at virtual resolution 100% / --ui-layer-scale and transform-scales down,
   ensuring uniform layout matching higher resolutions without clipping. */
html.ui-downscaled .ui-scale-layer,
html.ui-downscaled #ui-container,
html.ui-downscaled #loading-screen {
  width: calc(100% / var(--ui-layer-scale, 1)) !important;
  height: calc(100% / var(--ui-layer-scale, 1)) !important;
  right: auto !important;
  bottom: auto !important;
  transform: scale(var(--ui-layer-scale, 1));
  transform-origin: top left;
  --ui-global-scale: 1;
}

/* Small content-sized widgets downscaling for mobile landscape viewports.
   Virtual touch controls (#mobile-controls) are intentionally excluded so
   virtual joystick and dash buttons preserve fixed ergonomic touch sizing. */
html.ui-downscaled .ui-scale-widget,
html.ui-downscaled #boss-health-container,
html.ui-downscaled .round-complete-banner,
html.ui-downscaled .achievement-toast,
html.ui-downscaled .control-hints-panel,
html.ui-downscaled #perf-overlay,
html.ui-downscaled #benchmark-running-banner {
  zoom: var(--ui-layer-scale, 1);
  --ui-global-scale: 1;
}

/* ==========================================================================
   HOVER STATES ARE SUPPRESSED WHILE A CONTROLLER IS DRIVING THE UI
   --------------------------------------------------------------------------
   Reported by the user: a button the mouse happened to be sitting on stays
   lit after they pick up a controller, so two things look focused at once --
   the real controller focus (.controller-focused) and a ghost hover the
   player cannot get rid of without physically moving the mouse.

   That is browser behaviour, not a bug in this file: :hover is only
   re-evaluated on the next pointer event, so with the mouse untouched the
   element keeps matching :hover indefinitely. Confirmed experimentally --
   and note that `pointer-events: none` does NOT fix it, because it likewise
   only takes effect at the next hit-test. The only reliable lever is to stop
   the hover RULES from applying, which is a style recalc and therefore
   immediate.

   So every :hover selector in this file is prefixed with
   `:where(body:not(.gamepad-active))`. setInputMethod() (js/world.js) already
   toggles body.gamepad-active the instant real gamepad activity is seen, the
   same signal that hides the OS cursor. :where() is used deliberately: it
   contributes ZERO specificity, so each guarded rule keeps exactly the
   specificity it had and the cascade is otherwise untouched.

   Only the comma-separated parts that actually contain :hover are guarded --
   sibling parts such as :focus, :focus-visible and .controller-focused are
   left alone, since the controller path depends on the last of those.

   If you add a new :hover rule, add the same guard to it. */

body {
  background-color: var(--bg-color);
  color: var(--color-text-main);
  font-family: var(--font-main);
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  overflow: hidden;
  background-image:
    radial-gradient(at 0% 0%, rgba(88, 28, 135, 0.15) 0px, transparent 50%),
    radial-gradient(at 100% 100%, rgba(219, 39, 119, 0.1) 0px, transparent 50%);
}

/* Toggled by setInputMethod() (js/world.js) the instant real gamepad
   activity is seen -- nothing on screen is meant to be pointed at with a
   mouse while playing on a controller, so the real OS cursor is hidden
   entirely instead of sitting idle wherever it was last moved. Removed
   again immediately on real mouse/touch input taking back over. `*` so it
   also overrides every element's own `cursor: pointer`/etc (buttons, shop
   cards, ...) which would otherwise win by specificity over a plain `body`
   rule. */
body.gamepad-cursor-hidden,
body.gamepad-cursor-hidden * {
  cursor: none !important;
}

/* Game Wrapper Container - Fits browser window completely without borders */
#game-container {
  position: relative;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  background-color: #0d0a1b;
}

/* Loading Screen Overlay - High z-index viewport overlay covering canvas and HUD */
#loading-screen {
  position: fixed !important;
  top: 0 !important;
  left: 0 !important;
  width: 100vw !important;
  height: 100vh !important;
  z-index: 100000 !important;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
  background: rgb(var(--c-bg)) !important;
  transition: opacity 0.5s ease;
  pointer-events: auto !important;
}

/* UI Container - Positioned and scaled relative to 1200x800 base layout */
#ui-container {
  position: absolute;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  pointer-events: none;
  z-index: 5;
  box-sizing: border-box;
}


/* Canvas element - Fills game container completely behind UI */
#game-canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: block;
  background-color: rgb(var(--c-bg));
  z-index: 1;
}

/* Radar overlay canvas â€” same size/position as #game-canvas, but layered
   above every normal HUD panel (max z-index in the standard action-bar/
   health-bar chrome is 100) so the off-screen boss/drop/shop directional
   arrows are never hidden behind them. Stays below the full-screen modal
   overlays (pause/shop/weapon-tree/etc., 200+) since those already pause
   or cover gameplay. Transparent background (only ever cleared, never
   filled) and no pointer events so it can't intercept clicks. */
#radar-overlay-canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: block;
  background-color: transparent;
  pointer-events: none;
  z-index: 150;
}

/* Typography Utility */
.font-accent {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: 0.05em;
}

/* HUD System styles */
#hud {
  position: absolute;
  top: 16px;
  left: 16px;
  right: 16px;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 10;
  /* Scales up on short/mobile viewports only -- see resizeGame() in
     js/devpanel.js for how --ui-scale is computed. No-op (scale(1)) on any
     normal desktop-height window. Deliberately does NOT also multiply in
     --ui-global-scale (the large-display growth factor, unlike .mmo-action-
     bar below) -- this box already spans nearly the full viewport width via
     left/right: 16px, so it grows via CSS layout as the viewport widens on
     a 1440p/4K display; adding a transform on top of that would double-
     count and push .hud-top's content off past the real screen edges. Its
     content (rem-based text via .hud-stat/.hud-timer, and the calc()-scaled
     px padding on .hud-top itself) grows correctly on its own instead. */
  transform: scale(var(--ui-scale, 1));
  transform-origin: top center;
}

.hud-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: rgba(13, 10, 27, 0.92);
  /* px, not rem -- doesn't inherit the html-level --ui-global-scale font-size
     scaling above, so it's scaled directly here to keep pace with the
     (rem-based) label/value text growing inside it on large displays. */
  padding: calc(10px * var(--ui-global-scale, 1)) calc(20px * var(--ui-global-scale, 1));
  border-radius: 12px;
  border: 1px solid var(--border-color);
  box-shadow: 0 4px 30px rgba(0, 0, 0, 0.2);
}

.hud-stat {
  display: flex;
  align-items: baseline;
  gap: 6px;
}

.hud-stat .label {
  font-size: 0.75rem;
  color: var(--color-text-muted);
}

.hud-stat .value {
  font-size: 1.25rem;
  color: var(--color-primary);
  text-shadow: 0 0 10px var(--color-primary-glow);
}

#hud-difficulty {
  font-size: 1.15rem;
  letter-spacing: 0.05em;
  white-space: nowrap;
  text-transform: uppercase;
}

/* Dynamic In-Round Wager & Contract Tracker */
.wager-hud-tracker {
  align-self: center;
  display: flex;
  align-items: center;
  gap: 10px;
  background: rgba(15, 23, 42, 0.88);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(var(--c-primary), 0.4);
  box-shadow: 0 0 16px rgba(var(--c-primary), 0.25);
  border-radius: 999px;
  padding: 4px 12px;
  pointer-events: auto;
  position: relative;
  z-index: 85;
  transition: margin-top 0.3s cubic-bezier(0.2, 0.9, 0.3, 1), transform 0.25s ease, opacity 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
  will-change: margin-top, transform, opacity;
}

.wager-tracker-badge {
  display: flex;
  align-items: center;
  gap: 6px;
}

.wager-tracker-tag {
  font-size: 0.60rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  background: rgba(var(--c-primary), 0.2);
  color: rgb(var(--c-violet));
  border: 1px solid rgba(var(--c-primary), 0.45);
  padding: 1px 6px;
  border-radius: 4px;
}

.wager-tracker-title {
  font-family: var(--font-display, inherit);
  font-size: 0.76rem;
  font-weight: 700;
  color: #ffffff;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.wager-tracker-contract {
  display: flex;
  align-items: center;
  gap: 6px;
  border-left: 1px solid rgba(255, 255, 255, 0.15);
  padding-left: 8px;
}

.wager-contract-label {
  font-size: 0.62rem;
  font-weight: 700;
  color: rgb(var(--c-sky));
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.wager-contract-bar-wrap {
  width: 60px;
  height: 6px;
  background: rgba(255, 255, 255, 0.12);
  border-radius: 999px;
  overflow: hidden;
  position: relative;
}

.wager-contract-bar {
  width: 0%;
  height: 100%;
  background: #22c55e;
  border-radius: 999px;
  transition: width 0.2s ease, background-color 0.2s ease;
}

.wager-contract-val {
  font-family: var(--font-mono, monospace);
  font-size: 0.68rem;
  font-weight: 700;
  color: rgb(var(--c-slate));
}

.wager-hud-tracker.voided {
  border-color: rgba(var(--c-danger), 0.6);
  box-shadow: 0 0 16px rgba(var(--c-danger), 0.35);
  animation: contractVoidedPulse 1.5s ease-in-out infinite alternate;
}

.wager-hud-tracker.voided .wager-contract-val {
  color: rgb(var(--c-danger));
  font-weight: 800;
}

@keyframes contractVoidedPulse {
  0% { transform: scale(1); filter: brightness(1); }
  100% { transform: scale(1.02); filter: brightness(1.2); }
}

/* Moves wager pill down when boss health bars are active to prevent visual overlap */
.wager-hud-tracker.boss-active {
  margin-top: calc(36px * var(--ui-global-scale, 1));
}

/* Dynamic Glitch Hunt Event Tracker (Round 10 Chaos Anomaly) */
.glitch-hunt-hud {
  align-self: center;
  display: flex;
  align-items: center;
  gap: 10px;
  background: rgba(15, 23, 42, 0.88);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(var(--c-rose), 0.45);
  box-shadow: 0 0 16px rgba(var(--c-rose), 0.25);
  border-radius: 999px;
  padding: 4px 12px;
  pointer-events: auto;
  position: relative;
  z-index: 85;
  transition: margin-top 0.3s cubic-bezier(0.2, 0.9, 0.3, 1), transform 0.25s ease, opacity 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
  will-change: margin-top, transform, opacity;
}

/* Moves glitch hunt pill down when boss health bars are active to prevent visual overlap */
.glitch-hunt-hud.boss-active {
  margin-top: calc(36px * var(--ui-global-scale, 1));
}

/* If wager tracker is also active and visible, glitch hunt pill naturally stacks below it */
.wager-hud-tracker.boss-active:not([style*="none"]) ~ .glitch-hunt-hud.boss-active {
  margin-top: 0;
}

.glitch-hunt-hud.theme-uplink {
  border-color: rgba(var(--c-amber), 0.55);
  box-shadow: 0 0 16px rgba(var(--c-amber), 0.30);
}

.glitch-hunt-hud.theme-uplink .glitch-hunt-tag {
  background: rgba(var(--c-amber), 0.2);
  color: rgb(var(--c-amber));
  border-color: rgba(var(--c-amber), 0.5);
}

.glitch-hunt-hud.theme-glitch {
  border-color: rgba(var(--c-rose), 0.55);
  box-shadow: 0 0 16px rgba(var(--c-rose), 0.30);
}

.glitch-hunt-hud.theme-glitch .glitch-hunt-tag {
  background: rgba(var(--c-rose), 0.2);
  color: rgb(var(--c-rose));
  border-color: rgba(var(--c-rose), 0.5);
}

.glitch-hunt-hud.theme-quantum {
  border-color: rgba(var(--c-primary), 0.55);
  box-shadow: 0 0 16px rgba(var(--c-primary), 0.30);
}

.glitch-hunt-hud.theme-quantum .glitch-hunt-tag {
  background: rgba(var(--c-primary), 0.2);
  color: rgb(var(--c-violet));
  border-color: rgba(var(--c-primary), 0.5);
}

.glitch-hunt-badge {
  display: flex;
  align-items: center;
  gap: 6px;
}

.glitch-hunt-tag {
  font-size: 0.60rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  background: rgba(var(--c-rose), 0.2);
  color: rgb(var(--c-rose));
  border: 1px solid rgba(var(--c-rose), 0.5);
  padding: 1px 6px;
  border-radius: 4px;
}

.glitch-hunt-title {
  font-family: var(--font-display, inherit);
  font-size: 0.76rem;
  font-weight: 700;
  color: #ffffff;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.glitch-hunt-progress-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
  border-left: 1px solid rgba(255, 255, 255, 0.15);
  padding-left: 8px;
}

.glitch-hunt-rank-badge {
  font-size: 0.65rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 1px 6px;
  border-radius: 4px;
  transition: all 0.3s ease;
}

.glitch-hunt-rank-badge.rank-none {
  background: rgba(100, 116, 139, 0.2);
  color: rgb(var(--c-slate));
  border: 1px solid rgba(var(--c-slate), 0.4);
}

.glitch-hunt-rank-badge.rank-bronze {
  background: rgba(217, 119, 6, 0.25);
  color: rgb(var(--c-amber));
  border: 1px solid rgba(var(--c-amber), 0.6);
  box-shadow: 0 0 8px rgba(var(--c-amber), 0.3);
}

.glitch-hunt-rank-badge.rank-silver {
  background: rgba(var(--c-slate), 0.25);
  color: #e2e8f0;
  border: 1px solid rgba(226, 232, 240, 0.6);
  box-shadow: 0 0 8px rgba(226, 232, 240, 0.3);
}

.glitch-hunt-rank-badge.rank-gold {
  background: rgba(234, 179, 8, 0.25);
  color: #fde047;
  border: 1px solid rgba(250, 204, 21, 0.6);
  box-shadow: 0 0 10px rgba(250, 204, 21, 0.4);
}

.glitch-hunt-rank-badge.rank-platinum {
  background: rgba(var(--c-sky), 0.25);
  color: rgb(var(--c-sky));
  border: 1px solid rgba(var(--c-sky), 0.7);
  box-shadow: 0 0 12px rgba(var(--c-sky), 0.5);
  animation: pulse-rank-platinum 1.5s infinite alternate;
}

@keyframes pulse-rank-platinum {
  0% { box-shadow: 0 0 8px rgba(var(--c-sky), 0.4); }
  100% { box-shadow: 0 0 16px rgba(var(--c-sky), 0.8); }
}

.glitch-hunt-bar-container {
  width: 80px;
  height: 6px;
  background: rgba(15, 23, 42, 0.8);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 999px;
  overflow: hidden;
}

.glitch-hunt-bar-fill {
  height: 100%;
  width: 0%;
  background: rgb(var(--c-rose));
  border-radius: 999px;
  transition: width 0.25s ease-out, background-color 0.3s ease;
}

.glitch-hunt-bar-fill.rank-none { background: #64748b; }
.glitch-hunt-bar-fill.rank-bronze { background: #d97706; }
.glitch-hunt-bar-fill.rank-silver { background: rgb(var(--c-slate)); }
.glitch-hunt-bar-fill.rank-gold { background: #eab308; }
.glitch-hunt-bar-fill.rank-platinum { background: rgb(var(--c-sky)); }

.glitch-hunt-counter {
  font-size: 0.68rem;
  font-weight: 700;
  color: #e2e8f0;
  letter-spacing: 0.05em;
  white-space: nowrap;
}

/* ------------------------------------------------------------
   MOBILE HUD WAGER & EVENT TRACKER (HUD overhaul Phase 5)
   On mobile the timer / wave / threat live in the top-left bracket (#mobile-hud), so #hud only shows
   the wager and glitch-hunt trackers, top-centre, each as one line of 8px labels with a 60px, 2px
   progress line (plans/HUD_EDGE_TELEMETRY_PLAN.md 2.2). Display-only. The tag's background and border
   are written inline by js/round-modifier-ui.js, hence the !important.
   ------------------------------------------------------------ */

#hud.mobile-active,
.is-mobile #hud,
body.input-touch #hud {
  top: calc(14px + var(--safe-top, 0px));
  left: calc(10px + var(--safe-left, 0px));
  right: calc(10px + var(--safe-right, 0px));
  gap: 4px;
  /* No --ui-scale here: that short-window factor reaches 1.5x on a phone, which blew the trackers up
     well past the size of the #mobile-hud readouts beside them (#mobile-hud is not scaled by it). */
  transform: none;
  z-index: 85;
  pointer-events: none;
}

#hud.mobile-active .hud-top,
.is-mobile #hud .hud-top,
body.input-touch #hud .hud-top {
  display: none !important;
}

#hud.mobile-active .wager-hud-tracker,
.is-mobile .wager-hud-tracker,
body.input-touch .wager-hud-tracker,
#hud.mobile-active .glitch-hunt-hud,
.is-mobile .glitch-hunt-hud,
body.input-touch .glitch-hunt-hud {
  align-self: center;
  max-width: 300px;
  padding: 0;
  gap: 6px;
  white-space: nowrap;
  background: transparent;
  backdrop-filter: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  pointer-events: none; /* Display-only during frantic mobile combat */
}

#hud.mobile-active .wager-tracker-badge,
.is-mobile .wager-tracker-badge,
body.input-touch .wager-tracker-badge,
#hud.mobile-active .glitch-hunt-badge,
.is-mobile .glitch-hunt-badge,
body.input-touch .glitch-hunt-badge {
  gap: 4px;
  min-width: 0;
}

#hud.mobile-active .wager-tracker-tag,
.is-mobile .wager-tracker-tag,
body.input-touch .wager-tracker-tag,
#hud.mobile-active .glitch-hunt-tag,
.is-mobile .glitch-hunt-tag,
body.input-touch .glitch-hunt-tag {
  padding: 0;
  background: transparent !important;
  border: 0 !important;
  font: 600 8px/1 var(--font-display);
  letter-spacing: 0.18em;
}

#hud.mobile-active .wager-tracker-title,
.is-mobile .wager-tracker-title,
body.input-touch .wager-tracker-title,
#hud.mobile-active .glitch-hunt-title,
.is-mobile .glitch-hunt-title,
body.input-touch .glitch-hunt-title {
  max-width: 110px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: #fde68a;
  font: 600 8px/1 var(--font-display);
  letter-spacing: 0.18em;
  text-shadow: 0 1px 0 #000, 0 0 8px rgba(0, 0, 0, 0.9);
}

#hud.mobile-active .wager-tracker-contract,
.is-mobile .wager-tracker-contract,
body.input-touch .wager-tracker-contract,
#hud.mobile-active .glitch-hunt-progress-wrap,
.is-mobile .glitch-hunt-progress-wrap,
body.input-touch .glitch-hunt-progress-wrap {
  gap: 5px;
  padding-left: 0;
  border-left: 0;
}

#hud.mobile-active .wager-contract-label,
.is-mobile .wager-contract-label,
body.input-touch .wager-contract-label,
#hud.mobile-active .glitch-hunt-rank-badge,
.is-mobile .glitch-hunt-rank-badge,
body.input-touch .glitch-hunt-rank-badge {
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  font: 600 8px/1 var(--font-display);
  letter-spacing: 0.12em;
}

#hud.mobile-active .wager-contract-bar-wrap,
.is-mobile .wager-contract-bar-wrap,
body.input-touch .wager-contract-bar-wrap,
#hud.mobile-active .glitch-hunt-bar-container,
.is-mobile .glitch-hunt-bar-container,
body.input-touch .glitch-hunt-bar-container {
  width: 60px;
  height: 2px;
  border: 0;
  border-radius: 0;
  background: rgba(251, 191, 36, 0.2);
}

#hud.mobile-active .wager-contract-bar,
.is-mobile .wager-contract-bar,
body.input-touch .wager-contract-bar,
#hud.mobile-active .glitch-hunt-bar-fill,
.is-mobile .glitch-hunt-bar-fill,
body.input-touch .glitch-hunt-bar-fill {
  border-radius: 0;
}

#hud.mobile-active .wager-contract-val,
.is-mobile .wager-contract-val,
body.input-touch .wager-contract-val,
#hud.mobile-active .glitch-hunt-counter,
.is-mobile .glitch-hunt-counter,
body.input-touch .glitch-hunt-counter {
  color: #fde68a;
  font: 600 8px/1 var(--font-display);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 0 #000, 0 0 8px rgba(0, 0, 0, 0.9);
}

#hud.mobile-active .wager-hud-tracker.boss-active,
.is-mobile .wager-hud-tracker.boss-active,
body.input-touch .wager-hud-tracker.boss-active,
#hud.mobile-active .glitch-hunt-hud.boss-active,
.is-mobile .glitch-hunt-hud.boss-active,
body.input-touch .glitch-hunt-hud.boss-active {
  margin-top: 0;
}

.hud-timer {
  font-size: 1.5rem;
  color: var(--color-text-main);
  text-shadow: 0 0 8px rgba(255, 255, 255, 0.2);
}

/* ===== HUD overhaul "Edge Telemetry", Phase 1: top corners (desktop) =====================================
   plans/HUD_EDGE_TELEMETRY_PLAN.md. The old full-width .hud-top panel becomes two bracketed corner groups
   sitting directly on the arena: timer / wave / threat top-left, coins / score top-right. The wager and
   glitch-hunt trackers (siblings of .hud-top, kept there because mobile hides .hud-top but still shows
   them) stack under the left corner as a label plus a thin progress line.
   Every rule is scoped with :root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active), the exact complement of the mobile selectors above, so the mobile HUD is
   untouched. Sizes are rem (grows with the html-level --ui-global-scale) or px times --ui-global-scale.
   Inline colours written by JS (wave, threat tier, wager tag) are kept; their inline glow is swapped for
   the .cx-tele shadow stack, which needs !important to beat the style attribute. */
/* #hud scales up by --ui-scale on short windows (transform-origin top center). With the corners pinned to
   the edges, that pushed them off-screen (by ~110px each side at 1366x600), so on desktop the box is laid
   out at 1/--ui-scale of the available width and scaled from its left edge, landing exactly inside the
   16px margins. */
:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) {
  right: auto;
  width: calc((100% - 32px) / var(--ui-scale, 1));
  transform-origin: top left;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .hud-top {
  align-items: flex-start;
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  padding: calc(6px * var(--ui-global-scale, 1)) calc(10px * var(--ui-global-scale, 1));
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .hud-corner {
  --brk: calc(14px * var(--ui-global-scale, 1));
  --brk-w: calc(2px * var(--ui-global-scale, 1));
  display: flex;
  flex-direction: column;
  gap: calc(10px * var(--ui-global-scale, 1));
  padding: calc(14px * var(--ui-global-scale, 1)) calc(18px * var(--ui-global-scale, 1));
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .hud-corner-left {
  align-items: flex-start;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .hud-corner-right {
  align-items: flex-end;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .hud-corner-row {
  display: flex;
  align-items: flex-end;
  gap: calc(14px * var(--ui-global-scale, 1));
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .hud-corner .hud-stat .value {
  font-family: var(--font-display);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  text-shadow: 0 1px 0 #000, 0 0 2px #000, 0 0 12px rgba(0, 0, 0, 0.9) !important;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .hud-corner .hud-stat .label {
  font: 500 0.6875rem/1 var(--font-display);
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: rgba(226, 232, 240, 0.62);
  text-shadow: 0 1px 0 #000, 0 0 8px rgba(0, 0, 0, 0.9);
}

/* Timer: the big readout. min-width holds the corner steady while the digits tick. */
:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .hud-timer {
  font-family: var(--font-display);
  font-size: 3.375rem;
  font-weight: 700;
  line-height: 0.9;
  color: #fff;
}

/* CLEAR: n / ENTER SHOP (toggled by updateHud() in js/init.js instead of an inline font-size). */
.hud-timer.is-status {
  font-size: 0.75rem;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .hud-timer.is-status {
  font-size: 1.375rem;
  line-height: 1;
  letter-spacing: 0.12em;
  color: #fde68a;
  padding-bottom: 0.25rem;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .hud-stat-wave {
  flex-direction: column;
  align-items: flex-start;
  gap: calc(6px * var(--ui-global-scale, 1));
  padding-bottom: 0.125rem;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .hud-stat-wave .value {
  font-size: 1.375rem;
  /* #f472b6 rather than the inline #ec4899: the brighter pink keeps 4.5:1 over the contrast scrim
     (Phase 7), the darker one only managed 3.4:1. */
  color: #f472b6 !important;
}

/* Threat: tier name with a diamond pip in the tier colour (currentColor follows the JS colour write). */
:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) #hud-stat-difficulty .label {
  display: none;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) #hud-difficulty {
  display: inline-flex;
  align-items: center;
  gap: calc(8px * var(--ui-global-scale, 1));
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.24em;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) #hud-difficulty::before {
  content: "";
  width: calc(8px * var(--ui-global-scale, 1));
  height: calc(8px * var(--ui-global-scale, 1));
  background: currentColor;
  transform: rotate(45deg);
  flex: none;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .hud-stat-coins .value {
  font-size: 1.875rem;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .hud-stat-coins img {
  width: calc(24px * var(--ui-global-scale, 1)) !important;
  height: calc(24px * var(--ui-global-scale, 1)) !important;
  filter: drop-shadow(0 1px 0 #000) drop-shadow(0 0 6px rgba(0, 0, 0, 0.8));
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .hud-stat-score {
  gap: calc(10px * var(--ui-global-scale, 1));
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .hud-stat-score .value {
  font-size: 1.125rem;
  color: #d8b4fe;
}

/* Trackers: no pill, just a kicker line ("WAGER · TITAN'S GAUNTLET") and a 3px progress line,
   left-aligned with the content of the corner above. */
:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .wager-hud-tracker,
:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .glitch-hunt-hud {
  align-self: flex-start;
  flex-direction: column;
  align-items: stretch;
  gap: calc(6px * var(--ui-global-scale, 1));
  width: calc(250px * var(--ui-global-scale, 1));
  margin-left: calc(28px * var(--ui-global-scale, 1));
  padding: 0;
  background: transparent;
  backdrop-filter: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .wager-tracker-tag,
:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .glitch-hunt-tag {
  padding: 0;
  background: transparent !important;
  border: 0 !important;
  border-radius: 0;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .wager-tracker-tag,
:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .wager-tracker-title,
:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .glitch-hunt-tag,
:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .glitch-hunt-title {
  font: 600 0.6875rem/1 var(--font-display);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-shadow: 0 1px 0 #000, 0 0 8px rgba(0, 0, 0, 0.9);
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .wager-tracker-title,
:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .glitch-hunt-title {
  color: #fde68a;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .wager-tracker-tag::after,
:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .glitch-hunt-tag::after {
  content: "\00B7";
  margin-left: calc(6px * var(--ui-global-scale, 1));
  color: rgba(226, 232, 240, 0.62);
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .wager-tracker-contract,
:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .glitch-hunt-progress-wrap {
  gap: calc(8px * var(--ui-global-scale, 1));
  border-left: 0;
  padding-left: 0;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .wager-contract-label {
  font: 600 0.625rem/1 var(--font-display);
  letter-spacing: 0.16em;
  text-shadow: 0 1px 0 #000;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .wager-contract-bar-wrap,
:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .glitch-hunt-bar-container {
  flex: 1;
  width: auto;
  height: calc(3px * var(--ui-global-scale, 1));
  background: rgba(255, 255, 255, 0.14);
  border: 0;
  border-radius: 0;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .wager-contract-bar,
:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .glitch-hunt-bar-fill {
  border-radius: 0;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .wager-contract-val,
:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .glitch-hunt-counter {
  font-family: var(--font-display);
  font-size: 0.6875rem;
  font-variant-numeric: tabular-nums;
  color: #e2e8f0;
  text-shadow: 0 1px 0 #000, 0 0 6px rgba(0, 0, 0, 0.9);
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .glitch-hunt-rank-badge {
  border-radius: 0;
  font-size: 0.5625rem;
}

:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .wager-hud-tracker.voided .wager-tracker-title {
  color: rgb(var(--c-danger));
}
/* ============================================================================
   03b-chamfer-kit.css
   Chamfer (cut-corner) menu kit: tokens, the .cut primitive, shapes, the
   gamepad-focus variant and the window header pieces.
   ============================================================================
   Ported from "Claude outputs/chamfer-component-kit.html" (the approved spec).
   Plan: plans/MENU_CHAMFER_OVERHAUL_PLAN.md, sections 2, 3.1-3.5.

   WHERE THIS SITS: "03b" sorts after 03-base.css and before 04-hud-action-bar.css
   (build-css.js concatenates in plain filename order), so nothing is renumbered
   and the kit is EARLY in the cascade. The consequence is that every later
   module (06-shop's .glass-panel, 10's .btn, 36's boundary flare) beats a
   plain class selector from this file. The generic classes below are only
   ever applied through the NEW class names (.cut, .cx-*), which nothing else
   styles. Window behaviour (section 10) reaches the existing .glass-panel
   through a specificity-boosted selector; the remaining screen-specific
   pieces live in the PHASE 0 PILOT section at the bottom, id-scoped.

   clip-path HIDES box-shadow AND outline on the element it clips. So:
     * the element's own background is the FILL (translucent is fine),
     * ::before is the BORDER, a hollow frame cut with an evenodd polygon,
     * focus is drawn by swapping the border variables plus a ::after frame,
       never with an outline or a box-shadow.
   THE REGISTRY (Phase 2c): .cut is applied to existing classes by listing them next to `.cut`
   in the four selector lists below (base, ::before, focus, focus ::after), rather than adding
   a `cut` class to every element in index.html and in the JS-built templates. Currently
   registered: .btn (every menu button), .whats-new-action-btn, .overclock-mult-btn,
   .gear-refactor-info-btn (Phase 2c), and in Phase 2d .toggle-switch, .setting-card-val, the close
   buttons (.cx-close and the per-screen close classes), the top tabs (.bazaar-header-tab,
   .weapon-tree-tab), .credits-terminal-tab and the three segmented-control frames. A new family =
   add its class to those four lists (plus the reset and neutraliser lists in section 12).
   Do NOT revert to "background = border, ::before = fill": every translucent
   fill then shows the border colour through it (a real bug found while
   building the kit).
   ============================================================================ */

/* 1. Tokens ----------------------------------------------------------------- */
:root {
  /* Corner scale. Windows 24, cards 14, buttons 11, close/select/stat tiles 8,
     toggles/pills/keycaps 5. */
  --cut-xl: 24px;
  --cut-lg: 14px;
  --cut-md: 11px;
  --cut-sm: 8px;
  --cut-xs: 5px;

  /* Per-screen accent channel (comma separated, use as rgba(var(--acc), a)).
     Brand purple by default; section 9 below overrides it per overlay id.
     --acc2 (second gradient stop on dual-tone screens) is deliberately NOT
     declared here: every consumer writes var(--acc2, var(--acc)), because a
     `--acc2: var(--acc)` on :root would resolve to the ROOT value and a
     screen that only sets --acc would then keep a purple second stop. */
  --acc: var(--c-primary);
}

/* Short screens (phones in landscape, small laptop windows): a 24px window corner takes a visible bite
   out of a window that may only be ~380px tall, so windows drop to 16px. Cards drop to 10px: at 14px the
   shop card's corner clipped the Lock button and item icon on phones. Same breakpoint as
   css/27-responsive-short.css. */
@media (max-height: 600px) {
  :root {
    --cut-xl: 16px;
    --cut-lg: 10px;
  }
}

/* Mobile mode (phones, and Android tablets via the bridge) uses the compact card layouts whatever the
   height, so cards take the 10px cut there too. */
:root.is-mobile {
  --cut-lg: 10px;
}

/* 2. The .cut primitive ------------------------------------------------------
   Components only set four custom properties and never touch the geometry:
     --cut  corner size        --bw  border width
     --bd   border paint       --bg  fill
   --d is where the inner diagonal meets the inner edge: cut + bw * (sqrt2 - 1). */
.cut,
.btn,
.whats-new-action-btn,
.overclock-mult-btn,
.gear-refactor-info-btn,
.toggle-switch,
.setting-card-val,
.settings-close-btn,
.ach-close-btn,
.overclock-close-btn,
.passive-tree-sidebar-close-btn,
.gamble-reveal-close,
.modal-close-x,
.cx-close,
.credits-terminal-tab,
.bazaar-header-tab,
.weapon-tree-tab,
.ach-tabs-row,
.game-over-tabs-nav,
.su-track-tabs,
.shop-gear-card,
.shop-card,
.gear-compare-card,
.swap-equipped-card,
.gamble-fan-card,
.gear-card-card,
.cx-card,
.upgrade-card,
.choice-card,
.weapon-grid-card,
.weapon-tree-milestone-card,
.modifier-card,
.overclock-card,
.survivor-card,
.char-roster-card,
.difficulty-threat-card {
  --cut: var(--cut-md);
  --bw: 1px;
  --bd: rgba(var(--acc), 0.55);
  --bg: rgba(13, 10, 25, 0.94);
  position: relative;
  isolation: isolate;
  background: var(--bg);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}

.cut::before,
.btn::before,
.whats-new-action-btn::before,
.overclock-mult-btn::before,
.gear-refactor-info-btn::before,
.toggle-switch::before,
.setting-card-val::before,
.settings-close-btn::before,
.ach-close-btn::before,
.overclock-close-btn::before,
.passive-tree-sidebar-close-btn::before,
.gamble-reveal-close::before,
.modal-close-x::before,
.cx-close::before,
.credits-terminal-tab::before,
.bazaar-header-tab::before,
.ach-tabs-row::before,
.game-over-tabs-nav::before,
.su-track-tabs::before,
.shop-gear-card::before,
.shop-card::before,
.gear-compare-card::before,
.swap-equipped-card::before,
.gamble-fan-card::before,
.gear-card-card::before,
.cx-card::before,
.upgrade-card::before,
.choice-card::before,
.weapon-grid-card::before,
.weapon-tree-milestone-card::before,
.modifier-card::before,
.overclock-card::before,
.survivor-card::before,
.char-roster-card::before,
.difficulty-threat-card::before,
.weapon-tree-tab::after {
  --d: calc(var(--cut) + var(--bw) * 0.4142);
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: var(--bd);
  clip-path: polygon(evenodd,
    var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut), var(--cut) 0,
    var(--d) var(--bw), calc(100% - var(--bw)) var(--bw), calc(100% - var(--bw)) calc(100% - var(--d)), calc(100% - var(--d)) calc(100% - var(--bw)), var(--bw) calc(100% - var(--bw)), var(--bw) var(--d), var(--d) var(--bw));
}

/* 3. Tab shape: both TOP corners cut, square bottom, open bottom edge. */
.cut.cut-tab,
.bazaar-header-tab,
.weapon-tree-tab {
  clip-path: polygon(var(--cut) 0, calc(100% - var(--cut)) 0, 100% var(--cut), 100% 100%, 0 100%, 0 var(--cut));
}

.cut.cut-tab::before,
.bazaar-header-tab::before,
.weapon-tree-tab::after {
  clip-path: polygon(evenodd,
    var(--cut) 0, calc(100% - var(--cut)) 0, 100% var(--cut), 100% 100%, 0 100%, 0 var(--cut), var(--cut) 0,
    var(--d) var(--bw), calc(100% - var(--d)) var(--bw), calc(100% - var(--bw)) var(--d), calc(100% - var(--bw)) 100%, var(--bw) 100%, var(--bw) var(--d), var(--d) var(--bw));
}

/* 4. Gamepad focus on a clipped element ---------------------------------------
   --c-focus (sky) stays the single source of truth for focus (01-tokens.css).
   The border turns sky and thickens to 2px, the fill picks up a sky tint, and
   a white 1.5px frame is drawn just INSIDE the border on ::after, so focus is
   never carried by hue alone (the sky focus colour is also the accent of
   several screens). Solid buttons add the pulse; see the pilot section.
   The !important is deliberate: a component's own --bd/--bg (and its :hover
   swap) must not be able to hide focus. */
.cut.controller-focused,
.btn.controller-focused,
.whats-new-action-btn.controller-focused,
.overclock-mult-btn.controller-focused,
.gear-refactor-info-btn.controller-focused,
.toggle-switch.controller-focused,
.settings-close-btn.controller-focused,
.ach-close-btn.controller-focused,
.overclock-close-btn.controller-focused,
.passive-tree-sidebar-close-btn.controller-focused,
.gamble-reveal-close.controller-focused,
.modal-close-x.controller-focused,
.cx-close.controller-focused,
.credits-terminal-tab.controller-focused,
.bazaar-header-tab.controller-focused,
.shop-gear-card.controller-focused,
.shop-card.controller-focused,
.swap-equipped-card.controller-focused,
.cx-card.controller-focused,
.upgrade-card.controller-focused,
.choice-card.controller-focused,
.weapon-grid-card.controller-focused,
.weapon-tree-milestone-card.controller-focused,
.modifier-card.controller-focused,
.overclock-card.controller-focused-card,
.survivor-card.controller-focused,
.char-roster-card.controller-focused,
.difficulty-threat-card.controller-focused,
.weapon-tree-milestone-card:focus-visible,
.btn:focus-visible,
.whats-new-action-btn:focus-visible,
.overclock-mult-btn:focus-visible,
.gear-refactor-info-btn:focus-visible {
  --bd: rgb(var(--c-focus)) !important;
  --bw: 2px;
  --bg: rgba(var(--c-focus), 0.18) !important;
  color: #fff;
}

.cut.controller-focused::after,
.btn.controller-focused::after,
.whats-new-action-btn.controller-focused::after,
.overclock-mult-btn.controller-focused::after,
.gear-refactor-info-btn.controller-focused::after,
.toggle-switch.controller-focused::after,
.settings-close-btn.controller-focused::after,
.ach-close-btn.controller-focused::after,
.overclock-close-btn.controller-focused::after,
.passive-tree-sidebar-close-btn.controller-focused::after,
.gamble-reveal-close.controller-focused::after,
.modal-close-x.controller-focused::after,
.cx-close.controller-focused::after,
.credits-terminal-tab.controller-focused::after,
.bazaar-header-tab.controller-focused::after,
.shop-gear-card.controller-focused::after,
.shop-card.controller-focused::after,
.swap-equipped-card.controller-focused::after,
.cx-card.controller-focused::after,
.upgrade-card.controller-focused::after,
.choice-card.controller-focused::after,
.weapon-grid-card.controller-focused::after,
.weapon-tree-milestone-card.controller-focused::after,
.modifier-card.controller-focused::after,
.overclock-card.controller-focused-card::after,
.survivor-card.controller-focused::after,
.char-roster-card.controller-focused::after,
.difficulty-threat-card.controller-focused::after,
.weapon-tree-milestone-card:focus-visible::after,
.btn:focus-visible::after,
.whats-new-action-btn:focus-visible::after,
.overclock-mult-btn:focus-visible::after,
.gear-refactor-info-btn:focus-visible::after {
  --fw: 1.5px;
  --t: calc(var(--bw) + var(--fw));
  --d1: calc(var(--cut) + var(--bw) * 0.4142);
  --d2: calc(var(--cut) + var(--t) * 0.4142);
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: #fff;
  clip-path: polygon(evenodd,
    var(--d1) var(--bw), calc(100% - var(--bw)) var(--bw), calc(100% - var(--bw)) calc(100% - var(--d1)), calc(100% - var(--d1)) calc(100% - var(--bw)), var(--bw) calc(100% - var(--bw)), var(--bw) var(--d1), var(--d1) var(--bw),
    var(--d2) var(--t), calc(100% - var(--t)) var(--t), calc(100% - var(--t)) calc(100% - var(--d2)), calc(100% - var(--d2)) calc(100% - var(--t)), var(--t) calc(100% - var(--t)), var(--t) var(--d2), var(--d2) var(--t));
}

.cut.cut-tab.controller-focused::after,
.bazaar-header-tab.controller-focused::after {
  clip-path: polygon(evenodd,
    var(--d1) var(--bw), calc(100% - var(--d1)) var(--bw), calc(100% - var(--bw)) var(--d1), calc(100% - var(--bw)) 100%, var(--bw) 100%, var(--bw) var(--d1), var(--d1) var(--bw),
    var(--d2) var(--t), calc(100% - var(--d2)) var(--t), calc(100% - var(--t)) var(--d2), calc(100% - var(--t)) 100%, var(--t) 100%, var(--t) var(--d2), var(--d2) var(--t));
}

@keyframes cx-focus-pulse {
  50% { filter: brightness(1.25); }
}

/* 5. Window ------------------------------------------------------------------
   Apply .cut .cx-win to a window element. Gradient border bright at two
   opposite corners (--acc top-left, --acc2 bottom-right; --acc2 falls back
   to --acc), a faint accent wash from the top-left, two accent bars on
   the top edge (::after) and an optional bottom-right wedge (.cx-wedge child). */
.cx-win {
  --cut: var(--cut-xl);
  --bw: 1.5px;
  --bd: linear-gradient(160deg, rgb(var(--acc)), rgba(var(--acc), 0.3) 35%, rgba(var(--acc2, var(--acc)), 0.12) 65%, rgb(var(--acc2, var(--acc))));
  --bg: linear-gradient(135deg, rgba(var(--acc), 0.12), transparent 28%), rgba(13, 10, 25, 0.95);
}

.cx-win::after {
  content: "";
  position: absolute;
  top: 0;
  right: 30px;
  width: 72px;
  height: 4px;
  background: rgb(var(--acc));
  box-shadow: -84px 0 0 -1px rgba(var(--acc), 0.5);
  pointer-events: none;
}

.cx-wedge {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 42px;
  height: 42px;
  pointer-events: none;
  background: linear-gradient(135deg, transparent 50%, rgba(var(--acc), 0.55) 50%, rgba(var(--acc), 0.55) 62%, transparent 62%);
}

/* 6. Window header: kicker line, uppercase title, optional right-hand code,
   short accent bar under the title. */
.cx-head {
  display: flex;
  align-items: flex-end;
  gap: 14px;
  padding: 22px 24px 14px;
  border-bottom: 1px solid rgba(var(--acc), 0.22);
  position: relative;
}

.cx-head::after {
  content: "";
  position: absolute;
  left: 24px;
  bottom: -2px;
  width: 46px;
  height: 3px;
  background: rgb(var(--acc));
}

.cx-kicker {
  display: block;
  font: 500 0.64rem/1 var(--font-display);
  letter-spacing: 0.3em;
  color: rgba(var(--acc), 0.9);
  margin-bottom: 7px;
}

.cx-title {
  font: 700 1.55rem/1 var(--font-display);
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

.cx-code {
  margin-left: auto;
  font: 500 0.66rem/1 var(--font-display);
  letter-spacing: 0.22em;
  color: rgba(var(--c-text-muted), 0.8);
  padding-bottom: 4px;
}

/* 7. Close button: chamfered square. Use together with .cut. */
.cx-x {
  --cut: var(--cut-sm);
  --bd: rgba(var(--c-ink), 0.18);
  --bg: rgba(var(--c-ink), 0.04);
  width: 34px;
  height: 34px;
  padding: 0;
  border: 0;
  cursor: pointer;
  display: grid;
  place-items: center;
  font-size: 0.95rem;
  color: rgba(var(--c-text-main), 0.8);
  flex-shrink: 0;
}

:where(body:not(.gamepad-active)) .cx-x:hover {
  --bd: rgb(var(--c-danger));
  --bg: rgba(var(--c-danger), 0.2);
  color: #fff;
}


/* 8. Small components ----------------------------------------------------------
   Generic, unused for now. Combine with .cut (they only set its variables). */

/* keycap hint (LB / RB / A / ESC) */
.cx-key {
  --cut: 4px;
  --bd: rgba(var(--c-ink), 0.35);
  --bg: rgba(var(--c-ink), 0.06);
  display: inline-grid;
  place-items: center;
  min-width: 26px;
  height: 20px;
  padding: 0 6px;
  font: 700 0.62rem var(--font-display);
  letter-spacing: 0.06em;
  color: rgba(var(--c-text-main), 0.9);
}

/* rarity pill, coloured by a --r channel (see the --c-rarity-* tokens in 01-tokens.css):
   <span class="cut cx-pill" style="--r: var(--c-rarity-rare)">RARE</span> */
.cx-pill {
  --cut: var(--cut-xs);
  --r: var(--c-slate);
  --bd: rgba(var(--r), 0.8);
  --bg: rgba(var(--r), 0.15);
  display: inline-block;
  padding: 3px 9px 3px 10px;
  font: 700 0.62rem var(--font-display);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgb(var(--r));
}

/* count badge */
.cx-count {
  --cut: 4px;
  --bd: rgb(var(--acc));
  --bg: rgb(var(--acc));
  min-width: 20px;
  padding: 2px 5px;
  font: 700 0.66rem var(--font-display);
  color: #fff;
  text-align: center;
}

/* Slanted label strip: one side cut, used for card rarity tags and the NEW badge. It needs
   no border frame, so it is a plain clip-path (no .cut). --slant sets the cut width. */
.cx-slant {
  --slant: 7px;
  clip-path: polygon(0 0, 100% 0, calc(100% - var(--slant)) 100%, 0 100%);
}

/* card rarity tag: <span class="cx-slant cx-tag" style="--r: var(--c-rarity-magic)">MAGIC</span> */
.cx-tag {
  --r: var(--c-slate);
  display: inline-block;
  padding: 4px 12px 4px 10px;
  font: 700 0.58rem var(--font-display);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  background: rgb(var(--r));
  color: rgb(var(--c-bg));
}

/* NEW badge: gold strip with a blinking square. */
.cx-new {
  --slant: 6px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 14px 3px 9px;
  font: 700 0.62rem var(--font-display);
  letter-spacing: 0.2em;
  background: rgb(var(--c-gold));
  color: rgb(var(--c-bg));
}

.cx-new::before {
  content: "";
  width: 5px;
  height: 5px;
  background: rgb(var(--c-bg));
  animation: cx-blink 1s steps(1) infinite;
}

@keyframes cx-blink {
  50% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .cx-new::before { animation: none; }
}

/* 9. Per-screen accent mapping (plan 3.3) -----------------------------------------
   Mirrors css/36-cyber-transitions.css's per-screen palette, with two rule changes:
     (a) every screen module 36 themes SKY (#38bdf8) gets --c-cyan here, because sky is also
         the gamepad focus colour (--c-focus) and a focused element must not be hue-identical
         to its own window. Module 36's flare/scanline colour is NOT touched.
     (b) screens module 36 does not map at all (start, tutorial, the save-overwrite and respec
         confirms, credits, benchmark, ...) keep the :root default, brand purple --c-primary.
   --acc2 is the second gradient stop on dual-tone screens; where it is unset, consumers fall
   back to --acc. Only .cut / .cx-* rules read these, so this block changes nothing by itself. */
/* gold / amber */
#shop-screen,
#gear-swap-screen,
#inventory-confirm-modal:not(.gamble-confirm-mode) {
  --acc: var(--c-gold);
}

/* royal purple */
#gamble-reveal-screen,
#settings-modal,
#inventory-confirm-modal.gamble-confirm-mode {
  --acc: var(--c-primary);
}

/* electric violet */
#character-select-screen {
  --acc: var(--c-violet);
}

/* dual-tone cyan + purple */
#gear-refactor-screen {
  --acc: var(--c-cyan);
  --acc2: var(--c-primary);
}

/* dual-tone hot pink + deep purple (36's #ff007f / #7f00ff are not palette tokens) */
#weapon-drop-screen {
  --acc: 255, 0, 127;
  --acc2: 127, 0, 255;
}

/* bio emerald */
#difficulty-select-screen,
#survivor-upgrades-screen {
  --acc: var(--c-success);
}

/* crimson danger */
#game-over-screen,
#round-modifier-screen,
#round20-choice-screen {
  --acc: var(--c-danger);
}

/* "cyber cyan": the eight screens 36 themes sky */
#level-up-screen,
#instructions-modal,
#achievements-screen,
#overclock-nexus-screen,
#pause-screen,
#pause-stats-modal,
#changelog-modal,
#major-choice-screen {
  --acc: var(--c-cyan);
}

/* Phase 2a additions: windows whose old look carried a colour that module 36 does not map.
   The inline red borders on the two destructive confirms are gone (clip-path hides them), so the
   frame takes the danger accent instead; the What's New card was gold-bordered; Victory was a
   gold frame; the decryption terminal was gold. Chaos rounds (--acc primary) are in 33-round-modifier.css. */
#save-overwrite-confirm-modal,
#respec-confirm-modal {
  --acc: var(--c-danger);
}

#start-whats-new-card,
#credits-easter-egg-modal,
#game-over-screen.victory-theme {
  --acc: var(--c-gold);
}

/* 10. Window behaviour (generic) -------------------------------------------------
   Everything here keys off classes: any `.glass-panel.cx-win` inside an `.overlay` gets it.

   SPECIFICITY BOOST. The old look is defended by later modules: 36's flare is
   `.overlay.active .glass-panel { box-shadow: ... !important }` (0,3,0), and 36 also has
   id-scoped !important versions for #weapon-drop-screen / #gear-refactor-screen at (1,2,0),
   which no class-only selector can beat. :is() takes the specificity of its MOST specific
   argument, so `:is(#cx-boost, .overlay)` counts as an id (1,0,0) whichever argument
   matches (#cx-boost is a deliberate dummy id that exists nowhere), giving every selector
   below (1,x,x) without naming any real screen. The cost: a later per-screen override of a
   window needs an id too. */

/* The old glass look is neutralised. .cut supplies clip-path / the ::before frame / position;
   .cx-win supplies --cut, --bw, --bd, --bg. */
:is(#cx-boost, .overlay) .glass-panel.cx-win {
  background: var(--bg);
  border: 0;
  border-radius: 0;
  box-shadow: none;
  /* Identity, the same end state as 06-shop's .overlay.active .glass-panel
     (translateY(0) scale(1)). The CRT open/close animations own transform while they run. */
  transform: none;
  transition: none;
}

/* 36's open flare includes an INSET glow, which clip-path does not hide, so it must be killed
   outright. Replaced by the ::before brightness pulse below. (1,3,0) !important beats
   36's (0,3,0) and its id-scoped (1,2,0) dual-tone rules. */
:is(#cx-boost, .overlay).active .glass-panel.cx-win {
  box-shadow: none !important;
}

/* Overlay halo (plan 3.4, candidate A): a soft radial accent halo in the overlay's own
   background, as a gradient layer ABOVE the existing rgba(8,6,15,.88) scrim colour (a gradient
   paints over the colour layer; under an 88%-opaque scrim it would be about 4% visible).
   No wrapper element and no filter: drop-shadow on the clipped panel (it would be clipped).
   Size per screen via --cx-halo-w / --cx-halo-h (px, so the 4K layer scales them); --cx-halo (0..1,
   default 1) scales the strength, 0 turns the halo off (full-screen frames). Applied to
   the id/overlay rather than `.active`, so the halo does not pop off before the fade-out ends. */
.overlay:has(> .glass-panel.cx-win) {
  background:
    radial-gradient(ellipse var(--cx-halo-w, 380px) var(--cx-halo-h, 320px) at 50% 50%, rgba(var(--acc), calc(0.26 * var(--cx-halo, 1))) 0%, rgba(var(--acc), calc(0.1 * var(--cx-halo, 1))) 55%, transparent 100%),
    rgba(8, 6, 15, 0.88);
  /* short fade-in so the CRT line-expand is visible through it */
  transition: opacity 0.15s ease-out;
}

/* Open animation: CRT "line expands to panel", ~0.45s, drawn by animating the window's
   CLIP-PATH, never transform. A glowing horizontal slit (1.2% of the height, 55% of the width)
   widens to full width, then opens vertically to the chamfer shape.

   WHY NOT transform: scale(). getBoundingClientRect() includes transforms, and game JS
   measures windows as they open. js/character-select.js resizeCharHeroCanvas() sized the
   survivor preview canvas to ~147x3 px mid-squash, and because the canvas's CSS height follows
   its pixel height it never recovered (2026-10-06 bug: missing survivor preview). clip-path
   changes neither layout nor getBoundingClientRect(), so any measurement during the animation
   is correct. Do not reintroduce a transform/scale here or on the close.

   All three keyframes use six points so Chromium can interpolate them; the last one is the
   .cut chamfer polygon itself (same var(--cut)), and `backwards` fill means nothing is held
   afterwards, so the resting window is exactly the .cut shape. */
@keyframes cx-crt-in {
  0%   { clip-path: polygon(22.5% 49.4%, 77.5% 49.4%, 77.5% 50.6%, 77.5% 50.6%, 22.5% 50.6%, 22.5% 49.4%); filter: brightness(3); }
  45%  { clip-path: polygon(0 49.4%, 100% 49.4%, 100% 50.6%, 100% 50.6%, 0 50.6%, 0 49.4%);                 filter: brightness(2.2); }
  100% { clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut)); filter: none; }
}

:is(#cx-boost, .overlay).active .glass-panel.cx-win {
  animation: cx-crt-in 0.45s cubic-bezier(0.2, 0.9, 0.3, 1) backwards;
}

/* Close animation: the open in reverse (the slit closes, then shrinks and
   flashes out). It runs purely off the :not(.active) selector starting to match, so the JS
   that removes .active needs no change; the overlay's fade is delayed until the collapse has
   mostly happened. Input is released immediately regardless: `.overlay:not(.active) *` already
   sets pointer-events: none. On page load the closed state also matches, so this plays once
   while the overlay is at opacity 0 (invisible), and `forwards` leaves the panel collapsed
   until the next open swaps in cx-crt-in. */
/* clip-path, not transform: see the note on cx-crt-in. */
@keyframes cx-crt-out {
  0%   { clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut)); filter: none; }
  55%  { clip-path: polygon(0 49.4%, 100% 49.4%, 100% 50.6%, 100% 50.6%, 0 50.6%, 0 49.4%);                 filter: brightness(2.2); }
  100% { clip-path: polygon(22.5% 49.4%, 77.5% 49.4%, 77.5% 50.6%, 77.5% 50.6%, 22.5% 50.6%, 22.5% 49.4%); filter: brightness(3); }
}

:is(#cx-boost, .overlay):not(.active) .glass-panel.cx-win {
  animation: cx-crt-out 0.28s cubic-bezier(0.5, 0, 0.75, 0.2) forwards;
}

.overlay:has(> .glass-panel.cx-win):not(.active) {
  transition: opacity 0.12s ease-in 0.18s;
}

/* Port of module 36's "boundary flare": a brightness pulse of the ::before border (~0.24s) on
   open (after the panel has mostly expanded) and again on .is-morphing. Two keyframe names so
   that adding .is-morphing restarts the animation. */
@keyframes cx-flare {
  0%   { filter: brightness(2.6) saturate(1.3); }
  100% { filter: none; }
}

@keyframes cx-flare-morph {
  0%   { filter: brightness(2.6) saturate(1.3); }
  100% { filter: none; }
}

:is(#cx-boost, .overlay).active .glass-panel.cx-win::before {
  animation: cx-flare 0.24s ease-out 0.2s backwards;
}

:is(#cx-boost, .overlay) .glass-panel.cx-win.is-morphing::before {
  animation: cx-flare-morph 0.24s ease-out;
}

/* The scanline child (module 36) sits inside the clip and still sweeps; hold it until the
   panel has expanded so it does not sweep a 1px-tall line. */
:is(#cx-boost, .overlay).active .glass-panel.cx-win .cyber-panel-scanline {
  animation-delay: 0.22s;
  animation-fill-mode: both;
}

/* Smaller corner on tight screens (plan Phase 6 will tune further). */
.is-mobile .cx-win {
  --cut: 16px;
}

@media (max-height: 600px) {
  .cx-win {
    --cut: 16px;
  }
}

/* 11. Reward modifier: .cx-reward on a .cx-win window ---------------------------------
   Plan decision 2: the reward moments (Weapon Acquired, Gamble Reveal, Round Wager, Major
   Choice) add comparison-page option D ("holo projection") on the same chamfered frame. Not
   applied to any screen yet.
     * Border: a conic gradient through --acc then --acc2, rotated by the registered angle
       --cx-ang (6s, linear). --bd is a plain custom property, so var(--cx-ang) is substituted
       on the window and the substituted string is inherited by ::before, which repaints as the
       angle animates.
     * Fill: ::after is taken by the top bars, so the drifting scanlines (--cx-drift) and the
       periodic soft sweep band (--cx-sweep) are extra background layers of --bg, driven by
       registered properties.
   It animates every frame while open. Acceptable only if gameplay is paused behind these four
   screens; measure on the Steam Deck when Weapon Drop is converted (plan Phase 1 / 4). */
@property --cx-ang {
  syntax: "<angle>";
  inherits: true;
  initial-value: 0deg;
}

@property --cx-drift {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}

@property --cx-sweep {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}

@keyframes cx-reward-spin {
  to { --cx-ang: 360deg; }
}

@keyframes cx-reward-drift {
  to { --cx-drift: 4px; }
}

@keyframes cx-reward-sweep {
  0%   { --cx-sweep: 0; }
  75%  { --cx-sweep: 1; }
  100% { --cx-sweep: 1; }
}

.cx-win.cx-reward {
  --bd: conic-gradient(from var(--cx-ang),
    rgba(var(--acc), 0.12), rgb(var(--acc)) 8%, rgba(var(--acc), 0.12) 22%,
    rgba(var(--acc2, var(--acc)), 0.12) 50%, rgb(var(--acc2, var(--acc))) 58%, rgba(var(--acc2, var(--acc)), 0.12) 72%,
    rgba(var(--acc), 0.12));
  /* The band travels from just above the window to just below it: the position percentage
     resolves against (window height - 70px), so the 100% + 140px endpoint is height + 70px. */
  --bg:
    linear-gradient(180deg, transparent, rgba(var(--acc), 0.13), transparent) 0 calc(-70px + var(--cx-sweep) * (100% + 140px)) / 100% 70px no-repeat,
    linear-gradient(0deg, rgba(var(--acc), 0.07) 1px, transparent 1px) 0 var(--cx-drift) / 100% 4px repeat,
    linear-gradient(180deg, rgba(var(--acc), 0.12), transparent 35%, rgba(var(--acc2, var(--acc)), 0.06)),
    rgba(10, 8, 22, 0.94);
}

/* Only while open (a closed overlay is invisible, so it costs nothing). The CRT open stays in
   the list because `animation` is a single property on the window. */
:is(#cx-boost, .overlay).active .glass-panel.cx-win.cx-reward {
  animation:
    cx-crt-in 0.45s cubic-bezier(0.2, 0.9, 0.3, 1) backwards,
    cx-reward-spin 6s linear infinite,
    cx-reward-drift 1.2s linear infinite,
    cx-reward-sweep 4.5s linear infinite;
}

/* Reduced motion: no open/close animation, no flare, no reward animation (the reward frame
   rests at angle 0 with the band parked above the window), no short fade. Module 36 does the
   same for its scanline and flare. */
@media (prefers-reduced-motion: reduce) {
  :is(#cx-boost, .overlay).active .glass-panel.cx-win,
  :is(#cx-boost, .overlay).active .glass-panel.cx-win.cx-reward,
  :is(#cx-boost, .overlay).active .glass-panel.cx-win::before,
  :is(#cx-boost, .overlay) .glass-panel.cx-win.is-morphing::before,
  :is(#cx-boost, .overlay):not(.active) .glass-panel.cx-win {
    animation: none;
  }

  .overlay:has(> .glass-panel.cx-win):not(.active) {
    transition: opacity 0.15s ease-out;
  }
}



/* 12. Buttons (Phase 2c) -----------------------------------------------------------
   Ported from the kit's .cx-btn onto the EXISTING class names, so no markup change is needed for
   the common case. Shape comes from the registry in section 2 (.btn is registered there), colour
   from --bd / --bg, exactly like every other .cut component.

     .btn                 secondary: accent-tinted fill + accent border, white label  (--cut-md)
     .btn-primary         solid --acc fill, dark label, hover goes white. .btn-glow only ever
                          appears next to .btn-primary and adds nothing here: a glow is an outer
                          box-shadow, which the clip-path would hide.
     .btn-danger          red tint + red border; with .btn-primary it is a solid red button
     .btn-warning / -cyan / -purple   re-point --acc (gold / cyan / purple), so the same
                          secondary or primary rules give an accent variant
     .btn-sm              --cut-sm, tighter padding
     :disabled, .disabled, [aria-disabled]   hazard-stripe fill
     .controller-focused  the kit focus (sky 2px border + white inner edge); solid buttons go
                          solid white (sky border) and pulse, which separates a focused
                          primary from an unfocused one on every accent, cyan included.

   The old module-10 .btn / .btn-primary / .btn-secondary rules (rounded gradient + glow) were
   DELETED at source, not out-ranked. The geometry reset below uses the :is(#cx-boost, .overlay)
   boost (section 10) so that the many later per-button rules that still carry a border-radius, a
   border or a box-shadow cannot bring the old look back; every menu button sits inside an
   .overlay. Sizing declarations (padding, font-size, width, flex) from those later rules are NOT
   reset: they are per-button layout and keep working. */
.btn {
  --cut: var(--cut-md);
  --bd: rgba(var(--acc), 0.65);
  --bg: rgba(var(--acc), 0.1);
  width: 100%;
  padding: 11px 22px;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.82rem;
  line-height: 1.15;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-align: center;
  color: #fff;
  transition: transform 0.1s, color 0.15s;
}

:is(#cx-boost, .overlay) :is(.btn, .whats-new-action-btn, .overclock-mult-btn, .gear-refactor-info-btn,
  .toggle-switch,
  .setting-card-val,
  .settings-close-btn,
  .ach-close-btn,
  .overclock-close-btn,
  .passive-tree-sidebar-close-btn,
  .gamble-reveal-close,
  .modal-close-x,
  .cx-close,
  .credits-terminal-tab,
  .bazaar-header-tab,
  .ach-tabs-row,
  .game-over-tabs-nav,
  .su-track-tabs) {
  background: var(--bg);
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

:where(body:not(.gamepad-active)) .btn:hover {
  --bd: rgb(var(--acc));
  --bg: rgba(var(--acc), 0.26);
}

.btn:active:not(:disabled):not([aria-disabled="true"]) {
  transform: translateY(1px);
}

.btn-primary {
  --bd: rgb(var(--acc));
  --bg: rgb(var(--acc));
  padding: 13px 22px;
  font-size: 0.88rem;
  color: rgb(var(--c-bg));
}

:where(body:not(.gamepad-active)) .btn-primary:hover {
  --bd: #fff;
  --bg: #fff;
  color: rgb(var(--c-bg));
}

/* small variant; the dense contexts also drop to 0.06em tracking */
.btn.btn-sm {
  --cut: var(--cut-sm);
  padding: 8px 14px;
  font-size: 0.74rem;
  letter-spacing: 0.06em;
}

/* accent variants: only --acc moves. A SECONDARY one also tints its label (like .btn-danger below),
   so the colour reads at a glance; a primary keeps its dark label on the solid fill. */
.btn-warning { --acc: var(--c-gold); }
.btn-cyan    { --acc: var(--c-cyan); }
.btn-purple  { --acc: var(--c-primary); }

.btn-warning:not(.btn-primary) { color: #fde68a; }
.btn-cyan:not(.btn-primary)    { color: #a5f3fc; }
.btn-purple:not(.btn-primary)  { color: #e9d5ff; }

:where(body:not(.gamepad-active)) :is(.btn-warning, .btn-cyan, .btn-purple):not(.btn-primary):hover {
  color: #fff;
}

.btn-danger {
  --bd: rgba(var(--c-danger), 0.7);
  --bg: rgba(var(--c-danger), 0.14);
  color: #fca5a5;
}

:where(body:not(.gamepad-active)) .btn-danger:hover {
  --bd: rgb(var(--c-danger));
  --bg: rgba(var(--c-danger), 0.3);
  color: #fff;
}

.btn-primary.btn-danger {
  --bd: rgb(var(--c-danger));
  --bg: rgb(var(--c-danger));
  color: #fff;
}

:where(body:not(.gamepad-active)) .btn-primary.btn-danger:hover {
  --bd: #fff;
  --bg: #fff;
  color: rgb(var(--c-danger));
}

/* Maxed (Overclock): a finished state, not a disabled one, so it keeps the gold tint instead of
   the hazard stripe. Declared before the disabled rule and out-ranked by .btn-upgrade-oc.maxed. */
.btn.maxed {
  --acc: var(--c-gold);
  --bd: rgba(var(--c-gold), 0.45);
  --bg: rgba(var(--c-gold), 0.1);
  color: rgb(var(--c-gold));
}

/* Disabled: hazard stripe. Placed after every hover rule above (equal specificity, later wins)
   so a hover over a disabled button changes nothing. */
.btn:disabled,
.btn[aria-disabled="true"],
.btn.disabled {
  --bd: rgba(var(--c-ink), 0.12);
  --bg: repeating-linear-gradient(-45deg, rgba(var(--c-ink), 0.05) 0 6px, transparent 6px 12px), rgba(13, 10, 25, 0.9);
  color: rgba(var(--c-text-muted), 0.6);
  cursor: not-allowed;
}

.btn.maxed:disabled {
  --bd: rgba(var(--c-gold), 0.45);
  --bg: rgba(var(--c-gold), 0.1);
  color: rgb(var(--c-gold));
  cursor: default;
}

/* Focus. The generic focus variant (section 4) already covers the registry; solid buttons go
   solid WHITE with the sky border, dark label, and pulse. The old module-16 safety net draws an outline, an outer
   glow and scale(1.03) on EVERY .controller-focused element, all with !important; on a clipped
   button the outline/glow are invisible but the scale is not, so it is switched off here for the
   registry (an !important rule has to beat an !important rule, and this one out-ranks it by
   specificity). */
.btn-primary.controller-focused,
.btn-primary:focus-visible {
  /* White, not sky (decided 2026-10-06): a sky fill sat too close to the cyan accent of the
     eight cyan screens. White + the sky 2px border reads as focus on every accent colour. */
  --bg: #fff !important;
  color: rgb(var(--c-bg));
  animation: cx-focus-pulse 1.2s ease-in-out infinite;
}

:is(.btn, .whats-new-action-btn, .overclock-mult-btn, .gear-refactor-info-btn,
  .toggle-switch,
  .settings-close-btn,
  .ach-close-btn,
  .overclock-close-btn,
  .passive-tree-sidebar-close-btn,
  .gamble-reveal-close,
  .modal-close-x,
  .cx-close,
  .credits-terminal-tab,
  .bazaar-header-tab,
  .weapon-tree-tab,
  .settings-select,
  .side-tab,
  .ach-tab,
  .game-over-tab-btn,
  .su-track-tab,
  .shop-gear-card,
  .shop-card,
  .swap-equipped-card,
  .cx-card).controller-focused:not(.selected):not(.power-up):not(.rejected):not(.fizzle) {
  outline: none !important;
  /* the registry kit draws focus with --bd / ::after; the few members that also paint an inset ring
     (side tab, segmented tab, select, weapon tab) hand it over in --cx-ring */
  box-shadow: var(--cx-ring, none) !important;
  transform: none !important;
}

.btn .cx-key {
  --bd: rgba(var(--c-bg), 0.5);
  --bg: rgba(var(--c-bg), 0.15);
  color: inherit;
}

/* dense contexts: 0.06em tracking so the long labels still fit */
.is-mobile .btn {
  letter-spacing: 0.06em;
}

@media (max-height: 600px) {
  .btn {
    letter-spacing: 0.06em;
  }
}

@media (prefers-reduced-motion: reduce) {
  .btn-primary.controller-focused,
  .btn-primary:focus-visible {
    animation: none;
  }
}


/* ============================================================================
   PHASE 0 PILOT: the screen-specific remainder for Pause + Pause Stats
   ============================================================================
   Window behaviour (neutralised glass look, halo, CRT open/close, flare, scanline) is now
   generic, in section 10. What stays here is genuinely per-screen and id-scoped, until
   Phase 2 globalises buttons and controls: halo size, header spacing, titles, the Back button
   sizing, close-X and the stats rows. (The pilot's button look, focus and tracking are now the
   global button system, section 12 below.) Everything that touches an existing shared class
   (.section-title, .upgrade-header, .weapon-dmg-bar-*) is scoped under #pause-screen /
   #pause-stats-modal. Ids beat the later modules on specificity
   (1,x,x), including 36's !important rules where the override is itself !important.
   The window accent (cyan, not sky) comes from the mapping in section 9. */

/* halo sizes (default is 380 x 320) */
#pause-screen {
  --cx-halo-w: 340px;
  --cx-halo-h: 300px;
}

#pause-stats-modal {
  --cx-halo-w: 430px;
  --cx-halo-h: 250px;
}

/* Header: kicker + solid uppercase title + accent underline. The panel keeps its own
   padding, so the header runs content-width (not the kit's full-bleed 24px padding). */
#pause-screen .cx-head,
#pause-stats-modal .cx-head {
  width: 100%;
  margin: 0 0 14px;
  padding: 0 44px 12px 0;
  text-align: left;
  box-sizing: border-box;
}

#pause-screen .cx-head::after,
#pause-stats-modal .cx-head::after {
  left: 0;
}

#pause-screen .cx-title,
#pause-stats-modal .cx-title {
  /* replaces .section-title's gradient text + drop-shadow (06-shop) */
  background: none;
  -webkit-text-fill-color: currentColor;
  color: rgb(var(--c-text-main));
  filter: none;
  margin: 0;
  font-size: 1.55rem;
}

#pause-stats-modal .cx-title {
  font-size: 1.3rem;
}

#pause-stats-modal .upgrade-header.cx-head {
  margin-bottom: 2px;
}

/* "Back to Pause": was a 999px pill with inline sizing; now a primary chamfer button. */
#pause-stats-modal #pause-stats-back-btn.btn.cut {
  width: auto;
  min-width: 160px;
  padding: 8px 28px;
  font-size: 0.85rem;
}

/* Close X */
#pause-stats-close-x.cx-x {
  position: absolute;
  top: 14px;
  right: 16px;
  z-index: 10;
  transition: color 0.2s;
}

/* Stats rows are JS-generated (renderWeaponDamageBreakdown, js/init.js) and share
   .weapon-dmg-bar-* with the Game Over screen, so only restyle them here, under the modal:
   square corners and an accent edge. The bar colours are left as they were. */
#pause-stats-breakdown-container {
  align-self: stretch;
}

#pause-stats-breakdown-container .weapon-dmg-bar-row {
  border: 0;
  border-left: 2px solid rgba(var(--acc), 0.7);
  border-radius: 0;
  background: rgba(var(--acc), 0.06);
}

#pause-stats-breakdown-container .weapon-dmg-bar-title img,
#pause-stats-breakdown-container .weapon-dmg-bar-track,
#pause-stats-breakdown-container .weapon-dmg-bar-fill {
  border-radius: 0;
}

/* ============================================================================
   PHASE 2a: per-screen halo sizes
   ============================================================================
   --cx-halo-w / --cx-halo-h are the ellipse RADII in layer px (default 380 x 320). Rule of thumb:
   half the window size plus roughly 130-140px, so the glow shows beyond the frame. A window whose
   fill is opaque hides the part of the halo behind it. --cx-halo: 0 turns the halo off:
     * start screen: two persistent panels over the key art, which has its own background;
     * shop: the window is 96vw x 92vh, there is no margin to glow into;
     * game over: the stage frame is near-full-screen and the screen paints its own victory/defeat
       radial background (!important), so a halo could not show anyway.
   Sizes are for 1920x1080; everything is in layer px, so 4K scales with it. Pause / Pause Stats
   are set in the pilot section below. */
#start-screen,
#shop-screen,
#game-over-screen {
  --cx-halo: 0;
}

#changelog-modal      { --cx-halo-w: 480px; --cx-halo-h: 600px; }
#instructions-modal   { --cx-halo-w: 620px; --cx-halo-h: 400px; }
#save-overwrite-confirm-modal { --cx-halo-w: 340px; --cx-halo-h: 260px; }
#settings-modal       { --cx-halo-w: 560px; --cx-halo-h: 400px; }
#tutorial-modal       { --cx-halo-w: 400px; --cx-halo-h: 300px; }
#weapon-drop-screen   { --cx-halo-w: 480px; --cx-halo-h: 200px; }
#major-choice-screen  { --cx-halo-w: 480px; --cx-halo-h: 220px; }
#round-modifier-screen { --cx-halo-w: 620px; --cx-halo-h: 230px; }
/* nested inside #shop-screen, which switches the halo off, so it switches it back on */
#respec-confirm-modal { --cx-halo: 1; --cx-halo-w: 360px; --cx-halo-h: 260px; }
#overclock-nexus-screen { --cx-halo-w: 600px; --cx-halo-h: 200px; }
#level-up-screen      { --cx-halo-w: 580px; --cx-halo-h: 330px; }
#gear-swap-screen     { --cx-halo-w: 320px; --cx-halo-h: 280px; }
#inventory-confirm-modal { --cx-halo-w: 320px; --cx-halo-h: 240px; }
#gear-refactor-screen { --cx-halo-w: 460px; --cx-halo-h: 260px; }
#gamble-reveal-screen { --cx-halo-w: 420px; --cx-halo-h: 270px; }
#character-select-screen { --cx-halo-w: 700px; --cx-halo-h: 380px; }
#difficulty-select-screen { --cx-halo-w: 640px; --cx-halo-h: 220px; }
#survivor-upgrades-screen { --cx-halo-w: 700px; --cx-halo-h: 470px; }
#achievements-screen  { --cx-halo-w: 700px; --cx-halo-h: 460px; }
#round20-choice-screen { --cx-halo-w: 360px; --cx-halo-h: 260px; }
#benchmark-results-screen { --cx-halo-w: 480px; --cx-halo-h: 600px; }
#credits-easter-egg-modal { --cx-halo-w: 520px; --cx-halo-h: 420px; }


/* ============================================================================
   PHASE 2c: buttons that are registered but are not .btn
   ============================================================================
   The Gear Refactor "i" info button: a 32px square with an italic i. Its inline background, 1.5px
   border, 8px radius and glow were removed from index.html; it is a small chamfered tile now. */
#gear-refactor-info-btn {
  --cut: var(--cut-sm);
  --bd: rgba(var(--acc), 0.5);
  --bg: rgba(var(--acc), 0.12);
  color: rgb(var(--acc));
}

:where(body:not(.gamepad-active)) #gear-refactor-info-btn:hover {
  --bd: rgb(var(--acc));
  --bg: rgba(var(--acc), 0.26);
}


/* ============================================================================
   PHASE 2d: global controls
   ============================================================================
   Toggle, sliders, dropdown, close buttons, scrollbars and tabs. They keep their own classes
   (the registry above adds the shape); only the look lives here. Gamepad focus is the kit
   variant (section 4) wherever the element is clipped, and an inset ring or a colour swap where
   it is not. */

/* 13. Toggle switch ------------------------------------------------------------------------
   <button class="toggle-switch [active]"><span class="toggle-switch-knob"></span></button>.
   State is the .active class (js/settings.js, untouched). The ON / OFF label is generated on the
   knob's ::after (the knob itself is not clipped, so the label can sit outside the 18px square;
   the square chamfered knob is its ::before). */
.toggle-switch {
  --cut: 6px;
  --bd: rgba(var(--c-ink), 0.2);
  --bg: rgba(var(--c-ink), 0.04);
  width: 58px;
  height: 26px;
  padding: 0;
  border: 0;
  cursor: pointer;
  flex-shrink: 0;
}

.toggle-switch.active {
  --bd: rgb(var(--acc));
  --bg: rgba(var(--acc), 0.22);
}

.toggle-switch-knob {
  position: absolute;
  top: 4px;
  left: 4px;
  width: 18px;
  height: 18px;
  transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1);
}

.toggle-switch-knob::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(var(--c-text-muted), 0.9);
  clip-path: polygon(4px 0, 100% 0, 100% calc(100% - 4px), calc(100% - 4px) 100%, 0 100%, 0 4px);
  transition: background 0.18s;
}

.toggle-switch-knob::after {
  content: "OFF";
  position: absolute;
  top: 50%;
  left: calc(100% + 8px);
  transform: translateY(-50%);
  font: 700 0.58rem var(--font-display);
  letter-spacing: 0.12em;
  color: rgba(var(--c-text-muted), 0.8);
  pointer-events: none;
}

.toggle-switch.active .toggle-switch-knob {
  transform: translateX(32px);
}

.toggle-switch.active .toggle-switch-knob::before {
  background: rgb(var(--acc));
}

.toggle-switch.active .toggle-switch-knob::after {
  content: "ON";
  left: auto;
  right: calc(100% + 9px);
  color: #fff;
}

/* 14. Range slider + value chip -------------------------------------------------------------
   Segmented track (gap stripes in the panel colour over a fill / rest split) and a white bar
   thumb. The fill length is --pct, written by js/settings.js (syncSettingsRangeFill).
   The value readout next to it is a chamfered chip; .cx-val is the same chip for new markup. */
.settings-range-slider {
  --pct: 0%;
  -webkit-appearance: none;
  appearance: none;
  height: 20px;
  background: transparent;
  cursor: pointer;
}

.settings-range-slider::-webkit-slider-runnable-track {
  height: 8px;
  background:
    repeating-linear-gradient(90deg, transparent 0 8px, rgb(13, 10, 25) 8px 10px),
    linear-gradient(90deg, rgb(var(--acc)) var(--pct), rgba(var(--c-ink), 0.1) var(--pct));
}

.settings-range-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 8px;
  height: 20px;
  margin-top: -6px;
  border: 0;
  border-radius: 0;
  background: #fff;
  box-shadow: 0 0 8px rgba(var(--acc), 0.9);
}

.setting-card-val,
.cx-val {
  --cut: 5px;
  --bd: rgba(var(--acc), 0.45);
  --bg: rgba(var(--acc), 0.1);
  display: inline-block;
  min-width: 52px;
  padding: 4px 8px;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: rgb(var(--acc));
}

/* 15. Dropdown ---------------------------------------------------------------------------------
   A native <select> cannot carry ::before / ::after, so the frame is drawn with the border plus
   background layers: top to bottom the two halves of the chevron, the accent block behind it, a
   1px stroke on each of the two cut corners (the clip-path would otherwise leave them open) and
   the fill. --edge is where the cut diagonal sits along a 135deg gradient. The popup list is the
   browser's own; its option colours are in 25-settings.css. */
.settings-select {
  --cut: 7px;
  --bw: 1px;
  --bd: rgba(var(--acc), 0.5);
  --bg: rgba(13, 10, 25, 0.9);
  --blk: rgba(var(--acc), 0.25);
  --edge: calc(var(--cut) * 0.7071);
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  box-sizing: border-box;
  min-width: 150px;
  padding: 7px 34px 7px 12px;
  border: var(--bw) solid var(--bd);
  border-radius: 0;
  box-shadow: none;
  outline: none;
  cursor: pointer;
  font: 600 0.82rem/1.2 var(--font-display);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #fff;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  background:
    linear-gradient(to bottom left, rgb(var(--acc)) 50%, transparent 50%) right 13px center / 5px 5px no-repeat,
    linear-gradient(to bottom right, rgb(var(--acc)) 50%, transparent 50%) right 8px center / 5px 5px no-repeat,
    linear-gradient(var(--blk), var(--blk)) right center / 26px 100% no-repeat,
    linear-gradient(135deg, transparent calc(var(--edge) - var(--bw) * 1.2), var(--bd) calc(var(--edge) - var(--bw) * 1.2), var(--bd) var(--edge), transparent var(--edge)) right bottom / var(--cut) var(--cut) no-repeat,
    linear-gradient(135deg, transparent var(--edge), var(--bd) var(--edge), var(--bd) calc(var(--edge) + var(--bw) * 1.2), transparent calc(var(--edge) + var(--bw) * 1.2)) left top / var(--cut) var(--cut) no-repeat,
    var(--bg);
  background-origin: border-box;
  background-clip: border-box;
  transition: color 0.15s;
}

:where(body:not(.gamepad-active)) .settings-select:hover {
  --bd: rgb(var(--acc));
  --blk: rgba(var(--acc), 0.45);
}

.settings-select:focus,
.settings-select.controller-focused {
  --bd: rgb(var(--c-focus));
  --bw: 2px;
  --bg: rgb(16, 28, 48);
  --blk: rgba(var(--c-focus), 0.4);
  --cx-ring: inset 0 0 0 1.5px #fff;
  box-shadow: var(--cx-ring);
}

.settings-select option {
  text-transform: none;
}

/* 16. Close buttons ------------------------------------------------------------------------------
   Every close X keeps its own class and position (set per screen); this is the shared chamfered
   square, the same look as .cx-x. The three buttons that used to carry inline styles
   (#instructions-close-btn, #gear-refactor-close-btn, #gear-refactor-info-close-btn) take .cx-close.
   The dev panel's .dev-close-btn is deliberately not part of it. */
:is(.settings-close-btn, .ach-close-btn, .overclock-close-btn, .passive-tree-sidebar-close-btn,
  .gamble-reveal-close, .modal-close-x, .cx-close) {
  --cut: var(--cut-sm);
  --bd: rgba(var(--c-ink), 0.18);
  --bg: rgba(var(--c-ink), 0.04);
  box-sizing: border-box;
  min-width: 34px;
  height: 34px;
  padding: 0 8px;
  cursor: pointer;
  color: rgba(var(--c-text-main), 0.8);
  flex-shrink: 0;
}

:where(body:not(.gamepad-active)) :is(.settings-close-btn, .ach-close-btn, .overclock-close-btn,
  .passive-tree-sidebar-close-btn, .gamble-reveal-close, .modal-close-x, .cx-close):hover {
  --bd: rgb(var(--c-danger));
  --bg: rgba(var(--c-danger), 0.2);
  color: #fff;
}

.cx-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

#instructions-close-btn.cx-close {
  position: absolute;
  top: 16px;
  right: 18px;
  z-index: 10;
}

#gear-refactor-close-btn.cx-close {
  position: absolute;
  top: 10px;
  right: 12px;
  z-index: 5;
}

/* 17. Scrollbars ---------------------------------------------------------------------------------
   Square accent thumb with a glow on a ticked track, everywhere. The colour is --acc of the
   scrolling element's screen, or --sb where a screen picks its own (game over). Chromium 121+ stops
   drawing the ::-webkit-scrollbar parts as soon as scrollbar-width / scrollbar-color are set on an
   element, so those standard properties (the old per-screen declarations were removed) now only
   apply where the webkit parts do not exist at all. */
::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}

::-webkit-scrollbar-track {
  background: repeating-linear-gradient(180deg, rgba(var(--c-ink), 0.08) 0 2px, transparent 2px 8px);
}

::-webkit-scrollbar-track:horizontal {
  background: repeating-linear-gradient(90deg, rgba(var(--c-ink), 0.08) 0 2px, transparent 2px 8px);
}

::-webkit-scrollbar-thumb {
  background: rgb(var(--sb, var(--acc)));
  border-radius: 0;
  box-shadow: 0 0 6px rgba(var(--sb, var(--acc)), 0.8);
}

:where(body:not(.gamepad-active)) ::-webkit-scrollbar-thumb:hover {
  box-shadow: 0 0 10px rgba(var(--sb, var(--acc)), 1);
}

::-webkit-scrollbar-corner {
  background: transparent;
}

@supports not selector(::-webkit-scrollbar) {
  * {
    scrollbar-width: thin;
    scrollbar-color: rgb(var(--sb, var(--acc))) rgba(var(--c-ink), 0.06);
  }
}

/* 18. Segmented controls and tiles ---------------------------------------------------------------
   Achievements tabs, game-over tabs, survivor-upgrade track tabs: a chamfered frame holding flat
   buttons; the active one is solid accent with a dark label (the kit's .cx-seg). The decryption
   terminal's tabs (JS-built list in the Easter-egg modal) are chamfered tiles instead, since their
   children carry their own colours. */
:is(.ach-tabs-row, .game-over-tabs-nav, .su-track-tabs) {
  --cut: 8px;
  --bd: rgba(var(--acc), 0.45);
  --bg: rgba(var(--c-ink), 0.03);
  box-sizing: border-box;
  padding: 3px;
  gap: 3px;
}

:is(.ach-tab, .game-over-tab-btn, .su-track-tab) {
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  cursor: pointer;
  color: rgba(var(--c-text-muted), 1);
  clip-path: polygon(6px 0, 100% 0, 100% calc(100% - 6px), calc(100% - 6px) 100%, 0 100%, 0 6px);
  transition: background 0.15s, color 0.15s;
}

:where(body:not(.gamepad-active)) :is(.ach-tab, .game-over-tab-btn, .su-track-tab):hover {
  color: #fff;
  background: rgba(var(--acc), 0.12);
}

:is(.ach-tab, .game-over-tab-btn, .su-track-tab).active {
  background: rgb(var(--acc));
  color: rgb(var(--c-bg));
}

:is(.ach-tab, .game-over-tab-btn, .su-track-tab).controller-focused {
  --cx-ring: inset 0 0 0 1.5px #fff;
  background: rgb(var(--c-focus));
  color: rgb(var(--c-bg));
  box-shadow: var(--cx-ring);
}

.credits-terminal-tab {
  --cut: 8px;
  --bd: rgba(var(--c-ink), 0.12);
  --bg: rgba(15, 23, 42, 0.75);
}

:where(body:not(.gamepad-active)) .credits-terminal-tab:hover {
  --bd: rgb(var(--acc));
  --bg: rgba(var(--acc), 0.12);
}

.credits-terminal-tab.active {
  --bd: rgb(var(--acc));
  --bg: rgba(var(--acc), 0.2);
}

/* 19. Sidebar tab (.side-tab) ----------------------------------------------------------------------
   The shell shared by the settings and achievements sidebars (the markup carries .side-tab next to
   .settings-sidebar-tab / .ach-sidebar-tab, so nothing was renamed). Flat, with a left rail drawn as
   an inset shadow and the bottom-right corner cut. The family classes only add what differs (the
   achievements tab is two rows). .active and .controller-focused are defined after hover, so they
   win. Focus is a sky ring + a white inner ring, so it is never carried by hue alone on cyan screens. */
.side-tab {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  box-sizing: border-box;
  padding: 12px 14px;
  position: relative;
  text-align: left;
  cursor: pointer;
  border: 0;
  background: transparent;
  color: rgba(var(--c-text-muted), 1);
  font-size: 0.88rem;
  font-weight: 700;
  outline: none;
  box-shadow: inset 2px 0 0 rgba(var(--c-ink), 0.08);
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 9px), calc(100% - 9px) 100%, 0 100%);
  transition: background 0.15s, color 0.15s, box-shadow 0.15s;
}

:where(body:not(.gamepad-active)) .side-tab:hover {
  color: #fff;
  background: rgba(var(--acc), 0.06);
  box-shadow: inset 2px 0 0 rgba(var(--acc), 0.5);
}

.side-tab.active {
  color: #fff;
  background: linear-gradient(90deg, rgba(var(--acc), 0.3), rgba(var(--acc), 0.05));
  box-shadow: inset 3px 0 0 rgb(var(--acc));
}

.side-tab.controller-focused {
  --cx-ring: inset 0 0 0 2px rgb(var(--c-focus)), inset 0 0 0 3.5px #fff;
  color: #fff;
  background: linear-gradient(90deg, rgba(var(--c-focus), 0.3), rgba(var(--c-focus), 0.05));
  box-shadow: var(--cx-ring);
}

/* 20. Top tabs --------------------------------------------------------------------------------------
   .bazaar-header-tab and .weapon-tree-tab: the cut-tab shape (registry), a 2px accent baseline and an
   accent-filled active state. The baseline is part of --bg (a gradient), so it needs no pseudo
   element: ::before is the border frame and ::after the focus frame, which is why the old
   .bazaar-header-tab.active::after slide indicator was removed. The weapon-tree tab already uses its
   ::before for the milestone-progress fill, so its border frame is on ::after and its focus ring is an
   inset shadow instead of the white ::after frame. */
.bazaar-header-tab {
  --cut: 10px;
  --bd: rgba(var(--c-ink), 0.12);
  --bg: linear-gradient(0deg, rgba(var(--acc), 0.5) 0 2px, transparent 2px), rgba(var(--c-ink), 0.03);
  color: var(--color-text-muted);
  transition: color 0.15s;
}

:where(body:not(.gamepad-active)) .bazaar-header-tab:hover {
  --bd: rgba(var(--acc), 0.5);
  color: #fff;
}

.bazaar-header-tab.active {
  --bd: rgb(var(--acc));
  --bg: linear-gradient(0deg, rgb(var(--acc)) 0 2px, transparent 2px), linear-gradient(180deg, rgba(var(--acc), 0.35), rgba(var(--acc), 0.12));
  color: #fff;
}

.weapon-tree-tab {
  --cut: 8px;
  --bw: 1.5px;
  --bd: rgba(var(--c-ink), 0.12);
  --bg: rgba(25, 20, 46, 0.75);
  color: var(--color-text-muted);
  box-shadow: inset 0 -2px 0 rgba(var(--acc), 0.5);
}

:where(body:not(.gamepad-active)) .weapon-tree-tab:hover:not(.locked) {
  --bd: var(--progress-color, rgba(var(--acc), 0.5));
  --bg: rgba(30, 24, 55, 0.7);
  color: #fff;
}

.weapon-tree-tab.active {
  --bd: var(--progress-color, rgb(var(--acc)));
  --bg: linear-gradient(90deg, #2a1c48, #3c193a);
  color: #fff;
  box-shadow: inset 0 -2px 0 var(--progress-color, rgb(var(--acc)));
}

.weapon-tree-tab.controller-focused {
  --bd: rgb(var(--c-focus)) !important;
  --bw: 2px;
  --cx-ring: inset 0 0 0 1.5px #fff, inset 0 -2px 0 rgb(var(--c-focus));
  color: #fff;
}

/* 21. Cards (Phase 3a) -----------------------------------------------------------------------------
   One treatment for every card: .shop-gear-card (and the gamble panel), .shop-card, the gear-swap
   .gear-compare-card, .swap-equipped-card, .gamble-fan-card, the bordered .gear-card-card, and the
   generic .cx-card. All are registry members (14px chamfer, --cut-lg; 8px for the small fan card), so
   the frame is the ::before border and the fill is --bg; box-shadow and outline are clipped away and are
   not used. The rarity colour is one channel, --r, mapped from the existing rarity-* classes so no JS has to
   set a colour. The frame, a diagonal wash, the slanted tag strip, the striped art box and the dashed price
   divider all read from it. Per-card state is a variable swap: locked, junk, can't afford and focus change
   --bd / --bw / --bg, never a shadow. Focus is the kit's sky frame + white inner edge (section 4); the
   tag strip is a child and stays visible. ::after is the focus frame, so the legendary / ultimate sheen sits on
   ::after only while NOT focused. */
:is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card) {
  --cut: var(--cut-lg);
  --r: var(--c-rarity-common);
  --bw: 1px;
  --bd: rgba(var(--r), 0.55);
  --bg: linear-gradient(160deg, rgba(var(--r), 0.14), rgba(var(--r), 0.03) 55%, transparent), rgba(13, 10, 25, 0.94);
}

:is(#cx-boost, .overlay) :is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card) {
  background: var(--bg);
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

/* --r from the rarity classes already on the markup (shop-gear-card, gear-card root, gamble fan cards,
   the gear-swap compare cards via setCompareCardFrame). "standard" is the shop-card's name for common. */
:is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card, .gear-card).rarity-basic,
:is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card, .gear-card).rarity-common,
:is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card, .gear-card).rarity-standard { --r: var(--c-rarity-common); }
:is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card, .gear-card).rarity-magic { --r: var(--c-rarity-magic); }
:is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card, .gear-card).rarity-rare { --r: var(--c-rarity-rare); --bw: 1.5px; --bd: rgba(var(--r), 0.85); }
:is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card, .gear-card).rarity-legendary { --r: var(--c-rarity-legendary); --bw: 2px; --bd: rgb(var(--r)); }
:is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card, .gear-card).rarity-ultimate { --r: var(--c-rarity-ultimate); --bw: 2px; --bd: rgb(var(--r)); }
:is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card, .gear-card).rarity-anomalous { --r: var(--c-rarity-anomalous); --bw: 1.5px; --bd: rgb(var(--r)); }

/* ANOMALY RULE (Phase 3b, one rule for every card family): the frame stays the RARITY colour, because rarity is
   the tier and anomalous is a flag. Anomaly Infused gear shows as the holographic overlay and sweep of
   .gear-outer-glitched (css/14-gear-card.css), the "Glitched" text in the tag strip and a cyan accent on
   the icon / art box (css/14: .gear-outer-glitched .card-icon-box, .gear-card-anomalous .gear-card-icon).
   The modifier card is the exception that proves it: ANOMALOUS is its tier, so its frame is --c-rarity-anomalous. */


/* The gamble panel rides the shop-gear-card layout and is always ultimate purple. */
.shop-gear-card.shop-gamble-panel {
  --r: var(--c-rarity-ultimate);
  --bw: 1.5px;
  --bd: rgba(var(--r), 0.8);
  --bg: linear-gradient(145deg, rgba(var(--r), 0.2), rgba(14, 10, 26, 0.9) 60%), rgba(14, 10, 26, 0.95);
}

/* The compare card with an empty slot (no rarity-* class): a dim neutral frame. */
.gear-compare-card:not([class*="rarity-"]) {
  --bd: rgba(var(--c-ink), 0.15);
  --bg: rgba(0, 0, 0, 0.3);
}

/* Small fan card back: 8px cut, text and frame in the rarity colour. */
.gamble-fan-card.gamble-fan-card {
  --cut: var(--cut-sm);
  --bw: 2px;
  --bd: rgb(var(--r));
  --bg: linear-gradient(165deg, rgba(var(--r), 0.22), transparent 70%), linear-gradient(145deg, #1e1140, #2a1a5c);
  color: rgb(var(--r));
}

.gear-card-card {
  --cut: var(--cut-sm);
}

/* Sold out / can't afford (the old shop-card): dim frames; the lock states live with their components. */
.shop-card.sold-out {
  --bd: rgba(var(--c-ink), 0.08);
}

.shop-card.cant-afford {
  --bd: rgba(var(--c-danger), 0.35);
}

/* Hover (pointer only): brighter frame and lift. Locked / unaffordable / junk keep their own frames. */
:where(body:not(.gamepad-active)) :is(.shop-gear-card, .shop-card, .swap-equipped-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card):hover:not(.locked-item):not(.cant-afford):not(.card-is-junk):not(.sold-out) {
  --bd: rgb(var(--r));
  --bg: linear-gradient(160deg, rgba(var(--r), 0.24), rgba(var(--r), 0.06) 55%, transparent), rgba(18, 14, 36, 0.96);
}

:where(body:not(.gamepad-active)) .shop-card.cant-afford:hover {
  --bd: rgba(var(--c-danger), 0.7);
}

:where(body:not(.gamepad-active)) :is(.swap-equipped-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card):hover {
  transform: translateY(-2px);
}

.swap-equipped-card {
  --r: var(--c-danger);
}

/* Slanted rarity tag strip (the kit's .cx-tag look) on the card's own type / subtitle line. */
.shop-gear-card .card-type-text,
.gear-card[class*="rarity-"] .gear-card-subtitle {
  display: block;
  box-sizing: border-box;
  align-self: flex-start;
  padding: 3px 12px 3px 8px;
  background: rgb(var(--r));
  color: rgb(var(--c-bg));
  clip-path: polygon(0 0, 100% 0, calc(100% - 7px) 100%, 0 100%);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  opacity: 1;
}

.shop-gear-card .card-type-text {
  align-self: stretch;
  max-width: none;
  padding: 3px 9px 3px 4px;
  font-size: 0.6rem;
  letter-spacing: 0;
  overflow-wrap: normal;
  word-break: normal;
  text-align: left;
}

.shop-gear-card .card-type-text .card-type-glitched-tag {
  color: inherit;
}

.shop-gear-card .card-title-text,
.gear-card[class*="rarity-"] .gear-card-title {
  color: rgb(var(--r));
}

/* Striped art box: diagonal rarity stripes behind the item icon. */
.shop-gear-card .card-icon-box,
.gear-card[class*="rarity-"] .gear-card-icon {
  background: repeating-linear-gradient(135deg, rgba(var(--r), 0.14) 0 6px, rgba(var(--r), 0.04) 6px 12px), rgba(0, 0, 0, 0.4);
  border: 1px solid rgba(var(--r), 0.6);
  border-radius: 0;
}

.gear-card[class*="rarity-"] .gear-card-icon {
  border-width: 2px;
  box-shadow: none;
}

/* Dashed price divider above the coin figure. */
.shop-gear-card .card-price-badge {
  background: none;
  border: 0;
  border-top: 1px dashed rgba(var(--r), 0.55);
  border-radius: 0;
  box-shadow: none;
  text-shadow: none;
  align-self: stretch;
  margin-top: 2px;
  padding-top: 4px;
}

.shop-gear-card .card-price-badge.cannot-afford {
  border-top-color: rgba(var(--c-danger), 0.6);
}

/* Legendary and ultimate: the frame breathes (brightness only, so nothing is clipped) and a soft
   sheen sweeps across the card. Both are decoration, switched off under reduced motion. */
@keyframes cx-border-pulse {
  50% { filter: brightness(1.45); }
}

@keyframes cx-sheen {
  0%, 55% { background-position: 150% 0; }
  100% { background-position: -50% 0; }
}

:is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card).rarity-legendary:not(.controller-focused)::before {
  animation: cx-border-pulse 3s ease-in-out infinite;
}

:is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card).rarity-ultimate:not(.controller-focused)::before {
  animation: cx-border-pulse 2.5s ease-in-out infinite;
}

:is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card).rarity-legendary:not(.controller-focused):not(.gear-outer-glitched)::after,
:is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card).rarity-ultimate:not(.controller-focused):not(.gear-outer-glitched)::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(105deg, transparent 40%, rgba(var(--r), 0.22) 50%, transparent 60%) no-repeat;
  background-size: 250% 100%;
  background-position: 150% 0;
  animation: cx-sheen 4.5s ease-in-out infinite;
}


/* Reduced motion: the selectors repeat the :not() chains above so they out-rank the animating rules. */
@media (prefers-reduced-motion: reduce) {
  :is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card).rarity-legendary:not(.controller-focused)::before,
  :is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card).rarity-ultimate:not(.controller-focused)::before,
  :is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card).rarity-legendary:not(.controller-focused):not(.gear-outer-glitched)::after,
  :is(.shop-gear-card, .shop-card, .gear-compare-card, .swap-equipped-card, .gamble-fan-card, .gear-card-card, .cx-card, .upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card).rarity-ultimate:not(.controller-focused):not(.gear-outer-glitched)::after {
    animation: none;
  }
}

/* 22. Cards, Phase 3b: level-up, weapon, wager and overclock families --------------------------------------
   .upgrade-card (weapon drop, major choice), .choice-card, .weapon-grid-card, .weapon-tree-milestone-card,
   .modifier-card (Round Wager) and .overclock-card join the section 21 card. The registry lists, the --r
   rarity mapping, the base variables, the geometry reset, the pulses and reduced motion are the section 21
   rules (their :is() lists now include these classes). Below: what each family needs on top.
   --r is the family's own colour as an R, G, B channel: the milestone tier (weapon grid, milestone and
   choice cards, set by cxHexToChannels in js/), the wager modifier rarity, the overclock upgrade colour; the
   upgrade card falls back to the primary accent (premium: secondary; weapon drop: secondary).
   Pulses and sheen are decoration and switch off under reduced motion; the reveal / slam / pump animations
   are cinematics and keep running (see css/33). Selection animations no longer animate box-shadow (clipped):
   they flash filter: brightness / saturate instead. */
@property --oc-flash {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}

:is(#cx-boost, .overlay) :is(.upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .overclock-card, .survivor-card, .char-roster-card, .difficulty-threat-card) {
  background: var(--bg);
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

/* The focused card keeps its lift; the kit variable swap is the frame. (The lifting cards cannot use the
   section 12 neutraliser, which pins transform: none.) */
:is(.upgrade-card, .choice-card, .weapon-grid-card, .weapon-tree-milestone-card, .modifier-card, .survivor-card, .char-roster-card, .difficulty-threat-card).controller-focused:not(.selected):not(.power-up):not(.rejected):not(.fizzle),
.overclock-card.controller-focused-card {
  outline: none !important;
  box-shadow: var(--cx-ring, none) !important;
}

/* upgrade card / choice card: primary accent by default, secondary for premium and the weapon drop. */
.upgrade-card {
  --r: var(--c-primary);
  --bw: 1.5px;
  --bd: rgba(var(--r), 0.7);
}

.upgrade-card.premium,
#weapon-drop-screen .upgrade-card:not([class*="rarity-"]) {
  --r: var(--c-secondary);
}

#major-choice-screen .choice-card,
#major-choice-screen .upgrade-card {
  --bw: 2px;
  --bd: rgb(var(--r));
}

:where(body:not(.gamepad-active)) :is(.upgrade-card, .choice-card):not(.selected):not(.rejected):not(.power-up):hover {
  --bd: rgb(var(--r));
  --bg: linear-gradient(165deg, rgba(var(--r), 0.26), rgba(var(--r), 0.06) 60%, transparent), rgba(18, 14, 36, 0.96);
}

#major-choice-screen .card-icon {
  background: repeating-linear-gradient(135deg, rgba(var(--r), 0.14) 0 6px, rgba(var(--r), 0.04) 6px 12px), rgba(0, 0, 0, 0.45);
  border: 1px solid rgba(var(--r), 0.6);
  border-radius: 0;
}

#major-choice-screen .card-icon img {
  border-radius: 0;
}

#major-choice-screen .card-milestone-tag {
  color: rgb(var(--r));
}

/* weapon grid card: the full-bleed art covers the frame, so the frame and the focus edge sit above it. */
.weapon-grid-card {
  --bw: 1.5px;
  --bd: rgba(var(--r), 0.6);
}

.weapon-grid-card::before {
  z-index: 4;
}

.weapon-grid-card.controller-focused::after {
  z-index: 5;
}

:where(body:not(.gamepad-active)) .weapon-grid-card:not(.locked):hover {
  --bd: rgb(var(--r));
  --bw: 2px;
}

.weapon-grid-card.locked {
  --r: var(--c-ink);
  --bd: rgba(var(--r), 0.16);
  --bw: 1px;
  --bg: rgba(14, 11, 25, 0.7);
}

/* milestone card: the progress fill is a --bg layer (the old ::before bar), the category line a tag strip. */
.weapon-tree-milestone-card {
  --cut: var(--cut-sm);
  --p: var(--milestone-progress-percent, 0%);
  --bd: rgba(var(--r), 0.55);
  --bg: linear-gradient(90deg, rgba(var(--r), 0.26), transparent) 0 0 / var(--p) 100% no-repeat, rgba(18, 14, 34, 0.92);
}

.weapon-tree-milestone-card.active {
  --bd: rgb(var(--r));
  --bg: linear-gradient(90deg, rgba(var(--r), 0.36), transparent) 0 0 / var(--p) 100% no-repeat, rgba(22, 17, 44, 0.94);
}

.weapon-tree-milestone-card.in-progress {
  --bg: linear-gradient(90deg, transparent calc(var(--p) - 2px), rgb(var(--r)) calc(var(--p) - 2px) var(--p), transparent var(--p)), linear-gradient(90deg, rgba(var(--r), 0.3), transparent) 0 0 / var(--p) 100% no-repeat, rgba(22, 17, 44, 0.9);
}

.weapon-tree-milestone-card.locked {
  --bd: rgba(var(--r), 0.3);
}

:where(body:not(.gamepad-active)) .weapon-tree-milestone-card:hover {
  --bd: rgb(var(--c-gold));
}

.weapon-tree-milestone-card .card-category-tag {
  align-self: flex-start;
  padding: 2px 10px 2px 6px;
  background: rgb(var(--r));
  color: rgb(var(--c-bg));
  clip-path: polygon(0 0, 100% 0, calc(100% - 6px) 100%, 0 100%);
}

/* wager card: tier colour frame, wash in the fill, ultra rare is a gradient frame, anomalous is cyan. */
.modifier-card {
  --r: var(--c-slate);
  --bw: 1.5px;
  --bd: rgb(var(--r));
  --bg: linear-gradient(160deg, rgba(var(--r), 0.14), transparent 62%), rgba(6, 10, 24, 0.94);
}

.modifier-card.rarity-anomalous,
.modifier-card[data-rarity="ANOMALOUS"] {
  --r: var(--c-rarity-anomalous);
  --bw: 2px;
  --bd: rgb(var(--r));
  --bg: repeating-linear-gradient(0deg, transparent 0 2px, rgba(var(--r), 0.05) 2px 4px), linear-gradient(175deg, rgba(20, 8, 30, 0.95), rgba(6, 10, 24, 0.96));
}

.modifier-card.modifier-card-ultra-rare {
  --bw: 2px;
  --bd: linear-gradient(135deg, rgb(var(--c-sky)), rgb(var(--c-primary)) 50%, rgb(var(--c-secondary)));
}

:where(body:not(.gamepad-active)) .modifier-card:hover {
  --bg: linear-gradient(160deg, rgba(var(--r), 0.26), rgba(var(--r), 0.05) 62%, transparent), rgba(10, 14, 30, 0.96);
}

.modifier-card.revealed:is(.rarity-anomalous, .modifier-card-ultra-rare, [data-rarity="LEGENDARY"], [data-rarity="CHAOS"]):not(.controller-focused):not(.selected-slam)::before {
  animation: cx-border-pulse 3s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .modifier-card.revealed:is(.rarity-anomalous, .modifier-card-ultra-rare, [data-rarity="LEGENDARY"], [data-rarity="CHAOS"]):not(.controller-focused):not(.selected-slam)::before {
    animation: none;
  }
}

/* overclock card: the upgrade's colour as the frame; the pump is a colour burst in the fill. */
.overclock-card {
  --bw: 2px;
  --bd: rgb(var(--r));
  --bg: radial-gradient(circle at center, rgba(var(--r), var(--oc-flash)) 10%, transparent 78%), linear-gradient(180deg, rgba(var(--r), 0.12), transparent 55%), rgba(15, 23, 42, 0.82);
}

/* 23. Phase 3c: survivor / roster card and difficulty threat card ----------------------------------------
   .survivor-card and .char-roster-card are ONE element (js/character-select.js emits both classes), the
   character-select roster; .difficulty-threat-card is the difficulty screen's card. Both join the registry.
   Their old ::after underlines (active / hover) are --bg layers here, so ::after belongs to the kit focus
   frame. ACTIVE (the selected survivor / tier) and gamepad FOCUS are different states that can sit on
   different cards at once: active = a 2px coloured frame, a tinted fill and the underline; focus = the kit
   variable swap (sky frame, brighter tint) plus the white inner frame, which active never draws.
   No animation is added here, so there is nothing to switch off under reduced motion. */
/* --r is set per card by js/character-select.js from the survivor's glow colour; sky is only the fallback. */
.survivor-card,
.char-roster-card {
  --cut: 6px;
  --r: var(--c-sky);
  --bw: 1.5px;
  --bd: rgba(var(--c-ink), 0.14);
  --bg: rgba(22, 18, 38, 0.92);
}

:where(body:not(.gamepad-active)) :is(.survivor-card, .char-roster-card):not(.locked):hover {
  --bd: rgba(var(--r), 0.8);
  --bg: linear-gradient(180deg, rgba(var(--r), 0.14), rgba(var(--r), 0.03)), rgba(22, 18, 38, 0.95);
}

:is(.survivor-card, .char-roster-card).active {
  --bw: 2px;
  --bd: rgb(var(--r));
  --bg: linear-gradient(rgb(var(--r)), rgb(var(--r))) 50% calc(100% - 4px) / 60% 2px no-repeat, linear-gradient(180deg, rgba(var(--r), 0.2), rgba(var(--r), 0.06)), rgba(22, 18, 38, 0.95);
}

/* focus on the active card keeps the underline (the kit focus --bg is !important) */
:is(.survivor-card, .char-roster-card).active.controller-focused {
  --bg: linear-gradient(rgb(var(--c-focus)), rgb(var(--c-focus))) 50% calc(100% - 4px) / 60% 2px no-repeat, rgba(var(--c-focus), 0.18) !important;
}

/* locked survivor: grey hazard stripes on top of the existing opacity + grayscale (css/18) */
:is(.survivor-card, .char-roster-card).locked {
  --r: var(--c-ink);
  --bd: rgba(var(--c-ink), 0.14);
  --bg: repeating-linear-gradient(-45deg, rgba(var(--c-ink), 0.06) 0 6px, transparent 6px 12px), rgba(22, 18, 38, 0.92);
}

:is(.survivor-card, .char-roster-card).locked.active {
  --bw: 2px;
  --bd: rgba(var(--c-ink), 0.6);
}

/* Focus on a LOCKED survivor: css/18 greys the whole card (grayscale + 50% opacity), which also washed out
   the sky focus frame, so a controller player could not see focus moving across locked survivors. The card
   itself is restored while focused and only its contents stay greyed and dimmed. */
:is(.survivor-card, .char-roster-card).locked.controller-focused {
  opacity: 1;
  filter: none;
}

:is(.survivor-card, .char-roster-card).locked.controller-focused > * {
  opacity: 0.5;
  filter: grayscale(1);
}

/* difficulty threat card: --r is the tier (css/19). Underline: dim at rest, full when active, longer on hover. */
.difficulty-threat-card {
  --bw: 1.5px;
  --ul: rgba(var(--r), 0.35);
  --bd: rgba(var(--r), 0.4);
  --bg: linear-gradient(var(--ul), var(--ul)) 50% calc(100% - 4px) / 60% 2px no-repeat, radial-gradient(circle at 50% 0%, rgba(var(--r), 0.1), rgba(255, 255, 255, 0.015) 100%), rgba(13, 10, 25, 0.94);
}

.difficulty-threat-card.active {
  --bw: 2px;
  --ul: rgb(var(--r));
  --bd: rgb(var(--r));
  --bg: linear-gradient(var(--ul), var(--ul)) 50% calc(100% - 4px) / 60% 3px no-repeat, radial-gradient(circle at 50% 0%, rgba(var(--r), 0.22), rgba(var(--r), 0.05) 100%), rgba(13, 10, 25, 0.95);
}

:where(body:not(.gamepad-active)) .difficulty-threat-card:not(.difficulty-card--locked):hover {
  --ul: rgb(var(--r));
  --bd: rgb(var(--r));
  --bg: linear-gradient(var(--ul), var(--ul)) 50% calc(100% - 4px) / 84% 4px no-repeat, radial-gradient(circle at 50% 0%, rgba(var(--r), 0.2), rgba(var(--r), 0.04) 100%), rgba(18, 14, 36, 0.96);
}

.difficulty-threat-card.active.controller-focused {
  --bg: linear-gradient(rgb(var(--c-focus)), rgb(var(--c-focus))) 50% calc(100% - 4px) / 60% 3px no-repeat, rgba(var(--c-focus), 0.18) !important;
}

.difficulty-threat-card.difficulty-card--locked {
  --r: var(--c-ink);
  --ul: transparent;
  --bd: rgba(var(--c-ink), 0.1);
  --bg: rgba(13, 10, 25, 0.9);
}


/* 24. Inner surfaces (Phase 4) ----------------------------------------------------------------------
   Panels, rows, boxes and pills INSIDE an already-chamfered window. Unlike .cut, these keep their own
   real border: many vary it per instance (rarity, tag type, version, hover), which a --bd variable could
   not follow. Mechanism:
     * clip-path cuts the top-left and bottom-right corners (--cx-ic: 12px panels, 8px rows, 4px pills);
     * ::before (top-left) and ::after (bottom-right) are zero-height strips laid along each cut, whose
       border is `inherit`ed from the element, so the diagonal stroke always matches the element's current
       border colour, width and style (none for borderless boxes, which then draw nothing);
     * the radius is zeroed at id-level specificity, beating inline styles and class !important.
   Measured before adding (2026-10-06, running game): none of these had a ::before/::after of their own
   except .char-hero-weapon-card (borderless, so its own ::before is left alone, see below), none had an
   absolutely positioned child escaping it (so position: relative is safe), and none had a child poking
   outside its box except .mmo-slot's controller badge, which is why the equipment slots are squared
   instead of cut. --cx-ebw must equal the element's border width for the strips to sit exactly on the cut. */
:is(
  .shop-equip-panel, .shop-weapons-panel, #shop-stats-display, #shop-left-col, #shop-right-col, .passive-tree-layout, .char-hero-details,
  .char-hero-canvas-wrap, .su-body, .su-detail-panel, .instructions-sidebar,
  .instructions-detail-panel, .game-over-card-section, .game-over-hero-card, .credits-ai-card,
  .credits-spotlight-card, .gamble-card-back, .setting-card-row, .ach-grandmaster-item,
  .ach-standalone-row, .ach-family-row, .changelog-version-card, .game-over-stat-box-stacked, .game-over-loadout-section,
  .game-over-records-highlight-card, .game-over-points-reward-card, .game-over-run-badges,
  #shop-stats-list > div, .milestone-title-card, .tree-preview-choice-card, .weapon-drop-banner,
  .game-over-lifetime-row, .game-over-hero-ship-wrap, .char-hero-stat-meters, .char-hero-weapon-card,
  .su-detail-icon-wrap, .difficulty-survivor-badge, .gear-refactor-empower-box, .gear-refactor-header, .gear-refactor-affix-row, .gear-refactor-pool-item, .passive-tree-panel, .passive-tree-sidebar-toggle, .tree-node-badge, .passive-tree-nodes-pill, .passive-tree-gp-hint, #tutorial-badge,
  #tutorial-media-placeholder, .game-over-econ-pill, .credits-playtester-chip, .weapon-tag-pill, .milestone-progress-pill, .weapon-tag-badge, .weapon-metric-pill, .path-badge, .threat-badge-pill, .game-over-badge-pill,
  .weapon-grid-preview-badge,
  .weapon-grid-kbd, .difficulty-survivor-archetype, .changelog-badge-pill, .ach-sidebar-count, .credits-hud, .credits-hud-chip, .ach-stat-box, .ach-stat-panel, .ach-stat-icon, .ach-bestiary-row, .game-over-enemy-kill-row, .instructions-preview-frame) {
  --cx-ic: 8px;
  --cx-ebw: 1px;
  position: relative;
  clip-path: polygon(var(--cx-ic) 0, 100% 0, 100% calc(100% - var(--cx-ic)), calc(100% - var(--cx-ic)) 100%, 0 100%, 0 var(--cx-ic));
}

:is(
  .shop-equip-panel, .shop-weapons-panel, #shop-stats-display, #shop-left-col, #shop-right-col, .passive-tree-layout, .char-hero-details,
  .char-hero-canvas-wrap, .su-body, .su-detail-panel, .instructions-sidebar,
  .instructions-detail-panel, .game-over-card-section, .game-over-hero-card, .credits-ai-card,
  .credits-spotlight-card, .gamble-card-back, .ach-stat-panel, .instructions-preview-frame) {
  --cx-ic: 12px;
}

:is(
  .game-over-econ-pill, .credits-playtester-chip, .weapon-tag-pill, .milestone-progress-pill, .weapon-tag-badge, .weapon-metric-pill, .path-badge, .threat-badge-pill, .game-over-badge-pill, .weapon-grid-preview-badge, .weapon-grid-kbd,
  .difficulty-survivor-archetype, .changelog-badge-pill, .ach-sidebar-count, .credits-hud-chip, .ach-stat-icon) {
  --cx-ic: 4px;
}

.credits-spotlight-card,
.gamble-card-back {
  --cx-ebw: 2px;
}

/* Achievements Stats tab panels and the instructions preview frame use a 1.5px border. The preview frame
   carries the border and fill for its canvas (js/instructions-panel.js). */
.ach-stat-box,
.ach-stat-panel,
.instructions-preview-frame {
  --cx-ebw: 1.5px;
}

.instructions-preview-frame {
  border: 1.5px solid rgba(168, 85, 247, 0.4);
  background: #0a0814;
}

:is(#cx-boost, .overlay) :is(
  .shop-equip-panel, .shop-weapons-panel, #shop-stats-display, #shop-left-col, #shop-right-col, .passive-tree-layout, .char-hero-details,
  .char-hero-canvas-wrap, .su-body, .su-detail-panel, .instructions-sidebar,
  .instructions-detail-panel, .game-over-card-section, .game-over-hero-card, .credits-ai-card,
  .credits-spotlight-card, .gamble-card-back, .setting-card-row, .ach-grandmaster-item,
  .ach-standalone-row, .ach-family-row, .changelog-version-card, .game-over-stat-box-stacked, .game-over-loadout-section,
  .game-over-records-highlight-card, .game-over-points-reward-card, .game-over-run-badges,
  #shop-stats-list > div, .milestone-title-card, .tree-preview-choice-card, .weapon-drop-banner,
  .game-over-lifetime-row, .game-over-hero-ship-wrap, .char-hero-stat-meters, .char-hero-weapon-card,
  .su-detail-icon-wrap, .difficulty-survivor-badge, .gear-refactor-empower-box, .gear-refactor-header, .gear-refactor-affix-row, .gear-refactor-pool-item, .passive-tree-panel, .passive-tree-sidebar-toggle, .tree-node-badge, .passive-tree-nodes-pill, .passive-tree-gp-hint, #tutorial-badge,
  #tutorial-media-placeholder, .game-over-econ-pill, .credits-playtester-chip, .weapon-tag-pill, .milestone-progress-pill, .weapon-tag-badge, .weapon-metric-pill, .path-badge, .threat-badge-pill, .game-over-badge-pill,
  .weapon-grid-preview-badge,
  .weapon-grid-kbd, .difficulty-survivor-archetype, .changelog-badge-pill, .ach-sidebar-count, .credits-hud, .credits-hud-chip, .ach-stat-box, .ach-stat-panel, .ach-stat-icon, .ach-bestiary-row, .game-over-enemy-kill-row, .instructions-preview-frame) {
  border-radius: 0 !important;
}

/* the diagonal strokes: a strip of length cut x sqrt2, rotated -45deg about one end so its border lies just
   inside the cut. Positions are in the padding box, hence the --cx-ebw offsets. */
:is(
  .shop-equip-panel, .shop-weapons-panel, #shop-stats-display, #shop-left-col, #shop-right-col, .passive-tree-layout, .char-hero-details,
  .char-hero-canvas-wrap, .su-body, .su-detail-panel, .instructions-sidebar,
  .instructions-detail-panel, .game-over-card-section, .game-over-hero-card, .credits-ai-card,
  .credits-spotlight-card, .gamble-card-back, .setting-card-row, .ach-grandmaster-item,
  .ach-standalone-row, .ach-family-row, .changelog-version-card, .game-over-stat-box-stacked, .game-over-loadout-section,
  .game-over-records-highlight-card, .game-over-points-reward-card, .game-over-run-badges,
  #shop-stats-list > div, .milestone-title-card, .tree-preview-choice-card, .weapon-drop-banner,
  .game-over-lifetime-row, .game-over-hero-ship-wrap, .char-hero-stat-meters, .su-detail-icon-wrap,
  .difficulty-survivor-badge, .gear-refactor-empower-box, .gear-refactor-header, .gear-refactor-affix-row, .gear-refactor-pool-item, .passive-tree-panel, .passive-tree-sidebar-toggle, .tree-node-badge, .passive-tree-nodes-pill, .passive-tree-gp-hint, #tutorial-badge, #tutorial-media-placeholder,
  .game-over-econ-pill, .credits-playtester-chip, .weapon-tag-pill, .milestone-progress-pill, .weapon-tag-badge, .weapon-metric-pill, .path-badge, .threat-badge-pill, .game-over-badge-pill, .weapon-grid-preview-badge, .weapon-grid-kbd,
  .difficulty-survivor-archetype, .changelog-badge-pill, .ach-sidebar-count, .credits-hud, .credits-hud-chip, .ach-stat-box, .ach-stat-panel, .ach-stat-icon, .ach-bestiary-row, .game-over-enemy-kill-row, .instructions-preview-frame):not(.gear-outer-glitched)::before,
:is(
  .shop-equip-panel, .shop-weapons-panel, #shop-stats-display, #shop-left-col, #shop-right-col, .passive-tree-layout, .char-hero-details,
  .char-hero-canvas-wrap, .su-body, .su-detail-panel, .instructions-sidebar,
  .instructions-detail-panel, .game-over-card-section, .game-over-hero-card, .credits-ai-card,
  .credits-spotlight-card, .gamble-card-back, .setting-card-row, .ach-grandmaster-item,
  .ach-standalone-row, .ach-family-row, .changelog-version-card, .game-over-stat-box-stacked, .game-over-loadout-section,
  .game-over-records-highlight-card, .game-over-points-reward-card, .game-over-run-badges,
  #shop-stats-list > div, .milestone-title-card, .tree-preview-choice-card, .weapon-drop-banner,
  .game-over-lifetime-row, .game-over-hero-ship-wrap, .char-hero-stat-meters, .char-hero-weapon-card,
  .su-detail-icon-wrap, .difficulty-survivor-badge, .gear-refactor-empower-box, .gear-refactor-header, .gear-refactor-affix-row, .gear-refactor-pool-item, .passive-tree-panel, .passive-tree-sidebar-toggle, .tree-node-badge, .passive-tree-nodes-pill, .passive-tree-gp-hint, #tutorial-badge,
  #tutorial-media-placeholder, .game-over-econ-pill, .credits-playtester-chip, .weapon-tag-pill, .milestone-progress-pill, .weapon-tag-badge, .weapon-metric-pill, .path-badge, .threat-badge-pill, .game-over-badge-pill,
  .weapon-grid-preview-badge,
  .weapon-grid-kbd, .difficulty-survivor-archetype, .changelog-badge-pill, .ach-sidebar-count, .credits-hud, .credits-hud-chip, .ach-stat-box, .ach-stat-panel, .ach-stat-icon, .ach-bestiary-row, .game-over-enemy-kill-row, .instructions-preview-frame)::after {
  content: "";
  position: absolute;
  width: calc(var(--cx-ic) * 1.4142 + 1px);
  height: 0;
  border: 0;
  pointer-events: none;
}

:is(
  .shop-equip-panel, .shop-weapons-panel, #shop-stats-display, #shop-left-col, #shop-right-col, .passive-tree-layout, .char-hero-details,
  .char-hero-canvas-wrap, .su-body, .su-detail-panel, .instructions-sidebar,
  .instructions-detail-panel, .game-over-card-section, .game-over-hero-card, .credits-ai-card,
  .credits-spotlight-card, .gamble-card-back, .setting-card-row, .ach-grandmaster-item,
  .ach-standalone-row, .ach-family-row, .changelog-version-card, .game-over-stat-box-stacked, .game-over-loadout-section,
  .game-over-records-highlight-card, .game-over-points-reward-card, .game-over-run-badges,
  #shop-stats-list > div, .milestone-title-card, .tree-preview-choice-card, .weapon-drop-banner,
  .game-over-lifetime-row, .game-over-hero-ship-wrap, .char-hero-stat-meters, .su-detail-icon-wrap,
  .difficulty-survivor-badge, .gear-refactor-empower-box, .gear-refactor-header, .gear-refactor-affix-row, .gear-refactor-pool-item, .passive-tree-panel, .passive-tree-sidebar-toggle, .tree-node-badge, .passive-tree-nodes-pill, .passive-tree-gp-hint, #tutorial-badge, #tutorial-media-placeholder,
  .game-over-econ-pill, .credits-playtester-chip, .weapon-tag-pill, .milestone-progress-pill, .weapon-tag-badge, .weapon-metric-pill, .path-badge, .threat-badge-pill, .game-over-badge-pill, .weapon-grid-preview-badge, .weapon-grid-kbd,
  .difficulty-survivor-archetype, .changelog-badge-pill, .ach-sidebar-count, .credits-hud, .credits-hud-chip, .ach-stat-box, .ach-stat-panel, .ach-stat-icon, .ach-bestiary-row, .game-over-enemy-kill-row, .instructions-preview-frame):not(.gear-outer-glitched)::before {
  left: calc(-1 * var(--cx-ebw));
  top: calc(var(--cx-ic) - var(--cx-ebw));
  border-top: inherit;
  transform-origin: 0 0;
  transform: rotate(-45deg);
}

:is(
  .shop-equip-panel, .shop-weapons-panel, #shop-stats-display, #shop-left-col, #shop-right-col, .passive-tree-layout, .char-hero-details,
  .char-hero-canvas-wrap, .su-body, .su-detail-panel, .instructions-sidebar,
  .instructions-detail-panel, .game-over-card-section, .game-over-hero-card, .credits-ai-card,
  .credits-spotlight-card, .gamble-card-back, .setting-card-row, .ach-grandmaster-item,
  .ach-standalone-row, .ach-family-row, .changelog-version-card, .game-over-stat-box-stacked, .game-over-loadout-section,
  .game-over-records-highlight-card, .game-over-points-reward-card, .game-over-run-badges,
  #shop-stats-list > div, .milestone-title-card, .tree-preview-choice-card, .weapon-drop-banner,
  .game-over-lifetime-row, .game-over-hero-ship-wrap, .char-hero-stat-meters, .char-hero-weapon-card,
  .su-detail-icon-wrap, .difficulty-survivor-badge, .gear-refactor-empower-box, .gear-refactor-header, .gear-refactor-affix-row, .gear-refactor-pool-item, .passive-tree-panel, .passive-tree-sidebar-toggle, .tree-node-badge, .passive-tree-nodes-pill, .passive-tree-gp-hint, #tutorial-badge,
  #tutorial-media-placeholder, .game-over-econ-pill, .credits-playtester-chip, .weapon-tag-pill, .milestone-progress-pill, .weapon-tag-badge, .weapon-metric-pill, .path-badge, .threat-badge-pill, .game-over-badge-pill,
  .weapon-grid-preview-badge,
  .weapon-grid-kbd, .difficulty-survivor-archetype, .changelog-badge-pill, .ach-sidebar-count, .credits-hud, .credits-hud-chip, .ach-stat-box, .ach-stat-panel, .ach-stat-icon, .ach-bestiary-row, .game-over-enemy-kill-row, .instructions-preview-frame)::after {
  left: calc(100% + var(--cx-ebw) - var(--cx-ic));
  bottom: calc(-1 * var(--cx-ebw));
  border-bottom: inherit;
  transform-origin: 0 100%;
  transform: rotate(-45deg);
}

/* The credits control bar is position: fixed (centred with translateX), so it takes the chamfer
   from the lists above but keeps its own positioning. */
:is(#cx-boost, .overlay) #credits-hud {
  position: fixed;
}

/* Equipment slots: the controller "A" badge deliberately overhangs the slot by ~4px, which a clip would cut
   off, so the slots are squared rather than chamfered. Their images match (the HUD action bar keeps its
   6px from css/05 until the HUD pass). */
:is(#cx-boost, .overlay) :is(.mmo-slot),
:is(#cx-boost, .overlay) :is(.mmo-slot) img {
  border-radius: 2px !important;
}

/* The difficulty lock overlay is position: absolute (inset 2px inside its card), so it cannot join the
   lists above, which set position: relative. It is borderless, so it only needs the clip, sized to sit
   just inside the card's cut. It reads the card's inherited --cut, so it follows the short-screen shrink. */
.threat-lock-overlay {
  --cx-lo: calc(var(--cut, 14px) - 1px);
  clip-path: polygon(var(--cx-lo) 0, 100% 0, 100% calc(100% - var(--cx-lo)), calc(100% - var(--cx-lo)) 100%, 0 100%, 0 var(--cx-lo));
}

:is(#cx-boost, .overlay) .threat-lock-overlay {
  border-radius: 0 !important;
}

/* 25. Window kicker line (Phase 4) -------------------------------------------------------------------
   The small spaced-out label above a window title ("SYS // SUSPENDED" on Pause). Written as a
   data-kicker attribute on the existing title and drawn by ::before, so no title markup was restructured
   and each title keeps its own colour or gradient: the kicker resets the gradient-text properties for
   itself. Not added where a badge already sits above the title (Weapon Acquired, Major Choice, Round
   Wager), where the header is a bar of tabs and buttons (Bazaar, Overclock), or where the screen has
   its own eyebrow already (Settings, Achievements, the Tutorial popup's TUTORIAL label). The Changelog
   title sits in a flex row with the version badge, so a block ::before would land beside it, not above. */
[data-kicker]::before {
  content: attr(data-kicker);
  display: block;
  margin-bottom: 6px;
  font: 500 0.64rem/1 var(--font-display);
  letter-spacing: 0.3em;
  text-transform: uppercase;
  text-shadow: none;
  color: rgba(var(--acc), 0.9);
  -webkit-text-fill-color: rgba(var(--acc), 0.9);
  background: none;
  filter: none;
}

/* 26. Floating pieces outside the scaling layer (Phase 5) ---------------------------------------------
   The achievement toast, the round-complete banner's wager badges, the control-hint chips and the gear /
   weapon tooltip shared by the action bar and the pause screen's gear column float outside #ui-container
   and scale with `zoom` (css/02-scaling.css), which scales these px cuts with them. They use the section
   24 mechanism (clip-path plus inherited-border diagonal strips) but keep their own positioning: the toast
   and the tooltip are position: fixed. Ids give the rules enough weight over css/17, css/20 and the
   tooltip's inline border-radius (js/weapons-registry.js). The clip removes outer glows, so the toast and
   the wager badges carry an inset glow instead. */
#achievement-toast,
#round-complete-banner :is(.round-wager-payout-badge, .round-wager-voided-badge, .round-wager-payout-tag, .round-wager-voided-tag),
#control-hints-panel .control-hint-chip,
#mmo-action-bar-tooltip {
  --cx-ic: 8px;
  --cx-ebw: 1px;
  border-radius: 0 !important;
  clip-path: polygon(var(--cx-ic) 0, 100% 0, 100% calc(100% - var(--cx-ic)), calc(100% - var(--cx-ic)) 100%, 0 100%, 0 var(--cx-ic));
}

#round-complete-banner :is(.round-wager-payout-badge, .round-wager-voided-badge, .round-wager-payout-tag, .round-wager-voided-tag),
#control-hints-panel .control-hint-chip {
  position: relative;
}

#achievement-toast {
  --cx-ic: 11px;
  --cx-ebw: 1.5px;
  border-color: rgba(var(--c-gold), 0.7);
  box-shadow: inset 0 0 22px rgba(var(--c-gold), 0.14), inset 0 1px 0 rgba(255, 255, 255, 0.08);
}

#round-complete-banner :is(.round-wager-payout-badge, .round-wager-voided-badge) {
  --cx-ic: 7px;
  --cx-ebw: 1.5px;
}

#round-complete-banner .round-wager-payout-badge {
  box-shadow: inset 0 0 12px rgba(var(--c-gold), 0.2);
  animation-name: cx-wager-payout-pulse;
}

#round-complete-banner .round-wager-voided-badge {
  box-shadow: inset 0 0 12px rgba(var(--c-danger), 0.25);
}

#round-complete-banner :is(.round-wager-payout-tag, .round-wager-voided-tag) {
  --cx-ic: 4px;
}

#control-hints-panel .control-hint-chip {
  --cx-ic: 5px;
}

/* the old pulse grew an outer glow, which the clip would hide; this one breathes the inset glow instead */
@keyframes cx-wager-payout-pulse {
  0% { transform: scale(1); filter: brightness(1); box-shadow: inset 0 0 12px rgba(var(--c-gold), 0.2); }
  100% { transform: scale(1.02); filter: brightness(1.15); box-shadow: inset 0 0 18px rgba(var(--c-gold), 0.38); }
}

/* Diagonal strokes, as in section 24. A glitched gear tooltip uses both pseudos for its own glow and band
   (css/14-gear-card.css), so it keeps those instead. */
:is(#achievement-toast,
  #round-complete-banner :is(.round-wager-payout-badge, .round-wager-voided-badge, .round-wager-payout-tag, .round-wager-voided-tag),
  #control-hints-panel .control-hint-chip,
  #mmo-action-bar-tooltip:not(.gear-outer-glitched))::before,
:is(#achievement-toast,
  #round-complete-banner :is(.round-wager-payout-badge, .round-wager-voided-badge, .round-wager-payout-tag, .round-wager-voided-tag),
  #control-hints-panel .control-hint-chip,
  #mmo-action-bar-tooltip:not(.gear-outer-glitched))::after {
  content: "";
  position: absolute;
  width: calc(var(--cx-ic) * 1.4142 + 1px);
  height: 0;
  border: 0;
  pointer-events: none;
}

:is(#achievement-toast,
  #round-complete-banner :is(.round-wager-payout-badge, .round-wager-voided-badge, .round-wager-payout-tag, .round-wager-voided-tag),
  #control-hints-panel .control-hint-chip,
  #mmo-action-bar-tooltip:not(.gear-outer-glitched))::before {
  left: calc(-1 * var(--cx-ebw));
  top: calc(var(--cx-ic) - var(--cx-ebw));
  border-top: inherit;
  transform-origin: 0 0;
  transform: rotate(-45deg);
}

:is(#achievement-toast,
  #round-complete-banner :is(.round-wager-payout-badge, .round-wager-voided-badge, .round-wager-payout-tag, .round-wager-voided-tag),
  #control-hints-panel .control-hint-chip,
  #mmo-action-bar-tooltip:not(.gear-outer-glitched))::after {
  left: calc(100% + var(--cx-ebw) - var(--cx-ic));
  bottom: calc(-1 * var(--cx-ebw));
  border-bottom: inherit;
  transform-origin: 0 100%;
  transform: rotate(-45deg);
}

/* 27. HUD primitives (HUD overhaul "Edge Telemetry", Phase 0) -----------------------------------------
   Building blocks for the in-game HUD (plans/HUD_EDGE_TELEMETRY_PLAN.md). Unused until Phase 1.
   Readouts sit directly on the arena with no panel behind them, so legibility comes from the text-shadow
   stack in .cx-tele rather than a background. Numbers use Space Grotesk with tabular figures (the
   mockups used JetBrains Mono, but the game only loads Outfit and Space Grotesk, and the Android and
   Steam builds may run offline); tabular-nums keeps a ticking timer or HP value from jittering. Every
   fill is a transform or a custom property, so per-frame updates stay compositor-friendly. */

/* Corner brackets: two L-shapes on ::before / ::after, top-left + bottom-left by default.
   .cx-brk--right mirrors them to the right edge. */
.cx-brk {
  --brk: 14px;
  --brk-w: 2px;
  --brk-c: rgba(226, 232, 240, 0.45);
  position: relative;
}

.cx-brk::before,
.cx-brk::after {
  content: "";
  position: absolute;
  left: 0;
  width: var(--brk);
  height: var(--brk);
  border: 0 solid var(--brk-c);
  border-left-width: var(--brk-w);
  pointer-events: none;
}

.cx-brk::before {
  top: 0;
  border-top-width: var(--brk-w);
}

.cx-brk::after {
  bottom: 0;
  border-bottom-width: var(--brk-w);
}

.cx-brk--right::before,
.cx-brk--right::after {
  left: auto;
  right: 0;
  border-left-width: 0;
  border-right-width: var(--brk-w);
}

/* Telemetry text: tabular figures plus a shadow stack that holds contrast over bright effects. */
.cx-tele {
  font-family: var(--font-display);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  text-shadow: 0 1px 0 #000, 0 0 2px #000, 0 0 12px rgba(0, 0, 0, 0.9);
}

.cx-tele-kicker {
  font: 500 11px/1 var(--font-display);
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: rgba(226, 232, 240, 0.62);
  text-shadow: 0 1px 0 #000, 0 0 8px rgba(0, 0, 0, 0.9);
}

/* Segmented, slanted bar. --pct (0-1) drives the fill by scaleX; --seg-gap sets the segment pitch.
   An optional .cx-seg__shield child is positioned by --shield-start / --shield-len (0-1), which JS
   changes only when the values change (through _hudCache), not every frame. */
.cx-seg {
  --pct: 1;
  --seg-h: 14px;
  --seg-skew: -12deg;
  --seg-gap: 35px;
  --seg-fill: #f43f5e;
  --seg-track: rgba(244, 63, 94, 0.14);
  position: relative;
  height: var(--seg-h);
  background: var(--seg-track);
  transform: skewX(var(--seg-skew));
  overflow: hidden;
}

.cx-seg::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--seg-fill);
  box-shadow: 0 0 12px var(--seg-fill);
  transform: scaleX(var(--pct));
  transform-origin: left center;
}

.cx-seg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(90deg, transparent 0 calc(var(--seg-gap) - 2px), rgba(5, 4, 9, 0.95) calc(var(--seg-gap) - 2px) var(--seg-gap));
  pointer-events: none;
}

.cx-seg__shield {
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(var(--shield-start, 0) * 100%);
  width: calc(var(--shield-len, 0) * 100%);
  background: rgba(103, 232, 249, 0.85);
  z-index: 1;
}

/* HUD slot: full-bleed art, tier/rarity border (--slot-c), top-down cooldown sweep (scaleY on
   .cx-slot__cd, the same compositor-only approach the current action bar uses), level label below. */
.cx-slot {
  --slot: 58px;
  --slot-c: rgba(148, 163, 184, 0.22);
  position: relative;
  width: var(--slot);
  height: var(--slot);
  box-sizing: border-box;
  overflow: hidden;
  background: rgba(5, 4, 9, 0.7);
  border: 1.5px solid var(--slot-c);
}

.cx-slot > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.cx-slot__cd {
  position: absolute;
  inset: 0;
  background: rgba(5, 4, 9, 0.72);
  transform: scaleY(var(--cd, 0));
  transform-origin: top center;
  pointer-events: none;
}

.cx-slot.is-empty > img {
  filter: grayscale(1);
  opacity: 0.25;
}

.cx-slot__lvl {
  font: 700 11px/1 var(--font-display);
  font-variant-numeric: tabular-nums;
  text-align: center;
  color: var(--slot-c);
  text-shadow: 0 1px 0 #000;
}

/* Contrast outline (HUD overhaul Phase 7). The HUD readouts have no panel, so over a bright effect (a
   flamethrower or explosion flash behind a corner) their colours lose contrast. Instead of a backing
   box, every HUD glyph gets a tight dark outline: four 1px offset shadows plus a soft halo. The text
   is then judged against its own outline, not the arena, so it reads over anything without blocking
   more of the screen than the letters themselves. Against the #000 outline every value colour clears
   WCAG 4.5:1 with room to spare (white 21:1, gold 12:1, wave pink 7.6:1, low-HP 8:1, kicker grey 8.8:1).
   Bars get the same idea as a 1px dark ring (--hud-bar-ring). */
:root {
  --hud-outline: 1px 1px 0 #000, -1px 1px 0 #000, 1px -1px 0 #000, -1px -1px 0 #000, 0 0 3px #000, 0 0 8px rgba(0, 0, 0, 0.75);
  --hud-bar-ring: 0 0 0 1px rgba(5, 4, 9, 0.9);
}
/* ==========================================
   MMORPG Action Bar & HUD System
   ========================================== */

/* XP line (HUD overhaul "Edge Telemetry", Phase 3): "LV n" + a 3px line + "62%", the last row of the
   bottom-left vitals (#hud-vitals, styled below). It used to be a full-bleed 8px bar along the bottom
   edge, outside #ui-container; it now lives inside the layer and scales with it (so it left the
   zoom lists in css/02-scaling.css). The "| x / y XP" part of the caption is kept in the markup
   (#xp-current / #xp-target are still written) but hidden. */
.mmo-xp-bar {
  display: flex;
  align-items: center;
  gap: 10px;
}

.mmo-xp-bar .xp-bar-text {
  flex: none;
  color: #c084fc;
  font: 700 11px/1 var(--font-display);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.06em;
  white-space: nowrap;
  text-shadow: 0 1px 0 #000, 0 0 8px rgba(0, 0, 0, 0.9);
  transform-origin: left center;
  pointer-events: none;
}

.mmo-xp-bar .xp-bar-detail {
  display: none;
}

.hud-xp-track {
  position: relative;
  flex: 1;
  height: 3px;
  background: rgba(168, 85, 247, 0.2);
  overflow: hidden;
}

/* No width write: updateHud() (js/init.js) sets transform: scaleX() on this, through _hudCache.
   XP lands constantly in combat, so a width write here meant layout most frames while fighting. */
.mmo-xp-bar #xp-bar-fill {
  position: absolute;
  inset: 0;
  background: #c084fc;
  box-shadow: 0 0 6px rgba(192, 132, 252, 0.6);
  transform: scaleX(0);
  transform-origin: left center;
}

.hud-xp-pct {
  flex: none;
  min-width: 4ch;
  text-align: right;
  color: rgba(216, 180, 254, 0.75);
  font: 600 11px/1 var(--font-display);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 0 #000, 0 0 8px rgba(0, 0, 0, 0.9);
}

/* In-Game Level-Up XP Bar Surge (Desktop & Mobile) */
@keyframes xpBarLevelUpSurge {
  0% {
    filter: brightness(1) drop-shadow(0 0 0 rgba(var(--c-primary), 0));
    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.5);
  }
  25% {
    filter: brightness(2.2) drop-shadow(0 0 16px rgb(var(--c-sky)));
    box-shadow: 0 -4px 22px rgba(var(--c-sky), 0.95), 0 0 25px rgba(var(--c-primary), 0.9);
  }
  60% {
    filter: brightness(1.6) drop-shadow(0 0 10px rgb(var(--c-secondary)));
    box-shadow: 0 -3px 14px rgba(var(--c-secondary), 0.7);
  }
  100% {
    filter: brightness(1) drop-shadow(0 0 0 rgba(var(--c-primary), 0));
    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.5);
  }
}

@keyframes xpFillPulse {
  0% {
    background: linear-gradient(90deg, rgb(var(--c-primary)), #6b21a8);
    box-shadow: 0 0 10px rgba(var(--c-primary), 0.8);
  }
  30% {
    background: linear-gradient(90deg, rgb(var(--c-sky)), rgb(var(--c-secondary)));
    box-shadow: 0 0 25px rgba(var(--c-sky), 1), 0 0 15px rgba(var(--c-secondary), 0.9);
  }
  100% {
    background: linear-gradient(90deg, rgb(var(--c-primary)), #6b21a8);
    box-shadow: 0 0 10px rgba(var(--c-primary), 0.8);
  }
}

@keyframes xpTextPop {
  0% { transform: scale(1); }
  30% { transform: scale(1.22); }
  100% { transform: scale(1); }
}

.mmo-xp-bar.xp-bar-surge {
  animation: xpBarLevelUpSurge 0.65s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

/* The XP line has no box of its own any more, so the surge's box-shadow would draw a stray
   rectangle around the row: keep only its brightness flash there. */
#hud-vitals .mmo-xp-bar.xp-bar-surge {
  box-shadow: none;
  animation-name: hudXpRowSurge;
}

@keyframes hudXpRowSurge {
  0% { filter: brightness(1); }
  25% { filter: brightness(2.2) drop-shadow(0 0 8px rgb(var(--c-sky))); }
  100% { filter: brightness(1); }
}

.mmo-xp-bar #xp-bar-fill.xp-bar-surge {
  animation: xpFillPulse 0.65s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

.mmo-xp-bar.xp-bar-surge .xp-bar-text {
  animation: xpTextPop 0.65s cubic-bezier(0.16, 1, 0.3, 1) forwards;
  color: #fff;
  text-shadow: 0 0 12px rgb(var(--c-sky)), 0 1px 4px rgba(0, 0, 0, 0.9);
}

/* Mobile HUD XP Surge */
@keyframes mobileXpSurge {
  0% {
    box-shadow: 0 0 8px rgba(var(--c-primary), 0.7);
    filter: brightness(1);
  }
  30% {
    box-shadow: 0 0 18px rgba(var(--c-sky), 1), 0 0 28px rgba(var(--c-primary), 0.95);
    filter: brightness(2.1);
  }
  100% {
    box-shadow: 0 0 8px rgba(var(--c-primary), 0.7);
    filter: brightness(1);
  }
}

@keyframes mobileXpTextPop {
  0% { transform: translate(-50%, -50%) scale(1); }
  30% { transform: translate(-50%, -50%) scale(1.25); }
  100% { transform: translate(-50%, -50%) scale(1); }
}

.mobile-xp-track.xp-bar-surge {
  border-color: rgb(var(--c-sky)) !important;
  box-shadow: 0 0 16px rgba(var(--c-sky), 0.85), 0 0 24px rgba(var(--c-primary), 0.65) !important;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.mobile-xp-fill.xp-bar-surge {
  animation: mobileXpSurge 0.65s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

.mobile-xp-track.xp-bar-surge .mobile-bar-text {
  animation: mobileXpTextPop 0.65s cubic-bezier(0.16, 1, 0.3, 1) forwards;
  color: #fff;
  text-shadow: 0 0 10px rgb(var(--c-sky)), 0 1px 3px rgba(0, 0, 0, 1);
}

@media (prefers-reduced-motion: reduce) {
  /* Reduced-motion animation suppression removed: preserve vibrant XP surge glow */
  .mmo-xp-bar.xp-bar-surge,
  .mmo-xp-bar #xp-bar-fill.xp-bar-surge,
  .mmo-xp-bar.xp-bar-surge .xp-bar-text,
  .mobile-xp-track.xp-bar-surge,
  .mobile-xp-fill.xp-bar-surge,
  .mobile-xp-track.xp-bar-surge .mobile-bar-text {
    box-shadow: 0 0 10px rgba(var(--c-sky), 0.5) !important;
  }
}

/* HISTORICAL NOTE -- nine rules were removed from here.
   They divided --ui-global-scale back out of every rem-sized element inside
   #mmo-action-bar (slot icons, cooldown text, level/empower badges, health
   orb text, buff icons/timers). That existed solely to undo the old
   `html { font-size: calc(16px * var(--ui-global-scale)) }` root multiplier,
   which double-counted against this bar's own scale() transform and made 4K
   action-bar text render at 4x instead of 2x.

   Both halves of that problem are gone. The root font-size is flat again,
   and #ui-container -- this bar's ancestor -- is a scaled layer that sets
   --ui-global-scale to 1 for its whole subtree, so those rules had become
   `calc(Nrem / 1)`: no-ops in every reachable state (when the var is not 1
   the layer is active and overrides it to 1; when the layer is inactive the
   var is already 1). Deleted rather than left in place, because a rule that
   looks like it compensates for something is worse than no rule at all once
   the thing it compensated for no longer exists. */

/* The action bar layer, the weapon strip, the gear bracket and the bottom-left vitals (HUD overhaul
   "Edge Telemetry", Phases 3-4) live in css/05b-hud-telemetry.css, after css/05-hud-mobile.css, so
   they come after the shared .mmo-slot / .mmo-slot-icon base rules that js/shop.js also reuses. */
/* ==========================================
   Mobile-Only Gameplay HUD
   Replaces the desktop MMO-style top bar/action bar/xp bar entirely on
   touch devices (js/init.js's setMobileUIActive()). Deliberately has no
   enclosing panel/background behind the whole cluster -- each piece (bars,
   text, pause button) floats directly over gameplay, using text-shadow/box-
   shadow alone for legibility, rather than a glass-panel container.
   ========================================== */
.mobile-hud {
  display: none; /* toggled to "block" by setMobileUIActive() (js/init.js) */
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 10;
}

/* ===== Edge Telemetry, mobile (HUD overhaul Phase 5) ===================================================
   plans/HUD_EDGE_TELEMETRY_PLAN.md section 2.2, the "B · Mobile" artboard. Four corner blocks and a
   strip, no panels: readouts sit on the arena with a dark text-shadow, the same as desktop.
   - Top-left bracket (186px): timer / wave / threat on one line, HP number / max / +shield and level,
     a 6px slanted HP bar (shield segment after the HP), a 2px XP line, buff chips.
   - Top-centre: the wager / glitch-hunt tracker only, one line (css/03-base.css). The boss line stays
     in the arena on mobile (decision 1).
   - Top-right bracket: coins, score, five 22px gear thumbnails; then the 44x44 pause button.
   - Bottom-centre: the display-only weapon strip (decision 2), 30px tiles.
   - Bottom-right: the dash button (css/05-hud-mobile.css, end of file).
   Every corner block is offset by the --safe-* insets js/viewport-manager.js publishes.
   Fills are transforms written by updateMobileHud() (js/init.js) through _hudCache. */
.mobile-hud-topleft {
  --brk: 10px;
  --brk-w: 2px;
  position: absolute;
  top: calc(8px + var(--safe-top, 0px));
  left: calc(14px + var(--safe-left, 0px));
  width: 186px;
  box-sizing: border-box;
  padding: 6px 9px 7px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.mobile-tele-row {
  display: flex;
  align-items: baseline;
  gap: 7px;
  min-width: 0;
  white-space: nowrap;
}

.mobile-wave-sub {
  flex: none;
  color: #fff;
  font: 700 21px/0.9 var(--font-display);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 0 #000, 0 0 2px #000, 0 0 10px rgba(0, 0, 0, 0.9);
}

/* CLEAR: n / ENTER SHOP (updateMobileHud() toggles .is-status). */
.mobile-wave-sub.is-status {
  color: #fde68a;
  font-size: 12px;
  letter-spacing: 0.1em;
}

.mobile-wave-label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: #f472b6;
  font: 700 11px/1 var(--font-display);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 0 #000, 0 0 8px rgba(0, 0, 0, 0.9);
}

/* The old "WAVE n • TIER" separator, no longer drawn: wave and tier are separate readouts now. */
.mobile-wave-divider {
  display: none;
}

/* Threat tier: colour comes from updateMobileHud() (inline, the tier colour). */
.mobile-diff-val {
  margin-left: 7px;
  font: 600 8px/1 var(--font-display);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.mobile-hp-row {
  display: flex;
  align-items: baseline;
  gap: 5px;
  font-family: var(--font-display);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 0 #000, 0 0 8px rgba(0, 0, 0, 0.9);
}

.mobile-hp-now {
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
}

.mobile-hp-max {
  color: rgba(255, 255, 255, 0.6);
  font-size: 9px;
  font-weight: 600;
}

.mobile-hp-shield {
  color: #67e8f9;
  font-size: 9px;
  font-weight: 700;
}

.mobile-hp-shield:empty {
  display: none;
}

.mobile-lv {
  margin-left: auto;
  color: #c084fc;
  font-size: 8px;
  font-weight: 700;
}

/* HP bar: 6px, slanted, 1px gaps every 17px (::after). */
.mobile-bar-track {
  position: relative;
  width: 100%;
  height: 6px;
  background: rgba(244, 63, 94, 0.14);
  overflow: hidden;
  transform: skewX(-12deg);
  box-sizing: border-box;
}

.mobile-hp-track::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  background: repeating-linear-gradient(90deg, transparent 0 16px, rgba(5, 4, 9, 0.95) 16px 17px);
  pointer-events: none;
}

/* XP line: 2px, straight. */
.mobile-xp-track {
  height: 2px;
  background: rgba(168, 85, 247, 0.2);
  transform: none;
}

.mobile-bar-fill {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: scaleX(0);
  transform-origin: left center;
}

/* The old in-bar "HP 28 / 100" and "LVL 1 | x / y XP" captions. Still written (cheap, cached) but
   replaced by .mobile-hp-row; kept above the fills (z-index 5) if ever shown again. */
.mobile-bar-text {
  display: none;
  position: absolute;
  z-index: 5;
}

.mobile-overshield-fill {
  background: rgba(103, 232, 249, 0.85);
  pointer-events: none;
  z-index: 2;
}

.mobile-hp-fill {
  background: #f43f5e;
  box-shadow: 0 0 8px rgba(244, 63, 94, 0.7);
  z-index: 1;
}

.mobile-xp-fill {
  background: #c084fc;
  z-index: 1;
}

/* Low HP (<= 30%), toggled by updateMobileHud(). */
.mobile-hud-topleft.hp-low {
  --brk-c: rgba(251, 113, 133, 0.75);
}

.mobile-hud-topleft.hp-low .mobile-hp-now {
  color: #ff8a9a; /* same 5.2:1-over-scrim low-HP colour as desktop */
}

.mobile-hud-topleft.hp-low .mobile-hp-fill {
  background: #ef4444;
  animation: hudHpLowPulse 0.8s ease-in-out infinite alternate;
}

@media (prefers-reduced-motion: reduce) {
  .mobile-hud-topleft.hp-low .mobile-hp-fill {
    animation: none;
  }
}

/* Buff chips -- same buff list as the desktop chips (updateMobileBuffBarUI() / _renderBuffBar(),
   js/player.js): 9px icon + 8px label, 1.5px colour underline. */
.mobile-buff-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.mobile-buff-bar:empty {
  display: none;
}

.mobile-buff-icon {
  --buff-c: rgb(var(--c-violet));
  position: relative;
  display: flex;
  align-items: center;
  gap: 3px;
  height: 13px;
  padding: 1px 4px 1px 3px;
  background: rgba(5, 4, 9, 0.6);
  border-bottom: 1.5px solid var(--buff-c);
  overflow: hidden;
  box-sizing: border-box;
  animation: buffIconPopIn 0.15s ease-out;
}

.mobile-buff-icon[data-buff-key="overclock"],
.mobile-buff-icon[data-buff-key="last_chance_cooldown"] {
  --buff-c: #fbbf24;
}

.mobile-buff-icon[data-buff-key="shield_powerup"],
.mobile-buff-icon[data-buff-key="decoy_shield"] {
  --buff-c: #67e8f9;
}

.mobile-buff-icon[data-buff-key="double_xp"] {
  --buff-c: #c084fc;
}

.mobile-buff-icon[data-buff-key="speed_buff"] {
  --buff-c: #34d399;
}

.mobile-buff-icon[data-buff-key^="resonant_"],
.mobile-buff-icon[data-buff-key^="storm_"],
.mobile-buff-icon[data-buff-key="flow_streak"] {
  --buff-c: #f472b6;
}

.mobile-buff-icon img {
  width: 9px !important;
  height: 9px !important;
  object-fit: cover;
}

.mobile-buff-icon-glyph {
  position: relative;
  z-index: 2;
  flex: none;
  width: 9px;
  height: 9px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.mobile-buff-icon-glyph svg {
  width: 9px;
  height: 9px;
  display: block;
}

.mobile-buff-icon-glyph img {
  width: 9px;
  height: 9px;
  object-fit: cover;
}

.mobile-buff-fill {
  position: absolute;
  inset: 0;
  background: rgba(5, 4, 9, 0.5);
  transform-origin: top;
  pointer-events: none;
  will-change: transform;
}

.mobile-buff-stack-badge,
.mobile-buff-timer-text {
  position: relative;
  z-index: 2;
  color: #fff;
  font: 700 8px/1 var(--font-display);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 0 #000;
  pointer-events: none;
}

.mobile-buff-stack-badge {
  display: none; /* toggled to flex when a stack count is present */
  color: #fde68a;
}

.mobile-buff-stack-badge::before {
  content: "\00D7";
}

.mobile-buff-timer-text:empty {
  display: none;
}

/* Top-right: coins / score / gear bracket, then the pause button. */
.mobile-hud-topright {
  position: absolute;
  top: calc(10px + var(--safe-top, 0px));
  right: calc(14px + var(--safe-right, 0px));
  display: flex;
  align-items: flex-start;
  gap: 10px;
}

.mobile-score-block {
  --brk: 10px;
  --brk-w: 2px;
  position: relative;
  padding: 8px 11px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
}

.mobile-gold-row {
  display: flex;
  align-items: center;
  gap: 5px;
  color: #fbbf24;
  font: 700 16px/1 var(--font-display);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 0 #000, 0 0 10px rgba(0, 0, 0, 0.9);
}

.mobile-gold-icon {
  display: flex;
}

.mobile-score-label {
  display: none;
}

.mobile-score {
  color: #d8b4fe;
  font: 700 11px/1 var(--font-display);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 0 #000, 0 0 10px rgba(0, 0, 0, 0.9);
}

.mobile-gear-row {
  display: flex;
  gap: 3px;
}

.mobile-gear-row:empty {
  display: none;
}

.mobile-gear-thumb {
  width: 22px;
  height: 22px;
  overflow: hidden;
  background: rgba(5, 4, 9, 0.7);
  border-bottom: 2px solid var(--rarity-c, rgba(148, 163, 184, 0.22));
  box-sizing: border-box;
}

.mobile-gear-thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.mobile-gear-thumb.is-empty img {
  filter: grayscale(1);
  opacity: 0.25;
}

/* 44x44 touch target, chamfered like the menu buttons. */
.mobile-pause-btn {
  width: 44px;
  height: 44px;
  margin-top: 4px;
  padding: 0;
  border: 1.5px solid rgba(226, 232, 240, 0.4);
  border-radius: 0;
  background: rgba(5, 4, 9, 0.65);
  color: #e2e8f0;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  pointer-events: auto; /* the rest of .mobile-hud is click-through */
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
}

.mobile-pause-icon {
  width: 16px;
  height: 16px;
  object-fit: contain;
  pointer-events: none; /* clicks land on the button itself, not the icon */
}

/* Display-only weapon strip, bottom-centre between the joystick and dash thumbs. Its tiles are built
   by Player.updateInventoryUI() (js/player.js); the cooldown sweep shares updateWeaponCooldownsUI(). */
.mobile-weapons-strip {
  position: absolute;
  left: 50%;
  bottom: calc(6px + var(--safe-bottom, 0px));
  transform: translateX(-50%);
  display: flex;
  align-items: flex-end;
  gap: 3px;
  pointer-events: none;
}

.mobile-weapon-tile {
  --tier-c: rgba(255, 255, 255, 0.35);
  width: 30px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}

.mobile-weapon-art {
  position: relative;
  width: 30px;
  height: 30px;
  overflow: hidden;
  background: rgba(5, 4, 9, 0.7);
  border: 1px solid var(--tier-c);
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
}

.mobile-weapon-art img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.mobile-weapon-cd {
  position: absolute;
  inset: 0;
  background: rgba(5, 4, 9, 0.72);
  transform: scaleY(0);
  transform-origin: top;
}

.mobile-weapon-lvl {
  min-height: 7px;
  color: var(--tier-c);
  font: 700 7px/1 var(--font-display);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 0 #000;
}

.mobile-weapon-tile.is-empty .mobile-weapon-art {
  border-style: dashed;
  border-color: rgba(255, 255, 255, 0.12);
  background: rgba(5, 4, 9, 0.45);
}

.mobile-weapon-tile.is-locked .mobile-weapon-art {
  border-style: solid;
  border-color: rgba(148, 163, 184, 0.2);
  color: rgba(148, 163, 184, 0.45);
}

.mobile-weapon-tile.is-locked .mobile-weapon-lvl {
  color: rgba(148, 163, 184, 0.45);
}

/* Touchscreen-only Fullscreen button (index.html #mobile-fullscreen-btn,
   shown/hidden by js/init.js's updateFullscreenButtonVisibility()). Fixed to
   the viewport rather than nested in #mobile-hud, so it's available
   everywhere touch+non-fullscreen applies -- start screen, menus, and
   gameplay alike -- not only while the mobile gameplay HUD is showing.
   Anchored bottom-left, the one screen corner #mobile-hud/#mobile-controls
   never claim (top corners = HUD, bottom-right = dash button), with a
   z-index above #mobile-controls-wrapper's 350 so a tap on it is never
   swallowed by the joystick's touch zone underneath. */
.mobile-fullscreen-btn {
  display: none; /* toggled to flex by updateFullscreenButtonVisibility() */
  position: fixed;
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  left: calc(16px + env(safe-area-inset-left, 0px));
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, 0.2);
  background: rgba(20, 16, 36, 0.55);
  color: #fff;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  pointer-events: auto;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
  padding: 0;
  z-index: 600;
}

.mobile-fullscreen-btn svg {
  width: 20px;
  height: 20px;
  pointer-events: none; /* clicks land on the button itself, not the icon */
}

.mmo-left-section {
  position: absolute;
  left: 16px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
}

.mmo-right-section {
  position: absolute;
  right: 16px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Slot Grid */
.mmo-slot-grid {
  display: flex;
  gap: 8px;
  align-items: center;
}

/* Base UI Slot (Weapons/Gear) */
.mmo-slot {
  /* Fixed px, deliberately NOT calc()-scaled against --ui-global-scale --
     this lives inside #mmo-action-bar, whose own transform: scale() already
     includes --ui-global-scale (see .mmo-action-bar above), so it's already
     magnified as a whole. Scaling it again here would compound with that
     ancestor transform (e.g. 2x * 2x = 4x at 4K) and overflow the action
     bar's own (also-transformed) height. The .gear-arpg-layout override
     further down is a different, non-nested layout and handles its own
     scaling via container query units (min(100cqw, 100cqh)). */
  width: 44px;
  height: 44px;
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.45);
  border: 1.5px solid rgba(255, 255, 255, 0.12);
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.6);
  overflow: hidden;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  box-sizing: border-box;
}

.mmo-slot:not(.empty) {
  background: rgba(20, 16, 36, 0.85);
  border: 1.5px solid rgba(var(--c-primary), 0.4);
  box-shadow: 0 0 8px rgba(var(--c-primary), 0.15), inset 0 0 6px rgba(var(--c-primary), 0.1);
  cursor: help;
}

:where(body:not(.gamepad-active)) .mmo-slot:not(.empty):hover {
  border-color: rgb(var(--c-primary));
  box-shadow: 0 0 12px rgba(var(--c-primary), 0.45), inset 0 0 8px rgba(var(--c-primary), 0.15);
}

.mmo-slot img {
  width: 100% !important;
  height: 100% !important;
  border-radius: 6px;
  object-fit: cover;
}

.mmo-slot.empty {
  border-style: dashed;
  border-color: rgba(255, 255, 255, 0.08);
}

.mmo-slot-icon {
  font-size: 1.25rem;
  user-select: none;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Cooldown overlay for Weapon Slots.
   Animated via `transform: scaleY()` (compositor-only) instead of `height`
   (forces layout) -- Chrome's own DevTools flagged this exact element with
   "Compositing failed: Unsupported CSS property: height", confirming every
   cooldown-timer update was forced through full main-thread layout+paint
   instead of the cheap GPU compositor path. `height: 100%` + `scaleY(0..1)`
   with `transform-origin: bottom` reproduces the exact same visual (overlay
   grows/shrinks from the bottom edge) since the element is already
   bottom-anchored (`bottom: 0`). */
.mmo-slot-cooldown-overlay {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100%;
  transform: scaleY(0);
  transform-origin: bottom;
  background: rgba(8, 6, 15, 0.75);
  pointer-events: none;
  transition: transform 0.1s linear;
  will-change: transform;
}

.mmo-slot-cooldown-text {
  position: absolute;
  font-size: 0.65rem;
  font-weight: 800;
  color: rgb(var(--c-amber));
  text-shadow: 0 1px 3px rgba(0, 0, 0, 1);
  font-family: var(--font-display);
  pointer-events: none;
}

.mmo-slot-level-badge {
  position: absolute;
  top: 1px;
  right: 2px;
  font-size: 0.5rem;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.6);
  background: rgba(0, 0, 0, 0.7);
  padding: 0px 3px;
  border-radius: 2px;
  font-family: var(--font-display);
  pointer-events: none;
}

/* Empower Affordability Glow & Empower Level Badges (+X) */
.empower-affordable-glow {
  border-color: rgb(var(--c-cyan)) !important;
  box-shadow: 0 0 10px rgba(var(--c-cyan), 0.6), inset 0 0 8px rgba(var(--c-cyan), 0.35) !important;
}
/* Cheap, smooth pulse: the static box-shadow above stays put; only a
   compositor-friendly opacity-fading inner rim animates. Animating box-shadow
   (the old pulse-empower-glow) forced a per-frame repaint of every affordable
   gear slot and read as low-framerate -- exactly the paint-heavy failure mode
   /canvas2d-render-optimization warns about (transform/opacity only). */
.empower-affordable-glow::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(circle, rgba(var(--c-cyan), 0) 55%, rgba(var(--c-cyan), 0.6) 100%);
  pointer-events: none;
  z-index: 1;
  animation: empower-glow-pulse 1.6s ease-in-out infinite;
}
@keyframes empower-glow-pulse {
  0%, 100% { opacity: 0.25; }
  50% { opacity: 1; }
}

/* Item-level badge (top-left) on the Bazaar gear slots. Plain rem -- these
   slots sit outside #mmo-action-bar's transform and must scale once via the
   root font-size alone, matching the reasoning Test 203 documents. */
.mmo-slot-ilvl-badge {
  position: absolute;
  top: 2px;
  left: 2px;
  font-size: 0.5rem;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.85);
  background: rgba(0, 0, 0, 0.72);
  padding: 0 3px;
  border-radius: 3px;
  font-family: monospace;
  line-height: 1.3;
  pointer-events: none;
  z-index: 2;
}

.mmo-slot-empower-badge {
  position: absolute;
  bottom: 2px;
  right: 2px;
  font-size: 0.55rem;
  font-weight: bold;
  background: linear-gradient(135deg, #06b6d4, rgb(var(--c-info)));
  color: #ffffff;
  padding: 1px 4px;
  border-radius: 4px;
  box-shadow: 0 0 6px rgba(6, 182, 212, 0.7);
  letter-spacing: 0.05em;
  pointer-events: none;
  z-index: 2;
  font-family: monospace;
}

/* Dash button (HUD overhaul Phase 5): an 80px square hit area with four amber corner brackets, an
   inner 64px square, the bolt, charge pips and a "DASH" label underneath. Base rules (hit area,
   touch handling, cooldown overlay) are in css/17-dev-panel.css; this restyles them. The two-id
   selector also outranks #mobile-dash-btn:active's background there. */
#mobile-controls #mobile-dash-btn {
  right: calc(100px + var(--safe-right, 0px));
  bottom: calc(60px + var(--safe-bottom, 0px));
  border: 0;
  border-radius: 0;
  overflow: visible;
  box-shadow: none;
  background:
    linear-gradient(#fbbf24, #fbbf24) left top / 14px 2px no-repeat,
    linear-gradient(#fbbf24, #fbbf24) left top / 2px 14px no-repeat,
    linear-gradient(#fbbf24, #fbbf24) right top / 14px 2px no-repeat,
    linear-gradient(#fbbf24, #fbbf24) right top / 2px 14px no-repeat,
    linear-gradient(#fbbf24, #fbbf24) left bottom / 14px 2px no-repeat,
    linear-gradient(#fbbf24, #fbbf24) left bottom / 2px 14px no-repeat,
    linear-gradient(#fbbf24, #fbbf24) right bottom / 14px 2px no-repeat,
    linear-gradient(#fbbf24, #fbbf24) right bottom / 2px 14px no-repeat;
}

#mobile-controls #mobile-dash-btn::before {
  content: "";
  position: absolute;
  inset: 8px;
  background: rgba(251, 191, 36, 0.08);
  border: 1px solid rgba(251, 191, 36, 0.35);
  pointer-events: none;
}

#mobile-controls #mobile-dash-btn:active::before {
  background: rgba(251, 191, 36, 0.22);
}

#mobile-controls #mobile-dash-btn::after {
  content: "DASH";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -16px;
  text-align: center;
  color: #fbbf24;
  font: 600 8px/1 var(--font-display);
  letter-spacing: 0.3em;
  text-shadow: 0 1px 0 #000;
  pointer-events: none;
}

#mobile-controls #mobile-dash-btn .mobile-dash-icon svg {
  width: 26px;
  height: 26px;
  filter: none;
}

#mobile-controls #mobile-dash-btn .mobile-dash-cooldown-overlay {
  inset: 8px;
  width: auto;
  height: auto;
  background: rgba(5, 4, 9, 0.72);
}

#mobile-controls #mobile-dash-btn .mobile-dash-cooldown-text {
  top: 50%;
  bottom: auto;
  transform: translate(-50%, -50%);
  color: #fde68a;
  font: 700 12px/1 var(--font-display);
  font-variant-numeric: tabular-nums;
}

#mobile-controls #mobile-dash-btn .mobile-dash-charge-pips {
  top: auto;
  bottom: 14px;
  gap: 3px;
}

#mobile-controls #mobile-dash-btn .dash-charge-pip {
  width: 12px;
  height: 4px;
  border: 0;
  border-radius: 0;
  background: rgba(251, 191, 36, 0.22);
  box-shadow: none;
  transform: skewX(-20deg);
}

#mobile-controls #mobile-dash-btn .dash-charge-pip.filled {
  background: #fbbf24;
}

/* Controller-on-Android dash indicator (#mobile-gamepad-dash-indicator): sits at the end of the HP row
   in the top-left block, like the desktop HUD's dash readout, instead of a 60px twin of the touch
   button in its corner. An 11px bolt with the cooldown sweep over it, the seconds left while it
   recharges, and skewed pips when there is more than one charge. The base rule in
   css/17-dev-panel.css made it a fixed 60px circle in the bottom-right; reset here. */
#mobile-gamepad-dash-indicator.mobile-gamepad-dash-indicator {
  pointer-events: none; /* read-only, nobody taps it */
  position: relative;
  right: auto;
  bottom: auto;
  z-index: auto;
  width: auto;
  height: 13px;
  margin-left: 6px;
  align-items: center;
  gap: 3px;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  overflow: visible;
}

#mobile-gamepad-dash-indicator .mobile-dash-icon {
  position: relative;
  width: 12px;
  height: 12px;
}

#mobile-gamepad-dash-indicator .mobile-dash-icon svg {
  width: 11px;
  height: 11px;
  filter: drop-shadow(1px 1px 0 #000) drop-shadow(-1px -1px 0 #000);
}

#mobile-gamepad-dash-indicator .mobile-dash-cooldown-overlay {
  top: 0;
  bottom: auto;
  left: 0;
  width: 12px;
  height: 12px;
  background: rgba(5, 4, 9, 0.72);
}

#mobile-gamepad-dash-indicator .mobile-dash-cooldown-text {
  position: static;
  transform: none;
  color: #fde68a;
  font: 700 8px/1 var(--font-display);
  font-variant-numeric: tabular-nums;
}

#mobile-gamepad-dash-indicator .mobile-dash-cooldown-text:empty {
  display: none;
}

#mobile-gamepad-dash-indicator .mobile-dash-charge-pips {
  position: static;
  transform: none;
  gap: 2px;
}

#mobile-gamepad-dash-indicator .dash-charge-pip {
  width: 7px;
  height: 3px;
  border: 0;
  border-radius: 0;
  background: rgba(251, 191, 36, 0.22);
  box-shadow: none;
  transform: skewX(-20deg);
}

#mobile-gamepad-dash-indicator .dash-charge-pip.filled {
  background: #fbbf24;
}

/* Large touch screens (HUD overhaul follow-up, 2026-10-08). The mobile HUD is laid out in px for a
   ~412px-tall phone, so on an Android tablet (a Fire HD at 1280x800 CSS px, Lenovo / Samsung tabs)
   it sat at phone size in the corners of a much bigger screen. It now grows with the screen height,
   in steps, to roughly the footprint the desktop HUD has on a Steam Deck (also 1280x800): the
   top-left block goes from 186px to ~325px wide and the weapon tiles from 30px to ~52px (the Deck's are 58px) at 800px tall. Phones (412px and below) are
   unchanged. zoom (not transform) so each block's own offsets and the safe-area insets scale with
   it and it still lays out as a box; the joystick is left alone because js/init.js positions it at
   the touch point in screen px. */
:root {
  --mobile-hud-zoom: 1;
}

@media (min-height: 520px) {
  :root {
    --mobile-hud-zoom: 1.3;
  }
}

@media (min-height: 640px) {
  :root {
    --mobile-hud-zoom: 1.5;
  }
}

@media (min-height: 760px) {
  :root {
    --mobile-hud-zoom: 1.75;
  }
}

.mobile-hud-topleft,
.mobile-hud-topright,
.mobile-weapons-strip,
#mobile-controls #mobile-dash-btn,
#hud.mobile-active .wager-hud-tracker,
#hud.mobile-active .glitch-hunt-hud {
  zoom: var(--mobile-hud-zoom);
}
/* ==========================================
   Edge Telemetry HUD, desktop bottom row (HUD overhaul Phases 3-4)
   ==========================================
   plans/HUD_EDGE_TELEMETRY_PLAN.md. Its own module, after css/05-hud-mobile.css, because it restyles
   the shared .mmo-slot / .mmo-slot-icon / .mmo-buff-* classes for the in-game HUD only (scoped by
   #mmo-action-bar / #mmo-weapons-grid / #mmo-gear-grid / #hud-vitals), and those base rules, which
   js/shop.js reuses for the pause / shop / gear-swap slots, must stay the first rules of their name
   in style.css. The XP line's own rules stay in css/04-hud-action-bar.css next to its surge
   animation. */

/* Action Bar Container -- since the HUD overhaul Phase 4 (plans/HUD_EDGE_TELEMETRY_PLAN.md) an
   invisible bottom layer holding the weapon strip (bottom-centre) and the gear bracket (bottom-right).
   It stays one element because js/shop.js and js/weapons-registry.js query it.
   Scaling: on short windows the whole layer scales by --ui-scale about its bottom-centre. It is laid
   out at 100% / --ui-scale wide, so after the scale it spans the window exactly and a point x px
   from its left edge lands at x * --ui-scale on screen. That keeps the children in plain layer px
   (the same px #hud-vitals uses, which scales by the same factor from the bottom-left corner), so
   "clear of the vitals" is one constant below instead of a calc per window size.
   Only --ui-scale (the short-viewport factor): the large-display factor arrives from #ui-container's
   layer transform, and multiplying it in again here would double-count it. */
.mmo-action-bar {
  position: absolute;
  bottom: 0;
  left: 50%;
  width: calc(100% / var(--ui-scale, 1));
  height: 140px;
  transform: translateX(-50%) scale(var(--ui-scale, 1));
  transform-origin: center bottom;
  z-index: 50;
  box-sizing: border-box;
  pointer-events: none;
}

/* Weapon strip: six 58px tiles, bottom-centre. left never drops below 649px (the vitals' 448px plus
   a 12px gap plus half the 378px strip), so on narrow windows (Steam Deck, 1366x600) the strip
   slides right instead of sitting under the vitals. */
#mmo-action-bar .mmo-left-section {
  position: absolute;
  left: max(50%, 649px);
  top: auto;
  bottom: 24px;
  transform: translateX(-50%);
  pointer-events: auto;
}

#mmo-weapons-grid {
  gap: 6px;
  align-items: flex-start;
  padding-bottom: 16px; /* room for the level labels under the tiles */
}

#mmo-weapons-grid .mmo-slot {
  --tier-c: rgba(255, 255, 255, 0.35);
  width: 58px;
  height: 58px;
  border-radius: 0;
  background: rgba(5, 4, 9, 0.7);
  border: 1.5px solid var(--tier-c);
  box-shadow: none;
  overflow: visible; /* the level label sits under the tile; the art and overlay fill the box anyway */
}

:where(body:not(.gamepad-active)) #mmo-weapons-grid .mmo-slot:not(.empty):hover {
  border-color: var(--tier-c);
  box-shadow: 0 0 12px var(--tier-c);
}

#mmo-weapons-grid .mmo-slot-icon {
  position: absolute;
  inset: 0;
  overflow: hidden;
}

#mmo-weapons-grid .mmo-slot img {
  border-radius: 0;
}

/* Top-down sweep: the dark overlay shrinks towards the top as the weapon comes off cooldown. */
#mmo-weapons-grid .mmo-slot-cooldown-overlay {
  top: 0;
  bottom: auto;
  border-radius: 0;
  background: rgba(5, 4, 9, 0.72);
  transform-origin: top;
}

#mmo-weapons-grid .mmo-slot-cooldown-text {
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font: 700 14px/1 var(--font-display);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 2px #000, 0 0 6px rgba(0, 0, 0, 0.9);
}

#mmo-weapons-grid .mmo-slot-level-badge {
  top: calc(100% + 5px);
  right: auto;
  left: 50%;
  transform: translateX(-50%);
  padding: 0;
  background: none;
  border-radius: 0;
  color: var(--tier-c);
  font: 700 11px/1 var(--font-display);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  text-shadow: 0 1px 0 #000, 0 0 6px rgba(0, 0, 0, 0.9);
}

#mmo-weapons-grid .mmo-slot.empty {
  background: rgba(5, 4, 9, 0.45);
  border: 1.5px dashed rgba(255, 255, 255, 0.12);
}

/* Locked slot (js/player.js updateInventoryUI(): slot i opens at player level i * 5). */
#mmo-weapons-grid .mmo-slot.is-locked {
  border-style: solid;
  border-color: rgba(148, 163, 184, 0.22);
  color: rgba(148, 163, 184, 0.5);
  cursor: default;
}

#mmo-weapons-grid .mmo-slot.is-locked .mmo-slot-level-badge {
  color: rgba(148, 163, 184, 0.7);
}

/* Gear: bottom-right corner bracket with a "GEAR" kicker and five 46px tiles. updateGearUI()
   (js/player.js) writes the rarity colour as an inline border-color and glow; here only the bottom
   edge keeps it (a 2px rarity underline), the other three edges are a quiet frame. A glitched item
   keeps its .gear-outer-glitched box-shadow animation. Sits above the bottom-right control hints
   ("Pause" pill, css/17-dev-panel.css) rather than under it. */
#mmo-action-bar .mmo-right-section {
  --brk: 14px;
  --brk-w: 2px;
  position: absolute;
  top: auto;
  right: 28px;
  bottom: 48px;
  transform: none;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
  padding: 14px 18px;
  pointer-events: auto;
}

.hud-gear-kicker {
  line-height: 1;
}

#mmo-gear-grid {
  gap: 5px;
}

#mmo-gear-grid .mmo-slot {
  width: 46px;
  height: 46px;
  border-radius: 0;
  background: rgba(5, 4, 9, 0.7);
  border-style: solid;
  border-width: 1px 1px 2px;
  border-top-color: rgba(255, 255, 255, 0.14) !important;
  border-left-color: rgba(255, 255, 255, 0.14) !important;
  border-right-color: rgba(255, 255, 255, 0.14) !important;
}

#mmo-gear-grid .mmo-slot:not(.gear-outer-glitched) {
  box-shadow: none !important;
}

:where(body:not(.gamepad-active)) #mmo-gear-grid .mmo-slot:not(.empty):not(.gear-outer-glitched):hover {
  box-shadow: 0 0 10px rgba(255, 255, 255, 0.25) !important;
}

#mmo-gear-grid .mmo-slot img {
  border-radius: 0;
}

#mmo-gear-grid .mmo-slot.empty {
  background: rgba(5, 4, 9, 0.45);
}

/* ===== Bottom-left vitals (HUD overhaul "Edge Telemetry", Phase 3) =====================================
   plans/HUD_EDGE_TELEMETRY_PLAN.md. #hud-vitals replaces the centre health orb, the dash slot and the
   full-width XP bar: buff chips, then the HP number / max / +shield with the dash charge beside it,
   then a segmented, slanted HP bar with a shield segment, then the XP line. Desktop only (the mobile
   HUD hides it, like #mmo-action-bar). Inside #ui-container, so px values scale with the layer;
   --ui-scale covers short windows, the same factor #mmo-action-bar uses.
   Every per-frame value is a transform or a custom property written through _hudCache in
   js/init.js: --hp-frac / --os-frac / --os-start (0-1), the XP fill's scaleX, and .hp-low. */
.hud-vitals {
  --brk: 14px;
  --brk-w: 2px;
  position: absolute;
  left: 28px;
  bottom: 26px;
  z-index: 50;
  width: 420px;
  box-sizing: border-box;
  padding: 16px 18px 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  pointer-events: none;
  transform: scale(var(--ui-scale, 1));
  transform-origin: left bottom;
}

/* Buff chips: 16px icon + label (timer or stacks) on a dark chip with a 2px colour underline.
   _renderBuffBar() (js/player.js) builds them; the drain overlay (.mmo-buff-fill) dims the chip. */
#hud-vitals .mmo-buff-bar {
  position: static;
  margin: 0;
  flex-wrap: wrap;
  gap: 6px;
}

#hud-vitals .mmo-buff-bar:empty {
  display: none;
}

#hud-vitals .mmo-buff-icon {
  --buff-c: rgb(var(--c-violet));
  width: auto;
  height: 24px;
  padding: 0 8px 0 6px;
  gap: 6px;
  justify-content: flex-start;
  background: rgba(5, 4, 9, 0.6);
  border: 0;
  border-bottom: 2px solid var(--buff-c);
  border-radius: 0;
  box-shadow: none;
  overflow: hidden;
}

#hud-vitals .mmo-buff-icon[data-buff-key="overclock"],
#hud-vitals .mmo-buff-icon[data-buff-key="last_chance_cooldown"] {
  --buff-c: #fbbf24;
}

#hud-vitals .mmo-buff-icon[data-buff-key="shield_powerup"],
#hud-vitals .mmo-buff-icon[data-buff-key="decoy_shield"] {
  --buff-c: #67e8f9;
}

#hud-vitals .mmo-buff-icon[data-buff-key="double_xp"] {
  --buff-c: #c084fc;
}

#hud-vitals .mmo-buff-icon[data-buff-key="speed_buff"] {
  --buff-c: #34d399;
}

#hud-vitals .mmo-buff-icon[data-buff-key^="resonant_"],
#hud-vitals .mmo-buff-icon[data-buff-key^="storm_"],
#hud-vitals .mmo-buff-icon[data-buff-key="flow_streak"] {
  --buff-c: #f472b6;
}

#hud-vitals .mmo-buff-icon-glyph {
  position: relative;
  z-index: 2;
  flex: none;
  width: 16px;
  height: 16px;
}

#hud-vitals .mmo-buff-icon-glyph svg,
#hud-vitals .mmo-buff-icon-glyph img,
#hud-vitals .mmo-buff-icon img {
  width: 16px !important;
  height: 16px !important;
  border-radius: 0;
}

#hud-vitals .mmo-buff-fill {
  border-radius: 0;
  background: rgba(5, 4, 9, 0.5);
}

#hud-vitals .mmo-buff-stack-badge,
#hud-vitals .mmo-buff-timer-text {
  position: relative;
  inset: auto;
  z-index: 2;
  transform: none;
  min-width: 0;
  height: auto;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  color: #fff;
  font: 700 11px/1 var(--font-display);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 0 #000;
}

#hud-vitals .mmo-buff-stack-badge {
  color: #fde68a;
}

#hud-vitals .mmo-buff-stack-badge::before {
  content: "\00D7";
}

#hud-vitals .mmo-buff-timer-text:empty {
  display: none;
}

.hud-vitals-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
}

.hud-hp-readout {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-family: var(--font-display);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 0 #000, 0 0 2px #000, 0 0 12px rgba(0, 0, 0, 0.9);
}

.hud-hp-now {
  color: #fff;
  font-size: 40px;
  font-weight: 700;
  line-height: 0.9;
  transition: color 0.2s ease;
}

.hud-hp-max {
  color: rgba(255, 255, 255, 0.6);
  font-size: 15px;
  font-weight: 600;
}

#hud-vitals .hud-hp-shield {
  margin: 0;
  color: #67e8f9;
  font: 700 12px/1 var(--font-display);
  letter-spacing: 0;
}

/* Dash: the old slot, minus its tile -- an 18px bolt with the top-down cooldown sweep and seconds
   over it, and the charge pips beside it (pips only when maxDashCharges > 1, as before). */
#hud-vitals .dash-slot {
  width: auto;
  height: 26px;
  padding: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  overflow: visible;
  pointer-events: auto;
}

:where(body:not(.gamepad-active)) #hud-vitals .dash-slot:hover {
  border: 0;
  box-shadow: none;
}

#hud-vitals .dash-slot .mmo-slot-icon {
  flex: none;
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
}

#hud-vitals .dash-slot .mmo-slot-icon svg {
  width: 18px;
  height: 18px;
}

#hud-vitals .dash-slot .mmo-slot-cooldown-overlay {
  top: 0;
  bottom: auto;
  width: 26px;
  height: 26px;
  background: rgba(5, 4, 9, 0.72);
}

#hud-vitals .dash-slot .mmo-slot-cooldown-text {
  top: 0;
  left: 0;
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fde68a;
  font: 700 9px/1 var(--font-display);
  font-variant-numeric: tabular-nums;
}

#hud-vitals .mmo-dash-charge-pips {
  position: static;
  transform: none;
  gap: 4px;
}

#hud-vitals .dash-charge-pip {
  width: 14px;
  height: 6px;
  border: 0;
  border-radius: 0;
  background: rgba(251, 191, 36, 0.22);
  box-shadow: none;
  transform: skewX(-20deg);
}

#hud-vitals .dash-charge-pip.filled {
  background: #fbbf24;
  box-shadow: 0 0 6px rgba(251, 191, 36, 0.6);
}

/* Segmented, slanted HP bar (the old orb container). Fill = #health-orb-liquid scaled by --hp-frac;
   shield = #health-orb-overshield, a segment starting at --os-start and --os-frac long (it starts
   where HP ends, shifted back so it never runs past the end). ::after cuts the 2px gaps every 35px. */
#hud-vitals .hud-hp-bar {
  position: relative;
  left: auto;
  top: auto;
  z-index: auto;
  display: block;
  width: 100%;
  height: 14px;
  background: rgba(244, 63, 94, 0.14);
  border: 0;
  border-radius: 0;
  box-shadow: none;
  overflow: hidden;
  transform: skewX(-12deg);
}

#hud-vitals .hud-hp-bar::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  background: repeating-linear-gradient(90deg, transparent 0 33px, rgba(5, 4, 9, 0.95) 33px 35px);
  pointer-events: none;
}

#hud-vitals .mmo-health-orb-liquid {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, #be123c, #f43f5e);
  box-shadow: 0 0 12px rgba(244, 63, 94, 0.6);
  transform: scaleX(var(--hp-frac, 1));
  transform-origin: left center;
  transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

#hud-vitals .mmo-health-orb-overshield {
  position: absolute;
  top: 0;
  bottom: auto;
  left: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  background: rgba(103, 232, 249, 0.85);
  box-shadow: none;
  transform: translateX(calc(var(--os-start, 0) * 100%)) scaleX(var(--os-frac, 0));
  transform-origin: left center;
  transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Low HP (<= 30%), toggled by updateHud(): red number and brackets, and the fill pulses
   (opacity only, so it stays on the compositor). */
.hud-vitals.hp-low {
  --brk-c: rgba(251, 113, 133, 0.75);
}

.hud-vitals.hp-low .hud-hp-now {
  color: #ff8a9a; /* 5.2:1 over the contrast scrim; #fb7185 was 4.4:1 */
}

.hud-vitals.hp-low .mmo-health-orb-liquid {
  animation: hudHpLowPulse 0.8s ease-in-out infinite alternate;
}

@keyframes hudHpLowPulse {
  from { opacity: 1; }
  to { opacity: 0.45; }
}

@media (prefers-reduced-motion: reduce) {
  .hud-vitals.hp-low .mmo-health-orb-liquid {
    animation: none;
  }
}

/* ===== HUD Opacity (HUD overhaul Phase 6) ==============================================================
   Settings > Display > HUD Opacity writes --hud-opacity (0.3-1) on the root (applyHudOpacity(),
   js/settings.js), once per change. Only the HUD's group containers read it -- never single slots or
   text -- so the browser composites a handful of layers rather than dozens; at 1 nothing is created.
   Desktop: the two top corners, the trackers, the boss line, the vitals, the weapon strip, the gear
   bracket. Mobile: the top-left block, the coins / score / gear bracket, the weapon strip and the
   trackers. Never faded: the touch controls (joystick, dash), the pause button, the controller dash
   indicator, the control hints, tooltips, toasts and banners -- controls and one-off messages.
   Overrides back to full opacity, so fading never hides danger: low HP (.hp-low), a hovered weapon
   or gear group, and a boss line for its first 3 seconds (.is-fresh, js/main-loop.js). */
#hud .hud-corner,
#hud .wager-hud-tracker,
#hud .glitch-hunt-hud,
.boss-health-container,
#hud-vitals,
#mmo-action-bar .mmo-left-section,
#mmo-action-bar .mmo-right-section,
.mobile-hud-topleft,
.mobile-score-block,
.mobile-weapons-strip {
  opacity: var(--hud-opacity, 1);
}

/* The trackers keep their own transition list (css/03-base.css), which already includes opacity. */
#hud .hud-corner,
.boss-health-container,
#hud-vitals,
#mmo-action-bar .mmo-left-section,
#mmo-action-bar .mmo-right-section,
.mobile-hud-topleft,
.mobile-score-block,
.mobile-weapons-strip {
  transition: opacity 0.2s ease;
}

#hud-vitals.hp-low,
.mobile-hud-topleft.hp-low,
.boss-health-container.is-fresh {
  opacity: 1;
}

:where(body:not(.gamepad-active)) #mmo-action-bar .mmo-left-section:hover,
:where(body:not(.gamepad-active)) #mmo-action-bar .mmo-right-section:hover {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  #hud .hud-corner,
  .boss-health-container,
  #hud-vitals,
  #mmo-action-bar .mmo-left-section,
  #mmo-action-bar .mmo-right-section,
  .mobile-hud-topleft,
  .mobile-score-block,
  .mobile-weapons-strip {
    transition: none;
  }
}

/* Contrast outline on every HUD glyph (HUD overhaul Phase 7; --hud-outline in css/03b-chamfer-kit.css
   section 27). One rule for all HUD text rather than per readout, !important because some colours
   and glows are written inline by JS (wave, threat tier, wager tag). Tooltips, toasts and the touch
   controls are outside these containers and keep their own styling. */
#hud .hud-top *,
#hud .wager-hud-tracker *,
#hud .glitch-hunt-hud *,
.boss-health-container *,
#hud-vitals *,
#mmo-action-bar *,
#mobile-hud * {
  text-shadow: var(--hud-outline) !important;
}

/* Kickers (WAVE, SCORE, GEAR) were 62% white, which over a flash let the arena through the glyphs. */
#hud .hud-corner .hud-stat .label,
.hud-gear-kicker {
  color: #a3acb9;
}

/* Bars: a 1px dark ring so the track edge holds over bright effects. */
#hud-vitals .hud-hp-bar,
.hud-xp-track,
.boss-line-track,
.mobile-bar-track,
.wager-contract-bar-wrap,
.glitch-hunt-bar-container {
  box-shadow: var(--hud-bar-ring) !important;
}

/* Icons on the bare arena (coin, buff glyphs, dash bolt) get the same outline as a drop-shadow. */
#hud .hud-stat-coins img,
#hud-vitals .dash-slot svg,
.mobile-gold-icon img {
  filter: drop-shadow(1px 1px 0 #000) drop-shadow(-1px -1px 0 #000) drop-shadow(0 0 3px #000);
}

/* Bar tracks keep a dark base under their tint, so the empty part of a bar still reads as empty over
   a flash (on the normal dark floor it looks the same as before). Only the thin bars themselves. */
#hud-vitals .hud-hp-bar,
.mobile-hp-track {
  background: linear-gradient(rgba(244, 63, 94, 0.16), rgba(244, 63, 94, 0.16)), rgba(5, 4, 9, 0.6);
}

.hud-xp-track,
.mobile-xp-track {
  background: linear-gradient(rgba(168, 85, 247, 0.22), rgba(168, 85, 247, 0.22)), rgba(5, 4, 9, 0.6);
}

.boss-line-track {
  background: linear-gradient(rgba(239, 68, 68, 0.22), rgba(239, 68, 68, 0.22)), rgba(5, 4, 9, 0.6);
}

/* -- Settings > Display > HUD Elements ------------------------------------------------------------
   applyHudVisibility() (js/settings.js) sets one hud-hide-* class on <html> per switch turned off.
   !important because the HUD code writes inline display on several of these (buff bars, boss lines).
   Desktop pieces are absolutely positioned and the mobile ones sit at the ends of their blocks, so
   hiding one never moves the others. */
:root.hud-hide-weapons #mmo-action-bar .mmo-left-section,
:root.hud-hide-weapons #mobile-weapons-strip,
:root.hud-hide-gear #mmo-action-bar .mmo-right-section,
:root.hud-hide-gear #mobile-gear-row,
:root.hud-hide-buffs #mmo-buff-bar,
:root.hud-hide-buffs #mobile-buff-bar,
:root.hud-hide-score .hud-corner-right,
:root.hud-hide-score .mobile-gold-row,
:root.hud-hide-score .mobile-score-label,
:root.hud-hide-score #mobile-score,
:root.hud-hide-score.hud-hide-gear .mobile-score-block,
:root.hud-hide-boss-bars #boss-health-container {
  display: none !important;
}

/* The Core Architect's cinematic beats (js/main-loop.js ArchitectCinematic: its intro, each phase
   change, the last stand and its death) hide the whole HUD, so the letterbox and the Architect's
   voice line in the bottom bar are never covered. ArchitectCinematic.syncHud() toggles the class on
   <html>; the HUD fades back in when the beat ends. The touch controls stay. */
html.cinematic-hud-hidden #hud,
html.cinematic-hud-hidden .boss-health-container,
html.cinematic-hud-hidden #hud-vitals,
html.cinematic-hud-hidden #mmo-action-bar,
html.cinematic-hud-hidden #mobile-hud {
  opacity: 0 !important;
  visibility: hidden;
  transition: opacity 0.25s ease, visibility 0s linear 0.25s;
}
/* ==========================================================================
   Vibe Bazaar / Shop dopamine pass (js/shop.js): entrance cascade, slot
   cascade, tab-pane reveal, active-tab indicator, and purchase coin flash +
   burst. All transform/opacity/filter-only (the coin flash is a one-shot
   box-shadow pulse on a spend, not a per-frame animation). Honours
   prefers-reduced-motion.
   ========================================================================== */
#shop-screen .glass-panel {
  position: relative; /* anchors the coin burst nodes */
}

/* Entrance cascade -- fires while .shop-enter is on the bazaar panel. */
.shop-enter .shop-header-row {
  animation: shopSectionIn 360ms cubic-bezier(0.18, 0.9, 0.26, 1.1) both;
}
.shop-enter #shop-content-area {
  animation: shopSectionIn 380ms cubic-bezier(0.18, 0.9, 0.26, 1.1) both;
  animation-delay: 80ms;
}
.shop-enter .shop-currencies-bar {
  animation: shopSectionIn 380ms cubic-bezier(0.18, 0.9, 0.26, 1.1) both;
  animation-delay: 170ms;
}
@keyframes shopSectionIn {
  0% { opacity: 0; transform: translateY(14px); filter: blur(2px); }
  100% { opacity: 1; transform: none; filter: none; }
}

/* Slot cascade inside the equipment panel (--slot-index set by shop.js). */
.shop-enter .gear-arpg-layout .mmo-slot,
.shop-enter #shop-inv-weapons .mmo-slot {
  animation: shopSlotIn 300ms cubic-bezier(0.18, 0.9, 0.26, 1.1) both;
  animation-delay: calc(var(--slot-index, 0) * 45ms + 120ms);
}
@keyframes shopSlotIn {
  0% { opacity: 0; transform: scale(0.85); }
  100% { opacity: 1; transform: scale(1); }
}

/* Pane-switch reveal (Equipment / Shop tabs). */
#shop-content-equipment.pane-enter,
#shop-content-shop.pane-enter {
  animation: shopPaneIn 280ms cubic-bezier(0.18, 0.9, 0.26, 1.1) both;
}
@keyframes shopPaneIn {
  0% { opacity: 0; transform: translateY(8px); }
  100% { opacity: 1; transform: none; }
}

/* The active-tab slide indicator (.bazaar-header-tab.active::after) was removed: ::after is the
   gamepad-focus frame of the chamfer kit, and the 2px accent baseline now lives in the tab's own
   fill (css/03b-chamfer-kit.css section 20). */

/* Purchase coin flash (one-shot) + burst nodes */
.shop-currencies-bar.currency-flash {
  animation: shopCurrencyFlash 0.5s ease-out;
}
@keyframes shopCurrencyFlash {
  0% { box-shadow: 0 0 0 0 rgba(var(--c-gold), 0); }
  30% { box-shadow: 0 0 18px rgba(var(--c-gold), 0.55), inset 0 0 10px rgba(var(--c-gold), 0.3); }
  100% { box-shadow: 0 0 0 0 rgba(var(--c-gold), 0); }
}

.shop-burst-ring {
  position: absolute;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 40;
  border: 2px solid rgba(var(--c-gold), 0.95);
  box-shadow: 0 0 16px rgba(var(--c-gold), 0.8);
  transform: translate(-50%, -50%) scale(0);
  animation: shopBurst 540ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes shopBurst {
  0% { transform: translate(-50%, -50%) scale(0); opacity: 1; }
  100% { transform: translate(-50%, -50%) scale(30); opacity: 0; }
}
.shop-burst-flash {
  position: absolute;
  width: 110px;
  height: 110px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 39;
  background: radial-gradient(circle, rgba(255, 255, 255, 0.85) 0%, rgba(var(--c-gold), 0.45) 45%, transparent 70%);
  transform: translate(-50%, -50%) scale(0.4);
  animation: shopFlash 340ms ease-out forwards;
}
@keyframes shopFlash {
  0% { transform: translate(-50%, -50%) scale(0.4); opacity: 0.95; }
  100% { transform: translate(-50%, -50%) scale(1.8); opacity: 0; }
}

/* Floating Buff Bar (populated by updateBuffBarUI(), js/player.js) --
   sits directly above the weapon slots via bottom: 100% against
   .mmo-left-section's own position: absolute, rather than occupying real
   layout space itself. Deliberately has no background/border of its own so
   it's genuinely invisible with zero buffs active -- only the individual
   .mmo-buff-icon children (added/removed as buffs come and go) are ever
   visible. */
.mmo-buff-bar {
  position: absolute;
  left: 0;
  bottom: 100%;
  margin-bottom: 16px;
  display: flex;
  gap: 6px;
  pointer-events: none;
}

.mmo-buff-icon {
  width: 32px;
  height: 32px;
  border-radius: 7px;
  background: rgba(20, 16, 36, 0.9);
  border: 1.5px solid rgba(var(--c-primary), 0.4);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5), inset 0 0 6px rgba(var(--c-primary), 0.15);
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  /* visible, not hidden -- the stack badge sits at top: -5px (see
     .mmo-buff-stack-badge below), deliberately poking up above this box.
     overflow: hidden was clipping the top sliver of that badge off.
     .mmo-buff-icon img/.mmo-buff-fill below carry their own border-radius
     so the icon/fill corners still read as rounded without this clipping
     the box itself. */
  overflow: visible;
  box-sizing: border-box;
  animation: buffIconPopIn 0.15s ease-out;
}

@keyframes buffIconPopIn {
  from { transform: scale(0.4); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}

.mmo-buff-icon img {
  width: 100% !important;
  height: 100% !important;
  border-radius: 6px;
  object-fit: cover;
}

.mmo-buff-icon-glyph {
  font-size: 1rem;
  user-select: none;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.mmo-buff-icon-glyph svg {
  width: 18px;
  height: 18px;
  object-fit: contain;
  display: block;
}

.mmo-buff-icon-glyph img {
  width: 100%;
  height: 100%;
  border-radius: 6px;
  object-fit: cover;
}

/* Drains from full (scaleY(0), buff freshly applied) down to empty
   (scaleY(1), about to expire) -- same compositor-only scaleY trick as
   .mmo-slot-cooldown-overlay, just inverted since a buff bar reads more
   naturally as "draining away" than "filling up". */
.mmo-buff-fill {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 6px; /* keeps corners rounded now that the parent's own overflow: hidden is gone */
  background: rgba(8, 6, 15, 0.7);
  transform-origin: top;
  pointer-events: none;
  will-change: transform;
}

.mmo-buff-stack-badge {
  position: absolute;
  top: -5px;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(8, 6, 15, 0.9);
  border: 1px solid rgba(255, 255, 255, 0.25);
  color: rgb(var(--c-gold));
  font-size: 0.55rem;
  font-weight: 800;
  min-width: 14px;
  height: 14px;
  border-radius: 7px;
  display: none; /* toggled to flex when a stack count is present */
  align-items: center;
  justify-content: center;
  padding: 0 3px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.7);
  font-family: var(--font-display);
  pointer-events: none;
  z-index: 2;
  box-sizing: border-box;
}

.mmo-buff-timer-text {
  position: absolute;
  bottom: 1px;
  font-size: 0.5rem;
  font-weight: 700;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 1);
  font-family: var(--font-display);
  pointer-events: none;
  z-index: 2;
}

/* .gear-arpg-wrapper is the flexible region below the "Equipped Gear" title
   (index.html) -- it's what .gear-arpg-layout actually scales to fill, kept
   as a separate element so the title can stay pinned to the top of the panel
   (flex-shrink: 0 on the title, this wrapper takes all remaining space)
   instead of the whole title+grid group being vertically centered as one
   block, which used to push the title down whenever the panel had extra
   height. container-type: size turns it into a query container so the grid
   below can reference both its width AND height via cqw/cqh. */
.gear-arpg-wrapper {
  flex: 1;
  width: 100%;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  container-type: size;
}

/* ARPG-style equipped-gear cross (Bazaar's Equipment tab, #shop-inv-gear in
   index.html): Helm top-center, Armor dead center with Gloves to its left
   and Relic to its right, Boots below. Each .mmo-slot inside picks its
   grid-area via its own data-gear-slot attribute (already set by
   js/shop.js's updateShopInventoryDisplay() for the flat-row layout this
   replaces, so no JS changes were needed) rather than relying on DOM/source
   order like the old flex row did.
   Scales to fill the available area of .gear-arpg-wrapper instead of the
   base .mmo-slot's fixed 44px: `min(100cqw, 100cqh)` picks whichever of the
   wrapper's width/height is the limiting dimension, and `aspect-ratio: 1`
   applies that to the other axis too, so the cross always grows/shrinks to
   fill whatever space it's given while staying square (no fixed px cap). */
.gear-arpg-layout {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
  grid-template-areas:
    ".      helm  ."
    "gloves armor relic"
    ".      boots .";
  gap: 3.5%;
  width: min(100cqw, 100cqh);
  aspect-ratio: 1;
  box-sizing: border-box;
}

.gear-arpg-layout [data-gear-slot="helm"] { grid-area: helm; }
.gear-arpg-layout [data-gear-slot="armor"] { grid-area: armor; }
.gear-arpg-layout [data-gear-slot="gloves"] { grid-area: gloves; }
.gear-arpg-layout [data-gear-slot="relic"] { grid-area: relic; }
.gear-arpg-layout [data-gear-slot="boots"] { grid-area: boots; }

/* Below a usable size in either dimension, the 3x3 cross stops paying off --
   a 3-row-tall shape wastes most of its space on empty grid cells once the
   wrapper is short, and a 3-column-wide shape does the same once it's
   narrow, so the actual icons end up tiny even though there's spare room
   right next to them. Collapse back to the original flat single-row layout
   instead (same 5 slots, just in a line left-to-right), which uses the
   available space far more efficiently at small sizes -- a single row only
   needs 1/3 the height a 3-row cross does for the same icon size. Queries
   .gear-arpg-wrapper (container-type: size set above), triggers on width OR
   height since either one getting squeezed makes the cross the wrong shape
   for the space. */
@container (max-width: 190px) or (max-height: 170px) {
  .gear-arpg-layout {
    grid-template-columns: repeat(5, 1fr);
    grid-template-rows: 1fr;
    grid-template-areas: "helm gloves armor relic boots";
    gap: 6%;
    width: min(100cqw, 500cqh);
    aspect-ratio: 5 / 1;
  }
}

/* Each slot fills its grid cell instead of the base .mmo-slot's fixed 44px
   square. Explicitly forced square via `aspect-ratio: 1` (height: auto)
   rather than `width: 100%; height: 100%` -- the grid cells are square in
   theory (see .gear-arpg-layout's width/aspect-ratio math above), but that
   relies on several chained cqw/cqh + grid-fr calculations all agreeing
   exactly, and any rounding/containment edge case between them showed up as
   a slightly non-square icon. Setting the slot's own aspect-ratio makes it
   square unconditionally, decoupled from whether the cell itself worked out
   perfectly square. `container-type: inline-size` turns each slot into its
   own query container so its icon glyph/emoji (.mmo-slot-icon, set inline by
   js/shop.js at a fixed 0.95rem for every other slot on the page) can scale
   to a percentage of THIS slot's own width via cqw units -- the !important
   is only needed to beat that inline font-size, scoped narrowly to slots
   inside .gear-arpg-layout so weapon/action-bar slots elsewhere are
   untouched. */
.gear-arpg-layout .mmo-slot {
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  min-width: 0;
  min-height: 0;
  container-type: inline-size;
}

.gear-arpg-layout .mmo-slot-icon {
  /* Floor lowered from an earlier 1.2rem -- on small screens (see the
     .gear-arpg-layout width overrides in the mobile media queries below)
     the slot itself can end up well under 60px, and a 1.2rem-floored glyph
     would stop shrinking with it and start overflowing/clipping its box
     instead of scaling down like the rest of the cross does. */
  font-size: clamp(0.8rem, 55cqw, 3rem) !important;
}

/* The centre health orb rules lived here. Since the HUD overhaul (Phases 3 and 8) the orb container
   is the segmented HP bar in #hud-vitals, styled in css/05b-hud-telemetry.css; the orb-only rules
   (wave layer, text wrapper, orb text) were deleted with the elements they styled. */

.gear-detail-card {
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid rgba(255, 255, 255, 0.05);
  border-radius: 8px;
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  box-sizing: border-box;
}

/* Overlays (Centering Systems) */
.overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  min-height: 100%;
  background: rgba(8, 6, 15, 0.88);
  display: flex;
  justify-content: center;
  align-items: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s cubic-bezier(0.16, 1, 0.3, 1);
  z-index: 200;
}

.overlay:not(.active),
.overlay:not(.active) * {
  pointer-events: none !important;
}

.overlay.active {
  opacity: 1;
  pointer-events: auto;
}

#tutorial-modal {
  z-index: 550 !important;
}

/* Main Menu Wallpaper â€” overrides the shared flat .overlay background
   just for the start screen; other overlays (pause/settings/shop) keep
   the plain dark tint above. */
#start-screen {
  background-image: linear-gradient(rgba(8, 6, 15, 0.7), rgba(8, 6, 15, 0.7)), url('assets/background.png?v=1');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* Glassmorphic Panel UI */
.glass-panel {
  background: rgba(20, 16, 36, 0.75);
  border: 1px solid rgba(255, 255, 255, 0.08);
  /* px, not rem -- every screen built on .glass-panel (shop, pause, level-
     up, achievements, weapon-drop, settings, etc.) scales its own frame
     directly against --ui-global-scale so the panel keeps pace with the
     bigger rem-based text/buttons growing inside it on large displays. The
     existing `max-width: 90%` below is a relative cap, so it still keeps
     this from ever exceeding the actual viewport regardless of how big
     --ui-global-scale gets. */
  padding: calc(40px * var(--ui-global-scale, 1));
  width: calc(480px * var(--ui-global-scale, 1));
  max-width: 90%;
  box-shadow: 0 30px 60px rgba(0, 0, 0, 0.8),
              inset 0 1px 0 rgba(255, 255, 255, 0.1),
              0 0 50px rgba(var(--c-primary), 0.15);
  transform: translateY(20px) scale(0.95);
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.overlay.active .glass-panel {
  transform: translateY(0) scale(1);
}

.glass-panel.wide-panel {
  width: calc(700px * var(--ui-global-scale, 1));
}


.subtitle {
  font-size: 1rem;
  color: var(--color-text-muted);
  margin-bottom: 24px;
}

/* Instructions */
.instructions {
  background: rgba(0, 0, 0, 0.25);
  border-radius: 12px;
  padding: 18px;
  margin-bottom: 30px;
  width: 100%;
  border: 1px solid rgba(255, 255, 255, 0.03);
}

.instructions p {
  font-size: 0.9rem;
  color: var(--color-text-main);
  margin-bottom: 8px;
  line-height: 1.4;
}

.instructions p:last-child {
  margin-bottom: 0;
}

/* Upgrade Card Header */
.upgrade-header {
  margin-bottom: 24px;
}

.vibe-orb-icon {
  width: 50px;
  height: 50px;
  margin: 0 auto 12px auto;
  border-radius: 50%;
  background: radial-gradient(circle, #fff 10%, var(--color-secondary) 50%, var(--color-primary) 100%);
  box-shadow: 0 0 25px #fff, 
              0 0 40px var(--color-secondary), 
              0 0 60px var(--color-primary);
}

.section-title {
  font-size: 1.75rem;
  color: #fff;
  background: linear-gradient(90deg, #ff007f, #7f00ff);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 0 10px rgba(255, 0, 127, 0.4));
  margin-bottom: 6px;
}

.section-desc {
  font-size: 0.9rem;
  color: var(--color-text-muted);
}


.upgrade-card {
  position: relative;
  flex: 1;
  /* frame, fill and rarity colour: the shared card treatment, css/03b-chamfer-kit.css sections 21-22 */
  /* px, not rem -- scaled directly against --ui-global-scale, same
     reasoning as .shop-card above. */
  padding: calc(24px * var(--ui-global-scale, 1)) calc(16px * var(--ui-global-scale, 1));
  display: flex;
  flex-direction: column;
  align-items: center;
  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
  cursor: pointer;
  overflow: hidden;
}

:where(body:not(.gamepad-active)) .upgrade-card:hover {
  transform: translateY(-8px);
}

/* Premium / Rare Upgrade Card Accent: --r is the secondary accent (section 22 of css/03b-chamfer-kit.css) */

.card-glow {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: linear-gradient(90deg, var(--color-primary), transparent);
}

.upgrade-card.premium .card-glow {
  background: linear-gradient(90deg, var(--color-secondary), var(--color-primary));
}

.card-icon {
  font-size: 2rem;
  margin-bottom: 12px;
  /* px, not rem -- scaled directly against --ui-global-scale so this box
     keeps pace with its own font-size (which grows via the root font-size
     scale already). Without this, the box stayed a fixed 50px while the
     2rem icon glyph inside it grew past that height on large displays. */
  height: calc(50px * var(--ui-global-scale, 1));
  display: flex;
  align-items: center;
  justify-content: center;
  text-shadow: 0 0 10px rgba(255, 255, 255, 0.2);
}

.upgrade-card h3 {
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 700;
  margin-bottom: 8px;
  color: #fff;
}

.upgrade-card .card-desc {
  font-size: 0.8rem;
  color: var(--color-text-muted);
  line-height: 1.3;
  margin-bottom: 20px;
  flex-grow: 1;
}

/* Live, level-scaling numbers interpolated into weapon descriptions (see
   Weapon.getFullDescription/getDescTokens) â€” a distinct color so a dynamic
   number reads differently from surrounding static flavor text at a glance. */
.stat-dynamic {
  color: rgb(var(--c-cyan));
  font-weight: bold;
}

/* Major Choice Screen â€” bigger icons fill the card top, no Select button,
/* Caps the modal width for Major Choice Screen (#major-choice-screen) with
   distinct dual clash layout and milestone header. */
#major-choice-screen .major-choice-panel,
#major-choice-screen .glass-panel {
  max-width: 680px;
  position: relative;
  display: flex;
  flex-direction: column;
  padding: calc(16px * var(--ui-global-scale, 1)) calc(22px * var(--ui-global-scale, 1));
  box-sizing: border-box;
}

.major-choice-header {
  position: relative;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 44px;
  box-sizing: border-box;
}

.major-choice-emblem-wrap {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
}

.major-choice-emblem-glow {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(var(--c-amber), 0.6) 0%, rgba(var(--c-orange), 0.2) 60%, transparent 80%);
  filter: blur(6px);
  animation: wagerGlowPulse 3s ease-in-out infinite alternate;
  pointer-events: none;
}

.major-choice-emblem-svg {
  width: 36px;
  height: 36px;
  filter: drop-shadow(0 0 8px rgba(var(--c-amber), 0.7));
  z-index: 1;
}

.major-choice-header-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 2px;
}

.major-choice-milestone-badge {
  display: inline-block;
  font-family: var(--font-display, inherit);
  font-size: 0.62rem;
  font-weight: bold;
  letter-spacing: 0.08em;
  padding: 2px 10px;
  border-radius: 999px;
  border: 1.5px solid var(--milestone-color, #fb923c);
  color: var(--milestone-color, #fb923c);
  background: rgba(0, 0, 0, 0.4);
  box-shadow: 0 0 10px var(--milestone-glow, rgba(251, 146, 60, 0.4));
  margin-bottom: 2px;
  text-transform: uppercase;
}

.major-choice-header-center h2 {
  margin: 0;
  font-size: calc(1.35rem * var(--ui-global-scale, 1));
  line-height: 1.15;
  letter-spacing: 0.04em;
}

.major-choice-header-center p {
  margin: 0;
  font-size: calc(0.82rem * var(--ui-global-scale, 1));
  line-height: 1.25;
  color: rgba(226, 232, 240, 0.85);
}

#major-choice-screen #major-choices-container {
  display: flex;
  gap: 16px;
  margin-top: 14px;
  width: 100%;
}

#major-choice-screen .choice-card,
#major-choice-screen .upgrade-card {
  position: relative;
  flex: 1;
  min-width: 0;
  padding: 16px 14px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  /* frame / fill: the card treatment; --r is the milestone tier colour (js/upgrades.js sets it) */
  cursor: pointer;
  transition: transform 0.16s cubic-bezier(0.2, 0.9, 0.3, 1), opacity 0.25s ease, filter 0.25s ease;
  will-change: transform, opacity;
}

#major-choice-screen .choice-card.path-a {
  animation: choiceClashLeft 420ms cubic-bezier(0.18, 0.9, 0.26, 1.15) forwards;
}

#major-choice-screen .choice-card.path-b {
  animation: choiceClashRight 420ms cubic-bezier(0.18, 0.9, 0.26, 1.15) forwards;
}

@keyframes choiceClashLeft {
  0% {
    opacity: 0;
    transform: perspective(600px) translateX(-45px) rotateY(18deg) scale(0.9);
  }
  70% {
    opacity: 1;
    transform: perspective(600px) translateX(6px) rotateY(-3deg) scale(1.03);
  }
  100% {
    opacity: 1;
    transform: perspective(600px) translateX(0) rotateY(0deg) scale(1);
  }
}

@keyframes choiceClashRight {
  0% {
    opacity: 0;
    transform: perspective(600px) translateX(45px) rotateY(-18deg) scale(0.9);
  }
  70% {
    opacity: 1;
    transform: perspective(600px) translateX(-6px) rotateY(3deg) scale(1.03);
  }
  100% {
    opacity: 1;
    transform: perspective(600px) translateX(0) rotateY(0deg) scale(1);
  }
}

:where(body:not(.gamepad-active)) #major-choice-screen .choice-card:not(.selected):not(.power-up):not(.rejected):not(.fizzle):hover,
#major-choice-screen .choice-card:not(.selected):not(.power-up):not(.rejected):not(.fizzle).kb-focused,
#major-choice-screen .choice-card:not(.selected):not(.power-up):not(.rejected):not(.fizzle).controller-focused,
:where(body:not(.gamepad-active)) #major-choice-screen .upgrade-card:not(.selected):not(.power-up):not(.rejected):not(.fizzle):hover,
#major-choice-screen .upgrade-card:not(.selected):not(.power-up):not(.rejected):not(.fizzle).kb-focused,
#major-choice-screen .upgrade-card:not(.selected):not(.power-up):not(.rejected):not(.fizzle).controller-focused {
  transform: translateY(-6px);
}

#major-choice-screen .choice-card.selected {
  animation: evolutionSelectSlam 280ms cubic-bezier(0.15, 0.9, 0.2, 1.25) forwards;
  z-index: 10;
}

@keyframes evolutionSelectSlam {
  0% { transform: scale(1.03); }
  50% { transform: scale(1.12); filter: brightness(1.5) saturate(1.35); }
  100% { transform: scale(1.08); }
}

#major-choice-screen .choice-card.rejected {
  opacity: 0.18;
  filter: blur(2px) grayscale(60%);
  transform: scale(0.92);
  pointer-events: none;
}

#major-choice-screen .card-icon {
  width: calc(100px * var(--ui-global-scale, 1));
  height: calc(100px * var(--ui-global-scale, 1));
  min-width: calc(100px * var(--ui-global-scale, 1));
  min-height: calc(100px * var(--ui-global-scale, 1));
  /* striped art box (background, border): css/03b-chamfer-kit.css section 22 */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 6px;
  box-sizing: border-box;
  margin-bottom: 10px;
  flex-shrink: 0;
}
#major-choice-screen .card-icon img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: 6px;
}
#major-choice-screen .upgrade-card h3 {
  font-size: 1rem;
  margin-bottom: 4px;
}
#major-choice-screen .upgrade-card .card-desc {
  font-size: 0.78rem;
  margin-bottom: 0;
  line-height: 1.35;
  flex-grow: 0;
}

/* Floating Tree Stat Floater Pop */
.tree-stat-floater {
  position: absolute;
  left: 50%;
  top: -6px;
  transform: translate(-50%, -100%);
  font-size: 0.92rem;
  font-weight: 800;
  color: #60a5fa;
  text-shadow: 0 0 10px rgba(96, 165, 250, 0.8), 0 2px 4px rgba(0, 0, 0, 0.8);
  white-space: nowrap;
  pointer-events: none;
  animation: treeStatFloatUp 700ms cubic-bezier(0.15, 0.9, 0.2, 1) forwards;
  z-index: 400;
}

@keyframes treeStatFloatUp {
  0% {
    opacity: 0;
    transform: translate(-50%, 0) scale(0.7);
  }
  30% {
    opacity: 1;
    transform: translate(-50%, -14px) scale(1.15);
  }
  70% {
    opacity: 1;
    transform: translate(-50%, -24px) scale(1);
  }
  100% {
    opacity: 0;
    transform: translate(-50%, -36px) scale(0.9);
  }
}

/* Caps the panel's own height so #weapon-tree-content (below) actually has
   a bounded box to shrink into and scroll within -- flex:1 on a child does
   nothing useful if the parent's height is unbounded, since the child would
   just keep growing right along with it. Scoped to #level-up-screen rather
   than added to the shared .glass-panel.wide-panel rule since other screens
   using that class don't have this scrollable-middle-section layout. */
#level-up-screen .glass-panel.wide-panel {
  width: min(calc(94 * var(--vvw)), calc(920px * var(--ui-global-scale, 1)));
  max-width: 960px;
  max-height: calc(90 * var(--vvh));
  overflow: hidden;
}

/* ==========================================
   Weapon-Tree Carousel (Phase 3 of the weapon-
   upgrade UI depth work; replaces the horizontally-
   scrolling tab strip in #level-up-screen with a
   center-and-peek carousel -- one tab per weapon
   slot, the active one centered/full size, its
   immediate neighbors shown smaller and dimmed.
   Positioning math lives in js/weapon-tree.js's
   renderWeaponTreeTabs(), driven by the
   --tab-offset/--tab-scale/--tab-opacity/--tab-pointer
   custom properties set per tab below. )
   ========================================== */
.weapon-tree-tabs-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  margin-bottom: 16px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  padding-bottom: 12px;
  flex-shrink: 0;
}

.weapon-tree-bumper-icon {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  opacity: 0.85;
  filter: drop-shadow(0 0 4px rgba(var(--c-primary), 0.4));
}

.weapon-tree-carousel-arrow {
  flex-shrink: 0;
  width: 30px;
  height: 30px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(25, 20, 46, 0.5);
  color: rgba(255, 255, 255, 0.6);
  font-family: var(--font-display);
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s ease;
}

:where(body:not(.gamepad-active)) .weapon-tree-carousel-arrow:hover {
  border-color: rgba(var(--c-primary), 0.4);
  background: rgba(30, 24, 55, 0.7);
  color: #fff;
}

.weapon-tree-tabs {
  --carousel-unit: 135px;
  position: relative;
  flex: 1;
  min-width: 0;
  height: 52px;
  /* Belt-and-suspenders on top of the opacity:0 + pointer-events:none that
     actually do the hiding below: on a panel narrow enough that a 2+-slots-
     away tab's translateX doesn't clear the viewport, this still keeps it
     from being painted or hit-tested outside the visible box. */
  overflow: hidden;
}

.weapon-tree-tab {
  position: absolute;
  top: 50%;
  left: 50%;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  cursor: pointer;
  overflow: hidden;
  transition: transform 0.25s ease, opacity 0.25s ease, color 0.2s ease;
  font-family: var(--font-display);
  font-size: 0.78rem;
  white-space: nowrap;
  /* top tab: cut-tab shape, border frame on ::after (this tab's ::before is the progress fill),
     hover / active / focus colours: css/03b-chamfer-kit.css section 20 */
  /* Set per-tab by updateWeaponTreeCarouselPositions() (js/weapon-tree.js)
     from this tab's distance (in slots) from the active one -- 0 =
     centered/full size, 1 = a dimmed peek either side, 2+ faded to fully
     invisible and click/tap-proof. */
  transform: translate(-50%, -50%) translateX(var(--tab-offset, 0px)) scale(var(--tab-scale, 1));
  opacity: var(--tab-opacity, 1);
  pointer-events: var(--tab-pointer, auto);
}

/* Left-to-right milestone progress background fill */
.weapon-tree-tab::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: var(--progress-percent, 0%);
  background: linear-gradient(90deg, var(--progress-color, #3b82f6) 0%, transparent 100%);
  opacity: 0.32;
  pointer-events: none;
  transition: width 0.35s cubic-bezier(0.2, 0.9, 0.3, 1), background 0.3s ease;
  z-index: 0;
}

.weapon-tree-tab.active::before {
  opacity: 0.52;
  box-shadow: inset 0 0 14px var(--progress-glow, rgba(59, 130, 246, 0.4));
}

.weapon-tree-tab > * {
  position: relative;
  z-index: 1;
}

.weapon-tree-tab img {
  width: 22px;
  height: 22px;
  object-fit: cover;
  border-radius: 4px;
  flex-shrink: 0;
}

.weapon-tree-tab.locked {
  /* Deliberately NOT setting opacity here -- it's fully driven by the
     --tab-opacity var (js/weapon-tree.js's updateWeaponTreeCarouselPositions())
     same as every other tab, locked or not, so a locked tab 2+ slots from
     active still fades all the way to invisible instead of this rule's old
     flat 0.4 winning the cascade and leaving it visible as a stray chip. */
  cursor: not-allowed;
  filter: grayscale(1);
}

#level-up-screen #weapon-tree-tabs .weapon-tree-tab.controller-focused,
#weapon-tree-tabs .weapon-tree-tab.controller-focused,
.weapon-tree-tabs-row .weapon-tree-tab.controller-focused,
.weapon-tree-tab.controller-focused {
  transform: translate(-50%, -50%) translateX(var(--tab-offset, 0px)) scale(calc(var(--tab-scale, 1) * 1.05)) !important;
  transition: transform 0.25s ease, opacity 0.25s ease, box-shadow 0.15s ease, border-color 0.2s ease !important;
}

.weapon-tree-dots {
  /* Absolutely positioned within .weapon-tree-tabs-row's own bottom padding
     (12px, plenty for a 6px dot / 6px active pill) instead of sitting in
     normal flow as its own block -- reported by Richard: as a flow element
     this pushed every row below it down by its own height + margin, which
     was then just enough to make the weapon tree's fork-option labels
     overlap the Resume Arena button beneath them. Overlaying it here costs
     zero extra vertical space, so nothing below shifts at all. */
  position: absolute;
  left: 50%;
  bottom: 1px;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 6px;
}

.weapon-tree-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.2);
  cursor: pointer;
  transition: all 0.2s ease;
  flex-shrink: 0;
}

.weapon-tree-dot.locked {
  background: rgba(255, 255, 255, 0.08);
  cursor: not-allowed;
}

.weapon-tree-dot.active {
  background: rgb(var(--c-primary));
  width: 16px;
  border-radius: 3px;
}

/* #level-up-screen's panel caps its own height and scrolls this region
   internally (see the #level-up-screen .glass-panel.wide-panel rule near
   the bottom of this file) instead of letting it grow without bound --
   flex:1 + min-height:0 is what lets a flex child actually shrink to fit
   and scroll rather than overflowing its own box. Reported by Richard: on
   smaller screens, a long weapon description (see .weapon-tree-desc below,
   which gets its own tighter internal scroll first) could still grow this
   whole area tall enough to push the tree row down into the Resume Arena
   button. This keeps that from ever happening regardless of what grows --
   header, description, or tree row -- since the header/tabs-row above and
   the Resume button below are both outside this scrolling region. */
.weapon-tree-content {
  width: 100%;
  text-align: left;
  min-height: 0;
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 4px 8px;
  box-sizing: border-box;
}

.weapon-tree-header {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  margin-bottom: 10px;
}

.weapon-tree-icon-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}

.weapon-tree-header .weapon-tree-icon {
  width: 56px;
  height: 56px;
  object-fit: cover;
  border-radius: 8px;
  border: 1.5px solid rgba(255, 255, 255, 0.1);
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.5);
  flex-shrink: 0;
}

.weapon-tree-header-text {
  flex: 1;
  min-width: 0;
}

.weapon-tree-header-text h3 {
  font-family: var(--font-display);
  font-size: 1.1rem;
  color: #fff;
  margin-bottom: 2px;
}

.weapon-tree-level {
  font-size: 0.72rem;
  color: var(--color-primary);
  font-weight: bold;
  text-align: center;
  white-space: nowrap;
}

.weapon-tree-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 8px 0;
}

.weapon-tree-stat-chip {
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 6px;
  padding: 3px 8px;
  font-size: 0.68rem;
  color: rgba(255, 255, 255, 0.85);
  display: flex;
  gap: 4px;
  white-space: nowrap;
}

.weapon-tree-stat-chip .stat-label {
  color: var(--color-text-muted);
}

.weapon-tree-stat-chip .stat-change {
  color: var(--color-success);
  font-weight: bold;
}

.weapon-tree-desc {
  font-size: 0.75rem;
  color: var(--color-text-muted);
  line-height: 1.4;
  margin-top: 3px;
  margin-bottom: 4px;
}

.weapon-tree-next-desc {
  color: var(--color-success, #10b981);
  font-size: 0.72rem;
  font-weight: 600;
  line-height: 1.35;
  text-align: right;
  width: 100%;
  word-break: break-word;
  text-shadow: 0 0 8px rgba(var(--c-success), 0.25);
}

.weapon-tree-next-desc .next-label {
  color: var(--color-text-muted);
  font-weight: normal;
}

/* ==========================================
   Weapon Upgrade Header SVG Icon
   ========================================== */
.upgrade-header-icon {
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  animation: upgradeChevronPulse 2.4s ease-in-out infinite;
}

.upgrade-chevron-svg {
  width: 28px;
  height: 28px;
  filter: drop-shadow(0 0 8px rgba(59, 130, 246, 0.7));
}

@keyframes upgradeChevronPulse {
  0%, 100% {
    transform: translateY(0);
    filter: drop-shadow(0 0 6px rgba(59, 130, 246, 0.6));
  }
  50% {
    transform: translateY(-2px);
    filter: drop-shadow(0 0 14px rgba(96, 165, 250, 0.95));
  }
}

/* ==========================================
   Cyber Transition & Fluid Window Morphing
   ========================================== */
#level-up-screen .glass-panel.wide-panel {
  position: relative;
  overflow: hidden;
  transition: width 0.28s cubic-bezier(0.2, 0.8, 0.2, 1),
              max-width 0.28s cubic-bezier(0.2, 0.8, 0.2, 1),
              border-color 0.24s ease,
              box-shadow 0.24s ease;
}

#level-up-screen.view-grid .glass-panel.wide-panel {
  width: min(calc(94 * var(--vvw)), calc(660px * var(--ui-global-scale, 1)));
  max-width: calc(660px * var(--ui-global-scale, 1));
}

#level-up-screen.view-tree .glass-panel.wide-panel {
  width: min(calc(94 * var(--vvw)), calc(920px * var(--ui-global-scale, 1)));
  max-width: 960px;
}

/* Cyber boundary flare during resize / morphing */
#level-up-screen .glass-panel.is-morphing {
  border-color: rgba(56, 189, 248, 0.9) !important;
  box-shadow: 0 0 24px rgba(56, 189, 248, 0.65),
              0 0 48px rgba(56, 189, 248, 0.25),
              inset 0 0 16px rgba(56, 189, 248, 0.2) !important;
}

/* Horizontal cyber laser scanline sweeping across the panel */
.cyber-panel-scanline {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: linear-gradient(90deg, transparent 0%, rgba(56, 189, 248, 0.35) 15%, #38bdf8 50%, rgba(56, 189, 248, 0.35) 85%, transparent 100%);
  box-shadow: 0 0 10px #38bdf8, 0 0 20px rgba(56, 189, 248, 0.8);
  opacity: 0;
  pointer-events: none;
  z-index: 60;
}

#level-up-screen .glass-panel.is-morphing .cyber-panel-scanline {
  opacity: 1;
  animation: cyberScanlineSweep 0.28s cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
}

@keyframes cyberScanlineSweep {
  0% {
    top: 0%;
    opacity: 0;
  }
  20% {
    opacity: 1;
  }
  80% {
    opacity: 1;
  }
  100% {
    top: 100%;
    opacity: 0;
  }
}

/* ==========================================
   Weapon Grid Overview (3x2 Sub-View)
   ========================================== */
.weapon-grid-view {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1 1 auto;
  min-height: 0;
  box-sizing: border-box;
  transition: opacity 0.16s ease, transform 0.16s cubic-bezier(0.2, 0.8, 0.2, 1);
  will-change: opacity, transform;
}

.weapon-tree-view {
  width: 100%;
  display: flex !important;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  box-sizing: border-box;
  transition: opacity 0.16s ease, transform 0.16s cubic-bezier(0.2, 0.8, 0.2, 1);
  will-change: opacity, transform;
}

.weapon-view-dissolve {
  opacity: 0 !important;
  transform: scale(0.97) !important;
  pointer-events: none !important;
}

.weapon-view-materialize {
  opacity: 1 !important;
  transform: scale(1) !important;
}

#weapon-grid-view[style*="display: none"],
#level-up-screen.view-tree #weapon-grid-view {
  display: none !important;
}

#weapon-tree-view[style*="display: none"],
#level-up-screen.view-grid #weapon-tree-view {
  display: none !important;
}

.weapon-overview-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(2, auto);
  gap: 16px;
  width: 100%;
  /* 620px, or less on short windows: the cards are square and sized from this width, so on a
     wide-but-short screen (a 1280x520 window, or a phone in a browser at 954x444) the second row
     ran past the bottom of the window. 150 * --vvh - 320px keeps both rows plus the header and
     the Resume button inside the window (two rows of (W - 32) / 3 plus a 16px gap, with ~215px
     of header, footer and padding around them); from 700px tall up it is the old 620px. */
  max-width: min(620px, calc(150 * var(--vvh, 1vh) - 320px));
  margin: 0 auto;
  box-sizing: border-box;
}

.weapon-grid-card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  padding: 0;
  width: 100%;
  aspect-ratio: 1 / 1;
  /* frame, fill and --r (the milestone tier colour): css/03b-chamfer-kit.css sections 21-22 */
  cursor: pointer;
  transition: transform 0.2s cubic-bezier(0.2, 0.8, 0.2, 1);
  overflow: hidden;
  box-sizing: border-box;
  text-align: center;
}

/* Dedicated full-bleed art container filling the 1:1 square card */
.weapon-grid-card-hero.weapon-grid-card-art-container {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  pointer-events: none;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(10, 8, 20, 0.5);
  border: none;
  box-sizing: border-box;
}

.weapon-grid-card-bg-art {
  width: 100%;
  height: 100%;
  object-fit: cover;
  padding: 0;
  box-sizing: border-box;
  opacity: 1 !important;
  display: block;
  filter: none !important;
  transition: transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.weapon-grid-card-bg-fallback {
  font-size: 3.5rem;
  opacity: 1 !important;
}

:where(body:not(.gamepad-active)) .weapon-grid-card:not(.locked):hover .weapon-grid-card-bg-art,
.weapon-grid-card.controller-focused .weapon-grid-card-bg-art {
  transform: scale(1.05);
}

/* No dimming overlays: image displays in 100% full vibrant color.
   (.weapon-grid-card::before is the chamfer frame now; it sits above the full-bleed art, see css/03b section 22.) */
.weapon-grid-card-scrim {
  display: none !important;
}

:where(body:not(.gamepad-active)) .weapon-grid-card:not(.locked):hover {
  transform: translateY(-2px);
}

.weapon-grid-card.controller-focused {
  transform: translateY(-2px);
}

/* Top bar: full-width weapon title floating with gentle top-down scrim */
.weapon-grid-card-top {
  position: relative;
  z-index: 3;
  width: 100%;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px 10px 14px 10px;
  background: linear-gradient(180deg, rgba(12, 9, 24, 0.88) 0%, rgba(12, 9, 24, 0.45) 55%, transparent 100%);
  box-sizing: border-box;
}

.weapon-grid-card-title {
  font-family: var(--font-display);
  font-size: 0.92rem;
  font-weight: 700;
  color: #fff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  width: 100%;
  max-width: 100%;
  text-align: center;
  letter-spacing: 0.03em;
  padding: 0;
  background: none;
  backdrop-filter: none;
  border: none;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.9);
}

.weapon-grid-card-badge-overlay {
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 2px 7px;
  border-radius: 6px;
  background: rgba(10, 8, 22, 0.82);
  backdrop-filter: blur(4px);
  border: 1px solid var(--prog-color, #3b82f6);
  box-shadow: 0 0 8px var(--prog-glow, rgba(59, 130, 246, 0.4));
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}

.weapon-grid-card-max-tag {
  opacity: 0.85;
  font-size: 0.65rem;
}

/* Weapon Card Preview Overlay (Next Upgrade on Hover / Focus / Touch) */
.weapon-grid-card-preview-overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 34px 12px 38px 12px;
  background: rgba(8, 6, 18, 0.62);
  backdrop-filter: blur(2.5px);
  -webkit-backdrop-filter: blur(2.5px);
  box-sizing: border-box;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.22s cubic-bezier(0.2, 0.8, 0.2, 1),
              transform 0.22s cubic-bezier(0.2, 0.8, 0.2, 1);
  transform: translateY(4px);
  text-align: center;
}

:where(body:not(.gamepad-active)) .weapon-grid-card:not(.locked):hover .weapon-grid-card-preview-overlay,
.weapon-grid-card.controller-focused .weapon-grid-card-preview-overlay,
.weapon-grid-card:focus-visible .weapon-grid-card-preview-overlay,
.weapon-grid-card.touch-preview-active .weapon-grid-card-preview-overlay {
  opacity: 1;
  transform: translateY(0);
}

.weapon-grid-preview-badge {
  font-family: var(--font-display);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 8px;
  background: rgba(0, 0, 0, 0.82);
  border: 1px solid currentColor;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.7);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 6px;
}

.weapon-grid-preview-desc {
  font-family: var(--font-display);
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1.3;
  color: #ffffff;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 1), 0 0 8px rgba(0, 0, 0, 0.9);
  max-width: 100%;
  word-break: break-word;
}

/* Bottom section: tier details & progress floating with gentle bottom-up scrim */
.weapon-grid-card-bottom {
  position: relative;
  z-index: 3;
  width: 100%;
  flex-shrink: 0;
  margin-top: auto;
  padding: 14px 10px 8px 10px;
  background: linear-gradient(0deg, rgba(12, 9, 24, 0.92) 0%, rgba(12, 9, 24, 0.55) 60%, transparent 100%);
  border: none;
  display: flex;
  flex-direction: column;
  gap: 3px;
  box-sizing: border-box;
}

/* Progress bar section */
.weapon-grid-card-progress {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.weapon-grid-card-progress-labels {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.65rem;
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: 0.03em;
  color: #e2e8f0;
}

.weapon-grid-card-tier-label {
  color: var(--prog-color, #ffffff);
  text-transform: uppercase;
  font-weight: 700;
  transition: color 0.3s ease, text-shadow 0.3s ease;
}

.weapon-grid-card-lvl-label {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--prog-color, #ffffff);
  font-size: 0.68rem;
  letter-spacing: 0.04em;
  transition: color 0.3s ease;
}

/* 4-Segment Progress Bar */
.weapon-grid-card-segments {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 4px;
  box-sizing: border-box;
}

.weapon-grid-card-segment-track {
  flex: 1;
  height: 6px;
  background: rgba(0, 0, 0, 0.75);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 3px;
  overflow: hidden;
  position: relative;
  transition: border-color 0.3s ease, box-shadow 0.3s ease;
}

.weapon-grid-card-segment-fill {
  height: 100%;
  border-radius: 2px;
  background: var(--prog-color, #ffffff);
  box-shadow: 0 0 8px var(--prog-glow, rgba(255, 255, 255, 0.5));
  transition: width 0.35s cubic-bezier(0.2, 0.8, 0.2, 1), background 0.3s ease, box-shadow 0.3s ease;
}

/* Legacy single-bar fallback */
.weapon-grid-card-track {
  width: 100%;
  height: 5px;
  background: rgba(0, 0, 0, 0.7);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 3px;
  overflow: hidden;
  position: relative;
}

.weapon-grid-card-fill {
  height: 100%;
  border-radius: 2px;
  background: var(--prog-color, #ffffff);
  box-shadow: 0 0 8px var(--prog-glow, rgba(255, 255, 255, 0.5));
  transition: width 0.3s ease;
}

/* Upgrade Excitement Animations */
.weapon-grid-card-segment-track.segment-flash {
  border-color: #ffffff;
  animation: segment-flash-pulse 0.65s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.weapon-grid-card-segment-track.segment-flash .weapon-grid-card-segment-fill {
  animation: segment-fill-flash 0.65s cubic-bezier(0.2, 0.8, 0.2, 1);
}

@keyframes segment-flash-pulse {
  0% {
    border-color: #ffffff;
    box-shadow: 0 0 12px #ffffff, 0 0 20px var(--prog-glow, rgba(255, 255, 255, 0.8));
    transform: scaleY(1.3);
  }
  50% {
    border-color: var(--prog-color, #ffffff);
    box-shadow: 0 0 8px var(--prog-glow, rgba(255, 255, 255, 0.5));
    transform: scaleY(1.15);
  }
  100% {
    border-color: rgba(255, 255, 255, 0.15);
    box-shadow: none;
    transform: scaleY(1);
  }
}

@keyframes segment-fill-flash {
  0% {
    filter: brightness(2.6);
  }
  40% {
    filter: brightness(1.8);
  }
  100% {
    filter: brightness(1);
  }
}

.weapon-grid-card.is-upgraded {
  animation: card-upgrade-punch 0.5s cubic-bezier(0.2, 0.8, 0.2, 1);
}

@keyframes card-upgrade-punch {
  0% {
    transform: scale(1);
  }
  30% {
    transform: scale(1.035);
    filter: brightness(1.5) saturate(1.3);
  }
  100% {
    transform: scale(1);
    filter: brightness(1);
  }
}

.weapon-grid-card-badge-overlay.badge-punch,
.weapon-grid-card-lvl-label.lvl-punch {
  animation: badge-upgrade-punch 0.55s cubic-bezier(0.2, 0.8, 0.2, 1);
}

@keyframes badge-upgrade-punch {
  0% {
    transform: scale(1);
  }
  35% {
    transform: scale(1.22);
    filter: brightness(1.7);
  }
  70% {
    transform: scale(0.96);
  }
  100% {
    transform: scale(1);
    filter: brightness(1);
  }
}

/* Stat Floater on Upgrade */
.tree-stat-floater {
  position: absolute;
  top: 40%;
  left: 50%;
  transform: translate(-50%, 0);
  font-family: var(--font-display);
  font-size: 0.85rem;
  font-weight: 800;
  letter-spacing: 0.05em;
  color: #ffffff;
  text-shadow: 0 0 8px var(--prog-glow, rgba(255, 255, 255, 0.8));
  background: rgba(10, 8, 22, 0.9);
  backdrop-filter: blur(4px);
  padding: 3px 9px;
  border-radius: 6px;
  border: 1px solid var(--prog-color, #ffffff);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.6), 0 0 10px var(--prog-glow, rgba(255, 255, 255, 0.4));
  animation: tree-stat-float-up 0.75s cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
  pointer-events: none;
  z-index: 10;
  white-space: nowrap;
}

@keyframes tree-stat-float-up {
  0% {
    opacity: 0;
    transform: translate(-50%, 8px) scale(0.85);
  }
  20% {
    opacity: 1;
    transform: translate(-50%, -4px) scale(1.08);
  }
  40% {
    transform: translate(-50%, -10px) scale(1);
  }
  80% {
    opacity: 1;
    transform: translate(-50%, -24px) scale(0.98);
  }
  100% {
    opacity: 0;
    transform: translate(-50%, -32px) scale(0.9);
  }
}

/* Grid View Footer & Multi-Input Control Hints */
.weapon-grid-control-hints {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.76rem;
  letter-spacing: 0.04em;
  color: rgba(255, 255, 255, 0.6);
  margin-top: 10px;
  gap: 6px;
}

.weapon-grid-kbd {
  display: inline-block;
  padding: 1px 5px;
  font-family: inherit;
  font-size: 0.72rem;
  font-weight: 700;
  color: #e2e8f0;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.25);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}

:where(body:not(.gamepad-active)) .weapon-grid-hint-pad {
  display: none !important;
}

:where(body.gamepad-active) .weapon-grid-hint-pc {
  display: none !important;
}

:where(body.gamepad-active) .weapon-grid-hint-pad {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.is-mobile .weapon-grid-control-hints {
  display: none !important;
}

/* Locked Card Content */
.weapon-grid-card.locked {
  /* dim frame and fill: --bd / --bg in css/03b-chamfer-kit.css section 22 */
  cursor: not-allowed;
  opacity: 0.6;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 16px 10px;
  text-align: center;
  aspect-ratio: 1 / 1;
}

.weapon-grid-card-locked-icon {
  color: rgba(255, 255, 255, 0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.5));
}

.weapon-grid-card-locked-title {
  font-family: var(--font-display);
  font-size: 0.88rem;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.65);
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.weapon-grid-card-locked-desc {
  font-size: 0.74rem;
  color: rgba(255, 255, 255, 0.4);
}

/* Footer of grid view */
.weapon-grid-footer {
  margin-top: 16px;
  width: 100%;
  display: flex;
  justify-content: center;
}

.weapon-grid-close-btn {
  flex: 1;
  max-width: 380px;
}

/* Weapon Tree Footer Button Layout */
.weapon-tree-footer {
  margin-top: auto;
  width: 100%;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 16px;
  box-sizing: border-box;
  flex-shrink: 0;
  padding: 8px 6px 8px 6px;
}

/* Weapons Grid Return Button */
#weapon-tree-grid-btn {
  flex: 0 0 auto;
  width: auto !important;
  min-width: 140px;
  max-width: 180px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 18px;
  /* secondary chamfer .btn tinted with the screen's cyan accent: the old sky-blue border/fill
     declarations were dropped in favour of the kit's --bd/--bg (css/03b-chamfer-kit.css section 12) */
  white-space: nowrap;
}

/* Controller button icons in weapon tree and grid footers */
.weapon-tree-grid-pad-icon,
.level-up-resume-pad-icon {
  display: none;
  width: 18px;
  height: 18px;
  margin-right: 6px;
  vertical-align: middle;
  flex-shrink: 0;
  background: #000000 !important;
  border-radius: 50% !important;
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.95), 0 2px 4px rgba(0, 0, 0, 0.8) !important;
}

body.gamepad-active .weapon-tree-grid-pad-icon,
body.gamepad-active .level-up-resume-pad-icon {
  display: inline-block;
}

body.gamepad-active #weapon-tree-grid-icon {
  display: none !important;
}

/* #weapon-tree-grid-btn:hover (sky fill + glow) removed: the kit's .btn:hover does it. */

.weapon-tree-footer #weapon-tree-upgrade-btn,
.weapon-tree-footer #level-up-close-btn {
  flex: 1 1 0%;
  min-width: 0;
  width: auto;
  white-space: nowrap;
}


/* ==========================================
   Weapon-Tree Milestone Cards & Inspection Panel
   ========================================== */
#weapon-tree-milestone-panel {
  width: 100%;
  margin-top: 8px;
  min-height: 110px;
  box-sizing: border-box;
  padding: 4px 6px 8px 6px;
}

.weapon-tree-milestones-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  width: 100%;
  box-sizing: border-box;
  padding: 2px 4px 6px 4px;
}

@media (max-width: 1000px) {
  .weapon-tree-milestones-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 600px) {
  .weapon-tree-milestones-grid {
    grid-template-columns: 1fr;
  }
}

.weapon-tree-milestone-card {
  position: relative;
  overflow: hidden;
  /* frame, fill and the progress fill (a --bg layer driven by --milestone-progress-percent / --r):
     css/03b-chamfer-kit.css sections 21-22 */
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  box-sizing: border-box;
  text-align: left;
  cursor: pointer;
  transition: transform 0.15s ease, opacity 0.15s ease;
}

.weapon-tree-milestone-card > * {
  position: relative;
  z-index: 1;
}

:where(body:not(.gamepad-active)) .weapon-tree-milestone-card:hover {
  transform: translateY(-2px);
  opacity: 1 !important;
}

.weapon-tree-milestone-card.controller-focused {
  transform: translateY(-2px);
  opacity: 1 !important;
}

.weapon-tree-milestone-card.in-progress {
  opacity: 0.95;
}

.weapon-tree-milestone-card.locked {
  opacity: 0.65;
}

.weapon-tree-milestone-card .card-category-tag {
  font-size: 0.58rem;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  line-height: 1.2;
}

.weapon-tree-milestone-card .card-choice-name {
  font-size: 0.82rem;
  font-weight: bold;
  color: #ffffff;
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 1px;
}

.weapon-tree-milestone-card .card-choice-desc {
  font-size: 0.68rem;
  color: rgba(255, 255, 255, 0.85);
  line-height: 1.35;
  margin-top: 2px;
}

.weapon-tree-milestone-inspect-header {
  display: flex;
  align-items: stretch;
  gap: 12px;
  width: 100%;
  box-sizing: border-box;
  padding: 2px 4px 6px 4px;
  animation: fadeIn 0.15s ease-out;
}

@media (max-width: 768px) {
  .weapon-tree-milestone-inspect-header {
    flex-direction: column;
  }
}


.tree-pip {
  position: relative;
  z-index: 1;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.15);
  background: rgba(20, 16, 36, 0.9);
  flex-shrink: 0;
}

.tree-pip.done {
  background: var(--color-primary);
  border-color: var(--color-primary);
  box-shadow: 0 0 8px var(--color-primary-glow);
}

.tree-pip.next {
  border-color: #fff;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.15), 0 0 10px rgba(255, 255, 255, 0.4);
  animation: tree-pip-pulse 1.4s ease-in-out infinite;
}

/* Animates the INDEPENDENT `scale` property rather than `transform: scale()`.
   Why it matters: .controller-focused sets `transform: translateY(-4px) !important`,
   and an !important declaration outranks a CSS animation -- so as soon as the
   + button took controller focus (which now happens on every tab switch) this
   pulse was overridden and the button froze at 1.03, i.e. it visibly SHRANK
   from its 1.0-1.35 pulse. `scale` is a separate property that composes with
   `transform` instead of competing with it, so the pulse keeps running and
   focus/hover scale on top of it. Also used by .tree-fork-option.pending,
   which gains the same immunity. */
@keyframes tree-pip-pulse {
  0%, 100% { scale: 1; }
  50% { scale: 1.35; }
}

.tree-fork {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex-shrink: 0;
  cursor: pointer;
  padding: 2px;
  border-radius: 10px;
  transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

:where(body:not(.gamepad-active)) .tree-fork:hover,
.tree-fork:focus,
.tree-fork.controller-focused {
  outline: 2px solid rgb(var(--c-focus)) !important;
  box-shadow: 0 0 16px rgba(var(--c-focus), 0.75) !important;
  border-radius: 10px;
  transform: translateY(-2px);
}

.tree-fork-option {
  min-width: 108px;
  max-width: 150px;
  padding: 6px 10px;
  border-radius: 8px;
  border: 1.5px solid rgba(255, 255, 255, 0.1);
  background: rgba(25, 20, 46, 0.7);
  font-size: 0.66rem;
  line-height: 1.25;
  color: var(--color-text-muted);
  text-align: center;
  cursor: pointer;
  transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
  user-select: none;
}

:where(body:not(.gamepad-active)) .tree-fork-option:hover,
.tree-fork-option:focus {
  border-color: rgb(var(--c-focus)) !important;
  box-shadow: 0 0 14px rgba(var(--c-focus), 0.7) !important;
  transform: translateY(-2px);
  outline: none;
}

.tree-fork-option.controller-focused {
  border-color: rgb(var(--c-focus)) !important;
  box-shadow: 0 0 18px rgba(var(--c-focus), 0.9) !important;
  transform: translateY(-2px) !important;
  outline: 2px solid rgb(var(--c-focus)) !important;
}


.tree-preview-choice-card {
  flex: 1;
  padding: 8px 12px;
  background: rgba(25, 20, 48, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-top: 3px solid rgb(var(--c-sky));
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  transition: all 0.2s ease;
}

.tree-preview-choice-card.inspected {
  background: rgba(35, 28, 65, 0.85);
  border-color: rgba(var(--c-sky), 0.4);
}

.tree-preview-choice-card.picked {
  background: rgba(var(--c-success), 0.12);
  border-color: rgba(var(--c-success), 0.4);
}

.tree-preview-card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.tree-preview-choice-name {
  font-family: var(--font-display);
  font-size: 0.82rem;
  font-weight: 700;
  color: #ffffff;
}

.path-badge {
  font-size: 0.65rem;
  padding: 2px 8px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.1);
  color: var(--color-text-muted);
}

.path-badge.active-path {
  background: rgba(var(--c-success), 0.25);
  color: rgb(var(--c-success));
  font-weight: bold;
}

.tree-preview-choice-desc {
  font-size: 0.72rem;
  color: #d1d5db;
  line-height: 1.35;
}

.tree-fork-option .fork-option-name {
  display: block;
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 700;
  margin-bottom: 2px;
}

.tree-fork-option.locked {
  opacity: 0.35;
  filter: grayscale(0.6);
}

.tree-fork-option.selected {
  border-color: var(--fork-color, var(--color-primary));
  background: rgba(0, 0, 0, 0.3);
  color: #fff;
  box-shadow: 0 0 12px var(--fork-glow, var(--color-primary-glow));
}

.tree-fork-option.unselected {
  opacity: 0.4;
}

.tree-fork-option.pending {
  border-color: rgba(255, 255, 255, 0.5);
  animation: tree-pip-pulse 1.6s ease-in-out infinite;
}

.tree-node-label {
  position: absolute;
  top: -18px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 0.6rem;
  color: var(--color-text-muted);
  white-space: nowrap;
}


/* ==========================================================================
   Modernized Run-End / Game Over / Victory Stage Frame
   ========================================================================== */
#game-over-screen {
  z-index: 10000 !important;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.5s ease;
}

#game-over-screen.victory-theme {
  background: radial-gradient(circle at 50% 30%, rgba(var(--c-gold), 0.18) 0%, rgba(8, 6, 15, 0.94) 80%) !important;
}

#game-over-screen.defeat-theme {
  background: radial-gradient(circle at 50% 30%, rgba(var(--c-danger), 0.14) 0%, rgba(8, 6, 15, 0.96) 80%) !important;
}

.game-over-stage-frame {
  width: min(1280px, calc(96 * var(--vvw))) !important;
  max-width: calc(96 * var(--vvw)) !important;
  height: min(580px, calc(92 * var(--vvh))) !important;
  max-height: calc(92 * var(--vvh)) !important;
  display: flex !important;
  flex-direction: column !important;
  align-items: stretch !important;
  padding: calc(14px * var(--ui-global-scale, 1)) calc(18px * var(--ui-global-scale, 1)) !important;
  gap: 10px !important;
  box-sizing: border-box !important;
  /* window look (fill, border, corners, glow) comes from the chamfer kit: .cut.cx-win, 03b-chamfer-kit.css */
  overflow: hidden !important;
}

/* Victory: the gold window accent (--acc) is set in 03b-chamfer-kit.css. */

@media (min-height: 720px) and (min-width: 1024px) {
  .game-over-stage-frame {
    height: min(640px, calc(92 * var(--vvh))) !important;
  }
}

.game-over-header-row {
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  flex-shrink: 0;
}

.game-over-title {
  font-family: var(--font-display);
  font-size: 2.2rem;
  color: rgb(var(--c-danger));
  text-shadow: 0 0 25px rgba(var(--c-danger), 0.6);
  font-weight: 800;
  margin: 0;
  letter-spacing: 0.1em;
}

.game-over-title.victory {
  color: rgb(var(--c-gold));
  text-shadow: 0 0 25px rgba(var(--c-gold), 0.6);
}

.game-over-subtitle {
  font-size: 0.88rem;
  color: rgb(var(--c-text-muted));
  margin: 0;
}

.game-over-body-grid {
  display: grid;
  grid-template-columns: 1.05fr 1.15fr 0.95fr;
  gap: 12px;
  min-height: 0;
  flex: 1 1 auto;
  height: 100%;
  width: 100% !important;
  box-sizing: border-box !important;
}

/* 3-Column stage layout */
.game-over-column {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 0;
  height: 100%;
  overflow: hidden;
}

/* Left Hero Column */
.game-over-hero-column {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 0;
}

.game-over-hero-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 8px 12px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
  flex-shrink: 0;
}

.game-over-hero-identity-row {
  display: flex;
  align-items: center;
  gap: 10px;
}

.game-over-hero-ship-wrap {
  width: 44px;
  height: 44px;
  background: rgba(0, 0, 0, 0.45);
  border: 1.5px solid rgba(255, 255, 255, 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.game-over-hero-ship-wrap svg {
  width: 32px;
  height: 32px;
  filter: drop-shadow(0 0 6px rgba(var(--c-primary), 0.5));
}

.game-over-hero-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.game-over-hero-name {
  font-size: 1.1rem;
  font-weight: 800;
  color: rgb(var(--c-text-main));
  letter-spacing: 0.04em;
}

.game-over-hero-badge {
  font-size: 0.7rem;
  font-weight: 700;
  color: rgb(var(--c-sky));
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* Quick Run Badges */
.game-over-run-badges {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 4px;
  background: rgba(0, 0, 0, 0.35);
  padding: 6px 8px;
  border: 1px solid rgba(255, 255, 255, 0.06);
  text-align: center;
}

.game-over-badge-item {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.game-over-badge-label {
  font-size: 0.58rem;
  color: rgb(var(--c-slate));
  font-weight: 700;
  letter-spacing: 0.06em;
}

.game-over-badge-val {
  font-size: 0.95rem;
  font-weight: 800;
}

/* Final Build Loadout Section */
.game-over-loadout-section {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 10px;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid rgba(255, 255, 255, 0.06);
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}

.game-over-section-heading {
  font-size: 0.74rem;
  font-weight: 700;
  color: rgb(var(--c-violet));
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* Rich Item Lists */
.game-over-loadout-scroll {
  display: flex;
  flex-direction: column;
  gap: 4px;
  overflow-y: auto;
  min-height: 0;
  flex: 1 1 auto;
  padding-right: 5px;
}

.game-over-items-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 0;
  flex: 0 0 auto;
}

.game-over-item-card {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 6px;
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 6px;
  transition: all 0.18s ease;
  flex-shrink: 0;
}

:where(body:not(.gamepad-active)) .game-over-item-card:hover {
  background: rgba(255, 255, 255, 0.05);
  border-color: rgba(var(--c-primary), 0.35);
}

.game-over-item-icon {
  width: 26px;
  height: 26px;
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid rgba(255, 255, 255, 0.08);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  flex-shrink: 0;
}

.game-over-item-icon img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.game-over-item-info {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  flex: 1;
}

.game-over-item-name-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}

.game-over-item-name {
  font-size: 0.74rem;
  font-weight: 700;
  color: rgb(var(--c-text-main));
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.game-over-item-lvl {
  font-size: 0.62rem;
  font-weight: 800;
  color: rgb(var(--c-gold));
  background: rgba(var(--c-gold), 0.12);
  padding: 1px 4px;
  border-radius: 3px;
  border: 1px solid rgba(var(--c-gold), 0.25);
  line-height: 1;
}

.game-over-item-lvl.max {
  color: #f59e0b;
  border-color: #f59e0b;
  box-shadow: 0 0 6px rgba(245, 158, 11, 0.4);
}

.game-over-path-pill {
  font-size: 0.62rem;
  color: rgb(var(--c-sky));
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.game-over-gear-slot-label {
  font-size: 0.58rem;
  text-transform: uppercase;
  color: rgb(var(--c-slate));
  font-weight: 600;
}

.game-over-rarity-pill {
  font-size: 0.6rem;
  font-weight: 700;
  text-transform: uppercase;
  padding: 1px 4px;
  border-radius: 3px;
  line-height: 1;
}

.game-over-loadout-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 5px;
}

.game-over-loadout-slot {
  aspect-ratio: 1 / 1;
  background: rgba(0, 0, 0, 0.45);
  border: 1.5px solid rgba(255, 255, 255, 0.1);
  border-radius: 6px;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.game-over-loadout-slot img {
  width: 75%;
  height: 75%;
  object-fit: cover;
}

.game-over-loadout-slot.empty {
  border-style: dashed;
  border-color: rgba(255, 255, 255, 0.06);
}

.game-over-slot-lvl {
  position: absolute;
  bottom: 1px;
  right: 2px;
  font-size: 0.58rem;
  font-weight: 800;
  color: rgb(var(--c-gold));
  text-shadow: 0 1px 2px #000;
  background: rgba(0, 0, 0, 0.75);
  padding: 0 2px;
  border-radius: 2px;
}

/* Right Stats Column & Tabs */
.game-over-stats-column,
.game-over-records-column {
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow: hidden;
  min-height: 0;
  height: 100%;
  flex: 1 1 auto;
}

/* Controller-Focused Active Column Highlight (Gamepad Traversal) */
.game-over-hero-column.controller-column-focused,
.game-over-stats-column.controller-column-focused,
.game-over-records-column.controller-column-focused {
  /* square, to match the chamfer menu kit; the column is not clipped, so the glow still shows */
  box-shadow: 0 0 14px rgba(var(--c-primary), 0.35), inset 0 0 0 1.5px rgba(var(--c-primary), 0.55) !important;
  transition: box-shadow 0.2s ease, border-color 0.2s ease;
}

#game-over-screen.victory-theme .game-over-hero-column.controller-column-focused,
#game-over-screen.victory-theme .game-over-stats-column.controller-column-focused,
#game-over-screen.victory-theme .game-over-records-column.controller-column-focused {
  box-shadow: 0 0 14px rgba(var(--c-gold), 0.4), inset 0 0 0 1.5px rgba(var(--c-gold), 0.65) !important;
}

.game-over-tabs-nav {
  display: none;
  width: 100%;
  flex-shrink: 0;
  /* segmented control: the chamfered frame, the 3px inset and the gap come from the kit
     (css/03b-chamfer-kit.css section 18) */
}

.game-over-tab-btn {
  flex: 1;
  padding: 5px 8px;
  font-size: 0.76rem;
  font-weight: 700;
  font-family: var(--font-display, inherit);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  display: flex;
  align-items: center;
  justify-content: center;
  /* colour / fill / active / hover / focus: segmented control in css/03b-chamfer-kit.css section 18 */
}

.game-over-tab-panel {
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow-y: auto;
  min-height: 0;
  height: 100%;
  flex: 1 1 auto;
  padding-right: 2px;
}

.game-over-card-section {
  padding: 8px 10px;
  background: rgba(8, 6, 15, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.07);
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 0;
  height: 100%;
}

.game-over-subpanel {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 0;
  flex: 0 0 auto;
}

.game-over-subpanel.grow {
  flex: 1 1 auto;
}

.game-over-stat-pair-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  flex-shrink: 0;
}

.game-over-3stat-row {
  grid-template-columns: 1fr 1fr 1fr;
}

.game-over-stat-box-stacked {
  background: rgba(0, 0, 0, 0.4);
  padding: 6px 4px;
  border: 1px solid rgba(255, 255, 255, 0.06);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 2px;
}

.game-over-stat-box-stacked .game-over-stat-box-label {
  font-size: 0.58rem;
  color: rgb(var(--c-slate));
  font-weight: 700;
  letter-spacing: 0.06em;
}

.game-over-stat-box-stacked .game-over-stat-box-val {
  font-size: 1.05rem;
  font-weight: 800;
}

.game-over-weapon-breakdown-list {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-height: 0;
  flex-shrink: 0;
}

.weapon-dmg-bar-row {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 5px 7px;
  background: rgba(255, 255, 255, 0.02);
  border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.04);
  flex-shrink: 0;
}

.weapon-dmg-bar-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.78rem;
}

.weapon-dmg-bar-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
}

.weapon-dmg-bar-title img {
  width: 18px;
  height: 18px;
  border-radius: 3px;
}

.weapon-dmg-bar-track {
  width: 100%;
  height: 6px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 3px;
  overflow: hidden;
}

.weapon-dmg-bar-fill {
  height: 100%;
  border-radius: 3px;
  background: linear-gradient(90deg, rgb(var(--c-secondary)), rgb(var(--c-primary)));
  box-shadow: 0 0 6px rgba(var(--c-secondary), 0.4);
}

.game-over-enemy-kills-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3px 5px;
  flex-shrink: 0;
}

.game-over-badge-pill {
  font-size: 0.64rem;
  padding: 2px 6px;
  background: rgba(var(--c-cyan), 0.12);
  border: 1px solid rgba(var(--c-cyan), 0.3);
  color: rgb(var(--c-cyan));
  font-weight: 700;
}

/* Progression & Records Column */
.game-over-points-reward-card {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: linear-gradient(135deg, rgba(var(--c-gold), 0.12) 0%, rgba(20, 16, 36, 0.6) 100%);
  border: 1.5px solid rgba(var(--c-gold), 0.4);
  box-shadow: 0 0 15px rgba(var(--c-gold), 0.15);
  flex-shrink: 0;
}

.game-over-points-reward-icon {
  display: flex;
  align-items: center;
  justify-content: center;
}

.game-over-records-highlight-card {
  padding: 6px 8px;
  background: rgba(var(--c-gold), 0.05);
  border: 1px solid rgba(var(--c-gold), 0.2);
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex-shrink: 0;
}

.game-over-record-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 6px;
  background: rgba(245, 158, 11, 0.15);
  border: 1px solid rgba(245, 158, 11, 0.4);
  border-radius: 4px;
  font-size: 0.66rem;
  font-weight: 700;
  color: rgb(var(--c-gold));
}

.game-over-economy-card {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  flex-shrink: 0;
}

.game-over-econ-pill {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 5px 8px;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid rgba(255, 255, 255, 0.06);
}

.game-over-econ-label {
  font-size: 0.58rem;
  color: rgb(var(--c-slate));
  font-weight: 700;
  letter-spacing: 0.05em;
}

.game-over-econ-val {
  font-size: 0.88rem;
  font-weight: 800;
}

.game-over-lifetime-list {
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  flex: 1 1 auto;
  gap: 3px;
  font-size: 0.78rem;
  padding: 2px 0;
}

.game-over-lifetime-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 4px 6px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.04);
  background: rgba(255, 255, 255, 0.015);
}

.game-over-combat-subpanels-row {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding-right: 4px;
}

.game-over-combat-subpanels-row > .game-over-subpanel {
  flex: 0 0 auto;
  flex-shrink: 0;
  width: 100%;
  box-sizing: border-box;
}

.game-over-records-subpanels-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding-right: 4px;
}

.game-over-records-run-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex-shrink: 0;
}

.game-over-records-life-group {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}

.game-over-footer {
  display: flex;
  gap: 10px;
  width: 100%;
  padding-top: 2px;
}

.game-over-action-btn {
  flex: 1;
  min-height: 38px;
  font-size: 0.88rem;
  font-weight: 700;
}

/* ==========================================================================
   Scrollbars on the Game-Over / Victory / Defeat screen
   ==========================================================================
   The scrollbar shape (square accent thumb with glow, ticked track) is the global one in
   css/03b-chamfer-kit.css section 17; this screen only picks the thumb colour. The old
   scrollbar-width / scrollbar-color declarations were removed (see the note there). */
#game-over-stage-frame {
  --sb: var(--c-primary);
}

#game-over-screen.victory-theme #game-over-stage-frame {
  --sb: var(--c-gold);
}

#game-over-screen.defeat-theme #game-over-stage-frame {
  --sb: var(--c-danger);
}

/* Widescreen Desktop / Steam Deck Rules */
@media (min-width: 901px) and (min-height: 621px) {
  .game-over-tabs-nav {
    display: none !important;
  }
  .game-over-body-grid {
    display: grid !important;
    grid-template-columns: 1.05fr 1.15fr 0.95fr !important;
    gap: 12px !important;
    width: 100% !important;
  }
  .game-over-column,
  .game-over-hero-column,
  .game-over-stats-column,
  .game-over-records-column {
    display: flex !important;
  }
}

/* Mobile & Compact Screen Adaptation */
@media (max-width: 900px), (max-height: 620px) {
  .game-over-stage-frame {
    height: calc(94 * var(--vvh)) !important;
    max-height: calc(94 * var(--vvh)) !important;
    width: calc(98 * var(--vvw)) !important;
    padding: 8px 12px !important;
    gap: 6px !important;
    align-items: stretch !important;
  }
  .game-over-title {
    font-size: 1.35rem !important;
  }
  .game-over-subtitle {
    font-size: 0.72rem !important;
  }
  .game-over-tabs-nav {
    display: flex !important;
  }
  .game-over-body-grid {
    grid-template-columns: 1fr !important;
    display: flex !important;
    flex-direction: column !important;
    width: 100% !important;
    flex: 1 1 auto !important;
    min-height: 0 !important;
    gap: 0 !important;
  }
  .game-over-column,
  .game-over-hero-column,
  .game-over-stats-column,
  .game-over-records-column {
    display: none !important;
    width: 100% !important;
    height: 100% !important;
    min-height: 0 !important;
    flex: 1 1 auto !important;
    box-sizing: border-box !important;
  }
  .game-over-column.mobile-active,
  .game-over-hero-column.mobile-active,
  .game-over-stats-column.mobile-active,
  .game-over-records-column.mobile-active {
    display: flex !important;
  }
  .game-over-hero-card {
    padding: 6px 10px !important;
    gap: 6px !important;
  }
  .game-over-hero-ship-wrap {
    width: 34px !important;
    height: 34px !important;
  }
  .game-over-hero-ship-wrap svg {
    width: 24px !important;
    height: 24px !important;
  }
  .game-over-hero-name {
    font-size: 0.95rem !important;
  }
  .game-over-badge-val {
    font-size: 0.85rem !important;
  }
  .game-over-loadout-section {
    padding: 6px 10px !important;
    gap: 5px !important;
  }
  .game-over-section-heading {
    font-size: 0.7rem !important;
  }
  .game-over-tab-btn {
    padding: 4px 6px !important;
    font-size: 0.7rem !important;
    min-height: 30px !important;
  }
  .game-over-card-section {
    padding: 6px 10px !important;
    gap: 6px !important;
    width: 100% !important;
    box-sizing: border-box !important;
  }
  .game-over-stat-box-stacked {
    padding: 4px !important;
  }
  .game-over-stat-box-stacked .game-over-stat-box-val {
    font-size: 0.95rem !important;
  }
  .game-over-footer {
    gap: 8px !important;
    padding-top: 2px !important;
  }
  .game-over-action-btn {
    min-height: 32px !important;
    font-size: 0.78rem !important;
    padding: 4px 8px !important;
  }
}

/* Mobile Landscape 2-pane sub-layout for each tab */
@media (min-width: 580px) and (max-height: 620px) {
  .game-over-hero-column.mobile-active {
    display: grid !important;
    grid-template-columns: 0.95fr 1.25fr !important;
    gap: 10px !important;
    align-items: stretch !important;
  }
  .game-over-hero-column.mobile-active .game-over-hero-card {
    height: 100% !important;
    justify-content: space-evenly !important;
    box-sizing: border-box !important;
  }
  .game-over-hero-column.mobile-active .game-over-loadout-section {
    height: 100% !important;
    box-sizing: border-box !important;
  }

  .game-over-combat-subpanels-row {
    display: flex !important;
    flex-direction: column !important;
    gap: 8px !important;
    flex: 1 1 auto !important;
    min-height: 0 !important;
    overflow-y: auto !important;
    padding-right: 4px !important;
  }
  .game-over-combat-subpanels-row > .game-over-subpanel {
    flex: 0 0 auto !important;
    flex-shrink: 0 !important;
    width: 100% !important;
    box-sizing: border-box !important;
  }

  .game-over-records-subpanels-row {
    display: grid !important;
    grid-template-columns: 1.05fr 1fr !important;
    gap: 8px !important;
    flex: 1 1 auto !important;
    min-height: 0 !important;
    height: 100% !important;
  }
  .game-over-records-life-group {
    display: flex !important;
    flex-direction: column !important;
    height: 100% !important;
    min-height: 0 !important;
  }
  .game-over-lifetime-list {
    height: 100% !important;
    justify-content: space-between !important;
  }
}

@media (max-width: 650px) {
  .game-over-body-grid {
    grid-template-columns: 1fr !important;
  }
}

/* Weapon Tag Badges */
.weapon-tag-badges {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
  margin: 4px 0 6px 0;
}

.weapon-tag-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 2px 7px;
  font-family: var(--font-display, inherit);
  font-size: 0.65rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  line-height: 1.2;
  border: 1px solid rgba(255, 255, 255, 0.25);
  background: rgba(0, 0, 0, 0.45);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}

/* Universal Inline Vector SVG Icons (Strict No-Emojis Policy) */
.inline-svg-icon {
  display: inline-block;
  vertical-align: -0.15em;
  width: 1em;
  height: 1em;
  stroke: currentColor;
  fill: none;
  flex-shrink: 0;
  pointer-events: none;
}

.svg-icon-coin {
  color: rgb(var(--c-gold));
  vertical-align: -0.12em;
}

.svg-icon-sp {
  color: rgb(var(--c-primary));
  vertical-align: -0.12em;
}

.svg-icon-overclock {
  color: rgb(var(--c-violet));
  vertical-align: -0.12em;
}

.svg-icon-lock {
  color: rgba(255, 255, 255, 0.6);
}

.svg-icon-check {
  color: rgb(var(--c-success));
}

.svg-icon-cross {
  color: rgb(var(--c-danger));
}

.svg-icon-trash {
  color: #f87171;
}

/* Button Component styles: MOVED. .btn / .btn-primary / .btn-secondary (and their hover, active and
   disabled states) are now the chamfer button system, css/03b-chamfer-kit.css section 12. The
   rounded gradient + glow rules that lived here were deleted, not out-ranked. */
:where(body:not(.gamepad-active)) .upgrade-card:hover .btn-secondary {
  --bd: rgb(var(--acc));
  --bg: rgb(var(--acc));
  color: rgb(var(--c-bg));
}

/* Compact iOS-style toggle switch -- replaces the old full-width ON/OFF
   .btn-primary/.btn-secondary pair for binary settings (Damage Numbers,
   Tutorial Prompts in the Gameplay settings tab, js/settings.js). Markup is
   a single <button role="switch"> with a knob <span> child rather than a
   native <input type="checkbox">, so it keeps working with the existing
   click()-based gamepad focus system (js/main-loop.js's pollGamepadMenu())
   without needing a separate input path. State is driven entirely by the
   .active class + aria-checked, toggled in js/settings.js's updateSettingsUI().*/




/* The toggle switch look (chamfered track, square knob, ON/OFF label) lives in css/03b-chamfer-kit.css,
   section 13. State is still the .active class + aria-checked, driven by js/settings.js. */

/* Animations */
@keyframes pulse {
  0%, 100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0.9;
    transform: scale(0.98);
  }
}

.animate-pulse {
  animation: pulse 3s infinite ease-in-out;
}

@keyframes spin-slow {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.animate-spin-slow {
  animation: spin-slow 12s infinite linear;
}

/* Grids and layout alignments */
.choices-grid {
  display: flex;
  gap: 16px;
  justify-content: center;
  width: 100%;
}

.shop-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 12px;
  width: 100%;
}

.shop-card {
  position: relative;
  /* frame, fill and rarity colour: the shared card treatment, css/03b-chamfer-kit.css section 21 */
  /* Deliberately NOT scaled against --ui-global-scale, unlike .glass-panel/
     .upgrade-card above -- this card is a grid item inside .shop-grid's
     `grid-template-columns: repeat(3, 1fr)` with no minmax() safety net,
     and this file couldn't be rendered in a real browser to confirm
     whether growing its explicit width/padding would overflow that grid
     (vs. the column track just growing to absorb it) rather than scaling
     cleanly. Left untouched to avoid risking a broken shop grid on a
     heavily-used screen; the panel around it (.wide-panel above) and the
     card's own rem-based text still grow. Worth a manual check at 1440p/4K
     to see whether this one is worth revisiting.
  */
  padding: 16px 12px;
  display: flex;
  flex-direction: column;
  align-items: center;
  transition: all 0.25s ease;
  cursor: pointer;
  width: 210px;
  flex-shrink: 0;
  box-sizing: border-box;
}

:where(body:not(.gamepad-active)) .shop-card:hover {
  transform: translateY(-4px);
}

.shop-card.sold-out {
  opacity: 0.3;
  pointer-events: none;
}

/* .shop-card.cant-afford frame / hover tints: kit variables, css/03b-chamfer-kit.css section 21 */

/* "Lock" state (can't afford yet): deliberately NOT the gold "Buy" gradient
   below, so the two are distinguishable at a glance without reading the
   button text. Cool slate-blue reads as "reserve for later", not "purchase". */
.shop-card.cant-afford .btn-buy {
  background: linear-gradient(90deg, #64748b, #475569);
  color: #ffffff;
}

:where(body:not(.gamepad-active)) .shop-card.cant-afford:hover .btn-buy {
  box-shadow: 0 4px 10px rgba(100, 116, 139, 0.4);
}

.shop-card h3 {
  font-size: 0.95rem;
  color: #fff;
  margin-bottom: 4px;
  text-align: center;
}

.shop-card .card-desc {
  font-size: 0.75rem;
  color: var(--color-text-muted);
  text-align: center;
  margin-bottom: 12px;
  line-height: 1.3;
  flex-grow: 1;
}


.shop-card .btn-buy {
  background: linear-gradient(90deg, rgb(var(--c-gold)), #f59e0b);
  border: none;
  color: rgb(var(--c-bg));
  font-weight: 700;
  text-transform: uppercase;
  font-size: 0.75rem;
  padding: 6px 16px;
  border-radius: 6px;
  cursor: pointer;
  width: 100%;
  transition: all 0.2s ease;
}

:where(body:not(.gamepad-active)) .shop-card:hover .btn-buy {
  box-shadow: 0 4px 10px rgba(var(--c-gold), 0.4);
  transform: scale(1.02);
}


/* Brief input lockout on the gear-swap ("NEW GEAR FOUND") modal -- applied
   to the Scrap/Equip button row for the first second after the modal opens
   (triggerGearSwap(), js/gear.js) so a dash/attack input still held from
   the moment the item dropped can't be misread as an instant confirm on
   whichever button happened to be focused/under the cursor. Purely visual;
   the actual block is the window.gearSwapOpenTime timestamp check in the
   click handlers (js/init.js) and gamepad polling (js/main-loop.js). */
.gear-swap-buttons-locked .btn {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

/* Weapon Drop Screen & Dedicated Swap View */
.weapon-drop-panel {
  width: min(calc(92 * var(--vvw)), 680px);
  box-sizing: border-box;
  /* Anchor for the absolutely-positioned weapon-equip burst nodes
     (spawnWeaponEquipBurst, js/upgrades.js): the radial shockwave ring and
     flash are appended to this panel so they expand over the cards without
     being clipped by any card's own `overflow: hidden`. */
  position: relative;
}

.weapon-swap-preview-card {
  display: flex;
  align-items: center;
  gap: 12px;
  background: rgba(var(--c-sky), 0.08);
  border: 1px solid rgba(var(--c-sky), 0.35);
  border-radius: 8px;
  padding: 8px 12px;
  box-sizing: border-box;
  text-align: left;
}

.weapon-swap-preview-icon {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  background: rgba(15, 23, 42, 0.6);
  border: 1px solid rgba(var(--c-sky), 0.4);
}

.weapon-swap-preview-icon img {
  width: 44px;
  height: 44px;
  object-fit: cover;
  border-radius: 8px;
}

.weapon-swap-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  width: 100%;
  box-sizing: border-box;
}

.swap-equipped-card {
  display: flex;
  align-items: center;
  gap: 8px;
  /* frame / fill / hover / focus: css/03b-chamfer-kit.css section 21 */
  padding: 8px 10px;
  cursor: pointer;
  transition: all 0.2s ease;
  min-height: 48px;
  box-sizing: border-box;
  text-align: left;
  user-select: none;
}

/* .swap-equipped-card hover (lift, danger tint) and controller focus: css/03b-chamfer-kit.css section 21 */

.swap-equipped-icon {
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.25rem;
  background: rgba(0, 0, 0, 0.4);
  border: 1px solid rgba(255, 255, 255, 0.15);
}

.swap-equipped-icon img {
  width: 36px;
  height: 36px;
  object-fit: cover;
  border-radius: 6px;
}

.swap-equipped-info {
  display: flex;
  flex-direction: column;
  gap: 1px;
  overflow: hidden;
  flex: 1;
}

.swap-equipped-name {
  font-size: 0.82rem;
  font-weight: bold;
  color: #fff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.swap-equipped-lvl {
  font-size: 0.68rem;
  color: rgb(var(--c-gold));
  font-family: var(--font-display);
  font-weight: 600;
}

.swap-equipped-action {
  font-size: 0.65rem;
  font-weight: bold;
  color: rgb(var(--c-danger));
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: rgba(var(--c-danger), 0.15);
  padding: 2px 4px;
  border-radius: 3px;
  border: 1px solid rgba(var(--c-danger), 0.3);
  margin-top: 2px;
  align-self: flex-start;
}

/* .weapon-drop-action-btn.controller-focused (border glow + scale) removed: the buttons are
   chamfered .btn now and focus is the kit variant, css/03b-chamfer-kit.css section 4. */

/* Mobile & Short Viewport Overrides */
@media (max-height: 600px) {
  #weapon-drop-screen .weapon-drop-panel {
    max-height: calc(96 * var(--vvh));
    padding: 8px 14px !important;
    gap: 4px !important;
  }
  #weapon-drop-screen .vibe-orb-icon {
    width: 24px !important;
    height: 24px !important;
    margin-bottom: 2px !important;
  }
  #weapon-drop-screen .section-title {
    font-size: 1.05rem !important;
    margin-bottom: 0px !important;
  }
  #weapon-drop-screen .section-desc {
    font-size: 0.72rem !important;
  }
  #weapon-drop-screen .upgrade-card {
    padding: 8px 10px !important;
    gap: 2px !important;
  }
  #weapon-drop-screen .card-icon.weapon-drop-banner {
    width: 58px !important;
    height: 58px !important;
    min-width: 58px !important;
    min-height: 58px !important;
    margin-bottom: 4px !important;
    padding: 3px !important;
  }
  #weapon-drop-screen .card-icon.weapon-drop-banner img.weapon-drop-icon {
    width: 100% !important;
    height: 100% !important;
    object-fit: contain !important;
  }
  #weapon-drop-screen .upgrade-card h3 {
    font-size: 0.85rem !important;
  }
  #weapon-drop-screen .upgrade-card .card-desc {
    font-size: 0.7rem !important;
  }
  .weapon-swap-preview-card {
    padding: 4px 8px !important;
    gap: 8px !important;
  }
  .weapon-swap-preview-icon, .weapon-swap-preview-icon img {
    width: 32px !important;
    height: 32px !important;
  }
  .weapon-swap-grid {
    grid-template-columns: repeat(3, 1fr) !important;
    gap: 5px !important;
  }
  .swap-equipped-card {
    padding: 4px 6px !important;
    min-height: 40px !important;
    gap: 6px !important;
  }
  .swap-equipped-icon, .swap-equipped-icon img {
    width: 28px !important;
    height: 28px !important;
  }
  .swap-equipped-name {
    font-size: 0.72rem !important;
  }
  .swap-equipped-lvl {
    font-size: 0.62rem !important;
  }
  .swap-equipped-action {
    display: none !important;
  }
  .weapon-drop-action-btn {
    padding: 6px 10px !important;
    font-size: 0.78rem !important;
  }
}

@media (max-width: 640px) and (min-height: 601px) {
  .weapon-swap-grid {
    grid-template-columns: repeat(2, 1fr) !important;
  }
}

/* Shop Card Rarity Tiers: the frame / wash / pulse is --r in css/03b-chamfer-kit.css section 21; only the
   title and buy-button colours stay here. */
.shop-card.rarity-magic h3 {
  color: rgb(var(--c-info)) !important;
  text-shadow: 0 0 6px rgba(var(--c-info), 0.3);
}

.shop-card.rarity-rare h3 {
  color: rgb(var(--c-gold)) !important;
  text-shadow: 0 0 6px rgba(var(--c-gold), 0.3);
}

.shop-card.rarity-legendary h3 {
  color: rgb(var(--c-orange)) !important;
  text-shadow: 0 0 8px rgba(var(--c-orange), 0.4);
}
.shop-card.rarity-legendary .btn-buy {
  background: linear-gradient(135deg, rgb(var(--c-orange)), #c2410c) !important;
  border-color: rgb(var(--c-orange)) !important;
  color: #090314 !important;
}
:where(body:not(.gamepad-active)) .shop-card.rarity-legendary .btn-buy:hover {
  background: #ffffff !important;
  color: #c2410c !important;
}

.shop-card.rarity-ultimate h3 {
  color: rgb(var(--c-primary)) !important;
  text-shadow: 0 0 12px rgba(var(--c-primary), 0.5);
}
.shop-card.rarity-ultimate .btn-buy {
  background: linear-gradient(135deg, rgb(var(--c-primary)), #701a75) !important;
  border-color: rgb(var(--c-primary)) !important;
  color: #ffffff !important;
}
:where(body:not(.gamepad-active)) .shop-card.rarity-ultimate .btn-buy:hover {
  background: #ffffff !important;
  color: #701a75 !important;
}

/* rarity-legendary-pulse / rarity-ultimate-pulse removed (Phase 3b): superseded by cx-border-pulse (css/03b section 21). */

/* Gear Refactor / Empower modal (js/gear-refactor.js) -- selectable affix
   row list. Visual language deliberately echoes .gear-card-stat (bullet
   dot / star for overclocked lines) elsewhere in this file, but each row
   here is an actual clickable target instead of a plain <li>, so it needs
   its own hover/selected/disabled states on top of that. */
.gear-refactor-affix-list {
  list-style: none;
  margin: 0;
  padding: 2px 4px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 6px;
  text-align: left;
}

.gear-refactor-affix-row {
  position: relative;
  padding: 11px 36px 11px 16px;
  font-size: 0.85rem;
  color: rgba(255, 255, 255, 0.85);
  background: rgba(255, 255, 255, 0.04);
  border: 1.5px solid rgba(255, 255, 255, 0.08);
  cursor: pointer;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

:where(body:not(.gamepad-active)) .gear-refactor-affix-row:hover {
  background: rgba(var(--c-cyan), 0.08);
  border-color: rgba(var(--c-cyan), 0.4);
}

/* The one affix the player has selected to reroll this pass (not yet
   necessarily paid for -- see .gear-refactor-locked-badge below for the
   permanent post-purchase marker). */
.gear-refactor-affix-row.selected {
  background: rgba(var(--c-cyan), 0.14);
  border-color: rgb(var(--c-cyan));
  box-shadow: 0 0 10px rgba(var(--c-cyan), 0.35);
}

/* Every other affix once the item has a refactorLockedAffixIndex, or every
   row on an Ultimate Vibes item (fixed affixes, never refactorable). */
.gear-refactor-affix-row.disabled {
  cursor: not-allowed;
  opacity: 0.45;
}

.gear-refactor-locked-badge {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 0.8rem;
}

/* ==========================================================================
   Gear Refactor / Empower dopamine pass (js/gear-crafting.js): staggered
   modal entrance, affix-select slam, 3-option forge cascade, choice lock-in
   with sibling dissolve, and the empower stat pump. All transform/opacity/
   filter-only so nothing runs per frame. Honours prefers-reduced-motion.
   ========================================================================== */

/* Entrance cascade -- only fires while .gear-refactor-enter is on the panel
   (added once on open, removed after the sequence). Rows slide down one by
   one via their inline --row-index. */
.gear-refactor-enter .gear-refactor-header,
.gear-refactor-enter .gear-refactor-empower-box,
.gear-refactor-enter .gear-refactor-coins-readout {
  animation: gearAffixRowIn 320ms cubic-bezier(0.18, 0.9, 0.26, 1.1) both;
}
.gear-refactor-enter .gear-refactor-empower-box { animation-delay: 55ms; }
.gear-refactor-enter .gear-refactor-coins-readout { animation-delay: 100ms; }

.gear-refactor-enter .gear-refactor-affix-row:not(.gear-refactor-option-row) {
  animation: gearAffixRowIn 320ms cubic-bezier(0.18, 0.9, 0.26, 1.1) both;
  animation-delay: calc(var(--row-index, 0) * 55ms + 55ms);
}

@keyframes gearAffixRowIn {
  0% { opacity: 0; transform: translateY(12px) scale(0.97); filter: blur(2px); }
  100% { opacity: 1; transform: none; filter: none; }
}

/* Affix select slam -- applied via .just-selected (only the frame it's first
   picked), not on every re-render. */
.gear-refactor-affix-row.just-selected {
  animation: gearAffixSelectSlam 260ms cubic-bezier(0.15, 0.9, 0.2, 1.25);
}

@keyframes gearAffixSelectSlam {
  0% { transform: scale(1); }
  40% { transform: scale(1.035); box-shadow: 0 0 22px rgba(var(--c-cyan), 0.7); }
  100% { transform: scale(1); }
}

/* 3-option forge cascade reveal (choice mode) */
.gear-refactor-option-row {
  animation: gearOptionCascade 400ms cubic-bezier(0.18, 0.9, 0.26, 1.12) both;
  animation-delay: calc(var(--option-index, 0) * 95ms);
}

@keyframes gearOptionCascade {
  0% { opacity: 0; transform: perspective(700px) translateY(16px) rotateX(16deg) scale(0.94); }
  70% { opacity: 1; transform: perspective(700px) translateY(-3px) rotateX(-2deg) scale(1.01); }
  100% { opacity: 1; transform: perspective(700px) translateY(0) rotateX(0) scale(1); }
}

/* Choice lock-in slam + sibling dissolve */
.gear-refactor-option-row.selected {
  z-index: 5;
  animation: gearOptionSlam 220ms cubic-bezier(0.15, 0.9, 0.2, 1.25);
}
@keyframes gearOptionSlam {
  0% { transform: scale(1); }
  50% { transform: scale(1.06); box-shadow: 0 0 26px rgba(var(--c-cyan), 0.75); }
  100% { transform: scale(1.02); }
}
.gear-refactor-option-row.rejected {
  pointer-events: none;
  animation: gearOptionFizzle 260ms cubic-bezier(0.25, 0.9, 0.4, 1) forwards;
}
@keyframes gearOptionFizzle {
  0% { opacity: 1; filter: none; transform: none; }
  100% { opacity: 0.15; filter: blur(2px) grayscale(80%); transform: scale(0.96); }
}

/* Empower stat pump -- .empower-pump on the panel briefly flashes every
   affix row and the item header as the new values render in. */
.gear-refactor-panel.empower-pump .gear-refactor-affix-row,
.gear-refactor-panel.empower-pump .gear-refactor-header {
  animation: gearEmpowerPump 420ms cubic-bezier(0.15, 0.9, 0.2, 1.15);
}
@keyframes gearEmpowerPump {
  0% { filter: brightness(1); }
  40% { filter: brightness(1.6); transform: translateY(-2px); }
  100% { filter: brightness(1); transform: none; }
}

/* Forge flash -- one-shot cyan/purple ring pulse on the panel when the
   reroll cost is paid. */
/* The window is clip-path chamfered now, which hides box-shadow, so the flash is a brightness pulse.
   The kit's cx-crt-in stays first in the list: `animation` is one property and dropping it would
   replay the CRT open when .forge-flash is removed. */
:is(#cx-boost, .overlay).active .glass-panel.cx-win.gear-refactor-panel.forge-flash {
  animation: cx-crt-in 0.45s cubic-bezier(0.2, 0.9, 0.3, 1) backwards, gearForgeFlash 460ms ease-out;
}
@keyframes gearForgeFlash {
  0% { filter: none; }
  30% { filter: brightness(1.7) saturate(1.3); }
  100% { filter: none; }
}

/* Empower 5-pip progress bar */
.gear-refactor-empower-pips {
  display: flex;
  gap: 4px;
  justify-content: center;
  margin-top: 6px;
}
.gear-refactor-empower-pip {
  width: 16px;
  height: 6px;
  /* slanted segment, matching the HUD bars (the kit has no rounded pills) */
  clip-path: polygon(3px 0, 100% 0, calc(100% - 3px) 100%, 0 100%);
  background: rgba(var(--c-gold), 0.15);
  border: 1px solid rgba(var(--c-gold), 0.3);
  transition: background 0.2s ease, box-shadow 0.2s ease;
}
.gear-refactor-empower-pip.filled {
  background: rgb(var(--c-gold));
  box-shadow: 0 0 6px rgba(var(--c-gold), 0.6);
}
.gear-refactor-empower-pip.just-filled {
  animation: gearPipFill 360ms cubic-bezier(0.15, 0.9, 0.2, 1.2);
}
@keyframes gearPipFill {
  0% { transform: scale(0.4); filter: brightness(0.6); }
  60% { transform: scale(1.3); filter: brightness(1.7); }
  100% { transform: scale(1); filter: brightness(1); }
}

/* Chamfered rows and header (css/03b-chamfer-kit.css section 24 lists): their border is 1.5px, so
   the diagonal strokes need --cx-ebw to match. The item icon is squared, like the gear slots. */
.gear-refactor-header,
.gear-refactor-affix-row {
  --cx-ebw: 1.5px;
}
.gear-refactor-header {
  --cx-ic: 12px;
}
.gear-refactor-item-icon {
  border-radius: 0 !important;
}
/* The description sits clear of the close button. */
.gear-refactor-desc {
  padding: 0 56px;
}

/* Ready shimmer on the refactor button when an affix is picked + affordable */
#gear-refactor-reroll-btn.ready {
  position: relative;
  overflow: hidden;
}
/* ::after is the kit's white focus edge on a chamfer button (css/03b-chamfer-kit.css section 4),
   which would pick this shimmer's gradient up and clip it to a frame, so the shimmer rests while
   the button is focused (the focus pulse is the cue then). */
#gear-refactor-reroll-btn.ready:not(.controller-focused):not(:focus-visible)::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(110deg, transparent 20%, rgba(255, 255, 255, 0.4) 50%, transparent 80%);
  transform: translateX(-130%);
  animation: gearBtnShimmer 1.6s ease-in-out infinite;
}
@keyframes gearBtnShimmer {
  0%, 100% { transform: translateX(-130%); }
  50% { transform: translateX(130%); }
}

/* Radial forge burst nodes (spawnGearRefactorBurst, js/gear-crafting.js) */
.gear-refactor-burst {
  position: absolute;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 40;
  border: 2px solid rgba(var(--c-cyan), 0.95);
  box-shadow: 0 0 16px rgba(var(--c-cyan), 0.8);
  transform: translate(-50%, -50%) scale(0);
  animation: gearRefactorBurst 560ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes gearRefactorBurst {
  0% { transform: translate(-50%, -50%) scale(0); opacity: 1; }
  100% { transform: translate(-50%, -50%) scale(30); opacity: 0; }
}
.gear-refactor-flash {
  position: absolute;
  width: 110px;
  height: 110px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 39;
  background: radial-gradient(circle, rgba(255, 255, 255, 0.85) 0%, rgba(var(--c-cyan), 0.45) 45%, transparent 70%);
  transform: translate(-50%, -50%) scale(0.4);
  animation: gearRefactorFlash 360ms ease-out forwards;
}
@keyframes gearRefactorFlash {
  0% { transform: translate(-50%, -50%) scale(0.4); opacity: 0.95; }
  100% { transform: translate(-50%, -50%) scale(1.8); opacity: 0; }
}

/* Gear swap comparison cards */
.gear-compare-card {
  /* frame / fill / rarity colour: css/03b-chamfer-kit.css section 21 */
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.gear-item-name {
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 800;
  margin-bottom: 4px;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.gear-item-rarity {
  font-size: 0.75rem;
  text-transform: uppercase;
  font-weight: 700;
  letter-spacing: 0.1em;
  margin-bottom: 16px;
}

.gear-item-affix-list {
  list-style: none;
  font-size: 0.85rem;
  color: var(--color-text-main);
  text-align: left;
  display: inline-block;
  margin: 0 auto;
}

.gear-item-affix-list li {
  margin-bottom: 6px;
  position: relative;
  padding-left: 16px;
  white-space: nowrap;
}

.gear-item-affix-list li::before {
  content: "•";
  color: var(--color-primary);
  position: absolute;
  left: 0;
  font-weight: bold;
  filter: drop-shadow(0 0 5px var(--color-primary-glow));
}

.gear-item-ability {
  font-size: 0.8rem;
  color: rgb(var(--c-gold));
  margin-top: 14px;
  border-top: 1px dashed rgba(255, 255, 255, 0.1);
  padding-top: 10px;
  font-style: italic;
  font-weight: 600;
  text-shadow: 0 0 8px rgba(var(--c-gold), 0.3);
}

#gear-swap-screen {
  z-index: 300 !important;
}

/* ==========================================================================
   Gear Swap / Equip modal dopamine + redesign pass (js/gear.js's
   openGearEquipModal, js/init.js's equip click): solid dark-cyber backdrop,
   right-arrow direction indicator, card entrance clash, new-loot scan sweep +
   stat flash, and an equip slam with a burst. All transform/opacity/filter-
   only (the slam/burst box-shadow are one-shot, not per-frame). Honours
   prefers-reduced-motion.
   ========================================================================== */
#gear-swap-screen .glass-panel {
  position: relative; /* anchors the equip burst nodes */
  /* Solid dark-cyber backdrop matching the refactor menu. Deliberately NOT
     !important so the one-shot equip slam box-shadow animation can play. */
  background: linear-gradient(145deg, rgba(14, 10, 26, 0.95) 0%, rgba(8, 6, 18, 0.98) 100%);
  border: 1.5px solid rgba(var(--c-primary), 0.4);
}

/* Larger type for the compare cards in THIS modal only (the shared .gear-card
   used by tooltips/shop/pause stays as-is). */
#gear-swap-screen .gear-card {
  gap: 7px;
}
#gear-swap-screen .gear-card-title {
  font-size: 1.05rem;
}
#gear-swap-screen .gear-card-subtitle {
  font-size: 0.76rem;
}
#gear-swap-screen .gear-card-ilvl {
  font-size: 0.74rem;
}
#gear-swap-screen .gear-card-stat {
  font-size: 0.8rem;
}
#gear-swap-screen .gear-card-stat-up,
#gear-swap-screen .gear-card-stat-down {
  font-size: 0.72rem;
}

/* Right-arrow direction indicator (replaces the old lightning bolt). */
.gear-swap-arrow-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  flex-shrink: 0;
  animation: gearArrowNudge 1.8s ease-in-out infinite;
}
.gear-swap-arrow-svg {
  width: 30px;
  height: 30px;
}
@keyframes gearArrowNudge {
  0%, 100% { transform: translateX(-2px); }
  50% { transform: translateX(3px); }
}

/* Card entrance clash: EQUIPPED from the left, NEW LOOT from the right. */
.gear-swap-enter #gear-swap-equipped-card {
  animation: gearSwapCardInL 420ms cubic-bezier(0.18, 0.9, 0.26, 1.1) both;
}
.gear-swap-enter #gear-swap-new-card {
  animation: gearSwapCardInR 460ms cubic-bezier(0.18, 0.9, 0.26, 1.1) both;
  animation-delay: 40ms;
}
@keyframes gearSwapCardInL {
  0% { opacity: 0; transform: translateX(-26px) scale(0.97); }
  100% { opacity: 1; transform: none; }
}
@keyframes gearSwapCardInR {
  0% { opacity: 0; transform: translateX(26px) scale(0.97); }
  100% { opacity: 1; transform: none; }
}
.gear-swap-enter .gear-swap-arrow-wrap {
  animation: gearArrowNudge 1.8s ease-in-out infinite;
}

/* New-loot power-up: gold scan sweeps down the card, green (up) deltas flash. */
.gear-swap-enter #gear-swap-new-card .gear-card {
  position: relative;
  overflow: hidden;
}
.gear-swap-enter #gear-swap-new-card .gear-card::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 45%;
  background: linear-gradient(180deg, rgba(var(--c-gold), 0.16), transparent);
  transform: translateY(-120%);
  animation: gearNewLootScan 700ms ease-in-out 240ms both;
  pointer-events: none;
}
@keyframes gearNewLootScan {
  0% { transform: translateY(-120%); }
  100% { transform: translateY(280%); }
}
.gear-swap-enter #gear-swap-new-card .gear-card-stat-up {
  animation: gearStatFlash 650ms ease-out 260ms both;
}
@keyframes gearStatFlash {
  0% { color: rgb(var(--c-cyan)); }
  45% { color: #6ee7b7; }
  100% { color: rgb(var(--c-success)); }
}

/* Equip slam on the NEW LOOT card when the player commits. */
#gear-swap-new-card.equip-slam {
  animation: gearEquipSlam 320ms cubic-bezier(0.15, 0.9, 0.2, 1.25);
}
@keyframes gearEquipSlam {
  0% { transform: scale(1); }
  50% { transform: scale(1.1); box-shadow: 0 0 30px rgba(var(--c-gold), 0.85); }
  100% { transform: scale(1.02); }
}

/* Equip burst nodes (spawnGearSwapBurst, js/gear.js) */
.gear-swap-burst-ring {
  position: absolute;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 40;
  border: 2px solid rgba(var(--c-gold), 0.95);
  box-shadow: 0 0 16px rgba(var(--c-gold), 0.8);
  transform: translate(-50%, -50%) scale(0);
  animation: gearSwapBurst 540ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes gearSwapBurst {
  0% { transform: translate(-50%, -50%) scale(0); opacity: 1; }
  100% { transform: translate(-50%, -50%) scale(30); opacity: 0; }
}
.gear-swap-burst-flash {
  position: absolute;
  width: 120px;
  height: 120px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 39;
  background: radial-gradient(circle, rgba(255, 255, 255, 0.85) 0%, rgba(var(--c-gold), 0.45) 45%, transparent 70%);
  transform: translate(-50%, -50%) scale(0.4);
  animation: gearSwapFlash 340ms ease-out forwards;
}
@keyframes gearSwapFlash {
  0% { transform: translate(-50%, -50%) scale(0.4); opacity: 0.95; }
  100% { transform: translate(-50%, -50%) scale(1.8); opacity: 0; }
}

/* ==========================================================================
   Bazaar Gamble for Loot (js/shop.js) -- the shop entry panel and the long,
   skippable reveal cinematic (charge orb -> rolling card-back -> flip reveal +
   rarity flash). Solid dark-cyber backdrop matching the refactor / gear-swap
   panels. All transform/opacity/filter-only; honours prefers-reduced-motion.
   ========================================================================== */

/* Shop-tab entry panel */
.shop-gamble-panel {
  /* Rides the .shop-gear-card layout (card-col-left / card-col-right). Its purple "gamble" flavour is
     --r: ultimate purple in css/03b-chamfer-kit.css section 21. */
}
.shop-gamble-panel .shop-gamble-title {
  color: rgb(var(--c-violet));
  text-shadow: 0 0 10px rgba(var(--c-primary), 0.5);
}
.shop-gamble-mystery-icon {
  color: rgba(var(--c-violet), 0.8);
  font-size: 2rem;
  font-weight: 800;
  font-family: var(--font-display);
  text-shadow: 0 0 12px rgba(var(--c-primary), 0.6);
}
.shop-gamble-mystery-text {
  color: rgba(var(--c-violet), 0.65) !important;
}
.shop-gamble-stat {
  color: rgba(255, 255, 255, 0.5);
  font-style: italic;
}
.shop-gamble-odds {
  font-size: 0.66rem;
  color: rgb(var(--c-gold));
  font-weight: 700;
  white-space: nowrap;
}
.shop-gamble-btn {
  min-height: 34px;
}
/* Stack the gamble card's action bar (odds text above the button) so, on a
   wide grid cell, the nowrap "4% chance at Ultimate Vibes" line can't squeeze
   the button -- it becomes a full-width row just like the other cards' buy
   buttons. */
.shop-gear-card.shop-gamble-panel .card-actions-bar {
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
}
.shop-gear-card.shop-gamble-panel .shop-gamble-odds {
  text-align: center;
}

/* Gamble confirmation: 5 mystery cards fanned in an arch, one per rarity,
   each with a "?". Shown only for the gamble confirm (js/shop.js toggles
   #inv-confirm-gamble-fan). */
.inv-confirm-gamble-fan {
  display: flex;
  justify-content: center;
  align-items: flex-end;
  height: 120px;
  margin: 0 auto 16px;
  position: relative;
  animation: gambleFanPopup 420ms cubic-bezier(0.18, 0.9, 0.26, 1.12) both;
}

#inventory-confirm-modal #inv-confirm-message {
  white-space: normal;
  word-wrap: break-word;
  overflow-wrap: break-word;
  max-width: 400px;
  margin-left: auto;
  margin-right: auto;
  line-height: 1.45;
}
.gamble-fan-card {
  /* chamfered card back, coloured by --r (section 21 of css/03b-chamfer-kit.css) */
  width: 50px;
  height: 72px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 1.4rem;
  font-weight: 800;
  text-shadow: 0 0 10px currentColor;
  margin-left: -15px;
  transform-origin: bottom center;
  pointer-events: none;
}
.gamble-fan-card:first-child { margin-left: 0; }
.gamble-fan-card:nth-child(1) { transform: rotate(-26deg); z-index: 1; }
.gamble-fan-card:nth-child(2) { transform: rotate(-13deg); z-index: 2; }
.gamble-fan-card:nth-child(3) { transform: rotate(0deg) scale(1.04); z-index: 3; }
.gamble-fan-card:nth-child(4) { transform: rotate(13deg); z-index: 2; }
.gamble-fan-card:nth-child(5) { transform: rotate(26deg); z-index: 1; }
@keyframes gambleFanPopup {
  0% { transform: scale(0.82); opacity: 0; }
  100% { transform: scale(1); opacity: 1; }
}
@media (max-width: 480px) {
  .gamble-fan-card { width: 42px; height: 62px; margin-left: -12px; font-size: 1.2rem; }
}

/* Reveal overlay panel */
#gamble-reveal-screen .glass-panel {
  position: relative;
  background: linear-gradient(145deg, rgba(14, 10, 26, 0.95) 0%, rgba(8, 6, 18, 0.98) 100%);
  border: 1.5px solid rgba(var(--c-primary), 0.4);
  width: min(560px, calc(94 * var(--vvw)));
  padding: calc(18px * var(--ui-global-scale, 1)) calc(22px * var(--ui-global-scale, 1));
}
.gamble-reveal-close {
  /* chamfered close button: css/03b-chamfer-kit.css section 16 */
  position: absolute;
  top: 10px;
  right: 12px;
  z-index: 5;
}
.gamble-reveal-title {
  font-size: 1.4rem;
  background: linear-gradient(90deg, rgb(var(--c-violet)), rgb(var(--c-primary)));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  text-align: center;
  margin: 0 0 4px;
}
.gamble-reveal-stage {
  min-height: 170px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}
.gamble-reveal-hint {
  text-align: center;
  font-size: 0.7rem;
  color: rgba(255, 255, 255, 0.5);
  margin: 10px 0 0;
}
.gamble-reveal-actions {
  display: flex;
  gap: 10px;
  width: 100%;
  margin-top: 14px;
}
.gamble-reveal-actions button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  box-sizing: border-box;
}

/* Controller A glyph on focused outcome button with high-contrast black underlay */
.gamble-btn-icon {
  display: none;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  min-width: 22px;
  background: #000000;
  border: 1.5px solid rgba(255, 255, 255, 0.45);
  border-radius: 50%;
  box-shadow: 0 0 6px rgba(0, 0, 0, 0.95), inset 0 0 2px rgba(0, 0, 0, 0.9);
  box-sizing: border-box;
  flex-shrink: 0;
  margin-right: 6px;
}

.gamble-btn-icon img {
  width: 14px !important;
  height: 14px !important;
  object-fit: contain !important;
  margin: 0 !important;
  vertical-align: middle !important;
  display: block !important;
}

body.input-gamepad #gamble-reveal-actions button.controller-focused .gamble-btn-icon,
body.gamepad-active #gamble-reveal-actions button.controller-focused .gamble-btn-icon {
  display: inline-flex !important;
}

/* Charge orb */
.gamble-charge-orb {
  position: relative;
  width: 90px;
  height: 90px;
  border-radius: 50%;
  background: radial-gradient(circle, #fff 10%, rgb(var(--c-primary)) 55%, transparent 80%);
  box-shadow: 0 0 30px rgba(var(--c-primary), 0.8);
}
.gamble-orb-core {
  position: absolute;
  inset: 18px;
  border-radius: 50%;
  background: radial-gradient(circle, #fff, rgba(var(--c-primary), 0.3));
}
.gamble-charge-orb.charge {
  animation: gambleCharge 1.5s ease-in-out forwards;
}
@keyframes gambleCharge {
  0% { transform: scale(0.6) rotate(0deg); opacity: 0.4; filter: brightness(0.8); }
  40% { transform: scale(1.1) rotate(180deg); opacity: 1; filter: brightness(1.2); }
  100% { transform: scale(1.35) rotate(360deg); opacity: 0.9; filter: brightness(1.6); }
}

/* Rolling card-back */
.gamble-card-back {
  width: 120px;
  height: 150px;
  background: linear-gradient(145deg, #1e1140, #2a1a5c);
  border: 2px solid rgb(var(--c-primary));
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 2.5rem;
  color: rgba(255, 255, 255, 0.5);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6), 0 0 20px rgba(var(--c-primary), 0.3);
}
.gamble-card-back.rolling {
  animation: gambleRollFlip 0.22s linear infinite;
}
.gamble-card-back.rarity-basic { border-color: #ffffff; }
.gamble-card-back.rarity-magic { border-color: rgb(var(--c-info)); box-shadow: 0 0 20px rgba(var(--c-info), 0.5); }
.gamble-card-back.rarity-rare { border-color: rgb(var(--c-gold)); box-shadow: 0 0 20px rgba(var(--c-gold), 0.5); }
.gamble-card-back.rarity-legendary { border-color: rgb(var(--c-orange)); box-shadow: 0 0 22px rgba(var(--c-orange), 0.6); }
.gamble-card-back.rarity-ultimate { border-color: rgb(var(--c-primary)); box-shadow: 0 0 26px rgba(var(--c-primary), 0.7); }
@keyframes gambleRollFlip {
  0% { transform: perspective(500px) rotateY(-12deg) translateX(-8px); }
  50% { transform: perspective(500px) rotateY(8deg) translateX(8px); }
  100% { transform: perspective(500px) rotateY(-12deg) translateX(-8px); }
}

/* Reveal result: flip in + rarity flash + rarity outline/glow */
.gamble-reveal-result {
  position: relative;
  width: 100%;
  border: 1.5px solid rgba(255, 255, 255, 0.12);
  border-radius: 12px;
  padding: 12px;
  background: rgba(0, 0, 0, 0.3);
  box-sizing: border-box;
}
.gamble-reveal-result .gear-card {
  position: relative;
}
.gamble-reveal-result.revealed .gear-card {
  animation: gambleFlipIn 520ms cubic-bezier(0.18, 0.9, 0.26, 1.15) both;
}
@keyframes gambleFlipIn {
  0% { opacity: 0; transform: perspective(700px) rotateY(-70deg) scale(0.9); }
  60% { opacity: 1; transform: perspective(700px) rotateY(6deg) scale(1.02); }
  100% { opacity: 1; transform: none; }
}
.gamble-reveal-result.revealed::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(circle, rgba(255, 255, 255, 0.35) 0%, transparent 60%);
  animation: gambleRarityFlash 700ms ease-out both;
}
@keyframes gambleRarityFlash {
  0% { opacity: 0; }
  25% { opacity: 1; }
  100% { opacity: 0; }
}

/* Rarity pulse glow for legendary / ultimate reveals (the outline + base glow
   are set inline in js/shop.js; this just breathes the outer glow). */
.gamble-reveal-result.gamble-rarity-pulse {
  animation: gambleRarityPulse 2.8s ease-in-out infinite;
}
@keyframes gambleRarityPulse {
  0%, 100% { box-shadow: 0 0 16px var(--rarity-pulse-color, rgba(249, 115, 22, 0.5)); }
  50% { box-shadow: 0 0 30px var(--rarity-pulse-color, rgba(249, 115, 22, 0.85)); }
}

/* Short / mobile landscape compaction */
@media (max-height: 600px) {
  #gamble-reveal-screen .glass-panel {
    padding: 10px 14px !important;
  }
  .gamble-reveal-stage {
    min-height: 120px !important;
  }
  .gamble-charge-orb {
    width: 64px !important;
    height: 64px !important;
  }
  .gamble-reveal-result .gear-card-title {
    font-size: 0.95rem !important;
  }
}


/* ==========================================
   Standardized Gear Card (js/gear-card.js's buildGearCardHtml())
   Diablo-4-style layout shared by every UI surface that shows gear stats:
   gear-swap modal, action-bar tooltip + details panel, shop card + shop
   tooltip, pause screen. See js/gear-card.js for the full call-site list.
   ========================================== */

.gear-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  text-align: left;
  box-sizing: border-box;
  width: 100%;
}

/* Self-contained bordered variant -- used only by the action-bar details
   panel's stacked list of up to 5 equipped items, where each needs its own
   visual separator. Every other embedding (gear-swap modal, both floating
   tooltips, shop card) already sits inside a container that supplies its
   own border/background, so they use the borderless default instead. */
.gear-card.gear-card-card {
  /* chamfered, rarity-coloured frame: css/03b-chamfer-kit.css section 21 */
  padding: 8px 10px;
}

.gear-card-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}

.gear-card-title-block {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.gear-card-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 0.92rem;
  line-height: 1.25;
}

.gear-card-subtitle {
  font-size: 0.66rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  opacity: 0.9;
}

.gear-card-ilvl {
  font-size: 0.64rem;
  color: rgba(255, 255, 255, 0.45);
  font-weight: 600;
  margin-top: 1px;
}

.gear-card-icon {
  object-fit: cover;
  border-radius: 8px;
  border: 2px solid rgba(255, 255, 255, 0.15);
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4);
  flex-shrink: 0;
}

.gear-card-stats {
  list-style: none;
  margin: 2px 0 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.gear-card-stat {
  font-size: 0.72rem;
  color: rgba(255, 255, 255, 0.85);
  position: relative;
  padding-left: 12px;
}

.gear-card-stat::before {
  content: "•";
  position: absolute;
  left: 0;
  color: var(--color-primary);
}

/* Glitch Overclocked stat lines (js/gear-card.js) get a star bullet instead
   of the plain dot, in place of the per-line lightning-bolt marker this
   used to have -- the item as a whole is already flagged via the
   "Glitched" rarity prefix and the card's glitch border below, so each
   affected line only needs a lightweight visual tag. Two classes combined
   for specificity so this reliably wins over the plain dot rule above
   regardless of stylesheet order. */
.gear-card-stat.gear-card-stat-overclocked::before {
  content: "\25C6";
  color: rgb(var(--c-cyan));
  font-size: 0.85em;
  filter: drop-shadow(0 0 3px rgba(var(--c-cyan), 0.7));
}

/* Lost stats (the old item had these, the new one doesn't): shown as a plain
   red line below the kept stats -- deliberately no strikethrough and no red
   minus delta, so it reads more compactly than a struck-through entry. */
.gear-card-stat.gear-card-stat-lost,
.gear-card-stat.gear-card-stat-lost .gear-card-stat-down {
  color: rgb(var(--c-danger));
  text-decoration: none;
  opacity: 1;
}
.gear-card-stat.gear-card-stat-lost::before {
  color: rgb(var(--c-danger));
}

.gear-card-stat-up {
  color: rgb(var(--c-success));
  font-weight: bold;
  font-size: 0.66rem;
  text-decoration: none;
}

.gear-card-stat-down {
  color: rgb(var(--c-danger));
  font-weight: bold;
  font-size: 0.66rem;
  text-decoration: none;
}

.gear-card-stat-same {
  color: rgba(255, 255, 255, 0.4);
  font-size: 0.66rem;
}

/* Anomaly Infused ("Glitched") glow -- applied to whichever OUTER
   container each of the five gear-card locations already has (the
   gear-swap modal's .gear-compare-card wrapper, .shop-card, or one of the
   two floating tooltip divs), not to the inner .gear-card content itself.
   That outer container's border-color is set per-item to the rarity color
   (js/gear.js's setCompareCardFrame(), js/weapons-registry.js's
   showActionBarGearTooltip(), js/shop.js's showShopGearDetails(), and the
   .shop-card.rarity-X rules already baked into renderShopGroup()) -- this
   class only adds the flickering glow, cycling cyan/magenta with hard
   (non-eased) steps so it reads as "glitchy" rather than a smooth pulse,
   emanating inward (inset) from that border rather than bleeding outward,
   so it never fights with each container's own rarity-colored border.
   IMPORTANT: no `!important` on the box-shadow values below -- per the CSS
   Animations spec, `!important` declarations inside a @keyframes block are
   dropped entirely (not just de-prioritized), which was silently voiding
   every keyframe here and made the whole animation a no-op. A CSS animation
   already outranks any *non*-`!important` author rule regardless of
   specificity, which is enough to beat .shop-card.rarity-X's box-shadow
   (that one's plain, un-`!important`) and the inline box-shadow the JS side
   (js/gear.js, js/weapons-registry.js, js/shop.js) explicitly leaves unset
   while glitched.
   SEPARATE ISSUE this doesn't cover: `.shop-card.rarity-legendary`/
   `.rarity-ultimate` set their OWN `animation` (the old box-shadow pulses, since
   replaced by cx-border-pulse) on the same
   element. `animation` is a shorthand, so only one of the two competing
   declarations can win -- and `.shop-card.rarity-legendary` (2 classes)
   normally beats `.gear-outer-glitched` (1 class) on specificity, silently
   dropping the glitch animation entirely on shop cards specifically (the
   one place Glitched Legendary items actually appear pre-round-20 shop
   listings). Doubling the class in the selector below matches that
   specificity (2 classes each); since this rule is declared later in the
   file, source order then decides it in our favor. */
.gear-outer-glitched.gear-outer-glitched {
  /* Holographic cyber overlay: subtle ambient scanlines + dual-tone cyan/purple
     tint with strict container clipping to eliminate border bleeding.
     Composited 60 FPS motion via GPU opacity and transform layers. */
  position: relative;
  overflow: hidden !important;
  background-image: 
    linear-gradient(135deg, rgba(6, 182, 212, 0.12) 0%, rgba(147, 51, 234, 0.08) 100%),
    repeating-linear-gradient(
      0deg,
      transparent,
      transparent 3px,
      rgba(6, 182, 212, 0.04) 3px,
      rgba(6, 182, 212, 0.04) 5px
    ) !important;
  background-size: 100% 100%, 100% 5px !important;
  background-clip: padding-box !important;
}

/* Keeps the item icon/name/stats above the glow + band pseudos. */
.gear-outer-glitched.gear-outer-glitched > .gear-card,
.gear-outer-glitched.gear-outer-glitched > .mmo-slot-icon {
  position: relative;
  z-index: 1;
}

/* Smooth 60 FPS breathing inner glow: inset cyber-cyan & violet aura. */
/* the chamfer cards (css/03b-chamfer-kit.css section 21) keep ::before as the frame and flicker it instead */
.gear-outer-glitched.gear-outer-glitched:not(.shop-gear-card):not(.shop-card):not(.gear-compare-card):not(.gear-card-card):not(.swap-equipped-card)::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  z-index: 0;
  box-shadow: inset 0 0 16px 2px rgba(6, 182, 212, 0.45), inset 0 0 4px rgba(168, 85, 247, 0.3);
  animation: gearGlitchFlicker 2.8s ease-in-out infinite alternate;
  will-change: opacity;
}
@keyframes gearGlitchFlicker {
  0% { opacity: 0.45; }
  50% { opacity: 0.85; }
  100% { opacity: 0.55; }
}

/* Smooth 60 FPS holographic laser sweep: high-definition cyan beam traveling
   down the full height of the card without choppy steps. */
.gear-outer-glitched.gear-outer-glitched:not(.controller-focused)::after {
  /* :not(.controller-focused): on the chamfered cards ::after is the white focus frame while focused */
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 2;
  border-radius: inherit;
  background: linear-gradient(
    to bottom,
    transparent 0%,
    transparent 85%,
    rgba(6, 182, 212, 0.08) 88%,
    rgba(6, 182, 212, 0.25) 95%,
    rgba(255, 255, 255, 0.75) 99%,
    rgba(6, 182, 212, 0.9) 100%
  );
  transform: translateY(-100%);
  animation: gearGlitchSweep 2.8s cubic-bezier(0.25, 0.1, 0.25, 1) infinite;
  will-change: transform, opacity;
}
@keyframes gearGlitchSweep {
  0% { transform: translateY(-100%); opacity: 0; }
  10% { opacity: 1; }
  85% { opacity: 0.85; }
  100% { transform: translateY(100%); opacity: 0; }
}

/* Glitch Overclocked items when selected or focused by controller/mouse:
   only force the cyan border (the pseudos already provide the motion). */
.gear-outer-glitched.controller-focused,
.gear-outer-glitched.is-selected,
.shop-gear-card.gear-outer-glitched.controller-focused,
.shop-card.gear-outer-glitched.controller-focused,
.mmo-slot.gear-outer-glitched.controller-focused {
  border-color: rgb(var(--c-cyan)) !important;
}
.gear-outer-glitched.gear-outer-glitched:not(.shop-gear-card):not(.shop-card):not(.gear-compare-card):not(.gear-card-card):not(.swap-equipped-card).controller-focused::before {
  animation: gearGlitchFlicker 1.6s ease-in-out infinite alternate;
}

.gear-card.gear-card-anomalous .gear-card-icon {
  border-color: rgb(var(--c-cyan));
}

/* Glitch Overclocked items always render their inner icon frame in cyan with a glowing aura */
.gear-outer-glitched .card-icon-box,
.gear-outer-glitched .gear-compare-card-icon,
.gear-outer-glitched .pause-slot-icon,
.gear-outer-glitched .gear-card-icon,
.card-icon-box.gear-icon-glitched {
  border-color: rgb(var(--c-cyan)) !important;
  box-shadow: 0 0 10px rgba(var(--c-cyan), 0.55), inset 0 0 8px rgba(var(--c-cyan), 0.3) !important;
}

/* Glitch Overclocked item icon chromatic aberration & horizontal slice tear */
.gear-outer-glitched .card-icon-box img,
.gear-outer-glitched .mmo-slot-icon img,
.gear-outer-glitched .gear-compare-card-icon img,
.gear-outer-glitched .pause-slot-icon img,
.gear-outer-glitched .gear-card-icon,
.gear-outer-glitched .gear-details-icon img,
.card-icon-box.gear-icon-glitched img {
  animation: gearImageGlitchTear 2.8s infinite;
  will-change: transform, filter, clip-path;
}

@keyframes gearImageGlitchTear {
  0%, 75% {
    filter: none;
    transform: none;
    clip-path: none;
  }
  76% {
    filter: drop-shadow(-2.5px 0 0 #06b6d4) drop-shadow(2.5px 0 0 #ec4899);
    transform: translate(1.5px, -1px);
    clip-path: polygon(0 0, 100% 0, 100% 32%, 0 32%, 0 46%, 100% 46%, 100% 100%, 0 100%);
  }
  78% {
    filter: drop-shadow(3px -1px 0 #06b6d4) drop-shadow(-2.5px 1px 0 #ec4899);
    transform: translate(-2px, 1px) scale(1.02);
    clip-path: polygon(0 0, 100% 0, 100% 18%, 0 18%, 0 30%, 100% 30%, 100% 100%, 0 100%);
  }
  80% {
    filter: drop-shadow(-3px 0 0 #06b6d4) drop-shadow(2.5px 0 0 #ec4899);
    transform: translate(2px, 0);
    clip-path: polygon(0 0, 100% 0, 100% 62%, 0 62%, 0 76%, 100% 76%, 100% 100%, 0 100%);
  }
  82% {
    filter: drop-shadow(1.5px -0.5px 0 #06b6d4) drop-shadow(-1.5px 0.5px 0 #ec4899);
    transform: translate(-1px, 0.5px);
    clip-path: none;
  }
  85%, 100% {
    filter: none;
    transform: none;
    clip-path: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .gear-outer-glitched .card-icon-box img,
  .gear-outer-glitched .mmo-slot-icon img,
  .gear-outer-glitched .gear-compare-card-icon img,
  .gear-outer-glitched .pause-slot-icon img,
  .gear-outer-glitched .gear-card-icon,
  .gear-outer-glitched .gear-details-icon img,
  .card-icon-box.gear-icon-glitched img {
    animation: none !important;
    filter: none !important;
    transform: none !important;
    clip-path: none !important;
  }
}

.gear-card-ability {
  font-size: 0.7rem;
  color: rgb(var(--c-gold));
  margin-top: 4px;
  border-top: 1px dashed rgba(255, 255, 255, 0.1);
  padding-top: 6px;
  font-style: italic;
  font-weight: 600;
  text-shadow: 0 0 6px rgba(var(--c-gold), 0.3);
}

.gear-card-empty-note {
  font-size: 0.68rem;
  color: rgba(255, 255, 255, 0.5);
}

/* Locked shop card visual styling */
.shop-card.locked-item {
  --bd: rgb(var(--c-gold));
  --bw: 2px;
  --bg: linear-gradient(180deg, rgba(var(--c-gold), 0.2), transparent 55%), rgba(13, 10, 25, 0.96);
}

/* Actively locked/reserved AND still unaffordable: a brighter, more
   saturated blue than the plain "Lock" slate above, so it reads as
   "actively held for next reroll" rather than merely "not affordable yet".
   Scoped to .cant-afford so a card that's still tagged .locked-item from an
   earlier visit but is now affordable correctly falls through to the plain
   gold "Buy" look below instead. */
.shop-card.cant-afford.locked-item .btn-buy {
  background: linear-gradient(90deg, rgb(var(--c-sky)), #0369a1);
  color: #ffffff;
}

/* .upgrade-card.rarity-* frames and pulses: --r mapping and the border / sheen pulse live in
   css/03b-chamfer-kit.css sections 21-22. */

/* Dash Slot specific border overrides */
.mmo-slot.dash-slot {
  border-color: rgba(var(--c-gold), 0.4);
  background: rgba(20, 16, 36, 0.9);
  cursor: help;
}

:where(body:not(.gamepad-active)) .mmo-slot.dash-slot:hover {
  border-color: rgb(var(--c-gold));
  box-shadow: 0 0 12px rgba(var(--c-gold), 0.5);
}

.mmo-slot.dash-slot .mmo-slot-icon svg {
  width: 22px;
  height: 22px;
  filter: drop-shadow(0 0 6px rgba(var(--c-gold), 0.5));
  display: block;
}

/* Boss lines (HUD overhaul "Edge Telemetry", Phase 2; plans/HUD_EDGE_TELEMETRY_PLAN.md).
   Desktop only: on the mobile HUD updateBossHealthBars() (js/main-loop.js) keeps this container empty and
   boss health is drawn above each boss in-world instead.
   Each boss is a thin line (name + percentage over a 4px bar, no panel behind it), laid out side by side
   in the top-centre gap between the HUD corners. At most 3 are named (2 on windows under 1600px wide); the
   rest share one dimmer, narrower "+N MORE" entry at the end whose bar is their combined remaining HP.
   A lone boss gets the full 640px line; with several they split the gap and long names truncate. The fill is a transform written by JS (scaleX, only when it changes by 0.1%),
   so a boss fight adds no per-frame layout. Original class names are kept; .boss-line* are new. */
.boss-health-container {
  position: absolute;
  top: 74px;
  left: 20px;
  right: 20px;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: flex-start;
  gap: 24px;
  z-index: 80;
  pointer-events: none;
}

.boss-health-bar-wrapper {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1 1 0;
  min-width: 0;
  max-width: 640px;
}

/* Several bosses: tighter tracking so more of each name fits its share of the gap. */
.boss-health-container:has(> .boss-line + .boss-line) .boss-health-bar-text {
  letter-spacing: 0.16em;
}

/* Under 1600px wide (where the JS cap drops to 2) the gap is narrower still. */
@media (max-width: 1599px) {
  .boss-health-container {
    gap: 16px;
  }

  .boss-line-head {
    gap: 8px;
  }

  .boss-health-container:has(> .boss-line + .boss-line) .boss-health-bar-text {
    letter-spacing: 0.04em;
  }
}

.boss-line-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  min-width: 0;
}

.boss-health-bar-text {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: #fca5a5;
  font: 600 12px/1 var(--font-display);
  letter-spacing: 0.3em;
  text-transform: uppercase;
  text-shadow: 0 1px 0 #000, 0 0 2px #000, 0 0 12px rgba(0, 0, 0, 0.9);
}

.boss-line-pct {
  flex: none;
  color: #fca5a5;
  font: 700 12px/1 var(--font-display);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 0 #000, 0 0 2px #000, 0 0 12px rgba(0, 0, 0, 0.9);
}

.boss-line-track {
  position: relative;
  height: 4px;
  background: rgba(239, 68, 68, 0.2);
  overflow: hidden;
}

.boss-health-bar-fill {
  position: absolute;
  inset: 0;
  background: #ef4444;
  box-shadow: 0 0 10px rgba(239, 68, 68, 0.7);
  transform-origin: left center;
}

/* Summary entry for the bosses past the cap: narrower and quieter, so the named lines stay the focus. */
.boss-line--more {
  flex: 0 0 120px;
}

.boss-line--more .boss-health-bar-text,
.boss-line--more .boss-line-pct {
  color: rgba(226, 232, 240, 0.7);
}

.boss-line--more .boss-line-pct {
  letter-spacing: 0;
}

.boss-line--more .boss-line-track {
  margin-top: 1px;
  height: 2px;
  background: rgba(255, 255, 255, 0.12);
}

.boss-line--more .boss-health-bar-fill {
  background: rgba(248, 113, 113, 0.75);
  box-shadow: none;
}

/* HUD overhaul Phase 1: the desktop HUD is now two corner groups, so the boss lines sit up between them
   instead of spanning the full width under the old .hud-top panel. */
:root:not(.is-mobile) body:not(.input-touch) .boss-health-container {
  top: 34px;
  left: 330px;
  right: 330px;
}

/* The trackers now stack under the top-left corner, clear of the boss bar, so they no longer need
   to drop down while a boss is alive. */
:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .wager-hud-tracker.boss-active,
:root:not(.is-mobile) body:not(.input-touch) #hud:not(.mobile-active) .glitch-hunt-hud.boss-active {
  margin-top: 0;
}
/* Controller Focus Styling */
/* Focus lifts by whole pixels instead of growing. A fractional scale (the old
   scale(1.03)) blurs text in Chromium -- worst on cards promoted to their own
   layer (will-change: transform, entry animations), which are scaled as a
   bitmap -- so no text-bearing focus or hover state scales any more; the
   outline and glow carry the highlight. Icon-only zooms are unaffected. */
.controller-focused:not(.selected):not(.power-up):not(.rejected):not(.fizzle) {
  outline: 3px solid rgb(var(--c-focus)) !important;
  box-shadow: 0 0 15px rgba(var(--c-focus), 0.75) !important;
  transform: translateY(-4px) !important;
  transition: transform 0.1s ease, box-shadow 0.1s ease !important;
}

/* Power-up and fizzle animation shields: never allow controller focus outlines or transforms to disrupt active cinematics */
.controller-focused.selected,
.controller-focused.power-up,
.controller-focused.rejected,
.controller-focused.fizzle {
  outline: none !important;
  box-shadow: none !important;
  transform: none;
  transition: none !important;
}

.gear-refactor-affix-row.controller-focused {
  border-color: rgb(var(--c-focus)) !important;
  outline: 2.5px solid rgb(var(--c-focus)) !important;
  outline-offset: -2px !important;
  background: rgba(var(--c-focus), 0.25) !important;
  box-shadow: 0 0 15px rgba(var(--c-focus), 0.6) !important;
  transform: none !important;
}

/* The chamfer .btn buttons on this screen (empower, reroll, info, info-ok) take the kit focus
   variant (css/03b-chamfer-kit.css section 4); only the two close X buttons keep this rule until
   the close-button phase. */
#gear-refactor-close-btn.controller-focused,
#gear-refactor-info-close-btn.controller-focused {
  outline: 2.5px solid rgb(var(--c-focus)) !important;
  outline-offset: -2px !important;
  border-color: rgb(var(--c-focus)) !important;
  box-shadow: 0 0 14px rgba(var(--c-focus), 0.7) !important;
  transform: none !important;
}

/* .shop-gear-card.controller-focused (outline + glow) removed: invisible under the chamfer clip-path;
   focus is the kit variant, css/03b-chamfer-kit.css sections 4 and 21. */

/* .bazaar-header-tab.controller-focused (outline + glow + scale) removed: invisible under the
   chamfer clip-path; focus is the kit variant, css/03b-chamfer-kit.css section 4. */

#level-up-screen #weapon-tree-tabs .weapon-tree-tab.controller-focused,
#weapon-tree-tabs .weapon-tree-tab.controller-focused,
.weapon-tree-tabs-row .weapon-tree-tab.controller-focused,
.weapon-tree-tab.controller-focused {
  transform: translate(-50%, -50%) translateX(var(--tab-offset, 0px)) scale(calc(var(--tab-scale, 1) * 1.05)) !important;
  transition: transform 0.25s ease, opacity 0.25s ease, box-shadow 0.15s ease, border-color 0.2s ease !important;
}

/* Survivor Tree node and root controller focus overrides: ensure bright cyan border, outline and glow override animation shields */
#survivor-upgrades-screen .su-node.controller-focused,
#survivor-upgrades-screen .su-node.controller-focused.selected,
#survivor-upgrades-screen .su-root.controller-focused,
#survivor-upgrades-screen .su-root.controller-focused.selected,
#survivor-upgrades-screen .survivor-upgrades-focused-marker,
.su-node.controller-focused,
.su-node.controller-focused.selected,
.su-root.controller-focused,
.su-root.controller-focused.selected,
.survivor-upgrades-focused-marker {
  border-color: rgb(var(--c-focus)) !important;
  outline: 3px solid rgb(var(--c-focus)) !important;
  outline-offset: 2px !important;
  box-shadow: 0 0 0 2px rgba(var(--c-focus), 0.6), 0 0 20px rgba(var(--c-focus), 0.85) !important;
  z-index: 10 !important;
  /* No lift or scale: nodes sit on their connecting lines, and a scale blurs the label. */
  transform: none !important;
  transition: transform 0.1s ease, box-shadow 0.1s ease !important;
}

.gear-refactor-btn.controller-focused,
.btn-replace.controller-focused,
.mmo-slot.controller-focused {
  border-color: rgb(var(--c-focus)) !important;
  box-shadow: 0 0 18px rgba(var(--c-focus), 0.8) !important;
}

/* Level-up footer buttons: #level-up-screen .weapon-tree-footer/.weapon-grid-footer .btn.controller-focused
   (an INSET 2.5px outline, glow and scale) removed; they are chamfer .btn buttons now and take
   the kit focus variant. z-index kept so the focused one is never covered by its neighbour. */
#level-up-screen .weapon-tree-footer .btn.controller-focused,
#level-up-screen .weapon-grid-footer .btn.controller-focused {
  z-index: 10 !important;
}

/* Weapon slot controller A button glyph when focused in Bazaar */
#shop-inv-weapons .mmo-slot {
  overflow: visible;
}

.mmo-slot-controller-a-icon {
  display: none;
  position: absolute;
  top: -5px;
  right: -5px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #000000;
  border: 1.5px solid rgba(255, 255, 255, 0.85);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.8), 0 0 8px rgba(59, 130, 246, 0.6);
  z-index: 10;
  pointer-events: none;
  align-items: center;
  justify-content: center;
}

.mmo-slot-controller-a-icon img {
  width: 12px;
  height: 12px;
  object-fit: contain;
  display: block;
}

.mmo-slot.controller-focused .mmo-slot-controller-a-icon {
  display: flex;
}


/* Dev Sandbox Panel Layout & Aesthetics */
.dev-panel-container {
  display: none; /* hidden by default */
  position: fixed;
  right: 0;
  top: 0;
  bottom: 0;
  width: 380px;
  height: 100vh;
  max-height: 100vh;
  background: rgba(14, 11, 28, 0.96);
  border-left: 1.5px solid rgba(var(--c-primary), 0.4);
  box-shadow: -12px 0 32px rgba(0, 0, 0, 0.8),
              0 0 24px rgba(var(--c-primary), 0.2);
  backdrop-filter: blur(14px);
  z-index: 9999;
  flex-direction: column;
  color: #fff;
  font-family: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 0.8rem;
  box-sizing: border-box;
  overflow-y: hidden;
  pointer-events: auto;
}

.dev-panel-container.minimized {
  max-height: 42px;
  height: 42px;
  bottom: auto;
  border-bottom: 1.5px solid rgba(var(--c-primary), 0.4);
  border-radius: 0 0 0 12px;
  overflow: hidden;
}

.dev-panel-container.minimized .dev-tab-bar,
.dev-panel-container.minimized .dev-panel-body,
.dev-panel-container.minimized .dev-section {
  display: none !important;
}

/* Drag-to-resize grip on the panel's left edge (the panel is anchored via
   right: 0, so its left edge is the one that moves). Sits on top of the
   panel content via z-index; devSetupPanelResize() in js/devpanel.js reads
   pointer X deltas from mousedown/touchstart on this element and writes the
   result straight to the panel's inline `width` style, clamped by
   devClampPanelWidth(). Widened via a transparent hit-area rather than
   relying on the 3px visible sliver, since a 3px mouse target is a mis-click
   magnet -- especially on a touch screen. */
.dev-panel-resize-handle {
  position: absolute;
  left: -3px;
  top: 0;
  bottom: 0;
  width: 9px;
  cursor: ew-resize;
  z-index: 20;
  background: transparent;
  touch-action: none;
}

:where(body:not(.gamepad-active)) .dev-panel-resize-handle:hover,
.dev-panel-resize-handle.dragging {
  background: rgba(var(--c-primary), 0.4);
}

.dev-panel-container.minimized .dev-panel-resize-handle {
  display: none;
}

/* Applied to <body> for the duration of a drag so the resize cursor and
   text-selection lock stay correct even when the pointer briefly outruns the
   9px handle during a fast drag. */
body.dev-panel-resizing {
  cursor: ew-resize !important;
  user-select: none !important;
}

.dev-panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 14px;
  background: rgb(15, 12, 32);
  border-bottom: 1px solid rgba(var(--c-primary), 0.3);
  font-weight: 700;
  letter-spacing: 0.06em;
  color: rgb(var(--c-violet));
  position: sticky;
  top: 0;
  z-index: 10;
  flex-shrink: 0;
}

.dev-header-badge {
  font-size: 0.65rem;
  background: rgba(var(--c-primary), 0.2);
  border: 1px solid rgba(var(--c-primary), 0.4);
  color: #e9d5ff;
  padding: 2px 6px;
  border-radius: 4px;
  font-weight: 600;
  text-transform: uppercase;
}

.dev-close-btn {
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.1);
  color: rgba(255, 255, 255, 0.7);
  font-size: 0.85rem;
  font-weight: bold;
  cursor: pointer;
  width: 24px;
  height: 24px;
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.15s ease;
}

:where(body:not(.gamepad-active)) .dev-close-btn:hover {
  color: #fff;
  background: rgba(var(--c-danger), 0.3);
  border-color: rgb(var(--c-danger));
}

/* Tab Bar */
.dev-tab-bar {
  display: flex;
  background: rgba(9, 7, 20, 0.95);
  border-bottom: 1.5px solid rgba(255, 255, 255, 0.08);
  padding: 4px 6px 0;
  gap: 3px;
  overflow-x: auto;
  flex-shrink: 0;
  scrollbar-width: none;
}
.dev-tab-bar::-webkit-scrollbar {
  display: none;
}

.dev-tab-btn {
  flex: 1;
  min-width: 60px;
  padding: 8px 4px;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  color: rgba(255, 255, 255, 0.55);
  font-family: 'Outfit', sans-serif;
  font-size: 0.75rem;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
  transition: all 0.18s ease;
  white-space: nowrap;
}

:where(body:not(.gamepad-active)) .dev-tab-btn:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.03);
}

.dev-tab-btn.active {
  color: rgb(var(--c-sky));
  border-bottom-color: rgb(var(--c-sky));
  background: rgba(var(--c-sky), 0.08);
  text-shadow: 0 0 10px rgba(var(--c-sky), 0.5);
}

/* Panel Body & Scroll Container */
.dev-panel-body {
  flex: 1;
  overflow-y: auto;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.dev-tab-pane {
  display: none;
  flex-direction: column;
  gap: 10px;
}

.dev-tab-pane.active {
  display: flex;
}

/* Card Containers */
.dev-card {
  background: rgba(255, 255, 255, 0.025);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 8px;
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.dev-card-title {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: rgb(var(--c-sky));
  display: flex;
  align-items: center;
  justify-content: space-between;
}

/* Quick Toggle Switch Row */
.dev-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 0;
  gap: 8px;
}

.dev-toggle-label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.76rem;
  font-weight: 600;
  cursor: pointer;
  user-select: none;
}

.dev-toggle-label input[type="checkbox"] {
  accent-color: rgb(var(--c-primary));
  width: 16px;
  height: 16px;
  cursor: pointer;
}

/* Action Button Grids */
.dev-btn-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 6px;
}

.dev-btn-grid.cols-3 {
  grid-template-columns: repeat(3, 1fr);
}


.dev-btn {
  height: 32px;
  min-height: 32px;
  padding: 0 8px;
  font-size: 0.74rem;
  font-weight: 600;
  border-radius: 5px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.04);
  color: #fff;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  transition: all 0.15s ease;
  white-space: nowrap;
}

:where(body:not(.gamepad-active)) .dev-btn:hover {
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.25);
}

.dev-btn:active {
  transform: scale(0.98);
}

.dev-btn-cyan {
  border-color: rgba(var(--c-sky), 0.4);
  color: rgb(var(--c-sky));
  background: rgba(var(--c-sky), 0.08);
}
:where(body:not(.gamepad-active)) .dev-btn-cyan:hover {
  background: rgba(var(--c-sky), 0.2);
  border-color: rgb(var(--c-sky));
  box-shadow: 0 0 10px rgba(var(--c-sky), 0.3);
}

.dev-btn-gold {
  border-color: rgba(var(--c-gold), 0.4);
  color: rgb(var(--c-gold));
  background: rgba(var(--c-gold), 0.08);
}
:where(body:not(.gamepad-active)) .dev-btn-gold:hover {
  background: rgba(var(--c-gold), 0.2);
  border-color: rgb(var(--c-gold));
  box-shadow: 0 0 10px rgba(var(--c-gold), 0.3);
}

.dev-btn-purple {
  border-color: rgba(var(--c-primary), 0.4);
  color: rgb(var(--c-violet));
  background: rgba(var(--c-primary), 0.08);
}
:where(body:not(.gamepad-active)) .dev-btn-purple:hover {
  background: rgba(var(--c-primary), 0.2);
  border-color: rgb(var(--c-primary));
  box-shadow: 0 0 10px rgba(var(--c-primary), 0.3);
}

.dev-btn-green {
  border-color: rgba(var(--c-mint), 0.4);
  color: rgb(var(--c-mint));
  background: rgba(var(--c-mint), 0.08);
}
:where(body:not(.gamepad-active)) .dev-btn-green:hover {
  background: rgba(var(--c-mint), 0.2);
  border-color: rgb(var(--c-mint));
  box-shadow: 0 0 10px rgba(var(--c-mint), 0.3);
}

.dev-btn-red {
  border-color: rgba(var(--c-danger), 0.4);
  color: rgb(var(--c-danger));
  background: rgba(var(--c-danger), 0.08);
}
:where(body:not(.gamepad-active)) .dev-btn-red:hover {
  background: rgba(var(--c-danger), 0.25);
  border-color: rgb(var(--c-danger));
  box-shadow: 0 0 10px rgba(var(--c-danger), 0.3);
}

/* Weapons Slot Strip */
.dev-slot-strip {
  display: flex;
  gap: 6px;
  margin-bottom: 8px;
}

.dev-slot-chip {
  flex: 1;
  min-width: 0;
  padding: 6px 2px;
  background: rgba(0, 0, 0, 0.4);
  border: 1.5px solid rgba(255, 255, 255, 0.1);
  border-radius: 6px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  cursor: pointer;
  transition: all 0.18s ease;
  user-select: none;
}

:where(body:not(.gamepad-active)) .dev-slot-chip:hover {
  border-color: rgba(var(--c-primary), 0.5);
  background: rgba(var(--c-primary), 0.08);
}

.dev-slot-chip.active {
  border-color: rgb(var(--c-sky));
  background: rgba(var(--c-sky), 0.14);
  box-shadow: 0 0 10px rgba(var(--c-sky), 0.3);
}

.dev-slot-chip-num {
  font-size: 0.58rem;
  color: rgba(255, 255, 255, 0.5);
  font-weight: 700;
  text-transform: uppercase;
  line-height: 1;
}

.dev-slot-chip-icon {
  width: 32px;
  height: 32px;
  border-radius: 5px;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid rgba(255, 255, 255, 0.08);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  margin: 1px 0;
  flex-shrink: 0;
  transition: border-color 0.18s ease;
}

.dev-slot-chip.active .dev-slot-chip-icon {
  border-color: rgba(var(--c-sky), 0.4);
  background: rgba(var(--c-sky), 0.1);
}

.dev-slot-chip-img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

.dev-slot-chip-icon.empty {
  border: 1px dashed rgba(255, 255, 255, 0.14);
  background: transparent;
}

.dev-slot-chip-lvl {
  font-size: 0.68rem;
  font-weight: bold;
  color: #fff;
  line-height: 1;
}

.dev-slot-chip-lvl.max-lvl {
  color: rgb(var(--c-gold));
  text-shadow: 0 0 6px rgba(var(--c-gold), 0.4);
}

/* Milestone Path Choice Cards */
.dev-path-group {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 4px;
}

.dev-path-header {
  font-size: 0.68rem;
  font-weight: 700;
  color: rgb(var(--c-primary));
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.dev-path-options {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
}

.dev-path-card {
  padding: 6px 8px;
  border-radius: 5px;
  border: 1.5px solid rgba(255, 255, 255, 0.08);
  background: rgba(0, 0, 0, 0.4);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 2px;
  transition: all 0.15s ease;
}

:where(body:not(.gamepad-active)) .dev-path-card:hover {
  border-color: rgba(255, 255, 255, 0.25);
  background: rgba(255, 255, 255, 0.03);
}

.dev-path-card.selected {
  border-color: rgb(var(--c-primary));
  background: rgba(var(--c-primary), 0.15);
  box-shadow: 0 0 10px rgba(var(--c-primary), 0.3);
}

.dev-path-card.disabled {
  opacity: 0.35;
  pointer-events: none;
}

.dev-path-name {
  font-size: 0.72rem;
  font-weight: 700;
  color: #fff;
}

.dev-path-desc {
  font-size: 0.62rem;
  color: rgba(255, 255, 255, 0.6);
  line-height: 1.3;
}

/* Filter Chips and Quantity Selector */
.dev-filter-chips {
  display: flex;
  gap: 4px;
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: 2px;
}
.dev-filter-chips::-webkit-scrollbar {
  display: none;
}

.dev-filter-chip {
  padding: 4px 8px;
  font-size: 0.68rem;
  font-weight: 600;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.04);
  color: rgba(255, 255, 255, 0.6);
  cursor: pointer;
  white-space: nowrap;
  transition: all 0.15s ease;
}

:where(body:not(.gamepad-active)) .dev-filter-chip:hover {
  color: #fff;
  border-color: rgba(255, 255, 255, 0.25);
}

.dev-filter-chip.active {
  background: rgba(var(--c-sky), 0.15);
  border-color: rgb(var(--c-sky));
  color: rgb(var(--c-sky));
  font-weight: 700;
}

.dev-qty-pills {
  display: flex;
  gap: 4px;
}

.dev-qty-pill {
  flex: 1;
  padding: 4px 0;
  font-size: 0.7rem;
  font-weight: 700;
  border-radius: 4px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(0, 0, 0, 0.4);
  color: rgba(255, 255, 255, 0.6);
  cursor: pointer;
  text-align: center;
  transition: all 0.15s ease;
}

:where(body:not(.gamepad-active)) .dev-qty-pill:hover {
  color: #fff;
  border-color: rgba(255, 255, 255, 0.25);
}

.dev-qty-pill.active {
  border-color: rgb(var(--c-gold));
  background: rgba(var(--c-gold), 0.15);
  color: rgb(var(--c-gold));
}

/* Spawns Grid */
.dev-spawn-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 6px;
}

.dev-spawn-card {
  padding: 8px;
  border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(0, 0, 0, 0.35);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 2px;
  transition: all 0.15s ease;
  text-align: left;
}

:where(body:not(.gamepad-active)) .dev-spawn-card:hover {
  transform: translateY(-1px);
}

.dev-spawn-card:active {
  transform: scale(0.97);
}

.dev-spawn-card.type-standard {
  border-color: rgba(var(--c-mint), 0.25);
}
:where(body:not(.gamepad-active)) .dev-spawn-card.type-standard:hover {
  border-color: rgb(var(--c-mint));
  background: rgba(var(--c-mint), 0.1);
}

.dev-spawn-card.type-fast {
  border-color: rgba(var(--c-sky), 0.25);
}
:where(body:not(.gamepad-active)) .dev-spawn-card.type-fast:hover {
  border-color: rgb(var(--c-sky));
  background: rgba(var(--c-sky), 0.1);
}

.dev-spawn-card.type-tank {
  border-color: rgba(248, 113, 113, 0.25);
}
:where(body:not(.gamepad-active)) .dev-spawn-card.type-tank:hover {
  border-color: #f87171;
  background: rgba(248, 113, 113, 0.1);
}

.dev-spawn-card.type-elite {
  border-color: rgba(var(--c-primary), 0.3);
}
:where(body:not(.gamepad-active)) .dev-spawn-card.type-elite:hover {
  border-color: rgb(var(--c-primary));
  background: rgba(var(--c-primary), 0.12);
}

.dev-spawn-card.type-boss {
  border-color: rgba(var(--c-gold), 0.35);
}
:where(body:not(.gamepad-active)) .dev-spawn-card.type-boss:hover {
  border-color: rgb(var(--c-gold));
  background: rgba(var(--c-gold), 0.14);
}

.dev-spawn-card.type-anomaly {
  border-color: rgba(var(--c-secondary), 0.35);
}
:where(body:not(.gamepad-active)) .dev-spawn-card.type-anomaly:hover {
  border-color: rgb(var(--c-secondary));
  background: rgba(var(--c-secondary), 0.14);
}

.dev-spawn-title {
  font-size: 0.74rem;
  font-weight: 700;
  color: #fff;
}

.dev-spawn-role {
  font-size: 0.62rem;
  color: rgba(255, 255, 255, 0.5);
}

/* Clear Enemies Button with Live Counter Badge */
.dev-clear-enemies-btn {
  width: 100%;
  height: 36px;
  background: rgba(var(--c-danger), 0.12);
  border: 1.5px solid rgb(var(--c-danger));
  color: rgb(var(--c-danger));
  font-weight: 700;
  font-size: 0.78rem;
  border-radius: 6px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transition: all 0.15s ease;
}

:where(body:not(.gamepad-active)) .dev-clear-enemies-btn:hover {
  background: rgba(var(--c-danger), 0.25);
  box-shadow: 0 0 12px rgba(var(--c-danger), 0.4);
}

.dev-enemy-count-badge {
  background: rgb(var(--c-danger));
  color: #fff;
  font-size: 0.65rem;
  font-weight: 800;
  padding: 1px 6px;
  border-radius: 10px;
}


.dev-section-title {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-weight: bold;
  color: rgb(var(--c-sky));
  margin-bottom: 8px;
  text-transform: uppercase;
  font-size: 0.68rem;
  letter-spacing: 0.04em;
  cursor: pointer;
  user-select: none;
}


.dev-weapon-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid rgba(255, 255, 255, 0.04);
  padding: 6px;
  border-radius: 6px;
}

.dev-select {
  background: rgba(0, 0, 0, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.15);
  color: #fff;
  border-radius: 4px;
  padding: 3px 6px;
  font-size: 0.72rem;
  outline: none;
  font-family: monospace;
  cursor: pointer;
}

.dev-select:focus {
  border-color: rgb(var(--c-primary));
}

.dev-num-input {
  width: 32px;
  background: rgba(0, 0, 0, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.15);
  color: #fff;
  border-radius: 4px;
  padding: 3px;
  text-align: center;
  font-size: 0.72rem;
  outline: none;
  font-family: monospace;
  /* The custom +/- steppers below (.dev-stepper-btn) replace the browser's
     own up/down spinner arrows -- those render tiny and are hard to hit
     precisely (the original complaint), and don't appear at all on Android's
     WebView (a numeric keyboard shows instead), so they weren't a usable
     control on every platform this panel needs to work on anyway. */
  -moz-appearance: textfield;
  appearance: textfield;
}

.dev-num-input::-webkit-inner-spin-button,
.dev-num-input::-webkit-outer-spin-button {
  -webkit-appearance: none;
  appearance: none;
  margin: 0;
}

.dev-num-input:focus {
  border-color: rgb(var(--c-primary));
}

/* Wraps a .dev-num-input with two flanking +/- buttons (see
   devWireNumberSteppers() in js/devpanel.js) -- a much bigger, more
   reliable click/tap target than the native spinner arrows it replaces. */
.dev-num-stepper {
  display: flex;
  align-items: stretch;
  gap: 3px;
}

.dev-num-stepper .dev-num-input {
  flex: 1;
  min-width: 50px;
}

.dev-stepper-btn {
  flex: 0 0 26px;
  width: 26px;
  min-height: 26px;
  padding: 0;
  border-radius: 4px;
  border: 1px solid rgba(255, 255, 255, 0.15);
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
  font-size: 0.9rem;
  font-weight: bold;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  user-select: none;
}

:where(body:not(.gamepad-active)) .dev-stepper-btn:hover {
  background: rgba(var(--c-primary), 0.25);
  border-color: rgb(var(--c-primary));
}

.dev-stepper-btn:active {
  background: rgba(var(--c-primary), 0.45);
}

/* Mobile Virtual Controls Styling */
.mobile-controls-wrapper {
  position: absolute;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  pointer-events: none;
  z-index: 350; /* Bring it ABOVE all shop panels and choice screens (which are 200-300) */
}

#joystick-container {
  position: absolute;
  width: 120px;
  height: 120px;
  border-radius: 50%;
  /* backdrop-filter/blur is expensive on Android's compositor and this
     element can be visible continuously during touch play â€” swapped for a
     slightly more opaque flat fill instead of a live blur to get a similar
     frosted look without the per-frame GPU cost. */
  background: rgba(255, 255, 255, 0.14);
  border: 2px solid rgba(255, 255, 255, 0.18);
  pointer-events: none; /* Make the container itself completely transparent to setup touches */
  touch-action: none;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
  
  display: block;
  opacity: 0;
  transition: opacity 0.15s ease;
  
  /* Hard reset positioning vectors */
  left: 0;
  top: 0;
  /* Use margins to handle the offset centering calculation cleanly */
  margin-left: -60px; 
  margin-top: -60px;
}

#joystick-handle {
  position: absolute;
  top: 35px;
  left: 35px;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background: radial-gradient(circle, rgb(var(--c-violet)), rgb(var(--c-primary)));
  box-shadow: 0 0 15px rgba(var(--c-primary), 0.6);
  border: 2px solid rgba(255, 255, 255, 0.4);
  touch-action: none;
}

#mobile-dash-btn {
  position: absolute;
  bottom: 60px;
  right: 100px; /* Moved inward from 60px to 100px for a more natural resting position */
  width: 80px;
  height: 80px;
  border-radius: 50%;
  overflow: hidden;
  background: radial-gradient(circle, rgba(var(--c-gold), 0.2) 0%, rgba(20, 16, 36, 0.9) 100%);
  border: 2px solid rgba(var(--c-gold), 0.6);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.6), 0 0 18px rgba(var(--c-gold), 0.35), inset 0 0 12px rgba(var(--c-gold), 0.2);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: auto;
  touch-action: none;
  cursor: pointer;
  outline: none;
  transition: background 0.1s ease, transform 0.05s ease, box-shadow 0.1s ease;
  user-select: none;
}

/* Icon glyph -- kept as a normal (non-positioned) flex child so the button's
   existing align-items/justify-content centering still applies to it, while
   the cooldown overlay/text/pips below are absolutely positioned on top. */
.mobile-dash-icon {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

.mobile-dash-icon svg {
  width: 36px;
  height: 36px;
  filter: drop-shadow(0 0 8px rgba(var(--c-gold), 0.6));
  display: block;
}

/* Same scaleY-fill-from-bottom cooldown look as the desktop dash slot's
   .mmo-slot-cooldown-overlay (see style.css's .mmo-slot-cooldown-overlay and
   js/init.js's _updateDashCooldownUI()) -- kept as a separate rule rather
   than sharing that class since this one needs to be a circle (clipped via
   #mobile-dash-btn's overflow:hidden above) instead of a rounded rect. */
.mobile-dash-cooldown-overlay {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100%;
  transform: scaleY(0);
  transform-origin: bottom;
  background: rgba(8, 6, 15, 0.75);
  pointer-events: none;
  transition: transform 0.1s linear;
  z-index: 2;
}

.mobile-dash-cooldown-text {
  position: absolute;
  bottom: 8px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 0.75rem;
  font-weight: 800;
  color: rgb(var(--c-amber));
  text-shadow: 0 1px 3px rgba(0, 0, 0, 1);
  pointer-events: none;
  z-index: 3;
}

.mobile-dash-charge-pips {
  position: absolute;
  top: 10px;
  left: 50%;
  transform: translateX(-50%);
  display: none; /* toggled to flex by JS only when maxDashCharges > 1 */
  gap: 4px;
  z-index: 3;
}

#mobile-dash-btn:active {
  background: rgba(var(--c-secondary), 0.45);
  transform: scale(0.92);
  box-shadow: 0 0 25px rgba(var(--c-secondary), 0.6);
}

/* Read-only twin of #mobile-dash-btn shown in the exact same corner when a
   controller is active on Android (#mobile-controls hides entirely in that
   state -- see the comment on this element in index.html and
   syncMobileUIVisibility() in js/init.js). Smaller and non-interactive
   (pointer-events: none, no :active state, no touch-action) since nobody
   taps it -- it exists purely so a controller player can still see their
   dash cooldown/charges. Shares .mobile-dash-icon/.mobile-dash-cooldown-
   overlay/.mobile-dash-cooldown-text/.mobile-dash-charge-pips with the
   touch button so the fill/text/pips look and animate identically; only
   this wrapper's own size/position/interactivity differ. */
.mobile-gamepad-dash-indicator {
  position: absolute;
  bottom: 60px;
  right: 100px;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  overflow: hidden;
  background: radial-gradient(circle, rgba(var(--c-gold), 0.2) 0%, rgba(20, 16, 36, 0.9) 100%);
  border: 2px solid rgba(var(--c-gold), 0.6);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.6), 0 0 18px rgba(var(--c-gold), 0.35), inset 0 0 12px rgba(var(--c-gold), 0.2);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  z-index: 9;
}

/* Weapon Drop Header & Vector Requisition Emblem */
.weapon-drop-header {
  position: relative;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 44px;
  box-sizing: border-box;
}

.weapon-drop-emblem-wrap {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
}

.weapon-drop-emblem-glow {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(var(--c-secondary), 0.6) 0%, rgba(var(--c-primary), 0.2) 60%, transparent 80%);
  filter: blur(6px);
  animation: wagerGlowPulse 3s ease-in-out infinite alternate;
  pointer-events: none;
}

.weapon-drop-emblem-svg {
  width: 36px;
  height: 36px;
  filter: drop-shadow(0 0 8px rgba(var(--c-secondary), 0.7));
  z-index: 1;
}

.weapon-drop-header-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 2px;
}

.weapon-drop-slot-badge {
  display: inline-block;
  font-family: var(--font-display, inherit);
  font-size: 0.62rem;
  font-weight: bold;
  letter-spacing: 0.08em;
  padding: 2px 10px;
  border-radius: 999px;
  border: 1.5px solid rgba(var(--c-sky), 0.4);
  color: rgb(var(--c-sky));
  background: rgba(0, 0, 0, 0.4);
  box-shadow: 0 0 10px rgba(var(--c-sky), 0.25);
  margin-bottom: 2px;
  text-transform: uppercase;
}

/* Weapon Acquired cards: square hero icon showcasing full weapon artwork */
.card-icon.weapon-drop-banner {
  width: calc(96px * var(--ui-global-scale, 1));
  height: calc(96px * var(--ui-global-scale, 1));
  min-width: calc(96px * var(--ui-global-scale, 1));
  min-height: calc(96px * var(--ui-global-scale, 1));
  margin: 0 auto 12px auto;
  background: rgba(8, 6, 16, 0.65);
  border: 1.5px solid rgba(var(--c-primary), 0.45);
  box-shadow: 0 0 16px rgba(var(--c-primary), 0.25);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 6px;
  box-sizing: border-box;
  flex-shrink: 0;
  transition: transform 0.2s cubic-bezier(0.2, 0.9, 0.3, 1), box-shadow 0.2s ease, border-color 0.2s ease;
}

.card-icon.weapon-drop-banner img.weapon-drop-icon {
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: 8px;
  border: none;
}

:where(body:not(.gamepad-active)) #weapon-drop-screen .upgrade-card:hover .card-icon.weapon-drop-banner,
#weapon-drop-screen .upgrade-card.kb-focused .card-icon.weapon-drop-banner,
#weapon-drop-screen .upgrade-card.controller-focused .card-icon.weapon-drop-banner {
  transform: scale(1.06);
  border-color: rgba(var(--c-primary), 0.85);
  box-shadow: 0 0 22px rgba(var(--c-primary), 0.55);
}

/* the upgrade / swap cards' fill, frame and shadow are the chamfer kit (css/03b-chamfer-kit.css sections 21-22) */
#weapon-drop-screen .upgrade-card,
#weapon-drop-screen .swap-equipped-card {
  padding: 16px 14px;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 6px;
  cursor: pointer;
  transition: transform 0.16s cubic-bezier(0.2, 0.9, 0.3, 1), border-color 0.16s ease, box-shadow 0.16s ease, opacity 0.25s ease, filter 0.25s ease;
  will-change: transform, opacity;
}

/* 3-Card 3D Cascade Reveal */
#weapon-drop-screen .upgrade-card.weapon-card-cascade {
  opacity: 0;
  transform: perspective(800px) translateY(24px) rotateX(15deg) scale(0.92);
  animation: weaponCardCascade 450ms cubic-bezier(0.18, 0.9, 0.26, 1.15) forwards;
  animation-delay: calc(var(--card-index, 0) * 150ms);
}

@keyframes weaponCardCascade {
  0% {
    opacity: 0;
    transform: perspective(800px) translateY(28px) rotateX(18deg) scale(0.9);
  }
  70% {
    opacity: 1;
    transform: perspective(800px) translateY(-4px) rotateX(-2deg) scale(1.02);
  }
  100% {
    opacity: 1;
    transform: perspective(800px) translateY(0) rotateX(0deg) scale(1);
  }
}

:where(body:not(.gamepad-active)) #weapon-drop-screen .upgrade-card:not(.selected):not(.power-up):not(.rejected):not(.fizzle):hover,
#weapon-drop-screen .upgrade-card:not(.selected):not(.power-up):not(.rejected):not(.fizzle).kb-focused,
#weapon-drop-screen .upgrade-card:not(.selected):not(.power-up):not(.rejected):not(.fizzle).controller-focused {
  transform: translateY(-6px);
}

/* Weapon Equip Slam, sibling fizzle, then centre+raise power-up */
#weapon-drop-screen .upgrade-card.selected,
#weapon-drop-screen .swap-equipped-card.selected,
#major-choice-screen .choice-card.selected,
#major-choice-screen .upgrade-card.selected {
  animation: weaponEquipSlam 280ms cubic-bezier(0.15, 0.9, 0.2, 1.25) forwards;
  opacity: 1; /* beat the .weapon-card-cascade base opacity:0 after the fill is replaced */
  z-index: 10;
}

@keyframes weaponEquipSlam {
  0% { transform: scale(1.03); }
  50% { transform: scale(1.12); filter: brightness(1.5) saturate(1.35); }
  100% { transform: scale(1.08); }
}

/* Power-up cinematic: fade header and other controls so the selected card is the hero focus */
#weapon-drop-screen.is-powering-up .weapon-drop-header,
#weapon-drop-screen.is-powering-up .upgrade-header,
#weapon-drop-screen.is-powering-up .weapon-swap-preview-card,
#weapon-drop-screen.is-powering-up #weapon-offer-decline-row,
#weapon-drop-screen.is-powering-up #weapon-drop-control-legend,
#major-choice-screen.is-powering-up .major-choice-header,
#major-choice-screen.is-powering-up .modal-actions {
  opacity: 0;
  transform: translateY(-8px);
  transition: opacity 0.22s ease-out, transform 0.22s ease-out;
  pointer-events: none;
}

/* After the siblings fizzle (runWeaponPowerUp, js/upgrades.js): slide the
   chosen card to the centre of the grid and lift it while it charges.
   --power-x / --power-y are the measured grid-centre offset, set inline
   before the class lands. More specific than .selected, so it replaces the
   equip slam animation. */
#weapon-drop-screen .upgrade-card.selected.power-up,
#weapon-drop-screen .swap-equipped-card.selected.power-up {
  z-index: 20;
  animation: weaponCardPowerUp 620ms cubic-bezier(0.18, 0.9, 0.26, 1.1) forwards;
  will-change: transform, filter;
  pointer-events: none;
}

@keyframes weaponCardPowerUp {
  0% {
    transform: translate(0px, 0px) translateY(0) scale(1.08);
    filter: brightness(1);
  }
  40% {
    transform: translate(var(--power-x, 0px), var(--power-y, 0px)) translateY(-4px) scale(1.1);
    filter: brightness(1.35) saturate(1.3);
  }
  100% {
    transform: translate(var(--power-x, 0px), var(--power-y, 0px)) translateY(-10px) scale(1.15);
    filter: brightness(1.85) saturate(1.5);
  }
}

/* Unselected weapons fizzle out — own fade replaces the cascade animation's
   fill-forwards so the dissolve and blur actually play, settling down as it
   vanishes. */
#weapon-drop-screen .upgrade-card.rejected,
#weapon-drop-screen .swap-equipped-card.rejected {
  animation: weaponSiblingFizzle 260ms cubic-bezier(0.25, 0.9, 0.4, 1) forwards;
  pointer-events: none;
}

@keyframes weaponSiblingFizzle {
  0% { opacity: 1; filter: blur(1px) grayscale(30%); transform: scale(0.98); }
  100% { opacity: 0; filter: blur(4px) grayscale(90%); transform: scale(0.86) translateY(8px); }
}

#weapon-drop-screen .upgrade-card h3 {
  font-size: 1.05rem;
  margin: 2px 0;
  line-height: 1.25;
}

#weapon-drop-screen .upgrade-card .card-desc {
  font-size: 0.78rem;
  line-height: 1.35;
  color: rgba(255, 255, 255, 0.75);
  margin: 0;
}

/* Radial equip shockwave ring + flash burst (spawnWeaponEquipBurst,
   js/upgrades.js). Positioned via inline left/top at the selected card's
   centre, then transform/opacity-only animation -- no per-frame layout.
   Drawn above the .selected card (z 10) but below the always-visible header. */
.weapon-equip-burst {
  position: absolute;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 30;
  border: 2.5px solid rgba(var(--c-secondary), 0.95);
  box-shadow: 0 0 18px rgba(var(--c-secondary), 0.85),
              inset 0 0 6px rgba(var(--c-secondary), 0.6);
  transform: translate(-50%, -50%) scale(0);
  animation: weaponEquipShockwave 600ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

@keyframes weaponEquipShockwave {
  0% {
    transform: translate(-50%, -50%) scale(0);
    opacity: 1;
  }
  100% {
    transform: translate(-50%, -50%) scale(36);
    opacity: 0;
  }
}

.weapon-equip-flash {
  position: absolute;
  width: 120px;
  height: 120px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 29;
  background: radial-gradient(circle, rgba(255, 255, 255, 0.9) 0%, rgba(var(--c-secondary), 0.5) 45%, transparent 70%);
  transform: translate(-50%, -50%) scale(0.4);
  animation: weaponEquipFlash 380ms ease-out forwards;
}

@keyframes weaponEquipFlash {
  0% {
    transform: translate(-50%, -50%) scale(0.4);
    opacity: 0.95;
  }
  100% {
    transform: translate(-50%, -50%) scale(1.8);
    opacity: 0;
  }
}

/* Weapon Major Milestone Choice Epic Selection Power-Up */
#major-choice-screen .choice-card.selected.power-up {
  z-index: 25;
  animation: majorChoiceCardPowerUp 620ms cubic-bezier(0.18, 0.9, 0.26, 1.1) forwards;
  will-change: transform, filter, box-shadow;
  pointer-events: none;
}

@keyframes majorChoiceCardPowerUp {
  0% {
    transform: translate(0px, 0px) translateY(0) scale(1.08);
    filter: brightness(1);
  }
  40% {
    transform: translate(var(--power-x, 0px), var(--power-y, 0px)) translateY(-4px) scale(1.12);
    filter: brightness(1.4) saturate(1.3);
  }
  100% {
    transform: translate(var(--power-x, 0px), var(--power-y, 0px)) translateY(-10px) scale(1.15);
    filter: brightness(1.9) saturate(1.55);
  }
}

#major-choice-screen .choice-card.rejected.fizzle {
  animation: majorChoiceSiblingFizzle 260ms cubic-bezier(0.25, 0.9, 0.4, 1) forwards;
  pointer-events: none;
}

@keyframes majorChoiceSiblingFizzle {
  0% { opacity: 1; filter: blur(1px) grayscale(30%); transform: scale(0.98); }
  100% { opacity: 0; filter: blur(4px) grayscale(90%); transform: scale(0.86) translateY(8px); }
}

/* Tier-Themed Radial Shockwave Ring and Flash for Major Milestone */
.major-choice-burst {
  position: absolute;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 35;
  border: 2.5px solid var(--burst-color, #3b82f6);
  box-shadow: 0 0 20px var(--burst-glow, rgba(59, 130, 246, 0.8)),
              inset 0 0 8px var(--burst-color, #3b82f6);
  transform: translate(-50%, -50%) scale(0);
  animation: majorChoiceShockwave 600ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

.major-choice-burst.ring-2 {
  animation-delay: 90ms;
  border-width: 3.5px;
  box-shadow: 0 0 26px var(--burst-glow, rgba(168, 85, 247, 0.9)),
              inset 0 0 10px #ffffff;
}

@keyframes majorChoiceShockwave {
  0% {
    transform: translate(-50%, -50%) scale(0);
    opacity: 1;
  }
  100% {
    transform: translate(-50%, -50%) scale(38);
    opacity: 0;
  }
}

.major-choice-flash {
  position: absolute;
  width: 130px;
  height: 130px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 34;
  background: radial-gradient(circle, rgba(255, 255, 255, 0.95) 0%, var(--burst-glow, rgba(59, 130, 246, 0.55)) 45%, transparent 70%);
  transform: translate(-50%, -50%) scale(0.4);
  animation: majorChoiceFlash 400ms ease-out forwards;
}

@keyframes majorChoiceFlash {
  0% {
    transform: translate(-50%, -50%) scale(0.4);
    opacity: 0.95;
  }
  100% {
    transform: translate(-50%, -50%) scale(2.0);
    opacity: 0;
  }
}

/* Dynamic Control Hints Panel (js/control-hints.js) */
.control-hints-panel {
  position: fixed;
  bottom: calc(5px + var(--safe-bottom, 0px));
  right: calc(5px + var(--safe-right, 0px));
  display: none; /* toggled to flex by updateControlHintsPanel() */
  flex-direction: row;
  flex-wrap: wrap-reverse;
  justify-content: flex-end;
  align-items: flex-end;
  gap: 8px;
  max-width: calc(60 * var(--vvw));
  pointer-events: none;
  z-index: 600; /* above every overlay (highest existing modal is 500) */
}

.control-hint-chip {
  display: flex;
  align-items: center;
  gap: 6px;
  background: rgba(10, 10, 15, 0.85);
  border: 1px solid rgba(255, 255, 255, 0.12);
  padding: 5px 10px;
}

.control-hint-icons {
  display: flex;
  align-items: center;
  gap: 2px;
}

.control-hint-icon {
  width: 20px;
  height: 20px;
  object-fit: contain;
  opacity: 0.92;
}

.control-hint-label {
  font-size: 0.68rem;
  color: rgba(255, 255, 255, 0.75);
  white-space: nowrap;
}


/* Instructions Modal 2-Column Redesign */
.instructions-glass-panel {
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.7), 0 0 30px rgba(var(--c-primary), 0.15) !important;
}

.instructions-category-group {
  display: flex;
  flex-direction: column;
  margin-bottom: 6px;
}

.instructions-category-header {
  padding: 8px 10px;
  border-radius: 6px;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: rgb(var(--c-primary));
  background: rgba(var(--c-primary), 0.1);
  border: 1px solid rgba(var(--c-primary), 0.22);
  user-select: none;
  transition: all 0.15s ease;
}

:where(body:not(.gamepad-active)) .instructions-category-header:hover,
.instructions-category-header.controller-focused {
  background: rgba(var(--c-primary), 0.22);
  border-color: rgb(var(--c-primary));
  color: #ffffff;
  box-shadow: 0 0 10px rgba(var(--c-primary), 0.3);
}

.instructions-category-chevron {
  font-size: 0.65rem;
  color: rgba(255, 255, 255, 0.5);
  margin-left: auto;
  transition: transform 0.2s ease;
}

.instructions-category-group.collapsed .instructions-category-chevron {
  transform: rotate(-90deg);
}

.instructions-category-children {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-left: 10px;
  margin-top: 4px;
  margin-bottom: 4px;
  border-left: 1.5px dashed rgba(var(--c-primary), 0.3);
}

.instructions-category-group.collapsed .instructions-category-children {
  display: none;
}

.instructions-nav-list {
  scrollbar-width: thin;
  scrollbar-color: rgba(var(--c-primary), 0.4) transparent;
}

.instructions-nav-item {
  padding: 10px 12px;
  border-radius: 6px;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 10px;
  transition: all 0.15s ease;
  font-size: 0.8rem;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.75);
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid transparent;
  user-select: none;
}

:where(body:not(.gamepad-active)) .instructions-nav-item:hover {
  background: rgba(var(--c-primary), 0.15);
  color: #ffffff;
  border-color: rgba(var(--c-primary), 0.3);
}

.instructions-nav-item.active,
.instructions-nav-item.controller-focused {
  background: linear-gradient(135deg, rgba(var(--c-primary), 0.3), rgba(var(--c-focus), 0.2)) !important;
  color: #ffffff !important;
  border-color: rgb(var(--c-primary)) !important;
  box-shadow: 0 0 12px rgba(var(--c-primary), 0.35) !important;
}

/* ===========================================================
   CHARACTER SELECT (Hero Showcase Stage)
   =========================================================== */

#character-select-screen .glass-panel.wide-panel,
#character-select-screen .character-select-stage-frame {
  width: min(1120px, calc(96 * var(--vvw)));
  max-width: calc(96 * var(--vvw));
  max-height: min(760px, calc(94 * var(--vvh)));
  padding: calc(16px * var(--ui-global-scale, 1)) calc(20px * var(--ui-global-scale, 1));
  display: flex;
  flex-direction: column;
  gap: 10px;
  box-sizing: border-box;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  position: relative;
  text-align: left;
  /* window look (fill, border, corners, glow) comes from the chamfer kit: .cut.cx-win, 03b-chamfer-kit.css */
}

#character-select-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  border-bottom: 1.5px solid rgba(255, 255, 255, 0.08);
  padding-bottom: 8px;
  flex-shrink: 0;
  box-sizing: border-box;
  gap: 12px;
}

.char-select-header-title-wrap {
  display: flex;
  align-items: center;
  gap: 14px;
}

.char-select-title {
  font-size: 1.45rem;
  margin: 0;
  color: rgb(var(--c-violet));
  letter-spacing: 0.06em;
}

.char-select-progress-badge {
  font-size: 0.8rem;
  font-weight: 800;
  color: rgb(var(--c-gold));
  background: rgba(var(--c-gold), 0.12);
  border: 1px solid rgba(var(--c-gold), 0.35);
  padding: 3px 10px;
  border-radius: 999px;
  letter-spacing: 0.04em;
}

#character-select-back-btn,
.char-select-back-btn {
  padding: 8px 24px;
  font-size: 0.88rem;
  font-weight: 700;
  border: 1.5px solid rgba(255, 255, 255, 0.15);
  background: rgba(255, 255, 255, 0.03);
  color: #fff;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s;
}

:where(body:not(.gamepad-active)) #character-select-back-btn:hover,
#character-select-back-btn.controller-focused {
  background: rgba(var(--c-danger), 0.2);
  border-color: rgb(var(--c-danger));
  color: #fff;
}

/* Main Hero Showcase Stage (25% Left Hologram + 75% Right Details) */
.char-hero-stage {
  display: flex;
  gap: 16px;
  align-items: stretch;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  box-sizing: border-box;
  overflow: hidden;
}

/* Left Canvas Hologram Stage (Fixed 25% Width) */
.char-hero-canvas-wrap {
  flex: 0 0 25% !important;
  width: 25% !important;
  max-width: 25% !important;
  min-width: 0 !important;
  height: 100% !important;
  min-height: 0 !important;
  position: relative;
  background: radial-gradient(circle at center, rgba(var(--c-primary), 0.12) 0%, rgba(0, 0, 0, 0.5) 75%);
  border: 1.5px solid rgba(var(--c-primary), 0.3);
  box-shadow: inset 0 0 25px rgba(var(--c-primary), 0.15);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  box-sizing: border-box;
}

.char-hero-canvas {
  width: 100%;
  height: 100%;
  display: block;
}

.char-hero-holo-ring {
  position: absolute;
  width: 250px;
  height: 250px;
  border-radius: 50%;
  border: 1px dashed rgba(var(--c-sky), 0.25);
  pointer-events: none;
  animation: spin 30s linear infinite;
}

.char-hero-holo-grid {
  position: absolute;
  inset: 0;
  background-image: linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
                    linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
  background-size: 20px 20px;
  pointer-events: none;
}

.char-hero-lock-overlay {
  position: absolute;
  inset: 0;
  background: rgba(10, 8, 20, 0.88);
  backdrop-filter: blur(4px);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 16px;
  text-align: center;
  z-index: 5;
}

.char-lock-icon {
  font-size: 2.2rem;
  filter: drop-shadow(0 0 10px rgba(var(--c-gold), 0.5));
}

.char-lock-hint {
  font-size: 0.85rem;
  font-weight: 700;
  color: rgb(var(--c-gold));
  letter-spacing: 0.02em;
}

/* Right Details Column (Fills remaining 75% container width) */
.char-hero-details {
  flex: 1 1 calc(75% - 16px) !important;
  width: calc(75% - 16px) !important;
  min-width: 0 !important;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 8px;
  background: rgba(0, 0, 0, 0.28);
  border: 1px solid rgba(255, 255, 255, 0.08);
  padding: 14px 18px;
  box-sizing: border-box;
  overflow: hidden;
  position: relative;
}

.char-hero-identity {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.char-hero-name-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
}

.char-hero-name {
  font-size: 1.65rem;
  font-weight: 900;
  letter-spacing: 0.03em;
  margin: 0;
  color: #ffffff;
  text-shadow: 0 0 12px rgba(255, 255, 255, 0.3);
}

.char-hero-archetype-pill {
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  background: rgba(var(--c-sky), 0.15);
  border: 1px solid rgb(var(--c-sky));
  color: rgb(var(--c-sky));
  text-shadow: 0 0 8px rgba(var(--c-sky), 0.4);
}

.char-hero-tier-pips {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 6px;
}

.char-hero-desc {
  font-size: 0.76rem;
  line-height: 1.35em;
  min-height: 2.7em;
  max-height: 2.7em;
  color: rgba(255, 255, 255, 0.72);
  margin: 0;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* Stat Meters Grid */
.char-hero-stat-meters {
  display: flex;
  flex-direction: column;
  gap: 6px;
  background: rgba(255, 255, 255, 0.02);
  padding: 8px 12px;
  border: 1px solid rgba(255, 255, 255, 0.04);
}

.char-stat-meter-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.char-stat-label-wrap {
  display: flex;
  justify-content: space-between;
  font-size: 0.72rem;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.8);
}

.char-stat-val {
  font-family: monospace;
  font-size: 0.75rem;
  color: rgb(var(--c-gold));
}

.char-stat-bar-track {
  width: 100%;
  height: 6px;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.08);
  overflow: hidden;
  position: relative;
}

.char-stat-bar-fill {
  height: 100%;
  border-radius: 3px;
  transition: width 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

.char-stat-bar-fill.hp {
  background: linear-gradient(90deg, rgb(var(--c-danger)), rgb(var(--c-rose)));
  box-shadow: 0 0 6px rgba(var(--c-rose), 0.5);
}

.char-stat-bar-fill.damage {
  background: linear-gradient(90deg, #f59e0b, rgb(var(--c-gold)));
  box-shadow: 0 0 6px rgba(var(--c-gold), 0.5);
}

.char-stat-bar-fill.speed {
  background: linear-gradient(90deg, rgb(var(--c-success)), rgb(var(--c-mint)));
  box-shadow: 0 0 6px rgba(var(--c-mint), 0.5);
}

.char-stat-bar-fill.special {
  background: linear-gradient(90deg, #8b5cf6, rgb(var(--c-sky)));
  box-shadow: 0 0 6px rgba(var(--c-sky), 0.5);
}

/* Starting Weapon Card */
.char-hero-weapon-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: linear-gradient(135deg, rgba(20, 26, 44, 0.7) 0%, rgba(10, 14, 24, 0.85) 100%);
  border: 1px solid rgba(var(--c-accent), 0.28);
  padding: 10px 14px;
  position: relative;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(8px);
}

.char-hero-weapon-card::before {
  content: "";
  position: absolute;
  top: 0;
  left: 12px;
  right: 12px;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(var(--c-accent), 0.5), transparent);
  pointer-events: none;
}

.char-weapon-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
}

.char-weapon-sub {
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  color: rgba(var(--c-accent), 0.85);
  text-shadow: 0 0 8px rgba(var(--c-accent), 0.35);
}

.char-weapon-tags {
  display: flex;
  gap: 6px;
  align-items: center;
  flex-wrap: wrap;
}

.weapon-tag-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 2.5px 8px;
  font-family: var(--font-display, inherit);
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.1;
  color: var(--tag-color, #94a3b8);
  background: var(--tag-bg, rgba(148, 163, 184, 0.15));
  border: 1px solid var(--tag-border, rgba(148, 163, 184, 0.35));
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35), inset 0 0 6px rgba(0, 0, 0, 0.2);
  text-shadow: 0 0 6px var(--tag-color, #94a3b8);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
  white-space: nowrap;
}

.char-weapon-body {
  display: flex;
  align-items: center;
  gap: 12px;
}

.char-weapon-icon-frame {
  width: 54px;
  height: 54px;
  flex-shrink: 0;
  border-radius: 8px;
  background: radial-gradient(circle at 50% 50%, rgba(var(--c-accent), 0.12) 0%, rgba(8, 12, 22, 0.85) 100%);
  border: 1px solid rgba(var(--c-accent), 0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: hidden;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.char-weapon-icon-frame::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 6px;
  height: 6px;
  border-top: 1.5px solid rgba(var(--c-accent), 0.85);
  border-left: 1.5px solid rgba(var(--c-accent), 0.85);
  pointer-events: none;
}

.char-weapon-icon-frame::after {
  content: "";
  position: absolute;
  bottom: 0;
  right: 0;
  width: 6px;
  height: 6px;
  border-bottom: 1.5px solid rgba(var(--c-accent), 0.85);
  border-right: 1.5px solid rgba(var(--c-accent), 0.85);
  pointer-events: none;
}

.char-weapon-icon {
  width: 46px;
  height: 46px;
  object-fit: contain;
  filter: drop-shadow(0 0 6px rgba(var(--c-accent), 0.45));
}

.char-weapon-info {
  display: flex;
  flex-direction: column;
  gap: 3px;
  flex: 1;
  min-width: 0;
}

.char-weapon-name {
  font-size: 0.95rem;
  font-weight: 800;
  letter-spacing: 0.02em;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
}

.char-weapon-desc {
  font-size: 0.72rem;
  color: rgba(255, 255, 255, 0.68);
  line-height: 1.35em;
  min-height: 2.7em;
  max-height: 2.7em;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* Hero Action Controls */
.char-hero-actions {
  display: flex;
  gap: 10px;
  align-items: center;
  margin-top: 2px;
  width: 100%;
}

/* Character-select buttons: chamfered .btn buttons (css/03b-chamfer-kit.css section 12). This module
   now only carries layout (flex ratios, sizing, icon gap). The violet screen accent gives the
   primary Deploy its solid violet fill; hover/focus come from the kit (the old gradient, glow,
   outline and translateY lifts were deleted). Back keeps its danger-red hover intent. */
.char-deploy-btn {
  flex: 1.5;
  padding: 10px 18px;
  font-size: 0.95rem;
  font-weight: 800;
  gap: 8px;
}

.char-tree-btn {
  flex: 1.1;
  padding: 10px 14px;
  font-size: 0.88rem;
  font-weight: 700;
  gap: 8px;
}

.char-back-btn,
#character-select-back-btn {
  flex: 0.7;
  padding: 10px 14px;
  font-size: 0.88rem;
  font-weight: 700;
  gap: 6px;
  --bd: rgba(var(--c-ink), 0.25);
  --bg: rgba(var(--c-ink), 0.05);
}

:where(body:not(.gamepad-active)) .char-back-btn:hover,
:where(body:not(.gamepad-active)) #character-select-back-btn:hover {
  --bd: rgb(var(--c-danger));
  --bg: rgba(var(--c-danger), 0.2);
}

.char-deploy-pad-icon,
.char-tree-pad-icon,
.char-back-pad-icon {
  width: 18px;
  height: 18px;
  object-fit: contain;
  vertical-align: middle;
  flex-shrink: 0;
  filter: drop-shadow(0 0 4px rgba(255, 255, 255, 0.4));
}

.char-tree-badge {
  display: inline-flex;
  min-width: 16px;
  height: 16px;
  padding: 0 5px;
  border-radius: 999px;
  background: rgb(var(--c-gold));
  color: #000;
  font-size: 0.68rem;
  font-weight: 900;
  align-items: center;
  justify-content: center;
}

/* Bottom Horizontal Roster Dock (Dynamic Full Width 5 or 6 Column Centered Grid) */
.char-roster-dock,
#character-select-grid {
  display: grid !important;
  grid-template-columns: repeat(var(--roster-cols, 5), minmax(0, 1fr)) !important;
  gap: 12px;
  width: 100% !important;
  max-width: 100% !important;
  margin: 0 auto !important;
  justify-content: center !important;
  align-items: stretch;
  padding: 4px 0;
  box-sizing: border-box;
  flex: 0 0 auto;
  min-height: 0;
}

#character-select-grid.roster-cols-6,
.char-roster-dock.roster-cols-6 {
  gap: 8px;
}

#character-select-grid.roster-cols-6 .char-roster-card,
#character-select-grid.roster-cols-6 .survivor-card,
.char-roster-dock.roster-cols-6 .char-roster-card,
.char-roster-dock.roster-cols-6 .survivor-card {
  padding: 6px 4px;
}

#character-select-grid.roster-cols-6 .survivor-card__name,
.char-roster-dock.roster-cols-6 .survivor-card__name {
  font-size: 0.82rem;
}

#character-select-grid.roster-cols-6 .survivor-card__archetype,
.char-roster-dock.roster-cols-6 .survivor-card__archetype {
  font-size: 0.6rem;
}

.char-roster-card,
.survivor-card {
  width: 100% !important;
  min-width: 0 !important;
  max-width: 100% !important;
  padding: 8px 6px;
  color: #fff;
  cursor: pointer;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  text-align: center;
  transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  box-sizing: border-box;
}

/* Frame, fill, hover, active and focus are the chamfer kit (css/03b section 23); the card only lifts. The
   old active underline (::after) is a --bg layer there, so ::after stays free for the kit focus frame. */
:where(body:not(.gamepad-active)) .char-roster-card:hover,
.char-roster-card.active,
:where(body:not(.gamepad-active)) .survivor-card:hover,
.survivor-card.active {
  transform: translateY(-2px);
}

.survivor-card--locked,
.char-roster-card.locked {
  cursor: default;
  opacity: 0.5;
  filter: grayscale(1);
}

.survivor-card__portrait {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  overflow: hidden;
  background: rgba(var(--c-primary), 0.12);
  border: 1.5px solid rgba(var(--c-primary), 0.3);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.survivor-card__ship {
  display: block;
  width: 70%;
  height: 70%;
  overflow: visible;
}

.survivor-card__name {
  font-weight: bold;
  font-size: 0.88rem;
  letter-spacing: 0.02em;
}

.survivor-card__archetype {
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: rgb(var(--c-sky));
}

.survivor-card__upgrades-badge,
.char-card-points-badge {
  position: absolute;
  top: 6px;
  right: 6px;
  min-width: 14px;
  height: 14px;
  padding: 0 4px;
  border-radius: 999px;
  background: rgb(var(--c-gold));
  color: #000;
  font-size: 0.62rem;
  font-weight: 900;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0 6px rgba(var(--c-gold), 0.6);
}

.survivor-card__tiers {
  display: flex;
  align-items: center;
  gap: 5px;
}

.survivor-card__tier-pip {
  width: 8px;
  height: 8px;
  min-width: 8px;
  min-height: 8px;
  border-radius: 50% !important;
  border: 1.5px solid var(--pip-color, rgba(255, 255, 255, 0.4)) !important;
  background: transparent !important;
  box-sizing: border-box;
  display: inline-block !important;
  flex-shrink: 0;
}

.survivor-card__tier-pip.is-unlocked {
  background: var(--pip-color, #a855f7) !important;
  box-shadow: 0 0 8px var(--pip-color, #a855f7) !important;
}

.char-hero-tier-pips .survivor-card__tier-pip {
  width: 10px;
  height: 10px;
  min-width: 10px;
  min-height: 10px;
}

.char-roster-card .survivor-card__tiers {
  position: absolute;
  top: 6px;
  left: 6px;
  display: flex;
  gap: 3px;
  align-items: center;
}

/* ===========================================================
   DIFFICULTY SELECT OVERLAY (Threat Matrix & Mission Briefing Stage)
   =========================================================== */

.difficulty-select-stage-frame {
  width: 95% !important;
  max-width: 1040px !important;
  max-height: calc(92 * var(--vvh)) !important;
  display: flex !important;
  flex-direction: column !important;
  gap: 12px !important;
  padding: 18px 24px !important;
  box-sizing: border-box !important;
  position: relative !important;
  /* window look (fill, border, corners, glow) comes from the chamfer kit: .cut.cx-win, 03b-chamfer-kit.css */
}

/* Header Bar */
.difficulty-select-header {
  display: flex !important;
  justify-content: space-between !important;
  align-items: center !important;
  width: 100% !important;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08) !important;
  padding-bottom: 8px !important;
  gap: 12px !important;
  flex: 0 0 auto !important;
}

.difficulty-header-title-wrap {
  display: flex;
  align-items: center;
  gap: 12px;
}

.difficulty-title {
  font-size: 1.25rem !important;
  font-weight: 900 !important;
  letter-spacing: 0.06em !important;
  color: #fff !important;
  margin: 0 !important;
  text-transform: uppercase !important;
  text-shadow: 0 0 12px rgba(var(--c-primary), 0.6) !important;
}

.difficulty-progress-badge {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 800;
  background: rgba(var(--c-primary), 0.15);
  border: 1px solid rgba(var(--c-primary), 0.4);
  color: #d8b4fe;
}

.difficulty-survivor-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 12px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.1);
  margin-left: auto;
}

.difficulty-survivor-ship {
  display: inline-flex;
  width: 22px;
  height: 22px;
}
.difficulty-survivor-ship svg { width: 100%; height: 100%; }

.difficulty-survivor-name {
  font-size: 0.88rem;
  font-weight: 800;
  color: #fff;
}

.difficulty-survivor-archetype {
  font-size: 0.65rem;
  font-weight: 800;
  letter-spacing: 0.05em;
  padding: 2px 6px;
  background: rgba(var(--c-sky), 0.15);
  color: rgb(var(--c-sky));
  border: 1px solid rgba(var(--c-sky), 0.3);
}

/* 3-Card Thematic Threat Deck */
.difficulty-threat-deck,
#difficulty-select-grid {
  display: grid !important;
  grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
  gap: 14px !important;
  width: 100% !important;
  flex: 1 1 auto !important;
  min-height: 0 !important;
  align-items: stretch !important;
  padding: 4px 0 !important;
  box-sizing: border-box !important;
}

.difficulty-threat-card {
  position: relative;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  cursor: pointer;
  transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  box-sizing: border-box;
  overflow: hidden;
  text-align: left;
}

/* Thematic tier colours. --r is the tier as an R, G, B channel: the kit frame, fill wash and underline
   (css/03b section 23) are built from it; --threat-color / --threat-glow stay for the inner meters. */
.difficulty-threat-card.tier-normal {
  --r: var(--c-success);
  --threat-color: rgb(var(--c-success));
  --threat-glow: rgba(var(--c-success), 0.45);
}

.difficulty-threat-card.tier-normal .threat-multiplier-badge {
  background: rgba(var(--c-success), 0.12);
  border-color: rgba(var(--c-success), 0.5);
  color: rgb(var(--c-mint));
}

.difficulty-threat-card.tier-overdrive {
  --r: 245, 158, 11;
  --threat-color: #f59e0b;
  --threat-glow: rgba(245, 158, 11, 0.45);
}

.difficulty-threat-card.tier-overdrive .threat-multiplier-badge {
  background: rgba(245, 158, 11, 0.12);
  border-color: rgba(245, 158, 11, 0.5);
  color: rgb(var(--c-gold));
}

.difficulty-threat-card.tier-overload,
.difficulty-threat-card.tier-system_overload {
  --r: var(--c-danger);
  --threat-color: rgb(var(--c-danger));
  --threat-glow: rgba(var(--c-danger), 0.5);
}

.difficulty-threat-card.tier-overload .threat-multiplier-badge,
.difficulty-threat-card.tier-system_overload .threat-multiplier-badge {
  background: rgba(var(--c-danger), 0.15);
  border-color: rgba(var(--c-danger), 0.5);
  color: #ff6b6b;
}

/* Active (the selected tier), hover and gamepad focus are the chamfer kit (css/03b section 23): the old
   ::after underline became a --bg layer there, so ::after is free for the kit focus frame. The card
   only lifts. */
:where(body:not(.gamepad-active)) .difficulty-threat-card:hover,
.difficulty-threat-card.controller-focused {
  transform: translateY(-2px);
}

:where(body:not(.gamepad-active)) .difficulty-threat-card:hover .threat-multiplier-badge,
.difficulty-threat-card.controller-focused .threat-multiplier-badge {
  box-shadow: 0 0 10px var(--threat-glow);
}

/* Card Header */
.threat-card-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 6px;
  flex: 0 0 auto;
}

.threat-title-wrap {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.threat-name {
  font-size: 1.05rem;
  font-weight: 900;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--threat-color);
  margin: 0;
}

.threat-tagline {
  font-size: 0.68rem;
  font-style: italic;
  color: rgba(255, 255, 255, 0.55);
}

.threat-multiplier-badge {
  padding: 2px 7px;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 900;
  background: rgba(0, 0, 0, 0.4);
  border: 1px solid var(--threat-color);
  color: var(--threat-color);
  white-space: nowrap;
}

/* 4 Cyber Threat Progress Meters */
.threat-meters-wrap {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 6px 0;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  flex: 0 0 auto;
}

.threat-meter-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.threat-meter-labels {
  display: flex;
  justify-content: space-between;
  font-size: 0.62rem;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.7);
}

.threat-meter-val {
  font-weight: 800;
  color: #fff;
}

.threat-meter-track {
  height: 5px;
  width: 100%;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 999px;
  overflow: hidden;
}

.threat-meter-fill {
  height: 100%;
  border-radius: 999px;
  transition: width 0.3s ease;
}

.threat-meter-fill.fill-vitality {
  background: linear-gradient(90deg, rgb(var(--c-danger)), #f87171);
}
.threat-meter-fill.fill-lethality {
  background: linear-gradient(90deg, #f59e0b, rgb(var(--c-gold)));
}
.threat-meter-fill.fill-swarm {
  background: linear-gradient(90deg, rgb(var(--c-primary)), rgb(var(--c-violet)));
}
.threat-meter-fill.fill-hazards {
  background: linear-gradient(90deg, #06b6d4, rgb(var(--c-sky)));
}
.threat-meter-fill.fill-rewards {
  background: linear-gradient(90deg, rgb(var(--c-success)), rgb(var(--c-gold)));
}

/* Badges & Modifiers Box */
.threat-badges-box {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: auto;
  min-height: 22px;
  align-items: center;
}

.threat-badge-pill {
  font-size: 0.62rem;
  font-weight: 800;
  padding: 2px 6px;
  background: rgba(255, 255, 255, 0.05);
  color: rgba(255, 255, 255, 0.8);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.threat-badge-pill.danger {
  background: rgba(var(--c-danger), 0.15);
  color: #fca5a5;
  border-color: rgba(var(--c-danger), 0.35);
}

/* Best Wave Record */
.threat-record-box {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.68rem;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.6);
  padding-top: 2px;
}

.threat-record-val {
  color: rgb(var(--c-gold));
  font-weight: 800;
  display: inline-flex;
  align-items: center;
  gap: 3px;
}

.threat-record-val.empty {
  color: rgba(255, 255, 255, 0.4);
}

.threat-record-val.victory {
  color: rgb(var(--c-gold));
  text-shadow: 0 0 10px rgba(var(--c-gold), 0.4);
}

/* Locked Card State & Overlay */
.difficulty-threat-card.difficulty-card--locked {
  cursor: default;
}

:where(body:not(.gamepad-active)) .difficulty-threat-card.difficulty-card--locked:hover {
  transform: none;
}

.threat-lock-overlay {
  position: absolute;
  /* inset by the frame width so the kit frame (css/03b section 23) stays visible around the lock */
  inset: 2px;
  background: rgba(10, 8, 18, 0.88);
  backdrop-filter: blur(4px);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 16px;
  text-align: center;
  z-index: 5;
  box-sizing: border-box;
}

.threat-lock-icon {
  font-size: 1.6rem;
  filter: drop-shadow(0 0 8px rgba(var(--c-gold), 0.6));
}

.threat-lock-hint {
  font-size: 0.74rem;
  font-weight: 700;
  color: rgb(var(--c-gold));
  line-height: 1.35;
}

/* Action Controls Row */
.difficulty-hero-actions {
  display: flex;
  gap: 12px;
  align-items: center;
  justify-content: center;
  width: 100%;
  margin-top: 2px;
  flex: 0 0 auto;
}

/* Difficulty-select buttons: chamfered .btn buttons (css/03b-chamfer-kit.css section 12); layout only
   here. The emerald screen accent gives Launch its solid green fill; the disabled look is the
   kit's hazard stripe (the old opacity/box-shadow overrides were deleted). */
.difficulty-launch-btn {
  flex: 1.6;
  max-width: 280px;
  padding: 10px 22px;
  font-size: 0.95rem;
  font-weight: 800;
  gap: 8px;
}

.difficulty-back-btn,
#difficulty-select-back-btn {
  flex: 0.8;
  max-width: 140px;
  padding: 10px 16px;
  font-size: 0.88rem;
  font-weight: 700;
  gap: 6px;
  --bd: rgba(var(--c-ink), 0.25);
  --bg: rgba(var(--c-ink), 0.05);
}

:where(body:not(.gamepad-active)) .difficulty-back-btn:hover,
:where(body:not(.gamepad-active)) #difficulty-select-back-btn:hover {
  --bd: rgb(var(--c-danger));
  --bg: rgba(var(--c-danger), 0.2);
}

.difficulty-launch-pad-icon,
.difficulty-back-pad-icon {
  width: 18px;
  height: 18px;
  object-fit: contain;
  vertical-align: middle;
  flex-shrink: 0;
  filter: drop-shadow(0 0 4px rgba(255, 255, 255, 0.4));
}

/* Responsive Roster Grid Rules */
@media (max-width: 900px) {
  #character-select-grid,
  .char-roster-dock {
    grid-template-columns: repeat(var(--roster-cols, 5), minmax(0, 1fr)) !important;
    gap: 8px !important;
    width: 100% !important;
  }
  .char-roster-card,
  .survivor-card {
    min-width: 0 !important;
    max-width: none !important;
    width: 100% !important;
  }
}

/* Narrow windows: shrink the heading rather than letting "Choose Your
   Survivor" wrap to two lines. The wrap costs a whole line of vertical space
   on exactly the screens that have least of it, and the progress count was
   wrapping with it. */
@media (max-width: 620px) {
  #character-select-header h2 { font-size: 1.15rem; }
  #character-select-progress { font-size: 0.8rem; }
}

@media (max-width: 470px) {
  #character-select-header h2 { font-size: 1rem; letter-spacing: 0.02em; }
  #character-select-progress { font-size: 0.72rem; }
}

/* Landscape phones and short windows: vertical space is the constraint, not
   horizontal. A 373px-tall window leaves roughly 140px for a card that wanted
   ~215px, which clipped the stat list mid-way. Everything below buys that
   back -- smaller portrait, tighter gaps, smaller type, and less chrome
   around the grid -- so the whole card fits rather than relying on the
   scrollbar. Scrolling is the safety net for even shorter windows, not the
   primary answer. */
@media (max-height: 600px) {
  #character-select-screen .glass-panel.wide-panel,
  #difficulty-select-screen .glass-panel.wide-panel {
    padding: 8px 14px !important;
    gap: 4px !important;
    max-height: calc(96 * var(--vvh)) !important;
  }

  #character-select-header,
  #difficulty-select-header {
    padding-bottom: 4px !important;
    gap: 8px !important;
  }

  #character-select-header h2,
  #difficulty-select-header h2 {
    font-size: 1.05rem !important;
  }

  #character-select-progress,
  #difficulty-select-survivor {
    font-size: 0.72rem !important;
  }

  #character-select-grid,
  .char-roster-dock {
    grid-template-columns: repeat(var(--roster-cols, 5), minmax(0, 1fr)) !important;
    padding: 4px 0 !important;
    gap: 6px !important;
    width: 100% !important;
  }

  #difficulty-select-grid {
    padding: 6px 4px 6px !important;
    gap: 8px !important;
  }

  .char-roster-card,
  .survivor-card {
    min-width: 0 !important;
    max-width: none !important;
    width: 100% !important;
    padding: 4px 4px !important;
    gap: 1px !important;
    min-height: 0 !important;
  }

  .survivor-card__portrait {
    width: 28px !important;
    height: 28px !important;
  }


  .survivor-card__name {
    font-size: 0.8rem !important;
  }

  .survivor-card__archetype {
    font-size: 0.54rem !important;
    letter-spacing: 0.04em !important;
  }

  .survivor-card__tiers {
    min-height: 6px !important;
    gap: 3px !important;
    margin-top: 0 !important;
  }

  .survivor-card__tier-pip {
    width: 5px !important;
    height: 5px !important;
  }


  .survivor-card__upgrades {
    margin-top: auto !important;
    padding: 3px 8px !important;
    font-size: 0.64rem !important;
    border-radius: 6px !important;
    gap: 4px !important;
  }

  .survivor-card__upgrades-badge {
    min-width: 13px !important;
    height: 13px !important;
    font-size: 0.55rem !important;
  }


  #character-select-back-btn,
  #difficulty-select-back-btn {
    padding: 4px 20px !important;
    font-size: 0.76rem !important;
    border-radius: 6px !important;
  }
}

.instructions-nav-badge {
  font-size: 1.1rem;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Weapon tutorial topics use the weapon's real icon art in place of an
   emoji badge (instructionsBadgeHtml, js/instructions-panel.js). Sized
   inline per call site so the nav row and the larger detail heading can
   share one helper. object-fit keeps non-square art from stretching. */
.instructions-badge-img {
  object-fit: contain;
  flex-shrink: 0;
  vertical-align: middle;
  image-rendering: auto;
}

.instructions-nav-title {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
}

.instructions-detail-panel {
}


/* Round Complete Banner (index.html #round-complete-banner) */
.round-complete-banner {
  position: fixed;
  top: 14%;
  left: 50%;
  transform: translate(-50%, -16px) scale(0.85);
  opacity: 0;
  pointer-events: none;
  z-index: 500;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display, "Outfit", sans-serif);
  font-weight: 800;
  white-space: nowrap;
  transition: opacity 0.35s ease, transform 0.35s ease;
}

.round-complete-banner.show {
  opacity: 1;
  transform: translate(-50%, 0) scale(1);
}

.round-complete-title {
  font-size: 2.1rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgb(var(--c-success));
  text-shadow: 0 0 20px rgba(var(--c-success), 0.6), 0 0 42px rgba(var(--c-success), 0.35);
}

.round-wager-payout-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: rgba(15, 23, 42, 0.94);
  backdrop-filter: blur(10px);
  border: 1.5px solid rgb(var(--c-gold));
  padding: 6px 18px;
  font-size: 0.88rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #ffffff;
  animation: wagerPayoutBadgePulse 1.8s ease-in-out infinite alternate;
}

.round-wager-payout-tag {
  background: rgba(var(--c-gold), 0.22);
  color: rgb(var(--c-gold));
  border: 1px solid rgba(var(--c-gold), 0.6);
  padding: 2px 7px;
  font-size: 0.72rem;
  font-weight: 900;
}

.round-wager-rewards-text {
  color: rgb(var(--c-sky));
  text-shadow: 0 0 8px rgba(var(--c-sky), 0.5);
  font-weight: 800;
}

.round-wager-voided-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: rgba(20, 10, 15, 0.94);
  backdrop-filter: blur(10px);
  border: 1.5px solid rgb(var(--c-danger));
  box-shadow: 0 0 18px rgba(var(--c-danger), 0.45);
  border-radius: 999px;
  padding: 6px 18px;
  font-size: 0.82rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #f87171;
}

.round-wager-voided-tag {
  background: rgba(var(--c-danger), 0.25);
  color: #f87171;
  border: 1px solid rgba(var(--c-danger), 0.6);
  padding: 2px 7px;
  border-radius: 6px;
  font-size: 0.72rem;
  font-weight: 900;
}

@keyframes wagerPayoutBadgePulse {
  0% { transform: scale(1); filter: brightness(1); }
  100% { transform: scale(1.02); filter: brightness(1.15); box-shadow: 0 0 26px rgba(var(--c-gold), 0.6); }
}

@media (max-width: 600px), (max-height: 500px) {
  .round-complete-title {
    font-size: 1.5rem;
  }
  .round-wager-payout-badge,
  .round-wager-voided-badge {
    font-size: 0.74rem;
    padding: 4px 12px;
  }
}

/* Achievement unlock toast (index.html #achievement-toast, driven by
   js/achievements.js's AchievementToastUI) -- top-center, non-blocking,
   glassmorphic to match .glass-panel/.glass-card elsewhere. Queued one at a
   time; .active is toggled by JS, never left on permanently. */
.achievement-toast {
  position: fixed;
  /* Never above 70px: the desktop boss lines sit 34-56px from the top (HUD overhaul Phase 2), and
     6% alone reached them on short windows (36px at 1366x600). */
  top: max(6%, 70px);
  left: 50%;
  transform: translate(-50%, -14px);
  opacity: 0;
  pointer-events: none;
  z-index: 550;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 22px;
  background: rgba(20, 16, 36, 0.9);
  border: 1.5px solid rgba(var(--c-gold), 0.5);
  transition: opacity 0.35s cubic-bezier(0.16, 1, 0.3, 1),
              transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
  white-space: nowrap;
}

.achievement-toast.active {
  opacity: 1;
  transform: translate(-50%, 0);
}

.achievement-toast-badge {
  font-size: 2rem;
  line-height: 1;
  filter: drop-shadow(0 0 8px rgba(var(--c-gold), 0.6));
}

/* Bonus-weapon unlock toast icon (js/achievements.js's AchievementToastUI._advance(),
   when `data.iconSrc` is set) -- real weapon artwork instead of the plain
   emoji glyph regular achievement toasts use, sized to roughly match the
   2rem emoji's visual footprint above. */
.achievement-toast-badge-img {
  width: 34px;
  height: 34px;
  object-fit: contain;
  filter: drop-shadow(0 0 8px rgba(var(--c-gold), 0.6));
}

.achievement-toast-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: left;
}

.achievement-toast-title {
  font-family: var(--font-display, "Outfit", sans-serif);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgb(var(--c-gold));
}

.achievement-toast-name {
  font-family: var(--font-display, "Outfit", sans-serif);
  font-size: 1.05rem;
  font-weight: 800;
  color: #fff;
  text-shadow: 0 0 10px rgba(255, 255, 255, 0.2);
}

/* Achievements & Unlocks Screen (index.html #achievements-screen, rendered by
   js/achievements.js) -- 2-column split-panel interface with dynamic category
   sidebar, glassmorphism cards, and multi-input accessibility. */
.ach-modal-panel {
  height: min(700px, calc(88 * var(--vvh))) !important;
  max-height: calc(88 * var(--vvh)) !important;
  width: min(1120px, calc(94 * var(--vvw))) !important;
  max-width: 1120px !important;
  padding: calc(20px * var(--ui-global-scale, 1)) calc(24px * var(--ui-global-scale, 1)) !important;
  display: flex !important;
  flex-direction: column !important;
  gap: 12px !important;
  text-align: left !important;
  position: relative !important;
  box-sizing: border-box !important;
  overflow: hidden !important;
}

.ach-close-btn {
  /* chamfered close button: shape / colours / hover / focus from css/03b-chamfer-kit.css section 16 */
  position: absolute;
  top: 18px;
  right: 18px;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 6px;
}

.ach-close-pad-icon {
  width: 18px;
  height: 18px;
}

.ach-modal-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  width: 100%;
  border-bottom: 1.5px solid rgba(255, 255, 255, 0.08);
  padding-bottom: 10px;
  padding-right: 48px;
  flex-shrink: 0;
  box-sizing: border-box;
}

.ach-header-title-wrap {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.ach-header-subtitle {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: rgb(var(--c-primary));
  text-transform: uppercase;
}

.ach-header-title {
  color: #fff;
  margin: 0;
  text-transform: uppercase;
  font-size: 1.5rem;
  letter-spacing: 0.05em;
}

.ach-header-badge {
  color: rgb(var(--c-gold));
  font-size: 0.95rem;
  font-weight: bold;
  letter-spacing: 0.04em;
}

/* Top Pill Tabs Bar */
.ach-top-tabs-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  flex-shrink: 0;
}

.ach-tabs-row {
  display: flex;
  flex: 1;
  max-width: 460px;
  /* segmented control: frame, inset and gap from css/03b-chamfer-kit.css section 18 */
}

.ach-tab {
  flex: 1;
  padding: 8px 16px;
  font-family: var(--font-display, "Outfit", sans-serif);
  font-size: 0.84rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  text-align: center;
  outline: none;
  /* colour / fill / active / hover / focus: css/03b-chamfer-kit.css section 18 */
}

/* 2-Column Split Layout */
.ach-split-layout {
  display: flex !important;
  width: 100% !important;
  gap: 16px !important;
  flex: 1 !important;
  min-height: 0 !important;
  align-items: stretch !important;
  overflow: hidden !important;
  box-sizing: border-box !important;
}

/* Left Category Sidebar Navigation */
.ach-sidebar {
  display: flex !important;
  flex-direction: column !important;
  gap: 6px !important;
  width: 230px !important;
  min-width: 230px !important;
  max-width: 230px !important;
  flex-shrink: 0 !important;
  border-right: 1.5px solid rgba(255, 255, 255, 0.08) !important;
  padding: 4px 10px 4px 2px !important;
  box-sizing: border-box !important;
  overflow-y: auto !important;
  overflow-x: hidden !important;
}

.ach-sidebar-tab {
  /* The shared sidebar-tab shell (fill, rail, hover, active, focus) is .side-tab,
     css/03b-chamfer-kit.css section 19. Only what differs from the settings tab stays here:
     two rows (label + count) instead of one. */
  flex-direction: column;
  justify-content: center;
  min-height: 54px;
  gap: 4px;
  padding: 8px 12px;
  font-size: 0.84rem;
}

.ach-sidebar-tab-top,
.ach-sidebar-tab-left {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  width: 100%;
}

.ach-sidebar-tab-bottom {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  width: 100%;
  min-height: 18px;
}

.ach-sidebar-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  color: rgba(255, 255, 255, 0.65);
  transition: color 0.2s, transform 0.2s;
}

:where(body:not(.gamepad-active)) .ach-sidebar-tab:hover .ach-sidebar-icon,
.ach-sidebar-tab.active .ach-sidebar-icon {
  color: rgb(var(--acc));
  transform: scale(1.1);
}

.ach-sidebar-tab.controller-focused .ach-sidebar-icon {
  color: rgb(var(--c-focus));
}

.ach-sidebar-label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
}

.ach-sidebar-count {
  font-size: 0.72rem;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.45);
  background: rgba(0, 0, 0, 0.35);
  padding: 2px 7px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  flex-shrink: 0;
  font-family: monospace;
  letter-spacing: 0.2px;
}

.ach-sidebar-tab.active .ach-sidebar-count {
  color: rgb(var(--c-gold));
  border-color: rgba(var(--c-gold), 0.25);
}

/* Right Content Pane */
.ach-content-pane {
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-sizing: border-box;
}

.ach-scroll-container {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: 6px;
  box-sizing: border-box;
}

.ach-category {
  margin-bottom: 20px;
}

.ach-category.controller-focused {
  outline: 2px solid rgb(var(--c-focus));
  outline-offset: 4px;
  border-radius: 8px;
  background: rgba(var(--c-focus), 0.05);
}

.ach-category-title {
  font-family: var(--font-display, "Outfit", sans-serif);
  font-size: 0.88rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #60a5fa;
  border-bottom: 1px dashed rgba(96, 165, 250, 0.3);
  padding-bottom: 4px;
  margin: 0 0 10px 0;
}

.ach-subgroup-title {
  font-family: var(--font-display, "Outfit", sans-serif);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
  margin: 12px 0 6px 4px;
}

.ach-subgroup-hint {
  text-transform: none;
  font-weight: 500;
  letter-spacing: normal;
  color: rgba(255, 255, 255, 0.35);
}

.ach-family-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px 14px;
  background: rgba(255, 255, 255, 0.025);
  border: 1.5px solid rgba(255, 255, 255, 0.06);
  margin-bottom: 8px;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

:where(body:not(.gamepad-active)) .ach-family-row:hover {
  background: rgba(255, 255, 255, 0.04);
  border-color: rgba(var(--c-primary), 0.3);
}

.ach-family-row.controller-focused {
  border-color: rgb(var(--c-focus)) !important;
  box-shadow: 0 0 14px rgba(var(--c-focus), 0.6) !important;
  outline: 2px solid rgb(var(--c-focus)) !important;
  outline-offset: 1px;
}

.ach-standalone-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  background: rgba(255, 255, 255, 0.025);
  border: 1.5px solid rgba(255, 255, 255, 0.06);
  margin-bottom: 8px;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

:where(body:not(.gamepad-active)) .ach-standalone-row:hover {
  background: rgba(255, 255, 255, 0.04);
  border-color: rgba(var(--c-primary), 0.3);
}

.ach-standalone-row.controller-focused {
  border-color: rgb(var(--c-focus)) !important;
  box-shadow: 0 0 14px rgba(var(--c-focus), 0.6) !important;
  outline: 2px solid rgb(var(--c-focus)) !important;
  outline-offset: 1px;
}

.ach-family-row-top {
  display: flex;
  align-items: center;
  gap: 12px;
}

.ach-family-desc {
  font-size: 0.74rem;
  color: rgba(255, 255, 255, 0.65);
  padding-left: 2px;
  line-height: 1.35;
}

.ach-family-name, .ach-standalone-name {
  flex-shrink: 0;
  width: 170px;
  font-size: 0.84rem;
  font-weight: 700;
  color: #fff;
}

.ach-badges {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}

.ach-family-status-wrap {
  flex: 1;
  min-width: 90px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: flex-end;
}

.ach-family-status {
  font-size: 0.7rem;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.6);
  white-space: nowrap;
}

.ach-progress-bar {
  width: 100%;
  max-width: 140px;
  height: 6px;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.08);
  overflow: hidden;
}

.ach-progress-bar-fill {
  height: 100%;
  background: linear-gradient(90deg, #f59e0b, rgb(var(--c-gold)));
  border-radius: 3px;
  transition: width 0.3s ease;
}

.ach-standalone-status {
  flex-shrink: 0;
  font-size: 0.72rem;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.5);
  white-space: nowrap;
}

.ach-standalone-status.unlocked {
  color: rgb(var(--c-success));
}

.ach-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(var(--c-gold), 0.12);
  border: 1.5px solid rgba(var(--c-gold), 0.4);
  cursor: default;
  transition: transform 0.15s;
}

.ach-badge.locked {
  background: rgba(255, 255, 255, 0.03);
  border: 1.5px solid rgba(255, 255, 255, 0.08);
  filter: grayscale(1);
  opacity: 0.35;
}

:where(body:not(.gamepad-active)) .ach-badge:hover {
  transform: scale(1.12);
}

.ach-standalone-icon {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(var(--c-gold), 0.12);
  border: 1.5px solid rgba(var(--c-gold), 0.4);
}

.ach-standalone-row.locked .ach-standalone-icon {
  background: rgba(255, 255, 255, 0.03);
  border: 1.5px solid rgba(255, 255, 255, 0.08);
  filter: grayscale(1);
  opacity: 0.5;
}

.ach-standalone-row.locked .ach-standalone-name,
.ach-standalone-row.locked .ach-standalone-desc {
  opacity: 0.4;
}

.ach-standalone-desc {
  font-size: 0.74rem;
  color: rgba(255, 255, 255, 0.6);
  line-height: 1.35;
}

.ach-grandmaster-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: 10px;
}

.ach-grandmaster-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 10px 6px;
  background: rgba(255, 255, 255, 0.025);
  border: 1.5px solid rgba(255, 255, 255, 0.06);
  text-align: center;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

:where(body:not(.gamepad-active)) .ach-grandmaster-item:hover {
  background: rgba(255, 255, 255, 0.04);
  border-color: rgba(var(--c-gold), 0.4);
  transform: translateY(-2px);
}

.ach-grandmaster-item.controller-focused {
  border-color: rgb(var(--c-focus)) !important;
  box-shadow: 0 0 14px rgba(var(--c-focus), 0.6) !important;
  transform: translateY(-2px);
}

.ach-grandmaster-item.locked {
  opacity: 0.4;
  filter: grayscale(1);
}

.ach-grandmaster-item .ach-standalone-icon {
  width: 36px;
  height: 36px;
}

.ach-grandmaster-item span {
  font-size: 0.68rem;
  font-weight: 600;
  color: #fff;
  line-height: 1.25;
}

/* Unlocks tab weapon rows (index.html #unlocks-body, rendered by
   js/achievements.js's renderUnlocksTab()/renderWeaponUnlockItem()) --
   same row layout as .ach-standalone-row above, but with a real weapon
   icon <img> instead of an emoji badge. Locked bonus weapons render the
   real icon put through grayscale+brightness(0) to read as a black
   silhouette (shape barely legible, colors/details fully hidden) plus a
   lock badge, with the name replaced by "???" and the description
   replaced by which Grandmaster achievement unlocks it -- see
   BONUS_WEAPON_TO_GRANDMASTER in js/bonus-weapons.js. */
.unlock-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 10px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid rgba(255, 255, 255, 0.05);
  margin-bottom: 6px;
}

.unlock-icon-wrap {
  position: relative;
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(var(--c-gold), 0.12);
  border: 1.5px solid rgba(var(--c-gold), 0.4);
  overflow: hidden;
}

.unlock-icon {
  width: 22px;
  height: 22px;
  object-fit: contain;
}

.unlock-item.locked .unlock-icon-wrap {
  background: rgba(255, 255, 255, 0.03);
  border: 1.5px solid rgba(255, 255, 255, 0.08);
}

.unlock-item.locked .unlock-icon {
  filter: grayscale(1) brightness(0);
  opacity: 0.55;
}

.unlock-lock-badge {
  position: absolute;
  bottom: -3px;
  right: -3px;
  font-size: 0.62rem;
  background: rgba(15, 10, 25, 0.9);
  border-radius: 50%;
  width: 15px;
  height: 15px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(255, 255, 255, 0.15);
}

.unlock-info {
  flex: 1;
  min-width: 0;
}

.unlock-name {
  font-size: 0.82rem;
  font-weight: 700;
  color: #fff;
}

.unlock-item.locked .unlock-name {
  color: rgba(255, 255, 255, 0.4);
  font-style: italic;
  letter-spacing: 0.1em;
}

.unlock-desc {
  font-size: 0.72rem;
  color: rgba(255, 255, 255, 0.6);
}

.unlock-item.locked .unlock-desc {
  color: rgba(255, 255, 255, 0.35);
}

.unlock-status {
  flex-shrink: 0;
  font-size: 0.9rem;
  color: rgba(255, 255, 255, 0.3);
}

.unlock-item.controller-focused {
  border-color: rgb(var(--c-focus)) !important;
  box-shadow: 0 0 14px rgba(var(--c-focus), 0.6) !important;
  outline: 2px solid rgb(var(--c-focus)) !important;
  outline-offset: 1px;
}


/* Dash charge pips (index.html #mmo-dash-charge-pips, populated by
   js/init.js's _updateDashCooldownUI()) -- small dots under the desktop dash
   slot showing how many of the player's dash charges (see maxDashCharges in
   js/player.js) are currently banked, only shown at all when maxDashCharges
   > 1. Found this comment cut off with the rules it describes never
   actually written -- a pre-existing gap, not something touched by any
   recent change -- so the pips had no styling at all (invisible 0x0 spans)
   whenever a player had more than one dash charge. */
.mmo-dash-charge-pips {
  position: absolute;
  bottom: 3px;
  left: 50%;
  transform: translateX(-50%);
  display: none; /* toggled to flex by JS only when maxDashCharges > 1 */
  gap: 3px;
  z-index: 2;
}

.dash-charge-pip {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.25);
  border: 1px solid rgba(255, 255, 255, 0.3);
}

.dash-charge-pip.filled {
  background: rgb(var(--c-sky));
  border-color: rgba(var(--c-sky), 0.6);
  box-shadow: 0 0 4px rgba(var(--c-sky), 0.8);
}

/* Pause-screen equipment columns (index.html #pause-weapons-column/
   #pause-gear-column, populated once per pause by js/shop.js's
   updatePauseEquipmentDisplay()) -- a read-only summary of the player's
   current loadout, shown down the left (weapons) and right (gear) edges of
   the screen while paused. Positioned absolute within #pause-screen (an
   .overlay, which flex-centers its one existing child, the pause panel) so
   these two columns sit at the screen edges without disturbing that
   centering -- every platform (not just mobile) sees this, since it's on
   the shared pause screen. */
.pause-weapons-column,
.pause-gear-column {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 12px;
  z-index: 1;
}

.pause-weapons-column {
  left: 40px;
}

.pause-gear-column {
  right: 40px;
}

/* Pause-screen Combat & Weapon Damage Stats Modal */
#pause-stats-modal .glass-panel {
  max-width: 560px;
  width: 90%;
  border: 1.5px solid rgba(var(--c-sky), 0.3);
}


.pause-damage-rows {
  display: flex;
  flex-direction: column;
  gap: 6px;
  overflow-y: auto;
  font-size: 0.72rem;
  line-height: 1.35;
  color: rgba(255, 255, 255, 0.85);
  /* Scrollable rather than clipped: a late run can hold 6+ weapons, and the
     column is height-capped above. pointer-events re-enabled just here so a
     mouse wheel still works over the list on desktop. */
  pointer-events: auto;
}

.pause-slot-icon {
  position: relative;
  width: 48px;
  height: 48px;
  border-radius: 8px;
  background: rgba(20, 16, 36, 0.65);
  border: 2px solid rgba(255, 255, 255, 0.15);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.3rem;
  flex-shrink: 0;
}

.pause-slot-icon img {
  width: 28px;
  height: 28px;
  object-fit: contain;
}

.pause-slot-icon.empty {
  opacity: 0.35;
}

.pause-slot-level {
  position: absolute;
  bottom: -3px;
  right: -3px;
  font-size: 0.55rem;
  font-weight: 800;
  color: #fff;
  background: rgba(0, 0, 0, 0.75);
  border-radius: 4px;
  padding: 1px 3px;
  line-height: 1.2;
}


/* ============================================================
   The Vibe Web â€” radial passive tree overlay (js/passive-tree.js)
   Opens ABOVE the shop screen (base .overlay z-index is 200).
   ============================================================ */
/* The Vibe Web is now the 3rd tab pane inside #shop-screen (see
   index.html's "Tab Content Area") instead of its own full-screen
   .overlay -- PassiveTreeUI.open()/close() (js/passive-tree.js) still just
   toggle the .active class exactly as before, this only changes what that
   class means visually: a flex tab pane instead of a fixed, viewport-
   covering layer. checkIfModalsOpen()/main-loop.js's activeMenu detection
   both key off this same #passive-tree-screen.active check and need no
   changes as a result. */
#passive-tree-screen {
  display: none;
  flex: 1;
  min-height: 0;
  width: 100%;
  flex-direction: column;
}
#passive-tree-screen.active {
  display: flex;
}

.passive-tree-layout {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: row;
  background: rgba(5, 4, 12, 0.55);
  overflow: hidden;
  position: relative;
}

/* Floating overlay at the top of the tree canvas itself, replacing the old
   dedicated header row (title/points/"Back to Bazaar" button) now that the
   Vibe Web is a Bazaar tab -- the tab row above already handles navigation,
   and this reads as part of the tree view rather than a separate toolbar.
   pointer-events: none so it never blocks dragging/panning the canvas
   underneath it; the text itself has nothing to click. */
.passive-tree-topbar {
  position: absolute;
  top: 14px;
  left: 16px;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 6px 14px;
  border-radius: 20px;
  background: rgba(10, 8, 20, 0.55);
  border: 1px solid rgba(var(--c-primary), 0.25);
  backdrop-filter: blur(4px);
  pointer-events: none;
  z-index: 2;
}


/* Overclock Points readout (index.html #passive-tree-oc-points) -- cyan
   instead of .passive-tree-coins' gold so it reads as a visually distinct
   currency from Vibe Points at a glance, matching the electric/lightning
   accent color used elsewhere for dash/overclock-flavored UI. */
.passive-tree-oc-points {
  color: rgb(var(--c-sky));
  font-weight: 700;
  font-size: 0.85rem;
  white-space: nowrap;
}

.passive-tree-body {
  position: relative;
  flex: 1;
  min-width: 0;
  min-height: 0;
  height: 100%;
  /* Screen layer (plans/VIBE_WEB_CYBER_PLAN.md 2.3): the "monitor" the web sits in. Static and
     behind the canvas (which is cleared to transparent each frame), so it costs nothing per frame
     and never moves with the camera: a faint cyan centre bloom, a 40px grid and a vignette. */
  background:
    radial-gradient(ellipse at 50% 50%, rgba(34, 211, 238, 0.05), transparent 60%),
    radial-gradient(ellipse at 50% 50%, transparent 55%, rgba(0, 0, 0, 0.55) 100%),
    linear-gradient(rgba(148, 163, 184, 0.045) 1px, transparent 1px) 0 0 / 40px 40px,
    linear-gradient(90deg, rgba(148, 163, 184, 0.045) 1px, transparent 1px) 0 0 / 40px 40px,
    #07060f;
}

/* Scanlines over the web, under the node panel (z-index 3) and the drawer button (10). One static
   layer; skipped on .is-mobile, where it would be one more full-screen layer to composite over a
   canvas that redraws every frame. */
.passive-tree-body::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.022) 0 1px, transparent 1px 3px);
}

/* Telemetry readout, bottom-left, in the kit kicker style. Hidden on phones and short screens: the
   concept mock-up showed it colliding with the Survivability plate at 915x412. */
.passive-tree-body::before {
  content: "VIBE//NET \00B7  SECTOR MAP \00B7  3 / 3 SECTORS ONLINE";
  position: absolute;
  left: 14px;
  bottom: 10px;
  z-index: 2;
  pointer-events: none;
  font: 500 10px/1 var(--font-display);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: rgba(148, 163, 184, 0.5);
  white-space: nowrap;
}

.is-mobile .passive-tree-body::after,
.is-mobile .passive-tree-body::before {
  display: none;
}

@media (max-height: 480px) {
  .passive-tree-body::before {
    display: none;
  }
}

/* Set by PassiveTreeRenderer._updateZoomBounds() when even the fitted web is bigger than the canvas
   (1280x720): the readout would sit on the web. */
.passive-tree-body.ptree-web-overflows::before {
  display: none;
}

#passive-tree-canvas {
  width: 100%;
  height: 100%;
  display: block;
  cursor: grab;
}

.passive-tree-hint {
  display: none !important;
  pointer-events: none !important;
}

/* ============================================================
   Vibe Web Passives Upgrades Sidebar
   ============================================================ */
.passive-tree-sidebar {
  width: 280px;
  flex-shrink: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: rgba(14, 11, 26, 0.94);
  border-left: 1px solid rgba(var(--c-primary), 0.25);
  backdrop-filter: blur(8px);
  box-sizing: border-box;
  z-index: 5;
  transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.25s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}

.passive-tree-sidebar.controller-focused {
  border-left: 2px solid rgb(var(--c-primary));
  box-shadow: -4px 0 22px rgba(var(--c-primary), 0.45), inset 0 0 16px rgba(var(--c-primary), 0.12);
}

.passive-tree-sidebar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(20, 16, 36, 0.7);
  gap: 8px;
  flex-shrink: 0;
}

.passive-tree-sidebar-title-group {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  flex: 1;
}

.passive-tree-sidebar-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgb(var(--c-primary));
  filter: drop-shadow(0 0 6px rgba(var(--c-primary), 0.5));
  flex-shrink: 0;
}

.passive-tree-sidebar-title {
  font-size: 0.84rem;
  font-weight: 800;
  color: #ffffff;
  margin: 0;
  white-space: nowrap;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.passive-tree-sidebar-header-right {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}

.passive-tree-nodes-pill {
  font-size: 0.7rem;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 0; /* kit 4px chamfer pill */
  background: rgba(var(--c-primary), 0.18);
  border: 1px solid rgba(var(--c-primary), 0.4);
  color: rgb(var(--c-primary));
  letter-spacing: 0.03em;
  white-space: nowrap;
}

.passive-tree-gp-hint {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 7px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 0; /* kit 4px chamfer pill */
  font-size: 0.68rem;
  font-weight: 700;
  color: #fff;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.passive-tree-gp-hint img {
  width: 14px;
  height: 14px;
  display: block;
}

.passive-tree-sidebar-close-btn {
  /* chamfered close button: css/03b-chamfer-kit.css section 16 (hidden until the drawer mode shows it) */
  display: none;
  align-items: center;
  justify-content: center;
}

.passive-tree-sidebar-content {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  box-sizing: border-box;
}

/* Controller navigation hint footer when sidebar is focused */
.passive-tree-sidebar-gp-footer {
  display: flex;
  align-items: center;
  justify-content: space-around;
  padding: 8px 12px;
  background: rgba(10, 8, 18, 0.88);
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  font-size: 0.7rem;
  color: rgba(255, 255, 255, 0.75);
  flex-shrink: 0;
}

.passive-tree-sidebar-gp-footer .gp-hint-item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

.passive-tree-sidebar-gp-footer .gp-hint-item img {
  width: 15px;
  height: 15px;
  display: block;
}

/* Empty State */
.passive-tree-sidebar-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 28px 8px;
  color: rgba(255, 255, 255, 0.45);
  gap: 8px;
}

.sidebar-empty-title {
  font-size: 0.8rem;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.6);
  margin: 0;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.sidebar-empty-desc {
  font-size: 0.73rem;
  line-height: 1.45;
  margin: 0;
}

/* Thematic Stat Category Sections */
.passive-sidebar-section {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.passive-sidebar-section-header {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.76rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  padding-bottom: 4px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.passive-sidebar-section-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
}

.section-damage .passive-sidebar-section-header {
  color: #f87171;
}
.section-damage .passive-sidebar-section-dot {
  background: #ef4444;
  box-shadow: 0 0 8px rgba(239, 68, 68, 0.7);
}

.section-survivability .passive-sidebar-section-header {
  color: #60a5fa;
}
.section-survivability .passive-sidebar-section-dot {
  background: #3b82f6;
  box-shadow: 0 0 8px rgba(59, 130, 246, 0.7);
}

.section-speed .passive-sidebar-section-header {
  color: #c084fc;
}
.section-speed .passive-sidebar-section-dot {
  background: #a855f7;
  box-shadow: 0 0 8px rgba(168, 85, 247, 0.7);
}

.section-other .passive-sidebar-section-header {
  color: #22d3ee;
}
.section-other .passive-sidebar-section-dot {
  background: #06b6d4;
  box-shadow: 0 0 8px rgba(6, 182, 212, 0.7);
}

.passive-sidebar-stat-list {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.passive-sidebar-stat-row {
  display: flex;
  align-items: baseline;
  gap: 7px;
  font-size: 0.78rem;
  color: #f1f5f9;
  line-height: 1.45;
}

.passive-sidebar-stat-row .stat-bullet {
  font-size: 0.65rem;
  color: rgba(var(--c-primary), 0.9);
  flex-shrink: 0;
}

.passive-sidebar-stat-row .stat-text {
  font-weight: 600;
  color: #ffffff;
}

/* Floating Mobile Sidebar Toggle Button */
.passive-tree-sidebar-toggle {
  display: none;
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 10;
  background: rgba(14, 11, 26, 0.88);
  border: 1px solid rgba(var(--c-primary), 0.45);
  color: #fff;
  border-radius: 0; /* kit chamfer */
  padding: 5px 12px;
  font-size: 0.72rem;
  font-weight: 700;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  backdrop-filter: blur(6px);
  transition: all 0.2s ease;
}

:where(body:not(.gamepad-active)) .passive-tree-sidebar-toggle:hover {
  background: rgba(28, 22, 52, 0.95);
  border-color: rgba(var(--c-primary), 0.8);
}

/* The chamfer's clip-path would cut off an outline or outer glow, so focus is drawn inside. */
.passive-tree-sidebar-toggle:focus-visible,
.passive-tree-sidebar-toggle.controller-focused {
  outline: none;
  border-color: rgb(var(--c-primary));
  box-shadow: inset 0 0 0 1px rgb(var(--c-primary)), inset 0 0 10px rgba(var(--c-primary), 0.45);
}

/* Selected-node info panel */
.passive-tree-panel {
  position: absolute;
  z-index: 3; /* above the scanline overlay (.passive-tree-body::after) */
  top: 16px;
  right: 16px;
  width: 250px;
  max-width: calc(100% - 32px);
  /* Cyber window (plans/VIBE_WEB_CYBER_PLAN.md 2.4): 12px kit chamfer (css/03b-chamfer-kit.css
     section 24 lists), a border and 64x2 top bar in the node's sector colour (--tn-accent, set by
     PassiveTreeUI.showNodePanel()), faint scanlines over a dark gradient. No box-shadow: the
     chamfer's clip-path would cut it off anyway. */
  --tn-accent: rgb(var(--c-primary));
  background:
    linear-gradient(var(--tn-accent), var(--tn-accent)) 18px 0 / 64px 2px no-repeat,
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.02) 0 1px, transparent 1px 3px),
    linear-gradient(160deg, rgba(16, 12, 32, 0.97), rgba(7, 6, 16, 0.97));
  border: 1px solid rgba(var(--c-primary), 0.45);
  border-color: color-mix(in srgb, var(--tn-accent) 55%, transparent);
  border-radius: 0;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  box-shadow: none;
}

/* Chamfer sizes. The kit lists contain ids, so their --cx-ic (and their position: relative) beat a
   plain class here; these are id-scoped to win. The panel and the drawer button must stay
   absolutely positioned: the kit's position: relative dropped the panel below the canvas. */
#passive-tree-screen #tree-node-panel {
  --cx-ic: 12px;
  position: absolute;
}
#passive-tree-screen #passive-tree-sidebar-toggle {
  position: absolute;
}
#passive-tree-screen .tree-node-badge,
#passive-tree-screen .passive-tree-nodes-pill,
#passive-tree-screen .passive-tree-gp-hint {
  --cx-ic: 4px;
  border-radius: 0;
}
#passive-tree-screen .passive-tree-sidebar-toggle {
  --cx-ic: 6px;
  border-radius: 0;
}

/* "NODE //" kicker before the type line, in the accent colour. */
.passive-tree-panel #tree-node-type::before {
  content: "NODE // ";
  color: var(--tn-accent);
}

.passive-tree-panel .tree-node-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}

.passive-tree-panel .tree-node-title-group {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  flex: 1;
}

.passive-tree-panel h3 {
  margin: 0;
  font-size: 1.05rem;
  letter-spacing: 0.03em;
  line-height: 1.25;
  word-break: break-word;
}

.passive-tree-panel #tree-node-type {
  margin: 0;
  font-size: 0.64rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: rgba(203, 213, 225, 0.55);
  line-height: 1.2;
}

/* Dynamic Top-Right Pill Badge (Cost / Owned / Nexus) */
.passive-tree-panel .tree-node-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 8px;
  border-radius: 0; /* kit 4px chamfer pill */
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.05em;
  flex-shrink: 0;
  box-sizing: border-box;
  background: rgba(26, 18, 48, 0.85);
  border: 1px solid rgba(168, 85, 247, 0.4);
  color: #f5d0fe;
  box-shadow: none; /* clipped by the chamfer */
}

.passive-tree-panel .tree-node-badge.badge-cost {
  background: rgba(26, 18, 48, 0.85);
  border: 1px solid rgba(168, 85, 247, 0.4);
  color: #f5d0fe;
}

.passive-tree-panel .tree-node-badge.badge-cost.unaffordable {
  border-color: rgba(248, 113, 113, 0.45);
  color: #f87171;
  background: rgba(45, 15, 20, 0.85);
}

.passive-tree-panel .tree-node-badge.badge-owned {
  border-color: rgba(74, 222, 128, 0.45);
  color: #4ade80;
  background: rgba(14, 42, 24, 0.85);
  font-size: 0.65rem;
  letter-spacing: 0.08em;
  padding: 3px 7px;
}

.passive-tree-panel .tree-node-badge.badge-nexus {
  border-color: rgba(251, 191, 36, 0.5);
  color: #fbbf24;
  background: rgba(45, 34, 10, 0.85);
  font-size: 0.65rem;
  letter-spacing: 0.08em;
  padding: 3px 7px;
}

.passive-tree-panel .tree-node-badge .vibe-point-icon {
  width: 15px;
  height: 15px;
}

.passive-tree-panel #tree-node-stats {
  font-size: 0.8rem;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.9);
}

/* Subtle Cyber Footer Bar */
.passive-tree-panel .tree-node-footer {
  border-top: 1px dashed rgba(148, 163, 184, 0.2);
  padding-top: 8px;
  margin-top: 2px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.passive-tree-panel #tree-node-status {
  margin: 0;
  min-height: 1em;
  font-size: 0.72rem;
  font-weight: 600;
  color: #f87171;
  display: flex;
  align-items: center;
  gap: 6px;
}

.passive-tree-panel #tree-node-status.status-ok {
  color: #38bdf8;
}

.passive-tree-panel #tree-node-status.status-owned {
  color: #4ade80;
}

.passive-tree-panel .tree-node-mouse-hint {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

.passive-tree-panel .tree-node-mouse-hint img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

.passive-tree-panel #tree-buy-btn,
.passive-tree-panel #tree-overclock-btn {
  width: 100%;
  padding: 10px 14px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  box-sizing: border-box;
}

/* .passive-tree-panel #tree-buy-btn:disabled (opacity .45) removed: the disabled look is the kit's
   hazard stripe, css/03b-chamfer-kit.css section 12. */

.tree-btn-controller-a-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #000000;
  border: 1.5px solid rgba(255, 255, 255, 0.85);
  box-shadow: 0 0 6px rgba(0, 0, 0, 0.8), 0 0 6px rgba(59, 130, 246, 0.5);
  flex-shrink: 0;
}

.tree-btn-controller-a-chip img {
  width: 12px;
  height: 12px;
  object-fit: contain;
  display: block;
}

.vibe-point-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

.vibe-point-icon img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

/* Compact header on narrow / mobile viewports */
.is-mobile .passive-tree-topbar {
  top: 8px;
  left: 8px;
  gap: 8px;
  padding: 4px 10px;
}


.is-mobile .passive-tree-oc-points {
  font-size: 0.7rem;
}

.is-mobile .passive-tree-panel {
  top: auto;
  bottom: 12px;
  left: 12px;
  right: 12px;
  width: auto;
}

.is-mobile .passive-tree-hint {
  display: none !important;
  pointer-events: none !important;
}

/* Mobile landscape / narrow viewports (<= 768px):
   Turn sidebar into slide-out drawer with floating toggle button. */
@media (max-width: 768px) {
  .is-mobile .passive-tree-sidebar-toggle {
    display: inline-flex !important;
  }
  .is-mobile .passive-tree-sidebar {
    position: absolute !important;
    top: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    width: 260px !important;
    max-width: 85% !important;
    transform: translateX(100%) !important;
    border-left: 1px solid rgba(var(--c-primary), 0.4) !important;
    z-index: 25 !important;
  }
  .is-mobile .passive-tree-sidebar.drawer-open {
    transform: translateX(0) !important;
  }
  .is-mobile .passive-tree-sidebar-close-btn {
    display: inline-flex !important;
  }
}

/* Larger screens (tablets, Steam Deck, laptops, desktop monitors > 768px):
   Always dock sidebar at fixed 280px width, hide mobile toggle button, and hide drawer close button. */
@media (min-width: 769px) {
  .passive-tree-sidebar-toggle,
  .is-mobile .passive-tree-sidebar-toggle {
    display: none !important;
  }
  .passive-tree-sidebar-close-btn,
  .is-mobile .passive-tree-sidebar-close-btn {
    display: none !important;
  }
  .passive-tree-sidebar,
  .is-mobile .passive-tree-sidebar {
    position: relative !important;
    top: auto !important;
    right: auto !important;
    bottom: auto !important;
    left: auto !important;
    width: 280px !important;
    max-width: 280px !important;
    transform: none !important;
    display: flex !important;
  }
}

/* Weapon Upgrades (#level-up-screen) â€” tighten every dimension so the
   whole tree fits on a phone screen without scrolling the panel itself
   (the tree row still scrolls horizontally on its own if needed). */
.is-mobile #level-up-screen .glass-panel.wide-panel {
  padding: 18px 14px;
}

/* Achievements & Unlocks screen -- same phone-width tightening as
   #level-up-screen above, so the .ach-tab row doesn't get squeezed
   against a still-full-size 32px inline panel padding. */
.is-mobile #achievements-screen .glass-panel.wide-panel {
  padding: 18px 14px;
}

.is-mobile .ach-tab {
  padding: 7px 8px;
  font-size: 0.72rem;
  letter-spacing: 0.02em;
}

.is-mobile .weapon-tree-tabs-row {
  margin-bottom: 10px;
  padding-bottom: 8px;
  gap: 6px;
}

.is-mobile .weapon-tree-tabs {
  --carousel-unit: 105px;
  height: 44px;
}

.is-mobile .weapon-tree-tab {
  padding: 5px 9px;
  font-size: 0.7rem;
}

/* Mobile shows only the active card (updateWeaponTreeCarouselPositions(),
   js/weapon-tree.js, hides the dist-1 peeks entirely on .is-mobile) -- give
   it more room and a centered layout now that there's nothing flanking it,
   instead of leaving it sized as if peeks were still taking up space either
   side. */
.is-mobile .weapon-tree-tab.active {
  padding: 6px 12px;
  font-size: 0.75rem;
  min-width: 160px;
  max-width: 80%;
  justify-content: center;
}

.is-mobile .weapon-tree-carousel-arrow {
  width: 26px;
  height: 26px;
  font-size: 1rem;
}

.is-mobile .weapon-tree-dots {
  /* Row's own padding-bottom shrinks to 8px on mobile (see
     .is-mobile .weapon-tree-tabs-row above) -- keep the dots inside it. */
  bottom: 0px;
}

.is-mobile .weapon-tree-content {
  min-height: 0;
}

.is-mobile .weapon-tree-header {
  gap: 10px;
  margin-bottom: 6px;
}

.is-mobile .weapon-tree-header .weapon-tree-icon {
  width: 42px;
  height: 42px;
}

.is-mobile .weapon-tree-header-text h3 {
  font-size: 0.95rem;
}

/* Mobile trades the desktop scroll box (fine with a mouse, awkward nested
   inside an already-scrollable panel on touch) for a 2-line clamp + a
   "More" toggle (js/weapon-tree.js's setupWeaponTreeDescToggle()) instead,
   requested by Richard so a long description doesn't eat screen space by
   default -- overriding the base .weapon-tree-desc's max-height/overflow-y
   scroll rule entirely rather than combining the two behaviors. */
.is-mobile .weapon-tree-desc {
  font-size: 0.68rem;
  max-height: none;
  overflow-y: visible;
  padding-right: 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.is-mobile .weapon-tree-desc.expanded {
  display: block;
  overflow: visible;
}

.weapon-tree-desc-toggle {
  display: none;
  background: none;
  border: none;
  padding: 2px 0 0 0;
  color: rgb(var(--c-violet));
  font-family: var(--font-display);
  font-size: 0.68rem;
  text-decoration: underline;
  cursor: pointer;
}

.is-mobile .weapon-tree-stats {
  gap: 4px;
  margin: 6px 0;
}

.is-mobile .weapon-tree-stat-chip {
  font-size: 0.62rem;
  padding: 2px 6px;
}


.is-mobile .tree-fork-option {
  min-width: 84px;
  max-width: 120px;
  padding: 5px 7px;
  font-size: 0.6rem;
}

.is-mobile .tree-fork-option .fork-option-name {
  font-size: 0.66rem;
}

/* Scoped classes for the Bazaar header (index.html's #shop-screen) so the
   mobile breakpoint below can override size/padding cleanly -- these
   properties used to be set inline on the elements themselves, and an
   inline style always beats a class rule regardless of media query, so a
   @media override here would have had no effect against them. */
.bazaar-header-title {
  font-size: 1.6rem;
}
.bazaar-header-orb {
  width: 28px;
  height: 28px;
  margin: 0 !important;
  flex-shrink: 0;
}
.bazaar-header-tab {
  /* top tab: cut-tab shape, accent baseline, hover / active / focus from css/03b-chamfer-kit.css
     section 20 */
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 7px 18px;
  cursor: pointer;
  font-family: var(--font-display);
  font-size: 0.9rem;
  white-space: nowrap;
}

/* The Vibe Bazaar (#shop-screen) on narrow / mobile viewports -- the fixed
   96vw x 92vh sizing (index.html) and 3-tab header row read fine on desktop
   but need to shrink further, and the Equipment tab's 2 side-by-side
   columns (Weapons/Gear, Total Stats) don't have room to sit side by side
   on a phone-width screen. */
.is-mobile #shop-screen .glass-panel.wide-panel {
  width: calc(100 * var(--vvw)) !important;
  height: calc(100 * var(--vvh)) !important;
  min-width: calc(100 * var(--vvw)) !important;
  min-height: calc(100 * var(--vvh)) !important;
  max-width: calc(100 * var(--vvw)) !important;
  max-height: calc(100 * var(--vvh)) !important;
  padding-top: calc(4px + var(--safe-top)) !important;
  padding-right: calc(12px + var(--safe-right)) !important;
  padding-bottom: calc(4px + var(--safe-bottom)) !important;
  padding-left: calc(12px + var(--safe-left)) !important;
}

.is-mobile #pause-screen .glass-panel.wide-panel,
.is-mobile #level-up-screen .glass-panel.wide-panel,
.is-mobile #weapon-drop-screen .glass-panel.wide-panel,
.is-mobile #achievements-screen .glass-panel.wide-panel {
  padding-top: calc(16px + var(--safe-top)) !important;
  padding-right: calc(16px + var(--safe-right)) !important;
  padding-bottom: calc(16px + var(--safe-bottom)) !important;
  padding-left: calc(16px + var(--safe-left)) !important;
}

.is-mobile .bazaar-header-title {
  font-size: 1.05rem;
}
.is-mobile .bazaar-header-orb {
  width: 20px;
  height: 20px;
}
.is-mobile .bazaar-header-tab {
  padding: 5px 10px;
  font-size: 0.72rem;
}
.is-mobile .shop-tabs-row {
  gap: 4px !important;
}

/* #shop-next-btn (Start Round) carries the shared `.btn` component class
   (style.css, "Button Component styles"), which sets `width: 100%` -- built
   for buttons that fill a vertically-stacked panel (pause/level-up/etc.),
   not this one, which sits in a grid column next to other content and needs
   to shrink-wrap its own icon+label like the tabs beside it do. Nothing
   overrode that back to content-sized, so #shop-next-btn always tried to be
   "100% wide" against an ambiguous auto grid-column basis -- inflating both
   the button ITSELF (reported as "too big for the top nav") and, worse, the
   whole .shop-header-row's preferred width along with it. `.glass-panel` is
   `flex-direction: column; align-items: center`, so the row is a
   shrink-to-fit flex child that gets horizontally CENTERED in the panel --
   once the row's preferred width (inflated by the button) exceeded the
   panel's own width, centering it pushed the row's left edge (where the
   orb/title sit) out past the panel's actual boundary, which is what the
   user saw as the Vibe Bazaar orb "being cut off" in the top-left corner.
   Not width-gated -- unlike the other bazaar-header shrink rules below, this
   bug is present at every width, not just narrow ones (confirmed from a
   screenshot at 852px, above the 819px breakpoint). */
.shop-header-row .upgrade-header {
  margin: 0 !important;
  margin-bottom: 0 !important;
}

#shop-next-btn {
  width: auto !important;
  min-height: 34px !important;
  padding: 5px 14px;
  font-size: 0.82rem;
  --cut: var(--cut-sm);
}

/* Same shrink as the .is-mobile rules just above, but gated on viewport
   width instead of touch-device detection. .is-mobile only gets added by
   isSmallOrAndroidTouchDevice() (main.js) for a touchscreen (or the Android
   shell) -- a mouse/keyboard user who just resizes their desktop browser
   window narrower never gets it, but .shop-header-row hits the exact same
   overflow either way: at less than ~820px the row's grid-template-columns
   (auto 1fr auto) shrinks its middle column, but .shop-tabs-row is
   `position: absolute; left: 50%` -- centered on the ROW'S FULL width, not
   on that shrunken middle column -- so once the (unshrunk) title/orb on the
   left and the (unshrunk) Start Round button on the right eat into more of
   the row, the still full-size tabs start overlapping the title text
   instead of sitting cleanly between them. #shop-next-btn in particular had
   no responsive sizing at all before this, on ANY path (touch or width), so
   it stayed at its full desktop padding/font-size/icon size no matter how
   narrow the row got -- reported by the user as "the start round button is
   too large" once the header can't comfortably fit it anymore. */
@media (max-width: 819px) {
  .bazaar-header-title {
    font-size: 1.05rem;
  }
  .bazaar-header-orb {
    width: 20px;
    height: 20px;
  }
  .bazaar-header-tab {
    padding: 4px 10px;
    font-size: 0.72rem;
  }
  .shop-tabs-row {
    /* `!important`: .shop-tabs-row's gap: 8px is set inline (index.html),
       which always beats a plain class rule regardless of specificity or
       source order -- the same reason the .is-mobile counterpart above
       needs it too. */
    gap: 4px !important;
  }
  #shop-next-btn {
    min-height: 28px !important;
    padding: 4px 10px !important;
    font-size: 0.72rem !important;
    gap: 4px !important;
  }
  #shop-next-btn .shop-next-btn-menu-icon {
    width: 14px !important;
    height: 14px !important;
  }
}

/* Bazaar Equipment tab's gear/weapon details panel (#shop-weapon-details,
   js/shop.js's showShopWeaponDetails()/showShopGearDetails()) -- this only
   ever had styling inside the narrow-screen media query below, so at normal
   desktop widths it rendered as a bare, unstyled <div>: no background,
   border, or padding, just text floating directly over whatever was behind
   it. Promoted that same look to a real base rule here so it's legible at
   every width; the media query below still applies on top of it (all of
   its declared values are now identical to this base rule, since it was
   really always meant to be the default look, not a narrow-screen-only
   one -- left in place rather than removed to avoid touching working
   mobile behavior over a desktop-only bug). Positioning itself
   (position/top/left/z-index) is set inline by
   positionShopEquipmentTooltip() in js/shop.js, not here. */
.shop-equipment-tooltip-overlay {
  display: none;
  background: rgba(12, 12, 20, 0.95);
  border: 1.5px solid rgba(var(--c-primary), 0.6);
  border-radius: 12px;
  padding: 12px 16px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.85), 0 0 20px rgba(var(--c-primary), 0.25);
  backdrop-filter: blur(14px);
  width: 290px;
  max-width: calc(100 * var(--vvw) - 32px);
  pointer-events: auto;
  color: #fff;
  font-size: 0.75rem;
  line-height: 1.4;
  box-sizing: border-box;
}

/* Stack equipment page columns vertically ONLY on very narrow screens (< 720px) */
@media (max-width: 720px) {
  #shop-content-equipment {
    flex-direction: column !important;
    overflow-y: auto !important;
    gap: 16px !important;
    padding-bottom: calc(16px + var(--safe-bottom)) !important;
  }

  #shop-content-equipment > div {
    width: 100% !important;
    max-width: 100% !important;
    flex: none !important;
    box-sizing: border-box;
  }

  #shop-weapon-details,
  .shop-equipment-tooltip-overlay {
    position: fixed;
    z-index: 10000;
    display: none;
    background: rgba(12, 12, 20, 0.95);
    border: 1.5px solid rgba(var(--c-primary), 0.6);
    border-radius: 12px;
    padding: 12px 16px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.85), 0 0 20px rgba(var(--c-primary), 0.25);
    backdrop-filter: blur(14px);
    width: 290px;
    max-width: calc(100 * var(--vvw) - 32px);
    pointer-events: none;
    color: #fff;
    font-size: 0.75rem;
    line-height: 1.4;
    box-sizing: border-box;
  }

  /* Disable container query height collapse on narrow screens */
  .gear-arpg-wrapper {
    container-type: normal !important;
    width: auto !important;
    height: auto !important;
    display: block !important;
  }

  /* Realign gear layout to be a simple horizontal row when stacked */
  .gear-arpg-layout {
    display: flex !important;
    flex-direction: row !important;
    gap: 8px !important;
    width: auto !important;
    height: auto !important;
    aspect-ratio: auto !important;
    justify-content: start !important;
    align-items: center !important;
  }

  .gear-arpg-layout .mmo-slot {
    width: 44px !important;
    height: 44px !important;
    min-width: 44px !important;
    min-height: 44px !important;
    aspect-ratio: 1 !important;
  }

  .gear-arpg-layout .mmo-slot-icon {
    font-size: 0.95rem !important;
  }
}


/* Make shop cards scale gracefully on mobile while remaining horizontal */
.is-mobile .shop-card {
  width: 190px !important;
  padding: 12px 10px !important;
  flex-shrink: 0 !important;
}

.is-mobile .shop-card h3 {
  font-size: calc(0.9rem * var(--menu-scale)) !important;
}

.is-mobile .shop-card .card-desc {
  font-size: calc(0.72rem * var(--menu-scale)) !important;
}


/* Scrollbars: the global kit scrollbar, css/03b-chamfer-kit.css section 17. */

/* Chaos Wave Button energetic glow and pulse */
.chaos-wave-btn {
  background: linear-gradient(90deg, #8b5cf6, #d946ef) !important;
  color: #fff !important;
  box-shadow: 0 0 15px rgba(139, 92, 246, 0.8), 0 0 30px rgba(217, 70, 239, 0.4) !important;
  animation: chaos-pulse 1.5s infinite alternate !important;
  border: 1px solid rgba(255, 255, 255, 0.3) !important;
}

@keyframes chaos-pulse {
  0% {
    box-shadow: 0 0 10px rgba(139, 92, 246, 0.6), 0 0 20px rgba(217, 70, 239, 0.3);
    transform: scale(1.0);
  }
  100% {
    box-shadow: 0 0 20px rgba(139, 92, 246, 0.9), 0 0 40px rgba(217, 70, 239, 0.6), 0 0 10px rgba(255, 255, 255, 0.5);
    transform: scale(1.02);
  }
}

/* ==========================================================================
   Overclock Nexus Cyber-Console Redesign
   ========================================================================== */
#overclock-nexus-screen {
  /* colour only: the shorthand would also wipe the kit's accent halo (background-image) */
  background-color: rgba(3, 7, 18, 0.88) !important;
  backdrop-filter: blur(16px) !important;
  -webkit-backdrop-filter: blur(16px) !important;
}

#overclock-nexus-screen .overclock-panel {
  width: calc(940px * var(--ui-global-scale, 1));
  max-width: 96%;
  max-height: calc(94 * var(--vvh));
  padding: calc(14px * var(--ui-global-scale, 1)) calc(18px * var(--ui-global-scale, 1));
  position: relative;
  box-sizing: border-box;
  /* window look (fill, border, corners, glow) comes from the chamfer kit: .cut.cx-win, 03b-chamfer-kit.css */
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.overclock-close-btn {
  /* chamfered close button: css/03b-chamfer-kit.css section 16. The 44px touch target stays. */
  position: absolute;
  top: 10px;
  right: 12px;
  min-height: 44px;
  min-width: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
}

.overclock-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 4px;
  padding-right: 36px;
}

.overclock-title-wrap {
  display: flex;
  align-items: center;
  gap: 10px;
}


.overclock-title {
  color: rgb(var(--c-gold));
  font-size: 1.3rem;
  margin: 0;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  display: flex;
  align-items: center;
  gap: 6px;
  background: linear-gradient(90deg, rgb(var(--c-gold)), #f59e0b);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

.overclock-header-controls {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.overclock-mult-selector {
  display: inline-flex;
  align-items: center;
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid rgba(var(--c-gold), 0.35);
  border-radius: 999px;
  padding: 2px 4px;
  gap: 3px;
  box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.5);
}

.overclock-mult-label {
  font-family: var(--font-display);
  font-size: 0.66rem;
  font-weight: bold;
  color: rgba(255, 255, 255, 0.65);
  padding: 0 4px;
  display: inline-flex;
  align-items: center;
  letter-spacing: 0.05em;
}

/* Multiplier segment buttons (x1 / x5 / x10 / MAX): small chamfered buttons, registered in
   css/03b-chamfer-kit.css section 2 (so they get the clip-path, the ::before frame and the kit
   focus variant). The active one is the solid gold segment. */
.overclock-mult-btn {
  --cut: var(--cut-xs);
  --bd: transparent;
  --bg: transparent;
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 700;
  padding: 3px 8px;
  color: rgba(255, 255, 255, 0.65);
  cursor: pointer;
  transition: color 0.15s ease;
  min-height: 26px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

:where(body:not(.gamepad-active)) .overclock-mult-btn:hover {
  --bg: rgba(255, 255, 255, 0.08);
  color: #fff;
}

.overclock-mult-btn.active {
  --bd: rgb(var(--c-gold));
  --bg: rgb(var(--c-gold));
  color: rgb(var(--c-bg));
}

.overclock-points-pill {
  font-family: var(--font-display);
  font-size: 0.88rem;
  background: rgba(0, 0, 0, 0.5);
  border: 1px solid rgba(239, 68, 68, 0.4);
  padding: 4px 12px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  box-shadow: 0 0 12px rgba(239, 68, 68, 0.2), inset 0 0 8px rgba(0, 0, 0, 0.6);
}

.overclock-subtitle {
  font-size: 0.72rem;
  color: rgba(255, 255, 255, 0.6);
  margin: 0 0 8px 0;
  text-align: left;
}

.overclock-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  width: 100%;
  padding: 4px 2px 8px 2px;
  box-sizing: border-box;
  overflow-y: auto;
  max-height: calc(85 * var(--vvh) - 120px);
}

.overclock-card {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  padding: 10px 8px;
  box-sizing: border-box;
  text-align: center;
  position: relative;
  transition: transform 0.18s cubic-bezier(0.2, 0.8, 0.2, 1);
  overflow: hidden;
  /* frame / fill / --r (the upgrade's colour, set inline by js/passive-tree.js): css/03b-chamfer-kit.css section 22 */
}

.overclock-card > * {
  position: relative;
  z-index: 2;
}

/* .overclock-card::before is the chamfer frame now. The pump flash that used to live there is a
   radial layer of the card's --bg driven by the registered --oc-flash (section 22, css/03b). */

:where(body:not(.gamepad-active)) .overclock-card:hover {
  transform: translateY(-2px);
}

.overclock-card.pumping {
  animation: overclockCardPump 0.45s cubic-bezier(0.2, 0.9, 0.3, 1.2), overclockBackdropFlash 0.5s cubic-bezier(0.1, 0.9, 0.2, 1) forwards;
}

/* animates the registered --oc-flash (css/03b-chamfer-kit.css section 22): a colour burst inside the fill */
@keyframes overclockBackdropFlash {
  0% { --oc-flash: 0.95; }
  20% { --oc-flash: 0.8; }
  100% { --oc-flash: 0; }
}

@keyframes overclockCardPump {
  0% {
    transform: scale(1);
    filter: brightness(1);
  }
  20% {
    transform: scale(1.05);
    filter: brightness(1.4);
  }
  100% {
    transform: scale(1);
    filter: brightness(1);
  }
}

.overclock-stat-delta-float {
  position: absolute;
  top: 40%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-family: var(--font-display);
  font-size: 0.82rem;
  font-weight: 800;
  color: rgb(var(--c-gold));
  text-shadow: 0 0 10px rgba(var(--c-gold), 0.9), 0 0 4px #000;
  pointer-events: none;
  z-index: 30;
  animation: overclockStatFloat 0.65s cubic-bezier(0.2, 0.9, 0.3, 1) forwards;
  white-space: nowrap;
}

@keyframes overclockStatFloat {
  0% { opacity: 0; transform: translate(-50%, 0) scale(0.7); }
  25% { opacity: 1; transform: translate(-50%, -10px) scale(1.15); }
  80% { opacity: 0.9; transform: translate(-50%, -24px) scale(1.0); }
  100% { opacity: 0; transform: translate(-50%, -34px) scale(0.9); }
}

.overclock-crest-wrap {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 4px auto;
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.5);
}

.overclock-card-name {
  font-weight: bold;
  font-size: 0.76rem;
  line-height: 1.2;
  word-break: break-word;
  min-height: 2.1em;
  display: flex;
  align-items: center;
  justify-content: center;
}

.overclock-level-badge {
  font-size: 0.62rem;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.5);
  margin-top: 1px;
  letter-spacing: 0.03em;
}

.overclock-card-desc {
  font-size: 0.60rem;
  color: rgba(255, 255, 255, 0.6);
  margin-top: 3px;
  min-height: 2.4em;
  line-height: 1.2;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.overclock-card-stat {
  font-size: 0.72rem;
  color: #ffffff;
  font-weight: bold;
  margin-top: 4px;
}

.overclock-card-next {
  font-size: 0.66rem;
  color: rgb(var(--c-sky));
  font-weight: bold;
  margin-top: 2px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  padding-top: 2px;
}

/* Upgrade button on an Overclock card: a chamfered .btn (css/03b-chamfer-kit.css section 12). It
   is a gold primary when affordable, the hazard stripe when not (:disabled), and the gold-tint
   "MAXED" state with .maxed. The state used to be written as inline background/colour/border by
   js/passive-tree.js; that is gone, the classes and the disabled attribute carry it. */
.btn-upgrade-oc {
  --acc: var(--c-gold);
  --cut: var(--cut-sm);
  width: 100%;
  min-height: 40px;
  padding: 6px 4px;
  font-size: 0.66rem;
  font-weight: bold;
  letter-spacing: 0.06em;
  margin-top: 6px;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
}

.overclock-nexus-core-icon {
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  filter: drop-shadow(0 0 10px rgba(var(--c-gold), 0.65));
}

.overclock-y-hint {
  display: none;
  align-items: center;
}

body.gamepad-active .overclock-y-hint {
  display: inline-flex;
}

.oc-btn-a-badge {
  display: none;
  align-items: center;
  margin-right: 4px;
}

body.gamepad-active .btn-upgrade-oc.controller-focused .oc-btn-a-badge {
  display: inline-flex;
}

.overclock-card.controller-focused-card {
  /* the frame is the kit focus variant (css/03b-chamfer-kit.css sections 4 and 22); only the lift stays */
  transform: translateY(-3px);
}

.overclock-card.maxed {
  --bd: rgba(var(--c-gold), 0.55);
}

.overclock-card.maxed .overclock-level-badge {
  color: rgb(var(--c-gold)) !important;
  font-weight: 800;
}

.overclock-card.maxed .overclock-card-next {
  color: rgb(var(--c-gold)) !important;
  opacity: 0.85;
}

.overclock-card.maxed .btn-upgrade-oc {
  /* the gold-tint look is the kit's .btn.maxed; this only keeps it inert */
  cursor: default !important;
  pointer-events: none;
  opacity: 0.85;
}

.overclock-card.maxed .oc-btn-a-badge {
  display: none !important;
}

@media (max-width: 820px) {
  #overclock-nexus-screen .overclock-panel {
    max-height: calc(96 * var(--vvh)) !important;
    padding: 8px 10px !important;
  }
  .overclock-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 8px !important;
    max-height: calc(90 * var(--vvh) - 105px) !important;
    padding: 2px 2px 14px 2px !important;
  }
  .overclock-card {
    padding: 6px 5px !important;
  }
  .overclock-card-name {
    font-size: 0.70rem !important;
    min-height: 1.8em !important;
  }
  .overclock-card-desc {
    font-size: 0.56rem !important;
    min-height: 2em !important;
    line-height: 1.15 !important;
  }
  .overclock-card-stat {
    font-size: 0.68rem !important;
    margin-top: 2px !important;
  }
  .overclock-card-next {
    font-size: 0.62rem !important;
  }
  .btn-upgrade-oc {
    min-height: 36px !important;
    padding: 4px 2px !important;
    font-size: 0.62rem !important;
    margin-top: 4px !important;
  }
}

@media (prefers-reduced-motion: reduce) {
  /* Reduced-motion animation suppression removed: preserve overclock card pump & stat delta floaters */
  .overclock-card.pumping {
    /* Retain pump animation and the --oc-flash colour burst */
  }
  .overclock-stat-delta-float {
    /* Retain delta floater */
  }
}

/* ==========================================
/* ==========================================================================
   Modernized Homescreen / Title UI (.start-screen-modern)
   ========================================================================== */
#start-screen.start-screen-modern {
  display: flex !important;
  flex-direction: row !important;
  justify-content: flex-start !important;
  align-items: center !important;
  padding: calc(36px * var(--ui-global-scale, 1)) calc(50px * var(--ui-global-scale, 1)) !important;
  background-image: radial-gradient(circle at 75% 40%, rgba(20, 10, 35, 0.2) 0%, rgba(8, 6, 16, 0.75) 70%, rgba(5, 4, 10, 0.92) 100%),
                    linear-gradient(90deg, rgba(8, 6, 16, 0.92) 0%, rgba(8, 6, 16, 0.6) 42%, rgba(8, 6, 16, 0.15) 100%),
                    url('assets/background.png?v=1') !important;
  background-size: cover !important;
  background-position: center !important;
  background-repeat: no-repeat !important;
  overflow: hidden !important;
  box-sizing: border-box !important;
}

/* Ambient Particles Canvas */
.start-particles-canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 1;
}

/* Modern Left Navigation Rail */
.start-nav-rail {
  width: min(calc(92 * var(--vvw)), calc(420px * var(--ui-global-scale, 1))) !important;
  max-height: calc(90 * var(--vvh)) !important;
  padding: calc(32px * var(--ui-global-scale, 1)) calc(28px * var(--ui-global-scale, 1)) !important;
  display: flex !important;
  flex-direction: column !important;
  align-items: stretch !important;
  gap: calc(16px * var(--ui-global-scale, 1)) !important;
  box-sizing: border-box !important;
  position: relative !important;
  z-index: 5 !important;
  /* window look (fill, border, corners, glow) comes from the chamfer kit: .cut.cx-win, 03b-chamfer-kit.css */
}

.start-music-toggle-wrap,
.pause-music-toggle-wrap {
  position: absolute;
  top: 14px;
  right: 14px;
  display: flex;
  align-items: center;
  gap: 6px;
  z-index: 10;
}

.start-music-toggle,
.pause-music-toggle {
  position: relative;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.95rem;
  border: 1.5px solid rgba(255, 255, 255, 0.15);
  background: rgba(255, 255, 255, 0.04);
  color: #fff;
  cursor: pointer;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

.start-music-toggle-wrap {
  top: calc(14px * var(--ui-global-scale, 1)) !important;
  right: calc(14px * var(--ui-global-scale, 1)) !important;
  gap: calc(6px * var(--ui-global-scale, 1)) !important;
}

.start-music-toggle {
  width: calc(34px * var(--ui-global-scale, 1)) !important;
  height: calc(34px * var(--ui-global-scale, 1)) !important;
  border-width: calc(1.5px * var(--ui-global-scale, 1)) !important;
}

.start-music-toggle::after,
.pause-music-toggle::after {
  content: "";
  position: absolute;
  top: -6px;
  left: -6px;
  right: -6px;
  bottom: -6px;
}

.start-music-toggle svg,
.pause-music-toggle svg {
  width: 18px;
  height: 18px;
  stroke: currentColor;
  fill: none;
  display: block;
}

.start-music-toggle svg {
  width: calc(18px * var(--ui-global-scale, 1)) !important;
  height: calc(18px * var(--ui-global-scale, 1)) !important;
}

:where(body:not(.gamepad-active)) .start-music-toggle:hover,
:where(body:not(.gamepad-active)) .pause-music-toggle:hover {
  background: rgba(var(--c-primary), 0.2);
  border-color: rgb(var(--c-primary));
  transform: scale(1.08);
}

.start-music-pad-icon,
.pause-music-pad-icon {
  width: 22px;
  height: 22px;
  display: none;
  filter: drop-shadow(0 0 5px rgba(254, 181, 4, 0.6));
  user-select: none;
  pointer-events: none;
  animation: pulse 2.5s infinite ease-in-out;
}

.start-music-pad-icon {
  width: calc(22px * var(--ui-global-scale, 1)) !important;
  height: calc(22px * var(--ui-global-scale, 1)) !important;
}

body.input-gamepad .start-music-pad-icon,
body.gamepad-active .start-music-pad-icon,
body.input-gamepad .pause-music-pad-icon,
body.gamepad-active .pause-music-pad-icon {
  display: inline-block !important;
}

.is-mobile .pause-music-toggle-wrap {
  top: 8px;
  right: 8px;
}

.start-logo-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(4px * var(--ui-global-scale, 1)) !important;
  margin-bottom: calc(4px * var(--ui-global-scale, 1)) !important;
  user-select: none;
}

.start-logo-img {
  width: 100%;
  max-width: calc(320px * var(--ui-global-scale, 1)) !important;
  height: auto;
  display: block;
  filter: drop-shadow(0 0 18px rgba(244, 114, 182, 0.35));
}

.start-logo-sub {
  font-family: monospace;
  font-size: calc(0.68rem * var(--ui-global-scale, 1)) !important;
  font-weight: 700;
  letter-spacing: 0.22em;
  color: rgba(var(--c-sky), 0.85);
  text-transform: uppercase;
  text-shadow: 0 0 10px rgba(var(--c-sky), 0.4);
}

.start-btn-group {
  display: flex;
  flex-direction: column;
  gap: calc(10px * var(--ui-global-scale, 1)) !important;
  width: 100%;
}

/* Cyberpunk menu buttons: chamfered .btn (css/03b-chamfer-kit.css section 12) with the neon bar
   kept as an inner accent rail down the left edge. This screen is drawn at native resolution at 4K
   (outside the scaling layer, sizes are calc(N * --ui-global-scale)), so the chamfer and the
   border width are scaled the same way. Fill, border and hover/focus colours come from the kit's
   --bd / --bg variables; the old gradients, borders, glows and the focus outline/scale are gone. */
.start-menu-btn {
  --cut: calc(var(--cut-md) * var(--ui-global-scale, 1));
  --bw: calc(1px * var(--ui-global-scale, 1));
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: calc(12px * var(--ui-global-scale, 1)) calc(18px * var(--ui-global-scale, 1)) !important;
  font-size: calc(0.98rem * var(--ui-global-scale, 1)) !important;
  font-weight: 700 !important;
  letter-spacing: 0.08em !important;
  cursor: pointer !important;
  overflow: hidden !important;
}

.start-menu-btn[style*="display: none"],
.start-menu-btn.hidden {
  display: none !important;
}

/* The rail starts below the top-left chamfer so it is not cut by it. */
.start-menu-btn .btn-neon-bar {
  position: absolute;
  left: 0;
  top: var(--cut);
  bottom: 0;
  width: calc(4px * var(--ui-global-scale, 1));
  background: transparent;
  transition: background 0.2s ease;
}

/* secondary buttons: slide on mouse hover (the kit hover swaps the fill), rail lights up on hover
   or focus. Primary buttons keep their own rail colour (below): sky would vanish on the sky focus fill. */
:where(body:not(.gamepad-active)) .start-menu-btn:hover {
  transform: translateX(calc(4px * var(--ui-global-scale, 1)));
}

:where(body:not(.gamepad-active)) .start-menu-btn:not(.btn-primary):hover .btn-neon-bar,
.start-menu-btn:not(.btn-primary).controller-focused .btn-neon-bar,
.start-menu-btn:not(.btn-primary):focus-visible .btn-neon-bar {
  background: rgb(var(--c-focus));
}

.start-menu-btn.play-btn .btn-neon-bar {
  background: rgb(var(--c-gold));
}

/* Continue: success green (a solid primary button like New Game) */
.start-menu-btn.continue-btn {
  --acc: var(--c-success);
}

.start-menu-btn.continue-btn .btn-neon-bar {
  background: rgb(var(--c-mint));
}

/* Dedicated focus state for the two solid buttons: their fill goes solid sky on focus (kit focus
   variant), so the rail keeps its own colour (gold / mint, never sky) and thickens. */
.start-menu-btn.play-btn.controller-focused .btn-neon-bar,
.start-menu-btn.play-btn:focus-visible .btn-neon-bar {
  background: rgb(var(--c-gold));
  width: calc(7px * var(--ui-global-scale, 1));
}

.start-menu-btn.continue-btn.controller-focused .btn-neon-bar,
.start-menu-btn.continue-btn:focus-visible .btn-neon-bar {
  background: rgb(var(--c-mint));
  width: calc(7px * var(--ui-global-scale, 1));
}

.start-footer-row {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  width: 100%;
  margin-top: 2px;
}

.start-version-label {
  font-size: calc(0.72rem * var(--ui-global-scale, 1)) !important;
  color: rgba(255, 255, 255, 0.4);
  font-family: monospace;
  letter-spacing: 0.05em;
  user-select: none;
}

/* Floating "What's New" Teaser Card (Bottom-Right) */
.start-whats-new-card {
  position: absolute !important;
  bottom: calc(28px * var(--ui-global-scale, 1)) !important;
  right: calc(36px * var(--ui-global-scale, 1)) !important;
  width: min(calc(88 * var(--vvw)), calc(360px * var(--ui-global-scale, 1))) !important;
  padding: calc(16px * var(--ui-global-scale, 1)) calc(20px * var(--ui-global-scale, 1)) !important;
  display: flex !important;
  flex-direction: column !important;
  gap: calc(8px * var(--ui-global-scale, 1)) !important;
  box-sizing: border-box !important;
  z-index: 5 !important;
  /* window look (fill, border, corners, glow) comes from the chamfer kit: .cut.cx-win, 03b-chamfer-kit.css */
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;
  text-align: left !important;
  cursor: pointer !important;
}

:where(body:not(.gamepad-active)) .start-whats-new-card:hover {
  --bd: rgb(var(--acc));
  transform: translateY(-2px) !important;
}

.whats-new-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: calc(12px * var(--ui-global-scale, 1));
}

.whats-new-version {
  font-size: calc(1.35rem * var(--ui-global-scale, 1)) !important;
  font-weight: 800;
  color: rgb(var(--c-gold));
  letter-spacing: 0.04em;
  line-height: 1;
  font-family: 'Outfit', sans-serif;
  text-shadow: 0 0 10px rgba(var(--c-gold), 0.3);
}

.whats-new-date {
  font-size: calc(0.68rem * var(--ui-global-scale, 1)) !important;
  color: rgba(255, 255, 255, 0.4);
  white-space: nowrap;
  padding-top: calc(4px * var(--ui-global-scale, 1));
}

.whats-new-title {
  font-size: calc(0.82rem * var(--ui-global-scale, 1)) !important;
  font-weight: 700;
  color: rgb(var(--c-sky));
  letter-spacing: 0.01em;
  line-height: 1.3;
}

.whats-new-desc {
  font-size: calc(0.72rem * var(--ui-global-scale, 1)) !important;
  color: rgba(255, 255, 255, 0.55);
  line-height: 1.4;
}


.whats-new-action-btn {
  /* chamfered gold chip (registered in css/03b-chamfer-kit.css section 2); native-resolution
     scaling as on the menu buttons above */
  --cut: calc(var(--cut-sm) * var(--ui-global-scale, 1));
  --bw: calc(1px * var(--ui-global-scale, 1));
  --acc: var(--c-gold);
  --bd: rgba(var(--acc), 0.45);
  --bg: rgba(var(--acc), 0.12);
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  margin-top: calc(4px * var(--ui-global-scale, 1));
  padding: calc(6px * var(--ui-global-scale, 1)) calc(12px * var(--ui-global-scale, 1)) !important;
  color: rgb(var(--acc));
  font-size: calc(0.76rem * var(--ui-global-scale, 1)) !important;
  font-weight: 700;
  cursor: pointer;
  transition: transform 0.2s ease, color 0.15s;
  outline: none;
}

:where(body:not(.gamepad-active)) .whats-new-action-btn:hover {
  --bd: rgb(var(--acc));
  --bg: rgba(var(--acc), 0.25);
  transform: translateX(2px);
}

/* Full Changelog Modal Overlay */
.changelog-modal-panel {
  width: min(calc(92 * var(--vvw)), calc(680px * var(--ui-global-scale, 1))) !important;
  max-height: calc(86 * var(--vvh)) !important;
  padding: calc(24px * var(--ui-global-scale, 1)) calc(28px * var(--ui-global-scale, 1)) !important;
  display: flex !important;
  flex-direction: column !important;
  gap: 14px !important;
  box-sizing: border-box !important;
  position: relative !important;
  /* window look (fill, border, corners, glow) comes from the chamfer kit: .cut.cx-win, 03b-chamfer-kit.css */
}

.changelog-close-pad-icon {
  width: 18px;
  height: 18px;
  display: none;
  filter: drop-shadow(0 0 4px rgba(74, 222, 128, 0.6));
  user-select: none;
  pointer-events: none;
}

body.input-gamepad .changelog-close-pad-icon,
body.gamepad-active .changelog-close-pad-icon {
  display: inline-block !important;
}

.modal-close-x {
  /* chamfered close button: css/03b-chamfer-kit.css section 16 */
  position: absolute;
  top: 16px;
  right: 18px;
  font-size: 1.3rem;
  z-index: 10;
}

.changelog-header-wrap {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  border-bottom: 1.5px solid rgba(255, 255, 255, 0.08);
  padding-bottom: 10px;
}

.changelog-title {
  color: rgb(var(--c-violet));
  margin: 0;
  font-size: 1.12rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  display: flex;
  align-items: center;
  gap: 8px;
}

.changelog-scroll-container {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding-right: 6px;
}

/* Scrollbars: the global kit scrollbar, css/03b-chamfer-kit.css section 17. */

.changelog-version-card {
  background: rgba(255, 255, 255, 0.022);
  border: 1px solid rgba(255, 255, 255, 0.07);
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 5px;
  transition: all 0.2s ease;
}

:where(body:not(.gamepad-active)) .changelog-version-card:hover {
  border-color: rgba(var(--c-primary), 0.35);
  background: rgba(var(--c-primary), 0.04);
}

.changelog-version-card.latest {
  background: linear-gradient(135deg, rgba(var(--c-gold), 0.08) 0%, rgba(var(--c-primary), 0.05) 100%);
  border: 1px solid rgba(var(--c-gold), 0.4);
  box-shadow: 0 0 16px rgba(var(--c-gold), 0.08);
}

.changelog-card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.changelog-badge-pill {
  font-family: monospace;
  font-size: 0.78rem;
  font-weight: 700;
  padding: 2px 7px;
  letter-spacing: 0.03em;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.changelog-badge-pill.latest {
  color: rgb(var(--c-gold));
  background: rgba(var(--c-gold), 0.15);
  border: 1px solid rgba(var(--c-gold), 0.35);
  box-shadow: 0 0 8px rgba(var(--c-gold), 0.2);
}

.changelog-badge-pill.patch {
  color: rgba(255, 255, 255, 0.75);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.changelog-date {
  font-size: 0.7rem;
  color: rgba(255, 255, 255, 0.4);
}

.changelog-theme-title {
  font-size: 0.74rem;
  font-weight: 600;
  color: rgb(var(--c-sky));
  letter-spacing: 0.02em;
}

.changelog-section-label {
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-top: 6px;
  margin-bottom: 2px;
}

.changelog-section-label.features {
  color: rgb(var(--c-gold));
}

.changelog-section-label.changes {
  color: rgb(var(--c-sky));
}

.changelog-section-label.balance {
  color: rgb(var(--c-amber));
}

.changelog-section-label.fixes {
  color: #4ade80;
}

.changelog-bullet-list {
  margin: 0;
  padding-left: 14px;
  font-size: 0.71rem;
  line-height: 1.45;
  color: rgba(255, 255, 255, 0.75);
  display: flex;
  flex-direction: column;
  gap: 3.5px;
}

.changelog-bullet-list li {
  position: relative;
}

.changelog-bullet-list li strong {
  color: rgba(255, 255, 255, 0.95);
}


/* Responsive Start Screen (Changelog Modal & Mobile Nav Rail) */
@media (max-width: 950px), (max-height: 540px) {
  #start-screen.start-screen-modern {
    padding: 12px 18px !important;
    justify-content: flex-start !important;
    align-items: center !important;
  }

  .start-nav-rail {
    width: min(calc(94 * var(--vvw)), 420px) !important;
    padding: 14px 18px !important;
    gap: 8px !important;
    max-height: calc(94 * var(--vvh)) !important;
  }

  .start-logo-img {
    max-width: 200px !important;
    max-height: 52px !important;
  }

  .start-logo-sub {
    font-size: 0.6rem !important;
  }

  .start-btn-group {
    gap: 6px !important;
  }

  .start-menu-btn {
    padding: 6px 14px !important;
    font-size: 0.84rem !important;
    min-height: 32px !important;
  }

  /* Compact version-only patch badge on mobile */
  .start-whats-new-card {
    position: fixed !important;
    bottom: 10px !important;
    right: 10px !important;
    left: auto !important;
    width: auto !important;
    max-width: 120px !important;
    padding: 6px 12px !important;
    gap: 4px !important;
    --cut: 10px;
    --bd: rgba(var(--acc), 0.4);
    cursor: pointer !important;
    user-select: none !important;
    -webkit-tap-highlight-color: transparent !important;
  }

  .start-whats-new-card:active {
    transform: scale(0.95) !important;
    --bd: rgb(var(--acc));
  }

  .start-whats-new-card .whats-new-version {
    font-size: 0.85rem !important;
  }

  .start-whats-new-card .whats-new-date,
  .start-whats-new-card .whats-new-title,
  .start-whats-new-card .whats-new-desc,
  .start-whats-new-card .whats-new-details,
  .start-whats-new-card .whats-new-bullets,
  .start-whats-new-card .whats-new-action-btn {
    display: none !important;
  }
}

/* ==========================================================================
   2-Column Settings Menu Redesign (Sidebar & Content Pane)
   ========================================================================== */

#settings-modal .settings-modal-panel {
  width: min(840px, calc(94 * var(--vvw))) !important;
  min-width: min(840px, calc(94 * var(--vvw))) !important;
  max-width: calc(94 * var(--vvw)) !important;
  height: calc(560px * var(--ui-global-scale, 1)) !important;
  max-height: calc(90 * var(--vvh)) !important;
  padding: calc(22px * var(--ui-global-scale, 1)) !important;
  display: flex !important;
  flex-direction: column !important;
  align-items: stretch !important;
  gap: 14px !important;
  box-sizing: border-box !important;
  text-align: left !important;
  position: relative !important;
  overflow: hidden !important;
  /* window look (fill, border, corners, glow) comes from the chamfer kit: .cut.cx-win, 03b-chamfer-kit.css */
  border: 1.5px solid rgba(var(--c-primary), 0.4);
}

.settings-modal-header {
  display: flex !important;
  width: 100% !important;
  justify-content: space-between !important;
  align-items: center !important;
  border-bottom: 1.5px solid rgba(255, 255, 255, 0.08) !important;
  padding-bottom: 10px !important;
  flex-shrink: 0 !important;
  box-sizing: border-box !important;
}

.settings-header-title-wrap {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.settings-header-subtitle {
  font-size: 0.65rem;
  font-weight: 800;
  color: rgb(var(--c-primary));
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-family: monospace;
}

.settings-header-title {
  color: #fff;
  margin: 0;
  font-size: 1.5rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.settings-close-btn {
  /* chamfered close button: shape / colours / hover / focus from css/03b-chamfer-kit.css section 16 */
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-size: 0.9rem;
  font-weight: 700;
  margin-left: auto !important;
}

.settings-close-x {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}

.settings-close-svg {
  width: 14px;
  height: 14px;
  display: block;
}

.settings-split-layout {
  display: flex !important;
  width: 100% !important;
  gap: 18px !important;
  flex: 1 !important;
  min-height: 0 !important;
  align-items: stretch !important;
  overflow: visible !important;
  box-sizing: border-box !important;
}

/* Left Sidebar Navigation */
.settings-sidebar {
  display: flex !important;
  flex-direction: column !important;
  gap: 8px !important;
  width: 215px !important;
  min-width: 215px !important;
  max-width: 215px !important;
  flex-shrink: 0 !important;
  border-right: 1.5px solid rgba(255, 255, 255, 0.08) !important;
  padding: 6px 14px 6px 6px !important;
  box-sizing: border-box !important;
  overflow: visible !important;
}

/* .settings-sidebar-tab: the shell (fill, rail, hover, active, focus) is the shared .side-tab class,
   css/03b-chamfer-kit.css section 19 (the markup carries both classes). */

.settings-tab-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  color: rgba(255, 255, 255, 0.7);
  transition: color 0.2s cubic-bezier(0.4, 0, 0.2, 1), transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

:where(body:not(.gamepad-active)) .settings-sidebar-tab:hover .settings-tab-icon,
.settings-sidebar-tab.active .settings-tab-icon {
  color: rgb(var(--acc));
  transform: scale(1.1);
}

.settings-sidebar-tab.controller-focused .settings-tab-icon {
  color: rgb(var(--c-focus));
  transform: scale(1.15);
}

.settings-tab-svg {
  width: 18px;
  height: 18px;
  display: block;
}

.settings-tab-label {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Right Content Pane */
.settings-content-pane {
  flex: 1 1 0% !important;
  width: 0 !important;
  min-width: 0 !important;
  min-height: 0 !important;
  overflow-y: auto !important;
  padding-right: 8px !important;
  display: flex !important;
  flex-direction: column !important;
  box-sizing: border-box !important;
}

/* Scrollbars: the global kit scrollbar, css/03b-chamfer-kit.css section 17. */

.settings-panel {
  display: none;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  min-width: 100%;
  box-sizing: border-box;
}

.settings-panel.active {
  display: flex !important;
}

.setting-card-row {
  display: flex !important;
  flex-direction: column !important;
  gap: 8px !important;
  width: 100% !important;
  background: rgba(255, 255, 255, 0.02) !important;
  border: 1.5px solid rgba(255, 255, 255, 0.06) !important;
  padding: 12px 14px !important;
  box-sizing: border-box !important;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;
}

:where(body:not(.gamepad-active)) .setting-card-row:hover,
.setting-card-row.controller-focused,
.setting-card-row:has(.controller-focused),
.setting-card-row:focus-within,
:where(body:not(.gamepad-active)) .setting-row:hover,
.setting-row.controller-focused,
.setting-row:has(.controller-focused),
.setting-row:focus-within {
  background: rgba(var(--c-primary), 0.08);
  border-color: rgba(var(--c-primary), 0.35);
  box-shadow: 0 0 14px rgba(var(--c-primary), 0.15);
}

/* .toggle-switch.controller-focused (outline + glow + scale) removed: invisible under the chamfer
   clip-path; focus is the kit variant, css/03b-chamfer-kit.css section 4. */

.settings-range-slider.controller-focused {
  outline: 2px solid rgb(var(--c-focus)) !important;
  outline-offset: 4px !important;
  box-shadow: 0 0 14px rgba(var(--c-focus), 0.6) !important;
}

.settings-range-slider.controller-focused::-webkit-slider-thumb {
  background: rgb(var(--c-focus)) !important;
  box-shadow: 0 0 12px rgb(var(--c-focus)) !important;
}

/* .setting-action-btn.controller-focused (outline + glow + scale) removed: it was invisible under
   the chamfer clip-path; focus is the kit variant, css/03b-chamfer-kit.css section 4. */

.setting-card-row.row-toggle,
.setting-card-row.row-action,
.setting-card-row.row-select {
  flex-direction: row !important;
  justify-content: space-between !important;
  align-items: center !important;
}

.setting-card-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
  min-width: 0;
}

.setting-card-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
}

.setting-card-title {
  font-size: 0.92rem;
  font-weight: 700;
  color: #fff;
}

.setting-card-desc {
  font-size: 0.72rem;
  color: rgba(255, 255, 255, 0.5);
  line-height: 1.35;
}

.setting-card-val {
  /* value chip (chamfer, accent tint, min width): css/03b-chamfer-kit.css section 14 */
  font-size: 0.85rem;
  font-weight: 800;
}


.setting-card-control {
  display: flex;
  align-items: center;
}

.settings-range-slider {
  /* segmented track + fill + bar thumb: css/03b-chamfer-kit.css section 14. The fill length is
     the --pct custom property, kept in sync by js/settings.js (syncSettingsRangeFills). */
  outline: none;
  width: 100%;
  margin-top: 4px;
}

.setting-action-btn {
  padding: 8px 16px;
  font-size: 0.82rem;
  letter-spacing: 0.06em;
  min-width: 110px;
  cursor: pointer;
}

/* .btn-warning / .btn-cyan / .btn-danger on these buttons: the accent variants live in
   css/03b-chamfer-kit.css section 12 (they re-point --acc / the red tint). The old
   background / border / colour !important overrides that sat here were deleted. */

/* Settings dropdown: the closed state (chamfer, accent chevron block, hover, focus) is
   css/03b-chamfer-kit.css section 15. The native popup keeps these option rules. */
.settings-select option {
  background: #0f0c1d !important;
  color: #ffffff !important;
  font-size: 0.85rem !important;
  font-weight: 600 !important;
  padding: 8px 12px !important;
}

.settings-select option:checked {
  background: linear-gradient(90deg, #7e22ce, rgb(var(--c-accent-legacy))) !important;
  color: rgb(var(--c-gold)) !important;
  font-weight: bold !important;
}

/* HUD Opacity preview (Settings > Display, HUD overhaul Phase 6). The real HUD is behind the pause
   scrim while settings are open, so this chip shows the chosen --hud-opacity on an arena-coloured
   background: a mini timer and segmented HP bar. Decorative (aria-hidden, not in the gamepad list). */
.hud-opacity-preview {
  width: 160px;
  height: 40px;
  margin-top: 8px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  padding: 0 12px;
  background:
    radial-gradient(circle at 70% 40%, rgba(236, 72, 153, 0.45), transparent 45%),
    radial-gradient(circle at 25% 70%, rgba(56, 189, 248, 0.35), transparent 50%),
    linear-gradient(rgba(168, 85, 247, 0.12) 1px, transparent 1px) 0 0 / 14px 14px,
    linear-gradient(90deg, rgba(168, 85, 247, 0.12) 1px, transparent 1px) 0 0 / 14px 14px,
    #120d22;
  border: 1px solid rgba(255, 255, 255, 0.1);
  pointer-events: none;
}

.hud-opacity-preview-inner {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  opacity: var(--hud-opacity, 1);
}

.hud-opacity-preview-timer {
  flex: none;
  color: #fff;
  font: 700 16px/1 var(--font-display);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 0 #000, 0 0 8px rgba(0, 0, 0, 0.9);
}

.hud-opacity-preview-bar {
  position: relative;
  flex: 1;
  height: 8px;
  overflow: hidden;
  background: rgba(244, 63, 94, 0.14);
  transform: skewX(-12deg);
}

.hud-opacity-preview-bar::after {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(90deg, transparent 0 14px, rgba(5, 4, 9, 0.95) 14px 16px);
}

.hud-opacity-preview-fill {
  position: absolute;
  inset: 0;
  background: #f43f5e;
  transform: scaleX(0.7);
  transform-origin: left center;
}
/* ==========================================================================
   Landscape Mobile Layout Optimizations (iPhone 14 Pro Max / 932 x 430 px)
   ========================================================================== */

/* 1. Global Modal & Glass Panel Scrolling Bounds on Mobile */
.is-mobile #instructions-modal .glass-panel,
.is-mobile #settings-modal .glass-panel,
.is-mobile #achievements-screen .glass-panel.wide-panel,
.is-mobile #weapon-drop-screen .glass-panel,
.is-mobile #major-choice-screen .glass-panel,
.is-mobile #overclock-nexus-screen .glass-panel,
.is-mobile #level-up-screen .glass-panel.wide-panel,
.is-mobile #gear-swap-screen .glass-panel,
.is-mobile #gear-refactor-screen .glass-panel,
.is-mobile #tutorial-modal .glass-panel {
  padding: 16px !important;
  gap: 6px !important;
  max-height: calc(100 * var(--vvh)) !important;
  overflow-y: auto !important;
}

/* 2. Start Screen / Main Menu Compact Scaling on Mobile */
.is-mobile #start-screen .glass-panel {
  padding: 16px !important;
  gap: 12px !important;
}
.is-mobile #start-screen .glass-panel img {
  max-width: 180px !important;
  margin-bottom: 4px !important;
}
.is-mobile #start-screen .glass-panel button {
  padding: 8px 0 !important;
  font-size: 0.9rem !important;
}

/* 3. Hide Decorative Vibe Orb Icons to save vertical space in mobile upgrade screens */
.is-mobile #weapon-drop-screen .vibe-orb-icon,
.is-mobile #major-choice-screen .vibe-orb-icon {
  display: none !important;
}
.is-mobile #weapon-drop-screen .section-title,
.is-mobile #major-choice-screen .section-title {
  font-size: 1.25rem !important;
  margin-bottom: 4px !important;
}

/* 3b. Weapon Acquired banner icon -- had no mobile shrink path at all
   (only #major-choice-screen's .card-icon, a separate weapon PICK screen,
   already had one). Discrete compact size, same reasoning as the
   .shop-gear-card block above. */
.is-mobile .card-icon.weapon-drop-banner {
  width: 68px !important;
  height: 68px !important;
  min-width: 68px !important;
  min-height: 68px !important;
  margin-bottom: 6px !important;
  padding: 4px !important;
}
.is-mobile .card-icon.weapon-drop-banner img.weapon-drop-icon {
  width: 100% !important;
  height: 100% !important;
  object-fit: contain !important;
}

/* 3c. Shared gear-card-icon component (js/gear-card.js's buildGearCardHtml,
   iconSize option) -- used by the gear-swap compare cards (iconSize: 64),
   the action-bar equipment tooltip (iconSize: 44), and the pause/shop
   details panel (iconSize: 40). All three had no mobile shrink path.
   Flattened to one discrete compact size on mobile rather than trying to
   preserve each call site's relative size hierarchy -- on an ~800x350
   landscape screen, consistency and fitting the available space matter
   more than one icon being visually more prominent than another. Matches
   the same 32px value already used by the (unused-by-the-live-renderer)
   legacy .is-mobile .shop-card .gear-card-icon rule above, kept in sync
   for whenever that pattern needs referencing again. !important required:
   js/gear-card.js sets width/height via an inline style per iconSize. */
.is-mobile .gear-card-icon {
  width: 32px !important;
  height: 32px !important;
}

/* 4. Pause Screen Sidebar Notch Offset positioning on Mobile */
.is-mobile .pause-weapons-column {
  left: calc(16px + var(--safe-left)) !important;
}
.is-mobile .pause-gear-column {
  right: calc(16px + var(--safe-right)) !important;
}

.is-mobile #pause-screen .pause-menu-panel {
  max-width: min(calc(92 * var(--vvw)), 420px) !important;
  max-height: calc(94 * var(--vvh)) !important;
  padding: 8px 14px !important;
  gap: 4px !important;
}
.is-mobile #pause-screen .pause-title {
  font-size: 1.15rem !important;
  margin-bottom: 2px !important;
}
.is-mobile #pause-screen .pause-subtitle {
  font-size: 0.72rem !important;
  margin-bottom: 6px !important;
}
.is-mobile #pause-screen .pause-btn-grid {
  display: grid !important;
  grid-template-columns: 1fr 1fr !important;
  gap: 6px !important;
}
.is-mobile #pause-screen #resume-btn {
  grid-column: span 2 !important;
  min-height: 34px !important;
  padding: 6px 12px !important;
  font-size: 0.82rem !important;
}
.is-mobile #pause-screen .pause-btn-grid .btn:not(#resume-btn):not(#pause-exit-btn) {
  min-height: 30px !important;
  padding: 5px 8px !important;
  font-size: 0.72rem !important;
  margin: 0 !important;
}
.is-mobile #pause-screen #pause-exit-btn {
  grid-column: span 2 !important;
  min-height: 30px !important;
  padding: 5px 12px !important;
  font-size: 0.72rem !important;
  margin: 0 !important;
}

/* 5. Gear Swap Comparison Cards Scaling on Mobile */
.is-mobile #gear-swap-screen h2 {
  font-size: 1.3rem !important;
  margin-bottom: 8px !important;
}
.is-mobile #gear-swap-screen .gear-compare-card {
  min-height: 130px !important;
  padding: 8px !important;
}
.is-mobile #gear-swap-screen button {
  padding: 8px 0 !important;
}
.is-mobile #gear-refactor-screen .gear-refactor-affix-row {
  padding: 6px 30px 6px 10px !important;
  font-size: 0.74rem !important;
}
.is-mobile #gear-refactor-screen button {
  padding: 8px 0 !important;
}

/* 6. Tutorial Modal Compact Layout scaling on Mobile & Small Screens
 *
 * This whole block was dead until 0.19.2. It used to open with a stray
 * selector line -- `.is-mobile #tutorial-modal .glass-panel,` -- immediately
 * before the `@media` at-rule. A selector list ending in a comma followed by
 * an at-rule is invalid CSS: the parser reads `@media (...)` as the next
 * selector in the list, fails, and per CSS error recovery throws away the
 * ENTIRE qualified rule including its whole `{ ... }` body. Every rule below
 * was silently discarded by every browser, which is why the tutorial popup
 * still stacked image-above-text on phones and pushed the text off-screen.
 * Dropping that one line is what makes any of this apply. (`.is-mobile
 * #tutorial-modal .glass-panel` is already covered in section 1 above, so
 * nothing is lost by removing it here.)
 *
 * Breakpoint is width OR height, not width alone: a phone in landscape is
 * commonly ~932x430, which sails past any max-width phone breakpoint while
 * being the case that needs the horizontal layout most. `max-height: 600px`
 * catches it.
 */
@media (max-width: 900px), (max-height: 600px) {
  /* 95vw, not a fixed px cap. The old `max-width: 580px` was the binding
   * constraint on any landscape phone -- a 932px-wide screen got a 580px panel
   * with ~175px of dead space either side, which the media column then took
   * only 42% of. Letting the panel fill the width is what actually makes the
   * image bigger; the column share below is unchanged.
   * min() keeps a wide-but-short desktop window (which matches the
   * max-height arm of this query) from stretching the panel to ~1900px. */
  #tutorial-modal .glass-panel {
    width: calc(95 * var(--vvw)) !important;
    max-width: min(calc(95 * var(--vvw)), 1100px) !important;
    padding: 14px 16px !important;
    gap: 10px !important;
  }
  #tutorial-modal #tutorial-badge {
    width: 34px !important;
    height: 34px !important;
    font-size: 1.1rem !important;
  }
  #tutorial-modal h2 {
    font-size: 1.05rem !important;
  }

  /* Media left, text right -- the actual fix. Stacked, a full-width image ate
   * the whole viewport and shoved the text below the fold; at 42% width the
   * image is ~2.4x shorter (height scales with width) and the text sits
   * beside it instead of under it. One scroll region on the row, not nested
   * ones on both the row and the text -- the old version scrolled both, which
   * is a large part of why the overflow was so easy to miss. */
  /* Raised from 46vh: with the panel now full-width the image is wide enough
   * that its natural height would hit the old cap and get clipped, which would
   * have thrown away most of the extra width. */
  #tutorial-modal #tutorial-body-content {
    flex-direction: row !important;
    align-items: flex-start !important;
    gap: 12px !important;
    max-height: calc(52 * var(--vvh)) !important;
    overflow-y: auto !important;
  }
  #tutorial-modal #tutorial-body-content.has-weapon-grid {
    flex-direction: column !important;
  }
  #tutorial-modal #tutorial-body-content.has-weapon-grid #tutorial-media-container {
    flex: 0 0 100% !important;
    width: 100% !important;
  }
  #tutorial-modal #tutorial-media-container {
    flex: 0 0 42% !important;
    width: 42% !important;
    min-width: 0 !important;
    height: auto !important;
    align-self: flex-start !important;
    background: transparent !important;
    border: none !important;
  }
  /* NOTE: deliberately no `display` here. #tutorial-img, the enemy preview
   * canvas and the placeholder are mutually exclusive and toggled via inline
   * style.display by TutorialManager.triggerTutorial() (js/tutorial.js ~L306).
   * The old dead rule forced `display: block !important` on the image, which
   * would have shown an empty broken-image box on every topic that uses the
   * live enemy canvas or the placeholder instead. */
  /* max-width + width:auto rather than width:100%. With an explicit
   * `width: 100%`, a binding `max-height` shrinks the height while the width
   * stays pinned at 100% -- the image renders squashed rather than scaled.
   * Letting the width be auto and capping both axes keeps the aspect ratio
   * whichever constraint binds first. Every tutorial asset is >=560px wide
   * intrinsically and the column is at most ~460px, so max-width still binds
   * in practice and the image fills its column. */
  #tutorial-modal #tutorial-img {
    max-width: 100% !important;
    width: auto !important;
    height: auto !important;
    max-height: calc(48 * var(--vvh)) !important;
    object-fit: contain !important;
    border-radius: 8px !important;
    border: 1px solid rgba(255, 255, 255, 0.12) !important;
  }
  /* Both have fixed pixel heights inline (220px / 120px) sized for the
   * full-width stacked layout -- far too tall inside a 42% column. */
  #tutorial-modal #tutorial-enemy-preview-canvas {
    height: 130px !important;
  }
  #tutorial-modal #tutorial-media-placeholder {
    height: 90px !important;
  }
  /* min-width: 0 overrides the flex default of `auto`, which would otherwise
   * let a long unbroken word force the column wider than its share and push
   * the layout sideways. */
  #tutorial-modal #tutorial-text {
    flex: 1 1 auto !important;
    min-width: 0 !important;
    font-size: 0.8rem !important;
    line-height: 1.45 !important;
  }
  #tutorial-modal #tutorial-buttons-row {
    display: flex !important;
    flex-direction: row !important;
    gap: 10px !important;
    width: 100% !important;
    padding-top: 10px !important;
  }
  #tutorial-modal #tutorial-dismiss-btn,
  #tutorial-modal #tutorial-disable-btn {
    flex: 1 !important;
    width: 50% !important;
    padding: 8px 4px !important;
    font-size: 0.8rem !important;
    white-space: nowrap !important;
  }
}

/* 7. Game Over Screen Combat Dashboard scroll on Mobile */
.is-mobile #game-over-dashboard {
  max-height: calc(52 * var(--vvh)) !important;
  overflow-y: auto !important;
}

/* 8. Major Choice Screen compact layout for mobile (932x430 target) */
.is-mobile #major-choice-screen .glass-panel {
  max-width: min(calc(94 * var(--vvw)), 680px) !important;
  max-height: calc(94 * var(--vvh)) !important;
  padding: 10px 14px !important;
  display: flex !important;
  flex-direction: column !important;
  gap: 6px !important;
}
.is-mobile #major-choice-screen .upgrade-header {
  margin-bottom: 2px !important;
}
.is-mobile #major-choice-screen .section-desc {
  font-size: 0.72rem !important;
}
.is-mobile #major-choice-screen #major-choices-container {
  display: flex !important;
  flex-direction: row !important;
  gap: 10px !important;
  margin-top: 4px !important;
  width: 100% !important;
}
.is-mobile #major-choice-screen .upgrade-card {
  flex: 1 !important;
  min-width: 0 !important;
  display: flex !important;
  flex-direction: row !important;
  align-items: center !important;
  text-align: left !important;
  gap: 10px !important;
  padding: 8px 10px !important;
}
.is-mobile #major-choice-screen .card-icon {
  width: 56px !important;
  height: 56px !important;
  min-width: 56px !important;
  min-height: 56px !important;
  margin-bottom: 0 !important;
  padding: 4px !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  flex-shrink: 0 !important;
  box-sizing: border-box !important;
}
.is-mobile #major-choice-screen .card-icon img {
  width: 100% !important;
  height: 100% !important;
  object-fit: contain !important;
  border-radius: 6px !important;
  border: none !important;
  box-shadow: none !important;
}
.is-mobile #major-choice-screen .card-content-col {
  flex: 1 !important;
  min-width: 0 !important;
  display: flex !important;
  flex-direction: column !important;
  justify-content: center !important;
}
.is-mobile #major-choice-screen .upgrade-card h3 {
  font-size: 0.85rem !important;
  font-weight: bold !important;
  margin: 0 0 2px 0 !important;
  line-height: 1.2 !important;
}
.is-mobile #major-choice-screen .upgrade-card .card-desc {
  font-size: 0.68rem !important;
  line-height: 1.25 !important;
  color: rgba(255, 255, 255, 0.85) !important;
  margin: 0 !important;
}
.is-mobile #major-choice-screen [style*="margin-top: 20px"] {
  margin-top: 6px !important;
  display: flex !important;
  justify-content: center !important;
}
.is-mobile #major-choice-screen #major-choice-back-btn {
  font-size: 0.75rem !important;
  padding: 0 22px !important;
  height: 32px !important;
  line-height: 32px !important;
  width: auto !important;
  max-width: 200px !important;
  margin: 0 auto !important;
}

/* Smaller mobile display adaptations for Major Choice Screen (<= 820px width or <= 400px height) */
@media (max-width: 820px), (max-height: 400px) {
  .is-mobile #major-choice-screen .glass-panel {
    max-width: min(calc(94 * var(--vvw)), 540px) !important;
    padding: 8px 12px !important;
    gap: 4px !important;
  }
  .is-mobile #major-choice-screen .upgrade-header {
    margin-bottom: 0 !important;
    gap: 8px !important;
  }
  .is-mobile #major-choice-screen .major-choice-emblem-wrap {
    width: 28px !important;
    height: 28px !important;
  }
  .is-mobile #major-choice-screen .major-choice-emblem-svg {
    width: 24px !important;
    height: 24px !important;
  }
  .is-mobile #major-choice-screen .major-choice-milestone-badge {
    font-size: 0.60rem !important;
    padding: 2px 8px !important;
  }
  .is-mobile #major-choice-screen .section-title {
    font-size: 1.05rem !important;
  }
  .is-mobile #major-choice-screen .section-desc {
    font-size: 0.65rem !important;
  }
  .is-mobile #major-choice-screen #major-choices-container {
    gap: 8px !important;
    margin-top: 2px !important;
  }
  .is-mobile #major-choice-screen .upgrade-card {
    padding: 6px 8px !important;
    gap: 8px !important;
  }
  .is-mobile #major-choice-screen .card-icon {
    width: 42px !important;
    height: 42px !important;
    min-width: 42px !important;
    min-height: 42px !important;
    border-radius: 8px !important;
    padding: 3px !important;
  }
  .is-mobile #major-choice-screen .card-milestone-tag {
    font-size: 0.52rem !important;
  }
  .is-mobile #major-choice-screen .upgrade-card h3 {
    font-size: 0.76rem !important;
    line-height: 1.15 !important;
    margin: 0 0 1px 0 !important;
  }
  .is-mobile #major-choice-screen .upgrade-card .card-desc {
    font-size: 0.60rem !important;
    line-height: 1.2 !important;
  }
  .is-mobile #major-choice-screen #major-choice-back-btn {
    height: 28px !important;
    line-height: 28px !important;
    font-size: 0.72rem !important;
    padding: 0 16px !important;
  }
}

@media (max-height: 350px) {
  .is-mobile #major-choice-screen .card-icon {
    width: 36px !important;
    height: 36px !important;
    min-width: 36px !important;
    min-height: 36px !important;
  }
  .is-mobile #major-choice-screen .upgrade-card h3 {
    font-size: 0.72rem !important;
  }
  .is-mobile #major-choice-screen .upgrade-card .card-desc {
    font-size: 0.56rem !important;
  }
}

/* Controller Menu/Start icon inside Next Round button */
.shop-next-btn-menu-icon {
  display: none;
}

body.gamepad-active .shop-next-btn-menu-icon {
  display: inline-block;
}

/* Mobile landscape layout adjustments for Vibe Bazaar Shop Tab (legendary card overflow fix) */
.is-mobile #shop-content-area {
  justify-content: flex-start !important;
  padding-top: 4px !important;
}

.is-mobile #shop-content-shop {
  gap: 4px !important;
  justify-content: flex-start !important;
}

.is-mobile #shop-content-shop > div:first-child {
  margin-bottom: 0 !important;
}

.is-mobile #shop-content-shop h3.font-accent {
  font-size: 0.9rem !important;
  margin: 0 !important;
  padding-top: 2px !important;
}

/* Recover vertical budget for the scrollable #shop-items list on short
   landscape viewports (~800x350). Shrinking the item icon (below) frees up
   some room, but the header row's 64px min-height and the panel's own
   92vh/padding were the bigger budget-eaters -- box-model math (see Test
   206) showed even a maximally compact card row still needed ~87px more
   scroll budget than was available before these three trims to fit 2 rows
   instead of 1. Scoped to #shop-screen specifically rather than folded
   into the shared multi-screen mobile .glass-panel rule above, since that
   shared rule's max-height:100vh (not height/min-height) is intentionally
   conservative for screens with fixed-aspect content -- the shop's own
   list-based layout can safely use more of the viewport. */
.is-mobile #shop-screen .glass-panel.wide-panel {
  height: calc(98 * var(--vvh)) !important;
  min-height: calc(98 * var(--vvh)) !important;
  max-height: calc(98 * var(--vvh)) !important;
  padding: 12px 14px !important;
  gap: 6px !important;
}
.is-mobile .shop-header-row {
  min-height: 40px !important;
  padding: 6px 0 !important;
}
.is-mobile #shop-left-col,
.is-mobile #shop-right-col {
  padding: 8px !important;
  gap: 6px !important;
}

.is-mobile .shop-card {
  width: 190px !important;
  min-height: 170px !important;
  padding: 12px 8px !important;
  flex-shrink: 0 !important;
}

/* Compact gear card details inside shop cards on mobile */
.is-mobile .shop-card .gear-card {
  gap: 4px !important;
}

.is-mobile .shop-card .gear-card-header {
  gap: 4px !important;
}

.is-mobile .shop-card .gear-card-title {
  font-size: calc(0.9rem * var(--menu-scale)) !important;
  line-height: 1.15 !important;
}

.is-mobile .shop-card .gear-card-subtitle {
  font-size: calc(0.8rem * var(--menu-scale)) !important;
}

.is-mobile .shop-card .gear-card-ilvl {
  font-size: calc(0.8rem * var(--menu-scale)) !important;
  margin-top: 0 !important;
}

.is-mobile .shop-card .gear-card-icon {
  width: 32px !important;
  height: 32px !important;
  border-radius: 6px !important;
}

.is-mobile .shop-card .gear-card-stats {
  gap: 2px !important;
  margin-top: 1px !important;
}

.is-mobile .shop-card .gear-card-stat {
  font-size: calc(0.9rem * var(--menu-scale)) !important;
  padding-left: 9px !important;
}

.is-mobile .shop-card .gear-card-stat::before {
  font-size: 0.8em !important;
}

.is-mobile .shop-card .gear-card-ability {
  font-size: calc(0.62rem * var(--menu-scale)) !important;
  padding-top: 4px !important;
  margin-top: 2px !important;
}

/* Compact .shop-gear-card on mobile -- the live shop list component
   (js/shop.js's buildShopGearCardHtml()), as distinct from the legacy
   .shop-card rules directly above. That legacy component had a full mobile
   compaction pass (32px icon, tightened gaps) at some point, but it never
   got carried over when .shop-gear-card replaced it as the actual renderer
   -- so on a short/narrow viewport (~800x350 landscape) the icon stayed a
   fixed 100px and a single item card ate almost the entire scrollable
   list area, leaving room for only 1 visible instead of 2. Requested by
   the user: "the images are now too large on mobile ... ideally they
   should be able to see 2." Mirrors the same discrete-compact-size pattern
   as the legacy rules above (and reuses the 40px "compact icon" convention
   already used elsewhere in this codebase, e.g. buildGearCardHtml's
   iconSize: 40 call sites) rather than pushing --ui-global-scale/
   --menu-scale's continuous curves down to an extreme that would make
   surrounding menu text illegible. !important is required throughout since
   js/shop.js sets several of these (the item icon's width/height) via an
   inline style, which normal-weight CSS rules can never outrank regardless
   of selector specificity. See tests/pipeline-status-tests.js's Test 206
   for the box-model math behind these specific numbers -- unverified in a
   real browser (no Playwright/Chromium available in this environment), so
   worth a manual check on device. */
.is-mobile .shop-gear-card {
  padding: 4px 6px !important;
  margin: 0 !important;
  gap: 6px !important;
  min-height: 80px !important;
  flex-shrink: 0 !important;
}

.is-mobile .shop-gear-card .card-col-left {
  width: 60px !important;
  flex: 0 0 60px !important;
  gap: 2px !important;
  flex-shrink: 0 !important;
  justify-content: flex-start !important;
}

.is-mobile .shop-gear-card .card-icon-box {
  width: 55px !important;
  height: 55px !important;
  flex-shrink: 0 !important;
}

.is-mobile .shop-gear-card .card-icon-box img {
  width: 55px !important;
  height: 55px !important;
  object-fit: contain !important;
}

/* Type/item-level text (e.g. "Basic Gloves" / "Item Level 1") is dropped
   on mobile entirely -- redundant with the card's own rarity-colored
   border and title, and there's no room to wrap it under a 44px-wide
   icon column without it eating the vertical space the compact icon just
   freed up. */
.is-mobile .shop-gear-card .card-type-text,
.is-mobile .shop-gear-card .card-ilvl-text {
  display: none !important;
}

.is-mobile .shop-gear-card .card-col-right {
  gap: 2px !important;
  min-width: 0 !important;
  flex: 1 1 auto !important;
  justify-content: space-between !important;
}

.is-mobile .shop-gear-card .card-title-text {
  font-size: calc(0.85rem * var(--menu-scale)) !important;
  line-height: 1.2 !important;
}

/* Caps the stat list to a single line so a 2-3 affix item can't push the
   card taller than the compact icon column next to it. The full stat list
   remains available via the existing tap-to-inspect / hover flow
   (ViewportManager.bindInspectInteraction) -- this only affects the
   at-a-glance list row. */
.is-mobile .shop-gear-card .card-stats-body {
  font-size: calc(0.7rem * var(--menu-scale)) !important;
  display: -webkit-box !important;
  -webkit-box-orient: vertical !important;
  -webkit-line-clamp: 1 !important;
  line-clamp: 1 !important;
  overflow: hidden !important;
}

.is-mobile .shop-gear-card .card-actions-bar {
  margin-top: 2px !important;
  display: flex !important;
  align-items: center !important;
  gap: 4px !important;
  flex-shrink: 0 !important;
}

.is-mobile .shop-gear-card .btn-buy-gear {
  padding: 3px 8px !important;
  font-size: 0.68rem !important;
  height: 24px !important;
}

.is-mobile .shop-gear-card .btn-lock-gear {
  width: 24px !important;
  min-width: 24px !important;
  max-width: 24px !important;
  height: 24px !important;
  flex: 0 0 24px !important;
}

.is-mobile .shop-gear-card .btn-equip-inv {
  height: 24px !important;
  padding: 3px 8px !important;
  font-size: 0.68rem !important;
}

.is-mobile .shop-gear-card .btn-sell-inv {
  height: 24px !important;
  padding: 3px 8px !important;
  font-size: 0.68rem !important;
}

.is-mobile .shop-card-tag-btn {
  height: 22px !important;
  min-height: 22px !important;
  padding: 1px 6px !important;
  font-size: 0.68rem !important;
}

.is-mobile .shop-gear-card .card-price-badge {
  font-size: 0.65rem !important;
  padding: 1px 4px !important;
  gap: 3px !important;
  flex-shrink: 0 !important;
  margin-top: 2px !important;
}

.is-mobile .shop-gear-card .card-price-badge img {
  width: 11px !important;
  height: 11px !important;
}

/* Mobile landscape: unshrink inventory gear cards so all stats are fully visible and legible */
.is-mobile #shop-inventory-items .shop-gear-card,
.is-mobile #shop-buyback-items .shop-gear-card {
  min-height: 80px !important;
  height: auto !important;
  padding: 6px 8px !important;
  gap: 8px !important;
}

.is-mobile #shop-inventory-items .shop-gear-card .card-col-left,
.is-mobile #shop-buyback-items .shop-gear-card .card-col-left {
  width: 60px !important;
  flex: 0 0 60px !important;
  gap: 4px !important;
  justify-content: flex-start !important;
}

.is-mobile #shop-inventory-items .shop-gear-card .card-col-right,
.is-mobile #shop-buyback-items .shop-gear-card .card-col-right {
  gap: 3px !important;
  min-width: 0 !important;
  flex: 1 1 auto !important;
  justify-content: flex-start !important;
}

.is-mobile #shop-inventory-items .shop-gear-card .card-title-text,
.is-mobile #shop-buyback-items .shop-gear-card .card-title-text {
  font-size: 0.88rem !important;
  line-height: 1.25 !important;
}

.is-mobile #shop-inventory-items .shop-gear-card .card-stats-body,
.is-mobile #shop-buyback-items .shop-gear-card .card-stats-body {
  font-size: 0.72rem !important;
  line-height: 1.35 !important;
  display: block !important;
  overflow: visible !important;
  -webkit-line-clamp: unset !important;
  line-clamp: unset !important;
  max-height: none !important;
  flex: 1 1 auto !important;
}

.is-mobile #shop-inventory-items .shop-gear-card .gear-card-stats,
.is-mobile #shop-buyback-items .shop-gear-card .gear-card-stats {
  gap: 2px !important;
  margin: 2px 0 0 0 !important;
  padding: 0 !important;
  display: flex !important;
  flex-direction: column !important;
}

.is-mobile #shop-inventory-items .shop-gear-card .gear-card-stat,
.is-mobile #shop-buyback-items .shop-gear-card .gear-card-stat {
  font-size: 0.72rem !important;
  line-height: 1.35 !important;
  padding-left: 11px !important;
  white-space: normal !important;
  word-break: break-word !important;
}

.is-mobile #shop-inventory-items .shop-gear-card .gear-card-ability,
.is-mobile #shop-buyback-items .shop-gear-card .gear-card-ability {
  font-size: 0.70rem !important;
  line-height: 1.3 !important;
  margin-top: 3px !important;
}

.is-mobile #shop-inventory-items .shop-gear-card .card-actions-bar,
.is-mobile #shop-buyback-items .shop-gear-card .card-actions-bar {
  margin-top: 4px !important;
  display: flex !important;
  align-items: center !important;
  gap: 6px !important;
  flex-shrink: 0 !important;
}

.is-mobile #shop-inventory-items .shop-gear-card .btn-equip-inv {
  height: 26px !important;
  padding: 3px 10px !important;
  font-size: 0.72rem !important;
  font-weight: 700 !important;
}

.is-mobile #shop-inventory-items .shop-gear-card .btn-sell-inv {
  height: 26px !important;
  padding: 3px 10px !important;
  font-size: 0.72rem !important;
  font-weight: 700 !important;
}

/* Compact Reroll & Buy Level Up buttons on mobile landscape */
.is-mobile .shop-item-actions-row {
  margin-top: 2px !important;
  gap: 10px !important;
}

.is-mobile .shop-item-actions-row button {
  padding: 6px 0 !important;
  font-size: 0.8rem !important;
  line-height: 1.2 !important;
}

/* Compact currencies bar on mobile landscape */
.is-mobile .shop-currencies-bar {
  margin-top: 2px !important;
  padding-top: 6px !important;
  gap: 16px !important;
}

.is-mobile .shop-currencies-bar > div {
  font-size: 0.8rem !important;
}

/* Mobile landscape layout adjustments for Weapon Upgrades (#level-up-screen) */
.is-mobile #weapon-tree-content {
  display: flex !important;
  flex-direction: column !important;
  gap: 10px !important;
  align-items: flex-start !important;
  min-height: 0 !important;
  flex: 1 1 auto !important;
  overflow-y: auto !important;
  width: 100% !important;
}

.is-mobile #level-up-screen .weapon-tree-header {
  margin-bottom: 0 !important;
  display: flex !important;
  align-items: flex-start !important;
  gap: 10px !important;
  box-sizing: border-box;
  width: 100% !important;
}


/* Compact the header title row */
.is-mobile #level-up-screen .upgrade-header {
  margin-bottom: 4px !important;
  gap: 8px !important;
  flex-shrink: 0 !important;
}
.is-mobile #level-up-screen .upgrade-header-icon {
  width: 22px !important;
  height: 22px !important;
}
.is-mobile #level-up-screen .upgrade-chevron-svg {
  width: 22px !important;
  height: 22px !important;
}
.is-mobile #level-up-screen .section-title {
  font-size: 1.15rem !important;
}
.is-mobile #level-up-screen .upgrade-header > div:last-child {
  font-size: 0.78rem !important;
  padding: 2px 8px !important;
}

/* Full height flex stretch for weapon upgrades modal on mobile */
.is-mobile #level-up-screen .glass-panel.wide-panel {
  display: flex !important;
  flex-direction: column !important;
  height: calc(96 * var(--vvh)) !important;
  max-height: calc(96 * var(--vvh)) !important;
  padding: 8px 12px !important;
  box-sizing: border-box !important;
  overflow: hidden !important;
}

/* Modal only wide enough to fit the 3x2 icons on mobile landscape with tight edge gaps */
.is-mobile #level-up-screen.view-grid .glass-panel.wide-panel,
.is-mobile #level-up-screen:not(.view-tree) .glass-panel.wide-panel {
  width: fit-content !important;
  max-width: 96% !important;
  min-width: 0 !important;
  padding: 6px 8px !important;
  margin: auto !important;
}

.is-mobile #level-up-screen.view-tree .glass-panel.wide-panel {
  width: min(calc(96 * var(--vvw)), calc(920px * var(--ui-global-scale, 1))) !important;
  max-width: 96% !important;
  padding: 8px 12px !important;
}

/* Weapon Grid View mobile full-height expansion */
.is-mobile #weapon-grid-view {
  display: flex;
  flex-direction: column !important;
  flex: 1 1 auto !important;
  min-height: 0 !important;
  height: 100% !important;
  width: 100% !important;
  justify-content: space-between !important;
  align-items: center !important;
}

.is-mobile #weapon-grid-view[style*="display: none"],
.is-mobile #level-up-screen.view-tree #weapon-grid-view {
  display: none !important;
}

/* Weapon Tree View mobile layout */
.is-mobile #weapon-tree-view {
  display: flex !important;
  flex-direction: column !important;
  flex: 1 1 auto !important;
  min-height: 0 !important;
  height: 100% !important;
  width: 100% !important;
  overflow: hidden !important;
  box-sizing: border-box !important;
}

.is-mobile #weapon-tree-view[style*="display: none"],
.is-mobile #level-up-screen.view-grid #weapon-tree-view {
  display: none !important;
}

.is-mobile .weapon-overview-grid {
  --wog-card-h: calc((71 * var(--vvh) - 6px) / 2);
  display: grid !important;
  grid-template-columns: repeat(3, var(--wog-card-h)) !important;
  grid-template-rows: repeat(2, 1fr) !important;
  flex: 0 0 auto !important;
  min-height: 0 !important;
  height: calc(71 * var(--vvh)) !important;
  max-height: calc(73 * var(--vvh)) !important;
  width: fit-content !important;
  max-width: none !important; /* the desktop 620px cap (css/07) clipped the height-sized cards */
  margin: 0 auto !important;
  gap: 6px !important;
  justify-content: center !important;
  align-content: center !important;
}

/* Android tablets (1280x800 and up) count as mobile, so the cards above are sized from the screen
   height (281px each at 800px tall), but the grid view's window kept its 660px desktop cap
   (css/07-weapon-tree-carousel.css) and cut off the first column. min-width lets the window grow to
   fit the grid; on phones the grid is narrower than 660px, so nothing changes there. */
.is-mobile #level-up-screen.view-grid .glass-panel.wide-panel {
  min-width: fit-content !important;
  max-width: calc(96 * var(--vvw)) !important;
}

.is-mobile .weapon-grid-card {
  height: 100% !important;
  max-height: calc(35 * var(--vvh)) !important;
  width: 100% !important;
  max-width: 100% !important;
  min-width: 0 !important;
  min-height: 0 !important;
  aspect-ratio: 1 / 1 !important;
  justify-self: center !important;
  padding: 0 !important;
  display: flex !important;
  flex-direction: column !important;
  justify-content: space-between !important;
  align-items: center !important;
  box-sizing: border-box !important;
  overflow: hidden !important;
  position: relative !important;
}

.is-mobile .weapon-grid-card-top {
  position: relative !important;
  z-index: 3 !important;
  width: 100% !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  padding: 4px 6px 10px 6px !important;
  background: linear-gradient(180deg, rgba(12, 9, 24, 0.88) 0%, rgba(12, 9, 24, 0.45) 55%, transparent 100%) !important;
  box-sizing: border-box !important;
  flex: 0 0 auto !important;
}

.is-mobile .weapon-grid-card-title {
  font-size: 0.68rem !important;
  line-height: 1.15 !important;
  padding: 0 !important;
  background: none !important;
  border: none !important;
  width: 100% !important;
  max-width: 100% !important;
  text-align: center !important;
  white-space: nowrap !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9) !important;
}

.is-mobile .weapon-grid-card-art-container {
  position: absolute !important;
  inset: 0 !important;
  width: 100% !important;
  height: 100% !important;
  /* 0, not 10px: the card is chamfered (css/03b-chamfer-kit.css), and its clip shapes the art. */
  overflow: hidden !important;
  min-width: 0 !important;
  min-height: 0 !important;
  box-sizing: border-box !important;
}

.is-mobile .weapon-grid-card-bg-art {
  width: 100% !important;
  height: 100% !important;
  object-fit: cover !important;
  padding: 0 !important;
  box-sizing: border-box !important;
  opacity: 1 !important;
  /* 0, not 10px: the card is chamfered (css/03b-chamfer-kit.css), and its clip shapes the art. */
  display: block !important;
}

.is-mobile .weapon-grid-card-badge-overlay {
  font-size: 0.58rem !important;
  padding: 1px 4px !important;
  border-radius: 4px !important;
  position: static !important;
}

.is-mobile .weapon-grid-card-preview-overlay {
  position: absolute !important;
  inset: 0 !important;
  z-index: 2 !important;
  display: flex !important;
  flex-direction: column !important;
  align-items: center !important;
  justify-content: center !important;
  padding: 22px 6px 26px 6px !important;
  background: rgba(8, 6, 18, 0.65) !important;
  backdrop-filter: blur(2px) !important;
  -webkit-backdrop-filter: blur(2px) !important;
  /* 0, not 10px: the card is chamfered (css/03b-chamfer-kit.css), and its clip shapes the art. */
  box-sizing: border-box !important;
  opacity: 0 !important;
  pointer-events: none !important;
  transition: opacity 0.2s cubic-bezier(0.2, 0.8, 0.2, 1),
              transform 0.2s cubic-bezier(0.2, 0.8, 0.2, 1) !important;
  transform: translateY(3px) !important;
}

:where(body:not(.gamepad-active)) .is-mobile .weapon-grid-card:not(.locked):hover .weapon-grid-card-preview-overlay,
.is-mobile .weapon-grid-card.controller-focused .weapon-grid-card-preview-overlay,
.is-mobile .weapon-grid-card:focus-visible .weapon-grid-card-preview-overlay,
.is-mobile .weapon-grid-card.touch-preview-active .weapon-grid-card-preview-overlay {
  opacity: 1 !important;
  transform: translateY(0) !important;
}

.is-mobile .weapon-grid-preview-badge {
  font-size: 0.54rem !important;
  padding: 1px 5px !important;
  margin-bottom: 3px !important;
  background: rgba(0, 0, 0, 0.82) !important;
}

.is-mobile .weapon-grid-preview-desc {
  font-size: 0.60rem !important;
  line-height: 1.15 !important;
  padding: 0 2px !important;
  color: #ffffff !important;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 1), 0 0 6px rgba(0, 0, 0, 0.9) !important;
}

.is-mobile .weapon-grid-card-bottom {
  position: relative !important;
  z-index: 3 !important;
  gap: 2px !important;
  width: 100% !important;
  margin-top: auto !important;
  padding: 10px 6px 4px 6px !important;
  background: linear-gradient(0deg, rgba(12, 9, 24, 0.92) 0%, rgba(12, 9, 24, 0.55) 60%, transparent 100%) !important;
  border: none !important;
  backdrop-filter: none !important;
  box-sizing: border-box !important;
  flex: 0 0 auto !important;
}

.is-mobile .weapon-grid-card-progress {
  gap: 1px !important;
  width: 100% !important;
}

.is-mobile .weapon-grid-card-progress-labels {
  display: flex !important;
  justify-content: space-between !important;
  align-items: center !important;
  width: 100% !important;
  font-size: 0.52rem !important;
  line-height: 1 !important;
}

.is-mobile .weapon-grid-card-tier-label {
  font-size: 0.52rem !important;
  line-height: 1 !important;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9) !important;
}

.is-mobile .weapon-grid-card-lvl-label {
  font-size: 0.52rem !important;
  line-height: 1 !important;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9) !important;
}

.is-mobile .weapon-grid-card-track,
.is-mobile .weapon-grid-card-segment-track {
  height: 3.5px !important;
}

.is-mobile .weapon-grid-card-segments {
  gap: 2px !important;
  width: 100% !important;
  display: flex !important;
}

.is-mobile .weapon-grid-card.locked {
  gap: 4px !important;
  padding: 6px 4px !important;
  display: flex !important;
  flex-direction: column !important;
  justify-content: center !important;
  align-items: center !important;
  aspect-ratio: 1 / 1 !important;
}

.is-mobile .weapon-grid-card-locked-icon svg {
  width: 22px !important;
  height: 22px !important;
}

.is-mobile .weapon-grid-card-locked-title {
  font-size: 0.68rem !important;
  line-height: 1.1 !important;
}

.is-mobile .weapon-grid-card-locked-desc {
  font-size: 0.56rem !important;
  line-height: 1.1 !important;
}

.is-mobile .weapon-grid-footer {
  margin-top: 4px !important;
  width: 100% !important;
  flex-shrink: 0 !important;
  display: flex !important;
  justify-content: center !important;
}

.is-mobile .weapon-grid-close-btn {
  width: 100% !important;
  max-width: 100% !important;
  padding: 5px 0 !important;
  font-size: 0.8rem !important;
  line-height: 1.15 !important;
}

/* Compact the tabs row */
.is-mobile #level-up-screen .weapon-tree-tabs-row {
  margin-bottom: 8px !important;
  padding-bottom: 6px !important;
  flex-shrink: 0 !important;
}

/* Compact stat badges list */
.is-mobile #level-up-screen .weapon-tree-stats {
  display: flex !important;
  flex-wrap: wrap !important;
  gap: 4px !important;
  margin-top: 4px !important;
}

/* Compact the footer buttons at the bottom */
.is-mobile #level-up-screen .btn-primary {
  padding: 8px 0 !important;
  font-size: 0.85rem !important;
  line-height: 1.2 !important;
}
.is-mobile #level-up-screen .btn-primary.btn-glow {
  margin-top: 0 !important;
}
.is-mobile #level-up-screen .weapon-tree-footer,
.is-mobile #level-up-screen .weapon-grid-footer {
  display: flex !important;
  flex-direction: row !important;
  align-items: center !important;
  flex-shrink: 0 !important;
  margin-top: auto !important;
  padding: 6px 6px 8px 6px !important;
  gap: 14px !important;
  width: 100% !important;
  box-sizing: border-box !important;
}
.is-mobile #level-up-screen #weapon-tree-grid-btn {
  min-width: 120px !important;
  max-width: 145px !important;
  padding: 8px 10px !important;
  font-size: 0.8rem !important;
}

.is-mobile .weapon-tree-grid-pad-icon,
.is-mobile .level-up-resume-pad-icon {
  width: 15px !important;
  height: 15px !important;
  margin-right: 4px !important;
}

/* ==========================================================================
   CROSS-DEVICE RESPONSIVE ADAPTATION: SHORT VERTICAL VIEWPORTS & MOBILE LANDSCAPE
   Targeting Steam Deck (800px height ceiling) & Mobile Landscape (<600px height)
   ========================================================================== */
@media (max-height: 600px) {
  /* 1. Main Menu (#start-screen) */
  #start-screen {
    padding: 8px 16px !important;
    gap: 12px !important;
    height: 100% !important;
    min-height: 100% !important;
    max-height: none !important;
    top: 0 !important;
    bottom: 0 !important;
    left: 0 !important;
    right: 0 !important;
  }
  /* These rules used to target `#start-screen-left img`, `.game-logo` and
   * `.start-menu-btn`. NONE of those three exist in index.html -- the logo is
   * a bare `<img class="animate-pulse">` and the menu buttons are plain
   * `.btn`/`.btn-secondary`. So the entire short-screen compaction of the main
   * menu matched nothing and silently did nothing: the panel kept its inline
   * `padding: 40px; gap: 24px`, the logo its 340px width and the buttons their
   * `padding: 12px 0; font-size: 1.05rem`, adding up to ~530px of content in a
   * 430px-tall landscape viewport -- which clipped the logo off the top and
   * "Exit Game" off the bottom. Repointed at the real elements.
   * The `> img` / `> div` child combinators keep this off the absolutely
   * positioned music toggle and the version tag. */
  #start-screen .glass-panel,
  #start-screen .start-nav-rail {
    padding: 12px 18px !important;
    gap: 8px !important;
    max-height: calc(94 * var(--vvh)) !important;
  }
  #start-screen .glass-panel > img {
    max-height: 84px !important;
    width: auto !important;
    margin-bottom: 2px !important;
  }
  #start-screen .glass-panel > div {
    gap: 8px !important;
  }
  #start-screen .glass-panel .btn {
    padding: 7px 16px !important;
    min-height: 38px !important;
    font-size: 13px !important;
  }

  /* 2. Changelog Modal (#changelog-panel) */
  #changelog-panel {
    max-height: calc(92 * var(--vvh)) !important;
    padding: 12px 16px !important;
    gap: 8px !important;
  }
  #changelog-scroll-container {
    max-height: calc(55 * var(--vvh)) !important;
    overflow-y: auto !important;
  }

  /* 3. Instructions Modal (#instructions-modal) */
  #instructions-modal .glass-panel {
    max-height: calc(94 * var(--vvh)) !important;
    padding: 10px 14px !important;
  }
  .instructions-nav-item {
    padding: 8px 12px !important;
    min-height: 44px !important;
  }

  /* 4. Settings Modal (#settings-modal) */
  #settings-modal .settings-modal-panel {
    max-height: calc(94 * var(--vvh)) !important;
    padding: 10px 14px !important;
    gap: 8px !important;
  }
  .settings-sidebar {
    width: 170px !important;
    padding-right: 8px !important;
    gap: 4px !important;
  }
  .settings-sidebar-tab {
    padding: 8px 10px !important;
    font-size: 0.8rem !important;
    min-height: 38px !important;
  }
  .setting-card-row {
    padding: 8px 10px !important;
    gap: 4px !important;
  }
  .setting-card-title {
    font-size: 0.85rem !important;
  }

  /* 5. Save Overwrite & Respec Confirm Modals */
  #save-overwrite-confirm-modal .glass-panel,
  #respec-confirm-modal .glass-panel {
    max-height: calc(90 * var(--vvh)) !important;
    padding: 12px 16px !important;
  }

  /* 6. Tutorial Modal (#tutorial-modal) */
  #tutorial-modal .glass-panel {
    max-height: calc(92 * var(--vvh)) !important;
    padding: 10px 14px !important;
  }
  #tutorial-body-content {
    max-height: calc(50 * var(--vvh)) !important;
    overflow-y: auto !important;
  }

  /* 7. Major Choice Screen (#major-choice-screen) */
  #major-choice-screen .glass-panel {
    max-width: min(calc(94 * var(--vvw)), 680px) !important;
    max-height: calc(94 * var(--vvh)) !important;
    padding: 8px 14px !important;
  }
  #major-choices-container .upgrade-card {
    min-height: auto !important;
    padding: 8px 10px !important;
    display: flex !important;
    flex-direction: row !important;
    align-items: center !important;
    text-align: left !important;
    gap: 10px !important;
  }
  #major-choices-container .card-icon {
    width: 56px !important;
    height: 56px !important;
    min-width: 56px !important;
    min-height: 56px !important;
    margin-bottom: 0 !important;
  }

  /* 8. Weapon Drop Screen (#weapon-drop-screen) */
  #weapon-drop-screen {
    height: 100% !important;
    min-height: 100% !important;
    max-height: none !important;
    padding: 8px 14px !important;
  }
  #weapon-drop-screen .glass-panel,
  #weapon-drop-screen .weapon-drop-panel {
    max-height: calc(94 * var(--vvh)) !important;
    gap: 6px !important;
  }

  #weapon-tree-overlay-footer-btn,
  #weapon-tree-overlay-close-btn {
    border-radius: 999px !important;
  }

  /* 9. Vibe Bazaar (#shop-screen) */
  #shop-screen .glass-panel {
    height: calc(94 * var(--vvh)) !important;
    min-height: auto !important;
    max-height: calc(94 * var(--vvh)) !important;
    padding: 10px 14px !important;
    gap: 6px !important;
  }
  #shop-screen .shop-header-row {
    padding: 4px 0 !important;
    min-height: 44px !important;
  }
  #shop-content-area {
    gap: 8px !important;
  }

  /* 10. Overclock Nexus Screen (#overclock-nexus-screen) */
  #overclock-nexus-screen .glass-panel {
    max-height: calc(94 * var(--vvh)) !important;
    padding: 8px 14px !important;
    gap: 6px !important;
  }
  .btn-upgrade-oc {
    min-height: 44px !important;
    padding: 6px 10px !important;
  }

  /* 11. Level Up Weapon Tree Screen (#level-up-screen) */
  #level-up-screen {
    height: 100% !important;
    min-height: 100% !important;
    max-height: none !important;
    padding: 8px 12px !important;
  }
  #level-up-screen .glass-panel {
    max-height: calc(94 * var(--vvh)) !important;
  }
  #level-up-screen .weapon-tree-footer,
  #level-up-screen .weapon-grid-footer {
    margin-top: auto !important;
    flex-shrink: 0 !important;
    gap: 14px !important;
    padding-bottom: 6px !important;
  }
  #level-up-screen #weapon-tree-grid-btn {
    padding: 6px 12px !important;
    font-size: 0.8rem !important;
    min-width: 120px !important;
  }

  /* 12. Gear Swap Screen (#gear-swap-screen) */
  #gear-swap-screen .glass-panel {
    max-height: calc(94 * var(--vvh)) !important;
    padding: 8px 14px !important;
    gap: 8px !important;
  }

  /* 13. Gear Refactor / Empower Screen (#gear-refactor-screen) */
  #gear-refactor-screen .glass-panel {
    max-height: calc(94 * var(--vvh)) !important;
    padding: 12px 18px !important;
    width: 660px !important;
    max-width: calc(96 * var(--vvw)) !important;
  }
  .gear-refactor-title {
    font-size: 1.1rem !important;
    margin-bottom: 2px !important;
  }
  .gear-refactor-desc {
    font-size: 0.62rem !important;
    line-height: 1.15 !important;
    margin-bottom: 10px !important;
  }
  .gear-refactor-body-layout {
    flex-direction: row !important;
    gap: 14px !important;
  }
  .gear-refactor-col-left {
    flex: 0 0 220px !important;
    gap: 8px !important;
  }
  .gear-refactor-col-right {
    gap: 6px !important;
  }
  .gear-refactor-header {
    padding: 8px 10px !important;
    gap: 10px !important;
    margin-bottom: 0 !important;
  }
  .gear-refactor-affix-list {
    max-height: 190px !important;
    gap: 6px !important;
  }
  .gear-refactor-affix-row {
    padding: 6px 34px 6px 12px !important;
    min-height: 36px !important;
    font-size: 0.74rem !important;
    display: flex;
    align-items: center;
  }

  /* 14. Achievements Screen (#achievements-screen) */
  #achievements-screen .glass-panel.ach-modal-panel {
    height: calc(92 * var(--vvh)) !important;
    max-height: calc(92 * var(--vvh)) !important;
    padding: 8px 12px !important;
    gap: 8px !important;
  }
  .ach-modal-header {
    padding-bottom: 6px !important;
  }
  .ach-header-title {
    font-size: 1.15rem !important;
  }
  .ach-header-badge {
    font-size: 0.78rem !important;
  }
  .ach-tab {
    padding: 5px 10px !important;
    font-size: 0.74rem !important;
  }
  .ach-sidebar {
    width: 190px !important;
    min-width: 190px !important;
    max-width: 190px !important;
    padding: 2px 6px 2px 0 !important;
    gap: 4px !important;
  }
  .ach-sidebar-tab {
    padding: 5px 8px !important;
    min-height: 48px !important;
    gap: 3px !important;
    font-size: 0.76rem !important;
  }
  .ach-sidebar-tab-top,
  .ach-sidebar-tab-left {
    gap: 6px !important;
  }
  .ach-sidebar-label {
    font-size: 0.76rem !important;
  }
  .ach-sidebar-tab-bottom {
    min-height: 16px !important;
  }
  .ach-sidebar-count {
    font-size: 0.65rem !important;
    padding: 1px 5px !important;
  }
  .ach-family-row, .ach-standalone-row {
    padding: 6px 10px !important;
    margin-bottom: 6px !important;
  }
  .ach-family-name, .ach-standalone-name {
    width: 130px !important;
    font-size: 0.76rem !important;
  }
  #achievements-scroll-body {
    max-height: calc(60 * var(--vvh)) !important;
    overflow-y: auto !important;
  }

  /* 15. Pause Screen (#pause-screen) */
  #pause-screen .pause-menu-panel {
    max-height: calc(94 * var(--vvh)) !important;
    padding: 8px 14px !important;
    max-width: min(calc(92 * var(--vvw)), 420px) !important;
  }
  #pause-screen .pause-title {
    font-size: 1.15rem !important;
    margin-bottom: 2px !important;
  }
  #pause-screen .pause-subtitle {
    font-size: 0.72rem !important;
    margin-bottom: 6px !important;
  }
  #pause-screen .pause-btn-grid {
    display: grid !important;
    grid-template-columns: 1fr 1fr !important;
    gap: 6px !important;
  }
  #pause-screen #resume-btn {
    grid-column: span 2 !important;
    min-height: 34px !important;
    padding: 6px 12px !important;
    font-size: 0.82rem !important;
  }
  #pause-screen .pause-btn-grid .btn:not(#resume-btn):not(#pause-exit-btn) {
    min-height: 30px !important;
    padding: 5px 8px !important;
    font-size: 0.72rem !important;
    margin: 0 !important;
  }
  #pause-screen #pause-exit-btn {
    grid-column: span 2 !important;
    min-height: 30px !important;
    padding: 5px 12px !important;
    font-size: 0.72rem !important;
    margin: 0 !important;
  }

  /* 16. Game Over Screen (#game-over-screen) */
  #game-over-screen .glass-panel.game-over-stage-frame {
    height: calc(94 * var(--vvh)) !important;
    max-height: calc(94 * var(--vvh)) !important;
    padding: 8px 14px !important;
    gap: 6px !important;
    overflow: hidden !important;
  }
}

/* Base Refactor Modal Layout & Dynamic Info Scaling */
.gear-refactor-panel {
  width: calc(700px * var(--ui-global-scale, 1));
  max-width: calc(95 * var(--vvw));
  padding: calc(22px * var(--ui-global-scale, 1)) calc(26px * var(--ui-global-scale, 1));
  box-sizing: border-box;
  transition: width 0.22s cubic-bezier(0.16, 1, 0.3, 1), min-height 0.22s cubic-bezier(0.16, 1, 0.3, 1);
  /* Solid dark-cyber backdrop matching the settings modal: a near-opaque
     gradient (instead of the translucent .glass-panel wash) with a purple
     neon border and ambient glow so the refactor/empower menu reads as a
     solid window rather than floating glass. Deliberately NOT !important so
     the one-shot .forge-flash box-shadow animation can still play. */
  background: linear-gradient(145deg, rgba(14, 10, 26, 0.95) 0%, rgba(8, 6, 18, 0.98) 100%);
  border: 1.5px solid rgba(var(--c-primary), 0.4);
}

/* The kit's window rule sets `transition: none` at id-level specificity, which beat the
   width / min-height transition above; restore it with an id-scoped rule. */
#gear-refactor-screen .glass-panel.gear-refactor-panel.cx-win {
  transition: width 0.22s cubic-bezier(0.16, 1, 0.3, 1), min-height 0.22s cubic-bezier(0.16, 1, 0.3, 1);
}

.gear-refactor-panel.info-open {
  width: min(calc(92 * var(--vvw)), 840px);
  min-height: min(520px, calc(85 * var(--vvh)));
}

.gear-refactor-info-overlay {
  display: none;
  position: absolute;
  inset: 0;
  background: rgba(8, 6, 18, 0.97);
  backdrop-filter: blur(12px);
  border-radius: 0;
  z-index: 20;
  padding: 22px 26px;
  flex-direction: column;
  justify-content: space-between;
  text-align: left;
  box-sizing: border-box;
}

.gear-refactor-info-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
  border-bottom: 1px solid rgba(var(--c-sky), 0.3);
  padding-bottom: 8px;
  flex: 0 0 auto;
}

.gear-refactor-info-content {
  flex: 1 1 auto;
  overflow-y: auto;
  min-height: 0;
  font-size: 0.72rem;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.9);
  margin-bottom: 10px;
  padding-right: 4px;
}

.gear-refactor-pool-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 6px 10px;
  list-style: none;
  padding: 0;
  margin: 0;
}

.gear-refactor-pool-item {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(var(--c-sky), 0.25);
  padding: 8px 12px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}

@media (max-width: 640px) {
  .gear-refactor-panel.info-open {
    width: calc(95 * var(--vvw));
    min-height: min(440px, calc(90 * var(--vvh)));
  }
  .gear-refactor-pool-grid {
    grid-template-columns: 1fr;
  }
}

.gear-refactor-body-layout {
  display: flex;
  flex-direction: row;
  gap: 20px;
  align-items: stretch;
  text-align: left;
  width: 100%;
  box-sizing: border-box;
}

.gear-refactor-col-left {
  flex: 0 0 250px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.gear-refactor-col-right {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}

.gear-refactor-header {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 14px;
  background: rgba(0, 0, 0, 0.22);
  border: 1.5px solid rgba(255, 255, 255, 0.08);
}

.gear-refactor-empower-box {
  padding: 12px 14px;
  background: rgba(0, 0, 0, 0.25);
  border: 1px dashed rgba(var(--c-gold), 0.3);
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.gear-refactor-affix-list {
  list-style: none;
  margin: 0;
  padding: 2px 4px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 260px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

@media (max-height: 420px) {
  #gear-refactor-screen .glass-panel {
    padding: 6px 10px !important;
    max-height: calc(96 * var(--vvh)) !important;
  }
  .gear-refactor-title {
    font-size: 0.95rem !important;
  }
  .gear-refactor-desc {
    display: none !important; /* Save vertical height on 350px tall screens */
  }
  /* No list cap here: a capped list hid the 4th affix behind a scrollbar on 412px phones while
     the panel had room to spare. The panel scrolls instead if an item ever has more rows. */
  .gear-refactor-affix-list {
    max-height: none !important;
  }
  .gear-refactor-affix-row {
    padding: 3px 6px !important;
    min-height: 32px !important;
    font-size: 0.65rem !important;
  }
}

@media (max-width: 520px) {
  .gear-refactor-body-layout {
    flex-direction: column !important;
  }
  .gear-refactor-col-left {
    flex: none !important;
    width: 100% !important;
  }
}

/* Vibe Bazaar Equipment tab on short landscape mobile screens (reported by
   Richard: gear/weapon icons shrink way too small). Below ~480px of actual
   viewport height, the fixed paddings/margins/gaps below the header row and
   above the currencies bar eat most of the available space before the icon
   grids (.gear-arpg-layout / #shop-inv-weapons) even get a chance to size
   themselves -- .mmo-slot icons scale to fill whatever box they're given
   (see .gear-arpg-layout comments above), so trimming the surrounding
   chrome directly grows the icons instead of needing to touch icon sizing
   at all. Doesn't touch the >720px-wide stacking breakpoint above -- this
   is purely about vertical space, independent of width. */
@media (max-height: 480px) {
  #shop-screen .glass-panel {
    padding: 8px 12px !important;
    gap: 6px !important;
  }
  .shop-header-row {
    padding: 4px 0 !important;
    min-height: 38px !important;
  }
  .bazaar-header-orb {
    width: 18px !important;
    height: 18px !important;
  }
  .bazaar-header-title {
    font-size: 0.95rem !important;
  }
  #shop-next-btn {
    padding: 3px 8px !important;
    font-size: 0.68rem !important;
    gap: 4px !important;
  }
  #shop-next-btn .shop-next-btn-menu-icon {
    width: 12px !important;
    height: 12px !important;
  }
  #shop-content-equipment {
    gap: 10px !important;
  }
  .shop-equip-left-col {
    gap: 6px !important;
  }
  .shop-equip-panel,
  .shop-weapons-panel {
    padding: 6px 8px !important;
  }
  .shop-equip-panel > h4,
  .shop-weapons-panel > h4 {
    margin-bottom: 4px !important;
    padding-bottom: 3px !important;
  }
  #shop-inv-weapons {
    gap: 4px !important;
  }
  .gear-arpg-layout {
    gap: 2% !important;
  }
  .shop-currencies-bar {
    margin-top: 6px !important;
    padding-top: 6px !important;
  }
}

@media (max-height: 520px) {
  .weapon-overview-grid {
    gap: 8px !important;
  }
  .weapon-grid-card {
    min-height: 82px !important;
    padding: 0 !important;
  }
  .weapon-grid-card-title {
    font-size: 0.82rem !important;
  }
  .weapon-grid-footer {
    margin-top: 8px !important;
  }
  #major-choice-screen .glass-panel {
    max-width: min(calc(94 * var(--vvw)), 540px) !important;
    padding: 8px 12px !important;
  }
  #major-choices-container .upgrade-card {
    padding: 6px 8px !important;
    gap: 8px !important;
  }
  #major-choices-container .card-icon {
    width: 42px !important;
    height: 42px !important;
    min-width: 42px !important;
    min-height: 42px !important;
  }
  #major-choices-container .upgrade-card h3 {
    font-size: 0.76rem !important;
    margin-bottom: 2px !important;
  }
  #major-choices-container .card-desc {
    font-size: 0.60rem !important;
    line-height: 1.2 !important;
  }
}

/* ==========================================================================
   SHOP GEAR CARD LAYOUT (.shop-gear-card & 2-Column Grid)
   ========================================================================== */
#shop-items,
#shop-inventory-items {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  /* Rows must size to their card. With implicit auto rows, a grid of definite
     height (the inventory list scrolls inside a fixed panel) shrinks rows to
     fit it once the cards overflow: .shop-gear-card has overflow:hidden, so
     its automatic minimum height is 0 and only its 160px min-height stops the
     squeeze -- every card ends up 160px and the Equip / Sell row of rare and
     higher gear (more affix lines) is clipped off the bottom. */
  grid-auto-rows: max-content;
  gap: 8px;
  align-content: start;
  overflow-y: auto;
  flex-grow: 1;
  min-height: 0;
  padding: 6px 8px;
  box-sizing: border-box;
  scroll-padding: 8px;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
}

@media (max-width: 900px) {
  #shop-items,
  #shop-inventory-items {
    grid-template-columns: 1fr;
  }
}

/* The shop's left column scrolls as a whole inside #shop-left-scroll (gamble +
   items + buyback), so the item grid grows to content rather than scrolling
   internally -- otherwise you'd get two nested scrollbars and the pinned
   reroll/respec/level-up row below would desync. */
#shop-left-scroll {
  padding: 2px 4px;
  box-sizing: border-box;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
}

#shop-left-scroll #shop-items {
  overflow-y: visible;
  flex-grow: 0;
  flex-shrink: 0;
  min-height: max-content;
  height: auto;
}

.shop-gear-card {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: 8px;
  /* frame, fill, rarity colour, hover lift and focus: the shared card treatment,
     css/03b-chamfer-kit.css section 21 */
  padding: 8px 10px;
  margin: 0;
  box-sizing: border-box;
  position: relative;
  overflow: hidden;
  min-height: calc(160px * var(--ui-global-scale, 1));
  transition: transform 0.15s ease, filter 0.2s ease, opacity 0.2s ease;
}

.shop-gear-card.controller-focused {
  z-index: 2;
}

.shop-gear-card .card-col-left {
  width: calc(82px * var(--ui-global-scale, 1));
  flex: 0 0 calc(82px * var(--ui-global-scale, 1));
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 2px;
  min-height: max-content;
  flex-shrink: 0;
}

.shop-gear-card .card-icon-box {
  width: calc(72px * var(--ui-global-scale, 1));
  height: calc(72px * var(--ui-global-scale, 1));
  display: flex;
  align-items: center;
  justify-content: center;
  /* striped art box: css/03b-chamfer-kit.css section 21 */
  box-sizing: border-box;
  position: relative;
  overflow: hidden;
  flex-shrink: 0;
}

.shop-gear-card .card-icon-box img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.shop-gear-card .card-type-text {
  /* rarity tag strip: css/03b-chamfer-kit.css section 21 */
  font-size: 0.66rem;
  text-align: center;
  font-weight: bold;
  line-height: 1.15;
  word-wrap: break-word;
  max-width: calc(80px * var(--ui-global-scale, 1));
}

.shop-gear-card .card-type-glitched-tag {
  display: block;
  font-size: 0.58rem;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #22d3ee;
  line-height: 1;
  margin-bottom: 1px;
}

.shop-gear-card .card-ilvl-text {
  font-size: 0.62rem;
  color: rgba(255, 255, 255, 0.6);
  text-align: center;
  font-weight: 600;
  line-height: 1.1;
  margin: 0;
}

.shop-gear-card .card-col-right {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 4px;
  min-width: 0;
}

.shop-gear-card .card-header-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}

.shop-gear-card .card-header-left {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1;
}

.shop-gear-card .card-title-text {
  font-size: 0.95rem;
  font-weight: bold;
  font-family: var(--font-display);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.shop-gear-card .card-price-badge {
  /* dashed price divider + coloured figure: css/03b-chamfer-kit.css section 21 */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 1px 7px;
  font-family: var(--font-display);
  font-size: 0.76rem;
  font-weight: 800;
  letter-spacing: 0.03em;
  line-height: 1.2;
  white-space: nowrap;
  flex-shrink: 0;
  max-width: 100%;
  box-sizing: border-box;
}

.shop-gear-card .card-col-left .card-price-badge {
  margin-top: auto;
  margin-bottom: 0;
}

.shop-gear-card .card-price-badge.can-afford {
  color: rgb(var(--c-gold));
}

.shop-gear-card .card-price-badge.cannot-afford {
  color: #f87171;
}

.shop-gear-card .card-stats-body {
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.85);
  line-height: 1.35;
  flex-grow: 1;
}

.shop-gear-card .card-actions-bar {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  flex-wrap: wrap;
}

/* Junk item dulled & desaturated visual overlay (the frame / fill are kit variables) */
.card-is-junk {
  filter: grayscale(0.65) opacity(0.65) !important;
  --bd: rgba(var(--c-danger), 0.25);
  --bg: rgba(10, 8, 18, 0.7);
}

/* Top-right corner tag button */
.shop-card-tag-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 8px;
  border-radius: 12px;
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid rgba(255, 255, 255, 0.15);
  color: #ffffff;
  font-size: 0.72rem;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.15s ease;
  min-height: 24px;
  box-sizing: border-box;
  white-space: nowrap;
  flex-shrink: 0;
}

:where(body:not(.gamepad-active)) .shop-card-tag-btn:hover {
  background: rgba(255, 255, 255, 0.15);
  border-color: rgba(var(--c-gold), 0.6);
  transform: scale(1.04);
}

.shop-card-tag-btn .tag-controller-x-icon,
.btn-controller-a-icon,
.btn-controller-x-icon,
.btn-controller-y-icon,
.tag-controller-rs-icon {
  display: none;
  width: 18px;
  height: 18px;
  object-fit: contain;
  vertical-align: middle;
  background: #0d1117;
  border: 1.5px solid rgba(255, 255, 255, 0.5);
  border-radius: 50%;
  box-shadow: 0 0 6px rgba(0, 0, 0, 0.8);
  padding: 1px;
  box-sizing: border-box;
  flex-shrink: 0;
}

/* Controller icon visibility rules */
body.input-gamepad .shop-card-tag-btn .tag-controller-x-icon,
body.gamepad-active .shop-card-tag-btn .tag-controller-x-icon,
body.input-gamepad .tag-controller-rs-icon,
body.gamepad-active .tag-controller-rs-icon {
  display: inline-block !important;
}

body.input-gamepad .shop-gear-card.controller-focused .btn-controller-a-icon,
body.gamepad-active .shop-gear-card.controller-focused .btn-controller-a-icon,
body.input-gamepad .shop-gear-card.controller-focused .btn-controller-x-icon,
body.gamepad-active .shop-gear-card.controller-focused .btn-controller-x-icon,
body.input-gamepad .shop-gear-card.controller-focused .btn-controller-y-icon,
body.gamepad-active .shop-gear-card.controller-focused .btn-controller-y-icon {
  display: inline-block !important;
}

.shop-gear-card.locked-item {
  /* reserved for the next reroll: a blue 2px frame and a blue wash instead of the rarity colours */
  --bd: rgb(var(--c-info));
  --bw: 2px;
  --bg: linear-gradient(180deg, rgba(var(--c-info), 0.2), transparent 55%), rgba(13, 10, 25, 0.96);
}

.btn-lock-gear {
  width: 28px !important;
  min-width: 28px !important;
  max-width: 28px !important;
  height: 28px !important;
  flex: 0 0 28px !important;
  padding: 0 !important;
  margin: 0 !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  border-radius: 6px !important;
  position: relative !important;
  box-sizing: border-box !important;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}

:where(body:not(.gamepad-active)) .btn-lock-gear:hover {
  background: rgba(var(--c-info), 0.25) !important;
  border-color: rgba(var(--c-info), 0.6) !important;
  transform: scale(1.08);
}

.btn-lock-gear.locked {
  background: rgba(var(--c-info), 0.28) !important;
  border-color: rgb(var(--c-info)) !important;
  color: #60a5fa !important;
  box-shadow: 0 0 10px rgba(var(--c-info), 0.45) !important;
}

:where(body:not(.gamepad-active)) .btn-lock-gear.locked:hover {
  background: rgba(var(--c-info), 0.4) !important;
  border-color: #60a5fa !important;
}

.btn-lock-gear.locked svg rect {
  fill: rgba(var(--c-info), 0.35);
}

.btn-lock-gear .btn-controller-x-icon {
  position: absolute;
  top: -5px;
  right: -5px;
  width: 14px;
  height: 14px;
  z-index: 2;
}

/* The gamble card's A glyph appears only while the card is controller-
   focused, matching the shop buy buttons (black chip via .btn-controller-a-icon). */
body.input-gamepad .shop-gear-card.shop-gamble-panel.controller-focused .btn-controller-a-icon,
body.gamepad-active .shop-gear-card.shop-gamble-panel.controller-focused .btn-controller-a-icon {
  display: inline-block !important;
}

:where(body:not(.gamepad-active)) .card-is-junk:hover,
.card-is-junk.controller-focused {
  filter: grayscale(0.25) opacity(0.85) !important;
}

.tag-badge-junk {
  background: rgba(var(--c-danger), 0.2);
  border: 1px solid rgba(var(--c-danger), 0.5);
  color: rgb(var(--c-danger));
  font-size: 0.7rem;
  padding: 2px 6px;
  border-radius: 6px;
  font-weight: bold;
}

.tag-badge-favorite {
  background: rgba(var(--c-gold), 0.2);
  border: 1px solid rgba(var(--c-gold), 0.5);
  color: rgb(var(--c-gold));
  font-size: 0.7rem;
  padding: 2px 6px;
  border-radius: 6px;
  font-weight: bold;
}

/* Sold item flying proxy clone */
.shop-item-fly-proxy {
  position: absolute;
  pointer-events: none;
  z-index: 1000;
  box-sizing: border-box;
  transform-origin: center center;
  will-change: transform, opacity;
  box-shadow: 0 0 20px rgba(var(--c-gold), 0.6), 0 0 40px rgba(var(--c-gold), 0.3);
  border: 1.5px solid rgb(var(--c-gold)) !important;
}

/* FLIP sliding animation for remaining inventory cards */
.shop-card-flip-sliding {
  transition: transform 0.24s cubic-bezier(0.2, 0.8, 0.25, 1) !important;
  will-change: transform;
}


/* =====================================================================
 * Dynamic Controls Infographic (Game Start Tutorial)
 * ===================================================================== */
.controls-infographic-card {
  width: 100%;
  background: rgba(10, 8, 20, 0.85);
  border: 1.5px solid rgba(var(--c-primary), 0.35);
  border-radius: 12px;
  padding: 12px;
  box-sizing: border-box;
  box-shadow: 0 0 20px rgba(var(--c-primary), 0.15), inset 0 0 10px rgba(0, 0, 0, 0.5);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.controls-infographic-header {
  font-family: monospace;
  font-size: 0.72rem;
  font-weight: bold;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgb(var(--c-primary));
  display: flex;
  align-items: center;
  gap: 6px;
}

/* Phone Frame Graphic for Touch Screen Mode */
.phone-frame {
  width: 280px;
  max-width: 100%;
  height: 150px;
  background: #090a15;
  border: 3px solid rgb(var(--c-sky));
  border-radius: 20px;
  position: relative;
  box-shadow: 0 0 20px rgba(var(--c-sky), 0.3), inset 0 0 15px rgba(0, 0, 0, 0.9);
  overflow: hidden;
  display: flex;
  margin: 0 auto;
}

.phone-camera-notch {
  position: absolute;
  left: 8px;
  top: 50%;
  transform: translateY(-50%);
  width: 5px;
  height: 26px;
  background: rgba(255, 255, 255, 0.25);
  border-radius: 4px;
  z-index: 10;
}

.phone-screen-divider {
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 1px;
  border-left: 1px dashed rgba(255, 255, 255, 0.15);
  z-index: 5;
}

.phone-zone-left {
  position: absolute;
  left: 0;
  top: 0;
  width: 55%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: radial-gradient(circle at 40% 50%, rgba(var(--c-sky), 0.22) 0%, transparent 75%);
  padding: 8px;
  box-sizing: border-box;
}

/* Circular Dash Button in Bottom-Right Corner (matches Android/Touch HUD) */
.phone-dash-circle {
  position: absolute;
  right: 18px;
  bottom: 18px;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(var(--c-secondary), 0.45) 0%, rgba(var(--c-secondary), 0.15) 70%);
  border: 2px solid rgb(var(--c-secondary));
  box-shadow: 0 0 14px rgba(var(--c-secondary), 0.6), inset 0 0 8px rgba(var(--c-secondary), 0.3);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  z-index: 10;
  animation: pulse-dash-circle 1.8s infinite ease-in-out;
}

.phone-dash-circle .phone-dash-icon {
  width: 22px;
  height: 22px;
  object-fit: contain;
  filter: drop-shadow(0 0 6px rgb(var(--c-secondary)));
}

.phone-dash-label {
  font-family: monospace;
  font-size: 0.54rem;
  font-weight: bold;
  color: rgb(var(--c-secondary));
  letter-spacing: 0.05em;
  margin-top: 1px;
}

@keyframes pulse-dash-circle {
  0%, 100% { transform: scale(1); box-shadow: 0 0 12px rgba(var(--c-secondary), 0.5); }
  50% { transform: scale(1.1); box-shadow: 0 0 20px rgba(var(--c-secondary), 0.9); }
}

.phone-zone-icon {
  width: 44px;
  height: 44px;
  object-fit: contain;
}

.phone-zone-left .phone-zone-icon {
  filter: drop-shadow(0 0 8px rgb(var(--c-sky)));
  animation: pulse-swipe-anim 2s infinite ease-in-out;
}


@keyframes pulse-swipe-anim {
  0%, 100% { transform: scale(1) translateX(0); }
  50% { transform: scale(1.08) translateX(4px); }
}


.phone-zone-label {
  font-family: monospace;
  font-size: 0.64rem;
  font-weight: bold;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-top: 6px;
  text-align: center;
}

.phone-zone-left .phone-zone-label {
  color: rgb(var(--c-sky));
}


.phone-autofire-pill {
  position: absolute;
  bottom: 6px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 0.56rem;
  font-family: monospace;
  font-weight: bold;
  color: rgb(var(--c-violet));
  background: rgba(var(--c-primary), 0.25);
  border: 1px solid rgba(var(--c-primary), 0.5);
  padding: 2px 8px;
  border-radius: 10px;
  white-space: nowrap;
  z-index: 10;
}

/* PC & Gamepad Infographic Card Grid */
.controls-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: 8px;
  width: 100%;
}

.controls-badge-card {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  padding: 8px 6px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  text-align: center;
}

.controls-badge-icons {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  flex-wrap: wrap;
}

.controls-badge-icons img {
  height: 32px;
  width: auto;
  object-fit: contain;
  filter: drop-shadow(0 0 6px rgba(255, 255, 255, 0.45));
}

/* 2-Row Keyboard WASD Cluster Layout */
.wasd-cluster {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}

.wasd-row-top {
  display: flex;
  justify-content: center;
}

.wasd-row-bottom {
  display: flex;
  justify-content: center;
  gap: 2px;
}

.wasd-cluster img {
  height: 24px;
  width: auto;
  object-fit: contain;
  filter: drop-shadow(0 0 5px rgba(255, 255, 255, 0.45));
}

.controls-badge-label {
  font-size: 0.68rem;
  font-weight: bold;
  color: rgba(255, 255, 255, 0.85);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.controls-badge-subtext {
  font-size: 0.6rem;
  color: rgba(255, 255, 255, 0.5);
  font-family: monospace;
}

/* 6x2 Dynamic Weapon Arsenal Grid Infographic */
.weapon-grid-infographic-card {
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  overflow: hidden;
  padding: 6px 8px !important;
}

.weapon-slots-grid-6x2 {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-template-rows: repeat(2, auto);
  gap: 5px;
  width: 100%;
  max-width: 100%;
  padding: 4px;
  box-sizing: border-box;
}

@media (max-width: 550px) {
  .weapon-slots-grid-6x2 {
    grid-template-columns: repeat(4, 1fr);
    gap: 4px;
  }
}

.weapon-slot-cell {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(var(--c-primary), 0.35);
  border-radius: 6px;
  padding: 4px 2px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
  box-sizing: border-box;
  min-width: 0;
  overflow: hidden;
}

:where(body:not(.gamepad-active)) .weapon-slot-cell:hover {
  transform: translateY(-2px);
  border-color: rgb(var(--c-sky));
  box-shadow: 0 0 10px rgba(var(--c-sky), 0.4);
  background: rgba(var(--c-sky), 0.12);
}

.weapon-slot-cell img {
  width: 100%;
  max-width: 32px;
  height: auto;
  aspect-ratio: 1;
  object-fit: contain;
  border-radius: 6px;
  border: 1.5px solid rgba(var(--c-primary), 0.5);
  background: rgba(10, 8, 20, 0.6);
  padding: 2px;
  box-sizing: border-box;
  filter: drop-shadow(0 0 6px rgba(var(--c-primary), 0.5));
  transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
}

:where(body:not(.gamepad-active)) .weapon-slot-cell:hover img {
  border-color: rgb(var(--c-sky));
  box-shadow: 0 0 8px rgba(var(--c-sky), 0.6);
  transform: scale(1.05);
}

.weapon-slot-cell-name {
  font-size: 0.58rem;
  font-weight: bold;
  color: rgba(255, 255, 255, 0.9);
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
  line-height: 1.1;
}

/* 5x1 Dynamic Gear Rarity Grid Infographic */
.gear-rarity-infographic-card {
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  overflow: hidden;
  padding: 6px 8px !important;
}

.gear-slots-grid-5x1 {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 8px;
  width: 100%;
  max-width: 100%;
  padding: 4px;
  box-sizing: border-box;
}

@media (max-width: 550px) {
  .gear-slots-grid-5x1 {
    gap: 4px;
  }
}

.gear-rarity-slot-cell {
  background: rgba(255, 255, 255, 0.04);
  border: 1.5px solid #ffffff;
  border-radius: 8px;
  padding: 6px 4px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
  box-sizing: border-box;
  min-width: 0;
  overflow: hidden;
}

:where(body:not(.gamepad-active)) .gear-rarity-slot-cell:hover {
  transform: translateY(-2px);
  background: rgba(255, 255, 255, 0.08);
}

.gear-rarity-slot-cell img {
  width: 100%;
  max-width: 44px;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 6px;
  border: 1.5px solid rgba(255, 255, 255, 0.5);
  background: rgba(10, 8, 20, 0.6);
  padding: 2px;
  box-sizing: border-box;
  transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
}

.gear-rarity-slot-cell-name {
  font-size: 0.65rem;
  font-weight: bold;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
  line-height: 1.1;
  text-shadow: 0 0 6px rgba(0, 0, 0, 0.8);
}

/* Bazaar Gear Gamble Infographic */
.gamble-infographic-card {
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  overflow: hidden;
  padding: 8px 12px !important;
}

.gamble-infographic-layout {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
}

.gamble-preview-box {
  width: 52px;
  height: 52px;
  min-width: 52px;
  background: radial-gradient(circle, rgba(var(--c-primary), 0.25), rgba(12, 10, 24, 0.9));
  border: 1.5px solid rgb(var(--c-primary));
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0 16px rgba(var(--c-primary), 0.35);
  color: rgb(var(--c-violet));
}

.gamble-preview-details {
  display: flex;
  flex-direction: column;
  gap: 5px;
  flex: 1;
  min-width: 0;
}

.gamble-empower-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 0.68rem;
  font-weight: 700;
  color: #facc15;
  letter-spacing: 0.04em;
  text-shadow: 0 0 8px rgba(250, 204, 21, 0.5);
}

.gamble-empower-badge svg {
  color: #facc15;
  filter: drop-shadow(0 0 4px rgba(250, 204, 21, 0.6));
}

.gamble-rarity-row {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.gamble-rarity-pill {
  font-size: 0.6rem;
  font-weight: 700;
  padding: 2px 6px;
  border-radius: 4px;
  border: 1px solid;
  line-height: 1.2;
}

/* Round Wager Infographic */
.wager-infographic-card {
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  overflow: hidden;
  padding: 8px 12px !important;
}

.wager-infographic-layout {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: 10px;
  width: 100%;
  align-items: stretch;
}

@media (max-width: 550px) {
  .wager-infographic-layout {
    grid-template-columns: 1fr;
    gap: 6px;
  }
}

.wager-preview-card {
  background: linear-gradient(135deg, rgba(var(--c-danger), 0.15), rgba(24, 16, 28, 0.85));
  border: 1.5px solid rgba(var(--c-danger), 0.6);
  border-radius: 8px;
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  gap: 3px;
  box-shadow: 0 0 14px rgba(var(--c-danger), 0.2);
}

.wager-preview-header {
  font-size: 0.64rem;
  font-weight: 700;
  color: #f87171;
  letter-spacing: 0.05em;
  display: flex;
  align-items: center;
  gap: 5px;
}

.wager-preview-contract {
  font-size: 0.76rem;
  font-weight: 800;
  color: #ffffff;
  letter-spacing: 0.02em;
}

.wager-preview-reward {
  font-size: 0.64rem;
  font-weight: 700;
  color: rgb(var(--c-gold));
  letter-spacing: 0.03em;
}

.wager-preview-skip {
  background: rgba(255, 255, 255, 0.04);
  border: 1.5px dashed rgba(255, 255, 255, 0.25);
  border-radius: 8px;
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
}

.wager-preview-skip-title {
  font-size: 0.72rem;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.85);
  letter-spacing: 0.03em;
}

.wager-preview-skip-desc {
  font-size: 0.62rem;
  color: rgba(255, 255, 255, 0.5);
  line-height: 1.2;
}

/* =====================================================================
 * Chaos Wave Infographics (Rounds 5, 10, 15)
 * ===================================================================== */
.chaos-infographic-card {
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  overflow: hidden;
  padding: 8px 12px !important;
}

.chaos-infographic-header {
  font-family: monospace;
  font-size: 0.70rem;
  font-weight: bold;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 2px;
}

.chaos-infographic-grid {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: 8px;
  width: 100%;
  align-items: stretch;
}

@media (max-width: 550px) {
  .chaos-infographic-grid {
    grid-template-columns: 1fr;
    gap: 6px;
  }
}

.chaos-subcard {
  background: rgba(12, 10, 24, 0.75);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 8px;
  padding: 6px 8px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  box-sizing: border-box;
}

.chaos-beacon-card .chaos-subcard-objective {
  border-color: rgba(var(--c-orange), 0.4);
  background: linear-gradient(135deg, rgba(var(--c-orange), 0.08), rgba(12, 10, 24, 0.85));
}

.chaos-hopper-card .chaos-subcard-objective {
  border-color: rgba(34, 197, 94, 0.4);
  background: linear-gradient(135deg, rgba(34, 197, 94, 0.08), rgba(12, 10, 24, 0.85));
}

.chaos-dimensions-card .chaos-subcard-objective {
  border-color: rgba(var(--c-sky), 0.4);
  background: linear-gradient(135deg, rgba(var(--c-sky), 0.08), rgba(12, 10, 24, 0.85));
}

.chaos-subcard-title {
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  display: flex;
  align-items: center;
  gap: 4px;
}

.chaos-subcard-body {
  display: flex;
  align-items: center;
  gap: 8px;
}

.chaos-detail-text {
  font-size: 0.64rem;
  line-height: 1.25;
  color: rgba(255, 255, 255, 0.82);
  flex: 1;
}

.chaos-beacon-visual-card {
  padding: 4px 6px !important;
  display: flex;
  justify-content: center;
  align-items: center;
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
}

.chaos-beacon-arena-visual {
  width: 100%;
  max-width: 480px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 10px;
  overflow: hidden;
  box-shadow: 0 0 20px rgba(var(--c-orange), 0.22);
}

.chaos-beacon-svg-diagram {
  display: block;
  width: 100%;
  height: auto;
  max-height: 220px;
}

@keyframes chaosBeaconRotateDash {
  to {
    stroke-dashoffset: -32;
  }
}

.chaos-beacon-svg-dashed {
  animation: chaosBeaconRotateDash 3s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .chaos-beacon-svg-dashed {
    animation: none !important;
  }
}

.chaos-hopper-visual-card {
  padding: 4px 6px !important;
  display: flex;
  justify-content: center;
  align-items: center;
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
}

.chaos-hopper-arena-visual {
  width: 100%;
  max-width: 480px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 10px;
  overflow: hidden;
  box-shadow: 0 0 20px rgba(var(--c-rose), 0.22);
}

.chaos-hopper-svg-diagram {
  display: block;
  width: 100%;
  height: auto;
  max-height: 220px;
}

@keyframes chaosHopperRotateDash {
  to {
    stroke-dashoffset: -28;
  }
}

.chaos-hopper-svg-dashed {
  animation: chaosHopperRotateDash 3s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .chaos-hopper-svg-dashed {
    animation: none !important;
  }
}


.chaos-hazard-warning {
  font-size: 0.58rem;
  color: #fdba74;
  background: rgba(var(--c-orange), 0.1);
  border: 1px solid rgba(var(--c-orange), 0.3);
  border-radius: 4px;
  padding: 2px 5px;
  display: flex;
  align-items: center;
  gap: 4px;
  line-height: 1.2;
}

.chaos-tier-list {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 3px;
}


.tier-bronze .chaos-tier-tag { background: rgba(217, 119, 6, 0.25); color: #f59e0b; border: 1px solid rgba(245, 158, 11, 0.4); }
.tier-silver .chaos-tier-tag { background: rgba(var(--c-slate), 0.25); color: #cbd5e1; border: 1px solid rgba(203, 213, 225, 0.4); }
.tier-gold .chaos-tier-tag { background: rgba(234, 179, 8, 0.25); color: #facc15; border: 1px solid rgba(250, 204, 21, 0.4); }
.tier-platinum .chaos-tier-tag { background: rgba(var(--c-sky), 0.25); color: rgb(var(--c-sky)); border: 1px solid rgba(var(--c-sky), 0.4); }


.chaos-phase-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 2px;
}

.chaos-phase-pill {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 3px 5px;
  border-radius: 6px;
  border: 1px solid;
  text-align: center;
}

.phase-prime {
  background: rgba(6, 182, 212, 0.15);
  border-color: #06b6d4;
  color: rgb(var(--c-cyan));
}

.phase-void {
  background: rgba(var(--c-primary), 0.15);
  border-color: rgb(var(--c-primary));
  color: rgb(var(--c-violet));
}

.chaos-phase-name {
  font-family: monospace;
  font-size: 0.56rem;
  font-weight: 800;
  letter-spacing: 0.04em;
}

.chaos-phase-sub {
  font-size: 0.50rem;
  opacity: 0.85;
}

.chaos-phase-shift-arrow {
  color: rgba(255, 255, 255, 0.6);
  font-weight: bold;
  font-size: 0.85rem;
}

.chaos-portal-graphic {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 88px;
}

.chaos-portal-badge {
  font-family: monospace;
  font-size: 0.52rem;
  font-weight: 800;
  color: rgb(var(--c-rose));
  background: rgba(var(--c-rose), 0.18);
  border: 1px solid rgba(var(--c-rose), 0.45);
  padding: 2px 4px;
  border-radius: 4px;
  text-align: center;
}

.chaos-portal-alert {
  font-family: monospace;
  font-size: 0.48rem;
  font-weight: 700;
  color: #facc15;
  background: rgba(250, 204, 21, 0.15);
  padding: 1px 3px;
  border-radius: 3px;
  text-align: center;
}

/* ===========================================================
   SURVIVOR UPGRADES SCREEN — Redesigned
   =========================================================== */

.survivor-tree-overlay {
  /* colour only: the shorthand would also wipe the kit's accent halo (background-image) */
  background-color: rgba(4, 3, 10, 0.85) !important;
  backdrop-filter: blur(14px) saturate(120%) !important;
  -webkit-backdrop-filter: blur(14px) saturate(120%) !important;
}

.glass-panel.su-frame {
  width: min(calc(1160px * var(--ui-global-scale, 1)), calc(95 * var(--vvw)));
  max-width: calc(95 * var(--vvw));
  height: min(calc(720px * var(--ui-global-scale, 1)), calc(92 * var(--vvh)));
  max-height: calc(92 * var(--vvh));
  padding: calc(18px * var(--ui-global-scale, 1)) calc(22px * var(--ui-global-scale, 1));
  display: flex;
  flex-direction: column;
  gap: 12px;
  /* window look (fill, border, corners, glow) comes from the chamfer kit: .cut.cx-win, 03b-chamfer-kit.css */
  box-sizing: border-box;
  overflow: hidden;
  align-items: stretch;
  transition: none !important;
}

.su-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  border-bottom: 1.5px solid rgba(255, 255, 255, 0.08);
  padding-bottom: 8px;
  flex-shrink: 0;
  gap: 12px;
}

.su-header-left {
  display: flex;
  align-items: center;
  gap: 10px;
}

.su-title {
  color: rgb(var(--c-violet));
  margin: 0;
  text-transform: uppercase;
  font-size: 1.35rem;
  letter-spacing: 0.05em;
}

.su-balances {
  display: flex;
  gap: 14px;
  align-items: center;
  flex-wrap: wrap;
}

.su-balance {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border-radius: 999px;
  border: 1px solid rgba(var(--c-primary), 0.6);
  background: rgba(var(--c-primary), 0.12);
  box-shadow: 0 0 10px rgba(var(--c-primary), 0.2);
  white-space: nowrap;
}

.su-balance__label {
  font-size: 0.72rem;
  color: rgba(255, 255, 255, 0.75);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 600;
}

.su-balance__value {
  font-size: 1rem;
  font-weight: 800;
  color: rgb(var(--c-gold));
  font-family: var(--font-display);
}

/* 2-Column Main Content Layout */
.su-content-layout {
  display: grid;
  grid-template-columns: 1fr 310px;
  gap: 16px;
  flex: 1 1 auto;
  min-height: 0;
  align-items: stretch;
}

.su-tree-column {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  height: 100%;
  position: relative;
}

.su-track-tabs {
  /* segmented control: frame, inset and gap from css/03b-chamfer-kit.css section 18 */
  display: none;
  margin-bottom: 8px;
  flex-wrap: wrap;
  justify-content: center;
  flex-shrink: 0;
}

.su-track-tab {
  padding: 6px 14px;
  font-size: 0.75rem;
  font-weight: bold;
  /* colour / fill / active / hover / focus: css/03b-chamfer-kit.css section 18 */
}

/* Tree Scrollable Body */
.su-body {
  position: relative;
  flex: 1 1 auto;
  width: 100%;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  touch-action: pan-y;
  -webkit-overflow-scrolling: touch;
  padding: 12px 10px;
  border: 1.5px solid rgba(255, 255, 255, 0.08);
  background: rgba(10, 8, 20, 0.55);
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

/* Energy Threshold Backdrop */
.su-energy-backdrop {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  border-radius: 12px;
  overflow: hidden;
}

.su-energy-fill {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  background: linear-gradient(0deg, rgba(var(--c-primary), 0.22) 0%, rgba(var(--c-primary), 0.08) 80%, rgba(var(--c-violet), 0.25) 100%);
  transition: height 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

.su-energy-glow-edge {
  position: absolute;
  top: -2px;
  left: 0;
  width: 100%;
  height: 4px;
  background: linear-gradient(90deg, transparent 5%, rgb(var(--c-violet)) 30%, #e879f9 50%, rgb(var(--c-violet)) 70%, transparent 95%);
  box-shadow: 0 0 16px #e879f9, 0 0 8px rgb(var(--c-primary));
}

.su-threshold-line {
  position: absolute;
  left: 0;
  width: 100%;
  height: 0;
  border-top: 1.5px dashed rgba(255, 255, 255, 0.12);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 10px;
  box-sizing: border-box;
  pointer-events: none;
  z-index: 1;
  transition: border-color 0.3s ease, box-shadow 0.3s ease;
}

.su-threshold-tag {
  font-size: 0.6rem;
  font-family: var(--font-display);
  font-weight: 800;
  letter-spacing: 0.05em;
  color: rgba(255, 255, 255, 0.35);
  background: rgba(14, 10, 24, 0.9);
  padding: 2px 7px;
  border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  transform: translateY(-50%);
  transition: all 0.3s ease;
  white-space: nowrap;
  flex-shrink: 0;
}

.su-threshold-status {
  font-size: 0.55rem;
  font-family: var(--font-display);
  font-weight: 800;
  letter-spacing: 0.08em;
  color: rgba(255, 255, 255, 0.25);
  background: rgba(14, 10, 24, 0.9);
  padding: 2px 6px;
  border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.06);
  transform: translateY(-50%);
  transition: all 0.3s ease;
  white-space: nowrap;
  flex-shrink: 0;
}

.su-threshold-line.unlocked {
  border-top-color: rgba(var(--c-primary), 0.5);
  box-shadow: 0 0 12px rgba(var(--c-primary), 0.25);
}

.su-threshold-line.unlocked .su-threshold-tag {
  color: rgb(var(--c-violet));
  border-color: rgba(var(--c-primary), 0.4);
  box-shadow: 0 0 8px rgba(var(--c-primary), 0.3);
  background: rgba(24, 16, 42, 0.95);
}

.su-threshold-line.unlocked .su-threshold-status {
  color: rgb(var(--c-mint));
  border-color: rgba(var(--c-mint), 0.35);
  box-shadow: 0 0 8px rgba(var(--c-mint), 0.25);
  background: rgba(20, 36, 30, 0.95);
}

/* SVG Conduits Layer */
.su-conduits-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 2;
}

.su-conduit-path {
  fill: none;
  stroke-width: 2.5;
  opacity: 0.25;
  stroke-dasharray: 4 3;
  stroke-linecap: butt;
  transition: all 0.3s ease;
}

.su-conduit-path.lit {
  opacity: 0.85;
  stroke-width: 3;
  stroke-dasharray: none;
  stroke-linecap: butt;
  filter: drop-shadow(0 0 5px currentColor);
}

.su-conduit-path.animated-pulse {
  animation: su-conduit-shimmer 3s ease-in-out infinite;
}

@keyframes su-conduit-shimmer {
  0%, 100% { opacity: 0.75; }
  50% { opacity: 1; }
}

/* 3-Track Grid with side clearance for threshold markers */
.su-tracks-grid {
  position: relative;
  z-index: 3;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  margin-bottom: 8px;
  padding: 0 46px;
  box-sizing: border-box;
  flex: 1 1 auto;
  min-height: 0;
}

.su-track-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  height: 100%;
  gap: 8px;
}

.su-track-col-header {
  font-size: 0.82rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--track-color, #a855f7);
  text-shadow: 0 0 8px color-mix(in srgb, var(--track-color, #a855f7) 50%, transparent);
  opacity: 0.95;
  margin-bottom: 2px;
  font-weight: 700;
}

.su-track-col[data-track-idx="0"] { --track-color: rgb(var(--c-amber)); }
.su-track-col[data-track-idx="1"] { --track-color: rgb(var(--c-sky)); }
.su-track-col[data-track-idx="2"] { --track-color: #e879f9; }

/* Track Node Cards */
.su-node {
  position: relative;
  width: 100%;
  max-width: 110px;
  aspect-ratio: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 8px 6px;
  border-radius: 18px;
  background: rgba(18, 14, 32, 0.98);
  border: 1.5px solid var(--track-color, rgba(255, 255, 255, 0.12));
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
  cursor: pointer;
  outline: none;
  box-sizing: border-box;
  transition: all 0.18s cubic-bezier(0.4, 0, 0.2, 1);
}

.su-node__layer-badge {
  position: absolute;
  top: 5px;
  left: 8px;
  font-size: 0.58rem;
  font-weight: 800;
  font-family: var(--font-display);
  color: rgba(255, 255, 255, 0.45);
}

.su-node__icon-wrap {
  position: relative;
  width: 54%;
  aspect-ratio: 1;
  flex-shrink: 0;
  transition: all 0.2s ease;
}

.su-node__icon {
  width: 100%;
  height: 100%;
  display: block;
}

.su-node__name {
  font-size: 0.68rem;
  font-weight: 600;
  text-align: center;
  color: #fff;
  line-height: 1.15;
  max-width: 92%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-top: 1px;
}

.su-node__cost {
  font-size: 0.72rem;
  font-weight: 800;
  color: var(--track-color, #a855f7);
  font-family: var(--font-display);
}

.su-node__pts-label {
  font-size: 0.58rem;
  opacity: 0.75;
  font-weight: normal;
}

.su-node__owned-check {
  color: rgb(var(--c-success));
  font-weight: 900;
  font-size: 0.85rem;
  text-shadow: 0 0 8px rgb(var(--c-success));
}

.su-node.owned {
  border-color: rgb(var(--c-success));
  background: #0c1c17;
  box-shadow: 0 0 14px rgba(var(--c-success), 0.25);
}

.su-node.owned .su-node__icon-wrap {
  filter: drop-shadow(0 0 6px rgba(var(--c-mint), 0.5));
}

.su-node.purchasable:not(.owned) {
  box-shadow: 0 0 14px color-mix(in srgb, var(--track-color, #a855f7) 45%, transparent);
}

.su-node.purchasable:not(.owned) .su-node__icon-wrap {
  filter: drop-shadow(0 0 5px color-mix(in srgb, var(--track-color, #a855f7) 60%, transparent));
}

.su-node.locked {
  cursor: default;
  filter: grayscale(0.3);
  background: rgba(14, 11, 24, 0.98);
  border-color: rgba(255, 255, 255, 0.08);
}

.su-node.locked .su-node__name,
.su-node.locked .su-node__cost,
.su-node.locked .su-node__layer-badge {
  opacity: 0.5;
}

.su-node.locked .su-node__icon-wrap {
  opacity: 0.65;
  filter: contrast(1.15);
}

:where(body:not(.gamepad-active)) .su-node:hover,
.su-node.selected {
  border-color: rgb(var(--c-gold)) !important;
  box-shadow: 0 0 0 2px rgba(var(--c-gold), 0.5), 0 0 18px rgba(var(--c-gold), 0.4);
  z-index: 5;
}

.su-node.controller-focused,
.su-node.controller-focused.selected,
#survivor-upgrades-screen .su-node.controller-focused {
  border-color: rgb(var(--c-focus)) !important;
  outline: 3px solid rgb(var(--c-focus)) !important;
  outline-offset: 2px !important;
  box-shadow: 0 0 0 2px rgba(var(--c-focus), 0.6), 0 0 20px rgba(var(--c-focus), 0.85) !important;
  z-index: 10 !important;
  transform: none !important;
}

/* Icon Animations */
.su-icon__core { fill: var(--track-color, #a855f7); }
.su-icon__orbit-path { fill: none; stroke: var(--track-color, #a855f7); stroke-opacity: 0.35; stroke-width: 1; }
.su-icon__particle { fill: var(--track-color, #a855f7); }
.su-icon__spin { transform-origin: center; animation: su-icon-spin 5s linear infinite; }
.su-icon--l1 .su-icon__spin { animation-duration: 6s; }
.su-icon--l3 .su-icon__spin { animation-duration: 3.5s; }
@keyframes su-icon-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

.su-icon__pulse-ring { fill: none; stroke: var(--track-color, #a855f7); stroke-width: 1.5; transform-origin: center; animation: su-icon-pulse 2.2s ease-out infinite; opacity: 0; }
.su-icon__pulse-ring--b { animation-delay: 1.1s; }
@keyframes su-icon-pulse {
  0% { transform: scale(0.5); opacity: 0.9; }
  100% { transform: scale(1.8); opacity: 0; }
}

.su-icon--l3 .su-icon__shard { fill: var(--track-color, #a855f7); filter: drop-shadow(0 0 3px color-mix(in srgb, var(--track-color, #a855f7) 60%, transparent)); }
.su-icon--l3 .su-icon__core { filter: drop-shadow(0 0 4px color-mix(in srgb, var(--track-color, #a855f7) 70%, transparent)); }

.su-node.owned .su-icon__core,
.su-node.owned .su-icon__particle,
.su-node.owned .su-icon__shard { fill: rgb(var(--c-mint)); }
.su-node.owned .su-icon__pulse-ring { stroke: rgb(var(--c-mint)); }

/* ---- Soldier Bespoke Upgrade Node Icon Animations ------------------- */

/* 1. Firepower L1: Tuned Actuators */
.su-icon--soldier-actuators {
  color: var(--track-color, #fb923c);
}
.su-anim-piston-left {
  animation: su-piston-thrust-l 1.2s ease-in-out infinite alternate;
}
.su-anim-piston-right {
  animation: su-piston-thrust-r 1.2s ease-in-out infinite alternate 0.3s;
}
.su-actuator-laser {
  animation: su-laser-pulse 1.2s ease-in-out infinite alternate;
}
@keyframes su-piston-thrust-l {
  0% { transform: translateX(0px); }
  100% { transform: translateX(3px); filter: drop-shadow(0 0 4px rgb(var(--c-gold))); }
}
@keyframes su-piston-thrust-r {
  0% { transform: translateX(0px); }
  100% { transform: translateX(-3px); filter: drop-shadow(0 0 4px rgb(var(--c-gold))); }
}
@keyframes su-laser-pulse {
  0% { opacity: 0.4; transform: scale(0.8); }
  100% { opacity: 1; transform: scale(1.4); filter: drop-shadow(0 0 4px #ffffff); }
}

/* 2. Firepower L2: Overpressured Mags */
.su-icon--soldier-mag {
  color: var(--track-color, #fb923c);
}
.su-mag-rnd {
  opacity: 0.4;
  animation: su-mag-charge 1.6s ease-in-out infinite;
}
.su-rnd-0 { animation-delay: 0s; }
.su-rnd-1 { animation-delay: 0.25s; }
.su-rnd-2 { animation-delay: 0.5s; }
.su-rnd-3 { animation-delay: 0.75s; }

.su-mag-vent {
  opacity: 0;
  animation: su-mag-vent-pulse 1.6s ease-out infinite 0.9s;
}
@keyframes su-mag-charge {
  0%, 100% { opacity: 0.35; filter: none; }
  35%, 65% { opacity: 1; filter: drop-shadow(0 0 4px rgb(var(--c-gold))); }
}
@keyframes su-mag-vent-pulse {
  0% { opacity: 0; transform: scale(0.7); }
  30% { opacity: 1; transform: scale(1.1); filter: drop-shadow(0 0 5px rgb(var(--c-danger))); }
  80%, 100% { opacity: 0; transform: scale(1.4); }
}

/* 3. Firepower L3: Requisition Drop: Shotgun */
.su-icon--soldier-shotgun {
  color: var(--track-color, #fb923c);
}
.su-anim-shotgun-body {
  animation: su-shotgun-recoil 1.6s cubic-bezier(0.1, 0.9, 0.2, 1) infinite;
  transform-origin: center;
}
.su-shotgun-flash {
  animation: su-shotgun-flash-burst 1.6s ease-out infinite;
  transform-origin: 13px -6px;
}
.su-shotgun-pellet {
  animation: su-shotgun-pellet-fly 1.6s cubic-bezier(0.1, 0.7, 0.1, 1) infinite;
}
.su-p-1 { --p-dx: 7px; --p-dy: -6px; }
.su-p-2 { --p-dx: 8px; --p-dy: -2px; }
.su-p-3 { --p-dx: 9px; --p-dy: 0px; }
.su-p-4 { --p-dx: 8px; --p-dy: 3px; }
.su-p-5 { --p-dx: 7px; --p-dy: 6px; }

@keyframes su-shotgun-recoil {
  0% { transform: translate(-3px, 1px) rotate(-3deg); }
  18% { transform: translate(0px, 0px) rotate(0deg); }
  100% { transform: translate(0px, 0px) rotate(0deg); }
}
@keyframes su-shotgun-flash-burst {
  0% { opacity: 1; transform: scale(1.5); }
  14% { opacity: 0; transform: scale(0.3); }
  100% { opacity: 0; }
}
@keyframes su-shotgun-pellet-fly {
  0% { opacity: 1; transform: translate(0, 0) scale(1.3); }
  45% { opacity: 0.9; transform: translate(var(--p-dx), var(--p-dy)) scale(0.9); }
  75%, 100% { opacity: 0; transform: translate(calc(var(--p-dx) * 1.3), calc(var(--p-dy) * 1.3)) scale(0.4); }
}

/* 4. Fortification L1: Combat Plating */
.su-icon--soldier-plating {
  color: var(--track-color, #38bdf8);
}
.su-hex-plate {
  animation: su-hex-breathe 2.4s ease-in-out infinite alternate;
}
.su-hex-top { animation-delay: 0s; }
.su-hex-bl { animation-delay: 0.4s; }
.su-hex-br { animation-delay: 0.8s; }

.su-anim-hex-sheen {
  animation: su-sheen-sweep 2.4s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
@keyframes su-hex-breathe {
  0% { fill-opacity: 0.15; stroke-opacity: 0.6; }
  100% { fill-opacity: 0.45; stroke-opacity: 1; filter: drop-shadow(0 0 3px currentColor); }
}
@keyframes su-sheen-sweep {
  0%, 15% { opacity: 0; stroke-dasharray: 4 20; stroke-dashoffset: 20; }
  50% { opacity: 1; stroke-dasharray: 20 10; stroke-dashoffset: 0; }
  85%, 100% { opacity: 0; stroke-dasharray: 4 20; stroke-dashoffset: -20; }
}

/* 5. Fortification L2: Reinforced Bulkhead */
.su-icon--soldier-bulkhead {
  color: var(--track-color, #38bdf8);
}
.su-bulkhead-core {
  animation: su-bulkhead-core-pulse 2s ease-in-out infinite;
}
@keyframes su-bulkhead-core-pulse {
  0%, 100% { transform: scale(0.8); opacity: 0.6; }
  50% { transform: scale(1.3); opacity: 1; filter: drop-shadow(0 0 4px currentColor); }
}

/* 6. Fortification L3: Bulwark Reserve / Resonator (Standing Overshield) */
.su-icon--soldier-bulwark {
  color: var(--track-color, #38bdf8);
}
.su-bulwark-dome {
  animation: su-bulwark-dome-breathe 2.4s ease-in-out infinite alternate;
}
.su-bulwark-shield {
  animation: su-bulwark-shield-glow 2.4s ease-in-out infinite alternate;
}
.su-bulwark-hexgrid polygon {
  animation: su-bulwark-hex-flicker 1.8s ease-in-out infinite alternate;
}
.su-bulwark-hexgrid polygon:nth-child(2) {
  animation-delay: 0.9s;
}
.su-bulwark-core {
  animation: su-bulwark-core-flare 1.2s ease-in-out infinite alternate;
}
.su-bulwark-pulse {
  transform-origin: 0 0;
  animation: su-bulwark-wave 2.2s cubic-bezier(0.1, 0.8, 0.3, 1) infinite;
}
.su-bp-2 { animation-delay: 1.1s; }

@keyframes su-bulwark-dome-breathe {
  0% { opacity: 0.5; stroke-dasharray: 4 2; }
  100% { opacity: 1; stroke-dasharray: none; filter: drop-shadow(0 0 4px currentColor); }
}
@keyframes su-bulwark-shield-glow {
  0% { fill-opacity: 0.18; filter: none; }
  100% { fill-opacity: 0.45; filter: drop-shadow(0 0 6px currentColor); }
}
@keyframes su-bulwark-hex-flicker {
  0% { fill-opacity: 0.2; stroke-opacity: 0.4; }
  100% { fill-opacity: 0.6; stroke-opacity: 1; filter: drop-shadow(0 0 3px #67e8f9); }
}
@keyframes su-bulwark-core-flare {
  0% { transform: scale(0.8); opacity: 0.7; }
  100% { transform: scale(1.3); opacity: 1; filter: drop-shadow(0 0 5px #ffffff); }
}
@keyframes su-bulwark-wave {
  0% { transform: scale(0.5); opacity: 0.9; stroke-width: 1.8; }
  75% { opacity: 0.3; stroke-width: 1; }
  100% { transform: scale(1.45); opacity: 0; stroke-width: 0.4; }
}

/* 7. Logistics L1: Supply Drop */
.su-icon--soldier-supply {
  color: var(--track-color, #e879f9);
}
.su-anim-supply-pod {
  animation: su-supply-bob 2.4s ease-in-out infinite;
}
.su-coin-sparkle {
  animation: su-coin-twinkle 1.8s ease-in-out infinite;
  transform-origin: center;
}
.su-cs-1 { animation-delay: 0s; }
.su-cs-2 { animation-delay: 0.6s; }
.su-cs-3 { animation-delay: 1.2s; }
@keyframes su-supply-bob {
  0%, 100% { transform: translateY(0px); }
  50% { transform: translateY(3px); }
}
@keyframes su-coin-twinkle {
  0%, 100% { transform: scale(0.6); opacity: 0.3; }
  50% { transform: scale(1.3); opacity: 1; filter: drop-shadow(0 0 4px rgb(var(--c-gold))); }
}

/* 8. Logistics L2: Quartermaster Route */
.su-icon--soldier-route {
  color: var(--track-color, #e879f9);
}
.su-anim-route-compass {
  transform-origin: center;
  animation: su-icon-spin 8s linear infinite;
}
.su-route-wp {
  animation: su-wp-beacon 2s ease-in-out infinite;
}
.su-wp-1 { animation-delay: 0s; }
.su-wp-2 { animation-delay: 0.5s; }
.su-wp-3 { animation-delay: 1.0s; }
.su-wp-4 { animation-delay: 1.5s; }
@keyframes su-wp-beacon {
  0%, 100% { transform: scale(0.8); opacity: 0.4; }
  25% { transform: scale(1.4); opacity: 1; filter: drop-shadow(0 0 4px currentColor); }
}

/* 9. Logistics L3: Advance Recon */
.su-icon--soldier-recon {
  color: var(--track-color, #e879f9);
}
.su-anim-recon-sat {
  animation: su-sat-float 3s ease-in-out infinite;
}
.su-anim-radar-cone {
  transform-origin: center;
  animation: su-icon-spin 3.2s linear infinite;
}
.su-recon-target {
  animation: su-target-blink 3.2s ease-in-out infinite;
}
.su-tgt-1 { animation-delay: 0.8s; }
.su-tgt-2 { animation-delay: 2.4s; }
@keyframes su-sat-float {
  0%, 100% { transform: translateY(0px) rotate(-2deg); }
  50% { transform: translateY(-2px) rotate(2deg); }
}
@keyframes su-target-blink {
  0%, 20%, 100% { opacity: 0; transform: scale(0.5); }
  5% { opacity: 1; transform: scale(1.4); filter: drop-shadow(0 0 4px rgb(var(--c-gold))); }
  12% { opacity: 0.8; transform: scale(1); }
}

/* ---- Guardian Bespoke Upgrade Node Icon Animations ------------------- */

/* 1. Retaliation L1: Spiked Plating */
.su-icon--guardian-spikes {
  color: var(--track-color, #fb923c);
}
.su-anim-spike {
  transform-origin: center;
  animation: su-spike-thrust 1.2s cubic-bezier(0.1, 0.9, 0.2, 1) infinite;
}
.su-sp-r { animation-delay: 0.3s; }
.su-sp-b { animation-delay: 0.6s; }
.su-sp-l { animation-delay: 0.9s; }
@keyframes su-spike-thrust {
  0%, 100% { transform: scale(1); filter: none; }
  35% { transform: scale(1.35); filter: drop-shadow(0 0 4px currentColor); }
}

/* 2. Retaliation L2: Kinetic Return */
.su-icon--guardian-kinetic-return {
  color: var(--track-color, #fb923c);
}
.su-anim-kr-in {
  animation: su-kr-inward 1.6s ease-in-out infinite;
}
.su-kr-core {
  animation: su-kr-core-pulse 1.6s ease-in-out infinite;
}
.su-anim-kr-out {
  animation: su-kr-outward 1.6s ease-out infinite;
}
@keyframes su-kr-inward {
  0% { opacity: 0.2; transform: translateX(-4px); }
  50% { opacity: 1; transform: translateX(0px); }
  75%, 100% { opacity: 0.2; transform: translateX(0px); }
}
@keyframes su-kr-core-pulse {
  0%, 100% { transform: scale(0.8); opacity: 0.6; }
  50% { transform: scale(1.3); opacity: 1; filter: drop-shadow(0 0 6px currentColor); }
}
@keyframes su-kr-outward {
  0%, 40% { opacity: 0; transform: translateX(0px) scale(0.6); }
  65% { opacity: 1; transform: translateX(4px) scale(1.2); filter: drop-shadow(0 0 4px rgb(var(--c-gold))); }
  100% { opacity: 0; transform: translateX(8px) scale(0.8); }
}

/* 3. Retaliation L3: Countermeasure Array (Sonic Repulsor) */
.su-icon--guardian-repulsor {
  color: var(--track-color, #fb923c);
}
.su-repulsor-wave {
  transform-origin: 0 0;
  animation: su-repulsor-expand 2s cubic-bezier(0.1, 0.8, 0.3, 1) infinite;
}
.su-rw-1 { animation-delay: 0s; }
.su-rw-2 { animation-delay: 0.66s; }
.su-rw-3 { animation-delay: 1.33s; }
.su-repulsor-gem {
  animation: su-repulsor-gem-glow 1s ease-in-out infinite alternate;
}
@keyframes su-repulsor-expand {
  0% { transform: scale(0.4) rotate(0deg); opacity: 0.9; stroke-width: 1.8; }
  75% { opacity: 0.35; stroke-width: 1.1; }
  100% { transform: scale(1.5) rotate(45deg); opacity: 0; stroke-width: 0.4; }
}
@keyframes su-repulsor-gem-glow {
  0% { transform: scale(0.8); opacity: 0.7; }
  100% { transform: scale(1.3); opacity: 1; filter: drop-shadow(0 0 5px rgb(var(--c-gold))); }
}


.su-ss-1 { animation-delay: 0s; }
.su-ss-2 { animation-delay: 0.4s; }


/* ---- Scout Bespoke Upgrade Node Icon Animations ---------------------- */

/* 1. Bladework L1: Honed Edge */
.su-icon--scout-edge {
  color: var(--track-color, #fb923c);
}
.su-scout-blade {
  animation: su-scout-blade-slice 1.5s ease-in-out infinite alternate;
}
.su-sb-2 { animation-delay: 0.15s; }
.su-scout-glint {
  transform-origin: center;
  animation: su-scout-glint-flare 1.5s ease-in-out infinite;
}
.su-blade-spark {
  animation: su-blade-spark-pop 1.5s ease-in-out infinite;
  transform-origin: center;
}
.su-bs-2 { animation-delay: 0.3s; }
@keyframes su-scout-blade-slice {
  0% { transform: scale(0.92) rotate(-3deg); }
  100% { transform: scale(1.08) rotate(3deg); filter: drop-shadow(0 0 4px currentColor); }
}
@keyframes su-scout-glint-flare {
  0%, 100% { transform: scale(0.4) rotate(0deg); opacity: 0.2; }
  50% { transform: scale(1.4) rotate(90deg); opacity: 1; filter: drop-shadow(0 0 6px #ffffff); }
}
@keyframes su-blade-spark-pop {
  0%, 100% { transform: scale(0.3); opacity: 0; }
  50% { transform: scale(1.2); opacity: 1; filter: drop-shadow(0 0 4px rgb(var(--c-gold))); }
}

/* 2. Bladework L2: Deep Laceration */
.su-icon--scout-laceration {
  color: var(--track-color, #fb923c);
}
.su-scout-slash {
  animation: su-scout-slash-pulse 1.4s ease-in-out infinite;
}
.su-sl-2 { animation-delay: 0.2s; }
.su-sl-3 { animation-delay: 0.4s; }
.su-scout-drop {
  animation: su-scout-drop-drip 1.4s ease-in infinite;
  transform-origin: center top;
}
.su-sd-2 { animation-delay: 0.45s; }
.su-sd-3 { animation-delay: 0.9s; }
@keyframes su-scout-slash-pulse {
  0%, 100% { opacity: 0.6; stroke-width: 2px; }
  50% { opacity: 1; stroke-width: 2.8px; filter: drop-shadow(0 0 5px currentColor); }
}
@keyframes su-scout-drop-drip {
  0% { transform: translateY(-4px) scale(0.6); opacity: 0; }
  40% { opacity: 1; transform: translateY(0px) scale(1.2); }
  100% { transform: translateY(6px) scale(0.4); opacity: 0; }
}

/* 3. Bladework L3: Marksman's Cache (Bow & Arrow) */
.su-icon--scout-bow {
  color: var(--track-color, #fb923c);
}
.su-scout-bow-limb {
  animation: su-scout-bow-flex 1.6s ease-in-out infinite;
}
.su-scout-string {
  animation: su-scout-string-pull 1.6s ease-in-out infinite;
}
.su-anim-scout-arrow {
  animation: su-scout-arrow-shoot 1.6s cubic-bezier(0.2, 0.9, 0.3, 1) infinite;
}
.su-scout-arrow-trail {
  animation: su-scout-trail-flash 1.6s ease-out infinite;
}
@keyframes su-scout-bow-flex {
  0%, 60% { transform: scaleX(1); }
  75% { transform: scaleX(0.85); filter: drop-shadow(0 0 4px currentColor); }
  85%, 100% { transform: scaleX(1); }
}
@keyframes su-scout-string-pull {
  0%, 60% { transform: translateX(0px); }
  75% { transform: translateX(-3px); }
  82%, 100% { transform: translateX(0px); }
}
@keyframes su-scout-arrow-shoot {
  0%, 60% { transform: translateX(0px); opacity: 0.8; }
  75% { transform: translateX(-4px); opacity: 1; }
  82% { transform: translateX(12px); opacity: 1; filter: drop-shadow(0 0 6px #ffffff); }
  90%, 100% { transform: translateX(0px); opacity: 0.8; }
}
@keyframes su-scout-trail-flash {
  0%, 78% { opacity: 0; stroke-dashoffset: 12; }
  84% { opacity: 1; stroke-dashoffset: 0; filter: drop-shadow(0 0 4px rgb(var(--c-gold))); }
  100% { opacity: 0; stroke-dashoffset: -12; }
}


/* 6. Velocity L3: Afterburn Reserve */
.su-icon--scout-afterburn {
  color: var(--track-color, #38bdf8);
}
.su-afterburn-pip {
  animation: su-afterburn-pip-charge 1.6s ease-in-out infinite alternate;
}
.su-abp-1, .su-abp-4 { animation-delay: 0s; }
.su-abp-2, .su-abp-5 { animation-delay: 0.4s; }
.su-abp-3, .su-abp-6 { animation-delay: 0.8s; }
.su-anim-afterburn-spark {
  animation: su-afterburn-spark-arc 1.2s ease-in-out infinite alternate;
}
@keyframes su-afterburn-pip-charge {
  0% { opacity: 0.3; }
  100% { opacity: 1; filter: drop-shadow(0 0 4px currentColor); }
}
@keyframes su-afterburn-spark-arc {
  0%, 100% { opacity: 0.2; stroke-dasharray: 2 6; }
  50% { opacity: 1; stroke-dasharray: 8 0; filter: drop-shadow(0 0 5px #ffffff); }
}


/* 9. Evasion L3: Phase Buffer */
.su-icon--scout-phase {
  color: var(--track-color, #e879f9);
}
.su-phase-sphere {
  animation: su-scout-phase-breathe 2.2s ease-in-out infinite alternate;
}
.su-phase-grid-h {
  transform-origin: center;
  animation: su-scout-phase-spin-h 4s linear infinite;
}
.su-phase-grid-v {
  transform-origin: center;
  animation: su-scout-phase-spin-v 4s linear infinite;
}
.su-phase-core {
  animation: su-scout-phase-core-flare 1.1s ease-in-out infinite alternate;
}
.su-phase-distortion {
  transform-origin: 0 0;
  animation: su-scout-phase-ripple 2s cubic-bezier(0.1, 0.8, 0.3, 1) infinite;
}
@keyframes su-scout-phase-breathe {
  0% { fill-opacity: 0.15; stroke-opacity: 0.6; }
  100% { fill-opacity: 0.45; stroke-opacity: 1; filter: drop-shadow(0 0 6px currentColor); }
}
@keyframes su-scout-phase-spin-h {
  0% { transform: rotate(0deg) scaleY(1); }
  50% { transform: rotate(180deg) scaleY(0.4); }
  100% { transform: rotate(360deg) scaleY(1); }
}
@keyframes su-scout-phase-spin-v {
  0% { transform: rotate(0deg) scaleX(1); }
  50% { transform: rotate(-180deg) scaleX(0.4); }
  100% { transform: rotate(-360deg) scaleX(1); }
}
@keyframes su-scout-phase-core-flare {
  0% { transform: scale(0.8); opacity: 0.7; }
  100% { transform: scale(1.35); opacity: 1; filter: drop-shadow(0 0 7px #ffffff); }
}
@keyframes su-scout-phase-ripple {
  0% { transform: scale(0.4); opacity: 0.9; stroke-width: 1.8; }
  75% { opacity: 0.3; stroke-width: 1; }
  100% { transform: scale(1.45); opacity: 0; stroke-width: 0.4; }
}

/* Owned State Overrides */
.su-node.owned .su-icon--soldier-actuators,
.su-node.owned .su-icon--soldier-mag,
.su-node.owned .su-icon--soldier-shotgun,
.su-node.owned .su-icon--soldier-plating,
.su-node.owned .su-icon--soldier-bulkhead,
.su-node.owned .su-icon--soldier-bulwark,
.su-node.owned .su-icon--soldier-supply,
.su-node.owned .su-icon--soldier-route,
.su-node.owned .su-icon--soldier-recon,
.su-node.owned .su-icon--guardian-spikes,
.su-node.owned .su-icon--guardian-kinetic-return,
.su-node.owned .su-icon--guardian-repulsor,
.su-node.owned .su-icon--guardian-layered-hull,
.su-node.owned .su-icon--guardian-ablative,
.su-node.owned .su-icon--guardian-overflow,
.su-node.owned .su-icon--guardian-forward-bias,
.su-node.owned .su-icon--guardian-mass,
.su-node.owned .su-icon--guardian-aegis,
.su-node.owned .su-icon--scout-edge,
.su-node.owned .su-icon--scout-laceration,
.su-node.owned .su-icon--scout-bow,
.su-node.owned .su-icon--scout-lightweight,
.su-node.owned .su-icon--scout-recovery,
.su-node.owned .su-icon--scout-afterburn,
/* ---- Occultist Bespoke Upgrade Node Icon Animations ------------------ */

/* 1. Hexcraft L1: Lingering Mark */
.su-icon--occult-mark {
  color: var(--track-color, #fb923c);
}
.su-anim-hex-eye {
  animation: su-occult-eye-pulse 2.2s ease-in-out infinite alternate;
}
.su-hex-pupil {
  transform-origin: center;
  animation: su-occult-pupil-glow 1.4s ease-in-out infinite alternate;
}
.su-anim-curse-runes {
  transform-origin: center;
  animation: su-icon-spin 7s linear infinite;
}
@keyframes su-occult-eye-pulse {
  0% { transform: scale(0.94); fill-opacity: 0.2; }
  100% { transform: scale(1.06); fill-opacity: 0.45; filter: drop-shadow(0 0 5px currentColor); }
}
@keyframes su-occult-pupil-glow {
  0% { transform: scale(0.75); opacity: 0.7; }
  100% { transform: scale(1.35); opacity: 1; filter: drop-shadow(0 0 6px rgb(var(--c-gold))); }
}

/* 2. Hexcraft L2: Deepened Curse */
.su-icon--occult-curse {
  color: var(--track-color, #fb923c);
}
.su-curse-star {
  transform-origin: center;
  animation: su-icon-spin 9s linear infinite;
}
.su-curse-core {
  animation: su-occult-curse-core 1.2s ease-in-out infinite alternate;
}
.su-curse-flame {
  animation: su-occult-flame-twinkle 1.5s ease-in-out infinite;
  transform-origin: center;
}
.su-cf-1 { animation-delay: 0s; }
.su-cf-2 { animation-delay: 0.3s; }
.su-cf-3 { animation-delay: 0.6s; }
.su-cf-4 { animation-delay: 0.9s; }
.su-cf-5 { animation-delay: 1.2s; }
@keyframes su-occult-curse-core {
  0% { transform: scale(0.7); opacity: 0.6; }
  100% { transform: scale(1.3); opacity: 1; filter: drop-shadow(0 0 7px rgb(var(--c-danger))); }
}
@keyframes su-occult-flame-twinkle {
  0%, 100% { transform: scale(0.4); opacity: 0.2; }
  50% { transform: scale(1.4); opacity: 1; filter: drop-shadow(0 0 5px rgb(var(--c-gold))); }
}

/* 3. Hexcraft L3: Occult Reserve (Chrono Aura) */
.su-icon--occult-chrono {
  color: var(--track-color, #fb923c);
}
.su-chrono-aura {
  transform-origin: center;
  animation: su-icon-spin 6s linear infinite;
}
.su-anim-chrono-hands {
  transform-origin: center;
  animation: su-icon-spin 2s linear infinite;
}
.su-chrono-nexus {
  animation: su-occult-nexus-glow 1.2s ease-in-out infinite alternate;
}
@keyframes su-occult-nexus-glow {
  0% { transform: scale(0.8); opacity: 0.7; }
  100% { transform: scale(1.4); opacity: 1; filter: drop-shadow(0 0 6px #ffffff); }
}

/* 4. Siphon L1: Vital Tether */
.su-icon--occult-tether {
  color: var(--track-color, #38bdf8);
}
.su-vital-heart {
  transform-origin: center;
  animation: su-occult-heart-beat 1.4s ease-in-out infinite;
}
.su-siphon-tendril {
  animation: su-occult-tendril-flow 1.4s ease-in-out infinite;
}
.su-st-2 { animation-delay: 0.7s; }
.su-soul-spark {
  animation: su-occult-soul-glow 1.4s ease-in-out infinite alternate;
  transform-origin: center;
}
.su-ss-2 { animation-delay: 0.7s; }
@keyframes su-occult-heart-beat {
  0%, 100% { transform: scale(0.9); }
  30% { transform: scale(1.2); filter: drop-shadow(0 0 6px currentColor); }
  50% { transform: scale(1.05); }
}
@keyframes su-occult-tendril-flow {
  0% { opacity: 0.3; stroke-dasharray: 2 12; }
  50% { opacity: 1; stroke-dasharray: 14 0; filter: drop-shadow(0 0 4px #67e8f9); }
  100% { opacity: 0.3; stroke-dasharray: 2 12; }
}
@keyframes su-occult-soul-glow {
  0% { transform: scale(0.7); opacity: 0.5; }
  100% { transform: scale(1.3); opacity: 1; filter: drop-shadow(0 0 5px #67e8f9); }
}

/* 5. Siphon L2: Reserve Shell */
.su-icon--occult-shell {
  color: var(--track-color, #38bdf8);
}
.su-shell-rib {
  animation: su-occult-rib-expand 2s ease-in-out infinite alternate;
}
.su-sr-1 { animation-delay: 0s; }
.su-sr-2 { animation-delay: 0.25s; }
.su-sr-3 { animation-delay: 0.5s; }
.su-sr-4 { animation-delay: 0.75s; }
.su-shell-core {
  animation: su-occult-shell-core-pulse 1.2s ease-in-out infinite alternate;
}
@keyframes su-occult-rib-expand {
  0% { transform: scaleX(0.92); opacity: 0.6; }
  100% { transform: scaleX(1.08); opacity: 1; filter: drop-shadow(0 0 4px currentColor); }
}
@keyframes su-occult-shell-core-pulse {
  0% { transform: scale(0.8); opacity: 0.6; }
  100% { transform: scale(1.3); opacity: 1; filter: drop-shadow(0 0 6px #67e8f9); }
}

/* 6. Siphon L3: Blood Reservoir */
.su-icon--occult-reservoir {
  color: var(--track-color, #38bdf8);
}
.su-chalice-bowl {
  animation: su-occult-chalice-glow 2.2s ease-in-out infinite alternate;
}
.su-blood-pool {
  animation: su-occult-blood-shimmer 1.6s ease-in-out infinite alternate;
}
.su-blood-orb {
  animation: su-occult-blood-orb-rise 1.8s ease-in-out infinite;
  transform-origin: center;
}
.su-bo-2 { animation-delay: 0.6s; }
.su-bo-3 { animation-delay: 1.2s; }
@keyframes su-occult-chalice-glow {
  0% { fill-opacity: 0.25; }
  100% { fill-opacity: 0.5; filter: drop-shadow(0 0 5px currentColor); }
}
@keyframes su-occult-blood-shimmer {
  0% { fill: rgb(var(--c-danger)); filter: none; }
  100% { fill: rgb(var(--c-rose)); filter: drop-shadow(0 0 4px rgb(var(--c-danger))); }
}
@keyframes su-occult-blood-orb-rise {
  0%, 100% { transform: translateY(0px) scale(0.8); opacity: 0.5; }
  50% { transform: translateY(-4px) scale(1.2); opacity: 1; filter: drop-shadow(0 0 5px currentColor); }
}


/* ---- Demolitionist Bespoke Upgrade Node Icon Animations ------------- */

/* 1. Detonation L1: Volatile Compound */
.su-icon--demo-compound {
  color: var(--track-color, #fb923c);
}
.su-compound-liquid {
  animation: su-demo-liquid-slosh 2s ease-in-out infinite alternate;
}
.su-compound-bubble {
  animation: su-demo-bubble-rise 1.5s ease-in infinite;
  transform-origin: center bottom;
}
.su-cb-2 { animation-delay: 0.5s; }
.su-cb-3 { animation-delay: 1s; }
@keyframes su-demo-liquid-slosh {
  0% { transform: rotate(-3deg) scaleY(0.95); }
  100% { transform: rotate(3deg) scaleY(1.05); filter: drop-shadow(0 0 5px rgb(var(--c-danger))); }
}
@keyframes su-demo-bubble-rise {
  0% { transform: translateY(4px) scale(0.5); opacity: 0; }
  50% { opacity: 1; }
  100% { transform: translateY(-5px) scale(1.2); opacity: 0; filter: drop-shadow(0 0 4px rgb(var(--c-gold))); }
}

/* 2. Detonation L2: Sustained Burn */
.su-icon--demo-burn {
  color: var(--track-color, #fb923c);
}
.su-burn-flame-outer {
  animation: su-demo-flame-roared 1.4s ease-in-out infinite alternate;
}
.su-burn-flame-inner {
  animation: su-demo-flame-core 0.9s ease-in-out infinite alternate;
}
.su-burn-ember {
  animation: su-demo-ember-float 1.6s ease-out infinite;
}
.su-be-2 { animation-delay: 0.55s; }
.su-be-3 { animation-delay: 1.1s; }
@keyframes su-demo-flame-roared {
  0% { transform: scaleX(0.92) scaleY(0.96); filter: drop-shadow(0 0 4px currentColor); }
  100% { transform: scaleX(1.08) scaleY(1.04); filter: drop-shadow(0 0 8px rgb(var(--c-danger))); }
}
@keyframes su-demo-flame-core {
  0% { transform: scale(0.85); opacity: 0.8; }
  100% { transform: scale(1.2); opacity: 1; filter: drop-shadow(0 0 6px #ffffff); }
}
@keyframes su-demo-ember-float {
  0% { transform: translateY(4px) scale(0.6); opacity: 0; }
  40% { opacity: 1; }
  100% { transform: translateY(-6px) scale(1.3); opacity: 0; filter: drop-shadow(0 0 5px rgb(var(--c-gold))); }
}

/* 3. Detonation L3: Ordnance Cache */
.su-icon--demo-ordnance {
  color: var(--track-color, #fb923c);
}
.su-anim-demo-bomb {
  animation: su-demo-bomb-fall 1.8s ease-in-out infinite alternate;
}
.su-anim-demo-cluster {
  animation: su-demo-cluster-eject 1.8s ease-in-out infinite alternate;
}
.su-dc-2 { animation-delay: 0.3s; }
@keyframes su-demo-bomb-fall {
  0% { transform: translateY(-2px); }
  100% { transform: translateY(2px); filter: drop-shadow(0 0 6px currentColor); }
}
@keyframes su-demo-cluster-eject {
  0% { transform: scale(0.7) translate(0px, 0px); opacity: 0.5; }
  100% { transform: scale(1.15) translate(0px, 1px); opacity: 1; filter: drop-shadow(0 0 5px rgb(var(--c-danger))); }
}


.su-demo-armed-led {
  animation: su-demo-led-blink 0.6s steps(1) infinite;
}
@keyframes su-demo-led-blink {
  0%, 100% { fill: rgb(var(--c-danger)); filter: drop-shadow(0 0 6px rgb(var(--c-danger))); }
  50% { fill: #334155; filter: none; }
}

/* 6. Payload L3: Blast Radius Overcharge */
.su-icon--demo-overcharge {
  color: var(--track-color, #38bdf8);
}
.su-anim-mushroom-cap {
  animation: su-demo-cloud-billow 2.2s ease-in-out infinite alternate;
}
.su-mushroom-base {
  animation: su-demo-base-flash 1.5s ease-in-out infinite alternate;
}
.su-anim-mushroom-ring {
  transform-origin: 0px 1px;
  animation: su-demo-atomic-ring 2s ease-out infinite;
}
.su-mushroom-core {
  animation: su-demo-core-flare 1.1s ease-in-out infinite alternate;
}
@keyframes su-demo-cloud-billow {
  0% { transform: scale(0.94) translateY(1px); }
  100% { transform: scale(1.06) translateY(-2px); filter: drop-shadow(0 0 8px currentColor); }
}
@keyframes su-demo-base-flash {
  0% { opacity: 0.5; stroke-width: 1.4px; }
  100% { opacity: 1; stroke-width: 2.2px; filter: drop-shadow(0 0 6px rgb(var(--c-danger))); }
}
@keyframes su-demo-atomic-ring {
  0% { transform: scale(0.4); opacity: 0.9; stroke-width: 2px; }
  75% { opacity: 0.4; stroke-width: 1.2px; }
  100% { transform: scale(1.5); opacity: 0; stroke-width: 0.4px; }
}
@keyframes su-demo-core-flare {
  0% { transform: scale(0.75); opacity: 0.7; }
  100% { transform: scale(1.35); opacity: 1; filter: drop-shadow(0 0 7px #ffffff); }
}

/* 7. Munitions L1: Requisitioned Crates */
.su-icon--demo-crates {
  color: var(--track-color, #e879f9);
}
.su-anim-crate-coins {
  animation: su-demo-coins-float 1.8s ease-in-out infinite alternate;
}
.su-crate-coin {
  animation: su-demo-coin-twinkle 1.4s ease-in-out infinite;
}
.su-cc-2 { animation-delay: 0.45s; }
.su-cc-3 { animation-delay: 0.9s; }
@keyframes su-demo-coins-float {
  0% { transform: translateY(1px); }
  100% { transform: translateY(-3px); filter: drop-shadow(0 0 5px rgb(var(--c-gold))); }
}
@keyframes su-demo-coin-twinkle {
  0%, 100% { transform: scale(0.85); opacity: 0.7; }
  50% { transform: scale(1.2); opacity: 1; filter: drop-shadow(0 0 5px #ffffff); }
}


/* Owned State Overrides */
.su-node.owned .su-icon--soldier-actuators,
.su-node.owned .su-icon--soldier-mag,
.su-node.owned .su-icon--soldier-shotgun,
.su-node.owned .su-icon--soldier-plating,
.su-node.owned .su-icon--soldier-bulkhead,
.su-node.owned .su-icon--soldier-bulwark,
.su-node.owned .su-icon--soldier-supply,
.su-node.owned .su-icon--soldier-route,
.su-node.owned .su-icon--soldier-recon,
.su-node.owned .su-icon--guardian-spikes,
.su-node.owned .su-icon--guardian-kinetic-return,
.su-node.owned .su-icon--guardian-repulsor,
.su-node.owned .su-icon--guardian-layered-hull,
.su-node.owned .su-icon--guardian-ablative,
.su-node.owned .su-icon--guardian-overflow,
.su-node.owned .su-icon--guardian-forward-bias,
.su-node.owned .su-icon--guardian-mass,
.su-node.owned .su-icon--guardian-aegis,
.su-node.owned .su-icon--scout-edge,
.su-node.owned .su-icon--scout-laceration,
.su-node.owned .su-icon--scout-bow,
.su-node.owned .su-icon--scout-lightweight,
.su-node.owned .su-icon--scout-recovery,
.su-node.owned .su-icon--scout-afterburn,
.su-node.owned .su-icon--scout-deflect,
.su-node.owned .su-icon--scout-slipstream,
.su-node.owned .su-icon--scout-phase,
.su-node.owned .su-icon--occult-mark,
.su-node.owned .su-icon--occult-curse,
.su-node.owned .su-icon--occult-chrono,
.su-node.owned .su-icon--occult-tether,
.su-node.owned .su-icon--occult-shell,
.su-node.owned .su-icon--occult-reservoir,
.su-node.owned .su-icon--occult-offering,
.su-node.owned .su-icon--occult-portal,
.su-node.owned .su-icon--occult-grimoire,
.su-node.owned .su-icon--demo-compound,
.su-node.owned .su-icon--demo-burn,
.su-node.owned .su-icon--demo-ordnance,
.su-node.owned .su-icon--demo-casing,
.su-node.owned .su-icon--demo-fill,
.su-node.owned .su-icon--demo-overcharge,
.su-node.owned .su-icon--demo-crates,
.su-node.owned .su-icon--demo-order,
.su-node.owned .su-icon--demo-contract,
.su-node.owned .su-icon--cheese-extra-sharp,
.su-node.owned .su-icon--cheese-raclette,
.su-node.owned .su-icon--cheese-alone,
.su-node.owned .su-icon--cheese-swiss,
.su-node.owned .su-icon--cheese-wax,
.su-node.owned .su-icon--cheese-aged,
.su-node.owned .su-icon--cheese-liquid,
.su-node.owned .su-icon--cheese-curds,
.su-node.owned .su-icon--cheese-meltdown {
  color: rgb(var(--c-mint));
}
.su-node.owned .su-hex-plate,
.su-node.owned .su-bulwark-shield,
.su-node.owned .su-aegis-shield,
.su-node.owned .su-hull-plate,
.su-node.owned .su-ablative-tile,
.su-node.owned .su-scout-blade,
.su-node.owned .su-scout-frame,
.su-node.owned .su-scout-ship-prime,
.su-node.owned .su-phase-sphere,
.su-node.owned .su-anim-hex-eye,
.su-node.owned .su-curse-star,
.su-node.owned .su-vital-heart,
.su-node.owned .su-chalice-bowl,
.su-node.owned .su-grimoire-page,
.su-node.owned .su-burn-flame-outer,
.su-node.owned .su-anim-mushroom-cap,
.su-node.owned .su-contract-pad {
  fill: rgba(var(--c-mint), 0.25);
}
.su-node.owned .su-anim-radar-cone path {
  fill: rgba(var(--c-mint), 0.25);
}
.su-node.owned .su-anim-supply-pod rect:first-child {
  fill: rgba(var(--c-mint), 0.25);
}

/* Root Node Row */
.su-root-row {
  position: relative;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 8px;
  padding-top: 4px;
  flex-shrink: 0;
}

.su-root {
  position: relative;
  width: 155px;
  height: 58px;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 12px;
  padding: 6px 14px;
  border-radius: 18px;
  background: rgba(22, 16, 38, 0.98);
  border: 1.5px solid rgba(var(--c-primary), 0.4);
  cursor: pointer;
  outline: none;
  box-sizing: border-box;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
  transition: all 0.18s ease;
}

.su-root__icon-wrap {
  width: 38px;
  height: 38px;
  flex-shrink: 0;
}

.su-root__icon {
  width: 100%;
  height: 100%;
  display: block;
}

.su-root__info {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
}

.su-root__name {
  font-size: 0.7rem;
  font-weight: 800;
  color: #fff;
  letter-spacing: 0.04em;
}

.su-root__rank {
  font-size: 0.72rem;
  font-weight: 800;
  color: rgb(var(--c-violet));
  font-family: var(--font-display);
}

.su-root.maxed .su-root__rank {
  color: rgb(var(--c-success));
}

:where(body:not(.gamepad-active)) .su-root:hover,
.su-root.selected {
  border-color: rgb(var(--c-gold)) !important;
  box-shadow: 0 0 0 2px rgba(var(--c-gold), 0.5), 0 0 18px rgba(var(--c-gold), 0.4);
}

.su-root.controller-focused,
.su-root.controller-focused.selected,
#survivor-upgrades-screen .su-root.controller-focused {
  border-color: rgb(var(--c-focus)) !important;
  outline: 3px solid rgb(var(--c-focus)) !important;
  outline-offset: 2px !important;
  box-shadow: 0 0 0 2px rgba(var(--c-focus), 0.6), 0 0 20px rgba(var(--c-focus), 0.85) !important;
  z-index: 10 !important;
  transform: none !important;
}

/* Docked Inspector Panel */
.su-detail-panel {
  position: relative;
  width: 100%;
  height: 100%;
  background: rgba(14, 10, 26, 0.92);
  border: 1.5px solid rgba(var(--c-primary), 0.35);
  padding: 16px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5), inset 0 0 16px rgba(var(--c-primary), 0.05);
}

.su-detail-card-inner {
  display: flex;
  flex-direction: column;
  height: 100%;
  justify-content: space-between;
  gap: 10px;
}

.su-detail-header {
  display: flex;
  align-items: center;
  gap: 12px;
}

.su-detail-icon-wrap {
  width: 44px;
  height: 44px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(var(--c-primary), 0.3);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  padding: 4px;
  box-sizing: border-box;
}

.su-detail-header-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.su-detail-tier-badge {
  font-size: 0.62rem;
  font-weight: 800;
  font-family: var(--font-display);
  letter-spacing: 0.05em;
  color: rgb(var(--c-violet));
}

.su-detail-panel h3 {
  margin: 0;
  font-size: 1.05rem;
  letter-spacing: 0.03em;
  color: #fff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.su-detail-divider {
  width: 100%;
  height: 1px;
  background: rgba(255, 255, 255, 0.08);
}

.su-detail-effect {
  margin: 0;
  font-size: 0.9rem;
  font-weight: bold;
  color: rgb(var(--c-sky));
  line-height: 1.3;
  padding: 8px 10px;
  border-radius: 8px;
  background: rgba(var(--c-sky), 0.08);
  border: 1px solid rgba(var(--c-sky), 0.25);
}

.su-detail-desc {
  margin: 0;
  font-size: 0.78rem;
  line-height: 1.4;
  color: rgba(255, 255, 255, 0.7);
  flex-grow: 1;
  overflow-y: auto;
}

.su-detail-status-box {
  display: none;
  padding: 6px 10px;
  border-radius: 8px;
  background: rgba(var(--c-gold), 0.1);
  border: 1px solid rgba(var(--c-gold), 0.3);
}

.su-detail-status {
  font-size: 0.72rem;
  font-weight: 700;
  color: rgb(var(--c-gold));
}

.su-detail-actions {
  margin-top: 4px;
}

.su-detail-buy-btn {
  width: 100%;
  padding: 10px 0;
  font-size: 0.88rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  cursor: pointer;
}

/* .su-detail-buy-btn:disabled (opacity .45 + grayscale) removed: the disabled look is the kit's
   hazard stripe, css/03b-chamfer-kit.css section 12. */

/* Footer Buttons */
.su-foot {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  flex-shrink: 0;
  padding-top: 4px;
}

.su-respec {
  /* red tint + red border comes from .btn-danger, which index.html now puts on this button */
  padding: 8px 24px;
  font-size: 0.85rem;
  font-weight: bold;
}

.su-back-btn {
  padding: 8px 32px;
  font-size: 0.85rem;
  font-weight: bold;
}

/* Responsive Breakpoints: Short Viewports & Mobile Landscape */
@media (max-height: 600px) {
  .glass-panel.su-frame {
    width: calc(98 * var(--vvw)) !important;
    max-width: 1100px !important;
    height: calc(96 * var(--vvh)) !important;
    max-height: calc(96 * var(--vvh)) !important;
    padding: 8px 12px !important;
    gap: 6px !important;
  }


  .su-balance {
    font-size: 0.8rem !important;
  }

  .su-track-tabs {
    display: none !important;
  }

  .su-content-layout {
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) !important;
    gap: 8px !important;
    min-height: 0 !important;
    flex: 1 1 auto !important;
  }

  .su-tree-column {
    min-height: 0 !important;
    display: flex !important;
    flex-direction: column !important;
  }

  .su-body {
    padding: 6px 8px !important;
    min-height: 0 !important;
  }

  .su-tracks-grid {
    display: grid !important;
    grid-template-columns: repeat(3, 1fr) !important;
    gap: 6px !important;
    padding: 0 32px !important;
    margin-bottom: 2px !important;
  }

  .su-track-col {
    gap: 6px !important;
  }

  .su-track-col-header {
    font-size: 0.64rem !important;
    margin-bottom: 0 !important;
  }

  .su-node {
    max-width: 66px !important;
    padding: 3px 2px !important;
    border-radius: 10px !important;
  }

  .su-node__layer-badge {
    font-size: 0.48rem !important;
    top: 2px !important;
    left: 4px !important;
  }

  .su-node__icon-wrap {
    width: 36% !important;
  }

  .su-node__name {
    font-size: 0.54rem !important;
    line-height: 1.05 !important;
  }

  .su-node__cost {
    font-size: 0.56rem !important;
  }

  .su-node__pts-label {
    font-size: 0.48rem !important;
  }

  .su-node__owned-check {
    font-size: 0.75rem !important;
  }

  .su-root-row {
    margin-top: 2px !important;
    padding-top: 2px !important;
    gap: 8px !important;
  }

  .su-root {
    width: 120px !important;
    height: 40px !important;
    padding: 3px 8px !important;
    border-radius: 10px !important;
    gap: 6px !important;
  }

  .su-root__icon-wrap {
    width: 26px !important;
    height: 26px !important;
  }

  .su-root__name {
    font-size: 0.58rem !important;
  }

  .su-root__rank {
    font-size: 0.6rem !important;
  }

  .su-threshold-tag {
    font-size: 0.5rem !important;
    padding: 1px 5px !important;
  }

  .su-threshold-status {
    font-size: 0.46rem !important;
    padding: 1px 4px !important;
  }

  .su-detail-panel {
    padding: 8px 10px !important;
    height: 100% !important;
    max-height: none !important;
  }

  .su-detail-header {
    gap: 8px !important;
  }

  .su-detail-icon-wrap {
    width: 32px !important;
    height: 32px !important;
    padding: 2px !important;
  }

  .su-detail-tier-badge {
    font-size: 0.52rem !important;
  }

  .su-detail-panel h3 {
    font-size: 0.84rem !important;
  }

  .su-detail-effect {
    font-size: 0.74rem !important;
    padding: 4px 8px !important;
    border-radius: 6px !important;
  }

  .su-detail-desc {
    font-size: 0.65rem !important;
    line-height: 1.25 !important;
  }

  .su-detail-status-box {
    padding: 3px 6px !important;
    border-radius: 6px !important;
  }

  .su-detail-status {
    font-size: 0.6rem !important;
  }

  .su-detail-buy-btn {
    padding: 6px 0 !important;
    font-size: 0.76rem !important;
  }

  .su-foot {
    padding-top: 2px !important;
    gap: 10px !important;
  }

  .su-respec {
    padding: 5px 16px !important;
    font-size: 0.72rem !important;
  }

  .su-back-btn {
    padding: 5px 24px !important;
    font-size: 0.72rem !important;
  }
}

.is-mobile .su-frame {
  width: calc(98 * var(--vvw)) !important;
  max-width: 1100px !important;
  height: calc(96 * var(--vvh)) !important;
  max-height: calc(96 * var(--vvh)) !important;
  padding: 8px 12px !important;
  gap: 6px !important;
}

.is-mobile .su-content-layout {
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) !important;
  gap: 8px !important;
}

.is-mobile .su-track-tabs {
  display: none !important;
}

.is-mobile .su-tracks-grid {
  grid-template-columns: repeat(3, 1fr) !important;
  padding: 0 32px !important;
  gap: 6px !important;
}

.is-mobile .su-node {
  max-width: 66px !important;
  padding: 3px 2px !important;
  border-radius: 10px !important;
}


.is-mobile .su-detail-panel {
  height: 100% !important;
  max-height: none !important;
  padding: 8px 10px !important;
}

.is-mobile #character-select-screen .glass-panel.wide-panel,
.is-mobile #difficulty-select-screen .glass-panel.wide-panel {
  padding: 8px 14px !important;
  gap: 4px !important;
  max-height: calc(96 * var(--vvh)) !important;
}

.is-mobile #character-select-header,
.is-mobile #difficulty-select-header {
  padding-bottom: 4px !important;
  gap: 8px !important;
}

.is-mobile #character-select-header h2,
.is-mobile #difficulty-select-header h2 {
  font-size: 1.05rem !important;
}

.is-mobile #character-select-progress,
.is-mobile #difficulty-select-survivor {
  font-size: 0.72rem !important;
}

/* Responsive & Mobile Landscape Adapters for Character Select Stage */
@media (max-height: 650px), (max-width: 900px) {
  #character-select-screen .character-select-stage-frame {
    max-height: calc(98 * var(--vvh)) !important;
    width: calc(98 * var(--vvw)) !important;
    padding: 6px 10px !important;
    gap: 4px !important;
  }

  #character-select-header {
    padding-bottom: 3px !important;
  }

  .char-select-title {
    font-size: 1.05rem !important;
  }

  .char-select-progress-badge {
    font-size: 0.68rem !important;
    padding: 2px 7px !important;
  }

  #character-select-back-btn,
  .char-select-back-btn {
    padding: 3px 14px !important;
    font-size: 0.75rem !important;
  }

  .char-hero-stage {
    gap: 8px !important;
    flex: 1 1 auto !important;
    min-height: 0 !important;
  }

  .char-hero-canvas-wrap {
    flex: 0 0 25% !important;
    width: 25% !important;
    max-width: 25% !important;
    min-width: 0 !important;
    height: 100% !important;
    max-height: 190px !important;
  }

  .char-hero-holo-ring {
    width: 120px !important;
    height: 120px !important;
  }

  .char-hero-details {
    padding: 6px 10px !important;
    gap: 3px !important;
  }

  .char-hero-identity {
    min-height: auto !important;
    gap: 1px !important;
  }

  .char-hero-name {
    font-size: 1.15rem !important;
  }

  .char-hero-archetype-pill {
    font-size: 0.58rem !important;
    padding: 1px 6px !important;
  }

  .char-hero-desc {
    font-size: 0.65rem !important;
    line-height: 1.2em !important;
    min-height: 2.4em !important;
    max-height: 2.4em !important;
  }

  .char-hero-stat-meters {
    padding: 3px 8px !important;
    gap: 2px !important;
  }

  .char-stat-meter-row {
    gap: 1px !important;
  }

  .char-stat-label-wrap {
    font-size: 0.58rem !important;
  }

  .char-stat-val {
    font-size: 0.62rem !important;
  }

  .char-stat-bar-track {
    height: 3.5px !important;
  }

  .char-hero-weapon-card {
    padding: 4px 8px !important;
    min-height: auto !important;
    gap: 3px !important;
  }

  .char-weapon-sub {
    font-size: 0.58rem !important;
  }

  .char-weapon-tags {
    gap: 4px !important;
  }

  .weapon-tag-pill {
    font-size: 0.52rem !important;
    padding: 1px 5px !important;
    letter-spacing: 0.04em !important;
  }

  .char-weapon-body {
    gap: 8px !important;
  }

  .char-weapon-icon-frame {
    width: 36px !important;
    height: 36px !important;
    border-radius: 6px !important;
  }

  .char-weapon-icon-frame::before,
  .char-weapon-icon-frame::after {
    width: 4px !important;
    height: 4px !important;
  }

  .char-weapon-icon {
    width: 30px !important;
    height: 30px !important;
  }

  .char-weapon-name {
    font-size: 0.78rem !important;
  }

  .char-weapon-desc {
    font-size: 0.58rem !important;
    line-height: 1.15em !important;
    min-height: 2.3em !important;
    max-height: 2.3em !important;
  }

  .char-hero-actions {
    gap: 6px !important;
    margin-top: 0 !important;
  }

  .char-deploy-btn {
    padding: 4px 10px !important;
    font-size: 0.76rem !important;
  }

  .char-tree-btn {
    padding: 4px 8px !important;
    font-size: 0.72rem !important;
  }

  .char-roster-dock, #character-select-grid {
    grid-template-columns: repeat(var(--roster-cols, 5), minmax(0, 1fr)) !important;
    gap: 4px !important;
    padding: 2px 0 !important;
  }

  .char-roster-card {
    min-width: 0 !important;
    max-width: 130px !important;
    padding: 3px 4px !important;
    gap: 1px !important;
  }

  .char-roster-card .survivor-card__portrait {
    width: 22px !important;
    height: 22px !important;
  }

  .char-roster-card .survivor-card__name {
    font-size: 0.68rem !important;
  }

  .char-roster-card .survivor-card__archetype {
    font-size: 0.52rem !important;
  }

  .char-roster-card .char-card-points-badge {
    top: 2px !important;
    right: 2px !important;
    min-width: 12px !important;
    height: 12px !important;
    font-size: 0.5rem !important;
    padding: 0 2px !important;
  }
}

.is-mobile #character-select-screen .character-select-stage-frame {
  max-height: calc(98 * var(--vvh)) !important;
  width: calc(98 * var(--vvw)) !important;
  padding: 6px 10px !important;
  gap: 4px !important;
}

.is-mobile .char-hero-stage {
  gap: 8px !important;
  flex: 1 1 auto !important;
  min-height: 0 !important;
}

.is-mobile .char-hero-canvas-wrap {
    flex: 0 0 25% !important;
    width: 25% !important;
    max-width: 25% !important;
    min-width: 0 !important;
    height: 100% !important;
    max-height: 190px !important;
}

.is-mobile .char-hero-details {
  padding: 6px 10px !important;
  gap: 3px !important;
}

.is-mobile .char-hero-name {
  font-size: 1.15rem !important;
}

.is-mobile .char-hero-desc {
  font-size: 0.65rem !important;
  line-height: 1.2em !important;
  min-height: 2.4em !important;
  max-height: 2.4em !important;
}

.is-mobile .char-hero-stat-meters {
  padding: 3px 8px !important;
  gap: 2px !important;
}

.is-mobile .char-hero-weapon-card {
  padding: 4px 8px !important;
  min-height: auto !important;
  gap: 3px !important;
}

.is-mobile .char-weapon-icon-frame {
  width: 36px !important;
  height: 36px !important;
  border-radius: 6px !important;
}

.is-mobile .char-weapon-icon {
  width: 30px !important;
  height: 30px !important;
}

.is-mobile .char-deploy-btn {
  padding: 4px 10px !important;
  font-size: 0.76rem !important;
}

.is-mobile .char-tree-btn {
  padding: 4px 8px !important;
  font-size: 0.72rem !important;
}

.is-mobile .char-roster-card {
  min-width: 90px !important;
  max-width: 130px !important;
  padding: 3px 5px !important;
  gap: 1px !important;
}

.is-mobile #difficulty-select-grid {
  padding: 6px 4px 6px !important;
  gap: 8px !important;
}

.is-mobile #character-select-back-btn,
.is-mobile #difficulty-select-back-btn {
  padding: 3px 14px !important;
  font-size: 0.75rem !important;
}


/* Universal Gamepad Controller Button Underlay & High Contrast Styling */
.control-hint-icon,
.control-hint-icon-img,
.btn-controller-glyph,
.pad-icon-x,
.pad-icon-b,
.char-deploy-pad-icon,
.char-tree-pad-icon,
.char-back-pad-icon,
.survivor-card__upgrades-padicon,
.start-music-pad-icon,
.pause-music-pad-icon,
.changelog-close-pad-icon,
.start-whats-new-pad-icon,
.weapon-tree-bumper-icon,
.shop-next-btn-menu-icon,
.su-detail-buy-padicon,
.su-foot-padicon,
.su-root-padicon,
.legend-item img {
  background: #000000 !important;
  border-radius: 50% !important;
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.95), 0 2px 4px rgba(0, 0, 0, 0.8) !important;
}

.weapon-tree-bumper-icon,
.su-foot-padicon[src*="lb"],
.su-foot-padicon[src*="rb"],
.su-foot-padicon[src*="lt"],
.su-foot-padicon[src*="rt"],
img[src*="lb.svg"],
img[src*="rb.svg"],
img[src*="lt.svg"],
img[src*="rt.svg"] {
  border-radius: 4px !important;
}

/* ===========================================================
   Survivor colour theme + upgrade effects
   (js/survivor-tree-ui.js: applySurvivorTreeTheme, SurvivorTreeFx;
   chosen from Claude outputs/survivor-tree-polish.html)
   =========================================================== */

/* The window takes the survivor's colour, but Buy stays green: green means
   "yours / go" everywhere else, and Occultist red would read as a delete. */
#survivor-upgrades-screen #su-detail-buy-btn {
  --acc: var(--c-success);
}

/* Effects layer: inside .su-tree-column, outside the #survivor-upgrades-body
   that render() rebuilds, so an effect outlives the redraw it follows. */
.su-fx-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 20;
  overflow: hidden;
}

.su-fx-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.su-fx-banner {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.2em;
  color: #0b0813;
  background: linear-gradient(90deg, transparent, rgb(var(--c-primary)) 20%, #fff 50%, rgb(var(--c-primary)) 80%, transparent);
  opacity: 0;
}

.su-fx-banner.go {
  animation: su-fx-banner 1.6s ease-out;
}

@keyframes su-fx-banner {
  0%   { opacity: 0; transform: scaleX(0.1); }
  20%  { opacity: 1; transform: scaleX(1); }
  80%  { opacity: 1; }
  100% { opacity: 0; transform: scaleX(1.05); }
}

/* Ignite Burst: the bought node / Power Core flashes, pops and settles. */
.su-node.su-fx-ignite,
.su-root.su-fx-ignite {
  animation: su-fx-pop 0.55s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}

@keyframes su-fx-pop {
  0%   { transform: scale(1); filter: brightness(1); }
  25%  { transform: scale(1.16); filter: brightness(2.6); }
  60%  { transform: scale(0.97); filter: brightness(1.2); }
  100% { transform: scale(1); filter: brightness(1); }
}

.su-node.su-fx-ignite .su-node__owned-check {
  display: inline-block;
  animation: su-fx-check 0.5s 0.12s cubic-bezier(0.2, 0.9, 0.3, 1.3) backwards;
}

@keyframes su-fx-check {
  0%   { transform: scale(0) rotate(-20deg); }
  60%  { transform: scale(1.5) rotate(6deg); }
  100% { transform: scale(1) rotate(0); }
}

.su-root.su-fx-ignite .su-root__rank {
  display: inline-block;
  animation: su-fx-tick 0.45s ease-out;
}

@keyframes su-fx-tick {
  0%   { transform: none; }
  30%  { transform: translateY(-5px) scale(1.25); color: #fff; }
  100% { transform: none; }
}

/* Tier unlock (root ranks 5 / 10 / 15): the line flares, the opened row lights up in turn. */
.su-threshold-line.su-fx-flare {
  animation: su-fx-flare 1s ease-out;
}

@keyframes su-fx-flare {
  0%   { box-shadow: 0 0 0 transparent; }
  30%  { box-shadow: 0 0 14px 2px rgb(var(--c-primary)); }
  100% { box-shadow: 0 0 12px rgba(var(--c-primary), 0.25); }
}

.su-node.su-fx-tier {
  animation: su-fx-tier 0.8s ease-out;
}

@keyframes su-fx-tier {
  0%   { box-shadow: none; }
  35%  { box-shadow: 0 0 22px rgba(var(--c-primary), 0.95), inset 0 0 12px rgba(var(--c-primary), 0.5); border-color: rgb(var(--c-primary)); }
  100% { box-shadow: none; }
}
/* ===================================================================
   Benchmark results panel (index.html #benchmark-results-screen,
   populated by showBenchmarkResults() in js/benchmark.js)
   ===================================================================
   The panel started as four numbers and grew, through the Phase 0
   performance instrumentation, to around twenty -- long enough that a
   single column no longer fit on screen without scrolling and no longer
   read well when it did. .bench-grid lays the rows out in as many
   columns as the panel width allows (two on desktop, one on a phone or a
   narrow window) with no media query needed. Rows whose value is long
   free text -- the GPU string, the blur hotspot list -- opt out with
   .bench-row-wide and take the full width instead of being squeezed into
   half of it. */
.bench-card {
  width: 100%;
  box-sizing: border-box;
  text-align: left;
  padding: 12px 14px;
  background: rgba(8, 6, 15, 0.7);
  border-radius: 8px;
  border: 1.5px solid rgba(255, 255, 255, 0.08);
  margin: 0 0 10px;
  font-size: 0.88rem;
  line-height: 1.55;
}
.bench-card:first-of-type {
  margin-top: 12px;
}
.bench-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  column-gap: 24px;
  row-gap: 1px;
}
.bench-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  min-width: 0;
}
.bench-row-wide {
  grid-column: 1 / -1;
}
.bench-val {
  font-weight: bold;
  color: #cbd5e1;
  text-align: right;
  word-break: break-word;
  min-width: 0;
}
.bench-sep {
  grid-column: 1 / -1;
  border-top: 1px dashed rgba(255, 255, 255, 0.1);
  margin: 7px 0 5px;
}
.bench-section-label {
  font-size: 0.78rem;
  color: rgba(255, 255, 255, 0.6);
  margin-bottom: 4px;
}

/* #benchmark-results-copy-btn / -close-btn .controller-focused (glow + scale) removed: they are
   chamfer .btn buttons now and take the kit focus variant (css/03b-chamfer-kit.css section 4). */

/* ============================================================
   ROUND MODIFIER / WAGER SELECTION
   (#round-modifier-screen -- js/round-modifier-ui.js)
   ============================================================
   Two rules held to throughout:
     1. Animate transform and opacity only. Nothing here forces layout or
        repaints a blur per frame.
     2. Rarity is expressed entirely through the two custom properties
        --rm-color / --rm-glow, set inline per card by the renderer. Adding a
        rarity is a MODIFIER_RARITY edit in js/round-modifier-config.js with
        no stylesheet change at all.
   color-mix() is deliberately NOT used (the Android WebView floor is older
   than the Electron one); the rarity wash is a tinted ::before instead. */

#round-modifier-screen .glass-panel,
#round-modifier-screen .glass-panel.wide-panel,
.round-modifier-panel {
  width: min(980px, calc(93 * var(--vvw))) !important;
  max-width: calc(93 * var(--vvw)) !important;
  max-height: calc(90 * var(--vvh));
  display: flex;
  flex-direction: column;
  padding: calc(14px * var(--ui-global-scale, 1)) calc(22px * var(--ui-global-scale, 1));
  box-sizing: border-box;
}

.round-modifier-header {
  position: relative;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  padding: 0 44px;
  box-sizing: border-box;
}

.round-modifier-emblem-wrap {
  position: absolute;
  left: 4px;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
}

.round-modifier-emblem-glow {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(var(--c-violet), 0.6) 0%, rgba(var(--c-primary), 0.2) 60%, transparent 80%);
  filter: blur(6px);
  animation: wagerGlowPulse 3s ease-in-out infinite alternate;
  pointer-events: none;
}

.round-modifier-emblem-svg {
  width: 36px;
  height: 36px;
  filter: drop-shadow(0 0 8px rgba(var(--c-violet), 0.7));
  z-index: 1;
}

.round-modifier-header-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 2px;
}

.round-modifier-header-center h2 {
  margin: 0;
  font-size: calc(1.35rem * var(--ui-global-scale, 1));
  line-height: 1.15;
  letter-spacing: 0.04em;
}

.round-modifier-header-center p {
  margin: 0;
  font-size: calc(0.82rem * var(--ui-global-scale, 1));
  line-height: 1.25;
  color: rgba(226, 232, 240, 0.85);
}

.wager-anomaly-banner {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  margin-bottom: 4px;
  border-radius: 999px;
  background: rgba(var(--c-primary), 0.15);
  border: 1px solid rgba(var(--c-violet), 0.45);
  box-shadow: 0 0 10px rgba(var(--c-primary), 0.35);
  color: #f3e8ff;
  font-size: calc(0.68rem * var(--ui-global-scale, 1));
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  animation: wagerAnomalyPulse 2.4s ease-in-out infinite alternate;
}

.wager-anomaly-banner .wager-anomaly-icon {
  width: calc(12px * var(--ui-global-scale, 1));
  height: calc(12px * var(--ui-global-scale, 1));
  stroke: rgb(var(--c-violet));
}

#round-modifier-screen.chaos .wager-anomaly-banner {
  background: rgba(var(--c-danger), 0.2);
  border-color: rgba(248, 113, 113, 0.5);
  box-shadow: 0 0 12px rgba(var(--c-danger), 0.4);
  color: #fee2e2;
}

#round-modifier-screen.chaos .wager-anomaly-banner .wager-anomaly-icon {
  stroke: #f87171;
}

@keyframes wagerAnomalyPulse {
  0% {
    transform: scale(0.98);
    box-shadow: 0 0 6px rgba(var(--c-primary), 0.25);
  }
  100% {
    transform: scale(1.02);
    box-shadow: 0 0 14px rgba(var(--c-primary), 0.5);
  }
}

@keyframes wagerGlowPulse {
  0% { transform: scale(0.9); opacity: 0.6; }
  100% { transform: scale(1.15); opacity: 1; }
}

.round-modifier-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: calc(14px * var(--ui-global-scale, 1));
  margin-top: calc(12px * var(--ui-global-scale, 1));
  align-items: stretch;
  flex: 1 1 auto;
  min-height: 0;
}

.modifier-card {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
  width: 100%;
  min-height: calc(300px * var(--ui-global-scale, 1));
  padding: calc(16px * var(--ui-global-scale, 1));
  cursor: pointer;
  text-align: left;
  /* frame, fill and the rarity wash: the card treatment, css/03b-chamfer-kit.css sections 21-22
     (--r is the modifier rarity colour; js/round-modifier-ui.js sets it next to --rm-color). */
  /* 3D Concealed starting state until .revealed */
  opacity: 0;
  transform: perspective(800px) rotateY(85deg) scale(0.88);
  transition: transform 160ms cubic-bezier(0.2, 0.9, 0.3, 1);
  will-change: transform, opacity;
  box-sizing: border-box;
}

/* Animated Cyber Hologram Background layers */
.modifier-card-anim-bg {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
  border-radius: inherit;
  opacity: 0.9;
}

/* 1. Dynamic Rarity Radiant Radial Aurora */
.modifier-card-bg-gradient {
  position: absolute;
  inset: -20%;
  background: radial-gradient(
    circle at 50% 30%,
    rgba(var(--r, var(--c-primary)), 0.28) 0%,
    rgba(var(--r, var(--c-primary)), 0.12) 40%,
    transparent 70%
  );
  animation: wagerBgAuroraPulse 4.8s ease-in-out infinite alternate;
  will-change: transform, opacity;
}

@keyframes wagerBgAuroraPulse {
  0% {
    transform: scale(0.92) translate(-4%, -4%);
    opacity: 0.7;
  }
  50% {
    transform: scale(1.08) translate(3%, 2%);
    opacity: 1;
  }
  100% {
    transform: scale(0.96) translate(2%, 4%);
    opacity: 0.8;
  }
}

/* 2. Drifting Cyber Isometric Circuit Grid */
.modifier-card-bg-grid {
  position: absolute;
  inset: 0;
  background-image: 
    linear-gradient(to right, rgba(var(--r, var(--c-primary)), 0.08) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(var(--r, var(--c-primary)), 0.08) 1px, transparent 1px);
  background-size: 18px 18px;
  background-position: 0 0;
  mask-image: radial-gradient(ellipse at 50% 50%, rgba(0, 0, 0, 0.8) 20%, transparent 80%);
  -webkit-mask-image: radial-gradient(ellipse at 50% 50%, rgba(0, 0, 0, 0.8) 20%, transparent 80%);
  animation: wagerGridDrift 18s linear infinite;
  will-change: background-position;
}

@keyframes wagerGridDrift {
  0% {
    background-position: 0 0;
  }
  100% {
    background-position: 36px 36px;
  }
}

/* 3. Luminous Diagonal Laser Energy Sweep Band */
.modifier-card-bg-sweep {
  position: absolute;
  top: -60%;
  left: -60%;
  width: 220%;
  height: 220%;
  background: linear-gradient(
    115deg,
    transparent 42%,
    rgba(var(--r, var(--c-primary)), 0.04) 47%,
    rgba(var(--r, var(--c-primary)), 0.24) 50%,
    rgba(var(--r, var(--c-primary)), 0.04) 53%,
    transparent 58%
  );
  animation: wagerEnergySweep 5.4s cubic-bezier(0.4, 0, 0.2, 1) infinite;
  pointer-events: none;
  will-change: transform;
}

@keyframes wagerEnergySweep {
  0%, 25% {
    transform: translateY(-80%) rotate(0deg);
    opacity: 0;
  }
  30% {
    opacity: 1;
  }
  65% {
    opacity: 1;
  }
  75%, 100% {
    transform: translateY(80%) rotate(0deg);
    opacity: 0;
  }
}

/* 4. Ambient Rising Micro-Sparkles / Stardust */
.modifier-card-bg-particles {
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(1.5px 1.5px at 20% 30%, rgba(var(--r, var(--c-primary)), 0.65), transparent),
    radial-gradient(1.5px 1.5px at 75% 20%, rgba(var(--r, var(--c-primary)), 0.75), transparent),
    radial-gradient(2px 2px at 40% 70%, rgba(var(--r, var(--c-primary)), 0.7), transparent),
    radial-gradient(1px 1px at 85% 65%, rgba(var(--r, var(--c-primary)), 0.5), transparent),
    radial-gradient(2px 2px at 15% 85%, rgba(var(--r, var(--c-primary)), 0.6), transparent),
    radial-gradient(1.5px 1.5px at 60% 88%, rgba(var(--r, var(--c-primary)), 0.55), transparent);
  background-size: 100% 100%;
  animation: wagerParticlesFloat 7s ease-in-out infinite alternate;
  will-change: transform, opacity;
}

@keyframes wagerParticlesFloat {
  0% {
    transform: translateY(4px) scale(0.98);
    opacity: 0.55;
  }
  50% {
    transform: translateY(-3px) scale(1.02);
    opacity: 0.95;
  }
  100% {
    transform: translateY(-8px) scale(1);
    opacity: 0.65;
  }
}

/* Ensure content children sit above the background layers */
.modifier-card > :not(.modifier-card-anim-bg) {
  position: relative;
  z-index: 1;
}

/* Elevated hover/focus animation dynamics */
:where(body:not(.gamepad-active)) .modifier-card:hover .modifier-card-anim-bg,
.modifier-card.kb-focused .modifier-card-anim-bg,
.modifier-card.controller-focused .modifier-card-anim-bg {
  opacity: 1;
}

:where(body:not(.gamepad-active)) .modifier-card:hover .modifier-card-bg-gradient,
.modifier-card.kb-focused .modifier-card-bg-gradient,
.modifier-card.controller-focused .modifier-card-bg-gradient {
  filter: brightness(1.35);
}

/* 3D Flip-In Spring Animation upon reveal */
.modifier-card.revealed {
  opacity: 1;
  transform: perspective(800px) rotateY(0deg) scale(1);
  animation: modifierCard3DFlipIn 460ms cubic-bezier(0.18, 0.9, 0.26, 1.2) forwards;
}

@keyframes modifierCard3DFlipIn {
  0% {
    opacity: 0;
    transform: perspective(800px) rotateY(85deg) scale(0.85);
    filter: brightness(1.9) saturate(1.5);
  }
  60% {
    opacity: 1;
    transform: perspective(800px) rotateY(-8deg) scale(1.03);
    filter: brightness(1.45) saturate(1.3);
  }
  85% {
    transform: perspective(800px) rotateY(3deg) scale(0.99);
  }
  100% {
    opacity: 1;
    transform: perspective(800px) rotateY(0deg) scale(1);
    filter: brightness(1);
  }
}

/* The radiant rarity flash that used to be a radial ::before-style burst on .revealed::after is the
   brightness / saturation settle in the flip-in keyframes above: ::after is the kit's focus frame, and
   the old burst (animation: forwards, opacity 0) would have hidden it. */

:where(body:not(.gamepad-active)) .modifier-card:hover,
.modifier-card.kb-focused,
.modifier-card.controller-focused {
  transform: translateY(-6px);
}

/* .controller-focused is applied by pollGamepadMenu() (js/main-loop.js); the frame is the kit focus
   variant (css/03b-chamfer-kit.css section 4). */

/* Card Selection Slam: chosen card punches forward with intense rarity glow */
.modifier-card.selected-slam {
  z-index: 10 !important;
  pointer-events: none !important;
  animation: wagerCardSelectSlam 360ms cubic-bezier(0.15, 0.9, 0.2, 1.25) forwards !important;
}

@keyframes wagerCardSelectSlam {
  0% {
    transform: scale(1);
    filter: brightness(1);
  }
  35% {
    transform: scale(1.08) translateY(-4px);
    filter: brightness(1.75) saturate(1.4);
  }
  70% {
    transform: scale(1.05) translateY(-2px);
    filter: brightness(1.35) saturate(1.25);
  }
  100% {
    transform: scale(1.06) translateY(-2px);
    filter: brightness(1.3) saturate(1.2);
  }
}

/* Sibling Dissolve: non-selected cards fade out and sink backward */
.modifier-card.sibling-dissolve {
  pointer-events: none !important;
  animation: wagerSiblingDissolve 320ms cubic-bezier(0.25, 0.9, 0.4, 1) forwards !important;
}

@keyframes wagerSiblingDissolve {
  0% {
    opacity: 1;
    transform: scale(1);
  }
  100% {
    opacity: 0.2;
    transform: scale(0.92) translateY(12px);
    filter: grayscale(0.5) blur(1px);
  }
}

/* Visceral micro-shake on wager lock-in */
.round-modifier-panel.panel-micro-shake {
  animation: wagerPanelMicroShake 260ms cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
}

/* The window now carries the kit's cx-crt-in (one `animation` property, higher specificity), which
   would swallow the shake. cx-crt-in stays first in the list so removing .panel-micro-shake does
   not replay the CRT open. */
:is(#cx-boost, .overlay).active .glass-panel.cx-win.round-modifier-panel.panel-micro-shake {
  animation: cx-crt-in 0.45s cubic-bezier(0.2, 0.9, 0.3, 1) backwards, wagerPanelMicroShake 260ms cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
}

@keyframes wagerPanelMicroShake {
  0%, 100% { transform: translate(0, 0); }
  20% { transform: translate(-3px, 2px); }
  40% { transform: translate(3px, -2px); }
  60% { transform: translate(-2px, 1px); }
  80% { transform: translate(1px, -1px); }
}

/* Clean skip swipe fade: all cards smoothly dim and glide down */
.modifier-card.clean-skip-fade {
  pointer-events: none !important;
  animation: wagerCleanSkipFade 200ms ease-out forwards !important;
}

@keyframes wagerCleanSkipFade {
  0% {
    opacity: 1;
    transform: translateY(0);
  }
  100% {
    opacity: 0;
    transform: translateY(20px) scale(0.96);
  }
}


.modifier-card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  gap: 8px;
  flex-shrink: 0;
}

.modifier-card-slot {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-display);
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(226, 232, 240, 0.7);
}

.modifier-slot-indicator {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--rm-color, #94a3b8);
  box-shadow: 0 0 6px var(--rm-glow, rgba(148, 163, 184, 0.7));
  flex-shrink: 0;
}

.modifier-card-badge {
  position: static;
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px 12px 3px 8px;
  /* slanted tag strip, the kit's .cx-tag shape (a clipped element shows no glow) */
  clip-path: polygon(0 0, 100% 0, calc(100% - 6px) 100%, 0 100%);
  color: #080c16;
  background: var(--rm-color, #94a3b8);
  flex-shrink: 0;
  line-height: 1.2;
}

.modifier-card-badge-group {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.modifier-card-badge.modifier-card-badge-ultra {
  background: linear-gradient(135deg, rgb(var(--c-secondary)) 0%, rgb(var(--c-primary)) 50%, rgb(var(--c-sky)) 100%);
  color: #ffffff;
  font-weight: 900;
  letter-spacing: 0.1em;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
  animation: rm-badge-pulse 2s ease-in-out infinite alternate;
}

/* Ultra rare: a sky -> primary -> secondary gradient frame (section 22 of css/03b-chamfer-kit.css)
   and the shared border pulse, replacing the box-shadow shimmer (a clipped shadow is invisible). */

@keyframes rm-badge-pulse {
  0% { transform: scale(1); filter: brightness(1); }
  100% { transform: scale(1.04); filter: brightness(1.2); }
}

/* Anomalous modifier card: the frame is the anomalous token (--r, section 22 of css/03b-chamfer-kit.css), the
   glitch scanlines are a layer of its fill, and the pink chromatic fringe stays on the title and badge. */
.modifier-card-badge.modifier-card-badge-anomalous {
  background: linear-gradient(135deg, #ec4899 0%, #a855f7 50%, rgb(var(--c-rarity-anomalous)) 100%);
  color: #ffffff;
  font-weight: 900;
  letter-spacing: 0.12em;
  text-shadow: -1px 0 rgb(var(--c-rarity-anomalous)), 1px 0 #ec4899, 0 1px 2px rgba(0, 0, 0, 0.9);
  animation: rm-anomalous-badge-flicker 2.5s steps(2, start) infinite;
}

.modifier-card.rarity-anomalous .modifier-card-title {
  text-shadow: -1.5px 0 rgba(var(--c-rarity-anomalous), 0.75), 1.5px 0 rgba(236, 72, 153, 0.75);
}


@keyframes rm-anomalous-badge-flicker {
  0%, 100% { opacity: 1; transform: scale(1); }
  45% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.85; transform: scale(0.98) skewX(-1deg); }
  55% { opacity: 1; transform: scale(1.02) skewX(1deg); }
  80% { opacity: 1; transform: scale(1); }
  85% { opacity: 0.9; transform: scale(0.99); }
}

.modifier-card-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  flex: 1;
  justify-content: flex-start;
  width: 100%;
  box-sizing: border-box;
  align-items: stretch;
}

.modifier-card-title-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.modifier-card-icon {
  width: 32px;
  height: 32px;
  object-fit: contain;
  flex-shrink: 0;
}

.modifier-card-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.08rem;
  font-weight: 700;
  line-height: 1.2;
  color: #ffffff;
  text-shadow: 0 0 10px var(--rm-glow, rgba(148, 163, 184, 0.3));
}

.modifier-card-sections {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 2px;
  flex: 1;
  width: 100%;
  box-sizing: border-box;
  align-items: stretch;
}

.modifier-section-risk,
.modifier-section-reward {
  border-radius: 8px;
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  gap: 5px;
  text-align: left;
  flex: 1 1 0;
  width: 100%;
  box-sizing: border-box;
  align-self: stretch;
}

.modifier-section-risk {
  background: rgba(var(--c-danger), 0.09);
  border: 1px solid rgba(var(--c-danger), 0.28);
}

.modifier-section-reward {
  background: rgba(34, 197, 94, 0.09);
  border: 1px solid rgba(34, 197, 94, 0.28);
}

.modifier-reward-subgroup {
  display: flex;
  flex-direction: column;
  gap: 3px;
  flex: 1;
}

.modifier-subgroup-header {
  display: flex;
  align-items: center;
  gap: 4px;
}

.modifier-subgroup-label {
  font-size: 0.52rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 1px 5px;
  border-radius: 3px;
  line-height: 1.2;
}

.modifier-subgroup-label.inround-label {
  color: #4ade80;
  background: rgba(34, 197, 94, 0.15);
  border: 1px solid rgba(74, 222, 128, 0.35);
}

.modifier-subgroup-label.clear-label {
  color: rgb(var(--c-gold));
  background: rgba(245, 158, 11, 0.15);
  border: 1px solid rgba(var(--c-gold), 0.4);
}

.modifier-bullet-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1;
  justify-content: center;
}

.modifier-bullet-item {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  font-size: 0.78rem;
  line-height: 1.35;
}

.modifier-bullet-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  margin-top: 5px;
  flex-shrink: 0;
}

.modifier-bullet-dot.reward-dot {
  background: #4ade80;
  box-shadow: 0 0 6px rgba(74, 222, 128, 0.85);
}

.modifier-bullet-dot.clear-dot {
  background: rgb(var(--c-gold));
  box-shadow: 0 0 6px rgba(var(--c-gold), 0.85);
}

.modifier-bullet-dot.risk-dot {
  background: #f87171;
  box-shadow: 0 0 6px rgba(248, 113, 113, 0.85);
}

.modifier-bullet-text {
  flex: 1;
  word-break: break-word;
  overflow-wrap: break-word;
}

.modifier-bullet-list.reward-bullets .modifier-bullet-text {
  color: rgba(187, 247, 208, 0.95);
  font-weight: 500;
}

.modifier-bullet-list.clear-bullets .modifier-bullet-text {
  color: rgba(254, 240, 138, 0.95);
  font-weight: 500;
}

.modifier-bullet-list.risk-bullets .modifier-bullet-text {
  color: rgba(254, 202, 202, 0.95);
  font-weight: 500;
}

.modifier-section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 6px;
  min-height: 20px;
  width: 100%;
  box-sizing: border-box;
}

.modifier-section-label {
  font-size: 0.60rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  flex-shrink: 0;
}

.modifier-section-label.risk-label {
  color: #f87171;
}

.modifier-section-label.reward-label {
  color: #4ade80;
}

.modifier-contract-tag {
  font-size: 0.54rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: 4px;
  color: #fca5a5;
  background: rgba(185, 28, 28, 0.45);
  border: 1px solid rgba(248, 113, 113, 0.55);
  line-height: 1.2;
  white-space: nowrap;
  flex-shrink: 0;
}

.modifier-section-desc {
  margin: 0;
  font-size: 0.78rem;
  line-height: 1.35;
}

.modifier-section-desc.risk-desc {
  color: rgba(254, 202, 202, 0.95);
}

.modifier-section-desc.reward-desc {
  color: rgba(187, 247, 208, 0.95);
}

.modifier-tag-group {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
  justify-content: flex-end;
  margin-left: auto;
}


.round-modifier-footer {
  margin-top: calc(18px * var(--ui-global-scale, 1));
  display: flex;
  justify-content: center;
  flex-shrink: 0;
}

/* Skip button: a chamfered .btn (css/03b-chamfer-kit.css section 12), layout only here. The old slate
   pill, its hover lift and its focus glow were deleted; the screen accent is crimson. */
.round-modifier-skip-btn {
  min-width: 240px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 8px 20px;
}

.round-modifier-btn-glyph {
  width: 18px;
  height: 18px;
  object-fit: contain;
  vertical-align: -3px;
}

/* Chaos rounds: the panel itself picks up the exclusive theme. */
#round-modifier-screen.chaos {
  /* chaos accent for the window frame and halo (border-color / box-shadow are clipped away) */
  --acc: var(--c-primary);
}

/* ------------------------------------------------------------
   RESPONSIVE PROFILES (Steam Deck & Mobile)
   ------------------------------------------------------------ */

/* Extreme narrow / portrait phones (< 560px): cards stack vertically in a clean scroll list */
@media (max-width: 560px), (orientation: portrait) and (max-width: 560px) {
  .round-modifier-grid {
    grid-template-columns: 1fr;
    gap: 8px;
    overflow-y: auto;
    max-height: calc(65 * var(--vvh));
    padding-right: 4px;
    align-items: stretch;
  }
  .modifier-card {
    min-height: 0;
    padding: 10px 12px;
    gap: 6px;
    flex-shrink: 0;
  }
  .modifier-section-desc {
    font-size: 0.74rem;
    line-height: 1.25;
    word-break: break-word;
  }
  .modifier-bullet-item {
    font-size: 0.74rem;
    line-height: 1.25;
  }
  .modifier-subgroup-label {
    font-size: 0.48rem;
    padding: 1px 4px;
  }
  .modifier-contract-tag {
    font-size: 0.50rem;
    padding: 1px 5px;
  }
}

/* Short height screens (Steam Deck 800p, Standard Tablets) */
@media (max-height: 700px) {
  .round-modifier-panel {
    padding: 10px 18px;
    max-height: calc(95 * var(--vvh));
  }
  .round-modifier-header {
    min-height: 32px;
    padding: 0 32px;
  }
  .round-modifier-emblem-wrap {
    width: 28px;
    height: 28px;
    left: 2px;
  }
  .round-modifier-emblem-svg {
    width: 26px;
    height: 26px;
  }
  .wager-anomaly-banner {
    font-size: 0.58rem;
    padding: 1px 6px;
    margin-bottom: 2px;
    gap: 4px;
  }
  .wager-anomaly-banner .wager-anomaly-icon {
    width: 9px;
    height: 9px;
  }
  .round-modifier-header-center h2 {
    font-size: 1.08rem;
    margin: 0;
  }
  .round-modifier-header-center p {
    font-size: 0.74rem;
    margin: 0;
  }
  .round-modifier-grid {
    gap: 8px;
    margin-top: 8px;
  }
  .modifier-card {
    min-height: 0;
    padding: 8px 10px;
    gap: 5px;
  }
  .modifier-card-title {
    font-size: 0.92rem;
  }
  .modifier-card-sections {
    gap: 5px;
    flex: 1;
  }
  .modifier-section-risk,
  .modifier-section-reward {
    padding: 5px 8px;
    flex: 1 1 0;
    gap: 4px;
  }
  .modifier-reward-subgroup {
    gap: 2px;
  }
  .modifier-subgroup-label {
    font-size: 0.48rem;
    padding: 1px 4px;
  }
  .modifier-contract-tag {
    font-size: 0.50rem;
    padding: 1px 5px;
  }
  .modifier-section-desc {
    font-size: 0.72rem;
  }
  .modifier-bullet-list {
    gap: 3px;
  }
  .modifier-bullet-item {
    font-size: 0.72rem;
    gap: 5px;
  }
  .modifier-bullet-dot {
    width: 4px;
    height: 4px;
    margin-top: 4px;
  }
  .round-modifier-footer {
    margin-top: 8px;
  }
  .round-modifier-skip-btn {
    min-height: 38px;
    padding: 5px 14px;
    font-size: 0.82rem;
  }
}

/* Mobile Landscape & Short Viewports (iPhone, Android, Nintendo Switch / 360-520p height)
   Enforces 3-column horizontal cards with streamlined headers and full detail preservation */
@media (max-height: 520px) and (min-width: 561px) {
  #round-modifier-screen .glass-panel,
  #round-modifier-screen .glass-panel.wide-panel,
  .round-modifier-panel {
    width: calc(96 * var(--vvw)) !important;
    max-width: calc(96 * var(--vvw)) !important;
    max-height: calc(96 * var(--vvh)) !important;
    padding: 6px 12px !important;
  }
  .round-modifier-header {
    min-height: 24px;
    padding: 0 26px;
  }
  .round-modifier-emblem-wrap {
    width: 22px;
    height: 22px;
    left: 2px;
  }
  .round-modifier-emblem-svg {
    width: 20px;
    height: 20px;
  }
  .wager-anomaly-banner {
    font-size: 0.52rem;
    padding: 1px 5px;
    margin-bottom: 1px;
    gap: 3px;
    letter-spacing: 0.05em;
  }
  .wager-anomaly-banner .wager-anomaly-icon {
    width: 8px;
    height: 8px;
  }
  .round-modifier-header-center h2 {
    font-size: 0.95rem;
    line-height: 1.1;
  }
  .round-modifier-header-center p {
    font-size: 0.66rem;
    line-height: 1.15;
    opacity: 0.85;
  }
  .round-modifier-grid {
    display: grid !important;
    grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
    gap: 6px !important;
    margin-top: 4px !important;
    overflow-y: visible !important;
    max-height: none !important;
    align-items: stretch !important;
  }
  .modifier-card {
    min-height: 0 !important;
    padding: 6px 8px !important;
    gap: 4px !important;
  }
  .modifier-card-header {
    gap: 4px;
  }
  .modifier-card-slot {
    font-size: 0.58rem;
    gap: 4px;
  }
  .modifier-slot-indicator {
    width: 5px;
    height: 5px;
  }
  .modifier-card-badge {
    font-size: 0.56rem;
    padding: 2px 5px;
  }
  .modifier-card-badge-group {
    gap: 4px;
  }
  .modifier-card-body {
    gap: 4px;
    flex: 1;
  }
  .modifier-card-title-row {
    gap: 6px;
  }
  .modifier-card-icon {
    width: 22px;
    height: 22px;
  }
  .modifier-card-title {
    font-size: 0.82rem;
    line-height: 1.15;
  }
  .modifier-card-sections {
    gap: 3px;
    margin-top: 1px;
    flex: 1 !important;
  }
  .modifier-section-risk,
  .modifier-section-reward {
    padding: 3px 6px;
    gap: 2px;
    border-radius: 6px;
    flex: 1 1 0 !important;
  }
  .modifier-reward-subgroup {
    gap: 2px;
  }
  .modifier-subgroup-header {
    gap: 2px;
  }
  .modifier-subgroup-label {
    font-size: 0.44rem;
    padding: 0 3px;
    letter-spacing: 0.05em;
  }
  .modifier-section-header {
    min-height: 16px;
    gap: 4px;
  }
  .modifier-section-label {
    font-size: 0.52rem;
    letter-spacing: 0.06em;
  }
  .modifier-contract-tag {
    font-size: 0.46rem;
    padding: 1px 4px;
    letter-spacing: 0.04em;
  }
  .modifier-tag-group {
    gap: 2px;
  }
  .modifier-section-desc {
    font-size: 0.68rem;
    line-height: 1.2;
    word-break: break-word;
    overflow-wrap: break-word;
  }
  .modifier-bullet-list {
    gap: 2px;
  }
  .modifier-bullet-item {
    font-size: 0.66rem;
    line-height: 1.18;
    gap: 4px;
  }
  .modifier-bullet-dot {
    width: 4px;
    height: 4px;
    margin-top: 3px;
  }
  .round-modifier-footer {
    margin-top: 4px;
  }
  .round-modifier-skip-btn {
    min-height: 38px;
    padding: 4px 14px;
    font-size: 0.78rem;
  }
  .round-modifier-btn-glyph {
    width: 14px;
    height: 14px;
  }
}

/* Extra-tight landscape viewports (height <= 400px, e.g. iPhone SE / 8 / landscape phones with browser chrome) */
@media (max-height: 400px) and (min-width: 561px) {
  .round-modifier-header-center p {
    display: none; /* Hide explanatory subtitle to give maximum room to wager details */
  }
  .wager-anomaly-banner {
    display: none; /* Anomaly banner hidden on ultra-short screens to maximize card heights */
  }
  .round-modifier-panel {
    padding: 4px 10px !important;
  }
  .round-modifier-header {
    min-height: 20px;
  }
  .modifier-card {
    padding: 5px 7px !important;
    gap: 3px !important;
  }
  .modifier-card-title {
    font-size: 0.78rem;
  }
  .modifier-card-icon {
    width: 18px;
    height: 18px;
  }
  .modifier-section-desc {
    font-size: 0.64rem;
    line-height: 1.18;
  }
  .modifier-bullet-item {
    font-size: 0.62rem;
    line-height: 1.15;
    gap: 3px;
  }
  .modifier-bullet-dot {
    width: 3.5px;
    height: 3.5px;
    margin-top: 3px;
  }
  .modifier-subgroup-label {
    font-size: 0.40rem;
    padding: 0 2px;
  }
  .modifier-contract-tag {
    font-size: 0.42rem;
    padding: 0 3px;
  }
  .round-modifier-skip-btn {
    min-height: 34px;
    padding: 3px 12px;
    font-size: 0.74rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  /* Reduced-motion animation suppression removed across all menus per project direction.
     All cinematics, card reveals, power-ups, shop cascades, and bursts remain fully active.
     Selectors preserved for reference:
     .wager-hud-tracker, .modifier-card, .modifier-card.revealed,
  .modifier-card.selected-slam,
  .modifier-card.sibling-dissolve,
  .modifier-card.clean-skip-fade,
  .round-modifier-panel.panel-micro-shake,
     .choice-card.path-a, .choice-card.path-b, .choice-card.selected, .choice-card.selected.power-up,
     .choice-card.rejected.fizzle, .upgrade-card.weapon-card-cascade, .upgrade-card.selected,
     .upgrade-card.selected.power-up, .upgrade-card.rejected, .swap-equipped-card.selected,
     .swap-equipped-card.selected.power-up, .swap-equipped-card.rejected,
     .weapon-equip-burst, .weapon-equip-flash, .major-choice-burst, .major-choice-flash,
     .gear-refactor-affix-row, .gear-refactor-option-row, .gear-refactor-empower-pip.just-filled,
     .gear-refactor-burst, .empower-affordable-glow::after,
     .shop-enter .shop-currencies-bar, .shop-burst-ring,
     .gear-swap-enter #gear-swap-new-card, .gear-swap-burst-ring,
     .gamble-card-back.rolling, .gear-outer-glitched.gear-outer-glitched::before
  */
}

/* ==========================================================================
   Cinematic Cyber Roll Credits Screen
   ========================================================================== */
.credits-overlay {
  position: fixed;
  inset: 0;
  width: calc(100 * var(--vvw));
  height: calc(100 * var(--vvh));
  background: radial-gradient(circle at center, rgba(12, 18, 38, 0.98) 0%, rgba(5, 8, 18, 1) 100%);
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  overflow: hidden;
  user-select: none;
  -webkit-user-select: none;
  z-index: 8900;
}

.credits-overlay.active {
  display: flex;
}

.credits-starfield-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  opacity: 0.6;
}

.credits-scroll-viewport {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  pointer-events: none;
  display: flex;
  justify-content: center;
}

.credits-scroll-track {
  position: absolute;
  top: 100%;
  width: min(calc(92 * var(--vvw)), 680px);
  text-align: center;
  color: #fff;
  will-change: transform;
  pointer-events: auto;
  padding-bottom: 240px;
}

.credits-header-block {
  margin-bottom: 60px;
}

.credits-main-title {
  font-size: calc(2.5rem * var(--ui-global-scale, 1));
  font-weight: 900;
  letter-spacing: 4px;
  background: linear-gradient(90deg, rgb(var(--c-sky)), #818cf8);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  text-shadow: 0 0 30px rgba(var(--c-sky), 0.4);
}

.credits-main-sub {
  font-size: calc(0.95rem * var(--ui-global-scale, 1));
  letter-spacing: 3px;
  color: rgb(var(--c-slate));
  font-weight: 700;
  margin-top: 6px;
}

.credits-tagline {
  font-size: calc(0.82rem * var(--ui-global-scale, 1));
  letter-spacing: 2px;
  color: rgb(var(--c-gold));
  font-weight: 600;
  margin-top: 10px;
}

.credits-divider {
  width: 80px;
  height: 3px;
  background: linear-gradient(90deg, transparent, rgb(var(--c-sky)), transparent);
  margin: 24px auto;
  border-radius: 999px;
}

.credits-section {
  margin-bottom: 56px;
}

.credits-section-title {
  font-size: calc(1rem * var(--ui-global-scale, 1));
  font-weight: 800;
  letter-spacing: 2.5px;
  text-transform: uppercase;
  margin-bottom: 20px;
  text-shadow: 0 0 16px currentColor;
}

.credits-entries-list {
  display: flex;
  flex-direction: column;
  gap: 22px;
}

.credits-entry-name {
  font-size: calc(1.35rem * var(--ui-global-scale, 1));
  font-weight: 800;
  color: #f8fafc;
  letter-spacing: 1px;
}

.credits-entry-role {
  font-size: calc(0.9rem * var(--ui-global-scale, 1));
  color: rgb(var(--c-slate));
  margin-top: 2px;
}

.credits-entry-sub {
  font-size: calc(0.78rem * var(--ui-global-scale, 1));
  color: #64748b;
  font-style: italic;
  margin-top: 2px;
}

.credits-spotlight-card {
  background: rgba(15, 23, 42, 0.85);
  border: 2px solid var(--spot-glow, #38bdf8);
  padding: 24px 28px;
  box-shadow: 0 0 30px rgba(0, 0, 0, 0.6), 0 0 16px var(--spot-glow, rgba(56, 189, 248, 0.25));
  backdrop-filter: blur(8px);
  margin: 0 auto;
  max-width: 580px;
  text-align: center;
}

.spotlight-crest-wrap {
  display: flex;
  justify-content: center;
  margin-bottom: 12px;
}

.spotlight-name {
  font-size: calc(1.5rem * var(--ui-global-scale, 1));
  font-weight: 900;
  letter-spacing: 1.5px;
  text-shadow: 0 0 16px currentColor;
}

.spotlight-role {
  font-size: calc(0.95rem * var(--ui-global-scale, 1));
  color: #cbd5e1;
  font-weight: 600;
  margin-top: 4px;
}

.spotlight-notes {
  font-size: calc(0.88rem * var(--ui-global-scale, 1));
  color: #e2e8f0;
  font-style: italic;
  margin-top: 12px;
  line-height: 1.5;
  border-top: 1px dashed rgba(255, 255, 255, 0.15);
  padding-top: 10px;
}

.credits-footer-block {
  margin-top: 60px;
  margin-bottom: 40px;
}

.credits-footer-thanks {
  font-size: calc(1.6rem * var(--ui-global-scale, 1));
  font-weight: 900;
  letter-spacing: 3px;
  color: rgb(var(--c-gold));
  text-shadow: 0 0 20px rgba(var(--c-gold), 0.5);
  margin-bottom: 12px;
}

.credits-footer-copy {
  font-size: calc(0.78rem * var(--ui-global-scale, 1));
  color: #64748b;
  letter-spacing: 1.5px;
}

.credits-scroll-spacer {
  height: 250px;
}

/* Credits Dynamic Controls HUD */
.credits-hud {
  position: fixed;
  bottom: calc(24px * var(--ui-global-scale, 1));
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 12px;
  align-items: center;
  background: rgba(10, 15, 29, 0.92);
  backdrop-filter: blur(16px);
  border: 1.5px solid rgba(255, 255, 255, 0.15);
  padding: 8px 18px;
  z-index: 9000;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.7);
  transition: all 0.2s ease;
}

.credits-hud-chip {
  display: flex;
  align-items: center;
  gap: 10px;
  color: #e2e8f0;
  font-size: calc(0.92rem * var(--ui-global-scale, 1));
  font-weight: 700;
  letter-spacing: 0.3px;
  padding: 8px 18px;
  background: rgba(15, 23, 42, 0.82);
  border: 1.5px solid rgba(255, 255, 255, 0.18);
  cursor: pointer;
  white-space: nowrap;
  user-select: none;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
  transition: all 0.2s ease;
}

:where(body:not(.gamepad-active)) .credits-hud-chip:hover {
  background: rgba(255, 255, 255, 0.16);
  border-color: rgba(255, 255, 255, 0.35);
  transform: translateY(-1px);
}

.credits-hud.fast-forwarding .credits-hud-speed {
  background: rgba(var(--c-gold), 0.25);
  border-color: rgb(var(--c-gold));
  color: rgb(var(--c-gold));
  box-shadow: 0 0 16px rgba(var(--c-gold), 0.45);
}

.credits-hud-pause.paused {
  background: rgba(var(--c-danger), 0.22);
  border-color: rgb(var(--c-danger));
  color: rgb(var(--c-danger));
}

.credits-glyph-wrap {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.credits-svg-glyph {
  width: 30px;
  height: 30px;
  object-fit: contain;
  display: block;
  filter: drop-shadow(0 0 6px rgba(255, 255, 255, 0.4));
}

.credits-glyph-space {
  width: 48px;
  height: 30px;
}

.credits-hint-label {
  white-space: nowrap;
}

.credits-skip-btn {
  padding: 8px 22px;
  font-size: calc(0.92rem * var(--ui-global-scale, 1));
  font-weight: 700;
  letter-spacing: 0.5px;
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  white-space: nowrap;
}

.credits-hud .pad-only {
  display: none !important;
}

.credits-hud .pc-only {
  display: inline-flex !important;
}

body.gamepad-active .credits-hud .pc-only,
body.input-gamepad .credits-hud .pc-only {
  display: none !important;
}

body.gamepad-active .credits-hud .pad-only,
body.input-gamepad .credits-hud .pad-only {
  display: inline-flex !important;
}

body.input-touch .credits-hud .pc-only,
body.input-touch .credits-hud .pad-only,
body.input-touch .credits-hud .credits-glyph-wrap,
html.is-mobile:not(.gamepad-active):not(.input-gamepad) .credits-hud .pc-only,
html.is-mobile:not(.gamepad-active):not(.input-gamepad) .credits-hud .pad-only,
html.is-mobile:not(.gamepad-active):not(.input-gamepad) .credits-hud .credits-glyph-wrap,
body.is-mobile:not(.gamepad-active):not(.input-gamepad) .credits-hud .pc-only,
body.is-mobile:not(.gamepad-active):not(.input-gamepad) .credits-hud .pad-only,
body.is-mobile:not(.gamepad-active):not(.input-gamepad) .credits-hud .credits-glyph-wrap {
  display: none !important;
}

body.input-touch .credits-hud-chip,
body.input-touch .credits-skip-btn,
html.is-mobile .credits-hud-chip,
html.is-mobile .credits-skip-btn,
body.is-mobile .credits-hud-chip,
body.is-mobile .credits-skip-btn {
  justify-content: center;
  min-height: 44px;
}

/* Credits Easter Egg Modal */
.credits-easter-egg-modal {
  position: fixed !important;
  inset: 0 !important;
  display: none;
  z-index: 9500 !important;
  box-sizing: border-box;
  pointer-events: none;
  align-items: center;
  justify-content: center;
}

/* When opened at the end of the credits (over battle canvas) */
.credits-easter-egg-modal:not(.from-settings) {
  background: rgba(5, 8, 18, 0.75);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  align-items: center;
  justify-content: center;
  padding: calc(20px * var(--ui-global-scale, 1));
}

/* When opened from Settings -> Decrypted Logs */
.credits-easter-egg-modal.from-settings {
  background: rgba(5, 8, 18, 0.92);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  align-items: center;
  justify-content: center;
  padding: calc(20px * var(--ui-global-scale, 1));
  z-index: 9500 !important;
}

.credits-easter-egg-modal.active {
  display: flex !important;
  opacity: 1 !important;
  pointer-events: auto !important;
}

.credits-easter-egg-modal.active * {
  pointer-events: auto;
}

.credits-egg-panel,
.credits-terminal-frame {
  max-width: min(720px, calc(94 * var(--vvw)));
  width: min(720px, calc(94 * var(--vvw)));
  max-height: calc(92 * var(--vvh));
  border: 2px solid rgb(var(--c-gold));
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.75), 0 0 36px rgba(var(--c-gold), 0.4);
  padding: calc(20px * var(--ui-global-scale, 1));
  border-radius: 14px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-sizing: border-box;
  background: linear-gradient(145deg, rgba(14, 10, 26, 0.96), rgba(7, 5, 14, 0.98));
  pointer-events: auto !important;
}

/* The terminal rebuilds its panel (innerHTML) on every fragment-tab click, which would replay the
   kit's CRT open each time. The modal is display:none when closed, so no close animation exists either. */
#credits-easter-egg-modal.active .glass-panel.cx-win {
  animation: none;
}

.credits-easter-egg-modal.from-settings .credits-terminal-frame {
  max-width: min(720px, calc(94 * var(--vvw)));
  width: min(720px, calc(94 * var(--vvw)));
}

.credits-terminal-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  padding-bottom: 12px;
  border-bottom: 1px solid rgba(var(--c-gold), 0.25);
  flex-shrink: 0;
  width: 100%;
}

.credits-terminal-title-wrap {
  flex: 1;
  min-width: 0;
  padding-right: 16px;
}

.credits-terminal-sub {
  font-size: 0.72rem;
  letter-spacing: 1.5px;
  color: rgb(var(--c-slate));
}

.credits-terminal-title {
  color: rgb(var(--c-gold));
  font-size: 1.25rem;
  letter-spacing: 2px;
  margin: 2px 0 0 0;
}

.credits-terminal-progress-badge {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  background: rgba(var(--c-gold), 0.12);
  border: 1.5px solid rgba(var(--c-gold), 0.4);
  box-shadow: 0 0 14px rgba(var(--c-gold), 0.18);
  padding: 6px 14px;
  border-radius: 8px;
  flex-shrink: 0;
  align-self: flex-start;
}

.credits-terminal-progress-badge .progress-count {
  color: rgb(var(--c-gold));
  font-size: 1.15rem;
  font-weight: 800;
  letter-spacing: 1px;
  line-height: 1.1;
}

.credits-terminal-progress-badge .progress-label {
  color: #cbd5e1;
  font-size: 0.65rem;
  letter-spacing: 1.5px;
  font-weight: 700;
  margin-top: 2px;
}

.credits-pad-x-icon,
.credits-pad-b-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: middle;
}

.credits-pad-x-icon img,
.credits-pad-b-icon img {
  width: 18px;
  height: 18px;
  object-fit: contain;
  vertical-align: middle;
  display: block;
}

.credits-master-banner {
  background: linear-gradient(135deg, rgba(var(--c-danger), 0.2), rgba(var(--c-gold), 0.2));
  border: 1.5px solid rgb(var(--c-gold));
  box-shadow: 0 0 20px rgba(var(--c-gold), 0.35);
  padding: 10px 14px;
  border-radius: 8px;
  margin-top: 10px;
  flex-shrink: 0;
  text-align: center;
}

.credits-master-status {
  font-size: 0.72rem;
  letter-spacing: 1.5px;
  color: rgb(var(--c-gold));
  font-weight: 700;
}

.credits-master-headline {
  color: rgb(var(--c-danger));
  font-size: 1.05rem;
  letter-spacing: 1px;
  margin: 3px 0;
}

.credits-master-teaser {
  color: rgb(var(--c-gold));
  font-size: 1.2rem;
  font-weight: 800;
  letter-spacing: 2px;
}

.credits-master-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.78rem;
  color: #e2e8f0;
  margin-top: 4px;
  background: rgba(0, 0, 0, 0.35);
  padding: 2px 10px;
  border-radius: 999px;
  border: 1px solid rgba(var(--c-gold), 0.3);
}

.credits-terminal-layout {
  display: flex;
  gap: 12px;
  margin-top: 10px;
  flex: 1 1 auto;
  min-height: 0;
  max-height: calc(52 * var(--vvh));
  overflow: hidden;
}

.credits-terminal-tabs {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 212px;
  flex-shrink: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 8px;
  box-sizing: border-box;
}

.credits-terminal-tab {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  /* chamfered tile: shape / fill / hover / active / focus from css/03b-chamfer-kit.css section 18 */
  cursor: pointer !important;
  text-align: left;
  color: rgb(var(--c-slate));
  transition: color 0.15s ease;
  user-select: none;
  pointer-events: auto !important;
  touch-action: manipulation;
  position: relative;
}

.credits-terminal-tab > * {
  pointer-events: none;
}

:where(body:not(.gamepad-active)) .credits-terminal-tab:hover {
  color: #f8fafc;
}

.credits-terminal-tab.controller-focused,
.credits-terminal-tab.active {
  color: #f8fafc;
}

.credits-tab-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 24px;
  flex-shrink: 0;
  color: rgb(var(--c-sky));
}

.credits-tab-icon svg,
.credits-tab-icon .survivor-card__ship {
  width: 24px !important;
  height: 20px !important;
  display: block;
}

.credits-tab-frag {
  font-size: 0.72rem;
  font-family: monospace;
  color: #64748b;
  width: 14px;
  text-align: center;
  flex-shrink: 0;
}

.credits-tab-name {
  font-size: 0.82rem;
  font-weight: 600;
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: #e2e8f0;
}

.credits-tab-lock {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}

.credits-terminal-content {
  flex: 1;
  background: rgba(10, 15, 30, 0.7);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  padding: 14px;
  overflow-y: auto;
}

.credits-fragment-display {
  display: flex;
  flex-direction: column;
}

.credits-fragment-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 6px;
}

.credits-fragment-codename {
  font-size: 0.72rem;
  font-family: monospace;
  color: rgb(var(--c-sky));
  letter-spacing: 1px;
}

.credits-fragment-status-badge {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 1px;
  padding: 2px 6px;
  border-radius: 4px;
}

.credits-fragment-status-badge.status-unlocked {
  background: rgba(var(--c-success), 0.15);
  color: rgb(var(--c-success));
  border: 1px solid rgba(var(--c-success), 0.4);
}

.credits-fragment-status-badge.status-locked {
  background: rgba(var(--c-rose), 0.15);
  color: rgb(var(--c-rose));
  border: 1px solid rgba(var(--c-rose), 0.4);
}

.credits-fragment-title {
  color: #f8fafc;
  font-size: 1.08rem;
  margin: 0 0 3px 0;
  letter-spacing: 0.5px;
}

.credits-fragment-clearance {
  font-size: 0.7rem;
  font-family: monospace;
  color: #64748b;
  margin-bottom: 12px;
}

.credits-fragment-text {
  color: #e2e8f0;
  font-size: 0.92rem;
  line-height: 1.6;
  margin: 0;
}

.credits-scrambled-block {
  background: rgba(0, 0, 0, 0.45);
  padding: 12px;
  border-radius: 6px;
  font-size: 0.78rem;
  color: #64748b;
  line-height: 1.6;
  border-left: 3px solid rgb(var(--c-rose));
  word-break: break-all;
}

.credits-locked-hint {
  display: flex;
  align-items: center;
  color: rgb(var(--c-rose));
  font-size: 0.82rem;
  margin-top: 12px;
  line-height: 1.4;
}

.credits-terminal-footer {
  display: flex;
  justify-content: center;
  padding-top: 12px;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  margin-top: 10px;
  flex-shrink: 0;
  position: relative;
  z-index: 10;
  pointer-events: auto !important;
}

.credits-egg-close-btn {
  padding: 10px 40px;
  font-size: 0.95rem;
  font-weight: 700;
  cursor: pointer !important;
  pointer-events: auto !important;
  touch-action: manipulation;
  position: relative;
  z-index: 10;
  user-select: none;
}

.credits-egg-close-btn > * {
  pointer-events: none !important;
}

@media (max-width: 640px) {
  .credits-easter-egg-modal {
    align-items: center;
    justify-content: center;
    padding: 10px;
  }
  .credits-terminal-layout {
    flex-direction: column;
  }
  .credits-terminal-tabs {
    width: 100%;
    flex-direction: row;
    overflow-x: auto;
    padding: 6px;
  }
  .credits-terminal-tab {
    padding: 6px 8px;
  }
}

.credits-logo-wrap {
  display: flex;
  justify-content: center;
  width: 100%;
  margin-bottom: 24px;
}

.credits-logo-img {
  width: 100%;
  max-width: 100%;
  height: auto;
  object-fit: contain;
  filter: drop-shadow(0 0 28px rgba(var(--c-sky), 0.55));
}

.credits-ai-grid {
  display: flex;
  flex-direction: column;
  gap: 16px;
  max-width: 580px;
  margin: 0 auto;
}

.credits-ai-card {
  background: rgba(15, 23, 42, 0.85);
  border: 1.5px solid #818cf8;
  padding: 18px 22px;
  box-shadow: 0 0 22px rgba(129, 140, 248, 0.25);
  text-align: left;
}

.credits-ai-badge {
  display: inline-block;
  background: rgba(129, 140, 248, 0.2);
  color: #c7d2fe;
  border: 1px solid rgba(129, 140, 248, 0.5);
  border-radius: 999px;
  padding: 2px 10px;
  font-size: 0.72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 1px;
  margin-bottom: 6px;
}

.credits-ai-name {
  font-size: calc(1.25rem * var(--ui-global-scale, 1));
  font-weight: 900;
  letter-spacing: 1px;
}

.credits-ai-role {
  font-size: calc(0.88rem * var(--ui-global-scale, 1));
  color: #cbd5e1;
  margin-top: 4px;
  line-height: 1.4;
}

.credits-playtesters-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  max-width: 580px;
  margin: 0 auto;
}

.credits-playtester-chip {
  display: flex;
  align-items: center;
  gap: 10px;
  background: rgba(15, 23, 42, 0.75);
  border: 1.5px solid rgba(var(--c-secondary), 0.4);
  padding: 10px 14px;
  box-shadow: 0 0 14px rgba(var(--c-secondary), 0.15);
  text-align: left;
}

.credits-playtester-icon {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}

.credits-playtester-name {
  font-size: calc(0.95rem * var(--ui-global-scale, 1));
  font-weight: 800;
  color: #fdf2f8;
  letter-spacing: 0.5px;
}

@media (max-width: 680px) {
  .credits-main-title {
    font-size: 1.8rem;
  }
  .credits-playtesters-grid {
    grid-template-columns: 1fr;
  }
  .credits-hud {
    gap: 8px;
    padding: 6px 12px;
    bottom: 16px;
  }
  .credits-hud-chip {
    padding: 6px 12px;
    font-size: 0.8rem;
    gap: 6px;
  }
  .credits-svg-glyph {
    width: 24px;
    height: 24px;
  }
  .credits-glyph-space {
    width: 38px;
    height: 24px;
  }
  .credits-spotlight-card {
    padding: 18px 16px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .credits-logo-img.animate-pulse {
    animation: none !important;
  }
}

/* Shop Inventory Reroll Transition (Cyber Glitch & Dissolve + Staggered Cascade) */
@keyframes shopCardGlitchOut {
  0% {
    opacity: 1;
    transform: translate3d(0, 0, 0) skewX(0deg);
    filter: drop-shadow(0 0 0 rgba(var(--c-primary), 0));
  }
  25% {
    opacity: 0.85;
    transform: translate3d(-3px, 1px, 0) skewX(-2.5deg);
    filter: drop-shadow(-2px 0 4px rgba(6, 182, 212, 0.6));
  }
  50% {
    opacity: 0.6;
    transform: translate3d(3px, -1px, 0) skewX(2.5deg);
    filter: drop-shadow(2px 0 6px rgba(var(--c-secondary), 0.7));
  }
  75% {
    opacity: 0.3;
    transform: translate3d(-6px, 2px, 0) scale(0.97);
  }
  100% {
    opacity: 0;
    transform: translate3d(-12px, 4px, 0) scale(0.94);
    filter: blur(2px);
  }
}

.shop-card-glitch-out {
  animation: shopCardGlitchOut 120ms cubic-bezier(0.2, 0, 0.2, 1) forwards !important;
  pointer-events: none !important;
}

@keyframes shopCardCascadeIn {
  0% {
    opacity: 0;
    transform: translate3d(8px, -6px, 0) scale(0.95);
    filter: drop-shadow(0 0 12px rgba(var(--c-sky), 0.5));
  }
  60% {
    opacity: 1;
    transform: translate3d(-1px, 1px, 0) scale(1.01);
    filter: drop-shadow(0 0 6px rgba(var(--c-primary), 0.4));
  }
  100% {
    opacity: 1;
    transform: translate3d(0, 0, 0) scale(1);
    filter: none;
  }
}

.shop-card-cascade-in {
  animation: shopCardCascadeIn 180ms cubic-bezier(0.16, 1, 0.3, 1) backwards;
  animation-delay: calc(var(--card-index, 0) * 35ms);
}

/* The chamfered cards clip box-shadow, so the lock pulse is a brightness flash plus the small scale. */
@keyframes shopLockedPulse {
  0% {
    filter: brightness(1);
    transform: scale(1);
  }
  40% {
    filter: brightness(1.6) saturate(1.3);
    transform: scale(1.02);
  }
  100% {
    filter: brightness(1);
    transform: scale(1);
  }
}

.shop-card-locked-pulse {
  animation: shopLockedPulse 280ms ease-out !important;
}

@media (prefers-reduced-motion: reduce) {
  /* Reduced-motion suppression removed: shop card glitch-out, cascade-in, and locked pulse animate normally */
  .shop-card-glitch-out,
  .shop-card-cascade-in,
  .shop-card-locked-pulse {
    /* Preserve animation */
  }
}
/* ==========================================================================
   35-WEAPON-DESCRIPTIONS.CSS
   Structured ARPG Weapon Descriptions (Diablo / PoE / WoW Style)
   3-Section Layout: Overview, Combat Metrics Pills, Status/Effect Banners
   ========================================================================== */

.weapon-desc-block {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
  box-sizing: border-box;
  text-align: left;
}

.weapon-desc-overview {
  font-size: 0.82rem;
  line-height: 1.35;
  color: #e2e8f0;
  margin: 0;
  font-family: inherit;
}

/* --- Section 2: Combat Metrics Pills --- */
.weapon-desc-metrics {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 2px 0;
}

.weapon-metric-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: rgba(15, 23, 42, 0.75);
  border: 1px solid rgba(255, 255, 255, 0.14);
  padding: 2px 7px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: #cbd5e1;
  white-space: nowrap;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}

.weapon-metric-pill .metric-label {
  color: #94a3b8;
  font-weight: 500;
}

.weapon-metric-pill .metric-val {
  font-weight: 700;
}

/* Elemental Damage Colors */
.weapon-metric-pill.metric-damage-energy {
  border-color: rgba(56, 189, 248, 0.35);
  background: rgba(14, 116, 144, 0.2);
}
.weapon-metric-pill.metric-damage-energy .metric-val {
  color: #38bdf8;
  text-shadow: 0 0 6px rgba(56, 189, 248, 0.3);
}

.weapon-metric-pill.metric-damage-fire {
  border-color: rgba(249, 115, 22, 0.35);
  background: rgba(194, 65, 12, 0.2);
}
.weapon-metric-pill.metric-damage-fire .metric-val {
  color: #f97316;
  text-shadow: 0 0 6px rgba(249, 115, 22, 0.3);
}

.weapon-metric-pill.metric-damage-cold {
  border-color: rgba(103, 232, 249, 0.35);
  background: rgba(8, 145, 178, 0.2);
}
.weapon-metric-pill.metric-damage-cold .metric-val {
  color: #67e8f9;
  text-shadow: 0 0 6px rgba(103, 232, 249, 0.3);
}

.weapon-metric-pill.metric-damage-poison {
  border-color: rgba(52, 211, 153, 0.35);
  background: rgba(5, 150, 105, 0.2);
}
.weapon-metric-pill.metric-damage-poison .metric-val {
  color: #34d399;
  text-shadow: 0 0 6px rgba(52, 211, 153, 0.3);
}

.weapon-metric-pill.metric-damage-explosive {
  border-color: rgba(245, 158, 11, 0.35);
  background: rgba(180, 83, 9, 0.2);
}
.weapon-metric-pill.metric-damage-explosive .metric-val {
  color: #f59e0b;
  text-shadow: 0 0 6px rgba(245, 158, 11, 0.3);
}

.weapon-metric-pill.metric-damage-melee {
  border-color: rgba(248, 113, 113, 0.35);
  background: rgba(185, 28, 28, 0.2);
}
.weapon-metric-pill.metric-damage-melee .metric-val {
  color: #f87171;
  text-shadow: 0 0 6px rgba(248, 113, 113, 0.3);
}

.weapon-metric-pill.metric-damage-default {
  border-color: rgba(226, 232, 240, 0.3);
  background: rgba(51, 65, 85, 0.25);
}
.weapon-metric-pill.metric-damage-default .metric-val {
  color: #f1f5f9;
}

/* Cadence & Cooldown */
.weapon-metric-pill.metric-cooldown {
  border-color: rgba(129, 140, 248, 0.3);
  background: rgba(67, 56, 202, 0.2);
}
.weapon-metric-pill.metric-cooldown .metric-val {
  color: #a5b4fc;
}

/* Delivery specs (Projectiles, Bounces, Pierces, Radius) */
.weapon-metric-pill.metric-delivery {
  border-color: rgba(168, 85, 247, 0.3);
  background: rgba(107, 33, 168, 0.2);
}
.weapon-metric-pill.metric-delivery .metric-val {
  color: #c084fc;
}

/* --- Section 3: Status & Effect Callout --- */
.weapon-desc-effects {
  background: rgba(245, 158, 11, 0.08);
  border-left: 3px solid #f59e0b;
  border-radius: 0 4px 4px 0;
  padding: 4px 8px;
  font-size: 0.72rem;
  line-height: 1.3;
  color: #fde68a;
  margin-top: 2px;
}

.weapon-desc-effects.effects-cold {
  background: rgba(56, 189, 248, 0.08);
  border-left-color: #38bdf8;
  color: #bae6fd;
}

.weapon-desc-effects.effects-fire {
  background: rgba(249, 115, 22, 0.08);
  border-left-color: #f97316;
  color: #fed7aa;
}

.weapon-desc-effects.effects-tech {
  background: rgba(192, 132, 252, 0.08);
  border-left-color: #c084fc;
  color: #e9d5ff;
}

.weapon-desc-effects strong {
  color: #ffffff;
  font-weight: 700;
}

/* --- Context Overrides --- */
/* Drop Screen Cards */
.weapon-drop-card .weapon-desc-block {
  margin-top: 4px;
}
.weapon-drop-card .weapon-desc-overview {
  font-size: 0.76rem;
  line-height: 1.25;
}

/* Weapon Tree Header */
.weapon-tree-desc .weapon-desc-block {
  gap: 6px;
}

/* Mobile Landscape Constraints */
.is-mobile .weapon-desc-block {
  gap: 4px;
}
.is-mobile .weapon-desc-overview {
  font-size: 0.72rem;
  line-height: 1.2;
}
.is-mobile .weapon-metric-pill {
  font-size: 0.66rem;
  padding: 1px 5px;
}
.is-mobile .weapon-desc-effects {
  font-size: 0.66rem;
  padding: 2px 6px;
}
/* ============================================================================
   36-cyber-transitions.css
   Universal Cyber Transition System: Scanline Sweeps, Boundary Flares & Dissolve
   ============================================================================ */

/* 1. Thematic Neon Palettes per Screen / Modal */
:root {
  --cyber-transition-color: #38bdf8;
  --cyber-transition-rgb: 56, 189, 248;
}

/* Gold / Amber Theme (Shop, Bazaar, Gear Swap, Confirmations) */
#shop-screen,
#gear-swap-screen,
#inventory-confirm-modal:not(.gamble-confirm-mode) {
  --cyber-transition-color: #fbbf24;
  --cyber-transition-rgb: 251, 191, 36;
}

/* Royal Purple Theme (Gamble For Loot, Settings Modal, Gamble Confirmation) */
#gamble-reveal-screen,
#settings-modal,
#inventory-confirm-modal.gamble-confirm-mode {
  --cyber-transition-color: #a855f7;
  --cyber-transition-rgb: 168, 85, 247;
}

/* Electric Violet Theme (Choose Your Survivor) */
#character-select-screen {
  --cyber-transition-color: #c084fc;
  --cyber-transition-rgb: 192, 132, 252;
}

/* Dual-Tone Cyan & Purple Theme (Gear Refactor Workshop) */
#gear-refactor-screen {
  --cyber-transition-color: #22d3ee;
  --cyber-transition-rgb: 34, 211, 238;
  --cyber-transition-color-2: #a855f7;
  --cyber-transition-rgb-2: 168, 85, 247;
}

/* Dual-Tone Hot Pink & Deep Purple Theme (Weapon Acquired Drop Menu) */
#weapon-drop-screen {
  --cyber-transition-color: #ff007f;
  --cyber-transition-rgb: 255, 0, 127;
  --cyber-transition-color-2: #7f00ff;
  --cyber-transition-rgb-2: 127, 0, 255;
}

/* Bio Emerald Theme (Survivor Upgrades, Difficulty Select) */
#difficulty-select-screen,
#survivor-upgrades-screen {
  --cyber-transition-color: #10b981;
  --cyber-transition-rgb: 16, 185, 129;
}

/* Crimson Danger Theme (Game Over, Round 20 Choice, Round Modifier) */
#game-over-screen,
#round-modifier-screen,
#round20-choice-screen {
  --cyber-transition-color: #ef4444;
  --cyber-transition-rgb: 239, 68, 68;
}

/* Cyber Cyan Theme (Tech, Level-Up, Instructions, Achievements, Overclock, Pause, Changelog, Major Choice) */
#level-up-screen,
#instructions-modal,
#achievements-screen,
#overclock-nexus-screen,
#pause-screen,
#pause-stats-modal,
#changelog-modal,
#major-choice-screen {
  --cyber-transition-color: #38bdf8;
  --cyber-transition-rgb: 56, 189, 248;
}

/* 2. Glass Panel Frame Setup for Scanlines */
.overlay .glass-panel {
  position: relative;
  overflow: hidden;
}

/* 3. Thematic Laser Scanline Component */
.cyber-panel-scanline {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: linear-gradient(90deg, transparent 0%, rgba(var(--cyber-transition-rgb, 56, 189, 248), 0.35) 15%, var(--cyber-transition-color, #38bdf8) 50%, rgba(var(--cyber-transition-rgb, 56, 189, 248), 0.35) 85%, transparent 100%);
  box-shadow: 0 0 10px var(--cyber-transition-color, #38bdf8), 0 0 20px rgba(var(--cyber-transition-rgb, 56, 189, 248), 0.8);
  opacity: 0;
  pointer-events: none;
  z-index: 60;
  border-radius: 2px;
}

/* Dual-Tone Laser Scanlines */
#gear-refactor-screen .cyber-panel-scanline {
  background: linear-gradient(90deg, transparent 0%, rgba(34, 211, 238, 0.4) 15%, #22d3ee 38%, #a855f7 62%, rgba(168, 85, 247, 0.4) 85%, transparent 100%) !important;
  box-shadow: 0 0 10px #22d3ee, 0 0 20px rgba(168, 85, 247, 0.85) !important;
}

#weapon-drop-screen .cyber-panel-scanline {
  background: linear-gradient(90deg, transparent 0%, rgba(255, 0, 127, 0.4) 15%, #ff007f 38%, #7f00ff 62%, rgba(127, 0, 255, 0.4) 85%, transparent 100%) !important;
  box-shadow: 0 0 10px #ff007f, 0 0 20px rgba(127, 0, 255, 0.85) !important;
}

/* Trigger scanline sweep on modal open and sub-view morphing */
.overlay.active .glass-panel .cyber-panel-scanline,
.glass-panel.is-morphing .cyber-panel-scanline {
  opacity: 1;
  animation: cyberScanlineSweep 0.24s cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
}

/* 4. Boundary Glow Flare */
.overlay.active .glass-panel,
.glass-panel.is-morphing,
#settings-modal.active .settings-modal-panel,
#character-select-screen.active .character-select-stage-frame {
  border-color: rgba(var(--cyber-transition-rgb, 56, 189, 248), 0.85) !important;
  transition: border-color 0.24s ease, box-shadow 0.24s ease;
}

/* Dual-Tone Boundary Glow Flare (Refactor & Weapon Acquired) */
#gear-refactor-screen.active .glass-panel {
  border-color: rgba(34, 211, 238, 0.85) !important;
}

#weapon-drop-screen.active .glass-panel {
  border-color: rgba(255, 0, 127, 0.85) !important;
}

/* 5. Sub-View Cross-Fade Utility Classes */
.cyber-view-dissolve {
  opacity: 0 !important;
  transform: scale(0.97) !important;
  pointer-events: none !important;
  transition: opacity 0.08s ease, transform 0.08s ease;
}

.cyber-view-materialize {
  opacity: 1 !important;
  transform: scale(1) !important;
  pointer-events: auto !important;
  transition: opacity 0.14s cubic-bezier(0.2, 0.8, 0.2, 1), transform 0.14s cubic-bezier(0.2, 0.8, 0.2, 1);
}

/* 6. Accessibility & Reduced Motion */
@media (prefers-reduced-motion: reduce) {
  .cyber-panel-scanline {
    display: none !important;
    animation: none !important;
  }
  .overlay.active .glass-panel,
  .glass-panel.is-morphing,
  #gear-refactor-screen.active .glass-panel,
  #weapon-drop-screen.active .glass-panel,
  #settings-modal.active .settings-modal-panel,
  #character-select-screen.active .character-select-stage-frame {
    transition: none !important;
  }
}
/* ==========================================================================
   The walkable Vibe Bazaar (js/bazaar-hub.js).
   #shop-screen.hub-mode: the hub canvas fills the Bazaar and the classic
   glass panel is hidden while the player walks. .hub-panel-open: a vendor
   (or the inventory) has opened the panel, which shows over the hub as it
   always did, with a Back to Bazaar button in its header. The panel's own
   inline display is flex, hence the !important pair.
   ========================================================================== */
#bazaar-hub-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: none;
  z-index: 0;
  touch-action: none;
  outline: none;
}

#shop-screen.hub-mode {
  background: #050308;
}

#shop-screen.hub-mode #bazaar-hub-canvas {
  display: block;
}

/* Leaving through the portal: #shop-screen fades out over the arena still
   showing the hub's last frame, never the classic panel (BazaarHub.goThroughPortal). */
#shop-screen.hub-leaving {
  background: #050308;
}

#shop-screen.hub-leaving #bazaar-hub-canvas {
  display: block;
}

#shop-screen.hub-leaving > .glass-panel {
  display: none !important;
}

#shop-screen.hub-mode > .glass-panel {
  display: none !important;
}

#shop-screen.hub-mode.hub-panel-open > .glass-panel {
  display: flex !important;
  z-index: 1;
}

/* The hub stays behind the open panel, dimmed (it isn't redrawn while the
   panel is up, so this costs one composite, not a per-frame filter). */
#shop-screen.hub-mode.hub-panel-open #bazaar-hub-canvas {
  filter: brightness(0.4) saturate(0.8);
}

#shop-hub-back-btn {
  display: none;
}

#shop-screen.hub-mode #shop-hub-back-btn {
  display: flex;
}

/* The B glyph only means something on a controller. */
#shop-hub-back-btn .shop-hub-back-icon {
  display: none;
}

body.input-gamepad #shop-hub-back-btn .shop-hub-back-icon {
  display: inline-block;
}

/* The hub draws its own prompts: the Bazaar panel's control hints only show
   once a panel is open. */
body.bazaar-hub-walking .control-hints-panel {
  display: none !important;
}
/* ============================================================================
   38-chaos-intro.css
   The chaos round intro's rewards card (ChaosIntro._buildRewards, js/main-loop.js):
   the Bounty Pod's four rank tiers on the chamfer kit's cards (.cx-card, .cx-tag,
   .cx-kicker from css/03b-chamfer-kit.css), with the game's own currency icons.
   Each card's --r is its tier colour. Not interactive: Continue is read by
   ChaosIntro itself, so the whole panel ignores the pointer.
   ============================================================================ */
#chaos-intro-rewards {
  --acc: var(--c-orange);
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -52%);
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  width: max-content;
  max-width: calc(100% - 32px);
  pointer-events: none;
  z-index: 30;
}

#chaos-intro-rewards.on {
  display: flex;
}

#chaos-intro-rewards .cir-head {
  display: flex;
  align-items: center;
  gap: 12px;
  animation: cir-fade 0.3s ease both;
}

#chaos-intro-rewards .cir-head::before,
#chaos-intro-rewards .cir-head::after {
  content: "";
  width: 46px;
  height: 2px;
  background: rgb(var(--acc));
}

#chaos-intro-rewards .cir-head .cx-kicker {
  margin: 0;
  font-size: 0.78rem;
  color: rgb(var(--acc));
}

#chaos-intro-rewards .cir-row {
  display: flex;
  gap: 14px;
  justify-content: center;
  flex-wrap: wrap;
}

#chaos-intro-rewards .cir-card {
  --bw: 1.5px;
  --bd: rgba(var(--r), 0.85);
  width: 186px;
  padding: 0 16px 16px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  animation: cir-deal 0.42s cubic-bezier(0.2, 0.9, 0.3, 1.15) both;
  animation-delay: calc(var(--i, 0) * 0.09s + 0.1s);
}

#chaos-intro-rewards .cir-card .cx-tag {
  --r: inherit; /* the kit's .cx-tag resets --r to slate; take the card's tier colour */
  align-self: flex-start;
  margin-left: -16px;
  font-size: 0.66rem;
}

#chaos-intro-rewards .cir-need {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 12px 0 10px;
  border-bottom: 1px dashed rgba(var(--r), 0.4);
}

#chaos-intro-rewards .cir-need b {
  font: 700 2.5rem/1 var(--font-display);
  color: #fff;
  text-shadow: 0 0 14px rgba(var(--r), 0.55);
}

#chaos-intro-rewards .cir-need small {
  font: 600 0.62rem/1 var(--font-display);
  letter-spacing: 0.24em;
  color: rgba(var(--r), 0.9);
}

#chaos-intro-rewards .cir-loot {
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 9px 10px;
}

#chaos-intro-rewards .cir-loot li {
  display: flex;
  align-items: center;
  gap: 7px;
  font: 700 0.98rem/1 var(--font-display);
  color: rgb(var(--c-text-main));
  font-variant-numeric: tabular-nums;
}

#chaos-intro-rewards .cir-loot li.cir-gear {
  grid-column: 1 / -1;
  color: rgb(var(--c-rarity-rare));
}

#chaos-intro-rewards .cir-loot li.cir-gear-legendary {
  color: rgb(var(--c-rarity-legendary));
}

#chaos-intro-rewards .cir-ico {
  width: 24px;
  height: 24px;
  object-fit: contain;
  flex-shrink: 0;
  filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.6));
}

@keyframes cir-deal {
  from { opacity: 0; transform: translateY(18px) scale(0.96); }
  to   { opacity: 1; transform: none; }
}

@keyframes cir-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Short screens and phones: smaller cards so all four still fit on one row. */
@media (max-height: 600px) {
  #chaos-intro-rewards { gap: 8px; }
  #chaos-intro-rewards .cir-row { gap: 8px; }
  #chaos-intro-rewards .cir-card { width: 138px; padding: 0 10px 10px; }
  #chaos-intro-rewards .cir-card .cx-tag { margin-left: -10px; }
  #chaos-intro-rewards .cir-need { padding: 8px 0 6px; }
  #chaos-intro-rewards .cir-need b { font-size: 1.7rem; }
  #chaos-intro-rewards .cir-loot { margin-top: 8px; gap: 6px 6px; }
  #chaos-intro-rewards .cir-loot li { font-size: 0.8rem; gap: 5px; }
  #chaos-intro-rewards .cir-ico { width: 18px; height: 18px; }
}

@media (prefers-reduced-motion: reduce) {
  #chaos-intro-rewards .cir-card,
  #chaos-intro-rewards .cir-head { animation: none; }
}
