/* Direction A — "Quiet Official".
   Warm paper ground, one sans throughout, indigo for action, and the ISA's own
   correction red reserved strictly for filled-form previews.

   The direction originally paired a literary serif for headings with this sans for
   body. The serif was dropped 2026-08-25 in favour of a single family; the ground,
   the accent and the reserved red are unchanged. */

:root {
  --paper:   #FAF9F6;
  --surface: #FFFFFF;
  --panel:   #F2EFE7;
  --ink:     #1A1A17;
  --soft:    #4A463C;
  /*  #8A8578 until 2026-09-01, when the palette was measured rather than judged: it gave
      3.50:1 on --paper and 3.20:1 on --panel, against the 4.5:1 WCAG AA needs for text under
      18.66px. 92 rules colour text with this token and 84 of them set a size below that line
      -- including the help text under every interview question, which is the sentence
      explaining what an answer means to somebody working in a second language about their own
      immigration status.

      #706C61 gives 4.98:1 and 4.56:1. It moves 43 units of 441 in RGB distance and holds the
      same warm grey hue, so nothing about the palette's temperament changes.

      **Light only.** The dark theme redefines this token at #948F84, which already measures
      5.52:1 there, and darkening it would make it worse rather than better. */
  --muted:   #706C61;
  --faint:   #A9A395;
  --rule:    #E3DFD5;
  --line:    #D8D3C6;
  --accent:  #2E3A59;
  /*  The same two colours as channel triplets, so a gradient can fade one to alpha 0.
      **`transparent` is not the same colour with the alpha removed** -- it is
      `rgba(0,0,0,0)`, so `linear-gradient(var(--accent), transparent)` interpolates towards
      black and greys the middle of the band. Fading `rgb(R G B / .5)` to `rgb(R G B / 0)`
      keeps the hue constant the whole way down, which is what "even" means here.
      Kept beside their hex twins: two representations of one colour that must not drift. */
  --accent-rgb: 46 58 89;
  /*  The brand red, for the one rail row that names where you are rather than where you can
      go. Measured rather than judged, like --soft above: #C8102E is 5.59:1 on --paper, and
      3.02:1 on the dark ground -- a FAIL at AA, in the theme this row is most often read in.
      The dark value is #EF5F73 at 5.55:1, so the row carries the same emphasis in both
      themes instead of quietly receding in one. */
  --brand-red: #C8102E;
  --brand-red-rgb: 200 16 46;
  --preview: #C0392B;
  --warn:    #7A5A10;
  --warn-line:#E8CE86;
  --warn-bg: #FFF8E7;
  --ok:      #2F6B46;

  /* One face throughout. The display serif was dropped 2026-08-25: headings now carry
     their distinction in weight and size rather than in a second family. */
  --f-body: 'Zen Kaku Gothic New', 'Hiragino Sans', 'Noto Sans JP', system-ui, sans-serif;

  --w: 1560px;

  /* Every rail in the application, in one place. There were four numbers -- 248 on the shell,
     244 on the interview column, 236 on the reference pages, 248 again in a media query -- and
     a signed-in visitor to /wiki saw two of them side by side, 12px apart, which reads as a
     misalignment rather than as two different things. Narrowed from 248 on 2026-08-29: the
     longest label in any rail is "Experts & consultations" at 150px, and 224 clears it. */
  --rail: 224px;

  /*  Motion, 2026-09-01. Two curves and one duration scale, from Emil Kowalski's animation
      standards (github.com/emilkowalski/skill). Every transition in this stylesheet used the
      built-in `ease`, including entrances, and his decision order is explicit: entering or
      exiting wants **ease-out**, moving or morphing wants ease-in-out, and hover or colour
      keeps plain `ease`. The built-ins are also too weak to read as deliberate.

      **Never `ease-in` on UI.** It starts slow, which delays the exact moment the person is
      watching -- ease-out at 200ms *feels* faster than ease-in at 200ms. */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --press: 140ms;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper:   #17181A;
    --surface: #1D1F22;
    --panel:   #232529;
    --ink:     #E9E7E1;
    --soft:    #C6C2B8;
    --muted:   #948F84;
    --faint:   #6E6A61;
    --rule:    #2C2F34;
    --line:    #3A3E44;
    --accent:  #9DB0D6;
    --accent-rgb: 157 176 214;
    --brand-red-rgb: 239 95 115;
    --brand-red: #EF5F73;
    --preview: #E4796B;
    --warn:    #D8B36A;
    --warn-line:#5A4A22;
    --warn-bg: #26210F;
    --ok:      #7FB894;
  }
}
:root[data-theme="dark"] {
  --paper:#17181A; --surface:#1D1F22; --panel:#232529; --ink:#E9E7E1; --soft:#C6C2B8;
  --muted:#948F84; --faint:#6E6A61; --rule:#2C2F34; --line:#3A3E44; --accent:#9DB0D6;
  --accent-rgb: 157 176 214; --brand-red-rgb: 239 95 115;
  --brand-red:#EF5F73; --preview:#E4796B; --warn:#D8B36A; --warn-line:#5A4A22; --warn-bg:#26210F; --ok:#7FB894;
}

/*  Keyboard focus must not end up underneath the sticky topbar.

    `.app-top` is `position: sticky; top: 0` at `--topbar-h`, and the browser scrolls a
    tabbed-to element flush to the top of the scrollport -- which is *behind* the bar. WCAG 2.2
    **2.4.11 Focus Not Obscured (Minimum)**, level AA, and until 2026-09-01 nothing in this
    stylesheet set a scroll offset at all.

    On `html` because the document is the scrollport for the main column; the rail scrolls
    itself and needs none. The extra 12px is so the focused control clears the bar's edge
    rather than touching it, which reads as clipped even when it is technically visible.

    `scroll-behavior` is deliberately not set here: a smooth scroll on every Tab is motion on a
    keystroke, which the frequency rule in §10a of DESIGN-PRINCIPLES.md rules out. */
html { scroll-padding-top: calc(var(--topbar-h) + 12px); }

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--f-body);
  font-size: 17px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}

/* No underline anywhere, on the operator's direction 2026-08-29. Colour, weight and the
   hover state carry a link now.

   Worth stating rather than assuming, since it is the usual objection: `:focus-visible`
   below is untouched, so keyboard navigation still shows where it is, and that is the part
   of link affordance that is an accessibility requirement rather than a convention. What is
   given up is the cue a reader gets from a link in the middle of a sentence, and the places
   that matters most here -- statute, the glossary, the wiki -- are prose where the accent
   against `--ink` is a strong contrast rather than a subtle one. */
a { color: var(--accent); text-decoration: none; }
a:hover { opacity: .78; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.wrap { max-width: var(--w); margin: 0 auto; padding: 0 32px; }
/* Content grows with the window. The cap is expressed in characters rather than pixels,
   so it scales with the type size and only bites on very wide displays, where a
   200-character line would be unreadable rather than generous. */
.wrap.narrow > * { max-width: min(1104px, 100%); }

/* ---------- masthead ---------- */
.masthead {
  border-bottom: 1px solid var(--rule);
  background: var(--paper);
}
/* The masthead gets a wider track than the reading column: at 1120px the brand, seven
   nav items and the language switch could not fit, and every one of them wrapped. */
.masthead .wrap {
  /* Same track as the page content, so the brand lines up with the copy beneath it.
     The nav is sized to fit that width rather than the header being widened to fit. */
  max-width: var(--w);
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; padding-top: 18px; padding-bottom: 16px;
  flex-wrap: wrap;
}
.brand {
  /*  This row centres the MARK against the text block; `.brand-text` baselines the two
      texts to each other. Separating the two questions is the point -- one row could
      satisfy either and never both, because an image has no baseline worth aligning to and
      a small descriptor centred against a large wordmark floats above its baseline. */
  display: flex; align-items: center; gap: 10px; text-decoration: none;
  color: var(--ink); white-space: nowrap; flex-shrink: 0;
}
.brand-mark { width: 30px; height: 30px; flex: 0 0 auto; display: block; }

/*  ONE rule per selector. There were two `.brand span` rules here for most of 2026-09-03 --
    one setting `align-self`, the other size and colour. They did not conflict, which is why
    nothing looked broken, and it is still what decisions.md 2026-08-29 forbids after the
    `.side-brand` bug: "when a selector already exists, edit it. Do not add a second one
    lower down and trust the cascade to mean what you intended." The descriptor has its own
    class now, so `.brand span` matches nothing and there is nothing left to disagree. */
.brand-text { display: flex; align-items: baseline; gap: 10px; min-width: 0; }
.brand b { font-family: var(--f-body); font-size: 22px; font-weight: 500; letter-spacing: -.01em; }
.brand-desc { font-size: 13px; color: var(--muted); }

.mnav {
  display: flex; align-items: center; gap: 18px;
  flex-wrap: wrap; justify-content: flex-end; row-gap: 8px;
}
.mnav a { font-size: 14.5px; text-decoration: none; color: var(--soft); white-space: nowrap; }
.mnav a.on { color: var(--ink); border-bottom: 1px solid var(--accent); padding-bottom: 2px; }

/* ---------- grouped nav items ----------
   Documents and Guide each carry a menu. No script: the interview has to work in a
   browser without JavaScript, so the navigation does too. Hover opens it, and so does
   keyboard focus anywhere inside the group -- tabbing to the parent link reveals the
   menu, which is what makes the next Tab able to enter it. */
.mgroup { position: relative; display: inline-flex; align-items: center; }
.mgroup > a { display: inline-flex; align-items: center; gap: 4px; }

/* `on` is this link's own page; `group-on` is somewhere inside its menu. Collapsed, both
   should mark the group, because the item that is actually current is out of sight. */
.mgroup > a.group-on {
  color: var(--ink); border-bottom: 1px solid var(--accent); padding-bottom: 2px;
}
.caret { font-style: normal; font-size: 9px; color: var(--faint); transform: translateY(1px); }
.mgroup:hover .caret, .mgroup:focus-within .caret { color: var(--soft); }

/* The mouse has to cross the gap between the parent and the menu without leaving the
   group. A pseudo-element bridges it, rather than padding, which would shift the item
   inside a centre-aligned row. */
.mgroup::after {
  content: ''; position: absolute; top: 100%; left: 0; right: 0; height: 14px;
}

.mdrop {
  position: absolute; top: calc(100% + 14px); left: -14px; z-index: 40;
  display: flex; flex-direction: column; min-width: 172px;
  padding: 7px 0; background: var(--surface);
  border: 1px solid var(--line); border-radius: 2px;
  box-shadow: 0 8px 24px rgb(0 0 0 / 12%);
  opacity: 0; visibility: hidden; transform: translateY(-4px);
  transition: opacity .13s ease, transform .13s ease, visibility .13s;
}
.mgroup:hover .mdrop,
.mgroup:focus-within .mdrop { opacity: 1; visibility: visible; transform: none; }

.mdrop a { padding: 7px 16px; color: var(--soft); }
.mdrop a:hover { background: var(--panel); color: var(--ink); }
.mdrop a.on {
  color: var(--ink); border-bottom: 0; padding-bottom: 7px;
  box-shadow: inset 2px 0 0 var(--accent);
}

/* Where there is no hover -- a touch screen, whatever its width -- a menu that opens on
   hover is a menu with no way in, and the parent link swallows the tap. Flatten the group
   back to plain inline links, which is exactly the navigation this replaced. The width
   query catches a narrow window on a mouse, where the row has wrapped anyway. */
@media (hover: none), (max-width: 900px) {
  .mgroup { display: contents; }
  .mgroup::after { display: none; }
  .caret { display: none; }
  .mdrop {
    display: contents;
    position: static; opacity: 1; visibility: visible; transform: none;
    border: 0; box-shadow: none; background: none; padding: 0; min-width: 0;
  }
  .mdrop a { padding: 0; }
  /* On touch and narrow windows the menus flatten to plain inline links, so the
     sign-out form has to flatten with them -- otherwise the one row that is a <form>
     stays a block and breaks the line it sits in. It remains a POST either way. */
  .navright { margin-left: 0; }
  .mdrop-form { display: contents; }
  .mdrop-form button {
    display: inline; width: auto; padding: 0; font-size: inherit;
    color: var(--soft);
  }
  .mdrop a.on {
    box-shadow: none; border-bottom: 1px solid var(--accent); padding-bottom: 2px;
  }
  /* Flattened, the current item is visible on its own, so marking its parent as well
     underlines two things and says the page is both. Only the real one keeps the rule. */
  .mgroup > a.group-on { color: var(--soft); border-bottom: 0; padding-bottom: 0; }
}

/* Language: plain links at the head of the bar, not a segmented control at the tail.
   The control read as a setting sitting beside the account; the choice is about the whole
   page, so it goes where reading starts and looks like the other links. */
.langsw { display: inline-flex; align-items: center; gap: 16px; flex-shrink: 0; }
.langsw a {
  font-size: 14px; text-decoration: none; color: var(--muted); white-space: nowrap;
}
.langsw a:hover { color: var(--ink); }
.langsw a.on { color: var(--ink); font-weight: 600; }
/* A hairline between the two, and between the pair and the navigation after it.
   The separator is a pseudo-element in the gap, NOT padding on the anchor. Padding made
   the anchor's box wider than its text, so `.mnav a.on`'s underline -- which spans the
   box -- ran out to the left of the word and read as misaligned. Keeping the box equal
   to the text is what centres the rule. */
.langsw a { position: relative; }
.langsw a + a::before {
  /* Centred in the gap: half of it. At `left: -9px` against a 9px gap the hairline sat
     flush on the previous word, which made that word read as though it carried a trailing
     border -- the "English is shifted right" report. The rule under the active item was
     measured and is centred to within a pixel; it was the separator that was wrong. */
  content: ''; position: absolute; left: -8px; top: 2px; bottom: 2px;
  width: 1px; background: var(--line);
}
.langsw::after {
  content: ''; align-self: stretch; width: 1px; background: var(--line);
  margin: 3px 0 3px 8px;
}

/* Login / Profile, held to the right whatever sits between. */
.navright { margin-left: auto; display: inline-flex; align-items: center; flex-shrink: 0; }

/* A dropdown at the right edge must open leftward, or it opens off the viewport. */
.mdrop.right { left: auto; right: -14px; }

/* Sign-out is a POST, so the last row of the profile menu is a real form. It has to be
   indistinguishable from the links above it. */
.mdrop-form { margin: 5px 0 0; border-top: 1px solid var(--line); padding-top: 5px; }
.mdrop-form button {
  display: block; width: 100%; text-align: left; padding: 7px 16px;
  font: inherit; font-size: 15px; color: var(--soft);
  background: none; border: 0; cursor: pointer;
}
.mdrop-form button:hover { background: var(--panel); color: var(--ink); }

@media (max-width: 1080px) {
  .masthead .wrap { gap: 12px; }
  .mnav { gap: 14px; }
  .mnav a { font-size: 14.5px; }
}

/* ---------- the C direction ----------
   Adopted 2026-08-25 from design/mockups (variant C, with the controls taken down).
   Its premise: on every page except the interview step, a person's real question is
   "what do I do next", and nothing above the fold used to answer it. So a page opens
   with one band that names the next action, and nothing competes with it.

   Controls are a word and a rule rather than a filled block. The 2px accent rule marks
   the single control on a page that matters; everything else gets a hairline. What
   carries emphasis is position and rule weight, not fill. */

.band {
  display: flex; align-items: flex-start; gap: 28px;
  padding: 20px 32px 19px; background: var(--paper);
  /*  One edge, not two. `docs/DESIGN-SYSTEM.md` §4 specifies "an accent rule down the left
      edge" and its example markup carries no other border; a `border-bottom` had been added
      beside it, so the band rendered with two of four edges and read as an unfinished box
      rather than a deliberate accent. Reported from the home page, 2026-09-02.

      Removing the *left* rule instead was the other option and is worse: the band's ground
      is `--paper`, the same as the page, so with no edge at all it stops being a distinct
      element and the kicker is left floating. */
  border-left: 2px solid var(--accent);
}
.band .k {
  font-size: 11px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--accent); font-weight: 700;
}
.band .h { font-size: 22px; font-weight: 500; line-height: 1.28; margin-top: 3px; }
.band .s {
  font-size: 14.5px; color: var(--soft); margin-top: 4px; line-height: 1.6;
  max-width: 640px;
}
.band .act { margin-left: auto; flex: 0 0 auto; padding-top: 6px; }
@media (max-width: 760px) {
  .band { flex-direction: column; gap: 12px; padding: 16px 20px; }
  .band .act { margin-left: 0; padding-top: 0; }
}

.b {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: inherit; font-size: 16px; color: var(--ink); text-decoration: none;
  padding: 9px 0 8px; border: 0; background: none; cursor: pointer;
  border-bottom: 1px solid var(--line); white-space: nowrap;
}
.b:hover { opacity: 1; color: var(--accent); border-bottom-color: var(--accent); }
.b.pri { color: var(--accent); font-weight: 500; border-bottom: 2px solid var(--accent); }
.b.quiet { color: var(--muted); border-bottom-color: var(--rule); }
.b-row { display: flex; align-items: center; gap: 28px; flex-wrap: wrap; }

/* The four phases of the whole procedure, above the sixteen steps of the interview. A
   person can otherwise tell where they are in the questionnaire and nowhere else. */
.phases { display: grid; grid-template-columns: repeat(4, 1fr); border: 1px solid var(--line); background: var(--surface); }
.phases > div { padding: 14px 17px; position: relative; }
.phases > div + div { border-left: 1px solid var(--rule); }
.phases .st { font-size: 11px; letter-spacing: .13em; text-transform: uppercase; font-weight: 700; }
.phases .st.done { color: var(--ok); }
.phases .st.now  { color: var(--accent); }
.phases .st.next { color: var(--faint); }
.phases .pt { font-size: 15px; font-weight: 500; margin-top: 3px; }
.phases .pd { font-size: 13px; color: var(--muted); margin-top: 2px; line-height: 1.45; }
.phases .now-mark { position: absolute; left: 0; right: 0; bottom: -1px; height: 2px; background: var(--accent); }
@media (max-width: 860px) {
  .phases { grid-template-columns: 1fr 1fr; }
  .phases > div:nth-child(3) { border-left: 0; }
  .phases > div:nth-child(n+3) { border-top: 1px solid var(--rule); }
}

.tiles { display: grid; grid-template-columns: repeat(3, 1fr); border: 1px solid var(--line); background: var(--surface); }
.tiles > div { padding: 15px 18px; }
.tiles > div + div { border-left: 1px solid var(--rule); }
.tiles .n { font-size: 29px; font-weight: 500; line-height: 1; font-variant-numeric: tabular-nums; }
.tiles .l { font-size: 13.5px; color: var(--soft); margin-top: 5px; line-height: 1.45; }
@media (max-width: 700px) {
  .tiles { grid-template-columns: 1fr; }
  .tiles > div + div { border-left: 0; border-top: 1px solid var(--rule); }
}

/* ---------- features ---------- */
.featgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; margin-top: 24px; }
.featcard { padding: 20px 24px 22px; border-top: 1px solid var(--rule); }
.featcard:nth-child(3n+2), .featcard:nth-child(3n) { border-left: 1px solid var(--rule); }
.featcard h3 { font-size: 16.5px; font-weight: 500; margin: 0 0 5px; }
.featcard p { font-size: 14.5px; color: var(--soft); line-height: 1.7; margin: 0; }
.featgrid.refuses .featcard h3 { color: var(--warn); }
@media (max-width: 880px) {
  .featgrid { grid-template-columns: 1fr; }
  .featcard { border-left: 0 !important; }
}

/* ---------- pricing ---------- */
.tiers { display: grid; grid-template-columns: repeat(4, 1fr); border: 1px solid var(--line); background: var(--surface); margin-top: 24px; }
.tier { padding: 20px 20px 22px; display: flex; flex-direction: column; }
.tier + .tier { border-left: 1px solid var(--rule); }
.tier.pick { background: rgba(46, 58, 89, .045); }
.tnm { font-size: 17px; font-weight: 500; }
.tpr { font-size: 27px; font-weight: 500; margin-top: 9px; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
.tpr small { font-size: 13px; font-weight: 400; color: var(--muted); letter-spacing: 0; }
.tier dl { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; margin: 14px 0 0; font-size: 13.5px; }
.tier dt { color: var(--muted); }
.tier dd { margin: 0; font-variant-numeric: tabular-nums; }
.tnote { font-size: 13px; color: var(--muted); line-height: 1.6; margin: 12px 0 0; }
.tact { margin-top: auto; padding-top: 16px; }
@media (max-width: 900px) {
  .tiers { grid-template-columns: 1fr 1fr; }
  .tier:nth-child(3) { border-left: 0; }
  .tier:nth-child(n+3) { border-top: 1px solid var(--rule); }
}

/* The ladder. `pays` is the one rung where money moves the other way, and it is marked
   because a reader scanning a price list does not expect a row that pays them. */
.rung {
  display: grid; grid-template-columns: 58px 1fr 180px 150px; gap: 0 16px;
  align-items: baseline; padding: 13px 0; border-bottom: 1px solid var(--rule);
}
.rung:first-of-type { border-top: 1px solid var(--line); }
.rid { font-size: 14px; font-weight: 700; color: var(--accent); font-variant-numeric: tabular-nums; }
.rnm { font-size: 15.5px; font-weight: 500; }
.rbody { font-size: 13.5px; color: var(--soft); line-height: 1.6; margin-top: 2px; max-width: 620px; }
.rpr { font-size: 14px; font-variant-numeric: tabular-nums; }
.rdir { font-size: 12.5px; color: var(--muted); }
.rung.pays .rdir { color: var(--ok); }
@media (max-width: 820px) {
  .rung { grid-template-columns: 46px 1fr; }
  .rpr, .rdir { grid-column: 2; font-size: 13px; }
}

/* The reference window's output. Monospace because a passport number is read character
   by character and a proportional face invites a misread between 0 and O. */
.refbox {
  font-family: 'DejaVu Sans Mono', ui-monospace, Menlo, Consolas, monospace;
  font-size: 14px; line-height: 1.75; white-space: pre-wrap; word-break: break-word;
  background: var(--surface); border: 1px solid var(--line); border-radius: 2px;
  padding: 14px 16px; margin: 0; color: var(--ink); max-height: 420px; overflow: auto;
}
.refbox.mrz { font-size: 15px; letter-spacing: .06em; border-color: var(--accent); }

/* ---------- generic type ---------- */
h1 {
  font-family: var(--f-body); font-weight: 500; font-size: 38px; line-height: 1.22;
  margin: 12px 0 6px; letter-spacing: -.01em; text-wrap: balance;
}
h2 { font-family: var(--f-body); font-weight: 500; font-size: 26px; margin: 34px 0 10px; }
h3 { font-size: 17px; font-weight: 700; margin: 22px 0 6px; }
p { margin: 0 0 14px; max-width: min(1012px, 100%); text-wrap: pretty; }
/*  A headline line inside the h1. Deliberately carries no size, weight or colour: it
    inherits every one of them from the h1, so the two lines cannot drift apart the way
    the four rail paddings did on 2026-08-29. */
.h1-line { display: block; }

.lede { font-size: 17px; line-height: 1.75; color: var(--soft); max-width: min(1012px, 100%); }

/*  `.callout` was used by TEN templates and defined by none of the three stylesheets --
    found 2026-09-03 while adding an eleventh. Every one of them rendered as a bare div, and
    six set `border-left: 2px solid ...` inline, which draws a rule with no padding beside it
    and only makes sense against a base rule that was never written. Same shape as the input
    types missing from the base rule earlier the same day: the templates were making a claim
    about appearance and nothing was keeping it.

    Left border at 3px transparent so an inline `border-left` override lands at the same
    width the others sit at, instead of shifting the text by 1px on six pages. */
.callout {
  padding: 13px 16px; border: 1px solid var(--rule); border-left: 3px solid transparent;
  background: var(--panel); border-radius: 2px; font-size: 15px; line-height: 1.65;
}
.callout p { margin-bottom: 0; }

/*  A callout heading that carries a mark. `--accent` is the blue the Access cards already
    give the applicant role (`.acc-seat--applicant`), so the colour means the same thing in
    both places rather than being a second blue chosen by eye.

    `align-items: start` with a nudge, not `center`: centring looks right on one line and
    drops the mark to the middle of a two-line heading on a narrow window. */
.cta-h {
  color: var(--accent);
  /*  19px/500 is `.step-title` exactly, not a size picked to look similar. The heading
      sits directly above a list of step titles and reads as one of them; two values a
      pixel apart would be the rails of 2026-08-29 again, drifting the first time either
      moved. If .step-title changes, this should change with it. */
  font-size: 19px; font-weight: 500; line-height: 1.4;
  display: flex; align-items: flex-start; gap: 10px;
}
/*  The mark is sized to the text it sits beside, in em, so it follows the font size
    instead of being a second number to keep in step. */
.cta-h svg { width: 1em; height: 1em; flex: none; margin-top: .18em; }
.eyebrow {
  font-size: 13px; letter-spacing: .13em; text-transform: uppercase; color: var(--muted);
}
.sub-ja { font-size: 16px; color: var(--muted); margin-bottom: 18px; }
.muted { color: var(--muted); }
.small { font-size: 14.5px; }

/* ---------- buttons ---------- */
/* Controls, in the C direction: a word and a rule rather than a filled block. Redefined
   here rather than by editing thirty templates, so the whole interface converts at once
   and no page is left half in the old system. `.b` above is the same treatment for
   markup written since; `.btn` is what everything already says.

   The accent rule is 2px and marks the one control on a page that matters. Everything
   else takes a hairline, and `.ghost` -- which used to mean "not the primary one" --
   takes the muted colour that now says the same thing. */
.btn {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 9px 0 8px; font-family: inherit; font-size: 16.5px;
  border: 0; border-bottom: 2px solid var(--accent); background: none;
  color: var(--accent); font-weight: 500; border-radius: 0;
  cursor: pointer; text-decoration: none;
}
.btn:hover { opacity: 1; border-bottom-color: var(--ink); color: var(--ink); }
.btn.ghost {
  color: var(--muted); font-weight: 400; border-bottom: 1px solid var(--rule);
}
.btn.ghost:hover { color: var(--accent); border-bottom-color: var(--accent); }
/* The red control is the one exception that keeps a fill: it marks the preview whose
   whole point is that the applicant's own words are in the Agency's correction red, and
   a hairline would stop it reading as that. */
.btn.red {
  padding: 9px 18px; border: 1px solid var(--preview); background: var(--preview);
  color: #fff; border-radius: 2px; font-weight: 400;
}
.btn.red:hover { opacity: .9; border-color: var(--preview); color: #fff; }
.btn.small { font-size: 15px; }
/* Buttons sitting in a row need real space between them now that none of them has a box
   to separate it from its neighbour. */
form .btn + .btn, .btn + .btn { margin-left: 26px; }

/* ---------- interview layout ---------- */
.iv { display: grid; grid-template-columns: var(--rail) minmax(0, 1fr); gap: 0; }
.rail {
  padding: 30px 28px 40px 0; border-right: 1px solid var(--rule);
}
.rail h4 { font-size: 13px; letter-spacing: .13em; text-transform: uppercase; color: var(--muted); margin: 0 0 16px; }
.rail ol { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1px; }
.rail li a {
  display: flex; align-items: center; gap: 10px; padding: 7px 0;
  font-size: 15.5px; color: var(--muted); text-decoration: none;
}
.rail li.complete a { color: var(--soft); }
.rail li.now a { color: var(--ink); font-weight: 700; }
.rail li.now { border-left: 2px solid var(--accent); margin-left: -14px; padding-left: 12px; }
.dot { width: 14px; height: 14px; border-radius: 50%; border: 1.5px solid var(--line); flex-shrink: 0; }


.pct { margin-top: 26px; padding-top: 18px; border-top: 1px solid var(--rule); }
.pct b { font-family: var(--f-body); font-size: 34px; font-weight: 500; line-height: 1; }
.pct span { font-size: 14px; color: var(--muted); display: block; margin-top: 4px; }

.pane { padding: 30px 0 60px 40px; min-width: 0; }

/* ---------- questions ---------- */
.q { margin-bottom: 28px; padding-bottom: 4px; }
.q > label, .q .qlabel {
  display: block; font-size: 17px; font-weight: 500; margin-bottom: 5px;
}
.q .help { font-size: 15px; color: var(--muted); margin-bottom: 10px; max-width: min(966px, 100%); }
.req-tag {
  font-size: 12px; letter-spacing: .1em; text-transform: uppercase; color: var(--warn);
  border: 1px solid var(--warn-line); padding: 1px 5px; margin-left: 8px; white-space: nowrap;
}

/*  `email` and `password` were absent from this list until 2026-09-03, so every input of
    those two types fell through to the browser's own default -- no padding, a thinner
    border, and a smaller box sitting beside correctly-sized neighbours. Reported from the
    profile Settings page, where a short password field sat next to a tall address box, but
    it was never one page: 13 inputs across sign-in, forgot, set-password, account and
    settings. `.regform` and `.adm-acts` had each grown their own copy of this rule listing
    the two missing types, which is why registration and the admin panel looked right and
    hid how general the gap was.

    Listed explicitly rather than `input:not([type=submit])`, for the reason `.regform`
    gives below: a negation captures radios, checkboxes and file pickers the day somebody
    adds one. */
input[type=text], input[type=email], input[type=password], input[type=search],
input[type=url], input[type=date], input[type=tel], input[type=number], textarea, select {
  width: 100%; padding: 11px 13px; font-family: inherit; font-size: 17px;
  color: var(--ink); background: var(--surface);
  border: 1px solid var(--line); border-radius: 2px;
}
textarea { min-height: 110px; line-height: 1.7; resize: vertical; }
input:focus, textarea:focus, select:focus { border-color: var(--accent); }

.choices { display: flex; flex-direction: column; gap: 20px; }
.choice {
  display: flex; gap: 16px; align-items: flex-start; padding: 20px 22px;
  border: 1px solid var(--line); border-radius: 2px; background: var(--surface); cursor: pointer;
}
.choice:hover { border-color: var(--accent); background: var(--panel); }
.choice:has(input:checked) { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.choice input { margin: 4px 0 0; flex-shrink: 0; width: 20px; height: 20px; accent-color: var(--accent); }
.choice > span { display: block; min-width: 0; }
/* label and description are separate lines -- they ran together as inline spans */
.choice .cl { display: block; font-size: 19px; font-weight: 500; line-height: 1.45; }
.choice .cd {
  display: block; font-size: 16px; color: var(--soft); line-height: 1.7;
  margin-top: 7px; max-width: min(1012px, 100%);
}
.choices { gap: 20px; }

/* ---------- the two panes on the landing page ----------
   Each pane is one link, so it is one tab stop and the whole card is the target. The
   children are spans rather than block elements because an <a> may not contain a <div>
   and still be valid, and validity here is not pedantry: a browser that repairs the
   markup moves the closing tag, and the second pane ends up inside the first. */
.panes {
  display: grid; grid-template-columns: 1fr 1fr; gap: 22px; margin: 34px 0 4px;
  align-items: stretch;
}
/*  Halved on 2026-09-03, operator's ask. Most of it came from removing the kicker and the
    five-line body rather than from squeezing type: measured against the previous card at
    this column width, 391px -> 205px, a 48% reduction with nothing made smaller to read.
    The padding trim is the remainder. Compressing the type instead would have hit the one
    thing a chooser actually needs to read. */
.pane-card {
  display: flex; flex-direction: column; gap: 10px;
  padding: 22px 26px 20px; border: 1px solid var(--line); border-radius: 2px;
  background: var(--surface); text-decoration: none; color: inherit;
  transition: border-color .13s ease, background .13s ease;
}
.pane-card:hover, .pane-card:focus-visible {
  border-color: var(--accent); background: var(--panel); opacity: 1;
}
.pane-kicker {
  font-size: 12.5px; letter-spacing: .13em; text-transform: uppercase; color: var(--muted);
}
.pane-title { font-size: 27px; font-weight: 500; line-height: 1.25; color: var(--ink); }
.pane-body { font-size: 16px; line-height: 1.72; color: var(--soft); }
/*  Two columns, filled COLUMN-first: three rows, then overflow to the right. That
    ordering is the requirement rather than a side effect -- the operator asked for the
    added points to sit "to the right of the original points", and row-first flow would
    interleave old and new down the rows instead.

    Below 700px it goes back to one column. Each pane is roughly half of a 1104px measure,
    so two columns of 14.5px text are comfortable on a laptop and cramped on a phone, where
    a single column in reading order is the better answer anyway. */
.pane-list {
  display: grid; gap: 5px 16px; margin-top: 4px;
  grid-template-rows: repeat(3, auto);
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
}
@media (max-width: 700px) {
  .pane-list { grid-template-rows: none; grid-auto-flow: row; grid-auto-columns: auto; }
}
/*  `.hilite` shares these two rules rather than restating them. Copying six declarations
    for a mark that has to look identical is how the four rail paddings drifted on
    2026-08-29, and how `.regform` came to hide the input types missing from the base rule
    earlier today. One dot, two places that use it. */
.pane-item, .hilite {
  font-size: 14.5px; color: var(--soft); padding-left: 17px; position: relative;
}
.pane-item::before, .hilite::before {
  content: ""; position: absolute; left: 0; top: .62em;
  width: 6px; height: 6px; border-radius: 50%; background: var(--accent); opacity: .55;
}

/*  Wraps rather than scrolls or truncates: at four short items it is one line on a laptop
    and two or three on a phone, and every item stays readable at every width. */
.hilites { display: flex; flex-wrap: wrap; gap: 9px 26px; margin: 24px 0 0; }

/*  What free covers, and where it stops. Two columns on a laptop, stacked below 620px --
    and the "paid" column stacks BELOW the free one, which is the reading order the copy
    assumes: what you have, then what you do not. */
.freecols { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 26px; margin-top: 14px; }
@media (max-width: 620px) { .freecols { grid-template-columns: 1fr; } }
.freeh {
  font-size: 12.5px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 6px;
}
/*  `.ticks` was used by the market service list and by the free/paid columns and defined by
    nothing -- found 2026-09-03 while adding the second consumer, which is the third time in
    one day a class attribute turned out to be a claim nothing was keeping (`.callout`, the
    missing input types, this). Defined here, once, for both.

    A list, not a paragraph: each line is a separate thing somebody is buying or not buying,
    and prose would let them blur. */
.ticks { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 6px; }
.ticks li { font-size: 14.5px; line-height: 1.55; color: var(--soft); padding-left: 19px; position: relative; }
.ticks li::before {
  content: ""; position: absolute; left: 2px; top: .52em;
  width: 7px; height: 4px; border-left: 1.5px solid var(--ok); border-bottom: 1.5px solid var(--ok);
  transform: rotate(-45deg);
}

/*  The paid column takes no tick. A tick beside something a person does NOT have is the
    kind of small dishonesty that makes a whole panel untrustworthy. */
.ticks.plain li::before { content: none; }
.ticks.plain li { padding-left: 0; color: var(--muted); }
/*  `.pane-go` stood here until 2026-09-03 and is deleted rather than left unreferenced. It
    rendered "See how it works" inside a pane that was ITSELF the link -- a label for a
    control that is not a control. Removing the line removed the rule; a selector kept
    against a future that may not arrive is the dead code this file has been trimmed of
    twice already. Its `margin-top:auto` trick, for pinning a footer to the shorter of two
    stretched cards, is worth remembering if a pane ever needs a real footer. */

@media (max-width: 820px) {
  .panes { grid-template-columns: 1fr; gap: 16px; }
  .pane-card { padding: 18px 20px 17px; }
  .pane-title { font-size: 23px; }
}

/* ---------- the numbered guide on the two audience pages ---------- */
.steps { list-style: none; margin: 30px 0 6px; padding: 0; }
.step-row {
  display: flex; gap: 18px; align-items: flex-start;
  padding: 20px 0; border-top: 1px solid var(--rule);
}
.step-row:last-child { border-bottom: 1px solid var(--rule); }
.step-n {
  flex: 0 0 34px; height: 34px; border-radius: 50%; border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center;
  font-size: 15px; font-weight: 500; color: var(--accent); background: var(--surface);
}
.step-text { display: block; min-width: 0; }
.step-title { display: block; font-size: 19px; font-weight: 500; line-height: 1.4; }
.step-body {
  display: block; font-size: 16px; color: var(--soft); line-height: 1.75; margin-top: 6px;
  max-width: min(1012px, 100%);
}
.step-note {
  display: block; font-size: 14.5px; color: var(--muted); line-height: 1.7; margin-top: 8px;
  padding-left: 13px; border-left: 2px solid var(--rule);
}

.startbar {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  margin: 26px 0 8px;
}

/* ---------- registration and profile forms ---------- */
.regform { display: flex; flex-direction: column; gap: 6px; max-width: 460px; }
.regform.wide { max-width: 620px; }
.regform label { font-size: 15px; color: var(--soft); margin-top: 12px; }
/*  Every text-entry type, not three of them. `input[type=password]` was missing, so the
    password box on the registration page rendered as an unstyled browser default beside a
    styled email box -- different height, different border, different type size, side by side.
    Reported from a screenshot; invisible in the stylesheet, because the rule that was there
    looked complete.

    Listed explicitly rather than as `input:not([type=submit])`: a negation selector would
    silently capture radios, checkboxes and file pickers the day somebody adds one to a form
    that uses this class. */
.regform input[type=text], .regform input[type=email], .regform input[type=password],
.regform input[type=tel], .regform input[type=number], .regform input[type=date],
.regform input[type=search], .regform input[type=url], .regform textarea {
  width: 100%; padding: 11px 13px; font-family: inherit; font-size: 16.5px;
  border: 1px solid var(--line); border-radius: 2px;
  background: var(--surface); color: var(--ink);
}
.regform button { margin-top: 18px; align-self: flex-start; }

/* ---------- the draft marking ----------
   §5.1 of the concept document. Stated wherever a rendered case is shown, including to a
   professional, because a read-only view that did not say what it was would be the one
   surface where the platform's central claim went unstated. */
.draftmark {
  border: 1px solid var(--warn-line); background: var(--warn-bg); color: var(--warn);
  border-radius: 2px; padding: 16px 18px; margin: 22px 0 8px;
}
.draftmark strong { color: var(--warn); }
.draftmark p { color: var(--warn); }

/* A question label inside a read-back table: a label, not a column heading, so it does
   not take the uppercase treatment table.grid gives its th. */
.qlabel {
  width: 42%; font-weight: 500 !important; text-transform: none !important;
  letter-spacing: 0 !important; font-size: 15.5px !important; color: var(--soft) !important;
}

ul.plain { list-style: none; padding: 0; margin: 12px 0; }
ul.plain li { padding: 10px 0; border-bottom: 1px solid var(--rule); }

.yesno { display: flex; gap: 10px; }
.yesno label {
  flex: 0 0 auto; padding: 13px 30px; font-size: 17px; border: 1px solid var(--line); border-radius: 2px;
  background: var(--surface); cursor: pointer; font-size: 16.5px;
}
.yesno input { margin-right: 10px; width: 18px; height: 18px; accent-color: var(--accent); }

.gloss {
  margin-top: 10px; padding: 13px 15px; background: var(--panel);
  border-left: 2px solid var(--accent);
}
.gloss .gt {
  font-size: 13px; letter-spacing: .11em; text-transform: uppercase;
  color: var(--accent); margin-bottom: 5px;
}
.gloss .gb { font-size: 15.5px; line-height: 1.68; color: var(--soft); }

.err { color: var(--preview); font-size: 15px; margin-top: 7px; }
.hasErr input, .hasErr textarea { border-color: var(--preview); }

.actions {
  display: flex; gap: 12px; align-items: center;
  border-top: 1px solid var(--rule); padding-top: 22px; margin-top: 34px;
}
.actions .spacer { flex-grow: 1; }

/* ---------- documents ---------- */
.docs { display: grid; grid-template-columns: 380px minmax(0, 1fr); gap: 0; }
.doclist { border-right: 1px solid var(--rule); padding: 24px 26px 40px 0; }
.doccard { padding: 14px 0; border-bottom: 1px solid var(--rule); }
.doccard:last-child { border-bottom: 0; }
.doccard .dt { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.doccard .jp { font-size: 16.5px; font-weight: 700; }
.doccard .en { font-size: 14.5px; color: var(--soft); margin-top: 2px; }
.doccard .pp { font-size: 13px; color: var(--muted); white-space: nowrap; }
.doccard .why { font-size: 14px; color: var(--muted); margin-top: 7px; line-height: 1.6; }

.tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 9px; }
.tag {
  display: inline-block; white-space: nowrap;
  font-size: 12.5px; padding: 2px 8px; border: 1px solid var(--line);
  color: var(--muted); border-radius: 2px;
}
.tag.ok { background: var(--accent); border-color: var(--accent); color: var(--paper); }
.tag.warn { border-color: var(--warn-line); color: var(--warn); }
.tag.get { border-style: dashed; }

.docpane { padding: 24px 0 60px 34px; min-width: 0; }
.tabs { display: flex; gap: 8px; margin-bottom: 14px; }
.tabs a { padding: 6px 14px; font-size: 14.5px; text-decoration: none; border: 1px solid var(--line); color: var(--soft); border-radius: 2px; }
.tabs a.on.red { background: var(--preview); border-color: var(--preview); color: #fff; }
.tabs a.on { background: var(--accent); border-color: var(--accent); color: var(--paper); }

.viewer { width: 100%; height: 760px; border: 1px solid var(--line); background: var(--surface); }

.notice {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 13px 15px; background: var(--warn-bg); border: 1px solid var(--warn-line);
  font-size: 15px; color: var(--warn); line-height: 1.65; margin: 14px 0;
}
.notice svg { flex-shrink: 0; margin-top: 2px; }
/* Lists inside prose share the paragraph measure. Carrying their own cap left the
   bullets wrapping a couple of hundred pixels short of the text around them. */
.notice ul, .prose ul, .wrap ul { max-width: min(1012px, 100%); padding-left: 20px; }
.notice li, .prose li, .wrap li { margin-bottom: 8px; }

/* ---------- wiki / glossary ---------- */
/*  ── The two-column reference layout: wiki, kb, scenarios ────────────────────────────
    The last of the page-heading gaps, reported 2026-09-06. These three pages never used
    `.pg-head` -- their heading sits inside `.prose` -- so the sweep that brought every other
    page to 24px left them at 48-52px.

    **The two columns now start on the same line.** They were 34px and 30px, which is not a
    considered offset, it is two numbers written at different times: both columns open with an
    `.eyebrow`, and those eyebrows were 4px out of line on every reference page. Equal padding
    is what makes them align, and it is `--pg-head-y` so the three-column pages and every
    `.pg-head` page move together or not at all. */
:root { --pg-head-y: 6px; }
.two { display: grid; grid-template-columns: var(--rail) minmax(0, 1fr); gap: 44px; }
.toc { padding-top: var(--pg-head-y); }
.toc a {
  display: block; padding: 7px 0; font-size: 15.5px; color: var(--muted);
  text-decoration: none; border-bottom: 1px solid var(--rule);
}
.toc a.on { color: var(--ink); font-weight: 700; }

.prose { padding: var(--pg-head-y) 0 70px; }
.prose p { font-size: 17px; line-height: 1.85; color: var(--soft); }
.prose strong { color: var(--ink); font-weight: 700; }

.sources { margin-top: 40px; padding-top: 20px; border-top: 1px solid var(--rule); }
.sources h3 { font-size: 13px; letter-spacing: .13em; text-transform: uppercase; color: var(--muted); margin: 0 0 12px; }
.src { padding: 10px 0; border-bottom: 1px solid var(--rule); font-size: 15px; }
.src a { text-decoration: none; }
.src .pub { color: var(--muted); font-size: 14px; }
.src .sup { color: var(--muted); font-size: 14px; margin-top: 3px; line-height: 1.6; }

.term { padding: 18px 0; border-bottom: 1px solid var(--rule); }
.term .jp { font-family: var(--f-body); font-size: 22px; font-weight: 500; }
.term .rom { font-size: 14.5px; color: var(--muted); margin-left: 10px; font-style: italic; }
.term .en { font-size: 15.5px; color: var(--accent); margin-top: 2px; }
.term .desc { font-size: 15.5px; color: var(--soft); line-height: 1.75; margin-top: 7px; max-width: min(1000px, 100%); }

table.grid { width: 100%; border-collapse: collapse; margin: 16px 0; }
table.grid th, table.grid td {
  text-align: left; padding: 10px 18px 10px 0; border-bottom: 1px solid var(--rule);
  font-size: 15.5px; vertical-align: top;
}
table.grid th {
  font-weight: 700; color: var(--muted); font-size: 13px;
  letter-spacing: .1em; text-transform: uppercase; white-space: nowrap;
}
/* Sibling tables on one page previously sized their columns independently, so the
   same column drifted between sections. */
table.grid.cols-4 { table-layout: fixed; }
table.grid.cols-4 th:nth-child(1), table.grid.cols-4 td:nth-child(1) { width: 26%; }
table.grid.cols-4 th:nth-child(2), table.grid.cols-4 td:nth-child(2) { width: 14%; }
table.grid.cols-4 th:nth-child(3), table.grid.cols-4 td:nth-child(3) { width: 38%; }
table.grid.cols-4 th:nth-child(4), table.grid.cols-4 td:nth-child(4) { width: 22%; }

/*  Three columns, added 2026-09-03. `/about` carried `cols-4` on a three-column table --
    the only mismatch in the application, found by counting every `<th>` against every
    `cols-N` rather than by looking.

    It is worth understanding why it looked wrong rather than merely narrow. `cols-4` is
    `table-layout: fixed`, so the browser obeys the declared widths and stops measuring
    content. Three columns took 26 + 14 + 38 = 78% of the row, the description column got
    38% for text that needs most of the width, and the missing 22% left the rule under the
    last column short. Fixed layout does not fall back to something sensible; it does what
    it is told, which is the whole reason to use it and the whole risk. */
table.grid.cols-3 { table-layout: fixed; }
table.grid.cols-3 th:nth-child(1), table.grid.cols-3 td:nth-child(1) { width: 30%; }
table.grid.cols-3 th:nth-child(2), table.grid.cols-3 td:nth-child(2) { width: 16%; }
table.grid.cols-3 th:nth-child(3), table.grid.cols-3 td:nth-child(3) { width: 54%; }

/*  `.sec` was used by five templates and defined by none -- the fourth class attribute in
    one day that was a claim nothing kept, after `.callout`, `.ticks` and the missing input
    types. Four of the five supply their own inline margin, which is why nobody noticed; the
    fifth (`account/_tab_documents.html`) had no spacing at all. An inline style still wins,
    so the four are unchanged. */
.sec { margin-top: 26px; }

/*  ── The Inbox: two panes ───────────────────────────────────────────────────────────────
    List on the left, one entry open on the right.

    `minmax(0, …)` on both tracks is what stops a long subject or an unbroken URL widening a
    column past its share. A grid track defaults to `min-content`, so without it one long
    word in the list pushes the whole page wider and the scrollbar lands on the document
    rather than inside the pane -- the same trap `.tl-f` records one rule down.

    The list is capped at 340px because it carries a time and a name, and a wider column
    would just be whitespace between them; the pane takes the rest, which is where the
    1560px of a workstation actually goes. */
.ib {
  display: grid; grid-template-columns: minmax(0, 340px) minmax(0, 1fr);
  gap: 18px; margin: 22px 0 44px; align-items: start;
}
/*  No page header on this one, so the panes start where the header would have been and take
    the height it would have cost. `calc(100vh - …)` rather than a fixed height: the panes
    should end where the window does on any screen, and a magic pixel value is a guess about
    a viewport nobody measured. The subtraction is the top bar plus the beta band plus the
    margin below. */
.ib-full { margin-top: 18px; }

/*  ── How far down the panes go ───────────────────────────────────────────────────────
    **`height`, not `max-height`.** With a maximum, a mailbox holding four messages drew a
    short box with a stretch of page under it; the operator asked for the sender list to
    extend all the way down, and a maximum can only ever stop it going too far. A height
    makes both panes fill, and the list scrolls inside its own box when it outgrows them.

    The number was a bare `118px` beside `--topbar-h`, which is the "two numbers that must
    agree, written independently" defect DESIGN-STANDARDS §9.2 names -- nothing said what 118
    was made of, and it was about 40px too much, so the panes stopped short of the fold. It is
    written out now, one term per thing above them:

        --topbar-h      the masthead
        --pg-pad-y      the content column's top gutter
        18px            `.ib-full`'s own margin
        40px            the beta band: 9px padding twice, ~20px of 14.5px type, 1px rule
        20px            breathing room under the panes, so they do not touch the fold

    `100dvh` rather than `100vh`: on a phone `vh` is the *largest* viewport, so with the
    address bar showing the panes run under it. `dvh` follows the visible height. The `vh`
    line above it is the fallback for a browser that does not know `dvh` -- the later
    declaration simply does not parse there, which is the one place in CSS where writing a
    rule twice is the correct thing to do rather than the defect §9.2 is about. */
.ib-full {
  --ib-chrome: calc(var(--topbar-h) + var(--pg-pad-y) + 18px + 40px + 20px);
}
.ib-full .ib-col, .ib-full .ib-pane {
  height: calc(100vh - var(--ib-chrome));
  height: calc(100dvh - var(--ib-chrome));
  /*  A short window must not crush the panes into a strip. Below this they overflow the
      page and it scrolls, which is the honest failure. */
  min-height: 420px;
}

/*  The pane is a column: the correspondent and the tabs stay put and **the conversation
    scrolls under them**. It scrolled as one block before, so reading a long thread carried
    the name of the person who wrote it off the top of the screen -- which is the one thing
    on that pane you might need at the bottom of a long exchange. */
.ib-full .ib-pane { display: flex; flex-direction: column; }
.ib-full .ib-head, .ib-full .ib-tabs { flex: none; }
.ib-full .ib-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; }

/*  ── The two boxes start on the same line ────────────────────────────────────────────
    The list header used to sit OUTSIDE the bordered list, so the left box began about 34px
    lower than the right one and the two panes visibly failed to line up -- the operator's
    screenshot 2026-09-06 marks the gap with an arrow.

    The header is inside the box now, exactly as `.ib-head` is inside the right pane: the
    border moves to `.ib-col`, the list loses its own, and both boxes start at the top of the
    grid row. Aligning by nudging a margin would have held at one font size and drifted at
    the next; making the two structures the same is what makes the alignment survive.

    `min-height` matches the 46px avatar in `.ib-head` plus its 18px padding, so the first
    rule on the left lands level with the tab row on the right rather than a few pixels off. */
.ib-col {
  display: flex; flex-direction: column; min-width: 0;
  border: 1px solid var(--rule); border-radius: 2px; background: var(--surface);
  overflow: hidden;
}
.ib-lh {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 18px 20px; min-height: 46px; box-sizing: content-box;
  border-bottom: 1px solid var(--rule); flex: none;
}
.ib-lh h1 { font-size: 19px; margin: 0; }
/*  Beside the title, not at the edge. `margin-right: auto` is what pushes everything AFTER it
    to the right -- so the count sits against the word it counts and the gear takes the far
    side, without either needing a width. */
.ib-count {
  font-size: 12.5px; color: var(--muted); font-variant-numeric: tabular-nums;
  margin-right: auto;
}

/*  ── The settings popup ──────────────────────────────────────────────────────────────
    `<details>` rather than the masthead's hover dropdown: hover closes the moment the
    pointer leaves, and this holds a form. `position: relative` on the parent and `absolute`
    on the card, so opening it lays the card OVER the list rather than pushing the list down
    -- a settings panel that reflows the thing it configures is its own moving target. */
.ib-set { position: relative; flex: none; }
.ib-set > summary {
  list-style: none; cursor: pointer; display: flex; align-items: center;
  padding: 4px; border-radius: 2px; color: var(--muted);
}
.ib-set > summary::-webkit-details-marker { display: none; }
.ib-set > summary:hover { color: var(--ink); background: var(--panel); }
.ib-set[open] > summary { color: var(--ink); }
.ib-set-card {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 30; width: 288px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 2px;
  padding: 14px 16px 12px; box-shadow: 0 8px 26px rgb(0 0 0 / .22);
}
.ib-set-h { font-size: 13px; font-weight: 500; color: var(--ink); margin-bottom: 10px; }
.ib-set-row { display: flex; gap: 9px; align-items: flex-start; margin-bottom: 11px; cursor: pointer; }
.ib-set-row input { margin-top: 2px; flex: none; }
.ib-set-row b { display: block; font-size: 13.5px; font-weight: 400; color: var(--ink); }
.ib-set-row em { display: block; font-style: normal; font-size: 12px; color: var(--muted); margin-top: 1px; }
.ib-set-act { padding-top: 8px; border-top: 1px solid var(--rule); }
.ib-set-note { font-size: 11.5px; color: var(--muted); margin: 8px 0 0; line-height: 1.5; }

/*  Compact: less padding and one line fewer. The subject goes rather than the name, because
    the name is what the list is FOR -- the operator called it the sender list. */
.ib-list.is-compact .ib-row { padding: 7px 14px; }
.ib-list.is-compact .ib-sub { display: none; }

/*  The search row. Full width of the list pane, directly above what it filters. */
.ib-search {
  display: flex; align-items: center; gap: 8px; flex: none;
  padding: 10px 14px; border-bottom: 1px solid var(--rule);
}
/*  `min-width: 0` on the input as well as the row: a flex item defaults to `min-width: auto`,
    which for an input is its `size` attribute rather than zero, so it refuses to shrink and
    pushes the Clear link out of the pane on a narrow window. */
.ib-search input {
  flex: 1 1 auto; min-width: 0;
  padding: 7px 10px; font: inherit; font-size: 13.5px;
  color: var(--ink); background: var(--paper);
  border: 1px solid var(--line); border-radius: 2px;
}
.ib-search input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.ib-clear { font-size: 12.5px; color: var(--muted); flex: none; }
.ib-clear:hover { color: var(--accent); }
/*  Stacked below 900px, list first. On a narrow window a person picks from the list and then
    reads -- putting the pane first would show them a message before its context. */
@media (max-width: 900px) {
  .ib { grid-template-columns: 1fr; }
  /*  Stacked, the viewport height belongs to whichever pane is being read, not to each of
      them in turn: two boxes of 100dvh each would put the message a full screen below the
      list. They size to their content here and the page scrolls, which is what a narrow
      window does everywhere else in this application. */
  .ib-full .ib-col, .ib-full .ib-pane { height: auto; min-height: 0; max-height: 70vh; }
  .ib-full .ib-body { overflow-y: visible; }
}

/*  No border and no height of its own: it is the scrolling body of `.ib-col` now, the way
    `.ib-body` is the scrolling body of `.ib-pane`. `min-height: 0` because a flex item
    defaults to `min-height: auto` and would refuse to shrink, pushing its scrollbar onto the
    page instead of keeping it inside the list. */
.ib-list {
  list-style: none; margin: 0; padding: 0;
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
}
.ib-row {
  display: grid; gap: 2px; padding: 11px 14px; text-decoration: none;
  border-bottom: 1px solid var(--rule); border-left: 3px solid transparent;
}
/*  Room above the row the fragment lands on, so it arrives a little inside the pane instead
    of flush against the top edge where it reads as the first row of the list rather than the
    one that was chosen. `scroll-margin-top` belongs on the target, not the container: it is
    the element saying how it wants to be brought into view. */
.ib-list li { scroll-margin-top: 56px; }
.ib-list li:last-child .ib-row { border-bottom: 0; }
.ib-row:hover { background: var(--panel); text-decoration: none; }
.ib-row.on { background: var(--panel); border-left-color: var(--accent); }
.ib-row.is-new .ib-who { color: var(--ink); font-weight: 500; }
.ib-when { font-size: 11.5px; color: var(--muted); }
.ib-who { font-size: 14px; color: var(--soft); }
.ib-sub { font-size: 12.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ib-empty { padding: 16px; font-size: 14px; color: var(--muted); }

.ib-pane { border: 1px solid var(--rule); border-radius: 2px; background: var(--surface); min-width: 0; }
.ib-head { display: flex; align-items: center; gap: 14px; padding: 18px 20px; }
/*  Initials, not a photograph: no picture is held for either party in a question thread, and
    a broken image where a face would be is worse than saying what is known. */
/*  One disc, two sizes, driven by a variable rather than by a second rule. The large one is
    beside the correspondent's name at the head of the pane; the small one beside each message
    in the conversation. Written as `--av` so the type scales with the disc: a 15px letter in
    a 28px circle is a letter with a circle drawn round it, not a monogram. */
.ib-av {
  --av: 46px;
  display: flex; align-items: center; justify-content: center; flex: none;
  width: var(--av); height: var(--av); border-radius: 50%;
  background: var(--panel); border: 1px solid var(--rule);
  font-size: calc(var(--av) * .32); font-weight: 500; color: var(--soft);
  letter-spacing: .03em; line-height: 1;
}
.ib-av.sm { --av: 28px; }
.ib-idn { min-width: 0; }
.ib-nm { font-size: 17px; font-weight: 500; color: var(--ink); }
.ib-meta { font-size: 12.5px; color: var(--muted); margin-top: 2px; }

/*  The tab row. Scrolls rather than wraps: a second line of tabs moves the content down and
    the reader's eye with it, and these will grow. */
.ib-tabs {
  display: flex; gap: 20px; padding: 0 20px;
  border-bottom: 1px solid var(--rule); overflow-x: auto;
}
.ib-tabs a {
  padding: 9px 0 10px; font-size: 14px; color: var(--muted);
  text-decoration: none; white-space: nowrap; border-bottom: 2px solid transparent;
}
.ib-tabs a:hover { color: var(--soft); text-decoration: none; }
.ib-tabs a.on { color: var(--ink); border-bottom-color: var(--accent); }
.ib-body { padding: 18px 20px; }

/*  The field grid, shared by the Inbox's Details tab and anything else that shows label
    over value. What stood here until 2026-09-05 was a single-column timeline of cards; the
    operator's two-pane layout replaced it, and the rules that drew the rail, the dots and
    the cards are deleted rather than left unreferenced -- a selector kept against a future
    that may not arrive is the dead code this file has been trimmed of twice.

    `auto-fit` with a floor, not a fixed column count: a card with two fields leaves no empty
    tracks and one with six does not overflow, so a laptop gets fewer columns rather than a
    horizontal scrollbar, without a media query per breakpoint. */
.tl-fields {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 10px 22px;
}
/*  `min-width: 0` is not cosmetic. A grid item defaults to `min-width: auto`, so a long
    unbroken value -- an address, a subject with no spaces -- refuses to shrink and pushes the
    whole track wider than its share, which on a narrow window becomes a horizontal scrollbar
    on the page rather than a wrap inside the card. */
.tl-f { min-width: 0; }
.tl-l {
  font-size: 11.5px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 3px;
}
.tl-v { font-size: 14px; line-height: 1.55; color: var(--soft); word-break: break-word; }
.tl-act { margin-top: 14px; padding-top: 11px; border-top: 1px solid var(--rule); font-size: 13.5px; }

/*  The unread marker. Text, not only colour: WCAG 1.4.1 (Use of Colour) at A, and a bold
    name beside a normal one is not a distinction somebody scanning a list can rely on. */
.ib-new {
  font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--accent); margin-left: 6px;
}

/*  ── The conversation inside the right pane ──────────────────────────────────────────
    Each message keeps its own name and time, and the reader's own messages are marked with a
    left rule in the accent rather than being pushed to the opposite side. Chat bubbles on
    alternating sides read as instant messaging; this is correspondence about a legal document
    that both parties may need to re-read months later, and it should read like a letter. */
.ib-th { display: flex; flex-direction: column; gap: 18px; }
.ib-msg { border-left: 3px solid var(--rule); padding-left: 14px; }
.ib-th .thread-b { padding-left: 38px; }   /* aligned under the name, past the 28px disc */
.ib-msg.is-mine { border-left-color: var(--accent); }
/*  `center`, not `baseline`: a disc has no baseline worth aligning to, and against one the
    28px circle sat low with its bottom edge on the name's baseline. The two text spans keep
    their own alignment to each other by being the same size. */
.ib-msg-h {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 6px;
}
.ib-msg-w { font-size: 13.5px; font-weight: 500; color: var(--ink); }
.ib-msg-t { font-size: 11.5px; color: var(--muted); }

/*  A thread. Two roles, told apart by a border rather than by alignment: chat bubbles pushed
    to opposite sides read as instant messaging, and this is correspondence about a legal
    document that both sides may need to re-read months later. */
.thread { display: flex; flex-direction: column; gap: 14px; margin-top: 20px; }
.thread-m {
  padding: 13px 16px; border: 1px solid var(--rule); border-left: 3px solid var(--rule);
  border-radius: 2px; background: var(--surface);
}
.thread-m.is-pro { border-left-color: var(--accent); background: var(--panel); }
.thread-who { font-size: 12.5px; color: var(--soft); margin-bottom: 6px; }
/*  `pre-wrap`: somebody writing about their own situation uses paragraphs, and collapsing
    them would reflow their words into one block. */
.thread-b { font-size: 14.5px; line-height: 1.7; white-space: pre-wrap; word-break: break-word; }

/*  ── The Templates workspace ────────────────────────────────────────────────────────────
    Two cards, a rule, the section controls, a rule, the facsimile. The order is the
    operator's and docs/TEMPLATES-FEATURE.md §4 records it. */
.tplcards { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; margin-top: 22px; }
@media (max-width: 820px) { .tplcards { grid-template-columns: 1fr; } }
/*  A key-value table, so the label column is fixed and the value column takes the rest.
    NOT a `cols-N` grid: those size N columns from a header row and this has one `th` per
    row -- which `check-design.py` caught when the wrong class was applied. */
.tpltab { margin: 10px 0 0; }
.tpltab th { width: 34%; white-space: normal; }

/*  A rule the eye reads as a division of the page rather than as a border on something. */
.tplrule { border: 0; border-top: 1px solid var(--rule); margin: 30px 0 22px; }

.tplsecs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
/*  No underline: these are controls in a row of controls, and a rule under each one turns a
    toolbar into a paragraph of links. `.b` gives them their affordance already. */
.tplsec { display: inline-flex; align-items: center; gap: 8px; font-size: 14px; text-decoration: none; }
.tplsec:hover { text-decoration: none; }
.tplsec-n {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; flex: none; border-radius: 50%;
  background: var(--panel); border: 1px solid var(--rule);
  font-size: 11.5px; color: var(--muted);
}

/*  ── The facsimile ─────────────────────────────────────────────────────────────────────
    A sheet, not a form. It should read as a page so a person can see the shape of what
    they are filling -- and it must NOT read as the government's form, because a pixel copy
    rendered in a browser is something somebody could screenshot and try to file. Labelled
    rows with item numbers are unmistakably a guide. TEMPLATES-FEATURE §6.2. */
.sheet {
  border: 1px solid var(--rule); border-radius: 2px; background: var(--surface);
  max-height: 70vh; overflow-y: auto; margin-top: 12px;
}
.sheet-head {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  padding: 14px 18px; border-bottom: 1px solid var(--rule); background: var(--panel);
  position: sticky; top: 0;
}
.sheet-sec { padding: 14px 18px; border-bottom: 1px solid var(--rule); }
.sheet-sec:last-child { border-bottom: 0; }
.sheet-sec-h { font-size: 13px; color: var(--soft); margin-bottom: 10px; }

/*  The information mark and its note. CSS only, on hover AND focus -- hover alone is
    unreachable by keyboard and unusable on touch, which `.mgroup` established when the
    masthead groups were built.

    `position: relative` on the mark rather than on the section, so the note is placed
    against the icon and not against a block that may be 400px tall. */
.infoi { position: relative; display: inline-flex; margin-left: 6px; vertical-align: middle; cursor: help; }
.infoi-m {
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; border-radius: 50%;
  border: 1px solid var(--rule); color: var(--muted);
  font-size: 10.5px; font-style: italic; line-height: 1;
}
.infoi:hover .infoi-m, .infoi:focus .infoi-m { border-color: var(--accent); color: var(--accent); }
.infoi-p {
  position: absolute; left: 0; top: calc(100% + 7px); z-index: 40;
  width: min(340px, 78vw); padding: 12px 14px;
  background: var(--surface); border: 1px solid var(--rule); border-radius: 2px;
  box-shadow: 0 6px 24px rgb(0 0 0 / 18%);
  font-size: 13px; line-height: 1.6; color: var(--soft);
  opacity: 0; visibility: hidden; transition: opacity 120ms var(--ease-out);
}
.infoi:hover .infoi-p, .infoi:focus .infoi-p, .infoi:focus-within .infoi-p {
  opacity: 1; visibility: visible;
}
.infoi-h { display: block; font-weight: 500; color: var(--ink); margin-bottom: 5px; }
.infoi-ask {
  display: block; margin-top: 10px; padding-top: 9px;
  border-top: 1px solid var(--rule); color: var(--accent); font-size: 12.5px;
}
@media (prefers-reduced-motion: reduce) { .infoi-p { transition: none; } }
.sheet-row {
  display: grid; grid-template-columns: 26px 1fr 40%; gap: 10px;
  padding: 5px 0; align-items: baseline; font-size: 13.5px;
}
@media (max-width: 620px) { .sheet-row { grid-template-columns: 22px 1fr; } }
.sheet-no { color: var(--muted); font-size: 12px; text-align: right; }
.sheet-lab { color: var(--soft); }
.sheet-val { min-width: 0; }
/*  The same red `documents.py` uses for a preview render. decisions.md 2026-08-19: red means
    the platform produced it from the applicant's own answers, and the meaning should not
    change because the surface did. */
.sheet-ink { color: var(--preview); word-break: break-word; }
/*  An unanswered field draws a rule, not a blank -- so a person can see what is left WITHOUT
    a completeness score, which S6 forbids. */
.sheet-blank { display: block; border-bottom: 1px solid var(--rule); height: 1.1em; }
/*  自筆 fields are never filled and say so. decisions.md 2026-08-18: three fields must be
    handwritten, and printing a name in one is a common reason a bundle is handed back. */
.sheet-hand {
  font-size: 11.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted);
  border: 1px dashed var(--rule); padding: 1px 6px; border-radius: 2px;
}

/*  Statute text. `pre` because the extraction preserves article numbering and indentation
    and nothing else -- reflowing it as prose would destroy the only structure left. Wrapped
    rather than scrolled: a 50,000-character statute in a horizontally scrolling box is
    unreadable, and these run to that. */
.lawtext {
  white-space: pre-wrap; word-break: break-word;
  font-family: var(--f-body); font-size: 14px; line-height: 1.85; color: var(--soft);
  background: var(--panel); border: 1px solid var(--rule); border-radius: 2px;
  padding: 18px 20px; max-height: 70vh; overflow-y: auto; margin: 0;
}

/*  The standing statement at the foot of every page. Quiet by design: it is a fact about
    the product, not a warning, and a loud disclaimer reads as a service with something to
    hide (DEFENSIBILITY.md §5A.3). Separated by a rule rather than by weight. */
.foot-soft {
  margin: 22px 0 0; padding-top: 16px; border-top: 1px solid var(--rule);
  font-size: 13px; line-height: 1.6; color: var(--muted); max-width: 62ch;
}
.sec-h { font-size: 15px; font-weight: 500; margin: 0 0 8px; }

/*  `.note` and `.note.plain`, used by five templates and defined by none until 2026-09-03.
    Not a typo for `.notice`: that is the warn-coloured box with an icon, and these are the
    quieter explanatory blocks that sit under a field saying why something is the way it is.
    Three of the five are user-facing -- the settings page, the documents page and the
    identity refusal -- so this was unstyled text on pages where the explanation is the
    whole point.

    `.plain` drops the frame. It is used where the note follows its own field closely enough
    that a box would separate it from the thing it explains. */
.note {
  padding: 12px 15px; border: 1px solid var(--rule); background: var(--panel);
  border-radius: 2px; font-size: 14.5px; line-height: 1.65; color: var(--soft);
  margin: 14px 0;
}
.note.plain {
  padding: 0; border: none; background: none; margin: 8px 0 0;
  font-size: 13px; color: var(--muted);
}
.note p { margin-bottom: 0; }

/*  The fallback inside the PDF `<object>`: shown only to a browser that will not render a PDF
    inline, where it is the whole of the page's usefulness. Named rather than left inline
    because the §11 rule that caught it is right -- 20px of padding is a decision about a
    block, and a decision about a block is a class. */
.viewer-fb { padding: 20px; }

/*  The appearance and branding screens. Same story, smaller blast radius -- admin only. */
.adm-lede  { font-size: 14.5px; color: var(--muted); line-height: 1.6; margin: 0 0 18px; }
.adm-field { margin-bottom: 18px; }
.adm-label { display: block; font-size: 13px; font-weight: 500; color: var(--soft); margin-bottom: 5px; }
.adm-help  { font-size: 12.5px; color: var(--muted); margin-top: 5px; line-height: 1.5; }
.adm-dim   { color: var(--muted); }
.adm-check { display: flex; align-items: flex-start; gap: 8px; margin: 8px 0; }
.bm-use-body { font-size: 13.5px; color: var(--soft); line-height: 1.6; }
.linktree  { table-layout: auto; }

/* Auto layout gave the prose column whatever it asked for and squeezed the rest, so a
   Japanese document title broke mid-word in a 100px column while `Prepared by` and
   `Purpose` ran into each other. Stated widths, like cols-4 above. */
table.grid.cols-5 { table-layout: fixed; }
table.grid.cols-5 th:nth-child(1), table.grid.cols-5 td:nth-child(1) { width: 23%; }
table.grid.cols-5 th:nth-child(2), table.grid.cols-5 td:nth-child(2) { width: 11%; }
table.grid.cols-5 th:nth-child(3), table.grid.cols-5 td:nth-child(3) { width: 15%; }
table.grid.cols-5 th:nth-child(4), table.grid.cols-5 td:nth-child(4) { width: 12%; }
table.grid.cols-5 th:nth-child(5), table.grid.cols-5 td:nth-child(5) { width: 39%; }

table.grid.cols-7 { table-layout: fixed; }
table.grid.cols-7 th:nth-child(1), table.grid.cols-7 td:nth-child(1) { width: 13%; }
table.grid.cols-7 th:nth-child(2), table.grid.cols-7 td:nth-child(2) { width: 18%; }
table.grid.cols-7 th:nth-child(3), table.grid.cols-7 td:nth-child(3) { width: 11%; }
table.grid.cols-7 th:nth-child(4), table.grid.cols-7 td:nth-child(4) { width: 10%; }
table.grid.cols-7 th:nth-child(5), table.grid.cols-7 td:nth-child(5) { width: 11%; }
table.grid.cols-7 th:nth-child(6), table.grid.cols-7 td:nth-child(6) { width: 21%; }
table.grid.cols-7 th:nth-child(7), table.grid.cols-7 td:nth-child(7) { width: 16%; }

/* A fixed layout cannot shrink below its stated widths, so narrow windows scroll the
   table rather than crushing every column. .tablewrap already provides the scroller. */
table.grid.cols-5, table.grid.cols-7 { min-width: 720px; }
.scroll-x { overflow-x: auto; }

footer.foot {
  border-top: 1px solid var(--rule); margin-top: 40px;
  padding: 28px 0 60px; font-size: 14.5px; color: var(--muted);
}

/* Four columns that collapse to two on a phone rather than to one. A single column
   turns twenty links into a scroll, which is how a footer stops being navigation. */
.foot-nav {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 20px 28px;
}
.foot-col { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
.foot-h {
  font-size: 12px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink); margin-bottom: 3px;
}
.foot-col a { font-size: 14px; color: var(--muted); text-decoration: none; }
.foot-col a:hover { color: var(--accent); }


@media (max-width: 700px) {
  .foot-nav { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px; }
}

/* The beta notice, above every chrome state. Tokens only, no literal colour: `--accent`
   inverts between themes -- #2E3A59 light, #9DB0D6 dark -- so a hard-coded pair here would
   be the two-rasters-kept-in-step-by-hand problem the profile banner already refused.

   Deliberately not `position: sticky`. `.app-top` already is, and a second sticky bar takes
   a second bite out of a short viewport on the interview screens, where the rail and the
   question both need the height. It scrolls away and the page keeps its room. */
.betabar {
  background: var(--panel);
  border-bottom: 1px solid var(--rule);
  color: var(--soft);
  font-size: 14.5px;
  padding: 9px 0;
}
.betabar .wrap { align-items: baseline; display: flex; gap: 10px; }
.betabar b {
  border: 1px solid var(--accent);
  color: var(--accent);
  flex: none;
  font-size: 12px;
  letter-spacing: 0.08em;
  padding: 1px 7px;
  text-transform: uppercase;
}

/*  A flash is a card fixed to the viewport, not a bar in the page flow. Operator decision,
    2026-09-03: an informational message built into the layout pushes the page down and, at
    full width, carries far more weight than "a link is on its way" deserves.

    Fixing it to the viewport also removed the reason `base.html` rendered flashes in two
    places -- a card does not care what it is nested in, so the shell/document split that
    block existed for is gone.

    Colour by category, which was thrown away before: every message rendered in `--preview`.
    An error uses `--warn`, not `--preview`, for the reason `.errsum` states further down --
    `--preview` is the Agency's correction red, reserved for values written onto a form, and
    borrowing it here would put a third meaning on one colour. */
.toasts {
  position: fixed;
  top: calc(var(--topbar-h) + 14px);
  right: 18px;
  z-index: 60;                                  /* .app-top is 20 */
  display: flex; flex-direction: column; gap: 10px;
  width: min(380px, calc(100vw - 36px));
}
.flash {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--muted);
  box-shadow: 0 6px 24px rgb(0 0 0 / 18%);
  padding: 12px 15px;
  font-size: 14.5px; line-height: 1.5;
  color: var(--ink);
}
.flash--ok    { border-left-color: var(--ok); }
.flash--error { border-left-color: var(--warn); }

/*  Every toast leaves on its own, and the reason this rule changed the day after it was
    written is worth keeping.

    It first said an "ok" may auto-dismiss but an error may not -- somebody who looked away
    still needs to find out why the thing they asked for did not happen. That argument is
    fine in isolation and was wrong here, because this application has no JavaScript: with
    nothing to auto-dismiss it and no close control to press, an error toast was PERMANENT
    until the next navigation. Reported by the operator against `gate.register_first`, which
    sat over the page indefinitely. A message that cannot be dismissed is not a safer
    message, it is a permanent overlay.

    What makes the timing safe is that a flash is never the only telling. Form errors render
    inline through `.errsum`, and a gate redirect lands on the page that explains itself; the
    toast is the notice, not the record.

    Fourteen seconds against seven: an error has to be read and understood, an "ok" only
    noticed. */
.flash--ok    { animation: flash-out 500ms var(--ease-out)  7s forwards; }
.flash--error { animation: flash-out 500ms var(--ease-out) 14s forwards; }
@keyframes flash-out { to { opacity: 0; visibility: hidden; } }

@media (max-width: 620px) {
  .toasts { left: 12px; right: 12px; width: auto; }
}

@media (max-width: 900px) {
  .iv, .docs, .two { grid-template-columns: 1fr; }
  .rail, .doclist { border-right: 0; border-bottom: 1px solid var(--rule); padding-right: 0; }
  .pane, .docpane { padding-left: 0; }
  .rail li.now { margin-left: 0; padding-left: 12px; }
}

/* ------------------------------------------------------------------ */
/* Interview: three columns                                            */
/* The reading column stays measured; the extra width goes to the rail */
/* and to a right-hand aside, rather than stretching the prose.        */
/* ------------------------------------------------------------------ */

/* numbered steps in the left rail */
.rail ol { counter-reset: step; }
.rail li a { align-items: flex-start; }
/* Numbers, not badges: no disc, larger, right-aligned so 9 and 10 line up. */
.stepno {
  flex-shrink: 0; width: 22px; text-align: right;
  font-size: 16px; line-height: 24px; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.rail li.complete   .stepno { color: var(--soft); }
.rail li.now .stepno { color: var(--ink); font-weight: 700; }

/* The status mark sits between the number and the title, so the gap is structural
   rather than a margin that disappears when there is no mark to show. */
/* The mark occupies the same 24px line box as the number and the first line of the
   title, and is centred within it. Aligning a glyph or an icon by eye against text of a
   different size is what produced the drift; matching the line box removes the guesswork. */
.stepmark {
  flex-shrink: 0; width: 20px; height: 24px;
  display: inline-flex; align-items: center; justify-content: center;
}
.stepmark svg { display: block; }
.steptitle { min-width: 0; line-height: 24px; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}

/* right aside: sticky, so the ring stays visible through a long step */
.aside {
  border-left: 1px solid var(--rule);
  padding: 30px 0 60px 28px;
  position: sticky;
  /*  Offset by the bar, not zero. `.app-top` is `position: sticky; top: 0` with
      `z-index: 20`, and the document is the scrollport for this column -- so an aside stuck
      at `top: 0` comes to rest at the *same* line as the bar and, having no z-index of its
      own, slides underneath it. The completion ring is the top-most thing in here, so the
      percentage was the part that disappeared. Reported from the interview screen,
      2026-09-02.

      `.lib-toc` already had this right at `calc(var(--topbar-h) + 14px)`; this rule was
      simply never updated when the bar became sticky. The 14px matches it, and matches the
      12px `html { scroll-padding-top }` uses for the same reason -- an element flush against
      the bar's edge reads as clipped even when it is technically clear of it.

      `max-height` has to lose the same 64px, or the aside is a viewport tall starting 64px
      down and its own scrollbar runs off the bottom of the screen. */
  top: calc(var(--topbar-h) + 14px);
  align-self: start;
  max-height: calc(100vh - var(--topbar-h) - 14px);
  overflow-y: auto;
}
.aside h4 {
  font-size: 12px; letter-spacing: .13em; text-transform: uppercase;
  color: var(--muted); margin: 0 0 14px;
}

/* circular completion ring */
.ring-wrap { display: flex; flex-direction: column; align-items: center; padding-bottom: 8px; }
.ring { width: 118px; height: 118px; }
.ring svg { display: block; overflow: visible; }
.ring .track { stroke: var(--rule); }
.ring .fill  { stroke: var(--accent); transition: stroke-dashoffset .4s ease; }
/* Kept explicit rather than inherited: this is SVG text, where font-family does not
   cascade from body in every renderer. */
.ring .pcttext {
  font-family: var(--f-body); font-size: 22px; font-weight: 500;
  fill: var(--ink); letter-spacing: -.01em; font-variant-numeric: tabular-nums;
}



.ring-note { font-size: 13px; color: var(--muted); margin-top: 12px; text-align: center; }
.ring-label {
  display: block; margin-top: 4px;
  font-size: 12.5px; letter-spacing: .02em; color: var(--muted);
}

/* tool cards */
.tools { margin-top: 26px; padding-top: 20px; border-top: 1px solid var(--rule); }
.tool {
  display: block; padding: 13px 14px; margin-bottom: 10px;
  border: 1px solid var(--rule); border-radius: 2px;
  background: var(--surface); text-decoration: none; color: inherit;
}
.tool.planned { background: transparent; border-style: dashed; }
.tool:hover { border-color: var(--accent); }
/* block, or the title and description render as one run-on sentence */
.tool .tt { display: block; font-size: 14.5px; font-weight: 500; line-height: 1.4; }
.tool .td { display: block; font-size: 12.5px; color: var(--muted); line-height: 1.6; margin-top: 5px; }
.tool .tk {
  display: inline-block; font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); border: 1px solid var(--line); border-radius: 2px;
  padding: 1px 6px; margin-top: 8px; white-space: nowrap;
}
.tool.live .tk { border-color: var(--accent); color: var(--accent); }

@media (max-width: 1240px) {
  .iv3 { grid-template-columns: var(--rail) minmax(0, 1fr); }
  .aside { grid-column: 1 / -1; border-left: 0; border-top: 1px solid var(--rule);
           padding-left: 0; position: static; max-height: none; }
  .ring-wrap { align-items: flex-start; }
}
@media (max-width: 900px) {
  .iv3 { grid-template-columns: 1fr; }
  .iv3 .pane { padding-left: 0; padding-right: 0; }
}

/* ---- repeating answers -------------------------------------------------
   Some questions on the official forms are tables: the visits to Japan, both
   sides' families, the two witnesses to the marriage. They are answered as a
   grid because that is the shape the form asks for, and because a reader
   checking one against a passport reads down a column. */
.tablewrap { overflow-x: auto; margin-bottom: 8px; }
.qtable { width: 100%; border-collapse: collapse; min-width: 560px; }
.qtable th {
  text-align: left; font-size: 14px; font-weight: 500; color: var(--muted);
  letter-spacing: 0.02em; padding: 0 8px 6px 0; white-space: nowrap;
}
.qtable td { padding: 0 8px 8px 0; vertical-align: top; }
.qtable td:last-child, .qtable th:last-child { padding-right: 0; }
.qtable input[type=text] { font-size: 16px; padding: 9px 11px; }

.multi { display: flex; flex-wrap: wrap; gap: 12px; }
.multi .chip {
  display: inline-flex; align-items: center; gap: 9px; padding: 11px 18px;
  border: 1px solid var(--line); border-radius: 2px; background: var(--surface);
  font-size: 16.5px; cursor: pointer; white-space: nowrap;
}
.multi .chip:hover { border-color: var(--accent); background: var(--panel); }
.multi .chip:has(input:checked) { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.multi .chip input { width: 18px; height: 18px; margin: 0; accent-color: var(--accent); }

/* ---- the timeline chart ----------------------------------------------
   A Gantt drawn with two boxes per row and percentage offsets: no script, no
   canvas, no library. It prints, it scales with the text, and a reader with a
   screen reader gets the same information from the list underneath, which is
   the reason the list exists rather than being a duplicate of the picture. */
/*  A frame around the whole chart, on the operator's instruction 2026-09-03. It read as
    loose marks on the page: the bars, the scale above them and the labels beside them are
    one figure, and nothing said so.

    The padding is asymmetric on purpose. `.gantt-track` carries `margin-right: 168px` to
    keep the annotation column clear, so a symmetric box would look wrong -- generous on the
    right, tight on the left. 18px left, 12px right, and the track's own reservation does
    the rest.

    `--rule`, not `--line`: the same weight the tables and callouts use, so a figure sits in
    the page at the same level as the other blocks rather than announcing itself. */
.gantt {
  margin: 26px 0 6px; padding: 18px 12px 16px 18px;
  border: 1px solid var(--rule); border-radius: 2px; background: var(--panel);
}
@media (max-width: 700px) { .gantt { padding: 14px 10px 12px 12px; } }
.gantt-scale {
  /* Same track as the rows beneath it, gutter included, or the ticks stop lining up
     with the bars they label. */
  position: relative; height: 26px; margin-left: 216px; margin-right: 168px;
  border-bottom: 1px solid var(--line);
}
.gantt-tick { position: absolute; top: 0; transform: translateX(-50%); }
.gantt-tick span {
  font-size: 12.5px; color: var(--muted); letter-spacing: 0.02em; white-space: nowrap;
}
.gantt-tick::after {
  content: ""; position: absolute; left: 50%; top: 18px; width: 1px; height: 8px;
  background: var(--line);
}
/* Day zero, spanning the rows it belongs to. The wrapper is what gives it a height:
   before this it hung off the scale with a fixed -1000px overshoot, which ran past the
   last bar and down through the caption on every short route. */
.gantt-rows { position: relative; }
.gantt-zero {
  position: absolute; top: -6px; bottom: -2px; width: 1px;
  background: var(--accent); opacity: 0.5; z-index: 0;
}
.gantt-row { display: flex; align-items: center; gap: 0; margin-top: 9px; }
.gantt-label {
  flex: 0 0 216px; padding-right: 16px; font-size: 14.5px; line-height: 1.45;
  color: var(--soft); text-align: right;
}
/* The right gutter holds the figure that sits after a bar. Fixed, because the figure is
   a fixed width and a percentage of the track is not: 12% of 1560px fits "289.1 days
   (9.5 months)" and 12% of 1280px does not. */
.gantt-track { position: relative; flex: 1 1 auto; height: 30px; margin-right: 168px; }
.gantt-bar {
  position: absolute; top: 4px; height: 22px; border-radius: 2px;
  background: var(--accent); opacity: 0.85; min-width: 3px;
  display: flex; align-items: center;
}
.gantt-bar.is-wait {
  /* waiting, not doing: the same bar, visibly hollow */
  background: repeating-linear-gradient(
    -45deg, var(--accent) 0 2px, transparent 2px 7px);
  border: 1px solid var(--accent); opacity: 0.75;
}
.gantt-days {
  position: absolute; left: calc(100% + 9px); white-space: nowrap;
  font-size: 12.5px; color: var(--muted);
}
.gantt-mark {
  position: absolute; top: -3px; transform: translateX(-50%); z-index: 2;
}
.gantt-mark a {
  display: flex; align-items: center; justify-content: center;
  width: 19px; height: 19px; border-radius: 50%;
  font-size: 11.5px; font-weight: 600; text-decoration: none;
  background: var(--surface); color: var(--soft); border: 1px solid var(--line);
}
.gantt-mark.trap a { border-color: var(--warn-line); color: var(--warn); }
.gantt-mark.misconception a { border-color: var(--accent); color: var(--accent); }
.gantt-mark a:hover { background: var(--panel); }

.issue-no {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%; flex-shrink: 0;
  font-size: 12.5px; font-weight: 600;
  border: 1px solid var(--line); color: var(--soft);
}
.issue-no.trap { border-color: var(--warn-line); color: var(--warn); }
.issue-no.misconception { border-color: var(--accent); color: var(--accent); }

@media (max-width: 900px) {
  .gantt-scale { margin-left: 0; margin-right: 0; }
  .gantt-row { display: block; }
  .gantt-label { flex: none; text-align: left; padding: 0 0 3px; }
  .gantt-track { margin-right: 0; }
  .gantt-days { position: static; margin-left: 8px; }
}
/* A bar that reaches the right-hand edge has nowhere to put its label outside it. */

/* ==========================================================================
   The administration panel.

   A different shape from the rest of the interface, deliberately. The public pages are a
   document somebody reads once and leaves; this is a console somebody keeps open, so the
   sidebar does not move and only the content scrolls. It shares the palette and the type
   ramp so it is recognisably the same product, and shares nothing else.
   ========================================================================== */

.adm-sec {
  padding: 16px 20px 6px; font-size: 10.5px; letter-spacing: .15em;
  text-transform: uppercase; color: var(--muted); font-weight: 700;
}
.adm-link {
  display: flex; align-items: center; gap: 9px; padding: 9px 16px;
  font-size: 14.5px; color: var(--soft); text-decoration: none;
  border-left: 2px solid transparent;
}
.adm-link:hover { color: var(--ink); opacity: 1; }
.adm-link.on { color: var(--ink); font-weight: 500; border-left-color: var(--accent); background: rgba(46, 58, 89, .055); }
.adm-ic { width: 16px; height: 16px; flex: 0 0 auto; opacity: .7; }
.adm-link.on .adm-ic { opacity: 1; }
.adm-count {
  margin-left: auto; font-size: 11.5px; font-variant-numeric: tabular-nums;
  background: var(--accent); color: #fff; border-radius: 9px; padding: 1px 7px;
}

.adm-head { margin-bottom: 22px; }
.adm-head h1 { font-size: 29px; font-weight: 500; margin: 0 0 4px; letter-spacing: -.01em; }
.adm-head p { font-size: 15px; color: var(--soft); margin: 0; max-width: 760px; line-height: 1.65; }
/* Scoped to the admin content column rather than to a wrapper that no longer exists.
   `.adm-main` went with the standalone admin shell on 2026-08-29, and this rule went
   with it -- silently, because a heading that loses its size still renders. */
.pg.adm h2 { font-size: 18px; font-weight: 500; margin: 30px 0 8px; }
.adm-sub { font-size: 13.5px; color: var(--muted); line-height: 1.65; margin: 0 0 10px; max-width: 760px; }

.adm-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); border: 1px solid var(--line); background: var(--surface); }
.adm-tile { padding: 16px 18px; }
.adm-tile + .adm-tile { border-left: 1px solid var(--rule); }
.adm-tile .n { font-size: 30px; font-weight: 500; line-height: 1; font-variant-numeric: tabular-nums; letter-spacing: -.015em; }
.adm-tile .l { font-size: 13.5px; color: var(--soft); margin-top: 6px; line-height: 1.4; }
.adm-tile .l span { display: block; font-size: 12px; color: var(--muted); margin-top: 2px; }

.adm-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 0 34px; }
/* `.adm` and `.adm-side` are gone; the shell's own 900px breakpoint handles the
   column now. Only the admin content grid still needs collapsing. */
@media (max-width: 1000px) { .adm-cols { grid-template-columns: 1fr; } }

table.adm-tab { width: 100%; border-collapse: collapse; margin: 6px 0 4px; }
table.adm-tab th, table.adm-tab td {
  text-align: left; padding: 8px 16px 8px 0; border-bottom: 1px solid var(--rule);
  font-size: 14px; vertical-align: top; font-weight: 400;
}
table.adm-tab th { color: var(--soft); font-weight: 500; white-space: nowrap; }
table.adm-tab.wide tr:first-child th { font-size: 11.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); font-weight: 700; }
.adm-num { font-variant-numeric: tabular-nums; }
.adm-mut { color: var(--muted); font-size: 13px; }

.adm-pill { display: inline-block; font-size: 12px; padding: 1px 9px; border: 1px solid var(--line); border-radius: 10px; color: var(--muted); }
.adm-pill.on { border-color: var(--ok); color: var(--ok); }
.adm-pill.warn { border-color: var(--warn-line); color: var(--warn); }

.adm-bar { height: 8px; background: var(--rule); border-radius: 4px; overflow: hidden; margin: 8px 0; }
.adm-bar i { display: block; height: 100%; background: var(--accent); }

.adm-note {
  border: 1px solid var(--line); border-left: 2px solid var(--accent);
  background: var(--surface); padding: 14px 17px; margin: 18px 0;
  font-size: 14px; line-height: 1.7; color: var(--soft);
}
.adm-note strong { color: var(--ink); }
.adm-note p { margin: 8px 0 0; }
.adm-note.warn { border-left-color: var(--warn-line); background: var(--warn-bg); }
.adm-note.warn strong { color: var(--warn); }
.adm-note.act { border-left-color: var(--warn-line); background: var(--warn-bg); }
.adm-note.act strong { color: var(--warn); }
.adm-flash {
  border: 1px solid var(--line); border-left: 2px solid var(--ok); background: var(--surface);
  padding: 11px 15px; margin-bottom: 18px; font-size: 14px;
}

/* ------------------------------------------------------------------ */
/* A record, not a paragraph                                           */
/* Operator identity, registry numbers and addresses are fields that a */
/* reader checks one at a time -- a regulator, a payment processor, or */
/* somebody deciding whether to hand over a passport number. Two       */
/* columns on a desktop, stacked on a phone where 220px of label would */
/* leave nothing for the value.                                        */
.factlist {
  display: grid; grid-template-columns: 220px minmax(0, 1fr);
  gap: 0; margin: 4px 0 20px; border-top: 1px solid var(--rule);
}
.factlist dt, .factlist dd {
  padding: 11px 0; border-bottom: 1px solid var(--rule); margin: 0;
  font-size: 15px; line-height: 1.55;
}
.factlist dt { font-weight: 600; padding-right: 18px; }
.factlist dd { color: var(--ink); }

@media (max-width: 620px) {
  .factlist { grid-template-columns: 1fr; }
  .factlist dt { padding-bottom: 0; border-bottom: 0; font-size: 13px; color: var(--muted); }
  .factlist dd { padding-top: 3px; }
}

/* The referral code, set to be read off a screen and typed somewhere else: wide
   tracking, tabular figures, and large enough that the two groups of four stay
   distinct at a glance. It is printed the same way on the produced introduction. */
.refcode {
  font-size: 30px; font-weight: 600; letter-spacing: .16em;
  font-variant-numeric: tabular-nums; color: var(--accent);
  padding: 16px 20px; margin: 6px 0 8px;
  background: var(--paper-2, #f6f6f8); border-left: 3px solid var(--accent);
  display: inline-block;
}

/* ------------------------------------------------------------------ */
/* The professionals directory                                         */
/* Cards, not a table: each entry is a person, and the fields are of    */
/* different kinds. Deliberately uniform -- no card may be made to      */
/* stand out, because position and prominence are not for sale here.   */
.dirgrid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
  gap: 16px; margin-top: 26px;
}
.dircard {
  display: flex; flex-direction: column; gap: 9px;
  padding: 18px; border: 1px solid var(--rule); border-radius: 2px;
  text-decoration: none; color: var(--ink); background: var(--surface);
}
.dircard:hover { border-color: var(--accent); }
.dircard-head { display: flex; align-items: center; gap: 11px; }
.dirlogo {
  /* 54px, and no inner padding: at 42px with a 3px inset the portrait was too small to
     tell one entry from another, which defeats the point of having them. */
  width: 64px; height: 64px; object-fit: cover; flex-shrink: 0;
  border: 1px solid var(--rule); background: #fff;
}
.dirlogo.placeholder { background: var(--panel); border-style: dashed; }
.dirlogo.big { width: 96px; height: 96px; }
.dirname { font-size: 16.5px; font-weight: 600; line-height: 1.35; }

.dirbadge {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12.5px; color: var(--accent); white-space: nowrap;
}
.dirbadge svg { width: 14px; height: 14px; }

.dirmeta { display: flex; flex-wrap: wrap; gap: 4px 12px; font-size: 13.5px; color: var(--muted); }

/* Availability is a statement the professional made, so it is shown as a state and not
   as a judgement: a rule and a word, no colour that reads as good or bad. `closed` is
   muted rather than red -- honesty about capacity must not look like a warning. */
.diravail {
  font-size: 13px; padding-left: 9px; border-left: 2px solid var(--rule);
  color: var(--muted);
}
.diravail.av-open { border-left-color: var(--accent); color: var(--ink); }
.diravail.av-limited { border-left-color: var(--soft); color: var(--ink); }
.diravail.av-closed { border-left-color: var(--rule); color: var(--muted); }

.dirclients { font-size: 12.5px; color: var(--muted); }

.profhead { display: flex; gap: 18px; align-items: flex-start; margin: 6px 0 10px; }
@media (max-width: 560px) { .profhead { flex-direction: column; gap: 12px; } }

/* ------------------------------------------------------------------ */
/* The sign-in lander                                                  */
/* A card, centred on the page -- not a full-bleed split. The card is   */
/* the convention people know from every other service, and it keeps    */
/* the page itself feeling like a page rather than an application       */
/* takeover. The palette is this application's: the reference for the   */
/* layout was a dark violet console, and this is warm paper and indigo. */
/* A sign-in page that does not look like the rest of the site is the   */
/* page a phishing kit copies.                                          */
.signin-page {
  min-height: 100vh; min-height: 100dvh;
  display: flex; align-items: center; justify-content: center;
  padding: 32px 20px; background: var(--panel, var(--paper));
}
.signin-card {
  display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  width: 100%; max-width: 940px; min-height: 560px;
  background: var(--surface); border: 1px solid var(--rule); border-radius: 4px;
  overflow: hidden; box-shadow: 0 18px 48px rgb(0 0 0 / 10%);
}
.signin-card.no-art { grid-template-columns: minmax(0, 1fr); max-width: 480px; min-height: 0; }

.signin-art {
  position: relative; display: flex; flex-direction: column; justify-content: space-between;
  padding: 22px; overflow: hidden;
  background-color: #efe9e0; background-size: cover; background-position: center 42%;
}
/* The caption sits over a photograph, so it needs its own ground rather than relying on
   whichever pixels happen to be beneath it. A wash from the foot, not a box. */
.signin-art::after {
  content: ''; position: absolute; inset: 38% 0 0 0; pointer-events: none;
  background: linear-gradient(to bottom, rgb(28 26 24 / 0%), rgb(28 26 24 / 64%));
}
.signin-art-top, .signin-art-cap { position: relative; z-index: 2; }
.signin-art-top { display: flex; justify-content: space-between; align-items: center; gap: 12px; }

/* Fixed dark-on-translucent-white: these sit over a light photograph in both themes, so
   they are the one place here that does not use a theme variable. */
.signin-mark { font-size: 16px; font-weight: 600; color: #221f1c; text-decoration: none; }
.signin-back {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; text-decoration: none; color: #221f1c;
  padding: 5px 12px; border-radius: 999px;
  background: rgb(255 255 255 / 74%); border: 1px solid rgb(34 31 28 / 12%);
}
.signin-back:hover { background: rgb(255 255 255 / 94%); }

.signin-art-cap { max-width: 28ch; color: #fff; }
.signin-cap-h { font-size: 21px; line-height: 1.34; font-weight: 600; margin: 0 0 7px; }
.signin-cap-b { font-size: 13.5px; line-height: 1.6; margin: 0; color: rgb(255 255 255 / 87%); }

.signin-form { display: flex; align-items: center; justify-content: center; padding: 34px 30px; }
.signin-inner { width: 100%; max-width: 340px; }
.signin-topback { font-size: 13px; margin: 0 0 14px; }
.signin-inner h1 { font-size: 27px; margin: 0 0 6px; }
.signin-sub { font-size: 14px; color: var(--muted); margin: 0 0 22px; }

.signin-block { display: flex; flex-direction: column; gap: 7px; }
.signin-block label { font-size: 13px; color: var(--muted); }
.signin-block .f {
  font: inherit; font-size: 15px; padding: 10px 12px; width: 100%;
  border: 1px solid var(--rule); border-radius: 2px; background: var(--surface);
}
.signin-block .f:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
/* Not a filled slab: this design system has no filled buttons anywhere, and inventing one
   here would make sign-in the single page that does not look like the site. */
.signin-block .btn { align-self: flex-start; margin-top: 8px; }
.signin-note { font-size: 12.5px; color: var(--muted); line-height: 1.55; margin: 4px 0 0; }

.signin-or {
  display: flex; align-items: center; gap: 12px;
  margin: 22px 0 18px; color: var(--muted); font-size: 12.5px;
}
.signin-or::before, .signin-or::after { content: ''; flex: 1; height: 1px; background: var(--rule); }

/* Disabled has to look disabled -- opacity alone reads as a rendering glitch. */
.signin-off { border-left: 2px solid var(--warn-line); padding: 2px 0 2px 12px; margin-bottom: 13px; }
.signin-off strong { font-size: 13.5px; }
.signin-off p { font-size: 12.5px; color: var(--muted); line-height: 1.55; margin: 5px 0 0; }
.signin-block.disabled { opacity: .5; }
.signin-block.disabled .f, .signin-block.disabled .btn { cursor: not-allowed; }

.signin-foot { display: flex; gap: 15px; margin: 26px 0 0; font-size: 12.5px; }
.signin-foot a { color: var(--muted); text-decoration: none; }
.signin-foot a:hover { color: var(--accent); }

/* Below this the picture costs a screenful and earns nothing; the form is what the person
   came for. The card loses its shadow and fills the width. */
@media (max-width: 800px) {
  .signin-page { padding: 0; }
  .signin-card {
    grid-template-columns: 1fr; max-width: none; min-height: 100vh; min-height: 100dvh;
    border: 0; border-radius: 0; box-shadow: none;
  }
  /* A 190px band off a tall image needs its own focal point, or it lands on empty sky. */
  .signin-art { min-height: 190px; padding: 16px; background-position: center 46%; }
  .signin-art::after { inset: 0; }
  .signin-art-cap { display: none; }
  .signin-form { padding: 30px 20px 46px; }
}

/* ------------------------------------------------------------------ */

.btn.solid {
  background: var(--accent); color: var(--paper);
  border: 1px solid var(--accent); border-radius: 2px;
  padding: 11px 20px; font-weight: 500; font-size: 15.5px;
}
.btn.solid:hover { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.btn.solid[disabled] { opacity: .45; cursor: not-allowed; }
.btn.wide { width: 100%; justify-content: center; text-align: center; }
.signin-block .btn.solid { align-self: stretch; margin-top: 10px; }

/* The development-only administrator entry. It announces itself: a control that signs
   somebody in with no credentials should never be discreet. */
.signin-dev {
  margin-top: 26px; padding: 14px 16px;
  border: 1px dashed var(--warn-line); border-radius: 2px;
}
.signin-dev strong { font-size: 13.5px; display: block; }
.signin-dev p { font-size: 12.5px; color: var(--muted); line-height: 1.55; margin: 6px 0 12px; }

/* The document password in the admin Users panel. Set larger and spaced, because it is
   read off a screen and typed into a PDF reader by a person -- the one string in this
   interface whose whole job is to be transcribed without error. Appended once; app.css
   has already been duplicated by a whole block being added twice, so check before adding
   another. */
.adm-key {
  font-size: 1.15rem;
  letter-spacing: .08em;
  padding: .25rem .5rem;
  background: var(--rule-soft, #f2f2f0);
  border: 1px solid var(--rule, #d9d9d4);
}

/* Administrative action forms. Stacked with clear separation, because every one of them
   does something irreversible or close to it, and a row of buttons sitting side by side is
   how the wrong one gets pressed. */
.adm-acts { display: grid; gap: 1.5rem; max-width: 40rem; }
.adm-acts form { border: 1px solid var(--line); padding: 1rem 1.1rem; }
.adm-acts label { display: block; font-size: 13px; color: var(--muted); margin-bottom: .5rem; }
.adm-acts input[type=text], .adm-acts input[type=email], .adm-acts select {
  display: block; width: 100%; margin-top: .25rem; padding: .4rem .5rem;
  border: 1px solid var(--line); font: inherit; background: var(--bg);
}
.adm-acts .adm-mut { margin: .6rem 0 0; }
.adm-acts .adm-danger { border-color: var(--warn-line, #c0392b); }
.adm-acts .btn.red { color: var(--warn, #c0392b); border-color: var(--warn-line, #c0392b); }

/* ---------- the signed-in application shell ----------------------------------------
   Added 2026-08-29. One shell, two sidebars: `app.html` draws the chrome and picks the
   nav from `signed_in.is_professional`, and a page overrides `{% block sidenav %}` when
   it has case context the shell cannot know about.

   Lifted from design/mockups/dash.css, which drew this a while ago and was never built.
   Every value below is a token defined at the top of this file; no new colour is
   introduced, because the shell is a rehousing of the existing direction rather than a
   second one.

   `.wrap` is deliberately not used inside the shell -- the content column provides its
   own padding, and a page that keeps its `.wrap` inside `.pg` gets a second gutter. */

/* `align-items: start` matters: without it the grid stretches both columns to the tallest,
   which gives `.side` a height equal to the content and leaves it nothing to stick within.
   That is the usual reason a sticky sidebar silently does not stick. */
.app { display: grid; grid-template-columns: var(--rail) minmax(0, 1fr); min-height: 100vh;
       align-items: start; }

/* Fixed, on the operator's direction 2026-08-29. It was a grid column with no `position`, so
   on a long page -- sixty rows of audit log, the catalogue, the glossary -- the navigation
   had scrolled away by the time somebody wanted it.

   `sticky`, not `fixed`. Fixed takes the column out of flow, which means hand-maintaining a
   248px margin on the content that breaks the moment either number changes. Sticky keeps the
   grid doing the arithmetic.

   Its own `overflow-y` because the rail can outgrow the viewport -- the admin rail is the
   long one -- and a fixed sidebar whose bottom rows cannot be reached is worse than one that
   scrolls with the page. */
.side {
  background: var(--panel); border-right: 1px solid var(--line);
  display: flex; flex-direction: column; padding: 18px 0 16px;
  position: sticky; top: 0; height: 100vh; overflow-y: auto; overscroll-behavior: contain;
}
/*  **Nothing in a scrolling column may shrink.** A flex item defaults to `flex-shrink: 1`,
    so once the rail's content is taller than 100vh the browser takes the overflow out of the
    items themselves rather than scrolling — and `height: var(--topbar-h)` on `.side-brand`
    became a suggestion. That is why the mark was squashed in the Admin Panel and nowhere
    else: the admin rail is the only one with ten groups, and it is the only one that
    overflows. Reported from a screenshot 2026-09-06.

    On the container's children rather than on `.side-brand` alone, because the next thing
    added to this rail would have had the same bug and it would have looked like a different
    one. A column that scrolls should overflow, never compress. */
.side > * { flex-shrink: 0; }
/*  Room above a row the fragment lands on, so the chosen row arrives a little inside the rail
    rather than flush against its top edge — where it would read as the first row of the rail
    instead of the one that was clicked. Same reasoning as `.ib-list li`. */
/*  The anchor rows scroll to. An empty, unfocusable marker sitting immediately before its
    link — see the note in `admin/_shell.html` for why it is not the link itself. */
.nav-a { display: block; height: 0; scroll-margin-top: 70px; }
/*  The brand block is defined **once**, further down, beside the rule that sets the rail's
    height against the topbar. There were two `.side-brand` rules for one element and the
    later one won -- it set `flex-direction: column` inside a 53px box, so the mark stacked
    on top of the wordmark and was clipped by the sidebar's own edge. Reported from a
    screenshot; invisible in the file, because each rule reads correctly on its own.

    This is the fourth duplicate-declaration bug in two days (four identical rail-row rules,
    two brand rules). The rule to take from it: when a selector already exists, edit it --
    do not add a second one lower down and trust the cascade to mean what you intended. */
.side-brand b { font-size: 15.5px; font-weight: 500; letter-spacing: -.01em; line-height: 1.15; }

.side-sec { padding: 15px 16px 5px; }
.side-sec .kicker {
  font-size: 10.5px; letter-spacing: .15em; text-transform: uppercase;
  color: var(--muted); font-weight: 700;
}
.side-nav { display: flex; flex-direction: column; }
.side-nav a {
  display: flex; align-items: center; gap: 9px; padding: 9px 16px;
  font-size: 14.5px; color: var(--soft); text-decoration: none;
  border-left: 2px solid transparent;
}
.side-nav a:hover { color: var(--ink); opacity: 1; }
/*  The group's "something inside" mark. Sits where the count used to, so nothing shifts when
    a group gains or loses one. `--ok` rather than a new green: the palette already has a
    measured one and a second would be a colour nobody chose. */
/*  Beside the label, not out at the edge. Operator, 2026-09-06 — and they are right: a mark
    pushed to the far right of the row reads as belonging to the caret next to it rather than
    to the word it is about, and on a wide rail there is an inch of nothing between the two.

    `margin-left: -3px` against the row's own `gap: 9px`: a 7px dot needs less air than a word
    does, and at the full gap it looked detached from the label it modifies. The caret keeps
    its own `margin-left: auto` and stays at the edge, so nothing else in the row moves. */
.side-dot {
  flex: none; margin-left: -3px; align-self: center;
  width: 7px; height: 7px; border-radius: 50%; background: var(--ok);
}

.side-nav a .ct {
  margin-left: auto; font-size: 12px; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.side-nav a.on {
  color: var(--ink); font-weight: 500; border-left-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 6%, transparent);
}

.side-case { margin: 13px 16px 0; padding: 12px 0 0; border-top: 1px solid var(--rule); }
.side-case .nm { font-size: 14.5px; font-weight: 500; line-height: 1.35; }
.side-case .id { font-size: 12px; color: var(--muted); margin-top: 2px; font-variant-numeric: tabular-nums; }
.side-meter { height: 4px; background: var(--rule); border-radius: 2px; overflow: hidden; margin-top: 9px; }
.side-meter i { display: block; height: 100%; background: var(--accent); }
.side-case .pc { font-size: 12px; color: var(--muted); margin-top: 6px; font-variant-numeric: tabular-nums; }

.side-foot { margin-top: auto; padding: 13px 16px 0; border-top: 1px solid var(--rule); }
.side-foot a { display: block; font-size: 13.5px; color: var(--soft); text-decoration: none; padding: 3px 0; }
.side-foot .who { font-size: 13.5px; font-weight: 500; word-break: break-all; }
.side-foot form { margin: 4px 0 0; }
.side-foot button {
  font: inherit; font-size: 13.5px; color: var(--soft); background: none; border: 0;
  padding: 3px 0; cursor: pointer;
}

.app-main { background: var(--paper); min-width: 0; }
.app-top {
  display: flex; align-items: center; gap: 16px; padding: 0 26px; min-height: 52px;
  border-bottom: 1px solid var(--rule); background: var(--surface); flex-wrap: wrap;
}
.app-top .crumb { font-size: 12.5px; color: var(--muted); }
.app-top .crumb b { color: var(--soft); font-weight: 400; }
.app-top .sp { margin-left: auto; }
.app-top .langsw { font-size: 13px; }
/*  ── The content gutter, and the one rule that has to cancel it ──────────────────────
    `.pg`'s top padding and `.prof`'s negative margin are the same number in opposite
    directions: the profile band bleeds to the edges of the column, and any drift between the
    two shows as a stripe of page above the banner. They were written as `22px` and `-22px`
    independently, which is a coupling nothing enforced. Now neither can move without the
    other.

    The top gutter came down from 22px on 2026-09-06: with `.pg-head` above it the space over
    a page heading was 52px, which the operator reported as too much on every page. */
:root { --pg-pad-y: 18px; --pg-pad-x: 26px; }
.pg { padding: var(--pg-pad-y) var(--pg-pad-x) 34px; }

/*  ── The page heading block ──────────────────────────────────────────────────────────
    Thirty templates carried this as an inline `style="padding:…"`, in **four different
    values** -- 30, 40, 44 and 54 -- so no two pages agreed on how far below the bar a
    heading sat and no single edit could change any of it. One class, one number.

    6px on top of the 18px gutter: enough that the eyebrow is not touching the bar, little
    enough that the first thing on the page is near the top of it. */
.pg-head { padding: var(--pg-head-y) 0 4px; }

/* One breakpoint, and it collapses rather than hides. There is no script here, so a
   sidebar that needs a control to reopen is a sidebar somebody can be shut out of --
   below 900px the rail becomes a band across the top and the page scrolls normally. */
@media (max-width: 900px) {
  .app { grid-template-columns: 1fr; }
  /* Not sticky below the breakpoint: the rail is a band across the top there, and a band
     pinned at 100vh would be the whole screen. */
  .side { border-right: 0; border-bottom: 1px solid var(--line); padding-bottom: 10px;
          position: static; height: auto; overflow: visible; }
  .side-nav { flex-direction: row; flex-wrap: wrap; }
  .side-nav a { border-left: 0; border-bottom: 2px solid transparent; padding: 6px 14px; }
  .side-nav a.on { border-left-color: transparent; border-bottom-color: var(--accent); }
  .side-foot { margin-top: 10px; }
  .pg { padding: 18px 16px 28px; }
}

/* `.wrap narrow` capped its children for readability; inside the shell the content column
   is already bounded by the sidebar, so only the cap is wanted and not the second gutter
   `.wrap` would add on top of `.pg`. Same 1104px, expressed the same way. */
.pg.narrow > * { max-width: min(1104px, 100%); }

/* The interview inside the shell. The rail is the sidebar now, so the grid loses its first
   column and `.pg` supplies the gutter `.iv-wide` used to. `.iv3` and `.iv-wide` were used
   by `case/step.html` and nothing else; they are gone with it. */
/* The progress aside takes the same width as the rail opposite it. It was 320px against a
   224px rail, so the two columns framing the page were 96px apart and the page leaned. Same
   `--rail` token as every other rail here, for the reason the token exists: four
   hand-written numbers is how they drifted apart in the first place. */
.iv2 { display: grid; grid-template-columns: minmax(0, 1fr) var(--rail); gap: 0; align-items: start; }
.iv2 .pane { padding: 22px 40px 60px 0; min-width: 0; }
@media (max-width: 1100px) {
  .iv2 { grid-template-columns: 1fr; }
  .iv2 .pane { padding-right: 0; }
}

/* The rail, rendered inside the sidebar. Every mark rule above still applies unchanged --
   `.stepno`, `.stepmark`, `li.complete`, `li.incomplete`, `li.now` -- and only the container's
   own column padding and dividing border are neutralised, because in the sidebar the divider
   is the sidebar's own border. */
.side .rail { padding: 14px 20px 6px; border-right: 0; }
.side .rail h4 { margin: 0 0 10px; }
.side .rail li a { font-size: 13.5px; padding: 3px 0; }
.side .rail li.now { margin-left: -20px; padding-left: 18px; }

/* ---------- shell: the topbar profile control, and the rule that must line up ----------
   Added 2026-08-29 on the operator's mark-up of the running app. Two things.

   **Symmetry.** The sidebar's brand block and the topbar are the two things at the top of
   the page, and their bottom borders were at different heights -- 18px of sidebar padding
   plus the brand's own, against a 52px topbar -- so the horizontal rule broke at the seam.
   Both now derive from one value, which is the only way two rules stay level after either
   is edited. */
:root { --topbar-h: 64px; }   /* was 53. The brand's 26px mark and two lines of type had no
                                 room in it and sat hard against both edges. The height is
                                 shared with `.app-top`, so raising it keeps the rule under
                                 the brand level with the rule under the topbar -- which is
                                 the symmetry that was off, not the widths. */
.side { padding-top: 0; }
/*  Mark, then the name in both scripts, on one row aligned with the topbar beside it.

    A **row**, not a column: the column was for a wordmark alone, and the mark added to it
    stacked rather than sat beside. `align-items: center` rather than baseline, because the
    mark is an image with no baseline of its own -- a baseline row hangs it from its bottom
    edge and leaves it low against the type.

    The two lines are **live text**, not the `wordmark-bilingual-red.svg` lockup, and the
    reason is the theme. That file paints its Latin in ink (#1A1A17), which is invisible on
    the dark rail; serving a light and a dark copy would mean two requests and two files to
    keep in step for one line of type. Live text inherits `color` and is correct in both
    themes for free.

    Kana as text is safe **here** and nowhere else: this application's own UI is bilingual
    throughout and `--f-body` already leads with Japanese faces, so a machine that cannot
    render たくみペン cannot render the interview either. The brand *assets* stay outlines
    because they leave the platform -- an email, a print, somebody else's machine. */
.side-brand {
  height: var(--topbar-h); display: flex; flex-direction: row; align-items: center;
  gap: 10px; padding: 0 16px; border-bottom: 1px solid var(--rule);
  text-decoration: none; color: inherit;
}
.side-mark { width: 26px; height: 26px; flex: 0 0 auto; display: block; }
.side-brand .nm { display: flex; flex-direction: column; min-width: 0; }
/* Tabular-ish tracking on the kana: at 10.5px the default spacing sets たくみペン tighter
   than the Latin above it, and the two lines read as different weights rather than one block. */
.side-brand .kana { font-size: 10.5px; color: var(--muted); letter-spacing: .06em; line-height: 1.3; }
/* The topbar stays too: it carries the profile control and the language switch, and a
   control that scrolls away is one somebody has to hunt for. Above the content but below the
   profile menu, which opens over it. */
.app-top { min-height: var(--topbar-h); position: sticky; top: 0; z-index: 20; }

/* **The account controls belong in one place, at the top right.** They were in the sidebar
   foot, which put sign-out at the bottom of a column whose length depends on how many nav
   rows a person's role gives them -- so the control moved down the screen as the rail grew.
   A fixed corner does not move.

   Built on the same `.mgroup`/`.mdrop` above: hover *and* `:focus-within`, so tabbing to the
   button reveals the menu and the next Tab enters it. No script, and none is wanted here --
   sign-out is a form post, and a menu that needs JavaScript to reach it is a menu that can
   strand somebody signed in. */
.who-btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 8px 5px 5px; border-radius: 2px; text-decoration: none; color: var(--soft);
  /*  It became a `<button>` on 2026-09-01 so that clicking it opens the menu instead of
      navigating -- and picked up the browser's default button chrome with it: a grey square
      border and a button background around the avatar. Resetting those is the other half of
      that change, and it was missed because the rule declared no border, so nothing in the
      stylesheet looked wrong. A UA default is a declaration you did not write. */
  border: 0; background: none; font: inherit; cursor: pointer;
}
.who-btn:hover, .mgroup:focus-within .who-btn { background: var(--panel); color: var(--ink); }
.who-btn .av {
  width: 26px; height: 26px; flex: 0 0 auto; border-radius: 50%;
  background: var(--accent); color: var(--paper);
  display: grid; place-items: center; font-size: 11px; font-weight: 700; letter-spacing: .02em;
}
/* `.nm` was the name beside the avatar and is gone: a topbar is on screen the whole time a
   person is signed in, including on a shared machine and in every screenshot sent to support,
   and the name here was the address the account is keyed on. The menu still names them. */
.who-btn { padding: 5px 6px; gap: 5px; }
.who-menu { top: calc(100% + 8px); left: auto; right: -8px; min-width: 208px; z-index: 40; }
.who-menu .hd {
  padding: 8px 16px 9px; border-bottom: 1px solid var(--rule); margin-bottom: 5px;
}
.who-menu .hd b { display: block; font-size: 13.5px; font-weight: 500; word-break: break-all; }
.who-menu .hd span { display: block; font-size: 11.5px; color: var(--muted); margin-top: 1px; }
.who-menu form { margin: 5px 0 0; border-top: 1px solid var(--rule); padding-top: 5px; }
.who-menu button {
  display: block; width: 100%; text-align: left; font: inherit; font-size: 14.5px;
  padding: 7px 16px; color: var(--soft); background: none; border: 0; cursor: pointer;
}
.who-menu button:hover { background: var(--panel); color: var(--ink); }

@media (max-width: 900px) {
  .side-brand { height: auto; padding: 14px 16px; }
}

/* Public pages carry their own `.wrap` -- a 1560px centred column with 32px gutters -- and
   inside the shell that is a second gutter on top of `.pg`'s, and a second centring inside a
   column the sidebar has already narrowed. Neutralised rather than removed from 31 templates,
   because those pages are still served without the shell to anybody signed out and the
   `.wrap` is right there. */
.app .wrap { max-width: none; margin: 0; padding: 0; }
.app .wrap.narrow > * { max-width: min(1104px, 100%); }

/* The admin rail inside the shared shell, 2026-08-29. `admin/_shell.html` used to draw its
   own `.adm-side` column; it now overrides `{% block sidenav %}` and the column belongs to
   `.side`. The row styling is kept -- same icons, same active mark, same pending badge -- and
   only the container geometry is dropped, because the container is the shell's now. */
.side .adm-sec {
  padding: 15px 16px 5px; font-size: 10.5px; letter-spacing: .15em;
  text-transform: uppercase; color: var(--muted); font-weight: 700;
}
.side .adm-link {
  display: flex; align-items: center; gap: 9px; padding: 9px 16px;
  font-size: 14.5px; color: var(--soft); text-decoration: none;
  border-left: 2px solid transparent;
}
.side .adm-link:hover { color: var(--ink); opacity: 1; }
.side .adm-link.on {
  color: var(--ink); font-weight: 500; border-left-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 6%, transparent);
}
.side .adm-ic { width: 16px; height: 16px; flex: 0 0 auto; opacity: .7; }
.side .adm-link.on .adm-ic { opacity: 1; }
.side .adm-count {
  margin-left: auto; font-size: 11.5px; font-variant-numeric: tabular-nums;
  background: var(--accent); color: var(--paper);
  border-radius: 9px; padding: 1px 7px; line-height: 1.5;
}

/* ---------- the profile page ----------------------------------------------------------
   A banner, an avatar over it, an identity line and tabs. Added 2026-08-29.

   The banner is a gradient in the project's own accent rather than an image: there is no
   upload for one, and a stock photograph would be the first image this application serves
   that means nothing. */
/*  Bleeds the band to the column's edges by cancelling `.pg`'s gutter exactly -- see the
    note on `--pg-pad-y`. Calculated from the same tokens rather than repeating the numbers,
    because the numbers repeated are what let them drift. */
.prof { margin: calc(var(--pg-pad-y) * -1) calc(var(--pg-pad-x) * -1) 0; }
.prof-banner {
  height: 148px;
  /*  ── A calculated gradient, not a picture ────────────────────────────────────────────
      The drawn scene (`banner-blossom-*.svg`, `tools/build-banner.py`, `docs/BANNER.md`) was
      removed on the operator's instruction 2026-09-06 and every part of it deleted with it --
      165KB of SVG, its generator, its document and its five checks. A picture of somewhere on
      a page about somebody was decoration that had to be maintained; this is one declaration.

      **Blue for an applicant, red for a professional**, and the blue is the link colour
      because it is the same `--accent` token, not a value matched by eye.

      Fading to `rgb(… / 0)` rather than to `transparent`: `transparent` is `rgba(0,0,0,0)`,
      so a fade towards it travels through black and leaves a grey cast across the middle of
      the band. Holding the channels and dropping only the alpha keeps the hue constant top to
      bottom, which is what "subtle and even" requires.

      Three stops, not two. A straight two-stop fade reads as heaviest at the very top and
      then thins too quickly, because perceived lightness is not linear in alpha; the midpoint
      at 45% flattens the falloff so the band thins evenly to nothing. */
  background-image: linear-gradient(
    to bottom,
    rgb(var(--accent-rgb) / .42) 0%,
    rgb(var(--accent-rgb) / .17) 45%,
    rgb(var(--accent-rgb) / 0) 100%);
  /*  No `background-color` underneath any more. It existed so a failed image left the band
      accented rather than white -- there is no image to fail now, and a solid colour beneath
      a fade-to-nothing would simply cancel the fade. */
  background-repeat: no-repeat;
}

/*  A professional's band is the brand red. Same construction, same stops, one token changed:
    two gradients written out twice would drift the moment either is adjusted. */
.prof-banner.is-pro {
  background-image: linear-gradient(
    to bottom,
    rgb(var(--brand-red-rgb) / .42) 0%,
    rgb(var(--brand-red-rgb) / .17) 45%,
    rgb(var(--brand-red-rgb) / 0) 100%);
}

/*  An uploaded banner still wins: `.prof-banner[style]` carries a `background-image` inline,
    which outranks both rules above on specificity alone. Nothing needed here for that.

    `prefers-contrast: more` used to flatten the scene to a solid band. It is dropped: the
    gradient at .42 alpha is already quieter than the flat accent that was the high-contrast
    fallback, and a rule that made the page MORE saturated for somebody who asked for more
    contrast would have been backwards. */

/* The avatar overlaps the banner by half its own height, so the same amount of it is on the
   band as below it. Before, `-42px` against a 92px avatar left 42 above and 50 below, which
   is the kind of near-miss that reads as wrong without a reader being able to say why. */
/*  Corrected 2026-08-29. The name was bottom-aligned against the avatar, and the identity
    block is taller than the part of the avatar that hangs below the band -- so the heading's
    first 9px sat on the banner, dark text on dark navy, exactly as reported.

    The fix is that **only the avatar overlaps**. `.prof-id` now starts at the banner's lower
    edge and the avatar is pulled up out of it, so no amount of text can climb onto the band:
    a long name that wraps to two lines grows downward, onto paper. That is the case the old
    arrangement got wrong and would have got wrong again at the next font size.

    The other repair offered -- extend the banner down behind the whole block -- was weighed and
    rejected. `--accent` inverts between themes: #2E3A59 in light, #9DB0D6 in dark. Text laid on
    the banner would need one colour legible on both a dark navy and a light periwinkle, and
    there is no such colour. Keeping every word on paper is the only version that survives the
    theme switch, so the geometry moved rather than the band. */
.prof-id { display: flex; align-items: flex-start; gap: 20px; padding: 0 26px; }
.prof-av {
  margin-top: -46px;
  width: 92px; height: 92px; flex: 0 0 auto; border-radius: 6px;
  background: var(--panel); border: 4px solid var(--paper);
  box-shadow: 0 2px 10px rgb(0 0 0 / 14%);
  display: grid; place-items: center;
  font-size: 30px; font-weight: 500; color: var(--soft); letter-spacing: .02em;
}
/* Optically set against the part of the avatar that shows below the band rather than aligned
   to any of its edges -- the avatar's edges are its border and its shadow, and lining type up
   with a shadow is what made the previous rule need a comment to defend itself. */
.prof-who { padding-top: 6px; padding-bottom: 10px; min-width: 0; }
.prof-who h1 { font-size: 24px; font-weight: 500; margin: 0; letter-spacing: -.01em; line-height: 1.2; }
.prof-tick { color: var(--ok); font-size: 17px; margin-left: 4px; }
.prof-meta {
  display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: 5px;
  font-size: 13.5px; color: var(--muted);
}
.prof-tabs {
  display: flex; gap: 4px; flex-wrap: wrap;
  padding: 16px 26px 0; border-bottom: 1px solid var(--rule); margin-bottom: 22px;
}
.prof-tabs a {
  padding: 8px 14px 9px; font-size: 14.5px; color: var(--soft); text-decoration: none;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.prof-tabs a:hover { color: var(--ink); opacity: 1; }
.prof-tabs a.on { color: var(--ink); font-weight: 500; border-bottom-color: var(--accent); }
.prof-tabs .ct {
  font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums;
  background: var(--panel); border-radius: 9px; padding: 1px 7px; margin-left: 4px;
}

/* Documents grouped by the case that produced them. A case is the folder; there is no other
   grouping this application has, and inventing one would be inventing a hierarchy. */
.folders { display: grid; grid-template-columns: repeat(auto-fill, minmax(232px, 1fr)); gap: 14px; }
.folder {
  display: block; padding: 16px 17px 15px; text-decoration: none; color: inherit;
  border: 1px solid var(--line); background: var(--surface);
}
.folder:hover { border-color: var(--accent); opacity: 1; }
.folder-ic { font-size: 20px; color: var(--accent); line-height: 1; }
.folder-t { font-size: 15px; font-weight: 500; margin-top: 10px; line-height: 1.35; }
.folder-m { font-size: 13px; color: var(--muted); margin-top: 4px; font-variant-numeric: tabular-nums; }

@media (max-width: 900px) {
  .prof { margin: -18px -16px 0; }
  .prof-id, .prof-tabs { padding-left: 16px; padding-right: 16px; }
  .prof-av { width: 70px; height: 70px; font-size: 24px; }
}

/* ---------- settings, presented as sections ------------------------------------------
   Added 2026-08-29 on the operator's second reference. The shape is a labelled section on
   the left and its fields on the right: a person scanning for the one thing they came to
   change reads a column of section names rather than a column of every field in the account.

   It is a two-column grid that collapses to one, not a table, so the label sits above its
   own fields on a narrow screen instead of beside an empty cell. */
.set { display: grid; grid-template-columns: 232px minmax(0, 1fr); gap: 0 34px;
       padding: 22px 0; border-bottom: 1px solid var(--rule); align-items: start; }
.set:last-child { border-bottom: 0; }
.set-h { font-size: 15px; font-weight: 500; margin: 0; line-height: 1.4; }
.set-d { font-size: 13.5px; color: var(--muted); margin: 5px 0 0; line-height: 1.55; }

/* The field grid. `auto-fit` rather than a fixed column count, so a section with one field
   does not leave two empty tracks and a section with five wraps without being told to. */
.set-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(232px, 1fr)); gap: 14px 18px; }
.set-fields.one { grid-template-columns: 1fr; }
.set-f { min-width: 0; }
.set-f > label, .set-f > .lab {
  display: block; font-size: 13px; font-weight: 500; color: var(--soft); margin-bottom: 5px;
}
.set-f input, .set-f select, .set-f textarea { width: 100%; }
.set-f .hint { font-size: 12.5px; color: var(--muted); margin-top: 5px; line-height: 1.5; }
/*  A read-only value, not an input -- so no input rule reaches it and its metrics have to
    be kept in step by hand. Same padding, font size and border width as the inputs above,
    so a row of fields is one row; the muted colour and panel background are what say it
    cannot be typed in, and those are deliberately NOT matched. */
.set-f .ro {
  padding: 11px 13px; border: 1px solid var(--rule); background: var(--panel);
  color: var(--soft); font-size: 17px; border-radius: 2px;
}
.set-act { margin-top: 16px; }

@media (max-width: 820px) {
  .set { grid-template-columns: 1fr; gap: 12px; }
}


/* The reference group's second level. Indented rather than collapsible: there is no script
   on a signed-in page, and a group that needs one to open is a group somebody can be shut
   out of. Guide is the row above and remains a real link to its own page. */
/*  The submenu indent, and the selector list is the whole point.

    `.side-sub a` alone is specificity (0,1,1). `.side .adm-link` further down is (0,2,0) and
    wins, so **every submenu row in the Admin Panel rendered at the parent's indent** while
    the user rail indented correctly -- same markup, same `<details class="side-group">`,
    same `.side-sub` wrapper, different outcome, because one rail's links carry a class the
    other's do not.
    
    Nothing looked broken enough to report: an un-indented row is a row, and the reader
    supplies the hierarchy from the caret. Reported by the operator 2026-09-04.
    
    `.side .side-sub a` is (0,2,1) and beats it. Both selectors are kept so the rule holds
    inside `.side` and outside it, and it is ONE rule rather than a second lower down --
    decisions.md 2026-08-29, after the `.side-brand` bug and again after `.brand span`. */
.side .side-sub a,
.side-sub a { padding-left: 34px; font-size: 14px; color: var(--muted); }
.side-sub a:hover { color: var(--ink); }
.side-sub a.on { color: var(--ink); }

/* A group whose current page is one of its children. base.html has marked its masthead
   groups this way since they were built: `on` is this link's own page, `group-on` is
   somewhere inside it. Quieter than `on` on purpose -- two rows that look equally current
   is a nav that cannot say where you are, which is what the "exactly one entry highlighted"
   check exists to prevent. */
.side .adm-link.group-on { color: var(--soft); font-weight: 500; }

/* ---------- collapsible sidebar groups -------------------------------------------------
   `<details>`/`<summary>`, 2026-08-29. The one disclosure widget the platform gives without
   script: a real button to a screen reader, opened by Enter or Space, and it needs nothing
   from this project's zero-JavaScript position.

   `open` is set on the server from the page being rendered -- see the note in _shell.html.
   The marker is removed and replaced with a caret that rotates, because the default triangle
   sits outside the row and cannot be aligned with the icons above it. */
.side-group { border: 0; }
.side-group > summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; gap: 9px; padding: 9px 16px;
  font-size: 14.5px; color: var(--soft);
  border-left: 2px solid transparent;
}
.side-group > summary::-webkit-details-marker { display: none; }
.side-group > summary:hover { color: var(--ink); }
.side-caret {
  margin-left: auto; font-style: normal; font-size: 10px; color: var(--faint);
  transition: transform .12s ease;
}
.side-group[open] > summary { color: var(--ink); font-weight: 500; }
.side-group[open] .side-caret { transform: rotate(180deg); }
/* Marks the group holding the current page even while it is shut, which is what a person
   scanning a collapsed rail needs to see. */
.side-group[open] > summary { background: color-mix(in srgb, var(--accent) 4%, transparent); }

/* The submenu is indented past its group and eased open.

   **The easing is real where the browser supports it and absent where it does not**, which is
   worth stating rather than discovering. A `<details>` element cannot animate its own height
   without `interpolate-size: allow-keywords` and `::details-content` -- Chromium 131 and
   later. Everywhere else the rows appear instantly, which is the behaviour this rail had
   yesterday. Nothing depends on the animation, and nothing is script.

   The rows are animated rather than the element: `opacity` and a small `translateY` on the
   children work in every browser and carry most of the impression of the thing opening. */
.side-group > .side-sub { padding-left: 12px; }
/*  A transition, not a keyframe. Both were declared on this element, which is redundant, and
    the keyframe was the one that ran. His standards are explicit about why that is the wrong
    choice here: a CSS transition can be interrupted and retargeted mid-flight, a keyframe
    restarts from zero -- and opening and closing rail groups is exactly the rapid, reversible
    interaction that exposes the difference. Shortened to 140ms as well: the rail is used tens
    of times a session, which the frequency table puts in "reduce". */
.side-group > .side-sub a {
  opacity: 0; transform: translateY(-3px);
  transition: opacity 140ms var(--ease-out), transform 140ms var(--ease-out);
}
.side-group[open] > .side-sub a { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .side-group > .side-sub a { transition: none; opacity: 1; transform: none; }
}

/* Chromium 131+: the disclosure itself eases rather than snapping. Guarded by @supports so
   the declaration is inert everywhere else rather than half-applied. */
@supports (interpolate-size: allow-keywords) {
  .side-group { interpolate-size: allow-keywords; }
  .side-group::details-content {
    block-size: 0; overflow: hidden;
    transition: block-size .2s ease, content-visibility .2s allow-discrete;
  }
  .side-group[open]::details-content { block-size: auto; }
}

/* A stronger mark on the row actually being looked at. The 5.5% wash read as a hover state
   next to rows that also lighten on hover, so the current page and the row under the cursor
   were telling the same story. Twice the wash and a full-height accent edge. */
.side .adm-link.on, .side-nav a.on {
  background: color-mix(in srgb, var(--accent) 13%, transparent);
  border-left-color: var(--accent); border-left-width: 3px;
  color: var(--ink); font-weight: 500;
}
.side .side-sub .adm-link.on, .side-sub a.on {
  background: color-mix(in srgb, var(--accent) 11%, transparent);
}

/*  The panel's own row, in the brand red.

    Placed here, after `.side .adm-link.on`, and at the same specificity -- not earlier and
    not at `.adm-home` alone. The admin rail renders inside `base.html`'s `.side`, so
    `.side .adm-link.on` (0,3,0) governs the active row and sets `color: var(--ink)`. A bare
    `.adm-home` rule (0,1,0) loses, and would lose *silently*: the row would be red on every
    page except the one page it is the heading of. That is the cascade defect
    `decisions.md` 2026-08-29 records, where a second `.side-brand` rule lower down won and
    nobody could see why the first one had stopped applying. */
.side .adm-home, .side .adm-home.on, .side .adm-home:hover {
  color: var(--brand-red);
  font-weight: 500;
}

/* ---------- toggles --------------------------------------------------------------------
   A switch, on the operator's reference, in this project's own palette rather than the
   reference's green.

   **It is a `<button type="submit">`, not a checkbox.** There is no script on a signed-in
   page, so a checkbox would need a Save button beside it and the switch would show a state
   the server does not have yet -- a control that lies until somebody presses something else.
   A submit button posts the opposite of what it currently is, and the page comes back with
   the truth on it. One click, one round trip, no divergence.

   `aria-pressed` carries the state, which is what makes it a switch rather than a decorated
   button to anything that is not looking at the colour. */
.toggle-row {
  display: flex; align-items: center; gap: 18px; padding: 13px 0;
  border-bottom: 1px solid var(--rule);
}
.toggle-row:last-child { border-bottom: 0; }
.toggle-row .tl { min-width: 0; }
.toggle-row .tl b { display: block; font-size: 14.5px; font-weight: 400; color: var(--ink); }
.toggle-row .tl span { display: block; font-size: 13px; color: var(--muted); margin-top: 2px; line-height: 1.5; }

.toggle {
  margin-left: auto; flex: 0 0 auto; position: relative;
  width: 42px; height: 24px; padding: 0; border: 0; cursor: pointer;
  border-radius: 12px; background: var(--line);
  transition: background .14s ease;
}
.toggle::after {
  content: ''; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px;
  border-radius: 50%; background: var(--surface);
  box-shadow: 0 1px 3px rgb(0 0 0 / 26%);
  transition: transform .14s ease;
}
.toggle[aria-pressed="true"] { background: var(--ok); }
.toggle[aria-pressed="true"]::after { transform: translateX(18px); }
.toggle:hover { filter: brightness(1.06); }
.toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* A group of mutually exclusive choices -- system, light, dark -- where a switch cannot
   express three states. Same treatment, one selected. */
.seg { display: inline-flex; border: 1px solid var(--line); border-radius: 3px; overflow: hidden; }
.seg button {
  font: inherit; font-size: 13.5px; padding: 7px 15px; border: 0; cursor: pointer;
  background: var(--surface); color: var(--soft);
}
.seg button + button { border-left: 1px solid var(--line); }
.seg button:hover { color: var(--ink); }
.seg button[aria-pressed="true"] { background: var(--accent); color: var(--paper); font-weight: 500; }

/* The profile menu's rows read larger than the rail beside them: `.mdrop a` is 16px from the
   masthead it was written for, where the rail is 14.5px. Two navigations on one screen at two
   sizes look like a mistake, and the smaller of the two is the one a person reads more often. */
.who-menu a, .who-menu button { font-size: 14.5px; }
.who-menu .hd b { font-size: 13.5px; }

/* ---------- the branding screen ---------------------------------------------------------
   A grid of marks with what each is for beside it. The note under each is the part that
   matters: a brand page that is only a grid of logos is a page somebody downloads the wrong
   file from. */
.bm-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(196px, 1fr)); gap: 16px; margin: 14px 0 0; }
.bm-grid.wide { grid-template-columns: repeat(auto-fill, minmax(268px, 1fr)); }
.bm {
  border: 1px solid var(--line); background: var(--surface);
  padding: 16px 16px 14px; display: flex; flex-direction: column;
}
.bm-art { display: grid; place-items: center; min-height: 96px; margin-bottom: 12px; }
.bm-art img { max-width: 100%; max-height: 76px; }
.bm b { font-size: 14.5px; font-weight: 500; }
.bm span { font-size: 12.5px; color: var(--muted); margin-top: 4px; line-height: 1.5; flex: 1 1 auto; }
.bm-dl { margin-top: 12px; font-size: 12.5px; color: var(--accent); align-self: flex-start; }
/* A reversed mark on a light card proves nothing. */
.bm.dark { background: #17181A; border-color: #2C2F34; }
.bm.dark b { color: #E9E7E1 } .bm.dark span { color: #948F84 }

/* Placement studies. Deliberately crude -- they show where a mark sits and at what size, and
   a realistic mock would invite somebody to judge the mock instead. */
.bm-uses { display: grid; grid-template-columns: repeat(auto-fill, minmax(232px, 1fr)); gap: 16px; margin-top: 14px; }
.bm-use { border: 1px solid var(--line); background: var(--surface); padding: 14px; }
.bm-use b { display: block; font-size: 14px; font-weight: 500; margin-top: 12px; }
.bm-use span { display: block; font-size: 12.5px; color: var(--muted); margin-top: 4px; line-height: 1.5; }
.bm-use-art { height: 118px; border: 1px solid var(--rule); background: var(--paper); overflow: hidden; }
.bm-use-art.app { display: grid; grid-template-columns: 84px 1fr; }
.bm-use-side { background: var(--panel); border-right: 1px solid var(--line); padding: 10px 8px; }
.bm-use-side img { width: 22px; height: 22px; display: block; }
.bm-use-side span { display: block; font-size: 9px; color: var(--soft); margin-top: 5px; }
.bm-use-art.mail { padding: 14px; }
.bm-use-art.mail img { width: 132px; display: block; }
.bm-use-art.print { padding: 12px; display: flex; flex-direction: column; justify-content: space-between; }
.bm-use-art.print img { width: 26px; align-self: flex-end; }
.bm-use-art.avatar { display: grid; place-items: center; }
.bm-use-art.avatar img { width: 54px; height: 54px; }
.bm-use-lines i { display: block; height: 5px; background: var(--rule); margin-top: 7px; border-radius: 2px; }

.bm-rules { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; margin-top: 14px; }
.bm-rules > div { border-left: 2px solid var(--accent); padding: 2px 0 2px 13px; }
.bm-rules b { display: block; font-size: 14px; font-weight: 500; }
.bm-rules span { display: block; font-size: 12.5px; color: var(--muted); margin-top: 3px; line-height: 1.55; }

/* ---------------------------------------------------------------- search, 2026-08-29
   One box, on every list in the panel. `app/search.py` explains why the grammar is shared;
   this is the same argument applied to the chrome around it. */
.srch { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 4px 0 0; }
.srch input[type="search"] {
  flex: 1 1 280px; min-width: 0; padding: 7px 11px; font: inherit; font-size: 14px;
  border: 1px solid var(--line); background: var(--surface); color: var(--ink); border-radius: 2px;
}
.srch input[type="search"]:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.srch select { padding: 6px 9px; font: inherit; font-size: 13.5px;
               border: 1px solid var(--line); background: var(--surface); color: var(--ink); }
.srch-clear { font-size: 13.5px; color: var(--muted); }
.srch-count { font-size: 13px; color: var(--muted); margin-left: auto; font-variant-numeric: tabular-nums; }
.srch-warn { font-size: 13.5px; color: var(--warn); background: var(--warn-bg);
             border: 1px solid var(--warn-line); padding: 8px 11px; margin: 9px 0 0; }
.srch-help { margin: 9px 0 0; font-size: 13.5px; }
.srch-help > summary { cursor: pointer; color: var(--muted); list-style: none; }
.srch-help > summary::-webkit-details-marker { display: none; }
.srch-help > summary::before { content: "▸ "; }
.srch-help[open] > summary::before { content: "▾ "; }
.srch-help table { margin-top: 8px; }
mark { background: color-mix(in srgb, var(--accent) 26%, transparent); color: inherit;
       padding: 0 1px; border-radius: 2px; }

/* --------------------------------------------------------------- the document library */
.lib-shelves { display: flex; gap: 8px; flex-wrap: wrap; margin: 18px 0 0; }
.lib-shelf { display: flex; align-items: baseline; gap: 6px; padding: 6px 12px;
             border: 1px solid var(--line); font-size: 13.5px; color: var(--soft); }
.lib-shelf span { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.lib-shelf.on { border-color: var(--accent); color: var(--ink); font-weight: 500; }
.lib-hit { border: 1px solid var(--rule); background: var(--surface); padding: 13px 15px; margin-top: 12px; }
.lib-hit-t { display: block; font-size: 15px; font-weight: 500; }
.lib-line { display: flex; gap: 10px; margin-top: 6px; font-size: 13px; line-height: 1.5; }
.lib-line .n { flex: 0 0 auto; color: var(--faint); font-variant-numeric: tabular-nums;
               min-width: 3.5ch; text-align: right; }
.lib-read { display: grid; grid-template-columns: var(--rail) minmax(0, 1fr); gap: 34px; align-items: start; }
@media (max-width: 1000px) { .lib-read { grid-template-columns: 1fr; gap: 16px; } }
.lib-toc { position: sticky; top: calc(var(--topbar-h) + 14px); font-size: 13px; line-height: 1.45; }
.lib-toc b { display: block; font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
             color: var(--muted); margin-bottom: 7px; }
.lib-toc a { display: block; padding: 3px 0; color: var(--soft); }
.lib-toc a.l2 { padding-left: 10px; } .lib-toc a.l3 { padding-left: 22px; color: var(--muted); }
.lib-body { max-width: 76ch; line-height: 1.7; }
.lib-body h2 { font-size: 20px; font-weight: 500; margin: 30px 0 10px; }
.lib-body h3 { font-size: 16.5px; font-weight: 500; margin: 24px 0 8px; }
.lib-body h4, .lib-body h5, .lib-body h6 { font-size: 15px; font-weight: 500; margin: 20px 0 6px; }
.lib-body p { margin: 0 0 13px; }
.lib-body li { margin: 0 0 5px; }
.lib-body pre { background: var(--panel); border: 1px solid var(--rule); padding: 12px 14px;
                overflow-x: auto; font-size: 13px; line-height: 1.55; }
.lib-body code { background: var(--panel); padding: 1px 5px; font-size: 13px; }
.lib-body pre code { background: none; padding: 0; }
.lib-body blockquote { margin: 0 0 13px; padding: 2px 0 2px 15px;
                       border-left: 3px solid var(--line); color: var(--soft); }
.lib-body hr { border: 0; border-top: 1px solid var(--rule); margin: 26px 0; }
/*  ── A reference document is not an essay ────────────────────────────────────────────
    `.lib-body` caps at 76ch, which is right for reading and wrong for a seven-column table
    of statutes: the table is laid out inside that cap, so a Japanese column collapsed to a
    single character per line and the source URLs were clipped. Reported 2026-09-06.

    `wide` lifts the cap from the container and puts it back on the prose, one element type
    at a time. That way a paragraph still has a reading measure and a table still has the
    whole column -- rather than choosing between unreadable prose and an unreadable table. */
.lib-body.wide { max-width: none; }
.lib-body.wide > p,
.lib-body.wide > ul,
.lib-body.wide > ol,
.lib-body.wide > blockquote,
.lib-body.wide > h1,
.lib-body.wide > h2,
.lib-body.wide > h3,
.lib-body.wide > h4,
.lib-body.wide > h5,
.lib-body.wide > h6 { max-width: 76ch; }

/*  No column may collapse to one character. `min-width` on the cell rather than a fixed
    `table-layout`, because these tables have between three and seven columns and any fixed
    scheme would be wrong for most of them. The `.scroll-x` wrapper the renderer already
    emits takes the overflow. */
.lib-tab th, .lib-tab td { min-width: 8ch; }
.lib-tab { border-collapse: collapse; width: 100%; font-size: 13.5px; }
.lib-tab th, .lib-tab td { border: 1px solid var(--rule); padding: 6px 10px; text-align: left; vertical-align: top; }
.lib-tab th { background: var(--panel); font-weight: 500; }
.lib-dead { color: var(--muted); font-size: 12.5px; }

/*  The triage. A finding is marked by a left rule AND by the heading above it naming the
    severity in words -- colour is never the only signal (DESIGN-STANDARDS §6). */
.tri-q th { font-weight: 400; max-width: 62ch; }
.tri-yn { white-space: nowrap; }
.tri-yn label { margin-right: 14px; cursor: pointer; }
.tri-f { border-left: 3px solid var(--rule); padding: 2px 0 2px 14px; margin: 0 0 16px; }
.tri-f .tri-t { font-weight: 500; color: var(--ink); margin-bottom: 4px; }
.tri-f p { margin: 0 0 6px; max-width: 76ch; }
.tri-red  { border-left-color: var(--brand-red); }
.tri-amb  { border-left-color: var(--warn-line); }
.tri-ai   { border-left-color: var(--accent); }
.tri-moss { border-left-color: var(--ok); }

/* ------------------------------------------------------------------- compliance register */
.cmp-bar { display: flex; gap: 3px; margin-top: 18px; }
.cmp-seg { display: flex; flex-direction: column; justify-content: center; min-width: 0;
           padding: 11px 12px; color: var(--ink); background: var(--panel);
           border-left: 3px solid var(--line); }
.cmp-seg b { font-size: 19px; font-weight: 500; font-variant-numeric: tabular-nums; }
.cmp-seg span { font-size: 11.5px; color: var(--muted); white-space: nowrap;
                overflow: hidden; text-overflow: ellipsis; }
.cmp-seg.s-open { border-left-color: var(--preview); }
.cmp-seg.s-partial { border-left-color: var(--warn-line); }
.cmp-seg.s-met { border-left-color: var(--ok); }
.cmp { border: 1px solid var(--rule); background: var(--surface); padding: 15px 17px; margin-top: 12px; }
.cmp-h { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.cmp-h b { font-size: 15.5px; font-weight: 500; }
.cmp-auth { font-size: 12.5px; color: var(--muted); margin-top: 3px; }
.cmp-dl { display: grid; grid-template-columns: 122px minmax(0, 1fr); gap: 5px 16px; margin: 12px 0 0;
          font-size: 13.5px; line-height: 1.6; }
.cmp-dl dt { color: var(--muted); font-size: 11.5px; letter-spacing: .1em; text-transform: uppercase;
             padding-top: 3px; }
.cmp-dl dd { margin: 0; }
@media (max-width: 760px) { .cmp-dl { grid-template-columns: 1fr; gap: 2px 0; } }
.adm-pill.s-open { border-color: var(--preview); color: var(--preview); }
.adm-pill.s-partial { border-color: var(--warn-line); color: var(--warn); }
.adm-pill.s-met { border-color: var(--ok); color: var(--ok); }

/* ------------------------------------------------------------------------------ charts
   CSS and SVG, rendered on the server. No charting library and no CDN -- the same position
   the rest of the signed-in application holds, and it means no third party is told which
   metrics this operator looked at. */
.chart { display: flex; align-items: flex-end; gap: 2px; height: 132px; margin-top: 14px;
         padding: 0 1px; border-bottom: 1px solid var(--line); }
.chart-col { flex: 1 1 0; min-width: 0; height: 100%; display: flex; align-items: flex-end; }
.chart-col i { display: block; width: 100%; background: var(--accent); min-height: 1px; }
.chart-col:hover i { background: var(--preview); }
.chart-ax { display: flex; justify-content: space-between; font-size: 11.5px;
            color: var(--muted); margin-top: 5px; font-variant-numeric: tabular-nums; }
.chart-tab { margin-top: 8px; font-size: 13px; }
.chart-tab > summary { cursor: pointer; color: var(--muted); }
.meter { width: 140px; }
.meter i { display: block; height: 7px; background: var(--accent); min-width: 1px; }
.jmap { position: relative; border: 1px solid var(--rule); background: var(--panel);
        aspect-ratio: 3 / 2; max-width: 520px; margin-top: 12px; }
.jmap svg { width: 100%; height: 100%; display: block; }
.jmap circle { fill: var(--accent); fill-opacity: .28; stroke: var(--accent); stroke-width: .3; }
.jmap circle.hot { fill: var(--preview); fill-opacity: .55; stroke: var(--preview); }

/* --------------------------------------------------------------------------- reporting */
.rep-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(268px, 1fr)); gap: 14px;
            margin-top: 14px; }
.rep, .rep-wiz { display: block; border: 1px solid var(--rule); background: var(--surface);
                 padding: 14px 16px; color: inherit; }
.rep b, .rep-wiz b { display: block; font-size: 15px; font-weight: 500; }
.rep span, .rep-wiz span { display: block; font-size: 13px; color: var(--soft); margin-top: 5px; line-height: 1.55; }
.rep em { display: block; font-size: 12.5px; color: var(--muted); margin-top: 7px;
          font-style: normal; line-height: 1.5; }
.rep-wiz { margin-top: 18px; border-left: 3px solid var(--accent); }
.rep:hover, .rep-wiz:hover { border-color: var(--accent); }
.wiz { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 18px;
       margin-top: 18px; align-items: start; }
.wiz-step { border: 1px solid var(--rule); background: var(--surface); padding: 14px 16px; }
.wiz-n { display: inline-grid; place-items: center; width: 22px; height: 22px; border-radius: 50%;
         background: var(--accent); color: var(--paper); font-size: 12px; margin-bottom: 9px; }
.wiz-step label { display: block; font-size: 13.5px; font-weight: 500; }
.wiz-step input, .wiz-step select { display: block; width: 100%; margin-top: 6px; padding: 7px 10px;
  font: inherit; font-size: 14px; border: 1px solid var(--line);
  background: var(--paper); color: var(--ink); }
.wiz-step p { font-size: 12.5px; margin: 9px 0 0; line-height: 1.5; }
.sig { border: 1px solid var(--rule); border-left: 3px solid var(--line);
       background: var(--surface); padding: 11px 14px; margin-top: 10px; }
.sig.watch { border-left-color: var(--warn-line); }
.sig b { display: block; font-size: 14px; font-weight: 500; }
.sig span { display: block; font-size: 13px; color: var(--soft); margin-top: 4px; line-height: 1.55; }

/*  A line **between** rows, not under each one. Corrected 2026-08-30.

    The first version put `border-bottom` on every row and removed it from the last with three
    `:last-child` exceptions. That still draws a line under a row with nothing after it -- under
    `Guide`, a lone row above its own submenu, and under the last row of every group -- and a
    rule directly beneath a single short link, with nothing below to separate it *from*, reads
    as an underline on the link. Reported as exactly that.

    `a + a` draws only where there is a next sibling to divide from. It needs no exceptions: a
    lone row gets nothing, the last row of a group gets nothing, and "a line between each
    button" is what the selector literally says rather than what three rules together imply.

    The active row also suppresses the rule above and below it, so a highlighted band is bounded
    by its own background rather than cut across by a hairline running into it. */
.side-nav a + a,
.side-nav .adm-link + .adm-link { border-top: 1px solid var(--rule); }
.side-nav a.on, .side-nav a.on + a,
.side-nav .adm-link.on, .side-nav .adm-link.on + .adm-link { border-top-color: transparent; }
.side-group + .side-group > summary,
.side-nav + .side-group > summary { border-top: 1px solid var(--rule); }
.side-sub > a + a { border-top: 1px solid var(--rule); }

/* ------------------------------------------------------------------- the Access screen */
.acc-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(310px, 1fr)); gap: 14px;
            margin-top: 14px; align-items: start; }
.acc-card { border: 1px solid var(--rule); background: var(--surface); padding: 14px 17px; }
.acc-card b { display: block; font-size: 14.5px; font-weight: 500; margin-bottom: 8px; }
.acc-card ul { margin: 0; padding-left: 18px; font-size: 13.5px; line-height: 1.6; color: var(--soft); }
.acc-card li { margin-bottom: 5px; }
.acc-seats { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 14px;
             margin-top: 16px; }
/*  The seat card IS the submit button, so the whole card is the target without the control
    becoming a link -- `docs/ACCESS.md` §5 requires POST, and an `<a>` would be a GET a
    browser can follow on its own. Everything below therefore un-does the browser's button
    styling rather than styling a card that happens to contain a button. */
.acc-seat { appearance: none; -webkit-appearance: none; width: 100%; text-align: left;
            font: inherit; cursor: pointer;
            border: 1px solid var(--rule); border-left: 3px solid var(--accent);
            background: var(--surface); padding: 15px 17px; display: flex;
            flex-direction: column; align-items: flex-start; gap: 4px; }
.acc-seat b { font-size: 15px; font-weight: 500; color: var(--ink); }
.acc-seat .acc-seat-go { font-size: 13.5px; font-weight: 500; }
.acc-seat .acc-seat-id, .acc-seat .acc-seat-note { font-size: 13px; color: var(--soft); }
.acc-seat .acc-seat-id { margin-top: 4px; }
.acc-seat:hover { border-color: var(--line); background: var(--panel); }
.acc-seat:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/*  The two roles are told apart by colour, which is the whole reason the modifier exists.
    Applied to the left edge and to the action line, not to the card's body text: colour
    carrying meaning must not be the only signal, and the role is also written out in the
    title. Operator decision, 2026-09-02. */
.acc-seat--applicant { border-left-color: var(--accent); }
.acc-seat--applicant .acc-seat-go { color: var(--accent); }
.acc-seat--pro { border-left-color: var(--brand-red); }
.acc-seat--pro .acc-seat-go { color: var(--brand-red); }

/* ------------------------------------------------------ the profile image editor, 2026-08-31 */
.pedit { margin-top: 26px; }
.pedit h2 { font-size: 16px; font-weight: 500; margin: 0 0 4px; }
.pedit-row { display: flex; gap: 20px; align-items: flex-start; padding: 18px 0;
             border-top: 1px solid var(--rule); }
@media (max-width: 620px) { .pedit-row { flex-direction: column; } }
/* The preview is the shape the image will be shown in, not a generic thumbnail. Somebody
   uploading a portrait to a banner slot should see it cropped here rather than discover it
   on the page above. */
.pedit-prev { flex: 0 0 auto; display: grid; place-items: center; overflow: hidden;
              background: var(--panel); border: 1px solid var(--line); }
.pedit-prev.avatar { width: 92px; height: 92px; border-radius: 6px; }
.pedit-prev.banner { width: 232px; height: 34px; }
.pedit-prev img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pedit-prev span { font-size: 11.5px; color: var(--faint); }
.pedit-body { min-width: 0; flex: 1 1 auto; }
.pedit-body b { display: block; font-size: 14.5px; font-weight: 500; }
.pedit-spec { display: grid; grid-template-columns: auto 1fr; gap: 2px 14px; margin: 8px 0 0;
              font-size: 13.5px; }
.pedit-spec dt { color: var(--muted); }
.pedit-spec dd { margin: 0; color: var(--soft); }
.pedit-note { font-size: 13px; color: var(--muted); margin: 8px 0 0; line-height: 1.55; }
.pedit-file { display: block; margin-top: 11px; }
.pedit-file input { font: inherit; font-size: 13.5px; }
.pedit-acts { display: flex; gap: 8px; margin-top: 10px; }
.pedit-fine { font-size: 12.5px; color: var(--muted); line-height: 1.65; margin: 18px 0 0;
              padding-top: 14px; border-top: 1px solid var(--rule); }
/* The avatar becomes a frame for a picture rather than a box for two letters. */
.prof-av img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 3px; }

/* The demoted route picker on /begin. `<details>` because the platform gives a real
   disclosure for free: a button to a screen reader, Enter and Space open it, no script. */
.advanced > summary {
  cursor: pointer; font-size: 14.5px; color: var(--soft);
  list-style: none; padding: 8px 0;
}
.advanced > summary::-webkit-details-marker { display: none; }
.advanced > summary::before { content: "▸ "; color: var(--muted); }
.advanced[open] > summary::before { content: "▾ "; }
.advanced > summary:hover { color: var(--ink); }

/* ------------------------------------------------------- motion, 2026-09-01
   Applied against the frequency table in Emil Kowalski's animation standards, which is the
   part that decides *whether* to animate at all:

     100+ times a day   no animation, ever
     tens of times      remove or drastically reduce
     occasional         standard animation
     rare / first-time  can add delight

   For this product that resolves to almost nothing. A person answers seventeen steps and
   presses Continue seventeen times, so Continue gets press feedback and nothing else. The rail
   is used tens of times a session, so it stays quiet. What is genuinely occasional -- a flash
   confirming something was saved or deleted -- earns an entrance, and that is the whole budget.

   Everything below animates only `transform` and `opacity`, which skip layout and paint. */

/*  Press feedback. 0.97 and 140ms, inside his 100-160ms band and his 0.95-0.98 range.
    This is the one addition that touches every button in the application: a control that
    visibly answers a press feels like a control that received it, and this form is one people
    are anxious about. `:active` only -- no hover growth, which would animate on every pass of
    the cursor and fall foul of the frequency rule above. */
.btn:active, .b:active, button:active, .pick:active,
.acc-seat:active, .bm-dl:active { transform: scale(0.97); }
.btn, .b, button, .acc-seat, .bm-dl { transition: transform var(--press) var(--ease-out); }

/*  A flash is occasional by definition -- it appears when something was saved, removed or
    refused -- so it is the one element here that earns an entrance.

    `@starting-style` rather than a keyframe: it gives an entry animation with **no JavaScript
    and no mount flag**, which is the only mechanism available to a product that ships none.
    Where it is unsupported the message simply appears, which is what happens today. */
.flash {
  transition: opacity 200ms var(--ease-out), transform 200ms var(--ease-out);
}
@starting-style {
  .flash { opacity: 0; transform: translateY(-4px); }
}

@media (prefers-reduced-motion: reduce) {
  .btn, .b, button, .bm-dl, .flash { transition: none; }
  .btn:active, .b:active, button:active, .pick:active { transform: none; }
  /*  The dismissal STAYS; only the fade goes. Removing the animation outright was the
      first attempt, and it recreated the permanent-overlay bug above for exactly the people
      least able to work around it -- somebody who asks for less motion is asking not to be
      moved, not asking to be left with a message they cannot close. 1ms is a disappearance
      rather than a transition. */
  .flash--ok    { animation-duration: 1ms; }
  .flash--error { animation-duration: 1ms; }
}

/* The interview's error summary — W2. Sits above the form on a failed submit only.
   `--preview` is the Agency's correction red and is reserved for values written onto a form,
   so this uses `--warn`: an error here is our validation, not a mark on a government document,
   and borrowing that red would put a third meaning on it. */
.errsum {
  border: 1px solid var(--warn-line); border-left: 3px solid var(--warn);
  background: var(--warn-bg); color: var(--warn);
  padding: 14px 17px; margin: 0 0 22px; font-size: 15px;
}
.errsum:focus-visible { outline: 2px solid var(--warn); outline-offset: 2px; }
.errsum strong { display: block; font-size: 15.5px; font-weight: 500; }
.errsum ul { margin: 9px 0 0; padding-left: 19px; line-height: 1.7; }
.errsum a { color: var(--warn); font-weight: 500; }

/* ------------------------------------------------- the registration card, 2026-09-01
   A centred, constrained card rather than a full-bleed form. The first version put the
   fields at the page's full width, which on a wide monitor made a 1,100px-wide box to type
   an email address into — and set the two inputs at different widths from their content
   rather than from a shared measure.

   `.authpage` centres; `.authcard` holds the measure. Both are needed: centring the card
   without capping it just centres something already as wide as the page. */
.authpage {
  display: flex; justify-content: center;
  padding: clamp(40px, 7vh, 84px) 24px clamp(56px, 10vh, 96px);
}
.authcard { width: 100%; max-width: 440px; }
.authcard h1 { font-size: 30px; font-weight: 500; letter-spacing: -.015em; margin: 0; }
.authcard .lede { margin: 12px 0 0; font-size: 15.5px; }

/* The form fills the card, so both boxes take their width from the same measure rather than
   from their own content. `.regform`'s own 460px cap is wider than the card and would leave
   the two rules fighting over which one decided. */
.authcard .regform { max-width: none; margin-top: 22px; }
.authcard .regform label:first-of-type { margin-top: 0; }
.authcard .regform button { align-self: stretch; text-align: center; }
.authnote { margin: 6px 0 0; }
.authfoot { margin: 22px 0 0; padding-top: 18px; border-top: 1px solid var(--rule); }

/* ------------------------------------------------------- Associates, 2026-09-01
   The licensed professionals a person is actually working with. */
.assoc-list { display: flex; flex-direction: column; gap: 0; margin-top: 18px; }
.assoc {
  display: grid; grid-template-columns: 48px minmax(0, 1fr); gap: 16px;
  padding: 18px 0; border-top: 1px solid var(--rule);
}
.assoc-av {
  width: 48px; height: 48px; border-radius: 6px; background: var(--panel);
  display: grid; place-items: center; font-size: 16px; font-weight: 500;
  color: var(--soft); letter-spacing: .02em;
}
.assoc-body b { display: block; font-size: 16px; font-weight: 500; }
.assoc-meta { display: block; font-size: 13.5px; color: var(--muted); margin-top: 2px; }
.assoc-acts { list-style: none; margin: 11px 0 0; padding: 0;
              display: flex; flex-direction: column; gap: 7px; }
.assoc-acts li { font-size: 13.5px; color: var(--soft); }
.assoc-msg { display: block; color: var(--muted); margin-top: 2px; }
.assoc-empty {
  border: 1px solid var(--rule); background: var(--surface);
  padding: 22px 24px; margin-top: 18px;
}
.assoc-empty b { display: block; font-size: 16px; font-weight: 500; }
.assoc-empty p { margin: 8px 0 0; font-size: 14.5px; color: var(--soft); }
/* The rail's Guide disclosure reuses the admin group's summary styling, so its row matches
   every other row rather than being a second kind of thing in the same list. */
.side-group > summary.on { color: var(--ink); font-weight: 500; }

/* ---------------------------------------------- the scenario cards on /begin, 2026-09-02
   A card is now text plus its own action, so the row is a two-column grid rather than the
   radio-and-body flex the choices elsewhere still use. `align-items: end` puts the button on
   the card's baseline — the operator asked for the lower right, and on a card whose text runs
   to three lines that is where the eye finishes reading. */
.choice-pick {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: 18px 22px; align-items: end; cursor: default;
}
.pick-body { display: flex; flex-direction: column; min-width: 0; }
.pick-go { flex: 0 0 auto; white-space: nowrap; }
@media (max-width: 640px) {
  /* Under a phone's width the button goes full width beneath the text rather than squeezing
     beside it: a 90px-wide button next to three lines of wrapped text is a target sized by
     whatever space is left over, which is finding F1 in a different costume. */
  .choice-pick { grid-template-columns: 1fr; }
  .pick-go { width: 100%; }
}

/* ---------------------------------------------------------------- identity refusal page
   Two names side by side, because a refusal that quotes only one of them leaves the reader
   unable to see which is the mistake. `minmax(0, 1fr)` rather than `1fr`: a long unbroken
   name in a grid track sized `1fr` pushes the track past the container instead of wrapping,
   and a name is exactly the kind of string that has no space to break at. */
.ident-pair {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: 20px 28px;
}
.ident-pair .ro { font-size: 16px; word-break: break-word; }
.ident-what { margin: 14px 0 0; padding-left: 20px; max-width: 68ch; }
.ident-what li { margin-bottom: 12px; line-height: 1.6; color: var(--ink); }
.ident-act { display: flex; gap: 10px; margin-top: 26px; flex-wrap: wrap; align-items: center; }

/* ------------------------------------------------------------ documents: sort and view
   The `.seg` control was written for the theme picker, whose members are <button>s inside a
   form. These are <a>s -- links, so the ordering is bookmarkable and works with scripting off
   -- so the same appearance has to be declared for the anchor as well. Sharing the selector
   rather than adding a second `.docseg` class: two rules for one control is how the
   `.side-brand` bug of 2026-08-29 happened, where each rule read correctly on its own. */
.seg a {
  font: inherit; font-size: 13.5px; padding: 7px 15px; text-decoration: none;
  background: var(--surface); color: var(--soft); display: inline-block;
}
.seg a + a { border-left: 1px solid var(--line); }
.seg a:hover { color: var(--ink); }
/* `aria-current` rather than `aria-pressed`: these are links to a state, not toggles. The
   attribute that says "this is the one you are looking at" is the one that styles it, so the
   accessible name and the highlight cannot disagree. */
.seg a[aria-current="true"] { background: var(--accent); color: var(--paper); font-weight: 500; }

.docbar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 12px 20px; margin-bottom: 18px;
}
.docbar-l, .docbar-r { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.docbar-lab {
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted);
}

/* Its own scroll container, so a narrow window scrolls the table and not the page. */
.tablewrap { overflow-x: auto; }
.doctab { width: 100%; border-collapse: collapse; font-size: 14px; }
.doctab th, .doctab td { text-align: left; padding: 11px 14px; border-bottom: 1px solid var(--line); }
.doctab thead th {
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--muted); font-weight: 600; border-bottom-width: 2px; white-space: nowrap;
}
.doctab tbody th { font-weight: 500; }
.doctab tbody tr:hover { background: var(--surface); }
.doctab a { color: var(--ink); text-decoration: none; }
.doctab a:hover { text-decoration: underline; }
/* Counts line up down the column instead of drifting with the width of each digit. */
.doctab .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.doctab .when { color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (max-width: 560px) {
  .docbar { flex-direction: column; align-items: stretch; }
  .docbar-l, .docbar-r { justify-content: space-between; }
}

/* A channel that cannot deliver. Dimmed and non-interactive, with the reason in the row --
   never rendered as a switch that happens to be off, which would be a promise nothing keeps.
   `cursor: not-allowed` on the control rather than the row: the text is still selectable and
   still worth reading, and it is the control that will not move. */
.toggle-row.is-planned .tl b { color: var(--muted); }
.toggle-row.is-planned .tl span { opacity: 0.85; }
.toggle:disabled { opacity: 0.45; cursor: not-allowed; }
/* The two headings inside one settings block. Smaller than `.set-h`, which names the section
   -- these name the halves of it, and giving them the same weight would read as two sections
   that had lost their descriptions. */
.set-sub {
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.07em; font-weight: 600;
  color: var(--muted); margin: 0 0 10px;
}


/*  ── The access cover ────────────────────────────────────────────────────────────────
    A standalone page. It does not use the shell, because the shell is what is being
    withheld — see the note at the top of `cover.html`.

    The backdrop is a real `<img>` rather than a CSS background, so a reader that loads no
    stylesheet still gets a page rather than a bare heading on white, and the blur is already
    in the stored file rather than applied here: `backdrop-filter` is a paint operation, and a
    browser that does not support it would otherwise show the sharp original. */
.cv-body {
  margin: 0; min-height: 100vh; display: flex; align-items: center; justify-content: center;
  background: #12131a; color: #f2f0eb; text-align: center; padding: 40px 22px;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
}
.cv-bg {
  position: fixed; inset: 0; width: 100%; height: 100%; object-fit: cover;
  z-index: 0; opacity: .9;
}
/*  A scrim between the picture and the words. Contrast on a photograph cannot be measured
    once and trusted — a light patch anywhere behind the text is a failure at that spot — so
    the type sits on a wash dark enough that the picture cannot reach it. */
/*  **`z-index: -1`, and the whole page depended on it.** `.cv` is `position: relative;
    z-index: 1`, so it opens a stacking context — and this scrim is a *positioned* descendant
    inside it. CSS paints positioned descendants (step 8) AFTER in-flow inline content
    (step 6), so at `z-index: 0` the wash went over the heading and the message rather than
    under them: the text looked faded, which is what the operator saw. And being
    `position: fixed; inset: 0` it also lay across the whole viewport and swallowed every
    click, which is why the button did nothing.

    One cause, two symptoms that looked unrelated. A negative z-index moves it to step 3,
    which paints before the content — still inside `.cv`'s context, so still above `.cv-bg`.
    `pointer-events: none` as well: a decorative overlay should never be able to take a click
    even if some future rule moves it forward again. */
.cv-bg + .cv::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(180deg, rgb(8 9 13 / .55), rgb(8 9 13 / .78));
}
.cv { position: relative; z-index: 1; max-width: 620px; }
.cv-mark { width: 46px; height: 46px; margin: 0 auto; display: block; }

/*  The wordmark, between the mark and the state. Tracked and small against a large heading:
    it identifies the site, it is not the message — the reason somebody is on this page is the
    line below it, and a brand set at heading weight would compete with the thing they came
    to read. */
.cv-brand {
  margin: 14px 0 6px; font-size: 15px; font-weight: 500;
  letter-spacing: .08em; color: #ddd9d1;
}
.cv h1 {
  font-size: clamp(30px, 6vw, 52px); font-weight: 500; letter-spacing: -.02em;
  line-height: 1.1; margin: 0 0 18px;
}
.cv-msg { font-size: 17px; line-height: 1.7; color: #ddd9d1; margin: 0 0 26px; }

/*  ── The mark is the way in ──────────────────────────────────────────────────────────
    The "Administrator sign-in" button and the sentence under it are gone, on the operator's
    instruction: the mark itself is the link, which is discreet and reads as branding.

    **Discretion here is visual and nothing more.** It is not hidden from a screen reader —
    the link carries its real name — and it is not a security control: the protection is the
    password, the rate limit and the administrator check behind it, exactly as with the
    private entrance in `ACCESS-GATES.md`. A door nobody can see is still a door.

    The focus ring is deliberately NOT suppressed. A link with no visible text is precisely
    the one a keyboard user needs the ring to find. */
.cv-mark-link {
  display: inline-block; border-radius: 50%; line-height: 0;
  transition: opacity .15s ease, transform .15s ease;
}
.cv-mark-link:hover { opacity: .78; transform: scale(1.06); }

.cv-lang { font-size: 13.5px; color: #a9a49a; margin: 26px 0 0; }
.cv-lang a { color: #cfd7e8; text-decoration: none; margin: 0 6px; }
.cv-lang a[aria-current] { color: #fff; text-decoration: underline; }


/*  ── The Access cards ────────────────────────────────────────────────────────────────
    A grid of cards, one per cover or gate, the whole set legible on one screen. `auto-fit`
    with a floor rather than a fixed column count: seven cards should not leave an empty
    track on a wide monitor nor overflow a laptop, and that is one line rather than a media
    query per breakpoint. */
.gt-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: 14px; margin: 14px 0 0; align-items: start;
}
.gt-card {
  border: 1px solid var(--rule); border-radius: 2px; background: var(--surface);
  padding: 14px 16px 12px; min-width: 0;
}
/*  `is-on` means the gate is IN FORCE — the audience is closed — which is why it is red.
    Marked by a left rule AND by the word in the header, never by colour alone. The header
    word says "Disabled" for a gate and "On" for a cover, because a gate describes an
    audience's access and a cover describes itself. */
.gt-card.is-on { border-left: 3px solid var(--brand-red); }
.gt-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.gt-name { font-size: 15px; font-weight: 500; color: var(--ink); }
.gt-state { font-size: 11.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.gt-card.is-on .gt-state { color: var(--brand-red); }
.gt-what { font-size: 13px; margin: 6px 0 0; }
/*  Both states are shown, so the pair needs room to read as a choice rather than as one
    control with a stray label beside it. */
.gt-choice { flex-wrap: wrap; gap: 6px 14px; }
.gt-choice label { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; }
.gt-since { font-size: 12px; margin-top: 4px; }
.gt-f { display: block; margin-top: 10px; }
.gt-f > span { display: block; font-size: 12px; color: var(--muted); margin-bottom: 3px; }
.gt-f textarea, .gt-f input[type="text"], .gt-f input[type="number"], .gt-f input[type="file"] {
  width: 100%; box-sizing: border-box; font: inherit; font-size: 13px;
  padding: 6px 8px; color: var(--ink); background: var(--paper);
  border: 1px solid var(--line); border-radius: 2px;
}
.gt-row { display: flex; gap: 14px; align-items: center; margin-top: 8px; font-size: 12.5px; color: var(--muted); }
.gt-act {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--rule); font-size: 13.5px;
}


/*  ── The shipped-backdrop picker ─────────────────────────────────────────────────────
    Seven images are chosen by looking, so they are shown rather than named in a dropdown.
    `auto-fill` with a floor: the picker sits inside a 290px card on the Access page and
    could sit in a full-width form elsewhere, and neither should need its own rule. */
.bd-pick {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(74px, 1fr));
  gap: 7px; margin: 2px 0 4px;
}
.bd-tile { cursor: pointer; display: block; min-width: 0; }
/*  A tile that is its own submit button. Stripped of the button chrome so it reads as one of
    a set of pictures rather than seven buttons — but it IS a button, so it keeps its focus
    ring and its keyboard behaviour for free. */
button.bd-tile {
  appearance: none; background: none; border: 0; padding: 0; font: inherit; text-align: left;
  width: 100%;
}
button.bd-tile.is-on img { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent); }
button.bd-tile.is-on .bd-name { color: var(--ink); font-weight: 500; }
/*  Visually hidden, never `display: none`: the input must stay focusable and announced, and
    a `display: none` radio is unreachable from a keyboard. This is `.visually-hidden`'s job,
    written out here because the input needs it and the label around it must not have it. */
.bd-tile input {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}
.bd-tile img, .bd-swatch {
  display: block; width: 100%; height: 44px; object-fit: cover;
  border: 1px solid var(--rule); border-radius: 2px;
}
/*  The "none" tile: a flat swatch where the others have a picture, so the row reads as one
    set of choices rather than seven images and a stray control beside them. */
.bd-none .bd-swatch {
  background: repeating-linear-gradient(45deg,
    var(--panel) 0 6px, var(--surface) 6px 12px);
}
.bd-swatch { background: var(--panel); }
.bd-name {
  display: block; font-size: 10.5px; color: var(--muted); margin-top: 3px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/*  The chosen one is marked by a border AND by its name going solid — a coloured outline
    alone is colour carrying meaning, DESIGN-STANDARDS §6. */
.bd-tile input:checked ~ img,
.bd-tile input:checked ~ .bd-swatch { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent); }
.bd-tile input:checked ~ .bd-name { color: var(--ink); font-weight: 500; }
.bd-tile input:focus-visible ~ img,
.bd-tile input:focus-visible ~ .bd-swatch { outline: 2px solid var(--accent); outline-offset: 2px; }
