/**
 * ActivGate — MFA enrolment and challenge screens
 * ===============================================
 * mockups/mfa-2026-08-12, approved 2026-08-12:
 *   W1 — B7 (choose a method), B8 (authenticator setup), B9 (recovery codes)
 *   W2 — B1 (modal code step), B4 (full-page challenge), B5 (wrong code /
 *        rate-limited), B6 (recovery code entry)
 *
 * Every colour is written out at this call site rather than resolved from a
 * theme: dark mode is REMOVED on this platform (design-tokens.css declares
 * `color-scheme: light only` and its [data-theme="dark"] block is inert), so
 * the one dark surface here — .mfa-hero — states its own treatment directly
 * and unconditionally.
 *
 * design-tokens.css is NOT modified and NOT depended on for these values.
 *
 * W2 note on reach: this file is no longer loaded only by full pages. The
 * sign-in MODAL loads it too, because B1/B5/B6 are the same screens inside a
 * 376px pane and the code box in particular must be ONE component, not two
 * that drift. Everything below is scoped under .mfa-shell or .mfa-scope, so
 * co-existing with auth.css on the same page cannot leak either way.
 */

/* The approved mockup is drawn under `* { box-sizing: border-box }`, and this
   codebase does NOT set that globally — it sets it on form controls only. That
   split is visible, not theoretical: the two method cards on B7 are the same
   markup in an <a> and a <button>, and they came out 31px different in width
   because only the button inherited border-box. Scoped to these screens so it
   cannot reach anything else.

   .mfa-scope is the same reset with no layout attached — what the modal's OTP
   step wears, since .mfa-shell also carries a page max-width and 40px of top
   padding that make no sense inside a modal pane. */
.mfa-shell,
.mfa-shell *,
.mfa-shell *::before,
.mfa-shell *::after,
.mfa-scope,
.mfa-scope *,
.mfa-scope *::before,
.mfa-scope *::after {
  box-sizing: border-box;
}

/* `hidden` has to actually hide, and on these screens it did not.
   ============================================================
   The UA stylesheet's `[hidden] { display: none }` is an ordinary attribute
   rule: same specificity as a class selector, and it LOSES to any author rule
   that sets `display` on the same element. Almost every component below sets
   one — .mfa-alert and .mfa-warn are `display: flex`, .mfa-steps is `flex`,
   .mfa-eyebrow is `inline-flex` — so the `hidden` attribute in the markup, and
   every `el.hidden = true` in the JS that drives these screens, was inert.

   Measured in a browser against the shipped stylesheet: a `.mfa-alert` with
   `hidden` set computes `display: flex` and lays out 43.5px tall. That means
   B1/B4/B5 painted "That code didn't match" AND "Too many attempts" on first
   load, before the user had typed anything, on all three sign-in surfaces —
   ten elements in total (tests/security/test_mfa_forced_enrolment_screens.py
   enumerates them).

   Fixed once, here, rather than by adding a `.is-hidden` class to ten call
   sites: `hidden` is the platform's own answer and the JS already uses it.
   `!important` on this ONE property, which is what it is for — the alternative
   is a specificity race against every future component that sets `display`. */
.mfa-shell[hidden],
.mfa-scope[hidden],
.mfa-shell [hidden],
.mfa-scope [hidden] {
  display: none !important;
}

.mfa-shell {
  max-width: 940px;
  margin: 0 auto;
  padding: 40px 16px 72px;
}

.mfa-frame {
  display: grid;
  grid-template-columns: 1fr 1fr;
  background: #fff;
  border: 1px solid #e6ebf4;
  border-radius: 22px;
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 12px 32px -8px rgba(30, 40, 74, 0.16);
  overflow: hidden;
}

/* Solo (no brand panel): B8 and B9 */
.mfa-frame--solo {
  grid-template-columns: 1fr;
  max-width: 480px;
  margin: 0 auto;
}

/* --- brand panel (B7 left) ------------------------------------------------ */
.mfa-hero {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: 34px 30px;
  color: #fff;
  background: linear-gradient(135deg, #1E284A 0%, #2E74B8 55%, #F1C9AE 100%);
}

.mfa-hero::after {
  content: "";
  position: absolute;
  inset: auto -32% -46% -32%;
  height: 74%;
  background: radial-gradient(ellipse at 50% 0%, rgba(255, 255, 255, 0.34), transparent 68%);
  pointer-events: none;
}

.mfa-hero__glow {
  position: absolute;
  width: 190px;
  height: 190px;
  border-radius: 50%;
  top: -56px;
  right: -42px;
  background: radial-gradient(circle, rgba(255, 255, 255, 0.30), transparent 68%);
  pointer-events: none;
}

/* The ActivGate mark (templates/partials/_brand_mark.html). Replaced 13 copies
   of an inline Feather "layers" glyph that stood in for the logo across the
   whole auth surface (QA notes M1 / screenshot 11).

   --on-dark whitens it to a silhouette. The mark's own artwork is a blue
   gradient, which would vanish against the hero panel and the app-landing
   brand disc; brightness(0) flattens every channel to black and invert(1)
   lifts it to white, preserving the alpha edge so it reads as crisply as the
   stroked SVG it replaces. Applied per call site, never theme-driven. */
.ag-brand-mark {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.ag-brand-mark--on-dark {
  filter: brightness(0) invert(1);
}

.mfa-hero__logo {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  align-self: flex-start;
  font-size: 17px;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: #fff;
}

.mfa-hero__logo svg,
.mfa-hero__logo .ag-brand-mark {
  width: 26px;
  height: 26px;
  flex: none;
}

.mfa-hero__pitch {
  position: relative;
  z-index: 1;
  margin-top: auto;
  padding-top: 32px;
}

.mfa-hero__pitch h2 {
  margin: 0 0 9px;
  font-size: 20px;
  line-height: 1.28;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: #fff;
}

.mfa-hero__pitch p {
  margin: 0;
  max-width: 33ch;
  font-size: 13px;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.80);
}

.mfa-trust {
  list-style: none;
  padding: 0;
  margin: 17px 0 0;
  display: grid;
  gap: 8px;
}

.mfa-trust li {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 12.5px;
  color: rgba(255, 255, 255, 0.93);
}

.mfa-trust__tick {
  width: 17px;
  height: 17px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.20);
  display: grid;
  place-items: center;
  flex: none;
}

.mfa-trust__tick svg {
  width: 10px;
  height: 10px;
}

/* --- panel ---------------------------------------------------------------- */
.mfa-panel {
  display: flex;
  flex-direction: column;
  padding: 32px 32px 28px;
  background: #fff;
}

.mfa-steps {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 15px;
}

.mfa-steps__pip {
  height: 3px;
  flex: 1;
  border-radius: 2px;
  background: #e6ebf4;
}

.mfa-steps__pip--on {
  background: linear-gradient(145deg, #2563eb, #4f46e5);
}

.mfa-steps__label {
  margin-left: 3px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: #64748b;
}

.mfa-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  align-self: flex-start;
  margin-bottom: 11px;
  padding: 4px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: #2E74B8;
  background: #eaf2fb;
  border: 1px solid #d3e4f7;
}

.mfa-eyebrow--req {
  color: #9a3412;
  background: #fff7ed;
  border-color: #fed7aa;
}

.mfa-eyebrow--ok {
  color: #047857;
  background: #ecfdf5;
  border-color: #a7f3d0;
}

.mfa-title {
  margin: 0 0 7px;
  font-size: 22px;
  line-height: 1.22;
  font-weight: 800;
  letter-spacing: -0.032em;
  color: #1E284A;
}

.mfa-title--sm {
  font-size: 19px;
}

.mfa-sub {
  margin: 0 0 18px;
  font-size: 13.5px;
  line-height: 1.55;
  color: #6B7491;
}

.mfa-sub b {
  color: #2A2A55;
}

/* --- method cards (B7) ---------------------------------------------------- */
.mfa-methods {
  display: grid;
  gap: 10px;
  margin-bottom: 15px;
}

.mfa-method-form { display: contents; }

/* Rendered as both an <a> (passkey) and a <button> (authenticator). The
   button-specific resets are explicit so the card cannot collapse the way a
   default-styled <button> does when it is asked to lay out block content. */
.mfa-method {
  display: flex;
  width: 100%;
  -webkit-appearance: none;
  appearance: none;
  font: inherit;
  gap: 12px;
  align-items: flex-start;
  padding: 14px;
  border: 1.5px solid #dbe3ef;
  border-radius: 13px;
  background: #fff;
  cursor: pointer;
  text-align: left;
  text-decoration: none;
  color: inherit;
  transition: border-color 160ms ease, box-shadow 160ms ease, transform 160ms ease;
}

.mfa-method:hover {
  border-color: #b9cbe4;
  transform: translateY(-1px);
  text-decoration: none;
  color: inherit;
}

.mfa-method:focus-visible {
  outline: 3px solid rgba(46, 116, 184, 0.45);
  outline-offset: 2px;
}

.mfa-method--rec {
  border-color: #2E74B8;
  box-shadow: 0 0 0 3px rgba(46, 116, 184, 0.11);
}

.mfa-method[aria-disabled="true"] {
  opacity: 0.6;
  pointer-events: none;
}

.mfa-method__ic {
  width: 37px;
  height: 37px;
  border-radius: 10px;
  display: grid;
  place-items: center;
  flex: none;
  background: linear-gradient(145deg, #2563eb, #4f46e5);
  box-shadow: 0 6px 14px -4px rgba(79, 70, 229, 0.5);
}

.mfa-method__ic svg {
  width: 18px;
  height: 18px;
}

.mfa-method__ic--alt {
  background: #eef2f8;
  box-shadow: none;
}

.mfa-method__ic--alt svg {
  stroke: #1E284A;
}

.mfa-method__body {
  flex: 1;
  min-width: 0;
}

.mfa-method__title {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
  font-size: 14px;
  font-weight: 750;
  color: #1E284A;
}

.mfa-method__desc {
  margin-top: 2px;
  font-size: 12.5px;
  line-height: 1.5;
  color: #6B7491;
}

.mfa-method__go {
  align-self: center;
  flex: none;
  color: #c3ccdb;
}

.mfa-method__go svg {
  width: 17px;
  height: 17px;
  display: block;
}

.mfa-pill {
  padding: 2.5px 7px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  background: #ecfdf5;
  color: #047857;
  border: 1px solid #a7f3d0;
}

.mfa-pill--neutral {
  background: #eef2f8;
  color: #64748b;
  border-color: #dbe3ef;
}

/* --- QR + secret (B8) ----------------------------------------------------- */
.mfa-qrwrap {
  display: flex;
  gap: 18px;
  align-items: flex-start;
  margin-bottom: 16px;
}

.mfa-qr {
  width: 156px;
  height: 156px;
  border-radius: 13px;
  border: 1.5px solid #dbe3ef;
  padding: 9px;
  background: #fff;
  flex: none;
}

.mfa-qr img {
  width: 100%;
  height: 100%;
  display: block;
}

.mfa-qr-side {
  min-width: 0;
}

.mfa-qr-side h3 {
  margin: 0 0 5px;
  font-size: 13px;
  font-weight: 750;
  color: #1E284A;
}

.mfa-qr-side p {
  margin: 0 0 10px;
  font-size: 12.5px;
  line-height: 1.5;
  color: #6B7491;
}

.mfa-secret {
  display: flex;
  align-items: center;
  gap: 8px;
  justify-content: space-between;
  padding: 9px 11px;
  background: #f7f9fc;
  border: 1px solid #e6ebf4;
  border-radius: 10px;
}

.mfa-secret code {
  font: 700 12px/1.35 ui-monospace, Menlo, Consolas, monospace;
  color: #1E284A;
  letter-spacing: 0.05em;
  word-break: break-all;
  background: none;
  padding: 0;
}

.mfa-copy {
  flex: none;
  padding: 4px 8px;
  border-radius: 7px;
  border: 1px solid #dbe3ef;
  background: #fff;
  font-size: 11px;
  font-weight: 700;
  color: #2E74B8;
  cursor: pointer;
  font-family: inherit;
}

.mfa-copy:hover {
  background: #f2f8fd;
}

.mfa-hint {
  margin: 0 0 8px;
  font-size: 12.5px;
  color: #64748b;
}

.mfa-hint b {
  color: #1E284A;
}

/* =========================================================================
   THE CODE BOX — one component, four screens (B1, B4, B5, B6)
   =========================================================================
   ONE real <input>. The mockup draws six separate cells; this draws those
   cells as a BACKGROUND behind a single field, and that difference is
   deliberate and load-bearing:

   1. A six-box control has to assemble its value in JS. When that script does
      not run, a correct code becomes untypeable — the "correct at the API,
      undeliverable by the product" failure this programme has now paid for
      four times. Here the value is the field's own value, always, and a total
      script failure costs decoration and nothing else.

   2. THE SAME BOX RECEIVES A 9-CHARACTER RECOVERY CODE. On the sign-in modal
      #ag-signin-otp is both the authenticator box (B1) and the recovery box
      (B6) — one input, two credentials, which is exactly why Phase 1's
      maxlength="6" + pattern="\d{6}" locked recovery out entirely. Six
      fixed cells cannot hold XXXX-XXXX at all.

   The cells stay aligned to the glyphs because BOTH sides are expressed in
   `ch`, which in a monospace face is one character's advance by definition —
   so the track cannot drift when the font falls back from ui-monospace to
   Menlo to whatever the machine has. --mfa-cell + --mfa-gap is the advance,
   and `letter-spacing` is that minus the 1ch the glyph itself occupies. */
/* ONE source of geometry. The cells are real elements behind a fully
   transparent input, and the font lives HERE so that `ch` resolves against
   the same metrics for both children — the cell widths and the input's
   letter-spacing are then two readings of the same number and cannot drift. */
.mfa-code-field {
  --mfa-cell: 3.4ch;
  --mfa-gap: 0.62ch;
  --mfa-track: calc(6 * var(--mfa-cell) + 5 * var(--mfa-gap));
  position: relative;
  margin: 2px 0 9px;
  font: 800 23px/1 ui-monospace, Menlo, Consolas, monospace;
}

.mfa-code-field__cells {
  position: absolute;
  inset: 0;
  display: flex;
  gap: var(--mfa-gap);
  justify-content: center;
  pointer-events: none;
}

.mfa-code-field__cells i {
  width: var(--mfa-cell);
  border: 1.5px solid #dbe3ef;
  border-radius: 12px;
  background: #fbfcfe;
  transition: border-color 140ms ease, background-color 140ms ease;
}

.mfa-code-input {
  position: relative;
  z-index: 1;
  /* Sized to the cell TRACK and centred as a box, rather than spanning the
     field and centring its text. Centring the text is what put the caret in
     the 4th cell: `text-align: center` positions the run by its width, so an
     EMPTY field centres nothing at the midpoint and every length short of six
     lands somewhere other than cell 1. Matching the input box to the track
     makes the first glyph's home a fixed offset instead of a function of how
     much has been typed. */
  display: block;
  width: var(--mfa-track);
  margin-inline: auto;
  height: 57px;
  padding: 0;
  border: 1.5px solid transparent;
  border-radius: 12px;
  background: transparent;
  /* A one-time code reads left-to-right even in an Arabic UI. */
  direction: ltr;
  text-align: left;
  font: inherit;
  /* One glyph occupies 1ch; the cell pitch is cell+gap, so the space added
     after each glyph is the difference. The indent is then just the padding
     that centres a 1ch glyph inside its own cell — a constant, so cell 1 is
     the caret's home at every value length. */
  letter-spacing: calc(var(--mfa-cell) + var(--mfa-gap) - 1ch);
  text-indent: calc((var(--mfa-cell) - 1ch) / 2);
  color: #1E284A;
  caret-color: #2E74B8;
}

.mfa-code-input:focus {
  outline: none;
}

/* Focus lights the whole track rather than one cell: there is one field, and
   pretending otherwise would need JS to know where the caret is. */
.mfa-code-field:focus-within .mfa-code-field__cells i {
  border-color: #2E74B8;
  background: #fff;
  box-shadow: 0 0 0 3px rgba(46, 116, 184, 0.13);
}

/* B5, "That code didn't match" — the mockup's .otp--err. */
.mfa-code-field--error .mfa-code-field__cells i {
  border-color: #fca5a5;
  background: #fef2f2;
}

.mfa-code-field--error .mfa-code-input {
  color: #dc2626;
}

/* B6 — the recovery code. The approved design draws this one PLAIN
   (`xxxx-xxxx-xxxx` in a single wide field), not segmented, and that is the
   right shape as well as the drawn one: the value is 9 characters with a dash
   in the middle, so a 6-cell track would be actively misleading about what to
   type. The cells are hidden rather than restyled. */
.mfa-code-field--recovery .mfa-code-field__cells {
  display: none;
}

.mfa-code-field--recovery .mfa-code-input {
  width: 100%;
  margin-inline: 0;
  padding: 0 13px;
  border-color: #e6ebf4;
  border-radius: 10px;
  background: #f7f9fc;
  text-align: left;
  font: 700 15px/1 ui-monospace, Menlo, Consolas, monospace;
  letter-spacing: 0.12em;
  text-indent: 0;
}

.mfa-code-field--recovery .mfa-code-input::placeholder {
  color: #c3ccdb;
}

.mfa-code-field--recovery:focus-within .mfa-code-input {
  border-color: #2E74B8;
  background-color: #fff;
  box-shadow: 0 0 0 3px rgba(46, 116, 184, 0.13);
}

/* --- recovery codes (B9) -------------------------------------------------- */
.mfa-codes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  padding: 14px;
  margin-bottom: 14px;
  background: #f7f9fc;
  border: 1px solid #e6ebf4;
  border-radius: 13px;
}

.mfa-codes__code {
  padding: 4px 0;
  font: 700 13px/1.35 ui-monospace, Menlo, Consolas, monospace;
  letter-spacing: 0.06em;
  color: #1E284A;
  text-align: center;
  user-select: all;
}

.mfa-warn {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  padding: 11px 12px;
  margin-bottom: 14px;
  border-radius: 11px;
  background: #fff7ed;
  border: 1px solid #fed7aa;
  font-size: 12.5px;
  line-height: 1.5;
  color: #9a3412;
}

.mfa-warn svg {
  width: 16px;
  height: 16px;
  flex: none;
  margin-top: 1px;
}

.mfa-alert {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  padding: 11px 12px;
  margin-bottom: 14px;
  border-radius: 11px;
  background: #fef2f2;
  border: 1px solid #fecaca;
  font-size: 13px;
  line-height: 1.5;
  color: #991b1b;
}

/* W1 sized .mfa-warn svg but not this one, because B9's alert is text-only.
   B5 puts an icon in it, and an unsized <svg> in a flex row expands to fill
   the box — measured in a browser at ~200px tall, swallowing the message it
   was meant to annotate. */
.mfa-alert svg {
  width: 15px;
  height: 15px;
  flex: none;
  margin-top: 2px;
}

.mfa-ack {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  margin-bottom: 14px;
  font-size: 13px;
  line-height: 1.5;
  color: #2A2A55;
  cursor: pointer;
}

.mfa-ack input[type="checkbox"] {
  width: 18px;
  height: 18px;
  margin: 2px 0 0;
  flex: none;
  accent-color: #2563eb;
  cursor: pointer;
}

/* --- buttons -------------------------------------------------------------- */
.mfa-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 12px 18px;
  border: 0;
  border-radius: 11px;
  font-size: 14px;
  font-weight: 750;
  cursor: pointer;
  text-decoration: none;
  font-family: inherit;
  line-height: 1.2;
}

.mfa-btn--primary {
  background: var(--ag-gradient-button);
  color: #fff;
  box-shadow: 0 8px 20px -6px rgba(79, 70, 229, 0.55);
}

.mfa-btn--primary:hover {
  color: #fff;
  text-decoration: none;
  filter: brightness(1.04);
}

.mfa-btn--ghost {
  background: #fff;
  color: #1E284A;
  border: 1.5px solid #dbe3ef;
}

.mfa-btn--ghost:hover {
  background: #f6f9fd;
  color: #1E284A;
  text-decoration: none;
}

.mfa-btn[disabled],
.mfa-btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  box-shadow: none;
}

.mfa-btn svg {
  width: 16px;
  height: 16px;
  flex: none;
}

.mfa-btn-row {
  display: flex;
  gap: 9px;
  margin-bottom: 14px;
}

.mfa-btn-row > .mfa-btn {
  flex: 1;
}

.mfa-linkrow {
  margin-top: 13px;
  font-size: 12.5px;
  color: #6B7491;
  text-align: center;
}

.mfa-linkrow--left {
  text-align: left;
}

.mfa-linkrow a {
  color: #2E74B8;
  font-weight: 700;
  text-decoration: none;
}

.mfa-linkrow a:hover {
  text-decoration: underline;
}

/* "Sign out" is a POST (Django 5.0's LogoutView refuses GET), so the control
   has to be a <button> inside a <form> while still reading as the link in the
   sentence around it. The form is inline so it does not break the line. */
.mfa-linkform {
  display: inline;
  margin: 0;
}

.mfa-linkbtn {
  -webkit-appearance: none;
  appearance: none;
  display: inline;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: #2E74B8;
  font-weight: 700;
  cursor: pointer;
}

.mfa-linkbtn:hover {
  text-decoration: underline;
}

.mfa-status {
  margin: 0 0 12px;
  font-size: 13px;
  line-height: 1.5;
}

.mfa-status--error {
  color: #991b1b;
}

.mfa-status--ok {
  color: #047857;
}

/* =========================================================================
   W2 — challenge screens (B1, B4, B5, B6)
   ========================================================================= */

/* B5, "Attempt 2 of 5". The mockup writes this one inline; it is a state of
   the eyebrow, so it lives with the other two. */
.mfa-eyebrow--err {
  color: #991b1b;
  background: #fef2f2;
  border-color: #fecaca;
}

.mfa-btn + .mfa-btn {
  margin-top: 8px;
}

/* The throttle countdown. `tabular-nums` so 14:22 -> 14:21 does not make the
   sentence around it twitch once a second. */
.mfa-countdown {
  font-variant-numeric: tabular-nums;
  font-weight: 800;
}

/* B1/B5/B6 inside the sign-in MODAL.
   The modal pane is ~330px of usable width against the full page's 480px, so
   the type steps down and the code cells tighten — the mockup draws exactly
   this (.otp--sm: 44x52 cells against .otp's 47x57). Everything else is the
   same component. */
.mfa-scope .mfa-title {
  font-size: 19px;
}

.mfa-scope .mfa-sub,
.mfa-scope .mfa-hint {
  margin-bottom: 12px;
}

.mfa-scope .mfa-code-field {
  --mfa-cell: 3.15ch;
  --mfa-gap: 0.6ch;
  font-size: 21px;
}

.mfa-scope .mfa-code-input {
  height: 52px;
}

/* The step is a panel inside someone else's form, so it must not inherit a
   stray text-align from the modal shell. */
.mfa-scope {
  text-align: left;
}

/* =========================================================================
   ON A DARK CARD — .mfa-on-dark
   =========================================================================
   THE DEFECT THIS CLOSES, measured rather than reasoned about.
   `.mfa-title` is `color: #1E284A`. The compact sign-in modal's card
   (`.trailer-modal-card`, static/trailer/css/trailer.css) is
   `background: var(--trailer-secondary)`, and that token is **#1E284A**.
   Contrast 1.00:1 — the same colour, exactly. Both `<h4 class="mfa-title">`
   in includes/auth_modal_compact.html therefore painted navy-on-navy: the
   whole of B1/B5/B6's heading ("Enter your code", "That code didn't match",
   "Too many attempts", "Enter a recovery code") and the whole of B2/B3's
   ("Set up two-factor sign-in" / "Secure your new account"). That card is the
   surface `generic_login_redirect` sends EVERY anonymous visitor to.

   Nothing rescued it: trailer.css contains zero `.mfa-*` rules and its only
   heading override is `.trailer-modal-card h3` while these are `h4`, so the
   card's inherited `color: #F2F6FE` lost to the class rule on the element.

   WHY A CLASS AND NOT A DESCENDANT SELECTOR ON `.trailer-modal-card`.
   Dark mode is REMOVED on both platforms — there is no `prefers-color-scheme`
   or `[data-theme]` to hang this on, and a stylesheet that reaches into
   another component's class name to guess at its background is how the
   original mistake got made in reverse. `.mfa-on-dark` is applied at the CALL
   SITE by whoever knows the surface is dark, the same mechanism
   static/css/verification_badges.css uses with `.agv-on-dark`. A fourth
   surface that forgets it is a visibly-wrong heading, not a silent one, and
   tests/security/test_mfa_challenge_screens.py pins the two that need it.

   Only the colours change. Nothing here touches layout, and the light
   surfaces (templates/accounts/login.html, includes/auth_modal.html) are
   untouched because they never carry the class.

   Measured against #1E284A: #F2F6FE = 13.4:1, #C3CEE4 = 9.1:1,
   #9CC4EC = 7.9:1 — all well past WCAG AA for body text. */
.mfa-on-dark .mfa-title,
.mfa-on-dark .mfa-sub b,
.mfa-on-dark .mfa-hint b {
  color: #F2F6FE;
}

.mfa-on-dark .mfa-sub,
.mfa-on-dark .mfa-hint,
.mfa-on-dark .mfa-linkrow,
.mfa-on-dark .mfa-steps__label {
  color: #C3CEE4;
}

/* #2E74B8 is the brand link colour and reads at 2.9:1 on this card — and on
   B2 that link is the ONLY exit from the gate, because auth-modal.js sets
   `mfaEnrolLocked` and hides the close button. It gets the lightest value of
   the three. */
.mfa-on-dark .mfa-linkrow a,
.mfa-on-dark .mfa-linkbtn {
  color: #9CC4EC;
}

/* Self-contained rather than borrowing Bootstrap's .sr-only / .visually-hidden:
   this stylesheet now loads on the landing page too, where the Bootstrap CSS
   that defines those is not guaranteed to be present. */
.mfa-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

@media (max-width: 860px) {
  .mfa-frame {
    grid-template-columns: 1fr;
  }

  .mfa-hero {
    padding: 26px 22px 30px;
  }

  .mfa-hero__pitch {
    padding-top: 22px;
  }

  .mfa-panel {
    padding: 26px 22px 24px;
  }

  .mfa-qrwrap {
    flex-direction: column;
    align-items: stretch;
  }

  .mfa-qr {
    margin: 0 auto;
  }

  .mfa-codes {
    grid-template-columns: 1fr;
  }
}

/* The no-JS sign-in escape (W2 review C1)
   ======================================
   Rendered only inside <noscript>, so nothing here is ever painted for a
   scripted visitor. It is styled at all because the previous version of this
   escape was an unstyled link buried inside two containers that plain CSS sets
   to `display: none` — Bootstrap's `.modal` and `.trailer-auth-overlay` — and
   was therefore invisible to the only people who could ever see it. It now
   sits at the top level of includes/auth_modal_compact.html.

   Deliberately NOT scoped under .mfa-shell / .mfa-scope, unlike everything
   above: this banner's whole job is to be a top-level node of the page, with
   no ancestor that can hide it. Nothing else in the tree matches these two
   class names. */
.mfa-nojs-escape {
  max-width: 520px;
  margin: 24px auto;
  padding: 16px 18px;
  border: 1px solid #E3E8F2;
  border-radius: 14px;
  background: #FFFFFF;
  box-shadow: 0 10px 26px rgba(19, 32, 63, 0.07);
  font-family: inherit;
  text-align: center;
}

.mfa-nojs-escape p {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: #47506B;
}

.mfa-nojs-escape .mfa-linkrow {
  margin-top: 8px;
}


/* B10 — "Settings: required, still manageable" (approved 2026-08-12)
   ================================================================
   The settings rows. Scoped like everything else in this file: the page wears
   .mfa-shell .mfa-scope, so none of this can reach the rest of the site, and
   the [hidden] override above still applies inside it.

   Colours are literals for the same reason as the rest of the component —
   static/css/design-tokens.css is not modified and not depended on. Dark mode
   is REMOVED on this platform, so there is no theme-driven variant here; a
   dark surface would be styled per call site. */
.mfa-shell--narrow {
  max-width: 720px;
}

.mfa-srow {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
  padding: 18px 20px;
  margin-top: 14px;
  border: 1px solid #E3E8F2;
  border-radius: 16px;
  background: #FFFFFF;
  box-shadow: 0 10px 26px rgba(19, 32, 63, 0.05);
}

.mfa-srow--stack {
  flex-direction: column;
  align-items: stretch;
}

.mfa-srow__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
}

.mfa-srow__body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.mfa-srow__title {
  font-size: 14.5px;
  font-weight: 700;
  color: #17203A;
}

.mfa-srow__desc {
  font-size: 13px;
  line-height: 1.55;
  color: #6B7491;
}

.mfa-srow__form {
  flex: 0 0 auto;
}

/* "Always on" — the lock chip that replaced the toggle. It is a STATEMENT,
   not a control: no cursor, no hover, nothing to press. */
.mfa-lockchip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid #C7E3D0;
  background: #EAF7EF;
  color: #1E6B3E;
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
}

.mfa-lockchip svg {
  width: 13px;
  height: 13px;
}

.mfa-methodlist {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.mfa-methodlist__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 14px;
  border: 1px solid #EDF1F8;
  border-radius: 12px;
  background: #F8FAFD;
}

.mfa-methodlist__item--empty {
  background: #FFFFFF;
  border-style: dashed;
}

.mfa-methodlist__label {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  font-size: 13.5px;
  color: #17203A;
}

.mfa-methodlist__meta {
  font-size: 12px;
  color: #6B7491;
}

.mfa-methodlist__form {
  flex: 0 0 auto;
}

/* The refusal, in place of the button. Shown rather than hidden on purpose:
   an empty space where a control used to be reads as a bug, and the sentence
   is the only thing that tells a user what to do instead. */
.mfa-methodlist__blocked {
  flex: 0 0 auto;
  font-size: 12px;
  font-weight: 600;
  color: #8A93AC;
  text-align: right;
  max-width: 190px;
  line-height: 1.4;
}

.mfa-btn--inline {
  width: auto;
  padding: 8px 14px;
  font-size: 13px;
  margin: 0;
  /* .mfa-btn is a flex item in a row that also holds a long description, so
     without this "Add a method" wraps onto two lines and the row grows. */
  white-space: nowrap;
}

.mfa-btn--danger {
  background: #FFFFFF;
  border: 1px solid #E7C4C4;
  color: #A4322F;
}

.mfa-btn--danger:hover {
  background: #FCF2F2;
}

/* The "that worked" counterpart of .mfa-warn. */
.mfa-note {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin-top: 14px;
  padding: 12px 14px;
  border: 1px solid #C7E3D0;
  border-radius: 12px;
  background: #EAF7EF;
  color: #1E6B3E;
  font-size: 13px;
  line-height: 1.5;
}

.mfa-note svg {
  width: 17px;
  height: 17px;
  flex: 0 0 auto;
  margin-top: 1px;
}

@media (max-width: 620px) {
  .mfa-srow,
  .mfa-srow__head,
  .mfa-methodlist__item {
    flex-direction: column;
    align-items: stretch;
  }

  /* `align-items: stretch` above would blow the chip and the inline buttons
     out to the full row width — measured at 390px: a 300px-wide "Always on"
     pill and a 300px "Add a method" button, both of which read as full-width
     primary controls rather than the compact affordances they are. */
  .mfa-srow .mfa-lockchip,
  .mfa-srow .mfa-btn--inline {
    align-self: flex-start;
  }

  .mfa-methodlist__blocked {
    text-align: left;
    max-width: none;
  }
}
