:root {
    color-scheme: light;
    --paper: #fbf9f4;
    --paper-deep: #f4f0e7;
    --ink: #25221c;
    --ink-soft: #4f493e;
    /* Two quiet text tokens. There used to be a third, `--faint #aaa193`, and it carried text in
       twelve rules at 2.43:1 — a label a reader cannot read is not quiet, it is absent.

       Measured against the three surfaces text lands on — `--paper #fbf9f4`, the tinted panel
       `#f8f5ee`, and `--paper-deep #f4f0e7`. The worst case governs, because a token that clears
       the floor on paper and fails on the panel is a token that fails:

         --muted  #6f6759   5.31 / 5.13 / 4.91     (was #827a6d — 4.03 / 3.89 / 3.73, under AA)
         --quiet  #6f6759   the twelve rules that were on `--faint`

       `--faint` is GONE rather than demoted to hairline duty: once its text moved off it, nothing
       used it, and a token kept alive by a comment describing a job it does not do is how this
       stylesheet's documentation drifts. Hairlines have `--line` and `--line-soft` already.

       `--muted` and `--quiet` are the same value today. They are not the same token: `--muted` is
       secondary text, `--quiet` is a micro-label. Fusing them would lose the distinction the moment
       either wants to move. */
    --muted: #6f6759;
    --quiet: #6f6759;
    --line: #ddd6c8;
    --line-soft: #ece6da;
    /* #836427, not #8a6a2c. Gold is the one accent that sets text on its OWN tint — the run-state
       pill and the `Worth a look` triage chip are gold on `--gold-soft` — and there it measured
       4.31:1. On paper it was fine (4.78), which is why it survived the neutral pass: a token is
       only as good as its worst pairing. 4.72 on gold-soft, 5.23 on paper. */
    --gold: #836427;
    --gold-soft: #f5eddc;
    --wine: #7c3b34;
    --wine-soft: #f6eae7;
    --sage: #56684e;
    --sage-soft: #ebf0e6;
    /* `--shadow` is GONE (#30 Phase 20, R1). Elevation encodes "above the page", which no role in this
       design claims — printed law does not hover. Deleted rather than set to `none`, on the same rule
       that removed `--faint`: a token kept alive describing a job it does not do is how this file
       drifts. Dialogs keep their own literal shadows, because a modal genuinely IS above the page.

       R1 is signalled THREE ways and removing the shadow alone does not satisfy it. A lighter card on
       a darker ground under an ambient corner light is a sheet of paper on a desk whether or not it
       casts a shadow — so the `body` glow is gone and `--canvas #e9e6df` is deleted with it. The page
       ground IS `--paper`: one surface, no table, and the workspace bounded by a hairline instead of
       by being a different colour. */
    /* Four faces, four jobs — the design brief's own system, self-hosted (`static/fonts/`, fetched by
       `scripts/design/fetch_fonts.mjs`; never a font CDN, see that file). Each falls back to what we
       used before it, so a blocked or failed font request degrades to the previous design rather than
       to Times.

       The split that matters is DISPLAY vs BODY. Georgia did both, and it is a superb screen face
       *designed for body text at small sizes*, which is exactly why it was weak at 28px — it reads as
       big body text. Newsreader is variable with an optical-size axis: it changes shape between a
       14px row label and a 28px finding. */
    --display: 'Newsreader', Georgia, 'Times New Roman', serif;
    --serif: 'Spectral', Georgia, 'Times New Roman', serif;
    /* A reading measure for running prose. Legal argument is read, not scanned. */
    --measure: 68ch;
    --sans: 'Public Sans', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    /* Pinned, not `ui-monospace` first: that resolves to Menlo, Consolas or DejaVu by platform, so
       the face that means *machine-exact string* in this design was a different face on every
       reader's machine. */
    --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    --radius: 8px;
    --focus: 0 0 0 3px rgb(124 59 52 / 28%);
}

* { box-sizing: border-box; }

html { min-width: 320px; background: var(--paper); }

body {
    min-height: 100vh;
    margin: 0;
    color: var(--ink);
    background: var(--paper);
    font-family: var(--sans);
    line-height: 1.5;
}

button, input, textarea { font: inherit; }
button, label[for] { -webkit-tap-highlight-color: transparent; }
button { color: inherit; }
/* R2 + `decisions/034` § Reconciliation C3. `--wine` is the SUPPORT AXIS and nothing else. It was also
   the app's link/accent colour, which put two meanings on one channel — and the grammar's own rule says
   two meanings on one channel a few pixels apart is a defect even when each is locally sensible. It
   surfaced from the other end: the loudest chroma in the run header belonged to `New document` and
   `Delete from this browser`, which adjudicate nothing, wearing the colour reserved for a finding.
   Links carry an underline for affordance and ink for legibility. Chroma is a verdict. */
a { color: var(--ink-soft); text-underline-offset: 0.18em; }
a:hover, a:focus-visible { color: var(--ink); }
[hidden] { display: none !important; }

.visually-hidden {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
}

.skip-link {
    position: fixed;
    z-index: 100;
    top: 0.75rem;
    left: 0.75rem;
    padding: 0.65rem 0.9rem;
    border-radius: 4px;
    color: white;
    background: var(--ink);
    transform: translateY(-180%);
}

.skip-link:focus { transform: none; }

:focus-visible {
    outline: 2px solid var(--wine);
    outline-offset: 3px;
    box-shadow: var(--focus);
}

/* R9 — the masthead is an INSCRIPTION, not a bar. No band, no background, no bottom border: the
   letters sit on the page ground and the document begins beneath them. The band it replaced was a
   `--paper` strip above a `--paper` card with a third colour between them — three surfaces where the
   content needs one, and the gap between them existed only to separate two things that did not need
   separating. Removing it removes the gap rather than justifying it.

   `backdrop-filter: blur()` is gone with it: frosted translucency is material this page does not have.

   R8, the GUTTER. The band stays full-bleed for its (now absent) background; its CONTENTS take the
   workspace card's TEXT gutter — `edge + border + padding`, the card's 1px border included, which is
   the `+ 1px` below. Omitting it left both edges exactly 1px out: invisible, and wrong. Not the card's
   FRAME, which leaves the wordmark hanging 24px left of everything and reproduces in miniature the
   defect this rule fixes. NOTE: this anchor exists only where a workspace card does. `about.html` is
   centred and has no card; it falls back to the clamp. */
.site-header {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.4rem 1rem;
    padding: 1.5rem max(clamp(1rem, 4vw, 3.5rem), calc((100vw - 1240px) / 2 + 1.5rem)) 0.2rem;
    background: transparent;
}

.masthead-block { display: flex; min-width: 0; flex-direction: column; gap: 0.3rem; }

.wordmark {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.2rem 0;
    color: var(--ink);
    text-decoration: none;
}

/* R8's third axis. Rank is carried by size, colour AND REGISTER — and this subject spends the third
   where a generic page would spend the first. Demoting the wordmark on size alone made it recede, and
   law does not subordinate identity to substance: a filing opens with its caption block, `IN THE
   UNITED STATES DISTRICT COURT`, which is not large — it is capitalised and letterspaced. Caps plus
   tracking confer authority WITHOUT scale, so the masthead stays prominent and still does not compete
   with the document title, which is the subject.

   Uppercase via `text-transform`, never in the markup: `frontend-shell.spec.ts` asserts
   `.wordmark-name` has the text `Quo Warranto`, and `toHaveText` reads `textContent`. */
.wordmark-name {
    font: 500 1.16rem/1.2 var(--display);
    text-transform: uppercase;
    letter-spacing: 0.26em;
}
/* The English is PROMOTED to the Latin's own register — same face, size, weight and tracking — and set
   after it behind an interpunct. The two are then ONE INSCRIPTION IN TWO LANGUAGES, which is what
   bilingual inscriptions, coins and seals have always been, the interpunct being the Roman
   word-separator. Three things fall out:

     - The cluster loses a treatment. It ran tracked-caps-roman, italic-serif-in-curly-quotes,
       title-case-serif and title-case-underlined-link across two lines; the second of those is gone.
     - The MOOD objection dissolves more completely than quotation marks managed. A lapidary pairing
       has no illocutionary force at all, so there is nothing to mistake for the application asking a
       question — and no question mark, which was only ever completing a quoted phrase.
     - **R10 no longer applies here.** Its subject was a large size differential, and there is none
       now: same size, same face, so `align-items: baseline` is simply correct and the derived 3.5px
       optical offset is retired. The rule itself still stands wherever a differential exists.

   `--ink-soft`, not `--ink`: the application is called Quo Warranto, and setting the translation in
   full ink makes the two read as coequal names. Not `--muted` either, which goes washed in caps at
   this size. Case is `text-transform`, never markup. */
.wordmark-meaning {
    color: var(--ink-soft);
    font: 500 1.16rem/1.2 var(--display);
    text-transform: uppercase;
    letter-spacing: 0.26em;
}
/* Asymmetric on purpose: the 0.26em tracking already leaves space after WARRANTO's O, so equal margins
   read as off-centre. Enough air that the two phrases are two objects rather than one long run —
   17 English characters against 12 Latin ones otherwise make the translation the heavier of the pair. */
.wordmark-meaning::before { content: '·'; margin-inline: 0.7em 1.1em; letter-spacing: 0; }

/* R11 — institutional attribution. No chroma at rest: Richardson's own gold `#B4975A` measures 2.66:1
   on `--paper` and fails AA outright (it lives on their dark green ground), and every gold that clears
   AA comfortably here is at or darker than `--gold`, which IS a verdict colour. There is no gold that
   is legible, accessible and not a finding, so the line takes `--muted` (worst pairing 4.91) and the
   school name takes the same link treatment as everything else. */
.qw-attribution { margin: 0; color: var(--muted); font: 400 0.76rem/1.35 var(--serif); letter-spacing: 0.005em; }

.site-nav { display: flex; align-items: center; gap: 1.1rem; font-size: 0.82rem; }
.site-nav a { color: var(--ink-soft); text-decoration: none; }
.site-nav a:hover { color: var(--ink); }
/* R6 — hidden on the WORKSPACE only, where it labels the single view an interface with one view has.
   `about.html` carries the same element reading `About the project` beside `Review a document`, where
   it distinguishes two pages and is doing real navigation; deleting it globally would remove
   orientation from a screen this phase does not otherwise touch. */
.workspace-page .product-label { display: none; }
.product-label {
    color: var(--quiet);
    font: 500 0.66rem/1 var(--mono);
    letter-spacing: 0.12em;
    text-transform: uppercase;
}

/* The top padding is not the side padding. It was, back when a banded site header sat above this and
   the gap was separating two surfaces; the masthead is now an inscription ON this surface, and 52px
   under it read as the content having come loose. The sides still want the full clamp. */
main { width: 100%; padding: 1.1rem clamp(1.25rem, 4vw, 3.25rem) clamp(1.25rem, 4vw, 3.25rem); }

.login-main { display: grid; min-height: calc(100vh - 66px); place-items: center; }
.login-container {
    overflow: hidden;
    width: min(440px, 100%);
    border: 1px solid var(--line-soft);
    background: var(--paper);
}
.login-header { padding: 2rem 2rem 1.2rem; border-bottom: 1px solid var(--line-soft); }
.login-header h1 { margin: 0; font: 600 1.85rem/1.15 var(--display); letter-spacing: -0.02em; }
.login-header > p:last-child { margin: 0.65rem 0 0; color: var(--muted); font-size: 0.78rem; }
.login-form { display: grid; padding: 1.6rem 2rem 2rem; gap: 1rem; }
.form-group { display: grid; gap: 0.4rem; }
.form-group label { color: var(--ink-soft); font-size: 0.75rem; font-weight: 600; }
.form-group input {
    width: 100%;
    min-height: 44px;
    padding: 0.65rem 0.75rem;
    border: 1px solid var(--line);
    border-radius: 5px;
    color: var(--ink);
    background: white;
    font-size: 1rem;
}
.message-stack { display: grid; gap: 0.5rem; }
.login-form .error-message, .success-message, .noscript-notice {
    padding: 0.75rem;
    border: 1px solid #e1c4bd;
    border-radius: 5px;
    color: var(--wine);
    background: var(--wine-soft);
    font-size: 0.76rem;
}
.success-message { border-color: #cbd7c4; color: #34432f; background: var(--sage-soft); }
.noscript-notice { border-color: #ddc99d; color: #5e481e; background: var(--gold-soft); }
.login-actions { display: flex; gap: 0.7rem; }
.login-actions > * { flex: 1; }
.submit-button { width: 100%; }
.form-help { margin: 0; color: var(--muted); font-size: 0.72rem; }
.login-footer { padding: 0.9rem 2rem; border-top: 1px solid var(--line-soft); color: var(--muted); background: #f8f5ee; font-size: 0.7rem; text-align: center; }
.login-footer p { margin: 0; }
.spinner {
    display: inline-block;
    width: 1rem;
    height: 1rem;
    margin-right: 0.5rem;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
    vertical-align: -0.15em;
}
@keyframes spin { to { transform: rotate(360deg); } }

.about-container { max-width: 960px; margin: 0 auto; }
.about-hero { max-width: 760px; margin: 0 auto 2rem; text-align: center; }
.about-hero h1 { margin: 0; font: 600 clamp(2.2rem, 6vw, 3.5rem)/1.05 var(--display); letter-spacing: -0.035em; }
.about-hero > p:last-child { margin: 1rem auto 0; color: var(--ink-soft); font: 1.05rem/1.65 var(--serif); }
.about-section {
    margin-bottom: 1rem;
    padding: clamp(1.25rem, 4vw, 2.3rem);
    border: 1px solid var(--line-soft);
    background: var(--paper);
}
.about-section h2 { margin: 0 0 0.9rem; color: var(--ink); font: 600 1.45rem/1.2 var(--display); }
.about-section h3 { margin: 1.4rem 0 0.7rem; font: 600 1.1rem/1.2 var(--display); }
.about-section p, .about-section li { color: var(--ink-soft); line-height: 1.7; }
.about-section li + li { margin-top: 0.45rem; }
.hero-statement { font: 1.15rem/1.65 var(--serif); }
.use-cases, .pipeline-steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr)); gap: 0.8rem; }
.use-case, .pipeline-step, .highlight-box { padding: 1rem; border-left: 3px solid var(--sage); background: var(--sage-soft); }
.use-case strong, .pipeline-step .step-title { display: block; margin-bottom: 0.35rem; color: var(--ink); }
.use-case p { margin: 0; font-size: 0.82rem; }
.pipeline-step { border-left-color: var(--gold); background: var(--gold-soft); }
.pipeline-step .step-number { display: block; color: var(--gold); font: 600 1.7rem/1 var(--display); }
.pipeline-step .step-title { margin-top: 0.5rem; }
.pipeline-step .step-desc { color: var(--muted); font-size: 0.76rem; }
.highlight-box { margin: 1.4rem 0 0; }
.vision-section { border-left: 4px solid var(--wine); }
.about-footer { padding: 1.5rem 0; color: var(--muted); font-size: 0.75rem; text-align: center; }
.about-footer p { margin: 0.35rem; }

.upload-view { max-width: 1040px; margin: 0 auto; }
.upload-card { overflow: hidden; }
/* `clip`, not `hidden`: both keep the children inside the rounded corners, but `hidden` makes this a
   scroll container, and a scroll container ancestor is exactly what stops the detail view's rail
   from sticking. */
.workspace-view { overflow: clip; }
/* R1/R3, second pass. The card has NO FRAME. A bounding hairline was kept at first — "a bound, not an
   enclosure" — and on a same-coloured ground it became a competing edge: the border sat at 80 while
   every line of text sat on the 105 gutter, so the masthead read as inset by 25px even though it was
   aligned with the document title exactly (maintainer, 2026-07-31). Two edges 25px apart is the
   near-alignment this grammar already calls worse than either alternative.

   Moving the masthead out to the frame was rendered and rejected: it puts the wordmark 25px left of
   everything it heads, which is the hanging-wordmark defect the gutter rule exists to fix. Removing
   the frame leaves ONE edge. The column is still legible — the control bar's fill spans it, the row
   separators span it, and every line of text starts on it. Containment is nearly spent in this family;
   this is the last of it going.

   Consequence for the masthead gutter: the text gutter is now `edge + padding` with no border in it,
   so the `+ 1px` that used to account for the frame is gone from `.site-header`. */
.upload-card, .workspace-view {
    background: var(--paper);
}

.upload-card { padding: clamp(1.5rem, 5vw, 4rem); }
.hero-copy { max-width: 660px; margin: 0 auto 2.25rem; text-align: center; }
.eyebrow, .pane-label, .triage-label {
    margin: 0 0 0.45rem;
    color: var(--gold);
    font: 500 0.67rem/1.2 var(--mono);
    letter-spacing: 0.13em;
    text-transform: uppercase;
}

/* The workspace's own micro-labels are quieter than the upload hero's. `Triage` names a row of
   filters; it is not a status, and gold is the accent the run-state pill uses. It was the loudest
   thing in the control bar while saying the least. */
.triage-label { color: var(--muted); font-weight: 400; letter-spacing: 0.12em; }

.hero-copy h1 {
    margin: 0;
    font: 600 clamp(2.35rem, 6vw, 3.65rem)/1.02 var(--display);
    letter-spacing: -0.035em;
}

.hero-lede {
    max-width: 610px;
    margin: 1rem auto 0;
    color: var(--ink-soft);
    font: 1.06rem/1.68 var(--serif);
}

.resume-card {
    display: flex;
    max-width: 720px;
    margin: 0 auto 1.2rem;
    padding: 0.9rem 1rem;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    border: 1px solid #ddd0b4;
    border-radius: 6px;
    background: var(--gold-soft);
}
.resume-card h2 { margin: 0; font: 600 1rem/1.2 var(--display); }
.resume-card p:not(.eyebrow) { margin: 0.25rem 0 0; color: var(--muted); font-size: 0.72rem; }
.storage-notice { max-width: 720px; margin: 0 auto 1rem; padding: 0.75rem 1rem; border: 1px solid #e1c4bd; border-radius: 5px; color: var(--wine); background: var(--wine-soft); font-size: 0.76rem; }

.upload-grid { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(250px, 0.8fr); gap: 1.15rem; }

.drop-zone {
    display: flex;
    min-height: 250px;
    padding: 2rem;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    /* The dashed boundary STAYS, and it is a deliberate exception to R3 rather than an oversight: it
       is functional, not decorative — it says "inside here" to someone dragging a file, the way the
       excerpt panel's tint marks whose words those are. The RADIUS goes, because nothing else in this
       design has one any more. */
    border: 1.5px dashed #bfa880;
    color: var(--ink-soft);
    background: #f7f3ea;
    cursor: pointer;
    text-align: center;
    transition: border-color 160ms ease, background 160ms ease, transform 160ms ease;
}

.drop-zone:hover, .drop-zone.is-dragging { border-color: var(--gold); background: #f3ecdf; }
.drop-zone.is-dragging { transform: translateY(-2px); }
.drop-zone.is-disabled { cursor: wait; opacity: 0.66; }

.upload-mark {
    display: grid;
    width: 3.5rem;
    height: 3.5rem;
    margin-bottom: 1rem;
    place-items: center;
    border: 1px solid #dfd1b8;
    border-radius: 50%;
    color: var(--gold);
    background: var(--gold-soft);
}

.drop-title { font: 600 1.28rem/1.2 var(--display); }
.drop-help { margin-top: 0.35rem; color: var(--muted); font-size: 0.82rem; }
.browse-copy { color: var(--ink-soft); border-bottom: 1px solid var(--line); }
.supported-types { margin-top: 1rem; color: var(--quiet); font: 0.66rem/1.4 var(--mono); }

.selected-file {
    min-height: 1.5rem;
    margin-top: 0.65rem;
    color: var(--sage);
    font-size: 0.78rem;
}

/* R3, one level down from the workspace card. This was a bordered, tinted, radiused panel wrapping a
   SINGLE toggle, and boxing one control is what produced the defect the maintainer saw: its content
   ended far above its own border, so 34.4px of empty box sat below the drop zone's foot. That is the
   near-alignment this grammar calls worse than either alternative — too much to read as a row, too
   little to read as a choice.

   Stretching the two to a common height would have aligned the feet and made the void larger. Removing
   the enclosure means there is no second box to align: the option is a plain control beside the target
   it modifies. It also retires the `#f7f3ea` / `#f8f5ee` near-collision by leaving one tint on the
   page. The heading stays: it is grouping work for whatever lands next, and an unlabelled toggle
   floating beside a drop zone reads as orphaned. */
.review-options {
    padding: 0.15rem 0 0;
}

.review-options h2 { margin: 0 0 1rem; font: 600 1.05rem/1.2 var(--display); }
.option-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; cursor: pointer; }
.option-row strong { display: block; font-size: 0.84rem; }
.option-row small { display: block; margin-top: 0.35rem; color: var(--muted); font-size: 0.72rem; line-height: 1.5; }

.switch { position: relative; flex: 0 0 auto; }
.switch input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.switch span {
    display: block;
    width: 2.5rem;
    height: 1.4rem;
    padding: 0.16rem;
    border: 1px solid #c7c0b5;
    border-radius: 999px;
    background: #dcd7ce;
    transition: background 160ms ease;
}
.switch span::after {
    display: block;
    width: 0.95rem;
    height: 0.95rem;
    border-radius: 50%;
    background: white;
    box-shadow: 0 1px 3px rgb(0 0 0 / 20%);
    content: '';
    transition: transform 160ms ease;
}
/* Capability this deployment does not have: readable, plainly inert, not a broken control.
   Set from the privacy payload's `warrant_available` (progressive_semantic.html bootstrap). */
.option-row[data-unavailable] { cursor: default; }
.option-row[data-unavailable] strong { color: var(--muted); }
.option-row[data-unavailable] .switch span { opacity: 0.45; }
.switch input:disabled + span { cursor: not-allowed; }

.switch input:checked + span { border-color: var(--sage); background: var(--sage); }
.switch input:checked + span::after { transform: translateX(1.05rem); }
.switch input:focus-visible + span { outline: 2px solid var(--wine); outline-offset: 3px; box-shadow: var(--focus); }

.option-detail {
    margin-top: 1rem;
    padding-top: 0.9rem;
    border-top: 1px solid var(--line);
    color: var(--muted);
    font-size: 0.72rem;
}
.option-detail p { margin: 0.45rem 0; }

/* Data handling (#32). Was `.privacy-notice`: a bordered, tinted, sage panel — an
   unregistered survivor of Phase 20, which stripped containment from this family, and a
   standing contradiction besides. `--sage-soft` is the affirmative tint, but the notice it
   wrapped says under `PRIVACY_STRICT=false` that this server MAY retain results — a calm
   green box above text admitting retention is the `VOLUME_COVERAGE` defect: the channel
   contradicting the copy. Prominence is bought instead on the axes the grammar endorses —
   register and ink — per `VISUAL_GRAMMAR.md` § Surface, chroma and rank. */
.data-handling {
    /* Left-aligned to the content column, NOT centred. `.privacy-notice` centred itself,
       which a framed panel can do because it is a discrete object; unframed text that
       does not sit on the column reads as floating free of it. Phase 20's "one edge"
       finding, arriving here as soon as the frame came off. */
    max-width: 68ch;
    margin: 1.6rem 0 0;
    color: var(--ink);
    font-size: 0.78rem;
    line-height: 1.55;
}
.data-handling p { margin: 0 0 0.4rem; }
.data-handling p:last-child { margin-bottom: 0; }
.data-handling p:empty { display: none; }

/* Reuses the established micro-label device rather than inventing one — but in ink, not
   `--gold`: this block reports no finding, and gold is the upload hero's accent. */
.data-handling-label {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0 0 0.5rem;
    color: var(--ink);
    font: 500 0.67rem/1.2 var(--mono);
    letter-spacing: 0.13em;
    text-transform: uppercase;
}
/* Shown only when `server_retention_enabled === false` — see the bootstrap. The explicit
   [hidden] rule is not redundant: the UA stylesheet's `[hidden] { display: none }` is
   defined for HTML, and this is an SVG element. */
.data-handling-label svg { flex: 0 0 auto; }
.data-handling-label svg[hidden] { display: none; }

/* The operator's voice, not the system's. Everything else in this block is derived from
   settings this server controls and is true by construction; these two lines are an
   assertion about a third party that the server cannot verify. Set apart so the reader is
   never shown an unverifiable claim wearing the credibility of a guaranteed one. */
.operator-assertion {
    padding-left: 0.7rem;
    border-left: 2px solid var(--line);
    color: var(--ink-soft);
}

.upload-actions {
    display: flex;
    margin-top: 1.25rem;
    align-items: center;
    justify-content: flex-end;
    gap: 1rem;
}
.upload-status { margin: 0 auto 0 0; color: var(--muted); font-size: 0.76rem; }

.primary-button, .secondary-button, .text-button, .icon-button, .filter-chip {
    border: 0;
    background: transparent;
    cursor: pointer;
}
.primary-button {
    min-height: 2.65rem;
    padding: 0.68rem 1.35rem;
    border-radius: 999px;
    color: #f8f5ee;
    background: var(--ink);
    font-size: 0.82rem;
    font-weight: 650;
}
.primary-button:hover:not(:disabled) { background: var(--ink-soft); }
.primary-button:disabled { cursor: not-allowed; opacity: 0.42; }
.secondary-button {
    padding: 0.55rem 0.85rem;
    border: 1px solid var(--line);
    border-radius: 5px;
    color: var(--ink-soft);
    background: var(--paper);
    font-size: 0.75rem;
}
.text-button { padding: 0.35rem; color: var(--ink-soft); font-size: 0.78rem; text-decoration: underline; text-underline-offset: 0.18em; }
.text-button:hover:not(:disabled) { color: var(--ink); }
.icon-button { width: 2rem; height: 2rem; border-radius: 50%; color: var(--muted); font-size: 1.35rem; line-height: 1; }
.icon-button:hover { background: var(--paper-deep); }

.error-message { margin-top: 1rem; padding: 0.8rem 1rem; border: 1px solid #e2c3be; border-radius: 5px; color: var(--wine); background: var(--wine-soft); font-size: 0.78rem; }
.storage-recovery-actions { display: flex; margin-top: 0.75rem; justify-content: flex-end; gap: 0.75rem; }
.danger-text { color: var(--wine); }
.danger-button { padding: 0.6rem 0.9rem; border: 0; border-radius: 5px; color: white; background: var(--wine); cursor: pointer; font: 600 0.76rem/1 var(--sans); }

/* 1540px let the document view's verdict columns drift to the far right of a wide screen, so the
   eye had to travel most of the display between a case name and its verdicts. The design prototype
   works at 1000px; this is the same proportion with room for the locator line the prototype does
   not carry. */
.workspace-view { max-width: 1240px; margin: 0 auto; }
/* R7. NO `border-bottom` — the progress track IS the header's bottom rule. The track already sat
   directly above that border, so the bar and the border were the same line at two moments in the run's
   life; drawing both meant the bar had to vanish at a terminal state, and the title row it had been
   anchoring then floated. It does not vanish now: it fills while live and settles to a hairline. */
.run-header {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 0.85rem 1.5rem;
    padding: 1rem 1.5rem 0;
    background: var(--paper);
}
.run-title-row { display: flex; align-items: center; gap: 0.75rem; }
/* The trailing padding is not decoration. `overflow: hidden` clips at the ADVANCE width, and
   Newsreader's `f` — as in `Fixture-Brief.pdf` — carries ink past its own advance, so the terminal of
   the last letter was being shaved off a filename that otherwise fitted exactly. */
.run-title-row h1 { overflow: hidden; margin: 0; padding-inline-end: 0.12em; font: 600 1.4rem/1.2 var(--display); text-overflow: ellipsis; white-space: nowrap; }
/* R5/R6. The run-state chip is GONE. At a terminal state it was the second of THREE assertions of the
   same fact — the filled track, this chip, and `Run complete.` in the activity strip — and while
   running it said what the filling track already said. The rule below encodes run state now. */
.run-state { display: none; }
.run-actions { display: flex; align-items: center; gap: 0.5rem; }
/* The TRACK bleeds to the card's edge, because it is structure. The COPY above it does not: it is
   text, and keeps the one gutter every other line of text in this card keeps. Bleeding the block put
   `References 3 / 9` hard against the card edge and broke that gutter. */
.run-progress { grid-column: 1 / -1; }
.progress-copy { display: flex; justify-content: space-between; margin-bottom: 0.35rem; color: var(--muted); font: 0.7rem/1.2 var(--sans); letter-spacing: 0.02em; }
.progress-track {
    position: relative;
    overflow: hidden;
    height: 2px;
    margin-inline: -1.5rem;
    background: var(--line-soft);
    transition: height 240ms ease, background-color 240ms ease;
}
.progress-track span { position: absolute; inset-block: 0; left: 0; width: 0; }
/* R2: pendency reports no finding, so the track carries no chroma. */
#referenceProgress { background: var(--ink-soft); }
/* Drawn over the reference segment, on the same denominator, so the two read as one journey rather
   than two bars racing on different scales. It has had this colour since the track was written and
   never a width -- the expensive tier's progress was a label with no bar beside it. */
#assessmentProgress { background: var(--ink); }

/* R5 — every element that reports pendency is removed by its own resolution. Set by
   `frontend-shell.js:applyRunTerminalState`, which is the ONLY writer of this class; it fires on the
   live SSE path and on restore-from-storage, because a reloaded finished run must reach the same
   state as one that finished while you watched.

   The track is the exception that proves the rule: it does not disappear, it RESOLVES — into the
   hairline it was always going to become. Nothing appears, nothing vanishes, nothing levitates. */
body.run-terminal .progress-copy,
body.run-terminal #cancelRunBtn { display: none; }
body.run-terminal .progress-track { height: 1px; background: var(--line); }
body.run-terminal .progress-track span { display: none; }

/* The reassurance sweep. Warrant assessment on a long opinion takes 30-60s, and the brief is
   explicit that credible waiting is "a first-class design challenge, not polish" -- a tool that
   reads in silence feels broken. The sweep says the run is alive without claiming progress it
   cannot measure. */
.progress-pulse { width: 3.5rem !important; background: linear-gradient(90deg, transparent, #c79a44); opacity: 0.55; animation: qwsweep 1.8s linear infinite; }
@keyframes qwsweep { from { transform: translateX(-100%); } to { transform: translateX(2000%); } }

/* One bar under the run header: the filters and the way back on the left, the run's own activity on
   the right. These were three stacked full-width bands — activity, triage, and a row containing
   nothing but `← All citations` — costing three lines of the reader's screen for content that fits
   on one at this width, and the third of them appeared and disappeared with the view, pushing the
   entire workspace down a row on every open. The prototype puts one such line under the title and
   varies its content by run state; this varies by view instead, because our filters are live
   controls rather than the prototype's static counts. */
.workspace-bar {
    display: flex;
    flex-wrap: wrap;
    padding: 0.55rem 1.5rem;
    align-items: center;
    gap: 0.45rem 1.25rem;
    border-bottom: 1px solid var(--line);
    background: #f8f5ee;
}
.triage-bar { display: flex; flex: 0 1 auto; flex-wrap: wrap; align-items: center; gap: 0.4rem 1.4rem; }
.triage-label { margin: 0; }

/* Right-aligned and clipped rather than wrapping: the activity is the one thing here that changes
   several times a second, and a status line that reflows the controls beside it as it changes makes
   a button move out from under the cursor. */
.activity-strip { display: flex; flex: 0 1 auto; min-width: 0; margin-left: auto; align-items: center; gap: 0.6rem; }
.activity-strip p { overflow: hidden; margin: 0; color: var(--muted); font-size: 0.72rem; text-overflow: ellipsis; white-space: nowrap; }
.worker-list { display: flex; overflow: hidden; min-width: 0; margin: 0; padding: 0; gap: 0.4rem; list-style: none; }
.worker-item { color: var(--muted); font: 0.64rem/1.2 var(--mono); white-space: nowrap; }

/* R2. A triage filter ADJUDICATES NOTHING — it selects a subset. Tinting it in the band colours put a
   control in the palette reserved for findings, and four pill species shared this one bar (`All`, the
   three bands, the way back). The counts still carry the verdict information; the control does not
   need to wear it. Active state is a position, not a badge: an underline under the word.

   Spacing is now DECLARED. The pills' own padding had been standing in for the gap between the label,
   the way back and the first filter, so removing the fills removed spacing nobody had written down. */
.filter-chip { padding: 0.15rem 0; border: 0; color: var(--ink-soft); background: transparent; font-size: 0.78rem; white-space: nowrap; }
.filter-chip span { margin-left: 0.3rem; color: var(--muted); font-family: var(--sans); }
.filter-chip.is-active { color: var(--ink); font-weight: 600; box-shadow: inset 0 -2px 0 0 var(--ink); }

/* Two VIEWS of two panes. The filing is never a column of its own (PDF/DOCX formatting cannot be
   faithfully reproduced) -- it appears as the per-citation excerpt at the top of the memo.

   In the DOCUMENT view the citation list is the whole card and spends the width on three verdict
   columns; the memo is not on screen at all. In the DETAIL view the same list narrows to a rail and
   the memo takes the room, because the reasoned assessment is the product. The built version had
   only the second, permanently: 70% of the workspace held one italic sentence until the reader
   clicked something, while the list -- the surface that populates during a run -- was confined to
   the remaining 30% and could afford a case name and one status word. */
.review-workspace { display: grid; min-height: 20rem; }
.review-workspace[data-view="document"] { grid-template-columns: minmax(0, 1fr); }
.review-workspace[data-view="document"] .detail-panel { display: none; }
.review-workspace[data-view="detail"] { grid-template-columns: minmax(220px, 0.26fr) minmax(0, 1fr); }
.review-workspace[data-view="detail"] .list-hint { display: none; }
.citation-rail, .detail-panel { min-width: 0; background: var(--paper); }
.detail-panel { border-left: 1px solid var(--line); }

.run-count { color: var(--quiet); font: 0.68rem/1.2 var(--mono); }

/* The filter chips' box exactly: it shares their line now, and a back button half a pixel taller
   than the chips beside it is a back button that nudges the whole workspace down when it appears. */
.back-button { padding: 0.15rem 0; margin-right: 0.9rem; border: 0; color: var(--ink-soft); background: transparent; font-size: 0.78rem; white-space: nowrap; cursor: pointer; }
.back-button:hover, .back-button:focus-visible { color: var(--ink); }
/* R4, as narrowed by `decisions/034` § Reconciliation C1 to the grammar's own rule: monospace keeps
   machine-exact strings AND region micro-labels of three words or fewer at 0.64rem. It does NOT keep a
   SENTENCE. Uppercase mono destroys word shape twice — every glyph the same width, no ascender or
   descender profile — so it must be read letter by letter: an affordable tax on `REFERENCE`, a real
   one on a line of instructions addressed to a reader. `.memo-eyebrow` and the other region labels are
   untouched; the first draft of this rule demoted them to sans, which was a regression. */
.list-hint { margin: 0; padding: 0.5rem 1.5rem; border-bottom: 1px solid var(--line-soft); color: var(--muted); background: transparent; font: 0.82rem/1.5 var(--serif); }
.citation-list { margin: 0; padding: 0; list-style: none; }
/* The triage band on the row's left edge. `data-category` has been written by `upsertCitationRow`
   since the row existed and nothing styled it, so the list carried no triage colour at all and
   selection painted wine regardless of band. In the prototype the band edge IS the rail. */
.citation-row { border-bottom: 1px solid var(--line-soft); border-left: 3px solid var(--band, transparent); }
/* One token, two consumers: the edge that paints the band and the mark beside the rail's tag. Set as
   two independent colour rules they would drift, and a row whose edge and dot disagreed would be
   saying two things about the same citation. */
.citation-row[data-category="attention"] { --band: var(--wine); }
.citation-row[data-category="look"] { --band: var(--gold); }
.citation-row[data-category="clear"] { --band: #7d9070; }
.citation-row.is-selected { background: #f8f1ec; }
.citation-row.is-selected[data-category="pending"] { --band: var(--ink); }
/* `calc(1.5rem - 3px)` on the left, not `1rem`: the card's gutter is 1.5rem — `.list-hint` and the
   triage label both set their text there — and the row carries a 3px band INSIDE that gutter, so a
   symmetric 1rem put every row number 5px left of every other left-aligned thing in the card. Not
   aligned and not deliberately offset: the near-alignment the eye reads as a mistake. The prototype
   solves it the same way by construction (`padding-left: 23px` behind a 3px border = its own 26px
   gutter). Subtracting the border is the whole trick; the band must not eat the gutter.
   `align-items: baseline`, not `start`: three hand-tuned `padding-top` fudges used to approximate
   this — 0.15rem on the number, 0.1rem on the verdict cell, plus `align-self: start` — and landed the
   number 2.6px ABOVE the case name's baseline and the verdict 0.6px below it. Two near-misses in
   opposite directions. `baseline` aligns each grid item's FIRST baseline, which is also the right
   answer for a verdict that wraps ("Found — with / discrepancies"): its first line aligns, and the
   second hangs below, as in prose. */
.citation-row-button { display: grid; width: 100%; padding: 0.85rem 1.5rem 0.85rem calc(1.5rem - 3px); grid-template-columns: 1.75rem minmax(0, 1fr); gap: 0.15rem 1rem; align-items: baseline; border: 0; color: var(--ink); background: transparent; cursor: pointer; text-align: left; }
.citation-row-button:hover, .citation-row-button:focus-visible { background: #f8f5ee; }
.citation-number { color: var(--quiet); font: 0.64rem/1.2 var(--mono); }
.citation-row-copy { min-width: 0; }
/* break-word, not anywhere: a long case name should wrap at a word boundary and only split a
   word when no boundary fits. `anywhere` splits mid-word by preference, which reads as broken. */
/* 1.22, not 1.35. The case name and the cue beneath it are ONE unit — the name says which authority,
   the cue says which use of it — and at 1.35/1.45 with a 0.2rem margin they sat 6.1px apart inside a
   15.6px frame, 39% of the padding around them, against the prototype's 17%. An interior gap that
   approaches the exterior padding stops reading as one thing. Leading on a heading of one or two lines
   buys nothing the frame is not already buying. */
.citation-row-title { display: block; overflow-wrap: break-word; font: 600 0.97rem/1.22 var(--display); }
/* The filing's own words either side of the citation. NOT a "locator" in the citation sense (a
   pincite, a reporter page); a locator in the reader's own document — it answers "WHICH citation in
   the thing I uploaded will this button take me to?", by cueing recollection of the passage: *right,
   the Massachusetts v. EPA cite near the beginning, for redressability.* Maintainer's intent,
   2026-07-29; the class name is the ambiguous half and is debt (COMPONENT_CATALOG).
   That purpose makes the RECALL CUE the load-bearing part, which is the text BEFORE the citation —
   the proposition being asserted. What follows the cite recognizes nothing. So the two-line budget is
   a consequence of the cue, not a target: spend the line on `before`, and trim `after` first.
   It is not a smaller copy of the memo's excerpt either. Same string, two jobs — recognition before
   the click, reading after it. */
.citation-row-cue { display: -webkit-box; overflow: hidden; margin-top: 0.15rem; color: var(--muted); font: 0.78rem/1.4 var(--serif); -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
.citation-row-cue:empty { display: none; }
/* THE NEGATIVE MARGIN IS NOT OPTIONAL ON AN INLINE HIGHLIGHT.
   Horizontal padding on an inline `mark` does not just extend its background — it DISPLACES the text
   after it. `…(2007)</mark>.` rendered as `(2007) .`, a period floating off its own sentence, on every
   row whose citation is followed by punctuation. The margin cancels the displacement and keeps the
   background bleed, which is all the padding was ever for. Same defect, same fix, in
   `.filing-excerpt mark` below — where it was the *only* cause, the row also having had a space
   injected in `renderRowCue`. */
.citation-row-cue mark { padding: 0 0.15rem; margin: 0 -0.15rem; border-radius: 2px; color: var(--ink); background: var(--gold-soft); }
/* No text-transform: authored copy is authored. `capitalize` title-cased the deliberately
   careful "Fails to designate" into "Fails To Designate", letting CSS overwrite the
   non-inculpatory register the reference layer exists to protect. */
/* Colour and weight come from `[data-tone]` below; this only sets the shared box. It used to be muted
   mono at 0.62rem — undifferentiated whatever the gate said, so the column a reader scans first was the
   one carrying the least signal. */
.citation-row-status { margin-top: 0.2rem; }

/* The three verdict columns -- Reference, Support, Candor -- are the whole reason the document view
   takes the full width. Every cell says something: an unassessed axis reads "Not yet", never blank,
   because an empty cell reads as clean. */
/* Marks, drawn by CSS so they never enter `textContent`: the verdict name stays exactly the verdict
   name for a screen reader and for an assertion, and colour is never the only carrier of meaning.
   `✓` for a reference that found its authority, the prototype's small rotated square for anything
   wanting a second look on any tier, and nothing for `Supported`/`Faithful` — marking the expected
   baseline of ordinary lawyering would dress the normal case as an achievement. */
/* 0.875rem, not 0.78rem. In a triage list the case name is the INVARIANT — every row has one — and
   the verdict is the VARIABLE the reader came to scan. At 0.78rem the invariant was 15.5px semibold
   and the variable 12.5px, so the eye ran down a column of case names with the findings a faint
   ragged band to the right. This is the prototype's own size for the cell; we had set it smaller. */
/* No `align-self` and no `padding-top`: the grid aligns this cell's first baseline to the case name's
   (see `.citation-row-button`). `align-items: baseline` INSIDE the flex still sets the mark against
   the label's own first line. */
.verdict-cell { display: flex; align-items: baseline; gap: 0.4rem; font: 0.875rem/1.35 var(--display); }
.verdict-cell[data-mark="diamond"]::before { flex: 0 0 auto; width: 6px; height: 6px; transform: rotate(45deg) translateY(-1px); background: currentcolor; content: ""; }
.verdict-cell[data-mark="check"]::before { flex: 0 0 auto; color: var(--sage); font-size: 0.8em; content: "✓"; }
.citation-row-status[data-tone="critical"] { color: var(--wine); }
.citation-row-status[data-tone="moderate"] { color: var(--gold); }
.citation-row-status[data-tone="calm"] { color: var(--ink-soft); }
.citation-row-status[data-tone="quiet"] { color: var(--muted); }
.citation-row-support, .citation-row-candor { font-style: italic; }
.citation-row-support[data-bucket="fine"], .citation-row-candor[data-bucket="fine"] { color: var(--sage); }
.citation-row-support[data-bucket="problem"], .citation-row-candor[data-bucket="problem"] { color: var(--wine); }
.citation-row-support[data-bucket="abstain"], .citation-row-candor[data-bucket="abstain"] { color: var(--gold); }
.citation-row-support[data-bucket="pending"], .citation-row-candor[data-bucket="pending"],
.citation-row-support[data-bucket="na"], .citation-row-candor[data-bucket="na"] { color: var(--quiet); }
/* The rail's single condensed label, and the document view's verdict columns, are mutually
   exclusive: each view shows the labels its width can carry. */
/* The rail's shorthand verdict, marked. The prototype puts a small coloured lozenge before it and
   keys the colour to the row's triage band; ours takes the band from `--band`, so the mark and the
   row's edge are literally the same value. The MARK vocabulary stays ours — `✓` where the reference
   found its authority, the rotated square otherwise — because a diamond on every row would spend the
   distinction the column makes three inches to the right. Drawn with `::before`, so it never enters
   `textContent`. */
/* `baseline`, not `center`: a tag that wraps — `found — page not in the opinion` does, in an 8.5rem
   rail — centred its mark against the whole two-line block, so the diamond floated in the gutter
   between the lines, attached to neither. It belongs on the first line, as in `.verdict-cell`. */
.citation-row-tag { display: none; align-items: baseline; gap: 0.4rem; color: var(--muted); font: 0.64rem/1.3 var(--mono); text-transform: lowercase; }
.citation-row-tag[data-mark="diamond"]::before { flex: 0 0 auto; width: 5px; height: 5px; transform: rotate(45deg) translateY(-1px); background: var(--band, var(--muted)); content: ""; }
.citation-row-tag[data-mark="check"]::before { flex: 0 0 auto; color: var(--band, var(--sage)); content: "✓"; }

.review-workspace[data-view="document"] .citation-row-button { grid-template-columns: 1.75rem minmax(0, 1fr) 8.5rem 8.5rem 8.5rem; }
.review-workspace[data-view="document"] .citation-row-status { margin-top: 0; }
/* THE RAIL IS NAVIGATION, AND ITS COST IS MEASURED IN ROWS THE READER CAN SEE AT ONCE.
   The document row's padding matches the prototype's almost exactly; the RAIL's did not — 64.8px per
   row against 52.6px, 23% taller for the same two lines. Itemised, ink to ink: +4.6px of frame top and
   bottom (0.85rem against the prototype's 0.625rem), +2.1px of leading on a single ellipsised line,
   and +3.7px between the name and its tag — that last one spent TWICE, by a grid `row-gap` and a
   `margin-top` both nudging the same edge. Nine citations cost 596px instead of 473px, and the reader
   loses that many pixels of list while reading a memo.
   `1.25rem` and `0.6rem`, down from `1.5rem`/`0.75rem`: the number's ink is ~12px in a 24px column, so
   24px of dead space sat between `01` and the case name — which the name paid for in an ellipsis.
   `row-gap: 0` here, with the tag's own `margin-top` left as the single mechanism: two declarations
   nudging one edge is how a 5.6px gap becomes an 8.3px gap nobody chose. */
.review-workspace[data-view="detail"] .citation-row-button { padding: 0.625rem 1rem 0.625rem calc(1rem - 3px); grid-template-columns: 1.25rem minmax(0, 1fr); gap: 0 0.6rem; }
.review-workspace[data-view="detail"] .citation-row-title { overflow: hidden; font-size: 0.82rem; text-overflow: ellipsis; white-space: nowrap; }
.review-workspace[data-view="detail"] .citation-row-cue,
.review-workspace[data-view="detail"] .citation-row-status,
.review-workspace[data-view="detail"] .verdict-cell { display: none; }
.review-workspace[data-view="detail"] .citation-row-tag { display: flex; grid-column: 2; margin-top: 0.2rem; }
/* THE CARD IS AS TALL AS ITS CONTENT, AND THE PAGE SCROLLS.
   ------------------------------------------------------------------------------------------------
   Both panes used to be viewport-measured scroll boxes: `max-height: calc(100dvh - 33.5rem)`. That
   subtrahend is a measurement of the chrome above them, and measurements of a layout go stale the
   moment the layout changes -- which it did, repeatedly, across phases 6 to 11. By 2026-07-27 it
   over-subtracted by roughly 260px, so at 1440x1000 the memo was CLIPPED MID-SENTENCE inside its own
   scroll pane while ~245px of empty canvas sat below the whole card. The deliverable was being cut
   so that blank page could be shown, and the maintainer had raised the dead space twice.

   The fix is not a better constant. A memo is a document and a citation table is a table; both are
   page-shaped things, and a page-shaped thing inside a fixed box fights the reader's scroll wheel,
   hides its own scrollbar inside a card, and makes browser find-in-page useless. The prototype has
   no internal scroll pane anywhere. Neither do we now.

   The rail is the one exception, and it has to be: it is NAVIGATION, so it must stay reachable while
   a long memo scrolls past, and a 200-citation filing must not stretch the grid row and leave dead
   space beside a short memo. Sticky, self-scrolling, sized to the viewport rather than to a guess
   about the chrome. */
.citation-list { min-height: 0; }
.detail-body { min-height: 13rem; padding: clamp(1.4rem, 3vw, 2.6rem); }
.review-workspace[data-view="detail"] .citation-rail {
    position: sticky;
    top: 0;
    overflow: auto;
    align-self: start;
    max-height: 100vh;
    max-height: 100dvh;
}
.detail-body > * { max-width: var(--measure); }
.reference-card { display: grid; gap: 1rem; }
/* `.reference-heading`, not `.reference-card h3`. An element selector here is (0,1,1) and outranks
   the `.reference-headline` class (0,1,0) that the renderer sets deliberately — so the memo's ANSWER,
   the one-line finding the whole reference layer exists to produce, had been rendering at 1.15rem
   since it was written, while a placeholder reading "Not requested" rendered at 1.75rem. Third
   instance of this exact shape in this file. */
.reference-heading { margin: 0; font: 600 1.15rem/1.25 var(--display); }
/* Toned by CLASS, not by element. As `h3` these sat at (0,2,1) and outranked `.reference-headline`'s
   own `color: var(--ink)` — so the headline stayed wine however it was written. They apply to the
   plain heading, which is a label; the headline is a finding and stays ink, with the gate pill four
   lines above carrying the tone and the words carrying the news. */
.reference-card.tone-critical .reference-heading { color: var(--wine); }
.reference-card.tone-moderate .reference-heading { color: var(--gold); }
.reference-card.tone-calm .reference-heading { color: var(--sage); }
.reference-card.tone-quiet .reference-heading { color: var(--muted); }
/* R3 — OPPOSITION, NOT ENCLOSURE. The confrontation this product stages is a juxtaposition: a box
   encloses, a rule sets one thing against another. Hairlines are legitimate as SEPARATORS and
   illegitimate as CONTAINERS, and the grammar already says containment is nearly spent in this family.

   SCOPE, and it is deliberate (`decisions/034` § Reconciliation C2): this rule does NOT reach
   `.filing-excerpt`. The tinted panel is RESERVED for the filing's own words — it marks whose words
   those are, which is a role, not decoration — and stripping it would have been a regression against
   an Approved pattern. */
.referent { padding: 0.85rem 0 0.85rem 0.9rem; border: 0; border-left: 2px solid var(--line); background: transparent; }
.referent .memo-eyebrow { margin-bottom: 0.4rem; }
.referent-locators { margin: 0 0 0.4rem; color: var(--ink-soft); font: 0.85rem/1.4 var(--mono); }
.referent a { font-size: 0.78rem; }
.referent.is-link-only { display: flex; padding: 0; align-items: baseline; gap: 0.7rem; border: 0; background: none; }
.referent.is-link-only .memo-eyebrow { margin: 0; }
.recovery-evidence, .warrant-routing { margin: 0; padding: 0.8rem 0.9rem; border-left: 3px solid var(--gold); color: var(--ink-soft); background: var(--gold-soft); font: 0.88rem/1.6 var(--serif); }
/* The headline: the one-line answer, in display type, before any evidence. */
/* The finding, in the size a finding gets. Ink, not the tone colour: the gate pill six lines above
   already carries the tone, the headline says it in words, and the memo's rule is that colour marks
   WHICH AXIS rather than how bad the news is. Wine here also made the headline and the evidence
   heading below it two wine 600 sentences of nearly equal size saying nearly the same thing. */
.reference-headline { margin: 0; color: var(--ink); font: 600 1.6rem/1.2 var(--display); letter-spacing: -0.015em; }
.reference-note { margin: 0; padding: 0.15rem 0 0.15rem 0.9rem; border: 0; border-left: 2px solid var(--line); color: var(--ink-soft); background: transparent; font: 0.82rem/1.6 var(--serif); }
.reference-note.tone-critical { border-color: #e6cfc9; color: #7a463f; background: var(--wine-soft); }
.reference-note.tone-docket { border-color: #d3d9e4; color: #4a5060; background: #eef0f4; }

/* The recovery trace: what was cited, struck; what was found, beside it. "Recovered" without the
   trace is a word the reader has to take on trust. */
.recovery-trace { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 0.75rem; }
.trace-side { padding: 0.15rem 0 0.15rem 0.9rem; border: 0; border-left: 2px solid var(--line); }
.trace-side .memo-eyebrow { margin-bottom: 0.35rem; }
.trace-locator { margin: 0; font: 0.95rem/1.3 var(--mono); }
.trace-note { margin: 0.35rem 0 0; font: 0.76rem/1.5 var(--serif); }
.trace-cited { border-color: #e6cfc9; background: var(--wine-soft); }
.trace-cited .trace-locator { color: var(--wine); text-decoration: line-through; }
.trace-cited .trace-note, .trace-cited .memo-eyebrow { color: #7a463f; }
.trace-found { border-color: #dbe2cd; background: var(--sage-soft); }
.trace-found .trace-locator { color: #3f5238; }
.trace-found .trace-note, .trace-found .memo-eyebrow { color: #4a5a44; }

/* Designation failure: two pieces of evidence, presented as evidence. */
.designation-evidence { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 0.75rem; }
.evidence-card { padding: 0.15rem 0 0.15rem 0.9rem; border: 0; border-left: 2px solid var(--line); background: transparent; }
.evidence-card p:last-child { margin: 0; color: var(--ink-soft); font: 0.85rem/1.55 var(--serif); }

/* Findings carry a visible rank in a gutter, ordered worst-first. Six equally weighted bars is
   accurate to what the layer emitted and unreadable as a finding (.images/problem-pile.png). */
.reference-reasons { display: grid; margin: 0; padding: 0; gap: 0.4rem; list-style: none; }
/* `align-items: baseline` and a 3.75rem gutter, both deliberate.
   The chip used to sit in a 4.5rem column and fake its vertical position with `line-height: 1.9`,
   which gave 7px of ink a 21px line box and landed its baseline 3px ABOVE the sentence it labels —
   measured, every row. Leading is not alignment; the grid aligns first baselines directly.
   4.5rem held the longest severity word (`CRITICAL`/`MODERATE`, ~3.5rem set) plus 29px of nothing,
   so a label sat about 110px from its own finding and read as a second column rather than as a
   label. 3.75rem still fits the longest word and still aligns the findings down the list. */
.reference-reasons li { display: grid; align-items: baseline; padding: 0.55rem 0.75rem; grid-template-columns: 3.75rem minmax(0, 1fr); gap: 0.6rem; border-radius: 4px; background: var(--paper-deep); }
.severity-chip { color: var(--quiet); font: 0.64rem/1.55 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; }
.finding-text { color: var(--ink-soft); font: 0.85rem/1.55 var(--serif); }
.reference-reasons .severity-critical { border-left: 3px solid var(--wine); background: var(--wine-soft); }
.reference-reasons .severity-critical .severity-chip { color: var(--wine); }
.reference-reasons .severity-moderate { border-left: 3px solid var(--gold); background: var(--gold-soft); }
.reference-reasons .severity-moderate .severity-chip { color: var(--gold); }
/* `info` findings are often GOOD news — `located_via_reporter` means the citation's own locator
   resolved to the case it names — so they read as the quietest row, not as a third alarm. */
.reference-reasons .severity-info { border-left: 3px solid #c3ceb6; background: transparent; }
/* Scenario C's cited-vs-found table: the layer's mechanical heart, and the one state a single
   icon cannot express. */
.facet-table { width: 100%; border-collapse: collapse; font: 0.9rem/1.5 var(--serif); }
.facet-table th, .facet-table td { padding: 0.4rem 0.6rem; border-bottom: 1px solid var(--line-soft); text-align: left; }
.facet-table thead th { color: var(--quiet); font: 0.64rem/1.4 var(--mono); text-transform: uppercase; }
.facet-table tbody th { color: var(--muted); font-weight: 600; }
.facet-table tr.facet-disagree td:last-child { color: var(--wine); }
.facet-table tr.facet-weak td:last-child { color: var(--gold); }
.facet-note { color: var(--muted); font-size: 0.8em; }
/* Scenario E: the citation contradicts itself. Deterministic, striking, and previously unsayable. */
/* Evidence under the finding, not a second finding. It had a tinted panel, a wine rule and a wine
   600 heading — more visual weight than the headline it was supporting, and the grammar reserves the
   tinted panel for the filing's own words. What the reader needs here is the TABLE; the line above it
   is a label, so it is set as one. */
.reporter-conflict { padding: 0; border: 0; background: none; }
.reporter-conflict h4 { margin: 0 0 0.45rem; color: var(--muted); font: 400 0.64rem/1.3 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; }
.reporter-conflict dl { display: grid; margin: 0; gap: 0.3rem; }
.reporter-conflict dl > div { display: grid; grid-template-columns: minmax(6rem, auto) minmax(0, 1fr); gap: 0.7rem; }
.reporter-conflict dt { color: var(--ink); font: 0.85rem/1.5 var(--mono); }
.reporter-conflict dd { margin: 0; color: var(--ink-soft); font: 0.9rem/1.5 var(--serif); }
.collision-explainer, .did-you-mean { margin: 0; padding: 0.8rem 0.9rem; border-left: 3px solid var(--gold); color: var(--ink-soft); background: var(--gold-soft); font: 0.92rem/1.6 var(--serif); }

.reference-card details { border-top: 1px solid var(--line); padding-top: 0.7rem; }
.reference-card summary { cursor: pointer; color: var(--ink-soft); font-size: 0.75rem; }
.reference-candidate { margin-top: 0.7rem; padding: 0.7rem; border: 1px solid var(--line-soft); border-radius: 4px; }
.reference-candidate h4 { margin: 0; font: 600 0.85rem/1.3 var(--display); }
.reference-candidate dl { display: grid; margin: 0.5rem 0 0; gap: 0.35rem; }
.reference-candidate dl > div { display: grid; grid-template-columns: 6rem minmax(0, 1fr); gap: 0.5rem; }
.reference-candidate dt { color: var(--quiet); font: 0.64rem/1.4 var(--mono); text-transform: uppercase; }
.reference-candidate dd { margin: 0; color: var(--ink-soft); font-size: 0.68rem; }
.pincite-list h4 { margin: 0; font: 600 0.85rem/1.3 var(--display); }
.pincite-list ul { margin: 0.4rem 0 0; padding-left: 1.2rem; color: var(--ink-soft); font: 0.88rem/1.6 var(--serif); }
.short-form-status { margin: 0; padding: 0.75rem 0.85rem; border: 1px solid var(--line); border-radius: 4px; color: var(--ink-soft); background: #f8f5ee; font: 0.88rem/1.6 var(--serif); }
/* The assessment is "a short, source-grounded argument in the register of a bench memo" -- the
   brief's words -- and "the prose analysis is the article". It shipped at 0.75rem inside a 440px
   column with `overflow-wrap: anywhere`, i.e. the smallest type on the screen, breaking words
   mid-character. It is now the largest running text in the memo: the verdict is the headline and
   the reasoning is the body. `overflow-wrap: anywhere` is gone -- it belongs on opaque tokens
   (URLs, hashes), never on prose. */
.semantic-detail { margin-top: 2rem; padding-top: 1.6rem; border-top: 1px solid var(--line); }
/* The identity strip: eyebrow, gate and identity on ONE ruled line at the top of the memo. It ran to
   three -- a display-type case name, the gate below it, then a citation repeating the name -- which
   spent the top of the panel on a label and set it in the weight the memo reserves for FINDINGS.
   Quiet type here is the point: the news is the headline below, not the name of the case. */
.citation-header { display: flex; align-items: center; flex-wrap: wrap; margin-bottom: 1.4rem; padding-bottom: 0.85rem; border-bottom: 1px solid var(--line); gap: 0.4rem 0.75rem; }
.citation-header .memo-eyebrow { margin: 0; }
/* Sans, following the prototype, and for its reason: this line NAMES the authority, it does not
   argue about it. In the serif it read as a shrunken headline — Phase 7 fixed its weight and its
   line count and left it in the voice the memo reserves for prose. */
.citation-identity { min-width: 0; margin: 0; color: var(--ink-soft); font: 400 0.78rem/1.5 var(--sans); }
.gate-pill { display: inline-flex; padding: 0.2rem 0.6rem; align-items: baseline; gap: 0.35rem; border: 1px solid var(--line); border-radius: 999px; background: var(--paper-deep); font-size: 0.76rem; white-space: nowrap; }
.gate-pill[data-mark="diamond"]::before { align-self: center; width: 6px; height: 6px; transform: rotate(45deg); background: currentcolor; content: ""; }
.gate-pill[data-mark="check"]::before { content: "✓"; }
.gate-pill.tone-critical { border-color: #e6cfc9; color: var(--wine); background: var(--wine-soft); }
.gate-pill.tone-moderate { border-color: #ecdfc2; color: var(--gold); background: var(--gold-soft); }
.gate-pill.tone-calm { border-color: #dbe2cd; color: var(--sage); background: var(--sage-soft); }
.gate-pill.tone-quiet { color: var(--muted); }

/* Both verdicts on one row, each under a rule in its axis colour. Stacked as two cards, the reader
   had to hold the first in their head while scrolling to the second -- and the combinations are the
   product: "supported, but the quote is absent" is a different finding from either half. */
.verdict-pair { display: grid; margin-bottom: 1.9rem; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.5rem; }
.verdict-pair .memo-verdict { margin: 0; padding-top: 0.75rem; border-top: 2px solid var(--line); }
/* 1.75rem, not 1.55: measured against the prototype, its display:body ratio is 1.75 and ours was
   1.48 — smaller at the top and larger at the bottom, so every step was defensible and the hierarchy
   came out flat. The finding is the largest thing in the memo; it should look it. */
.verdict-pair .memo-verdict .semantic-label { font-size: 1.75rem; letter-spacing: -0.01em; }
.verdict-pair .memo-gloss { font-size: 0.9rem; }
.memo-verdict.axis-support { border-top-color: var(--wine); }
.memo-verdict.axis-candor { border-top-color: #46566e; }
/* #9a6449 was #a06a4e — 4.28:1, the axis tint darkened just past the floor to 4.65. Its candor
   twin `#5b6a86` measures 5.18 and is unchanged. */
.memo-verdict.axis-support .memo-eyebrow { color: #9a6449; }
.memo-verdict.axis-candor .memo-eyebrow { color: #5b6a86; }
/* The reasoning below carries the same axis colour on its left edge, so a reader scrolling into
   prose can still tell which question it answers. */
.semantic-card.axis-support { border-left: 3px solid var(--wine); padding-left: 1.15rem; }
.semantic-card.axis-candor { border-left: 3px solid #46566e; padding-left: 1.15rem; }

.reference-disclosure { margin-top: 2rem; padding-top: 1.2rem; border-top: 1px solid var(--line); }
.reference-disclosure > summary { color: var(--muted); cursor: pointer; font: 0.78rem/1.4 var(--serif); }
.reference-disclosure[open] > summary { margin-bottom: 1.1rem; }

.semantic-siblings { display: grid; gap: 1.8rem; }
.semantic-card { min-width: 0; }
/* The two card QUESTIONS — `Does the authority bear the claim?`, `Is the document's account
   faithful?` — set out of the micro-label device they were sharing with region names.
   Uppercase monospace destroys word shape twice over (every glyph the same width, no
   ascender/descender profile), which is an affordable tax on `REFERENCE` and a real one on a
   34-character sentence. Sans, sentence case, at the size the grammar gives metadata that names
   rather than argues. Nowhere near the 28px display verdict, so it cannot read as the competing
   second heading the grammar warns about. The short region names above prose blocks —
   `The filing says`, `In your filing` — stay micro-labels; that is what the device is for.

   This rule was `.semantic-card h3` and matched NOTHING: these labels have always been
   `<p class="memo-eyebrow">`. It is class-targeted now (`card-question`, set in
   `makeSemanticCard`) rather than structural, because the voice eyebrows share this container. */
.semantic-card .card-question { margin: 0 0 0.5rem; color: var(--muted); font: 400 0.82rem/1.4 var(--sans); letter-spacing: 0; text-transform: none; }
.semantic-label { display: block; margin-bottom: 0.6rem; color: var(--ink); font: 600 1.9rem/1.15 var(--display); letter-spacing: -0.02em; }
.semantic-rationale { color: var(--ink); font: 1rem/1.72 var(--serif); }
/* Deliberately NOT a blanket `.semantic-card p` rule: at specificity (0,1,1) it outranks
   `.memo-eyebrow` (0,1,0) and silently restyled every eyebrow inside the card as body prose. */
.semantic-state-note { margin: 0.6rem 0 0; color: var(--ink-soft); font: 1rem/1.72 var(--serif); }
/* --- the memo ------------------------------------------------------------------------------
   The verdict is the headline and the prose is the article. The two voices -- the filing's and
   the source's -- are distinguished because setting them against each other IS the argument. */
/* Micro-labels are QUIET — in WEIGHT and TRACKING, which is where the refinement lives. Measured
   against the prototype 2026-07-27: theirs are 400 at 0.12em; ours were 500 at 0.08em. Small
   uppercase mono needs MORE tracking, not less — the letters have nowhere to breathe — and 500 on a
   system mono at 10px is noisy where 400 is a whisper.

   Their COLOUR is not copied. The prototype sets these labels at #a49c8c, which is 2.59:1 on its
   paper. That is far under the 4.5:1 AA floor for text this size, and a label a reader cannot read
   is not quiet, it is absent. The brief chose a look; it did not audit contrast, and the reference
   is not authority for that. Ours are `--muted` — which was itself 4.03:1 when this note was
   written, i.e. this comment recorded the rule and then failed it by 0.47. It is 5.31:1 now. */
.memo-eyebrow { margin: 0 0 0.45rem; color: var(--muted); font: 400 0.64rem/1.3 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; }
.memo-verdict { margin-bottom: 1.3rem; }
.memo-verdict .semantic-label { margin-bottom: 0.35rem; }
/* Bucket, not severity: the taxonomy is a spectrum whose middle is the product, so "partial
   credit" must not be flattened into a red/green binary. Colour marks WHERE a verdict sits. */
/* The verdict headline stays INK whatever it says. Colour in this block means WHICH AXIS -- the rule
   above it and its eyebrow are wine for support, blue for candor -- so tinting the headline by
   severity put two different colour meanings six pixels apart, and shouted a word that already says
   what it means. Every display verdict in the prototype is #23201a; only its unassessed variant is
   drawn faint, which is the one case kept below. */
.memo-verdict.bucket-abstain .semantic-label { color: var(--muted); }
.memo-gloss { margin: 0; color: var(--ink-soft); font: italic 1rem/1.6 var(--serif); }
/* The two voices, distinguished by LABEL and by TYPE — not by a panel each.
   The brief's requirement is that "distinguishing the two visually is the whole rhetorical move";
   it does not ask for two tinted cards with two more rule colours. Those cost a nesting level and
   put a third and fourth left-rule colour into a column that already has one, so the axis rule that
   says which question this prose answers stopped reading as the outermost thing. Roman for what the
   filing said, italic for what the court said, each named above it: the same distinction on the
   channels that carry meaning here anyway. */
/* The top margin is load-bearing now that the panel is gone: the card's question eyebrow and the
   first voice label are both mono micro-labels, and with nothing between them they read as one
   two-line label rather than as a section and its first block. */
.memo-voice { margin: 1.15rem 0; padding: 0; border: 0; background: none; }
/* `.voice-words`, never `.memo-voice p` — see the warning above `.semantic-state-note`. A bare
   element selector here is (0,1,1) and outranks `.memo-eyebrow` (0,1,0), which set the voice
   LABELS in serif body prose (and italic serif in the source block) instead of the mono micro-label
   every other eyebrow in the memo uses. Three label treatments in one column, from one selector. */
.memo-voice .voice-words { margin: 0; color: var(--ink); font: 1rem/1.72 var(--serif); }
/* Subordinate to the card's question eyebrow, not a peer of it — the label is saying *whose words
   these are*, which is a smaller job. It used to claim that rank with `font-size: 0.6rem` against
   the eyebrow's 0.64rem: 0.64px, which no reader has ever perceived. Rank here is carried by
   PROXIMITY — a tighter gap below binds the label to its quotation — and by sitting inside the
   card's left rule. There is one micro-label size in this stylesheet now. */
.memo-voice .memo-eyebrow { margin-bottom: 0.3rem; }
.voice-source .voice-words { color: var(--ink-soft); font-style: italic; }
.memo-essay { margin-top: 1.2rem; }
.memo-essay p { margin: 0 0 1rem; color: var(--ink); font: 1rem/1.72 var(--serif); }
.memo-essay p:last-child { margin-bottom: 0; }
/* The essays run concede -> however -> more importantly, and the shape is worth showing. The
   prototype shows it by setting the pivot WORD in italic gold inside an ordinary paragraph; we
   indented the whole paragraph behind a rule of its own, which made a turn in the argument look
   like a subordinate block and added a third indent to the column. Same information, no structure. */
.essay-pivot { color: var(--gold); font-style: italic; }
/* An anchor is a passage of the opinion, inline in the sentence it substantiates -- click to read
   it. This is what makes the assessment checkable rather than pronounced. */
.source-anchor { padding: 0 0.1em; border: 0; border-bottom: 1px solid var(--wine); border-radius: 2px; color: var(--wine); background: transparent; cursor: pointer; font: inherit; }
.source-anchor:hover, .source-anchor:focus-visible { background: var(--wine-soft); }
.memo-issues { margin: 0.4rem 0 0; padding-left: 1.2rem; color: var(--ink-soft); font: 0.95rem/1.65 var(--serif); }
.memo-essay + .memo-eyebrow { margin-top: 1.5rem; }
/* Scoped to beat `.verdict-pair .memo-verdict .semantic-label` (0,3,0), which was setting a
   PLACEHOLDER — "Not requested", "Queued" — at 1.75rem, the size this design reserves for findings.
   Same shape as the `.reference-card h3` bug above: a rule written later, at higher specificity, for
   a different purpose, quietly taking over. */
.semantic-label.is-pending,
.verdict-pair .memo-verdict .semantic-label.is-pending { font-size: 1.25rem; color: var(--muted); letter-spacing: 0; }
.contest-surface { margin-top: 1.8rem; padding-top: 1.3rem; border-top: 1px solid var(--line); }
.contest-heading { margin: 0 0 0.3rem; color: var(--ink); font: 600 1.15rem/1.3 var(--display); }
.contest-note { margin: 0 0 0.8rem; color: var(--muted); font: italic 0.95rem/1.6 var(--serif); }

.source-reference-list { display: grid; margin: 0.8rem 0 0; padding: 0; gap: 0.6rem; list-style-position: inside; }
.source-reference-list li { padding: 0.65rem; border-left: 3px solid var(--sage); background: var(--sage-soft); }
.source-reference-list blockquote { margin: 0; color: var(--ink-soft); font: italic 0.98rem/1.65 var(--serif); }
.source-reference-list span { color: var(--quiet); overflow-wrap: anywhere; font: 0.64rem/1.2 var(--mono); text-transform: uppercase; }
.source-expand-button { margin-left: 0.4rem; }
.semantic-chat-button { margin-top: 0.2rem; }
.source-opinion-text { margin: 0; white-space: pre-wrap; font: 0.9rem/1.7 var(--serif); }
.chat-message { margin: 0.4rem 0; padding: 0.7rem 0.8rem; border-radius: 5px; font: 0.95rem/1.6 var(--serif); }
.chat-user { margin-left: 1.5rem; background: var(--gold-soft); }
.chat-agent { margin-right: 1.5rem; background: var(--sage-soft); }
.chat-activity { color: var(--muted); background: var(--paper-deep); font-family: var(--mono); font-size: 0.64rem; }
.chat-unavailable { color: var(--wine); background: var(--wine-soft); }
.empty-state { max-width: 30rem; margin: 1rem auto; color: var(--muted); font: italic 0.85rem/1.6 var(--serif); }
.citation-list > .empty-state { padding: 1rem; }

.filing-excerpt-host { margin-bottom: 1.4rem; }
.excerpt-label { margin: 0 0 0.55rem; color: var(--quiet); font: 400 0.64rem/1.3 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; }
.excerpt-prose { margin: 0; }
/* A panel, not a pull-quote. The left rule read as "the tool is quoting you"; the filing's words are
   the SUBJECT of the memo, not an aside within it, and the prototype gives them a bounded panel of
   their own. */
.filing-excerpt { margin: 0; padding: 1rem 1.15rem; border: 1px solid #e6e0d2; border-radius: 6px; color: var(--ink); background: #f8f5ee; font: 1rem/1.75 var(--serif); }
/* The citation reads as a LOCATOR inside the prose rather than as an alarm: mono, a quiet fill, and
   a dotted rule. A pink highlight in a memo about whether a citation holds up looks like a verdict
   the excerpt has not earned the right to give. */
.filing-excerpt mark { padding: 0 0.2em; margin: 0 -0.2em; border-bottom: 1px dotted #b6a988; color: var(--ink); background: #efe9db; font-family: var(--mono); font-size: 0.85em; }
.filing-excerpt blockquote { margin: 0.4rem 0 0.4rem 1rem; color: var(--ink-soft); }
.component-reveal { margin-top: 0.6rem; }
.component-reveal summary { cursor: pointer; color: var(--muted); font: 0.78rem/1.4 var(--serif); }
.component-reveal summary:hover { color: var(--wine); }
.component-reveal dl { display: grid; margin: 0.6rem 0 0; gap: 0.3rem; }
.component-reveal dl > div { display: grid; grid-template-columns: 7rem minmax(0, 1fr); gap: 0.6rem; }
.component-reveal dt { color: var(--quiet); font: 0.64rem/1.5 var(--mono); text-transform: uppercase; }
.component-reveal dd { margin: 0; color: var(--ink-soft); font: 0.9rem/1.5 var(--serif); }

.chat-surface { padding: 1rem; border-top: 1px solid var(--line); background: #f8f5ee; }
.chat-surface h3 { margin: 0 0 0.7rem; font: 600 0.95rem/1.2 var(--display); }
.chat-surface textarea { width: 100%; resize: vertical; padding: 0.65rem; border: 1px solid var(--line); border-radius: 5px; color: var(--ink); background: white; font-size: 0.78rem; }
.chat-surface form { display: grid; justify-items: end; gap: 0.5rem; }
.chat-messages { display: grid; gap: 0.5rem; }

.source-dialog { width: min(780px, calc(100vw - 2rem)); max-height: calc(100vh - 2rem); padding: 0; border: 1px solid var(--line); border-radius: var(--radius); color: var(--ink); background: var(--paper); box-shadow: 0 30px 90px rgb(25 20 13 / 35%); }
.source-dialog::backdrop { background: rgb(37 34 28 / 50%); backdrop-filter: blur(2px); }
.source-dialog > header { display: flex; padding: 1rem 1.2rem; align-items: center; justify-content: space-between; border-bottom: 1px solid var(--line); background: #f8f5ee; }
.source-dialog h2 { margin: 0; font: 600 1.15rem/1.2 var(--display); }
.source-content { overflow: auto; max-height: 70vh; padding: 1.5rem; font: 1rem/1.75 var(--serif); }
.confirm-dialog { width: min(460px, calc(100vw - 2rem)); padding: 1.4rem; border: 1px solid var(--line); border-radius: var(--radius); color: var(--ink); background: var(--paper); box-shadow: 0 30px 90px rgb(25 20 13 / 35%); }
.confirm-dialog::backdrop { background: rgb(37 34 28 / 50%); }
.confirm-dialog h2 { margin: 0; font: 600 1.2rem/1.2 var(--display); }
.confirm-dialog p { color: var(--muted); font-size: 0.8rem; }
.dialog-actions { display: flex; margin-top: 1.2rem; justify-content: flex-end; gap: 0.75rem; }

@media (max-width: 1080px) {
    .review-workspace[data-view="detail"] { grid-template-columns: minmax(190px, 0.24fr) minmax(0, 1fr); }
    /* Three verdict columns do not fit; Support and Candor keep their room and the reference label
       folds back under the case name, where it lived before the columns existed. */
    .review-workspace[data-view="document"] .citation-row-button { grid-template-columns: 2.2rem minmax(0, 1fr) 7rem 7rem; }
    .review-workspace[data-view="document"] .citation-row-status { grid-column: 2; margin-top: 0.2rem; }
    .detail-body { min-height: 260px; }
}

@media (max-width: 760px) {
    .site-header { align-items: flex-start; }
    .wordmark { flex-direction: column; gap: 0.15rem; }
    /* R8's register axis costs width: 0.26em of tracking on 12 caps is most of a small viewport. Caps
       still carry the rank at the reflow floor (WCAG 320px @ 200%); the tracking is what has to give. */
    .wordmark-name, .wordmark-meaning { font-size: 1.02rem; letter-spacing: 0.14em; }
    .wordmark-meaning::before { margin-inline: 0.35em 0.55em; }
    .qw-attribution { font-size: 0.72rem; }
    .product-label { display: none; }
    main { padding: 0.75rem; }
    .upload-card { padding: 1.35rem; }
    .hero-copy { text-align: left; }
    .hero-copy h1 { font-size: 2.4rem; }
    .upload-grid { grid-template-columns: 1fr; }
    .drop-zone { min-height: 205px; }
    .upload-actions { align-items: stretch; flex-direction: column; }
    .resume-card { align-items: stretch; flex-direction: column; }
    .primary-button { width: 100%; }
    .run-header { grid-template-columns: 1fr; padding: 0.9rem 1rem; }
    .run-actions { grid-row: 3; justify-content: space-between; }
    .run-progress { grid-column: 1; }
    /* On a phone the bar's two halves stack: there is no width to right-align into, and clipping the
       activity to a sliver is worse than giving it its own line. */
    .workspace-bar { padding-inline: 1rem; }
    .activity-strip { flex-basis: 100%; margin-left: 0; }
    .review-workspace { display: block; min-height: 0; }
    /* On a phone the two views are the whole navigation: the detail view is the memo and its back
       button, with no rail competing for the width. */
    .review-workspace[data-view="detail"] .citation-rail { display: none; }
    .review-workspace[data-view="document"] .citation-row-button { grid-template-columns: 2rem minmax(0, 1fr); }
    .review-workspace[data-view="document"] .citation-row-status { grid-column: 2; margin-top: 0.2rem; }
    .review-workspace[data-view="document"] .verdict-cell { grid-column: 2; }
    .review-workspace[data-view="document"] .citation-row-support,
    .review-workspace[data-view="document"] .citation-row-candor { font-size: 0.72rem; }
    .citation-rail, .detail-panel { border-top: 1px solid var(--line); border-left: 0; }
    .detail-body { min-height: 320px; }
}

@media (max-width: 460px) {
    .site-nav { gap: 0.55rem; }
    .wordmark-meaning { font-size: 0.76rem; }
    .hero-copy h1 { font-size: 2.05rem; }
    .hero-lede { font-size: 0.96rem; }
    .run-title-row { align-items: flex-start; flex-direction: column; }
    .progress-copy { gap: 0.5rem; flex-direction: column; }
    .login-header, .login-form { padding-inline: 1.2rem; }
    .login-actions { flex-direction: column; }
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        scroll-behavior: auto !important;
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
    /* Explicit rather than left to the blanket rule above, which would run the sweep once and park
       it off-screen — invisible by accident. A reader who has asked for no motion should get none,
       by decision. */
    .progress-pulse { display: none; }
}

@media (forced-colors: active) {
    .filter-chip.is-active, .primary-button { border: 1px solid ButtonText; }
    .switch span { border: 1px solid ButtonText; }
}
