/* ==========================================================================
   components.css — Load order 3 of 3.
   Implements FU-V1 primitives (.disclosure, .kpi-bloom, .sparkline,
   .chip-row, .delta-arrow, .slide-over, .status-strip) + shipped
   FreshnessBadge / ChipFilter, plus this consumer's own shapes.
   ========================================================================== */

/* ==================== masthead / nav ==================== */

.pub-head {
  position: sticky;
  top: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--color-surface-bg) 92%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--color-border);
}

.pub-head__inner {
  display: flex;
  align-items: center;
  gap: var(--space-comfortable);
  min-height: 58px;
  padding-block: var(--space-compact);
}

.pub-mast {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  flex-shrink: 0;
}
.pub-mast:hover { text-decoration: none; }
.pub-mast {
  font-family: var(--type-family-display);
  font-size: 1.0625rem;
  letter-spacing: -0.02em;
  white-space: nowrap;
}
.pub-mast b { font-weight: var(--type-weight-semibold); }

.pub-nav {
  display: none;
  align-items: center;
  gap: 2px;
  margin-left: auto;
}
.pub-nav a {
  padding: 6px 10px;
  font-size: var(--type-scale-small);
  color: var(--color-text-secondary);
  border-radius: var(--radius-subtle);
  white-space: nowrap;
}
.pub-nav a:hover { background: var(--color-surface-bg-sunken); text-decoration: none; color: var(--color-text-primary); }
.pub-nav a[aria-current="page"] {
  color: var(--color-text-primary);
  font-weight: var(--type-weight-medium);
  box-shadow: inset 0 -2px 0 var(--color-accent-primary);
}

@media (min-width: 900px) { .pub-nav { display: flex; } .pub-nav-burger { display: none; } }

.pub-nav-burger {
  margin-left: auto;
  background: none;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-subtle);
  padding: 6px 11px;
  font-size: var(--type-scale-small);
}

.pub-nav-drawer {
  display: none;
  border-top: 1px solid var(--color-border);
  padding-block: var(--space-compact) var(--space-comfortable);
}
.pub-nav-drawer[data-open="true"] { display: block; }
.pub-nav-drawer a {
  display: block;
  padding: 10px 2px;
  font-size: var(--type-scale-body);
  border-bottom: 1px solid var(--color-border);
}
@media (min-width: 900px) { .pub-nav-drawer { display: none !important; } }

/* ==================== status strip (T0) ==================== */

.status-strip {
  background: var(--color-surface-bg-inverse);
  color: var(--color-text-inverse);
  /* R391: sticks BELOW the sticky header rather than at top:0, where it would
     slide underneath and vanish. .pub-head is `sticky; top:0; z-index:50`, so
     the offset is the header's own height and the z-index sits just under it.
     Together they hold 102px of chrome, which is the price of keeping the
     regime, conviction, macro-health and issue readings on screen while the
     reader scrolls -- the line they most often scroll back up to find. */
  position: sticky;
  top: var(--pub-head-h);
  z-index: 49;
}
/* A reader who has asked for less motion has not asked for less information,
   so the strip stays put rather than unsticking; nothing here animates. */
@media (max-height: 520px) {
  /* On a short viewport 102px of fixed chrome is a quarter of the screen.
     The header alone stays; the strip returns to the flow. */
  .status-strip { position: static; }
}
.status-strip-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-comfortable) var(--space-airy);
  padding-block: 11px;
}
.strip-chunk {
  display: flex;
  align-items: baseline;
  gap: 7px;
  font-size: var(--type-scale-small);
}
.strip-chunk dt {
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  text-transform: uppercase;
  letter-spacing: var(--type-tracking-wide);
  color: color-mix(in srgb, var(--color-text-inverse) 62%, transparent);
}
.strip-chunk dd {
  margin: 0;
  font-family: var(--type-family-mono);
  font-weight: var(--type-weight-medium);
  font-variant-numeric: tabular-nums;
}
.strip-spacer { margin-left: auto; }

/* ---- R391: the strip is the highest-value line on the site ----
   It was 11px, unlinked, on an inverse ground. Three changes:
   (1) the VALUE is raised to a readable size while the LABEL stays at eyebrow
       size, so the figure leads and its name recedes -- previously both sat at
       the same weight and the line read as a row of equal captions;
   (2) every value links to the surface that derives it (real anchors only);
   (3) the regime value carries its severity, re-bound below for dark ground. */
.strip-chunk dd {
  font-size: var(--type-scale-body);
  line-height: 1.25;
}
.strip-link {
  color: inherit;
  text-decoration-line: underline;
  text-decoration-color: color-mix(in srgb, var(--color-text-inverse) 38%, transparent);
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  border-radius: 2px;
}
.strip-link:hover,
.strip-link:focus-visible {
  text-decoration-color: currentColor;
  outline: 2px solid var(--color-text-inverse);
  outline-offset: 2px;
}

/* The severity ramp is authored for light ground. On the inverse strip the
   same foregrounds sit on near-black, where the amber and green lose contrast,
   so the strip re-binds --sev-fg to the lighter end of each palette ramp.
   This is a ground change, not a vocabulary change: sev_class() still decides
   WHICH severity applies, and the strip only decides how that severity is
   drawn against black. */
.status-strip .sev-green { --sev-fg: var(--palette-green-on-ink); }
.status-strip .sev-amber { --sev-fg: var(--palette-amber-on-ink); }
.status-strip .sev-red   { --sev-fg: var(--palette-red-on-ink); }
.status-strip .sev-void  { color: inherit; }
.status-strip .sev { color: var(--sev-fg); font-weight: var(--type-weight-semibold); }

/* The sticky header would otherwise land on top of whichever heading the
   strip links to. Offsets every in-page target by the header's own height. */
:target,
#composite, #board, #read {
  scroll-margin-top: calc(var(--pub-head-h, 56px) + var(--space-comfortable));
}

/* ==================== depth control ==================== */

.depth-bar {
  border-bottom: 1px solid var(--color-border);
  background: var(--color-surface-bg-subtle);
}
.depth-bar-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-comfortable);
  padding-block: 10px;
}

.segmented {
  display: inline-flex;
  padding: 2px;
  background: var(--color-surface-bg-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-subtle);
}
.segmented button {
  border: 0;
  background: none;
  padding: 5px 12px;
  font-size: var(--type-scale-caption);
  font-family: var(--type-family-mono);
  text-transform: uppercase;
  letter-spacing: 0.055em;
  color: var(--color-text-tertiary);
  border-radius: 2px;
  transition: background var(--motion-duration-subtle) var(--motion-easing-standard),
              color var(--motion-duration-subtle) var(--motion-easing-standard);
}
.segmented button[aria-pressed="true"] {
  background: var(--color-surface-bg-raised);
  color: var(--color-text-primary);
  box-shadow: var(--elevation-raised);
  font-weight: var(--type-weight-medium);
}

.depth-hint {
  font-size: var(--type-scale-caption);
  color: var(--color-text-tertiary);
  flex: 1 1 240px;
  min-width: 0;
}

/* ==================== chip row / filter ==================== */

.chip-row { display: flex; flex-wrap: wrap; gap: 6px; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-secondary);
  background: var(--color-surface-bg-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-rounded);
  transition: all var(--motion-duration-subtle) var(--motion-easing-standard);
}
.chip:hover { border-color: var(--color-border-strong); text-decoration: none; }
.chip[aria-pressed="true"] {
  background: var(--color-surface-bg-inverse);
  border-color: var(--color-surface-bg-inverse);
  color: var(--color-text-inverse);
}

/* ==================== severity tokens ==================== */

.sev { --sev-fg: var(--color-text-secondary); --sev-bg: var(--color-accent-neutral-soft); }
.sev-green  { --sev-fg: var(--color-accent-success); --sev-bg: var(--color-accent-success-soft); }
.sev-amber  { --sev-fg: var(--color-accent-warning); --sev-bg: var(--color-accent-warning-soft); }
.sev-red    { --sev-fg: var(--color-accent-danger);  --sev-bg: var(--color-accent-danger-soft); }
.sev-void   { --sev-fg: var(--color-text-tertiary);  --sev-bg: var(--color-accent-neutral-soft); }

.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  font-weight: var(--type-weight-medium);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--sev-fg, var(--color-text-secondary));
  background: var(--sev-bg, var(--color-accent-neutral-soft));
  border-radius: var(--radius-subtle);
  white-space: nowrap;
}
.badge-dot {
  width: 6px; height: 6px;
  border-radius: var(--radius-full);
  background: currentColor;
  flex-shrink: 0;
}

/* ==================== FreshnessBadge (shipped primitive) ==================== */

.freshness-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-tertiary);
}
.freshness-badge::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: var(--radius-full);
  background: var(--color-accent-success);
}
.freshness-badge[data-state="stale"] { color: var(--color-accent-warning); }
.freshness-badge[data-state="stale"]::before { background: var(--color-accent-warning); }
.freshness-badge[data-state="aged"] { color: var(--color-accent-danger); }
.freshness-badge[data-state="aged"]::before { background: var(--color-accent-danger); }
/* unknown: no readable cycle date. Styled explicitly because the base rule
   paints the dot success-green, so an unstyled fourth state would render as
   an assurance -- the exact failure the computed state exists to end. */
.freshness-badge[data-state="unknown"] { color: var(--color-text-tertiary); }
.freshness-badge[data-state="unknown"]::before { background: var(--color-text-tertiary); }
/* held: reviewed this cycle and deliberately not moved. A fifth state exists
   because the four above cannot express it and each available substitute
   misreports it. "stale" and "aged" say we did not look. "unknown" says we
   cannot tell, which is the opposite of a decision. The base rule's
   success-green says the value is current, which is true of the review and
   not of the value.

   Secondary text rather than tertiary, because a hold is a deliberate act and
   should not recede to the same weight as an absence. A ring rather than a
   filled dot: every other state fills its dot because the system computed it
   from a date, and a hold is the one state an editor chose. That difference
   survives greyscale and colour-blindness, which a hue change alone would
   not. */
.freshness-badge[data-state="held"] { color: var(--color-text-secondary); }
.freshness-badge[data-state="held"]::before {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--color-text-secondary);
}

/* ==================== card / panel ==================== */

.panel {
  background: var(--color-surface-bg-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-subtle);
  padding: var(--space-comfortable);
}
.panel-airy { padding: var(--space-airy); }
.panel-flush { padding: 0; overflow: hidden; }
.panel-quiet { background: var(--color-surface-bg-subtle); }

/* Declared pending state. A section we are collecting but do not yet hold.
   Dashed rather than solid so it reads as a deliberate absence at a glance,
   never as a panel that failed to render. */
.panel-pending {
  background: var(--color-surface-bg-subtle);
  border-style: dashed;
}

/* The pending chip. Same eyebrow register as .freshness-badge deliberately:
   both answer "can I rely on what is under this?", so they should not look
   like two unrelated inventions. Tertiary, not warning -- a panel that is
   still collecting is not a fault, and colouring it as one would train the
   reader to discount states that are working exactly as designed. */
.pending-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-tertiary);
  margin-right: 6px;
}
.pending-chip::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: var(--radius-full);
  background: var(--color-text-tertiary);
}

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-compact);
  flex-wrap: wrap;
  padding: 13px var(--space-comfortable);
  border-bottom: 1px solid var(--color-border);
  background: var(--color-surface-bg-subtle);
}

/* ==================== kpi-bloom (DL-V2 / FU-V1) ==================== */

.kpi-bloom {
  background: var(--color-surface-bg-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-subtle);
  overflow: hidden;
}
.kpi-bloom-rest {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  padding: var(--space-comfortable);
}
.kpi-bloom-rest:hover { background: var(--color-surface-bg-subtle); }
.kpi-bloom-value {
  display: flex;
  align-items: baseline;
  gap: var(--space-compact);
  margin-top: 6px;
}
.kpi-bloom-value .figure {
  font-family: var(--type-family-display);
  font-size: 2.125rem;
  line-height: 1;
  letter-spacing: -0.028em;
  font-variant-numeric: tabular-nums;
}
.kpi-bloom-sub {
  margin-top: 7px;
  font-size: var(--type-scale-caption);
  color: var(--color-text-tertiary);
  display: flex;
  align-items: center;
  gap: 6px;
}
.kpi-bloom-reveal {
  display: none;
  padding: var(--space-comfortable);
  border-top: 1px solid var(--color-border);
  background: var(--color-surface-bg-subtle);
  font-size: var(--type-scale-small);
}
.kpi-bloom[data-bloom="open"] .kpi-bloom-reveal { display: block; }

.bloom-caret {
  margin-left: auto;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  color: var(--color-text-tertiary);
  transition: transform var(--motion-duration-subtle) var(--motion-easing-standard);
}
.kpi-bloom[data-bloom="open"] .bloom-caret { transform: rotate(180deg); }

/* ==================== disclosure (FU-V1, Rule 9) ==================== */

.disclosure { border-top: 1px solid var(--color-border); }
.disclosure:first-of-type { border-top: 0; }

.disclosure-trigger {
  display: flex;
  align-items: center;
  gap: var(--space-compact);
  width: 100%;
  padding: 14px var(--space-comfortable);
  background: none;
  border: 0;
  text-align: left;
  transition: background var(--motion-duration-subtle) var(--motion-easing-standard);
}
.disclosure-trigger:hover { background: var(--color-surface-bg-subtle); }
.disclosure-trigger .caret {
  flex-shrink: 0;
  font-family: var(--type-family-mono);
  font-size: 0.625rem;
  color: var(--color-text-tertiary);
  transition: transform var(--motion-duration-subtle) var(--motion-easing-standard);
}
.disclosure[data-open="true"] .caret { transform: rotate(90deg); }

.disclosure-panel {
  display: none;
  padding: 0 var(--space-comfortable) var(--space-comfortable);
}
.disclosure[data-open="true"] .disclosure-panel { display: block; }

/* ==================== gauge ==================== */

.gauge-wrap { display: flex; align-items: center; gap: var(--space-airy); flex-wrap: wrap; }

.gauge-track {
  position: relative;
  height: 9px;
  border-radius: var(--radius-rounded);
  background: linear-gradient(90deg,
    var(--color-accent-danger) 0%,
    var(--color-accent-warning) 42%,
    var(--color-accent-success) 100%);
  flex: 1 1 220px;
  min-width: 160px;
}
.gauge-needle {
  position: absolute;
  top: -5px;
  width: 3px;
  height: 19px;
  background: var(--color-text-primary);
  border-radius: 2px;
  transform: translateX(-50%);
  box-shadow: 0 0 0 2px var(--color-surface-bg-raised);
}
.gauge-scale {
  display: flex;
  justify-content: space-between;
  margin-top: 7px;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  color: var(--color-text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* ==================== tripwire board ==================== */

.channel + .channel { margin-top: var(--space-airy); }

.channel-head {
  display: flex;
  align-items: baseline;
  gap: var(--space-compact);
  flex-wrap: wrap;
  padding-bottom: 7px;
  margin-bottom: var(--space-compact);
  border-bottom: 1px solid var(--color-border-strong);
}

.wire {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-subtle);
  background: var(--color-surface-bg-raised);
  border-left: 3px solid var(--sev-fg, var(--color-border));
}
.wire + .wire { margin-top: 6px; }

.wire-rest {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 4px var(--space-comfortable);
  align-items: center;
  width: 100%;
  background: none;
  border: 0;
  text-align: left;
  padding: 11px var(--space-comfortable);
}
.wire-rest:hover { background: var(--color-surface-bg-subtle); }

.wire-name { font-weight: var(--type-weight-medium); font-size: var(--type-scale-small); }
.wire-meta {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 13px;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  color: var(--color-text-tertiary);
}
.wire-figure {
  display: flex;
  align-items: baseline;
  gap: 7px;
  font-family: var(--type-family-mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.wire-figure .v { font-size: var(--type-scale-body-lg); font-weight: var(--type-weight-medium); }
.wire-figure .t { font-size: var(--type-scale-eyebrow); color: var(--color-text-tertiary); }

/* Below the board breakpoint the sparkline and its placeholder are dropped:
   the figure + threshold pair and the state badge are what the row is for. */
@media (max-width: 759px) {
  .wire-rest > .cluster { justify-self: end; flex-wrap: nowrap; }
  .wire-rest .sparkline { display: none; }
  .wire-rest > .cluster > .caption { display: none; }
  .wire-figure { flex-wrap: wrap; white-space: normal; }
}

@media (min-width: 760px) {
  .wire-rest { grid-template-columns: minmax(0, 1.5fr) minmax(0, 1.6fr) auto auto; }
  .wire-meta { grid-column: auto; flex-direction: column; gap: 2px; }
}

.wire-detail {
  display: none;
  padding: var(--space-comfortable);
  border-top: 1px dashed var(--color-border);
  background: var(--color-surface-bg-subtle);
}
.wire[data-open="true"] .wire-detail { display: block; }

/* ==================== dl grid (field/value pairs) ==================== */

.fields {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  background: var(--color-border);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-subtle);
  overflow: hidden;
}
@media (min-width: 620px) { .fields { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 980px) { .fields-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 820px) { .fields-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.field { background: var(--color-surface-bg-raised); padding: 10px 13px; min-width: 0; }
.field dt {
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-tertiary);
}
.field dd {
  margin: 3px 0 0;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-small);
  font-variant-numeric: tabular-nums;
  overflow-wrap: break-word;
}

/* ==================== matrix ==================== */

.matrix-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

.matrix {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--type-scale-small);
  min-width: 640px;
}
.matrix th, .matrix td {
  padding: 9px 11px;
  text-align: left;
  border-bottom: 1px solid var(--color-border);
  white-space: nowrap;
}
.matrix thead th {
  position: sticky;
  top: 0;
  background: var(--color-surface-bg-subtle);
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-tertiary);
  font-weight: var(--type-weight-medium);
  border-bottom: 1px solid var(--color-border-strong);
}
.matrix tbody th { font-weight: var(--type-weight-medium); background: var(--color-surface-bg-raised); }
.matrix tbody tr:hover td { background: var(--color-surface-bg-subtle); }

/* Prose variant. `.matrix` is built for short numeric grids: it carries a
   640px floor and nowrap cells, both of which are wrong for a table whose
   last column holds a recorded sentence. In a 644px drawer that floor forced
   a 1000px table and clipped the driver text behind a horizontal scrollbar.
   This modifier drops the floor and lets the final column wrap; the dated
   columns stay nowrap so the reader can still scan the trail by date. */
.matrix-prose { min-width: 0; }
.matrix-prose td:last-child,
.matrix-prose th:last-child { white-space: normal; line-height: 1.45; }
.matrix-prose td:last-child { min-width: 18ch; }

/* Narrow viewports. A three-column trail inside a full-width drawer leaves the
   driver about 150px, which renders a recorded sentence as a ribbon and still
   overflows by the scrollbar width. Below 560px the row stacks instead: date
   and level read as one line, the driver sits beneath it at full width. The
   header is dropped because each value is self-describing once stacked, and
   the min-width floor is released so nothing can force a horizontal scroll. */
@media (max-width: 560px) {
  .matrix-prose thead { display: none; }
  .matrix-prose, .matrix-prose tbody, .matrix-prose tr, .matrix-prose td { display: block; width: auto; }
  .matrix-prose tr { padding: 10px 0; border-bottom: 1px solid var(--color-border); }
  .matrix-prose tr:last-child { border-bottom: 0; }
  .matrix-prose td { border-bottom: 0; padding: 0; }
  .matrix-prose td:nth-child(1), .matrix-prose td:nth-child(2) { display: inline-block; padding-right: 8px; }
  .matrix-prose td:last-child { min-width: 0; display: block; margin-top: 3px; color: var(--color-text-secondary); }
  /* Stacking drops the header row, which is safe only while every value is
     self-describing -- true of the three-column trail this block was written
     for (a date, a level chip, a sentence), false the moment a fourth column
     arrives. Measured at 390px on 2026-09-14: the domain table's prose column
     rendered "source not recorded" as a bare orphan line under the sentence,
     with nothing to say which column it belonged to. A cell that carries
     `data-th` restates its own header when stacked; cells that do not carry it
     (chips, dates) stay unlabelled, so the rule cannot add noise to the case it
     was already handling correctly. */
  .matrix-prose td[data-th]::before {
    content: attr(data-th);
    display: block;
    font-family: var(--type-family-mono);
    font-size: var(--type-scale-eyebrow);
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--color-text-tertiary);
    margin-bottom: 2px;
  }
}

.cell {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 46px;
  padding: 2px 7px;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-caption);
  font-variant-numeric: tabular-nums;
  color: var(--sev-fg);
  background: var(--sev-bg);
  border-radius: var(--radius-subtle);
}

/* ==================== sparkline ==================== */

.sparkline { display: block; overflow: visible; }
.sparkline path { vector-effect: non-scaling-stroke; }

/* ==================== judgment card ==================== */

.judgment { border: 1px solid var(--color-border); border-radius: var(--radius-subtle); background: var(--color-surface-bg-raised); }
.judgment + .judgment { margin-top: var(--space-compact); }
.judgment-head { display: flex; gap: var(--space-comfortable); align-items: flex-start; padding: var(--space-comfortable); }
.judgment-id {
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  color: var(--color-text-tertiary);
  padding-top: 3px;
  flex-shrink: 0;
}
.judgment-text { font-size: var(--type-scale-body-lg); line-height: var(--type-leading-normal); }

/* ==================== delta arrow ==================== */

.delta-arrow { font-family: var(--type-family-mono); font-size: var(--type-scale-caption); color: var(--sev-fg, var(--color-text-tertiary)); white-space: nowrap; }

/* ==================== slide-over ==================== */

.slide-over {
  position: fixed;
  inset: 0 0 0 auto;
  width: min(480px, 100%);
  max-width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  border-left: 1px solid var(--color-border);
  background: var(--color-surface-bg-raised);
  box-shadow: var(--elevation-floating);
  overflow-y: auto;
}
.slide-over::backdrop { background: rgba(22, 38, 59, 0.34); }
.slide-over-head {
  position: sticky; top: 0;
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-compact);
  padding: var(--space-comfortable);
  background: var(--color-surface-bg-raised);
  border-bottom: 1px solid var(--color-border);
}
.slide-over-body { padding: var(--space-comfortable); }
.icon-btn {
  background: none; border: 1px solid var(--color-border);
  border-radius: var(--radius-subtle); padding: 4px 9px;
  font-family: var(--type-family-mono); font-size: var(--type-scale-caption);
  color: var(--color-text-secondary);
}

/* ==================== buttons ==================== */

.pub-cta--ghost {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 9px 16px;
  font-size: var(--type-scale-small);
  font-weight: var(--type-weight-medium);
  border-radius: var(--radius-subtle);
  border: 1px solid var(--color-border-strong);
  background: var(--color-surface-bg-raised);
  color: var(--color-text-primary);
  transition: all var(--motion-duration-subtle) var(--motion-easing-standard);
}
.pub-cta--ghost:hover { text-decoration: none; background: var(--color-surface-bg-subtle); }
.pub-cta {
  background: var(--color-surface-bg-inverse);
  border-color: var(--color-surface-bg-inverse);
  color: var(--color-text-inverse);
}
.pub-cta:hover { background: color-mix(in srgb, var(--color-surface-bg-inverse) 88%, var(--palette-white)); }
.btn-ghost { border-color: transparent; background: none; padding-inline: 4px; }
.btn-ghost:hover { background: none; text-decoration: underline; }

/* ==================== gap / empty state ==================== */

.gap-note {
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-subtle);
  background: var(--color-surface-bg-subtle);
  padding: var(--space-comfortable);
}

/* ==================== depth visibility ==================== */
/* T0 always visible. Higher tiers reveal as depth increases. */
/* Hide by matching only what should be hidden. Revealing by re-declaring
   `display` would clobber whatever display the component itself needs
   (flex, grid), so a visible tier carries no display declaration at all. */
body:not([data-depth]) [data-tier="t1"],
body:not([data-depth]) [data-tier="t2"],
body:not([data-depth]) [data-tier="t3"],
body[data-depth="t0"] [data-tier="t1"],
body[data-depth="t0"] [data-tier="t2"],
body[data-depth="t0"] [data-tier="t3"],
body[data-depth="t1"] [data-tier="t2"],
body[data-depth="t1"] [data-tier="t3"],
body[data-depth="t2"] [data-tier="t3"] { display: none; }

/* ==================== footer ==================== */

.pub-foot {
  border-top: 1px solid var(--color-border);
  background: var(--color-surface-bg-subtle);
  padding-block: var(--space-gutter);
  margin-top: var(--space-section);
}
.pub-foot__cols { display: grid; gap: var(--space-airy); grid-template-columns: 1fr; }
@media (min-width: 760px) { .pub-foot__cols { grid-template-columns: 1.5fr 1fr 1fr 1fr; } }
.pub-foot a { color: var(--color-text-secondary); font-size: var(--type-scale-small); display: block; padding: 3px 0; }

.pub-trust {
  margin-top: var(--space-airy);
  padding-top: var(--space-comfortable);
  border-top: 1px solid var(--color-border);
  font-size: var(--type-scale-caption);
  color: var(--color-text-tertiary);
  line-height: var(--type-leading-normal);
  max-width: 76ch;
}

/* ==========================================================================
   ADDENDUM §10 components
   Evidence drawer, source-tier tags, thesis cards, evidence rails, episodes.
   ========================================================================== */

/* ---------- source-tier + classification tags ---------- */
.tier-tag {
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  letter-spacing: 0.04em;
  padding: 2px 6px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-subtle);
  color: var(--color-text-tertiary);
  background: var(--color-surface-bg-subtle);
  white-space: nowrap;
}
.tier-tag.tier-T1, .tier-tag.tier-T2 { color: var(--color-text-secondary); border-color: var(--color-border-strong); }
.tier-tag.tier-T5, .tier-tag.tier-breach {
  color: var(--color-accent-danger);
  border-color: color-mix(in srgb, var(--color-accent-danger) 45%, var(--color-border));
  background: color-mix(in srgb, var(--color-accent-danger) 7%, var(--color-surface-bg-raised));
}
.tier-tag.tier-SA, .tier-tag.tier-CC, .tier-tag.tier-TS {
  color: var(--color-accent-primary);
  border-color: color-mix(in srgb, var(--color-accent-primary) 40%, var(--color-border));
}

.chip-evidence { cursor: pointer; }
.chip-evidence::before {
  content: "";
  width: 5px; height: 5px; border-radius: 999px;
  background: var(--color-accent-primary);
  display: inline-block; margin-right: 5px;
}
.chip-sm { padding: 2px 7px; font-size: var(--type-scale-eyebrow); }

/* ---------- clickable rows ---------- */
.matrix-clickable tbody tr { cursor: pointer; }
.matrix-clickable tbody tr:hover td,
.matrix-clickable tbody tr:hover th { background: var(--color-surface-bg-subtle); }
.matrix-clickable tbody tr:focus-visible { outline: 2px solid var(--color-accent-primary); outline-offset: -2px; }

/* ---------- evidence drawer ---------- */
.slide-over-wide { width: min(660px, 100%); }
.ev-head-main { display: flex; align-items: flex-start; gap: 10px; min-width: 0; }
.ev-filters {
  position: sticky; top: 0; z-index: 1;
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  padding: 10px var(--space-comfortable);
  border-bottom: 1px solid var(--color-border);
  background: var(--color-surface-bg-subtle);
}
.ev-filters .btn-ghost { margin-left: auto; }
.ev-card {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-subtle);
  background: var(--color-surface-bg);
  padding: var(--space-comfortable);
}
.ev-card + .ev-card { margin-top: var(--space-compact); }
.ev-card-top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ev-pub { font-size: var(--type-scale-small); font-weight: var(--type-weight-medium); }
.ev-url-state {
  margin-left: auto;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  color: var(--color-text-tertiary);
  white-space: nowrap;
}
.ev-url-state[data-state="resolved"] { color: var(--color-accent-success); }
.ev-url-state[data-state="unreachable"] { color: var(--color-accent-warning); }
.ev-title { font-size: var(--type-scale-body); margin: 8px 0 2px; }
.ev-series { font-size: var(--type-scale-caption); color: var(--color-text-tertiary); margin: 0 0 7px; }
.ev-link {
  display: block;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-caption);
  word-break: break-all;
  color: var(--color-accent-primary);
}
.ev-fields { margin-top: var(--space-compact); }
.ev-note { margin-top: var(--space-compact); }
.ev-copy { margin-top: 9px; }
.ev-foot {
  position: sticky; bottom: 0;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px var(--space-comfortable);
  border-top: 1px solid var(--color-border);
  background: var(--color-surface-bg-raised);
}
.ev-foot .pub-cta--ghost { font-size: var(--type-scale-caption); max-width: 42%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------- thesis cards ---------- */
.thesis {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-subtle);
  background: var(--color-surface-bg-raised);
  padding: var(--space-airy);
}
.thesis + .thesis { margin-top: var(--space-airy); }
.thesis-head { display: flex; gap: var(--space-comfortable); justify-content: space-between; align-items: flex-start; flex-wrap: wrap; }
.lede-sm { font-family: var(--type-family-display); font-size: var(--type-scale-body-lg); line-height: var(--type-leading-normal); margin-top: var(--space-compact); max-width: 62ch; }
.thesis-rails { display: grid; gap: var(--space-comfortable); grid-template-columns: 1fr; margin-top: var(--space-comfortable); }
@media (min-width: 900px) { .thesis-rails { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.thesis-foot {
  display: flex; gap: var(--space-comfortable); flex-wrap: wrap; align-items: center;
  margin-top: var(--space-comfortable); padding-top: var(--space-compact);
  border-top: 1px solid var(--color-border);
}
.thesis-foot .link, .link { color: var(--color-accent-primary); }

/* ---------- evidence rail (C1: rendered by reference, never authored) ---------- */
.rail { list-style: none; margin: 8px 0 0; padding: 0; }
.rail-item {
  display: grid; gap: 1px 10px; align-items: baseline;
  grid-template-columns: minmax(0, 1fr) auto auto;
  grid-template-areas: "name val chip" "meta val chip";
  padding: 7px 10px;
  border-left: 2px solid var(--sev-fg, var(--color-border));
  background: var(--color-surface-bg-subtle);
  min-width: 0;
}
.rail-item + .rail-item { margin-top: 4px; }
.rail-link { grid-area: name; font-size: var(--type-scale-small); font-weight: var(--type-weight-medium); min-width: 0; }
.rail-val {
  grid-area: val; align-self: center;
  font-family: var(--type-family-mono); font-size: var(--type-scale-small);
  color: var(--sev-fg, var(--color-text-primary)); text-align: right; white-space: nowrap;
}
.rail-meta { grid-area: meta; display: flex; gap: 8px; flex-wrap: wrap; align-items: baseline; min-width: 0; }
.rail-state { font-family: var(--type-family-mono); font-size: var(--type-scale-eyebrow); color: var(--sev-fg, var(--color-text-tertiary)); }
.rail-dist, .rail-asof { font-size: var(--type-scale-eyebrow); color: var(--color-text-tertiary); }
.rail-item .chip { grid-area: chip; align-self: center; }

/* Per-zone provenance line emitted by _dashboard_ssr_common.as_of_footer (AI-4).
   Was `asym-zone__asof`, a class from another consumer's design system that no
   investor stylesheet defined, so the line every SSR zone appends rendered at
   body size instead of as an eyebrow. Legacy selector kept as an alias because
   five frozen archive pages under site/brief/ still carry the old name and are
   not rebaked. Matches .rail-asof at line 808. */
.pub-asof, .asym-zone__asof { font-size: var(--type-scale-eyebrow); color: var(--color-text-tertiary); }
.pub-asof time, .asym-zone__asof time { font-family: var(--type-family-mono); }

/* ---------- SSR zone tables (tripwire board, freshness panel) ---------- */
/* The two monitor SSR zones emit a wrapper plus a table. Both carried
   `asym-zone` / `asym-table`, another consumer's design-system dialect that no
   investor stylesheet defined -- the same failure as `asym-zone__asof` at line
   812, and the estate had no table styling of any kind, so both tables would
   have rendered as bare browser-default tables.

   Why this was invisible until now: `indicator_panel` is absent from the served
   record, so build_panel_model returns no indicators and both zones emit only
   an empty state. The classes therefore never reached a page and
   check_class_backing_css.py passed. The arrays populate at the 2026-08-30
   wave (_posture_derive._history_series, commons PR #652), at which point the
   tables render for the first time. Proven pre-wave by rendering both builders
   against a synthetic 12-row panel: the gate went FATAL on exactly these two
   classes.

   The wrapper class is dropped rather than renamed -- it carried no styling
   intent, only the `data-mount` hook, and a `pub-zone` would have been a new
   chrome class outside post_pass.PUB_CONTRACT. The table takes `pub-table`,
   already in that contract. The legacy `asym-table` selector is kept as an
   alias because five frozen archive pages under site/brief/ still carry the old
   name and are not rebaked. */
.pub-table, .asym-table {
  width: 100%; border-collapse: collapse;
  margin-block: var(--space-compact);
  font-size: var(--type-scale-small);
}
.pub-table thead th, .asym-table thead th {
  text-align: left; padding: 6px 8px;
  font-size: var(--type-scale-eyebrow); font-weight: var(--type-weight-medium);
  color: var(--color-text-tertiary); text-transform: uppercase; letter-spacing: 0.04em;
  border-bottom: 1px solid var(--color-border);
}
.pub-table tbody td, .asym-table tbody td {
  padding: 7px 8px; vertical-align: baseline;
  border-bottom: 1px solid var(--color-border);
}
.pub-table tbody tr:last-child td, .asym-table tbody tr:last-child td { border-bottom: 0; }
/* Readings are figures, not prose: mono, right-aligned, never wrapped mid-value.
   The first column is the indicator name and stays prose-aligned. */
.pub-table td:not(:first-child), .asym-table td:not(:first-child),
.pub-table th:not(:first-child), .asym-table th:not(:first-child) {
  font-family: var(--type-family-mono); text-align: right; white-space: nowrap;
}
/* CONTAIN THE WIDE NUMERIC TABLES. Measured on the live monitor page at a 390px
   viewport on 2026-09-14: the document overflowed its viewport by 516px, and the
   offender was .pub-table -- the freshness board runs to 17 columns, all of them
   `white-space: nowrap` figures by design. The page was not merely cramped, it
   was horizontally scrollable as a whole, which drags the header, the prose and
   every other section sideways with it. This predates the evidence drawer; the
   drawer work is what put a 390px viewport under a microscope.

   `display: block` + `overflow-x: auto` makes the TABLE its own scroll container
   without a wrapper element, so the three builders that emit these tables
   (monitor_ssr_board_data, monitor_ssr_freshness_data, posture_roster_data) need
   no markup change and cannot drift apart from each other. Unconditional rather
   than inside a breakpoint: a table that fits shows no scrollbar, so there is
   nothing to gate, and a breakpoint would only re-create the bug on the next
   viewport nobody tested. The nowrap on figure columns is kept -- a reading that
   wraps mid-value is worse than one you scroll to. */
.pub-table, .asym-table { display: block; overflow-x: auto; max-width: 100%;
  -webkit-overflow-scrolling: touch; }

@media (max-width: 520px) {
  .pub-table, .asym-table { font-size: var(--type-scale-eyebrow); }
  .pub-table thead th, .asym-table thead th,
  .pub-table tbody td, .asym-table tbody td { padding: 5px 5px; }
}
.rail-falsify .rail-item { border-left-style: dashed; }

/* ---------- validation episodes ---------- */
.episode {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-subtle);
  background: var(--color-surface-bg-raised);
  padding: var(--space-airy);
}
.episode + .episode { margin-top: var(--space-comfortable); }

/* ---------- generic panels / tables used by the new surfaces ---------- */
.panel-critical {
  border-left: 2px solid var(--color-accent-danger);
  background: color-mix(in srgb, var(--color-accent-danger) 5%, var(--color-surface-bg-raised));
  padding: var(--space-comfortable);
}
.badge-quiet { color: var(--color-text-tertiary); white-space: normal; text-transform: none; letter-spacing: 0.01em; }
.list-tight { margin: 6px 0 0; padding-left: 1.1em; }
.list-tight li + li { margin-top: 4px; }
/* Same containment as .pub-table above, for the same measured reason. Probed on
   the live monitor page at 390px on 2026-09-14 by hiding one table at a time and
   re-reading documentElement.scrollWidth: with .pub-table contained the document
   still overflowed by 189px, and hiding this one -- the five-column segment table
   (Segment / Stress / Direction / Contagion / Reading) -- dropped it by 114px.
   Its columns are prose, so it has a content-driven minimum width no breakpoint
   can talk it out of. Four builders emit this class (credit_stress_data,
   dashboard_ssr_tailrisk_data, debt_dynamics_data, tariff_tracker_data), so the
   cure belongs on the class, not on any one of them. */
.table { width: 100%; border-collapse: collapse; font-size: var(--type-scale-small);
  display: block; overflow-x: auto; max-width: 100%; -webkit-overflow-scrolling: touch; }
.table th, .table td { text-align: left; padding: 8px 11px; border-bottom: 1px solid var(--color-border); vertical-align: top; }
.table thead th { font-family: var(--type-family-mono); font-size: var(--type-scale-eyebrow); letter-spacing: 0.05em; text-transform: uppercase; color: var(--color-text-tertiary); }
.k { font-family: var(--type-family-mono); font-size: var(--type-scale-eyebrow); letter-spacing: 0.05em; text-transform: uppercase; color: var(--color-text-tertiary); margin-right: 6px; }
.h6 { font-family: var(--type-family-display); font-size: var(--type-scale-body); font-weight: var(--type-weight-medium); margin: 0 0 5px; }

/* ---------- posture-in-time chart ---------- */
.chart-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.chart-scroll svg { min-width: 700px; max-width: 100%; height: auto; display: block; }
.lg-swatch {
  display: inline-block; width: 10px; height: 10px; border-radius: 2px;
  margin-right: 5px; vertical-align: -1px;
}
.lg-hollow { background: none !important; border: 1px dashed currentColor; }
.lg-hatch {
  /* Brass, not amber: a carried reading is not a fault, and amber is this
     site's warning colour. Matches the chart's own hatch pattern. */
  background-color: var(--color-accent-primary-soft);
  background-image: repeating-linear-gradient(45deg,
    var(--color-accent-primary) 0 2px, transparent 2px 5px);
}
.chart-legend {
  list-style: none; margin: var(--space-compact) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 6px 18px;
  font-size: var(--type-scale-caption); color: var(--color-text-secondary);
}
.chart-legend li { display: flex; align-items: center; min-width: 0; }

.badge-wrap { white-space: normal; }

.chart-hint { margin-top: 6px; color: var(--color-text-tertiary); }
@media (min-width: 760px) { .chart-hint { display: none; } }

/* ==================== threshold band gauge (ported from the 6-year monitor) ==================== */
.tgauge { position: relative; height: 26px; margin: 2px 0 6px; }
.tgauge-track {
  position: absolute; left: 0; right: 0; top: 9px; height: 8px;
  border-radius: var(--radius-full); overflow: hidden;
  background: var(--color-accent-success-soft);
}
.tgauge-warn, .tgauge-danger { position: absolute; top: 0; bottom: 0; }
.tgauge-warn { background: var(--color-accent-warning-soft); }
.tgauge-danger { background: var(--color-accent-danger-soft); }
.tgauge-tick {
  position: absolute; top: 4px; width: 1px; height: 18px;
  background: var(--color-accent-warning); transform: translateX(-0.5px);
}
.tgauge-tick.is-trigger { background: var(--color-accent-danger); }
.tgauge-marker {
  position: absolute; top: 5px; width: 3px; height: 16px; border-radius: 2px;
  background: var(--color-text-primary); transform: translateX(-1.5px);
  box-shadow: 0 0 0 2px var(--color-surface-bg);
}
.tgauge-cap {
  display: flex; flex-wrap: wrap; gap: 4px 16px;
  font-family: var(--type-family-mono); font-size: var(--type-scale-caption);
  color: var(--color-text-tertiary);
}
.tgauge-cap b { color: var(--color-text-secondary); font-weight: var(--type-weight-medium); }
.tgauge-cap .cap-gap { color: var(--color-text-primary); }

/* ---- PORT FIX: 8 layout classes used by the mockup with ZERO backing CSS.
   This is the SS10.7 defect shape (an off-pattern class with no CSS behind it
   shipping a broken reader surface). Found and cured at port time. ---- */
.read-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:18px}
.mon-grid {display:grid;grid-template-columns:1fr;gap:10px}
.pm-grid  {display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px}
.fw-grid  {display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:16px}
.bs-grid  {display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:14px}
.ent-grid {display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:14px}
.v-grid   {display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:16px}
.fields-2 {display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px}
@media(max-width:720px){.read-grid,.pm-grid,.fw-grid,.bs-grid,.ent-grid,.v-grid,.fields-2{grid-template-columns:1fr}}

/* ---- pub-* chrome contract aliases (25-class shell vocabulary) ---- */
.pub-head{position:sticky;top:0;z-index:50}
.pub-foot__cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:24px}

/* ---- R35 stale banner: a rendered state, not a caption ---- */
.pub-stale{display:block;padding:10px 0;border-bottom:1px solid var(--line,#2a2a2a);
  font-size:13px;line-height:1.5}
.pub-stale[data-fresh="stale"]{background:#3a2a12;color:#f0c674}
.pub-stale[data-fresh="fresh"]{background:#16241a;color:#8fd19e}
.pub-stale[data-fresh="unknown"]{background:#2a2a2a;color:#bbb}
.pub-stale .pub-wrap{display:flex;gap:10px;align-items:baseline;flex-wrap:wrap}
.pub-stale b{font-weight:600}

/* ---- PORT FIX 2: two further no-backing-CSS classes, found by the §10.7 gate
   in verify_port.py rather than by eye. ---- */

/* .rail-support is the solid counterpart to .rail-falsify (which IS styled,
   `border-left-style: dashed`). The pairing was implied by the markup and
   never declared, so a supporting rail and a falsifying rail rendered
   identically -- the one visual distinction the evidence rail exists to make.
   Declared explicitly rather than left to the default. */
.rail-support .rail-item { border-left-style: solid; }

/* NO .sev-* addition here, deliberately. The §10.7 gate flagged a bare `sev-`
   and my first cure invented a `.sev-excluded` colour for it. Reading the
   renderer first (mockup assets/app.js:393 `sev: ""` for tier-excluded, and
   :405 `sevOf` returning "" for a mild negative correlation) shows the empty
   severity is the AUTHOR'S CHOICE -- those cells are meant to carry no severity
   colour at all. The defect is only that a deliberate "no severity" was
   expressed as an invalid class name. Cure is in post_pass.py: drop the
   modifier, keep the base .sev. Giving it a colour would have invented a
   distinction the design never made.
   W3 BUILDER REQUIREMENT: builders emit `class="sev"` with no modifier for an
   absent severity, never a trailing `sev-`. */

/* Declared extension: a footer entry for a surface that is not built yet.
   Rendered as text rather than a link so nothing invites a dead click, but
   still legible at the same weight as its siblings. */
.pub-foot__planned {
  display: inline-block;
  color: var(--color-text-muted, #6b7280);
  cursor: default;
}


/* ==================== scenario weights + asset outlook (SSR regions) ====================
   Added 2026-08-26 (session arti-3337026d) with the SSR binding of INVESTOR_STRESS_REGIME
   and INVESTOR_ASSET_OUTLOOK on brief.html. Both regions previously rendered via JS
   variables and had ZERO backing CSS, as did .evidence-trigger and .asym-state shipped
   in PR #56 — the §10.7 backing-CSS gate (tools/verify_port.py) was dead and unwired,
   so nothing caught it. Layout lives here, never in an inline <style> block.
   Bar width arrives as the custom property --sw-w on the element (a datum, not a rule). */

/* ---------- shared: builder empty state ---------- */

.asym-state {
  padding: var(--space-comfortable);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-subtle);
  background: var(--color-surface-bg-subtle);
  color: var(--color-text-tertiary);
  font-size: var(--type-scale-small);
  line-height: var(--type-leading-normal);
}
.asym-state--empty { font-style: italic; }

/* ---------- shared: evidence trigger (un-hidden by assets/evidence.js) ---------- */

.evidence-trigger {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-secondary);
  background: var(--color-surface-bg-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  cursor: pointer;
  transition: border-color var(--motion-duration-subtle) var(--motion-easing-standard),
              color var(--motion-duration-subtle) var(--motion-easing-standard);
}
.evidence-trigger:hover { border-color: var(--color-border-strong); color: var(--color-text-primary); }
.evidence-trigger:focus-visible { outline: 2px solid var(--color-accent-primary); outline-offset: 2px; }

/* ---------- scenario weights (sw-*) ---------- */

.sw-regime {
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-caption);
  color: var(--color-text-secondary);
  margin: 0 0 var(--space-comfortable);
}
.sw-regime strong { color: var(--color-text-primary); font-weight: var(--type-weight-semibold); }

.sw-list { list-style: none; margin: 0 0 var(--space-comfortable); padding: 0; }
.sw-row {
  display: grid;
  grid-template-columns: minmax(9rem, 14rem) 1fr auto;
  align-items: center;
  gap: var(--space-compact);
  padding: 5px 0;
}
.sw-row + .sw-row { border-top: 1px solid var(--color-border); }
.sw-row__label { font-size: var(--type-scale-small); color: var(--color-text-primary); }
.sw-row__bar {
  position: relative;
  display: block;
  height: 6px;
  min-width: 40px;
  background: var(--color-surface-bg-sunken);
  border-radius: var(--radius-full);
  overflow: hidden;
}
.sw-row__fill {
  display: block;
  height: 100%;
  width: var(--sw-w, 0%);
  background: var(--color-accent-neutral-soft, var(--palette-brass));
  border-radius: var(--radius-full);
}
.sw-row:first-child .sw-row__fill { background: var(--palette-brass); }

/* ── chart primitives (R379) ───────────────────────────────────────────────
   Backing CSS for stacked_share_svg / diverging_bar_svg / band_position_svg in
   tools/ds1_builders/_dashboard_ssr_common.py. Every class a chart primitive
   emits is declared HERE and nowhere else: the radar these replaced shipped
   four classes with no backing rule in any stylesheet the page linked, so it
   rendered unstyled on the live reader for weeks. Colour is taken from the
   semantic token layer in assets/tokens.css, never from a literal.

   A first-child override exists above for `.sw-row__fill`; the diverging bar
   sets `background` inline from the sign, which wins over it by specificity of
   the style attribute. That is deliberate — on a signed chart the first row is
   not privileged, it is merely the most stressed. */
.share-bar { display: block; border-radius: var(--radius-full); overflow: hidden; }

/* The drawn zero axis. Absolutely positioned inside `.sw-row__bar`, which is
   already `position: relative; overflow: hidden`, so the line cannot escape
   the track. */
.sw-row__zero {
  position: absolute; top: 0; bottom: 0; width: 1px;
  background: var(--color-text-tertiary);
  transform: translateX(-0.5px);
}

/* Position marks on a band track: `--now` is the current reading, the plain
   form is a prior reading. Different weights, not different hues, so the pair
   stays legible in greyscale and in print. */
.sw-row__mark {
  position: absolute; top: 0; bottom: 0; width: 2px;
  background: var(--color-text-tertiary);
  transform: translateX(-1px);
}
.sw-row__mark--now {
  width: 3px;
  background: var(--color-text-primary);
}

/* A band track carries no fill -- only marks -- so it needs more presence than
   the filled bars do, and the two marks must be told apart at a glance. On
   review of the rendered page the pair was indistinguishable: a 2px tertiary
   tick beside a 3px primary one, both inside a 6px pale track, read as a
   smudge. Three changes, all shape rather than hue, so the distinction
   survives greyscale, print and colour-blind readers:
     - the track is taller and its ends are drawn, so -1 and +1 are visible
       positions rather than implied ones;
     - the CURRENT reading is a full-height bar with a head that overhangs the
       track, making it unmistakably the subject;
     - the PRIOR reading is a hollow tick inset from the track edges, reading
       as a reference point rather than a second subject. */
.bandpos {
  position: relative;
  display: block;
  height: 10px;
  background: var(--color-surface-bg-sunken);
  border-inline: 1px solid var(--color-border-strong);
  border-radius: 2px;
  overflow: visible;
}
.bandpos .sw-row__zero {
  background: var(--color-border-strong);
  width: 1px;
}
.bandpos .sw-row__mark {
  width: 2px;
  top: 2px;
  bottom: 2px;
  background: var(--color-text-tertiary);
  box-shadow: 0 0 0 1px var(--color-surface-bg-raised);
}
.bandpos .sw-row__mark--now {
  width: 3px;
  top: -3px;
  bottom: -3px;
  background: var(--color-text-primary);
  border-radius: 1px;
  box-shadow: none;
}
/* R392: a row figure takes the ROW size. It was on the headline numeral scale,
   which put a per-class reading at up to 67px -- larger than the section
   heading and far larger than the geometry that gives it meaning. The row is
   the unit of comparison here; the number labels it. */
.sw-row__pct {
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-numeral-row);
  font-weight: var(--type-weight-medium);
  color: var(--color-text-primary);
  font-variant-numeric: tabular-nums;
  min-width: 3.5em;
  text-align: right;
}

.sw-derived {
  font-size: var(--type-scale-body);
  line-height: var(--type-leading-relaxed);
  color: var(--color-text-primary);
  border-left: 2px solid var(--palette-brass);
  padding-left: var(--space-comfortable);
  margin: 0 0 var(--space-comfortable);
}

.sw-cmf { margin-top: var(--space-comfortable); padding-top: var(--space-comfortable); border-top: 1px solid var(--color-border); }
.sw-cmf__head {
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-tertiary);
  margin: 0 0 var(--space-dense);
}
.sw-warn {
  font-size: var(--type-scale-small);
  color: var(--color-text-tertiary);
  font-style: italic;
  margin: var(--space-dense) 0 0;
}

/* ---------- asset outlook (ao-*) ---------- */

.ao-list { list-style: none; margin: 0; padding: 0; }
.ao-row {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-subtle);
  background: var(--color-surface-bg-raised);
  padding: var(--space-comfortable);
}
.ao-row + .ao-row { margin-top: var(--space-compact); }
.ao-row__head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-compact); }
.ao-row__name {
  font-family: var(--type-family-display);
  font-size: var(--type-scale-body-lg);
  font-weight: var(--type-weight-semibold);
  margin: 0;
}
.ao-row__label {
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-secondary);
}
.ao-row__nums {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-compact);
  margin-top: var(--space-dense);
}
.ao-row__score {
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-numeral);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-primary);
}
.ao-row__delta, .ao-row__conv {
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-tertiary);
}
/* No earlier published edition carries this class, so there is no move to show.
   Dimmer than a real delta so an absence does not read as a measurement. */
.ao-row__delta--none { color: var(--color-text-disabled); }
.ao-row__sep { color: var(--color-text-disabled); padding: 0 2px; }
.ao-row__detail {
  font-size: var(--type-scale-small);
  line-height: var(--type-leading-normal);
  color: var(--color-text-secondary);
  margin: var(--space-dense) 0 0;
}
.ao-row__blind {
  font-size: var(--type-scale-small);
  line-height: var(--type-leading-normal);
  color: var(--color-text-secondary);
  margin: var(--space-dense) 0 0;
}

.ao-badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  margin-right: 6px;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  color: var(--color-text-secondary);
}
.ao-badge--alert { border-color: var(--color-accent-warning); color: var(--color-accent-warning); }
.ao-badge--blind { border-color: var(--color-accent-neutral-soft, var(--color-border-strong)); color: var(--color-text-tertiary); }

/* --- Declared-coverage states (asset-outlook-coverage-policy.json v1.0.0) ---
   Every row states the share of its declared indicator weight that carried a
   reading. Amber is the estate's one meaning for incomplete coverage; grey is
   withheld / non-actionable. Colour never carries the meaning alone -- the row
   also writes out "Coverage-blocked", "Indicative" or "Conviction withheld". */
.ao-row__cov {
  margin: var(--space-hairline) 0 0;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-caption);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-tertiary);
}
.ao-row__cov--full { color: var(--color-text-tertiary); }
.ao-row__cov--indicative { color: var(--color-accent-warning, var(--color-text-secondary)); }
.ao-row__cov--blocked {
  color: var(--color-text-secondary);
  font-weight: 600;
}
/* R310 -- the coverage-corrected second reading, beside the raw published sum.
   The score is a weighted sum over reporting inputs only, so a thin class reads
   more moderate than its inputs support. Both numbers are shown; a corrected
   value outside the index's own range is stated, never clipped. */
.ao-row__scale {
  margin: var(--space-hairline) 0 0;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-caption);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-tertiary);
}
.ao-row__scale--out-of-range {
  color: var(--color-text-secondary);
}
/* R311 -- reporting indicators one flag step from the top of the ladder, with
   the exact move each would make to the class score. Salvaged from R245: no
   threshold level is published on either plane, so distance is stated in flag
   steps, which are. */
.ao-row__step {
  margin: var(--space-hairline) 0 0;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-caption);
  font-variant-numeric: tabular-nums;
  color: var(--color-accent-warning, var(--color-text-secondary));
}
.ao-row__label--blocked {
  color: var(--color-text-tertiary);
  border-bottom: 1px dotted var(--color-border-strong);
}
.ao-row__score--withheld {
  color: var(--color-text-tertiary);
  font-style: normal;
  letter-spacing: 0.02em;
}
.ao-row__conv--withheld { color: var(--color-text-tertiary); }
.ao-badge--indicative {
  border-color: var(--color-accent-warning, var(--color-border-strong));
  color: var(--color-accent-warning, var(--color-text-secondary));
  margin-left: var(--space-hairline);
}
.ao-ev__row--none td { color: var(--color-text-tertiary); }
.ao-ev__none {
  font-style: italic;
  color: var(--color-text-tertiary);
}

.ao-ev { margin-top: var(--space-compact); }
.ao-ev__table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--type-scale-small);
}
.ao-ev__table th {
  text-align: left;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-tertiary);
  font-weight: var(--type-weight-medium);
  padding: 4px 8px 4px 0;
  border-bottom: 1px solid var(--color-border);
}
.ao-ev__table td { padding: 4px 8px 4px 0; border-bottom: 1px solid var(--color-border); color: var(--color-text-secondary); }
.ao-ev__table tr:last-child td { border-bottom: 0; }
.ao-ev__ind { font-family: var(--type-family-mono); color: var(--color-text-primary); }
.ao-ev__num { font-family: var(--type-family-mono); font-variant-numeric: tabular-nums; text-align: right; }

@media (max-width: 600px) {
  .sw-row { grid-template-columns: 1fr auto; }
  .sw-row__bar { grid-column: 1 / -1; order: 3; }
  .ao-ev__table { font-size: var(--type-scale-caption); }
}

/* ==================== §10.7 backing rules for hook classes ====================
   Added 2026-08-26 (session arti-3337026d) when the revived §10.7 gate
   (tools/check_class_backing_css.py) reported 14 classes with no rule in any
   stylesheet the page links. They are NOT all invisible: .arch-item and .arch-list
   are hooks layered on the already-styled .panel / .stack / .cluster utilities, so
   the archive list renders. The ones that were genuinely unstyled are the bare
   elements — .arch-item-excerpt, .arch-item-read, .pub-para — and .src-list, a
   source list that was rendering with default browser bullets. Rules below are
   deliberately light: they give each hook an intentional job rather than
   re-specifying what the base utility already provides. */

/* ---------- archive index (archive.html) ---------- */

.arch-list { /* hook: .stack supplies the rhythm; this scopes the entries */ }
.arch-item { /* hook: .panel supplies surface, border and padding */ }
.arch-item-head { justify-content: space-between; align-items: baseline; }
.arch-item-title { margin: var(--space-dense) 0 0; }
.arch-item-excerpt {
  font-size: var(--type-scale-body);
  line-height: var(--type-leading-relaxed);
  color: var(--color-text-secondary);
  margin: var(--space-dense) 0 0;
}
.arch-item-read {
  margin: var(--space-compact) 0 0;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.arch-summary { color: var(--color-text-secondary); }
.arch-republished { color: var(--color-text-tertiary); font-style: italic; }

/* ---------- published prose + source lists (brief.html and issue permalinks) ---------- */

.pub-prose { max-width: var(--layout-prose); }
.pub-para {
  font-size: var(--type-scale-body-lg);
  line-height: var(--type-leading-relaxed);
  color: var(--color-text-primary);
  margin: 0 0 var(--space-comfortable);
}
.pub-list { list-style: none; margin: 0; padding: 0; }
.src-list { margin-top: var(--space-compact); }
.src-row {
  font-size: var(--type-scale-small);
  line-height: var(--type-leading-normal);
  padding: 4px 0;
}
.src-row + .src-row { border-top: 1px solid var(--color-border); }

/* ---------- .btn base (only .btn-ghost / .btn-* modifiers were defined) ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-secondary);
  background: transparent;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-rounded);
  cursor: pointer;
  transition: border-color var(--motion-duration-subtle) var(--motion-easing-standard),
              color var(--motion-duration-subtle) var(--motion-easing-standard);
}
.btn:hover { border-color: var(--color-border-strong); color: var(--color-text-primary); }
.btn:focus-visible { outline: 2px solid var(--color-accent-primary); outline-offset: 2px; }

/* ---- reader list (workers/investor-subscribe) ------------------------------
   The subscribe panel was a dead end: a heading, a paragraph saying there was
   nothing to subscribe to, and two links away. These carry the form that
   replaced it. Kept to the page's own tokens — no new colours, no new type. */
.sub-form { margin-top: var(--space-comfortable); max-width: 34rem; }
.sub-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: stretch; }
.sub-input {
  flex: 1 1 15rem; min-width: 0; font: inherit; color: var(--color-text-primary);
  background: var(--color-surface-bg-raised); border: 1px solid var(--color-border);
  border-radius: 2px; padding: 11px 13px;
}
.sub-input:focus-visible { outline: 2px solid var(--color-accent-primary); outline-offset: 1px; }
.sub-input::placeholder { color: var(--color-text-tertiary); }
.sub-consent {
  display: flex; gap: 9px; align-items: flex-start;
  margin-top: 13px; font-size: .88rem; line-height: 1.5; color: var(--color-text-secondary);
}
.sub-consent input { margin-top: .25em; flex: 0 0 auto; accent-color: var(--color-accent-primary); }
.sub-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.sub-status { margin-top: 13px; font-size: .9rem; line-height: 1.55; }
.sub-status:empty { display: none; }
.sub-status[data-state="ok"] { color: var(--color-text-primary); }
.sub-status[data-state="held"] { color: var(--color-text-secondary); }
.sub-status[data-state="err"] { color: var(--color-text-primary); }

/* ---- "Since your last visit" strip (site/assets/js/reader-prefs.js) --------
   Injected above the freshness banner when the publication record shows issues
   published since the reader was last here. Deliberately the SOFT accent tone:
   .pub-stale above it is a warning about data age, and a returning reader
   being told what is new is not a warning. Same vertical rhythm so the two
   read as one band when both are present. ------------------------------- */
.visit-delta {
  display: block;
  padding: 10px 0;
  background: var(--palette-brass-soft, #F5EDDC);
  border-bottom: 1px solid var(--color-border, #d9d4c7);
  border-left: 3px solid var(--palette-brass, #A87524);
  font-size: 13px;
  line-height: 1.5;
  color: var(--color-text-primary, #1b1b1b);
}
.visit-delta .pub-wrap {
  display: flex;
  gap: 12px;
  align-items: baseline;
  flex-wrap: wrap;
}
.visit-delta__text { margin: 0; font-weight: 600; }
.visit-delta__link {
  color: var(--palette-brass, #A87524);
  text-decoration: underline;
  white-space: nowrap;
}
.visit-delta__close {
  margin-left: auto;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--color-text-secondary, #5a5a5a);
  text-decoration: underline;
  cursor: pointer;
}

/* ==================== Open findings register ==================== */
/* INVESTOR_OPEN_FINDINGS (brief.html). A cumulative dated register, so the
   row is a date rail plus a body rather than a card — 36 cards would read as
   36 competing claims, where this is one list carried across issues. */

.finding-head {
  display: flex;
  align-items: baseline;
  gap: var(--space-compact);
  flex-wrap: wrap;
  padding: var(--space-compact) var(--space-comfortable);
  border-bottom: 1px solid var(--color-border);
}

.finding-count {
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  font-weight: var(--type-weight-medium);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-primary);
}

.finding-span {
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  color: var(--color-text-tertiary);
  font-variant-numeric: tabular-nums;
}

.finding-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.finding {
  display: flex;
  gap: var(--space-comfortable);
  padding: var(--space-compact) var(--space-comfortable);
  border-bottom: 1px solid var(--color-border);
}

.finding:last-child { border-bottom: 0; }

.finding-date {
  flex: 0 0 auto;
  min-width: 5.9em;
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-caption);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-tertiary);
  padding-top: 2px;
}

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

.finding-headline {
  margin: 0;
  font-size: var(--type-scale-body);
  line-height: var(--type-leading-tight);
  color: var(--color-text-primary);
  text-wrap: pretty;
}

.finding-why {
  margin: 6px 0 0;
  font-size: var(--type-scale-caption);
  line-height: var(--type-leading-normal);
  color: var(--color-text-secondary);
  text-wrap: pretty;
}

.finding-meta { margin-top: 9px; gap: 6px; }

.finding-src {
  font-family: var(--type-family-mono);
  font-size: var(--type-scale-eyebrow);
  color: var(--color-text-tertiary);
}

a.finding-src { color: var(--color-accent-primary); }

/* Signal strength deliberately does NOT reuse the sev-* tokens: `high` means
   the pipeline read the finding confidently, not that the finding is dangerous.
   A monochrome weight ramp says "more certain" without asserting severity. */
.badge.strength-high { color: var(--color-text-primary); }
.badge.strength-med  { color: var(--color-text-secondary); }
.badge.strength-low  { color: var(--color-text-tertiary); }

.badge.badge-new {
  color: var(--color-accent-primary);
  background: var(--color-accent-primary-soft, var(--color-accent-neutral-soft));
}

@media (max-width: 560px) {
  .finding { flex-direction: column; gap: 4px; }
  .finding-date { min-width: 0; padding-top: 0; }
}

/* ── historical validation (INVESTOR_HISTORICAL_VALIDATION, 2026-09-12) ───────
   The record and the disclosures that qualify it are one block: the stats row
   never appears without the methodology note and disclaimer beneath it. */
.hv{display:block}
.hv-stats{display:flex;flex-wrap:wrap;gap:var(--space-gutter);
  padding:var(--space-compact) 0 var(--space-comfortable);
  border-bottom:1px solid var(--color-border)}
.hv-stat{display:flex;flex-direction:column;gap:3px;min-width:0}
.hv-stat-n{font-family:var(--type-family-mono);font-size:var(--type-scale-body);
  font-weight:var(--type-weight-medium);color:var(--color-text-primary);
  line-height:var(--type-leading-tight)}
.hv-stat-l{font-size:var(--type-scale-eyebrow);letter-spacing:.06em;
  text-transform:uppercase;color:var(--color-text-tertiary)}
.hv-gap{margin:var(--space-comfortable) 0 0}
.hv-table{margin-top:var(--space-comfortable)}
.hv-table th{white-space:nowrap}
.hv-ep{font-weight:var(--type-weight-medium);white-space:nowrap}
.hv-verdict{font-size:var(--type-scale-caption);white-space:nowrap;
  padding:2px 7px;border-radius:var(--radius-subtle);
  border:1px solid var(--color-border);color:var(--color-text-secondary)}
.hv-hit{border-color:var(--color-border-strong);color:var(--color-text-primary)}
.hv-miss{border-color:var(--color-border-strong);color:var(--color-text-primary);
  font-style:italic}
.hv-open{color:var(--color-text-tertiary)}
.hv-pending{color:var(--color-text-tertiary);font-style:italic}
.hv-note{margin-top:var(--space-comfortable)}
.hv-fp{margin-top:var(--space-airy);padding-top:var(--space-comfortable);
  border-top:1px solid var(--color-border)}
.hv-fp-head{color:var(--color-text-primary)}
.hv-fp-note{margin-top:6px;max-width:74ch}
.hv-disclaimer{margin-top:var(--space-comfortable);max-width:74ch;
  color:var(--color-text-tertiary)}

/* ── tactical alerts (INVESTOR_TACTICAL_ALERTS, 2026-09-12) ──────────────────
   State is carried by a weight-and-border ramp, not by the sev-* danger
   tokens: WARNING here means a threshold was crossed, not that the reader
   should act. */
.ta{display:block}
.ta-summary{font-size:var(--type-scale-caption);color:var(--color-text-tertiary);
  margin-bottom:var(--space-compact)}
.ta-list{list-style:none;margin:0;padding:0;display:grid;
  gap:var(--space-compact);grid-template-columns:1fr}
.ta-card{border:1px solid var(--color-border);border-radius:var(--radius-subtle);
  padding:var(--space-compact) var(--space-comfortable)}
.ta-top{display:flex;align-items:baseline;gap:var(--space-dense);flex-wrap:wrap}
.ta-name{font-size:var(--type-scale-body);font-weight:var(--type-weight-medium);
  line-height:var(--type-leading-tight);margin:0;min-width:0}
.ta-state{font-family:var(--type-family-mono);font-size:var(--type-scale-eyebrow);
  letter-spacing:.07em;padding:2px 7px;border-radius:var(--radius-subtle);
  border:1px solid var(--color-border);color:var(--color-text-tertiary);
  white-space:nowrap;flex:none}
.ta-critical,.ta-alert{border-color:var(--color-border-strong);
  color:var(--color-text-primary);font-weight:var(--type-weight-medium);
  background:var(--color-accent-neutral-soft)}
.ta-warning{border-color:var(--color-border-strong);color:var(--color-text-primary);
  font-weight:var(--type-weight-medium)}
.ta-watch{color:var(--color-text-secondary)}
.ta-clear,.ta-unknown{color:var(--color-text-tertiary);font-style:italic}
.ta-desc{margin:var(--space-dense) 0 0;font-size:var(--type-scale-caption);
  line-height:var(--type-leading-relaxed);color:var(--color-text-secondary);
  max-width:80ch}
.ta-meta{margin:var(--space-dense) 0 0;font-size:var(--type-scale-eyebrow);
  color:var(--color-text-tertiary)}
.ta-id{font-family:var(--type-family-mono)}

/* ── safe haven (INVESTOR_SAFE_HAVEN, 2026-09-12) ───────────────────────────*/
.sh{display:block}
.sh-lead{padding-bottom:var(--space-compact);
  border-bottom:1px solid var(--color-border)}
.sh-asset{font-size:1.55rem;font-weight:var(--type-weight-medium);
  line-height:var(--type-leading-tight);margin:4px 0 0}
.sh-chips{display:flex;flex-wrap:wrap;gap:var(--space-gutter);
  margin-top:var(--space-compact)}
.sh-chip{display:flex;flex-direction:column;gap:2px}
.sh-chip-l{font-size:var(--type-scale-eyebrow);letter-spacing:.06em;
  text-transform:uppercase;color:var(--color-text-tertiary)}
.sh-rationale{margin:var(--space-comfortable) 0 0;max-width:78ch;
  line-height:var(--type-leading-relaxed);color:var(--color-text-secondary)}
.sh-falsifier{margin-top:var(--space-comfortable)}
.sh-notes{display:grid;gap:var(--space-compact);grid-template-columns:1fr;
  margin-top:var(--space-comfortable)}
.sh-note{border-left:2px solid var(--color-border);
  padding-left:var(--space-compact)}
.sh-note-l{font-size:var(--type-scale-eyebrow);letter-spacing:.06em;
  text-transform:uppercase;color:var(--color-text-tertiary);margin:0 0 4px}
.sh-src{margin-top:var(--space-comfortable);color:var(--color-text-tertiary)}
@media (min-width:680px){.sh-notes{grid-template-columns:repeat(3,1fr)}}
@media (max-width:560px){
  .hv-stats{gap:var(--space-compact)}
  .ta-card{padding:var(--space-compact)}
}

/* ── dated interpretation registers (2026-09-13) ─────────────────────────────
   Three panels share one visual grammar because they share one epistemic
   status: each is a REGISTER of dated observations written by the
   interpretation leg, not a live gauge. The grammar therefore leads with the
   date and keeps the level/stance subordinate to it — the opposite emphasis to
   a current-cycle scorecard. Severity reuses the existing sev-* ramp so a
   reader who has learned it on the monitor does not learn a second one here. */

/* cross-monitor register (INVESTOR_CROSS_MONITOR_LINKAGES, posture.html).
   Card styling follows .cbt-card deliberately: it is the same shape of claim
   (a named institution, a state, a date it has held since) and readers on this
   page have already learned to read it. Interactive because each card opens
   the evidence drawer, so it carries the affordance the static cards do not. */
.cml-wrap{margin-top:var(--space-compact)}
.cml-head{margin-top:var(--space-airy)}
.cml-grid{display:grid;gap:var(--space-compact);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr))}
.cml-intro{max-width:74ch;margin-bottom:var(--space-comfortable)}
.cml-flags,.cml-standing-intro{max-width:78ch;margin:0 0 var(--space-compact)}
.cml-standing-intro{color:var(--color-text-secondary)}
.cml-foot{max-width:78ch;color:var(--color-text-tertiary)}
/* The card is not the trigger -- the button inside it is (see the builder for
   why), so the card takes no pointer affordance and no focus ring. */
.cml-card{transition:border-color var(--motion-duration-subtle) var(--motion-easing-standard)}
.cml-card:focus-within{border-color:var(--color-accent-primary)}
.cml-top{display:flex;justify-content:space-between;align-items:baseline;
  gap:var(--space-dense);flex-wrap:wrap}
.cml-name{margin:0;min-width:0;font-size:var(--type-scale-body);
  font-weight:var(--type-weight-medium);line-height:var(--type-leading-tight)}
.cml-class{flex:none;font-size:var(--type-scale-eyebrow)}
.cml-count{margin:var(--space-dense) 0 0;font-size:var(--type-scale-caption);
  color:var(--color-text-secondary)}
.cml-status{margin:var(--space-dense) 0 0;max-width:80ch;
  line-height:var(--type-leading-relaxed)}
.cml-dates{margin:4px 0 0;color:var(--color-text-tertiary)}
.cml-more{margin-top:var(--space-compact);align-self:flex-start}

/* validation episode drawer (INVESTOR_HISTORICAL_VALIDATION).
   `.cell-more` sits in a table cell next to the value it reveals, so it is
   inline-block and spaced from the label rather than block-level like the card
   variant. Named for the position, not the page: validation.html puts it in an
   Episode cell and method.html in a Now cell, and a third page will want the
   same thing. `.hv-more` is kept as an alias so a cached page mid-deploy is not
   left with an unstyled button. */
.cell-more,.hv-more{margin-left:var(--space-compact);vertical-align:baseline}
.hv-ep{white-space:nowrap}
/* Sub-heading inside a drawer body, between two stacked bodies (fields then a
   table). Not a page-level kicker: it needs top space because something always
   precedes it. */
.ev-sub{margin-top:var(--space-comfortable);margin-bottom:var(--space-compact)}
/* The drawer is narrower than the page, and this table is two columns of which
   one is numeric, so it does not need the 640px floor `.matrix` sets for wide
   numeric grids. */
.ev-ep-scores{min-width:0;width:100%}
.ev-ep-scores th[scope=row]{font-weight:var(--type-weight-regular);
  white-space:normal}

/* central bank stance trajectory (INVESTOR_CB_TRACKER) */
.cbt-head,.spt-head{margin-top:var(--space-airy)}
.cbt-intro,.jrh-intro,.mtt-intro,.spt-intro{max-width:74ch;
  margin-bottom:var(--space-comfortable)}
.cbt-grid,.jrh-grid,.spt-grid{display:grid;gap:var(--space-compact);
  grid-template-columns:1fr}
.cbt-card,.jrh-card,.spt-card{border:1px solid var(--color-border);
  border-left:3px solid var(--sev-fg,var(--color-border-strong));
  border-radius:var(--radius-subtle);
  padding:var(--space-compact) var(--space-comfortable)}
.cbt-top,.jrh-top,.spt-top{display:flex;justify-content:space-between;
  align-items:baseline;gap:var(--space-dense);flex-wrap:wrap}
.cbt-name,.jrh-name,.spt-week{margin:0;min-width:0;
  font-size:var(--type-scale-body);font-weight:var(--type-weight-medium);
  line-height:var(--type-leading-tight)}
.cbt-stance,.jrh-level{font-family:var(--type-family-mono);
  font-size:var(--type-scale-caption);white-space:nowrap;flex:none}
.cbt-run,.jrh-since{margin:var(--space-dense) 0 0;
  font-size:var(--type-scale-caption);color:var(--color-text-secondary)}
.cbt-prev,.jrh-change{margin:4px 0 0;font-size:var(--type-scale-eyebrow);
  color:var(--color-text-tertiary)}
.cbt-signal,.jrh-driver{margin:var(--space-dense) 0 0;max-width:80ch;
  font-size:var(--type-scale-caption);
  line-height:var(--type-leading-relaxed);color:var(--color-text-secondary)}
.cbt-score,.jrh-score{margin-top:var(--space-dense)}
.cbt-meta,.jrh-meta{margin:var(--space-dense) 0 0;
  font-size:var(--type-scale-eyebrow);color:var(--color-text-tertiary)}
.cbt-foot,.jrh-foot,.spt-foot{margin-top:var(--space-compact);
  font-size:var(--type-scale-eyebrow);color:var(--color-text-tertiary)}
/* The lag notice is the load-bearing sentence on a stale register: it is set at
   reading weight, not shrunk to a footnote. */
/* No-JS fallback list for the macro-health indicator domains. Same role as
   .jrh-trail on coverage.html: without JS the evidence drawer never opens, so the
   dated observations print inline beneath the domain prose. */
.mh-obs{margin:var(--space-compact) 0 0;padding-left:1.1em;list-style:disc;color:var(--color-text-secondary);line-height:1.5}
.mh-obs>li+li{margin-top:3px}
.jrh-trail{margin:var(--space-compact) 0 0;padding-left:1.1em;list-style:disc;color:var(--color-text-secondary);line-height:1.5}.jrh-trail>li+li{margin-top:2px}
.cbt-lag,.jrh-lag,.spt-lag{margin-top:var(--space-compact);max-width:74ch;
  font-size:var(--type-scale-caption);color:var(--color-text-secondary);
  border-left:2px solid var(--color-border-strong);
  padding-left:var(--space-compact)}

/* scenario assessment register (INVESTOR_SCENARIO_TRAJECTORY).
   No bar, anywhere, by design: the branches assessed do not always account for the
   whole, so length would encode a share of a set that was never established. The
   percentages carry the weight instead, and are set at data weight to say so. */
.spt-cover{font-family:var(--type-family-mono);
  font-size:var(--type-scale-eyebrow);white-space:nowrap;flex:none;
  color:var(--color-text-tertiary)}
.spt-rows{list-style:none;margin:var(--space-compact) 0 0;padding:0;
  display:grid;gap:2px}
.spt-row{display:flex;justify-content:space-between;align-items:baseline;
  gap:var(--space-compact);padding-block:5px;
  border-bottom:1px solid var(--color-border)}
.spt-rows>.spt-row:last-child{border-bottom:0}
.spt-label{font-size:var(--type-scale-caption);color:var(--color-text-secondary)}
.spt-val{font-size:var(--type-scale-caption);
  font-weight:var(--type-weight-medium);color:var(--color-text-primary);
  white-space:nowrap}
/* An unassessed branch is not a small number: it is the absence of a judgement, so it
   is set as prose at tertiary weight and never as a figure. */
.spt-val--none{font-family:var(--type-family-sans);
  font-weight:var(--type-weight-regular);color:var(--color-text-tertiary);
  font-style:italic}
.spt-val--zero{color:var(--color-text-secondary)}
.spt-row--none .spt-label{color:var(--color-text-tertiary)}
.spt-note{margin:var(--space-dense) 0 0;max-width:76ch;
  font-size:var(--type-scale-caption);color:var(--color-text-secondary)}
.spt-basis{margin:var(--space-dense) 0 0;max-width:80ch;
  font-size:var(--type-scale-caption);
  line-height:var(--type-leading-relaxed);color:var(--color-text-secondary)}
.spt-cover-note{margin-top:var(--space-dense);max-width:76ch;
  font-size:var(--type-scale-caption);color:var(--color-text-secondary)}
.spt-prov{margin-top:var(--space-compact);max-width:76ch;
  font-size:var(--type-scale-eyebrow);color:var(--color-text-tertiary)}
.jrh-code{font-family:var(--type-family-mono);
  font-size:var(--type-scale-eyebrow);color:var(--color-text-tertiary);
  margin-left:var(--space-dense)}

/* market-divergence register (INVESTOR_MATT) */
.mtt-summary{font-size:var(--type-scale-caption);
  color:var(--color-text-tertiary);margin-bottom:var(--space-dense)}
.mtt-note{max-width:76ch;margin:0 0 var(--space-comfortable);
  font-size:var(--type-scale-caption);color:var(--color-text-secondary)}
.mtt-grid{display:grid;gap:var(--space-compact);grid-template-columns:1fr}
.mtt-card{border:1px solid var(--color-border);
  border-radius:var(--radius-subtle);
  padding:var(--space-compact) var(--space-comfortable)}
.mtt-theme{margin:0;font-size:var(--type-scale-body);
  font-weight:var(--type-weight-medium);line-height:var(--type-leading-tight)}
.mtt-chips{display:flex;flex-wrap:wrap;gap:var(--space-dense);
  margin-top:var(--space-dense)}
.mtt-new{border-color:var(--color-border-strong);
  color:var(--color-text-primary);font-weight:var(--type-weight-medium)}
.mtt-dir,.mtt-score,.mtt-conf{color:var(--color-text-tertiary)}
.mtt-view{margin:var(--space-dense) 0 0;max-width:80ch;
  font-size:var(--type-scale-caption);
  line-height:var(--type-leading-relaxed);color:var(--color-text-secondary)}
.mtt-view-label{font-size:var(--type-scale-eyebrow);letter-spacing:.06em;
  text-transform:uppercase;color:var(--color-text-tertiary);
  margin-right:var(--space-dense)}
.mtt-meta{margin:var(--space-dense) 0 0;
  font-size:var(--type-scale-eyebrow);color:var(--color-text-tertiary)}
/* R389: a generic absence disclosure. An absence panel owes the reader two
   things -- that the figure is not there, and why -- but it owes them at
   different moments. The monitor rail was spending eleven lines of its most
   valuable position justifying two absences, which is the reader complaint
   ("spends too much effort justifying itself without explaining things") in
   one screenful. So the state stays inline as one line and the reasoning goes
   one click away.

   Native <details>, not the .disclosure/.disclosure-panel pair: that pair sets
   display:none in CSS and needs assets/disclosure.js to reveal it, and
   monitor.html does not load that file. A server-rendered .disclosure-panel on
   a page without the toggle is permanently invisible -- the defect recorded at
   the head of assets/disclosure.js, where every source chip on brief.html was
   present in the markup and unreachable by any reader for weeks. <details>
   needs no script, so it cannot fail that way. matt_data.py already uses it.
   Kept visually identical to .mtt-more so the two read as one affordance. */
.why-more{margin-top:var(--space-compact)}
.why-more>summary{cursor:pointer;font-size:var(--type-scale-caption);
  color:var(--color-text-secondary)}
.why-more>summary:focus-visible{outline:2px solid var(--color-accent-primary);
  outline-offset:2px;border-radius:2px}
.why-more>.caption{margin-top:var(--space-compact)}

/* Non-consensus positions, below the divergence register on read.html. Set off
   by a rule rather than by a card border: these are adjacent third-party context
   and a card would give them the same visual weight as the monitor's own
   register entries above, which would misstate whose reading they are.
   `.evidence-trigger` inside a list row needs its own alignment -- the default
   is a block-level button, which on a one-line row pushes the trigger onto a
   line of its own and doubles the height of every row. */
.mtt-contra{margin-top:var(--space-comfortable);
  padding-top:var(--space-compact);border-top:1px solid var(--color-border)}
.mtt-contra .caption{max-width:76ch}
.mtt-contra-list{margin-top:var(--space-compact)}
.mtt-contra-list>li{margin-bottom:var(--space-compact);max-width:80ch;
  font-size:var(--type-scale-caption);
  line-height:var(--type-leading-relaxed);color:var(--color-text-secondary)}
.mtt-contra-list .evidence-trigger{display:inline-flex;vertical-align:baseline;
  margin-left:var(--space-dense)}
/* The card trigger sits under the provenance footer, so it needs the same top
   gap the footer itself takes from the views above it. */
.mtt-card .evidence-trigger{margin-top:var(--space-compact)}

.mtt-more{margin-top:var(--space-comfortable)}
.mtt-more>summary{cursor:pointer;font-size:var(--type-scale-caption);
  color:var(--color-text-secondary)}
.mtt-more>.mtt-grid{margin-top:var(--space-compact)}
@media (min-width:760px){
  .cbt-grid,.jrh-grid,.mtt-grid,.spt-grid{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:560px){
  .cbt-card,.jrh-card,.mtt-card,.spt-card{padding:var(--space-compact)}
}

/* ---- R252: the archived states. An archive page is neither fresh nor late;
   it is as published, so it renders its own state rather than a derivation
   against the current run (staleness_banner_data.build_archived). ---- */
.pub-stale[data-fresh="archived"]{background:#20242c;color:#b9c2d0}
.pub-stale[data-fresh="archived"] a{color:inherit;text-decoration:underline}
.freshness-badge[data-state="archived"]{background:#20242c;color:#b9c2d0;
  border-color:#38404e}
.asym-state--not-retained,
.asym-state--unavailable{font-style:italic;color:var(--color-text-tertiary)}
.asym-state--not-retained a,
.asym-state--unavailable a{color:inherit;text-decoration:underline}

/* ── Licence-ruled readings ──────────────────────────────────────────────
   A reading we may not publish still occupies the space the number would
   have: R381's rule for withheld stress classes, applied to a single cell.
   A cell that simply vanished would let a reader take "no number" for "no
   signal", and the distinction between a wire we cannot quote and a wire
   that is quiet is the more important fact.

   Defined HERE rather than in sigil.css because monitor.html loads
   components.css and does NOT load sigil.css or tokens-v3.css. The tripwire
   board began emitting .val-absent / .blocked-fill on 2026-09-14, and those
   classes would have rendered as unstyled inline text on it — the chip would
   have read as body copy sitting in a numeric column. `.blocked-fill` is
   given a self-contained fallback here for the same reason: its --tex-blocked
   texture is a tokens-v3 token that this page never loads. */
.val-absent {
  display: inline-block;
  font-size: 12px;
  font-style: italic;
  line-height: 1.4;
  color: var(--color-text-tertiary);
  padding: 1px 6px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-subtle);
  white-space: nowrap;
}
.val-absent.blocked-fill {
  border-left-width: 2px;
  border-left-color: var(--color-text-tertiary);
  background: var(--color-surface-bg-subtle);
}

/* Tripwire board: distance cell at or past trigger (monitor_ssr_board_data.py).
   The builder emitted `.crit` believing it backed; only the compound `.tag.crit`
   existed, so "past trigger" rendered in body colour (check_class_backing_css,
   2026-09-24). Bare-class rule, danger token, so light/dark both follow tokens. */
.crit { color: var(--color-accent-danger); font-weight: 600; }
