/* =====================================================================
   Annuity Benchmark — design system
   AB-ARCH-3.0 §38. Hand-written, no framework: a build step is a thing that
   can fail on a shared host, and this is not a large enough surface to need
   one.

   §38.1 — the brand idea is the lighthouse. "Not a salesman and not a
   scorekeeper — a fixed point that tells you where you actually are." The
   system therefore has no gradients, no shadows that imply depth for its own
   sake, no motion, and no urgency. Operational density is a feature (§38.5).
   ===================================================================== */

:root {
  /* §38.4 — sampled from the mark, so every surface and the emblem belong
     to one system.

     SAMPLED, now, rather than chosen to go with it. These were an
     educated guess made against a placeholder drawing, and when the real
     mark arrived nothing compared the two: the blues were a shade off and
     the mark had no amber in it at all. The values below are read off the
     actual logo file — cyan through blue, with a white tower and a white
     light — so the claim this comment makes is true. */
  --navy-900:      #0A3C66;
  --navy-700:      #11558C;
  --beacon-blue:   #0192F9;
  --signal-cyan:   #01BFF9;
  --parchment:     #F7F5F0;
  --ink:           #1B2430;
  --muted:         #5A6775;

  /* NOT from the mark, and labelled so.

     The mark is two blues and white. This platform still needs a colour
     that means "look at this", and borrowing one of the two blues for it
     would make an attention state indistinguishable from a brand
     surface. So the amber is a functional colour chosen to read clearly
     against the parchment and to remain legible to the common forms of
     colour blindness — and it is never presented as a brand colour,
     because it is not one. The old name claimed it came from the
     lighthouse lantern; the lantern is white. */
  --attention:     #B8761B;
  /* Kept as an alias: every screen and every sealed artifact already
     refers to it by the old name, and a sealed deliverable must render
     in five years exactly as it rendered when it was hashed. Renaming a
     token a sealed document depends on is a change to that document. */
  --lantern-amber: var(--attention);

  /* Derived neutrals. Not in §38.4, so they are expressed in terms of the
     tokens that are, rather than invented as new brand colours. */
  --rule:          #D9D4CA;
  --rule-strong:   #B9B2A4;
  --surface:       #FFFFFF;
  --surface-sunk:  #EFECE4;

  /* An institutional theme may set --accent and nothing else (§38.6).
     It defaults to the beacon blue. */
  --accent: var(--beacon-blue);

  /* §38.5 — editorial serif for display, humanist sans for interface,
     monospace for contract numbers, form numbers and hashes. System stacks:
     a web font is a network dependency and a privacy question, and neither is
     worth it for an operational tool. */
  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua",
           Georgia, "Times New Roman", serif;
  --sans:  "Segoe UI", Roboto, -apple-system, BlinkMacSystemFont, "Helvetica Neue",
           Arial, sans-serif;
  --mono:  ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
           "Liberation Mono", monospace;

  /* §38.5 — a four-pixel spacing base. */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;

  /* §38.5 — reading surfaces capped at roughly sixty-eight characters. */
  --measure: 68ch;
}

/* ---------------------------------------------------------------------
   §38.4 CONTROL — status semantics are FIXED and not alterable by any
   tenant theme. They are declared here, outside the themeable block, and
   no tenant stylesheet is ever loaded after this file.

   §38.4 and §22.7 rule 9 — status is NEVER conveyed by colour alone.
   Colour, icon and text label always travel together, for accessibility
   and for printing. The .chip markup enforces that: the icon and label
   are structural, not decorative.
   --------------------------------------------------------------------- */
:root {
  --status-verified:            #1F7A5C;
  --status-reported:            #2E6FA7;
  --status-calculated:          #6B5CA5;
  --status-limited:             #B8761B;
  --status-conflicted:          #A6322B;
  --status-not-collected:       #7A8694;
  --status-not-applicable:      #9AA4B0;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.55;
  color: var(--ink);
  background: var(--parchment);
  /* §38.5 — tabular figures mandatory in every money and date column. Set at
     the root so a column cannot opt out by omission. */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

h1, h2, h3, h4 { font-family: var(--serif); font-weight: 600; line-height: 1.2;
                 margin: 0 0 var(--s3); color: var(--navy-900); }
h1 { font-size: 28px; letter-spacing: -0.01em; }
h2 { font-size: 21px; }
h3 { font-size: 17px; }
h4 { font-size: 15px; font-family: var(--sans); text-transform: uppercase;
     letter-spacing: 0.06em; color: var(--muted); font-weight: 600; }

p { margin: 0 0 var(--s4); max-width: var(--measure); }
a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { text-decoration-thickness: 2px; }

code, .mono, .num--contract, .num--hash {
  font-family: var(--mono); font-size: 0.92em;
}

/* --- skip link, because every workflow must be keyboard operable (§22.9) -- */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--navy-900); color: #fff; padding: var(--s3) var(--s4);
}
.skip:focus { left: 0; }

:focus-visible {
  outline: 3px solid var(--signal-cyan);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------
   Shell
   --------------------------------------------------------------------- */
.shell { display: flex; min-height: 100vh; }

.rail {
  flex: 0 0 232px; background: var(--navy-900); color: #fff;
  display: flex; flex-direction: column; padding: var(--s4) 0;
}
.rail__mark { display: flex; align-items: center; gap: var(--s3);
              padding: 0 var(--s4) var(--s5); }
.rail__mark svg { flex: 0 0 32px; }
.rail__wordmark { font-family: var(--serif); font-size: 15px; line-height: 1.15; }
.rail__wordmark small { display: block; font-family: var(--sans); font-size: 10px;
                        letter-spacing: 0.1em; text-transform: uppercase;
                        color: var(--signal-cyan); margin-top: 2px; }

.rail nav { display: flex; flex-direction: column; }
.rail nav a {
  color: #CFD8E3; text-decoration: none; padding: var(--s2) var(--s4);
  font-size: 14px; border-left: 3px solid transparent;
}
.rail nav a:hover { background: var(--navy-700); color: #fff; }
.rail nav a[aria-current="page"] {
  background: var(--navy-700); color: #fff;
  border-left-color: var(--lantern-amber);
}
.rail__group { padding: var(--s4) var(--s4) var(--s1); font-size: 10px;
               letter-spacing: 0.1em; text-transform: uppercase; color: #7E8EA3; }
.rail__foot { margin-top: auto; padding: var(--s4); font-size: 12px; color: #8C9AAD;
              border-top: 1px solid var(--navy-700); }

.main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  background: var(--surface); border-bottom: 1px solid var(--rule);
  padding: var(--s3) var(--s5); display: flex; align-items: center; gap: var(--s4);
}
.topbar__title { font-family: var(--serif); font-size: 17px; color: var(--navy-900); }
.topbar__spacer { flex: 1 1 auto; }
.topbar__who { font-size: 13px; color: var(--muted); text-align: right; line-height: 1.3; }
.topbar__who strong { display: block; color: var(--ink); font-weight: 600; }

.content { padding: var(--s5); flex: 1 1 auto; }
.content--reading { max-width: calc(var(--measure) + var(--s8)); }

/* A partner logo sits in the designated position and never replaces the mark
   or the attribution (§38.6). */
.partner { display: flex; align-items: center; gap: var(--s3);
           padding: var(--s3) var(--s4); border-top: 1px solid var(--navy-700);
           margin-top: var(--s3); }
.partner img { max-height: 24px; max-width: 120px; }
.partner span { font-size: 11px; color: #8C9AAD; }

/* ---------------------------------------------------------------------
   Cards, tables, panels
   §38.5 — "Tables are tables, not cards — operational density is a feature."
   --------------------------------------------------------------------- */
.panel { background: var(--surface); border: 1px solid var(--rule);
         margin-bottom: var(--s5); }
.panel__head { padding: var(--s3) var(--s4); border-bottom: 1px solid var(--rule);
               display: flex; align-items: baseline; gap: var(--s3); }
.panel__head h2, .panel__head h3 { margin: 0; }
.panel__head .spacer { flex: 1 1 auto; }
.panel__body { padding: var(--s4); }
.panel__body--flush { padding: 0; }
.panel__note { padding: var(--s3) var(--s4); background: var(--surface-sunk);
               border-top: 1px solid var(--rule); font-size: 13px; color: var(--muted); }

table.grid { width: 100%; border-collapse: collapse; font-size: 14px; }
table.grid th, table.grid td {
  text-align: left; padding: var(--s2) var(--s4);
  border-bottom: 1px solid var(--rule); vertical-align: top;
}
table.grid thead th {
  background: var(--navy-700); color: #fff; font-weight: 600; font-size: 12px;
  letter-spacing: 0.04em; text-transform: uppercase;
  position: sticky; top: 0;   /* §22.5 — sticky header on dense grids */
}
table.grid tbody tr:hover { background: var(--parchment); }
table.grid td.num, table.grid th.num { text-align: right; white-space: nowrap; }
table.grid caption { caption-side: top; text-align: left; padding: 0 0 var(--s2);
                     font-size: 13px; color: var(--muted); }

.num { font-variant-numeric: tabular-nums; }
.num--money, .num--rate { white-space: nowrap; }
.num--empty { color: var(--muted); }

dl.facts { display: grid; grid-template-columns: minmax(140px, 220px) 1fr;
           gap: var(--s2) var(--s4); margin: 0; font-size: 14px; }
dl.facts dt { color: var(--muted); }
dl.facts dd { margin: 0; }

/* ---------------------------------------------------------------------
   §38.7 COMPONENT ONE — the evidence chip.

   "Appears beside every material number, everywhere. Shows status, source
   and date; opens the source at the exact page with the passage
   highlighted. A number that cannot carry one cannot be displayed as a
   fact."

   Colour, icon and label together (§38.4 CONTROL). The ::before carries a
   glyph so the meaning survives greyscale printing and colour-blindness.
   --------------------------------------------------------------------- */
.chip {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; line-height: 1.4; padding: 1px 7px 1px 5px;
  border: 1px solid currentColor; border-radius: 2px;
  text-decoration: none; white-space: nowrap; vertical-align: 1px;
  font-family: var(--sans); font-variant-numeric: normal;
}
.chip::before { font-size: 11px; font-weight: 700; }
.chip__label { font-weight: 600; }
.chip__meta  { opacity: 0.85; font-weight: 400; }

.chip--verified       { color: var(--status-verified); }
.chip--verified::before { content: "✓"; }
.chip--reported       { color: var(--status-reported); }
.chip--reported::before { content: "i"; }
.chip--calculated     { color: var(--status-calculated); }
.chip--calculated::before { content: "ƒ"; }
.chip--limited        { color: var(--status-limited); }
.chip--limited::before { content: "!"; }
.chip--conflicted     { color: var(--status-conflicted); }
.chip--conflicted::before { content: "✕"; }
.chip--not-collected  { color: var(--status-not-collected); }
.chip--not-collected::before { content: "◦"; }
.chip--not-applicable { color: var(--status-not-applicable); }
.chip--not-applicable::before { content: "–"; }

a.chip:hover { background: currentColor; }
a.chip:hover .chip__label, a.chip:hover .chip__meta { color: #fff; }

/* ---------------------------------------------------------------------
   §38.7 COMPONENT TWO — the calculation receipt.

   "Expands inline beside any calculated figure. Inputs with their own
   chips, rule version, parameters, rounding, build, result, warnings.
   Prints into the appendix."

   A <details> element, so it is keyboard operable and prints expanded
   without script.
   --------------------------------------------------------------------- */
.receipt { border: 1px solid var(--rule); background: var(--surface);
           margin: var(--s2) 0 var(--s4); font-size: 13px; }
.receipt > summary {
  cursor: pointer; padding: var(--s2) var(--s3); list-style: none;
  display: flex; align-items: center; gap: var(--s3);
  background: var(--surface-sunk); border-bottom: 1px solid transparent;
}
.receipt[open] > summary { border-bottom-color: var(--rule); }
.receipt > summary::-webkit-details-marker { display: none; }
.receipt > summary::before {
  content: "▸"; color: var(--status-calculated); font-size: 11px;
}
.receipt[open] > summary::before { content: "▾"; }
.receipt__formula { font-family: var(--mono); font-size: 12px; color: var(--muted); }
.receipt__result { margin-left: auto; font-weight: 600; }
.receipt__body { padding: var(--s3); }
.receipt__section { margin-bottom: var(--s3); }
.receipt__section:last-child { margin-bottom: 0; }
.receipt__section > h5 {
  margin: 0 0 var(--s1); font-size: 10px; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted); font-weight: 600;
}
.receipt table { width: 100%; border-collapse: collapse; font-size: 12px; }
.receipt table td { padding: 2px var(--s2) 2px 0; vertical-align: top; }
.receipt table td:first-child { color: var(--muted); white-space: nowrap; }
.receipt__hash { font-family: var(--mono); font-size: 11px; color: var(--muted);
                 word-break: break-all; }

/* ---------------------------------------------------------------------
   §38.7 COMPONENT THREE — the limitation block.

   "Visually distinct, non-dismissible, stating what could not be verified
   and what that means. Identical approved text in every rendering."

   There is deliberately no dismiss control and no `hidden` state: §22.7
   rule 8 forbids personalisation hiding a mandatory control alert, and
   §38.6 forbids a tenant softening or hiding a limitation.
   --------------------------------------------------------------------- */
.limitation {
  border: 1px solid var(--status-limited);
  border-left-width: 4px;
  background: #FDF8EF;
  padding: var(--s3) var(--s4);
  margin: var(--s4) 0;
  max-width: var(--measure);
}
.limitation__head {
  display: flex; align-items: center; gap: var(--s2);
  font-weight: 600; color: #8A5912; margin-bottom: var(--s1);
  font-size: 13px; letter-spacing: 0.02em;
}
.limitation__head::before { content: "!"; font-weight: 700; }
.limitation p { margin: 0 0 var(--s2); }
.limitation p:last-child { margin-bottom: 0; }
.limitation--conflict { border-color: var(--status-conflicted); background: #FDF2F1; }
.limitation--conflict .limitation__head { color: #7F2620; }
.limitation--conflict .limitation__head::before { content: "✕"; }

/* ---------------------------------------------------------------------
   Refusals. DECISION 14 and CAL-1 — "a refusal is a valid, displayable
   result", so it has a presentation of its own rather than being rendered
   as an error or an empty cell.
   --------------------------------------------------------------------- */
.refusal { border: 1px dashed var(--rule-strong); background: var(--surface-sunk);
           padding: var(--s3); font-size: 13px; margin: var(--s2) 0; }
.refusal__code { font-family: var(--mono); font-size: 11px; color: var(--status-limited);
                 letter-spacing: 0.04em; }
.refusal__reason { margin: var(--s1) 0; }
.refusal__remedy { color: var(--muted); }

/* ---------------------------------------------------------------------
   State pills for the seven independent dimensions (§21.1). Shown
   together, because "the interface can always explain all current
   blockers simultaneously rather than only the first."
   --------------------------------------------------------------------- */
.states { display: flex; flex-wrap: wrap; gap: var(--s2); margin: 0; padding: 0;
          list-style: none; }
.states li { font-size: 11px; border: 1px solid var(--rule-strong);
             background: var(--surface); padding: 1px var(--s2); }
.states li b { color: var(--muted); font-weight: 600; text-transform: uppercase;
               letter-spacing: 0.05em; font-size: 10px; }
.states li.is-blocking { border-color: var(--status-conflicted);
                         color: var(--status-conflicted); }
.states li.is-attention { border-color: var(--status-limited);
                          color: #8A5912; }
.states li.is-done { border-color: var(--status-verified); color: var(--status-verified); }

/* --- the three clocks (§12.4), displayed separately and never summed --- */
.clocks { display: flex; gap: var(--s5); font-size: 13px; }
.clocks div { display: flex; flex-direction: column; }
.clocks b { font-size: 10px; text-transform: uppercase; letter-spacing: 0.07em;
            color: var(--muted); font-weight: 600; }

/* ---------------------------------------------------------------------
   Forms, buttons
   --------------------------------------------------------------------- */
label { display: block; font-size: 13px; font-weight: 600; margin-bottom: var(--s1); }
.hint { font-size: 12px; color: var(--muted); font-weight: 400; margin-top: 2px; }

input[type="text"], input[type="email"], input[type="password"], input[type="date"],
input[type="number"], select, textarea {
  width: 100%; padding: var(--s2) var(--s3); font: inherit; color: var(--ink);
  background: var(--surface); border: 1px solid var(--rule-strong); border-radius: 2px;
}
input:focus, select:focus, textarea:focus { border-color: var(--accent); }
/* ---------------------------------------------------------------------
   Form fields.

   `.field` is a <label> wrapping a caption, a control and a line of
   help. A label is inline by default, so without the block rules below
   the three run together into a single sentence — "The six-digit code
   [input] Codes change every thirty seconds" — which is how every form
   built on this pattern was rendering, on several screens, for as long
   as the pattern has existed.

   It looked like a layout preference nobody had got to. It was a class
   that had never been styled at all.
   --------------------------------------------------------------------- */
.field {
  display: block;
  margin-bottom: var(--s4);
  max-width: 420px;
}
.field__label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.01em;
  margin-bottom: var(--s1);
  color: var(--ink);
}
.field > input,
.field > select,
.field > textarea {
  display: block;
  width: 100%;
}
.field__help {
  display: block;
  font-size: 12px;
  line-height: 1.5;
  color: var(--muted);
  margin-top: var(--s1);
  font-weight: 400;
}
/* Where a value was prefilled from something already on file, this says
   from what. A prefilled figure that looks typed is a figure the next
   person trusts more than its source deserves. */
.field__source {
  display: block;
  font-size: 12px;
  color: var(--beacon-blue);
  margin-top: var(--s1);
  font-weight: 400;
}
/* A checkbox reads the other way round: control first, then the words. */
.field--check {
  display: flex;
  align-items: flex-start;
  gap: var(--s2);
  max-width: 540px;
}
.field--check > input {
  width: auto;
  margin-top: 3px;
  flex: none;
}
.field--check > span {
  font-size: 13px;
  line-height: 1.5;
  font-weight: 400;
}
.input--narrow { max-width: 9rem; }
.inline-form { display: flex; gap: var(--s2); align-items: center; }
.inline-form input { margin: 0; }

.btn {
  display: inline-flex; align-items: center; gap: var(--s2);
  font: inherit; font-weight: 600; font-size: 14px;
  padding: var(--s2) var(--s4); border: 1px solid var(--navy-900);
  background: var(--navy-900); color: #fff; cursor: pointer; border-radius: 2px;
  text-decoration: none;
}
.btn:hover { background: var(--navy-700); border-color: var(--navy-700); }
.btn--secondary { background: var(--surface); color: var(--navy-900); }
.btn--secondary:hover { background: var(--parchment); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }
.btn-row { display: flex; gap: var(--s3); align-items: center; margin-top: var(--s4); }

/* §22.7 rule 5 — a destructive action requires typed confirmation and is
   never the default focus. */
.btn--destructive { background: var(--surface); color: var(--status-conflicted);
                    border-color: var(--status-conflicted); }
.btn--destructive:hover { background: var(--status-conflicted); color: #fff; }

/* ---------------------------------------------------------------------
   §22.7 rule 6 — "Empty states explain what will appear and what to do."
   --------------------------------------------------------------------- */
.empty { border: 1px dashed var(--rule-strong); padding: var(--s5);
         text-align: left; color: var(--muted); background: var(--surface); }
.empty h3 { color: var(--ink); }
.empty p { margin-bottom: var(--s2); }

/* --- release check results --- */
.checks { list-style: none; margin: 0; padding: 0; }
.checks li { display: flex; align-items: baseline; gap: var(--s3);
             padding: var(--s2) 0; border-bottom: 1px solid var(--rule); }
.checks li:last-child { border-bottom: 0; }
.checks li::before { font-weight: 700; width: 1.2em; }
.checks li.pass::before { content: "✓"; color: var(--status-verified); }
.checks li.fail::before { content: "✕"; color: var(--status-conflicted); }
.checks li.fail { color: var(--status-conflicted); }

/* --- the stop control banner: mandatory, non-dismissible (§22.7 rule 8) --- */
.stop-banner {
  background: var(--status-conflicted); color: #fff;
  padding: var(--s3) var(--s5); font-size: 14px;
  display: flex; align-items: baseline; gap: var(--s3);
}
.stop-banner strong { font-size: 13px; letter-spacing: 0.06em; text-transform: uppercase; }

/* --- honest degradation notice, for a control the deployment cannot meet --- */
.honest-note {
  border: 1px solid var(--rule-strong); border-left: 4px solid var(--muted);
  background: var(--surface); padding: var(--s3) var(--s4); font-size: 13px;
  margin: var(--s4) 0; max-width: var(--measure);
}
.honest-note h4 { margin-bottom: var(--s1); }

/* ---------------------------------------------------------------------
   §22.8 — mobile supports capture, messages, task action and approvals
   that do not require document comparison. Large-table analysis and
   document comparison remain desktop surfaces, "and the platform says so
   rather than degrading silently into an unusable layout."
   --------------------------------------------------------------------- */
.desktop-only-note { display: none; }

@media (max-width: 860px) {
  .shell { flex-direction: column; }
  .rail { flex: 0 0 auto; flex-direction: row; align-items: center;
          overflow-x: auto; padding: var(--s2); }
  .rail nav { flex-direction: row; }
  .rail__group, .rail__foot, .partner { display: none; }
  .rail__mark { padding: 0 var(--s3) 0 var(--s2); }
  .content { padding: var(--s4); }
  dl.facts { grid-template-columns: 1fr; gap: 0 0; }
  dl.facts dt { margin-top: var(--s3); }
  .clocks { flex-direction: column; gap: var(--s2); }

  /* Say so, rather than degrade silently. */
  .desktop-only { display: none; }
  .desktop-only-note { display: block; border: 1px dashed var(--rule-strong);
                       padding: var(--s4); font-size: 13px; color: var(--muted);
                       background: var(--surface); }
}

/* ---------------------------------------------------------------------
   Print. §17.3 requires the limitation block and the receipt to render
   identically in the printed document, and §22.9 requires real text
   rather than flattened images of tables.
   --------------------------------------------------------------------- */
@media print {
  body { background: #fff; font-size: 11pt; }
  .rail, .topbar, .btn, .btn-row, .skip { display: none !important; }
  .content { padding: 0; }
  .panel { border-color: #999; break-inside: avoid; }
  /* Receipts print expanded, into the appendix. */
  .receipt { break-inside: avoid; }
  .receipt > summary { background: #f2f2f2; }
  .receipt:not([open]) .receipt__body { display: block; }
  /* The limitation block is non-dismissible and prints in full. */
  .limitation { border-color: #000; background: #fff; break-inside: avoid; }
  a[href^="/"]::after { content: ""; }
  .chip { border-color: #000; color: #000 !important; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* =====================================================================
   The presentation plane
   ---------------------------------------------------------------------
   §4.1 — a separate surface from the secure application, and it looks
   like one. Light, wide, readable; no dense data tables, because there
   is no client data here to put in one.

   §38.7 — the status semantics defined above are NOT reused here. A
   public figure has no verification status, and borrowing the visual
   language of a verified finding for a figure a visitor typed from
   memory would be the most consequential dishonesty in the product.
   ===================================================================== */

body.pub {
  background: var(--parchment);
  color: var(--ink);
}

.pub-wrap {
  width: 100%;
  max-width: 1080px;
  margin-inline: auto;
  padding-inline: var(--s5);
}

/* ---- header ---- */

.pub-head {
  background: var(--navy-900);
  border-bottom: 3px solid var(--signal-cyan);
}

.pub-head__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s5);
  min-height: 76px;
  flex-wrap: wrap;
}

.pub-brand {
  display: flex;
  align-items: center;
  gap: var(--s3);
  color: #fff;
  text-decoration: none;
  font-family: var(--serif);
  font-size: 18px;
  line-height: 1.15;
}

.pub-brand small {
  display: block;
  font-family: var(--sans);
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--signal-cyan);
  margin-top: 3px;
}

.pub-nav {
  display: flex;
  align-items: center;
  gap: var(--s5);
}

.pub-nav a:not(.btn) {
  color: #cfe0f2;
  text-decoration: none;
  font-size: 14px;
  padding-block: var(--s2);
  border-bottom: 2px solid transparent;
}

.pub-nav a:not(.btn):hover { color: #fff; }
.pub-nav a[aria-current="page"] {
  color: #fff;
  border-bottom-color: var(--lantern-amber);
}

.pub-main { padding-block: var(--s7) var(--s8); }

/* ---- the lede ---- */

.pub-lede { max-width: var(--measure); }

.pub-lede h1 {
  font-family: var(--serif);
  font-size: clamp(27px, 3.4vw, 40px);
  line-height: 1.12;
  letter-spacing: -0.01em;
  margin: 0 0 var(--s4);
}

.pub-lede__sub {
  font-size: 18px;
  line-height: 1.5;
  color: var(--muted);
  margin: 0 0 var(--s5);
}

.pub-eyebrow {
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--beacon-blue);
  font-weight: 600;
  margin: 0 0 var(--s3);
}

/* ---- the tool grid ---- */

.pub-grid {
  display: grid;
  gap: var(--s4);
  grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));
  margin-block: var(--s5);
}

.pub-card {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: var(--s5);
  text-decoration: none;
  color: inherit;
  transition: border-color .12s ease, transform .12s ease;
}

.pub-card:hover {
  border-color: var(--beacon-blue);
  transform: translateY(-1px);
}

.pub-card h3 {
  font-family: var(--serif);
  font-size: 19px;
  margin: 0;
}

.pub-card__q {
  font-size: 14px;
  color: var(--ink);
  margin: 0;
}

.pub-card__meta {
  margin-top: auto;
  padding-top: var(--s3);
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
  border-top: 1px solid var(--surface-sunk);
}

/* ---- the form ---- */

.pub-form {
  display: grid;
  gap: var(--s5);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: var(--s5);
}

.pub-field { display: flex; flex-direction: column; gap: var(--s2); }

.pub-field > label {
  font-size: 13px;
  font-weight: 600;
  line-height: 1.35;
}

.pub-field input,
.pub-field select {
  font: inherit;
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  padding: 9px 11px;
  border: 1px solid var(--rule-strong);
  border-radius: 2px;
  background: var(--surface);
  color: var(--ink);
  width: 100%;
}

.pub-field input:focus,
.pub-field select:focus {
  outline: 2px solid var(--beacon-blue);
  outline-offset: -1px;
  border-color: var(--beacon-blue);
}

.pub-field__help { font-size: 12px; color: var(--muted); margin: 0; }

.pub-field__suffix {
  font-size: 12px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.pub-field__error {
  font-size: 12.5px;
  color: var(--status-conflicted);
  margin: 0;
  font-weight: 600;
}

.pub-field--wide { grid-column: 1 / -1; }

.pub-form__actions { grid-column: 1 / -1; }

/* ---- the answer ---- */

.pub-answer {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-top: 3px solid var(--beacon-blue);
  border-radius: 3px;
  padding: var(--s5) var(--s5) var(--s6);
  margin-block: var(--s6);
}

.pub-answer__figure {
  font-family: var(--serif);
  font-size: clamp(32px, 5vw, 48px);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  margin: 0;
}

.pub-answer__label {
  font-size: 14px;
  color: var(--muted);
  margin: var(--s2) 0 0;
}

.pub-working {
  margin: var(--s5) 0 0;
  border-top: 1px solid var(--surface-sunk);
}

.pub-working div {
  display: flex;
  justify-content: space-between;
  gap: var(--s4);
  padding: 7px 0;
  border-bottom: 1px solid var(--surface-sunk);
  font-size: 14px;
}

.pub-working dt { color: var(--muted); margin: 0; }
.pub-working dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
  text-align: right;
  font-weight: 600;
}

.pub-points { margin: var(--s5) 0 0; padding: 0; list-style: none; }

.pub-points li {
  position: relative;
  padding-left: var(--s5);
  margin-bottom: var(--s3);
  font-size: 14.5px;
  line-height: 1.55;
  max-width: var(--measure);
}

.pub-points li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .55em;
  width: 10px;
  height: 2px;
  background: var(--beacon-blue);
}

/* The questions to put to a carrier. Amber, because the specification
   reserves amber for a limitation and "you need to ask somebody else"
   is precisely that. */
.pub-ask {
  margin-block: var(--s5);
  padding: var(--s5);
  background: #FDF8EC;
  border: 1px solid #E8D5A3;
  border-left: 3px solid var(--lantern-amber);
  border-radius: 2px;
}

.pub-ask h3 {
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  margin: 0 0 var(--s3);
  color: #8A6410;
}

.pub-ask ol { margin: 0; padding-left: var(--s5); }
.pub-ask li { margin-bottom: var(--s2); font-size: 14.5px; line-height: 1.5; }

/* What the answer is NOT. Deliberately not styled as fine print: it is
   load-bearing, so it reads at the same size as the answer's own points. */
.pub-not {
  margin-block: var(--s5);
  padding: var(--s4) var(--s5);
  background: var(--surface-sunk);
  border-left: 3px solid var(--muted);
  font-size: 14.5px;
  line-height: 1.55;
  max-width: var(--measure);
}

.pub-not strong { display: block; margin-bottom: var(--s1); }

.pub-source {
  font-size: 12px;
  color: var(--muted);
  margin-top: var(--s5);
}

.pub-source code {
  font-family: var(--mono);
  font-size: 11.5px;
  background: var(--surface-sunk);
  padding: 1px 5px;
  border-radius: 2px;
}

/* ---- footer ---- */

.pub-foot {
  border-top: 1px solid var(--rule);
  background: var(--surface);
  padding-block: var(--s6);
  margin-top: var(--s8);
}

.pub-foot p {
  font-size: 13px;
  line-height: 1.55;
  color: var(--muted);
  max-width: var(--measure);
  margin: 0 0 var(--s3);
}

.pub-foot__meta { font-size: 12px; }
.pub-foot a { color: var(--beacon-blue); }

@media (max-width: 640px) {
  .pub-wrap { padding-inline: var(--s4); }
  .pub-main { padding-block: var(--s5) var(--s6); }
  .pub-form { padding: var(--s4); }
  .pub-answer { padding: var(--s4); }
}

/* =====================================================================
   The reader — §9.4
   ---------------------------------------------------------------------
   The page on the left at a size worth reading, the capture form on the
   right. They are side by side because they are one action: a layout
   that made the reviewer scroll between the page and the form would be
   a layout that encouraged capturing from memory.
   ===================================================================== */

.reader {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 420px;
  gap: var(--s5);
  align-items: start;
}

.reader__pagebar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4);
  padding-bottom: var(--s3);
  margin-bottom: var(--s3);
  border-bottom: 1px solid var(--rule);
}

.reader__canvas {
  position: relative;
  display: block;
  background: var(--surface-sunk);
  border: 1px solid var(--rule-strong);
  /* The drag is the primary interaction, so the cursor says so and the
     browser's own text selection is kept out of the way. */
  cursor: crosshair;
  user-select: none;
  touch-action: none;
  line-height: 0;
}

.reader__canvas img { width: 100%; height: auto; display: block; }

/* The live drag. */
.reader__sel {
  position: absolute;
  border: 2px solid var(--beacon-blue);
  background: rgba(11, 132, 227, .14);
  pointer-events: none;
}

/* An anchor already captured. Amber, and labelled, so a reviewer can see
   at a glance what has been taken from this page and what has not. */
.reader__anchor {
  position: absolute;
  border: 2px solid var(--lantern-amber);
  background: rgba(236, 183, 47, .12);
  pointer-events: auto;
}

.reader__anchor span {
  position: absolute;
  top: -1px;
  left: -1px;
  transform: translateY(-100%);
  background: var(--lantern-amber);
  color: #3A2B05;
  font-size: 10px;
  letter-spacing: .04em;
  line-height: 1.6;
  padding: 0 5px;
  white-space: nowrap;
  font-family: var(--sans);
}

/* An anchor with no value attached is a loose end, not a capture. */
.reader__anchor.is-orphan {
  border-color: var(--status-conflicted);
  background: rgba(166, 50, 43, .10);
}
.reader__anchor.is-orphan span {
  background: var(--status-conflicted);
  color: #fff;
}

.reader__text {
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.5;
  white-space: pre-wrap;
  background: var(--surface);
  border: 1px solid var(--rule);
  padding: var(--s4);
  max-height: 60vh;
  overflow: auto;
  user-select: text;
}

.reader__side { display: flex; flex-direction: column; gap: var(--s4); }

.reader__list { list-style: none; margin: 0; padding: 0; }

.reader__list li {
  padding: var(--s3) 0;
  border-bottom: 1px solid var(--surface-sunk);
}
.reader__list li:last-child { border-bottom: 0; }

.reader__list .num {
  float: right;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.reader__list p { margin: var(--s1) 0 0; }

@media (max-width: 1100px) {
  .reader { grid-template-columns: minmax(0, 1fr); }
  .reader__side { order: -1; }
}

/* =====================================================================
   Utilities
   ---------------------------------------------------------------------
   These exist because the application sets a deliberately strict
   Content-Security-Policy with `style-src 'self'`, which blocks every
   style="..." attribute in markup. The templates had been written with
   inline styles, so the browser was silently discarding them and the
   pages were rendering unstyled in ways nobody noticed until a headless
   browser was pointed at them with the console open.

   The fix is these classes rather than 'unsafe-inline'. §28.7 holds that
   a posture is established by implemented controls, and a CSP relaxed to
   make a layout work is not an implemented control.

   Genuinely dynamic geometry — an anchor rectangle whose position is
   data — is applied through the CSSOM in JavaScript, which CSP does not
   govern, and never through a style attribute.
   ===================================================================== */

.u-flush      { margin: 0; }
.u-stack-1    { margin-top: var(--s2); }
.u-stack-2    { margin-top: var(--s3); }
.u-stack-3    { margin-top: var(--s4); }
.u-stack-4    { margin-top: var(--s5); }
.u-gap-below  { margin-bottom: var(--s4); }
.u-gap-below-lg { margin-bottom: var(--s5); }
.u-inline-gap { margin-right: var(--s2); }
.u-measure    { max-width: var(--measure); }
.u-scroll-x   { overflow-x: auto; }
.u-tiny       { font-size: 11px; }
.u-small      { font-size: 12px; }
.u-lede       { font-size: 21px; }
.u-title      { font-size: 24px; margin-bottom: var(--s1); }
.u-inherit    { color: inherit; }
.u-conflict   { color: var(--status-conflicted); }
.u-limited    { color: var(--status-limited); }
.u-sunk       { background: var(--surface-sunk); }
.u-chiplet    { font-size: 12px; padding: 2px 8px; }
.u-row        { display: flex; flex-wrap: wrap; gap: var(--s2); }

.u-pre {
  font-size: 11px;
  overflow: auto;
  margin: 0;
}

.u-sub {
  color: var(--muted);
  margin-bottom: var(--s5);
}

.u-emphatic {
  font-size: 16px;
  color: var(--ink);
}

/* A header cell rotated to keep a wide permission matrix readable. */
.u-vertical {
  writing-mode: vertical-rl;
  text-orientation: mixed;
  height: 150px;
}

/* The first column of a wide table, pinned while the rest scrolls. */
.u-sticky-col {
  position: sticky;
  left: 0;
  background: var(--surface);
}
.u-sticky-col--head {
  position: sticky;
  left: 0;
  background: var(--navy-700);
}

.u-centre { text-align: center; }
.u-deny   { background: #FDF2F1; }

/* The sign-in card. */
.u-centre-viewport {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s5);
}
.u-card-width { width: 100%; max-width: 420px; }
.u-navy       { background: var(--navy-900); }

.u-brand-row {
  display: flex;
  align-items: center;
  gap: var(--s3);
  margin-bottom: var(--s5);
  color: #fff;
}

.u-brand-name {
  font-family: var(--serif);
  font-size: 19px;
  line-height: 1.15;
}

.u-brand-tag {
  display: block;
  font-family: var(--sans);
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--signal-cyan);
  margin-top: 3px;
}

/* The policy simulator's matrix. Three outcomes, three appearances: an
   explicit denial is bolder than a mere absence of a grant, because
   §22.2 makes denials non-overridable and that difference matters. */
.cell-allowed { color: var(--status-verified); }
.cell-denied  { color: var(--status-conflicted); font-weight: 700; }
.cell-absent  { color: var(--muted); }

/* =====================================================================
   Workflow state — deliberately NOT the status chips
   ---------------------------------------------------------------------
   §38.7 locks the status semantics: verified, reported, calculated,
   limited, conflicted, not-collected. Those describe how much is known
   about a FACT.

   A deliverable being draft, approved or released describes where it has
   got to in a PROCESS, which is a different kind of claim entirely.
   Giving "approved" the green tick that means "verified" would quietly
   suggest the contents had been checked against evidence, when what has
   happened is that a second person signed it off. So workflow state gets
   its own, flatter vocabulary, and the two cannot be confused at a
   glance.
   ===================================================================== */

.state {
  display: inline-block;
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 2px;
  border: 1px solid var(--rule-strong);
  color: var(--muted);
  background: var(--surface-sunk);
  white-space: nowrap;
}

.state--draft      { }
.state--approved   { border-color: var(--navy-700); color: var(--navy-700); background: #EDF3FA; }
.state--released   { border-color: var(--navy-900); color: #fff; background: var(--navy-900); }
.state--superseded { text-decoration: line-through; }
.state--withdrawn  { border-color: var(--status-conflicted); color: var(--status-conflicted); background: #FDF2F1; }

/* =====================================================================
   Intake — the four doors
   ---------------------------------------------------------------------
   Each door is a card rather than a line in a dropdown, because the
   consequences differ and a dropdown hides them. Somebody choosing
   "archive acquisition" should be able to see, at the moment of
   choosing, that it means no carrier will ever be contacted.
   ===================================================================== */

.doors { display: grid; gap: var(--s3); }

.door {
  display: flex;
  gap: var(--s3);
  align-items: flex-start;
  padding: var(--s4);
  border: 1px solid var(--rule);
  border-radius: 3px;
  background: var(--surface);
  cursor: pointer;
}

.door:hover { border-color: var(--rule-strong); }

.door:has(input:checked) {
  border-color: var(--beacon-blue);
  box-shadow: inset 0 0 0 1px var(--beacon-blue);
  background: #F7FBFF;
}

.door input { margin-top: 3px; flex: none; }

.door__body { display: block; }

.door__note,
.door__facts {
  display: block;
  font-size: 13px;
  line-height: 1.5;
  color: var(--muted);
  margin-top: var(--s1);
  max-width: var(--measure);
}

/* The consequences, set apart from the description so they read as
   facts about what this choice permits rather than as more prose. */
.door__facts {
  margin-top: var(--s2);
  font-size: 12px;
  color: var(--navy-700);
  letter-spacing: .01em;
}

/* =====================================================================
   The carrier desk
   ---------------------------------------------------------------------
   A list rather than a table, because each row carries the questions
   themselves and the reason a request cannot be sent. Those are the two
   things a person needs to act on, and a table would push both into a
   tooltip.
   ===================================================================== */

.desk-list { list-style: none; margin: 0; padding: 0; }

.desk-item {
  padding: var(--s4) 0;
  border-bottom: 1px solid var(--surface-sunk);
}
.desk-item:last-child { border-bottom: 0; }

.desk-item__head,
.desk-item__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4);
  flex-wrap: wrap;
}

.desk-item__foot { margin-top: var(--s3); }

/* Why this request cannot go anywhere. Amber, because the specification
   reserves amber for a limitation, and "blocked until somebody does
   something" is exactly that. */
.desk-item__block {
  margin: var(--s3) 0 0;
  padding: var(--s3) var(--s4);
  background: #FDF8EC;
  border-left: 3px solid var(--lantern-amber);
  font-size: 13.5px;
  line-height: 1.5;
  max-width: var(--measure);
}

.desk-questions {
  margin: var(--s3) 0 0;
  padding-left: var(--s5);
  max-width: var(--measure);
}

.desk-questions li { margin-bottom: var(--s2); font-size: 14px; line-height: 1.5; }

/* Overdue earns a left edge, not a red row. A row that shouts is a row
   people stop seeing. */
.desk-item.is-overdue {
  border-left: 3px solid var(--status-conflicted);
  padding-left: var(--s4);
  margin-left: calc(var(--s4) * -1);
}

.state--drafted, .state--authorised, .state--queued { }
.state--transmitted { border-color: var(--navy-700); color: var(--navy-700); background: #EDF3FA; }
.state--escalated   { border-color: var(--status-conflicted); color: var(--status-conflicted); background: #FDF2F1; }
.state--unanswered_overdue { border-color: var(--status-limited); color: var(--status-limited); background: #FDF8EC; }

/* The reason a question is being asked, under the question rather than
   trailing it. A carrier who can see the reason answers the question
   that was meant rather than the question that was typed (§12.2). */
.desk-why {
  display: block;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--muted);
  margin-top: 2px;
}

/* =====================================================================
   The owner portal
   ---------------------------------------------------------------------
   Permissions are given the same visual weight as reviews. An owner's
   two questions are "what did you find?" and "what did I agree to?",
   and a layout that made the second a footnote would be answering only
   the one the business cares about.
   ===================================================================== */

.owner-block { margin-block: var(--s7); }

.owner-block > h2 {
  font-family: var(--serif);
  font-size: 22px;
  margin: 0 0 var(--s3);
  padding-bottom: var(--s3);
  border-bottom: 1px solid var(--rule);
}

.owner-case,
.owner-grant {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: var(--s5);
  margin-bottom: var(--s4);
}

.owner-case__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s4);
  flex-wrap: wrap;
}

.owner-case__head strong { display: block; font-size: 16px; }

.owner-case__state {
  margin: var(--s3) 0 0;
  font-size: 15px;
  line-height: 1.55;
  max-width: var(--measure);
}

.owner-reports { list-style: none; margin: var(--s4) 0 0; padding: 0; }

.owner-reports li {
  display: flex;
  align-items: center;
  gap: var(--s3);
  flex-wrap: wrap;
}

.owner-permits { margin: var(--s3) 0; padding-left: var(--s5); }
.owner-permits li { font-size: 14.5px; line-height: 1.6; }

/* A withdrawn permission stays on the list, dimmed but legible. An owner
   asking "what did I agree to?" is owed the history as well as the
   present, and removing the row would answer only half the question. */
.owner-grant.is-ended { background: var(--surface-sunk); }
.owner-grant.is-ended .owner-permits { color: var(--muted); }

.owner-withdraw {
  margin-top: var(--s4);
  padding-top: var(--s4);
  border-top: 1px solid var(--surface-sunk);
}

.owner-withdraw__row {
  display: flex;
  gap: var(--s3);
  align-items: stretch;
  margin-top: var(--s2);
  flex-wrap: wrap;
}

.owner-withdraw__row input {
  flex: 1 1 18rem;
  font: inherit;
  font-size: 14px;
  padding: 8px 11px;
  border: 1px solid var(--rule-strong);
  border-radius: 2px;
}

.owner-withdraw__row button { flex: none; }

/* The signed-in name in a portal header. A class rather than an inline
   style: `style-src 'self'` discards the attribute, and the name would
   render in body colour against the navy bar — invisible. */
.pub-nav__who { font-size: 13px; color: #cfe0f2; }

/* =====================================================================
   AB Programs — batches, items, bulk operations, queues (§19)
   ---------------------------------------------------------------------
   These reuse the FLAT workflow vocabulary (.state) rather than the fact
   status chips. A batch item is not "verified"; it is matched, or it is
   not. Borrowing the evidence vocabulary here would make a routing state
   look like an evidential one at a glance, which is exactly the
   confusion the two vocabularies exist to prevent.
   ===================================================================== */

.state--done       { border-color: var(--status-verified); color: var(--status-verified); }
.state--attention  { border-color: var(--status-limited); color: var(--status-limited);
                     background: #FDF7EC; }
.state--blocked    { border-color: var(--status-conflicted); color: var(--status-conflicted);
                     background: #FDF2F1; }

/* The reconciliation strip. Every disposition is shown, including the
   zeroes: a count that disappears when it is zero is a count nobody
   notices becoming non-zero. */
.tally {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
}
.tally div { background: var(--surface); padding: var(--s3) var(--s4); }
.tally dt {
  font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); margin: 0 0 2px;
}
.tally dd {
  margin: 0; font-size: 22px; font-variant-numeric: tabular-nums;
  font-family: var(--font-display, inherit);
}
.tally div.is-open dd    { color: var(--status-limited); }
.tally div.is-blocked dd { color: var(--status-conflicted); }

/* The capacity bar. The reserved share is drawn, not described, because
   the whole point of PRG-5 is that somebody can SEE the slots an import
   is not allowed to take. */
.capacity { display: flex; gap: 2px; margin: var(--s2) 0 0; }
.capacity span {
  flex: 1 1 0; height: 10px; border: 1px solid var(--rule-strong);
  background: var(--surface-sunk);
}
.capacity span.is-running  { background: var(--navy-700); border-color: var(--navy-700); }
.capacity span.is-reserved { background: repeating-linear-gradient(
  45deg, transparent, transparent 3px, var(--rule-strong) 3px, var(--rule-strong) 4px); }

/* The bulk workbench proposal. The exclusions sit beside the population
   at the same weight — never smaller, never below the fold. */
.proposal { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s4); }
.proposal > div { border: 1px solid var(--rule); padding: var(--s4);
                  background: var(--surface); }
.proposal .big { font-size: 34px; font-family: var(--font-display, inherit);
                 font-variant-numeric: tabular-nums; line-height: 1.1; }
.proposal .excluded { border-color: var(--status-limited); background: #FDF7EC; }

@media (max-width: 720px) { .proposal { grid-template-columns: 1fr; } }

/* Available to screen readers, absent from the page. Table captions use
   this where the surrounding panel already carries a visible heading. */
.u-visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0;
  margin: -1px; overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}

/* A detached document stays on the case, visibly set aside rather than
   removed — a figure already drawn from it still has to be explainable. */
table.grid tr.is-detached td { opacity: .62; }
table.grid tr.is-detached td:first-child { opacity: 1; }

/* =====================================================================
   Break-glass and view-as banners (migration 023)
   ---------------------------------------------------------------------
   Deliberately loud and deliberately fixed to the top of the viewport.
   Both are states somebody must not be able to forget they are in, and
   a notice that scrolls away is a notice that is only seen once.
   ===================================================================== */
.standout {
  position: sticky; top: 0; z-index: 60;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3);
  padding: var(--s3) var(--s4);
  font-size: 14px; line-height: 1.4;
  border-bottom: 2px solid rgba(0,0,0,.25);
}
.standout strong { font-weight: 700; }
.standout a { color: inherit; text-decoration: underline; }
.standout form { margin: 0 0 0 auto; }
.standout button {
  font: inherit; font-weight: 600; cursor: pointer;
  background: rgba(255,255,255,.92); color: #16202C;
  border: 0; border-radius: 2px; padding: 5px 14px;
}
.standout--viewas   { background: #4B3A7A; color: #fff; }
.standout--elevated { background: #8A2B1F; color: #fff; }

@media print { .standout { display: none; } }

/* A permission tick-box and its label stay on one line. `.u-row` wraps,
   which pushed a long label onto its own line and detached it visually
   from the box it belongs to. */
.perm { display: flex; align-items: baseline; gap: var(--s2); margin: 0 0 6px; }
.perm input { flex: 0 0 auto; margin: 0; }
.perm > span { flex: 1 1 auto; }

/* ---------------------------------------------------------------------
   Two-step sign-in.

   The QR matrix is drawn as a table of cells rather than fetched as an
   image, because the usual <img src="https://chart-api/..."> sends the
   TOTP secret to a third party in a query string. See
   AB\Modules\Identity\QrCode.

   `border-collapse` and a fixed cell size are what make a table of
   divs read as a scannable square: any gap between cells is a white
   line through the symbol, and a scanner reads a white line as a
   module boundary that is not there.
   --------------------------------------------------------------------- */
.qr {
  border-collapse: collapse;
  margin: var(--space-4) 0;
  background: #fff;
  /* The quiet zone. A QR code with no margin is one many scanners will
     not see at all — the specification requires four modules of clear
     space and most readers enforce it. */
  padding: 16px;
  border: 16px solid #fff;
  outline: 1px solid var(--rule);
}
.qr td {
  width: 5px;
  height: 5px;
  padding: 0;
  border: 0;
  line-height: 0;
  font-size: 0;
}
.qr--on  { background: #000; }
.qr--off { background: #fff; }

.secret-key code {
  display: inline-block;
  font-size: 15px;
  letter-spacing: 0.08em;
  padding: 10px 14px;
  background: var(--surface-sunk);
  border: 1px solid var(--rule);
  border-radius: 4px;
  word-break: break-all;
}

.input--code {
  font-size: 24px;
  letter-spacing: 0.35em;
  text-align: center;
  max-width: 10ch;
  font-variant-numeric: tabular-nums;
}

.recovery-codes {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: var(--space-2);
}
.recovery-codes code {
  display: block;
  font-size: 16px;
  letter-spacing: 0.06em;
  padding: 10px 12px;
  background: var(--surface-sunk);
  border: 1px solid var(--rule);
  border-radius: 4px;
}

.steps { margin: 0 0 var(--space-4); padding-left: 20px; }
.steps li { margin-bottom: 6px; }
