/* NURSEAL — account screens (CP2)
 * Loaded after legal.css, which owns the palette, the shell, and the paper. */

.paper--narrow { max-width: 620px; margin: 0 auto; }

/* legal.css leaves .back-link and .policy-nav links at their 22px line box,
 * under both the house 32px floor and WCAG 2.5.8's 24px minimum. Padding them
 * out here, scoped to the account screens. The legal pages carry the same gap
 * and are left alone deliberately — that is a separate pass, not CP2's. */
.back-link,
.policy-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding: 5px 2px;
}

/* ------------------------------------------------------------------ forms */

.field { margin: 0 0 22px; }

.field label {
  display: block;
  margin-bottom: 8px;
  color: var(--ink);
  font-size: 15px;
  font-weight: 650;
}

.field .hint {
  margin: 6px 0 0;
  color: var(--muted);
  font-size: 13px;
}

/* ⛔ A6/D4 — THESE FIVE RULES WERE KEYED TO `[type="email"]` AND MEANT "a text
   field in this form". CP7's typed-code input is `type="text"` — correctly so,
   since type="number" strips a leading zero — and it therefore matched NONE of
   them: no 52px touch target, no border, no focus ring, and, worst of the five,
   no red border when showCodeError() sets `data-invalid` on its field. The
   error message appeared and the field it belonged to looked untouched.

   🔑 SAME SHAPE AS A5, RUNNING THE OTHER WAY. There, a token that named a
   COLOUR ended up doing a SURFACE's job; here, a selector that names a TYPE is
   doing a ROLE's job — and in both cases the second use is invisible until
   something new arrives to expose it. The repair is the same too: say the role.

   ⚠ Scoped to `.field`, which this stylesheet owns, and MEASURED before it was
   widened: the only inputs inside a `.field` anywhere in app/ are this form's
   email field and the code field JS builds beside it. `.ed-input` (type=date)
   is in `.ed-row`, not a `.field`, and legal.css declares no input rules at
   all, so nothing else changes. A checkbox dropped into a `.field` later would
   inherit a 52px bordered slab — loud and immediately visible, which is the
   right direction to fail in. Degrade toward confusing, never toward broken. */
.field input {
  width: 100%;
  min-height: 52px;
  padding: 12px 16px;
  color: var(--ink);
  font: 17px/1.4 var(--sans);
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 14px;
}

.field input:hover { border-color: var(--lavender); }

/* ⚖ N8 (Sami, 2026-08-23, direction B): the RING takes the colour the BORDER
 * in this same rule already has. Before, the rule said "focus is plum" and
 * "focus is blush" in consecutive declarations — and `--blush` at seal/night
 * (#f2a8c1) is the nearest colour in the whole product to `--warning`
 * (#f0aec2), the border a field wears when it is INVALID. ⚠ The tracker row
 * called that "6 of 255 = the same pink"; measured, it is ΔE 4.1, which is
 * ABOVE the ~2.3 just-noticeable difference. What is true and narrower: it is
 * the closest pair by about seven times and the only one of twelve
 * measurements under the bar. ⚠ And since N5 autofocused this field, it is no
 * longer a halo she causes by tabbing — it is what step 2 of the sign-in door
 * looks like the instant it appears.
 * ⚠ SCOPED TO THIS RULE ON PURPOSE — and that scope was CORRECT then and is
 * SPENT now. This sentence used to read "`--blush` still paints four other focus
 * rings (`.btn:focus-visible` below, and three in legal.css)", which N8b made
 * false the next day by repainting all four. Corrected rather than deleted,
 * because the reasoning still holds for why N8 stopped here: none of those four
 * sat beside a `--warning` border, so none had N8's collision, and repainting
 * them inside N8's batch would have moved controls nobody drew.
 * ⛔ WHAT N8b FOUND is that collision was never the only floor: all four read
 * 1.86:1 / 1.72:1 at seal/day against SC 1.4.11's 3.0 bar, and the gate that had
 * cleared them (Gate 8) grades TEXT at 4.5 and never reads an outline. They are
 * `--plum-ink` now, and universe B has no `var(--blush)` consumer left. */
.field input:focus-visible,
.field input:focus {
  border-color: var(--plum);
  outline: 3px solid var(--plum);
  outline-offset: 2px;
}

.field[data-invalid="true"] input { border-color: var(--warning); }

.field-error {
  margin: 8px 0 0;
  color: var(--warning);
  font-size: 14px;
  font-weight: 600;
}

/* ---------------------------------------------------------------- buttons */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 52px;
  padding: 14px 26px;
  color: var(--paper);
  font: 650 17px/1 var(--sans);
  text-decoration: none; /* .btn can be an <a> (callback's retry) — no underline inside a button */
  background: var(--plum-ink);
  border: 1.5px solid var(--plum-ink);
  border-radius: 14px;
  cursor: pointer;
  transition: background 120ms ease, transform 120ms ease;
}

.btn:hover { color: var(--paper); }

.btn:hover { background: var(--plum); border-color: var(--plum); }
.btn:active { transform: translateY(1px); }

/* ⚖ N8b (2026-08-24): --blush → --plum-ink, and the reason is a FLOOR, not taste.
 * N8b was filed as a coherence question and its row said "no accessibility floor
 * is breached", citing a0-token-gate Gate 8. Gate 8 grades TEXT foreground on
 * background at 1.4.3's 4.5 bar and never looks at an outline; a focus ring is
 * NON-text, graded by SC 1.4.11 at 3.0 against what it is adjacent to. A green
 * gate about a different question was reading as clearance. MEASURED: --blush at
 * seal/day — the DEFAULT theme — reads 1.86:1 on the paper and 1.72:1 on the page
 * ground. That is a real failure that shipped, not a preference.
 * ⚖ WHY --plum-ink AND NOT --plum (which N8 gave the field): N8's own rule is
 * "the ring takes the colour this element already has", and .btn is --plum-ink —
 * background AND border. Applying the same rule to a differently-coloured control
 * gives a different answer, which is the rule working rather than drifting.
 * It also measures strongest: worst cell 6.12 vs --plum's 4.46.
 * ⛔ Graded by Gate 9, which sweeps EVERY focus ring in app/ off disk — 33 of
 * them — so the next ring cannot ship unmeasured the way these four did. */
.btn:focus-visible {
  outline: 3px solid var(--plum-ink);
  outline-offset: 3px;
}

.btn[disabled] {
  background: var(--lavender);
  border-color: var(--lavender);
  cursor: progress;
}

.btn--wide { width: 100%; }

.btn--quiet {
  min-height: 44px;
  padding: 11px 20px;
  color: var(--plum-ink);
  font-size: 15px;
  background: transparent;
  border-color: var(--line);
}

.btn--quiet:hover { color: var(--plum-ink); background: var(--lavender-soft); border-color: var(--lavender); }

/* ⛔ THE CONFIRM CARD’S TWO CHOICES — AND THE RULE EXISTS BECAUSE THEIR LABELS
   CONTAIN AN EMAIL ADDRESS. An address has no space to break at, which is the
   same fact `.whoami b` below already had to answer; `.btn` is `650 17px/1`
   with no wrapping rule, so the label simply ran off the phone.
   ⚖ MEASURED BEFORE IT WAS WRITTEN (18.11(1), 2026-08-28): with
   `genaya.mendoza.rn@students.example.edu` the primary button rendered
   **403px wide, right edge at 444px, inside a 320px viewport** — half the
   address off-screen, on the SAFE action.
   ⛔⛔ AND THE REFLEX GATE IS BLIND TO IT: the document reported
   `scrollWidth === clientWidth === 320` the whole time, because the button
   overflows its container without extending the page. `n18-11-callback-shots`
   measures the BUTTON against the VIEWPORT, and keeps the page-level check only
   as a control recording that it reads clean either way.
   ⚠ SCOPED, NOT ADDED TO `.btn`: `.btn` is worn by every control on three
   account pages and none of the others holds an address — widening it would
   repaint surfaces nobody drew. */
/* The same fact one element over, and it survived the button fix because the
   arm that should have caught it read `textContent` — which is blind to
   clipping. At 320px the heading painted "genaya.mendoza.rn@students.exam" and
   stopped; only the screenshot showed it. `overflow-wrap` is inherited, so this
   one declaration covers the bold account name and the sentence under it. */
.confirm-note { overflow-wrap: anywhere; }

.confirm-choice {
  max-width: 100%;
  min-width: 0;            /* a flex item’s default `auto` floor refuses to shrink below its content */
  overflow-wrap: anywhere; /* the address itself is the only available break point */
  line-height: 1.25;       /* .btn is `17px/1`; two lines at 1 collide */
  text-align: center;
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 20px;
}

@media (prefers-reduced-motion: reduce) {
  .btn { transition: none; }
  .btn:active { transform: none; }
  /* legal.css sets scroll-behavior: smooth on <html> with no reduce override;
     these pages inherit it, so the override belongs here. */
  html { scroll-behavior: auto; }
}

/* ------------------------------------------------------- status / results */

/* Present in the DOM from first paint, empty. A region created together with
 * its message is silently dropped by most screen readers. */
.status {
  margin: 20px 0 0;
  font-size: 15px;
}

.status:empty { margin: 0; }

.status .ok,
.status .bad,
.status .working {
  display: block;
  padding: 16px 18px;
  border-radius: 14px;
}

.status .ok  { color: var(--ok-ink); background: var(--ok-bg); border: 1px solid var(--mint); }
.status .bad { color: var(--warning); background: var(--warning-bg); border: 1px solid var(--blush-line); }
.status .working { color: var(--ink-2); background: var(--lavender-soft); border: 1px solid var(--line); }

/* ── A6/D1 — the "this page never booted" notice ───────────────────────────
   display:none here is the RESTING state, and it is deliberately the only
   place that decides visibility for the good case. Two things reveal it, both
   of which run when the module does not: the <noscript><style> block in each
   page's <head>, and `data-noboot` set by the classic watchdog script.
   It borrows .status .bad's exact trio rather than inventing a treatment — the
   page already has a vocabulary for "this did not work", and those three
   tokens are already graded in all four theme×mode cells. */
.noboot-note {
  display: none;
  margin: 0 0 20px;
  padding: 16px 18px;
  color: var(--warning);
  background: var(--warning-bg);
  border: 1px solid var(--blush-line);
  border-radius: 14px;
  font-size: 15px;
}

.noboot-note strong { display: block; margin-bottom: 4px; }

[data-noboot] .noboot-note { display: block; }
/* An ID, so it beats anything the page's own rules could put back. */
[data-noboot] #signin-form { display: none; }

.status strong { display: block; margin-bottom: 4px; }

/* --------------------------------------------------------------- account  */

.rows { margin: 0; }

.rows div {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 18px;
  justify-content: space-between;
  padding: 14px 0;
  border-bottom: 1px solid var(--line);
}

.rows div:last-child { border-bottom: 0; }
.rows dt { color: var(--muted); font-size: 14px; }
.rows dd { margin: 0; color: var(--ink); font-size: 15px; font-weight: 620; }

.tag {
  display: inline-block;
  padding: 4px 11px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.02em;
  border-radius: 999px;
}

.tag--founder { color: var(--founder-ink); background: var(--lavender-soft); border: 1px solid var(--lavender); }
.tag--none    { color: var(--muted); background: var(--tag-bg); border: 1px solid var(--line); }

/* The route out of "No paid access yet". A brand-new account lands on THIS page
   straight from sign-in, so this row was Nurseal's first sentence and it had
   nowhere to go (measured 2026-08-20). Sized to access-warden's 32px floor like
   .back-link above rather than styled as a button: it navigates, it is not the
   page's primary action, and this row's job is still to state a fact. */
.tier-route {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  margin-left: 2px;
  padding: 5px 2px;
  font-size: 13px;
}

/* ---------------------------------------------------------------- consent */

.consent {
  margin: 30px 0 0;
  padding: 24px 26px;
  background: var(--lavender-wash);
  border: 1px solid var(--line);
  border-radius: 18px;
}

.consent h2 { margin-top: 0; }

.consent .split {
  display: grid;
  gap: 18px;
  margin: 20px 0;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

.consent .split section {
  padding: 16px 18px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 14px;
}

.consent .split h3 {
  margin: 0 0 10px;
  font: 700 14px/1.2 var(--sans);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.consent .split ul { margin: 0; padding-left: 20px; color: var(--ink-2); font-size: 14px; }
.consent .split li { margin-bottom: 6px; }
.consent .split li:last-child { margin-bottom: 0; }

.consent .yes h3 { color: var(--plum-ink); }
.consent .no h3  { color: var(--warning); }

.consent-state {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 14px;
  font-size: 15px;
}

.hidden { display: none; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ------------------------------------------------------------ delete (S5)
 *
 * The destructive control and its confirmation. The dialog is a NATIVE
 * <dialog> on purpose: modal focus trapping, Escape-to-close, and focus
 * returning to the button that opened it all come free and correct. A
 * hand-rolled overlay would have to re-implement three things this project has
 * no reference implementation for yet, and access-warden's charter is explicit
 * that a role added without its full keyboard contract measures worse than no
 * ARIA at all.
 */

.btn--danger {
  color: var(--paper);
  background: var(--warning);
  border-color: var(--warning);
}

.btn--danger:hover { background: var(--danger-hover); border-color: var(--danger-hover); }

.confirm {
  width: min(560px, calc(100vw - 32px));
  padding: 0;
  color: var(--ink);
  background: var(--paper);
  border: 1.5px solid var(--line);
  border-radius: 18px;
  box-shadow: var(--confirm-shadow);
}

.confirm::backdrop { background: var(--confirm-backdrop); }

.confirm-body { padding: 26px 26px 22px; }
.confirm h2 { margin: 0 0 12px; font-size: 22px; }
.confirm p { margin: 0 0 14px; color: var(--ink-2); font-size: 15px; line-height: 1.55; }
.confirm p:last-of-type { margin-bottom: 0; }

/* The counts she is deciding against. Given weight, because a number she
 * recognises is a better stop than a word she has to copy (ruling S5-D5). */
.confirm-count {
  margin: 0 0 16px;
  padding: 14px 16px;
  color: var(--ink);
  font-size: 16px;
  background: var(--lavender-soft);
  border: 1px solid var(--lavender);
  border-radius: 12px;
}

.confirm-count strong { font-weight: 720; }

.confirm-limit {
  margin: 0 0 4px;
  padding: 12px 16px;
  color: var(--warning);
  font-size: 14px;
  background: var(--warning-bg);
  border: 1px solid var(--blush-line);
  border-radius: 12px;
}

.confirm-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  padding: 18px 26px 24px;
  border-top: 1px solid var(--line);
}

.confirm-actions .btn { min-height: 48px; padding: 12px 20px; font-size: 16px; }

@media (max-width: 520px) {
  .confirm-actions { flex-direction: column; }
  .confirm-actions .btn { width: 100%; }
}

/* ── Owner-only: the feedback card (tracker step 36) ──────────────────────────
   Ruled by Sami 2026-08-11 — the account card is the inbox; Telegram is held
   for "if that's not enough".

   ⚠ These rules describe a section only ONE account ever renders, so nothing
     here is on a customer's path. It still gets the same target sizes and
     focus treatment as the rest of the page: an owner surface that quietly
     drops the standard is how the standard becomes optional.                  */
#owner-feedback {
  margin: 26px 0 30px;
  padding: 18px 18px 6px;
  border: 1px solid var(--lavender);
  border-radius: 14px;
  background: var(--lavender-soft);
}
#owner-feedback h2 { margin-top: 0; }
.of-count { color: var(--plum); font-weight: 600; }
.of-lede { margin: 0 0 12px; color: var(--ink-2); font-size: 0.95rem; }

.of-list { margin: 0; padding: 0; list-style: none; }
.of-list li {
  margin: 0 0 10px;
  padding: 12px 14px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
}
.of-meta {
  margin: 0 0 6px;
  font-size: 0.8rem;
  color: var(--muted);
  /* A long path plus an email must wrap rather than widen the card — the
     account page is read on a phone as often as anywhere else. */
  overflow-wrap: anywhere;
}
.of-body {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--ink);
  /* She types newlines; they are part of what she said. `pre-wrap` keeps them
     without letting a pasted 200-character line escape the card. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* ── NURSE/61 · the row action, and where a closed report goes ─────────────

   Sami picked THE FOLD (2026-09-04) over a three-chip filter: open reports are
   the card, closed ones sit behind one line that stays shut. The row treatment
   is deliberately identical in both places — the fold MOVES a row, it never
   restyles it — which is what keeps the filter a one-layout-change switch if
   this list ever gets long enough to want it.

   ⛔ NOT ONE HARDCODED COLOUR IN THIS BLOCK. Every value is a token defined in
      all four theme × scheme cells in legal.css, so night and sapphire follow
      for free. A literal hex here would look right in day and wrong in night,
      which is the one failure a day-only screenshot cannot catch.             */
.of-acts {
  margin: 10px 0 0;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
}

/* 44px minimum on an owner surface too. An owner screen that quietly drops the
   target standard is how the standard becomes optional. */
.of-btn {
  font: inherit;
  font-size: 0.82rem;
  padding: 9px 14px;
  min-height: 44px;
  border-radius: 8px;
  border: 1px solid var(--lavender);
  background: var(--paper);
  color: var(--plum-ink);
  cursor: pointer;
}
.of-btn.is-primary {
  background: var(--plum-ink);
  border-color: var(--plum-ink);
  color: var(--paper);
}
.of-btn:hover { border-color: var(--plum); }
.of-btn:focus-visible { outline: 3px solid var(--plum-ink); outline-offset: 2px; }
.of-btn[disabled] { opacity: 0.6; cursor: default; }

/* The optional note. `flex: 1 1 16rem` rather than a width, and the BASIS is
   the whole mechanism: .of-acts wraps, so a basis wider than the leftover room
   beside the button pushes the field onto its own line on a phone with no
   media query. ⛔ MEASURED, because the first version claimed exactly this and
   was wrong — at `12ch` the field survived beside the button at 390px, squeezed
   to ~110px, and rendered the placeholder as "What you did (". A placeholder
   truncated mid-word reads as a broken control, and no gate here could see it:
   every arm asserted the 44px HEIGHT, which was correct throughout.
   ⚠ `min-width: 0` is still load-bearing — a flex item's default `auto` floor
   refuses to shrink below its content, so without it the row overflows instead
   of wrapping. */
.of-note-in {
  font: inherit;
  font-size: 0.85rem;
  flex: 1 1 16rem;
  min-width: 0;
  min-height: 44px;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--paper);
  color: var(--ink);
}
.of-note-in:focus-visible { outline: 3px solid var(--plum-ink); outline-offset: 2px; }
.of-note-in[disabled] { opacity: 0.6; }

/* Closed: receded, not hidden. It keeps the same border radius and padding as
   an open row — this is the same report, filed, not a different kind of thing. */
.of-list li.is-done { background: var(--tag-bg); border-color: var(--line); }
.of-list li.is-done .of-body { color: var(--muted); }

.of-stamp {
  margin: 8px 0 0;
  font-size: 0.78rem;
  color: var(--ok-ink);
  background: var(--ok-bg);
  display: inline-block;
  padding: 3px 9px;
  border-radius: 999px;
}
.of-note {
  margin: 6px 0 0;
  font-size: 0.85rem;
  color: var(--ink-2);
  font-style: italic;
  /* Same wrapping rule as .of-body — it is also text a person typed. */
  overflow-wrap: anywhere;
}

/* The fold itself. The default marker is removed and re-drawn so the whole
   summary row is a 44px target rather than just the triangle. */
.of-fold {
  margin: 2px 0 12px;
  border-top: 1px solid var(--lavender);
  padding-top: 4px;
}
.of-fold summary {
  cursor: pointer;
  font-size: 0.9rem;
  color: var(--plum-ink);
  font-weight: 600;
  list-style: none;
  padding: 8px 2px;
  min-height: 44px;
  display: flex;
  align-items: center;
}
.of-fold summary::-webkit-details-marker { display: none; }
.of-fold summary::before { content: "▸"; margin-right: 8px; }
.of-fold[open] summary::before { content: "▾"; }
.of-fold summary:focus-visible { outline: 3px solid var(--plum-ink); outline-offset: 2px; }
.of-fold .of-list { margin-top: 6px; }

/* ═══ CP6/R5 · her purchases — the receipt ══════════════════════════════════

   ⚖️ Styled like the account rows, NOT like the buy page. This is a record, not
   a shop: nothing here is a call to action, no price is emphasised, and there
   is no accent that would make a past purchase look like an offer. The one
   place money appears larger is the amount itself, because that is the number
   she came to check.

   ⛔ No raw hex — every colour is an existing token, so all four theme cells are
   answered without a new value. Same bar A0/A1 set for this file.

   ⚠ A REFUNDED ROW IS DIMMED, NEVER STRUCK THROUGH OR RECOLOURED RED. The words
   already say "Refunded in full"; a colour that carries the meaning on its own
   fails the moment it is printed, screenshotted in greyscale, or read aloud —
   and this is precisely the row someone reads while disputing a charge. */
.purchases { margin-top: var(--s5, 28px); }
.pu-lede { color: var(--ink-2); margin: 6px 0 12px; max-width: 56ch; }
.pu-list { margin: 0; padding: 0; list-style: none; }
.pu-list li {
  margin: 0 0 10px;
  padding: 12px 14px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
}
.pu-list li[data-status="refunded"] { opacity: 0.72; }
.pu-head { margin: 0 0 4px; font-size: 1rem; color: var(--ink); font-weight: 600; }
.pu-meta { margin: 0; font-size: 0.8rem; color: var(--muted); overflow-wrap: anywhere; }
.pu-refund {
  margin: 12px 0 0; font-size: 0.9rem; line-height: 1.55; color: var(--ink-2);
  max-width: 60ch;
}

/* ═══ CP3C/T5 · her exam date ═══════════════════════════════════════════════
   Green-lit by Sami 2026-08-12.

   ⚖️ Styled to sit BESIDE her account rows, not to compete with them. This is
   an optional field on a page whose other controls export and delete her data;
   the one thing it must not do is look more important than those. So: no card,
   no accent border, the same rhythm as the rows above it.

   ⛔ No raw hex — every colour here is an existing token. This file was audited
   2026-08-02 as carrying 7 raw hex and no token block of its own, and the
   theme work that eventually lands is priced on that number not growing. */
.examdate { margin-top: var(--s5, 28px); }
.ed-opt {
  font-size: 12.5px; font-weight: 500; color: var(--muted);
  border: 1px solid var(--line); border-radius: 999px; padding: 1px 8px;
  vertical-align: middle; margin-left: 6px;
}
.ed-lede { color: var(--ink-2); margin: 6px 0 12px; max-width: 56ch; }
.ed-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
/* 44px in both axes — a date input is a touch target on the phone she studies
   on, and the browser's own picker button lives inside it. */
.ed-input {
  min-height: 44px; padding: 0 10px;
  border: 1.5px solid var(--line); border-radius: 8px;
  font-family: inherit; font-size: 15px; color: var(--ink);
  /* ⛔ WAS `var(--card)`, WHICH DOES NOT EXIST HERE (fixed 2026-08-14, A0b).
     --card is defined only in study.css. These pages load legal.css, which has
     no such token, so this declaration resolved to nothing and the field was
     TRANSPARENT in production from the day it shipped (CP3C/T5) — showing the
     .paper mix (#fffdfc) instead of an input surface. It read as correct only
     because a transparent input over near-white paper looks near-white; the day
     a night mode lands it becomes an invisible field on a dark card.
     --paper is this file's own convention: `.field input[type="email"]` twelve
     rules up already uses it with the identical border. Found by A0's gate,
     which asserts that no declaration resolves to empty. */
  background: var(--paper);
}
.ed-input:focus-visible { outline: 2px solid var(--plum); outline-offset: 2px; }
/* The countdown reads as a fact about her, not as an alert. Same weight as the
   lede — if it ever needs to shout, that is a product decision, not a colour. */
.ed-count { margin: 10px 0 0; color: var(--ink-2); font-weight: 600; }

/* ── N1 · the password field and the spare key ─────────────────────────────
   Added 2026-08-23. Sami: "password on". Password is the everyday door; the
   emailed code is the spare key.

   ⛔ `.btn--quiet` IS NOT REDEFINED HERE even though the spare key uses it and
   its `--line` border is very pale. That class already ships on other controls,
   and quietly restyling a shared class to suit one new caller is how a page
   inherits an identity nobody chose. The spare key gets a SCOPED lift inside
   `.spare` instead, so nothing outside this block moves. */

/* Label and "Show" sit on one baseline so the toggle is findable without
   competing with the label for the eye. */
.pw-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.pw-row label { margin: 0; }

/* A text control, deliberately not a second button: two real buttons stacked
   in one field read as two choices, and only one of them is the action. */
.link-btn {
  background: none;
  border: 0;
  padding: 4px 2px;
  font: inherit;
  font-size: 13px;
  color: var(--plum-ink);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.link-btn:hover { color: var(--plum); }
.link-btn:focus-visible { outline: 2px solid var(--plum); outline-offset: 2px; border-radius: 4px; }

.pwset { margin-top: var(--s5, 28px); }

.spare { margin-top: 26px; padding-top: 20px; border-top: 1px solid var(--line); }
.spare p { margin: 0 0 12px; font-size: 14px; color: var(--ink-2); line-height: 1.6; }
.spare p strong { color: var(--ink); }

/* ⚠ THE SCOPED LIFT, AND IT IS A MEASUREMENT NOT A PREFERENCE. `--line`
   (#eadff7) against `--paper` (#fffdfd) is a hairline meant for dividers; on a
   button it disappears, and this is the one control every account that already
   exists MUST find — nobody on this project has a password yet. Caught in the
   comp by reading the pixels, where it rendered as a caption rather than
   something to press. `--plum` is the same family, just actually visible. */
.spare .btn--quiet { border-color: var(--plum); }


/* ── N5 · the email-first door ─────────────────────────────────────────────
   Sami, 2026-08-23: ask for the email, then throw up the password prompt.

   ⛔ THE TWO STEPS ARE ONE PAGE AND ONE FORM, WHICH IS NOT A SHORTCUT.
      `signin-form` keeps `method="post"` — the only thing standing between a
      browser that never boots and a student's email address sitting in a URL,
      in her history and in the next Referer — and the `<noscript>` /
      `data-noboot` notice keeps working, because there is still exactly one
      page to fail on. Two real pages would have needed both guarantees rebuilt.

   ⚠ `display: none` RATHER THAN REMOVAL. Every element stays in the DOM at
     both steps, so `input.value` is readable from step 2, a password manager
     sees the address it is filling against, and no existing handler or gate
     loses its anchor. The form is `novalidate`, so a hidden `required` email
     input cannot wedge a native submit.

   ⛔ THE SPARE KEY IS HIDDEN AT STEP 1 ON PURPOSE, AND IT IS THE MAIL BUDGET
      THAT DECIDES IT. Pressing Continue is free; "Email me a sign-in code" is
      the one control on this page that spends from the SMTP2GO pool shared with
      genaya-hub. N3 measured the launch hour at ~60 mails against a 25-30/hour
      ceiling, so putting the mail-spending route beside the free one at the
      very first tap is exactly the failure N1 exists to prevent. It is one tap
      further in, never hidden. */

[data-step="email"] #whoami,
[data-step="email"] #password-field,
[data-step="email"] .spare { display: none; }

[data-step="password"] #email-field { display: none; }

/* Step 1's answer, echoed at the top of step 2 — the only thing telling her
   WHICH address she is about to prove she owns. */
.whoami {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 22px;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--lavender-soft);
}
/* ⚠ `overflow-wrap: anywhere` because an email address has no spaces to break
   at, and `min-width: 0` because a flex item's default `auto` floor refuses to
   shrink below its content — without it a long address overflows the card
   instead of wrapping. Measured on this lane once already, on the recovery
   card's named-account button. Wrapping rather than ellipsising: the address is
   the one thing here that has to be RECOGNISABLE, and a truncated one answers
   "is this yours?" with a shrug. */
.whoami b { min-width: 0; color: var(--ink); font-weight: 600; overflow-wrap: anywhere; }
.whoami .link-btn { flex: none; }
