/* Map exhibit — self-contained; nothing under web/css is imported.
   Tokens follow the validated reference palette (dataviz skill):
   light/dark are both selected, not auto-inverted. */

:root {
  color-scheme: light dark;
}

.ex-root {
  color-scheme: light;
  /* chrome */
  --page: #f9f9f7;
  --surface: #fcfcfb;
  --ink: #0b0b0b;
  --ink-2: #52514e;
  --ink-muted: #898781;
  --hairline: #e1e0d9;
  --border: rgba(11, 11, 11, 0.10);
  /* Layer 1 sequential ramp (blue, monotone lightness; validated) */
  --ramp-nd: #b7d3f6;
  --ramp-det: #6da7ec;
  --ramp-ge4: #256abf;
  --ramp-gt10: #0d366b;
  /* designed no-data blank (hatch, never white, never ramp) */
  --nodata-bg: #efeeea;
  --nodata-line: #b5b3aa;
  /* Layer 2 overlay (different channel: marks, not fill) */
  --orders: #eb6834;
  --orders-ring: #fcfcfb;
  /* Lead sequential ramp (violet — a different hue than the PFAS blue so
     the parameter switch is visible at a glance; monotone lightness;
     adjacent steps validated: worst ΔE 14.9 CVD / 16.4 normal) */
  --lead-le: #d3ccf1;
  --lead-aap: #a294e2;
  --lead-who: #6c56c6;
  --lead-al: #3b2a8c;
  /* Lead designed off-ladder states (validated all-pairs against the ramp
     and the order-mark orange; identity also carried by legend + tooltip) */
  --lead-zero: #cbb264;
  --lead-nd: #45a08a;
  /* Record-age fill mode (sepia ordinal ramp; deliberately a warm
     neutral family — not the band ramp's hue, not the mark orange) */
  --age-cur: #e3d3b5;
  --age-old: #bb8d52;
  --age-vold: #6f4d20;
  /* Arsenic model marks (county scale; validated vs the order-mark
     orange: worst pair ΔE 11.8 CVD) */
  --as-mark: #45a08a;
  /* USGS PFAS groundwater model marks (40-km block scale; hollow, the
     model grammar, in the PFAS blue family so the City→Well flip
     rhymes — reuses the validated ramp's #256abf step; validated as a
     pair vs the order-mark orange: ΔE 23.8 CVD / 34.1 normal, light) */
  --gw-mark: #256abf;
  /* Nitrate violation states (two KINDS of record fact, deliberately
     categorical hues, never a ramp: an MCL exceedance and an MR
     paperwork failure are not amounts of the same thing; validated
     all-pairs with the order-mark orange — worst pair ΔE 9.2 CVD
     light / 8.6 dark, normal-vision 21.8 / 18.7) */
  --nit-mcl: #b12e83;
  --nit-mr: #2a78d6;
  --nit-other: #1baf7a;
  /* Problem-penetration view (orders per ACS household, banded —
     computed within the commercial layer, displayed on categorical
     chemistry signal ZIPs). Orange = unreached (the mandate/order-mark
     semantic); blue ramp = reached, three steps (the validated blue
     ramp's own adjacent steps); suppressed = orange crosshatch
     (texture channel — a different pattern class and color than the
     grey no-record hatch). Cross-family pairs validated: orange vs
     each blue ΔE ≥ 23.8 CVD; grey vs palest blue 14.6 CVD / 15.1
     normal (light), 24.6 CVD (dark). */
  --pen-zero: #eb6834;
  --pen-x-bg: #f6d9c8;
  --pen-x-line: #eb6834;
  --pen-lo: #b7d3f6;
  --pen-mid: #6da7ec;
  --pen-hi: #256abf;
  --pen-nohh: #a8a69d;
  /* USGS ambient nitrate marks (county scale; a sequential teal ramp
     for the shared nitrate ladder bands, FILLED SQUARES — the teal
     family says "USGS county-scale knowledge" next to the arsenic
     marks, and filled-vs-hollow separates a measured summary from a
     model. Ordinal ramp validated per mode (monotone L, ΔL gaps,
     light-end contrast); cross-family vs the order-mark orange worst
     pair ΔE 9.4 CVD light / 9.0 dark, with shape + surface ring as
     the standing secondary encoding. The palest step sits at 2.52:1
     contrast (light) — relief carried by legend labels, counts and
     tooltips, per the exhibit's precedent.) */
  --nitamb-le: #57b0a0;
  --nitamb-s1: #358d7e;
  --nitamb-s2: #1e6a5e;
  --nitamb-mcl: #104a41;
  --nitamb-unres: #8a887f;
  /* SYR4 measured concentration marks (county scale, filled squares —
     the measured mark grammar; the same teal knowledge-family as the
     ambient squares and the arsenic model circles, so each City⇄Well
     flip rhymes while filled-vs-hollow keeps measured and modeled
     apart. Shared by the SYR4 nitrate and SYR4 arsenic layers, which
     never co-occur; band meaning is carried by the legend. The
     censored state (--syr4-cens) is a desaturated member of the same
     family: a bounded non-detect, in the value family, visibly not a
     ramp step; --syr4-unres is the neutral unresolved gray. */
  --syr4-le: #57b0a0;
  --syr4-b1: #358d7e;
  --syr4-b2: #1e6a5e;
  --syr4-mcl: #104a41;
  --syr4-cens: #7ba99b;
  --syr4-unres: #8a887f;
  /* map furniture */
  --state-border: #b9b7ae;
}

:root[data-theme="dark"] .ex-root {
  color-scheme: dark;
  --page: #0d0d0d;
  --surface: #1a1a19;
  --ink: #ffffff;
  --ink-2: #c3c2b7;
  --ink-muted: #898781;
  --hairline: #2c2c2a;
  --border: rgba(255, 255, 255, 0.10);
  --ramp-nd: #0d366b;
  --ramp-det: #256abf;
  --ramp-ge4: #6da7ec;
  --ramp-gt10: #b7d3f6;
  --nodata-bg: #232322;
  --nodata-line: #4c4c47;
  --orders: #d95926;
  --orders-ring: #1a1a19;
  --lead-le: #3b2a8c;
  --lead-aap: #6c56c6;
  --lead-who: #a294e2;
  --lead-al: #d3ccf1;
  --lead-zero: #cbb264;
  --lead-nd: #3f9d83;
  --age-cur: #55462c;
  --age-old: #a4753a;
  --age-vold: #e0c290;
  --as-mark: #3f9d83;
  --gw-mark: #3987e5; /* dark selected, not inverted; vs orange ΔE 26.8 CVD / 31.8 normal */
  --nit-mcl: #cc4fae;
  --nit-mr: #3987e5;
  --nit-other: #199e70;
  --pen-zero: #d95926;
  --pen-x-bg: #45291a;
  --pen-x-line: #d95926;
  --pen-lo: #0d366b;
  --pen-mid: #256abf;
  --pen-hi: #6da7ec;
  --pen-nohh: #7c7a72;
  --nitamb-le: #1a6f60;
  --nitamb-s1: #2f8f7d;
  --nitamb-s2: #57b0a0;
  --nitamb-mcl: #8ed3c6;
  --nitamb-unres: #85837a;
  --syr4-le: #1a6f60;
  --syr4-b1: #2f8f7d;
  --syr4-b2: #57b0a0;
  --syr4-mcl: #8ed3c6;
  --syr4-cens: #4f7d72;
  --syr4-unres: #85837a;
  --state-border: #4a4a45;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .ex-root {
    color-scheme: dark;
    --page: #0d0d0d;
    --surface: #1a1a19;
    --ink: #ffffff;
    --ink-2: #c3c2b7;
    --ink-muted: #898781;
    --hairline: #2c2c2a;
    --border: rgba(255, 255, 255, 0.10);
    --ramp-nd: #0d366b;
    --ramp-det: #256abf;
    --ramp-ge4: #6da7ec;
    --ramp-gt10: #b7d3f6;
    --nodata-bg: #232322;
    --nodata-line: #4c4c47;
    --orders: #d95926;
    --orders-ring: #1a1a19;
    --lead-le: #3b2a8c;
    --lead-aap: #6c56c6;
    --lead-who: #a294e2;
    --lead-al: #d3ccf1;
    --lead-zero: #cbb264;
    --lead-nd: #3f9d83;
    --age-cur: #55462c;
    --age-old: #a4753a;
    --age-vold: #e0c290;
    --as-mark: #3f9d83;
    --gw-mark: #3987e5;
    --nit-mcl: #cc4fae;
    --nit-mr: #3987e5;
    --nit-other: #199e70;
    --pen-zero: #d95926;
    --pen-x-bg: #45291a;
    --pen-x-line: #d95926;
    --pen-lo: #0d366b;
    --pen-mid: #256abf;
    --pen-hi: #6da7ec;
    --pen-nohh: #7c7a72;
    --nitamb-le: #1a6f60;
    --nitamb-s1: #2f8f7d;
    --nitamb-s2: #57b0a0;
    --nitamb-mcl: #8ed3c6;
    --nitamb-unres: #85837a;
    --syr4-le: #1a6f60;
    --syr4-b1: #2f8f7d;
    --syr4-b2: #57b0a0;
    --syr4-mcl: #8ed3c6;
    --syr4-cens: #4f7d72;
    --syr4-unres: #85837a;
    --state-border: #4a4a45;
  }
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
}

.ex-root {
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  background: var(--page);
  color: var(--ink);
  height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  font-size: 14px;
}

.ex-header {
  padding: 14px 20px 10px;
  border-bottom: 1px solid var(--hairline);
}

.ex-header h1 {
  font-size: 17px;
  font-weight: 650;
  margin: 0 0 3px;
}

.ex-header p {
  margin: 0;
  color: var(--ink-2);
  font-size: 12.5px;
  max-width: 72em;
}

.ex-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 22px;
  padding: 9px 20px;
  border-bottom: 1px solid var(--hairline);
  background: var(--surface);
  font-size: 13px;
}

.ex-controls label { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.ex-controls label.disabled { color: var(--ink-muted); cursor: default; }

/* Demo path: the active choice must be unmistakable at a glance —
   checked options get a filled pill, not just a radio dot. */
.param-switch label,
.ex-controls label.toggle {
  border-radius: 5px;
  padding: 2px 7px;
  border: 1px solid transparent;
}
.param-switch label:has(input:checked) {
  background: var(--ink);
  color: var(--surface);
  font-weight: 650;
}
.ex-controls label.toggle:has(input:checked) {
  border-color: var(--orders);
  font-weight: 650;
}
.ex-controls .spacer { flex: 1; }
.ex-controls button {
  font: inherit;
  color: var(--ink-2);
  background: none;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 3px 10px;
  cursor: pointer;
}
.ex-controls button:hover { color: var(--ink); }


.param-switch {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 3px 10px;
}
.param-tag {
  font-size: 10px;
  letter-spacing: 0.05em;
  color: var(--ink-muted);
}

/* The source/contaminant grid — the switcher is the client's table:
   columns are where a household's water comes from, rows are
   contaminants, and each cell names its data source. One click per
   cell; no nesting, no second switch. The private-well lead position
   is an empty cell: no record of any kind exists there. */
.source-grid {
  display: grid;
  grid-template-columns: auto auto auto;
  gap: 2px 8px;
  align-items: stretch;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 5px 10px 6px;
  font-size: 12px;
}
.source-grid .sg-corner { min-width: 0; }
.source-grid .sg-col {
  font-size: 10px;
  font-weight: 650;
  letter-spacing: 0.05em;
  color: var(--ink-muted);
  padding: 0 7px 2px;
}
.source-grid .sg-row {
  font-size: 10px;
  font-weight: 650;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-muted);
  align-self: center;
  padding-right: 2px;
}
.source-grid label {
  border-radius: 5px;
  padding: 1px 7px;
  border: 1px solid transparent;
}
.source-grid label:has(input:checked) {
  background: var(--ink);
  color: var(--surface);
  font-weight: 650;
}
/* The one cell that is a statement, not a view: city-water arsenic —
   its machine-readable record is compliance violations only. */
.source-grid .sg-static {
  color: var(--ink-muted);
  padding: 1px 7px;
  align-self: center;
  cursor: help;
}

/* Vintage dot-overlay legend swatches: the same two densities the map
   draws (dots = record age; the no-data hatch stays diagonal lines). */
.swatch.dots, .swatch.dots-dense {
  background-color: var(--age-swatch-bg, var(--lead-aap));
  background-image: radial-gradient(var(--ink) 1px, transparent 1.1px);
  background-size: 7px 7px;
}
.swatch.dots-dense { background-size: 4px 4px; }

.ex-main {
  flex: 1;
  display: flex;
  min-height: 0;
}

.ex-maparea {
  flex: 1;
  position: relative;
  min-width: 0;
  background: var(--surface);
}

#map {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  cursor: grab;
}
#map.dragging { cursor: grabbing; }

/* Persistent model-vintage badge: shown only while the arsenic layer is
   selected — a 2010-basis model must not read as current. */
.model-badge {
  position: absolute;
  right: 12px;
  top: 10px;
  max-width: 430px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--as-mark);
  border-radius: 6px;
  padding: 6px 10px;
  font-size: 11px;
  letter-spacing: 0.03em;
  color: var(--ink-2);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
}
.model-badge strong { color: var(--ink); font-weight: 650; }

.tooltip {
  position: absolute;
  pointer-events: none;
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.14);
  padding: 8px 10px;
  font-size: 12px;
  max-width: 300px;
  line-height: 1.45;
  z-index: 5;
}
.tooltip .tt-zip { font-weight: 650; margin-bottom: 2px; }
.tooltip .tt-dim { color: var(--ink-2); }
.tooltip .tt-state { font-weight: 600; }

.ex-side {
  width: 335px;
  overflow-y: auto;
  border-left: 1px solid var(--hairline);
  background: var(--page);
  padding: 14px 16px 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
}
.panel h2 {
  font-size: 11px;
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0 0 8px;
}
.panel p { margin: 6px 0 0; font-size: 11.5px; color: var(--ink-2); line-height: 1.5; }

.legend-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 4px 0;
  font-size: 12px;
}
.legend-row .count { margin-left: auto; color: var(--ink-muted); font-variant-numeric: tabular-nums; }

.swatch {
  width: 15px;
  height: 15px;
  border-radius: 3px;
  border: 1px solid var(--border);
  flex: none;
}
.swatch.hatch {
  background:
    repeating-linear-gradient(45deg, var(--nodata-line) 0 1.5px,
      var(--nodata-bg) 1.5px 5px);
}
/* bare surface: the zero-detect states left off the fill — examined,
   nothing found; deliberately distinct from the no-record hatch */
.swatch.bare { background: var(--surface); }
/* suppressed order cell in the problem-penetration view: orange crosshatch —
   a different pattern class and color than the grey no-record hatch */
.swatch.crosshatch {
  background:
    repeating-linear-gradient(45deg, var(--pen-x-line) 0 1.2px,
      transparent 1.2px 4px),
    repeating-linear-gradient(-45deg, var(--pen-x-line) 0 1.2px,
      var(--pen-x-bg) 1.2px 4px);
}
.swatch.mini {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 2px;
  margin-right: 4px;
  vertical-align: -1px;
}

.mark { width: 18px; height: 15px; flex: none; position: relative; }
.mark svg { display: block; width: 100%; height: 100%; overflow: visible; }

/* Problem-penetration panel: mandate line (SPEC 7.19) + ranked table. */
.pen-mandate {
  font-weight: 650;
  color: var(--ink);
}
.pen-count { font-size: 11px; }
.pen-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 11px;
  margin-top: 6px;
}
.pen-table th {
  text-align: left;
  font-weight: 650;
  font-size: 9.5px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ink-muted);
  padding: 2px 4px 4px 0;
  border-bottom: 1px solid var(--hairline);
}
.pen-table td {
  padding: 3px 4px 3px 0;
  border-bottom: 1px solid var(--hairline);
  color: var(--ink-2);
  white-space: nowrap;
}
.pen-table td:first-child { font-weight: 650; color: var(--ink); font-variant-numeric: tabular-nums; }
.pen-table .num, .pen-table td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* Methodology: the one panel that holds every methods sentence,
   ceiling, conversion and caveat — collapsed by default. */
.methodology summary {
  cursor: pointer;
  font-size: 11px;
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.methodology summary:hover { color: var(--ink); }
.methodology[open] summary { margin-bottom: 6px; }
.methodology h3 {
  font-size: 11.5px;
  font-weight: 650;
  margin: 12px 0 2px;
  color: var(--ink);
}
.methodology p {
  margin: 4px 0 0;
  font-size: 11px;
  color: var(--ink-2);
  line-height: 1.55;
}
/* The one control inside Methodology: opens the SDWA violations view
   (the enforcement record), which holds no switcher position. */
.methodology button {
  font: inherit;
  font-size: 11px;
  color: var(--ink-2);
  background: none;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 3px 10px;
  cursor: pointer;
  margin-top: 6px;
}
.methodology button:hover { color: var(--ink); }

.ex-footer {
  padding: 8px 20px;
  border-top: 1px solid var(--hairline);
  color: var(--ink-muted);
  font-size: 10.5px;
  line-height: 1.5;
}

.hidden { display: none !important; }

@media (max-width: 900px) {
  .ex-main { flex-direction: column; }
  .ex-side { width: auto; border-left: none; border-top: 1px solid var(--hairline); }
  .ex-maparea { min-height: 420px; }
}
