/* The shell, drawn from design's tokens.css. Nothing here names a colour: a literal in this file
 * is a token that was not declared, and the next screen would invent its own.
 *
 * architecture.md §4.1: Django renders HTML, HTMX swaps fragments, Alpine handles local state.
 * There is no client router and no component library, so this file is the component library.
 *
 * Square by default. tokens.css sets --radius to 0 with the reason attached: "a record, not a
 * card". Anything rounded here would be a decision taken by accident.
 */
*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--ground);
  color: var(--text);
  font: var(--size-body)/1.6 var(--font);
  -webkit-text-size-adjust: 100%;
}

/* WCAG 2.2 AA 2.4.1. Hidden until focused, then visible and in the flow. */
.skip {
  position: absolute;
  left: -9999px;
  top: var(--s-2);
  background: var(--surface);
  color: var(--text);
  padding: var(--s-2) var(--s-4);
  z-index: 10;
}
.skip:focus { left: var(--s-2); }

/* **Ink, not the tenant colour** (`tokens.css`, handover 8: "One ring on every control, in ink, so
 * a focused primary button cannot draw a gold ring on a gold fill"). This was `--t-fg`, which is the
 * tenant colour for use on the light ground, so inside the masthead it sat on `--t-raw` and the ring
 * was 1:1 against its own background on the shipped default. That is `#102`, and design's rule
 * closes it. `tokens.css` now ships the bare `:focus-visible`; this keeps the explicit selector list
 * so the offset applies to the same set as before. */
:where(a, button, input, select, textarea, summary):focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 2px;
}

/* **Design's interaction states, handover 8.** Our class names are `.button--primary` where the
 * canvas says `.btn-primary`; the values are design's exactly.
 *
 * **The primary is an inset wash, never a darker hex.** Design's reason is the one asked for in
 * `#129`: "`--t-raw` is the tenant's variable, and one wash deepens a navy and a pale gold in the
 * same direction". A hand-picked shade would behave differently per customer, which is what
 * ADR 0003 forbids.
 *
 * **On the secondary the border is the load-bearing half**, because "a fill change alone is a
 * colour-only signal".
 *
 * **Nothing moves.** Design: no lift, no shadow, no transform, because "motion is the first thing
 * to fail on a low-end Android, and a record does not need to feel springy." */
.button--primary:hover { box-shadow: inset 0 0 0 999px rgba(19, 25, 32, 0.14); }
.button--secondary:hover { background: var(--line-hairline); border-color: var(--text); }

/* **Pressed, handover 9's 17a.** The same wash at 26 per cent rather than 14, so the press
 * registers as deeper than the hover it replaces. **No translate**, which design states as the
 * rule: "a button that drops 1px feels responsive on a laptop and looks like a rendering fault on
 * a slow repaint". */
.button--primary:active { box-shadow: inset 0 0 0 999px rgba(19, 25, 32, 0.26); }

/* **Design's disabled state ships in `tokens.css` and does not reach our markup.** Its selector is
 * the bare `[disabled], [aria-disabled="true"]`, which is one attribute, and `.button--primary` is
 * one class: the specificities tie, `base.css` loads second, and the later rule wins. Measured
 * rather than reasoned about: a disabled primary on the sign-in page kept the tenant fill,
 * `rgb(11, 44, 90)` on the shipped default, so design's grey never appeared.
 *
 * **So the rule is repeated here at a specificity that can win**, with design's values unchanged.
 * It is not a second opinion about the treatment; it is the same treatment, reachable.
 *
 * **Nothing renders a disabled control yet**, which is why this was easy to miss:
 * `import_map.html` records that not disabling Confirm is deliberate until design's 9i is built.
 * The rule is here so that the day it is built, the state is the one design drew rather than a
 * tenant-coloured button that cannot be pressed. */
.button[disabled],
.button[aria-disabled="true"] {
  background: var(--line-hairline);
  color: var(--text-label);
  border: 1px solid var(--line);
  box-shadow: none;
  cursor: default;
}
/* **No hover and no press**, design's words. Without these the wash still lands on a control
 * nobody can press, which is the clearest possible lie about what a click will do. */
.button[disabled]:hover,
.button[disabled]:active,
.button[aria-disabled="true"]:hover,
.button[aria-disabled="true"]:active { box-shadow: none; background: var(--line-hairline); }

a { color: var(--t-fg); }

/* ---- The masthead is design's since handover 72 (#158) --------------------------------------
 *
 * `workforce.css` draws the bar, the lockup, the section links, the divider, the account menu
 * and the two rows below 700; the shell's markup is design's `_masthead.html` with our blocks
 * (`design/base.html`). What was here, the bar, the brand, the nav, the divider, the link, the
 * current mark, the `.account*` menu and the `body > .masthead` narrow treatment, went with it,
 * and the collision list in `test_against_design_spec.py` lost six names. Two things of ours stay:
 * the hover below, which no vendored file declares, and the assessment's mode and counter further
 * down, which are the one surface that replaces the bar's contents. */
/* **`text-decoration: none` on hover, because a global rule in `tokens.css` puts it back.** Design
 * sets `a:hover { text-decoration: underline }` there, and `.masthead__link`'s own
 * `text-decoration: none` is 0,1,0 against that rule's 0,1,1, so every nav item underlined on
 * hover. The rule below is 0,2,0 and beats it back. The bar is a set of destinations rather than
 * links in prose, and the current one already carries an underline as its marker, so a second
 * underline appearing under a different item on hover reads as the selection moving.
 *
 * **No vendored file declares `.masthead__link:hover`**, handover 72 included. An earlier version of this comment said
 * design's did and set only a colour; `grep` finds the selector in none of the four vendored files,
 * and the colour-only rule it described is ours, on the line below. Getting that wrong costs the
 * next handover its diff: somebody checking whether design fixed the hover looks for design's rule,
 * finds nothing, and cannot tell a rule design removed from one that never existed. `#159`: the
 * masthead is design's since handover 72 and this one rule is still ours. */
.masthead__link:hover { color: var(--t-on); text-decoration: none; }

/* The console bar's link home and its hover rule were ours for one handover and are `console.css`'s
 * since handover 77 ("both belong in the partial rather than your shell"). */

/* ---- The console's mark at the board's size, until `console.css` carries it (#159) ------------
 *
 * Handover 77's note: "the mark is 26px, and it is no longer an em", matching the tenant plate's
 * content box, with the wordmark at `--size-h2`; "applied to the console bar and all three 26m
 * doors, 15 lockups". The boards carry it (a 26px mark, a 21px wordmark, centred, gap 2px) and
 * `console.css` still says `0.727em` of a body-sized word, which is the 11px mark the founder
 * called too small. A size is not spacing, so the board governs and these two rules restate
 * its values, scoped to the bar because `console.css` loads after this file and a lone class
 * would lose on order; they leave when design's file catches up with its note. */
.console__masthead .console__wordmark { font-size: var(--size-h2); align-items: center; gap: 2px; }
.console__masthead .console__mark { height: 26px; width: 26px; top: 0; margin-right: 0; }

/* ---- The bar's account element as 26p and 26r draw it, until `console.css` carries it -------
 *
 * Two things measured against handover 94's boards that its file does not do. 26p draws 48px
 * between the last section link and the avatar, the divider centred in it, which is the tenant
 * bar's `margin: 0 24px` on its divider (handover 73); `console.css` gives its divider no margin,
 * so the link, the divider and the avatar touch. And below 700 the file's first narrow block
 * still says `flex-direction: column` while its new one wraps rows by `order`, so the wordmark
 * centred alone on a row and the account fell to a second, where 26r draws the two on one row
 * with the nav beneath. Both scoped to the bar so they win on order; both sent to design. */
.console__masthead .console__divider { margin: 0 24px; }
@media (max-width: 700px) {
  /* The tag beats the class's tie: `console.css` loads after this file. */
  header.console__masthead { flex-direction: row; }
}

/* ---- The four rules that were ours on design's masthead left at handover 73 ---------------
 *
 * The name dropping at 360, WebKit's disclosure marker, 24px either side of the divider and
 * 8e's gutter on `.masthead__brand` were here for one handover (#158) and are `workforce.css`'s
 * now, with design's own reasons beside them; the collision list lost the four names with them.
 * What stays of ours on the bar is `.masthead__link:hover` above and the assessment's mode and
 * counter below. */

.page { flex: 1; width: 100%; max-width: 1080px; margin: 0 auto; padding: var(--s-6) var(--s-4); }
/* **A surface that carries design's own body owns its padding and, since handover 18, its width.**
 * Design's `.surface__body` is `max-width: 1148px; padding: 32px 24px 40px; margin-inline: auto`,
 * and design's note calls it "ONE CONTENT CONTAINER, EVERY SURFACE, and it is HERE rather than per
 * page". Our `.page` was adding `--s-6 --s-4` on top of that padding, and its own `max-width: 1080`
 * sits **below** design's 1148, so leaving it would clamp the container and the widening handover
 * 18 exists for would silently not happen. Both are dropped where design's body is present.
 *
 * **Scoped rather than removed**, because every surface built before handover 14 puts its content
 * straight into `.page` and still wants the 1080 and the padding.
 *
 * **Design's own `django/README.md` still says "the shell draws ... the centred 1080 measure"**,
 * which is the one place left disagreeing with the 1148 in `workforce.css` and in the `12a` and
 * `9i` spec notes. The stylesheet is what renders, so it wins; the README line is on `#159`. */
.page:has(> .surface__body) { padding: 0; max-width: none; }
/* The operator console's container is design's `.console__body` (ADR 0022, `console.css`), the
 * same measure and padding as `.surface__body`, and takes the same release from `.page`'s own. */
.page:has(> .console__body) { padding: 0; max-width: none; }

/* **The same reset for the signed-out door**, and for the same reason one layer down. Design's
 * signed-out surfaces open with `.gate`, which centres, and `.gate__card`, which is the 400px.
 * `.page--door`'s own `max-width: 400px` sits at exactly the card's width, so with `.gate`'s
 * `padding: 40px 24px 44px` inside it the card would be squeezed to 352 and every door page would
 * render 48px narrower than design draws it. Dropped where design's gate is present, kept where it
 * is not, which is the same scoping `.surface__body` gets above and for the same reason: a door
 * page not yet rebuilt still wants our 400 and our padding. */
.page--door:has(> .gate) { max-width: none; padding: 0; }
/* **The shell's status block went to design's banner, 11 September 2026.** `base.html` renders
 * `messages` above `{% block content %}`, and it did so with our own `.status`, a green band that
 * inherited `max-width: none` from the uncapped `.page` and then, capped at 1148, still sat 48px
 * wider than the card beneath it, because the card is inside the container's padding. Design
 * draws no page-level status: every `_banner.html` in the handover sits inside `.surface__body`.
 * So the shell now draws design's banner inside a wrapper carrying the container's own measure and
 * padding, and `.status` and its four variants are deleted with nothing left rendering them. The
 * state itself, a banner above a page rather than in a card, is still one design has not drawn,
 * and it stays on `#159`. */
/* **The signed-in foot is a full-bleed band and its contents take the measure**, which is what the
 * masthead does and what an artboard cannot show: an artboard is a fixed width, so a band drawn to its
 * edges and a band drawn to the window's are the same picture there and different things in a
 * browser.
 *
 * **The children take the measure, not the `footer`.** Design puts `border-top` in an inline style
 * on the element, and an inline style beats a stylesheet, so constraining the element constrains
 * the rule with it and it stops 324px short of each edge on a 1728px window. Letting the element
 * run full width lets design's own border run the width of the page, the way the masthead's edge
 * does, with nothing overridden. */
.foot-measure > footer > * {
  /* **Indented to the measure's left edge rather than centred, and the reason is a second child
   * that is not here today.** `auto` margins centre each child on its own width, so the closing
   * line design used to draw, at an inline `max-width: 74ch`, landed 258px right of the lockup.
   * Handover 15 removed that line and the footer has one child now, which makes this rule and
   * `margin: 0 auto` behave identically. **Keep it anyway**: design can reinstate a second line at
   * any handover, and the two only agree while there is one child.
   *
   * **The footer's horizontal padding cancels, whatever it is, provided it is symmetric.** `100%`
   * resolves against the footer's content box, so a padding of `p` insets by `p` and removes `p`
   * from the half-difference, and the child's left edge is `(W - 1148) / 2` either way. Design's
   * value has already moved from `24` to `28` with no effect here. **An asymmetric padding would
   * break it** and nothing guards that, so it is the thing to check when this value next changes.
   *
   * **The clamp is load-bearing.** Below the container width plus the footer's own padding the
   * margin would go negative and push the lockup out of the band; `max(0px, ...)` gives the child
   * the content box with design's symmetric inset instead, which is the band at 360px.
   *
   * **1148 tracks design's container and is not a number of ours.** Handover 18 made
   * `.surface__body` the one content container at `max-width: 1148px`, so the foot's contents line
   * up with the content above them. It was 1080 while the shell carried the measure. If design
   * moves the container, this moves with it, and the two are only correct together. */
  margin-left: max(0px, calc((100% - 1148px) / 2));
  margin-right: 0;
  max-width: 1148px;
  box-sizing: border-box;
}
/* The signed-out surfaces. One column, centred, on the ground rather than a full-bleed panel:
 * this page is a door, not a landing page. */
.page--door { max-width: 400px; padding-top: var(--s-7); }

.foot {
  padding: var(--s-4);
  color: var(--text-secondary);
  font-size: var(--size-meta);
  border-top: 1px solid var(--line);
}

h1 { font-size: var(--size-h1); line-height: 1.25; margin: 0; font-weight: 600; letter-spacing: -0.015em; }
h2 { font-size: var(--size-h2); line-height: 1.3; margin: var(--s-6) 0 var(--s-3); }
p { margin: 0 0 var(--s-4); }
.quiet { color: var(--text-secondary); font-size: var(--size-body-sm); }

/* Measurements are the handover's, taken from the surface files rather than chosen here. Where a
 * value is a token it is written as one; #DFE3E7 is a card edge design used literally and
 * tokens.css did not carry, so it is literal here too rather than approximated by --line.
 *
 * **Design settled it at handover 14 and this declaration no longer paints.** `workforce.css`
 * gives `.card` `border: 1px solid var(--line)`, which is #D5DAE0, and it loads second, so every
 * card in the product takes design's edge and the literal below is dead for `.card`.
 *
 * **Ten other declarations in this file still paint it**, over nine selectors: `.panel`,
 * `.listing`, `.listing__head`, `.grid th`, `.sitting__card`, `.sitting__option` and its
 * `:last-child`, `.rail` twice, and `.aside-card`. Nine names and ten declarations, because `.rail`
 * is painted twice. It was thirteen over twelve until the evidence record moved to design's frame
 * and `.record`, `.record__head` and `.record-rail__card` went.
 * None of those names is one design declares, so none takes `--line` and all of them sit a shade
 * off a handover 14 card. **Recount before acting on this**, by parsing the
 * declaration blocks rather than grepping the string: an earlier version of this comment said
 * seven and named three, which would have reconciled three and left ten. The evidence record and
 * the sitting page are where both edges already appear together. On `#159` for design. */
.card { background: var(--surface); border: 1px solid #DFE3E7; padding: 32px; }
/* **Inside a handover 14 surface, design's card owns its own padding.** `workforce.css` puts none
 * on `.card`: the padding lives on `.card__body`, `.card__head` and `.card__foot`, and a bare
 * `.card` is a container for rows that sit flush to its edges. Ours puts 32px on `.card` itself.
 * Both files declare the class and design's loads second, so design's wins property by property,
 * and `padding` is not among the properties it declares. The 32px therefore survived: under a
 * `.card__body` it doubled to 58px, which is what the founder opened on Home, and around design's
 * bare finished-course list on My Learning it inset every row by 32px design had not drawn.
 *
 * **Scoped by the surface rather than by the card's own children**, which is the version this
 * replaces. `.card:has(> .card__body)` caught the doubling and missed the bare card entirely, and
 * the two are the same defect. `.surface__body` is on every template built from handover 14 and on
 * none built before it, so this is the whole boundary in one selector: the twelve signed-out
 * surfaces keep their 32px untouched. */
.surface__body .card { padding: 0; }
/* **A container's padding is its top edge, the same way it is its bottom one.** `h2` carries a
 * 28px top margin for spacing between sections of a page, and inside a card that stacked on the
 * 32px padding and put 60px above the first heading. The sibling rule for the last child is on
 * `.panel` below and exists for the mirror-image reason. */
/* **Checked against the surfaces already signed off, rather than assumed safe.** `h2` is the only
 * element in this file with a top margin, so the rule moves nothing on sign-in, account settings,
 * People, Roles or the evidence record: every container's first child there is a `div`
 * (`.panel__row`, `.panel__title`, `.eyebrow`) or an `h1`, and all of those are already at zero. */
.card > :first-child,
.panel > :first-child,
.listing__head > :first-child { margin-top: 0; }
.card__lede { margin: 8px 0 0; font-size: var(--size-body-sm); line-height: 1.6; color: var(--text-secondary); }

/* Forms. Every control has a real label: a placeholder is not one, it disappears on the first
 * keystroke and is unreadable to anyone who needs the contrast. */
.field { margin-top: 16px; display: flex; flex-direction: column; gap: 7px; }
.field:first-of-type { margin-top: 22px; }
.field > label { font-size: var(--size-meta); font-weight: 600; }
/* Under the control, not above it: it is guidance for what to type, and a hint above the field
 * reads as part of the label. Tied to the input with aria-describedby so it is announced. */
.field__hint {
  display: block;
  margin-top: 6px;
  font-size: var(--size-meta);
  line-height: 1.6;
  color: var(--text-secondary);
}
/* `.row input` as well: screen 14 puts the label beside the control rather than above it, and a
 * field that only looks like a field inside `.field` is a field that renders as a bare underline
 * everywhere else. */
.field input,
.row input {
  width: 100%;
  padding: 13px;
  font: inherit;
  font-size: var(--size-body-sm);
  color: var(--text);
  background: var(--surface);
  /* Design's field border, used literally. It is the same value as --unrecorded and not the same
   * thing: that token means "nothing recorded here" and is dotted wherever it carries meaning.
   * Borrowing it for chrome is how a semantic palette stops meaning one thing at every scale. */
  border: 1px solid #7C8590;
}
/* 1.5px ink, which is the design's filled and focused field. The extra half pixel comes out of
 * the padding rather than moving the field, so nothing shifts when it takes focus. */
.field input:focus,
.row input:focus {
  border: 1.5px solid var(--text);
  padding: 12.5px;
  outline-offset: 3px;
}
.field--invalid input,
.row.field--invalid input {
  border: 1.5px solid var(--status-error);
  padding: 12.5px;
}
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: 44px;
  padding: 13px var(--s-5);
  font: inherit;
  font-weight: 600;
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
}
/* --t-on rather than white, and --t-edge rather than nothing: a pale gold tenant takes ink text
 * and a drawn edge, with no per-tenant decision (handover rule 6). */
.button--primary {
  display: block;
  width: 100%;
  margin-top: 22px;
  padding: 14px 16px;
  font-size: var(--size-body);
  background: var(--t-raw);
  border-bottom: 1px solid var(--t-edge);
  color: var(--t-on);
  text-align: center;
}

/* The two ways off this screen, side by side under the action. */
.door-links {
  margin-top: 16px;
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: var(--size-meta);
}
.door-links a { font-weight: 600; text-decoration: none; }
.door-links a:hover { text-decoration: underline; text-underline-offset: 2px; }

/* The Octralis lockup and what we will never ask for. Below the fold of the card, deliberately:
 * the learner's relationship is with their employer, and we appear at the bottom. */
.lockup {
  margin-top: 20px;
  border-top: 1px solid var(--line-hairline);
  padding-top: 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.lockup__note { font-size: var(--size-meta); line-height: 1.6; color: var(--text-secondary); }
/* The door pages give the primary action the full width of a 400px card. Inside a settings panel
 * it is one control among several and sizes to its label, which is design's shape on screen 14. */
.button--inline { display: inline-flex; width: auto; padding: 12px 22px; }


/* Screen 14's shape: the things you can change, and a narrower column for the things you cannot.
 * One column below 900px, because a 320px rail beside a form does not fit at 360. */
.settings {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: var(--s-6);
  align-items: start;
}
@media (max-width: 900px) {
  .settings { grid-template-columns: minmax(0, 1fr); }
}
.settings__column { display: flex; flex-direction: column; gap: 18px; }

/* A section of the page, not a door. Tighter than .card, which is sized for a single centred
 * form on an otherwise empty screen. */
.panel { background: var(--surface); border: 1px solid #DFE3E7; padding: 22px 24px; }
/* **The panel's own padding is its bottom edge.** `.panel__note` and `.panel__foot` are `<p>`, so
 * they keep the user agent's 1em bottom margin, and as the last child that margin adds to the
 * padding: every panel on the evidence record measured 23px above its first child and 39px below
 * its last. Zeroing it here rather than per template, because the imbalance is in the shell and
 * every surface built on it has it. */
.panel > *:last-child { margin-bottom: 0; }
.panel--tight { padding: 20px; }
.panel__title { font-size: var(--size-body-lg); font-weight: 600; letter-spacing: -0.01em; }
.panel__note {
  margin-top: 6px;
  font-size: var(--size-body-sm);
  line-height: 1.6;
  color: var(--text-secondary);
}
.panel__foot {
  max-width: 62ch;
  margin-top: 11px;
  font-size: var(--size-meta);
  line-height: 1.6;
  color: var(--text-secondary);
}

/* The eyebrow is design's alone since handover 64. Ours declared the same family, size, weight
 * and colour, a letter-spacing design's `.eyebrow` beat everywhere, and a line-height of 1 that
 * design's declared nothing for, so deleting ours would have dropped thirty-nine labels to the
 * body's 1.6 (#147 item 5). Design declares `line-height: 1` now, "a small-caps mono label at 1.6
 * is a line of text rather than a label, and the value was load-bearing and unstated". */

/* Label beside control, which is what an admin density looks like. It stacks at 640px, where a
 * 180px label column leaves nothing for the field. */
.row {
  display: grid;
  grid-template-columns: 180px minmax(0, 1fr);
  gap: var(--s-4);
  align-items: center;
}
@media (max-width: 640px) {
  .row { grid-template-columns: minmax(0, 1fr); gap: 7px; }
}

.facts { margin-top: 12px; display: flex; flex-direction: column; gap: 11px; }
.facts > div { display: flex; justify-content: space-between; gap: 12px; font-size: var(--size-meta); }
.facts .facts__label { color: var(--text-secondary); }
.facts .facts__mono { font-family: var(--font-mono); font-size: var(--size-label); }

.link-action {
  display: inline-block;
  font-size: var(--size-meta);
  font-weight: 600;
  color: var(--t-fg);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  font-family: inherit;
}
/* The offset is design's, and it is the half that was missing: an underline hard against the
 * baseline clips a descender on a link inside a sentence. */
.link-action:hover { text-decoration: underline; text-underline-offset: 2px; }

/* Enrolment: three steps, with the ones you are on marked. A real list, because it is a sequence
 * and the order carries what happens next. */
.steps {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4);
  margin: var(--s-5) 0 0;
  padding: 0;
  list-style: none;
}
.steps__step {
  font: 600 var(--size-caps)/1 var(--font-mono);
  letter-spacing: 0.14em;
  /* --text-secondary, not --unrecorded: tokens.css says caps labels take --text-label or darker,
   * and #7C8590 is 3.15:1 on the ground. This is `--size-caps` text, 11px since handover 9, which is where that matters most. */
  color: var(--text-secondary);
}
/* Not colour alone (design-brief.md §4). The marker is what says which step this is; the weight
 * and colour reinforce it, and `aria-current="step"` says it to a screen reader. */
.steps__step--now { color: var(--text); }
.steps__step--now::before { content: "▸ "; }

.qr { margin-top: var(--s-5); max-width: 200px; }
.qr svg { width: 100%; height: auto; }
.typed-key {
  margin: var(--s-2) 0 0;
  font: 600 var(--size-h3)/1.4 var(--font-mono);
  letter-spacing: 0.08em;
  overflow-wrap: anywhere;
}

/* Recovery codes. Mono and tabular so ten of them line up down a column, and large enough to be
 * copied onto paper without squinting. */
.codes {
  display: grid;
  /* Wide enough that a code never wraps. One broken across two lines is one copied onto paper
   * wrong, and there is no second chance to read it. */
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: var(--s-2) var(--s-4);
  margin: var(--s-5) 0 0;
  padding: 0;
  list-style: none;
}
.codes__code {
  font: 500 var(--size-body)/1.8 var(--font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

/* Design: "Finish stays inert until that is ticked". The server keeps the same rule and refuses
 * an unticked post, which is what actually holds; this is the affordance. A browser without
 * `:has()` shows a live button, presses it, and gets the refusal with its reason, which is the
 * right way round for a rule enforced somewhere the page cannot reach. */
form:has(input[name="saved"]:not(:checked)) .button--primary {
  background: var(--text-label);
  border-color: transparent;
  cursor: not-allowed;
}

.tickbox {
  display: flex;
  gap: var(--s-3);
  align-items: baseline;
  font-size: var(--size-body-sm);
}
.tickbox input { margin: 0; }

.panel__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
  flex-wrap: wrap;
}
/* --text and --text-label rather than the semantic palette. tokens.css says each semantic mark
 * means exactly one thing at every scale, and --evidence carries "a level demonstrated, NEVER
 * used for progress or completion". A settings badge is chrome, and borrowing the palette for
 * chrome is the direction that erodes ADR 0003 rather than reverses it. */
.badge {
  font: 600 var(--size-caps)/1 var(--font-mono);
  letter-spacing: 0.12em;
  padding: var(--s-1) var(--s-2);
  border: 1px solid var(--text);
  color: var(--text);
}
.badge--quiet { border-color: var(--text-label); color: var(--text-label); }

.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-3);
  margin-top: var(--s-5);
}

/* A second action beside the primary one: design's "Replace my authenticator app" is white with
 * an ink border, so the primary stays the only filled thing on the panel. */
.button--secondary {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--text-label);
}

.recovery { margin-top: var(--s-5); }
.recovery__summary {
  font-size: var(--size-body-sm);
  font-weight: 600;
  color: var(--t-fg);
  cursor: pointer;
  list-style: none;
}
/* Same two rules as the account menu: one for the standard marker, one for WebKit's. */
.recovery__summary::marker { content: ""; }
.recovery__summary::-webkit-details-marker { display: none; }

.spaced-tight { margin-top: var(--s-3); }

/* Screen-reader-only. A label a sighted person does not need, because the placeholder and the
 * selected option say it, is still the only thing naming the control to anybody else. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Search and the two filters, on one line where there is room and stacked where there is not. */
.finder {
  display: flex;
  align-items: stretch;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: var(--s-5);
}
.finder__search {
  flex: 1;
  min-width: 300px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 13px;
  background: var(--surface);
  border: 1.5px solid var(--text);
}
.finder__icon { flex: none; color: var(--text-secondary); }
.finder__search input {
  width: 100%;
  border: 0;
  padding: 0;
  font: inherit;
  font-size: var(--size-body-sm);
  color: var(--text);
  background: transparent;
}
.finder__search input:focus { outline: none; }
.finder__search:focus-within { outline: 2px solid var(--text); outline-offset: 2px; }
/* **Design draws the arrow, so the native one is suppressed.** The canvas puts a `▾` at the scale's floor
 * against the right padding, and a browser's own arrow is a different glyph at a different size in
 * every engine, so leaving it native means the control never matches the drawing on any machine.
 * `appearance: none` plus a positioned glyph is the only way to hold design's mark. */
/* **The whole list is one card** (design's 8a). The head holds the count, the filters and the
 * bulk row, separated from the table by a rule rather than by a gap on the ground. */
.listing { background: var(--surface); border: 1px solid #DFE3E7; }
.listing__head {
  padding: 18px 20px; border-bottom: 1px solid #DFE3E7;
  display: flex; flex-direction: column; gap: 16px;
}
/* Design's card head puts the title and the route on one line, baseline-aligned, and wraps rather
 * than shrinking. Every value here is handover 10's `.card__head`, including the `calc` on the gap.
 *
 * **A modifier because the block is what the other heads use.** `.listing__head` itself is on
 * People and Roles, whose heads stack a count heading over a row and a finder, so changing
 * `flex-direction` on the block would silently re-lay-out both. `--stacked` further down this file
 * is not the opposite arrangement, it is `gap: 0` on the same column, and its users are My
 * Competencies and My Learning rather than the administrator listings. An earlier version of this
 * comment said the reverse of both, which would have sent the next person editing the block. */
.listing__head--spread {
  flex-direction: row; align-items: baseline; justify-content: space-between;
  gap: calc(var(--s-3) + 2px); flex-wrap: wrap;
}
.listing__head > .panel__row { gap: 16px; }
.listing .finder { margin-top: 0; }
.listing .bulk { margin-top: 0; padding-top: 14px; }
.listing .table-scroll { margin-top: 0; }
.listing .grid { border: 0; }

/* Design's list heading is `--size-body-lg`, not the page h1: on 8a the count sits inside the card as
 * a card title rather than as the page's own heading, which is already in the masthead. */
.list-title { font-size: var(--size-body-lg); font-weight: 600; letter-spacing: -0.01em; line-height: 1.3; }
.list-title + .panel__note { margin-top: 4px; font-size: var(--size-meta); }

.finder__filter { position: relative; display: flex; }
.finder__filter::after {
  content: "\25BE";
  position: absolute; right: 13px; top: 50%; transform: translateY(-50%);
  font-size: var(--size-micro); line-height: 1; color: var(--text);
  pointer-events: none;
}
.finder__filter select {
  min-width: 170px;
  width: 100%;
  height: 100%;
  appearance: none;
  padding: 11px 30px 11px 13px;
  font: inherit;
  font-size: var(--size-body-sm);
  color: var(--text);
  background: var(--surface);
  border: 1px solid #7C8590;
  border-radius: 0;
}

.bulk {
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: 1px solid var(--line-hairline);
}
.bulk__row {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  flex-wrap: wrap;
  font-size: var(--size-body-sm);
}

/* A wide table scrolls inside its own container. The page body never scrolls sideways, which is
 * design-brief.md §7's 360px rule applied to the one thing that cannot narrow. */
.table-scroll { overflow-x: auto; }
.grid { width: 100%; border-collapse: collapse; background: var(--surface); }
.grid th {
  padding: 9px 12px;
  text-align: left;
  font: 600 var(--size-caps)/1.3 var(--font-mono);
  letter-spacing: 0.1em;
  color: var(--text-secondary);
  border-bottom: 1px solid #DFE3E7;
  white-space: nowrap;
}
.grid td {
  padding: 11px 12px;
  font-size: var(--size-meta);
  color: var(--text-secondary);
  border-bottom: 1px solid var(--line-hairline);
}
.grid__name { font-size: var(--size-body-sm); font-weight: 500; color: var(--text); }
.grid__empty { padding: var(--s-6) var(--s-4); color: var(--text-secondary); text-align: center; }

.paging {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  flex-wrap: wrap;
  margin-top: var(--s-4);
  font-size: var(--size-body-sm);
}
.paging__links { display: flex; gap: var(--s-4); margin-left: auto; }

.stack > * + * { margin-top: var(--s-4); }
.spaced { margin-top: var(--s-5); }
.inline-form { display: inline; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* Long-form lesson text: a reading lesson's body, and a video lesson's transcript.
   Design's 7c and 8a. 17px at 360px rather than a smaller size, because this is the one surface
   somebody reads for eight minutes, and a measure that stops a line before it becomes hard to
   track back from. `design-brief.md` §1 puts the learner at English as a second or third register,
   which is a reason for shorter lines rather than denser ones.
   `--size-body-lg` rather than a literal: this is the first surface that token was written for
   ("course reading. Never smaller: people read this for forty-five minutes"), and a literal is a
   token that was not looked up. It would also mix rem against the px headings, so a learner who
   raises their browser default for legibility would sink the headings below the body text. */
.prose { max-width: 66ch; font-size: var(--size-body-lg); line-height: 1.65; }
.prose > * + * { margin-top: 1em; }
.prose h2, .prose h3 { margin-top: 1.6em; line-height: 1.3; }
.prose ul, .prose ol { padding-left: 1.4em; }
.prose li + li { margin-top: 0.4em; }

/* The assessment player. Design's 3a, 3b and 3c: one shell for both item kinds, the choice above
   and the reasoning below it. Options are a real radio group, so the whole thing works with the
   HTMX and Alpine attributes ignored (`architecture.md` §4.1) and a screen reader reads it as the
   single-choice question it is. */
.options { border: 0; margin: 0; padding: 0; display: grid; gap: 8px; }
.option {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 14px 16px; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); cursor: pointer;
}
.option:hover { border-color: var(--text-secondary); }
/* The whole row is the target, not the 20px circle. `design-brief.md` §1 puts this on a phone in
   a branch, and a 44px target is the difference between answering and mis-answering. */
.option input { margin-top: 3px; min-width: 20px; min-height: 20px; }
.option:focus-within { outline: 2px solid var(--text); outline-offset: 2px; }

.field--text {
  width: 100%; min-height: 7em; font: inherit; padding: 12px;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface);
}


/* ---- My Learning -------------------------------------------------------- *
 * `Learner Home.dc.html` 6a and 9h. The name, the sentence and the chip stacked in a row.
 * **The rank is gone with the block that carried it**: design's 19b removed the ranked gap list
 * from Home, "for one person with eight rows it is the same information twice on one page", and
 * `.ranked__rank` had no other user. My Learning draws no rank, so nothing here does. */
.ranked {
  padding: 13px 16px; border-top: 1px solid var(--line-hairline);
  display: flex; gap: 12px; align-items: flex-start;
}
.ranked__body { display: flex; flex-direction: column; gap: 5px; flex: 1; min-width: 0; }
.ranked__name { font-size: var(--size-body-sm); line-height: 1.35; font-weight: 500; }
.ranked__line { font-size: var(--size-meta); line-height: 1.45; color: var(--text-secondary); }
.ranked--close { flex-direction: column; gap: 7px; }

/* ---- My Competencies ---------------------------------------------------- *
 * **The block that stood here is deleted.** It drew this surface out of our own `.competency*`,
 * `.listing__head--stacked` and `.listing__rows`, and handover 14 moved the page onto design's
 * `.record__row`, `.card--sectioned` and `.card__head`. `grep` finds none of those names in any
 * template. Left declared, the next surface to draw a competency row would reach for
 * `.competency__body` and get our pre-handover-14 `1fr 140px` grid instead of design's, which
 * CLAUDE.md records as the cause of two rebuilds: "reaching for an existing class instead of
 * building the structure drawn". The administrator's matrix (`#22`) is the next one to do it.
 *
 * **One rule survives, because design writes it inline and a media query cannot reach an inline
 * declaration.** Design's `my_competencies.html` puts
 * `display:flex; flex-direction:column; gap:7px; align-items:flex-start` on the row's aside. The
 * values below are design's; the class exists so the narrow rule can apply.
 *
 * **Design's `.record__row` collapses to one column at 700px**, and a column here then costs a
 * line per competency, eight times, on the surface most constrained for height, which is where
 * this was found the first time.
 *
 * **Nothing inside needs an `align-self` reset**, which the pre-handover-14 version of this block
 * carried: the row held our own `.tag`, whose `align-self: flex-start` had to be undone here or it
 * top-aligned against a centred link. The chip is design's now and design gives it `flex: none` and
 * no `align-self`, so `align-items` on this element decides it at both widths. */
.record__aside { display: flex; flex-direction: column; gap: 7px; align-items: flex-start; }
@media (max-width: 700px) {
  .record__aside { flex-direction: row; align-items: center; gap: 14px; }
}

/* ---- Learner Home, after the baseline ----------------------------------- *
 * **The block that stood here is deleted, and its deletion is the point.** It hand-duplicated
 * design's `.layout--with-rail`, `.page__title`, `.page__intro` and `.rail__card` under our own
 * names, with a comment saying the values were safe to take from an unvendored `workforce.css`
 * while the names were not. Handover 14 vendored that file, the three learner surfaces are built
 * from design's templates, and `grep` finds `.home__main`, `.home__rail`, `.page-title`,
 * `.page-intro`, `.rail-card` and `.rail-card__text` in no template in the tree.
 *
 * **Left in place it would have been the register's own hazard**: our copy of design's numbers,
 * still carrying the literal card edge and still telling a reader that design's stylesheet was out
 * of tree, next to the file that now holds those rules. `octralis/design/README.md` records the
 * four names as shadowing design's; they no longer exist to shadow anything. */

/* The rail's legend. Each swatch is the same mark the track uses, at the size a legend needs, so
 * the key and the thing it explains cannot drift apart. */
.legend { margin: 12px 0 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 9px; }
.legend li {
  display: flex; align-items: flex-start; gap: 10px;
  font-size: var(--size-meta); line-height: 1.5; color: var(--text-secondary);
}
.legend__swatch { flex: none; width: 26px; height: 14px; margin-top: 2px; }

/* Design's mark in a table cell: a small square that carries the state before the words do, so a
 * row scans without reading. Dotted is absence, solid is a demonstrated level. ADR 0003's rule that
 * a mark is never colour alone is what makes the dash pattern load-bearing rather than decorative. */
.cell-mark {
  display: inline-block; width: 11px; height: 11px; margin-right: 8px;
  vertical-align: baseline;
}
.cell-mark--unrecorded { border: 1.5px dotted var(--unrecorded); }
.cell-mark--evidence { background: var(--evidence); }


/* **The evidence record's own block was deleted with `#158`.** Sixteen comment blocks went: fifteen
 * that each sat on a deleted rule, eleven of them under the section header and four earlier in the
 * file with the written-answer rules, plus the three-paragraph section header itself. All fifteen
 * described this surface. The header asserted a 640px cap and a 190px label column in the present
 * tense, which are the two handover-8 numbers this change exists to retire. It survived the first
 * pass, which is the failure this very comment is about, found on review rather than by the sweep.
 * **Recount by parsing, not by reading**: comment blocks in the old revision against the new, less
 * the two that were edited rather than deleted, which show up as one gone and one added each.
 * The surface is built from design's `facts__*`, `card--sectioned` and `.quote` now, and
 * `workforce.css` carries the values. A comment sits next to the constraint
 * it justifies in this file, so a comment describing a rule that no longer exists reads as a
 * description of a live one. */


/* ===========================================================================
 * The assessment player. Design's `Assessment.dc.html` 3a at 360px and 3c at
 * desktop, taken from the canvas rather than approximated.
 *
 * **Two treatments, not one that shrinks.** At desktop the card floats on the
 * ground and each option is a discrete bordered box; at 360px the whole page
 * is one card and the options are flush rows divided by a hairline. Design
 * drew both, and the difference is not decoration: at 360px a gap between
 * four bordered boxes spends most of the width on edges.
 * =========================================================================== */

/* The masthead in assessment mode. The bar is the shell's, so only its
 * contents are here. `align-self` rather than the bar's `align-items`, which
 * is `stretch` so a section link can fill it. */
/* **The push is here, not on the counter**, for the same reason design's ordinary bar puts its
 * one auto margin on the nav: one auto margin, on the element that is always present in this
 * mode. Two of them share the free space between them and land both children mid-bar. */
.masthead__mode {
  margin-right: auto;
  align-self: center;
  font-size: var(--size-meta);
  font-weight: 600;
  color: var(--t-on);
}
.masthead__counter {
  align-self: center;
  font: 500 var(--size-label)/1 var(--font-mono);
  /* Design's own value. 84 per cent of the fill's own foreground rather than a
   * grey, so it holds on a navy and on a gold. */
  color: color-mix(in srgb, var(--t-on) 84%, transparent);
}
/* **The gutters below 700 are the contents' own, which is how design's bar works there.** Since
 * handover 72 `workforce.css` takes the bar's padding to 0 below 700 and gives the lockup its 16px
 * on the left and the menu its 16px on the right, so the two rows can each run edge to edge. In
 * this mode the bar's contents are these two, so they carry the same 16, which is also what 3a
 * draws on its own bar (`padding: 0 16px`). Without it "Baseline assessment" sat at x=0 at 360. */
@media (max-width: 700px) {
  .masthead__mode { padding-left: 16px; }
  .masthead__counter { padding-right: 16px; }
}
/* Design's 3a drops the competency from the counter at 360px: "4 of 8" rather
 * than "Section 4 of 8 · Data, privacy and confidentiality", which would wrap
 * the bar to two lines for a name the question repeats immediately below. */
.masthead__counter-of { display: none; }

.sitting {
  display: grid;
  /* **300px, not design's 260.** Design's rail labels are its own tenant's short section names
   * ("1 · AI Foundations"); ours are competency names, and "Human Oversight & Escalation" wraps at
   * 260 and reads as a broken row. 300 is the width design gives the Home rail on 2e, so the two
   * rails in the product agree rather than each picking a number. */
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 28px;
  align-items: start;
}
.sitting__card {
  background: var(--surface);
  border: 1px solid #DFE3E7;
  padding: 28px;
  max-width: 680px;
}
.sitting__eyebrow {
  font: 600 var(--size-caps)/1 var(--font-mono);
  letter-spacing: 0.1em;
  color: var(--text-label);
}
.sitting__stem {
  margin: 14px 0 0;
  font-size: var(--size-h3);
  line-height: 1.45;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-wrap: pretty;
}
/* Design's 3a: the scenario's question follows its situation as a second
 * paragraph at the same size, weight 600. */
.sitting__ask { margin: 12px 0 0; font-size: var(--size-h3); line-height: 1.45; font-weight: 600; }

.sitting__options { border: 0; margin: 20px 0 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.sitting__option {
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 14px 16px;
  border: 1px solid #DFE3E7;
  cursor: pointer;
}
/* **The real radio, hidden but not removed.** `appearance: none` on the input
 * keeps it focusable, keeps it in the tab order and keeps arrow-key selection,
 * which a `display: none` input loses. The drawn circle is the sibling span. */
.sitting__option input {
  appearance: none;
  flex: none;
  width: 20px;
  height: 20px;
  margin: 0;
  border: 1.5px solid #7C8590;
  border-radius: 50%;
  display: grid;
  place-items: center;
}
.sitting__option input::before {
  content: "";
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--text);
  transform: scale(0);
}
.sitting__option input:checked::before { transform: scale(1); }
.sitting__option input:checked { border-color: var(--text); }
.sitting__option:hover { border-color: var(--text-secondary); }
.sitting__option:focus-within { outline: 2px solid var(--text); outline-offset: 2px; }
.sitting__option-text { font-size: var(--size-body-sm); }
/* **Three marks on the chosen option, not one.** The fill, the border weight
 * and the label's weight, because ADR 0003's rule is that nothing is carried
 * by one channel: the filled dot alone is a 10px difference and the ground
 * alone disappears in greyscale. */
.sitting__option:has(input:checked) {
  border: 1.5px solid var(--text);
  background: var(--surface-sunken);
}
.sitting__option:has(input:checked) .sitting__option-text { font-weight: 600; }

.sitting__actions { margin-top: 24px; display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
/* `.button--primary` carries the door page's 22px top margin and full width, which the row
 * supplies here instead. Design's padding on this one is 13px 26px, not `.button--inline`'s
 * 12px 22px. */
.sitting__actions .button { margin-top: 0; padding: 13px 26px; }
.sitting__actions .link-action { font-size: var(--size-meta); }

/* The justification box. Design's 3a, and `design-brief.md` §6's mechanism. */
.sitting__box { margin-top: 24px; display: flex; flex-direction: column; gap: 10px; }
.sitting__box-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.sitting__box-title { font-size: var(--size-body-sm); font-weight: 600; }
/* Design draws this as a bordered chip, not an eyebrow. It is the promise the
 * box rests on, so it is given the weight of a stamp rather than a caption. */
.chip-stamp {
  font: 600 var(--size-label)/1.35 var(--font-mono);
  letter-spacing: 0.08em;
  color: var(--text);
  border: 1px solid var(--text);
  padding: 3px 8px;
}
.sitting__box-note { margin: 0; font-size: var(--size-meta); line-height: 1.55; color: var(--text-secondary); text-wrap: pretty; }

/* The sections rail. Design's 3c. */
.rail {
  background: var(--surface);
  border: 1px solid #DFE3E7;
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
/* **`.rail__title` is design's and is deleted here** (`#147` item 4). It was two unrelated rules
 * under one name: design gives it to `.rail__card`'s title at `--size-body`, and ours gave it to
 * the sections rail's label as an 11px mono caps eyebrow. Design's file loads second, so the
 * sitting rail's QUESTIONS label rendered at 15px in body weight, which is design's card title on
 * our label. The label takes `.eyebrow eyebrow--wide` instead, which is design's own component and
 * is what design's `assessment_item.html` puts in that position.
 *
 * **That file is not vendored, so cite the one that is.** `competency/home.html` is design's own
 * shipped template and puts `<div class="eyebrow eyebrow--wide">OPTIONAL</div>` directly above its
 * `.rail__title`, which is the same pattern in a file anybody here can open. Rebuilding the rest of
 * the sitting rail from design's file is `#158`. */
.rail__list { display: flex; flex-direction: column; gap: 9px; font-size: var(--size-meta); }
/* **A step can wrap, so it is aligned to its first line rather than centred.** Design's
 * `align-items: center` and `line-height: 1` are right for a label that is always one line: with
 * two, the box floats into the gap between them and the two lines collide. The mark keeps its own
 * `line-height: 1` through `.rail__mark`, so the padding below is what sits it on the first line's
 * cap height rather than its baseline. */
.rail__step { display: flex; gap: 10px; align-items: flex-start; line-height: 1.35; }
.rail__step > span:last-child { min-width: 0; }
.rail__mark { margin-top: 1px; }
/* **The mark carries the state, not the colour.** A finished step is a ticked
 * box, the current one a solid square, one still to come a dotted square:
 * three different shapes, so the rail survives greyscale and a 360px screen in
 * sunlight. ADR 0003. */
.rail__mark { flex: none; width: 14px; height: 14px; }
.rail__mark--now { border: 1.5px solid var(--text); }
/* `--unrecorded` and not the literal, unlike the two chrome uses above: a step nobody has answered
 * is nothing recorded here, which is what that token means and why it is dotted everywhere else in
 * the product. */
.rail__mark--later { border: 1.5px dotted var(--unrecorded); }
/* The tick's stroke, reachable from here rather than written into the SVG in `sitting.html`, where
 * no stylesheet change could ever have found it. The value is design's de-emphasis grey and is
 * chrome, so it stays the literal for the same reason the marks above do rather than borrowing
 * `--unrecorded`, which would say the opposite of what a finished step means. */
.rail__mark--done { color: #7C8590; }
.rail__step--done { color: var(--text-secondary); }
.rail__step--now { font-weight: 600; }
/* Handover 9 resolved the third grey: it was drift, converted across 71 declarations to
 * `--text-secondary`, and `#5B6672` survives only as `--annotation-text` for the review canvas's
 * own prose. **If that token ever appears in this file or a template, a canvas note has escaped
 * into the product**, which is design's own test for it. */
.rail__step--later { color: var(--text-secondary); }
.rail__note {
  border-top: 1px solid var(--line-hairline);
  padding-top: 13px;
  font-size: var(--size-meta);
  line-height: 1.55;
  color: var(--text-secondary);
}

/* 360px. Design's 3a: one card, edge to edge, flush rows and no rail. Below
 * the desktop rules, because a media query adds no specificity and the mobile
 * layout written above them never applies. */
@media (max-width: 720px) {
  .masthead__counter-of { display: none; }
  .sitting { display: block; }
  .sitting__card { padding: 0; max-width: none; }
  /* Each block is a flush section divided by a hairline, so the padding moves
   * from the card onto the blocks. */
  .sitting__head { padding: 16px; border-bottom: 1px solid var(--line-hairline); display: flex; flex-direction: column; gap: 4px; }
  .sitting__body { padding: 16px; border-bottom: 1px solid var(--line-hairline); }
  .sitting__stem { margin: 0; font-size: var(--size-body-sm); line-height: 1.6; font-weight: 400; }
  .sitting__ask { font-size: var(--size-body-sm); line-height: 1.6; }
  .sitting__options { margin: 0; gap: 0; }
  .sitting__option {
    padding: 13px 16px;
    border: 0;
    border-bottom: 1px solid var(--line-hairline);
    align-items: flex-start;
  }
  .sitting__option:last-child { border-bottom: 1px solid #DFE3E7; }
  .sitting__option:has(input:checked) { border: 0; border-bottom: 1px solid var(--line-hairline); background: var(--surface-sunken); }
  .sitting__option-text { font-size: var(--size-meta); line-height: 1.45; }
  .sitting__box { margin: 0; padding: 16px; }
  .sitting__actions { margin: 0; padding: 16px; }
  .rail { border: 0; border-top: 1px solid #DFE3E7; }
}
@media (min-width: 721px) {
  .masthead__counter-of { display: inline; }
}

/* ---- Learner Home, day one. Design's `Learner Home.dc.html` 2e -------------
 * **Two columns, because the page has two things to say.** The card sitting
 * alone in a 1080px measure reads as a card that has drifted left, which is
 * what it was: design puts a 300px rail beside it carrying what happens next
 * and who can see the record, and the summary cards under it in column one.
 * "Same single action, more air rather than more content." */
.day-one {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 24px 32px;
  align-items: start;
}
.day-one__main { grid-column: 1; }
/* Rows 1 to 3 of column one: the card, the two summaries, the footnote. The
 * rail runs beside all three. */
.day-one__rail { grid-column: 2; grid-row: 1 / span 3; }
.day-one__cards { grid-column: 1; display: flex; gap: 20px; flex-wrap: wrap; }
.day-one__cards > * { flex: 1; min-width: 280px; }
.day-one__foot { grid-column: 1; max-width: 62ch; font-size: var(--size-meta); line-height: 1.6; color: var(--text-secondary); }
.day-one__title { margin: 14px 0 0; font-size: var(--size-display); font-weight: 600; letter-spacing: -0.02em; line-height: 1.2; }
.day-one__lede { margin: 12px 0 0; max-width: 58ch; font-size: var(--size-body); line-height: 1.6; color: var(--text-secondary); text-wrap: pretty; }
.day-one__act { margin-top: 22px; display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.day-one__act .button { margin-top: 0; width: auto; display: inline-flex; padding: 14px 30px; }
.day-one__act-note { font-size: var(--size-meta); color: var(--text-secondary); }

/* The rail. A numbered sequence, so an ordered list. */
.aside-card {
  background: var(--surface);
  border: 1px solid #DFE3E7;
  padding: 22px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.next { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0; }
.next__step { display: flex; gap: 13px; padding-bottom: 16px; }
.next__step:last-child { padding-bottom: 0; }
/* **Solid for the step you are on, dotted for the ones you are not**, which is
 * the same dash-pattern distinction the competency track and the assessment
 * rail use: a shape, never a colour on its own (ADR 0003). */
.next__mark {
  flex: none;
  width: 22px; height: 22px;
  border: 1px dotted var(--text-label);
  display: grid; place-items: center;
  font: 600 var(--size-caps)/1 var(--font-mono);
  color: var(--text-secondary);
}
.next__step--now .next__mark { border: 1px solid var(--text); color: var(--text); }
.next__what { font-size: var(--size-meta); font-weight: 600; line-height: 1.3; color: var(--text-secondary); }
.next__step--now .next__what { color: var(--text); }
.next__detail { margin: 4px 0 0; font-size: var(--size-meta); line-height: 1.5; color: var(--text-secondary); }
.seen { border-top: 1px solid var(--line-hairline); padding-top: 16px; display: flex; flex-direction: column; gap: 7px; }
.seen p { margin: 0; font-size: var(--size-meta); line-height: 1.55; color: var(--text-secondary); }

/* Design's 2e stacks at its own breakpoint: a 300px rail beside a 58ch measure
 * needs about 900px before the card starts losing its line length. */
@media (max-width: 900px) {
  .day-one { grid-template-columns: minmax(0, 1fr); }
  .day-one__rail { grid-column: 1; grid-row: auto; }
}


/* ---- The baseline result. Design's `Assessment.dc.html` 18a ---------------
 * **The one result screen that must not read as a mark.** Counted rather than
 * judged, so there is no fill, no bar and no colour carrying a verdict: the
 * only thing distinguishing a row is whether it names a level or says it was
 * not covered. */
/* **A sectioned card, which is what design draws and what the first version missed.** Each block
 * carries its own padding and the head carries a rule under it, so a plain `.card` with uniform
 * padding is wrong in every measurement while looking close in a screenshot. Design's spec states
 * why the three densities differ: "the head at 26/28 because it carries the only sentence a nervous
 * reader finishes, rows at 13/28 because eight of them are a record, the foot at 18/28 because it
 * holds an action. A uniform padding flattens that into a list of equal things."
 *
 * **It fills its container and is not 660px wide.** That number was copied off the artboard, where
 * the card sits at 1080 with an annotation column beside it, and design's spec names the mistake
 * directly: "earlier canvases showed cards at 660px and 760px for the same reason and those numbers
 * should never have been copied. Blocks fill their container; only prose is measured, and it is
 * measured in ch." The founder saw the result as empty space down the right of the page.
 *
 * Values from `docs/design-spec/18a-baseline-result.json`, vendored from design's own
 * `handover/spec/`, which is a box model rather than a picture,
 * so `--line` is the border rather than the literal the measured version used. */
.starting-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); }
.starting__head { padding: 26px 28px; border-bottom: 1px solid var(--line); }
/* **Design's own three values for this heading, not the shared `h1`'s.** The spec gives the head's
 * `h3` a line height of 1.2 and a letter spacing of -0.02em, where `h1` above is 1.25 and -0.015em.
 * At 24px the line height is the difference between 28.8 and 30, visible when the heading wraps to
 * two lines; the tracking is a third of a pixel per character and invisible until it is measured,
 * which is why it was inherited for a whole round on a surface declared built from the spec. Both
 * are stated here rather than left to the cascade. */
.starting__h { margin: 14px 0 0; line-height: 1.2; letter-spacing: -0.02em; }
/* Ink and body size, not the secondary grey a caption takes: this sentence carries the screen's
 * argument rather than annotating it. */
.starting__lede {
  margin: 12px 0 0;
  max-width: 58ch;
  font-size: var(--size-body);
  line-height: 1.65;
  color: var(--text);
}
.starting__label { padding: 20px 28px 8px; }
.starting__foot { padding: 18px 28px 24px; display: flex; flex-direction: column; gap: 16px; }

.starting { margin-top: 0; }
.starting__row {
  padding: 13px 28px;
  border-bottom: 1px solid var(--line-hairline);
  display: grid;
  grid-template-columns: minmax(0, 1fr) 150px;
  gap: 18px;
  align-items: center;
}
.starting__what { min-width: 0; display: flex; align-items: baseline; gap: 10px; font-size: var(--size-body-sm); line-height: 1.4; }
.starting__code {
  flex: none;
  font: 600 var(--size-label)/1.4 var(--font-mono);
  color: var(--text-secondary);
}
/* Mono, so "Starting at Level 2" and "Not covered" occupy a stable column and
 * the eye reads down it rather than across each row. */
.starting__level { font: 600 var(--size-label)/1.5 var(--font-mono); color: var(--text); }
.starting__note {
  margin: 0;
  max-width: 66ch;
  font-size: var(--size-meta);
  line-height: 1.6;
  color: var(--text-secondary);
}
.starting__act { display: flex; gap: 12px; flex-wrap: wrap; }
/* The control is design's `.btn--primary` since handover 86, when the spec stopped naming a
 * control of its own ("a spec that names its own control class is a second control"), so its
 * padding and height are `workforce.css`'s and no rule of ours sits on it. */

/* **The 360px treatment is design's now**, `docs/design-spec/18a-baseline-result.json`'s
 * `responsive` section, handover 64 (`#146`). There was one before it, the row stacked and the
 * sides dropped to 16px, and both numbers were ours, so it was removed and asked for; this one is
 * the spec's at 700: the row becomes one column and the start label moves under the name,
 * "because a fixed level column at 360 starves the name it is explaining", the head and the foot
 * keep their sectioning at a smaller scale, and the two controls stack full width. "Nothing is
 * dropped at 360 ... a result is the one screen a learner cannot be asked to open on something
 * wider." `test_the_narrow_treatment_is_the_specs` holds the values to the section. The section
 * says nothing about the rows label, so that block keeps design's 20px 28px 8px at every width,
 * and whether it should narrow with its neighbours is asked on #146 rather than guessed here. */
@media (max-width: 700px) {
  .starting__head { padding: 20px 18px; }
  .starting__row { grid-template-columns: minmax(0, 1fr); gap: 4px; padding: 13px 18px; }
  .starting__foot { padding: 16px 18px 20px; }
  .starting__act { flex-direction: column; }
  /* "the two controls stack full width": `.btn` fits its label (`align-self: flex-start`), so
   * the spec's full width is asked of the control here, scoped to this foot at this width. */
  .starting__act .btn { align-self: stretch; }
}
/* ---- One employee, for an administrator (`People.dc.html` 13a) -------------------------------
 *
 * **The row's columns are design's, moved off the inline style so design's own collapse can
 * apply.** `person_detail.html` writes `grid-template-columns:minmax(0,1fr) 130px 150px` inline on
 * `.record__row`, which is the board's value at desktop: no track on this surface, a "Needs L2"
 * cell in its place. An inline value beats every stylesheet rule, so at 700px and below design's
 * `.record__row { grid-template-columns: minmax(0, 1fr) }` never ran and the name column measured
 * 0px at 360. Same defect as the requirement marks on Roles, from the same cause. 13a is drawn at
 * desktop only, so the narrow state is not ours to draw either: it is the collapse design's
 * stylesheet already states for the component, restated here at the same breakpoint. A modifier
 * of our own rather than a rule on `.record__row`, which is design's name, and compounded with it
 * because `workforce.css` loads second: a lone `.record__row--person` ties design's `.record__row`
 * on specificity and loses on order, which put the 262px track column back at desktop. */
/* The third column is the board's 150px until its content is wider. The chip is design's and
 * "NO REQUIREMENT" beside a Record link runs past 150, which put the link outside the card on a
 * person with no role; a content-sized track lets the name column give instead. */
.record__row.record__row--person { grid-template-columns: minmax(0, 1fr) 130px minmax(150px, max-content); }
@media (max-width: 700px) {
  .record__row.record__row--person { grid-template-columns: minmax(0, 1fr); }
}
