  :root {
    /* VIS-002: dark, modern theme. The names are historical (parchment/wood
       from the old brown look) — they are kept because they are used ~200
       times; only the values changed. Read them as: parchment = base
       surface, parchment-dark = raised surface, surface-2 = bars/headers,
       wood = border, heading/text/muted = the three text levels. */
    --parchment: #151a21;
    --parchment-dark: #1c222b;
    --surface-2: #10141a;
    --wood: #39424f;
    --wood-dark: #10141a;
    --wood-light: #39424f;
    --heading: #e9edf3;
    --text: #dfe4ea;
    --muted: #9aa4b2;
    --on-accent: #141821;
    --gold: #d9b45c;
    --gold-light: #f0cd7a;
    --gold-dark: #a8862f;
    --green: #5fa34a;
    --red: #d9534f;
    /* UX-073: --red reads 4.0:1 as text on slate and 3.1:1 under light text;
       text-on-dark and filled danger surfaces use these AA-safe steps. */
    --red-text: #ec7f7b;
    --red-fill: #a8332f;

    /* VIS-002: semantic color pass -- gold was overloaded for plain hover/
       selected states (page tabs, resource rows, mode-select buttons,
       combat target marker) with zero mastery/prestige/achievement meaning;
       those states now use --color-active (reusing --green's own value per
       the audit's "Grøn = active/running/obtainable/ready" mapping) so gold
       reads as "special" again. --color-magic and --color-locked are new
       roles the audit calls for that nothing in the codebase served before;
       --color-locked's value matches .skill-tile.locked's own
       already-shipping background so tokenizing it doesn't change how it
       looks (same derive-from-observed approach as VIS-001). */
    --color-active: var(--green);
    --color-magic: #9b6bd9;
    --color-locked: #1e242d;

    /* VIS-001: spacing/typography/radius scale, derived from game.css's own
       already-observed values (grepped, not invented) so tokenizing a
       selector never visibly changes it. Foundation phase of the owner-
       supplied Visual Design System audit (2026-09-26) -- see
       claude/tasks.json VIS-001/002/003 for the follow-up phases. */
    --space-xs: 2px;
    --space-sm: 4px;
    --space-md: 8px;
    --space-lg: 12px;
    --space-xl: 16px;
    --font-size-xs: 12px;
    --font-size-sm: 12px;
    --font-size-md: 13px;
    --font-size-lg: 18px;
    --radius-sm: 4px;
    --radius-md: 6px;
    --radius-lg: 8px;
  }

  * { box-sizing: border-box; }
  /* UX-093: native controls (checkbox, select arrow, scrollbars) follow the dark cabinet. */
  :root { color-scheme: dark; accent-color: var(--color-active); }

  /* VIS-003: VIS-002 retimede alt der havde en regel, men et <select> uden en
     regel arver ingenting -- browserens default er sort på hvidt, og seks af
     dem stod tilbage som hvide kasser på det mørke tema (bl.a. #page-jump og
     #skill-jump, som ER navigationen på mobil). En basisregel her dækker dem
     alle, i stedet for at opremse id'er der skal vedligeholdes hver gang en
     ny <select> tilføjes. De klasser der har brug for anden padding eller
     flex (.inventory-filter-select m.fl.) lægger stadig oven på. */
  /* UX-079: tekst-, søge- og talfelter + textarea får samme mørke basis
     (DESIGN.md Inputs: Deep Well, 1px iron, 6px radius, serif). */
  select,
  input[type="search"],
  input[type="text"],
  input[type="number"],
  input[type="email"],
  input[type="password"],
  textarea {
    font-family: inherit;
    border: 1px solid var(--wood);
    border-radius: 6px;
    background: var(--wood-dark);
    color: var(--heading);
  }
  input[type="search"],
  input[type="text"],
  input[type="number"],
  input[type="email"],
  input[type="password"],
  textarea { padding: 4px 8px; }
  input::placeholder, textarea::placeholder { color: var(--muted); opacity: 1; }
  select:focus-visible,
  input:focus-visible,
  textarea:focus-visible { outline: 2px solid var(--color-active); outline-offset: 1px; }

  /* Den åbne dropdown tegnes af styresystemet og arver ikke altid ovenstående;
     at sætte den eksplicit holder listen læsbar i stedet for lys-på-lys. */
  select option {
    background: var(--wood-dark);
    color: var(--heading);
  }

  /* UX-006: visible to assistive tech, not to the eye. */
  .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  #save-error {
    margin: 12px;
    padding: 12px 16px;
    border: 2px solid var(--red);
    background: var(--parchment);
    color: var(--red-text);
  }

  #recover-original-btn { margin: 0 12px 12px; }

  body {
    margin: 0;
    /* Phase 37/63: extra top padding clears the fixed status bar (see
       .status-bar below) so it never overlaps the title on load. The bar
       is two rows tall (main row + the page-tabs row below it), and the
       page-tabs row can itself wrap to 2 lines on narrow viewports — this
       padding has enough slack for that worst case, which is harmless
       (just a bit of extra whitespace on wider screens, never an overlap). */
    padding: 150px 24px 24px;
    font-family: Georgia, 'Times New Roman', serif;
    background: var(--parchment);
    color: var(--text);
    display: flex;
    justify-content: center;
  }

  .game {
    width: 100%;
    max-width: 640px;
  }

  /* Phase 37 ("A persistent status bar"): gold, HP, and current-activity
     progress used to live only in the scrolling column below — the page
     runs up to ~8 screens tall on mobile, so that information disappeared
     the moment you scrolled down to Talents or Quests. This bar is fixed
     to the very top of the viewport (not just `sticky`, which would still
     be pushed around by body's own padding) so it's always visible.
     Its three fields are pure mirrors of DOM the game already renders
     correctly elsewhere (renderGold(), the combat panel's player-hp-*
     elements, and action-label/action-bar) — see renderStatusBar() — so
     there's no second copy of any game-state calculation to keep in sync.
     UX-026: the header's own #gold-display line was removed as a pure
     duplicate of this bar's #status-gold — renderGold() now writes
     #status-gold directly from state.gold instead of the old header
     element mirroring the other way around. */
  .status-bar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 100;
    background: var(--surface-2);
    border-bottom: 2px solid var(--wood);
    padding: 8px 16px;
    display: flex;
    /* The quick-nav row sits below the main gold/HP/activity row
       (.status-bar-inner) — column stacking (instead of flex's default
       row) is what makes them sit one above the other rather than
       fighting for horizontal space, especially at narrow mobile widths. */
    flex-direction: column;
    align-items: center;
  }

  .status-bar-inner {
    width: 100%;
    max-width: 640px;
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: nowrap;
  }

  .status-gold {
    font-weight: bold;
    font-size: 13px;
    color: var(--gold-light);
    white-space: nowrap;
    flex: 0 0 auto;
  }

  .status-hp {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: 0 0 auto;
  }

  .status-hp.status-hidden {
    display: none;
  }

  .status-hp-label {
    font-size: 12px;
    font-weight: bold;
    color: var(--text);
    white-space: nowrap;
  }

  .status-hp-bar-outer {
    width: 60px;
    height: 8px;
    background: var(--surface-2);
    border: 1px solid var(--wood);
    border-radius: 4px;
    overflow: hidden;
    flex: 0 0 auto;
  }

  .status-hp-bar-inner {
    height: 100%;
    background: linear-gradient(90deg, var(--green), #8cc077);
    width: 0%;
  }

  .status-activity {
    flex: 1 1 auto;
    min-width: 0; /* lets text-overflow: ellipsis actually kick in inside a flex item */
  }

  .status-activity-label {
    font-size: 12px;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    margin-bottom: 2px;
  }

  .status-activity-label.blocked {
    color: #e88a8a; /* var(--red) is too dark to read on the status bar's own dark background */
    font-weight: bold;
  }

  /* VIS-007 / UX-077: VIS-004's single, frequently-updated delta lives in
     #toast-container (order: 1 puts it on top of the column-reverse stack).
     While faded out it leaves the flow so it never leaves a gap. */
  .status-activity-delta {
    order: 1;
    position: absolute;
    bottom: 0;
    right: 0;
    width: max-content;
    max-width: min(360px, calc(100vw - 32px));
    box-sizing: border-box;
    overflow-wrap: anywhere;
    white-space: normal;
    background: var(--surface-2);
    color: var(--text);
    border: 1px solid var(--gold);
    border-radius: 6px;
    padding: 8px 14px;
    font-size: 13px;
    font-weight: bold;
    text-align: center;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
    pointer-events: none;
    opacity: 0;
    transition: opacity 1.1s ease-in;
  }

  .status-activity-delta.status-activity-delta-visible {
    position: static;
    opacity: 1;
    transition: none;
  }

  @media (prefers-reduced-motion: reduce) {
    /* Audit section 21: no animated transition -- the text simply appears
       and is overwritten/cleared on the next gain, never fades. */
    .status-activity-delta { transition: none; }
  }

  .status-activity-bar-outer {
    height: 6px;
    background: var(--surface-2);
    border: 1px solid var(--wood);
    border-radius: 3px;
    overflow: hidden;
  }

  .status-activity-bar-inner {
    height: 100%;
    background: var(--color-active);
    width: 0%;
  }

  /* Quick-nav: added during the UX audit pass. The page runs 5800+px tall
     at desktop width across 9+ major panels with no in-page navigation —
     this is a pure jump-to-section aid, it never reads or writes game
     state, so it's safe to add without touching any gameplay logic. */
  .status-nav-row {
    width: 100%;
    max-width: 640px;
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 6px;
    padding-top: 6px;
    border-top: 1px solid var(--wood);
  }

  /* Phase 63 Part 2: replaces the old jump-to-section <select> — now that
     every major panel is reachable as its own tab, a scroll-to-it dropdown
     is redundant (see DESIGN_BACKLOG.md's "Does this replace the quick-nav
     dropdown" decision). Lives in the same sticky row the select used to
     occupy, so it's reachable without scrolling from anywhere in the page. */
  .page-tabs {
    width: 100%;
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    justify-content: center;
  }

  .page-tab-btn {
    flex: 0 1 auto;
    padding: 4px 10px;
    border: 1px solid var(--wood);
    border-radius: 4px;
    background: var(--parchment);
    color: var(--text);
    cursor: pointer;
    font-family: inherit;
    font-size: 12px;
  }

  .page-tab-btn:hover {
    background: var(--color-active);
    color: var(--on-accent);
  }

  .page-tab-btn.active {
    background: var(--color-active);
    border-color: var(--heading);
    color: var(--on-accent);
    font-weight: bold;
  }

  /* UX-006: visible keyboard focus across the app shell (tab row, desktop
     sidebar, combat panel). Native buttons/summaries are already reachable;
     what was missing was a ring you can see on the dark theme. */
  /* UX-022: the two nav selects are the ONLY way to move around below 540px,
     and they were the one thing the first slice's list of classes missed --
     they kept the UA default ring, a 1px near-black outline that is invisible
     on the dark status bar. They are also the first controls in tab order on
     a phone, so this was the first thing a keyboard user could not see. */
  .page-tab-btn:focus-visible,
  .sidebar-category-heading:focus-visible,
  .sidebar-skill-btn:focus-visible,
  .status-nav-row select:focus-visible,
  .resource-btn:focus-visible {
    outline: 3px solid var(--heading);
    outline-offset: 2px;
  }

  /* Phase 40 ("a feedback/juice pass"): a small toast stack for level-ups
     and quest completions — see showToast() in the script. Stacks bottom-up
     above the queue/combat panels rather than the fixed status bar, so it
     never competes with that bar's own always-visible info. */
  /* UX-072: anchored bottom-right (max 3, see showToast) so toasts no longer
     cover mid-screen Claim buttons and cards. */
  #toast-container {
    position: fixed;
    bottom: 16px;
    right: 16px;
    z-index: 200;
    display: flex;
    flex-direction: column-reverse;
    gap: 6px;
    align-items: flex-end;
    pointer-events: none;
    max-width: min(360px, calc(100vw - 32px));
  }

  .toast {
    pointer-events: auto; /* UX-077: only the toast itself, never the container's empty box */
    background: var(--surface-2);
    color: var(--text);
    border: 1px solid var(--gold);
    border-radius: 6px;
    padding: 8px 14px;
    font-size: 13px;
    font-weight: bold;
    text-align: center;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 0.3s ease, transform 0.3s ease;
  }

  .toast.toast-visible {
    opacity: 1;
    transform: translateY(0);
  }

  /* UX-087: toasts never cover navigation. Desktop (>=1024px): bottom of
     the content column, right of the 280px sidebar. Phones: one toast at the
     bottom of the viewport (safe-area aware), clear of the top status bar
     and its page/skill selects; tap to dismiss (showToast). */
  @media (min-width: 1024px) {
    #toast-container { left: 304px; right: auto; align-items: flex-start; }
    .status-activity-delta { right: auto; left: 0; }
  }
  @media (max-width: 539px) {
    #toast-container { bottom: calc(12px + env(safe-area-inset-bottom, 0px)); left: 8px; right: 8px; max-width: none; align-items: stretch; }
    #toast-container .toast:not(:last-child) { display: none; }
    #toast-container .toast, .status-activity-delta {
      padding: 4px 10px; font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .status-activity-delta { left: 0; right: 0; max-width: none; width: auto; }
  }

  /* UX-026: compact header. #gold-display (a pure duplicate of the
     always-visible #status-gold above) was removed entirely, and this
     block's own weight is cut — the title stays (it's the only place the
     game's name appears once the header is this small) but no longer
     needs to compete with the panels below it for vertical space. */
  h1 {
    text-align: center;
    color: var(--heading);
    margin: 0 0 2px;
    font-size: 18px;
  }

  .subtitle {
    text-align: center;
    color: var(--muted);
    margin-bottom: 8px;
    font-size: 12px;
    font-style: italic;
  }

  /* UX-026: the element this class was named for (#gold-display) is gone —
     only #potion-display still uses it, for the same centred/bold styling. */
  .gold-display {
    text-align: center;
    font-size: 13px;
    font-weight: bold;
    color: var(--heading);
    margin-bottom: 16px;
  }

  .panel {
    background: var(--parchment-dark);
    border: 2px solid var(--wood);
    border-radius: 8px;
    padding: 16px;
    margin-bottom: 16px;
  }

  /* UX-060: a lighter, lower-padding sub-card for grouping Township's many
     subsystems -- same visual language as .panel, clearly a sub-section
     rather than a sibling panel. */
  .town-subsection {
    background: var(--parchment);
    border: 1px solid var(--wood);
    border-radius: var(--radius-md);
    padding: 10px 12px;
    margin-bottom: 12px;
  }

  .town-subsection h3 {
    margin-top: 0;
  }

  /* Bug fix found while working on Phase 53: this used to be scoped as
     `.panel.panel-hidden` (both classes on the SAME element), which only
     ever matched actual `.panel` divs. But `panel-hidden` is used
     everywhere as a generic "hide this" utility class on plenty of
     non-panel elements too (the Prestige button, the Slayer task button,
     the potion status readout, ...) — those elements had `panel-hidden`
     toggled onto them correctly by the JS, but the CSS never actually
     hid them, so e.g. a "Prestige" button sat visibly on every skill
     panel even at level 1, long before it was actually eligible. The
     utility stays unscoped and uses !important so component selectors
     such as button.action cannot override the hidden state. */
  .panel-hidden {
    display: none !important;
  }

  .panel h2 {
    margin: 0 0 var(--space-lg) 0;
    font-size: var(--font-size-lg);
    color: var(--heading);
    border-bottom: 1px solid var(--wood);
    padding-bottom: 6px;
  }

  .panel h3 {
    margin: var(--space-lg) 0 6px;
    font-size: var(--font-size-md);
    color: var(--heading);
  }

  .skill-tabs { display: grid; gap: 10px; }
  .skill-group { --c: #7fae68; min-width: 0; }
  .skill-group[data-category="production"] { --c: #d08a5e; }
  .skill-group[data-category="elite"] { --c: #9a8fd6; }
  .skill-group[data-category="township"] { --c: #c79a4a; }
  .skill-group[data-category="support"] { --c: #92a7bb; }
  .skill-group[data-category="combat"] { --c: #d4796a; }
  .panel .skill-tab-group-heading { margin: 0; padding: 6px 9px; border-left: 3px solid var(--c); font-size: 14px; font-weight: bold; color: var(--heading); cursor: pointer; }
  .skill-group[open] > .skill-tab-group-heading { margin-bottom: 9px; }
  .skill-tab-group-heading:focus-visible { outline: 3px solid var(--heading); outline-offset: 2px; }
  .skill-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(116px, 1fr)); gap: 8px; }
  .skill-tile { position: relative; display: flex; flex-direction: column; align-items: center; gap: 4px; min-width: 0; padding: 12px 7px 9px; border: 1px solid #39424f; border-radius: 5px; background: var(--parchment); color: var(--text); font: inherit; cursor: pointer; }
  .skill-tile:hover { border-color: var(--c); background: #222a35; }
  .skill-tile:focus-visible { outline: 3px solid var(--heading); outline-offset: 3px; z-index: 1; }
  .skill-tile.active { border: 2px solid var(--heading); padding: 11px 6px 8px; background: #2e2717; }
  .skill-tile.running { box-shadow: inset 0 3px var(--c); }
  .skill-tile.running .skill-tile-note { color: var(--c); font-weight: bold; }
  .skill-tile.running .skill-tile-note::before { content: '● '; }
  .skill-tile-icon { width: 39px; height: 39px; font-size: 30px; line-height: 39px; }
  .skill-tile-icon svg { width: 100%; height: 100%; }
  /* VIS-001: inline icon used wherever an enemy/skill id has a symbol in the shared sprite */
  .inline-icon { width: 1.1em; height: 1.1em; vertical-align: -0.2em; }
  .skill-tile-name { font-size: 13px; font-weight: bold; overflow-wrap: anywhere; }
  .skill-tile-level { font-size: 11px; color: #9aa4b2; }
  .skill-tile-xp { display: block; width: 100%; height: 4px; margin-top: 3px; background: #2a323d; border-radius: 3px; overflow: hidden; }
  .skill-tile-xp > span { display: block; height: 100%; background: var(--c); }
  .skill-tile-note { font-size: 11px; line-height: 1.4; color: #9aa4b2; }
  .skill-tile.sub-skill { background: #1e242d; }
  .skill-tile.sub-skill .skill-tile-icon { width: 30px; height: 30px; margin: 4px 0 5px; }
  .skill-tile.locked { cursor: default; background: var(--color-locked); }
  .skill-tile.locked .skill-tile-icon { filter: grayscale(1); opacity: .65; }
  .skill-tile.locked .skill-tile-level::before { content: '◇ '; }
  .skill-tile.locked .skill-tile-xp { visibility: hidden; }
  .skill-grid-hint { font-size: 12px; line-height: 1.5; color: #9aa4b2; margin: -4px 0 14px; }
  .level-up-flash { background-color: var(--gold-light) !important; color: var(--on-accent) !important; }
  @media (max-width: 480px) {
    .skill-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
    .skill-tile { padding-left: 4px; padding-right: 4px; }
    .skill-tile-name { font-size: 11px; }
    .skill-tile-note { font-size: 11px; }
  }


  .skill-header {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: 6px;
  }

  .skill-level {
    font-size: 20px;
    font-weight: bold;
    color: var(--heading);
  }

  .xp-info {
    font-size: 12px;
    color: var(--muted);
  }

  .bar-outer {
    background: #2a323d;
    border: 1px solid var(--wood);
    border-radius: 6px;
    height: 16px;
    overflow: hidden;
    margin-bottom: 4px;
  }

  .bar-inner {
    height: 100%;
    background: linear-gradient(90deg, var(--gold), var(--gold-light));
    width: 0%;
    transition: width 0.15s linear;
  }

  .bar-inner.enemy-hp {
    background: linear-gradient(90deg, var(--red), #e08585);
  }

  .bar-inner.player-hp {
    background: linear-gradient(90deg, var(--green), #8cc077);
  }

  .action-bar-outer {
    background: #2a323d;
    border: 1px solid var(--wood);
    border-radius: 6px;
    height: 10px;
    overflow: hidden;
    margin-top: 10px;
  }

  .action-bar-inner {
    height: 100%;
    background: var(--green);
    width: 0%;
  }

  .action-label {
    font-size: 12px;
    color: var(--muted);
    margin-top: 4px;
    text-align: center;
  }

  .action-label.blocked,
  .footer-note.blocked {
    color: var(--red-text);
    font-weight: bold;
  }

  /* IDLE-001 (DEC-089) */
  .skip-bank-label {
    display: block;
    font-size: 11px;
    color: var(--muted);
    text-align: center;
    margin-top: 4px;
  }

  /* UX-024: visual hierarchy inside #panel-activity, per the UX/UI-audit's
     "Skill-dashboard og aktivitet" section. Every element these rules touch
     keeps its own existing id/class and is still written to by the exact
     same renderX() functions as before this task — only the surrounding
     wrapper's presentation changes. Layer 1 (current action) is the
     biggest/clearest; layer 2 (level/xp) is next; layer 3
     (mastery/prestige/tool/etc.) is deliberately smaller and quieter;
     layer 4 (flavor text) is dimmed. */
  .activity-layer-current {
    background: rgba(217, 180, 92, 0.08);
    border: 1px solid var(--wood);
    border-radius: 8px;
    padding: 12px;
    margin-bottom: 14px;
  }

  /* UX-069: Combat's idle state lives in Encounter; drop the empty frame. */
  .activity-layer-current:not(:has(> :not(.panel-hidden))) { display: none; }

  .activity-layer-current .action-bar-outer {
    height: 20px;
    margin-top: 0;
  }

  .activity-layer-current .action-label {
    font-size: 15px;
    font-weight: bold;
    color: var(--heading);
    margin-top: 8px;
  }

  .activity-layer-current .action-label.blocked {
    color: var(--red-text);
  }

  .activity-layer-progress {
    margin-bottom: 12px;
  }

  .activity-layer-disclosure {
    border-top: 1px solid var(--wood);
    margin-top: 10px;
  }

  .activity-layer-disclosure > summary {
    cursor: pointer;
    color: var(--heading);
    font-size: 13px;
    font-weight: bold;
    padding: 8px 0 4px;
  }

  .activity-layer-secondary {
    padding-top: 4px;
    font-size: 13px;
  }

  .activity-layer-secondary .skill-level {
    font-size: 14px;
  }

  .activity-layer-secondary .xp-info {
    font-size: 11px;
  }

  .activity-layer-secondary .bar-outer {
    height: 10px;
  }

  #panel-activity .lore-flavor {
    font-size: 11px;
    color: var(--muted);
    opacity: 0.75;
    margin-top: 14px;
    margin-bottom: 0;
    padding-top: 8px;
    border-top: 1px solid var(--wood);
  }

  .resource-list {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
  }

  #regions-overview {
    margin-top: 18px;
    padding-top: 12px;
    border-top: 1px solid var(--wood);
  }

  #regions-overview h3,
  #regions-bonus-totals h4 {
    margin: 0 0 6px;
  }

  .region-bonus-totals {
    margin: 6px 0 12px;
    padding-left: 22px;
  }

  .region-tree,
  .region-tree-children {
    list-style: none;
    margin: 0;
    padding: 0;
  }

  .region-tree-item {
    min-width: 0;
  }

  .region-tree > .region-tree-item + .region-tree-item,
  .region-tree-children > .region-tree-item + .region-tree-item {
    margin-top: 8px;
  }

  .region-tree-children {
    margin: 8px 0 0 12px;
    padding-left: 12px;
    border-left: 2px solid var(--wood);
  }

  .region-tree-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 10px;
    min-width: 0;
    padding: 8px 10px;
    border: 1px solid var(--wood);
    border-radius: var(--radius-md);
    background: var(--parchment);
  }

  .region-tree-details {
    display: grid;
    gap: 2px;
    min-width: 0;
  }

  .region-tree-name {
    overflow-wrap: anywhere;
  }

  .region-tree-status,
  .region-tree-bonus {
    overflow-wrap: anywhere;
  }

  .region-view-button {
    flex: 0 0 auto;
    min-width: 56px;
  }

  .region-unknown-branches {
    margin: 5px 0 0 10px;
    overflow-wrap: anywhere;
  }

  .resource-btn.region-view-highlight {
    outline: 3px solid var(--heading);
    outline-offset: 2px;
    animation: region-view-pulse 0.6s ease-in-out 2 alternate;
  }

  @keyframes region-view-pulse {
    from { box-shadow: 0 0 0 0 transparent; }
    to { box-shadow: 0 0 0 5px var(--color-active); }
  }

  @media (max-width: 480px) {
    .region-tree-row {
      gap: 6px;
      padding: 8px;
    }

    .region-tree-children {
      margin-left: 6px;
      padding-left: 8px;
    }
  }

  .resource-section-heading {
    flex: 0 0 100%;
    margin: 12px 0 0;
    color: var(--heading);
  }

  .resource-card {
    box-sizing: border-box;
    display: flex;
    flex: 1 1 calc(33% - var(--space-md));
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
    min-width: 160px;
    max-width: 100%;
    padding: 10px;
    border: 2px solid var(--wood);
    border-radius: var(--radius-md);
    background: var(--parchment);
    color: var(--text);
    overflow-wrap: anywhere;
  }

  /* UX-073 (DESIGN.md): selection is a green edge on a faint green tint,
     never a full green fill -- body text stays light and readable. */
  .resource-card:not(.locked):hover {
    background: var(--parchment-dark);
    border-color: var(--color-active);
    color: var(--text);
  }

  .resource-card.active {
    background: color-mix(in srgb, var(--color-active) 14%, var(--parchment));
    border-color: var(--color-active);
    color: var(--heading);
  }

  .resource-card > .resource-btn {
    flex: 0 0 100%;
    width: 100%;
    min-width: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    color: inherit;
    white-space: normal;
  }

  .resource-card > .resource-btn:hover:not(:disabled),
  .resource-card > .resource-btn.active {
    border-color: transparent;
    background: transparent;
    color: inherit;
  }

  .resource-card > .resource-btn.active {
    font-weight: bold;
  }

  .resource-card > .resource-meta,
  .resource-card > .resource-usage,
  .resource-card > .resource-stats,
  .resource-card > .resource-zone-bonus,
  .resource-card > .resource-artifice-effect,
  .resource-card > .resource-inputs,
  .resource-card > .resource-potion-preview,
  .resource-card > .tooltip-anchor,
  .resource-card > .resource-quantity-note {
    flex: 0 0 100%;
    min-width: 0;
  }

  .resource-card > [data-quantity-control].hidden {
    display: none;
  }

  .resource-btn {
    flex: 1 1 calc(33% - var(--space-md));
    min-width: 160px;
    padding: 10px;
    border: 2px solid var(--wood);
    border-radius: var(--radius-md);
    background: var(--parchment);
    cursor: pointer;
    font-family: inherit;
    text-align: left;
    font-size: var(--font-size-md);
    color: var(--text);
  }

  .resource-btn:hover:not(:disabled) {
    background: var(--parchment-dark);
    border-color: var(--color-active);
    color: var(--text);
  }

  .resource-btn.active {
    background: color-mix(in srgb, var(--color-active) 14%, var(--parchment));
    border-color: var(--color-active);
    color: var(--heading);
    font-weight: bold;
  }

  .resource-btn:disabled {
    opacity: 0.45;
    cursor: not-allowed;
  }

  .equipment-comparison,
  .equipment-equipped-label {
    display: block;
    width: 100%;
    margin-top: 4px;
    font-size: 11px;
    font-weight: normal;
    line-height: 1.4;
    overflow-wrap: anywhere;
  }

  .equipment-comparison-against,
  .equipment-comparison-delta.neutral {
    color: var(--muted);
  }

  .equipment-comparison-delta.positive {
    color: var(--green);
  }

  .equipment-comparison-delta.negative {
    color: var(--red-text);
  }

  .equipment-equipped-label {
    color: var(--color-active); /* UX-073: active rows are a tint now, not a green fill */
  }

  /* UX-065: left column, free figure column (2 tracks), right column; combat row below. */
  .equipment-slot-grid {
    display: grid;
    position: relative;
    z-index: 1;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    grid-template-areas:
      "head . . amulet"
      "shoulder . . gloves"
      "cloak . . ring"
      "armor . . trinket"
      "bracers . . legs"
      "belt . . boots"
      "melee offhand ranged magic";
    gap: 8px;
    max-width: 920px; /* UX-081: use the panel width so slot hints aren't cut */
    margin: 0 auto;
  }

  .equipment-summary-row.off-hand-inactive {
    opacity: 0.5;
  }

  .equipment-paper-doll-layout {
    position: relative;
    isolation: isolate;
    width: 100%;
    max-width: 920px;
    margin: 0 0 var(--space-xl);
  }

  .equipment-paper-doll-figure {
    position: absolute;
    z-index: 0;
    left: 50%;
    width: 280px;
    height: 400px;
    object-fit: contain;
    object-position: center top;
    transform: translateX(-50%);
    top: 8px;
    opacity: 0.22;
    pointer-events: none;
  }

  .equipment-summary-row {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 2px;
    min-width: 0;
    width: 100%;
    height: 76px; /* UX-093: room for a two-line hint */
    padding: var(--space-sm) var(--space-md);
    text-align: left;
    overflow: hidden;
    background: var(--panel);
    position: relative;
    z-index: 1;
    white-space: normal;
    line-height: 1.3;
    cursor: pointer;
  }

  .equipment-summary-row.active {
    background: var(--panel);
    color: inherit;
    border-color: var(--green);
    box-shadow: inset 3px 0 0 var(--green);
  }

  .equipment-slot-label {
    font-size: 0.75em;
    opacity: 0.7;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
  }

  .equipment-slot-item {
    min-width: 0;
    max-width: 100%;
    overflow-wrap: normal;
  }

  .equipment-slot-item.empty {
    opacity: 0.55;
  }

  .equipment-slot-placeholder {
    filter: grayscale(1);
  }

  /* UX-074: an empty slot's next step, and the totals line under the doll. */
  .equipment-slot-hint {
    font-size: 11px;
    color: var(--muted); /* UX-081: craft hints stay neutral (Gold Is Earned) */
    overflow: hidden;
    max-width: 100%;
    /* UX-093: wrap to two lines instead of cutting the recipe name */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
  }
  .equipment-slot-hint.best-owned { color: var(--gold-light); }
  /* UX-081: Equip/Recipe sits in the tile's grid area, bottom-right. */
  button.action.equipment-slot-action {
    position: relative;
    z-index: 2;
    align-self: start;
    justify-self: end;
    margin: 16px 6px 0 0;
    padding: 1px 8px;
    font-size: 11px;
    line-height: 1.4;
  }

  @media (max-width: 600px) {
    /* one shared tile height (UX-057) with room for a two-line hint */
    .equipment-summary-row { height: 84px; }
    .equipment-summary-row.active { box-shadow: none; } /* UX-081: no side-tab on the phone tile */
  }

  .equipment-stat-overview {
    margin: 8px 0 10px;
    font-size: 13px;
    color: var(--heading);
    font-variant-numeric: tabular-nums;
  }

  @media (max-width: 600px) {
    .equipment-paper-doll-figure {
      display: none;
    }

    .equipment-slot-grid {
      grid-template-columns: repeat(2, minmax(0, 1fr));
      grid-template-areas:
        "head amulet"
        "shoulder gloves"
        "cloak ring"
        "armor trinket"
        "bracers legs"
        "belt boots"
        "melee offhand"
        "ranged magic";
    }
  }

  .equipment-summary-row:focus-visible {
    outline: 3px solid var(--heading);
    outline-offset: 2px;
  }

  /* UX-064: Equipment cards (slots, profiles, sets) share VIS-001 spacing. */
  .combat-profiles-disclosure {
    margin: 0 0 var(--space-lg);
    padding: var(--space-lg);
    border: 1px solid var(--wood);
    border-radius: var(--radius-md);
    min-width: 0;
  }

  .combat-profiles-disclosure > summary {
    cursor: pointer;
    font-weight: bold;
    color: var(--heading);
    overflow-wrap: anywhere;
  }

  .combat-profiles-disclosure > summary:focus-visible {
    outline: 3px solid var(--heading);
    outline-offset: 3px;
  }

  .equipment-profile-card {
    border: 1px solid var(--wood);
    border-radius: var(--radius-md);
    padding: var(--space-lg);
    margin: var(--space-md) 0;
  }

  .equipment-profile-card input {
    display: block;
    margin: 6px 0;
    max-width: 100%;
  }

  .equipment-profile-card button {
    margin: 4px 6px 0 0;
  }

  /* Phase 48c: bosses need to read as visually distinct from the regular
     enemy ladder at a glance — a colored left border, same visual language
     as .skill-tab-btn.running's left-border marker from the tabbed-UI work. */
  .resource-btn.boss-btn {
    border-left: 4px solid var(--red);
  }

  .resource-name {
    display: block;
    font-weight: bold;
    overflow-wrap: anywhere;
  }

  /* UX-025: the cost/reward/time line directly under a resource button's
     name is the number a player actually decides on -- "important stat"
     tier (13-14px) from the 2026-09-25 typography audit, not secondary
     chrome. */
  .resource-meta {
    display: block;
    font-size: 13px;
    color: var(--muted);
  }

  .resource-usage {
    display: block;
    margin-top: 2px;
    color: var(--muted);
    font-size: 11px;
    line-height: 1.35;
    overflow-wrap: anywhere;
  }

  .resource-artifice-effect {
    display: block;
    font-size: 12px;
    line-height: 1.4;
    color: var(--heading);
    overflow-wrap: anywhere;
  }

  /* VIS-006: the game's first real, reusable tooltip component (attachTooltip()
     in js/render.js) -- replaces the browser's own native `title` tooltip
     (still kept as a redundant fallback, never removed) on two sites: the
     mastery badge, and a locked resource row's lock-reason text. Design per
     the visual-design-system audit section 7 (hover/tooltips) and section 21
     (accessibility -- tooltip info must be reachable without precise hover).
     `.tooltip-anchor` is a thin positioning wrapper JS inserts around the
     trigger element; `.tooltip-panel` is that trigger's sibling, never its
     child, so a caller that keeps re-assigning the trigger's own textContent
     every redraw (both call sites do) never wipes the panel back out. */
  .tooltip-anchor {
    position: relative;
  }

  .tooltip-trigger {
    cursor: help;
  }

  .tooltip-trigger:focus-visible {
    outline: 3px solid var(--heading);
    outline-offset: 2px;
  }

  .tooltip-panel {
    /* `display: none` (not opacity/visibility): a hidden-but-still-laid-out
       panel is an absolutely positioned box that can extend past the
       viewport edge near a right-aligned trigger, and unlike opacity/
       visibility, `display: none` fully removes it from layout, so it can
       never widen document.documentElement.scrollWidth while inactive
       (regression caught by tests/e2e/queue-ux.e2e.test.js's own unrelated
       "no horizontal scrollbar" check). It also can't be transitioned,
       which is exactly right here: audit section 21 calls for an instant
       show/hide, never an animated entrance -- there is nothing left for
       prefers-reduced-motion to need to disable. */
    display: none;
    position: absolute;
    left: 0;
    bottom: 100%;
    margin-bottom: var(--space-xs);
    z-index: 20;
    min-width: 160px;
    max-width: 260px;
    padding: var(--space-sm) var(--space-md);
    background: var(--surface-2);
    border: 1px solid var(--parchment-dark);
    border-radius: var(--radius-sm);
    color: var(--text);
    font-size: var(--font-size-xs);
    font-weight: normal;
    line-height: 1.4;
    pointer-events: none;
  }

  .tooltip-anchor:hover .tooltip-panel,
  .tooltip-trigger:focus-visible + .tooltip-panel {
    display: block;
  }

  .resource-inputs {
    display: block;
    font-size: 11px;
    color: var(--heading);
    margin-top: 2px;
  }

  .resource-inputs.missing {
    color: var(--red-text);
  }

  .resource-potion-preview > span {
    display: block;
    line-height: 1.4;
    overflow-wrap: anywhere;
  }

  .resource-potion-preview [data-potion-part="change"] {
    color: var(--muted);
  }

  /* UX-016 / DEC-045 obs 5: what the crafted item gives (weapon power, armor
     mitigation), styled like .resource-inputs but in gold so "what you get"
     reads apart from "what you need" right below it. */
  .resource-stats {
    display: block;
    font-size: 11px;
    color: var(--gold);
    margin-top: 2px;
  }

  /* CG-028a: a discovered sea zone's permanent Fishing yield-chance
     contribution, styled like .resource-stats (read-only, no control). */
  .resource-zone-bonus {
    display: block;
    font-size: 11px;
    color: var(--gold);
    margin-top: 2px;
  }

  .recipe-qty-toggle-btn {
    font-family: inherit;
    font-size: 11px;
    padding: 2px 6px;
    border: 1px solid var(--wood);
    border-radius: 4px;
    background: var(--parchment);
    color: var(--heading);
    cursor: pointer;
    flex: 0 0 auto;
  }

  .recipe-qty-toggle-btn:hover,
  .recipe-qty-toggle-btn.active {
    background: var(--wood);
    color: var(--text);
  }

  .resource-quantity-label {
    font-size: 11px;
    color: var(--heading);
  }

  .resource-quantity-input {
    width: 60px;
    padding: 2px 4px;
    font-size: 12px;
    font-family: inherit;
    border: 1px solid var(--wood);
    border-radius: 4px;
  }

  .resource-quantity-note {
    flex: 0 0 100%;
    font-size: 11px;
    color: var(--heading);
  }

  /* RR-001 (IDEA-0028): Rune Reserves quick-target stock controls */
  .rune-reserve-label {
    font-size: 11px;
    color: var(--heading);
    margin-left: 4px;
  }

  .rune-target-btn {
    padding: 2px 6px;
    font-size: 11px;
    border-radius: 3px;
  }

  /* Phase 44 (Per-item mastery): a small badge on each resource row —
     reuses the existing row rather than a new UI surface, per the
     design doc's own recommended option. --wood-dark, not --gold: the
     active resource card uses the gold accent surface, so gold-on-gold text was invisible
     there — found via a real Playwright render, not just reading the CSS. */
  .mastery-badge {
    display: block;
    font-size: 11px;
    font-weight: bold;
    color: var(--heading);
    margin-left: 6px;
  }

  .hp-block {
    margin-bottom: 10px;
  }

  /* UX-080 */
  .combat-low-hp-warning {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 10px;
    margin: 4px 0 0;
    font-size: 13px;
    font-weight: bold;
    color: #e88a8a; /* readable Ember Red on slate, as .status-activity-label.blocked */
  }
  .combat-low-hp-stop[hidden] { display: none; }
  .active-skill-style { font-weight: normal; color: var(--muted); font-size: 15px; }
  /* On a phone the skills grid pushed the fight below the fold; #skill-jump
     still switches skills, so the grid steps aside while Combat is viewed. */
  @media (max-width: 539px) {
    body.viewing-combat #panel-skills { display: none; }
  }

  .status-badge-list {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-top: 4px;
  }

  .status-badge {
    display: inline-block;
    font-size: 11px;
    padding: 2px 6px;
    border-radius: 4px;
    background: var(--parchment);
    border: 1px solid var(--wood-light);
    color: var(--heading);
    font-weight: bold;
  }

  .status-badge-enrage {
    background: #3a1a1c;
    border-color: #ff6b6b;
    color: #f28b82;
  }

  .status-badge-barrier {
    background: #17263c;
    border-color: #8ab4f8;
    color: #8ab4f8;
  }

  .status-badge-resonance {
    background: #241a3a;
    border-color: #9061f9;
    color: #b9a4f5;
  }

  /* R-02: enemy-instance affixes (Hulking, Swift, Regenerating, Thieving). */
  .status-badge-affix {
    background: #2a2410;
    border-color: #d4a017;
    color: #e8c15a;
  }

  .enemy-affix-toggle {
    cursor: pointer;
    font: inherit;
    font-size: 11px;
    font-weight: bold;
    line-height: 1.3;
    text-align: left;
  }

  .enemy-affix-details {
    box-sizing: border-box;
    flex: 0 0 100%;
    min-width: 0;
    padding: 4px 6px;
    color: var(--heading);
    font-size: 12px;
    font-weight: normal;
    line-height: 1.4;
    overflow-wrap: anywhere;
  }

  .hp-label {
    font-size: 13px;
    font-weight: bold;
    color: var(--heading);
    margin-bottom: 4px;
  }

  .combat-stats {
    font-size: 12px;
    color: var(--muted);
    margin-bottom: 12px;
  }

  /* UX-069: fight status + Start/Stop first; target picker folds to the chosen enemy. */
  .combat-status-row,
  .combat-target-heading {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md);
    margin-bottom: var(--space-lg);
  }

  .combat-target-heading h3 { margin: 0; }

  .combat-status-text {
    font-weight: bold;
    color: var(--muted);
  }

  .combat-status-text.is-fighting { color: var(--color-active); }

  #enemy-list > [hidden],
  #enemy-change-target-btn[hidden] { display: none; }

  #enemy-list .enemy-list-heading,
  #enemy-list .enemy-locked-toggle { flex: 1 1 100%; }

  #enemy-list .enemy-locked-toggle { text-align: left; }

  #enemy-list .resource-btn:hover:not(:disabled) {
    background: var(--parchment-dark);
    color: var(--text);
    border-color: var(--color-active);
  }

  #enemy-list .resource-btn.active {
    background: color-mix(in srgb, var(--color-active) 14%, var(--parchment));
    border-color: var(--color-active);
    color: var(--heading);
  }

  #enemy-list .resource-btn.enemy-locked:disabled {
    opacity: 1;
    background: var(--color-locked);
    color: var(--muted);
  }

  /* UX-018: all-styles overview chips, same visual family as the
     status-badge-list above (small pill, parchment background). The
     active style's chip gets a stronger border/background so it reads as
     "this is what's training right now" without a legend. */
  .combat-styles-overview {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 12px;
  }

  .rift-records {
    margin-top: 12px;
    padding-top: 10px;
    border-top: 1px solid var(--wood-light);
    color: var(--text);
    font-size: 13px;
  }

  .rift-history-list {
    display: grid;
    gap: 4px;
    margin: 6px 0 0;
    padding-left: 20px;
  }

  #rift-history-more {
    margin-top: 6px;
  }

  #rift-history-more summary {
    cursor: pointer;
    color: var(--heading);
  }

  .combat-style-chip {
    display: inline-block;
    font-size: 12px;
    padding: 3px 8px;
    border-radius: 4px;
    background: var(--parchment);
    border: 1px solid var(--wood-light);
    color: var(--heading);
    font-weight: bold;
  }

  .combat-style-chip.active {
    background: #17263c;
    border-color: #8ab4f8;
    color: #8ab4f8;
  }

  #combat-panel,
  .combat-subview {
    min-width: 0;
  }

  #combat-panel {
    scroll-margin-top: 64px;
  }

  .combat-view-tabs {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr));
    gap: 6px;
    margin: 8px 0 14px;
  }

  .combat-view-tab {
    min-width: 0;
    white-space: normal;
    overflow-wrap: anywhere;
  }

  .combat-view-tab[aria-selected="true"] {
    border-color: var(--heading);
    color: var(--heading);
    box-shadow: inset 0 0 0 1px currentColor;
  }

  .combat-subview[hidden] {
    display: none !important;
  }

  .combat-setup-shortcut {
    margin: 10px 0 14px;
    padding: 10px 12px;
    border: 1px solid var(--wood-light);
    border-radius: 6px;
    background: var(--parchment);
    color: var(--text);
  }

  .combat-setup-shortcut h3 {
    margin: 0 0 5px;
  }

  .combat-setup-shortcut p {
    margin: 0 0 8px;
  }

  .combat-policy-controls {
    margin: 10px 0;
  }

  .combat-policy-controls h3 {
    margin: 0 0 4px;
  }

  .combat-priority-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    min-width: 0;
    margin-bottom: 8px;
  }

  .combat-priority-row select {
    max-width: 100%;
  }

  #ability-status-list {
    box-sizing: border-box;
    margin: 4px 0 0;
    padding-left: 18px;
    width: 100%;
    font-size: 12px;
  }

  #ability-status-list li {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-bottom: 5px;
  }

  #ability-status-list .ability-status-text {
    flex: 1 1 180px;
    min-width: 0;
  }

  #ability-status-list .ability-condition-select {
    flex: 0 1 auto;
    min-width: min(100%, 190px);
  }

  .combat-log-disclosure {
    margin-top: 12px;
  }

  .combat-log-disclosure summary {
    cursor: pointer;
    color: var(--heading);
    margin-bottom: 6px;
  }

  .combat-preparation {
    margin: 0 0 14px;
    padding: 10px 12px;
    border: 1px solid var(--wood-light);
    border-radius: 6px;
    background: var(--parchment);
    color: var(--text);
  }

  .combat-preparation h3 {
    margin: 0 0 6px;
  }

  .combat-preparation-details {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
    gap: 4px 14px;
  }

  .combat-preparation-line {
    margin: 0;
    font-size: 12px;
    overflow-wrap: anywhere;
  }

  .combat-preparation-line strong {
    color: var(--heading);
  }

  .combat-preparation-warning {
    color: var(--danger, #8b1f1f);
  }

  .combat-preparation-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
  }

  .weapon-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-md);
  }

  /* UX-038: native disclosures make each collection card keyboard-accessible,
     while the summary keeps its progress and next bonus visible when closed. */
  #equipment-sets-list {
    flex-direction: column;
    align-items: stretch;
  }

  .equipment-set-card {
    flex: 1 1 100%;
    min-width: 0;
    border: 1px solid var(--wood);
    border-radius: 6px;
    background: var(--parchment);
    color: var(--text);
    overflow: hidden;
  }

  .equipment-set-summary {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 4px 10px;
    padding: 9px 10px;
    cursor: pointer;
    list-style: revert;
    overflow-wrap: anywhere;
  }

  .equipment-set-summary:focus-visible {
    outline: 2px solid var(--color-active);
    outline-offset: -3px;
  }

  .equipment-set-card[open] .equipment-set-summary {
    border-bottom: 1px solid var(--wood);
  }

  .equipment-set-name {
    color: var(--heading);
    font-weight: bold;
  }

  .equipment-set-progress {
    color: var(--muted);
    text-align: right;
  }

  .equipment-set-bonus-summary,
  .equipment-set-next {
    grid-column: 1 / -1;
    min-width: 0;
    overflow-wrap: anywhere;
  }

  .equipment-set-bonus-summary {
    font-weight: 600;
  }

  .equipment-set-next {
    color: var(--muted);
    font-size: 12px;
  }

  .equipment-set-piece-list {
    display: grid;
    gap: 4px;
    margin: 0;
    padding: 8px 10px;
    list-style: none;
  }

  .equipment-set-piece {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 8px;
    align-items: start;
    padding: 5px 0;
    border-bottom: 1px solid var(--parchment-dark);
  }

  .equipment-set-piece:last-child {
    border-bottom: 0;
  }

  .equipment-set-piece-name,
  .equipment-set-piece-ownership {
    min-width: 0;
    overflow-wrap: anywhere;
  }

  .equipment-set-piece-ownership {
    color: var(--muted);
    text-align: right;
  }

  .combat-log {
    background: var(--parchment);
    border: 1px solid var(--wood);
    border-radius: 6px;
    padding: 8px 10px;
    font-size: 12px;
    max-height: 160px;
    overflow-y: auto;
  }

  .combat-log-line {
    padding: 3px 0;
    border-bottom: 1px solid var(--parchment-dark);
  }

  .combat-log-line:last-child {
    border-bottom: none;
  }

  /* Phase 54 ("World & Lore"): four short flavor lines on existing screens
     (Township, Combat/enemy selector, Talents, Quests) — pure text, reuses
     the existing .footer-note pattern's spacing but is visually distinct
     (italic) so it reads as "world flavor" rather than "how this panel
     works" instructions. */
  .endless-task-row {
    margin-top: 12px;
    padding-top: 10px;
    border-top: 1px solid var(--wood);
  }

  .endless-task-row .footer-note {
    margin-bottom: 6px;
  }

  .lore-flavor {
    font-style: italic;
    font-size: 12px;
    color: var(--heading);
    opacity: 0.85;
    margin-bottom: 8px;
  }

  /* The founding myth reuses .talent-branch's collapsible-disclosure look
     (see below) rather than inventing a second visual pattern for the same
     "collapsed by default, doesn't add page length" need. */
  .founding-myth {
    margin-bottom: 10px;
    border: 1px solid var(--wood);
    border-radius: 6px;
    padding: 8px 10px;
    background: rgba(255,255,255,0.15);
  }

  .founding-myth summary {
    font-size: 13px;
    font-weight: bold;
    color: var(--heading);
    cursor: pointer;
  }

  .founding-myth p {
    font-size: 12px;
    line-height: 1.6;
    margin: 8px 0 0;
  }

  /* QA/UI audit: talent branches became a <details> disclosure (see
     renderTalents()) so a player sees every branch's name and progress at
     a glance without the whole tree's ~40+ node cards being expanded and
     taking up scroll space at once. */
  .talent-branch {
    margin-bottom: 10px;
    border: 1px solid var(--wood);
    border-radius: 6px;
    padding: 8px 10px;
    background: rgba(255,255,255,0.15);
  }

  .talent-branch:last-child {
    margin-bottom: 0;
  }

  .talent-branch summary {
    margin: 0;
    font-size: 13px;
    font-weight: bold;
    color: var(--heading);
    cursor: pointer;
    list-style: revert;
  }

  .talent-branch summary:hover {
    color: var(--muted);
  }

  /* UX-071: next node + affordable marker in the branch header. */
  .talent-branch-next {
    margin-left: 10px;
    font-weight: normal;
    font-size: 12px;
    color: var(--muted);
  }

  /* UX-083: the one buyable node carries an explicit action, not just a brighter card. */
  /* UX-091: bulk learn, readable locked nodes, prestige CTA. */
  .talent-learn-all { margin-top: 8px; }
  .resource-btn.talent-node-locked:disabled { opacity: 1; color: var(--muted); }
  .resource-btn.talent-node-locked .resource-name { color: var(--muted); }
  .talent-prestige-cta { font-size: inherit; }

  .talent-learn-cta {
    align-self: flex-start;
    margin-top: 12px;
    padding: 3px 10px;
    border-radius: 4px;
    background: var(--gold);
    color: var(--on-accent);
    font-size: 12px;
    font-weight: 600;
  }
  .talent-learnable:hover .talent-learn-cta,
  .talent-learnable:focus-visible .talent-learn-cta { background: var(--gold-light); }

  .talent-affordable {

    margin-left: 10px;
    font-size: 12px;
    color: #f0cd7a;
  }

  .talent-affordable::before {
    content: "";
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: 5px;
    border-radius: 50%;
    background: #d9b45c;
    vertical-align: middle;
  }

  #panel-talents > .footer-note {
    text-align: left;
    font-size: 13px;
    max-width: 75ch;
  }

  .talent-branch[open] summary {
    margin-bottom: 6px;
  }

  .talent-branch .talent-node-list {
    margin-top: 8px;
  }

  .stats-search-label {
    display: block;
    margin: 14px 0 4px;
    color: var(--heading);
    font-size: 12px;
    font-weight: bold;
  }

  #stats-search {
    box-sizing: border-box;
    width: 100%;
    max-width: 560px;
    margin-bottom: 10px;
  }

  #stats-search-empty {
    margin: 8px 0;
  }

  .stats-groups {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
    align-items: start;
    gap: 8px;
  }

  .stats-groups .stats-domain {
    min-width: 0;
    margin: 0;
  }

  /* UX-068: Stats sections fold; jump row on top. */
  .stats-jump {
    display: flex;
    gap: 4px 16px;
    margin-bottom: 12px;
    overflow-x: auto;
    border-bottom: 1px solid var(--wood);
  }
  /* UX-093: navigation, not actions: text links on an iron rule, one scrolling row on mobile. */
  .stats-jump button {
    flex: none;
    padding: 6px 0;
    border: 0;
    background: none;
    color: var(--gold-light);
    font: inherit;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
  }
  .stats-jump button:hover { color: var(--heading); }
  .stats-jump button:focus-visible { outline: 2px solid var(--color-active); outline-offset: 2px; }

  .stats-section {
    margin: 0 0 12px;
  }

  .stats-section > summary {
    cursor: pointer;
    padding: 6px 0;
  }

  .stats-section > summary h3 {
    display: inline;
    margin: 0;
  }

  .pet-shelf {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 6px;
  }

  .pet-tile {
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: 8px;
    align-items: center;
    padding: 6px 8px;
    background: #151a21;
    border: 1px solid #39424f;
    border-radius: 6px;
    color: #9aa4b2;
  }

  .pet-tile > :first-child {
    grid-row: span 2;
  }

  .pet-tile-name {
    color: #dfe4ea;
    font-size: 13px;
  }

  .pet-tile-level {
    font-size: 12px;
  }

  .pet-tile.found {
    border-color: #d9b45c;
  }

  #resource-codex-search {
    box-sizing: border-box;
    width: 100%;
    max-width: 560px;
    margin-bottom: 10px;
  }

  #resource-codex-list .resource-codex-row[hidden] {
    display: none !important;
  }

  #stats-groups .market-row[hidden] {
    display: none !important;
  }

  .talent-node-list {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
  }

  .npc-capacity {
    font-size: 13px;
    font-weight: bold;
    color: var(--heading);
    margin-bottom: 8px;
  }

  .npc-row {
    display: block;
    background: var(--parchment);
    border: 1px solid var(--wood);
    border-radius: 6px;
    padding: 8px 10px;
    font-size: 13px;
    margin-bottom: 6px;
  }

  .npc-row:last-child {
    margin-bottom: 0;
  }

  .npc-name {
    font-weight: bold;
  }

  .npc-summary {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 10px;
    cursor: pointer;
    min-width: 0;
  }

  .npc-summary::marker {
    color: var(--heading);
  }

  .npc-assignment {
    color: var(--heading);
    font-size: 12px;
    overflow-wrap: anywhere;
  }

  .npc-details-controls {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
    margin-top: 10px;
    min-width: 0;
  }

  .npc-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    color: var(--heading);
    font-size: 11px;
    font-weight: bold;
    min-width: 0;
  }

  .queue-entry-label {
    flex: 1 1 auto;
    min-width: 0;
  }

  .queue-entry-controls {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex: 0 1 auto;
    gap: 4px;
    flex-wrap: wrap;
  }

  .npc-row select {
    font-size: 12px;
    width: 100%;
    min-width: 0;
    padding: 4px;
  }

  .npc-stat {
    font-size: 11px;
    color: var(--heading);
    grid-column: 1 / -1;
    overflow-wrap: anywhere;
  }

  .npc-details-actions {
    grid-column: 1 / -1;
    border-top: 1px solid var(--wood);
    padding-top: 8px;
  }

  .npc-row button.npc-dismiss {
    background: var(--red-fill);
    color: white;
    font-weight: bold;
  }

  .npc-row button {
    font-family: inherit;
    background: var(--red-fill);
    color: white;
    border: none;
    border-radius: 4px;
    padding: 4px 8px;
    font-size: 11px;
    cursor: pointer;
    flex: 0 0 auto;
  }

  @media (max-width: 480px) {
    .npc-details-controls {
      grid-template-columns: minmax(0, 1fr);
    }

    .npc-stat,
    .npc-details-actions {
      grid-column: 1;
    }
  }

  /* UX-067: job groups lead the villager roster. */
  #village-food-cook-btn { margin: 0 0 12px; }

  .npc-group {
    background: var(--parchment);
    border: 1px solid var(--wood);
    border-radius: 6px;
    padding: 10px 12px;
    font-size: 13px;
    margin-bottom: 8px;
  }

  .npc-group-header {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 4px 12px;
  }

  .npc-group-title { font-weight: bold; }

  .npc-group-output,
  .npc-group-roles {
    font-size: 12px;
    color: var(--muted);
  }

  .npc-group-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
  }

  .npc-group-count { width: 72px; }

  .npc-group-controls button { min-height: 32px; }

  /* UX-090: Township jump links, presets, materials list, left-aligned notes. */
  .town-jump {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 12px;
    margin-bottom: 12px;
    font-size: 13px;
  }
  .town-jump a { color: var(--heading); text-underline-offset: 3px; }
  #panel-township #npc-capacity,
  #panel-township .town-subsection { scroll-margin-top: 96px; }
  .town-note { margin: 0 0 8px; font-size: 12px; color: var(--muted); }
  #town-project-refund-why { margin-left: 8px; }
  .town-project-materials { margin: 6px 0 10px; padding-left: 18px; font-size: 12px; }
  .town-project-materials li { margin: 2px 0; }
  .npc-group-presets { display: inline-flex; gap: 4px; }
  .npc-group-controls .npc-group-preset { min-height: 32px; padding: 4px 8px; font-size: 12px; }

  .npc-roster-details { margin-top: 12px; }

  .npc-roster-details > summary {
    cursor: pointer;
    font-weight: bold;
    margin-bottom: 8px;
    min-height: 32px;
    display: list-item;
  }

  #npc-show-all-btn { margin-top: 8px; }

  .offline-row .action { margin-top: 8px; }

  .market-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-bottom: 10px;
  }

  .market-view-switch {
    display: flex;
    flex: 0 0 auto;
    gap: 4px;
  }

  .market-view-button {
    font-family: inherit;
    background: var(--surface-2);
    color: white;
    border: 1px solid var(--wood);
    border-radius: 4px;
    padding: 6px 12px;
    font-size: 12px;
    cursor: pointer;
  }

  .market-view-button[aria-pressed="true"] {
    background: var(--green);
    color: var(--on-accent);
  }

  .market-view-button:focus-visible {
    outline: 2px solid var(--heading);
    outline-offset: 2px;
  }

  .market-search-input {
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
    flex: 1 1 200px;
    padding: 6px 10px;
    margin-bottom: 0;
    font-size: 13px;
    font-family: inherit;
    border: 1px solid var(--wood);
    border-radius: 6px;
  }

  .market-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    background: var(--parchment);
    border: 1px solid var(--wood);
    border-radius: 6px;
    padding: 8px 10px;
    font-size: 13px;
    transition: background-color 0.6s ease; /* Phase 40: lets .level-up-flash pulse on a just-claimed quest row */
    margin-bottom: 6px;
  }

  .market-row:last-child {
    margin-bottom: 0;
  }

  .market-name {
    font-weight: bold;
    flex: 1 1 auto;
  }

  /* UX-025: Market/Inventory/Bestiary/Stats rows all reuse .market-meta for
     the price/qty/reward figure next to a .market-name -- same "important
     stat" tier as .resource-meta (13-14px), since it's the number a player
     is reading the row for. */
  .market-meta {
    color: var(--heading);
    font-size: 13px;
    flex: 0 0 auto;
  }

  .market-row.bestiary-row {
    display: grid;
    width: 100%;
    grid-template-columns: minmax(0, 1fr);
    gap: 3px;
  }

  #bestiary-list {
    display: grid;
    gap: 6px;
  }

  .market-row .bestiary-drops,
  .market-row .bestiary-drop-uses {
    overflow-wrap: anywhere;
  }

  .market-row button {
    font-family: inherit;
    background: var(--surface-2);
    color: white;
    border: none;
    border-radius: 4px;
    padding: 4px 8px;
    font-size: 11px;
    cursor: pointer;
    flex: 0 0 auto;
  }

  .market-row button:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }

  .quest-info {
    flex: 1 1 auto;
    min-width: 0;
  }

  .claimable-quests-section {
    margin: 14px 0;
  }

  .claimable-quests-section h4 {
    margin: 0 0 8px;
    color: var(--heading);
  }

  .claim-all-quests-btn {
    margin-bottom: 8px;
  }

  .claim-all-quests-btn[hidden] {
    display: none;
  }

  .claimable-quest-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
  }
  .claimable-quest-list[hidden] { display: none; } /* the flex rule above would otherwise override the hidden attribute (UX-084 fold) */

  #claimable-quest-list .market-row {
    border-left: 3px solid #8fd694;
  }

  .quest-status,
  .goal-status-badge {
    display: inline-flex;
    align-items: center;
    margin: 2px 6px 3px 0;
    padding: 2px 6px;
    border-radius: 10px;
    background: #303744;
    color: var(--heading);
    font-size: 11px;
    font-weight: bold;
    line-height: 1.35;
    white-space: nowrap;
  }

  .quest-status-claimable,
  .goal-status-claimable {
    background: #204b36;
    color: #b8f0c0;
  }

  .quest-status-working,
  .goal-status-working {
    background: #3d3524;
    color: #efd28c;
  }

  .quest-status-ready,
  .goal-status-ready {
    background: #293b4d;
    color: #c3e1ff;
  }

  .quest-status-completed,
  .goal-status-completed,
  .goal-status-done {
    background: #303a31;
    color: #b9d9ba;
  }

  .all-quests-details,
  .treasure-map-details {
    margin: 14px 0;
    border-top: 1px solid var(--wood);
    padding-top: 10px;
  }

  .all-quests-details > summary,
  .treasure-map-details > summary {
    cursor: pointer;
    color: var(--heading);
    font-size: 14px;
    font-weight: bold;
  }

  .all-quests-hint {
    margin: 8px 0;
  }

  .quest-search-label {
    display: block;
    margin: 10px 0 4px;
    color: var(--heading);
    font-size: 12px;
    font-weight: bold;
  }

  #quest-search {
    display: block;
    box-sizing: border-box;
    width: 100%;
    max-width: 520px;
    margin-bottom: 8px;
  }

  .quest-show-completed-label {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 6px;
    margin: 8px 0;
    cursor: pointer;
  }

  #quest-list .quest-search-hidden {
    display: none !important;
  }

  #quest-filter-empty {
    margin: 8px 0;
  }

  /* QA/UI audit: completed quests are hidden by default (see renderQuests()
     and the "Show completed quests too" checkbox) so a long-played save
     isn't mostly a wall of already-claimed rows. */
  #quest-list .quest-completed-row {
    display: none;
  }

  #quest-list.show-completed .quest-completed-row {
    display: flex;
  }

  /* GG-001: Pinned Goals and Possible Goals */
  .pinned-goals-card {
    background: #1b212a;
    border: 1px solid #39424f;
    border-radius: 6px;
    padding: 8px 10px;
  }
  .pinned-goals-card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 12px;
    font-weight: bold;
    color: var(--heading);
    margin-bottom: 6px;
  }
  .pinned-goals-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
  }
  .pinned-goal-row {
    background: #1b212a;
    border: 1px solid #39424f;
    border-radius: 5px;
    padding: 6px 9px;
  }
  .pinned-goal-header {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: 4px;
    gap: 8px;
  }
  .pinned-goal-title {
    font-size: 12px;
    font-weight: bold;
    color: var(--heading);
  }
  .pinned-goal-desc {
    font-size: 11px;
    color: #9aa4b2;
  }
  .pinned-goal-progress {
    display: flex;
    align-items: center;
    gap: 8px;
  }
  .pinned-goal-bar-wrap {
    flex: 1;
    min-width: 60px;
  }
  /* UX-074: Collection's next goals -- closest locked achievements and per-category bars. */
  .collection-progress {
    appearance: none;
    width: 100%;
    height: 6px;
    border: 0;
    border-radius: 3px;
    background: #2a323d;
    overflow: hidden;
  }
  .collection-progress::-webkit-progress-bar { background: #2a323d; }
  .collection-progress::-webkit-progress-value { background: var(--gold); }
  .collection-progress::-moz-progress-bar { background: var(--gold); }
  .collection-closest { margin-top: 12px; }
  .collection-toolbar-field { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted); }
  /* UX-093: at phone width the two filters share one row (label above select) and the recent chips stay compact. */
  @media (max-width: 600px) {
    #collection-title-slot { display: contents; }
    #panel-collection .inventory-toolbar { flex-wrap: nowrap; }
    #panel-collection .collection-toolbar-field { flex: 1 1 0; min-width: 0; flex-direction: column; align-items: stretch; gap: 2px; }
    #panel-collection .collection-toolbar-field select { width: 100%; min-width: 0; }
    #collection-recent { gap: 6px; }
    #collection-recent .market-row { padding: 4px 8px; }
    #collection-recent .market-meta { display: none; }
  }
  /* UX-093: the tagline is said once on the login screen; on a phone it only pushes every page down. */
  @media (max-width: 600px) { .game-tagline { display: none; } }

  .collection-closest h3 { margin: 0 0 6px; }
  .collection-closest-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 2px 8px;
    padding: 6px 0;
    font-size: 13px;
  }
  .collection-closest-name { overflow-wrap: anywhere; }
  .collection-closest-count { color: var(--muted); font-variant-numeric: tabular-nums; }
  .collection-closest-row .collection-progress { grid-column: 1 / -1; }
  #collection-groups summary .collection-progress {
    display: block;
    max-width: 240px;
    margin-top: 4px;
  }
  #collection-groups .collection-group-complete > summary { opacity: 0.6; }
  #collection-groups .collection-group-complete .collection-progress::-webkit-progress-value { background: var(--green); }
  #collection-groups .collection-group-complete .collection-progress::-moz-progress-bar { background: var(--green); }
  .pinned-goal-pct {
    font-size: 11px;
    font-weight: bold;
    color: var(--heading);
    min-width: 34px;
    text-align: right;
  }
  .pinned-goal-unpin-btn {
    font-size: 11px;
    padding: 1px 6px;
    border-radius: 3px;
    border: 1px solid #39424f;
    background: #1b212a;
    color: var(--heading);
    cursor: pointer;
  }
  .pinned-goal-unpin-btn:hover {
    background: #3a1a1c;
    border-color: #e0a0a0;
  }
  .pinned-goal-completed-badge {
    font-size: 11px;
    font-weight: bold;
    color: #8fd694;
  }
  .possible-goals-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
  }
  .possible-goal-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 5px 8px;
    background: #1b212a;
    border: 1px solid #232a34;
    border-radius: 4px;
    font-size: 12px;
  }
  .possible-goal-title {
    font-weight: 500;
    color: var(--heading);
    flex: 1 1 auto;
    min-width: 0;
    overflow-wrap: anywhere;
  }
  .possible-goal-pin-btn, .pin-goal-btn {
    font-size: 11px;
    padding: 2px 7px;
    border-radius: 4px;
    border: 1px solid #39424f;
    background: #1b212a;
    color: var(--heading);
    cursor: pointer;
  }
  .possible-goal-pin-btn:hover, .pin-goal-btn:hover {
    background: #1e242d;
    border-color: var(--muted);
  }
  .possible-goal-pin-btn:disabled, .pin-goal-btn:disabled {
    opacity: 0.5;
    cursor: default;
  }

  /* AJ-001 / IDEA-0057: Adventure Journal */
  .adventure-journal-section {
    background: #1b212a;
    border: 1px solid #39424f;
    border-radius: 6px;
    padding: 10px 12px;
  }
  .adventure-journal-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-height: 480px;
    overflow-y: auto;
  }
  .journal-entry-row {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    background: #1b212a;
    border: 1px solid #39424f;
    border-radius: 5px;
    padding: 8px 10px;
    transition: background 0.15s ease;
  }
  .journal-entry-row:hover {
    background: #1b212a;
  }
  .journal-icon {
    font-size: 18px;
    line-height: 1;
    flex: 0 0 24px;
    text-align: center;
    padding-top: 2px;
  }
  .journal-content {
    flex: 1 1 auto;
    min-width: 0;
  }
  .journal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 2px;
  }
  .journal-title {
    font-size: 13px;
    font-weight: bold;
    color: var(--heading);
  }
  .journal-desc {
    font-size: 11px;
    color: #9aa4b2;
    line-height: 1.35;
  }
  /* UX-084: same-minute entries read as one group: no repeated time, tighter rows. */
  .journal-entry-row.journal-entry-grouped { margin-top: -4px; padding-top: 4px; padding-bottom: 4px; }
  .stats-headline {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 8px 16px;
    margin: 0 0 12px;
  }
  .stats-headline dt { font-size: 12px; color: var(--muted); }
  .stats-headline dd { margin: 0; font-size: 18px; font-weight: 600; color: var(--heading); font-variant-numeric: tabular-nums; }
  .journal-time {

    font-size: 11px;
    color: #8b95a5;
    margin-top: 3px;
  }
  .journal-empty-note {
    font-size: 12px;
    color: var(--muted);
    font-style: italic;
    text-align: center;
    padding: 16px 8px;
  }



  .inventory-group {
    margin-bottom: var(--space-lg);
  }

  .inventory-group:last-child {
    margin-bottom: 0;
  }

  .inventory-group h3 {
    margin: 0 0 var(--space-md) 0;
    font-size: var(--font-size-md);
    color: var(--heading);
  }

  /* UX-058: compact icon-tile grid, same auto-fill pattern as .skill-grid
     (line ~467), instead of a wide always-expanded flex row per item. */
  .inventory-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(76px, 1fr));
    gap: 8px;
  }

  .inv-item {
    min-width: 0;
  }

  .item-details {
    min-width: 0;
  }

  .inv-tile-face {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    width: 100%;
    background: var(--parchment);
    border: 1px solid var(--wood);
    border-radius: 6px;
    padding: 8px 4px;
    font-size: 13px;
    cursor: pointer;
    list-style: none;
  }

  .inv-tile-face::-webkit-details-marker {
    display: none;
  }

  /* R-21: rarity border, generic for any item tagged in ITEM_RARITY --
     reused as-is by the weapon-picker's .resource-btn rows below. */
  .item-rarity-rare .inv-tile-face,
  .resource-btn.item-rarity-rare {
    border-color: #3b82c4;
    box-shadow: 0 0 0 1px rgba(59, 130, 196, 0.35);
  }

  .item-rarity-epic .inv-tile-face,
  .resource-btn.item-rarity-epic {
    border-color: #a855f7;
    box-shadow: 0 0 0 1px rgba(168, 85, 247, 0.4);
  }

  .inv-tile-face:focus-visible {
    outline: 2px solid var(--heading);
    outline-offset: 2px;
  }

  .inv-tile-icon {
    display: block;
    font-size: 22px;
    line-height: 1;
  }

  .inv-tile-name {
    display: block;
    width: 100%;
    font-size: 11px;
    text-align: center;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .inv-item .count {
    font-weight: bold;
    color: var(--heading);
  }

  .item-detail-name {
    font-weight: 600;
    color: var(--heading);
  }

  .item-detail-content {
    display: grid;
    gap: 4px;
    min-width: 0;
    margin-top: 6px;
  }

  .item-detail-content .item-usage,
  .item-detail-content .item-flavor,
  .item-detail-content .recipe-consumers {
    display: block;
    min-width: 0;
    overflow-wrap: anywhere;
  }

  /* UX-003: complete item-use description inside the selected item's details. */
  .item-usage {
    flex: 0 0 100%;
    font-size: 11px;
    color: var(--heading);
    opacity: 0.75;
  }

  /* UX-010 / ITM-001: authored lore remains a secondary, italic detail. */
  .item-flavor {
    flex: 0 0 100%;
    font-size: 11px;
    color: var(--heading);
    opacity: 0.6;
    font-style: italic;
  }

  .inventory-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 10px;
    align-items: center;
  }

  /* UX-088: inventory explainer, geode block and chest key reason. */
  .inventory-intro {
    margin: 0 0 10px;
    font-size: 12px;
    color: var(--muted);
    text-align: left;
  }

  .geode-block {
    display: flex;
    gap: 12px;
    align-items: center;
    margin-bottom: 12px;
  }

  .geode-block > .inv-item {
    flex: 0 0 auto;
    width: 88px;
  }

  .geode-controls {
    display: grid;
    gap: 6px;
    flex: 1 1 auto;
    min-width: 0;
  }

  .geode-hint {
    margin: 0;
    font-size: 11px;
    color: var(--muted);
  }

  .geode-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
  }

  .geode-ore-label {
    display: inline-flex;
    gap: 4px;
    align-items: center;
    font-size: 12px;
  }

  .chest-need-key {
    font-size: 11px;
    color: var(--muted);
  }

  .inventory-toolbar .inventory-filter-select,
  .inventory-toolbar .inventory-sort-select {
    flex: 1 1 140px;
    min-width: 0;
  }

  .inventory-toolbar .inventory-search-input {
    flex: 1 1 200px;
    margin-bottom: 0;
  }

  /* VIS-003: border/background/color kommer nu fra select-basisreglen; her
     bliver kun det tilbage der faktisk afviger. Den gamle `var(--card, ...)`
     pegede på en variabel der aldrig har eksisteret -- kun fallbacken virkede. */
  .inventory-filter-select,
  .inventory-sort-select {
    padding: 6px 10px;
    font-size: 12px;
    border-radius: 6px;
    flex: 0 0 auto;
  }

  .inventory-search-input {
    width: 100%;
    box-sizing: border-box;
    padding: 6px 10px;
    margin-bottom: 10px;
    font-size: 13px;
    font-family: inherit;
    border: 1px solid var(--wood);
    border-radius: 6px;
  }

  .favorite-toggle {
    font-family: inherit;
    background: none;
    border: none;
    padding: 0;
    margin-left: 6px;
    font-size: 14px;
    line-height: 1;
    cursor: pointer;
    flex: 0 0 auto;
    color: #e5a00d;
  }

  .reserve-wrap {
    font-size: 11px;
    color: var(--heading);
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 3px;
    flex: 0 0 auto;
  }

  .reserve-input {
    width: 48px;
    font-size: 11px;
    font-family: inherit;
    padding: 2px 4px;
    border: 1px solid var(--wood);
    border-radius: 4px;
    background: var(--bg, #1b212a);
    text-align: right;
  }

  /* CG-030a: read-only recipe consumers are available in item details. */
  .recipe-consumers {
    flex: 0 0 100%;
    font-size: 11px;
    color: var(--heading);
    opacity: 0.75;
  }

  .reserve-estimate,
  .reserve-estimate-detail {
    flex: 0 0 100%;
    color: var(--heading);
    overflow-wrap: anywhere;
  }

  .reserve-estimate {
    font-size: 11px;
    font-weight: 600;
  }

  .reserve-estimate-detail {
    font-size: 11px;
    opacity: 0.7;
  }

  .lock-toggle {
    font-family: inherit;
    background: none;
    border: none;
    padding: 0;
    margin-left: 6px;
    font-size: 13px;
    line-height: 1;
    cursor: pointer;
    flex: 0 0 auto;
  }

  .salvage-btn {
    font-family: inherit;
    font-size: 11px;
    padding: 2px 6px;
    border: 1px solid var(--wood);
    border-radius: 4px;
    background: var(--parchment);
    color: var(--heading);
    cursor: pointer;
    margin-left: 4px;
    flex: 0 0 auto;
  }

  .salvage-btn:hover:not(:disabled) {
    background: var(--wood);
    color: var(--text);
  }

  .salvage-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }

  .upgrade-btn {
    font-family: inherit;
    font-size: 11px;
    padding: 2px 6px;
    border: 1px solid var(--gold);
    border-radius: 4px;
    background: var(--parchment);
    color: var(--heading);
    cursor: pointer;
    margin-left: 4px;
    flex: 0 0 auto;
  }

  .upgrade-btn:hover:not(:disabled) {
    background: var(--gold);
    color: var(--on-accent);
  }

  .upgrade-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }

  .empty-note {
    font-size: 13px;
    color: var(--muted);
    font-style: italic;
  }

  .controls {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
  }

  .settings-session-actions {
    margin-bottom: 12px;
  }

  .settings-groups {
    display: grid;
    gap: 12px;
    min-width: 0;
  }

  .settings-group {
    min-width: 0;
    padding: 12px;
    background: var(--parchment-dark);
    border: 1px solid var(--wood);
    border-radius: 6px;
  }

  .settings-group h3 {
    margin: 0 0 8px;
  }

  /* UX-085: helper text sits under left-aligned headings and controls. */
  #panel-controls .footer-note { text-align: left; }
  .settings-group h4 { margin: 14px 0 6px; font-size: 13px; color: var(--muted); }
  .settings-group h3 + h4 { margin-top: 4px; }
  .settings-session-actions { align-items: center; }
  .pause-status { font-size: 13px; color: var(--muted); }
  .pause-status.is-paused { color: var(--gold-light); font-weight: 600; }
  .settings-group > .footer-note {

    margin-top: 0;
  }

  .settings-group .save-io {
    margin-top: 12px;
  }

  .settings-account .cloud-auth-box h4 {
    margin: 0 0 8px;
  }

  .settings-danger-zone {
    border-color: var(--red-text);
    border-left-width: 5px;
  }

  .settings-danger-zone h3 {
    color: var(--red-text);
  }

  #panel-controls button:focus-visible,
  #panel-controls a:focus-visible,
  #panel-controls input:focus-visible,
  #panel-controls textarea:focus-visible {
    outline: 3px solid var(--heading);
    outline-offset: 2px;
  }

  button.action, a.action {
    font-family: inherit;
    background: var(--wood);
    color: var(--text);
    border: none;
    border-radius: 6px;
    padding: 8px 14px;
    cursor: pointer;
    font-size: 13px;
    /* Phase 53: the "Download as file" link reuses this same class as
       every action button (a.action, alongside button.action) — an <a>
       is inline by default, so it needs these to actually look and sit
       like the buttons next to it instead of hugging its text. */
    display: inline-block;
    text-decoration: none;
    line-height: 1.2;
  }

  button.action:hover, a.action:hover {
    background: var(--surface-2);
  }

  /* UX audit fix: recruit-btn, monument-btn and queue-add-btn are all set
     to .disabled = true/false in JS depending on affordability/capacity,
     but this class previously had no :disabled rule at all — a disabled
     button rendered pixel-identical to an enabled one (only .market-row
     button had a disabled style). Same treatment as that existing rule. */
  button.action:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    background: var(--wood);
  }

  button.danger {
    background: var(--red-fill);
  }

  /* Phase 53 ("save export/import"): the export/import boxes share the
     same parchment-dark card look as an .offline-row, tucked inside the
     Game controls panel rather than a modal — export/import are optional
     tools someone reaches for occasionally, not an interruption like the
     offline-progress summary. */
  .save-io {
    margin-top: 12px;
    padding: 12px;
    background: var(--parchment-dark);
    border: 1px solid var(--wood);
    border-radius: 6px;
  }

  .cloud-auth-fields {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 6px;
    max-width: 420px;
  }

  .cloud-auth-fields.panel-hidden {
    display: none;
  }

  .cloud-auth-fields input {
    box-sizing: border-box;
    width: 100%;
    padding: 8px;
    border: 1px solid var(--wood);
    border-radius: 4px;
    background: var(--parchment);
    color: var(--text);
    font: inherit;
  }

  .cloud-auth-fields .controls {
    margin-top: 4px;
  }

  .cloud-history-list {
    display: grid;
    gap: 6px;
    list-style: none;
    margin: 8px 0;
    padding: 0;
  }

  .cloud-history-list .action {
    text-align: left;
    width: 100%;
  }

  #cloud-history-preview {
    margin-top: 8px;
  }

  .save-io textarea {
    width: 100%;
    font-family: 'Courier New', monospace;
    font-size: 12px;
    padding: 8px;
    border: 1px solid var(--wood);
    border-radius: 4px;
    background: var(--parchment);
    color: var(--text);
    resize: vertical;
    box-sizing: border-box;
  }

  button.danger:hover {
    background: #8f2a27;
  }

  .history-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-height: 220px;
    overflow-y: auto;
  }

  .history-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    background: var(--parchment);
    border: 1px solid var(--wood);
    border-radius: 6px;
    padding: 6px 10px;
    font-size: 12px;
  }

  .history-row .meta {
    display: flex;
    flex-direction: column;
  }

  .history-row .label {
    font-weight: bold;
  }

  .history-row .date {
    color: var(--muted);
    font-size: 11px;
  }

  .history-row button {
    font-family: inherit;
    background: var(--green);
    color: var(--on-accent);
    border: none;
    border-radius: 4px;
    padding: 4px 8px;
    font-size: 11px;
    cursor: pointer;
  }

  .footer-note {
    text-align: center;
    font-size: var(--font-size-xs);
    color: var(--muted);
    margin-top: var(--space-md);
  }

  /* UX-025: .footer-note covers two very different jobs -- static lore/
     "how this panel works" prose (stays 11px, per the audit's own intent
     that flavor text stay small) and live gameplay status/counters (Township
     villager status, mastery pool checkpoints, queue capacity, Prosperity
     tribute, offline-speed note, etc.) that a player actually reads as data.
     .footer-note-data is an additive modifier (combined with .footer-note,
     never a replacement) that raises just the data use-sites into the
     "secondary info" tier (12-13px) without touching the ~50 lore/
     instructional .footer-note use-sites left untouched across the game. */
  .footer-note-data {
    font-size: var(--font-size-sm);
  }

  /* UX-076: text-weight link inside a data note (Skilling's next-goal line). */
  .inline-link-button {
    padding: 0;
    border: 0;
    background: none;
    color: var(--heading);
    font: inherit;
    text-decoration: underline;
    text-underline-offset: 2px;
    cursor: pointer;
  }
  .inline-link-button:focus-visible { outline: 2px solid var(--color-active); outline-offset: 2px; }

  /* UX-062: Rift/Horde's labeled stat fields, same "facts you scan, not
     prose you parse" shape as #horde-loadout-records' table. */
  .status-fields {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 4px 14px;
  }

  .status-field {
    display: inline-flex;
    gap: 4px;
  }

  .status-field-label {
    color: var(--muted);
  }

  .status-field-value {
    font-weight: bold;
    color: var(--heading);
  }

  .status-fields-note {
    margin: 4px 0 0;
  }

  .companion-care-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    margin: 8px 0 12px;
  }

  .companion-food-select {
    flex: 1 1 190px;
    min-width: min(100%, 150px);
  }

  .companion-feed-amount {
    flex: 0 0 auto;
  }

  .companion-feed-preview {
    flex: 1 0 100%;
    margin-top: 0;
    text-align: left;
    overflow-wrap: anywhere;
  }

  /* Offline-progress modal */
  .modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 50;
  }

  .modal-overlay.hidden {
    display: none;
  }

  .modal-box {
    background: var(--parchment);
    border: 3px solid var(--wood);
    border-radius: 10px;
    padding: 24px;
    max-width: 460px;
    max-height: 85vh;
    overflow-y: auto;
    text-align: center;
  }

  .modal-box h2 {
    margin-top: 0;
    color: var(--heading);
  }

  /* Phase 41 ("redesign the offline-progress modal"): replaces the old
     single blended <p> (built with literal \n line breaks and
     white-space: pre-line on .modal-box) with a real per-activity
     breakdown — one card per skill/combat/villager segment, each showing
     what was actually gained, xp and an implied xp/hr, and any level-up,
     instead of one run-on paragraph. See renderOfflineModal(). */
  #offline-summary {
    text-align: center;
    margin-bottom: 4px;
  }

  #offline-speed-note {
    text-align: center;
    margin-top: 0;
    margin-bottom: 14px;
  }

  #offline-breakdown {
    text-align: left;
  }

  .offline-row {
    background: var(--parchment-dark);
    border: 1px solid var(--wood);
    border-radius: 6px;
    padding: 8px 10px;
    margin-bottom: 8px;
  }

  .offline-row-header {
    font-weight: bold;
    color: var(--heading);
    font-size: 13px;
  }

  .offline-row-detail {
    font-size: 12px;
    color: var(--muted);
    margin-top: 2px;
  }

  .offline-row-note {
    font-size: 12px;
    margin-top: 4px;
  }

  .offline-row-note.level-up {
    color: var(--green);
    font-weight: bold;
  }

  .offline-row-note.warning {
    color: var(--red-text);
    font-weight: bold;
  }

  /* Market flexible selling UI */
  .market-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 8px;
    padding: 6px 8px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
  }

  .market-name {
    font-weight: 600;
    color: var(--heading);
  }

  .market-meta {
    font-size: 13px;
    color: var(--muted);
  }

  /* UX-010 / ITM-001: functional usage line + lore line on the Market buy
     rows, same pattern as .item-usage / .item-flavor in Inventory. */
  .market-usage {
    flex: 0 0 100%;
    font-size: 11px;
    color: var(--heading);
    opacity: 0.75;
  }

  .market-row.resource-codex-row {
    display: grid;
    width: 100%;
    grid-template-columns: minmax(0, 1fr);
    gap: 3px;
  }

  #resource-codex-list {
    display: grid;
    gap: 6px;
  }

  .resource-codex-source,
  .resource-codex-usage {
    overflow-wrap: anywhere;
  }

  .market-flavor {
    flex: 0 0 100%;
    font-size: 11px;
    color: var(--heading);
    opacity: 0.6;
    font-style: italic;
  }

  .market-actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
  }

  .market-custom-sell {
    display: inline-flex;
    align-items: center;
    gap: 4px;
  }

  .market-sell-qty-input {
    width: 50px;
    padding: 2px 4px;
    font-size: 11px;
    font-family: inherit;
    border: 1px solid var(--wood);
    border-radius: 4px;
  }

  .market-sell-1-btn,
  .market-sell-x-btn,
  .market-sell-all-btn,
  .market-sell-btn {
    font-size: 11px;
    padding: 2px 6px;
    border-radius: 4px;
  }

  /* UX-089: price under the name; Qty | Max | Sell in fixed columns on every row. */
  .market-sell-row { flex-wrap: nowrap; }
  .market-sell-row .market-name { flex: 1 1 auto; min-width: 0; }
  .market-sell-row .market-meta { display: block; font-weight: 400; font-size: 12px; }
  .market-sell-row .market-actions {
    display: grid;
    grid-template-columns: 5.5em 3.5em 12em;
    flex: 0 0 auto;
  }
  .market-sell-row .market-actions .market-sell-btn { grid-column: 3; }
  .market-sell-row .market-actions button { width: 100%; }
  .market-max-btn { font-size: 11px; padding: 2px 6px; border-radius: 4px; }
  .market-qty-label { font-size: 11px; color: var(--muted); }
  .market-sell-x-btn.market-sell-all-armed {
    border: 1px solid var(--red);
    color: var(--heading);
    background: var(--wood-dark);
  }
  @media (max-width: 539px) {
    .market-sell-row { flex-wrap: wrap; gap: 4px 8px; }
    .market-sell-row .market-name {
      flex: 1 1 100%;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .market-sell-row .market-meta { display: inline; margin-left: 6px; }
    .market-sell-row .market-actions { flex: 1 1 100%; gap: 4px; grid-template-columns: auto auto 1fr; }
    .market-sell-row .market-actions button { padding: 6px 8px; }
    #market-category-filter, #market-sort-select { flex: 1 1 120px; min-width: 0; }
    .market-sell-qty-input { width: 52px; }
  }


/* Persistent skill browsing and a non-colour-only combat target marker. */
#skill-jump { min-width: 0; max-width: 145px; flex: 0 1 145px; }
.status-nav-row .page-tabs { min-width: 0; flex: 1; }

#enemy-hp-list .attack-target { border-left: 3px solid var(--color-active); padding-left: 8px; }

/* BUG-011 / UX-009 slice 2: the eight page tabs wrapped to 3 rows at 480px,
   4 at 390px and 8 at 320px, so the fixed bar grew to 141/172/296px against
   the 150px body reserves for it and buried the title from 420px down.
   Below the breakpoint the tabs are replaced by #page-jump, a <select> with
   the same eight destinations, so the row is two short controls instead of
   eight buttons and a select. Both are always in the DOM (see
   renderPageTabs()) — these rules are the only thing that decides which one
   the player sees, so no JS anywhere reads the viewport width.

   One breakpoint, 540px, and it is measured rather than guessed: with
   #skill-jump in the row the tabs hold two rows down to 540px (110px bar,
   40px of slack), go to three at 520px (141px, 9px left) and overflow at
   420px (172px). The interim fix that shipped first dropped #skill-jump
   below 540px instead and said the phone was left without a skill picker;
   it gets one back here, because below 540px the tabs are gone and the row
   has room for both selects. Raising padding-top is still not an option —
   eight rows at 320px would need 320px of reserved space.
   `tests/e2e/status-bar-layout.e2e.test.js` and
   `tests/e2e/mobile-nav.e2e.test.js` hold the invariant. */
#page-jump { display: none; }
@media (max-width: 539px) {
  .status-nav-row .page-tabs { display: none; }
  #page-jump { display: block; min-width: 0; flex: 1 1 auto; }
  /* UX-086: the two-select bar is ~70px here, so 150px left a dead band above the
     title; the status-bar-layout e2e test still guards bar <= reserved. */
  body { padding-top: 100px; }
  /* UX-086: the running skill and its progress come first; the skill grid
     (also reachable from the skill select above) moves to the end. */
  .game { display: flex; flex-direction: column; }
  #panel-skills { order: 1; }

}


/* At the desktop breakpoint, font/emoji metrics can otherwise put the last
   tab on a third row. Five columns (nine tabs since R-01 added Collection,
   5 + 4) keep the reserved two-row height stable; update this count
   alongside PAGE_TABS in js/render.js if a page tab is ever added/removed. */
@media (min-width: 540px) and (max-width: 700px) {
  .status-nav-row .page-tabs { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .page-tab-btn { padding-inline: 3px; white-space: nowrap; }
}

/* MP-001 / IDEA-0048: Material and Recipe Planner UI */
.recipe-plan-btn {
  font-family: inherit;
  font-size: 11px;
  padding: 2px 6px;
  border: 1px solid var(--wood);
  border-radius: 4px;
  background: var(--parchment);
  color: var(--heading);
  cursor: pointer;
  flex: 0 0 auto;
}

.recipe-plan-btn:hover {
  background: var(--wood);
  color: var(--text);
}

/* UX-015 / DEC-045 obs 2: "Make 1" quick-craft button, styled like its
   .recipe-plan-btn neighbour in the actions bar so the two read as a set. */
.recipe-make1-btn {
  font-family: inherit;
  font-size: 11px;
  padding: 2px 6px;
  border: 1px solid var(--wood);
  border-radius: 4px;
  background: var(--parchment);
  color: var(--heading);
  cursor: pointer;
  flex: 0 0 auto;
}

.recipe-make1-btn:hover:not(:disabled) {
  background: var(--wood);
  color: var(--text);
}

.material-planner-box {
  max-width: 520px;
  width: 92%;
  text-align: left;
}

.planner-close-x {
  background: transparent;
  border: none;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  color: var(--heading);
  padding: 0 4px;
}

.planner-close-x:hover {
  color: var(--red-text);
}

.planner-qty-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 10px 0;
  font-size: 13px;
  font-weight: bold;
  color: var(--heading);
}

.planner-qty-row input[type="number"] {
  font-family: inherit;
  font-size: 13px;
  width: 80px;
  padding: 3px 6px;
  border: 1px solid var(--wood);
  border-radius: 4px;
  background: #1b212a;
  color: var(--text);
}

.artisan-order-controls {
  display: flex;
  align-items: end;
  flex-wrap: wrap;
  gap: 8px 12px;
  margin: 8px 0;
}

.artisan-order-controls label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  color: var(--heading);
  font-size: 13px;
  font-weight: bold;
}

.artisan-order-controls select,
.artisan-order-controls input[type="number"] {
  min-height: 32px;
  max-width: 100%;
  padding: 6px 8px;
  border: 1px solid var(--wood);
  border-radius: 4px;
  background: var(--parchment-dark);
  color: var(--heading);
  font: inherit;
}

.artisan-order-controls select {
  width: min(100%, 320px);
}

.artisan-order-controls input[type="number"] {
  width: 140px;
}

/* TS-002: Auto-Mason on/off + gold reserve in Treasury. */
.auto-mason-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  margin-bottom: 10px;
}

.auto-mason-controls label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--heading);
  font-size: 13px;
}

.auto-mason-controls input[type="text"] {
  width: 100px;
  min-height: 32px;
  padding: 6px 8px;
  border: 1px solid var(--wood);
  border-radius: 6px;
  background: var(--parchment-dark);
  color: var(--heading);
  font: inherit;
  text-align: right;
}

.auto-mason-controls input[aria-invalid="true"] {
  border-color: var(--danger, #c0392b);
}

.artisan-order-progress {
  align-self: center;
}

.planner-banner {
  padding: 8px 12px;
  border-radius: 6px;
  font-weight: bold;
  font-size: 13px;
  margin-bottom: 6px;
}

.planner-status-ready {
  background: #14301c;
  border: 1px solid #81c784;
  color: #8fd694;
}

.planner-status-intermediate {
  background: #122c38;
  border: 1px solid #81d4fa;
  color: #7fc5e8;
}

.planner-status-missing {
  background: #3a2a12;
  border: 1px solid #ffb74d;
  color: #e0a44a;
}

.planner-subtext {
  font-size: 12px;
  color: var(--muted);
  margin-bottom: 8px;
}

.planner-section {
  margin-top: 12px;
}

.planner-section-title {
  font-size: 11px;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--heading);
  margin-bottom: 6px;
}

.planner-empty-note {
  font-size: 12px;
  font-style: italic;
  color: var(--muted);
}

.planner-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.planner-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 12px;
}

.planner-chip-ok {
  background: #14301c;
  border: 1px solid #a5d6a7;
  color: #8fd694;
}

.planner-chip-missing {
  background: #3a1a1c;
  border: 1px solid #ef9a9a;
  color: #f28b82;
}

.planner-chip-deficit {
  font-weight: bold;
}

.planner-chip-reserve {
  color: var(--muted);
  font-size: 11px;
}

.planner-skill-req {
  color: var(--muted);
  font-size: 11px;
}

.planner-tree-view {
  background: rgba(0, 0, 0, 0.03);
  border: 1px solid var(--parchment-dark);
  border-radius: 6px;
  padding: 8px 12px;
  max-height: 220px;
  overflow-y: auto;
  font-size: 12px;
}

.planner-tree-root, .planner-tree-sublist {
  list-style: none;
  margin: 0;
  padding-left: 16px;
}

.planner-tree-root {
  padding-left: 0;
}

.planner-tree-node {
  margin: 4px 0;
}

.planner-tree-item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}

.planner-tree-label {
  font-weight: 500;
}

.planner-tree-badge {
  display: inline-block;
  padding: 1px 5px;
  border-radius: 3px;
  font-size: 11px;
  font-weight: bold;
}

.tree-badge-ok {
  background: #14301c;
  color: #8fd694;
  border: 1px solid #a5d6a7;
}

.tree-badge-missing {
  background: #3a1a1c;
  color: #f28b82;
  border: 1px solid #ef9a9a;
}

.planner-tree-deficit {
  font-size: 11px;
  color: var(--red-text);
  font-style: italic;
}

/* SC-001 (IDEA-0023): Aether Stability Card & Attunement */
.aether-stability-card {
  padding: 8px 12px;
  background: #1b212a;
  border: 1px solid var(--wood-light, #39424f);
  border-radius: 6px;
}

.aether-stability-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
}

.aether-stability-title {
  font-size: 13px;
  font-weight: bold;
  color: var(--heading);
}

.aether-stability-badge {
  font-size: 11px;
  font-weight: bold;
  padding: 2px 7px;
  border-radius: 4px;
  border: 1px solid;
}

.badge-stable {
  background: #14301c;
  border-color: #81c784;
  color: #8fd694;
}

.badge-volatile {
  background: #241a3a;
  border-color: #9061f9;
  color: #b9a4f5;
}

.aether-stability-btn-group {
  display: flex;
  gap: 8px;
}

.aether-mode-btn {
  flex: 1;
  padding: 6px 10px;
  font-size: 12px;
  font-weight: bold;
  cursor: pointer;
  border-radius: 4px;
  border: 1px solid var(--wood-light, #39424f);
  background: #1b212a;
  color: var(--text);
  transition: all 0.15s ease;
}

.aether-mode-btn:hover {
  border-color: var(--muted);
  background: var(--parchment);
}

.aether-mode-btn.active {
  background: var(--color-active);
  border-color: var(--color-active);
  color: var(--on-accent);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

/* CG-026c: Mining Risk Card & Approach (direct forlæg the Aether Stability
   Card above — own classes so Aether's own styling stays untouched). */
.mining-risk-card {
  padding: 8px 12px;
  background: #1b212a;
  border: 1px solid var(--wood-light, #39424f);
  border-radius: 6px;
}

.mining-risk-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
}

.mining-risk-title {
  font-size: 13px;
  font-weight: bold;
  color: var(--heading);
}

.mining-risk-badge {
  font-size: 11px;
  font-weight: bold;
  padding: 2px 7px;
  border-radius: 4px;
  border: 1px solid;
}

.badge-careful {
  background: #14301c;
  border-color: #81c784;
  color: #8fd694;
}

.badge-reckless {
  background: #3a1a1a;
  border-color: #e57373;
  color: #f5a4a4;
}

.mining-risk-btn-group {
  display: flex;
  gap: 8px;
}

.mining-mode-btn {
  flex: 1;
  padding: 6px 10px;
  font-size: 12px;
  font-weight: bold;
  cursor: pointer;
  border-radius: 4px;
  border: 1px solid var(--wood-light, #39424f);
  background: #1b212a;
  color: var(--text);
  transition: all 0.15s ease;
}

.mining-mode-btn:hover {
  border-color: var(--muted);
  background: var(--parchment);
}

.mining-mode-btn.active {
  background: var(--color-active);
  border-color: var(--color-active);
  color: var(--on-accent);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

/* CG-026d: Fishing Patience Card & Approach (direct forlæg the Mining Risk
   Card above — own classes so Mining's own styling stays untouched). */
.fishing-patience-card {
  padding: 8px 12px;
  background: #1b212a;
  border: 1px solid var(--wood-light, #39424f);
  border-radius: 6px;
}

.fishing-patience-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
}

.fishing-patience-title {
  font-size: 13px;
  font-weight: bold;
  color: var(--heading);
}

.fishing-patience-badge {
  font-size: 11px;
  font-weight: bold;
  padding: 2px 7px;
  border-radius: 4px;
  border: 1px solid;
}

.badge-quick {
  background: #14301c;
  border-color: #81c784;
  color: #8fd694;
}

.badge-patient {
  background: #1a2a3a;
  border-color: #64b5f6;
  color: #90caf9;
}

.fishing-patience-btn-group {
  display: flex;
  gap: 8px;
}

.fishing-mode-btn {
  flex: 1;
  padding: 6px 10px;
  font-size: 12px;
  font-weight: bold;
  cursor: pointer;
  border-radius: 4px;
  border: 1px solid var(--wood-light, #39424f);
  background: #1b212a;
  color: var(--text);
  transition: all 0.15s ease;
}

.fishing-mode-btn:hover {
  border-color: var(--muted);
  background: var(--parchment);
}

.fishing-mode-btn.active {
  background: var(--color-active);
  border-color: var(--color-active);
  color: var(--on-accent);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

.fishing-bait-controls {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px solid var(--wood-light, #39424f);
}

.fishing-bait-explanation {
  margin: 0 0 7px;
  line-height: 1.4;
}

.fishing-bait-mode-btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.fishing-bait-status {
  margin-top: 7px;
  color: var(--heading);
  font-size: 12px;
  line-height: 1.4;
  overflow-wrap: anywhere;
}

/* CG-026e: Woodcutting Yield Card & Approach (direct forlæg the Fishing
   Patience Card above — own classes so Fishing's own styling stays
   untouched). */
.woodcutting-yield-card {
  padding: 8px 12px;
  background: #1b212a;
  border: 1px solid var(--wood-light, #39424f);
  border-radius: 6px;
}

.woodcutting-yield-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
}

.woodcutting-yield-title {
  font-size: 13px;
  font-weight: bold;
  color: var(--heading);
}

.woodcutting-yield-badge {
  font-size: 11px;
  font-weight: bold;
  padding: 2px 7px;
  border-radius: 4px;
  border: 1px solid;
}

.badge-bundle {
  background: #3a2e14;
  border-color: #e5b873;
  color: #f5c876;
}

.woodcutting-yield-btn-group {
  display: flex;
  gap: 8px;
}

.woodcutting-mode-btn {
  flex: 1;
  padding: 6px 10px;
  font-size: 12px;
  font-weight: bold;
  cursor: pointer;
  border-radius: 4px;
  border: 1px solid var(--wood-light, #39424f);
  background: #1b212a;
  color: var(--text);
  transition: all 0.15s ease;
}

.woodcutting-mode-btn:hover {
  border-color: var(--muted);
  background: var(--parchment);
}

.woodcutting-mode-btn.active {
  background: var(--color-active);
  border-color: var(--color-active);
  color: var(--on-accent);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

/* CG-026f: Foraging Focus card (Herbs / Forager's Eye). */
.foraging-focus-card,
.skinning-focus-card {
  padding: 8px 12px;
  background: #1b212a;
  border: 1px solid var(--forest-light, #526745);
  border-radius: 6px;
}

.foraging-focus-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
}

.foraging-focus-title {
  font-size: 13px;
  font-weight: bold;
  color: var(--heading);
}

.foraging-focus-badge {
  font-size: 11px;
  font-weight: bold;
  padding: 2px 7px;
  border-radius: 4px;
  border: 1px solid;
}

.badge-herbs {
  background: #213326;
  border-color: #6d9b6a;
  color: #a8d7a0;
}

.badge-finds {
  background: #3a2e14;
  border-color: #e5b873;
  color: #f5c876;
}

.foraging-focus-explanation {
  margin: 2px 0 8px;
  line-height: 1.4;
}

.foraging-focus-btn-group {
  display: flex;
  gap: 8px;
}

.foraging-focus-mode-btn {
  flex: 1;
  padding: 6px 10px;
  font-size: 12px;
  font-weight: bold;
  cursor: pointer;
  border-radius: 4px;
  border: 1px solid var(--forest-light, #526745);
  background: #1b212a;
  color: var(--text);
  transition: all 0.15s ease;
}

.foraging-focus-mode-btn:hover {
  border-color: var(--muted);
  background: var(--parchment);
}

.foraging-focus-mode-btn.active {
  background: var(--color-active);
  border-color: var(--color-active);
  color: var(--on-accent);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

.skinning-focus-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
}

.skinning-focus-title {
  font-size: 13px;
  font-weight: bold;
  color: var(--heading);
}

.skinning-focus-badge {
  font-size: 11px;
  font-weight: bold;
  padding: 2px 7px;
  border-radius: 4px;
  border: 1px solid;
}

.skinning-focus-explanation {
  margin: 2px 0 8px;
  line-height: 1.4;
}

.skinning-focus-btn-group {
  display: flex;
  gap: 8px;
}

.skinning-focus-mode-btn {
  flex: 1;
  padding: 6px 10px;
  font-size: 12px;
  font-weight: bold;
  cursor: pointer;
  border-radius: 4px;
  border: 1px solid var(--forest-light, #526745);
  background: #1b212a;
  color: var(--text);
  transition: all 0.15s ease;
}

.skinning-focus-mode-btn:hover {
  border-color: var(--muted);
  background: var(--parchment);
}

.skinning-focus-mode-btn.active {
  background: var(--color-active);
  border-color: var(--color-active);
  color: var(--on-accent);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

/* DLS-001 (IDEA-0062): Desktop left sidebar UI */
.desktop-sidebar {
  display: none;
}

@media (min-width: 1024px) {
  body {
    padding-left: 304px;
    padding-top: 52px;
    justify-content: flex-start;
  }

  .game {
    max-width: 1100px;
    width: 100%;
    margin: 0;
  }

  /* Desktop sidebar provides persistent navigation; hide redundant top nav row & central grid */
  #panel-skills,
  .status-nav-row {
    display: none;
  }

  .status-bar-inner {
    max-width: 1100px;
  }

  .desktop-sidebar {
    display: flex;
    flex-direction: column;
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    width: 280px;
    padding: 52px 8px 16px;
    background: var(--parchment-dark);
    border-right: 2px solid var(--wood);
    box-shadow: 2px 0 6px rgba(0, 0, 0, 0.08);
    overflow-y: auto;
    z-index: 90;
    font-family: inherit;
    color: var(--text);
  }

  .sidebar-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 4px 8px 8px;
    border-bottom: 1px solid var(--wood);
    margin-bottom: 8px;
  }

  .sidebar-title {
    font-size: 18px;
    font-weight: bold;
    color: var(--heading);
    letter-spacing: 0.5px;
  }

  .sidebar-section-title {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--muted);
    font-weight: bold;
    padding: 6px 8px 4px;
  }

  .sidebar-nav {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 4px;
    margin-bottom: 12px;
  }

  .sidebar-nav-btn {
    font-family: inherit;
    font-size: 12px;
    font-weight: 500;
    padding: 6px 8px;
    border: 1px solid var(--wood);
    border-radius: 4px;
    background: var(--parchment);
    color: var(--text);
    cursor: pointer;
    text-align: center;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
    user-select: none;
  }

  .sidebar-nav-btn:hover {
    background: var(--wood);
    color: var(--text);
  }

  .sidebar-nav-btn.active {
    background: var(--surface-2);
    color: var(--color-active);
    border-color: var(--color-active);
    font-weight: bold;
  }

  .sidebar-skills {
    display: flex;
    flex-direction: column;
    gap: 8px;
  }

  .sidebar-category-group {
    --c: #7fae68;
    border: 1px solid var(--wood);
    border-radius: 4px;
    background: var(--parchment-dark);
    overflow: hidden;
  }

  .sidebar-category-group[data-category="production"] { --c: #d08a5e; }
  .sidebar-category-group[data-category="elite"] { --c: #9a8fd6; }
  .sidebar-category-group[data-category="township"] { --c: #c79a4a; }
  .sidebar-category-group[data-category="support"] { --c: #92a7bb; }
  .sidebar-category-group[data-category="combat"] { --c: #d4796a; }

  .sidebar-category-heading {
    font-size: 12px;
    font-weight: bold;
    color: var(--heading);
    background: rgba(255, 255, 255, 0.05);
    padding: 6px 8px;
    cursor: pointer;
    user-select: none;
  }

  .sidebar-category-heading:hover {
    background: rgba(255, 255, 255, 0.09);
  }

  .sidebar-category-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 4px;
  }

  .sidebar-skill-btn {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 5px 8px;
    border: 1px solid transparent;
    border-radius: 4px;
    background: transparent;
    color: var(--text);
    cursor: pointer;
    font-family: inherit;
    font-size: 13px;
    text-align: left;
    transition: background 0.12s, border-color 0.12s;
  }

  .sidebar-skill-btn:hover {
    background: rgba(255, 255, 255, 0.05);
    border-color: var(--wood);
  }

  .sidebar-skill-btn.active-view {
    background: var(--parchment);
    border-color: var(--muted);
    font-weight: bold;
  }

  .sidebar-skill-btn.running {
    box-shadow: inset 3px 0 0 var(--green);
  }

  .sidebar-skill-btn.locked {
    opacity: 0.55;
    cursor: not-allowed;
  }

  .sidebar-skill-icon {
    width: 18px;
    height: 18px;
    flex: 0 0 18px;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .sidebar-skill-icon svg {
    width: 18px;
    height: 18px;
  }

  .sidebar-skill-info {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-width: 0;
  }

  .sidebar-skill-name {
    font-size: 13px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .sidebar-skill-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 11px;
    color: var(--muted);
    gap: 4px;
  }

  .sidebar-skill-running-dot {
    display: inline-block;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--green);
    margin-right: 3px;
  }
}

/* ICON-001: transparent raster item assets preserve the existing text labels. */
.game-item-icon {
  display: inline-block;
  width: 30px;
  height: 30px;
  object-fit: contain;
  vertical-align: middle;
  flex: 0 0 auto;
}

.resource-name .game-item-icon,
.resource-btn .game-item-icon {
  width: 32px;
  height: 32px;
}

.inv-item .game-item-icon,
.market-name .game-item-icon {
  width: 28px;
  height: 28px;
}

.game-item-icon-fallback {
  display: inline-block;
  min-width: 1.1em;
  text-align: center;
  vertical-align: middle;
}

.game-ui-icon-slot {
  display: inline-flex;
  width: 1.1em;
  height: 1.1em;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  vertical-align: -0.2em;
}

.game-ui-icon-fallback {
  display: inline-flex;
  width: 100%;
  height: 100%;
  align-items: center;
  justify-content: center;
}

.game-ui-icon-slot.has-raster .game-ui-icon-fallback {
  display: none;
}

.game-ui-raster-icon {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.skill-tile-icon .game-ui-icon-slot,
.sidebar-skill-icon .game-ui-icon-slot {
  width: 100%;
  height: 100%;
  vertical-align: middle;
}

.horde-loadout-records {
  width: 100%;
  max-width: 100%;
  margin: 6px 0 10px;
}

.horde-loadout-records-table {
  width: 100%;
  max-width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
  font-size: 0.88em;
}

.horde-loadout-records-table caption {
  padding: 3px 5px;
  text-align: left;
  font-weight: 700;
}

.horde-loadout-records-table th,
.horde-loadout-records-table td {
  padding: 4px 5px;
  vertical-align: top;
  overflow-wrap: anywhere;
}

.horde-loadout-records-table th:first-child {
  width: 48%;
  text-align: left;
}

.horde-loadout-records-table th:nth-child(2),
.horde-loadout-records-table th:nth-child(3) {
  width: 26%;
}

.horde-loadout-records-table .horde-record-number {
  text-align: right;
}

.horde-loadout-records-table .horde-record-current {
  background-color: rgba(129, 197, 255, 0.14);
}

.horde-loadout-records-table .horde-record-current > th:first-child {
  box-shadow: inset 3px 0 0 #55a9f3;
}

.horde-records-empty {
  margin: 0;
}

/* CLOUD-005 mandatory account entry gate. */
body.auth-gated > :not(#cloud-login-gate):not(#email-verify-banner) { display: none !important; }
body.auth-gated { display: block !important; min-height: 100vh; padding: 0 !important; }
/* UX-059: Eldervale's own palette/panel language instead of hardcoded hex,
   so the first screen a player sees matches the rest of the UI. */
.cloud-login-gate { position: relative; isolation: isolate; box-sizing: border-box; width: 100%; min-height: 100vh; display: grid; grid-template-rows: auto 1fr; gap: 32px; place-items: center; padding: 24px; background: var(--surface-2); color: var(--text); }
/* ART-009: the gradient mask reveals the dark token beneath the image,
   acting as an overlay without painting anything when the image fails. */
.cloud-login-gate::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background-image: url("../assets/art/login/eldervale-dusk-1920.webp");
  background-size: cover; background-position: center;
  -webkit-mask-image: linear-gradient(180deg, #000a 0%, #0006 45%, #0009 100%);
  mask-image: linear-gradient(180deg, #000a 0%, #0006 45%, #0009 100%);
}
@media (max-width: 767px) {
  .cloud-login-gate::before { background-image: url("../assets/art/login/eldervale-dusk-960.webp"); }
}
.cloud-login-gate[hidden] { display: none !important; }
/* The title remains real text, readable and responsive above the login card. */
.cloud-login-brand {
  margin: clamp(8px, 3vh, 28px) 0 0; color: var(--gold-light);
  font-family: Georgia, "Times New Roman", serif;
  font-size: clamp(40px, 7vw, 76px); font-weight: 700; line-height: 1.15;
  letter-spacing: .1em; text-indent: .1em; text-align: center;
  text-shadow: 0 2px 4px #000, 0 4px 24px #000;
}
.cloud-login-card { width: min(100%, 460px); padding: 28px; border: 2px solid var(--wood); border-radius: var(--radius-lg); background: var(--parchment-dark); background-image: linear-gradient(180deg, var(--parchment) 0%, var(--parchment-dark) 140px); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); }
.cloud-login-card h1 { margin-top: 0; }
.cloud-login-card #cloud-login-title { color: var(--gold-light); }
.cloud-login-card label { display: block; margin: 14px 0 6px; color: var(--muted); }
.cloud-login-card input { box-sizing: border-box; width: 100%; padding: 10px; border: 1px solid var(--wood); border-radius: var(--radius-md); background: var(--surface-2); color: inherit; }
.cloud-login-card .controls { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
/* UX-073: one obvious primary action on the gate (green = go, never gold). */
.cloud-login-card .action.primary { min-height: 44px; padding-inline: 20px; border-color: var(--color-active); background: var(--color-active); color: var(--on-accent); font-weight: bold; }
.cloud-login-card .action.primary:hover:not(:disabled) { background: color-mix(in srgb, var(--color-active) 85%, #fff); }
.cloud-login-card [role="status"] { min-height: 1.5em; }
.cloud-login-card [role="status"]:empty { min-height: 0; margin: 0; }
.cloud-login-card[hidden] { display: none; }
/* UX-086: show/hide sits inside the password field; Caps Lock hint below it. */
.cloud-login-card .password-field { position: relative; }
.cloud-login-card .password-field input { padding-right: 64px; }
.cloud-login-card .password-toggle { position: absolute; top: 0; bottom: 0; right: 4px; z-index: 1; padding: 0 10px; border: 0; border-radius: var(--radius-md); background: none; color: var(--muted); font: inherit; font-size: 13px; cursor: pointer; }
.cloud-login-card .password-toggle:hover { color: var(--heading); }
.cloud-login-card .password-toggle:focus-visible { outline: 2px solid var(--color-active); outline-offset: 2px; }
.cloud-login-card .gate-hint { margin: 6px 0 0; font-size: 13px; color: var(--gold-light); }
.cloud-login-card .gate-hint[hidden] { display: none; }

.cloud-login-card .link-button { margin-top: 8px; padding: 0; border: 0; background: none; color: var(--muted); text-decoration: underline; cursor: pointer; font: inherit; }
@media (max-width: 520px) { .cloud-login-gate { padding: 12px; } .cloud-login-card { padding: 20px; } }

/* ICON-011: large current-enemy portrait in the encounter panel. */
.enemy-portrait { display: flex; justify-content: center; margin: 8px 0; }
.enemy-portrait .game-ui-icon-slot { width: min(192px, 40vw); height: min(192px, 40vw); font-size: min(96px, 20vw); vertical-align: middle; }
/* Dev-pass 2026-10-03: fast clicking must never select text; every button shows hover + pressed state. */
button, .page-tab-btn, .skill-tile, .resource-card, [role="button"] { user-select: none; -webkit-user-select: none; }
button:not(:disabled):hover { filter: brightness(1.12); }
button:not(:disabled):active { filter: brightness(0.9); transform: translateY(1px); }
button:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }

/* FEEDBACK-002: feedback dialog + status bar link */
.status-feedback-link { background: none; border: none; color: inherit; opacity: 0.75; font-size: 0.8em; text-decoration: underline; cursor: pointer; padding: 2px 4px; }
.status-feedback-link:hover, .status-feedback-link:focus-visible { opacity: 1; }
/* Phones keep the nav selects as the first Tab stops (UX-022); Settings has the button there. */
@media (max-width: 539px) { .status-feedback-link { display: none; } }
.feedback-dialog { width: min(480px, calc(100vw - 24px)); max-height: calc(100vh - 24px); box-sizing: border-box; background: var(--panel, #1f1f1f); color: inherit; border: 1px solid #555; border-radius: 8px; padding: 16px; }
.feedback-dialog::backdrop { background: rgba(0, 0, 0, 0.6); }
.feedback-dialog form { display: flex; flex-direction: column; gap: 6px; }
.feedback-dialog textarea { width: 100%; box-sizing: border-box; resize: vertical; font: inherit; }
.feedback-types { display: flex; flex-wrap: wrap; gap: 12px; border: none; padding: 0; margin: 0; }

/* CLOUD-009: discreet email-verification reminder; never blocks play. */
.email-verify-banner { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px; padding: 6px 12px; background: var(--surface-2); color: var(--text); font-size: 0.9em; border-bottom: 1px solid var(--border, rgba(127,127,127,0.3)); }
.email-verify-banner[hidden] { display: none !important; }
body.auth-gated > .email-verify-banner { position: fixed; top: 0; left: 0; right: 0; z-index: 10; }

/* UX-075: unspent-points count -- reward gold text, no red dot. */
.unspent-badge {
  margin-left: 6px;
  padding: 0 6px;
  border: 1px solid var(--gold-dark);
  border-radius: 8px;
  color: var(--gold);
  font-size: 11px;
  font-weight: bold;
  font-variant-numeric: tabular-nums;
}

.offline-footer { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 8px; }
/* UX-092: Continue stays on screen however long the homecoming is; on phones the
   talent nudge takes its own row above it. */
#offline-modal .offline-footer { position: sticky; bottom: -24px; margin: 0 -24px -24px; padding: 10px 24px 24px; background: var(--parchment); border-top: 1px solid var(--wood); }
@media (max-width: 539px) { .offline-talents-nudge { flex-basis: 100%; } }
.offline-talents-nudge { display: flex; align-items: center; gap: 8px; margin-right: auto; order: -1; font-size: 13px; color: var(--gold); }
.offline-talents-nudge[hidden] { display: none; }

/* DUNG-001: Marrow Crypt room list -- the sequence is the information. */
.dungeon-rooms {
  display: grid;
  gap: 6px;
  margin: 8px 0;
  padding-left: 22px;
  font-size: 13px;
  color: var(--text);
}
.dungeon-room-tag {
  font-size: 12px;
  color: var(--heading);
}
.dungeon-room-note {
  display: block;
  color: var(--text);
  opacity: 0.85;
}
.dungeon-room-cleared strong { text-decoration: line-through; text-decoration-thickness: 1px; }
.dungeon-room-current strong, .dungeon-room-paused strong { color: var(--heading); }
.dungeon-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
/* UX-098: one card per enemy on the field, HP bar above the art; wraps, never side-scrolls. */
#enemy-hp-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 8px; }
#enemy-hp-list .enemy-card { margin: 0; padding: 6px; background: var(--parchment-dark); border: 1px solid var(--wood); border-radius: 6px; min-width: 0; overflow-wrap: anywhere; }
#enemy-hp-list .enemy-card.attack-target { border-color: var(--color-active); border-left-width: 3px; padding-left: 6px; }
#enemy-hp-list .enemy-card-dead { opacity: .45; }
.enemy-card-art { display: flex; justify-content: center; margin: 6px 0; }
.enemy-card-art .game-ui-icon-slot { width: 96px; height: 96px; font-size: 56px; }
@media (max-width: 480px) {
  #enemy-hp-list { grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); }
  .enemy-card-art .game-ui-icon-slot { width: 64px; height: 64px; font-size: 40px; }
}

/* NEWS-001: quiet "What's new" link in the nav row, not a red badge (DESIGN.md). */
.news-badge {
  flex: none;
  padding: 4px 10px;
  border: 1px solid var(--gold-light);
  border-radius: 4px;
  background: none;
  color: var(--gold-light);
  font: inherit;
  font-size: 0.85em;
  cursor: pointer;
}
.news-badge:hover { color: var(--heading); }
.news-badge:focus-visible { outline: 2px solid var(--color-active); outline-offset: 2px; }
.news-section { scroll-margin-top: 120px; }
.news-section h4 { margin: 12px 0 6px; }
.news-entry { padding: 8px 0; border-bottom: 1px solid var(--wood); }
.news-entry h5 { margin: 0 0 4px; color: var(--heading); }
.news-entry time { margin-left: 6px; font-weight: normal; font-size: 0.85em; opacity: 0.7; }
.news-entry p { margin: 0; }
.news-discord:not([hidden]) { display: inline-block; }
.news-discord { margin-bottom: 6px; color: var(--gold-light); }
