/* ===========================================================================
   BRIDGE AI — components
   ---------------------------------------------------------------------------
   Every component below exists to render ONE honest thing:
     .verdict      the six pre-registered machine verdicts, and nothing else
     .ladder       the R1..R8 scorecard, VERBATIM, with the killing rung marked
     .stages       a submission walking the funnel, failures shown inline
     .banner       a fault, loudly, never a decoration
     .empty        an empty state that says what empty MEANS here
   =========================================================================== */

/* ============================================================== surfaces */
.card {
  background: var(--ink-850);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--s5);
}
.card--flush { padding: 0; overflow: hidden; }
.card--raised { background: var(--ink-800); box-shadow: var(--sh-2); }
.card--link { transition: border-color var(--fast) var(--ease), transform var(--fast) var(--ease); }
.card--link:hover { border-color: var(--line-2); transform: translateY(-2px); }

.card > header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  flex-wrap: wrap;
  margin-bottom: var(--s4);
}
.card > header h3 {
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  font-weight: 600;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--text-3);
}

/* ============================================================== verdicts */
/* The six words, and only the six. A seventh variant does not exist because a
   seventh verdict does not exist (docs/RESEARCH-CONTRACT.md section 4). */
.verdict {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  padding: var(--s1) var(--s3);
  border-radius: var(--r-sm);
  border: 1px solid var(--mute-line);
  background: var(--mute-wash);
  color: var(--mute);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
}
.verdict::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 2px;
  background: currentColor;
  flex: none;
}
.verdict--pass         { color: var(--green); border-color: var(--green-line); background: var(--green-wash); }
.verdict--fail_no_edge { color: var(--coral); border-color: var(--coral-line); background: var(--coral-wash); }
.verdict--fail_fragile { color: var(--amber); border-color: var(--amber-line); background: var(--amber-wash); }
.verdict--insufficient_evidence { color: var(--steel); border-color: var(--steel-line); background: var(--steel-wash); }
.verdict--unspecifiable { color: var(--stone); border-color: var(--stone-line); background: var(--stone-wash); }
.verdict--disqualified {
  color: var(--rust);
  border-color: var(--rust-line);
  /* Hatched on purpose: a disqualified run is not a weak result, it is not a
     result, and it must not look like one. */
  background:
    repeating-linear-gradient(135deg,
      rgba(226, 89, 78, .16) 0 5px, transparent 5px 10px),
    var(--rust-wash);
}

/* The unmissable chip at the top of a strategy card. */
.verdict--hero {
  font-size: clamp(var(--t-md), 3.2vw, var(--t-lg));
  padding: var(--s3) var(--s5);
  border-radius: var(--r-md);
  letter-spacing: .04em;
  border-width: 1px;
  box-shadow: var(--sh-2);
}
.verdict--hero::before { width: 10px; height: 10px; border-radius: 3px; }

.decision {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: 2px var(--s2);
  border-radius: var(--r-sm);
  border: 1px dashed var(--mute-line);
  color: var(--text-3);
}
.decision { white-space: nowrap; }
.decision--shortlisted { color: var(--green); border: 1px solid var(--green-line); background: var(--green-wash); }
.decision--rejected    { color: var(--coral); border: 1px solid var(--coral-line); background: var(--coral-wash); }
/* "No sign-off needed" (a FAIL/DISQUALIFIED/INSUFFICIENT/UNSPECIFIABLE row) and
   "not tested yet" (no verdict at all) are STATES OF THE WORLD, not pending
   work — muted, so the eye goes to the rows that do await a person. */
.decision--moot, .decision--untested { color: var(--text-3); border-color: var(--mute-line); }

/* ================================================================ pills */
.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  padding: 3px var(--s2);
  border-radius: var(--r-pill);
  border: 1px solid var(--line-2);
  background: var(--ink-800);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--text-2);
  white-space: nowrap;
}
.pill--ok   { color: var(--green); border-color: var(--green-line); background: var(--green-wash); }
.pill--warn { color: var(--yellow); border-color: var(--yellow-line); background: var(--yellow-wash); }
.pill--bad  { color: var(--coral); border-color: var(--coral-line); background: var(--coral-wash); }
.pill-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }
.pill--live .pill-dot { animation: beat 1.8s var(--ease) infinite; }
@keyframes beat {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: .35; transform: scale(.7); }
}
@media (prefers-reduced-motion: reduce) { .pill--live .pill-dot { animation: none; } }

/* =============================================================== buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  font-weight: 600;
  letter-spacing: .02em;
  padding: var(--s3) var(--s5);
  border-radius: var(--r-md);
  border: 1px solid var(--line-2);
  background: var(--ink-800);
  color: var(--text);
  cursor: pointer;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease),
              transform var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.btn:hover { background: var(--ink-750); border-color: var(--line-3); }
.btn:active { transform: translateY(1px); }
.btn--primary {
  background: linear-gradient(96deg, var(--yellow), var(--yellow-deep));
  border-color: transparent;
  color: var(--ink-1000);
  box-shadow: 0 10px 30px -14px rgba(255, 214, 77, .65);
}
.btn--primary:hover { background: linear-gradient(96deg, #FFE27A, var(--yellow)); }
.btn--go {
  background: linear-gradient(96deg, var(--green), var(--green-deep));
  border-color: transparent;
  color: var(--ink-1000);
  box-shadow: 0 10px 30px -14px rgba(61, 220, 132, .6);
}
.btn--danger { color: var(--coral); border-color: var(--coral-line); background: var(--coral-wash); }
.btn--danger:hover { background: rgba(255, 141, 125, .18); }
.btn--ghost { background: transparent; }
.btn--sm { padding: var(--s1) var(--s3); font-size: var(--t-xs); }
.btn--lg { padding: var(--s4) var(--s6); font-size: var(--t-base); }
.btn--block { width: 100%; }
.btn[disabled], .btn[aria-disabled="true"] {
  opacity: .45;
  cursor: not-allowed;
  background: var(--ink-800);
  color: var(--text-3);
  border-color: var(--line);
  box-shadow: none;
  transform: none;
}

/* ================================================================ fields */
.field { display: flex; flex-direction: column; gap: var(--s2); }
.field > label {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--text-3);
}
.input, .select, .textarea {
  width: 100%;
  font-family: var(--font-mono);
  font-size: var(--t-base);
  color: var(--text);
  background: var(--ink-1000);
  border: 1px solid var(--line-2);
  border-radius: var(--r-md);
  padding: var(--s3) var(--s4);
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.input::placeholder, .textarea::placeholder { color: var(--text-disabled); }
.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--yellow-line);
  box-shadow: 0 0 0 3px rgba(255, 214, 77, .12);
}
/* `appearance:none` with `background-image:none` strips the chevron and leaves
   a dropdown that looks exactly like a text input, while still reserving 32px
   on the right for the arrow it no longer draws — which is what was
   truncating "flat, newest first" and "INSUFFICIENT_EVIDENCE". The chevron is
   inline (house rule: no external requests) and drawn in --text-3. */
.select {
  appearance: none;
  cursor: pointer;
  padding-right: var(--s5);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%236B846A' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--s3) center;
  background-size: 10px 6px;
}
.select:focus { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23FFD64D' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); }

/* The native date control is the only light-on-dark chrome in the filter card.
   The glyph is tinted into the palette; the ISO hint under the pair is what
   answers the locale placeholder, since every date this archive DISPLAYS is
   ISO and the browser asks for mm/dd/yyyy. */
.input[type="date"]::-webkit-calendar-picker-indicator {
  filter: invert(.6) sepia(.2) saturate(.4) hue-rotate(60deg);
  cursor: pointer;
}
.field-hint {
  margin-top: var(--s1);
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  color: var(--text-3);
}
/* The client-side refine box: it belongs with the rows it narrows, not with
   the server filters, so it sits above them with its own breathing room. */
.refine-field { max-width: 32rem; margin-bottom: var(--s4); }
.textarea { resize: vertical; min-height: 96px; line-height: 1.55; }

/* ---------------------------------------------------- the hero paste box */
.pastebox {
  position: relative;
  border: 1px solid var(--line-2);
  border-radius: var(--r-xl);
  background:
    linear-gradient(180deg, rgba(255, 214, 77, .05), transparent 52%),
    var(--ink-850);
  padding: var(--s5);
  box-shadow: var(--sh-3);
  transition: border-color var(--mid) var(--ease), box-shadow var(--mid) var(--ease);
}
.pastebox:focus-within { border-color: var(--yellow-line); box-shadow: var(--glow-yellow), var(--sh-3); }
.pastebox.is-invalid { border-color: var(--coral-line); }
.pastebox .textarea {
  border: 0;
  background: transparent;
  padding: 0;
  font-size: var(--t-md);
  min-height: 3.2em;
}
.pastebox .textarea:focus { box-shadow: none; }
.pastebox-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4);
  flex-wrap: wrap;
  margin-top: var(--s4);
  padding-top: var(--s4);
  border-top: 1px solid var(--line);
}
.pastebox-status {
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  color: var(--text-3);
  min-height: 1.4em;
}
.pastebox-status.is-ok  { color: var(--green); }
.pastebox-status.is-bad { color: var(--coral); }

/* ================================================================ banners */
.banner {
  display: flex;
  gap: var(--s3);
  align-items: flex-start;
  padding: var(--s3) var(--s4);
  border-radius: var(--r-md);
  border: 1px solid var(--line-2);
  background: var(--ink-800);
  font-size: var(--t-sm);
  line-height: 1.55;
  color: var(--text-2);
}
.banner + .banner { margin-top: var(--s2); }
.sysbanners:not(:empty) > .banner:last-child { margin-bottom: var(--s5); }

/* The verdict + decision pair at the top of a strategy card: right-aligned
   beside the title on a desktop, left-aligned under it on a phone, where
   right-alignment reads as a stray. */
.chipstack { display: flex; flex-direction: column; gap: var(--s2); align-items: flex-end; }
@media (max-width: 760px) { .chipstack { align-items: flex-start; } }
.banner b, .banner strong { color: var(--text); font-weight: 600; }
.banner code {
  font-family: var(--font-mono);
  color: var(--yellow);
  background: var(--yellow-wash);
  padding: 1px 5px;
  border-radius: var(--r-sm);
}
.banner-mark { flex: none; font-family: var(--font-mono); font-weight: 700; }
.banner--warn   { border-color: var(--yellow-line); background: var(--yellow-wash); }
.banner--warn   .banner-mark { color: var(--yellow); }
.banner--danger { border-color: var(--coral-line); background: var(--coral-wash); }
.banner--danger .banner-mark { color: var(--coral); }
.banner--info   { border-color: var(--steel-line); background: var(--steel-wash); }
.banner--info   .banner-mark { color: var(--steel); }
.banner--ok     { border-color: var(--green-line); background: var(--green-wash); }
.banner--ok     .banner-mark { color: var(--green); }

.flash {
  display: flex;
  gap: var(--s3);
  align-items: flex-start;
  margin-bottom: var(--s5);
  padding: var(--s3) var(--s4);
  border-left: 3px solid var(--yellow);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  background: var(--ink-800);
  font-size: var(--t-sm);
  color: var(--text-2);
}

/* ========================================================== empty states */
.empty {
  border: 1px dashed var(--line-2);
  border-radius: var(--r-lg);
  padding: var(--s7) var(--s5);
  text-align: center;
  background: rgba(8, 20, 8, .5);
}
.empty-mark {
  font-family: var(--font-mono);
  font-size: var(--t-lg);
  color: var(--text-4);
  letter-spacing: .1em;
}
.empty h3 {
  margin-top: var(--s3);
  font-family: var(--font-mono);
  font-size: var(--t-md);
  letter-spacing: var(--track-tight);
}
.empty p { margin: var(--s2) auto 0; max-width: 52ch; color: var(--text-3); font-size: var(--t-sm); }
.empty .btn { margin-top: var(--s5); }

/* ============================================================= skeletons */
.skeleton {
  border-radius: var(--r-sm);
  background: linear-gradient(90deg, var(--ink-800) 0%, var(--ink-750) 50%, var(--ink-800) 100%);
  background-size: 200% 100%;
  animation: shimmer 1.6s linear infinite;
  color: transparent !important;
  min-height: 1em;
}
@keyframes shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .skeleton { animation: none; } }
.skeleton--line { height: 10px; width: 100%; }
.skeleton--short { width: 40%; }

/* ================================================================ stages */
/* One submission walking submitted -> ... -> verdict. Failure states are
   RESULTS and render inline, in place, never as a hidden error. */
.stages {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  align-items: stretch;
}
.stage {
  display: flex;
  align-items: center;
  gap: var(--s2);
  padding: var(--s1) var(--s3);
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  background: var(--ink-850);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--text-4);
  white-space: nowrap;
}
.stage-dot {
  width: 7px; height: 7px; border-radius: 50%;
  border: 1px solid var(--line-3);
  background: transparent;
  flex: none;
}
.stage--done { color: var(--green); border-color: var(--green-line); background: var(--green-wash); }
.stage--done .stage-dot { background: var(--green); border-color: var(--green); }
.stage--active {
  color: var(--yellow);
  border-color: var(--yellow-line);
  background: var(--yellow-wash);
}
.stage--active .stage-dot { background: var(--yellow); border-color: var(--yellow); animation: beat 1.4s var(--ease) infinite; }
@media (prefers-reduced-motion: reduce) { .stage--active .stage-dot { animation: none; } }
/* QUEUED IS NOT RUNNING. The beat on .stage--active means "work is happening
   right now"; a job that is merely waiting gets its own still state, so the
   rail cannot claim a worker is computing when the worker is down. */
.stage--queued {
  color: var(--text-3);
  border-color: var(--yellow-line);
  background: transparent;
}
.stage--queued .stage-dot { background: transparent; border-color: var(--yellow-line); }
.stage--result { color: var(--stone); border-color: var(--stone-line); background: var(--stone-wash); }
.stage--result .stage-dot { background: var(--stone); border-color: var(--stone); }
.stage--failed { color: var(--coral); border-color: var(--coral-line); background: var(--coral-wash); }
.stage--failed .stage-dot { background: var(--coral); border-color: var(--coral); }
.stage--skipped { opacity: .45; }

.stage-note {
  margin-top: var(--s3);
  padding: var(--s3) var(--s4);
  border-radius: var(--r-md);
  border: 1px solid var(--line-2);
  background: var(--ink-800);
  font-size: var(--t-sm);
  color: var(--text-2);
  line-height: 1.55;
}
.stage-note--result { border-color: var(--stone-line); background: var(--stone-wash); }
.stage-note--failed { border-color: var(--coral-line); background: var(--coral-wash); }
.stage-note b { color: var(--text); }

/* ====================================================== the progress block */
/* WAITING IS NOT WORKING. The rail says which stages happened; this block
   says whether the funnel is still moving and whether a PERSON is the thing
   it is waiting for. The two must never be confusable, so the working states
   are cool and unmarked (nothing is expected of you), and the states that
   need a human are warm, bordered, and carry the button. */
.stage--waiting {
  color: var(--amber);
  border-color: var(--amber-line);
  background: var(--amber-wash);
  border-style: dashed;
}
.stage--waiting .stage-dot { background: transparent; border-color: var(--amber); }
.stage--blocked {
  color: var(--amber);
  border-color: var(--amber-line);
  background: var(--amber-wash);
}
.stage--blocked .stage-dot { background: var(--amber); border-color: var(--amber); }

.progress {
  margin-top: var(--s3);
  padding: var(--s3) var(--s4);
  border-radius: var(--r-md);
  border: 1px solid var(--line-2);
  background: var(--ink-800);
  font-size: var(--t-sm);
  color: var(--text-2);
  line-height: 1.55;
}
/* The states a human is the blocker for are the only ones that raise their
   voice: a louder border and a warm wash, so "nothing will happen until you
   act" cannot be skimmed past as though it were progress. */
.progress--waiting,
.progress--blocked,
.progress--stalled { border-color: var(--amber-line); background: var(--amber-wash); }
.progress--failed  { border-color: var(--coral-line); background: var(--coral-wash); }
.progress--finished { border-color: var(--green-line); background: var(--green-wash); }
.progress--result  { border-color: var(--stone-line); background: var(--stone-wash); }

.progress-head { display: flex; gap: var(--s3); align-items: baseline; flex-wrap: wrap; }
.progress-text { flex: 1 1 260px; min-width: 0; }

.progress-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  padding: 2px var(--s3);
  border-radius: var(--r-pill);
  border: 1px solid var(--line-2);
  background: var(--ink-850);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: .04em;
  white-space: nowrap;
  color: var(--text-3);
}
.progress-badge--ok   { color: var(--green); border-color: var(--green-line); background: var(--green-wash); }
.progress-badge--info { color: var(--steel); border-color: var(--steel-line); background: var(--steel-wash); }
.progress-badge--warn { color: var(--amber); border-color: var(--amber-line); background: var(--amber-wash); }
.progress-badge--bad  { color: var(--coral); border-color: var(--coral-line); background: var(--coral-wash); }
/* Only a RUNNING badge beats. A waiting one must never borrow the animation
   that means "work is happening right now". */
.progress--running .progress-badge .pill-dot { animation: beat 1.4s var(--ease) infinite; }
@media (prefers-reduced-motion: reduce) {
  .progress--running .progress-badge .pill-dot { animation: none; }
}

.progress-reasons { margin: var(--s3) 0 0; padding-left: var(--s5); }
.progress-reasons li { margin-top: var(--s2); }

.progress-clock { margin-top: var(--s3); color: var(--text-3); }
.progress-worker { margin-top: var(--s2); color: var(--text-3); }
.progress-worker--down { color: var(--coral); }

.progress-timing { margin-top: var(--s3); }
.progress-timing summary { cursor: pointer; }
.progress-table { width: 100%; border-collapse: collapse; margin-top: var(--s2); }
.progress-table th,
.progress-table td {
  text-align: left;
  padding: 2px var(--s3) 2px 0;
  border-bottom: 1px solid var(--line);
  color: var(--text-3);
  white-space: nowrap;
}
.progress-table th { color: var(--text-4); font-weight: 400; }

/* ================================================================ ladder */
/* THE CENTREPIECE. Eight rungs on one spine. A human must see WHICH rule
   killed a strategy in three seconds, so the killing rung carries a coral
   spine segment and a marker, and every rung renders its stored actual and
   threshold VERBATIM from Verdict.scorecard. */
.ladder { border-top: 1px solid var(--line); }

.rung {
  display: grid;
  grid-template-columns: 26px 1fr minmax(120px, auto) minmax(110px, auto) 78px;
  gap: var(--s3);
  align-items: center;
  padding: var(--s3) var(--s2);
  border-bottom: 1px solid var(--line);
  position: relative;
}
.rung::before {                      /* the spine */
  content: "";
  position: absolute;
  left: 12px; top: 0; bottom: 0;
  width: 2px;
  background: var(--line-2);
}
.rung:first-child::before { top: 50%; }
.rung:last-child::before  { bottom: 50%; }

.rung-id {
  position: relative;
  z-index: 1;
  width: 26px; height: 26px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--ink-850);
  border: 1px solid var(--line-2);
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  font-weight: 700;
  color: var(--text-3);
}
.rung-title { font-size: var(--t-sm); color: var(--text-2); }
.rung-title .split {
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: .1em;
  color: var(--text-4);
  margin-left: var(--s2);
}
.rung-actual, .rung-threshold {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-sm);
}
.rung-actual { color: var(--text); font-weight: 600; }
.rung-threshold { color: var(--text-3); }
.rung-threshold::before { content: "bar "; color: var(--text-4); font-size: var(--t-2xs); }
.rung-mark {
  justify-self: end;
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: 2px var(--s2);
  border-radius: var(--r-sm);
  border: 1px solid var(--mute-line);
  color: var(--text-3);
  white-space: nowrap;
}

.rung--pass .rung-id { color: var(--green); border-color: var(--green-line); background: var(--green-wash); }
.rung--pass .rung-mark { color: var(--green); border-color: var(--green-line); background: var(--green-wash); }

.rung--fail { background: linear-gradient(90deg, var(--coral-wash), transparent 70%); }
.rung--fail::before { background: var(--coral); }
.rung--fail .rung-id { color: var(--coral); border-color: var(--coral); background: var(--coral-wash); }
.rung--fail .rung-actual { color: var(--coral); }
.rung--fail .rung-mark { color: var(--coral); border-color: var(--coral-line); background: var(--coral-wash); }

/* NOT SCORED stays visually quiet — but by MUTING THE GROUND, not by making
   the words unreadable. The dashed mark is what says "never measured"; the ink
   is the same readable tertiary every other rung uses. */
.rung--none { background: var(--mute-wash); }
.rung--none .rung-title, .rung--none .rung-actual { color: var(--text-4); }
.rung--none .rung-mark { border-style: dashed; color: var(--text-4); }

/* UNDER THE FLOOR — an R2 row that did not clear. tokens.css fixes steel as
   "INSUFFICIENT EVIDENCE — deliberately cool: NOT a failure", which is exactly
   what the row's own stored detail says: "Under the floor this split decides
   nothing — which is not the same as failing." It must never wear the coral of
   the rung that killed the strategy. */
.rung--short { background: linear-gradient(90deg, var(--steel-wash), transparent 70%); }
.rung--short::before { background: var(--steel); }
.rung--short .rung-id { color: var(--steel); border-color: var(--steel-line); background: var(--steel-wash); }
.rung--short .rung-actual { color: var(--steel); }
.rung--short .rung-mark { color: var(--steel); border-color: var(--steel-line); background: var(--steel-wash); }

.rung--killer { box-shadow: inset 3px 0 0 var(--coral); }
/* The decisive rung of an INSUFFICIENT_EVIDENCE verdict is an R2 floor row —
   `_decisive_row_id` resolves it, correctly, from the stored flags. It really
   did decide the verdict, so it keeps the killer rail and the tag; the rail is
   steel there because nothing was MISSED, which is what coral means. */
.rung--short.rung--killer { box-shadow: inset 3px 0 0 var(--steel); }
.rung--short .rung-killer-tag { color: var(--steel); }
.rung-killer-tag {
  grid-column: 2 / -1;
  margin-top: var(--s1);
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--coral);
}
.rung-detail {
  grid-column: 2 / -1;
  margin-top: var(--s2);
  font-size: var(--t-sm);
  color: var(--text-3);
  line-height: 1.55;
  max-width: 88ch;
}
/* The recorded sentence above is never edited. Where the recorded EVIDENCE
   contradicts it, the contradiction is printed here, in coral, attached to the
   rung it belongs to — so the reader meets both, in that order. */
.rung-caveat {
  grid-column: 2 / -1;
  margin-top: var(--s2);
  padding-left: var(--s3);
  border-left: 2px solid var(--coral);
  font-size: var(--t-sm);
  color: var(--coral);
  line-height: 1.55;
  max-width: 88ch;
}

.ladder-legend {
  display: flex;
  gap: var(--s4);
  flex-wrap: wrap;
  margin-top: var(--s4);
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-4);
}

@media (max-width: 760px) {
  .rung {
    grid-template-columns: 26px 1fr auto;
    row-gap: var(--s1);
  }
  .rung-title { grid-column: 2 / -1; }
  .rung-actual { grid-column: 2; }
  .rung-mark { grid-column: 3; grid-row: 2; }
  .rung-threshold { grid-column: 2 / -1; }
}

/* ================================================================ tables */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--t-sm);
}
.table th {
  text-align: left;
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  font-weight: 600;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--text-4);
  padding: var(--s2) var(--s3);
  border-bottom: 1px solid var(--line-2);
  white-space: nowrap;
}
.table td {
  padding: var(--s3);
  border-bottom: 1px solid var(--line);
  color: var(--text-2);
  vertical-align: middle;
}
.table tbody tr:hover td { background: var(--ink-800); }

/* Column weight follows IMPORTANCE. Without hints the archive inverted it: the
   strategy name wrapped to two lines in a narrow column while an internal file
   path spent three lines in Source. The Source cell is clipped with its full
   value in `title`; nothing is lost, it just stops shouting. */
@media (min-width: 761px) {
  /* `width` alone loses: with table-layout:auto every other column's
     min-content (nowrap headings, chips) wins, and the one column whose text
     CAN wrap is the one that gets squeezed — which is how a strategy name
     ended up on four lines beside a one-line file path. min-width is what
     actually holds the space. */
  .table--archive th:nth-child(1) { width: 26%; min-width: 12rem; }
  .table--archive th:nth-child(2) { width: 18%; }
  .table--archive td.clip {
    max-width: 22ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}
/* The margin's provenance note sits UNDER its figure, not beside it: inline
   and nowrap it was the widest thing in the row, for the least important
   thing in it. */
.margin-note { display: block; margin-top: 2px; }
.table .n { font-family: var(--font-mono); font-variant-numeric: tabular-nums; text-align: right; color: var(--text); }
.table .n--pos { color: var(--green); }
.table .n--neg { color: var(--coral); }

/* Below 760px the archive stops being a table and becomes a stack of cards,
   each cell labelled by its column — genuinely usable at 390px. */
@media (max-width: 760px) {
  .table--stack thead { display: none; }
  .table--stack, .table--stack tbody, .table--stack tr, .table--stack td { display: block; width: 100%; }
  .table--stack tr {
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    margin-bottom: var(--s3);
    background: var(--ink-850);
    padding: var(--s2);
  }
  .table--stack td { border: 0; padding: var(--s2); display: flex; gap: var(--s3); align-items: baseline; }
  .table--stack td::before {
    content: attr(data-label);
    flex: none;
    min-width: 96px;
    font-family: var(--font-mono);
    font-size: var(--t-2xs);
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--text-4);
  }
  .table--stack .n { text-align: left; }
}

/* ================================================================== KPIs */
.kpi {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--ink-850);
  padding: var(--s4);
}
/* Two-up at phone width (see base.css): the tighter padding is what buys the
   second column, and it has to sit AFTER `.kpi` to win on source order. */
@media (max-width: 760px) {
  .kpi { padding: var(--s3); }
}
.kpi-label {
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--text-4);
}
.kpi-value {
  margin-top: var(--s2);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-xl);
  font-weight: 600;
  letter-spacing: var(--track-tight);
  line-height: 1;
}
.kpi-note { margin-top: var(--s2); font-size: var(--t-xs); color: var(--text-3); }
.kpi--green .kpi-value { color: var(--green); }
.kpi--coral .kpi-value { color: var(--coral); }
.kpi--amber .kpi-value { color: var(--amber); }
.kpi--steel .kpi-value { color: var(--steel); }
.kpi--stone .kpi-value { color: var(--stone); }
.kpi--rust  .kpi-value { color: var(--rust); }

/* A horizontal bar showing HOW the archive died, by verdict. */
.deathbar {
  display: flex;
  height: 10px;
  border-radius: var(--r-pill);
  overflow: hidden;
  border: 1px solid var(--line-2);
  background: var(--ink-1000);
}
.deathbar span { display: block; height: 100%; }
.deathbar-key { display: flex; flex-wrap: wrap; gap: var(--s3); margin-top: var(--s3); }
.deathbar-key span {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--text-3);
}
.deathbar-key i { width: 8px; height: 8px; border-radius: 2px; display: inline-block; }

/* =========================================================== disclosure */
.disclosure {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--ink-850);
  overflow: hidden;
}
.disclosure + .disclosure { margin-top: var(--s2); }
.disclosure > summary {
  cursor: pointer;
  list-style: none;
  padding: var(--s3) var(--s4);
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  color: var(--text-2);
  display: flex;
  align-items: center;
  gap: var(--s3);
}
.disclosure > summary::-webkit-details-marker { display: none; }
.disclosure > summary::before {
  content: "+";
  font-weight: 700;
  color: var(--text-4);
  width: 1ch;
}
.disclosure[open] > summary::before { content: "\2212"; }
.disclosure[open] > summary { border-bottom: 1px solid var(--line); color: var(--text); }
.disclosure-body { padding: var(--s4); }

pre.code {
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  line-height: 1.5;
  color: var(--text-2);
  background: var(--ink-1000);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: var(--s4);
  overflow: auto;
  max-height: 60vh;
}

/* ============================================================ rule prose */
.rules dl { display: grid; grid-template-columns: minmax(96px, auto) 1fr; gap: var(--s2) var(--s4); }
.rules dt {
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--text-4);
  padding-top: 3px;
}
.rules dd { margin: 0; color: var(--text-2); font-size: var(--t-sm); line-height: 1.6; }
.rules dd .tok { font-family: var(--font-mono); color: var(--text); }
.rules dd .op  { color: var(--yellow); font-family: var(--font-mono); }
.rules ul li { padding-left: var(--s4); position: relative; }
.rules ul li::before { content: "\25B8"; position: absolute; left: 0; color: var(--text-4); }
@media (max-width: 560px) {
  .rules dl { grid-template-columns: minmax(0, 1fr); gap: var(--s1) 0; }
  .rules dd { margin-bottom: var(--s3); }
}

.assumptions li {
  padding: var(--s3) var(--s4);
  border-left: 2px solid var(--yellow-line);
  background: var(--yellow-wash);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  font-size: var(--t-sm);
  color: var(--text-2);
  line-height: 1.55;
}
.assumptions li + li { margin-top: var(--s2); }

/* ==================================================== the trade gallery */
/* The images are PNGs rendered by research/charts.py and served by the panel's
   auth-gated chart route. Everything here is layout: no rule below changes a
   figure, and nothing is hidden at any width — a chart a reader cannot see is
   a chart that is not evidence. */
.chartfig { margin: 0 0 var(--s5); }
.chartfig img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--ink-1000);
}
.chartfig figcaption {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3);
  align-items: baseline;
  justify-content: space-between;
  margin-top: var(--s2);
  font-size: var(--t-sm);
  color: var(--text-3);
}
.chartfig figcaption .n { font-family: var(--font-mono); color: var(--text); }

/* The sampling caption. Full strength, never a whispered footnote: a gallery
   that samples silently misrepresents the strategy it is evidence for. */
.chartcaption {
  margin: 0 0 var(--s4);
  font-size: var(--t-sm);
  color: var(--text-2);
}
.chartcaption--sampled {
  border-left: 2px solid var(--yellow-line);
  background: var(--yellow-wash);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  padding: var(--s3) var(--s4);
}
.chartcaption b { color: var(--text); }

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--s4);
}
.tile {
  position: relative;
  display: block;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--ink-850);
  padding: var(--s2);
  text-decoration: none;
  color: inherit;
  transition: border-color .15s ease, transform .15s ease;
}
.tile:hover, .tile:focus-visible {
  border-color: var(--line-3);
  transform: translateY(-1px);
}
.tile img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--r-sm);
  background: var(--ink-1000);
}
.tile-meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s2);
  margin-top: var(--s2);
}
.tile-side {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: var(--track-wide);
  color: var(--text-2);
}
.tile-meta .n { font-family: var(--font-mono); font-size: var(--t-sm); color: var(--text); }
.tile-sub {
  display: flex;
  justify-content: space-between;
  gap: var(--s2);
  margin-top: var(--s1);
  font-size: var(--t-2xs);
  color: var(--text-3);
}
.tile-tag {
  position: absolute;
  top: var(--s3);
  right: var(--s3);
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: .06em;
  color: var(--ink-1000);
  background: var(--yellow);
  border-radius: var(--r-sm);
  padding: 2px 6px;
}
/* The signed-figure tones, unscoped (the table has its own copies). */
.n--pos { color: var(--green); }
.n--neg { color: var(--coral); }

@media (max-width: 560px) {
  .gallery { grid-template-columns: 1fr; }
}

/* ============================================================ chart slot */
/* The honest empty state, kept as its own component: it is what a strategy
   with no rendered trades shows, and it must never look like a chart. */
.chartslot {
  border: 1px dashed var(--line-2);
  border-radius: var(--r-md);
  background: var(--ink-1000);
  min-height: 200px;
  display: grid;
  place-items: center;
  padding: var(--s5);
  text-align: center;
}
.chartslot[data-state="ready"] { border-style: solid; place-items: stretch; }
.chartslot svg { width: 100%; height: auto; }
.chart-line { fill: none; stroke: var(--green); stroke-width: 1.6; vector-effect: non-scaling-stroke; }
.chart-zero { stroke: var(--line-2); stroke-width: 1; vector-effect: non-scaling-stroke; }
.chart-fill { fill: var(--green-wash); stroke: none; }
.chart-caption {
  margin-top: var(--s2);
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: .06em;
  color: var(--text-4);
}

/* ============================================================== signoff */
.signoff {
  border: 1px solid var(--line-2);
  border-radius: var(--r-lg);
  background:
    linear-gradient(180deg, rgba(61, 220, 132, .05), transparent 46%),
    var(--ink-850);
  padding: var(--s5);
}
.signoff h2 { font-family: var(--font-mono); font-size: var(--t-md); letter-spacing: var(--track-tight); }
.signoff-why {
  margin-top: var(--s3);
  padding: var(--s3) var(--s4);
  border-radius: var(--r-md);
  border: 1px solid var(--line-2);
  background: var(--ink-800);
  font-size: var(--t-sm);
  color: var(--text-2);
  line-height: 1.55;
}
.signoff-actions { display: flex; gap: var(--s3); flex-wrap: wrap; margin-top: var(--s4); }
.signoff-actions form { display: contents; }

.confirm {
  border: 1px solid var(--yellow-line);
  background: var(--yellow-wash);
  border-radius: var(--r-lg);
  padding: var(--s5);
}
.confirm h2 { font-family: var(--font-mono); font-size: var(--t-md); color: var(--yellow); }
.confirm-restate {
  margin-top: var(--s3);
  padding: var(--s4);
  border-radius: var(--r-md);
  background: var(--ink-1000);
  border: 1px solid var(--line-2);
  font-size: var(--t-sm);
  color: var(--text-2);
  line-height: 1.6;
}
.confirm-restate b { color: var(--text); }

/* ============================================================== splits */
.split-head {
  display: flex;
  align-items: center;
  gap: var(--s3);
  flex-wrap: wrap;
}
.split-tag {
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: 2px var(--s2);
  border-radius: var(--r-sm);
  border: 1px solid var(--line-2);
  color: var(--text-3);
}
.split-tag--confirm { color: var(--steel); border-color: var(--steel-line); background: var(--steel-wash); }
.split-tag--short   { color: var(--steel); border-color: var(--steel-line); background: var(--steel-wash); }

/* A split UNDER THE TRADE FLOOR. Its figures are recorded evidence and they
   stay on the page — but the gate scored none of them, so they are muted and
   never tinted green or coral: a tone here would be a verdict the gate
   explicitly refused to give. */
.floor-tag {
  display: flex;
  align-items: baseline;
  gap: var(--s2);
  flex-wrap: wrap;
  margin-bottom: var(--s3);
  font-size: var(--t-sm);
  color: var(--steel);
  line-height: 1.5;
}
.grid-4--unscored .kpi {
  border-style: dashed;
  background: var(--mute-wash);
}
.grid-4--unscored .kpi-value { color: var(--text-3); font-weight: 500; }

/* ============================================================== filters */
.filters {
  display: grid;
  gap: var(--s3);
  /* 12.5rem, not 150px: the longest option a select has to show is
     "INSUFFICIENT_EVIDENCE" / "flat, newest first", and a track that truncates
     the default option is a filter whose current state cannot be read. */
  grid-template-columns: repeat(auto-fit, minmax(12.5rem, 1fr));
  align-items: end;
}
.filters .field > label { font-size: var(--t-2xs); }
.filter-actions { display: flex; gap: var(--s2); align-items: end; }

.chipbar { display: flex; flex-wrap: wrap; gap: var(--s2); }
.chipbar a {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  padding: 3px var(--s3);
  border-radius: var(--r-pill);
  border: 1px solid var(--line-2);
  color: var(--text-3);
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.chipbar a:hover { color: var(--text); border-color: var(--line-3); }
.chipbar a[aria-current="true"] { color: var(--yellow); border-color: var(--yellow-line); background: var(--yellow-wash); }

/* =============================================================== login */
.login-page {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: var(--s6) var(--gutter);
}
.login-card {
  width: 100%;
  max-width: 400px;
  background: var(--ink-850);
  border: 1px solid var(--line-2);
  border-radius: var(--r-xl);
  padding: var(--s6);
  box-shadow: var(--sh-3);
}
.login-card .brand { justify-content: flex-start; font-size: var(--t-lg); }
.login-card form { margin-top: var(--s5); display: flex; flex-direction: column; gap: var(--s4); }
.login-error {
  font-size: var(--t-sm);
  color: var(--coral);
  border: 1px solid var(--coral-line);
  background: var(--coral-wash);
  border-radius: var(--r-md);
  padding: var(--s3) var(--s4);
}
.login-foot {
  margin-top: var(--s5);
  padding-top: var(--s4);
  border-top: 1px solid var(--line);
  font-size: var(--t-xs);
  color: var(--text-4);
  line-height: 1.6;
}

/* ============================================================== footer */
.footnote {
  margin-top: var(--s8);
  padding-top: var(--s5);
  border-top: 1px solid var(--line);
  font-size: var(--t-xs);
  color: var(--text-4);
  line-height: 1.7;
}
.footnote b { color: var(--text-3); font-weight: 600; }

/* ======================================================== variant cohorts
   Generating k variants of one idea and shortlisting the best is the most
   common way honest-looking research lies to itself. The caption below is
   therefore styled like a BAR, not like a footnote: yellow is this panel's
   colour for the pre-registration itself, and the sentence sits above the
   cohort it describes, full width, impossible to scroll past on the way to a
   winning row. */
.cohort { margin-top: var(--s3); }
.cohort-caption {
  font-size: var(--t-sm);
  line-height: 1.65;
  color: var(--yellow);
  border: 1px solid var(--yellow-line);
  background: var(--yellow-wash);
  border-radius: var(--r-md);
  padding: var(--s3) var(--s4);
  margin-bottom: var(--s4);
}
.cohort-caption--tight {
  font-size: var(--t-xs);
  padding: var(--s2) var(--s3);
  margin-bottom: var(--s2);
}
.cohort-self td { background: var(--ink-800); }
.cohort-self td:first-child { box-shadow: inset 2px 0 0 var(--yellow); }

/* A variant nested under the parent it was generated from. */
.table .row--nested td:first-child { padding-left: var(--s5); }
.nest-mark {
  font-family: var(--font-mono);
  color: var(--text-4);
  margin-right: var(--s2);
}
.nest {
  margin-top: var(--s3);
  padding-left: var(--s3);
  border-left: 1px solid var(--line-2);
}
.nest-list { list-style: none; margin: 0; padding: 0; }
.nest-list li {
  display: flex;
  align-items: center;
  gap: var(--s2);
  flex-wrap: wrap;
  padding: var(--s1) 0;
  font-size: var(--t-sm);
}

/* The inline "variant" tag in the archive table. */
.tag {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  border-radius: var(--r-sm);
  padding: 1px 6px;
  margin-left: var(--s2);
  vertical-align: middle;
}
.tag--variant {
  color: var(--yellow);
  border: 1px solid var(--yellow-line);
  background: var(--yellow-wash);
}

/* Source fidelity (research/fidelity.py): what a row actually TESTED, beside
   the verdict it is quoted by. `loose` wears the coral of a disqualified
   result on purpose — a verdict on an approximation of a source is not
   evidence about that source, which is the same class of fact. A faithful row
   renders no tag at all; the absence of a tag is the quiet case. */
.tag--kind, .tag--mech, .tag--fidelity {
  color: var(--steel);
  border: 1px solid var(--steel-line);
  background: var(--steel-wash);
  margin-left: 0;
  margin-right: var(--s2);
}
.tag--fidelity { margin-left: var(--s2); margin-right: 0; }
.tag--kind-rule_substituted,
.tag--kind-feature_dropped,
.tag--fidelity-loose {
  color: var(--coral);
  border-color: var(--coral-line);
  background: var(--coral-wash);
}
.tag--kind-unclassified,
.tag--mech-core,
.tag--fidelity-approximate,
.tag--fidelity-unclassified,
.tag--fidelity-unrecorded {
  color: var(--yellow);
  border-color: var(--yellow-line);
  background: var(--yellow-wash);
}
