/* CZDTS console: dark by default, dense, no decoration that is not a number or a label.
   Light is the same design re-stepped for a light surface, taken from prefers-color-scheme. */

:root {
  color-scheme: dark;
  --surface-0: #121211;
  --surface-1: #1a1a19;
  --surface-2: #222221;
  --line: #34342f;
  --line-soft: #292927;
  --text-primary: #ffffff;
  --text-secondary: #c3c2b7;
  --text-muted: #8f8e85;
  --accent: #3987e5;
  --good: #199e70;
  --warning: #c98500;
  --serious: #d95926;
  --critical: #e66767;
  --series-1: #3987e5;
  --series-2: #d95926;
  --series-3: #199e70;
  --series-4: #9085e9;
  --series-5: #e66767;
  --band: rgba(57, 135, 229, 0.22);
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
  --mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
  --sans: ui-sans-serif, system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

@media (prefers-color-scheme: light) {
  :root {
    color-scheme: light;
    --surface-0: #f2f1ed;
    --surface-1: #fcfcfb;
    --surface-2: #f6f5f1;
    --line: #d8d7d0;
    --line-soft: #e6e5df;
    --text-primary: #0b0b0b;
    --text-secondary: #52514e;
    --text-muted: #78776f;
    --accent: #2a78d6;
    --good: #1baf7a;
    --warning: #eda100;
    --serious: #eb6834;
    --critical: #e34948;
    --series-1: #2a78d6;
    --series-2: #eb6834;
    --series-3: #1baf7a;
    --series-4: #4a3aa7;
    --series-5: #e34948;
    --band: rgba(42, 120, 214, 0.18);
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--surface-0);
  color: var(--text-primary);
  font: 13px/1.45 var(--sans);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3 { margin: 0; font-weight: 600; letter-spacing: 0.01em; }

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

header.top {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 10px 18px;
  background: var(--surface-1);
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 900;
}

.wordmark {
  font: 600 16px/1 var(--sans);
  letter-spacing: 0.18em;
}
.wordmark span { color: var(--accent); }
/* The breadcrumb, which only reports.html still draws. Every other page's header names its page
   through the current entry of the shared navigation instead, so that the page is named once rather
   than once in a breadcrumb and again in a link list. */
.page-name { color: var(--text-secondary); font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; }
.spacer { flex: 1; }
.clock { font: 12px/1 var(--mono); color: var(--text-secondary); }
.identity { font: 11px/1 var(--mono); color: var(--text-muted); }
.header-link { font-size: 12px; padding: 6px 2px; }
/* The page the reader is already on: named, so the row says where they are, and not a link, so
   there is nothing in the header that leads back to the page it is drawn on. */
.header-link.current { color: var(--text-primary); font-weight: 600; cursor: default; }

/* ------------------------------------------------- the shared navigation and its search box

   One row, written by web/nav.js. The links keep the size they had when each page wrote its own,
   so this changes where the list comes from and not how the header looks. */

.nav {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  min-width: 0;
}

/* Position is on the form so the result list hangs off the input and not off the header, which is
   sticky and would clip a child of its own. */
.nav-search { position: relative; display: flex; min-width: 0; }
.nav-search input[type="search"] {
  font: 12px/1 var(--sans);
  color: var(--text-primary);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 6px 8px;
  width: 190px;
  min-width: 0;
}
.nav-search input[type="search"]:focus {
  outline: none;
  border-color: var(--accent);
}

.nav-results {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 950;
  width: 340px;
  max-width: calc(100vw - 24px);
  max-height: 60vh;
  overflow-y: auto;
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: 5px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}
.nav-results[hidden] { display: none; }
.nav-group + .nav-group { border-top: 1px solid var(--line); }
.nav-group-head {
  padding: 7px 10px 4px;
  font: 11px/1 var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.nav-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 6px 10px;
  color: var(--text-primary);
  text-decoration: none;
}
a.nav-row:hover { background: var(--surface-2); text-decoration: none; }
.nav-row-name { font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-row-meta { margin-left: auto; font: 11px var(--mono); color: var(--text-muted); white-space: nowrap; }
.nav-row-all { border-top: 1px solid var(--line-soft); }
.nav-row-all .nav-row-name { color: var(--accent); }
.nav-none { padding: 6px 10px; font: 11px var(--mono); color: var(--text-muted); }
.nav-results .error { margin: 6px 10px; }

/* An admin only control, in a strip of its own rather than in the link list.
   Build deck queues a job that reads every organisation's outputs at once, so the API allows it to
   the platform operator alone and answers everybody else 403. A control that refuses most readers
   does not belong beside the links that serve all of them. */
.admin-strip {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-left: 12px;
  border-left: 1px solid var(--line);
}
.admin-strip .admin-label {
  font: 11px/1 var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

button {
  font: 12px/1 var(--sans);
  color: var(--text-primary);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 6px 10px;
  cursor: pointer;
}
button:hover { border-color: var(--accent); }
button[disabled] { opacity: 0.5; cursor: default; }

/* ---------------------------------------------------------------- layout */

main { padding: 14px 18px 40px; display: grid; gap: 14px; }

.panel {
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: 6px;
  box-shadow: var(--shadow);
  overflow: hidden;
}
.panel > h2 {
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
  padding: 10px 12px;
  border-bottom: 1px solid var(--line-soft);
  display: flex;
  gap: 10px;
  align-items: baseline;
}
.panel > h2 .hint { font: 11px/1 var(--sans); letter-spacing: 0; text-transform: none; color: var(--text-muted); }
.panel .body { padding: 12px; }

.two-up { display: grid; grid-template-columns: minmax(0, 2.1fr) minmax(300px, 1fr); gap: 14px; }
@media (max-width: 1080px) { .two-up { grid-template-columns: minmax(0, 1fr); } }

/* ---------------------------------------------------------------- counters */

.counters { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
.tile {
  background: var(--surface-1);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 10px 12px;
}
.tile .label { font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-muted); }
.tile .value { font: 600 26px/1.15 var(--mono); margin-top: 4px; }
.tile .sub { font: 11px/1.3 var(--mono); color: var(--text-secondary); margin-top: 3px; }
.tile.wide { grid-column: span 2; }
@media (max-width: 700px) { .tile.wide { grid-column: span 1; } }

.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.chip {
  font: 11px/1 var(--mono);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 4px 8px;
  color: var(--text-secondary);
  white-space: nowrap;
}
.chip.pending { color: var(--text-muted); }
.chip b { color: var(--text-primary); font-weight: 600; }

/* ---------------------------------------------------------------- map */

#map, #site-map, #ent-map, #permian-map, #arizona-map {
  height: 520px; width: 100%; background: var(--surface-2);
}
#site-map, #ent-map { height: 360px; }
/* The layer under the map: a quicklook the engine drew, or the scene a vendor would sell. */
#scene img { width: 100%; display: block; border: 1px solid var(--line-soft); border-radius: 4px; }
.leaflet-container { background: var(--surface-2); font: 12px var(--sans); }
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
  background: var(--surface-1);
  color: var(--text-primary);
  border: 1px solid var(--line);
  border-radius: 5px;
}
.leaflet-popup-content { margin: 10px 12px; }
/* `background-color`, never the `background` shorthand. The shorthand resets every background
   property it does not name, `background-image` among them, and the icons on these controls are
   background images: Leaflet's own zoom glyphs and every button Leaflet.draw adds come from a
   sprite that leaflet.draw.css sets as `background-image`. This file loads after that one at the
   same specificity, so a shorthand here won that cascade and blanked the sprite, and the draw
   toolbar rendered as a column of empty white squares with nothing to say what any of them did.
   The long-hand changes the surface the icons sit on and leaves the icons alone. */
.leaflet-bar a, .leaflet-control-layers-toggle { background-color: var(--surface-1); color: var(--text-primary); }

.site-marker {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 4px;
  border: 1.5px solid rgba(0, 0, 0, 0.55);
  font: 600 11px/1 var(--mono);
  color: #10100f;
}
.marker-alert { box-shadow: 0 0 0 3px var(--critical); }
.site-marker.parked {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: transparent;
  border: 1.5px solid var(--text-muted);
}

details.parked-list > summary {
  cursor: pointer;
  padding: 10px 12px;
  color: var(--text-secondary);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border-top: 1px solid var(--line-soft);
}
details.parked-list > summary .hint { text-transform: none; letter-spacing: 0; color: var(--text-muted); }

.popup-title { font-weight: 600; margin-bottom: 4px; }
.popup-meta { color: var(--text-secondary); font-size: 11px; }
.popup-numbers { margin-top: 6px; display: grid; grid-template-columns: auto auto; gap: 2px 10px; font: 11px var(--mono); }
.popup-numbers dt { color: var(--text-muted); }
.popup-numbers dd { margin: 0; text-align: right; }

.legend { display: flex; flex-wrap: wrap; gap: 12px; padding: 8px 12px; border-top: 1px solid var(--line-soft); }
.legend span { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; color: var(--text-secondary); }
.swatch { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }
.badge {
  font: 10px/1 var(--mono);
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 3px 5px;
  color: var(--text-muted);
}

/* ---------------------------------------------------------------- tables */

.scroll { overflow-x: auto; }
table { border-collapse: collapse; width: 100%; font: 12px/1.4 var(--sans); }
th, td { padding: 6px 10px; text-align: left; border-bottom: 1px solid var(--line-soft); white-space: nowrap; }
th {
  font: 11px/1 var(--sans);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-muted);
  position: sticky;
  top: 0;
  background: var(--surface-1);
}
td.num, th.num { text-align: right; font-family: var(--mono); }
tbody tr:hover { background: var(--surface-2); }
.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; margin-right: 6px; vertical-align: -1px; }

.state-good { color: var(--good); }
.state-warning { color: var(--warning); }
.state-serious { color: var(--serious); }
.state-critical { color: var(--critical); }
.muted { color: var(--text-muted); }

/* ---------------------------------------------------------------- queues, feed */

.queues { display: flex; flex-wrap: wrap; gap: 10px; }
.queue {
  flex: 1 1 150px;
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 8px 10px;
  background: var(--surface-2);
}
.queue .name { font: 11px var(--mono); color: var(--text-secondary); }
.queue .figures { display: flex; gap: 14px; margin-top: 4px; font: 600 18px/1 var(--mono); }
.queue .figures small { display: block; font: 10px/1 var(--sans); color: var(--text-muted); letter-spacing: 0.05em; text-transform: uppercase; margin-bottom: 3px; }

.feed { max-height: 520px; overflow-y: auto; }
.alert-row { padding: 9px 12px; border-bottom: 1px solid var(--line-soft); display: grid; gap: 3px; }
.alert-row .head { display: flex; gap: 8px; align-items: baseline; }
.alert-row .trigger { font-weight: 600; }
.alert-row .when { margin-left: auto; font: 11px var(--mono); color: var(--text-muted); }
.alert-row .meta { font: 11px var(--mono); color: var(--text-secondary); }

.empty { padding: 22px 14px; color: var(--text-muted); text-align: center; font-size: 12px; }
.empty strong { display: block; color: var(--text-secondary); font-weight: 600; margin-bottom: 4px; }

/* ---------------------------------------------------------------- chart */

/* ---------------------------------------------------------------- run files */
/* The files a run wrote, grouped by run. One block per run, one row per file, and one preview
   area under them all: a quicklook is looked at in place, a JSON is read in place, and anything
   else is downloaded through the API rather than from the store. */
.run-files { border-bottom: 1px solid var(--line-soft); }
.run-head { display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline; padding: 8px 12px;
  font: 12px var(--mono); }
.run-head .muted { font: 11px var(--mono); }
.product-preview { padding: 0 12px 12px; }
.product-preview img { width: 100%; display: block; border: 1px solid var(--line-soft); border-radius: 4px; }
.product-preview pre { font: 11px/1.5 var(--mono); color: var(--text-secondary); background: var(--surface-2);
  border: 1px solid var(--line-soft); border-radius: 4px; padding: 10px; max-height: 340px;
  overflow: auto; white-space: pre-wrap; word-break: break-word; }

/* ---------------------------------------------------------------- verification certificate */
/* The Independent Space MRV panel. Laid out as a document rather than as a dashboard tile,
   because it is a document: the claim, the numbers behind it, the licence chain of its inputs
   and the method an auditor reads. */
.certificate { border: 1px solid var(--line); border-radius: 6px; padding: 16px; background: var(--surface-1); }
.cert-head { display: flex; justify-content: space-between; gap: 12px; align-items: flex-start;
  border-bottom: 1px solid var(--line-soft); padding-bottom: 10px; font-size: 13px; }
.cert-head .muted { font: 11px/1.5 var(--mono); }
.cert-claim { margin: 12px 0; font-size: 13px; line-height: 1.55; color: var(--text-primary); }
.cert-numbers { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 4px 18px; margin: 0 0 10px; }
.cert-row { display: flex; gap: 10px; align-items: baseline; justify-content: space-between;
  border-bottom: 1px dotted var(--line-soft); padding: 4px 0; }
.cert-row dt { font-size: 11px; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-muted); }
.cert-row dd { margin: 0; font: 600 13px/1.2 var(--mono); text-align: right; }
.cert-row dd .muted { font: 10px/1.2 var(--sans); font-weight: 400; letter-spacing: 0; }
.cert-method { font: 11px/1.6 var(--sans); color: var(--text-secondary); margin: 6px 0 12px; }

.chart { width: 100%; height: auto; display: block; }
.chart .axis { stroke: var(--line); stroke-width: 1; }
.chart .grid { stroke: var(--line-soft); stroke-width: 1; }
.chart text { fill: var(--text-muted); font: 10px var(--mono); }
.chart .series { fill: none; stroke: var(--series-1); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.chart .band { fill: var(--band); stroke: none; }
.chart .marker { fill: var(--series-1); stroke: var(--surface-1); stroke-width: 2; }
/* The fused series: the tightened band drawn inside the wider one it replaces. */
.chart .band-alt { fill: var(--series-2); opacity: 0.28; }
.chart .series-alt { stroke: var(--series-2); }
.chart .crosshair { stroke: var(--text-muted); stroke-width: 1; stroke-dasharray: 3 3; }
.chart-readout { font: 11px var(--mono); color: var(--text-secondary); padding: 0 12px 10px; min-height: 16px; }

/* ---------------------------------------------------------------- draw page */

.draw-shell {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(340px, 440px);
  height: calc(100vh - 49px);
}
.draw-map-wrap { display: flex; flex-direction: column; min-width: 0; border-right: 1px solid var(--line); }
#draw-map { flex: 1 1 auto; min-height: 240px; background: var(--surface-2); }

.draw-toolbar, .draw-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: var(--surface-1);
  border-bottom: 1px solid var(--line-soft);
}
.draw-form { border-bottom: none; border-top: 1px solid var(--line-soft); }
label.inline { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-secondary); }
label.inline input[type="text"] { min-width: 90px; }
.draw-toolbar #goto { min-width: 190px; }
select {
  font: 12px var(--sans);
  padding: 6px 8px;
  border-radius: 4px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text-primary);
  max-width: 240px;
}
.area-readout { font: 12px var(--mono); color: var(--text-secondary); }
.area-readout b { color: var(--text-primary); font: 600 14px var(--mono); }
#monitor { background: var(--accent); border-color: var(--accent); color: #fbfbfa; }

.draw-side { display: flex; flex-direction: column; min-width: 0; background: var(--surface-1); }
.tabs { display: flex; gap: 0; border-bottom: 1px solid var(--line); }
.tab {
  flex: 1;
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  background: transparent;
  padding: 10px 8px;
  color: var(--text-muted);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.tab[aria-selected="true"] { color: var(--text-primary); border-bottom-color: var(--accent); }
.tab-body { flex: 1; overflow-y: auto; padding: 12px; }
.tab-body h3 {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin: 14px 0 6px;
  display: flex;
  gap: 8px;
  align-items: baseline;
}
.tab-body h3:first-child { margin-top: 0; }
.tab-body h3 .hint { font: 11px/1 var(--sans); letter-spacing: 0; text-transform: none; color: var(--text-muted); }
.tab-body .chart-readout { padding: 6px 0 0; }

@media (max-width: 1080px) {
  .draw-shell { grid-template-columns: minmax(0, 1fr); height: auto; }
  .draw-map-wrap { border-right: none; }
  #draw-map { height: 460px; flex: none; }
  .draw-side { border-top: 1px solid var(--line); }
  .tab-body { max-height: 520px; }
}

/* ---------------------------------------------------------------- drawer */

dialog.drawer {
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface-1);
  color: var(--text-primary);
  padding: 0;
  width: min(420px, 92vw);
}
dialog.drawer::backdrop { background: rgba(0, 0, 0, 0.55); }
dialog.drawer .body { display: grid; gap: 12px; }
/* The persona switcher fills the drawer: it is the control the demo reaches for most. */
dialog.drawer label.field select { max-width: none; width: 100%; }
label.field { display: grid; gap: 4px; font-size: 12px; color: var(--text-secondary); }
input[type="text"] {
  font: 12px var(--mono);
  padding: 7px 8px;
  border-radius: 4px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text-primary);
}
label.check { display: flex; gap: 8px; align-items: center; font-size: 12px; color: var(--text-secondary); }
.row-actions { display: flex; gap: 8px; justify-content: flex-end; }
.note { font-size: 11px; color: var(--text-muted); }

/* The 401 banner: locked, not broken. Every page gets it from ui.js, above everything else. */
.auth-banner {
  position: sticky;
  top: 0;
  z-index: 900;
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 8px 14px;
  border-bottom: 1px solid var(--line-soft);
  border-left: 3px solid var(--warning);
  background: var(--surface-2);
  font-size: 12px;
  color: var(--text-secondary);
}
.auth-banner button { margin-left: 0; }
.auth-banner button:last-child { margin-left: auto; }

.error {
  border-left: 3px solid var(--critical);
  background: var(--surface-2);
  padding: 8px 10px;
  font: 11px/1.4 var(--mono);
  color: var(--text-secondary);
}
/* The second line of a failure: the row in the messages table that recorded it. Quieter than the
   sentence above it, because it is the handle on the failure rather than the failure itself, and
   it is read once by whoever is about to report the thing. */
.error-trail { margin-top: 5px; color: var(--text-muted); }
.error-trail code { font: inherit; }

/* ---------------------------------------------------------------- messages */

.messages { max-height: 420px; overflow-y: auto; }
.message-row { padding: 8px 12px; border-bottom: 1px solid var(--line-soft); }
.message-row .head { display: flex; gap: 10px; align-items: baseline; font: 11px/1 var(--mono); }
.message-row .level { text-transform: uppercase; letter-spacing: 0.05em; }
.message-row .source { color: var(--text-secondary); }
.message-row .when { margin-left: auto; color: var(--text-muted); }
.message-row .text { margin-top: 4px; font-size: 12px; color: var(--text-primary); white-space: normal; }
.message-row .detail { margin-top: 4px; }
.message-row .detail summary { font: 11px/1 var(--mono); color: var(--text-muted); cursor: pointer; }
.message-row .detail pre {
  margin: 6px 0 0;
  padding: 8px;
  background: var(--surface-2);
  overflow-x: auto;
  font: 11px/1.4 var(--mono);
  color: var(--text-secondary);
}
.message-filters { display: flex; gap: 8px; align-items: center; padding: 8px 12px; }
.vendor-errors { margin: 10px 0; display: grid; gap: 6px; }

/* ---------------------------------------------------------------- the verticals catalogue */

.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(380px, 1fr)); gap: 14px; }
.vertical-card > h2 { align-items: baseline; }
.vertical-card .body { display: grid; gap: 8px; }
.vertical-card h3 {
  margin: 8px 0 0;
  font: 11px/1 var(--sans);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.vertical-card h3 .note { text-transform: none; letter-spacing: 0; margin-left: 6px; }
.vertical-card .pitch { margin: 0; font-size: 13px; line-height: 1.55; color: var(--text-primary); }
.vertical-card .definition { margin: 0; font-size: 12px; line-height: 1.5; color: var(--text-secondary); }
.vertical-card .note { margin: 0; line-height: 1.5; }
.vertical-card .note.overlay { color: var(--text-secondary); }
.vertical-card .row-actions.statement { justify-content: flex-start; align-items: center; }
.vertical-card.is-method { border-style: dashed; }

.invariants, .sites { list-style: none; margin: 0; padding: 0; display: grid; gap: 5px; }
.invariants li {
  display: grid;
  grid-template-columns: 84px auto;
  gap: 2px 8px;
  font-size: 12px;
  color: var(--text-muted);
}
.invariants li .mark {
  grid-row: span 2;
  font: 10px/1.6 var(--mono);
  letter-spacing: 0.04em;
  color: var(--text-muted);
}
.invariants li.is-built .mark { color: var(--good); }
.invariants li .name { font: 600 12px/1.3 var(--mono); color: var(--text-secondary); }
.invariants li.is-built .name { color: var(--text-primary); }
.invariants li .statement { font-size: 11px; line-height: 1.45; }
.sites li { font-size: 12px; color: var(--text-secondary); }
.sites li a { font-weight: 600; }

.badge.status-built { color: var(--good); border-color: var(--good); }
.badge.status-partial { color: var(--warning); border-color: var(--warning); }
.badge.status-declared { color: var(--text-muted); }
.badge.status-method { color: var(--text-secondary); }

/* ---------------------------------------------------------------- ground deformation panel */
#deformation-panel tr.unmeasured td { color: var(--text-muted); font-style: italic; }
#deformation-panel .flag {
  display: inline-block;
  font: 600 10px/1.6 var(--mono);
  letter-spacing: 0.03em;
  padding: 1px 6px;
  border-radius: 3px;
  border: 1px solid currentColor;
}
#deformation-panel .flag-warn { color: var(--warning); }
#deformation-caveat { color: var(--text-muted); font-size: 12px; line-height: 1.5; }

/* Conveyance: invariant status badges, plain colour and no poster styling. */
.badge.status-observed { color: var(--good); border-color: var(--good); }
.badge.status-degraded { color: var(--warning); border-color: var(--warning); }
.badge.status-unobserved { color: var(--warning); border-color: var(--warning); font-weight: 600; }
.badge.status-not_evaluated { color: var(--text-muted); }
#heatmap img, #dq-invariants table { max-width: 100%; }

/* Managed system: a question that does not apply to this asset. It is not `not_evaluated`, which
   is a test that could not be run, and the colour keeps the two apart as well as the word does. */
.badge.status-not_applicable { color: var(--text-secondary); border-style: dashed; }

/* ---------------------------------------------------------------- the uninvited state

   A visitor with no invitation is reading a locked panel, not an empty one, so it is set as
   prose and not as a failure: no red rule, no monospace, and the sentence that says the data is
   held back rather than absent carries the only emphasis. */

.locked {
  padding: 18px 16px;
  max-width: 62ch;
  display: grid;
  gap: 8px;
  color: var(--text-secondary);
  font-size: 12px;
  line-height: 1.55;
}
.locked strong {
  display: block;
  color: var(--text-primary);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.locked p { margin: 0; }
.locked p.held {
  border-left: 2px solid var(--accent);
  padding-left: 10px;
  color: var(--text-primary);
}
.locked p.note { word-break: break-word; }
/* A panel says it in one line: the heading above it has already named it. */
.locked.locked-brief { padding: 20px 14px; color: var(--text-muted); font-style: italic; }
/* Inside a counters grid the line is one tile that spans the row, so the grid does not break. */
.tile.locked-tile { grid-column: 1 / -1; padding: 0; }
.tile.locked-tile .locked { padding: 10px 12px; }

/* ---------------------------------------------------------------- the viewer's own identity */

.viewer-card {
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--surface-2);
  padding: 10px 12px;
  display: grid;
  gap: 8px;
}
.viewer-card h3 {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.viewer-card dl { margin: 0; }
.viewer-card .row-actions { justify-content: flex-start; }
/* label.field is a grid, which outranks the hidden attribute on its own. The fields a reader has
   no use for are hidden, not merely disabled, because neither can do anything but mislead. */
dialog.drawer label[hidden] { display: none; }

/* A control a viewer may not use. Disabled carries the refusal; the title carries the reason, and
   the dashed edge says it is withheld rather than merely busy. */
button.read-only, select.read-only {
  border-style: dashed;
  opacity: 0.55;
  cursor: not-allowed;
}

/* ---------------------------------------------------------------- tablet and narrow laptop

   The header is one flex row carrying the wordmark, the page name, eleven links, a search box, the
   identity, the clock and up to three buttons, and flex does not wrap unless it is told to. It was
   told to below 700px and nowhere else, so between 701px and 1080px, which is every tablet held
   either way and every laptop window that is not full screen, the row was wider than the viewport
   and the whole page scrolled sideways to fit it. The band was invisible from a desktop, where the
   row fits, and from the phone rules, which already wrap.

   Wrapping is the whole fix, and it is separate from the phone block below because it is the only
   part of that block this band needs: the header stays sticky, the spacer keeps pushing the right
   hand group over, and nothing is resized. Below 700px the rules further down take over. */

@media (max-width: 1080px) {
  header.top { flex-wrap: wrap; row-gap: 8px; }
  /* The link list is the part that has to give, and it gives by wrapping inside itself rather than
     by pushing the buttons off the end of the row: the nav is a flex container of its own, so its
     links fill the width they are left and then start a second line under themselves. */
  header.top .nav { flex: 1 1 auto; }
  /* The search box takes a line of its own here, which is not cosmetic. The result list is
     positioned against the box, and a box that has wrapped to an unpredictable position takes its
     list with it: pinned to the box's right edge it hung off the left of the viewport, and pinned
     to the left edge it would hang off the right, depending on where the wrap happened to leave it.
     A box that spans the row has both edges where the row's edges are, so the list can be pinned to
     both and can overflow neither. */
  .nav-search { flex: 1 1 100%; }
  .nav-search input[type="search"] { width: 100%; }
  .nav-results { left: 0; right: 0; width: auto; }
}

/* ---------------------------------------------------------------- phone width

   An investor opens the link on a phone. The header is a flex row of links that would otherwise
   run off the side, and nothing below it may scroll sideways. */

@media (max-width: 700px) {
  header.top { flex-wrap: wrap; gap: 8px 12px; padding: 8px 12px; position: static; }
  header.top .spacer { flex: 0 0 100%; height: 0; }
  header.top .page-name { font-size: 11px; }
  .header-link { padding: 4px 0; }
  .nav { gap: 8px 10px; }
  .nav-results { width: auto; left: 0; right: 0; }
  main { padding: 12px 12px 32px; }
  .counters { grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }
  .tile .value { font-size: 20px; }
  .auth-banner { flex-wrap: wrap; position: static; }
  .locked { padding: 14px 12px; }
  #map, #site-map, #ent-map, #arizona-map, #permian-map { height: 320px; }
}

/* ---------------------------------------------------------------- the gate

   enter.html, which is what app.czdts.com serves a visitor holding no credential. It is the only
   page in the console that is a single column of prose with one control in it, so it gets its own
   few rules rather than bending the panel grid every other page is laid out on.

   Everything here is drawn from the same custom properties as the rest of the console, so light,
   dark and the phone rules below need nothing of their own: what changes between the themes is the
   surface and the text colour, and those are variables. */

.gate { padding-top: 8vh; }
/* Centred by its own auto margins rather than by the grid's alignment: main is a grid whose single
   implicit column stretches, so the margins have room to work and no percentage has to resolve
   against a content sized track. */
.gate-panel { width: min(52ch, 100%); margin: 0 auto; }
.gate-card { display: grid; gap: 12px; color: var(--text-secondary); line-height: 1.55; }
.gate-card p { margin: 0; }
/* The code is the one thing on the page that is typed, so it gets the full width of the card and
   the monospace the rest of the console gives an identifier. */
.gate-card input[type="text"] { width: 100%; }
.gate-card form { display: grid; gap: 10px; }
.gate-actions { display: flex; gap: 10px; align-items: center; }

/* A refused code is a fact, not a fault in the platform, so it is set as a line of text with the
   critical colour on its edge rather than as the red ruled error box a failed request gets. */
.gate-failure {
  border-left: 2px solid var(--critical);
  padding: 2px 0 2px 10px;
  color: var(--text-primary);
  font-size: 12px;
}

.gate-rule { border: 0; border-top: 1px solid var(--line-soft); margin: 4px 0 0; }
/* The way out is not a footnote: it is the answer for most of the people who reach this page. */
.gate-out { color: var(--text-secondary); }
.gate-out strong { color: var(--text-primary); }

@media (max-width: 700px) {
  .gate { padding-top: 16px; }
  .gate-actions { flex-wrap: wrap; }
}
