/* Page chrome, in-game HUD, overlays and the Archives.
   Shares the lobby's tokens (--gold, --line, --hair, --font-ui, --font-mark, --aether; see lobby.css)
   and adds a grotesque for numerals, labels and buttons, where a display serif gets hard to read. */

:root {
    --font-data: 'Cabinet Grotesk', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --glass: linear-gradient(180deg, rgba(17, 19, 28, 0.86), rgba(7, 8, 12, 0.95));
    --hud-pad: 10px;
    --deck-h: 164px;
    --map-h: 0px; /* what the minimap takes above the deck, where it floats there (phones held upright) */
    --actions-w: clamp(320px, 40vw, 520px);
    --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
    --hout: #a3e635;
}

/* Same flames as the lobby faction cards in index.html. */
[data-faction="gildenmere"] { --flame: #ff8b3d; }
[data-faction="solarcene"] { --flame: #ffe6a3; }
[data-faction="ashveld"] { --flame: #58f07a; }
[data-faction="dominion"] { --flame: #ff4d2e; }
[data-faction="veilborn"] { --flame: #8f5bff; }

/* ── Page ── */

/* The page never scrolls; without this a trackpad swipe rubber-bands it or triggers swipe-back. */
html, body { overscroll-behavior: none; }

body {
    margin: 0;
    overflow: hidden;
    background-color: #020617;
    font-family: var(--font-data);
    user-select: none;
    -webkit-user-select: none;
    touch-action: none;
    width: 100vw;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding-left: env(safe-area-inset-left, 0px);
    padding-right: env(safe-area-inset-right, 0px);
}

/* Tailwind's CDN sheet loads after this file, so its utilities need outranking where they are retuned. */
body .font-serif { font-family: var(--font-ui); }
.text-amber-400 { color: var(--gold) !important; }
.text-amber-500 { color: var(--gold-dim) !important; }
.hidden { display: none !important; }

::-webkit-scrollbar { width: 4px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(242, 201, 76, 0.4); }

#canvas-container { position: fixed; inset: 0; z-index: 0; touch-action: none; }
#canvas-container canvas { display: block; width: 100%; height: 100%; touch-action: none; }

.ui-layer { position: fixed; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 10; display: flex; flex-direction: column; }
.pointer-events-auto { pointer-events: auto; }

kbd {
    padding: 1px 5px;
    font-family: var(--font-data);
    font-size: 0.62rem;
    font-weight: 700;
    line-height: 1.3;
    color: var(--gold-hi);
    background: rgba(0, 0, 0, 0.45);
    border: 1px solid rgba(255, 255, 255, 0.22);
    border-bottom-width: 2px;
    border-radius: 3px;
}

/* ── World-space overlays: health bars and floating text ── */

.hp-bar-container {
    position: absolute;
    left: 0;
    top: 0;
    transform: translate(-50%, -100%);
    width: 40px;
    height: 4px;
    background: rgba(239, 68, 68, 0.3);
    border: 1px solid rgba(0, 0, 0, 0.5);
    pointer-events: none;
    display: none;
    z-index: 20;
    will-change: transform;
}

.hp-bar-fill { height: 100%; width: 100%; background: #22c55e; box-shadow: 0 0 5px #22c55e; }
.hp-bar-fill.enemy, .hp-bar-enemy { background: #ef4444 !important; box-shadow: 0 0 5px #ef4444 !important; }
.hp-bar-fill.ally, .hp-bar-ally { background: #22c55e !important; box-shadow: 0 0 5px #22c55e !important; }

.vfx-particle {
    position: absolute;
    z-index: 40;
    font-weight: 800;
    font-size: 1.4rem;
    letter-spacing: 0.04em;
    pointer-events: none;
    text-shadow: 0 0 10px #fff;
    animation: floatUp 1s ease-out forwards;
    will-change: transform, opacity;
}

.vfx-particle.damage-number {
    font-size: 1.05rem;
    color: #ef4444 !important;
    text-shadow: 0 0 8px #f59e0b, 0 0 12px #ef4444, 2px 2px 0px #000 !important;
}

@keyframes floatUp {
    0% { transform: translateY(0) scale(1); opacity: 1; }
    100% { transform: translateY(-60px) scale(1.5); opacity: 0; }
}

/* ── Toast (see js/ui/toast.js) ── */

#error-popup {
    position: fixed;
    top: calc(var(--hud-pad) + 64px);
    left: 50%;
    z-index: 130;
    max-width: min(92vw, 36rem);
    padding: 10px 18px;
    pointer-events: none;
    font-size: 0.9rem;
    font-weight: 700;
    text-align: center;
    color: #fff8de;
    background: var(--glass);
    border: 1px solid var(--gold);
    border-radius: 3px;
    box-shadow: 0 18px 44px -16px #000, 0 0 40px -14px var(--aether);
    opacity: 0;
    transform: translate(-50%, -8px);
    transition: opacity 0.25s, transform 0.35s var(--ease);
}

#error-popup.show { opacity: 1; transform: translate(-50%, 0); }

/* ── Panels shared by modals (admin panel, Archives) ── */

.modal-bg { background: rgba(4, 5, 8, 0.8); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }

.luxury-border {
    color: #fff;
    background: var(--glass);
    border: 1px solid var(--line);
    border-radius: 3px;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 30px 80px -30px #000;
}

.luxury-text { color: var(--gold) !important; text-shadow: 0 1px 0 #000 !important; }

/* ── HUD top: three floating islands ── */

.hud-top {
    position: absolute;
    inset: 0 0 auto 0;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: start;
    gap: var(--hud-pad);
    /* the bar is absolute, so the side padding of #game-ui does not reach it: it keeps clear of a camera hole itself */
    padding: max(var(--hud-pad), env(safe-area-inset-top, 0px)) max(var(--hud-pad), env(safe-area-inset-right, 0px)) 0 max(var(--hud-pad), env(safe-area-inset-left, 0px));
}

.hud-island {
    display: flex;
    align-items: center;
    min-width: 0;
    min-height: 44px;
    padding: 4px;
    background: var(--glass);
    border: 1px solid var(--line);
    border-radius: 3px;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 14px 36px -18px #000, 0 0 60px -30px var(--aether);
    -webkit-backdrop-filter: blur(12px) saturate(130%);
    backdrop-filter: blur(12px) saturate(130%);
    animation: hud-drop 0.7s var(--ease) backwards;
}

.hud-status { justify-self: start; max-width: 100%; overflow: hidden; }
.hud-score { animation-delay: 0.08s; }
.hud-tools { justify-self: end; gap: 2px; animation-delay: 0.16s; }

@keyframes hud-drop {
    from { opacity: 0; transform: translateY(-14px); }
}

.hud-faction {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
    padding: 0 14px 0 12px;
    font-family: var(--font-ui);
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    white-space: nowrap;
}

/* Name over rival, so the island stays narrow enough to sit beside the centred score. */
.hud-faction-names { display: flex; flex-direction: column; min-width: 0; line-height: 1.1; }
#ui-faction-name { overflow: hidden; text-overflow: ellipsis; }

.hud-rival {
    gap: 4px;
    font-family: var(--font-data);
    font-size: 0.68rem;
    letter-spacing: 0.14em;
    color: var(--gold-dim);
}

.hud-faction .faction-gem { --f: var(--aether); --flame: var(--aether); width: 0.7rem; margin: 0; }

.hud-stat {
    flex: none;
    display: flex;
    align-items: center;
    gap: 6px;
    height: 34px;
    padding: 0 14px;
    border-left: 1px solid var(--hair);
    white-space: nowrap;
}

.hud-stat > i { font-size: 1rem; color: var(--gold); }

.hud-value {
    font-size: 1.25rem;
    font-weight: 800;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: #fff;
}

.hud-sub { font-size: 0.75rem; font-weight: 500; font-variant-numeric: tabular-nums; color: var(--gold-dim); }

/* Next income wave ("+33 over 7s"). The reserved width keeps the units counter from shifting when the seconds lose a digit. */
.hud-income { min-width: 11ch; }

.hud-label {
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--gold-dim);
}

#ui-enemy-faction { color: #ff9c8a; }

.hud-score-side,
.hud-score-mid { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 2px 14px; }
.hud-score-side { min-width: 60px; }
.hud-score-mid { border-inline: 1px solid var(--hair); }
.hud-score-mid .hud-value { font-size: 1rem; color: var(--gold-hi); }

/* Your own side carries the faction's colour. */
#game-ui[data-side="west"] [data-side="west"] .hud-label,
#game-ui[data-side="east"] [data-side="east"] .hud-label { color: var(--aether); }

.hud-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 34px;
    padding: 0 14px;
    font-family: var(--font-data);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    white-space: nowrap;
    color: #e9dcb4;
    border: 1px solid transparent;
    border-radius: 2px;
    cursor: pointer;
    transition: color 0.2s, border-color 0.2s, background-color 0.2s, transform 0.35s var(--ease);
}

.hud-btn:hover { color: #fff8de; background: rgba(255, 255, 255, 0.06); border-color: var(--line); transform: translateY(-1px); }
.hud-btn:active { transform: translateY(1px); }

.hud-btn:focus-visible,
.hud-cta:focus-visible,
.action-btn:focus-visible { outline: 2px solid var(--aether); outline-offset: 2px; }

/* Leaving takes a second click (see main.js). */
#btn-back-to-menu .when-armed,
#btn-back-to-menu.armed .when-idle { display: none; }
#btn-back-to-menu.armed .when-armed { display: inline; }

#btn-back-to-menu.armed,
.hud-btn-danger { color: #fee2e2; background: rgba(127, 29, 29, 0.92); border-color: #f87171; }

#btn-back-to-menu.armed:hover,
.hud-btn-danger:hover { color: #fff; background: #991b1b; border-color: #fca5a5; }

#btn-cancel-build {
    position: absolute;
    right: var(--hud-pad);
    bottom: calc(var(--deck-h) + var(--map-h) + env(safe-area-inset-bottom, 0px) + 12px);
    min-height: 44px;
    min-width: 44px;
    touch-action: manipulation;
    box-shadow: 0 14px 36px -14px #000;
}
#btn-cancel-build.hidden {
    display: none !important;
}

/* ── Match preparation banner ── */

.hud-banner {
    position: absolute;
    top: calc(var(--hud-pad) + 58px);
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    max-width: min(92vw, 44rem);
    padding: 10px 22px;
    text-align: center;
    background: var(--glass);
    border: 1px solid var(--line);
    border-radius: 3px;
    box-shadow: 0 0 40px -12px var(--aether), inset 0 1px 0 rgba(255, 255, 255, 0.07);
}

.hud-banner-main { font-family: var(--font-ui); font-size: 1.3rem; font-weight: 700; line-height: 1; color: #fff; }
#prep-countdown { font-variant-numeric: tabular-nums; color: var(--gold); }

.hud-keys {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 4px 6px;
    font-size: 0.72rem;
    color: var(--gold-dim);
}

.hud-keys kbd:not(:first-child) { margin-left: 8px; }

/* ── Scoreboard: held with Tab or toggled by "Stand"; the same table closes the game-over screen ── */

.hud-scoreboard {
    position: absolute;
    top: calc(var(--hud-pad) + 58px);
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: min(92vw, 28rem);
    max-height: calc(100% - var(--deck-h) - var(--hud-pad) - 76px);
    overflow: hidden;
    padding: 10px 14px 12px;
    background: var(--glass);
    border: 1px solid var(--line);
    border-radius: 3px;
    box-shadow: 0 0 40px -12px var(--aether), inset 0 1px 0 rgba(255, 255, 255, 0.07);
}

.sb-table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }

.sb-table th,
.sb-table td {
    padding: 5px 8px;
    font-size: 0.82rem;
    font-weight: 800;
    line-height: 1.2;
    text-align: right;
    color: #fff;
    border-top: 1px solid var(--hair);
}

.sb-table tbody th { font-weight: 500; text-align: left; color: #cbd5e1; }
.sb-table td,
.sb-table thead th + th { width: 5rem; }

.sb-table thead th {
    padding-top: 0;
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--gold-dim);
    border-top: 0;
}

/* The local player's column. */
.sb-table .sb-own { background: color-mix(in srgb, var(--aether) 14%, transparent); }
.sb-table thead .sb-own { color: var(--aether); }

/* ── Command deck: minimap, selection, actions. One row, three cells, no dead space. ── */

#bottom-ui-bar {
    position: absolute;
    inset: auto 0 0 0;
    height: calc(var(--deck-h) + env(safe-area-inset-bottom, 0px));
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-rows: minmax(0, 1fr); /* the row may not grow past the deck when a cell has a lot to say */
    padding-bottom: env(safe-area-inset-bottom, 0px);
    /* Close to opaque on purpose: a backdrop blur this large would re-run over the 3D canvas every frame. */
    background: var(--glass);
    border-top: 1px solid var(--line);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 -24px 60px -30px #000, 0 -1px 50px -22px var(--aether);
    pointer-events: auto;
    animation: hud-rise 0.7s var(--ease) 0.1s backwards;
}

@keyframes hud-rise {
    from { opacity: 0; transform: translateY(24px); }
}

/* Clicks on the deck must not fall through to the 3D canvas. */
#bottom-ui-bar * { pointer-events: auto; }

/* Each cell is placed explicitly: on touch screens the info card (#ui-tooltip) lies over the first two,
   and auto-placement would push them out of its way. */
#minimap-container { grid-area: 1 / 1; }
#unit-stats-panel { grid-area: 1 / 2; }
#action-grid-parent { grid-area: 1 / 3; }

/* The board is 4:1, so the minimap is too: at full deck height it fills its cell edge to edge. */
#minimap-container {
    display: flex;
    align-items: center;
    width: min(28vw, calc(4 * (var(--deck-h) - 2 * var(--hud-pad)) + 2 * var(--hud-pad)));
    padding: var(--hud-pad);
}

#minimap {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 1;
    background: #000;
    border: 1px solid var(--line);
    border-radius: 2px;
    box-shadow: inset 0 0 20px #000;
}

/* A size container: the selection lays itself out by the room this cell has, not by the window (see the @container rules). */
#unit-stats-panel {
    container-type: inline-size;
    --cell-h: 31px;
    --cell-gap: clamp(8px, 1vw, 14px);
    display: flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
    min-height: 0;
    padding: var(--hud-pad) 16px;
    border-left: 1px solid var(--hair);
}

/* Lit from below by the flame of the selection's own faction (data-faction is set in renderContextPanel). */
#unit-portrait-container {
    position: relative;
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    max-height: 104px;
    aspect-ratio: 1;
    overflow: hidden;
    background:
        radial-gradient(120% 90% at 50% 112%, color-mix(in srgb, var(--flame, var(--aether)) 46%, transparent), transparent 70%),
        #0a0b10;
    border: 1px solid var(--line);
    border-radius: 2px;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
}

#unit-portrait-placeholder i {
    font-size: 2.6rem;
    color: var(--gold-hi);
    filter: drop-shadow(0 0 12px color-mix(in srgb, var(--flame, var(--aether)) 80%, transparent));
}

/* On the wrapper: the icon inside is rewritten on every re-render, which would restart the transition. */
#unit-portrait-placeholder { transition: transform 0.7s ease-out; }
#unit-stats-panel:hover #unit-portrait-placeholder { transform: scale(1.08); }

#ctx-tier {
    position: absolute;
    top: 4px;
    left: 4px;
    padding: 1px 4px;
    font-size: 0.66rem;
    font-weight: 800;
    letter-spacing: 0.08em;
    color: var(--gold-hi);
    background: rgba(0, 0, 0, 0.55);
    border: 1px solid var(--line);
    border-radius: 2px;
}

#ctx-tier:empty { display: none; }

/* Nothing selected: the portrait would be stale, so a hint takes the cell instead. */
#unit-stats-panel:has(#context-panel.hidden) #unit-portrait-container { display: none; }

.ctx-empty {
    display: none;
    max-width: 34rem;
    margin: 0;
    font-family: var(--font-ui);
    font-style: italic;
    font-size: 1.05rem;
    line-height: 1.35;
    text-wrap: balance;
    color: var(--gold-dim);
}

#context-panel.hidden + .ctx-empty { display: block; }

#context-panel {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 5px;
    min-width: 0;
    max-height: 100%;
    overflow: hidden;
    /* ponytail: plays when the panel appears, not when the selection jumps from one entity to the next; restart it from renderContextPanel if that is missed. */
    animation: ctx-in 0.45s var(--ease) backwards;
}

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

.ctx-main,
.ctx-aside { display: flex; flex-direction: column; gap: 5px; min-width: 0; }

/* Rows keep their height. Left free to shrink, the title was the row that got cut in half. */
.ctx-main > *,
.ctx-aside > * { flex: none; }

.ctx-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }

/* What the selection is, at the far end of its name. It gives way long before the name does; an enemy's reads in the rival red of the top bar. */
#ctx-kind { flex: 0 100 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.is-enemy #ctx-kind { color: #ff9c8a; }

#ctx-title {
    min-width: 0;
    margin: 0;
    font-family: var(--font-ui);
    font-size: 1.3rem;
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
    overflow: clip visible; /* sideways only, for the ellipsis: the line box is tighter than the font, and accents reach above it */
    text-overflow: ellipsis;
}

/* Health and mana: label, notched bar, value. The outer columns are fixed, so the two bars start and end together. */
.ctx-meter { display: grid; grid-template-columns: 2.4rem minmax(0, 1fr) 6.2rem; align-items: center; gap: 8px; }

.ctx-meter-value {
    font-size: 0.8rem;
    font-weight: 800;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    text-align: right;
    white-space: nowrap;
    color: #fff;
}

.ctx-bar {
    position: relative;
    height: 8px;
    overflow: hidden;
    background: rgba(0, 0, 0, 0.55);
    border-radius: 1px;
    box-shadow: inset 0 0 0 1px var(--hair);
}

.ctx-bar > div { height: 100%; transition: width 0.25s linear; }

/* A notch every tenth. */
.ctx-bar::after {
    content: '';
    position: absolute;
    inset: 0;
    background: repeating-linear-gradient(90deg, transparent 0 calc(10% - 1px), rgba(0, 0, 0, 0.6) calc(10% - 1px) 10%);
}

/* --hp runs 0-100 (setHpFill in ui_manager.js) and drives the width and the colour: red through yellow to green. */
#ctx-hp-fill {
    width: calc(var(--hp, 100) * 1%);
    background: color-mix(in oklch, #4ade80 calc(var(--hp, 100) * 1%), #ef4444);
}

#ctx-builder-stats .ctx-bar { height: 5px; }
#ctx-mana-fill { width: 100%; background: linear-gradient(90deg, #2563eb, #60a5fa); }
#ctx-mana-fill[style*="width: 0%"] {
    box-shadow: none;
    background: transparent;
}
#ctx-spawn-progress { background: linear-gradient(90deg, var(--gold-dim), var(--gold)); }

/* One row of cells. Those that do not fit wrap to a second row, which the fixed height hides: a cell shows whole or not at all. */
.ctx-stats { display: flex; flex-wrap: wrap; column-gap: var(--cell-gap); height: var(--cell-h); overflow: hidden; }
.ctx-cell { display: flex; flex-direction: column; justify-content: space-between; min-width: 0; max-width: 100%; height: var(--cell-h); }
.ctx-cell:not(.hidden) ~ .ctx-cell { padding-left: var(--cell-gap); border-left: 1px solid var(--hair); }

/* A spawner's cells are those of the unit it produces, named in the first one. */
.ctx-cell-lead { max-width: 48%; }
.ctx-cell-lead .stat-value { color: var(--gold-hi); }

.stat-label {
    font-size: 0.62rem;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--gold-dim);
}

.stat-value {
    overflow: hidden;
    font-size: 1rem;
    font-weight: 800;
    line-height: 1.15;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: #fff;
}

/* The next wave (markup from renderContextPanel): one strip of label, bar and countdown.
   With room to spare it becomes the card beside the stats, see the wide @container rule. */
#ctx-spawner-info { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 2px 8px; }
#ctx-spawner-info .ctx-bar { grid-area: 1 / 2; }

/* The reserved width keeps the bar from twitching when the seconds gain or lose a digit. */
#ctx-spawn-timer-text {
    grid-area: 1 / 3;
    min-width: 5ch;
    font-size: 0.8rem;
    font-weight: 800;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    text-align: right;
    color: var(--gold-hi);
}

.ctx-spawn-rate { display: none; font-size: 0.78rem; font-weight: 500; line-height: 1.2; white-space: nowrap; color: #cbd5e1; }

/* The unit's name, for the sliver of a cell where the "Produceert" cell has to go (see below). */
.ctx-spawn-unit { display: none; max-width: 9rem; overflow: hidden; text-overflow: ellipsis; }

#ctx-desc,
#ctx-lore { margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#ctx-desc { font-size: 0.78rem; font-weight: 500; line-height: 1.3; color: #cbd5e1; }
#ctx-desc:empty { display: none; }
#ctx-lore { font-family: var(--font-ui); font-style: italic; font-size: 0.92rem; line-height: 1.2; color: var(--gold-dim); }

/* The next wave takes the place of the lore. */
#ctx-spawner-info:not(.hidden) ~ #ctx-lore { display: none; }

/* Stacked, the rows of a selection with a mana bar leave no line for the lore either. */
@container (width < 780px) {
    #context-panel:has(#ctx-builder-stats:not(.hidden)) #ctx-lore { display: none; }
}

/* A sliver of a cell (windows up to about 1300px wide): the bars lose their labels, the portrait gives up half its room,
   and the unit's name moves from the first stat cell to the next-wave strip so damage, attack and armour still fit. */
@container (width < 420px) {
    #unit-portrait-container { max-height: 64px; }
    #unit-portrait-placeholder i { font-size: 1.7rem; }
    #ctx-kind,
    .ctx-meter > .stat-label,
    .ctx-cell-lead,
    .ctx-spawn-label { display: none; }
    .ctx-spawn-unit { display: block; }
    .ctx-cell-lead ~ .ctx-cell:nth-child(2) { padding-left: 0; border-left: 0; }
    .ctx-meter { grid-template-columns: minmax(0, 1fr) 5.4rem; }
}

/* A wide cell: stats on the left, the next wave or the lore on the right, so no bar has to span 900px to fill the row. */
@container (width >= 780px) {
    #context-panel { flex-direction: row; align-items: center; gap: 18px; }
    .ctx-main { flex: 2 1 0; gap: 8px; }
    .ctx-aside { flex: 1 1 0; align-self: stretch; justify-content: center; padding-left: 18px; border-left: 1px solid var(--hair); }

    #ctx-spawner-info { grid-template-columns: auto minmax(0, 1fr); column-gap: 12px; }
    #ctx-spawn-timer-text { grid-area: 1 / 1 / 3 / 2; min-width: 4.5ch; font-size: 2.1rem; text-align: left; }
    #ctx-spawner-info .stat-label { grid-area: 1 / 2; align-self: end; }
    .ctx-spawn-rate { display: block; grid-area: 2 / 2; align-self: start; }
    #ctx-spawner-info .ctx-bar { grid-area: 3 / 1 / 4 / 3; margin-top: 6px; }

    #ctx-lore { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; white-space: normal; text-wrap: pretty; }
}

/* Slots share each row equally and wrap once they would drop under 70px, so any number of actions fills the cell. */
#action-grid-parent {
    width: var(--actions-w);
    min-height: 0;
    padding: var(--hud-pad);
    overflow: hidden;
    border-left: 1px solid var(--hair);
}

#action-grid { display: flex; flex-wrap: wrap; align-content: stretch; gap: 6px; width: 100%; height: 100%; }
#build-menu, #skills-upgrades-menu { display: contents; }

/* One action: its button and, on touch screens, the tab that opens its info card (UIManager.addAction). */
.action-slot { flex: 1 1 70px; display: flex; min-width: 0; min-height: 44px; }

.action-btn {
    position: relative;
    flex: 1 1 0;
    min-width: 0;
    padding: 6px 6px 5px;
    overflow: hidden;
    font-family: var(--font-data);
    color: #f3ead0;
    background: linear-gradient(180deg, rgba(42, 44, 58, 0.9), rgba(15, 16, 23, 0.95));
    border: 1px solid rgba(242, 201, 76, 0.28);
    border-radius: 2px;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.09);
    cursor: pointer;
    transition: transform 0.35s var(--ease), border-color 0.2s, box-shadow 0.3s, filter 0.2s;
}

/* Outranks the centring utilities the button templates in ui_manager.js carry. */
#action-grid .action-btn { display: flex; flex-direction: column; align-items: stretch; justify-content: space-between; gap: 2px; }

.action-btn:hover {
    transform: translateY(-2px);
    border-color: var(--gold);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 10px 24px -12px var(--aether);
}

.action-btn:active { transform: translateY(1px); }
.action-btn:disabled { cursor: not-allowed; }

/* The building being placed. */
.action-btn.active {
    border-color: var(--gold);
    background: linear-gradient(180deg, color-mix(in srgb, var(--aether) 30%, #171922), #0b0c11);
    box-shadow: inset 0 0 0 1px rgba(242, 201, 76, 0.3), 0 0 26px -8px var(--aether);
}

.action-btn.unaffordable { filter: saturate(0.5) brightness(0.8); }
.action-btn.unaffordable .cost-tag { color: #f87171; border-color: rgba(248, 113, 113, 0.4); }
.action-btn.unaffordable .cost-mana {
    color: #64748b;
    border-color: rgba(100, 116, 139, 0.3);
    text-shadow: none;
    box-shadow: none;
}

.action-btn-thumb {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 65%;
    background-size: cover;
    background-position: center right;
    background-repeat: no-repeat;
    opacity: 0.35;
    mask-image: linear-gradient(to left, black 20%, transparent 100%);
    -webkit-mask-image: linear-gradient(to left, black 20%, transparent 100%);
    pointer-events: none;
    z-index: 0;
}

.action-btn:hover .action-btn-thumb {
    opacity: 0.55;
    transform: scale(1.04);
    transition: opacity 0.2s ease, transform 0.3s ease;
}

.action-btn > *:not(.action-btn-thumb) {
    position: relative;
    z-index: 1;
}
.action-btn.unaffordable:hover {
    box-shadow: none;
    border-color: rgba(255, 255, 255, 0.1);
}

/* A locked building, or a spent charge or cooldown (Nexus shop). The button stays clickable so the refusal can say why. */
.action-btn.unavailable { opacity: 0.55; filter: grayscale(1); cursor: not-allowed; }

/* Research or cooldown running on a button: the seconds left over a bar that drains (timerVeil in ui_manager.js).
   A researching button is not greyed out as well, or the countdown would be too. */
.btn-timer {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: grid;
    place-items: center;
    font-size: 1rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    color: var(--gold);
    background: rgba(8, 9, 14, 0.82);
    cursor: progress;
}
.btn-timer::after {
    content: "";
    position: absolute;
    inset: auto 0 0 0;
    height: 3px;
    background: var(--aether);
    transform-origin: left;
    animation: btn-timer-drain var(--secs) linear var(--elapsed) both;
}
@keyframes btn-timer-drain { from { transform: scaleX(1); } to { transform: scaleX(0); } }

/* With 7+ actions (all build options and the faction spell) four to a row wraps into two even rows instead of 6 + 2.
   Two rows leave ~59px per button, so the role icon moves into the corner and the tier tag makes way for the price. */
#action-grid.dense .action-slot { flex-basis: calc(25% - 6px); max-height: calc(50% - 3px); min-height: 0; }
#action-grid.dense .action-btn-badges { position: absolute; top: 3px; right: 4px; }
#action-grid.dense .action-btn .tier-tag { display: none; }
/* Nine buildings and the spell make ten: five to a row keeps the two rows. Narrow layouts stay at four and scroll. */
@media (min-width: 901px) and (min-height: 521px) {
    #action-grid.dense:has(.action-slot:nth-child(9)) .action-slot { flex-basis: calc(20% - 6px); max-height: calc(50% - 3px); min-height: 0; }
}

#action-grid.dense .action-btn {
    padding: 4px 5px 3px;
    gap: 1px;
    min-height: 0;
}
#action-grid.dense .action-btn .title {
    font-size: 0.7rem;
    line-height: 1.15;
}
#action-grid.dense .action-btn .cost-tag {
    padding: 1px 4px;
    font-size: 0.68rem;
}
#action-grid.dense .action-btn .role-badge {
    font-size: 0.85rem;
}

/* Selling: red-tinted, with the refund in green. */
.action-btn-sell { border-color: rgba(248, 113, 113, 0.4); background: linear-gradient(180deg, rgba(127, 29, 29, 0.55), rgba(24, 8, 10, 0.95)); }
.action-btn-sell:hover { border-color: #f87171; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 10px 24px -12px #ef4444; }
.action-btn-sell .title { color: #fca5a5; }
.action-btn-sell .cost-tag { color: #86efac; border-color: rgba(134, 239, 172, 0.35); }

.action-btn-badges { display: flex; align-items: center; justify-content: space-between; pointer-events: none; }
.action-btn .role-badge { font-size: 1rem; color: var(--gold); }

.action-btn .tier-tag {
    padding: 1px 4px;
    font-size: 0.58rem;
    font-weight: 800;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: #aab4c5;
    border: 1px solid rgba(255, 255, 255, 0.16);
    border-radius: 2px;
}

.action-btn .title {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
    font-size: 0.66rem;
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: 0.04em;
    text-align: left;
    text-transform: uppercase;
    overflow-wrap: anywhere;
    color: #fff;
}

.action-btn .bld-sub {
    display: inline-block;
    font-size: 0.64rem;
    font-weight: 800;
    line-height: 1.1;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    padding: 1px 3px;
    border-radius: 2px;
    margin-top: 2px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}
.action-btn .bld-sub.sub-spawner {
    color: #38bdf8;
    background: rgba(14, 165, 233, 0.15);
    border: 1px solid rgba(56, 189, 248, 0.35);
}
.action-btn .bld-sub.sub-turret {
    color: #fb923c;
    background: rgba(249, 115, 22, 0.15);
    border: 1px solid rgba(251, 146, 60, 0.35);
}
.action-btn .bld-sub.sub-income {
    color: #4ade80;
    background: rgba(34, 197, 94, 0.15);
    border: 1px solid rgba(74, 222, 128, 0.35);
}
.action-btn .bld-sub.sub-support {
    color: #c084fc;
    background: rgba(168, 85, 247, 0.15);
    border: 1px solid rgba(192, 132, 252, 0.35);
}

.cost-tag {
    align-self: flex-end;
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 2px 5px;
    font-size: 0.72rem;
    font-weight: 800;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    background: rgba(0, 0, 0, 0.5);
    border: 1px solid rgba(242, 201, 76, 0.3);
    border-radius: 2px;
}

.cost-aether { color: var(--gold); }

/* A note in place of a price ("1x per ronde"): may wrap, the button can be narrow. */
.cost-note { max-width: 100%; text-align: right; line-height: 1.15; white-space: normal; color: var(--gold-hi); }
.cost-mana { color: #38bdf8; border-color: rgba(56, 189, 248, 0.35); }
/* Also costs Hout: a small tree perched on the Aether price, in the colour of the Hout counter. A button has no room for a second number. */
.cost-tag:has(.cost-plus) { position: relative; }
.cost-plus { position: absolute; top: -9px; right: -1px; font-size: 0.72rem; color: var(--hout); filter: drop-shadow(0 0 2px #000); }
.hud-lumber > i { color: var(--hout); }
/* Five to a row leaves a charged item's note ("1x per ronde") no second line, and "Gebruikt" no room beside a hotkey. */
#action-grid.dense .note-long,
#action-grid.dense .action-btn[aria-disabled="true"] kbd { display: none; }

.action-btn kbd,
#action-grid .action-btn kbd {
    position: absolute !important;
    left: 4px;
    bottom: 3px;
    z-index: 2;
}

/* What an action does (UIManager.showTooltip). With a mouse it floats over the hovered button; it sits in the deck's
   markup so that on touch screens it can dock there instead, see the touch rules at the end. Fixed, because
   showTooltip places it in viewport coordinates. */
#ui-tooltip {
    position: fixed;
    z-index: 50;
    width: 20rem;
    max-width: calc(100vw - 20px);
    padding: 14px 16px;
    pointer-events: none;
    font-size: 0.82rem;
    color: var(--gold-dim);
    background: var(--glass);
    border: 1px solid var(--line);
    border-radius: 3px;
    box-shadow: 0 24px 60px -20px #000, 0 0 50px -24px var(--aether);
}

.tip-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }

.tip-head h4 {
    min-width: 0;
    margin: 0;
    font-family: var(--font-ui);
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: 0.04em;
    color: var(--gold-hi);
}

.tip-head h4 i { margin-right: 0.3em; font-size: 0.85em; color: #ff9c8a; } /* the padlock of a locked building */
.tip-kind { flex: none; }
.tip-note { margin: 4px 0 0; font-weight: 700; line-height: 1.3; color: #fff8de; }
.tip-stats { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 8px 0 0; padding-top: 8px; border-top: 1px solid var(--hair); }
.tip-stats div { display: flex; align-items: baseline; gap: 6px; }
.tip-stats dd { margin: 0; font-weight: 800; font-variant-numeric: tabular-nums; color: #fff; }
.tip-desc { margin: 8px 0 0; font-family: var(--font-ui); font-style: italic; font-size: 0.95rem; line-height: 1.35; text-wrap: pretty; color: #cbd5e1; }
.tip-close { display: none; }

/* Stat diff improvements and combat mechanics in rich tooltips (R5) */
.tip-diffs {
    margin: 8px 0 0;
    padding: 6px 8px;
    background: rgba(0, 0, 0, 0.45);
    border: 1px solid rgba(242, 201, 76, 0.25);
    border-radius: 2px;
    font-size: 0.78rem;
}

.tip-diff-head {
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--gold-hi);
    margin-bottom: 4px;
}

.tip-diff-row {
    display: flex;
    align-items: baseline;
    gap: 6px;
    line-height: 1.35;
    font-variant-numeric: tabular-nums;
}

.diff-label {
    color: var(--gold-dim);
    min-width: 82px;
}

.diff-before {
    color: #94a3b8;
    text-decoration: line-through;
    opacity: 0.8;
}

.diff-arrow {
    color: var(--gold);
    font-size: 0.75rem;
}

.diff-after {
    color: #ffffff;
    font-weight: 700;
}

.diff-badge {
    color: #86efac;
    font-weight: 800;
    margin-left: auto;
}

.tip-mechanics {
    margin: 6px 0 0;
    padding: 6px 8px;
    background: rgba(30, 27, 75, 0.45);
    border-left: 2px solid #a855f7;
    font-size: 0.78rem;
    color: #e2e8f0;
    line-height: 1.3;
}

.tip-mech-text {
    margin: 2px 0 0;
    color: #f1f5f9;
}

/* The info tab of an action. Touch only (it carries .for-touch): with a mouse the card shows on hover. */
.action-info {
    flex: none;
    display: grid;
    place-items: center;
    width: 40px; /* a finger beside the build button must not start a build */
    margin-left: -1px; /* shares the button's hairline */
    font-size: 1.05rem;
    color: var(--gold-dim);
    background: rgba(8, 9, 14, 0.92);
    border: 1px solid rgba(242, 201, 76, 0.28);
    border-radius: 0 2px 2px 0;
    cursor: pointer;
    touch-action: manipulation;
    transition: color 0.2s, background-color 0.2s, border-color 0.2s, transform 0.35s var(--ease);
}

.action-info:active { transform: scale(0.92); }
.action-info[aria-expanded="true"] { color: #1b1202; background: var(--gold); border-color: var(--gold-hi); }

/* ── Cinematic overlays: pause, round result, game over. The live battlefield is the backdrop. ── */

.hud-scrim {
    background: radial-gradient(ellipse at center, rgba(4, 5, 8, 0.5) 0%, rgba(4, 5, 8, 0.92) 78%);
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
}

.hud-hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: clamp(0.75rem, 2.5vh, 1.5rem);
    width: min(92vw, 64rem);
    text-align: center;
    animation: hud-hero-in 0.8s var(--ease) backwards;
}

@keyframes hud-hero-in {
    from { opacity: 0; transform: translateY(22px) scale(0.97); filter: blur(6px); }
}

/* Wide container and a clamped size keep every title to two lines at most. */
.hud-hero-title {
    margin: 0;
    font-family: var(--font-ui);
    font-size: clamp(3rem, 5vw + 2vh, 5.5rem);
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.04em;
    text-wrap: balance;
    color: var(--gold-hi);
    text-shadow: 0 2px 0 rgba(0, 0, 0, 0.9), 0 0 36px color-mix(in srgb, var(--aether) 60%, transparent);
}

/* Game over takes the whole screen, washed green for a win and red for a loss (data-result, set in main.js).
   --aether follows the result so the title glow, the own scoreboard column and the button glow match it. */
#game-over-screen {
    --result: #4ade80;
    --aether: var(--result);
    background:
        radial-gradient(110% 65% at 50% 0%, color-mix(in srgb, var(--result) 30%, transparent), transparent 70%),
        radial-gradient(ellipse at center, rgba(4, 5, 8, 0.8) 0%, rgba(4, 5, 8, 0.97) 75%);
    box-shadow: inset 0 0 200px -60px var(--result);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    animation: go-wash 0.9s ease backwards;
}

#game-over-screen[data-result="lose"] { --result: #f04444; }

@keyframes go-wash { from { opacity: 0; } }

/* Blackletter only where the text is mixed case; it is unreadable in capitals. */
#go-title {
    font-family: var(--font-mark);
    font-size: clamp(4rem, 7vw + 3vh, 8rem);
    font-weight: 800;
    letter-spacing: 0;
    background: linear-gradient(180deg, color-mix(in srgb, var(--result) 25%, #fff) 15%, var(--result) 55%, color-mix(in srgb, var(--result) 55%, #000));
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    text-shadow: none;
    filter: drop-shadow(0 3px 0 rgba(0, 0, 0, 0.9)) drop-shadow(0 0 40px color-mix(in srgb, var(--result) 55%, transparent));
}

.hud-hero-sub {
    max-width: 44rem;
    margin: 0;
    font-family: var(--font-ui);
    font-style: italic;
    font-size: clamp(1.05rem, 1.2vw + 0.6vh, 1.4rem);
    line-height: 1.4;
    text-wrap: balance;
    color: #e6dfcc;
    text-shadow: 0 1px 12px #000;
}

#round-countdown { font-style: normal; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--gold); }

.hud-hero-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 12px;
    margin-top: clamp(0.5rem, 2vh, 1.5rem);
}

#go-scoreboard {
    width: min(92vw, 34rem);
    max-height: 36vh;
    overflow-y: auto;
    padding: 8px 14px 10px;
    background: var(--glass);
    border: 1px solid color-mix(in srgb, var(--result) 35%, transparent);
    border-top: 2px solid var(--result);
    border-radius: 3px;
}

#go-scoreboard:empty { display: none; }

.hud-cta {
    min-height: 3.2rem;
    padding: 0 2.25rem;
    font-family: var(--font-data);
    font-size: 1rem;
    font-weight: 800;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: #1b1202;
    background: linear-gradient(180deg, #fff0bd 0%, #f3cb5b 30%, #d79f25 62%, #9c6a0d 100%);
    border: 1px solid #ffe9a6;
    border-radius: 2px;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7), 0 0 0 1px rgba(0, 0, 0, 0.6), 0 16px 44px -14px var(--aether);
    cursor: pointer;
    transition: transform 0.35s var(--ease), filter 0.2s, border-color 0.2s, color 0.2s;
}

.hud-cta:hover { transform: translateY(-2px); filter: brightness(1.08); }
.hud-cta:active { transform: translateY(1px); }

.hud-cta-ghost {
    color: #f3ead0;
    background: rgba(10, 11, 16, 0.7);
    border-color: var(--line);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.09);
}

.hud-cta-ghost:hover { color: #fff; border-color: var(--gold); filter: none; }

/* ── The Archives: the one scrolling surface, so the scroll-driven pieces live here ── */

.codex-frame { display: flex; flex-direction: column; width: 100%; max-width: 72rem; max-height: 90vh; max-height: 90dvh; overflow: hidden; }

.codex-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.75rem 0.75rem 0.75rem 1.5rem;
    border-bottom: 1px solid var(--hair);
}

.codex-head h2 {
    margin: 0;
    font-family: var(--font-ui);
    font-size: 1.4rem;
    font-weight: 700;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--gold-hi);
}

#btn-close-codex {
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    font-size: 1.2rem;
    color: var(--gold-dim);
    border: 1px solid transparent;
    border-radius: 2px;
    transition: color 0.2s, border-color 0.2s, transform 0.5s var(--ease);
}

#btn-close-codex:hover { color: #fff; border-color: var(--line); transform: rotate(90deg); }

#codex-content {
    flex: 1;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: clamp(1rem, 3vw, 2.5rem);
    padding-top: 0;
    font-size: 0.95rem;
    line-height: 1.6;
    color: #e6dfcc;
}

.codex-display {
    margin: 0;
    padding: clamp(1.5rem, 5vh, 3.5rem) 0;
    font-family: var(--font-mark);
    font-size: clamp(2.25rem, 5vw, 4.5rem);
    font-weight: 800;
    line-height: 1.05;
    text-wrap: balance;
    color: var(--gold-hi);
}

/* Inline pill set into the heading: the five faction flames. */
.type-pill {
    display: inline-block;
    width: 2.4em;
    height: 0.62em;
    margin: 0 0.12em;
    vertical-align: 0.06em;
    background: linear-gradient(90deg, #ff8b3d, #ffe6a3, #58f07a, #ff4d2e, #8f5bff, #ff8b3d) 0 0 / 200% 100%;
    border-radius: 999px;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.3), 0 0 30px -6px #ff8b3d;
    animation: pill-drift 9s linear infinite;
}

@keyframes pill-drift {
    to { background-position: -200% 0; }
}

.codex-split { display: grid; grid-template-columns: minmax(0, 1fr); gap: 2rem; }

.codex-pin h3 {
    margin: 0 0 0.5rem;
    font-family: var(--font-ui);
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.15;
    color: var(--gold);
}

.codex-pin p { margin: 0 0 1.75rem; max-width: 34rem; }

.codex-stack { display: flex; flex-direction: column; gap: 1.25rem; }

.codex-card {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    padding: 1.25rem 1.5rem 1.5rem;
    background: linear-gradient(180deg, #161823, #0a0b10);
    border: 1px solid var(--line);
    border-radius: 3px;
    box-shadow: 0 -20px 40px -26px #000;
}

/* The faction's fire, banked low until the card is hovered. */
.codex-card::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    background: radial-gradient(90% 70% at 85% 115%, color-mix(in srgb, var(--flame) 45%, transparent), transparent 70%);
    opacity: 0.55;
    transform-origin: bottom right;
    transition: transform 0.7s ease-out, opacity 0.5s;
}

.codex-card:hover::before { opacity: 1; transform: scale(1.05); }

.codex-card h4 { margin: 0; font-family: var(--font-ui); font-size: 1.5rem; font-weight: 700; color: var(--gold-hi); }
.codex-card blockquote { margin: 0.15rem 0 1rem; font-family: var(--font-ui); font-style: italic; color: var(--gold-dim); }
.codex-card dl { display: grid; gap: 0.6rem; margin: 0; }
.codex-card dt { font-size: 0.7rem; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; color: var(--flame); }
.codex-card dd { margin: 0; font-size: 0.86rem; line-height: 1.45; color: #cbd5e1; }

/* Room to read: the title column pins while the faction cards stack over one another. Needs a
   scroller taller than a card, so short and narrow screens get a plain list. */
@media (min-width: 900px) and (min-height: 700px) {
    .codex-split { grid-template-columns: minmax(0, 4fr) minmax(0, 7fr); align-items: start; gap: 3rem; }
    .codex-pin { position: sticky; top: 0.5rem; }
    .codex-stack { padding-bottom: 14vh; }
    .codex-card { position: sticky; top: calc(0.5rem + var(--i) * 0.9rem); }
}

/* Narrow windows wrap the actions into two short rows; the badge row has to make way for the title. */
@media (max-width: 1100px) {
    .action-btn-badges { display: none; }
}

/* Where the badges show, the corner icon needs room beside the title. */
@media (min-width: 1101px) {
    #action-grid.dense .action-btn .title { padding-right: 18px; }
}

/* ── Phones in landscape and narrow windows ── */

@media (max-height: 520px), (max-width: 900px) {
    :root { --hud-pad: 6px; --deck-h: 104px; --actions-w: clamp(220px, 38vw, 340px); }

    #game-ui {
        padding-left: env(safe-area-inset-left, 0px);
        padding-right: env(safe-area-inset-right, 0px);
    }

    .hud-island { min-height: 36px; padding: 2px; -webkit-backdrop-filter: none; backdrop-filter: none; }
    .hud-faction { gap: 8px; padding: 0 8px; font-size: 0.8rem; letter-spacing: 0.08em; }
    .hud-stat { height: 28px; gap: 4px; padding: 0 8px; }
    .hud-value { font-size: 1rem; }
    .hud-sub { font-size: 0.65rem; }
    .hud-keys:not(.for-touch) { display: none; }
    .hud-score-side, .hud-score-mid { padding: 0 8px; gap: 0; }
    .hud-score-side { min-width: 0; }
    .hud-btn { min-height: 28px; padding: 0 7px; font-size: 0.68rem; letter-spacing: 0.08em; }
    .hud-income { min-width: 10ch; font-size: 0.6rem; }
    .hud-status .hud-stat { padding: 0 6px; }
    .hud-banner { top: calc(var(--hud-pad) + 44px); padding: 6px 14px; }
    .hud-banner-main { font-size: 1rem; }
    .hud-scoreboard { top: calc(var(--hud-pad) + 44px); padding: 6px 10px 8px; }
    .sb-table th, .sb-table td { padding: 1px 6px; font-size: 0.68rem; }
    .sb-table thead th { font-size: 0.64rem; }
    #go-scoreboard { max-height: 40vh; max-height: 40dvh; padding: 4px 10px 6px; }

    #minimap-container { width: min(26vw, calc(4 * (var(--deck-h) - 2 * var(--hud-pad)) + 2 * var(--hud-pad))); }
    #unit-stats-panel { --cell-h: 27px; gap: 8px; padding: var(--hud-pad) 8px; }
    #unit-portrait-container { max-height: 60px; }
    #context-panel, .ctx-main, .ctx-aside { gap: 3px; }
    #ctx-title { font-size: 1rem; }
    .ctx-meter-value, #ctx-spawn-timer-text { font-size: 0.7rem; }
    .ctx-bar { height: 6px; }
    .stat-label { font-size: 0.66rem; letter-spacing: 0.06em; }
    .stat-value { font-size: 0.85rem; }
    #ctx-desc, #ctx-lore { display: none; }
    .ctx-empty { font-size: 0.85rem; }

    /* Nine actions (the Nexus shop, a T3 spawner with older upgrades unbought) wrap to a third row of four: it scrolls into view. */
    #action-grid-parent { overflow-y: auto; overscroll-behavior: contain; }
    #action-grid { gap: 4px; }
    .action-slot { flex-basis: 60px; }
    .action-btn { padding: 3px 4px; }
    .action-btn .title { font-size: 0.68rem; }
    .cost-tag { font-size: 0.62rem; padding: 1px 3px; }
    .action-btn kbd { display: none; }

    .hud-cta { min-height: 2.6rem; padding: 0 1.25rem; font-size: 0.85rem; }
    .codex-head h2 { font-size: 1.05rem; }
}

/* ── Tool menu: once the three islands no longer fit side by side, the tool buttons fold behind
   one toggle (js/ui/hud_menu.js). On wide screens the toggle is gone and the list is transparent. ── */

.hud-menu-toggle { display: none; }
.hud-tools-list { display: contents; }

/* Placing a building by touch: says what the next tap does, beside the cancel button. */
.hud-build-hint {
    position: absolute;
    left: max(var(--hud-pad), env(safe-area-inset-left, 0px));
    bottom: calc(var(--deck-h) + var(--map-h) + env(safe-area-inset-bottom, 0px) + 12px);
    display: flex;
    align-items: center;
    min-height: 44px;
    margin: 0;
    padding: 0 14px;
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--gold-hi);
    background: var(--glass);
    border: 1px solid var(--line);
    border-radius: 3px;
    box-shadow: 0 14px 36px -14px #000;
}

#btn-cancel-build.hidden + .hud-build-hint { display: none; }

@media (max-height: 520px), (max-width: 900px) {
    .hud-top { z-index: 2; } /* the open list may reach down over the deck on a landscape phone */
    .hud-tools { position: relative; }
    .hud-menu-toggle { position: relative; display: inline-flex; justify-content: center; min-width: 44px; min-height: 32px; padding: 0; font-size: 1.15rem; }
    .hud-menu-toggle::after { content: ''; position: absolute; inset: -6px; } /* a 44px target around a 32px button */
    .hud-tools.open .hud-menu-toggle { color: #fff8de; background: rgba(255, 255, 255, 0.06); border-color: var(--line); }

    .hud-tools-list {
        position: absolute;
        top: calc(100% + 6px);
        right: 0;
        z-index: 5;
        display: none;
        flex-direction: column;
        gap: 2px;
        min-width: 11rem;
        padding: 4px;
        background: var(--glass);
        border: 1px solid var(--line);
        border-radius: 3px;
        box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 24px 60px -20px #000, 0 0 50px -24px var(--aether);
    }

    .hud-tools.open .hud-tools-list { display: flex; animation: hud-drop 0.35s var(--ease) backwards; }
    .hud-tools-list .hud-btn { min-height: 44px; padding: 0 14px; font-size: 0.72rem; letter-spacing: 0.14em; }
}

/* ── Phones: the minimap is a thumbnail. A tap opens it, and only the open map steers the camera;
   a touch on the field puts it back (input_handler.js). Each layout below gives it its corner and its two widths. ── */

@media (max-width: 640px) and (min-height: 521px), (hover: none) and (pointer: coarse) and (max-height: 520px) {
    #minimap-container {
        position: absolute;
        grid-area: auto; /* out of the grid: measured from the deck's own edges, not from a cell's */
        left: max(var(--hud-pad), env(safe-area-inset-left, 0px));
        z-index: 1;
        padding: 0;
        cursor: pointer;
        transition: width 0.3s var(--ease);
    }
    #minimap-container:not(.open) #minimap { pointer-events: none; }
    #minimap { box-shadow: inset 0 0 20px #000, 0 12px 30px -12px #000; }
}

/* ── Phones held upright: status over the score, and a deck of two rows of actions with the minimap's
   thumbnail on its top edge. Same breakpoint as the lobby sheet in lobby.css. ── */

@media (max-width: 640px) and (min-height: 521px) {
    /* The deck is two rows of actions. A selection adds a row above them and takes the minimap's place. */
    :root { --deck-h: 116px; --map-h: calc(9.5vw + var(--hud-pad)); }
    #game-ui:has(#context-panel:not(.hidden)) { --deck-h: 217px; --map-h: 0px; }
    #game-ui:has(#context-panel:not(.hidden)) #minimap-container { display: none; }

    .hud-top { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "status tools" "score score"; row-gap: 4px; }
    .hud-status { grid-area: status; justify-self: stretch; }
    .hud-faction { flex: 1; }
    /* The Hout counter takes the room of the word "over": the next wave reads "+33/10s" here. */
    .hud-over { font-size: 0; }
    .hud-over::after { content: "/"; font-size: 0.6rem; }
    .hud-income { min-width: 7ch; }
    .hud-status .hud-stat { padding: 0 4px; }
    .hud-tools { grid-area: tools; }
    .hud-score { grid-area: score; justify-self: center; min-height: 30px; }

    /* Everything hung under the top bar clears both of its rows, and the notch. */
    .hud-banner,
    .hud-scoreboard { top: calc(max(var(--hud-pad), env(safe-area-inset-top, 0px)) + 88px); }
    /* Edge to edge: centred on left: 50% it could only shrink to half the screen, too narrow for the touch hints. */
    .hud-banner { left: var(--hud-pad); right: var(--hud-pad); max-width: none; transform: none; }
    .hud-scoreboard { max-height: calc(100% - var(--deck-h) - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px) - 110px); }
    /* above the deck, not over the wave banner under the top bar */
    #error-popup { top: auto; bottom: calc(var(--deck-h) + var(--map-h) + env(safe-area-inset-bottom, 0px) + 56px); }

    #bottom-ui-bar { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); transition: height 0.3s var(--ease); }
    /* 38vw across is the 9.5vw of --map-h tall: the board is 4:1. Open, it spans the screen. */
    #minimap-container { bottom: calc(100% + var(--hud-pad)); width: 38vw; }
    #minimap-container.open { width: calc(100% - 2 * var(--hud-pad)); }

    /* The selection strip lays itself out by its own width (the @container rules above); with
       nothing selected the row closes up. */
    /* 104px: the tallest selection (a spawner with mana) is five rows, 90px, inside 6px of padding. */
    #unit-stats-panel { grid-area: 1 / 1; height: 104px; padding: 6px 10px; border-left: 0; }
    #unit-stats-panel:has(#context-panel.hidden) { display: none; }

    /* Three to a row, four once there are seven or more; a third row scrolls. */
    #action-grid-parent { grid-area: 2 / 1; width: auto; border-left: 0; overflow-y: auto; overscroll-behavior: contain; }
    #action-grid { height: auto; min-height: 100%; }
    .action-slot { flex-basis: calc(33.33% - 4px); min-height: 48px; }
    /* Ten actions are three rows of four: the deck makes room for all three instead of scrolling the spell out of sight. */
    #action-grid.dense .action-slot { flex-basis: calc(25% - 4px); min-height: 46px; max-height: none; }
    #game-ui:has(#action-grid.dense) { --deck-h: 170px; }
    #game-ui:has(#action-grid.dense):has(#context-panel:not(.hidden)) { --deck-h: 271px; }
}

/* ── Touch: no cursor to hover with, no keys to press ── */

@media (hover: hover), (pointer: fine) {
    .for-touch { display: none !important; }
}

@media (hover: none) and (pointer: coarse) {
    #scoreboard.hud-scoreboard { pointer-events: auto; }
    .for-mouse,
    .action-btn kbd { display: none !important; }

    /* A tap leaves :hover stuck on the button, so the feedback moves to the press. */
    .hud-btn:hover,
    .hud-cta:hover,
    .action-btn:hover { transform: none; }
    .hud-btn:active,
    .hud-cta:active,
    .action-btn:active { transform: scale(0.96); }

    .action-btn:not(:only-child) { border-radius: 2px 0 0 2px; }

    /* Puts the selection away (hud_menu.js). It sits in the corner the selection's kind label has on wider cells. */
    #unit-stats-panel { position: relative; }
    #unit-stats-panel:has(#context-panel.hidden) .ctx-close { display: none; }
    .ctx-close { position: absolute; top: 0; right: 0; display: grid; place-items: center; width: 44px; height: 44px; font-size: 0.95rem; color: var(--gold-dim); }
    .ctx-close:active { transform: scale(0.9); }
    .ctx-head { padding-right: 30px; }

    /* No cursor to anchor a tooltip to, and a card over the field hides the fight. The card opens from an action's
       info tab and takes the place of the minimap and the selection inside the deck, so the field stays clear and
       the actions stay live beside it. A tap on the card, on its tab or on the field puts it away. */
    #ui-tooltip {
        position: relative;
        inset: auto !important; /* showTooltip's left and top are for the hover tooltip */
        grid-area: 1 / 1 / 2 / 3;
        z-index: 3;
        container: tip / size; /* size containment: whatever it has to say, the deck's rows keep their height */
        width: auto;
        max-width: none;
        padding: 6px 34px 6px 12px;
        overflow-y: auto;
        overscroll-behavior: contain;
        pointer-events: auto;
        background: #0c0d13;
        border: 0;
        border-radius: 0;
        box-shadow: inset 0 0 0 1px var(--line), inset 0 -40px 60px -50px var(--aether);
        animation: ctx-in 0.3s var(--ease) backwards;
    }

    .tip-head { justify-content: flex-start; }
    .tip-head h4 { font-size: 1rem; line-height: 1.1; }
    .tip-note { margin-top: 2px; font-size: 0.76rem; line-height: 1.25; }
    .tip-stats { gap: 0 12px; margin-top: 3px; padding-top: 3px; font-size: 0.76rem; line-height: 1.25; }
    .tip-stats .stat-label { font-size: 0.68rem; letter-spacing: 0.08em; }
    .tip-desc { margin-top: 3px; font-size: 0.86rem; line-height: 1.2; }
    .tip-close { position: absolute; top: 8px; right: 10px; display: block; font-size: 0.95rem; color: var(--gold-dim); }

    /* A phone's card is short: the notes and the numbers stay whole, the lore is cut to two lines, or to one
       where the card is narrow enough for the numbers to need a second row. */
    @container tip (max-height: 130px) {
        .tip-desc { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
        .tip-note ~ .tip-desc { display: none; } /* a note says more than the lore it replaces */
    }
    @container tip (max-height: 130px) and (max-width: 380px) {
        .tip-desc { -webkit-line-clamp: 1; }
    }
}

/* A landscape phone has no deck: the field runs to the bottom edge. The actions stand two abreast on the right,
   the minimap's thumbnail has the left corner, and a selection or an action's card lies along the bottom between them. */
@media (hover: none) and (pointer: coarse) and (max-height: 520px) {
    /* --deck-h is what stands in the left corner: the thumbnail, or the selection or card in its place. */
    :root { --deck-h: 40px; --actions-w: clamp(184px, 25vw, 216px); }
    #game-ui:has(#context-panel:not(.hidden)),
    #game-ui:has(#ui-tooltip:not(.hidden)) { --deck-h: 110px; }
    /* the toast stands over the bottom strip, between the corner and the actions, clear of the wave banner */
    #error-popup { top: auto; bottom: calc(var(--deck-h) + env(safe-area-inset-bottom, 0px) + 16px); left: calc((100% - var(--actions-w)) / 2); }

    /* The bar is the whole screen under the top bar, see-through and deaf: its cells stand at its bottom
       and take the touches, the field has the rest. */
    #bottom-ui-bar {
        inset: calc(max(var(--hud-pad), env(safe-area-inset-top, 0px)) + 44px) 0 0 0;
        height: auto;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: end;
        gap: var(--hud-pad);
        padding: 0 max(var(--hud-pad), env(safe-area-inset-right, 0px)) max(var(--hud-pad), env(safe-area-inset-bottom, 0px)) max(var(--hud-pad), env(safe-area-inset-left, 0px));
        background: none;
        border: 0;
        box-shadow: none;
        pointer-events: none;
    }

    #minimap-container { bottom: max(var(--hud-pad), env(safe-area-inset-bottom, 0px)); width: 136px; }
    /* Open, as wide as the room beside the actions allows. */
    #minimap-container.open { width: min(34rem, calc(100% - var(--actions-w) - 3 * var(--hud-pad) - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px))); }

    #unit-stats-panel,
    #ui-tooltip { grid-area: 1 / 1; height: 104px; border-radius: 3px; }
    #unit-stats-panel { background: var(--glass); border: 1px solid var(--line); box-shadow: 0 14px 36px -14px #000; }
    #unit-stats-panel:has(#context-panel.hidden),
    #game-ui:has(#context-panel:not(.hidden)) #minimap-container { display: none; }

    /* Two abreast, each 44px tall: ten actions stand in five rows, more scroll. */
    #action-grid-parent {
        grid-area: 1 / 2;
        max-height: 100%;
        overflow-y: auto;
        overscroll-behavior: contain;
        background: var(--glass);
        border: 1px solid var(--line);
        border-radius: 3px;
        box-shadow: 0 14px 36px -14px #000;
    }
    #action-grid { height: auto; }
    .action-slot,
    #action-grid.dense .action-slot { flex: 0 0 calc(50% - 2px); height: 44px; }
    .action-info { width: 36px; }

    /* Both make way for the actions. */
    #btn-cancel-build { right: calc(max(var(--hud-pad), env(safe-area-inset-right, 0px)) + var(--actions-w) + var(--hud-pad)); }
    .hud-scoreboard { left: calc((100% - var(--actions-w)) / 2); max-width: calc(100% - var(--actions-w) - 4 * var(--hud-pad)); }
}

/* Upright, the deck is one column: the card lies over the selection, or opens that row when nothing is selected. */
@media (hover: none) and (pointer: coarse) and (max-width: 640px) and (min-height: 521px) {
    #game-ui:has(#ui-tooltip:not(.hidden)) { --deck-h: 217px; }
    #ui-tooltip { grid-area: 1 / 1; height: 104px; }
}

@media (prefers-reduced-motion: reduce) {
    #game-ui *,
    .hud-hero,
    .type-pill,
    #error-popup {
        animation: none !important;
        transition: none !important;
    }
}
