/* Step 1 flow: find and confirm (S1.0) and the canvas (S1.2) */

/* The sticky site header must stack above the Leaflet maps. Leaflet's
   own z-indexes run to 1000 (controls; panes 200-700, plus this flow's
   in-map pills at 500), all inside containers that create no stacking
   context, so they compete with the nav globally and a nav at the
   default 100 scrolls under the map. Raise the nav, never lower
   Leaflet's panes. Scoped here rather than nav.css on purpose: this
   sheet loads only on the flow pages, so pages with overlays that sit
   above the nav by design (calculator slide-over at 100, questionnaire
   modal at 100, toast at 200) keep their layering. */
.nav { z-index: 1100; }
.sp-main { max-width: 1040px; margin: 0 auto; padding: 26px 20px 60px; width: 100%; }
.sp-screen { display: none; }
.sp-screen.active { display: block; animation: sp-fadeIn .35s ease; }
@keyframes sp-fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
/* The flow's blocks toggle with the hidden attribute. Author display
   rules (.btn-row is flex) would outrank the attribute's UA style, so
   hidden is pinned here once for every block in the flow. */
.sp-main [hidden], .s1-strip [hidden] { display: none !important; }

/* ── The Step 1 strip (D80, D81; S1a) ─────────────────────────────────
   A 44px row in the 1040px column under the wordmark-only nav: Home
   (hidden until the screen's script shows it, D53), a hairline, the
   eyebrow, and the actions slot at the right, where project-sync.js puts
   Save project or the saved state (D109). */
.s1-strip-wrap { max-width: 1040px; width: 100%; margin: 0 auto; padding: 8px 20px 0; }
.s1-strip { display: flex; align-items: center; gap: 14px; min-height: 44px; flex-wrap: wrap; }
.s1-home { display: inline-flex; align-items: center; gap: 6px; min-height: 44px;
  font-family: 'DM Sans', sans-serif; font-size: 13px; font-weight: 500; color: var(--text-2);
  text-decoration: none; }
.s1-home:hover { color: var(--pool); }
.s1-hair { width: 1px; height: 16px; background: var(--border-2); }
.s1-eyebrow { font-family: 'DM Sans', sans-serif; font-size: 11px; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--pool-dark); }
.s1-actions { margin-left: auto; display: flex; align-items: center; gap: 10px; }
/* Save project in the strip (D81, D109; the Sep 29 boards' quiet
   underlined control), and the saved state in its place signed in. */
.s1-save, .done-band-save { flex: none; display: inline-flex; align-items: center; min-height: 44px;
  margin: 0; padding: 8px 6px; background: none; border: none; font-family: 'DM Sans', sans-serif;
  font-size: 12.5px; font-weight: 600; color: var(--pool-dark); white-space: nowrap; cursor: pointer;
  text-decoration: underline; text-decoration-color: var(--teal-border); text-underline-offset: 3px; }
.s1-save:hover, .done-band-save:hover { text-decoration-color: var(--pool); }
.s1-save:focus-visible, .done-band-save:focus-visible { outline: 2px solid var(--teal-border); outline-offset: 2px; border-radius: var(--r-sm); }
.s1-saved { font-size: 10.5px; font-weight: 600; letter-spacing: .04em; color: var(--pool-dark); white-space: nowrap; }
.s1-saved--failed { font-size: 12px; font-weight: 500; letter-spacing: 0; color: var(--text-2); }

/* ── Find and confirm (S1.0) ──────────────────────────────────────── */
.sp-find-main { padding-top: 26px; }
.s1-title { font-family: 'Fraunces', serif; font-weight: 400; font-style: normal; font-size: 24px;
  letter-spacing: -.3px; line-height: 1.25; color: var(--forest); margin: 0 0 6px; text-wrap: balance; }
@media (max-width: 767px) { .s1-title { font-size: 22px; } }
.s1-lede { margin: 4px 0 14px; }
/* The address card: the field row, the quiet lines, the map, and the
   state below the map, 14px apart. */
.find-card { display: flex; flex-direction: column; gap: 14px; }
.find-row { margin-top: 0; }
.find-row .addr-input { flex: 1 1 240px; min-width: 0; min-height: 46px; }
.find-row .zip-input { flex: 0 0 110px; min-width: 110px; }
.find-row .btn { min-height: 46px; white-space: nowrap; }
.addr-row { display: flex; gap: 10px; margin-top: 26px; flex-wrap: wrap; }
.addr-input {
  flex: 1; min-width: 260px; padding: 12px 14px; border-radius: var(--r-sm);
  border: 1px solid var(--border); font-family: 'DM Sans', sans-serif;
  font-size: 15px; color: var(--text); background: var(--surface);
}
.addr-input:focus { outline: none; border-color: var(--teal-border); box-shadow: 0 0 0 3px rgba(168,221,228,.35); }
.zip-input { flex: 0 0 110px; min-width: 110px; }
.addr-input.invalid { border-color: var(--sun); box-shadow: 0 0 0 3px rgba(212,137,42,.3); }
/* The field error and the two quiet lines sit tight under the field row
   (the card's gap, pulled back 6px). */
.addr-error { margin: -6px 0 0; font-size: 12.5px; color: var(--sun-dark); font-family: 'DM Sans', sans-serif; font-weight: 600; }
.records-line, .locked-line { margin: -6px 0 0; font-size: 12.5px; line-height: 1.5; font-family: 'DM Sans', sans-serif; }
.records-line { color: var(--text-3); }
.records-line span { color: var(--text-2); font-weight: 500; }
.locked-line { color: var(--text-2); }

/* Buttons */
.btn { display: inline-flex; align-items: center; gap: 8px; border: none; cursor: pointer;
  font-family: 'DM Sans', sans-serif; font-size: 14px; font-weight: 600;
  border-radius: var(--r); padding: 11px 20px; transition: all .18s ease; }
.btn-cta { background: var(--sun); color: #fff; }
.btn-cta:hover { background: var(--sun-hover); }
.btn-ghost { background: var(--surface); color: var(--text-3); border: 1px solid var(--border); font-weight: 500; }
.btn-ghost:hover { color: var(--text); border-color: var(--border-2); }
.btn:disabled { background: var(--border-2); cursor: not-allowed; color: #fff; }
.btn-row { display: flex; gap: 10px; margin-top: 20px; flex-wrap: wrap; align-items: center; }

/* Shell shared with the canvas's gated head */
.eyebrow { font-size: 11px; font-weight: 600; letter-spacing: 0.8px; text-transform: uppercase; color: var(--text-3); margin-bottom: 8px; }
.stage-title { font-family: 'Fraunces', serif; font-weight: 400; font-size: 24px; letter-spacing: -0.3px; color: var(--forest); margin-bottom: 6px; }
.lede { color: var(--text-2); font-size: 15px; max-width: 640px; margin-bottom: 22px; }
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); padding: 20px; }
.card + .card { margin-top: 14px; }
.card h3 { font-family: 'Fraunces', serif; font-weight: 400; font-size: 17px; color: var(--forest); margin-bottom: 10px; }

/* Map. 360px at every width. The boards draw 300px on a phone, but the
   Oct 6 outage card (imagery.js) stands 275px tall at 390 with the real
   fonts and must clear the credit line, so the phone map keeps the
   height the two-screen flow had (GOTCHAS, Oct 15 2026). */
.pinmap-wrap { position: relative; border-radius: var(--r); overflow: hidden; height: 360px; border: 1px solid var(--border);
  background: var(--surface-2); }
#pinMap { position: absolute; inset: 0; }
.pinmap-wrap.dropping #pinMap,
.pinmap-wrap.dropping .leaflet-container { cursor: crosshair; }
.map-hint { position: absolute; top: 12px; left: 50%; transform: translateX(-50%);
  background: var(--surface); border: 1px solid var(--border); border-radius: 999px;
  padding: 6px 14px; font-size: 12.5px; color: var(--text);
  display: none; max-width: calc(100% - 24px); text-align: center; z-index: 500; pointer-events: none; }
.pinmap-wrap.dropping .map-hint { display: block; }
/* The map area rests until a lookup answers, holds while one runs (or
   while the map library loads), and says so when the library will not
   load. Above Leaflet's panes and controls, so the live map shows only
   once the panel steps aside (data-state="map"). */
.map-rest { position: absolute; inset: 0; z-index: 1050; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 12px; padding: 20px; text-align: center;
  font-family: 'DM Sans', sans-serif; font-size: 13.5px; color: var(--text-2);
  background: var(--surface-2); }
@supports (color: color-mix(in oklch, red 50%, blue)) {
  .map-rest { background: color-mix(in oklch, var(--pool-light) 35%, var(--surface-2)); }
}
.pinmap-wrap[data-state="map"] .map-rest { display: none; }
.map-rest-retry { min-height: 40px; padding: 9px 16px; }
/* One keyframe for the holding and checking bars; frozen under reduced
   motion so the still is what renders. */
.map-rest-bar { width: 160px; height: 4px; border-radius: 2px; background: var(--border); overflow: hidden; position: relative; }
.map-rest-bar span { position: absolute; top: 0; bottom: 0; left: 0; width: 40%; border-radius: 2px;
  background: var(--pool-mid); animation: sp-holding 1.6s linear infinite; }
@keyframes sp-holding { 0% { transform: translateX(-100%); } 100% { transform: translateX(260%); } }
@media (prefers-reduced-motion: reduce) { .map-rest-bar span { animation: none; transform: translateX(75%); } }
/* A quiet caption when the ZIP has no map center on file or the centers
   did not load. Stacked above the attribution line, never beside it. */
.map-note { position: absolute; bottom: 44px; left: 12px; z-index: 500; max-width: calc(100% - 24px);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-pill);
  padding: 6px 12px; font-size: 12.5px; color: var(--text); font-family: 'DM Sans', sans-serif; }

/* The pin check (ruled Sep 29): the band reads before the confirm button. */
.matched-block { display: flex; flex-direction: column; gap: 12px; }
.check-band { display: flex; gap: 12px; align-items: flex-start; background: var(--pool-light);
  border-left: 3px solid var(--pool-mid); border-radius: var(--r-sm); padding: 10px 14px 10px 12px;
  font-family: 'DM Sans', sans-serif; font-size: 13px; line-height: 1.5; color: var(--pool-dark); text-wrap: pretty; }
.check-band svg { flex: none; margin-top: 1px; }
.find-card .btn-row { margin-top: 0; }
.drop-help { font-size: 12.5px; color: var(--text-3); font-family: 'DM Sans', sans-serif; }

/* The parcel check and its result share one grid cell, so the area is as
   tall as the found state from the moment the check starts and the
   continue button lands where the eye already is (S1a, the layout-shift
   note). The checking layer is the found state's height with one line
   and the holding bar. */
.result-area { display: grid; }
.result-area > * { grid-area: 1 / 1; }
.result-checking { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  background: var(--surface-2); border-radius: var(--r); padding: 20px; text-align: center;
  font-family: 'DM Sans', sans-serif; font-size: 13.5px; color: var(--text-2); }
.result-area[data-phase="checking"] .result-found { visibility: hidden; }
.result-area[data-phase="found"] .result-checking { visibility: hidden; }
.result-found .path-banner { margin-bottom: 12px; }

/* Geolocation status (manual pin mode). Informational, not an error:
   declining location is a valid choice, so it uses the pool family,
   never the urgent tokens. Shown via JS (display) plus .show for the
   appear transition. */
.geo-note { display: none; background: var(--pool-light);
  border-left: 3px solid var(--pool-mid); border-radius: var(--r-sm);
  padding: 9px 12px; font-size: 12.5px; color: var(--pool-dark);
  font-family: 'DM Sans', sans-serif;
  opacity: 0; transform: translateY(3px);
  transition: opacity .3s ease, transform .3s ease; }
.geo-note.show { opacity: 1; transform: none; }

/* Path banners */
.path-banner { border-radius: var(--r); padding: 16px 18px; display: flex; gap: 14px; align-items: flex-start; margin-bottom: 16px; }
.path-banner.assisted { background: var(--pool-light); border: 1px solid var(--teal-border); }
.path-banner.trace { background: var(--sun-light); border: 1px solid #EAC98A; }
.path-banner .t { font-weight: 600; font-size: 14.5px; color: var(--text); margin-bottom: 3px; }
.path-banner.assisted .t { color: var(--pool-dark); }
.path-banner.trace .t { color: var(--sun-dark); }
.path-banner .d { font-size: 13px; color: var(--text-2); }

/* UAT coverage gate (confirm screen). Inputs reuse .addr-input; the two
   additions are the light-surface error line (entry's .addr-error color is
   tuned for the dark hero panel) and the confirmation box, which follows
   the .geo-note recipe: informational, pool family, never the urgent
   tokens. */
.gate-error { margin-top: 8px; font-size: 12.5px; color: var(--sun-dark);
  font-family: 'DM Sans', sans-serif; font-weight: 600; }
.gate-done { background: var(--pool-light);
  border-left: 3px solid var(--pool-mid); border-radius: var(--r-sm);
  padding: 12px 14px; font-size: 13.5px; color: var(--pool-dark);
  font-family: 'DM Sans', sans-serif; }

/* Canvas screen (S1.2): nav 54 / strip 44 / map flex / sheet auto, one
   flex column filling the viewport below the sticky nav and the Step 1
   strip (the Sep 29 canvas pass; the strip joined Oct 16 2026). The map
   wrap takes whatever the sheet leaves, so the sheet is in the page
   flow and can never cover the pool, the attribution, or the header.
   The 98px is load-bearing exactly as the 54px was (GOTCHAS.md, Design,
   the single-row nav): the strip below pins to one row with no top
   padding so it is 44px at every width. dvh keeps phone browser chrome
   honest; the vh line is the fallback. */
.s1-canvas-shell .s1-strip-wrap { padding-top: 0; }
.s1-canvas-shell .s1-strip { flex-wrap: nowrap; height: 44px; }
.sp-canvas-main { max-width: none; padding: 0; display: flex; flex-direction: column;
  height: calc(100vh - 98px); height: calc(100dvh - 98px);
  /* The screen's fade-in starts 8 px low (sp-fadeIn), and a transform
     counts toward the page's scroll area: for its 0.35 s the page was
     8 px taller than the screen, a scrollbar flashed where the computer
     draws them, and the rail was sized 15 px short (Nov 3 2026). */
  overflow: hidden; }
/* The canvas is the whole page while drawing (D193). The column above
   fills the screen under the nav and the strip, and nothing is left
   below it to scroll to: the site footer goes while the drawing column
   shows (the ending, a readable page, keeps it, the column hidden
   then); the body's 100vh floor goes, since on a phone's browser 100vh
   is the screen with its toolbars away, taller than the 100dvh column;
   the page neither bounces nor refreshes on a pull; and the sheet's
   scroll stays in the sheet. */
body:has(.sp-canvas-main:not([hidden])) { min-height: 0; }
body:has(.sp-canvas-main:not([hidden])) > .footer { display: none; }
html:has(.sp-canvas-main:not([hidden])) { overscroll-behavior: none; }
/* The in-page heading renders only in gated mode: on the map screen the
   nav and the strip are the whole header and the title lives in the
   empty sheet (pool placement spec, prototype audit). */
.sp-canvas-main .canvas-head { display: none; }
.canvas-head { padding: 14px 20px 12px; }
.canvas-head .stage-title { font-size: 20px; margin-bottom: 0; }
/* Chained with .sp-screen.active: the flow's base rule sets
   display:block at two-class specificity, which would silently collapse
   this flex column (same class of trap as the hero-panel modifier entry
   in GOTCHAS.md). */
.sp-canvas-screen.sp-screen.active { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.canvas-map-wrap { position: relative; flex: 1 1 auto; min-height: 0;
  border-top: 1px solid var(--border); }
#canvasMap { position: absolute; inset: 0; background: var(--surface-2); }

/* The two columns of the canvas page (S1g): the drawing's fixed-height
   column and the ending's readable column trade places; hidden on
   either must beat the column's own display. */
.sp-canvas-main[hidden], .sp-done-main[hidden] { display: none !important; }

/* ── The footer (S1g, boards 8 and 9) ───────────────────────────────
   Finish the site plan as the screen's one fill, under the panels in
   the sheet and the rail alike; the working state swaps the label and
   runs the hairline along the button's foot. */
.sp-foot { flex: 0 0 auto; padding: 12px 16px 14px; border-top: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 8px; background: var(--surface); }
.sp-foot[hidden] { display: none; }
.sp-finish { position: relative; overflow: hidden; width: 100%; min-height: 48px; justify-content: center;
  font-size: 14px; }
.sp-finish[aria-busy="true"] { cursor: default; }
.sp-finish[aria-busy="true"]:hover { background: var(--sun); }
.sp-finish-track { position: absolute; left: 0; bottom: 0; width: 100%; height: 3px;
  background: rgba(255,255,255,.3); overflow: hidden; }
.sp-finish-track[hidden] { display: none; }
.sp-finish-bar { position: absolute; left: 0; bottom: 0; width: 38%; height: 3px;
  background: var(--sun-dark); animation: sp-holding 1.6s ease-in-out infinite; }
.sp-foot-line { font-size: 12.5px; line-height: 1.5; color: var(--text-2); }
.sp-foot-line:empty { display: none; }
/* While the file renders the drawing holds still: the sections and the
   pool's handles take no input, the tabs and the map's pan still do. */
.sp-house.is-finishing .sp-panels { pointer-events: none; opacity: .55; }
.is-finishing .leaflet-interactive, .is-finishing .leaflet-marker-icon { pointer-events: none !important; }

/* ── The ending (S1.3, D81; board 7) ─────────────────────────────── */
.sp-done-main { padding-top: 26px; }
.done-stack { display: flex; flex-direction: column; gap: 16px; }
.done-ready { display: flex; gap: 20px; flex-wrap: wrap; align-items: flex-start; }
.done-preview { flex: 0 0 164px; width: 164px; height: 212px; border: 1px solid var(--border-2);
  border-radius: 3px; background: var(--surface); overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,.08); }
.done-preview img { display: block; width: 100%; height: 100%; object-fit: cover; }
.done-text { flex: 1 1 180px; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.done-where { display: flex; flex-direction: column; }
.done-address { font-size: 15px; font-weight: 600; color: var(--text); }
.done-place { font-size: 13px; color: var(--text-2); }
.done-artifact { font-size: 13.5px; line-height: 1.5; color: var(--text-2); text-wrap: pretty; }
.done-actions { display: flex; gap: 10px 14px; flex-wrap: wrap; align-items: center; padding-top: 4px; }
.done-download { display: inline-flex; align-items: center; min-height: 44px; font-size: 13px; font-weight: 600;
  color: var(--pool-dark); text-decoration: underline; text-decoration-color: var(--teal-border);
  text-underline-offset: 3px; cursor: pointer; }
.done-download:hover { text-decoration-color: var(--pool); }
.done-adjust { display: inline-flex; align-items: center; min-height: 44px; background: none; border: none;
  padding: 0; font-family: 'DM Sans', sans-serif; font-size: 13px; font-weight: 500; color: var(--text-2);
  cursor: pointer; }
.done-adjust:hover { color: var(--pool); }
.done-attach { font-size: 12.5px; line-height: 1.5; color: var(--text-3); margin-top: -6px; }
.done-failed[hidden] { display: none; }
.done-status { font-size: 13px; line-height: 1.5; color: var(--text-2); margin-top: -4px; }
.done-status:empty { display: none; }
.done-failed-body { font-size: 14px; line-height: 1.6; color: var(--text-2); margin: 0 0 14px; }
.done-band { display: flex; align-items: center; gap: 12px; background: var(--pool-light);
  border-left: 3px solid var(--pool-mid); border-radius: var(--r-sm); padding: 10px 12px 10px 14px; }
.done-band[hidden] { display: none; }
.done-band-text { flex: 1 1 auto; min-width: 0; font-size: 13px; line-height: 1.5; color: var(--pool-dark); text-wrap: pretty; }
.done-band-actions { flex: none; display: flex; align-items: center; }
.done-band-x { flex: none; width: 44px; height: 44px; background: none; border: none; color: var(--pool-dark);
  font-size: 18px; line-height: 1; cursor: pointer; border-radius: var(--r-sm); }
.done-band-x:hover { background: rgba(11,123,138,.10); }
.done-next { display: flex; flex-direction: column; gap: 10px; padding-top: 4px; }
.done-step2 { min-height: 48px; padding: 12px 22px; font-size: 14.5px; text-decoration: none; }
.done-next-line { font-size: 13px; line-height: 1.5; color: var(--text-2); }
@media (max-width: 767px) {
  /* The first page stays beside the text at phone widths (board 7,
     done-390): the text column takes what the 112px preview leaves. */
  .done-ready { flex-wrap: nowrap; gap: 14px; }
  .done-preview { flex-basis: 112px; width: 112px; height: 145px; }
  .done-text { flex-basis: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .sp-finish-bar { animation: none; transform: none; }
}

/* Gate mode: the defensive degrade card replaces the map, and the page
   returns to the flow's normal readable column. */
.sp-canvas-main.gated { display: block; height: auto; max-width: 1040px;
  margin: 0 auto; padding: 26px 20px 60px; }
.sp-canvas-main.gated .sp-canvas-screen.sp-screen.active { display: block; }
.sp-canvas-main.gated .canvas-head { display: block; padding: 0 0 4px; }
.sp-canvas-main.gated .canvas-head .stage-title { font-size: 24px; margin-bottom: 18px; }
.sp-canvas-main.gated .pool-sheet { display: none; }

/* ── Pool control sheet ─────────────────────────────────────────────
   Since S1c-2 the Pools panel of the canvas housing (.sp-house, below):
   in-flow at phone widths (height from content, animated by JS between
   state swaps, scrolled by the housing under its cap); inside the 352px
   rail at ≥768px. The housing carries the chrome (white, --border-2 top
   edge, 14px top radius); the panel keeps the 16px side padding, 8px
   row gaps and 44px controls of the spec. */
/* iOS Safari: quick successive taps on a control (stepper −/+ taps
   especially) match the browser's double-tap page-zoom heuristic and
   zoom the viewport instead of registering the second tap.
   touch-action: manipulation keeps taps taps on every sheet control
   and on the flow's buttons (confirm screen included: same issue
   class). Scoped to controls only: the map container keeps Leaflet's
   own touch-action, so pinch zoom on the map is untouched, and the
   viewport meta stays user-scalable for accessibility. */
.pool-sheet,
.pool-sheet button,
.pool-sheet input,
.sp-house button,
.sp-house input,
.sb-strip button,
.sp-main .btn {
  touch-action: manipulation;
}

.pool-sheet { flex: 0 0 auto; background: var(--surface);
  overflow: hidden; }
.pool-sheet.animating { transition: height .22s ease; }
@media (prefers-reduced-motion: reduce) {
  .pool-sheet.animating { transition: none; }
}
.pool-sheet-inner { padding: 14px 16px 12px; display: flex;
  flex-direction: column; }
.pool-state { display: flex; flex-direction: column; gap: 8px; }

.pool-body { font-family: 'DM Sans', sans-serif; font-size: 13px;
  color: var(--text-2); margin: 0; line-height: 1.45; }
.pool-cta-row { display: flex; gap: 8px; align-items: stretch; }
.pool-cta { flex: 1 1 auto; height: 48px; }
/* The first visit (D171): Your pool's heading as the rows' group has
   it, the line, and the six shapes as tiles, three across; a tap places
   the pool in that shape. Under them Custom's line, and after a removal
   "Pool removed" with Undo. */
.pool-empty-h { padding-bottom: 0; }
.pool-place-shapes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
.pool-place-tile { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  min-height: 60px; padding: 8px 4px; font-family: 'DM Sans', sans-serif; font-size: 12.5px; font-weight: 500;
  color: var(--text); background: var(--surface); border: 1px solid var(--border-2); border-radius: var(--r-sm);
  cursor: pointer; }
.pool-place-tile:hover { border-color: var(--pool); }
.pool-place-tile svg { width: 34px; height: 20px; fill: none; stroke: var(--pool-dark); stroke-width: 1.5; stroke-linejoin: round; }
.pool-place-name { line-height: 1.2; text-align: center; }
.pool-place-hint { margin: 0; }
.pool-undo-row { align-items: center; justify-content: space-between; }
.pool-undo-row[hidden] { display: none; }
.pool-undo-line { font-family: 'DM Sans', sans-serif; font-size: 13px; color: var(--text-2); }

.pool-btn-ghost, .pool-btn-outline { font-family: 'DM Sans', sans-serif;
  font-weight: 600; font-size: 13px; height: 44px; padding: 0 16px;
  border-radius: var(--r-pill); cursor: pointer; }
.pool-btn-ghost { background: transparent; border: none;
  color: var(--text-2); }
.pool-btn-ghost:hover { color: var(--text); }
.pool-btn-outline { background: var(--pool-light);
  color: var(--pool-dark); border: 1.5px solid var(--pool); }
.pool-btn-outline:hover { background: var(--pool); color: #fff; }

.pool-edit-head { display: flex; align-items: center;
  justify-content: space-between; min-height: 44px; }
.pool-state-label { font-family: 'DM Sans', sans-serif; font-weight: 600;
  font-size: 14px; color: var(--pool-dark); }
.pool-state-label.warning { color: var(--urgent-text); }
.pool-edit-actions { display: flex; gap: 4px; }
.pool-hint { font-family: 'DM Sans', sans-serif; font-size: 12.5px;
  color: var(--text-3); }
/* The arrow keys, said where there is a keyboard to press them (D135):
   a mouse or a trackpad, never a phone. Under Angle, led by its label
   in the label colour (D153). */
.pool-hint--keys { display: none; }
@media (hover: hover) and (pointer: fine) { .pool-hint--keys { display: block; } }
.pool-hint-tip { font-weight: 600; color: var(--pool-dark); }

.pool-row-label { font-family: 'DM Sans', sans-serif; font-size: 11px;
  font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-3); line-height: 1; }
/* The spec's editing-height budget (≈244px: header row, presets row,
   steppers row, angle label line + track) has no separate label lines
   for Size / Width / Length, so those labels are screen-reader only.
   The angle label keeps its visible line, which the budget includes. */
.pool-label-sr { position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.pool-presets { display: flex; gap: 6px; }
.pool-preset-chip { flex: 1 1 0; height: 44px;
  font-family: 'DM Mono', monospace; font-size: 13px;
  color: var(--text-2); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  cursor: pointer; padding: 0; }
.pool-preset-chip.active { background: var(--pool-light);
  border-color: var(--pool); color: var(--pool-dark); }

/* The value box takes the row's room (68 px in the 352 px rail, more on
   a phone): at the pool spec's fixed 56 px, "W 16 ft" in DM Mono ran
   into the box's lines (Oct 24 2026). 13 px matches the size chips. */
.pool-steppers { display: flex; gap: 8px; }
.pool-stepper { flex: 1 1 0; min-width: 0; }
.pool-stepper-controls { display: flex; }
.pool-step-btn { width: 44px; height: 44px; font-size: 18px;
  font-family: 'DM Sans', sans-serif; color: var(--pool-dark);
  background: var(--surface); border: 1px solid var(--border);
  cursor: pointer; }
.pool-step-btn:first-child { border-radius: var(--r-sm) 0 0 var(--r-sm); }
.pool-stepper-controls .pool-step-btn:last-child {
  border-radius: 0 var(--r-sm) var(--r-sm) 0; }
.pool-step-value { flex: 1 1 auto; width: 0; min-width: 64px; height: 44px; text-align: center;
  font-family: 'DM Mono', monospace; font-size: 13px; color: var(--text);
  border: 1px solid var(--border); border-left: none; border-right: none;
  border-radius: 0; background: var(--surface); padding: 0 6px; box-sizing: border-box; }
.pool-step-btn { flex: none; }
.pool-step-value:focus { outline: 2px solid var(--pool); outline-offset: -2px; }
.pool-range-helper { font-family: 'DM Sans', sans-serif; font-size: 11px;
  color: var(--text-3); margin-top: 4px; }

.pool-angle-head { display: flex; align-items: baseline;
  justify-content: space-between; }
.pool-angle-readout { font-family: 'DM Sans', sans-serif; font-size: 12.5px;
  color: var(--text-2); }
.pool-angle-track { position: relative; height: 44px; }
.pool-angle-track input[type="range"] { width: 100%; height: 44px;
  margin: 0; accent-color: var(--pool); position: relative; z-index: 1; }
.pool-angle-ticks { position: absolute; inset: 0; pointer-events: none; }
.pool-angle-tick { position: absolute; top: 8px; bottom: 8px; width: 2px;
  margin-left: -1px; background: var(--teal-border); }

/* Every part of the pool a row (D169): no row wraps the pool. The tab
   reads as two groups, Your pool and Around the pool, their headings
   alike (a small label in capitals). Each row's heading opens it in
   place (D165): the chevron, the name, and while closed its value at
   the right (one short fact, the quiet colour while nothing is set).
   One row open on the tab at a time, and only it is outlined: a card
   that reaches 8 px into the sheet's sides so the widest block inside it
   (Around the pool's four steppers, D134) keeps its width. */
.pool-group { display: flex; flex-direction: column; }
.pool-group-h, .yd-group-h { margin: 0; font-family: 'DM Sans', sans-serif; font-weight: 600;
  font-size: 11px; letter-spacing: .05em; text-transform: uppercase; color: var(--text-2);
  line-height: 16px; padding: 4px 0 8px; }
.pool-group-h .pool-state-label { font: inherit; color: inherit; }
.pool-group-h .pool-state-label.warning { color: var(--urgent-text); }
/* The other pool of a plan saved with two (D166): its heading a button. */
.pool-group-head { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 44px;
  padding: 0; background: none; border: 0; cursor: pointer; text-align: left; font: inherit; color: inherit; }
.pool-summary { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pool-other { border-bottom: 1px solid var(--border); margin-bottom: 8px; }
.pool-prows { display: flex; flex-direction: column; border-bottom: 1px solid var(--border); }
.pool-prow { display: flex; flex-direction: column; border-top: 1px solid var(--border); }
.pool-prow.is-open { gap: 8px; margin: 4px -8px; padding: 0 8px 8px; border: 1.5px solid var(--pool);
  border-radius: var(--r); background: var(--surface); }
.pool-prow.is-open + .pool-prow { border-top: 0; }
.pool-prow-h { margin: 0; font: inherit; flex: 1 1 auto; min-width: 0; }
.pool-prow-head { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 48px;
  padding: 4px 0; background: none; border: 0; cursor: pointer; text-align: left;
  font-family: 'DM Sans', sans-serif; color: inherit; }
/* A row's heading under the keyboard: the tabs' outline, inside the
   heading so the rail's edge never clips it (the browser's own was a
   heavy black box, Nov 3 2026). */
.pool-prow-head:focus-visible, .yd-row-head:focus-visible { outline: 2px solid var(--pool); outline-offset: -2px; border-radius: var(--r-sm); }
.pool-row-chev { flex: none; color: var(--pool-dark); transition: transform .15s ease; }
.pool-prow-head[aria-expanded="true"] .pool-row-chev { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) { .pool-row-chev { transition: none; } }
.pool-prow-name { flex: none; font-weight: 600; font-size: 14px; color: var(--pool-dark); }
.pool-prow-sum { margin-left: auto; min-width: 0; font-size: 13px; color: var(--text);
  text-align: right; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pool-prow-sum.is-unset { color: var(--text-3); }
.pool-prow-sum[hidden] { display: none; }
.pool-prow-body { display: flex; flex-direction: column; gap: 14px; }
.pool-prow-body[hidden], .pool-shape-main[hidden] { display: none; }
.pool-shape-main { display: flex; flex-direction: column; gap: 8px; }
.pool-btn-remove { align-self: flex-start; height: 44px; padding: 0; background: none; border: 0;
  font-family: 'DM Sans', sans-serif; font-weight: 600; font-size: 13px; color: var(--text-2);
  text-decoration: underline; text-decoration-color: var(--border-2); text-underline-offset: 3px; cursor: pointer; }
.pool-btn-remove:hover { color: var(--text); text-decoration-color: currentColor; }
/* Remove on the Your pool heading's line, at the right (Oct 30 2026). */
.pool-group-headrow { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.pool-group-headrow .pool-group-h { padding-bottom: 4px; }
.pool-btn-remove--head { align-self: center; flex: none; font-size: 12.5px; }

/* S1f (D98, handoff.md item 3). The editing state's pieces stack with
   the state's 8px gap; [hidden] needs saying again, since each sets its
   own display. */
.pool-edit, .pool-box, .pool-draw, .pool-shape { display: flex;
  flex-direction: column; gap: 8px; }
.pool-edit[hidden], .pool-box[hidden], .pool-draw[hidden],
.pool-corner-line[hidden] { display: none; }
/* The shape row: five chips at the presets' construction, each a
   30 × 18 icon stroked 1.6 in currentColor. */
/* Six chips since the L (D145): each at least 44 px wide, so six still
   share one row in the rail and on a phone; narrower than that they
   wrap (Colin, Oct 27 2026: "let them wrap"). */
.pool-shapes { display: flex; flex-wrap: wrap; gap: 6px; }
.pool-shape-chip { flex: 1 1 44px; height: 44px; display: flex;
  align-items: center; justify-content: center; padding: 0;
  color: var(--text-2); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  cursor: pointer; }
.pool-shape-chip.active { background: var(--pool-light);
  border-color: var(--pool); color: var(--pool-dark); }
.pool-shape-chip svg { width: 30px; height: 18px; fill: none;
  stroke: currentColor; stroke-width: 1.6; stroke-linejoin: round; }
.pool-corner-line { font-family: 'DM Sans', sans-serif; font-size: 13px;
  color: var(--text); line-height: 1.45; margin: 0; }
/* Pool features (D130, named so since D154): the section under Angle, a
   rule above it; each row's chips at the presets' construction in DM
   Sans (12.5 px so four fit the 302 px the rail and a 360 phone leave).
   Depth is the next section (D154), the same rule above it: its two
   steppers with static values, a quiet dash in each until the first
   tap, and the deep end's words with Swap ends. */
/* The rows' bodies (D169, the folds of D158 before): the controls
   under the heading while the row is open. */
.pool-details-line { font-family: 'DM Sans', sans-serif; font-size: 12.5px;
  color: var(--text-3); line-height: 1.45; margin: 0; }
.pool-detail { display: flex; flex-direction: column; gap: 8px; }
.pool-detail-chips { display: flex; gap: 6px; }
.pool-detail-chip { flex: 1 1 0; min-width: 0; height: 44px; padding: 0 2px;
  font-family: 'DM Sans', sans-serif; font-size: 12.5px; font-weight: 500;
  color: var(--text-2); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  cursor: pointer; white-space: nowrap; overflow: hidden; }
.pool-detail-chip.active { background: var(--pool-light);
  border-color: var(--pool); color: var(--pool-dark); font-weight: 600; }
.pool-detail-note { font-family: 'DM Sans', sans-serif; font-size: 12.5px;
  color: var(--text-2); line-height: 1.45; margin: 0; }
.pool-detail-note[hidden] { display: none; }
.pool-depth-right { display: inline-flex; align-items: baseline; gap: 12px; }
.pool-btn-link { background: none; border: none; padding: 0;
  font-family: 'DM Sans', sans-serif; font-weight: 600; font-size: 12.5px;
  color: var(--pool-dark); text-decoration: underline; cursor: pointer;
  line-height: 1.2; }
.pool-btn-link[hidden] { display: none; }
.pool-depth-steppers.is-unset .pool-step-value { color: var(--text-3); }
/* Unsure (D177): each end's label tagged Typical while the pair shown is
   the typical one; Keep these and its line under the steppers; Back to
   unsure at the Depth row's foot once a depth is set. */
.pool-depth-tag { display: none; margin-left: 6px; padding: 2px 6px; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--text-2); font-size: 10px; letter-spacing: .04em; vertical-align: 1px; }
.pool-depth-steppers.is-unset .pool-depth-tag { display: inline-block; }
.pool-depth-unsure { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.pool-depth-unsure[hidden], .pool-depth-clear[hidden] { display: none; }
.pool-depth-keep { height: 40px; padding: 0 14px; font-family: 'DM Sans', sans-serif; font-size: 13px; font-weight: 600;
  color: var(--text); background: var(--surface); border: 1px solid var(--border-2); border-radius: var(--r-sm); cursor: pointer; }
.pool-depth-keep:hover { border-color: var(--pool); color: var(--pool-dark); }
.pool-depth-typical-note { margin: 0; line-height: 1.45; }
.pool-depth-clear { align-self: flex-start; text-decoration: underline; text-underline-offset: 3px; }
/* The typical pair's floor (D177): the run quiet, the section's lines
   dashed and its words in the quiet colour. */
.pool-run-row.is-unset .pool-step-value { color: var(--text-3); }
.pool-section-depth.quiet, .pool-section-label.quiet { fill: var(--text-3); }
/* D159: the deep end past what the pool's length holds, its warning and
   the two fixes; the deep end's + at the length's limit. */
.pool-step-value.is-over { color: var(--urgent-text); }
.pool-over { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px;
  background: var(--urgent-bg); border: 1px solid var(--urgent-border); border-radius: var(--r-sm); }
.pool-over[hidden] { display: none; }
.pool-over-text { margin: 0; font-family: 'DM Sans', sans-serif; font-size: 12.5px; line-height: 1.45; color: var(--urgent-text); }
.pool-over-fixes { display: flex; flex-direction: column; gap: 6px; }
.pool-over-fix { width: 100%; background: var(--surface); }
.pool-over-fix[hidden] { display: none; }
.pool-step-btn.at-limit { color: var(--text-3); }
.pool-depth-steppers[hidden], .pool-deep-end[hidden] { display: none; }
/* The ends line's place (D139 (6)): under the depth's steppers once the
   deep end is marked; it stands down with the line, so the block's gap
   is not spent on an empty slot. */
.pool-depth-end-slot[hidden] { display: none; }
/* A custom shape's walls (D147): the shallow wall's line, the rows that
   ask for a tap on the photo while a wall is picked, and the section's
   caption along the water. */
.pool-steps-wall[hidden], .pool-pick-row[hidden], .pool-section-note[hidden] { display: none; }
.pool-pick-row { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: 44px; padding: 0 10px; margin: 0 -10px; background: var(--pool-light); border-radius: var(--r-sm); }
.pool-pick-words { font-family: 'DM Sans', sans-serif; font-size: 13px; font-weight: 600; color: var(--pool-dark); line-height: 1.3; }
.pool-section-note { font-family: 'DM Mono', monospace; font-size: 10px; line-height: 1.4; color: var(--text-3); margin: 0; }
.sp-picking .sp-pool-shape { cursor: default; }
/* The size steppers' 8 px between the two ends: at 16 the deep end's +
   ran 1.5 px past the open row's edge in the rail, and "10.5 ft" was
   tight in its box (Nov 3 2026). */
.pool-depth-steppers { gap: 8px; }
.pool-depth-end { margin-bottom: 6px; }
.pool-step-static { display: flex; align-items: center; justify-content: center; }
.pool-deep-end { display: flex; align-items: center; justify-content: space-between;
  gap: 12px; min-height: 44px; }
.pool-deep-words { font-family: 'DM Sans', sans-serif; font-size: 13px;
  color: var(--text-2); line-height: 1.3; }
/* The floor (D139): the Shallow floor row (the words, a whole-foot
   stepper, "then slopes"), a stepper button at its limit greyed but
   still a target, the section 76px tall at the row's width, and a chip
   that cannot be taken greyed. */
.pool-run-row { display: flex; align-items: center; gap: 8px; }
.pool-run-row[hidden], .pool-section[hidden] { display: none; }
.pool-run-words { font-family: 'DM Sans', sans-serif; font-size: 13px;
  color: var(--text-2); line-height: 1.3; white-space: nowrap; }
.pool-step-btn.at-limit { color: var(--text-3); background: var(--surface-2); cursor: default; }
.pool-section { display: block; }
.pool-section svg { display: block; }
.pool-section-depth { font-family: 'DM Mono', monospace; font-size: 10px; fill: var(--pool-dark); }
.pool-section-depth.deep { fill: var(--surface); }
.pool-section-label { font-family: 'DM Mono', monospace; font-size: 10px; fill: var(--text-2); }
.pool-detail-chip.is-off { color: var(--text-3); background: var(--surface-2); cursor: default; }
/* A pool's row when deselected: the answers in words under its name,
   the undecided line quieter. */
.pool-row-detail { font-family: 'DM Sans', sans-serif; font-size: 12.5px;
  color: var(--text-2); line-height: 18px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.pool-row-detail.undecided { color: var(--text-3); }
.pool-summary-wrap { min-width: 0; }
/* The drawing instrument's body: the readout between two rules, Close
   the shape as the fill, Undo last corner as a text control. */
.pool-draw-tap { color: var(--text); }
.pool-draw-readout { display: flex; align-items: center; min-height: 44px;
  font-family: 'DM Mono', monospace; font-size: 13px; color: var(--text);
  border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.pool-draw .pool-cta { width: 100%; }
.pool-draw .pool-cta:disabled { opacity: .45; cursor: default; }
.pool-btn-text { height: 44px; background: none; border: none; padding: 0;
  font-family: 'DM Sans', sans-serif; font-weight: 600; font-size: 13px;
  color: var(--pool-dark); cursor: pointer; }
.pool-btn-text:disabled { color: var(--text-3); cursor: default; }
/* The L's second leg (D145): its row under the main leg's steppers,
   the two moves side by side; "Main leg" names the box when it is one. */
.pool-leg { display: flex; flex-direction: column; gap: 8px; padding-top: 10px; border-top: 1px solid var(--border); }
.pool-leg-label { color: var(--pool-dark); }
.pool-leg-moves { display: flex; gap: 18px; }
/* Where the leg goes (D160): four small L's, north up, the pressed one
   as a pressed shape chip. */
.pool-leg-pick { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
.pool-leg-at { height: 60px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-sm); cursor: pointer;
  font-family: 'DM Sans', sans-serif; font-size: 11px; font-weight: 600; color: var(--text-2); }
.pool-leg-at svg { display: block; color: currentColor; }
.pool-leg-at.active { background: var(--pool-light); border-color: var(--pool); color: var(--pool-dark); }
/* A row per pool (two or more, and the deselected list): the name and
   size with Adjust, a 1px rule between rows and above what follows. */
.pool-rows { display: flex; flex-direction: column; }
.pool-rows:empty { display: none; }
.pool-row { border-bottom: 1px solid var(--border); padding-bottom: 8px; }
.pool-rows + .pool-row, .pool-row + .pool-row { padding-top: 8px; }
.pool-rows--after .pool-row { border-bottom: none; border-top: 1px solid var(--border);
  padding-top: 8px; padding-bottom: 0; }
.pool-add-row { display: flex; align-items: center; justify-content: space-between; }
.pool-add { display: inline-flex; align-items: center; gap: 8px; height: 44px;
  padding: 0; background: none; border: none; cursor: pointer;
  font-family: 'DM Sans', sans-serif; font-weight: 600; font-size: 13px;
  color: var(--pool-dark); }
.pool-add svg { width: 14px; height: 14px; fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; }

/* ── The canvas housing (S1c-2) ─────────────────────────────────────
   Phone: the tabbed bottom sheet, in flow under the map and the chip
   strip; max-height set by canvas-sheet.js (440px, or what leaves the
   map 302px); the tab row stays, the panels scroll. Desktop (≥768px):
   the 352px rail beside the map, full height, no strip. The street-side
   gate replaces the tabs until the street side is confirmed. */
.sp-house { flex: 0 0 auto; display: flex; flex-direction: column;
  min-height: 0; min-width: 0; background: var(--surface);
  border-top: 1px solid var(--border-2);
  /* No negative-margin overlap: the sheet stays fully in flow so it
     never covers the map's bottom edge, where the attribution sits. */
  border-radius: 14px 14px 0 0; overflow: hidden; }
.sp-house[hidden] { display: none; }
.sp-tabs { flex: none; display: flex; gap: 8px; padding: 0 12px;
  border-bottom: 1px solid var(--border); overflow-x: auto;
  scrollbar-width: none; min-width: 0; }
.sp-tabs::-webkit-scrollbar { display: none; }
.sp-tabs[hidden] { display: none; }
.sp-tab { height: 44px; padding: 0 2px; background: none; border: none;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  font-family: 'DM Sans', sans-serif; font-size: 12px; font-weight: 600;
  color: var(--text-2); white-space: nowrap; cursor: pointer;
  display: inline-flex; align-items: center; gap: 5px; }
.sp-tab:hover { color: var(--pool-dark); }
.sp-tab.is-active { color: var(--pool-dark); border-bottom-color: var(--pool); }
.sp-tab:focus-visible { outline: 2px solid var(--pool); outline-offset: -2px; }
.sp-tab-count { font-family: 'DM Mono', monospace; font-size: 11px;
  font-weight: 400; color: var(--text-3); }
.sp-tab-count:empty { display: none; }
.sp-tab-dot { width: 7px; height: 7px; border-radius: 50%; }
.sp-tab-dot[hidden] { display: none; }
.sp-tab-dot--priority { background: var(--sun); }
.sp-tab-dot--urgent { background: var(--urgent-text); }
/* The imagery read running (S1e): a --pool-mid dot after "Structures",
   pulsing, still under reduced motion. */
.sp-tab-dot--reading { background: var(--pool-mid); animation: sb-pulse 1.4s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .sp-tab-dot--reading { animation: none; } }
.sp-panels { flex: 1 1 auto; min-height: 0; overflow: auto;
  -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }
.sp-panels[hidden] { display: none; }
.sp-panel[hidden] { display: none; }
.sp-gate { flex: 1 1 auto; min-height: 0; overflow: auto; overscroll-behavior: contain;
  padding: 18px 16px 16px; display: flex; flex-direction: column; gap: 12px; }
.sp-gate[hidden] { display: none; }

@media (min-width: 768px) {
  .sp-canvas-screen.sp-screen.active { flex-direction: row; }
  .canvas-map-wrap { border-top: none; }
  /* The rail's width for its rows, --sp-rail (D194: 352 px up to 500,
     the width the lot does not need, site-plan-canvas.js), whatever
     the computer's scrollbars (Nov 3 2026, GOTCHAS): --sp-sbw is the
     bar's width where the system draws
     one that takes room (site-plan-canvas.js measures it, 0 where bars
     float over the content, and sets .sp-bars where it is not 0), and
     the gutter keeps that room whether or not the panels scroll, so a
     row opening past the rail's height never reflows the rest. */
  .sp-house { flex: 0 0 calc(var(--sp-rail, 352px) + var(--sp-sbw, 0px)); width: calc(var(--sp-rail, 352px) + var(--sp-sbw, 0px)); border-top: none;
    border-left: 1px solid var(--border); border-radius: 0;
    max-height: none !important; }
  .sp-bars .sp-panels, .sp-bars .sp-gate { scrollbar-gutter: stable; }
  .sp-tabs { gap: 6px; padding: 0 8px; }
  .sp-tab { font-size: 11px; }
  .sb-strip { display: none !important; }
}

/* ── The pinned chip strip (phone) ─────────────────────────────────
   48px, 40px pills, scrolls sideways, order over the line, shortfalls,
   prompts, the rest. */
.sb-strip { flex: none; display: flex; gap: 6px; padding: 4px 12px;
  background: var(--surface); border-top: 1px solid var(--border);
  overflow-x: auto; scrollbar-width: none; min-height: 48px; box-sizing: border-box; }
.sb-strip::-webkit-scrollbar { display: none; }
.sb-strip[hidden] { display: none; }
.sb-chip { flex: none; display: inline-flex; align-items: center; gap: 6px;
  height: 40px; padding: 0 12px; border-radius: var(--r-pill);
  border: 1px solid var(--border); background: var(--surface);
  color: var(--text-2); font-family: 'DM Sans', sans-serif;
  font-size: 12px; font-weight: 600; white-space: nowrap; cursor: pointer; }
.sb-chip-dist { font-family: 'DM Mono', monospace; font-size: 13px;
  font-weight: 400; color: var(--pool-dark); }
.sb-chip-seg { font-size: 10.5px; padding: 1px 6px; }
.sb-chip-tail { font-weight: 500; }
.sb-chip--priority { border-color: var(--priority-text);
  background: var(--priority-bg); color: var(--priority-text); }
.sb-chip--priority .sb-chip-dist { color: var(--priority-text); }
.sb-chip--urgent { border-color: var(--urgent-text);
  background: var(--urgent-bg); color: var(--urgent-text); }
.sb-chip--prompt { gap: 8px; border: 1.5px solid var(--pool);
  background: var(--pool-light); color: var(--pool-dark); }
.sb-chip-link { color: var(--pool); text-decoration: underline;
  text-underline-offset: 2px; }

/* ── Provenance frames: solid (checked), dashed (unverified), hatched
   (entered or chosen by the homeowner). Readable with color removed:
   the frames differ by line, not hue. */
.sb-frame { font-family: 'DM Mono', monospace; font-size: 11px;
  color: var(--text-2); padding: 2px 7px; border-radius: var(--r-pill);
  border: 1px solid var(--border-2); background: var(--surface-2);
  white-space: nowrap; }
.sb-frame--dashed { border-style: dashed; border-color: var(--text-3);
  background: var(--surface); }
/* No frame: "none set" beside the distance to the house, the words
   alone (the Oct 18 house rows). */
.sb-frame--none { border: none; background: none; padding: 0; color: var(--text-3); }
.sb-frame--hatched { background-color: var(--surface);
  background-image: repeating-linear-gradient(135deg,
    color-mix(in srgb, var(--border-2) 45%, transparent) 0 1px, transparent 1px 5px); }

/* ── Sections ──────────────────────────────────────────────────────── */
.sb-section { display: flex; flex-direction: column; gap: 10px;
  padding: 12px 16px 14px; font-family: 'DM Sans', sans-serif; }
.sb-eyebrow { font-size: 11px; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-3); }
.sb-line { font-size: 13px; line-height: 1.45; color: var(--text-2);
  margin: 0; text-wrap: pretty; }
.sb-hint { font-size: 12px; line-height: 1.45; color: var(--text-3);
  margin: 0; text-wrap: pretty; }
.sb-footer { font-size: 11.5px; line-height: 1.45; color: var(--text-3);
  margin: 0; text-wrap: pretty; }
.sb-mono { font-family: 'DM Mono', monospace; color: var(--text); }
.sb-link { background: none; border: none; padding: 0; cursor: pointer;
  font: inherit; color: var(--pool-dark); text-decoration: underline;
  text-decoration-color: var(--teal-border); text-underline-offset: 2px; }
.sb-link:hover { text-decoration-color: var(--pool); }
.sb-link--big { font-size: 12.5px; font-weight: 600; min-height: 32px;
  text-underline-offset: 3px; }
.sb-section a { color: var(--pool-dark); text-decoration: underline;
  text-decoration-color: var(--teal-border); text-underline-offset: 2px; }
.sb-section a:hover { text-decoration-color: var(--pool); }
.sb-actions { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.sb-cta { height: 48px; font-size: 14px; }
.sb-btn-ghost { font-family: 'DM Sans', sans-serif; font-weight: 600;
  font-size: 13px; height: 44px; padding: 0 14px; border-radius: var(--r-pill);
  background: transparent; border: none; color: var(--pool-dark); cursor: pointer; }
.sb-btn-ghost:hover { background: var(--pool-light); }
.sb-btn-outline { font-family: 'DM Sans', sans-serif; font-weight: 600;
  font-size: 13px; height: 44px; padding: 0 16px; border-radius: var(--r-pill);
  background: var(--pool-light); color: var(--pool-dark);
  border: 1.5px solid var(--pool); cursor: pointer; }
.sb-btn-outline:hover { background: var(--pool); color: var(--white); }
.sb-btn-outline:disabled, .sb-cta:disabled { background: var(--border-2);
  border-color: var(--border-2); color: var(--white); cursor: default; }
.sb-pill-change { flex: none; font-family: 'DM Sans', sans-serif; font-weight: 600;
  font-size: 12px; height: 32px; padding: 0 12px; border-radius: var(--r-pill);
  background: var(--surface); color: var(--pool); border: 1px solid var(--teal-border);
  cursor: pointer; }
.sb-pill-change:hover { background: var(--pool); color: var(--white); }

/* The trace card in the gate's slot (D98; the street-side gate and pick
   of board 12 used it until D161). */
.sb-gate-h { font-family: 'Fraunces', serif; font-weight: 600; font-size: 19px;
  letter-spacing: -.3px; color: var(--forest); margin: 0; line-height: 1.25; }
.sb-gate-body { font-size: 13.5px; line-height: 1.5; color: var(--text-2);
  margin: 0; text-wrap: pretty; }
.sb-gate-actions { display: flex; flex-direction: column; gap: 8px; padding-top: 4px; }
/* The site's .btn is inline-flex, which sets a full-width label at the
   left edge; the boards (Oct 2 board 12, Oct 18 item 5) center it. */
.sb-gate-actions .sb-cta { width: 100%; justify-content: center; }
.sb-gate-actions .sb-btn-ghost { width: 100%; font-size: 13.5px; height: 44px; }
.sb-sides { display: flex; flex-wrap: wrap; gap: 6px; }
.sb-side-chip { display: inline-flex; align-items: center; gap: 6px; height: 40px;
  padding: 0 12px 0 9px; font-family: 'DM Sans', sans-serif; font-size: 12.5px;
  font-weight: 500; color: var(--text); background: var(--surface);
  border: 1px solid var(--border-2); border-radius: var(--r-pill);
  white-space: nowrap; cursor: pointer; }
.sb-side-chip:hover { border-color: var(--pool); }
/* Two street sides are on: the others wait until one is cleared. */
.sb-side-chip:disabled { opacity: .45; cursor: not-allowed; }
.sb-side-chip:disabled:hover { border-color: var(--border-2); }
.sb-side-chip.is-on { font-weight: 600; color: var(--pool-dark);
  background: var(--pool-light); border: 1.5px solid var(--pool-deep); }
.sb-box { fill: var(--surface); stroke: var(--border-2); stroke-width: 1.5; }
.sb-box--on { fill: var(--pool); stroke: var(--pool); }
.sb-check { color: var(--white); }

/* The Lot line tab (D161, Oct 28 2026): the line's one sentence, what
   the homeowner changed with Reset beside it, the street side's chips
   (44 px, a chip per side of the lot, wrapping when there are more than
   four), the corner link. */
.sb-lot > .sb-line { font-size: 13.5px; line-height: 1.5; }
/* The changes, then Reset under them at the right (Oct 30 2026). */
.sb-lot-changed { display: flex; flex-direction: column; align-items: stretch; gap: 2px; }
.sb-lot .sb-lot-changed > .sb-link { align-self: flex-end; }
.sb-lot-changed-words { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.sb-prov-sub { margin: 0; color: var(--text-2); }
.sb-street { display: flex; flex-direction: column; gap: 8px; padding-top: 12px; border-top: 1px solid var(--border); }
.sb-street-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.sb-street-label { font-size: 14px; font-weight: 600; color: var(--text); }
/* The Lot line tab's first heading, Check lot line, in the Street side
   heading's style (Oct 30 2026). */
.sb-lot-head { margin: 0; font-family: inherit; line-height: inherit; }
.sb-street-from { font-size: 12px; color: var(--text-3); }
.sb-street-chips .sb-side-chip { height: 44px; padding: 0 10px 0 8px; font-size: 13px; }
.sb-street .sb-link, .sb-lot-changed .sb-link { min-height: 44px; font-size: 13px; font-weight: 600;
  text-underline-offset: 3px; align-self: flex-start; }
/* A label and its value side by side, Change at the row's end (D129):
   the street side here, the zoning district and the lot size on the
   Setbacks tab. A value not set yet takes the amber. */
.sb-kv { display: flex; align-items: center; gap: 10px; min-height: 44px;
  border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.sb-kv-k { flex: none; font-size: 13.5px; color: var(--text-2); }
.sb-kv-v { min-width: 0; font-size: 17px; font-weight: 600; line-height: 1.25; color: var(--text); }
.sb-kv .sb-pill-change { margin-left: auto; }
.sb-kv--unset .sb-kv-v { font-size: 15px; color: var(--priority-text); }
/* Reset to county line never wraps in the row it joins. */
.sb-btn-nowrap { white-space: nowrap; }
/* The trace's running readout (handoff.md item 5): a row between two
   hairlines in DM Mono, from the first corner. */
.sb-trace-readout { display: flex; align-items: center; gap: 10px; min-height: 44px;
  border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
  font-family: 'DM Mono', monospace; font-size: 13px; color: var(--text); }

/* The district and lot-size pickers (the row itself is .sb-kv, D129). */
.sb-card-eyebrow { font-size: 10px; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--pool-dark); }
.sb-picker { display: flex; flex-direction: column; gap: 10px; padding: 10px 12px;
  background: var(--pool-light); border: 1px solid var(--teal-border); border-radius: var(--r-sm); }
.sb-picker-h { font-family: 'Fraunces', serif; font-weight: 600; font-size: 17px;
  color: var(--forest); margin: 0; line-height: 1.3; }
.sb-options { display: flex; flex-direction: column; gap: 4px; }
.sb-option { display: flex; align-items: center; gap: 10px; min-height: 44px;
  padding: 0 10px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-sm); cursor: pointer; font-size: 13.5px; color: var(--text); }
.sb-option.is-on { border-color: var(--pool); background: var(--surface); }
.sb-option input { accent-color: var(--pool); margin: 0; width: 18px; height: 18px; }
.sb-option-name { flex: 1 1 auto; min-width: 0; font-weight: 500; }
.sb-option-key { font-family: 'DM Mono', monospace; font-size: 11px; color: var(--text-3); }
.sb-where { display: flex; flex-direction: column; gap: 4px; }
.sb-where-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 13px; color: var(--text-2); min-height: 32px; }
.sb-code { font-family: 'DM Mono', monospace; font-size: 13px; color: var(--text);
  background: var(--surface); border: 1px solid var(--border); border-radius: 4px; padding: 2px 6px; }

/* The table (D129, Colin, Oct 26 2026): Pool to, Distance, Minimum.
   Each heading starts where its values start; the two number columns
   are fixed and the first wraps, so the distance sits close to the line
   it measures and the minimum has room. A line's rows (its shortfall,
   the code's words, its notes) share one tbody: one tint, one rule. */
.sb-tbl { width: 100%; border-collapse: collapse; table-layout: fixed; }
.sb-tbl col.sb-col-d { width: 84px; }
.sb-tbl col.sb-col-m { width: 108px; }
.sb-tbl th, .sb-tbl td { padding: 0; font-weight: inherit; text-align: left; vertical-align: top; }
.sb-tbl thead th { font-size: 12px; font-weight: 600; line-height: 1.3; color: var(--text-2);
  padding: 0 12px 6px 0; border-bottom: 1px solid var(--border-2); vertical-align: bottom; }
.sb-tbl thead th:first-child { padding-left: 8px; }
.sb-tbl thead th:last-child { padding-right: 8px; }
.sb-tbl tbody.sb-row { border-bottom: 1px solid var(--border); scroll-margin-top: 8px; }
.sb-tbl .sb-row-main > th { padding: 9px 12px 9px 8px; }
.sb-row-label { display: block; font-size: 14px; font-weight: 500; line-height: 18px; color: var(--text); }
.sb-row-sub { display: block; font-size: 12px; line-height: 16px; color: var(--text-2); margin-top: 1px; }
.sb-tbl .sb-row-dist { font-family: 'DM Mono', monospace; font-size: 15px; font-weight: 500; line-height: 18px;
  color: var(--text); white-space: nowrap; padding: 9px 12px 0 0; }
.sb-tbl .sb-row-min { font-size: 12.5px; line-height: 18px; color: var(--text-2); padding: 9px 8px 0 0; }
.sb-tbl .sb-row-min--num { font-family: 'DM Mono', monospace; font-size: 13px; white-space: nowrap; }
.sb-tbl .sb-row-readout { font-size: 12.5px; font-weight: 600; line-height: 18px; color: var(--urgent-text);
  padding: 9px 8px 0 0; }
/* "In words" opens the code's words under the row; its tap area is 44 px tall. */
.sb-words-btn { position: relative; display: inline-flex; align-items: center; gap: 3px; padding: 0;
  border: 0; background: none; font: 600 12.5px/18px 'DM Sans', sans-serif; color: var(--pool-dark); cursor: pointer; }
.sb-words-btn::after { content: ''; position: absolute; left: -12px; right: -8px; top: -13px; bottom: -13px; }
.sb-words-btn svg, .sb-more svg { transition: transform .15s ease; }
.sb-words-btn[aria-expanded="true"] svg, .sb-more[aria-expanded="true"] svg { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .sb-words-btn svg, .sb-more svg { transition: none; } }
/* What a line carries under it, across the three columns. */
.sb-tbl .sb-row-msg td, .sb-tbl .sb-row-said td, .sb-tbl .sb-row-note td { padding: 0 8px 10px; }
.sb-tbl .sb-row-msg td { font-size: 12.5px; line-height: 1.45; text-wrap: pretty; }
.sb-block-head { font-weight: 600; }
.sb-tbl tbody.sb-row--priority { background: var(--priority-bg); }
.sb-row--priority .sb-row-dist, .sb-row--priority .sb-row-min, .sb-tbl .sb-row--priority .sb-row-msg td { color: var(--priority-text); }
.sb-tbl tbody.sb-row--urgent { background: var(--urgent-bg); }
.sb-tbl .sb-row--urgent .sb-row-msg td { color: var(--urgent-text); }
.sb-said-words { margin: 0 0 6px; padding: 8px 10px; border: 1px solid var(--border-2);
  border-radius: var(--r-sm); background: var(--surface); font-size: 13px; font-weight: 600;
  line-height: 1.4; color: var(--text); text-wrap: pretty; }
.sb-said-words--dashed { border-style: dashed; }
.sb-said-note { margin: 0; font-size: 12px; line-height: 1.45; color: var(--text-2); }
.sb-tbl tbody.sb-grp th { padding: 12px 8px 4px; }
.sb-group { font-size: 12.5px; font-weight: 600; color: var(--pool-dark); }
.sb-note { margin: 0; font-size: 12px; line-height: 1.45; color: var(--text-2); text-wrap: pretty; }
/* The reading note (D90): where a chained number came from, under its row. */
.sb-reading-note { margin: 0; font-size: 11.5px; line-height: 1.45; color: var(--text-2); text-wrap: pretty; }
.sb-sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* The count above the table when a distance is short (D129). */
.sb-count { display: flex; align-items: center; gap: 8px; margin: 0; font-size: 13px; font-weight: 600;
  line-height: 1.4; color: var(--priority-text); }
.sb-count-dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--sun); }
.sb-count--urgent { color: var(--urgent-text); }
.sb-count--urgent .sb-count-dot { background: var(--urgent-text); }
/* The Source block (D129): each code once, then the lines it covers. A
   section under "§" or "§§" stays whole, as on the page (Oct 17 2026). */
.sb-src { display: flex; flex-direction: column; gap: 4px; }
/* The block opens from "Where these come from" (D143): closed until
   asked, the toggle its face. */
.sb-src-body { display: flex; flex-direction: column; gap: 4px; }
.sb-src-body[hidden] { display: none; }
.sb-src-h { margin: 0 0 2px; font-family: 'DM Sans', sans-serif; line-height: 1.4; }
.sb-src-code { margin: 0; font-size: 13px; line-height: 1.4; color: var(--text); }
.sb-src-code a { font-weight: 600; }
.sb-src-line { margin: 0; font-size: 12.5px; line-height: 1.45; color: var(--text-2); text-wrap: pretty; }
.sb-src-line .sb-sec { white-space: nowrap; }
.sb-src-line .sb-link { font-size: inherit; }
.sb-more { align-self: flex-start; display: inline-flex; align-items: center; gap: 4px; min-height: 44px;
  padding: 0; border: 0; background: none; font: 600 12.5px 'DM Sans', sans-serif;
  color: var(--pool-dark); cursor: pointer; }
.sb-why { list-style: none; margin: 4px 0 0; padding: 10px 12px; background: var(--bg); border-radius: var(--r);
  display: flex; flex-direction: column; gap: 8px; font-size: 12.5px; line-height: 1.45; color: var(--text); }
.sb-why strong { font-weight: 600; }

/* Blocks around the table. */
.sb-other { display: flex; flex-direction: column; gap: 4px; padding: 9px 12px;
  border: 1px dashed var(--border-2); border-radius: var(--r-sm); }
.sb-other .sb-card-eyebrow { color: var(--text-3); }
.sb-other .sb-line { font-size: 12.5px; }
.sb-prompt { display: flex; flex-direction: column; gap: 8px; padding-top: 4px; }
.sb-prompt-h { font-size: 13.5px; font-weight: 600; color: var(--text); line-height: 1.4; text-wrap: pretty; }
.sb-entry { display: flex; flex-direction: column; gap: 10px; padding-top: 4px; }
.sb-entry-h { font-size: 13.5px; font-weight: 600; color: var(--text); line-height: 1.4; }
.sb-entry-grid { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 8px; }
.sb-field-label { display: flex; flex-direction: column; gap: 4px; font-size: 10px;
  font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--text-3); }
.sb-field { display: flex; align-items: center; height: 44px; border: 1px solid var(--border-2);
  border-radius: var(--r-sm); background: var(--surface); padding: 0 10px; }
.sb-field:focus-within { border: 1.5px solid var(--pool); box-shadow: 0 0 0 3px rgba(168,221,228,.35); }
.sb-field input { flex: 1 1 auto; min-width: 0; width: 100%; border: none; background: none;
  font-family: 'DM Mono', monospace; font-size: 15px; color: var(--text); padding: 0; outline: none; }
.sb-unit { font-family: 'DM Mono', monospace; font-size: 11px; color: var(--text-3);
  text-transform: none; letter-spacing: 0; }
.sb-barrier { display: flex; flex-direction: column; gap: 3px; padding: 9px 12px;
  border: 1px solid var(--border-2); border-radius: var(--r-sm); background: var(--surface-2); }
.sb-barrier .sb-card-eyebrow { color: var(--text-3); }
.sb-barrier .sb-line { font-size: 12.5px; }
.sb-pending { display: flex; align-items: center; gap: 8px; }
.sb-pulse { width: 7px; height: 7px; border-radius: 50%; background: var(--pool-mid);
  animation: sb-pulse 1.4s ease-in-out infinite; }
@keyframes sb-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .35; transform: scale(.7); } }
@media (prefers-reduced-motion: reduce) { .sb-pulse { animation: none; } }

/* ── Structures (S1e, D98; docs/design/step1-rest-2026-10-18, item 1) ──
   The pending line under the street-side question and on the tab, the
   holding bar, the empty state's full-width ways to add one, the rows with
   their status and Edit, the corrections, and the classify card. */
.st-gate-line, .st-pending { display: flex; align-items: flex-start; gap: 8px; }
.st-gate-line { margin-top: -10px; }
.st-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--pool-mid);
  margin-top: .45em; animation: sb-pulse 1.4s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .st-dot { animation: none; } }
.st-bar { position: relative; height: 3px; background: var(--border); border-radius: 2px; overflow: hidden; }
.st-bar span { position: absolute; left: 0; top: 0; width: 40%; height: 3px; border-radius: 2px;
  background: var(--pool-mid); animation: sp-holding 1.6s linear infinite; }
@media (prefers-reduced-motion: reduce) { .st-bar span { animation: none; transform: translateX(75%); } }
.st-read-row .st-read { width: 100%; justify-content: center; }
/* The read's loading state (D120): placeholder rows the results replace,
   pulsing as the tab's dot does; still under reduced motion. */
.st-loading { display: flex; flex-direction: column; gap: 10px; }
.st-skeleton { display: flex; flex-direction: column; border-top: 1px solid var(--border); }
.st-skel-row { display: flex; align-items: center; gap: 10px; min-height: 48px; border-bottom: 1px solid var(--border); }
.st-skel-row > span { display: block; background: var(--surface-2); animation: st-skel 1.4s ease-in-out infinite; }
@keyframes st-skel { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
/* The glyph's place on a placeholder row: a soft pill (D156). */
.st-skel-glyph { flex: none; width: 20px; height: 14px; border-radius: 7px; }
.st-skel-name { flex: 0 1 auto; width: 42%; height: 10px; border-radius: 5px; }
.st-skel-row:nth-child(2) .st-skel-name { width: 30%; }
.st-skel-row:nth-child(3) .st-skel-name { width: 22%; }
.st-skel-token { flex: none; width: 64px; height: 18px; border-radius: var(--r-pill); margin-left: auto; }
@media (prefers-reduced-motion: reduce) { .st-skel-row > span { animation: none; } }
/* Two ways to add a structure (D133): Trace a structure and Add a box
   share the row, half each; with nothing on the list yet they stand 48
   px tall, the empty state's hero action (D98), the line under them
   saying which is which. */
.st-add-row { display: flex; gap: 8px; }
.st-add-row > .sb-btn-outline { flex: 1 1 0; min-width: 0; padding: 0 10px; white-space: nowrap; }
.st-add-row--full > .sb-btn-outline { height: 48px; font-size: 14px; }
.st-add-hint { margin-top: -4px; }
/* Traced and reshaped yard changes (D152): the three trace buttons
   across the row under the kinds, a link with its hint beside it. */
.yd-trace-row { display: flex; flex-wrap: wrap; gap: 6px; }
.yd-trace-row > .sb-btn-outline { flex: 1 1 96px; min-width: 0; padding: 0 8px; white-space: nowrap; font-size: 12.5px; }
.yd-trace-hint { margin-top: -4px; }
.yd-link-row { display: flex; align-items: center; gap: 12px; min-height: 44px; }
.yd-link-row .sb-hint { flex: 1 1 auto; }
/* The way on (D118): a text link with an arrow at the right, under a
   hairline, so it reads as moving on rather than as one of the tab's
   tools (Colin, Oct 24 2026). Go to Pools on the Yard changes tab takes
   the same link in its own row. */
.st-next-row, .sb-next-row { display: flex; justify-content: flex-end;
  border-top: 1px solid var(--border); padding-top: 4px; margin-top: 2px; }
.sb-next { display: inline-flex; align-items: center; gap: 6px; min-height: 44px;
  padding: 0 2px; background: none; border: none; cursor: pointer;
  font-family: 'DM Sans', sans-serif; font-size: 14px; font-weight: 600; color: var(--pool-dark); }
.sb-next:hover .sb-next-label { text-decoration: underline; text-underline-offset: 3px; }
.sb-next-arrow { font-size: 16px; line-height: 1; transition: transform .15s ease; }
.sb-next:hover .sb-next-arrow { transform: translateX(2px); }
.sb-next:focus-visible { outline: 2px solid var(--pool); outline-offset: 2px; border-radius: var(--r-sm); }
@media (prefers-reduced-motion: reduce) { .sb-next-arrow { transition: none; } }
.st-rows { display: flex; flex-direction: column; }
.st-row { display: flex; flex-direction: column; gap: 8px; border-top: 1px solid var(--border); }
.st-rows .st-row:last-child { border-bottom: 1px solid var(--border); }
/* Rows open in place (D165): the heading is the row's one button, open
   or closed; the open one a card as the Pools tab's are, its outline's
   handles live on the map. */
.st-row-h { margin: 0; font: inherit; }
.st-row-head { display: flex; align-items: center; gap: 10px; min-height: 48px; width: 100%;
  padding: 4px 0; background: none; border: 0; cursor: pointer; text-align: left;
  font-family: 'DM Sans', sans-serif; color: inherit; }
.st-row.is-open { margin: 4px -8px; padding: 0 8px 12px; border: 1.5px solid var(--pool); border-radius: var(--r); }
.st-rows .st-row.is-open:last-child { border-bottom: 1.5px solid var(--pool); }
.st-row.is-open + .st-row { border-top: 0; }
.st-live-line { color: var(--pool-dark); }
/* A structure's outline takes a tap on the Structures tab alone (D165). */
.st-taps-off .st-shape { pointer-events: none; }
/* The kind's glyph on each list's rows (D156, Oct 28 2026, the "Row
   icons" mock's option A): a line drawing on a 20 by 16 grid in the
   map's ink, teal for what is there, amber and dashed for what the
   project adds, in place of the box that read as a check box. The box
   stays as the fallback when canvas-glyphs.js has not loaded. */
.pr-glyph { flex: none; display: block; width: 20px; height: 16px; fill: none; stroke: currentColor;
  stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; }
.pr-glyph--structure { color: var(--pool-deep); }
.pr-glyph--yard { color: var(--sun-dark); stroke-dasharray: 2.6 1.6; }
.st-swatch { flex: none; width: 18px; height: 14px; box-sizing: border-box;
  border: 1.5px solid var(--pool-deep); background: var(--surface); }
.st-row-name { flex: 1 1 auto; min-width: 0; font-size: 13.5px; font-weight: 500; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.st-row.is-open .st-row-name { color: var(--pool-dark); font-weight: 600; }
.st-token { flex: none; font-size: 11px; font-weight: 600; color: var(--text-2); background: var(--surface-2);
  border: 1px solid var(--border-2); border-radius: var(--r-pill); padding: 2px 8px; white-space: nowrap; }
.st-row.is-removed:not(.is-open) .st-row-head > *:not(.pool-row-chev) { opacity: .55; }
.st-row.is-removed .st-swatch, .st-row.is-removed .st-glyph { opacity: .55; }
.st-label { display: block; }
.st-types { display: flex; flex-wrap: wrap; gap: 6px; }
.st-type { height: 40px; padding: 0 14px; font-family: 'DM Sans', sans-serif; font-size: 12.5px;
  font-weight: 500; color: var(--text); background: var(--surface); border: 1px solid var(--border-2);
  border-radius: var(--r-pill); cursor: pointer; }
.st-type:hover { border-color: var(--pool); }
.st-type.is-on { background: var(--pool-light); border: 1.5px solid var(--pool-deep); color: var(--pool-dark); font-weight: 600; }
.st-field-label { display: flex; flex-direction: column; gap: 6px; }
.st-field input { font-family: 'DM Sans', sans-serif; font-size: 14px; }
/* The three corrections (D140): each a row of its own, the control over
   the line that says what it does, so the line is read with the control
   and not in a block under all three (Colin, Oct 27 2026). The ghost
   button's padding is pulled back so its text sits on the panel's edge,
   and the line steps in to meet it. */
.st-actions { display: flex; flex-direction: column; gap: 6px; margin-left: -14px; }
.st-corr { display: flex; flex-direction: column; }
.st-corr .sb-btn-ghost { align-self: flex-start; white-space: nowrap; }
.st-corr .sb-btn-ghost[aria-pressed="true"] { background: var(--pool-light); }
.st-corr-line { margin: -6px 0 0 14px; }
/* Or DIY (D140): the quiet line between the read and the two ways to
   draw a structure by hand, a hairline either side. */
.st-or { display: flex; align-items: center; gap: 10px; margin: -4px 0; font-size: 12.5px; font-weight: 600;
  color: var(--text-3); text-transform: uppercase; letter-spacing: .04em; }
.st-or::before, .st-or::after { content: ''; flex: 1 1 0; height: 1px; background: var(--border); }
/* Clear the read (D140): under the rows, the ghost button over its line,
   set as the corrections are. */
.st-clear-row { display: flex; flex-direction: column; margin-left: -14px; }
.st-clear-row .st-clear { align-self: flex-start; white-space: nowrap; }
.st-clear-line { margin: -6px 0 0 14px; }
.st-classify { gap: 10px; }
/* "Is it there now?" (S1f PR 2): Existing and Planned side by side. */
.st-planned { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.st-planned .sb-option { font-size: 13.5px; }
.st-planned .sb-option.is-on { border-width: 1.5px; padding: 0 9.5px; }

/* ── Yard changes (S1f PR 2, D98; docs/design/step1-rest-2026-10-18,
   item 4) ──────────────────────────────────────────────────────────
   The amber line with its glyph, a row per yard change (the kind's
   glyph, D156, the name, the size, Adjust), the four kinds' chips with
   their glyphs; the selected one's block is the pool's (.pool-edit-head,
   .pool-steppers, .pool-angle). The fallback swatches are drawn in the
   map's amber: --sun at 22% under a dashed --sun-dark outline. */
.yd-intro { display: flex; align-items: flex-start; gap: 10px; }
.yd-intro .yd-swatch { margin-top: 3px; }
.yd-intro .yd-kind { margin-top: 2px; }
.yd-swatch { flex: none; width: 22px; height: 14px; display: block; }
.yd-swatch rect, .yd-type-swatch rect { fill: var(--sun); fill-opacity: .22; stroke: var(--sun-dark);
  stroke-width: 1.5; stroke-dasharray: 4 2.5; }
/* Around the pool (D155): the Pools tab's last group, under the pool's
   (D169, its heading as the pool's group's is). Its rows open in place
   as the pool's do (D165). */
.pool-around { background: var(--surface); }
.pool-around[hidden] { display: none; }
.yd-rows { display: flex; flex-direction: column; border-bottom: 1px solid var(--border); }
.yd-row { display: block; border-top: 1px solid var(--border); }
.yd-row-h { margin: 0; font: inherit; }
.yd-row-head { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 48px;
  padding: 4px 0; background: none; border: 0; cursor: pointer; text-align: left;
  font-family: 'DM Sans', sans-serif; color: inherit; }
.yd-row-open { display: flex; flex-direction: column; gap: 8px; margin: 4px -8px;
  padding: 0 8px 4px; border: 1.5px solid var(--pool); border-radius: var(--r); }
.yd-row-open + .yd-row { border-top: 0; }
.yd-row-open .yd-row-name.pool-state-label { font-size: 14px; }
.yd-row-gone { display: flex; align-items: center; justify-content: space-between; gap: 10px; min-height: 48px; }
.yd-row-gone .yd-row-name { color: var(--text-2); }
.yd-trace-card { display: flex; flex-direction: column; gap: 10px; }
/* One way in for each kind (D170): a tile per way, its small drawing
   (the pool in the map's teal, the yard change in its amber), its name
   and a line; the question in the chips' place, Cancel at its foot. */
.yd-ask { display: flex; flex-direction: column; gap: 8px; padding-top: 4px; }
.yd-ask-h { margin: 0; font-family: 'DM Sans', sans-serif; font-size: 14px; font-weight: 600; color: var(--pool-dark); }
.yd-tile { display: flex; align-items: center; gap: 12px; width: 100%; min-height: 60px; padding: 8px 12px;
  background: var(--surface); border: 1px solid var(--border-2); border-radius: var(--r);
  cursor: pointer; text-align: left; font-family: 'DM Sans', sans-serif; color: var(--text); }
.yd-tile:hover { border-color: var(--pool); }
.yd-tile-art { flex: none; display: block; }
.yd-art-amber { fill: var(--sun); fill-opacity: .22; stroke: var(--sun-dark); stroke-width: 1.5; stroke-dasharray: 4 2.5; }
.yd-art-edge { fill: var(--sun); fill-opacity: .4; stroke: var(--sun-dark); stroke-width: 1.5; }
.yd-art-pool { fill: var(--pool); fill-opacity: .45; stroke: var(--pool); stroke-width: 1.25; }
.yd-art-dots circle { fill: var(--surface); stroke: var(--sun-dark); stroke-width: 1.25; }
.yd-tile-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.yd-tile-title { font-size: 14px; font-weight: 600; color: var(--pool-dark); }
.yd-tile-sub { font-size: 12.5px; line-height: 1.35; color: var(--text-2); }
.yd-ask-actions { display: flex; justify-content: flex-end; }
/* Box or Own shape (D170): two halves of one control over an open
   deck's, patio's or coping's controls, the one in force lit as a
   preset chip is. */
.yd-shape-switch { display: flex; gap: 0; }
.yd-shape-opt { flex: 1 1 0; height: 40px; padding: 0 8px; font-family: 'DM Sans', sans-serif;
  font-size: 13px; font-weight: 500; color: var(--text-2); background: var(--surface);
  border: 1px solid var(--border); cursor: pointer; white-space: nowrap; }
.yd-shape-opt:first-child { border-radius: var(--r-sm) 0 0 var(--r-sm); }
.yd-shape-opt:last-child { border-radius: 0 var(--r-sm) var(--r-sm) 0; border-left: 0; }
.yd-shape-opt.on { background: var(--pool-light); border-color: var(--pool); color: var(--pool-dark); }
.yd-shape-opt.on + .yd-shape-opt.on, .yd-shape-opt:last-child.on { border-left: 1px solid var(--pool); }
/* Lawn or turf (D187): grass or artificial turf, its line under it. */
.yd-surface { display: flex; flex-direction: column; gap: 6px; }
.yd-surface .sb-hint { margin: 0; }
/* The own shape in hand: its line, Undo last change and Start over. */
.yd-own { display: flex; flex-direction: column; gap: 6px; }
.yd-own .sb-line { margin: 0; }
.yd-own-actions { display: flex; flex-wrap: wrap; gap: 4px 16px; }
.yd-own-actions .pool-btn-ghost { height: 44px; padding: 0; }
.yd-own-actions .pool-btn-ghost:disabled { color: var(--text-3); cursor: default; }
/* The Coping row (D170): a row of the pool's, drawn by the yard module
   into its slot between Steps and Pool features. The slot itself takes
   no room; the open row's outline meets its neighbours as the pool's
   own rows do. */
.pool-prow-slot { display: contents; }
.pool-prow.is-open + .pool-prow-slot > .pool-prow { border-top: 0; }
.pool-prow-slot:has(> .pool-prow.is-open) + .pool-prow { border-top: 0; }
.pool-prow-gone { flex-direction: row; align-items: center; justify-content: space-between; gap: 10px; min-height: 48px; }
.pool-prow-gone .pool-prow-name { color: var(--text-2); }
/* The name, and under it the line that says it is over the lot line
   (D151), as the pool's block says in its label. */
.yd-row-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
/* Named as the pool's rows are (D169). */
.yd-row-name { min-width: 0; font-size: 14px; font-weight: 600; color: var(--pool-dark);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.yd-row-over { font-size: 12px; font-weight: 600; color: var(--urgent-text); white-space: nowrap; }
.yd-row-size { flex: none; font-family: 'DM Mono', monospace; font-size: 12px; color: var(--text-2); white-space: nowrap; }
.yd-add-row { display: flex; align-items: center; gap: 8px; padding-top: 2px; }
.yd-edit { display: flex; flex-direction: column; gap: 8px; }
/* The four kinds, on the tab all the time (D137, Oct 26 2026); greyed
   before a pool, under the line that says to place one first. */
.yd-add-label { padding-top: 4px; }
.yd-types { display: flex; flex-wrap: wrap; gap: 6px; }
.yd-type { display: inline-flex; align-items: center; gap: 8px; height: 40px; padding: 0 14px 0 10px;
  font-family: 'DM Sans', sans-serif; font-size: 12.5px; font-weight: 500; color: var(--text);
  background: var(--surface); border: 1px solid var(--border-2); border-radius: var(--r-pill);
  white-space: nowrap; cursor: pointer; }
.yd-type:hover:not([disabled]) { border-color: var(--pool); }
.yd-type[disabled] { color: var(--text-3); cursor: default; opacity: .6; }
.yd-type-swatch { flex: none; width: 16px; height: 12px; display: block; }
.yd-type .yd-type-glyph { width: 18px; height: 14px; }
.yd-type[disabled] .yd-type-glyph { color: var(--text-3); }
.yd-type-swatch rect { stroke-width: 1.2; stroke-dasharray: 3 2; }
/* ── Fences (D186) ─────────────────────────────────────────────────
   White on a dark edge so they stand out on grass and pavement alike,
   square posts every 8 ft (canvas-fence.js). There now and staying:
   solid. New or replaced: dashed, the edge showing through the gaps.
   Coming out: faded and crossed. Not answered yet: dotted. The glyph on
   the rows and the chip draws each kind the same way. */
.fn-glyph { flex: none; display: block; width: 22px; height: 16px; overflow: visible; }
.yd-type .fn-glyph.yd-type-glyph { width: 20px; height: 14px; }
.fn-glyph.fn-row-glyph { width: 24px; height: 16px; }
.fn-g-edge { fill: none; stroke: var(--text); stroke-width: 5; stroke-opacity: .85; }
.fn-g-edge.fn-g-thin { stroke-width: 4; stroke-opacity: .8; }
.fn-g-line { fill: none; stroke: var(--surface); stroke-width: 2.4; }
.fn-g-dash { stroke-dasharray: 4 3; }
.fn-g-dots { stroke-width: 1.8; stroke-dasharray: 1 3; stroke-linecap: round; }
.fn-g-faded { stroke-opacity: .45; }
.fn-g-line.fn-g-faded { stroke-opacity: .6; stroke-width: 2; }
.fn-g-post { fill: var(--surface); stroke: var(--text); stroke-width: 1.2; }
.fn-g-x-edge { fill: none; stroke: var(--text); stroke-width: 3.6; stroke-linecap: round; }
.fn-g-x { fill: none; stroke: var(--surface); stroke-width: 1.6; stroke-linecap: round; }
.yd-type[disabled] .fn-glyph { opacity: .6; }
.fn-card-glyph { display: inline-block; vertical-align: -3px; margin-right: 8px; }
.fn-row-sum { font-size: 12px; color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fn-row-open { gap: 10px; }
.fn-switch .yd-shape-opt { white-space: normal; line-height: 1.2; }
.fn-switch .yd-shape-opt:not(:first-child) { border-left: 0; }
.fn-switch .yd-shape-opt:not(:first-child):not(:last-child) { border-radius: 0; }
.fn-switch .yd-shape-opt.on { border-left: 1px solid var(--pool); }
.fn-hint { margin: 0; }
.fn-line { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.fn-line .pool-row-label { padding: 0; }
.fn-stepper .fn-step-value { display: flex; align-items: center; justify-content: center; min-width: 72px;
  font-family: 'DM Mono', monospace; font-size: 13px; font-variant-numeric: tabular-nums; }
.fn-gate { display: flex; align-items: center; gap: 8px; }
.fn-gate .fn-line { flex: 1 1 auto; min-width: 0; }
.fn-gate .fn-line .pool-row-label { font-weight: 500; color: var(--text); text-transform: none; letter-spacing: 0; font-size: 13px; }
.fn-with { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.fn-with .sb-btn-outline { height: 40px; }
.fn-with .sb-btn-outline.is-on { background: var(--pool); color: var(--white); }
.fn-pick { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 12px;
  background: var(--pool-light); border: 1px solid var(--teal-border); border-radius: var(--r-sm); }
.fn-pick .sb-line { margin: 0; font-weight: 600; color: var(--pool-dark); }
/* On the map: the posts, the crosses, the labels and the open fence's
   corners. Marks take no taps (their pane passes them through). */
.leaflet-container .fn-mark { pointer-events: none; }
.fn-post span { position: absolute; left: -4px; top: -4px; width: 8px; height: 8px; box-sizing: border-box;
  background: var(--surface); border: 1.5px solid var(--text); }
.fn-x span { position: absolute; left: -6px; top: -6px; width: 12px; height: 12px; }
.fn-x span::before, .fn-x span::after { content: ""; position: absolute; left: -1px; top: 4px; width: 14px; height: 4px;
  background: var(--surface); border: 1px solid var(--text); border-radius: 2px; box-sizing: border-box; }
.fn-x span::before { transform: rotate(45deg); }
.fn-x span::after { transform: rotate(-45deg); }
.fn-label { position: absolute; left: 0; top: 0; white-space: nowrap; font-family: 'DM Sans', sans-serif;
  font-size: 11px; font-weight: 600; line-height: 1.3; color: var(--text); background: var(--surface);
  border: 1px solid var(--text); border-radius: 4px; padding: 2px 7px; }
.fn-label--new, .fn-label--replaced, .fn-label--ask { border-style: dashed; }
.fn-label--out { color: var(--text-2); border-color: var(--text-2); text-decoration: line-through; }
.fn-label.is-on { background: var(--pool-light); border: 2px solid var(--pool); padding: 1px 6px; }
.leaflet-container .fn-handle { cursor: move; }
.fn-handle span { position: absolute; left: 7px; top: 7px; width: 14px; height: 14px; box-sizing: border-box;
  border-radius: 50%; background: var(--surface); border: 2px solid var(--pool-deep); }
.leaflet-container.fn-picking { cursor: crosshair; }
.leaflet-container path.fn-hit { cursor: pointer; }
.leaflet-container.fn-picking path.fn-hit { cursor: crosshair; }
/* While anything is drawn corner by corner (a fence, a trace, a pool's
   shape) a fence's line takes no taps: they are posts and corners. */
.leaflet-container.dr-drawing path.fn-hit { pointer-events: none; }
.pool-range-helper[hidden] { display: none; }
/* Around the pool (D134, Oct 26 2026): a width per side, each stepper on
   the side of a small drawing of the pool it widens (north up, as the
   map), named by where that side faces; the drawing follows the widths.
   The value box narrows to 46 px so two steppers and the drawing share
   the 320 px a 352 px rail leaves. */
.yd-cross { display: grid; grid-template-columns: auto minmax(40px, 1fr) auto;
  grid-template-areas: "top top top" "left glyph right" "bottom bottom bottom";
  column-gap: 4px; row-gap: 8px; align-items: end; }
.yd-side { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.yd-side--top { grid-area: top; align-items: center; }
.yd-side--bottom { grid-area: bottom; align-items: center; }
.yd-side--left { grid-area: left; align-items: flex-start; }
.yd-side--right { grid-area: right; align-items: flex-end; text-align: right; }
.yd-side-label { display: block; max-width: 134px; font-family: 'DM Sans', sans-serif;
  font-size: 12px; font-weight: 600; line-height: 1.3; color: var(--text-2); }
.yd-side .pool-stepper-controls { width: 134px; }
.yd-side .pool-step-value { flex: 0 0 46px; min-width: 46px; padding: 0 2px; }
.yd-glyph { grid-area: glyph; align-self: center; justify-self: center; display: flex; }
.yd-glyph svg { display: block; }
.yd-glyph-box { fill: var(--sun); fill-opacity: .22; stroke: var(--sun-dark); stroke-width: 1.25; stroke-dasharray: 3 2; }
.yd-glyph-pool { fill: var(--pool); fill-opacity: .45; stroke: var(--pool-deep); stroke-width: 1.25; }
.yd-with-pool { margin: 0; }
/* On the map a drag on it moves its pool, as on the pool itself. */
.leaflet-container path.yd-shape.yd-around { cursor: grab; }

/* A yard change's name on the map (D101): plain type inside its own
   box where it fits (10/600 --sun-dark with a --surface edge), placed
   and fitted by canvas-yard.js; none on a deck, a patio or coping
   around a pool, whose box is the pool's. */
.yd-name-icon { pointer-events: none; }
.yd-name { position: absolute; transform: translate(-50%, -50%); font-family: 'DM Sans', sans-serif;
  font-size: 10px; font-weight: 600; line-height: 1.2; color: var(--sun-dark); white-space: nowrap;
  text-shadow: 0 0 2px var(--surface), 0 0 2px var(--surface), 0 0 3px var(--surface); }
.leaflet-container path.yd-shape { cursor: move; }

/* On the map: each structure's name on its shape, in plain type
   (10/600 --pool-dark with a --surface edge) where it fits inside it
   and hidden where it does not (D101), a removed one's quieter; the new
   box's chip, dashed, above the box (a label since D128: the box moves
   by the four-arrow grip). */
.st-name-icon { pointer-events: none; }
.st-name { position: absolute; transform: translate(-50%, -50%); font-family: 'DM Sans', sans-serif;
  font-size: 11px; font-weight: 600; line-height: 1.3; color: var(--pool-dark); background: var(--surface);
  border: 1px solid var(--border); border-radius: 4px; padding: 2px 7px; white-space: nowrap; }
.st-name--in { font-size: 10px; line-height: 1.2; background: none; border: 0; border-radius: 0; padding: 0;
  text-shadow: 0 0 2px var(--surface), 0 0 2px var(--surface), 0 0 3px var(--surface); }
.st-name--removed { color: var(--text-2); }
.st-name--new { border: 1px dashed var(--pool-deep); }
/* The corner tool's handles (canvas-corners.js): a 44 px target around
   a corner of radius 7 (--surface, 2 px --pool-deep; the one in hand
   radius 8, --pool with a --surface ring) and a handle of radius 4.5 on
   each side's middle (--surface, 1.5 --pool); a new box's corners
   radius 4.5, a custom pool's 5.5. The boards' figures are SVG radii
   with the stroke centered on them, so each dot here is twice the
   radius plus the stroke across (GOTCHAS.md, Oct 18). */
/* Through .leaflet-container: leaflet.css loads after this file, and
   its .leaflet-marker-icon { display: block } would put the dot in the
   target's top left corner, 18 px off its corner. */
.leaflet-container .cn-handle { display: flex; align-items: center; justify-content: center; cursor: grab; }
.cn-dot { display: block; box-sizing: border-box; border-radius: 50%; outline-offset: 3px; }
.cn-handle--corner .cn-dot { width: 16px; height: 16px; background: var(--surface); border: 2px solid var(--pool-deep); }
.cn-handle--mid .cn-dot { width: 10.5px; height: 10.5px; background: var(--surface); border: 1.5px solid var(--pool); }
/* A side in hand (D119): its dot fills as a corner's does. */
.cn-handle--mid.is-held .cn-dot { background: var(--pool); border-color: var(--pool); }
/* A + on each side's middle (D170): a yard change's own shape in hand,
   where a tap adds a corner. Amber, as the outline it adds to. It sits
   over the corners (canvas-corners.js) and takes taps on its dot and a
   ring 7 px round it only, a 36 px target, so a corner near it keeps the
   rest of its own 44 px. */
.leaflet-container .cn-handle--plus.cn-handle--mid { pointer-events: none; }
.leaflet-container .cn-handle--plus.cn-handle--mid .cn-dot { pointer-events: auto; position: relative; }
.cn-handle--plus.cn-handle--mid .cn-dot::after { content: ''; position: absolute; inset: -7px; border-radius: 50%; }
.cn-handle--plus.cn-handle--mid .cn-dot { width: 22px; height: 22px; background: var(--surface);
  border: 1.5px solid var(--sun-dark); display: flex; align-items: center; justify-content: center; }
.cn-handle--plus.cn-handle--mid .cn-dot::before { content: '+'; font-family: 'DM Sans', sans-serif;
  font-size: 15px; font-weight: 600; line-height: 1; color: var(--sun-dark); }
.cn-handle--plus.cn-handle--mid.is-held .cn-dot { background: var(--sun-light); }
.cn-handle--corner.is-held .cn-dot { width: 16px; height: 16px; background: var(--pool); border: none;
  box-shadow: 0 0 0 2px var(--surface); }
.cn-handle--small .cn-dot { width: 10.5px; height: 10.5px; border-width: 1.5px; }
.cn-handle--pool.cn-handle--corner .cn-dot { width: 13px; height: 13px; }
.cn-dot:focus-visible { outline: 2px solid var(--pool); }
.leaflet-container .cn-body { cursor: move; }
/* The move grip (D127 the lot line's, D128 a structure's; the corner
   tool's moveGripIcon): a 44 px target around a 32 px disc (--surface,
   2 px --pool-deep, a four-arrow mark in --pool-deep, a soft shadow so
   it reads on any roof); in hand it fills --pool, mark and edge
   --surface, as a corner does. */
.leaflet-container .cn-move { display: flex; align-items: center; justify-content: center; cursor: move; }
.cn-move-dot { display: flex; align-items: center; justify-content: center; box-sizing: border-box;
  width: 32px; height: 32px; border-radius: 50%; background: var(--surface); border: 2px solid var(--pool-deep);
  color: var(--pool-deep); box-shadow: 0 1px 3px rgba(0,0,0,.28); outline-offset: 3px; }
.cn-move-dot svg { display: block; pointer-events: none; }
.cn-move.is-held .cn-move-dot { background: var(--pool); border-color: var(--surface); color: var(--surface); }
.cn-move-dot:focus-visible { outline: 2px solid var(--pool); }
/* The drawing instrument (canvas-draw.js): a dot of radius 5.5 at each
   corner, the first radius 7 on a 44px target that closes the shape
   (2 px --pool-deep over --surface); the map's cursor marks a tap as a
   corner. Through .leaflet-container, since leaflet.css loads after
   this file. */
.leaflet-container .dr-handle { display: flex; align-items: center; justify-content: center; }
.dr-dot { display: block; box-sizing: border-box; width: 13px; height: 13px; border-radius: 50%;
  background: var(--surface); border: 2px solid var(--pool-deep); }
.dr-handle--first .dr-dot { width: 16px; height: 16px; cursor: pointer; }
.dr-dot:focus-visible { outline: 2px solid var(--pool); outline-offset: 3px; }
.leaflet-container.dr-drawing { cursor: crosshair; }
/* While an outline is drawn every tap is a corner on the photo (D133):
   the pools, their grab discs and the yard changes let taps through, so
   a structure traced beside a pool or over a deck takes its corners
   there. The pool module already does this for its own custom shape. */
.leaflet-container.dr-drawing .leaflet-overlay-pane .leaflet-interactive { pointer-events: none !important; }
/* The trace look (the lot line, D98, handoff.md item 5): radius 6 at
   each corner, the first radius 8 with a 2.5 stroke, and its chip
   centered 26 px above it, a pill in --pool-dark on --surface edged
   1.5 --pool-deep. The chip takes no taps: a tap there lands on the
   photo, as anywhere else. */
.dr-handle--trace .dr-dot { width: 14px; height: 14px; }
.dr-handle--trace.dr-handle--first .dr-dot { width: 18.5px; height: 18.5px; border-width: 2.5px; }
.leaflet-container .dr-chip-wrap { pointer-events: none; }
.dr-chip { position: absolute; left: 0; top: 0; transform: translate(-50%, calc(-50% - 26px));
  font-family: 'DM Sans', sans-serif; font-size: 11px; font-weight: 600; line-height: 1.3;
  color: var(--pool-dark); background: var(--surface); border: 1.5px solid var(--pool-deep);
  border-radius: var(--r-pill); padding: 3px 9px; white-space: nowrap; pointer-events: none; }

/* ── Map overlays ────────────────────────────────────────────────────
   Every chip is a divIcon in a 0×0 wrapper, centered on its marker
   point with a transform; canvas-setbacks-view.js moves the point to
   keep chips beside their lines, off the pool pill and each other, and
   at least 6px inside the map. No raw text on imagery: every chip has
   a surface behind it. */
.sb-icon { pointer-events: none; }
/* Tags (Oct 6 2026, every width): outside the lot line, the distance
   with the minimum under it in smaller, quieter type. While the pool is
   selected only the dimension lines draw. */
.sb-tag { position: absolute; transform: translate(-50%, -50%);
  font-family: 'DM Mono', monospace; font-size: 12px; line-height: 1.25;
  text-align: center; color: var(--pool-dark); background: var(--surface);
  border: 1px solid var(--border); border-radius: 4px; padding: 2px 7px;
  white-space: nowrap; box-sizing: border-box; }
.sb-tag-s { font-size: 10px; line-height: 1.25; color: var(--text-2); }
.sb-tag--priority { color: var(--priority-text); background: var(--priority-bg);
  border-color: var(--priority-text); }
.sb-tag--priority .sb-tag-s { color: var(--priority-text); }
/* The tags stay up while a pool or a yard change is in hand (D135, Oct
   26 2026; hidden while selected from Oct 6 to then): they sit outside
   the lot, so they cover nothing, and the number follows the drag. */
/* No room outside the lot in this view: hidden until a zoom or a pan
   makes room (phone only). */
.sb-noroom { visibility: hidden; }
/* The size pill outside the lot on a phone, on a dotted leader from
   the pool's edge; the pool's own pill steps aside while it shows. */
.sb-pill { position: absolute; transform: translate(-50%, -50%);
  font-family: 'DM Mono', monospace; font-size: 12px; line-height: 1.35;
  color: #fff; background: var(--pool-deep); border-radius: var(--r-sm);
  padding: 3px 8px; white-space: nowrap; }
/* Each pool's own label steps aside while its pill is out; a pool over
   the lot line keeps its warning label on itself (S1f: there can be two). */
.sb-pill-out .pool-dim-label:not(.warning) { visibility: hidden; }
/* The box a custom shape is drawn from shows no size (S1f). */
.pool-dim-label.drawing { visibility: hidden; }
.sb-street-chip { position: absolute; transform: translate(-50%, -50%);
  font-family: 'DM Sans', sans-serif; font-size: 11px; font-weight: 600; line-height: 1.3;
  color: var(--pool-dark); background: var(--surface); border: 1.5px solid var(--pool-deep);
  border-radius: var(--r-pill); padding: 4px 10px; white-space: nowrap; }
.sb-street-chip--quiet { font-size: 10.5px; color: var(--text-2);
  border: 1px solid var(--border-2); padding: 3px 9px; }
.sb-band-chip { position: absolute; transform: translate(-50%, -50%); width: 68px;
  box-sizing: border-box; font-family: 'DM Sans', sans-serif; font-size: 10px; font-weight: 600;
  line-height: 1.3; text-align: center; color: var(--pool-dark); background: var(--surface);
  border: 1px solid var(--border); border-radius: 4px; padding: 3px 6px; }

/* Dimension pill centered on the pool: DM Mono 12px, white on
   --pool-deep; urgent-family tokens in the warning state. The divIcon
   wrapper Leaflet positions is 0×0; the pill centers itself with a
   transform and never takes pointer events. */
.pool-dim-icon { pointer-events: none; }
.pool-dim-label { position: absolute; transform: translate(-50%, -50%);
  font-family: 'DM Mono', monospace; font-size: 12px; line-height: 1.35;
  color: #fff; background: var(--pool-deep); border-radius: var(--r-sm);
  padding: 3px 8px; white-space: nowrap; text-align: center;
  pointer-events: none; }
.pool-dim-label.warning { background: var(--urgent-bg);
  color: var(--urgent-text); }
/* "Deep" inside the pool's deep half (D130): white on the darker half,
   no box; hidden where it does not fit or the size pill sits on it. */
.pool-deep-word { position: absolute; transform: translate(-50%, -50%);
  font-family: 'DM Sans', sans-serif; font-size: 11px; font-weight: 600;
  letter-spacing: .02em; line-height: 1.3; color: #fff; white-space: nowrap;
  pointer-events: none; }
.pool-deep-word.hidden { visibility: hidden; }

/* Address label on the canvas pin. Overrides Leaflet's tooltip chrome
   with the flow's pill recipe; wraps instead of clipping at phone
   widths. */
.leaflet-tooltip.canvas-addr-label { font-family: 'DM Sans', sans-serif;
  font-size: 12.5px; font-weight: 600; color: var(--pool-dark);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-pill); padding: 5px 12px;
  /* The tooltip pane is a 0-width containing block, so shrink-to-fit
     collapses to min-content without an explicit max-content width. */
  white-space: normal; width: max-content; max-width: 240px; text-align: center;
  box-shadow: 0 1px 4px rgba(0,0,0,.14); }
.leaflet-tooltip-top.canvas-addr-label::before { border-top-color: var(--border); }
/* The pin and its label step aside while a pool is on the lot or the
   map is too small for them (canvas-setbacks-view.js, syncAddress), and
   for good once the lot line is drawn (D131, Oct 26 2026): from then the
   address is the chip on the street below. */
.sb-addr-hidden .canvas-addr-pin,
.sb-addr-hidden .leaflet-tooltip.canvas-addr-label,
.sp-lot-drawn .canvas-addr-pin,
.sp-lot-drawn .leaflet-tooltip.canvas-addr-label { display: none; }
/* The address on the street in front of the lot (D131): the label's pill
   with a pin mark, outside the lot beyond the Street side chip. One line;
   a long typed street ends in an ellipsis. */
.sb-addr-chip { position: absolute; transform: translate(-50%, -50%);
  display: inline-flex; align-items: center; gap: 5px; box-sizing: border-box; max-width: 220px;
  font-family: 'DM Sans', sans-serif; font-size: 12px; font-weight: 600; line-height: 1.3;
  color: var(--pool-dark); background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-pill); padding: 4px 11px 4px 9px; white-space: nowrap;
  box-shadow: 0 1px 4px rgba(0,0,0,.14); }
.sb-addr-chip svg { flex: none; }
.sb-addr-text { overflow: hidden; text-overflow: ellipsis; }

/* Dropzone */
.dropzone { border: 1.5px dashed var(--border-2); border-radius: var(--r); padding: 28px 20px;
  text-align: center; background: var(--surface-2); transition: all .18s ease; cursor: pointer; }
.dropzone:hover, .dropzone.armed { border-color: var(--teal-border); background: var(--pool-light); }
.dropzone .ic { display: flex; justify-content: center; margin-bottom: 8px; }
.dropzone .t { font-weight: 600; font-size: 14px; color: var(--text); }
.dropzone .d { font-size: 12.5px; color: var(--text-3); margin-top: 4px; }
.file-chip { display: none; align-items: center; gap: 10px; background: var(--surface);
  border: 1px solid var(--teal-border); border-radius: var(--r-sm); padding: 10px 14px;
  margin-top: 12px; font-size: 13px; color: var(--pool-dark); }
.file-chip.show { display: flex; }
.file-chip .x { margin-left: auto; cursor: pointer; color: var(--text-3); font-size: 16px; line-height: 1; }
.recap { margin-top: 22px; font-size: 12.5px; color: var(--text-3); text-align: center; }

/* Imagery fallback (imagery.js, Oct 6 2026). On the backup photos the
   credit line says so; nothing else is added. The card apologizes when no photos load at
   all, at the top of the map clear of the zoom control, and offers Try
   again while the map keeps trying in the background. */
.imagery-card { position: absolute; top: 10px; left: 56px; right: 10px; z-index: 1000;
  max-width: 360px; display: flex; gap: 10px; align-items: flex-start;
  font-family: 'DM Sans', sans-serif; color: var(--text-2); background: var(--surface);
  border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px;
  box-shadow: 0 4px 16px rgba(4,62,72,.16); }
.imagery-card-icon { flex: 0 0 auto; width: 34px; height: 34px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: var(--pool-dark); background: var(--priority-bg); }
.imagery-card-h { font-family: 'Fraunces', serif; font-size: 15px; font-weight: 600;
  line-height: 1.25; color: var(--pool-dark); }
.imagery-card-b { font-size: 12.5px; line-height: 1.45; margin-top: 3px; }
.imagery-card-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; margin-top: 9px; }
.imagery-card-link { font: 600 12.5px 'DM Sans', sans-serif; color: var(--pool-dark);
  text-decoration: underline; text-underline-offset: 2px; }
/* The confirm buttons wait for a photo on the map (site-plan-2.js). */
.btn.is-photo-wait { background: var(--border-2); border-color: var(--border-2); color: #fff; cursor: not-allowed; }
.imagery-card-btn { margin-top: 0; font: 600 12.5px 'DM Sans', sans-serif;
  color: var(--pool-dark); background: var(--surface); border: 1px solid var(--pool-deep);
  border-radius: var(--r-pill); padding: 6px 14px; min-height: 32px; cursor: pointer; }
.imagery-card-btn:disabled { color: var(--text-2); border-color: var(--border-2); cursor: default; }

/* The steps as a list (D172, from the "Steps, as many as fit" prototype):
   each set a line in its own box that opens in place (its name, where it
   sits, its size at the right), the three kinds to add as tiles while
   there are none and as chips under Add more after, the ask while a
   place is picked on the photo (amber, as the places lit on the map
   are), the Removed line with Undo, and the line over the rows when a
   change of the pool took some off. */
.ps-list { display: flex; flex-direction: column; gap: 10px; }
.ps-intro { margin: 0; font-family: 'DM Sans', sans-serif; font-size: 12.5px; color: var(--text-3); line-height: 1.45; }
.ps-sets { display: flex; flex-direction: column; gap: 6px; }
.ps-set { border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface); }
.ps-set.is-open { border: 1.5px solid var(--pool); }
.ps-set-head { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 52px; padding: 6px 10px;
  background: none; border: 0; cursor: pointer; text-align: left; font-family: 'DM Sans', sans-serif; color: inherit; }
.ps-set-head[aria-expanded="true"] .pool-row-chev { transform: rotate(90deg); }
.ps-set-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.ps-set-name { font-size: 13.5px; font-weight: 600; color: var(--text); }
.ps-set-where { font-size: 12.5px; color: var(--text-2); line-height: 1.35; }
.ps-set-spec { margin-left: auto; flex: none; font-family: 'DM Mono', monospace; font-size: 12px; color: var(--text-2); white-space: nowrap; }
.ps-set-body { display: flex; flex-direction: column; gap: 10px; padding: 0 10px 10px; }
.ps-line { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.ps-line-note { font-family: 'DM Sans', sans-serif; font-size: 12.5px; color: var(--text-2); }
.ps-stepper .pool-step-value { min-width: 0; }
.ps-step-words { font-family: 'DM Sans', sans-serif; font-size: 12.5px; white-space: nowrap; }
.ps-stepper .pool-step-btn svg { display: block; margin: 0 auto; }
.ps-helper { margin-top: -4px; color: var(--text-3); }
.ps-note { margin: 0; font-family: 'DM Sans', sans-serif; font-size: 12.5px; line-height: 1.45; color: var(--sun-dark);
  background: var(--sun-light); border-radius: var(--r-sm); padding: 6px 8px; }
.ps-acts { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; }
.ps-acts .pool-btn-outline { height: 40px; }
.ps-tiles { display: flex; flex-direction: column; gap: 8px; }
.ps-tile[aria-disabled="true"] { cursor: default; background: var(--surface-2); }
.ps-tile[aria-disabled="true"]:hover { border-color: var(--border-2); }
.ps-tile[aria-disabled="true"] .yd-tile-art { opacity: .45; }
.ps-tile[aria-disabled="true"] .yd-tile-title { color: var(--text-3); }
.ps-tile.is-on, .ps-chip.is-on { border-color: var(--sun); box-shadow: 0 0 0 2px var(--sun); }
.ps-art-pool { fill: var(--pool-light); stroke: var(--pool); stroke-width: 1.5; }
.ps-art-tread { fill: none; stroke: var(--pool-dark); stroke-width: 1.2; }
.ps-more-label { margin-top: 2px; }
.ps-chips { display: flex; gap: 6px; }
.ps-pick { display: flex; flex-direction: column; gap: 4px; padding: 6px 10px; border: 1.5px dashed var(--sun);
  border-radius: var(--r-sm); background: var(--sun-light); }
.ps-pick-line { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.ps-pick .pool-pick-words { color: var(--text); }
.ps-why { margin: 0 0 4px; font-family: 'DM Sans', sans-serif; font-size: 12.5px; line-height: 1.4; color: var(--sun-dark); }
.ps-pick .pool-hint { margin: 0 0 4px; }
.ps-gone { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 48px;
  padding: 0 6px 0 12px; border: 1px dashed var(--border-2); border-radius: var(--r-sm);
  font-family: 'DM Sans', sans-serif; font-size: 13px; color: var(--text-2); }
.ps-notice { display: flex; flex-direction: column; gap: 2px; margin-bottom: 8px; padding: 8px 10px 2px;
  border: 1px solid var(--sun); border-radius: var(--r-sm); background: var(--sun-light); }
.ps-notice[hidden] { display: none; }
.ps-notice-text { margin: 0; font-family: 'DM Sans', sans-serif; font-size: 13px; line-height: 1.4; color: var(--text); }
.ps-notice-acts { display: flex; gap: 16px; }
/* On the map: the places a set can go while one is picked, lit in amber
   (a ring on a corner, a bar beside a wall or an end), the others grey
   with a cross or dashed; and the open set's ground outlined in amber. */
.ps-target-icon { background: none; border: 0; }
.ps-target { position: absolute; left: 50%; top: 50%; width: 16px; height: 16px; margin: -8px 0 0 -8px; border-radius: 50%;
  box-sizing: border-box; }
.ps-target.is-ok { background: var(--surface); border: 2px solid var(--sun-dark); box-shadow: 0 0 0 6px color-mix(in srgb, var(--sun) 35%, transparent); }
.ps-target.is-off { width: 12px; height: 12px; margin: -6px 0 0 -6px; background: var(--surface-2); border: 2px solid var(--text-3); }
.ps-target.is-off::before, .ps-target.is-off::after { content: ''; position: absolute; left: 50%; top: 50%; width: 8px; height: 1.5px;
  margin: -0.75px 0 0 -4px; background: var(--text-3); transform: rotate(45deg); }
.ps-target.is-off::after { transform: rotate(-45deg); }
.ps-target-icon:focus-visible { outline: 2px solid var(--pool); outline-offset: 2px; border-radius: 50%; }
.ps-target-hit:focus-visible { outline: none; stroke: var(--pool); stroke-opacity: .35; }
@keyframes ps-glow { 0%, 100% { opacity: .55; } 50% { opacity: .15; } }
.ps-target.is-ok { animation: ps-ring 1.4s ease-in-out infinite; }
@keyframes ps-ring { 0%, 100% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--sun) 45%, transparent); } 50% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--sun) 12%, transparent); } }
.ps-target-glow { animation: ps-glow 1.4s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .ps-target.is-ok, .ps-target-glow { animation: none; } }

/* The cover (D191), under the coping in the Coping and cover row: a
   small heading, chips that wrap, the end switch, and what the row reads
   off the drawing: a teal note where the cover has what it needs, an
   amber one (the yard's colour for what is planned) where it does not,
   a quiet one for a rule. */
.cv { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
.cv-sub { font-family: 'DM Sans', sans-serif; font-size: 11px; font-weight: 700; letter-spacing: 0.06em; color: var(--text-2); }
.cv-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.cv-chips .pool-detail-chip { flex: 1 1 auto; min-width: 31%; padding: 0 10px; }
.cv-read { margin: 0; border-radius: var(--r-sm); padding: 8px 10px; display: flex; flex-direction: column; gap: 8px; }
.cv-read--ok { background: var(--pool-light); }
.cv-read--rule { background: var(--surface-2); }
.cv-read--warn { background: var(--sun-light); border: 1px dashed var(--sun); }
.cv-read--warn .cv-read-text { color: var(--sun-dark); }
.cv-read-text { margin: 0; font-family: 'DM Sans', sans-serif; font-size: 12.5px; line-height: 1.45; color: var(--pool-deep); }
.cv-read .pool-over-fixes { flex-direction: row; flex-wrap: wrap; }
.cv-read .pool-over-fix { width: auto; }

/* Fit the lot (D192): the third button in Leaflet's zoom bar, its glyph
   centred as the + and − are. */
.leaflet-bar a.leaflet-control-zoom-fit { display: flex; align-items: center; justify-content: center; }
.leaflet-control-zoom-fit svg { display: block; }
