/* Ferduin. Mobile first: the base rules fit a 360 to 420 px phone. min-width queries add room. */
:root {
  --bg: #f4ecdb;
  --surface: #fffaf0;
  --ink: #2b2118;
  --muted: #6f5f4d;
  --line: #d6c3a4;
  --accent: #b5542d;
  --accent-ink: #fffaf0;
  --danger: #a33a2c;
  --ok: #3d7a3a;
  --hl: #ffd34d;
  --tile-muted: #433829;   /* secondary text on a card with its 28% fill: at least 4.8:1 for every resource */
  --tile-ok: #2a5c26;
  --res-wood: #2f5d3a;
  --res-brick: #b7784c;  /* brick resource, in the clay tone of its terrain */
  --res-sheep: #a9d68e;
  --res-wheat: #e3b546;
  --res-ore: #8e9196;
  --res-desert: #e7d4a4;
  --p-red: #c0392b;
  --p-blue: #2e6fbf;
  --p-orange: #e67e22;
  --p-white: #f7f5ee;
  --p-green: #2e8b57;
  --p-purple: #7d4fb0;
  /* Board markers use fixed colours: they must read on every tile in both themes. */
  --mark-dark: #2b2118;
  --mark-light: #fffaf0;
  /* Tile depth: the side is the resource colour at --side-mix, the rest is --side-ink. The rim is light. */
  --side-ink: #2b2118;
  --side-mix: 55%;
  --rim: rgba(255, 250, 240, 0.55);
  --radius: 12px;
  --gutter: 16px;
  --tab-h: 56px;
  --topbar-h: 56px;
  --safe-b: env(safe-area-inset-bottom, 0px);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #1e1914;
    --surface: #2a241d;
    --ink: #f1e6d3;
    --muted: #b7a58c;
    --line: #5b4c3a;
    --accent: #d8794a;
    --accent-ink: #1e1914;
    --danger: #e0705f;
    --ok: #7cc474;
    --hl: #e8b923;
    --tile-muted: #e3d6c0;
    --tile-ok: #b4eeac;
    --res-desert: #b89d6a;
    --p-white: #e8e4da;
    --side-ink: #0d0a07;
    --side-mix: 45%;
    --rim: rgba(255, 240, 210, 0.35);
  }
}

:root[data-theme="dark"] {
  --bg: #1e1914;
  --surface: #2a241d;
  --ink: #f1e6d3;
  --muted: #b7a58c;
  --line: #5b4c3a;
  --accent: #d8794a;
  --accent-ink: #1e1914;
  --danger: #e0705f;
  --ok: #7cc474;
  --hl: #e8b923;
  --res-desert: #b89d6a;
  --p-white: #e8e4da;
  --side-ink: #0d0a07;
  --side-mix: 45%;
  --rim: rgba(255, 240, 210, 0.35);
}

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

body {
  background: var(--bg);
  color: var(--ink);
  font-size: 16px;
  line-height: 1.4;
  min-height: 100vh;
  overflow-x: hidden;
  overflow-wrap: anywhere;
  -webkit-text-size-adjust: 100%;
}
body.in-game { padding-bottom: calc(var(--tab-h) + var(--safe-b)); }

h2 { font-size: 1.15rem; margin: 0 0 8px; }
h3 { font-size: 1rem; margin: 14px 0 6px; }
p { margin: 0 0 8px; }

:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
svg :focus { outline: none; }

/* Top bar */
.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 8px;
  height: var(--topbar-h);
  padding: 5px var(--gutter);
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.brand {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--accent);
  font-weight: 700;
  font-size: 1.2rem;
  text-decoration: none;
  flex: none;
}
.game-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--muted);
  font-size: 0.95rem;
  text-align: right;
}
.topbar .btn { flex: none; }

.wrap { max-width: 1280px; margin: 0 auto; padding: 12px var(--gutter) 24px; }
/* The game sections keep their own 16px gutter, so the wrapper adds none (no double gutter). */
body.in-game .wrap { padding-left: 0; padding-right: 0; }
#home, #lobby { max-width: 640px; margin: 0 auto; }

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px;
  margin-bottom: 12px;
  min-width: 0;
}

.stack { display: flex; flex-direction: column; gap: 10px; }
.row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.muted { color: var(--muted); }
.small-text { font-size: 0.9rem; }
.battle-row { display: inline-flex; gap: 2px; vertical-align: middle; flex-wrap: wrap; }
.battle-row img { image-rendering: pixelated; }
.battle-side { display: inline-flex; flex-direction: column; align-items: center; gap: 2px; vertical-align: middle; font-style: normal; }
.empty { color: var(--muted); font-style: italic; }
.empty-state { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
ul.plain { list-style: none; margin: 0; padding: 0; }
ul.plain > li { padding: 8px 0; border-bottom: 1px solid var(--line); }
ul.plain > li:last-child { border-bottom: 0; }

label { display: flex; flex-direction: column; gap: 6px; font-size: 1rem; min-width: 0; }
label.inline { flex-direction: row; align-items: center; gap: 8px; flex-wrap: wrap; }

input, select {
  font: inherit;
  font-size: 16px;
  min-height: 44px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg);
  color: var(--ink);
  max-width: 100%;
  min-width: 0;
}
input.num { width: 84px; }
input.invite-input { flex: 1 1 200px; }

/* Buttons. Every control is at least 44 px tall. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  font: inherit;
  min-height: 44px;
  min-width: 44px;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  touch-action: manipulation;
}
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); font-weight: 600; }
.btn.danger { color: var(--danger); border-color: var(--danger); }
.btn.solid-danger { background: var(--danger); border-color: var(--danger); color: var(--accent-ink); font-weight: 600; }
.btn.small { padding: 0 12px; font-size: 0.95rem; }
.btn.help { width: 44px; padding: 0; font-size: 1.1rem; font-weight: 700; }
.btn.on { border-color: var(--accent); box-shadow: inset 0 0 0 2px var(--accent); }
/* Active mode: filled, bold label. Mode bubbles and their panel buttons both use it. */
.btn.is-active { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); font-weight: 700; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

.action { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; max-width: 100%; }
.action .btn { max-width: 100%; text-align: left; }
.reason, .cost { margin: 0; font-size: 0.85rem; color: var(--muted); }

.stepper { display: inline-flex; align-items: center; gap: 6px; }
.step { width: 44px; height: 44px; padding: 0; font-size: 1.3rem; line-height: 1; }
.count { min-width: 3ch; text-align: center; font-weight: 700; font-size: 1.1rem; }

.pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--line);
  font-size: 0.85rem;
}
.dot { display: inline-block; width: 12px; height: 12px; border-radius: 50%; vertical-align: middle; background: var(--pc); border: 1px solid var(--ink); }
.pc-red { --pc: var(--p-red); }
.pc-blue { --pc: var(--p-blue); }
.pc-orange { --pc: var(--p-orange); }
.pc-white { --pc: var(--p-white); }
.pc-green { --pc: var(--p-green); }
.pc-purple { --pc: var(--p-purple); }

/* Resource colors, shared by the stripe, the legend and the board */
.res-wood { --c: var(--res-wood); }
.res-brick { --c: var(--res-brick); }
.res-sheep { --c: var(--res-sheep); }
.res-wheat { --c: var(--res-wheat); }
.res-ore { --c: var(--res-ore); }
.res-desert { --c: var(--res-desert); }

/* Game header: next step, resource stripe and payout timing. It scrolls away so the board gets the screen. */
.gstatus {
  padding: 10px var(--gutter) 8px;
  background: var(--bg);
}
.status-line { margin: 0 0 4px; font-weight: 600; }
.status-sub { margin: 0 0 6px; font-size: 0.9rem; color: var(--muted); }
.stripe {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 6px;
}
.res {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-top: 4px solid var(--c);
  border-radius: 10px;
  padding: 4px 1px;
  position: relative;
  overflow: hidden;
}
.res > :not(.res-fill) { position: relative; }
.res .n { font-size: 1.15rem; font-weight: 700; line-height: 1.2; }
.res .l { font-size: 0.75rem; color: var(--tile-muted); }
.res .inc { font-size: 0.75rem; color: var(--tile-ok); text-align: center; line-height: 1.2; }
.res .inc.none { color: var(--tile-muted); }
/* The stock cap under the count. At the cap the number and the word "full" take the accent colour. */
.res .cap { font-size: 0.7rem; color: var(--tile-muted); line-height: 1.2; }
.res.is-full .n, .res.is-full .cap { color: var(--accent); font-weight: 700; }
/* The fraction of a unit waiting in the carry; it joins the whole count once it reaches 1. */
.res .frac { font-size: 0.7rem; color: var(--tile-muted); line-height: 1.2; }
/* Progress toward the next payment of this resource: the card itself fills from the bottom. Text stays above it. */
.res .res-fill {
  position: absolute; left: 0; right: 0; bottom: 0; height: 0; z-index: 0;
  background: color-mix(in srgb, var(--c) 28%, transparent);
  box-shadow: inset 0 2px 0 var(--c);  /* the level line stays solid so the fill reads at a glance */
}
@media (prefers-reduced-motion: no-preference) {
  .res .res-fill { transition: height 1s linear; }
}
/* A bank courier on its way: it walks along the bottom of the card. Tap it for the time left. */
.res.has-trader { padding-bottom: 24px; }
.res .trader {
  position: absolute; bottom: 2px; left: calc((100% - 22px) * var(--p, 0)); z-index: 1;
  width: 22px; height: 22px; padding: 1px; border: 0; background: none; cursor: pointer; line-height: 0;
}
.res .trader img { image-rendering: pixelated; }
.res .trader:focus-visible { outline: 2px solid var(--accent); border-radius: 4px; }
@media (prefers-reduced-motion: no-preference) {
  .res .trader { transition: left 1s linear; }
}
.res.gain { box-shadow: inset 0 0 0 2px var(--ok); }
@media (prefers-reduced-motion: no-preference) {
  .res.gain { animation: gain-flash 1.2s ease-out 2; }
}
@keyframes gain-flash {
  from { background: var(--hl); }
  to { background: var(--surface); }
}
.stripe-note { grid-column: 1 / -1; color: var(--muted); font-size: 0.9rem; }
.payout {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 2px 10px;
  margin: 6px 0 0;
  font-size: 0.9rem;
  color: var(--muted);
}
.gain-line { font-weight: 700; color: var(--ok); }
.rule { font-size: 0.9rem; color: var(--muted); margin: 0 0 8px; }

/* Game columns. Phone: one column. Desktop: board left, panels right. */
.game-cols { padding: 0 var(--gutter); }
.board-col { min-width: 0; }
.banner {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 8px;
  background: var(--surface);
  border: 2px solid var(--accent);
  border-radius: 12px;
  padding: 10px 12px;
}
.banner p { margin: 0; font-weight: 600; }
.banner-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }

.board-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 8px;
}
/* Mode bubbles: 48 px discs with a 12 px label under each. Five equal columns, so they fit a 360 px phone. */
.mode-bar {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  justify-items: center;
  gap: 4px;
  margin-bottom: 8px;
}
.mbub {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: 12px;
  line-height: 1.2;
  cursor: pointer;
  touch-action: manipulation;
}
.mbub-disc {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border: 2px solid var(--line);
  border-radius: 50%;
  background: var(--surface);
}
.mbub:hover:not([aria-disabled="true"]) .mbub-disc { border-color: var(--accent); }
.mbub-label { white-space: nowrap; }
/* Active: filled disc, a double ring and a bold label. Shape and weight, not colour alone. */
.mbub.is-active .mbub-disc {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent);
}
.mbub.is-active .mbub-label { font-weight: 700; }
.mbub[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }
.mbub-disc { position: relative; isolation: isolate; }
.mbub-badge { position: absolute; top: -4px; right: -6px; z-index: 1; box-shadow: 0 0 0 2px var(--bg); }
/* Letters waiting: two rings ripple out from the Trade disc */
.mbub.has-mail .mbub-disc::before,
.mbub.has-mail .mbub-disc::after {
  content: "";
  position: absolute;
  inset: -2px;
  z-index: -1;
  border-radius: 50%;
  border: 3px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  pointer-events: none;
  animation: mail-ripple 1.8s ease-out infinite;
}
.mbub.has-mail .mbub-disc::after { animation-delay: 0.9s; }
.mbub.has-mail .mbub-disc { border-color: var(--accent); }
@keyframes mail-ripple { from { transform: scale(1); opacity: 1; } to { transform: scale(1.6); opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .mbub.has-mail .mbub-disc::before { animation: none; transform: scale(1.15); opacity: 0.8; }
  .mbub.has-mail .mbub-disc::after { display: none; }
}
.mode-note {
  margin: 8px 0 0;
  padding: 8px 10px;
  font-size: 0.9rem;
  color: var(--ink);
  background: var(--surface);
  border-left: 3px solid var(--accent);
  border-radius: 6px;
}

.zoombar { display: flex; justify-content: flex-end; gap: 6px; margin-bottom: 6px; }
.zbtn { width: 44px; padding: 0; font-size: 1.4rem; line-height: 1; }
.zfit { padding: 0 14px; }
.board-wrap {
  position: relative;  /* the garrison popover is placed inside it */
  overflow: auto;
  overscroll-behavior: contain;
  max-height: 70vh;
  -webkit-overflow-scrolling: touch;
}
.board-wrap svg { display: block; width: 100%; height: auto; touch-action: manipulation; overflow: visible; user-select: none; }
.board-wrap.dragging, .board-wrap.dragging * { cursor: grabbing !important; }
.legend { display: flex; flex-wrap: wrap; gap: 6px 12px; font-size: 0.85rem; color: var(--muted); margin-top: 6px; }
.legend span { display: inline-flex; align-items: center; gap: 4px; }

/* Next step card: fills the space under the board on a phone, and sits in the right column on desktop */
.next-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  margin: 12px 0 0;
  padding: 12px 14px;
  background: var(--surface);
  border: 2px solid var(--accent);
  border-radius: var(--radius);
}
.next-card h2 { margin: 0; font-size: 1rem; color: var(--accent); }
.next-text { margin: 0; }

/* Board drawing */
.hex { stroke: var(--line); stroke-width: 0.03; }
.hex.wood { fill: var(--res-wood); }
.hex.brick { fill: var(--res-brick); }
.hex.sheep { fill: var(--res-sheep); }
.hex.wheat { fill: var(--res-wheat); }
.hex.ore { fill: var(--res-ore); }
.hex.desert { fill: var(--res-desert); }

/* Tile depth. The side is the same hex pushed down (EXTRUDE in app.js), in the resource colour
   (class res-*, which sets --c) mixed toward --side-ink. The fallback is for browsers without color-mix. */
.hex-side { fill: #4a3b2c; fill: color-mix(in srgb, var(--c) var(--side-mix), var(--side-ink)); }
.hex-shade { stroke: none; }
.hex-rim { fill: none; stroke: var(--rim); stroke-width: 0.03; }

/* Roads: ink outline, owner colour rim, then the cobble pattern (stroke set as an attribute in app.js) */
.road-under { stroke: var(--ink); stroke-width: 0.24; stroke-linecap: round; }
.road { stroke: var(--pc); stroke-width: 0.2; stroke-linecap: round; }
.road-cobble { stroke-width: 0.14; stroke-linecap: round; }

/* Workers: decoration on the hexes. Each one loops four frames (slots) and bobs once per half loop. Idle the loop is
   1.6 s (stand, stride, stand, lifted foot). A working worker (class work) loops in 0.8 s (stand, windup, strike, hold).
   --pf is the worker's place in its loop, 0 to 1, set per worker in app.js, so no two workers move in step.
   Frame 1 alone when motion is reduced. */
.worker { pointer-events: none; --t: 1.6s; }
.worker.work { --t: 0.8s; }
.worker image { image-rendering: pixelated; }
.worker .slot + .slot { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .worker {
    animation: worker-bob calc(var(--t) / 2) ease-in-out infinite;
    animation-delay: calc((var(--pf) - 2) * var(--t));
  }
  .worker .slot + .slot { display: inline; }
  .worker .slot { animation: worker-slot var(--t) steps(1) infinite; }
  /* Slot n is shown for the quarter of the loop that starts at (--pf + (n - 1) / 4). */
  .worker .slot:nth-child(1) { animation-delay: calc((var(--pf) - 2) * var(--t)); }
  .worker .slot:nth-child(2) { animation-delay: calc((var(--pf) - 1.75) * var(--t)); }
  .worker .slot:nth-child(3) { animation-delay: calc((var(--pf) - 1.5) * var(--t)); }
  .worker .slot:nth-child(4) { animation-delay: calc((var(--pf) - 1.25) * var(--t)); }
}
/* px in an SVG transform are board units, so this is 0.03 units. */
@keyframes worker-bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-0.03px); }
}
@keyframes worker-slot {
  0% { opacity: 1; }
  25%, 100% { opacity: 0; }
}

/* Scenery: still sprites on the tiles, under the roads, buildings and workers. They never take a tap. */
.scenery { pointer-events: none; }
/* Carts ride over the workers and under the buildings. They never take a tap. */
.carts { pointer-events: none; }

/* Pixel art stays sharp when scaled: sprites and SVG image tiles */
img[src^="assets/pixel/"], image { image-rendering: pixelated; }

/* A building's garrison count above it: a shield with the number, or "?" when it is hidden. The shield and its text keep
   fixed light and dark colours in both themes, so the text stays dark on parchment. Sized in board units in renderBoard,
   so it scales with the board. Taps go to its hit target, not to the drawing. */
.garrison { pointer-events: none; }
.garrison-shield { fill: #fffaf0; stroke: #2b2118; stroke-width: 0.03; stroke-linejoin: round; }
.garrison.unknown .garrison-shield { fill: #e3d8c2; }
.garrison.open .garrison-shield { stroke: var(--accent); stroke-width: 0.07; }
.garrison.compromised:not(.open) .garrison-shield { stroke: #b3261e; stroke-width: 0.05; }
.garrison-alert { fill: #fffaf0; stroke: #b3261e; stroke-width: 0.035; }
.scouted-list .linkish { all: unset; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; }
.scouted-list .linkish:hover, .scouted-list .linkish:focus-visible { text-decoration: underline; outline: revert; }
.garrison-count { fill: #2b2118; font-size: 0.3px; font-weight: 700; text-anchor: middle; dominant-baseline: central; }

/* The garrison popover: HTML inside the scrolling board box, placed by syncGarrison() in app.js. */
.garrison-pop {
  position: absolute;
  z-index: 5;
  width: 300px;  /* fixed, so nothing resizes or moves when the count or the label changes */
  max-width: calc(100% - 8px);
  padding: 10px 12px;
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
  scroll-margin: calc(var(--topbar-h) + 12px) 12px calc(var(--tab-h) + var(--safe-b) + 12px);  /* clear of the top bar and tab bar when it scrolls into view */
  max-height: calc(100% - 8px);  /* a tall card scrolls inside itself instead of running off a short board */
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: manipulation;
}
.garrison-pop:focus { outline: none; }
.build-pop { width: 230px; text-align: center; }
.gp-head { display: flex; flex-direction: column; margin-bottom: 8px; padding-right: 40px; }
.gp-close {
  position: absolute; top: 2px; right: 2px;
  width: 44px; height: 44px; padding: 0;
  background: none; border: 0; color: var(--muted);
  font-size: 1.6rem; line-height: 1; cursor: pointer;
}
/* Six boxes in two rows of three. Every box and figure has a fixed size, so nothing shifts when the count changes. */
.gp-units { display: grid; grid-template-columns: repeat(3, minmax(0, 52px)); gap: 4px; justify-content: center; }
.gp-units .slot {
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: auto; aspect-ratio: 1;   /* up to 52 px, and shrinks on a 320 px screen */
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--bg);
}
.gp-units .slot.empty { border-style: dashed; opacity: 0.55; }
.gp-unknown { font-size: 2.2rem; font-weight: 700; line-height: 1; text-align: center; color: var(--muted); }
.gp-units .slot img { max-width: 100%; height: auto; }
.garrison-pop .small-text { margin: 4px 0 0; }
.gp-strip { display: flex; align-items: stretch; justify-content: center; gap: 6px; }
.gp-strip .step { height: auto; }  /* a tall bar down each side of the boxes */
/* A soldier you would add: faded, in the next free box. */
.gp-units .slot.ghost { border-style: dashed; border-color: var(--accent); }
.gp-units .slot.ghost img { opacity: 0.4; }
/* One line of icons and counts: the garrison, what the building produces, a price. */
.gp-line { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 2px 12px; margin: 8px 0 0; font-weight: 700; }
.gp-line img, .cost-item img { width: 16px; height: 16px; }
.cost-total, .cost-icons { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 2px 10px; }
.cost-item { display: inline-flex; align-items: center; gap: 4px; font-weight: 700; color: var(--ink); }
.cost-item.short { color: var(--danger); }
/* A button and its price side by side; the reason it is off wraps under them. */
.garrison-pop .action { margin-top: 10px; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 4px 10px; }
.garrison-pop .action { justify-content: center; }
.garrison-pop .action .reason { display: none; }  /* shown as the button's tooltip instead */
.garrison-pop .action .btn { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 16px; border-radius: 22px; font-weight: 700; }
.garrison-pop .action .btn:disabled { opacity: 0.45; }
.garrison-pop .gp-head strong { font-size: 1rem; }
.garrison-pop { border-radius: 14px; padding: 12px 14px; }
.gp-units button.slot { padding: 0; font: inherit; color: inherit; cursor: pointer; }
.gp-units .slot.picked { border-color: var(--accent); outline: 2px solid var(--accent); outline-offset: 1px; }

/* Hit targets are invisible. Their on-screen size (at least 28 px across) is set by sizeHits() in app.js. */
.hit { fill: transparent; cursor: pointer; }
.road-hit { stroke: transparent; stroke-linecap: round; fill: none; cursor: pointer; }
.hit:focus-visible { stroke: var(--accent); stroke-width: 0.12; }
.road-hit:focus-visible { stroke: var(--accent); stroke-opacity: 0.35; }

/* Visible markers. They sit above the pieces and never cover a building body. Pointer events go to the hit targets. */
.mark { pointer-events: none; }
.mark-dark { fill: var(--mark-dark); }
.mark-dot { fill: var(--hl); stroke: var(--mark-light); }
.mark-halo { display: none; fill: none; stroke: var(--mark-light); }
@media (prefers-reduced-motion: no-preference) {
  .mark-halo {
    display: inline;
    animation: mark-pulse 1.8s ease-out 3;  /* three pulses, then still: repeated motion is distracting */
    animation-delay: calc(var(--pf, 0) * -1.8s);  /* each halo starts partway through its pulse, so the marks ripple */
    transform-box: fill-box;
    transform-origin: center;
  }
}
@keyframes mark-pulse {
  from { opacity: 0.8; transform: scale(0.6); }
  to { opacity: 0; transform: scale(1.8); }
}
.mark-road-dark { stroke: var(--mark-dark); stroke-linecap: round; }
.mark-road-light { stroke: var(--mark-light); stroke-linecap: round; }
.mark-road-hl { stroke: var(--hl); }
.attack-line { stroke: var(--pc); fill: none; opacity: 0.9; }
.is-move .attack-line { opacity: 0.5; }  /* your own move: quieter than an attack */
.yield-bar { stroke: #000; stroke-width: 0.025px; pointer-events: none; }
.yield-bar.good { fill: #4cc35a; }
.yield-bar.ok { fill: #f2c230; }
.yield-bar.poor { fill: #e0533f; }
.hex-yield { font: bold 0.26px sans-serif; text-anchor: middle; fill: #fff; stroke: #000; stroke-width: 0.05px; paint-order: stroke; pointer-events: none; }
.hide-numbers .hex-yield { display: none; }
.attack-count { font: bold 0.32px sans-serif; text-anchor: middle; fill: #fff; stroke: #000; stroke-width: 0.06px; paint-order: stroke; }
.mark-ring-dark { fill: none; stroke: var(--mark-dark); }
.mark-ring { fill: none; stroke: var(--accent); }
.mark-ring.target { stroke: var(--danger); }

/* Phone tab bar and bottom sheets */
.tabbar {
  display: none;
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  height: calc(var(--tab-h) + var(--safe-b));
  padding-bottom: var(--safe-b);
  background: var(--surface);
  border-top: 1px solid var(--line);
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
body.in-game .tabbar { display: grid; }
.tab {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: var(--tab-h);
  height: 100%;
  background: none;
  border: 0;
  color: var(--muted);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  touch-action: manipulation;
}
.tab[aria-pressed="true"] { color: var(--accent); box-shadow: inset 0 3px 0 var(--accent); }
.badge {
  display: inline-block;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--danger);
  color: var(--accent-ink);
  font-size: 0.75rem;
  line-height: 18px;
  text-align: center;
}

.panels { min-width: 0; }
.panel {
  display: none;
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(var(--tab-h) + var(--safe-b));
  z-index: 25;
  max-height: 62vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--surface);
  border-top: 1px solid var(--line);
  border-radius: 16px 16px 0 0;
  box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.25);
  padding: 0 var(--gutter) 12px;
}
.panel.open { display: block; }
.panel-head {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  background: var(--surface);
  padding: 8px 0;
  margin-bottom: 8px;
  border-bottom: 1px solid var(--line);
}
.panel-head h2 { margin: 0; }
.panel-body { display: flex; flex-direction: column; gap: 10px; }
.panel-body h3:first-child { margin-top: 0; }
.log-list { list-style: none; margin: 0; padding: 0; max-height: 52vh; overflow-y: auto; font-size: 0.92rem; }
.log-list li { padding: 5px 0; border-bottom: 1px solid var(--line); }

/* Player cards, key/value lists, vassalage */
.pcard { border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px; }
.pcard.muted { padding: 8px 12px; }
.pcard header { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; margin-bottom: 6px; font-weight: 600; }
.grid2 { display: grid; grid-template-columns: auto 1fr; gap: 3px 12px; margin: 0; font-size: 0.92rem; }
.grid2 dt { color: var(--muted); }
.grid2 dd { margin: 0; overflow-wrap: anywhere; }
.subcard { border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; }
.bank-status { margin: 0; color: var(--ok); font-weight: 600; }
.bank-status:empty { margin: 0; }

/* How it works steps */
.steps { margin: 0 0 12px; padding-left: 20px; }
.steps li { margin-bottom: 8px; }

/* Toasts sit above the tab bar during a game */
.toasts {
  position: fixed;
  left: 50%;
  bottom: 12px;
  transform: translateX(-50%);
  width: calc(100% - 32px);
  max-width: 480px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 40;
}
body.in-game .toasts { bottom: calc(var(--tab-h) + var(--safe-b) + 8px); }
.toast {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  background: var(--surface);
  color: var(--danger);
  border: 1px solid var(--danger);
  border-radius: var(--radius);
  padding: 8px 10px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.2);
}
.toast .msg { color: var(--ink); }

/* Winner card */
.winner-screen {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--gutter);
  background: var(--bg);
}
.winner-card {
  width: 100%;
  max-width: 420px;
  text-align: center;
  background: var(--surface);
  border: 2px solid var(--accent);
  border-radius: 16px;
  padding: 28px 18px;
}
.winner-card h2 { font-size: 1.7rem; color: var(--accent); }

/* Dialogs: confirm and how it works */
dialog {
  width: min(calc(100% - 32px), 420px);
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--surface);
  color: var(--ink);
  padding: 18px;
}
dialog::backdrop { background: rgba(0, 0, 0, 0.45); }
.code-input { width: 100%; margin-top: 10px; text-align: center; font-size: 2rem; letter-spacing: 0.3em; font-variant-numeric: tabular-nums; }
.dlg-actions { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; margin-top: 14px; }

/* Wider phones and tablets */
@media (min-width: 768px) {
  .board-wrap { max-height: 75vh; }
  .gstatus, .game-cols { max-width: 760px; margin: 0 auto; }
  .gstatus { padding-top: 12px; }
  .panel {
    left: 50%;
    right: auto;
    width: min(560px, calc(100% - 32px));
    transform: translateX(-50%);
  }
  body.in-game .toasts { bottom: calc(var(--tab-h) + var(--safe-b) + 8px); }
}

/* Desktop: board on the left; the next step card and the four panels stacked on the right; no tab bar */
@media (min-width: 1100px) {
  body.in-game { padding-bottom: 0; }
  body.in-game .toasts { bottom: 12px; }
  .tabbar { display: none !important; }
  .gstatus, .game-cols { max-width: 1100px; margin: 0 auto; }
  .gstatus { padding: 12px var(--gutter) 10px; }
  .game-cols {
    display: grid;
    grid-template-columns: minmax(0, 640px) minmax(0, 380px);
    justify-content: center;
    gap: 24px;
    align-items: start;
    padding: 0 var(--gutter);
  }
  .board-col { max-width: min(640px, calc((100vh - 240px) * 1.03)); width: 100%; }
  .board-wrap { max-height: none; }
  .panels { display: flex; flex-direction: column; gap: 12px; }
  .next-card { margin: 0; }
  .panel {
    display: block;
    position: static;
    width: auto;
    max-height: none;
    transform: none;
    overflow: visible;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: none;
    padding: 0 14px 12px;
  }
  .panel-head { position: static; margin: 0 -14px 10px; padding: 10px 14px; }
  .panel-close { display: none; }
  .log-list { max-height: 360px; }
}

/* ---------- Letters: trade offers as sealed letters (Players sheet) ----------
   Parchment stays light in both themes: it is paper, not a surface. */
/* Self-hosted, OFL (licenses beside the files). No handwritten Georgian font is openly licensed, so Georgian falls back to Noto Serif Georgian. */
@font-face { font-family: "Dancing Script"; font-weight: 400 700; font-display: swap; src: url(assets/fonts/dancing-script.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Noto Serif Georgian"; font-weight: 400 700; font-display: swap; src: url(assets/fonts/noto-serif-georgian.woff2) format("woff2");
  unicode-range: U+0589, U+10A0-10FF, U+1C90-1CBA, U+1CBD-1CBF, U+205A, U+2D00-2D2F, U+2E31; }
.letters {
  --paper: #f8eccd;
  --paper2: #ecdcae;
  --seal: #8f2a1d;
  --parch-ink: #2b2118;
  --serif: "Palatino Linotype", Palatino, "Book Antiqua", Georgia, "Noto Serif Georgian", serif;
  --hand: "Dancing Script", "Noto Serif Georgian", var(--serif);
  interpolate-size: allow-keywords;  /* lets the closed envelope grow to the letter's height */
}
.letters h3 { margin: 0; }
.letters .lab { margin: 10px 0 0; font-size: 0.8rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--muted); }
.letters .hint, .letters .pend { margin: 0; font-size: 0.9rem; color: var(--muted); }
.letters .pend { font: italic 0.95rem var(--serif); }
.letters .reason { min-height: 1.2em; }
.letters .reason.warn { color: var(--accent); font-weight: 600; }
.letters .btn.block { width: 100%; min-height: 50px; font-size: 1.05rem; }
.letters button:active:not(:disabled) { transform: scale(0.97); }
.letters .res-ico { vertical-align: -0.2em; image-rendering: pixelated; }
.letters-out { display: flex; flex-direction: column; gap: 8px; }
.letters-out:empty, #realm-letters:empty { display: none; }

/* Trade | Message | The bank */
.letters .seg { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; background: var(--bg); border: 1px solid var(--line); border-radius: 10px; padding: 3px; }
.letters .seg button { min-height: 40px; border: 0; border-radius: 8px; background: none; font: inherit; font-weight: 600; color: var(--muted); cursor: pointer; touch-action: manipulation; }
.letters .seg button[aria-pressed="true"] { background: var(--surface); color: var(--ink); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); }

/* Resource tiles: a tap adds one, the corner minus takes one away */
.letters .res-tiles { display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; padding-top: 12px; }
.letters .chip { position: relative; border: 2px solid var(--line); border-radius: 10px; background: var(--surface); }
.letters .chip.on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, var(--surface)); }
.letters .chip .add { width: 100%; min-height: 72px; border: 0; background: none; border-radius: 8px; font: inherit; font-size: 0.85rem; color: var(--ink); cursor: pointer; touch-action: manipulation;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; padding: 4px 2px; }
.letters .chip .add:disabled { opacity: 0.45; cursor: not-allowed; }
.letters .chip small { font-size: 0.72rem; color: var(--muted); text-align: center; line-height: 1.15; }
.letters .chip.over small { color: var(--accent); font-weight: 700; }
.letters .cnt { position: absolute; top: -9px; right: -7px; min-width: 22px; height: 22px; padding: 0 5px; border-radius: 11px; background: var(--accent); color: var(--accent-ink);
  font: 700 0.8rem/22px system-ui, sans-serif; text-align: center; pointer-events: none; }
.letters .sub { position: absolute; top: -14px; left: -10px; z-index: 2; width: 34px; height: 34px; padding: 0; border-radius: 50%; border: 1px solid var(--line);
  background: var(--surface); color: var(--ink); font-size: 1rem; line-height: 1; cursor: pointer; touch-action: manipulation; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); }

/* Write to */
.letters .people { display: flex; flex-wrap: wrap; gap: 8px; }
.letters .person { min-height: 44px; padding: 0 14px; border-radius: 22px; border: 2px solid var(--line); background: var(--surface); color: var(--ink);
  font: inherit; font-weight: 600; display: inline-flex; align-items: center; gap: 8px; cursor: pointer; touch-action: manipulation; }
.letters .person[aria-pressed="true"] { border-color: var(--accent); }
.letters .shield { fill: var(--pc); stroke: var(--ink); stroke-width: 1.3; }

/* The letter itself */
.letters .letter { position: relative; border-radius: 6px; padding: 18px 18px 16px; font-family: var(--serif); color: var(--parch-ink);
  background: radial-gradient(120% 90% at 20% 10%, #fbf1d6, var(--paper) 55%, var(--paper2)); border: 1px solid #c9b27f;
  box-shadow: 0 2px 0 #c9b27f, 0 8px 16px rgba(43, 33, 24, 0.18); }
.letters .letter .to { font-size: 0.95rem; font-style: italic; margin: 0 0 8px; opacity: 0.8; }
.letters .letter .body { font-size: 1.12rem; line-height: 1.5; margin: 0; }
.letters .letter .body b { font-weight: 700; border-bottom: 2px solid var(--accent); }
.letters .letter .sig { text-align: right; font-style: italic; margin: 10px 0 0; }
.letters .letter .sig small { font-size: 0.8rem; opacity: 0.8; }
.letters .letter .body { white-space: pre-wrap; overflow-wrap: anywhere; }
/* Handwriting by default; the Aa button on any letter switches every letter to plain type. */
.letters .letter, .letters .mail-log p { font-family: var(--hand); }
.letters .letter .body { font-size: 1.3rem; line-height: 1.4; }
.plain-letters .letters .letter, .plain-letters .letters .mail-log p { font-family: var(--serif); }
.plain-letters .letters .letter .body { font-size: 1.12rem; line-height: 1.5; }
.letters .hand-toggle { position: absolute; top: 6px; right: 6px; min-width: 32px; height: 28px; padding: 0 6px; border: 1px solid #c9b27f; border-radius: 6px;
  background: rgba(255, 255, 255, 0.35); color: var(--parch-ink); font: 600 0.8rem var(--serif); cursor: pointer; opacity: 0.75; }
.letters .hand-toggle:hover, .letters .hand-toggle:focus-visible { opacity: 1; }
.letters .letter .to { padding-right: 40px; }
/* A written letter: the text box is the parchment itself */
.letters textarea.note { display: block; width: 100%; box-sizing: border-box; resize: vertical; min-height: 6em; padding: 0; border: 0; background: none;
  font: inherit; color: inherit; line-height: inherit; }
.letters textarea.note:focus-visible { outline: 2px dashed var(--seal); outline-offset: 4px; }
#letters-history:empty { display: none; }
.letters .mail-log p { margin: 2px 0 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.letters .mail-log small { color: var(--muted); }

/* Waiting for an answer: one card per letter out */
.letters .wait { display: flex; gap: 12px; align-items: center; padding: 10px 12px; border: 1px dashed var(--muted); border-radius: 6px; font-family: var(--serif); }
.letters .wait p { margin: 0; flex: 1; line-height: 1.4; }
.letters .ring { --p: 1; flex: none; width: 46px; height: 46px; border-radius: 50%; display: grid; place-items: center;
  background: conic-gradient(var(--accent) calc(var(--p) * 360deg), var(--line) 0); }
.letters .ring > span { width: 36px; height: 36px; border-radius: 50%; background: var(--surface); display: grid; place-items: center; font: 0.72rem system-ui, sans-serif; font-variant-numeric: tabular-nums; }

/* The envelope: open flap behind the letter, back, pocket in front, closing flap, seals */
.letters .opened { position: relative; margin: 10px 0 6px; }
.letters .lwrap { position: relative; z-index: 1; overflow: hidden; padding-bottom: 20px; }
.letters .lwrap .letter { margin: 0 14px; padding-bottom: 54px; }
.letters .eo { position: relative; height: 78px; margin-top: -68px; }
.letters .eback { position: absolute; inset: 0; z-index: 0; background: linear-gradient(#8a6f3c, #a88d55); border: 1px solid #b79f66; border-radius: 4px; }
.letters .eflap { position: absolute; left: 0; right: 0; top: -40px; height: 42px; z-index: 0; background: linear-gradient(#cdb67e, #a88d55); clip-path: polygon(50% 0, 100% 100%, 0 100%); }
.letters .epocket { position: absolute; left: 0; right: 0; top: 12px; bottom: 0; z-index: 2; border-radius: 0 0 4px 4px; border: 1px solid #b79f66; box-shadow: 0 -2px 4px rgba(60, 40, 10, 0.25);
  background: linear-gradient(to bottom right, transparent calc(50% - 1px), rgba(120, 90, 40, 0.35) 50%, transparent calc(50% + 1px)) left / 50% 100% no-repeat,
    linear-gradient(to bottom left, transparent calc(50% - 1px), rgba(120, 90, 40, 0.35) 50%, transparent calc(50% + 1px)) right / 50% 100% no-repeat,
    linear-gradient(#e2cf9c, #d4bd85); }
.letters .eflap2 { position: absolute; left: 0; right: 0; top: 0; height: 46px; z-index: 3; background: #bfa468; clip-path: polygon(0 0, 100% 0, 50% 100%); transform: scaleY(0); transform-origin: top; }
.letters .wax { position: absolute; left: 50%; top: 22px; margin-left: -23px; z-index: 4; width: 46px; height: 46px; border-radius: 50%; display: grid; place-items: center;
  background: radial-gradient(circle at 35% 30%, #c4513f, var(--seal) 60%, #5e150d); color: #f8eccd; font: 700 1.25rem var(--serif);
  box-shadow: inset 0 -3px 5px rgba(0, 0, 0, 0.35), 0 1px 3px rgba(0, 0, 0, 0.4); }
.letters .wax.stamp { opacity: 0; }
.letters .peek { position: absolute; left: 10px; right: 10px; bottom: -7px; height: 14px; z-index: 0; background: #c2a96f; border: 1px solid #9c8450; border-radius: 0 0 4px 4px;
  transition: transform 0.3s, opacity 0.3s; }
.letters .peek + .peek { left: 20px; right: 20px; bottom: -13px; background: #ae9560; }
.letters .meta2 { position: absolute; left: 0; right: 0; top: calc(100% + 20px); z-index: 5; text-align: center; font: italic 0.95rem var(--serif); color: var(--muted);
  opacity: 0; pointer-events: none; transition: opacity 0.2s; }
.letters .opener { display: none; position: absolute; inset: 0; z-index: 6; background: none; border: 0; border-radius: 6px; cursor: pointer; }
.letters .acts { display: flex; gap: 8px; margin-top: 12px; transition: opacity 0.3s 1.3s; }
.letters .acts .btn { flex: 1; }
.letters .opened .more { margin: 8px 2px 0; text-align: center; font: italic 0.9rem var(--serif); color: var(--muted); transition: opacity 0.3s 1.3s; }

/* Closed: the same layout with the letter tucked into the pocket and the flap shut. Opening runs in order:
   seal breaks, closing flap folds up, open flap rises, letter slides out, buttons fade in. */
.letters .opened .letter { transition: transform 0.6s ease-out 0.8s; }
.letters .opened .lwrap { transition: height 0.4s ease-out; }
.letters .opened .eo { transition: margin-top 0.4s ease-out; }
.letters .opened .eflap { transform-origin: bottom; transition: transform 0.3s ease-out 0.45s; }
.letters .opened .eflap2 { transition: transform 0.3s ease-in 0.2s; }
.letters .opened .wax.sender { opacity: 0; transform: scale(1.3) rotate(14deg); transition: opacity 0.25s, transform 0.25s; }
.letters .opened.closed .lwrap { height: 20px; }
.letters .opened.closed .letter { transform: translateY(calc(100% + 20px)); }
.letters .opened.closed .eo { margin-top: 0; }
.letters .opened.closed .eflap { transform: scaleY(0); }
.letters .opened.closed .eflap2 { transform: scaleY(1); }
.letters .opened.closed .wax.sender { opacity: 1; transform: none; animation: wax-pulse 2.4s ease-in-out infinite; }
.letters .opened.closed .meta2 { opacity: 1; }
.letters .opened.closed .opener { display: block; }
.letters .opened.closed .acts { opacity: 0; visibility: hidden; }
.letters .opened.closed .more { opacity: 0; }
.letters .opened:not(.closed) .peek { opacity: 0; transform: translateY(-8px); }
.letters .notrans, .letters .notrans * { transition: none !important; }
@keyframes wax-pulse { 50% { transform: scale(1.06); } }

/* Accept (and sending): the letter sinks into the pocket, the flap closes, your seal is pressed on */
.letters .opened.sealing .letter { animation: letter-sink 0.6s ease-in forwards; }
@keyframes letter-sink { from { transform: translateY(0); clip-path: inset(0 0 0 0); } to { transform: translateY(100%); clip-path: inset(0 0 100% 0); } }
.letters .opened.sealing .eflap { animation: flap-down 0.35s 0.55s ease-in forwards; }
@keyframes flap-down { to { transform: scaleY(0); } }
.letters .opened.sealing .eflap2 { animation: flap-close 0.35s 0.85s ease-out forwards; }
@keyframes flap-close { to { transform: scaleY(1); } }
.letters .opened.sealing .wax.stamp { animation: seal-press 0.45s 1.25s cubic-bezier(0.3, 1.6, 0.5, 1) forwards; }
@keyframes seal-press { from { opacity: 0; transform: scale(2.4); } to { opacity: 1; transform: scale(1); } }
.letters .opened.sealing .eo { animation: env-away 0.5s 2s ease-in forwards; }
@keyframes env-away { to { transform: translateY(-30px) scale(0.8); opacity: 0; } }
.letters .opened.sending .eo { animation: env-fly 0.7s 1.8s ease-in forwards; }
@keyframes env-fly { 30% { transform: translateY(8px) rotate(3deg); } 100% { transform: translate(120px, -320px) rotate(-20deg) scale(0.35); opacity: 0; } }
.letters .opened.sealing .acts, .letters .opened.burning .acts, .letters .opened.sealing .more, .letters .opened.burning .more { opacity: 0; transition: opacity 0.2s; pointer-events: none; }

/* Decline: the letter burns from the top edge down, flames ride the burn line, embers drift up */
@property --b { syntax: '<percentage>'; inherits: true; initial-value: -10%; }
.letters .opened.burning .letter { z-index: 3; animation: letter-burn 1.5s ease-in forwards;
  -webkit-mask-image: linear-gradient(to bottom, transparent var(--b), #000 calc(var(--b) + 6%)); mask-image: linear-gradient(to bottom, transparent var(--b), #000 calc(var(--b) + 6%)); }
.letters .opened.burning .letter::before { content: ""; position: absolute; left: 0; right: 0; top: var(--b); height: 18%; pointer-events: none;
  background: linear-gradient(#2a1206, rgba(90, 40, 10, 0.6) 40%, transparent); }
@keyframes letter-burn { 0% { --b: -10%; filter: none; } 30% { filter: sepia(0.6) brightness(0.85); } 100% { --b: 110%; filter: sepia(1) brightness(0.5); } }
.letters .opened.burning .eo { animation: env-char 1.5s ease-in forwards; }
@keyframes env-char { 60% { filter: brightness(0.4) sepia(1); } 100% { filter: brightness(0.2); opacity: 0; transform: translateY(10px); } }
.letters .fire { position: absolute; left: 14px; right: 14px; top: 0; z-index: 4; display: none; overflow: hidden; pointer-events: none; }
.letters .opened.burning .fire { display: block; animation: fire-line 1.5s ease-in forwards; }
@keyframes fire-line { from { --b: -10%; } to { --b: 110%; } }
.letters .fire .line { position: absolute; left: 0; right: 0; top: calc(var(--b) - 30px); height: 44px; display: flex; justify-content: space-around; align-items: flex-end; }
.letters .flame { width: 22px; height: 40px; border-radius: 50% 50% 45% 45% / 65% 65% 35% 35%; transform-origin: 50% 100%; filter: blur(0.6px); mix-blend-mode: screen;
  background: radial-gradient(ellipse at 50% 85%, #fffbe0 0, #ffd23f 22%, #ff8a1f 48%, #e8380d 68%, transparent 74%); animation: flicker 0.18s ease-in-out infinite alternate; }
.letters .flame:nth-child(2n) { animation-duration: 0.23s; }
.letters .flame:nth-child(3n + 1) { animation-delay: -0.1s; }
.letters .flame:nth-child(odd) { width: 18px; height: 30px; }
.letters .flame:nth-child(3n) { height: 48px; }
@keyframes flicker { from { transform: scale(1, 1) skewX(-4deg); } to { transform: scale(0.85, 1.2) skewX(5deg); } }
.letters .ember { position: absolute; top: var(--b); width: 4px; height: 4px; border-radius: 50%; background: #ffb547; box-shadow: 0 0 6px 2px #ff6a00; opacity: 0;
  animation: ember-rise 1s ease-out infinite; }
@keyframes ember-rise { 0% { opacity: 1; transform: translate(0, 0); } 100% { opacity: 0; transform: translate(var(--dx), -70px) scale(0.4); } }

@media (prefers-reduced-motion: reduce) {
  .letters .opened, .letters .opened * { transition-duration: 0.01s !important; transition-delay: 0s !important; animation-duration: 0.01s !important; animation-delay: 0s !important; }
  .letters .fire { display: none !important; }
}
.letters .battle-lines { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 8px; margin: 10px 0; font-style: italic; }
