/* ==========================================================================
   Teristorial 0.2 — kingdom management, living map, war room.
   Loaded after styles.css and responsive.css; this file owns every component
   introduced with the province simulation.
   ========================================================================== */

:root {
  --good: #4f8c6a;
  --fair: #c69141;
  --bad: #b8604f;
  --ink-soft: #6b7b72;
  --panel-line: #d3ddd2;
  --sea-shallow: #9dc6c9;
  --sea-deep: #6f9fa8;
  --land: #d8dfc2;
  --coast-ink: #4a6b5c;
}

body { min-width: 0; font-size: 16.4px; }
.app-shell { display: flex; flex-direction: column; min-height: 100vh; }
.dashboard-grid { grid-template-columns: 288px minmax(0, 1fr) 348px; min-height: 0; flex: 1; }
.left-panel, .right-panel { max-height: calc(100vh - 116px); overflow-y: auto; overscroll-behavior: contain; }
.left-panel::-webkit-scrollbar, .right-panel::-webkit-scrollbar { width: 8px; }
.left-panel::-webkit-scrollbar-thumb, .right-panel::-webkit-scrollbar-thumb { background: #8cae9b; border-radius: 4px; }
.panel-section { padding: 20px 20px; }
.empty-note { margin: 6px 0 0; color: #8b9990; font-size: 13.7px; font-style: italic; }
.hidden { display: none !important; }

/* ---------- topbar ---------- */
.topbar-center { gap: 9px; font-size: 13.7px; min-width: 0; overflow: hidden; white-space: nowrap; }
/* The centre strip was clipping mid-word — "Foreign courts: calm (threa" — because
   the brand block reserves a fixed 270px it does not need and the strip is
   `overflow: hidden`. It gets the room back, and anything still too long ends in
   an ellipsis so a cut reads as a cut rather than as a broken string. */
.brand-lockup { min-width: 196px; }
/* When the strip runs short it is the province count that gives way, not the
   warning. "12 provinces · 0 occupied · 0 puppet" grows as the realm does and
   is on screen in three other places; "Courts hold off · 5 min" is the only
   copy of a thing the player can act on. */
#realmSummary { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
#threatLabel { flex: 0 0 auto; }
#pauseButton { font-size: 13.7px; }
body.is-paused .status-dot { background: #d09a4f; box-shadow: 0 0 0 4px #d09a4f22; }
.notification-button span.is-quiet { background: #6d8479; }
.notification-tray { max-height: 70vh; overflow-y: auto; }
.critical-item small { display: block; margin-top: 5px; color: #9aa79e; font: 11.9px 'DM Mono', monospace; }
.critical-item.positive { border-left: 3px solid var(--good); padding-left: 9px; }
.critical-item.alert { border-left: 3px solid var(--bad); padding-left: 9px; }

/* ---------- left panel ---------- */
.resource-row { flex-wrap: wrap; gap: 12px 8px; }
.resource-icon.influence { color: #7d84b5; }
.ledger-button {
  width: 100%; margin-top: 18px; display: flex; align-items: center; justify-content: space-between;
  padding: 11px 12px; border: 1px solid #c6d6c6; background: #e7f0e5; color: #2b5748;
  cursor: pointer; text-align: left; border-radius: 3px;
}
.ledger-button:hover { background: #dcead9; }
.ledger-button.is-negative { border-color: #ddb5aa; background: #f4e0d8; color: #8d4a3c; }
.ledger-button small { display: block; font: 11.9px 'DM Mono', monospace; letter-spacing: 1px; color: #7c8b81; }
.ledger-button strong { font: 700 20.9px 'DM Mono', monospace; }
.ledger-hint { font: 600 12.8px Manrope; color: #5d7a6a; }
.ledger-hint b { font-weight: 400; font-size: 17.3px; margin-left: 4px; }

.treaty-state.safe { color: var(--good); }
.treaty-state.steady { color: var(--fair); }
.treaty-state.strained { color: var(--bad); }

.watch-item {
  display: block; width: 100%; text-align: left; margin-bottom: 7px; padding: 9px 10px;
  border: 1px solid #dbe2d8; border-left-width: 3px; background: #f6f7f1; cursor: pointer; border-radius: 2px;
}
.watch-item strong { display: block; font-size: 13.7px; color: #2d4c40; }
.watch-item span { display: block; margin-top: 3px; font-size: 12.8px; color: #76867c; line-height: 1.4; }
.watch-item.good { border-left-color: var(--good); }
.watch-item.warn { border-left-color: var(--fair); }
.watch-item.bad { border-left-color: var(--bad); }
.watch-item:hover { background: #eef2ea; }

/* ---------- map stage ---------- */
.map-stage { display: flex; flex-direction: column; min-width: 0; }
.map-toolbar { height: auto; padding: 18px 24px 12px; align-items: flex-start; gap: 18px; }
.map-toolbar h2 { font-size: 22.7px; }
.map-summary { display: flex; gap: 16px; margin-left: auto; text-align: right; }
.map-summary small { display: block; color: #8a978d; font: 11.9px 'DM Mono', monospace; letter-spacing: 1px; }
.map-summary strong { font: 700 19.1px 'DM Mono', monospace; color: #2f5849; }
.map-wrap { flex: 1; height: auto; min-height: 420px; margin: 0 18px 12px; background: #cfdcd6; }
.map-canvas { position: absolute; inset: 0; }
.realm-map { width: 100%; height: 100%; min-width: 0; display: block; transform: none; }
.map-legend { display: grid; grid-template-columns: repeat(2, auto); gap: 5px 12px; }
.legend-dot.occupied { background: #b8654f; }
.legend-dot.puppet { background: #c39a55; }
.legend-dot.tribe { background: #a68972; }
.legend-dot.free { background: #b5c99c; }

/* sea */
.sea-plate { transition: opacity .4s ease; }
.sea-currents path {
  fill: none; stroke: #e2f4f4; stroke-width: 7; opacity: .25;
  stroke-dasharray: 30 22; animation: sea-drift 14s linear infinite;
}
@keyframes sea-drift { to { stroke-dashoffset: -208px; } }
.sea-label {
  fill: #eaf7f7; opacity: .55; font-family: 'DM Mono', monospace; letter-spacing: 3px;
  text-anchor: middle; pointer-events: none; font-weight: 500;
}

/* land */
.coast-glow { fill: #1d3b3d; opacity: .5; }
.land-plate { fill: var(--land); }
.coast-line { fill: none; stroke: #f2f4e6; stroke-width: 2.4; stroke-linejoin: round; opacity: .8; pointer-events: none; }
.terrain-glyph { fill: none; stroke-linecap: round; stroke-linejoin: round; pointer-events: none; opacity: .5; }
.glyph-mountain { stroke: #6d6a58; stroke-width: 1.5; }
.glyph-hills { stroke: #7f8567; stroke-width: 1.3; }
.glyph-forest { stroke: #4d7245; stroke-width: 1.4; }
.glyph-desert { stroke: #bfa367; stroke-width: 1.2; }
.glyph-marsh { stroke: #5d8878; stroke-width: 1.2; }
.lake { fill: #86bdc6; stroke: #4f8894; stroke-width: 1.4; }
.river { fill: none; stroke: #6aa8bd; stroke-linecap: round; stroke-linejoin: round; opacity: .85; }

/* provinces */
.province { cursor: pointer; outline: none; }
.province-fill { fill: #c9cfb4; fill-opacity: .58; transition: fill-opacity .25s ease, fill .3s ease; }
.province-integration { fill: #5d9576; fill-opacity: .72; opacity: 0; transition: opacity .6s ease; pointer-events: none; }
.province-hatch { fill: none; pointer-events: none; }
.province-border { fill: none; stroke: #4a6b5c; stroke-width: .7; opacity: .33; pointer-events: none; }
.country-border { fill: none; stroke: #23423a; stroke-width: 2.4; stroke-linejoin: round; opacity: .75; pointer-events: none; }

/* Your own outline, and only yours.
   The first question anybody has looking at this map is "which of this is
   mine", and until now the whole answer was a fill colour that terrain shading
   and the night wash both eat into. Your border is heavier, brighter and
   carries a soft outward glow, so the shape of the realm reads at a glance and
   at any zoom - the realm is a shape before it is a colour. Every other crown
   is left exactly as it was, so this reads as *yours* rather than as a general
   increase in border weight. */
.country-border.is-own {
  stroke: #f0e4c4; stroke-width: 3.4; opacity: .95;
  filter: drop-shadow(0 0 5px rgba(240, 228, 196, .45));
}

.own-player .province-fill { fill: #5d9576; }
.own-ally .province-fill { fill: #86b3c4; }
.own-neutral .province-fill { fill: #cdc596; }
.own-rival .province-fill { fill: #c07d6d; }
.own-tribe .province-fill { fill: #a98d74; }
.own-free .province-fill { fill: #b5c99c; fill-opacity: .4; }
.own-puppet .province-fill { fill: #c39a55; }

.province.is-free .province-fill { stroke: #7d9268; stroke-width: 1.6; stroke-dasharray: 7 4; }
.province.is-chartered .province-fill { stroke: #86765a; stroke-width: 1.4; stroke-dasharray: 5 3; }
.province.is-occupied .province-hatch { fill: url(#occupationHatch); opacity: .5; }
.province.is-puppet .province-hatch { fill: url(#puppetHatch); opacity: .55; }
.province.is-unrest .province-fill { animation: unrest-flicker 2.6s ease-in-out infinite; }
@keyframes unrest-flicker { 50% { fill-opacity: .38; } }

/* Hover and selection both used to be a change in fill opacity alone - .58 to
   .92 to 1 - which on a saturated fill under a night wash is very nearly
   nothing. A player clicked a province, the panel on the right filled with its
   name, and the map gave no sign of which one they had picked. Both are drawn
   on the outline now, where a shape change is legible over any fill. */
.province:hover .province-fill,
.province:focus .province-fill { fill-opacity: .95; }
.province:hover .province-hatch,
.province:focus .province-hatch {
  fill: none; stroke: rgba(255, 253, 242, .5); stroke-width: 2;
  vector-effect: non-scaling-stroke;
}

.province.is-selected .province-fill { fill-opacity: 1; }
.province.is-selected { filter: drop-shadow(0 0 7px rgba(255, 231, 168, .5)); }
.province.is-selected .province-hatch {
  fill: none; stroke: #ffe7a8; stroke-width: 3.2;
  vector-effect: non-scaling-stroke;
}
/* Hover must never be mistaken for selection, so the selected ring wins. */
.province.is-selected:hover .province-hatch { stroke: #fff3cf; stroke-width: 3.6; }
/* The province the introduction is pointing at.
 *
 * The single most useful thing the opening can do is join the sentence to the
 * place: "click Rillreach" is an instruction, and the same words with Rillreach
 * breathing on the map are an answer. A slow ring on the outline rather than
 * anything on the fill, so it reads over any terrain and cannot be mistaken for
 * the hostile pulse, which is faster, red, and on the fill.
 *
 * Deliberately unhurried - 2.6s - because this sits under a card the player is
 * reading, and anything quicker competes with the words instead of supporting
 * them. `stroke` only, so it composites without a filter and costs nothing that
 * a gesture has to undo. */
.province.is-coach-target .province-hatch {
  fill: none; stroke: #ffe7a8; stroke-width: 3;
  vector-effect: non-scaling-stroke;
  animation: coach-ring 2.6s ease-in-out infinite;
}
/* The floor is .58 rather than .35: a marker that fades to almost nothing for
   part of its cycle is one the player can look straight at and miss. It
   breathes between clearly-there and unmissable, never between there and
   gone. */
@keyframes coach-ring {
  0%, 100% { stroke-opacity: .58; stroke-width: 2.8; }
  50% { stroke-opacity: 1; stroke-width: 4.4; }
}
/* Selection still wins: once they have clicked it, the steady ring is the
   truth and a pulsing one would say the job was not done. */
.province.is-coach-target.is-selected .province-hatch { animation: none; stroke-width: 3.2; }

.province.is-war-target .province-fill { animation: hostile-pulse 1.4s ease-in-out infinite; }
.province.is-pulsing .province-hatch { stroke: #ffe9a8; stroke-width: 4; fill: none; animation: pulse-ring 1.4s ease-out 1; }
@keyframes pulse-ring { from { opacity: 1; stroke-width: 7; } to { opacity: 0; stroke-width: 1; } }

/* labels */
.province-label {
  fill: #24413a; font: 600 13.7px Manrope; text-anchor: middle; pointer-events: none;
  opacity: 0; transition: opacity .3s ease; paint-order: stroke; stroke: #f4f6e9; stroke-width: 2.4;
}
.province-label.is-visible { opacity: .88; }
.province-label.is-selected { opacity: 1; font-weight: 800; fill: #16302a; }
/* The selected province's name in the same gold as its ring, so the label and
   the outline are plainly about the same place. */
body.mode-night .province-label.is-selected { fill: #ffe7a8; }
.country-label {
  fill: #1e3a33; font: 800 17.3px 'Playfair Display', serif; letter-spacing: 2px; text-anchor: middle;
  pointer-events: none; opacity: .55; paint-order: stroke; stroke: #f2f4e6; stroke-width: 3;
}
.country-label.is-hidden { opacity: 0; }

/* trade + war overlays */
.layer-trade { opacity: 0; transition: opacity .35s ease; pointer-events: none; }
.trade-route { fill: none; stroke: #d39a4d; stroke-width: 2.6; stroke-dasharray: 9 8; animation: route-flow 1.4s linear infinite; }
.trade-node { fill: #f0c879; stroke: #8a6a2c; stroke-width: 2; }
.layer-war { pointer-events: none; }
.war-supply { fill: none; stroke: #6f8f78; stroke-width: 2; stroke-dasharray: 4 6; opacity: .7; }
.war-advance { fill: none; stroke: #c2624f; stroke-width: 4; stroke-linecap: round; }
.war-front { fill: #b8503b; stroke: #ffeede; stroke-width: 3; }
.war-objective { fill: none; stroke: #b8503b; stroke-width: 2.5; stroke-dasharray: 6 5; animation: objective-spin 8s linear infinite; }
@keyframes objective-spin { to { stroke-dashoffset: -44px; } }

/* map modes */
.map-stage[data-map-mode="terrain"] .province-fill { fill: var(--biome); fill-opacity: .8; }
.map-stage[data-map-mode="terrain"] .province-border { opacity: .16; }
.map-stage[data-map-mode="terrain"] .country-border { opacity: .4; stroke-width: 1.8; }
.map-stage[data-map-mode="terrain"] .province-integration { opacity: 0 !important; }
.map-stage[data-map-mode="terrain"] .terrain-glyph { opacity: .95; }
.map-stage[data-map-mode="terrain"] .country-label { opacity: .25; }
.map-stage[data-map-mode="seas"] { --sea-shallow: #4f97a6; --sea-deep: #2d6a7c; }
.map-stage[data-map-mode="seas"] .layer-land { opacity: .42; }
.map-stage[data-map-mode="seas"] .sea-label { opacity: .95; font-size: 17.3px; }
.map-stage[data-map-mode="seas"] .sea-currents path { opacity: .7; }
.map-stage[data-map-mode="trade"] .layer-trade { opacity: 1; }
.map-stage[data-map-mode="trade"] .province-fill { fill-opacity: .35; }
.map-stage[data-map-mode="war"] .own-rival .province-fill { animation: hostile-pulse 1.6s ease-in-out infinite; }
.map-stage[data-map-mode="war"] .terrain-glyph { opacity: .8; }
.map-stage[data-map-mode="war"] .country-border { stroke: #7d3b2e; opacity: .9; }
@keyframes hostile-pulse { 50% { fill-opacity: .55; } }

/* ---------- command sidebar ---------- */
.crown-section { padding-top: 18px; }
/* Seven tabs across a sidebar: at readable type they no longer fit on one row,
   and a tab you cannot read is worse than a tab on a second row. */
.command-tabs { grid-template-columns: repeat(4, 1fr); position: sticky; top: 0; z-index: 6; }
.command-tab { font-size: 17.3px; padding: 7px 2px; }
.command-tab span { font-size: 11.5px; letter-spacing: .2px; }
.realm-score strong { font-size: 25.4px; }
.realm-score small { font-size: 11.9px; }
.global-response { position: sticky; top: 48px; z-index: 5; }
.global-response.positive { border-bottom-color: #b8d3ba; background: #dcebdd; }
.global-response.warning { background: #f4e1d6; border-bottom-color: #e0bda9; }

.focus-section { min-height: 0; }
.focus-title { align-items: flex-start; }
.focus-crest { border-radius: 4px; font-size: 19.1px; }
.focus-crest.is-player { background: #d7e8d7; color: #2f6349; }
.focus-crest.is-rival { background: #f1d8d2; color: #96473a; }
.focus-crest.is-tribe { background: #e8ded1; color: #7a5f42; }
.focus-crest.is-ally { background: #d6e6ef; color: #3d6a80; }
.focus-crest.is-free { background: #e6eedc; color: #5f7a4c; }
.standing-pill {
  margin-left: auto; padding: 4px 7px; border-radius: 2px; font: 600 11.9px 'DM Mono', monospace;
  letter-spacing: .8px; text-transform: uppercase; background: #e4eae1; color: #5e7367;
}
.standing-pill.prosperous { background: #d6ecd9; color: #2f6b45; }
.standing-pill.steady { background: #e3ecdc; color: #4d6b52; }
.standing-pill.strained { background: #f6e8cf; color: #8a6421; }
.standing-pill.struggling { background: #f5dbd2; color: #96473a; }

.focus-stats { grid-template-columns: repeat(3, 1fr); gap: 8px 0; }
.focus-stat { border-right: 1px solid var(--panel-line); padding-left: 10px; }
.focus-stat:nth-child(3n) { border-right: 0; }
.focus-stat:nth-child(3n+1) { padding-left: 0; }
.focus-stat span { display: block; font: 11.9px 'DM Mono', monospace; color: #8c988e; letter-spacing: .8px; }
.focus-stat strong { font: 700 17.3px 'DM Mono', monospace; color: #3d6556; }
.focus-stat.good strong { color: var(--good); }
.focus-stat.fair strong { color: var(--fair); }
.focus-stat.bad strong { color: var(--bad); }

.occupation-block { margin: 14px 0; padding: 11px; background: #f4ece4; border: 1px solid #e0d2c4; border-radius: 3px; }
.occupation-head { display: flex; justify-content: space-between; align-items: baseline; font-size: 14.6px; }
.occupation-head span { font: 12.8px 'DM Mono', monospace; color: #8a6f5b; }
.occupation-bars { margin: 9px 0; display: grid; gap: 6px; }
.occupation-bar { display: grid; grid-template-columns: 96px 1fr 34px; align-items: center; gap: 8px; font-size: 12.8px; color: #7a6957; }
.occupation-bar b { text-align: right; font: 600 12.8px 'DM Mono', monospace; }
.meter.rose span { background: #c0705f; }
.occupation-note { margin: 4px 0 9px; font-size: 12.8px; color: #85705d; line-height: 1.45; }
.policy-row { display: flex; flex-wrap: wrap; gap: 5px; }
.policy-chip {
  border: 1px solid #d9cab9; background: #fdf8f2; color: #7a6551; padding: 5px 7px;
  font: 600 12.8px Manrope; cursor: pointer; border-radius: 2px;
}
.policy-chip.active { background: #6f5137; border-color: #6f5137; color: #f6ece0; }

.governor-row { display: flex; align-items: center; gap: 9px; margin: 12px 0; padding: 9px; background: #f2f5ee; border: 1px solid var(--panel-line); }
.governor-crest { width: 30px; height: 30px; border-radius: 50%; background: #cfdfd0; color: #3d6556; display: grid; place-items: center; font: 700 14.6px 'DM Mono', monospace; }
.governor-row strong { display: block; font-size: 13.7px; }
.governor-row p { margin: 2px 0 0; font-size: 12.8px; color: #7c8a80; }
.mini-action { margin-left: auto; border: 1px solid #c8d6c6; background: #e6efe3; color: #3a5f4e; padding: 5px 8px; font: 600 12.8px Manrope; cursor: pointer; border-radius: 2px; }

.focus-actions { display: grid; gap: 7px; margin-top: 12px; }
.focus-action {
  display: block; width: 100%; text-align: left; padding: 10px 11px; cursor: pointer;
  border: 1px solid #d3ddd2; background: #f6f8f2; border-radius: 2px;
}
.focus-action strong { display: block; font-size: 14.6px; color: #2d4c40; }
.focus-action small { display: block; margin-top: 3px; font-size: 12.8px; color: #7c8a80; line-height: 1.4; }
.focus-action:hover { background: #eaf1e6; }
.focus-action.primary { background: #e1eee0; border-color: #a9cbb1; }
.focus-action.warning { background: #f7ece0; border-color: #e0c9a9; }
.focus-action.attack { background: #f2d8d0; border-color: #c98d7c; }
.focus-action.attack strong { color: #8d3f30; }
.focus-blocked { margin: 6px 0 0; padding: 9px 10px; background: #f0efe6; border-left: 3px solid #c9b98f; font-size: 13.7px; color: #77705c; line-height: 1.5; }

.strategy-picker { padding: 9px 10px; background: #f2f2ea; border: 1px solid #ded8c6; border-radius: 2px; }
.strategy-picker > span { display: block; font: 11.9px 'DM Mono', monospace; letter-spacing: 1px; color: #8a8570; margin-bottom: 7px; }
.strategy-row { display: flex; gap: 5px; }
.strategy-note { margin: 8px 0 0; font-size: 12.8px; color: #7d7663; line-height: 1.45; }

.dispatch.positive .dispatch-time { color: #4f8c6a; }
.dispatch.warning .dispatch-time, .dispatch.alert .dispatch-time { color: #b8604f; }

/* ---------- footer ticker ---------- */
.app-footer { height: auto; min-height: 44px; padding: 8px 24px; gap: 16px; }
/* Both ends of the footer hold their size, so a long opinion line ellipsises
   instead of pushing "Open the People panel" off the edge. The ticker is the
   only thing down there that is allowed to be any length at all, and the
   voices system will happily produce a forty-word one. */
.footer-tag {
  flex: 0 0 auto;
  font: 500 12.8px 'DM Mono', monospace; letter-spacing: 1.3px;
}
.opinion-ticker { flex: 1; min-width: 0; overflow: hidden; }
.opinion-line {
  margin: 0; color: #8a5f43; font: italic 16.4px 'Playfair Display', serif;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  animation: opinion-in .5s ease-out;
}
.opinion-line em { font-size: 13.7px; color: #97a196; font-style: normal; font-family: 'DM Mono', monospace; }
.opinion-line.negative { color: #a35347; }
.opinion-line.positive { color: #4d7b5c; }
@keyframes opinion-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.footer-link {
  flex: 0 0 auto;
  border: 0; background: none; color: #5c7a68;
  font: 600 12.8px Manrope; cursor: pointer; white-space: nowrap;
}

/* ---------- popout workspaces ---------- */
.popout-scrim { position: fixed; inset: 0; z-index: 30; background: #12241f4d; backdrop-filter: blur(1.5px); }
body:not(.panel-open) .popout-scrim { display: none; }
.popout {
  position: fixed; z-index: 34; top: 88px; left: 50%; transform: translateX(-50%);
  width: min(1080px, calc(100vw - 48px)); max-height: calc(100vh - 128px);
  display: flex; flex-direction: column;
  background: var(--panel); border: 1px solid #c2d2c3; box-shadow: 0 26px 70px #14312629;
  animation: popout-in .18s ease-out;
}
@keyframes popout-in { from { opacity: 0; transform: translate(-50%, 8px); } to { opacity: 1; transform: translate(-50%, 0); } }
.popout-head { display: flex; align-items: flex-start; gap: 16px; padding: 16px 22px; border-bottom: 1px solid var(--panel-line); background: #f4f6ef; }
.popout-head h2 { margin: 4px 0 0; font: 700 22.7px 'Playfair Display', serif; color: #27453b; }
.popout-head .popup-close { width: auto; margin-left: auto; border: 1px solid var(--panel-line); border-radius: 2px; }
.popout-body { padding: 20px 22px 26px; overflow-y: auto; }
.popout-body::-webkit-scrollbar { width: 9px; }
.popout-body::-webkit-scrollbar-thumb { background: #a3bfae; border-radius: 5px; }
.section-title { margin: 22px 0 10px; font: 700 15.5px Manrope; color: #37594c; letter-spacing: .2px; }
.panel-note { margin: 14px 0 0; padding: 10px 12px; background: #f0f3ea; border-left: 3px solid #b7cbae; font-size: 13.7px; line-height: 1.6; color: #6e7d73; }
.detail-note { margin: 8px 0 0; font-size: 13.2px; color: #7c8a80; line-height: 1.5; }
.detail-note.warn { color: #a35b48; }

.panel-action {
  border: 1px solid #c9d8c7; background: #eef3ea; color: #35594a; padding: 8px 10px;
  font: 600 13.7px Manrope; cursor: pointer; border-radius: 2px;
}
.panel-action:hover { background: #e2ece0; }
.panel-action.active { background: #2d5b4d; border-color: #2d5b4d; color: #f1f5ea; }
.panel-action.primary { background: #dcecd9; border-color: #a3c8ac; }
.panel-action.warning { background: #f6e6d8; border-color: #ddbf9f; color: #8a5a34; }
.panel-action.is-disabled { opacity: .5; cursor: not-allowed; }
.detail-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 9px; }

/* ---------- kingdom panel ---------- */
.kingdom-summary { display: grid; grid-template-columns: repeat(6, 1fr); gap: 9px; }
.summary-tile { padding: 11px 12px; background: #f1f4ec; border: 1px solid var(--panel-line); }
.summary-tile span { display: block; font: 11.9px 'DM Mono', monospace; letter-spacing: 1px; color: #86948b; }
.summary-tile strong { display: block; margin: 5px 0 2px; font: 700 21.8px 'DM Mono', monospace; color: #2f5849; }
.summary-tile small { font-size: 12.8px; color: #83918a; }

.crown-tax { margin: 16px 0 6px; padding: 12px 14px; background: #f5f1e6; border: 1px solid #ddd6c2; }
.crown-tax label { display: block; font-size: 14.6px; color: #6b6553; }
.crown-tax input[type="range"] { width: 100%; margin: 10px 0 4px; accent-color: #7d6b3c; }
.crown-tax p { margin: 0; font-size: 13.2px; color: #857c66; line-height: 1.5; }

.kingdom-controls { display: flex; flex-wrap: wrap; gap: 12px; margin: 14px 0 12px; }
.chip-row { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; }
.chip-label { font: 11.9px 'DM Mono', monospace; letter-spacing: 1px; color: #8a968d; margin-right: 3px; }
.chip { border: 1px solid var(--panel-line); background: #f4f6f0; color: #667a6f; padding: 5px 9px; font: 600 12.8px Manrope; cursor: pointer; border-radius: 12px; }
.chip.active { background: #2d5b4d; border-color: #2d5b4d; color: #f1f5ea; }

.kingdom-layout { display: grid; grid-template-columns: minmax(280px, 380px) minmax(0, 1fr); gap: 18px; align-items: start; }
.province-list { display: grid; gap: 5px; max-height: 62vh; overflow-y: auto; padding-right: 6px; }
.province-row {
  display: grid; grid-template-columns: 26px minmax(0, 1fr) auto 34px; gap: 9px; align-items: center;
  width: 100%; text-align: left; padding: 9px 10px; border: 1px solid var(--panel-line);
  background: #f7f8f3; cursor: pointer; border-radius: 2px;
}
.province-row:hover { background: #edf2e9; }
.province-row.is-selected { border-color: #7ea88f; background: #e5f0e3; box-shadow: inset 3px 0 #4f8c6a; }
.row-spec { font-size: 17.3px; }
.row-main strong { display: block; font-size: 14.6px; color: #2d4c40; }
.row-main small { display: block; margin-top: 2px; font-size: 12.3px; color: #83918a; }
.row-bars { display: flex; gap: 3px; align-items: flex-end; height: 22px; }
.mini-bar { display: block; width: 5px; height: 100%; background: #e2e7de; border-radius: 1px; position: relative; }
.mini-bar b { position: absolute; bottom: 0; left: 0; right: 0; display: block; border-radius: 1px; }
.mini-bar.good b { background: var(--good); }
.mini-bar.fair b { background: var(--fair); }
.mini-bar.bad b { background: var(--bad); }
.row-standing { font: 700 15.5px 'DM Mono', monospace; text-align: right; }
.row-standing.prosperous { color: var(--good); }
.row-standing.steady { color: #55755f; }
.row-standing.strained { color: var(--fair); }
.row-standing.struggling { color: var(--bad); }

.province-detail { border: 1px solid var(--panel-line); background: #fbfbf6; padding: 16px 18px; }
.detail-empty h3 { margin: 0 0 8px; font: 700 19.1px 'Playfair Display', serif; }
.detail-empty p { font-size: 14.2px; color: #7b8a80; line-height: 1.6; }
.detail-hint { color: #4f7b62; }
.detail-hint.warn { color: #a35b48; }
.detail-head { display: flex; align-items: flex-start; gap: 11px; padding-bottom: 12px; border-bottom: 1px solid var(--panel-line); }
.detail-crest { width: 38px; height: 38px; border-radius: 4px; background: #dfe9d9; display: grid; place-items: center; font-size: 20px; }
.detail-head h3 { margin: 0; font: 700 20px 'Playfair Display', serif; color: #274b40; }
.detail-head p { margin: 3px 0 0; font: 12.8px 'DM Mono', monospace; color: #86948b; letter-spacing: .6px; }
.detail-metrics { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 16px; margin: 14px 0; }
.detail-metric { display: grid; grid-template-columns: 96px 1fr 26px; align-items: center; gap: 8px; font-size: 13.2px; color: #74837a; }
.detail-metric b { text-align: right; font: 600 12.8px 'DM Mono', monospace; color: #3d6556; }
.detail-block { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--panel-line); }
.detail-block h4 { margin: 0 0 8px; font: 700 14.6px Manrope; color: #37594c; }
.detail-block p { margin: 0; font-size: 13.7px; color: #74837a; line-height: 1.55; }
.detail-block.occupation { background: #f7efe6; border: 1px solid #e2d4c4; border-top: 0; padding: 12px 13px; }

.building-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); gap: 8px; }
.building-card { padding: 10px; border: 1px solid var(--panel-line); background: #f4f7f1; border-radius: 2px; }
.building-card.has-level { border-color: #a9c9b0; background: #eaf3e7; }
.building-head { display: flex; align-items: center; gap: 6px; font-size: 14.6px; }
.building-head span { font-size: 16.4px; }
.building-head b { margin-left: auto; font: 600 12.8px 'DM Mono', monospace; color: #5e7a6a; }
.building-card p { margin: 6px 0 8px; font-size: 12.8px; color: #7d8b82; line-height: 1.45; }
.building-button {
  width: 100%; border: 1px solid #c4d5c3; background: #e7efe4; color: #35594a;
  padding: 7px; font: 600 12.8px Manrope; cursor: pointer; border-radius: 2px;
}
.building-button.is-disabled { opacity: .55; cursor: not-allowed; }
.explain-grid { display: grid; gap: 8px; }
.explain-row { display: grid; grid-template-columns: 110px 60px 1fr; gap: 8px; align-items: baseline; font-size: 13.2px; }
.explain-row span { color: #86948b; font: 11.9px 'DM Mono', monospace; letter-spacing: .8px; }
.explain-row strong { font: 700 14.6px 'DM Mono', monospace; color: #3d6556; }
.explain-row p { margin: 0; color: #7d8b82; line-height: 1.5; }

/* ---------- people panel ---------- */
.people-headline, .army-headline, .diplomacy-headline, .ledger-headline {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 9px; margin-bottom: 6px;
}
.people-headline > div, .army-headline > div, .diplomacy-headline > div, .ledger-headline > div {
  padding: 11px 12px; background: #f1f4ec; border: 1px solid var(--panel-line);
}
.people-headline span, .army-headline span, .diplomacy-headline span, .ledger-headline span {
  display: block; font: 11.9px 'DM Mono', monospace; letter-spacing: 1px; color: #86948b;
}
.people-headline strong, .army-headline strong, .diplomacy-headline strong {
  display: block; margin-top: 5px; font: 700 21.8px 'DM Mono', monospace; color: #2f5849;
}
.people-columns { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 18px; }
.people-columns h4 { margin: 0 0 10px; font: 700 14.6px Manrope; color: #37594c; }
.pressure-list { display: grid; gap: 6px; }
.pressure-row { display: grid; grid-template-columns: 140px 1fr 40px; align-items: center; gap: 9px; font-size: 13.7px; color: #74837a; }
.pressure-track { position: relative; height: 7px; background: #e6eae2; border-radius: 4px; }
.pressure-track::before { content: ''; position: absolute; left: 50%; top: -2px; bottom: -2px; width: 1px; background: #b9c4bb; }
.pressure-track i { position: absolute; top: 0; height: 100%; border-radius: 4px; }
.pressure-track i.good { background: var(--good); }
.pressure-track i.bad { background: var(--bad); }
.pressure-row b { text-align: right; font: 600 12.8px 'DM Mono', monospace; }
.pressure-row b.good { color: var(--good); }
.pressure-row b.bad { color: var(--bad); }
.opinion-feed { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px; max-height: 300px; overflow-y: auto; }
.opinion-entry {
  padding: 9px 11px; background: #f5f6f0; border-left: 3px solid #b9c7b6;
  font: italic 14.6px 'Playfair Display', serif; color: #5d6a61; line-height: 1.5;
}
.opinion-entry em { display: block; margin-top: 5px; font: 11.9px 'DM Mono', monospace; color: #93a099; font-style: normal; }
.opinion-entry.positive { border-left-color: var(--good); }
.opinion-entry.negative { border-left-color: var(--bad); }
.group-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 10px; }
.group-card { padding: 12px; border: 1px solid var(--panel-line); background: #f7f8f3; }
.group-card.bad { border-color: #e0c0b6; background: #f9efeb; }
.group-card.good { border-color: #b9d5bd; background: #f0f7ee; }
.group-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.group-icon { font-size: 18.2px; }
.group-head strong { display: block; font-size: 14.6px; }
.group-head small { display: block; margin-top: 2px; font-size: 12.3px; color: #86948b; }
.group-head b { margin-left: auto; font: 700 17.3px 'DM Mono', monospace; color: #3d6556; }
.group-card p { margin: 8px 0 0; font-size: 13.2px; color: #7a887f; line-height: 1.5; }
.group-driver { color: #5d7a6a !important; }
.group-cares { font-size: 12.3px !important; color: #96a29a !important; }

/* ---------- army panel ---------- */
.division-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 10px; }
.division-card { padding: 12px; border: 1px solid var(--panel-line); background: #f7f8f3; }
.division-head { display: flex; align-items: center; gap: 8px; }
.division-head span { font-size: 18.2px; }
.division-head strong { font-size: 14.6px; }
.division-head b { margin-left: auto; font: 700 16.4px 'DM Mono', monospace; color: #3d6556; }
.division-card p { margin: 7px 0 9px; font-size: 13.2px; color: #7a887f; line-height: 1.5; }
.division-bars { display: grid; gap: 5px; margin-bottom: 10px; }
.division-card .panel-action { width: 100%; }
.commander-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 9px; }
.commander-card { text-align: left; padding: 11px; border: 1px solid var(--panel-line); background: #f7f8f3; cursor: pointer; }
.commander-card.active { border-color: #7ea88f; background: #e7f1e4; box-shadow: inset 3px 0 #4f8c6a; }
.commander-card strong { display: block; font-size: 14.6px; }
.commander-card small { display: block; margin-top: 3px; font: 12.3px 'DM Mono', monospace; color: #86948b; }
.commander-card p { margin: 7px 0 0; font-size: 13.2px; color: #7a887f; line-height: 1.5; }

/* ---------- diplomacy + frontier ---------- */
.coalition-banner { margin: 12px 0; padding: 13px 15px; background: #f6e2da; border: 1px solid #ddb5a7; }
.coalition-banner strong { display: block; font: 700 16.4px 'Playfair Display', serif; color: #8d3f30; }
.coalition-banner p { margin: 6px 0 0; font-size: 13.7px; color: #8a6055; line-height: 1.5; }
.request-list { display: grid; gap: 9px; }
.request-card { padding: 13px 15px; background: #f5f1e4; border: 1px solid #ddd5bf; }
.request-head { display: flex; justify-content: space-between; align-items: baseline; }
.request-head strong { font-size: 15.5px; color: #6b5a33; }
.request-head span { font: 12.8px 'DM Mono', monospace; color: #8d8265; }
.request-card p { margin: 7px 0 0; font-size: 14.2px; color: #77705c; line-height: 1.6; }
.request-terms { font: 12.8px 'DM Mono', monospace !important; color: #948a6e !important; }
.alliance-list { display: grid; gap: 9px; }
.alliance-row { display: grid; grid-template-columns: minmax(0, 1fr) 120px auto; gap: 14px; align-items: center; padding: 12px 14px; border: 1px solid var(--panel-line); background: #f7f8f3; }
.alliance-row strong { font-size: 15.1px; }
.alliance-row small { display: block; margin-top: 3px; font: 12.3px 'DM Mono', monospace; color: #86948b; }
.alliance-row p { margin: 6px 0 0; font-size: 13.2px; color: #7a887f; }
.alliance-trust b { display: block; font: 700 17.3px 'DM Mono', monospace; color: #3d6556; margin-bottom: 5px; }
.court-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 10px; }
.court-card { padding: 12px; border: 1px solid var(--panel-line); background: #f7f8f3; }
.court-card.war { border-color: #d8a99d; background: #f9eeea; }
.court-card.allied { border-color: #a9c9b0; background: #eff6ec; }
.court-card.puppet { border-color: #ddc79a; background: #f8f2e3; }
.court-head { display: flex; align-items: center; gap: 9px; margin-bottom: 9px; }
.court-crest { width: 30px; height: 30px; border-radius: 50%; background: #dde7d8; display: grid; place-items: center; font: 700 14.6px 'DM Mono', monospace; color: #3d6556; }
.court-head strong { display: block; font-size: 15.1px; }
.court-head small { display: block; margin-top: 2px; font-size: 12.3px; color: #86948b; }
.court-relation { margin-left: auto; font: 11.9px 'DM Mono', monospace; letter-spacing: .6px; color: #6f8377; }
.court-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 5px; margin-bottom: 8px; }
.court-stats span { display: block; font: 11.4px 'DM Mono', monospace; color: #8d9a92; letter-spacing: .6px; }
.court-stats b { font: 700 14.6px 'DM Mono', monospace; color: #3d6556; }
.frontier-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 10px; margin-top: 14px; }
.frontier-card { padding: 12px; border: 1px solid var(--panel-line); background: #f7f8f3; }
.frontier-card.is-adjacent { border-color: #a9c9b0; background: #f0f7ee; }
.frontier-head { display: flex; align-items: center; gap: 8px; }
.frontier-head span { font-size: 18.2px; }
.frontier-head strong { display: block; font-size: 15.1px; }
.frontier-head small { display: block; margin-top: 2px; font-size: 12.3px; color: #86948b; }
.frontier-head b { margin-left: auto; font: 700 15.5px 'DM Mono', monospace; color: #7d6b3c; }
.frontier-card p { margin: 8px 0 0; font-size: 13.2px; color: #7a887f; line-height: 1.5; }
.frontier-note { color: #6f8377 !important; }

/* ---------- treasury ledger ---------- */
.ledger-headline strong { display: block; margin-top: 5px; font: 700 21.8px 'DM Mono', monospace; color: #2f5849; }
.ledger-headline small { font-size: 12.3px; color: #86948b; }
.ledger-headline.bad strong { color: #a35b48; }
.ledger-spark { width: 100%; height: 46px; margin: 14px 0 4px; }
.spark-line { fill: none; stroke: #4f8c6a; stroke-width: 1.4; vector-effect: non-scaling-stroke; }
.spark-zero { stroke: #c4cec6; stroke-width: 1; stroke-dasharray: 3 3; vector-effect: non-scaling-stroke; }
.ledger-columns { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; margin-top: 12px; }
.ledger-columns h4 { margin: 0 0 10px; font: 700 14.6px Manrope; color: #37594c; }
.ledger-row { display: grid; grid-template-columns: minmax(0, 1fr) 64px; gap: 6px 10px; padding: 8px 0; border-bottom: 1px solid #e7eae2; }
.ledger-label { font-size: 14.2px; color: #466154; }
.ledger-value { text-align: right; font: 700 14.6px 'DM Mono', monospace; }
.ledger-value.good { color: var(--good); }
.ledger-value.bad { color: var(--bad); }
.ledger-note { grid-column: 1 / -1; margin: 0; font-size: 12.8px; color: #8a978e; line-height: 1.45; }
.ledger-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 8px; margin-top: 18px; }
.ledger-facts > div { padding: 9px 10px; background: #f1f4ec; border: 1px solid var(--panel-line); }
.ledger-facts span { display: block; font: 11.4px 'DM Mono', monospace; letter-spacing: 1px; color: #86948b; }
.ledger-facts strong { display: block; margin-top: 4px; font: 700 17.3px 'DM Mono', monospace; color: #2f5849; }
.ledger-advice { margin-top: 18px; padding: 13px 15px; background: #f0f3ea; border-left: 3px solid #b7cbae; }
.ledger-advice h4 { margin: 0 0 7px; font: 700 14.6px Manrope; color: #37594c; }
.ledger-advice p { margin: 0; font-size: 14.2px; color: #6e7d73; line-height: 1.6; }
.guide-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 14px; }
/* The aim leads and spans the grid, because it is the one thing the old guide
   never said and the one thing every other section assumes you already know. */
.guide-aim { grid-column: 1 / -1; }
.guide-aim h4 { color: #a3703f; }
.guide-aim p strong { color: #2f6350; }
body.mode-night .guide-aim h4 { color: #e0b463; }
body.mode-night .guide-aim p strong { color: #8fc0a5; }
.guide-again { grid-column: 1 / -1; }
.guide-again .panel-action { margin-top: 10px; }

/* The tester tools. Marked as plainly as possible - somebody who sees this
   block and is not testing the game should know at once that it is not for
   them, and somebody who is should be able to find it in a crowded panel. */
.guide-admin {
  grid-column: 1 / -1;
  padding: 14px 16px; border-radius: 3px;
  background: rgba(232, 201, 138, .07);
  border: 1px dashed rgba(232, 201, 138, .45);
}
.guide-admin h4 { display: flex; align-items: center; gap: 9px; }
.admin-tag {
  padding: 3px 7px; border-radius: 2px;
  background: #d9a04e; color: #23241c;
  font: 700 10.4px 'DM Mono', monospace; letter-spacing: 1.2px;
}
.guide-admin .panel-action { margin-top: 11px; }
.guide-admin .panel-action:disabled { opacity: .6; cursor: default; }

/* The same mark in the topbar, so a tester can see at a glance which account
   they are signed in as without opening anything. */
.admin-badge { display: none; }
body.is-admin .admin-badge {
  display: inline-block; margin-left: 2px;
  padding: 3px 7px; border-radius: 2px;
  background: #d9a04e; color: #23241c;
  font: 700 10px 'DM Mono', monospace; letter-spacing: 1.2px;
}
.guide-grid h4 { margin: 0 0 6px; font: 700 15.1px Manrope; color: #37594c; }
.guide-grid p { margin: 0; font-size: 14.2px; color: #74837a; line-height: 1.65; }

/* ---------- war room ---------- */
.war-room {
  position: fixed; z-index: 60; inset: 5vh 5vw; padding: 20px 24px 22px;
  display: flex; flex-direction: column; gap: 12px; overflow-y: auto;
  background: var(--panel); border: 1px solid #b6cbb8; box-shadow: 0 25px 80px #112b234d;
}
.war-subtitle { margin: 5px 0 0; font: 12.8px 'DM Mono', monospace; letter-spacing: 1px; color: #86948b; }
.battle-scene {
  display: grid; grid-template-columns: 1fr 1.6fr 1fr; min-height: 168px;
  background: #293e39; border: 1px solid #415f52; position: relative; overflow: hidden;
  --front: .2; --intensity: .3;
}
.battle-lane { position: relative; min-width: 0; overflow: hidden; }
.friendly-lane { background: linear-gradient(110deg, #2f5a4d, #4e7a64); }
.enemy-lane { background: linear-gradient(250deg, #7d4e4b, #b3726a); }
.army-banner { position: absolute; top: 12px; left: 15px; right: 15px; color: #e2f0dc; font: 700 13.7px 'DM Mono', monospace; letter-spacing: 1px; }
.enemy-banner { text-align: right; }
.army-banner span { display: block; margin-top: 4px; color: #c3d8c6; font-size: 11.9px; letter-spacing: .6px; font-weight: 400; }
.enemy-banner span { color: #f0c8bd; }
.formation { position: absolute; bottom: 18px; left: 15px; display: grid; grid-template-columns: repeat(4, 14px); gap: 8px; }
.enemy-formation { left: auto; right: 15px; }
.formation i { width: 11px; height: 17px; display: block; border-radius: 6px 6px 2px 2px; background: #dcebd2; box-shadow: 0 4px 0 #1c4036; }
.enemy-formation i { background: #f3d1c8; box-shadow: 0 4px 0 #713f3d; }
.is-advancing .friendly-formation { animation: push-forward 2.6s ease-in-out infinite alternate; }
.is-advancing .enemy-formation { animation: give-ground 2.6s ease-in-out infinite alternate; }
.is-holding .friendly-formation { animation: dig-in 3.4s ease-in-out infinite alternate; }
.is-retreating .friendly-formation { animation: fall-back 2.2s ease-in-out infinite alternate; }
.is-flanking .friendly-formation { animation: wheel-wide 2.4s ease-in-out infinite alternate; }
@keyframes push-forward { to { transform: translateX(16px); } }
@keyframes give-ground { to { transform: translateX(-12px); } }
@keyframes dig-in { to { transform: translateY(3px); } }
@keyframes fall-back { to { transform: translateX(-20px); opacity: .8; } }
@keyframes wheel-wide { to { transform: translate(14px, -12px); } }

.battle-ground { position: relative; background: radial-gradient(ellipse at center, #62705f 0, #3b514a 55%, #263a37 100%); overflow: hidden; }
.front-track { position: absolute; left: 6%; right: 6%; top: 50%; height: 5px; margin-top: -2px; background: #ffffff1f; border-radius: 3px; }
.front-fill { height: 100%; background: linear-gradient(90deg, #6fae8c, #e0c27d); border-radius: 3px; transition: width .35s ease; }
.clash {
  position: absolute; top: 50%; transform: translate(-50%, -50%); width: 74px; height: 44px;
  display: grid; place-items: center; border: 1px solid #e4c47c; border-radius: 50%;
  background: #d59c5733; color: #f4d596; font: 11px 'DM Mono', monospace; letter-spacing: .5px;
  transition: left .35s ease; animation: impact-pulse 1.8s ease-in-out infinite;
}
.is-sieging .clash { border-color: #d1d6c4; background: #7c88762e; }
.supply-road { position: absolute; left: 6%; bottom: 12px; color: #b9cbb2; font: 11px 'DM Mono', monospace; letter-spacing: 1px; }
.battle-scene .battle-smoke { opacity: calc(var(--intensity) * .9); }
.battle-scene .tracer, .battle-scene .battle-flash { opacity: calc(var(--intensity)); }
.is-holding .tracer, .is-retreating .tracer { animation-duration: 3.4s; }
.is-over .battle-smoke, .is-over .tracer, .is-over .battle-flash { display: none; }
.smoke-one { left: 30%; top: 62%; } .smoke-two { right: 28%; top: 26%; animation-delay: 1.2s; }
.tracer-one { left: 8%; top: 32%; } .tracer-two { right: 8%; top: 68%; }
.battle-flash { left: calc(var(--front) * 88% + 6%); top: 46%; }

.war-phase-strip { display: flex; flex-wrap: wrap; gap: 5px; }
.phase-chip { padding: 5px 9px; border: 1px solid var(--panel-line); background: #f3f5ee; color: #7a887f; font: 600 12.8px Manrope; border-radius: 12px; }
.phase-chip.done { background: #e5efe2; color: #4f7b62; }
.phase-chip.active { background: #2d5b4d; border-color: #2d5b4d; color: #f1f5ea; }

.war-room-grid { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: 18px; }
.war-column h4 { margin: 0 0 8px; font: 700 14.6px Manrope; color: #37594c; }
.war-divisions { display: grid; gap: 5px; margin-bottom: 12px; }
.war-division { display: grid; grid-template-columns: 24px minmax(0, 1fr) 110px; gap: 9px; align-items: center; padding: 8px 10px; border: 1px solid var(--panel-line); background: #f7f8f3; }
.war-division.is-spent { opacity: .5; }
.division-icon { font-size: 16.4px; }
.war-division strong { display: block; font-size: 14.2px; }
.war-division small { display: block; margin-top: 2px; font: 12.3px 'DM Mono', monospace; color: #86948b; }
.division-meters { display: grid; gap: 4px; }
.war-log { max-height: 190px; overflow-y: auto; padding: 10px 12px; background: #1d332dED; border-left: 3px solid #d59b4f; }
.log-line { margin: 0 0 7px; font-size: 13.7px; color: #d3e3d3; line-height: 1.45; }
.log-line:first-child { color: #fff3d6; font-weight: 600; }
.log-line.victory { color: #a7e0b4; }
.log-line.retreat, .log-line.losses { color: #f0b4a4; }
.log-line.siege { color: #e8d6a8; }
.war-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px; margin-bottom: 14px; }
.war-tile { padding: 10px 11px; background: #eef3e9; border: 1px solid #d5e3d4; }
.war-tile span { display: block; font: 11.4px 'DM Mono', monospace; letter-spacing: 1px; color: #84928a; }
.war-tile strong { display: block; margin-top: 5px; font: 700 19.1px 'DM Mono', monospace; color: #28534b; }
.war-tile.good strong { color: var(--good); }
.war-tile.fair strong { color: var(--fair); }
.war-tile.bad strong { color: var(--bad); }
.war-intel { display: grid; gap: 4px; margin-bottom: 14px; }
.intel-row { display: flex; justify-content: space-between; padding: 6px 9px; background: #f4f2e8; border: 1px solid #e0dbc9; font-size: 13.7px; color: #7d7663; }
.intel-row strong { font: 600 13.7px 'DM Mono', monospace; color: #5c5540; }
.war-conditions { display: grid; gap: 6px; }
.condition-row { padding: 8px 10px; background: #f5f6f0; border-left: 3px solid #b9c7b6; }
.condition-row strong { display: block; font-size: 14.2px; color: #37594c; }
.condition-row p { margin: 3px 0 0; font-size: 13.2px; color: #7a887f; line-height: 1.45; }
.war-actions {
  position: sticky; bottom: -22px; z-index: 2; display: flex; flex-wrap: wrap; gap: 7px;
  padding: 10px 0 12px; margin-bottom: -4px; background: var(--panel);
  box-shadow: 0 -10px 16px -8px #14312622;
}
.war-command { border: 1px solid #c9d9c8; padding: 9px 14px; background: #f3f5ed; color: #567064; cursor: pointer; font: 600 13.7px Manrope; display: flex; flex-direction: column; align-items: center; gap: 1px; line-height: 1.25; }
.war-command small { font: 500 10.6px 'DM Mono', ui-monospace, monospace; opacity: .72; letter-spacing: .01em; }
.war-command.active { background: #2d5b4d; color: white; border-color: #2d5b4d; }
.war-command:disabled { opacity: .45; cursor: not-allowed; }
.war-status { margin: 0; padding: 10px 12px; background: #f0f3ea; border-left: 3px solid #b7cbae; font-size: 14.6px; color: #5f7268; line-height: 1.55; }

/* ---------- dusk / night ---------- */
body.mode-dusk { --land: #cdd2b6; --sea-shallow: #93b4b6; --sea-deep: #6a8f96; }
body.mode-night { --land: #6f8474; --sea-shallow: #2c4b53; --sea-deep: #17323c; --panel-line: #2c403c; }
body.mode-night .map-wrap { filter: none; border-color: #39504b; background: #101d1d; }
body.mode-night .coast-line { stroke: #21403a; opacity: .9; }
body.mode-night .land-plate { fill: #536b5c; }
body.mode-night .province-label { fill: #e6f0e2; stroke: #1b302b; }
body.mode-night .country-label { fill: #dbe9d9; stroke: #14282400; opacity: .45; }
body.mode-night .sea-label { fill: #8fd0d8; opacity: .5; }
body.mode-night .terrain-glyph { opacity: .38; }
body.mode-night .popout { background: #16241f; border-color: #385048; color: #d6e3d5; }
body.mode-night .popout-head { background: #10201d; border-color: #2c403c; }
body.mode-night .popout-head h2, body.mode-night .section-title,
body.mode-night .detail-block h4, body.mode-night .war-column h4 { color: #d8e5d8; }
body.mode-night .summary-tile, body.mode-night .province-row, body.mode-night .province-detail,
body.mode-night .group-card, body.mode-night .division-card, body.mode-night .court-card,
body.mode-night .frontier-card, body.mode-night .commander-card, body.mode-night .alliance-row,
body.mode-night .building-card, body.mode-night .war-division, body.mode-night .war-tile,
body.mode-night .ledger-facts > div, body.mode-night .people-headline > div,
body.mode-night .army-headline > div, body.mode-night .diplomacy-headline > div,
body.mode-night .ledger-headline > div, body.mode-night .watch-item {
  background: #1c302a; border-color: #344b44; color: #cfe0d0;
}
body.mode-night .summary-tile strong, body.mode-night .row-main strong,
body.mode-night .detail-head h3, body.mode-night .group-head b,
body.mode-night .war-tile strong, body.mode-night .ledger-facts strong { color: #d7ecd8; }
body.mode-night .panel-action, body.mode-night .chip, body.mode-night .building-button,
body.mode-night .war-command, body.mode-night .policy-chip, body.mode-night .mini-action {
  background: #274a3d; border-color: #43695a; color: #d6ead7;
}
body.mode-night .panel-action.active, body.mode-night .chip.active,
body.mode-night .war-command.active { background: #5f8a6f; border-color: #5f8a6f; color: #0f1e1a; }
body.mode-night .panel-note, body.mode-night .ledger-advice,
body.mode-night .condition-row, body.mode-night .war-status { background: #1b332c; border-left-color: #5f8a6f; color: #b9cfbc; }
body.mode-night .opinion-entry { background: #1b332c; color: #c3d6c5; }
body.mode-night .crown-tax { background: #2a2e22; border-color: #4a4a38; }
body.mode-night .request-card { background: #2b2b22; border-color: #4d4a36; }
body.mode-night .intel-row { background: #24291f; border-color: #454a37; color: #cfc9ac; }
body.mode-night .ledger-button { background: #22443a; border-color: #416b58; color: #d6ead7; }
body.mode-night .app-footer { background: #101b1a; }
body.mode-night .popout-scrim { background: #04100d80; }
body.mode-night .focus-action, body.mode-night .governor-row, body.mode-night .strategy-picker {
  background: #1c302a; border-color: #344b44;
}
body.mode-night .focus-action strong { color: #d7ecd8; }
body.mode-night .occupation-block { background: #2c2620; border-color: #4a3f33; }
body.mode-night .detail-block.occupation { background: #2c2620; border-color: #4a3f33; }

/* ---------- responsive ---------- */
@media (max-width: 1400px) {
  .dashboard-grid { grid-template-columns: 250px minmax(0, 1fr) 320px; }
  .kingdom-summary { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 1150px) {
  .dashboard-grid { grid-template-columns: minmax(0, 1fr) 320px; }
  .left-panel { display: none; }
  .kingdom-layout { grid-template-columns: 1fr; }
  .people-columns, .ledger-columns { grid-template-columns: 1fr; }
  .war-room-grid { grid-template-columns: 1fr; }
}
@media (max-width: 860px) {
  /* The 0.1 stylesheet turned the sidebars into two-column grids and clipped
     the shell; both have to be undone before the stacked layout works. */
  .app-shell { overflow: visible; width: 100%; }
  .dashboard-grid { display: flex; flex-direction: column; }
  .left-panel, .right-panel { display: block; max-height: none; overflow: visible; }
  .left-panel { order: 3; border-width: 1px 0 0; }
  .right-panel { order: 2; border-width: 1px 0 0; }
  .map-stage { order: 1; }
  .topbar { height: auto; min-height: 60px; padding: 8px 14px; gap: 10px; flex-wrap: wrap; }
  .topbar-center { display: none; }
  .topbar-actions { margin-left: auto; gap: 8px; }
  .brand-lockup { min-width: 0; }
  .map-toolbar { padding: 14px 16px 10px; flex-wrap: wrap; gap: 10px; }
  .map-toolbar > div:first-child { min-width: 0; flex: 1 1 220px; }
  .map-summary { margin-left: 0; gap: 14px; text-align: left; }
  .map-wrap { height: 58vh; min-height: 300px; margin: 0 10px 10px; }
  .map-footer { height: auto; padding: 10px 16px; gap: 8px 16px; flex-wrap: wrap; }
  .command-tabs { position: static; }
  .global-response { position: static; }
  .popout { top: 56px; left: 8px; right: 8px; transform: none; width: auto; max-height: calc(100vh - 76px); }
  .popout-body { padding: 14px 14px 20px; }
  .kingdom-summary { grid-template-columns: repeat(2, 1fr); }
  .kingdom-layout, .people-columns, .ledger-columns, .war-room-grid { grid-template-columns: 1fr; }
  .province-list { max-height: 320px; }
  .war-room { inset: 3vh 8px; padding: 14px; }
  .battle-scene { grid-template-columns: 1fr; grid-template-rows: 84px 1fr 84px; min-height: 260px; }
  .formation { grid-template-columns: repeat(6, 12px); }
  .war-stats { grid-template-columns: repeat(2, 1fr); }
  .app-footer { flex-wrap: wrap; gap: 8px 14px; }
  .footer-link { display: none; }
  @keyframes popout-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
}

@media (max-width: 620px) {
  .topbar { padding: 8px 10px; }
  .brand-lockup h1 { font-size: 20px; }
  .avatar, #guideButton { display: none; }
  .map-legend { display: none; }
  .map-toolbar h2 { font-size: 20px; }
  .play-hint { font-size: 13.7px; }
  .map-summary strong { font-size: 17.3px; }
  .command-tab { font-size: 15.5px; padding: 6px 1px; }
  .command-tab span { font-size: 10.5px; letter-spacing: 0; }
  .panel-section { padding: 16px 14px; }
  .kingdom-summary, .ledger-facts, .people-headline, .army-headline,
  .diplomacy-headline, .ledger-headline { grid-template-columns: 1fr 1fr; }
  .detail-metrics, .explain-row { grid-template-columns: 1fr; }
  .explain-row strong { margin-bottom: 2px; }
  .province-row { grid-template-columns: 22px minmax(0, 1fr) 30px; }
  .row-bars { display: none; }
  .alliance-row { grid-template-columns: 1fr; }
  .focus-stats { grid-template-columns: 1fr 1fr; }
  .focus-stat:nth-child(3n) { border-right: 1px solid var(--panel-line); }
  .focus-stat:nth-child(3n+1) { padding-left: 10px; }
  .focus-stat:nth-child(2n) { border-right: 0; }
  .focus-stat:nth-child(2n+1) { padding-left: 0; }
  .chip { padding: 6px 8px; }
  .war-stats { grid-template-columns: 1fr 1fr; }
  .war-actions { gap: 5px; }
  .war-command { padding: 8px 10px; font-size: 12.8px; }
}

/* ==================================================================
   0.3 — a bigger, deeper map: ocean, relief, cities, zoom
   Loaded after the 0.2 rules above, so anything here deliberately wins.
   ================================================================== */

/* The map earns more of the screen, and the left sidebar can fold away. */
.map-wrap { min-height: 520px; margin: 0 14px 10px; background: #123033; overflow: hidden; }
.map-canvas { cursor: grab; }
.map-canvas.is-panning { cursor: grabbing; }
.map-canvas.is-panning .province { pointer-events: none; }
body.map-wide .left-panel { display: none; }
body.map-wide .app-grid { grid-template-columns: 1fr 372px; }

/* ---------- ocean ---------- */
/* Open water runs well past the frame; depth is drawn outward from the shore
   by stroking the coast outline three times, so the sea reads as sea rather
   than as a coloured card the continent is sitting on. */
:root { --sea-shallow: #7fb6c0; --sea-deep: #24596b; }
.sea-plate { transition: opacity .4s ease; }
.sea-swell { pointer-events: none; opacity: .5; animation: swell-drift 26s linear infinite; }
@keyframes swell-drift { to { transform: translate(-39px, 0); } }
.sea-shelf path { fill: none; stroke-linejoin: round; pointer-events: none; }
.shelf-deep { stroke: #3f7f8d; stroke-width: 78; opacity: .5; }
.shelf-mid { stroke: #5b9faa; stroke-width: 42; opacity: .55; }
.shelf-shallow { stroke: #8ec7cb; stroke-width: 17; opacity: .6; }
.sea-currents path { stroke-width: 9; opacity: .18; }
.sea-label { letter-spacing: 4px; opacity: .48; }

/* ---------- land ---------- */
.land-shadow { fill: #0e2b2c; opacity: .55; }
.coast-glow { opacity: .35; }
.land-sheen { pointer-events: none; }
.coast-line { stroke: #f6f8ea; stroke-width: 2.2; vector-effect: non-scaling-stroke; opacity: .85; }
/* two elevation bands, blurred, so high ground looks like high ground */
.relief { pointer-events: none; }
.relief-mid { fill: #6f7a5a; opacity: .16; }
.relief-high { fill: #4f4b3f; opacity: .2; }
.province-border { stroke-width: 1.1; vector-effect: non-scaling-stroke; }
.country-border { stroke-width: 2.6; vector-effect: non-scaling-stroke; }
/* Restated after the non-scaling-stroke block above, which would otherwise
   win on stroke-width and flatten your own outline back to everybody
   else's. Non-scaling so the realm keeps the same weight at every zoom. */
.country-border.is-own { stroke-width: 3.6; vector-effect: non-scaling-stroke; }
.river { stroke: #6fb0c4; opacity: .9; }
.lake { stroke-width: 1.6; vector-effect: non-scaling-stroke; }

/* ---------- labels scale with the view, not with the world ----------
   Sizes are in world units, chosen so that at the default view (the whole
   continent across the card) they land at a readable number of screen pixels;
   --zoom-inv then holds that apparent size constant as the view closes in. */
.province-label { font-size: calc(27px * var(--zoom-inv, 1)); stroke-width: calc(6px * var(--zoom-inv, 1)); }
.country-label { font-size: calc(46px * var(--zoom-inv, 1)); stroke-width: calc(9px * var(--zoom-inv, 1)); }
.sea-label { font-size: calc(1em * var(--zoom-inv, 1)); }

/* ---------- cities ---------- */
/* Far out you see countries, mid you see provinces, close in you see the towns
   people actually live in. That is the whole point of zooming. */
.city { pointer-events: all; cursor: pointer; opacity: 0; transition: opacity .25s ease; }
.city-dot { fill: #3c4a3e; stroke: #f6f8ea; stroke-width: calc(2.6px * var(--zoom-inv, 1)); }
.city-core { fill: #f6f8ea; }
.city-spire { fill: #3c4a3e; }
.city.is-held .city-dot, .city.is-held .city-spire { fill: #24503c; }
.city-label {
  fill: #223c33; font: 600 calc(25px * var(--zoom-inv, 1)) Manrope; text-anchor: middle;
  pointer-events: none; paint-order: stroke; stroke: #f6f8ea;
  stroke-width: calc(6px * var(--zoom-inv, 1)); opacity: 0; transition: opacity .25s ease;
}
.realm-map[data-zoom="mid"] .city.is-seat,
.realm-map[data-zoom="near"] .city { opacity: 1; }
.realm-map[data-zoom="near"] .city.is-seat .city-label { opacity: .95; }
.realm-map[data-zoom="near"] .city.city-town .city-label { opacity: .8; }
.city.is-selected-province { opacity: 1; }
.city:hover .city-label { opacity: 1; }
/* close in, province names and fills get out of the way of the towns */
.realm-map[data-zoom="far"] .province-label { opacity: 0; }
.realm-map[data-zoom="far"] .province-label.is-selected { opacity: 1; }
.realm-map[data-zoom="near"] .province-label { opacity: 0; }
.realm-map[data-zoom="near"] .province-fill { fill-opacity: .34; }
.realm-map[data-zoom="near"] .province.is-selected .province-fill { fill-opacity: .5; }
.realm-map[data-zoom="near"] .country-label { opacity: 0; }
.realm-map[data-zoom="far"] .province-border { opacity: .2; }

/* ---------- harbours, lanes and shipping ---------- */
.harbour { opacity: 0; transition: opacity .25s ease; cursor: pointer; }
.harbour-ring { fill: #1d4c5a; fill-opacity: .35; stroke: #cfe9ec; stroke-width: calc(2.8px * var(--zoom-inv, 1)); }
.harbour-anchor { fill: none; stroke: #eaf7f7; stroke-width: calc(3px * var(--zoom-inv, 1)); stroke-linecap: round; }
.harbour.is-working .harbour-ring { fill: #2f7f6a; fill-opacity: .7; }
.harbour.is-blockaded .harbour-ring { fill: #8a3427; fill-opacity: .8; animation: hostile-pulse 1.5s ease-in-out infinite; }
.realm-map[data-zoom="mid"] .harbour.is-working,
.realm-map[data-zoom="near"] .harbour { opacity: 1; }
.map-stage[data-map-mode="trade"] .harbour,
.map-stage[data-map-mode="seas"] .harbour { opacity: 1; }

.layer-lanes { opacity: 0; transition: opacity .35s ease; pointer-events: none; }
.sea-lane { fill: none; stroke: #dff2f4; stroke-width: 2; stroke-dasharray: 5 9; opacity: .3; vector-effect: non-scaling-stroke; }
.map-stage[data-map-mode="seas"] .layer-lanes,
.map-stage[data-map-mode="trade"] .layer-lanes { opacity: .9; }

.trade-route { stroke-width: 3.4; vector-effect: non-scaling-stroke; opacity: .5; }
.trade-route.is-active { opacity: 1; }
.trade-route.is-raided { stroke: #b8503b; animation: hostile-pulse 1.2s ease-in-out infinite; }
/* ------------------------------------------------------------------ */
/* ships                                                               */
/* ------------------------------------------------------------------ */
/* One ship, drawn in parts, so that what a hull is doing is readable from the
   colour of its sail rather than from a different silhouette: a convoy under
   canvas, a squadron under a red pennant, a landing force low in the water. */
.trade-ship, .landing-convoy, .fleet, .voyage { pointer-events: none; }
.ship-hull {
  fill: #efe3c6; stroke: #3b3426; stroke-width: calc(2.6px * var(--zoom-inv, 1));
  stroke-linejoin: round; stroke-linecap: round;
}
.ship-deck {
  fill: none; stroke: #8a7a58; stroke-width: calc(1.6px * var(--zoom-inv, 1)); opacity: .8;
}
.ship-mast {
  fill: none; stroke: #3b3426; stroke-width: calc(2.4px * var(--zoom-inv, 1)); stroke-linecap: round;
}
.ship-sail {
  fill: #fbf5e4; stroke: #3b3426; stroke-width: calc(1.7px * var(--zoom-inv, 1));
  stroke-linejoin: round;
}
.ship-flag { fill: #b8503b; stroke: none; }
.ship-cargo { fill: #8a6a3e; stroke: #3b3426; stroke-width: calc(1.4px * var(--zoom-inv, 1)); stroke-linejoin: round; }
/* the water the bow is pushing: the one thing that says this hull is moving */
.ship-bow {
  fill: none; stroke: #f4fbfb; stroke-width: calc(2.4px * var(--zoom-inv, 1));
  stroke-linecap: round; opacity: .45;
}

/* every ship rides on the swell, and no two of them on the same beat */
.ship-bob {
  transform-box: fill-box; transform-origin: 50% 90%;
  animation: ship-bob 3.4s ease-in-out infinite;
}
.trade-ship .ship-bob { animation-duration: 4.1s; }
.landing-convoy .ship-bob { animation-duration: 2.6s; }
.voyage.is-blockade .ship-bob { animation-duration: 2.9s; }
@keyframes ship-bob {
  0%, 100% { transform: translateY(0) rotate(-1.7deg); }
  50% { transform: translateY(-1.6px) rotate(1.7deg); }
}

/* a ship moored in a harbour is scenery, and only shown when the map is either
   close enough in or in a view that is about the water */
.fleet { opacity: 0; transition: opacity .3s ease; }
.fleet .ship-hull { fill: #dfeadb; }
.fleet .ship-sail { fill: #eef4ea; }
.fleet .ship-bob { animation-duration: 5.2s; }
.fleet .ship-bow { opacity: 0; }
.fleet-label {
  fill: #eaf7f7; font: 600 calc(22px * var(--zoom-inv, 1)) 'DM Mono', monospace; text-anchor: middle;
  paint-order: stroke; stroke: #12343a; stroke-width: calc(6px * var(--zoom-inv, 1));
}
.realm-map[data-zoom="mid"] .fleet, .realm-map[data-zoom="near"] .fleet,
.map-stage[data-map-mode="seas"] .fleet, .map-stage[data-map-mode="war"] .fleet { opacity: 1; }

/* ------------------------------------------------------------------ */
/* a fleet under way                                                   */
/* ------------------------------------------------------------------ */
/* A voyage is always drawn, in every view and at every zoom: it is something
   happening now, not a feature of the coast. The route ahead of it is dotted
   and the water it has already crossed is solid, so the map answers both
   "where is the fleet" and "how much of this is left" without a number. */
.voyage-lane {
  fill: none; stroke: #dff2f4; stroke-width: 2.6; stroke-dasharray: 4 8;
  vector-effect: non-scaling-stroke; opacity: .5; stroke-linecap: round;
}
.voyage-wake {
  fill: none; stroke: #f0e3c4; stroke-width: 4; opacity: .45;
  vector-effect: non-scaling-stroke; stroke-linecap: round;
}
.voyage .ship-hull { fill: #f3ead4; }
.voyage .fleet-label { fill: #f6ecd4; }

/* a squadron sailing to close a coast: red canvas, red water behind it */
.voyage.is-blockade .ship-sail { fill: #e8bfb2; }
.voyage.is-blockade .ship-hull { fill: #e9d8c6; }
.voyage-wake.is-hostile { stroke: #d59a86; }
.voyage.is-blockade .fleet-label { fill: #f2c9ba; }

/* a fleet that has been turned around: same ships, no urgency */
.voyage.is-return { opacity: .78; }
.voyage.is-return .ship-flag { fill: #8a7a58; }
.landing-lane {
  fill: none; stroke: #e0a24d; stroke-width: 4; stroke-dasharray: 10 7;
  vector-effect: non-scaling-stroke; animation: route-flow 1.1s linear infinite;
}

/* ---------- zoom controls ---------- */
.map-zoom {
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%); z-index: 4;
  display: flex; flex-direction: column; gap: 6px;
  background: #0f2c2fdd; border: 1px solid #2d5a5c; border-radius: 4px; padding: 6px;
}
.map-zoom button {
  width: 30px; height: 26px; display: grid; place-items: center; cursor: pointer;
  background: #1a4346; color: #dff2f4; border: 1px solid #2f6265; border-radius: 2px;
  font: 600 15.5px 'DM Mono', monospace;
}
.map-zoom button:hover { background: #276266; }
.map-zoom button.wide { width: 30px; font-size: 12.8px; letter-spacing: 0; }
.map-zoom .zoom-level {
  text-align: center; color: #9fc6c8; font: 600 11.9px 'DM Mono', monospace; letter-spacing: .5px;
}
.map-hint {
  position: absolute; left: 50%; transform: translateX(-50%); bottom: 12px; z-index: 4; color: #cfe9ec;
  background: #0f2c2fcc; border: 1px solid #2d5a5c; border-radius: 3px; padding: 4px 8px;
  font: 500 11.4px 'DM Mono', monospace; letter-spacing: .3px; pointer-events: none;
  white-space: nowrap; max-width: calc(100% - 24px); overflow: hidden; text-overflow: ellipsis;
}

/* ---------- local roads ---------- */
/* Only meaningful once you are inside a province, so they cost nothing until
   the view is close: the seat of government and the towns it collects from. */
.layer-roads { opacity: 0; transition: opacity .3s ease; pointer-events: none; }
.realm-map[data-zoom="near"] .layer-roads { opacity: .75; }
.local-road {
  fill: none; stroke: #b9a98a; stroke-width: calc(4px * var(--zoom-inv, 1));
  stroke-linecap: round; stroke-dasharray: calc(11px * var(--zoom-inv, 1)) calc(7px * var(--zoom-inv, 1));
}
.local-road.is-paved { stroke: #cdbd9a; stroke-dasharray: none; stroke-width: calc(5px * var(--zoom-inv, 1)); }

/* ---------- the Admiralty ---------- */
.navy-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); gap: 8px; margin-bottom: 14px; }
.navy-tile { padding: 9px 11px; background: #f2f6f2; border: 1px solid #dde5dd; border-radius: 3px; }
.navy-tile span { display: block; font: 500 11.9px 'DM Mono', monospace; letter-spacing: 1px; color: #7d8d83; }
.navy-tile strong { display: block; margin-top: 3px; font: 700 20px 'DM Mono', monospace; color: #2f5849; }
.navy-tile small { display: block; margin-top: 2px; font-size: 12.8px; color: #7d8d83; line-height: 1.35; }
.navy-alert {
  margin: 0 0 12px; padding: 8px 11px; background: #f7e3da; border: 1px solid #e2bcab;
  border-left-width: 3px; border-radius: 3px; font-size: 13.7px; color: #8a3f2c; line-height: 1.45;
}
.section-note { margin: -4px 0 10px; font-size: 13.7px; color: #76867c; line-height: 1.5; }

.ship-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(196px, 1fr)); gap: 9px; margin-bottom: 18px; }
.ship-card { padding: 10px 11px; background: #f6f8f4; border: 1px solid #dde5dd; border-radius: 3px; display: flex; flex-direction: column; gap: 7px; }
.ship-card.has-some { border-left: 3px solid #4f8f72; background: #eef5ef; }
.ship-head { display: flex; align-items: center; gap: 8px; }
.ship-icon { font-size: 20px; }
.ship-head strong { display: block; font-size: 14.6px; color: #24413a; }
.ship-head small { display: block; font: 500 12.8px 'DM Mono', monospace; color: #7d8d83; }
.ship-card p { margin: 0; font-size: 13.2px; color: #6f7f75; line-height: 1.45; }
.ship-stats { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.ship-stats li { display: flex; justify-content: space-between; font-size: 12.8px; color: #7d8d83; }
.ship-stats b { font: 600 12.8px 'DM Mono', monospace; color: #2f5849; }
.ship-build {
  margin-top: auto; padding: 6px 8px; cursor: pointer; border-radius: 2px;
  background: #2f5849; color: #f2f6ec; border: 1px solid #24463a;
  font: 600 12.8px 'DM Mono', monospace; letter-spacing: .5px;
}
.ship-build:hover { background: #3a6b58; }
.ship-build:disabled { background: #e6eae4; color: #a6b1a8; border-color: #d8ded6; cursor: not-allowed; }

.route-list, .landing-list, .blockade-list { display: grid; gap: 8px; margin-bottom: 18px; }
.route-row {
  display: grid; grid-template-columns: 1fr auto auto; gap: 12px; align-items: center;
  padding: 9px 11px; background: #f6f8f4; border: 1px solid #dde5dd; border-left-width: 3px; border-radius: 3px;
}
.route-row.is-running { border-left-color: #4f8f72; background: #eef5ef; }
.route-row.is-raided { border-left-color: #b8503b; background: #f8e7e0; }
.route-main strong { display: block; font-size: 14.6px; color: #24413a; }
.route-main small { display: block; margin-top: 2px; font: 500 12.8px 'DM Mono', monospace; color: #7d8d83; }
.route-why { margin: 4px 0 0; font-size: 12.8px; color: #76867c; line-height: 1.4; }
.route-value { text-align: right; }
.route-value b { display: block; font: 700 17.3px 'DM Mono', monospace; color: #2f6349; }
.route-value span { font: 500 11.9px 'DM Mono', monospace; color: #8a978d; }
.route-controls { display: grid; gap: 5px; }
.route-stepper { display: flex; align-items: center; gap: 5px; }
.route-stepper span { font: 500 11px 'DM Mono', monospace; letter-spacing: .8px; color: #8a978d; width: 42px; }
.route-stepper b { min-width: 16px; text-align: center; font: 600 14.6px 'DM Mono', monospace; color: #2f5849; }
.route-stepper button {
  width: 20px; height: 20px; cursor: pointer; border-radius: 2px;
  background: #e8efe8; border: 1px solid #cfdacf; color: #2f5849; font: 600 14.6px 'DM Mono', monospace;
}
.route-stepper button:hover { background: #d8e6d9; }
.route-stepper button:disabled { color: #b6c0b7; cursor: not-allowed; }

.landing-row {
  display: grid; grid-template-columns: 1fr auto auto; gap: 12px; align-items: center;
  padding: 10px 11px; background: #f6f8f4; border: 1px solid #dde5dd; border-left: 3px solid #5d8fa8; border-radius: 3px;
}
.landing-row.is-risky { border-left-color: #c98a3f; background: #f9f0e2; }
.landing-main strong { display: block; font-size: 14.6px; color: #24413a; }
.landing-main small { display: block; margin-top: 2px; font: 500 12.8px 'DM Mono', monospace; color: #7d8d83; }
.landing-main p { margin: 4px 0 0; font-size: 13.2px; color: #6f7f75; line-height: 1.45; max-width: 42ch; }
.landing-stats { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.landing-stats li { display: flex; gap: 10px; justify-content: space-between; font-size: 12.8px; color: #7d8d83; }
.landing-stats b { font: 600 12.8px 'DM Mono', monospace; color: #2f5849; }
.landing-go {
  padding: 8px 12px; cursor: pointer; border-radius: 2px; background: #8a3f2c; color: #fbf1e9;
  border: 1px solid #6f3122; font: 600 12.8px 'DM Mono', monospace; letter-spacing: .5px;
}
.landing-go:hover { background: #a04b34; }

.blockade-row {
  display: flex; gap: 12px; align-items: center; justify-content: space-between;
  padding: 9px 11px; background: #f6f8f4; border: 1px solid #dde5dd; border-radius: 3px;
}
.blockade-row.is-active { border-left: 3px solid #8a3f2c; background: #f8e7e0; }
.blockade-row strong { display: block; font-size: 14.6px; color: #24413a; }
.blockade-row small { display: block; margin-top: 2px; font: 500 12.8px 'DM Mono', monospace; color: #7d8d83; }
.blockade-row p { margin: 4px 0 0; font-size: 13.2px; color: #6f7f75; line-height: 1.45; max-width: 52ch; }
.blockade-toggle {
  padding: 7px 11px; cursor: pointer; border-radius: 2px; background: #e8efe8;
  border: 1px solid #cfdacf; color: #2f5849; font: 600 12.8px 'DM Mono', monospace; letter-spacing: .5px;
}
.blockade-toggle:hover { background: #d8e6d9; }

/* ---------- claiming free land ---------- */
.focus-detail {
  margin: 6px 0 0; padding: 7px 9px; background: #eef3ec; border: 1px solid #dbe4da;
  border-radius: 3px; font-size: 13.2px; color: #55665c; line-height: 1.5;
}
.frontier-card.is-unreachable { opacity: .72; border-style: dashed; }
.frontier-objection {
  margin: 6px 0 0; padding: 7px 9px; background: #f7efe2; border: 1px solid #e4d3b4;
  border-left-width: 3px; border-radius: 3px; font-size: 13.2px; color: #7d6330; line-height: 1.5;
}
.frontier-cost { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 2px; }
.frontier-cost li { display: flex; justify-content: space-between; font-size: 12.8px; color: #7d8d83; }
.frontier-cost b { font: 600 12.8px 'DM Mono', monospace; color: #2f5849; }

/* ==================================================================
   0.3 - the war room: a projection, and a field with real units on it
   ================================================================== */

/* ---------- projection ---------- */
.war-forecast {
  display: flex; gap: 18px; align-items: center; justify-content: space-between;
  margin: 0 0 12px; padding: 11px 14px; border-radius: 3px;
  background: #eef3ec; border: 1px solid #dbe4da; border-left: 4px solid #7d8d83;
}
.war-forecast[data-state="winning"] { background: #e6f1e6; border-left-color: #4f8f72; }
.war-forecast[data-state="losing"] { background: #f8e7e0; border-left-color: #b8503b; }
.war-forecast[data-state="stalled"] { background: #f7efe2; border-left-color: #c98a3f; }
.war-forecast[data-state="crossing"] { background: #e4eff3; border-left-color: #4f8fa6; }
.war-forecast[data-state="over"] { background: #eceee9; border-left-color: #6f7f75; }
.war-forecast.is-imminent { animation: forecast-urgent 1.1s ease-in-out infinite; }
@keyframes forecast-urgent { 50% { box-shadow: inset 0 0 0 2px #b8503b55; } }
.forecast-eyebrow { font: 500 11.9px 'DM Mono', monospace; letter-spacing: 1.4px; color: #7d8d83; }
.forecast-main strong { display: block; margin: 2px 0 3px; font: 700 20.9px 'DM Mono', monospace; color: #24413a; }
.forecast-main p { margin: 0; font-size: 13.7px; color: #5b6b61; line-height: 1.5; max-width: 68ch; }
.forecast-gauge { min-width: 132px; text-align: right; }
.gauge-track { height: 5px; background: #dbe2d8; border-radius: 3px; overflow: hidden; }
.gauge-fill { height: 100%; background: #4f8f72; transition: width .5s ease; }
.war-forecast[data-state="losing"] .gauge-fill { background: #b8503b; }
.war-forecast[data-state="stalled"] .gauge-fill { background: #c98a3f; }
.forecast-gauge small { display: block; margin-top: 4px; font: 500 11.9px 'DM Mono', monospace; color: #8a978d; }

/* ---------- the field ---------- */
/* One box, with the front line held in a CSS variable. Every unit is placed
   from that variable, so the whole picture moves when the simulation moves and
   nothing here animates anything it invented itself. */
.battle-field {
  /* The war room is a scrolling flex column and every child of the field is
     absolutely positioned, so without flex: none the field has no content
     height to defend and collapses to a line. */
  position: relative; flex: none; height: 300px; min-height: 300px;
  margin: 0 0 10px; overflow: hidden;
  border-radius: 3px; border: 1px solid #2c4a3f; --front: .5; --intensity: .4;
}
.war-forecast, .war-summary, .war-phase-strip { flex: none; }
.field-sky { position: absolute; inset: 0 0 58% 0; background: linear-gradient(#cfdfe4, #e7eee4); }
.field-ground {
  position: absolute; inset: 42% 0 0 0;
  background: linear-gradient(#7f9a72, #5d7a58 60%, #4a6448);
}
.battle-field[data-biome="desert"] .field-ground { background: linear-gradient(#d8c493, #bca86f 60%, #a08f5e); }
.battle-field[data-biome="desert"] .field-sky { background: linear-gradient(#e3d9bd, #f1e8cf); }
.battle-field[data-biome="mountain"] .field-ground { background: linear-gradient(#9a9c92, #75776d 60%, #5c5e56); }
.battle-field[data-biome="forest"] .field-ground { background: linear-gradient(#5f8158, #47653f 60%, #3a5334); }
.battle-field[data-biome="marsh"] .field-ground { background: linear-gradient(#7e9384, #60786a 60%, #4d6357); }
.battle-field[data-biome="tundra"] .field-ground { background: linear-gradient(#c3cfc9, #a3b3ab 60%, #8b9b93); }
.field-weather { position: absolute; inset: 0; pointer-events: none; }
.field-weather[data-weather="rain"] {
  background-image: repeating-linear-gradient(72deg, #ffffff22 0 1px, transparent 1px 7px);
  animation: weather-fall .55s linear infinite;
}
.field-weather[data-weather="storm"] {
  background-image: repeating-linear-gradient(66deg, #ffffff33 0 2px, transparent 2px 6px);
  animation: weather-fall .32s linear infinite; box-shadow: inset 0 0 90px #12222055;
}
.field-weather[data-weather="fog"] { background: #dfe7e4; opacity: .42; }
.field-weather[data-weather="heat"] { background: linear-gradient(#f6e2b955, transparent); }
@keyframes weather-fall { to { background-position: 24px 40px; } }

.field-banner {
  position: absolute; top: 8px; z-index: 4; padding: 3px 8px; border-radius: 2px;
  font: 600 11.9px 'DM Mono', monospace; letter-spacing: 1.2px; color: #f2f6ec; background: #24463a; opacity: .92;
}
.field-banner span { font-weight: 500; opacity: .82; letter-spacing: .4px; }
.field-banner.friendly-side { left: 8px; }
.field-banner.enemy-side { right: 8px; background: #7a3427; }

.objective-marker { position: absolute; right: 14px; bottom: 20px; z-index: 3; text-align: center; }
.objective-flag { display: block; width: 3px; height: 34px; margin: 0 auto; background: #f2e3c8; position: relative; }
.objective-flag::after {
  content: ''; position: absolute; left: 3px; top: 0; width: 18px; height: 11px;
  background: #b8503b; clip-path: polygon(0 0, 100% 0, 78% 50%, 100% 100%, 0 100%);
}
.objective-marker small {
  display: block; margin-top: 3px; font: 600 11px 'DM Mono', monospace; letter-spacing: .8px;
  color: #f6f8ea; text-shadow: 0 1px 3px #1d2f28;
}

/* the front line itself */
.battle-field .front-track {
  position: absolute; left: 0; right: 0; top: 50%; height: 3px; z-index: 2;
  background: #1d2f2833; transform: translateY(-50%);
}
.battle-field .front-fill { height: 100%; background: #f0e3c4; opacity: .7; transition: width .5s ease; }
.battle-field .clash {
  position: absolute; top: 13px; z-index: 7; transform: translateX(-50%);
  padding: 3px 9px; border-radius: 11px; background: #1d2f28dd; border: 1px solid #f0d9a8;
  font: 600 11.9px 'DM Mono', monospace; letter-spacing: .9px; color: #f6ecd4; white-space: nowrap;
  transition: left .5s ease;
}

/* ---------- unit counters ---------- */
.unit-layer { position: absolute; inset: 0; z-index: 3; pointer-events: none; }
.unit-counter {
  position: absolute; top: 50%; width: 62px; text-align: center;
  margin-top: calc(var(--row) * 19px);
  transition: left .6s ease, margin-top .6s ease, opacity .4s ease;
}
.unit-counter { left: calc(var(--pos) * 100%); }
.unit-counter.side-friendly { transform: translate(-100%, -50%); }
.unit-counter.side-enemy { transform: translate(0, -50%); }
.unit-counter.is-spent { opacity: .35; filter: grayscale(1); }
.unit-counter.is-flanking { animation: flank-sweep 1.6s ease-in-out infinite alternate; }
@keyframes flank-sweep { to { margin-top: calc(var(--row) * 19px - 9px); } }

.counter-body {
  display: flex; align-items: center; gap: 3px; justify-content: center;
  padding: 3px 4px; border-radius: 2px; background: #24463aee; border: 1px solid #12261f;
}
.side-enemy .counter-body { background: #7a3427ee; border-color: #5a2318; }
.counter-icon { font-size: 12.8px; color: #f2f6ec; line-height: 1; }
.counter-blocks { display: flex; gap: 1px; }
.counter-blocks i { width: 3px; height: 9px; border-radius: 1px; background: #dfe9d8; }
.counter-blocks i.gone { background: #ffffff26; }
.side-enemy .counter-blocks i { background: #f4ddd4; }
.counter-label {
  display: inline-block; margin-top: 3px; padding: 1px 4px; border-radius: 2px;
  background: #1d2f28b3; font: 600 11px 'DM Mono', monospace; letter-spacing: .3px; color: #f6f8ea;
}
.side-enemy .counter-label { background: #4a1f16b3; }
.counter-morale { height: 2px; margin: 2px 6px 0; background: #1d2f2855; border-radius: 2px; overflow: hidden; }
.counter-morale span { display: block; height: 100%; background: #8fd0a4; transition: width .5s ease; }
.side-enemy .counter-morale span { background: #e2a08f; }

/* ---------- the crossing ---------- */
.crossing-layer { position: absolute; inset: 0; z-index: 6; opacity: 0; transition: opacity .5s ease; pointer-events: none; }
.crossing-layer.is-active { opacity: 1; }
.crossing-sea {
  position: absolute; inset: 0;
  background: linear-gradient(#3f7f8d, #24596b);
  box-shadow: inset 0 0 80px #0d2a2b88;
}
.crossing-sea::after {
  content: ''; position: absolute; inset: 0; opacity: .3;
  background-image: repeating-linear-gradient(90deg, #ffffff22 0 2px, transparent 2px 26px);
  animation: swell-drift 9s linear infinite;
}
.crossing-convoy {
  position: absolute; top: 50%; left: calc(8% + var(--crossed, 0) * 76%);
  transform: translate(-50%, -50%); text-align: center;
  transition: left .6s linear; animation: convoy-roll 2.6s ease-in-out infinite;
}
@keyframes convoy-roll { 50% { transform: translate(-50%, calc(-50% - 5px)) rotate(-2deg); } }
.convoy-ship { font-size: 20.9px; margin: 0 1px; filter: drop-shadow(0 2px 3px #0a20218c); }
.crossing-convoy small {
  display: block; margin-top: 4px; padding: 2px 7px; border-radius: 10px;
  background: #0f2c2fdd; color: #dff2f4; font: 600 11px 'DM Mono', monospace; letter-spacing: .9px;
}

/* ---------- effects ---------- */
.gun-flash {
  position: absolute; top: 50%; left: calc(var(--front) * 100% - 14%); width: 26px; height: 26px;
  transform: translate(-50%, -50%); border-radius: 50%; opacity: 0; z-index: 5;
  background: radial-gradient(#fff6d8, #f0b04a00 70%);
}
.gun-flash.is-firing { animation: gun-fire .9s steps(2, end) infinite; }
@keyframes gun-fire { 0%, 60% { opacity: 0; } 70% { opacity: 1; } 100% { opacity: 0; } }
.casualty-layer { position: absolute; inset: 0; z-index: 4; pointer-events: none; }
.casualty-mark {
  position: absolute; width: 5px; height: 5px; border-radius: 50%; background: #7c2f22;
  box-shadow: 0 0 5px #7c2f2288; animation: casualty-fade 1.5s ease-out forwards;
}
@keyframes casualty-fade {
  0% { opacity: .95; transform: scale(.4); }
  100% { opacity: 0; transform: scale(2.4) translateY(7px); }
}

/* ---------- the result ---------- */
.war-summary {
  margin: 0 0 12px; padding: 12px 14px; border-radius: 3px;
  background: #f6f8f4; border: 1px solid #dde5dd;
}
.summary-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.summary-head strong { font: 700 17.3px 'Playfair Display', serif; color: #24413a; }
.summary-head span { font: 500 12.8px 'DM Mono', monospace; color: #8a978d; }
.summary-head.is-won strong { color: #2f6349; }
.summary-head.is-lost strong { color: #8a3f2c; }
.summary-stats { list-style: none; display: flex; flex-wrap: wrap; gap: 16px; margin: 9px 0; padding: 0; }
.summary-stats li { display: grid; }
.summary-stats span { font: 500 11.9px 'DM Mono', monospace; letter-spacing: .9px; color: #8a978d; }
.summary-stats b { font: 700 17.3px 'DM Mono', monospace; color: #2f5849; }
.war-summary p { margin: 0; font-size: 13.7px; color: #5b6b61; line-height: 1.55; }

/* ==================================================================
   0.3 - keeping a gesture cheap
   A zoom or a pan should write one viewBox attribute and re-rasterise as
   little as possible. Two rules do most of that work: layers that are not
   visible at this zoom are display:none rather than transparent, so they leave
   the render tree entirely; and while the map is actually being moved the
   continent-wide filters and the fine detail come off.
   ================================================================== */

/* invisible layers cost nothing */
.realm-map[data-zoom="far"] .layer-roads,
.realm-map[data-zoom="mid"] .layer-roads { display: none; }
.map-stage:not([data-map-mode="seas"]):not([data-map-mode="trade"]) .layer-lanes { display: none; }
.realm-map[data-zoom="far"] .city:not(.is-selected-province) { display: none; }
.realm-map[data-zoom="mid"] .city:not(.is-seat):not(.is-selected-province) { display: none; }
.realm-map[data-zoom="far"] .harbour:not(.is-working):not(.is-blockaded) { display: none; }
.map-stage[data-map-mode="seas"] .realm-map .harbour,
.map-stage[data-map-mode="trade"] .realm-map .harbour { display: block; }
/* city labels only exist close in, so they need not be laid out before that */
.realm-map:not([data-zoom="near"]) .city-label { display: none; }

/* while the view is moving: no continent-wide filters, no fine detail */
.realm-map.is-interacting .land-shadow,
.realm-map.is-interacting .coast-glow,
.realm-map.is-interacting .layer-relief { display: none; }
/* display:none, not visibility:hidden — a hidden element is still laid out,
   and laying out several hundred SVG text nodes is the thing being avoided */
.realm-map.is-interacting .terrain-glyph,
.realm-map.is-interacting .layer-cities,
.realm-map.is-interacting .layer-harbours,
.realm-map.is-interacting .layer-labels,
.realm-map.is-interacting .layer-roads { display: none; }
.realm-map.is-interacting .province.is-selected { filter: none; }
/* Your own outline carries a glow, and a filter is re-rasterised on every
   frame the view moves - the one thing this whole block exists to avoid. The
   stroke underneath it is pale gold and non-scaling, so the realm is still
   perfectly readable mid-gesture; it is only the halo that goes. */
.realm-map.is-interacting .country-border.is-own { filter: none; }
/* The coach ring is an animation on a stroke, and a gesture is the one moment
   worth trading every ornament for speed. The province keeps the stroke; only
   the breathing stops. */
.realm-map.is-interacting .province.is-coach-target .province-hatch { animation: none; }
.realm-map.is-interacting .province-fill,
.realm-map.is-interacting .province-integration { transition: none; }
.realm-map.is-interacting .sea-swell,
.realm-map.is-interacting .sea-currents path,
.realm-map.is-interacting .trade-route,
.realm-map.is-interacting .landing-lane { animation: none; }

/* Moving the map means rasterising every path in it again on every frame, so a
   gesture is the one moment worth trading detail for speed. Antialiasing the
   coastline is the single most expensive thing on the frame and the least
   missed at speed; rivers, lanes, the swell and the ships on it are all drawn
   again 180 ms after the last input. */
.realm-map.is-interacting { shape-rendering: optimizeSpeed; text-rendering: optimizeSpeed; }
.realm-map.is-interacting .layer-water,
.realm-map.is-interacting .layer-lanes,
.realm-map.is-interacting .sea-swell,
.realm-map.is-interacting .sea-currents,
.realm-map.is-interacting .layer-sites,
.realm-map.is-interacting .trade-ship,
.realm-map.is-interacting .fleet,
.realm-map.is-interacting .ship-bow,
.realm-map.is-interacting .province-integration { display: none; }
.realm-map.is-interacting .ship-bob { animation: none; }
/* the map is its own paint island: nothing outside it needs repainting when it
   moves, and nothing inside it can spill out */
.map-wrap { contain: paint; }

/* a town founded during play announces itself, then settles into the map */
.city.is-founded .city-dot { stroke: #f0d9a8; }
.city.is-new { display: block !important; }
.city.is-new .city-dot { animation: new-town 1.2s ease-out 3; transform-origin: center; }
.city.is-new .city-label { opacity: 1 !important; display: block !important; }
@keyframes new-town { 0% { transform: scale(2.4); opacity: .3; } 100% { transform: scale(1); opacity: 1; } }

/* ==================================================================
   0.3 - other people's wars
   ================================================================== */

/* ---------- on the map ---------- */
.layer-threats { pointer-events: none; }
.threat-arrow {
  fill: none; stroke: #8a6a2c; stroke-width: 3; stroke-dasharray: 12 8; opacity: .55;
  vector-effect: non-scaling-stroke; animation: route-flow 1.6s linear infinite;
}
.threat-arrow.is-against-you { stroke: #b8503b; stroke-width: 4.5; opacity: .95; animation-duration: .9s; }
/* the marker on the map: named apart from the panel header of the same idea,
   which is a div and was leaking its flex rules onto this circle */
.threat-point { fill: #c08a3a; stroke: #f6ecd4; stroke-width: 2; opacity: .8; }
.threat-point.is-against-you { fill: #b8503b; opacity: 1; animation: hostile-pulse 1.2s ease-in-out infinite; }

/* ---------- threats in the Army panel ---------- */
.threat-list { display: grid; gap: 10px; margin-bottom: 18px; }
.threat-card {
  padding: 11px 13px; background: #f8efe8; border: 1px solid #e2c7b6;
  border-left: 3px solid #c98a3f; border-radius: 3px;
}
.threat-card.is-pressed { border-left-color: #b8503b; background: #f8e7e0; }
.threat-card.is-critical { border-left-color: #8a3f2c; background: #f6ded5; animation: hostile-pulse 1.8s ease-in-out infinite; }
.threat-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; margin-bottom: 7px; }
.threat-head strong { font-size: 15.5px; color: #24413a; }
.threat-head small { display: block; margin-top: 2px; font: 500 12.8px 'DM Mono', monospace; color: #7d8d83; }
.threat-head b { font: 700 19.1px 'DM Mono', monospace; color: #8a3f2c; }
.threat-note { margin: 7px 0 9px; font-size: 13.2px; color: #6f7f75; line-height: 1.5; }

/* ---------- a siege on the focus card ---------- */
.siege-block {
  margin: 10px 0; padding: 9px 11px; background: #f8e7e0;
  border: 1px solid #e0b5a5; border-left: 3px solid #b8503b; border-radius: 3px;
}
.siege-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.siege-head strong { font-size: 14.2px; color: #8a3f2c; }
.siege-head span { font: 600 12.8px 'DM Mono', monospace; color: #a56754; }
.siege-block .meter { margin: 6px 0; }
.siege-block p { margin: 0 0 7px; font-size: 13.2px; color: #6f5a52; line-height: 1.5; }

/* ---------- what a court is thinking ---------- */
.court-mind {
  margin-top: 9px; padding: 8px 10px; background: #f1f4ef;
  border: 1px solid #dde5dd; border-radius: 3px;
}
.court-mind.is-alarming { background: #f8e7e0; border-color: #e0b5a5; }
.mind-head { display: flex; align-items: baseline; gap: 8px; }
.mind-goal {
  padding: 1px 6px; border-radius: 9px; background: #2f5849; color: #f2f6ec;
  font: 600 11px 'DM Mono', monospace; letter-spacing: 1px;
}
.court-mind.is-alarming .mind-goal { background: #8a3f2c; }
.mind-head small { font: 500 11.9px 'DM Mono', monospace; color: #8a978d; }
.court-mind p { margin: 5px 0 0; font-size: 13.2px; color: #5b6b61; line-height: 1.5; }
.mind-nature { color: #8a978d !important; font-style: italic; }

/* ---------- choosing where a town goes ---------- */
.layer-sites { pointer-events: all; }
.site-marker { cursor: pointer; }
.site-halo {
  fill: #f0c879; fill-opacity: .18; stroke: #e0a24d; stroke-width: calc(2.5px * var(--zoom-inv, 1));
  stroke-dasharray: calc(7px * var(--zoom-inv, 1)) calc(5px * var(--zoom-inv, 1));
  animation: site-breathe 2.4s ease-in-out infinite;
}
@keyframes site-breathe { 50% { fill-opacity: .34; } }
.site-dot { fill: #f6f8ea; stroke: #8a6a2c; stroke-width: calc(2.5px * var(--zoom-inv, 1)); }
.site-marker.is-selected .site-halo { fill-opacity: .45; stroke: #2f6349; stroke-width: calc(4px * var(--zoom-inv, 1)); }
.site-marker.is-selected .site-dot { fill: #2f6349; stroke: #f6f8ea; }
.site-marker:hover .site-halo { fill-opacity: .4; }
.site-label {
  fill: #f6ecd4; font: 600 calc(20px * var(--zoom-inv, 1)) 'DM Mono', monospace; text-anchor: middle;
  paint-order: stroke; stroke: #1d2f28; stroke-width: calc(6px * var(--zoom-inv, 1)); pointer-events: none;
}
/* while a site is being chosen, the towns already there get out of the way */
.realm-map.is-choosing-site .city-label { opacity: .25 !important; }

.founding-flow {
  margin-top: 8px; padding: 10px 11px; background: #f4f7f1;
  border: 1px solid #d5e0d3; border-left: 3px solid #4f8f72; border-radius: 3px;
}
.founding-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.founding-head strong { font-size: 14.6px; color: #24413a; }
.founding-head span { font: 500 11.9px 'DM Mono', monospace; color: #8a978d; }
.founding-note { margin: 5px 0 8px; font-size: 13.2px; color: #6f7f75; line-height: 1.5; }
.site-chips { display: grid; grid-template-columns: repeat(auto-fit, minmax(88px, 1fr)); gap: 5px; }
.site-chip {
  padding: 6px 7px; text-align: left; cursor: pointer; border-radius: 2px;
  background: #ffffff; border: 1px solid #d5e0d3;
}
.site-chip strong { display: block; font: 600 12.8px 'DM Mono', monospace; color: #2f5849; }
.site-chip small { display: block; margin-top: 2px; font-size: 11.9px; color: #8a978d; }
.site-chip:hover { background: #eef4ec; }
.site-chip.active { background: #dfeede; border-color: #4f8f72; }
.founding-name { display: block; margin: 9px 0 8px; }
.founding-name span { display: block; font: 500 11.9px 'DM Mono', monospace; letter-spacing: 1px; color: #8a978d; }
.founding-name input {
  width: 100%; margin-top: 4px; padding: 7px 8px; border-radius: 2px;
  background: #ffffff; border: 1px solid #d5e0d3; color: #24413a; font: 500 14.6px Manrope;
}
.founding-name input:focus { outline: none; border-color: #4f8f72; }
.founding-actions { display: grid; gap: 5px; }

/* ==================================================================
   0.3 - the book of decrees
   ================================================================== */
.decree-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); gap: 8px; margin-bottom: 16px; }

.composer { display: grid; gap: 8px; padding: 11px 13px; background: #f4f7f1; border: 1px solid #d5e0d3; border-radius: 3px; }
.compose-row { display: grid; grid-template-columns: 108px 1fr; gap: 10px; align-items: center; }
.compose-row > span { font: 500 11.9px 'DM Mono', monospace; letter-spacing: 1.1px; color: #8a978d; text-align: right; }
.draft-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.draft-chip {
  padding: 5px 9px; cursor: pointer; border-radius: 11px; background: #ffffff;
  border: 1px solid #d5e0d3; color: #46584d; font: 500 13.2px Manrope;
}
.draft-chip:hover { background: #eef4ec; }
.draft-chip.active { background: #2f5849; border-color: #24463a; color: #f2f6ec; font-weight: 600; }
.draft-select, .draft-input {
  width: 100%; padding: 6px 8px; border-radius: 2px; background: #ffffff;
  border: 1px solid #d5e0d3; color: #24413a; font: 500 14.2px Manrope;
}
.draft-select:focus, .draft-input:focus { outline: none; border-color: #4f8f72; }

.decree-preview {
  margin: 12px 0 18px; padding: 13px; border-radius: 3px;
  background: #fbfaf6; border: 1px solid #dde5dd; border-left: 3px solid #2f5849;
}
.preview-text { margin: 0 0 11px; font: 600 15.5px 'Playfair Display', serif; color: #24413a; line-height: 1.5; }
.preview-columns { display: grid; grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr); gap: 16px; }
.preview-columns h5 {
  margin: 0 0 6px; font: 500 11.9px 'DM Mono', monospace; letter-spacing: 1.1px; color: #8a978d; text-transform: uppercase;
}
.preview-effects { list-style: none; margin: 0; padding: 0; display: grid; gap: 3px; }
.preview-effects li { display: flex; justify-content: space-between; gap: 8px; font-size: 13.2px; color: #6f7f75; }
.preview-effects b { font: 600 13.2px 'DM Mono', monospace; }
.preview-effects b.up { color: #2f6349; }
.preview-effects b.down { color: #a8503b; }

.predict-list { display: grid; gap: 4px; }
.predict-row { display: grid; grid-template-columns: 74px 1fr 34px 62px; gap: 6px; align-items: center; }
.predict-group { font-size: 12.8px; color: #5b6b61; }
.predict-track { position: relative; height: 5px; background: #e6ebe4; border-radius: 3px; }
.predict-track::before { content: ''; position: absolute; left: 50%; top: -2px; bottom: -2px; width: 1px; background: #c3cec3; }
.predict-bar { position: absolute; top: 0; height: 100%; border-radius: 3px; }
.predict-bar.is-against { right: 50%; background: #b8503b; }
.predict-bar.is-for { left: 50%; background: #4f8f72; }
.predict-row b { font: 600 13.2px 'DM Mono', monospace; text-align: right; }
.predict-row small { font-size: 11.9px; color: #8a978d; }
b.is-against, strong.is-against { color: #a8503b; }
b.is-for, strong.is-for { color: #2f6349; }

.preview-voice {
  margin-top: 11px; padding: 9px 11px; border-radius: 3px;
  background: #f4e9e2; border-left: 3px solid #b8503b;
}
.preview-voice.is-for { background: #e9f1e7; border-left-color: #4f8f72; }
.preview-voice p { margin: 0; font: italic 14.2px 'Playfair Display', serif; color: #4a4034; line-height: 1.55; }
.preview-voice small { display: block; margin-top: 5px; font: 500 11.9px 'DM Mono', monospace; color: #8a978d; }

.preview-verdict {
  display: flex; justify-content: space-between; align-items: flex-end; gap: 14px;
  margin-top: 12px; padding-top: 11px; border-top: 1px solid #e2e8e0;
}
.preview-verdict span { display: block; font: 500 11.9px 'DM Mono', monospace; letter-spacing: 1.1px; color: #8a978d; }
.preview-verdict strong { display: block; margin: 2px 0; font: 700 20.9px 'DM Mono', monospace; }
.preview-verdict small { font-size: 12.8px; color: #8a978d; }
.preview-verdict .panel-action { flex: none; min-width: 128px; }

.decree-list { display: grid; gap: 9px; margin-bottom: 18px; }
.decree-card { padding: 10px 12px; background: #f6f8f4; border: 1px solid #dde5dd; border-left: 3px solid #8a978d; border-radius: 3px; }
.decree-card.is-hated { border-left-color: #b8503b; background: #f8ece7; }
.decree-card.is-loved { border-left-color: #4f8f72; background: #eef5ef; }
.decree-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; }
.decree-head strong { font-size: 15.1px; color: #24413a; }
.decree-head small { display: block; margin-top: 2px; font: 500 12.3px 'DM Mono', monospace; color: #8a978d; }
.decree-text { margin: 6px 0; font-size: 13.7px; color: #5b6b61; line-height: 1.55; }
.decree-bars { margin: 7px 0 5px; }
.decree-note { margin: 0; font-size: 12.8px; color: #8a978d; line-height: 1.5; }

.debate-feed { display: grid; gap: 7px; }
.debate-line { padding: 8px 11px; border-radius: 3px; background: #f4e9e2; border-left: 3px solid #b8503b; }
.debate-line.is-for { background: #e9f1e7; border-left-color: #4f8f72; }
.debate-line p { margin: 0; font: italic 14.2px 'Playfair Display', serif; color: #4a4034; line-height: 1.55; }
.debate-line small { display: block; margin-top: 4px; font: 500 11.9px 'DM Mono', monospace; color: #8a978d; }

@media (max-width: 900px) {
  .preview-columns { grid-template-columns: 1fr; }
  .compose-row { grid-template-columns: 1fr; }
  .compose-row > span { text-align: left; }
}

/* ---------- the council ---------- */
.council-summary { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 10px; font: 500 12.8px 'DM Mono', monospace; color: #8a978d; }
.council-summary .is-against { color: #a8503b; }
.council-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(268px, 1fr)); gap: 9px; margin-bottom: 18px; }
.council-card { padding: 10px 12px; background: #f6f8f4; border: 1px solid #dde5dd; border-left: 3px solid #8a978d; border-radius: 3px; }
.council-card.is-opposed { border-left-color: #b8503b; background: #f8ece7; }
.council-card.is-doubtful { border-left-color: #c98a3f; background: #f9f2e5; }
.council-card.is-supportive, .council-card.is-enthusiastic { border-left-color: #4f8f72; background: #eef5ef; }
.council-card.is-vacant { border-left-color: #a6b1a8; border-style: dashed; opacity: .85; }
.council-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.council-head strong { font-size: 14.2px; color: #24413a; }
.council-stance { font: 500 11.9px 'DM Mono', monospace; letter-spacing: .8px; color: #8a978d; text-transform: uppercase; }
.council-speech { margin: 6px 0 7px; font: italic 14.2px 'Playfair Display', serif; color: #4a4034; line-height: 1.6; }
.council-meta { display: flex; flex-wrap: wrap; gap: 9px; margin-bottom: 7px; font: 500 11.9px 'DM Mono', monospace; color: #8a978d; }
.council-actions { display: flex; flex-wrap: wrap; gap: 5px; }
.council-actions .mini-action { flex: 1; min-width: 88px; }
.mini-action.warning { border-color: #e0b5a5; color: #8a3f2c; }

.dispute-card { margin-bottom: 10px; padding: 11px 13px; background: #f7efe2; border: 1px solid #e4d3b4; border-left: 3px solid #c98a3f; border-radius: 3px; }
.dispute-head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.dispute-head strong { font-size: 14.6px; color: #24413a; }
.dispute-head span { font: 500 11.9px 'DM Mono', monospace; letter-spacing: .9px; color: #8a978d; text-transform: uppercase; }
.dispute-card p { margin: 7px 0 9px; font: italic 14.6px 'Playfair Display', serif; color: #4a4034; line-height: 1.6; }
.dispute-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.dispute-actions .panel-action { flex: 1; min-width: 140px; }
.dispute-actions .panel-action small { display: block; margin-top: 2px; font: 400 11.9px 'DM Mono', monospace; opacity: .75; }

/* the wake behind a crossing: how far the fleet has actually come */
.landing-wake {
  fill: none; stroke: #f0e3c4; stroke-width: 5; opacity: .5;
  vector-effect: non-scaling-stroke; stroke-linecap: round;
}
.landing-convoy .fleet-label { fill: #f6ecd4; }


/* ------------------------------------------------------------------ */
/* notifications you can act on                                        */
/* ------------------------------------------------------------------ */
/* Anything that names a place or a decision is a way into the game, not just a
   line of news: clicking it moves the map there and opens the panel where the
   decision is actually made. */
.is-actionable { cursor: pointer; position: relative; transition: background .15s ease, transform .15s ease; }
.is-actionable:hover, .is-actionable:focus-visible {
  background: #2a4d4133; outline: none; transform: translateX(2px);
}
.is-actionable:focus-visible { box-shadow: inset 2px 0 0 #6fae90; }
.critical-go {
  display: block; margin-top: 6px; color: #6fae90;
  font: 600 11.9px 'DM Mono', monospace; letter-spacing: .1em; text-transform: uppercase;
}
.is-actionable:hover .critical-go { color: #8fd0b0; }
body.mode-day .is-actionable:hover, body.mode-day .is-actionable:focus-visible { background: #dcebe0; }
body.mode-day .critical-go { color: #2f6d55; }


/* ------------------------------------------------------------------ */
/* the dossier on a foreign court                                      */
/* ------------------------------------------------------------------ */
/* Everything you would want before answering a treaty offer, in the place the
   answer is given. The spotlight is the other half: the map itself says where. */
.court-dossier {
  margin: 10px 0; padding: 11px 12px; border: 1px solid #2f4f47; border-radius: 5px;
  background: #16282433;
}
.dossier-where { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.dossier-where small { color: #9fb8a8; font: 500 11.5px 'DM Mono', monospace; }
.dossier-where b { color: #d5e7d8; }
.panel-action.ghost {
  background: transparent; border: 1px solid #4a7a67; color: #9ed3b4; padding: 6px 10px;
  white-space: nowrap;
}
.panel-action.ghost:hover { background: #24463a; color: #d9f0e2; }
.dossier-facts {
  list-style: none; margin: 10px 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px 10px;
}
.dossier-facts li { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.dossier-facts span { color: #8aa396; font: 600 9.5px 'DM Mono', monospace; letter-spacing: .09em; }
.dossier-facts b { color: #dce9dd; font: 700 13px 'DM Mono', monospace; overflow-wrap: anywhere; }
.dossier-worth { margin: 11px 0 0; color: #cfe0d2; font-size: 13px; line-height: 1.6; }
.dossier-mind { margin: 6px 0 0; color: #97b0a2; font: italic 12.5px/1.6 'Playfair Display', serif; }

body.mode-day .court-dossier { background: #eef3ec; border-color: #cbd8cd; }
body.mode-day .dossier-where small { color: #5d7167; }
body.mode-day .dossier-where b, body.mode-day .dossier-facts b { color: #24413a; }
body.mode-day .dossier-worth { color: #35514a; }
body.mode-day .dossier-mind { color: #647a6f; }
body.mode-day .panel-action.ghost { border-color: #94b6a3; color: #2f6d55; }

/* the land a court holds, answered on the map */
.province.is-spotlight .province-fill {
  stroke: #f0c86a; stroke-width: calc(4px * var(--zoom-inv, 1));
  animation: spotlight-pulse 1.3s ease-in-out infinite;
}
@keyframes spotlight-pulse { 50% { stroke: #fff0c4; filter: brightness(1.18); } }


/* ------------------------------------------------------------------ */
/* the Outer Isles                                                     */
/* ------------------------------------------------------------------ */
/* Land the crown knows is there and nothing else. The fog is not a texture over
   the map, it is the map: an unsurveyed province is a silhouette, a rumoured one
   is a silhouette somebody has described, and only a surveyed one has a name and
   a deposit on it. */
.land-plate.is-frontier { fill: #24352f; stroke: none; }
.coast-line.is-frontier { fill: none; stroke: #9fb4a4; stroke-width: 2.4; opacity: .55; vector-effect: non-scaling-stroke; }
.province.is-frontier .province-fill { fill: var(--biome, #3d6350); opacity: .5; }
.province-border.is-frontier { fill: none; stroke: #16262b; stroke-width: 1.4; opacity: .5; vector-effect: non-scaling-stroke; }

.province-fog { fill: #0d1b20; opacity: .88; transition: opacity .8s ease; }
.province.is-rumoured .province-fog { opacity: .62; }
.province.is-surveyed .province-fog { opacity: 0; }
.province.is-surveyed .province-fill { opacity: .95; }
.province.is-colony .province-fill { fill: #6f9d87; opacity: 1; }
.province.is-frontier.is-selected .province-fill { stroke: #f0c86a; stroke-width: calc(3px * var(--zoom-inv, 1)); }

.province-label.is-frontier { opacity: 0; transition: opacity .5s ease; }
.province-label.is-frontier.is-visible { opacity: 1; }
.province-label.is-frontier .province-name {
  fill: #e8f2e8; font: 700 calc(26px * var(--zoom-inv, 1)) 'DM Mono', monospace; text-anchor: middle;
  paint-order: stroke; stroke: #0d1b20; stroke-width: calc(6px * var(--zoom-inv, 1));
}
.province-label.is-frontier .province-resource {
  fill: #f0c86a; font: 600 calc(21px * var(--zoom-inv, 1)) 'DM Mono', monospace; text-anchor: middle;
  paint-order: stroke; stroke: #0d1b20; stroke-width: calc(5px * var(--zoom-inv, 1));
}
.country-label.is-frontier { fill: #8fb0a0; opacity: .55; }
.harbour.is-frontier .harbour-ring { fill: none; stroke: #cfe0d2; stroke-width: calc(2px * var(--zoom-inv, 1)); opacity: .6; }


/* the Outer Isles, in the Frontier panel */
.isles-summary {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin: 12px 0 14px;
}
.isles-summary div {
  padding: 10px 12px; border: 1px solid #2f4f47; border-radius: 5px; background: #16282433;
}
.isles-summary span { display: block; color: #8aa396; font: 600 9.5px 'DM Mono', monospace; letter-spacing: .09em; }
.isles-summary strong { display: block; margin-top: 4px; color: #dce9dd; font: 700 15px 'DM Mono', monospace; }
.isles-sailing {
  margin: 0 0 12px; padding: 11px 13px; border-left: 3px solid #f0c86a; background: #2a241633;
}
.isles-sailing strong { display: block; color: #f0d9a8; font-size: 13px; }
.isles-sailing span { color: #b9ae90; font: 500 12px 'DM Mono', monospace; }
.isles-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 11px; }
.isle-card {
  border: 1px solid #2f4f47; border-radius: 6px; padding: 12px 13px; background: #16282433;
}
.isle-card.is-unknown { border-style: dashed; opacity: .82; }
.isle-card.is-colony { border-color: #6f9d87; background: #1d3a3033; }
.isle-head { display: flex; align-items: center; gap: 10px; }
.isle-head span { font-size: 20px; }
.isle-head strong { display: block; font-size: 14px; color: #e2eee3; }
.isle-head small { display: block; color: #92ab9d; font: 500 11.5px 'DM Mono', monospace; }
.isle-head b { margin-left: auto; color: #9ed3b4; font: 700 10px 'DM Mono', monospace; letter-spacing: .1em; }
.isle-card p { margin: 9px 0 0; color: #b8ccbd; font-size: 12.8px; line-height: 1.6; }
.isle-stats { list-style: none; margin: 10px 0 0; padding: 0; display: grid; grid-template-columns: repeat(2, 1fr); gap: 7px 10px; }
.isle-stats span { display: block; color: #8aa396; font: 600 9.5px 'DM Mono', monospace; letter-spacing: .08em; }
.isle-stats b { color: #dce9dd; font: 700 13px 'DM Mono', monospace; }
.isle-note { font-style: italic; color: #9ab3a4 !important; }

body.mode-day .isles-summary div, body.mode-day .isle-card { background: #eef3ec; border-color: #cbd8cd; }
body.mode-day .isles-summary strong, body.mode-day .isle-head strong, body.mode-day .isle-stats b { color: #24413a; }
body.mode-day .isle-card p { color: #43594f; }

/* what the deposits do, as opposed to what they are worth */
.isles-effects {
  list-style: none; margin: 0 0 12px; padding: 10px 13px; display: grid; gap: 5px;
  border-left: 3px solid #6f9d87; background: #1d3a3033;
}
.isles-effects li { color: #c6dcc9; font: 500 12.5px 'DM Mono', monospace; }
body.mode-day .isles-effects { background: #e7f0e8; }
body.mode-day .isles-effects li { color: #2f5344; }


/* ------------------------------------------------------------------ */
/* work orders                                                         */
/* ------------------------------------------------------------------ */
/* What a province has been told to do with its year. Every card states what it
   would actually produce under that order, so the trade is read rather than
   discovered. */
.order-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 9px; margin-top: 10px; }
.order-card {
  text-align: left; cursor: pointer; padding: 11px 12px; border-radius: 5px;
  border: 1px solid #2f4f47; background: #16282433; color: inherit; font: inherit;
  transition: border-color .15s ease, background .15s ease;
}
.order-card:hover { border-color: #6f9d87; background: #1d3a3033; }
.order-card.is-active { border-color: #f0c86a; background: #2a241633; }
.order-head { display: flex; align-items: center; gap: 8px; }
.order-head span { font-size: 16px; }
.order-head strong { font-size: 13px; color: #e2eee3; }
.order-head b { margin-left: auto; color: #f0c86a; font: 700 9px 'DM Mono', monospace; letter-spacing: .1em; }
.order-card p { margin: 7px 0 0; color: #9fb8a8; font: italic 12px/1.55 'Playfair Display', serif; }
.order-figures { list-style: none; margin: 9px 0 0; padding: 0; display: grid; grid-template-columns: repeat(2, 1fr); gap: 5px 8px; }
.order-figures span { display: block; color: #8aa396; font: 600 9px 'DM Mono', monospace; letter-spacing: .08em; }
.order-figures b { color: #dce9dd; font: 700 12.5px 'DM Mono', monospace; }

body.mode-day .order-card { background: #eef3ec; border-color: #cbd8cd; }
body.mode-day .order-card.is-active { border-color: #c79a3e; background: #f6efdd; }
body.mode-day .order-head strong, body.mode-day .order-figures b { color: #24413a; }
body.mode-day .order-card p { color: #5d7167; }


/* carriage: trade inside the realm */
.carriage-list { display: grid; gap: 9px; margin: 10px 0 4px; }
.carriage-row {
  display: grid; grid-template-columns: 1fr auto auto; gap: 12px; align-items: center;
  padding: 11px 13px; border: 1px solid #2f4f47; border-radius: 5px; background: #16282433;
}
.carriage-row.is-running { border-color: #6f9d87; background: #1d3a3033; }
.carriage-row strong { display: block; font-size: 13.5px; color: #e2eee3; }
.carriage-row small { display: block; color: #8aa396; font: 500 11.5px 'DM Mono', monospace; }
.carriage-row p { margin: 5px 0 0; color: #9fb8a8; font-size: 12.2px; line-height: 1.5; }
.carriage-value { text-align: right; }
.carriage-value b { display: block; color: #9ed3b4; font: 700 15px 'DM Mono', monospace; }
.carriage-value span { color: #8aa396; font: 500 9.5px 'DM Mono', monospace; letter-spacing: .08em; }

body.mode-day .carriage-row { background: #eef3ec; border-color: #cbd8cd; }
body.mode-day .carriage-row strong { color: #24413a; }
body.mode-day .carriage-row p { color: #55695f; }
body.mode-day .carriage-value b { color: #2f6d55; }


/* ------------------------------------------------------------------ */
/* the realm in danger                                                 */
/* ------------------------------------------------------------------ */
/* Only on screen when there is something to answer. The colour is the severity:
   a nervous border, a realm in danger, a realm fighting for its life. */
.peril-banner {
  margin: 12px 0 4px; padding: 13px 15px; border-radius: 6px;
  border: 1px solid #7a5a3a; border-left-width: 4px; background: #2a201433;
}
.peril-banner.is-serious { border-color: #b8823b; background: #33240f33; }
.peril-banner.is-grave { border-color: #b8503b; background: #33150f44; animation: hostile-pulse 2.4s ease-in-out infinite; }
.peril-head { display: flex; align-items: baseline; gap: 10px; }
.peril-head strong { font: 700 15px 'Playfair Display', serif; color: #f2d9a8; }
.peril-banner.is-grave .peril-head strong { color: #f4c4b4; }
.peril-head span { margin-left: auto; color: #c0a87e; font: 700 11px 'DM Mono', monospace; }
.peril-banner > p { margin: 7px 0 0; color: #cbbb9c; font-size: 13px; line-height: 1.6; }
.peril-effects { list-style: none; margin: 11px 0 0; padding: 0; display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.peril-effects span { display: block; color: #a8987a; font: 600 9.5px 'DM Mono', monospace; letter-spacing: .08em; }
.peril-effects b { color: #f2d9a8; font: 700 14px 'DM Mono', monospace; }
.peril-note { margin: 9px 0 0 !important; color: #a8987a !important; font: italic 12.5px/1.6 'Playfair Display', serif !important; }
.peril-banner .panel-action { margin-top: 10px; }

body.mode-day .peril-banner { background: #f7efe2; border-color: #c79a3e; }
body.mode-day .peril-head strong { color: #7a4a20; }
body.mode-day .peril-banner > p, body.mode-day .peril-note { color: #6b5a42 !important; }
body.mode-day .peril-effects b { color: #7a4a20; }


/* ------------------------------------------------------------------ */
/* the academy                                                         */
/* ------------------------------------------------------------------ */
/* A scholar is a person with a name, a field and a way of working, so the card
   is shaped like the councillor cards rather than like a technology tile. */
.academy-summary { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-bottom: 12px; }
.academy-summary div { padding: 10px 12px; border: 1px solid #2f4f47; border-radius: 5px; background: #16282433; }
.academy-summary span { display: block; color: #8aa396; font: 600 9.5px 'DM Mono', monospace; letter-spacing: .09em; }
.academy-summary strong { display: block; margin-top: 4px; color: #dce9dd; font: 700 15px 'DM Mono', monospace; }
.academy-effects {
  list-style: none; margin: 0 0 12px; padding: 10px 13px; display: grid; gap: 5px;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  border-left: 3px solid #a98bc4; background: #241d3033;
}
.academy-effects li { color: #cfc6dc; font: 500 12.5px 'DM Mono', monospace; }

.scholar-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); gap: 11px; }
.scholar-card { border: 1px solid #2f4f47; border-radius: 6px; padding: 12px 13px; background: #16282433; }
.scholar-card.is-offer { border-style: dashed; border-color: #a98bc4; }
.scholar-card.is-idle { border-color: #b8823b; }
.scholar-head { display: flex; align-items: center; gap: 10px; }
.scholar-head span { font-size: 19px; }
.scholar-head strong { display: block; font-size: 14px; color: #e2eee3; }
.scholar-head small { display: block; color: #92ab9d; font: 500 11.5px 'DM Mono', monospace; }
.scholar-head b { margin-left: auto; color: #d8b4a0; font: 700 12px 'DM Mono', monospace; }
.scholar-card p { margin: 8px 0 0; color: #b8ccbd; font-size: 12.8px; line-height: 1.55; }
.scholar-work b { color: #e6dcf0; }
.scholar-work.is-idle { color: #d9b48a; font-style: italic; }
.scholar-progress { height: 6px; border-radius: 6px; background: #21332e; margin-top: 9px; overflow: hidden; }
.scholar-progress span { display: block; height: 100%; background: #a98bc4; border-radius: 6px; transition: width .4s ease; }
.scholar-note { display: block; margin-top: 5px; color: #8aa396; font: 500 11px 'DM Mono', monospace; }
.scholar-controls { display: flex; align-items: center; gap: 10px; margin-top: 11px; flex-wrap: wrap; }
.scholar-controls .route-stepper b { min-width: 92px; text-align: center; }

.shelf-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); gap: 11px; }
.shelf { border: 1px solid #2f4f47; border-radius: 6px; padding: 12px 13px; background: #16282433; }
.shelf-head { display: flex; align-items: center; gap: 9px; }
.shelf-head strong { font-size: 13.5px; color: #e2eee3; }
.shelf-head b { margin-left: auto; color: #a98bc4; font: 700 12px 'DM Mono', monospace; }
.shelf > p { margin: 7px 0 0; color: #94ab9e; font: italic 12px/1.5 'Playfair Display', serif; }
.shelf-list { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 7px; }
.shelf-list li { padding-left: 14px; position: relative; opacity: .55; }
.shelf-list li::before { content: '○'; position: absolute; left: 0; color: #6d8579; }
.shelf-list li.is-known { opacity: 1; }
.shelf-list li.is-known::before { content: '●'; color: #a98bc4; }
.shelf-list strong { display: block; font-size: 12.5px; color: #dce9dd; }
.shelf-list small { display: block; color: #8fa697; font-size: 11.5px; line-height: 1.45; }

body.mode-day .academy-summary div, body.mode-day .scholar-card, body.mode-day .shelf {
  background: #f1eef5; border-color: #d3cbdd;
}
body.mode-day .academy-effects { background: #efeaf6; }
body.mode-day .academy-effects li, body.mode-day .academy-summary strong,
body.mode-day .scholar-head strong, body.mode-day .shelf-head strong, body.mode-day .shelf-list strong {
  color: #3a2f4a;
}
body.mode-day .scholar-card p, body.mode-day .shelf-list small { color: #5c5268; }


/* ------------------------------------------------------------------ */
/* saved realms                                                        */
/* ------------------------------------------------------------------ */
/* A slot shows what is in it — the season, the size of the realm, whether it
   was at war — so choosing one is choosing a moment rather than a number. */
.save-account {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 13px 15px; margin-bottom: 14px; border-radius: 6px;
  border: 1px solid #2f4f47; background: #16282433;
}
.save-account strong { display: block; font-size: 14px; color: #e2eee3; }
.save-account p { margin: 5px 0 0; max-width: 62ch; color: #9fb8a8; font-size: 12.8px; line-height: 1.6; }
.save-account .panel-action { margin-left: auto; white-space: nowrap; }

.save-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); gap: 11px; }
.save-card {
  border: 1px solid #2f4f47; border-radius: 6px; padding: 12px 13px; background: #16282433;
}
.save-card.has-save { border-color: #4f7a68; }
.save-card.is-auto { border-style: dashed; }
.save-head { display: flex; align-items: baseline; gap: 10px; }
.save-head strong { font-size: 14px; color: #e2eee3; }
.save-head span { margin-left: auto; color: #8aa396; font: 500 11px 'DM Mono', monospace; }
.save-head .is-empty { color: #6d8579; }
.save-realm { margin: 8px 0 0; color: #cfe0d2; font: italic 13px/1.5 'Playfair Display', serif; }
.save-realm.is-empty { color: #7d9488; }
.save-facts { list-style: none; margin: 10px 0 0; padding: 0; display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px 10px; }
.save-facts span { display: block; color: #8aa396; font: 600 9px 'DM Mono', monospace; letter-spacing: .08em; }
.save-facts b { color: #dce9dd; font: 700 12.5px 'DM Mono', monospace; }
.save-where { margin: 9px 0 0 !important; color: #8aa396 !important; font: 500 11px 'DM Mono', monospace !important; }
.save-actions { display: flex; gap: 6px; margin-top: 11px; flex-wrap: wrap; }
.save-actions .panel-action { flex: 1; min-width: 72px; text-align: center; }

body.mode-day .save-account, body.mode-day .save-card { background: #eef3ec; border-color: #cbd8cd; }
body.mode-day .save-account strong, body.mode-day .save-head strong, body.mode-day .save-facts b { color: #24413a; }
body.mode-day .save-account p, body.mode-day .save-realm { color: #55695f; }


/* the Firebase setup check */
.save-account-actions { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }
.setup-check {
  margin: 0 0 14px; padding: 12px 14px; border-radius: 6px;
  border: 1px solid #b8823b; border-left-width: 4px; background: #33240f33;
}
.setup-check.is-ok { border-color: #6f9d87; background: #1d3a3033; }
.setup-check.is-running { color: #b9ae90; font: italic 13px 'Playfair Display', serif; }
.setup-check > strong { display: block; font-size: 14px; color: #f2d9a8; }
.setup-check.is-ok > strong { color: #9ed3b4; }
.setup-check ol { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 9px; }
.setup-check li b { display: block; font: 700 12.5px 'DM Mono', monospace; color: #d9b48a; }
.setup-check li.is-ok b { color: #8fd0b0; }
.setup-check li span { display: block; margin-top: 2px; color: #b8ccbd; font-size: 12.5px; line-height: 1.5; }
.setup-check li em { display: block; margin-top: 4px; color: #f0c86a; font: italic 12.5px/1.5 'Playfair Display', serif; }
body.mode-day .setup-check { background: #f7efe2; }
body.mode-day .setup-check > strong { color: #7a4a20; }
body.mode-day .setup-check li span { color: #55695f; }

/* where the last save actually went */
.save-receipt {
  margin: 0 0 12px; padding: 9px 13px; border-radius: 5px;
  border-left: 3px solid #6d8579; background: #16282433;
  color: #b8ccbd; font: 500 12.5px 'DM Mono', monospace;
}
.save-receipt.is-cloud { border-color: #6f9d87; background: #1d3a3033; color: #cfe8d5; }
.save-receipt.is-failed { border-color: #b8503b; background: #33150f33; color: #e8c4b8; }
.save-receipt b { color: #e2eee3; }
body.mode-day .save-receipt { background: #eef3ec; color: #45594f; }
body.mode-day .save-receipt b { color: #24413a; }

/* ------------------------------------------------------------------ */
/* Together: one kingdom, more than one crown                          */
/* ------------------------------------------------------------------ */

.together-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin: 10px 0 16px;
}

/* The code is read down a phone, so it is set wide and unambiguous rather
   than small and tidy. */
.together-code-line {
  font-size: 14px;
  letter-spacing: 0.04em;
  color: var(--ink-dim, #9fb6ad);
  margin: 4px 0 10px;
}

.together-code-line strong {
  font-family: ui-monospace, "SF Mono", Consolas, monospace;
  font-size: 22px;
  letter-spacing: 0.22em;
  color: var(--gold, #e8c98a);
  margin-left: 8px;
}

.together-code {
  font-family: ui-monospace, "SF Mono", Consolas, monospace;
  font-size: 18px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  width: 9ch;
  padding: 8px 10px;
  color: inherit;
  background: rgba(0, 0, 0, 0.28);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 4px;
}

.together-members,
.together-feed {
  list-style: none;
  margin: 0 0 18px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.together-members li,
.together-feed li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  padding: 7px 10px;
  border-left: 2px solid transparent;
  background: rgba(255, 255, 255, 0.03);
  border-radius: 3px;
}

.together-members li.is-here { border-left-color: var(--good, #8fe0a5); }
/* Somebody who has shut their laptop has not left, and a partner waiting on a
   decision from them should be able to see the difference. */
.together-members li.is-away { opacity: 0.55; border-left-color: transparent; }
.together-feed li.is-refused { border-left-color: var(--bad, #ff9b8a); opacity: 0.8; }

.together-when {
  margin-left: auto;
  font-size: 11px;
  color: var(--ink-dim, #9fb6ad);
  white-space: nowrap;
}

.together-tag {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 2px 6px;
  border-radius: 999px;
  background: rgba(232, 201, 138, 0.16);
  color: var(--gold, #e8c98a);
}

.together-tag.is-warn {
  background: rgba(255, 155, 138, 0.16);
  color: var(--bad, #ff9b8a);
}

/* invites the host has cut, in the Together panel */
.together-invites {
  list-style: none;
  margin: 0 0 18px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.together-invites li {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 7px 10px;
  background: rgba(255, 255, 255, 0.03);
  border-radius: 3px;
}

.together-invite-code {
  font-family: ui-monospace, "SF Mono", Consolas, monospace;
  font-size: 15px;
  letter-spacing: 0.16em;
  color: var(--gold, #e8c98a);
}

.panel-action.subtle {
  background: transparent;
  font-size: 12px;
  padding: 5px 10px;
}

/* ------------------------------------------------------------------ */
/* The first five minutes: locked panels, hints, confirmations         */
/* ------------------------------------------------------------------ */

/* A locked tab keeps its place in the row. Dimmed and marked, never removed —
   a row that changes shape as you play is disorienting, and the promise of
   depth is part of what makes the first minutes worth spending. */
.command-tab.is-locked {
  opacity: 0.42;
  position: relative;
}

.command-tab.is-locked::after {
  content: "\00a0\1F512";
  position: absolute;
  top: 3px;
  right: 5px;
  font-size: 9px;
  opacity: 0.8;
}

.locked-panel {
  max-width: 560px;
  padding: 8px 2px 0;
}

.locked-panel h3 {
  font: 700 20px 'Playfair Display', serif;
  margin: 6px 0 12px;
}

.locked-why {
  font-size: 14px;
  line-height: 1.66;
  margin: 0 0 14px;
}

.locked-opens {
  font-size: 13.5px;
  line-height: 1.6;
  padding: 11px 13px;
  border-left: 2px solid var(--gold, #e8c98a);
  background: rgba(255, 255, 255, 0.03);
  margin: 0 0 16px;
}

/* A confirmation is rendered where the button was, so the player's eye never
   leaves the thing they were deciding about and nothing covers the numbers
   they were reading. */
.confirm-inline {
  border: 1px solid rgba(255, 155, 138, 0.4);
  border-left-width: 3px;
  border-radius: 3px;
  background: rgba(255, 155, 138, 0.07);
  padding: 11px 13px;
  margin: 4px 0;
  max-width: 420px;
}

.confirm-inline strong {
  display: block;
  font-size: 14px;
  margin-bottom: 5px;
}

.confirm-inline p {
  margin: 0 0 10px;
  font-size: 12.8px;
  line-height: 1.6;
  color: var(--ink-dim, #9fb6ad);
}

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

/* A hint appears once, next to the thing it is about, and goes away for good. */
.hint {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  margin: 0 0 14px;
  border-left: 2px solid var(--gold, #e8c98a);
  background: rgba(232, 201, 138, 0.07);
  border-radius: 3px;
  font-size: 13px;
  line-height: 1.6;
}

.hint p { margin: 0; flex: 1; }
.hint strong { display: block; margin-bottom: 3px; }

.hint-dismiss {
  border: 0;
  background: none;
  color: var(--ink-dim, #9fb6ad);
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  padding: 0 2px;
  flex: none;
}

.hint-dismiss:hover { color: inherit; }

/* A folded section. Shut, it still says what is inside and how much — a fold
   that hides its own contents is just a thing to click at random. */
.fold {
  border-top: 1px solid rgba(255, 255, 255, 0.07);
  margin-top: 4px;
}

.fold-head {
  display: flex;
  align-items: baseline;
  gap: 9px;
  width: 100%;
  padding: 12px 2px;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
  text-align: left;
  font: inherit;
}

.fold-head:hover .fold-title { color: var(--gold, #e8c98a); }

.fold-caret {
  color: var(--ink-dim, #9fb6ad);
  font-size: 11px;
  flex: none;
  width: 10px;
}

.fold-title {
  font: 600 13.5px Manrope, sans-serif;
  letter-spacing: 0.02em;
}

.fold-summary {
  margin-left: auto;
  font: 11.5px 'DM Mono', monospace;
  color: var(--ink-dim, #9fb6ad);
  text-align: right;
}

.fold-body { padding: 2px 0 14px; }

/* The one switch that opens every fold. Not a difficulty setting, and the
   label says so by naming what it does rather than who it is for. */
.expert-toggle {
  margin-left: auto;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: transparent;
  color: var(--ink-dim, #9fb6ad);
  border-radius: 999px;
  padding: 5px 12px;
  font: 500 11.5px 'DM Mono', monospace;
  cursor: pointer;
  white-space: nowrap;
}

.expert-toggle:hover { color: inherit; border-color: rgba(255, 255, 255, 0.3); }
.expert-toggle.is-on { color: var(--gold, #e8c98a); border-color: rgba(232, 201, 138, 0.4); }

/* Map views a new player has no use for yet. Seas and Trade mean nothing
   without a fleet; War means nothing without a war. Removed from the row
   rather than dimmed — unlike a command tab there is no depth being promised
   here, only a filter that would currently show an empty map. */
.map-view.is-hidden-view { display: none; }

/* ------------------------------------------------------------------ */
/* What now: the one thing worth doing next                            */
/* ------------------------------------------------------------------ */

/* This card is the answer to "what do I do now", which is the one question a
   new player has and the only one the opening screen could not answer. It was
   drawn exactly like the five blocks of status beneath it, so it read as the
   first of six things rather than as the one thing. It now leads: a warmer
   ground, a rule down its left edge in the same gold the eyebrow uses, and a
   heavier heading. Nothing was added to it and nothing below it was taken
   away — only the order the eye takes them in. */
.next-step-section {
  padding: 18px 23px 19px;
  border-bottom: 1px solid var(--line, #294038);
  border-left: 3px solid rgba(232, 201, 138, .5);
  background: rgba(232, 201, 138, .045);
}

.next-step-section.is-urgent {
  border-left-color: rgba(255, 155, 138, .62);
  background: rgba(255, 155, 138, .06);
}

.next-step .eyebrow {
  color: var(--ink-dim, #8ea79a);
  margin: 0 0 7px;
}

.next-step.is-urgent .eyebrow { color: var(--bad, #ff9b8a); }

.next-step strong {
  display: block;
  font: 700 17.2px 'Playfair Display', serif;
  line-height: 1.3;
  margin-bottom: 7px;
}

.next-why {
  margin: 0 0 12px;
  font-size: 12.9px;
  line-height: 1.62;
  color: var(--ink-dim, #8ea79a);
}

.next-go {
  width: 100%;
  border: 1px solid rgba(232, 201, 138, 0.44);
  background: rgba(232, 201, 138, 0.16);
  color: var(--gold, #e8c98a);
  border-radius: 3px;
  padding: 9px 12px;
  font: 600 12.8px Manrope, sans-serif;
  cursor: pointer;
  transition: background .18s;
}

.next-go:hover { background: rgba(232, 201, 138, 0.19); }

.next-step.is-urgent .next-go {
  border-color: rgba(255, 155, 138, 0.4);
  background: rgba(255, 155, 138, 0.1);
  color: var(--bad, #ff9b8a);
}

.next-step.is-urgent .next-go:hover { background: rgba(255, 155, 138, 0.2); }

/* The opening minutes: quieten the status a new player cannot act on. Not
   hidden — folded to their heading, so the player can see they exist and open
   them, and so nothing appears out of nowhere when the introduction ends. */
body.is-introducing .strength-section .metric,
body.is-introducing .grow-section #treatyList,
body.is-introducing .grow-section .text-button {
  display: none;
}

body.is-introducing .strength-section,
body.is-introducing .grow-section {
  padding-top: 14px;
  padding-bottom: 14px;
  opacity: 0.55;
}

/* `.grow-section` reserves 300px for a treaty list that the introduction has
   just hidden, and `.strength-section` holds four meters that are also gone —
   so quietening them left the opening screen with a 270px hole in the left
   column and "Needs attention" stranded at the bottom of it. A folded section
   has to be the height of its heading, or the fold reads as a rendering fault
   rather than as a decision. */
body.is-introducing .strength-section,
body.is-introducing .grow-section { min-height: 0; }

body.is-introducing .strength-section .section-heading,
body.is-introducing .grow-section .section-heading {
  margin-bottom: 0;
}

/* ------------------------------------------------------------------ */
/* Not animating what nobody is looking at                             */
/* ------------------------------------------------------------------ */

/* A workspace covers the map and dims what is left of it. The core design rule
   here is that animation must communicate something real - and behind a scrim
   it communicates nothing, while the sea currents, the drifting lanes and the
   bobbing ships go on repainting every frame. Paused rather than hidden, so
   they pick up exactly where they were when the panel closes. */
body.panel-open .realm-map *,
body.panel-open .sea-swell,
body.panel-open .ship-bob {
  animation-play-state: paused;
}

/* The same reasoning for a player who has asked their system for less motion:
   every decorative loop stops, and only the transitions that show a state
   change survive - shortened rather than removed, because an instant change
   with no transition reads as a glitch. */
@media (prefers-reduced-motion: reduce) {
  .sea-currents path,
  .sea-swell,
  .ship-bob,
  .trade-route,
  .war-objective,
  .province.is-unrest .province-fill,
  .province.is-war-target .province-fill,
  .map-stage[data-map-mode="war"] .own-rival .province-fill,
  /* `.weather-layer` was named here before the layer existed - the selector was
     written in anticipation and then the feature was not built for a while.
     It is the inner group that carries the animation. */
  .weather-layer,
  .weather-drift {
    animation: none !important;
  }

  * {
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------------------------------------------------------------- */
/* the central bank, the debt and the treasurer                      */
/* ---------------------------------------------------------------- */
/* Lives in the Economy panel rather than a tab of its own: the coin and the
   debt are the treasury, and the ledger is where a player already goes to
   ask why the treasury is moving. */

.counsel-card {
  margin: 12px 0 14px;
  padding: 12px 14px;
  border: 1px solid var(--line, #2c3b31);
  border-left: 3px solid var(--gold, #c9a227);
  border-radius: 8px;
  background: var(--panel-soft, rgba(255, 255, 255, .03));
}

.counsel-card.is-settled { border-left-color: var(--line, #2c3b31); opacity: .78; }

.counsel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 5px;
}

.counsel-rate {
  font-family: 'DM Mono', monospace;
  font-size: 13.5px;
  color: var(--gold, #c9a227);
}

.counsel-verdict { margin: 0 0 7px; font-size: 15px; }

.counsel-reasons {
  margin: 0 0 10px;
  padding-left: 17px;
  font-size: 13px;
  line-height: 1.55;
  opacity: .85;
}

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

.bank-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 8px;
  margin: 10px 0 12px;
}

.mint-desk {
  padding: 12px 14px;
  border: 1px solid var(--line, #2c3b31);
  border-radius: 8px;
  background: var(--panel-soft, rgba(255, 255, 255, .03));
}

.mint-desk label { display: block; margin-bottom: 6px; font-size: 14px; }
.mint-desk input[type="range"] { width: 100%; margin-bottom: 8px; }

.loan-row,
.loan-offer {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 3px 10px;
  padding: 9px 11px;
  margin-bottom: 7px;
  border: 1px solid var(--line, #2c3b31);
  border-radius: 7px;
  background: var(--panel-soft, rgba(255, 255, 255, .02));
}

.loan-row small,
.loan-offer small {
  grid-column: 1 / -1;
  font-size: 12.5px;
  line-height: 1.5;
  opacity: .72;
}

.loan-row.is-owed strong { color: var(--bad, #d08c7a); }
.loan-row.is-held strong { color: var(--good, #8fbf92); }
.loan-row .mini-action { grid-column: 1 / -1; justify-self: start; margin-top: 4px; }

.loan-who { font-weight: 600; }
.loan-offer.is-shut { opacity: .5; }
.loan-actions { grid-column: 1 / -1; display: flex; gap: 7px; margin-top: 5px; }

/* ---------------------------------------------------------------- */
/* a blockaded harbour                                               */
/* ---------------------------------------------------------------- */
/* Sits above the map for as long as a port is shut, rather than being a
   notification that scrolls away. It is the only banner in the game that
   does not time out, because the thing it is about does not either. */

.blockade-alarm {
  /* A stage child, so it must never widen the stage. */
  box-sizing: border-box;
  max-width: 100%;
  min-width: 0;
  display: flex;
  align-items: flex-start;
  gap: 13px;
  margin: 0 0 10px;
  padding: 12px 15px;
  border: 1px solid #7d3d34;
  border-left: 4px solid #c9564a;
  border-radius: 9px;
  background: linear-gradient(90deg, rgba(201, 86, 74, .16), rgba(201, 86, 74, .05));
  animation: blockade-pulse 2.4s ease-in-out infinite;
}

.blockade-alarm.hidden { display: none; }

@keyframes blockade-pulse {
  0%, 100% { border-left-color: #c9564a; }
  50% { border-left-color: #f0a093; }
}

/* Animation must communicate something real, and a pulse on a permanent alarm
   is decoration to anybody who has asked not to see motion. */
@media (prefers-reduced-motion: reduce) {
  .blockade-alarm { animation: none; }
}

.blockade-mark {
  flex: none;
  font-size: 22px;
  line-height: 1.2;
  color: #f0a093;
}

.blockade-copy { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.blockade-copy strong { display: block; font-size: 15.5px; margin-bottom: 3px; }
.blockade-copy p { margin: 0 0 4px; font-size: 13.5px; line-height: 1.5; opacity: .9; }

.blockade-odds b { font-weight: 600; }
.blockade-odds .is-strong { color: #8fbf92; }
.blockade-odds .is-even { color: #e0c06a; }
.blockade-odds .is-weak { color: #e08d7a; }

.blockade-actions {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: stretch;
}

.blockade-sailing {
  display: inline-block;
  padding: 6px 10px;
  border: 1px dashed #7d3d34;
  border-radius: 6px;
  font-size: 12.5px;
  opacity: .85;
}

/* At phone width the order goes under the text rather than beside it. */
@media (max-width: 900px) {
  .blockade-alarm { flex-wrap: wrap; }
  .blockade-actions { flex-direction: row; width: 100%; }
}

/* An ally's hulls sailing with your fleet. Distinguished by colour rather than
   by a different drawing: it is the same class of ship, under another flag. */
.voyage.is-allied .ship-hull { fill: #3f5f6a; }
.voyage.is-allied .ship-sail { fill: #dfe9ec; }
.voyage.is-allied .ship-flag { fill: #7fb6c9; }
.voyage.is-allied .fleet-label { fill: #9fd0de; }
.voyage.is-allied { opacity: .92; }

/* ---------------------------------------------------------------- */
/* pacts, the press and the market                                   */
/* ---------------------------------------------------------------- */

.pact-card {
  margin: 10px 0;
  padding: 10px 12px;
  border: 1px solid var(--line, #2c3b31);
  border-left: 3px solid #7f9bb5;
  border-radius: 7px;
  background: var(--panel-soft, rgba(255, 255, 255, .03));
}

.pact-card.is-bound { border-left-color: #8fbf92; }
.pact-card strong { display: block; font-size: 14px; margin-bottom: 3px; }
.pact-card p { margin: 0 0 7px; font-size: 13px; line-height: 1.5; opacity: .85; }

/* --- the press --- */
.press-standing {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 9px;
  margin-bottom: 12px;
}

.press-standing > div {
  padding: 11px 13px;
  border: 1px solid var(--line, #2c3b31);
  border-radius: 8px;
  background: var(--panel-soft, rgba(255, 255, 255, .03));
}

.press-standing span {
  display: block;
  font: 500 10.5px 'DM Mono', monospace;
  letter-spacing: 1.2px;
  opacity: .6;
}

.press-standing strong {
  display: block;
  margin: 3px 0 2px;
  font: 700 20px 'Playfair Display', serif;
  text-transform: capitalize;
}

.press-standing small { font-size: 12px; opacity: .75; }
.press-drift.is-up { color: #8fbf92; }
.press-drift.is-down { color: #e08d7a; }

.press-column { display: flex; flex-direction: column; gap: 9px; }

.press-cutting {
  padding: 11px 13px;
  border: 1px solid var(--line, #2c3b31);
  border-left: 3px solid var(--line, #2c3b31);
  border-radius: 7px;
  background: var(--panel-soft, rgba(255, 255, 255, .02));
}

.press-cutting.is-ally { border-left-color: #8fbf92; }
.press-cutting.is-friendly { border-left-color: #9fd0de; }
.press-cutting.is-neutral { border-left-color: #b9a98a; }
.press-cutting.is-hostile { border-left-color: #e0c06a; }
.press-cutting.is-war { border-left-color: #e08d7a; }

.press-head {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 4px;
}

.press-head strong { font: 700 14.5px 'Playfair Display', serif; }
.press-head span { font: 11px 'DM Mono', monospace; opacity: .6; }
.press-cutting p { margin: 0; font-size: 13.5px; line-height: 1.6; }

/* --- the market --- */
.market-need,
.market-shut {
  padding: 12px 14px;
  margin-bottom: 12px;
  border: 1px solid #7d6a34;
  border-left: 3px solid #e0c06a;
  border-radius: 8px;
  background: rgba(224, 192, 106, .09);
}

.market-shut { border-color: #7d3d34; border-left-color: #c9564a; background: rgba(201, 86, 74, .1); }
.market-need strong, .market-shut strong { display: block; margin-bottom: 3px; font-size: 15px; }
.market-need p, .market-shut p { margin: 0; font-size: 13.5px; line-height: 1.55; opacity: .9; }

.market-quay {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  padding: 8px 12px;
  margin-bottom: 10px;
  border: 1px solid var(--line, #2c3b31);
  border-radius: 7px;
  font: 12px 'DM Mono', monospace;
  opacity: .82;
}

.market-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 6px 12px;
  padding: 10px 12px;
  margin-bottom: 8px;
  border: 1px solid var(--line, #2c3b31);
  border-radius: 8px;
  background: var(--panel-soft, rgba(255, 255, 255, .02));
}

.market-row.is-scarce { border-left: 3px solid #e08d7a; }
.market-row.is-dear { border-left: 3px solid #e0c06a; }
.market-row.is-cheap { border-left: 3px solid #9fd0de; }
.market-row.is-glutted { border-left: 3px solid #8fbf92; }

.market-name strong { display: block; font-size: 14.5px; }
.market-name small { display: block; font-size: 12.5px; line-height: 1.45; opacity: .7; }
.market-price { text-align: right; font: 12.5px 'DM Mono', monospace; }
.market-price span { display: block; }
.market-price b { color: var(--gold, #c9a227); }
.market-price small { display: block; margin-top: 2px; opacity: .65; }
/* Tight groups. Without the flex-basis the buttons inherit the action-stack's
   `width: 100%` and spread across the row with holes between them. */
.market-sizes,
.market-actions {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: flex-start;
}

/* `.mini-action` carries `margin-left: auto` so it can sit at the right of a
   row on its own. In a flex group that pushes every button apart and leaves
   holes between them, which is what the market rows looked like. */
.market-sizes .mini-action,
.market-actions .mini-action { flex: 0 0 auto; width: auto; margin-left: 0; }
.market-sizes .mini-action { min-width: 46px; text-align: center; }
.market-sizes .mini-action.active { border-color: var(--gold, #c9a227); color: var(--gold, #c9a227); }
.market-note { grid-column: 1 / -1; margin: 2px 0 0; font-size: 12px; opacity: .65; }

/* What settling is worth, said beside what it costs. Green because it is the
   half of the decision that was missing. */
.focus-detail.is-worth,
.frontier-worth {
  color: #8fbf92;
  border-left: 2px solid #8fbf92;
  padding-left: 8px;
  margin: 6px 0;
  font-size: 12.8px;
  line-height: 1.55;
}

/* What a decision costs you somewhere else. Amber because it is not a refusal —
   the attack is still offered, and marching anyway is often right. */
.focus-detail.is-warning {
  color: #c99a4a;
  background: none;
  border: 0;
  border-left: 2px solid #c99a4a;
  padding-left: 8px;
  margin: 6px 0;
  font-size: 12.8px;
  line-height: 1.55;
}
.focus-detail.is-warning strong { color: #e0b463; }

/* ---------- a rising on the focus card ----------

   Amber while it is still an argument, red once it is armed. It sits above the
   occupation block because a province that is rising is more urgent than a
   province that is merely being integrated, and it carries the whole
   arithmetic: a player should never lose a province to a number they were not
   shown. */
.rebellion-block {
  margin: 10px 0; padding: 9px 11px; background: #f9f0df;
  border: 1px solid #e2cda0; border-left: 3px solid #c8922f; border-radius: 3px;
}
.rebellion-block.is-lost { background: #f8e7e0; border-color: #e0b5a5; border-left-color: #b8503b; }
.rebellion-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.rebellion-head strong { font-size: 14.2px; color: #8a6a22; }
.rebellion-block.is-lost .rebellion-head strong { color: #8a3f2c; }
.rebellion-pill {
  padding: 1px 7px; border-radius: 9px; background: #c8922f; color: #fff;
  font: 600 11px 'DM Mono', monospace; letter-spacing: .6px; white-space: nowrap;
}
.rebellion-pill.rose { background: #b8503b; }
.rebellion-block .meter { margin: 7px 0; }
.rebellion-block p { margin: 6px 0; font-size: 13.2px; color: #6f5a52; line-height: 1.5; }
.rebellion-demand {
  margin: 8px 0; padding: 7px 9px; background: rgba(255, 255, 255, .55);
  border: 1px solid #e2cda0; border-radius: 2px;
}
.rebellion-demand strong { font-size: 13.4px; color: #8a6a22; }
.rebellion-demand p { margin: 3px 0 0; }
.rebellion-demand em { display: block; margin-top: 3px; font-style: normal; opacity: .8; }
/* `.mini-action` carries `margin-left: auto`, which would push these apart. */
.rebellion-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.rebellion-actions .mini-action { flex: 0 0 auto; margin-left: 0; }
.mini-action.danger { border-color: #e0b5a5; background: #f8e7e0; color: #8a3f2c; }
.mini-action[disabled] { opacity: .45; cursor: not-allowed; }
.rebellion-note { margin: 7px 0 0; font-size: 12.4px; opacity: .75; line-height: 1.5; }

body.mode-night .rebellion-block { background: #2e2819; border-color: #55462a; }
body.mode-night .rebellion-block.is-lost { background: #2f2220; border-color: #5a3a32; }
body.mode-night .rebellion-head strong { color: #e0b463; }
body.mode-night .rebellion-block.is-lost .rebellion-head strong { color: #e09b84; }
body.mode-night .rebellion-block p { color: #c3b7a6; }
body.mode-night .rebellion-demand { background: rgba(0, 0, 0, .22); border-color: #55462a; }
body.mode-night .rebellion-demand strong { color: #e0b463; }
body.mode-night .mini-action.danger { background: #3a2724; border-color: #5a3a32; color: #e09b84; }

/* A province the crown has lost to its own people: not foreign, a hole in the
   realm, and drawn as one. */
.own-rebel .province-fill { fill: #9c5344; fill-opacity: .55; }
.province.is-rebel .province-fill {
  stroke: #b8503b; stroke-dasharray: 5 3; stroke-width: 1.4; fill-opacity: .62;
}

/* ---------- what the crown tells the realm ----------

   The two numbers a game like this usually hides are the two that are largest
   here: how big a lie an option is, in words, and the chance per minute of
   being caught telling it. Amber for a stretch, red for an invention, green
   for a claim that happens to be true. */
.proclaim-block {
  margin-top: 10px; padding: 11px; background: #f4ece4;
  border: 1px solid #e0d2c4; border-radius: 3px;
}
.proclaim-verdict { margin: 0 0 8px; font-size: 13.6px; line-height: 1.55; color: #5b4a42; }
.proclaim-cynicism {
  margin: 0 0 9px; padding: 7px 9px; font-size: 12.8px; line-height: 1.5;
  background: #f8e7e0; border-left: 3px solid #b8503b; border-radius: 2px; color: #8a3f2c;
}
.proclaim-active {
  margin-bottom: 10px; padding: 9px 11px; background: #fff8ea;
  border: 1px solid #e2cda0; border-left: 3px solid #c8922f; border-radius: 3px;
}
.proclaim-active-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.proclaim-active-head strong { font-size: 14px; color: #8a6a22; }
.proclaim-pill {
  padding: 1px 7px; border-radius: 9px; background: #c8922f; color: #fff;
  font: 600 11px 'DM Mono', monospace; white-space: nowrap;
}
.proclaim-active p { margin: 6px 0; font-size: 13px; line-height: 1.5; color: #6f5a52; }
.proclaim-active .mini-action { margin-left: 0; }

.proclaim-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr)); gap: 7px; }
.proclaim-option {
  display: grid; gap: 2px; padding: 9px; text-align: left; cursor: pointer;
  background: #fbf7f1; border: 1px solid #e0d2c4; border-radius: 3px;
  font: inherit; color: inherit;
}
.proclaim-option:hover { border-color: #c8922f; }
.proclaim-option.active { border-color: #c8922f; background: #fff8ea; }
.proclaim-icon { font-size: 15px; opacity: .75; }
.proclaim-option strong { font-size: 13.2px; line-height: 1.35; }
.proclaim-candour { font: 600 11.6px 'DM Mono', monospace; letter-spacing: .3px; }
.proclaim-candour.is-true { color: #4e7d5c; }
.proclaim-candour.is-lie { color: #b8503b; }
.proclaim-risk { font-size: 11.6px; opacity: .65; line-height: 1.4; }

body.mode-night .proclaim-block { background: #2c2620; border-color: #4a3f33; }
body.mode-night .proclaim-verdict { color: #d8cdbd; }
body.mode-night .proclaim-cynicism { background: #2f2220; color: #e09b84; }
body.mode-night .proclaim-active { background: #2e2819; border-color: #55462a; }
body.mode-night .proclaim-active-head strong { color: #e0b463; }
body.mode-night .proclaim-active p { color: #c3b7a6; }
body.mode-night .proclaim-option { background: #241f1a; border-color: #4a3f33; color: #ded4c6; }
body.mode-night .proclaim-option.active { background: #2e2819; border-color: #c8922f; }
body.mode-night .proclaim-candour.is-true { color: #8fbf92; }
body.mode-night .proclaim-candour.is-lie { color: #e09b84; }

/* ---------- a province event on the focus card ----------

   Blue-grey rather than amber or red: an event is a decision, not an alarm, and
   it should not read as louder than a rising happening in the same province.
   Every option carries its own price under it. */
.incident-block {
  margin: 10px 0; padding: 9px 11px; background: #eef1f4;
  border: 1px solid #cfd8de; border-left: 3px solid #6d8a9c; border-radius: 3px;
}
.incident-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.incident-head strong { font-size: 14px; color: #3f5a6b; line-height: 1.35; }
.incident-clock {
  padding: 1px 7px; border-radius: 9px; background: #6d8a9c; color: #fff;
  font: 600 11px 'DM Mono', monospace; white-space: nowrap;
}
.incident-block > p { margin: 7px 0; font-size: 13.2px; line-height: 1.5; color: #5b6a72; }
.incident-options { display: grid; gap: 6px; margin-top: 8px; }
.incident-option {
  display: grid; gap: 2px; padding: 8px 9px; text-align: left; cursor: pointer;
  background: #fbfcfd; border: 1px solid #cfd8de; border-radius: 2px;
  font: inherit; color: inherit;
}
.incident-option:hover { border-color: #6d8a9c; }
.incident-option strong { font-size: 13.2px; }
.incident-option small { font-size: 12.2px; opacity: .75; line-height: 1.45; }
.incident-option.is-barred { opacity: .5; cursor: not-allowed; }
.incident-note { margin: 8px 0 0; font-size: 12px; opacity: .6; line-height: 1.45; }

body.mode-night .incident-block { background: #232c31; border-color: #3c4a52; }
body.mode-night .incident-head strong { color: #9fc4d8; }
body.mode-night .incident-block > p { color: #b8c4cb; }
body.mode-night .incident-option { background: #1d2429; border-color: #3c4a52; color: #dbe3e8; }
body.mode-night .incident-option:hover { border-color: #6d8a9c; }

/* ---------- an enemy squadron on the water ----------

   The same hull and the same wake as your own fleet, because it is the same
   kind of thing. What differs is the colour, and that the lane it is following
   is not drawn until its course is plain: an unrevealed squadron is a ship on
   the sea with no line to read off it, which is the information the player is
   being asked to decide without. */
.voyage.is-enemy .ship-hull, .voyage.is-enemy path { fill: #b8503b; stroke: #8a3f2c; }
.voyage.is-enemy .fleet-label { fill: #e09b84; letter-spacing: 1px; }
.voyage-lane.is-hostile { stroke: #b8503b; stroke-opacity: .5; stroke-dasharray: 6 5; }
.voyage-wake.is-hostile { stroke: #b8503b; stroke-opacity: .35; }
.voyage-lane.is-hidden, .voyage-wake.is-hidden { stroke: none; opacity: 0; }

/* ---------- an enemy squadron in the Admiralty ---------- */
.squadron-list { display: grid; gap: 8px; margin-bottom: 12px; }
.squadron-card {
  padding: 10px 11px; background: #f8e7e0; border: 1px solid #e0b5a5;
  border-left: 3px solid #b8503b; border-radius: 3px;
}
.squadron-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.squadron-head strong { font-size: 14px; color: #8a3f2c; }
.squadron-pill {
  padding: 1px 7px; border-radius: 9px; background: #b8503b; color: #fff;
  font: 600 11px 'DM Mono', monospace; white-space: nowrap;
}
.squadron-card p { margin: 7px 0; font-size: 13.2px; line-height: 1.5; color: #6f5a52; }
.squadron-odds { font-size: 12.2px; opacity: .75; }
.squadron-card .mini-action { margin-left: 0; }
body.mode-night .squadron-card { background: #2f2220; border-color: #5a3a32; }
body.mode-night .squadron-head strong { color: #e09b84; }
body.mode-night .squadron-card p { color: #c3b7a6; }

/* ---------- weather and the turning year ----------

   The last thing the map did not do when nothing was happening. Ships bobbed,
   convoys ran the lanes and the swell moved, but the light on the land never
   changed, so a realm at peace was a still image of a realm at peace.

   Both effects are one CSS animation on one element and one attribute that
   changes four times a year. Nothing here is touched per tick, which is what
   keeps `a refresh that changes nothing touches nothing` at zero. */
.weather-layer { pointer-events: none; }
.weather-drift {
  /* The field is drawn twice and drifts by exactly its own width, so the loop
     restarts with the second copy exactly where the first one was. */
  animation: weather-drift 190s linear infinite;
  /* Deliberately no `will-change: transform`. It would promote this group to
     its own compositing layer, and the group covers the whole continent - a
     large raster held for a five-shadow animation the compositor handles well
     enough without the hint. The map performance pass was about not paying for
     things that were already free. */
}
@keyframes weather-drift {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* The season, as a wash over the land only, and a faint one. The province fills
   are the political colour code and the map stops being readable the moment a
   tint starts arguing with them - so this is at the threshold of noticeable and
   deliberately stays there. */
.season-wash {
  pointer-events: none;
  fill: transparent;
  transition: fill 2.4s ease;
}
.map-stage[data-season="spring"] .season-wash { fill: rgba(150, 200, 130, .085); }
.map-stage[data-season="summer"] .season-wash { fill: rgba(228, 196, 108, .075); }
.map-stage[data-season="harvest"] .season-wash { fill: rgba(206, 142, 66, .095); }
.map-stage[data-season="winter"] .season-wash { fill: rgba(176, 202, 222, .11); }

/* Night is already a colder, darker board, so the washes are pulled back under
   it rather than stacked on top of a tint that is doing the same job. */
body.mode-night .map-stage[data-season="spring"] .season-wash { fill: rgba(130, 190, 140, .06); }
body.mode-night .map-stage[data-season="summer"] .season-wash { fill: rgba(224, 186, 96, .05); }
body.mode-night .map-stage[data-season="harvest"] .season-wash { fill: rgba(198, 130, 58, .07); }
body.mode-night .map-stage[data-season="winter"] .season-wash { fill: rgba(150, 186, 214, .09); }

/* Weather stops with every other decorative loop: behind an open workspace it
   communicates nothing while still repainting, and while the map is being
   dragged it is competing with the gesture for the same frames. */
body.panel-open .weather-drift,
.realm-map.is-interacting .weather-drift { animation: none; }

/* ---------- the sea state, drawn ----------

   The weather on the map was decoration until the sea state existed. It is a
   readout now: the clouds run harder and the water darkens because the fleet is
   genuinely slower and blinder, and a player who has learned to read it is
   reading something true. Every rule here is a speed or an opacity on an
   element that was already animating, so none of it costs a new layer. */
.map-stage[data-sea="calm"] .weather-drift { animation-duration: 300s; opacity: .45; }
.map-stage[data-sea="fair"] .weather-drift { animation-duration: 190s; opacity: .75; }
.map-stage[data-sea="fresh"] .weather-drift { animation-duration: 120s; opacity: 1; }
.map-stage[data-sea="gale"] .weather-drift { animation-duration: 62s; opacity: 1.25; }
.map-stage[data-sea="storm"] .weather-drift { animation-duration: 34s; opacity: 1.6; }
.weather-drift { transition: opacity 3s ease; }

/* The water itself: flat and slow in a calm, running hard in a storm. */
.map-stage[data-sea="calm"] .sea-swell { animation-duration: 44s; opacity: .32; }
.map-stage[data-sea="fresh"] .sea-swell { animation-duration: 19s; opacity: .62; }
.map-stage[data-sea="gale"] .sea-swell { animation-duration: 11s; opacity: .8; }
.map-stage[data-sea="storm"] .sea-swell { animation-duration: 7s; opacity: .95; }
.map-stage[data-sea="gale"] .sea-currents path,
.map-stage[data-sea="storm"] .sea-currents path { opacity: .3; }

/* And the whole board loses its light under weather that would keep a fleet in
   harbour. Kept off the land tint so the political colours are untouched. */
.map-stage[data-sea="gale"] .sea-plate { filter: brightness(.9); }
.map-stage[data-sea="storm"] .sea-plate { filter: brightness(.78) saturate(.85); }
.sea-plate { transition: filter 3s ease; }

/* ---------- the weather on the water, in the Admiralty ---------- */
.sea-weather {
  margin-bottom: 12px; padding: 10px 11px; background: #eef3f6;
  border: 1px solid #cfdce4; border-left: 3px solid #6d8a9c; border-radius: 3px;
}
.sea-weather.is-rough { background: #f4eee3; border-color: #ded0b4; border-left-color: #c8922f; }
.sea-weather-head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.sea-weather-head strong { font-size: 14.4px; color: #3f5a6b; }
.sea-weather.is-rough .sea-weather-head strong { color: #8a6a22; }
.sea-weather-season { font: 600 11.6px 'DM Mono', monospace; opacity: .7; text-align: right; }
.sea-weather p { margin: 6px 0 0; font-size: 13.2px; line-height: 1.5; color: #5b6a72; }
.sea-weather-effect { font-weight: 600; }
.sea-weather-forecast { opacity: .75; font-size: 12.4px; }
body.mode-night .sea-weather { background: #222b31; border-color: #3b4a53; }
body.mode-night .sea-weather.is-rough { background: #2e2819; border-color: #55462a; }
body.mode-night .sea-weather-head strong { color: #9fc4d8; }
body.mode-night .sea-weather.is-rough .sea-weather-head strong { color: #e0b463; }
body.mode-night .sea-weather p { color: #b8c4cb; }

/* ---------- every way out of a blockade ----------

   Listed together, with the ones the realm cannot afford greyed rather than
   hidden: "you would need 440 gold and you have 259" is the most useful
   sentence on the card, and hiding it would leave the player exactly as stuck
   as they were before. */
.blockade-answers {
  margin-bottom: 12px; padding: 10px 11px; background: #f8e7e0;
  border: 1px solid #e0b5a5; border-left: 3px solid #b8503b; border-radius: 3px;
}
.blockade-answers-head { margin: 0 0 9px; font-size: 13.2px; line-height: 1.55; color: #6f5a52; }
.blockade-answer {
  padding: 8px 9px; margin-top: 6px; background: rgba(255, 255, 255, .55);
  border: 1px solid #e0b5a5; border-radius: 2px;
}
.blockade-answer.is-barred { opacity: .58; }
.blockade-answer-head { display: flex; align-items: baseline; gap: 8px; }
.blockade-answer-head strong { flex: 1 1 auto; font-size: 13.4px; color: #8a3f2c; }
.blockade-answer-head .mini-action { margin-left: 0; flex: 0 0 auto; }
.blockade-answer p { margin: 4px 0 0; font-size: 12.8px; line-height: 1.5; color: #6f5a52; }
body.mode-night .blockade-answers { background: #2f2220; border-color: #5a3a32; }
body.mode-night .blockade-answers-head { color: #c3b7a6; }
body.mode-night .blockade-answer { background: rgba(0, 0, 0, .22); border-color: #5a3a32; }
body.mode-night .blockade-answer-head strong { color: #e09b84; }
body.mode-night .blockade-answer p { color: #c3b7a6; }

/* ---------- the introduction: the primer, then the three steps ----------

   The one full-cover surface in the game. Everything else here is rendered in
   place, beside the thing it is about, on the principle that a modal moves the
   player's eye off the numbers they were reading. The primer is the deliberate
   exception: there are no numbers to read yet, and the whole point of it is to
   be the only thing on screen for twenty seconds.

   It holds the clock while it is up (`paintFirstPlay` in main.js), so nothing
   behind it is moving and nothing is being missed. */
.first-play:empty { display: none; }

.primer {
  position: fixed; inset: 0; z-index: 4000;
  display: grid; place-items: center;
  padding: 32px 24px;
  background: rgba(14, 24, 21, .88);
  backdrop-filter: blur(3px);
  overflow-y: auto;
  animation: primer-in .34s ease both;
}
@keyframes primer-in { from { opacity: 0; } to { opacity: 1; } }

.primer-sheet {
  width: min(860px, 100%);
  padding: 40px 44px 34px;
  background: #f7f5ec;
  border: 1px solid #cfd8c9;
  border-top: 3px solid #d9a04e;
  border-radius: 3px;
  box-shadow: 0 30px 70px rgba(0, 0, 0, .45);
  animation: primer-rise .42s cubic-bezier(.2, .8, .3, 1) both;
}
@keyframes primer-rise {
  from { opacity: 0; transform: translateY(18px) scale(.985); }
  to { opacity: 1; transform: none; }
}

.primer-sheet .eyebrow { color: #a3703f; letter-spacing: 1.6px; }
.primer-sheet h2 {
  margin: 10px 0 0;
  font: 800 35px 'Playfair Display', serif;
  line-height: 1.12; letter-spacing: -.4px; color: #21443a;
}
.primer-lede {
  margin: 14px 0 0; max-width: 62ch;
  font-size: 16px; line-height: 1.62; color: #566a5f;
}

/* Two columns of two. A single column of four reads as a manual; four across
   reads as a feature grid on a landing page. Two by two is the only shape that
   reads as "here are the four things". */
.primer-points {
  display: grid; grid-template-columns: 1fr 1fr; gap: 18px 30px;
  margin: 28px 0 0; padding: 24px 0 4px;
  border-top: 1px solid #dde3d7;
}
/* The four points arrive one after another rather than all at once.
   A block of four paragraphs appearing together is a wall to be skipped; the
   same four arriving in sequence are read, because each one is briefly the only
   new thing on screen. 70ms apart - fast enough that nobody waits for it,
   slow enough that the eye follows the order rather than choosing one. */
.primer-points section {
  position: relative; padding-left: 38px;
  animation: primer-point .42s cubic-bezier(.2, .8, .3, 1) both;
}
.primer-points section:nth-child(1) { animation-delay: .16s; }
.primer-points section:nth-child(2) { animation-delay: .23s; }
.primer-points section:nth-child(3) { animation-delay: .30s; }
.primer-points section:nth-child(4) { animation-delay: .37s; }
@keyframes primer-point {
  from { opacity: 0; transform: translateY(9px); }
  to { opacity: 1; transform: none; }
}

/* The numbered disc draws itself as the point lands. */
.primer-points section .primer-num { animation: primer-num .5s ease both; animation-delay: inherit; }
@keyframes primer-num {
  from { opacity: 0; transform: scale(.55); }
  60% { transform: scale(1.08); }
  to { opacity: 1; transform: none; }
}

.primer-sheet .eyebrow { animation: primer-point .4s ease both; }
#primerTitle { animation: primer-point .5s cubic-bezier(.2, .8, .3, 1) both; animation-delay: .04s; }
.primer-lede { animation: primer-point .5s cubic-bezier(.2, .8, .3, 1) both; animation-delay: .09s; }
.primer-actions { animation: primer-point .45s ease both; animation-delay: .46s; }
.primer-note { animation: primer-point .45s ease both; animation-delay: .52s; }

/* The gold rule under the lede draws across rather than appearing. */
.primer-points { position: relative; }
.primer-points::before {
  content: ''; position: absolute; top: -1px; left: 0; height: 1px;
  background: #d9a04e; width: 0;
  animation: primer-rule .6s ease both; animation-delay: .1s;
}
@keyframes primer-rule { to { width: 100%; } }
.primer-num {
  position: absolute; left: 0; top: 1px;
  width: 25px; height: 25px; border-radius: 50%;
  display: grid; place-items: center;
  background: #e2ecdf; color: #3b6b58;
  font: 700 12.4px 'DM Mono', monospace;
}
.primer-points h3 {
  margin: 2px 0 5px;
  font: 700 15.4px Manrope, sans-serif; color: #27473c;
}
.primer-points p {
  margin: 0; font-size: 13.8px; line-height: 1.6; color: #64756a;
}
.primer-points strong { color: #3b6b58; }

.primer-actions {
  display: flex; align-items: center; gap: 14px;
  margin-top: 26px; padding-top: 22px;
  border-top: 1px solid #dde3d7;
}
.primer-begin {
  border: 0; border-radius: 2px; cursor: pointer;
  padding: 13px 26px;
  background: #2d5b4d; color: #f2f4e9;
  font: 700 15px Manrope, sans-serif;
  transition: background .2s, transform .2s;
}
.primer-begin:hover { background: #20473c; transform: translateY(-1px); }
.primer-skip {
  border: 1px solid #cdd6c9; border-radius: 2px; cursor: pointer;
  padding: 12px 18px; background: transparent; color: #6b7d72;
  font: 600 13.4px Manrope, sans-serif;
}
.primer-skip:hover { border-color: #b6c3b4; color: #4a5d53; }
.primer-note {
  margin: 14px 0 0; font-size: 12.4px; line-height: 1.55; color: #8a968d;
}
.primer-note strong { color: #6b7d72; }

body.mode-night .primer-sheet { background: #1e2a26; border-color: #35473f; }
body.mode-night .primer-sheet h2 { color: #e6efe4; }
body.mode-night .primer-lede { color: #b3c3b7; }
body.mode-night .primer-points { border-top-color: #35473f; }
body.mode-night .primer-num { background: #2b3d36; color: #8fc0a5; }
body.mode-night .primer-points h3 { color: #dbe7d9; }
body.mode-night .primer-points p { color: #a7b7ab; }
body.mode-night .primer-points strong { color: #8fc0a5; }
body.mode-night .primer-actions { border-top-color: #35473f; }
body.mode-night .primer-skip { border-color: #3e5149; color: #a7b7ab; }
body.mode-night .primer-skip:hover { border-color: #577064; color: #d6e3d6; }
body.mode-night .primer-note { color: #7e8f83; }

/* ---------- the coach card ----------

   Over the map rather than in a sidebar, because two of the three steps are
   performed on the map and a card in the right rail would be asking the player
   to hold an instruction in their head while they look somewhere else. Bottom
   centre: it clears the map toolbar, the view switcher and the zoom column,
   and the legend sits left of it. */
.coach {
  /* Fixed to the viewport, not to the map, and centred on the map column
     rather than on the window — the grid is 308px of sidebar on the left and
     372px on the right, so the middle of the map sits 32px left of the middle
     of the screen. `bottom` clears the app footer (42px) and the map footer
     (54px). Both numbers are restated at the narrow breakpoint below, which is
     the price of not being able to live inside the box it points at. */
  position: fixed; z-index: 400;
  left: calc(50% - 32px); bottom: 114px; transform: translateX(-50%);
  width: min(520px, 44vw);
  padding: 15px 18px 14px;
  background: #f8f6ec;
  border: 1px solid #c9d4c6;
  border-left: 3px solid #d9a04e;
  border-radius: 3px;
  box-shadow: 0 16px 40px rgba(20, 34, 28, .5);
  animation: coach-in .3s ease both;
}

/* The map's own furniture stands down while a step is being explained. The
   legend, the scroll/drag hint and the hover tooltip are all reference material
   for somebody who already knows what they are looking at, and all three sit
   exactly where the card does. They come back the moment the steps end, which
   is the same bargain the panel gates make: nothing removed, only deferred. */
body.coaching .map-legend,
body.coaching .map-hint,
body.coaching .region-tooltip { opacity: 0; pointer-events: none; }
/* The tooltip is left out of the transition on purpose: it is rewritten and
   repositioned on every hover, and it is the one element down here that
   changes many times a second. It snaps; the other two fade. */
.map-legend, .map-hint { transition: opacity .25s; }
@keyframes coach-in {
  from { opacity: 0; transform: translate(-50%, 10px); }
  to { opacity: 1; transform: translateX(-50%); }
}

@media (max-width: 1250px) {
  /* the grid narrows to 280 / 330, so the map's centre moves to 25px left */
  .coach { left: calc(50% - 25px); }
}
/* A finished step reads as a small arrival: the rule turns green and the card
   settles, rather than the words simply being replaced. */
.coach.is-payoff { border-left-color: #5d9576; animation: coach-land .42s cubic-bezier(.2, .8, .3, 1) both; }
@keyframes coach-land {
  0% { opacity: 0; transform: translate(-50%, 7px) scale(.985); }
  100% { opacity: 1; transform: translateX(-50%); }
}
.coach.is-payoff .coach-said { animation: primer-point .4s ease both; animation-delay: .1s; }
.coach.is-payoff .coach-actions { animation: primer-point .4s ease both; animation-delay: .2s; }

/* Three dots, not a checklist. A visible list of three tasks is a list of the
   two the player is not doing. */
.coach-dots { display: flex; gap: 5px; margin-bottom: 9px; }
.coach-dots i {
  position: relative; overflow: hidden;
  width: 22px; height: 3px; border-radius: 3px;
  background: #d6dcd2;
}
/* The bar for the step in hand fills from the left as a slow sweep, so the
   card reads as something in progress rather than a static notice. It is the
   only thing on this card that moves while the player is thinking, which is
   the point: it says the game is waiting rather than stuck. */
.coach-dots i.is-now::after,
.coach-dots i.is-done::after {
  content: ''; position: absolute; inset: 0;
  border-radius: 3px; transform-origin: left center;
}
.coach-dots i.is-now::after {
  background: #d9a04e;
  animation: dot-fill 2.4s cubic-bezier(.4, 0, .2, 1) infinite;
}
.coach-dots i.is-done::after { background: #5d9576; animation: dot-done .38s ease both; }
@keyframes dot-fill {
  0% { transform: scaleX(0); opacity: .9; }
  60% { transform: scaleX(1); opacity: 1; }
  100% { transform: scaleX(1); opacity: .35; }
}
@keyframes dot-done { from { transform: scaleX(0); } to { transform: scaleX(1); } }

.coach .eyebrow { color: #a3703f; }
.coach.is-payoff .eyebrow { color: #4b7d63; }
.coach strong {
  display: block; margin: 5px 0 4px;
  font: 700 16.2px 'Playfair Display', serif; color: #234739;
}
.coach-ask, .coach-said {
  margin: 4px 0 0; font-size: 13.6px; line-height: 1.58; color: #5e6f66;
}
.coach-ask strong, .coach-said strong {
  display: inline; margin: 0; font: inherit; font-weight: 700; color: #2f6350;
}
.coach-actions { display: flex; align-items: center; gap: 9px; margin-top: 12px; }
.coach-go {
  border: 0; border-radius: 2px; cursor: pointer;
  padding: 8px 15px; background: #2d5b4d; color: #f0f2e7;
  font: 600 13px Manrope, sans-serif;
  transition: background .2s;
}
.coach-go:hover { background: #20473c; }
.coach.is-payoff .coach-go { background: #43765f; }
.coach-skip {
  margin-left: auto; border: 0; background: none; cursor: pointer;
  color: #8a968d; font: 500 12px 'DM Mono', monospace;
  text-decoration: underline; text-underline-offset: 3px;
}
.coach-skip:hover { color: #5e6f66; }

/* Fully opaque, both themes. A card carrying the only instruction on screen
   cannot be 95% of itself over a continent of terrain, rivers and labels -
   at 1600px that reads as a design choice and at 1250px it reads as a bug. */
body.mode-night .coach { background: #202c28; border-color: #3a4c44; }
body.mode-night .coach-dots i { background: #33443d; }
body.mode-night .coach strong { color: #e3ede1; }
body.mode-night .coach-ask, body.mode-night .coach-said { color: #aebeb2; }
body.mode-night .coach-ask strong, body.mode-night .coach-said strong { color: #8fc0a5; }
body.mode-night .coach-skip { color: #7e8f83; }
body.mode-night .coach-skip:hover { color: #b6c6ba; }

/* ---------- a player who has asked for less motion ----------

   Everything the introduction does to draw the eye is motion, and motion is the
   one thing some people cannot use: it ranges from distracting to genuinely
   sickening. `prefers-reduced-motion` is that request, made by the operating
   system, and the honest answer is not a slower animation but none.

   Nothing is hidden and nothing is skipped - the primer still arrives, the dots
   still show which step is which, the map still marks the province. They simply
   arrive rather than travel. The introduction teaches exactly as much either
   way, which is the test of whether the motion was ever carrying meaning. */
@media (prefers-reduced-motion: reduce) {
  .primer,
  .primer-sheet,
  .primer-sheet .eyebrow,
  #primerTitle,
  .primer-lede,
  .primer-points section,
  .primer-points section .primer-num,
  .primer-points::before,
  .primer-actions,
  .primer-note,
  .coach,
  .coach.is-payoff,
  .coach.is-payoff .coach-said,
  .coach.is-payoff .coach-actions,
  .coach-dots i.is-now::after,
  .coach-dots i.is-done::after,
  .province.is-coach-target .province-hatch {
    animation: none !important;
    transition: none !important;
  }
  /* The rule is drawn rather than drawn *across*, and the step in hand is a
     solid bar rather than a sweeping one - both still say what they said. */
  .primer-points::before { width: 100%; }
  .coach-dots i.is-now::after { background: #d9a04e; transform: none; opacity: 1; }
  .coach-dots i.is-done::after { background: #5d9576; transform: none; opacity: 1; }
  .province.is-coach-target .province-hatch { stroke-opacity: 1; stroke-width: 3.4; }
}
