/*
 * Every visual is a Tiny Swords sprite. Panels, buttons, ribbons and bars are
 * CSS border-image 9-slices repacked by tools/build_ui.py; the slice rules
 * themselves live in the generated /assets/ui/slices.css.
 */

:root {
  --ui-scale: 0.35px;
  --ink: #2b2330;
  --ink-soft: #5a4c53;
  --parchment: #efe4bd;
  --gap: 16px;
}

* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
}

body {
  margin: 0;
  font-family: "Trebuchet MS", "Segoe UI", Verdana, sans-serif;
  font-weight: 700;
  color: var(--ink);
  background-color: #4b8ba0;
  background-image: url("/art/Terrain/Water/Water.png");
  background-size: 128px 128px;
  background-repeat: repeat;
  image-rendering: pixelated;
  cursor: url("/assets/cursors/cursor.png") 1 1, default;
  overflow-x: hidden;
}

img,
canvas {
  image-rendering: pixelated;
}

/* Keep the pack's cursor everywhere, including over text fields and buttons. */
button,
input,
select,
label,
a {
  cursor: url("/assets/cursors/cursor.png") 1 1, default;
  font-family: inherit;
}

/* ---------- drifting sky ---------- */

.sky {
  position: fixed;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  z-index: 0;
}

.cloud {
  position: absolute;
  opacity: 0.5;
  transform: scale(2);
  transform-origin: left center;
  will-change: transform;
}

.cloud-1 {
  top: 8%;
  animation: drift 90s linear infinite;
}

.cloud-2 {
  top: 44%;
  animation: drift 140s linear infinite -40s;
}

.cloud-3 {
  top: 74%;
  animation: drift 110s linear infinite -80s;
}

@keyframes drift {
  from {
    left: -20%;
  }
  to {
    left: 110%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cloud {
    animation: none;
  }
}

/* ---------- layout ---------- */

#app {
  position: relative;
  z-index: 1;
  min-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--gap);
  padding: 32px 20px 48px;
}

.screen {
  width: 100%;
  max-width: 1080px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--gap);
}

.screen-narrow {
  max-width: 520px;
}

.row {
  display: flex;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
}

.row-center {
  justify-content: center;
}

.grow {
  flex: 1 1 auto;
}

/* ---------- titles ---------- */

.title-ribbon {
  --ui-scale: 0.62px;
  min-height: 90px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 8px;
  text-align: center;
  color: var(--parchment);
  font-size: 30px;
  letter-spacing: 3px;
  text-transform: uppercase;
  text-shadow: 0 3px 0 rgba(0, 0, 0, 0.45);
}

/* Byline keeps its own casing — the ribbon above it is uppercased. */
.title-ribbon small {
  display: block;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 1.5px;
  text-transform: none;
  opacity: 0.8;
  margin-top: 3px;
}

.ribbon-label {
  --ui-scale: 0.45px;
  min-height: 42px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 6px;
  color: var(--parchment);
  font-size: 14px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.4);
  white-space: nowrap;
}

/* ---------- panels ---------- */

.panel {
  --ui-scale: 0.35px;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 14px;
  background-clip: padding-box;
}

.panel-tight {
  --ui-scale: 0.36px;
}

.panel h2 {
  margin: 0;
  font-size: 17px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* SpecialPaper is a dark board; everything sitting on it flips to light ink. */
.panel.ts-paper-special {
  color: var(--parchment);
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.35);
}

.panel.ts-paper-special h2,
.panel.ts-paper-special .empty-note {
  color: #cfd8de;
}

/* ---------- buttons ---------- */

.btn {
  --ui-scale: 0.34px;
  background: none;
  border-style: solid;
  min-height: 46px;
  padding: 2px 4px;
  color: var(--parchment);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 2px;
  text-transform: uppercase;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.4);
  transition: transform 60ms ease-out, filter 120ms ease-out;
}

.btn:hover:not(:disabled) {
  filter: brightness(1.12);
}

.btn:active:not(:disabled) {
  transform: translateY(2px);
}

.btn:disabled {
  filter: grayscale(0.7) brightness(0.85);
  opacity: 0.75;
}

.btn:focus-visible {
  outline: 3px solid #fff3c4;
  outline-offset: 3px;
}

.btn-big {
  --ui-scale: 0.35px;
  min-height: 74px;
  min-width: 300px;
  font-size: 21px;
  letter-spacing: 3px;
}

.btn-wide {
  width: 100%;
}

/* The pressed sprite is a separate sheet, so swap the whole 9-slice on :active. */
.btn.ts-btn-blue:active:not(:disabled) {
  border-image-source: url("/assets/ui/btn-blue-pressed.png");
}

.btn.ts-btn-red:active:not(:disabled) {
  border-image-source: url("/assets/ui/btn-red-pressed.png");
}

/* ---------- form controls ---------- */

.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.field > span {
  font-size: 12px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.input {
  font-size: 16px;
  font-weight: 700;
  color: var(--ink);
  padding: 10px 12px;
  border: 3px solid #7d6a52;
  border-radius: 2px;
  background: #f6ecc9;
  box-shadow: inset 0 3px 0 rgba(0, 0, 0, 0.12);
  outline: none;
  min-width: 0;
}

.input:focus {
  border-color: #4f97a3;
}

.input::placeholder {
  color: #a9977a;
  font-weight: 600;
}

/* Segmented picker built from the pack's tiny square buttons. */
.seg {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.seg-opt {
  --ui-scale: 0.24px;
  background: none;
  border-style: solid;
  min-height: 38px;
  padding: 0 14px;
  color: var(--parchment);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.4);
  filter: grayscale(0.55) brightness(0.9);
}

.seg-opt[aria-pressed="true"] {
  filter: none;
}

.seg-opt:disabled {
  opacity: 0.5;
}

/* ---------- toast ---------- */

.toast {
  --ui-scale: 0.3px;
  position: fixed;
  left: 50%;
  bottom: 28px;
  transform: translate(-50%, 20px);
  z-index: 50;
  max-width: min(90vw, 420px);
  padding: 4px 10px;
  color: var(--parchment);
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.4);
  font-size: 14px;
  text-align: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 160ms ease-out, transform 160ms ease-out;
}

.toast.show {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* ---------- menu ---------- */

.menu-stack {
  display: flex;
  flex-direction: column;
  gap: 18px;
  align-items: center;
}

.menu-hero {
  display: flex;
  gap: 8px;
  align-items: flex-end;
  justify-content: center;
  min-height: 150px;
}

.menu-hero .sprite {
  filter: drop-shadow(0 6px 6px rgba(0, 0, 0, 0.3));
}

/* ---------- lobby browser ---------- */

.lobby-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-height: 340px;
  overflow-y: auto;
  padding-right: 4px;
}

/* SpecialPaper is the dark gold-trimmed board, so its contents go light. */
.lobby-row {
  --ui-scale: 0.22px;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 8px;
  background: none;
  border-style: solid;
  text-align: left;
  color: var(--parchment);
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.35);
}

.lobby-row:hover {
  filter: brightness(1.06);
}

.lobby-row .name {
  font-size: 16px;
  letter-spacing: 1px;
}

.lobby-row .meta {
  font-size: 12px;
  color: #b9c3ca;
  letter-spacing: 1px;
}

.lobby-row .count {
  font-size: 15px;
  letter-spacing: 1px;
  white-space: nowrap;
}

.lock {
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
}

.empty-note {
  padding: 18px 4px;
  text-align: center;
  color: var(--ink-soft);
  font-size: 14px;
  letter-spacing: 1px;
}

/* ---------- lobby ---------- */

.lobby-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: var(--gap);
  width: 100%;
  align-items: start;
}

@media (max-width: 900px) {
  .lobby-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

.slots {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.slot {
  --ui-scale: 0.2px;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 80px;
  padding: 4px 6px;
  border-style: solid;
  color: var(--parchment);
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.35);
}

.slot.empty {
  filter: grayscale(0.8) brightness(0.98);
  opacity: 0.7;
}

.slot .portrait {
  width: 66px;
  height: 66px;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  border-radius: 4px;
  border: 3px solid var(--faction-hex, rgba(0, 0, 0, 0.15));
  background: rgba(0, 0, 0, 0.08);
}

.slot .ribbon-label {
  --ui-scale: 0.34px;
  flex: 0 0 auto;
}

.slot .who {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.slot .who .name {
  font-size: 17px;
  letter-spacing: 1px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.slot .tags {
  display: flex;
  gap: 6px;
  align-items: center;
  flex-wrap: wrap;
}

.tag {
  font-size: 11px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.16);
  color: var(--parchment);
}

.tag.ready {
  background: #4f8f4a;
  color: #f2f7e6;
}

.tag.waiting {
  background: #b4783a;
  color: #fdf0dc;
}

.tag.host {
  background: #4f97a3;
  color: #eefbff;
}

.tag.bot {
  background: #6b5f8c;
  color: #efe8ff;
}

.slot .kick {
  margin-left: auto;
  width: 34px;
  height: 34px;
  flex: 0 0 auto;
  border: none;
  background: url("/art/UI%20Elements/UI%20Elements/Buttons/TinySquareRedButton.png") center / contain no-repeat;
  color: #ffe9e4;
  font-size: 14px;
  font-weight: 700;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.4);
}

.slot .kick:hover {
  filter: brightness(1.15);
}

/* ---------- faction picker ---------- */

/* Always one row of five, whatever the column width. */
.factions {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 6px;
}

.faction {
  position: relative;
  min-width: 0;
  padding: 6px 2px 8px;
  border: 3px solid transparent;
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.07);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  color: var(--ink-soft);
  font-size: 11px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  transition: transform 90ms ease-out;
}

.faction:hover:not(:disabled) {
  transform: translateY(-3px);
}

.faction[aria-pressed="true"] {
  border-color: var(--faction-hex);
  background: rgba(255, 255, 255, 0.35);
  box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.25), 0 0 18px var(--faction-hex);
}

.faction:disabled {
  filter: grayscale(0.85);
  opacity: 0.5;
}

.faction > span {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.faction .taken-by {
  font-size: 10px;
  letter-spacing: 0;
  text-transform: none;
  color: #6b5a45;
}

/* The preview ground is the chosen banner's own colour — no water underneath,
   so the card reads as that faction's field. */
.faction-preview {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 16px;
  min-height: 150px;
  border-radius: 4px;
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--faction-hex, #7a8b95) 78%, #ffffff) 0%,
    var(--faction-hex, #7a8b95) 55%,
    color-mix(in srgb, var(--faction-hex, #7a8b95) 72%, #000000) 100%
  );
  box-shadow: inset 0 0 0 3px
    color-mix(in srgb, var(--faction-hex, #7a8b95) 55%, #000000);
  padding: 6px;
  transition: background 200ms ease-out, box-shadow 200ms ease-out;
}

.faction-preview .sprite {
  filter: drop-shadow(0 4px 4px rgba(0, 0, 0, 0.35));
}

/* ---------- settings ---------- */

.settings {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.setting-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.setting-row > span {
  font-size: 12px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.homeland-note {
  font-size: 12px;
  line-height: 1.45;
  color: var(--ink-soft);
}

/* ---------- country picker modal ---------- */

.country-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.65);
  animation: country-fade 200ms ease-out;
}

@keyframes country-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}

.country-modal {
  position: relative;
  max-width: 720px;
  width: 90vw;
  max-height: 80vh;
  overflow-y: auto;
  background: var(--parchment, #f5ebd7);
  border: 3px solid rgba(0, 0, 0, 0.3);
  border-radius: 8px;
  padding: 24px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
}

.country-modal h2 {
  margin: 0 0 16px;
  font-size: 17px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--ink-soft, #6b5a45);
  text-align: center;
}

.country-modal-close {
  position: absolute;
  top: 8px;
  right: 12px;
  background: none;
  border: none;
  font-size: 24px;
  color: var(--ink-soft, #6b5a45);
  cursor: pointer;
  line-height: 1;
  padding: 4px;
}

.country-modal-close:hover {
  color: var(--ink, #3d3224);
}

.country-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 8px;
}

.country-card {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border: 2px solid transparent;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.05);
  cursor: pointer;
  transition: transform 80ms ease-out, border-color 100ms;
  text-align: left;
  font-family: inherit;
  font-size: 13px;
  color: var(--ink, #3d3224);
}

.country-card:hover:not(:disabled) {
  transform: translateY(-2px);
  border-color: rgba(0, 0, 0, 0.2);
  background: rgba(255, 255, 255, 0.4);
}

.country-card.selected {
  border-color: #4a90d9;
  background: rgba(74, 144, 217, 0.12);
  box-shadow: 0 0 10px rgba(74, 144, 217, 0.25);
}

.country-card:disabled {
  opacity: 0.4;
  cursor: default;
}

.country-flag {
  font-size: 22px;
  line-height: 1;
  flex-shrink: 0;
}

.country-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 500;
}

.country-taken {
  font-size: 10px;
  color: var(--ink-soft, #6b5a45);
  white-space: nowrap;
}

.readonly-value {
  font-size: 15px;
  letter-spacing: 1px;
  color: var(--ink);
}

/* ---------- chat ---------- */

.chat-log {
  display: flex;
  flex-direction: column;
  gap: 4px;
  height: 150px;
  overflow-y: auto;
  padding: 6px 8px;
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.08);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.4px;
}

.chat-log .system {
  color: var(--ink-soft);
  font-style: italic;
}

.chat-log .from {
  color: #3f6f7a;
}

.code-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 22px;
  letter-spacing: 6px;
  color: var(--ink);
}

.code-pill button {
  --ui-scale: 0.2px;
  border-style: solid;
  background: none;
  color: var(--parchment);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  padding: 4px 8px;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.4);
}

/* ---------- battlefield ---------- */

/* The match takes the whole viewport; #app's centred column does not apply. */
.battlefield {
  position: fixed;
  inset: 0;
  z-index: 5;
  overflow: hidden;
  background: #0a0f16;
}

.battlefield .field {
  display: block;
  width: 100%;
  height: 100%;
  outline: none;
  image-rendering: pixelated;
}

.battlefield > .hud-resources,
.battlefield > .hud-top-left,
.battlefield > .hud-command,
.battlefield > .hud-bottom-centre,
.battlefield > .hud-bottom-right,
.battlefield > .hud-leave {
  position: absolute;
}

.battlefield .ts-paper-special {
  color: var(--parchment);
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.4);
}

.battlefield .ts-btn-blue {
  color: var(--parchment);
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.4);
}

/* Top-left column: player roster over the status panel. */
.hud-top-left {
  top: 12px;
  left: 12px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  max-width: 340px;
}

.hud-roster-panel {
  --ui-scale: 0.22px;
  border-style: solid;
  padding: 4px 8px;
}

.hud-resources {
  --ui-scale: 0.18px;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  border-style: solid;
  padding: 2px 10px;
  display: flex;
  align-items: center;
  gap: 22px;
}

.res {
  position: relative;
  display: flex;
  align-items: center;
  gap: 7px;
}

/* Hovering an entry lifts it over its neighbours so their icons are not painted
   on top of its tooltip. */
.res:hover {
  z-index: 4;
}

.res-icon {
  width: 44px;
  height: 44px;
  filter: drop-shadow(0 2px 0 rgba(0, 0, 0, 0.35));
}

/* Divider before the population readout: it is a different kind of number. */
.res-population {
  padding-left: 20px;
  border-left: 2px solid rgba(255, 255, 255, 0.18);
}

.res-value {
  min-width: 3ch;
  font-size: 19px;
  font-weight: 700;
  letter-spacing: 1px;
  font-variant-numeric: tabular-nums;
}

/* One player per row. */
.hud-roster {
  display: flex;
  flex-direction: column;
  gap: 5px;
  align-items: flex-start;
  font-size: 13px;
  letter-spacing: 1px;
  white-space: nowrap;
}

.hud-player {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* Knocked out: still listed, still named, plainly no longer playing. */
.hud-player-out {
  opacity: 0.55;
  font-style: italic;
}

.hud-player-out .dot {
  filter: grayscale(1);
}

.hud-player .dot {
  width: 12px;
  height: 12px;
  border-radius: 2px;
  background: var(--faction-hex);
  box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.35);
}

/* Sits under the roster, so the command card keeps the bottom-left corner and
   its tooltips have empty space to pop into. */
.hud-status-panel {
  --ui-scale: 0.2px;
  border-style: solid;
  padding: 4px 8px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.hud-status {
  font-size: 14px;
  letter-spacing: 1px;
}

.hud-hint {
  font-size: 11px;
  letter-spacing: 0.5px;
  color: #b3bec7;
}

/* Bottom-right column: quick select sitting on the minimap, so the two read as
   one corner rather than two floating panels. */
.hud-bottom-right {
  right: 12px;
  bottom: 12px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
}

.hud-minimap {
  border: none;
  border-image: none;
  background: url('/assets/ui/minimap_panel.png') no-repeat center / 100% 100%;
  padding: 16px;
  line-height: 0;
}

/* ------------------------------------------------------------ quick select */

/* The list opens upward, out of the corner it lives in, and is anchored to the
   button's own box so it lines up with the minimap under it. */
.hud-roster-select {
  position: relative;
  display: flex;
  flex-direction: column;
  align-self: flex-end;
}

.roster-button {
  --ui-scale: 0.20px;
  border-style: solid;
  background: none;
  padding: 2px 6px;
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: 5px;
  color: var(--parchment);
  font: inherit;
  font-size: 11px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.45);
  cursor: pointer;
}

.roster-button:hover,
.roster-button:focus-visible {
  filter: brightness(1.08);
}

.roster-caption {
  flex: 1;
  text-align: left;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.roster-count {
  font-weight: 700;
  opacity: 0.85;
  flex-shrink: 0;
  white-space: nowrap;
}

.roster-chevron {
  font-size: 10px;
  opacity: 0.8;
}

.roster-button[aria-expanded="true"] .roster-chevron {
  transform: rotate(180deg);
}

/* Absolute so opening the list never shoves the minimap down the screen. A
   long roster scrolls inside its own box rather than growing past the top of
   the window. */
.roster-list {
  --ui-scale: 0.22px;
  position: absolute;
  bottom: calc(100% + 4px);
  right: 0;
  width: 232px;
  max-height: 46vh;
  overflow-y: auto;
  border-style: solid;
  padding: 4px;
  display: flex;
  flex-direction: column;
  gap: 1px;
  z-index: 6;
}

.roster-list {
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.3) transparent;
}

.roster-list::-webkit-scrollbar {
  width: 6px;
}

.roster-list::-webkit-scrollbar-track {
  background: transparent;
}

.roster-list::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.3);
  border-radius: 3px;
}

.roster-list::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.5);
}

.roster-list[hidden] {
  display: none;
}

.roster-row {
  border: none;
  background: none;
  flex-shrink: 0;
  padding: 3px 6px;
  color: var(--parchment);
  font: inherit;
  font-size: 12px;
  letter-spacing: 0.4px;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.5);
  cursor: pointer;
  border-radius: 3px;
}

.roster-row:hover,
.roster-row:focus-visible {
  background: rgba(246, 231, 184, 0.16);
}

/* Idlers are what the list is opened to find, so they are the one thing in it
   that is picked out rather than left to be read. */
.roster-row-idle {
  color: #f6e7b8;
  font-weight: 700;
}

.roster-empty {
  flex-shrink: 0;
  padding: 4px 6px;
  font-size: 12px;
  opacity: 0.7;
  color: var(--parchment);
}

.hud-minimap .minimap {
  display: block;
  width: 251px;
  height: 251px;
  image-rendering: pixelated;
}

.hud-leave {
  position: absolute;
  top: 12px;
  right: 12px;
  min-height: 40px;
  padding: 0 10px;
  font-size: 13px;
}

/* ------------------------------------------------------------- victory */

.victory-overlay {
  position: absolute;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.6);
  animation: victory-fade 600ms ease-out;
}

.victory-overlay[hidden] {
  display: none;
}

@keyframes victory-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}

.victory-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
}

.victory-content .title-ribbon {
  --ui-scale: 0.8px;
  min-height: 110px;
  font-size: 38px;
  letter-spacing: 4px;
  animation: victory-pop 400ms 200ms ease-out both;
}

@keyframes victory-pop {
  from { transform: scale(0.7); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}

.victory-content .btn {
  animation: victory-pop 400ms 500ms ease-out both;
}

/* ---------- command card ---------- */

.hud-command {
  left: 12px;
  bottom: 12px;
  border: none;
  border-image: none;
  background: url('/assets/ui/toolbar_hud.png') no-repeat center / 100% 100%;
  padding: 38px 36px 46px 36px;
}

.cmd-grid {
  display: grid;
  grid-template-columns: repeat(4, 56px);
  grid-template-rows: repeat(3, 56px);
  gap: 5px;
}

/* The building inspector, bottom centre between the command card and the
   minimap. Same wood-table slices as the command card, at the same scale, so
   the two read as one row of furniture. */
/* Bottom-centre column: the training queue rides directly on top of the panel
   that describes the building it belongs to, so the two move as one whatever
   height either of them takes. The column itself is click-through; only the
   panels in it take the pointer. */
.hud-bottom-centre {
  left: 50%;
  bottom: 12px;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  pointer-events: none;
}

.hud-bottom-centre > * {
  pointer-events: auto;
}

.hud-inspect {
  border: none;
  border-image: none;
  background: url('/assets/ui/info_panel.png') no-repeat center / 100% 100%;
  padding: 38px 36px 46px 36px;
  color: var(--parchment);
}

.hud-inspect[hidden] {
  display: none;
}

/* Fixed box on purpose. The panel is read at a glance while the game runs, and
   a card that resized itself around whatever is selected would move its own
   labels out from under the eye. Everything inside is laid out to a fixed
   grid; only the values ever change. */
.inspect-body {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 10px;
  width: 330px;
  height: 108px;
}

.inspect-icon {
  width: 62px;
  height: 62px;
  object-fit: contain;
  image-rendering: pixelated;
  filter: drop-shadow(0 2px 0 rgba(0, 0, 0, 0.35));
}

.inspect-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
  min-width: 0;
}

/* A long name ("Castle of Ljubljana") is cut rather than allowed to widen the
   card or wrap onto a second line and push the rows down. */
.inspect-title {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: #fff;
  text-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  height: 18px;
}

.inspect-subtitle {
  font-size: 11px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  opacity: 0.75;
  margin-bottom: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  height: 14px;
}

.inspect-stats {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

/* Every row is always in the DOM, empty ones included, so a castle that starts
   training does not shunt the rows above it. The label column is a fixed width
   so the values line up in one column whatever the labels say. */
.inspect-stat {
  display: grid;
  grid-template-columns: 78px 1fr;
  gap: 10px;
  align-items: baseline;
  height: 16px;
  font-size: 12px;
  letter-spacing: 1px;
  white-space: nowrap;
}

.inspect-label {
  text-transform: uppercase;
  opacity: 0.8;
  overflow: hidden;
  text-overflow: ellipsis;
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.5);
}

.inspect-value {
  font-weight: 700;
  text-align: right;
  overflow: hidden;
  text-overflow: ellipsis;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}

/* The icon keeps its footprint whatever is selected: a 1x1 house sprite must
   not sit at a different height from a 2x2 castle. */
.inspect-icon {
  flex: 0 0 auto;
}

/* -------------------------------------------------------------- multi-select */

.hud-multi-select {
  border: none;
  border-image: none;
  background: url('/assets/ui/info_panel.png') no-repeat center / 100% 100%;
  padding: 38px 36px 46px 36px;
  color: var(--parchment);
}

.hud-multi-select[hidden] {
  display: none;
}

.hud-multi-select .inspect-body {
  flex-direction: column;
  align-items: stretch;
  padding: 4px 6px;
}

.hud-multi-select .multi-slot {
  width: 44px;
  height: 44px;
}

.multi-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  overflow: hidden;
  align-items: flex-start;
  align-content: flex-start;
}

.multi-slot {
  position: relative;
  width: 48px;
  height: 48px;
  padding: 2px;
  border: 2px solid rgba(255, 255, 255, 0.15);
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.25);
  cursor: pointer;
  transition: border-color 0.15s;
}

.multi-slot:hover {
  border-color: rgba(255, 255, 255, 0.55);
}

.multi-avatar {
  width: 100%;
  height: 100%;
  object-fit: contain;
  image-rendering: pixelated;
}

.multi-count {
  position: absolute;
  bottom: 1px;
  right: 3px;
  font-size: 13px;
  font-weight: 700;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
  pointer-events: none;
}

.multi-tip {
  bottom: calc(100% + 6px);
}

.multi-slot:hover .multi-tip,
.multi-slot:focus-visible .multi-tip {
  opacity: 1;
}

/* ------------------------------------------------------------------- queue */

/* The training queue: one portrait per ordered character, oldest on the left.
   Every slot is a cancel button, so the whole strip carries the crosshair —
   there is nothing else a click in here can do. */
.hud-queue {
  padding: 4px 0;
  display: flex;
  align-items: flex-end;
  gap: 8px;
  border: none;
  background: none;
}

.hud-queue[hidden] {
  display: none;
}

.queue-slot {
  position: relative;
  padding: 0;
  border: none;
  background: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  cursor: url("/assets/cursors/Icon_09.png") 16 16, pointer;
}

.queue-slot[hidden] {
  display: none;
}

/* Round on purpose: a portrait, not another square command slot, so the queue
   never reads as a row of things to press for more of the same. */
.queue-portrait {
  position: relative;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  overflow: hidden;
  display: grid;
  place-items: center;
  background: rgba(24, 16, 10, 0.72);
  box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.45), 0 2px 0 rgba(0, 0, 0, 0.35);
  transition: box-shadow 90ms ease-out;
}

.queue-avatar {
  width: 34px;
  height: 34px;
  object-fit: contain;
  image-rendering: pixelated;
}

/* The cross only appears under the pointer, where it says what the click will
   do before it is made. */
.queue-cross {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 26px;
  font-weight: 700;
  line-height: 1;
  color: #ffe8e2;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.6);
  background: rgba(150, 32, 26, 0.62);
  opacity: 0;
  transition: opacity 90ms ease-out;
}

.queue-slot:hover .queue-cross,
.queue-slot:focus-visible .queue-cross {
  opacity: 1;
}

.queue-slot:hover .queue-portrait,
.queue-slot:focus-visible .queue-portrait {
  box-shadow: inset 0 0 0 2px rgba(226, 104, 94, 0.9), 0 2px 0 rgba(0, 0, 0, 0.35);
}

.queue-bar {
  width: 38px;
  height: 6px;
  border-radius: 3px;
  overflow: hidden;
  background: rgba(24, 16, 10, 0.8);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.5);
}

/* Only the head of a queue ever moves; the rest sit at zero until their turn.
   The transition is short so a bar that jumps back to 0 on the next order does
   not look like it is winding backwards. */
.queue-fill {
  display: block;
  width: 0;
  height: 100%;
  background: linear-gradient(180deg, #f5d772, #d29a33);
  transition: width 120ms linear;
}

.cmd-slot {
  position: relative;
  width: 56px;
  height: 56px;
  padding: 0;
  border: none;
  background-color: transparent;
  background-repeat: no-repeat;
  background-position: center;
  background-size: 100% 100%;
  image-rendering: pixelated;
  display: grid;
  place-items: center;
  transition: transform 70ms ease-out, filter 120ms ease-out;
}

/* Empty sockets are inert; so are slots the player cannot afford yet. Both are
   dimmed, but only the empty ones are really `disabled` in the DOM. */
.cmd-slot:disabled,
.cmd-slot[aria-disabled="true"] {
  filter: brightness(0.78) saturate(0.7);
}

/* Lift the hovered slot so its tooltip is not painted over by later siblings.
   Locked slots lift too — they still have a cost to show. */
.cmd-slot:not(:disabled):hover,
.cmd-slot:focus-visible {
  z-index: 4;
}

/* Only a slot that can actually be pressed lights up and depresses. */
.cmd-slot:not(:disabled):not([aria-disabled="true"]):hover {
  filter: brightness(1.18);
}

.cmd-slot:not(:disabled):not([aria-disabled="true"]):active {
  transform: translateY(2px);
}

.cmd-slot[aria-pressed="true"] {
  filter: brightness(1.3);
  box-shadow: inset 0 0 0 3px #f6e7b8;
  border-radius: 6px;
}

.cmd-slot:focus-visible {
  outline: 3px solid #fff3c4;
  outline-offset: 2px;
}

.cmd-icon {
  width: 42px;
  height: 42px;
  pointer-events: none;
  filter: drop-shadow(0 2px 0 rgba(0, 0, 0, 0.35));
}

/* Building sprites are much wider than the action icons, so let them fill the
   socket and keep their aspect ratio instead of being squashed to a square. */
.cmd-slot.cmd-building .cmd-icon {
  width: 50px;
  height: 50px;
  object-fit: contain;
}

/* Costs make the label long; let the tooltip wrap instead of running off. */
.cmd-slot.cmd-building .cmd-tip {
  white-space: normal;
  width: max-content;
  /* Never wider than the window, however narrow it gets. */
  max-width: min(190px, calc(100vw - 16px));
  text-align: center;
  text-transform: none;
  letter-spacing: 0.5px;
}

/* Tooltip, drawn from the pack's dark paper rather than the browser's. Shared
   by the command card and the resource bar; only which way it opens differs,
   since one sits at the bottom of the screen and the other at the top. */
.cmd-tip,
.res-tip,
.multi-tip {
  position: absolute;
  left: 50%;
  /* Centred over the slot, then nudged by whatever it takes to stay inside the
     window — the shifts are measured in JS and set as custom properties. */
  transform: translate(calc(-50% + var(--tip-shift-x, 0px)), var(--tip-shift-y, 0px));
  z-index: 3;
  padding: 2px 6px;
  border-style: solid;
  border-image-source: url("/assets/ui/paper-special.png");
  border-image-slice: 44 55 43 55 fill;
  border-image-width: calc(44 * var(--ui-scale)) calc(55 * var(--ui-scale))
    calc(43 * var(--ui-scale)) calc(55 * var(--ui-scale));
  border-image-repeat: repeat;
  border-width: calc(44 * var(--ui-scale)) calc(55 * var(--ui-scale))
    calc(43 * var(--ui-scale)) calc(55 * var(--ui-scale));
  color: var(--parchment);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.4);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 120ms ease-out;
}

.cmd-tip {
  bottom: calc(100% + 6px);
}

.cmd-slot:not(:disabled):hover .cmd-tip,
.cmd-slot:focus-visible .cmd-tip {
  opacity: 1;
}

/* The resource bar hangs under the top edge, so its tips open downward. They
   carry a heading, a rate and the arithmetic behind it, so unlike a command
   tooltip they are several short lines rather than one shouted one. */
.res-tip {
  top: calc(100% + 6px);
  width: max-content;
  max-width: min(260px, calc(100vw - 16px));
  white-space: normal;
  text-align: center;
  text-transform: none;
  letter-spacing: 0.5px;
  font-size: 11px;
  font-weight: 400;
  line-height: 1.45;
}

.res:hover .res-tip,
.res:focus-visible .res-tip {
  opacity: 1;
}

/* Each line is its own block so the tip reads as heading / rate / working. */
.res-tip > span {
  display: block;
}

.res-tip-name {
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
}

/* The arithmetic behind the rate, quieter than the rate itself. */
.res-tip-formula {
  opacity: 0.66;
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------- cheat console */
.cheat-console[hidden] {
  display: none;
}
.cheat-console {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: rgba(0, 0, 0, 0.85);
  font-family: monospace;
  font-size: 14px;
  color: #0f0;
  padding: 8px;
  z-index: 200;
  max-height: 200px;
  display: flex;
  flex-direction: column;
}
.cheat-log {
  overflow-y: auto;
  flex: 1;
  max-height: 140px;
}
.cheat-line {
  padding: 2px 0;
  white-space: pre-wrap;
}
.cheat-input {
  background: transparent;
  border: none;
  border-top: 1px solid #0f04;
  color: #0f0;
  font-family: monospace;
  font-size: 14px;
  padding: 4px 0;
  outline: none;
  width: 100%;
}

/* ---------- convert tooltip ---------- */
.convert-tooltip {
  position: fixed;
  pointer-events: none;
  z-index: 100;
  background: rgba(0, 0, 0, 0.82);
  color: #f3ead1;
  font: 600 13px "Trebuchet MS", sans-serif;
  padding: 5px 10px;
  border-radius: 4px;
  white-space: nowrap;
  border: 1px solid rgba(243, 234, 209, 0.25);
}

/* ---------- action menu ---------- */
.action-menu {
  position: fixed;
  z-index: 100;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 3px;
  background: rgba(0, 0, 0, 0.85);
  border: 1px solid rgba(243, 234, 209, 0.25);
  border-radius: 4px;
  min-width: 120px;
}
.action-menu[hidden] { display: none; }
.action-menu-item {
  border: none;
  background: none;
  color: #f3ead1;
  font: 600 12px "Trebuchet MS", sans-serif;
  padding: 5px 10px;
  text-align: left;
  cursor: pointer;
  border-radius: 3px;
  white-space: nowrap;
}
.action-menu-item:hover {
  background: rgba(246, 231, 184, 0.16);
}
