/* Self-hosted. The HUD's condensed face is load-bearing for the layout -- the
   reference's labels run 0.47em per character where a text serif runs 0.62 --
   so it cannot depend on reaching a font host. Latin subset only, 21KB a
   weight, and it renders identically offline, in CI, and on a player's phone. */
/* One file, and it was always one file.
   This shipped as three -- oswald-500, -600 and -700 -- and all three were
   byte-identical (md5 5f49329..., 21,472 bytes each). Declaring one static
   face three times does not make three weights: every `font-weight: 700` in
   the HUD below matched a face whose glyphs are the default instance, so
   nothing ever rendered at 700 and 42KB was spent saying so.
   It is a variable font -- fvar, STAT, avar and HVAR are all in the table
   directory -- so a single declaration with a weight *range* is both smaller
   and the only version of this that produces a real 700. */
@font-face {
  font-family: 'HUD Condensed';
  font-style: normal;
  font-weight: 200 700;
  font-display: block;
  src: url('./assets/fonts/oswald-variable.woff2') format('woff2-variations'),
       url('./assets/fonts/oswald-variable.woff2') format('woff2');
}

/* BOOTLEG EMPIRE — 1920s operations HUD.
   Warm brass on green-black. One screen, no scrolling: a data shell top and
   bottom, the town filling everything between them, and anything else over the
   top of it. A single committed visual world, painted explicitly. */

:root {
  color-scheme: dark;

  --ink:        #0d100e;
  --ink-2:      #141915;
  --panel:      #1d1a17;
  --panel-2:    #24211d;
  --rule:       #36312c;
  --brass:      #c9a227;
  --brass-dim:  #8a7222;
  --cream:      #e8e2d0;
  --cream-dim:  #9d978a;
  --red:        #a63c32;
  --red-bright: #d1564a;
  --green:      #6f9d6b;
  --sky:        #1a241f;

  --display: 'Jost', 'Futura', 'Century Gothic', 'Trebuchet MS', sans-serif;
  --body: 'Crimson Pro', 'Iowan Old Style', 'Palatino Linotype', Georgia, serif;

  --dash-h: 78px;
  --tabs-h: 54px;

  /* Room for a notch and a home bar. Real on a phone; not ours to claim when
     the page is running inside someone else's frame, where the insets belong
     to the host and reserving them again just banks dead space above the
     dashboard and below the menu. app.js marks the document when embedded. */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
}

html[data-embedded] { --safe-top: 0px; --safe-bottom: 0px; }

/* A host page that embeds this one may pad the root element for the notch and
   the home bar — the artifact shell does exactly that. Our shell reserves them
   itself, on the dashboard and the menu, so a second reservation is dead space
   at both ends and the game shrinks to fit between them. `html:root` outranks
   a plain `:root` rule whichever stylesheet lands last. */
html:root { padding: 0; }

* { box-sizing: border-box; }

html, body { height: 100%; overflow: hidden; }

body {
  margin: 0;
  background: var(--ink);
  color: var(--cream);
  font-family: var(--body);
  font-size: 15px;
  line-height: 1.4;
  display: flex;
  flex-direction: column;
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior: none;
}

h2, h3, button, .display, select, input, .lvl, .num { font-family: var(--display); }

/* ------------------------------------------------------- dashboard (top) */

.dash {
  flex: 0 0 auto;
  background: linear-gradient(180deg, #221f1c, #111613);
  border-bottom: 2px solid var(--brass-dim);
  padding-top: var(--safe-top);
}

.dash-main {
  display: grid;
  grid-template-columns: 1fr 1fr minmax(96px, 0.9fr);
  align-items: stretch;
}
/* However many cells there are: the row only carries resources this build can
   actually spend, so it grows and shrinks as systems are surfaced. */
.dash-sub {
  display: grid;
  grid-auto-flow: column;
  /* minmax(0, 1fr), not 1fr. `1fr` is `minmax(auto, 1fr)`, so a cell whose
     content is wide — "+800/hr" — refuses to shrink below it and takes the
     room from its neighbours. On a phone that crushed the last cell to a few
     pixels: "C... 5. spee...". Equal columns have to be allowed to shrink. */
  grid-auto-columns: minmax(0, 1fr);
  border-top: 1px solid var(--rule);
}

/* Wide enough for one row: eight cells across instead of stacking, so the
   dashboard stays dense rather than stretching three cells over a monitor. */
@media (min-width: 760px) {
  .dash { display: flex; }
  .dash-main { flex: 3 1 0; }
  .dash-sub { flex: 5 1 0; border-top: 0; border-left: 1px solid var(--rule); }
  .dash-sub .cell { padding: 6px 12px; }
  .dash-sub .cell .v { font-size: 17px; }
  .dash-sub .cell .r { font-size: 11px; }
}

.cell {
  padding: 6px 10px;
  border-right: 1px solid var(--rule);
  min-width: 0;
}
.cell:last-child { border-right: 0; }
/* The Chips cell carries the longest line on the row and is the one a player
   taps, so it gets a little more room than an even split. */
.dash-sub .cell.chips { min-width: 0; }
.cell .k {
  display: block;
  font-family: var(--display);
  font-size: 9px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--cream-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cell .v {
  font-family: var(--display);
  font-size: 19px;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  display: block;
  /* A cell is a fifth of a phone: a six-figure balance must not push the one
     beside it off the screen. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cell .r {
  font-size: 11px;
  color: var(--green);
  font-variant-numeric: tabular-nums;
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cell .r.warn { color: var(--red-bright); }
.cell .r.flat { color: var(--cream-dim); }
.cell .r.waiting { color: #ffd98a; }

.dash-sub .cell { padding: 5px 7px; }
.dash-sub .cell .v { font-size: 14px; }
.dash-sub .cell .r { font-size: 10px; }

.cell.clean .v { color: var(--cream); }
.cell.dirty .v { color: var(--red-bright); }
.cell.chips .v { color: #d8a0a0; }
#dash-chips { cursor: pointer; }

/* Heat lives in the dashboard, as a gauge rather than a number in a list. */
.cell.heat { cursor: pointer; }
.heat-top { display: flex; align-items: baseline; justify-content: space-between; gap: 6px; }
.heat-num { font-family: var(--display); font-size: 19px; line-height: 1.1; font-variant-numeric: tabular-nums; }
.heat-tier {
  font-family: var(--display);
  font-size: 8.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-align: right;
}
.heat-bar {
  position: relative;
  height: 6px;
  margin-top: 4px;
  border-radius: 3px;
  background: #0e0d0b;
  overflow: hidden;
}
.heat-bar > i { display: block; height: 100%; transition: width .4s linear, background .6s; }
.heat-bar > u { position: absolute; top: 0; bottom: 0; width: 1px; background: rgba(232, 226, 208, 0.3); }

/* ------------------------------------------------------------------ town */

.town {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  background: radial-gradient(72% 62% at 50% 40%, #24312a 0%, var(--sky) 55%, #0e1310 100%);
  overflow: hidden;
}
#base { width: 100%; height: 100%; display: block; touch-action: none; }

.opening-card {
  flex: 0 0 auto;
  width: 100%;
  padding: 5px 12px;
  background: rgba(16, 23, 19, 0.94);
  border-bottom: 1px solid var(--brass-dim);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: 10px;
  align-items: center;
}
.opening-eyebrow { color: var(--brass); font: 9px var(--display); letter-spacing: .14em; text-transform: uppercase; }
.opening-card strong, .hood-card strong { font: 600 14px var(--display); }
.opening-card .opening-eyebrow, .opening-card strong { grid-column: 1; }
.opening-detail { display: none; }
.opening-card button { grid-column: 2; grid-row: 1 / span 2; justify-self: end; padding: 7px 10px; color: var(--ink); background: var(--brass); white-space: nowrap; }
.city-map { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; padding: 12px; background: repeating-linear-gradient(45deg, #121a16, #121a16 10px, #1e2922 11px, #1e2922 14px); border: 1px solid var(--brass-dim); }
.hood-card { display: grid; gap: 5px; padding: 13px; border: 1px solid var(--rule); background: var(--panel-2); }
.hood-card.home { border-color: var(--brass); box-shadow: 0 0 0 2px rgba(201,162,39,.15); }
.hood-card span:not(.opening-eyebrow) { color: var(--cream-dim); font-size: 12px; }
.hood-card .hood-landmark { color: var(--brass) !important; text-transform: capitalize; }
.vance-intro { padding: 13px; border-left: 3px solid var(--brass); background: var(--panel-2); font-size: 17px; }
.story-lead { margin: 4px 0 16px; font-size: 19px; line-height: 1.4; white-space: pre-line; }
.crew-slider, .send-slider { display: grid; gap: 2px; min-width: 120px; font: 12px var(--display); color: var(--cream-dim); }
.crew-slider input, .send-slider input { width: 100%; accent-color: var(--brass); touch-action: auto; }
.crew-slider output, .send-slider output { color: var(--cream); font-weight: 600; }
.crew { flex-wrap: wrap; }
@media (max-height: 580px) { .opening-card { padding: 3px 9px; } }

.plot { pointer-events: none; }
.plot.selected { filter: brightness(1.07); }
.hit { pointer-events: all; cursor: pointer; }
.hit:focus { outline: none; }
.hit:focus-visible { stroke: var(--brass); stroke-width: 2.5; }

.plot-label {
  font-family: var(--display);
  font-size: 11px;
  fill: var(--cream-dim);
  letter-spacing: 0.06em;
  paint-order: stroke;
  stroke: #10150f;
  stroke-width: 3px;
  stroke-linejoin: round;
}
.lvl { font-size: 13px; fill: var(--brass); font-weight: 500; }
.prog-text { font-family: var(--display); font-size: 9px; fill: var(--cream-dim); }
/* A bobbing marker over the block. Scoped: an unqualified `.ready` is a name
   any panel might reach for, and one that did picked up a 26px hover. */
#base .ready { animation: bob 1.6s ease-in-out infinite; }
@keyframes bob { 0%, 100% { transform: translateY(-26px); } 50% { transform: translateY(-32px); } }

/* What a building has made and is waiting to hand over (docs/41-collecting.md).
   A brass disc with the resource on it, bobbing over the roof; red once the
   building has gone twelve hours and stopped. */
/* Traffic on the block's streets: one stretch per car, fading in at one
   junction and out at the next (iso.js `traffic`). Gone under reduced motion:
   a car parked in the middle of a road is not a calmer street. */
#base .traffic-car { animation: drive 10s linear infinite; opacity: 0; }
@keyframes drive {
  0% { transform: translate(0, 0); opacity: 0; }
  8% { opacity: 1; }
  88% { opacity: 1; }
  100% { transform: translate(var(--dx), var(--dy)); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { #base .traffic-car { display: none; } }

/* A level landing on the block (app.js `celebrateBuild`): light off the lot,
   sparks, and the level rising off the roof. */
#base .levelup-rays path { fill: #ffd46b; }
#base .levelup-rays { transform-box: fill-box; transform-origin: center; animation: levelup-rays 1.6s ease-out forwards; }
@keyframes levelup-rays { from { transform: scale(.2) rotate(0deg); opacity: .95; } to { transform: scale(1.15) rotate(25deg); opacity: 0; } }
#base .levelup-ring { fill: none; stroke: #ffe39a; stroke-width: 5; transform-box: fill-box; transform-origin: center; animation: levelup-ring 1.1s ease-out forwards; }
@keyframes levelup-ring { from { transform: scale(.3); opacity: 1; } to { transform: scale(4.2); opacity: 0; } }
#base .levelup-sparks circle { fill: #fff2c2; animation: levelup-spark 1.3s ease-out forwards; }
@keyframes levelup-spark { from { transform: translate(0, 0); opacity: 1; } to { transform: translate(var(--sx), var(--sy)); opacity: 0; } }
#base .levelup-banner { animation: levelup-banner 2.5s ease-out forwards; }
#base .levelup-banner rect { fill: #2a120c; stroke: #f0c264; stroke-width: 3; filter: drop-shadow(0 4px 6px #000a); }
#base .levelup-banner text { text-anchor: middle; font: 700 22px var(--hud-face, system-ui); letter-spacing: .06em; fill: #ffe7a6; }
#base .levelup.is-milestone .levelup-banner text { font-size: 28px; }
#base .levelup-banner .levelup-sub { font-size: 14px !important; fill: #f0c264; letter-spacing: .18em; }
/* A blow, not a level: the same flare in red, for Eddie's robbery. */
#base .levelup.is-alarm .levelup-rays path { fill: #e0533c; }
#base .levelup.is-alarm .levelup-ring { stroke: #ff7a5c; }
#base .levelup.is-alarm .levelup-sparks circle { fill: #ffb199; }
#base .levelup.is-alarm .levelup-banner rect { fill: #3a0d08; stroke: #e0533c; }
#base .levelup.is-alarm .levelup-banner text { fill: #ffd2c4; }
@keyframes levelup-banner { 0% { transform: translateY(10px) scale(.6); opacity: 0; } 15% { transform: translateY(-6px) scale(1.08); opacity: 1; } 25% { transform: translateY(-10px) scale(1); } 80% { opacity: 1; } 100% { transform: translateY(-46px); opacity: 0; } }
.toast.level-up { border-left-color: var(--brass); color: #ffe3a0; }
#base .collect-bob { animation: collect-bob 1.8s ease-in-out infinite; }
@keyframes collect-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }
#base .collect-disc { fill: #f3e2b4; stroke: #b8862f; stroke-width: 4px; filter: drop-shadow(0 3px 4px rgba(0,0,0,.6)); }
#base .collect-tail { fill: #b8862f; }
#base .collect-bubble.is-full .collect-disc { stroke: #d0402f; stroke-width: 5px; }
#base .collect-bubble.is-full .collect-tail { fill: #d0402f; }
#base .collect-bubble.is-full .collect-bob { animation-duration: 0.9s; }
#base .collect-hit { pointer-events: all; cursor: pointer; }
#base .collect-hit:focus { outline: none; }
#base .collect-hit:focus-visible { stroke: var(--brass); stroke-width: 3; }
#base .collect-float text { font: 700 26px var(--display, system-ui); fill: #ffe7a6; paint-order: stroke; stroke: #10150f; stroke-width: 4px; }
#base .collect-rise { animation: collect-rise 1.4s ease-out forwards; }
@keyframes collect-rise { from { transform: translateY(0); opacity: 1; } 70% { opacity: 1; } to { transform: translateY(-46px); opacity: 0; } }

.recenter {
  position: absolute;
  right: 10px;
  bottom: 10px;
  width: 38px;
  height: 38px;
  min-height: 0;
  padding: 0;
  display: grid;
  place-items: center;
  color: var(--cream-dim);
  background: rgba(16, 21, 17, 0.9);
}

/* Heat tints the town as the Bureau closes in. */
.town::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(78% 70% at 50% 50%, transparent 38%, var(--heat-tint, transparent) 100%);
  transition: background .8s linear;
}

/* ---------------------------------------------------------- tabs (bottom) */

.tabs {
  flex: 0 0 auto;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  background: linear-gradient(0deg, #111613, #221f1c);
  border-top: 2px solid var(--brass-dim);
  padding-bottom: var(--safe-bottom);
}
.tab {
  position: relative;
  min-height: var(--tabs-h);
  background: none;
  border: 0;
  border-right: 1px solid var(--rule);
  border-radius: 0;
  color: var(--cream-dim);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 6px 2px;
  font-size: 9px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  cursor: pointer;
}
.tab:last-child { border-right: 0; }
/*
 * The dot is the signal, so it has to read at a glance.
 *
 * Six pixels was a speck. It carries more work now than it used to: the
 * guidance card only walks a player to their *first* reward, and after that
 * noticing this is how they know there is money waiting. A ring around it
 * separates it from the tab artwork at any background brightness.
 */
.tab .dot {
  position: absolute;
  transform: translate(14px, -12px);
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--red-bright);
  box-shadow: 0 0 0 2px #1d1a17, 0 0 6px #ff5a4a66;
}
.tab[aria-selected="true"] { color: var(--brass); background: rgba(201, 162, 39, 0.08); }
.tab:focus-visible { outline: 2px solid var(--brass); outline-offset: -2px; }

/* ---------------------------------------------------------------- sheets */

.scrim { position: fixed; inset: 0; background: rgba(8, 11, 9, 0.62); z-index: 20; }
.scrim[hidden], .sheet[hidden] { display: none !important; }

.sheet {
  position: fixed;
  z-index: 21;
  left: 0;
  right: 0;
  bottom: 0;
  max-height: calc(100% - 92px);
  background: var(--panel);
  border-top: 2px solid var(--brass-dim);
  display: flex;
  flex-direction: column;
  padding-bottom: var(--safe-bottom);
  animation: rise .18s ease-out;
}
@keyframes rise { from { transform: translateY(14px); opacity: 0.6; } to { transform: none; opacity: 1; } }

/*
 * The income breakdown is the one panel that does not belong at the bottom.
 *
 * Every other sheet answers "what do you want to do", and a thumb-height
 * bottom sheet is the right shape for that. This one answers "where does that
 * number come from", and the number is a dashboard cell at the top of the
 * screen. A panel that rose from the far end of the phone to explain it made
 * the player look away from the thing they had just tapped and then find it
 * again afterwards. So this one unrolls downward out of the dashboard, from
 * the cell that was tapped: `--drop-top` is the underside of the dashboard and
 * `--drop-x` the middle of the cell, both measured at open time in `app.js`.
 */
.sheet[data-panel="resource"] {
  top: var(--drop-top, 0px);
  bottom: auto;
  left: 6px;
  right: 6px;
  width: auto;
  max-height: calc(100dvh - var(--drop-top, 0px) - 84px);
  border-top: 0;
  border-right: 1px solid var(--brass-dim);
  border-bottom: 2px solid var(--brass-dim);
  border-left: 1px solid var(--brass-dim);
  border-radius: 0 0 10px 10px;
  padding-bottom: 0;
  transform-origin: var(--drop-x, 50%) top;
  /* The theme's shadow is cast upward, for a panel standing on the bottom
     edge. This one hangs from the top, so its shadow falls the other way. */
  box-shadow: 0 24px 60px #0a0908dd;
  animation: drop .2s cubic-bezier(.2, .78, .32, 1);
}
/* The tab of panel still attached to the cell it came out of. */
.sheet[data-panel="resource"]::before {
  content: "";
  position: absolute;
  top: -7px;
  left: calc(var(--drop-x, 50%) - 8px);
  width: 16px;
  height: 8px;
  background: inherit;
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
/* Unrolling, not sliding: the panel's own top edge stays put against the
   dashboard while the rest of it is revealed downward. */
@keyframes drop {
  from { clip-path: inset(0 0 100% 0); opacity: .4; }
  to { clip-path: inset(0 0 0 0); opacity: 1; }
}

@media (min-width: 720px) {
  .sheet {
    left: 50%;
    right: auto;
    bottom: 50%;
    transform: translate(-50%, 50%);
    width: 460px;
    max-height: 78%;
    border: 1px solid var(--brass-dim);
    border-radius: 4px;
  }
  @keyframes rise { from { opacity: 0.4; } to { opacity: 1; } }
  /* Still anchored to the dashboard, which is full width at every size. */
  .sheet[data-panel="resource"] {
    left: 6px;
    right: 6px;
    bottom: auto;
    transform: none;
    width: auto;
    max-height: calc(100dvh - var(--drop-top, 0px) - 84px);
    border-radius: 0 0 10px 10px;
  }
}

.sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--rule);
  background: var(--panel-2);
}
.sheet-head h2 {
  margin: 0;
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--brass);
}
.sheet-close {
  min-height: 34px;
  width: 34px;
  padding: 0;
  font-size: 20px;
  line-height: 1;
  background: none;
  border: 0;
  color: var(--cream-dim);
}
.sheet-body { padding: 13px 14px 16px; min-height: 0; }
.sheet[data-panel="crews"] .sheet-body,
.sheet[data-panel="raid"] .sheet-body,
.sheet[data-panel="building"] .sheet-body { overflow-y: auto; }

/* ------------------------------------------------------------ sheet rows */

.blurb { color: var(--cream-dim); font-style: italic; font-size: 13.5px; margin: 0 0 11px; }

.row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 0;
  border-bottom: 1px dotted var(--rule);
  font-size: 13.5px;
}
.row:last-of-type { border-bottom: 0; }
.row .k { color: var(--cream-dim); }
.row .v { font-variant-numeric: tabular-nums; text-align: right; }
.row .v .up { color: var(--green); }
.row .v .warn { color: var(--red-bright); }
.row .v .heat-notice { color: var(--brass); }

.cost {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  margin-top: 11px;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}
.cost .short { color: var(--red-bright); }
.cost svg { vertical-align: -4px; }

button {
  background: var(--panel-2);
  color: var(--cream);
  border: 1px solid var(--rule);
  border-radius: 2px;
  min-height: 44px;
  padding: 8px 14px;
  font-size: 12.5px;
  letter-spacing: 0.06em;
  cursor: pointer;
}
button:hover:not(:disabled) { border-color: var(--brass-dim); color: var(--brass); }
button:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }
button:disabled { opacity: 0.4; cursor: not-allowed; }
button.primary { border-color: var(--brass-dim); color: var(--brass); }
button.wide { width: 100%; margin-top: 12px; }

/* The one control that destroys something. Red at rest rather than only once
   armed, so it never reads like the buttons around it. */
button.danger { border-color: #5a2b26; color: var(--red-bright); }
button.danger:hover:not(:disabled) { border-color: var(--red-bright); color: var(--red-bright); }
button.danger small { color: var(--cream-dim); }

.actions { display: flex; gap: 8px; margin-top: 12px; }
.actions button { flex: 1; }

.bar { height: 4px; background: var(--ink); border-radius: 2px; overflow: hidden; margin-top: 10px; }
.bar div { height: 100%; background: var(--brass-dim); }

.note { color: var(--red); font-size: 12.5px; margin: 9px 0 0; }
.prereq-link { display: block; margin: 9px 0 0; padding: 3px 0; min-height: 40px;
  border: 0; background: none; color: var(--brass); text-align: left; font-size: 13px; }
.prereq-link:hover { text-decoration: underline; }
.rule { margin: 11px 0 0; padding-top: 9px; border-top: 1px dotted var(--rule); font-size: 11.5px; color: var(--cream-dim); font-style: italic; }
.empty { color: var(--cream-dim); font-style: italic; font-size: 13.5px; margin: 0; }

.inc {
  display: grid;
  grid-template-columns: 22px 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 7px 0;
  border-bottom: 1px dotted var(--rule);
}
.inc:last-of-type { border-bottom: 0; }
.inc.idle .n { color: var(--cream-dim); }
.inc .n { font-size: 13.5px; }
.inc .s { display: block; font-size: 11.5px; color: var(--cream-dim); }
.inc .s.warn { color: var(--red-bright); }
.inc .a { font-family: var(--display); font-size: 14px; font-variant-numeric: tabular-nums; color: var(--green); }
.inc .a.none { color: var(--cream-dim); }

.wire-entry {
  display: grid;
  grid-template-columns: 52px 1fr;
  gap: 8px;
  padding: 6px 0;
  border-bottom: 1px dotted var(--rule);
  font-size: 12.5px;
}
.wire-entry:last-child { border-bottom: 0; }
.wire-entry .t { font-family: var(--display); font-size: 10.5px; color: var(--cream-dim); font-variant-numeric: tabular-nums; }
.wire-entry.raid-bureau, .wire-entry.padlock, .wire-entry.heat-up { color: var(--red-bright); }
.wire-entry.warning { color: var(--brass); }
.wire-entry.heat-down, .wire-entry.bribe, .wire-entry.build { color: var(--green); }
.wire-entry.rush { color: #d8a0a0; }
.wire-entry [data-report-seq] { grid-column: 2; justify-self: start; min-height: 34px; }
.sheet[data-panel="neighborhood"] .actions { flex-wrap: wrap; }
.sheet[data-panel="neighborhood"] .actions button { min-width: 125px; }

/* ----------------------------------------------------------------- crews */

.crew, .target {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px dotted var(--rule);
}
.crew-n, .target-n { flex: 1 1 auto; min-width: 0; }
.crew-n .n, .target-n .n { font-size: 14px; display: block; }
.crew-n .s, .target-n .s {
  display: block;
  font-size: 11.5px;
  color: var(--cream-dim);
}
.crew-c {
  font-family: var(--display);
  font-size: 18px;
  font-variant-numeric: tabular-nums;
  color: var(--brass);
  min-width: 46px;
  text-align: right;
}
.crew button { min-width: 104px; padding: 6px 8px; line-height: 1.25; }
.crew button small, .target .s { font-size: 10.5px; }
.crew:not(.march) { display: grid; grid-template-columns: minmax(0, 1fr) minmax(116px, 0.72fr); }
.crew:not(.march) > button { min-width: 0; }
.crew-counts { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; text-align: center;
  font: 600 16px var(--display); color: var(--brass); font-variant-numeric: tabular-nums; }
.crew-count-head { display: grid; grid-template-columns: minmax(0, 1fr) repeat(2, minmax(58px, 0.36fr));
  gap: 4px; font: 11px var(--display); color: var(--cream-dim); text-align: center; }
.crew-slider { min-width: 0; }
.yard-progress { border: 1px solid var(--brass-dim); padding: 10px; margin-bottom: 12px;
  display: grid; gap: 3px; }
.yard-progress span { color: var(--cream-dim); }
.yard-progress button { margin-top: 6px; }

.crew.march .n { color: var(--brass); }
.building-training { border-top: 1px solid var(--rule); margin-top: 14px; padding-top: 10px; }
.building-training h3 { margin: 0 0 7px; font-size: 14px; color: var(--brass); }
.dispatch-confirm { padding: 9px 11px; margin: 0 0 12px; border: 1px solid var(--brass-dim);
  color: var(--brass); background: var(--panel-2); font: 13px var(--display); }

.send {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 0;
  border-bottom: 1px dotted var(--rule);
}
.send .crew-n { flex: 1 1 auto; }
.send button {
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  font-size: 19px;
  line-height: 1;
}
.send .crew-c { min-width: 52px; }

/* --------------------------------------------------- the Yard's upgrades */

.chips {
  display: flex;
  gap: 6px;
  align-items: center;
  margin: 0 0 10px;
  font-size: 11.5px;
  color: var(--cream-dim);
}
.chip { min-height: 34px; padding: 4px 10px; font-size: 12px; flex: 1 1 auto; }
.chip.tier { flex: 0 0 auto; min-width: 34px; padding: 4px 6px; }
.chip.done { color: var(--green); border-color: var(--green); }
.chips .hint { margin-left: auto; font-style: italic; white-space: nowrap; }

.node {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 5px 0;
  border-bottom: 1px dotted var(--rule);
}
.node:last-of-type { border-bottom: 0; }
.node .crew-n { flex: 1 1 auto; min-width: 0; }
.node.shut .n, .node.shut .s { color: var(--cream-dim); opacity: 0.75; }
.node button { min-width: 108px; padding: 5px 8px; line-height: 1.2; }
.node button small { font-size: 10.5px; }

.pips { display: inline-flex; gap: 3px; margin-left: 6px; vertical-align: 2px; }
.pips i { width: 14px; height: 4px; border-radius: 2px; background: var(--rule); }
.pips i.on { background: var(--brass); }

/* A 25-node tree is a lot of rows for a 667pt screen. Rather than letting the
   panel scroll — the one thing this UI does not do — it tightens up on short
   screens: smaller rows, no explainer, and the chips share a line. */
@media (max-height: 720px) {
  /* The sheet may also take more of a short screen: there is no town worth
     looking at behind a panel you are reading. */
  .sheet { max-height: calc(100% - 56px); }
  .node { padding: 2px 0; }
  .node .n { font-size: 13px; }
  .node .s { font-size: 10.5px; }
  .node button { min-height: 38px; min-width: 84px; font-size: 11.5px; }
  .chips { margin-bottom: 6px; }
  .chip { min-height: 30px; }
  .sheet-body .rule { display: none; }
  .sheet-body { padding: 8px 14px 10px; }
  .blurb { margin-bottom: 7px; }
  /* The testing panel is the tallest sheet in the game — three button rows,
     three readouts and a wipe — and it is the one the owner opens on a phone. */
  .actions, button.wide { margin-top: 8px; }
  .sheet[data-panel="testing"] { max-height: calc(100% - 12px); }
}
@media (min-width: 720px) {
  .sheet[data-panel="testing"] { max-height: 92%; }
}

.target { cursor: pointer; }
.target:hover .n { color: var(--brass); }
.target-v { text-align: right; }
.target-v .a {
  display: block;
  font-family: var(--display);
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  color: var(--red-bright);
}
.target-v .s.up { color: var(--green); }
.target-v .s.warn { color: var(--red-bright); }

.toast.raid-won { border-left-color: var(--green); color: var(--green); }
.toast.raid-lost { border-left-color: var(--red); color: var(--red-bright); }
.wire-entry.raid-won, .wire-entry.train { color: var(--green); }
.wire-entry.raid-lost { color: var(--red-bright); }

/* ----------------------------------------------------------------- smoke */

/* Chimney smoke is drawn by facades.js; it is animated here so it stays a
   style decision, and so reduced-motion turns it off without touching markup. */
.smoke circle {
  animation: smoke-drift 7s ease-in-out infinite;
  transform-box: fill-box;
  transform-origin: center;
}

@keyframes smoke-drift {
  0%   { transform: translate(0, 0) scale(0.6); opacity: 0; }
  30%  { opacity: 1; }
  100% { transform: translate(9px, -26px) scale(1.5); opacity: 0; }
}

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

/* ---------------------------------------------------------------- toasts */

/* Crews on the road, over the block. A march is the only thing in the game
   that happens to you while you are looking somewhere else, so it does not
   live behind a tab. */
.marches {
  position: absolute;
  left: 10px;
  bottom: 10px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  pointer-events: none;
  max-width: calc(100% - 20px);
}
.marches .m {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 9px;
  border-radius: 999px;
  font: 500 11px/1 var(--display);
  letter-spacing: .02em;
  background: color-mix(in srgb, var(--panel) 92%, transparent);
  color: var(--cream);
  border: 1px solid var(--rule);
  box-shadow: 0 2px 8px rgb(0 0 0 / .25);
}
.marches .m.back { border-color: var(--green); color: var(--green); }
.marches .m.incoming {
  border-color: var(--red-bright);
  color: var(--red-bright);
  animation: incoming 1.6s ease-in-out infinite;
}
@keyframes incoming {
  50% { border-color: var(--red); box-shadow: 0 0 0 3px color-mix(in srgb, var(--red) 25%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .marches .m.incoming { animation: none; }
}
.marches .m.scout { color: var(--cream-dim); }
.marches .m b { font-weight: 600; }

.toasts {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: min(90%, 420px);
  bottom: 18px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  pointer-events: none;
}
.toast {
  align-self: flex-start;
  max-width: 100%;
  background: rgba(17, 22, 18, 0.94);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--brass-dim);
  border-radius: 3px;
  padding: 7px 11px;
  font-size: 12.5px;
  animation: toast-in .25s ease-out;
}
.toast.leaving { opacity: 0; transition: opacity .6s linear; }
.toast.raid-bureau, .toast.padlock { border-left-color: var(--red); color: var(--red-bright); }
.toast.warning, .toast.heat-up { border-left-color: var(--brass); color: var(--brass); }
.toast.collect { border-left-color: var(--green); }
.collect-panel { margin: 10px 0; padding: 8px 10px 10px; border: 1px solid var(--brass-dim); border-radius: 4px; }
.collect-panel.is-full { border-color: var(--red); }
.collect-panel .v { display: flex; gap: 6px; justify-content: flex-end; }
@keyframes toast-in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  *, .ready, .toast, .sheet { animation: none !important; transition: none !important; }
}

/* -------------------------------------------------- street-level redesign */
:root {
  --ink: #111b1c;
  --ink-2: #23201d;
  --panel: #24211e;
  --panel-2: #302c27;
  --rule: #504942;
  --brass: #e7bf72;
  --brass-dim: #a88248;
  --cream: #f7ebd1;
  --cream-dim: #c0b9a8;
  --green: #a0c598;
  --sky: #233637;
}
body { background: #101c1d; }
.dash {
  background: linear-gradient(160deg, #2e2a25 0%, #1e1c19 74%);
  border-bottom: 1px solid #b69760;
  box-shadow: 0 4px 22px #0b1417a6;
  z-index: 7;
}
.cell { border-color: #ffffff18; }
.cell .k { color: #c9b891; }
.cell .v { color: #f6e4be; text-shadow: 0 1px 8px #0008; }
.cell .r { color: #b4d1a2; }
.cell.dirty .v { color: #deb0a0; }
.cell.chips .v { color: #e7c485; }
.town {
  background: radial-gradient(ellipse at 55% 52%, #46524a, #1d3030 60%, #0d1a1d 100%);
}
.town::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  background: linear-gradient(180deg, #11212a50, transparent 23%, transparent 78%, #101d20ad);
}
.town::after { z-index: 1; }
#base { filter: saturate(1.19) contrast(1.08); }
.district-mark {
  position: absolute;
  top: 16px;
  left: 17px;
  z-index: 2;
  display: grid;
  gap: 1px;
  pointer-events: none;
  text-shadow: 0 2px 9px #091312, 0 0 18px #091312;
}
.district-kicker { color: #f2c881; font: 600 10px var(--display); letter-spacing: .28em; }
.district-mark strong { color: #f7ead3; font: 600 23px/.98 var(--display); letter-spacing: .08em; }
.district-era { color: #dfd1b4; font: 500 9px var(--display); letter-spacing: .12em; }
.district-era i { display: inline-block; width: 3px; height: 3px; border-radius: 50%; background: #d9ad66; vertical-align: 2px; margin: 0 4px; }
.street-car { filter: drop-shadow(0 1px 2px #0009); }
.street-walker { filter: drop-shadow(0 2px 2px #000b); }
.plot-label { fill: #f2d49b; stroke: #12201e; font-size: 10px; font-weight: 600; letter-spacing: .035em; }
.plot-empty circle { filter: drop-shadow(0 0 6px #d9a85999); }
.plot.selected { filter: drop-shadow(0 0 5px #e4b86377); }
.lvl { fill: #f1cd87; font-weight: 600; }
.prog-text { fill: #f6e0b3; }
.recenter { z-index: 3; width: 42px; height: 42px; border: 1px solid #b89963; border-radius: 50%; color: #ead0a0; background: #141b1ce8; box-shadow: 0 4px 15px #0008; }
.marches, .toasts { z-index: 3; }
.tabs { z-index: 7; background: linear-gradient(#302c27, #1e1c19); border-top: 1px solid #ab8b53; box-shadow: 0 -5px 20px #1019189c; }
.tab { color: #dfd0b0; border-color: #ffffff19; font-size: 9px; letter-spacing: .08em; }
.tab svg { width: 23px; height: 23px; }
.tab[aria-selected="true"] { color: #ffda90; background: linear-gradient(#c29b4933, transparent); box-shadow: inset 0 3px #d5aa62; }
.sheet { background: linear-gradient(155deg, #332e29 0%, #23201d 48%, #1f1d1a 100%); border-top: 2px solid #c8a361; box-shadow: 0 -22px 60px #0a0908dd; }
.sheet-head { background: linear-gradient(120deg, #433d37, #2d2924); padding: 13px 17px; border-bottom-color: #a2804c7d; }
.sheet-head h2 { color: #f2d596; font-size: 15px; font-weight: 600; letter-spacing: .13em; }
.sheet-close { color: #f6dfb8; border: 1px solid #a58c62; border-radius: 50%; width: 36px; height: 36px; }
.sheet-body { padding: 19px 18px 24px; overflow-y: auto; }
.blurb { color: #e4d6bd; font-size: 16px; line-height: 1.44; }
.row { border-bottom: 1px solid #af97724a; padding: 11px 0; font-size: 15px; }
.row .k { color: #c6b89e; }
.row .v { color: #f5e8d1; }
button { border-radius: 5px; border-color: #8f7955; background: #403b35; color: #f4e4c6; font-weight: 600; }
button:hover:not(:disabled) { background: #4b453e; }
button.primary, #upgrade-btn:not(:disabled), #opening-action { background: linear-gradient(180deg, #efca80, #c89a4d); border: 1px solid #f6d491; color: #221f1b; box-shadow: inset 0 1px #ffebb9, 0 4px 14px #040b0a6b; }
button.primary:hover:not(:disabled), #upgrade-btn:hover:not(:disabled), #opening-action:hover { color: #181614; background: #f5d594; }
button:disabled { opacity: .55; }
.bar { height: 7px; background: #141311; }
.bar div { background: linear-gradient(90deg, #947449, #edc879); }
.crew, .target { border-bottom-color: #8e86664d; padding: 13px 0; }
.crew-counts { color: #f1c879; }
.crew-slider input, .send-slider input { height: 28px; accent-color: #e5b564; }
.prereq-link { border-bottom: 1px solid #a38453; border-radius: 0; color: #efc980; }

@media (max-width: 680px) {
  .dash-main { grid-template-columns: minmax(0, 1fr) minmax(0, .85fr) 82px; }
  .dash .cell { padding: 5px 8px; }
  .dash-main .cell .v, .heat-num { font-size: 17px; }
  .dash-main .cell .r { font-size: 10px; }
  .cell.heat .k { display: block; }
  .heat-top { align-items: center; }
  .heat-tier { font-size: 8px; }
  .heat-bar { height: 4px; margin-top: 1px; }
  .dash-sub .cell { padding: 4px 5px; }
  .dash-sub .cell .v { font-size: 13px; }
  .dash-sub .cell .r { display: none; }
  .dash-sub .cell .k { font-size: 8px; letter-spacing: .06em; }
  .dash-sub { min-height: 35px; }
  .opening-card {
    position: fixed;
    left: 12px;
    right: 12px;
    bottom: calc(var(--tabs-h) + var(--safe-bottom) + 16px);
    width: auto;
    z-index: 6;
    padding: 12px 14px;
    gap: 2px 11px;
    background: linear-gradient(135deg, #332f2aea, #1c1916ee);
    border: 1px solid #dab269;
    border-left: 4px solid #edbf6b;
    border-radius: 7px;
    box-shadow: 0 10px 25px #0d0c0ae0, inset 0 1px #ffffff26;
    backdrop-filter: blur(8px);
  }
  .opening-card .opening-eyebrow { font-size: 9px; letter-spacing: .19em; }
  .opening-card strong { font-size: 17px; line-height: 1.13; color: #ffecc7; }
  .opening-card .opening-detail { display: block; grid-column: 1 / -1; grid-row: 3; color: #ddcfaf; font-size: 12px; line-height: 1.25; margin-top: 4px; }
  .opening-card button { grid-column: 2; grid-row: 1 / span 2; align-self: center; max-width: 145px; white-space: normal; padding: 9px 11px; text-align: center; line-height: 1.15; font-size: 11px; min-height: 44px; }
  .district-mark { top: 17px; left: 17px; }
  .district-mark strong { font-size: 20px; }
  .recenter { bottom: 152px; right: 14px; }
  .sheet { max-height: calc(100dvh - 34px); border-radius: 14px 14px 0 0; }
  .sheet-head { padding: 12px 16px; }
  .sheet-body { padding: 17px 17px 28px; }
  .tabs .tab { min-height: 59px; padding: 7px 1px; }
  .tabs .tab svg { width: 22px; height: 22px; }
  .toasts { top: auto; bottom: 18px; }
}
@media (max-width: 365px) {
  .opening-card { left: 8px; right: 8px; padding: 10px; }
  .opening-card strong { font-size: 15px; }
  .opening-card button { max-width: 112px; font-size: 10px; }
  .district-era { font-size: 8px; }
}
@media (max-width: 365px) and (max-height: 620px) {
  .opening-card { padding: 7px 9px; bottom: calc(var(--tabs-h) + var(--safe-bottom) + 8px); }
  .opening-card .opening-detail { display: none; }
  .opening-card strong { font-size: 14px; }
  .recenter { bottom: 116px; }
}
@media (prefers-reduced-motion: reduce) {
  .street-life { display: none; }
  .opening-card { backdrop-filter: none; }
}

.city-horizon { position: absolute; top: 0; left: 0; width: 100%; height: min(47%, 360px); pointer-events: none; z-index: 1; opacity: .92; }
.horizon-cloud { animation: cloud-pass 34s linear infinite alternate; }
.neon-glow { filter: drop-shadow(0 0 5px #e8a14b); animation: neon-breathe 5s ease-in-out infinite; }
@keyframes cloud-pass { to { transform: translateX(35px); } }
@keyframes neon-breathe { 50% { opacity: .58; filter: drop-shadow(0 0 2px #e8a14b); } }
@media (prefers-reduced-motion: reduce) { .horizon-cloud, .neon-glow { animation: none; } }

.building-hero {
  position: relative;
  height: 172px;
  margin: -19px -18px 17px;
  overflow: hidden;
  background: radial-gradient(ellipse at 50% 85%, #b38a5247 0%, #433d3655 36%, #142425 77%),
    repeating-linear-gradient(120deg, transparent, transparent 19px, #ffffff06 20px, transparent 21px);
  border-bottom: 1px solid #b79862;
}
.building-hero::before, .building-hero::after { content: ''; position: absolute; width: 25px; height: 25px; border-color: #be9a60; border-style: solid; opacity: .72; }
.building-hero::before { left: 11px; top: 11px; border-width: 1px 0 0 1px; }
.building-hero::after { right: 11px; top: 11px; border-width: 1px 1px 0 0; }
.building-portrait { display: block; width: 100%; height: 142px; margin: 3px 0 0; overflow: visible; filter: drop-shadow(0 9px 8px #0c0b09c7) saturate(1.2); }
.building-hero.new .building-portrait { opacity: .68; }
.building-hero-caption { position: absolute; left: 15px; right: 15px; bottom: 7px; display: flex; gap: 8px; justify-content: space-between; align-items: baseline; padding: 7px 11px; background: #191715d9; border: 1px solid #ae8d5b87; }
.building-hero-caption span { color: #e2be7c; font: 500 9px var(--display); letter-spacing: .13em; text-transform: uppercase; }
.building-hero-caption strong { color: #fff0ca; font: 600 15px var(--display); text-align: right; }
.sheet[data-panel="story"] .story-lead { color: #ffe6b6; font-size: 22px; line-height: 1.32; padding: 15px; border: 1px solid #a9855073; background: #332f2a; }
.sheet[data-panel="story"] .sheet-body { background: radial-gradient(ellipse at 50% 0%, #63543b52, transparent 64%); }
.rival-quote { margin: 16px 0; padding: 14px 16px; border-left: 3px solid #d1a45f; background: #201d1a; color: #f2dec0; }
.character-card { display:flex; align-items:center; gap:16px; margin:0 0 20px; padding:12px; background:linear-gradient(125deg,#3b3630,#1f1d1a); border:1px solid #b38d50; border-radius:5px; }
.character-card img { width:112px; height:112px; flex:0 0 112px; object-fit:cover; border:1px solid #d3ae6b; border-radius:3px; }
.character-card > div { display:grid; gap:6px; min-width:0; }
.character-card strong { color:#ffe4aa; font:600 24px/1.1 var(--display); }
.character-card span { color:#d5c7a9; font-size:14px; line-height:1.3; }
.character-card .character-kicker { color:#d8ad67; font-size:12px; letter-spacing:.08em; text-transform:uppercase; }
.character-thumb { width:56px; height:56px; flex:0 0 56px; object-fit:cover; border:1px solid #b38d50; border-radius:4px; }
.target:has(.character-thumb) { gap:10px; }
.world-character { pointer-events:none; }
.world-character rect { fill:#c4a269; stroke:#101c17; stroke-width:3; }
@media (max-width:360px) { .character-card { gap:12px; padding:9px; } .character-card img { width:88px; height:88px; flex-basis:88px; } .character-card strong { font-size:21px; } .character-thumb { width:44px; height:44px; flex-basis:44px; } }
.rival-quote strong { display: block; color: #e9bc73; font: 600 15px var(--display); text-transform: uppercase; letter-spacing: .1em; margin-bottom: 7px; }
.rival-quote span { display: block; font: italic 19px/1.4 'Crimson Pro', serif; }
.story-next,.rival-style { margin: 14px 0; padding: 11px 14px; border: 1px solid #bd985d78; background: #332e29; color: #f6dfa7; font-size: 15px; line-height: 1.4; }
.raid-theater { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px; min-height: 152px; margin: -16px -16px 18px; border-bottom: 3px solid #e2be78; background: radial-gradient(circle at 50% 100%, #b38b3d81, transparent 60%), linear-gradient(145deg,#35312c,#191714); color: #e8cf9b; text-align: center; animation: report-arrive .35s ease-out both; }
.raid-theater.defeat { border-color: #a86358; background: radial-gradient(circle at 50% 100%, #81352b91, transparent 60%), linear-gradient(145deg,#302626,#191714); }
.raid-theater span { font: 600 12px var(--display); letter-spacing: .2em; }
.raid-theater strong { font: 700 clamp(28px, 7vw, 40px) var(--display); color: #ffedc4; letter-spacing: .035em; }
.raid-temptation { display: grid; gap: 6px; margin: 15px 0; padding: 16px; border: 1px solid #c29953; background: linear-gradient(145deg,#403a34,#26231f); }
.raid-temptation > span { font: 600 12px var(--display); letter-spacing: .14em; color: #e2bd78; }
.raid-temptation strong { color: #ffe3a3; font-size: 20px; }
.raid-temptation small { color: #e7c9a3; font-size: 14px; }
@keyframes report-arrive { from { opacity: 0; transform: scale(.96) translateY(12px); } to { opacity: 1; transform: scale(1) translateY(0); } }
@media (prefers-reduced-motion:reduce) { .raid-theater { animation: none; } }
@media (max-width: 680px) {
  .building-hero { margin: -17px -17px 15px; height: 156px; }
  .building-portrait { height: 130px; }
  .building-hero-caption strong { font-size: 14px; }
}

@media (max-width: 680px) {
  .sheet[data-panel="building"] #upgrade-btn,
  .sheet[data-panel="building"] #rush-btn {
    position: sticky;
    bottom: 1px;
    z-index: 2;
    box-shadow: 0 -8px 20px #141b1cd9, inset 0 1px #ffebb9;
  }
  .sheet[data-panel="testing"] .sheet-body { overflow-y: auto; }
}

.hammer-arm { transform-box: fill-box; transform-origin: 20% 85%; animation: hammer-swing .8s ease-in-out infinite alternate; }
.work-dust { animation: dust-lift 1.3s ease-out infinite; }
@keyframes hammer-swing { to { transform: rotate(-37deg); } }
@keyframes dust-lift { 0% { opacity: 0; transform: translateY(3px); } 35% { opacity: .8; } 100% { opacity: 0; transform: translate(6px, -11px); } }
@media (prefers-reduced-motion: reduce) { .hammer-arm, .work-dust { animation: none; } }

.city-horizon {
  height: 100%;
  background: url('./assets/skyline-1926.webp') center 62% / cover no-repeat;
  -webkit-mask-image: none;
  mask-image: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity .42s ease, visibility 0s linear .42s;
}
.district-mark { opacity: 0; visibility: hidden; transition: opacity .35s ease, visibility 0s linear .35s; }
.town.intro-splash .city-horizon { z-index: 5; opacity: .96; visibility: visible; transition-delay: 0s; }
.town.intro-splash .district-mark {
  z-index: 6;
  top: 10%;
  left: 7%;
  opacity: 1;
  visibility: visible;
  transition-delay: 0s;
}
.town.intro-splash .district-kicker { font-size: 12px; }
.town.intro-splash .district-mark strong { font-size: clamp(32px, 10vw, 56px); }
.town.intro-splash .district-era { font-size: 11px; }
.town.intro-splash #base, .town.intro-splash .recenter,
.town.intro-splash .marches, .town.intro-splash .toasts { opacity: 0; }
.town #base, .town .recenter, .town .marches, .town .toasts { transition: opacity .35s ease; }
.town.splash-leaving .city-horizon, .town.splash-leaving .district-mark { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .city-horizon, .district-mark, .town #base, .town .recenter, .town .marches, .town .toasts { transition: none; }
}

/* Compact, readable dialogs with room to see the block around them. */
.sheet { width: min(88vw, 460px); padding-bottom: 0; border: 1px solid #c8a361; border-radius: 12px; }
.sheet-head { padding: 8px 11px; gap: 8px; flex-shrink: 0; border-radius: 11px 11px 0 0; }
.sheet-heading { display: flex; align-items: center; gap: 10px; min-width: 0; flex: 1; }
.sheet-head h2 { font-size: 17px; letter-spacing: .08em; overflow-wrap: anywhere; }
.sheet-subtitle { font-size: 16px; line-height: 1.2; color: #e4d6bd; font-style: italic; }
.sheet-subtitle:not([hidden]) { flex: 1; min-width: 0; }
.sheet-close { flex: 0 0 40px; width: 40px; min-height: 40px; font-size: 26px; }
.sheet-body { padding: 10px 12px 12px; font-size: 17px; line-height: 1.3; }
.sheet-body > .header-description { display: none; }
.sheet-body .row { padding: 6px 0; font-size: 17px; gap: 10px; }
.sheet-body .row .k, .sheet-body .row .v { min-width: 0; overflow-wrap: break-word; }
.sheet-body .blurb { font-size: 17px; line-height: 1.3; margin-bottom: 8px; }
.sheet-body .rule { display: block; margin-top: 7px; padding-top: 7px; font-size: 15px; line-height: 1.3; }
.sheet-body .actions { margin-top: 9px; gap: 8px; }
.sheet-body button { font-size: 16px; line-height: 1.2; padding: 9px 8px; }
.sheet-body button small { font-size: 14px; }
.sheet-body .note, .sheet-body .empty { font-size: 16px; }
.sheet-body .crew, .sheet-body .target { padding: 8px 0; }
@media (max-width: 719px) {
  .sheet { left: 6vw; right: auto; bottom: calc(var(--safe-bottom) + 12px); max-height: calc(88dvh - var(--safe-bottom)); }
}

[data-resource] { cursor: pointer; }
[data-resource]:focus-visible { outline: 2px solid var(--brass); outline-offset: -2px; }
.income-total { font-weight: 700; border-top: 2px solid var(--brass); }
.income-contribution .v.up { color: var(--green); }
.income-contribution .v.warn { color: var(--red-bright); }
.building-introduction { margin: 0 0 10px; font-size: 18px; line-height: 1.4; color: #f2e5cd; }
.opening-card .opening-eyebrow { font-size: 12px; letter-spacing: .1em; }
.opening-card .opening-detail { font-size: 15px; line-height: 1.3; }
.opening-card button { font-size: 15px; min-height: 44px; }
@media (max-width: 680px) {
  .opening-card { gap: 4px 10px; padding: 10px 12px; }
  .opening-card strong { font-size: 18px; }
  .opening-card button { max-width: 145px; font-size: 15px; padding: 8px 10px; }
  .opening-card .opening-detail { display: block; margin-top: 2px; }
  .recenter { bottom: 180px; }
}
@media (max-width: 365px) {
  .opening-card { grid-template-columns: minmax(0, 1fr) 112px; padding: 8px; }
  .opening-card strong { font-size: 17px; }
  .opening-card button { font-size: 14px; }
  .opening-card .opening-detail { font-size: 14px; }
}

/* Gothic Animation: painted masonry, worn brass and warm street light. */
.gothic-building { filter: drop-shadow(0 4px 3px #080c0ec0); }
.gothic-building.shuttered { filter: grayscale(.8) brightness(.55); }
.steam { fill: #bec5c0; opacity: 0; animation: chimney-drift 4s ease-out infinite; }
@keyframes chimney-drift { 15% { opacity: .3; } to { transform: translate(-12px,-34px) scale(2.4); opacity: 0; } }
.walk-leg { animation: walking-step .85s ease-in-out infinite alternate; }
.walk-leg.rear { animation-delay: -.85s; }
.walk-arm { animation: walking-arm .85s ease-in-out infinite alternate; }
.walking-body { animation: walking-bob .85s ease-in-out infinite; }
@keyframes walking-step { from { transform: rotate(-24deg); } to { transform: rotate(24deg); } }
@keyframes walking-arm { from { transform: rotate(27deg); } to { transform: rotate(-27deg); } }
@keyframes walking-bob { 50% { transform: translateY(-.6px); } }
.building-hero .gothic-building { filter: drop-shadow(0 6px 5px #0008); }
.building-hero:has(.build-progress) .building-hero-caption { bottom: 43px; }
.build-progress { position: absolute; bottom: 7px; left: 15px; right: 15px; height: 32px; border: 1px solid #d6ac64; border-radius: 4px; background: #171512ed; overflow: hidden; }
/* Eased, because the width is now written once a frame rather than baked into
 * a rebuilt string -- so it can glide between readings instead of stepping. */
.build-progress-fill { height: 100%; background: linear-gradient(90deg,#75603b,#b18b49); transition: width .25s linear; }
/* Inline flow, not grid. As a grid container every run of text became its own
 * row, so "1m 31s" stacked four rows deep in a 32px box and showed "1". */
.build-progress strong { position: absolute; inset: 0; display: block; line-height: 30px; text-align: center; font: 700 20px/30px var(--display); color: #fff4d7; text-shadow: 0 1px 3px #000,0 0 3px #000; font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (prefers-reduced-motion: reduce) { .build-progress-fill { transition: none; } }
.build-action { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 10px; }
.build-action button { min-height: 44px; padding: 7px 18px; }
.build-action small { display: block; font-size: 13px; }
.training-cost { grid-column: 1 / -1; padding: 8px 10px; border: 1px solid #a0824e80; background: #181613; color: #efd39e; font: 16px var(--display); }
.crew .crew-slider { grid-column: 1 / -1; display: block; font: 600 17px var(--display); color: #f4e5c9; }
.crew-slider > span { display: block; white-space: nowrap; }
.crew-slider input { display: block; margin: 5px 0; }
.training-action { grid-column: 1 / -1; display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.training-action > span { font: 14px/1.4 var(--display); color: var(--cream-dim); }
.training-action small { display: block; font-size: 15px; color: var(--cream); }
.crew .training-action button { min-width: 76px; min-height: 44px; font-size: 17px; }
.marches { left: 8px; top: 10px; bottom: auto; display: block; width: 190px; max-width: 54%; pointer-events: auto; border: 1px solid #a98b55; border-radius: 5px; background: #0c1314ed; box-shadow: 0 3px 12px #0008; overflow: hidden; }
#march-toggle { display: flex; width: 100%; align-items: center; justify-content: space-between; gap: 6px; min-height: 44px; padding: 6px 9px; border: 0; font: 600 13px var(--display); color: #f0d397; background: linear-gradient(#3e3933,#24211d); }
#march-list { padding: 5px; }
#march-list[hidden] { display: none; }
.marches .m { border-radius: 2px; display: flex; justify-content: space-between; padding: 7px 4px; margin-bottom: 4px; font-size: 12px; line-height: 1.35; box-shadow: none; }
.marches .m strong { display: block; font-size: 17px; font-variant-numeric: tabular-nums; }
.marches .m button { padding: 4px; min-height: 44px; font-size: 12px; }
.march-empty { font: 12px var(--display); color: #b5b79d; padding: 2px 4px; margin: 3px; }
@media (prefers-reduced-motion: reduce) { .steam, .walk-leg, .walk-arm, .walking-body { animation: none; } .street-life { display: none; } }
.marches[hidden] { display: none; }
.marches.minimized { width: 166px; }
.build-action { margin-top: 0; min-height: 44px; }
.build-action + .rule { margin: 6px 0 0; padding: 0; border: 0; font-size: 14px; line-height: 1.25; }
.building-actions { min-height: 110px; }

/*
 * The cost and the button that spends it, pinned to the bottom of the panel.
 *
 * Without this they render in document order, after the comparison rows and
 * the Mansion's support-milestone list, and on a phone that puts them off the
 * end of the sheet: measured at y=714 on an iPhone 13's 664px viewport and
 * y=729 on an SE's 568px. The body scrolls, so the button was reachable — but
 * only by a player who thinks to flick a panel whose visible content looks
 * complete. A playtest that taps where the button says it is spent 21 taps and
 * 63 seconds on "Upgrade to level 2" with the Mansion still at level 1.
 *
 * Sticky rather than a separate footer element so the action keeps its place
 * in the reading order and scrolls into the flow once the player has read past
 * it. `.building-tabs` is already sticky at the foot of this same scrollport,
 * so when a hall shows its tab bar the action sits on top of it instead of
 * underneath.
 */
.building-actions {
  position: sticky;
  bottom: 0;
  z-index: 3;
  padding-top: 10px;
  background: linear-gradient(#1f1d1a00 0, #1f1d1a 10px);
  border-top: 1px solid #9d835055;
}
.building-actions.with-tabs { bottom: 46px; }

/* Issues 16-26: compact queues, explicit comparisons and focused crew controls. */
.queue-dock { position:absolute; top:8px; left:8px; z-index:4; display:flex; flex-direction:column; align-items:flex-start; gap:6px; max-width:calc(100% - 16px); pointer-events:none; }
.queue-dock .marches, .build-queues { position:static; width:210px; max-width:100%; background:#0c1314f5; border:1px solid #ad905a; border-radius:5px; pointer-events:auto; box-shadow:0 3px 12px #0008; overflow:hidden; }
.queue-dock .minimized { width:58px; }
/* Waiting for the player, opened when they choose (app.js `renderNotices`). */
.notices { position:absolute; top:8px; right:8px; z-index:4; display:flex; flex-direction:column; align-items:flex-end; gap:6px; max-width:min(240px, calc(100% - 90px)); }
.notices[hidden] { display:none; }
.raid-risk .raid-losses { display:block; margin-top:3px; font-size:13px; color:var(--cream-dim); }
.notice { display:grid; gap:1px; text-align:left; padding:7px 11px; min-height:44px; border:1px solid #f0c264; border-radius:6px; background:linear-gradient(180deg,#3a1d12f2,#22110bf2); color:#fff3e4; box-shadow:0 3px 12px #000a; animation:notice-in .35s ease-out; }
.notice b { font:700 13px var(--hud-face, system-ui); letter-spacing:.06em; text-transform:uppercase; color:#ffd98a; }
.notice span { font-size:12px; color:#f3e2c0; }
@keyframes notice-in { from { transform:translateX(16px); opacity:0; } to { transform:none; opacity:1; } }
.queue-toggle { width:100%; display:flex; align-items:center; justify-content:space-between; gap:6px; padding:7px; min-height:48px; border:0; color:#ffe0a1; font:600 14px var(--display); }
.queue-toggle svg { width:25px; height:25px; flex-shrink:0; }
.minimized .queue-toggle { width:56px; height:56px; min-height:56px; flex-direction:column; justify-content:center; gap:0; padding:3px; }
.minimized .queue-name { display:none; }
.minimized .queue-toggle b { font-size:13px; line-height:18px; }
#build-list { padding:5px; }
#build-list[hidden] { display:none; }
.queue-build { display:grid; grid-template-columns:1fr auto; width:100%; gap:4px; padding:7px; margin:0 0 4px; text-align:left; font-size:12px; }
.queue-build progress { grid-column:1/-1; width:100%; height:7px; accent-color:#e4ba6b; }
.town.intro-splash .queue-dock { opacity:0; pointer-events:none; }
.comparison-head, .sheet-body .row.comparison { display:grid; grid-template-columns:minmax(0,1.3fr) minmax(0,1fr) minmax(0,1fr); gap:6px; }
.comparison-head { margin-top:8px; padding:4px 0; color:#d4b879; font:600 12px var(--display); }
.comparison-head span:not(:first-child), .comparison .v { text-align:right; }
.sheet-body .row.comparison { font-size:15px; }
.building-tabs { display:flex; position:sticky; bottom:-12px; margin:10px -12px -12px; background:#1d1b18; border-top:1px solid #9d8350; z-index:2; }
.building-tabs button { flex:1; min-height:46px; border:0; border-radius:0; }
.building-tabs [aria-pressed="true"] { background:#d6ad60; color:#201e1b; }
.crew-stats { display:grid; gap:5px; margin:0 0 10px; font:16px var(--display); }
.crew-stats small { color:var(--cream-dim); font-size:13px; }
.sheet:is([data-panel="raid"], [data-panel="crew-selection"]) .send { display:block; padding:8px 0; }
.send-heading { display:flex; align-items:center; justify-content:space-between; gap:8px; font-size:16px; }
.send-heading label { white-space:nowrap; color:var(--cream-dim); }
.send-heading input { width:76px; padding:7px 4px; border:1px solid #9e8456; border-radius:4px; color:var(--cream); background:#23201d; font:600 18px var(--display); text-align:center; }
.sheet:is([data-panel="raid"], [data-panel="crew-selection"]) input.send-slider { display:block; width:80%; min-width:0; margin:7px auto 0; height:30px; accent-color:var(--brass); }
.sheet-body .raid-footnote { font-size:17px; }
.queue-dock .marches.minimized { width:58px; }
.minimized #march-toggle { width:56px; height:56px; min-height:56px; flex-direction:column; justify-content:center; gap:0; padding:3px; }
.raid-intel { display:grid; gap:3px; padding:0 0 8px; font-size:16px; }
.raid-intel span { font-size:15px; color:var(--cream-dim); }
.sheet[data-panel="raid"] .row .k { flex:0 0 90px; overflow-wrap:normal; font-size:16px; }
.sheet[data-panel="raid"] .row .v { flex:1; font-size:16px; }

.building-actions.is-building { min-height:0; }

.opening-card[hidden] { display: none; }

/* City is a playable surface, not a dialog. */
.world-map[hidden] { display:none; }
.world-map { position:absolute; inset:0; z-index:4; background:#15221f; overflow:hidden; }
.world-heading { position:absolute; top:0; left:0; right:0; z-index:2; display:flex; align-items:center; justify-content:space-between; gap:12px; padding:12px 16px; background:linear-gradient(#101d1ff5,#101d1fbf,transparent); pointer-events:none; }
.world-heading span { font:12px var(--display); letter-spacing:.17em; color:#ddbc7b; }
.world-heading h2 { margin:0; color:#f4e7c8; font:600 26px var(--display); }
.world-heading button { pointer-events:auto; max-width:140px; font-size:14px; padding:8px 12px; min-height:44px; background:#141b1ced; }
/* `clip`, not just `hidden`: the map inside is drawn larger than this box, and a
   `hidden` box can still be scrolled by the browser -- focusing a marker past the
   edge would shift the whole map out from under the camera. Focus pans instead:
   see the `focusin` handler in world-map.js. */
.world-viewport { position:relative; width:100%; height:100%; touch-action:none; cursor:grab; overflow:hidden; overflow:clip; }
.world-viewport:active { cursor:grabbing; }
/* Drawn larger than the viewport and moved under it by a transform on a layer of
   its own, so a drag never repaints the map: see `render` in world-map.js. The
   width, height and transform are set there. */
.world-canvas { position:absolute; left:0; top:0; display:block; transform-origin:0 0; will-change:transform; }
.world-block { cursor:pointer; }
.world-boundary { fill:#62403740; stroke:#bb7956; stroke-width:2; }
.world-block.is-home .world-boundary { fill:#9b87353d; stroke:#e6c57a; }
/* A real account, not one of the five authored outfits. Cool against their
 * warm ochre, so "somebody is actually behind this block" reads at a glance. */
.world-block.is-player .world-boundary { fill:#3c5c6b47; stroke:#8fc3d4; }
.world-block.is-player .world-owner { fill:#8fc3d4; }
.world-block.scouted .world-boundary { fill:#a8753142; stroke:#e9c77c; }
.world-block.beaten .world-boundary { fill:#9b873580; stroke:#f5d274; stroke-width:4; }
.world-block.beaten .world-nameplate { stroke:#f5d274; stroke-width:3; }
.world-rumor { opacity:.57; }
.world-rumor circle { fill:#1c2926c9; stroke:#d2ac6c; stroke-width:2; stroke-dasharray:8 7; }
.world-rumor text { fill:#e5d5b4; font-family:Jost,sans-serif; }
.world-rumor .rumor-symbol { font-size:39px; font-weight:600; }
.world-rumor .rumor-name { font-size:21px; letter-spacing:2px; }
.world-rumor .rumor-clue { font-size:15px; }
.world-rumor.revealed { opacity:.9; }
.world-rumor.revealed circle { stroke-dasharray:none; }
.world-rumor.revealed .rumor-symbol { fill:#f1cb83; }
.world-block:hover .world-boundary,.world-block:focus .world-boundary { stroke:#fff0b6; stroke-width:5; }
.world-block:focus { outline:none; }
.world-nameplate { fill:#14221ff5; stroke:#a78653; stroke-width:1; }
.world-block text { fill:#f4e7cf; font:600 28px Jost,sans-serif; }
.world-block .world-owner { fill:#c9ab71; font:17px Jost,sans-serif; letter-spacing:2px; }
.world-hint { position:absolute; bottom:7px; left:12px; margin:0; font-size:14px; color:#e5d9bd; text-shadow:0 1px 3px #000; pointer-events:none; }
.world-routes path { fill:none; stroke:#e4c37a; stroke-width:3; stroke-dasharray:8 8; }
.world-routes circle { fill:#ffdfa1; stroke:#222; stroke-width:3; }
.world-rival-portrait { height:130px; background:radial-gradient(ellipse,#66705a55,transparent 70%); }
.world-rival-portrait svg { display:block; width:100%; height:100%; }
.view-world .opening-card,.view-world #recenter,.view-world .district-mark { display:none; }
.view-world .queue-dock { z-index:5; top:var(--world-heading-height, 180px); }
@media (prefers-reduced-motion:reduce) { .world-map .steam { animation:none; } }

.world-viewport { user-select:none; -webkit-user-select:none; }
.view-world #build-queues { display:none; }
.building-services { margin-top:16px; border-top:1px solid var(--brass-dim); }
.building-services h3 { font:600 20px var(--display); }
.covert-target { padding:10px 0; border-bottom:1px solid var(--brass-dim); }
.covert-target summary { cursor:pointer; font-size:17px; min-height:44px; }
.covert-job { display:grid; gap:6px; padding:12px 0; }
.covert-job p { margin:0; font-size:16px; }
.covert-job small { font-size:14px; }
.intel-card { display:grid; gap:5px; padding:10px 0; }
.world-routes path { stroke:#fff; opacity:.45; }

/* The Yard: one continuous blueprint, with inspectable locked tiles. */
.yard-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.yard-tabs button { flex: 1 0 27%; min-height: 44px; padding: 8px; font-size: 13px; }
.yard-guide { margin: 8px 0; font-size: 15px; line-height: 1.35; }
.yard-continue { width: 100%; min-height: 44px; font-size: 13px; }
.research-tier { scroll-margin-top: 8px; }
.research-tier h3 { display: flex; align-items: center; gap: 8px; font-size: 14px; margin: 16px 0 10px; color: var(--brass); }
.research-tier h3 span { border: 1px solid var(--brass-dim); padding: 3px 8px; }
.research-grid { display: grid; gap: 12px 8px; position: relative; }
.crew-grid { grid-template-columns: repeat(6, 1fr); }
.crew-grid .research-tile { grid-column: span 2; }
.crew-grid .research-tile:nth-of-type(4) { grid-column: 2 / span 2; }
.crew-grid .research-tile:nth-of-type(5) { grid-column: 4 / span 2; }
.crew-grid::before { content: ''; position: absolute; pointer-events: none; border: 1px solid var(--brass-dim); border-top: 0; left: 16%; right: 16%; top: 32%; bottom: 28%; }
.economy-grid { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; }
.sheet-body .research-tile { border: 0; padding: 0; background: transparent; min-width: 0; display: flex; align-items: center; flex-direction: column; gap: 5px; position: relative; color: var(--cream); }
.research-square { width: 64px; height: 64px; display: flex; align-items: center; justify-content: center; position: relative; background: linear-gradient(135deg,#3f3a34,#1b1916); border: 1px solid #c3a363; box-shadow: inset 0 0 0 3px #23201c,0 3px 8px #0006; }
.economy-grid .research-square { width: 100%; max-width: 64px; aspect-ratio: 1; height: auto; min-height: 44px; }
.research-square svg { width: 26px; height: 26px; stroke: currentColor; fill: none; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.research-square b { position: absolute; right: 4px; top: 1px; font-size: 11px; color: #f2d399; }
.sheet-body .research-square small { position: absolute; bottom: 1px; font-size: 9px; letter-spacing: 0; }
.research-label { font-size: 11px; line-height: 1.2; font-weight: 500; overflow-wrap: anywhere; }
.research-tile.locked .research-square { color: #a8afa5; border-color: #726c66; background: #23201d; }
.research-tile.completed .research-square { border-color: #9ec091; color: #bbe2ad; }
.research-tile.working .research-square { border-color: #f4d184; box-shadow: 0 0 12px #d5ac4a55; }
.research-tile:focus-visible { outline: 2px solid #f4d184; outline-offset: 4px; }
.research-trunk { height: 28px; width: 1px; background: var(--brass-dim); margin: 12px auto 0; }
.research-detail-heading { display: flex; align-items: center; gap: 14px; margin: 18px 0 12px; }
.research-detail-heading svg { width: 46px; height: 46px; fill: none; stroke: var(--brass); stroke-width: 1.5; flex-shrink: 0; }
.research-detail-heading h3 { margin: 0; font-size: 20px; }
.research-detail-heading p { margin: 4px 0 0; }
.research-description, .research-price, .research-lock { font-size: 17px; line-height: 1.4; }
.research-lock { color: var(--brass); }
#sheet[data-panel="yard"] #sheet-body, #sheet[data-panel="yard-detail"] #sheet-body { overflow-y: auto; overscroll-behavior: contain; }
@media (prefers-reduced-motion: reduce) { .research-tree { scroll-behavior: auto; } }
.storage-explanation { border-top: 1px solid var(--brass-dim); margin-top: 16px; padding-top: 8px; }
.storage-explanation h3 { font-size: 17px; }
.storage-explanation p { font-size: 16px; line-height: 1.4; margin: 8px 0; }
.sheet-body .research-tile { letter-spacing: 0; text-transform: none; }
.sheet-body .research-tile:hover { background: transparent; }
.research-tile:hover .research-square { outline: 1px solid var(--brass); }
.research-square svg { width: 22px; height: 22px; transform: translateY(-3px); }
.research-label { word-break: normal; overflow-wrap: normal; }
.economy-grid .research-tile::after { content: ''; position: absolute; width: 1px; height: 12px; background: var(--brass-dim); bottom: -15px; }

.sheet-body .yard-tabs button { min-width: 0; font-size: 13px; padding: 8px 4px; letter-spacing: .02em; }
.research-label { overflow-wrap: anywhere; }
.research-trunk { height: 18px; margin-top: 8px; }
.crew-grid::before { display: none; }
.crew-links { position: absolute; width: 100%; height: 100%; pointer-events: none; fill: none; stroke: var(--brass-dim); stroke-width: 1; }

/* Engraved brass, worn leather, and a working crew's field manual. */
#sheet[data-panel="yard"], #sheet[data-panel="yard-detail"] {
  border-color: #a9864f;
  box-shadow: 0 22px 60px #000b, 0 0 0 3px #171512, inset 0 0 0 1px #dfc08030;
}
#sheet[data-panel="yard"] .sheet-head, #sheet[data-panel="yard-detail"] .sheet-head {
  background: linear-gradient(110deg,#3e3933,#272420 65%,#34302b);
}
#sheet[data-panel="yard"] #sheet-body, #sheet[data-panel="yard-detail"] #sheet-body {
  background:
    radial-gradient(ellipse at 18% 0%,#b9954620,transparent 60%),
    repeating-linear-gradient(117deg,#d4c1a604 0 1px,transparent 1px 5px),
    linear-gradient(110deg,#201e1b,#171513 60%,#25221f);
}
.yard-identity { padding: 3px 0 8px; }
.yard-identity > span { display: block; font: 500 9px var(--display); letter-spacing: .16em; color: #b8a17c; }
.yard-identity strong { display: block; font: 600 20px var(--body); color: #f1dfb9; margin-top: 4px; }
.sheet-body .yard-tabs { gap: 5px; padding: 5px; border: 1px solid #6e624c; background: #0d0c0a80; box-shadow: inset 0 2px 5px #0008; }
.sheet-body .yard-tabs button { border: 1px solid #71644c; border-radius: 2px; background: linear-gradient(#403b35,#292622); color: #cfc5aa; box-shadow: inset 0 1px #fff1,0 2px 2px #0005; }
.sheet-body .yard-tabs button.primary { background: linear-gradient(135deg,#e5c684,#b98c43); color: #1f1c19; border-color: #e3c991; text-shadow: 0 1px #ffe8bc55; }
.yard-guide { color: #c6bda6; font-size: 14px; }
.sheet-body .yard-continue { min-height: 44px; padding: 8px; font-size: 13px; border: 0; border-bottom: 1px solid #8f754c; background: transparent; color: #d4b574; letter-spacing: .025em; text-align: left; }
.research-tier { position: relative; padding: 0 0 6px; }
.research-tier h3 { margin: 20px 0 16px; gap: 8px; color: #e5c995; }
.research-tier h3 > span { min-width: 27px; text-align: center; font: 600 15px var(--body); background: linear-gradient(145deg,#4b4934,#2a2723); border: 1px solid #ad8d54; box-shadow: inset 0 0 0 2px #23201c,0 2px 5px #0007; }
.research-tier h3 > b { font-size: 12px; text-transform: uppercase; letter-spacing: .08em; }
.research-tier h3 > small { margin-left: auto; color: #b4a282; font: 11px var(--display); border-bottom: 1px solid #6b5d43; padding: 3px; }
.research-square, .research-tile.locked .research-square {
  border: 1px solid #a68a55; border-radius: 5px;
  background: radial-gradient(ellipse at 50% 32%,#62604660,transparent 68%),repeating-linear-gradient(135deg,#cfbd8520 0 1px,transparent 1px 4px),linear-gradient(145deg,#453f38,#2a2622 55%,#181613);
  box-shadow: inset 0 0 0 2px #181613,inset 0 0 0 3px #c7a66155,inset 0 5px 8px #fff1,inset 0 -5px 8px #0007,0 4px 0 #0d0c0a,0 6px 9px #0008;
  transition: transform .16s ease,box-shadow .16s ease;
}
.research-square::before { content: ''; position: absolute; inset: 5px; border: 1px solid #dcc69225; border-radius: 50%; pointer-events: none; }
.research-square svg { width: 26px; height: 26px; color: #f0d79d; filter: drop-shadow(0 2px 1px #000c); stroke-width: 1.65; transform: translateY(-3px); }
.research-square b { right: -2px; top: -5px; min-width: 16px; padding: 1px 3px; font: 600 11px var(--body); background: #201d1a; border: 1px solid #c8a766; color: #f3daa6; box-shadow: 0 2px 3px #0008; }
.sheet-body .research-square small { bottom: 3px; font: 600 9px var(--display); color: #ead9b6; text-shadow: 0 1px 2px #000; }
.research-rivets::before,.research-rivets::after { content: ''; position: absolute; width: 3px; height: 3px; border-radius: 50%; background: #c7aa76; box-shadow: 0 1px 1px #000; left: 3px; }
.research-rivets::before { top: 3px; } .research-rivets::after { bottom: 3px; }
.research-pips { display: flex; gap: 3px; width: 100%; max-width: 60px; padding: 3px 1px 0; }
.research-pips i { flex: 1; height: 3px; background: #0a0a09; border: 1px solid #796745; box-shadow: 0 1px #ffffff0c; }
.research-pips i.filled { background: #efca75; border-color: #f6db9a; box-shadow: 0 0 4px #dcaf4e80; }
.research-label { color: #e4d7b9; font-size: 11px; text-shadow: 0 2px 2px #000; }
.research-tile.locked .research-square { border-color: #666059; background: repeating-linear-gradient(135deg,#9499860a 0 1px,transparent 1px 4px),linear-gradient(145deg,#3b3630,#1d1b18); box-shadow: inset 0 0 0 2px #171512,inset 0 0 0 3px #81776b28,0 3px 0 #0d0c0b,0 5px 6px #0006; }
.research-tile.locked .research-square svg { color: #9b9287; }
.research-tile.locked .research-square b { color: #b3baa3; border-color: #6a6259; }
.research-tile.locked .research-label { color: #a5af9b; }
.research-tile.locked .research-rivets::before,.research-tile.locked .research-rivets::after { background: #7a7064; }
.research-tile.completed .research-square { background: radial-gradient(ellipse at 50% 25%,#887c6f40,transparent),linear-gradient(145deg,#514a42,#25221f); border-color: #b6c789; box-shadow: inset 0 0 0 2px #1d1b18,inset 0 0 0 3px #b6c78966,0 4px 0 #0d0c0b,0 0 14px #82a45c25; }
.research-tile.completed .research-square svg { color: #d3e9ab; }
.research-tile.completed .research-pips i { background: #b7d78e; border-color: #cceba3; }
.research-tile.working .research-square { border-color: #ffdc82; animation: yard-work-glow 2.5s ease-in-out infinite; }
@keyframes yard-work-glow { 50% { box-shadow: inset 0 0 0 2px #201e1b,inset 0 0 0 3px #e5b955,0 4px 0 #100f0d,0 0 18px #e4ac4755; } }
@media (hover:hover) { .research-tile:hover .research-square { transform: translateY(-2px); outline: 1px solid #ead097; } }
.research-tile:active .research-square { transform: translateY(2px); }
.crew-links { stroke: #b4975d; stroke-width: 1.5; filter: drop-shadow(0 2px 1px #000); }
.research-trunk { background: linear-gradient(#ba9a59,#645538); width: 2px; height: 24px; position: relative; }
.research-trunk::after { content: ''; position: absolute; bottom: 0; left: -2px; width: 6px; height: 6px; transform: rotate(45deg); background: #c4a566; box-shadow: 0 1px 5px #000; }
.economy-grid .research-tile::after { background: #9c824e; height: 13px; bottom: -17px; box-shadow: 1px 1px #0008; }
.research-detail-heading { padding: 14px 10px; border-block: 1px solid #8e7547; background: linear-gradient(90deg,#8d744523,transparent); }
.research-detail-heading svg { padding: 6px; border: 1px solid #ad8c54; background: linear-gradient(140deg,#4c453e,#24211d); box-shadow: inset 0 0 0 2px #181614,0 3px 6px #0008; }
.research-detail-heading h3 { color: #ebd09c; }
.yard-progress { background: linear-gradient(120deg,#67522e50,#24211e); border-left: 3px solid #d8b36c; }
@media (max-width:350px) { .economy-grid .research-square svg { width: 22px; height: 22px; } .economy-grid .research-square small { font-size: 8px; } }
@media (prefers-reduced-motion:reduce) { .research-tile.working .research-square { animation: none; } .research-square { transition: none; } }

/* Do not wait for a second tap on popup actions on touch browsers. */
#sheet-body button { touch-action: manipulation; }
#sheet-body[aria-busy="true"] { cursor: progress; }

/* Reward-first reports and short, actionable street jobs. */
.sheet-body { overflow-x: hidden; min-width: 0; }
.sheet-body > * { max-width: 100%; box-sizing: border-box; }
.result-heading { font: 700 25px/1.15 var(--display); margin: 2px 0 12px; letter-spacing: .03em; }
.reward-grid { display: grid; grid-template-columns: repeat(3,minmax(0,1fr)); gap: 8px; margin: 10px 0; }
.reward-grid > div { min-width: 0; padding: 12px 8px; border: 1px solid #bd985d; border-radius: 4px; background: #36322d; }
.reward-grid strong { display: block; color: #ffe3a0; font: 700 28px/1.1 var(--display); overflow-wrap: anywhere; }
.reward-grid span { display: block; font-size: 14px; margin-top: 5px; color: #e2d9c4; }
.result-status { font-size: 15px; color: #c4c5b5; margin: 8px 0; }
.result-losses { display:flex; flex-wrap:wrap; justify-content:space-between; gap:8px; font-size:15px; padding:8px 0; }
.unlock-prize { display: grid; gap: 5px; background: #3f3a34; border-left: 3px solid #edc271; color: #ffe2a5; padding: 12px; margin: 10px 0; font-size: 16px; }
.unlock-prize span { font-size:15px; line-height:1.4; }
.result-character { margin-top:16px; }
.result-character .character-card { padding:8px; margin:0; gap:12px; }
.result-character .character-card img { width:64px; height:64px; flex-basis:64px; }
.result-character .character-card strong { font-size:21px; }
.result-character .character-card span { font-size:14px; }
.result-quote { font-style:italic; margin:8px 0; color:#dfc496; font-size:16px; }
.preparation, .ledger-alternative { padding:12px; margin:12px 0; background:#302c28; border:1px solid #867b6e; border-radius:4px; }
.preparation p, .ledger-alternative p { margin:6px 0; }
.preparation small, .ledger-alternative small { display:block; font-size:14px; line-height:1.4; color:#cdd0bb; }
.job-terms { display:flex; flex-wrap:wrap; gap:8px 16px; font-size:15px; margin:12px 0; }
.heat-cost { color:#f6cd76; }
.world-streets path { fill:none; stroke:#646849; stroke-width:20; stroke-linejoin:round; opacity:.55; }
.world-streets text { fill:#b4b394; font:600 27px var(--display); letter-spacing:4px; text-anchor:middle; }
.world-job { cursor:pointer; }
.world-job circle { fill:#253d32; stroke:#e4bb71; stroke-width:4; }
.world-job text { fill:#ffe2a5; font:700 26px var(--display); }
.world-job .job-label { font-size:22px; paint-order:stroke; stroke:#202e24; stroke-width:5px; }
.world-job .job-status { font-size:15px; fill:#e6d7b6; paint-order:stroke; stroke:#202e24; stroke-width:4px; }
.world-job.job-locked circle { stroke:#8d947e; }
.world-job:focus circle, .world-job:hover circle { fill:#526340; stroke:#fff0c5; }
.world-crew { cursor:pointer; fill:#d4bf96; stroke:#16221d; stroke-width:4; paint-order:stroke; }
.world-crew .crew-hit { fill:transparent; stroke:none; }
.world-crew .crew-weapon { fill:none; stroke:#e4b866; stroke-width:6; stroke-linecap:round; }
.world-crew .crew-level { fill:#b18a43; stroke:#181d17; stroke-width:3; }
.world-crew text { fill:#141b16; stroke:none; font:700 28px var(--display); }
.world-crew:focus-visible .crew-level { stroke:#fff0c5; stroke-width:5; }
.world-crew:focus { outline:none; }
.world-jobs { position:absolute; bottom:35px; left:12px; right:12px; z-index:2; display:flex; gap:8px; flex-wrap:wrap; justify-content:center; }
.world-jobs button { font-size:14px; min-height:40px; padding:7px 12px; background:#141b1cf2; border:1px solid #b89a60; }
@media(max-width:420px) { .reward-grid { gap:5px; } .reward-grid strong { font-size:24px; } .reward-grid > div { padding:10px 6px; } .world-jobs { gap:5px; } .world-jobs button { font-size:14px; padding:7px; } }

/* Rewards stay above the scene without replacing the active decision. */
.reward-notices { position:fixed; bottom:76px; right:12px; width:min(410px,calc(100vw - 24px)); z-index:60; display:grid; gap:8px; pointer-events:none; }
.reward-notice { display:grid; grid-template-columns:1fr auto auto; align-items:center; gap:8px; padding:12px; background:#23201d; color:var(--cream); border:1px solid var(--brass); box-shadow:0 6px 20px #0008; border-radius:8px; font-size:14px; }
.reward-notice button { pointer-events:auto; font-size:14px; min-height:40px; }
.reward-notice span { min-width:0; }
.job-milestone, .waiting-job { display:grid; gap:8px; margin:12px 0; padding:12px; border:1px solid var(--rule); border-radius:6px; }
.job-milestone span, .waiting-job > span { font-size:14px; color:var(--cream-dim); }
.job-milestone progress { width:100%; height:8px; accent-color:var(--brass); }
.waiting-job .job-milestone { padding:0; margin:4px 0; border:0; }
.waiting-activities { border-top:1px solid var(--rule); margin-top:16px; padding-top:8px; }
.crew-objective { padding:12px; border-left:3px solid var(--brass); margin:12px 0; }
.world-goal { display:block; max-width:min(500px,60vw); margin-top:6px; text-align:left; font-size:14px; }
@media (max-width:600px) { .reward-notice { grid-template-columns:1fr auto; } .reward-notice span { grid-column:1 / -1; } .world-goal { max-width:58vw; font-size:12px; } }
.training-diversions { display:flex; gap:8px; flex-wrap:wrap; align-items:center; padding:10px 0; }
.training-diversions strong { flex-basis:100%; font-size:14px; }
.training-diversions button { flex:1; min-height:42px; color:var(--cream); border-color:var(--brass); }
.encounter-level { display:flex; align-items:end; gap:12px; margin:14px 0; }
.encounter-level label { flex:1; display:grid; gap:6px; }
.encounter-level button { min-width:44px; min-height:44px; }
.encounter-level select { width:100%; min-height:44px; background:#24211d; color:var(--cream); border:1px solid var(--brass); border-radius:5px; padding:8px; font:inherit; }
.encounter-enemy { display:grid; gap:6px; border-left:3px solid var(--brass); padding:12px; background:#34302b; }
.encounter-enemy span { color:var(--cream-dim); font-size:14px; }

.reward-notices { max-height: min(36dvh, 320px); overflow-y: auto; overscroll-behavior: contain; pointer-events: auto; }
.reward-notices:empty { display:none; }
.reward-notice button { min-height:44px; }
.build-complete { padding:12px; margin-bottom:14px; border:1px solid var(--brass); background:#3c3731; border-radius:8px; }
.build-complete > strong { color:var(--brass); font-size:18px; }
.build-complete p { margin:8px 0; }
.reward-hub { position:fixed; bottom:76px; right:12px; z-index:60; display:flex; flex-direction:column; align-items:flex-end; gap:8px; max-width:calc(100vw - 24px); }
.reward-hub[hidden], .reward-notices[hidden] { display:none !important; }
#reward-inbox { min-height:44px; padding:8px 12px; background:#23201d; border:1px solid var(--brass); color:var(--cream); box-shadow:0 3px 12px #0008; }
.reward-hub .reward-notices { position:static; width:min(410px,calc(100vw - 24px)); }

/* The tutorial lives on the block, with a brief completion note. */
#opening-card { position: relative; inset: auto; width: 100%; padding: 5px 12px; gap: 2px 10px; border-radius: 0; box-shadow: none; grid-template-columns: minmax(0,1fr) auto; }
#opening-card .opening-detail { display: none; }
#opening-card .opening-eyebrow { font-size: 10px; }
#opening-card strong { font-size: 14px; line-height: 1.15; }
#opening-card button { min-width: 0; max-width: 140px; min-height: 44px; padding: 6px 10px; font-size: 13px; white-space: normal; overflow-wrap: anywhere; }
.block-guide { position: absolute; z-index: 12; display: grid; justify-items: center; transform: translate(-50%,-100%); pointer-events: none; color: #ffda70; width: 190px; }
.block-guide span { max-width: 190px; padding: 4px 8px; border-radius: 5px; background: #17271ff2; color: #fff0bc; font: 600 13px var(--display); text-align: center; box-shadow: 0 2px 6px #0008; }
/* `guide-bob`, not `guide-pulse`: `.job-guide` further down declares its own
 * @keyframes under that name, and a duplicate name replaces the earlier rule
 * outright -- so this blade lost its bob and silently inherited a plain fade.
 * The rotation rides in a custom property so the keyframes can carry it too;
 * a transform set from script would be dropped every time the bob ran. */
.block-guide svg { fill: #ffda70; stroke: #4b3612; stroke-width: 2; filter: drop-shadow(0 3px 3px #0009); transform: rotate(var(--guide-angle, 0deg)); animation: guide-bob 1.2s ease-in-out infinite; }
@keyframes guide-bob { 50% { transform: translateY(-9px) rotate(var(--guide-angle, 0deg)); opacity: .55; } }
/* Off the edge it is a bearing, not a caption, so the words would only crowd it. */
.block-guide.off-screen span { display: none; }
/* Sized like a message from Eddie rather than a corner toast: this is the one
 * place the game explains what the player just paid for, and it now waits to be
 * closed instead of expiring after six seconds, so it can afford the room. */
.build-tip { pointer-events: none; position: absolute; z-index: 15; left: 50%; transform: translateX(-50%); bottom: calc(var(--safe-bottom, 0px) + 16px); width: min(560px, calc(100% - 24px)); padding: 18px 52px 18px 20px; background: #2a2622fa; border: 1px solid #d5b36a; border-radius: 12px; box-shadow: 0 10px 30px #0008; color: #f4e9ce; }
.build-tip strong { display: block; font: 600 21px/1.25 var(--display); color: #ffeab4; }
.build-tip p { margin: 10px 0 0; font-size: 16px; line-height: 1.45; }
.build-tip > span:not(:empty) { display: block; margin-top: 10px; color: #e9c974; font-size: 15px; }
#build-tip-close { pointer-events: auto; position: absolute; right: 4px; top: 4px; width: 44px; height: 44px; padding: 0; border: 0; background: transparent; color: #f4e9ce; font-size: 26px; }

.block-guide[hidden], .build-tip[hidden], .view-world .block-guide, .view-world .build-tip { display: none; }
@media (prefers-reduced-motion: reduce) { .block-guide svg { animation: none; } }

/* Results stay beside the action; construction history has its own quiet tab. */
.report-tabs { display:flex; gap:8px; margin-bottom:16px; }
.report-tabs button { flex:1; min-width:0; min-height:44px; padding:10px 8px; font-size:14px; }
.report-tabs [aria-selected="true"] { background:var(--brass); color:#221f1b; }
.street-result { padding:12px; margin-bottom:16px; border:1px solid var(--brass); border-radius:8px; background:#39342f; }
.street-result > strong { font:600 20px var(--display); }
.street-result p { font-size:14px; margin:8px 0; }
.street-result progress { width:100%; accent-color:var(--brass); }
.street-result-actions { display:flex; gap:8px; margin-top:12px; }
.street-result-actions button { flex:1; min-width:0; min-height:44px; padding:10px 6px; font-size:14px; }
.waiting-activities > p, .waiting-activities > h3, .waiting-activities .waiting-job { flex-basis:100%; }
.march-tracking { position:absolute; z-index:3; left:50%; transform:translateX(-50%); bottom:106px; width:min(480px,calc(100% - 24px)); padding:12px; border:1px solid var(--brass); background:#0c1314f5; border-radius:8px; }
.march-tracking strong, .march-tracking span { display:block; font-size:14px; margin-bottom:6px; }
.march-tracking button { min-height:44px; width:100%; }
.march-tracking[hidden] { display:none; }

.world-heading .world-goal { max-width:min(500px,58vw); }

/* Full-width portraits and distinct navigation versus purchase actions. */
.sheet-body > .building-hero { width:calc(100% + 24px); max-width:none; margin:-10px -12px 12px; box-sizing:border-box; }
.sheet-body > .building-tabs + .building-hero { margin-top:0; }
.building-tabs { position:static; margin:-10px -12px 12px; border-top:0; border-bottom:1px solid #746342; }
.building-tabs button { display:flex; align-items:center; justify-content:center; gap:8px; color:#c9c0a9; background:#1d1a17; }
.building-tabs [aria-pressed="true"] { background:#39342e; color:#f6d88f; box-shadow:inset 0 -3px #e4bc69; }
.building-tabs svg { width:25px; height:25px; fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
#sheet[data-panel="raid"] .character-card { padding:0; margin:0 0 8px; gap:10px; }
#sheet[data-panel="raid"] .character-card img { width:54px; height:54px; }
#sheet[data-panel="raid"] .character-card strong { font-size:19px; }
#sheet[data-panel="raid"] .character-card span { display:none; }
#sheet[data-panel="raid"] .raid-temptation { margin:8px 0; padding:8px; }
#sheet[data-panel="raid"] .raid-intel { margin:0 0 8px; }
#sheet[data-panel="raid"] .unlock-prize { padding:8px; margin:8px 0; }
#sheet[data-panel="raid"] .send { margin:4px 0; }
.wire-guide { position:absolute; bottom:100%; left:50%; transform:translateX(-50%); font:700 38px system-ui; color:#ffda70; text-shadow:0 2px 5px #000; pointer-events:none; animation:wire-bounce .8s ease-in-out infinite alternate; }
@keyframes wire-bounce { to { transform:translate(-50%, -8px); } }
@media(prefers-reduced-motion:reduce) { .wire-guide { animation:none; } }
#dialogue-cutout { position:absolute; bottom:calc(100% - 12px); left:50%; transform:translateX(-50%); width:230px; height:190px; object-fit:contain; object-position:bottom; pointer-events:none; filter:drop-shadow(0 4px 7px #0007); }
/*
 * The rival stands behind the dashboard, not over it.
 *
 * The cutout is 190px tall and hangs off the top of the sheet, which on an
 * iPhone 13 puts its head at y=46 against a dashboard that ends at y=96 — so
 * Eddie's hat covered the Guns readout while he talked about taking your
 * money. Lifting the dashboard over the sheet for the length of a dialogue
 * reads correctly (he is in the street; the ledger is in front of you) and
 * keeps the numbers legible. It also lifts the dashboard over the scrim, which
 * is the point: those numbers are what the taunt is about.
 */
body:has(#sheet.dialogue-sheet) .dash { position: relative; z-index: 22; }
#sheet.dialogue-sheet { bottom:calc(var(--safe-bottom) + 24px); max-height:calc(100dvh - 230px - var(--safe-bottom)); }
#sheet.dialogue-sheet .character-card { display:none; }
@media(min-width:720px) { #sheet.dialogue-sheet { transform:translateX(-50%); } }
.mission-art { width:100%; height:120px; background-image:url('./assets/mission-atlas.webp'); background-size:100% 300%; border-radius:8px; border:1px solid #9c8051; box-sizing:border-box; margin:0 0 12px; }
.mission-freight { background-position:center top; }
.mission-protection { background-position:center center; }
.mission-shipment { background-position:center bottom; }
.mission-shortcut { background-image:linear-gradient(transparent,#100f0ddd),url('./assets/mission-atlas.webp'); background-size:100% 100%,100% 300%; min-height:68px; padding:28px 8px 5px!important; color:#fff0d4; text-shadow:0 1px 3px #000; }
.mission-shortcut.mission-freight { background-position:center,center top; }
.mission-shortcut.mission-protection { background-position:center,center center; }
.mission-shortcut.mission-shipment { background-position:center,center bottom; }
.waiting-job .mission-art { height:90px; margin-bottom:8px; }
.sheet-body > .building-tabs { width:calc(100% + 24px); box-sizing:border-box; }

/* Keep illustrated jobs reachable beside the live crew dock on small screens. */
@media (max-width:600px) {
  .world-jobs { flex-wrap:nowrap; justify-content:flex-start; overflow-x:auto; padding-bottom:2px; }
  .world-jobs button { flex:0 0 138px; min-height:68px; }
  .view-world .queue-dock { bottom:112px; overflow-y:auto; }
  .view-world .queue-dock > * { flex-shrink:0; }
}

/* Crew preparation fits in a single phone screen, including dispatch. */
#sheet[data-panel="street-crews"] { max-height:calc(100dvh - 24px - var(--safe-bottom)); }
#sheet[data-panel="street-crews"] .sheet-head h2 { font-size:17px; letter-spacing:0; text-transform:none; }
#sheet[data-panel="street-crews"] .sheet-body { display:grid; gap:8px; padding:8px 12px 12px; font-size:15px; line-height:1.2; }
#sheet[data-panel="street-crews"] p { margin:0; font-size:13px; }
#sheet[data-panel="street-crews"] p:empty { display:none; }
.street-hero { display:flex; align-items:center; gap:12px; }
.street-portrait { flex:0 0 96px; height:96px; background-image:url('./assets/street-crew-atlas.webp'); background-size:300% 200%; }
.street-hero > div:last-child { display:grid; gap:7px; font-size:13px; color:var(--cream-dim); }
.street-trip { color:#ffe3a0; font:700 30px/1 var(--display); }
.street-trip span { display:block; font-size:16px; font-weight:500; }
.street-hero small { font-size:12px; color:#a9b49c; }
.street-trip { font-size:26px; }
#sheet[data-panel="street-crews"] h3 { margin:0; font-size:15px; }
#sheet[data-panel="street-crews"] .reward-grid { margin:5px 0 0; gap:6px; }
#sheet[data-panel="street-crews"] .reward-grid > div { padding:7px; }
#sheet[data-panel="street-crews"] .reward-grid strong { font-size:22px; }
#sheet[data-panel="street-crews"] .reward-grid span { font-size:12px; margin-top:3px; }
#sheet[data-panel="street-crews"] .unlock-prize { margin:0; padding:7px 9px; gap:3px; font-size:14px; }
#sheet[data-panel="street-crews"] .unlock-prize span { font-size:14px; line-height:1.2; }
#sheet[data-panel="street-crews"] .crew-slider { font-size:14px; }
#sheet[data-panel="street-crews"] .crew-slider input { margin:0; height:32px; }
#sheet[data-panel="street-crews"] .street-result { display:grid; gap:8px; padding:9px; margin:0; }
#sheet[data-panel="street-crews"] .street-result-actions { margin:0; }
#sheet[data-panel="street-crews"] .dispatch-confirm { margin:0; padding:10px; }
@media(max-height:600px) { .street-portrait { flex-basis:72px; height:72px; } }

/* Let the city fill the screen. Monitoring opens only when requested. */
.world-heading { padding:8px; gap:8px; background:linear-gradient(#101d1fcc,transparent); }
.world-heading h2 { font-size:18px; }
.world-heading button { min-height:44px; font-size:13px; padding:8px 12px; }
.view-world .queue-dock { top:64px; bottom:auto; max-height:calc(100% - 150px); overflow-y:auto; }
.view-world #build-queues { display:block; }
.world-tools { position:absolute; bottom:12px; right:12px; z-index:6; }
.world-tools summary { cursor:pointer; list-style:none; min-height:44px; display:flex; align-items:center; justify-content:center; padding:0 14px; background:#141b1ced; border:1px solid #ad905a; border-radius:5px; font:600 14px var(--display); }
.world-tools nav { position:absolute; bottom:52px; right:0; width:min(260px,80vw); display:grid; padding:6px; gap:4px; background:#0c1314; border:1px solid #ad905a; border-radius:6px; box-shadow:0 4px 20px #0008; }
.world-tools nav button { text-align:left; min-height:44px; margin:0; max-width:none; font-size:14px; }
.crew-highlight, .crew-pointer { display:none; pointer-events:none; }
.is-found .crew-highlight { display:block; fill:#ffe19b44; stroke:#ffe19b; stroke-width:3; animation:crew-found 1s ease-in-out infinite; }
.is-found .crew-pointer { display:block; fill:#ffe19b; stroke:none; }
@keyframes crew-found { 50% { opacity:.35; } }
.march-slugger { background:url('./assets/street-crew-atlas.webp') 0 0 / 300% 200%; animation:crew-step .35s ease-in-out infinite alternate; }
@keyframes crew-step { to { translate:0 -3px; } }
.street-fight-status { display:grid; gap:6px; }
.street-fight-status strong { display:block; font-size:13px; }
.street-fight-status button { min-height:44px; }
@media(prefers-reduced-motion:reduce) { .is-found .crew-highlight, .march-slugger { animation:none; } }

.world-map:has(.world-tools[open]) { z-index:6; }

/* Two shared crew slots, with quiet outbound and homebound tracks. */
#march-list { padding:4px 7px; }
.crew-queue-row { position:relative; padding:7px 0; border-bottom:1px solid #8b977333; font:12px/1.25 var(--display); }
.crew-queue-row:last-child { border-bottom:0; }
.crew-queue-row > div:first-child { display:flex; justify-content:space-between; gap:8px; }
.crew-queue-row span { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.crew-queue-row small { flex-shrink:0; color:var(--cream-dim); font-size:11px; }
.crew-queue-row.idle { display:flex; justify-content:space-between; opacity:.65; }
.crew-trip-bars { display:flex; gap:4px; margin-top:5px; }
.crew-trip-bars progress { width:50%; height:4px; border:0; border-radius:3px; appearance:none; background:#191715; }
.crew-trip-bars progress::-webkit-progress-bar { background:#191715; border-radius:3px; }
.crew-trip-bars progress::-webkit-progress-value { background:#d5b473; border-radius:3px; }
.crew-trip-bars progress:last-child::-webkit-progress-value { background:#81a68b; }
.crew-trip-bars progress::-moz-progress-bar { background:#d5b473; }
.crew-track { font-size:11px; padding:2px 5px; margin-top:4px; }
.crew-queues-panel { margin:0 0 10px; }
.world-region-labels { display:none; fill:#ddd5bc; text-anchor:middle; font:600 9500px var(--display); letter-spacing:500px; opacity:.65; pointer-events:none; }
.world-overview .world-region-labels { display:block; }
.world-heading h2 { font-size:14px; text-align:center; }

.view-world .city-horizon { display:none; }
.world-overview .world-block, .world-overview .world-job, .world-overview .world-rumors { display:none; }
.view-world .town.intro-splash .queue-dock, .view-world .town.intro-splash .marches { opacity:1; }
.crew-queue-row { min-height:44px; box-sizing:border-box; }
.crew-queue-row [data-track-street] { position:absolute; inset:0; width:100%; height:100%; margin:0; padding:0; opacity:0; min-height:0; }
.crew-queue-row:has([data-track-street]):hover { background:#d5b4730c; }
.crew-queue-row:focus-within { outline:1px solid var(--brass); }
.crew-queue-row:has([data-recall]) { padding-right:46px; }
.crew-queue-row [data-recall] { position:absolute; top:0; right:0; width:44px; height:44px; margin:0; padding:2px; font-size:10px; }

/* Regional gathering sites share one illustrated atlas, with twelve distinct buildings. */
.resource-sprite { width:100%; height:100%; background-image:url('./assets/resource-nodes.webp'); background-size:400% 300%; background-repeat:no-repeat; }
.world-resource { cursor:pointer; }
.world-resource .crew-hit { fill:transparent; stroke:none; }
.world-resource:focus { outline:none; }
.world-terrain { opacity:1; }
.world-resource .resource-name { fill:#fff0cf; font:600 21px Georgia,serif; paint-order:stroke; stroke:#192721; stroke-width:5px; stroke-linejoin:round; }
.world-resource .resource-stock { fill:#eee1bd; font:600 15px system-ui; paint-order:stroke; stroke:#192721; stroke-width:4px; }
.world-resource.depleted .resource-sprite { filter:grayscale(.7); opacity:.6; }
.resource-summary { display:flex; align-items:center; gap:12px; }
.resource-summary .resource-sprite { flex:none; width:125px; height:112px; }
.resource-summary strong,.resource-summary small { display:block; }
.resource-summary strong { font-size:23px; margin:5px 0; }
.resource-summary .eyebrow { font-size:10px; }
.gather-metrics { display:grid; grid-template-columns:1fr 1fr; gap:12px; border-block:1px solid #b99a5655; padding:12px 0; margin:8px 0 15px; }
.gather-metrics small,.gather-metrics strong { display:block; }
.gather-metrics strong { color:#ffe2a1; font-size:19px; margin-top:5px; }
#sheet[data-panel="resource-node"] #sheet-body { padding:12px 16px; }
#sheet[data-panel="resource-node"] .crew-slider { margin:8px 0; }
#sheet[data-panel="resource-node"] #gather-error:empty { display:none; }
@media(max-height:640px) { .resource-summary .resource-sprite { width:85px; height:76px; } .gather-metrics { padding:7px 0; margin:5px 0; } }

/* A quiet ground layer and consistent contact shadows keep playable sites legible. */
.world-scenery-sprite { width:100%; height:100%; background:url('./assets/terrain-props.webp') 0 0 / 300% 200% no-repeat; }
.world-scenery { pointer-events:none; }
.site-clearing { fill:url(#site-clearing); stroke:none; pointer-events:none; }
.site-shadow { fill:url(#site-shadow); stroke:none; pointer-events:none; }
.world-map .world-character { display:none; }
.world-map .world-block .world-boundary { fill:none; stroke:none; }
.world-map .world-block:hover .world-boundary,.world-map .world-block:focus .world-boundary { stroke:none; }
.world-map .world-nameplate,.resource-nameplate { fill:#14221fed; stroke:#c7b27a55; stroke-width:1; }
.world-map .world-nameplate { rx:7px; }
.world-resource .resource-name { font:600 30px Jost,sans-serif; fill:#f4e7cf; stroke:none; }
.world-resource .resource-stock { font:500 20px Jost,sans-serif; fill:#d8bf85; stroke:none; }
.world-map .world-crew .crew-level { fill:#172821ed; stroke:#c7b27a88; stroke-width:1; }
.world-map .world-crew text { fill:#f4dfac; }
.world-map .world-rumor { opacity:.35; }

.world-map .world-block text:not(.world-owner) { font-size:32px; }

/* Missions have their own home; Crews stays focused on training and deployments. */
.mission-next { padding:12px; margin-bottom:14px; border:1px solid #b99a5666; border-radius:7px; }
.mission-next h3 { margin:5px 0 10px; font-size:18px; }
.mission-next small { color:var(--brass); text-transform:uppercase; letter-spacing:.08em; }
.mission-finders { display:grid; grid-template-columns:1fr 1fr; gap:8px; margin-bottom:14px; }
.mission-finders button { min-width:0; font-size:13px; padding:8px; }
.mission-card { display:grid; grid-template-columns:76px minmax(0,1fr); gap:8px 12px; padding:14px 0; border-top:1px solid #b99a5644; }
.mission-card .mission-art { height:76px; width:76px; margin:0; border-radius:6px; }
.mission-card h3 { margin:0 0 5px; font-size:18px; }
.mission-card p { margin:3px 0; font-size:14px; }
.mission-card small { font-size:13px; }
.mission-card > .mission-status,.mission-card > .job-milestone,.mission-card > button { grid-column:1/-1; }
.mission-card .job-milestone { margin:0; }

.mansion-support { margin:12px 0; padding:10px 0; border-top:1px solid var(--rule); }
.mansion-support h3 { font-size:16px; margin:0 0 8px; }
.support-row { display:flex; gap:8px; justify-content:space-between; align-items:center; font-size:13px; padding:4px 0; }
.support-row button { min-height:44px; font-size:12px; padding:6px 10px; }

/* The still's strength: the one control on the block that is set, not bought.
   Both sides of the trade are on screen together, so the panel is a little
   taller than the rows around it and says so with a rule above. */
.booze-strength { margin:12px 0; padding:10px 0; border-top:1px solid var(--rule); }
.booze-strength h3 { font-size:16px; margin:0 0 8px; }
.booze-strength input[type=range] {
  /* `margin:0` is load-bearing: the UA sheet gives a range input 2px of
     horizontal margin, so `width:100%` lands 4px wider than the box it is in
     and the panel scrolls sideways by exactly that. */
  display:block; width:100%; height:28px; margin:0; box-sizing:border-box;
  accent-color:var(--brass); touch-action:auto;
}
.booze-strength .strength-scale { display:flex; justify-content:space-between; padding:0 2px 6px;
  font-size:12px; color:var(--cream-dim); font-variant-numeric:tabular-nums; }
.booze-strength .strength-scale .on { color:var(--brass); }
.booze-strength strong { display:block; font-size:17px; color:var(--brass); }
.booze-strength .blurb { margin:4px 0 8px; }

/* Heat: what the Bureau is looking at, and how much of it each thing is. */
.heat-detail { margin: 8px 0 0; }
.heat-detail summary { padding: 6px 0; color: #e0c58a; cursor: pointer; }
.heat-source { display: grid; grid-template-columns: minmax(0,1fr) minmax(60px,2fr) 40px; align-items: center; gap: 8px; padding: 4px 0; font-size: 15px; }
.heat-source i { display: block; height: 7px; background: #161412; border: 1px solid #6d655c; }
.heat-source i b { display: block; height: 100%; background: linear-gradient(90deg, #c9a227, #c97c27); }
.heat-source span:last-child { text-align: right; color: var(--cream-dim); font-variant-numeric: tabular-nums; }

/* Today's work. The first thing in Missions, because it is what a returning
   player came back for. */
.daily-board { display: grid; gap: 8px; padding: 11px; border: 1px solid var(--brass-dim); background: var(--panel-2); }
.daily-board header { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.daily-board h3 { margin: 0; font-size: 16px; color: #f3d99a; }
.daily-streak { font: 600 13px var(--display); color: #e7c485; }
.daily-streak.quiet { color: var(--cream-dim); font-weight: 400; }
.daily-task { display: grid; grid-template-columns: minmax(0,1fr) auto; gap: 3px 8px; align-items: baseline; padding: 6px 0; border-top: 1px solid #ffffff14; }
.daily-task strong { display: block; font-size: 15px; }
.daily-task small { display: block; font-size: 13px; color: var(--cream-dim); }
.daily-count { font-variant-numeric: tabular-nums; font-size: 14px; color: var(--cream-dim); }
.daily-task progress { grid-column: 1 / -1; width: 100%; height: 6px; accent-color: #d6ad60; }
.daily-chips { grid-column: 1 / -1; justify-self: end; font: 600 12px var(--display); color: #e7c485; }
.daily-task.done strong { color: #bfe0a8; }
.daily-task.done progress { accent-color: #8fc06d; }
.daily-task.claimed { opacity: .55; }
/* A dead Collect button should not look like the brightest thing on screen. */
#claim-daily:disabled { background: transparent; color: var(--cream-dim); border: 1px solid #ffffff22; opacity: 1; }

/* One-time rewards, one rung per track. The first thing in Missions, because
   with a sixty-dollar stake it is where the player's money actually is. */
.reward-ladder { display: grid; gap: 8px; padding: 11px; border: 1px solid var(--brass-dim); background: var(--panel-2); }
.reward-ladder.has-ready { border-color: var(--brass); box-shadow: 0 0 0 1px #d6ad6033 inset; }
.reward-ladder header { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.reward-ladder h3 { margin: 0; font-size: 16px; color: #f3d99a; }
.ladder-ready { font: 600 13px var(--display); color: #ffd98a; }
.ladder-step { display: grid; grid-template-columns: minmax(0,1fr) auto; gap: 4px 8px; align-items: baseline; padding: 7px 0; border-top: 1px solid #ffffff14; }
.ladder-step small { display: block; font: 600 11px var(--display); letter-spacing: .14em; text-transform: uppercase; color: var(--cream-dim); }
.ladder-step strong { display: block; font-size: 15px; }
.ladder-step span { font-size: 13px; color: var(--cream-dim); }
.ladder-bag { justify-self: end; font: 600 13px var(--display); color: #e7c485; white-space: nowrap; }
.ladder-step button { grid-column: 1 / -1; margin-top: 5px; }
.ladder-wait { grid-column: 1 / -1; justify-self: end; font-size: 13px; color: var(--cream-dim); }
.ladder-step.is-ready strong { color: #ffe3a0; }
.ladder-collect-all { display: grid; gap: 3px; justify-items: center; min-height: 48px; }
.ladder-collect-all small { font: 600 12px var(--display); letter-spacing: .02em; text-transform: none; color: #3a2a12; }
.ladder-collect-all .icon-art { width: 16px; height: 16px; vertical-align: -3px; }

/* ------------------------------------------------- the Ladder (`climb-`)
 * Not to be confused with `.ladder-step` above, which is the Missions reward
 * ladder. This is the endless fight ladder: one opponent at a time, filling
 * the sheet, because there is only ever one decision on it.
 */
.climb-face { flex: 0 0 auto; border: 1px solid #c9a22755; border-radius: 6px; overflow: hidden; background: #23201c; }
.climb-face svg { display: block; width: 100%; height: auto; }
.climb-face.big { width: 96px; }
.climb-face.small { width: 52px; }

.climb-card { display: flex; align-items: center; gap: 13px; padding: 12px; margin: 0 0 12px; border: 1px solid var(--brass); border-radius: 8px; background: #39342f; }
.climb-card.won { border-color: #7fbf8a; background: #3a352f; }
.climb-card.lost { border-color: #9a5b52; background: #3a2c29; }
.climb-who { display: grid; gap: 3px; min-width: 0; }
.climb-who .eyebrow { font-size: 11.5px; letter-spacing: .07em; text-transform: uppercase; color: #a9b49c; }
.climb-who strong { font: 600 21px/1.15 var(--display); color: #ffe3a0; overflow-wrap: anywhere; }
.climb-who em { font-style: normal; font-size: 14px; color: var(--brass); }
.climb-who span { font-size: 13px; color: var(--cream-dim); }

.climb-taunt { margin: 0 0 10px; padding-left: 11px; border-left: 2px solid var(--brass); font: italic 400 16px/1.45 var(--body); color: #e2d9c4; }
.climb-reveal { margin: 0 0 12px; font-size: 13px; color: #a9b49c; }

.climb-odds { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin: 0 0 12px; }
.climb-odds > div { min-width: 0; padding: 9px 7px; border: 1px solid var(--rule); border-radius: 4px; background: var(--panel-2); text-align: center; }
.climb-odds small { display: block; font-size: 11px; color: #a9b49c; }
.climb-odds strong { display: block; margin-top: 3px; font: 600 17px/1.15 var(--display); color: var(--cream); overflow-wrap: anywhere; }
.climb-odds.clear > div:last-child strong { color: #9fd9a6; }
.climb-odds.close > div:last-child strong { color: #ffe3a0; }
.climb-odds.thin > div:last-child strong,
.climb-odds.out > div:last-child strong { color: var(--red-bright); }

.climb-purse h3 { margin: 0; font-size: 14px; color: var(--cream-dim); font-weight: 500; }
.climb-purse .reward-grid { margin: 6px 0 12px; }
.climb-rules { margin: 0 0 14px; font-size: 12.5px; line-height: 1.45; color: #a9b49c; }
.climb-result-actions { display: grid; gap: 8px; }

.climb-ahead { display: flex; align-items: center; gap: 11px; margin-top: 16px; padding: 10px; border: 1px dashed var(--rule); border-radius: 6px; }
.climb-ahead div { display: grid; gap: 2px; min-width: 0; }
.climb-ahead small { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: #a9b49c; }
.climb-ahead strong { font: 600 16px var(--display); color: var(--cream); }
.climb-ahead span { font-size: 12.5px; color: var(--cream-dim); }

/* The way in, from Crews. A full-width control, not a link in a paragraph. */
.climb-entry { position: relative; display: flex; align-items: center; gap: 11px; width: 100%; min-height: 44px; margin: 0 0 12px; padding: 9px 11px; border: 1px solid var(--rule); border-radius: 8px; background: var(--panel-2); text-align: left; }
.climb-entry.is-ready { border-color: var(--brass); background: #39342f; }
.climb-entry div { display: grid; gap: 2px; min-width: 0; }
.climb-entry small { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--brass); }
.climb-entry strong { font: 600 17px var(--display); color: var(--cream); overflow-wrap: anywhere; }
.climb-entry span { font-size: 12.5px; color: var(--cream-dim); }
.climb-entry .dot { position: absolute; top: 7px; right: 7px; }

/* Detailed character sprites share the courtyard's angled camera. */
.battle-stage { position:relative; margin:0 0 10px; border:1px solid #746345; border-radius:8px; overflow:hidden; background:#201e19; }
.battle { display:block; width:100%; height:auto; max-height: min(58dvh,520px); }
.battle .fighters { opacity:0; }
.battle.ready .fighters { opacity:1; }
.battle .fig.enemy .fighter-pose { filter:sepia(.16) saturate(.85) brightness(.88); }
.battle .fig.down .side-mark { opacity:0; }
.battle-caption { position:absolute; top:10px; left:12px; margin:0; font:500 11px var(--display); color:#f3e7cf; text-shadow:0 1px 3px #000; letter-spacing:.06em; }
.battle-caption span { display:block; font-size:10px; color:#d2c4ad; margin-top:3px; }
.battle-status { text-align:center; padding:7px 10px; font:500 11px var(--display); letter-spacing:.08em; text-transform:uppercase; color:#ddc99e; background:#201f1a; }
#sheet[data-panel="ladder"]:has(.battle-stage) #sheet-body { padding:10px; }

.battle-bar { display: flex; align-items: center; gap: 8px; padding: 7px 9px; border-top: 1px solid var(--rule); background: var(--panel-2); }
.battle-bar .side { flex: 1 1 0; min-width: 0; font-size: 11.5px; color: #a9b49c; }
.battle-bar .side strong { display: block; font: 600 15px var(--display); color: var(--cream); }
.battle-bar .side.them { text-align: right; }
.battle-bar .side.them strong { color: var(--red-bright); }
.battle-bar button { min-height: 38px; padding: 6px 14px; font-size: 13px; }
.battle-round { flex: 0 0 auto; font-size: 11px; letter-spacing: .07em; text-transform: uppercase; color: var(--brass); }

/* Ladder jobs: a quiet workbench, tactile props, and 44px touch targets. */
.puzzle-art { display: inline-block; flex: none; width: 44px; height: 44px; background-image: url('./assets/ladder-puzzle-props.webp'); background-size: 300% 200%; background-repeat: no-repeat; filter: drop-shadow(0 3px 3px #0008); }
.art-sort { background-position: 0 0; }
.art-escape { background-position: 50% 0; }
.art-lookouts { background-position: 100% 0; }
.art-freight { background-position: 0 100%; }
.art-switchboard { background-position: 50% 100%; }
.puzzle-heading { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.puzzle-hero { width: 66px; height: 66px; }
.puzzle-heading small { display: block; color: #d9b56d; font: 11px/1.4 Jost, sans-serif; letter-spacing: .7px; text-transform: uppercase; }
.puzzle-heading h3 { margin: 3px 0; font: 600 21px/1.15 Jost, sans-serif; }
.puzzle-heading div > span { font: 12px/1.3 Jost, sans-serif; color: #c1c6b8; }
.puzzle-rule { margin: 8px 0 12px; font: 14px/1.4 Jost, sans-serif; color: #e3decc; }
.puzzle-workbench { padding: 8px; border: 1px solid #84714d; border-radius: 8px; background: radial-gradient(ellipse at top, #413c36, #181613); box-shadow: inset 0 2px 14px #0008; }
.puzzle-grid { display: grid; grid-template-columns: repeat(var(--cols), minmax(0, 1fr)); gap: 2px; width: min(100%, 360px); margin: auto; }
.puzzle-tile { position: relative; aspect-ratio: 1; min-width: 0; min-height: 44px; width: 100%; padding: 0; overflow: hidden; border: 1px solid #605952; border-radius: 3px; background: #302c27; touch-action: manipulation; }
.puzzle-tile:disabled { opacity: 1; }
.puzzle-tile .puzzle-art { position: absolute; inset: 0; width: 100%; height: 100%; }
.puzzle-tile:focus-visible, .puzzle-load:focus-visible, .puzzle-rack:focus-visible { outline: 3px solid #fff0b6; outline-offset: 1px; z-index: 1; }
.car-cell { background: repeating-linear-gradient(0deg, #333c35 0 12px, #303930 12px 13px); }
.escape-arrow { position: absolute; right: 3px; bottom: 0; color: #fff0b6; font: bold 26px/1 Jost, sans-serif; text-shadow: 0 1px 3px #000, 0 0 5px #000; }
.vacated { color: #839081; font-size: 20px; }
.rooftop { background: color-mix(in srgb, var(--district) 30%, #18201e); box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--district) 65%, #18201e); }
.district-label { position: absolute; top: 3px; left: 4px; color: var(--district); font: bold 11px/1 Jost, sans-serif; z-index: 1; }
.roof-blocked { color: #d7d3c088; font-size: 24px; }
.rooftop.conflict { outline: 2px solid #e28d79; outline-offset: -3px; }
.rooftop.conflict::after { content: '!'; position: absolute; right: 3px; bottom: 2px; color: #fff; background: #a53e2b; border-radius: 50%; width: 16px; font: bold 13px/16px Jost, sans-serif; }
.puzzle-loads { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 4px; margin-bottom: 8px; }
.puzzle-load { min-height: 44px; min-width: 0; padding: 3px; display: flex; align-items: center; justify-content: center; gap: 5px; color: #d0ad6e; border-color: #766549; background: #2b2723; }
.puzzle-load b { font: 11px Jost, sans-serif; }
.puzzle-load svg { width: 34px; height: 34px; }
.puzzle-load:disabled { opacity: .3; }
.puzzle-load.selected, .puzzle-rack.selected { border-color: #ffe3a2; box-shadow: inset 0 0 0 2px #e1bf7a; background-color: #514832; }
.puzzle-rotate { grid-column: span 2; min-height: 44px; padding: 4px; font: 13px Jost, sans-serif; }
.grid-freight { padding: 3px; border: 3px double #a38657; background: #171b17; }
.cargo-cell { background: repeating-linear-gradient(90deg, #403b2d 0 10px, #302f24 10px 11px); border-color: #635a3e; }
.freight-slot { color: #b8a57266; font: 20px Jost, sans-serif; }
.load-number { position: absolute; bottom: 2px; right: 4px; font: bold 12px Jost, sans-serif; color: #fff0cb; text-shadow: 0 1px 3px #000; }
.socket { background: #30291f; border-color: #635039; }
.socket svg { display: block; width: 100%; height: 100%; }
.socket.live { background: #51432a; }
.contact-number { position: absolute; top: 2px; right: 3px; color: #211e17; background: #cfae65; border: 1px solid #f6d593; border-radius: 50%; width: 16px; font: bold 11px/14px Jost, sans-serif; }
.wire-end { position: absolute; left: 3px; bottom: 2px; color: #ffe2a2; font: bold 9px Jost, sans-serif; }
.puzzle-racks { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 9px 6px; }
.puzzle-rack { min-width: 0; min-height: 44px; padding: 4px; border: 1px solid #7d6847; border-radius: 4px; background: linear-gradient(90deg, #493727, #24211e 12%, #24211e 88%, #493727); }
.rack-cases { display: flex; flex-direction: column; gap: 2px; }
.rack-cases > i { display: flex; align-items: center; justify-content: center; height: 25px; font-style: normal; }
.case-empty { border: 1px dashed #91805b33; }
.contraband-case { border: 1px solid var(--brand); background: color-mix(in srgb, var(--brand) 25%, #20251e); }
.contraband-case .puzzle-art { width: 25px; height: 25px; }
.contraband-case b { font: bold 14px Jost, sans-serif; color: var(--brand); }
.puzzle-rack small { display: block; margin-top: 5px; font: 10px Jost, sans-serif; color: #d6c49b; }
.puzzle-progress { min-height: 18px; margin: 8px 0; color: #e4c17e; font: 12px/1.4 Jost, sans-serif; }
.puzzle-controls { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.puzzle-controls button { min-width: 0; min-height: 44px; padding: 6px; font: 13px Jost, sans-serif; }
.puzzle-tip { padding-left: 10px; border-left: 2px solid #ba9556; font: 13px/1.4 Jost, sans-serif; color: #d7d4c4; }
.puzzle-purse { margin-top: 10px; font: 12px Jost, sans-serif; }
.puzzle-purse summary { cursor: pointer; color: #c5b890; min-height: 30px; padding-top: 5px; }
@media (max-width: 400px) {
  .sheet[data-panel="ladder"] { width: calc(100% - 12px); }
  .sheet[data-panel="ladder"] .sheet-body { padding: 8px; }
  .puzzle-workbench { padding: 4px; }
  .puzzle-heading h3 { font-size: 18px; }
  .puzzle-hero { width: 56px; height: 56px; }
  .puzzle-rule { font-size: 13px; }
  .puzzle-grid { gap: 1px; }
}
/* Fit the entire job on a phone without inheriting the generic sheet button padding. */
.sheet-body .puzzle-tile { padding: 0; }
.sheet-body .puzzle-load { padding: 3px; min-height: 44px; }
.sheet-body .puzzle-rack { padding: 4px; }
.sheet-body .puzzle-rack small { font-size: 10px; }
.sheet-body .puzzle-rotate { padding: 4px; font-size: 12px; }
.puzzle-grid { width: min(100%, max(240px, calc(var(--cols) * 48px))); }
.puzzle-loads { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 3px; }
.puzzle-load svg { width: 25px; height: 30px; }
.puzzle-rotate { grid-column: span 1; }
.rack-cases > i { height: 21px; }
.contraband-case .puzzle-art { width: 21px; height: 21px; }
@media (max-width: 400px) {
  .sheet[data-panel="ladder"] { left: 6px; }
  .puzzle-heading { gap: 8px; }
  .puzzle-rule { margin-bottom: 8px; }
}

@media (max-width: 719px) {
  .sheet[data-panel="ladder"]:has(.ladder-puzzle) { max-height: calc(100dvh - 24px - var(--safe-bottom)); }
}


/* Playtest polish: give the playable scene room, with a compact phone fallback. */
#sheet[data-panel="ladder"]:has(.ladder-puzzle, .battle-stage) { width: min(860px, calc(100vw - 32px)); max-height: calc(100dvh - 32px); }
#sheet[data-panel="ladder"]:has(.ladder-puzzle, .battle-stage) .sheet-body { padding: 16px; }
.puzzle-scene { padding: 14px; border: 1px solid #a28754; border-radius: 9px; background: linear-gradient(#1d1b1844,#141311cc), url('./assets/battle/courtyard.webp') center/cover; box-shadow: inset 0 0 50px #0009; }
.puzzle-scene-caption { color: #f0d9a7; text-shadow: 0 2px 3px #000; text-transform: uppercase; letter-spacing: .12em; font: 12px/1.4 var(--display); margin: 0 0 12px; }
.puzzle-workbench { padding: 18px; background: #181613c9; border-color: #927449; overflow: hidden; }
.puzzle-grid { width: min(100%, 440px); gap: 6px; }
.puzzle-heading h3 { font-size: 27px; }
.puzzle-rule { max-width: 680px; font-size: 15px; }
.puzzle-racks { gap: 14px; }
.sheet-body .puzzle-rack { padding: 9px 7px; border-width: 3px; border-bottom-width: 9px; box-shadow: 5px 6px 0 #130f0baa, inset 0 0 18px #0009; }
.rack-cases > i { height: 58px; border-bottom-width: 4px; }
.contraband-case .puzzle-art { width: 55px; height: 55px; }
.contraband-case b { font-size: 18px; }
.sheet-body .puzzle-rack small { font-size: 12px; }
.car-cell { background: #22282499; border: 1px dashed #baa17080; overflow: visible; }
.car-cell .puzzle-art { transform: rotate(var(--car-angle, 0deg)); }
.escape-arrow { background: #0b161de6; border: 1px solid #c1a46e; border-radius: 50%; width: 29px; height: 29px; text-align: center; font-size: 25px; right: 3px; bottom: 3px; }
.grid-lookouts { gap: 8px; }
.rooftop { border-width: 3px; border-bottom-width: 8px; box-shadow: 3px 5px 0 #090d0ccc, inset 0 0 0 2px var(--district); background: linear-gradient(135deg,#fff1, #0006), color-mix(in srgb, var(--district) 24%, #18201e); }
.district-label { font-size: 15px; }
.scene-freight { background: linear-gradient(#201a12aa,#101511dd), url('./assets/battle/courtyard.webp') center/cover; }
.puzzle-loads { grid-template-columns: repeat(4,minmax(0,1fr)); gap: 7px; }
.sheet-body .puzzle-load { min-height: 56px; padding: 5px; }
.puzzle-load svg { width: 44px; height: 40px; }
.puzzle-load b { font-size: 14px; }
.grid-freight { border: 8px ridge #847455; padding: 7px; box-shadow: 0 7px 0 #111; }
.scene-switchboard .puzzle-workbench { background: repeating-linear-gradient(0deg,#3b271d,#3b271d 5px,#362319 6px,#483023 9px); border: 6px ridge #8c6840; }
.socket { border: 3px ridge #957345; border-radius: 50%; background: radial-gradient(#4c3a25,#181613); box-shadow: 0 3px 7px #0009; }
.socket.live { box-shadow: 0 0 12px #e8b55a66; }
.contact-number { width: 23px; font-size: 14px; line-height: 21px; }
.wire-end { font-size: 12px; }
.puzzle-progress { font-size: 14px; }
.battle { max-height: min(64dvh,620px); }
.battle .fig.enemy .fighter-pose { filter: sepia(.4) saturate(1.15); }
.battle .fig:not(.enemy) .fighter-pose { filter: drop-shadow(0 0 2px #67b7c8); }
.climb-debrief { border-left: 3px solid #cfaa68; padding: 8px 14px; background: #1b1916; margin: 12px 0; }
.climb-debrief h3 { margin: 0; font-size: 17px; }
.climb-debrief p { font-size: 14px; line-height: 1.45; }
.chip-training-toggle { grid-column: 1 / -1; font-size: 12px; min-height: 44px; }
@media (max-width: 719px) {
  #sheet[data-panel="ladder"]:has(.ladder-puzzle, .battle-stage) { width: calc(100% - 12px); left: 6px; max-height: calc(100dvh - 20px - var(--safe-bottom)); }
  #sheet[data-panel="ladder"]:has(.ladder-puzzle, .battle-stage) .sheet-body { padding: 8px; }
  .puzzle-heading h3 { font-size: 20px; }
  .puzzle-rule { font-size: 13px; }
  .puzzle-scene { padding: 6px; }
  .puzzle-scene-caption { font-size: 10px; margin-bottom: 6px; }
  .puzzle-workbench { padding: 4px; }
  .puzzle-grid, .grid-lookouts { gap: 1px; }
  .puzzle-racks { gap: 4px; }
  .sheet-body .puzzle-rack { padding: 3px; border-width: 1px; border-bottom-width: 5px; }
  .rack-cases > i { height: 30px; }
  .contraband-case .puzzle-art { width: 30px; height: 30px; }
  .contraband-case b { font-size: 13px; }
  .puzzle-loads { grid-template-columns: repeat(4,minmax(0,1fr)); gap: 3px; }
  .sheet-body .puzzle-load { min-height: 44px; }
  .puzzle-load svg { width: 30px; height: 30px; }
  .grid-freight { border-width: 3px; padding: 2px; }
  .scene-switchboard .puzzle-workbench { border-width: 3px; }
  .puzzle-tile { min-height: 40px; }
}
@media (prefers-reduced-motion: reduce) { .puzzle-tile, .puzzle-art { animation: none; transition: none; } }
@media (max-width: 400px) {
  .puzzle-scene { padding: 3px; }
  .puzzle-workbench { padding: 2px; }
  .puzzle-tile { min-height: 44px; }
  .puzzle-controls { position: sticky; bottom: 0; background: #272420; padding: 6px 0; z-index: 3; }
}

/* Small skirmishes: crisp clipping, restrained side cues, no glowing cutouts. */
.battle .fig .fighter-pose { filter: none; }
.battle .fig.enemy .fighter-pose { filter: none; }
.battle .fig:not(.enemy) .fighter-pose { filter: none; }
.battle .fig.down { opacity: .65; }
.battle-representation { margin: 0; padding: 5px 10px; background: #201f1a; color: #b6b7aa; font-size: 11px; text-align: center; }

.raid-risk { margin: 12px 0; padding: 10px 12px; border: 1px solid #bc9755; border-radius: 6px; background: #292b22; }
.raid-risk strong { text-transform: capitalize; color: #e3c78e; }
.raid-risk p { margin: 6px 0; }
.raid-risk small { display: block; line-height: 1.45; color: #c1c6b9; }
#opening-card #opening-diversion { grid-column: 1 / -1; grid-row: 3; min-width: 0; max-width: none; justify-self: stretch; min-height: 44px; white-space: normal; overflow-wrap: anywhere; background: #34302b; }


/* Compact missions and consistent resource symbols. */
.cell .k { display:flex; align-items:center; gap:4px; }
.cell .k svg { width:16px; height:16px; flex:none; }
.resource-amount { display:inline-flex; align-items:center; gap:3px; white-space:nowrap; }
.resource-amount svg { width:17px; height:17px; flex:none; }
.reward-grid strong { display:flex; align-items:center; justify-content:center; gap:5px; }
.mission-tabs { display:flex; gap:8px; margin-bottom:14px; }
.mission-tabs button { flex:1; min-height:44px; }
.mission-tabs button[aria-pressed="true"] { color:var(--cream); border-color:var(--brass); background:#ac85472b; }
.ladder-step { grid-template-columns:minmax(0,1fr) auto; align-items:center; gap:8px; padding:12px 0; }
.ladder-step > strong { font-size:15px; }
.ladder-step .ladder-bag { display:flex; flex-wrap:wrap; justify-content:flex-end; gap:5px; }
.ladder-step .ladder-bag small { width:100%; text-align:right; letter-spacing:0; text-transform:none; }
.ladder-step button { grid-column:2; margin:0; min-height:36px; padding:5px 12px; }
.ladder-step .ladder-wait { grid-column:2; text-align:right; }
.quick-job-pages { display:flex; align-items:center; justify-content:space-between; gap:12px; }
.quick-job-pages button { min-height:44px; }
.takeover-portrait { background-image:url('./assets/takeover-portraits.png'); background-size:400% 300%; aspect-ratio:3/4; }
.world-location { position:absolute; z-index:3; left:12px; bottom:62px; display:flex; gap:8px; align-items:center; pointer-events:none; }
.world-location button, .world-location output { pointer-events:auto; background:#141b1ced; color:var(--cream); border:1px solid #af93665c; padding:8px; border-radius:4px; }
.world-location button { min-height:44px; font-size:12px; }
.world-location output { font:13px var(--display); font-variant-numeric:tabular-nums; }
.crew-queue-row .crew-trip-link { position:static; display:block; opacity:1; width:100%; height:auto; border:0; background:transparent; text-align:left; padding:4px 0; }
.crew-trip-link > div:first-child { display:flex; justify-content:space-between; gap:8px; }

#dash-sub .v { display:flex; align-items:center; gap:3px; }
#dash-sub .v svg { width:15px; height:15px; flex:none; }

/* Compact missions and indivisible numeric values, including narrow phones. */
.reward-grid strong, .resource-amount, .daily-count, .daily-chips, .res-value, .heat-cost { white-space:nowrap; word-break:normal; overflow-wrap:normal; }
.reward-grid { grid-template-columns:repeat(auto-fit,minmax(116px,1fr)); }
.reward-grid strong { font-size:clamp(20px,5vw,28px); }
.ladder-step { gap:4px 8px; padding:7px 0; }
.ladder-step:not(.is-ready) { grid-template-rows:auto; }
.world-location { left:50%; transform:translateX(-50%); bottom:12px; gap:12px; }
.world-location button { display:grid; place-items:center; width:44px; padding:8px; }
.world-location output { white-space:nowrap; }
.world-find { position:absolute; right:12px; bottom:12px; z-index:4; min-height:44px; padding:8px 12px; background:#141b1c; border:1px solid #a68b57; }
.world-heading { justify-content:center; }
.find-level { display:grid; grid-template-columns:auto minmax(50px,1fr) 64px; align-items:center; gap:12px; }
.find-level input { min-width:0; width:100%; }
.find-level input[type=number] { padding:10px 5px; color:var(--cream); background:#141b1c; border:1px solid #8b7957; }
.prize-wheel-wrap { position:relative; width:min(280px,82vw); aspect-ratio:1; margin:24px auto; }
.prize-wheel { width:100%; height:100%; border-radius:50%; border:7px solid #b69958; box-shadow:0 4px 20px #0008; transition:transform 3.1s cubic-bezier(.12,.72,.16,1); }
.wheel-pointer { position:absolute; z-index:2; left:calc(50% - 12px); top:-15px; color:#fff2c6; font-size:26px; text-shadow:0 2px 3px #000; }
.wheel-hub { position:absolute; inset:38%; border-radius:50%; display:grid; place-items:center; background:#141b1c; border:2px solid #cfb477; font:700 24px var(--display); color:#e7c875; }
.wheel-result { text-align:center; }
.wheel-legend { padding:0; list-style:none; }
.wheel-legend li { display:grid; grid-template-columns:12px 1fr auto; gap:8px; padding:4px 0; align-items:center; }
.wheel-legend i { width:10px; height:10px; border-radius:50%; }
@media(prefers-reduced-motion:reduce) { .prize-wheel { transition:none; } }
.numeral { display:inline !important; font:inherit !important; color:inherit !important; letter-spacing:inherit !important; margin:0 !important; white-space:nowrap; overflow-wrap:normal; word-break:normal; }
.prize-wheel { position:relative; }
.wheel-sector-number { position:absolute; transform:translate(-50%,-50%); color:#fff8df; font:600 12px var(--display); text-shadow:0 1px 2px #000; }
.world-location { display:block; }
.world-location output { display:block; font-size:12px; }
.world-location button { position:absolute; left:calc(100% + 12px); top:50%; transform:translateY(-50%); }
.world-find { min-width:50px; padding:8px; }
.wheel-sector-number { display:grid; justify-items:center; gap:1px; line-height:1; }
.wheel-sector-number svg { width:18px; height:18px; filter:drop-shadow(0 1px 1px #0008); }
.wheel-sector-number small { font:600 9px var(--display); }
.wheel-sector-number b { font:700 10px var(--display); }
/* Resource cells must not inherit the horizontal research-chip layout. */
.dash-sub .cell.chips { display:block; margin:0; }

/* Compact encounter details and a shared dispatch picker. */
.climb-purse .reward-grid, .shipment-job .reward-grid { display:flex; flex-wrap:nowrap; gap:6px; }
.climb-purse .reward-grid > *, .shipment-job .reward-grid > * { flex:1; min-width:0; padding:8px 3px; }
.climb-purse .reward-grid strong, .shipment-job .reward-grid strong { font-size:clamp(14px,4vw,22px); }
.raid-actions { display:flex; gap:8px; align-items:center; }
.raid-actions button { flex:1; min-width:0; }
.sheet[data-panel="raid"] .row .k { white-space:nowrap; flex:0 0 auto; }
.job-guide { fill:#e2b76a; font-size:70px; animation:guide-pulse 1s ease-in-out infinite alternate; pointer-events:none; }
@keyframes guide-pulse { to { opacity:.35; } }
@media (prefers-reduced-motion: reduce) { .job-guide { animation:none; } }


/* Timed jobs and unmistakable contraband destinations. */
.puzzle-timer { display:flex; align-items:center; gap:12px; padding:10px 12px; margin:8px 0; border:1px solid #a88d57; border-radius:6px; background:#221f1b; }
.puzzle-timer strong { font:700 24px/1.2 var(--display); font-variant-numeric:tabular-nums; color:#f3d89d; }
.puzzle-timer span { font-size:12px; }
.puzzle-timer.urgent, .puzzle-timer.expired { border-color:#d87857; background:#3b241e; }
.puzzle-feedback { margin:8px 0; color:#f0dba8; min-height:2.8em; font-size:13px; }
/* The selected rack, and the racks it can move to.
 *
 * Both are outlines rather than box-shadows, and both live down here after
 * `.sheet-body .puzzle-rack`. That rule sets its own box-shadow at the same
 * specificity as `.puzzle-rack.selected` and later in the file, so it won
 * -- which left the rack you tapped looking untouched while the racks it
 * could move to lit up green, and made tapping a rack read as highlighting
 * the wrong ones. */
.puzzle-rack.selected { outline:3px solid #ffe3a2; outline-offset:1px; background:#514832; }
.puzzle-rack.can-receive { outline:2px solid #88c99f; outline-offset:1px; background:#3c3731; }
.puzzle-rack.selected .contraband-case.is-top { box-shadow:0 0 0 2px #ffe6a6; }
.puzzle-case-flight { border:2px solid #ffe6a6; border-radius:3px; box-shadow:0 5px 12px #0009; justify-content:center; align-items:center; }
.march-wheel { opacity:.45; }


/* ------------------------------------------------------- the family tree */

/*
 * Seven chairs, drawn as the shape the org actually has: one at the top, two
 * under it, four under those. The connectors are pseudo-elements rather than
 * an SVG overlay because the rows reflow — four Capos are two-up on a narrow
 * phone — and a drawn line would have to be re-measured every time they did.
 */
.family-tree { display:grid; gap:0; margin:0 0 18px; }
.tree-rank { display:flex; gap:8px; justify-content:center; flex-wrap:wrap; align-items:stretch; position:relative; }
/* One Underboss's pair of Capos, kept together when the row wraps. */
.tree-branch { display:flex; gap:8px; flex:1 1 240px; min-width:0; align-items:stretch; position:relative; }
.tree-rank + .tree-rank { margin-top:22px; }
/* The stem out of the rank above, and the rail the chairs below hang from. */
.tree-rank + .tree-rank::before {
  content:""; position:absolute; top:-22px; left:50%; width:1px; height:11px;
  background:#a2804c; transform:translateX(-.5px);
}
.tree-rank + .tree-rank::after {
  content:""; position:absolute; top:-11px; left:14%; right:14%; height:11px;
  border:1px solid #a2804c; border-bottom:0; border-radius:4px 4px 0 0;
}
.tree-rank:only-child::before, .tree-rank:only-child::after { display:none; }

/*
 * The Capos hang off their own Underboss, not off the rank as a whole, so the
 * connector belongs to the branch rather than to the row — otherwise one rail
 * over four chairs claims a reporting line that does not exist, and says the
 * wrong thing twice over once the branches wrap onto separate lines.
 */
.tree-capos { row-gap:22px; margin-top:22px; }
.tree-capos::before, .tree-capos::after { display:none; }
.tree-branch::before {
  content:""; position:absolute; top:-22px; left:50%; width:1px; height:11px;
  background:#a2804c; transform:translateX(-.5px);
}
.tree-branch::after {
  content:""; position:absolute; top:-11px; left:24%; right:24%; height:11px;
  border:1px solid #a2804c; border-bottom:0; border-radius:4px 4px 0 0;
}

.family-chair, .family-person {
  display:flex; flex-direction:column; align-items:stretch; gap:6px; text-align:left;
  padding:8px 10px; flex:1 1 150px; min-width:0; max-width:240px;
  border:1px solid #6f6047; border-radius:6px; background:#221f1b; color:inherit;
  font:inherit;
}
.family-chair.boss { max-width:280px; border-color:#e0bb72; background:#2e2a26; }
.family-chair.underboss { border-color:#bfa066; }
.family-chair.empty { border-style:dashed; }
.family-chair.open { border-color:#8fd0a3; border-style:solid; background:#2f2b26; }
.family-chair.held, .family-person.held { box-shadow:0 0 0 2px #f2d596; background:#39342e; }
.family-person { flex:1 1 100%; max-width:none; }

/* The chair's own line. It names the rank once, so the card in it does not. */
.chair-rank {
  display:flex; align-items:baseline; gap:6px;
  font:500 9.5px/1.4 var(--body); letter-spacing:.14em; text-transform:uppercase;
  color:#e6c98d; border-bottom:1px solid #6f604733; padding-bottom:5px;
}
.chair-rank small { margin-left:auto; color:#9c8f74; letter-spacing:.03em; text-transform:none; font-size:10.5px; white-space:nowrap; }
.chair-body { display:flex; align-items:center; gap:9px; min-height:40px; min-width:0; }
.chair-empty { font-size:12.5px; font-style:italic; color:#9a8f79; }
.family-chair.open .chair-empty { color:#a9d8b8; font-style:normal; }

.family-face { flex:0 0 auto; width:34px; }
.family-face .mugshot { display:block; width:34px; height:40px; }
.family-who { display:grid; gap:1px; min-width:0; }
.family-who strong { font-size:13.5px; line-height:1.2; }
.family-role { font-size:11px; color:#c6b89e; }
.family-bonus { font-size:11.5px; line-height:1.3; color:#e4d6bd; }
.family-bonus em { display:block; color:#9c8f74; font-style:normal; font-size:10.5px; }
.family-held { align-self:flex-start; font:500 9.5px/1 var(--body); letter-spacing:.12em; text-transform:uppercase; color:#f2d596; }

.family-bench-head { margin:16px 0 8px; font:500 11.5px/1 var(--body); letter-spacing:.2em; text-transform:uppercase; color:var(--brass); }
.family-bench { display:grid; gap:8px; margin-bottom:14px; }
.family-tutorial { padding:10px 12px; margin:0 0 14px; border:1px solid #a9855073; border-radius:6px; background:#332f2a; }
.family-tutorial strong { display:block; color:#ffe6b6; font-size:14px; margin-bottom:4px; }
.family-tutorial p { margin:0; font-size:12.5px; line-height:1.45; color:#e4d6bd; }

/* Fifty slots, and an honest picture of how empty they are. */
.inventory-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(52px, 1fr)); gap:6px; margin:12px 0; }
.inventory-slot {
  aspect-ratio:1; border:1px solid #57503f; border-radius:5px; background:#1a1816;
  display:flex; align-items:center; justify-content:center;
  font-size:10px; text-align:center; color:#c6b89e; overflow:hidden; padding:2px;
}
.inventory-slot.filled { border-color:var(--brass); background:#2e2a26; }

/* ------------------------------------------------------------- no world yet */

/*
 * The door, for a page reached without a city. Deliberately plain: it is not a
 * game screen and should not look like one loading.
 */
.no-world-body {
  display: grid;
  place-items: center;
  min-height: 100svh;
  margin: 0;
  padding: 0 24px;
  background: var(--ink);
}

.no-world {
  max-width: 34rem;
  text-align: center;
  color: var(--cream-dim);
}

.no-world h1 {
  margin: 0 0 1.25rem;
  color: var(--brass);
  font-size: clamp(1.75rem, 7vw, 2.75rem);
  letter-spacing: 0.08em;
}

.no-world p { margin: 0 0 1rem; line-height: 1.6; }

.no-world-hint { color: var(--cream-dim); font-size: 0.95rem; }

.no-world code {
  padding: 0.15em 0.4em;
  border: 1px solid var(--rule);
  border-radius: 4px;
  background: var(--panel);
  color: var(--cream);
}

.door-providers { display: grid; gap: 10px; margin: 1.5rem 0 0; }

.door-button {
  display: block;
  padding: 0.85rem 1rem;
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: var(--panel-2);
  color: var(--cream);
  text-decoration: none;
  font-weight: 600;
}

.door-apple { background: #111; border-color: #333; }
.door-google { background: #f4f4f2; color: #1f1f1f; border-color: #d8d8d4; }

/* Says which of the two screens you are on, because they ask for different
 * things and the buttons alone were doing that work. */
.door-heading {
  margin: 0 0 0.2rem;
  font: 600 1.35rem/1.2 var(--display);
  color: var(--cream);
  letter-spacing: 0.02em;
}

.door-or {
  margin: 1.1rem 0 0.4rem;
  color: var(--cream-dim);
  font-size: 0.85rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.door-form { display: grid; gap: 10px; text-align: left; margin-top: 0.5rem; }

.door-form label {
  display: grid;
  gap: 4px;
  color: var(--cream-dim);
  font-size: 0.85rem;
}

.door-form input {
  padding: 0.7rem 0.75rem;
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: var(--ink-2);
  color: var(--cream);
  font: inherit;
  /* 16px or iOS zooms the page on focus and the door jumps. */
  font-size: 16px;
}

.door-form button { margin-top: 4px; }
.door-error { margin: 0; color: var(--red-bright); font-size: 0.9rem; }
.door-error[hidden] { display: none; }

.door-note { margin: 0; color: var(--green); font-size: 0.9rem; }
.door-note[hidden] { display: none; }

.door-quiet {
  margin-top: 2px;
  border: 0;
  background: none;
  color: var(--cream-dim);
  font: inherit;
  font-size: 0.85rem;
  text-decoration: underline;
}


/* ========================================================================
   CITY SCREEN V2
   Approved 2026-09-29 City mockup. Scoped to the City shell only.
   ======================================================================== */
:root{
  --v2-panel:#171512;--v2-brass:#c99043;--v2-paper:#ecd7ad;
  --v2-red:#b72f27;--v2-teal:#28d0b1;--v2-cream:#f6e8c8;
}
.city-rebuild-hud{
  position:relative;z-index:8;
  background:linear-gradient(180deg,rgba(255,255,255,.025),transparent 45%),var(--v2-panel);
  border:2px solid #75512b;border-left:0;border-right:0;
  box-shadow:inset 0 0 0 1px #d5a25255,0 4px 10px #0007;
}
.city-rebuild-hud .dash-main{grid-template-columns:1fr 1fr .92fr}
.city-rebuild-hud .dash-sub{border-top:2px solid #76532d}
.city-rebuild-hud .cell{
  position:relative;min-height:62px;padding:7px 8px 6px;border-right:2px solid #76532d;
  background:linear-gradient(135deg,rgba(255,255,255,.018),transparent 55%);
}
.city-rebuild-hud .dash-sub .cell{min-height:51px;padding:5px 6px}
.city-rebuild-hud .cell::after{
  content:'';position:absolute;right:-4px;top:-4px;width:6px;height:6px;border-radius:50%;
  background:#d7a253;border:1px solid #51371d;z-index:2;
}
.city-rebuild-hud .cell .k{color:var(--v2-cream);font-weight:600;letter-spacing:.08em;font-size:9px}
.city-rebuild-hud .cell .v{color:var(--v2-cream);font-size:21px;font-weight:600;text-shadow:0 1px #000}
.city-rebuild-hud .dash-sub .cell .v{
  display:flex;align-items:center;justify-content:flex-start;gap:5px;line-height:1;font-size:15px;
}
.city-rebuild-hud .dash-sub .cell .v svg{
  flex:0 0 27px;width:27px!important;height:27px!important;margin-right:2px;
}
.city-rebuild-hud .dash-sub .cell:nth-child(1) .v svg{color:#d95a35!important}
.city-rebuild-hud .dash-sub .cell:nth-child(2) .v svg{color:#d9c7a1!important}
.city-rebuild-hud .dash-sub .cell:nth-child(3) .v svg{color:#b08a55!important}
.city-rebuild-hud .dash-sub .cell:nth-child(4) .v svg{color:#e6b54c!important}
.city-rebuild-hud .dash-sub .cell:nth-child(5) .v svg{color:#d64035!important}
.city-rebuild-hud .cell .r{color:var(--v2-teal);font-size:11px;font-weight:600}
.city-rebuild-hud .cell.dirty .v,.city-rebuild-hud .cell.chips .v{color:var(--v2-cream)}
.city-rebuild-hud svg{filter:drop-shadow(0 1px 1px #0008)}

.v2-money{display:flex;align-items:center;gap:7px}
.v2-money-copy,.v2-heat-copy{display:block;min-width:0;flex:1}
.v2-cash-art{position:relative;display:block;flex:0 0 46px;width:46px;height:42px;transform:skewY(-5deg)}
.v2-cash-art i{position:absolute;left:2px;width:40px;height:14px;border:1.4px solid currentColor;border-radius:1px;box-shadow:0 2px 1px #0007}
.v2-cash-art i:nth-child(1){bottom:0}.v2-cash-art i:nth-child(2){bottom:5px}.v2-cash-art i:nth-child(3){bottom:10px}.v2-cash-art i:nth-child(4){bottom:15px}.v2-cash-art i:nth-child(5){bottom:20px}
.v2-cash-art b{position:absolute;z-index:3;left:17px;top:4px;font:700 13px Georgia,serif;transform:skewY(5deg)}
.clean-art{color:#31533e}.clean-art i{background:#ded8b6}
.dirty-art{color:#741a18}.dirty-art i{background:#d24b43}
.v2-heat{display:grid;grid-template-columns:46px minmax(0,1fr);align-items:center;column-gap:7px}
.v2-heat-badge{position:relative;width:43px;height:48px;display:grid;place-items:center;background:linear-gradient(145deg,#ffd274,#b36e1e);clip-path:polygon(50% 0,93% 13%,88% 66%,50% 100%,12% 66%,7% 13%);filter:drop-shadow(0 2px 1px #0008)}
.v2-heat-badge::before{content:'';position:absolute;width:34px;height:38px;background:#d99d35;clip-path:polygon(50% 0,93% 13%,88% 66%,50% 100%,12% 66%,7% 13%)}
.v2-heat-badge b{position:relative;z-index:1;color:#734615;font:700 21px Georgia,serif;text-shadow:0 1px #ffe1a3}
.v2-heat-copy .k{display:block}.v2-heat-copy .heat-top{margin-top:-2px}

.city-rebuild-objective{
  position:relative;z-index:7;min-height:69px;padding:8px 10px 9px 14px;
  grid-template-columns:minmax(0,1fr) auto;column-gap:8px;color:#17110b;
  background:radial-gradient(circle at 18% 10%,#fff5d855,transparent 20%),linear-gradient(95deg,#e6c996,#f3dfb9 55%,#dfbf89);
  border:0;border-bottom:2px solid #60401f;box-shadow:0 4px 9px #0006;
}
.city-rebuild-objective::before,.city-rebuild-objective::after{
  content:'';position:absolute;left:0;right:0;height:5px;opacity:.48;
  background:repeating-linear-gradient(102deg,transparent 0 11px,#5e3e20 12px 13px,transparent 14px 23px);
}
.city-rebuild-objective::before{top:-2px}.city-rebuild-objective::after{bottom:-2px;transform:scaleX(-1)}
.city-rebuild-objective .opening-eyebrow{display:inline-block;width:max-content;padding:2px 8px;background:var(--v2-red);color:#fff0d8;font-weight:700;font-size:10px}
.city-rebuild-objective strong{color:#17110b;font-size:15px;font-weight:600}
.city-rebuild-objective button{
  min-width:116px;min-height:52px;padding:6px 10px;border-radius:5px;border:2px solid #552018;
  background:linear-gradient(#cf3d31,#9d2822);box-shadow:inset 0 0 0 2px #ed765944,0 2px 0 #4c1b16;
  color:#fff0dc;font-size:13px;font-weight:700;text-transform:uppercase;
}
.city-rebuild-objective #opening-action{display:grid;place-items:center;line-height:1.02}
.city-rebuild-objective .v2-cta-main{display:block;font-size:13px;font-weight:700}
.city-rebuild-objective .v2-cta-sub{display:block;font-size:10px;letter-spacing:.12em;margin-top:2px;color:#ffd8b6}

.city-rebuild-stage{
  background:#0a0f10;
}
.city-rebuild-stage::before{
  content:'';position:absolute;inset:0;pointer-events:none;z-index:0;
  background:none;
}
.city-rebuild-stage::after{background:none}
.city-rebuild-stage #base{position:relative;z-index:1;filter:saturate(.96) contrast(1.04) brightness(1.08)}
.city-rebuild-stage .city-horizon{position:relative;z-index:1;opacity:.9;filter:saturate(.92) brightness(1.12)}
.city-rebuild-stage .district-mark{opacity:.62}
.city-rebuild-stage .block-guide,.city-rebuild-stage .queue-dock,.city-rebuild-stage .toasts,.city-rebuild-stage .recenter{z-index:5}
.city-rebuild-stage .recenter{
  width:54px;height:54px;right:12px;bottom:12px;border-radius:50%;color:var(--v2-cream);
  background:#141b1ce8;border:2px solid var(--v2-brass);box-shadow:inset 0 0 0 2px #261a0f,0 4px 12px #0009;
}
.city-rebuild-stage .recenter svg{width:22px;height:22px}
.city-rebuild-stage .block-guide span{border:2px solid #b18448;border-radius:4px;background:#0b201ee8;color:#f4dfb6;box-shadow:inset 0 0 0 1px #0008,0 3px 9px #0008;font-weight:600}
.city-rebuild-stage .block-guide svg path{fill:#ffd14d;stroke:#704b1f;stroke-width:1}
.city-rebuild-stage .backdrop{filter:saturate(.96)}
.city-rebuild-stage .plot:not(.selected){filter:none}
.city-rebuild-stage .plot.selected{filter:brightness(1.08) saturate(1.05)}
.city-rebuild-stage .street-life{opacity:.95}
.city-rebuild-stage .chimney-steam .steam{fill:#c4b39b;opacity:.22}
.city-rebuild-stage .lot-ground{filter:saturate(.9) brightness(1.02)}
.city-rebuild-stage .plot-empty circle{fill:#102522;stroke:#d6a052;stroke-width:2}
.city-rebuild-stage .plot-empty rect{fill:#0b1c1ae8;stroke:#b78345}
.city-rebuild-stage .plot-label{fill:#f1d8a7;stroke:#0a1210;stroke-width:4px;font-weight:600}
.city-rebuild-stage .lvl{fill:#f6c867;font-weight:700}

/* THE FILTER GOES ON THE WRAPPER, NEVER ON `.v2-building-art`.
   That element is a nested `<svg>` whose viewBox crops one milestone out of a
   seven-milestone sheet, and `overflow:hidden` is what does the cropping. A
   CSS filter on the same element feeds the filter the *uncropped* content and
   never re-applies the clip, so every lot painted its building's whole
   progression row -- all seven levels, side by side, across the block. Moving
   the filter one element out to the group leaves the crop to run on its own
   and keeps the warmth and the drop shadow. Same trap as `.v3-tree`. */
.city-v2-building{filter:saturate(1.03) contrast(1.06) brightness(1.08) drop-shadow(0 4px 3px rgba(0,0,0,.5))}
.city-v2-building[data-building="mansion"]{filter:saturate(1.08) contrast(1.07) brightness(1.13) drop-shadow(0 5px 4px rgba(0,0,0,.55))}
.city-v2-building[data-building="distillery"],.city-v2-building[data-building="speakeasy"]{filter:saturate(1.06) contrast(1.08) brightness(1.08) drop-shadow(0 4px 3px rgba(0,0,0,.52))}
.v2-building-warmth{filter:blur(5px)}
.v2-street-life .street-car{filter:brightness(.92) saturate(.82) drop-shadow(0 2px 1px #0009)}
.v2-street-life .street-walker{filter:brightness(.92) drop-shadow(0 1px 1px #0009)}
.v2-lamp-pool{mix-blend-mode:screen}

.city-rebuild-tabs{
  position:relative;z-index:8;min-height:78px;background:linear-gradient(180deg,#1a1816,#11100e);
  border-top:2px solid var(--v2-brass);box-shadow:0 -4px 12px #0007;
}
.city-rebuild-tabs .tab{min-height:76px;padding:6px 1px 5px;gap:4px;color:#efd8aa;border-right:2px solid #73502b;font-size:8px;font-weight:600;letter-spacing:.055em}
.city-rebuild-tabs .tab::before{content:'';position:absolute;left:-3px;top:-4px;width:6px;height:6px;border-radius:50%;background:#d7a253;border:1px solid #51371d}
.city-rebuild-tabs .tab svg{width:32px;height:32px;color:#e9bc6a;filter:drop-shadow(0 2px 1px #0008)}
.city-rebuild-tabs .tab[aria-selected=true]{color:#fff0c7;background:linear-gradient(#c990431c,transparent)}
.city-rebuild-tabs .tab .dot{width:13px;height:13px;transform:translate(16px,-17px);background:#e5332c;box-shadow:0 0 0 2px #f2d29a,0 2px 5px #000}

@media(max-width:520px){
  :root{--tabs-h:78px}
  .city-rebuild-hud .cell{min-height:59px}
  .city-rebuild-hud .dash-sub .cell{min-height:49px}
  .city-rebuild-hud .cell .v{font-size:19px}
  .city-rebuild-hud .dash-sub .cell .v{font-size:14px}
  .city-rebuild-objective{min-height:66px}
  .city-rebuild-tabs .tab{font-size:7.8px}
}
@media(max-width:380px){
  .v2-cash-art{transform:scale(.82) skewY(-5deg);transform-origin:left center;flex-basis:39px}
  .v2-heat{grid-template-columns:38px minmax(0,1fr);gap:4px}
  .v2-heat-badge{transform:scale(.84);transform-origin:center}
}
@media(max-width:360px){
  .city-rebuild-hud .dash-sub .cell .v svg{flex-basis:22px;width:22px!important;height:22px!important}
}
@media(max-width:350px){
  .city-rebuild-hud .cell{padding-left:5px;padding-right:5px}
  .city-rebuild-hud .cell .v{font-size:17px}
  .city-rebuild-hud .dash-sub .cell .v{font-size:12.5px}
  .city-rebuild-objective strong{font-size:13px}
  .city-rebuild-objective button{min-width:100px;font-size:11px}
  .city-rebuild-tabs .tab svg{width:28px;height:28px}
  .city-rebuild-tabs .tab{font-size:7px}
}


/* ========================================================================
   CITY CINEMATIC V3
   Visual target: approved dense waterfront mockup. This pass changes only
   presentation. Game state, hit targets and simulation remain authoritative.
   ======================================================================== */
.city-rebuild-stage .city-horizon{
  opacity:1;filter:saturate(1.1) contrast(1.05) brightness(1.15);
}
.city-v2-building{
  filter:saturate(1.14) contrast(1.08) brightness(1.13) drop-shadow(0 5px 4px rgba(0,0,0,.55));
}
.city-v2-building[data-building="mansion"]{
  filter:saturate(1.18) contrast(1.1) brightness(1.2) drop-shadow(0 7px 5px rgba(0,0,0,.62));
}
.v2-lamp-pool{opacity:1;filter:blur(1px)}
.city-rebuild-stage .street-life{opacity:1;filter:brightness(1.08) saturate(.95)}
.city-rebuild-stage .lot-ground{filter:saturate(.96) brightness(1.08)}
.city-rebuild-stage .plot.selected{filter:brightness(1.15) saturate(1.1)}
/* The environment should reach the screen edges instead of reading as a board. */
.city-rebuild-stage svg#base{overflow:visible}

@media(max-width:520px){
}

/* V3 navigation reads as six illustrated game buttons, not a web toolbar. */
.city-rebuild-tabs{position:relative;min-height:88px;background:linear-gradient(180deg,#171513,#0f0e0c);border-top:2px solid #d29c4a;box-shadow:0 -5px 12px #0009;backdrop-filter:blur(.35px)}
.city-rebuild-tabs .tab{min-height:86px;padding:7px 1px 5px;gap:3px;font-family:Georgia,serif;font-size:8.5px;font-weight:700;letter-spacing:.045em;text-shadow:0 1px #000}
.city-rebuild-tabs .tab svg{width:40px;height:40px;filter:drop-shadow(0 3px 2px #0009)}
.city-rebuild-tabs .tab[aria-selected=true]{background:radial-gradient(circle at 50% 36%,#d39b412b,transparent 48%)}
@media(max-width:520px){:root{--tabs-h:88px}.city-rebuild-tabs .tab{min-height:86px}.city-rebuild-tabs .tab svg{width:38px;height:38px}}

.v3-tree{filter:saturate(1.08) brightness(1.04) drop-shadow(0 4px 3px #0008)}
.v3-parked-car{filter:saturate(.82) brightness(.9) drop-shadow(0 3px 2px #000a)}
/* Keep the active operation readable against the newly dense district. */
.city-rebuild-stage .plot{filter:drop-shadow(0 3px 2px rgba(0,0,0,.18))}
.city-rebuild-stage .plot.selected{filter:brightness(1.16) saturate(1.12) drop-shadow(0 5px 4px rgba(0,0,0,.3))}

/* V3 parchment directive is a torn strip with an illustrated brass arrow. */
.city-rebuild-objective{
  backdrop-filter:blur(.35px);
  background:
    radial-gradient(circle at 16% 12%,#fff7dd66,transparent 20%),
    linear-gradient(96deg,#d9b879 0%,#f1d9a8 42%,#e5c58d 100%);
  border-top:1px solid #f4dfb2;border-bottom:2px solid #6c4825;
  box-shadow:0 5px 12px #0007;
}
.city-rebuild-objective .opening-eyebrow{
  display:flex;align-items:center;gap:7px;padding:0;background:none;color:#6c351e;
  font:700 10px/1 Georgia,serif;letter-spacing:.08em;text-transform:uppercase;
}
.city-rebuild-objective .opening-eyebrow i{
  display:grid;place-items:center;width:27px;height:27px;border-radius:50%;
  background:linear-gradient(#d9a64e,#9a6124);border:2px solid #70431e;
  color:#2a1c10;font:900 17px/1 Georgia,serif;box-shadow:inset 0 0 0 2px #f0c87355,0 2px 2px #0004;
}
.city-rebuild-objective strong{font-family:Georgia,serif;font-weight:700;letter-spacing:.01em}
.city-rebuild-objective button#opening-action{
  border-radius:6px;border:2px solid #5a1c17;background:linear-gradient(#d84b3d,#9d271f);
  box-shadow:inset 0 0 0 2px #f18a6b55,0 3px 0 #521a16,0 4px 8px #0005;
  font-family:Georgia,serif;
}

/* Remove the remaining "floating board" read by letting the ground disappear
   into the surrounding district rather than ending in a hard dark plate. */
.city-rebuild-stage .backdrop > polygon:first-of-type{opacity:.18}
.city-rebuild-stage .v2-water{filter:saturate(1.15) brightness(1.12)}
.city-rebuild-stage .v2-bridge{filter:drop-shadow(0 3px 3px #0008)}
.city-rebuild-stage .v2-bridge circle{filter:drop-shadow(0 0 3px #ffc15c)}

/* V3 resource row: each counter gets an object-sized illustration and value. */
.city-rebuild-hud .dash-sub .v3-resource{padding:4px 3px 5px;text-align:center}
.city-rebuild-hud .dash-sub .v3-resource .k{display:block;text-align:center;font-family:Georgia,serif;font-size:8px;letter-spacing:.06em}
.city-rebuild-hud .dash-sub .v3-resource .v{justify-content:center;gap:2px;font-family:Georgia,serif;font-size:14px}
.city-rebuild-hud .dash-sub .v3-resource .v b{font-weight:700}
.v3-resource-art{display:grid;place-items:center;width:34px;height:30px;filter:drop-shadow(0 2px 2px #0009)}
.city-rebuild-hud .dash-sub .v3-resource .v .v3-resource-art svg{width:31px!important;height:31px!important;margin:0}
.v3-resource[data-kind="booze"] .v3-resource-art{background:radial-gradient(circle,#d8b16422,transparent 64%)}
.v3-resource[data-kind="manpower"] .v3-resource-art{background:radial-gradient(circle,#e8d5aa1c,transparent 64%)}
.v3-resource[data-kind="weapons"] .v3-resource-art{background:radial-gradient(circle,#c98f5224,transparent 64%)}
.v3-resource[data-kind="influence"] .v3-resource-art{background:radial-gradient(circle,#e8b94a2b,transparent 64%)}
.v3-resource[data-kind="chips"] .v3-resource-art{background:radial-gradient(circle,#d7483f25,transparent 64%)}
@media(max-width:350px){
 .v3-resource-art{width:28px;height:27px}
 .city-rebuild-hud .dash-sub .v3-resource .v .v3-resource-art svg{width:27px!important;height:27px!important}
 .city-rebuild-hud .dash-sub .v3-resource .v{font-size:12px}
}

.v3-pedestrian{filter:brightness(1.02) drop-shadow(0 2px 1px #000a)}
/* Give the upper HUD the carved-panel weight of the approved mockup. */
.city-rebuild-hud .dash-main .cell{box-shadow:inset 0 0 16px #0003,inset 0 1px #f2c16a18}
.city-rebuild-hud .dash-sub .cell{box-shadow:inset 0 0 12px #0002}
.city-rebuild-hud .cell::after{box-shadow:inset 0 1px #f9d893,0 1px 2px #0008}
.v2-cash-art{filter:drop-shadow(0 3px 2px #0009)}
.v2-heat-badge{filter:drop-shadow(0 3px 2px #000a)}

/* V3 building massing: the operation must dominate the neighborhood rather
   than look like miniatures on oversized lots. */
.city-v3-building{transform-origin:center bottom}
.city-v3-building{filter:saturate(1.18) contrast(1.1) brightness(1.15) drop-shadow(0 6px 4px #0009)}
.city-v3-building[data-building="mansion"]{filter:saturate(1.2) contrast(1.1) brightness(1.22) drop-shadow(0 8px 6px #000a)}
.v3-building-shadow{filter:blur(3px)}
.city-v3-building .level-details{filter:brightness(1.12) saturate(1.08)}

/* The reference is dusk, not near-black night. Lift the playable lower half
   while retaining enough ink for the amber windows and brass UI to pop. */
.city-rebuild-stage::after{background:linear-gradient(180deg,transparent 46%,rgba(8,18,15,.05) 72%,rgba(3,10,9,.12))}

.v3-waterfront-industry{filter:drop-shadow(0 4px 4px #0008)}
.v3-harbor-traffic{filter:drop-shadow(0 3px 2px #0009)}
/* Warmer reflection band ties the neighborhood to the waterfront. */
.city-rebuild-stage .v2-water{filter:saturate(1.22) brightness(1.16) drop-shadow(0 -2px 7px rgba(226,137,58,.12))}

/* V3 guidance is a game sign, not a floating web tooltip. */
.city-rebuild-stage .block-guide{width:210px;color:#ffd45d}
.city-rebuild-stage .block-guide span{
  max-width:210px;padding:6px 13px;border:2px solid #d1a04d;border-radius:4px;
  background:linear-gradient(#102a27,#071a19);color:#f8e5b9;
  font:700 14px/1.1 Georgia,serif;letter-spacing:.01em;
  box-shadow:inset 0 0 0 2px #3c2a18,0 4px 9px #0009;
}
.city-rebuild-stage .block-guide svg{width:48px;height:64px;filter:drop-shadow(0 4px 3px #000a)}
.city-rebuild-stage .block-guide svg path{fill:#ffd24e;stroke:#6b421d;stroke-width:1.4}

.v3-cargo-cluster{filter:saturate(1.04) drop-shadow(0 2px 2px #0008)}
/* Preserve legibility as environmental detail rises. */
.city-rebuild-stage .v2-selected-lot{filter:drop-shadow(0 0 5px rgba(255,184,64,.35))}
.city-rebuild-stage [data-badge]{filter:drop-shadow(0 2px 2px #0008)}

.v3-corner-crowd{filter:brightness(1.04) drop-shadow(0 2px 1px #0009)}
/* Subtle amber vignette keeps the eye on the operation while retaining detail
   at the edges, matching the painted reference rather than a black fade. */

/* V3 phone composition. Reserve more of the screen for the city itself while
   retaining the larger illustrated controls. */
@media(max-width:520px){
  .city-rebuild-stage .recenter{width:58px;height:58px;border-width:3px}
  .city-rebuild-hud .cell{min-height:55px;padding-top:5px;padding-bottom:4px}
  .city-rebuild-hud .dash-sub .cell{min-height:45px;padding-top:3px;padding-bottom:3px}
  .city-rebuild-hud .cell .v{font-size:18px}
  .city-rebuild-hud .dash-sub .v3-resource .v{font-size:13px}
  .v3-resource-art{height:27px;width:31px}
  .city-rebuild-hud .dash-sub .v3-resource .v .v3-resource-art svg{width:28px!important;height:28px!important}
  .city-rebuild-objective{min-height:64px;padding:6px 9px 7px 12px}
  .city-rebuild-objective .opening-eyebrow i{width:24px;height:24px;font-size:15px}
  .city-rebuild-objective strong{font-size:15px}
  .city-rebuild-objective button{min-height:50px;min-width:114px}
  .city-rebuild-tabs{min-height:82px}
  .city-rebuild-tabs .tab{min-height:80px}
  .city-rebuild-tabs .tab svg{width:36px;height:36px}
}

.v3-horizon-haze{filter:blur(5px);mix-blend-mode:screen}
/* The city should be the first thing the eye sees after the HUD. */

/* Selected building gets a painted pool of light rather than relying only on
   the geometric diamond, which helps it survive the denser environment. */
.city-rebuild-stage .plot.selected .v2-building-warmth{opacity:.16}

/* HUD typography follows the illustrated reference more closely: labels are
   warm serif display text, numbers stay compact and readable. */
.city-rebuild-hud .cell .k{font-family:Georgia,serif;font-weight:700;letter-spacing:.07em}
.city-rebuild-hud .cell .v{font-family:Georgia,serif;font-variant-numeric:tabular-nums}
.city-rebuild-hud .cell .r{font-family:Georgia,serif;letter-spacing:.01em}
.v2-money-copy .k,.v2-heat-copy .k{font-size:9px}
.v2-money-copy .v{font-size:22px}

.v3-utility-pole{filter:drop-shadow(0 3px 2px #0008)}
.v3-overhead-wire{filter:drop-shadow(0 1px 1px #0007)}
.v3-delivery-truck{filter:saturate(.9) brightness(.95) drop-shadow(0 3px 2px #000a)}
/* Mild texture through CSS gradients avoids a sterile vector finish. */
.city-rebuild-stage::before{
  background:
    radial-gradient(ellipse at 50% 17%,rgba(255,177,75,.30),transparent 31%),
    radial-gradient(ellipse at 50% 66%,rgba(255,145,49,.11),transparent 52%),
    repeating-linear-gradient(17deg,rgba(255,238,196,.012) 0 1px,transparent 1px 5px);
}

/* Slightly roughen signage and storefront contrast so environmental text reads
   painted-on rather than like floating UI. */

/* Brass corner hardware helps the HUD and navigation feel like one physical
   interface rather than independent CSS boxes. */
.city-rebuild-hud .dash-main,.city-rebuild-hud .dash-sub{position:relative}
.city-rebuild-tabs::before,.city-rebuild-tabs::after{
 content:'';position:absolute;top:-5px;width:9px;height:9px;border-radius:50%;
 background:radial-gradient(circle at 35% 30%,#f2cf82,#9b6429 62%,#4d3118);
 border:1px solid #4c3017;z-index:3
}
.city-rebuild-tabs::before{left:5px}.city-rebuild-tabs::after{right:5px}

/* Separate atmospheric planes with progressively softer contrast. */
.v3-waterfront-industry{filter:saturate(.88) brightness(.92) blur(.15px) drop-shadow(0 4px 4px #0007)}
.city-rebuild-stage .v2-bridge{opacity:.88}
.v3-harbor-traffic{opacity:.82}


/* Maintain readable UI over the richer scene. */
.city-rebuild-hud{backdrop-filter:blur(.35px)}
.city-rebuild-hud{box-shadow:inset 0 0 0 1px #d5a25255,0 5px 12px #0009}

.v3-street-steam{filter:blur(2px)}
@keyframes v3-steam-drift{0%,100%{opacity:.72;transform:translateY(0)}50%{opacity:1;transform:translateY(-4px)}}
.v3-street-steam{animation:v3-steam-drift 4.8s ease-in-out infinite}
@media(prefers-reduced-motion:reduce){.v3-street-steam{animation:none}}

/* Stronger warm/cool split: amber street level against blue-gray distance. */
.city-rebuild-stage{
  isolation:isolate;
  box-shadow:inset 0 0 80px rgba(34,20,10,.18);
  /* Flat, like the stage it sits behind: the gradient only ever showed in the
     margin around the drawn block, and that margin is the same field now. */
  background: #0a0f10;
}
.city-rebuild-stage .city-horizon{filter:saturate(.96) contrast(1.02) brightness(1.08)}
.city-rebuild-stage #base{transform-origin:center center;filter:saturate(1.16) contrast(1.09) brightness(1.14)}

.v3-bench,.v3-bin{filter:saturate(.92) drop-shadow(0 2px 1px #0008)}
/* Reduce geometric road-line prominence. The approved image reads as streets,
   not a visible board grid. */
.city-rebuild-stage .backdrop [fill="url(#cobbles)"]{opacity:.86}
.city-rebuild-stage .backdrop [stroke="#6e6a52"]{opacity:.22}

/* Let scenery carry more of the screen while retaining crisp interactive art. */
.v3-tree{opacity:.96}
.city-v3-building,.city-rebuild-stage [data-badge],.city-rebuild-stage .block-guide{opacity:1}

/* ==================================================================== V3 HUD
   Measured off the approved art rather than guessed at. At the 442pt width the
   reference is drawn for: three equal plates on the top row, five on the
   second, a near-black field inside a brass frame, and type a good deal larger
   than a drawn-icon HUD needed. Everything below scales from those numbers.  */

:root {
  --hud-field: #060d0e;          /* the reference samples at 3,12,14 -- almost black */
  --hud-field-lo: #03080a;
  --brass-lit: #e3b968;
  --brass-mid: #b78d3f;
  --brass-dark: #6d5220;
}

.city-rebuild-hud {
  position: relative;
  /* `.dash` reserves the notch here -- keep it, and zero only the sides. */
  padding: var(--safe-top) 0 0;
}

/* Equal plates. The reference measures 143.5 / 149 / 133 across the top row and
   an even five below -- near enough to identical that anything else reads as a
   mistake, which is exactly how the old 1fr/.9fr/112px looked. */
.city-rebuild-hud .dash-main,
.city-rebuild-hud .dash-sub {
  position: relative;
  display: grid;
  gap: 0;
  background: transparent;
  border: 0;
}
/* Not equal columns. Measured on the reference, the rules sit at x 303.5 and
   601.5 across the top row and at 190 / 369.5 / 567 / 718 across the bottom,
   which is 284 / 297 / 263 and 171 / 179 / 198 / 151 / 147 -- Weapons widest
   because its label is, Heat narrowest because its number is short. Equal
   fifths were what clipped WEAPONS and RESPECT to "WEA..." and "RES...". */
.city-rebuild-hud .dash-main {
  grid-template-columns: minmax(0, 284fr) minmax(0, 297fr) minmax(0, 263fr);
}
/* Widths follow the word, not the reference's exact rules. MEN is three
   letters sitting in the second-widest column while RESPECT, at seven, had the
   second-narrowest -- which is why it read "RESPE...". Taking 30 off Men and
   giving it to Respect costs Men nothing: its label still clears its column
   with room, and the icons either side shrink into the difference. */
.city-rebuild-hud .dash-sub {
  grid-template-columns: minmax(0, 168fr) minmax(0, 146fr) minmax(0, 200fr)
                         minmax(0, 189fr) minmax(0, 143fr);
}

/* The frame, measured off the reference in pixels rather than read off it.
   The last pass gave every plate its own four-sided brass box and four rivets.
   Adjacent plates then doubled both, which is the "rivets, corners and
   dividers are all off" everyone could see: a grid of separate tiles where the
   reference has one riveted frame with rules inside it.
   Measured on the reference at 885px wide, scaled to the 440px a phone gives:
     outer frame   x 14..19 and 865..870, y 24 / 296     -> 3px, all four sides
     row rule      y 168..170                            -> 2px
     row-1 rules   x 303.5, 601.5  (three equal plates)  -> 2px
     row-2 rules   x 190, 369.5, 567, 718  (five, unequal)
     rivet         ~12px across                          -> 6px
   Nothing here is per-cell any more except the rule on a cell's right edge. */
.city-rebuild-hud {
  position: relative;
  border: 3px solid var(--brass-mid);
  box-shadow: inset 0 0 0 1px #2a1e0c, inset 0 2px 14px #000a;
}
.city-rebuild-hud .cell {
  position: relative;
  min-width: 0;
  margin: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}
/* The rule between plates, and nothing on the last one -- the frame closes it. */
.city-rebuild-hud .cell + .cell {
  border-left: 2px solid var(--brass-mid);
  box-shadow: inset 1px 0 0 #2a1e0c;
}
/* The rule between the two rows. */
.city-rebuild-hud .dash-main { border-bottom: 2px solid var(--brass-mid); }

/* Every rule carries a rivet at each end, and the row's own rule carries one
   where the frame meets it. `--rivet` is the one size in the file: a rivet
   drawn at two sizes in two places is what made the old corners read wrong. */
:root { --rivet: 9px; }
.city-rebuild-hud .cell > .rivets { display: none; }
.city-rebuild-hud .cell + .cell::before,
.city-rebuild-hud .cell + .cell::after {
  content: '';
  position: absolute;
  left: calc(var(--rivet) / -2 - 1px);
  width: var(--rivet); height: var(--rivet);
  background: url('./assets/frame/rivet.webp') center / contain no-repeat;
  filter: drop-shadow(0 1px 1px #000b);
  pointer-events: none;
  z-index: 6;
}
/* Centred on the line they sit on, so a rivet never half-overlaps its
   neighbour across the row rule -- which is what "touching" looked like. */
.city-rebuild-hud .dash-main .cell + .cell::before { top: calc(var(--rivet) / -2 - 1px); }
.city-rebuild-hud .dash-main .cell + .cell::after  { bottom: calc(var(--rivet) / -2 - 2px); }
.city-rebuild-hud .dash-sub  .cell + .cell::before { top: calc(var(--rivet) / -2 - 1px); }
.city-rebuild-hud .dash-sub  .cell + .cell::after  { bottom: calc(var(--rivet) / -2 - 1px); }

/* The four corners of the bar, and the two places the row rule meets the
   frame: the same six-way join treated the same way. */
.city-rebuild-hud::before,
.city-rebuild-hud::after,
.city-rebuild-hud .dash-main::after {
  content: '';
  position: absolute;
  left: 1px; right: 1px;
  height: var(--rivet);
  background:
    url('./assets/frame/rivet.webp') left center / var(--rivet) var(--rivet) no-repeat,
    url('./assets/frame/rivet.webp') right center / var(--rivet) var(--rivet) no-repeat;
  filter: drop-shadow(0 1px 1px #000b);
  pointer-events: none;
  z-index: 7;
}
.city-rebuild-hud::before { top: 1px; }
.city-rebuild-hud::after  { bottom: 1px; }
.city-rebuild-hud .dash-main::after { bottom: calc(var(--rivet) / -2); }

/* A rivet wherever two lines meet, and nothing fancier.
   The corner assets went because they were a different object from the rivets
   on every other join, and at 17px they crowded the rivets either side of them
   -- the bar read as a pile of hardware rather than a riveted frame. One part,
   one size, one rule: every place a vertical rule meets a horizontal one gets
   a rivet, corners included, because a corner is just the intersection at the
   end of the frame. */
.city-rebuild-hud,
.city-rebuild-tabs {
  background-image: linear-gradient(180deg, var(--hud-field) 0%, var(--hud-field-lo) 100%);
  background-repeat: no-repeat;
  background-origin: border-box;
  background-clip: border-box;
}

/* ---------------------------------------------------------------- row one */
/* Row one is 72css tall on the reference (y 24..169 of 885, at 440 wide).
   It was rendering at 98 -- the art alone was 66 before padding -- which is why
   the bar ate a third more of the screen than the design gives it. */
.city-rebuild-hud .dash-main .cell {
  display: flex;
  align-items: center;
  gap: clamp(4px, 1.6vw, 9px);
  padding: 5px clamp(4px, 1.6vw, 10px);
}
/* The art gives way, the words do not.
   Both of these were `flex: 0 0 auto` with a percentage cap, so the art took
   its share of every plate and the copy lived on the remainder -- which is how
   "CLEAN CASH" became "CLEAN CAS" and "RESPECT" became "RES...". The reference
   does not work that way: its Respect plate is 74css wide and spends 49 of it
   on the word, leaving the star whatever is left, while Weapons spends 84 on a
   longer word in a wider plate. So the icon shrinks first and the label keeps
   its width. */
.v3-money-art {
  flex: 0 100 auto;
  /* Not 0. The art yields to the words, but it does not disappear -- with a
     floor of zero the Heat shield collapsed entirely behind "UNDER
     INVESTIGATION · → 0", which is how the badge went missing from the bar. */
  min-width: clamp(30px, 8.6vw, 40px);
  display: grid;
  place-items: center;
  height: clamp(38px, 12.6vw, 56px);
  width: auto;
  max-width: 42%;
  filter: drop-shadow(0 2px 3px #000b);
}
.v3-money-art .icon-art { height: 100%; width: auto; max-width: 100%; display: block; }
.v2-money-copy, .v2-heat-copy { display: block; min-width: 0; flex: 1 1 auto; overflow: hidden; }

.city-rebuild-hud .dash-main .cell .k {
  display: block;
  font: 700 clamp(10px, 3.02vw, 14.5px)/1.1 'HUD Condensed', 'Arial Narrow', sans-serif;
  letter-spacing: 0;
  text-transform: uppercase;
  color: #efe2c0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: clip;
}
.city-rebuild-hud .dash-main .cell .v {
  display: block;
  font: 700 clamp(17px, 5.1vw, 26px)/1.06 'HUD Condensed', 'Arial Narrow', sans-serif;
  letter-spacing: -.02em;
  color: #fff;
  text-shadow: 0 2px 4px #000c;
}
.city-rebuild-hud .dash-main .cell .r { font-size: clamp(10px, 2.9vw, 13px); }

/* ---------------------------------------------------------------- row two */
.city-rebuild-hud .dash-sub .cell.v3-resource {
  display: flex;
  align-items: center;
  gap: clamp(3px, 1.2vw, 7px);
  padding: 6px clamp(3px, 1.2vw, 8px);
}
.v3-resource-art {
  flex: 0 100 auto;
  min-width: clamp(18px, 5.2vw, 24px);
  display: grid;
  place-items: center;
  height: clamp(30px, 9.4vw, 42px);
  width: auto;
  max-width: 40%;
  filter: drop-shadow(0 1px 2px #000b);
}
.v3-resource-art .icon-art { height: 100%; width: auto; max-width: 100%; display: block; }
.v3-resource-copy { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; line-height: 1.06; }
.city-rebuild-hud .dash-sub .cell .k {
  /* 11px wanted 55 for WEAPONS in a 47px column. The label is the shortest
     word in the plate and the least of what it says -- the number is the
     point -- so it gives up the two pixels rather than the "PONS". */
  font: 700 clamp(7.6px, 2.14vw, 9.4px)/1.1 'HUD Condensed', 'Arial Narrow', sans-serif;
  letter-spacing: 0;
  text-transform: uppercase;
  color: #efe2c0;
  margin: 0;
}
.city-rebuild-hud .dash-sub .cell .v {
  font: 700 clamp(12.5px, 3.6vw, 19px)/1.06 'HUD Condensed', 'Arial Narrow', sans-serif;
  letter-spacing: -.02em;
  color: #fff;
  text-shadow: 0 2px 3px #000c;
}

/* ------------------------------------------------------------------- heat */
.heat-blocks { display: flex; gap: 2px; margin: 3px 0 2px; }
.heat-blocks i {
  flex: 1 1 0;
  height: clamp(6px, 1.9vw, 9px);
  border-radius: 1px;
  background: #1e1c19;
  box-shadow: inset 0 0 3px #000a;
}
.heat-blocks i.lit { box-shadow: inset 0 1px 0 #ffffff3d, 0 0 5px #d9922f55; }

/* Federal Crackdown: the plate itself says so.
   The top tier used to be a word that did not fit -- "FEDE..." -- so the bars
   carry the level and the plate carries the alarm. Dull on purpose: this sits
   behind the numbers a player reads every few seconds, and a bright flash
   there would be unreadable long before it was useful. */
@keyframes heat-crackdown-pulse {
  0%, 100% { box-shadow: inset 0 0 14px #c0452c33, 0 0 0 #c0452c00; }
  50%      { box-shadow: inset 0 0 22px #c0452c66, 0 0 7px #c0452c3d; }
}
.city-rebuild-hud .cell.heat-crackdown {
  animation: heat-crackdown-pulse 2.6s ease-in-out infinite;
}
/* A pulse is motion, and motion is the one thing some people cannot have on
   screen. The tier still reads from five red bars without it. */
@media (prefers-reduced-motion: reduce) {
  .city-rebuild-hud .cell.heat-crackdown {
    animation: none;
    box-shadow: inset 0 0 18px #c0452c4d;
  }
}
.city-rebuild-hud .heat-top { display: flex; align-items: baseline; gap: 5px; }
.city-rebuild-hud .heat-num { font: 700 clamp(19px, 5.9vw, 26px)/1 Georgia, serif; }
.heat-tier {
  display: block;
  font: 700 clamp(8.5px, 2.6vw, 11px)/1.1 Georgia, serif;
  letter-spacing: .01em;
  text-transform: uppercase;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.city-rebuild-hud .cell.heat { overflow: hidden; }
.city-rebuild-hud .cell.heat .r { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* The Heat plate reads across, then down.
   The badge used to sit left of a four-line stack, the way the money plates
   carry their art -- which left the bars a third of the plate wide and a line
   of words underneath them. Nothing is written under the bars now, so the
   badge moves up beside the number, the bars take the whole width, and the
   badge gets the height the stack was using. */
.city-rebuild-hud .cell.heat { align-items: stretch; }
.city-rebuild-hud .v2-heat-copy { display: flex; flex-direction: column; justify-content: center; gap: 6px; width: 100%; }
.city-rebuild-hud .heat-top {
  display: flex;
  align-items: center;
  gap: clamp(5px, 1.8vw, 10px);
  justify-content: flex-start;
}
.city-rebuild-hud .heat-top .k { flex: 0 0 auto; margin: 0; }
.city-rebuild-hud .heat-num { flex: 0 0 auto; }
.v3-heat-art {
  flex: 1 1 auto;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  min-width: 0;
}
.v3-heat-art .icon-art {
  height: clamp(34px, 11.4vw, 50px);
  width: auto;
  max-width: 100%;
  display: block;
  filter: drop-shadow(0 2px 3px #000b);
}
.city-rebuild-hud .heat-blocks { width: 100%; margin: 0; gap: clamp(2px, .8vw, 4px); }
.city-rebuild-hud .heat-blocks i { height: clamp(8px, 2.6vw, 12px); border-radius: 2px; }

/* ------------------------------------------------------------- bottom bar */
.city-rebuild-tabs {
  position: relative;
  padding-top: 4px;
  padding-bottom: var(--safe-bottom);
  border-top: 3px solid var(--brass-mid);
}
.city-rebuild-tabs [data-tab] {
  position: relative;
  background: transparent;
  border: 0;
}
/* The divider runs the whole height of the bar, so it actually meets the rail
   at the top and the frame at the bottom. It used to stop short of both, which
   is why the rivets floated below the top line rather than sitting on the join
   they are supposed to be pinning. */
.city-rebuild-tabs [data-tab] + [data-tab] {
  box-shadow: inset 2px 0 0 -1px #5d3721, inset 3px 0 2px -2px #000;
}
.city-rebuild-tabs [data-tab] + [data-tab]::after,
.city-rebuild-tabs [data-tab] + [data-tab]::before {
  content: '';
  position: absolute;
  left: calc(var(--rivet) / -2);
  width: var(--rivet); height: var(--rivet);
  background: url('./assets/frame/rivet.webp') center / contain no-repeat;
  filter: drop-shadow(0 1px 1px #000a);
  pointer-events: none;
  z-index: 6;
}
/* On the rail, not under it, and on the bottom frame at the other end. */
.city-rebuild-tabs [data-tab] + [data-tab]::before { top: calc(var(--rivet) / -2 - 2px); }
.city-rebuild-tabs [data-tab] + [data-tab]::after  { bottom: calc(var(--rivet) / -2 - 1px); }

/* The bar's own two top corners, where its rail meets its sides. */
.city-rebuild-tabs::before {
  content: '';
  position: absolute;
  left: 1px; right: 1px;
  top: 1px;
  height: var(--rivet);
  background:
    url('./assets/frame/rivet.webp') left center / var(--rivet) var(--rivet) no-repeat,
    url('./assets/frame/rivet.webp') right center / var(--rivet) var(--rivet) no-repeat;
  filter: drop-shadow(0 1px 1px #000a);
  pointer-events: none;
  z-index: 7;
}
.tab-art {
  height: clamp(34px, 11.3vw, 50px);
  width: auto;
  max-width: 94%;
  object-fit: contain;
  display: block;
  filter: drop-shadow(0 1px 2px #000b);
}
.city-rebuild-tabs [data-tab] span,
.city-rebuild-tabs [data-tab] small {
  /* UNDERWORLD is the longest word on the bar and was reaching the frame on
     both sides of its slot at 3.3vw. A hair smaller, and a hair of padding, so
     no label sits on the brass. */
  font: 700 clamp(8.6px, 2.95vw, 13.5px)/1.1 'HUD Condensed', 'Arial Narrow', sans-serif;
  letter-spacing: .01em;
  text-transform: uppercase;
  color: #efe2c0;
  padding: 0 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
/* The corner asset needs a square to sit in; dropped on the bar's ends at 15px
   it read as a stray hook rather than a corner. The reference frames the whole
   bar, so frame it -- and on all four sides, not just the top edge. */
.city-rebuild-tabs {
  border: 3px solid var(--brass-mid);
  border-bottom: 0;
  box-shadow: inset 0 0 0 1px #2a1e0c, inset 0 2px 10px #000a;
}


/* ----------------------------------------------------------- next move */
.city-rebuild-objective .opening-card,
.opening-card {
  background: url('./assets/hud/notice.webp') center / 100% 100% no-repeat;
  clip-path: none;
  box-shadow: none;
  border: 0;
  filter: drop-shadow(0 3px 7px #0008);
  padding: 15px 15px 17px;
}
/* A clip-path removed its notches from hit-testing as well as from view; the
   paper does not, so say plainly that only the buttons are targets. */
.city-rebuild-objective, .opening-card { pointer-events: none; }
.city-rebuild-objective button, .opening-card button { pointer-events: auto; }

.city-rebuild-objective .opening-eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  background: none; box-shadow: none; padding: 0;
}
.city-rebuild-objective .opening-eyebrow b {
  display: inline-block;
  padding: 4px 11px;
  background: linear-gradient(180deg, #bb3327 0%, #9a241c 100%);
  color: #fdf1d8;
  font: 700 clamp(11px, 3.2vw, 14px)/1 Georgia, serif;
  letter-spacing: .08em;
  text-transform: uppercase;
  box-shadow: 0 1px 3px #0007, inset 0 1px 0 #ffffff38;
}
.city-rebuild-objective .opening-eyebrow i { display: none; }
.eyebrow-hand { width: clamp(30px, 8.6vw, 40px); height: clamp(30px, 8.6vw, 40px); object-fit: contain; display: block; filter: drop-shadow(0 1px 2px #0009); }
.city-rebuild-objective .opening-card strong,
.opening-card strong {
  display: block; margin-top: 7px;
  font: 700 clamp(16px, 4.8vw, 21px)/1.15 Georgia, serif;
  color: #2b1d10; text-shadow: 0 1px 0 #ffffff5c;
}
.city-rebuild-objective button#opening-action {
  background: linear-gradient(180deg, #c8402f 0%, #a32a22 58%, #7d1d17 100%);
  border: 1px solid #5e1410; border-radius: 3px; color: #fff3dd;
  box-shadow: inset 0 1px 0 #ffffff4d, inset 0 -2px 4px #00000055, 0 2px 4px #0008;
  text-shadow: 0 1px 2px #00000088;
}
#opening-action .v2-cta-main { font: 700 clamp(14px, 4.2vw, 18px)/1.1 Georgia, serif; letter-spacing: .05em; text-transform: uppercase; }
#opening-action .v2-cta-sub { font-size: clamp(9px, 2.7vw, 12px); letter-spacing: .14em; opacity: .85; }

/* An icon stands in for a drawn one, so it defaults to the drawn one's size:
   `icon()` serves eleven places and only two are the HUD. */
.icon-art { width: 20px; height: 20px; object-fit: contain; display: inline-block; vertical-align: -.24em; }

/* The reference is drawn at 442pt. Below that the plates get narrower but the
   words do not, so the art gives ground first and the labels keep their size
   -- a clipped "CLEAN CASI" is worse than a slightly smaller bundle of notes. */
@media (max-width: 415px) {
  .city-rebuild-hud .dash-main .cell { gap: 4px; padding-inline: 4px; }
  .city-rebuild-hud .dash-sub .cell.v3-resource { gap: 3px; padding-inline: 3px; }
  /* 0.88 of the reference's 66 / 46, which is the width ratio at 390pt. */
  .v3-money-art { height: 58px; }
  .v3-resource-art { height: 40px; }
}

/* Six tabs across a 390pt phone is 65pt each; the reference gives its nav art
   0.84 of the slot and a 14.6px label, so both scale rather than shrink. */
@media (max-width: 415px) {
  .city-rebuild-tabs [data-tab] span,
  .city-rebuild-tabs [data-tab] small { font-size: 12.4px; letter-spacing: -.02em; }
  .tab-art { height: 44px; width: auto; }
}

/* The reference is a 442x888 phone and its HUD is genuinely tall -- about 173px
   with the inset, which is where this one lands at that size. A 320x568 screen
   cannot spare the same share: the same chrome there takes 39% of the height
   and leaves the block too little to pan. Give the art back on the short
   screens rather than letting the stage pay for it. */
@media (max-width: 360px), (max-height: 620px) {
  .city-rebuild-hud .dash-main .cell { padding: 4px; gap: 3px; }
  .city-rebuild-hud .dash-sub .cell.v3-resource { padding: 3px; gap: 2px; }
  .v3-money-art { height: 38px; }
  .v3-resource-art { height: 26px; }
  .city-rebuild-hud .dash-main .cell .v { font-size: 17px; }
  .city-rebuild-hud .dash-sub .cell .v { font-size: 12.5px; }
  .city-rebuild-hud .dash-main .cell .k { font-size: 10px; }
  .city-rebuild-hud .dash-sub .cell .k { font-size: 8px; }
  .city-rebuild-hud .heat-num { font-size: 17px; }
  .city-rebuild-hud .cell { margin: 1px; }
  .tab-art { height: 28px; }
  .city-rebuild-tabs [data-tab] span, .city-rebuild-tabs [data-tab] small { font-size: 8.6px; }
}
@media (max-width: 360px), (max-height: 620px) {
  .city-rebuild-tabs { padding-top: 2px; }
  .city-rebuild-tabs [data-tab] { padding-block: 3px; }
}

/* The unread dot rode over the artwork at the old icon size; at the reference's
   it only needs to mark the corner. */
/* The V3 pass translated this dot up by 17px to clear a 27px icon. At the
   reference's 44px it clears nothing and lands above the bar, over the map.
   Position it on the icon's corner and drop the offset. */
.city-rebuild-tabs [data-tab] .dot {
  position: absolute;
  width: 11px; height: 11px;
  top: 7px; right: 16%;
  transform: none;
  background: #e5332c;
  border-radius: 50%;
  box-shadow: 0 0 0 1.5px #1a0d0b, 0 1px 3px #000a;
}

/* ======================================================== PANEL FACELIFT V3
   The bar was rebuilt to the reference -- a near-black field inside a brass
   frame with a rivet at every join -- and every panel behind it was left on
   the palette it had before that: green plates, grey hairlines, a different
   face on every heading. Opening one threw the player out of the world the
   bar had just built, which is what "all menu screens still use the old
   formatting" describes.
   The chrome is one object now, and the object is stated once here: the same
   field, the same brass, the same rivet asset at the same `--rivet` size, the
   same condensed face on anything that is a heading. The playfield keeps its
   own colours -- the map is scenery, not chrome. */

:root {
  /* A panel's field is the bar's field, one step up. A sheet floats over the
     map; the bar is bolted to the screen edge. Identical values would flatten
     the two into one plane. */
  --plate:    #0c1314;
  --plate-lo: #070c0d;
  --plate-up: #141b1c;
  --hud-face: 'HUD Condensed', 'Arial Narrow', sans-serif;
}

body { background: var(--hud-field-lo); }
.scrim { background: #03070880; }

/* ------------------------------------------------------------- the panel */
.sheet {
  background: linear-gradient(180deg, var(--plate) 0%, var(--plate-lo) 100%);
  border: 3px solid var(--brass-mid);
  border-radius: 3px;
  box-shadow: inset 0 0 0 1px #2a1e0c, 0 18px 54px #000000d9;
}
/* One rivet in each corner, from the same file and at the same size as the
   bar's. Four background positions on one pseudo-element rather than four
   elements, and `::before` stays free for the resource panel's tab. */
.sheet::after {
  content: '';
  position: absolute;
  inset: 1px;
  pointer-events: none;
  z-index: 4;
  background:
    url('./assets/frame/rivet.webp') left  top    / var(--rivet) var(--rivet) no-repeat,
    url('./assets/frame/rivet.webp') right top    / var(--rivet) var(--rivet) no-repeat,
    url('./assets/frame/rivet.webp') left  bottom / var(--rivet) var(--rivet) no-repeat,
    url('./assets/frame/rivet.webp') right bottom / var(--rivet) var(--rivet) no-repeat;
  filter: drop-shadow(0 1px 1px #000b);
}
/* The resource drop-down has no top edge -- it hangs off the bar -- so it has
   no top corners to rivet. */
.sheet[data-panel="resource"]::after {
  background:
    url('./assets/frame/rivet.webp') left  bottom / var(--rivet) var(--rivet) no-repeat,
    url('./assets/frame/rivet.webp') right bottom / var(--rivet) var(--rivet) no-repeat;
}

.sheet-head {
  position: relative;
  background: linear-gradient(180deg, #151d1e, #0a1112);
  border-bottom: 2px solid var(--brass-mid);
  border-radius: 0;
}
/* The head rule is a rule like any other, so it gets a rivet where it meets
   the frame at either end. */
.sheet-head::after {
  content: '';
  position: absolute;
  left: 0; right: 0;
  bottom: calc(var(--rivet) / -2 - 1px);
  height: var(--rivet);
  pointer-events: none;
  z-index: 5;
  background:
    url('./assets/frame/rivet.webp') left  center / var(--rivet) var(--rivet) no-repeat,
    url('./assets/frame/rivet.webp') right center / var(--rivet) var(--rivet) no-repeat;
  filter: drop-shadow(0 1px 1px #000b);
}
.sheet-head h2 {
  font-family: var(--hud-face);
  font-weight: 700;
  letter-spacing: .07em;
  color: var(--brass-lit);
}
.sheet-close {
  color: var(--brass-lit);
  border: 1px solid var(--brass-dark);
  background: #0b1213;
}

/* Headings inside a panel are the bar's face too -- a panel that opens in a
   different typeface is a different product. Body copy stays on the serif:
   it is prose, and the condensed face is a label face. */
.sheet-body h2, .sheet-body h3,
.result-heading, .character-card strong, .rival-quote strong,
.world-heading h2, .build-tip strong, .raid-theater strong,
.reward-grid strong, .street-result > strong {
  font-family: var(--hud-face);
  font-weight: 700;
}

/* ----------------------------------------------- surfaces inside a panel */
/* A card is the field one step up with a brass hairline. Its own accent --
   the coloured left edge on a quote or a prize -- is left alone. */
.sheet-body .reward-grid > div,
.sheet-body .character-card,
.sheet-body .hood-card,
.sheet-body .raid-temptation,
.sheet-body .training-cost,
.sheet-body .encounter-enemy,
.sheet-body .climb-card,
.sheet-body .preparation,
.sheet-body .ledger-alternative,
.sheet-body .crew-counts,
#reward-inbox {
  background: linear-gradient(180deg, var(--plate-up), var(--plate-lo));
  border-color: var(--brass-dark);
}
.sheet-body .rival-quote,
.sheet-body .vance-intro,
.sheet-body .unlock-prize,
.sheet-body .climb-debrief,
.sheet-body .yard-progress {
  background: var(--plate-up);
}
/* Hairlines between rows are brass at low weight, not grey. Grey rules were
   the last thing in a panel that did not belong to the frame. */
.sheet-body .row,
.sheet-body .crew,
.sheet-body .target {
  border-bottom-color: #6d522066;
}
.sheet-body .bar { background: #050a0b; }

/* Secondary buttons sit in the field, framed like everything else. The gold
   primary is named out rather than left to the cascade: `button.primary` and
   `.sheet-body button` carry the same specificity, so the later one would
   simply take the fill off every call to action in the game. The selected
   tab in a segmented control is named out for the same reason. */
.sheet-body button:not(.primary):not(#upgrade-btn):not(#opening-action):not([aria-selected="true"]) {
  background: linear-gradient(180deg, #1a2324, #0d1516);
  border: 1px solid var(--brass-dark);
  color: var(--cream);
}
.sheet-body button:not(.primary):not(#upgrade-btn):not(#opening-action):not([aria-selected="true"]):hover:not(:disabled) {
  background: #202b2c;
}

/* The frame is 3px where the old hairline was 1px, and on a 320px phone those
   four pixels come out of the panel's usable width -- enough that the research
   grid, whose tiles have a 44px finger floor, stops fitting its row. Take them
   back off the body's own padding: the content box is exactly the width it was
   before the frame went on. */
.sheet-body { padding-left: 10px; padding-right: 10px; }
.sheet-body > .building-hero {
  width: calc(100% + 20px);
  margin-left: -10px;
  margin-right: -10px;
}

/* --------------------------------------------------- everything floating */
.toast {
  background: #070d0ef0;
  border: 1px solid var(--brass-dark);
}
.opening-card:not(.city-rebuild-objective) {
  background: #070d0ef0;
  border-bottom: 2px solid var(--brass-mid);
}

/* ===================================================== NOTICE AND QUEUE DIALS
   The next-move notice and the two queue chips, stated once and last.

   Both were built out of the same parts as the panels they sit over -- a
   gradient, a hairline border, a radius -- and both read as browser chrome
   laid on painted art. The reference makes each one an object: the notice is
   a strip of paper with an enamelled sign screwed to it, and a queue is a
   dial in a banded ring. Nothing here is a new image; the only art is the
   pointing hand and the rivet, which the panels already use. */

/* ------------------------------------------------------------- the notice */

/* Three columns and two rows: the hand, what it points at, and the sign. The
   hand spans both rows because it points at the notice, not at its first
   line, and the sign spans both because it is one object. */
#opening-card.city-rebuild-objective {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  column-gap: clamp(7px, 2.4vw, 12px);
  row-gap: 1px;
  min-height: 0;
  /* THE PAPER IS NOT SYMMETRIC, SO THE PADDING IS NOT EITHER. Measured off
     `notice.webp`: clean paper starts 6.4% of the strip down from the top and
     ends 9.6% up from the bottom, and the deepest scallop bites 23% in at the
     top against 33% at the bottom. Centred content therefore sits level in the
     box and low on the sheet -- the objective's descenders ran into the char
     while the label had room above it. These two add up to what the symmetric
     pair added up to, so the strip is the same height and everything in it
     moved up by half the difference. */
  padding-top: clamp(2.5px, 0.85vw, 5px);
  padding-bottom: clamp(5.5px, 1.95vw, 11px);
  padding-inline: clamp(9px, 2.8vw, 15px);
}
#opening-card.city-rebuild-objective .eyebrow-hand {
  grid-column: 1; grid-row: 1 / span 2;
  /* Width only. The art is 1.92:1 and a square box with `contain` inside it
     drew the hand at half the size it was asked for. */
  width: clamp(45px, 13.4vw, 64px); height: auto;
  filter: drop-shadow(0 2px 3px #0009);
  /* Tipped up to point at the label, not at the middle of the strip: the
     label is what it is introducing. Turned about the cuff, so the hand stays
     where it was and only the finger rises. */
  align-self: end;
  transform: translateY(-6%) rotate(-17deg);
  transform-origin: 18% 62%;
}
/* The label sits on the top row at its own height; the objective takes the
   rest of the strip and is centred in it -- between the bottom of the label
   and the bottom of the paper, not pushed down against the scorched edge. */
#opening-card.city-rebuild-objective { grid-template-rows: auto 1fr; }
#opening-card.city-rebuild-objective .opening-eyebrow { grid-column: 2; grid-row: 1; display: block; align-self: start; }
#opening-card.city-rebuild-objective strong { grid-column: 2; grid-row: 2; margin: 0; align-self: center; }
#opening-card.city-rebuild-objective #opening-action { grid-column: 3; grid-row: 1 / span 2; }
#opening-card.city-rebuild-objective #opening-diversion { grid-column: 1 / -1; grid-row: 3; }
#opening-card.city-rebuild-objective .opening-detail { display: none; }

/* A stamped label, not a heading: the condensed face the rest of the HUD is
   set in, white on red, tight to its own text. */
#opening-card.city-rebuild-objective .opening-eyebrow b {
  display: inline-block;
  padding: 3px 9px 2px;
  border-radius: 2px;
  background: linear-gradient(180deg, #c33b2c 0%, #9c241c 100%);
  color: #fff;
  font: 700 clamp(10px, 3vw, 13px)/1 var(--hud-face);
  letter-spacing: .085em;
  text-transform: uppercase;
  box-shadow: 0 1px 3px #00000059, inset 0 1px 0 #ffffff2e;
}
#opening-card.city-rebuild-objective strong {
  display: block;
  font: 700 clamp(15px, 4.5vw, 21px)/1.08 var(--hud-face);
  letter-spacing: 0;
  color: #16100a;
  text-shadow: 0 1px 0 #ffffff4d;
}

/* The sign: an enamelled plate screwed to the paper, with the same rivet in
   the same four corners as every panel in the game. */
#opening-card.city-rebuild-objective button#opening-action {
  position: relative;
  display: grid; place-items: center;
  gap: 1px;
  min-width: 0;
  min-height: 44px;
  padding: clamp(6px, 2vw, 10px) clamp(10px, 3.4vw, 18px);
  border: 0;
  border-radius: clamp(6px, 1.9vw, 10px);
  background: linear-gradient(177deg, #bd392d 0%, #a62c23 44%, #7c1c16 100%);
  box-shadow:
    inset 0 0 0 2px #00000052,       /* the bevel inside the rim */
    inset 0 2px 1px #ffffff30,       /* the gloss along the top edge */
    inset 0 -6px 10px #00000047,
    0 0 0 2px #2b140f,               /* the rim itself */
    0 3px 6px #00000073;
  color: #fff3e4;
  font-family: var(--hud-face);
  text-transform: uppercase;
}
#opening-card.city-rebuild-objective #opening-action::after {
  content: '';
  position: absolute;
  inset: clamp(4px, 1.3vw, 7px);
  pointer-events: none;
  background:
    url('./assets/frame/rivet.webp') left  top    / var(--rivet) var(--rivet) no-repeat,
    url('./assets/frame/rivet.webp') right top    / var(--rivet) var(--rivet) no-repeat,
    url('./assets/frame/rivet.webp') left  bottom / var(--rivet) var(--rivet) no-repeat,
    url('./assets/frame/rivet.webp') right bottom / var(--rivet) var(--rivet) no-repeat;
  filter: drop-shadow(0 1px 1px #000a);
}
#opening-card.city-rebuild-objective #opening-action .v2-cta-main {
  font: 700 clamp(13px, 3.9vw, 18px)/1 var(--hud-face);
  letter-spacing: .03em;
  text-shadow: 0 1px 2px #0000008f;
}
/* The arrow is drawn, not written: it says "and this takes you there", which
   is not something a screen reader needs read out after the verb. */
#opening-card.city-rebuild-objective #opening-action .v2-cta-sub {
  margin: 0;
  color: #fff3e4;
  font: 700 clamp(10px, 3vw, 14px)/1 var(--hud-face);
  letter-spacing: .05em;
  opacity: 1;
  text-shadow: 0 1px 2px #0000008f;
}
#opening-card.city-rebuild-objective #opening-action .v2-cta-sub::after { content: '\2009\2192'; }

/* ------------------------------------------------------- the queue dials */

/* Collapsed, a queue is a dial: a banded brass ring with a dark face in it,
   and the painted tool on the face with its count under it.

   The ring was drawn here once -- two conic sweeps, one for the light and one
   for the joints between staves -- which was the right shape and as close to
   brass as a gradient gets. It is one image now, the same way the notice is
   one image, so the dial, the hand and the paper are all the same material
   and the stylesheet stops impersonating any of them.

   Both dials are named by id. `#march-toggle` was given its own background and
   its own 56px box by an earlier pass, and a class cannot outrank an id: say
   the dial once, for both, or the crews dial keeps the old grey gradient while
   the builds dial gets the ring. */
.queue-dock .minimized {
  width: var(--dial);
  background: none;
  border: 0;
  border-radius: 50%;
  box-shadow: none;
  overflow: visible;
}
:root { --dial: clamp(54px, 15.4vw, 62px); }
.queue-dock .minimized :is(#build-toggle, #march-toggle) {
  position: relative;
  width: var(--dial); height: var(--dial);
  min-height: 0;
  padding: 0;
  gap: 0;
  border-radius: 50%;
  /* The face is painted into the ring, so there is no second layer under it. */
  background: url('./assets/hud/dial.webp') center / 100% 100% no-repeat;
  box-shadow: none;
  filter: drop-shadow(0 3px 5px #000000a6);
}

/* The tool sits above the middle of the face and the count under it, which is
   where a dial puts its needle and its reading. Sized one at a time: the
   hammer stands up and the truck lies down, so one width across both would
   draw one of them half the size of the other. */
.queue-icon { display: block; object-fit: contain; }
.queue-dock .minimized #build-toggle .queue-icon { width: 44%; margin-top: 1%; }
.queue-dock .minimized #march-toggle .queue-icon { width: 63%; margin-top: 6%; }
.queue-dock .minimized :is(#build-toggle, #march-toggle) b {
  margin-top: 2%;
  color: #fff;
  font: 700 clamp(13px, 3.9vw, 16px)/1 var(--hud-face);
  letter-spacing: .01em;
  text-shadow: 0 1px 2px #000, 0 0 3px #000c;
}

/* Open, the queue is a list with a heading, and the tool is the heading's
   mark. A truck twice as wide as a hammer is tall needs saying here too. */
.queue-toggle .queue-icon { height: 25px; width: auto; }
#march-toggle .queue-icon { height: auto; width: 32px; }

/* --------------------------------------------- the map, pulled a long way back

   Past the point where a marker is twelve points across (see `world-map.js`),
   the map stops drawing what is on it and draws only where things are. The
   crews, the sites and the scenery are dropped from the markup there; these
   four are fixed pieces that never change, so hiding them is cheaper than
   rebuilding them and brings them straight back on the way in.

   What is left is the city itself: terrain, water, roads and the region names,
   which is what a map pulled back this far is for. */
.world-far .world-block,
.world-far .world-players,
.world-far .world-job,
.world-far .world-rumors { display: none; }
/* Outside the loaded area round the view: see `cullFixed` in world-map.js. */
.world-culled { display: none; }

/* What the plan was, under a goal that stands in for it while the builders or
   the crews are busy, with when it opens up. */
.opening-card .opening-then { display: block; grid-column: 1 / -1; font-size: 12px; line-height: 1.2; opacity: .9; }
#opening-card.city-rebuild-objective .opening-then {
  grid-column: 2; grid-row: 3; margin: 0;
  font: 600 clamp(11px, 3.2vw, 13px)/1.15 var(--hud-face);
  color: #4a3520;
}
#opening-card.city-rebuild-objective .opening-then ~ #opening-diversion { grid-row: 4; }
.opening-until, .opening-after-until { white-space: nowrap; font-variant-numeric: tabular-nums; }

/* A button whose command is on its way to the server: disabled at once, and
   saying what it is doing, so the tap is seen to have landed. The label is
   drawn over the button's own text, which stays as its accessible name. */
button.is-pending { position: relative; color: transparent !important; cursor: progress; }
button.is-pending > * { visibility: hidden; }
button.is-pending::after {
  content: attr(data-pending);
  position: absolute; inset: 0;
  display: grid; place-items: center;
  color: var(--pending-ink, #f4e6c4); font-weight: 700; letter-spacing: .02em;
  animation: pending-pulse 1s ease-in-out infinite alternate;
}
@keyframes pending-pulse { from { opacity: .65; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { button.is-pending::after { animation: none; } }

/* The next name on the Underworld climb, and what he leaves behind. */
.climb-next { display: flex; gap: 11px; align-items: flex-start; margin: 0 0 12px; padding: 10px 11px; border: 1px dashed #c9a22788; border-radius: 8px; background: #2f2b27; }
.climb-next > div { display: grid; gap: 2px; min-width: 0; }
.climb-next .eyebrow { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--brass); }
.climb-next strong { font-size: 15px; color: var(--cream); }
.climb-next strong em { font-weight: 400; color: var(--cream-dim); }
.climb-next > div > span:not(.eyebrow) { font-size: 12px; color: var(--cream-dim); }
.climb-spoils { margin: 4px 0 0; font-size: 13px; color: #d9c48a; }
.climb-spoils.won { margin: 0 0 12px; padding: 8px 10px; border-radius: 6px; background: #2f3a2c; color: #cfe3c1; }
.climb-taken { margin: 0 0 10px; }
.climb-taken h3 { margin: 0 0 4px; font-size: 14px; color: var(--cream-dim); font-weight: 500; }
.climb-taken ul { margin: 0; padding-left: 18px; font-size: 13px; color: var(--cream); }

/* ------------------------------------------------------------------ the Bag */

button.inventory-slot { position: relative; cursor: pointer; font: inherit; }
.inventory-slot.rarity-uncommon { border-color: #6f9fd0; }
.inventory-slot.rarity-rare { border-color: #d9a441; box-shadow: inset 0 0 10px #d9a44155; }
.inventory-slot.selected { outline: 2px solid var(--cream); outline-offset: 1px; }
.inventory-slot .item-count { position: absolute; right: 3px; bottom: 2px; font: 700 11px/1 var(--hud-face, sans-serif); color: #fff; text-shadow: 0 1px 2px #000; }
.item-art { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 6px; position: relative; }
.item-art svg { width: 22px; height: 22px; }
.item-art.crate { background: linear-gradient(180deg, #7a5a33, #5a3f22); box-shadow: inset 0 0 0 2px #3b2914; }
.item-art.speedup { color: #f1e3c2; background: #3a4552; }
.item-art.speedup.kind-construction { background: #6b4b2a; }
.item-art.speedup.kind-training { background: #5a2f2f; }
.item-art.speedup.kind-yard { background: #2f4a37; }
.item-art.speedup b { position: absolute; left: 0; right: 0; bottom: -2px; font: 700 9px/1 var(--hud-face, sans-serif); text-align: center; }
.bag-detail { margin: 6px 0 12px; padding: 10px; border: 1px solid #57503f; border-radius: 8px; background: #26231f; }
.bag-detail-head { display: flex; gap: 10px; align-items: center; }
.bag-detail-head strong { display: block; font-size: 15px; color: var(--cream); }
.bag-detail p { margin: 8px 0; font-size: 13px; color: #d8ccb2; }
.rarity-label { font-size: 12px; color: var(--cream-dim); }
.rarity-label.rarity-uncommon { color: #8fb8e4; }
.rarity-label.rarity-rare { color: #e6b95a; }
.bag-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.bag-timer { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 6px; align-items: center; padding: 6px 0; border-top: 1px solid #3c372f; }
.bag-timer span { font-size: 13px; color: var(--cream); }
.bag-timer small { display: block; color: var(--cream-dim); }

/* Speed-ups from the Bag, beside the timer they work on. */
.speedup-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 8px 0 0; grid-column: 1 / -1; }
.speedup-row > span { font-size: 12px; color: var(--cream-dim); }
.speedup-btn { min-height: 36px; padding: 4px 9px; font-size: 13px; font-weight: 700; }
.speedup-btn i { font-style: normal; font-weight: 400; font-size: 11px; margin-left: 4px; opacity: .8; }
.speedup-btn small { margin-left: 5px; font-weight: 400; opacity: .8; }
.found-item { display: flex; align-items: center; gap: 9px; margin: 8px 0; font-size: 13px; color: #e8dcc0; }
.found-item .item-art { flex: 0 0 auto; width: 30px; height: 30px; }

/* A report that arrived without taking the screen: the notice pulses once. */
.notice.fresh { animation: notice-in .35s ease-out, notice-pulse 1.2s ease-in-out .35s 2; }
@keyframes notice-pulse { 50% { box-shadow: 0 0 0 4px #f0c26488, 0 3px 12px #000a; } }
@media (prefers-reduced-motion: reduce) { .notice.fresh { animation: none; } }
.ambush { margin: 8px 0; padding: 8px 10px; border: 1px solid #9a5b52; border-radius: 6px; background: #3a2c29; }
.ambush h3 { margin: 0 0 4px; font-size: 14px; color: #f0c8a8; }
.ambush p { margin: 0; font-size: 13px; color: #e8d8c0; }
.ambush.warn { border-color: #d0583f; }
.activity-purpose { margin: 6px 0 10px; font-size: 13px; color: #d9c48a; }
.mission-tabs button small { display: block; font-size: 11px; font-weight: 400; opacity: .8; }

/* The getaway board's cars, seen from above, turned to face their exits. */
.car-cell .car-art { position: absolute; inset: 4%; width: 92%; height: 92%; transform: rotate(var(--car-angle, 0deg)); filter: drop-shadow(0 2px 2px #0007); }


/* A choice the player makes once: each option on its own card. */
.choice-card { margin: 0 0 12px; padding: 10px 11px; border: 1px solid #57503f; border-radius: 8px; background: #2a2622; }
.choice-card h3 { margin: 0 0 6px; font-size: 15px; color: var(--cream); }
.choice-card p { margin: 6px 0; font-size: 13px; color: #d8ccb2; }
.choice-card .choice-cost { color: #e2c48a; }

/* Preparing for a fight on the road: who goes, and a look at the ambush. */
.escort { margin: 8px 0; padding: 8px 10px; border: 1px solid #57503f; border-radius: 6px; background: #2a2622; }
.escort h3 { margin: 0 0 6px; font-size: 14px; color: var(--cream); }
.escort [data-tipoff] small { display: block; font-weight: 400; opacity: .8; }
.escort [data-tipoff][aria-pressed="true"] { border-color: #7fbf8a; }
.next-report { margin-top: 10px; }
.raid-risk .raid-heat { display: block; font-size: 12px; color: #e8b48a; }


/* Illustrated Yard cards: the same 3 + 2 geometry for every research branch. */
.research-tree { position: relative; isolation: isolate; }
.yard-links { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; z-index: -1; }
.yard-links path { fill: none; stroke: #786342; stroke-width: 1.5; stroke-dasharray: 3 3; }
.yard-links path.met { stroke: #d2b273; stroke-dasharray: none; }
.yard-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 30px 8px; padding: 0 10px; }
.yard-grid .research-tile { grid-column: span 2; }
.yard-grid .research-tile:nth-child(4) { grid-column: 2 / span 2; }
.yard-grid .research-tile:nth-child(5) { grid-column: 4 / span 2; }
#sheet .yard-grid .research-tile { min-width: 0; padding: 5px 4px 7px; gap: 5px; border: 1px solid #80683f; border-radius: 7px; background: #211f1a; box-shadow: 0 3px 6px #0007; justify-content: flex-start; }
#sheet .yard-grid .research-tile:hover { background: #302b22; }
#sheet .yard-grid .research-square { width: 100%; height: auto; aspect-ratio: 1; border: 0; border-radius: 4px; overflow: hidden; box-shadow: none; background: #191713; }
.yard-grid .research-square::before { display: none; }
.yard-art { display: block; width: 100%; height: 100%; aspect-ratio: 1; background-repeat: no-repeat; flex-shrink: 0; }
.operations-art { background-image: url('./assets/yard/operations.webp'); background-size: 500% 400%; }
.crew-art { background-image: url('./assets/yard/crews.webp'); background-size: 400% 300%; }
#sheet .yard-grid .research-label { font-size: 12px; line-height: 1.2; min-height: 2.4em; font-weight: 600; overflow-wrap: normal; hyphens: none; color: #f2e1bd; }
#sheet .yard-grid .yard-benefit { font: 500 11px/1.3 var(--display); color: #d9c49a; min-height: 2.6em; }
#sheet .yard-grid .yard-rank { font: 600 10px/1.3 var(--display); margin-top: auto; color: #e8c77f; }
#sheet .yard-grid .locked { border-color: #595343; }
.yard-grid .locked .yard-art { filter: saturate(.4) brightness(.75); }
#sheet .yard-grid .locked .yard-rank { color: #c4b8a3; }
#sheet .yard-grid .completed { border-color: #9abd79; }
#sheet .yard-grid .completed .yard-rank { color: #bad797; }
#sheet .yard-grid .working { border-color: #f0cc73; box-shadow: 0 0 12px #dfb35755; }
#sheet .yard-grid .yard-required { outline: 2px solid #d4b574; outline-offset: 2px; }
.research-tree .research-tier { padding-bottom: 18px; }
.research-tree .research-tier h3 { padding: 0 10px; }
.yard-role { color: #e5d0a7; font-size: 14px; line-height: 1.4; margin: 10px 0 6px; }
#sheet .yard-guide { font-size: 13px; }
.research-detail-heading .yard-art { width: 88px; height: 88px; border-radius: 6px; }
.yard-requires, .yard-unlocks { display: grid; gap: 6px; margin: 16px 0; }
#sheet .yard-prerequisite { min-height: 44px; padding: 9px; font-size: 13px; line-height: 1.4; letter-spacing: 0; text-align: left; text-transform: none; white-space: normal; }
#sheet .yard-prerequisite.met { color: #bad797; }
.yard-preview { align-items: start; gap: 12px; }
.yard-preview .v { white-space: normal; text-align: right; }
@media (min-width: 600px) { #sheet .yard-grid .research-label { font-size: 15px; } #sheet .yard-grid .yard-benefit { font-size: 13px; } }
@media (max-width: 360px) {
  .yard-grid { gap: 28px 6px; padding-inline: 6px; }
  #sheet .yard-grid .research-label { font-size: 11px; }
  #sheet .yard-grid .yard-benefit { font-size: 10px; }
}

/* A recruit on the report that brought them: who, what, and the chair. */
.recruit-card { display:grid; grid-template-columns:auto 1fr; gap:6px 10px; align-items:center; margin:10px 0; padding:10px; border:1px solid #8b6a35; border-radius:8px; background:#24170f; }
.recruit-card.seated { border-color:#55766c; }
.recruit-card > button { grid-column:1 / -1; min-height:40px; }
.recruit-card .family-bonus em { color:#e0a27a; }
.recruit-card.seated .family-bonus em { color:#9fc7a9; }
.activity-purpose p { margin: 0 0 6px; }
.activity-stakes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; margin: 0; }
.activity-stakes > div { min-width: 0; padding: 4px 6px; border: 1px solid #5d4a2c; border-radius: 4px; background: #2a1f15; }
.activity-stakes dt { font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: #a8936a; }
.activity-stakes dd { margin: 1px 0 0; font-size: 11.5px; line-height: 1.25; color: #eadbb8; overflow-wrap: anywhere; }

/* Family and Bag: artwork first, clear actions, compact empty states. */
#sheet:is([data-panel="family"], [data-panel="bag"]) { background: #151917; }
#sheet:is([data-panel="family"], [data-panel="bag"]) #sheet-body { background: radial-gradient(ellipse at top left, #6e57331f, transparent 65%); }
.panel-eyebrow { display:block; font:600 10px/1.5 var(--display); letter-spacing:.16em; color:#c5a877; }
.family-overview, .bag-overview { margin:0 0 14px; padding:14px 0; border-bottom:1px solid #b3975c45; }
.family-overview { display:flex; gap:12px; align-items:center; justify-content:space-between; }
.family-overview strong, .bag-overview strong { display:block; font:600 21px/1.4 var(--display); color:#f4e6cc; }
.family-overview strong span, .bag-overview strong span { font:400 12px/1.4 var(--display); color:#b8b4a8; }
#sheet .family-overview button { flex:0 0 100px; min-height:44px; padding:8px; font:600 12px/1.3 var(--display); border-color:#a68a53; border-radius:6px; }
.family-guidance { font:400 13px/1.5 var(--display); color:#c4c5bc; margin:0 0 18px; }
.family-rank h3, .family-reserves h3, .bag-group h3 { display:flex; align-items:center; gap:8px; justify-content:space-between; margin:18px 0 10px; font:600 18px/1.3 var(--display); letter-spacing:0; color:#ecdbb8; }
.family-rank h3 small, .family-reserves h3 small, .bag-group h3 small { font:400 11px/1.4 var(--display); color:#b3ad9b; }
#sheet[data-panel="family"] .family-tree { gap:0; }
#sheet[data-panel="family"] .tree-rank { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; }
#sheet[data-panel="family"] .tree-rank::before, #sheet[data-panel="family"] .tree-rank::after { display:none; }
#sheet[data-panel="family"] .family-chair, #sheet[data-panel="family"] .family-person { max-width:none; width:100%; border:1px solid #80694170; border-radius:9px; padding:10px; background:linear-gradient(135deg,#30342a,#1b211e); box-shadow:0 4px 12px #0004; letter-spacing:0; }
#sheet[data-panel="family"] .family-chair.filled { grid-column:1 / -1; }
#sheet[data-panel="family"] .family-chair.boss { grid-column:1 / -1; border-color:#b59454; }
#sheet[data-panel="family"] .family-chair.empty { background:#1c211e; box-shadow:none; border-style:dashed; }
#sheet[data-panel="family"] .family-chair.empty .chair-body { min-height:26px; }
#sheet[data-panel="family"] .chair-rank { font:600 10px/1.5 var(--display); color:#d0b87d; padding:0 0 6px; }
#sheet[data-panel="family"] .chair-rank small { font:400 10px/1.5 var(--display); }
#sheet[data-panel="family"] .chair-body { gap:14px; align-items:center; }
.family-portrait { display:block; width:100%; height:100%; background-image:url('./assets/family/portraits.webp'); background-size:500% 100%; background-repeat:no-repeat; border-radius:6px; }
#sheet[data-panel="family"] .family-face { width:86px; height:126px; overflow:hidden; border-radius:6px; box-shadow:0 2px 8px #0006; }
#sheet[data-panel="family"] .family-who { gap:5px; }
#sheet[data-panel="family"] .family-who strong { font:600 19px/1.15 var(--display); color:#f7ead1; }
#sheet[data-panel="family"] .family-role { font:400 12px/1.4 var(--display); color:#b4b8ac; }
#sheet[data-panel="family"] .family-bonus { font:500 14px/1.4 var(--display); color:#e5d3a8; }
#sheet[data-panel="family"] .family-bonus em { margin-top:4px; font:400 11px/1.4 var(--display); }
#sheet[data-panel="family"] .chair-empty { font:400 12px/1.4 var(--display); color:#999e91; }
#sheet[data-panel="family"] .chair-empty > span { font-size:22px; vertical-align:middle; margin-right:4px; color:#b79c67; }
#sheet[data-panel="family"] .family-chair.open, #sheet[data-panel="family"] .held { border-color:#d5b677; outline:2px solid #d5b67766; outline-offset:1px; }
.recruit-card .family-face { width:60px; height:90px; }
.panel-empty { text-align:center; padding:22px 15px; margin:12px 0; border:1px solid #ac905136; border-radius:8px; background:#25291f; }
.panel-empty strong { display:block; font:600 18px/1.4 var(--display); color:#ead9b4; }
.panel-empty p { font:400 13px/1.5 var(--display); color:#b9bcae; }
.panel-empty img { display:block; width:100px; height:100px; object-fit:contain; margin:0 auto 12px; }
#sheet[data-panel="bag"] .bag-overview p, .bag-group > p { font:400 12px/1.4 var(--display); color:#b3b7aa; margin:4px 0 10px; }
#sheet[data-panel="bag"] .inventory-grid { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:9px; margin:10px 0 22px; }
#sheet[data-panel="bag"] .inventory-slot { position:relative; display:flex; flex-direction:column; align-items:stretch; justify-content:flex-start; aspect-ratio:auto; min-width:0; min-height:155px; padding:6px 6px 9px; border:1px solid #746444; border-radius:8px; background:linear-gradient(160deg,#34382c,#1b211d); box-shadow:0 3px 8px #0004; letter-spacing:0; }
#sheet[data-panel="bag"] .inventory-slot.rarity-uncommon { border-color:#678977; }
#sheet[data-panel="bag"] .inventory-slot.rarity-rare { border-color:#b79b60; }
#sheet[data-panel="bag"] .inventory-slot.selected { outline:2px solid #efd498; outline-offset:2px; background:#45412c; }
#sheet[data-panel="bag"] .item-art { display:flex; width:100%; height:auto; aspect-ratio:1; border:0; box-shadow:none; border-radius:5px; background:#181b16; margin:0 0 7px; }
#sheet[data-panel="bag"] .item-art.crate .icon-art { width:94%; height:94%; margin:auto; }
.speedup-art { display:block; width:100%; height:100%; background:url('./assets/bag/speedups.webp') no-repeat; background-size:200% 200%; border-radius:5px; }
#sheet[data-panel="bag"] .item-art.speedup { position:relative; overflow:hidden; }
#sheet[data-panel="bag"] .item-art.speedup b { position:absolute; left:5px; right:auto; bottom:5px; top:auto; transform:none; background:#131a16e8; border:1px solid #aa936659; border-radius:4px; padding:2px 5px; font:600 13px/1.3 var(--display); color:#ffe2a4; }
#sheet[data-panel="bag"] .item-count { top:8px; right:8px; bottom:auto; padding:2px 5px; border-radius:4px; background:#101814e8; color:#f4e6c8; font:600 12px/1.3 var(--display); }
.item-name { font:600 12px/1.3 var(--display); color:#f2e6cd; text-align:left; overflow-wrap:anywhere; }
.item-value { margin-top:5px; font:400 10px/1.3 var(--display); text-align:left; color:#b9bbaa; }
#sheet[data-panel="bag"] .bag-detail { padding:14px; margin:0 0 20px; border-color:#c7a76b; border-radius:9px; background:#2b3025; }
#sheet[data-panel="bag"] .bag-detail-head .item-art { flex:0 0 80px; width:80px; height:80px; margin:0; }
#sheet[data-panel="bag"] .bag-detail-head strong { font:600 19px/1.3 var(--display); }
#sheet[data-panel="bag"] .bag-actions button, #sheet[data-panel="bag"] .bag-timer button { min-height:44px; font:600 13px/1.3 var(--display); }
#sheet[data-panel="bag"] .bag-timer { flex-wrap:wrap; gap:8px; }
@media (max-width:360px) {
  #sheet[data-panel="bag"] .inventory-grid { grid-template-columns:repeat(2,minmax(0,1fr)); }
  #sheet[data-panel="family"] .family-face { width:76px; height:114px; }
  #sheet[data-panel="family"] .family-who strong { font-size:17px; }
}
@media (min-width:700px) {
  #sheet[data-panel="bag"] .inventory-grid { grid-template-columns:repeat(4,minmax(0,1fr)); }
}

/* The Yard opens on its research; the building's own panel is one tap away. */
.yard-actions { display: flex; align-items: stretch; gap: 8px; }
.yard-actions .yard-continue { flex: 1 1 auto; width: auto; }
.sheet-body .yard-building { flex: 0 0 auto; min-height: 44px; padding: 8px 10px; font-size: 12px; border: 0; border-bottom: 1px solid #8f754c; background: transparent; color: #cbb68c; }

/* Level discs and empty-lot names keep a readable size when the block is fit
   to the screen (`labelScale`). Scaled about the lot's own centre. */
#base .label-scale { transform: scale(var(--label-scale, 1)); transform-box: view-box; transform-origin: 0 0; }

/* The way back from a prerequisite, and a Mansion with nothing left in its way. */
.return-to { margin-top: 10px; }
.upgrade-ready { margin: 10px 0 0; padding: 8px 10px; border: 1px solid #9abd79; border-radius: 6px; background: #22301f; color: #cfe8b5; font-weight: 600; text-align: center; }

/* The upgrade table while the still's dial is moving: it describes the setting
   in force, so it steps back until the new one is saved. */
#sheet-body .is-stale { opacity: .4; transition: opacity .15s; }
.strength-saving { color: #e8c77f; }

/* The chapter on the goal card's top line: name, a pip per step, the prize. */
#opening-card .opening-eyebrow { display: flex; align-items: center; gap: 8px; min-width: 0; white-space: nowrap; }
.opening-chapter { display: inline-flex; align-items: center; gap: 6px; min-width: 0; overflow: hidden; text-transform: none; letter-spacing: 0; }
.opening-chapter em { font-style: normal; font-weight: 700; color: #6c351e; }
.opening-chapter small { color: #7a4a26; font-size: 10px; }
.opening-chapter .chapter-prize { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.chapter-pips { display: inline-flex; gap: 3px; flex: none; }
.chapter-pips .chapter-pip { display: block; width: 7px; height: 7px; border-radius: 50%; border: 1px solid #6c351e; background: transparent; }
.chapter-pips .chapter-pip.done { background: #9d271f; border-color: #5a1c17; }
@media (max-width: 420px) { .opening-chapter .chapter-prize, .opening-chapter em { display: none; } }
.recruit-card .recruit-demo { grid-column: 1 / -1; margin: 4px 0 0; color: #e8dcc0; font-size: 13px; }
.recruit-card .recruit-demo b { color: #cfe8b5; }
.away-enables { margin: 10px 0 6px; color: #cfe8b5; font-weight: 600; }
