/* Before You Send — the panel's delivery surface.
   Palette and type carried from the published interface spec so the app and the
   spec do not drift. Brick is reserved for tail severity and is never spent on
   anything else; blue is the institution's own colour, which is the right one
   for a tool used inside a ministry and the wrong one for an alarm. */

:root {
  --ground:#EDEFF1; --surface:#FFFFFF; --sunk:#E3E7EA;
  --ink:#14181D;    --ink-2:#4A535D;   --ink-3:#7D8891;
  --rule:#D3D8DD;   --rule-strong:#B6BEC6;
  --accent:#1B4B8F; --accent-soft:#E3EAF4; --on-accent:#FFFFFF;
  --alarm:#A8321F;  --alarm-soft:#F6E3DF;  --alarm-mid:#D98B7C;
  --calm:#2C6B57;   --calm-soft:#DEEAE5;
  --flash:#FFFFFF;  --flash-peak:.88;

  /* Kiosk: there is no centred measure. The page is the screen, and this is
     the only thing holding text off the edge of it. */
  --gutter: clamp(18px, 3.2vw, 64px);
  --deck: calc(100dvh - 54px);

  /* Every number the panel reports is this size, wherever it appears. A figure
     that changes size according to which surface it lives on reads as a
     hierarchy the record does not have. */
  --fig: clamp(40px, 3.6vw, 66px);

  --display:"Archivo","Helvetica Neue",Helvetica,Arial,sans-serif;
  --body:"Source Serif 4","Iowan Old Style",Georgia,"Times New Roman",serif;
  --mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ground:#0F1216; --surface:#171B21; --sunk:#10141A;
    --ink:#E6EAEE;    --ink-2:#9AA5B1;   --ink-3:#6C7681;
    --rule:#262C35;   --rule-strong:#39414C;
    --accent:#7FA9E0; --accent-soft:#1B2432; --on-accent:#0F1216;
    --alarm:#E08272;  --alarm-soft:#2A1B18;  --alarm-mid:#8A4A3E;
    --calm:#6FBFA2;   --calm-soft:#17251F;
    --flash:#AFC6E6; --flash-peak:.40;
  }
}
:root[data-theme="dark"] {
  --ground:#0F1216; --surface:#171B21; --sunk:#10141A;
  --ink:#E6EAEE;    --ink-2:#9AA5B1;   --ink-3:#6C7681;
  --rule:#262C35;   --rule-strong:#39414C;
  --accent:#7FA9E0; --accent-soft:#1B2432; --on-accent:#0F1216;
  --alarm:#E08272;  --alarm-soft:#2A1B18;  --alarm-mid:#8A4A3E;
  --calm:#6FBFA2;   --calm-soft:#17251F;
  --flash:#AFC6E6; --flash-peak:.40;
}

*,*::before,*::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin:0; background: var(--ground); color: var(--ink);
  font-family: var(--body); font-size:16px; line-height:1.55;
  -webkit-font-smoothing: antialiased;
}
:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }

/* ── the bar ─────────────────────────────────────────────────────────────── */

.bar {
  position: sticky; top: env(safe-area-inset-top, 0px); z-index:20;
  display:flex; align-items:center; justify-content:space-between; gap:16px;
  padding:0 20px; height:54px;
  background: var(--surface); border-bottom:1px solid var(--rule);
}
.mark {
  font-family: var(--display); font-weight:700; font-size:14.5px;
  letter-spacing:-0.01em; color: var(--ink); text-decoration:none;
}
.rail { display:flex; gap:22px; margin:0; padding:0; list-style:none; }
.rail li {
  display:flex; align-items:center; gap:7px;
  font-family: var(--mono); font-size:11px; letter-spacing:.1em;
  text-transform:uppercase; color: var(--ink-3);
}
.rail b {
  display:grid; place-items:center; width:18px; height:18px; font-weight:500;
  border:1px solid var(--rule-strong); border-radius:50%; font-size:10px;
}
/* The rail reads the stage the server rendered rather than being told which step
   it is on, so there is no second copy of "where the run is" to go stale
   (AX-OVK-00077, AX-OVK-00091).

   Scoped from BODY, not from main. The rail is in the header, which is main's
   SIBLING, so `main:has(...) .rail--1` asked for a .rail--1 inside main and
   there has never been one — the current step has never been marked on any of
   the three stages. body:has() is the same read of the same server-rendered
   class, from the one element that contains both the bar and the stage.

   Not the OUTGOING stage, though. During an outerHTML swap the leaving section
   still carries its own stage class while the arriving one is already in the
   document, so for the length of the exit body:has() is true for both and the
   rail lights two steps at once. htmx marks the leaving node .htmx-swapping,
   which is the only thing in the page that distinguishes them. */
body:has(.stage--content:not(.htmx-swapping)) .rail--1,
body:has(.stage--asking:not(.htmx-swapping))  .rail--2,
body:has(.stage--result:not(.htmx-swapping))  .rail--3 { color: var(--ink); }
body:has(.stage--content:not(.htmx-swapping)) .rail--1 b,
body:has(.stage--asking:not(.htmx-swapping))  .rail--2 b,
body:has(.stage--result:not(.htmx-swapping))  .rail--3 b {
  background: var(--accent); border-color: var(--accent); color: var(--on-accent);
}
/* The steps behind you are done, not pending: dimmer than the one you are on,
   brighter than the ones you have not reached, so the rail reads as a position
   in a sequence rather than one lit item among three identical ones. */
body:has(.stage--asking) .rail--1,
body:has(.stage--result) .rail--1,
body:has(.stage--result) .rail--2 { color: var(--ink-2); }
body:has(.stage--asking) .rail--1 b,
body:has(.stage--result) .rail--1 b,
body:has(.stage--result) .rail--2 b {
  background:none; border-color: var(--ink-3); color: var(--ink-2);
}

/* No centred column anywhere. main is the screen; each stage owns its own
   gutter and fills the deck it is given. Prose still carries a measure in ch —
   full bleed is a layout decision and not a licence for 160-character lines. */
main { max-width:none; margin:0; padding:0; }
.stage { min-height: var(--deck); }
.gone { padding: clamp(60px,14vh,140px) var(--gutter); }

/* ── type ────────────────────────────────────────────────────────────────── */

.eyebrow {
  font-family: var(--mono); font-size:10.5px; text-transform:uppercase;
  letter-spacing:.16em; color: var(--ink-3); margin:0 0 14px;
}
h1 {
  font-family: var(--display); font-weight:700; font-size:clamp(29px,4.4vw,43px);
  line-height:1.1; letter-spacing:-0.025em; margin:0 0 18px; text-wrap:balance;
}
.lede { font-size:18px; line-height:1.55; color: var(--ink-2); margin:0 0 30px; max-width:56ch; }
.hint { font-family: var(--body); font-size:13.5px; color: var(--ink-3); margin:10px 0 0; max-width:52ch; }

.notice {
  margin:0 0 22px; padding:12px 15px; font-size:15px; color: var(--ink);
  background: var(--accent-soft); border-left:3px solid var(--accent);
}
.gone { padding:40px 0; font-size:17px; color: var(--ink-2); }

/* ── stage 1: the entry ─────────────────────────────────────────────────────
   What the tool is down one side, the box you put the text in down the other.
   Both are on screen at once at any size worth calling a desk. */

.stage--content {
  /* SAFE centre. Plain `center` distributes the overflow to BOTH ends when the
     content is taller than the deck, and the half that goes above the container
     cannot be scrolled back to — the top of the form ends up out of reach on any
     laptop-height window. `safe` falls back to start exactly when that happens. */
  display:grid; align-content:safe center;
  padding: clamp(22px,3.4vh,60px) var(--gutter);
}
/* ONE column, centred on the page: what the tool is on top, the box you put the
   text in underneath. Side by side, the two halves could carry their own widths
   because nothing lined them up. Stacked, they cannot — the eye reads a centred
   column off its LEFT EDGE, not off its midpoint, so two different measures on
   the same axis read as a mistake even when both are centred. They share one. */
.col {
  display:grid; grid-template-columns: minmax(0, 72ch); justify-content:center;
  gap: clamp(26px,3.6vh,52px); align-items:start; width:100%;
}
/* The column is centred; the words inside it are not. Prose and a two-term
   table are read down a straight left edge, and centring them would trade that
   for symmetry the page does not need. */
.pitch, .give { max-width:none; }

/* The box you put the text in is built like every other surface the tool shows
   you: one hairline box on --surface, a mono label strip across the top, the
   content inside it. Same as the readout and the aggregate tables, so the page
   the officer types into and the page they read back are the same object. */
.entry {
  display:flex; flex-direction:column;
  background: var(--surface); border:1px solid var(--rule); border-radius:2px;
}
.entry:focus-within { border-color: var(--accent); box-shadow:0 0 0 3px var(--accent-soft); }
/* Sized so the whole stacked column FITS a laptop deck. Side by side, the box
   could take a third of the viewport on its own because the pitch was beside it
   rather than above it; stacked, every pixel here is a pixel the page has to
   scroll, and a centred layout that does not fit is not centred — align-content
   falls back to start and the Run button goes under the fold. It still opens on
   roughly six lines and grows with the window. */
.give .entry textarea { min-height: clamp(150px, 20vh, 320px); }


.entry > input[type="radio"] { position:absolute; opacity:0; pointer-events:none; }
.tabs {
  display:flex; gap:0; margin:0;
  background: var(--sunk); border-bottom:1px solid var(--rule);
}
.tabs label {
  font-family: var(--mono); font-size:10.5px; text-transform:uppercase;
  letter-spacing:.11em; color: var(--ink-3); cursor:pointer;
  padding:13px 17px; border-right:1px solid var(--rule);
  border-bottom:1px solid transparent; margin-bottom:-1px;
}
.tabs label:hover { color: var(--ink-2); }
#src-text:checked ~ .tabs label[for="src-text"],
#src-link:checked ~ .tabs label[for="src-link"] {
  color: var(--ink); background: var(--surface); border-bottom-color: var(--surface);
}
.pane { padding:17px 19px 0; }
#src-text:not(:checked) ~ .pane--text, #src-link:not(:checked) ~ .pane--link { display:none; }

textarea, input[type="url"] {
  width:100%; display:block; font-family: var(--body); font-size:16.5px;
  line-height:1.62; color: var(--ink); background: var(--surface);
  border:1px solid var(--rule); border-radius:2px; padding:17px 18px;
  resize:vertical;
}
input[type="url"] { font-family: var(--mono); font-size:14px; }
textarea:focus, input[type="url"]:focus { outline:none; border-color: var(--accent); box-shadow:0 0 0 3px var(--accent-soft); }
/* Inside the capture panel the box IS the border, so the field does not draw a
   second one and the focus ring lands on the panel (:focus-within above). */
.entry textarea, .entry input[type="url"] {
  border:0; border-radius:0; padding:0; background:none;
}
.entry textarea:focus, .entry input[type="url"]:focus { box-shadow:none; }
.entry .hint { padding-bottom:2px; }

button {
  margin-top:18px; font-family: var(--display); font-weight:600; font-size:14px;
  letter-spacing:.015em; color: var(--on-accent); background: var(--accent);
  border:1px solid var(--accent); border-radius:2px; padding:12px 22px; cursor:pointer;
}
button:hover { filter:brightness(1.08); }
.entry button { margin:17px 19px 19px; align-self:stretch; padding:15px 22px; font-size:15px; }
button.htmx-request { opacity:.55; pointer-events:none; }

/* Same hairline grid, same mono label column, as the readout and both aggregate
   tables. Three surfaces on this tool state a label against a value and they all
   now state it the same way. */
.facts {
  margin: clamp(22px,3.2vh,40px) 0 0;
  background: var(--surface); border:1px solid var(--rule); border-radius:2px;
}
.facts > div {
  display:grid; grid-template-columns:minmax(108px,26%) 1fr;
  border-bottom:1px solid var(--rule);
}
.facts > div:last-child { border-bottom:0; }
.facts dt {
  padding:14px 15px; background: var(--sunk);
  font-family: var(--mono); font-size:10.5px; text-transform:uppercase;
  letter-spacing:.11em; color: var(--ink-3);
}
.facts dd { margin:0; padding:14px 16px; font-size:14.5px; line-height:1.5; color: var(--ink-2); }

/* ── stage 2: the panel being asked ──────────────────────────────────────────
   It owns the whole screen for exactly as long as nobody has answered
   (AX-OVK-00091), so it breaks out of main's measure: a panel shown inside a
   1180px column is a picture of the panel, not the panel. */

.stage--asking {
  display:grid; grid-template-rows:auto minmax(0,1fr) auto;
  gap: clamp(12px, 2.2vh, 26px);
  padding: clamp(22px,4.5vh,52px) var(--gutter) clamp(16px,2.6vh,30px);
}
.asking-copy { width:100%; max-width:66ch; margin:0 auto; text-align:center; }
.asking-copy .eyebrow { justify-content:center; }
.asking-copy h1 {
  font-family: var(--display); font-weight:700; letter-spacing:-0.022em;
  font-size: clamp(27px, 3.3vw, 45px); line-height:1.07; margin:7px 0 11px;
}
.asking-copy .lede {
  margin:0 auto; max-width:58ch; color: var(--ink-2);
  font-size: clamp(15px, .55vw + 13px, 18.5px); line-height:1.5;
}
/* The roster reading itself out. One seat at a time and legible as it lands,
   which is the standard the replies are held to (AX-OVK-00089). */
.seating {
  display:flex; align-items:baseline; justify-content:center; gap:12px;
  flex-wrap:wrap; margin:20px 0 0;
  font-family: var(--mono); font-size:11.5px; letter-spacing:.06em;
  text-transform:uppercase; color: var(--ink-3);
}
.seating .count {
  font-family: var(--display); font-weight:700;
  font-size: calc(var(--fig) * .62); line-height:1;
  letter-spacing:-0.035em; font-variant-numeric: tabular-nums;
  color: var(--accent); margin-right:2px;
}
.seat-line {
  min-width:24ch; text-align:left; letter-spacing:.05em;
  color: var(--ink-2); text-transform:none;
  border-left:2px solid var(--rule-strong); padding-left:11px;
}
.seat-line[data-lang="Russian"] { border-left-color: var(--calm); }
.seat-line[data-lang="Estonian"] { border-left-color: var(--accent); }

/* The stratum being seated, and the mix as it builds. The two colours here are
   the two colours on the points and they mean the same thing in both places. */
.strata {
  display:flex; align-items:baseline; justify-content:center; gap:clamp(14px,2vw,34px);
  flex-wrap:wrap; margin:14px 0 0;
}
.district {
  font-family: var(--display); font-weight:700;
  font-size: clamp(19px, 1.5vw + 10px, 30px); letter-spacing:-0.02em; color: var(--ink);
  min-width:11ch;
}
.mix { display:flex; gap:16px; align-items:baseline; }
.mix b {
  font-family: var(--mono); font-size:11px; font-weight:400;
  letter-spacing:.08em; text-transform:uppercase; color: var(--ink-3);
  display:flex; align-items:baseline; gap:6px;
}
.mix b::before { content:""; width:9px; height:9px; border-radius:50%; align-self:center; }
.mix--et::before { background: var(--accent); }
.mix--ru::before { background: var(--calm); }
.mix span {
  font-family: var(--display); font-weight:700; font-size:20px;
  letter-spacing:-0.02em; font-variant-numeric: tabular-nums; color: var(--ink);
}

/* The axes, so the box is a reading and not a shape. */
.axes {
  position:absolute; left:0; bottom:0; z-index:1;
  display:flex; flex-wrap:wrap; gap:3px 18px; margin:0; padding:0; list-style:none;
  font-family: var(--mono); font-size:10.5px; letter-spacing:.09em;
  text-transform:uppercase; color: var(--ink-3);
}
.axes b { font-weight:500; color: var(--accent); margin-right:5px; }
.axes-box { flex-basis:100%; color: var(--ink-3); opacity:.72; letter-spacing:.05em; }

.asking-note {
  margin:15px auto 0; font-family: var(--mono); font-size:11.5px;
  letter-spacing:.06em; text-transform:uppercase; color: var(--ink-3);
}
/* The one element on stage 2 that answers "is this thing still going". It is
   deliberately larger than the note it sits under: the same figure at 11.5px in
   small caps read as part of the sentence and nobody saw it move. Tabular
   figures so the digits do not shuffle sideways each second. */
.deliberating {
  display:flex; align-items:center; justify-content:center; gap:10px;
  margin:18px auto 0; font-family: var(--mono); color: var(--ink-2);
}
.deliberating-word {
  font-size:12px; letter-spacing:.14em; text-transform:uppercase;
}
.deliberating-clock {
  font-size:20px; font-weight:500; color: var(--ink);
  font-variant-numeric: tabular-nums; letter-spacing:.02em;
}
.deliberating-dot {
  width:8px; height:8px; border-radius:50%; background: var(--accent);
  animation: deliberating-pulse 1.6s ease-in-out infinite;
}
@keyframes deliberating-pulse {
  0%, 100% { opacity:.25; transform:scale(.8); }
  50%      { opacity:1;   transform:scale(1.15); }
}
/* Motion here is the point, not decoration, so when it is not wanted the dot
   holds steady rather than disappearing — the state is still legible. */
@media (prefers-reduced-motion: reduce) {
  .deliberating-dot { animation:none; opacity:.9; }
}
/* The canvas takes whatever is left, which on a laptop is most of the screen.
   The cloud has to be big enough that a pile-up in the middle of the box is
   visible rather than inferred — that is the whole test AX-OVK-00083 sets. */
.asking-cloud { position:relative; min-height:0; }
.asking-cloud canvas { position:absolute; inset:0; width:100%; height:100%; display:block; }
.asking-watch {
  margin:0 auto; max-width:64ch; padding-top:13px; text-align:center;
  border-top:1px solid var(--rule);
  font-family: var(--mono); font-size:11px; line-height:1.6; color: var(--ink-3);
}

/* ── between the stages ──────────────────────────────────────────────────────
   One transition out and one transition in at every boundary, never a cut
   (AX-OVK-00091). The stage is named so only the stage animates; everything
   around it is identical across the swap and stays put. Browsers without view
   transitions swap plainly, which is a downgrade and not a break. */

#stage { view-transition-name: stage; }
::view-transition-old(stage) { animation: stage-out 300ms cubic-bezier(.4,0,1,1) both; }
::view-transition-new(stage) { animation: stage-in 520ms cubic-bezier(.2,.8,.22,1) 90ms both; }
@keyframes stage-out { to { opacity:0; transform: translateY(-12px) scale(.992); } }
@keyframes stage-in { from { opacity:0; transform: translateY(18px) scale(.996); } }

/* One frame of light when the readout lands, marking one real event — the run
   freezing — and fired by nothing else (AX-OVK-00089). */
.flash {
  position:fixed; inset:0; z-index:200; pointer-events:none;
  background: var(--flash); opacity:0;
  animation: flash 560ms cubic-bezier(.1,.62,.3,1) both;
}
@keyframes flash {
  0% { opacity:0; }
  11% { opacity: var(--flash-peak); }
  100% { opacity:0; }
}
/* The handoff out of stage 2 is no longer marked on arrival: stage 2 animates
   out instead (compose.js exit()), and one boundary gets one transition. The
   .flash--white variant that covered the cut is gone with it; .flash itself
   stays, for the end-of-run mark it was always also for. */

/* ── stage 3: the band ────────────────────────────────────────────────────── */

.band {
  position:relative; height:272px; margin-top:26px; overflow:hidden;
  background: var(--sunk); border:1px solid var(--rule); border-radius:2px;
  transition: height 900ms cubic-bezier(.22,.7,.2,1);
}
/* height:100% is doing real work here, not tidying up. A canvas is a REPLACED
   element, and for those `height:auto` resolves to the INTRINSIC height — the
   buffer's own height attribute — with `bottom` ignored rather than used to
   size it (CSS 2.1 §10.6.5). So top:0/bottom:0 never set this height. The
   buffer did, and resize() sets the buffer from clientHeight * pixelRatio,
   which is the intrinsic height it just read: every resize multiplied it.
   The canvas reached 1730px inside a 340px band, and since the band clips,
   the panel was drawn centred in a box five times too tall and only its top
   strip was ever on screen. That is the cut-off — the camera was framing the
   cloud correctly the whole time, into a viewport nobody could see most of. */
.band canvas {
  position:absolute; top:0; right:0; width:47%; height:100%; display:block;
  transition: width 900ms cubic-bezier(.22,.7,.2,1);
}
/* The run is over and the panel stays. It does not shrink to a strip and the
   heading does not fade: the finished cloud is the panel's actual shape with
   every answer in it, and that is when it is most worth looking at. It only
   gains room, because the copy beside it has one more thing to say. */
.band.settled { height:clamp(300px, 34vh, 420px); }
.band.settled canvas { width:58%; }
.band-copy {
  position:absolute; left:0; top:0; bottom:0; width:53%; z-index:1;
  display:flex; flex-direction:column; justify-content:center; gap:9px;
  padding:0 30px 0 26px; transition: opacity 400ms ease;
}
.settled-note {
  display:none; margin-top:2px;
  font-family: var(--mono); font-size:11px; line-height:1.6; color: var(--ink-3);
  padding-left:11px; border-left:2px solid var(--accent); max-width:46ch;
}
.band.settled .settled-note { display:block; }
.band.settled .note { display:none; }
.band-copy h2 {
  font-family: var(--display); font-weight:700; font-size:16px;
  letter-spacing:-0.01em; margin:0; color: var(--ink);
}
.band-copy p { margin:0; font-size:14px; line-height:1.5; color: var(--ink-2); max-width:44ch; }
.band-copy .note {
  font-family: var(--mono); font-size:11px; line-height:1.55; color: var(--ink-3);
  padding-left:11px; border-left:1px solid var(--rule-strong); max-width:46ch;
}

.progress {
  margin:0; padding:13px 2px; border-bottom:1px solid var(--rule);
  font-family: var(--mono); font-size:11.5px; letter-spacing:.06em;
  text-transform:uppercase; color: var(--ink-3);
}
.progress .count {
  font-family: var(--display); font-weight:700;
  font-size: clamp(22px, 2vw, 34px); line-height:1;
  font-variant-numeric: tabular-nums; color: var(--accent);
  letter-spacing:-0.03em; vertical-align:-2px; margin-right:1px;
}
.progress { display:flex; align-items:baseline; gap:7px; flex-wrap:wrap; }
.dots { animation: blink 1.4s steps(1) infinite; }
@keyframes blink { 0%,60%{opacity:1} 61%,100%{opacity:.25} }

/* ── stage 3: the split ───────────────────────────────────────────────────── */

.stage--result { padding: 0 var(--gutter) clamp(54px,9vh,120px); }

.split {
  display:grid; grid-template-columns:minmax(0,0.9fr) minmax(0,1.1fr);
  gap:38px; padding-top:30px; align-items:start;
}
.draft { position:sticky; top:78px; }
.draft-text {
  background: var(--surface); border:1px solid var(--rule); border-radius:2px;
  padding:22px 24px; margin-top:12px;
}
.draft-text p { margin:0 0 14px; font-size:16.5px; line-height:1.62; max-width:66ch; }
.draft-text p:last-child { margin-bottom:0; }

.zone h2 {
  font-family: var(--display); font-weight:700; font-size:19px; letter-spacing:-0.015em;
  margin:0 0 6px; display:flex; align-items:center; gap:9px;
}
.zone--tail h2::before {
  content:""; width:9px; height:9px; background: var(--alarm); flex:none;
}
.zone-note { margin:0 0 16px; font-size:13.5px; color: var(--ink-3); max-width:54ch; }
.zone > h2 + .cards { margin-top:14px; }

.cards { display:flex; flex-direction:column; gap:9px; }

.zone--queue { margin-top:34px; }
.zone--queue .zone-note { max-width:72ch; }
/* One card, one size, wherever it sits. grid-auto-rows:1fr equalises every row
   to the tallest reply in the field rather than letting each row find its own
   height, and the card is a column with its tags pushed to the floor, so the
   quote starts on the same line and the buttons end on the same line across all
   twenty-four. Nothing is truncated to achieve it: a reply is verbatim or it is
   not a reply (AX-OVK-00093), so the longest one sets the height and the rest
   carry the slack. */
.cards--queue {
  display:grid; grid-template-columns:repeat(auto-fill,minmax(290px,1fr));
  gap:10px; grid-auto-rows:1fr; align-items:stretch;
}
.cards--queue > *, .cards--tail > .card { display:flex; flex-direction:column; }
/* A floor, so the field is the height it is going to be from the first card
   rather than growing under the officer as twenty-three more land. Only a reply
   longer than this moves it, and then it moves once. */
.cards--queue > * { min-height: clamp(148px, 12vw, 196px); }
.cards > * .tags { margin-top:auto; padding-top:11px; }

.placeholder {
  display:grid; place-items:center; height:78px;
  border:1px dashed var(--rule-strong); border-radius:2px;
  font-family: var(--mono); font-size:10px; text-transform:uppercase;
  letter-spacing:.2em; color: var(--ink-3);
}

.card {
  background: var(--surface); border:1px solid var(--rule); border-radius:2px;
  border-left:3px solid color-mix(in oklab, var(--alarm) calc(var(--sev,0) * 105%), var(--rule));
  padding:13px 16px;
  animation: land calc(360ms + var(--sev,0) * 300ms) cubic-bezier(.2,.8,.22,1) both;
}
.card .who {
  margin:0 0 5px; font-family: var(--mono); font-size:10.5px;
  letter-spacing:.05em; color: var(--ink-3);
}
.card blockquote { margin:0 0 9px; font-size:16.5px; line-height:1.5; color: var(--ink); }
.card--silent { background:none; }
.card--silent blockquote { color: var(--ink-2); }
.card--tail { animation:none; border-left-width:5px; padding:16px 17px; background: var(--surface); }
.card--tail blockquote { font-size:clamp(15px,1.05vw + 7px,18px); line-height:1.45; }

.tags { display:flex; flex-wrap:wrap; gap:6px; margin:0; }
.tag {
  font-family: var(--mono); font-size:9.5px; text-transform:uppercase;
  letter-spacing:.09em; padding:3px 7px; border:1px solid var(--rule);
  border-radius:2px; color: var(--ink-3);
}
.tag--angry { color: var(--alarm); border-color: var(--alarm-mid); background: var(--alarm-soft); }
.tag--sad   { color: var(--alarm-mid); border-color: var(--alarm-mid); }
.tag--like, .tag--care { color: var(--calm); border-color: var(--calm); background: var(--calm-soft); }
/* WOULD_COMMENT, the second field of the contract (AX-OVK-00085), and the most
   decision-relevant mark on a card: the seat said it would really post this
   publicly, under its own name. So it is emphatic — full-strength ink on a
   solid border, against the muted --ink-3 every other tag sits at.

   Emphatic and COLOURLESS, though. The field says the comment will be VISIBLE,
   not that it is bad: a seat that likes the post and would post that is a good
   outcome, and a hue here would be this tag passing a verdict the field does
   not carry. The reaction beside it already holds the valence. It was accent
   blue, which on this page is also focus, the step you are on, and Estonian —
   so on an Estonian seat's card the loudest claim was drawn in the same colour
   as that seat's own language marker. */
.tag--posts { color: var(--ink); border-color: var(--ink-2); font-weight:500; }
.tag--off   { border-style:dashed; }

@keyframes land {
  0% {
    opacity:0;
    transform: translateY(calc(10px + var(--sev,0) * 20px)) scale(calc(1 - var(--sev,0) * 0.03));
    box-shadow:0 0 0 calc(var(--sev,0) * 11px) var(--alarm-soft);
  }
  60% { opacity:1; }
  100% { opacity:1; transform:none; box-shadow:0 0 0 0 transparent; }
}

/* ── the harshest five, directly above the queue (AX-OVK-00093) ──────────────
   A row of PanelRun::TAIL slots the width of the screen, all of them on screen
   from the first frame. Nothing here animates by stylesheet: the row is swapped
   whole on every tail event, and a CSS animation on .card--tail would replay on
   all five every time one arrived — five motions for one append, which is the
   undifferentiated flicker AX-OVK-00089 closes off. arrivals.js diffs the row by
   seat and gives each card the one motion it earned: arriving, moving up a
   place, or being pushed out. */

/* A rule above, to part it from the draft. NONE between it and the queue below:
   the five are the sharp end of that same list, and a divider there would draw
   them as a separate finding (AX-OVK-00093). */
.zone--tail {
  margin-top:52px; padding-top:26px;
  border-top:1px solid var(--rule-strong);
}
.zone--tail h2 { font-size:clamp(20px,1.5vw + 12px,27px); }
.zone--tail .zone-note { max-width:72ch; }
.cards--tail {
  position:relative;                 /* the origin ghosts are placed against */
  display:grid; grid-template-columns:repeat(5,minmax(0,1fr));
  gap:10px; align-items:stretch;
  counter-reset: slot;
}
.cards--tail > * { counter-increment: slot; position:relative; }

/* An EMPTY slot still counts, because it is a place held open. A FILLED one does
   not: a card's number is a rank the server computed and it is not always its
   position in the row, so it is rendered as content rather than counted here
   (AX-OVK-00096). A CSS counter can only ever say 1,2,3,4,5 — which is the
   invented order this axiom exists to stop. */
.placeholder::before {
  content: counter(slot);
  position:absolute; top:-9px; left:-1px;
  display:grid; place-items:center; width:18px; height:18px;
  font-family: var(--display); font-size:10px; font-weight:700;
  color: var(--ink-3); background: var(--ground);
  border:1px solid var(--rule-strong); border-radius:50%;
}
.cards--tail .rank {
  position:absolute; top:-9px; left:-1px; margin:0;
  display:grid; place-items:center; min-width:18px; height:18px; padding:0 4px;
  font-family: var(--display); font-size:10px; font-weight:700;
  font-variant-numeric: tabular-nums; letter-spacing:0;
  color: var(--on-accent); border:1px solid transparent; border-radius:9px;
  background: color-mix(in oklab, var(--alarm) calc(var(--sev,0) * 100%), var(--rule-strong));
}
/* Level with another of the five. Drawn as a shared place rather than a
   position: the scorer graded them the same and cannot separate them. */
.cards--tail .rank--level {
  color: var(--ink-2); background: var(--ground);
  border-color: color-mix(in oklab, var(--alarm) calc(var(--sev,0) * 100%), var(--rule-strong));
  border-style:dashed;
}

/* The same two marks, inline in the note that explains them. Built from the same
   shape as the real badge so the reader matches a glyph to a glyph rather than a
   sentence to a glyph — but on a fixed mid severity, because these two stand for
   every card and not for any one of them: the real badge takes its colour from
   that card's own --sev, and an example inheriting a severity it does not have
   would be making a claim about a reply that does not exist. */
.rank-eg {
  display:inline-grid; place-items:center; min-width:18px; height:17px; padding:0 4px;
  font-family: var(--display); font-size:10px; font-weight:700;
  font-variant-numeric: tabular-nums; letter-spacing:0; vertical-align:1px;
  color: var(--on-accent); border:1px solid transparent; border-radius:9px;
  background: var(--alarm-mid);
}
.rank-eg--level {
  color: var(--ink-2); background: var(--ground);
  border-color: var(--alarm-mid); border-style:dashed;
}

/* When five is not the whole of the harsh end. */
.cut-note {
  margin:0 0 12px; padding:9px 13px;
  border-left:3px solid var(--alarm-mid); background: var(--alarm-soft);
  font-size:13.5px; line-height:1.5; color: var(--ink); max-width:74ch;
}
.cut-note b {
  font-family: var(--display); font-weight:700; font-size:15px;
  font-variant-numeric: tabular-nums;
}
.cards--tail .placeholder { height:auto; min-height:154px; }
.cards--tail .card { display:flex; flex-direction:column; }
.cards--tail .card blockquote { flex:1 1 auto; }
.cards--tail .card .tags { margin-top:auto; }

/* A card on its way out of the five. It is the real node, re-attached over the
   slot it just lost, so what leaves the row is the reply that was actually
   displaced and not a redrawing of it. */
.card--evicted {
  position:absolute; margin:0; pointer-events:none; z-index:1;
  box-shadow:0 6px 18px rgba(0,0,0,.09);
}
.card--evicted::before { display:none; }

/* ── the readout ─────────────────────────────────────────────────────────── */

.done { margin-top:46px; border-top:2px solid var(--rule-strong); padding-top:26px; }

/* Every figure the run reports, in a box, at a size you can read across a desk.
   The gloss under each stays full size and stays attached: a big number with its
   qualification shrunk to a footnote is how "twenty-four residents said" gets
   into a press release (AX-OVK-00092). */
.readout {
  display:grid; grid-template-columns:repeat(auto-fit,minmax(clamp(220px,17vw,300px),1fr));
  gap:1px; margin:0; background: var(--rule);
  border:1px solid var(--rule); border-radius:2px; overflow:hidden;
}
.readout > div {
  display:flex; flex-direction:column; gap:2px;
  padding:18px 20px 20px; background: var(--surface);
}
.readout dt {
  font-family: var(--mono); font-size:10.5px; text-transform:uppercase;
  letter-spacing:.12em; color: var(--ink-3); margin-bottom:2px;
}
.readout dd { margin:0; }
.readout dd:not(.gloss), .fig {
  display:block;
  font-family: var(--display); font-weight:700;
  font-size: var(--fig); line-height:1.02;
  letter-spacing:-0.045em; font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.readout .of, .fig .of {
  font-size:.3em; font-weight:600; letter-spacing:-0.01em; color: var(--ink-3);
  font-variant-numeric: normal; white-space:nowrap;
}
/* Who the sharpest reactions came from. Still numbers, so still big — just more
   than one of them. */
.readout .tally { display:flex; flex-wrap:wrap; gap:4px 18px; align-items:baseline; }
.readout .tally-item { font-size:15px; font-weight:600; color: var(--ink-3); letter-spacing:0; }
.readout .tally-item b {
  font-size: calc(var(--fig) * .8); font-weight:700; letter-spacing:-0.04em;
  color: var(--ink); font-variant-numeric: tabular-nums; margin-right:3px;
}
.readout .gloss {
  margin-top:11px; font-size:13.5px; line-height:1.5; color: var(--ink-2);
  max-width:40ch;
}
.nothing {
  margin:30px 0 0; padding-left:16px; border-left:2px solid var(--rule-strong);
  font-size:15px; line-height:1.6; color: var(--ink-2); max-width:64ch;
}

/* ── narrow ──────────────────────────────────────────────────────────────── */

@media (max-width: 1040px) {
  .cards--tail { grid-template-columns:repeat(2,minmax(0,1fr)); }
  .cards--tail .placeholder { min-height:110px; }
}
@media (max-width: 900px) {
  /* Nothing to unstack any more — the column stacks at every width now. All a
     narrow screen needs is to stop reserving a measure it does not have. */
  .col { grid-template-columns:minmax(0,1fr); gap:26px; }
  .give .entry textarea { min-height:clamp(170px,26vh,300px); }
  .split { grid-template-columns:1fr; gap:30px; }
  .zone--margin { margin-top:6px; }
  .draft { position:static; }
  .band { height:200px; }
  .band.settled { height:clamp(260px,40vh,340px); }
}
@media (max-width: 620px) {
  .cards--tail { grid-template-columns:minmax(0,1fr); }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration:1ms !important; transition-duration:1ms !important; }
}

/* ── stage 3: the draft you can still change ──────────────────────────────── */

.draft-form textarea {
  margin-top:12px; font-size:16.5px; line-height:1.62;
  background: var(--surface); border:1px solid var(--rule);
}
.stale:empty { display:none; }
.stale {
  margin-top:14px; padding:14px 16px;
  background: var(--alarm-soft); border-left:3px solid var(--alarm);
}
.stale p { margin:0 0 12px; font-size:14.5px; line-height:1.5; color: var(--ink); }
.stale button { margin:0; font-size:13px; padding:9px 16px; }
.lineage { margin:12px 0 0; font-size:13px; color: var(--ink-3); }
.lineage a { color: var(--accent); }

.card--dropped { border-left:3px dashed var(--rule-strong); background:none; }
.card--dropped .drop { margin:4px 0 0; font-size:13.5px; line-height:1.5; color: var(--ink-3); }
.card--dropped .drop span { font-family: var(--mono); font-size:11.5px; }

.dropped-note {
  margin:24px 0 0; padding:12px 15px; font-size:14px; line-height:1.55;
  color: var(--ink-2); border-left:2px dashed var(--rule-strong);
}
.readout dd.small {
  font-family: var(--display); font-weight:700; font-size:19px; letter-spacing:-0.01em;
  line-height:1.25;
}

/* ── The anchor, the margin and translation (AX-OVK-00085, AX-OVK-00081) ───────
   The quote is the persona's own words about which line they caught on, so it is
   set in the draft's own serif rather than the interface font: it is the
   officer's sentence coming back to them, not a label the system applied. */

.anchor {
  margin:0 0 9px; padding-left:10px;
  border-left:2px solid var(--rule);
  font-size:13.5px; line-height:1.5; color: var(--ink-2);
}
.anchor-label {
  display:block;
  font-family: var(--display); font-size:10.5px; font-weight:600;
  letter-spacing:.07em; text-transform:uppercase; color: var(--ink-3);
}
.anchor q { font-style:italic; }
.anchor q::before, .anchor q::after { content:""; }

.translate {
  margin-left:auto;
  padding:2px 9px;
  font-family: var(--display); font-size:11px; font-weight:600; letter-spacing:.04em;
  color: var(--ink-3); background:none;
  border:1px solid var(--rule); border-radius:999px;
  cursor:pointer;
}
.translate:hover { color: var(--accent); border-color: var(--accent); }
.translate[disabled] { opacity:.5; cursor:progress; }

.translation:empty { display:none; }
.translated {
  margin:9px 0 0; padding:8px 10px;
  font-size:14.5px; line-height:1.5; color: var(--ink-2);
  background: var(--sunk); border-radius:4px;
}
.translated-label {
  display:block;
  font-family: var(--display); font-size:10px; font-weight:600;
  letter-spacing:.07em; text-transform:uppercase; color: var(--ink-3);
}
.translated--failed { color: var(--alarm); }

/* The margin surface. One row per sentence of the draft; the marks sit to the
   right of the line they belong to, which is what makes it a margin rather than
   a second list of reactions. */
.zone--margin { margin-top:0; }
.zone--margin h3 {
  margin:0 0 4px;
  font-family: var(--display); font-size:12px; font-weight:700;
  letter-spacing:.08em; text-transform:uppercase; color: var(--ink-2);
}

.margin { margin:12px 0 0; padding:0; list-style:none; }
.margin .line {
  display:grid; grid-template-columns:1fr auto; gap:10px; align-items:start;
  padding:8px 0 8px 10px;
  border-left:3px solid var(--rule);
  border-bottom:1px solid var(--rule);
}
.margin .line:last-child { border-bottom:none; }
.margin .line--hit {
  border-left-color: color-mix(in oklab, var(--alarm) calc(var(--worst,0) * 100%), var(--rule));
}
.margin .sentence { margin:0; font-size:15px; line-height:1.5; color: var(--ink); max-width:74ch; }
.margin .marks {
  display:flex; flex-wrap:wrap; gap:3px; align-items:center;
  margin:2px 0 0; justify-content:flex-end; max-width:15ch;
}
.margin .marks--none {
  margin:2px 0 0;
  font-family: var(--display); font-size:10.5px; letter-spacing:.04em;
  color: var(--ink-3); white-space:nowrap;
}
.margin .mark {
  width:9px; height:9px; border-radius:50%;
  background: color-mix(in oklab, var(--alarm) calc(var(--sev,0) * 100%), var(--rule-strong));
}
.margin .mark.tag--like, .margin .mark.tag--care, .margin .mark.tag--love {
  background: var(--calm);
}
.margin .n {
  margin-left:4px;
  font-family: var(--display); font-size:10.5px; font-weight:600;
  letter-spacing:.04em; color: var(--ink-3); white-space:nowrap;
}

/* ── The aggregates, and they come last (AX-OVK-00079, AX-OVK-00081) ──────────
   Everything here is below the voices. Nothing in this block may be moved above
   them: a number read first becomes the thing the officer remembers, and every
   figure here summarises people they have not read yet. */

.aggregates {
  margin:34px 0 0; padding-top:22px;
  border-top:1px solid var(--rule-strong);
}
.aggregates > h2 {
  margin:0 0 20px;
  font-family: var(--display); font-size:13px; font-weight:700;
  letter-spacing:.09em; text-transform:uppercase; color: var(--ink-2);
}
.agg { margin:0 0 44px; }
.agg h3 {
  margin:0 0 5px;
  font-family: var(--display); font-size:17px; font-weight:700;
  letter-spacing:-0.01em; color: var(--ink);
}

.grid-figure, .rounds-figure { margin:14px 0 10px; }
.fig-label {
  font-family: var(--display); font-size:10px; font-weight:600;
  letter-spacing:.05em; fill: var(--ink-3);
}
.fig-value { font-family: var(--mono); font-size:15px; }
.fig-sub   { font-family: var(--display); font-size:9px; letter-spacing:.03em; }

.rounds-figure { display:flex; flex-wrap:wrap; gap:16px; }
.multiple { flex:0 0 156px; }
.multiple--reported .multiple-title { color: var(--ink); }
.multiple-title {
  margin:0 0 2px;
  font-family: var(--display); font-size:10.5px; font-weight:600;
  letter-spacing:.05em; text-transform:uppercase; color: var(--ink-3);
}
.multiple-note {
  margin:2px 0 0;
  font-family: var(--mono); font-size:10.5px; line-height:1.45; color: var(--ink-3);
}

/* The tables are the fallback AND the truth: d3 draws from the same JSON they
   were rendered from, so if the two ever disagree the table is right. They are
   drawn as the same hairline grid of boxes as the readout, with the figure at
   the same size, because a number is not less of a number for being an
   aggregate — it is only further down the page (AX-OVK-00093). */
.grid-table, .rounds-table {
  width:100%; margin:14px 0 0;
  border-collapse:collapse;
  border:1px solid var(--rule); border-radius:2px;
  background: var(--surface);
  overflow:hidden;
}
.grid-table caption, .rounds-table caption {
  margin-bottom:8px;
  font-family: var(--mono); font-size:10.5px; letter-spacing:.06em;
  text-transform:uppercase; color: var(--ink-3); text-align:left;
}
.grid-table th, .grid-table td, .rounds-table th, .rounds-table td {
  padding:15px 18px 17px; border:1px solid var(--rule);
  text-align:left; vertical-align:top;
}
/* The label column and the header row are labels, not figures. */
.grid-table thead th, .rounds-table thead th,
.grid-table tbody th, .rounds-table tbody th {
  font-family: var(--mono); font-size:10.5px; font-weight:400;
  letter-spacing:.11em; text-transform:uppercase; color: var(--ink-3);
  background: var(--sunk); white-space:nowrap;
}
.grid-table tbody th, .rounds-table tbody th {
  vertical-align:middle; color: var(--ink-2); font-size:11px;
}
/* The scale the figure sits on, drawn under the figure. Brick is spent here and
   this is the one other place it is allowed: this IS severity, which is what it
   is reserved for. */
.fig-scale {
  display:block; position:relative; height:5px; margin-top:10px; max-width:220px;
  background: var(--sunk); border:1px solid var(--rule); border-radius:3px;
  overflow:hidden;
}
.fig-scale i {
  position:absolute; left:0; top:0; bottom:0; display:block;
  width: calc(var(--sev,0) * 100%);
  background: color-mix(in oklab, var(--alarm) calc(var(--sev,0) * 100%), var(--accent));
}

/* A cell says one person, so it is laid out like one: what they pressed, who
   they are, and where that sits against everyone else. */
.cell-tags { display:flex; flex-wrap:wrap; gap:6px; margin:0 0 9px; }
.cell-tags .tag { font-size:11px; letter-spacing:.07em; padding:5px 9px; }
.cell-who {
  margin:0; font-family: var(--display); font-weight:700;
  font-size: clamp(18px, 1.1vw + 10px, 26px); letter-spacing:-0.02em; color: var(--ink);
}

.scale-note {
  margin:14px 0 0; padding-left:14px; border-left:2px solid var(--rule-strong);
  font-size:13.5px; line-height:1.55; color: var(--ink-2); max-width:70ch;
}
.scale-note b {
  font-family: var(--mono); font-weight:500; font-size:12.5px; color: var(--ink);
}

.fig-note, .fig-refused {
  display:block; margin-top:7px;
  font-family: var(--mono); font-size:11px; line-height:1.45;
  letter-spacing:.02em; color: var(--ink-3);
}
/* A cell the panel refused to colour. It says so at the size of a sentence,
   not at the size of a number it does not have. */
.fig-refused {
  margin-top:0; font-family: var(--body); font-size:13.5px;
  font-style:italic; color: var(--ink-3); max-width:30ch;
}
.round--reported th { color: var(--ink); }

.round--reported td .fig { color: var(--accent); }

.rounds-note {
  font-family: var(--display); font-size:10.5px; letter-spacing:.04em; color: var(--ink-3);
}

/* A refusal, not a caution. Two numbers side by side with a warning under them
   are read as roughly comparable, which is the one thing they are not. */
.incomparable {
  display:block; margin-top:6px; padding:7px 9px;
  border-left:3px solid var(--alarm); background: var(--alarm-soft);
  font-size:13px; line-height:1.5; color: var(--ink);
}

.no-margin {
  margin:22px 0 0; padding:10px 12px;
  background: var(--sunk); border-radius:4px;
  font-size:13px; line-height:1.55; color: var(--ink-2); max-width:62ch;
}

@media (max-width: 720px) {
  .rounds-figure { gap:12px; }
  .multiple { flex:0 0 132px; }
}

/* ── how it landed: the reaction mix ──────────────────────────────────────── */

/* The readout's figures, made proportional. Every colour here is the colour that
   reaction already wears on a card, so a band of red in this bar and an ANGRY
   chip three screens up are the same statement in the same ink — the bar teaches
   nothing new, it just lets the eye count.

   No green-amber-red, and no hue for "would post". The scale runs from the
   alarm end to the calm end because that is how the reactions themselves are
   valenced (EngagementScore::REACTION_VALENCE), not because one end is a
   recommendation. AX-OVK-00080 closes the traffic light by name. */
.landed { margin:0 0 18px; }
.landed-bar {
  display:flex; gap:2px; height:28px; margin-bottom:10px;
  border-radius:2px; overflow:hidden;
}
.landed-seg { display:block; min-width:3px; background: var(--rule-strong); }
.landed--angry { background: var(--alarm); }
.landed--sad   { background: var(--alarm-mid); }
.landed--wow, .landed--haha, .landed--none { background: var(--rule-strong); }
.landed--love, .landed--like, .landed--care { background: var(--calm); }
/* Dropped is not a quiet opinion, so it is not drawn as one: hatched rather than
   filled, because nobody knows what these seats would have said. */
.landed--dropped {
  background: repeating-linear-gradient(135deg,
    var(--rule-strong) 0 3px, transparent 3px 7px);
}

.landed-key { display:flex; flex-wrap:wrap; gap:4px 16px; margin:0 0 6px; }
.landed-item {
  display:inline-flex; align-items:center; gap:6px;
  font-family: var(--mono); font-size:10.5px; text-transform:uppercase;
  letter-spacing:.09em; color: var(--ink-3);
}
.landed-item i { width:9px; height:9px; border-radius:2px; flex:none; }
.landed-item b { font-weight:600; color: var(--ink); font-size:12px; letter-spacing:0; }
.landed-note {
  margin:0; font-family: var(--mono); font-size:10.5px; line-height:1.6;
  color: var(--ink-3); max-width:70ch;
}

/* ── the standing actions in the bar ──────────────────────────────────────── */

.bar-left, .bar-right { display:flex; align-items:center; gap:clamp(14px,2vw,28px); }
.bar-left { gap:clamp(12px,1.6vw,22px); }
.bar-actions { display:flex; align-items:center; gap:10px; }

/* Small, quiet, and not competing with "Run the panel" on stage 1 or with
   anything in the result. These are a way back and a way round, not the thing
   the page is for. */
.bar-run, .bar-new {
  font-family: var(--mono); font-size:10.5px; text-transform:uppercase;
  letter-spacing:.09em; line-height:1; white-space:nowrap;
  padding:7px 11px; border-radius:2px; border:1px solid var(--rule-strong);
  background:none; color: var(--ink-2); text-decoration:none; cursor:pointer;
}
.bar-run:hover, .bar-new:hover { color: var(--ink); border-color: var(--ink-2); }
.bar-run { border-color: var(--ink-2); color: var(--ink); }
/* The call to action, and the loud one of the two. Accent fill is the page's
   established "this is the button" — the same treatment Run the panel wears on
   stage 1 — so it reads as an action rather than as another label in a bar full
   of them. */
.bar-new {
  background: var(--accent); color: var(--on-accent); border-color: var(--accent);
  font-weight:600; padding:7px 13px;
}
.bar-new:hover { color: var(--on-accent); border-color: var(--accent); filter:brightness(1.08); }

/* The pulse marks an EVENT and then stops: the result has landed, and there is
   a next thing to do. Three beats, then it rests.

   Bounded on purpose. AX-OVK-00089 closes decorative animation unconnected to
   the run, and a CTA pulsing forever is exactly that — motion that means
   nothing, on a page the officer is trying to read four screens of. It is also
   why the pulse is hung off the stage-3 rule and not off the element: the beat
   starts when the result arrives, not while the panel is still answering, where
   it would be pulling the eye off the run to advertise leaving it. */
@keyframes cta-pulse {
  0%   { box-shadow:0 0 0 0 var(--accent); }
  70%  { box-shadow:0 0 0 8px transparent; }
  100% { box-shadow:0 0 0 0 transparent; }
}
body:has(#rerun) .bar-new { animation: cta-pulse 1.6s cubic-bezier(.3,.7,.4,1) 3; }

/* ONE slot, and what is in it is whatever this stage can actually offer.
   Both elements are always in the markup and at most one is ever shown:

     stage 1  nothing — the form's own "Run the panel" is on the screen already,
              and a second run button beside it would be two ways to do one thing
     stage 2  "Start again" — the only thing left to do while the panel answers
     stage 3  "Run it again" — submits the draft box, edited or not

   Neither rule names a stage directly. The re-run button asks whether the form
   it points at is on the page; the other asks the body which stage the server
   rendered. That keeps the bar from holding a second opinion about where the
   run is, which is the thing AX-OVK-00077 is about.

   :not(.htmx-swapping) is not decoration. During an outerHTML swap the leaving
   stage is still in the document while the arriving one is already there, so
   for the length of the exit BOTH conditions hold and one slot would show two
   buttons. htmx marks the leaving node; the rail needed the same guard. */
.bar-run, .bar-new { display:none; }
/* Stage 2 can only be left. Stage 3 can be left OR run again, and both belong
   there: "run it again" is the same draft one more time, "start new" is a
   different post entirely, and after reading a result the officer is doing one
   or the other. They are ordered and weighted so the pair cannot be misread —
   the loop the tool is for reads as the action, leaving reads as the way out. */
body:has(.stage--asking:not(.htmx-swapping)) .bar-new,
body:has(#rerun) .bar-new { display:inline-block; }
body:has(#rerun) .bar-run { display:inline-block; }

@media (max-width: 900px) {
  /* The rail is the first thing to go: it says where you are, and the actions
     say what you can do, which is worth more on a narrow bar. */
  .bar .rail { display:none; }
}

@media (prefers-reduced-motion: reduce) {
  .bar-new { animation:none !important; }
}

/* ── a suggested edit, one line (AX-OVK-00097) ────────────────────────────── */

.ask-suggest {
  font-family: var(--mono); font-size:9.5px; text-transform:uppercase;
  letter-spacing:.09em; padding:3px 8px; margin-left:8px;
  border:1px dashed var(--rule-strong); border-radius:2px;
  background:none; color: var(--ink-3); cursor:pointer;
}
.ask-suggest:hover { color: var(--ink); border-color: var(--ink-2); border-style:solid; }
.ask-suggest.htmx-request { opacity:.5; }

.suggestion {
  margin:10px 0 4px; padding:14px 16px;
  border:1px solid var(--rule); border-left:3px solid var(--ink-2);
  border-radius:2px; background: var(--surface);
}
/* The evidence is at the top and it is not collapsible. The whole reason this
   narrow form is allowed is that the officer cannot reach the edit without
   passing what provoked it — a suggestion with its objections folded away is
   the button AX-OVK-00080 refused, wearing a disclosure triangle. */
.suggestion-why { margin:0 0 8px; font-size:13.5px; color: var(--ink-2); }
.suggestion-why b { color: var(--ink); font-weight:600; }
.suggestion-said {
  margin:0 0 12px; padding-left:16px; display:flex; flex-direction:column; gap:5px;
  font-size:14px; line-height:1.45; color: var(--ink-2);
  border-left:1px solid var(--rule-strong); list-style:none;
}
.suggestion-said li::before { content:"— "; color: var(--ink-3); }

.suggestion-was, .suggestion-new { margin:0 0 7px; font-size:15px; line-height:1.45; }
.suggestion-was span, .suggestion-new span {
  display:block; font-family: var(--mono); font-size:9.5px; text-transform:uppercase;
  letter-spacing:.09em; color: var(--ink-3); margin-bottom:2px;
}
.suggestion-was q { color: var(--ink-3); text-decoration:line-through; quotes:none; }
/* Never styled as the officer's own text: it is a proposal, in a box, marked as
   one, until they take it. */
.suggestion-new q {
  display:block; color: var(--ink); quotes:none;
  padding:8px 10px; background: var(--ground); border:1px dashed var(--ink-2);
}

.suggestion-do { display:flex; gap:8px; margin:12px 0 0; }
.suggestion .use, .suggestion .keep {
  font-family: var(--mono); font-size:10px; text-transform:uppercase;
  letter-spacing:.09em; padding:7px 12px; border-radius:2px; cursor:pointer;
  border:1px solid var(--ink-2); background:none; color: var(--ink);
}
/* "Keep mine" is a real answer, not a dismiss: it sits beside the other at the
   same size, because the honest response to a suggestion is often no. */
.suggestion .keep { border-color: var(--rule-strong); color: var(--ink-3); }
.suggestion .keep:hover { color: var(--ink); border-color: var(--ink-2); }
.suggestion .use:hover { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

.suggestion-refused, .suggestion-took {
  margin:10px 0 0; font-family: var(--mono); font-size:11px; line-height:1.6;
  color: var(--ink-3); padding-left:10px; border-left:2px solid var(--rule-strong);
}
.suggestion-took { color: var(--ink-2); border-left-color: var(--accent); }
