/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

/* ─── me[tt] Custom Styles ───────────────────────────────────────────────── */
/* Built on top of Pico CSS dark theme */

:root {
  /* Dark charcoal + antique gold — inspired by the ancient world theme of Mega Empires */
  --mett-bg: #0a0b0b;
  --mett-surface: #131616;
  --mett-surface2: #1b2020;
  --mett-border: #283030;
  --mett-text: #e4e0d6;     /* soft warm off-white — easy on the eyes, ~14:1 on the bg */
  --mett-muted: #bfbaad;    /* secondary text, a step below --mett-text (~10:1) */
  --mett-accent: #c4933f;   /* antique gold */
  --mett-logo-bracket: var(--mett-accent); /* gold bracket in wordmark */
  --mett-danger: #cc3333;
  --mett-success: #2ea84a;
  --mett-warning: #cc8800;

  /* Pico overrides */
  --pico-background-color: var(--mett-bg);
  --pico-card-background-color: var(--mett-surface);
  --pico-border-color: var(--mett-border);

  /* Status-grid table column widths. Each `.status-grid .X` block applies
     `width: var(--col-X); min-width: var(--col-X)`. Per-breakpoint blocks
     below only override the variables, not the rules. */
  --col-mil: 2.2rem;
  --col-city: 2.2rem;
  --col-census-pop: 2.1rem;
  --col-mov: 2.2rem;
  --col-rank: 1.2rem;
  --col-adv-pts: 1.9rem;
  --col-ast-pts: 1.9rem;
  --col-total-vp: 2.4rem;
  /* One empire-box width shared by every status table so the player boxes line
     up across Census / Trade / A.S.T. order / Timeline / Leaderboard. Bumped at
     4K below. */
  --empire-box-w: 7.5rem;

  /* Border-radius scale — tighter than browser defaults for a
     dashboard look. Use these vars instead of literal values when
     editing existing rules; they make a future redesign one-edit. */
  --radius-tight: 0.125rem;   /* chips, table inputs */
  --radius-soft: 0.1875rem;   /* buttons, icon toggles */
  --radius-card: 0.25rem;     /* sections, cards */
  --radius-pill: 624.9375rem; /* fully-rounded badges */
  --radius-panel: 0.75rem;    /* panels / sections on every page */
  --radius-row: 0.4rem;       /* ends of a striped table row */
  --mett-stripe: rgba(255, 255, 255, 0.05); /* alternating table rows */

  /* AST progress strip on the civ page. Phone breakpoint below
     overrides these. Declared up here (not next to .ast-progress-grid)
     so a later unconditional :root block can't accidentally beat the
     media-query override on source order. */
  --ast-node-size: 2rem;
  --ast-node-gap: 0.1875rem;
}

/* App typeface: the platform's UI font (crisp, hinted, familiar). One token
   for every page; Pico's own font var points at it so form controls match.
   A self-hosted condensed web font was tried 2026-10-25 and dropped — it read
   soft/blurry on desktop monitors. */
:root {
  --mett-font: system-ui, -apple-system, 'Segoe UI', sans-serif;
  --pico-font-family: var(--mett-font);
  --pico-font-family-sans-serif: var(--mett-font);
  /* Pico's own text colours (body, headings, form fields) follow our token,
     so no page shows Pico's brighter near-white. */
  --pico-color: var(--mett-text);
  --pico-h1-color: var(--mett-text);
  --pico-h2-color: var(--mett-text);
  --pico-h3-color: var(--mett-text);
  --pico-h4-color: var(--mett-text);
  --pico-h5-color: var(--mett-text);
  --pico-h6-color: var(--mett-text);
  --pico-form-element-color: var(--mett-text);
}

body {
  background: var(--mett-bg);
  color: var(--mett-text);
  font-family: var(--mett-font);
}

/* ─── Site header / logo ──────────────────────────────────────────────────── */

.site-header {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.45rem 0.75rem 0.3rem;
}

/* WebSocket offline indicator — rendered by ws-client.js when the
   connection has been down for more than ~1.5 s (instant flicker doesn't
   show the pill). Pinned bottom-centre so it's visible on every page,
   above the version footer. */
.mett-offline-pill {
  position: fixed;
  left: 50%;
  bottom: 0.5rem;
  transform: translateX(-50%);
  padding: 0.3rem 0.7rem;
  border-radius: var(--radius-soft);
  background: rgba(204, 51, 51, 0.92);
  color: #fff;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
  z-index: 100;
  pointer-events: none;
  user-select: none;
  box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.35);
}
.mett-offline-pill[hidden] { display: none; }

/* Tiny build-version stamp inline in the header, immediately to the left of
   the admin gear. Frees the bottom-left corner so the status grid can reclaim
   the vertical space the fixed footer used to reserve. */
.mett-version {
  margin-left: auto;
  padding: 0.1rem 0.4rem;
  border-radius: 0.25rem;
  background: rgba(255, 255, 255, 0.05);
  font-size: 0.6rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--mett-muted);
  opacity: 0.6;
  user-select: none;
  white-space: nowrap;
  flex-shrink: 0;
}

.mett-wordmark {
  font-size: 1.05rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  color: var(--mett-text);
  text-decoration: none;
  flex-shrink: 0;
}

.mw-bracket {
  color: var(--mett-logo-bracket);
}

.mett-tagline {
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  color: var(--mett-muted);
  white-space: nowrap;
}

.admin-gear {
  font-size: 1rem;
  color: var(--mett-muted);
  text-decoration: none;
  padding: 0.1rem 0.25rem;
  flex-shrink: 0;
}

.admin-gear:hover { color: var(--mett-text); }

/* ─── Header ──────────────────────────────────────────────────────────────── */

.mett-header {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin: 0.25rem 0 0.3rem;
}

/* ─── Phase strip ─────────────────────────────────────────────────────────── */

.phase-strip {
  display: flex;
  align-items: center;
  gap: 2rem;
  flex-wrap: wrap;
}

.phase-info {
  color: var(--mett-muted);
  font-size: 0.8rem;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  white-space: nowrap;
}

.phase-steps {
  display: flex;
  align-items: center;
  gap: 0;
  list-style: none;
  margin: 0;
  padding: 0;
}

.phase-step {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.2rem 0.55rem;
  color: var(--mett-muted);
  opacity: 0.35;
  transition: opacity 0.2s;
}

.phase-step.phase-done {
  opacity: 0.4;
}

.phase-step.phase-active {
  opacity: 1;
  color: #15130f;
  background: var(--mett-accent);
  border-radius: var(--radius-pill);
}

.phase-step.phase-future {
  opacity: 0.3;
}

.phase-sep {
  list-style: none;
  font-size: 0.65rem;
  color: var(--mett-muted);
  opacity: 0.3;
  padding: 0 0.1rem;
  user-select: none;
}

/* ─── Badges ──────────────────────────────────────────────────────────────── */

.mode-badge,
.revealed-badge,
.final-round-badge {
  display: inline-block;
  padding: 0.15rem 0.5rem;
  border-radius: 624.9375rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.mode-badge {
  background: var(--mett-accent);
  color: #fff;
}

.final-round-badge {
  background: var(--mett-danger);
  color: #fff;
  animation: pulse-badge 1.5s ease-in-out infinite;
}

@keyframes pulse-badge {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.6; }
}

/* Submit-success flash — applied via window.mettFlash() in api.js after a
   successful POST so the player gets visual confirmation their value was
   accepted. The element gets a soft green outer glow that fades over ~1.5 s. */
.mett-flash {
  animation: mett-flash-anim 1.4s ease-out;
  border-radius: var(--radius-card);
}
@keyframes mett-flash-anim {
  0%   { box-shadow: 0 0 0 2px rgba(46, 168, 74, 0); }
  15%  { box-shadow: 0 0 0 3px rgba(46, 168, 74, 0.65); }
  100% { box-shadow: 0 0 0 2px rgba(46, 168, 74, 0); }
}

.revealed-badge {
  background: var(--mett-success);
  color: #fff;
}

/* ─── Civilization badges ─────────────────────────────────────────────────── */

.civ-badge {
  display: inline-block;
  padding: 0.1875rem 0.5rem;
  border-radius: 0.1875rem;
  font-weight: 700;
  font-size: 0.875rem;
  white-space: nowrap;
  border: 0.0625rem solid rgba(0,0,0,0.15);
}

.civ-badge-with-num {
  /* Calm badge: neutral text, colour only on the .civ-num inside. */
  display: inline-flex;
  align-items: center;
  gap: 0;
  padding-left: 0;
  width: 7.1875rem;
  box-sizing: border-box;
  background: transparent;
  color: var(--mett-text);
  border: none;
}
.civ-badge-label { min-width: 0; }

/* Census table column sizing */
.census-table { table-layout: fixed; width: 100%; }

.lb-table td, .census-table td { font-weight: 700; }

.census-table .city-col {
  width: 2.125rem;
  text-align: center;
  font-size: 0.85rem;
  white-space: nowrap;
}
.census-table .mil-col {
  width: 2.125rem;
  text-align: center;
  padding-left: 0.25rem;
  padding-right: 0.25rem;
  white-space: nowrap;
}
.census-table thead .mil-col { color: #cc4444; }
.census-table .mov-col {
  width: 2.125rem;
  text-align: center;
  white-space: nowrap;
}
.census-table thead .mov-col { color: #4a8a5a; }
.mov-check { color: #4caf6a; font-weight: 700; }
.census-pop { width: 3.25rem; }

/* Red military dot */
.mil-dot {
  display: inline-block;
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  background: var(--mett-danger);
  box-shadow: 0 0 0.25rem var(--mett-danger);
  vertical-align: middle;
}

.census-pop { text-align: right; font-size: 1rem; white-space: nowrap; }

.submitted-hidden { color: #4a8a5a; font-size: 0.85rem; }   /* muted green ✓ */
.not-submitted    { color: var(--mett-warning); font-size: 0.85rem; }
.cell-na          { color: var(--mett-muted); font-weight: 400; }  /* muted — for data not relevant this phase */

/* Military icon — red dot in census table, ⚔ on header/buttons */

/* Military & Wonder toggles on civ page */
.mil-won-row { display: flex; flex-direction: column; gap: 0.5rem; }
.mil-toggle-civ, .won-toggle-civ, .spc-toggle-civ {
  width: 100%;
  padding: 0.5rem 1rem;
  border-radius: 0.25rem;
  border: 0.0625rem solid var(--mett-border);
  font-size: 0.9rem;
  cursor: pointer;
  text-align: center;
}
.mil-toggle-civ.mil-on  { background: #3a2020; border-color: #cc5555; color: #ff8888; }
.mil-toggle-civ.mil-off { background: var(--mett-surface2); color: var(--mett-muted); }
.won-toggle-civ.won-on  { background: #2a2a10; border-color: #aaaa22; color: #dddd44; }
.won-toggle-civ.won-off { background: var(--mett-surface2); color: var(--mett-muted); }
.spc-toggle-civ.spc-on  { background: #1a1a30; border-color: #5555cc; color: #8888ff; }
.spc-toggle-civ.spc-off { background: var(--mett-surface2); color: var(--mett-muted); }

/* "Units moved" readiness toggle on the census section of the civ page */
.mov-row { display: flex; flex-direction: column; gap: 0.25rem; margin-top: 0.75rem; }
.mov-toggle-civ {
  width: 100%;
  padding: 0.6rem 1rem;
  border-radius: 0.25rem;
  border: 0.0625rem solid var(--mett-border);
  font-size: 0.95rem;
  cursor: pointer;
  text-align: center;
}
.mov-toggle-civ.mov-on  { background: #123020; border-color: #3caa66; color: #7fe0a0; }
.mov-toggle-civ.mov-off { background: var(--mett-surface2); color: var(--mett-muted); }
.mov-toggle-civ:disabled { opacity: 0.5; cursor: not-allowed; }
.mov-hint { color: var(--mett-muted); font-size: 0.8rem; }

.total-vp { text-align: right; }

/* Leaderboard ties */
.rank-tie { color: var(--mett-warning); font-weight: 900; font-size: 1rem; }
.lb-group-start td { border-top: 0.125rem solid var(--mett-border); }

/* ─── Tables ──────────────────────────────────────────────────────────────── */

.mett-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}

.mett-table th {
  /* No header band and no row lines (Pico draws both by default): calm
     tables separate rows with stripes instead — see Calm components. */
  background: transparent;
  border-bottom: none;
  color: var(--mett-muted);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0.5rem 0.6rem;
  white-space: nowrap;
}

.mett-table td {
  background: transparent;
  border-bottom: none;
  padding: 0.3rem 0.55rem;
  vertical-align: middle;
  height: 2rem;  /* fixed row height so tables align across columns */
  overflow: hidden;
  white-space: nowrap;
}

.rank { color: var(--mett-muted); font-size: 0.85rem; width: 2rem; text-align: center; }

/* Player name in go-empire — visible by default, block on mobile for card layout */
.go-player-name { display: none; font-size: 0.78rem; color: var(--mett-muted); margin-top: 0.1rem; }
.adv-pts { text-align: right; }
.ast-pts { text-align: right; }

.table-hint {
  margin: 0;
  font-size: 0.8rem;
  color: var(--mett-muted);
}

.census-hint {
  display: block;
  font-size: 0.75rem;
  opacity: 0.5;
  margin-top: 0.25rem;
}

.table-scroll { overflow-x: auto; }

/* ─── S3 status page layout (4-column, TV-optimised) ─────────────────────── */

.status-grid {
  display: grid;
  gap: 0.5rem;
  align-items: stretch;
  min-width: 0;
}

/* Mobile: single-column, natural height, scrollable */
@media (max-width: 43.75em) {
  .status-grid {
    grid-template-columns: 1fr;
  }
}

/* Desktop/TV: 5-column, viewport-locked, no scroll */
@media (min-width: 43.76em) {
  .status-grid {
    /* Order: census | trade | A.S.T. Progress (ranking) | AST board | leaderboard.
       Every table except the AST board is content-sized (auto); the board is the
       sole flexible column (1fr) so it soaks up all the spare width — the place
       extra real estate is most useful (wider, more readable AST cells). */
    grid-template-columns: auto auto auto 1fr auto;
    /* Fill the viewport vertically — cards stretch to match each other
       (align-items: stretch), but tables stay natural-sized. 4.7rem
       accounts for site-header + status-header + main padding ≈ 95px. */
    min-height: calc(100vh - 4.7rem);
    max-height: calc(100vh - 4.7rem);
    overflow: hidden;
  }
  /* Anchor body so residual rounding doesn't trigger a scrollbar. */
  html:has(.status-grid),
  body:has(.status-grid) { overflow: hidden; height: 100%; }
}
.status-grid > * { min-width: 0; }
.status-grid .mett-table { width: 100%; }

/* Compact phase strip on status page */
.status-header { margin: 0 0 0.2rem; }
.status-header .phase-info { font-size: 1.15rem; font-weight: 700; color: var(--mett-text); }
.status-header .phase-step { font-size: 0.9rem; padding: 0.1rem 0.65rem; }
/* Full-screen toggle (status page) — shown only where the browser supports it
   (main.js sets html.fs-supported). Absolutely placed at the right end of the
   status header so it never adds height to the tightly budgeted TV chrome. */
.status-header { position: relative; }
.fullscreen-toggle {
  display: none;
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  width: auto;
  margin: 0;
  padding: 0.1rem 0.4rem;
  background: transparent;
  border: none;
  box-shadow: none;
  color: var(--mett-muted);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}
.fs-supported .fullscreen-toggle { display: inline-block; }
.fullscreen-toggle:hover { color: var(--mett-text); }

/* Trim Pico's vertical padding on the home page so 18 empires + the AST
   legend fit a 1080p viewport without scrolling. Other pages keep Pico's
   default vertical rhythm (this :has rule only matches when status-grid
   is present, which is the main display). */
main.container-fluid:has(.status-grid) { padding-block: 0.25rem; }

/* Compact table density — tuned so 18 empires fit in a 1080p viewport
   without scrolling. Row height computes to ~36 px at Pico's fluid root. */
.status-grid .table-section   { padding: 0.25rem 0.4rem; display: flex; flex-direction: column; }
.status-grid .table-section h3 { font-size: 0.65rem; margin-bottom: 0.15rem; line-height: 1.15; min-height: 2.3em; }
/* The A.S.T. Progress Order title is long; cap it to the empire-box width so it
   wraps to two lines and the card hugs the boxes (no dead space on the right).
   The uniform 2-line h3 min-height above keeps every table's first row aligned. */
.status-grid .ast-order-section h3 { max-width: var(--empire-box-w); }
.status-grid .table-hint       { font-size: 0.58rem; margin-top: auto; margin-bottom: 0; padding-top: 0.15rem; }
.status-grid .ab-legend        { margin-top: auto; font-size: 0.46rem; line-height: 1.2; padding: 0.1rem 0 0; gap: 0.05rem 0.6rem; }
.status-grid .ab-legend li     { gap: 0.2rem; }
.status-grid .ab-legend-dot    { width: 0.5rem; height: 0.5rem; }
/* Row height + font scale with viewport HEIGHT (not width) so the table
   uses available vertical space without overflowing — works regardless of
   aspect ratio (1920×1200, 3440×1440 ultrawide, 4K, etc). Floors are
   conservative so 1366×768 still fits 18 rows + chrome inside 100vh;
   ceilings cap growth on very tall displays. */
.status-grid .mett-table       { font-size: clamp(0.62rem, 1.1vh, 1.3rem); border-collapse: separate; border-spacing: 0 clamp(2px, 0.3vh, 5px); line-height: 1.1; }
.status-grid .mett-table th    { padding: clamp(0.08rem, 0.25vh, 0.22rem) 0.4rem; }
.status-grid .mett-table td    { padding: clamp(0.05rem, 0.18vh, 0.18rem) 0.4rem; font-size: inherit; }
/* Match the .ab-table tr line-height so the chip cell content
   (civ-num span + name) computes the same height in every status table.
   Without this, the .mett-table tr inherits a larger pico line-height,
   which in turn makes the civ-num span taller in census/ast.progress
   (where civ-num is visible) than in lb/ast.order (where it's hidden). */
.status-grid .mett-table tr,
.status-ast tr { line-height: 1.1; }

/* Fixed layout with explicit width (= sum of column widths) so empire column respects stated 5.5rem.
   table-layout:fixed + width:auto causes Chrome to use fill-available, ignoring max-width on cells. */
/* width = empire-cell (7.5) + mil + city + census-pop + mov column widths.
   Sum of the column vars at default break = 7.5 + 2.2 + 2.2 + 2.1 + 2.2 = 16.2rem
   so the empire chip column doesn't get any leftover width and the chip
   stays at its declared 7.5rem like every other table. */
.status-grid .census-table { table-layout: fixed; width: calc(7.5rem + var(--col-mil) + var(--col-city) + var(--col-census-pop) + var(--col-mov)); }
.status-grid .census-table thead th:first-child { width: 7.5rem; }

/* Narrow columns — widths come from --col-* on :root, overridden per breakpoint. */
.status-grid .mil-col    { width: var(--col-mil);        min-width: var(--col-mil); }
.status-grid .city-col   { width: var(--col-city);       min-width: var(--col-city); }
.status-grid .census-pop { width: var(--col-census-pop); min-width: var(--col-census-pop); }
.status-grid .mov-col    { width: var(--col-mov);        min-width: var(--col-mov); }
.status-grid .rank       { width: var(--col-rank);       min-width: var(--col-rank); }
.status-grid .adv-pts    { width: var(--col-adv-pts);    min-width: var(--col-adv-pts); }
.status-grid .ast-pts    { width: var(--col-ast-pts);    min-width: var(--col-ast-pts); }
.status-grid .total-vp   { width: var(--col-total-vp);   min-width: var(--col-total-vp); }

/* Full-width colored empire cells — fixed width so all tables align.
   Font scales with viewport height to match the row heights above.
   A subtle inset outline gives the chip definition against any card
   background regardless of its own colour (contrast item 11.4 — empire
   colours stay as identity). The outer ring shadow was tested but
   removed: combined with the AST.PROGRESS row tints (regress/advance)
   it read as a "border" and pulled focus away from the row tint itself. */
.empire-cell {
  font-weight: 600;
  overflow: hidden;
  width: 7.5rem;
  min-width: 7.5rem;
  max-width: 7.5rem;
  border-radius: var(--radius-tight);
  /* Neutral cell — the empire colour lives only on the .civ-num badge. */
  color: var(--mett-text);
  line-height: 1.15;
  vertical-align: middle;
}

/* Line 1: seat-number badge + civ name (single line, ellipsis if long). */
.empire-civ {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Line 2: the player's display name — dimmer and smaller, present in every
   status table so the name is visible in-cell without a dedicated column. */
.empire-player-name {
  display: block;
  font-size: clamp(0.55rem, 0.85vh, 1.05rem);
  font-weight: 400;
  opacity: 0.8;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.1;
}

.civ-num {
  /* Empire number badge — the one place an empire's colour appears, on every
     page (status tables, admin badges, player hero). Colours come from
     --civ / --civ-fg set inline on an ancestor; size follows the text. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: middle;
  background: var(--civ, var(--mett-surface2));
  color: var(--civ-fg, var(--mett-text));
  font-size: 0.8em;
  font-weight: 700;
  line-height: 1;
  min-width: 1.6em;
  text-align: center;
  border-radius: var(--radius-soft);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.25);
  padding: 0.12em 0.15rem;
  margin-right: 0.3rem;
}

/* Trade group separator — pseudo-element centered in the 4px border-spacing gap.
   border-top alone lands at the bottom of the gap; top:-2px centers a 1px line in it. */
.status-grid .trade-table .trade-group-start td {
  border-top: none;
  overflow: visible;
  position: relative;
}
.status-grid .trade-table .trade-group-start td::before {
  content: '';
  position: absolute;
  top: -2px;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--mett-accent);
  pointer-events: none;
}

/* Leaderboard score-group separator: same gap-centred line as the trade
   table, so it adds no height and rows stay aligned with the other tables. */
.status-grid .lb-table .lb-group-start td {
  border-top: none;
  overflow: visible;
  position: relative;
}
.status-grid .lb-table .lb-group-start td::before {
  content: '';
  position: absolute;
  top: -2px;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--mett-border);
  pointer-events: none;
}

/* West/East in one trade table: a narrow vertical label per region (rowspan)
   and a divider in the row gap where East starts — no heading row, so the
   trade rows stay aligned with every other status table. */
.trade-table { --trade-region-w: 1.3rem; }
.trade-table:not(.trade-two-regions) { --trade-region-w: 0rem; }
.trade-region-col { width: var(--trade-region-w); }
.status-grid .trade-table.mett-table tbody tr td.trade-region,
.status-grid .trade-table.mett-table th.trade-region {
  width: var(--trade-region-w);
  padding: 0;
  background: transparent;
  border-radius: 0;
}
.status-grid .trade-table td.trade-region span {
  display: inline-block;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-size: clamp(0.5rem, 0.85vh, 1rem);
  font-weight: 700;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--mett-muted);
}
.status-grid .trade-table td.trade-region { text-align: center; vertical-align: middle; }
/* With the label column first, the empire cell starts the striped row. */
.status-grid .trade-two-regions td.empire-cell { border-radius: 0.4rem 0 0 0.4rem; }
.status-grid .trade-table .trade-region-start td {
  overflow: visible;
  position: relative;
}
.status-grid .trade-table .trade-region-start td::before {
  content: '';
  position: absolute;
  top: -2px;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--mett-muted);
  opacity: 0.6;
  pointer-events: none;
}

/* AST order table — single empire-cell column, group separators between levels */
.ast-order-table { table-layout: fixed; }
/* Single empire column — pin the whole table to the shared box width so it
   can't stretch to fill its grid cell (the freed space goes to the timeline). */
.status-grid .ast-order-table { width: var(--empire-box-w); }
.ast-order-table td { width: var(--empire-box-w); min-width: var(--empire-box-w); }
.ast-order-table .ast-order-group-start td {
  border-top: none;
  overflow: visible;
  position: relative;
}
.ast-order-table .ast-order-group-start td::before {
  content: '';
  position: absolute;
  top: -2px;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--mett-border);
  pointer-events: none;
}

/* Leaderboard: fixed layout pins every column to a fixed width — empire to the
   shared box width (so it lines up with every other table), rank and the three
   number columns to their vars. Its width is set from those columns in the
   board token block (never from content), so the timeline (not the
   leaderboard) absorbs the spare horizontal space. */
.status-grid .lb-table { table-layout: fixed; width: max-content; }
.lb-rank-col   { width: var(--col-rank); }
.lb-empire-col { width: var(--empire-box-w); }
.lb-adv-col    { width: var(--col-adv-pts); }
.lb-ast-col    { width: var(--col-ast-pts); }
.lb-total-col  { width: var(--col-total-vp); }

/* AST board compact sizing for s3 — !important beats the wide media-query rule.
   Row pitch matches other status-grid tables (height + border-spacing) so all
   18 empires line up across columns within a 1080p viewport. */
.ab-table.status-ast {
  /* Fill the AST grid cell so the fixed layout can split the data columns
     evenly; auto-width let the table content-size and then compress unevenly. */
  width: 100% !important;
  font-size: 0.65rem !important;
  border-collapse: separate !important;
  /* Match the other status-grid tables so AST.PROGRESS data rows align
     vertically with leaderboard / census / ast-order rows. */
  border-spacing: 0 clamp(2px, 0.3vh, 5px) !important;
}
.status-ast thead th { font-size: clamp(0.55rem, 0.85vh, 1rem); padding: clamp(0.08rem, 0.25vh, 0.22rem) 0.4rem; }
/* Equalised across all status-grid tables so the first data row aligns
   with the leaderboard / census / ast-order rows next to it. The mett-table
   tr inherits a larger font-size than the ab-table tr (different parent
   font-size cascades), so a unit-less line-height on tr would compute to
   different pixel heights per table. line-height: 1 caps that, then the
   th's own padding sets the actual thead height — identical across all
   four tables. */
.status-grid thead tr,
.status-ast thead tr { line-height: 1; height: 1.6rem; }
/* Inside the status grid, the AST.PROGRESS chip lives in an .ab-table
   cell which by default has a 1 px faint-white border + a 2 px dark
   border-right (for horizontal-scroll separation in the standalone
   AST board view). Both treatments leave the chip looking different
   from the other tables' chips (empire colour visible OUTSIDE the
   inset border ring). Strip them so all five tables render chips
   identically. */
/* The .ab-table td rule (line ~1513) zeroes out td padding to give
   AST.PROGRESS its tight grid look. For the chip column inside the
   status grid we want the same padding as the leaderboard / census td
   (the clamp formula from .status-grid .mett-table td), so chip rows
   compute the same height — and align horizontally — at every viewport. */
.status-ast .ab-civ-label.empire-cell {
  border: none !important;
  padding: clamp(0.05rem, 0.18vh, 0.18rem) 0.4rem;
}
.status-ast .ab-civ-label { width: 7.5rem; min-width: 7.5rem; }
.status-ast td.empire-cell { font-size: clamp(0.62rem, 1.2vh, 1.4rem); }
/* colgroup pins every data column to one width (table-layout:fixed honours the
   <col> over the colspan'd band headers) so all A.S.T. cells are equal width. */
.status-ast .ab-label-col { width: 7.5rem; }
/* No width on the data cols: table-layout:fixed splits the leftover table
   width equally across all of them, so every A.S.T. cell is exactly equal. */
.status-ast .ab-data-col  { width: auto; }
.status-ast .ab-cell      { width: clamp(1.9rem, 2.4vw, 3rem); height: clamp(1.1rem, 3.3vh, 3.6rem); }
/* Phone: the desktop board fills its grid cell and equal-splits the columns,
   but a ~390px phone cell would crush the 17 cells to ~14px. On mobile let the
   board content-size to readable fixed-width cells and scroll horizontally
   inside its .ab-scroll card instead. Placed after the base rules so it wins
   the cascade on mobile (same specificity, later source order). */
@media (max-width: 43.75em) {
  .ab-table.status-ast { width: max-content !important; }
  .status-ast .ab-data-col { width: clamp(1.9rem, 2.4vw, 3rem); }
}
.status-ast .ab-level-num { width: clamp(1.9rem, 2.4vw, 3rem); font-size: clamp(0.45rem, 0.78vh, 0.95rem) !important; }
.status-ast .ab-round-num { width: clamp(1.9rem, 2.4vw, 3rem); font-size: clamp(0.45rem, 0.78vh, 0.95rem) !important; }
.status-ast .ab-name      { font-size: clamp(0.55rem, 0.85vh, 1rem) !important; }
.status-ast .ab-magnet {
  width: 1.1rem;
  /* Never wider than the (equal) cell; aspect-ratio drives height off the
     (possibly capped) width so the chip stays circular and can't overflow.
     height:auto is required to beat the global `.ab-magnet { height }` rule,
     which would otherwise pin an explicit height and turn the chip into an oval. */
  max-width: 100%;
  height: auto;
  aspect-ratio: 1;
  box-sizing: border-box;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.5rem;
  font-weight: 700;
  vertical-align: middle;
}
/* Calamity regression marker — a red ring + glow around the empire's token so
   the GM can confirm the correct empire was regressed. Ring drawn with
   box-shadow (not border) so it never changes the chip's size or circularity.
   Cleared on round advance (players.regressed reset). */
.status-ast .ab-magnet-regressed {
  box-shadow: 0 0 0 0.16rem #e01b1b, 0 0 0.5rem 0.1rem rgba(224, 27, 27, 0.85);
  outline: 0.09rem solid #2a0000;  /* thin dark separation so the red ring reads on any empire colour */
  outline-offset: -0.02rem;
}

/* AST status hints on the AST.PROGRESS row (item 11.3): surface
   "will advance" and "will regress" so the GM and table see what's
   about to happen at the next AST run.
   Two complementary signals per state:
   - A faint coloured tint behind the row (red for regress, gold for
     advance) — the AST cells alongside the chip pick up the tint;
     the chip itself sits on top with its own empire colour, so the
     chip's visual rhythm with neighbouring rows stays intact.
   - A glyph appended after the empire name inside the chip
     (← for regress, → for advance), travelling with the chip
     without changing its dimensions. */
/* No row tint, and no arrow inside the empire box — the advance/regress
   indicator lives in the start column (.ab-move), coloured to match admin. */
.ab-move {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  line-height: 1;
  font-size: clamp(0.8rem, 1.8vh, 2rem);
}
.ab-move-advance { color: var(--mett-success); }
.ab-move-stay    { color: var(--mett-warning); }
.ab-move-regress { color: var(--mett-danger); }

/* ─── S3 phone layout — single column, normal density ────────────────────── */

@media (max-width: 43.75em) {
  .status-grid {
    grid-template-columns: 1fr;
    gap: 1rem;
  }

  /* Undo TV-compact sizing */
  .status-header { margin: 0.5rem 0 0.75rem; }

  .status-grid .table-section   { padding: 0.6rem 0.8rem; }
  .status-grid .table-section h3 { font-size: 0.9rem; margin-bottom: 0.5rem; }
  .status-grid .table-hint       { font-size: 0.78rem; margin-top: 0.35rem; }
  .status-grid .mett-table       { font-size: 0.84rem; }
  .status-grid .mett-table th    { font-size: 0.72rem; padding: 0.35rem 0.5rem; }
  .status-grid .mett-table td    { height: 2rem; padding: 0.15rem 0.5rem; }

  /* Census: fixed layout pinned to the card width. Percentage data columns are
     font-independent, so the table can never content-size past the card edge and
     clip the (rightmost) MOV column — even at large OS text sizes. The empire
     column (auto) takes the remainder and ellipsises the name. */
  .status-grid .census-table { table-layout: fixed; width: 100%; }
  .status-grid .census-table thead th:first-child { width: auto; }
  .status-grid .mil-col    { width: 15%; min-width: 0; }
  .status-grid .city-col   { width: 15%; min-width: 0; }
  .status-grid .census-pop { width: 16%; min-width: 0; }
  .status-grid .mov-col    { width: 15%; min-width: 0; }
  :root {
    --col-rank: 1.8rem;
    --col-adv-pts: 2.5rem;
    --col-ast-pts: 2.5rem;
    --col-total-vp: 3rem;
  }

  .census-table th.mil-col,
  .census-table th.city-col,
  .census-table th.census-pop,
  .census-table th.mov-col { padding-left: 0.25rem; padding-right: 0.25rem; }

  /* Empire cells: unconstrained, fill remaining space */
  .empire-cell { width: auto; min-width: 5rem; max-width: none; font-size: 0.84rem; }

  /* Trade table: full-width, empire col % so it stays proportional at any font size */
  .status-grid .trade-table      { table-layout: fixed; width: 100%; }
  .status-grid .trade-empire-col { width: 40%; }
  .status-grid .trade-chip-col   { width: auto; }
  /* Chips in px — must not scale with user font size; 9×16+8×2+10 = 170px needed */
  .status-grid .trade-chip       { width: 16px; height: 24px; font-size: 10px; }
  .status-grid .trade-chips      { gap: 2px; }
  .status-grid .trade-table td   { padding-left: 5px; padding-right: 5px; }
}

/* ─── S3 WQHD layout — 2560px CSS px (native 2560p, or 4K @ 1.5×) ─────────── */

@media (min-width: 160rem) {
  .status-grid .table-section   { padding: 0.45rem 0.55rem; }
  .status-grid .table-section h3 { font-size: 0.82rem; margin-bottom: 0.35rem; }
  .status-grid .table-hint       { font-size: 0.72rem; }
  .status-grid .ab-legend        { font-size: 0.62rem; gap: 0.15rem; }

  /* font/row sizing now handled by viewport-height-relative clamp() at the
     base level — see .status-grid .mett-table above. WQHD-specific tweaks
     stay below for column proportions and chip widths. */

  /* Census: fixed table (empire box + mil + city + pop + mov columns) */
  .status-grid .census-table { width: calc(var(--empire-box-w) + var(--col-mil) + var(--col-city) + var(--col-census-pop) + var(--col-mov)); }
  .status-grid .census-table thead th:first-child { width: var(--empire-box-w); }
  :root {
    --col-mil: 2.2rem;
    --col-mov: 2.2rem;
    /* WQHD has width to spare in the timeline; wider boxes keep long player
       names whole at the larger board type. */
    --empire-box-w: 8.5rem;
  }

  .empire-cell { width: var(--empire-box-w); min-width: var(--empire-box-w); max-width: var(--empire-box-w); }
  .ast-order-table td { width: var(--empire-box-w); min-width: var(--empire-box-w); }

  /* Trade separator: re-center 1px line in the now-5px gap */
  .status-grid .trade-table .trade-group-start td::before { top: -2.5px; }

  /* AST board: row heights + fonts handled by viewport-height clamp() above. */
  .status-ast .ab-civ-label { width: var(--empire-box-w); min-width: var(--empire-box-w); }
  .status-ast .ab-label-col { width: var(--empire-box-w); }
  .status-ast .ab-magnet    { width: 1.5rem; font-size: clamp(0.62rem, 1vh, 1.05rem); }
}

/* ─── S3 4K layout — 3072px CSS px (4K @ 1.25×) ───────────────────────────── */

@media (min-width: 192rem) {
  .status-grid {
    /* census | trade | A.S.T. Progress (ranking) | AST board | leaderboard —
       board is the sole flexible column so it takes the spare 4K width. */
    grid-template-columns: auto auto auto 1fr auto;
    gap: 0.75rem;
  }

  .status-grid .table-section   { padding: 0.55rem 0.65rem; }
  .status-grid .table-section h3 { font-size: 0.95rem; margin-bottom: 0.4rem; }
  .status-grid .table-hint       { font-size: 0.82rem; }
  .status-grid .ab-legend        { font-size: 0.72rem; gap: 0.2rem; }

  /* Census: explicit width = empire box + the mil/city/pop/mov columns. */
  .status-grid .census-table { width: calc(var(--empire-box-w) + var(--col-mil) + var(--col-city) + var(--col-census-pop) + var(--col-mov)); }
  .status-grid .census-table thead th:first-child { width: var(--empire-box-w); }
  :root {
    --col-mil: 3rem;
    --col-mov: 3rem;
    /* Wide enough for a full two-part player name (e.g. "Nils-Anders Nøttseter")
       on the 2nd line at the enlarged 4K font, with breathing room to spare. */
    --empire-box-w: 13rem;
  }

  .empire-cell { width: var(--empire-box-w); min-width: var(--empire-box-w); max-width: var(--empire-box-w); }
  .ast-order-table td { width: var(--empire-box-w); min-width: var(--empire-box-w); }

  /* Trade separator: re-center in 6px gap */
  .status-grid .trade-table .trade-group-start td::before { top: -3px; }

  /* AST board: row heights + fonts handled by viewport-height clamp() above.
     The colgroup col wins under table-layout:fixed, so it must widen to 9rem
     here too — otherwise the row label stays 7.5rem and the larger 4K font
     truncates 8-char civ names (Carthage, Dravidia). */
  .status-ast .ab-civ-label { width: var(--empire-box-w); min-width: var(--empire-box-w); }
  .status-ast .ab-label-col { width: var(--empire-box-w); }
  .status-ast .ab-magnet    { width: 1.8rem; font-size: clamp(0.72rem, 1vh, 1.05rem); }
}

/* Bigger type + taller rows only when the window is also tall enough. A 4K
   screen at 125 % scaling is 3072 CSS px wide but only ~1600 tall (minus
   browser chrome): it gets the 4K column widths above but keeps the base
   vh-scaled rows, which is what makes it fit. */
@media (min-width: 192rem) and (min-height: 115rem) {
  /* ── Bigger type + taller rows to fill a 4K TV ───────────────────────────
     The base vh-clamps leave ~560px empty below each table at 4K and read
     small from across the room. Raise the row-height and font vh coefficients
     (~20% larger text) so the 18 rows fill the available height. 4K-only —
     1080p/1440p keep their tuned density. */
  .status-grid .mett-table    { font-size: clamp(1rem, 1.32vh, 1.7rem); }
  /* The short column codes (MIL/CITY/POP/MOV) are bold and don't fit the narrow
     columns at the large 4K header font — the rightmost (MOV) then spills past
     the table's right border. Give them a smaller header font + tight padding
     so every code sits inside its column. */
  .status-grid .census-table th.mil-col,
  .status-grid .census-table th.city-col,
  .status-grid .census-table th.census-pop,
  .status-grid .census-table th.mov-col { font-size: 0.85rem; padding-left: 0.2rem; padding-right: 0.2rem; }
  .status-ast .ab-level-num,
  .status-ast .ab-round-num   { font-size: clamp(0.62rem, 0.94vh, 1.15rem) !important; }
  .status-ast .ab-name        { font-size: clamp(0.7rem, 1.02vh, 1.25rem) !important; }
  .status-ast .ab-magnet      { width: 2.3rem; font-size: clamp(0.9rem, 1.2vh, 1.35rem); }
}

/* ─── Status page responsive font scaling ─────────────────────────────────── */
@media (max-width: 87.5em) {
  .mett-table { font-size: 0.84rem; }
  .mett-table th { font-size: 0.7rem; padding: 0.4rem 0.5rem; }
  .mett-table td { height: 1.9rem; padding: 0.25rem 0.5rem; }
  .table-section { padding: 0.6rem; }
}
@media (max-width: 68.75em) {
  .mett-table { font-size: 0.8rem; }
  .mett-table td { height: 1.75rem; }
  .table-section { padding: 0.5rem; }
}
@media (max-width: 43.75em) {
  .mett-table { font-size: 0.78rem; }
  main.container-fluid { padding-left: 0.3rem !important; padding-right: 0.3rem !important; }
  .lb-table .adv-pts, .lb-table .ast-pts, .lb-table .total-vp, .lb-table .rank { padding-left: 0.2rem; padding-right: 0.2rem; }
}

/* ─── Admin page responsive font scaling ──────────────────────────────────── */

@media (max-width: 75em) {
  .admin-table { font-size: 0.82rem; }
  .admin-table td { height: 1.9rem; }
  .admin-table .player-name-input { width: 6.875rem; font-size: 0.82rem; }

  .admin-header h2 { font-size: 1.2rem; }
}
@media (max-width: 56.25em) {
  .admin-table { font-size: 0.76rem; }
  .admin-table .player-name-input { width: 5.625rem; font-size: 0.76rem; }

  .ast-select { font-size: 0.76rem; }

  .setup-section, .admin-section { padding: 0.4rem 0.6rem; }
}
@media (max-width: 43.75em) {
  /* Admin — ultra compact for phone */
  .admin-table { font-size: 0.68rem; }
  .admin-table td, .admin-table th { padding: 0.15rem 0.2rem; height: 1.6rem; }
  .admin-table .player-name-input { width: 4.5rem; font-size: 0.68rem; }

  .census-admin-input { width: 2.625rem !important; font-size: 0.68rem; padding: 0.12rem 0.15rem; }

  .ast-select { font-size: 0.66rem; padding: 0.1rem 0.15rem; }
  .ast-ctrl { gap: 0.15rem; }

  .admin-section { padding: 0.3rem 0.4rem; }

  /* All tables on phone — minimal column gaps */
  .mett-table td, .mett-table th { padding-left: 0.2rem; padding-right: 0.2rem; }
}

.table-section {
  background: var(--mett-surface);
  padding: 0.75rem;
  display: flex;
  flex-direction: column;
  overflow-x: hidden;
  min-width: 0;
}

.table-section h3 {
  margin: 0 0 0.75rem;
  font-size: 0.9rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--mett-muted);
  font-weight: 700;
}

/* ─── Banners ─────────────────────────────────────────────────────────────── */

.final-round-banner {
  padding: 1rem 1.5rem;
  border-radius: var(--radius-card);
  margin-bottom: 1.5rem;
  font-weight: 500;
}

.final-round-banner {
  background: #3a1010;
  border: 0.0625rem solid var(--mett-danger);
  color: #ff9999;
}

/* Game-over empire badge: let it size to content so long names like "Carthage"
   never clip regardless of font rendering or monitor DPI. */
.game-over-table .civ-badge-with-num { width: auto; min-width: 8rem; }

/* ─── Game-over table: card layout on narrow/large-text screens ───────────── */
@media (max-width: 43.75em) {
  .game-over-table thead { display: none; }
  .game-over-table,
  .game-over-table tbody { display: block; }
  .game-over-table tr {
    display: grid;
    /* empire: fit-content caps at 55% so total always gets meaningful space */
    grid-template-columns: 1.8rem fit-content(55%) 1fr;
    align-items: stretch;  /* all three cells same height as empire badge */
    gap: 0.5rem;
    padding: 0.45rem 0.1rem;
    border-bottom: 0.0625rem solid var(--mett-border);
  }
  .game-over-table tr.lb-tied { background: rgba(204,136,0,0.06); }
  .game-over-table td { height: auto; overflow: visible; }
  /* Rank: vertically centred */
  .game-over-table .go-rank   { padding: 0; display: flex; align-items: center; justify-content: center; font-size: 0.9rem; }
  /* Empire: flex container so badge stretches to fill full cell height */
  .game-over-table .go-empire { padding: 0; overflow: visible; white-space: normal; display: flex; align-items: stretch; }
  /* Total: vertically centred, right-aligned — 1fr gives it all remaining space */
  .game-over-table .go-total  { padding: 0; display: flex; align-items: center; justify-content: flex-end; white-space: nowrap; font-size: 1rem; overflow: visible; }
  .game-over-table .go-ast,
  .game-over-table .go-adv   { display: none; }
  .game-over-table .go-tie   { grid-column: 1 / 4; padding: 0.25rem 0 0; }
  .game-over-table .go-tie:empty { display: none; }
  /* Badge fills empire cell: flex:1 for full width, align-self:stretch for full height */
  .game-over-table .civ-badge-with-num { flex: 1 1 100%; display: flex; white-space: normal; align-items: flex-start; }
  .game-over-table .civ-badge-label   { display: flex; flex-direction: column; line-height: 1.25; }
  .game-over-table .go-player-name    { display: block !important; font-size: 0.72rem; opacity: 0.82; margin-top: 0.15rem; }
  /* strip padding from the game-over section so table sits flush */
  .go-section { padding: 0.15rem 0.05rem; }
  main.container-fluid { padding-left: 0.15rem !important; padding-right: 0.15rem !important; }
}

/* Medal flags (⚑) in gold/silver/bronze */
.medal {
  font-size: 1rem;
  vertical-align: middle;
}
.medal-gold   { color: #f5c518; }
.medal-silver { color: #adb5bd; }
.medal-bronze { color: #cd7f32; }

/* Late Iron Age star toggle button (admin game-over) */
.lia-star-btn {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 0.9rem;
  padding: 0 0.2rem;
  vertical-align: middle;
  transition: color 0.15s;
}
.lia-star-on  { color: var(--mett-accent); }
.lia-star-off { color: var(--mett-border); }
.lia-star-off:hover { color: var(--mett-muted); }
.lia-star-ineligible { color: var(--mett-border); opacity: 0.3; cursor: default; }

/* LIA bonus chip (leaderboard + player page) */
.lia-bonus-chip { color: var(--mett-accent); font-size: 0.85rem; }
.lia-bonus-row  { margin-top: 0.25rem; }

/* Tie-break rank dropdown */
.rank-select {
  --pico-form-element-spacing-vertical: 0.15rem;
  --pico-form-element-spacing-horizontal: 0.35rem;
  font-size: 0.8rem;
  width: auto;
}

/* ─── Civ Page ────────────────────────────────────────────────────────────── */

.civ-hero {
  background: var(--mett-surface);
  color: var(--mett-text);
  border-radius: var(--radius-panel);
  padding: 0.45rem 0.85rem;
  margin-bottom: 0.4rem;
  position: relative;
}

.civ-hero-content {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.civ-hero h2 {
  font-size: 1.7rem;
  font-weight: 900;
  margin: 0;
  color: inherit;
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.civ-player-name {
  font-size: 1rem;
  font-weight: 400;
  opacity: 0.8;
}

.civ-region-tag {
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  color: var(--mett-muted);
  align-self: flex-start;
  text-transform: uppercase;
}

.civ-body {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.4rem;
}

.civ-body > * { min-width: 0; } /* prevent grid items from expanding beyond their track */

.civ-section.ast-section {
  grid-column: 1 / -1;
}

/* ─── Civ page base rules — must all come BEFORE any media-query overrides ── */

.civ-section {
  background: var(--mett-surface);
  padding: 0.4rem 0.6rem;
  margin: 0; /* kill Pico's default section block-spacing */
}

.civ-section h3 {
  margin: 0 0 0.4rem;
  font-size: 0.82rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--mett-muted);
  font-weight: 700;
}

.census-submitted { color: var(--mett-success); font-weight: 600; margin: 0 0 0.35rem; font-size: 0.9rem; }
.census-pending { color: var(--mett-warning); margin: 0 0 0.35rem; font-size: 0.9rem; }
.status-icon-fixed { display: inline-block; width: 1em; text-align: center; flex-shrink: 0; }

.census-input-row {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

.census-input {
  --pico-form-element-spacing-vertical: 0.25rem;
  --pico-form-element-spacing-horizontal: 0.5rem;
  flex: 1;
  max-width: 10rem;
  background: var(--mett-surface2);
  border: 0.0625rem solid var(--mett-border);
  border-radius: 0.25rem;
  color: var(--mett-text);
  font-size: 0.95rem;
  margin: 0 !important;
}

/* Advance card inputs */
.adv-cards { display: flex; flex-direction: column; gap: 0.25rem; }
.adv-card-row { display: flex; align-items: center; gap: 0.5rem; }   /* match .census-input-row so −/input/+ line up with the city row */
.adv-card-label { flex: 0 0 auto; font-size: 0.82rem; color: var(--mett-muted); white-space: nowrap; }  /* label now sits on the right, under the city Submit */
.adv-btn {
  width: 1.4rem;
  height: 1.4rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0.0625rem solid var(--mett-border);
  border-radius: 0.1875rem;
  background: var(--mett-surface2);
  color: var(--mett-text);
  cursor: pointer;
  font-size: 0.95rem;
  line-height: 1;
  padding: 0;
  flex-shrink: 0;
}
.adv-btn:hover { background: var(--mett-border); }
.adv-card-input {
  --pico-form-element-spacing-vertical: 0.18rem;
  --pico-form-element-spacing-horizontal: 0.35rem;
  flex: 1;
  max-width: 10rem;            /* match .census-input so it aligns with the city select */
  text-align: right;
  background: var(--mett-surface2);
  border: 0.0625rem solid var(--mett-border);
  border-radius: 0.1875rem;
  color: var(--mett-text);
  font-size: 0.88rem;
  margin: 0 !important;
}
/* Hide number input spinners globally for compact layout */
.adv-card-input::-webkit-outer-spin-button,
.adv-card-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.adv-card-input[type=number] { -moz-appearance: textfield; }
.adv-total-row {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin-top: 0.25rem;
  padding-top: 0.3rem;
  border-top: 0.0625rem solid var(--mett-border);
}
.adv-total-label { flex: 1; font-size: 0.85rem; color: var(--mett-muted); }
.adv-total-value { font-weight: 800; font-size: 1rem; min-width: 2.5rem; text-align: right; }

.btn-submit {
  background: var(--mett-accent);
  color: #fff;
  border: none;
  border-radius: 0.25rem;
  padding: 0.3rem 0.8rem;
  font-size: 0.88rem;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
.btn-submit:hover { filter: brightness(1.15); }

.move-order {
  margin: 0.5rem 0 0;
  font-size: 0.85rem;
  color: var(--mett-muted);
}

/* ─── AST Section on civ page ─────────────────────────────────────────────── */

.ast-current {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin-bottom: 0.4rem;
}
.ast-level-label { color: var(--mett-muted); }
.ast-level-value { font-size: 1.8rem; font-weight: 900; }
.ast-era { color: var(--mett-muted); font-size: 0.85rem; }

.ast-next {
  background: var(--mett-surface2);
  border: 0.0625rem solid var(--mett-accent);
  border-radius: 0.25rem;
  padding: 0.35rem 0.55rem;
  margin-bottom: 0.35rem;
}
.ast-next h4 { margin: 0 0 0.4rem; font-size: 0.85rem; color: var(--mett-accent); }
.ast-req-text { margin: 0; font-weight: 600; font-size: 1rem; }

.ast-warn-regress { margin: 0; font-weight: 700; color: var(--mett-danger); font-size: 1rem; }
.ast-req-status { display: flex; flex-direction: column; gap: 0.3rem; }
.req-row { display: flex; align-items: baseline; gap: 0.4rem; font-weight: 600; font-size: 0.95rem; }
.req-ok { color: var(--mett-success); }
.req-fail { color: var(--mett-danger); }
.req-unknown { color: var(--mett-muted); }
.req-have { font-weight: 400; font-size: 0.8rem; color: var(--mett-muted); }

/* ─── Civ page responsive overrides (base rules above, breakpoints below) ── */

/* Mid-range: 1366×768 and similar — compact but readable */
@media (max-width: 87.5em) {
  main.container-fluid { padding-bottom: 0.4rem !important; }
  .civ-hero { padding: 0.28rem 0.65rem; margin-bottom: 0.2rem; }
  .civ-hero h2 { font-size: 1.6rem; }
  .civ-player-name { font-size: 0.85rem; }
  .civ-region-tag { font-size: 0.62rem; padding: 0.1rem 0.3rem; }
  .civ-section { padding: 0.28rem 0.5rem; }
  .civ-section h3 { font-size: 0.74rem; margin-bottom: 0.18rem; }
  .census-submitted, .census-pending { font-size: 0.82rem; margin-bottom: 0.2rem; }
  .census-input { height: 1.75rem; min-height: 0; line-height: 1.75rem; }
  .adv-card-input { height: 1.65rem; min-height: 0; line-height: 1.65rem; }
  .adv-btn { width: 1.65rem; height: 1.65rem; min-height: 0; }
  .adv-total-row { margin-top: 0.12rem; padding-top: 0.15rem; }
  .btn-submit { height: 1.75rem; min-height: 0; }
  .move-order { margin-top: 0.25rem; font-size: 0.8rem; }
  .ast-current { gap: 0.25rem; margin-bottom: 0.08rem; }
  .ast-level-value { font-size: 1.35rem; }
  .ast-next { padding: 0.25rem 0.45rem; margin-bottom: 0.15rem; }
  .ast-next h4 { font-size: 0.74rem; margin-bottom: 0.08rem; }
  .ast-req-text { font-size: 0.78rem; }

  :root { --ast-node-size: 1.5rem; --ast-node-gap: 0.09rem; }
}

/* Mobile phones ≤700px — single column, very compact */
@media (max-width: 43.75em) {
  main.container-fluid { padding-left: 0.25rem !important; padding-right: 0.25rem !important; padding-bottom: 0.2rem !important; padding-top: 0.4rem !important; }
  .mett-tagline { display: none; }

  /* Hero */
  .civ-hero { padding: 0.25rem 0.45rem; margin-bottom: 0.3rem; }
  .civ-hero-content { gap: 0.02rem; }
  .civ-hero h2 { font-size: 1.5rem; gap: 0.4rem; }
  .civ-player-name { font-size: 0.9rem; }
  .civ-region-tag { font-size: 0.56rem; padding: 0.06rem 0.2rem; }

  /* Body layout — single column with air between sections */
  .civ-body { grid-template-columns: 1fr; gap: 0.3rem; }
  .civ-section { padding: 0.3rem 0.45rem; }
  .civ-section h3 { font-size: 0.64rem; margin-bottom: 0.1rem; letter-spacing: 0.04em; }

  /* Census */
  .census-submitted, .census-pending { font-size: 0.68rem; margin-bottom: 0.05rem; }
  .census-input-row { gap: 0.18rem; }
  .census-input { -webkit-appearance: none; appearance: none; font-size: 0.95rem; padding: 0 0 0 0.45rem; height: 2.6rem; min-height: 0; line-height: 2.6rem; box-sizing: border-box; border-radius: 0.1875rem; }
  .btn-submit { font-size: 0.92rem; padding: 0 0.85rem; height: 2.6rem; min-height: 0; box-sizing: border-box; }
  .move-order { font-size: 0.64rem; margin-top: 0.06rem; }

  /* Advances */
  .adv-cards { gap: 0.06rem; }
  .adv-card-row { gap: 0.18rem; margin: 0; }   /* match .census-input-row phone gap so columns line up */
  .adv-card-label { font-size: 0.74rem; }
  .adv-card-input { -webkit-appearance: none; appearance: none; font-size: 0.95rem; padding: 0 0.35rem 0 0; flex: 1; max-width: 10rem; width: auto; height: 2.6rem; min-height: 0; line-height: 2.6rem; text-align: right; box-sizing: border-box; border-radius: 0.1875rem; margin: 0 !important; }
  .adv-btn { width: 2.6rem; height: 2.6rem; min-height: 0; font-size: 1.2rem; }
  .adv-total-row { margin-top: 0.06rem; padding-top: 0.08rem; gap: 0.18rem; }
  .adv-total-label { font-size: 0.64rem; }
  .adv-total-value { font-size: 0.85rem; min-width: 1.8rem; }

  /* Military, Wonder & Special — 3-column row */
  .mil-won-row { flex-direction: row; gap: 0.2rem; }
  .mil-toggle-civ, .won-toggle-civ, .spc-toggle-civ { flex: 1; min-width: 0; padding: 0.85rem 0.3rem; font-size: 0.85rem; }

  /* AST section */
  .ast-current { margin-bottom: 0.1rem; gap: 0.2rem; }
  .ast-level-label { font-size: 0.7rem; }
  .ast-level-value { font-size: 0.95rem; }
  .ast-era { font-size: 0.66rem; }
  .ast-next { padding: 0.18rem 0.3rem; margin-bottom: 0.12rem; }
  .ast-next h4 { font-size: 0.66rem; margin-bottom: 0.08rem; }
  .ast-req-text { font-size: 0.72rem; }

  /* AST strip: 17 nodes (expert) must fit ≈412px without h-scroll */
  :root { --ast-node-size: 1.3rem; --ast-node-gap: 0.0625rem; }
  .ast-node { font-size: 0.55rem; }
  .ast-age-label { font-size: 0.36rem; padding: 0.0625rem 0; margin-bottom: 0.0625rem; }

  /* City + VP rows + the SUM row share one grid so every column lines up.
     Wide non-square steppers (numbers are always small), a narrow input,
     and a last column (1fr) where Submit, the N-VP labels and the SUM value
     all sit left-aligned — i.e. directly below the Submit button. */
  .census-pop-row,
  .city-count-row,
  .adv-card-row,
  .adv-total-row {
    display: grid;
    /* fr columns spend the full row width — no fixed caps leaving dead space,
       and fr shrinks to fit so the row never overflows horizontally even at
       large OS font. Submit + the steppers stretch to fill, like the
       mil/won/spc row's flex:1 buttons. Submit gets the largest share. */
    grid-template-columns: 1fr 1.3fr 1fr 2fr;
    gap: min(0.3rem, 1.2vw);
    align-items: center;
  }
  .btn-submit { padding: 0 0.5rem; }
  /* Population row: wide input across the −/select/+ columns, Submit in the
     last column so it sits directly under the city Submit. */
  .census-pop-row > .census-input { grid-column: 1 / 4; width: 100%; max-width: none; }
  .census-pop-row > .btn-submit { grid-column: 4; justify-self: stretch; }
  .city-count-row > .adv-btn,
  .adv-card-row > .adv-btn { width: 100%; height: 2.6rem; }
  .city-count-row > .census-input,
  .adv-card-row > .adv-card-input { width: 100%; max-width: none; }
  .city-count-row > .btn-submit { justify-self: stretch; }
  .adv-card-label { text-align: left; font-size: 0.95rem; }   /* under the Submit button, not far right */
  .adv-total-label { grid-column: 1 / 4; }                    /* "SUM" on the left */
  .adv-total-value { grid-column: 4; text-align: left; min-width: 0; }  /* aligns under Submit, with the N-VP labels */
}

/* Rules with no responsive override — fine after the breakpoints */
.ast-next.req-all-ok { border-color: var(--mett-success); }
.ast-next.req-not-met { border-color: var(--mett-danger); }

/* The player page must NEVER scroll sideways on a phone. Clip any stray
   horizontal overflow (real-device font rounding, or a wrapped AST age-label
   painting past the viewport edge) while leaving vertical scroll intact —
   mirrors the status page's overflow safety net. */
html:has(.civ-page),
body:has(.civ-page) { overflow-x: hidden; }

.ast-bar-wrap {
  overflow-x: auto;
  margin-top: 0.75rem;
  scrollbar-width: none; /* Firefox */
}
.ast-bar-wrap::-webkit-scrollbar { display: none; } /* Chrome/Safari */

.ast-progress-grid {
  display: grid;
  gap: var(--ast-node-gap);
  width: 100%;                 /* fill the section — no wasted space on the right */
}

.ast-age-label {
  font-size: 0.5rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  text-align: center;
  white-space: normal;         /* wrap rather than clip — 1-cell ages go to 2 lines */
  overflow-wrap: normal;       /* break at spaces only, never mid-word ("EARLY/IRON/AGE") */
  word-break: normal;
  line-height: 1.05;
  align-self: stretch;         /* every band fills the row → all boxes equally tall */
  display: flex;
  flex-direction: column;
  justify-content: flex-end;   /* text sits at the bottom, next to the cells */
  align-items: center;
  min-width: 0;
  border-radius: 0.1875rem 0.1875rem 0 0;
  padding: 0.125rem 0.1rem;
  margin-bottom: 0.125rem;
}

.ast-node {
  min-width: 0;                /* cells stretch to fill their 1fr column (wider than tall) */
  height: var(--ast-node-size);
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 0.1875rem;
  font-size: 0.65rem;
  font-weight: 700;
  cursor: default;
}

.ast-node.past { background: var(--mett-surface2); color: var(--mett-muted); }
.ast-node.active {
  background: var(--mett-accent);
  color: #fff;
  box-shadow: 0 0 0.5rem var(--mett-accent);
  transform: scale(1.1);
}
.ast-node.future { background: var(--mett-surface); border: 0.0625rem solid var(--mett-border); color: var(--mett-muted); }

/* ─── AST Board View ─────────────────────────────────────────────────────── */

/* Shrink-wrap the table so it doesn't stretch to fill the page */
.ab-scroll {
  overflow-x: auto;
  display: inline-block;   /* key: shrinks to table width */
  max-width: 100%;
}

.ab-table {
  border-collapse: collapse;
  table-layout: fixed;
  /* width is sum of columns: 6.25rem label + 17 × 1.875rem = 38.125rem */
  width: 38.125rem;
  font-size: 0.72rem;
}

/* Scale up on wider screens: 68.75rem → 10rem label + 17×3rem = 61rem */
@media (min-width: 68.75em) {
  .ab-scroll { display: block; }
  .ab-table { width: 61rem; font-size: 0.82rem; }
  .ab-civ-label { width: 8.125rem; }
  .ab-level-num { width: 3rem; font-size: 0.72rem; }
  .ab-cell { width: 3rem; height: 2.125rem; }
  .ab-magnet { width: 1.625rem; height: 1.625rem; }
  .ab-name { font-size: 0.72rem; }
  .ab-round-num { font-size: 0.72rem; }
}

/* Even wider: 87.5rem → 11.25rem label + 17×3.625rem = 72.875rem */
@media (min-width: 87.5em) {
  .ab-table { width: 72.875rem; font-size: 0.88rem; }
  .ab-civ-label { width: 8.4375rem; }
  .ab-level-num { width: 3.625rem; font-size: 0.76rem; }
  .ab-cell { width: 3.625rem; height: 2.5rem; }
  .ab-magnet { width: 1.875rem; height: 1.875rem; }
  .ab-name { font-size: 0.76rem; }
  .ab-round-num { font-size: 0.76rem; }
}

.ab-table th, .ab-table td {
  padding: 0;
  border: 0.0625rem solid rgba(255,255,255,0.08);
}

/* Civ label column — sticky so it stays visible when scrolling */
.ab-civ-label {
  width: 7.8125rem;
  padding: 0.2rem 0.4rem;
  background: var(--mett-bg);
  position: sticky;
  left: 0;
  z-index: 2;
  border-right: 0.125rem solid rgba(0,0,0,0.5) !important;
}

.ab-corner { background: var(--mett-bg) !important; z-index: 3; }
.status-ast .ab-corner { background: transparent !important; border: none !important; }

.ab-vp-label {
  font-size: 0.6rem;
  color: var(--mett-muted);
  font-weight: 400;
  text-align: right;
  padding-right: 0.3rem;
}

/* Age band header row */
.ab-header {
  text-align: center;
  padding: 0.2rem 0.1rem;
  vertical-align: middle;
  overflow: hidden;
  border-bottom: 0.125rem solid rgba(0,0,0,0.4) !important;
}

.ab-name {
  display: block;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  line-height: 1.15;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  word-break: break-word;
  hyphens: auto;
}

/* Level number row */
.ab-level-num {
  text-align: center;
  font-size: 0.62rem;
  font-weight: 700;
  padding: 0.15rem 0;
  width: 1.875rem;
  border-bottom: 0.125rem solid rgba(0,0,0,0.4) !important;
}

/* Age band colours — headers */
.age-start   { background: #1a1a1a; color: #666; }
.age-stone   { background: #3a3028; color: #c8b89a; }
.age-ebronze { background: #352818; color: #d4a870; }
.age-mbronze { background: #2e1e0e; color: #c09050; }
.age-lbronze { background: #221408; color: #a07840; }
.age-eiron   { background: #2a2000; color: #c8a020; }
.age-liron   { background: #1e1004; color: #b06828; }

/* Cell tints for the body rows */
.ab-cell {
  width: 1.875rem;
  height: 1.5rem;
  text-align: center;
  vertical-align: middle;
}

/* Distinct, higher-contrast age tints: a light-tan → deepening-bronze ramp,
   then a cool steel for Early Iron, so adjacent ages read apart at a glance.
   Late Iron Age has no tint here — its cell background is the empire's own
   colour, set inline in main.ts (the "finish line"). */
.ab-cell.age-start   { background: rgba(255,255,255,0.04); }
.ab-cell.age-stone   { background: rgba(170,156,132,0.30); }
.ab-cell.age-ebronze { background: rgba(224,164,74,0.52); }   /* bright amber */
.ab-cell.age-mbronze { background: rgba(170,96,34,0.58); }    /* orange bronze */
.ab-cell.age-lbronze { background: rgba(104,52,16,0.70); }    /* dark red-brown */
.ab-cell.age-eiron   { background: rgba(96,114,144,0.48); }
/* Late Iron Age (the finish line) takes the empire's colour, toned down. */
.ab-cell.age-liron   { background: color-mix(in srgb, var(--civ) 45%, transparent); }

/* Age borders removed — the colour contrast separates the ages now. The Start
   column keeps its divider (see .ab-start-col). */
.ab-age-end { /* intentionally empty */ }

/* Start column — level 0, where all empires sit at game start */
.ab-start-col {
  border-right: 0.125rem solid rgba(255,255,255,0.22) !important;
  opacity: 0.6;
}
.ab-level-num.ab-start-col {
  font-style: italic;
  letter-spacing: 0;
}

/* Magnet dot */
.ab-magnet {
  display: inline-block;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 50%;
  border: 0.0938rem solid rgba(0,0,0,0.4);
  box-shadow: 0 0.0625rem 0.1875rem rgba(0,0,0,0.6), inset 0 0.0625rem 0.125rem rgba(255,255,255,0.25);
  vertical-align: middle;
}

/* Requirements legend below the board */
.ab-legend {
  list-style: none;
  padding: 0.5rem 0 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1.2rem;
  font-size: 0.72rem;
  color: var(--mett-muted);
}

.ab-legend li { display: flex; align-items: center; gap: 0.35rem; }

/* Requirement legend on the player page — always visible below the AST strip,
   one era per line. Each era's requirement is broken into parts coloured green
   (reached) or red (still needed). The player page is allowed to scroll
   vertically. */
.ast-req-legend { flex-direction: column; font-size: 0.62rem; gap: 0.12rem; padding: 0.3rem 0.5rem 0.5rem; }
/* Block flow (not flex) so each era's requirement wraps like plain inline text —
   fits one line when it can, and only ever wraps at the " + " separators (never
   mid-label), never horizontally overflowing. Matches the old white-text width. */
.ast-req-legend li { display: block; }
.ast-req-legend .ab-legend-dot { display: inline-block; vertical-align: middle; margin-right: 0.3rem; }
.ast-req-legend strong { margin-right: 0.2rem; }
.req-part { white-space: nowrap; }
.req-part-ok      { color: var(--mett-success); }
.req-part-fail    { color: var(--mett-danger); }
.req-part-unknown { color: var(--mett-muted); }
/* Stone Age has no requirements — it's always satisfied, so show it green. */
.req-part-none    { color: var(--mett-success); }
.req-sep          { color: var(--mett-muted); }

.ab-legend-dot {
  display: inline-block;
  width: 0.625rem;
  height: 0.625rem;
  border-radius: 0.125rem;
  flex-shrink: 0;
}

/* Legend dots match the board's age palette. Late Iron Age is per-empire
   (each cell is that empire's colour), so its swatch is multi-coloured. */
.ab-legend-dot.age-stone   { background: #9c9072; }
.ab-legend-dot.age-ebronze { background: #e0a448; }
.ab-legend-dot.age-mbronze { background: #a85e22; }
.ab-legend-dot.age-lbronze { background: #5a2e0e; }
.ab-legend-dot.age-eiron   { background: #6a7d9e; }
.ab-legend-dot.age-liron   { background: conic-gradient(from 45deg, #e0533a, #e0b13a, #4caf50, #3a9ad0, #9b59d0, #e0533a); }

/* Round track footer row */
.ab-round-label {
  font-size: 0.6rem;
  color: var(--mett-muted);
  font-weight: 400;
  text-align: right;
  padding-right: 0.3rem;
}

.ab-round-num {
  text-align: center;
  font-size: 0.6rem;
  color: var(--mett-muted);
  padding: 0.12rem 0;
  border-top: 0.0625rem solid rgba(255,255,255,0.08);
}

.ab-round-current {
  color: var(--mett-accent);
  font-weight: 700;
  background: rgba(196,147,63,0.12) !important;
}

/* ─── Admin Page ──────────────────────────────────────────────────────────── */

.admin-page h2 { margin-bottom: 1.5rem; }

.setup-section,
.admin-section {
  background: var(--mett-surface);
  padding: 0.35rem 0.6rem;
  margin-bottom: 0.3rem;
}

.setup-section h3,
.admin-section h3 {
  margin: 0 0 0.5rem;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--mett-muted);
  font-weight: 700;
}

/* ─── Admin: backups list (collapsed by default) ───────────────────────────── */
.backup-section summary { cursor: pointer; }
.backup-section summary h3 { display: inline; margin: 0; }
.backup-section[open] summary { margin-bottom: 0.4rem; }
.backup-table td { white-space: nowrap; }

/* ─── Admin: round-transition summary panel (item 11.10) ────────────────────
   Surfaces what changed at the previous advanceRound. Admin-only — the
   status page deliberately stays clean. Tight by design — the panel
   shouldn't dominate the admin view. */
.admin-section.round-summary {
  border-left: 0.1875rem solid var(--mett-accent);
  padding: 0.4rem 0.6rem 0.5rem;
}
.admin-section.round-summary h3 {
  color: var(--mett-muted);
  font-size: 0.7rem;
  margin: 0 0 0.25rem;
}
.round-summary .rs-line {
  margin: 0;
  padding: 0.15rem 0;
  font-size: 0.8rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem;
  line-height: 1.3;
}
.round-summary .rs-icon {
  font-size: 0.95rem;
  font-weight: 700;
  width: 1.1rem;
  flex-shrink: 0;
  text-align: center;
}
.round-summary .rs-advanced .rs-icon  { color: var(--mett-accent); }
.round-summary .rs-regressed .rs-icon { color: var(--mett-danger); }
.round-summary .rs-stayed .rs-icon    { color: var(--mett-muted); }
.round-summary .rs-lia-bonus { color: var(--mett-accent); font-weight: 600; }
.round-summary .rs-lia-blocked,
.round-summary .rs-lia-late  { color: var(--mett-muted); font-size: 0.78rem; }
.round-summary .rs-final     { color: var(--mett-warning); font-weight: 600; font-size: 0.85rem; }
.round-summary .rs-end       { color: var(--mett-danger); font-weight: 700; font-size: 0.85rem; }
.round-summary .rs-quiet     { color: var(--mett-muted); font-style: italic; font-size: 0.78rem; }
.round-summary .rs-chip {
  display: inline-flex;
  align-items: center;
  padding: 0.04rem 0.4rem;
  font-size: 0.78rem;
  margin: 0;
}

.mode-toggle-row {
  display: flex;
  gap: 2rem;
  flex-wrap: wrap;
}

.mode-toggle-row label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
}

.player-count-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.player-count-select {
  background: var(--mett-surface2);
  border: 0.0625rem solid var(--mett-border);
  border-radius: 0.25rem;
  padding: 0.3rem 0.5rem;
  color: var(--mett-text);
  font-size: 1rem;
  cursor: pointer;
}

.setup-hint {
  font-size: 0.8rem;
  color: var(--mett-muted);
  margin: 0;
}

/* ─── Name inputs ─────────────────────────────────────────────────────────── */

.name-inputs-grid2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.35rem 1.25rem;
}

@media (max-width: 37.5em) {
  .name-inputs-grid2 { grid-template-columns: 1fr; }
}

.name-input-row {
  display: flex;
  align-items: stretch;
  gap: 0.4rem;
}

.name-civ-tag {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 0.5rem;
  border-radius: 0.125rem;
  font-size: 0.75rem;
  font-weight: 700;
  white-space: nowrap;
  flex-shrink: 0;
  min-width: 5.5rem;
}

.name-text-input {
  flex: 1;
  min-width: 0;
  margin: 0 !important;
  background: var(--mett-surface2);
  border: 0.0625rem solid var(--mett-border);
  border-radius: 0.25rem;
  padding: 0.3rem 0.5rem;
  color: var(--mett-text);
  font-size: 0.85rem;
  height: auto;
  line-height: 1.4;
}

/* ─── Admin active controls ───────────────────────────────────────────────── */

.admin-header {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-bottom: 0.35rem;
}

.admin-header h2 { margin: 0; }
.admin-badges { display: flex; gap: 0.5rem; }

.round-controls {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  align-items: center;
}

.round-hint {
  font-size: 0.8rem;
  color: var(--mett-warning);
  opacity: 0.85;
}

/* Login page */
.login-page {
  max-width: 20rem;
  margin: 4rem auto;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.login-form {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.login-input {
  width: 100%;
  padding: 0.5rem 0.75rem;
  font-size: 1rem;
  background: var(--mett-bg-alt);
  border: 0.0625rem solid var(--mett-border);
  border-radius: 0.35rem;
  color: var(--mett-text);
}
.login-error {
  color: #e05555;
  font-size: 0.9rem;
}
.pwd-ok {
  color: #4caf50;
  font-size: 0.9rem;
}
.change-pwd-form {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
  margin-top: 0.25rem;
}
.change-pwd-form .login-input {
  width: auto;
  flex: 1 1 10rem;
}

/* Round phase stepper (admin) — reuses .phase-step/.phase-sep from the status
   strip; just give it a little breathing room above the controls. */
.admin-phase-steps {
  margin-bottom: 0.6rem;
  flex-wrap: wrap;
}
.round-phase-progress {
  font-size: 0.85rem;
  opacity: 0.85;
  margin-right: 0.5rem;
}
.round-phase-progress #round-progress-count { font-weight: 700; opacity: 1; }

/* Reset Pico CSS margin AND padding on all form elements inside admin table */
.admin-table input,
.admin-table select,
.admin-table button {
  margin: 0 !important;
}
.admin-table input[type=text],
.admin-table input[type=number],
.admin-table select {
  --pico-form-element-spacing-vertical: 0.12rem;
  --pico-form-element-spacing-horizontal: 0.35rem;
}

.admin-table { font-size: 0.84rem; }
.admin-table td { height: 1.75rem; padding: 0.15rem 0.4rem; }
.admin-table th { padding: 0.25rem 0.4rem; font-size: 0.68rem; }

/* 1080p laptop-on-the-table — primary target is WQHD/4K, but the 18-row
   Players table runs ~300 px past the fold at FHD with the default
   density. Tighten rows, form-element padding, and icon buttons so all
   18 players fit (Danger Zone may still need a small scroll). Capped
   below the WQHD breakpoint (160em) so TV-display density at 2560px+
   is untouched. */
@media (min-width: 75em) and (max-width: 159.99em) {
  /* Goal at 1080p: full admin page (header → players → round summary →
     danger zone → nag) fits in 1080px without scrolling. The Players
     table dominates vertical space, so shrink rows + form elements
     aggressively here while keeping content readable. */
  .admin-table { font-size: 0.78rem; }
  .admin-table td { height: 1rem; padding: 0.02rem 0.4rem; }
  .admin-table th { padding: 0.08rem 0.4rem; font-size: 0.65rem; }
  .admin-table input[type=text],
  .admin-table input[type=number],
  .admin-table select {
    --pico-form-element-spacing-vertical: 0;
    height: 1.2rem !important;
    min-height: 0;
    line-height: 1;
    font-size: 0.74rem;
    padding-top: 0;
    padding-bottom: 0;
  }
  .admin-table .icon-toggle { width: 1.15rem; height: 1.15rem; font-size: 0.72rem; }
  .admin-table .lia-star-btn { font-size: 0.85rem; padding: 0; }
  /* Empire chip in admin row — shrink to match the 1080p row height */
  .admin-table .civ-badge { padding: 0.05rem 0.4rem; font-size: 0.74rem; }
  .admin-table .civ-badge-with-num { width: 6rem; }
  .ast-ctrl { gap: 0.15rem; }
  .admin-section { padding: 0.2rem 0.5rem; margin-bottom: 0.15rem; }
  .admin-section h3 { font-size: 0.65rem; margin-bottom: 0.18rem; }
  .admin-phase-steps { margin-bottom: 0.3rem; }
  .round-controls { margin-top: 0.15rem; gap: 0.5rem; align-items: center; }
  .round-controls button { padding: 0.25rem 0.7rem; font-size: 0.78rem; min-height: 0; line-height: 1.2; }
  .round-hint { font-size: 0.7rem; }
  /* Admin page header — compact title row sitting above the round-section. */
  .admin-page > h2 {
    font-size: 0.95rem;
    line-height: 1.2;
    margin: 0 0 0.25rem;
  }

  /* Compact danger zone + password nag at the foot. */
  .danger-section .danger-row { gap: 0.4rem; }
  .danger-section button { padding: 0.2rem 0.6rem; font-size: 0.74rem; min-height: 0; }
  .default-pwd-nag { padding: 0.2rem 0.6rem; font-size: 0.7rem; margin-top: 0.15rem; }
  /* Round-summary slimmed: drop the h3 header (the icon strip is
     self-explanatory) and tighten line spacing. */
  .round-summary h3 { display: none; }
  .round-summary { padding: 0.2rem 0.5rem; }
  .round-summary .rs-line { padding: 0.04rem 0; gap: 0.2rem; }
  .round-summary .rs-chip { font-size: 0.72rem; padding: 0.02rem 0.3rem; }
}
.admin-table th { width: 14.28%; }

.admin-table .player-name-input {
  background: transparent;
  border: 0.0625rem solid transparent;
  color: var(--mett-text);
  font-size: 0.84rem;
  padding: 0.15rem 0.35rem;
  border-radius: 0.1875rem;
  width: 7.5rem;
}
.admin-table .player-name-input:focus {
  border-color: var(--mett-accent);
  background: var(--mett-surface2);
  outline: none;
}

.mil-won-cell { display: flex; flex-direction: row; gap: 0.25rem; align-items: center; }
.mil-toggle, .won-toggle, .spc-toggle {
  border: 0.0625rem solid var(--mett-border);
  border-radius: 0.1875rem;
  padding: 0.12rem 0.35rem;
  font-size: 0.76rem;
  cursor: pointer;
  white-space: nowrap;
}
/* Icon-only compact variant used in admin table */
.icon-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.8rem;
  height: 1.8rem;
  padding: 0;
  font-size: 0.9rem;
  line-height: 1;
  border-radius: var(--radius-soft);
  flex-shrink: 0;
}
.mil-toggle.mil-on { background: #3a2020; border-color: #cc5555; color: #ff8888; }
.mil-toggle.mil-off { background: var(--mett-surface2); color: var(--mett-muted); }
.won-toggle.won-on  { background: #2a2a10; border-color: #aaaa22; color: #dddd44; }
.won-toggle.won-off { background: var(--mett-surface2); color: var(--mett-muted); }
.spc-toggle.spc-on  { background: #1a1a30; border-color: #5555cc; color: #8888ff; }
.spc-toggle.spc-off { background: var(--mett-surface2); color: var(--mett-muted); }

/* Calamity regression button (admin table) — drops the empire one AST step. */
.regress-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.8rem;
  height: 1.8rem;
  padding: 0;
  font-size: 0.8rem;
  line-height: 1;
  border-radius: var(--radius-soft);
  border: 0.0625rem solid var(--mett-border);
  background: var(--mett-surface2);
  color: #d98a8a;
  cursor: pointer;
  flex-shrink: 0;
}
.regress-btn:hover:not(:disabled) { background: #3a2020; border-color: #cc5555; color: #ff8888; }
.regress-btn:disabled { opacity: 0.3; cursor: not-allowed; }
/* Active = this empire was regressed this round; echoes the status board's red marker. */
.regress-btn.regress-active { background: #3a1414; border-color: #e01b1b; color: #ff8888; box-shadow: 0 0 0.35rem rgba(224, 27, 27, 0.6); }

/* Special-ability dimming: non-holders in the AST order column (active whenever any player holds the ability) */
.ast-order-table tr.special-dim td { opacity: 0.15; }

.ast-ctrl {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}
/* Admin AST movement indicator: green → advance, orange = no change,
   red ← regress. Fixed-width container keeps the select arrows aligned. */
.ast-status-ind {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.1875rem;
  flex-shrink: 0;
}
.ast-move {
  font-weight: 700;
  font-size: 1.05rem;
  line-height: 1;
}
.ast-move-advance { color: var(--mett-success); }
.ast-move-stay    { color: var(--mett-warning); }
.ast-move-regress { color: var(--mett-danger); }
.ast-move-unknown { color: var(--mett-border); }

.ast-select {
  background: var(--mett-surface2);
  border: 0.0625rem solid var(--mett-border);
  border-radius: 0.25rem;
  color: var(--mett-text);
  padding: 0.1rem 0.25rem;
  font-size: 0.82rem;
  width: 4.25rem;
}

.city-admin-select {
  background: var(--mett-surface2);
  border: 0.0625rem solid var(--mett-border);
  border-radius: 0.25rem;
  color: var(--mett-text);
  padding: 0.1rem 0.25rem;
  font-size: 0.82rem;
  width: 4.25rem;
}

.census-admin-input { width: 5.875rem !important; flex: none; }
.census-admin-input::-webkit-inner-spin-button,
.census-admin-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; display: none; }
.census-admin-input { -moz-appearance: textfield; }
.census-admin-input {
  background: var(--mett-surface2);
  border: 0.0625rem solid var(--mett-border);
  border-radius: 0.1875rem;
  padding: 0.15rem 0.3rem;
  color: var(--mett-text);
  font-size: 0.82rem;
  text-align: right;
  margin: 0 !important;
}
.census-admin-input:focus {
  border-color: var(--mett-accent);
  outline: none;
}
.census-admin-input::placeholder { color: var(--mett-muted); }

.danger-row { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; }
#sim-controls { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.5rem; }

/* Informational nag shown below the Danger Zone when the admin password is still the seeded default. */
.default-pwd-nag {
  margin: 1.25rem 0 0;
  padding: 0.5rem 0.75rem;
  font-size: 0.8rem;
  color: var(--mett-muted);
  border-left: 0.125rem solid #6a5a22;
  background: rgba(106, 90, 34, 0.08);
  border-radius: 0 0.25rem 0.25rem 0;
}
.default-pwd-nag strong { color: var(--mett-fg); }

/* ─── Buttons ─────────────────────────────────────────────────────────────── */

.btn-primary {
  background: var(--mett-accent);
  color: #fff;
  border: none;
  border-radius: 0.25rem;
  padding: 0.5rem 1.2rem;
  font-weight: 700;
  font-size: 0.9rem;
  cursor: pointer;
}
.btn-primary:hover { filter: brightness(1.15); }
.btn-primary:disabled { opacity: 0.4; cursor: not-allowed; }

.btn-danger {
  background: var(--mett-danger);
  color: #fff;
  border: none;
  border-radius: 0.25rem;
  padding: 0.45rem 1rem;
  font-weight: 700;
  cursor: pointer;
}

.error-msg {
  color: #ff6666;
  font-size: 0.85rem;
  margin: 0.5rem 0 0;
  min-height: 1.2em;
}

.not-in-game {
  text-align: center;
  padding: 4rem 2rem;
  color: var(--mett-muted);
}

/* ── Trade card layout (still used in main view) ──────────────────────────── */
.trade-table { width: 100%; }
.trade-table .trade-card-col {
  width: 10rem;
  vertical-align: middle;
  padding-top: 0.25rem;
  padding-bottom: 0.25rem;
}
.trade-table .trade-card-col.submitted-hidden { color: #4a8a5a; font-size: 1rem; font-weight: 700; }
.trade-table .trade-card-col.not-submitted    { color: #8a3a3a; font-size: 1rem; font-weight: 700; }
.trade-no-cards { color: var(--mett-muted); }
.phase-hint { color: var(--mett-muted); font-size: 0.78rem; margin: 0 0 0.4rem; }
.phase-badge {
  display: inline-block;
  margin-left: 0.5rem;
  padding: 0.1rem 0.4rem;
  border-radius: var(--radius-tight);
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: var(--mett-surface2);
  color: var(--mett-muted);
  vertical-align: middle;
}

/* Trade card chips */
.trade-chips {
  display: flex;
  flex-wrap: nowrap;
  gap: 0.125rem;
}
.trade-chip {
  width: 1rem;
  height: 1.5rem;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 0.125rem;
  border: 0.0625rem solid var(--mett-border);
  background: var(--mett-surface2);
  color: var(--mett-text);
  font-size: 0.625rem;
  font-weight: 700;
  line-height: 1;
}
.trade-chip-wonder {
  background: #2a2a10;
  border-color: #aaaa22;
  color: #dddd44;
}
.trade-table .trade-group-start td {
  border-top: 0.125rem solid var(--mett-accent);
}

/* ── Error toast ─────────────────────────────────────────────────────────── */
#mett-toast {
  position: fixed;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%);
  background: #7a1a1a;
  color: #fff;
  padding: 0.55rem 1.1rem;
  border-radius: 0.35rem;
  border: 1px solid #cc3333;
  font-size: 0.875rem;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s;
  z-index: 9999;
  white-space: nowrap;
}
#mett-toast.visible { opacity: 1; }

/* ── Short-viewport compaction for the player page ────────────────────────
   The civ page must fit without scroll even on short screens: 375×667
   phones and 1366×768 laptops both overflowed the width-only breakpoints.
   Height-scoped so taller viewports (390×844, 411×731 portrait, 1080p+)
   keep the roomier layout. Header rules are scoped with :has(.civ-page)
   because the status/admin layouts are height-tuned around the default
   header. */

/* Short landscape: laptops (1366×768) and tablets/phones in landscape */
@media (min-width: 43.76em) and (max-height: 50em) {
  body:has(.civ-page) .site-header { padding: 0.25rem 0.75rem 0.15rem; }
  .civ-hero { padding: 0.18rem 0.65rem; margin-bottom: 0.15rem; }
  .civ-hero h2 { font-size: 1.3rem; }
  .civ-body { gap: 0.25rem; }
  .civ-section { padding: 0.2rem 0.5rem; }
  .ast-level-value { font-size: 1.05rem; }
  .ast-current { margin-bottom: 0.05rem; }
  .ast-next { padding: 0.18rem 0.45rem; margin-bottom: 0.1rem; }
  .ast-req-status { gap: 0.15rem; }
  .req-row { font-size: 0.82rem; gap: 0.3rem; }
  .req-have { font-size: 0.72rem; }
  .ast-bar-wrap { margin-top: 0.25rem; }
}

/* Short phones — squeeze below the ≤700px-wide baseline. The em threshold
   deliberately scales with the user's font-size preference: at default fonts
   it only catches genuinely short screens (≤760px, e.g. 375×667 — every
   modern Pixel/iPhone is ≥812 and keeps the roomy layout), but with the OS
   font size turned up (e.g. Pixel "Large" ≈ 1.3×) a 412×915 Pixel 8 measures
   ≤49em and gets the compact layout, which is what lets the bigger text
   still fit without scrolling. At ≥1.5× scaling the page scrolls vertically
   by design — fighting a strong accessibility preference with density would
   defeat its purpose. */
@media (max-width: 43.75em) and (max-height: 49em) {
  body:has(.civ-page) .site-header { padding: 0.2rem 0.75rem 0.1rem; }
  body:has(.civ-page) .mett-wordmark { font-size: 0.9rem; }
  main.container-fluid { padding-top: 0.2rem !important; }
  .civ-hero { padding: 0.25rem 0.6rem; margin-bottom: 0.3rem; }
  .civ-hero h2 { font-size: 1.2rem; }
  .civ-body { gap: 0.3rem; }
  .civ-section { padding: 0.3rem 0.45rem; }
  .phase-hint { font-size: 0.62rem; margin-bottom: 0.08rem; }
  .census-input { height: 1.9rem; line-height: 1.9rem; }
  .btn-submit { height: 1.9rem; }
  .adv-card-input { height: 1.9rem; line-height: 1.9rem; }
  .adv-btn { height: 1.9rem; }
  .city-count-row > .adv-btn,
  .adv-card-row > .adv-btn { height: 1.9rem; }
  .mil-toggle-civ, .won-toggle-civ, .spc-toggle-civ { padding: 0.3rem; }
  .ast-current { margin-bottom: 0.04rem; }
  .ast-level-value { font-size: 0.85rem; }
  .ast-next { padding: 0.12rem 0.3rem; margin-bottom: 0.08rem; }
  .ast-next h4 { margin-bottom: 0.04rem; }
  .ast-req-status { gap: 0.12rem; }
  .req-row { font-size: 0.78rem; gap: 0.25rem; }
  .req-have { font-size: 0.68rem; }
  .ast-bar-wrap { margin-top: 0.12rem; }
  :root { --ast-node-size: 1.15rem; }
  .ast-node { font-size: 0.5rem; }
}

/* ─── Calm components (every page) ──────────────────────────────────────────
   One look for status, admin and player pages: borderless rounded panels, no
   header band on tables, alternating row stripes instead of row lines, and the
   empire colour only on the number badge (.civ-num, below). Colours and
   corners only — sizes are set per page, so the board's row pitch and
   cross-table alignment are untouched. */
.table-section,
.setup-section,
.admin-section,
.civ-section {
  border: 0.0625rem solid transparent;
  border-radius: var(--radius-panel);
}
.danger-section.setup-section,
.danger-section.admin-section { border-color: #442222; }

.status-ast .ab-civ-label.empire-cell { background: transparent; }
.mett-table tbody tr:nth-child(even) td,
.status-ast tbody tr:nth-child(even) .ab-civ-label {
  background: var(--mett-stripe);
}
/* Row states sit on top of the stripes. */
.mett-table tbody tr.lb-tied td { background: rgba(204, 136, 0, 0.1); }
.mett-table tbody tr:hover td  { background: var(--mett-surface2); }
/* Round the ends of each striped row instead of each cell (tables with
   border-collapse: collapse simply ignore the radius). */
.mett-table td { border-radius: 0; }
.mett-table td:first-child { border-radius: var(--radius-row) 0 0 var(--radius-row); }
.mett-table td:last-child  { border-radius: 0 var(--radius-row) var(--radius-row) 0; }
.mett-table td:only-child,
.status-ast .ab-civ-label.empire-cell { border-radius: var(--radius-row); }

/* Leaderboard: the "=N" rank already marks ties, and nearly every score is
   its own group, so the per-group divider would draw a line under almost
   every row. The stripes carry the scanning instead. */
.status-grid .lb-table .lb-group-start td::before { content: none; }

/* ─── Board type scale ───────────────────────────────────────────────────────
   One set of viewport-height tokens for the TV board (≥ 700 px wide). The
   *-base values are tuned for a full 18-player game at 1080p; breakpoints (the
   tall-4K block below) only re-value the bases.

   Smaller games fill the board: main.ts sets --players on .status-grid and
   rows grow by 18 / players (up to 3×), so the same height is used by fewer,
   taller rows. Width is fixed by the five side-by-side tables, so text grows
   less: civ names (which have spare width in their box) up to 1.3×, numbers
   up to 1.15× (three-digit totals must still fit their column), player names
   not at all (the longest already fills the box). Trade chips follow the
   numbers, not the rows, so the trade column barely widens. */
@media (min-width: 43.76em) {
  .status-grid {
    --board-row-base: clamp(1.1rem, 3.65vh, 4.2rem);
    --board-name-base: clamp(0.8rem, 1.5vh, 1.8rem);
    --board-num-base: clamp(0.85rem, 1.6vh, 1.9rem);
    --board-sub: clamp(0.55rem, 0.85vh, 1.05rem);
    --board-head: clamp(0.55rem, 0.95vh, 1.1rem);

    --text-scale-max: 1.2;
    --num-scale-max: 1.15;
    --row-scale: clamp(1, calc(18 / var(--players, 18)), 3);
    --text-scale: clamp(1, calc(1 + (var(--row-scale) - 1) * 0.3), var(--text-scale-max));
    --num-scale: min(var(--text-scale), var(--num-scale-max));
    --board-row: calc(var(--board-row-base) * var(--row-scale));
    --board-name: calc(var(--board-name-base) * var(--text-scale));
    --board-num: calc(var(--board-num-base) * var(--num-scale));
  }
  .status-grid .mett-table td,
  .status-ast .ab-cell                { height: var(--board-row); }
  .status-grid .mett-table td.empire-cell,
  .status-ast td.empire-cell          { font-size: var(--board-name); }
  .status-grid .empire-player-name    { font-size: var(--board-sub); }
  .status-grid .mett-table th,
  .status-ast thead th                { font-size: var(--board-head); }
  .status-grid td.census-pop,
  .status-grid td.city-col,
  .status-grid td.rank,
  .status-grid td.adv-pts,
  .status-grid td.ast-pts,
  .status-grid td.total-vp,
  .status-grid td.trade-card-col.not-submitted,
  .status-grid td.trade-card-col.submitted-hidden { font-size: var(--board-num); }

  /* Trade-card chips are sized from the row height (never the viewport
     width), so they can never make a trade row taller than the rows in the
     other tables — width-based chip sizes once did on a 4K screen at 125 %.
     The column holds 9 chips + gaps + the cell's 2 × 0.4rem padding. */
  .status-grid {
    --chip-h: calc(var(--board-row-base) * 0.66 * var(--num-scale));
    --chip-w: calc(var(--chip-h) * 0.62);
    --chip-gap: max(1px, calc(var(--chip-w) * 0.08));
    --trade-chip-col-w: calc(9 * var(--chip-w) + 8 * var(--chip-gap) + 0.8rem);
  }
  .status-grid .trade-table      { table-layout: fixed; width: calc(var(--trade-region-w) + var(--empire-box-w) + var(--trade-chip-col-w)); }
  .status-grid .trade-empire-col { width: var(--empire-box-w); }
  .status-grid .trade-chip-col   { width: var(--trade-chip-col-w); }
  .status-grid .trade-chips      { gap: var(--chip-gap); }
  .status-grid .trade-chip       { width: var(--chip-w); height: var(--chip-h); font-size: calc(var(--chip-h) * 0.5); }

  /* Leaderboard width is the sum of its columns — never its content. With a
     content-sized table, a tie rank like "=10" widened the leaderboard, which
     narrowed the timeline, which wrapped the age legend onto one more line and
     pushed the board past the bottom of a 1080p screen. Every leaderboard
     column is sized from the number font, so its widest value fits at every
     size: "=18" for rank, two digits for ADV / AST, three for the total.
     The census number columns (cities, population) work the same way. All
     factors leave room for wide system fonts (DejaVu Sans digits are ~11 %
     wider than Noto's). */
  .status-grid {
    --col-city: calc(var(--board-num-base) * 1.5 + 0.8rem);
    --col-census-pop: calc(var(--board-num-base) * 1.5 + 0.8rem);
    /* From the base number size (× the largest number scale, 1.15), not the
       scaled one: the width — and so the timeline's width — must not change
       with the player count either. */
    --col-rank: calc(var(--board-num-base) * 2.6 + 0.3rem);
    --col-adv-pts: calc(var(--board-num-base) * 1.5 + 0.8rem);
    --col-ast-pts: calc(var(--board-num-base) * 1.5 + 0.8rem);
    --col-total-vp: calc(var(--board-num-base) * 2.3 + 0.8rem);
  }
  .status-grid td.rank { padding-left: 0.15rem; padding-right: 0.15rem; }
  .status-grid .lb-table {
    width: calc(var(--col-rank) + var(--empire-box-w) + var(--col-adv-pts) + var(--col-ast-pts) + var(--col-total-vp));
  }

  /* The VP / Round axis under the timeline stays one line per cell — with a
     wide system font (DejaVu Sans, Linux's default) "17+" and "Round →"
     wrapped and made the axis 12 px taller at 1080p. */
  .status-ast tfoot td { white-space: nowrap; letter-spacing: -0.04em; }
}
@media (min-width: 192rem) and (min-height: 115rem) {
  .status-grid {
    --board-row-base: clamp(2.5rem, 4.3vh, 6rem);
    --board-name-base: clamp(1rem, 1.62vh, 2rem);
    --board-num-base: clamp(1rem, 1.75vh, 2.1rem);
    --board-sub: clamp(0.72rem, 1.02vh, 1.3rem);
    --board-head: clamp(0.75rem, 1.05vh, 1.3rem);
    /* 4K type already uses most of each column's width. */
    --text-scale-max: 1.1;
    --num-scale-max: 1;
  }
}
