/* ============================================================================
 * auth.css — the standalone account & password pages (Phase 2 Task 11b).
 *
 * Pixel source: project/auth/auth-screens.jsx — AuthShell + CardHead +
 * TextField + PwField + ReqList + SubmitBtn, across the three screens:
 *   - ClaimAccount  (invite / set initial password)   -> activate.html
 *   - ResetRequest  (forgot / request a reset link)    -> forgot.html
 *   - ResetChoose   (reset with token / new password)  -> reset.html
 *
 * Like login.css these are STANDALONE surfaces OUTSIDE the portal shell, but
 * token- and font-pure via the Phase-1 --tp-* system. The field metrics match
 * the login page exactly (46px control / 11px radius / brand focus ring) so
 * every auth surface reads as one family.
 *
 * D-085: no inline JS/handlers, no inline style="" — the show/hide toggles,
 * the live requirement checklist, the password-match indicator and the submit
 * busy face all live in static/js/auth.js, bound through data-au-* hooks.
 * element.style writes by JS are allowed; this stylesheet supplies every
 * static rule. Token-pure: the only literal is the on-ink #FFFFFF the design
 * system already allowlists for text on solid fills.
 * ========================================================================= */

/* ---- centered-card shell (AuthShell device="desktop") ---------------------- */
.au-page {
  min-height: 100vh;
  min-height: 100dvh;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Device chrome, BOTH axes (2026-08-10 — the viewport-fit=cover rollout).
   *
   * These five templates own their own <head> and now declare
   * `viewport-fit=cover` like base.html does, so the layout viewport extends
   * under the Island / rounded corners / home indicator and nothing above this
   * page absorbs the insets for it — there is no portal topbar out here.
   *
   * THIS rule is the >=768px half of that. At those widths .au-shell is a
   * centred 440px column floating inside this padded page box, so the page's
   * own padding IS the right inset site: the tablet band (768-1023.98px) is
   * where an installed counter iPad's home indicator actually is (D-170), and
   * 48px of designed padding does not by itself reserve a band it knows
   * nothing about. Below 768 the card goes edge-to-edge and this padding drops
   * to 0, which is why the phone override re-homes the insets onto the ROWS
   * (see the media block at the bottom of this file) rather than pulling the
   * full-bleed card off the glass.
   *
   * Two operators, one per axis (design-delta #92(a)): calc() vertically so the
   * designed 48px survives on top of the reserved band, max() horizontally
   * because a landscape notch inset already IS the clearance. Every inset is 0
   * in an ordinary browser tab, so the designed 48/24 is byte-for-byte what
   * desktop renders. Swept by tests/test_device_chrome.py. */
  padding: calc(48px + var(--tp-safe-top) + var(--tp-env-bar-h)) max(24px, var(--tp-safe-right))
    calc(48px + var(--tp-safe-bottom)) max(24px, var(--tp-safe-left));
  background: var(--tp-bg);
  font-family: var(--tp-font-ui);
  color: var(--tp-ink);
}

.au-shell {
  width: 100%;
  max-width: 440px;
  display: flex;
  flex-direction: column;
}

/* ---- brand mark above the card (BrandMark size 34) ------------------------- */
.au-brand {
  display: flex;
  justify-content: center;
  padding: 0 0 30px;
}

.au-shell.is-muted .au-brand {
  /* Expired/used/invalid: desaturate the whole lockup so the triangle reads as
     deliberately inactive, not just low-contrast (D-153 "1C" muted rule). */
  filter: grayscale(1);
  opacity: 0.5;
}

/* The mark is the Stacks wordmark lockup (.st-authlock / brand.css, D-153) —
   .au-brand above only centers it (desktop) / left-aligns it (phone).
   TODO(dark-mode): dark-set lockup. */

/* ---- the card ------------------------------------------------------------- */
.au-card {
  background: var(--tp-surface);
  border: 1px solid var(--tp-hairline);
  border-radius: 18px;
  overflow: hidden;
  /* No box-shadow (it read --tp-shadow-hero until cohesion Stage 3). §9.2 · 01
     declines the raised card and names no "hero" exception: a standalone auth
     card is still a card sitting in the page, and the whole reason the ladder
     is four rungs is that "how important does this look" was never one of the
     questions it answers. The hairline is the edge. */
}

/* The 4px top accent bar — the bundle's brand gradient #2456E6 -> #6E9BF5.
 * The brand stop is the token; the lighter stop is a one-off ramp endpoint the
 * design system owns no token for (allowlisted in tests/styleguide/conftest.py,
 * same precedent as the login hero's dark stops). */
.au-card-accent {
  height: 4px;
  background: linear-gradient(90deg, var(--tp-brand) 0%, #6E9BF5 100%);
}

.au-shell.is-muted .au-card-accent {
  background: var(--tp-hairline);
}

.au-card-body {
  padding: 34px 36px 36px;
}

/* ---- card head (CardHead: tinted icon tile + title + sub) ------------------ */
.au-head {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-bottom: 22px;
}

.au-head-icon {
  width: 52px;
  height: 52px;
  border-radius: 14px;
  display: grid;
  place-items: center;
  font-size: 25px;
}

.au-head-icon--brand {
  background: var(--tp-brand-soft);
  color: var(--tp-brand);
}

.au-head-icon--ok {
  background: var(--tp-ok-soft);
  color: var(--tp-ok);
}

.au-head-icon--muted {
  background: var(--tp-hairline-2);
  color: var(--tp-muted);
}

/* The design system's WARN and NEUTRAL icon-tile tones on the family's head tile — the
 * Sandbox jump-in's hand-off page (board `Sandbox - Follow-ups and Jump In V1`, Part F:
 * F3's warn `arrows-rotate`, F2's neutral flask and F4's neutral `ban`). The pairs are the
 * DS IconTile's own: warn is the soft wash with `--tp-warn-ink` (the contrast fix the base
 * warn misses on its wash), neutral the hairline-2 fill with ink-2 — `--muted` above is a
 * different, quieter glyph and stays what the expired states wear. */
.au-head-icon--warn {
  background: var(--tp-warn-soft);
  color: var(--tp-warn-ink);
}

.au-head-icon--neutral {
  background: var(--tp-hairline-2);
  color: var(--tp-ink-2);
}

/* A SPINNER IN THE TILE'S SLOT (Part F's F1: "so F1 to F3 do not jump when the page
 * resolves"). The slot is the tile's own height with the ring at its start, as drawn; the
 * ring is the DS Spinner on a light surface — the hairline track and an ink sweep, the
 * inverse of `.au-spin`, which lives on a filled button. D-224: an action in flight is a
 * spinner, never a skeleton. */
.au-head-wait {
  height: 52px;
  display: flex;
  align-items: center;
}

.au-head-wait-ring {
  width: 24px;
  height: 24px;
  box-sizing: border-box;
  border-radius: var(--tp-radius-pill);
  border: 2px solid var(--tp-hairline);
  border-top-color: var(--tp-ink);
  animation: au-spin var(--tp-spin-dur) linear infinite;
}

.au-head-text {
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.au-title {
  margin: 0;
  font-size: 24px;
  /* display-scale type — 700; was 780, off §9.6's five-value scale. */
  font-weight: var(--tp-type-display-weight);
  letter-spacing: -0.02em;
  color: var(--tp-ink);
  line-height: 1.1;
}

.au-sub {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--tp-muted);
}

/* THE REASON, in a sunken box (Part F: "so the one variable sentence reads apart from the
 * fixed ones"): the page background inside a hairline-2 edge, 8px (the control/inner-block
 * radius), 14/1.5 in full ink. It sits between the title and the fix line inside
 * `.au-head-text`, whose 7px gap the margins top up to the drawn 14 above and 10 below. */
.au-reason {
  margin: 7px 0 3px;
  padding: 11px 13px;
  border-radius: var(--tp-radius-control);
  background: var(--tp-bg);
  border: 1px solid var(--tp-hairline-2);
  font-size: 14px;
  line-height: 1.5;
  color: var(--tp-ink);
}

/* ---- "setting up <email>" verified banner (ClaimAccount main) -------------- */
.au-target {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 11px 13px;
  margin-bottom: 18px;
  background: var(--tp-brand-soft);
  border-radius: 11px;
}

.au-target-icon {
  color: var(--tp-brand);
  font-size: 16px;
  flex-shrink: 0;
}

.au-target-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.au-target-eyebrow {
  font-size: 11px;
  font-weight: 600;
  color: var(--tp-brand);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.au-target-email {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--tp-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.au-target-badge {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  font-weight: 700;
  color: var(--tp-ok);
  background: var(--tp-ok-soft);
  border-radius: var(--tp-radius-pill);
  padding: 3px 9px;
  flex-shrink: 0;
}

/* ---- error banner (rate-limit / server error; mirrors lg-error in login.css) */
.au-error {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin: 0;
  padding: 11px 13px;
  border-radius: var(--tp-radius-control);
  background: var(--tp-danger-soft);
  color: var(--tp-danger);
  border: 1px solid var(--tp-danger);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.4;
}

.au-error i {
  margin-top: 1px;
  flex-shrink: 0;
}

/* ---- the form ------------------------------------------------------------- */
.au-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.au-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.au-field-label {
  display: flex;
  align-items: center;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--tp-ink-2);
}

/* The wrapper carries the border + focus ring; it holds the leading glyph, the
 * input, and (for password fields) the Show/Hide toggle — mirrors the bundle's
 * TextField/PwField span. */
.au-control {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 48px;
  padding: 0 13px;
  border-radius: 11px;
  background: var(--tp-surface);
  border: 1px solid var(--tp-hairline);
  transition: border 0.15s, box-shadow 0.15s;
}

.au-control:focus-within {
  border-color: var(--tp-brand);
  box-shadow: 0 0 0 3px var(--tp-brand-soft);
}

.au-control-icon {
  color: var(--tp-muted);
  font-size: 16px;
  flex-shrink: 0;
}

.au-input {
  flex: 1;
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  font-size: 14.5px;
  color: var(--tp-ink);
  font-family: var(--tp-font-ui);
}

.au-input::placeholder {
  color: var(--tp-muted);
}

/* Show/Hide password toggle, anchored at the trailing edge of the control. */
.au-show-toggle {
  border: none;
  background: transparent;
  color: var(--tp-muted);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  font-family: var(--tp-font-ui);
  padding: 0;
  white-space: nowrap;
  flex-shrink: 0;
}

/* ---- password-match indicator on the confirm field's label ----------------- */
.au-match {
  margin-left: auto;
  display: none;
  align-items: center;
  gap: 4px;
  font-weight: 600;
}

.au-match--ok {
  color: var(--tp-ok);
}

.au-match--bad {
  color: var(--tp-danger);
}

.au-field[data-au-match="ok"] .au-match--ok {
  display: inline-flex;
}

.au-field[data-au-match="bad"] .au-match--bad {
  display: inline-flex;
}

/* When the confirm field doesn't match, the control reads as an error. */
.au-field[data-au-match="bad"] .au-control {
  border-color: var(--tp-danger);
  box-shadow: 0 0 0 3px var(--tp-danger-soft);
}

/* ---- password requirement checklist (ReqList) ------------------------------ */
.au-reqs {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 13px 14px;
  background: var(--tp-bg);
  border: 1px solid var(--tp-hairline-2);
  border-radius: 11px;
}

.au-req {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--tp-ink-2);
  transition: color 0.15s;
}

/* Empty field: every rule reads as a hint, not a failure. */
.au-reqs[data-au-state="empty"] .au-req {
  color: var(--tp-muted);
}

.au-req.is-ok {
  color: var(--tp-ok);
}

.au-req-dot {
  width: 17px;
  height: 17px;
  border-radius: var(--tp-radius-pill);
  flex-shrink: 0;
  display: grid;
  place-items: center;
  background: var(--tp-hairline-2);
  color: var(--tp-muted);
  font-size: 11px;
  transition: background 0.15s, color 0.15s;
}

.au-req.is-ok .au-req-dot {
  background: var(--tp-ok-soft);
  color: var(--tp-ok);
}

/* The check glyph shows only once the rule passes; otherwise a small dot. */
.au-req-check {
  display: none;
}

.au-req-empty-dot {
  width: 4px;
  height: 4px;
  border-radius: var(--tp-radius-pill);
  background: var(--tp-muted);
}

.au-req.is-ok .au-req-check {
  display: inline-block;
}

.au-req.is-ok .au-req-empty-dot {
  display: none;
}

/* ---- submit button (SubmitBtn: idle -> working -> done) -------------------- */
.au-submit {
  height: 50px;
  border-radius: 12px;
  border: 1px solid var(--tp-ink);
  background: var(--tp-ink);
  color: #FFFFFF;
  font-size: 15px;
  /* a BUTTON LABEL, 600; was 650, off §9.6's five-value scale. */
font-weight: var(--tp-type-button-label-weight);
  font-family: var(--tp-font-ui);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  white-space: nowrap;
  transition: background 0.2s;
}

/* Disabled (requirements not yet met): hairline fill, muted label, no border. */
.au-submit:disabled {
  background: var(--tp-hairline);
  border-color: var(--tp-hairline);
  color: var(--tp-muted);
  cursor: default;
}

.au-submit-face {
  display: none;
  align-items: center;
  gap: 10px;
}

.au-submit[data-au-state="idle"] .au-submit-face--idle,
.au-submit[data-au-state="working"] .au-submit-face--working,
.au-submit[data-au-state="done"] .au-submit-face--done {
  display: inline-flex;
}

/* The done state goes brand-ok green (the bundle's success fill). */
.au-submit[data-au-state="done"] {
  background: var(--tp-ok);
  border-color: var(--tp-ok);
  color: #FFFFFF;
}

.au-spin {
  width: 15px;
  height: 15px;
  border-radius: var(--tp-radius-pill);
  border: 2px solid var(--tp-spinner-track-on-fill);
  border-top-color: #FFFFFF;
  animation: au-spin var(--tp-spin-dur) linear infinite;
  flex-shrink: 0;
}

@keyframes au-spin {
  to { transform: rotate(360deg); }
}

/* ---- OR divider + Microsoft link (ClaimAccount footer options) ------------- */
.au-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 2px 0;
}

.au-divider-line {
  flex: 1;
  height: 1px;
  background: var(--tp-hairline);
}

.au-divider-text {
  font-size: 11.5px;
  color: var(--tp-muted);
  font-weight: 500;
}

.au-ms {
  height: 46px;
  border-radius: 12px;
  border: 1px solid var(--tp-hairline);
  background: var(--tp-surface);
  color: var(--tp-ink-2);
  font-size: 13.5px;
  font-weight: 600;
  font-family: var(--tp-font-ui);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  text-decoration: none;
}

.au-ms:hover {
  background: var(--tp-bg);
}

.au-ms-glyph {
  display: grid;
  grid-template-columns: 7px 7px;
  gap: 2px;
}

.au-ms-sq {
  width: 7px;
  height: 7px;
  border-radius: 1px;
}

.au-ms-sq--r { background: #F25022; }
.au-ms-sq--g { background: #7FBA00; }
.au-ms-sq--b { background: #00A4EF; }
.au-ms-sq--y { background: #FFB900; }

/* ---- secondary button (expired states: "Return to sign in") ---------------- */
.au-btn-secondary {
  height: 50px;
  border-radius: 12px;
  border: 1px solid var(--tp-hairline);
  background: var(--tp-surface);
  color: var(--tp-ink);
  font-size: 15px;
  /* a BUTTON LABEL, 600; was 650, off §9.6's five-value scale. */
font-weight: var(--tp-type-button-label-weight);
  font-family: var(--tp-font-ui);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  text-decoration: none;
}

.au-btn-secondary:hover {
  background: var(--tp-bg);
}

.au-btn-primary {
  height: 50px;
  border-radius: 12px;
  border: 1px solid var(--tp-ink);
  background: var(--tp-ink);
  color: #FFFFFF;
  font-size: 15px;
  /* a BUTTON LABEL, 600; was 650, off §9.6's five-value scale. */
  font-weight: var(--tp-type-button-label-weight);
  font-family: var(--tp-font-ui);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  text-decoration: none;
}

.au-btn-primary:hover {
  opacity: 0.92;
}

/* ---- success state (Password set / Password updated) ----------------------- */
.au-success {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 18px;
  padding: 12px 0 6px;
}

.au-success-mark {
  position: relative;
  width: 64px;
  height: 64px;
}

.au-success-ring {
  position: absolute;
  inset: 0;
  border-radius: var(--tp-radius-pill);
  border: 2px solid var(--tp-ok);
  animation: au-ripple 1100ms ease-out infinite;
}

@keyframes au-ripple {
  0% { transform: scale(0.8); opacity: 0.8; }
  100% { transform: scale(1.8); opacity: 0; }
}

.au-success-disc {
  width: 64px;
  height: 64px;
  border-radius: var(--tp-radius-pill);
  background: var(--tp-ok-soft);
  color: var(--tp-ok);
  display: grid;
  place-items: center;
  font-size: 32px;
}

.au-success-text {
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.au-success-title {
  margin: 0;
  font-size: 23px;
  /* display-scale type — 700; was 780, off §9.6's five-value scale. */
  font-weight: var(--tp-type-display-weight);
  letter-spacing: -0.02em;
  color: var(--tp-ink);
}

.au-success-sub {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--tp-muted);
  max-width: 320px;
}

/* ---- info note (ResetRequest "sent": ask your manager) --------------------- */
.au-note {
  display: flex;
  gap: 11px;
  padding: 13px 14px;
  background: var(--tp-bg);
  border: 1px solid var(--tp-hairline-2);
  border-radius: 11px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--tp-ink-2);
}

.au-note-icon {
  color: var(--tp-muted);
  font-size: 16px;
  flex-shrink: 0;
  margin-top: 1px;
}

/* ---- footer line under the card (TextLink / fine print) -------------------- */
.au-footer {
  text-align: center;
  padding: 20px 0 0;
  font-size: 12.5px;
  color: var(--tp-muted);
}

.au-textlink {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: none;
  background: transparent;
  color: var(--tp-brand);
  font-size: 13.5px;
  font-weight: 600;
  font-family: var(--tp-font-ui);
  text-decoration: none;
  cursor: pointer;
  padding: 4px;
}

.au-textlink:hover {
  text-decoration: underline;
}

/* ---- the keyboard focus ring: the PORTAL'S ring, for the family ---------------
 * `components.css` gives every portal page `:focus-visible { outline: 2px solid
 * var(--tp-brand); outline-offset: 2px }`. These standalone documents never load that
 * sheet, so until 2026-09-30 their controls fell back to the engine's own ring,
 * `outline: auto 1px` in ink: on an ink-filled button that is a dark band on a dark
 * fill (measured on the Sandbox hand-off page's only action, F3's *Back to Stacks*, at
 * 1440, 940 and 390 — the jump-in's UI verification, VF-1). The ring is declared HERE,
 * once, on the family's buttons and text links, so every auth document moves together.
 * Not on `.au-input` or `.au-show-toggle`: their `.au-control` wrapper already draws the
 * field's ring with `:focus-within`, and a second ring inside it would be a double one.
 * Pinned by tests/styleguide/test_auth_focus_ring.py. */
.au-btn-primary:focus-visible,
.au-btn-secondary:focus-visible,
.au-submit:focus-visible,
.au-textlink:focus-visible,
.se-btn:focus-visible {
  outline: 2px solid var(--tp-brand);
  outline-offset: 2px;
}

/* ---- the way back to sign-in, INSIDE the card (Part I, I2) --------------------------
 * The Sandbox's forgot page, where jump-in is configured, draws *Back to sign in* inside
 * the card, centred in a 44px row, and the "Came from Stacks?" line under it — "last,
 * under a rule, below every action the page already had". Face 5 without the line keeps
 * the link in `.au-footer` below the card (SBX-A95(8)). The row is the link's 44px box
 * at every width, as drawn; the link is the family's `.au-textlink`. Straight after a
 * head, the head's own margin is the gap — `.au-alt`'s rule, for the same reason. */
.au-back {
  margin: 16px 0 0;
  min-height: var(--tp-touch-min);
  display: flex;
  justify-content: center;
  align-items: center;
}

.au-head + .au-back {
  margin-top: 0;
}

/* ---- the quiet line at the FOOT of the card, under a rule --------------------
 * Part F's "Have a Sandbox password? Sign in" (F2) and quiet "Back to Stacks" (F4); Part I
 * draws the same line ("Came from Stacks?") on the Sandbox's sign-in pages, so it is the
 * family's, built once here. Centred, 13px muted, the link the family's own `.au-textlink`
 * at the line's size — its 4px padding makes the drawn 6px gap from a 2px one. Straight
 * after a head, the head's own margin is the gap. */
.au-alt {
  margin: 20px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--tp-hairline-2);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 4px 2px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--tp-muted);
  text-align: center;
}

.au-head + .au-alt {
  margin-top: 0;
}

/* Part I's first consumer outside the card family: the Sandbox's sign-in panel, a column
 * that spaces its own children (`.lg-panel-inner`, gap 26). There the column's gap IS the
 * space above the rule, and the line adds none — as straight after a head. Measured before
 * this rule: 46px of air above the rule (the gap plus 20), against the board's 20. */
.lg-panel-inner > .au-alt {
  margin-top: 0;
}

/* `text-wrap: pretty` (the board's own idiom for a sentence) reaches the label's box by
 * inheritance: where the label wraps, the break moves up a word rather than leaving
 * "menu" and its glyph alone on the last line (measured on the session-expired card at
 * every width and the sign-in panel at 940 — the jump-in's UI verification, VF-7). A label
 * that fits on one line (F2, F4, the forgot card) is unchanged. */
.au-alt .au-textlink {
  font-size: inherit;
  text-wrap: pretty;
}

/* A text link's LAST WORD AND ITS GLYPH never part. A label long enough to wrap (Part I's
 * "Open the Sandbox again from the Stacks menu", in the session-expired card's 316px
 * column) otherwise left the glyph alone on a line of its own: an icon is an atomic inline,
 * and Chromium breaks before one even after a no-break space or a word joiner (both
 * measured). `auth/_came_from_stacks.html` says why the label and glyph share one box. */
.au-textlink-tail {
  white-space: nowrap;
}

/* Shown only where script runs: F1's spinner face, which would be false with script off —
 * that page shows its <noscript> F2 instead. A capability query, not a breakpoint (the
 * sandbox-chrome.css precedent); `(scripting: none)` never matches a page that runs script. */
@media (scripting: none) {
  .au-js-only {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .au-spin { animation: none; }
  .au-head-wait-ring { animation: none; }
  .au-success-ring { animation: none; opacity: 0; }
}

/* ---- responsive: edge-to-edge card on phone (AuthShell device="mobile") ----- */
/* Device chrome on phone: the page box drops to `padding: 0` here so the card
 * can run edge-to-edge, which means EVERY inset this surface owes is owed by
 * one of the rows below. That is the audit's own shape — "background surfaces
 * still run edge to edge; only content and controls pull in" — and it is what
 * .lg-hero / .lg-panel and .ob-top / .ob-stage already do on their own
 * standalone pages. Padding .au-page instead would letterbox the white card
 * inside a --tp-bg band, i.e. re-create the exact look viewport-fit=cover
 * exists to remove. */
@media (max-width: 767.98px) {
  .au-page {
    padding: 0;
    min-height: 100dvh;
  }

  .au-shell {
    max-width: 100%;
    flex: 1;
  }

  /* TOP row of the page: with `.au-page` at `padding: 0` this row starts at the
   * device edge, so the Stacks lockup began at y 26 and ran ~43px — the whole
   * mark inside the 59px Island band, the same defect finding 3 recorded for
   * `.lg-hero` and finding 5 for `.ob-top`. calc(), so the designed 26px of air
   * survives ON TOP of the reserved band: measured 85 = 26 + 59. */
  .au-brand {
    justify-content: flex-start;
    padding: calc(26px + var(--tp-safe-top) + var(--tp-env-bar-h)) max(22px, var(--tp-safe-right))
      18px max(22px, var(--tp-safe-left));
  }

  .au-card {
    flex: 1;
    border-radius: 0;
    border-left: none;
    border-right: none;
    box-shadow: none;
  }

  /* Sides only. The card's white wash keeps running to the glass (it is the
   * padded box, not the painted one) and only the fields/copy pull in. */
  .au-card-body {
    padding: 26px max(22px, var(--tp-safe-right)) 30px max(22px, var(--tp-safe-left));
  }

  /* The BOTTOM row is whichever of the two comes last, so each states its own
   * case rather than both reserving the band:
   *
   *   - no footer (the success / expired states, and set_pin's keypad) — the
   *     card is :last-child, is `flex: 1`, and therefore ends ON the glass. It
   *     takes a BARE inset on the WRAPPER, the .tp-popover-card / .tp-sheet-card
   *     / .ins-sheet shape (design-delta #92(c)): the wash still reaches the
   *     edge, and .au-card-body's own 30px is the internal padding that stacks
   *     on top of it.
   *   - footer present — the <p> below the card is the last row, and takes
   *     calc() so its designed 26px survives the reserved band.
   *
   * Scoped to `.au-shell >` because .au-card is also the direct child in the
   * muted/expired shells, and :last-child is the whole point of the rule. */
  .au-shell > .au-card:last-child {
    padding-bottom: var(--tp-safe-bottom);
  }

  .au-footer {
    padding: 18px max(22px, var(--tp-safe-right))
      calc(26px + var(--tp-safe-bottom)) max(22px, var(--tp-safe-left));
  }

  /* Part F's 390 frames: the foot line at 14px, 18 above its rule and 12 below it. */
  .au-alt {
    margin-top: 18px;
    padding-top: 12px;
    font-size: 14px;
  }

  /* "Back to sign in" is a 44px text action at 390 (design-delta #164, board 5c).
     Measured before: 13.5px text + 4px padding, a ~26px target under the touch floor
     on every auth page that carries it (forgot, reset). Fixed HERE, at the
     primitive, so every consumer moves together — never per page. */
  .au-textlink {
    min-height: var(--tp-touch-min);
  }
}

/* …AND ON A COARSE POINTER AT ANY WIDTH (2026-09-23, Sandbox close-out re-shoot
 * F-4). The phone band above is a question about the viewport; the tap floor is a
 * question about the POINTER, and a 940 tablet sits outside that band with no
 * mouse — "Back to sign in" measured 120x24 there. The twin declares exactly
 * what the phone block does (the components.css `_TWINNED_TOUCH_FLOORS` rule),
 * and the link is already `inline-flex; align-items: center`, so the text stays
 * vertically centred in the taller box. */
@media (pointer: coarse) {
  .au-textlink {
    min-height: var(--tp-touch-min);
  }
}

/* ============================================================================
 * Session-expired card (.se-*) — ps-pages.jsx PageSession
 *
 * A standalone centered card used ONLY by auth/session_expired.html. Shares
 * .au-page for the full-viewport centering + background; the card is narrower
 * (380px, matching the bundle) and uses a different internal layout (WU mark
 * inside the card at the top, textAlign center, no top accent bar).
 *
 * Token-pure: the only literals are the on-ink #FFFFFF (allowlisted for
 * text on solid fills) and the brand gradient lighter stop #6E9BF5 (the same
 * allowlisted ramp endpoint already in .au-card-accent).
 * ========================================================================= */

/* ---- centered card -------------------------------------------------------- */
.se-card {
  width: 100%;
  max-width: 380px;
  background: var(--tp-surface);
  border: 1px solid var(--tp-hairline);
  border-radius: 16px;
  /* No box-shadow — same decline as `.au-card` above (cohesion Stage 3). */
  padding: 34px 32px 26px;
  text-align: center;
}

/* ---- WU brand mark (inside the card — matches PageSession layout) ---------- */
/* The card logo is the Stacks wordmark lockup (.st-authlock / brand.css, D-153) —
   this wrapper only centers it above the copy. */
.se-logo {
  display: flex;
  justify-content: center;
  margin: 0 auto 18px;
}

/* ---- title ----------------------------------------------------------------- */
.se-title {
  margin: 0 0 6px;
  font-size: 17px;
  font-weight: 700;
  color: var(--tp-ink);
  letter-spacing: -0.01em;
}

/* ---- body copy ------------------------------------------------------------- */
.se-copy {
  margin: 0 0 22px;
  font-size: 12.5px;
  color: var(--tp-ink-2);
  line-height: 1.55;
  text-wrap: pretty;
}

/* ---- primary Sign in button (ink fill — same rule as .au-btn-primary) ------ */
.se-btn {
  height: 46px;
  border-radius: 9px;
  background: var(--tp-ink);
  color: #FFFFFF; /* on-ink text (allowlisted) */
  border: none;
  font-size: 13px;
  font-weight: 600;
  font-family: var(--tp-font-ui);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  text-decoration: none;
  transition: opacity 0.15s;
}

.se-btn:hover {
  opacity: 0.88;
}

/* ---- "You'll return to …" hint line --------------------------------------- */
.se-return {
  margin: 14px 0 0;
  font-size: 11px;
  color: var(--tp-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---- mono version footer -------------------------------------------------- */
.se-footer {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-top: 22px;
  padding-top: 14px;
  border-top: 1px solid var(--tp-hairline-2);
  font-family: var(--tp-font-mono);
  font-size: 9.5px;
  color: var(--tp-muted);
}

.se-footer-sep {
  opacity: 0.6;
}

/* ---- responsive: edge-to-edge on phone ------------------------------------ */
@media (max-width: 767.98px) {
  .se-card {
    max-width: 100%;
    border-radius: 0;
    border-left: none;
    border-right: none;
    box-shadow: none;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    /* This card IS the page below 768 — 100dvh tall inside a .au-page whose own
     * padding has dropped to 0 — so all four of its edges are device edges and
     * it owns all four insets itself. The base `34px 32px 26px` is restated
     * here rather than patched per-side, because a shorthand is what renders
     * and pinning it whole is what stops a future tidy silently wiping a term
     * (INSET_ZERO_METRICS). Content is vertically centred, so the top/bottom
     * terms are what keep a long copy block off the Island and the gesture bar
     * as the viewport shortens. */
    padding: calc(34px + var(--tp-safe-top) + var(--tp-env-bar-h)) max(32px, var(--tp-safe-right))
      calc(26px + var(--tp-safe-bottom)) max(32px, var(--tp-safe-left));
  }
}
