/* ============================================================================
   auth.css, Layer 7: the registration & login pages (page-scoped; loaded by
   pages/register.html + pages/login.html via block page_css).
   Tokens only; logical properties only; same laws as the system sheets,
   swept by the suite like base/components/landing (tests/test_layer6.py).

   The registration is a TRUE multi-step Duolingo-cadence onboarding (evolving the
   Claude Design Export's RegisterStepped pattern for the platform): ONE
   decision-or-tight-group per screen. The .stepflow chrome is a top progress bar
   (FILLS per step) + a back chevron + an n/total count; each step is a
   .rishiguide speech-bubble over a .step-fields task card; a sticky .stepflow-foot
   CONTINUE sits in thumb reach; steps slide forward/back via .pagetransition. The
   onboarding-flow vocabulary (.type-cards, .reg-welcome*, .btn-quiet,
   .reg-success*, .rishiguide, .pagetransition, .step-fields, .stepflow-foot) lives
   here, the only sheet the register page loads. The /login card is ONE clean
   .auth-card panel (the double-box fix: a single surface treatment, not stacked
   .auth-card + .grad-border). Tokens + logical properties throughout.
   ========================================================================== */

/* ---- the band: joining IS the hero act, so it wears the hero atmosphere ---- */
.auth-section {
  /* the shared lit ground (--bg-hero-lit): --bg-hero + a gold top-glow. Register + login share
     it; the landing hero rides the SAME ground via --bg-hero-landing (= this base + the settle
     band; user call). */
  background: var(--bg-hero-lit);
  color: var(--white);
  /* the end padding MIRRORS the top bar-regrow (the bleed's --topbar-h transparent border sits
     inside this box), so the safe-center content box below is exactly the VISIBLE screen and the
     cluster centers on it; without the mirror it centered on (screen + bar)/2 and sat one
     half-bar too low (user-caught). */
  padding-block: var(--space-6) calc(var(--space-6) + var(--topbar-h));
  /* THE GROUND FILLS THE SCREEN (user call, the landing hero-floor law applied to
     the funnel): a FLOOR, so content-heavy steps still grow past it; svh, never vh; the
     under-glass bleed (components.css) makes border-box span the bar, so one screen ends exactly
     at the fold and re-resolves at every viewport. Every HTMX sub-step swaps INSIDE this
     section, so the floor covers the whole funnel by construction. */
  min-block-size: 100svh;
  /* the content CENTERS in the screen-tall band (the landing cluster's grammar): `safe` center,
     never plain: a step taller than the screen (long register steps, a11y text scale) degrades
     to top-flow instead of clipping its own head behind the sticky bar. */
  display: grid;
  align-content: safe center;
}

/* the REGISTER cluster rides a step ABOVE geometric center (user call: its card-heavy bottom
   half reads low when dead-centered; the extra end padding biases the optical center up). Login
   keeps the plain mirror: its compact card already reads centered. */
.auth-section:not(.auth-section-login) {
  padding-block-end: calc(var(--space-6) + var(--topbar-h) + var(--space-7));
}

.auth-head {
  text-align: center;
  margin-block-end: var(--space-5);
}

/* the picker's title + subtitle (register step 0 only: they ride INSIDE the swapped #reg-flow now,
   so they disappear on every input step). Centered; the .auth-sub carries its own top gap, and the
   .pagetransition grid spaces it from the Rishi welcome below. */
.reg-pick-head {
  text-align: center;
}

/* THE PICKER'S OWN TYPE SCALE (operator calls: bigger, and dynamic on EVERY
   device including phones). Everything here was flat or floor-pinned: the subline sat at
   20px from 320 to 1920, and a px-floored clamp re-flattened the whole set below ~390, so a
   320 and a 390 phone rendered identically. Two corrections:
     · the TITLE is derived from the COLUMN, not from a viewport ramp — the picker column is
       min(680px, 100vw - 2 * --container-pad) and the string measures 5.79x its font-size
       (clone-measured), so column/7.4 paints ~78% of the column at EVERY width: 37px on a
       320 phone, 46 at 390, 76 at 640, 92 once the column caps (a full column-width title
       read too big, operator-caught). It cannot plateau early because the column is the only
       thing that plateaus, and at 78% it can never overflow.
     · every supporting line is rem + vw with a floor BELOW its 320px value, so the ramp is
       live on the smallest phone instead of sitting on its floor. */
.reg-phase-type {
  --reg-col: min(680px, 100vw - var(--container-pad) * 2);
}

.reg-pick-head .auth-title {
  font-size: calc(var(--reg-col) / 7.4);
}

.reg-pick-head .auth-sub {
  font-size: clamp(0.875rem, 1rem + 0.625vw, 1.5625rem);
}

.auth-title {
  font-size: var(--text-display);
  font-weight: var(--w-display);
  line-height: var(--leading-tight);
}

.auth-sub {
  margin-block-start: var(--space-3);
  font-size: var(--text-h3);
  font-weight: var(--w-medium);
  line-height: var(--leading-loose);
}

/* /login now SHARES the register background (the user's call: copy the register bg to login): it
   inherits .auth-section's gold top-glow + --bg-hero (no gold-veil override). Rishi greets INSIDE the
   card as a chat guide (.login-guide below); the frosted-glass card floats over the shared ground. */

/* the sign-in greeting hierarchy (the user's call): the welcome line QUIETS to a small heading and
   the brand PROMISE becomes the gradient HERO below it. Scoped to login (the register keeps its own). */
/* Both lines were FLAT tokens (measured: 20px and 32px at every width from 320 to 1920), so
   the greeting never grew with the device. They now ramp on the §13 continuous schedule
   (operator call), and the recorded hierarchy is preserved BY CONSTRUCTION: the
   welcome caps at 38px, under the promise's 43px, so the gradient line stays the hero. */
.auth-section-login .auth-title {
  /* 28 → 38 (was a flat 20): significantly bigger on EVERY device, the phone included.
     The string measures 5.84x its size, so even at 28px it needs 164px of the 272px rail a
     320px phone gives it. */
  font-size: clamp(28px, 24.29px + 0.952vw, 38px);
  font-weight: var(--w-heading);
}
.auth-section-login .auth-sub {
  /* THE PROMISE IS SIZED FROM THE CARD ITSELF, at every width (operator call):
     a viewport RAMP could only meet the card at the one width it was tuned for and ran 72px
     short at 1024 (measured), so the size is DERIVED from the card's own expression instead —
     the card is `min(460px, 100vw - 2 * --container-pad)` (its max-inline-size inside the
     shared container), and the rendered line measures 10.9x its font-size (range-measured on
     the real render; a max-content clone reads 10.35 and overshoots). Dividing the one by the
     other makes the line track the card BY CONSTRUCTION at every viewport, with 11 as the
     divisor so the ~1% tolerance keeps a font-metric drift from folding a second line.
     The 32px floor holds the phones, where the card is too narrow to host one line at all
     and the copy wraps exactly as it does today. */
  font-size: max(32px, calc(min(460px, 100vw - var(--container-pad) * 2) / 11));
  font-weight: var(--w-display);
  line-height: var(--leading-tight);
  background: var(--grad-gold);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* the in-FORM Rishi CHAT guide (top of the sign-in card): Rishi on the inline-start, his speech
   bubble beside him; both REACT to the mode (loginCard inPassword / inSms / inReset). A real
   chat moment: the LIQUID-GLASS bubble (the shared cue stack below, one recipe with the
   register guide), Rishi leaning into it. */
.login-guide {
  display: flex;
  align-items: center;
  gap: 0;
  margin-block-end: var(--space-4);
}
.login-guide-rishi {
  flex: none;
  position: relative;
  z-index: 1;
}
.login-guide-rishi::before {
  content: "";
  position: absolute;
  inset: -10%;
  z-index: -1;
  background: var(--halo-gold);
}
.login-guide-rishi img {
  display: block;
  inline-size: 88px;
  block-size: 88px;
}
.login-guide-bubble {
  flex: 1;
  min-inline-size: 0;
  margin: 0;
  margin-inline-start: -14px; /* the lean: Rishi (z-index 1) overlaps the bubble's near edge
     (this guide already ran inline-start-first, so only its pose needed the mirror) */
  padding: var(--space-3) var(--space-4);
  border-radius: var(--r-lg);
  color: var(--white);
  font-size: var(--text-body);
  font-weight: var(--w-medium);
  line-height: var(--leading);
  text-wrap: pretty;
  /* look = the shared PRESENT-GLASS cue stack below (film + hairline rim + specular);
     ringless by construction: a gold border-box sheet under a translucent film bleeds. */
}

.auth-body {
  max-inline-size: 760px;
}

/* ============================================================================
   THE STEPFLOW CHROME, the registration region #reg-flow carries .stepflow: a
   head (back chevron + a per-step progress bar + an n/total count) over a body
   that holds the steps. The bar/count/back are CLIENT state advanced by
   registerForm.paintProgress (the five numbered steps fill the bar; the picker is
   step 0, a server screen before the component mounts).

   DESKTOP (≥768px): the stepped flow centers in a FOCUSED column (not the 760px
   picker width, and never a stretched mobile layout): one task reads calm and
   premium, the Duolingo/Revolut single-decision rhythm. The picker's 3 type-cards
   keep the wider grid (they are a row, not a single field).
   ========================================================================== */
/* THE ENTRANCE SWEEP (app.js regEntrance, the ONE owner; see its "THE SWEEP"
   header): where a type pick starts with no scroll to spend (business, and every
   desktop pick: the picker's cards sit in one visible row), the entrance's
   missing travel is a compositor-only translate the director drives to 0 on the
   SAME quartic clock as the scroll glide. The sheet owns the recipe, the
   director owns only the distance (--reg-sweep, negative = above its rest).
   transition-property narrows base.css's .htmx-settling transition to opacity;
   its transform transition would otherwise smear every tween frame. The class is
   never added under reduced motion / a11y-motion (the director's motionless()),
   so that posture needs no override here. */
.reg-flow.is-sweeping {
  transform: translateY(var(--reg-sweep, 0px));
  transition-property: opacity;
  will-change: transform;
}

.stepflow {
  display: grid;
  /* ONE inter-block rhythm (the user's call, the flow read sparse and
     UNEQUAL: 32/40/40/66 gaps): every stacked block gaps space-4; the head cluster
     is tighter (space-3) and the card pads space-5, §13 one-token-per-run */
  gap: var(--space-4);
}

/* the focused desktop column for the stepped content (the form steps, the code
   step, the success beat); the picker grid opts out below. */
@media (min-width: 768px) {
  .reg-form,
  .reg-phase-code,
  .reg-success {
    max-inline-size: 560px;
    margin-inline: auto;
    inline-size: 100%;
  }
}

.stepflow-head {
  display: grid;
  gap: var(--space-3);   /* the chrome cluster is one tight unit (bar · strip) */
  /* extra air UNDER the steps (the owner's call): the flow's
     space-4 gap alone sat the guide too close to the strip */
  margin-block-end: var(--space-4);
}

/* the step panels are .pagetransition grids (a 40px chrome default, defined LATER
   in this sheet; the two-class scope outranks it): inside the stepped flow they
   join the one 24px rhythm (guide → card → foot) */
.stepflow .reg-step,
.stepflow .reg-phase-code {
  gap: var(--space-4);
}

.stepflow-topbar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.stepflow-back {
  display: grid;
  place-items: center;
  inline-size: 40px;
  block-size: 40px;
  flex-shrink: 0;
  border: none;
  background: none;
  color: var(--gold-bright);
  border-radius: var(--r-full);
  cursor: pointer;
  transition: transform var(--motion-press) var(--ease-standard);
}

/* the `arrow` glyph points forward (→); mirror it to point BACK (the .profile-back
   convention): in the RTL flow "back" is visually rightward, the glyph handles it */
.stepflow-back svg {
  inline-size: 24px;
  block-size: 24px;
  transform: scaleX(-1);
}

.stepflow-back:active {
  transform: scale(0.9);
}

/* disabled (phase 1) / the no-type placeholder: present for layout, invisible +
   inert, so the progress bar keeps its position on every phase */
.stepflow-back[disabled],
.stepflow-back[aria-hidden="true"] {
  opacity: 0;
  pointer-events: none;
}

/* the progress TRACK is liquid glass (the gold fill rides above, clipped by
   the pill); rims only: a 10px strip carries no float */
.stepflow-progress {
  flex: 1;
  block-size: 10px;
  border-radius: var(--r-full);
  background: var(--build-pod-film);
  -webkit-backdrop-filter: blur(14px) saturate(1.5);
  backdrop-filter: var(--glass-nav-blur);
  overflow: hidden;
}

.stepflow-progress-fill {
  display: block;
  block-size: 100%;
  border-radius: var(--r-full);
  background: var(--grad-gold-fill);
  /* R2 (DESIGN.md §10 endowed progress, never an empty bar): step 1 reads as a head start; the
     registerForm.paintProgress getter still overrides --p per phase. */
  inline-size: var(--p, 8%);
  /* R1: the fill SPRINGS forward each phase (snaps, not glides) + reads as lit metal. */
  box-shadow: var(--edge-light);
  transition: inline-size var(--motion-reveal) var(--ease-spring);
}

.stepflow-count {
  font-size: var(--text-caption);
  font-weight: var(--w-heading);
  color: var(--slate-on-dark);
  font-variant-numeric: tabular-nums;
  direction: ltr;
  min-inline-size: 4ch;
  text-align: center;
}

/* ---- THE GOAL-GRADIENT STEP STRIP (lawsofux goal-gradient, DESIGN §10): the five
   numbered steps as pictogram discs under the bar: done = gold-fill + check (a
   one-shot POP at the flip moment), current = the ringed gold focal point, future
   = dimmed waiting. A done disc is a BUTTON (the jump-back door). RTL: the first
   step sits at the inline-start (right) and the goal at the left; progress moves
   with the reading direction. ---- */
.stepstrip {
  display: flex;
  justify-content: center;
  align-items: start;
  gap: clamp(4px, 2.2vw, var(--space-3));
  margin: 0;             /* the head grid gap owns the rhythm */
}
.stepstrip-node {
  display: grid;
  justify-items: center;
  gap: 4px;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  cursor: default;
  inline-size: clamp(46px, 13vw, 64px);
  min-inline-size: 0;
}
.stepstrip-node:not(:disabled) { cursor: pointer; }
/* the RESTING disc is LIQUID GLASS (the owner's call, the flow's
   one film + lens + lensing rims over the hero ground); the CURRENT and DONE
   states below keep their opaque gold composites: the strong states stay. */
.stepstrip-disc {
  position: relative;
  display: grid;
  place-items: center;
  inline-size: clamp(38px, 10.5vw, 48px);
  block-size: clamp(38px, 10.5vw, 48px);
  border-radius: var(--r-full);
  border: 2px solid transparent;
  background: var(--build-pod-film);
  -webkit-backdrop-filter: blur(14px) saturate(1.5);
  backdrop-filter: var(--glass-nav-blur);
  transition: box-shadow var(--motion-bloom) var(--ease-bloom);
}
.stepstrip-picto {
  display: grid;
  place-items: center;
  inline-size: 74%;
  block-size: 74%;
  opacity: 0.45;
  filter: grayscale(0.6);
  transition: opacity var(--motion-state) var(--ease-standard),
              filter var(--motion-state) var(--ease-standard),
              transform var(--motion-state) var(--ease-standard);
}
.stepstrip-picto .picto { display: block; inline-size: 100%; block-size: 100%; }
.stepstrip-check {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: var(--on-accent);
  opacity: 0;
  transform: scale(0.4);
  transition: opacity var(--motion-micro) var(--ease-standard),
              transform var(--motion-state) var(--ease-spring);
}
.stepstrip-check svg { inline-size: 46%; block-size: 46%; }
.stepstrip-name {
  font-size: 11px;
  color: var(--slate-on-dark);
  white-space: nowrap;
  transition: color var(--motion-state) var(--ease-standard);
}
/* CURRENT: the one lit focal point (ADHD: attention lands exactly here) */
.stepstrip-node.is-current .stepstrip-disc {
  background:
    linear-gradient(var(--navy-2), var(--navy-2)) padding-box,
    var(--grad-gold) border-box;
  box-shadow: var(--glow-gold);
}
.stepstrip-node.is-current .stepstrip-picto { opacity: 1; filter: none; }
.stepstrip-node.is-current .stepstrip-name {
  color: var(--gold-bright);
  font-weight: var(--w-heading);
}
/* DONE: the pictogram hands over to the gold check (the reference grammar) */
.stepstrip-node.is-done .stepstrip-disc {
  background:
    var(--grad-gold-fill) padding-box,
    var(--grad-gold) border-box;
  box-shadow: var(--edge-light);
}
.stepstrip-node.is-done .stepstrip-picto { opacity: 0; transform: scale(0.5); }
.stepstrip-node.is-done .stepstrip-check { opacity: 1; transform: scale(1); }
.stepstrip-node.is-done .stepstrip-name { color: var(--white); }
.stepstrip-node.is-done:not(:disabled):hover .stepstrip-disc { box-shadow: var(--glow-gold); }
.stepstrip-node:focus-visible { outline: none; }
/* the keyboard ring is the ONLY focus indicator here (the node kills its outline), so it
   keeps the instant state beat while the hover glow rides the bloom envelope */
.stepstrip-node:focus-visible .stepstrip-disc {
  box-shadow: var(--focus-ring-lit);
  transition-duration: var(--motion-state);
}
/* the completion POP: the Tier-1 micro-beat replayed exactly at the flip moment
   (token-timed; the reduced-motion kill switch collapses it) */
.stepstrip-disc.is-popping {
  animation: stepstrip-pop var(--motion-reveal) var(--ease-spring);
}
@keyframes stepstrip-pop {
  0% { transform: scale(1); }
  45% { transform: scale(1.22); box-shadow: var(--glow-celebrate); }
  100% { transform: scale(1); }
}
/* the finale closure: the whole strip settles gold under the confetti beat (the
   celebration itself stays the sanctioned registration finale, §8) */
.stepstrip.is-complete .stepstrip-disc {
  box-shadow: var(--edge-light), var(--glow-gold);
}
/* the narrowest phones: five nodes must share ~272px of content box (live-measured
   at 320: the clamp floor alone overflowed 24px), so the whole scale steps down */
@media (max-width: 359px) {
  .stepstrip { gap: 2px; }
  .stepstrip-node { inline-size: 42px; }
  .stepstrip-disc { inline-size: 34px; block-size: 34px; }
  .stepstrip-name { font-size: 10px; }
}

/* the body is the spacing spine: the welcome/guide + the form card + the success
   beat each occupy it as one .pagetransition; the gap reaches the wrappers */
.stepflow-body {
  display: grid;
  align-content: start;
  gap: var(--space-4);
}

/* ---- the per-step task card (ONE decision per screen, the Duolingo cadence).
   Each step's fields sit in a .step-fields panel: the gradient-ring card surface
   (the brand panel, DESIGN.md §4), generously padded so the one task breathes.
   The card is the SAME for the details steps + the code step (.reg-code) so the
   flow reads as one consistent surface advancing. ---- */
.step-fields {
  display: grid;
  gap: var(--space-4);
  margin: 0;
  padding: var(--space-5) var(--space-4);
  border: 2px solid transparent;
  border-radius: var(--r-lg);
  background:
    linear-gradient(var(--navy-2), var(--navy-2)) padding-box,
    var(--grad-gold) border-box;
}

@media (min-width: 640px) {
  .step-fields {
    padding: var(--space-5);
  }
}

/* the step's title: the ONE thing this screen asks for (COGA orientation: a
   clear single subject). The Rishi bubble carries the warm prompt; this is the
   crisp label. */
.step-title {
  margin: 0;
  font-size: var(--text-h2);
  font-weight: var(--w-heading);
  color: var(--gold-bright);
  line-height: var(--leading-heading);
}

/* the sticky CONTINUE foot (thumb reach on mobile, the Duolingo/Revolut sticky
   key): full-width, sits below the step card with the body's rhythm. The button
   itself is .btn-primary (the chunky gold key); .reg-submit makes it full-width.
   On desktop it stays in the comfortable max-width column (the body caps width),
   so it never stretches awkwardly. */
.stepflow-foot {
  display: grid;
  /* the form's own space-4 gap IS the button's separation (the one-rhythm
     pass: the extra margin made the run read unequal; supersedes the earlier
     generous-gap call) */
  margin-block-start: 0;
}

/* ============================================================================
   THE BUILD-YOUR-PROFILE STEP (the ownership rebuild): step 1 is a
   live PREVIEW CARD the member edits in place (the Airbnb "how does this look?"
   grammar on the brand's lit navy): the typed name / picked field / chosen
   areas mirror into the card head, so joining reads as BUILDING your own
   dashboard, not filling a form. The sun/moon THEME PICK is an explicit playful
   pair riding the same ONE theme mechanism (applyThemeChoice) as the shared
   toggle key.
   THE LIQUID-GLASS CARD (the engagement pass): the preview head is
   a frosted pane over an UNDER-GLASS AURORA that gathers light as the card
   fills: registerForm.syncBuiltGlow steps [data-built] 0→3 (name · field ·
   areas), each landing a Tier-1 micro-win (pulse + haptic). The aurora lives
   INSIDE the step card's ring (absolute inset:0 = the padding box, so the gold
   border stays crisp); the direct children lift above it (a positioned ::before
   otherwise paints over in-flow content).
   ========================================================================== */
.reg-build {
  position: relative;
}

.reg-build::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: calc(var(--r-lg) - 2px);
  pointer-events: none;
  /* the FIRST COMMIT's exact pools (bd8a0c20, the owner's reference: their
     %-sized radii carry the long soft falloff down the card); ONLY the rest
     opacity differs: 0.6 (0.3 read as absent, 0.8 as loud), climbing to 1 */
  /* the THEMED aurora paint (tokens.css --build-aurora): the dark arm holds
     the first commit's exact pools; the beige arm the iridescent gold field */
  background: var(--build-aurora);
  opacity: 0.6;
  transition: opacity var(--motion-reveal) var(--ease-standard);
}

.reg-build[data-built="1"]::before { opacity: 0.75; }
.reg-build[data-built="2"]::before { opacity: 0.88; }
.reg-build[data-built="3"]::before { opacity: 1; }

.reg-build > * {
  position: relative;
}

.reg-build-toprow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

/* the theme pick, a compact segmented pair on the card's title row: the ACTIVE
   theme wears the gold fill (the pressed-key read), the other waits quiet.
   LIQUID GLASS (the owner's call): the badges' own film + lens over
   the aurora, legal here (the pick sits OUTSIDE the head's pane, so this is
   the stack's one lens), with the canonical lensing rims + small float. */
.theme-pick {
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  border-radius: var(--r-full);
  background: var(--build-pod-film);
  -webkit-backdrop-filter: blur(14px) saturate(1.5);
  backdrop-filter: var(--glass-nav-blur);
  box-shadow: var(--glass-edge), inset 0 -1px 0 var(--mix-white-12), var(--glass-shadow-sm);
  transform: translateZ(0);  /* own compositor layer, the smooth-scroll law */
}

.theme-pick-opt {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-block-size: 44px;   /* the §10 tap floor */
  padding: 4px 16px;
  border: 0;
  border-radius: var(--r-full);
  background: none;
  color: var(--slate-on-dark-bright);
  font-size: var(--text-caption);
  font-weight: var(--w-medium);
  cursor: pointer;
  transition:
    background var(--motion-state) var(--ease-standard),
    color var(--motion-state) var(--ease-standard),
    transform var(--motion-press) var(--ease-standard);
}

.theme-pick-opt:active {
  transform: scale(0.95);
}

.theme-pick-opt:not([aria-pressed="true"]):hover {
  color: var(--white);
  background: var(--state-hover);
}

.theme-pick-opt:focus-visible {
  box-shadow: var(--focus-ring-lit);
}

.theme-pick-opt[aria-pressed="true"] {
  color: var(--navy);
  font-weight: var(--w-heading);
  background: var(--grad-gold-fill);
  box-shadow: var(--edge-light);
}

.theme-pick-glyph {
  display: grid;
  place-items: center;
}

.theme-pick-glyph svg {
  inline-size: 18px;
  block-size: 18px;
  display: block;
}

/* the live preview HEAD, the member's future identity card in miniature, now
   LIQUID GLASS: the app's ONE recipe (--glass-nav-grad tint + --glass-nav-blur
   backdrop, the nav pane / dashboard meta twins) over the .reg-build aurora,
   with the diagonal sheen + lit top edge selling the pane and a small float
   seating it. The gold hairline ring stays: it is still THEIR identity card. */
.reg-build-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4);
  border-radius: var(--r);
  border: 1.5px solid transparent;
  /* the head's films ride the themed token (dark: sheen + nav tint exactly as
     shipped; beige: a whisper white film so the iridescent field pours
     through the lens) over the platform gold ring */
  background:
    var(--build-head-glass),
    var(--build-head-ring) border-box;
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: var(--build-head-lens);
  box-shadow: var(--glass-edge), var(--glass-shadow-sm);
  transform: translateZ(0);  /* own compositor layer, the smooth-scroll law */
}

/* no backdrop support → the raised lit card (the .auth-card-login fallback
   grammar): the aurora still glows behind, only the lens is lost */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .reg-build-head {
    background:
      var(--grad-lit-card-raised) padding-box,
      var(--grad-gold) border-box;
  }
}

/* the avatar seat: the gold initial disc (the profile empty-state grammar),
   the quiet profile glyph until the first typed letter takes its place */
.reg-build-avatar {
  position: relative;
  display: grid;
  place-items: center;
  inline-size: 60px;
  block-size: 60px;
  flex-shrink: 0;
  border-radius: var(--r-full);
  background: var(--grad-gold-fill);
  box-shadow: var(--edge-light);
  color: var(--navy);
  transition: box-shadow var(--motion-state) var(--ease-standard);
}

/* the first typed letter lights the disc: the card coming alive reads in the
   avatar too (the same is-live flip paintBuildPreview drives on the name) */
.reg-build-avatar.is-live {
  box-shadow: var(--edge-light), var(--glow-gold);
}

.reg-build-avatar > svg {
  inline-size: 28px;
  block-size: 28px;
  color: color-mix(in srgb, var(--navy) 55%, transparent);
  transition: opacity var(--motion-state) var(--ease-standard);
}

.reg-build-avatar.is-live > svg {
  opacity: 0;
}

.reg-build-initial {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: var(--text-h2);
  font-weight: var(--w-display);
}

.reg-build-id {
  display: grid;
  gap: 8px;             /* the elevated pods need their own breath under the name */
  min-inline-size: 0;   /* the §13 flex clamp: a long name wraps, never overflows */
}

/* the name line: a shade quieter while it still shows the placeholder, WHITE
   the moment the member's own name lands (the is-live flip, their card coming
   alive). The bright alias keeps the resting text legible over the aurora-lit
   glass in BOTH themes (the visibility raise: the muted slate
   washed out on the brightened pane). */
.reg-build-name {
  font-size: var(--text-h3);
  font-weight: var(--w-heading);
  line-height: var(--leading-heading);
  color: var(--slate-on-dark-bright);
  overflow-wrap: break-word;
  transition: color var(--motion-state) var(--ease-standard);
}

.reg-build-name.is-live {
  /* the TYPED name wears the app's gradient ink (the owner's call, goldish
     on dark, brownish on light: --grad-gold auto-themes); the recipe mirrors
     base.css .text-grad (the canonical gradient-ink home: a class can't
     ride the is-live flip without JS, so the four lines repeat HERE only) */
  background: var(--grad-gold);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.reg-build-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

/* THE FACT PODS (the liquid pass, Mobbin-checked against the iOS
   Liquid Glass chip grammar): TRUE transparent glass is the LENS WITHOUT THE
   PAINT, the components.css transparent-topbar lesson, and exactly what the
   iOS references show: a glass pill is a WHISPER white-mix film taking the
   backdrop's OWN hue, never a colored tint (--glass-nav-grad here read as a
   blue/gray band over the navy card, the same documented failure). So: the
   ONE THEMED --build-pod-film token, the same seat for rest and live (a
   mismatched resting fill "looks odd", the owner's call; --state-hover was
   tried and its beige INK film re-made the tan pill)
   + pure LENSING rims + the small float.
   ONE LENS PER STACK: the pods carry NO backdrop-filter of their own; the
   head IS a backdrop root, so a nested pod lens samples only the head's thin
   tint WITHOUT the aurora behind it and carved GRAY pills out of the amber
   field (the owner's regression catch, same-DOM A/B vs bd8a0c20); as films on
   the head's one pane, the aurora stays continuous through them.
   ZERO border: a stroke sheet shines through translucent glass as a wash
   (the canonical home's documented removal). A LIVE fact brightens its film
   (--sheen mix) and gains a GOLD SPECULAR top rim, highlight as light on
   the glass edge, never paint inside it; the brand otherwise lives in the
   type chip's gold bold text. overflow clips the mint sweep to the pill. */
.reg-build-chip,
.reg-build-fact {
  position: relative;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  min-block-size: 30px;
  padding: 4px 14px;
  border: 0;
  border-radius: var(--r-full);
  background: var(--build-pod-film);
  box-shadow: var(--glass-edge), inset 0 -1px 0 var(--mix-white-12), var(--glass-shadow-sm);
  font-size: var(--text-caption);
}

.reg-build-chip {
  color: var(--gold-bright);
  font-weight: var(--w-heading);
}

.reg-build-fact {
  font-weight: var(--w-medium);
  color: var(--slate-on-dark-bright);
  transition: color var(--motion-state) var(--ease-standard);
}

/* the pre-filled type is ALWAYS live; a landed fact joins it, the SAME film
   as rest (one seat color, the owner's call) under the gold specular rim
   (the "you are real on this card" light) */
.reg-build-chip,
.reg-build-fact.is-live {
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--gold-bright) 45%, transparent),
    inset 0 -1px 0 var(--mix-white-12),
    var(--glass-shadow-sm);
}

/* a CSS display on the element defeats the hidden attribute's UA display:none;
   restate it, or the areas pod would render before any area lands */
.reg-build-fact[hidden] {
  display: none;
}

.reg-build-fact.is-live {
  color: var(--white);
}

/* THE MINT FLASH, the liquid-glass pods' Tier-1 visual (app.js mintPod; the
   coin-strike): ONE specular band sweeps across the pill and is gone. A glow
   pulse reads as paint ON glass (the owner's call, "cheap"); a moving light
   IS glass behavior. Compositor-only (transform/opacity, §8); physical
   left/translateX so the sweep direction is one aesthetic constant in RTL and
   LTR alike; reduced motion never adds the class (mintPod's own gate) and the
   token collapse zeroes it anyway. */
.reg-build-chip.is-minting::after,
.reg-build-fact.is-minting::after {
  content: "";
  position: absolute;
  inset-block: 0;
  left: -60%;
  inline-size: 55%;
  pointer-events: none;
  background: linear-gradient(
    90deg,
    transparent,
    color-mix(in srgb, var(--sheen) 90%, transparent) 50%,
    transparent
  );
  transform: skewX(-18deg);
  /* --motion-celebrate (900ms): the ONE mint sweep for all three badges, both
     themes (the sheen band is theme-invariant white), the owner's call: a
     savored, visually striking pass (500ms still read as a flick); a win is
     savored, never on the critical path (§8) */
  animation: pod-mint var(--motion-celebrate) var(--ease-emphasized) both;
}

@keyframes pod-mint {
  0% { transform: translateX(0) skewX(-18deg); opacity: 0; }
  20% { opacity: 1; }
  100% { transform: translateX(300%) skewX(-18deg); opacity: 0; }
}

/* the register glass surfaces' a11y arm lives at the END of this sheet: an
   arm must sit AFTER every rule it overrides to win the equal-specificity
   cascade tie (the components.css shared-arm trap, recorded finding). */

/* the CODE step's declaration checkboxes sit as ONE tight, evenly spaced
   group (the owner's call): the subgroup owns a space-2 rhythm between the
   rows; the card's space-4 run stays around the group */
.code-declarations {
  display: grid;
  gap: var(--space-2);
}

/* the create key wears Rishi's KEY PICTOGRAM (the full-color family; the
   outdated functional key mark retired here), sized to the label line and
   vertically centered with it */
.reg-code .submit-label {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* the 48-viewBox pictogram carries its own inner air; a near-zero gap
     reads as the right closeness (space-2 doubled it; the owner's call) */
  gap: 2px;
}

.reg-code .submit-label .picto {
  inline-size: 32px;
  block-size: 32px;
}

/* the finish key's mark is the quiet double check (icons.html), currentColor on the gold face */
.reg-code .submit-label > svg {
  inline-size: 24px;
  block-size: 24px;
  flex-shrink: 0;
}

/* the areas + specialties sections join the CARD as titled sections: a hairline seam,
   never a second card-in-card ring (the old standalone areas step merged here); without
   this reset a fieldset keeps the browser-default groove border, an untokenized ring */
.reg-build-areas,
.reg-specialties {
  display: grid;
  gap: var(--space-3);
  margin: 0;
  padding: var(--space-4) 0 0;
  border: 0;
  border-block-start: 1px solid var(--mix-gold-30);
}

.reg-build-areas-title {
  font-size: var(--text-h3);
}

/* the specialty checklist's hint hugs its title (operator tweak, tightened
   same day): pull one space-2 out of the shared space-3 row gap. */
.reg-specialties .field-hint {
  margin-block-start: calc(-1 * var(--space-2));
}

/* ============================================================================
   PAGETRANSITION (the keyed step slide), each step panel slides in on a step
   change: forward = from the inline-end, back = from the inline-start
   (registerForm.gotoStep replays the animation via slidePhase). Compositor-only;
   the reduced-motion token collapse makes it instant, and the meaning (the
   content) is shown either way.
   ========================================================================== */
.pagetransition {
  display: grid;
  align-content: start;
  gap: var(--space-5);
  inline-size: 100%;
}

.pagetransition.is-sliding-forward,
.pagetransition.is-sliding-back {
  animation-duration: var(--motion-page);
  animation-timing-function: var(--ease-emphasized);
  animation-fill-mode: both;
}

.pagetransition.is-sliding-forward {
  animation-name: pt-in-forward;
}

.pagetransition.is-sliding-back {
  animation-name: pt-in-back;
}

/* pt-in-forward / pt-in-back live in components.css (the one canonical
   @keyframes namespace; token-identical copies here were deleted, wave 2). */

/* ============================================================================
   RISHIGUIDE (the design export's mascot speech-bubble, the Duolingo
   conversational-guide pattern). Rishi on the inline-end, a clean rounded bubble
   he leans into (no janky CSS triangle); the bubble pops in on the state token.
   ON THIS SURFACE the welcome variant carries the larger hero pose; the per-phase
   guides carry a compact pose.
   ========================================================================== */
.rishiguide {
  display: flex;
  align-items: center;
  gap: 0;
  margin: 0;
}

/* THE POSE SITS ON THE INLINE-START SIDE, which under this RTL app is the physical RIGHT
   (operator call: the guide read as an LTR construction). `row-reverse` was what
   pushed it to the physical LEFT; the plain row leaves the avatar first, so the flip needs no
   new rule, only the deletion of that one. The modifier keeps its name because the templates
   and the overlap rule below both address it. */
.rishiguide-end {
  flex-direction: row;
}

.rishiguide-avatar {
  flex-shrink: 0;
  position: relative;
  z-index: 2;
}

.rishiguide-avatar::before {
  content: "";
  position: absolute;
  inset: -10%;
  z-index: -1;
  background: var(--halo-gold);
}

.rishiguide-avatar img,
.login-guide-rishi img {
  /* MIRRORED so the pose faces INTO its bubble from the right: the ONE sanctioned brand-mark
     exception to the §12 never-mirror rule, bounded to the guide+bubble pairing (DESIGN.md §12
     owns the ruling and its limits; a §5 pose standing alone is never mirrored). */
  transform: scaleX(-1);
}
/* LTR twin: the guide sits at the inline-START, which is the physical LEFT under LTR, so the
   bubble is on its RIGHT and the UNMIRRORED pose (which faces right) is the one facing INTO
   it. Same rule, other arm: the mirror above is what "faces the bubble" means under RTL. */
html[dir="ltr"] .rishiguide-avatar img,
html[dir="ltr"] .login-guide-rishi img { transform: none; }

.rishiguide-avatar img {
  display: block;
  block-size: 104px;
  inline-size: auto;
}

.rishiguide-bubble {
  position: relative;
  flex: 1;
  padding: var(--space-4) var(--space-5);
  border-radius: var(--r-lg);
  color: var(--white);
  font-size: var(--text-lead);
  font-weight: var(--w-medium);
  line-height: var(--leading-loose);
  text-wrap: pretty;
  /* LIQUID GLASS (the owner's call; supersedes the earlier flat
     ring stance): ringless: the film + lens + lensing rims carry the edge
     (a gold border-box sheet under a translucent film is the documented
     bleed trap); the small float seats it over the hero ground. */
  border: 0;
  background: var(--build-pod-film);
  -webkit-backdrop-filter: blur(14px) saturate(1.5);
  backdrop-filter: var(--glass-nav-blur);
  animation: pop-in var(--motion-state) var(--ease-spring) both;
}

/* THE PRESENT-GLASS CUE STACK, apple.com-slick (the owner's correction: the
   first cut's stacked strokes + heavy band read as paint): THREE cues only,
   one light direction, consistent across every auth glass surface, the
   register flow's chrome AND the /login guide bubble: ONE fine
   hairline rim (--mix-white-12 auto-themes: a light rim on dark glass, a
   SOFT INK rim on beige, which is what makes the material legible on the
   light ground) · the crisp top specular · the float. A breath of top light
   (10%) hints the pane; the lens does the rest. CURRENT/DONE disc states win
   by specificity and stay untouched. */
.stepstrip-disc,
.stepflow-progress,
.rishiguide-bubble,
.login-guide-bubble {
  /* TWO cues, nothing else (the owner's twice-made "overbearing" call: on a
     flat ground every extra layer reads as a painted button, not glass):
     the thin see-through film (55% of the badges' token: the ground's tint
     through the lens IS the material) + ONE fine hairline rim (auto-themes:
     light on dark, soft ink on beige, the light-theme legibility) + the
     crisp top specular arc. No float, no band. */
  /* the themed chrome film (tokens.css --build-chrome-film): dark = the
     canonical NAVY-BLUE liquid tint PAINTED into the film (blue without the
     saturate lens, the one-stage law holds), beige = the light whisper */
  background: var(--build-chrome-film);
  box-shadow:
    inset 0 0 0 1px var(--mix-white-12),
    var(--glass-edge);
  /* the LENS WITHOUT SATURATE (the transparent-topbar lesson, re-applied for
     the LOAD STAGE the owner caught): the backdrop-filter engages a few
     frames AFTER first paint, and over the near-flat hero ground
     saturate(1.5) was the whole color difference between the pre-lens and
     engaged frames: headed-observed gray (50,66,85) snapping to blue
     (44,68,96) at ~180ms. Blur-only paints both stages alike, so the switch
     disappears; 14px = the nav's trimmed radius (the topbar literal). */
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  /* each lens on its OWN compositor layer (the .bottomnav smooth-scroll law:
     a backdrop re-blurs EVERY scroll frame; unlayered, the entrance sweep
     stuttered; the owner's catch) */
  transform: translateZ(0);
}

.rishiguide-bubble strong,
.rishiguide-bubble b {
  color: var(--gold-bright);
  font-weight: var(--w-heading);
}

/* Rishi OVERLAPS the bubble's near edge: he leans into it (the design's
   tail-free lean); pull the bubble under the avatar from the side that faces him,
   the avatar (z-index 2) sits on top. Logical inset keeps it RTL-correct — and since the
   pose moved to the inline-START side, the bubble is pulled from ITS start edge now. */
.rishiguide-end .rishiguide-bubble {
  margin-inline-start: -26px;
}

/* ---- the welcome moment (no type yet): Rishi-key guides (§5) ----
   the welcome IS a rishiguide, but with the larger hero pose + the gold-bright
   guidance line; it composes the rishiguide layout with these overrides. */
/* the welcome guide keeps Rishi to the SIDE (the rishiguide lean, like the per-step guides) so it
   renders COMPACT on mobile (the user's call): a big stacked Rishi above the bubble was too tall.
   A compact hero Rishi leaves the gradient welcome line room to breathe beside him. */
.reg-welcome {
  margin: 0;
}

.reg-welcome-rishi img {
  block-size: 108px;
}

@media (min-width: 640px) {
  .reg-welcome-rishi img {
    block-size: 132px;
  }
}

/* the welcome line is WHITE (the user's call): clean + high-contrast on the navy bubble. */
.reg-welcome-line {
  /* was a flat --text-lead (18px at every width): Rishi's welcome now grows with the page,
     rem + vw so the ramp is live at 320 too. Scoped to THIS line, so the shared
     .rishiguide-bubble the login guide wears is untouched. */
  font-size: clamp(0.85rem, 0.955rem + 0.536vw, 1.4375rem);
  font-weight: var(--w-medium);
  color: var(--white);
}

/* ---- the type picker: three gradient-ring cards; selected stays lit ---- */
.type-cards {
  display: grid;
  gap: var(--space-3);
}

@media (min-width: 640px) {
  .type-cards {
    grid-template-columns: repeat(3, 1fr);
  }
}

.type-card {
  --grad-surface: var(--navy-2);
  display: grid;
  justify-items: center;
  align-content: start;
  /* a SPACIOUS, even internal rhythm (the user's de-cram): disc → title → desc each get space-3, not the
     crammed space-2, and the card carries generous vertical padding so it reads premium, never tight. */
  gap: var(--space-3);
  padding: var(--space-5) var(--space-4);
  border-radius: var(--r);
  background:
    linear-gradient(var(--grad-surface), var(--grad-surface)) padding-box,
    var(--grad-gold) border-box;
  border: 2px solid transparent;
  color: var(--white);
  text-align: center;
  text-decoration: none;
  transition:
    transform var(--motion-press) var(--ease-standard),
    box-shadow var(--motion-bloom) var(--ease-bloom);
}

.type-card:hover {
  box-shadow: var(--ring-shine), var(--glow-gold);
  transform: translateY(-2px);
}

.type-card:active {
  transform: scale(0.97);
}

.type-disc {
  display: grid;
  place-items: center;
  inline-size: 80px;
  block-size: 80px;
  border-radius: var(--r-full);
  background:
    linear-gradient(var(--navy-3), var(--navy-3)) padding-box,
    var(--grad-gold) border-box;
  border: 3px solid transparent;
  color: var(--gold-bright);
}

/* the full-color pictogram carries its own internal margins (the 48-grid
   live area + ground pill), so it earns more of the disc than a stroke mark */
.type-disc svg {
  inline-size: 62%;
  block-size: 62%;
}

.type-title {
  /* the card headings grow with the picker (was a flat 20px) */
  font-size: clamp(0.95rem, 1.0625rem + 0.625vw, 1.625rem);
  font-weight: var(--w-heading);
}

.type-desc {
  /* was --text-caption: 14px FLAT, the smallest copy on the page and the hardest to read on
     a phone. The floor keeps it at the a11y body minimum the tokens document (16px) while
     the vw term keeps it growing from there. */
  font-size: clamp(1rem, 0.929rem + 0.357vw, 1.1875rem);
  /* a light variant CLOSE to white (user's call): the same slate lifted toward white
     (--slate-on-dark-bright); the white heading title keeps the hierarchy above it. */
  color: var(--slate-on-dark-bright);
  max-inline-size: 24ch;
}

/* (Choosing a type is a full re-render to the stepped form: the picker is shown
   ONLY while choosing, so the old in-place is-selected / has-selection collapse
   states are gone; a tapped card navigates, it never becomes a "selected" chip.) */

/* ---- the /login card: ONE clean gradient-ring panel (the design export's
   login.card.html), the SINGLE surface around the sign-in modes. The earlier
   double-box came from stacking TWO surface treatments on one element (the
   .auth-card rule here AND the .grad-border utility in the markup, each painting
   a padding-box/border-box gradient at a DIFFERENT radius); login.html now wears
   ONLY .auth-card, so this is the lone surface. The register steps use their OWN
   .step-fields panels (above), never this, so .reg-form stays a bare layout
   container (no nested card-in-card). ---- */
.auth-card {
  background:
    linear-gradient(var(--navy-2), var(--navy-2)) padding-box,
    var(--grad-gold) border-box;
  border: 2px solid transparent;
  border-radius: var(--r-lg);
  padding: var(--space-5) var(--space-4);
}

@media (min-width: 640px) {
  .auth-card {
    padding: var(--space-6) var(--space-6);
  }
}

.auth-card-login {
  max-inline-size: 460px;
  margin-inline: auto;
  /* frosted glass over the lit hero (the v2 floating surface): premium + calm; the
     inputs keep their own opaque fill, so legibility is never softened. */
  background:
    var(--glass-bloom) padding-box,
    var(--glass-dark-grad) padding-box,
    var(--grad-gold) border-box;
  -webkit-backdrop-filter: blur(18px) saturate(1.3);
  backdrop-filter: blur(var(--glass-blur)) saturate(1.3);
  box-shadow: var(--glass-edge), var(--glass-shadow);
}
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .auth-card-login {
    background: linear-gradient(var(--navy-2), var(--navy-2)) padding-box, var(--grad-gold) border-box;
  }
}

/* .reg-form is a BARE layout container now (NOT a card): on /register it holds
   the step panels + the sticky foot with the body's rhythm; on /login each mode
   <form> is a plain grid inside the single .auth-card surface, no nested box. */
.reg-form {
  display: grid;
  gap: var(--space-4);
}

/* the shared summary's bottom gap is the GLOBAL .form-error-summary rule
   (components.css, consistent on every page); no register-only override needed. */

/* ---- the קוד phase (Layer 7.5): one focused proof, same card ---- */

/* the card ends on the quiet-key row, whose --tap-min reserve already contributes
   ~20px below its ink, so the shared space-5 pad measured 60px at the bottom
   against 44px at the top. Trim the pad by that reserve; the card frames its
   content equidistant (DESIGN.md §13, the banner law's measure-to-the-ink rule). */
.reg-code .step-fields {
  padding-block-end: calc(var(--space-5) - var(--space-3));
}

.reg-code-title {
  font-size: var(--text-h3);
  font-weight: var(--w-heading);
}

.reg-code-line {
  color: var(--slate-on-dark);
}

.reg-code-phone {
  color: var(--gold-bright);
  font-weight: var(--w-medium);
}

.reg-code-note {
  font-size: var(--text-caption);
  color: var(--gold-bright);
}

.reg-code-note:empty {
  display: none;
}

/* the two quiet keys are --tap-min tall, so ~19px of tap reserve sits ABOVE their
   ink: the card's space-4 run would read 42px here against 36 everywhere else.
   Pull the reserve back so the INK lands on the same rhythm (DESIGN.md §13:
   equal VISUAL gaps, measured, not equal raw padding). */
.reg-code-alt {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  /* ZERO row gap: when the pair stacks (≤~430px) each key already carries its own
     --tap-min box, so a row gap stacks ON TOP of two reserves and measured 46px
     between the inks against the card's 33-37 run. The column gap still separates
     them side by side. */
  gap: 0 var(--space-4);
  margin-block-start: calc(-1 * var(--space-2));
}

/* ---- the /login mode card (Layer 7.5+): one calm card, four ways through ---- */

/* the arriving mode form fades + rises 8px on the state token (§8 --motion-state
   class; the same modest travel as the htmx swap); exits are instant (a mode
   swap discards, never travels). Reduced motion collapses via the token kill
   switch, so the meaning (the form) is never gated on the motion. */
.mode-enter {
  transition:
    opacity var(--motion-state) var(--ease-standard),
    transform var(--motion-state) var(--ease-standard);
}

.mode-enter-start {
  opacity: 0;
  transform: translateY(8px);
}

.mode-enter-end {
  opacity: 1;
  transform: translateY(0);
}

/* the "או" seam between the primary key and the alternate ways in */
.auth-or {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  color: var(--slate-on-dark);
  font-size: var(--text-caption);
}

.auth-or::before,
.auth-or::after {
  content: "";
  block-size: 1px;
  flex: 1;
  background: var(--navy-3);
}

/* the two alternate MODE KEYS (phone-code sign-in / the recovery key): visible,
   bordered, calm, never competing with the one primary (§6), but real keys
   with the press + hover language every interactive element carries */
.auth-modes {
  display: grid;
  gap: var(--space-2);
}

@media (min-width: 480px) {
  .auth-modes {
    grid-template-columns: 1fr 1fr;
  }
}

.btn-mode {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-block-size: var(--tap-min);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--navy-3);
  border-radius: var(--r);
  background: none;
  color: var(--gold-bright);
  font-size: var(--text-caption);
  font-weight: var(--w-medium);
  cursor: pointer;
  transition:
    transform var(--motion-press) var(--ease-standard),
    border-color var(--motion-press) var(--ease-standard),
    background-color var(--motion-press) var(--ease-standard),
    box-shadow var(--motion-bloom) var(--ease-bloom);
}

.btn-mode:hover {
  border-color: var(--gold);
  background: var(--state-hover);
  box-shadow: var(--glow-gold); /* the shaped-button hover-glow law (DESIGN.md §6) */
}

.btn-mode:active {
  transform: scale(0.97);
  background: var(--state-press);
}

/* the mode keys carry full-color pictograms (the SSO-button grammar), a
   little larger than a stroke mark so the layered art stays legible */
.btn-mode svg {
  inline-size: 26px;
  block-size: 26px;
  flex-shrink: 0;
}

/* the forgot-password channel choice: the two-button STEP 1 (the user's correction: channel
   FIRST, never an email-first form). Two stacked full-width keys in the btn-mode grammar, each
   crowned by its full-color pictogram (phone / email, the §6 showcase register); a touch larger
   than the inline mode-keys because this is the PRIMARY choice of the flow. */
.reset-channels {
  display: grid;
  gap: var(--space-2);
}

.reset-channels .btn-mode {
  padding-block: var(--space-3);
  font-size: var(--text-body);
}

.reset-channels .btn-mode svg {
  inline-size: 30px;
  block-size: 30px;
}

/* STEP 4 (the new password) is crowned by the lock pictogram, the "password" showcase glyph,
   centered above the title (the §6 showcase register, the icon the user asked for). */
.reset-hero {
  display: flex;
  justify-content: center;
  margin-block-end: var(--space-2);
}

.reset-hero .picto {
  inline-size: 56px;
  block-size: 56px;
}

/* the one-time code reads as THE code: centered, spaced, heading-weight digits
   (LTR is set on the field; applies to the registration קוד phase too, one
   pattern everywhere) */
.reg-code input[autocomplete="one-time-code"] {
  text-align: center;
  letter-spacing: 0.3em;
  font-weight: var(--w-heading);
}

/* a filled note is a quiet confirmation chip, not a floating caption (the
   sent/reset-done beats, Tier 1: calm, present, no celebration) */
.reg-code-note:not(:empty) {
  padding: var(--space-2) var(--space-3);
  border-radius: var(--r-sm);
  background: var(--navy-3);
  --side-stroke: var(--gold);
}

/* quiet in-flow actions (resend / back): text-buttons, still ≥48px targets
   with the <100ms pressed state every interactive element carries (§6) */
.btn-quiet {
  background: none;
  border: none;
  padding: var(--space-2);
  min-block-size: var(--tap-min);
  color: var(--gold-bright);
  font-size: var(--text-body);
  font-weight: var(--w-medium);
  cursor: pointer;
  transition:
    transform var(--motion-press) var(--ease-standard),
    opacity var(--motion-press) var(--ease-standard);
}

.btn-quiet:hover {
  text-decoration: underline;
}

.btn-quiet:active {
  transform: scale(0.97);
}

.btn-quiet:disabled {
  opacity: 0.5;
  cursor: default;
}

.field-pw {
  display: grid;
  gap: var(--space-2);
}

/* once the flow is DONE (the success beat), the stepflow head (progress bar +
   back chevron) leaves with the form; the success summary owns the screen
   (§10 END); the picker is already gone (a type was chosen). */
.reg-flow.is-done .stepflow-head {
  display: none;
}

/* ---- the locations picker: MOVED to components.css (shared by register + the L9 profile
   places-of-work editor, the move-never-copy doctrine, decisions.md L8 #5). The .surface-light
   overrides for the cream profile body live in profile.css. ---- */

/* ---- the success beat (§10 peak–end: summary + ONE next step) ---- */
.reg-success {
  display: grid;
  justify-items: center;
  gap: var(--space-3);
  text-align: center;
  animation: pop-in var(--motion-reveal) var(--ease-emphasized) both;
}

/* R4: the rishi-confetti finishing pose SPRINGS in synced with the confetti (fired at
   --motion-reveal); the wrapper keeps its own pop-in entrance above. */
.reg-success picture {
  position: relative;
  z-index: 0;
  animation: pop-in var(--motion-reveal) var(--ease-spring) both;
}

.reg-success picture::before {
  content: "";
  position: absolute;
  inset: -10%;
  z-index: -1;
  background: var(--halo-gold);
}

.reg-success img {
  max-block-size: 200px;
  inline-size: auto;
}

/* the milestone word wraps on a phone (and in English at desktop): even lines, never a one-word tail */
.reg-success .milestone-word {
  text-wrap: balance;
}

.reg-success-title {
  font-size: var(--text-h1);
  font-weight: var(--w-display);
  color: var(--gold-bright);
}

.reg-success-line {
  font-size: var(--text-lead);
}

.reg-success-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--space-2);
  justify-items: start;
  color: var(--slate-on-dark);
}

.reg-success-list li {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.reg-success-list svg {
  inline-size: 18px;
  block-size: 18px;
  color: var(--success);
  flex-shrink: 0;
}

.reg-success-note {
  font-size: var(--text-caption);
  color: var(--slate-on-dark);
}

/* ---- the coupon ticket (the code the lead keeps): a dashed gold edge over a faint gold film,
   the ribbon on the gold fill, the code at h1 on the gold ramp, LTR. Springs in with the pose so
   the beat lands as one. Kept COMPACT on purpose: the ticket adds to a beat that must still fit a
   900px-tall desktop below the bar (measured: the display-size code pushed it to 816px). ---- */
.reg-coupon {
  display: grid;
  justify-items: center;
  gap: var(--space-1);
  inline-size: min(100%, 22rem);
  /* the top edge meets the ribbon's pill, the bottom edge the note's line box (whose leading
     adds its own air), so the top takes one step more to READ even (operator call) */
  padding: var(--space-4) var(--space-4) var(--space-3);
  border: 2px dashed var(--gold-bright);
  border-radius: var(--r-lg);
  background: color-mix(in srgb, var(--gold) 14%, transparent);
  animation: pop-in var(--motion-reveal) var(--ease-spring) both;
}

.reg-coupon-ribbon {
  margin: 0;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--r-full);
  background: var(--grad-gold-fill);
  color: var(--on-accent);
  font-size: var(--text-caption);
  font-weight: var(--w-heading);
}

.reg-coupon-code {
  margin: 0;
  font-size: var(--text-h1);
  font-weight: var(--w-display);
  line-height: var(--leading-tight);
  letter-spacing: 0.18em;
  font-variant-numeric: tabular-nums;
}

.reg-coupon-note {
  margin: 0;
  font-size: var(--text-caption);
  color: var(--slate-on-dark);
  text-wrap: balance; /* two even lines on a phone, never a one-word orphan */
}

/* ---- below-card alternative action (login <-> register cross-links) ---- */
.auth-alt {
  margin-block-start: var(--space-4);
  text-align: center;
  color: var(--slate-on-dark);
}

.auth-alt a {
  color: var(--gold-bright);
  font-weight: var(--w-medium);
}

/* ---- the guide pose shrinks on the narrowest phones so the bubble keeps room
   (mobile-first: the layered Rishi art must never squeeze the guidance line) ---- */
@media (max-width: 380px) {
  .rishiguide-avatar img {
    block-size: 84px;
  }
  .rishiguide-bubble {
    font-size: var(--text-body);
    padding: var(--space-3) var(--space-4);
  }
  /* the picker's welcome keeps its own ramp here: this block's job is the bubble's PADDING
     and the pose size on a 320px phone, and its blanket --text-body re-flattened the line to
     17px (measured), undoing the ramp above for exactly the device that needed it most. */
  .reg-welcome-line {
    font-size: clamp(0.85rem, 0.955rem + 0.536vw, 1.4375rem);
  }
}

/* ============================================================================
   THE AUTH GLASS SURFACES' A11Y ARM, LAST IN THE SHEET by design: an arm
   must sit AFTER every rule it overrides to win the equal-specificity cascade
   tie (the components.css shared-arm trap, recorded finding). Translucency is
   a preference, never a requirement: the opaque tile, no lens.
   ========================================================================== */
@media (prefers-reduced-transparency: reduce) {
  .reg-build-chip,
  .reg-build-fact,
  .theme-pick,
  .stepstrip-disc,
  .stepflow-progress,
  .rishiguide-bubble,
  .login-guide-bubble {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    background-color: var(--navy-4);
    background-image: none;
  }
  /* the head takes the SAME opaque tile as its no-backdrop arm (below) rather than the flat
     one above: its gold ring is a border-box background LAYER, so `background-image: none`
     would erase the ring along with the lens. Both arms therefore land the identical
     ring-keeping surface: one degraded look, reached by either route. */
  .reg-build-head {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    background:
      var(--grad-lit-card-raised) padding-box,
      var(--grad-gold) border-box;
  }
}

/* the OTHER a11y arm for the same surfaces: no backdrop-filter support at all. Same sheet-end
   position for the same cascade reason, same opaque tile. (.reg-build-head's own no-support
   fallback sits with its rule above, where it already wins its tie.) */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .theme-pick,
  .stepstrip-disc,
  .stepflow-progress,
  .rishiguide-bubble {
    background-color: var(--navy-4);
    background-image: none;
  }
}
