/* ==========================================================================
   ShopFront — Login & registration
   --------------------------------------------------------------------------
   Loaded by login.html only. Load order is
   `tokens.css → styles.css → page.css → login.css`; page.css supplies the
   breadcrumb, this file everything below it.

   Same house rules as the rest of the build:
     · no raw colour, no raw shadow, no off-grid spacing — tokens only;
     · logical properties throughout (dir="rtl", inline-start = right);
     · flat. Surfaces separate by border and tone, never by shade.

   Two ideas drive the layout. First, the form is the page — it sits on the
   inline-start (right) half where the eye lands first in RTL, and the
   marketing panel takes the leftover. Second, nothing ever moves: the card
   is a fixed-height stage and every view inside it (login, register, code,
   done) is swapped in place, so switching a tab does not make the page
   jump under the pointer.

   Contents
     01  Auth layout
     02  Brand side panel
     03  Card shell & views
     04  Segmented tabs        (ورود / ثبت‌نام)
     05  Method switch         (رمز عبور / کد یک‌بارمصرف)
     06  Fields
     07  Checkbox, meta row & password strength
     08  One-time-code boxes
     09  Submit, loading & done view
     10  Responsive
     11  Motion, contrast & print
   ========================================================================== */


/* ==========================================================================
   01 · AUTH LAYOUT
   ========================================================================== */

.auth {
  padding-block: var(--space-8) var(--section-gap);
}

/* The card is deliberately the narrower track. A login form wider than
   ~30rem reads as a settings page: the label-to-field distance grows and
   the eye stops treating the column as one object. */
.auth__grid {
  display: grid;
  grid-template-columns: minmax(0, 30rem) minmax(0, 1fr);
  gap: var(--space-8);
  align-items: start;
}


/* ==========================================================================
   02 · BRAND SIDE PANEL & 3D STAGE
   --------------------------------------------------------------------------
   Second in the DOM, so in RTL it lands on the left and — more to the
   point — falls *below* the form once the grid collapses. On a phone the
   first thing under the thumb has to be the first field, not a value
   proposition.

   The stage at the top is a real 3D scene, not a picture of one: the
   objects are DOM layers in a shared `perspective`, each rotated in space
   with `transform-style: preserve-3d`, so the candles genuinely stand off
   the glass panel and the parcel genuinely has three lit faces. That buys
   three things a render cannot — it weighs nothing over the wire, it stays
   sharp at any zoom or DPR, and its colours come from the same ramps as
   the rest of the site, so it can never drift out of palette.

   The whole composition is sized in `em` against one font-size on .stage.
   That single clamp is the scale knob: change it and every object, gap and
   offset moves together.

   Colour plan — the panel is the one place the palette is allowed to open
   up, so each object takes a different ramp and they are lit from the same
   upper-right key light: teal candles, amber coin, navy parcel, green and
   white glass pills, one red down-candle as the accent the eye lands on.

   To art-direct it with a render instead, see `.stage--art` at the end of
   this section and IMAGE-PROMPTS.md §۵.
   ========================================================================== */

/* The panel is a light surface, not a dark slab. Everything tonal about it
   is declared as the six knobs below and nothing downstream states a
   colour of its own — which is what lets the dark override at the end of
   this block re-light the whole panel, scene included, in one place. */
.auth-side {
  --side-tint-a: var(--teal-100);
  --side-tint-b: var(--navy-100);
  --side-glow-teal:   var(--teal-200);
  --side-glow-amber:  var(--amber-100);
  --side-glow-indigo: var(--navy-200);
  --side-glow-opacity: 0.85;
  /* The fallback scene's glass and its cast shadow. */
  --side-glass:        oklch(1 0 0 / 0.74);
  --side-glass-border: var(--border-default);
  --side-shadow:       oklch(0.243 0.045 262 / 0.22);

  position: relative;
  overflow: hidden;
  padding: var(--panel-pad);
  border: var(--border-hairline) solid var(--border-subtle);
  border-radius: var(--panel-radius);
  /* Two soft key lights over the page surface — teal from the top corner,
     navy from the bottom — so the field behind the artwork is lit rather
     than flat. Light enough that the render's own white glass panel still
     reads against it. */
  background:
    radial-gradient(120% 88% at 84% 4%, var(--side-tint-a), transparent 58%),
    radial-gradient(92% 70% at 6% 98%, var(--side-tint-b), transparent 62%),
    linear-gradient(168deg, var(--bg-surface), var(--bg-surface-2));
  color: var(--fg-default);
}

/* Dark theme keeps the same construction and only drops the lights: a
   light panel would be the one glaring rectangle on a dark page. */
:root[data-theme="dark"] .auth-side {
  --side-tint-a: oklch(0.322 0.066 167 / 0.85);
  --side-tint-b: oklch(0.262 0.064 260 / 0.85);
  --side-glow-teal:   var(--teal-600);
  --side-glow-amber:  var(--amber-700);
  --side-glow-indigo: var(--navy-600);
  --side-glow-opacity: 0.65;
  --side-glass:        oklch(1 0 0 / 0.10);
  --side-glass-border: oklch(1 0 0 / 0.22);
  --side-shadow:       oklch(0 0 0 / 0.62);
}

.auth-side > * {
  position: relative;
}

/* ---- Stage ------------------------------------------------------------ */

.stage {
  position: relative;
  block-size: clamp(14rem, 24vw, 18.5rem);
  margin-block-end: var(--space-7);
  /* The one scale knob: every object below is measured in em. */
  font-size: clamp(0.78rem, 0.52rem + 0.72vw, 1.06rem);
  /* Shallow enough that the rotations read as depth rather than as a
     fish-eye. The origin sits high and to the inline-start because that is
     where the key light is. */
  perspective: 62em;
  perspective-origin: 62% 34%;
}

/* Blurred colour behind the objects. Three, not one: a single glow reads
   as a vignette, three overlapping hues read as a lit room. */
.stage__glow {
  position: absolute;
  border-radius: var(--radius-circle);
  filter: blur(2.6em);
  opacity: var(--side-glow-opacity);
  pointer-events: none;
}

.stage__glow--teal {
  inline-size: 14em;
  block-size: 14em;
  inset-block-start: -3em;
  inset-inline-start: 18%;
  background: radial-gradient(circle, var(--side-glow-teal), transparent 68%);
}

.stage__glow--amber {
  inline-size: 10em;
  block-size: 10em;
  inset-block-end: -1em;
  inset-inline-end: 6%;
  background: radial-gradient(circle, var(--side-glow-amber), transparent 66%);
}

.stage__glow--indigo {
  inline-size: 12em;
  block-size: 12em;
  inset-block-end: -2em;
  inset-inline-start: -2em;
  background: radial-gradient(circle, var(--side-glow-indigo), transparent 68%);
  opacity: calc(var(--side-glow-opacity) * 0.8);
}

.stage__scene {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}

/* The contact shadow that stops the objects looking pasted on. */
.stage__floor {
  position: absolute;
  inset-inline: 16%;
  inset-block-end: 8%;
  block-size: 2.4em;
  border-radius: var(--radius-circle);
  background: radial-gradient(ellipse at center, var(--side-shadow), transparent 72%);
  filter: blur(0.6em);
}

/* ---- Object 1 · the glass chart panel --------------------------------- */

.scene-card {
  position: absolute;
  inset-block-start: 13%;
  inset-inline-start: 20%;
  inline-size: 17.5em;
  block-size: 12em;
  display: grid;
  grid-template-rows: auto 1fr;
  gap: 0.9em;
  padding: 1em 1.1em 1.2em;
  border: 1px solid var(--side-glass-border);
  border-radius: 1.2em;
  background: var(--side-glass);
  box-shadow:
    0 1.8em 2.8em -0.9em var(--side-shadow),
    inset 0 1px 0 oklch(1 0 0 / 0.55);
  backdrop-filter: blur(0.5em);
  transform: rotateX(13deg) rotateY(-17deg) rotateZ(1.5deg);
  transform-style: preserve-3d;
  /* Animated through `translate`, not `transform`: the rotation above has
     to survive, and the two are separate properties. */
  animation: stage-float-a 7.5s var(--ease-in-out) infinite;
}

.scene-card__bar {
  display: flex;
  gap: 0.4em;
}

.scene-card__bar i {
  inline-size: 0.55em;
  block-size: 0.55em;
  border-radius: var(--radius-circle);
  background: var(--border-strong);
}

.scene-card__bar i:first-child { background: var(--red-400); }
.scene-card__bar i:nth-child(2) { background: var(--amber-400); }
.scene-card__bar i:last-child   { background: var(--teal-400); }

/* LTR inside an RTL document, deliberately: a price chart's time axis runs
   left to right everywhere, so in the document's own direction the run
   would climb the wrong way and read as a crash. */
.scene-chart {
  direction: ltr;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 0.55em;
  transform-style: preserve-3d;
}

/* Each candle is lifted off the glass in Z, so the panel casts it rather
   than containing it. --h is the body height, set per candle in the HTML. */
.scene-chart__candle {
  position: relative;
  inline-size: 1.15em;
  block-size: var(--h);
  border-radius: 0.3em;
  background: linear-gradient(170deg, var(--teal-300), var(--teal-500) 52%, var(--teal-700));
  box-shadow:
    inset 0 0 0 1px oklch(1 0 0 / 0.22),
    0 0.5em 0.9em -0.45em oklch(0 0 0 / 0.7);
  transform: translateZ(1.4em);
}

/* Wick. */
.scene-chart__candle::before {
  content: "";
  position: absolute;
  inset-inline-start: 50%;
  inset-block-end: 100%;
  inline-size: 0.16em;
  block-size: 0.85em;
  border-radius: var(--radius-pill);
  background: var(--fg-subtle);
  translate: 50% 0;
}

/* The one red mark in the composition. Down-candles are the only thing red
   is allowed to be in this system, which is exactly what it is here. */
.scene-chart__candle--down {
  background: linear-gradient(170deg, var(--red-300), var(--red-500) 52%, var(--red-700));
}

/* ---- Object 2 · the discount coin ------------------------------------- */

.scene-coin {
  position: absolute;
  inset-block-start: 2%;
  inset-inline-end: 9%;
  display: grid;
  place-items: center;
  inline-size: 4.8em;
  block-size: 4.8em;
  border-radius: var(--radius-circle);
  /* Conic for the milled metal, radial on top for the specular hit. */
  background:
    radial-gradient(circle at 34% 26%, oklch(1 0 0 / 0.85), transparent 44%),
    conic-gradient(from 210deg,
      var(--amber-600), var(--amber-400) 24%, var(--amber-100) 40%,
      var(--amber-500) 62%, var(--amber-700) 86%, var(--amber-600));
  box-shadow:
    0 1.1em 1.8em -0.6em var(--side-shadow),
    inset 0 0 0 0.26em oklch(1 0 0 / 0.30);
  transform: rotateX(16deg) rotateY(-24deg) rotateZ(-8deg);
  transform-style: preserve-3d;
  animation: stage-float-b 6.4s var(--ease-in-out) infinite;
}

/* The rim: the same disc pushed back in Z, which is what gives the coin
   thickness instead of a drawn outline. */
.scene-coin::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--radius-circle);
  background: linear-gradient(160deg, var(--amber-700), var(--amber-600) 60%, var(--amber-700));
  transform: translateZ(-0.55em);
}

.scene-coin b {
  font-size: 1.9em;
  font-weight: var(--weight-black);
  line-height: 1;
  color: oklch(0.40 0.09 62);
  text-shadow: 0 1px 0 oklch(1 0 0 / 0.55);
}

/* ---- Object 3 · the parcel -------------------------------------------- */

.scene-cube {
  position: absolute;
  inset-block-end: 14%;
  inset-inline-start: 7%;
  inline-size: 4.4em;
  block-size: 4.4em;
  transform-style: preserve-3d;
  transform: rotateX(-24deg) rotateY(-36deg);
  animation: stage-float-c 8.2s var(--ease-in-out) infinite;
}

.scene-cube__face {
  position: absolute;
  inset: 0;
  border-radius: 0.3em;
  box-shadow: inset 0 0 0 1px oklch(1 0 0 / 0.16);
}

/* Half the cube's size, so the three faces meet at its edges. */
.scene-cube__face--front { background: linear-gradient(158deg, var(--navy-500), var(--navy-800)); transform: translateZ(2.2em); }
.scene-cube__face--side  { background: linear-gradient(158deg, var(--navy-700), var(--navy-950)); transform: rotateY(90deg) translateZ(2.2em); }
.scene-cube__face--top   { background: linear-gradient(158deg, var(--teal-400), var(--teal-600)); transform: rotateX(90deg) translateZ(2.2em); }

/* Packing tape across the lid — the detail that reads "parcel" rather than
   "cube". */
.scene-cube__face--top::after {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 42%;
  inline-size: 0.55em;
  background: oklch(1 0 0 / 0.32);
}

/* ---- Object 4 · the floating pills ------------------------------------ */

.scene-pill {
  position: absolute;
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.5em 0.9em;
  border: 1px solid var(--side-glass-border);
  border-radius: var(--radius-pill);
  background: var(--side-glass);
  box-shadow: 0 0.9em 1.5em -0.7em var(--side-shadow);
  backdrop-filter: blur(0.5em);
  font-size: 0.95em;
  font-weight: var(--weight-bold);
  white-space: nowrap;
}

.scene-pill .icon {
  font-size: 1em;
}

.scene-pill--up {
  inset-block-start: 6%;
  inset-inline-start: 2%;
  border-color: var(--success);
  background: var(--success-subtle);
  color: var(--success-text);
  transform: rotate(-6deg);
  animation: stage-float-b 7s var(--ease-in-out) infinite 0.4s;
}

/* ---- Object 5 · the secure-login tile ---------------------------------
   The counterweight to the parcel on the far side of the panel, and the
   one object that says something about *this* page rather than about the
   shop. */
.scene-badge {
  position: absolute;
  inset-block-end: 9%;
  inset-inline-end: 5%;
  display: grid;
  justify-items: center;
  align-content: center;
  gap: 0.25em;
  inline-size: 5.2em;
  block-size: 5.2em;
  border-radius: 1.35em;
  background:
    radial-gradient(120% 90% at 26% 14%, oklch(1 0 0 / 0.28), transparent 58%),
    linear-gradient(152deg, var(--navy-400), var(--navy-700) 62%, var(--navy-900));
  box-shadow:
    0 1.4em 2.2em -0.8em var(--side-shadow),
    inset 0 1px 0 oklch(1 0 0 / 0.35);
  color: var(--slate-0);
  transform: rotateX(12deg) rotateY(16deg) rotateZ(-6deg);
  animation: stage-float-c 6.8s var(--ease-in-out) infinite 0.2s;
}

.scene-badge .icon {
  font-size: 1.7em;
  color: var(--teal-300);
}

.scene-badge b {
  font-size: 0.72em;
  font-weight: var(--weight-bold);
}

/* Three offsets and three periods that do not divide into each other, so
   the objects never bob in unison. */
@keyframes stage-float-a {
  0%, 100% { translate: 0 0.15em; }
  50%      { translate: 0 -0.65em; }
}
@keyframes stage-float-b {
  0%, 100% { translate: 0 -0.45em; }
  50%      { translate: 0 0.5em; }
}
@keyframes stage-float-c {
  0%, 100% { translate: 0 0.4em; }
  50%      { translate: 0 -0.5em; }
}

/* ---- The render ------------------------------------------------------
   `stage--art` stands the built scene down in favour of an illustration.
   The glows are deliberately *not* hidden with it: the render carries an
   alpha channel, so they light it from behind exactly as they lit the
   scene, and they fill the width the square artwork does not.

   The stage grows taller here because the artwork is square — a square
   dropped into the band the scene used would be sized by the short side
   and end up half the panel's width. */
.stage--art {
  block-size: clamp(15rem, 30vw, 24rem);
}

.stage--art .stage__scene {
  display: none;
}

.stage__art {
  position: relative;
  display: block;
  inline-size: 100%;
  block-size: 100%;
  /* contain, never cover: the composition is four objects with air
     between them, and cropping any edge cuts one of them in half. */
  object-fit: contain;
  /* The render's own contact shadows are dark grey on transparent, which
     all but disappears against a navy panel. This puts the objects back
     on the ground. */
  filter: drop-shadow(0 1rem 1.4rem var(--side-shadow));
}

/* ---- Copy ------------------------------------------------------------- */

.auth-side__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-inline-sm);
  padding: var(--space-1-5) var(--space-3);
  border: var(--border-hairline) solid var(--border-brand);
  border-radius: var(--radius-pill);
  background: var(--bg-brand-subtle);
  color: var(--brand-text);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
}

.auth-side__title {
  margin-block-start: var(--space-5);
  font-size: var(--text-4xl);
  font-weight: var(--weight-extrabold);
  line-height: var(--leading-tight);
}

.auth-side__lead {
  margin-block-start: var(--space-3);
  max-inline-size: 34ch;
  color: var(--fg-body);
  font-size: var(--text-lg);
  line-height: var(--leading-normal);
}

/* Four short glass tiles rather than four full-width rows: the scene above
   is now the thing being looked at, and the benefits are the caption to
   it. Two columns keeps the panel's height in the same range as the form
   beside it. */
.auth-side__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2-5);
  margin-block-start: var(--space-6);
  list-style: none;
}

.auth-side__list li {
  display: grid;
  align-content: start;
  gap: var(--space-1);
  padding: var(--space-4);
  border: var(--border-hairline) solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-surface);
}

.auth-side__list .icon-tile {
  justify-self: start;
  margin-block-end: var(--space-1);
}

.auth-side__list b {
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
}

.auth-side__list li > span:last-child {
  color: var(--fg-muted);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
}

/* Security note. It is the last thing read before the first keystroke, so
   it says what happens to the data, not how much we care about it. */
.auth-side__note {
  display: flex;
  align-items: flex-start;
  gap: var(--gap-inline-sm);
  margin-block-start: var(--space-6);
  padding-block-start: var(--space-5);
  border-block-start: var(--border-hairline) solid var(--border-subtle);
  color: var(--fg-muted);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
}

.auth-side__note .icon {
  flex: none;
  margin-block-start: 0.15em;
}


/* ==========================================================================
   03 · CARD SHELL & VIEWS
   ========================================================================== */

.auth-card {
  padding: clamp(var(--space-5), 3vw, var(--space-8));
  border: var(--border-hairline) solid var(--border-subtle);
  border-radius: var(--panel-radius);
  background: var(--card-bg);
}

.auth-card__head {
  display: grid;
  gap: var(--space-2);
  margin-block-end: var(--space-6);
}

/* The done view brings its own heading, so the shared head steps aside.
   Spelt out because a class that sets `display` outranks the user agent's
   `[hidden] { display: none }` — setting .hidden in script would otherwise
   do nothing here. */
.auth-card__head[hidden] {
  display: none;
}

.auth-card__title {
  font-size: var(--text-4xl);
  font-weight: var(--weight-extrabold);
  line-height: var(--leading-tight);
  color: var(--fg-default);
}

.auth-card__sub {
  color: var(--fg-muted);
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
}

/* Only one view is in the DOM flow at a time; the rest carry [hidden]. */
.auth-view[hidden] {
  display: none;
}

/* Whatever view is showing, its first paint fades rather than snaps —
   enough to say "this replaced that", not enough to wait for. */
.js .auth-view:not([hidden]) {
  animation: auth-swap var(--duration-base) var(--ease-out) both;
}

@keyframes auth-swap {
  from { opacity: 0; translate: 0 var(--space-2); }
  to   { opacity: 1; translate: 0 0; }
}

/* Card foot — the escape hatch. A shop that forces an account before it
   will show a price loses the sale, so the way out is a real link and it
   is never hidden behind a menu. */
.auth-card__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-inline-md);
  margin-block-start: var(--space-6);
  padding-block-start: var(--space-5);
  border-block-start: var(--border-hairline) solid var(--border-subtle);
  color: var(--fg-muted);
  font-size: var(--text-sm);
}

.auth-card__foot a {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-inline-xs);
  color: var(--brand-text);
  font-weight: var(--weight-bold);
}

.auth-card__foot a:hover {
  text-decoration: underline;
  text-underline-offset: 0.25em;
}


/* ==========================================================================
   04 · SEGMENTED TABS  (ورود / ثبت‌نام)
   --------------------------------------------------------------------------
   Two equal halves and a thumb that slides between them. The thumb is a
   separate element rather than a background on the active button so the
   travel is animatable, and it is aria-hidden — the state a screen reader
   needs is on aria-selected, not on a moving rectangle.
   ========================================================================== */

.seg {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-1);
  padding: var(--space-1);
  border-radius: var(--radius-pill);
  background: var(--bg-surface-3);
}

.seg__thumb {
  position: absolute;
  z-index: 0;
  inset-block: var(--space-1);
  inset-inline-start: var(--space-1);
  inline-size: calc(50% - var(--space-1) - var(--space-0-5));
  border-radius: var(--radius-pill);
  background: var(--bg-surface);
  border: var(--border-hairline) solid var(--border-subtle);
  transition: translate var(--duration-base) var(--ease-out);
}

/* Physical, and deliberately so: the document is RTL, the second tab sits
   to the *left* of the first, so the thumb travels in -X to reach it. */
.seg[data-active="register"] .seg__thumb {
  translate: calc(-100% - var(--space-1)) 0;
}

.seg__btn {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--gap-inline-sm);
  min-block-size: var(--btn-height);
  border-radius: var(--radius-pill);
  color: var(--fg-muted);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  transition: var(--transition-colors);
}

.seg__btn[aria-selected="true"] {
  color: var(--brand-text);
}

.seg__btn:hover {
  color: var(--fg-default);
}

.seg__btn:focus-visible {
  outline: var(--ring-width) solid var(--ring-color);
  outline-offset: var(--ring-offset);
}


/* ==========================================================================
   05 · METHOD SWITCH  (رمز عبور / کد یک‌بارمصرف)
   --------------------------------------------------------------------------
   The two-way login. Both routes end in the same account, so they are
   peers on one row rather than a primary path with a link underneath it.
   ========================================================================== */

/* Both panels open the same distance below the tab strip, whether the
   first thing in them is the method switch or a field. */
.auth-panel {
  margin-block-start: var(--space-6);
}

.method {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2-5);
  margin-block-end: var(--space-6);
}

.method__btn {
  display: flex;
  align-items: center;
  gap: var(--gap-inline-sm);
  padding: var(--space-3) var(--space-3-5);
  border: var(--border-thin) solid var(--border-default);
  border-radius: var(--radius-lg);
  background: var(--bg-surface);
  color: var(--fg-body);
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  text-align: start;
  transition: var(--transition-colors);
}

.method__btn .icon {
  flex: none;
  color: var(--fg-subtle);
  transition: var(--transition-colors);
}

.method__btn:hover {
  border-color: var(--border-strong);
  background: var(--bg-surface-2);
}

.method__btn[aria-selected="true"] {
  border-color: var(--brand);
  background: var(--bg-brand-subtle);
  color: var(--brand-text);
}

.method__btn[aria-selected="true"] .icon {
  color: var(--brand);
}

.method__btn:focus-visible {
  outline: var(--ring-width) solid var(--ring-color);
  outline-offset: var(--ring-offset);
}


/* ==========================================================================
   06 · FIELDS
   --------------------------------------------------------------------------
   The border, the focus ring and the invalid state all live on the
   wrapper, not the input: the row carries an icon and a toggle button
   beside the text, and those have to sit inside the same outline.
   ========================================================================== */

.auth-form {
  display: grid;
  gap: var(--space-5);
}

.auth-form[hidden] {
  display: none;
}

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

.field__label {
  display: flex;
  align-items: baseline;
  gap: var(--gap-inline-sm);
  color: var(--fg-body);
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
}

.field__optional {
  margin-inline-start: auto;
  color: var(--fg-subtle);
  font-size: var(--text-xs);
  font-weight: var(--weight-normal);
}

.field__control {
  display: flex;
  align-items: center;
  gap: var(--gap-inline-sm);
  padding-inline: var(--input-pad-inline);
  border: var(--border-thin) solid var(--input-border);
  border-radius: var(--input-radius);
  background: var(--input-bg);
  transition: var(--transition-colors), box-shadow var(--duration-fast) var(--ease-standard);
}

.field__control:focus-within {
  border-color: var(--input-border-focus);
  box-shadow: var(--ring);
}

.field__icon {
  flex: none;
  color: var(--fg-subtle);
  font-size: var(--icon-md);
  transition: var(--transition-colors);
}

.field__control:focus-within .field__icon {
  color: var(--brand);
}

.field__input {
  flex: 1;
  min-inline-size: 0;
  block-size: var(--input-height);
  border: 0;
  background: none;
  color: var(--input-fg);
  font-family: inherit;
  font-size: var(--text-lg);
}

.field__input::placeholder {
  color: var(--input-placeholder);
}

/* The ring belongs to the wrapper; a second one on the input would draw a
   pill inside a pill. */
.field__input:focus {
  outline: none;
}

/* Phone numbers, e-mail addresses and passwords are Latin/numeric strings.
   They are laid out left-to-right so digits and dots read in the order
   they were typed, then aligned to the inline-start edge of the RTL row —
   which is the right — so the text still starts where the label does. */
.field__input--ltr {
  direction: ltr;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Trailing affordances: the ✓ that confirms a field is accepted, and the
   eye that reveals a password. */
.field__ok {
  flex: none;
  display: none;
  color: var(--success);
  font-size: var(--icon-md);
}

.field.is-valid .field__ok {
  display: block;
}

.field__toggle {
  flex: none;
  display: grid;
  place-items: center;
  inline-size: var(--space-9);
  block-size: var(--space-9);
  margin-inline-end: calc(var(--space-2) * -1);
  border-radius: var(--radius-circle);
  color: var(--fg-subtle);
  font-size: var(--icon-md);
  transition: var(--transition-colors);
}

.field__toggle:hover {
  background: var(--bg-surface-3);
  color: var(--fg-default);
}

.field__toggle:focus-visible {
  outline: var(--ring-width) solid var(--ring-color);
  outline-offset: calc(var(--ring-offset) * -1);
}

/* Two icons in one button; the pressed state decides which shows. */
.field__toggle .icon--off { display: none; }
.field__toggle[aria-pressed="true"] .icon--on  { display: none; }
.field__toggle[aria-pressed="true"] .icon--off { display: block; }

.field__hint {
  display: flex;
  align-items: center;
  gap: var(--gap-inline-xs);
  color: var(--fg-subtle);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
}

/* Errors are announced, so they must exist in the DOM before they have
   text — they are emptied and refilled, never inserted and removed. */
.field__error {
  display: none;
  align-items: center;
  gap: var(--gap-inline-xs);
  color: var(--danger-text);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-snug);
}

.field__error .icon {
  flex: none;
}

.field.is-invalid .field__error {
  display: flex;
}

.field.is-invalid .field__control {
  border-color: var(--danger);
}

.field.is-invalid .field__icon {
  color: var(--danger);
}

/* An error replaces the hint rather than stacking under it: two lines of
   grey-and-red guidance about one input is one line too many. */
.field.is-invalid .field__hint {
  display: none;
}

/* Caps Lock. Sits between the control and the error slot, and only ever
   appears while a password field has focus. */
.field__caps {
  display: none;
  align-items: center;
  gap: var(--gap-inline-xs);
  color: var(--warning-text);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

.field__caps.is-on {
  display: flex;
}


/* ==========================================================================
   07 · CHECKBOX, META ROW & PASSWORD STRENGTH
   ========================================================================== */

/* Same construction as the catalogue's filter checkbox: the real input is
   present for the keyboard and the accessibility tree, and a box is drawn
   beside it. */
.check {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--gap-inline-sm);
  color: var(--fg-body);
  font-size: var(--text-md);
  line-height: var(--leading-snug);
  cursor: pointer;
}

.check input {
  position: absolute;
  opacity: 0;
  inline-size: 1px;
  block-size: 1px;
}

.check__box {
  flex: none;
  display: grid;
  place-items: center;
  inline-size: var(--space-5);
  block-size: var(--space-5);
  border: var(--border-thin) solid var(--border-strong);
  border-radius: var(--radius-xs);
  color: transparent;
  font-size: var(--icon-sm);
  transition: var(--transition-colors);
}

.check input:checked ~ .check__box {
  border-color: var(--brand);
  background: var(--brand);
  color: var(--fg-on-brand);
}

.check input:focus-visible ~ .check__box {
  outline: var(--ring-width) solid var(--ring-color);
  outline-offset: var(--ring-offset);
}

.check a {
  color: var(--brand-text);
  font-weight: var(--weight-bold);
}

.check a:hover {
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

/* The terms checkbox is a field in its own right — it can fail — so it
   gets the same invalid treatment as an input. */
.check-field.is-invalid .check__box {
  border-color: var(--danger);
}

/* Remember-me and forgot-password on one line. They are a pair: the first
   is what you set before submitting, the second the way out if you can't. */
.form-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-inline-md);
}

.form-meta__link {
  color: var(--brand-text);
  font-size: var(--text-md);
  font-weight: var(--weight-bold);
}

.form-meta__link:hover {
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

/* ---- Strength meter ---------------------------------------------------
   Four segments and a word. The word is what carries the meaning — the
   bars are a redundant, colour-only channel and are hidden from the
   accessibility tree. */
.strength {
  display: grid;
  gap: var(--space-2);
}

.strength__track {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-1);
}

.strength__seg {
  block-size: var(--space-1-5);
  border-radius: var(--radius-pill);
  background: var(--bg-surface-3);
  transition: background-color var(--duration-base) var(--ease-standard);
}

.strength[data-level="1"] .strength__seg:nth-child(-n + 1),
.strength[data-level="2"] .strength__seg:nth-child(-n + 2) {
  background: var(--danger);
}

.strength[data-level="3"] .strength__seg:nth-child(-n + 3) {
  background: var(--warning);
}

.strength[data-level="4"] .strength__seg {
  background: var(--success);
}

.strength__label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-inline-sm);
  color: var(--fg-subtle);
  font-size: var(--text-sm);
}

.strength__label b {
  font-weight: var(--weight-bold);
}

.strength[data-level="1"] .strength__label b,
.strength[data-level="2"] .strength__label b { color: var(--danger-text); }
.strength[data-level="3"] .strength__label b { color: var(--warning-text); }
.strength[data-level="4"] .strength__label b { color: var(--success-text); }


/* ==========================================================================
   08 · ONE-TIME-CODE BOXES
   ========================================================================== */

.verify-to {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gap-inline-sm);
  padding: var(--space-3) var(--space-4);
  border: var(--border-hairline) solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-surface-2);
  color: var(--fg-body);
  font-size: var(--text-md);
}

.verify-to b {
  direction: ltr;
  font-weight: var(--weight-bold);
  font-variant-numeric: tabular-nums;
}

.verify-to button {
  margin-inline-start: auto;
  display: inline-flex;
  align-items: center;
  gap: var(--gap-inline-xs);
  color: var(--brand-text);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
}

.verify-to button:hover {
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

/* LTR, always: a verification code is a number read left-to-right, and
   every SMS the visitor is comparing it against shows it that way. */
.code {
  direction: ltr;
  display: flex;
  justify-content: center;
  gap: clamp(var(--space-1-5), 2vw, var(--space-2-5));
}

.code__box {
  inline-size: clamp(2.5rem, 13vw, 3.25rem);
  block-size: clamp(3rem, 15vw, 3.75rem);
  border: var(--border-thin) solid var(--input-border);
  border-radius: var(--radius-md);
  background: var(--input-bg);
  color: var(--fg-default);
  font-family: inherit;
  font-size: var(--text-4xl);
  font-weight: var(--weight-bold);
  font-variant-numeric: tabular-nums;
  text-align: center;
  transition: var(--transition-colors), box-shadow var(--duration-fast) var(--ease-standard);
}

.code__box:focus {
  outline: none;
  border-color: var(--input-border-focus);
  box-shadow: var(--ring);
}

.code__box:not(:placeholder-shown) {
  border-color: var(--brand);
  background: var(--bg-brand-subtle);
}

.code.is-invalid .code__box {
  border-color: var(--danger);
}

.code__box::-webkit-outer-spin-button,
.code__box::-webkit-inner-spin-button {
  appearance: none;
  margin: 0;
}

/* The code group's error. Unlike a field error this one is written as bare
   text by the script, so it carries no icon and is styled to be invisible
   while it is empty rather than toggled with a class. */
.code-error {
  min-block-size: 1lh;
  color: var(--danger-text);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  text-align: center;
}

.code-error:empty {
  min-block-size: 0;
}

.resend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--gap-inline-sm);
  color: var(--fg-muted);
  font-size: var(--text-md);
}

.resend__timer {
  font-weight: var(--weight-bold);
  font-variant-numeric: tabular-nums;
  color: var(--fg-default);
}

.resend__btn {
  color: var(--brand-text);
  font-weight: var(--weight-bold);
}

.resend__btn:hover:not(:disabled) {
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

.resend__btn:disabled {
  color: var(--fg-subtle);
  cursor: not-allowed;
}

/* Back to the form the code was requested from. */
.verify-back {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-inline-xs);
  justify-self: center;
  color: var(--fg-muted);
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
}

.verify-back:hover {
  color: var(--fg-default);
}


/* ==========================================================================
   09 · SUBMIT, LOADING & DONE VIEW
   ========================================================================== */

/* A submit that is busy keeps its width — the label is replaced by a
   spinner of the same box, so the button does not resize mid-request and
   move whatever is under the cursor. */
.btn.is-loading {
  pointer-events: none;
  opacity: 0.85;
}

.btn__spinner {
  display: none;
  inline-size: 1.15em;
  block-size: 1.15em;
  border: var(--border-thick) solid oklch(1 0 0 / 0.35);
  border-block-start-color: currentColor;
  border-radius: var(--radius-circle);
  animation: btn-spin 720ms linear infinite;
}

.btn.is-loading .btn__spinner { display: block; }
.btn.is-loading .btn__label,
.btn.is-loading .icon { display: none; }

@keyframes btn-spin {
  to { rotate: 360deg; }
}

.auth-done {
  display: grid;
  justify-items: center;
  gap: var(--space-4);
  padding-block: var(--space-6);
  text-align: center;
}

.auth-done__mark {
  display: grid;
  place-items: center;
  inline-size: var(--space-16);
  block-size: var(--space-16);
  border-radius: var(--radius-circle);
  background: var(--success-subtle);
  color: var(--success-text);
  font-size: var(--icon-xl);
}

.auth-done__title {
  font-size: var(--text-4xl);
  font-weight: var(--weight-extrabold);
  color: var(--fg-default);
}

/* The script focuses this heading so the outcome is announced. That is a
   programmatic move, not a keyboard one, so it must not draw a ring —
   :focus-visible still does when someone actually tabs back to it. */
.auth-done__title:focus:not(:focus-visible) {
  outline: none;
}

.auth-done__text {
  max-inline-size: 42ch;
  color: var(--fg-muted);
  font-size: var(--text-lg);
  line-height: var(--leading-normal);
}

.auth-done__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--gap-inline-md);
  margin-block-start: var(--space-2);
}

/* Demo notice. This build has no server, so the page says so rather than
   pretending an account was created somewhere. */
.auth-note {
  display: flex;
  align-items: flex-start;
  gap: var(--gap-inline-sm);
  margin-block-start: var(--space-5);
  padding: var(--space-3) var(--space-4);
  border: var(--border-hairline) solid var(--border-default);
  border-radius: var(--radius-lg);
  background: var(--bg-surface-2);
  color: var(--fg-muted);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
}

.auth-note .icon {
  flex: none;
  margin-block-start: 0.15em;
  color: var(--fg-subtle);
}


/* ==========================================================================
   10 · RESPONSIVE
   ========================================================================== */

/* One column well before the panel gets narrow enough to squeeze the
   form: below this the two tracks would each be under 24rem, and the
   marketing copy would start hyphenating. */
@media (max-width: 68.75rem) {
  .auth__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-6);
    max-inline-size: 34rem;
    margin-inline: auto;
  }

  .auth-side__title {
    font-size: var(--text-3xl);
  }
}

@media (max-width: 36rem) {
  .auth {
    padding-block-start: var(--space-5);
  }

  .auth-card,
  .auth-side {
    border-radius: var(--radius-2xl);
    padding: var(--space-5);
  }

  /* Stacked, not side by side: at this width two method buttons on one
     row put "کد یک‌بارمصرف" on two lines. */
  .method {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
  }

  .auth-card__title {
    font-size: var(--text-3xl);
  }

  /* One column of benefit tiles, and a shorter stage: at this width the
     scene would otherwise eat half the first screenful of the panel. */
  .auth-side__list {
    grid-template-columns: minmax(0, 1fr);
  }

  .stage {
    block-size: 13rem;
    margin-block-end: var(--space-6);
  }

  .form-meta {
    align-items: flex-start;
    flex-direction: column;
    gap: var(--space-3);
  }
}


/* ==========================================================================
   11 · MOTION, CONTRAST & PRINT
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .js .auth-view:not([hidden]) {
    animation: none;
  }

  /* The scene keeps its depth — the rotations are static transforms — and
     loses only the bobbing. */
  .scene-card,
  .scene-coin,
  .scene-cube,
  .scene-pill,
  .scene-badge {
    animation: none;
  }

  .seg__thumb,
  .strength__seg {
    transition: none;
  }

  .btn__spinner {
    animation-duration: 2.4s;
  }
}

@media (prefers-contrast: more) {
  .auth-card,
  .field__control,
  .method__btn,
  .code__box {
    border-width: var(--border-thick);
    border-color: var(--fg-default);
  }

  .field__hint,
  .auth-card__foot {
    color: var(--fg-body);
  }
}

@media print {
  .auth-side,
  .seg,
  .method,
  .auth-card__foot {
    display: none;
  }
}
