/*
 * One spacing scale, one type scale, one neutral ramp, one accent, one radius.
 * Every value below this block is drawn from these and nothing is freehand.
 *
 * No webfont is loaded. A page that fetches a font makes an outbound request, and the
 * claim this tool is built on is that nothing leaves the machine.
 */

:root {
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-6: 24px;
  --space-8: 32px;
  --space-12: 48px;
  --space-16: 64px;

  --text-xs: 0.75rem;
  --text-sm: 0.8125rem;
  --text-base: 0.9375rem;
  --text-md: 1rem;
  --text-lg: 1.25rem;
  --text-xl: 1.75rem;
  --text-2xl: 2.25rem;

  --radius: 6px;
  --radius-pill: 999px;

  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

  /* Three landmark tracks at one lightness and one chroma, so no landmark outranks
   * another by accident, and the same three hues in both modes so the dark set is the
   * measured counterpart of the light one rather than a second hand-picked palette.
   * Acceptance is scripts/validate_palette.js, not an opinion. A status colour never
   * draws a mark on the trace: the takeoff rule's threshold is not a landmark, so it
   * takes ink and a dash rather than a hue. */
  --track-onset: #b54f05;
  --track-takeoff: #a8488d;
  --track-touchdown: #2172c6;
  --mark-threshold: var(--text-tertiary);
  --marker-contrast: #ffffff;

  color-scheme: light;
  --surface: #ffffff;
  --surface-raised: #f7f8f9;
  --surface-sunken: #eef1f4;
  --surface-inset: #e4e9ee;
  --border: #dde2e8;
  --border-strong: #b9c2cc;
  --text: #11181f;
  --text-secondary: #4f5b68;
  --text-tertiary: #78838f;
  --accent: #0a6a6f;
  --accent-hover: #085458;
  --accent-quiet: #e2f0f0;
  --accent-contrast: #ffffff;
  --warning: #9a5b00;
  --warning-quiet: #fdf3e2;
  --danger: #b42318;
  --danger-quiet: #fdeceb;
  --ok: #0f6b45;
  --ok-quiet: #e6f4ee;
  --trace: #1d2730;
  --grid: #eaeef2;
  --scrim: rgba(10, 15, 20, 0.5);
  --shadow: 0 8px 28px rgba(17, 24, 31, 0.16);
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --surface: #12171c;
  --surface-raised: #191f26;
  --surface-sunken: #0d1216;
  --surface-inset: #232b34;
  --border: #2a333d;
  --border-strong: #3d4954;
  --text: #e8edf2;
  --text-secondary: #a3aeb9;
  --text-tertiary: #7b8794;
  --accent: #47b3b0;
  --accent-hover: #63c6c3;
  --accent-quiet: #10312f;
  --accent-contrast: #06211f;
  --warning: #e0a33c;
  --warning-quiet: #2e2312;
  --danger: #f08b80;
  --danger-quiet: #33191a;
  --ok: #52bd8c;
  --ok-quiet: #10281f;
  --trace: #cfd9e2;
  --grid: #202832;
  --shadow: 0 8px 28px rgba(0, 0, 0, 0.5);
  --track-onset: #d76e33;
  --track-takeoff: #c967ac;
  --track-touchdown: #4492e7;
  /* The three tracks are lightened for a dark chart, so the label sitting on one takes the
     dark ink rather than the light: white on the lightened set reads at 3.2 to 3.5 against a
     4.5 floor, and the dark ink reads at 5.4 to 5.8. */
  --marker-contrast: #0d1216;
}

@media (prefers-color-scheme: dark) {
  :root[data-theme="auto"] {
    color-scheme: dark;
    --surface: #12171c;
    --surface-raised: #191f26;
    --surface-sunken: #0d1216;
    --surface-inset: #232b34;
    --border: #2a333d;
    --border-strong: #3d4954;
    --text: #e8edf2;
    --text-secondary: #a3aeb9;
    --text-tertiary: #7b8794;
    --accent: #47b3b0;
    --accent-hover: #63c6c3;
    --accent-quiet: #10312f;
    --accent-contrast: #06211f;
    --warning: #e0a33c;
    --warning-quiet: #2e2312;
    --danger: #f08b80;
    --danger-quiet: #33191a;
    --ok: #52bd8c;
    --ok-quiet: #10281f;
    --trace: #cfd9e2;
    --grid: #202832;
    --shadow: 0 8px 28px rgba(0, 0, 0, 0.5);
    --track-onset: #d76e33;
    --track-takeoff: #c967ac;
    --track-touchdown: #4492e7;
    --marker-contrast: #0d1216;
  }
}

*, *::before, *::after { box-sizing: border-box; }

/* A `display` declaration on a component beats the hidden attribute, and both the drawer
   and the workspace stage carry one. */
[hidden] { display: none !important; }

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.55;
  color: var(--text);
  background: var(--surface-sunken);
  -webkit-text-size-adjust: 100%;
}

h1, h2, h3 { margin: 0; line-height: 1.25; font-weight: 600; }
p { margin: 0; }
svg { stroke: currentColor; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius);
}

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: calc(var(--space-4) * -4);
  z-index: 50;
  padding: var(--space-2) var(--space-4);
  background: var(--accent);
  color: var(--accent-contrast);
  border-radius: var(--radius);
  text-decoration: none;
}
.skip-link:focus { top: var(--space-4); }

/* Spoken and not drawn. Clipped rather than hidden, because a hidden element is read by
   nothing, and one line high rather than none, because a zero-height box is dropped too. */
.offscreen {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

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

.app-header {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3) var(--space-6);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.app-header__identity { display: flex; align-items: center; gap: var(--space-3); }
.app-header__mark { width: 32px; height: 32px; flex: none; }
.app-header__mark rect { fill: var(--accent); }
.app-header__mark path { stroke: var(--accent-contrast); }
.app-header h1 { font-size: var(--text-md); letter-spacing: -0.01em; }
.app-header__tagline { font-size: var(--text-sm); color: var(--text-secondary); }
.app-header__status { display: flex; align-items: center; gap: var(--space-3); }

/* Quiet on purpose: a reader already working in the tab is not being sold the desktop
   application, only told where it is. */
.app-header__install {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Flex layout discards the space between the word and its longer phrase. */
  gap: var(--space-1);
  min-height: 44px;
  min-width: 44px;
  font-size: var(--text-sm);
  color: var(--text-secondary);
  white-space: nowrap;
}
.app-header__install:hover { color: var(--text); }

.privacy-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--ok);
  background: var(--ok-quiet);
  border: 1px solid color-mix(in srgb, var(--ok) 30%, transparent);
  border-radius: var(--radius-pill);
}
.privacy-badge__icon { width: 16px; height: 16px; flex: none; }

/* ---------------------------------------------------------------- banner */

.banner {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-6);
  font-size: var(--text-sm);
  border-bottom: 1px solid var(--border);
}
.banner--error { background: var(--danger-quiet); color: var(--text); border-bottom-color: color-mix(in srgb, var(--danger) 35%, transparent); }
.banner__body { display: grid; gap: var(--space-2); }
.banner strong { color: var(--danger); }
.banner__note { color: var(--text-secondary); }
.banner summary { cursor: pointer; color: var(--text-secondary); }

.violation-list {
  margin: var(--space-2) 0 0;
  padding-left: var(--space-4);
  display: grid;
  gap: var(--space-1);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  max-height: 220px;
  overflow-y: auto;
}

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

main { padding: var(--space-6); }
.stage { max-width: 1500px; margin: 0 auto; }

.workspace {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 380px;
  grid-template-areas:
    "trace decisions"
    "headlines decisions"
    "spread decisions"
    "metrics build";
  gap: var(--space-6);
  align-items: start;
}
.workspace__trace { grid-area: trace; }
.workspace__headlines { grid-area: headlines; }
.workspace__decisions {
  grid-area: decisions;
  position: sticky;
  top: var(--space-6);
  max-height: calc(100vh - var(--space-12));
  overflow-y: auto;
}
.workspace__spread { grid-area: spread; }
.workspace__metrics { grid-area: metrics; }
.workspace__build { grid-area: build; }
/* Grid and flex children default to min-width:auto, which lets a long unbroken string
   push the page sideways. */
.workspace > *, .panel, .metric, .metric-grid > *, .column-grid > *, .decision, .spread-controls > * { min-width: 0; }

.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-6);
}
.panel--standalone { max-width: 900px; margin: 0 auto; }
.panel--rail { padding: var(--space-4); }

.panel__head {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: var(--space-4);
}
.panel__head h2 { font-size: var(--text-md); }
.panel__sub, .panel__lead { font-size: var(--text-sm); color: var(--text-secondary); }
.panel__sub:empty { display: none; }
.panel__lead { margin-bottom: var(--space-4); }
.panel__head-actions { display: flex; gap: var(--space-2); }
.panel__foot { margin-top: var(--space-6); display: flex; justify-content: flex-end; }

/* ---------------------------------------------------------------- buttons */

.button {
  font: inherit;
  font-size: var(--text-sm);
  font-weight: 500;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 44px;
  padding: 0 var(--space-4);
  border-radius: var(--radius);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
}
.button:hover:not(:disabled) { background: var(--surface-raised); }
.button:disabled { opacity: 0.5; cursor: not-allowed; }
.button--primary { background: var(--accent); border-color: var(--accent); color: var(--accent-contrast); }
.button--primary:hover:not(:disabled) { background: var(--accent-hover); border-color: var(--accent-hover); }
.button--ghost { border-color: transparent; background: transparent; color: var(--text-secondary); }
.button--ghost:hover:not(:disabled) { background: var(--surface-raised); color: var(--text); }
.button--small { min-height: 32px; padding: 0 var(--space-3); font-size: var(--text-xs); }
.button--icon { min-height: 44px; width: 44px; padding: 0; }
.button--icon svg { width: 16px; height: 16px; }

/* ---------------------------------------------------------------- empty */

.empty { max-width: 780px; margin: var(--space-12) auto; display: grid; gap: var(--space-8); }
.empty--error { text-align: left; }
.empty--error h2 { font-size: var(--text-lg); color: var(--danger); }
.empty__hint { font-size: var(--text-sm); color: var(--text-secondary); }
.empty__hint code {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  background: var(--surface-inset);
  padding: var(--space-1);
  border-radius: var(--radius);
}

.dropzone {
  display: grid;
  justify-items: center;
  gap: var(--space-3);
  text-align: center;
  padding: var(--space-12) var(--space-6);
  background: var(--surface);
  border: 2px dashed var(--border-strong);
  border-radius: var(--radius);
  cursor: pointer;
}
.dropzone.is-over { border-color: var(--accent); background: var(--accent-quiet); }
.dropzone__icon { width: 40px; height: 40px; color: var(--text-tertiary); }
.dropzone h2 { font-size: var(--text-lg); }
.dropzone p { font-size: var(--text-sm); color: var(--text-secondary); max-width: 46ch; }
.dropzone__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); }

.loading { max-width: 420px; margin: var(--space-16) auto; display: grid; gap: var(--space-4); justify-items: center; }
.loading__bar { width: 100%; height: 4px; background: var(--surface-inset); border-radius: var(--radius-pill); overflow: hidden; }
.loading__bar span { display: block; width: 40%; height: 100%; background: var(--accent); border-radius: var(--radius-pill); animation: slide 1.1s ease-in-out infinite; }
@keyframes slide { 0% { transform: translateX(-100%); } 100% { transform: translateX(250%); } }

/* ---------------------------------------------------------------- columns */

.column-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--space-3); }

.column-card {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-3);
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  font: inherit;
  color: inherit;
}
.column-card:hover { border-color: var(--border-strong); }
.column-card[aria-checked="true"] { border-color: var(--accent); background: var(--accent-quiet); }
.column-card__name { font-weight: 600; font-size: var(--text-sm); display: flex; justify-content: space-between; gap: var(--space-2); align-items: center; }
.column-card__stats { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.column-card__spark { width: 100%; height: 32px; display: block; }
.column-card__spark path { stroke: var(--text-tertiary); fill: none; stroke-width: 1.2; }
.column-card[aria-checked="true"] .column-card__spark path { stroke: var(--accent); }

.field-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--space-4); margin-top: var(--space-6); }
.field { display: grid; gap: var(--space-1); }
.field--inline { grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: var(--space-2); }
.field label { font-size: var(--text-sm); font-weight: 500; }
.field__hint { font-size: var(--text-xs); color: var(--text-secondary); }
.field__input-group { display: flex; align-items: center; gap: var(--space-2); }
.field__suffix { font-size: var(--text-sm); color: var(--text-secondary); }

input[type="number"], input[type="text"], select {
  font: inherit;
  font-size: var(--text-sm);
  min-height: 44px;
  padding: 0 var(--space-3);
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  max-width: 100%;
}
select { cursor: pointer; }

/* A number the field has not accepted is not the number the results ran against, and the hint
   below it says which one did. The border is the second signal, because colour alone carries
   no meaning to a reader who cannot see it. */
input:invalid { border-color: var(--danger); }

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

.chart { position: relative; width: 100%; height: 380px; touch-action: none; overflow: hidden; user-select: none; }
.chart canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.chart__overlay { position: absolute; inset: 0; }

.marker {
  position: absolute;
  top: 0;
  width: 44px;
  margin-left: -22px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: ew-resize;
  font: inherit;
  color: inherit;
}
.marker::before {
  content: "";
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: 2px;
  height: 100%;
  background: var(--marker-colour);
}
.marker__label {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--marker-colour);
  color: var(--marker-contrast);
}
.marker__label--start { transform: none; }
.marker__label--end { transform: translateX(-100%); }
.marker--onset { --marker-colour: var(--track-onset); }
.marker--takeoff { --marker-colour: var(--track-takeoff); }
.marker--touchdown { --marker-colour: var(--track-touchdown); }
.marker--dragged .marker__label::after { content: " drag"; opacity: 0.75; font-weight: 400; }


/*
 * Focus on the trace, ringed in two colours rather than one.
 *
 * A single accent ring is drawn on top of whatever the mark is standing on, and what a
 * landmark stands on is its own hue: the accent reads 1.20 to 1.30 against the three tracks
 * in light and 1.28 to 1.39 in dark, against a floor of 3. The pair below is measured on
 * every colour the plot can put behind it. The surface ring touches the mark and reads 4.90
 * to 5.28 against the tracks in light, 5.17 to 5.59 in dark, 12.60 and 15.16 against the
 * trace. The text ring touches the panel and reads 17.88 and 15.30 against it.
 */
.marker:focus-visible,
.window-handle:focus-visible,
.selection-region:focus-visible {
  outline: none;
  background: color-mix(in srgb, var(--text) 8%, transparent);
}
.marker:focus-visible::before,
.window-handle:focus-visible::before,
.selection-region:focus-visible::before {
  box-sizing: content-box;
  border: 2px solid var(--surface);
  outline: 2px solid var(--text);
  outline-offset: 0;
}

.window-handle {
  position: absolute;
  top: 0;
  width: 24px;
  margin-left: -12px;
  border: 0;
  padding: 0;
  background: transparent;
  cursor: col-resize;
}
.window-handle::before {
  content: "";
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: 2px;
  height: 100%;
  background: var(--accent);
}
.window-body { position: absolute; top: 0; background: transparent; border: 0; cursor: grab; }
.window-body:active { cursor: grabbing; }
/* The band has no mark of its own to ring, so the two colours are its own edges. */
.window-body:focus-visible {
  border: 2px solid var(--surface);
  outline: 2px solid var(--text);
  outline-offset: -4px;
}

/* The band itself is drawn on the canvas. This layer is what a reader tabs to and what a
 * screen reader reads out, so it takes no ink of its own beyond the mark on the active span. */
.selection-layer { position: absolute; inset: 0; pointer-events: none; }
.selection-region {
  position: absolute;
  top: 0;
  border: 0;
  padding: 0;
  background: transparent;
  cursor: crosshair;
  pointer-events: auto;
}
.selection-region::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background: var(--text-tertiary);
}
.selection-region--active::before { height: 4px; background: var(--text); }

.chart-selection {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "readout actions" "numbers numbers";
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius);
  background: var(--surface-raised);
}
.chart-selection[hidden] { display: none; }
.chart-selection__actions { grid-area: actions; display: flex; flex-wrap: wrap; gap: var(--space-1); }
.chart-selection__readout {
  grid-area: readout;
  display: grid;
  gap: var(--space-1);
  font-size: var(--text-xs);
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.chart-selection__span { color: var(--text); font-family: var(--font-mono); }
.chart-selection__origin { color: var(--text-secondary); }

.chart-selection__numbers { grid-area: numbers; display: grid; gap: var(--space-2); }
.chart-selection__numbers[hidden] { display: none; }
.chart-selection__figures {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-6);
  margin: 0;
  padding-top: var(--space-2);
  border-top: 1px solid var(--border);
}
.chart-selection__figure { display: grid; gap: 0; }
.chart-selection__figure dt { font-size: var(--text-xs); color: var(--text-secondary); }
.chart-selection__figure dd {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.chart-selection__method {
  max-width: 44ch;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  overflow-wrap: anywhere;
}
.chart-selection__heading {
  margin: var(--space-1) 0 calc(-1 * var(--space-2));
  font-size: var(--text-xs);
  font-weight: 650;
  color: var(--text);
}
.chart-selection__no-landmarks,
.chart-selection__phase {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--text-secondary);
}
.chart-selection__phase {
  padding: var(--space-2);
  border-left: 3px solid var(--track-touchdown);
  background: color-mix(in srgb, var(--track-touchdown) 7%, transparent);
}
.chart-selection__elsewhere { margin: 0; font-size: var(--text-xs); color: var(--text-tertiary); }

.chart-crosshair {
  position: absolute;
  width: 0;
  pointer-events: none;
  color: var(--text);
}
.chart-crosshair__vertical,
.chart-crosshair__horizontal { position: absolute; display: block; background: var(--border-strong); opacity: 0.8; }
.chart-crosshair__vertical { top: 0; left: 0; width: 1px; height: 100%; }
.chart-crosshair__horizontal { height: 1px; }
.chart-crosshair__label {
  position: absolute;
  top: var(--space-1);
  left: 0;
  transform: translateX(-50%);
  z-index: 2;
  width: max-content;
  white-space: normal;
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
}
.chart-crosshair__label--start { transform: none; }
.chart-crosshair__label--end { transform: translateX(-100%); }

.chart-nav {
  display: grid;
  grid-template-columns: auto minmax(180px, 1fr);
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius);
  background: var(--surface-raised);
}
.chart-nav[hidden] { display: none; }
.chart-nav__actions { display: flex; gap: var(--space-1); }
.chart-nav__range { display: grid; grid-template-columns: auto minmax(100px, 1fr); align-items: center; gap: var(--space-3); font-size: var(--text-xs); color: var(--text-secondary); }
.chart-nav__range input { width: 100%; accent-color: var(--accent); }

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  margin-top: var(--space-3);
  font-size: var(--text-xs);
  color: var(--text-secondary);
}
.chart-legend span { display: inline-flex; align-items: center; gap: var(--space-2); }
.chart-legend i { width: 14px; height: 0; border-top-width: 2px; border-top-style: solid; display: inline-block; }
/* Three gestures, each under the thing it acts on, rather than one paragraph a reader has to
   read whole to find the one sentence about the marker they are holding. */
.chart-help {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-1) var(--space-3);
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  color: var(--text-tertiary);
}
.chart-help dt { color: var(--text-secondary); font-weight: 600; }
.chart-help dd { margin: 0; }

/* What a step through the history did to the record. It takes the quiet surface rather than a
   status colour, because nothing has gone wrong: a choice went back to what it was. */
.record-change {
  margin-top: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-left: 3px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface-sunken);
  font-size: var(--text-sm);
  color: var(--text);
}
.record-change[hidden] { display: none; }

/* ---------------------------------------------------------------- metrics */

.metric-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--space-3);
  align-items: start;
}
.metric-grid--headlines { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.metric {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-4);
  background: var(--surface-raised);
  border-radius: var(--radius);
}
.metric--headline { background: var(--accent-quiet); }
.metric__label { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-secondary); }
.metric__value {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: var(--space-2);
  row-gap: var(--space-1);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-lg);
  font-weight: 600;
  line-height: 1.1;
}
/* One step under the spread, and one step over the rest. The one large figure on the page
   is the disagreement rather than any measurement: leading with a measurement settles a
   live debate in favour of whichever side reads loudest. */
.metric--headline .metric__value { font-size: var(--text-xl); }
.metric__primary, .metric__secondary { white-space: nowrap; }
.metric__primary small { margin-left: var(--space-1); }
.metric__value small { font-size: var(--text-md); font-weight: 500; color: var(--text-secondary); }
.metric__value--absent { font-size: var(--text-md); color: var(--text-tertiary); font-family: var(--font-body); font-weight: 500; }
.metric__note { font-size: var(--text-xs); color: var(--text-secondary); }

/* A state of its own, and it is neither a warning nor an error: nothing has gone wrong,
   nobody has chosen yet. It borrows no status colour, because every one of those is spoken
   for by a meaning, and reads as ink on a quieter surface with a rule down its edge. */
.metric--provisional { background: var(--surface-sunken); border: 1px dashed var(--border-strong); }
.metric__provisional {
  display: grid;
  gap: var(--space-1);
  font-size: var(--text-xs);
  color: var(--text-secondary);
  border-left: 3px solid var(--border-strong);
  padding-left: var(--space-3);
}
.metric__provisional strong { color: var(--text); font-weight: 600; }
.metric__provisional code { font-family: var(--font-mono); font-size: var(--text-xs); overflow-wrap: anywhere; }
/* The open choices, named under the count and reaching the first of their rows on the rail. */
.metric__provisional-reach {
  justify-self: start;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--text);
  text-align: left;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.metric__provisional-reach:hover { color: var(--accent); }

/* The signal sits beside the number it is about rather than in a panel of its own, which
   is the whole of the pattern: the reader meets it where they read the value. */
.metric__signal {
  display: grid;
  gap: var(--space-1);
  font-size: var(--text-xs);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius);
  background: var(--warning-quiet);
  border: 1px solid color-mix(in srgb, var(--warning) 40%, transparent);
}
.metric__signal--incomparable { background: var(--surface-inset); border-color: var(--border); }
.metric__signal-figure { font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--warning); font-weight: 600; }
.metric__signal--incomparable .metric__signal-figure { color: var(--text-secondary); }
.metric__signal-remedy { color: var(--text); }

/* The same finding, on the other values it is about. One line rather than the paragraph,
   and it reaches the paragraph in one interaction. */
.metric__signal-elsewhere {
  display: grid;
  align-content: center;
  /* Sized by its own line rather than stretched down the card. Seven of these on one page
     is the case this exists for, and a stretched one is as tall as the paragraph it spares
     the reader. */
  align-self: start;
  gap: var(--space-1);
  text-align: left;
  width: 100%;
  min-height: 44px;
  font: inherit;
  font-size: var(--text-xs);
  color: var(--text-secondary);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius);
  background: var(--surface-inset);
  border: 1px dashed var(--border);
  cursor: pointer;
}
.metric__signal-elsewhere:hover { border-style: solid; color: var(--text); }

.metric-record {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-3);
  align-items: center;
  width: 100%;
  min-height: 36px;
  padding: var(--space-2) 0 0;
  border: 0;
  border-top: 1px dashed var(--border);
  background: transparent;
  color: var(--text-secondary);
  font: inherit;
  font-size: var(--text-xs);
  text-align: left;
  cursor: pointer;
}
.metric-record:hover { color: var(--text); border-top-color: var(--accent); }
.metric-record__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.metric-record__count { white-space: nowrap; font-variant-numeric: tabular-nums; }

/* The instants this number rests on, in the words the trace draws beside them. The rule under
   each one is monospaced because it is an identifier a reader retypes, not prose. */
.kv--landmarks dd { display: grid; gap: var(--space-1); }
.landmark-time { font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--text); }
.landmark-rule {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-secondary);
  overflow-wrap: anywhere;
}

/* The rules that would have produced this number instead, one row each, with the number
   beside the name so the comparison is a column a reader reads down rather than two panels
   they hold in their head. */
.competing__construct {
  margin-top: var(--space-3);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-secondary);
}
.competing { display: grid; gap: var(--space-1); min-width: 0; }
.competing__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius);
  background: var(--surface-raised);
}
.competing__row--running { background: var(--accent-quiet); }
.competing__name {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--text);
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.competing__name:hover { text-decoration: underline; }
.competing__mark { font-size: var(--text-xs); color: var(--text-secondary); }
.competing__value {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--text);
  white-space: nowrap;
}

.method-list { display: grid; gap: var(--space-2); min-width: 0; }
.method-list .provenance {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  min-height: 44px;
  min-width: 0;
  overflow: hidden;
  background: var(--surface-raised);
}
.method-list .rule-source { grid-column: 3; white-space: nowrap; }
.method-list .provenance__badges { grid-column: 2 / -1; flex-wrap: wrap; }

/* One line per contributing method, so the provenance stays shorter than the value it
   sits under. */
.provenance {
  font: inherit;
  font-size: var(--text-xs);
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  min-height: 26px;
  padding: var(--space-1) var(--space-2);
  text-align: left;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
}
.provenance:hover { background: var(--surface); border-color: var(--border); color: var(--text); }
.provenance__badges .tag { white-space: nowrap; }
.provenance__name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.provenance__badges { flex: none; display: flex; gap: var(--space-1); }
.provenance--unbacked .provenance__name { font-style: italic; }

.chip {
  font: inherit;
  font-size: var(--text-xs);
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-pill);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text-secondary);
  cursor: pointer;
  text-align: left;
}
.chip:hover { border-color: var(--accent); color: var(--text); }
.chip--unbacked { border-style: dashed; }
.chip--failing { border-color: color-mix(in srgb, var(--danger) 45%, transparent); color: var(--danger); background: var(--danger-quiet); }
.chip--override { border-color: color-mix(in srgb, var(--warning) 45%, transparent); color: var(--warning); background: var(--warning-quiet); }

/* The plate the tab analyses against, in the corner on every stage and one click from
   changing. It carries the count with its denominator rather than a tick, because a plate
   short of a member produces results that cannot be declared to match another lab's. */
.plate-chip { min-height: 32px; padding: var(--space-1) var(--space-3); }
.plate-chip__icon { width: 14px; height: 14px; flex: none; }
/* The cap sits on the name so a long one ellipsises on its own. Capping the chip made the
   name and the count compete for one budget, and the name lost at four characters. */
.plate-chip__name { min-width: 0; max-width: 16ch; overflow: hidden; text-overflow: ellipsis; color: var(--text); font-weight: 600; }
.plate-chip__count { flex: none; font-variant-numeric: tabular-nums; }

.plate-options { display: grid; gap: var(--space-2); margin-bottom: var(--space-3); }

.status-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--text-tertiary); }
.status-dot--recommended { background: var(--ok); }
.status-dot--accepted { background: var(--accent); }
.status-dot--contested { background: var(--warning); }
.status-dot--legacy { background: var(--text-tertiary); }
.status-dot--deprecated { background: var(--danger); }

.notice {
  display: grid;
  gap: var(--space-1);
  padding: var(--space-3);
  margin-top: var(--space-4);
  font-size: var(--text-sm);
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface-raised);
}
.notice--warning { border-color: color-mix(in srgb, var(--warning) 40%, transparent); background: var(--warning-quiet); }
.notice--danger { border-color: color-mix(in srgb, var(--danger) 40%, transparent); background: var(--danger-quiet); }
.notice strong { display: block; }

/* ---------------------------------------------------------------- decisions */

.decision { border-top: 1px solid var(--border); padding: var(--space-3) 0; }
.decision:first-child { border-top: 0; padding-top: 0; }
.decision__head { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: baseline; gap: var(--space-2); }
/* The row's quantity wraps rather than clipping. The tag and the claim beside it take the
   width a long one needs, and a quantity named halfway is the quantity unnamed. */
.decision__title { min-width: 0; font-size: var(--text-sm); font-weight: 600; }
.decision__meta { font-size: var(--text-xs); color: var(--text-tertiary); }
.decision__control, .decision__params { margin-top: var(--space-2); width: 100%; }
.decision__control { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-2); }
.decision__control select { width: 100%; min-width: 0; }
.decision__inspect { align-self: stretch; border-radius: var(--radius); }
.decision__params { display: grid; gap: var(--space-2); }
/* The rule an empty control is running. It wraps rather than clipping, because a rule named
   halfway is the rule unnamed, and it sits under the control the way an answer sits under
   the question it answers. */
.decision__running { display: block; margin-top: var(--space-2); font-size: var(--text-xs); color: var(--text); }
.decision--provisional { border-left: 3px solid var(--border-strong); padding-left: var(--space-3); }
/* A row carrying what ran rather than a question. It holds no control, so its title sits at
   the weight of a heading over a list instead of the weight of a label over a choice. */
.decision--record .decision__title { font-weight: 500; color: var(--text-secondary); }

/* Choices the rules beneath the chosen one take, folded away because the registry's verdict
   on most of them is to bind a value and not display it. Open, they are the same controls
   the panel above carries, so they take the same grid. */
.beneath { margin-top: var(--space-3); }
.beneath summary { cursor: pointer; font-size: var(--text-xs); color: var(--text-secondary); padding: var(--space-1) 0; }
.beneath .decision__params { margin-top: var(--space-2); }
.decision__settings { margin-top: var(--space-2); }
.decision__settings > summary { cursor: pointer; font-size: var(--text-xs); color: var(--text-secondary); padding: var(--space-1) 0; }
.decision__settings-body { display: grid; gap: var(--space-2); }

/* Rules that ran inside the chosen one and were never asked about. Displayed because the
   registry says to display them, quiet because nobody asked a question here. */
.ran-beside { display: grid; gap: var(--space-1); margin-top: var(--space-2); }
.ran-beside__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "title action" "value source";
  align-items: center;
  gap: var(--space-1) var(--space-2);
  width: 100%;
  min-height: 44px;
  font-size: var(--text-xs);
  color: var(--text-secondary);
  padding: var(--space-1) var(--space-2);
  text-align: left;
  font-family: var(--font-body);
  background: transparent;
  cursor: pointer;
  border-top: 1px dashed var(--border);
  border-right: 0;
  border-bottom: 0;
}
.ran-beside__row:hover { background: var(--surface-raised); color: var(--text); }
/* The two verdicts owe the reader different things, so they do not look the same. One is a
   value being shown unasked, which is content and reads solid. The other is an offer to go
   and look at what else was available, which is not a statement and reads open. */
.ran-beside__row--default-and-show { border-left: 3px solid var(--border-strong); padding-left: var(--space-2); }
.ran-beside__row--surface-on-demand { border-left: 3px dashed var(--border); padding-left: var(--space-2); }
.ran-beside__title { grid-area: title; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ran-beside__value { grid-area: value; min-width: 0; font-family: var(--font-mono); font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ran-beside__row > .rule-source { grid-area: source; white-space: nowrap; }
.ran-beside__action { grid-area: action; color: var(--text-tertiary); white-space: nowrap; }
.chip--quiet { border-style: dashed; color: var(--text-tertiary); }

/* Who chose the rule on a row, in the weight the values beside it already carry. Every rule
   has one, so it is a sentence and not a pill: a mark on all of them would read as a badge on
   the exceptional ones and carry none of the fact. Under a control it sits at half the gap
   that follows, so it reads as belonging to the rule above rather than to the values below. */
.rule-source { font-size: var(--text-xs); color: var(--text-secondary); }
.decision__head > .rule-source { white-space: nowrap; }

.tag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-pill);
}
.tag--decide { color: var(--warning); background: var(--warning-quiet); border: 1px solid color-mix(in srgb, var(--warning) 40%, transparent); }
.tag--advanced { color: var(--text-secondary); background: var(--surface-inset); }
.tag--provisional { color: var(--text-secondary); background: var(--surface-sunken); border: 1px dashed var(--border-strong); }
.tag--fails { color: var(--danger); background: var(--danger-quiet); border: 1px solid color-mix(in srgb, var(--danger) 40%, transparent); }

.undecided {
  margin-top: var(--space-2);
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-xs);
  color: var(--warning);
  background: var(--warning-quiet);
  border: 1px solid color-mix(in srgb, var(--warning) 40%, transparent);
  border-radius: var(--radius);
}

/* Label over control, one column, both kinds of value alike. Beside its label a control
   sized to its own contents starts at a different edge on every row, and an alternative the
   registry names is a sentence, which sizes that column to itself and leaves the label a
   letter wide. */
.param { display: grid; gap: var(--space-1); }
.param label { font-size: var(--text-xs); color: var(--text-secondary); overflow-wrap: anywhere; }
.param select, .param input { min-height: 36px; font-size: var(--text-xs); width: 100%; }


.kv { margin: 0; display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--space-1) var(--space-3); font-size: var(--text-xs); }
.kv dt { color: var(--text-secondary); }
.kv dd { margin: 0; font-family: var(--font-mono); overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------- spread */

.spread-controls {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-4);
  align-items: start;
  margin-bottom: var(--space-4);
}
.spread-axes, .run-suffixes { border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-3); margin: 0; }
.spread-axes legend, .run-suffixes legend { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-secondary); padding: 0 var(--space-1); }
.spread-axes__opening { margin: 0 0 var(--space-2); font-size: var(--text-xs); color: var(--text-secondary); }
.spread-axes__opening:empty { display: none; }
.spread-axes label, .run-suffixes label { display: flex; gap: var(--space-2); align-items: baseline; font-size: var(--text-xs); padding: var(--space-1) 0; cursor: pointer; }
.spread-axes input, .run-suffixes input { margin: 0; accent-color: var(--accent); min-width: 16px; min-height: 16px; }

.spread-headline {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-4);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-bottom: var(--space-4);
}
.spread-headline__figure {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-2xl);
  font-weight: 600;
  color: var(--accent);
  line-height: 1;
}
.spread-headline__text { font-size: var(--text-sm); color: var(--text-secondary); max-width: 52ch; }

.spread-axis { position: relative; height: 70px; margin: var(--space-3) 0 var(--space-4); }
.spread-axis__line { position: absolute; left: 0; right: 0; top: 18px; height: 2px; background: var(--border-strong); }
.spread-axis__span { position: absolute; top: 14px; height: 10px; background: color-mix(in srgb, var(--accent) 30%, transparent); border-radius: var(--radius-pill); }
.spread-tick { position: absolute; top: 4px; width: 2px; height: 30px; margin-left: -1px; background: var(--text-secondary); opacity: 0.55; }
.spread-tick--baseline { background: var(--accent); opacity: 1; height: 44px; top: -3px; width: 3px; }
.spread-bound { position: absolute; top: 36px; font-family: var(--font-mono); font-size: var(--text-xs); font-variant-numeric: tabular-nums; color: var(--text-secondary); white-space: nowrap; }
.spread-bound--max { transform: translateX(-100%); }
.spread-table-count { margin-bottom: var(--space-2); }
.spread-all { margin-top: var(--space-3); }
.spread-all > summary { cursor: pointer; color: var(--text-secondary); font-size: var(--text-xs); padding: var(--space-2) 0; }
.spread-all[open] > summary { margin-bottom: var(--space-2); }

/* Reaching a quantity the path does not visit. Sits under the rows it adds to, separated by
   a rule rather than by a card, because it is the same list continued. */
.add-quantity { margin-top: var(--space-4); padding-top: var(--space-4); border-top: 1px solid var(--border); display: grid; gap: var(--space-2); }
.add-quantity label { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-secondary); }
.add-quantity__list { list-style: none; margin: 0; padding: 0; max-height: 220px; overflow-y: auto; display: grid; gap: var(--space-1); }
.add-quantity__option {
  width: 100%;
  text-align: left;
  font: inherit;
  font-size: var(--text-xs);
  color: var(--text);
  background: none;
  border: 1px solid transparent;
  border-radius: var(--radius);
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
}
.add-quantity__option:hover { background: var(--surface-raised); border-color: var(--border); }
.add-quantity__none { font-size: var(--text-xs); color: var(--text-secondary); padding: var(--space-2) var(--space-3); }

/* What a folder needs declaring that one trial does not. Separated from the questions above
   it by a rule and a gap rather than by a second card, so the stage stays one question. */
.run-declaration { margin-top: var(--space-6); padding-top: var(--space-6); border-top: 1px solid var(--border); }
.run-declaration h3 { margin: 0; font-size: var(--text-sm); font-weight: 600; color: var(--text-secondary); }
.run-declaration .field-row { margin-top: var(--space-3); }

.batch-controls { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: center; margin-bottom: var(--space-4); }
.batch-controls__toggle { display: flex; gap: var(--space-2); align-items: center; font-size: var(--text-xs); color: var(--text-secondary); cursor: pointer; }
.batch-controls__toggle input { margin: 0; accent-color: var(--accent); min-width: 16px; min-height: 16px; }
.batch-summary { margin-bottom: var(--space-1); font-size: var(--text-md); font-weight: 600; font-variant-numeric: tabular-nums; }
.batch-declaration { margin: 0 0 var(--space-4); }
.batch-declaration:empty { display: none; }

.table-scroll { overflow-x: auto; }
table.data { width: 100%; border-collapse: collapse; font-size: var(--text-xs); }
table.data th, table.data td { text-align: left; padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--border); white-space: nowrap; }
table.data thead th { position: sticky; top: 0; z-index: 1; background: var(--surface); box-shadow: 0 1px 0 var(--border-strong); }
table.data td:first-child { max-width: 42ch; overflow: hidden; text-overflow: ellipsis; }
.batch-table { max-height: min(70vh, 720px); overflow: auto; }
table.data th { color: var(--text-secondary); font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; font-size: var(--text-xs); }
table.data td.numeric { font-family: var(--font-mono); font-variant-numeric: tabular-nums; text-align: right; }
table.data tr[data-extreme="low"] td, table.data tr[data-extreme="high"] td { background: var(--accent-quiet); }
table.data td.failed { color: var(--danger); white-space: normal; }
/* A row opens its own record from the name it is under. Underlined rather than boxed: a
   button drawn in every cell of a column reads as a column of buttons rather than as names. */
.row-record {
  font: inherit;
  display: block;
  width: 100%;
  min-height: 24px;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  text-decoration: underline dotted var(--text-tertiary);
  cursor: pointer;
}
.row-record:hover { color: var(--accent); text-decoration-color: var(--accent); }

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

.drawer { position: fixed; inset: 0; z-index: 40; display: flex; justify-content: flex-end; }
/* `display` here would otherwise beat the hidden attribute and leave the panel open. */
.drawer[hidden] { display: none; }
.drawer__scrim { position: absolute; inset: 0; background: var(--scrim); border: 0; }
.drawer__panel {
  position: relative;
  width: min(560px, 100%);
  background: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow: var(--shadow);
  display: flex;
  flex-direction: column;
  max-height: 100%;
  min-width: 0;
  overflow: hidden;
}
.drawer__head { display: flex; align-items: flex-start; gap: var(--space-3); padding: var(--space-4) var(--space-6); border-bottom: 1px solid var(--border); }
.drawer__head h2 { flex: 1; font-size: var(--text-md); }
.drawer__body { min-width: 0; padding: var(--space-6); overflow-x: hidden; overflow-y: auto; display: grid; gap: var(--space-6); }
/* A grid item is as wide as its widest content unless it is told otherwise, so a line too
   long for the panel widened the panel instead of scrolling inside the block holding it. */
.drawer__body > * { min-width: 0; }
.drawer__body h3 { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-secondary); margin-bottom: var(--space-2); }
.drawer__body p, .drawer__body li { font-size: var(--text-sm); }
.drawer__body ul { margin: 0; padding-left: var(--space-4); display: grid; gap: var(--space-2); }
.rule-text { font-family: var(--font-mono); font-size: var(--text-xs); line-height: 1.6; white-space: pre-wrap; background: var(--surface-sunken); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-3); overflow-x: auto; }
/* Each step's distance from the number is written in leading spaces, so a wrapped line
   would put a rule that fed another rule at the depth of the one it fed. */
.account { margin: 0; white-space: pre; }
.metric-account { min-width: 0; }
.metric-account > summary { color: var(--text-secondary); cursor: pointer; font-size: var(--text-sm); font-weight: 600; }
.metric-account[open] > summary { margin-bottom: var(--space-2); color: var(--text); }
.drawer a { color: var(--accent); }

/* ---------------------------------------------------------------- footer */

.app-footer { padding: var(--space-6); text-align: center; font-size: var(--text-xs); color: var(--text-tertiary); }
.app-footer a { color: var(--text-secondary); }

/* ---------------------------------------------------------------- narrow */

@media (max-width: 1080px) {
  .workspace {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "trace"
      "headlines"
      "decisions"
      "spread"
      "metrics"
      "build";
    gap: var(--space-3);
  }
  .workspace__decisions { position: static; max-height: none; overflow-y: visible; }
}

@media (max-width: 640px) {
  /* A narrow screen is a touch screen often enough that the compact desktop sizes are the
     wrong default here, whatever the pointer media query reports. */
  .button--small { min-height: 44px; padding: 0 var(--space-3); }
  .provenance { min-height: 44px; }
  .row-record { min-height: 44px; }
  .chip { min-height: 44px; padding: var(--space-2) var(--space-3); }
  .param select, .param input { min-height: 44px; }
  .beneath summary, .metric-account > summary { min-height: 44px; padding: var(--space-3) 0; }
  .decision__settings > summary { min-height: 44px; display: flex; align-items: center; padding: var(--space-2) 0; }
  .add-quantity input, .add-quantity__option { min-height: 44px; }
  .spread-axes label { min-height: 44px; align-items: center; }
  .spread-axes input { min-width: 20px; min-height: 20px; }
  .spread-all > summary { min-height: 44px; display: flex; align-items: center; }
  .skip-link { min-height: 44px; display: inline-flex; align-items: center; }
  .window-handle { width: 44px; margin-left: -22px; }
  .marker__label { padding: var(--space-1); }
  .drawer__head { padding: var(--space-3) var(--space-4); }
  .drawer__body { padding: var(--space-4); gap: var(--space-4); }

  main { padding: var(--space-4) var(--space-3); }
  .app-header { padding: var(--space-3) var(--space-4); }
  .app-header__tagline { display: none; }
  .banner { padding: var(--space-3) var(--space-4); }
  .panel { padding: var(--space-4); }
  .empty { margin: var(--space-6) auto; }
  .dropzone { padding: var(--space-8) var(--space-4); }
  .dropzone__actions { width: 100%; }
  .dropzone__actions .button { flex: 1 1 auto; }
  .chart { height: 180px; }
  .chart-help { display: none; }
  .chart-nav { grid-template-columns: minmax(0, 1fr); }
  .chart-nav__actions .button { flex: 1; }
  .chart-selection { grid-template-columns: minmax(0, 1fr); }
  .chart-selection__actions .button { flex: 1 1 auto; }
  .chart-nav__range { grid-template-columns: minmax(0, 1fr); gap: var(--space-1); }
  .metric-grid { grid-template-columns: minmax(0, 1fr); }
  .metric-grid--headlines { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); }
  .metric--headline { gap: var(--space-1); padding: var(--space-3); }
  .decision { padding: var(--space-2) 0; }
  .metric-record { min-height: 44px; }
  .metric__value { font-size: var(--text-md); }
  .metric--headline .metric__value { font-size: var(--text-lg); }
  .spread-headline__figure { font-size: var(--text-xl); }
  .privacy-badge span { display: none; }
  .privacy-badge { padding: var(--space-2); }
  .app-header__install span { display: none; }
}

/* Dense controls stay compact under a mouse and grow to a full touch target on a
   touch device, rather than being sized for one input and broken for the other. */
@media (pointer: coarse) {
  .button--small { min-height: 44px; padding: 0 var(--space-4); }
  .chip { min-height: 44px; padding: var(--space-2) var(--space-3); }
  .param select, .param input { min-height: 44px; }
  .spread-axes label, .run-suffixes label { padding: var(--space-2) 0; min-height: 44px; align-items: center; }
  .spread-axes input, .run-suffixes input { min-width: 22px; min-height: 22px; }
  .batch-controls__toggle { min-height: 44px; }
  .batch-controls__toggle input { min-width: 22px; min-height: 22px; }
  .add-quantity__option { min-height: 44px; }
  .add-quantity input { min-height: 44px; }
  .window-handle { width: 44px; margin-left: -22px; }
  .column-card { padding: var(--space-4); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}
