/* css/screens.css — the full-screen views (WP-071/073, 12 § TitleScreen and the screen set).

   `#screen-root` cross-fades as ONE element (ui/screenRouter.js drives its opacity), so nothing in
   here animates a screen's own opacity — two overlapping fades would multiply and the swap would
   dip to black in the middle instead of crossing. */

.screen {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

/* ── TitleScreen ───────────────────────────────────────────────────────────────────────── */

/* No `position` here. `.screen` above is already `absolute; inset: 0`, which is both what fills
   #screen-root AND the containing block the backdrop needs — and since `.screen-title` has the same
   specificity and comes later, adding `position: relative` here silently OVERRODE that absolute and
   collapsed the container to a content-sized box (390px of a 720px root), centring the menu in the
   top half of the screen. It looked like a flexbox problem and was a cascade problem. */
.screen-title {
    overflow: hidden; /* the drifting backdrop scales past its box — without this it paints over the
                         letterboxing and the game stops being pillarboxed on a wide monitor */
}

.title-backdrop {
    position: absolute;
    inset: 0;
    background: url('../assets/ui/title_backdrop.png') center / cover no-repeat;
    image-rendering: pixelated;
    /* 12: a slow 60 s scale drift 1.0 → 1.05. It is CSS rather than a rAF loop because a menu that
       spins the main thread to nudge a transform is a menu that costs battery while doing nothing —
       and the media query below disables it for free. */
    animation: title-drift 60s ease-in-out infinite alternate;
    transform-origin: center;
    z-index: 0;
}

@keyframes title-drift {
    from { transform: scale(1); }
    to   { transform: scale(1.05); }
}

.title-logo,
.title-buttons,
.title-version {
    position: relative;
    z-index: 1; /* above the backdrop, below nothing else — the title screen has no overlays */
}

.title-logo {
    margin: 0 0 var(--space-6);
}

.title-buttons {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    width: 16rem; /* 12 § TitleScreen pins the column width */
}

.title-version {
    position: absolute;
    right: var(--space-3);
    bottom: var(--space-2);
    margin: 0;
    /* 12 § TitleScreen pins 0.875rem and --ui-parchment-dark exactly. This was 11px at 0.5 opacity
       — under 12's own floor ("All text >= 14 px CSS", § Accessibility), and dimmed a token that is
       already the dim one. A version stamp is small print, not unreadable print. */
    font-size: 0.875rem;
    color: var(--ui-parchment-dark);
}

/* ── BootGateScreen ────────────────────────────────────────────────────────────────────── */

.screen-gate {
    background: var(--ui-ink); /* 12 § BootGateScreen: full-screen --ui-ink behind the panel */
}

.gate-panel {
    width: 100%;
    max-width: 40rem; /* 12 § BootGateScreen (the settings panel is 44rem — deliberately wider) */
    max-height: 90vh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    align-items: flex-start;
}

.gate-logo {
    margin: 0 0 var(--space-3);
    align-self: center;
}

.gate-steps {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    width: 100%;
}

.gate-step {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    color: var(--ui-parchment);
}

/* The three seals are the FIRST THREE CELLS of icons_ui.png's row 0, in this order. That is not a
   guess: 13 § icons_ui pins the sheet's cell order („the three gate-checklist seals siegel_wartend,
   siegel_gruen, siegel_gebrochen" first), artgen generates the sheet from 13, and the built
   manifest agrees (row 0, startCol 0/1/2 — checked, not assumed).

   Addressed from CSS rather than through render/sprites.js on purpose: 06 runs loadAllSheets AFTER
   the gate, so at gate time no manifest and no atlas exist. A gate that waited for 112 sheets to
   validate could never report the failure that stopped them loading. */
.gate-seal {
    flex: none;
    width: 16px;
    height: 16px;
    background-image: url('../assets/ui/icons_ui.png');
    image-rendering: pixelated;
}

.gate-seal[data-seal='siegel_wartend'] { background-position: 0 0; }
.gate-seal[data-seal='siegel_gruen']   { background-position: -16px 0; }
.gate-seal[data-seal='siegel_gebrochen'] { background-position: -32px 0; }

.gate-heading {
    margin: 0;
    color: var(--ui-parchment);
}

/* --ui-parchment, not --ui-parchment-dark. OWNER DECISION 2026-07-16: secondary text on wood read
   3.42:1, under WCAG AA's 4.5:1 for 14 px. Brightening clears it at 4.87:1 with no art change.
   The dim/bright hierarchy on wood is deliberately given up — 4.87:1 is the ceiling against
   panel_holz's midtone without regenerating the art, and primary text is at that ceiling too. The
   hierarchy now comes from SIZE and position (0.875rem vs 1rem), not from colour. */
.gate-body,
.gate-note {
    margin: 0;
    font-size: 0.875rem;
    color: var(--ui-parchment);
}

.gate-failure {
    /* Parchment, per 12: the failure detail is the one thing on this screen the player must READ,
       and ink-on-parchment is the contrast pair the accessibility floor is measured against. */
    color: var(--ui-ink);
    width: 100%;
}

.gate-failure .gate-heading,
.gate-failure .gate-body,
.gate-hints {
    color: var(--ui-ink);
}

.gate-hints {
    margin: var(--space-2) 0 0;
    padding-left: var(--space-4);
    font-size: 0.875rem;
}

/* 12: a wood trough with a gold fill and 1 px stepped pixel edges — no radius, no gradient. */
.gate-progress {
    width: 100%;
    height: 16px;
    background: var(--ui-wood-dark);
    border: 2px solid var(--ui-wood);
    border-radius: 0;
}

.gate-progress-fill {
    height: 100%;
    /* `width: 0` is load-bearing, not a default. This is a block div, so without it `width: auto`
       fills the trough — measured: a FULL bar on a fresh mount, before generation or a download had
       run a single step. Both users of this bar set an inline width on their first report, so the
       bug only ever showed in the gap before it, which is exactly the moment the bar is a promise
       about how long the player must wait. */
    width: 0;
    background: var(--ui-gold);
    /* No transition: the fill is driven by real download progress, and an eased width would report
       a percentage the download has not reached. */
}

/* ── SettingsScreen ────────────────────────────────────────────────────────────────────── */

.settings-frame {
    width: 100%;
    max-width: 44rem; /* 12 § SettingsScreen */
    /* 12 § Edge cases: panels keep an internal scroll rather than collapsing the layout, so the
       Spiel tab (six sliders + a seven-row table) stays reachable at the 720 px minimum height. */
    max-height: 90vh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    /* No background: `.panel-wood`'s `border-image … fill` paints the middle slice over the content
       box, so one here would be invisible dead code. */
}

.settings-tabs {
    display: flex;
    gap: var(--space-2);
    align-items: flex-end;
}

/* Inactive handles are the DARK wood and the active one is the plain wood — 13 § Palette owns the
   hex values and the set is exactly --ui-wood / --ui-wood-dark. The `--ui-wood-light` this first
   reached for does not exist; a var() fallback would have hidden that behind an off-token brown
   invented here, which is precisely what 12 forbids ("reference the semantic tokens only, never
   hex values"). Receding the inactive tabs reads the same and costs no new token. */
.settings-tab {
    border: 0;
    background: var(--ui-wood-dark);
    color: var(--ui-parchment-dark);
    font: inherit;
    padding: var(--space-2) var(--space-3);
    cursor: pointer;
    /* 12: "active tab lifts 2 px". The lift is a margin change, not a transform, so the tab strip's
       baseline actually moves and the active handle reads as joined to the panel below it. */
    margin-bottom: 0;
}

.settings-tab.is-active {
    background: var(--ui-wood);
    color: var(--ui-parchment);
    margin-bottom: 2px;
}

.settings-tab:focus-visible {
    outline: 2px solid var(--ui-gold);
    outline-offset: 2px;
}

.settings-panel {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.settings-row {
    display: grid;
    /* The value readout is a fixed column: letting it size to content makes every slider's right
       edge jump as the number goes 100 % → 95 % mid-drag. */
    grid-template-columns: 12rem 1fr 4rem;
    align-items: center;
    gap: var(--space-3);
}

.settings-label {
    color: var(--ui-parchment);
}

.settings-value {
    text-align: right;
    color: var(--ui-parchment);
    font-variant-numeric: tabular-nums;
}

.settings-slider:disabled,
.settings-toggle:disabled {
    opacity: 0.5;
}

.settings-presets,
.settings-choices {
    display: flex;
    gap: var(--space-2);
}

.settings-choice[aria-pressed='true'] {
    outline: 2px solid var(--ui-gold);
    outline-offset: -4px; /* inside the 9-slice border, or the ring would sit on the wood frame */
}

.settings-note {
    margin: 0;
    font-size: 0.875rem; /* 12's floor: never below 14 px */
    color: var(--ui-parchment);
}

.settings-heading {
    margin: var(--space-3) 0 0;
    color: var(--ui-parchment);
}

.settings-shortcuts {
    border-collapse: collapse;
    color: var(--ui-parchment);
    font-size: 0.875rem;
    text-align: left;
}

/* Was --ui-gold: 3.13:1 on wood, the same failure as the parchment-dark text and missed by the same
   eye, because it is a different token. Gold is 12's selection/focus signal — 12 specifies no colour
   for this column, so tinting it was an invention that also spent a reserved signal on a static
   table. Parchment + bold reaches 4.87:1 and distinguishes the column by WEIGHT, which is the
   hierarchy rule the rest of this change adopts. Found by measuring every text on every screen, not
   by patching the ones I remembered writing. */
.settings-shortcut-key {
    padding-right: var(--space-3);
    white-space: nowrap;
    color: var(--ui-parchment);
    font-weight: bold;
}

.settings-scale-ends {
    grid-column: 2; /* under the slider it annotates, not in the label column */
    font-size: 0.875rem;
    color: var(--ui-parchment);
}

.settings-footer {
    display: flex;
    justify-content: flex-end;
}

/* 12 § Transitions: both the drift and the cross-fade are disabled under reduced motion. A drifting
   backdrop is exactly the kind of slow continuous motion that triggers vestibular symptoms, and it
   conveys nothing — so it stops entirely rather than merely slowing. */
@media (prefers-reduced-motion: reduce) {
    .title-backdrop {
        animation: none;
        transform: scale(1);
    }
}

/* ── WorldgenProgressScreen (12 § WorldgenProgressScreen) ──────────────────────────────── */

/* 12: "centered wood panel on darkened backdrop". Darkened rather than opaque — generation is the
   one screen where something IS happening behind the UI, and hiding the world entirely during the
   longest wait in the game wastes the only reassurance available. */
.screen-worldgen {
    background: rgb(0 0 0 / 0.6);
}

.worldgen-panel {
    width: 100%;
    max-width: 36rem;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    align-items: stretch;
}

.worldgen-title {
    margin: 0;
    color: var(--ui-parchment);
    text-align: center;
}

.worldgen-line {
    margin: 0;
    /* The stage caption changes on every report and the SOULS line grows a name and a trade. Without
       a reserved height the panel jolts each time the text wraps to a second line. */
    min-height: 2.5em;
    color: var(--ui-parchment);
}

.worldgen-warming {
    margin: 0;
    font-size: 0.875rem;
    color: var(--ui-parchment);
}

.worldgen-panel .button-wood {
    align-self: flex-end;
}

/* ── LoadGameScreen (12 § LoadGameScreen) ──────────────────────────────────────────────── */

/* 12: "Full-screen parchment". This was --ui-ink, copied from the gate without re-reading, and the
   heading vanished: the pixel font's glyphs are dark ink, so „Eure Spielstände" was dark-on-dark.
   It only ever looked fine on the title, where the backdrop happens to be a bright sky. Parchment is
   also what makes the wood cards read as objects laid ON something. */
.screen-loadgame {
    background: var(--ui-parchment);
    color: var(--ui-ink);
}

.loadgame-frame {
    width: 100%;
    max-width: 48rem; /* 12 § LoadGameScreen */
    max-height: 90vh;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.loadgame-title {
    margin: 0;
    align-self: center;
}

/* 12: "scrollable card list". The list scrolls, NOT the frame — the footer's „Zurück" and
   „Aus Datei einlesen" must stay reachable with twenty saves, and a player who cannot get back to
   the title is stuck on a screen whose whole purpose is leaving it. */
.loadgame-list {
    flex: 1;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    min-height: 0; /* without this a flex child refuses to shrink and the footer is pushed off */
}

.loadgame-card {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: var(--space-3);
    align-items: start;
    color: var(--ui-parchment);
}

.loadgame-thumb {
    width: 96px;
    height: 72px;
    image-rendering: pixelated;
}

.loadgame-thumb img {
    display: block;
    image-rendering: pixelated;
}

/* 12's crest placeholder for a save with no thumbnail — which every IMPORTED save is until its
   first real save (saveManager writes thumbnail: null on the import path), so this is an ordinary
   state, not a defensive one. 13 § icons_ui ships `wappen_platzhalter` for exactly this; a plain
   brown box would have been a placeholder standing in for a placeholder that already exists. */
.loadgame-thumb.is-placeholder {
    background: var(--ui-wood-dark);
    border: 2px solid var(--ui-wood);
    display: flex;
    align-items: center;
    justify-content: center;
}

/* A 16 px child, not a background on the 96×72 box: the box is far larger than one cell, so a
   background-position into the sheet would spill the NEIGHBOURING icons into view. */
.loadgame-crest {
    width: 16px;
    height: 16px;
    background-image: url('../assets/ui/icons_ui.png');
    background-position: -112px -16px; /* wappen_platzhalter: row 1, col 7 — checked in the manifest */
    image-rendering: pixelated;
}

.loadgame-name {
    margin: 0 0 var(--space-2);
}

.loadgame-line {
    margin: 0;
    font-size: 0.875rem;
    color: var(--ui-parchment); /* on the wood card; the screen's own text is --ui-ink */
}

.loadgame-actions {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* --ui-INK, not --ui-parchment-dark. This line sits on the parchment SCREEN, not on a wood card, and
   parchment-dark on parchment measures 1.42:1 — against 12 § Accessibility's stated floor ("contrast
   of --ui-ink on --ui-parchment", 7:1). --ui-ink measures 11.09:1.

   Worth naming: this was CORRECT until I fixed the background. The colour was chosen when the screen
   was --ui-ink, and turning the screen parchment silently inverted every foreground on it. A colour
   is only ever right against the thing behind it, so changing a background is a change to every
   text colour above it — and the one text that had no card under it was the one that broke. */
.loadgame-empty {
    margin: 0;
    color: var(--ui-ink);
    text-align: center;
}

/* D-P12's A/B rows, indented beneath their parent card. `grid-column: 1 / -1` is load-bearing: the
   card is a three-column grid and these rows are its 4th+ children, so without it each row drops
   into column 1 of a new grid row — measured as a stray „Laden" floating under the thumbnail. */
.loadgame-autosave {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin: var(--space-2) 0 0 var(--space-8);
}

/* The pending seal doubles as 12's hourglass: it is the "waiting/automatic" glyph in the same set
   (13 § icons_ui, row 0 col 0), so the autosave rows and the gate's checklist speak one language. */
.loadgame-hourglass {
    flex: none;
    width: 16px;
    height: 16px;
    background-image: url('../assets/ui/icons_ui.png');
    background-position: 0 0;
    image-rendering: pixelated;
}

.loadgame-footer {
    display: flex;
    justify-content: space-between;
    gap: var(--space-3);
}

/* The real <input type=file> is hidden INSIDE its styled label, so clicking the label is a genuine
   user gesture on the input. `display: none` would take it out of the accessibility tree and off the
   keyboard; this keeps it focusable and operable. */
.loadgame-file {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.loadgame-import {
    display: inline-flex;
    align-items: center;
    cursor: pointer;
}
