/* Euria — "The Campaign Sheet"
 *
 * The whole interface is one printed sheet lit from above: warm paper, warm ink
 * for land, a single cool ink reserved for water, and one gold for anything the
 * player can commit. Nothing else earns a hue.
 *
 * Two type families, strictly divided:
 *   EB Garamond      everything a person READS   — names, instructions, log, prose
 *   Barlow Condensed everything a person COUNTS or CLICKS — numerals, labels, buttons
 */

* { box-sizing: border-box; margin: 0; padding: 0; }
[hidden] { display: none !important; }

:root {
  /* ---- Surfaces ---- */
  --paper-desk: #cbbb98;
  --paper-desk-bg:
    radial-gradient(120% 90% at 50% 0%, rgba(255, 248, 230, 0.55), rgba(120, 96, 58, 0.22)),
    #cbbb98;
  --paper-sheet: linear-gradient(160deg, #f2ead5, #e7dcc0);
  --paper-bar: linear-gradient(180deg, #efe5cc, #e6dabc);
  --paper-rail: linear-gradient(180deg, #e9dec3, #e3d6b6);
  --paper-raised: linear-gradient(180deg, #f0e6cd, #e7dbbd);
  --paper-well: rgba(255, 251, 238, 0.55);
  --paper-token: #f8f1de;

  /* ---- Ink and rules ---- */
  --ink: #2f281d;              /* names, headings, numerals on paper — 12.8:1 */
  --ink-body: #5f5340;         /* instructions, log lines, descriptions — 5.9:1 */
  --ink-muted: #8b7a58;        /* 2.9:1 — TRACKED BARLOW LABELS ONLY, never a sentence */
  --ink-strong-rule: #6d5c3c;  /* sheet frame, landmass outlines, ordinary borders */
  --ink-rule: #b8a67e;         /* structural borders: bar, rail, panel edges */
  --ink-rule-soft: #cbbb95;    /* dividers inside a rail; dotted log separators */
  --ink-hairline: #c3ab77;     /* every secondary control border, every cell edge */
  --ink-numeral: #fdf6e4;      /* figures reversed out of a deep — army discs, hulls */

  /* ---- Semantic ink: four meanings, four inks, no others ---- */
  --gold: #b3812c;             /* COMMIT — the one action that spends something */
  --gold-deep: #7d6535;
  --gold-ring: #8a5f14;        /* selection on the sheet */
  --alert: #a44a35;            /* HOSTILE — attack, betrayal, capital lost, forced */
  --alert-ink: #8b3f2c;
  --friendly: #66743c;         /* FRIENDLY — fortify, unload, allied, income gained */
  --sea-ink: #6f8592;          /* WATER — nothing on land may use this */

  /* ---- Geometry, edges, elevation ---- */
  --radius: 2px;               /* paper does not round; this is the printer's bleed */
  --lift-inset: 0 1px 0 rgba(255, 255, 255, 0.35) inset;
  --lift-float: 0 18px 40px -18px rgba(60, 44, 20, 0.7);
  --lift-modal: 0 24px 60px -20px rgba(30, 22, 10, 0.8);
  --lift-sheet: drop-shadow(0 10px 24px rgba(60, 44, 20, 0.35));

  /* ---- Type ---- */
  --font-read: 'EB Garamond', Georgia, 'Iowan Old Style', 'Times New Roman', serif;
  --font-count: 'Barlow Condensed', 'Helvetica Neue Condensed', 'Arial Narrow',
                system-ui, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, Menlo, Consolas, monospace;

  /* Presentation motion multiplier; set from the pacing selector (Normal 1,
   * Fast 0.4, Instant 0) so "Instant" is genuinely instant. */
  --motion: 1;
}

html, body { height: 100%; height: 100dvh; }
body {
  background: var(--paper-desk-bg);
  color: var(--ink);
  font-family: var(--font-read);
  font-size: 15px;
  line-height: 1.45;
  overflow: hidden;
}

/* ---- Controls: four tiers, and no fifth ---- */

button {
  font-family: var(--font-count);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink);
  background: transparent;
  border: 1px solid var(--ink-hairline);
  border-radius: var(--radius);
  padding: 9px 14px;
  cursor: pointer;
  transition: background calc(0.12s * var(--motion)),
              border-color calc(0.12s * var(--motion)),
              transform calc(0.06s * var(--motion)),
              opacity calc(0.15s * var(--motion));
}
button:hover:not(:disabled) { background: rgba(255, 251, 238, 0.5); border-color: var(--gold-deep); }
button:active:not(:disabled) { transform: translateY(1px); }
button:focus-visible { outline: 2px solid var(--gold-ring); outline-offset: 2px; }
/* Disabled sits back but is never hidden — the player must see the control exists. */
button:disabled { opacity: 0.55; cursor: default; }

button.primary {
  background: var(--gold);
  border-color: var(--gold-deep);
  color: var(--ink-numeral);
  font-weight: 600;
  box-shadow: var(--lift-inset);
}
button.primary:hover:not(:disabled) { background: #c08e33; border-color: var(--gold-deep); }

button.danger {
  background: var(--alert);
  border-color: var(--alert-ink);
  color: var(--ink-numeral);
  font-weight: 600;
  box-shadow: var(--lift-inset);
}
button.danger:hover:not(:disabled) { background: #b35540; border-color: var(--alert-ink); }

/* Quiet: top-bar controls. Border at 15% until hover. */
button.quiet {
  border-color: rgba(109, 92, 60, 0.15);
  color: var(--ink-body);
}
button.quiet:hover:not(:disabled) { border-color: var(--ink-hairline); }

select, input[type="text"] {
  font-family: var(--font-read);
  font-size: 15px;
  color: var(--ink);
  background: var(--paper-well);
  border: 1px solid var(--ink-hairline);
  border-radius: var(--radius);
  padding: 8px 10px;
  width: 100%;
}
select:focus-visible, input[type="text"]:focus-visible {
  outline: 2px solid var(--gold-ring);
  outline-offset: 1px;
}

/* ---- Setup screen ---- */
#setup-screen, #home-screen, #lobby-screen {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow-y: auto;
  background: var(--paper-desk-bg);
}
.setup-card {
  width: 440px;
  background: var(--paper-raised);
  border: 1px solid var(--ink-rule);
  border-radius: var(--radius);
  padding: 36px 40px 40px;
  box-shadow: var(--lift-modal);
}
.setup-card h1 {
  font-family: var(--font-read);
  font-weight: 400;
  font-size: 46px;
  letter-spacing: 0.2em;
  text-align: center;
  color: var(--ink);
}
.setup-card .tagline {
  text-align: center;
  font-style: italic;
  color: var(--ink-body);
  margin: 4px 0 26px;
}
.setup-card label {
  display: block;
  font-family: var(--font-count);
  font-weight: 500;
  font-size: 10.5px;
  color: var(--ink-muted);
  text-transform: uppercase;
  letter-spacing: 0.22em;
  margin: 18px 0 6px;
}
.setup-card .start-row { margin-top: 28px; }
.setup-card .start-row button { width: 100%; padding: 13px; font-size: 13px; }

#setup-seed { font-family: var(--font-mono); font-size: 13px; letter-spacing: 0.02em; }

/* The rule explanations are sentences, so they take the reading face — the
 * counting face is never set as a sentence. Needs to out-specify
 * `.setup-card label` above, which styles the field labels. */
.setup-card label.setup-check {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-family: var(--font-read);
  font-size: 14px;
  line-height: 1.4;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-body);
  margin: 10px 0 0;
  cursor: pointer;
}
.setup-check input { margin-top: 4px; accent-color: var(--gold); }

/* ---- Home: three doors ---- */

.home-doors { display: flex; flex-direction: column; gap: 10px; margin-top: 26px; }
.home-doors button { width: 100%; padding: 13px; font-size: 13px; }

/* A labelled rule, so "or join a friend" reads as a fork rather than a third
   option stacked under the other two. */
.home-or {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 22px 0 12px;
  font-family: var(--font-count);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--ink-muted);
}
.home-or::before, .home-or::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--ink-rule-soft);
}
.home-join { display: flex; gap: 8px; }
/* The code is read off a phone and typed in, so it is set in the mono face at
   a size that cannot be misread, and it accepts lowercase without complaint. */
#home-code {
  flex: 1;
  font-family: var(--font-mono);
  font-size: 19px;
  letter-spacing: 0.35em;
  text-align: center;
  text-transform: uppercase;
  padding: 10px 12px;
}
#home-join { padding: 10px 22px; }
.home-error {
  margin-top: 14px;
  color: var(--alert-ink);
  font-size: 14px;
  line-height: 1.4;
  text-align: center;
}

/* ---- Lobby ---- */

.lobby-card { width: 520px; }

.lobby-code-block { text-align: center; margin: 8px 0 4px; }
.lc-label {
  font-family: var(--font-count);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--ink-muted);
}
/* The one thing on this screen everybody else needs, so it is the biggest
   thing on it. */
.lc-code {
  display: block;
  width: 100%;
  background: var(--paper-well);
  border: 1px solid var(--ink-hairline);
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 44px;
  letter-spacing: 0.3em;
  text-indent: 0.3em;
  color: var(--ink);
  padding: 12px 0 10px;
  margin: 6px 0 5px;
  cursor: pointer;
}
.lc-code:hover { border-color: var(--gold); }
.lc-hint { font-family: var(--font-read); font-style: italic; color: var(--ink-body); font-size: 13px; }

.lobby-seats { display: flex; flex-direction: column; gap: 6px; }
.lobby-seat {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  background: var(--paper-well);
  border: 1px solid var(--ink-hairline);
  border-radius: var(--radius);
  min-height: 44px;
}
.lobby-seat.me { border-color: var(--gold); }
.lobby-seat.empty { background: none; border-style: dashed; }
.lobby-seat.gone { opacity: 0.55; }
.ls-swatch { width: 14px; height: 14px; border-radius: 50%; flex: none; }
.ls-name {
  font-family: var(--font-read);
  font-size: 15px;
  color: var(--ink);
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ls-open { color: var(--ink-muted); font-style: italic; }
.ls-input {
  flex: 1;
  min-width: 0;
  font-family: var(--font-read);
  font-size: 15px;
  padding: 4px 8px;
}
.ls-tag {
  font-family: var(--font-count);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--ink-muted);
  flex: none;
}
.ls-gone { color: var(--alert-ink); }
/* align-items matters: without it the swatches stretch to the row's height and
   the circles become ovals the moment the row wraps on a phone. */
.ls-colors { display: flex; align-items: center; gap: 4px; flex: none; }
.ls-color {
  width: 16px;
  height: 16px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--ink-hairline);
  cursor: pointer;
}
.ls-color.on { box-shadow: 0 0 0 2px var(--paper-raised), 0 0 0 3px var(--gold-ring); }
.ls-toggle {
  flex: none;
  font-size: 10.5px;
  padding: 5px 10px;
  letter-spacing: 0.12em;
}
.lobby-note, .lobby-status {
  font-family: var(--font-read);
  font-style: italic;
  color: var(--ink-body);
  font-size: 13px;
  text-align: center;
  margin-top: 12px;
  min-height: 18px;
}
.lobby-card .start-row { display: flex; gap: 10px; }

/* ---- Game layout ---- */
#game-screen {
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* ---- Top bar: standings, phase stepper, phase-end ---- */
#top-bar {
  height: 58px;
  min-height: 58px;
  flex: none;
  background: var(--paper-bar);
  border-bottom: 1px solid var(--ink-rule);
  box-shadow: var(--lift-inset), 0 6px 18px -14px rgba(60, 44, 20, 0.5);
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 16px;
  z-index: 5;
}
#player-strip {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
#player-strip::-webkit-scrollbar { display: none; }

.player-chip {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 5px 12px 5px 9px;
  border-radius: var(--radius);
  border: 1px solid transparent;
  background: var(--paper-well);
  white-space: nowrap;
  /* Chips SHRINK rather than scroll. Standings are one of the three registers
     that must be continuously present, so at six players the names ellipsize
     and every player stays on screen — losing a name is recoverable, losing a
     whole player from the standings is not. */
  flex: 0 1 auto;
  min-width: 148px;    /* below this a name stops being a name */
  transition: opacity calc(0.2s * var(--motion));
}
.player-chip .p-chip {
  width: 12px; height: 12px;
  border-radius: 50%;
  flex: none;
  box-shadow: 0 0 0 1.5px var(--paper-token), 0 0 0 2.5px rgba(70, 52, 24, 0.35);
}
.player-chip .pc-main { min-width: 0; overflow: hidden; }
/* The count never truncates — it is the reason the chip exists. */
.player-chip .pc-right { text-align: right; flex: none; }
.player-chip .pc-name {
  font-family: var(--font-read);
  font-size: 15px;
  letter-spacing: 0.02em;
  color: var(--ink);
  display: flex;
  align-items: center;
  gap: 5px;
  overflow: hidden;
}
.player-chip .pc-label { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.player-chip .pc-sub { overflow: hidden; text-overflow: ellipsis; }
.player-chip .pc-flag { font-size: 11px; }
.player-chip .pc-armies {
  font-family: var(--font-count);
  font-weight: 600;
  font-size: 25px;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.player-chip .pc-sub {
  font-family: var(--font-count);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}
.player-chip .pc-sub b { color: var(--ink-body); font-weight: 500; }

/* The active player: an inset ring in their own deep, breathing. */
.player-chip.current { box-shadow: 0 0 0 2px var(--chip-deep, var(--gold)) inset; }
.player-chip.current .pc-name { font-weight: 500; }
.player-chip.you .pc-name { letter-spacing: 0.04em; }
.player-chip.dead { opacity: 0.35; }
.player-chip.dead .pc-name { text-decoration: line-through; }
/* Government-in-exile: no land, but a fleet still afloat — still playing. */
.player-chip.exile { border-style: dashed; border-color: var(--ink-hairline); }

/* ---- Nation popover ---- */
#nation-popover {
  position: absolute;
  top: 6px;
  background: var(--paper-raised);
  border: 1px solid var(--ink-rule);
  border-radius: var(--radius);
  padding: 12px 14px;
  font-size: 14px;
  z-index: 8;
  min-width: 200px;
  box-shadow: var(--lift-float);
  pointer-events: none;
  animation: fadeUp calc(0.22s * var(--motion)) ease;
}
#nation-popover .np-title {
  font-family: var(--font-read);
  font-size: 17px;
  letter-spacing: 0.06em;
  color: var(--ink);
  margin-bottom: 8px;
}
#nation-popover .np-persona {
  font-style: italic;
  color: var(--ink-strong-rule);
  margin: -2px 0 8px;
  line-height: 1.35;
}
#nation-popover .np-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 18px;
  color: var(--ink-body);
  padding: 3px 0;
}
#nation-popover .np-row small {
  font-family: var(--font-count);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
#nation-popover .np-row b {
  font-family: var(--font-count);
  font-weight: 600;
  font-size: 17px;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
#nation-popover .np-row.hostile { color: var(--alert-ink); }
#nation-popover .np-row.total {
  border-top: 1px solid var(--ink-rule-soft);
  margin-top: 5px;
  padding-top: 7px;
}
#nation-popover .np-row.total b { font-size: 22px; color: var(--gold-deep); }
.p-chip {
  width: 14px; height: 14px;
  border-radius: 50%;
  flex: none;
  box-shadow: 0 0 0 1.5px var(--paper-token), 0 0 0 2.5px rgba(70, 52, 24, 0.35);
}

/* ---- Phase stepper and phase-end (top bar) ---- */
#phase-stepper { display: flex; align-items: center; gap: 4px; flex: none; }
#phase-stepper .step {
  font-family: var(--font-count);
  font-weight: 500;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--ink-muted);
  padding: 5px 10px;
  border-radius: var(--radius);
  transition: color calc(0.2s * var(--motion)), background calc(0.2s * var(--motion));
}
#phase-stepper .step:not(:last-child)::after {
  content: '·';
  margin-left: 8px;
  color: var(--ink-hairline);
}
#phase-stepper .step.active { color: var(--ink-numeral); background: var(--gold-deep); }
#phase-stepper .step.done { color: var(--friendly); }
/* Not your turn: the obligation register steps back, but the board stays at
   full strength — you are meant to be watching it. */
#action-bar.bot-turn #phase-stepper { opacity: 0.62; }

#btn-phase-end { flex: none; }

#btn-log { position: relative; flex: none; padding: 9px 12px; }
#log-badge {
  position: absolute;
  top: -6px; right: -6px;
  background: var(--alert);
  color: var(--ink-numeral);
  border-radius: 9px;
  font-family: var(--font-count);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  padding: 1px 5px;
  min-width: 16px;
}

/* ---- Orders bar (footer) ---- */
#action-bar {
  height: 68px;
  min-height: 68px;
  flex: none;
  z-index: 5;
  background: var(--paper-bar);
  border-top: 1px solid var(--ink-rule);
  box-shadow: 0 -6px 18px -14px rgba(60, 44, 20, 0.5);
  display: flex;
  align-items: center;
  gap: 22px;
  padding: 0 18px;
}
#action-bar.bot-turn #turn-info { opacity: 0.62; }

#turn-info { flex: 1; min-width: 0; }
#phase-title {
  font-family: var(--font-read);
  font-size: 17px;
  letter-spacing: 0.06em;
  color: var(--ink);
}
/* Instructions WRAP. They never clip — an ellipsis on a rule explanation is
 * the difference between a game you can learn and one you cannot. */
#phase-help {
  font-family: var(--font-read);
  font-size: 14px;
  line-height: 1.35;
  color: var(--ink-body);
  max-height: 2.7em;
  overflow: hidden;
}
#phase-help b { font-weight: 600; color: var(--ink); }

#place-controls { display: flex; align-items: center; gap: 14px; flex: none; }
#place-counter {
  font-family: var(--font-count);
  font-weight: 600;
  font-size: 34px;
  line-height: 1;
  color: var(--gold-deep);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
#place-counter b { font-weight: 600; }
#place-counter .pc-unit {
  display: block;
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

#amt-seg { display: flex; height: 44px; }
#amt-seg button {
  border-radius: 0;
  padding: 0 13px;
  font-size: 12px;
  border-right-width: 0;
}
#amt-seg button:first-child { border-radius: var(--radius) 0 0 var(--radius); }
#amt-seg button:last-child { border-radius: 0 var(--radius) var(--radius) 0; border-right-width: 1px; }
#amt-seg button.on {
  background: var(--gold);
  border-color: var(--gold-deep);
  color: var(--ink-numeral);
  font-weight: 600;
  box-shadow: var(--lift-inset);
}

#action-buttons { display: flex; gap: 8px; flex: none; }
#action-buttons button { white-space: nowrap; }

/* A held set is armies you have not collected. The button says so: the badge
   carries the payout, the gold ring marks it as ready, and the ring breathes
   only in a phase where the trade is actually open to you. Under
   prefers-reduced-motion the breathing stops and the ring stays. */
#action-buttons button.has-set {
  border-color: var(--gold-deep);
  box-shadow: 0 0 0 1px var(--gold-deep);
}
#action-buttons button.has-set.alert {
  animation: setReady calc(1.9s * var(--motion)) ease-in-out infinite;
}
@keyframes setReady {
  0%, 100% { box-shadow: 0 0 0 1px var(--gold-deep); }
  50%      { box-shadow: 0 0 0 4px rgba(179, 129, 44, 0.28); }
}
.btn-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 5px;
  border-radius: 9px;
  background: var(--gold-deep);
  color: var(--ink-numeral);
  font-family: var(--font-count);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
}

/* ---- Log drawer ---- */
/* Starts BELOW the top bar. The phase-end control and the standings live up
   there and must never be covered — an overlay that hides the control ending
   your turn is worse than no overlay. */
#log-drawer {
  position: fixed;
  top: 58px; right: 0; bottom: 0;
  width: 318px;
  max-width: 90vw;
  background: var(--paper-rail);
  border-left: 1px solid var(--ink-rule);
  z-index: 9;
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform calc(0.22s * var(--motion)) ease;
  box-shadow: var(--lift-float);
}
#log-drawer.open { transform: translateX(0); }
#log-drawer[hidden] { display: flex; }   /* animate via transform, not display */
.drawer-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 12px;
  border-bottom: 1px solid var(--ink-rule);
  font-family: var(--font-count);
  font-size: 10.5px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.drawer-head select { width: auto; padding: 5px 8px; font-size: 13px; }
.drawer-head button { padding: 6px 10px; font-size: 11px; }
#seed-display {
  font-family: var(--font-mono);
  color: var(--ink-body);
  font-size: 11px;
  letter-spacing: 0;
  text-transform: none;
  max-width: 96px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
  flex: 1;
}
#seed-display:hover { color: var(--ink); }

.drawer-opts {
  flex: none;
  padding: 9px 14px;
  border-bottom: 1px solid var(--ink-rule);
}
.opt-check {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  font-family: var(--font-count);
  font-size: 10.5px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.opt-check:hover { color: var(--ink-body); }
.opt-check input { accent-color: var(--gold); }

/* Your own nation breakdown, permanent. Opponents keep the hover popover;
   this is the one you consult constantly. */
#drawer-nations {
  flex: none;
  padding: 12px 14px 14px;
  border-bottom: 1px solid var(--ink-rule);
  font-size: 14px;
  color: var(--ink-body);
}
#drawer-nations:empty { display: none; }
#drawer-nations .np-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 14px;
  padding: 4px 0;
}
#drawer-nations .np-row small {
  font-family: var(--font-count);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
#drawer-nations .np-row b {
  font-family: var(--font-count);
  font-weight: 600;
  font-size: 17px;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
#drawer-nations .np-row.hostile { color: var(--alert-ink); }
#drawer-nations .np-row.total {
  border-top: 1px solid var(--ink-rule-soft);
  margin-top: 6px;
  padding-top: 8px;
}
#drawer-nations .np-row.total b { font-size: 22px; color: var(--gold-deep); }
.rail-head {
  font-family: var(--font-count);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-bottom: 8px;
}

#log {
  flex: 1;
  overflow-y: auto;
  padding: 10px 14px;
  font-family: var(--font-read);
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-body);
}
#log .entry {
  padding: 5px 0 5px 16px;
  position: relative;
  border-bottom: 1px dotted var(--ink-rule-soft);
}
#log .entry b { font-weight: 600; color: var(--ink); }
/* The dot's SHAPE encodes what kind of thing happened, so the log is skimmable
   without being read. Colour is not doing this job — there is no fifth ink. */
#log .entry.income::before,
#log .entry.diplomacy::before,
#log .entry.territory::before,
#log .entry.combat::before {
  content: '';
  position: absolute;
  left: 2px; top: 11px;
  width: 6px; height: 6px;
  background: var(--ink-muted);
}
#log .entry.income::before,
#log .entry.diplomacy::before { border-radius: 50%; }
#log .entry.territory::before { border-radius: 1px; }
#log .entry.combat::before { transform: rotate(45deg); }
#log .entry.round-marker {
  font-family: var(--font-count);
  font-size: 11px;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--ink-muted);
  border-bottom: none;
  border-top: 1px solid var(--ink-rule);
  margin-top: 8px;
  padding: 8px 0 4px;
}

/* ---- Log ticker (board overlay) ---- */
#log-ticker {
  position: absolute;
  left: 22px;
  bottom: 20px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 5px;
  pointer-events: none;
  z-index: 3;
  max-width: 46%;
}
.tick-entry {
  font-family: var(--font-read);
  font-size: 15px;
  color: var(--ink);
  text-shadow:
     0 0 5px var(--paper-token), 0 0 5px var(--paper-token),
     0 0 9px var(--paper-token), 0 0 14px var(--paper-token);
  animation: tickFade calc(6s * var(--motion)) forwards;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}
.tick-entry b { font-weight: 600; }
@keyframes tickFade {
  0% { opacity: 0; transform: translateY(5px); }
  6% { opacity: 1; transform: translateY(0); }
  80% { opacity: 1; }
  100% { opacity: 0; }
}

/* ---- Turn banner ---- */
/* ---- Capital countdown ----------------------------------------------------
   A notice, not a control: it sits over the top of the sheet and passes every
   click through to the territories underneath, because the deadline it is
   announcing is answered by clicking one of them. Two states — counting, and
   due — and the second one is the only place on the board besides the commit
   buttons that is allowed to use the gold. */
#capital-countdown {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 7;
  display: flex;
  align-items: center;
  gap: 13px;
  max-width: min(540px, 88%);
  padding: 9px 15px 9px 12px;
  background: var(--paper-raised);
  border: 1px solid var(--ink-rule);
  border-radius: var(--radius);
  box-shadow: var(--lift-float), var(--lift-inset);
  pointer-events: none;
  animation: fadeUp calc(0.3s * var(--motion)) ease;
}
#capital-countdown .cc-seal {
  font-size: 25px;
  line-height: 1;
  color: var(--ink-muted);
  flex: none;
  transition: color calc(0.3s * var(--motion));
}
#capital-countdown .cc-body { min-width: 0; }
#capital-countdown .cc-label {
  font-family: var(--font-count);
  font-weight: 600;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.24em;
  color: var(--ink-muted);
}
#capital-countdown .cc-value {
  font-family: var(--font-read);
  font-size: 17px;
  line-height: 1.25;
  color: var(--ink);
  margin-top: 1px;
}
#capital-countdown .cc-value b {
  font-family: var(--font-count);
  font-weight: 600;
  font-size: 21px;
  font-variant-numeric: tabular-nums;
  color: var(--gold-deep);
}
#capital-countdown .cc-note {
  font-family: var(--font-read);
  font-style: italic;
  font-size: 12.5px;
  line-height: 1.3;
  color: var(--ink-body);
  margin-top: 2px;
}
/* One pip per build round: filled while the turn is still yours to use,
   hollow once it is spent. Three shapes on a rail read as a countdown at a
   glance, which the numeral alone does not. */
#capital-countdown .cc-pips { display: flex; gap: 5px; flex: none; margin-left: 2px; }
#capital-countdown .cc-pips i {
  width: 9px; height: 9px;
  border-radius: 50%;
  border: 1.5px solid var(--gold-deep);
  transition: background calc(0.3s * var(--motion)), opacity calc(0.3s * var(--motion));
}
#capital-countdown .cc-pips i.left { background: var(--gold-deep); }
#capital-countdown .cc-pips i.spent { background: none; opacity: 0.35; }
/* Due: the turn has arrived. Gold frame, gold seal, and a slow pulse — loud
   enough to be unmissable, slow enough not to nag while you are deciding. */
#capital-countdown.due {
  border-color: var(--gold);
  box-shadow: var(--lift-float), var(--lift-inset), 0 0 0 1px var(--gold) inset;
  animation: fadeUp calc(0.3s * var(--motion)) ease,
             capitalDue calc(2.4s * var(--motion)) ease-in-out calc(0.3s * var(--motion)) infinite;
}
#capital-countdown.due .cc-seal { color: var(--gold); }
#capital-countdown.due .cc-label { color: var(--gold-deep); }
/* No pips once the clock has run out: three empty rings next to an
   instruction is a countdown with nothing left to count. */
#capital-countdown.due .cc-pips { display: none; }
@keyframes capitalDue {
  0%, 100% { box-shadow: var(--lift-float), var(--lift-inset), 0 0 0 1px var(--gold) inset; }
  50% { box-shadow: var(--lift-float), var(--lift-inset), 0 0 0 3px rgba(179, 129, 44, 0.34); }
}

#turn-banner {
  position: absolute;
  top: 34%;
  left: 50%;
  transform: translateX(-50%);
  pointer-events: none;
  z-index: 6;
  font-family: var(--font-read);
  font-weight: 400;
  letter-spacing: 0.08em;
  text-align: center;
  animation: bannerIn calc(1.5s * var(--motion)) ease forwards;
  text-shadow:
     0 0 8px var(--paper-token), 0 0 8px var(--paper-token),
     0 0 18px var(--paper-token), 0 0 30px var(--paper-token);
}
#turn-banner.banner-you { font-size: 38px; color: var(--ink); }
#turn-banner.banner-bot { font-size: 22px; color: var(--ink-body); font-style: italic; }
@keyframes bannerIn {
  0% { opacity: 0; transform: translateX(-50%) translateY(10px); }
  12% { opacity: 1; transform: translateX(-50%) translateY(0); }
  75% { opacity: 1; }
  100% { opacity: 0; transform: translateX(-50%) translateY(-6px); }
}

/* ---- Board: the sheet on the desk ---- */
#board-wrap {
  flex: 1 1 0;
  min-height: 0;
  min-width: 0;
  overflow: hidden;
  position: relative;
  padding: 14px;                 /* desk shows through: the sheet is an object */
  background: var(--paper-desk-bg);
}
#board {
  width: 100%;
  height: 100%;
  display: block;
  filter: var(--lift-sheet);
}

.continent-label {
  font-family: var(--font-read);
  font-size: 37px;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  fill: var(--ink-strong-rule);
  opacity: 0.42;
  text-anchor: middle;
  pointer-events: none;
}
.continent-label.island { font-size: 21px; letter-spacing: 0.24em; }

/* ---- Territories ---- */
/* NO stroke here. The nation-state border (solid / dashed / faint) is set as an
 * attribute in updateBoard for the same reason the fill is — highlight()
 * rewrites the class attribute wholesale on every refresh, so state may never
 * live in a class. The selection-role rules below DO set stroke in CSS, which
 * is correct: a CSS rule beats a presentation attribute, so a selection ring
 * cleanly overrides the nation border underneath it. */
.territory {
  cursor: default;
  transition: fill calc(0.3s * var(--motion)) ease,
              fill-opacity calc(0.2s * var(--motion)) ease;
}
.territory.selectable { cursor: pointer; }
/* Out of reach: not a sixth ring — the absence of one, plus a step back.
 * Applied to everything not participating while a selection is open. */
.territory.dimmed { fill-opacity: 0.62; }
.territory.selectable:hover { filter: brightness(1.06); }
/* Every selection role must reset BOTH stroke-dasharray and stroke-opacity.
 * The nation-state border sets them as attributes, and a role that only
 * overrode the colour would inherit a faint dashed edge from a tile that
 * happens to be outside a nation. */
.territory.selected {
  stroke: var(--gold-ring);
  stroke-width: 9;
  stroke-dasharray: none;    /* exactly one at a time, and static, so the */
  stroke-opacity: 1;         /* marching targets read as the moving thing */
}
.territory.atk-target {
  stroke: var(--alert);
  stroke-width: 6.4;
  stroke-dasharray: 25 16;
  stroke-opacity: 1;
  cursor: crosshair;
  animation: marchAnts calc(1.4s / max(var(--motion), 0.001)) linear infinite;
}
.territory.fort-target {
  stroke: var(--friendly);
  stroke-width: 6.4;
  stroke-dasharray: 25 16;
  stroke-opacity: 1;
  cursor: pointer;
  animation: marchAnts calc(1.4s / max(var(--motion), 0.001)) linear infinite;
}
@keyframes marchAnts { to { stroke-dashoffset: -82; } }

/* Something here just changed — the one signal that makes a fast bot turn
   legible. A ring in the actor's own ink, expanding out of the anchor. It is
   positioned with cx/cy attributes and scaled about that centre, so unlike the
   fleet bob it can safely animate transform. */
.puff {
  fill: none;
  stroke-width: 5;
  pointer-events: none;
  transform-box: fill-box;
  transform-origin: center;
  animation: puff calc(0.62s * var(--motion)) cubic-bezier(0.2, 0.6, 0.3, 1) forwards;
}
@keyframes puff {
  0% { transform: scale(0.45); opacity: 0.9; }
  100% { transform: scale(2.5); opacity: 0; }
}

.army-badge circle {
  stroke: var(--paper-token);
  stroke-width: 2.5;
  pointer-events: none;
}
.army-badge text {
  font-family: var(--font-count);
  font-weight: 600;
  fill: var(--ink-numeral);
  font-size: 28px;
  text-anchor: middle;
  dominant-baseline: central;
  pointer-events: none;
  font-variant-numeric: tabular-nums;
}
/* Three digits. A presentation attribute cannot do this — the rule above would
 * win — so the size change has to come from a class. */
.army-badge text.crowded { font-size: 21px; }
.territory-label {
  font-family: var(--font-read);
  fill: var(--ink);
  font-size: 21px;
  letter-spacing: 0.04em;
  text-anchor: middle;
  pointer-events: none;
  paint-order: stroke;
  stroke: rgba(242, 234, 213, 0.85);
  stroke-width: 4.5px;
}

.nation-outline {
  fill: none;
  stroke-width: 5;
  stroke-opacity: 0.9;
  stroke-linejoin: round;
  pointer-events: none;
}
/* The star is always the FOUNDER's deep. A heavier halo than this eats the
   glyph and the seat stops reading as anyone's in particular. */
.capital-star {
  font-size: 30px;
  text-anchor: middle;
  pointer-events: none;
  paint-order: stroke;
  stroke: var(--paper-token);
  stroke-width: 2.8px;
}
/* A seat named in the founding round but not yet in force. Ghosted, because
   during that one round it is a mark on the map and nothing more: no third
   die, no capital rate. It solidifies when the last empire has named one. */
.capital-star.designate { opacity: 0.42; }
/* A seat held by someone other than its founder: a dashed medallion in the
   founder's deep. Its presence means "this capital has been taken". */
.capital-ring {
  fill: var(--paper-token);
  fill-opacity: 0.75;
  stroke-width: 3.5;
  stroke-dasharray: 7 5;
  pointer-events: none;
}

/* ---- Water. The ocean is the paper: no water fill, anywhere. ---- */
.sea-zone {
  fill: rgba(111, 133, 146, 0);
  stroke: none;
  pointer-events: all;   /* required: the resting state paints nothing */
  transition: fill calc(0.12s * var(--motion));
}
.sea-zone:hover { fill: rgba(111, 133, 146, 0.05); }
.sea-zone.selectable { cursor: pointer; }
.sea-zone.selectable:hover { fill: rgba(111, 133, 146, 0.09); }
.sea-zone.selected { stroke: var(--gold-ring); stroke-width: 7; }
.sea-zone.sea-target {
  stroke: var(--alert);
  stroke-width: 6.4;
  stroke-dasharray: 25 16;
  cursor: crosshair;
  animation: marchAnts calc(1.4s / max(var(--motion), 0.001)) linear infinite;
}
.sea-zone.sail-target { cursor: pointer; }
.sea-zone.build-slot { cursor: pointer; }

.sea-div-layer { pointer-events: none; }
.sea-div {
  fill: none;
  stroke: var(--sea-ink);
  stroke-opacity: 0.4;
  stroke-width: 4.4;
  stroke-dasharray: 5 18;
  stroke-linecap: round;
}
.sea-label {
  font-family: var(--font-read);
  font-style: italic;
  font-size: 21px;
  letter-spacing: 0.1em;
  text-anchor: middle;
  fill: var(--sea-ink);
  fill-opacity: 0.62;
  pointer-events: none;
}

/* Sea routes are LAND-graph edges that happen to cross water, so they are drawn
   in WARM ink. Cool ink here would read as a sea-zone mark. */
.adj-line { stroke: var(--gold-deep); stroke-width: 4.4; stroke-dasharray: 4 11; stroke-linecap: round; }
.adj-line.sea { stroke-opacity: 0.55; }
.adj-line.strait { stroke-opacity: 0.8; stroke-dasharray: 4 7; }
.strait-tick { stroke: var(--gold-deep); stroke-opacity: 0.5; stroke-width: 3.5; stroke-linecap: round; }

/* ---- Fleets ---- */
.fleet-layer, .ghost-layer { pointer-events: none; }
.ship-hull { stroke: rgba(47, 40, 29, 0.55); stroke-width: 1.8; stroke-linejoin: round; }
.ship-mast { stroke: var(--ink); stroke-opacity: 0.75; stroke-width: 2.6; stroke-linecap: round; }
.ship-sail { stroke: rgba(47, 40, 29, 0.4); stroke-width: 1.4; stroke-linejoin: round; }
/* The bob IS the affordance: a hull that may still sail this turn moves, one
   that has sailed is still. Its non-moving state is a fact, not a fallback,
   which is why reduced motion can stop it without losing information. */
.ship-bob.can-sail { animation: bob calc(2.4s / max(var(--motion), 0.001)) ease-in-out infinite; }
@keyframes bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-4.4px); }
}

/* Sea-graph destinations: a disc at the zone pole, not an outline of the whole
   zone — outlining is what a SELECTED zone does. */
.sail-mark-ring {
  fill: rgba(111, 133, 146, 0.14);
  stroke: var(--sea-ink);
  stroke-width: 4.4;
  stroke-dasharray: 9 9;
}
.sail-mark-dot { fill: var(--sea-ink); }
.build-mark-ring {
  fill: rgba(102, 116, 60, 0.14);
  stroke: var(--friendly);
  stroke-width: 4.4;
  stroke-dasharray: 9 9;
}
.ship-ghost path { stroke: var(--friendly); stroke-width: 3.2; stroke-dasharray: 4 5; opacity: 0.85; }

/* Coast glow and shipping lanes are decoration — without this their strokes are
   hit regions, and the coast's is 18px wide around every shoreline, exactly
   where a player reaches to click the sea. */
.deco-layer { pointer-events: none; }

/* Build-source picker */
.build-sources { display: flex; flex-direction: column; gap: 6px; margin: 12px 0; }
.build-sources .build-src {
  width: 100%;
  text-align: left;
  font-family: var(--font-read);
  font-size: 15px;
  letter-spacing: 0.02em;
  text-transform: none;
}
.bs-cost {
  font-family: var(--font-count);
  float: right;
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}

/* ---- Terrain: mountains, rivers, bridges (static per map) ---- */
.terrain-layer { pointer-events: none; }
.ridge-shadow { fill: none; stroke: rgba(95, 74, 44, 0.25); stroke-width: 12; stroke-linecap: round; stroke-linejoin: round; }
.mtn { fill: #5f4a2c; stroke: rgba(47, 40, 29, 0.5); stroke-width: 1; stroke-linejoin: round; }
.mtn-lit { fill: rgba(255, 248, 230, 0.3); }
.river-under { fill: none; stroke: rgba(242, 234, 213, 0.7); stroke-width: 14; stroke-linecap: round; stroke-linejoin: round; }
/* No stroke-width: the ribbon tapers toward its mouth and sets the gauge
   per segment as an attribute, which a rule here would override. */
.river { fill: none; stroke: var(--sea-ink); stroke-linecap: round; stroke-linejoin: round; }
.tree-crown { fill: #4f6340; stroke: rgba(47, 40, 29, 0.45); stroke-width: 0.9; stroke-linejoin: round; }
.tree-trunk { fill: #5a4a2e; }

/* ---- The paper treatment: four static passes ---- */
.sheet-pass { pointer-events: none; }
.graticule { fill: none; stroke: var(--ink-strong-rule); stroke-width: 1.4; stroke-dasharray: 2 12; stroke-opacity: 0.55; }
.grain { mix-blend-mode: multiply; }
.sheet-frame { fill: none; stroke: var(--ink-strong-rule); }

/* ---- Tooltip ---- */
#tooltip {
  position: absolute;
  pointer-events: none;
  background: var(--paper-raised);
  border: 1px solid var(--ink-rule);
  border-radius: var(--radius);
  padding: 10px 12px;
  font-family: var(--font-read);
  font-size: 14px;
  display: none;
  z-index: 5;
  max-width: 300px;
  box-shadow: var(--lift-float);
}
#tooltip .tt-name { font-size: 17px; letter-spacing: 0.06em; color: var(--ink); }
#tooltip .tt-sub { color: var(--ink-body); margin-top: 3px; line-height: 1.35; }
#tooltip .tt-sub b { color: var(--ink); font-weight: 600; }
/* Figures inside running copy take the counting face. */
.tt-num, #nation-popover .tt-num {
  font-family: var(--font-count);
  font-weight: 600;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.hostile { color: var(--alert-ink); }

/* ---- Micro-animations ---- */
.army-badge text.pop { animation: badgePop calc(0.35s * var(--motion)) cubic-bezier(0.34, 1.56, 0.64, 1); }
@keyframes badgePop {
  0% { font-size: 28px; }
  40% { font-size: 34px; }
  100% { font-size: 28px; }
}
.place-float {
  font-family: var(--font-count);
  font-weight: 600;
  font-size: 38px;
  text-anchor: middle;
  pointer-events: none;
  paint-order: stroke;
  stroke: var(--paper-token);
  stroke-width: 6px;
  animation: floatUp calc(0.9s * var(--motion)) ease-out forwards;
}
@keyframes floatUp {
  0% { opacity: 0; transform: translateY(4px); }
  15% { opacity: 1; }
  100% { opacity: 0; transform: translateY(-25px); }
}
@keyframes fadeUp {
  from { opacity: 0; transform: translateY(5px); }
  to { opacity: 1; transform: none; }
}
.key-hints {
  margin-top: 14px;
  text-align: right;
  font-family: var(--font-count);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.key-hints kbd {
  background: var(--paper-well);
  border: 1px solid var(--ink-hairline);
  border-bottom-width: 2px;
  border-radius: var(--radius);
  padding: 1px 5px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0;
}

.die.rolling { animation: dieRoll calc(0.28s * var(--motion)) ease; }
@keyframes dieRoll {
  0% { transform: translateY(-6px) rotate(-10deg); opacity: 0.4; }
  100% { transform: none; opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  #turn-banner { display: none !important; }
  /* Marching rings become static dashes; the pulse becomes a static ring. */
  .territory.atk-target, .territory.fort-target, .sea-zone.sea-target { animation: none !important; }
  .ship-bob.can-sail { animation: none !important; }
  .player-chip.current { box-shadow: 0 0 0 2px var(--chip-deep, var(--gold)) inset; }
}

/* ---- Modals ---- */
#modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(40, 32, 18, 0.42);   /* light: overlays refer to board state */
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
}
.modal {
  width: 520px;                          /* 440 could not hold the battle header */
  max-width: calc(100vw - 40px);
  max-height: calc(100vh - 40px);
  overflow-y: auto;
  background: var(--paper-raised);
  border: 1px solid var(--ink-rule);
  border-radius: var(--radius);
  padding: 28px 32px;
  box-shadow: var(--lift-modal);
  animation: modalIn calc(0.22s * var(--motion)) ease-out;
}
@keyframes modalIn {
  0% { opacity: 0; transform: translateY(6px); }
  100% { opacity: 1; transform: none; }
}
.modal h3 {
  font-family: var(--font-read);
  font-weight: 400;
  font-size: 19px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
  margin-bottom: 6px;
}
.modal .sub { color: var(--ink-body); font-size: 14px; margin-bottom: 16px; line-height: 1.4; }
.modal .sub b { color: var(--ink); font-weight: 600; }
.modal .modal-buttons { display: flex; gap: 8px; margin-top: 20px; justify-content: flex-end; }

/* defence breakdown: every die the defender rolls, and what bought it */
.def-note {
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--ink-body);
  background: var(--paper-well);
  border: 1px solid var(--ink-hairline);
  border-left: 3px solid var(--ink-muted);
  border-radius: var(--radius);
  padding: 9px 12px;
  margin-bottom: 14px;
}
.def-note.bonus { border-left-color: var(--alert-ink); }
.def-note .db-head { color: var(--ink); }
.def-note .db-head b {
  font-family: var(--font-count);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
.def-note.bonus .db-head b { color: var(--alert-ink); }
.db-rows { margin-top: 7px; border-top: 1px solid var(--ink-hairline); }
.db-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 3px 0;
  font-size: 12.5px;
}
.db-row span { flex: 1; min-width: 0; }
.db-row b {
  flex: none;
  font-family: var(--font-count);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--alert-ink);
}
.db-row.db-base { color: var(--ink-muted); }
.db-row.db-base b { color: var(--ink-muted); }
.db-cap {
  margin-top: 7px;
  font-size: 12.5px;
  font-style: italic;
  color: var(--ink-muted);
}
.db-cap b { font-style: normal; color: var(--ink); font-weight: 600; }

/* provocation: what attacking an ally costs you diplomatically */
.prov-note {
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--ink-body);
  background: var(--paper-well);
  border: 1px solid var(--ink-hairline);
  border-left: 3px solid var(--ink-muted);
  border-radius: var(--radius);
  padding: 9px 12px;
  margin-bottom: 14px;
}
.prov-note b { color: var(--ink); font-weight: 600; }
.prov-note.bad { border-left-color: var(--alert-ink); color: var(--alert-ink); }
.prov-note.bad b { color: var(--alert-ink); }
.prov-meter {
  display: flex;
  height: 5px;
  margin-top: 8px;
  border-radius: 3px;
  overflow: hidden;
  background: var(--ink-hairline);
}
.prov-meter i { display: block; height: 100%; }
.prov-meter .prov-have { background: var(--ink-muted); }
.prov-meter .prov-add { background: var(--alert-ink); }

/* battle */
.battle-sides { display: flex; align-items: stretch; gap: 12px; }
.battle-side {
  flex: 1;
  background: var(--paper-well);
  border: 1px solid var(--ink-hairline);
  border-radius: var(--radius);
  padding: 14px;
  text-align: center;
}
.battle-side .bs-title {
  font-family: var(--font-count);
  font-size: 10.5px;
  color: var(--ink-muted);
  text-transform: uppercase;
  letter-spacing: 0.22em;
}
.battle-side .bs-terr {
  font-family: var(--font-read);
  font-size: 17px;
  letter-spacing: 0.06em;
  margin: 3px 0 8px;
  color: var(--ink);
}
.battle-side .bs-armies {
  font-family: var(--font-count);
  font-size: 28px;
  font-weight: 600;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.battle-vs {
  display: flex;
  align-items: center;
  font-family: var(--font-count);
  font-size: 18px;
  color: var(--ink-muted);
}
.dice-row { display: flex; gap: 7px; justify-content: center; margin-top: 12px; min-height: 38px; }
.die {
  position: relative;
  width: 32px; height: 32px;
  border-radius: var(--radius);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-count);
  font-weight: 600; font-size: 18px;
  background: var(--paper-token);
  border: 1px solid var(--ink-hairline);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.die.def { background: #efe0d8; border-color: #cbab9c; }
/* Losing dice step back but stay legible — the pairing must survive the roll. */
.die.lose { opacity: 0.42; }
/* Which dice the defender would not have had. A player who never reads the
   header still sees five dice with two badges. */
.die-bonus {
  position: absolute;
  top: -7px; right: -7px;
  background: var(--alert);
  color: var(--ink-numeral);
  border-radius: 8px;
  font-family: var(--font-count);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.04em;
  padding: 1px 4px;
}
#battle-report {
  text-align: center;
  color: var(--ink-body);
  font-size: 14px;
  margin-top: 12px;
  min-height: 20px;
}

/* Amount control: stepper for the last army or two, slider for crossing a
   wide range. Both drive the same value. */
.stepper {
  display: grid;
  grid-template-columns: 44px 1fr 44px;
  align-items: center;
  gap: 12px;
  margin-top: 18px;
}
.stepper .step-btn {
  width: 44px; height: 44px;      /* the 44px hit-target floor */
  padding: 0;
  font-size: 20px;
  line-height: 1;
  letter-spacing: 0;
}
.stepper .step-value {
  font-family: var(--font-count);
  font-weight: 600;
  font-size: 44px;
  line-height: 1;
  text-align: center;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.stepper .step-range {
  grid-column: 1 / -1;
  text-align: center;
  font-family: var(--font-count);
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.stepper .step-slider {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 2px;
}
/* Drawn by hand rather than left to the browser: a default range brings its
   own blue and its own proportions, and this modal is the one place a stray
   system control would be most visible. `--fill` is set from JS on every
   change so the spent part of the track reads at a glance. */
.stepper .step-slider input[type="range"] {
  flex: 1;
  min-width: 0;
  height: 30px;                   /* a drag target you can hit while hurried */
  margin: 0;
  background: none;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
}
.stepper .step-slider input[type="range"]::-webkit-slider-runnable-track {
  height: 8px;
  border-radius: 4px;
  border: 1px solid var(--ink-hairline);
  background: linear-gradient(to right,
    var(--gold) var(--fill, 100%), var(--paper-well) var(--fill, 100%));
}
.stepper .step-slider input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 24px; height: 24px;
  margin-top: -9px;               /* centres the thumb on the 8px track */
  border-radius: 50%;
  background: var(--gold);
  border: 1px solid var(--gold-deep);
  box-shadow: var(--lift-inset);
}
.stepper .step-slider input[type="range"]::-moz-range-track {
  height: 8px;
  border-radius: 4px;
  border: 1px solid var(--ink-hairline);
  background: var(--paper-well);
}
.stepper .step-slider input[type="range"]::-moz-range-progress {
  height: 8px;
  border-radius: 4px;
  background: var(--gold);
}
.stepper .step-slider input[type="range"]::-moz-range-thumb {
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--gold);
  border: 1px solid var(--gold-deep);
}
.stepper .step-slider input[type="range"]:focus { outline: none; }
.stepper .step-slider input[type="range"]:focus-visible::-webkit-slider-thumb {
  box-shadow: 0 0 0 3px rgba(179, 129, 44, 0.35);
}
.stepper .step-slider input[type="range"]:focus-visible::-moz-range-thumb {
  box-shadow: 0 0 0 3px rgba(179, 129, 44, 0.35);
}
.stepper .step-end {
  font-family: var(--font-count);
  font-size: 12px;
  letter-spacing: 0.14em;
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}
.modal-note {
  margin-top: 14px;
  color: var(--alert-ink);
  font-size: 13.5px;
  line-height: 1.35;
}

/* cards */
/* The value table, stated once where the choice is made. Fixed values mean it
   is true for the whole game, so it can be a legend rather than a running
   commentary on the next rung. */
#cm-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  align-items: baseline;
  margin-top: 10px;
  padding: 7px 10px;
  border: 1px solid var(--ink-hairline);
  border-radius: var(--radius);
  background: var(--paper-well);
  font-size: 15px;
  color: var(--ink-body);
}
#cm-legend .tt-num { font-size: 14px; }
#cm-legend .cm-wild {
  font-family: var(--font-count);
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--ink-muted);
}
#cards-list { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.trade-card {
  width: 96px;
  border: 1px solid var(--ink-hairline);
  border-radius: var(--radius);
  background: var(--paper-well);
  padding: 11px 6px;
  text-align: center;
  cursor: pointer;
  user-select: none;
  opacity: 0.7;                      /* never hidden: the player is choosing */
  transition: opacity calc(0.15s * var(--motion)),
              border-color calc(0.15s * var(--motion));
}
.trade-card:hover { opacity: 0.9; }
.trade-card.selected-card {
  opacity: 1;
  border-color: var(--gold-deep);
  border-width: 2px;
  background: rgba(179, 129, 44, 0.12);
}
.trade-card .rc-icon { font-size: 22px; color: var(--ink); }
.trade-card .rc-type {
  font-family: var(--font-count);
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.22em;
  color: var(--ink-muted); margin-top: 3px;
}
.trade-card .rc-terr { font-size: 13px; margin-top: 5px; min-height: 26px; color: var(--ink-body); }
.trade-card .rc-owned {
  font-family: var(--font-count);
  color: var(--friendly); font-size: 10px; font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase;
}

/* diplomacy */
#dip-list { margin-top: 12px; max-height: 52vh; overflow-y: auto; }
.dip-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 2px;
  border-bottom: 1px solid var(--ink-rule-soft);
}
.dip-row .p-chip { margin-top: 4px; }
.dip-main { flex: 1; min-width: 0; }
.dip-name { font-family: var(--font-read); font-size: 17px; letter-spacing: 0.06em; color: var(--ink); }
.dip-sub { color: var(--ink-body); font-size: 13px; margin-top: 3px; }
.dip-sub b { color: var(--ink); font-weight: 600; }
.dip-record { color: var(--ink-muted); }
.dip-status { font-size: 13px; margin-top: 5px; color: var(--ink-body); }
.dip-status.ok { color: var(--friendly); }
.dip-status.warn { color: var(--alert-ink); }
/* Impossibilities and forecasts are italic — absence and hypothesis. */
.dip-status.none { font-style: italic; color: var(--ink-strong-rule); }
.dip-action { flex: none; align-self: center; text-align: center; }
.dip-action button { white-space: nowrap; }
.dip-hint {
  font-size: 11px;
  color: var(--ink-muted);
  margin-top: 4px;
  font-style: italic;
}

/* alliance markers on the player strip */
.ally-dots { display: inline-flex; align-items: center; gap: 3px; vertical-align: 1px; }
.ally-dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  display: inline-block;
  box-shadow: 0 0 0 1.5px var(--paper-token);
}
.ally-dot.breaking { opacity: 0.5; box-shadow: 0 0 0 1.5px var(--gold); }

/* game over */
#gameover-title {
  font-family: var(--font-read);
  font-size: 34px;
  letter-spacing: 0.02em;
  text-align: center;
  color: var(--ink);
  margin-bottom: 8px;
}
#gameover-sub { text-align: center; color: var(--ink-body); margin-bottom: 10px; }

/* ============================================================================
   TOUCH AND SMALL SCREENS
   ============================================================================
   The desktop layout above is the reference. Everything here is the same game
   rearranged for a hand, under three rules it never breaks:

   1. All six players stay on screen. The standings are one of the registers
      that must be continuously present, so chips shed their NAMES on a phone
      rather than shedding players -- a colour and a number is still a
      standing, an absent chip is not.
   2. The phase-END control stays at the opposite edge from the in-phase
      controls. On a phone that means it stays in the top bar while armies are
      placed at the bottom, which is also where a thumb rests -- so the rule
      that protects a mouse protects a thumb for the same reason.
   3. Nothing that explains a rule is ever clipped. Help text wraps or the
      panel scrolls; an ellipsis on a rule is the difference between a game you
      can learn and one you cannot.
   ------------------------------------------------------------------------- */

/* The board owns its gestures: no browser pan, no double-tap zoom, no text
   selection while dragging across it. Harmless on a desktop, essential on a
   phone, where the alternative is Safari scrolling the page when the player
   meant to move the map. */
#board-wrap {
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}
body { overscroll-behavior: none; }

/* The notch, the rounded corners and the home indicator. Applied to the bars
   rather than the page so the board still runs edge to edge underneath. */
#top-bar {
  padding-top: env(safe-area-inset-top);
  height: calc(58px + env(safe-area-inset-top));
  min-height: calc(58px + env(safe-area-inset-top));
  padding-left: max(16px, env(safe-area-inset-left));
  padding-right: max(16px, env(safe-area-inset-right));
}
#action-bar {
  padding-bottom: env(safe-area-inset-bottom);
  height: calc(68px + env(safe-area-inset-bottom));
  min-height: calc(68px + env(safe-area-inset-bottom));
  padding-left: max(18px, env(safe-area-inset-left));
  padding-right: max(18px, env(safe-area-inset-right));
}

/* Only one of the two phase-end labels is ever shown. */
.pe-short { display: none; }

/* ---- Anything driven by a finger ---------------------------------------- */
@media (pointer: coarse) {
  /* Apple's minimum is 44pt and it is a floor, not a target. */
  button, select, input[type="text"] { min-height: 44px; }
  #amt-seg button { min-height: 40px; padding-left: 16px; padding-right: 16px; }
  /* min-height from the button rule above beats height, which is what turned
     these into ovals. Overridden explicitly, and sized as a real target: six
     40px circles still fit a 390px row. */
  .ls-color { width: 40px; height: 40px; min-height: 40px; }
  .ls-toggle { min-height: 38px; }

  /* A tap is not a hover. Both of these would otherwise stick after a touch,
     leaving a territory looking selectable when it is not. */
  .territory.selectable:hover { filter: none; }
  .trade-card:hover { opacity: 1; }
  * { -webkit-tap-highlight-color: transparent; }
}

/* ---- Phones, either way up ----------------------------------------------
   A phone in landscape is 844px WIDE, so width alone does not identify one --
   it would leave six full-width chips fighting over a strip that fits three.
   Short-and-landscape is the reliable second signal: desktop windows are
   rarely under 500px tall, phones on their side always are. */
@media (max-width: 760px), (max-height: 500px) and (orientation: landscape) {
  /* The deadline notice is a banner on a desk and a strip on a phone: it must
     never become a card sitting on top of the board it is talking about. */
  #capital-countdown {
    top: 6px;
    max-width: calc(100% - 12px);
    gap: 9px;
    padding: 6px 11px 6px 9px;
  }
  #capital-countdown .cc-seal { font-size: 19px; }
  /* The explanatory sentence goes; the round pips stay, because they are the
     countdown itself rather than a gloss on it. */
  #capital-countdown .cc-note { display: none; }

  /* Chips lose their names, never their existence. Colour plus armies is the
     smallest thing that is still a standing. */
  .player-chip {
    min-width: 0;
    flex: 0 1 auto;
    gap: 7px;
    padding: 4px 9px 4px 7px;
  }
  .player-chip .pc-main { display: none; }
  .player-chip .pc-right .pc-sub { display: none; }
  .player-chip .pc-armies { font-size: 16px; line-height: 1.1; }
  #player-strip { gap: 4px; }
  /* Six chips, a phase-end control and the log, inside 390px. The chip is
     pared to a colour and a number and nothing else fits, so nothing else is
     asked for. */
  .player-chip { padding: 4px 7px 4px 6px; gap: 5px; }
  .player-chip .p-chip { width: 10px; height: 10px; }
  #btn-log { padding: 9px 10px; }

  #btn-phase-end { padding-left: 14px; padding-right: 14px; }
  .pe-long { display: none; }
  .pe-short { display: inline; }

  #board-wrap { padding: 6px; }

  /* The log drawer is a side rail on a desktop and a full sheet on a phone. */
  #log-drawer {
    width: 100%;
    max-width: none;
    padding-bottom: env(safe-area-inset-bottom);
  }
}

/* ---- Phone, portrait: the map fills, the orders sit under it ------------- */
@media (max-width: 760px) and (orientation: portrait) {
  #action-bar {
    height: auto;
    min-height: 0;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 8px 12px;
    padding-top: 10px;
    padding-bottom: calc(10px + env(safe-area-inset-bottom));
  }
  /* Stepper first and full width: it is the map of the turn. */
  #phase-stepper { order: 1; width: 100%; justify-content: flex-start; }
  #turn-info { order: 2; flex: 1 1 100%; }
  #place-controls { order: 3; flex: 1 1 100%; justify-content: space-between; }
  #action-buttons { order: 4; flex: 1 1 100%; }
  #action-buttons button { flex: 1; }

  #phase-title { font-size: 16px; }
  /* Wraps to two lines, then scrolls. Never truncated -- see rule 3 above. */
  #phase-help {
    max-height: 3.2em;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
}

/* ---- Phone, landscape: height is the scarce thing ------------------------ */
@media (max-height: 500px) and (orientation: landscape) {
  #top-bar {
    height: calc(46px + env(safe-area-inset-top));
    min-height: calc(46px + env(safe-area-inset-top));
    gap: 10px;
  }
  #action-bar {
    height: calc(60px + env(safe-area-inset-bottom));
    min-height: calc(60px + env(safe-area-inset-bottom));
    gap: 14px;
  }
  #board-wrap { padding: 4px; }
  /* Two registers survive at this height: what phase it is, and what to do.
     The stepper is an indicator and the phase title already says it. */
  #phase-stepper { display: none; }
  /* Two lines fit at this size, and the panel scrolls past them rather than
     truncating -- an instruction that explains a rule is never clipped. */
  #phase-help { font-size: 12px; line-height: 1.32; max-height: 2.64em; overflow-y: auto; }
  #phase-title { font-size: 15px; }
  .setup-card { padding: 20px 24px 24px; }
  .setup-card h1 { font-size: 34px; }
}

/* ---- Pre-game cards on a small screen ------------------------------------ */
@media (max-width: 560px) {
  #setup-screen, #home-screen, #lobby-screen {
    align-items: flex-start;
    padding: max(12px, env(safe-area-inset-top)) 10px
             max(12px, env(safe-area-inset-bottom));
  }
  .setup-card, .lobby-card {
    width: 100%;
    max-width: 100%;
    padding: 26px 20px 28px;
  }
  .setup-card h1 { font-size: 38px; }
  .lc-code { font-size: 34px; letter-spacing: 0.24em; text-indent: 0.24em; }
  /* The swatch row is the widest thing in a seat; let it drop to its own line
     rather than squeezing the name into nothing. */
  .lobby-seat { flex-wrap: wrap; }
  .ls-colors { width: 100%; justify-content: space-between; padding-top: 2px; }
  .modal { width: calc(100vw - 20px); max-width: none; }
}
