/* Iron Reign — the whole look, in one sheet.
 *
 * The art is hand-painted: weathered timber, mossy stone, muted browns and
 * greens on a pale cream ground, everything lit from the upper left. The UI is
 * built to sit inside that painting rather than on top of it — parchment
 * panels, an ink-dark text colour, brass and iron accents, a serif for the
 * headings and a plain sans for the numbers. It should read as a war-room
 * ledger somebody has been writing in for a month. No neon, and no emoji as
 * icons: the five little glyphs are inline SVG at the bottom of this file.
 *
 * Shadows fall to the lower right, always, because that is where the art puts
 * them. A highlight on the top edge and a shadow on the bottom is the whole
 * trick that makes the panels read as pressed paper instead of CSS boxes.
 */

:root {
  --paper:      #ece2cd;   /* the ground the whole page sits on */
  --paper-dark: #ddd0b4;
  --panel:      #f5eeda;   /* a fresh sheet laid on the ground */
  --panel-2:    #ebe1c8;
  --ink:        #2c261d;
  --ink-soft:   #6a5c48;
  --ink-faint:  #8d7f68;
  --rule:       #c6b795;   /* a ruled line, aged */
  --rule-dark:  #9d8c68;
  --brass:      #9c7a37;
  --brass-lit:  #d5b25f;
  --iron:       #6a707a;
  --moss:       #5d6b45;
  --moss-lit:   #7d8c5d;
  --blood:      #8d3a2a;
  --blood-ink:  #7a2f22;   /* alarm text: the same red, dark enough to read */
  --blood-lit:  #b0563f;
  --gold:       #b8912f;

  --shadow:     0 1px 0 rgba(255,252,242,.7) inset, 0 2px 5px rgba(58,45,28,.16);
  --shadow-lg:  0 1px 0 rgba(255,252,242,.7) inset, 0 6px 18px rgba(58,45,28,.22);

  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, "Times New Roman", serif;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  --radius: 4px;   /* a ledger has corners, not pills */
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  min-height: 100%;
}

body {
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.45;
  color: var(--ink);
  /* Cream ground plus a faint woven texture. Two cheap gradients, no image
     request, and it stops the large empty areas from looking like plastic. */
  background-color: var(--paper);
  background-image:
    radial-gradient(120% 80% at 20% 0%, rgba(255,253,246,.75), rgba(255,253,246,0) 60%),
    repeating-linear-gradient(90deg, rgba(120,96,58,.045) 0 1px, rgba(0,0,0,0) 1px 3px),
    repeating-linear-gradient(0deg,  rgba(120,96,58,.045) 0 1px, rgba(0,0,0,0) 1px 3px);
  background-attachment: fixed;
  -webkit-text-size-adjust: 100%;
}

h1, h2, h3 {
  font-family: var(--serif);
  font-weight: 600;
  letter-spacing: .01em;
  margin: 0;
}

a { color: var(--brass); text-decoration: none; }
a:hover { color: var(--ink); text-decoration: underline; }

.ir-muted { color: var(--ink-faint); }
.ir-sep { color: var(--rule-dark); padding: 0 2px; }

/* Numbers are read in columns and compared, so they get tabular figures
   everywhere they appear. A resource counter that changes width every second
   makes the whole bar twitch. */
.ir-res-n, .ir-cost-c, .ir-cd, .ir-u-have, .ir-b-lvl, .ir-player-meta, .ir-num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* ── Masthead ──────────────────────────────────────────────────────────── */

.ir-top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 16px;
  padding: 10px 16px;
  background: linear-gradient(180deg, #4a3f30, #382f24);
  border-bottom: 3px solid var(--brass);
  color: #efe6d2;
  box-shadow: 0 4px 14px rgba(40,30,16,.28);
}

.ir-top-left, .ir-top-right {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}
.ir-top-right { margin-left: auto; }

.ir-brand { display: flex; flex-direction: column; line-height: 1.15; color: inherit; }
.ir-brand:hover { text-decoration: none; }
.ir-brand-name {
  font-family: var(--serif);
  font-size: 21px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--brass-lit);
  text-shadow: 0 1px 0 rgba(0,0,0,.5);
}
.ir-brand-world { font-size: 12px; color: #bfae8d; letter-spacing: .04em; }

.ir-chip {
  font-size: 12px;
  padding: 3px 9px;
  border: 1px solid rgba(212,186,132,.4);
  border-radius: var(--radius);
  background: rgba(0,0,0,.22);
  color: #dccfae;
  white-space: nowrap;
}
.ir-chip-quiet { opacity: .8; text-transform: capitalize; }

.ir-player { text-align: right; line-height: 1.2; }
.ir-player-name { font-family: var(--serif); font-size: 16px; color: #f3e9d2; }
.ir-player-meta { display: block; font-size: 11.5px; color: #b6a684; }

.ir-back {
  font-size: 12.5px;
  color: #cdbc98;
  border: 1px solid rgba(212,186,132,.35);
  border-radius: var(--radius);
  padding: 5px 9px;
  white-space: nowrap;
}
.ir-back:hover { background: rgba(0,0,0,.25); color: #f3e9d2; text-decoration: none; }

/* ── Ledger bar ────────────────────────────────────────────────────────── */

.ir-ledger {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: stretch;
  gap: 14px;
  flex-wrap: wrap;
  padding: 8px 16px;
  background: linear-gradient(180deg, var(--panel), var(--panel-2));
  border-bottom: 1px solid var(--rule-dark);
  box-shadow: 0 3px 10px rgba(58,45,28,.14);
}
.ir-ledger-idle { opacity: .55; }

.ir-ledger-village { display: flex; align-items: center; gap: 8px; min-width: 0; }

.ir-select {
  font-family: var(--serif);
  font-size: 15px;
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--rule-dark);
  border-radius: var(--radius);
  padding: 6px 8px;
  max-width: 46vw;
  /* A native select is the best village switcher on a phone that exists. */
}
.ir-select:disabled { opacity: 1; color: var(--ink); }

.ir-coords { font-size: 12px; color: var(--ink-faint); white-space: nowrap; }

.ir-res {
  display: flex;
  gap: 8px;
  flex: 1 1 380px;
  min-width: 0;
}

.ir-res-cell {
  position: relative;
  flex: 1 1 0;
  min-width: 84px;
  padding: 4px 8px 7px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: rgba(255,252,242,.6);
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas: "ic n" "lbl rate" "bar bar";
  align-items: center;
  column-gap: 6px;
}
.ir-res-cell > * { min-width: 0; }
.ir-res-cell .ir-ic { grid-area: ic; }
.ir-res-n {
  grid-area: n;
  font-size: 15px;
  font-weight: 600;
  text-align: right;
  /* A grid item defaults to min-width:auto, so a five-digit count refuses to
     shrink and spills over the cell beside it. On a phone that read as three
     numbers printed on top of each other. */
  overflow: hidden;
  white-space: nowrap;
}
.ir-res-lbl {
  grid-area: lbl;
  font-size: 10px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.ir-res-rate { grid-area: rate; font-size: 10.5px; color: var(--moss); text-align: right; }
.ir-res-bar {
  grid-area: bar;
  height: 3px;
  margin-top: 4px;
  background: rgba(120,96,58,.18);
  border-radius: 2px;
  overflow: hidden;
}
.ir-res-bar > span {
  display: block;
  height: 100%;
  width: 0;
  background: var(--moss-lit);
  transition: width .25s linear;
}
/* A full warehouse is production being thrown away, so it shouts. */
.ir-res-cell.full { border-color: var(--blood); background: rgba(176,86,63,.12); }
.ir-res-cell.full .ir-res-bar > span { background: var(--blood-lit); }
.ir-res-meta { flex: 0 1 auto; min-width: 96px; }

/* ── Nav ───────────────────────────────────────────────────────────────── */

.ir-nav {
  display: flex;
  gap: 2px;
  padding: 0 12px;
  background: linear-gradient(180deg, var(--paper-dark), var(--paper));
  border-bottom: 1px solid var(--rule-dark);
}
.ir-nav a {
  position: relative;
  font-family: var(--serif);
  font-size: 15px;
  color: var(--ink-soft);
  padding: 10px 14px;
  border-bottom: 3px solid transparent;
}
.ir-nav a:hover { color: var(--ink); text-decoration: none; background: rgba(255,252,242,.5); }
.ir-nav a.on {
  color: var(--ink);
  border-bottom-color: var(--brass);
  background: rgba(255,252,242,.75);
}

.ir-badge {
  display: inline-block;
  min-width: 17px;
  margin-left: 5px;
  padding: 0 4px;
  font-family: var(--sans);
  font-size: 10.5px;
  line-height: 16px;
  text-align: center;
  color: #fff;
  background: var(--blood);
  border-radius: 9px;
  vertical-align: 1px;
}

/* `display` on the rule above outranks the UA sheet's [hidden]{display:none},
   so api.js setting el.hidden left a bright red "0" pinned to the Tribe tab
   whenever there was nothing to read. Every toggled element on this page needs
   the same guard, not just this one. */
[hidden] { display: none !important; }

/* ── View & panels ─────────────────────────────────────────────────────── */

.ir-view {
  max-width: 1240px;
  margin: 0 auto;
  padding: 16px 14px 40px;
}

.ir-panel {
  background:
    linear-gradient(180deg, rgba(255,253,246,.85), rgba(255,253,246,.35)),
    var(--panel);
  border: 1px solid var(--rule-dark);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px 16px;
  margin: 0 0 16px;
}
.ir-panel > h2 {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-size: 19px;
  margin: -2px 0 10px;
  padding-bottom: 7px;
  border-bottom: 1px solid var(--rule);
}
.ir-h-note {
  margin-left: auto;
  font-family: var(--sans);
  font-size: 11.5px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.ir-loading, .ir-empty { text-align: center; color: var(--ink-soft); padding: 34px 18px; }
.ir-empty h2 { border: 0; justify-content: center; margin-bottom: 6px; }

/* Two columns on a desktop: the war room down the left, the village itself
 * across the rest of the width, because the village is what a player is doing
 * on all but a handful of the minutes they are here.
 *
 * The DOM order is village-then-war — the order a phone reads and a keyboard
 * walks — and `order` is what puts the war column on the left above 1000 px.
 * One markup path, two layouts, nothing to keep in step.
 *
 * `align-items: start` is load-bearing. Without it the war column stretches to
 * the height of the building grid, and "the alerts at the bottom of the column"
 * lands 2,000 px below the fold instead of directly under the insights. */
.ir-cols { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0 18px; }
.ir-col { min-width: 0; }

@media (min-width: 1000px) {
  .ir-cols {
    grid-template-columns: minmax(268px, 336px) minmax(0, 1fr);
    align-items: start;
  }
  .ir-col-war { order: -1; }
}

/* ── Village header ────────────────────────────────────────────────────── */

.ir-vh {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 14px;
  margin-bottom: 14px;
  padding-bottom: 10px;
  border-bottom: 2px solid var(--rule-dark);
}
.ir-vh-name { font-size: 27px; line-height: 1.1; }
.ir-vh-meta { display: flex; flex-wrap: wrap; gap: 6px; margin-left: auto; }

.ir-tag {
  font-size: 11.5px;
  letter-spacing: .04em;
  padding: 3px 8px;
  color: var(--ink-soft);
  background: rgba(255,252,242,.7);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  white-space: nowrap;
}
.ir-tag-warn { color: #7a2f22; border-color: var(--blood); background: rgba(176,86,63,.1); }

.ir-rename { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.ir-rename input {
  font-family: var(--serif);
  font-size: 22px;
  color: var(--ink);
  background: #fffdf5;
  border: 1px solid var(--rule-dark);
  border-radius: var(--radius);
  padding: 4px 8px;
  min-width: 0;
  max-width: 100%;
}

/* ── The watch: one calm line, and the war column ──────────────────────── */
/*
 * The incoming list used to be a red banner across the top of the village, one
 * row per attack. Under a bot raid that is forty rows above everything, and the
 * player opens their village to a wall of alarm with the game itself pushed off
 * the bottom of the screen — the first building card started 1,900 px down.
 *
 * What is left up here is a single status row. The list lives at the bottom of
 * the war column and scrolls inside its own panel.
 */

.ir-watch {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 14px;
  padding: 8px 12px;
  font-size: 14px;
  color: var(--ink);
  background: linear-gradient(180deg, rgba(255,253,246,.9), rgba(240,232,212,.7));
  border: 1px solid var(--rule-dark);
  border-left: 4px solid var(--brass);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.ir-watch .ir-ic { width: 16px; height: 16px; }
.ir-watch-text { flex: 1 1 auto; min-width: 0; }
.ir-watch-text b { font-variant-numeric: tabular-nums; }
.ir-watch-more { flex: 0 0 auto; white-space: nowrap; }
.ir-watch-help { color: var(--moss); }
.ir-watch.is-calm { border-left-color: var(--moss); color: var(--ink-soft); }

/* Two minutes out, and the line is allowed to shout. Colour and weight only —
   an urgent case that grows the row back into a banner has undone the whole
   point of the row. */
.ir-watch.is-urgent {
  color: var(--blood-ink);
  border-color: var(--blood);
  border-left-color: var(--blood);
  background: linear-gradient(180deg, rgba(176,86,63,.2), rgba(176,86,63,.09));
}
.ir-watch.is-urgent .ir-cd,
.ir-watch.is-urgent .ir-watch-more { color: var(--blood-ink); }

/* ── Attack insights ───────────────────────────────────────────────────── */

.ir-ins-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  margin-bottom: 11px;
}
.ir-ins-cell {
  padding: 6px 6px 7px;
  text-align: center;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: rgba(255,252,242,.65);
}
.ir-ins-n {
  display: block;
  font-family: var(--serif);
  font-size: 17px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--blood-ink);
}
.ir-ins-l {
  display: block;
  font-size: 9.5px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.ir-ins-who { list-style: none; margin: 0; padding: 0; }
.ir-ins-who li {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 5px 0;
  font-size: 13px;
  border-bottom: 1px dotted var(--rule);
}
.ir-ins-who li:last-child { border-bottom: 0; }
.ir-ins-c {
  flex: 0 0 auto;
  min-width: 30px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--blood-ink);
}
/* A long neighbour name must not push the countdown off the panel: this is the
   cell that gives, and an ellipsis says so. */
.ir-ins-w {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ir-ins-who .ir-cd { flex: 0 0 auto; font-size: 13px; }
.ir-ins-rest { margin: 7px 0 0; font-size: 12px; }
.ir-ins-foot {
  margin: 11px 0 0;
  padding-top: 9px;
  font-size: 12.5px;
  color: var(--ink-soft);
  border-top: 1px solid var(--rule);
}

/* ── Your own marches ──────────────────────────────────────────────────── */

.ir-mvr-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 240px;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--rule-dark) transparent;
}
.ir-mvr {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 0;
  font-size: 13px;
  border-bottom: 1px dotted var(--rule);
}
.ir-mvr:last-child { border-bottom: 0; }
.ir-mvr-where { flex: 1 1 auto; min-width: 0; }
.ir-mvr-haul { display: block; margin-top: 2px; }
.ir-mvr .ir-cd { flex: 0 0 auto; font-size: 13px; }

/* The movement tags the rally and report screens use. Both of those inject
   their own copy when they mount; this one is here because the village is the
   screen a session opens FIRST, and an unstyled tag on a returning raid is
   exactly the row that has to be readable. Same values, so it does not matter
   which sheet wins the cascade. */
.ir-tag-att { background: #f1dad3; border-color: #b9705f; color: #7d2618; }
.ir-tag-def { background: #dce7d4; border-color: #7d9a6b; color: #3c5730; }
.ir-tag-spy { background: #dce2e9; border-color: #7d8fa2; color: #37424e; }
.ir-tag-ret { background: #e9dfc6; border-color: var(--rule-dark); color: var(--ink-soft); }

/* ── Alerts ────────────────────────────────────────────────────────────── */
/*
 * Bounded, and scrolled INSIDE the panel. This is the rule that stops forty
 * incoming attacks from becoming forty screens of page, and it is why the list
 * can afford to be complete.
 */
.ir-alerts { scroll-margin-top: 96px; }
.ir-alert-list {
  list-style: none;
  margin: 0;
  padding: 2px 9px;
  background: rgba(255,252,242,.5);
  border: 1px solid var(--rule);
  border-radius: 3px;
  box-shadow: inset 0 9px 8px -9px rgba(58,45,28,.3),
              inset 0 -9px 8px -9px rgba(58,45,28,.4);
  max-height: 328px;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--rule-dark) transparent;
}
.ir-alert {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 5px 0;
  font-size: 13px;
  border-bottom: 1px dotted rgba(122,47,34,.22);
}
.ir-alert:last-child { border-bottom: 0; }
.ir-alert-kind {
  flex: 0 0 42px;
  font-size: 9.5px;
  letter-spacing: .09em;
  text-transform: uppercase;
}
.ir-alert.is-threat .ir-alert-kind { color: var(--blood-ink); }
/* Reinforcements are the one incoming a defender is glad to see, so they are
   the one row in this list that is not the colour of blood. */
.ir-alert.is-help { border-left: 3px solid var(--moss); padding-left: 6px; }
.ir-alert.is-help .ir-alert-kind { color: var(--moss); }
.ir-alert-who {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ir-alert-when { flex: 0 0 auto; text-align: right; display: grid; }
.ir-alert-when .ir-cd { font-size: 13.5px; color: var(--blood-ink); }
.ir-alert-when .ir-muted { font-size: 10.5px; font-variant-numeric: tabular-nums; }
.ir-alert-rest { margin: 8px 0 0; font-size: 12px; }

/* The status line scrolled the player here; a second of highlight is what says
   "this is the thing you pressed" — especially on a phone, where the panel
   arrives from three screens away. */
.ir-alerts.is-found { box-shadow: 0 0 0 2px var(--brass-lit), var(--shadow); }
.ir-col-war.is-found {
  outline: 2px solid var(--brass-lit);
  outline-offset: 4px;
  border-radius: var(--radius);
}

/* ── The drill ground ──────────────────────────────────────────────────── */
/*
 * Five recruit panels stacked down the middle column is a lot of scrolling for
 * six rows each, so they sit side by side wherever there is room. `.ir-panel`
 * already carries its own bottom margin; only the column gap is set here.
 */
.ir-drill {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 0 16px;
  align-items: start;
}

/* ── Queues ────────────────────────────────────────────────────────────── */

.ir-q-list { list-style: none; margin: 0; padding: 0; }
.ir-q {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 0;
  border-bottom: 1px dotted var(--rule);
}
.ir-q:last-child { border-bottom: 0; }
.ir-q-art {
  width: 42px; height: 42px;
  border: 1px solid var(--rule-dark);
  border-radius: 3px;
  background: rgba(255,252,242,.6);
  object-fit: cover;
  flex: 0 0 auto;
}
.ir-q-body { flex: 1 1 auto; min-width: 0; }
.ir-q-bar {
  height: 5px;
  margin-top: 5px;
  background: rgba(120,96,58,.18);
  border-radius: 3px;
  overflow: hidden;
}
.ir-q-bar > span {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--brass), var(--brass-lit));
}
.ir-q-right { text-align: right; flex: 0 0 auto; display: grid; gap: 2px; }
.ir-cd { font-size: 14px; font-weight: 600; color: var(--ink); }

/* ── Building grid ─────────────────────────────────────────────────────── */

.ir-b-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
  gap: 12px;
}

.ir-b {
  display: flex;
  gap: 11px;
  padding: 10px;
  background: linear-gradient(180deg, rgba(255,253,246,.9), rgba(240,232,212,.75));
  border: 1px solid var(--rule-dark);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.ir-b-empty { opacity: .82; }
.ir-b-empty .ir-b-art img { filter: grayscale(.55) brightness(1.04); }
.ir-b-short { border-color: var(--gold); }

.ir-b-art {
  position: relative;
  flex: 0 0 auto;
  width: 92px; height: 92px;
  border: 1px solid var(--rule-dark);
  border-radius: 3px;
  overflow: hidden;
  background: #e2d8bd;
  box-shadow: inset 0 1px 4px rgba(58,45,28,.25);
}
.ir-b-art img { width: 100%; height: 100%; object-fit: cover; display: block; }

.ir-b-lvl {
  position: absolute;
  left: 0; bottom: 0;
  min-width: 24px;
  padding: 1px 6px;
  font-size: 13px;
  font-weight: 700;
  color: #f6eed8;
  background: rgba(44,38,29,.86);
  border-top-right-radius: 4px;
}
.ir-b-queued {
  position: absolute;
  right: 0; bottom: 0;
  padding: 1px 6px;
  font-size: 11.5px;
  font-weight: 700;
  color: #2c261d;
  background: var(--brass-lit);
  border-top-left-radius: 4px;
}

.ir-b-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.ir-b-body h3 { font-size: 17px; line-height: 1.15; }
.ir-b-blurb {
  margin: 2px 0 7px;
  font-size: 12px;
  color: var(--ink-faint);
  /* Two lines of flavour, then the numbers. A card that grows a third line
     ruins the grid rhythm on a phone. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.ir-b-next { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 8px; }
.ir-b-to {
  font-family: var(--serif);
  font-size: 12.5px;
  color: var(--ink-soft);
  border-bottom: 1px solid var(--rule);
}
.ir-b-act { margin-top: auto; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ir-b-why { font-size: 11.5px; color: var(--ink-faint); flex: 1 1 120px; }
.ir-b-short .ir-b-why { color: #8a6a1f; }

/* ── Cost chips ────────────────────────────────────────────────────────── */

.ir-cost { display: inline-flex; flex-wrap: wrap; gap: 4px 8px; }
.ir-cost-c {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 12.5px;
  color: var(--ink-soft);
  white-space: nowrap;
}

/* ── Recruit & garrison ────────────────────────────────────────────────── */

.ir-u-list, .ir-g-list { list-style: none; margin: 0; padding: 0; }
.ir-u {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 0;
  border-bottom: 1px dotted var(--rule);
}
.ir-u:last-child { border-bottom: 0; }
.ir-u-art {
  width: 46px; height: 46px;
  flex: 0 0 auto;
  border: 1px solid var(--rule-dark);
  border-radius: 3px;
  background: #e2d8bd;
  object-fit: cover;
}
.ir-u-body { flex: 1 1 auto; min-width: 0; display: grid; gap: 1px; }
.ir-u-have { font-size: 11.5px; color: var(--ink-faint); }
.ir-u-act { display: flex; align-items: center; gap: 5px; flex: 0 0 auto; }

/* `input.ir-num`, not `.ir-num` — the class means two things.

   Line 84 above hands it to anything that prints a number, and the army,
   report and rankings screens use it exactly that way, on spans, divs and
   table cells. Unscoped, this box painted a 66px bordered input around every
   one of them: "350 in the village" wrapped to three lines inside a text
   field, the report's SENT/LOST/LEFT columns each grew a frame, and the
   garrison's empty running total became a blank input box beside the Clear
   button. The box belongs to the control, so say so. */
input.ir-num {
  width: 66px;
  font-family: var(--sans);
  font-size: 14px;
  color: var(--ink);
  background: #fffdf5;
  border: 1px solid var(--rule-dark);
  border-radius: var(--radius);
  padding: 7px 6px;
  text-align: right;
}
input.ir-num:focus { outline: 2px solid var(--brass); outline-offset: 1px; }

.ir-g-list { display: flex; flex-wrap: wrap; gap: 8px; }
.ir-g-list li {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 4px 8px 4px 4px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: rgba(255,252,242,.7);
}
.ir-g-list img { width: 32px; height: 32px; border-radius: 3px; object-fit: cover; }
.ir-g-list b { font-size: 14px; }

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

.ir-btn {
  appearance: none;
  -webkit-appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--serif);
  font-size: 14px;
  color: var(--ink);
  background: linear-gradient(180deg, #f3ead2, #ddd0ae);
  border: 1px solid var(--rule-dark);
  border-radius: var(--radius);
  padding: 8px 14px;
  cursor: pointer;
  /* 38 px tall: a thumb target, not a mouse target. */
  min-height: 38px;
  box-shadow: 0 1px 0 rgba(255,253,246,.8) inset, 0 2px 3px rgba(58,45,28,.18);
  text-decoration: none;
}
.ir-btn:hover { background: linear-gradient(180deg, #f8f1dc, #e4d8b8); text-decoration: none; }
.ir-btn:active { transform: translateY(1px); box-shadow: 0 1px 2px rgba(58,45,28,.2); }
.ir-btn:disabled {
  cursor: not-allowed;
  color: var(--ink-faint);
  background: #e3dac4;
  box-shadow: none;
  opacity: .8;
}
.ir-btn:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }

.ir-btn-primary {
  color: #fbf4e2;
  background: linear-gradient(180deg, #6f5a2c, #4f3f1e);
  border-color: #3b2f16;
  text-shadow: 0 1px 0 rgba(0,0,0,.35);
}
.ir-btn-primary:hover { background: linear-gradient(180deg, #806a35, #5d4a24); }

/* "You cannot pay for this yet" — but still pressable. See village.js. */
.ir-btn-warn {
  color: #4a3a10;
  background: linear-gradient(180deg, #e8d59a, #d3ba73);
  border-color: #a98f47;
}

.ir-linkbtn {
  appearance: none;
  border: 0;
  background: none;
  padding: 4px 2px;
  font-family: var(--sans);
  font-size: 12px;
  color: var(--brass);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.ir-linkbtn:hover { color: var(--blood); }
.ir-vh-name .ir-linkbtn { margin-left: 8px; vertical-align: 4px; }

/* ── Toasts ────────────────────────────────────────────────────────────── */

.ir-toasts {
  position: fixed;
  /* BOTTOM LEFT, not centre. Centred toasts sit on top of the thing the player
     is reading, and under an AI raid this corner fires often — an alert you
     have to look past is worse than no alert. */
  left: 14px;
  bottom: 14px;
  z-index: 200;
  display: grid;
  gap: 8px;
  width: min(340px, calc(100vw - 28px));
  justify-items: start;
  /* Never swallow the click aimed at what is underneath. */
  pointer-events: none;
}
.ir-toast {
  padding: 10px 14px;
  font-size: 13.5px;
  color: #f6eed8;
  background: rgba(44,38,29,.94);
  border-left: 4px solid var(--brass);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  transition: opacity .5s ease, transform .5s ease;
}
.ir-toast-ok { border-left-color: var(--moss-lit); }
.ir-toast-warn { border-left-color: var(--gold); }
.ir-toast-bad { border-left-color: var(--blood-lit); }
.ir-toast-out { opacity: 0; transform: translateY(8px); }
/* The running count on a coalesced alert. One toast that says "x12" instead of
   twelve toasts is the whole point of the coalescing in api.js. */
.ir-toast-count {
  display: inline-block;
  margin-left: 8px;
  padding: 0 7px;
  border-radius: 9px;
  font-size: 11.5px;
  font-weight: 700;
  color: #2a2118;
  background: var(--gold);
}

/* ── The gate ──────────────────────────────────────────────────────────── */

.ir-gate {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(30,24,16,.72);
  backdrop-filter: blur(2px);
  overflow: auto;
}
.ir-gate[hidden] { display: none; }
.ir-gate-card {
  width: min(560px, 100%);
  padding: 26px 24px 20px;
  background: linear-gradient(180deg, #f7f0dc, #e8dcc0);
  border: 1px solid var(--rule-dark);
  border-top: 4px solid var(--brass);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  text-align: center;
}
.ir-gate-title {
  font-size: 30px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink);
}
.ir-gate-sub { color: var(--ink-soft); font-size: 14px; margin: 8px 0 18px; }
.ir-gate-note { font-size: 12px; color: var(--ink-faint); margin: 12px 0 0; }
.ir-gate-back { display: inline-block; margin-top: 16px; color: var(--brass); border-color: var(--rule-dark); }

.ir-world-list { display: grid; gap: 10px; text-align: left; }
.ir-world {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  background: rgba(255,253,246,.7);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}
.ir-world.joined { border-color: var(--moss); }
.ir-world-id { flex: 1 1 auto; min-width: 0; font-family: var(--serif); font-size: 17px; }
.ir-world-meta {
  display: block;
  font-family: var(--sans);
  font-size: 11.5px;
  color: var(--ink-faint);
}
/* Only the world KIND is title-cased. Capitalising the whole line turned
   "day 4 of 30 · 62 players" into "Day 4 Of 30 · 62 Players". */
.ir-world-kind { text-transform: capitalize; }

/* ── Footer ────────────────────────────────────────────────────────────── */

.ir-foot {
  text-align: center;
  padding: 6px 16px 26px;
  font-size: 12.5px;
  color: var(--ink-faint);
}

/* ── The shared audio strip ────────────────────────────────────────────── */
/*
 * shared/site_audio.css dresses the strip for the dark games. Repainting it in
 * parchment here is only colour — the markup, the ids and the behaviour stay
 * exactly as the shared module built them, so mute, both volume sliders and
 * skip keep working on desktop and touch alike.
 */
.ir-audio .mps-audio {
  background: rgba(0,0,0,.22);
  border-color: rgba(212,186,132,.35);
  padding: 4px 8px;
}
.ir-audio .mps-audio-btn {
  color: #e8dcbe;
  background: rgba(255,252,242,.1);
  border-color: rgba(212,186,132,.3);
  min-height: 32px;
}
.ir-audio .mps-audio-btn:hover { background: rgba(255,252,242,.2); }
/* The strip must be able to SHRINK. Left at its max-content width it pushed
 * the masthead 25 px past the viewport on a phone, and a body that scrolls
 * sideways drags the fixed bottom nav out with it. */
.ir-audio { min-width: 0; }
.ir-audio .mps-audio { max-width: 100%; }
.ir-audio .mps-audio-slider { accent-color: var(--brass-lit); flex: 1 1 56px; min-width: 34px; }

/*
 * `.volume-slider` reset. web/style.css — which this page does not link, but
 * which every other page in this origin does — pins that class
 * `position: fixed; top: 12px`, and an unreset slider teleports to the corner
 * of the screen. It has bitten this repo more than once, so the reset ships
 * here whether or not the rule can currently reach us.
 */
.volume-slider {
  position: static;
  top: auto;
  left: auto;
  right: auto;
  bottom: auto;
  z-index: auto;
  width: auto;
  height: auto;
  accent-color: var(--brass-lit);
}

/* ── Icons ─────────────────────────────────────────────────────────────── */
/*
 * Five inline SVGs, drawn in the palette of the art: a log, two bricks, an
 * ingot, a villager and an hourglass, plus a chest for the warehouse. Inline so
 * they cost no request, and drawn rather than typed because an emoji renders as
 * a different picture on every platform and belongs to none of them.
 */
.ir-ic {
  display: inline-block;
  width: 14px;
  height: 14px;
  vertical-align: -2px;
  background: center / contain no-repeat;
  flex: 0 0 auto;
}
.ir-ic-wood {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect x='2' y='5' width='12' height='6' rx='3' fill='%238a6a45'/%3E%3Cellipse cx='4.2' cy='8' rx='1.8' ry='3' fill='%23c9a06c'/%3E%3Cellipse cx='4.2' cy='8' rx='.7' ry='1.2' fill='%238a6a45'/%3E%3C/svg%3E");
}
.ir-ic-clay {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect x='2' y='4' width='12' height='3.6' rx='.7' fill='%23a9634a'/%3E%3Crect x='2' y='8.4' width='12' height='3.6' rx='.7' fill='%23c07a5c'/%3E%3C/svg%3E");
}
.ir-ic-iron {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 12h10l-1.6-4H4.6z' fill='%236e7883'/%3E%3Cpath d='M4.6 8h6.8L10.2 5H5.8z' fill='%239aa5b1'/%3E%3C/svg%3E");
}
.ir-ic-pop {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='5' r='2.4' fill='%236b5b45'/%3E%3Cpath d='M2.8 13.6c0-2.9 2.3-5.2 5.2-5.2s5.2 2.3 5.2 5.2z' fill='%236b5b45'/%3E%3C/svg%3E");
}
.ir-ic-time {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.2 2.2h7.6v2.1L8.6 8l3.2 3.7v2.1H4.2v-2.1L7.4 8 4.2 4.3z' fill='none' stroke='%235b4a35' stroke-width='1.3' stroke-linejoin='round'/%3E%3C/svg%3E");
}
.ir-ic-watch {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1.4l5.4 1.7v4.5c0 3.4-2.6 5.4-5.4 6.9-2.8-1.5-5.4-3.5-5.4-6.9V3.1z' fill='%238d3a2a'/%3E%3Cpath d='M8 3.1l3.7 1.2v3.3c0 2.3-1.8 3.7-3.7 4.8z' fill='%23b0563f'/%3E%3C/svg%3E");
}
.ir-ic-store {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.4 5.6a4.6 4.6 0 0 1 9.2 0z' fill='%23a07f52'/%3E%3Crect x='2.2' y='5.5' width='11.6' height='7.2' rx='1' fill='%238a6a45'/%3E%3Cpath d='M2.2 8.6h11.6' stroke='%23efe4c8' stroke-width='1'/%3E%3Crect x='6.9' y='7.1' width='2.2' height='3' rx='.5' fill='%23c8a45c'/%3E%3C/svg%3E");
}

/* ── Phones ────────────────────────────────────────────────────────────── */
/*
 * The nav moves to the bottom of the screen, where a thumb is. It is the SAME
 * element, repositioned — a second copy would mean two sets of ids and one of
 * them always rots.
 */
@media (max-width: 860px) {
  body { padding-bottom: calc(60px + env(safe-area-inset-bottom, 0px)); }

  .ir-top { padding: 8px 12px; gap: 8px; }
  .ir-brand-name { font-size: 18px; }
  .ir-top-right { gap: 8px; flex-wrap: wrap; justify-content: space-between; }
  .ir-player { text-align: left; }
  /* Audio gets its own full-width row rather than fighting the name for space. */
  .ir-audio { flex: 1 1 100%; }
  .ir-audio .mps-audio { width: 100%; }
  /* The back link is in the footer and in the gate; on a phone the masthead
     needs the width more than it needs a third copy. */
  .ir-top .ir-back { display: none; }

  .ir-ledger { padding: 7px 10px; gap: 8px; }
  .ir-ledger-village { width: 100%; }
  .ir-select { flex: 1 1 auto; max-width: none; }
  /* Three pits on one row, warehouse and population on the next. The bases are
     explicit: left to `flex: 1 1 0` the cells shrink far enough that a fourth
     squeezes onto the first row and every number overlaps its neighbour. */
  .ir-res { flex: 1 1 100%; gap: 6px; flex-wrap: wrap; }
  .ir-res-cell { flex: 1 1 30%; min-width: 0; padding: 3px 6px 6px; }
  .ir-res-n { font-size: 13.5px; }
  .ir-res-lbl { font-size: 9px; letter-spacing: .05em; }
  .ir-res-rate { font-size: 9.5px; }
  .ir-res-meta { flex: 1 1 46%; }

  .ir-nav {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 100;
    justify-content: space-between;
    gap: 0;
    padding: 0 2px calc(env(safe-area-inset-bottom, 0px));
    border-top: 2px solid var(--brass);
    border-bottom: 0;
    box-shadow: 0 -3px 12px rgba(58,45,28,.22);
  }
  .ir-nav a {
    flex: 1 1 0;
    text-align: center;
    font-size: 13px;
    padding: 11px 2px;
    border-bottom: 0;
    border-top: 3px solid transparent;
  }
  .ir-nav a.on { border-top-color: var(--brass); border-bottom-color: transparent; }

  .ir-view { padding: 12px 10px 24px; }
  .ir-panel { padding: 12px; }
  .ir-vh-name { font-size: 23px; }
  .ir-vh-meta { margin-left: 0; }

  /* One column of building cards below ~560 px; two above it. The card keeps
     its art-beside-text shape either way, which is what makes it readable at
     phone width without a second layout. */
  .ir-b-grid { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 10px; }
  .ir-b-art { width: 76px; height: 76px; }
  .ir-b-body h3 { font-size: 16px; }

  .ir-u-act { flex-wrap: wrap; justify-content: flex-end; max-width: 132px; }
  input.ir-num { width: 58px; }

  /* One column, so the war room is simply below the village — which is the
     order the markup is already in. The status line stays at the top, the
     button in it scrolls down to the list.

     The lists are bounded off the VIEWPORT here rather than a pixel height: a
     phone screen is the thing they must not swamp, and 46vh leaves half of it
     for whatever the player scrolled down to look at. */
  .ir-watch { flex-wrap: wrap; gap: 2px 8px; padding: 8px 10px; font-size: 13.5px; }
  .ir-watch-text { flex: 1 1 140px; }
  .ir-watch-more { flex: 1 1 100%; text-align: right; }
  /* Clear of the sticky ledger bar, which is two rows of resources on a phone. */
  .ir-alerts { scroll-margin-top: 128px; }
  .ir-alert-list { max-height: 46vh; }
  .ir-mvr-list { max-height: 40vh; }
  .ir-drill { grid-template-columns: 1fr; }

  .ir-toasts { bottom: calc(70px + env(safe-area-inset-bottom, 0px)); }
}

@media (max-width: 400px) {
  .ir-nav a { font-size: 11.5px; padding: 10px 1px; }
  .ir-b-grid { grid-template-columns: 1fr; }
}

/* Somebody who has asked for less motion gets no sliding bars or fading
   toasts; the numbers still update, which is the part that matters. */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}


/* == The muster: the host panel and the world list ==========================
 *
 * The screen a player meets before they have a village. It renders into the
 * gate overlay, so everything here is scoped under the card rather than being
 * a second set of page-level rules.
 *
 * The host panel is a FORM in an overlay, which is the one place this design
 * needs a wider column than the rest: three labelled controls in a 560 px
 * centred card read as a stack of orphaned labels with their hints wrapped
 * underneath. It also has to survive a 390 px phone, so every control below is
 * a full-width row that wraps rather than a grid that squeezes.
 */

/* A card TALLER than the viewport must not have its top clipped. `align-items:
   center` on the overlay does exactly that: the overflow goes both ways and a
   scroll container cannot reach above its own start edge, so the muster's
   heading was unreachable on a laptop and most of the panel on a phone.
   `margin: auto` on the flex item centres it while it fits and pushes from the
   start once it does not — which is the whole fix, and it leaves the short
   sign-in card exactly where it was. */
.ir-gate { align-items: flex-start; }
.ir-gate-card { margin: auto; }

.ir-gate-card.ir-gate-muster { width: min(720px, 100%); text-align: left; }
.ir-gate-muster .ir-gate-title,
.ir-gate-muster .ir-gate-sub { text-align: center; }

/* The routed half of the muster (#/worlds) is the same list and the same host
   panel inside #view. It needs the card's column width and nothing else — the
   panel styles below are written against the elements, not against the gate. */
.ir-muster-screen { max-width: 720px; margin: 0 auto; }

.ir-world-by {
  display: block;
  font-family: var(--sans);
  font-size: 11px;
  color: var(--ink-faint);
  font-style: italic;
}
/* A finished round is no longer LISTED here at all — it belongs under "Past
   rounds", where it is a report rather than something that looks joinable. The
   rule survives for a cached client reading an older server's response. */
.ir-world.ended { opacity: .72; border-style: dashed; }

.ir-host {
  margin: 18px 0 0;
  padding: 16px 14px 14px;
  background: rgba(255,253,246,.68);
  border: 1px solid var(--rule-dark);
  border-top: 3px solid var(--brass);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.ir-host-head { margin-bottom: 14px; }
.ir-host-title {
  margin: 0;
  font-family: var(--serif);
  font-size: 20px;
  letter-spacing: .04em;
  color: var(--ink);
}
.ir-host-sub { margin: 4px 0 0; font-size: 12.5px; color: var(--ink-soft); }
.ir-host-foot { margin-top: 14px; }
.ir-host-foot .ir-btn { width: 100%; }
.ir-host-foot .ir-gate-note { text-align: center; }

/* The muster with a round already running. Not a disabled form — there is
   nothing to choose while somebody else's round is on, so the panel says so
   and points at the one thing that can be done. Brass on the top edge is what
   marks a panel you can act in; this one is quieter. */
.ir-host-shut { border-top-color: var(--rule-dark); background: rgba(255,253,246,.5); }
.ir-host-shut .ir-host-head { margin-bottom: 0; }
.ir-host-shut .ir-host-foot .ir-btn { width: 100%; }

/* The round's name, which a signed-in host does not type. */
.ir-host-named b {
  display: block;
  font-family: var(--serif);
  font-size: 18px;
  letter-spacing: .03em;
  color: var(--ink);
}
.ir-host-named .ir-field-h { margin-top: 2px; }

/* The round-over bar. Between the nav and the view, full width, so it is the
   first thing read on a world that has stopped — and it carries the way to the
   standings rather than only the news. */
.ir-over {
  display: flex;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
  margin: 12px auto 0;
  padding: 9px 13px;
  max-width: 1180px;
  background: linear-gradient(180deg, rgba(255,253,246,.92), rgba(235,225,200,.8));
  border: 1px solid var(--rule-dark);
  border-left: 3px solid var(--brass);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.ir-over-text { flex: 1 1 260px; font-size: 13.5px; color: var(--ink-soft); }

/* A past round opened from the muster takes the whole card. */
.ir-round-panel { text-align: left; }
.ir-round-panel h3 { margin: 16px 0 6px; }

.ir-field { padding: 10px 0; border-top: 1px solid var(--rule); }
.ir-field:first-of-type { border-top: 0; padding-top: 0; }
.ir-field-head { margin-bottom: 7px; }
.ir-field-l {
  font-family: var(--serif);
  font-size: 14.5px;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--ink);
}
.ir-field-h { display: block; font-size: 11.5px; color: var(--ink-faint); }
.ir-field-b { display: grid; gap: 8px; }

/* Segmented runtime picker. Buttons rather than a select: four options, and
   the whole point of the panel is that the choice is visible at a glance. */
.ir-seg { display: flex; flex-wrap: wrap; gap: 6px; }
.ir-seg-b {
  flex: 1 1 84px;
  appearance: none;
  -webkit-appearance: none;
  min-height: 38px;
  font-family: var(--serif);
  font-size: 14px;
  color: var(--ink);
  background: linear-gradient(180deg, #f3ead2, #ddd0ae);
  border: 1px solid var(--rule-dark);
  border-radius: var(--radius);
  cursor: pointer;
}
.ir-seg-b:hover { background: linear-gradient(180deg, #f8f1dc, #e4d8b8); }
.ir-seg-b.on {
  color: #fbf4e2;
  background: linear-gradient(180deg, #6f5a2c, #4f3f1e);
  border-color: #3b2f16;
  text-shadow: 0 1px 0 rgba(0,0,0,.35);
}
.ir-seg-b:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }

.ir-slider { display: flex; align-items: center; gap: 10px; }
.ir-range {
  flex: 1 1 auto;
  min-width: 0;
  /* 28 px of thumb target. A range input styled down to a hairline is
     unusable on a phone, which is half of this site's traffic. */
  height: 28px;
  accent-color: #6f5a2c;
}
.ir-slider-out {
  flex: 0 0 auto;
  min-width: 62px;
  text-align: right;
  font-family: var(--sans);
  font-size: 17px;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.ir-presets { display: flex; flex-wrap: wrap; gap: 6px; }
.ir-chip-b {
  appearance: none;
  -webkit-appearance: none;
  min-height: 30px;
  padding: 3px 10px;
  font-family: var(--sans);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
  background: #fffdf5;
  border: 1px solid var(--rule);
  border-radius: 999px;
  cursor: pointer;
}
.ir-chip-b.on { color: var(--ink); border-color: var(--brass); background: #f4e6c4; }
.ir-chip-b:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }

.ir-bots { display: flex; align-items: center; gap: 10px; }
.ir-bots-lbl { font-size: 13px; color: var(--ink-soft); }
.ir-toggle {
  appearance: none;
  -webkit-appearance: none;
  min-width: 62px;
  min-height: 38px;
  font-family: var(--serif);
  font-size: 14px;
  color: var(--ink-faint);
  background: #e3dac4;
  border: 1px solid var(--rule-dark);
  border-radius: var(--radius);
  cursor: pointer;
}
.ir-toggle.on {
  color: #fbf4e2;
  background: linear-gradient(180deg, #6b7a4f, #4c5838);
  border-color: #3b4429;
  text-shadow: 0 1px 0 rgba(0,0,0,.3);
}
.ir-toggle:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }
input.ir-bots-n:disabled { opacity: .5; }

.ir-text {
  width: 100%;
  font-family: var(--serif);
  font-size: 15px;
  color: var(--ink);
  background: #fffdf5;
  border: 1px solid var(--rule-dark);
  border-radius: var(--radius);
  padding: 8px 10px;
  min-height: 38px;
}
.ir-text:focus { outline: 2px solid var(--brass); outline-offset: 1px; }

/* The consequences block. Every number in it came off /worlds/preview — the
   client does not price a world any more than it prices a barracks. */
.ir-consequence {
  margin-top: 14px;
  padding: 10px 12px;
  background: rgba(236,226,205,.75);
  border: 1px dashed var(--rule-dark);
  border-radius: var(--radius);
}
.ir-consequence-t {
  margin: 0 0 6px;
  font-family: var(--serif);
  font-size: 12px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.ir-consequence-l { margin: 0; padding-left: 18px; font-size: 12.5px; line-height: 1.5; }
.ir-consequence-l li { margin: 3px 0; color: var(--ink-soft); }
.ir-consequence-l b { color: var(--ink); font-variant-numeric: tabular-nums; }
/* The one line that must NOT move when the slider does. Marked, because a host
   dragging speed to 800x needs to see that marches did not follow it. */
.ir-consequence-l li.ir-keep {
  list-style: none;
  margin-left: -14px;
  padding-left: 12px;
  border-left: 3px solid var(--moss);
}

@media (max-width: 560px) {
  .ir-gate { padding: 10px; }
  .ir-gate-card.ir-gate-muster { padding: 18px 14px 16px; }
  /* The row is a column on a phone: name, meta, founder, then the button
     across the full width, so nothing has to be squeezed to 90 px. */
  .ir-world { flex-wrap: wrap; }
  .ir-world .ir-btn { width: 100%; }
  /* Two by two rather than three-then-one: four options in a ragged 3+1 look
     like a wrap accident instead of a choice. */
  .ir-seg-b { flex: 1 1 calc(50% - 3px); }
  .ir-slider { flex-wrap: wrap; }
  .ir-slider-out { flex: 1 0 100%; text-align: left; }
}
