/* MAYOR - HUD skin. Owned by the ui agent. Pairs with src/ui.js.
   Late-night New York from a rooftop: dark glass, monospace numbers. */

:root {
  --bg:      #657d69;
  --glass:   #f8fbf8;
  --glass2:  #eef4ed;
  --line:    #dce5dc;
  --line2:   #e7ede6;
  --text:    #293e40;
  --text2:   #53696b;
  --dim:     #6a7f80;
  --amber:   #9d7027;
  --cyan:    #26758d;
  --green:   #2f7952;
  --rose:    #bb554c;
  --violet:  #8265a3;
  --ui:   "Segoe UI", -apple-system, system-ui, sans-serif;
  --mono: "Bahnschrift", "Segoe UI", system-ui, sans-serif;
  --r:    14px;
  --shadow: 0 7px 22px rgba(21, 43, 34, .22), 0 2px 3px rgba(21, 43, 34, .10);
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; overflow: hidden; background: var(--bg); }
body { font-family: var(--ui); color: var(--text); -webkit-font-smoothing: antialiased; user-select: none; }
#app { position: fixed; inset: 0; }
#city { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

/* the HUD never eats a drag: only real controls opt back in */
#hud, .mm-root { position: fixed; inset: 0; pointer-events: none; z-index: 10; }
.mm-bar, .mm-tools, .mm-rail, .mm-dock, .mm-tut, .mm-scrim, .mm-market { pointer-events: auto; }
.mm-toasts { pointer-events: none; }

button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }

.glass, .mm-bar, .mm-tools, .mm-rail, .mm-dock .seg, .mm-modal, .mm-tut, .toast {
  background: var(--glass);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow);
}

::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .13); border-radius: 8px; }
::-webkit-scrollbar-track { background: transparent; }

/* ---------- top bar ---------- */
.mm-bar {
  position: absolute; top: 10px; left: 10px; right: 10px; height: 64px;
  display: flex; align-items: center; gap: 12px; padding: 0 12px; border-radius: 16px;
}
.brand { display: flex; align-items: center; gap: 12px; flex: none; }
.mark { display: flex; flex-direction: column; line-height: 1.02; }
.mark .m1 { font-size: 10px; letter-spacing: 3px; color: var(--dim); }
.mark .m2 { font-size: 17px; font-weight: 800; letter-spacing: 1.2px; color: var(--amber); }
.clock { padding-left: 12px; border-left: 1px solid var(--line); }
.clock .day { font-family: var(--mono); font-size: 15px; font-weight: 600; }
.clock .year { font-size: 10px; color: var(--dim); letter-spacing: .6px; }

.stats { display: flex; gap: 7px; flex: 1 1 auto; min-width: 0; }
.tile {
  flex: 1 1 0; min-width: 0; padding: 5px 9px 3px; border-radius: 10px;
  border: 1px solid transparent; background: rgba(255, 255, 255, .035);
  transition: border-color .3s, background .3s;
}
.tile.wide { flex: 1.45 1 0; }
.tile .tl { font-size: 8.5px; letter-spacing: 1.3px; color: var(--dim); white-space: nowrap; }
.tile .tv { display: flex; align-items: baseline; gap: 5px; min-width: 0; }
.tile .num {
  font-family: var(--mono); font-size: 19px; font-weight: 600; color: var(--c, var(--text));
  letter-spacing: -.6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tile .sub { font-family: var(--mono); font-size: 10.5px; color: var(--dim); white-space: nowrap; }
.tile .sub.up { color: var(--green); }
.tile .sub.down { color: var(--rose); }
.k-app .sub { font-size: 15px; }
.tile.warn { background: rgba(240, 168, 72, .08); border-color: rgba(240, 168, 72, .3); }
.tile.alarm { background: rgba(244, 102, 122, .1); border-color: rgba(244, 102, 122, .42); }
.tile.pulse { animation: pulse 1.4s ease-out 1; }
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(79, 209, 232, .55); }
  70%  { box-shadow: 0 0 0 11px rgba(79, 209, 232, 0); }
  100% { box-shadow: 0 0 0 0 rgba(79, 209, 232, 0); }
}
.c-amber  { --c: var(--amber); }
.c-cyan   { --c: var(--cyan); }
.c-green  { --c: var(--green); }
.c-rose   { --c: var(--rose); }
.c-violet { --c: var(--violet); }
.spark { display: block; width: 100%; height: 15px; margin-top: 1px; opacity: .8; overflow: visible; }
.spark polyline { stroke: var(--c, var(--text2)); }
.spark circle { fill: var(--c, var(--text2)); }

.speed { display: flex; align-items: center; gap: 8px; flex: none; }
.speed .sl { font-size: 8.5px; letter-spacing: 1.3px; color: var(--dim); }
.seg { display: flex; border: 1px solid var(--line); border-radius: 9px; overflow: hidden; background: rgba(0, 0, 0, .25); }
.sb {
  font-family: var(--mono); font-size: 11.5px; padding: 6px 9px; color: var(--text2);
  border-right: 1px solid var(--line2); transition: background .15s, color .15s;
}
.sb:last-child { border-right: 0; }
.sb:hover { background: rgba(255, 255, 255, .06); color: var(--text); }
.sb.on { background: var(--amber); color: #10161f; font-weight: 700; }

/* ---------- left toolbar ---------- */
.mm-tools {
  position: absolute; left: 10px; top: 86px; bottom: 62px; width: 152px;
  padding: 8px; display: flex; flex-direction: column; gap: 4px; overflow-y: auto;
}
.mm-tools .head { font-size: 8.5px; letter-spacing: 1.6px; color: var(--dim); padding: 2px 4px 4px; }
.mm-tools .sep { height: 1px; background: var(--line); margin: 5px 2px; flex: none; }
.tool {
  display: grid; grid-template-columns: 17px 1fr auto; align-items: center; gap: 7px;
  padding: 7px 8px; border-radius: 9px; border: 1px solid transparent;
  background: rgba(255, 255, 255, .04); flex: none; transition: background .12s, border-color .12s, opacity .2s;
}
.tool:hover { background: rgba(255, 255, 255, .09); }
.tool .k {
  font-family: var(--mono); font-size: 9.5px; color: var(--dim); text-align: center;
  background: rgba(0, 0, 0, .35); border-radius: 4px; padding: 2px 0;
}
.tool .tn { font-size: 12px; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tool .tc { font-family: var(--mono); font-size: 10.5px; color: var(--amber); opacity: .75; }
.tool.on { background: rgba(240, 168, 72, .17); border-color: rgba(240, 168, 72, .55); }
.tool.on .k { color: var(--amber); }
.tool.poor { opacity: .35; }
.tool.poor .tc { color: var(--rose); }
.tool.doze .tn, .tool.doze .tc { color: var(--rose); }
.tool.doze.on { background: rgba(244, 102, 122, .18); border-color: rgba(244, 102, 122, .6); }

/* ---------- right rail ---------- */
.mm-rail {
  position: absolute; right: 10px; top: 86px; bottom: 10px; width: 306px;
  display: flex; flex-direction: column; overflow: hidden;
}
.mm-rail.collapsed { width: 44px; }
.mm-rail.collapsed .tab, .mm-rail.collapsed .panes { display: none; }
.tabs { display: flex; align-items: stretch; gap: 2px; padding: 4px 6px 0; border-bottom: 1px solid var(--line); flex: none; }
.collapse { color: var(--dim); padding: 6px 8px; font-size: 15px; line-height: 1; }
.collapse:hover { color: var(--text); }
.tab {
  flex: 1; padding: 9px 4px 8px; font-size: 11.5px; letter-spacing: .5px; color: var(--dim);
  border-bottom: 2px solid transparent; margin-bottom: -1px; transition: color .15s;
}
.tab:hover { color: var(--text2); }
.tab.on { color: var(--text); border-bottom-color: var(--cyan); }
.panes { flex: 1; min-height: 0; position: relative; }
.pane { display: none; position: absolute; inset: 0; overflow-y: auto; padding: 10px; }
.pane.on { display: block; }

.polhead {
  display: flex; justify-content: space-between; align-items: center;
  padding: 7px 9px; margin-bottom: 8px; border-radius: 9px; background: rgba(0, 0, 0, .28);
  position: sticky; top: -10px; z-index: 2;
}
.polhead .lbl { font-size: 8.5px; letter-spacing: 1.3px; color: var(--dim); }
.polhead .v { font-family: var(--mono); font-size: 14px; color: var(--amber); }
.polhead .v.over { color: var(--rose); }
.cards { display: flex; flex-direction: column; gap: 7px; }
.empty { font-size: 12px; color: var(--dim); padding: 14px 4px; text-align: center; }
.pcard {
  display: grid; grid-template-columns: 24px 1fr 32px; align-items: center; gap: 9px;
  width: 100%; text-align: left; padding: 9px; border-radius: 11px;
  border: 1px solid var(--line2); background: rgba(255, 255, 255, .035);
  transition: background .15s, border-color .15s, opacity .2s;
}
.pcard:hover { background: rgba(255, 255, 255, .08); }
.pcard.on { background: rgba(167, 139, 250, .14); border-color: rgba(167, 139, 250, .5); }
.pcard.locked { opacity: .45; }
.picon { font-size: 17px; text-align: center; }
.pbody { min-width: 0; display: block; }
.pname { display: flex; align-items: baseline; justify-content: space-between; gap: 6px; }
.pname .n { font-size: 12.5px; font-weight: 600; }
.pcost { font-family: var(--mono); font-size: 10px; color: var(--amber); flex: none; }
.pblurb { display: block; font-size: 10.5px; line-height: 1.35; color: var(--text2); margin-top: 2px; }
.plock { display: none; font-size: 10px; color: var(--cyan); margin-top: 3px; }
.plock.show { display: block; }
.psw {
  width: 30px; height: 17px; border-radius: 9px; background: rgba(255, 255, 255, .12);
  position: relative; transition: background .18s; justify-self: end;
}
.psw .knob {
  position: absolute; top: 2px; left: 2px; width: 13px; height: 13px; border-radius: 50%;
  background: var(--text2); transition: transform .18s, background .18s;
}
.pcard.on .psw { background: var(--violet); }
.pcard.on .psw .knob { transform: translateX(13px); background: #fff; }

.loglist { display: flex; flex-direction: column; }
.li { display: grid; grid-template-columns: 48px 1fr; gap: 7px; padding: 6px 2px; border-bottom: 1px solid var(--line2); }
.li .d { font-family: var(--mono); font-size: 9.5px; color: var(--dim); padding-top: 1px; }
.li .t { font-size: 11.5px; line-height: 1.4; color: var(--text2); }
.li.k-good  .t { color: var(--green); }
.li.k-bad   .t { color: var(--rose); }
.li.k-event .t { color: var(--violet); }

.pane .sub { display: block; font-size: 8.5px; letter-spacing: 1.4px; color: var(--dim); margin: 4px 2px 7px; }
.ledger { display: flex; flex-direction: column; gap: 1px; margin-bottom: 16px; }
.brow { display: flex; justify-content: space-between; align-items: baseline; padding: 7px 9px; border-radius: 8px; background: rgba(255, 255, 255, .03); }
.brow .bl { font-size: 11.5px; color: var(--text2); }
.brow .bv { font-family: var(--mono); font-size: 13px; }
.brow.good .bv { color: var(--green); }
.brow.bad .bv  { color: var(--rose); }
.brow.pol .bv  { color: var(--violet); }
.brow.total { margin-top: 5px; background: rgba(0, 0, 0, .3); border: 1px solid var(--line); }
.brow.total .bl { color: var(--text); font-weight: 600; }
.brow.total .bv { color: var(--green); font-size: 15px; }
.brow.total.bad .bv { color: var(--rose); }

.srow { display: block; margin-bottom: 13px; }
.srow .sl { display: flex; justify-content: space-between; font-size: 11.5px; color: var(--text2); margin-bottom: 3px; }
.srow .sv { font-family: var(--mono); color: var(--amber); }
.slider { width: 100%; accent-color: var(--amber); cursor: pointer; }
.slider.hot { accent-color: var(--rose); }
.srow .warn { display: none; font-size: 10px; color: var(--rose); margin-top: 3px; line-height: 1.3; }
.srow .warn.show { display: block; }

/* ---------- bottom dock ---------- */
.mm-dock { position: absolute; left: 10px; bottom: 10px; display: flex; gap: 8px; align-items: center; }

/* ---- the tour caption ----
   One line at the bottom of the screen and a way out of it. Deliberately not
   a modal: the tour drives the real game underneath, and anything that dimmed
   or blocked it would be hiding the only thing worth looking at. */
.mm-tour {
  position: absolute; left: 50%; bottom: 26px; transform: translateX(-50%);
  z-index: 30; pointer-events: auto;
  display: flex; align-items: center; gap: 14px;
  max-width: min(680px, 92vw); padding: 11px 13px 11px 19px;
  border-radius: 999px; background: rgba(16, 22, 26, .9);
  border: 1px solid rgba(255, 255, 255, .14);
  box-shadow: 0 14px 44px rgba(0, 0, 0, .45);
  opacity: 0; transition: opacity .4s ease;
}
.mm-tour.on { opacity: 1; }
.tr-say {
  font-family: var(--obs-serif, Georgia, serif); font-size: 15.5px;
  color: #fff; line-height: 1.35;
}
.tr-skip {
  flex: none; font-family: var(--ui); font-size: 11px; letter-spacing: 1.4px;
  text-transform: uppercase; color: rgba(255, 255, 255, .72);
  border: 1px solid rgba(255, 255, 255, .24); border-radius: 999px;
  padding: 7px 13px; transition: color .2s, background .2s;
}
.tr-skip:hover { color: #fff; background: rgba(255, 255, 255, .14); }
@media (max-width: 720px) {
  .mm-tour { bottom: 14px; padding: 9px 10px 9px 15px; gap: 10px; }
  .tr-say { font-size: 13.5px; }
}
@media (prefers-reduced-motion: reduce) { .mm-tour { transition: none; } }

/* ---- the chapter card ----
   Bottom-left, above the dock. The whole brief for this element was "good
   gamification, not overstimulating", so it is one card, it never animates on
   its own, it never blocks input, and the only thing that moves without being
   clicked is a 2px rule. */
.mm-quest {
  position: absolute; left: 10px; bottom: 62px; width: 268px;
  pointer-events: auto; overflow: hidden;
  background: var(--glass); border: 1px solid var(--line);
  border-radius: 12px; box-shadow: var(--shadow);
}
.q-head {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 9px 11px 8px; text-align: left;
}
.q-ch { flex: 1; font-size: 10px; letter-spacing: 1.5px; color: var(--text); font-weight: 700; }
.q-count { font-family: var(--mono); font-size: 10.5px; color: var(--dim); }
.q-caret {
  width: 7px; height: 7px; border-right: 1.5px solid var(--dim); border-bottom: 1.5px solid var(--dim);
  transform: rotate(-45deg); transition: transform .22s; margin-left: 1px;
}
.mm-quest.open .q-caret { transform: rotate(45deg); }

.q-bar { height: 2px; background: var(--line2); }
.q-bar i { display: block; height: 100%; background: var(--amber); transition: width .45s ease; }

.q-hint {
  padding: 8px 11px 9px; font-size: 11px; line-height: 1.45; color: var(--text2);
}
.mm-quest.finished .q-hint { display: none; }

/* Collapsed hides the list, never the hint: one line of what to do next is
   the reason the card exists at all. */
.q-list { margin: 0; padding: 0 11px 10px; list-style: none; display: none; }
.mm-quest.open .q-list { display: block; }
.q-step {
  display: flex; align-items: center; gap: 8px;
  font-size: 11.5px; color: var(--text2); padding: 3px 0;
}
.q-tick {
  width: 11px; height: 11px; border-radius: 50%; flex: none;
  border: 1.5px solid var(--line); transition: background .2s, border-color .2s;
}
.q-step.done { color: var(--dim); text-decoration: line-through; text-decoration-thickness: 1px; }
.q-step.done .q-tick { background: var(--green); border-color: var(--green); }

.clock.rank { min-width: 74px; }
.clock.rank .day { font-family: var(--ui); font-size: 12.5px; font-weight: 600; color: var(--amber); }

@media (max-height: 680px) { .mm-quest { display: none; } }
@media (prefers-reduced-motion: reduce) {
  .q-bar i, .q-caret, .q-tick { transition: none; }
}
.mm-dock .seg { padding: 3px; gap: 2px; border-radius: 11px; }
.mm-dock .cap { font-size: 8.5px; letter-spacing: 1.3px; color: var(--dim); padding: 0 7px; align-self: center; }
.ob {
  font-size: 11px; padding: 6px 10px; border-radius: 8px; color: var(--text2);
  text-transform: capitalize; transition: background .15s, color .15s;
}
.ob:hover { background: rgba(255, 255, 255, .08); color: var(--text); }
.ob.on { background: rgba(79, 209, 232, .18); color: var(--cyan); }
.ob.off { color: var(--dim); }
.ob.danger { color: var(--rose); }
.ob.danger.armed { background: var(--rose); color: #14181f; font-weight: 700; }

/* ---------- toasts ---------- */
.mm-toasts {
  position: absolute; left: 50%; bottom: 74px; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 7px; z-index: 40;
}
.toast {
  padding: 9px 15px; border-radius: 11px; font-size: 12.5px; max-width: 460px; text-align: center;
  border-left: 3px solid var(--cyan);
  opacity: 0; transform: translateY(14px) scale(.97);
  transition: opacity .26s ease, transform .26s cubic-bezier(.2, .9, .3, 1.2);
  will-change: transform, opacity;
}
.toast.in { opacity: 1; transform: none; }
.toast.k-good { border-left-color: var(--green); }
.toast.k-bad  { border-left-color: var(--rose); }

/* ---------- modal + game over ---------- */
.mm-scrim {
  position: absolute; inset: 0; display: none; align-items: center; justify-content: center;
  background: rgba(4, 7, 14, .74); backdrop-filter: blur(3px); z-index: 60;
}
.mm-scrim.show { display: flex; }
.mm-modal {
  width: min(520px, 84vw); max-height: 84vh; overflow-y: auto; padding: 26px 26px 20px;
  text-align: center; border-radius: 18px;
  animation: pop .2s cubic-bezier(.2, .9, .3, 1.1);
}
@keyframes pop { from { opacity: 0; transform: translateY(12px) scale(.97); } }
.micon { font-size: 40px; line-height: 1; }
.mtitle { font-size: 21px; font-weight: 700; margin: 10px 0 8px; letter-spacing: .2px; }
.mtext { font-size: 13.5px; line-height: 1.55; color: var(--text2); margin-bottom: 18px; }
.mchoices { display: flex; flex-direction: column; gap: 8px; }
.choice {
  display: flex; align-items: center; gap: 11px; width: 100%; text-align: left;
  padding: 11px 13px; border-radius: 11px; border: 1px solid var(--line);
  background: rgba(255, 255, 255, .045); transition: background .14s, border-color .14s, transform .1s;
}
.choice:hover { background: rgba(255, 255, 255, .1); }
.choice:focus-visible, .choice:focus { border-color: var(--cyan); background: rgba(79, 209, 232, .12); }
.choice:active { transform: scale(.99); }
.choice .ck {
  font-family: var(--mono); font-size: 11px; color: var(--dim); flex: none;
  width: 20px; height: 20px; line-height: 20px; text-align: center;
  background: rgba(0, 0, 0, .4); border-radius: 5px;
}
.choice .ct { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.choice .cl { font-size: 14.5px; font-weight: 600; }
.choice .ch { font-size: 11px; color: var(--dim); line-height: 1.35; }
.choice.big { justify-content: center; margin-top: 16px; border-color: var(--amber); }
.choice.big .ct { align-items: center; font-size: 14.5px; font-weight: 600; color: var(--amber); }
.mhint { font-size: 10px; color: var(--dim); margin-top: 14px; letter-spacing: .4px; }
.ostats { display: flex; flex-direction: column; gap: 1px; text-align: left; }
.orow { display: flex; justify-content: space-between; padding: 7px 10px; border-radius: 8px; background: rgba(255, 255, 255, .035); font-size: 12.5px; }
.orow b { font-family: var(--mono); color: var(--amber); }

/* ---------- first-run tutorial ---------- */
.mm-tut { position: absolute; left: 174px; bottom: 62px; width: 310px; padding: 14px 16px 12px; }
.mm-tut .th { font-size: 9px; letter-spacing: 1.6px; color: var(--amber); margin-bottom: 8px; }
.mm-tut ol { margin: 0; padding-left: 17px; }
.mm-tut li { font-size: 11.5px; line-height: 1.5; color: var(--text2); margin-bottom: 4px; }
.mm-tut .ok {
  margin-top: 8px; width: 100%; padding: 7px; border-radius: 8px; font-size: 11.5px;
  background: rgba(255, 255, 255, .07); color: var(--text);
}
.mm-tut .ok:hover { background: rgba(255, 255, 255, .14); }

/* ---------- tight windows (1100x720 floor) ---------- */
@media (max-width: 1280px) {
  .tile .num { font-size: 17px; }
  .tile .tl { letter-spacing: .9px; }
  .mm-rail { width: 274px; }
  .mm-tools { width: 140px; }
}
@media (max-height: 760px) {
  .mm-bar { height: 58px; }
  .mm-tools, .mm-rail { top: 78px; }
  .spark { height: 12px; }
  .tool { padding: 5px 8px; }
}
@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition-duration: .01ms !important; }
}

/* City HUD: opaque, compact controls keep the browser's compositor cheap. */
[hidden] { display: none !important; }
button { touch-action: manipulation; }
button:disabled, button[aria-disabled="true"] { cursor: not-allowed; }
#city { touch-action: none; cursor: grab; }
#city.building { cursor: crosshair; }
#city:active { cursor: grabbing; }
.ui-icon { width: 22px; height: 22px; display: block; flex: none; }
.icon-btn { width: 42px; height: 42px; display: grid; place-items: center; border-radius: 12px; color: var(--text2); }
.icon-btn:hover { background: #e8f0e7; color: var(--green); }
.mm-bar { top: 18px; left: 20px; right: 183px; height: 64px; padding: 0; gap: 14px; border: 0; background: none; box-shadow: none; pointer-events: none; }
.brand, .stats { border: 1px solid #fff; background: var(--glass); border-radius: 16px; box-shadow: var(--shadow); pointer-events: auto; }
.brand { height: 64px; gap: 10px; padding: 10px 14px 10px 10px; }
.city-seal { width: 40px; height: 42px; display: grid; place-items: center; background: #358367; color: #fff6cd; border-radius: 11px; box-shadow: inset 0 -3px 0 #23684f; }
.city-seal .ui-icon { width: 27px; height: 27px; }
.mark .m1 { font-size: 9px; letter-spacing: 2px; color: var(--dim); }
.mark .m2 { font-size: 16px; letter-spacing: .3px; color: var(--text); margin-top: 4px; }
.clock { padding-left: 11px; margin-left: 2px; }
.clock .day { font-size: 13px; }
.clock .year { font-size: 9px; letter-spacing: 0; margin-top: 4px; }
.stats { gap: 0; height: 64px; padding: 8px 4px; }
.tile { position: relative; padding: 3px 10px 3px 41px; border: 0; border-radius: 0; background: none; border-right: 1px solid var(--line2); }
.tile:last-child { border-right: 0; }
.tile.wide { flex: 1.7; }
.tile .tl { font-size: 10px; letter-spacing: 0; color: var(--dim); margin-bottom: 3px; }
.tile .num { color: var(--text); font-size: 19px; letter-spacing: -.5px; line-height: 24px; font-variant-numeric: tabular-nums; }
.tile .tv { gap: 5px; }
.tile .sub { font-size: 10px; }
.k-app .sub { display: none; }
.stat-icon { position: absolute; left: 9px; top: 12px; color: var(--c); }
.stat-icon .ui-icon { width: 24px; height: 24px; }
.spark { display: none; }
.speed { position: fixed; bottom: 74px; left: 20px; gap: 0; pointer-events: auto; padding: 5px; background: var(--glass); border: 1px solid #fff; border-radius: 12px; box-shadow: var(--shadow); }
.speed .sl { display: none; }
.seg { background: none; border-color: var(--line); }
.speed .seg { border: 0; }
.sb { padding: 9px 11px; border: 0; border-radius: 7px; font-size: 12px; }
.sb.on { color: white; background: #398469; }
.sb:hover { color: var(--green); background: #e6efe4; }
.city-actions { position: absolute; top: 18px; right: 20px; display: flex; gap: 8px; pointer-events: auto; }
.hall-btn, .settings-btn { background: var(--glass); border: 1px solid #fff; box-shadow: var(--shadow); height: 48px; }
.hall-btn { display: flex; align-items: center; gap: 9px; border-radius: 14px; padding: 0 13px; font-size: 12px; font-weight: 650; }
.hall-btn .ui-icon { color: var(--green); }
.hall-btn[aria-expanded="true"] { background: #dfece0; }
.settings-btn { width: 42px; border-radius: 14px; }
.camera-controls { position: absolute; right: 20px; top: 95px; display: flex; flex-direction: column; gap: 3px; border: 1px solid white; background: var(--glass); border-radius: 14px; padding: 3px; box-shadow: var(--shadow); pointer-events: auto; }
.camera-controls .icon-btn { width: 36px; height: 36px; }
.mm-tools { left: auto; top: auto; bottom: 92px; right: 20px; width: 338px; max-height: calc(100dvh - 188px); display: block; padding: 0; overflow: auto; border-radius: 18px; border: 1px solid #fff; }
.catalog-head { display: flex; align-items: center; justify-content: space-between; padding: 19px 16px 15px 21px; }
.catalog-kicker { font-size: 11px; color: var(--dim); margin-bottom: 4px; }
.catalog-head h2 { margin: 0; font-size: 23px; font-weight: 650; letter-spacing: -.8px; }
.catalog-tabs { display: flex; padding: 0 14px; border-bottom: 1px solid var(--line); gap: 5px; }
.category { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 7px; padding: 11px 3px 12px; font-size: 11px; color: var(--dim); border-bottom: 3px solid transparent; }
.category .ui-icon { width: 22px; height: 22px; }
.category.on { color: var(--green); background: #edf3e9; border-bottom-color: #4c9570; border-radius: 10px 10px 0 0; font-weight: 650; }
.category:hover { color: var(--green); }
.category-title { padding: 17px 21px 6px; font-size: 11px; color: var(--dim); }
.tool-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; padding: 5px 14px 12px; }
.tool { position: relative; display: flex; flex-direction: column; gap: 3px; padding: 8px 3px 10px; border: 1px solid transparent; border-radius: 12px; background: transparent; text-align: center; min-width: 0; }
.tool:hover { background: #eaf1e7; border-color: #d5e3cf; }
.tool.on { background: #e3efdb; border-color: #91b878; box-shadow: inset 0 -2px 0 #b8cf9f; }
.tool .build-icon { width: 69px; height: 61px; filter: drop-shadow(0 3px 2px #52734b18); }
.tool .k { position: absolute; top: 5px; right: 6px; font-size: 8px; line-height: 14px; min-width: 13px; padding: 0 3px; background: #e9eee5; color: #778770; border-radius: 4px; }
.tool .tn { font-size: 11px; line-height: 15px; max-width: 100%; font-weight: 600; color: var(--text); }
.tool .tc { font-size: 11px; color: var(--amber); opacity: 1; }
.tool.poor { opacity: .48; }
.tool.doze { flex-direction: row; justify-content: center; margin: 0 16px 10px; padding: 7px 10px; gap: 10px; border-color: var(--line); background: #f1f4ee; }
.tool.doze .build-icon, .tool.doze .k { display: none; }
.tool.doze .tn { color: var(--text2); font-size: 10px; }
.tool.doze .tc { color: var(--dim); font-size: 10px; }
.tool.doze.on { border-color: #c78474; background: #f5e2d7; }
.catalog-note { padding: 12px 19px; display: flex; align-items: center; gap: 10px; border-top: 1px solid var(--line2); background: #f0f5ed; color: var(--dim); font-size: 10px; line-height: 15px; }
.catalog-note .ui-icon { width: 19px; }
.build-toggle { position: absolute; bottom: 24px; right: 20px; width: 160px; height: 50px; display: flex; gap: 11px; align-items: center; justify-content: center; border: 1px solid #91b395; border-radius: 14px; color: white; background: #377f60; box-shadow: 0 4px 0 #24553e, 0 8px 19px #153b3c38; pointer-events: auto; font-size: 14px; font-weight: 650; }
.build-toggle:hover { background: #438d6b; }
.build-toggle[aria-expanded="true"] { background: #f8fbf8; color: #377f60; border-color: #fff; box-shadow: 0 4px 0 #b8cbb7, 0 8px 19px #153b3c38; }
.mm-rail { top: 96px; bottom: 94px; right: 20px; width: 338px; z-index: 20; border: 1px solid white; border-radius: 17px; }
.mm-rail.collapsed { display: none; }
.tabs { padding: 8px 9px 0; }
.collapse { order: 5; font-size: 22px; }
.tab { font-size: 12px; padding: 12px 5px; }
.tab.on { border-color: var(--green); }
.pcard { background: #fff; padding: 11px; border-color: var(--line2); }
.pcard:hover, .choice:hover { background: #eaf2e7; }
.pcard.on { background: #eef3e5; border-color: #b6c99e; }
.pcard.on .psw { background: #538c64; }
.pname .n { font-size: 12px; }
.pblurb { color: var(--text2); font-size: 11px; }
.pcost { color: var(--amber); }
.psw { background: #d6dfd3; }
.psw .knob { background: #fff; }
.polhead, .brow.total { background: #e9f0e5; }
.brow, .orow { background: #f0f4eb; }
.mm-dock { left: 20px; bottom: 22px; gap: 9px; }
.mm-dock .seg { background: var(--glass); border-color: white; }
.ob { padding: 9px 10px; color: var(--text2); }
.ob:hover { background: #e8efe3; color: var(--green); }
.ob.on { color: var(--green); background: #e1ecda; }
.mm-dock .cap { letter-spacing: 0; font-size: 10px; }
.placement-hint { position: absolute; left: 50%; bottom: 25px; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; gap: 3px; color: white; text-shadow: 0 1px 5px #163c29; background: #274832e0; padding: 10px 18px; border-radius: 13px; }
.placement-hint strong { font-size: 12px; font-weight: 600; }
.placement-hint span { font-size: 10px; color: #e0e9d9; }
.cancel-build { position: absolute; right: -58px; top: 9px; background: var(--glass); color: var(--green); border-radius: 9px; padding: 8px 10px; font-size: 11px; pointer-events: auto; }
.graphics-panel { position: absolute; top: 78px; right: 20px; width: 290px; padding: 20px; border-radius: 16px; background: var(--glass); border: 1px solid #fff; box-shadow: var(--shadow); pointer-events: auto; z-index: 35; }
.graphics-panel h3 { font-size: 19px; margin: 0 0 6px; }
.graphics-panel p { color: var(--dim); font-size: 11px; line-height: 16px; margin: 0 0 13px; }
.quality-choice { width: 100%; padding: 12px; display: flex; flex-direction: column; gap: 4px; text-align: left; border: 1px solid var(--line); border-radius: 10px; margin-bottom: 6px; }
.quality-choice strong { font-size: 12px; }
.quality-choice span { font-size: 10px; color: var(--dim); }
.quality-choice.on { background: #e4efdc; border-color: #9ab786; }
.help-btn { position: absolute; left: 20px; top: 101px; width: 36px; height: 36px; border-radius: 50%; background: var(--glass); border: 1px solid white; box-shadow: var(--shadow); pointer-events: auto; color: var(--green); font-size: 18px; font-weight: 700; }
.mobile-map { display: none; }
.mm-tut { left: 20px; top: 151px; bottom: auto; width: 292px; z-index: 30; }
.mm-tut .th { letter-spacing: .5px; font-size: 11px; color: var(--green); }
.mm-tut .ok { background: #e0ebd7; color: var(--green); }
.mm-toasts { bottom: 99px; }
.mm-scrim { background: #1a302cbf; }
.choice { background: #f0f4eb; }
.choice .ck { background: #dfe9d9; }
.choice:focus-visible { background: #e4f0df; }
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-thumb { background: #bacbbb; }

@media (max-width: 1320px) {
  .tile { padding-left: 12px; } .stat-icon { display: none; }
  .tile .num { font-size: 17px; } .tile .tl { letter-spacing: 0; }
  .placement-hint { left: 57%; }
}
@media (max-width: 1050px) {
  .mm-bar { right: 174px; gap: 9px; } .brand { padding-right: 10px; } .clock { display: none; }
  .tile.k-rent, .tile.k-traf, .tile.k-unemp { display: none; }
  .placement-hint { left: 50%; bottom: 83px; }
  .mm-tools, .mm-rail { width: 312px; } .tool-grid { gap: 2px; }
  .mm-dock .sys { position: absolute; left: 0; bottom: 112px; }
}
@media (max-width: 700px) {
  .mm-bar { top: 10px; left: 10px; right: 10px; height: 55px; gap: 7px; }
  .brand { height: 55px; padding: 8px; gap: 0; } .city-seal { width: 35px; height: 37px; }
  .brand .mark { display: none; } .stats { height: 55px; }
  .tile { padding: 3px 7px; } .tile .num { font-size: 16px; line-height: 21px; }
  .tile .tl { font-size: 9px; } .tile .sub { display: none; } .tile.wide { flex: 1.4; }
  .city-actions { right: 10px; top: 78px; gap: 7px; } .hall-btn, .settings-btn { height: 42px; }
  .hall-btn { padding: 0 11px; } .camera-controls { top: 135px; right: 10px; }
  .help-btn { left: 12px; top: 80px; }
  .mobile-map { display: block; position: absolute; left: 57px; top: 82px; padding: 10px; background: var(--glass); border: 1px solid white; border-radius: 11px; box-shadow: var(--shadow); color: var(--green); font-size: 10px; pointer-events: auto; }
  .mm-root.map-open .mm-dock .ov { display: flex; position: fixed; left: 10px; top: 127px; bottom: auto; z-index: 25; }
  .mm-tools { width: min(338px, calc(100vw - 20px)); right: 10px; bottom: 84px; max-height: calc(100dvh - 220px); }
  .catalog-head { padding: 13px 12px 10px 18px; } .catalog-head h2 { font-size: 21px; }
  .category { padding: 8px 2px; gap: 4px; } .category-title { padding-top: 12px; }
  .tool .build-icon { height: 53px; } .tool { padding-top: 5px; padding-bottom: 7px; }
  .mm-rail { top: 132px; right: 10px; width: min(338px, calc(100vw - 20px)); bottom: 83px; }
  .build-toggle { right: 12px; bottom: 20px; width: 134px; height: 45px; font-size: 12px; }
  .speed { bottom: 22px; left: 10px; padding: 3px; } .sb { padding: 10px 9px; font-size: 11px; }
  .mm-dock { bottom: 80px; left: 10px; flex-direction: column; align-items: start; }
  .mm-dock .ov { display: none; } .mm-dock .sys { position: static; }
  .mm-dock .sys .ob { padding: 9px 8px; font-size: 10px; }
  .placement-hint { left: 50%; bottom: 142px; max-width: 240px; text-align: center; }
  .mm-tools:not([hidden]) ~ .placement-hint { display: none; }
  .mm-tools:not([hidden]) ~ .mm-dock { display: none; }
  .graphics-panel { top: 128px; right: 10px; }
  .mm-tut { left: 10px; top: 129px; max-width: calc(100vw - 75px); }
}
@media (max-height: 620px) and (min-width: 701px) {
  .mm-tools { bottom: 87px; max-height: calc(100dvh - 185px); }
  .catalog-head { padding-top: 12px; padding-bottom: 10px; }
  .tool .build-icon { height: 45px; } .category { padding: 6px 2px; }
  .catalog-note { display: none; } .category-title { padding-top: 8px; }
}

/* ---- district market -------------------------------------------------- */
/* Sits left of the rail. .mm-rail is 306px at right:10px, so 326px clears it;
   when the rail collapses to 44px this panel simply has more room, which is
   the only direction that matters. Reuses the .glass treatment above so it
   reads as part of the same HUD rather than a bolt-on. */
.mm-market {
  position: absolute; right: 326px; top: 86px; width: 268px;
  background: var(--glass); border: 1px solid var(--line); border-radius: 12px;
  padding: 10px 11px 9px; font-size: 11px;
}
.mkt-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.mkt-title { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.mkt-t1 { font-size: 8.5px; letter-spacing: 1.3px; color: var(--dim); }
.mkt-t2 {
  font-family: var(--mono); font-size: 11px; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* the badge is the panel's honesty: it always says which of the three data
   states you are looking at, and "local" is the default until a real snapshot
   lands. */
.mkt-badge {
  font-size: 8.5px; letter-spacing: 1px; text-transform: uppercase;
  padding: 2px 6px; border-radius: 999px; flex: none;
  border: 1px solid var(--line); color: var(--dim); background: var(--glass2);
}
.mkt-badge.live { color: var(--green); border-color: color-mix(in srgb, var(--green) 40%, var(--line)); }
.mkt-badge.stale { color: var(--rose); border-color: color-mix(in srgb, var(--rose) 40%, var(--line)); }

.mkt-term {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin: 7px 0 4px; padding-bottom: 6px; border-bottom: 1px solid var(--line2);
}
.mkt-office {
  font-family: var(--mono); font-size: 10px; color: var(--dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mkt-office.bad { color: var(--rose); }
.mkt-rating {
  font-family: var(--mono); font-size: 13px; font-weight: 600; color: var(--green); flex: none;
}
.mkt-rating.bad { color: var(--rose); }

.mkt-list { display: flex; flex-direction: column; }
.mrow {
  display: grid; grid-template-columns: 9px 1fr auto 42px 42px;
  align-items: center; gap: 6px; padding: 3px 0;
}
.mrow + .mrow { border-top: 1px solid var(--line2); }
.ma { font-size: 8px; color: var(--dim); text-align: center; }
.ma.up { color: var(--green); } .ma.down { color: var(--rose); }
.mn {
  font-family: var(--mono); font-size: 10px; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mv { font-family: var(--mono); font-size: 11.5px; font-weight: 600; text-align: right; }
.mc { font-family: var(--mono); font-size: 10px; color: var(--dim); text-align: right; }
.mc.up { color: var(--green); } .mc.down { color: var(--rose); }
.mspark { width: 42px; height: 14px; }
.mspark polyline { stroke: var(--dim); opacity: .55; }

.mkt-foot {
  margin-top: 7px; padding-top: 6px; border-top: 1px solid var(--line2);
  font-size: 9.5px; color: var(--dim); letter-spacing: .2px;
}

/* No room beside the rail on a narrow screen, and the game comes first. */
@media (max-width: 1180px) { .mm-market { display: none; } }

/* ---- wallet (driven by web3/bundle.js, inert without it) --------------- */
.w-status { font-family: var(--mono); font-size: 10px; color: var(--dim); margin-bottom: 5px; }
.w-row { display: flex; gap: 5px; }
.w-btn {
  flex: 1; padding: 5px 8px; font-size: 10px; border-radius: 7px;
  border: 1px solid var(--line); color: var(--text2); background: var(--glass2);
  white-space: nowrap; transition: background .12s, color .12s;
}
.w-btn:hover { background: var(--glass); color: var(--text); }
.w-btn.primary { background: var(--amber); border-color: var(--amber); color: #10161f; font-weight: 600; }
.w-btn.primary:hover { filter: brightness(1.06); }
.w-btn:disabled { opacity: .55; cursor: default; }

.w-scrim {
  position: fixed; inset: 0; z-index: 60; pointer-events: auto;
  background: rgba(20, 32, 28, .46); display: flex; align-items: center; justify-content: center;
}
.w-modal {
  width: min(360px, 92vw); padding: 20px; border-radius: 14px;
  background: var(--glass); border: 1px solid var(--line); box-shadow: var(--shadow);
  display: flex; flex-direction: column; gap: 9px;
}
.w-title { font-size: 15px; font-weight: 700; color: var(--text); }
.w-sub { font-size: 11px; color: var(--dim); line-height: 1.45; }
.w-input {
  font: inherit; font-size: 13px; padding: 9px 10px; border-radius: 8px;
  border: 1px solid var(--line); background: #fff; color: var(--text); width: 100%;
}
.w-input:focus { outline: 2px solid var(--cyan); outline-offset: 1px; }
.w-err { font-size: 10.5px; color: var(--rose); min-height: 13px; line-height: 1.35; }
.w-actions { display: flex; gap: 7px; }
.w-actions .w-btn { padding: 8px 10px; font-size: 11.5px; }

/* The same dialog, seen from the title screen.
   The wallet modal is drawn by the chain layer and inherits the HUD's light
   palette, which is right where it was born - inside a light HUD over the
   city. On the shell it is a white card in the middle of a dark carriage, so
   the shell restyles it rather than the chain layer growing a second theme it
   would have to keep in sync. Scoped to body.obs-open: in game it stays
   exactly the dialog it was. */
body.obs-open .w-scrim {
  background: rgba(6, 9, 10, .76);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
}
body.obs-open .w-modal {
  width: min(430px, 92vw); padding: 28px 28px 24px; border-radius: 16px; gap: 12px;
  background: rgba(17, 21, 23, .975); border-color: rgba(255, 255, 255, .13);
  font-family: var(--obs-serif);
  box-shadow: 0 30px 90px rgba(0, 0, 0, .6);
}
body.obs-open .w-title {
  font-family: var(--obs-display); font-size: 27px; font-weight: 400;
  text-transform: uppercase; letter-spacing: -.02em; color: #fff;
}
body.obs-open .w-sub { font-family: var(--ui); font-size: 12.5px; color: rgba(255, 255, 255, .62); }
body.obs-open .w-input {
  background: rgba(255, 255, 255, .06); border-color: rgba(255, 255, 255, .2);
  color: #fff; font-size: 15px; padding: 12px 13px;
}
body.obs-open .w-input::placeholder { color: rgba(255, 255, 255, .35); }
body.obs-open .w-btn {
  border-color: rgba(255, 255, 255, .28); color: rgba(255, 255, 255, .85);
  background: rgba(255, 255, 255, .05); border-radius: 999px;
}
body.obs-open .w-btn:hover { background: rgba(255, 255, 255, .14); color: #fff; }
body.obs-open .w-btn.primary { background: #fff; border-color: #fff; color: #10161a; font-weight: 600; }
body.obs-open .w-actions { margin-top: 4px; }
body.obs-open .w-actions .w-btn { padding: 11px 20px; font-size: 13.5px; }


/* ==== MAYOR shell =====================================================
   A train window onto the city. The frame never moves; the city outside it
   does, driven by scroll. What shows through the aperture is the live
   renderer underneath - there is no video layer and no second canvas.

   Instrument Serif is SELF-HOSTED, not linked. The module contract bans
   external fonts because CSP is default-src 'self' and the app must run from
   a desktop shell with no network; two woff2 files in src/fonts cost 43KB and
   settle it, so the design keeps the typeface it was drawn in. */
@font-face {
  font-family: 'Instrument Serif';
  font-style: normal; font-weight: 400; font-display: swap;
  src: url('fonts/instrument-serif.woff2') format('woff2');
}
@font-face {
  font-family: 'Instrument Serif';
  font-style: italic; font-weight: 400; font-display: swap;
  src: url('fonts/instrument-serif-italic.woff2') format('woff2');
}
/* Jaro, self-hosted rather than pulled from fonts.googleapis.com. The page's
   CSP is default-src 'self' and CONTRACT.md forbids external fonts, so the
   Google <link> tags would need both a style-src and a font-src exemption to
   render a single typeface. A 19KB file in the repo needs neither, works
   offline, and cannot change under us. Latin subset only - the UI is English.
   One weight: Jaro ships 400 and a variable optical size, nothing else. */
@font-face {
  font-family: 'Jaro';
  font-style: normal; font-weight: 400; font-display: swap;
  src: url('fonts/jaro.woff2') format('woff2');
}

:root {
  --obs-serif: 'Instrument Serif', Georgia, 'Iowan Old Style', 'Times New Roman', serif;
  /* The display face. Titles and the wordmark only - never body copy, never
     the HUD, which is dense tabular data Jaro would wreck. */
  --obs-display: 'Jaro', 'Arial Black', 'Segoe UI', system-ui, sans-serif;
  --obs-ink: #ffffff;
  --obs-dim: rgba(255, 255, 255, .72);
  --obs-gold: #e2ab4c;
  --obs-car: #0a0c0d;          /* carriage interior */
}

body.obs-open { overflow: hidden; }
body.obs-open #hud { opacity: 0; pointer-events: none; }
#hud { transition: opacity .45s ease; }

/* Nothing is on the canvas until the shell has pointed the camera at the
   title stop.
   game.js starts its frame loop the moment it loads, and shell.js is three
   script tags further down the body - so if the parser stops for any of them
   the renderer can get a frame away first, at the camera game.js centred for
   playing rather than the wide shot the title screen opens on. That frame is
   the flash of city on load. The class is on <body> in the markup and comes
   off in Shell.show(), one apply() after the camera is where it belongs; the
   fade is the same beat the shell itself arrives on, so the city appears with
   the carriage rather than before it. */
body.obs-boot { background: #06090a; }
body.obs-boot #city { opacity: 0; }
#city { transition: opacity .5s ease .1s; }

.obs-shell {
  position: fixed; inset: 0; z-index: 40;
  font-family: var(--obs-serif); color: var(--obs-ink);
  animation: obs-in .8s ease both;
}
@keyframes obs-in { from { opacity: 0; } to { opacity: 1; } }

/* ---- the carriage ------------------------------------------------------
   The overlay from the original design, self-hosted. object-fit:cover so it
   fills any viewport, and the scale(1.03) in the keyframes is load-bearing
   rather than decorative: without it the 6px lift would expose a bare edge
   at the bottom of the frame on every bob. */
.obs-car {
  position: absolute; inset: 0; width: 100%; height: 100%;
  /* cover, then scaled past it. The overlay is 1.79:1, so how much carriage
     you see depends entirely on the viewport's aspect: on a 2.1:1 pane cover
     crops vertically and the frame reads thick and obvious, while on a 1.6:1
     laptop it shows almost the whole plate and the frame thins to a sliver
     with the city bleeding edge to edge. Scaling past cover pins the frame at
     a usable weight on every shape, and it is also what hides the bob. */
  object-fit: cover; object-position: center 45%;
  pointer-events: none; z-index: 2; user-select: none;
  animation: train-bob 3s ease-in-out infinite;
  will-change: transform;
}
/* The original numbers, unchanged. */
@keyframes train-bob {
  0%, 100% { transform: translateY(0px) scale(1.22); }
  50%      { transform: translateY(-6px) scale(1.22); }
}
body.obs-still .obs-car { animation: none; transform: scale(1.22); }

/* Sits BELOW the carriage so it only ever darkens the view through the
   glass, never the seats and sill, which are already dark and lit. */
.obs-vignette {
  position: absolute; inset: 0; pointer-events: none; z-index: 1;
  background: radial-gradient(58% 50% at 50% 40%,
    rgba(6, 9, 10, .1) 0%, rgba(6, 9, 10, .42) 62%, rgba(6, 9, 10, .72) 100%);
}

/* ---- Lumora's liquid glass, unchanged in spirit ---- */
.liquid-glass {
  background: rgba(255, 255, 255, .01);
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, .1);
  position: relative; overflow: hidden;
}
.liquid-glass::before {
  content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1.4px;
  background: linear-gradient(180deg,
    rgba(255, 255, 255, .45) 0%, rgba(255, 255, 255, .15) 20%,
    rgba(255, 255, 255, 0) 40%, rgba(255, 255, 255, 0) 60%,
    rgba(255, 255, 255, .15) 80%, rgba(255, 255, 255, .45) 100%);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  pointer-events: none;
}

/* ---- nav ---- */
.obs-nav {
  position: absolute; top: 0; left: 0; right: 0; z-index: 5;
  display: flex; align-items: center; justify-content: space-between;
  padding: 22px 30px; gap: 18px; pointer-events: none;
}
.obs-nav > * { pointer-events: auto; }
.obs-mark {
  font-family: var(--obs-display); font-size: 21px; letter-spacing: .6px;
  color: #fff; text-decoration: none; cursor: pointer;
}
/* Jaro ships one upright weight and no italic, so the accent here is colour
   alone. Asking for italic would get a synthesised oblique, which shears a
   heavy display face into mush. */
.obs-mark-c { color: var(--obs-gold); }
.obs-links {
  display: flex; align-items: center; gap: 4px;
  padding: 5px 7px; border-radius: 999px;
}
.obs-link {
  font-family: var(--ui); font-size: 12.5px; letter-spacing: .1px;
  color: rgba(255, 255, 255, .88); padding: 7px 13px; border-radius: 999px;
  transition: color .2s, background .2s;
}
.obs-link:hover { color: #fff; background: rgba(255, 255, 255, .12); }
.obs-enter { background: #fff; color: #10161a; font-weight: 600; }
.obs-enter:hover { background: rgba(255, 255, 255, .9); color: #10161a; }

/* ---- the scroller ------------------------------------------------------
   Lenis drives this element, not the page: html and body are overflow:hidden
   and #app is fixed, so there is no document scroll to hijack. */
.obs-scroll {
  position: absolute; inset: 0; z-index: 3;
  overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: none;
}
.obs-scroll::-webkit-scrollbar { width: 0; height: 0; }
/* Centred, then pushed up, so the copy lands inside the main window rather
   than on the sill and the seats below it. The window's centre in the
   overlay sits near 42% of the height, which is what the offset targets. */
/* Left-aligned, and the right padding is what keeps it there: the copy sits
   in the left third of the window aperture so the city stays visible through
   the glass beside it, and the district ledger owns the opposite corner. */
.obs-scene {
  height: 100vh; display: flex; align-items: center; justify-content: flex-start;
  /* The top pad is the nav's own height. Centring alone puts a tall hero
     block behind the wordmark on a short viewport; this moves the centre
     rather than shrinking the type to avoid the collision. */
  padding: 86px 32vw 14vh 12vw; text-align: left;
}
/* Sized in rem, not ch. `ch` is the width of "0", and the serif's zero is
   narrow enough that 42ch lands at ~315px - starved next to a Jaro headline
   whose single word "GODDAMN" is 570px. A column shared by two typefaces has
   to be measured in the one unit both of them agree on. */
.obs-copy {
  max-width: min(34rem, 40vw); will-change: opacity, transform;
  display: flex; flex-direction: column; align-items: flex-start;
}

.obs-kicker {
  font-family: var(--ui); font-size: 9.5px; letter-spacing: 3.4px;
  color: rgba(255, 255, 255, .72); text-transform: uppercase; margin-bottom: 14px;
  text-shadow: 0 1px 12px rgba(0, 0, 0, .95);
}
.obs-title {
  margin: 0; font-family: var(--obs-display); font-weight: 400;
  line-height: .78; letter-spacing: -.03em;
  font-size: clamp(44px, 9.4vw, 158px);
  font-optical-sizing: auto;
  text-transform: uppercase;
  text-shadow: 0 2px 46px rgba(0, 0, 0, .75);
}
/* Each line its own block. Three short lines stacked read as a headline;
   one long wrapping string reads as a paragraph that happens to be huge. */
.obs-title .l { display: block; }
.obs-title em { font-style: normal; color: var(--obs-gold); }
.obs-stop {
  margin: 0; font-family: var(--obs-display); font-weight: 400;
  line-height: 1; letter-spacing: -.02em; text-transform: uppercase;
  font-size: clamp(34px, 5.2vw, 62px);
  text-shadow: 0 2px 34px rgba(0, 0, 0, .8);
}
/* The line that has to land. Italic serif, full white, sits above the body
   so the eye takes the argument before the detail. */
.obs-lede {
  margin: 18px 0 0; font-style: italic; color: #fff;
  font-size: clamp(17px, 1.9vw, 25px); line-height: 1.34; letter-spacing: -.2px;
  text-shadow: 0 1px 18px rgba(0, 0, 0, .95);
}
.obs-body {
  margin: 12px 0 0; font-size: clamp(14px, 1.45vw, 17px); line-height: 1.62;
  color: rgba(255, 255, 255, .84); text-shadow: 0 1px 16px rgba(0, 0, 0, .92);
}
/* The overheard complaint the whole game is an answer to. Ruled rather than
   boxed - a border-left is the quietest way to mark a quotation. */
.obs-quote {
  margin: 20px 0 0; padding-left: 17px; border-left: 2px solid var(--obs-gold);
  font-style: italic; font-size: clamp(15px, 1.6vw, 20px); line-height: 1.48;
  color: rgba(255, 255, 255, .92); text-shadow: 0 1px 16px rgba(0, 0, 0, .95);
}
.obs-punch {
  margin: 18px 0 0; font-size: clamp(15px, 1.6vw, 19px); color: #fff;
  letter-spacing: -.1px; text-shadow: 0 1px 16px rgba(0, 0, 0, .95);
}

.obs-cta { display: flex; gap: 10px; margin-top: 26px; flex-wrap: wrap; justify-content: flex-start; }
.obs-btn {
  font-family: var(--obs-serif); font-size: 16px; padding: 12px 30px; border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, .34); color: #fff;
  background: rgba(255, 255, 255, .06);
  transition: background .2s, border-color .2s, transform .15s;
}
.obs-btn:hover { background: rgba(255, 255, 255, .16); border-color: rgba(255, 255, 255, .55); transform: translateY(-1px); }
.obs-btn.primary { background: #fff; border-color: #fff; color: #10161a; }
.obs-btn.primary:hover { background: rgba(255, 255, 255, .9); }
.obs-btn.armed { border-color: var(--rose); color: #ffd9d4; background: rgba(187, 85, 76, .3); }
/* Third door, quieter than the other two: it is only ever an alternative to
   a decision already made, never the decision itself. */
.obs-btn.ghost {
  border-color: transparent; background: none; color: rgba(255, 255, 255, .62);
  padding-left: 14px; padding-right: 14px; text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, .25); text-underline-offset: 5px;
}
.obs-btn.ghost:hover { color: #fff; background: none; text-decoration-color: rgba(255, 255, 255, .7); }

/* ---- leaving ----
   The flight out. Everything the shell drew fades while the camera keeps
   moving underneath it; the canvas below has been live the whole time, so
   there is nothing to load and nothing to cover up. pointer-events goes
   first, so a stray wheel event cannot drive apply() into the flight. */
.obs-shell.leaving { pointer-events: none; }
.obs-shell.leaving .obs-car,
.obs-shell.leaving .obs-vignette,
.obs-shell.leaving .obs-scroll,
.obs-shell.leaving .obs-nav,
.obs-shell.leaving .obs-ledger,
.obs-shell.leaving .obs-foot {
  opacity: 0; transition: opacity .42s ease;
}
@media (prefers-reduced-motion: reduce) {
  .obs-shell.leaving .obs-car,
  .obs-shell.leaving .obs-vignette,
  .obs-shell.leaving .obs-scroll,
  .obs-shell.leaving .obs-nav,
  .obs-shell.leaving .obs-ledger,
  .obs-shell.leaving .obs-foot { transition: none; }
}
.obs-note {
  margin-top: 14px; font-family: var(--ui); font-size: 10.5px;
  letter-spacing: 1.4px; color: rgba(255, 255, 255, .6); text-transform: uppercase; min-height: 13px;
}
.obs-hint {
  margin-top: 22px; font-family: var(--ui); font-size: 9.5px; letter-spacing: 2.6px;
  text-transform: uppercase; color: rgba(255, 255, 255, .42);
  animation: obs-breathe 2.6s ease-in-out infinite;
}
@keyframes obs-breathe { 0%, 100% { opacity: .42; } 50% { opacity: .9; } }
body.obs-still .obs-hint { animation: none; }

/* ---- the district ledger ----
   Bottom-right, opposite the copy. Every name is always present; only the
   weight changes, so riding the line reads as a list filling in rather than
   a highlight sliding down it. */
.obs-ledger {
  position: absolute; right: 34px; bottom: 74px; z-index: 5;
  display: flex; flex-direction: column; align-items: flex-end; gap: 2px;
}
.obs-led {
  display: flex; align-items: center; justify-content: flex-end; gap: 9px;
  padding: 3px 0; transition: opacity .3s;
}
/* Stop 0 names no district. It keeps its slot so the rail stays a faithful
   scrubber for the ride, but it draws nothing. */
.obs-led.blank { height: 0; padding: 0; pointer-events: none; }
.obs-led-rule {
  width: 0; height: 1px; background: var(--obs-gold);
  transition: width .32s cubic-bezier(.2, .7, .3, 1);
}
.obs-led-name {
  font-family: var(--ui); font-size: 11px; letter-spacing: 2.4px; font-weight: 600;
  text-transform: uppercase; white-space: nowrap;
  color: rgba(255, 255, 255, .3);
  text-shadow: 0 1px 10px rgba(0, 0, 0, .95);
  transition: color .3s;
}
.obs-led.past .obs-led-name { color: rgba(255, 255, 255, .58); }
.obs-led.on   .obs-led-name { color: #fff; }
.obs-led.on   .obs-led-rule { width: 26px; }
.obs-led:hover .obs-led-name { color: #fff; }

/* ---- footer ---- */
.obs-foot {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 5;
  padding: 0 30px 20px; pointer-events: none;
}
/* Left, because the bottom-right corner now belongs to the ledger. */
.obs-stats { display: flex; gap: 22px; flex-wrap: wrap; justify-content: flex-start; }
.obs-stat {
  font-family: var(--ui); font-size: 9.5px; letter-spacing: 1.5px;
  text-transform: uppercase; color: rgba(255, 255, 255, .45);
}

/* ---- panels ---- */
.obs-shell > .obs-panel-host {
  position: absolute; inset: 0; z-index: 9; overflow-y: auto;
  background: rgba(6, 9, 10, .9);
  display: flex; align-items: flex-start; justify-content: center; padding: 46px 22px;
}
.obs-panel {
  position: relative; width: min(760px, 100%);
  background: rgba(17, 21, 23, .97); border: 1px solid rgba(255, 255, 255, .13);
  border-radius: 16px; padding: 34px 36px 38px;
  animation: obs-rise .35s ease both;
}
@keyframes obs-rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
.obs-panel h2 { margin: 0 0 6px; font-weight: 400; font-size: 33px; letter-spacing: -.4px; }
.obs-panel h3 { margin: 0 0 5px; font-family: var(--ui); font-size: 13.5px; font-weight: 700; color: #fff; }
.obs-panel h3.sub {
  margin: 26px 0 10px; font-family: var(--ui); font-size: 9.5px;
  letter-spacing: 2.2px; text-transform: uppercase; color: rgba(255, 255, 255, .5); font-weight: 600;
}
.obs-panel p { margin: 0; font-family: var(--ui); color: rgba(255, 255, 255, .68); line-height: 1.62; font-size: 13.5px; }
.obs-panel p.lede { font-family: var(--obs-serif); font-size: 17px; line-height: 1.55; color: rgba(255, 255, 255, .8); }
.obs-panel p.fine { margin-top: 20px; font-size: 12px; opacity: .6; }
.obs-close {
  position: absolute; top: 12px; right: 15px; font-size: 27px; line-height: 1;
  color: rgba(255, 255, 255, .6); padding: 4px 10px; border-radius: 8px;
}
.obs-close:hover { color: #fff; background: rgba(255, 255, 255, .09); }

.obs-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 13px; margin-top: 20px; }
.obs-card { padding: 16px 17px; border-radius: 11px; background: rgba(255, 255, 255, .045); border: 1px solid rgba(255, 255, 255, .08); }
.obs-card p { font-size: 12.5px; }

.obs-keys { display: grid; grid-template-columns: auto 1fr; gap: 7px 18px; margin: 0; }
.obs-keys dt {
  font-family: var(--mono); font-size: 11.5px; color: #fff;
  background: rgba(255, 255, 255, .1); padding: 3px 9px; border-radius: 5px; white-space: nowrap;
}
.obs-keys dd { margin: 0; font-family: var(--ui); color: rgba(255, 255, 255, .68); font-size: 12.5px; align-self: center; }

.obs-choices { display: flex; gap: 9px; flex-wrap: wrap; }
.obs-choice {
  flex: 1 1 190px; text-align: left; padding: 13px 15px; border-radius: 11px;
  border: 1px solid rgba(255, 255, 255, .13); background: rgba(255, 255, 255, .04);
  display: flex; flex-direction: column; gap: 3px; transition: border-color .18s, background .18s;
}
.obs-choice:hover { background: rgba(255, 255, 255, .09); }
.obs-choice.on { border-color: var(--obs-gold); background: rgba(226, 171, 76, .14); }
.obs-choice strong { font-family: var(--ui); font-size: 13px; font-weight: 700; }
.obs-choice span { font-family: var(--ui); font-size: 11px; color: rgba(255, 255, 255, .6); line-height: 1.45; }
.obs-choice.wide { flex-basis: 100%; }

/* Short viewports, not narrow ones. A 13-inch laptop with browser chrome, or
   a docked window, lands near 600px of height - and the hero block is tall
   enough that it overflows the aperture upward and collides with the nav.
   Height queries are the ones that matter for a full-bleed screen. */
@media (max-height: 760px) {
  .obs-title { font-size: clamp(40px, 11vh, 104px); }
  .obs-lede { font-size: clamp(16px, 2.4vh, 21px); margin-top: 12px; }
  .obs-quote { margin-top: 14px; }
  .obs-punch { margin-top: 12px; }
  .obs-ledger { bottom: 58px; gap: 0; }
  .obs-stop { font-size: clamp(28px, 5.5vh, 50px); }
  .obs-body { font-size: 14px; margin-top: 12px; }
  .obs-scene { padding-bottom: 9vh; }
  .obs-cta { margin-top: 18px; }
  .obs-kicker { margin-bottom: 10px; }
}
@media (max-height: 560px) {
  .obs-hint, .obs-note, .obs-foot { display: none; }
  .obs-title { font-size: clamp(30px, 7vh, 60px); }
  .obs-quote, .obs-lede { display: none; }
  .obs-ledger { display: none; }
  .obs-body { font-size: 12.5px; line-height: 1.5; }
  .obs-btn { padding: 9px 22px; font-size: 14px; }
}

@media (max-width: 900px) {
  .obs-ledger { display: none; }
  .obs-stats { display: none; }
  .obs-nav { padding: 16px 18px; }
  .obs-link { padding: 6px 10px; font-size: 11.5px; }
  .obs-scene { padding: 0 8vw 12vh; }
  .obs-panel { padding: 26px 22px 30px; }
}
@media (prefers-reduced-motion: reduce) {
  .obs-shell, .obs-panel { animation: none; }
  .obs-car, .obs-hint { animation: none; }
  #hud { transition: none; }
}

/* ================================================================== *
 * the inspector - src/inspect.js
 *
 * Two surfaces. The tooltip is a name and one line of context, following
 * the cursor; the panel is the full record, parked in the left column
 * between the top bar and the dock, which is the only region of the HUD
 * nothing else claims.
 *
 * Both are pointer-events:auto islands inside #hud, which is not - the
 * canvas underneath has to keep receiving drags.
 * ================================================================== */

.ens-tip {
  position: absolute; top: 0; left: 0; z-index: 40;
  pointer-events: none;
  max-width: min(420px, 72vw);
  padding: 7px 11px 8px;
  background: var(--glass);
  border: 1px solid #fff;
  border-radius: 10px;
  box-shadow: var(--shadow);
  opacity: 0; transition: opacity .10s ease;
  will-change: transform;
}
.ens-tip.on { opacity: 1; }
.ens-tip-name {
  font-family: var(--mono); font-size: 12.5px; font-weight: 600;
  color: var(--text); letter-spacing: .1px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.ens-tip-sub {
  font-size: 10.5px; color: var(--dim); margin-top: 2px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
/* Colour carries the class of thing, so you learn what you are pointing at
   before you finish reading the name. */
.ens-tip[data-kind="parcel"] .ens-tip-name { color: var(--green); }
.ens-tip[data-kind="person"] .ens-tip-name { color: var(--cyan); }
.ens-tip[data-kind="cab"]    .ens-tip-name { color: var(--amber); }
.ens-tip[data-kind="bus"]    .ens-tip-name { color: var(--violet); }

.ens-panel {
  position: absolute; left: 20px; top: 96px; width: 340px;
  max-height: calc(100dvh - 232px);
  display: none; flex-direction: column; overflow: hidden;
  pointer-events: auto; z-index: 30;
  background: var(--glass); border: 1px solid #fff;
  border-radius: 17px; box-shadow: var(--shadow);
}
.ens-panel.on { display: flex; }

.ens-head { position: relative; padding: 17px 44px 13px 19px; border-bottom: 1px solid var(--line); }
.ens-kicker { font-size: 9px; letter-spacing: 1.8px; color: var(--dim); }
.ens-title { margin: 3px 0 5px; font-size: 20px; font-weight: 650; letter-spacing: -.5px; }
.ens-addr {
  font-family: var(--mono); font-size: 11px; color: var(--green);
  word-break: break-all; line-height: 1.35;
}
.ens-close {
  position: absolute; top: 12px; right: 12px; width: 28px; height: 28px;
  border-radius: 8px; font-size: 19px; line-height: 1; color: var(--dim);
}
.ens-close:hover { background: #e8efe3; color: var(--text); }

.ens-body { padding: 4px 19px 18px; overflow-y: auto; }
.ens-sec { padding-top: 14px; }
.ens-sec h3 {
  margin: 0 0 7px; font-size: 9px; letter-spacing: 1.6px;
  color: var(--dim); font-weight: 600;
}

/* the namespace tree */
.ens-tree { list-style: none; margin: 0; padding: 0; }
.ens-tree li {
  display: flex; align-items: baseline; gap: 6px;
  padding: 3px 0; font-family: var(--mono); font-size: 11px;
}
.ens-depth { color: var(--line); width: 9px; flex: none; }
.ens-label { color: var(--text2); word-break: break-all; flex: 1; }
.ens-tree li.self .ens-label { color: var(--text); font-weight: 600; }
.ens-tree li.self .ens-depth { color: var(--amber); }
.ens-badge {
  flex: none; font-family: var(--ui); font-size: 8px; letter-spacing: .8px;
  padding: 2px 6px; border-radius: 999px;
  background: var(--line2); color: var(--dim);
}
.ens-badge.live { background: #dceadf; color: var(--green); }

/* fact tables */
.ens-facts { display: grid; grid-template-columns: 104px 1fr; gap: 4px 10px; margin: 0; }
.ens-facts dt { font-size: 11px; color: var(--dim); }
.ens-facts dd { margin: 0; font-size: 11.5px; color: var(--text); word-break: break-word; }
.ens-facts dd.mono { font-family: var(--mono); font-size: 10.5px; color: var(--text2); }

/* the roll of people */
.ens-roll { list-style: none; margin: 0; padding: 0; }
.ens-roll li {
  display: grid; grid-template-columns: 1fr auto; gap: 0 8px;
  padding: 6px 0; border-bottom: 1px solid var(--line2);
}
.ens-roll li:last-child { border-bottom: 0; }
.ens-who { font-size: 12px; font-weight: 600; }
.ens-trade { font-size: 10.5px; color: var(--dim); text-align: right; align-self: center; }
.ens-roll .ens-sub {
  grid-column: 1 / -1; font-family: var(--mono); font-size: 10px;
  color: var(--cyan); word-break: break-all;
}
.ens-more { margin: 9px 0 0; font-size: 10.5px; color: var(--dim); }
.ens-note {
  margin: 16px 0 0; font-size: 10.5px; line-height: 1.5; color: var(--dim);
  padding-top: 12px; border-top: 1px solid var(--line2);
}

/* On a short or narrow window the record takes the whole left column and
   the tooltip shrinks; neither may ever push the canvas around. */
@media (max-width: 760px), (max-height: 620px) {
  .ens-panel { left: 10px; right: 10px; width: auto; top: 84px; max-height: 58dvh; }
  .ens-tip { max-width: 60vw; }
}
