/* GEMGRAFT type system — self-hosted variable fonts (OFL, see assets/ASSET-REGISTRY.json).
   Cinzel: engraved arcane display (wordmark, headings). Sora: UI + numerals. */
@font-face {
    font-family: 'Cinzel';
    src: url('../../assets/fonts/cinzel-var.woff2') format('woff2');
    font-weight: 400 900;
    font-display: swap;
}

@font-face {
    font-family: 'Sora';
    src: url('../../assets/fonts/sora-var.woff2') format('woff2');
    font-weight: 100 800;
    font-display: swap;
}

:root {
    --font-display: 'Cinzel', 'Times New Roman', serif;
    --font-ui: 'Sora', 'Segoe UI', Tahoma, sans-serif;
    --bg-primary: #060911;
    --bg-secondary: #0d1322;
    --panel: rgba(12, 18, 31, 0.78);
    --border: rgba(255, 255, 255, 0.1);
    --text: #ecf2ff;
    --text-muted: #8ea0c8;
    --accent: #00d4ff;
    --danger: #ff5577;
    --mana: #00ecff;
    --radius: 14px;
}

* {
    box-sizing: border-box;
}

html,
body {
    margin: 0;
    width: 100%;
    height: 100%;
    background: radial-gradient(circle at top left, #111a33, #05070f 45%);
    color: var(--text);
    font-family: var(--font-ui);
    overflow: hidden;
    overscroll-behavior: none;
    -webkit-tap-highlight-color: transparent;
}

#game-shell {
    position: relative;
    width: 100%;
    height: 100%;
    padding: 10px;
    display: grid;
    grid-template-rows: auto 1fr auto;
    gap: 10px;
    -webkit-user-select: none;
    user-select: none;
}

.glass-panel {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--panel);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    box-shadow: 0 14px 35px rgba(0, 0, 0, 0.35);
}

#top-hud {
    min-height: 64px;
    padding: var(--space-2, 8px) var(--space-3, 12px);
    display: flex;
    align-items: center;
    gap: 14px;
}

/* Pressure-readable stat chip (B2a): role-tinted icon + label + value.
   --role is set per chip (wave/mana/lives/score) further down. */
.hud-stat {
    --role: var(--accent);
    display: flex;
    align-items: center;
    gap: var(--space-2, 8px);
    min-width: 70px;
    padding: var(--space-1, 4px) var(--space-2, 8px);
    border: 1px solid color-mix(in srgb, var(--role), transparent 80%);
    border-radius: var(--radius-md, 12px);
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--role), transparent 88%),
        color-mix(in srgb, var(--role), transparent 96%));
}

.hud-stat .stat-icon {
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
    color: color-mix(in srgb, var(--role), white 18%);
    filter: drop-shadow(0 0 6px color-mix(in srgb, var(--role), transparent 55%));
}

.hud-stat .stat-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.hud-stat .label {
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 1.5px;
    font-size: 10px;
    font-weight: 700;
}

.hud-stat .value {
    font-size: 22px;
    line-height: 1.1;
    font-weight: 700;
}

.hud-stat .value.mana {
    color: var(--mana);
}

.hud-stat .value.lives {
    color: #ff788e;
}

#hud-controls {
    margin-left: auto;
    display: flex;
    gap: 8px;
}

.hud-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    border: 1px solid var(--border, rgba(255, 255, 255, 0.15));
    background: rgba(0, 0, 0, 0.3);
    color: var(--text);
    border-radius: var(--radius-md, 12px);
    padding: 10px var(--space-3, 12px);
    cursor: pointer;
    font-weight: 600;
    font-size: 13px;
    min-height: 42px;
    touch-action: manipulation;
}

.hud-btn svg {
    width: 16px;
    height: 16px;
    flex: 0 0 auto;
    fill: currentColor;
    opacity: 0.92;
}

.hud-btn:hover {
    border-color: color-mix(in srgb, var(--accent), transparent 45%);
}

#game-main {
    min-height: 0;
    display: grid;
    grid-template-columns: 1fr 320px;
    gap: 10px;
}

#battlefield-shell {
    min-height: 0;
    border-radius: var(--radius);
    overflow: hidden;
    border: 1px solid rgba(255, 255, 255, 0.08);
    background: #03050c;
}

#battlefield-stage {
    position: relative;
    width: 100%;
    height: 100%;
    touch-action: none;
}

#battlefield-stage canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

/* WebGL compositor output. Sits above the 2D source canvases (which it samples
   as textures) and below the interactive UI overlay. Hidden until activated. */
#gl-canvas {
    z-index: 4;
    pointer-events: none;
    display: none;
}

#battlefield-stage.gl-active #gl-canvas {
    display: block;
}

/* When the compositor is active the 2D source canvases are drawn only to be
   sampled as textures — keep them off the visible display. */
#battlefield-stage.gl-active #bg-canvas,
#battlefield-stage.gl-active #game-canvas,
#battlefield-stage.gl-active #fx-canvas {
    visibility: hidden;
}

#ui-overlay-canvas {
    z-index: 5;
    pointer-events: auto;
    touch-action: none;
}

#wave-banner {
    position: absolute;
    top: 14px;
    left: 50%;
    transform: translateX(-50%);
    padding: 8px 14px;
    z-index: 20;
    font-weight: 700;
    letter-spacing: 0.8px;
    color: var(--accent);
}

#wave-banner.hidden {
    opacity: 0;
    pointer-events: none;
}

#wave-banner.active {
    opacity: 1;
    transition: opacity 0.2s ease;
}

#selection-panel {
    position: absolute;
    right: 12px;
    bottom: 12px;
    width: 280px;
    padding: 12px;
    z-index: 25;
}

#selection-panel h3 {
    margin: 0 0 8px;
    font-size: 18px;
}

#selection-panel p {
    margin: 0;
    color: var(--text-muted);
    font-size: 12px;
    line-height: 1.35;
}

.selection-actions {
    margin-top: 10px;
    display: flex;
    gap: 8px;
}

.selection-actions button {
    flex: 1;
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 10px;
    padding: 8px;
    background: rgba(0, 0, 0, 0.25);
    color: var(--text);
    cursor: pointer;
    font-size: 12px;
    min-height: 42px;
    touch-action: manipulation;
}

.selection-actions button:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

#control-rail {
    min-height: 0;
    padding: var(--space-3, 12px);
    display: flex;
    flex-direction: column;
    gap: var(--space-3, 12px);
    overflow: auto;
}

.panel-block h3 {
    margin: 0 0 8px;
    font-size: 14px;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--text-muted);
}

.panel-block select,
.panel-block button {
    font-family: inherit;
}

#active-map-name {
    margin: 0;
    font-size: 16px;
    font-weight: 700;
    color: var(--text);
}

#challenge-label {
    margin: 8px 0 0;
    font-size: 11px;
    line-height: 1.3;
    color: var(--text-muted);
}

.button-grid {
    display: grid;
    gap: 8px;
}

.button-grid.two {
    grid-template-columns: 1fr 1fr;
}

.button-grid.four {
    grid-template-columns: repeat(2, 1fr);
}

.mode-btn,
.buy-gem-btn {
    border-radius: 11px;
    border: 1px solid rgba(255, 255, 255, 0.16);
    background: rgba(0, 0, 0, 0.36);
    color: var(--text);
    padding: 12px 10px;
    cursor: pointer;
    font-weight: 600;
    font-size: 13px;
    min-height: 42px;
    touch-action: manipulation;
}

.mode-btn.active {
    border-color: var(--accent);
    box-shadow: 0 0 0 1px rgba(0, 212, 255, 0.4) inset;
}

.buy-gem-btn.red {
    border-color: rgba(239, 68, 68, 0.55);
}

.buy-gem-btn.green {
    border-color: rgba(34, 197, 94, 0.55);
}

.buy-gem-btn.yellow {
    border-color: rgba(250, 204, 21, 0.55);
}

.buy-gem-btn.blue {
    border-color: rgba(59, 130, 246, 0.55);
}

.talent-list {
    display: grid;
    gap: 6px;
}

.talent-row {
    border: 1px solid rgba(255, 255, 255, 0.09);
    border-radius: 10px;
    background: rgba(0, 0, 0, 0.24);
    padding: 8px;
    display: grid;
    grid-template-columns: 1fr auto auto auto;
    align-items: center;
    gap: 6px;
    font-size: 11px;
}

.talent-row strong {
    display: block;
    font-size: 12px;
}

.talent-row small {
    color: var(--text-muted);
}

.talent-upgrade {
    width: 32px;
    height: 32px;
    border-radius: 8px;
    border: 1px solid rgba(0, 212, 255, 0.45);
    background: rgba(0, 212, 255, 0.12);
    color: var(--text);
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
}

.talent-upgrade:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

#stash-bar {
    min-height: 88px;
    padding: 10px 14px;
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-3, 12px);
    align-items: center;
}

.stash-title {
    font-size: 12px;
    letter-spacing: 1.4px;
    text-transform: uppercase;
    color: var(--text-muted);
}

#stash-grid {
    display: grid;
    grid-template-columns: repeat(8, minmax(52px, 72px));
    justify-content: start;
    gap: 10px;
}

/* Inventory cell: square, sized so the gem chip reads (bezel + pips legible).
   Every state is designed: rest / hover / focus / drop-hover / occupied / empty. */
.stash-slot {
    aspect-ratio: 1;
    min-height: 52px;
    border-radius: 14px;
    border: 1px solid rgba(148, 170, 220, 0.16);
    background:
        radial-gradient(circle at 50% 42%, rgba(120, 150, 220, 0.10), rgba(0, 0, 0, 0) 62%),
        linear-gradient(160deg, rgba(22, 30, 52, 0.85), rgba(6, 9, 18, 0.92));
    color: var(--text);
    display: grid;
    place-content: center;
    gap: 2px;
    cursor: pointer;
    touch-action: none;
    transition: transform var(--duration-fast, 150ms) ease,
        border-color var(--duration-fast, 150ms) ease,
        box-shadow var(--duration-fast, 150ms) ease;
}

.stash-slot:hover {
    border-color: rgba(160, 190, 255, 0.42);
    transform: translateY(-2px);
}

.stash-slot:focus-visible {
    outline: 2px solid rgba(120, 200, 255, 0.85);
    outline-offset: 2px;
}

/* Empty cell: a waiting socket — engraved ring + soft plus, brighter on hover. */
.stash-slot:not(.occupied) {
    border-style: dashed;
    border-color: rgba(148, 170, 220, 0.22);
}

.stash-slot:not(.occupied)::before {
    content: '';
    grid-area: 1 / 1;
    place-self: center;
    width: 58%;
    aspect-ratio: 1;
    border-radius: 50%;
    border: 1px solid rgba(148, 170, 220, 0.18);
    box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.5);
}

.stash-slot:not(.occupied):hover {
    border-color: rgba(160, 190, 255, 0.4);
}

.stash-slot.occupied {
    border-style: solid;
    border-color: color-mix(in srgb, var(--gem-color), transparent 55%);
    box-shadow:
        inset 0 0 18px color-mix(in srgb, var(--gem-color), transparent 82%),
        0 0 16px color-mix(in srgb, var(--gem-color), transparent 74%);
}

.stash-slot.occupied:hover {
    border-color: color-mix(in srgb, var(--gem-color), white 25%);
    box-shadow:
        inset 0 0 18px color-mix(in srgb, var(--gem-color), transparent 76%),
        0 0 24px color-mix(in srgb, var(--gem-color), transparent 60%);
}

/* Live drop target under a dragged gem: unmistakable ready-state. */
.stash-slot.drop-hover {
    border-style: solid;
    border-color: color-mix(in srgb, var(--gem-color, #7dd8ff), white 40%);
    box-shadow:
        inset 0 0 22px rgba(125, 216, 255, 0.25),
        0 0 26px rgba(125, 216, 255, 0.35);
    transform: translateY(-2px) scale(1.05);
}

/* Merge payoff: the cell that received the merged gem pops its upgraded chip. */
.stash-slot.merge-pop {
    animation: stash-merge-pop 620ms cubic-bezier(0.2, 0.9, 0.3, 1.35);
}

@keyframes stash-merge-pop {
    0% { transform: scale(0.82); }
    45% {
        transform: scale(1.14);
        box-shadow:
            inset 0 0 22px color-mix(in srgb, var(--gem-color), transparent 55%),
            0 0 34px color-mix(in srgb, var(--gem-color), transparent 30%);
    }
    100% { transform: scale(1); }
}

/* Chip-backed cells: the set jewel fills the cell; corner badge = exact tier. */
.stash-slot.has-sprite {
    background-repeat: no-repeat;
    background-position: center;
    background-size: 96%;
    position: relative;
}

.stash-slot.has-sprite .slot-lvl {
    position: absolute;
    right: 4px;
    bottom: 3px;
    font-size: 10px;
    padding: 1px 5px;
    border-radius: 6px;
    background: rgba(8, 12, 24, 0.78);
    border: 1px solid color-mix(in srgb, var(--gem-color), transparent 40%);
}

.slot-lvl {
    font-size: 12px;
    font-weight: 700;
}

.slot-shape {
    font-size: 10px;
    color: color-mix(in srgb, var(--gem-color), white 40%);
}

.slot-empty {
    opacity: 0.5;
    font-size: 20px;
}

.drag-ghost {
    --gem-color: #ffffff;
    position: fixed;
    width: 70px;
    height: 70px;
    transform: translate(-50%, -50%);
    border-radius: 50%;
    border: 1px solid color-mix(in srgb, var(--gem-color), white 20%);
    background: color-mix(in srgb, var(--gem-color), black 75%);
    box-shadow: 0 0 24px color-mix(in srgb, var(--gem-color), transparent 50%);
    pointer-events: none;
    z-index: 200;
    display: grid;
    place-content: center;
    text-align: center;
}

/* Chip-backed drag ghost: the gem-in-bezel is the whole visual, so drop the
   placeholder disc/border and let the chip fill. */
.drag-ghost.has-chip {
    background-color: transparent;
    border: none;
    box-shadow: none;
    background-repeat: no-repeat;
    background-position: center;
    background-size: contain;
    place-content: end center;
}

.drag-ghost .g-lvl {
    font-size: 14px;
    font-weight: 700;
}

.drag-ghost.has-chip .g-lvl {
    padding: 0 6px;
    border-radius: 6px;
    background: rgba(6, 10, 20, 0.72);
    font-size: 11px;
}

.drag-ghost .g-shape {
    margin-top: 2px;
    font-size: 10px;
}

#menu-overlay {
    position: absolute;
    inset: 0;
    z-index: 130;
    display: none;
    align-items: center;
    justify-content: center;
    background: rgba(2, 4, 10, 0.76);
}

#menu-overlay.active {
    display: flex;
}

#menu-overlay .menu-screen.hidden {
    display: none;
}

.menu-screen {
    width: min(560px, 94vw);
    padding: 24px;
}

#menu-screen-title {
    text-align: center;
}

#menu-screen-title h1 {
    margin: 0;
    font-size: clamp(32px, 5vw, 46px);
    letter-spacing: 1.2px;
}

#menu-screen-title p {
    margin: 10px 0 0;
    color: var(--text-muted);
    line-height: 1.4;
}

#menu-screen-level h2,
#menu-screen-shop h2 {
    margin: 0 0 14px;
    font-size: 26px;
}

#menu-screen-level .menu-field-label {
    display: block;
    margin: 0 0 8px;
    font-size: 11px;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    color: var(--text-muted);
}

/* Map cards (radiogroup). The route art is graded for type over its lower
   quarter, so the name plate overlays the art there rather than sitting under
   it. Selected reads as an engraved rail INSIDE the edge; focus is the shared
   ring OUTSIDE it — so a card that is both wears both, unambiguously. */
#menu-screen-level {
    width: min(940px, 94vw);
}

.map-card-grid {
    display: grid;
    /* auto-fit, not auto-fill: at the 890px menu width this resolves to FOUR
       tracks, and auto-fit then collapses the empty one to 0px along with its
       gutter so the three real cards each take the full 286px. Computed
       grid-template-columns reads "286px 286px 286px 0px" — that trailing 0px is
       the collapsed track doing its job, not a stray column. auto-fill would
       keep the fourth track at its 190px minimum and shrink every card to make
       room for nothing. */
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 14px;
    /* Room for the focus ring's 2px offset inside the scroll container. */
    padding: 2px;
    max-height: min(56vh, 540px);
    overflow-y: auto;
}

.map-card {
    position: relative;
    border-radius: 12px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    background: var(--surface-2);
    overflow: hidden;
    cursor: pointer;
    transition:
        transform 160ms cubic-bezier(0.16, 1, 0.3, 1),
        border-color 160ms ease,
        box-shadow 160ms ease;
}

.map-card-art {
    position: relative;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: var(--surface-2);
}

.map-card-art img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Held well down so the selected card is the only one at full burn. The
       eye compares neighbours, so this contrast — not the accent rail — is
       what actually carries selection at a glance. */
    filter: brightness(0.46) saturate(0.62);
    transform: scale(1);
    transition: transform 320ms cubic-bezier(0.16, 1, 0.3, 1), filter 160ms ease;
}

/* Scrim: the art clears the type-overlay gate at 11-16% lower-quarter
   variation, which is a legibility budget, not a licence to skip the scrim. */
.map-card-plate {
    position: absolute;
    inset: auto 0 0 0;
    display: grid;
    gap: 3px;
    padding: 16px 11px 9px;
    background: linear-gradient(180deg, transparent, rgba(3, 6, 13, 0.86) 46%);
}

.map-card-name {
    font-family: var(--font-display);
    font-size: 17px;
    font-weight: 700;
    line-height: 1.05;
    letter-spacing: 0.02em;
    color: var(--text-muted);
    transition: color 160ms ease;
}

.map-card-challenge {
    display: inline-block;
    font-size: 9px;
    line-height: 1.2;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.map-card-stars {
    position: absolute;
    right: 11px;
    bottom: 10px;
    display: flex;
    gap: 4px;
}

.map-card-star {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, 0.5);
    background: rgba(3, 6, 13, 0.55);
}

.map-card-star.is-earned {
    border-color: var(--accent);
    background: var(--accent);
    box-shadow: 0 0 7px color-mix(in srgb, var(--accent), transparent 45%);
}

/* Fallback: art that never decodes leaves a legible, still-selectable plate
   on an engraved field — never a blank tile. */
.map-card-artless .map-card-art img {
    display: none;
}

.map-card-artless .map-card-art {
    background:
        repeating-linear-gradient(
            118deg,
            rgba(255, 255, 255, 0.032) 0 2px,
            transparent 2px 13px
        ),
        var(--surface-1);
}

.map-card-artless .map-card-plate {
    background: none;
}

.map-card:hover {
    transform: translateY(-2px);
    border-color: rgba(255, 255, 255, 0.22);
}

.map-card:hover .map-card-art img {
    filter: brightness(1) saturate(1);
    transform: scale(1.045);
}

.map-card:active {
    transform: translateY(0) scale(0.985);
    transition-duration: 100ms;
}

/* Selection is deliberately NON-GEOMETRIC. This used to add translateY(-3px),
   which left the selected card 3px above its neighbours forever — the whole row
   read as stair-stepped at rest, because a resting state has no reason to break
   the grid's shared baseline. The accent ring, the glow, the full-burn art and
   the brightened name/challenge already carry the state four times over; the
   reduced-motion block below has always dropped this transform for exactly this
   reason. Hover/active keep their lift: those are momentary pointer feedback,
   and only ever on the card actually under the cursor. */
.map-card.is-selected {
    border-color: color-mix(in srgb, var(--accent), transparent 42%);
    box-shadow:
        inset 0 0 0 2px var(--accent),
        inset 0 1px 0 0 rgba(255, 255, 255, 0.34),
        0 0 22px color-mix(in srgb, var(--accent), transparent 62%),
        0 14px 30px rgba(0, 0, 0, 0.5);
}

/* Second, non-geometric selection signal, so the state does not rest entirely
   on an edge treatment competing with the art's own cyan route glow. */
.map-card.is-selected .map-card-challenge {
    color: var(--accent);
}

.map-card.is-selected .map-card-art img {
    filter: brightness(1) saturate(1);
}

.map-card.is-selected .map-card-name {
    color: var(--text);
}

#menu-challenge-label {
    margin: 10px 0 0;
    font-size: 12px;
    line-height: 1.35;
    color: var(--text-muted);
}

#menu-screen-shop h2 span {
    color: var(--accent);
}

.menu-actions {
    margin-top: 14px;
    display: flex;
    gap: 10px;
}

.menu-actions .menu-btn {
    flex: 1;
}

.menu-btn {
    border-radius: 10px;
    border: 1px solid rgba(255, 255, 255, 0.2);
    background: rgba(0, 0, 0, 0.36);
    color: var(--text);
    padding: 11px 14px;
    cursor: pointer;
    font-weight: 700;
    font-size: 13px;
}

.menu-btn.primary {
    border-color: rgba(0, 212, 255, 0.58);
    background: rgba(0, 212, 255, 0.18);
}

#menu-back-link {
    position: absolute;
    left: 16px;
    bottom: 16px;
    z-index: 132;
    color: var(--text);
    text-decoration: none;
    padding: 8px 12px;
    font-size: 12px;
}
#run-overlay,
#preview-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(2, 4, 10, 0.72);
}

#run-overlay {
    z-index: 120;
}

/* Outcome backdrops: owner-generated cinematic art behind the run card. The
   scrim gradient keeps the glass card readable over the bright victory sky;
   static images only, so reduced-motion needs no special-casing here. */
#run-overlay.victory {
    background:
        linear-gradient(rgba(3, 6, 14, 0.42), rgba(3, 6, 14, 0.66)),
        url("../../assets/ui/victory-bg.webp") center / cover no-repeat;
}

#run-overlay.defeat {
    background:
        linear-gradient(rgba(3, 4, 10, 0.5), rgba(3, 4, 10, 0.74)),
        url("../../assets/ui/defeat-bg.webp") center / cover no-repeat;
}

#preview-overlay {
    z-index: 140;
}
#run-overlay.hidden,
#preview-overlay.hidden,
#selection-panel.hidden {
    display: none;
}

.run-card,
.preview-card {
    width: min(420px, 92vw);
    padding: 20px;
    text-align: center;
}

.run-card h2,
.preview-card h3 {
    margin: 0 0 10px;
}

#run-summary {
    text-align: left;
    white-space: pre-wrap;
    color: var(--text-muted);
    background: rgba(0, 0, 0, 0.26);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 10px;
    padding: 10px;
    min-height: 132px;
}

#btn-play-again,
#btn-return-title,
#btn-open-fullscreen {
    margin-top: 12px;
    border-radius: 10px;
    border: 1px solid rgba(0, 212, 255, 0.5);
    background: rgba(0, 212, 255, 0.15);
    color: var(--text);
    padding: 10px 14px;
    cursor: pointer;
    font-weight: 700;
}

#btn-play-again,
#btn-return-title {
    width: 100%;
}

#btn-return-title {
    margin-top: 8px;
    border-color: rgba(255, 255, 255, 0.25);
    background: rgba(255, 255, 255, 0.08);
}
body.preview-mode #control-rail,
body.preview-mode #stash-bar,
body.preview-mode #top-hud,
body.preview-mode #selection-panel {
    opacity: 0.35;
    pointer-events: none;
}

@media (max-width: 1180px) {
    #game-main {
        grid-template-columns: 1fr;
        grid-template-rows: 1fr auto;
    }

    #control-rail {
        max-height: 280px;
    }

    #stash-grid {
        grid-template-columns: repeat(8, minmax(50px, 1fr));
    }
}

@media (orientation: portrait) and (max-width: 980px) {
    #game-shell {
        padding: 5px;
        gap: 5px;
    }

    #top-hud {
        flex-wrap: wrap;
        gap: 4px;
        padding: 6px 8px;
        min-height: 58px;
    }

    .hud-stat {
        min-width: 56px;
    }

    .hud-stat .label {
        font-size: 9px;
        letter-spacing: 1px;
    }

    .hud-stat .value {
        font-size: 16px;
    }

    #hud-controls {
        width: 100%;
        margin-left: 0;
        gap: 6px;
        touch-action: manipulation;
    }

    #hud-controls .hud-btn {
        flex: 1;
        min-height: 40px;
        font-size: 12px;
        padding: 8px 8px;
    }

    #game-main {
        grid-template-columns: 1fr;
        grid-template-rows: minmax(34vh, 40vh) auto;
    }

    #battlefield-shell {
        min-height: 34vh;
        border-radius: 14px;
    }

    #control-rail {
        max-height: 136px;
        min-height: 118px;
        display: grid;
        grid-auto-flow: column;
        grid-auto-columns: minmax(176px, 1fr);
        gap: 8px;
        padding: 8px;
        overflow-x: auto;
        overflow-y: hidden;
        scroll-snap-type: x mandatory;
        touch-action: pan-x;
    }

    #control-rail .panel-block {
        min-height: 100%;
        border: 1px solid rgba(255, 255, 255, 0.1);
        border-radius: 10px;
        padding: 8px;
        background: rgba(0, 0, 0, 0.2);
        scroll-snap-align: start;
    }

    #control-rail .panel-block h3 {
        margin-bottom: 6px;
        font-size: 12px;
        letter-spacing: 0.9px;
    }

    #challenge-label {
        margin-top: 5px;
        font-size: 10px;
        line-height: 1.2;
    }

    .mode-btn,
    .buy-gem-btn,
    .selection-actions button {
        min-height: 36px;
        font-size: 12px;
        padding: 7px 6px;
        border-radius: 9px;
    }

    #stash-bar {
        grid-template-columns: 1fr;
        gap: 5px;
        min-height: auto;
        padding: 6px 8px;
    }

    .stash-title {
        font-size: 11px;
        letter-spacing: 1px;
    }

    /* Mobile inventory rail: fixed thumb-sized cells that scroll horizontally
       instead of squeezing 8 unreadable cells into the viewport. */
    #stash-grid {
        grid-template-columns: repeat(8, 48px);
        gap: 6px;
        overflow-x: auto;
        padding-bottom: 4px;
        -webkit-overflow-scrolling: touch;
    }

    .stash-slot {
        min-height: 48px;
        border-radius: 12px;
    }

    .slot-lvl {
        font-size: 11px;
    }

    .slot-shape {
        font-size: 9px;
    }

    .slot-empty {
        font-size: 13px;
    }

    .menu-actions {
        flex-direction: column;
    }

    #menu-back-link {
        left: 12px;
        bottom: 12px;
    }
}

body.egg-prismatic {
    background: radial-gradient(circle at 20% 10%, #2a1a44, #060911 40%, #102241);
}

body.egg-prismatic .glass-panel {
    border-color: rgba(123, 47, 255, 0.35);
}

body.egg-void #fx-canvas {
    filter: hue-rotate(140deg) saturate(1.2);
}






:root {
    /* B1 design tokens. Values audited against the pre-token render: no drift.
       (--text / --danger / --mana live in the base :root at the top of file.) */
    /* Surfaces: glass levels, panel base (0) to raised controls (2). */
    --surface-0: linear-gradient(180deg, rgba(16, 24, 42, 0.88), rgba(8, 13, 25, 0.82));
    --surface-1: linear-gradient(180deg, rgba(12, 20, 36, 0.9), rgba(6, 10, 20, 0.84));
    --surface-2: linear-gradient(180deg, rgba(10, 17, 31, 0.92), rgba(4, 8, 18, 0.88));
    --panel: var(--surface-0);
    --border: rgba(171, 208, 255, 0.12);
    --text-muted: #9eb0d6;
    /* Color roles: accent = arcane cyan; HUD resource/vital/score roles. */
    --accent: #6be8ff;
    --resource-mana: #7ff5ff;
    --vital-lives: #ff9ab2;
    --score: #ffe08d;
    /* Gem colors — mirror Config.GEM.BASE_COLORS exactly (affinity glyphs). */
    --gem-red: #ef4444;
    --gem-green: #22c55e;
    --gem-yellow: #facc15;
    --gem-blue: #3b82f6;
    /* Spacing rhythm (4px base). */
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 20px;
    /* Radii, motion, elevation. */
    --radius-sm: 9px;
    --radius-md: 12px;
    --radius-lg: 14px;
    --radius: 16px;
    --duration-fast: 150ms;
    --duration-normal: 300ms;
    --ease-out: ease;
    --shadow-1: 0 10px 24px rgba(0, 0, 0, 0.22);
    --shadow-2: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 18px 45px rgba(0, 0, 0, 0.42);
}

html,
body {
    background:
        radial-gradient(circle at 14% 12%, rgba(74, 114, 255, 0.16), transparent 26%),
        radial-gradient(circle at 82% 18%, rgba(0, 212, 255, 0.12), transparent 24%),
        radial-gradient(circle at 50% 100%, rgba(113, 72, 255, 0.12), transparent 30%),
        linear-gradient(180deg, #050813, #02040a 72%);
    font-family: var(--font-ui);
}

body::before,
body::after {
    content: '';
    position: fixed;
    inset: -12%;
    pointer-events: none;
    z-index: -1;
}

body::before {
    background:
        radial-gradient(circle at 24% 30%, rgba(90, 118, 255, 0.16), transparent 22%),
        radial-gradient(circle at 74% 24%, rgba(0, 212, 255, 0.13), transparent 20%),
        radial-gradient(circle at 52% 72%, rgba(167, 96, 255, 0.11), transparent 26%);
    filter: blur(28px);
    animation: body-drift 18s ease-in-out infinite alternate;
}

body::after {
    background: linear-gradient(115deg, transparent 0%, rgba(255, 255, 255, 0.03) 46%, transparent 52%);
    opacity: 0.7;
    animation: body-sheen 14s linear infinite;
}

.glass-panel {
    border: 1px solid var(--border);
    background: var(--panel);
    box-shadow: var(--shadow-2);
}

#top-hud {
    position: relative;
    min-height: 70px;
    overflow: hidden;
    gap: var(--space-4, 16px);
}

#top-hud::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.05), transparent);
    transform: translateX(-100%);
    animation: hud-sheen 9s linear infinite;
    pointer-events: none;
}

.hud-stat {
    position: relative;
    min-width: 78px;
}

.hud-stat .value {
    text-shadow: 0 0 18px rgba(255, 255, 255, 0.08);
}

#hud-controls {
    flex-wrap: wrap;
    justify-content: flex-end;
}

.hud-btn,
.mode-btn,
.buy-gem-btn,
.menu-btn,
.selection-actions button,
#btn-play-again,
#btn-return-title,
#btn-open-fullscreen {
    position: relative;
    overflow: hidden;
    transition:
        transform var(--duration-fast, 150ms) var(--ease-out, ease),
        border-color var(--duration-fast, 150ms) var(--ease-out, ease),
        box-shadow var(--duration-fast, 150ms) var(--ease-out, ease),
        background var(--duration-fast, 150ms) var(--ease-out, ease);
}

.hud-btn::before,
.mode-btn::before,
.buy-gem-btn::before,
.menu-btn::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(120deg, transparent, rgba(255, 255, 255, 0.09), transparent 72%);
    transform: translateX(-130%);
    transition: transform 0.22s ease;
}

.hud-btn:hover::before,
.mode-btn:hover::before,
.buy-gem-btn:hover::before,
.menu-btn:hover::before {
    transform: translateX(130%);
}

.hud-btn:hover,
.mode-btn:hover,
.buy-gem-btn:hover,
.menu-btn:hover,
.selection-actions button:hover,
#btn-play-again:hover,
#btn-return-title:hover,
#btn-open-fullscreen:hover {
    transform: translateY(-1px);
    box-shadow: var(--shadow-1);
}

.hud-btn:active,
.mode-btn:active,
.buy-gem-btn:active,
.menu-btn:active,
.selection-actions button:active {
    transform: translateY(0);
}

.hud-btn {
    background: var(--surface-2);
}

.hud-btn:active {
    transform: translateY(0) scale(0.97);
}

/* Keyboard focus ring on every interactive control. */
.hud-btn:focus-visible,
.hud-actions-toggle:focus-visible,
.mode-btn:focus-visible,
.buy-gem-btn:focus-visible,
.menu-btn:focus-visible,
.talent-upgrade:focus-visible,
.selection-actions button:focus-visible,
.map-card:focus-visible,
#btn-play-again:focus-visible,
#btn-return-title:focus-visible,
#btn-open-fullscreen:focus-visible,
#menu-back-link:focus-visible {
    outline: 2px solid color-mix(in srgb, var(--accent), transparent 15%);
    outline-offset: 2px;
}

.hud-btn.accent {
    border-color: rgba(107, 232, 255, 0.5);
    background: linear-gradient(180deg, rgba(7, 46, 66, 0.92), rgba(3, 20, 34, 0.92));
    box-shadow: inset 0 0 0 1px rgba(107, 232, 255, 0.12);
}

#battlefield-shell {
    background:
        radial-gradient(circle at 50% 0%, rgba(113, 164, 255, 0.08), transparent 40%),
        linear-gradient(180deg, rgba(5, 9, 19, 0.98), rgba(3, 6, 12, 1));
    box-shadow:
        inset 0 0 0 1px rgba(255, 255, 255, 0.02),
        inset 0 -40px 80px rgba(0, 0, 0, 0.25),
        0 28px 80px rgba(0, 0, 0, 0.45);
}

#wave-banner {
    top: 20px;
    padding: 10px 16px;
    border-color: rgba(107, 232, 255, 0.18);
    background: linear-gradient(180deg, rgba(10, 19, 36, 0.88), rgba(7, 13, 24, 0.82));
    box-shadow: 0 14px 30px rgba(0, 0, 0, 0.32);
}

#wave-banner.active {
    animation: wave-banner-in 220ms ease;
}

#selection-panel {
    background: var(--panel);
    box-shadow: 0 20px 36px rgba(0, 0, 0, 0.34);
}

.selection-actions button:hover {
    border-color: rgba(107, 232, 255, 0.38);
}

.mode-btn,
.buy-gem-btn,
.menu-btn,
.selection-actions button {
    background: var(--surface-1);
}

.mode-btn.active {
    box-shadow:
        inset 0 0 0 1px rgba(107, 232, 255, 0.3),
        0 0 28px rgba(0, 212, 255, 0.14);
}

.talent-row {
    background: linear-gradient(180deg, rgba(9, 15, 29, 0.84), rgba(4, 8, 16, 0.82));
}

/* (stash-slot surface/hover/occupied design lives in the primary block above —
   the inventory-cell redesign consolidated the earlier polish overrides.) */

.drag-ghost {
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
}

#menu-overlay {
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    background:
        radial-gradient(circle at top, rgba(62, 104, 255, 0.22), transparent 30%),
        rgba(2, 4, 10, 0.78);
}

body.in-run-menu #menu-overlay {
    background:
        radial-gradient(circle at top, rgba(0, 212, 255, 0.18), transparent 34%),
        rgba(2, 5, 12, 0.82);
}

.menu-screen {
    border: 1px solid rgba(255, 255, 255, 0.08);
    background: var(--surface-1);
    box-shadow: 0 30px 70px rgba(0, 0, 0, 0.42);
    animation: menu-screen-in 220ms ease;
}

#menu-screen-pause h2,
#menu-screen-title h1,
#menu-screen-level h2,
#menu-screen-shop h2 {
    text-shadow: 0 0 24px rgba(255, 255, 255, 0.08);
}

#menu-run-summary {
    margin: 14px 0 0;
    padding: 10px 12px;
    border-radius: 12px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    background: rgba(0, 0, 0, 0.22);
    color: var(--text-muted);
    line-height: 1.5;
}

.menu-actions-stack {
    flex-direction: column;
}

#menu-back-link {
    box-shadow: 0 12px 26px rgba(0, 0, 0, 0.28);
    transition: transform 0.16s ease, border-color 0.16s ease;
}

#menu-back-link:hover {
    transform: translateY(-1px);
    border-color: rgba(107, 232, 255, 0.3);
}

#menu-back-link.hidden {
    display: none;
}

.run-card,
.preview-card {
    background: var(--surface-1);
    box-shadow: 0 30px 70px rgba(0, 0, 0, 0.42);
}

#run-summary {
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
}

.hidden {
    display: none !important;
}

@keyframes body-drift {
    from {
        transform: translate3d(-2%, -1%, 0) scale(1);
    }
    to {
        transform: translate3d(2%, 1%, 0) scale(1.04);
    }
}

@keyframes body-sheen {
    from {
        transform: translateX(-18%);
    }
    to {
        transform: translateX(18%);
    }
}

@keyframes hud-sheen {
    from {
        transform: translateX(-120%);
    }
    to {
        transform: translateX(120%);
    }
}

@keyframes wave-banner-in {
    from {
        opacity: 0;
        transform: translate(-50%, -8px);
    }
    to {
        opacity: 1;
        transform: translate(-50%, 0);
    }
}

@keyframes menu-screen-in {
    from {
        opacity: 0;
        transform: translateY(8px) scale(0.985);
    }
    to {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

@media (orientation: portrait) and (max-width: 980px) {
    #hud-controls {
        justify-content: stretch;
    }

    #hud-controls .hud-btn {
        flex: 1 1 calc(50% - 4px);
    }

    #menu-run-summary {
        font-size: 11px;
    }
}

@media (orientation: landscape) and (max-height: 540px) {
    #game-shell {
        padding: 4px;
        gap: 4px;
    }

    #top-hud {
        min-height: 52px;
        padding: 5px 8px;
        gap: 5px;
    }

    .hud-stat {
        min-width: 52px;
    }

    .hud-stat .label {
        font-size: 9px;
        letter-spacing: 1px;
    }

    .hud-stat .value {
        font-size: 15px;
    }

    #hud-controls {
        gap: 5px;
    }

    #hud-controls .hud-btn {
        min-height: 40px;
        font-size: 12px;
        padding: 6px 8px;
    }

    #game-main {
        grid-template-rows: minmax(42vh, 48vh) auto;
        gap: 6px;
    }

    #control-rail {
        max-height: 114px;
        min-height: 100px;
        display: grid;
        grid-auto-flow: column;
        grid-auto-columns: minmax(170px, 1fr);
        gap: 6px;
        padding: 6px;
        overflow-x: auto;
        overflow-y: hidden;
        scroll-snap-type: x mandatory;
    }

    #control-rail .panel-block {
        min-height: 100%;
        border: 1px solid rgba(255, 255, 255, 0.1);
        border-radius: 10px;
        padding: 7px;
        background: rgba(0, 0, 0, 0.2);
        scroll-snap-align: start;
    }

    #control-rail .panel-block h3 {
        margin-bottom: 5px;
        font-size: 12px;
    }

    .mode-btn,
    .buy-gem-btn {
        min-height: 34px;
        font-size: 12px;
        padding: 6px 6px;
        border-radius: 9px;
    }

    #stash-bar {
        padding: 5px 8px;
        gap: 5px;
    }

    .stash-title {
        font-size: 11px;
        letter-spacing: 1px;
    }

    /* Short-landscape inventory rail: same scrollable fixed-cell pattern. */
    #stash-grid {
        grid-template-columns: repeat(8, 44px);
        gap: 6px;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

    .stash-slot {
        min-height: 44px;
        border-radius: 11px;
    }

.slot-empty {
        font-size: 13px;
    }
}

.hud-actions-toggle {
    display: none;
    border: 1px solid rgba(255, 255, 255, 0.2);
    background: linear-gradient(180deg, rgba(10, 17, 31, 0.92), rgba(4, 8, 18, 0.88));
    color: var(--text);
    border-radius: 10px;
    width: 38px;
    height: 38px;
    padding: 0;
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    place-items: center;
    touch-action: manipulation;
}

@media (orientation: portrait) and (max-width: 980px), (orientation: landscape) and (max-height: 540px) {
    #top-hud {
        overflow: visible;
        position: relative;
    }

    /* Compact chips: tint carries the role; icons yield width back to values. */
    .hud-stat .stat-icon {
        display: none;
    }

    .hud-stat {
        padding: 2px var(--space-1, 4px);
        border-radius: var(--radius-sm, 9px);
    }

    .hud-actions-toggle {
        display: grid;
        margin-left: auto;
        flex: 0 0 auto;
    }

    #hud-controls {
        position: absolute;
        top: calc(100% + 6px);
        right: 8px;
        width: min(230px, calc(100vw - 18px));
        padding: 8px;
        border-radius: 12px;
        border: 1px solid rgba(255, 255, 255, 0.16);
        background: linear-gradient(180deg, rgba(12, 20, 36, 0.96), rgba(6, 10, 18, 0.92));
        box-shadow: 0 18px 35px rgba(0, 0, 0, 0.42);
        display: none;
        grid-template-columns: 1fr 1fr;
        gap: 6px;
        z-index: 90;
        margin-left: 0;
    }

    #top-hud.hud-controls-open #hud-controls {
        display: grid;
    }

    #hud-controls .hud-btn {
        min-height: 40px;
        font-size: 12px;
        padding: 7px 8px;
    }
}

#boot-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(2, 5, 12, 0.84);
    z-index: 160;
}

#boot-overlay.hidden {
    display: none;
}

.boot-card {
    width: min(520px, 92vw);
}

#boot-overlay-message {
    margin: 0 0 12px;
    color: var(--text);
}

#boot-overlay-detail {
    margin: 0;
    white-space: pre-wrap;
    text-align: left;
    color: var(--text-muted);
    background: rgba(0, 0, 0, 0.24);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 12px;
    padding: 12px;
    font: 12px/1.5 Consolas, 'Courier New', monospace;
}

/* ==========================================================================
   2026-03 UI PASS: MOBILE MAP PRIORITY + BUBBLE-FILM RAINBOW TYPOGRAPHY
   ========================================================================== */

:root {
    --bubble-rainbow: linear-gradient(120deg, #67e8f9 0%, #86efac 18%, #fef08a 34%, #fdba74 50%, #f9a8d4 66%, #c4b5fd 82%, #67e8f9 100%);
}

#menu-screen-title h1,
#menu-screen-pause h2,
#menu-screen-level h2,
#menu-screen-shop h2,
#run-title {
    background: var(--bubble-rainbow);
    background-size: 220% auto;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    animation: gem-rainbow-shift 11s linear infinite;
}

/* Chip role colors: wave=accent, mana=arcane blue, lives=vital pink, score=gold. */
#top-hud .hud-stat.wave {
    --role: var(--accent);
}

#top-hud .hud-stat.mana {
    --role: var(--resource-mana);
}

#top-hud .hud-stat.lives {
    --role: var(--vital-lives);
}

#top-hud .hud-stat.score {
    --role: var(--score);
}

#top-hud .hud-stat .value {
    color: var(--role);
}

/* Pressure readability: UIManager toggles .danger when lives run low. */
#top-hud .hud-stat.lives.danger {
    --role: var(--danger);
    animation: hud-danger-pulse 1s ease-in-out infinite;
}

@keyframes hud-danger-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(255, 85, 119, 0); }
    50% { box-shadow: 0 0 16px 2px rgba(255, 85, 119, 0.38); }
}

.panel-block h3,
.stash-title {
    color: #b5c7ff;
}

@keyframes gem-rainbow-shift {
    0% {
        background-position: 0% 50%;
    }

    100% {
        background-position: 220% 50%;
    }
}

@media (prefers-reduced-motion: reduce) {
    #menu-screen-title h1,
    #menu-screen-pause h2,
    #menu-screen-level h2,
    #menu-screen-shop h2,
    #run-title {
        animation: none;
        background-size: 100% auto;
    }

    .stash-slot.merge-pop {
        animation: none;
    }

    /* Selected/hover still change — they just stop moving and stop easing. */
    .map-card,
    .map-card-art img {
        transition: none;
    }

    /* .is-selected is redundant HERE by design: its resting translateY was
       removed so the row keeps one baseline, so it has no transform left to
       cancel. Kept as the forward guard — if a resting lift is ever
       reintroduced, reduced motion already refuses it. */
    .map-card:hover,
    .map-card:active,
    .map-card.is-selected {
        transform: none;
    }

    .map-card:hover .map-card-art img {
        transform: none;
    }

    .stash-slot,
    .stash-slot:hover,
    .stash-slot.drop-hover {
        transition: none;
        transform: none;
    }

    #top-hud .hud-stat .label,
    #control-rail .panel-block h3,
    .stash-title {
        animation: none;
        background-size: 100% auto;
    }

    /* Danger stays readable through the static tint alone. */
    #top-hud .hud-stat.lives.danger {
        animation: none;
    }

    /* E1: title wordmark is static under reduced motion (no rise/scale, no glow
       pulse). The E1 animation rule is appended later in the file at equal
       specificity, so !important is required to win the cascade regardless of
       source order (idiomatic reduced-motion kill). Base opacity/transform
       (1 / none) apply once the animation is gone. */
    #menu-overlay.title-mode #menu-screen-title h1 {
        animation: none !important;
        opacity: 1;
        transform: none;
    }
}

/* Mobile portrait: reclaim vertical space for larger battlefield */
@media (orientation: portrait) and (max-width: 980px) {
    #game-shell {
        padding: 3px;
        gap: 4px;
        grid-template-rows: auto minmax(0, 1fr) auto;
    }

    #top-hud {
        min-height: 52px;
        padding: 5px 7px;
        gap: 6px;
    }

    .hud-stat {
        min-width: 48px;
    }

    .hud-stat .label {
        font-size: 8px;
        letter-spacing: 0.9px;
    }

    .hud-stat .value {
        font-size: 14px;
    }

    #game-main {
        grid-template-columns: 1fr;
        grid-template-rows: minmax(0, 1fr) auto;
        gap: 4px;
    }

    #battlefield-shell {
        min-height: 0;
        height: 100%;
        border-radius: 12px;
    }

    #control-rail {
        max-height: 104px;
        min-height: 92px;
        padding: 6px;
        gap: 6px;
        grid-auto-columns: minmax(150px, 1fr);
    }

    #control-rail .panel-block {
        padding: 6px;
    }

    #control-rail .panel-block h3 {
        margin-bottom: 4px;
        font-size: 11px;
        letter-spacing: 0.6px;
    }

    #active-map-name {
        font-size: 13px;
    }

    #challenge-label {
        margin-top: 4px;
        font-size: 9px;
        line-height: 1.15;
    }

    .mode-btn,
    .buy-gem-btn,
    .selection-actions button {
        min-height: 32px;
        font-size: 11px;
        padding: 5px 6px;
        border-radius: 8px;
    }

    #stash-bar {
        padding: 5px 7px;
        gap: 4px;
    }

    .stash-title {
        font-size: 10px;
        letter-spacing: 0.8px;
    }

    #stash-grid {
        gap: 6px;
    }

    /* Rail cells stay legible; the grid scrolls instead of squashing. */
    .stash-slot {
        min-height: 44px;
        border-radius: 11px;
    }

    .slot-lvl {
        font-size: 10px;
    }

    .slot-shape {
        font-size: 8px;
    }

    .slot-empty {
        font-size: 12px;
    }

    #selection-panel {
        right: 8px;
        left: 8px;
        bottom: 8px;
        width: auto;
        padding: 9px;
    }

    #selection-panel h3 {
        font-size: 14px;
    }

    #selection-panel p {
        font-size: 11px;
    }
}

/* Mobile landscape: keep map dominant */
@media (orientation: landscape) and (max-height: 540px) {
    #game-main {
        grid-template-rows: minmax(0, 1fr) auto;
    }

    #battlefield-shell {
        min-height: 0;
    }

    #control-rail {
        max-height: 96px;
        min-height: 88px;
        grid-auto-columns: minmax(156px, 1fr);
    }

    #stash-bar {
        padding: 4px 6px;
    }

    .stash-slot {
        min-height: 42px;
    }
}

/* Second compact pass: force battlefield priority on real phone viewports */
@media (orientation: portrait) and (max-width: 980px) {
    #game-shell {
        height: 100dvh;
        padding: 2px !important;
        gap: 3px !important;
        grid-template-rows: auto minmax(0, 1fr) auto !important;
    }

    #top-hud {
        min-height: 44px !important;
        padding: 4px 6px !important;
        gap: 4px !important;
        border-radius: 11px;
    }

    #top-hud .hud-stat {
        min-width: 44px !important;
    }

    #top-hud .hud-stat .label {
        font-size: 7px !important;
        letter-spacing: 0.7px !important;
    }

    #top-hud .hud-stat .value {
        font-size: 13px !important;
        line-height: 1 !important;
    }

    .hud-actions-toggle {
        width: 34px;
        height: 34px;
        font-size: 17px;
        border-radius: 9px;
    }

    #game-main {
        min-height: 0;
        height: 100%;
        grid-template-columns: 1fr !important;
        grid-template-rows: minmax(0, 1fr) auto !important;
        gap: 3px !important;
        align-content: stretch;
    }

    #battlefield-shell {
        min-height: 0 !important;
        height: 100%;
        border-radius: 11px;
    }

    #control-rail {
        max-height: 78px !important;
        min-height: 70px !important;
        padding: 4px !important;
        gap: 4px !important;
        grid-auto-columns: minmax(138px, 1fr) !important;
    }

    #control-rail .panel-block {
        padding: 5px !important;
    }

    #control-rail .panel-block h3 {
        margin-bottom: 3px !important;
        font-size: 10px !important;
        letter-spacing: 0.6px !important;
    }

    #active-map-name {
        font-size: 12px !important;
        line-height: 1.15;
    }

    #challenge-label {
        display: none;
    }

    .mode-btn,
    .buy-gem-btn,
    .selection-actions button {
        min-height: 30px !important;
        font-size: 10px !important;
        padding: 4px 5px !important;
        border-radius: 8px !important;
    }

    #stash-bar {
        grid-template-columns: auto 1fr !important;
        min-height: 52px !important;
        padding: 4px 6px !important;
        gap: 6px !important;
        align-items: center;
    }

    .stash-title {
        font-size: 9px !important;
        letter-spacing: 0.6px !important;
        white-space: nowrap;
    }

    #stash-grid {
        gap: 6px !important;
    }

    .stash-slot {
        min-height: 44px !important;
        border-radius: 11px !important;
    }

    .slot-lvl {
        font-size: 9px !important;
    }

    .slot-shape {
        font-size: 7px !important;
    }

    .slot-empty {
        font-size: 11px !important;
    }

    #selection-panel {
        right: 6px;
        left: 6px;
        bottom: 6px;
        width: auto;
        padding: 8px;
    }

    #selection-panel h3 {
        font-size: 13px;
    }

    #selection-panel p {
        font-size: 10px;
    }
}

@media (orientation: landscape) and (max-height: 540px) {
    #game-shell {
        height: 100dvh;
        padding: 2px !important;
        gap: 3px !important;
    }

    #game-main {
        grid-template-rows: minmax(0, 1fr) auto !important;
        gap: 3px !important;
    }

    #control-rail {
        max-height: 74px !important;
        min-height: 66px !important;
        grid-auto-columns: minmax(132px, 1fr) !important;
    }

    #stash-bar {
        min-height: 58px !important;
    }

    .stash-slot {
        min-height: 42px !important;
    }
}

/* Rainbow typography accents in-game */
#top-hud .hud-stat .label,
#control-rail .panel-block h3,
.stash-title {
    background: var(--bubble-rainbow);
    background-size: 220% auto;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    animation: gem-rainbow-shift 13s linear infinite;
}

/* Final mobile fit pass: remove oversized level card and fit build/buy controls cleanly */
@media (orientation: portrait) and (max-width: 980px) {
    #control-rail {
        display: grid !important;
        grid-template-columns: 1fr 1fr !important;
        grid-auto-flow: row !important;
        grid-auto-columns: initial !important;
        max-height: 76px !important;
        min-height: 68px !important;
        overflow: hidden !important;
        overflow-x: hidden !important;
        overflow-y: hidden !important;
        scroll-snap-type: none !important;
        padding: 4px !important;
        gap: 4px !important;
    }

    #control-rail .panel-block:first-child {
        display: none !important;
    }

    #control-rail .panel-block {
        min-height: 0 !important;
        padding: 4px !important;
        border-radius: 8px !important;
    }

    #control-rail .panel-block h3 {
        margin-bottom: 3px !important;
        font-size: 9px !important;
        letter-spacing: 0.7px !important;
    }

    #control-rail .button-grid.two,
    #control-rail .button-grid.four {
        gap: 3px !important;
    }

    #control-rail .button-grid.four {
        grid-template-columns: 1fr 1fr !important;
    }

    #control-rail .mode-btn,
    #control-rail .buy-gem-btn {
        min-height: 25px !important;
        padding: 2px 3px !important;
        font-size: 8px !important;
        line-height: 1.1 !important;
        border-radius: 7px !important;
        white-space: normal;
        word-break: break-word;
    }

    #stash-bar {
        min-height: 48px !important;
    }

    .stash-title {
        font-size: 8px !important;
    }

    .stash-slot {
        min-height: 40px !important;
    }
}

@media (orientation: landscape) and (max-height: 540px) {
    #control-rail .panel-block:first-child {
        display: none !important;
    }

    #control-rail {
        grid-template-columns: 1fr 1fr !important;
        grid-auto-flow: row !important;
        grid-auto-columns: initial !important;
        max-height: 66px !important;
        min-height: 60px !important;
        overflow: hidden !important;
        scroll-snap-type: none !important;
    }
}

/* Hard mobile fit: guaranteed no button clipping */
@media (orientation: portrait) and (max-width: 980px) {
    #control-rail {
        display: grid !important;
        grid-template-columns: 1fr 1fr !important;
        grid-template-areas: "build buy" !important;
        grid-auto-flow: row !important;
        grid-auto-columns: initial !important;
        max-height: 102px !important;
        min-height: 102px !important;
        padding: 6px !important;
        gap: 6px !important;
        overflow: hidden !important;
    }

    #control-rail .panel-block:first-child {
        display: none !important;
    }

    #control-rail .panel-block:nth-child(2) {
        grid-area: build;
    }

    #control-rail .panel-block:nth-child(3) {
        grid-area: buy;
    }

    #control-rail .panel-block {
        padding: 6px !important;
        min-height: 0 !important;
        border-radius: 9px !important;
    }

    #control-rail .panel-block h3 {
        margin-bottom: 4px !important;
        font-size: 10px !important;
        letter-spacing: 0.7px !important;
        line-height: 1 !important;
    }

    #control-rail .button-grid.two {
        grid-template-columns: 1fr 1fr !important;
        gap: 4px !important;
    }

    #control-rail .button-grid.four {
        grid-template-columns: 1fr 1fr !important;
        gap: 4px !important;
    }

    #control-rail .mode-btn,
    #control-rail .buy-gem-btn {
        min-height: 29px !important;
        padding: 4px 4px !important;
        font-size: 9px !important;
        line-height: 1.1 !important;
        border-radius: 8px !important;
        display: flex;
        align-items: center;
        justify-content: center;
        text-align: center;
    }

    #stash-bar {
        min-height: 54px !important;
        padding: 4px 6px !important;
    }

    .stash-slot {
        min-height: 40px !important;
    }
}

@media (orientation: landscape) and (max-height: 540px) {
    #control-rail {
        max-height: 88px !important;
        min-height: 88px !important;
        grid-template-columns: 1fr 1fr !important;
        grid-auto-flow: row !important;
        grid-auto-columns: initial !important;
        padding: 5px !important;
        gap: 5px !important;
        overflow: hidden !important;
    }

    #control-rail .panel-block:first-child {
        display: none !important;
    }

    #control-rail .button-grid.four {
        grid-template-columns: 1fr 1fr !important;
    }

    #control-rail .mode-btn,
    #control-rail .buy-gem-btn {
        min-height: 26px !important;
        font-size: 8px !important;
        padding: 3px 4px !important;
    }
}

#coach-hint {
    position: absolute;
    left: 14px;
    top: 68px;
    z-index: 24;
    width: min(320px, calc(100% - 28px));
    padding: 10px 12px;
    border-color: rgba(107, 232, 255, 0.22);
    background: linear-gradient(180deg, rgba(10, 18, 34, 0.94), rgba(5, 9, 18, 0.9));
    pointer-events: none;
}

.coach-label {
    display: block;
    margin-bottom: 6px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 1.1px;
    text-transform: uppercase;
    color: var(--accent);
}

#coach-hint-text {
    margin: 0;
    color: var(--text);
    font-size: 12px;
    line-height: 1.4;
}

.selection-body {
    display: grid;
    gap: 8px;
}

.selection-role {
    font-size: 13px;
    font-weight: 700;
    color: var(--text);
}

.selection-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.selection-tag {
    border: 1px solid rgba(107, 232, 255, 0.22);
    border-radius: 999px;
    padding: 3px 8px;
    font-size: 10px;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: #c7f6ff;
    background: rgba(0, 212, 255, 0.08);
}

.selection-gemline {
    color: var(--text-muted);
    font-size: 12px;
    line-height: 1.35;
}

.selection-stats {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 6px;
}

.selection-stat {
    font-size: 11px;
    color: var(--text-muted);
}

.selection-stat strong {
    color: var(--text);
}

@media (orientation: portrait) and (max-width: 980px) {
    #coach-hint {
        top: 54px;
        left: 8px;
        width: min(270px, calc(100% - 16px));
        padding: 8px 10px;
    }

    #coach-hint-text {
        font-size: 11px;
    }

    .selection-stats {
        grid-template-columns: 1fr 1fr;
    }
}

/* ---- GEMGRAFT type application (T1 identity polish) ---- */
#menu-screen-title h1 {
    font-family: var(--font-display);
    font-weight: 800;
    letter-spacing: 0.12em;
    text-shadow: 0 0 22px rgba(90, 180, 255, 0.55), 0 0 52px rgba(160, 90, 255, 0.3);
}

.menu-screen h2,
#run-title {
    font-family: var(--font-display);
    font-weight: 700;
    letter-spacing: 0.06em;
}

#wave-banner,
.stash-title,
.panel-block h3,
.hud-stat .label {
    font-family: var(--font-ui);
}

.hud-stat .value {
    font-variant-numeric: tabular-nums;
}

#btn-mute svg {
    width: 17px;
    height: 17px;
    display: block;
    fill: currentColor;
}

/* ==========================================================================
   B2b-B5: rail cards, selection, menus, feedback surfaces (token system)
   ========================================================================== */

/* Build / Buy cards: element-tinted icon + name + mana cost chip. */
.mode-btn,
.buy-gem-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-1, 4px);
    padding: var(--space-2, 8px) var(--space-1, 4px);
}

.card-icon {
    width: 20px;
    height: 20px;
    flex: 0 0 auto;
    fill: currentColor;
    color: var(--accent);
    filter: drop-shadow(0 0 5px color-mix(in srgb, currentColor, transparent 55%));
}

.buy-gem-btn.red .card-icon { color: #ef4444; }
.buy-gem-btn.green .card-icon { color: #22c55e; }
.buy-gem-btn.yellow .card-icon { color: #facc15; }
.buy-gem-btn.blue .card-icon { color: #3b82f6; }

.cost-chip {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 1px var(--space-2, 8px);
    border-radius: 999px;
    border: 1px solid color-mix(in srgb, var(--resource-mana), transparent 75%);
    background: color-mix(in srgb, var(--resource-mana), transparent 92%);
    color: var(--resource-mana);
    font-size: 11px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.cost-chip svg {
    width: 10px;
    height: 10px;
    fill: currentColor;
}

/* Unaffordable cards: dimmed + desaturated, no hover lift (mana gates the rail). */
.mode-btn.unaffordable,
.buy-gem-btn.unaffordable {
    opacity: 0.5;
    filter: saturate(0.35);
}

.mode-btn.unaffordable:hover,
.buy-gem-btn.unaffordable:hover {
    transform: none;
    box-shadow: none;
}

/* Selection panel (B3): engraved heading + element-dotted gem summary. */
#selection-panel h3 {
    font-family: var(--font-display);
    letter-spacing: 0.05em;
    padding-bottom: var(--space-1, 4px);
    border-bottom: 1px solid color-mix(in srgb, var(--accent), transparent 78%);
}

.selection-gemline.has-gem::before {
    content: '';
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: 6px;
    border-radius: 50%;
    background: var(--gem-color, var(--accent));
    box-shadow: 0 0 6px color-mix(in srgb, var(--gem-color, var(--accent)), transparent 40%);
}

#btn-remove-entity:hover {
    border-color: color-mix(in srgb, var(--danger), transparent 45%);
}

/* Menus (B4): primary/secondary button hierarchy, talent cards, cost chips. */
.menu-btn.primary {
    box-shadow:
        inset 0 0 0 1px color-mix(in srgb, var(--accent), transparent 70%),
        0 0 22px color-mix(in srgb, var(--accent), transparent 84%);
}

.menu-btn.primary:hover {
    border-color: color-mix(in srgb, var(--accent), transparent 25%);
}

.menu-btn:not(.primary):hover {
    border-color: color-mix(in srgb, var(--accent), transparent 55%);
}

.talent-row {
    border-radius: var(--radius-md, 12px);
    background: var(--surface-1);
}

.talent-row:hover {
    border-color: color-mix(in srgb, var(--accent), transparent 70%);
}

.talent-level {
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.talent-cost {
    padding: 1px var(--space-2, 8px);
    border-radius: 999px;
    border: 1px solid color-mix(in srgb, var(--score), transparent 75%);
    background: color-mix(in srgb, var(--score), transparent 92%);
    color: var(--score);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* Feedback surfaces (B5): wave-banner pill, commander-tip accent rail. */
#wave-banner {
    display: flex;
    align-items: center;
    gap: var(--space-2, 8px);
    border-radius: 999px;
}

#wave-banner .banner-icon {
    width: 15px;
    height: 15px;
    flex: 0 0 auto;
    fill: currentColor;
}

/* Final-boss announcement. The pill grows into the ~520x290 surface ART-RUN-ROUND1
   specifies for boss-badge-banner, and the insignia REPLACES the 15px svg icon at
   that scale. Everything is scoped to .boss, so an ordinary wave keeps the pill
   exactly as it was. */
#wave-banner .banner-badge {
    display: none;
}

#wave-banner.boss {
    flex-direction: column;
    gap: var(--space-1, 4px);
    width: min(520px, 76vw);
    max-height: min(290px, 42vh);
    padding: 14px 22px 12px;
    border-radius: var(--radius-md, 14px);
    border-color: rgba(240, 214, 138, 0.34);   /* prestige gold, boss-only */
    box-shadow: 0 18px 44px rgba(0, 0, 0, 0.5);
}

/* The art is PORTRAIT (640x640 canvas, 273x640 of content) — contain, never
   cover, or the obelisk stretches. min-height 0 lets it shrink inside the
   flex column on short viewports instead of overflowing the banner. */
#wave-banner.boss .banner-badge {
    display: block;
    flex: 1 1 auto;
    min-height: 0;
    width: auto;
    max-width: 100%;
    object-fit: contain;
    filter: drop-shadow(0 6px 18px rgba(0, 0, 0, 0.55));
}

/* The svg icon is the FALLBACK, not a companion: at boss scale the insignia
   carries the read, and both at once is two icons saying one thing. If the
   insignia fails to decode UIManager drops .boss, which restores this. */
#wave-banner.boss .banner-icon {
    display: none;
}

#wave-banner.boss #wave-banner-text {
    font-size: var(--text-lg, 1.125rem);
    letter-spacing: 0.04em;
    text-align: center;
    flex: 0 0 auto;
}

#coach-hint {
    border-left: 3px solid color-mix(in srgb, var(--accent), transparent 30%);
    border-top-left-radius: var(--radius-sm, 9px);
    border-bottom-left-radius: var(--radius-sm, 9px);
}

/* Compact breakpoints: cards flatten to name + cost rows. */
@media (orientation: portrait) and (max-width: 980px), (orientation: landscape) and (max-height: 540px) {
    #control-rail .card-icon {
        display: none;
    }

    .mode-btn,
    .buy-gem-btn {
        flex-direction: row;
        gap: var(--space-1, 4px);
    }

    .cost-chip {
        padding: 0 5px;
        font-size: 9px;
    }

    .cost-chip svg {
        width: 8px;
        height: 8px;
    }
}

/* ==========================================================================
   E1: CINEMATIC TITLE SCREEN
   Nebula backdrop + wordmark entrance/glow, scoped to #menu-overlay.title-mode
   (toggled in UIManager.showMenuScreen only when screen === 'title', so the
   pause/level/shop screens keep their plain scrim — the nebula never leaks).
   ========================================================================== */

/* Static nebula layer: above the overlay's own scrim, behind the title card.
   pointer-events:none so the Start/Talent buttons stay clickable through it. */
#menu-overlay.title-mode::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    /* Edge-dark vignette preserves the nebula's luminous center for the wordmark. */
    background:
        radial-gradient(ellipse at 50% 45%, rgba(3, 6, 14, 0.26), rgba(2, 4, 10, 0.74) 72%),
        url('../../assets/ui/title-nebula-bg.webp') center / cover no-repeat;
}

/* Title card sits above the nebula; top is translucent so the luminous center
   glows behind the wordmark, bottom is denser so the subtitle + buttons read. */
#menu-overlay.title-mode #menu-screen-title {
    position: relative;
    z-index: 1;
    border-color: rgba(120, 190, 255, 0.18);
    background: linear-gradient(180deg,
        rgba(6, 12, 26, 0.32) 0%,
        rgba(5, 9, 20, 0.7) 55%,
        rgba(4, 8, 18, 0.86) 100%);
    box-shadow: 0 30px 80px rgba(0, 0, 0, 0.5);
}

/* Wordmark: keep the engraved rainbow shift, add a slow fade+scale entrance and
   a soft cyan glow pulse. Legibility over the nebula rides on the glow shadow. */
#menu-overlay.title-mode #menu-screen-title h1 {
    animation:
        gem-rainbow-shift 11s linear infinite,
        title-rise 1000ms var(--ease-out, ease) both,
        title-glow 3.6s ease-in-out 1s infinite;
}

@keyframes title-rise {
    from { opacity: 0; transform: translateY(16px) scale(0.92); }
    to { opacity: 1; transform: translateY(0) scale(1); }
}

@keyframes title-glow {
    0%, 100% { text-shadow: 0 0 20px rgba(107, 232, 255, 0.4), 0 0 52px rgba(150, 90, 255, 0.22); }
    50% { text-shadow: 0 0 30px rgba(107, 232, 255, 0.66), 0 0 66px rgba(150, 90, 255, 0.36); }
}

/* ==========================================================================
   E2: GUIDED FIRST-RUN ONBOARDING
   Coach card gains a step-dot row + Skip affordance while a guide is active,
   and a spotlight ring pulses on the control the current step points at.
   ========================================================================== */

/* Footer row (dots + skip) only appears while the guide drives the coach card. */
.coach-footer { display: none; }

#coach-hint.onboarding .coach-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2, 8px);
    margin-top: var(--space-2, 8px);
}

.coach-steps {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.coach-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--text-muted), transparent 45%);
    transition:
        background var(--duration-fast, 150ms) var(--ease-out, ease),
        transform var(--duration-fast, 150ms) var(--ease-out, ease);
}

.coach-dot.active {
    background: var(--accent);
    transform: scale(1.25);
    box-shadow: 0 0 8px color-mix(in srgb, var(--accent), transparent 40%);
}

/* Coach card is pointer-events:none, so the Skip button re-enables its own. */
.coach-skip {
    pointer-events: auto;
    display: inline-flex;
    align-items: center;
    min-height: 40px;
    padding: 6px 14px;
    border: 1px solid color-mix(in srgb, var(--text-muted), transparent 58%);
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.28);
    color: var(--text-muted);
    font: 600 11px var(--font-ui);
    letter-spacing: 0.4px;
    cursor: pointer;
    touch-action: manipulation;
    transition:
        color var(--duration-fast, 150ms) var(--ease-out, ease),
        border-color var(--duration-fast, 150ms) var(--ease-out, ease);
}

.coach-skip:hover {
    color: var(--text);
    border-color: color-mix(in srgb, var(--accent), transparent 45%);
}

.coach-skip:focus-visible {
    outline: 2px solid color-mix(in srgb, var(--accent), transparent 15%);
    outline-offset: 2px;
}

/* Spotlight: a single <body data-onboard-step> attr rings the step's target.
   box-shadow is outset (overflow:hidden on the buttons never clips it); the
   stash cells are untouched — only the #stash-bar container gets the ring. */
body[data-onboard-step="build"] #btn-build-pedestal,
body[data-onboard-step="buy"] .buy-gem-btn,
body[data-onboard-step="socket"] #stash-bar {
    position: relative;
    z-index: 2;
    animation: onboard-pulse 1.6s ease-in-out infinite;
}

@keyframes onboard-pulse {
    0%, 100% {
        box-shadow:
            0 0 0 2px color-mix(in srgb, var(--accent), transparent 45%),
            0 0 14px color-mix(in srgb, var(--accent), transparent 68%);
    }
    50% {
        box-shadow:
            0 0 0 3px var(--accent),
            0 0 26px color-mix(in srgb, var(--accent), transparent 40%);
    }
}

@media (prefers-reduced-motion: reduce) {
    /* Static spotlight — clearly highlighted, no pulse. */
    body[data-onboard-step="build"] #btn-build-pedestal,
    body[data-onboard-step="buy"] .buy-gem-btn,
    body[data-onboard-step="socket"] #stash-bar {
        animation: none;
        box-shadow:
            0 0 0 2px var(--accent),
            0 0 16px color-mix(in srgb, var(--accent), transparent 55%);
    }

    .coach-dot { transition: none; }
}

/* ==========================================================================
   T5: next-wave preview — intermission strip / active-wave chip
   ========================================================================== */

#wave-preview {
    position: absolute;
    top: 62px; /* below the transient wave-banner lane (top: 20px) */
    left: 50%;
    transform: translateX(-50%);
    z-index: 19; /* under the wave-banner (20) so the two never fight */
    max-width: min(92%, 680px);
    padding: var(--space-2, 8px) var(--space-3, 12px);
    font-family: var(--font-ui);
    font-size: 13px;
    letter-spacing: 0.4px;
    text-align: center;
    color: var(--text);
    pointer-events: none;
    opacity: 0.95;
    transition: opacity var(--duration-normal, 300ms) var(--ease-out, ease);
}

#wave-preview .wp-label {
    margin-right: var(--space-1, 4px);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 1.1px;
    text-transform: uppercase;
    color: var(--accent);
}

/* Affinity marks: a color pip + a hue-neutral wedge/shield mark per row
   (assets/ui/affinity/affinity-marks.webp, assets/ui/pips/gem-color-pips.webp).
   The mark is a MASK, not an image, so `color` on .aff-<name> still drives its
   hue exactly as it drove the retired ▲/⛨ glyphs — one source of truth for the
   affinity color. --sp-size/--sp-pos are the pure atlas geometry from
   waveIconography.spriteSheetStyle; a cell that could not be resolved emits no
   span at all, so nothing ever paints the whole sheet. */
#wave-preview .aff {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    vertical-align: -2px;
    line-height: 1;
}

/* Affinity meaning for assistive tech: the strip is aria-live="polite", and the
   marks are aria-hidden sprites, so this carries the words. Not `display: none`
   — that would hide it from the announcement too. */
#wave-preview .wp-sr {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

#wave-preview .wp-badge,
#wave-preview .wp-mark,
#wave-preview .wp-pip {
    display: inline-block;
    flex: none;
    background-repeat: no-repeat;
    background-size: var(--sp-size);
    background-position: var(--sp-pos);
}

#wave-preview .wp-badge {
    width: 16px;
    height: 16px;
    margin-right: 3px;
    vertical-align: -3px;
    background-image: url('../../assets/ui/affinity/family-badges.webp');
}

#wave-preview .wp-pip {
    width: 12px;
    height: 12px;
    background-image: url('../../assets/ui/pips/gem-color-pips.webp');
}

#wave-preview .wp-mark {
    width: 12px;
    height: 12px;
    background-image: none;
    background-color: currentColor;
    -webkit-mask-image: url('../../assets/ui/affinity/affinity-marks.webp');
    mask-image: url('../../assets/ui/affinity/affinity-marks.webp');
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: var(--sp-size);
    mask-size: var(--sp-size);
    -webkit-mask-position: var(--sp-pos);
    mask-position: var(--sp-pos);
}

#wave-preview .aff-red { color: var(--gem-red); }
#wave-preview .aff-green { color: var(--gem-green); }
#wave-preview .aff-yellow { color: var(--gem-yellow); }
#wave-preview .aff-blue { color: var(--gem-blue); }

/* Icon box sizes are NOT restyled per state (e.g. .wp-chip): --sp-size/--sp-pos
   are baked in JS against BADGE_PX/MARK_PX, so a CSS-only resize would slide the
   atlas onto the wrong cell. Change the constant in UIManager, not here. */

/* Collapsed chip during the active wave: smaller, quieter, same truth. */
#wave-preview.wp-chip {
    font-size: 12px;
    padding: var(--space-1, 4px) var(--space-2, 8px);
    opacity: 0.6;
}

@media (prefers-reduced-motion: reduce) {
    /* Presence only — strip appears and collapses without easing. */
    #wave-preview {
        transition: none;
    }
}
