/* divergence.css · the DECIDING beat's pane · where the reads split
 * ════════════════════════════════════════════════════════════════════
 *
 * Companion to lib/divergence.js, which renders the graph-spine ontology
 * (lib/spine.js, ported from liminal-natsec/graph-spine).
 *
 * LAYOUT MODEL · depth is VERTICAL, divergence is HORIZONTAL.
 * Each read is a column carrying its provenance chain top-to-bottom
 * (observation → anomaly → hypothesis → claim → actionOption) with the typed
 * edge and its confidence rendered BETWEEN nodes. Horizontal room is the scarce
 * axis — the shell's centre pane is ~434px — so the ontology's depth spends
 * vertical space, which is free.
 *
 * Loaded standalone by cut 01 alongside surface-nav.css / brand-upgrade.css (the
 * established per-feature idiom) rather than folded into cut-shell.css, because
 * this is Decide-stage-specific and must not cascade into cuts that never fire
 * the DECIDING beat.
 *
 * RULE 1 COMPLIANCE (cuts/CONTRIBUTING.md) · canon only, zero hardcoded hex.
 *
 * CHROMA DISCIPLINE · v0.3 SEVERITY LANE (founder ruling, 2026-07-29 —
 * design-system/atlas/state-atlas.html + signal-atlas.html). Two sanctioned kinds
 * of earned signal, and they must never be flattened:
 *
 *   · SEVERITY is a property of the EVIDENCE — "flagged anomaly · refuted finding
 *     · custody alert · carried by evidence, not by the primitive". Severity uses
 *     **--alarm / --watch only**.
 *   · LIFECYCLE STATE uses **the four registers only**. A refused or corrected
 *     read is a lifecycle state → the judgment register (`--judgment`, which is
 *     `var(--wholeness)`; cf. state-atlas `.cell--refused{color:var(--wholeness)}`).
 *
 *   The ruling's own words: *"a refused agent and a flagged anomaly never share a
 *   hue"* / *"never flatten severity into judgment."*
 *
 * Applied here:
 *   refused read (lifecycle)      → --judgment            NOT --alarm
 *   CONTRADICTS (refuted finding) → --alarm                evidence severity
 *   WEAKENS (uncertain, pending)  → --watch                evidence severity
 *   SUPPORTS (favorable delta)    → --resolved             NOT --signal
 *   anomaly (flagged)             → --watch                evidence severity
 *   failed sourceIntegrityCheck   → --watch                "uncertain signal
 *                                                           pending corroboration"
 *   everything else               → INK. Per the atlas, chroma appears only where
 *                                   a hue names a measurement. A claim or an
 *                                   action measures nothing on its own — its
 *                                   EDGE carries the confidence, so the edge
 *                                   carries the colour. This also matches
 *                                   graph-spine, which puts confidence on the
 *                                   edge rather than the node.
 */

.divergence-pane[hidden] { display: none; }

.dvg {
  border-top: 1px solid var(--frame-border);
  border-bottom: 1px solid var(--frame-border);
  padding: 12px 0 14px;
  animation: dvg-arrive var(--tx-settle, 0.32s) ease-out both;

  /* CONTAINER, not viewport. The centre pane is ~434px at a 1440px window
     (.main is 280px | 1fr | 320px plus chrome), so a viewport media query never
     fires and side-by-side columns collapse to ~136px. The pane must respond to
     the space it actually has, in the catalog and standalone alike. */
  container-type: inline-size;
  container-name: dvg;
}

/* ─── header ─────────────────────────────────────────────────────────── */

.dvg-h {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-mid);
  margin-bottom: 10px;
}

.dvg-h-glyph { color: var(--judgment); font-size: 13px; }

.dvg-tag {
  margin-left: auto;
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--judgment);
  background: var(--judgment-bg);
  border: 1px solid var(--judgment-edge);
  border-radius: 3px;
  padding: 2px 7px;
  text-transform: none;
}

/* ─── case root · the emergence affordance ───────────────────────────── */

.dvg-ground {
  display: flex;
  align-items: baseline;
  gap: 10px;
  background: var(--frame-bg-2);
  border: 1px dashed var(--card-border);
  border-radius: 6px;
  padding: 8px 12px;
  margin-bottom: 8px;
  cursor: pointer;
  transition: border-color var(--tx-settle, 0.32s) ease,
              background var(--tx-settle, 0.32s) ease;
}

.dvg-ground:hover,
.dvg-ground:focus-visible {
  border-color: var(--judgment-edge);
  background: var(--judgment-bg);
  outline: none;
}

.dvg-ground-label,
.dvg-rule-label {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  white-space: nowrap;
}

.dvg-ground-body { font-size: 12px; color: var(--text-mid); }

.dvg-ground-hint,
.dvg-edge-hint {
  margin-left: auto;
  font-size: 10px;
  color: var(--text-faint);
  opacity: 0;
  transition: opacity var(--tx-settle, 0.32s) ease;
  white-space: nowrap;
}

/* The edge hint is an operator affordance, revealed on hover. In flow it
   reserved ~75px of the caption row while invisible — width taken from the
   one span carrying the actual disagreement. Lift it out of the flex flow:
   the row's scarce axis is horizontal, and per this file's own layout model
   depth spends vertical space, which is free. */
.dvg-edge-hint {
  position: absolute;
  right: 12px;
  bottom: 4px;
  margin-left: 0;
}

.dvg-ground:hover .dvg-ground-hint,
.dvg-ground:focus-visible .dvg-ground-hint,
.dvg-edge-caption:hover .dvg-edge-hint,
.dvg-edge-caption:focus-visible .dvg-edge-hint { opacity: 1; }

/* ─── columns · one per read, never merged ───────────────────────────── */

.dvg-grid {
  display: grid;
  grid-template-columns: repeat(var(--dvg-cols, 3), 1fr);
  gap: 10px;
}

.dvg-col {
  display: flex;
  flex-direction: column;
  gap: 6px;
  background: var(--frame-bg-2);
  border: 1px solid var(--card-border);
  border-radius: 6px;
  padding: 10px 12px 12px;
}

/* A refused read is the read, not an empty slot — typed chrome, full weight.
   Judgment register, NOT severity: a refused agent is a lifecycle state, and the
   v0.3 ruling forbids it sharing a hue with a flagged anomaly. */
.dvg-col.is-refused { border-color: var(--judgment-edge); background: var(--judgment-bg); }

.dvg-agent {
  display: flex;
  align-items: center;
  gap: 6px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--frame-border);
}

.dvg-agent-name { font-size: 11px; letter-spacing: 0.04em; color: var(--text); }

.dvg-reg {
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-left: auto;
}

.dvg-reg[data-reg="diligence"] { color: var(--diligence); }
.dvg-reg[data-reg="synthesis"] { color: var(--synthesis); }
.dvg-reg[data-reg="judgment"]  { color: var(--judgment); }
.dvg-reg[data-reg="outreach"]  { color: var(--outreach); }

/* ─── the chain · provenance depth, rendered downward ────────────────── */

/* The nodes bleed 6px outward so their hover background reaches the card edge.
   The chain absorbs that bleed (pad in, pull out by the same amount) — without
   this the children are 12px wider than the chain and it overflows. */
.dvg-chain {
  display: flex;
  flex-direction: column;
  padding-inline: 6px;
  margin-inline: -6px;
}

.dvg-node {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 5px 6px;
  margin: 0 -6px;
  border-radius: 4px;
  cursor: pointer;
  transition: background var(--tx-settle, 0.32s) ease,
              box-shadow var(--tx-settle, 0.32s) ease;
}

.dvg-node:hover,
.dvg-node:focus-visible {
  background: var(--judgment-bg);
  box-shadow: inset 2px 0 0 0 var(--judgment);
  outline: none;
}

.dvg-node-type {
  font-size: 9px;
  letter-spacing: 0.1em;
  color: var(--text-faint);
}

/* Only nodes whose hue NAMES a measurement get chroma (severity lane v0.3).
   · anomaly — "flagged anomaly" is domain severity, by name
   · sourceIntegrityCheck — a provenance gap is "watch-grade evidence · uncertain
     signal pending corroboration"
   claim and actionOption stay INK: they measure nothing on their own. Their edge
   carries the confidence, so the edge carries the colour — which is also where
   graph-spine puts it (EdgeProvenance.confidence).
   (A reviewRule never appears in a chain — traceBack does not traverse to it —
   so its chrome lives on .dvg-rule below, not here.) */
.dvg-node[data-node-type="anomaly"]              .dvg-node-type { color: var(--watch); }
.dvg-node[data-node-type="sourceIntegrityCheck"] .dvg-node-type { color: var(--watch); }

.dvg-node-title {
  font-size: 11.5px;
  line-height: 1.4;
  color: var(--text);
}

.dvg-node[data-node-type="observation"] .dvg-node-title { color: var(--text-mid); }

/* ─── the typed edge between two nodes ───────────────────────────────── */

.dvg-edge-step {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 2px 0 2px 8px;
  margin-left: 3px;
  border-left: 1px solid var(--frame-border);
  min-height: 16px;
}

.dvg-edge-step--supports    { border-left-color: var(--resolved); }
.dvg-edge-step--weakens     { border-left-color: var(--watch); }
.dvg-edge-step--contradicts { border-left-color: var(--alarm); }

.dvg-edge-type {
  font-size: 8.5px;
  letter-spacing: 0.1em;
  color: var(--text-faint);
}

.dvg-edge-step--supports    .dvg-edge-type { color: var(--resolved); }
.dvg-edge-step--weakens     .dvg-edge-type { color: var(--watch); }
.dvg-edge-step--contradicts .dvg-edge-type { color: var(--alarm); }

/* Confidence lives on the EDGE, per graph-spine's EdgeProvenance — a belief is
   only as strong as the link carrying it. */
.dvg-edge-conf {
  font-size: 9px;
  font-variant-numeric: tabular-nums;
  color: var(--text-faint);
}

.dvg-edge-conf[data-band="high"] { color: var(--resolved); }
.dvg-edge-conf[data-band="mid"]  { color: var(--watch); }
.dvg-edge-conf[data-band="low"]  { color: var(--alarm); }

/* ─── terminal · refusal stated as geometry ──────────────────────────── */

.dvg-terminal {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: auto;
  padding-top: 8px;
  border-top: 1px dashed var(--judgment-edge);
}

.dvg-terminal-kind {
  font-size: 9px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--judgment);
}

/* The four refusal_kinds are distinguished by TEXT, not by hue. Giving each its
   own colour would either spend severity hues on a lifecycle state (forbidden by
   the v0.3 ruling) or invent register attributions that do not exist. The kind is
   already named in the label — "refused · substrate" — so nothing is lost. */

.dvg-terminal-note { font-size: 10px; color: var(--text-faint); line-height: 1.35; }

/* ─── the divergence edge · disagreement across columns ──────────────── */

.dvg-edge-caption {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-top: 8px;
  padding: 6px 12px 18px;
  border-radius: 6px;
  background: var(--frame-bg-2);
  border: 1px solid var(--card-border);
  cursor: pointer;
  transition: border-color var(--tx-settle, 0.32s) ease;
}

.dvg-edge-caption[data-polarity="contradicts"] { border-left: 2px solid var(--alarm); }
.dvg-edge-caption[data-polarity="weakens"]     { border-left: 2px solid var(--watch); }
.dvg-edge-caption[data-polarity="supports"]    { border-left: 2px solid var(--resolved); }

.dvg-edge-caption:hover,
.dvg-edge-caption:focus-visible { border-color: var(--judgment-edge); outline: none; }

.dvg-edge-label {
  flex: 0 0 auto;
  font-size: 9px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
}

.dvg-edge-label--contradicts { color: var(--alarm); }
.dvg-edge-label--weakens     { color: var(--watch); }
.dvg-edge-label--supports    { color: var(--resolved); }

/* The note carries the disagreement itself — it outranks the metadata that
   annotates it. Previously every child sized to content and the note was the
   only one that could shrink, so it took 118px while its own label, score and
   hint took 163px between them, wrapping one sentence over five lines. */
.dvg-edge-note {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 11px;
  color: var(--text-mid);
}

.dvg-edge-caption > .dvg-edge-conf { flex: 0 0 auto; }

/* ─── carried review rule · memory reaching into this case ───────────── */

.dvg-rule {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 6px;
  padding: 6px 12px;
  border-radius: 6px;
  background: var(--judgment-bg);
  border: 1px solid var(--judgment-edge);
  cursor: pointer;
  transition: border-color var(--tx-settle, 0.32s) ease;
}

.dvg-rule:hover,
.dvg-rule:focus-visible { border-color: var(--judgment); outline: none; }

.dvg-rule-title { font-size: 11px; color: var(--text); }
.dvg-rule-note  { font-size: 10px; color: var(--text-faint); }

/* ─── corrected state · the founder's hand, visible ──────────────────── */

.is-corrected {
  box-shadow: inset 2px 0 0 0 var(--judgment) !important;
  background: var(--judgment-bg) !important;
}

/* ─── motion ─────────────────────────────────────────────────────────── */

@keyframes dvg-arrive {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}

/* Nothing here is motion-dependent — reduced motion simply lands it instantly. */
@media (prefers-reduced-motion: reduce) {
  .dvg { animation: none; }
  .dvg-ground,
  .dvg-node,
  .dvg-edge-caption,
  .dvg-rule,
  .dvg-ground-hint,
  .dvg-edge-hint { transition: none; }
}

/* ─── narrow container · reads stack as rows ─────────────────────────────
   Below ~560px of pane width there is not room for a legible chain in a column,
   so the reads stack full-width. Chains stay vertical — that is the ontology's
   depth and it is never traded away; only the columns' side-by-side comparison
   is. Polarity and confidence survive the layout change intact. */

@container dvg (max-width: 560px) {
  .dvg-grid { grid-template-columns: 1fr; }

  /* Collapsed by default: three full chains stacked run past 1000px, which
     destroys the at-a-glance comparison the pane exists for. Show the claim and
     the action it triggers; hide the ground it was built from until asked. The
     edge hides with the node it leads to (data-edge-to) so nothing dangles. */
  .dvg-col:not(.is-open):not(.is-refused) .dvg-node[data-node-type="observation"],
  .dvg-col:not(.is-open):not(.is-refused) .dvg-node[data-node-type="anomaly"],
  .dvg-col:not(.is-open):not(.is-refused) .dvg-node[data-node-type="hypothesis"],
  .dvg-col:not(.is-open):not(.is-refused) .dvg-edge-step[data-edge-to="anomaly"],
  .dvg-col:not(.is-open):not(.is-refused) .dvg-edge-step[data-edge-to="hypothesis"],
  .dvg-col:not(.is-open):not(.is-refused) .dvg-edge-step[data-edge-to="claim"] {
    display: none;
  }

  /* .dvg-col qualifier is load-bearing: the base `.dvg-expand{display:none}`
     rule is declared LATER in this file, so an unqualified selector here loses
     the source-order tie and the button never appears. */
  .dvg-col .dvg-expand { display: block; }
}

/* ─── provenance expander · narrow mode only ─────────────────────────── */

.dvg-expand {
  display: none; /* columnar mode shows the whole chain already */
  margin-top: 6px;
  padding: 4px 6px;
  font: inherit;
  font-size: 9.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
  background: transparent;
  border: 1px solid var(--frame-border);
  border-radius: 4px;
  cursor: pointer;
  text-align: left;
  transition: border-color var(--tx-settle, 0.32s) ease, color var(--tx-settle, 0.32s) ease;
}

.dvg-expand:hover,
.dvg-expand:focus-visible {
  color: var(--text-mid);
  border-color: var(--judgment-edge);
  outline: none;
}

.dvg-expand .dvg-expand-close { display: none; }
.dvg-col.is-open .dvg-expand .dvg-expand-open { display: none; }
.dvg-col.is-open .dvg-expand .dvg-expand-close { display: inline; }

@media (prefers-reduced-motion: reduce) {
  .dvg-expand { transition: none; }
}

/* No container-query support · fall back to stacking at narrow viewports so the
   pane is never worse than the pre-container behaviour. */
@supports not (container-type: inline-size) {
  @media (max-width: 720px) {
    .dvg-grid { grid-template-columns: 1fr; }
  }
}
