/* =====================================================================
   Zevvy society site plan (Phase 4). The only stylesheet this page loads.

   PART 1, shared tokens and primitives.
   css/mobile.css is 38 KB and is 95% the map application's own component
   library. The previous society page loaded all of it purely to inherit
   the token block, which cost roughly 250 ms of transfer and parse on
   Slow 4G with a 4x CPU throttle, against a 3,000 ms LCP budget that the
   site plan now also has to fit inside. So the token block below is a
   VERBATIM copy of mobile.css lines 7-71, and the primitives are verbatim
   copies of its .zv-tag / .zv-btn / .zv-card / focus-ring / reduced-motion
   rules, de-scoped from #zv so they work on a normal document.

   That duplication is exactly the drift risk SOCIETY-PLAN.md warned about,
   so it is checked mechanically rather than trusted: scripts/verify-tokens.mjs
   parses this file and mobile.css and fails if any token value differs.
   Run it before committing a change to either.

   PART 2 onwards, the page itself. It is one file rather than two because
   a second stylesheet costs a whole 400 ms round trip on the target
   connection, which the LCP budget cannot absorb.

   Type floor on this page is 14px with no exceptions, including the SVG
   labels, which is why those live outside the camera transform in screen
   space rather than being counter-scaled inside it.
   ===================================================================== */

:root {
  --zv-accent: #00d68f;
  --zv-accent-2: #24e5a4;
  --zv-accent-ink: #00291d;
  --zv-blue: #4c8dff;
  --zv-amber: #ffb020;
  --zv-red: #ff5a5f;

  --zv-dc-ink: var(--zv-accent);
  --zv-ac-ink: #8fb4ff;
  --zv-warn-ink: var(--zv-amber);
  --zv-bad-ink: #ff9599;

  --zv-bg: #0a0e0d;
  --zv-surface: #1a2321;
  --zv-surface-2: #243130;
  --zv-surface-3: #2f3d3b;
  --zv-line: rgba(255, 255, 255, 0.13);
  --zv-text: #f1f7f5;
  --zv-text-2: #a3b3ae;
  --zv-text-3: #8b9c97;
  --zv-shadow: 0 18px 50px rgba(0, 0, 0, 0.7);
  --zv-shadow-sm: 0 6px 20px rgba(0, 0, 0, 0.55);
  --zv-scrim: rgba(4, 8, 7, 0.72);

  --zv-r-lg: 28px;
  --zv-r-md: 20px;
  --zv-r-sm: 14px;

  --zv-top: env(safe-area-inset-top, 0px);
  --zv-bottom: env(safe-area-inset-bottom, 0px);
  --zv-vh: 100dvh;

  --zv-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

html[data-theme="light"] {
  --zv-accent: #00a877;
  --zv-accent-2: #00c489;
  --zv-accent-ink: #00291d;
  --zv-dc-ink: #00693f;
  --zv-ac-ink: #1550b8;
  --zv-warn-ink: #7a4f00;
  --zv-bad-ink: #b3151c;
  --zv-bg: #eef2f0;
  --zv-surface: #ffffff;
  --zv-surface-2: #f2f5f4;
  --zv-surface-3: #e6ebe9;
  --zv-line: rgba(12, 26, 22, 0.09);
  --zv-text: #0d1513;
  --zv-text-2: #5b6d68;
  --zv-text-3: #5f706b;
  --zv-shadow: 0 18px 50px rgba(15, 35, 30, 0.18);
  --zv-shadow-sm: 0 6px 18px rgba(15, 35, 30, 0.12);
  --zv-scrim: rgba(240, 245, 243, 0.8);
}

/* ---------- shared primitives ---------- */

.zv-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 14px;
  font-weight: 800;
  padding: 3px 8px;
  border-radius: 8px;
  background: var(--zv-surface-2);
  color: var(--zv-text-2);
  letter-spacing: 0.01em;
}

.zv-tag.zv-dc { background: rgba(0, 214, 143, 0.16); color: var(--zv-dc-ink); }
.zv-tag.zv-ac { background: rgba(76, 141, 255, 0.16); color: var(--zv-ac-ink); }
.zv-tag.zv-warn { background: rgba(255, 176, 32, 0.16); color: var(--zv-warn-ink); }
.zv-tag.zv-bad { background: rgba(255, 90, 95, 0.16); color: var(--zv-bad-ink); }

.zv-btn {
  height: 52px;
  border-radius: 26px;
  background: var(--zv-accent);
  color: var(--zv-accent-ink);
  font-size: 16px;
  font-weight: 750;
  /* PHASE 10 / BTN-01. This rule never reset text-decoration, and .zv-btn is
     used on <a> as well as <button>: the committee page's two hero CTAs, the
     ones the whole page exists to get a committee to press, were rendering
     with the browser's default underline through the label. A button with an
     underlined label reads as a broken button. Invisible to every check in
     the suite, because underline is not overflow, contrast, type size or a
     tap target: it is just wrong, and only an eye catches it. */
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  width: 100%;
  border: 0;
  font-family: inherit;
  cursor: pointer;
  transition: transform 0.1s ease, filter 0.15s ease;
}

.zv-btn svg { width: 20px; height: 20px; flex: none; }
.zv-btn:active { transform: scale(0.975); filter: brightness(0.95); }
.zv-btn.zv-ghost { background: var(--zv-surface-2); color: var(--zv-text); }
.zv-btn.zv-sm { height: 44px; font-size: 14.5px; border-radius: 22px; }
.zv-btn[disabled] { opacity: 0.45; pointer-events: none; }

.zv-card {
  background: var(--zv-surface-2);
  border-radius: var(--zv-r-md);
  padding: 14px;
  border: 1px solid var(--zv-line);
}

:where(button, input, select, textarea, a, [tabindex]):focus-visible {
  outline: 2px solid var(--zv-accent);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.08s !important;
    scroll-behavior: auto !important;
  }
}

/* --------------------------------------------------- plan palette, dark */

/* The materials have to separate from each other before any of them can
   separate from a charger bay. First pass had ground, road and tarmac
   within about 4% luminance of each other, which turned the plan into a
   beige field with coloured boxes on it. These are spread deliberately:
   ground is the lightest surface in light theme and the darkest in dark
   theme, roads step away from it in the opposite direction in each, and
   buildings sit on a cooler hue entirely so they read as a material
   rather than as another shade of the ground. */
:root {
  --pl-ground: #151b19;
  --pl-outside: #080c0b;
  --pl-road: #27302d;
  --pl-road-line: #45524d;
  --pl-tarmac: #1e2725;
  --pl-bay-line: #3c4a45;
  --pl-green: #1c3524;
  --pl-green-2: #2f5c3b;
  --pl-water: #15384a;
  --pl-build: #313d4a;
  --pl-build-line: #647382;
  --pl-build-top: #3f4d5c;
  --pl-shadow: rgba(0, 0, 0, 0.55);
  --pl-wall: #616e67;
  --pl-dash: #4c5954;
  --pl-label: #ccd9d4;
  --pl-label-halo: #101614;

  --st-free-fill: #14382a;
  --st-free-line: #34d99b;
  --st-free-ink: #8af2c8;
  --st-busy-fill: #16294c;
  --st-busy-line: #5f99ff;
  --st-busy-ink: #b3ccff;
  --st-held-fill: #3a2c0c;
  --st-held-line: #efac2c;
  --st-held-ink: #ffd68c;
  --st-down-fill: #401a1d;
  --st-down-line: #ff7176;
  --st-down-ink: #ffb6b9;

  --sp-plan-h: clamp(300px, calc(100svh - 274px), 560px);
  --sp-max: 1280px;
}

html[data-theme="light"] {
  --pl-ground: #eef0ea;
  --pl-outside: #cbd2ca;
  --pl-road: #c1c8c0;
  --pl-road-line: #9ba69c;
  --pl-tarmac: #d4dad1;
  --pl-bay-line: #a3ada1;
  --pl-green: #c0dbab;
  --pl-green-2: #8bbc70;
  --pl-water: #9fd1e3;
  --pl-build: #b3bfc9;
  --pl-build-line: #74838f;
  --pl-build-top: #ccd5dd;
  --pl-shadow: rgba(28, 44, 58, 0.18);
  --pl-wall: #6a756f;
  --pl-dash: #8b968f;
  --pl-label: #26302c;
  --pl-label-halo: #eef0ea;

  --st-free-fill: #c6ecd6;
  --st-free-line: #00794f;
  --st-free-ink: #005136;
  --st-busy-fill: #d2e1fc;
  --st-busy-line: #1a5bc7;
  --st-busy-ink: #123a86;
  --st-held-fill: #fae2b6;
  --st-held-line: #965c00;
  --st-held-ink: #613b00;
  --st-down-fill: #fbd6d6;
  --st-down-line: #bd2129;
  --st-down-ink: #85161c;
}

/* ------------------------------------------------------------ page shell */

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
/* Components below set display on elements that are also toggled with the
   hidden attribute, and a class rule beats the UA [hidden] rule. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--zv-bg);
  color: var(--zv-text);
  font-family: var(--zv-font);
  -webkit-font-smoothing: antialiased;
  text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
  /* PHASE 10 / CHROME-04. This was `overflow-x: hidden`, and it was silently
     disabling the sticky header on both society pages.
     `overflow-x: hidden` on body makes body a scroll container. A
     position:sticky child sticks to its nearest scrollport, which is then
     body, but body is not the thing being scrolled (the viewport scrolls the
     root), so the sticky offset never engages and the header simply scrolls
     away. On the committee page, 4,010px long, that meant the brand, the
     theme toggle and the only link back to the rest of the site left the
     screen after the first flick and never came back.
     `clip` clips exactly the same overflow and does NOT create a scroll
     container, so sticky works. Chrome 90+, Firefox 81+, Safari 16+; where it
     is not supported it degrades to `visible`, which is safe here because
     scripts/phase10-matrix.mjs gates horizontal overflow to zero across all
     twelve viewports rather than relying on this declaration to hide it. */
  overflow-x: clip;
}

body { font-size: 15px; line-height: 1.55; }
img { max-width: 100%; display: block; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
a { color: inherit; }

.sp-wrap { max-width: var(--sp-max); margin: 0 auto; padding: 0 16px; }

/* Keyboard users otherwise tab the header, the summary, three bank pills and
   then all 12 bay targets before reaching any prose. Clipped to 1x1 until
   focused, so it never occupies layout and never trips the 44px target
   audit, and a full-size real target once it is focused. */
.sp-skip {
  position: absolute; left: 8px; top: 8px; z-index: 200;
  /* Unfocused it must occupy nothing at all: no padding and no min-height,
     or it stays a 32x44 box that reads as an undersized touch target. */
  width: 1px; height: 1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
  background: var(--zv-accent); color: var(--zv-accent-ink);
  font-size: 15px; font-weight: 750; text-decoration: none;
}
.sp-skip:focus-visible, .sp-skip:focus {
  width: auto; height: auto; overflow: visible;
  clip: auto; clip-path: none;
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 16px;
  border-radius: 12px;
  outline: 2px solid var(--zv-text); outline-offset: 2px;
}
/* the skip target must be able to take focus for the jump to stick */
#why:focus, #page-foot:focus, #how:focus { outline: none; }
.sp-sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------------------------------------------------------------- header */

/* PHASE 10 / CHROME-01. Was 90% of --zv-bg over a 14px blur, so a tenth of
   every heading, figure and bay label that scrolled past it came through the
   header as a moving grey ghost. Milder than the homepage's 82%, identical in
   kind, and it fails the same test: at some scroll position, content visibly
   overlaps the header. Opaque is the only version of that sentence that is
   true. The blur went with it because a backdrop-filter behind an opaque fill
   is a per-frame GPU pass that composites nothing, and this header is sticky
   on a page whose whole interaction is scrolling and panning.
   CHROME-02: scroll-padding-top so the skip link and the committee page's
   five in-page anchors land their target below the header instead of behind
   it. `scroll-margin-top` on each target was the alternative; one declaration
   on the scroll container cannot be forgotten when a section is added. */
.sp-head {
  position: sticky; top: 0; z-index: 50;
  background: var(--zv-bg);
  border-bottom: 1px solid var(--zv-line);
  padding-top: var(--zv-top);
}
html { scroll-padding-top: calc(56px + var(--zv-top) + 12px); }
.sp-head-row { display: flex; align-items: center; gap: 10px; height: 56px; }
.sp-brand {
  display: flex; align-items: center; gap: 9px; min-width: 0; flex: 1;
  text-decoration: none; color: inherit; padding: 6px 0;
}
.sp-brand img { width: 26px; height: 26px; flex: none; border-radius: 7px; }
.sp-brand-txt { min-width: 0; }
.sp-brand-txt b { display: block; font-size: 14px; font-weight: 750; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sp-brand-txt span { display: block; font-size: 14px; color: var(--zv-text-3); line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sp-icon-btn {
  width: 44px; height: 44px; border-radius: 14px; flex: none;
  display: grid; place-items: center;
  background: var(--zv-surface-2); color: var(--zv-text-2); border: 1px solid var(--zv-line);
}
.sp-icon-btn svg { width: 19px; height: 19px; }
.sp-icon-btn:active { background: var(--zv-surface-3); }

/* --------------------------------------------------------------- the stage */

.sp-stage { padding: 14px 0 0; }

.sp-title { margin: 0 0 2px; font-size: 20px; font-weight: 800; letter-spacing: -0.02em; line-height: 1.2; }
.sp-title-sub { margin: 0 0 12px; font-size: 14px; color: var(--zv-text-2); }

/* One tappable summary line: the whole reason a resident opens this.
   Reserved height so the JS refresh cannot shift the plan below it. */
.sp-status {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  min-height: 60px; padding: 9px 12px; margin-bottom: 10px;
  border-radius: 16px; background: var(--zv-surface-2); border: 1px solid var(--zv-line);
}
.sp-status-n { font-size: 26px; font-weight: 800; line-height: 1; font-variant-numeric: tabular-nums; color: var(--st-free-line); flex: none; }
.sp-status-t { flex: 1; min-width: 0; }
.sp-status-t b { display: block; font-size: 15px; font-weight: 750; line-height: 1.25; }
.sp-status-t span { display: block; font-size: 14px; color: var(--zv-text-2); line-height: 1.3; margin-top: 1px; }
.sp-status-go { width: 30px; height: 30px; flex: none; display: grid; place-items: center; color: var(--zv-text-3); }
.sp-status-go svg { width: 18px; height: 18px; }

/* Bank switcher: the honest fix for "the other clusters are off screen at a
   zoom where bays are big enough to tap". */
.sp-banks {
  display: flex; gap: 8px; overflow-x: auto; padding: 0 0 10px;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
  /* CLS: the pills are rendered by JS. Without this the container is 10px
     tall on first paint and then shoves the whole plan down by 44px. */
  min-height: 54px;
}
.sp-banks::-webkit-scrollbar { display: none; }
.sp-bank {
  display: flex; align-items: center; gap: 8px; flex: none;
  min-height: 44px; padding: 0 14px; border-radius: 14px;
  background: var(--zv-surface-2); border: 1px solid var(--zv-line);
  font-size: 14px; font-weight: 700; white-space: nowrap;
}
.sp-bank[aria-pressed="true"] { background: var(--zv-surface-3); border-color: color-mix(in srgb, var(--zv-accent) 45%, var(--zv-line)); }
.sp-bank .n { font-size: 14px; font-weight: 800; color: var(--st-free-ink); background: var(--st-free-fill); border: 1px solid var(--st-free-line); border-radius: 8px; padding: 0 6px; line-height: 20px; }
.sp-bank .n.zero { color: var(--zv-text-2); background: var(--zv-surface-3); border-color: var(--zv-line); }

/* ------------------------------------------------------------- plan canvas */

.sp-canvas {
  position: relative;
  height: var(--sp-plan-h);
  border-radius: 20px;
  overflow: hidden;
  background: var(--pl-outside);
  border: 1px solid var(--zv-line);
  contain: paint;
}
.sp-plan {
  display: block; width: 100%; height: 100%;
  touch-action: none;
  cursor: grab;
  background: var(--pl-outside);
}
.sp-plan:active { cursor: grabbing; }

/* Layer visibility is driven from one place so a zoom threshold can turn a
   whole layer off rather than the code hiding elements one at a time. */
.sp-plan[data-detail="low"] .pl-tier2 { display: none; }
.sp-plan[data-mode="bank"] .pl-bay-hit { display: none; }
.sp-plan[data-mode="bay"] .pl-bank-hit,
.sp-plan[data-mode="bay"] .pl-bank-ring,
.sp-plan[data-mode="bay"] .pl-bank-badge { display: none; }
.sp-plan[data-mode="bank"] .pl-bay-label { display: none; }

/* plan geometry */
.pl-outside { fill: var(--pl-outside); }
.pl-ground { fill: var(--pl-ground); }
.pl-wall { fill: none; stroke: var(--pl-wall); stroke-width: 2.5px; vector-effect: non-scaling-stroke; }
.pl-road { fill: none; stroke: var(--pl-road); stroke-linecap: butt; stroke-linejoin: round; }
.pl-centre { fill: none; stroke: var(--pl-road-line); stroke-width: 1px; stroke-dasharray: 7 8; vector-effect: non-scaling-stroke; opacity: 0.8; }
.pl-bay-div { fill: none; stroke: var(--pl-bay-line); stroke-width: 0.15; }
.pl-track { fill: none; stroke: var(--pl-green-2); stroke-width: 1.1; }
.pl-chev { fill: none; stroke: var(--pl-road-line); stroke-width: 1.4px; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.pl-hl-busy { fill: none; stroke: var(--st-busy-line); stroke-width: 0.16; opacity: 0.5; }
.pl-hl-down { fill: none; stroke: var(--st-down-line); stroke-width: 0.24; opacity: 0.65; }
.pl-green { fill: var(--pl-green); }
.pl-tree { fill: var(--pl-green-2); }
.pl-water { fill: var(--pl-water); }
.pl-tarmac { fill: var(--pl-tarmac); }
.pl-baylines { fill: url(#pl-bays-v); }
.pl-baylines-h { fill: url(#pl-bays-h); }
.pl-build { fill: var(--pl-build); stroke: var(--pl-build-line); stroke-width: 1.5px; vector-effect: non-scaling-stroke; stroke-linejoin: round; }
.pl-build-shadow { fill: var(--pl-shadow); stroke: none; }
.pl-build-core { fill: var(--pl-build-top); }
.pl-minor { fill: var(--pl-build-top); stroke: var(--pl-build-line); stroke-width: 1px; vector-effect: non-scaling-stroke; }
.pl-dash { fill: none; stroke: var(--pl-dash); stroke-width: 1.2px; stroke-dasharray: 6 5; vector-effect: non-scaling-stroke; }
.pl-mark { fill: none; stroke: var(--pl-road-line); stroke-width: 1.2px; vector-effect: non-scaling-stroke; }
.pl-gate { fill: none; stroke: var(--st-held-line); stroke-width: 2.5px; vector-effect: non-scaling-stroke; stroke-linecap: round; }

/* charger bays: light low saturation fill, fully opaque outline, same hue */
.pl-bay { stroke-width: 2.2px; vector-effect: non-scaling-stroke; }
.pl-bay.st-free { fill: var(--st-free-fill); stroke: var(--st-free-line); }
.pl-bay.st-busy { fill: var(--st-busy-fill); stroke: var(--st-busy-line); }
.pl-bay.st-held { fill: var(--st-held-fill); stroke: var(--st-held-line); stroke-dasharray: 7 4; }
.pl-bay.st-down { fill: var(--st-down-fill); stroke: var(--st-down-line); }
.pl-hatch { pointer-events: none; }
.pl-hatch.st-busy { fill: url(#pl-hatch-busy); }
.pl-hatch.st-down { fill: url(#pl-hatch-down); }
.pl-ped { stroke-width: 1.6px; vector-effect: non-scaling-stroke; }
.pl-ped.st-free { fill: var(--st-free-line); stroke: var(--st-free-line); }
.pl-ped.st-busy { fill: var(--st-busy-line); stroke: var(--st-busy-line); }
.pl-ped.st-held { fill: var(--st-held-line); stroke: var(--st-held-line); }
.pl-ped.st-down { fill: var(--st-down-line); stroke: var(--st-down-line); }
.pl-bay-mine { fill: none; stroke: var(--zv-accent); stroke-width: 2.5px; stroke-dasharray: 4 3; vector-effect: non-scaling-stroke; }

/* Hit targets. Sized in world units by JS so they are never under 44 CSS px,
   which is the whole point: the drawn bay may be smaller, the target is not. */
.pl-bay-hit, .pl-bank-hit, .pl-tower-hit { fill: transparent; cursor: pointer; outline: none; }
.pl-bay-hit:focus-visible, .pl-bank-hit:focus-visible, .pl-tower-hit:focus-visible {
  fill: color-mix(in srgb, var(--zv-accent) 22%, transparent);
  stroke: var(--zv-accent); stroke-width: 3px; vector-effect: non-scaling-stroke;
}
.pl-bank-ring { fill: none; stroke: var(--zv-accent); stroke-width: 2px; stroke-dasharray: 5 4; vector-effect: non-scaling-stroke; opacity: 0.85; pointer-events: none; }

/* Screen-space label layer: sits outside the camera transform, so every
   label is exactly the px size it says it is at every zoom level. */
.pl-label { font-size: 14px; font-weight: 700; fill: var(--pl-label); pointer-events: none; text-anchor: middle; dominant-baseline: middle;
  paint-order: stroke; stroke: var(--pl-label-halo); stroke-width: 3.5px; stroke-linejoin: round; }
.pl-label.tiny { font-size: 14px; font-weight: 650; letter-spacing: 0.02em; }
/* The whole label group, not just its <text>. The status glyph is a stroked
   <path>/<circle> and the bank badge is a filled <rect>; both paint ON TOP of
   the hit rects, and without this they win the hit test, so a tap landing on
   the tick inside a free bay, or on the "2 free" pill, resolved to a element
   with no tap action and did nothing. Phase 9. */
.pl-bay-label, .pl-bank-badge { pointer-events: none; }
.pl-bay-label text { font-size: 14px; font-weight: 800; text-anchor: middle; dominant-baseline: middle; pointer-events: none;
  paint-order: stroke; stroke-width: 3px; stroke-linejoin: round; }
.pl-bay-label .code { font-weight: 750; }
.pl-bay-label.st-free text { fill: var(--st-free-ink); stroke: var(--st-free-fill); }
.pl-bay-label.st-busy text { fill: var(--st-busy-ink); stroke: var(--st-busy-fill); }
.pl-bay-label.st-held text { fill: var(--st-held-ink); stroke: var(--st-held-fill); }
.pl-bay-label.st-down text { fill: var(--st-down-ink); stroke: var(--st-down-fill); }
.pl-bay-label .gl { stroke: none; }
.pl-bank-badge text { font-size: 14px; font-weight: 800; fill: var(--zv-accent-ink); text-anchor: middle; dominant-baseline: middle; pointer-events: none; }
.pl-bank-badge rect { fill: var(--zv-accent); }

/* pulse on the bay that is about to free up first */
.pl-next { transform-box: fill-box; transform-origin: center; animation: pl-pulse 2.6s ease-out infinite; }
@keyframes pl-pulse { 0% { opacity: 0.55; transform: scale(1); } 70%, 100% { opacity: 0; transform: scale(1.7); } }
@media (prefers-reduced-motion: reduce) { .pl-next { animation: none; opacity: 0.3; } }

/* --------------------------------------------------------- plan overlays */

.sp-ctrl { position: absolute; right: 10px; bottom: 10px; display: flex; flex-direction: column; gap: 8px; }
.sp-ctrl button {
  width: 44px; height: 44px; border-radius: 14px; display: grid; place-items: center;
  background: color-mix(in srgb, var(--zv-surface) 92%, transparent);
  border: 1px solid var(--zv-line); color: var(--zv-text);
  box-shadow: var(--zv-shadow-sm); backdrop-filter: blur(8px);
}
.sp-ctrl button svg { width: 20px; height: 20px; }
.sp-ctrl button:active { background: var(--zv-surface-3); }
.sp-ctrl button[disabled] { opacity: 0.4; }

.sp-scale {
  position: absolute; left: 10px; bottom: 12px; pointer-events: none;
  font-size: 14px; font-weight: 700; color: var(--pl-label);
  display: flex; flex-direction: column; gap: 3px; align-items: flex-start;
  text-shadow: 0 0 4px var(--pl-label-halo), 0 0 4px var(--pl-label-halo);
}
.sp-scale i { display: block; height: 7px; border: 1.5px solid var(--pl-label); border-top: 0; width: 60px; }

.sp-hint {
  position: absolute; left: 10px; top: 10px; right: 64px;
  font-size: 14px; font-weight: 650; line-height: 1.35;
  padding: 8px 11px; border-radius: 12px;
  /* Measured 3.55:1 against its real composited backdrop when this was
     --zv-text-2 over a 93% surface: the plan showing through the panel is
     lighter than the surface token it was checked against. Opaque panel,
     full-strength ink. */
  background: var(--zv-surface);
  border: 1px solid var(--zv-line); color: var(--zv-text);
  box-shadow: var(--zv-shadow-sm);
}
.sp-hint[hidden] { display: none; }

/* ------------------------------------------------------------ stage foot */

.sp-foot { display: flex; align-items: center; gap: 8px; padding: 10px 0 4px; flex-wrap: wrap; }
.sp-points {
  display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 13px;
  border-radius: 14px; background: color-mix(in srgb, var(--zv-accent) 13%, var(--zv-surface-2));
  border: 1px solid color-mix(in srgb, var(--zv-accent) 34%, var(--zv-line));
  font-size: 14px; font-weight: 700;
}
.sp-points b { color: var(--zv-dc-ink); font-variant-numeric: tabular-nums; }
.sp-points svg { width: 17px; height: 17px; color: var(--zv-dc-ink); flex: none; }
.sp-foot-btn {
  display: flex; align-items: center; gap: 7px; min-height: 44px; padding: 0 13px;
  border-radius: 14px; background: var(--zv-surface-2); border: 1px solid var(--zv-line);
  font-size: 14px; font-weight: 700; color: var(--zv-text-2); text-decoration: none;
}
.sp-foot-btn svg { width: 16px; height: 16px; flex: none; }
.sp-foot-spacer { flex: 1; min-width: 0; }

.sp-demo {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 14px; color: var(--zv-text-3); padding: 8px 0 0;
}
.sp-demo i { width: 7px; height: 7px; border-radius: 50%; background: var(--zv-amber); flex: none; }

/* ------------------------------------------------------------- the legend */

.sp-legend { display: none; padding: 12px 0 0; }
.sp-legend.is-open { display: block; }
.sp-legend ul { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 9px 14px; }
.sp-legend li { display: flex; align-items: center; gap: 9px; font-size: 14px; color: var(--zv-text-2); }
.sp-legend .sw { width: 26px; height: 20px; border-radius: 5px; flex: none; border: 2px solid; display: grid; place-items: center; }
.sp-legend .sw svg { width: 12px; height: 12px; }
.sp-legend .sw.st-free { background: var(--st-free-fill); border-color: var(--st-free-line); color: var(--st-free-ink); }
.sp-legend .sw.st-busy { background: var(--st-busy-fill); border-color: var(--st-busy-line); color: var(--st-busy-ink); }
.sp-legend .sw.st-held { background: var(--st-held-fill); border-color: var(--st-held-line); color: var(--st-held-ink); border-style: dashed; }
.sp-legend .sw.st-down { background: var(--st-down-fill); border-color: var(--st-down-line); color: var(--st-down-ink); }
.sp-legend .sw.pk { background: var(--pl-tarmac); border-color: var(--pl-bay-line); }
.sp-legend .sw.gr { background: var(--pl-green); border-color: var(--pl-green-2); }
.sp-legend .sw.bd { background: var(--pl-build); border-color: var(--pl-build-line); }
.sp-legend .sw.rd { background: var(--pl-road); border-color: var(--pl-road-line); }
.sp-legend p { font-size: 14px; color: var(--zv-text-3); margin: 12px 0 0; }

/* ------------------------------------------------------------ sheet/panel */

.sp-scrim {
  position: fixed; inset: 0; z-index: 80; background: var(--zv-scrim);
  opacity: 0; visibility: hidden; transition: opacity 0.22s ease, visibility 0.22s;
}
.sp-scrim.is-open { opacity: 1; visibility: visible; }

.sp-sheet {
  position: fixed; z-index: 81; left: 0; right: 0; bottom: 0;
  max-height: 86svh; display: flex; flex-direction: column;
  background: var(--zv-surface); border-radius: 24px 24px 0 0;
  box-shadow: var(--zv-shadow);
  transform: translateY(101%);
  transition: transform 0.28s cubic-bezier(0.22, 1, 0.3, 1);
  visibility: hidden;
}
.sp-sheet.is-open { transform: none; visibility: visible; }
.sp-sheet.is-drag { transition: none; }

.sp-grab { height: 22px; display: grid; place-items: center; flex: none; touch-action: none; cursor: grab; }
.sp-grab::before { content: ""; width: 40px; height: 4px; border-radius: 2px; background: var(--zv-text-3); opacity: 0.55; }

.sp-sheet-head {
  display: flex; align-items: flex-start; gap: 10px; flex: none;
  padding: 2px 14px 12px; border-bottom: 1px solid var(--zv-line);
}
.sp-back, .sp-close {
  width: 44px; height: 44px; border-radius: 14px; flex: none; display: grid; place-items: center;
  background: var(--zv-surface-2); color: var(--zv-text-2); border: 1px solid var(--zv-line);
}
.sp-back svg, .sp-close svg { width: 19px; height: 19px; }
.sp-sheet-title { flex: 1; min-width: 0; padding-top: 2px; }
.sp-sheet-title h2 { margin: 0; font-size: 19px; font-weight: 800; letter-spacing: -0.01em; line-height: 1.2; }
.sp-sheet-title p { margin: 3px 0 0; font-size: 14px; color: var(--zv-text-2); line-height: 1.35; }
.sp-sheet-body { overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; padding: 14px 14px calc(20px + var(--zv-bottom)); }

/* --------------------------------------------------------- sheet content */

.sp-kv { display: grid; grid-template-columns: repeat(2, 1fr); gap: 9px; margin-bottom: 14px; }
.sp-kv > div { background: var(--zv-surface-2); border: 1px solid var(--zv-line); border-radius: 14px; padding: 10px 12px; }
.sp-kv .k { font-size: 14px; color: var(--zv-text-3); font-weight: 650; }
.sp-kv .v { font-size: 16px; font-weight: 750; margin-top: 2px; }

.sp-now {
  display: flex; gap: 12px; align-items: center; padding: 13px;
  border-radius: 16px; margin-bottom: 14px; border: 1px solid;
}
.sp-now.st-free { background: var(--st-free-fill); border-color: var(--st-free-line); color: var(--st-free-ink); }
.sp-now.st-busy { background: var(--st-busy-fill); border-color: var(--st-busy-line); color: var(--st-busy-ink); }
.sp-now.st-held { background: var(--st-held-fill); border-color: var(--st-held-line); color: var(--st-held-ink); }
.sp-now.st-down { background: var(--st-down-fill); border-color: var(--st-down-line); color: var(--st-down-ink); }
.sp-now-ring { width: 52px; height: 52px; flex: none; }
.sp-now-ring text { font-size: 14px; font-weight: 800; fill: currentColor; text-anchor: middle; dominant-baseline: middle; }
.sp-now-ico { width: 52px; height: 52px; flex: none; display: grid; place-items: center; border-radius: 16px; background: color-mix(in srgb, currentColor 18%, transparent); }
.sp-now-ico svg { width: 24px; height: 24px; }
.sp-now-t b { display: block; font-size: 15px; font-weight: 800; line-height: 1.3; }
.sp-now-t span { display: block; font-size: 14px; opacity: 0.92; line-height: 1.4; margin-top: 2px; }

.sp-h3 { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin: 20px 0 10px; }
.sp-h3 h3 { margin: 0; font-size: 16px; font-weight: 800; letter-spacing: -0.01em; flex: none; }
.sp-h3 span { font-size: 14px; color: var(--zv-text-3); min-width: 0; text-align: right; line-height: 1.35; }
.sp-h3:first-child { margin-top: 0; }

/* ---- the forward schedule --------------------------------------------- */

.sp-day { margin-bottom: 6px; }
.sp-day-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 14px 0 8px; }
.sp-day-head b { font-size: 15px; font-weight: 800; }
.sp-day-head span { font-size: 14px; color: var(--zv-text-3); }

/* The orientation strip: the whole day at a glance, peak window shaded,
   a now marker. Detail lives in the segment list below it. */
.sp-strip { position: relative; height: 26px; border-radius: 8px; overflow: hidden; background: var(--zv-surface-3); margin-bottom: 4px; }
.sp-strip i { position: absolute; top: 0; bottom: 0; display: block; }
.sp-strip i.free { background: var(--st-free-fill); box-shadow: inset 0 0 0 1px var(--st-free-line); }
.sp-strip i.busy { background: var(--st-busy-fill); box-shadow: inset 0 0 0 1px var(--st-busy-line); }
.sp-strip i.past { background: var(--zv-surface-3); opacity: 0.75; }
.sp-strip i.peak { background: repeating-linear-gradient(135deg, transparent 0 5px, color-mix(in srgb, var(--st-held-line) 42%, transparent) 5px 7px); border-left: 1px solid color-mix(in srgb, var(--st-held-line) 60%, transparent); border-right: 1px solid color-mix(in srgb, var(--st-held-line) 60%, transparent); }
.sp-strip i.now { width: 2px; background: var(--zv-text); z-index: 2; }
.sp-strip-ax { display: flex; justify-content: space-between; font-size: 14px; color: var(--zv-text-3); margin-bottom: 12px; }

.sp-segs { display: flex; flex-direction: column; gap: 8px; }
.sp-seg {
  display: flex; align-items: stretch; gap: 0; width: 100%; text-align: left;
  border-radius: 14px; overflow: hidden; border: 1px solid var(--zv-line);
  background: var(--zv-surface-2); min-height: 60px;
}
.sp-seg .rail { width: 5px; flex: none; }
.sp-seg .in { flex: 1; min-width: 0; padding: 10px 12px; display: flex; align-items: center; gap: 10px; }
.sp-seg .txt { flex: 1; min-width: 0; }
.sp-seg .when { display: block; font-size: 15px; font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1.3; }
.sp-seg .who { display: block; font-size: 14px; color: var(--zv-text-2); margin-top: 2px; line-height: 1.35; }
.sp-seg .cta { flex: none; display: flex; align-items: center; gap: 6px; font-size: 14px; font-weight: 800; }
.sp-seg .cta svg { width: 16px; height: 16px; }

.sp-seg.free { background: color-mix(in srgb, var(--st-free-fill) 55%, var(--zv-surface-2)); border-color: color-mix(in srgb, var(--st-free-line) 45%, var(--zv-line)); }
.sp-seg.free .rail { background: var(--st-free-line); }
.sp-seg.free .cta { color: var(--st-free-ink); }
.sp-seg.busy .rail { background: var(--st-busy-line); }
.sp-seg.held .rail { background: var(--st-held-line); }
.sp-seg.down .rail { background: var(--st-down-line); }
.sp-seg.mine { border-color: var(--zv-accent); }
.sp-seg[disabled] { opacity: 1; }
.sp-seg .pts {
  font-size: 14px; font-weight: 800; padding: 3px 8px; border-radius: 8px; flex: none;
  background: var(--zv-surface-3); color: var(--zv-text-2); white-space: nowrap;
}
.sp-seg .pts.cheap { background: var(--st-free-fill); color: var(--st-free-ink); border: 1px solid var(--st-free-line); }
.sp-seg .pts.dear { background: var(--st-held-fill); color: var(--st-held-ink); border: 1px solid var(--st-held-line); }

/* ---- reserve flow ------------------------------------------------------ */

.sp-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
.sp-chip {
  min-height: 44px; padding: 0 14px; border-radius: 13px; font-size: 14px; font-weight: 750;
  background: var(--zv-surface-2); border: 1px solid var(--zv-line); color: var(--zv-text);
  font-variant-numeric: tabular-nums;
}
.sp-chip[aria-pressed="true"] { background: var(--zv-accent); color: var(--zv-accent-ink); border-color: transparent; }
.sp-chip[disabled] { opacity: 0.38; }

.sp-quote { background: var(--zv-surface-2); border: 1px solid var(--zv-line); border-radius: 16px; padding: 14px; margin-bottom: 12px; }
.sp-quote-row { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; padding: 5px 0; }
.sp-quote-row .k { font-size: 14px; color: var(--zv-text-2); }
.sp-quote-row .v { font-size: 15px; font-weight: 750; font-variant-numeric: tabular-nums; }
.sp-quote-row.total { border-top: 1px solid var(--zv-line); margin-top: 6px; padding-top: 11px; }
.sp-quote-row.total .k { font-size: 15px; font-weight: 700; color: var(--zv-text); }
.sp-quote-row.total .v { font-size: 22px; font-weight: 800; color: var(--zv-dc-ink); }

/* The comparison, shown at the moment of choosing. This is the mechanism. */
.sp-shift {
  border-radius: 16px; padding: 13px; margin-bottom: 12px;
  background: color-mix(in srgb, var(--st-free-line) 12%, var(--zv-surface-2));
  border: 1px solid color-mix(in srgb, var(--st-free-line) 40%, var(--zv-line));
}
.sp-shift-top { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.sp-shift-top svg { width: 20px; height: 20px; color: var(--st-free-line); flex: none; }
.sp-shift-top b { font-size: 15px; font-weight: 800; }
.sp-shift-bars { display: flex; flex-direction: column; gap: 8px; margin-bottom: 11px; }
.sp-shift-bar { display: flex; align-items: center; gap: 9px; }
.sp-shift-bar .lb { font-size: 14px; font-weight: 700; width: 82px; flex: none; font-variant-numeric: tabular-nums; line-height: 1.25; }
.sp-shift-bar .lb small { font-size: 14px; font-weight: 650; color: var(--zv-text-3); }
.sp-shift-bar .tr { flex: 1; height: 22px; border-radius: 7px; background: var(--zv-surface-3); overflow: hidden; }
.sp-shift-bar .tr i { display: block; height: 100%; border-radius: 7px; background: var(--st-held-line); transition: width 0.3s ease; }
.sp-shift-bar.cheap .tr i { background: var(--st-free-line); }
.sp-shift-bar .vl { font-size: 14px; font-weight: 800; width: 58px; text-align: right; flex: none; font-variant-numeric: tabular-nums; }
.sp-shift p { font-size: 14px; color: var(--zv-text-2); margin: 0 0 11px; line-height: 1.45; }

.sp-actions { display: flex; flex-direction: column; gap: 9px; margin-top: 6px; }

.sp-toast {
  position: fixed; left: 50%; bottom: calc(22px + var(--zv-bottom)); transform: translate(-50%, 140%);
  z-index: 95; width: max-content; max-width: min(440px, calc(100vw - 32px));
  display: flex; align-items: center; gap: 10px;
  padding: 13px 16px; border-radius: 16px; font-size: 14px; font-weight: 700; line-height: 1.4;
  background: var(--zv-text); color: var(--zv-bg); box-shadow: var(--zv-shadow);
  transition: transform 0.3s cubic-bezier(0.22, 1, 0.3, 1);
}
.sp-toast.is-on { transform: translate(-50%, 0); }
.sp-toast svg { width: 19px; height: 19px; flex: none; }

/* ---- technical report -------------------------------------------------- */

.sp-health {
  display: flex; align-items: center; gap: 12px; padding: 13px; border-radius: 16px;
  margin-bottom: 14px; border: 1px solid;
}
.sp-health.good { background: var(--st-free-fill); border-color: var(--st-free-line); color: var(--st-free-ink); }
.sp-health.watch { background: var(--st-held-fill); border-color: var(--st-held-line); color: var(--st-held-ink); }
.sp-health.bad { background: var(--st-down-fill); border-color: var(--st-down-line); color: var(--st-down-ink); }
.sp-health svg { width: 26px; height: 26px; flex: none; }
.sp-health b { display: block; font-size: 16px; font-weight: 800; }
.sp-health span { display: block; font-size: 14px; opacity: 0.92; margin-top: 2px; line-height: 1.4; }

.sp-log { display: flex; flex-direction: column; gap: 9px; }
.sp-log-item { background: var(--zv-surface-2); border: 1px solid var(--zv-line); border-radius: 14px; padding: 11px 13px; }
.sp-log-item .d { font-size: 14px; font-weight: 800; color: var(--zv-text); font-variant-numeric: tabular-nums; }
.sp-log-item p { font-size: 14px; color: var(--zv-text-2); margin: 4px 0 0; line-height: 1.5; }
.sp-log-item .by { font-size: 14px; color: var(--zv-text-3); margin-top: 5px; }

.sp-incident { border-radius: 16px; padding: 13px; border: 1px solid var(--zv-line); background: var(--zv-surface-2); }
.sp-incident + .sp-incident { margin-top: 10px; }
.sp-incident .d { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 800; margin-bottom: 8px; }
.sp-incident .d svg { width: 16px; height: 16px; color: var(--st-held-line); flex: none; }
.sp-incident dl { margin: 0; }
.sp-incident dt { font-size: 14px; font-weight: 750; color: var(--zv-text); margin-top: 9px; }
.sp-incident dt:first-child { margin-top: 0; }
.sp-incident dd { font-size: 14px; color: var(--zv-text-2); margin: 2px 0 0; line-height: 1.5; }
.sp-incident .out { margin-top: 11px; padding-top: 10px; border-top: 1px solid var(--zv-line); font-size: 14px; color: var(--st-free-ink); font-weight: 650; line-height: 1.5; }

.sp-clean {
  display: flex; align-items: center; gap: 11px; padding: 13px; border-radius: 16px;
  background: var(--st-free-fill); border: 1px solid var(--st-free-line); color: var(--st-free-ink);
  font-size: 14px; font-weight: 650; line-height: 1.45;
}
.sp-clean svg { width: 22px; height: 22px; flex: none; }

/* ---- tower panel ------------------------------------------------------- */

.sp-people { display: flex; flex-direction: column; gap: 8px; }
/* Wraps rather than truncating the car model: at 320px a status pill like
   "71%, until 7:35 PM" plus "Tata Nexon EV Max" cannot share a line, and
   the model is the half a resident is scanning for. */
.sp-person { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 11px; padding: 9px 12px; border-radius: 14px; background: var(--zv-surface-2); border: 1px solid var(--zv-line); min-height: 60px; }
.sp-person.me { border-color: var(--zv-accent); background: color-mix(in srgb, var(--zv-accent) 10%, var(--zv-surface-2)); }
.sp-person .av { width: 40px; height: 40px; border-radius: 13px; flex: none; display: grid; place-items: center; background: var(--zv-surface-3); font-size: 14px; font-weight: 800; color: var(--zv-text-2); }
.sp-person .tx { flex: 1 1 130px; min-width: 0; }
.sp-person .tx b { display: block; font-size: 15px; font-weight: 750; }
.sp-person .tx span { display: block; font-size: 14px; color: var(--zv-text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sp-person .st { flex: none; margin-left: auto; font-size: 14px; font-weight: 800; padding: 4px 9px; border-radius: 9px; border: 1px solid; white-space: nowrap; }
.sp-person .st.st-busy { background: var(--st-busy-fill); border-color: var(--st-busy-line); color: var(--st-busy-ink); }
.sp-person .st.st-held { background: var(--st-held-fill); border-color: var(--st-held-line); color: var(--st-held-ink); }
/* --zv-text-3 on --zv-surface-3 measured 4.34:1, under the 4.5:1 floor. */
.sp-person .st.idle { background: var(--zv-surface-3); border-color: var(--zv-line); color: var(--zv-text-2); }

.sp-note {
  display: flex; gap: 9px; align-items: flex-start; font-size: 14px; color: var(--zv-text-2);
  background: var(--zv-surface-2); border: 1px dashed var(--zv-line); border-radius: 14px;
  padding: 11px 13px; line-height: 1.5; margin-top: 14px;
}
.sp-note svg { width: 17px; height: 17px; color: var(--zv-text-3); flex: none; margin-top: 2px; }

/* ---- points panel ------------------------------------------------------ */

.sp-meter { background: var(--zv-surface-2); border: 1px solid var(--zv-line); border-radius: 18px; padding: 15px; margin-bottom: 16px; }
.sp-meter-top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.sp-meter-top .big { font-size: 30px; font-weight: 800; line-height: 1; font-variant-numeric: tabular-nums; }
.sp-meter-top .sm { font-size: 14px; color: var(--zv-text-2); }
.sp-meter-bar { height: 12px; border-radius: 6px; background: var(--zv-surface-3); overflow: hidden; }
.sp-meter-bar i { display: block; height: 100%; border-radius: 6px; background: var(--zv-accent); transition: width 0.4s ease; }

.sp-bands { display: flex; flex-direction: column; gap: 9px; }
.sp-band { display: flex; align-items: center; gap: 12px; padding: 12px 13px; border-radius: 14px; border: 1px solid var(--zv-line); background: var(--zv-surface-2); }
.sp-band.peak { background: var(--st-held-fill); border-color: var(--st-held-line); }
.sp-band.off { background: var(--st-free-fill); border-color: var(--st-free-line); }
.sp-band .tx { flex: 1; min-width: 0; }
.sp-band .tx b { display: block; font-size: 15px; font-weight: 800; }
.sp-band.peak .tx b, .sp-band.peak .tx span, .sp-band.peak .cost { color: var(--st-held-ink); }
.sp-band.off .tx b, .sp-band.off .tx span, .sp-band.off .cost { color: var(--st-free-ink); }
.sp-band .tx span { display: block; font-size: 14px; color: var(--zv-text-2); margin-top: 1px; }
.sp-band .cost { flex: none; font-size: 18px; font-weight: 800; font-variant-numeric: tabular-nums; text-align: right; }
.sp-band .cost small { display: block; font-size: 14px; font-weight: 650; opacity: 0.85; }

.sp-rules { list-style: none; margin: 14px 0 0; padding: 0; display: flex; flex-direction: column; gap: 11px; }
.sp-rules li { display: flex; gap: 10px; font-size: 14px; color: var(--zv-text-2); line-height: 1.5; }
.sp-rules li svg { width: 18px; height: 18px; flex: none; color: var(--zv-dc-ink); margin-top: 2px; }
.sp-rules li b { color: var(--zv-text); font-weight: 750; }

/* ------------------------------------------------------- committee console */

.sp-console {
  position: fixed; inset: 0; z-index: 88; background: var(--zv-bg);
  display: flex; flex-direction: column;
  transform: translateY(100%); visibility: hidden;
  transition: transform 0.3s cubic-bezier(0.22, 1, 0.3, 1), visibility 0.3s;
}
.sp-console.is-open { transform: none; visibility: visible; }
.sp-console-head {
  display: flex; align-items: center; gap: 10px; flex: none;
  padding: calc(10px + var(--zv-top)) 16px 10px; border-bottom: 1px solid var(--zv-line);
}
.sp-console-head .t { flex: 1; min-width: 0; }
.sp-console-head .t b { display: block; font-size: 17px; font-weight: 800; }
.sp-console-head .t span { display: block; font-size: 14px; color: var(--zv-text-2); }
.sp-console-body { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 16px 16px calc(28px + var(--zv-bottom)); }
.sp-console-inner { max-width: 1080px; margin: 0 auto; }

.sp-cards { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin-bottom: 18px; }
.sp-stat { background: var(--zv-surface-2); border: 1px solid var(--zv-line); border-radius: 16px; padding: 13px; }
.sp-stat .k { font-size: 14px; color: var(--zv-text-3); font-weight: 650; line-height: 1.3; }
.sp-stat .v { font-size: 24px; font-weight: 800; margin-top: 4px; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.sp-stat .d { font-size: 14px; color: var(--zv-text-2); margin-top: 3px; line-height: 1.35; }
.sp-stat .d.up { color: var(--st-free-ink); font-weight: 700; }

/* utilisation chart: two series, before and after points */
.sp-chart { background: var(--zv-surface-2); border: 1px solid var(--zv-line); border-radius: 18px; padding: 15px 13px 11px; }
.sp-chart-key { display: flex; gap: 16px; margin-bottom: 12px; font-size: 14px; color: var(--zv-text-2); }
.sp-chart-key span { display: flex; align-items: center; gap: 7px; }
.sp-chart-key i { width: 14px; height: 10px; border-radius: 3px; }
.sp-chart-key i.now { background: var(--zv-accent); }
.sp-chart-key i.was { background: none; border: 1.5px dashed var(--zv-text-3); }
.sp-bars { display: flex; align-items: flex-end; gap: 2px; height: 130px; }
.sp-bar-col { flex: 1; height: 100%; display: flex; align-items: flex-end; position: relative; }
.sp-bar-col .was { position: absolute; left: 0; right: 0; bottom: 0; border: 1.5px dashed var(--zv-text-3); border-bottom: 0; border-radius: 3px 3px 0 0; }
.sp-bar-col .now { width: 100%; background: var(--zv-accent); border-radius: 3px 3px 0 0; position: relative; z-index: 1; }
.sp-bar-col.pk .now { background: var(--st-held-line); }
.sp-bar-ax { display: flex; justify-content: space-between; font-size: 14px; color: var(--zv-text-3); margin-top: 8px; }

.sp-split { height: 34px; border-radius: 10px; overflow: hidden; display: flex; background: var(--zv-surface-3); margin-bottom: 10px; }
.sp-split i { display: block; height: 100%; }
.sp-split i.el { background: var(--zv-text-3); }
.sp-split i.zv { background: var(--zv-ac-ink); }
.sp-split i.net { background: var(--zv-accent); }
.sp-split-key { display: flex; flex-wrap: wrap; gap: 8px 16px; font-size: 14px; color: var(--zv-text-2); }
.sp-split-key span { display: flex; align-items: center; gap: 7px; }
.sp-split-key i { width: 12px; height: 12px; border-radius: 4px; flex: none; }

.sp-ctl { display: flex; flex-direction: column; gap: 18px; }
.sp-ctl-row label { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: 15px; font-weight: 750; margin-bottom: 6px; }
.sp-ctl-row output { color: var(--zv-dc-ink); font-variant-numeric: tabular-nums; font-weight: 800; }
.sp-ctl-row input[type="range"] { width: 100%; height: 44px; -webkit-appearance: none; appearance: none; background: none; display: block; }
.sp-ctl-row input[type="range"]::-webkit-slider-runnable-track { height: 8px; border-radius: 4px; background: var(--zv-surface-3); }
.sp-ctl-row input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 28px; height: 28px; border-radius: 50%; background: var(--zv-accent); margin-top: -10px; border: 3px solid var(--zv-surface); box-shadow: var(--zv-shadow-sm); }
.sp-ctl-row input[type="range"]::-moz-range-track { height: 8px; border-radius: 4px; background: var(--zv-surface-3); }
.sp-ctl-row input[type="range"]::-moz-range-thumb { width: 24px; height: 24px; border-radius: 50%; background: var(--zv-accent); border: 3px solid var(--zv-surface); }
.sp-ctl-hint { font-size: 14px; color: var(--zv-text-3); margin: 2px 0 0; line-height: 1.45; }

.sp-bay-ctl { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 9px 0; border-top: 1px solid var(--zv-line); min-height: 60px; }
.sp-bay-ctl:first-of-type { border-top: 0; }
.sp-bay-ctl .n { font-size: 15px; font-weight: 750; }
.sp-bay-ctl .s { font-size: 14px; color: var(--zv-text-3); }
.sp-block-btn { min-height: 44px; min-width: 96px; padding: 0 14px; border-radius: 13px; font-size: 14px; font-weight: 750; background: var(--zv-surface-3); color: var(--zv-text); flex: none; }
/* Not --st-down-line: that token is tuned to be a bay outline against a
   pale fill, and white text on it measured 2.67:1 in dark theme. This is a
   fixed red picked for white text specifically, 5.8:1 in both themes. */
.sp-block-btn.on { background: #c1272d; color: #fff; }

/* ------------------------------------------------------------- prose page */

.sp-prose { padding: 8px 0 0; }
.sp-sec { padding: 30px 0; border-top: 1px solid var(--zv-line); }
.sp-eyebrow { font-size: 14px; font-weight: 800; color: var(--zv-dc-ink); text-transform: uppercase; letter-spacing: 0.07em; margin: 0 0 8px; }
.sp-sec h2 { font-size: 22px; font-weight: 800; letter-spacing: -0.02em; margin: 0 0 8px; line-height: 1.2; }
.sp-lede { font-size: 15px; color: var(--zv-text-2); margin: 0 0 18px; max-width: 62ch; line-height: 1.6; }

.sp-voice {
  border-left: 3px solid var(--zv-accent); padding: 2px 0 2px 16px; margin: 0 0 16px;
  font-size: 17px; line-height: 1.55; font-weight: 600; max-width: 56ch;
}
.sp-voice cite { display: block; font-size: 14px; font-style: normal; color: var(--zv-text-3); font-weight: 650; margin-top: 10px; }

/* Progressive disclosure for the copy a resident wants once and then never
   again. 44px tall because it is a real tap target even though the audit's
   selector list does not catch a bare <summary>. */
.sp-more { margin: 0 0 4px; }
.sp-more > summary {
  display: flex; align-items: center; gap: 8px; min-height: 44px;
  font-size: 14px; font-weight: 700; color: var(--zv-dc-ink); cursor: pointer;
  list-style: none; width: max-content;
}
.sp-more > summary::-webkit-details-marker { display: none; }
.sp-more > summary::after {
  content: ""; width: 8px; height: 8px; flex: none;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg); transition: transform 0.2s ease;
}
.sp-more[open] > summary::after { transform: translateY(2px) rotate(-135deg); }
.sp-more > summary:focus-visible { outline: 2px solid var(--zv-accent); outline-offset: 3px; border-radius: 8px; }

/* The commercial figures on this page are invented and the page is public,
   so the label travels WITH the number rather than sitting in a footnote
   the reader has already scrolled past. */
.sp-warn {
  display: flex; gap: 10px; align-items: flex-start; margin: 0 0 16px;
  font-size: 14px; line-height: 1.5; color: var(--zv-text);
  background: color-mix(in srgb, var(--zv-warn-ink) 12%, var(--zv-surface-2));
  border: 1px solid color-mix(in srgb, var(--zv-warn-ink) 42%, var(--zv-line));
  border-radius: 14px; padding: 12px 14px;
}
.sp-warn svg { width: 19px; height: 19px; color: var(--zv-warn-ink); flex: none; margin-top: 1px; }
.sp-warn b { font-weight: 800; }

.sp-samp {
  display: block; font-style: normal; font-size: 14px; font-weight: 700;
  letter-spacing: 0.04em; text-transform: uppercase; color: var(--zv-warn-ink);
  line-height: 1.1; margin-bottom: 2px;
}

.sp-steps { display: flex; flex-direction: column; gap: 14px; }
.sp-step { display: flex; gap: 13px; }
.sp-step-n { width: 32px; height: 32px; border-radius: 11px; background: var(--zv-accent); color: var(--zv-accent-ink); display: grid; place-items: center; font-size: 15px; font-weight: 800; flex: none; }
.sp-step b { display: block; font-size: 15px; font-weight: 750; margin-bottom: 3px; }
.sp-step p { font-size: 14px; color: var(--zv-text-2); margin: 0; line-height: 1.55; max-width: 58ch; }

/* CLS: Phase 6 moved the commercial rows out of the HTML and into
   paintMoney(), so every rupee figure has one source. That makes the block
   JS-built, so its height is reserved the way #sp-faq's is. Measured 509px
   at 320 and 360, 508 at 414, 507 from 768 up: the rows wrap the same way at
   every width because the amount column is fixed. Re-measure if a row's
   label or description changes length. */
.sp-money { display: grid; grid-template-columns: 1fr; gap: 10px; min-height: 509px; }
.sp-money-row { display: flex; align-items: center; gap: 12px; padding: 13px; border-radius: 16px; background: var(--zv-surface-2); border: 1px solid var(--zv-line); }
.sp-money-row .tx { flex: 1; min-width: 0; }
.sp-money-row .tx b { display: block; font-size: 15px; font-weight: 750; }
.sp-money-row .tx span { display: block; font-size: 14px; color: var(--zv-text-2); line-height: 1.45; margin-top: 2px; }
.sp-money-row .amt { flex: none; font-size: 17px; font-weight: 800; font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.sp-money-row.net { background: color-mix(in srgb, var(--zv-accent) 12%, var(--zv-surface-2)); border-color: color-mix(in srgb, var(--zv-accent) 36%, var(--zv-line)); }
.sp-money-row.net .amt { color: var(--zv-dc-ink); }
.sp-money-row .amt small { display: block; font-size: 14px; font-weight: 650; color: var(--zv-text-3); }

.sp-flag {
  display: flex; gap: 10px; align-items: flex-start; font-size: 14px; color: var(--zv-text-2);
  background: var(--zv-surface-2); border: 1px dashed var(--zv-line); border-radius: 14px;
  padding: 12px 14px; margin-top: 14px; line-height: 1.55;
}
.sp-flag svg { width: 18px; height: 18px; color: var(--zv-amber); flex: none; margin-top: 2px; }

/* CLS: the list is built by JS from the FAQ data, so its height has to be
   reserved. Phase 4 reserved 426px on the assumption that every question
   fits one 60px line. Measured, several wrapped to 70px and the real closed
   height was 476px at 360px wide and 517px at 320px, so the reservation was
   50px short and only escaped the CLS budget because the shift happens far
   below the fold. Phase 5 shortened the questions, bringing those to 456px
   and 496px; reserving the wider of the two means nothing shifts at either
   width. Re-measure if the question text changes again. */
#sp-faq { min-height: 496px; }
.sp-faq-item { border-bottom: 1px solid var(--zv-line); }
.sp-faq-item:last-child { border-bottom: 0; }
.sp-faq-q { width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 60px; padding: 14px 2px; text-align: left; font-size: 15px; font-weight: 750; line-height: 1.4; }
.sp-faq-q svg { width: 20px; height: 20px; color: var(--zv-text-3); flex: none; transition: transform 0.2s ease; }
.sp-faq-item.is-open .sp-faq-q svg { transform: rotate(180deg); }
.sp-faq-a { display: none; font-size: 14px; color: var(--zv-text-2); line-height: 1.65; padding: 0 2px 18px; max-width: 68ch; }
.sp-faq-item.is-open .sp-faq-a { display: block; }

.sp-form { display: flex; flex-direction: column; gap: 12px; max-width: 480px; }
.sp-form label { font-size: 14px; font-weight: 700; color: var(--zv-text-2); margin-bottom: 6px; display: block; }
.sp-form input, .sp-form select {
  width: 100%; min-height: 50px; border-radius: 14px; background: var(--zv-surface-2);
  border: 1px solid var(--zv-line); padding: 0 14px; font-size: 16px; font-weight: 600;
  color: var(--zv-text); outline: none; font-family: inherit;
}
.sp-form input:focus, .sp-form select:focus { border-color: var(--zv-accent); }
.sp-form-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.sp-form-note { font-size: 14px; color: var(--zv-text-3); margin: 4px 0 0; line-height: 1.5; }

.sp-footer { padding: 28px 0 40px; border-top: 1px solid var(--zv-line); }
.sp-footer p { font-size: 14px; color: var(--zv-text-3); margin: 0 0 6px; max-width: 62ch; }
.sp-footer nav { display: flex; flex-wrap: wrap; gap: 4px 18px; margin-top: 8px; }
.sp-footer a { display: inline-flex; align-items: center; min-height: 44px; color: var(--zv-dc-ink); font-weight: 700; font-size: 14px; text-decoration: none; }

/* ===================================================== PHASE 9: the split */

/* The resident page ends here: one quiet way through to the committee page,
   and nothing else below the plan. */
.sp-resident-foot {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 12px 20px; padding: 18px 16px 28px;
}
.sp-onward {
  display: inline-flex; align-items: center; gap: 8px; min-height: 44px;
  font-size: 14px; font-weight: 700; color: var(--zv-dc-ink); text-decoration: none;
}
.sp-onward svg { width: 17px; height: 17px; flex: none; }
.sp-resident-foot nav { display: flex; gap: 4px 18px; flex-wrap: wrap; }
.sp-resident-foot nav a {
  /* min-width as well as min-height: "Zevvy" is a short enough label that a
     44px-tall link was still only 38.8px wide. */
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; min-width: 44px;
  font-size: 14px; font-weight: 650; color: var(--zv-text-3); text-decoration: none;
}

/* The committee page opens on the numbers, not on a pitch. */
.sp-cmte-hero { padding: 26px 16px 8px; }
.sp-cmte-hero h1 { font-size: 27px; font-weight: 800; letter-spacing: -0.02em; line-height: 1.15; margin: 0 0 10px; }
.sp-cmte-cta { display: flex; flex-wrap: wrap; gap: 10px; margin: 4px 0 22px; }
.sp-cmte-cta .zv-btn { min-height: 48px; padding: 0 20px; }
.sp-cmte-figs {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px;
  margin-bottom: 14px;
}
.sp-cmte-figs > div {
  background: var(--zv-surface-2); border: 1px solid var(--zv-line);
  border-radius: 16px; padding: 13px 14px;
}
.sp-cmte-figs b {
  display: block; font-size: 23px; font-weight: 800; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums; color: var(--zv-dc-ink);
}
.sp-cmte-figs span { display: block; font-size: 14px; color: var(--zv-text-2); margin-top: 2px; line-height: 1.35; }

@media (min-width: 1024px) {
  .sp-cmte-hero { padding: 44px 32px 10px; }
  .sp-cmte-hero h1 { font-size: 38px; max-width: 20ch; }
  .sp-cmte-hero .sp-lede { font-size: 17px; max-width: 62ch; }
  .sp-cmte-figs { max-width: 760px; }
  .sp-resident-foot { padding: 22px 32px 34px; }
}

/* ---------------------------------------------------- short viewports */

@media (max-height: 560px) and (orientation: landscape) {
  :root { --sp-plan-h: calc(100svh - 196px); }
  .sp-title, .sp-title-sub { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .sp-status { min-height: 52px; margin-bottom: 8px; }
  .sp-stage { padding-top: 10px; }
}

/* -------------------------------------------------------------- desktop */

@media (min-width: 1024px) {
  /* 300px is the stage chrome above the plan on desktop (header, title,
     summary, bank pills) plus a margin, so the plan bottoms out just
     inside the fold rather than running under it. */
  :root { --sp-plan-h: clamp(420px, calc(100svh - 300px), 760px); }

  .sp-wrap { padding: 0 32px; }
  .sp-head-row { height: 64px; }
  .sp-brand-txt b { font-size: 15px; }

  .sp-stage { padding-top: 22px; }
  .sp-title { font-size: 27px; }
  .sp-title-sub { font-size: 15px; margin-bottom: 16px; }

  /* PHASE 7: the plan is the page, so the stage is not capped at --sp-max.
     It spans the viewport with a 5% gutter each side. The prose below keeps
     the 1280px measure, because 90vw of a 1920px monitor is an unreadable
     line length for body copy — this override is deliberately scoped to the
     stage and nothing else. */
  .sp-wrap.sp-stage { max-width: none; padding-left: 5%; padding-right: 5%; }

  /* the real plan-plus-detail layout: the plan keeps the width, the panel
     is permanently docked rather than covering it.

     The panel used to be a fixed 404/440px. Against a now-uncapped stage
     that made the plan smaller on a 1280px window than it had been, because
     a fixed column eats a bigger share of a narrower row: at 1280 the plan
     was 750px of a 1216px row, and a 5% gutter alone would have cut it to
     686px. Sizing the panel as a proportion instead, floored at the width
     the design already supports on a phone and capped so it stops growing
     on very wide monitors, makes the plan wider at every breakpoint. */
  .sp-stage-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) clamp(360px, 26%, 460px);
    gap: 20px; align-items: start;
  }
  .sp-stage-main { min-width: 0; }
  .sp-status { min-height: 66px; }
  .sp-status-n { font-size: 30px; }

  /* Scoped to the stage grid: the docked panel only makes sense beside the
     plan. society-for-committees.html reuses the same sheet for bay history
     opened from the console's fault list, and there it stays a bottom sheet
     at every width. */
  .sp-stage-grid .sp-scrim { display: none; }
  .sp-stage-grid > .sp-sheet {
    position: sticky; top: 84px; left: auto; right: auto; bottom: auto;
    transform: none; visibility: visible; border-radius: 20px;
    border: 1px solid var(--zv-line); background: var(--zv-surface);
    height: calc(100svh - 108px); max-height: 880px;
    box-shadow: none;
  }
  .sp-stage-grid > .sp-sheet .sp-grab { display: none; }
  .sp-stage-grid > .sp-sheet .sp-sheet-head { padding: 14px 16px 13px; }
  .sp-stage-grid > .sp-sheet .sp-sheet-body { padding: 16px; }
  .sp-stage-grid > .sp-sheet .sp-close { display: none; }
  .sp-stage-grid > .sp-sheet.at-root .sp-back { display: none; }

  .sp-legend ul { grid-template-columns: repeat(2, 1fr); }
  .sp-money { grid-template-columns: 1fr; max-width: 760px; }
  .sp-cards { grid-template-columns: repeat(4, 1fr); }
  .sp-console-body { padding: 24px 32px calc(40px + var(--zv-bottom)); }
  .sp-two { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; align-items: start; }
  .sp-sec { padding: 44px 0; }
  .sp-sec h2 { font-size: 26px; }
  .sp-steps { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px 28px; }
  .sp-toast { bottom: 26px; }
}

@media (min-width: 1440px) {
  /* only the gutter between plan and panel widens here; the panel itself is
     already proportional from 1024px up. */
  .sp-stage-grid { gap: 26px; }
}
