* { box-sizing: border-box; margin: 0; padding: 0; }
html { height: 100%; }
/* Column layout: #app takes the remaining height, #measurements is docked
   below it at a fixed height. min-height:0 on #app is what lets the sidebar
   and the map shrink instead of pushing the measurements panel off-screen. */
body {
  height: 100%; font-family: system-ui, sans-serif; font-size: 14px;
  display: flex; flex-direction: column;
  --mp-h: 180px;
}
#app { display: flex; flex: 1 1 auto; min-height: 0; }

/* ---- Left panel ---- */
#panel {
  width: 380px; min-width: 380px;
  background: #f7f7f7;
  border-right: 1px solid #ddd;
  display: flex; flex-direction: column;
  overflow-y: auto;
}

/* ---- Panel title ---- */
#panel-title {
  padding: 10px 12px 8px;
  border-bottom: 1px solid #ddd;
  flex-shrink: 0;
}
#panel-title h2 { font-size: 14px; font-weight: 700; color: #222; }
#panel-title .subtitle { font-size: 11px; color: #777; margin-top: 2px; }
#panel-title .copyright { font-size: 10px; color: #aaa; margin-top: 1px; }
.title-footer { display: flex; align-items: center; justify-content: space-between; }
.adv-toggle {
  display: flex; align-items: center; gap: 3px;
  font-size: 10px; color: #aaa; cursor: pointer;
}
.adv-toggle input { margin: 0; cursor: pointer; }
/* Advanced is a *user* gate (CSS class); the inline display:none data gates
   mean "this study cannot show this" and must still win when Advanced is on. */
body:not(.adv-on) .adv-only { display: none !important; }
/* Page nav (Map | Calibration | …) — same strip idiom as the mode toggles,
   but links between the applet's pages rather than in-page state. */
.applet-nav {
  display: flex; border: 1px solid #ccc; border-radius: 4px;
  overflow: hidden; margin-top: 6px;
}
.applet-nav a {
  flex: 1; padding: 4px 8px; text-align: center; text-decoration: none;
  background: white; font-size: 11px; color: #555; font-weight: 600;
}
.applet-nav a:hover { background: #f0f4ff; }
.applet-nav a.active { background: #4a90d9; color: white; }

/* ---- Collapsible sidebar sections ---- */
.sidebar-section { border-bottom: 1px solid #ddd; }
.section-header {
  display: flex; flex-direction: column;
  padding: 7px 12px; cursor: pointer;
  font-size: 12px; font-weight: 600; color: #555;
  user-select: none; background: #f0f0f0;
}
.section-header:hover { background: #e8e8e8; }
.sec-label {
  padding: 7px 12px;
  font-size: 12px; font-weight: 600; color: #555;
  background: #f0f0f0;
  border-bottom: 1px solid #e0e0e0;
  display: flex; justify-content: space-between; align-items: center;
}
.sec-header-top {
  display: flex; justify-content: space-between; align-items: center;
}
.sec-arrow { font-size: 10px; color: #999; transition: transform 0.15s; }
.sidebar-section.expanded .sec-arrow { transform: rotate(90deg); }
.section-body { display: none; padding: 8px 10px; }
.sidebar-section.expanded .section-body { display: block; }
.sec-summary { font-size: 12px; color: #333; font-weight: 500; margin-top: 3px; white-space: normal; line-height: 1.3; }
.sidebar-section.expanded .sec-summary { display: none; }

/* ---- Dropdowns ---- */
.ctrl-group { display: flex; flex-direction: column; gap: 3px; margin-bottom: 6px; }
.ctrl-group:last-child { margin-bottom: 0; }
.ctrl-group label { font-size: 11px; font-weight: 600; color: #666; }
.ctrl-group select {
  width: 100%; padding: 4px 6px; border: 1px solid #ccc;
  border-radius: 4px; background: white; font-size: 12px; cursor: pointer;
}
.ctrl-group select:focus { outline: 2px solid #4a90d9; }
.ctrl-group select:disabled { background: #f0f0f0; color: #aaa; cursor: not-allowed; }

/* ---- Tooltip-indicator icon ----
   Disabled <select>s and tightly-packed grid cells consume hover area and
   suppress the native title-attr tooltip from showing on their parents.
   `.tip` is a small `(?)` glyph placed next to a label that carries the
   title= itself: always discoverable, always hoverable, regardless of
   neighboring disabled controls. */
.tip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 13px; height: 13px;
  margin-left: 3px;
  border-radius: 50%;
  background: #c2c9d2;
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  cursor: help;
  vertical-align: middle;
  line-height: 1;
  user-select: none;
}
.tip:hover { background: #4a90d9; }

/* ---- Traveler profile (always-visible compact section) ---- */
#traveler-section {
  border-bottom: 1px solid #ddd;
  padding: 7px 10px 8px;
  background: #f0f0f0;
}
.traveler-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
}
.traveler-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #777;
}
.uc-toggle-strip {
  display: flex;
  border: 1px solid #ccc;
  border-radius: 4px;
  overflow: hidden;
}
.uc-toggle-btn {
  padding: 3px 10px;
  border: none;
  background: white;
  font-size: 11px;
  cursor: pointer;
  color: #555;
  line-height: 1.4;
}
.uc-toggle-btn:hover { background: #f0f4ff; }
.uc-toggle-btn.active { background: #4a90d9; color: white; font-weight: 600; }
.traveler-grid {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1fr;
  gap: 8px;
}
.traveler-grid .ctrl-group { min-width: 0; }
.traveler-extras {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 6px;
}
.traveler-extras:empty,
.traveler-extras:not(:has(> *:not([style*="display:none"]))) {
  margin-top: 0;
}
#uc-specific-controls { display: none; }
#uc-specific-controls.visible { display: block; }

/* ---- Indicator list ----
   `.ind-group` was an accordion; SPEC-s22 S2 flattens the panel into one
   ordered column of buttons. The four `[data-group]` wrapper divs survive as
   plain grouping containers only — grpSel() and state.activeGroup resolution
   (app.js, compare.js, indicators.js) key off `.ind-group[data-group="X"]` —
   so they carry no border/background/radius and no open/closed state; every
   row in every group is always rendered. `.ind-group-body` also survives as a
   nesting level (compare.js appends its mode-change buttons into it) but is
   always visible now. */
.ind-group { margin-bottom: 10px; }
.ind-group-body { padding: 0; }
/* #ind-subctrl (SPEC-s22 S4, §5): the single shared sub-control host,
   relocated by app.js's syncSubControls() to sit under whichever row is
   currently active. A sub-control row gets ~345px at panel width 380px. */
.ind-subctrl { display: flex; flex-direction: column; gap: 3px; margin: 6px 0 2px; }
.ind-subctrl label { font-size: 11px; font-weight: 600; color: #666; }
.ind-subctrl select { width: 100%; padding: 4px 6px; border: 1px solid #ccc; border-radius: 4px; background: white; font-size: 12px; cursor: pointer; }

.ind-btn {
  display: block; width: 100%; text-align: left;
  padding: 4px 7px; margin-bottom: 2px;
  border: 1px solid #ddd; border-radius: 3px;
  background: white; cursor: pointer; font-size: 11px; color: #444;
}
.ind-btn:last-child { margin-bottom: 0; }
.ind-btn:hover { background: #f0f4ff; }
.ind-btn.active {
  background: #4a90d9; color: white; border-color: #3a7bc8; font-weight: 600;
}

/* ---- Normalization strips (per km² / total / per person / %) ---- */
/* Right-aligned, compact pill row. width:fit-content + margin-left:auto
   keeps it small without needing a float (and, as a flex item in the
   sub-control host's column, aligns it to the row's right edge).
   SPEC-s22 §5.3 moved these out of the indicator groups: they are no longer
   one fixed toggle per group but two elements in #ind-subctrl whose buttons
   renderNormStrip() rebuilds for whichever indicator is active. */
.norm-toggle {
  display: flex;
  border: 1px solid #ccc;
  border-radius: 3px;
  overflow: hidden;
  margin: 0 0 3px auto;
  width: fit-content;
}
.norm-btn {
  padding: 0 8px;
  border: none;
  background: white;
  font-size: 10px;
  color: #666;
  cursor: pointer;
  line-height: 1.6;
}
.norm-btn + .norm-btn { border-left: 1px solid #ddd; }
.norm-btn:hover { background: #f0f4ff; }
.norm-btn.active { background: #4a90d9; color: white; font-weight: 600; }

/* ---- Sub-control checkbox row (SPEC-s22 §5.5's log₁₀ switch) ---- */
/* Metrics match the normalization strips above so the host's remaining
   controls line up whichever combination is showing. */
.subctrl-check { display: flex; align-items: center; gap: 5px; margin: 2px 0 4px; font-size: 12px; }
.subctrl-check input { margin: 0; cursor: pointer; }
.subctrl-check label { font-size: 11px; font-weight: 600; color: #666; cursor: pointer; }

/* ---- Outbound indicator buttons ---- */
.od-btn {
  display: block; width: 100%; text-align: center;
  padding: 3px 1px; border: 1px solid #ddd; border-radius: 3px;
  background: white; cursor: pointer; font-size: 11px; color: #aaa;
  transition: background 0.1s;
}
.od-btn:hover:not(:disabled) { background: #f0f4ff; color: #444; }
.od-btn.active { background: #4a90d9; color: white; border-color: #3a7bc8; }
.od-btn:disabled { background: #f4f4f4; color: #ccc; cursor: not-allowed; border-color: #eee; }

/* ---- Composite indicator chips (Mode choice / Destination choice) ----
   Indicators with no live per-mode column read as text buttons in the
   .ind-btn idiom. They keep .od-btn so every selection/disable path still
   finds them; these rules only undo .od-btn's centred glyph and muted
   colour. The .active and
   :disabled rules are the same in both classes, so they need no override. */
.ind-row { margin-bottom: 4px; }
.ind-row:last-child { margin-bottom: 0; }
/* Session 27: an indicator button with its own drop-down to the right, on one
   line — "Destinations per km² [Shop ▾]". The button keeps .ind-btn's
   display:block/width:100% in the cascade, so `flex: 1 1 auto; min-width: 0`
   is what actually lets the select claim its width instead of being pushed
   off the panel. The select is capped rather than sized so a long category
   name ("Religious or community") truncates instead of squeezing the button
   down to its ellipsis. */
.ind-row-inline { display: flex; align-items: center; gap: 5px; }
body.adv-on .ind-row-inline.adv-only { display: flex; }
.ind-row-inline > .ind-btn { flex: 1 1 auto; min-width: 0; margin-bottom: 0; }
.row-select {
  flex: 0 1 auto; max-width: 46%; min-width: 0;
  padding: 3px 4px; border: 1px solid #ccc; border-radius: 3px;
  background: white; font-size: 11px; color: #444; cursor: pointer;
}
.od-chip {
  text-align: left; color: #444; padding: 4px 7px; margin-bottom: 2px;
}
.od-chip:last-child { margin-bottom: 0; }

/* ---- Per-mode generalized impedance (Mode choice family) ----
   One indicator per mode rather than an indicator x column cell, so these are
   .ind-btn (not .od-btn) laid out as a wrapping chip row. The swatch carries
   the mid stop of that mode's ramp, so the button reads as its map.
   SPEC-s22 S4 split the old single `#impedance-modes` block: `.imp-row-label`
   is now the static row (`#row-gtm`) that stays in the flat list, and the
   chips (`.imp-btns` / `.imp-btn`) are shared sub-control host content that
   moves — the CAR / CAR_NONHH pair also merges into one chip (§5.1); see
   app.js buildImpedanceButtons / updateImpedanceButtonState. */
.imp-row-label {
  font-size: 10px; color: #555; padding: 2px 3px 3px 0;
  display: flex; align-items: center; line-height: 1.2;
  cursor: pointer; border-radius: 3px;
}
/* Clickable (app.js wires a click handler): the chip row underneath only
   shows once a gtm_* indicator is already active, so this row needs its own
   affordance as the family's entry point. */
.imp-row-label:hover { background: #f0f4ff; }
/* Session 27: one chip row PER FAMILY, permanently under its own row label
   (`#chips-gtm` / `#chips-pmode` / `#chips-trips`) rather than one shared row
   the sub-control host moved about. The chips have to be visible whether or
   not their family is the active indicator, and a single relocating row
   cannot be under three labels at once. */
.imp-btns { display: flex; flex-wrap: wrap; gap: 3px; margin: 0 0 6px; }
.imp-btn {
  display: inline-flex; align-items: center; gap: 5px;
  width: auto; margin-bottom: 0; padding: 3px 8px 3px 6px;
}
.imp-btn::before {
  content: ''; flex: none; width: 9px; height: 9px; border-radius: 2px;
  background: var(--imp-chip, #ccc);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.18);
}
.imp-btn:disabled {
  background: #f4f4f4; color: #ccc; cursor: not-allowed; border-color: #eee;
}
/* The chip is the mode's identity, so it dims rather than disappearing. */
.imp-btn:disabled::before { opacity: 0.3; }
.imp-btn:disabled:hover { background: #f4f4f4; }
.imp-btn.active::before { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.55); }

/* ---- Layer toggles ---- */
.layer-toggle-row {
  display: flex; align-items: center; gap: 6px;
  font-size: 11px; cursor: pointer; padding: 2px 0;
}
.layer-toggle-row input[type="checkbox"] { cursor: pointer; flex-shrink: 0; }
.layer-swatch {
  display: inline-block; width: 20px; height: 4px;
  border-radius: 2px; flex-shrink: 0;
}
.transit-freq-legend {
  margin: 2px 0 2px 22px; display: flex; flex-direction: column; gap: 2px;
}
.transit-freq-row {
  display: flex; align-items: center; gap: 5px; font-size: 10px; color: #777;
}
.transit-freq-swatch {
  display: inline-block; width: 14px; height: 3px; border-radius: 1px; flex-shrink: 0;
}

/* ---- Map area ---- */
#map-area { flex: 1; display: flex; flex-direction: column; position: relative; }
#map { flex: 1; }

/* Loading overlay shown while a scenario's lazily-fetched data is in flight. */
#loading-overlay {
  position: absolute;
  inset: 0;
  z-index: 950;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.45);
}
#loading-overlay[hidden] { display: none; }
#loading-overlay .spinner {
  width: 40px;
  height: 40px;
  border: 4px solid rgba(74, 144, 217, 0.25);
  border-top-color: #4a90d9;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- Measurements panel (bottom-docked, full width, fixed height) ----
   Replaces the floating #mp-body. The panel is always present; when no
   origin is pinned it shows #mp-placeholder instead of #mp-body.

   #mp-body uses CSS multi-column so the migrated hover-panel blocks fill the
   width instead of running off the bottom; overflow spills into further
   columns and is reachable by scrolling horizontally. The mode-choice panel
   opts out of the column flow (info-panel--mc) and scrolls vertically instead:
   at the panel's 180px it is a table plus one side block, and a column flow
   would push the side block off the right edge rather than let it scroll.
   The original brief said no scrolling at all; the dock is now firmly 180px,
   which makes a scrollbar the honest alternative to silent clipping. */
#measurements {
  flex: 0 0 var(--mp-h); height: var(--mp-h);
  background: #fff; border-top: 1px solid #ccc;
  display: flex; flex-direction: column;
  font-size: 12px; color: #333;
}
#mp-header {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 10px;
  padding: 5px 12px; background: #f7f7f7; border-bottom: 1px solid #e3e3e3;
}
/* Panel-supplied context, left of the O -> D slots. Hidden entirely when the
   active panel has nothing to put there, so the header does not carry an empty
   rule. Shrinks before the O -> D readout does. */
#mp-context {
  display: flex; align-items: baseline; gap: 10px;
  flex: 0 1 auto; min-width: 0; overflow: hidden;
  font-size: 11px; color: #556; white-space: nowrap;
  padding-right: 10px; border-right: 1px solid #ddd;
}
#mp-context:empty { display: none; }
#mp-context b { color: #222; }
#mp-context .mp-ctx-who { overflow: hidden; text-overflow: ellipsis; }
#mp-context .mp-ctx-lmc { color: #445; cursor: help; }
.mp-od { display: flex; align-items: center; gap: 6px; font-size: 12px; flex: 0 0 auto; }
.mp-od-slot {
  padding: 2px 7px; border-radius: 3px; border: 1px solid #ddd;
  background: #fff; color: #999; font-variant-numeric: tabular-nums;
}
.mp-od-slot.filled { color: #222; font-weight: 600; border-color: #b9cbe4; background: #eef4fb; }
.mp-od-slot.previewing { color: #444; font-style: italic; border-style: dashed; }
.mp-od-arrow { color: #888; }
/* Outside the OD family the header reports ONE zone: no arrow, no empty
   destination slot, no Swap (renderMeasurementsHeader). Three widgets
   asserting a pair that does not exist, and ~140px #mp-context could use. */
.mp-od.mp-od--single .mp-od-arrow,
.mp-od.mp-od--single #mp-od-dest { display: none; }
.mp-btn[hidden] { display: none; }
.mp-stage {
  color: #777; font-style: italic;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mp-spacer { flex: 1; }
.mp-btn {
  background: #fff; border: 1px solid #ccc; border-radius: 3px;
  padding: 2px 8px; font-size: 11px; color: #1a4a8a; cursor: pointer;
  /* Never wrap or shrink: a two-line "Swap" makes the whole header taller,
     and the header's height comes straight out of the body's 148px. */
  white-space: nowrap; flex: 0 0 auto;
}
.mp-btn:hover:not(:disabled) { background: #eef4fb; border-color: #b9cbe4; }
.mp-btn:disabled { color: #bbb; cursor: default; }
#mp-body {
  flex: 1 1 auto; min-height: 0;
  /* Asymmetric bottom padding: at 180px the mode panel's formula line lands
     within ~2px of the fold, and a symmetric 8px was enough on its own to
     raise a 6px scrollbar on the common case. */
  padding: 6px 12px 4px;
  columns: 380px 3; column-gap: 22px; column-rule: 1px solid #eee;
  overflow-x: auto; overflow-y: auto;
}
#mp-body > * { break-inside: avoid; }
#mp-placeholder {
  flex: 1 1 auto; display: none;
  align-items: center; justify-content: center;
  color: #999; font-size: 12px; text-align: center; padding: 0 20px;
}
#measurements.mp-empty #mp-body { display: none; }
#measurements.mp-empty #mp-placeholder { display: flex; }
#mp-body .pn-name { font-weight: 700; margin-bottom: 5px; color: #222; font-size: 13px; }
.pn-row { display: flex; justify-content: space-between; gap: 8px; padding: 1px 0; }
.pn-label { color: #666; }
.pn-val { font-weight: 600; color: #222; }
#mp-body .pn-row { display: flex; justify-content: space-between; gap: 8px; padding: 1px 0; }
#mp-body .pn-label { color: #666; }
#mp-body .pn-val { font-weight: 600; color: #222; }
.pn-dens-swatch {
  display: inline-block; width: 10px; height: 10px;
  border-radius: 2px; margin-right: 5px;
}
#mp-body .pn-section { margin-top: 5px; padding-top: 4px; border-top: 1px solid #eee; }
#mp-body .pn-mode-table { width: 100%; border-collapse: collapse; }
#mp-body .pn-mode-table th {
  text-align: right; color: #666; font-weight: 500; padding: 1px 4px 3px 4px;
  font-size: 10px; border-bottom: 1px solid #ddd;
}
#mp-body .pn-mode-table th:first-child { text-align: left; }
#mp-body .pn-mode-table td { text-align: right; padding: 2px 4px; color: #444; font-size: 11px; }
#mp-body .pn-mode-table td:first-child { text-align: left; color: #555; }
#mp-body .pn-mode-table tr.pn-optimal td,
#mp-body .pn-mode-table tr.pn-likeliest td { font-weight: 700; color: #111; }
/* The row the `pmode_{MODE}` choropleth is showing (SPEC-s22 §6). Deliberately
   a different channel from pn-likeliest's weight — the two rows are often
   different modes and must stay separately readable — so this is a rule on the
   row box plus an underline on the Share cell the map is actually painting. */
#mp-body .pn-mode-table tr.pn-mapped-mode td { box-shadow: inset 0 -2px 0 -1px #444; }
#mp-body .pn-mode-table tr.pn-mapped-mode td:first-child { box-shadow: inset 2px -2px 0 -1px #444; }
#mp-body .pn-mode-table td.pn-mapped-cell {
  font-weight: 700; color: #111; background: rgba(0, 0, 0, 0.07);
}
#mp-body .pn-optimal-badge {
  display: inline-block; font-size: 9px; font-weight: 600;
  color: #fff; background: #4a90d9; border-radius: 3px;
  padding: 0 3px; margin-left: 3px; vertical-align: middle;
}
/* `info-panel--wide` was the floating panel's 340px -> 560px widening. The
   measurements panel is always full-width, so the class is inert here; the
   JS still sets it and the rule is kept as the documented no-op. */
#mp-body.info-panel--wide { max-width: none; }
#mp-body .pn-util-purpose { font-weight: 600; color: #445; font-size: 11px; }
/* .od-purpose (the labelled select block that hosted Trip purpose,
   Destination category and Destination type) is gone as of session 27 — all
   three moved inline onto their own indicator rows as `.row-select`. */
/* Profile breakdown table */
#mp-body .pn-uc-table { width: 100%; border-collapse: collapse; margin-top: 4px; }
#mp-body .pn-uc-table th {
  text-align: right; color: #555; font-weight: 500; padding: 1px 4px 2px 4px;
  font-size: 10px; border-bottom: 1px solid #ddd; white-space: nowrap;
}
#mp-body .pn-uc-table th:first-child { text-align: left; }
#mp-body .pn-uc-table th.pn-uc-group {
  text-align: center; border-bottom: 1px solid #bbb; padding-bottom: 1px;
  font-size: 10px; color: #444; font-weight: 600;
}
#mp-body .pn-uc-table th.pn-uc-group-spacer { border-bottom: none; }
#mp-body .pn-uc-table td {
  text-align: right; padding: 2px 4px; color: #444; font-size: 11px;
}
#mp-body .pn-uc-table td:first-child { text-align: left; color: #555; white-space: nowrap; }
#mp-body .pn-uc-table tr.pn-uc-total td,
#mp-body .pn-mode-table tr.pn-total-row td {
  font-weight: 600; border-top: 1px solid #ddd; color: #222;
}
#mp-body .pn-uc-table td.pn-uc-sel { font-weight: bold; color: #222; }
#mp-body .pn-uc-table th.pn-uc-sel { font-weight: bold; color: #333; }
/* Nested row dimension (employer-paid parking within each income bracket). The
   bracket cell spans its sub-rows, so centre it vertically and rule off each
   group; the nested label reads as a left-aligned stub, not a number. */
#mp-body .pn-uc-table td.pn-uc-inc {
  vertical-align: middle; border-right: 1px solid #e3e3e3;
}
#mp-body .pn-uc-table td.pn-uc-nest {
  text-align: left; color: #666; white-space: normal; padding-right: 6px;
}
#mp-body .pn-uc-table tr.pn-uc-grp td { border-top: 1px solid #e3e3e3; }
/* A combination no traveler profile can occupy — not a zero. */
#mp-body .pn-uc-table td.pn-uc-na { color: #c4c4c4; }

/* ---- Logsums utility breakdown ---- */
#mp-body .pn-util { margin-top: 6px; }
#mp-body .pn-util-head { display: flex; align-items: center; gap: 8px; }
#mp-body .pn-util-toggle {
  font-weight: 700; color: #234; cursor: pointer; user-select: none; font-size: 12px;
}
#mp-body .pn-util-toggle:hover { color: #06c; }
#mp-body .pn-util-group { font-size: 11px; padding: 1px 3px; }
#mp-body .pn-util-note { color: #666; font-size: 10px; margin: 3px 0; line-height: 1.35; }
/* Utility decomposition table. Numeric cells must not wrap — a wrapped numeric
   cell doubles the row height and the panel is already the tallest thing on the
   map. Headers are the exception: they are glossed ("Long-walk penalty (kink)",
   not "kink"), which makes them roughly twice as wide as bare model jargon, and
   left nowrap that one header alone eats ~150px. Two header lines cost ~11px
   once; a nowrap header costs width on every row. The mode column and the
   mode-specific chip cell wrap too. */
/* The decomposition table spans the whole panel rather than flowing inside one
   380px column. It is eight columns wide by design and cannot be squeezed into
   a column of the width the surrounding prose blocks want; left in the flow it
   fragments, and its last rows land in a neighbouring column detached from the
   header that names them — an unreadable table that still looks like a table. */
#mp-body .pn-decomp { margin-top: 0; width: auto; column-span: all; }
#mp-body .pn-decomp td { white-space: nowrap; }
#mp-body .pn-decomp th { white-space: normal; vertical-align: bottom; }
#mp-body .pn-decomp td:first-child { white-space: normal; }
/* The inline factors that are not shared across modes. Ragged by construction —
   car under PARKING_CHOICE carries the most — so it wraps within a bounded
   width rather than pushing the table into horizontal scroll. */
#mp-body .pn-decomp td.pn-decomp-chips {
  white-space: normal; max-width: 300px; text-align: left; line-height: 1.5;
}
#mp-body .pn-chip {
  display: inline-block; margin: 0 3px 1px 0; padding: 0 4px;
  border-radius: 3px; background: rgba(255,255,255,0.62); color: #334;
  font-size: 10px; white-space: nowrap; cursor: help;
}
/* The unexplained-residual tripwire. Styled as a defect, because that is what
   it is: on a complete build it never renders. */
#mp-body .pn-chip-warn {
  background: #fff2cc; color: #7a5200; border: 1px solid #e0c069;
}
/* ---- Mode-choice panel layout (table | model constants) ---- */
/* The column flow is off here: the two blocks are laid out explicitly, the
   table shrink-to-fit at its natural width and the constants taking what is
   left. `column-span: all` on .pn-decomp is inert under `columns: auto`. */
#mp-body.info-panel--mc { columns: auto; column-gap: normal; column-rule: none; }
.pn-mc-main { display: flex; gap: 22px; align-items: flex-start; }
.pn-mc-tbl { flex: 0 0 auto; }
.pn-mc-side { flex: 0 1 auto; min-width: 0; padding-top: 2px; }
#mp-body .pn-mc-side .pn-util-note { margin: 2px 0; }
/* The collapsed unavailable-mode row: one line for every mode the pair cannot
   use, grouped by reason. Left-aligned and wrapping, unlike every other cell
   in this table — it is a sentence, not a number. */
#mp-body .pn-mode-unavail td {
  text-align: left; white-space: normal; color: #888; font-style: italic;
  font-size: 10px; padding-top: 3px; border-top: 1px solid #eee;
}
#mp-body .pn-decomp-formula {
  border-top: 1px solid #eee; padding-top: 2px; margin-top: 1px; color: #556;
}
#mp-body .pn-util-sub { font-weight: 600; color: #445; font-size: 11px; margin-top: 5px; }
/* Destination-choice symbol · meaning · value rows */
#mp-body .pn-dc-tbl { margin-top: 2px; width: auto; }
#mp-body .pn-dc-tbl td { padding: 1px 6px 1px 0; font-size: 11px; }
#mp-body .pn-dc-tbl .pn-dc-sym { text-align: left; color: #445; font-weight: 600; white-space: nowrap; }
#mp-body .pn-dc-tbl .pn-dc-meaning { text-align: left; color: #888; }
#mp-body .pn-dc-tbl .pn-dc-val { text-align: right; color: #222; white-space: nowrap; }
/* Operand cell: the arithmetic that produces the value, sitting just left of
   it — light, right-aligned, so each force stays one row and the value column
   stays the sum's spine. */
#mp-body .pn-dc-tbl .pn-dc-op { text-align: right; color: #999; white-space: nowrap; }
#mp-body .pn-util-tbl th { font-size: 10px; }
#mp-body .pn-util-tbl td { font-size: 11px; }

/* ---- Destination-choice panel (dc_* indicators; plan session 4) ---- */
/* Flex replaces the base multicol: this panel manages its own three regions,
   and the category table scrolls INSIDE its region rather than fragmenting
   into columns. Click-to-pin is what makes an in-panel scrollbar usable --
   once the pair is frozen the list stops swapping under the cursor. */
#mp-body.info-panel--dc {
  columns: auto; column-gap: normal;
  display: flex; flex-direction: column;
  /* The category list is this panel's own scroller, so the outer box does not
     scroll horizontally. It does scroll VERTICALLY as a safety valve: at the
     dock's 180px the fixed regions (head + forces column) land within a few
     px of the fold, and clipping the last force silently is worse than a
     scrollbar that engages only when they genuinely overrun. */
  overflow: hidden auto;
}
/* .dcp-head is gone — it restated the dock header's O -> D slots, and what it
   did not restate moved to #mp-context (renderDestChoicePanel). */
.dcp-cols { display: flex; gap: 22px; flex: 1 1 auto; min-height: 0; }
.dcp-col-forces { flex: 0 0 auto; }
/* The outputs sit beside the forces, not under them: stacked they were the
   127px that overran a 120px box. The rule marks the seam between "what the
   sum is made of" and "what the sum produces". Under ~1500px of dock they
   stack again (.dcp-narrow, set by the renderer) — there the width matters
   more than the height, and the height is no longer the binding constraint. */
.dcp-col-sum { display: flex; gap: 22px; flex: 0 0 auto; }
.dcp-col-out { flex: 0 0 auto; border-left: 1px solid #eee; padding-left: 16px; }
.dcp-cols.dcp-narrow .dcp-col-sum { flex-direction: column; gap: 0; }
.dcp-cols.dcp-narrow .dcp-col-out {
  border-left: none; padding-left: 0;
  margin-top: 4px; padding-top: 3px; border-top: 1px solid #eee;
}
.dcp-col-mid { flex: 0 0 auto; max-width: 350px; }
/* Takes the width the outputs column freed, so a two-up category list has
   somewhere to go. Still scrolls, as the fallback past two columns' worth. */
.dcp-col-cats { flex: 1 1 auto; min-width: 0; overflow-y: auto; padding-right: 4px; }
/* Tight gap on purpose: two-up runs ~7px over the column at 1700px with the
   18px the other seams use, and the two sub-tables are one list. */
.dcp-cat-cols { display: flex; gap: 12px; align-items: flex-start; }
/* ---- Compare-mode destination-choice panel (compare pass 2) ---- */
/* Five columns instead of the explore panel's four: symbol, meaning, A, B, Δ.
   The three numeric columns share .pn-dc-val, so only the header row and the
   two summing rows need rules of their own. */
#mp-body .pn-dc-cmp th {
  font-size: 10px; color: #888; font-weight: 600; text-align: right;
  padding: 0 6px 1px 0; white-space: nowrap;
}
#mp-body .pn-dc-cmp tr.pn-dc-strong td { font-weight: 700; color: #111; }
#mp-body .pn-dc-cmp tr.pn-dc-strong .pn-dc-meaning { font-weight: 400; color: #777; }
/* A band constant that MOVED between the two scenarios: the recalibration
   case a single ladder would otherwise misreport silently. */
.dcp-band-moved { border-color: #999; background: #fbf7ee; }
.dcp-band-dlt { font-size: 9px; font-weight: 600; }

.dcp-ladder { display: flex; gap: 3px; }
.dcp-band {
  border: 1px solid #ddd; border-radius: 3px; padding: 1px 6px;
  text-align: center; font-size: 10px; color: #667; cursor: help;
}
.dcp-band-val { font-weight: 600; color: #334; font-size: 11px; }
.dcp-band-cur { background: #eef4fb; border-color: #4a90d9; }
.dcp-band-cur .dcp-band-val { color: #1a4a8a; }
/* Sized to content, not stretched: `#mp-body .pn-mode-table { width: 100% }`
   out-specifies a bare `.dcp-cat-tbl`, and at 469px the four columns drifted
   so far apart the rows were hard to track across. */
#mp-body .dcp-cat-tbl { border-collapse: collapse; width: auto; }
/* Headers stay on one line: two-up, the narrower sub-table wrapped "Size here"
   and "Δ removed" onto a second line and stood taller than its twin. */
#mp-body .dcp-cat-tbl th { white-space: nowrap; }
/* Category labels too: content-sizing let "Shop" and its `map` tag split over
   two lines, which knocked the two-up sub-tables' rows out of alignment with
   each other. A long label widens the column instead of doubling a row. */
#mp-body .dcp-cat-tbl td:first-child { white-space: nowrap; }
/* Sticky header so the category list scrolls under its own labels. */
#mp-body .dcp-cat-tbl thead th { position: sticky; top: 0; background: #fff; }
#mp-body .dcp-cat-tbl tr.dcp-cat-cur td { font-weight: 700; color: #111; background: #eef4fb; }

/* ---- Statistics panels (population / destination) ----
   Same shape as .dcp-cols: the column flow off, a leading column that
   decomposes the mapped number, and the rest of the width for the group's
   other indicators as one table. The multicol these panels used to ride ran
   the destination list across arbitrary breaks and the population cross-tab
   343px off the right edge at 1280. */
#mp-body.info-panel--stats {
  columns: auto; column-gap: normal; column-rule: none;
  display: flex; flex-direction: column;
  /* The table column is this panel's own scroller, like the dc category list,
     so the outer box does not scroll horizontally. Vertically it still does,
     as the safety valve for a lead column that overruns 148px. */
  overflow: hidden auto;
}
.stp-cols { display: flex; gap: 22px; flex: 1 1 auto; min-height: 0; }
/* Shrinkable but not growable: the row labels set its natural width, and past
   ~300px it is only stretching a two-column key/value list. */
.stp-col-lead { flex: 0 1 300px; min-width: 0; }
/* Scrolls on BOTH axes, and it is the table's own adjacent scroller rather
   than #mp-body's off-screen fourth column — which is what made the old
   343px overflow silent. The population cross-tab needs 946px of a 1280px
   dock, so it fits with room; a study with a wider user-class definition
   gets a visible scrollbar right under the table instead of a clip. */
.stp-col-tbl { flex: 1 1 auto; min-width: 0; overflow: auto; padding-right: 4px; }
/* Content-sized inside this panel: the base `width: 100%` stretched the
   cross-tab to whatever was left and wrapped its cells when that was less
   than its natural width, trading a scrollbar for a taller table. */
#mp-body.info-panel--stats .pn-uc-table { width: auto; margin-top: 0; }
/* Overall Access puts TWO tables in the table column: purposes and modes are
   two families that share no columns. Side by side rather than stacked --
   #mp-body is 148px tall and stacked they want ~218, where side by side the
   taller (the six-row mode table, measured at 128px) still fits. Below the
   width where both fit, .stp-col-tbl's own adjacent scrollbar takes over,
   which is the visible failure mode the silent clip was not. Gap matches
   .dcp-cat-cols: the two tables are one region. */
#mp-body .cum-tbls { display: flex; gap: 12px; align-items: flex-start; }
/* The mode table's rows carry their mode's hue inline (info_panel.js). The
   cell background .dcp-cat-cur paints for the active row would sit on top of
   it, so here the highlight is carried by the row's own darker tint plus the
   bold text the rule already sets. */
#mp-body .cum-mode-tbl tr.dcp-cat-cur td { background: transparent; }

.dcp-map-tag {
  display: inline-block; font-size: 9px; font-weight: 600;
  color: #fff; background: #4a90d9; border-radius: 3px;
  padding: 0 3px; margin-left: 3px; vertical-align: middle;
}

/* ---- Legend ---- */
#legend {
  position: absolute; bottom: 28px; right: 12px;
  background: rgba(255,255,255,0.96); border: 1px solid #ccc;
  border-radius: 6px; padding: 8px 10px; z-index: 900;
  font-size: 11px; min-width: 140px;
  box-shadow: 0 2px 6px rgba(0,0,0,0.15);
  max-height: 70vh; overflow-y: auto;
}
#legend .leg-title { font-weight: 700; margin-bottom: 5px; color: #333; font-size: 11px; }
#legend #leg-compare-view {
  font-size: 10px; color: #555; font-style: italic;
  margin: -3px 0 5px;
}
#legend #leg-advanced { margin: -2px 0 5px; }
#leg-advanced-body { margin-top: 4px; }
#leg-scale-row {
  display: flex; align-items: center; gap: 6px; margin-bottom: 6px;
}
#leg-scale-row label { font-size: 11px; font-weight: 600; color: #1a4a8a; }
/* The strip reuses .norm-toggle / .norm-btn so it reads as the same kind of
   control as the per-km²/total pills, but it is never auto-sized away from
   the legend's left edge the way those are inside the sub-control column. */
#leg-scale-toggle { margin: 0; }
#leg-scale-toggle .norm-btn:disabled {
  background: #f4f4f4; color: #bbb; cursor: not-allowed;
}
#leg-opacity-row, #leg-height-row { margin-bottom: 6px; }
#leg-opacity-row label, #leg-height-row label {
  font-size: 11px; font-weight: 600; color: #1a4a8a;
}
#leg-opacity-row #leg-opacity-slider,
#leg-height-row #height-slider {
  width: 100%; margin-top: 3px; cursor: pointer;
}
#leg-cap-slider-row {
  display: flex; align-items: center; gap: 4px;
  font-size: 10px; color: #555;
}
#leg-cap-slider-row label { white-space: nowrap; }
#leg-cap-slider { flex: 1; min-width: 60px; cursor: pointer; }
#leg-cap-value {
  font-variant-numeric: tabular-nums;
  width: 48px; text-align: right; color: #333;
  font-size: 10px; padding: 1px 2px;
  border: 1px solid #ccc; border-radius: 2px;
  background: #fff;
}
#leg-cap-value:focus { outline: none; border-color: #1a4a8a; }
#leg-cap-unit { color: #555; font-size: 10px; }
.leg-cap-reset {
  background: none; border: none; padding: 0; cursor: pointer;
  font-size: 10px; color: #888; text-decoration: underline;
}
.leg-cap-reset:hover { color: #555; }
#legend .leg-bar {
  height: 13px; border-radius: 3px; margin-bottom: 4px;
  background: linear-gradient(to right, #ccc, #ccc);
}
#legend .leg-labels { display: flex; justify-content: space-between; color: #555; }
#legend .leg-divider { border-top: 1px solid #ddd; margin: 5px 0 4px; }
#legend .leg-modes-row {
  display: flex; flex-wrap: wrap;
  gap: 4px 10px;
  padding: 1px 0;
}
#legend .leg-mode-chip {
  display: inline-flex; align-items: center; gap: 5px;
}
#legend .leg-mode-swatch {
  display: inline-block; width: 12px; height: 12px;
  border-radius: 2px; flex-shrink: 0;
}
#legend .leg-mode-label { color: #444; }
/* Categorical legend rows (density classes) */
#legend .leg-cat-row {
  display: flex; align-items: center; gap: 5px;
  padding: 1px 0;
}
#legend .leg-cat-swatch {
  display: inline-block; width: 12px; height: 12px;
  border-radius: 2px; flex-shrink: 0;
}
#legend .leg-cat-label { color: #444; }
#legend .leg-cat-range { color: #888; margin-left: auto; }
#legend .leg-cat-absent { opacity: 0.4; }
#legend .leg-cat-note { color: #888; font-size: 10px; margin-top: 3px; }

/* The 5-column `.cum-grid` table (Total / Per km² / Per person / % x one row
   per mode) and its `.ind-btn-sm` dots are gone (SPEC-s22 S4): the table's
   two axes are now the normalization strips (§5.3) and the shared mode chip
   row (§5.1), so the cumulative group is plain `.ind-btn` rows like every
   other group. */

/* ---- City Snapshot ---- */
#snapshot-digest {
  flex: 1;
  font-size: 10px;
  font-weight: 400;
  color: #888;
  text-align: right;
  padding-right: 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.snapshot-stat-line {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  margin-bottom: 4px;
}
.snapshot-stat-line .lbl { font-weight: 400; color: #555; }
.snapshot-stat-line .val { font-weight: 600; color: #222; }
.snapshot-stat-line .delta-down { font-weight: 600; color: #c0392b; }
.snapshot-stat-line .delta-up   { font-weight: 600; color: #27ae60; }
.snapshot-histogram {
  width: 100%;
  display: block;
  margin-bottom: 4px;
}
.snap-tooltip {
  position: absolute; background: #333; color: #fff; font-size: 10px;
  padding: 3px 6px; border-radius: 3px; pointer-events: none;
  display: none; white-space: nowrap; z-index: 10;
}
.snap-hist-wrapper { position: relative; }
.snap-legend {
  display: flex; gap: 10px; font-size: 10px; color: #555;
  margin-top: 2px; margin-bottom: 6px; flex-wrap: wrap;
}
.snap-legend-item { display: flex; align-items: center; gap: 3px; }
.snap-mode-rows { margin-bottom: 4px; position: relative; }
.snap-mode-row  { display:flex; align-items:center; gap:4px; margin-bottom:2px; }
.snap-mode-lbl  { font-size:9px; color:#888; width:54px; flex-shrink:0;
                  text-align:right; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.snapshot-modal-bar {
  display: flex;
  height: 22px;
  border-radius: 4px;
  overflow: hidden;
  margin-bottom: 4px;
}
.snapshot-modal-bar div {
  transition: width 300ms ease;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  font-weight: 600;
  color: white;
  overflow: hidden;
  white-space: nowrap;
}
.snapshot-subtitle {
  font-size: 10px;
  font-weight: 400;
  color: #888;
}

/* ---- Compare Summary ---- */
.compare-summary-headline {
  background: #fff;
  border: 1px solid #d0d8e6;
  border-radius: 4px;
  padding: 6px 8px;
  margin-bottom: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.compare-summary-headline .csh-line1 {
  font-size: 10px;
  color: #666;
  letter-spacing: 0.02em;
}
.compare-summary-headline .csh-delta {
  font-size: 18px;
  font-weight: 700;
}
.compare-summary-headline .csh-delta.up   { color: #27ae60; }
.compare-summary-headline .csh-delta.down { color: #c0392b; }
.compare-summary-headline .csh-delta.flat { color: #555; }
.compare-summary-headline .csh-tail {
  font-size: 10px;
  color: #777;
}
.compare-summary-card {
  margin-bottom: 8px;
}
.compare-summary-card .csc-title {
  font-size: 11px;
  font-weight: 600;
  color: #555;
  margin-bottom: 3px;
}
.compare-summary-card .csc-caption {
  font-size: 10px;
  color: #777;
  margin-top: 3px;
}
.compare-toggles {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
  margin: 4px 0 4px 0;
}
.compare-toggle {
  font-size: 9px;
  padding: 2px 6px;
  border: 1px solid #ccc;
  border-radius: 10px;
  background: white;
  cursor: pointer;
  color: #555;
  user-select: none;
  line-height: 1.4;
}
.compare-toggle:hover { background: #f3f6fb; }
.compare-toggle.on { font-weight: 600; }
.compare-toggle.tint-A { border-color: #888; }
.compare-toggle.tint-A.on { background: #888; color: white; }
.compare-toggle.tint-B { border-color: #2f99a6; }
.compare-toggle.tint-B.on { background: #2f99a6; color: white; }
.compare-stats-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 10px;
  margin-top: 4px;
}
.compare-stats-table th,
.compare-stats-table td {
  text-align: right;
  padding: 1px 4px;
  border-bottom: 1px solid #eee;
}
.compare-stats-table th { color: #888; font-weight: 600; }
.compare-stats-table td:first-child,
.compare-stats-table th:first-child { text-align: left; color: #666; }
.compare-stats-table tr:last-child td { border-bottom: none; }
.compare-stats-table .delta-up   { color: #27ae60; font-weight: 600; }
.compare-stats-table .delta-down { color: #c0392b; font-weight: 600; }
.compare-uc-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 10px;
}
.compare-uc-table th {
  color: #888; font-weight: 600;
  padding: 2px 4px;
  border-bottom: 1px solid #ddd;
  text-align: right;
  font-size: 9px;
  letter-spacing: 0.02em;
}
.compare-uc-table th:first-child { text-align: left; }
.compare-uc-row {
  cursor: pointer;
}
.compare-uc-row td {
  padding: 2px 4px;
  border-bottom: 1px solid #f0f0f0;
  text-align: right;
  color: #444;
  font-size: 10px;
}
.compare-uc-row td:first-child {
  text-align: left;
  color: #333;
  white-space: nowrap;
}
.compare-uc-row:hover { background: #f5f8fc; }
.compare-uc-row.left-behind {
  background: #fff5f0;
}
.compare-uc-row.left-behind:hover { background: #ffe9dc; }
.compare-uc-row.active {
  border-left: 3px solid #4a90d9;
  background: #eaf2fb;
}
.compare-uc-row.active:hover { background: #d8e6f5; }
.compare-uc-row .delta-up   { color: #27ae60; font-weight: 600; }
.compare-uc-row .delta-down { color: #c0392b; font-weight: 600; }
.compare-legend {
  display: flex;
  gap: 8px;
  font-size: 9px;
  color: #555;
  margin-top: 2px;
  flex-wrap: wrap;
}
.compare-legend-item {
  display: flex; align-items: center; gap: 3px;
}

/* ---- Legend overlays section ---- */
#legend { max-height: 70vh; overflow-y: auto; }
#legend-overlays { border-bottom: 1px solid #ddd; padding-bottom: 6px; margin-bottom: 6px; }
.leg-section-title {
  cursor: pointer; font-size: 11px; font-weight: 700; color: #555;
  padding: 2px 0 4px; user-select: none;
}
.leg-section-title:hover { color: #333; }
.collapse-arrow { font-size: 10px; color: #999; margin-left: 4px; }

/* ---- 3D toggle button ---- */
#btn-3d-toggle {
  display: block; width: 100%; text-align: left;
  padding: 4px 7px; margin-bottom: 8px;
  border: 1px solid #b0c8e8; border-radius: 3px;
  background: #e8f2ff; cursor: pointer; font-size: 11px; color: #1a4a8a;
  font-weight: 600;
}
#btn-3d-toggle:hover { background: #d0e6ff; }
#btn-3d-toggle.active { background: #4a90d9; color: white; border-color: #3a7bc8; }

/* MapLibre zoom control margin */
.maplibregl-ctrl-top-right { margin-top: 10px; }

/* ---- Scenario picker ---- */
#scenario-picker {
  border-bottom: 1px solid #ddd;
  padding: 7px 10px 8px;
  background: #f0f0f0;
}
.picker-label {
  font-size: 10px; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: #777; display: block; margin-bottom: 4px;
}
#scenario-picker select {
  width: 100%; padding: 4px 6px; border: 1px solid #ccc;
  border-radius: 4px; background: white; font-size: 12px; cursor: pointer;
  text-overflow: ellipsis; overflow: hidden; white-space: nowrap;
  min-width: 0;
}

/* ---- Unified scenario table (axes + flat-scenario, Explore + Compare) ----
   CSS grid; axis-name column is capped + wraps so the dropdown columns get
   the bulk of the panel width. In Compare the swap icon is absolute-positioned
   at the seam between Reference and Alternative — no dedicated column means
   the body rows aren't burning width on a blank cell beneath the icon. */
.scenario-table {
  display: grid;
  gap: 4px 6px;
  align-items: center;
  margin-top: 4px;
}
.scenario-table-explore {
  grid-template-columns: minmax(0, 110px) minmax(0, 1fr);
}
.scenario-table-compare {
  grid-template-columns: minmax(0, 110px) minmax(0, 1fr) minmax(0, 1fr);
}
.scenario-table .st-cell {
  min-width: 0;
}
.scenario-table .st-header {
  font-size: 9px; font-weight: 600; letter-spacing: 0.06em;
  text-transform: uppercase; color: #777;
  text-align: center;
}
.scenario-table .st-header.st-axis-name { text-align: left; }
.scenario-table .st-axis-name {
  font-size: 11px; color: #555; font-weight: 600;
  line-height: 1.15;
  padding-right: 4px;
  word-wrap: break-word;
}
.scenario-table .st-header.st-ref {
  position: relative;
}
.scenario-table select {
  width: 100%; padding: 3px 4px; border: 1px solid #ccc;
  border-radius: 4px; background: white; font-size: 10px; cursor: pointer;
  text-overflow: ellipsis; overflow: hidden; white-space: nowrap;
  min-width: 0;
}
.scenario-table select option:disabled { color: #bbb; }
#btn-swap-ab.swap-btn {
  position: absolute;
  top: 50%;
  right: -12px;
  transform: translateY(-50%);
  width: 22px; height: 18px; padding: 0;
  border: none; background: transparent;
  font-size: 14px; line-height: 1; color: #888;
  cursor: pointer;
  z-index: 1;
}
#btn-swap-ab.swap-btn:hover { color: #1a4a8a; }

/* ---- Explore/Compare toggle strip ---- */
.mode-toggle-strip {
  display: flex; border: 1px solid #ccc; border-radius: 4px;
  overflow: hidden;
}
#compare-view-toggle { margin-top: 6px; }
#compare-view-toggle .mode-btn:disabled {
  opacity: 0.5; cursor: not-allowed; background: #f5f5f5;
}
#compare-view-toggle .mode-btn:disabled:hover { background: #f5f5f5; }
.scenario-section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
}
.mode-btn {
  flex: 1; padding: 4px 8px; border: none;
  background: white; font-size: 11px; cursor: pointer; color: #555;
  font-weight: 600;
}
.mode-btn:hover { background: #f0f4ff; }
.mode-btn.active { background: #4a90d9; color: white; }

