/* ============================================================================
   GeoLiquefy Liquefaction Hazard Engine: single-screen dashboard layout.
   Companion to harness.css (tokens + component layer). This sheet holds the
   layout and the gl-* helper primitives ported from the design handoff
   (docs/design/design_handoff_geoliquefy_dashboard/, frame 1a).
   Desktop is a fixed 1440x900-class viewport with NO page scroll: only the
   memo panel and the match-table region scroll, in place.
   ========================================================================== */

/* ---- helper primitives (ported from the handoff prototype) --------------- */

/* 2026-08-25 readability pass: micro-UI (labels, headers, inputs, figures)
   moved to the --font-ui sans stack; primary label/header floors raised to 12px (secondary meta text 11-11.5px) with
   uppercase REMOVED from every selector that notation flows through. The
   uppercase transform was corrupting engineering notation (sigma-v rendered
   as capital-sigma V, gamma as capital Gamma): only word-only selectors
   (.gl-k, .gl-grp, .db-verdict-label) may keep uppercase. */
.gl-fig {
  font-family: var(--font-body);
  font-feature-settings: "tnum";
  font-variant-numeric: tabular-nums;
}
.gl-k {
  font-size: 0.75rem;
  line-height: 1.2;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-family: var(--font-body);
  color: var(--accent-700);
}
.gl-lbl {
  font-size: 0.75rem;
  line-height: 1.2;
  letter-spacing: 0.02em;
  font-weight: 500;
  font-family: var(--font-body);
  color: var(--on-surface-2);
}
.gl-in {
  width: 100%;
  box-sizing: border-box;
  padding: 2px 0.5rem;
  font-size: 0.875rem;
  font-family: var(--font-body);
  font-feature-settings: "tnum";
  background: transparent;
  color: var(--on-surface-0);
  border: 1px solid var(--border-divider);
  border-radius: 2px;
}
.gl-in:hover { border-color: var(--border-control); }
.gl-in:focus-visible { outline: 2px solid var(--accent-600); outline-offset: 1px; }
.gl-f { display: grid; gap: 1px; }
.gl-grp {
  font-size: 0.75rem;
  line-height: 1.2;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-family: var(--font-body);
  color: var(--on-surface-1);
  border-bottom: 1px solid var(--border-divider);
  padding-bottom: 2px;
}
.gl-th {
  font-size: 0.75rem;
  line-height: 1.2;
  letter-spacing: 0.02em;
  font-family: var(--font-body);
  color: var(--on-surface-2);
  text-align: left;
  font-weight: 500;
  padding: 0 0.75rem 0.4375rem 0;
  white-space: nowrap;
}
/* Notation embedded inside an uppercased parent (e.g. the plot kicker):
   restore case and tracking so q_c1N,cs is never mangled. */
.gl-notation { text-transform: none; letter-spacing: normal; }
/* True subscripts must never grow a grid row or table line. Scoped to the
   page bodies (not .db-frame) so dialog mounts outside the frame are
   covered too. */
body.db-body-root sub, body.cpt-body sub { line-height: 0; font-size: 0.72em; }
.gl-td {
  font-size: 0.84375rem;
  line-height: 1.5;
  padding: 0.625rem 0.75rem 0.625rem 0;
  border-top: 1px solid var(--border-divider);
  vertical-align: top;
}
.gl-scroll { overflow: auto; scrollbar-width: thin; }

.hidden { display: none !important; }

/* ---- page frame ---------------------------------------------------------- */

html.db-root, body.db-body-root {
  height: 100%;
}

/* Fluid scale (2026-08-25 readability pass): the dashboard's rem sizes are
   authored against a 16px root at the 1440x900 design frame. The root tracks
   the smaller of viewport width/1440 and height/900, so larger screens scale
   the whole frame up proportionally (capped at 1.333x, reached at 1920x1200)
   and SHORTER screens scale it down (floor 13px = 0.81x, so a 1366x768
   laptop gets the complete frame at ~0.85x instead of an overflowing rail,
   the pre-pass failure mode there). The <=1200px accordion bands stay in px:
   at those widths the vw term keeps the root near its floor and the bands'
   own layout does not depend on the root. */
html.db-root { font-size: clamp(13px, min(1.1111vw, 1.7778vh), 21.33px); }
body.db-body-root {
  margin: 0;
  background: var(--surface-0);
  color: var(--on-surface-0);
  font-family: var(--font-body);
  font-size: 0.9375rem;
  line-height: 1.55;
  overflow: hidden;
}
.db-frame {
  height: 100vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.db-frame a { color: var(--accent-700); text-decoration: none; }
.db-frame a:hover { color: var(--accent-600); text-decoration: underline; }
.db-frame :focus-visible { outline: 2px solid var(--accent-600); outline-offset: 2px; }

/* ---- header bar (~46px at design scale) -------------------------------------------------- */

.db-header {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.5625rem 1.125rem;
  border-bottom: 1px solid var(--border-divider);
  flex: none;
}
.db-brand {
  font-family: var(--font-heading);
  font-weight: var(--font-bold);
  font-size: 1.0625rem;
  letter-spacing: var(--tracking-wordmark);
}
.db-brand span, .db-rep-brand span { font-weight: var(--font-light); }
.db-vr { width: 1px; height: 1.625rem; background: var(--border-divider); flex: none; }
.db-vr-sm { width: 1px; height: 1.25rem; background: var(--border-divider); flex: none; }
.db-title-stack { display: grid; gap: 1px; }
.db-title { font-family: var(--font-heading); font-size: 0.875rem; }
.db-header-meta {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 1rem;
  font-size: 0.75rem;
  color: var(--on-surface-2);
}
.db-avatar {
  width: 1.375rem;
  height: 1.375rem;
  border: 1px solid var(--border-control);
  border-radius: 50%;
  flex: none;
}

/* ---- site-level finding, inside the report's cover section ---------------
   The verdict no longer rides a full-width band above the work: it sits on
   the page, where the export prints it. The box keeps the shipped
   proportions (8px 28px / 40px / lh 1.06, rem-scaled) so the label reads as
   the same object it did in the band; the derivation line beneath it is new
   and is the D2 fix (the verdict states where it came from). */

.db-verdict-box {
  border: 1px solid var(--on-surface-0);
  border-radius: var(--radius-md);
  padding: 0.5rem 1.75rem 0.625rem;
  display: grid;
  gap: 0.125rem;
  justify-items: start;
}
.db-verdict-label {
  display: block;
  font-family: var(--font-heading);
  font-weight: var(--font-light);
  font-size: 2.5rem;
  line-height: 1.06;
  letter-spacing: var(--tracking-display);
  text-transform: uppercase;
}
.db-rep-derivation {
  font-size: 0.78125rem;
  color: var(--on-surface-2);
  line-height: 1.45;
}
.db-verdict-flags { display: grid; gap: 0.3125rem; }
.db-verdict-flags .tag { justify-self: start; letter-spacing: 0.06em; }
.db-verdict-note {
  font-size: 0.78125rem;
  color: var(--on-surface-2);
  line-height: 1.45;
}

/* ---- body split ---------------------------------------------------------- */

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

/* input rail: 414px at design scale (25.875rem), never scrolls */
.db-rail {
  width: 25.875rem;
  flex: none;
  border-right: 1px solid var(--border-divider);
  padding: 0.5rem 0.875rem;
  display: flex;
  flex-direction: column;
  gap: 0.1875rem;
  overflow: hidden;
}
.db-rail-head { display: flex; align-items: baseline; gap: 0.625rem; }
.db-disclosure {
  margin: 0;
  font-size: 0.71875rem;
  line-height: 1.3;
  color: var(--on-surface-2);
}
.db-rail-sub { font-size: 0.75rem; color: var(--on-surface-2); }
.db-rail-note {
  margin: 0.125rem 0 0.25rem;
  font-size: 0.71875rem;
  line-height: 1.4;
  color: var(--accent-700, var(--on-surface-1));
}
.db-rail-link { margin-left: auto; font-size: 0.75rem; }
.db-grid3 {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 0.1875rem 0.5625rem;
}
.db-grid4 {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.1875rem 0.5625rem;
}
.db-span2 { grid-column: span 2; }
.db-rail-foot {
  display: flex;
  gap: 0.5rem;
  margin-top: auto;
  padding-top: 0.375rem;
  border-top: 1px solid var(--border-divider);
}
.db-rail-foot .btn { flex: 1; }

/* ---- deliverable-first centre column -------------------------------------
   Desk (the tinted surround) carries one sheet of paper, .db-report. Widths
   are rem so they ride html.db-root's clamp: at 1366x768 the root falls to
   ~13.6px and the whole three-column frame scales with it rather than
   overflowing. Authored against the 1440x900 frame: rail 25.875rem (414px),
   control rail 18.5rem (296px), paper max 41.5rem (664px). */

.db-desk {
  flex: 1;
  min-width: 0;
  display: flex;
  justify-content: center;
  background: var(--surface-1);
  padding: 0.75rem 0.75rem 0.875rem;
  min-height: 0;
}
.db-report {
  width: 100%;
  max-width: 41.5rem;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--surface-0);
  border: 1px solid var(--border-divider);
  box-shadow: 0 3px 10px rgba(45, 43, 43, 0.10);
}
.db-rep-head {
  display: flex;
  align-items: baseline;
  gap: 0.625rem;
  padding: 0.75rem 1.5rem 0.625rem;
  border-bottom: 1px solid var(--border-divider);
  flex: none;
}
.db-rep-brand {
  font-family: var(--font-heading);
  font-weight: var(--font-bold);
  font-size: 1rem;
  letter-spacing: var(--tracking-wordmark);
}
.db-rep-kicker { letter-spacing: 0.06em; }
.db-rep-stamp {
  margin-left: auto;
  display: grid;
  gap: 1px;
  text-align: right;
  font-size: 0.71875rem;
  color: var(--on-surface-2);
}
.db-rep-ver { color: var(--on-surface-1); }

/* The sheet scrolls, the frame does not: a report is a scroll of sections,
   and the control rail beside it must stay put while it moves. */
.db-rep-scroll {
  flex: 1;
  min-height: 0;
  padding: 0 1.5rem 1.25rem;
}
.db-rep-sec {
  padding: 1.125rem 0 0.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}
.db-rep-sec + .db-rep-sec { border-top: 1px solid var(--border-divider); padding-top: 1.125rem; }
.db-rep-sec-head { display: flex; align-items: baseline; gap: 0.625rem; }
.db-rep-sec-sub { margin-left: auto; font-size: 0.75rem; color: var(--on-surface-2); text-align: right; }
.db-rep-kv {
  margin: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.3125rem 1.25rem;
}
.db-rep-kv-row { min-width: 0; }
.db-rep-kv dt { margin: 0; }
.db-rep-kv dd {
  margin: 1px 0 0;
  font-size: 0.84375rem;
  overflow-wrap: anywhere;
}
.db-rep-id { font-size: 0.75rem; color: var(--on-surface-2); }
.db-rep-note {
  margin: 0;
  font-size: 0.71875rem;
  line-height: 1.45;
  color: var(--on-surface-2);
}
.db-rep-table { width: 100%; border-collapse: collapse; }
.db-rep-table .gl-td { padding: 0.25rem 0.625rem 0.25rem 0; font-size: 0.8125rem; }
/* Value right-aligned against its own unit column, not against the table
   edge: the export prints "2.5638  MPa" as two adjacent columns, so this
   does too. Positional so the header cells track the body cells. */
.db-rep-table th:nth-child(2), .db-rep-table td:nth-child(2) { text-align: right; }
.db-rep-table th:nth-child(3), .db-rep-table td:nth-child(3) {
  width: 5.5rem;
  padding-left: 0.625rem;
}
.db-rep-unit { color: var(--on-surface-2); font-size: 0.75rem; }
.db-rep-end {
  margin-top: 1.125rem;
  padding-top: 0.625rem;
  border-top: 1px solid var(--border-divider);
  display: grid;
  gap: 0.1875rem;
}
.db-rep-end-note {
  font-size: 0.71875rem;
  line-height: 1.45;
  color: var(--on-surface-2);
}

/* The column -> label rule, on screen. Static markup, so it is present and
   pinnable before any run; JS only marks which row the current label came
   from. */
.db-rule {
  border: 1px solid var(--border-divider);
  border-radius: var(--radius-md);
  background: var(--surface-1);
  padding: 0.5rem 0.75rem 0.625rem;
  display: grid;
  gap: 0.375rem;
}
.db-rule-head { letter-spacing: 0.06em; }
.db-rule-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.3125rem 1.125rem;
}
.db-rule-item {
  display: flex;
  align-items: baseline;
  gap: 0.3125rem;
  font-size: 0.78125rem;
  color: var(--on-surface-2);
}
.db-rule-col { color: var(--on-surface-1); }
.db-rule-item.db-rule-active { color: var(--on-surface-0); }
.db-rule-item.db-rule-active .db-rule-label {
  border-bottom: 2px solid var(--accent-600);
  font-weight: 500;
}
.db-rule-note {
  margin: 0;
  font-size: 0.75rem;
  line-height: 1.55;
  color: var(--on-surface-2);
}
/* The rule sits behind a disclosure since 2026-09-02 (founder: the screening
   read as packed). Static markup either way; only the default state moved. */
.db-rule-details { margin-top: 0.125rem; }
.db-rule-summary {
  cursor: pointer;
  font-size: 0.75rem;
  color: var(--on-surface-2);
  letter-spacing: 0.02em;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
}
.db-rule-summary::-webkit-details-marker { display: none; }
.db-rule-summary::before {
  content: "";
  width: 0.375rem;
  height: 0.375rem;
  border-right: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  transform: rotate(-45deg);
  transition: transform var(--duration-fast, 120ms) var(--ease-standard, ease);
}
.db-rule-details[open] .db-rule-summary::before { transform: rotate(45deg); }
.db-rule-details[open] .db-rule-summary { margin-bottom: 0.5rem; }

/* Inputs and derived values, folded at the foot of the sheet. */
.db-rep-details {
  border-top: 1px solid var(--border-divider);
  margin-top: 0.9375rem;
  padding-top: 0.9375rem;
}
.db-rep-details-summary { cursor: pointer; list-style: none; }
.db-rep-details-summary::-webkit-details-marker { display: none; }
.db-rep-details-summary .gl-k::before {
  content: "";
  display: inline-block;
  width: 0.375rem;
  height: 0.375rem;
  margin-right: 0.5rem;
  vertical-align: 0.125rem;
  border-right: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  transform: rotate(-45deg);
  transition: transform var(--duration-fast, 120ms) var(--ease-standard, ease);
}
.db-rep-details[open] .db-rep-details-summary .gl-k::before { transform: rotate(45deg); }
.db-rep-details > .db-rep-sec { border-top: none; padding-top: 0.75rem; }
.db-rep-details > .db-rep-sec + .db-rep-sec { border-top: 1px solid var(--border-divider); }
.db-rep-sub-k { color: var(--on-surface-1); }

/* Provenance foot: identity rows, last and quiet. */
.db-rep-foot {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.5rem;
}
.db-rep-foot-row { display: flex; gap: 0.375rem; align-items: baseline; min-width: 0; }
.db-rep-foot-note { margin: 0; font-size: 0.75rem; font-style: italic; color: var(--on-surface-2); }
.db-rep-foot dt { margin: 0; }
.db-rep-foot dd {
  margin: 0;
  font-size: 0.75rem;
  color: var(--on-surface-1);
  overflow-wrap: anywhere;
}

/* ---- control rail: what leaves the building, and what holds it back ------ */

.db-crail {
  width: 18.5rem;
  flex: none;
  border-left: 1px solid var(--border-divider);
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}
.db-crail-sec {
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border-divider);
  display: grid;
  gap: 0.4375rem;
  align-content: start;
}
.db-crail-head { display: flex; align-items: baseline; gap: 0.625rem; }
.db-crail-open { margin-left: auto; font-size: 0.75rem; }
.db-crail-copy {
  margin: 0;
  font-size: 0.71875rem;
  line-height: 1.5;
  color: var(--on-surface-2);
}
.db-crail-actions { display: grid; gap: 0.375rem; }
.db-crail-actions .btn { width: 100%; }
.db-conf-count { margin-left: auto; font-size: 0.78125rem; }
.db-crail-evidence { flex: 1; min-height: 0; border-bottom: none; }
.db-ev-thumb {
  border: 1px solid var(--border-divider);
  border-radius: var(--radius-md);
  background: var(--surface-0);
  height: 8.75rem;
  overflow: hidden;
}
.db-ev-thumb svg {
  width: 100%;
  height: 100%;
  display: block;
  font-family: var(--font-body);
  font-feature-settings: "tnum";
}

/* ---- evidence drill-down: plot at full size, matches at full height ------ */

.db-ev-dialog {
  width: min(72rem, 94vw);
  height: min(46rem, 88vh);
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.db-ev-sub { font-size: 0.71875rem; color: var(--on-surface-2); max-width: 34rem; }
.db-ev-dialog .db-dialog-close { margin-left: auto; }
.db-ev-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
  padding-top: 0.625rem;
}
.db-ev-body .db-plot {
  flex: none;
  height: 24rem;
  border-right: none;
  padding: 0;
}
/* The plot SVG is a fixed 560x330 viewBox. Left to fill a column three times
   that wide it letterboxes, and "full size" buys dead gutters instead of a
   bigger plot. Cap the well at the height's own aspect and centre it: the
   drawing then fills its box at ~652x384, larger than the 620x300 it had in
   the pre-Phase-2 mid row. */
.db-ev-body .db-plot-svg-wrap {
  width: 100%;
  max-width: 40.75rem;
  align-self: center;
}
.db-ev-body .db-matches { flex: 1; min-height: 0; }
.db-ev-body .db-matches-scroll { padding: 0; }
/* Field remarks are full NGL narrative paragraphs. Unclamped, one match fills
   the drill-down and the ranking stops being scannable, so they clamp to five
   lines with a button that opens the rest in place.

   The clamp rides the inner div, never the cell. A <td> cannot become a
   -webkit-box: the browser forces display:flow-root, the clamp is silently
   ignored, and only overflow:hidden takes effect, which crops the text at the
   row's height with no ellipsis and no word boundary. That is what this rule
   did until 2026-09-02. */
.db-ev-body .db-match-remarks-text {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 5;
  line-clamp: 5;
  overflow: hidden;
}
.db-ev-body .db-match-remarks-text.is-expanded {
  display: block;
  -webkit-line-clamp: none;
  line-clamp: none;
  overflow: visible;
}
.db-match-remarks-more {
  margin-top: 2px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  font: inherit;
  font-size: 0.71875rem;
  color: var(--accent-600);
}
.db-match-remarks-more:hover { text-decoration: underline; }

.db-plot {
  flex: 1;
  min-width: 0;
  padding: 0.6875rem 1rem 0.8125rem;
  display: flex;
  flex-direction: column;
  gap: 0.5625rem;
  border-right: 1px solid var(--border-divider);
}
.db-plot-head { display: flex; align-items: baseline; gap: 0.875rem; }
.db-plot-head .gl-k { white-space: nowrap; }
.db-plot-sub { font-size: 0.75rem; color: var(--on-surface-2); white-space: nowrap; }
.db-frame input[type="checkbox"] { accent-color: var(--accent-600); }
.db-plot-toggles {
  /* Own row under the plot head: the full curve citations (Boulanger &
     Idriss 2014 etc., 2026-08-25 founder request) cannot share the head
     row with the kicker + sub in the ~620px mid column. */
  display: flex;
  gap: 1rem;
  font-size: 0.78125rem;
}
/* Dashboard only: tuck the toggle row toward the head it belongs to. The
   cpt page keeps the toggles inside its wrapping results-card head, where
   a negative margin would overlap the wrapped line. */
.db-plot > .db-plot-toggles { margin-top: -0.25rem; }
.db-plot-toggles label {
  display: flex; gap: 0.3125rem; align-items: center; cursor: pointer;
  white-space: nowrap;
}
.db-plot-svg-wrap { width: 100%; flex: 1; min-height: 0; }
.db-plot-svg-wrap svg {
  width: 100%;
  height: 100%;
  display: block;
  font-family: var(--font-body);
  font-feature-settings: "tnum";
}
.db-plot-legend {
  display: flex;
  gap: 1.125rem;
  font-size: 0.75rem;
  color: var(--on-surface-2);
  flex-wrap: wrap;
  align-items: center;
}
.db-plot-legend .db-legend-item { display: flex; gap: 0.375rem; align-items: center; }
.db-plot-legend .db-legend-note { color: var(--on-surface-2); }

/* screening + memo are report sections now: no fixed-height judgement stack,
   no inner scrollers. The sheet scrolls as one document. */
.db-panel-head { display: flex; align-items: baseline; gap: 0.625rem; }
.db-panel-meta { margin-left: auto; font-size: 0.71875rem; color: var(--on-surface-2); }
/* CLAUDE.md-mandated data-thin preface: verbatim and prominent */
.db-thin-preface {
  font-size: 0.78125rem;
  line-height: 1.45;
  color: var(--warn-800);
  background: var(--warn-soft);
  border: 1px solid var(--warn-800);
  border-radius: var(--radius-sm);
  padding: 0.3125rem 0.5rem;
}
.db-screening table { width: 100%; border-collapse: collapse; }
/* Real payloads carry two borings plus the preface where the mock had one
   row: tighter cells than the base .gl-td keep the memo panel alive below */
.db-screening .gl-td {
  padding: 0.5rem 0.75rem 0.5rem 0;
  font-size: 0.875rem;
  vertical-align: top;
}
.db-screening .db-decision { line-height: 1.5; color: var(--on-surface-1); }
/* Decision column as an outlined chip. Never filled, never coloured by the
   column's severity: no screening status rides a fill (design plan D2). */
.db-col-chip {
  display: inline-block;
  border: 1px solid var(--on-surface-1);
  border-radius: 999px;
  padding: 0 0.45em;
  font-size: 0.75rem;
  line-height: 1.5;
}
.db-screening td:first-child { white-space: nowrap; }
.db-screening td:nth-child(2) { white-space: nowrap; }
.db-screening .db-thin-mark { color: var(--on-surface-1); font-size: 0.6875rem; }
/* The site conclusion is core's own plain-English sentence; it leads the
   table at body size rather than trailing it as a footnote. */
.db-site-conclusion {
  margin: 0;
  font-size: 0.875rem;
  color: var(--on-surface-0);
  line-height: 1.55;
}
.db-site-conclusion:empty { display: none; }
.db-memo p {
  font-size: 0.875rem;
  line-height: 1.7;
  text-align: left;
  margin: 0;
  color: var(--on-surface-0);
  /* The measure: about 68 characters a line. The column does not move;
     only the text block inside it stops short of the right edge. */
  max-width: 68ch;
}
.db-memo p + p { margin-top: 0.5rem; }
.db-memo .db-memo-note { font-style: italic; color: var(--on-surface-2); }
.db-memo .gl-grp { margin-top: 1rem; }
.db-memo .gl-grp + p { margin-top: 0.375rem; }
/* Section headings carry a hairline in the accent: colour marks structure
   here, never a screening state (design plan D2). */
.db-memo .db-memo-h {
  color: var(--accent-700);
  border-bottom: 1px solid var(--accent-ring);
  padding-bottom: 0.25rem;
  max-width: 68ch;
}
/* The claim line: each section's first sentence, the one the prompt makes
   its conclusion. Weight only; 500 exists in DM Sans, 600 does not. */
.db-memo-lead { font-weight: 500; color: var(--on-surface-0); }
/* The verdict word inside prose: weight and tracking, no fill, no hue. */
.db-memo-verdict { font-weight: 700; letter-spacing: 0.04em; }
/* Pointer clauses are asides: italic, accent, jump on click. */
.db-memo-ptr { font-style: italic; color: var(--accent-700); text-decoration: none; }
.db-memo-ptr:hover { text-decoration: underline; }
/* margin-left bumped from 1px: at 0.65em the row marker sat close enough to
   the preceding digit to misread as one run of digits (the "5621" reading
   in the lens-02-ux audit was a readability symptom of the same closeness
   that made the un-labelled accessible name unreadable). user-select: none
   is a second line of defence for copied text now that the anchor's
   aria-label carries the real citation and the sup itself is aria-hidden:
   selecting and pasting the citation should not additionally paste the row
   marker digit onto the end of the site id either. */
.db-memo-cite-n { font-size: 0.65em; color: var(--accent-700); margin-left: 0.15em; user-select: none; }

/* case-history matches */
.db-matches { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.db-matches-head {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  padding: 0.625rem 0.875rem 0.375rem;
  flex: none;
}
.db-matches-sub { font-size: 0.75rem; color: var(--on-surface-2); }
.db-matches-ctl { margin-left: auto; font-size: 0.75rem; color: var(--on-surface-2); }
.db-matches-scroll { flex: 1; min-height: 0; padding: 0 0.875rem 0.625rem; }
.db-matches table { width: 100%; border-collapse: collapse; }
.db-match-rank { color: var(--on-surface-1); }
.db-match-site { display: grid; gap: 1px; }
.db-match-name { font-size: 0.84375rem; }
.db-match-ref { font-size: 0.6875rem; color: var(--on-surface-1); }
.db-match-remarks { max-width: 17.5rem; line-height: 1.5; font-size: 0.8125rem; }
.db-match-tags { display: flex; flex-wrap: wrap; gap: 0.25rem; }
.db-match-tags .tag-outline { border: 1px solid var(--on-surface-2); }
.db-match-sim { text-align: right; padding-right: 0; }
.db-th-right { text-align: right; padding-right: 0; }

/* ---- live-run chrome: skeletons, delta strip, OOR marks, walls, dialogs -- */

@keyframes db-skel-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}
.db-skel { position: relative; }
.db-skel > * { visibility: hidden; }
.db-skel::after {
  content: "";
  position: absolute;
  inset: 0.625rem 0.875rem;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  animation: db-skel-pulse 1.4s ease-in-out infinite;
}

/* delta strip: rides directly under the verdict band, dismissible */
.db-delta {
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.25rem 1.125rem;
  border-bottom: 1px solid var(--border-divider);
  background: var(--warn-soft);
  font-size: 0.75rem;
  color: var(--on-surface-2);
}
.db-delta-close {
  margin-left: auto;
  border: none;
  background: none;
  color: var(--on-surface-2);
  font-size: 0.875rem;
  cursor: pointer;
  padding: 0 2px;
}

/* out-of-range field marks; the run-error strip in the rail */
.gl-in.db-oor { border-color: var(--accent-600); }
.gl-in.db-input-error { border-color: var(--danger-600); }
.db-oor-note { font-size: 0.75rem; color: var(--accent-700); line-height: 1.4; }
.db-run-error {
  font-size: 0.71875rem;
  color: var(--danger-600);
  line-height: 1.4;
  border: 1px solid var(--danger-600);
  border-radius: var(--radius-sm);
  padding: 0.3125rem 0.5rem;
}

/* memo stage line + compliance warning */
.db-memo-stage {
  font-size: 0.71875rem;
  color: var(--on-surface-2);
  font-style: italic;
}
.db-compliance-warn {
  font-size: 0.75rem;
  color: var(--danger-600);
  border: 1px solid var(--danger-600);
  border-radius: var(--radius-sm);
  padding: 0.3125rem 0.5rem;
  line-height: 1.4;
}

/* auth / billing walls: full-viewport overlays above the frame */
.db-wall {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: var(--surface-0);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: auto;
}
.db-wall-inner { max-width: 30rem; width: 100%; padding: 1.5rem; }

/* ---- signed-out front door (Phase 1, UX-REBUILD-PLAN-2026-08-26) ----------
   The auth wall is not a bare overlay any more: it is a two-column front
   door, explain left and the Clerk panel right. Three things hold it up.

   1. The wall keeps .db-wall (fixed, inset 0, z-index 40, opaque). The
      dashboard behind it is a worked example a signed-out visitor has no
      context for, so it stays covered; the door supplies the context
      instead.
   2. The header and footer are lifted ABOVE the wall (z-index 45, under the
      dialog backdrop at 50) so the page chrome, brand and product name stay
      on screen while the door is up. .db-door therefore reserves vertical
      room for them with padding rather than insetting itself, since both
      bars are content-sized, not fixed-height.
   3. Every size is in rem so the door rides html.db-root's clamp, the same
      as the dashboard. Verified at 1440x900, 1366x768 and 390x844.

   Clerk mounts into a fresh child of .db-door-panel, never the panel itself
   and never the wall: see wallMountNode in js/dashboard/auth.mjs. Nothing
   here may be moved onto the element a Clerk mount receives. */
.db-header, .db-footer { position: relative; z-index: 45; }

.db-door { align-items: flex-start; padding: 4rem 1.5rem 3rem; }
.db-door-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 24rem;
  gap: 2.5rem;
  align-items: start;
  width: 100%;
  max-width: 66rem;
  margin: auto;
}
.db-door-explain { min-width: 0; }
.db-door-eyebrow { display: block; letter-spacing: 0.06em; }
.db-door-h1 {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 2.125rem;
  line-height: 1.15;
  margin: 0.5rem 0 0.75rem;
  color: var(--on-surface-0);
}
.db-door-lead {
  margin: 0 0 1.25rem;
  font-size: 1rem;
  line-height: 1.55;
  color: var(--on-surface-0);
  max-width: 34rem;
}
.db-door-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 0 2rem;
  margin: 0 0 1.25rem;
  padding: 0.625rem 0;
  border-top: 1px solid var(--border-divider);
  border-bottom: 1px solid var(--border-divider);
}
.db-door-fact { min-width: 0; }
.db-door-fact dt { margin: 0; }
.db-door-fact dd { margin: 0.125rem 0 0; font-size: 0.9375rem; color: var(--on-surface-0); }
.db-door-cols {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.5rem;
  margin-bottom: 1.125rem;
}
.db-door-col p {
  margin: 0.3125rem 0 0;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--on-surface-0);
}
.db-door-crosslink {
  margin: 0 0 1rem;
  font-size: 0.875rem;
  color: var(--on-surface-0);
}
.db-door-crosslink a, .db-door-foot a { color: var(--accent-700); }
.db-door-crosslink a:hover, .db-door-foot a:hover { color: var(--accent-600); text-decoration: underline; }
.db-door-foot {
  margin: 0;
  padding-top: 0.625rem;
  border-top: 1px solid var(--border-divider);
  font-size: 0.71875rem;
  line-height: 1.5;
  color: var(--on-surface-2);
}
/* The Clerk sign-in card sizes itself; the panel only reserves the column and
   keeps the card at the top of it. Its class attribute is never touched by
   Clerk, because Clerk is handed a child of this element. */
.db-door-panel { display: flex; justify-content: center; min-width: 0; }

@media (max-width: 60rem) {
  .db-door { padding: 3.5rem 1rem 2.5rem; }
  .db-door-split { grid-template-columns: minmax(0, 1fr); gap: 1.75rem; max-width: 34rem; }
  .db-door-h1 { font-size: 1.75rem; }
  .db-door-cols { grid-template-columns: minmax(0, 1fr); gap: 1rem; }
  .db-door-facts { gap: 0.75rem 1.5rem; }
  /* The explainer stays FIRST when the columns stack. Ordering the panel
     first would put the sign-in card above the fold and the statement of
     what the engine is below it, which is defect D1 again at 390px. */
  .db-door-panel { justify-content: flex-start; }
}

/* The CPT door is not inside html.db-root, so it has no root clamp and no
   .db-frame chrome above the wall. Give it the same reading measure at the
   page's own 16px root. */
.cpt-body .db-door { padding-top: 2.5rem; }

/* dialogs (harness.css supplies .dialog-backdrop/.dialog visuals) */
.dialog-backdrop { z-index: 50; }
.db-dialog-close {
  margin-left: auto;
  border: none;
  background: none;
  color: var(--on-surface-2);
  font-size: 0.9375rem;
  cursor: pointer;
  padding: 0 2px;
}
.db-sites-dialog { width: min(35rem, 92vw); }
.db-sites-body { max-height: 18.75rem; display: grid; gap: 0.5rem; padding: 0.375rem 0; }
.db-site-row { display: grid; gap: 2px; border-top: 1px solid var(--border-divider); padding-top: 0.5rem; }
.db-site-name { font-size: 0.84375rem; }
.db-site-meta { font-size: 0.71875rem; color: var(--on-surface-2); }
.db-sites-foot { display: flex; gap: 0.5rem; align-items: center; padding-top: 0.5rem; }
.db-sites-status { font-size: 0.71875rem; color: var(--on-surface-2); }
.db-dialog-copy { font-size: 0.8125rem; line-height: 1.5; margin: 0.5rem 0; }
.db-adv-body { display: grid; gap: 0.625rem; padding-top: 0.5rem; min-width: 20rem; }
.db-adv-check {
  display: flex;
  gap: 0.5rem;
  align-items: flex-start;
  font-size: 0.78125rem;
  line-height: 1.45;
  cursor: pointer;
}

/* ---- rail accordion (inert on desktop, real on phone/tablet) ------------- */

/* Slack distribution (2026-08-25 readability pass): at viewport heights
   above the 56.25rem design frame the rail's spare height used to pool in one
   dead gap above the Reset row. flex:1 + space-between spreads it between
   the groups instead; the gap value below is the minimum spacing when there
   is no slack. The ≤75rem band resets this for the accordion. */
.db-rail-details {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1;
  /* Safety net: on viewports below the supported scale envelope the rail
     scrolls in place instead of overflowing through the footer buttons.
     Within the envelope there is never overflow, so this stays inert and
     the never-scrolls design contract holds. */
  overflow-y: auto;
}
/* Chromium 131+ (and other modern engines) wrap a details element's content
   in an internal ::details-content box, which would break the flex chain
   from .db-rail-details down to .db-rail-groups; give the wrapper the same
   column-flex role. Engines without the pseudo lay the children out
   directly, where the parent rules above already apply. */
.db-rail-details::details-content {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1;
}
.db-rail-details > .db-rail-groups {
  display: flex;
  flex-direction: column;
  gap: 0.1875rem;
  flex: 1;
  justify-content: space-between;
}
.db-rail-summary { display: none; }
.db-mobile-bar { display: none; }

/* ---- footer (~36px at design scale) ------------------------------------------------------ */

.db-footer {
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.875rem;
  padding: 0.4375rem 1.125rem;
  border-top: 1px solid var(--border-divider);
  font-size: 0.71875rem;
  color: var(--on-surface-2);
}
.db-footer-links { display: flex; gap: 0.875rem; flex: none; }
.db-footer-vr { width: 1px; align-self: stretch; background: var(--border-divider); flex: none; }
.db-danger-link { color: var(--danger-600); }
.db-footer .db-danger-link:hover { color: var(--danger-600); }
.db-independence {
  flex: 1;
  min-width: 0;
  line-height: 1.45;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.db-independence a { color: var(--on-surface-2); }
.db-independence a:hover { color: var(--accent-600); }

/* Memo citations: a case named in the memo links to its evidence row. */
.db-memo-cite {
  color: inherit;
  text-decoration: underline dotted;
  text-underline-offset: 2px;
}
.db-memo-cite:hover { color: var(--accent-600); text-decoration-style: solid; }
tr.db-match-cited td { background: color-mix(in srgb, var(--accent-600) 10%, transparent); }

/* ============================================================================
   Responsive bands. These MUST stay at the end of the file: their overrides
   share specificity with the base rules above, so source order is what makes
   them win (a band placed mid-file silently loses to later base rules).
   ========================================================================== */

/* ---- tablet band (~701-1200px): rail collapses to the accordion, the
   report sheet and control rail stack under it; the page scrolls ---------- */

@media (max-width: 1200px) {
  body.db-body-root { overflow: auto; }
  .db-frame { height: auto; min-height: 100vh; }
  .db-main { flex-direction: column; }
  .db-rail {
    width: auto;
    border-right: none;
    border-bottom: 1px solid var(--border-divider);
    overflow: visible;
  }
  /* accordion mode: natural height, no slack distribution */
  .db-rail-details { flex: none; overflow-y: visible; }
  .db-rail-details::details-content { flex: none; }
  .db-rail-details > .db-rail-groups { flex: none; justify-content: flex-start; }
  .db-rail-summary {
    display: flex;
    align-items: baseline;
    gap: 8px;
    cursor: pointer;
    list-style: none;
    font-size: 12px;
    padding: 4px 0;
  }
  .db-rail-summary::-webkit-details-marker { display: none; }
  .db-rail-edit { margin-left: auto; font-size: 11px; color: var(--accent-700); }
  .db-rail-foot { margin-top: 6px; }
  .db-rail-foot .btn { flex: none; }
  .db-verdict-label { font-size: 34px; }

  /* The sheet stops being a scroller of its own: the page scrolls instead,
     so a long memo is reachable without a nested scrollbar. */
  .db-desk { padding: 10px 12px; }
  .db-report { max-width: none; }
  .db-rep-scroll { overflow: visible; }
  .db-crail {
    width: auto;
    border-left: none;
    border-top: 1px solid var(--border-divider);
    overflow: visible;
  }
  .db-crail-evidence { flex: none; }
  .db-crail-actions { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---- phone band (~<=700px): one column, fixed action bar (frame 2a) ------
   The evidence drill-down stays a dialog here rather than unfolding onto the
   page as the pre-Phase-2 layout did: the plot and the match table are the
   second screen on every width, which keeps one evidence model instead of
   two. */

@media (max-width: 700px) {
  /* Flatten the desktop containers so every panel becomes a direct flex
     child of the frame and can be reordered. */
  .db-main, .db-desk, .db-report, .db-rep-scroll, .db-crail { display: contents; }

  .db-frame { padding-bottom: 64px; }
  /* The answer leads, then the inputs that produced it, then the rest of the
     report in its printed order. Screen-reader browse order follows the DOM
     and so differs from the visual order for the two promoted blocks;
     accepted, as in the 2026-08-25 layout: tab order stays monotonic and the
     landmarks survive the flattening. */
  /* Negative, not 1..5: every other flattened panel keeps the default
     order:0, so positive values would push these five BELOW the report body
     instead of above it. */
  .db-header { order: -5; }
  .db-delta { order: -4; }
  .db-rep-head { order: -3; }
  .db-rep-cover { order: -2; }
  .db-rail { order: -1; }

  /* Compact header: brand + case count + avatar only (frame 2a) */
  .db-header { gap: 8px; padding: 10px 14px 8px; }
  .db-header .db-vr, .db-header .db-title-stack, .db-header .db-vr-sm,
  .db-header #db-link-sites, .db-header #db-link-faq { display: none; }
  .db-brand { font-size: 15px; }
  .db-header-meta { gap: 8px; font-size: 10px; margin-left: 0; flex: 1; }
  .db-avatar { margin-left: auto; width: 20px; height: 20px; }

  /* Report chrome as stacked cards */
  .db-rep-head { padding: 10px 14px 8px; }
  .db-rep-stamp { font-size: 10px; }
  .db-rep-sec { padding: 11px 14px; border-bottom: 1px solid var(--border-divider); }
  .db-rep-sec + .db-rep-sec { border-top: none; padding-top: 11px; }
  .db-rep-end { margin: 0; padding: 11px 14px; border-top: none; }
  .db-rep-kv { grid-template-columns: 1fr; }
  .db-verdict-box { padding: 8px 16px 10px; }
  .db-verdict-label { font-size: 31px; line-height: 1.05; white-space: normal; }

  /* Inputs accordion: two-column grids inside */
  .db-rail { padding: 10px 14px; }
  .db-grid3, .db-grid4 { grid-template-columns: 1fr 1fr; }
  .db-span2 { grid-column: span 2; }

  /* Control rail sections become cards; the fixed bar carries Run, so the
     rail's own Run button would be a duplicate. */
  .db-crail-sec { padding: 11px 14px; }
  .db-crail-actions { grid-template-columns: 1fr 1fr; }
  .db-crail-actions #btn-run { display: none; }
  .db-ev-thumb { height: 150px; }

  /* Evidence dialog on a phone: full-bleed, plot in a horizontally
     scrolling well at its natural aspect, matches as stacked rows. */
  .db-ev-dialog { width: 96vw; height: 90vh; }
  .db-ev-sub { display: none; }
  .db-ev-body .db-plot { height: auto; }
  .db-plot-head { flex-wrap: wrap; gap: 8px; }
  .db-plot-toggles { margin-left: 0; flex-wrap: wrap; gap: 10px; }
  .db-plot-svg-wrap {
    overflow-x: auto;
    overflow-y: hidden;
    border: 1px solid var(--border-divider);
    border-radius: var(--radius-md);
  }
  .db-plot-svg-wrap svg { width: 640px; height: 250px; }

  .db-matches-head { flex-wrap: wrap; }
  .db-matches-scroll { overflow: auto; }
  .db-matches thead { display: none; }
  .db-matches table, .db-matches tbody { display: block; }
  .db-matches tr {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2px 10px;
    border-top: 1px solid var(--border-divider);
    padding: 8px 0;
  }
  .db-matches td { display: block; border-top: none; padding: 0; }
  .db-matches td:nth-child(1) { grid-column: 1 / -1; }
  .db-matches td:nth-child(2) { grid-column: 1 / -1; }
  .db-match-remarks { grid-column: 1 / -1; max-width: none; }
  .db-matches td:nth-child(8), .db-matches td:nth-child(9) { grid-column: 1 / -1; }
  .db-match-sim { text-align: left; }

  /* Footer wraps; independence statement un-truncates */
  .db-footer { flex-wrap: wrap; height: auto; }
  .db-independence { white-space: normal; overflow: visible; flex-basis: 100%; }

  /* Fixed bottom action bar */
  .db-mobile-bar {
    display: flex;
    gap: 8px;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 30;
    padding: 9px 14px 14px;
    border-top: 1px solid var(--border-divider);
    background: var(--surface-0);
  }
  .db-mobile-bar .btn-primary { flex: 1; }
}

/* P2 a11y: prefers-reduced-motion. harness.css already silences .skeleton
   and .btn; this covers the rest of this sheet's own motion: the one
   @keyframes animation it defines (the skeleton pulse) and the disclosure
   arrows' rotate transitions. The pointer-clause smooth scroll is JS-driven
   (page.mjs's scrollBehavior()), not CSS, so it is not here. */
@media (prefers-reduced-motion: reduce) {
  .db-skel::after { animation: none; }
  .db-rule-summary::before,
  .db-rep-details-summary .gl-k::before {
    transition: none;
  }
}
