/*
 * CurbCheck — components: the search card, the result list, the detail sheet.
 * Shell and layout live in styles.css; every value comes from tokens.css.
 *
 * Two rules here are safety rules, not taste:
 *  - A verdict is never carried by colour alone (SPEC §11): every chip holds a
 *    word, a symbol, and the same dash pattern the map draws.
 *  - The caveat block is never a disclosure (UX_AUDIT (f) 5), so it has no
 *    collapsed state to style.
 */

/* ---- Search card ------------------------------------------------------- */

.search-card {
  display: flex;
  flex-direction: column;
  gap: var(--s-7);
}

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

.field {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  min-width: 0;
}

.advanced .field {
  gap: var(--s-2);
}

label,
.field-label,
.results-heading,
.as-posted-eyebrow {
  font-size: var(--t-micro);
  font-weight: var(--w-semibold);
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  color: var(--c-text-muted);
}

.text-input {
  width: 100%;
  min-width: 0;
  min-height: var(--tap-min);
  padding: 0 var(--s-6);
  border: 0;
  border-radius: var(--r-lg);
  background: var(--c-surface);
  box-shadow:
    inset 0 0 0 1px var(--c-border-strong),
    var(--e-1);
  font-size: var(--t-body);
  font-variant-numeric: tabular-nums;
  transition:
    box-shadow var(--m-fast) var(--ease-out),
    background var(--m-fast) var(--ease-out);
}

.text-input::placeholder {
  color: var(--c-text-muted);
}

.text-input:hover {
  box-shadow:
    inset 0 0 0 1px var(--c-text-muted),
    var(--e-1);
}

.text-input:focus-visible {
  box-shadow:
    inset 0 0 0 1.5px var(--c-accent),
    var(--focus-ring);
}

input[type="date"].text-input,
input[type="time"].text-input,
input[type="number"].text-input {
  padding: 0 var(--s-5);
}

.when-row {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: var(--s-4);
}

.sub-field {
  display: flex;
  align-items: center;
  gap: var(--s-4);
}

.sub-field[hidden] {
  display: none;
}

.sub-field .text-input {
  width: 140px;
}

.summary-line {
  margin: 0;
  font-size: var(--t-small);
  font-variant-numeric: tabular-nums;
  color: var(--c-text-secondary);
}

.hint {
  margin: 0;
  font-size: var(--t-caption);
  color: var(--c-text-secondary);
}

.hint:empty {
  display: none;
}

/* Chip groups double as the duration, walk-radius, and ranking controls. They
   are `role="radiogroup"` with roving tabindex, so one Tab stop each. */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
}

/* 12 px, not 16: at 16 the four `Prefer` chips measured 362 px against a 358 px
   rail and wrapped 3 + 1, leaving the *selected* default alone on its own line.
   The four walk radii still wrap 4 + 1, which is the split they mean — presets,
   then Custom. */
.chip {
  min-height: 34px;
  padding: 0 var(--s-5);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-pill);
  background: var(--c-chip);
  backdrop-filter: var(--blur-chip);
  -webkit-backdrop-filter: var(--blur-chip);
  color: var(--c-text-secondary);
  font-size: var(--t-small);
  font-weight: var(--w-medium);
  white-space: nowrap;
  transition:
    background var(--m-fast) var(--ease-out),
    color var(--m-fast) var(--ease-out),
    border-color var(--m-fast) var(--ease-out),
    transform var(--m-instant) var(--ease-out);
}

.chip:hover {
  border-color: var(--c-accent);
  color: var(--c-text);
}

.chip:active {
  transform: scale(0.97);
}

.chip[aria-checked="true"] {
  background: var(--c-accent-soft);
  border-color: var(--c-accent);
  color: var(--c-accent-ink);
  font-weight: var(--w-semibold);
}

.chip[aria-disabled="true"] {
  opacity: 0.55;
  cursor: default;
}

.advanced {
  margin-top: var(--s-3);
  font-size: var(--t-small);
}

.advanced > summary {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  width: fit-content;
  padding: var(--s-2) var(--s-4);
  border-radius: var(--r-pill);
  list-style: none;
  color: var(--c-text-secondary);
  font-size: var(--t-caption);
  font-weight: var(--w-medium);
}

.advanced > summary::-webkit-details-marker {
  display: none;
}

.advanced > summary::before {
  content: "›";
  display: inline-block;
  transition: transform var(--m-fast) var(--ease-out);
}

.advanced[open] > summary::before {
  transform: rotate(90deg);
}

.advanced > summary:hover {
  background: var(--c-chip);
  color: var(--c-text);
}

.advanced-body {
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
  margin-top: var(--s-5);
  padding: var(--s-5) var(--s-6);
  border-radius: var(--r-lg);
  background: var(--c-surface-sunken);
  box-shadow: inset 0 0 0 1px var(--c-border);
}

.advanced label {
  display: flex;
  justify-content: space-between;
  gap: var(--s-4);
  text-transform: none;
  letter-spacing: 0;
  font-weight: var(--w-medium);
  color: var(--c-text-secondary);
}

.advanced output {
  font-variant-numeric: tabular-nums;
  font-weight: var(--w-semibold);
  color: var(--c-text);
}

input[type="range"] {
  width: 100%;
  accent-color: var(--c-accent);
}

.primary {
  min-height: var(--tap-min);
  padding: 0 var(--s-6);
  border: 0;
  border-radius: var(--r-lg);
  background: var(--c-accent);
  /* Not #fff: --c-accent is a *light* blue in dark mode, and white on it
     measures 2:1. The inverse token flips with the scheme and keeps 7:1. */
  color: var(--c-text-inverse);
  font-size: var(--t-body);
  font-weight: var(--w-semibold);
  letter-spacing: var(--track-tight);
  box-shadow: var(--e-2);
  transition:
    background var(--m-fast) var(--ease-out),
    transform var(--m-instant) var(--ease-out),
    box-shadow var(--m-fast) var(--ease-out);
}

.primary:hover {
  background: var(--c-accent-hover);
  box-shadow: var(--e-lift);
}

.primary:active {
  transform: translateY(1px);
}

.primary:disabled {
  background: var(--c-text-muted);
  color: var(--c-text-inverse);
  cursor: progress;
  box-shadow: none;
}

/* The stale marker: the walk radius and the window are server-side inputs, so
   changing one makes what is on screen an answer to a different question. */
.primary.is-stale {
  box-shadow:
    0 0 0 3px var(--c-select-glow),
    var(--e-2);
}

.stale-note {
  margin: calc(var(--s-4) * -1) 0 0;
  font-size: var(--t-caption);
  color: var(--v-ambiguous-ink);
}

.stale-note[hidden] {
  display: none;
}

.ghost {
  min-height: 32px;
  padding: 0 var(--s-5);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--c-text-secondary);
  font-size: var(--t-caption);
  font-weight: var(--w-medium);
  transition:
    background var(--m-fast) var(--ease-out),
    color var(--m-fast) var(--ease-out);
}

.ghost:hover {
  background: var(--c-chip);
  color: var(--c-text);
}

/* The one-line summary the search card collapses to after a search. */
.search-summary {
  display: flex;
  align-items: center;
  gap: var(--s-5);
  padding: var(--s-5) var(--s-5) var(--s-5) var(--s-6);
  border-radius: var(--r-lg);
  background: var(--c-surface);
  box-shadow: var(--e-1);
}

.search-summary[hidden] {
  display: none;
}

.search-summary-text {
  flex: 1 1 auto;
  margin: 0;
  min-width: 0;
  font-size: var(--t-small);
  font-variant-numeric: tabular-nums;
  line-height: var(--lh-tight);
}

.search-summary-text b {
  display: block;
  font-size: var(--t-body);
  font-weight: var(--w-semibold);
  letter-spacing: var(--track-tight);
}

.search-summary .ghost {
  flex: 0 0 auto;
}

/* ---- Autocomplete (ARIA combobox) -------------------------------------- */

.combobox {
  position: relative;
}

.ac-list {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + var(--s-3));
  z-index: 12;
  max-height: 320px;
  overflow-y: auto;
  overscroll-behavior: contain;
  list-style: none;
  margin: 0;
  padding: var(--s-2);
  border-radius: var(--r-lg);
  border: 1px solid var(--c-glass-border);
  background: var(--c-glass-raised);
  backdrop-filter: var(--blur-panel);
  -webkit-backdrop-filter: var(--blur-panel);
  box-shadow: var(--e-3);
}

.ac-list[hidden] {
  display: none;
}

.ac-option {
  display: flex;
  align-items: center;
  gap: var(--s-5);
  padding: var(--s-4) var(--s-5);
  border-radius: var(--r-md);
  cursor: pointer;
}

.ac-option[aria-selected="true"],
.ac-option:hover {
  background: var(--c-accent-soft);
}

.ac-glyph {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: var(--r-sm);
  background: var(--c-surface-sunken);
  color: var(--c-text-secondary);
  font-size: var(--t-small);
}

.ac-body {
  min-width: 0;
}

.ac-label {
  display: block;
  font-size: var(--t-small);
  font-weight: var(--w-medium);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ac-secondary {
  display: block;
  font-size: var(--t-caption);
  color: var(--c-text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ac-option-pin .ac-glyph {
  background: var(--c-accent-soft);
  color: var(--c-accent-ink);
}

/* ---- Verdict chips ----------------------------------------------------- */

/* One swatch, one word. The swatch's gradient is set from web/verdicts.js, the
   same table the map paints from, so a chip is the line it points at. */
.verdict-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--s-4);
  padding: 3px var(--s-5) 3px var(--s-4);
  border-radius: var(--r-pill);
  border: 1px solid transparent;
  font-size: var(--t-micro);
  font-weight: var(--w-semibold);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  white-space: nowrap;
}

.verdict-pattern {
  width: 14px;
  height: 6px;
  flex: 0 0 auto;
  border-radius: var(--r-pill);
}

.verdict-legal {
  background: var(--v-legal-soft);
  color: var(--v-legal-ink);
}

/* Legality by absence. Same colour family, deliberately unfilled: a dashed
   outline says "nothing was read here" where a solid chip would say "a sign
   said yes" (UX_AUDIT P0-1). */
.verdict-absence {
  background: transparent;
  color: var(--v-legal-ink);
  border: 1px dashed color-mix(in srgb, var(--v-legal) 55%, transparent);
}

.verdict-ambiguous {
  background: var(--v-ambiguous-soft);
  color: var(--v-ambiguous-ink);
}

.verdict-illegal {
  background: var(--v-illegal-soft);
  color: var(--v-illegal-ink);
}

.verdict-no_data {
  background: var(--v-nodata-soft);
  color: var(--v-nodata-ink);
}

/* ---- Count pills: the verdict filter and the honest totals -------------- */

/* A 2x2 grid, not a wrapped row: four pills of four different widths wrap
   3 + 1 and read as a ragged sentence rather than as a stat block. */
.stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-3);
  margin-top: var(--s-6);
}

.stats:empty {
  display: none;
}

.stat-pill {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-height: 30px;
  padding: 0 var(--s-5);
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  font-size: var(--t-caption);
  line-height: 1;
  transition:
    opacity var(--m-fast) var(--ease-out),
    box-shadow var(--m-instant) var(--ease-out);
}

.pill-swatch {
  width: 12px;
  height: 5px;
  flex: 0 0 auto;
  border-radius: var(--r-pill);
}

.pill-count {
  font-weight: var(--w-semibold);
}

.pill-word {
  opacity: 0.8;
}

/* Pressed out: the pill keeps its count — hiding a verdict must never hide how
   much of it there is (UX_AUDIT (f) 3) — and says so by going flat and struck. */
.stat-pill[aria-checked="false"] {
  background: transparent;
  border-color: var(--c-border-strong);
  color: var(--c-text-muted);
}

.stat-pill[aria-checked="false"] .pill-swatch {
  opacity: 0.35;
}

.stat-pill[aria-checked="false"] .pill-word {
  text-decoration: line-through;
}

.stat-legal[aria-checked="true"] {
  background: var(--v-legal-soft);
  color: var(--v-legal-ink);
}

.stat-ambiguous[aria-checked="true"] {
  background: var(--v-ambiguous-soft);
  color: var(--v-ambiguous-ink);
}

.stat-illegal[aria-checked="true"] {
  background: var(--v-illegal-soft);
  color: var(--v-illegal-ink);
}

.stat-no_data[aria-checked="true"] {
  background: var(--v-nodata-soft);
  color: var(--v-nodata-ink);
}

/* ---- "2 things to know" ------------------------------------------------ */

.caveat-summary:empty {
  display: none;
}

.caveat-disclosure {
  margin-top: var(--s-3);
}

.caveat-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-4) var(--s-2) var(--s-3);
  border: 0;
  border-radius: var(--r-pill);
  background: transparent;
  font-size: var(--t-caption);
  font-weight: var(--w-medium);
  color: var(--c-text-secondary);
}

.caveat-toggle::before {
  content: "›";
  transition: transform var(--m-fast) var(--ease-out);
}

.caveat-toggle[aria-expanded="true"]::before {
  transform: rotate(90deg);
}

.caveat-toggle:hover {
  background: var(--c-chip);
  color: var(--c-text);
}

/* ---- Result list ------------------------------------------------------- */

.results-heading[hidden] {
  display: none;
}

.results-heading {
  margin: var(--s-7) 0 var(--s-3);
}

.results-region {
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
}

/* The region is a hand-off target, not a control: it is out of the tab order
   and takes focus only when the collapsing search card would otherwise drop it
   (`showResponse`). At 2,113 px tall the standard ring drew a 4 px box round the
   whole scroll height, nearly all of it off screen. The cue is the status line
   announcing the new count and the next Tab landing on result #1. */
.results-region:focus-visible {
  box-shadow: none;
}

.results-count {
  margin: 0;
  font-size: var(--t-small);
  color: var(--c-text-secondary);
}

.results {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  width: 100%;
  padding: var(--s-5) var(--s-6) var(--s-4);
  text-align: left;
  border: 0;
  border-radius: var(--r-lg);
  background: var(--c-surface);
  box-shadow:
    inset 0 0 0 1px var(--c-border),
    var(--e-1);
  transition:
    transform var(--m-fast) var(--ease-out),
    box-shadow var(--m-fast) var(--ease-out);
}

/* No left colour bar: the chip is the verdict, and 12 cards each wearing a
   4 px stripe read as a striped column rather than as twelve answers. */
.card:hover,
.card.is-hovered {
  transform: translateY(-2px);
  box-shadow:
    inset 0 0 0 1px var(--c-border),
    var(--e-lift);
}

/* Selection is a ring, not a fill: a tinted card competes with the verdict
   chip for the same job, and the ring survives dark mode unchanged. */
.card[aria-pressed="true"] {
  box-shadow:
    0 0 0 2px var(--c-accent),
    0 0 0 5px var(--c-select-glow),
    var(--e-lift);
}

.card-head {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  margin-bottom: var(--s-2);
}

.card-rank {
  min-width: 1.4em;
  font-size: var(--t-caption);
  font-weight: var(--w-medium);
  color: var(--c-text-muted);
}

.card-rank::before {
  content: "#";
  opacity: 0.6;
}

.card-street {
  font-size: var(--t-body);
  font-weight: var(--w-medium);
  letter-spacing: var(--track-tight);
  line-height: var(--lh-tight);
}

.card-cross {
  font-size: var(--t-caption);
  line-height: var(--lh-normal);
  color: var(--c-text-muted);
}

/* One bold number — the walk — then a second for the price when there is one.
   Everything else on this row is muted small text. */
.card-metrics {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-5);
  margin-top: var(--s-4);
}

.card-walk {
  font-size: var(--t-lead);
  font-weight: var(--w-semibold);
  letter-spacing: var(--track-tight);
  white-space: nowrap;
}

.card-unit {
  font-size: var(--t-caption);
  font-weight: var(--w-regular);
  color: var(--c-text-muted);
}

.card-price {
  font-size: var(--t-body);
  font-weight: var(--w-semibold);
  white-space: nowrap;
}

.card-capacity {
  font-size: var(--t-caption);
  color: var(--c-text-muted);
}

.card-reason {
  margin-top: var(--s-3);
  font-size: var(--t-caption);
  line-height: var(--lh-normal);
  color: var(--c-text-secondary);
}

.card-reason-absence {
  color: var(--v-nodata-ink);
}

.show-more {
  align-self: flex-start;
}

/* Collapsed verdict groups. Always present, always counted from the server's
   `counts`, even when the group is empty (UX_AUDIT (f) 7). */
.group {
  border-radius: var(--r-lg);
  background: var(--c-surface);
  box-shadow: var(--e-1);
  overflow: hidden;
}

.group-toggle {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  width: 100%;
  min-height: var(--tap-min);
  padding: var(--s-4) var(--s-6);
  border: 0;
  background: transparent;
  text-align: left;
  font-size: var(--t-small);
  font-weight: var(--w-medium);
}

.group-toggle::after {
  content: "›";
  margin-left: auto;
  color: var(--c-text-muted);
  transition: transform var(--m-fast) var(--ease-out);
}

.group-toggle[aria-expanded="true"]::after {
  transform: rotate(90deg);
}

.group-count {
  color: var(--c-text-secondary);
  font-variant-numeric: tabular-nums;
}

.group-body {
  padding: 0 var(--s-4) var(--s-4);
}

.group-body[hidden] {
  display: none;
}

.group-body .results {
  gap: var(--s-3);
}

.group-note {
  margin: 0 0 var(--s-3);
  padding: 0 var(--s-3);
  font-size: var(--t-caption);
  color: var(--c-text-secondary);
}

/* ---- Loading skeletons ------------------------------------------------- */

.skeleton-card {
  height: 96px;
  border-radius: var(--r-lg);
  background: var(--c-surface-sunken);
  box-shadow: inset 0 0 0 1px var(--c-border);
}

.progress-text {
  margin: 0;
  font-size: var(--t-small);
  color: var(--c-text-secondary);
}

/* ---- Detail sheet ------------------------------------------------------ */

.detail {
  position: absolute;
  right: var(--s-6);
  top: var(--s-6);
  /* Stops one band short of the bottom so the OpenStreetMap credit and the
     About & data button are never underneath it. An attribution nobody can
     read or click is not an attribution. */
  bottom: calc(var(--s-6) + 30px);
  width: var(--sheet-w);
  max-width: calc(100% - var(--s-6) * 2);
  z-index: 8;
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-radius: var(--r-2xl);
  border: 1px solid var(--c-glass-border);
  background: var(--c-glass-raised);
  backdrop-filter: var(--blur-panel);
  -webkit-backdrop-filter: var(--blur-panel);
  box-shadow: var(--e-sheet);
  overflow: hidden;
  animation: sheet-in var(--m-base) var(--ease-out);
}

.detail[hidden] {
  display: none;
}

@keyframes sheet-in {
  from {
    opacity: 0;
    transform: translateX(12px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

.detail-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0 var(--s-7) var(--s-9);
}

.detail-header {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-start;
  gap: var(--s-5);
  padding: var(--s-6) var(--s-7) var(--s-5);
  border-bottom: 1px solid var(--c-glass-border);
}

.detail-heading {
  min-width: 0;
}

.detail-title {
  flex: 1 1 auto;
  margin: 0;
  font-size: var(--t-title);
  font-weight: var(--w-semibold);
}

.detail-sub {
  margin: var(--s-2) 0 0;
  font-size: var(--t-caption);
  color: var(--c-text-secondary);
}

.detail-close {
  flex: 0 0 auto;
  min-width: var(--tap-min);
  min-height: 34px;
  padding: 0 var(--s-5);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-pill);
  background: transparent;
  font-size: var(--t-caption);
  font-weight: var(--w-medium);
  color: var(--c-text-secondary);
}

.detail-close:hover {
  background: var(--c-chip);
  color: var(--c-text);
}

.detail h3 {
  margin: var(--s-8) 0 var(--s-4);
  font-size: var(--t-caption);
  font-weight: var(--w-semibold);
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  color: var(--c-text-muted);
}

.detail h4 {
  margin: var(--s-5) 0 var(--s-3);
  font-size: var(--t-small);
  font-weight: var(--w-semibold);
}

.detail-verdict {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  margin-top: var(--s-6);
  padding: var(--s-6);
  border-radius: var(--r-lg);
  background: var(--c-surface);
  box-shadow: var(--e-1);
}

.detail-verdict-legal {
  background: var(--v-legal-soft);
}

.detail-verdict-ambiguous {
  background: var(--v-ambiguous-soft);
}

.detail-verdict-illegal {
  background: var(--v-illegal-soft);
}

.detail-verdict-no_data {
  background: var(--v-nodata-soft);
}

/* The practical answer. The largest thing in the sheet, because it is the one
   line a driver reads before deciding. */
.detail-headline {
  margin: 0;
  font-size: var(--t-lead);
  line-height: var(--lh-tight);
  letter-spacing: var(--track-tight);
  font-weight: var(--w-semibold);
}

/* The window and the rule that decided it. Body ink, not muted: this is the
   sentence that changes a decision, and UX_AUDIT (e) 9 puts a floor of 14 px
   under anything a parking decision depends on. */
.detail-why {
  margin: 0;
  font-size: var(--t-body);
  line-height: var(--lh-normal);
  color: var(--c-text);
}

/* "Before you park" — every caveat, always open, directly under the verdict. */
.caveat-block {
  margin-top: var(--s-5);
  padding: var(--s-5) var(--s-6);
  border-radius: var(--r-lg);
  background: var(--v-ambiguous-soft);
  color: var(--v-ambiguous-ink);
  box-shadow: inset 3px 0 0 var(--v-ambiguous);
}

.caveat-block h3 {
  margin: 0 0 var(--s-3);
  color: inherit;
}

.caveat-block ul {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: var(--t-small);
  line-height: var(--lh-normal);
}

.caveat-block li + li {
  margin-top: var(--s-3);
}

.notice {
  margin: var(--s-5) 0 0;
  padding: var(--s-5) var(--s-6);
  border-radius: var(--r-lg);
  font-size: var(--t-small);
  line-height: var(--lh-normal);
  background: var(--c-surface-sunken);
  box-shadow: inset 3px 0 0 var(--c-border-strong);
}

.notice-ambiguous {
  background: var(--v-ambiguous-soft);
  color: var(--v-ambiguous-ink);
  box-shadow: inset 3px 0 0 var(--v-ambiguous);
}

.notice-no_data {
  background: var(--v-nodata-soft);
  color: var(--v-nodata-ink);
  box-shadow: inset 3px 0 0 var(--v-nodata);
}

.sign-card {
  margin-bottom: var(--s-5);
  padding: var(--s-5) var(--s-6);
  border-radius: var(--r-lg);
  background: var(--c-surface);
  box-shadow: var(--e-1);
}

.as-posted-eyebrow {
  display: block;
  margin-bottom: var(--s-3);
  font-size: var(--t-micro);
  font-weight: var(--w-semibold);
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  color: var(--c-text-muted);
}

/* Raw sign text, quoted verbatim (SPEC §10). Wrapped, never truncated, never
   scrolled sideways. */
.as-posted {
  margin: 0;
  padding: var(--s-5) var(--s-6);
  border-radius: var(--r-md);
  background: var(--c-surface-sunken);
  box-shadow: inset 0 0 0 1px var(--c-border-strong);
  font-family: var(--font-mono);
  font-size: var(--t-small);
  line-height: var(--lh-normal);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* The software's reading of the sign quoted above it. Indented under the
   verbatim block and labelled "Means:", so it can never be mistaken for a
   second quotation of the sign (SPEC §11). */
.sign-reading {
  margin: var(--s-3) 0 0;
  padding-left: var(--s-4);
  border-left: 2px solid var(--c-border-strong);
  font-size: var(--t-small);
  line-height: var(--lh-normal);
  color: var(--c-text);
}

/* Whether this sign is in force for the window is the whole question, so the
   edge carries the answer as well as the words do. The accent, never a verdict
   hue: a rule that applies can be the one permitting parking as easily as the
   one forbidding it, and a red edge on "2-hour metered parking" would say the
   opposite of what the sign says. */
.sign-reading-all,
.sign-reading-part {
  border-left-color: var(--c-accent);
}

.sign-reading-none {
  color: var(--c-text-secondary);
}

.sign-reading-unread {
  border-left-color: var(--v-ambiguous);
  color: var(--v-ambiguous-ink);
}

.sign-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-5);
  margin-top: var(--s-3);
  font-size: var(--t-caption);
  font-variant-numeric: tabular-nums;
  color: var(--c-text-secondary);
}

.collapse-toggle {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  width: 100%;
  min-height: 38px;
  padding: var(--s-3) var(--s-5);
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  background: transparent;
  text-align: left;
  font-size: var(--t-small);
  color: var(--c-text-secondary);
}

.collapse-toggle::after {
  content: "›";
  margin-left: auto;
  transition: transform var(--m-fast) var(--ease-out);
}

.collapse-toggle[aria-expanded="true"]::after {
  transform: rotate(90deg);
}

.collapse-body {
  margin-top: var(--s-4);
}

.collapse-body[hidden] {
  display: none;
}

.rule {
  margin-top: var(--s-4);
  padding-top: var(--s-4);
  border-top: 1px solid var(--c-border);
}

.rule-summary {
  margin: 0 0 var(--s-3);
  font-size: var(--t-small);
  font-weight: var(--w-semibold);
}

.facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s-2) var(--s-6);
  margin: 0;
  font-size: var(--t-caption);
  font-variant-numeric: tabular-nums;
}

.facts dt {
  color: var(--c-text-muted);
}

.facts dd {
  margin: 0;
  overflow-wrap: anywhere;
}

.detail-fineprint {
  margin: var(--s-7) 0 0;
  padding-top: var(--s-5);
  border-top: 1px solid var(--c-border);
  font-size: var(--t-caption);
  line-height: var(--lh-normal);
  color: var(--c-text-secondary);
}

/* ---- About & data ------------------------------------------------------ */

.detail-about .detail-scroll > section + section {
  margin-top: var(--s-8);
}

.detail-about p {
  font-size: var(--t-small);
  line-height: var(--lh-normal);
  color: var(--c-text-secondary);
}

.about-lede {
  margin: 0 0 var(--s-5);
  font-size: var(--t-small);
  color: var(--c-text-secondary);
}

.source-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
}

.source-list li {
  display: grid;
  gap: var(--s-1);
}

.source-name {
  font-size: var(--t-small);
  font-weight: var(--w-medium);
}

.source-id {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: var(--c-text-muted);
}

.source-role {
  font-size: var(--t-caption);
  color: var(--c-text-secondary);
}

/* SPEC §17 in full. Loose leading because it is 121 words of legal text and
   nobody reads a wall set at 1.45. */
.about-disclaimer {
  margin: 0;
  padding: var(--s-5) var(--s-6);
  border-radius: var(--r-lg);
  background: var(--v-ambiguous-soft);
  box-shadow: inset 3px 0 0 var(--v-ambiguous);
  color: var(--v-ambiguous-ink);
  font-size: var(--t-small);
  line-height: var(--lh-loose);
}

/* ---- Phone: the sheet is a second drawer layer over the rail ----------- */

@media (max-width: 1099px) {
  /* 520 px of a 1024 px screen, next to a 340 px rail, left 145 px of map and
     buried the legend under the sheet. The sheet is still the widest thing on
     the screen; it just stops short of hiding what the map has to keep saying.
     The second term keeps it off the rail too: 440 px next to the 340 px rail
     needs 816 px, and an iPad in portrait is 768, where the sheet's left edge
     used to sit 36 px over the results. */
  .detail {
    width: min(440px, calc(100% - 340px - var(--s-5) * 3));
    right: var(--s-5);
    top: var(--s-5);
    bottom: calc(var(--s-5) + 30px);
  }
}

@media (max-width: 640px) {
  .detail {
    right: 0;
    left: 0;
    top: var(--s-7);
    bottom: 0;
    width: auto;
    max-width: none;
    border-radius: var(--r-2xl) var(--r-2xl) 0 0;
    animation: sheet-up var(--m-slow) var(--ease-out);
  }

  @keyframes sheet-up {
    from {
      transform: translateY(14px);
      opacity: 0;
    }
    to {
      transform: translateY(0);
      opacity: 1;
    }
  }

  .detail-header {
    padding: var(--s-5) var(--s-6) var(--s-4);
  }

  .detail-scroll {
    padding: 0 var(--s-6) var(--s-9);
  }

  .when-row {
    grid-template-columns: 1fr 1fr;
  }
}

/* ---- Map furniture ----------------------------------------------------- */

/* Not MapLibre's teardrop: a disc reads at any zoom and cannot be mistaken for
   a verdict line (DESIGN_DIRECTION §6). */
.map-marker {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--c-marker);
  box-shadow:
    0 0 0 3px #fff,
    0 0 0 4px rgba(0, 0, 0, 0.25),
    0 4px 10px rgba(26, 86, 176, 0.45);
}

.ring-label {
  padding: var(--s-1) var(--s-4);
  border-radius: var(--r-pill);
  background: var(--c-surface-scrim);
  backdrop-filter: var(--blur-chip);
  -webkit-backdrop-filter: var(--blur-chip);
  box-shadow: var(--e-1);
  font-size: var(--t-micro);
  font-weight: var(--w-medium);
  color: var(--c-text-secondary);
  white-space: nowrap;
}

.ac-option-empty {
  color: var(--c-text-secondary);
  font-size: var(--t-small);
  cursor: default;
}
