/* ══════════════════════════════════════════════════════════════════════
   css/recorder.css — THE RECORDER'S OWN SHEET. §ED742.

   EVERY RULE HERE WAS CUT OUT OF css/briefing.css, IN THE ORDER IT STOOD
   THERE, WITH THE COMMENT THAT STOOD ABOVE IT. Nothing was rewritten. The
   family is the one js/reader-answer.js and js/waveform.js render into:
   .ba-* and .wv / .wv-bar (js/landing-question.js adds .ba-claim). It is
   the same recorder on every page that mounts it, so it is the same sheet:
   index.html, briefing.html, record.html, archive.html, calendar.html,
   collection.html and vault.html all load THIS file, and the six app pages
   still load briefing.css AFTER it — briefing.css keeps the last word,
   exactly as briefing.html:107 already orders its own pair.

   WHY IT EXISTS. §ED721 measured briefing.css on the landing: 281,807 bytes
   loaded, 11,781 used (4.35%). The recorder rules are 26KB of the file; the
   other ~146KB is comments and ~95KB is calendar/archive/vault/page-chrome
   the landing never renders. The landing now loads this file and NOT
   briefing.css. This is the shared extraction §ED721 ruled for — NOT a
   landing-scoped copy, which would be ~12KB duplicated across two files and
   a fork the next edit forgets.

   SIX RULES WERE SHARED WITH .ra-card / .bf-* SELECTORS and are SPLIT — the
   .ba- selectors are here, the rest stayed, each half naming the other.
   scripts/audit-ed742.js §5 asserts the two halves still carry identical
   declarations, so the split cannot drift silently.

   TOKENS COME FROM css/tokens.css + css/global.css (this file declares no
   :root, exactly as briefing.css declared none) — every consumer already
   loads both before this sheet.
   ══════════════════════════════════════════════════════════════════════ */

/* ── §ED262 THE READER ANSWER SURFACE ───────────────────────────────────────
   The bf-note LOOK, deliberately: recessed well, neutral left rule, quiet
   uppercase label, calm actions. A reader should read the answer block and the
   note block as the same KIND of thing — their own words on their own card —
   because they are. What is NOT copied is bf-note's plumbing: notes are
   auth.uid()-only with a hard cap of three (119), and this surface is
   anonymous-first and uncapped, written only through a service-role function.

   NO ARCADE. No celebration, no progress bar, no fill, no tick, no badge. The
   countdown is a sentence, not a meter — R12 asks for the missing thing to be
   NAMED, and a bar would be the "1 of 3 complete" framing in graphic form.

   CONTRAST: every pair below is measured in scripts/test-ed262-reader-answer.js
   against the real token values from css/global.css, in BOTH themes, asserted
   >= 4.5:1. Nothing here is eyeballed. --text-subtle is used only where
   test-ed262 proves it clears the bar on the surface it actually sits on. */
.ba-zone { margin: 12px 0 2px; }

.ba-zone.is-busy { opacity: 0.6; pointer-events: none; }   /* in flight — never a spinner, never a message */

/* The question. First-class — it is the card speaking, not a label.
   §ED430 · Fraunces 400, matching the .ba-zone > .ba-question declaration
   below so the question does not change face if the child combinator ever
   misses (reader-answer.js always mounts it inside .ba-zone today). */
.ba-question {
  font-family: var(--font-display);
  font-size: 0.95rem; line-height: 1.45; font-weight: 400;
  color: var(--text-primary);
  margin: 0 0 10px;
}

.ba-question.is-answered-q { font-weight: 400;   /* §ED430 · ruled */ color: var(--text-muted); margin-bottom: 8px; }

/* §ED548 FOLLOW-UP — PIN THE QUESTION while a take is live (recording or
   paused). Measured live: at realistic mobile heights the question scrolled
   fully off-screen while paused. position:sticky, not fixed: it reserves its
   own height in normal flow, so nothing jumps or gets covered while it is
   NOT stuck, and it only overlaps scrolled content once actually stuck —
   which is the point of pinning it. Toggled by mountRecorder()'s setState();
   at rest and in review the class is absent and .ba-question behaves exactly
   as above. Background is handled per-variant below: the corpus path's
   `.ba-zone > .ba-question` already carries a solid lime band, the `.is-bank`
   path does not (see the §ED440 block) and needs an explicit opaque one. */
.ba-question.ba-question-pinned {
  position: sticky;
  top: 0;
  z-index: 5;
}

/* The taps. A wrapping row of quiet pills — five siblings, and the write-in is
   one of them, NOT a control set apart from them. Ratified: the write-in is a
   fifth option, and styling it as a link or a form toggle would demote it. */
.ba-options { display: flex; flex-wrap: wrap; gap: 8px; }

.ba-option {
  font-family: var(--font-body);
  font-size: 0.85rem; line-height: 1.35; font-weight: 600;
  text-align: left; cursor: pointer;
  color: var(--text-primary);
  background: var(--surface-well);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  padding: 8px 15px;
}

.ba-option:hover { border-color: var(--accent-ink); }

.ba-option:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }

/* A terminal option ("We didn't", "I don't know") is NOT dimmed or demoted.
   27-generate-question.js:280 is explicit that a reader with no counterpart is
   DONE, and that pushing them further is how invented answers happen — so the
   honest answer must not look like the lesser one. Same weight, same colour. */
.ba-option.is-terminal { }

.ba-option-writein { border-style: dashed; }

/* The inline write-in. Multi-line: a spoken answer runs to several sentences,
   and a one-line input would make speech look like the wrong way to use it. */
.ba-editor { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; }

.ba-input-row { display: flex; align-items: flex-end; gap: 8px; }

.ba-input {
  flex: 1 1 auto; width: 100%; box-sizing: border-box; resize: vertical;
  font-family: var(--font-body); font-size: 0.9rem; line-height: 1.5;
  color: var(--text-primary); background: var(--surface);
  border: 1px solid var(--border-strong); border-radius: 8px; padding: 9px 11px;
}

.ba-input::placeholder { color: var(--text-subtle); }

.ba-input:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 1px; }

/* §ED572 — the declarative half of "the writing box clears the fixed nav".
   js/reader-answer.js's clearBottomChrome() scrolls the box clear on focus by
   measuring the bar's live rect; this makes the BROWSER's own scrolling agree
   with it, so scrollIntoView(), a fragment jump, sequential focus navigation
   and a test driver's auto-scroll all stop at the same line instead of parking
   the box under the bar. --nav-bottom-h is calc(64px + var(--safe-bottom)) —
   the token, never a literal, so a notched device's taller bar is covered. */
.ba-input { scroll-margin-bottom: calc(var(--nav-bottom-h, 64px) + 12px); }

/* The mic. Present ONLY where the Web Speech API is — reader-answer.js never
   creates this node otherwise, so there is no disabled state to style and no
   "not supported" affordance to design. A reader without it sees a text box
   and no evidence anyone else got more. */
.ba-mic {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; cursor: pointer;
  color: var(--text-muted);
  background: var(--surface-well);
  border: 1px solid var(--border-strong); border-radius: 50%;
}

.ba-mic:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }

/* Held. A colour + border change, no pulse and no waveform: a live recording
   animation is theatre, and this surface promises the opposite of theatre.

   SUPERSEDED BY §ED440 PHASE E, PART 4 — and the reasoning is what changes,
   not just the verdict. "Theatre" is the right objection to the LANDING's
   waveform, which is seeded-random bars with no audio behind them (R8): a
   performance of listening. It is the wrong objection to a waveform driven by
   an AnalyserNode on the reader's own live input, because that is not a
   performance, it is the only EVIDENCE the reader gets that the microphone is
   actually hearing them. A mic button that changes colour proves the button
   was pressed. Bars that move when you speak prove the mic is on — which is
   the single most useful thing this surface can tell someone who has just
   been asked to talk about their family.
   The new treatment is in the Phase E block at the foot of this sheet. It
   never renders bars without data behind them: no analyser degrades to one
   pulsing indicator, never to invented bars. */
.ba-mic.is-live { color: var(--accent-ink); border-color: var(--accent-ink); }

.ba-mic-ic { display: inline-flex; }

/* Actions — same shapes and same words as the note editor (card.js:470/472). */
.ba-actions { display: flex; gap: 8px; align-items: center; }

.ba-save, .ba-cancel {
  font-family: var(--font-body); font-size: 0.78rem; font-weight: 600; cursor: pointer;
  border-radius: 7px; padding: 6px 14px;
}

.ba-save { border: none; background: var(--accent-ink); color: #fff; }

.ba-cancel { border: 1px solid var(--border-strong); background: transparent; color: var(--text-muted); }

.ba-save:focus-visible, .ba-cancel:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }

/* The CONFIRMED answer — echoed only after the server issued a row id. Same
   recessed well as .bf-note, so a reader's answer and a reader's note sit in
   visibly the same register. */
.ba-answer {
  padding: 9px 12px 9px 13px;
  background: var(--surface-well);
  border-left: 3px solid var(--border-strong);
  border-radius: 0 8px 8px 0;
}

.ba-answer-value {
  font-family: var(--font-body); font-size: 0.9rem; font-weight: 600; line-height: 1.45;
  color: var(--text-primary); margin: 0; overflow-wrap: break-word;
}

.ba-answer-text {
  font-family: var(--font-body); font-size: 0.9rem; line-height: 1.5;
  color: var(--text-primary); margin: 6px 0 0; overflow-wrap: break-word;
  white-space: pre-wrap;   /* VERBATIM — the reader's own line breaks survive */
}

/* The tap the reader already committed, shown while they add words to it. */
.ba-chosen {
  font-family: var(--font-body); font-size: 0.85rem; font-weight: 600;
  color: var(--text-muted); margin: 0 0 8px;
}

/* "Add words to this" — a quiet ambient trigger, exactly .bf-note-add's weight.
   It must never look like an unfinished step: the answer is already complete. */
.ba-more {
  display: inline-flex; align-items: center; margin-top: 8px;
  border: none; background: transparent; cursor: pointer;
  font-family: var(--font-body); font-size: 0.8rem; font-weight: 600;
  color: var(--text-muted); padding: 2px 0; text-decoration: underline;
}

.ba-more:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; border-radius: 4px; }

/* ── COUNTDOWN AND PAYOFF ──────────────────────────────────────────────────
   No meter, no bar, no numerals-as-score. --text-muted, not --text-subtle:
   this is the line that carries the promise, so it is read, not skimmed. */
.ba-progress { margin-top: 10px; }

.ba-countdown {
  font-family: var(--font-body); font-size: 0.8125rem; line-height: 1.45;
  color: var(--text-muted); margin: 0;
}

/* The payoff. Set apart by a rule, not by a colour flood or a card — the
   ratified line is the reward, and decorating it would cheapen it. */
.ba-progress.is-payoff {
  border-top: 1px solid var(--border-strong);
  padding-top: 10px;
}

/* §ED267 — THE SAME LINE, BEFORE THE FIRST ANSWER. It is the promise here and
   the payoff there, so it is the same words in the same face at the same size:
   a reader who reaches three must recognise the sentence they were shown at
   zero, and re-styling it would break that recognition.
   WHAT DIFFERS IS THE SEPARATOR, and only that. --border (the subtle one), not
   --border-strong: at zero this line follows the options and is part of the
   ask, so it is joined to it. At three it follows a confirmed answer and closes
   the entry, so it is ruled off. Same type, different punctuation. */
.ba-progress.is-promise {
  border-top: 1px solid var(--border);
  padding-top: 10px;
  margin-top: 12px;
}

/* §ED553 · 0.875rem (14px) → 1rem. THIS WAS A LIVE §ED440 BREACH AND IT IS
   FIXED ON BOTH SURFACES, NOT SCOPED TO THE ONE THAT FOUND IT.

   §ED440's type floor is 16px and this line sat two under it. It was invisible
   for as long as the only instrument pointed at the floor was the landing
   probe and this rule rendered only inside the app; §ED553 mounts the answer
   surface on the landing, scripts/audit-ed549.js §6 measured every element
   carrying text, and .ba-payoff @14px was the single failure.

   IT IS CHANGED IN briefing.css, SO IT CHANGES /briefing.html TOO — stated
   plainly rather than discovered later. That is deliberate: the alternative was
   a landing-only override, which would be two type ramps for one component and
   the same fork this pass refuses everywhere else. The line it governs is the
   ratified payoff ("One answer a day, kept private…"), read by exactly the
   audience the 16px floor exists for. Nothing else about the rule moves. */
.ba-payoff {
  font-family: var(--font-body); font-size: 1rem; line-height: 1.5; font-weight: 600;
  color: var(--text-primary); margin: 0;
}

/* The claim prompt rides ALONGSIDE the payoff, never in front of it: the payoff
   shows anonymously (ratified), so the account is an offer, not a toll. */
.ba-claim {
  display: inline-block; margin-top: 8px;
  font-family: var(--font-body); font-size: 0.8125rem; font-weight: 600;
  color: var(--text-primary); text-decoration: underline;
}

html.theme-light .ba-claim { color: var(--accent-ink); }   /* mirrors .bf-note-limit-link exactly */

/* Wider viewports: the options row would otherwise stretch a five-pill line
   across a full-width card and read as a toolbar. Cap it at the measure of the
   prose it belongs to. */
@media (min-width: 900px) {
  .ba-options { max-width: 34rem; }
  .ba-input-row { max-width: 34rem; }
}

/* §ED742 · SPLIT FROM A SHARED RULE. The selectors below used to share one
   declaration block with .ra-card in css/briefing.css; that half stays
   there. KEEP THE TWO DECLARATION BLOCKS IDENTICAL — scripts/audit-ed742.js
   §5 diffs them. */
.ba-zone {
  --card-pad-x: 20px;
  --card-pad-y: 18px;
  padding: var(--card-pad-y) var(--card-pad-x);
  border: 1.5px solid var(--border-strong);
  border-radius: 14px;
  overflow: hidden;
  background: var(--surface-well);
}

/* §ED742 · SPLIT FROM A SHARED RULE. The selectors below used to share one
   declaration block with html.theme-light .ra-card in css/briefing.css; that half stays
   there. KEEP THE TWO DECLARATION BLOCKS IDENTICAL — scripts/audit-ed742.js
   §5 diffs them. */
html.theme-light .ba-zone {
  background: var(--surface);
  box-shadow: var(--shadow-card);
}

/* §ED742 · SPLIT FROM A SHARED RULE. The selectors below used to share one
   declaration block with .ra-card > .ra-question in css/briefing.css; that half stays
   there. KEEP THE TWO DECLARATION BLOCKS IDENTICAL — scripts/audit-ed742.js
   §5 diffs them. */
.ba-zone > .ba-question,
.ba-zone > .ba-question.is-answered-q {
  background: var(--accent);
  color: var(--accent-text);
  margin-left: calc(var(--card-pad-x) * -1);
  margin-right: calc(var(--card-pad-x) * -1);
  padding-left: var(--card-pad-x);
  padding-right: var(--card-pad-x);
}

/* §ED742 · SPLIT FROM A SHARED RULE. The selectors below used to share one
   declaration block with .ra-card > .ra-question in css/briefing.css; that half stays
   there. KEEP THE TWO DECLARATION BLOCKS IDENTICAL — scripts/audit-ed742.js
   §5 diffs them. */
.ba-zone > .ba-question,
.ba-zone > .ba-question.is-answered-q {
  font-family: var(--font-display);
  font-size: 1.5rem;
  line-height: 1.22;
  font-weight: 400;   /* §ED430 · ruled */
  letter-spacing: -0.005em;
  font-variant-numeric: lining-nums;
}

/* /briefing's band is the question alone — it bleeds top and sides itself. */
.ba-zone > .ba-question,
.ba-zone > .ba-question.is-answered-q {
  margin-top: calc(var(--card-pad-y) * -1);
  padding-top: var(--card-pad-y);
  padding-bottom: var(--card-pad-y);
  margin-bottom: var(--card-pad-y);
}

/* .ba-zone's shipped outer margin stays; it is a nested well inside the daily
   card, not a page-level card, and this build does not restructure /briefing. */
.ba-zone { margin: 12px 0 2px; }

/* CONSEQUENCE, the §ED285 defect generalised to /briefing. §ED285 found that
   .bf-note's own background is --surface-well, which vanishes once the CARD is
   --surface-well in dark, and stepped the note up to --surface. /briefing was
   never checked for the same collision — and it has TWO of them: .ba-option
   (briefing.css:2321) and .ba-answer (briefing.css:2380) are both
   --surface-well, and both now sit on a --surface-well body in dark. Both step
   up the same way, dark only. Light needs no step: there the body is --surface
   and --surface-well is already the recessed one, so the shipped tokens are
   already correct — same two tokens either way, swapped, exactly as §ED285.
   .ba-input is already --surface and so stays legible on the dark body
   untouched; the write-in's figure is verified, not assumed. */
html:not(.theme-light) .ba-zone .ba-option,
html:not(.theme-light) .ba-zone .ba-answer {
  background: var(--surface);
}

/* ── THE QUESTION — "THE BAND" ──────────────────────────────────────────
   THE BAND IS RATIFIED SHIPPED DESIGN (§ED285, face re-ruled §ED430): the
   question sits on a full-bleed lime band, shared by /record and the Daily.
   §ED440 does NOT change it — this pass restyles, it does not redesign, and
   the band is not in its remit. See the note in
   docs/ED440-DESIGN-LANGUAGE.md flagging the band against the palette
   invariant; that tension is Jake's to rule on, not this pass's to resolve.

   WHAT IS FIXED HERE IS A SPECIFICITY BUG THIS LAYER WALKED INTO. The first
   draft styled bare `.ba-question` (0,1,0), which LOSES to the band's
   `.ba-zone > .ba-question` (0,2,0) — so every declaration in it was dead and
   the band went on reading global.css's --accent/--accent-text instead of the
   token layer. That is precisely the failure mode T1 warns about, hit inside
   the very block that documents it.
   The selector below MATCHES the band's own specificity and wins on source
   order, so the band now reads --c-* like everything else. It is a pure token
   mapping: same fill, same ink, same geometry. --c-on-accent on --c-accent
   measures 16.77:1. */
.ba-zone > .ba-question,
.ba-zone > .ba-question.is-answered-q {
  background: var(--c-accent);
  color: var(--c-on-accent);
  font-family: var(--c-f-display);
}

/* ── THE OPTION ROWS — lifted from the landing's .p-opt ─────────────────
   Landing geometry: 12/18 padding, --r-md, 1px hairline, body-size text.
   The app's pills (999px radius, 0.85rem, --surface-well) become rows. */
.ba-option {
  font-family: var(--c-f-body);
  font-size: var(--c-t-body);
  line-height: 1.55;
  font-weight: 400;
  color: var(--c-ink-2);
  background: var(--c-surface);
  border: var(--c-e1-border);
  border-radius: var(--c-r-md);
  padding: 12px 18px;
  box-shadow: var(--c-e1-shadow);
  transition: transform    var(--c-m-tap)    var(--c-e-standard),
              border-color var(--c-m-toggle) var(--c-e-out),
              background-color var(--c-m-toggle) var(--c-e-out);
}

.ba-option:hover { border-color: var(--c-accent-ink); background: var(--c-surface-2); }

.ba-option:active { transform: scale(.98); }

.ba-option:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; }

/* THE CHOSEN ROW — the landing's .p-opt:first-child treatment.
   STATIC FALLBACK FIRST, then the color-mix. An engine without color-mix
   (WKWebView below iOS 16.4) keeps the flat tint above instead of falling
   through to a transparent row; a modern engine takes the mix. The two
   fallbacks are the mix resolved against the light and dark surfaces. */
/* SPECIFICITY, MEASURED NOT ASSUMED. briefing.css:2705 carries
     html:not(.theme-light) .ba-zone .ba-option,
     html:not(.theme-light) .ba-zone .ba-answer { background: var(--surface); }
   a §ED285-derived DARK-ONLY step-up (the option/answer wells collide with a
   --surface-well body in dark). At (0,3,1) it beats a bare `.ba-option`
   (0,1,0) and a `html:not(.theme-light) .ba-answer` (0,2,1) — so the first
   draft of this layer lost BOTH in dark: the option kept global.css's
   #1D1D1D, and the answered/celebration tint never appeared at all. Light was
   fine, so every light screenshot looked correct and hid it. It was caught by
   scripts/audit-ed440-tokens.js reading computed style, not by eye.
   The selectors below MATCH (0,3,1) and win on source order. The step-up
   BEHAVIOUR is preserved exactly — only its tokens change. */
html:not(.theme-light) .ba-zone .ba-option,
html[data-theme="dark"] .ba-zone .ba-option { background: var(--c-surface); }

.ba-zone .ba-answer {
  background: #EEF7CC;                       /* light fallback, pre-color-mix */
  border-left: 3px solid var(--c-accent-ink);
  border-radius: 0 var(--c-r-sm) var(--c-r-sm) 0;
  padding: 11px 14px;
}

html:not(.theme-light) .ba-zone .ba-answer,
html[data-theme="dark"] .ba-zone .ba-answer { background: #23291A; }  /* dark fallback */

@supports (background: color-mix(in oklab, red 22%, blue)) {
  .ba-zone .ba-answer,
  html:not(.theme-light) .ba-zone .ba-answer,
  html[data-theme="dark"] .ba-zone .ba-answer {
    background: color-mix(in oklab, var(--c-accent) 22%, var(--c-surface));
  }
}

.ba-answer-value { color: var(--c-ink); font-weight: 560; font-size: var(--c-t-body); }

.ba-answer-text  { color: var(--c-ink-2); font-size: var(--c-t-body); line-height: var(--c-lh-body); }

.ba-answer.is-just-saved {
  animation: bf-answer-land var(--c-m-celebrate) var(--c-e-spring) both;
  transform-origin: left center;
}

.ba-answer.is-just-saved .ba-answer-value::before {
  content: '';
  display: inline-block;
  width: 15px; height: 15px;
  margin-right: 8px;
  vertical-align: -2px;
  background: var(--c-accent-ink);
  /* The landing's .p-opt-tick path, as a mask so it inherits the accent. */
  -webkit-mask: var(--c-tick) center / contain no-repeat;
          mask: var(--c-tick) center / contain no-repeat;
  animation: bf-tick-in var(--c-m-celebrate) var(--c-e-spring) both;
}

/* REDUCED MOTION. The token layer already flattens --c-e-spring to an
   ease-out and nulls the amplitudes, so this degrades on its own. What is
   pinned here is the END STATE: the confirmation must still HAPPEN — the
   answer and its tick arrive, just without the overshoot. Duration is
   collapsed by global.css's universal kill; `none` is never used, because
   `none` would skip the end state and could leave the block at opacity 0. */
@media (prefers-reduced-motion: reduce) {
  .ba-answer.is-just-saved,
  .ba-answer.is-just-saved .ba-answer-value::before {
    animation-name: bf-tick-in;      /* opacity-led, no scale overshoot */
    transform: none;
  }
}

/* ── EDIT / SAVE CONTROLS ──────────────────────────────────────────────── */
.ba-save {
  background: var(--c-accent);
  color: var(--c-on-accent);
  border: none;
  border-radius: var(--c-r-sm);
  font-family: var(--c-f-body);
  transition: transform var(--c-m-tap) var(--c-e-standard);
}

.ba-save:active { transform: scale(.97); }

.ba-cancel { border: var(--c-e1-border); color: var(--c-ink-2); background: transparent; }

.ba-save:focus-visible, .ba-cancel:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; }

.ba-more   { color: var(--c-ink-2); font-size: var(--c-t-micro); }

.ba-chosen { color: var(--c-ink-2); font-size: var(--c-t-micro); }

.ba-input  { background: var(--c-surface); border: var(--c-e1-border); border-radius: var(--c-r-sm); color: var(--c-ink); }

/* ── STREAK + PROGRESS ─────────────────────────────────────────────────
   NEUTRAL INK, INCLUDING THE NUMERALS. DESIGN-INVARIANTS.md bans small lime
   text on the dark theme even where the raw contrast ratio is high, and a
   streak numeral is exactly the "small numeral" that law names. No exception
   is made for the one number that would look good in lime. The light theme
   keeps --c-accent-ink for small text, which that law explicitly permits. */
.ba-progress .ba-countdown { color: var(--c-ink-2); font-size: var(--c-t-micro); }

.ba-progress.is-payoff { border-top: 1px solid var(--c-line); }

.ba-progress.is-payoff .ba-countdown { color: var(--c-ink); }

html.theme-light .ba-progress.is-payoff .ba-countdown,
html[data-theme="light"] .ba-progress.is-payoff .ba-countdown { color: var(--c-accent-ink); }

/* ══════════════════════════════════════════════════════════════════════════
   §ED440 PHASE D · ITEM 1 — THE OPTIMISTIC ANSWER
   The highest-priority fix of this pass. Part 1 mechanic 4.
   ══════════════════════════════════════════════════════════════════════════ */
/* THE DIM IS GONE. `.ba-zone.is-busy { opacity:.6 }` (briefing.css:2305) meant
   the one feedback a reader got for tapping their answer was the ENTIRE
   question block fading out, while the row they chose stayed unmarked until
   the server replied. On anything worse than office wifi that is a dead tap.
   The old class is left defined above — nothing sets it any more — and
   reader-answer.js now sets `.is-committing`, which blocks a second press and
   CHANGES NOTHING VISIBLE. The chosen row is the feedback. */
.ba-zone.is-committing { pointer-events: none; }

/* THE CHOSEN ROW, PAINTED WITHIN ONE FRAME OF THE TAP.
   Deliberately the SAME treatment as the confirmed .ba-answer below — the
   lime tint at 22% over the surface, the accent hairline — because the
   optimistic state is not a "pending" state with its own look. It is the
   answer, shown immediately, which the server then either confirms (the
   block rebuilds and the 640ms spring fires) or takes back (the class comes
   off and .ba-failed appears). A distinct third appearance for "probably
   saved" would be inventing a state the reader does not have.
   COLOUR AND BORDER ONLY — no transform, no opacity — so there is nothing
   here to drop a frame on and nothing for reduced-motion to kill.
   Specificity matches the (0,3,1) dark step-up at briefing.css:2895 and wins
   on source order; see that rule's note for why a bare .ba-option loses. */
.ba-zone .ba-option.is-chosen,
html:not(.theme-light) .ba-zone .ba-option.is-chosen,
html[data-theme="dark"] .ba-zone .ba-option.is-chosen {
  background: #EEF7CC;                      /* light fallback, pre-color-mix */
  border-color: var(--c-accent-ink);
  color: var(--c-ink);
}

html:not(.theme-light) .ba-zone .ba-option.is-chosen,
html[data-theme="dark"] .ba-zone .ba-option.is-chosen { background: #23291A; }

@supports (background: color-mix(in oklab, red 22%, blue)) {
  .ba-zone .ba-option.is-chosen,
  html:not(.theme-light) .ba-zone .ba-option.is-chosen,
  html[data-theme="dark"] .ba-zone .ba-option.is-chosen {
    background: color-mix(in oklab, var(--c-accent) 22%, var(--c-surface));
  }
}

/* THE TAKE-BACK. Shown only where an optimistic paint was reverted and
   nothing re-rendered over it. Warm danger token, at the reading floor —
   this is a sentence a reader must actually read. */
.ba-failed {
  margin: 10px 0 0;
  color: var(--c-danger);
  font-size: var(--c-t-micro);
  line-height: 1.5;
}

/* Inline progress on the write-in's Save — an ACTION waiting, not a toggle. */
.ba-save.is-saving { opacity: .72; cursor: default; }

/* ── §ED487 · THE UNSAVED WRITE-IN ────────────────────────────────────────
   Shown when the server refused an edit (503) or already held an answer
   (409) and the reader had typed prose. js/reader-answer.js adopts the
   STORED answer above this block; this is the paragraph that did NOT save,
   put back on screen so the reader can still read it and copy it.

   NO GROUND OF ITS OWN — deliberately, and for the reason §ED70 names.
   .ba-answer's base rule paints `--surface-well`, which belongs to the
   OLD token layer (global.css), while every colour in this §ED440 block
   comes from the NEW one (tokens.css --c-*). Mixing the two would set
   light ink on a dark well in one theme and never be noticed until a
   reader met it. So this block inherits the zone's ground and borrows its
   ink from exactly the rules that already ship beside it: --c-danger from
   .ba-failed above, --c-ink / --c-ink-2 from .ba-answer-value and
   .ba-answer-text at briefing.css:3016.

   IT MUST NOT READ AS A SECOND ANSWER. .ba-answer is the lime-tinted
   confirmed block; this is a DOTTED danger edge with no fill, so the two
   are distinguishable by shape as well as by colour — the dotted rule
   survives forced-colours and greyscale, which a tint does not.

   TYPE FLOOR (§ED306): the reader's own words are set at --c-t-body, not
   at a caption size. This is the last place that paragraph exists. */
.ba-unsaved {
  margin: 12px 0 0;
  padding: 2px 0 2px 13px;
  border-left: 3px dotted var(--c-danger);
}

.ba-unsaved-lead {
  margin: 0;
  color: var(--c-danger);
  font-size: var(--c-t-micro);
  line-height: 1.5;
}

.ba-unsaved-label {
  margin: 10px 0 0;
  color: var(--c-ink-2);
  font-size: var(--c-t-micro);
  line-height: 1.5;
}

.ba-unsaved-text {
  margin: 4px 0 0;
  color: var(--c-ink);
  font-size: var(--c-t-body);
  line-height: var(--c-lh-body);
  overflow-wrap: break-word;
  white-space: pre-wrap;   /* VERBATIM — the reader's own line breaks survive */
}

/* §ED742 · SPLIT FROM A SHARED RULE. The selectors below used to share one
   declaration block with html .bf-page .bf-signup in css/briefing.css; that half stays
   there. KEEP THE TWO DECLARATION BLOCKS IDENTICAL — scripts/audit-ed742.js
   §5 diffs them. */
html .bf-page .ba-zone {
  background: var(--c-surface);
  border-color: var(--c-line);
  box-shadow: var(--c-e1-shadow);
}

/* (e) THE VOICE AFFORDANCE — voice is the differentiator and looked like an
   afterthought: a 38px circle on --surface-well (#101010) with
   --border-strong, i.e. old graphite tokens, reading as a secondary icon
   button beside a text field.
   NO WAVEFORM. §ED438 R8 forbids porting the landing's FAKE .p-wave over a
   real player, and reader-answer.js's own comment already rules a live
   recording animation out as theatre. This is a target and a colour, not a
   performance. */
.bf-page .ba-mic {
  width: auto; min-width: 44px; height: 44px; padding: 0 16px; gap: 8px;
  background: var(--c-surface);
  border: 1px solid color-mix(in srgb, var(--c-accent-ink) 34%, transparent);
  border-radius: var(--c-r-full);
  color: var(--c-accent-ink);
  font-size: var(--c-t-micro);
  font-weight: 500;
  transition: transform var(--c-m-tap) var(--c-e-standard),
              border-color var(--c-m-toggle-out) var(--c-e-standard);
}

.bf-page .ba-mic:hover  { border-color: var(--c-accent-ink); background: var(--c-accent-wash); }

.bf-page .ba-mic:active { transform: scale(.97); }

.bf-page .ba-mic.is-live {
  background: var(--c-band-fill); border-color: var(--c-band-fill); color: var(--c-on-accent);
}

/* ── ITEM 4 · D3 — THE OPTIONS TO THE PRIMARY INK TIER ───────────────────
   NOT a contrast fix. Measured: 7.74:1 light / 7.40:1 dark — both PASS AA
   comfortably. It is a HIERARCHY defect: .ba-option was set to --c-ink-2,
   the SECONDARY tier, while the prose it asks the reader to act on sits on
   the primary tier — so the options rendered at ~45% of the contrast of the
   body copy and read as secondary text.

   THE LIFT WAS THE ERROR, AND IT WAS MINE. Phase B took --ink-2 faithfully
   from the landing's .p-opt. But the landing's options are a STATIC PICTURE
   of a control inside a marketing page — decorative, never tapped. The app's
   are the live control a reader must read and choose between. This is the
   concrete case Part 2 names: where the landing's value cannot port, say so.
   Matches the (0,3,1) dark step-up and wins on source order. */
.bf-page .ba-zone .ba-option,
html:not(.theme-light) .bf-page .ba-zone .ba-option,
html[data-theme="dark"] .bf-page .ba-zone .ba-option { color: var(--c-ink); }

/* ── ITEM 5 · THE BAND, DIALLED (P4b) ────────────────────────────────────
   Jake ruled P4b. The lip STAYS A FULL-BLEED LIP; only the lime's lightness
   moves, and only in dark. --c-band-fill resolves to #CCFF00 in light and
   #A8D400 in dark — see css/tokens.css for the measurement and for why the
   rejected P4 tint was wrong. Specificity matches the band's own
   .ba-zone > .ba-question (0,2,0) and wins on source order; a bare
   .ba-question (0,1,0) would lose silently, which is the T1 defect. */
.bf-page .ba-zone > .ba-question { background: var(--c-band-fill); }

/* §ED742 · SPLIT FROM A SHARED RULE. The selectors below used to share one
   declaration block with html .bf-hook-text, html .ar-locked-hook, html .ra-card > .ra-question in css/briefing.css; that half stays
   there. KEEP THE TWO DECLARATION BLOCKS IDENTICAL — scripts/audit-ed742.js
   §5 diffs them. */
html .ba-zone > .ba-question,
html .ba-zone > .ba-question.is-answered-q {
  font-variation-settings: 'opsz' 72, 'wght' 400;
}

/* ══════════════════════════════════════════════════════════════════════════
   §ED440 PHASE E · THE VOICE AFFORDANCE (Part 4)

   Voice is the differentiator and it looked like an afterthought: a 15px glyph
   in a row of grey buttons, indistinguishable from "cancel". This makes it
   read as the PREMIUM path — which is what it is, because a recorded voice is
   the thing the reader's family will actually want in twenty years and a typed
   sentence is not.

   THE THREE STATES ARE IN js/waveform.js; this sheet only dresses them.
   ══════════════════════════════════════════════════════════════════════════ */
/* ── (4a) IDLE — the mic reads as the premium path ───────────────────────
   Lime-tinted, specular-edged, unmistakably tappable, and visibly a
   DIFFERENT KIND of control from the neutral actions beside it. */
html .bf-page .ba-mic {
  background: linear-gradient(to bottom,
                color-mix(in srgb, var(--c-accent) 16%, var(--c-surface)),
                var(--c-surface));
  border: 1px solid color-mix(in srgb, var(--c-accent-ink) 42%, transparent);
  /* The specular. Same one light source as every other lit object. */
  box-shadow: var(--c-specular-edge-soft), var(--c-e1-shadow);
}

html:not(.theme-light) .bf-page .ba-mic,
html[data-theme="dark"] .bf-page .ba-mic {
  background: linear-gradient(to bottom,
                color-mix(in srgb, var(--c-accent-ink) 22%, var(--c-surface)),
                var(--c-surface));
}

/* ── THE HELD STATE MUST OUTRANK THE IDLE ONE. A SPECIFICITY DEFEAT, CAUGHT ──
   MEASURED, not spotted by eye. The dark idle rule above is
   `html:not(.theme-light) .bf-page .ba-mic` = (0,3,1); Phase D's held rule is
   `.bf-page .ba-mic.is-live` = (0,3,0). Same class count, but the idle rule
   carries an element selector too, so IT WINS — and in dark the mic kept its
   resting gradient for the entire recording. Probed computed style while
   holding the button: background-color rgba(0,0,0,0) and a live background-
   image, i.e. the held rule was dead. Light was unaffected (its idle rule is
   (0,2,1) and loses correctly), so this was a DARK-ONLY silent failure — the
   exact shape §ED440 T1 records, and the exact reason this pass verifies by
   computed style instead of by looking at frames.

   `background` and not `background-color`: the idle rule sets a gradient,
   which lives in background-image, so overriding only the colour would leave
   the gradient painted on top of it and the fix would look like it failed.
   The shorthand resets both. */
html .bf-page .ba-mic.is-live,
html:not(.theme-light) .bf-page .ba-mic.is-live,
html[data-theme="dark"] .bf-page .ba-mic.is-live {
  background: var(--c-band-fill);
  border-color: var(--c-band-fill);
  color: var(--c-on-accent);
}

/* ── (4b) THE WAVEFORM TRACK ─────────────────────────────────────────────
   28 DOM bars. Height is driven by a custom property so the only thing that
   changes per frame is a transform on the compositor — no layout, no paint,
   which is what makes 60fps affordable on a phone that is also recording.

   `scaleY` on a bottom-anchored bar, NOT `height`. Animating height is a
   layout write per bar per frame — 28 layouts per frame, and on a mid-range
   Android that alone would drop the recording. */
.wv {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 34px;
  padding: 0 2px;
  flex: 1 1 auto;
  min-width: 0;
  /* --wv-p is playback progress, 0..1. Unset outside playback. */
}

.wv-bar {
  flex: 1 1 0;
  min-width: 2px;
  height: 100%;
  border-radius: var(--c-r-full);
  background: color-mix(in srgb, var(--c-accent-ink) 30%, transparent);
  transform-origin: bottom center;
  transform: scaleY(var(--wv-h, .2));
  transition: transform 90ms linear, background-color var(--c-m-toggle) var(--c-e-standard);
}

html:not(.theme-light) .wv-bar,
html[data-theme="dark"] .wv-bar {
  background: color-mix(in srgb, var(--c-accent-ink) 38%, transparent);
}

/* IDLE is DECORATIVE AND SAYS SO. The resting form is a fixed hand-set shape
   (js/waveform.js REST), not data and not random. It is beautiful at rest,
   which is the entire requirement, and it claims nothing. */
.wv:not(.is-live):not(.is-playback) .wv-bar {
  background: color-mix(in srgb, var(--c-ink-3) 34%, transparent);
}

/* ── (4c) RECORDING — real data, so it gets the accent ───────────────────
   The bars only take the lime while they are carrying live input. That is the
   distinction the supersession note above turns on: colour marks DATA here,
   not activity. */
.wv.is-live .wv-bar {
  background: var(--c-accent-ink);
  /* 60ms, not the 90ms rest value: at analyser frame rate a longer ease
     smears consecutive frames together and the bars stop tracking speech. */
  transition: transform 60ms linear;
}

html:not(.theme-light) .wv.is-live .wv-bar,
html[data-theme="dark"] .wv.is-live .wv-bar { background: var(--c-band-fill); }

/* THE RULED DEGRADATION — no AnalyserNode, or reduced motion. ONE indicator,
   pulsing. Never fake bars. The bars hold the resting form and stop being the
   thing that carries the state; the dot carries it instead. */
.wv.is-pulse .wv-bar { transition: none; }

.wv.is-pulse::after {
  content: '';
  position: absolute;
  right: 6px; top: 50%;
  width: 9px; height: 9px;
  margin-top: -4.5px;
  border-radius: var(--c-r-full);
  background: var(--c-accent-ink);
  animation: wvPulse 1.4s var(--c-e-inout) infinite;
}

.wv.is-pulse { position: relative; padding-right: 22px; }

/* Under reduced motion the dot stops pulsing and simply STAYS LIT — the state
   is still conveyed, which is the rule (opacity end-states survive, motion
   does not). Recording is unaffected either way; see js/waveform.js. */
@media (prefers-reduced-motion: reduce) {
  .wv.is-pulse::after { animation: none; opacity: 1; }
}

/* ── (4d) PLAYBACK — peaks from the real buffer, with real progress ──────
   The played portion takes the accent; the rest stays quiet. One gradient on
   the TRACK rather than a class per bar, so progress costs no DOM writes. */
/* THE PLAYED BARS ARE THE UNPLAYED BARS. The split is carried entirely by the
   wash below, not per bar — one element for progress rather than 28 DOM
   writes, which is the whole reason --wv-p is a custom property.
   A GRADIENT LAYER PINNED TO `background-size: 0 100%` LIVED HERE AND HAD
   NEVER RENDERED A PIXEL: zero width, and nothing ever resized it. §ED527b's
   law is to delete a declaration found never to have applied, so it is gone.
   Proven inert rather than assumed — arm 3 pixel-diffs the bars against the
   old rule and gets 0 differing pixels. */
.wv.is-playback .wv-bar {
  background: color-mix(in srgb, var(--c-ink-3) 30%, transparent);
}

.wv.is-playback {
  --wv-p: 0;
  -webkit-mask-image: none;
}

/* The played/unplayed split, scaled from the left edge by --wv-p, which
   js/waveform.js writes from the audio element's own currentTime — so the
   progress is the audio's, never a timer's.

   TRANSFORM, NOT WIDTH — §ED537 defect 3. This animated `width` until now,
   which is a layout write per frame on the one element that is on screen
   precisely because something is playing. §ED440 permits transform and
   opacity only. The breach was INERT while --wv-p never moved off 0 for a
   paused element (§ED537 defect 2); fixing the progress is what turned a
   dormant breach into a live one, which is why the two land together.
   MEASURED (scripts/audit-ed537-waveform.js arm 3): the scaled fill reaches
   the same pixel as the width fill at p = 0, .25, .5, .75 and 1 — worst edge
   delta 0px — with the track box and all 28 bar boxes identical between the
   two arms, which is the layout-shift half of that arm.

   `overflow:hidden` went with it: the pseudo-element has no children and
   never clipped anything.

   THE 10px `border-radius` WENT TOO, AND THAT IS A DELIBERATE VISUAL CHANGE
   RATHER THAN A SIDE EFFECT. scaleX squashes horizontal curvature: a 10px
   radius under scaleX(.25) draws as 2.5px across, so the fill's leading edge
   would taper differently at every progress value — MEASURED at 0.85% of the
   track's pixels, peak channel delta 73, all of it on that one corner. A
   progress fill's leading edge should be a clean vertical boundary anyway,
   and the wash sits behind 28 bars in a 34px track where its own corners were
   never legible. Removing it is what makes the transform provably identical
   to the width fill — arm 3a diffs the two at 0 pixels. Arm 3b prices the
   radius removal itself against the rule as it shipped, separately, so the
   intended change is never hidden inside the mechanical one.

   THE WASH IS ACCENT PLUS A WARM NEUTRAL, AND THE NEUTRAL IS LIGHT-ONLY —
   §ED537 defect 4. MEASURED on the shipped rule: the accent wash alone
   separates played from unplayed by ΔE 27.8 against the dark ground but only
   ΔE 13.6 against paper. The same wash reads twice as strongly in dark as in
   light, which is the whole complaint. THE FIX SPENDS NO MORE ACCENT: hue 72
   stays at 18% in both themes and carries the IDENTITY of the played side.
   The legibility is bought with --c-ink-3 — the same warm neutral the
   unplayed bars are already made of, so no colour is invented and no cool
   grey enters. Light lands at ΔE 22.9 and the two themes come within 1.21x
   of each other. */
.wv.is-playback::before {
  content: '';
  position: absolute;
  inset: 0;
  transform-origin: left center;
  transform: scaleX(var(--wv-p, 0));
  pointer-events: none;
  background-color: color-mix(in srgb, var(--c-accent-ink) 18%, transparent);
  background-image: linear-gradient(color-mix(in srgb, var(--c-ink-3) 24%, transparent) 0 100%);
  transition: transform 120ms linear;
}

html:not(.theme-light) .wv.is-playback::before,
html[data-theme="dark"] .wv.is-playback::before {
  /* Dark already separates at ΔE 27.8 on the accent alone — measured. Adding
     the neutral here would only mute the accent to fix nothing, and --c-ink-3
     inverts to a LIGHT warm grey in dark, so it would lift the wash rather
     than deepen it. */
  background-image: none;
}

.wv.is-playback { position: relative; }

/* ── (4e) THE VOICE ROW ──────────────────────────────────────────────────
   Mic and waveform side by side: the affordance and the evidence, together.
   At 375 the waveform takes what the mic leaves and never pushes it off the
   row (min-width:0 + flex on the track). */
.ba-voice-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-width: 0;
  margin-top: 10px;
}

/* The track fills whatever the mic leaves and never pushes it off the row.
   `min-width:0` on a flex child is the part everyone omits: without it the
   default `min-width:auto` refuses to shrink below content size and the
   overflow reappears at 375. */
.ba-voice-row .wv { flex: 1 1 auto; min-width: 0; }

/* ── (4e-ii) THE REFUSED MIC — §ED525 ─────────────────────────────────────
   The line js/reader-answer.js writes under the voice row when getUserMedia
   or the recognizer refuses. Until §ED525 that refusal was swallowed
   entirely, which is how netlify.toml's `microphone=()` outlived the voice
   build by two months (§ED524).

   NOT AN ERROR TREATMENT, ON PURPOSE. No --c-danger, no dotted rule, no box
   — those belong to `.ba-unsaved`, where the reader's own prose is at stake
   and the alarm is earned. Nothing is lost here: the answer box is still
   there, still typed into, still saved. So this is set as quiet prose in the
   caption voice, the same --c-ink-2 / --c-t-micro pairing `.ba-chosen` and
   `.ba-unsaved-label` use. It should read as the app saying what happened,
   not as the app going wrong.

   STYLED AT ALL, which is the point of writing it down. `.ba-refused` — the
   §ED424 R3 refusal line — has no rule anywhere in this repo and has been
   flagged as an orphan twice (§ED430, §ED487); it renders as a bare browser
   default <p>. This class does not repeat that.

   SCOPE MATCHES `.ba-voice-row` ABOVE, which is the only place the note is
   ever inserted (as its next sibling). briefing.html, archive.html and
   vault.html all load this sheet and are the only three pages that mount a
   reader answer block. */
.ba-voice-note {
  margin: 8px 0 0;
  color: var(--c-ink-2);
  font-size: var(--c-t-micro);
  line-height: 1.5;
  overflow-wrap: break-word;   /* long UA strings never widen the card */
}

/* §ED742 · the recorder half of a mixed @media (min-width: 1024px) block; the rest stays in briefing.css. */
@media (min-width: 1024px) {
  /* THE BAND IS FULL-BLEED BY RULING and bleeds to the CARD's edge. In a
       split it must bleed to its own COLUMN's edge instead, or it tears across
       the gutter into the prose. This is the kind of thing only a render shows. */
  .ba-zone { border-radius: var(--c-r-lg); overflow: hidden; }
}

@media (min-width: 1380px) {

  /* D3 · THE SPLIT, ONLY WHERE THE RAIL FITS AND ONLY WHEN THERE IS SOMETHING
     TO PUT IN IT.

     1380, NOT 1360. §ED527's report put the threshold at 1360 from the formula
     ".bf-wrap = viewport − 102px". That formula was read off a 1440 render and
     does not hold below 1440. The real one is

         .bf-wrap = ICB − 2 x clamp(20px, 5vw, 72px)        (--c-gutter)

     so the gutter is still SCALING at 1360 (68px a side, not the capped 72),
     the rail lands at 1224px rather than 1240, and the prose column dips to
     673px. 0.9 x ICB >= 1240 solves to ICB >= 1377.8; 1380 is that with 2px of
     slack. scripts/audit-ed527-layout.js measures 1379 and 1380 either side of
     this line, and it is what caught the 1360 error.

     The threshold is measured against the INITIAL CONTAINING BLOCK, since a
     media feature excludes a classic scrollbar. A window narrow enough that a
     scrollbar pushes the ICB under 1380 reads as one column, which is the
     right answer at that size anyway.

     The grid tracks and alignment are NOT restated — they are still L2's at
     :4375 and were the half of that block that always worked. */
  /* `:has(.bf-daily-body .ba-zone)`, NOT `:has(.ba-zone)`. The bare form
     over-reaches, and the page it breaks is a LIVE one. js/reader-answer.js
     is not the only thing that mounts a .ba-zone into .bf-wrap:

       js/card.js:2473          inside .bf-daily-body        <- the split's zone
       js/card.js:1610/2026/2106  other card shapes in .bf-stack
       js/briefing.js:471       §ED424's locked-day question, appended
                                straight to #bf-stack

     On a locked day (LADDER_MODE is on in production) the last of those puts
     a .ba-zone in .bf-wrap with no .bf-daily-body anywhere on the page. The
     bare selector would widen that page's rail to 1240px with nothing to
     split, running the locked teaser's prose to ~1112px — a NEW defect of
     exactly the kind this block exists to remove. Requiring the zone to be
     inside .bf-daily-body ties the widening to the thing that consumes it.

     A descendant combinator inside :has() is fine — it is :has() inside
     :has() that is invalid. Specificity 0-4-0 (0-1-0 + 0-1-0 + the argument's
     own 0-2-0), against :3388's 0-2-0.

     scripts/audit-ed527-layout.js asserts this directly (A7): it injects a
     stray .ba-zone into .bf-stack at every desktop width and requires the
     rail and the layout not to move. */
  .bf-page .bf-wrap:has(.bf-daily-body .ba-zone) {
    max-width: 1240px;
  }
  .bf-page .bf-daily-body:has(.ba-zone) {
    display: grid;
    /* THE GAP IS FIXED, NOT 3vw. L2 set `clamp(28px, 3vw, 56px)`, which is a
       proportional gutter inside a container that STOPS growing at 1240px —
       so past the cap every extra pixel of viewport came straight out of the
       prose. That is the §ED527 defect in miniature and the layout check's
       monotonic assertion fails on it: 686.8px at 1440 falling to 678.2px at
       1728.

       40px is not a taste value either. The card's content box at the 1240
       rail is 1240 − 2px border − 128px padding = 1110px; with a 380px answer
       rail, 1110 − 40 − 380 = 690px — the SAME measure the single-column
       desktop delivers. So the answer rail is now purely ADDITIVE: turning it
       on cannot cost the reader a single character of line length. That is
       what L2's own comment asked for ("L2 keeps the measure and uses the
       space") and what the 3vw gutter quietly prevented. */
    column-gap: 40px;
  }
  .bf-page .bf-daily-body:has(.ba-zone) > .bf-reaction-wrap {
    position: sticky;
    top: 92px;
  }
}

/* ══════════════════════════════════════════════════════════════════════════
   END §ED440 OVERRIDE LAYER. APPEND NOTHING AFTER THIS LINE.
   ══════════════════════════════════════════════════════════════════════════ */
/* ── §ED545 · THE HONEST QUESTION STATES ──────────────────────────────────
 * When there is no question to ask, the block SAYS SO. It does not collapse,
 * and it does not render an em-dash — js/card.js:2462's dash is what an
 * absent fact looks like, and Jake has ruled that out as a day's answer.
 *
 * .ba-state reuses .ba-zone (both classes are set on the node) so the box,
 * its margins and its typography are the ones the answer block already owns —
 * a reader meets one surface here, whether it is asking or explaining.
 * .ba-slot is the placeholder appended synchronously while the question is
 * fetched: it holds the position and NOTHING ELSE, so a slow round trip shows
 * empty space rather than a frame around nothing. */
.ba-slot { min-height: 0; }

.ba-state-sub {
  margin: 6px 0 0;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--text-muted);
}

/* The vault link on the exhausted state is an <a>, not a <button>, because it
 * navigates. .ba-more carries the affordance's look; these two lines are the
 * whole of what an anchor needs that a button did not. */
a.ba-more { display: inline-block; text-decoration: none; }

/* §ED691 — the free_limit_reached state's price line and Continue control.
 * Spacing only, deliberately: .ba-state-sub already carries this page's
 * colour/typography treatment for a sub-line, and this file layers an
 * OLDER (--text-*, --accent-ink) and a NEWER (--c-*, the §ED440 token set
 * below) system on the same class names in different contexts — inventing
 * a third colour declaration here risks exactly the aliasing-flips-the-
 * theme defect this codebase has hit before.
 * .ba-paywall-price gets the sub-line's existing look with a little more
 * air above it (it follows a second .ba-state-sub, not the heading).
 *
 * §ED713 finding #4 — .ba-paywall-cta IS NO LONGER SPACING-ONLY. This is
 * the wall's one revenue click, and it was a 66×28px transparent gray text
 * link with no other accent competing for the view — the one-accent-per-
 * view rule entitles it to the real thing. Every property below is set
 * explicitly (not left to .ba-more's cascade) so this button's look cannot
 * drift with whichever of the two token systems above happens to win a
 * future edit: --accent/--accent-text/--accent-hover are the OLDER system,
 * the same ones .bf-wall-cta and .bf-mwall-cta above already use for an
 * identical filled pill in this same file. */
.ba-paywall-price { margin-top: 14px; }

.ba-paywall-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  min-height: 44px;
  margin-top: 18px;
  padding: 12px 22px;
  border: none;
  border-radius: 10px;
  background: var(--accent);
  color: var(--accent-text);
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  transition: background 120ms ease, transform 120ms ease;
}

.ba-paywall-cta:hover { background: var(--accent-hover); }

.ba-paywall-cta:active { transform: scale(0.97); }

/* ═══════════════════════════════════════════════════════════════════════════
   §ED548 · THE DAILY SURFACE IS THE QUESTION
   ═══════════════════════════════════════════════════════════════════════════
   PORTED FROM record-moment.html (branch ed535-record-moment, commits
   b5001aeb / 2b3da7ad / c1d74c12) — the RATIFIED design. Every rule below is
   its .rm-* counterpart with the class renamed to the .ba-* family this
   surface already uses; geometry, tokens, and motion are unchanged from the
   approved file. Where a value differs from the prototype it is because the
   prototype was a full-bleed <main> and this is a block inside #bf-stack.

   ── DESIGN LAW (§ED440), CHECKED CLAUSE BY CLAUSE ────────────────────────
   · HUE 72 LOCKED, WARM NEUTRALS. Every colour here is a --c-* token from
     css/tokens.css. There is not one literal colour value in this block, so
     a cool grey cannot get in by hand.
   · ONE ACCENT PER VIEW, AND IT BELONGS TO THE RECORD AFFORDANCE. This is
     the clause that forced a real change rather than a rename: `.ba-zone >
     .ba-question` puts the question on a FULL-BLEED LIME BAND. On a card
     among cards that band is the licensed answer-zone exception (§ED469).
     On a page whose only content IS the question, the band and the record
     button would be two large accent areas in one view — and the law says
     the accent is the record affordance's. So `.is-bank` drops the band and
     sets the question as the prototype sets it: Fraunces 400 at opsz 72, on
     the page's own ground. The corpus path keeps its band untouched; the
     band's own note (briefing.css, "that tension is Jake's to rule on") is
     answered here only for the surface §ED548 rules on.
     THE LIVE WAVEFORM IS NOT A SECOND ACCENT: 28 two-pixel bars carrying
     real analyser data are a mark, not an area — §ED440 R10/F1 governs large
     lime AREAS and glows at scale, which this is neither.
   · 16PX TYPE FLOOR. --c-t-micro is the smallest size named anywhere below,
     and it is 16px. Nothing here sets a rem/px font-size under it.
   · GLASS ON CHROME, NEVER CONTENT. No backdrop-filter in this block.
   · TRANSFORM AND OPACITY ONLY. Every transition and every keyframe below
     animates transform or opacity and nothing else — no width, no height,
     no top/left, no colour, no box-shadow. The ONE spring is the existing
     .ba-answer.is-just-saved, fired on server-confirmed save; this block
     adds no second one.
   · BOTH THEMES. The tokens re-point under html.theme-light, so every rule
     here follows without a light-only override — with two exceptions that
     are called out where they appear.
   ═══════════════════════════════════════════════════════════════════════════ */
/* ── THE SURFACE ─────────────────────────────────────────────────────────
   UN-CARDED. .ba-zone (briefing.css above) is a bordered, padded, shadowed
   well because it sits among cards. Here it is the whole screen, so the
   chrome comes off: no border, no background, no radius, no shadow, and the
   negative-margin band trick below it has nothing left to bleed against.
   Specificity is measured, not hoped for: `.ba-zone.is-bank` is (0,2,0) and
   beats both the base `.ba-zone` (0,1,0) and the token layer's own
   `.ra-card, .ba-zone` (0,1,0) on specificity, and beats
   `html.theme-light .ba-zone` (0,2,1)? — no, it does NOT, so the light
   override is restated explicitly below rather than assumed. */
.ba-zone.is-bank {
  --card-pad-x: 0px;
  --card-pad-y: 0px;
  padding: 0;
  border: 0;
  border-radius: 0;
  overflow: visible;
  background: transparent;
  margin: 0;
}

/* (0,3,1) — matches html.theme-light .ba-zone's own specificity and wins on
   source order. Without this the light theme kept --surface and --shadow-card
   and the question sat on a white card the dark theme did not have. */
html.theme-light .ba-zone.is-bank,
html[data-theme="light"] .ba-zone.is-bank {
  background: transparent;
  box-shadow: none;
}

/* ── THE QUESTION ────────────────────────────────────────────────────────
   .rm-question, verbatim. BOTH VARIATION AXES ARE NAMED: Fraunces defaults
   opsz to 144 and wght to 900, so naming one axis alone renders this in Black
   at the poster cut. 72 rather than 144 because at display size on a phone the
   poster cut's apertures close up, and this audience is the one the 16px floor
   exists for.
   THE BAND IS UNSET, NOT OVERPAINTED. background/color/margin/padding are all
   returned to their unstyled values so nothing of the lime band survives as a
   sliver — an overpaint would leave the negative margins in place and pull the
   text outside the column. (0,2,0), matching `.ba-zone > .ba-question` and
   winning on source order; the `.is-answered-q` variant is listed for the same
   reason the band lists it — it carries its own colour at equal specificity. */
.ba-zone.is-bank > .ba-question,
.ba-zone.is-bank > .ba-question.is-answered-q {
  background: transparent;
  color: var(--c-ink);
  margin-left: 0;
  margin-right: 0;
  padding-left: 0;
  padding-right: 0;
  font-family: var(--c-f-display);
  font-variation-settings: 'opsz' 72, 'wght' 400;
  font-weight: 400;
  font-size: clamp(2rem, 4.3vw, 3.5rem);     /* 32px -> 56px */
  line-height: 1.14;
  letter-spacing: -.012em;
  text-wrap: balance;
  margin-top: 0;
  margin-bottom: 0;
}

/* The answered question steps back to body scale — it is a caption for the
   answer beneath it now, not the thing being asked. */
.ba-zone.is-bank > .ba-question.is-answered-q {
  font-size: clamp(1.25rem, 2.2vw, 1.625rem);
  color: var(--c-ink-2);
  margin-bottom: 14px;
}

/* PINNED, THE is-bank QUESTION MUST BE OPAQUE — §ED440: "GLASS ON CHROME,
   NEVER CONTENT" and this is content. Unpinned it sits `background:
   transparent` on the page's own ground (above); pinned it can overlap
   scrolled content underneath it once stuck, so it takes the page's own
   ground color solid instead of letting that content show through. No
   backdrop-filter, no alpha — a flat --c-bg fill, both themes. */
.ba-zone.is-bank > .ba-question.ba-question-pinned {
  background: var(--c-bg);
}

/* ── READ ALOUD — A FIRST-CLASS CONTROL, NEVER DRAWN DEAD ────────────────
   .rm-aloud, verbatim. The element does not exist at all where the engine has
   no speechSynthesis (js/reader-answer.js buildAloud() returns null), so there
   is no disabled state to style and none is provided. */
.ba-aloud {
  margin-top: var(--c-room-sm);
  align-self: flex-start;
  display: inline-flex; align-items: center; gap: 12px;
  font: inherit; font-size: 1.0625rem;       /* 17px */
  color: var(--c-ink);
  background: var(--c-surface);
  border: 1px solid var(--c-line);
  border-radius: var(--c-r-full);
  padding: 13px 24px 13px 20px;
  min-height: 52px;
  cursor: pointer;
  box-shadow: var(--c-e1-shadow);
  transition: transform var(--c-m-tap) var(--c-e-standard),
              opacity var(--c-m-toggle) var(--c-e-standard);
}

.ba-aloud:hover { opacity: .86; }

.ba-aloud:active { transform: scale(.98); }

.ba-aloud:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 3px; }

.ba-aloud-ic { display: inline-flex; flex: 0 0 auto; }

.ba-aloud-ic svg { display: block; width: 22px; height: 22px; }

.ba-aloud.is-speaking .ba-aloud-ic svg { animation: ba-speak 1.1s var(--c-e-inout) infinite; }

/* ── THE RECORD AFFORDANCE ───────────────────────────────────────────────
   .rm-cta, verbatim: the largest element on the screen in every state that
   draws it, and the one place the accent lives. */
.ba-rec-host { display: block; margin-top: var(--c-room-sm); }

.ba-rec-cta {
  width: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px;
  min-height: 168px;
  padding: 34px 28px;
  border: 1px solid transparent;
  border-radius: var(--c-r-xl);
  background: var(--c-accent);
  color: var(--c-on-accent);
  font: inherit;
  cursor: pointer;
  box-shadow: var(--c-e2-shadow);
  transition: transform var(--c-m-tap) var(--c-e-standard),
              opacity var(--c-m-toggle) var(--c-e-standard);
}

.ba-rec-cta:hover { transform: translateY(calc(-1 * var(--c-amp-sm))); }

.ba-rec-cta:active { transform: scale(.985); }

.ba-rec-cta:focus-visible { outline: 3px solid var(--c-focus); outline-offset: 4px; }

.ba-rec-cta[disabled] { opacity: .6; cursor: default; }

.ba-rec-ic svg { display: block; width: 44px; height: 44px; }

.ba-rec-label {
  font-family: var(--c-f-display);
  font-variation-settings: 'opsz' 72, 'wght' 400;
  font-weight: 400;
  font-size: clamp(1.5rem, 2.4vw, 1.875rem);  /* 24px -> 30px */
  line-height: 1.2; letter-spacing: -.008em;
}

.ba-rec-sub { font-size: var(--c-t-micro); opacity: .72; line-height: 1.45; text-align: center; }

/* THE BUTTON STAYS LIME WHILE RECORDING — §ED535, Jake's ruling, carried
   across verbatim. An earlier build handed the accent to the waveform when
   recording began and dropped the button to a neutral outline; rendered, that
   made STOP — the control the reader most needs to find — the quietest thing
   on screen at the one moment it matters. No rule below changes the fill. */
/* ── THE EVIDENCE ROW — waveform + clock, and in review the player ───────── */
.ba-rec-evidence {
  display: flex; align-items: center; gap: 16px;
  width: 100%; min-width: 0;
  margin-top: 20px;
  padding: 16px 20px;
  background: var(--c-surface);
  border: var(--c-e1-border);
  border-radius: var(--c-r-md);
}

.ba-rec-evidence .wv { flex: 1 1 auto; min-width: 0; height: 72px; }

.ba-rec-wave-host { display: flex; flex: 1 1 auto; min-width: 0; }

.ba-rec-elapsed {
  flex: 0 0 auto;
  font-family: var(--c-f-mono);
  font-size: var(--c-t-micro);
  font-variant-numeric: tabular-nums;
  color: var(--c-ink-2);
  letter-spacing: .02em;
}

.ba-rec[data-state="recording"] .ba-rec-elapsed { color: var(--c-ink); }

/* ── TRANSPORT ───────────────────────────────────────────────────────────
   Pause / Carry on / Record it again / the confirmation pair. All neutral
   outline — NOT lime, deliberately, even where one of them is the primary
   thing to do: the accent is spent, once, on the record affordance. */
.ba-rec-transport { display: flex; gap: 12px; margin-top: 14px; flex-wrap: wrap; }

.ba-rec-tbtn {
  font: inherit; font-size: var(--c-t-micro);
  color: var(--c-ink); background: var(--c-surface);
  border: 1px solid var(--c-line); border-radius: var(--c-r-full);
  padding: 12px 22px; min-height: 48px; cursor: pointer;
  display: inline-flex; align-items: center; gap: 9px;
  transition: transform var(--c-m-tap) var(--c-e-standard),
              opacity var(--c-m-toggle) var(--c-e-standard);
}

.ba-rec-tbtn:hover { opacity: .84; }

.ba-rec-tbtn:active { transform: scale(.97); }

.ba-rec-tbtn:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; }

.ba-rec-tbtn svg { display: block; width: 17px; height: 17px; }

/* THE STATUS LINE — PRESENT ONLY IN THE STATES THAT SPEAK.
   The first cut reserved its height in every state, reasoning that "Go quiet
   as long as you need to" appearing must not push the writing box down. That
   was the wrong trade and the screenshots showed it: at rest and in review the
   line is EMPTY, so the page carried a 97px hole between the record affordance
   and the writing box (measured: CTA ends 777, label starts 874) that read as
   a missing element rather than as breathing room.
   The reflow it was buying off is not worth buying: the status only ever
   appears at the same instant the evidence row and the transport do, which is
   a change the reader just caused by tapping. Its 39px inside that is not a
   jump. So it is displayed in recording and paused, and collapsed elsewhere. */
.ba-rec-status {
  display: none;
  margin: 14px 0 0;
  font-size: var(--c-t-micro);
  line-height: 1.55;
  color: var(--c-ink-2);
  min-height: 1.55em;
}

.ba-rec[data-state="recording"] .ba-rec-status,
.ba-rec[data-state="paused"] .ba-rec-status { display: block; }

/* ── REVIEW ──────────────────────────────────────────────────────────────── */
.ba-review { margin-top: var(--c-room-sm); }

.ba-review-head {
  font-family: var(--c-f-display);
  font-variation-settings: 'opsz' 72, 'wght' 400;
  font-weight: 400;
  font-size: 1.5rem; line-height: 1.25; margin: 0 0 4px;
  color: var(--c-ink);
}

.ba-review-sub { margin: 0 0 18px; font-size: var(--c-t-micro); color: var(--c-ink-2); }

.ba-rec-play {
  flex: 0 0 auto;
  width: 48px; height: 48px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--c-ink);
  background: var(--c-bg);
  border: 1px solid var(--c-line);
  border-radius: var(--c-r-full);
  cursor: pointer;
  transition: transform var(--c-m-tap) var(--c-e-standard),
              opacity var(--c-m-toggle) var(--c-e-standard);
}

.ba-rec-play:hover { opacity: .84; }

.ba-rec-play:active { transform: scale(.94); }

.ba-rec-play:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 3px; }

.ba-rec-play svg { display: block; width: 20px; height: 20px; }

/* THE WAVEFORM IS THE PLAYER. The strip is the seek target and it is a real
   slider (role/tabindex/aria-value* set in js/reader-answer.js's mountPlayer),
   so it needs a focus ring and a pointer, not just bars. */
.ba-rec-seek {
  display: flex; flex: 1 1 auto; min-width: 0;
  align-items: center;
  min-height: 48px;
  border-radius: var(--c-r-sm);
  cursor: pointer;
  touch-action: manipulation;
}

.ba-rec-seek:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 4px; }

.ba-rec-audio { display: none; }        /* the engine, not a control */

.ba-rec-silent { margin: 14px 0 0; }

/* THE CONFIRMATION. Quiet prose and two neutral buttons — discarding a
   recording is the only destructive act on this surface, and it asks. */
.ba-rec-confirm { margin-top: 16px; }

.ba-rec-confirm-q { margin: 0 0 12px; font-size: var(--c-t-micro); color: var(--c-ink); }

.ba-rec-confirm-row { display: flex; gap: 12px; flex-wrap: wrap; }

/* ── THE WRITING BOX — AN EQUAL CITIZEN ─────────────────────────────────
   Always present, never introduced by a failure, and labelled as an
   alternative rather than as a fallback. */
.ba-write-label {
  display: block;
  margin: var(--c-room-sm) 0 10px;
  font-size: var(--c-t-micro);
  color: var(--c-ink-2);
}

.ba-zone.is-bank .ba-input {
  width: 100%;
  min-height: 132px;
  resize: vertical;
  font-family: var(--c-f-body);
  font-size: var(--c-t-body);              /* 18px reading floor */
  line-height: var(--c-lh-body);
  color: var(--c-ink);
  background: var(--c-surface);
  border: var(--c-e1-border);
  border-radius: var(--c-r-md);
  padding: 18px 20px;
  box-shadow: var(--c-e1-shadow);
}

.ba-zone.is-bank .ba-input::placeholder { color: var(--c-ink-3); opacity: 1; }

.ba-zone.is-bank .ba-input-row { display: block; }

/* KEEP THIS. Ink-filled, not lime — the accent is already spent, and the
   prototype's own [data-state="review"] promotion to lime is deliberately NOT
   ported: on this surface the record CTA is still on screen above it in every
   state except review, and two lime areas in one view is the thing the law
   forbids. Full width, 56px, the landing's pill. */
.ba-zone.is-bank .ba-save {
  margin-top: 22px;
  width: 100%;
  font-family: var(--c-f-body);
  font-size: 1.0625rem;
  color: var(--c-bg);
  background: var(--c-ink);
  border: 1px solid var(--c-ink);
  border-radius: var(--c-r-full);
  padding: 16px 28px; min-height: 56px; cursor: pointer;
  transition: transform var(--c-m-tap) var(--c-e-standard),
              opacity var(--c-m-toggle) var(--c-e-standard);
}

.ba-zone.is-bank .ba-save:hover { opacity: .88; }

.ba-zone.is-bank .ba-save:active { transform: scale(.985); }

.ba-zone.is-bank .ba-save:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 3px; }

.ba-zone.is-bank .ba-actions { display: block; }

.ba-zone.is-bank .ba-cancel {
  margin-top: 12px;
  width: 100%;
  min-height: 48px;
  border-radius: var(--c-r-full);
  font-size: var(--c-t-micro);
}

/* ── THE ATTACHMENT SEAM (§ED548 addendum) ───────────────────────────────
   A PLACE, NOT A FEATURE. `.ba-attachments` is rendered `hidden` and empty by
   js/reader-answer.js's renderAfterSave(); this rule exists so that the day an
   attachment affordance is built, it has a position, a rhythm and a rule
   already waiting for it — a feature, not a redesign of the saved answer.
   Photos and recipes will hang off AN ANSWER: never a gallery, never a recipe
   manager, no ingredient or step fields. The layout below says so — it is a
   row of small items under one answer, not a grid that wants to be browsed.
   It styles nothing today because `[hidden]` keeps it out of the flow. */
.ba-attachments {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 18px;
}

.ba-attachments[hidden] { display: none; }

/* ── §ED569 · THE VOICE DECISION ─────────────────────────────────────────
   Mounted by js/reader-answer.js's mountVoiceConsent(), beneath the saved
   answer and its recording, above the progress ladder.

   IT IS DELIBERATELY QUIET. This is not a banner, not a modal, not a card
   competing with the answer above it — a reader has just finished saying
   something, and a consent prompt that shouts would be the loudest thing on a
   surface whose whole design law puts the reader's own words first. A hairline
   rule and the muted type the .ba-voice-note family already uses; no accent, no
   fill, no shadow, no motion. Nothing on this block animates and nothing
   demands a decision.

   THE TWO BUTTONS ARE EQUALS. Same size, same weight, same border, same
   colour — No is not a text link beside a filled Yes. A visual hierarchy
   between them would be a thumb on the scale of a decision this product has no
   business influencing, and it would quietly contradict the landing's promise
   that a recording is used "only if you say so".

   48px MIN-HEIGHT on both, the tap-target floor the rest of this sheet keeps.
   flex-wrap so a narrow viewport stacks them rather than shrinking them under
   that floor. */
.ba-consent {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--c-line, rgba(0, 0, 0, 0.12));
}

.ba-consent-body {
  margin: 0;
  font-size: var(--c-t-micro);
  line-height: 1.5;
  color: var(--c-ink-soft, inherit);
  max-width: 44rem;
}

.ba-consent-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 12px;
}

/* `flex: 1 1 0` AND NOT `1 1 auto`, AND THAT IS THE WHOLE OF THE EQUALITY.
   With an `auto` basis the two buttons size to their CONTENT first, so "Yes"
   came out 402.2px against "No" at 397.8px — a 4.4px advantage to Yes, on a
   consent decision, produced by nothing but the width of the word. This probe
   measured it (test-ed569-client.js §3) and the number is why the rule reads
   as it does: a zero basis divides the row evenly and the labels stop voting. */
.ba-consent-yes,
.ba-consent-no {
  flex: 1 1 0;
  min-width: 96px;
  min-height: 48px;
  padding: 0 18px;
  border: 1px solid var(--c-line, rgba(0, 0, 0, 0.24));
  border-radius: var(--c-r-full);
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: var(--c-t-micro);
  cursor: pointer;
}

.ba-consent-yes[disabled],
.ba-consent-no[disabled] { opacity: 0.5; cursor: default; }

.ba-consent-foot {
  margin: 12px 0 0;
  font-size: var(--c-t-micro);
  color: var(--c-ink-soft, inherit);
  opacity: 0.75;
}

/* §ED732 — prior-name chips ahead of the free-text subject-note field. Same
   token family as .ba-consent-yes/.ba-consent-no directly above (this file
   already warns, at §ED691's comment, against mixing the OLDER --accent-ink
   system with this NEWER --c-* one on one class — these sit in the same
   .ba-consent block as those two buttons, so they take the same system).
   Deliberately NOT a filled lime pill: .sc-chip elsewhere in this codebase is
   a branded share-card mark and claims the accent on purpose; a "who was
   this about" chip is an ordinary secondary control, and §ED718 already
   measured this page's accent budget as tight, so a row of up to six lime
   fills next to a save-flow ask is not a cost worth paying for a chip. The
   selected state below is a fill/border change only, never color. */
.ba-chip-row { display: flex; flex-wrap: wrap; gap: 8px; }

.ba-chip {
  /* 44px, not .ba-consent-yes/no's 48px: that comment's floor is for this
     sheet's PRIMARY actions (full-width, one pair). A chip is secondary and
     one of up to six in a wrapping row; 44px is still the accepted minimum
     (iOS HIG), just not the same floor as a lone yes/no decision. */
  min-height: 44px;
  padding: 0 16px;
  border: 1px solid var(--c-line, rgba(0, 0, 0, 0.24));
  border-radius: var(--c-r-full);
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: var(--c-t-micro);
  cursor: pointer;
}

.ba-chip:hover { background: var(--c-surface-2); }

.ba-chip:focus-visible { outline: 2px solid var(--c-line); outline-offset: 2px; }

.ba-chip[aria-pressed="true"] { background: var(--c-surface-2); border-color: var(--c-ink-3, var(--c-line)); }

.ba-chip[disabled] { opacity: 0.6; cursor: default; }

/* §ED742 · the recorder half of a mixed @media (max-width: 560px) block; the rest stays in briefing.css. */
@media (max-width: 560px) {
  .ba-rec-cta { min-height: 140px; padding: 26px 20px; }
  
  .ba-rec-ic svg { width: 38px; height: 38px; }
  
  .ba-rec-evidence { padding: 14px 16px; gap: 12px; }
  
  .ba-rec-evidence .wv { height: 60px; }
}
