/* identity_oidc/static/identity_oidc/auth-neumorphic.css
 *
 * "Encrypted Calm" — light neumorphic auth surface for the
 * Therapatic Identity Provider.
 *
 * Design vocabulary:
 *
 *   - IdP is a deliberate handoff surface ("you crossed into the
 *     security boundary"). Visually distinct from the SPA so users
 *     know which trust zone they're in.
 *   - Soft cool-cream base; surface color matches body so
 *     dual-shadow neumorphism reads.
 *   - One accent color (deeper teal — not the bright SPA teal,
 *     which vibrates uncomfortably on light backgrounds).
 *   - Three reusable surface primitives:
 *       .na-raised   — outset dual shadow (cards, CTA at rest)
 *       .na-pressed  — inset dual shadow (button on active)
 *       .na-carved   — deeper inset (inputs, secret boxes)
 *   - Trust signals (live session dot, encrypted-session strip,
 *     wordmark) anchor the enterprise-grade feel.
 *
 * A11y:
 *   - Focus halo replaces (not removes) browser outline on
 *     interactive elements.
 *   - `prefers-reduced-motion` stops pulse + breath animations.
 *   - All text contrast against the base meets WCAG AA;
 *     primary CTA and links meet AAA.
 *   - Decoration carried by shadow, semantics carried by text.
 *
 * Class prefix `.na-*` (neumorphic-auth).
 */

/* The Cairo face (Arabic + Latin). An @import must precede every other
   rule. Every neumorphic auth page and every account page links this
   sheet first, so this one line gives all of them the Arabic face. */
@import url("fonts/cairo.css");

/* ── Tokens ─────────────────────────────────────────────────── */

:root {
  /* Surface — slight cool tint reads as clinical, not yellow */
  --na-bg: #eef0f4;
  --na-surface: #eef0f4;        /* neumorphism: surface == body */
  --na-surface-recess: #e6e9ee; /* one notch deeper for carved boxes */

  /* Shadows — bright highlight (top-left) + cool soft shadow
     (bottom-right). The contrast ratio between these two is what
     makes neumorphic depth read on light surfaces. */
  --na-shadow-light: rgba(255, 255, 255, 0.95);
  --na-shadow-dark: rgba(168, 178, 196, 0.42);

  /* Text — banker's-blue/slate, not flat black */
  --na-text-strong: #1a2540;
  --na-text: #324063;
  --na-text-muted: #6a7691;
  --na-text-subtle: #8995a8;

  /* Accent — deeper teal that reads as confident on a light bg */
  --na-accent: #0ea5a3;
  --na-accent-deep: #0d8a89;
  --na-accent-soft: rgba(14, 165, 163, 0.20);
  --na-accent-glow: rgba(14, 165, 163, 0.14);

  /* Semantic */
  --na-danger: #be2d4f;
  --na-danger-soft: rgba(190, 45, 79, 0.10);
  --na-warning: #b97d00;
  --na-warning-soft: rgba(185, 125, 0, 0.10);
  --na-success: var(--na-accent);

  /* Radii */
  --na-radius-card: 24px;
  --na-radius-control: 14px;
  --na-radius-pill: 100px;

  /* Spacing — equal to the .na-form gap (a test holds them together): a
     notice drawn in the card ahead of a form keeps the form's own rhythm
     (see "Card notices" below). */
  --na-space-stack: 16px;

  /* Type */
  --na-font:
    ui-sans-serif, system-ui, -apple-system, "Segoe UI",
    Roboto, "Helvetica Neue", Arial, "Apple Color Emoji",
    "Segoe UI Emoji", sans-serif;
  --na-font-mono:
    ui-monospace, "SFMono-Regular", "JetBrains Mono",
    Menlo, Consolas, "Liberation Mono", monospace;

  /* Easing — slow start, slow end ("liquid") */
  --na-ease: cubic-bezier(0.6, 0, 0.4, 1);
  --na-ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* On an Arabic (RTL) document the text face is Cairo, with the Latin stack
   kept as the fallback; the stack above had no Arabic face at all, so Arabic
   fell to whatever the reader's machine had. `:root[dir="rtl"]`, not
   `[dir="rtl"]`: at (0,2,0) it out-ranks the plain `:root` that
   account-neumorphic.css redeclares AFTER this file loads. LTR pages keep the
   value above. --na-font-mono stays Latin: it only sets codes and e-mail
   addresses. */
:root[dir="rtl"] {
  --na-font:
    "Cairo", ui-sans-serif, system-ui, -apple-system, "Segoe UI",
    Roboto, "Helvetica Neue", Arial, "Apple Color Emoji",
    "Segoe UI Emoji", sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }

/* The HTML `hidden` attribute is a semantic signal — it MUST
   always mean "don't render this." The browser UA stylesheet's
   `[hidden] { display: none }` rule loses specificity ties to
   any author rule that sets `display: <anything>`. That's how
   `<button hidden class="na-button--passkey">` ended up visible
   despite the JS keeping `hidden` set on browsers that have
   Conditional UI. `!important` here is correct: it preserves
   the contract the `hidden` attribute claims to provide. */
[hidden] { display: none !important; }

/* ── Body + topology backdrop ───────────────────────────────── */

body.na-body {
  background: var(--na-bg);
  color: var(--na-text);
  font-family: var(--na-font);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;

  /* Multi-layer radial "beacon" — reads as soft topology emanating
     from the card. Deep teal at very low opacity so it tints
     without competing with the card. */
  background-image:
    radial-gradient(ellipse 720px 520px at 50% 38%, rgba(14, 165, 163, 0.045) 0%, transparent 65%),
    radial-gradient(ellipse 1100px 700px at 50% 45%, rgba(14, 165, 163, 0.025) 0%, transparent 70%),
    radial-gradient(circle 420px at 50% 50%, rgba(26, 37, 64, 0.015) 0%, transparent 60%);
  background-attachment: fixed;
}

/* Faint concentric contour-ring overlay — reads as subliminal
   topology + "secure session" beacon. */
body.na-body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  background:
    repeating-radial-gradient(
      circle at 50% 45%,
      transparent 0,
      transparent 80px,
      rgba(14, 165, 163, 0.020) 81px,
      transparent 82px
    );
  z-index: 0;
}

/* ── Layout ─────────────────────────────────────────────────── */

.na-shell {
  position: relative;
  z-index: 1;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* Top bar — "Back to Therapatic" (see `.na-home` below), or nothing */
.na-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px 28px 8px;
  font-size: 11.5px;
  color: var(--na-text-muted);
  letter-spacing: 0.05em;
  gap: 16px;
  flex-wrap: wrap;
}

/* Stage — vertically centers the card */
.na-stage {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px 24px 8px;
}

/* ── Card — the breathing centerpiece ───────────────────────── */

.na-card {
  position: relative;
  width: 100%;
  max-width: 440px;
  border-radius: var(--na-radius-card);
  padding: 40px 36px 30px;

  /* Brushed-metal sheen: 3-stop top-to-bottom gradient on the
     card surface. Barely perceptible (~3% lightness delta) but
     reads as "milled aluminum panel" rather than flat cream. */
  background: linear-gradient(
    180deg,
    #f2f4f8 0%,
    #ecedf1 55%,
    #e7e9ee 100%
  );

  /* surface-raised: bright top-left highlight + soft cool depth */
  box-shadow:
    -12px -12px 26px var(--na-shadow-light),
    14px 14px 34px var(--na-shadow-dark);

  /* Entrance animation — runs once on page load: card glides up
     8px while fading in, then settles into the breath cycle.
     Two animations composed so the entrance never restarts. */
  animation:
    na-enter 480ms var(--na-ease) both,
    na-breath 8s var(--na-ease) infinite 480ms;
  will-change: transform, opacity;
}

@keyframes na-enter {
  0%   { opacity: 0; transform: translateY(8px) scale(0.995); }
  100% { opacity: 1; transform: translateY(0)   scale(1.000); }
}

@keyframes na-breath {
  0%, 100% { transform: scale(1.000); }
  50%      { transform: scale(1.0025); }
}

/* Brand mark inside the card head — wordmark engraved DIRECTLY into
   the card surface. No secondary lozenge / chip / pill. The
   neumorphic depth comes from per-letter drop-shadow filters that
   read as "stamped into the cream surface", like a corporate
   embossing seal pressed into letterhead. */
.na-card__brand {
  text-align: center;
  margin: 4px 0 26px;
}

.na-card__mark {
  /* Pure layout container — no background, no shadow. The logo
     itself carries the engraved visual via `filter:`. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.na-card__logo {
  display: block;
  width: 200px;
  height: auto;
  user-select: none;
  pointer-events: none;
  /* Per-letter engraved illusion:
       - 1px bright highlight cast DOWN-RIGHT (the cut edge catches
         light from upper-left).
       - 1px soft dark cast UP-LEFT (the recessed cavity is in
         shadow on the lit side).
     The 0px blur on both keeps the edge crisp so it reads as
     "carved" rather than "soft drop-shadow". */
  filter:
    drop-shadow(1px 1px 0 rgba(255, 255, 255, 0.92))
    drop-shadow(-1px -1px 0 rgba(80, 95, 120, 0.18));
}

/* On hi-dpi the per-letter engraving is sharper if we tighten the
   shadow offsets — 0.5px renders as a true subpixel highlight. */
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
  .na-card__logo {
    filter:
      drop-shadow(0.5px 0.5px 0 rgba(255, 255, 255, 0.95))
      drop-shadow(-0.5px -0.5px 0 rgba(80, 95, 120, 0.22));
  }
}

.na-card__title {
  margin: 0;
  text-align: center;
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.012em;
  color: var(--na-text-strong);
}

.na-card__subtitle {
  margin: 8px 0 0;
  text-align: center;
  font-size: 13.5px;
  color: var(--na-text-muted);
  line-height: 1.55;
}

.na-card__divider {
  height: 1px;
  margin: 24px 0 22px;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(26, 37, 64, 0.08) 50%,
    transparent 100%
  );
}

/* ── Form ───────────────────────────────────────────────────── */

.na-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.na-field {
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.na-label {
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 10px;
  font-weight: 600;
  color: var(--na-text-muted);
}

.na-input {
  appearance: none;
  width: 100%;
  background: var(--na-surface);
  border: 0;
  outline: 0;
  padding: 14px 16px;
  font-size: 14.5px;
  font-family: var(--na-font);
  color: var(--na-text-strong);
  border-radius: var(--na-radius-control);

  /* surface-carved */
  box-shadow:
    inset 4px 4px 10px var(--na-shadow-dark),
    inset -3px -3px 8px var(--na-shadow-light);

  transition:
    box-shadow 240ms var(--na-ease),
    color 240ms var(--na-ease);
}

.na-input::placeholder { color: var(--na-text-subtle); }

/* Input + adjacent reveal button (eye toggle on password fields).
   The button sits absolute over the input; the input compensates
   with `padding-inline-end` so typed text never collides. */
.na-input-wrap {
  position: relative;
  display: block;
}

.na-input-wrap .na-input--with-toggle {
  /* Extra inline-end padding so input contents clear the toggle */
  padding-inline-end: 46px;
}

.na-input__toggle {
  position: absolute;
  inset-inline-end: 8px;
  top: 50%;
  transform: translateY(-50%);
  appearance: none;
  background: transparent;
  border: 0;
  padding: 7px;
  border-radius: 10px;
  color: var(--na-text-muted);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition:
    color 200ms var(--na-ease),
    background 200ms var(--na-ease),
    box-shadow 200ms var(--na-ease);
}

.na-input__toggle:hover {
  color: var(--na-accent-deep);
  background: rgba(14, 165, 163, 0.06);
}

.na-input__toggle:active {
  /* surface-pressed in miniature */
  background: rgba(14, 165, 163, 0.10);
  color: var(--na-accent-deep);
}

.na-input__toggle:focus-visible {
  outline: 0;
  color: var(--na-accent-deep);
  box-shadow: 0 0 0 2px var(--na-accent), 0 0 16px var(--na-accent-glow);
}

/* Eye-icon state: open by default, swap to closed when aria-pressed
   is "true" (i.e. password is currently revealed → next click hides). */
.na-input__toggle .na-eye--closed { display: none; }
.na-input__toggle[aria-pressed="true"] .na-eye--open { display: none; }
.na-input__toggle[aria-pressed="true"] .na-eye--closed { display: inline-flex; }

.na-input:focus,
.na-input:focus-visible {
  /* surface-carved + soft teal halo (a11y-grade contrast) */
  box-shadow:
    inset 4px 4px 10px var(--na-shadow-dark),
    inset -3px -3px 8px var(--na-shadow-light),
    0 0 0 1.5px var(--na-accent),
    0 0 24px 4px var(--na-accent-glow);
}

/* Mono-rendering for inputs that hold secret-y data
   (TOTP codes, recovery codes, etc.) */
.na-input--mono {
  font-family: var(--na-font-mono);
  letter-spacing: 0.08em;
}

.na-helper {
  font-size: 11.5px;
  color: var(--na-text-muted);
  margin-top: -2px;
  line-height: 1.5;
}

/* ── Card notices ─────────────────────────────────────────────
   An error banner or a helper line drawn in the card ahead of a form
   (step-up's "Signed in as", select-context / register / verify-email
   errors) sat flush on the first control: the card is plain block flow and
   neither carried a margin, and `.na-helper` above pulls itself 2px up,
   which is meant for a hint under an input. Spaced here by position, so
   every page that puts a notice before its form is covered at once. The
   margin collapses into a larger neighbour's (footer, error-page CTA), so
   gaps that were already wider are left as they were. */
.na-card > .na-helper {
  margin-block: 0 var(--na-space-stack);
}

/* OTP / digit-code input — wider tracking + monospace for the
   six-digit step-up code. Keeps the regular `.na-input` chrome
   (inset shadow, focus ring) so nothing else changes. */
.na-input--otp {
  font-family: var(--na-font-mono);
  letter-spacing: 0.32em;
  text-align: center;
  font-size: 18px;
  font-weight: 600;
}

/* Radio-card list — used by /oidc/select-context to let a user pick
   personal vs a tenant workspace. Each row is a hit-target with
   neumorphic carving; selecting one fills the indicator ring with
   the accent. */
.na-choices {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 8px;
}
.na-choice {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  border-radius: var(--na-radius-control);
  background: var(--na-surface-recess);
  box-shadow:
    inset 4px 4px 10px var(--na-shadow-dark),
    inset -3px -3px 8px var(--na-shadow-light);
  cursor: pointer;
  transition: box-shadow 200ms var(--na-ease);
}
.na-choice:hover {
  box-shadow:
    inset 5px 5px 12px var(--na-shadow-dark),
    inset -4px -4px 10px var(--na-shadow-light);
}
.na-choice__input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.na-choice__visual {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--na-surface);
  box-shadow:
    -3px -3px 6px var(--na-shadow-light),
    3px 3px 6px var(--na-shadow-dark);
  flex-shrink: 0;
  position: relative;
}
.na-choice__visual::after {
  content: "";
  position: absolute;
  inset: 5px;
  border-radius: 50%;
  background: var(--na-accent);
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 160ms var(--na-ease), transform 160ms var(--na-ease-spring);
}
.na-choice__input:checked + .na-choice__visual::after {
  opacity: 1;
  transform: scale(1);
}
.na-choice__input:focus-visible + .na-choice__visual {
  box-shadow:
    -3px -3px 6px var(--na-shadow-light),
    3px 3px 6px var(--na-shadow-dark),
    0 0 0 3px var(--na-accent-soft);
}
.na-choice__body {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.na-choice__title {
  font-weight: 600;
  color: var(--na-text-strong);
  font-size: 14.5px;
}
.na-choice__subtitle {
  font-size: 12.5px;
  color: var(--na-text-muted);
}

/* "or" divider between two CTAs (e.g. OTP form / passkey button on
   the step-up page). Renders as a thin hairline on each side of an
   uppercase label, neutral coloring so it doesn't compete. */
.na-divider {
  display: flex;
  align-items: center;
  margin: 22px 0;
  color: var(--na-text-muted);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
}
.na-divider::before,
.na-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: rgba(168, 178, 196, 0.32);
}
.na-divider span {
  padding: 0 14px;
}

/* ── Button ─────────────────────────────────────────────────── */

.na-button {
  appearance: none;
  width: 100%;
  background: var(--na-surface);
  color: var(--na-accent-deep);
  border: 0;
  padding: 15px 18px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.04em;
  font-family: var(--na-font);
  cursor: pointer;
  border-radius: var(--na-radius-control);

  /* surface-raised + inner accent ring */
  box-shadow:
    -6px -6px 14px var(--na-shadow-light),
    8px 8px 20px var(--na-shadow-dark),
    inset 0 0 0 1px rgba(14, 165, 163, 0.25);

  transition:
    box-shadow 240ms var(--na-ease),
    color 240ms var(--na-ease),
    transform 240ms var(--na-ease);

  margin-top: 6px;
}

.na-button:hover {
  color: var(--na-accent-deep);
  box-shadow:
    -8px -8px 18px var(--na-shadow-light),
    11px 11px 26px var(--na-shadow-dark),
    inset 0 0 0 1px rgba(14, 165, 163, 0.55),
    0 0 28px var(--na-accent-glow);
}

.na-button:active {
  /* surface-pressed */
  box-shadow:
    inset 4px 4px 10px var(--na-shadow-dark),
    inset -3px -3px 8px var(--na-shadow-light),
    inset 0 0 0 1px rgba(14, 165, 163, 0.40);
  transform: scale(0.995);
  color: var(--na-accent-deep);
}

.na-button:focus-visible {
  box-shadow:
    -6px -6px 14px var(--na-shadow-light),
    8px 8px 20px var(--na-shadow-dark),
    inset 0 0 0 1px rgba(14, 165, 163, 0.40),
    0 0 0 2.5px var(--na-accent),
    0 0 24px var(--na-accent-glow);
}

.na-button:disabled {
  cursor: not-allowed;
  color: var(--na-text-subtle);
  box-shadow:
    -4px -4px 10px var(--na-shadow-light),
    6px 6px 14px var(--na-shadow-dark);
}

/* Submit-loading state — set by JS on form submit. The button
   shows a spinner inside its existing label and ignores further
   clicks; the entire form is disabled so the user can't change
   inputs mid-flight. */
.na-button--loading {
  cursor: progress;
  pointer-events: none;
  color: var(--na-text-subtle);
}

.na-button--loading .na-button__label { opacity: 0.55; }

.na-button__spinner {
  display: none;
  width: 14px;
  height: 14px;
  margin-inline-end: 10px;
  border: 2px solid var(--na-accent-deep);
  border-top-color: transparent;
  border-radius: 50%;
  animation: na-spin 700ms linear infinite;
  vertical-align: -2px;
}
.na-button--loading .na-button__spinner { display: inline-block; }

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

/* Caps Lock notice — appears below a password field when the
   browser reports CapsLock is active during typing. Renders as
   a small carved chip in warning amber so it reads as a hint,
   not a hard error. */
.na-caps-lock {
  display: none;
  margin-top: 8px;
  padding: 8px 12px;
  border-radius: 10px;
  background: var(--na-surface);
  color: var(--na-warning);
  font-size: 11.5px;
  letter-spacing: 0.04em;
  font-weight: 500;
  box-shadow:
    inset 2px 2px 6px var(--na-shadow-dark),
    inset -1px -1px 4px var(--na-shadow-light);
}

.na-caps-lock[data-active="true"] {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.na-caps-lock__icon {
  width: 11px;
  height: 11px;
  flex-shrink: 0;
}

/* Secondary button — same surface, no accent ring */
.na-button--secondary {
  color: var(--na-text);
  box-shadow:
    -6px -6px 14px var(--na-shadow-light),
    8px 8px 20px var(--na-shadow-dark);
}
.na-button--secondary:hover {
  color: var(--na-text-strong);
  box-shadow:
    -8px -8px 18px var(--na-shadow-light),
    11px 11px 26px var(--na-shadow-dark);
}

/* Passkey button — secondary CTA below the main form, only shown
   on browsers that LACK WebAuthn Conditional UI. On modern Chrome
   / Safari / Edge / Firefox 119+, the email field's autofill
   dropdown surfaces passkeys inline and this explicit button is
   redundant — auth-neumorphic.js keeps the `hidden` attribute set
   in that case. The global `[hidden]` rule near the top of this
   file enforces the hidden state win-vs-`display`. */
.na-button--passkey {
  margin-top: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  position: relative;
}

.na-button--passkey svg {
  flex-shrink: 0;
  color: var(--na-accent-deep);
}

.na-pill {
  display: inline-block;
  padding: 3px 9px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--na-accent-deep);
  background: rgba(14, 165, 163, 0.10);
  border-radius: 100px;
  margin-inline-start: 2px;
}

/* Danger button — same surface, danger ring */
.na-button--danger {
  color: var(--na-danger);
  box-shadow:
    -6px -6px 14px var(--na-shadow-light),
    8px 8px 20px var(--na-shadow-dark),
    inset 0 0 0 1px rgba(190, 45, 79, 0.25);
}
.na-button--danger:hover {
  box-shadow:
    -8px -8px 18px var(--na-shadow-light),
    11px 11px 26px var(--na-shadow-dark),
    inset 0 0 0 1px rgba(190, 45, 79, 0.55),
    0 0 28px rgba(190, 45, 79, 0.18);
}

/* ── Alert ──────────────────────────────────────────────────── */

.na-alert {
  background: var(--na-surface);
  color: var(--na-danger);
  padding: 12px 14px;
  border-radius: var(--na-radius-control);
  font-size: 13px;
  line-height: 1.5;
  /* slightly carved + warm danger glow */
  box-shadow:
    inset 2px 2px 8px var(--na-shadow-dark),
    inset -2px -2px 6px var(--na-shadow-light),
    0 0 22px rgba(190, 45, 79, 0.05);
}

.na-card > .na-alert {
  margin-block-end: var(--na-space-stack);
}

.na-alert--success {
  color: var(--na-accent-deep);
  box-shadow:
    inset 2px 2px 8px var(--na-shadow-dark),
    inset -2px -2px 6px var(--na-shadow-light),
    0 0 22px var(--na-accent-glow);
}

/* An alert above a form is the form's sibling, outside its flex gap; this
   gives it the stack spacing the form puts between its own fields, the same
   token "Card notices" uses, so the two cannot drift apart. */
.na-alert + .na-form { margin-block-start: var(--na-space-stack); }

/* The registration switch (ADR-0065): "by invitation only" is information,
   not a success and not an error, so it reads in the body text colour. */
.na-alert--notice {
  color: var(--na-text);
}

/* The way out under a notice or a refusal: a lead-in and the support and
   contact links. It wraps on a phone, and the gap (not a margin) separates
   the items, so it reads the same in both directions. */
.na-alert__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 14px;
  margin-block-start: 8px;
  color: var(--na-text-muted);
}
/* The RTL selector outranks the later `[dir="rtl"] .na-link` margin. */
.na-alert__actions .na-link,
[dir="rtl"] .na-alert__actions .na-link { margin-inline: 0; }

/* ── Check-inbox confirmation ────────────────────────────────
   A calm, centered handoff state after registration. The email
   action, password confirmation and onboarding are three separate
   steps, so the copy and visual hierarchy describe each accurately. */

.na-check-inbox {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.na-check-inbox__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 62px;
  height: 62px;
  margin-bottom: 20px;
  color: var(--na-accent-deep);
  border-radius: 50%;
  box-shadow:
    -6px -6px 14px var(--na-shadow-light),
    8px 8px 20px var(--na-shadow-dark),
    inset 0 0 0 1px var(--na-accent-soft);
}

.na-check-inbox__icon svg {
  width: 30px;
  height: 30px;
}

.na-check-inbox__message {
  max-width: 34rem;
  margin: 0;
  color: var(--na-text);
  font-size: 14px;
  line-height: 1.7;
}

.na-check-inbox__expiry {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin: 18px 0 0;
  padding: 8px 13px;
  color: var(--na-accent-deep);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.4;
  border-radius: var(--na-radius-pill);
  box-shadow:
    inset 2px 2px 6px var(--na-shadow-dark),
    inset -1px -1px 4px var(--na-shadow-light);
}

.na-check-inbox__expiry svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

.na-check-inbox__help {
  max-width: 31rem;
  margin: 20px 0 0;
  color: var(--na-text-muted);
  font-size: 12.5px;
  line-height: 1.65;
}

.na-check-inbox__action {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 24px;
  text-decoration: none;
}

/* "Back to app" beside the closure confirmation on the sign-in page: a link
   into the app that opened the Delete account page (identity_account
   .deletion_return). A link, never a redirect -- the person reads the notice. */
.na-closure__back {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 14px 0 18px;
  text-decoration: none;
}

/* ── Trust badges (carved pebbles) ──────────────────────────── */

.na-trust {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  margin-top: 24px;
}

.na-trust__item {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px;
  background: var(--na-surface);
  border-radius: var(--na-radius-pill);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--na-text-muted);
  font-weight: 500;
  /* surface-carved */
  box-shadow:
    inset 2px 2px 6px var(--na-shadow-dark),
    inset -1px -1px 4px var(--na-shadow-light);
}

.na-trust__icon {
  width: 11px;
  height: 11px;
  opacity: 0.7;
  flex-shrink: 0;
}

/* Helper text shown below a field — used on registration for the
   password-policy hint ("Minimum 8 characters…"). Sits inside the
   form flow rather than under a specific input. */
.na-hint {
  font-size: 12px;
  color: var(--na-text-muted);
  line-height: 1.45;
  margin: -4px 0 2px;
}

/* Required confirmation checkbox (the one 18+ and Terms tick on
   registration). The native box, tinted with the accent, beside a label
   that wraps; logical properties so the box sits on the reading side in
   Arabic too. */
.na-check {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--na-text);
  cursor: pointer;
}

.na-check__box {
  flex: 0 0 auto;
  inline-size: 18px;
  block-size: 18px;
  margin-block-start: 1px;
  margin-inline: 0;
  accent-color: var(--na-accent-deep);
  cursor: pointer;
}

.na-check__box:focus-visible {
  outline: 2px solid var(--na-accent-deep);
  outline-offset: 2px;
}

/* ── Footer (inside card) ───────────────────────────────────── */

.na-card__footer {
  text-align: center;
  margin-top: 22px;
  font-size: 12.5px;
  color: var(--na-text-muted);
}

/* Secondary footer line — used for "Forgot your password?" so it
   sits below the primary "New here? Create an account" without
   competing for attention. */
.na-card__footer--muted {
  margin-top: 8px;
  font-size: 11.5px;
}

.na-link {
  color: var(--na-accent-deep);
  text-decoration: none;
  font-weight: 600;
  margin-inline-start: 6px;
  transition: color 220ms var(--na-ease);
}
.na-link:hover { color: var(--na-text-strong); }

.na-link--muted {
  color: var(--na-text-muted);
  font-weight: 500;
}
.na-link--muted:hover { color: var(--na-accent-deep); }

/* ── Bottom legal strip ─────────────────────────────────────── */

.na-legal {
  text-align: center;
  padding: 22px 24px 30px;
  font-size: 11px;
  color: var(--na-text-subtle);
  letter-spacing: 0.04em;
}

.na-legal__line + .na-legal__line { margin-top: 4px; }

/* Terms + Privacy, on every page the shell renders. Its own link class rather
   than `.na-link`: that one carries a `margin-inline-start` (and an RTL rule
   flipping it) for inline use next to a sentence, which would push the pair
   off-centre in a centred strip. */
.na-legal__links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.na-legal__link {
  color: var(--na-text-muted);
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color 220ms var(--na-ease);
}
.na-legal__link:hover { color: var(--na-text-strong); }

.na-legal__sep { color: var(--na-text-subtle); }

/* ── Language switcher (carved pebble pill) ─────────────────── */

.na-lang {
  display: inline-flex;
  align-items: center;
  padding: 6px 14px;
  border-radius: var(--na-radius-pill);
  background: var(--na-surface);
  font-size: 11px;
  color: var(--na-text-muted);
  text-decoration: none;
  letter-spacing: 0.04em;
  font-weight: 500;
  box-shadow:
    inset 2px 2px 6px var(--na-shadow-dark),
    inset -1px -1px 4px var(--na-shadow-light);
  transition: color 220ms var(--na-ease);
}
.na-lang:hover { color: var(--na-text-strong); }

/* On an English page the pill reads "العربية" — the only Arabic on the page,
   so none of the RTL rules reach it. The anchor carries lang="ar" (which a
   screen reader also needs to pronounce it); give that word the Arabic face
   and drop the tracking that splits its letters. Latin text is untouched. */
.na-lang:lang(ar) {
  font-family: "Cairo", var(--na-font);
  letter-spacing: normal;
}

/* ── RTL ────────────────────────────────────────────────────── */

[dir="rtl"] .na-link { margin-inline-start: 0; margin-inline-end: 6px; }

/* A link inside a sentence (the register checkbox label) takes no margin
   in either direction: the sentence's own spaces separate it, so the 6px
   above would widen one gap, and in Arabic it sat between "شروط الخدمة"
   and the "و" that follows. It comes after the RTL rule to outrank it. */
.na-link--inline,
[dir="rtl"] .na-link--inline { margin-inline: 0; }

/* ── Mobile ─────────────────────────────────────────────────── */

@media (max-width: 600px) {
  .na-card {
    padding: 32px 24px 22px;
    border-radius: 20px;
    /* Tighter shadows on mobile so they stay crisp */
    box-shadow:
      -7px -7px 16px var(--na-shadow-light),
      9px 9px 22px var(--na-shadow-dark);
  }
  .na-card__title { font-size: 20px; }
  .na-input {
    box-shadow:
      inset 3px 3px 8px var(--na-shadow-dark),
      inset -2px -2px 6px var(--na-shadow-light);
  }
  .na-button {
    box-shadow:
      -4px -4px 10px var(--na-shadow-light),
      6px 6px 14px var(--na-shadow-dark),
      inset 0 0 0 1px rgba(14, 165, 163, 0.25);
  }
  .na-topbar { padding: 14px 18px 4px; }
}

/* ── Reduced motion ─────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  /* Card stays put (no entrance, no breath); spinner falls back
     to instant; every transition is reduced to ~0. */
  .na-card,
  .na-button__spinner { animation: none; }
  .na-card { opacity: 1; transform: none; }
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

/* ════════════════════════════════════════════════════════════════
   LOGIN PAGE
   ════════════════════════════════════════════════════════════════

   Everything below is either (a) scoped to `.na-body--aa`, or
   (b) a component only the login template renders.

   `.na-body--aa` began as the sign-in page's own scope
   (`.na-body--aa`). Since 2026-10-02 (owner: AA on every IdP form
   page) `_neumorphic_auth_shell()` puts it on EVERY page it renders —
   register, forgot / reset password, verify and email-change confirm,
   select-context, step-up and the journey pages — so the darkened
   inks, the control boundary, the focus ring and the filled primary
   CTA below are the IdP's, not the sign-in page's. The ratios were
   measured there; the other pages use the same surfaces.

   Measured contrast, WCAG 2.1 (sRGB), against the surface the text
   actually sits on. The card is a gradient (#f2f4f8 → #e7e9ee), so
   every ratio below is quoted against its DARKEST stop (#e7e9ee) —
   the worst case — or against the input fill (#eef0f4) for text
   inside a control.

     BEFORE                                        ratio
       button label   #0d8a89 on #eef0f4            3.67  ✗ (needs 4.5)
       placeholder    #8995a8 on #eef0f4            2.66  ✗ (needs 4.5)
       muted text     #6a7691 on #e7e9ee            3.75  ✗ (needs 4.5)
       focus ring     #0ea5a3 on #eef0f4            2.66  ✗ (needs 3.0)
       caps-lock note #b97d00 on #eef0f4            3.07  ✗ (needs 4.5)
       input boundary  — (shadow only, no boundary)       ✗ (needs 3.0)

     AFTER
       button label   #ffffff on #0b7d7c            4.95  ✓
       placeholder    #5d677f on #eef0f4            4.96  ✓
       subtle ink     #5d677f on #e6e9ee (recess)   4.65  ✓
                      #5d677f on #dce8eb            4.52  ✓
                      (the body where its three tints overlap; #616b83
                      read 4.26 there, and 4.49 on the legal strip)
       muted text     #535e73 on #e7e9ee            5.37  ✓
       focus ring     #0a6a67 on #eef0f4            5.63  ✓
       caps-lock note #8d5f00 on #eef0f4            4.88  ✓
       input boundary #75839c on #eef0f4            3.36  ✓
                      #75839c on #e7e9ee            3.15  ✓
*/

.na-body--aa {
  /* Same hues, darkened until they clear AA. The neumorphic
     surfaces, radii, shadows and brand teal are untouched. */
  --na-text-muted: #535e73;
  --na-text-subtle: #5d677f;
  --na-accent-deep: #0a6a67;
  --na-warning: #8d5f00;

  /* Primary CTA fill + the boundary colour for carved controls. */
  --na-accent-fill: #0b7d7c;
  --na-accent-fill-hover: #0a6a67;
  --na-control-edge: #75839c;
}

/* ── Input boundary + focus ─────────────────────────────────── */

/* The carved inset shadow alone reads as depth, not as an edge —
   there is no colour boundary at all, so a control is impossible to
   locate at 3:1. Add a real 1px inset ring and keep the carving. */
.na-body--aa .na-input {
  box-shadow:
    inset 0 0 0 1px var(--na-control-edge),
    inset 4px 4px 10px var(--na-shadow-dark),
    inset -3px -3px 8px var(--na-shadow-light);
}

.na-body--aa .na-input:hover {
  box-shadow:
    inset 0 0 0 1px var(--na-accent-deep),
    inset 4px 4px 10px var(--na-shadow-dark),
    inset -3px -3px 8px var(--na-shadow-light);
}

.na-body--aa .na-input:focus,
.na-body--aa .na-input:focus-visible {
  box-shadow:
    inset 0 0 0 1px var(--na-accent-deep),
    inset 4px 4px 10px var(--na-shadow-dark),
    inset -3px -3px 8px var(--na-shadow-light),
    0 0 0 2.5px var(--na-accent-deep);
}

/* An invalid field carries the danger edge so the association is
   visible as well as announced. */
.na-body--aa .na-input[aria-invalid="true"] {
  box-shadow:
    inset 0 0 0 1px var(--na-danger),
    inset 4px 4px 10px var(--na-shadow-dark),
    inset -3px -3px 8px var(--na-shadow-light);
}

.na-body--aa .na-input[aria-invalid="true"]:focus,
.na-body--aa .na-input[aria-invalid="true"]:focus-visible {
  box-shadow:
    inset 0 0 0 1px var(--na-danger),
    inset 4px 4px 10px var(--na-shadow-dark),
    inset -3px -3px 8px var(--na-shadow-light),
    0 0 0 2.5px var(--na-danger);
}

/* The eye toggle sits ON the input, so its focus ring needs the
   same weight as the field's. */
.na-body--aa .na-input__toggle:focus-visible {
  box-shadow: 0 0 0 2.5px var(--na-accent-deep);
}

/* Every other focusable thing on the page gets one consistent,
   AA-contrast ring rather than the browser default.
   Deliberately NO border-radius here: an outline already follows the
   element's own radius, so setting one would reshape the pill-shaped
   .na-lang and .na-home into rounded rectangles for as long as they
   hold focus. Each element keeps its own radius. */
.na-body--aa a:focus-visible {
  outline: 2.5px solid var(--na-accent-deep);
  outline-offset: 2px;
}

/* ── Primary CTA ────────────────────────────────────────────── */

/* Filled, not outlined: the old CTA was the same cream as the
   secondary passkey button and read as one of three equal
   choices. Filling it makes the primary action unambiguous AND
   fixes the label contrast in the same move. */
.na-body--aa .na-button--primary {
  background: var(--na-accent-fill);
  color: #ffffff;
  box-shadow:
    -6px -6px 14px var(--na-shadow-light),
    8px 8px 20px var(--na-shadow-dark);
}

.na-body--aa .na-button--primary:hover {
  background: var(--na-accent-fill-hover);
  color: #ffffff;
  box-shadow:
    -8px -8px 18px var(--na-shadow-light),
    11px 11px 26px var(--na-shadow-dark),
    0 0 28px var(--na-accent-glow);
}

.na-body--aa .na-button--primary:active {
  background: var(--na-accent-fill-hover);
  color: #ffffff;
  box-shadow:
    inset 3px 3px 8px rgba(0, 0, 0, 0.22),
    inset -2px -2px 6px rgba(255, 255, 255, 0.10);
}

.na-body--aa .na-button--primary:focus-visible {
  background: var(--na-accent-fill);
  color: #ffffff;
  outline: 2.5px solid var(--na-accent-deep);
  outline-offset: 2.5px;
  box-shadow:
    -6px -6px 14px var(--na-shadow-light),
    8px 8px 20px var(--na-shadow-dark);
}

/* Spinner rides on the filled ground, so it must be white. */
.na-body--aa .na-button--primary .na-button__spinner {
  border-color: #ffffff;
  border-top-color: transparent;
}

/* In-flight: keep the filled ground and full-contrast label. The
   shared `.na-button--loading` greys the label out, which would
   drop "Signing in…" below AA exactly when it matters. */
.na-body--aa .na-button--primary.na-button--loading {
  background: var(--na-accent-fill-hover);
  color: #ffffff;
  cursor: progress;
}

.na-body--aa .na-button--primary.na-button--loading .na-button__label {
  opacity: 1;
}

/* ── Field-level error ──────────────────────────────────────── */

/* Always in the DOM as a `role="alert"` live region so that both
   the server-rendered message and a client-side one announce.
   `:empty` hides it when there is nothing to say — no `hidden`
   juggling, and the live region is never torn out of the a11y
   tree. */
.na-field__error {
  margin: 2px 0 0;
  font-size: 12.5px;
  line-height: 1.45;
  font-weight: 500;
  color: var(--na-danger);
  display: flex;
  align-items: flex-start;
  gap: 6px;
}

.na-field__error:empty { display: none; }

.na-field__error::before {
  content: "";
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  margin-top: 1px;
  background: var(--na-danger);
  /* Exclamation-in-circle, drawn as a mask so it inherits the
     danger colour and needs no extra asset. */
  -webkit-mask: var(--na-icon-alert) center / contain no-repeat;
  mask: var(--na-icon-alert) center / contain no-repeat;
}

:root {
  --na-icon-alert: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7v6'/%3E%3Cpath d='M12 16.5v.01'/%3E%3C/svg%3E");
}

/* ── Recovery link (moved beneath the password field) ───────── */

.na-field__recovery {
  display: flex;
  justify-content: flex-end;   /* flips automatically under [dir=rtl] */
  margin-top: 2px;
}

/* Was 11.5px, buried in a footer under the register CTA. Now 13.5px
   with a ~40px tall target, directly below the field it recovers. */
.na-recovery {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: 8px 6px;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--na-accent-deep);
  text-decoration: none;
  border-radius: 8px;
  transition: color 200ms var(--na-ease), background 200ms var(--na-ease);
}

.na-recovery:hover {
  color: var(--na-text-strong);
  text-decoration: underline;
}

/* ── "Back to Therapatic" (top bar) ─────────────────────────── */

.na-home {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 8px 10px;
  margin-inline-start: -10px;   /* keep the text optically aligned */
  border-radius: var(--na-radius-pill);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: none;
  color: var(--na-text-muted);
  text-decoration: none;
  transition: color 200ms var(--na-ease), background 200ms var(--na-ease);
}

.na-home:hover {
  color: var(--na-accent-deep);
  background: rgba(14, 165, 163, 0.08);
}

.na-home__icon {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
}

/* The arrow points back toward the start of the line, so it has to
   mirror along with the text direction. */
[dir="rtl"] .na-home__icon { transform: scaleX(-1); }

/* ── Utilities ──────────────────────────────────────────────── */

/* Visually hidden, still announced. Carries the "Signing in…"
   status without duplicating the text already visible on the
   button. */
.na-sr-only {
  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;
}

/* Replaces the former inline `style="margin-top:12px"` on the
   resend-verification form. */
.na-form--resend { margin-top: 12px; }

/* Register: "this address already has an account". The answer and
   its one way forward sit together above the form. The Sign in form
   posts the address to /oidc/login, so it reaches no URL
   (identity_oidc/register_existing.py). */
.na-existing { margin-bottom: 20px; }
.na-existing__form { margin-top: 12px; }

/* ── Login: mobile ──────────────────────────────────────────── */

@media (max-width: 600px) {
  /* The narrow-screen block above re-declares `.na-input` /
     `.na-button` box-shadows with tighter offsets, which would drop
     the boundary ring we just added. Re-assert it. */
  .na-body--aa .na-input {
    box-shadow:
      inset 0 0 0 1px var(--na-control-edge),
      inset 3px 3px 8px var(--na-shadow-dark),
      inset -2px -2px 6px var(--na-shadow-light);
  }
  .na-body--aa .na-input:focus,
  .na-body--aa .na-input:focus-visible {
    box-shadow:
      inset 0 0 0 1px var(--na-accent-deep),
      inset 3px 3px 8px var(--na-shadow-dark),
      inset -2px -2px 6px var(--na-shadow-light),
      0 0 0 2.5px var(--na-accent-deep);
  }
  .na-body--aa .na-input[aria-invalid="true"] {
    box-shadow:
      inset 0 0 0 1px var(--na-danger),
      inset 3px 3px 8px var(--na-shadow-dark),
      inset -2px -2px 6px var(--na-shadow-light);
  }
  .na-body--aa .na-button--primary {
    background: var(--na-accent-fill);
    color: #ffffff;
    box-shadow:
      -4px -4px 10px var(--na-shadow-light),
      6px 6px 14px var(--na-shadow-dark);
  }
  /* The top bar wraps at this width; keep the home link on its own
     line rather than letting it collide with the card. */
  .na-home { font-size: 12.5px; }
}

/* ── Arabic (RTL) typography ────────────────────────────────── */

/* Form controls do not inherit font-family: a <button> or <input> with no
   font rule of its own (the password eye toggle, row actions on the account
   pages) falls to the browser's control font, which has no Arabic face
   either. Zero specificity, so every class that does set a font — the mono
   OTP input included — still wins. RTL only: LTR pages are unchanged. */
:where([dir="rtl"]) :where(button, input, select, textarea) { font-family: inherit; }

/* letter-spacing breaks Arabic cursive joining: tracked Arabic renders as
   disconnected letters. Every tracked rule in this file is reset on an RTL
   document; the [dir="rtl"] prefix adds one attribute, so each reset
   out-ranks the rule it undoes whatever the order. LTR rules are untouched.

   Deliberately NOT reset: .na-input--otp and .na-input--mono. They only ever
   hold digits or a Latin code, and the tracking is what makes a six-digit
   code readable. tests/typography/test_arabic_css_rules.py holds the list. */
[dir="rtl"] .na-topbar,
[dir="rtl"] .na-card__title,
[dir="rtl"] .na-label,
[dir="rtl"] .na-divider,
[dir="rtl"] .na-button,
[dir="rtl"] .na-caps-lock,
[dir="rtl"] .na-pill,
[dir="rtl"] .na-trust__item,
[dir="rtl"] .na-legal,
[dir="rtl"] .na-lang,
[dir="rtl"] .na-home {
  letter-spacing: normal;
}

/* ── Error family frame (404 / 500 / dead links) ────────────── */

/* journey_shell.py draws the whole family in the auth shell under
   `.na-body--error`. What the shell does for a sign-in form is not right for
   these pages, and each rule below corrects one thing:

     * the shell's card breathes forever (na-breath, infinite). These pages
       settle once and stay settled, still well inside 6.5 s (WCAG 2.2.2);
       the entrance stays. Reduced motion keeps the shell's `animation: none`;
     * the shell always writes the trust-badge row and a closing footer, both
       empty here, and their margins left 46px of blank card under the last
       line. A browser without `:has()` keeps that spacing, nothing worse;
     * the way back ("Back to sign in") is a real target: 44px, 48px on
       phones, like .na-recovery on the sign-in page. The negative margin
       gives the taller box's height back, so no line moves. It stands alone
       in its footer, so the .na-link margin meant for a link that follows a
       sentence would push it off centre;
     * Cairo's "normal" line height is about 1.9, which spaces a two-line
       Arabic title like two paragraphs;
     * the 404 / 500 message wraps "pretty", like the leads of the expired
       pages: left to the default it ends on one word alone ("دقائق." under
       a full line at 1440 in Arabic, "minutes." at 320 in English). */
@media (prefers-reduced-motion: no-preference) {
  .na-body--error .na-card { animation: na-enter 480ms var(--na-ease) both; }
}

.na-body--error .na-trust:not(:has(*)),
.na-body--error .na-card__footer:not(:has(*)) { display: none; }

.na-body--error .na-card__footer .na-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  margin-block: -14px;
  margin-inline: 0;
  padding: 0 12px;
  border-radius: 10px;
}

@media (max-width: 600px) {
  .na-body--error .na-card__footer .na-link {
    min-height: 48px;
    margin-block: -16px;
  }
}

[dir="rtl"] .na-body--error .na-card__title { line-height: 1.35; }

.na-body--error .na-alert { text-wrap: pretty; }

/* ── Error pages (404 / 500) ────────────────────────────────── */

/* The vignette error_art.py draws above the message: the web app's 404
   picture, in this service's palette. The real Therapatic figure on a
   path of small steps — solid stones were walked, dashed ones are not on
   the map, and the lit house is the way back. Presentation attributes
   and these rules only: the CSP is style-src 'self'. The brand figure's
   light colours are the ones logo.svg and the web app's .logo use. */
.na-body--error {
  --na-logo-body: #108abd;
  --na-logo-head: #1c4052;
}

.na-error-art {
  display: block;
  width: 100%;
  max-width: 280px;
  height: auto;
  margin: 0 auto 16px;
  overflow: visible;
}

/* RTL mirrors the path so home is on the reading-start side — but never
   the brand figure, which is counter-flipped back. */
[dir="rtl"] .na-error-art__world { transform: matrix(-1, 0, 0, 1, 280, 0); }

[dir="rtl"] .na-error-art__figure {
  transform-box: fill-box;
  transform-origin: center;
  transform: scaleX(-1);
}

.na-error-art__ground { fill: var(--na-accent-soft); }
.na-error-art__stone { fill: var(--na-shadow-dark); }
.na-error-art__here { fill: var(--na-accent-soft); }

.na-error-art__ghost {
  fill: none;
  stroke: var(--na-text-subtle);
  stroke-width: 1.2;
  stroke-dasharray: 3 3;
}

/* The step that is not on the map. */
.na-error-art__ring {
  fill: var(--na-accent-glow);
  stroke: var(--na-accent);
  stroke-width: 2;
  stroke-dasharray: 7 6;
  stroke-linecap: round;
}

.na-error-art__way-back {
  fill: none;
  stroke: var(--na-accent);
  stroke-width: 3;
  stroke-dasharray: 0.1 7;
  stroke-linecap: round;
}

/* Mask luminance (white reveals), not a colour on screen. */
.na-error-art__reveal {
  fill: none;
  stroke: #fff;
  stroke-width: 12;
  stroke-linecap: round;
  stroke-dasharray: 1 1;
  stroke-dashoffset: 0;
}

.na-error-art__house {
  fill: var(--na-shadow-dark);
  stroke: var(--na-shadow-dark);
  stroke-width: 3;
  stroke-linejoin: round;
}

.na-error-art__house--lit {
  fill: var(--na-accent-fill);
  stroke: var(--na-accent-fill);
}

.na-error-art__door { fill: var(--na-warning); }

/* 404 only: the way back draws itself once, then the house lights up.
   The rules above are the final frame, so reduced motion sees it drawn
   and lit; the 500 page never moves. */
@media (prefers-reduced-motion: no-preference) {
  .na-error-art--not-found .na-error-art__reveal {
    animation: na-error-draw 1.2s cubic-bezier(0.45, 0, 0.3, 1) 0.4s both;
  }

  .na-error-art--not-found .na-error-art__house--lit,
  .na-error-art--not-found .na-error-art__door {
    animation: na-error-light 0.5s ease-out 1.5s both;
  }
}

@keyframes na-error-draw { from { stroke-dashoffset: 1; } }
@keyframes na-error-light { from { opacity: 0; } }

/* ── Expired links & stale forms (the hourglass) ───────────── */

/* expired_pages.py draws these: the 404's path, with an hourglass standing
   on the way ahead of the figure. Run out (EXPIRED_ART) for a dead link, a
   stale form or a sign-in step that timed out; turned over, with the fresh
   link waiting at home's door (SENT_ART), once a new one has been sent. Same
   rules as the block above: presentation only, CSP style-src 'self', light
   theme like the rest of the IdP, and the resting state is the final frame,
   so reduced motion sees the finished picture. */
.na-error-art__glass-plate { fill: var(--na-accent-soft); }

.na-error-art__glass-bulb {
  fill: rgba(255, 255, 255, 0.35);
  stroke: var(--na-text-subtle);
  stroke-width: 1.2;
  stroke-linejoin: round;
}

.na-error-art__glass-sand { fill: var(--na-warning); opacity: 0.8; }

.na-error-art__glass-stream {
  fill: none;
  stroke: var(--na-warning);
  stroke-width: 1;
  stroke-linecap: round;
  opacity: 0.8;
}

/* Run out: the last grains have already fallen at rest. */
.na-error-art__glass-stream--last { opacity: 0; }

/* The fresh link at home's door. An envelope is not text, but it is
   counter-flipped like the figure so the mirrored world never draws it
   backwards. */
[dir="rtl"] .na-error-art__letter-flip {
  transform-box: fill-box;
  transform-origin: center;
  transform: scaleX(-1);
}

.na-error-art__letter-body {
  fill: #fff;
  stroke: var(--na-accent-deep);
  stroke-width: 1.3;
}

.na-error-art__letter-flap {
  fill: none;
  stroke: var(--na-accent-deep);
  stroke-width: 1.3;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Expired: the last grains fall, then the way back draws. Sent: the letter
   walks home along the path, then the house lights. Each runs once and is
   still within 2.5 s. */
@media (prefers-reduced-motion: no-preference) {
  .na-error-art--expired .na-error-art__glass-stream--last {
    animation: na-error-last-grains 1.3s ease-out 0.2s both;
  }

  .na-error-art--expired .na-error-art__reveal {
    animation: na-error-draw 1.2s cubic-bezier(0.45, 0, 0.3, 1) 1.2s both;
  }

  .na-error-art--sent .na-error-art__letter {
    animation: na-error-deliver 1.6s cubic-bezier(0.45, 0, 0.3, 1) 0.3s both;
  }

  .na-error-art--sent .na-error-art__house--lit {
    animation: na-error-light 0.5s ease-out 1.8s both;
  }
}

@keyframes na-error-last-grains {
  0%, 70% { opacity: 0.8; }
  100% { opacity: 0; }
}

@keyframes na-error-deliver {
  0% { transform: translate(140px, 22px); opacity: 0; }
  15% { opacity: 1; }
  100% { transform: none; opacity: 1; }
}

/* ── The page's own words ── */

/* The longer titles of this family (the Arabic "confirmation link" one wraps
   at every width) break into even lines instead of leaving one word alone on
   the second. Scoped to the error family: other pages keep their titles. */
.na-body--error .na-card__title { text-wrap: balance; }

.na-journey__lead {
  margin: 0 0 18px;
  color: var(--na-text);
  font-size: 15px;
  line-height: 1.6;
  text-align: center;
  text-wrap: pretty;
}

[dir="rtl"] .na-journey__lead { line-height: 1.85; }

.na-journey__form { margin: 0; }

/* An <a> styled as .na-button: the IdP's button is width:100%, but an anchor
   is inline, so it needs a block-level display to take that width. */
.na-journey__fresh {
  display: flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
}

.na-journey__note {
  margin: 12px 0 0;
  color: var(--na-text-muted);
  font-size: 13px;
  line-height: 1.55;
  text-align: center;
  text-wrap: pretty;
}

/* ── The 500's way forward and its support reference ── */

/* error_pages.py puts "Try again" under the message and, when the request
   carries one of our ids, the reference a reader quotes to support. The id
   is Latin whatever the page language (a <bdi dir="ltr">), selectable in
   one go, and wraps rather than widening the card on a phone. */
.na-body--error .na-alert + .na-journey__fresh { margin-top: 18px; }

.na-error-reference {
  margin: 16px 0 0;
  color: var(--na-text-muted);
  font-size: 13px;
  line-height: 1.55;
  text-align: center;
}

.na-error-reference__id {
  display: inline-block;
  margin-inline-start: 4px;
  padding: 2px 8px;
  border-radius: var(--na-radius-pill);
  background: var(--na-surface-recess);
  color: var(--na-text);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  overflow-wrap: anywhere;
  user-select: all;
}

.na-error-reference + .na-journey__note { margin-top: 4px; }
