/* ═══ the screens before there is a session ════════════════════════════════
   Sign in, first-run setup, choosing a company, the reset link and the gate a
   temporary password leads to — one frame, web/app/authshell.js.

   These were three centred forms on an empty page, which is what a debug tool
   looks like. They are also the first thing anybody ever sees of this product,
   and the only screens where somebody is deciding whether to trust it with
   their employees' bank details.

   ── THE SPLIT ─────────────────────────────────────────────────────────────
   The form on the left and the brand panel on the right (docs/47 §5.1): the
   form is the task, and the panel is what somebody looks at while they type.
   The panel is not a stock photograph. It carries three product cards drawn
   here in CSS — the outline of a payslip line, a register row and a
   filing-calendar chip, with no words or figures a screen change could make
   untrue — and a greeting: the time of day by India's clock, and whose door
   this is. Nothing else (docs/69). Under both, a liquid of three lights.

   Below 900px the two stack, form first. The panel does not disappear:
   somebody signing in on a phone is still greeted, and still sees whose door.

   ── THE MOTION ────────────────────────────────────────────────────────────
   docs/48 §C.2: one sequence on arrival, done inside 1.2 seconds; slow loops
   once it has settled; five answers to what a person does. Every
   keyframe runs FROM hidden TO the element's own resting style, and that
   resting style is visible — so if the animations never run, the screen is
   finished rather than empty, and nothing in the form is disabled, inert or
   out of reach while they do. Every duration is in tokens.css, the door's
   timeline in a block of its own there, in the order it plays, so the
   stylesheet can be read against the table it came from (docs/70 moved it
   there when the token test began reading durations).

   Reduced motion switches every one of them OFF, at the end of this file. It
   does not shorten them: a shortened entrance keeps its delay, and sits
   invisible for as long as the delay lasts (docs/51 §3). One thing still
   arrives: the greeting fades in, once, from the first frame — a fade is not
   a movement (docs/69).                                                        */

/* The auth screens are full bleed. `#outlet` is the same `.wrap` every section
   renders into — padded and centred — which is right for a page of tables and
   wrong for a split that should reach both edges of the window. */
body.bare .wrap{max-width:none; padding:0}

.auth{
  /* The timeline — docs/48 §C.2 as numbers — is in tokens.css ("the door's
     timeline"), with the liquid's three clocks, --liquid-a/b/c, which the bar
     shares (docs/70). What stays here is not a duration: */
  --door-bleed:24px;          /* the liquid's blur, so its edges run together */

  min-height:100vh;
  display:grid;
  grid-template-columns:minmax(400px, 46%) 1fr;
}

/* One entrance for everything the form side marks: opacity and an 8 px rise,
   from hidden to where the element already is. `backwards` holds the start
   during its delay; nothing holds the end, so a finished entrance leaves no
   animation on the element to fight a hover or a focus. */
.auth [data-enter]{animation:door-rise var(--door-rise) var(--ease) var(--at, 0ms) backwards}
@keyframes door-rise{from{opacity:0; translate:0 8px}}

/* ── the brand side ────────────────────────────────────────────────────── */
.auth-brand{
  position:relative; isolation:isolate;
  display:flex; flex-direction:column; justify-content:space-between; gap:32px;
  padding:40px 48px 40px;
  color:var(--on-brand);
  /* The ground: there from the first frame. Only the liquid arrives over it. */
  background:linear-gradient(160deg, var(--brand-1) 0%, var(--brand-2) 46%, var(--brand-3) 100%);
  overflow:hidden;
}
.auth-brand > *{position:relative; z-index:1}

/* ── the liquid ────────────────────────────────────────────────────────────
   Three soft lights over the ground — the indigo's own light, the accent,
   and the one cool note the tokens keep — each on a layer of its own so each
   can keep its own time: 24, 31 and 38 seconds a turn. They have a common
   multiple, as any three whole numbers do, but it is 14,136 seconds: the
   panel shows the same moment twice only every 3 h 55 min 36 s, and
   test_the_door.py works that out from this file and holds it above an hour.

   Each light is a box only as big as the light, turning about a point
   outside itself, so the light travels an orbit and turns its long axis as
   it goes, and swells a little on the far side. Linear, because a turn that
   eases stops four times a lap and water does not. Blurred, so the edges
   bleed into one another.

   What it costs is measured, because the form beside it must answer on
   time. The first draft turned three layers each bigger than the panel and
   screened them together, and a browser drawing without a graphics card —
   the walks' — fell from 60 frames a second to 21: the eye's 120 ms
   crossfade was still going at 220. Lights only as big as themselves gave
   back eleven frames; laying them over each other plainly instead of
   screening gave back the rest (56). The panel must stay the box the lights
   are positioned and clipped in, at every width.

   The greeting sits on it, and has to be read at its brightest.
   api/tools/design_tokens.py tries every light at its strongest and absent,
   in every combination, over every stop of the ground, and holds the
   greeting's white above the 3:1 WCAG asks of large text at the brightest
   of them — 3.51 with the strengths below. */
.auth-brand > .auth-mesh{
  position:absolute; inset:0; z-index:0; pointer-events:none;
  animation:door-mesh var(--door-mesh) var(--ease) backwards;
}
.auth-mesh i{position:absolute; filter:blur(var(--door-bleed))}
.auth-mesh i:nth-child(1){
  left:-14%; top:-13%; width:80%; height:66%;
  background:radial-gradient(closest-side,
    color-mix(in srgb, var(--brand-light) 56%, transparent) 0%, transparent 100%);
  transform-origin:62% 65%;
  animation:door-liquid-a var(--liquid-a) linear var(--door-settled) infinite;
}
.auth-mesh i:nth-child(2){
  left:36%; top:53%; width:72%; height:58%;
  background:radial-gradient(closest-side,
    color-mix(in srgb, var(--brand-cool) 40%, transparent) 0%, transparent 100%);
  transform-origin:36% 29%;
  animation:door-liquid-b var(--liquid-b) linear var(--door-settled) infinite;
}
.auth-mesh i:nth-child(3){
  left:35%; top:-9%; width:86%; height:70%;
  background:radial-gradient(closest-side,
    color-mix(in srgb, var(--brand-3) 64%, transparent) 0%, transparent 100%);
  transform-origin:36% 73%;
  animation:door-liquid-c var(--liquid-c) linear var(--door-settled) infinite;
}
@keyframes door-mesh{from{opacity:0}}
/* A lap each, swelling on the far side and back. The second light turns the
   other way, so the three are never simply a picture rotating. */
@keyframes door-liquid-a{25%{rotate:90deg; scale:1.06} 50%{rotate:180deg; scale:1.12} 75%{rotate:270deg; scale:1.06} to{rotate:360deg}}
@keyframes door-liquid-b{25%{rotate:-90deg; scale:1.08} 50%{rotate:-180deg; scale:1.04} 75%{rotate:-270deg; scale:1.1} to{rotate:-360deg}}
@keyframes door-liquid-c{25%{rotate:90deg; scale:.96} 50%{rotate:180deg; scale:1.08} 75%{rotate:270deg; scale:1.02} to{rotate:360deg}}

/* ── the product cards ─────────────────────────────────────────────────── */
.auth-cards{
  position:relative; width:100%; max-width:600px; margin:6px auto 0;
  height:clamp(220px, 38vh, 350px);
}
.pcard{
  position:absolute; padding:12px 16px 12px; border-radius:var(--r-lg);
  background:color-mix(in srgb, var(--on-brand) 97%, transparent);
  box-shadow:0 1px 0 color-mix(in srgb, var(--on-brand) 70%, transparent) inset, var(--shadow-brand);
  /* In perspective, all three turned the same way, so they read as planes
     receding rather than as three cards thrown on a table. */
  transform:perspective(1300px) rotateX(14deg) rotateY(-22deg) rotateZ(4deg);
  animation:door-card var(--door-card) var(--ease) var(--at) backwards;
}
/* Back to front, each a little paler, and overlapping only at a corner — the
   first draft stacked them half over each other, and a translucent card over
   a grid of cells reads as a smudge, not as depth. */
.pcard.cal{
  top:0; right:0; width:42%; height:56%;
  background:color-mix(in srgb, var(--on-brand) 82%, transparent);
  --at:var(--door-cards-at);
}
.pcard.reg{
  top:23%; left:29%; width:45%; height:51%;
  background:color-mix(in srgb, var(--on-brand) 91%, transparent);
  --at:calc(var(--door-cards-at) + var(--door-card-gap));
}
.pcard.slip{
  top:46%; left:0; width:46%; height:54%;
  --at:calc(var(--door-cards-at) + 2 * var(--door-card-gap));
}
@keyframes door-card{from{opacity:0; translate:0 14px; scale:.97}}

/* The float is on an inner layer, so it composes with the entrance on the
   card itself instead of replacing it. */
.pfloat{
  height:100%; display:flex; flex-direction:column; gap:8px;
  animation:door-float var(--door-float) ease-in-out infinite;
}
.pcard.cal .pfloat{animation-delay:var(--door-settled)}
.pcard.reg .pfloat{animation-delay:calc(var(--door-settled) + var(--door-float-gap))}
.pcard.slip .pfloat{animation-delay:calc(var(--door-settled) + 2 * var(--door-float-gap))}
@keyframes door-float{25%{translate:0 -4px} 75%{translate:0 4px}}

/* Inside a card every class starts pc- — see the note on CARDS in authshell.js
   for the two names the first draft borrowed by accident. */
.pcard i, .pcard b{display:block; border-radius:var(--r-full)}
.pc-bar{height:7px; background:color-mix(in srgb, var(--brand-2) 17%, var(--on-brand))}
.pcard .w30{width:30%} .pcard .w35{width:35%} .pcard .w40{width:40%}
.pcard .w45{width:45%} .pcard .w50{width:50%} .pcard .w55{width:55%}

.pc-head{display:flex; align-items:center; gap:8px; margin-bottom:2px}
.pc-head .pc-bar{height:9px; background:color-mix(in srgb, var(--brand-2) 34%, var(--on-brand))}
.pc-head .pc-dot{width:9px; height:9px; margin-left:auto; background:var(--brand-cool)}
.pcard .pc-logo{
  width:20px; height:20px; border-radius:var(--r-sm); flex:none;
  background:linear-gradient(135deg, var(--brand-2), var(--brand-3));
}

/* a payslip: labels, amounts, and the net pay underlined by its weight */
.pc-line{
  display:flex; align-items:center; justify-content:space-between; padding:4px 0 6px;
  border-bottom:1px solid color-mix(in srgb, var(--brand-2) 11%, transparent);
}
.pc-amt{width:18%; height:7px; background:color-mix(in srgb, var(--brand-2) 36%, var(--on-brand))}
.pc-line.net{border-bottom:0; padding-top:6px}
.pc-line.net .pc-bar{height:9px; background:color-mix(in srgb, var(--brand-2) 42%, var(--on-brand))}
.pc-line.net .pc-amt{width:27%; height:11px; background:var(--brand-3)}

/* a register: a head row and three rows, each closed by a tick */
.pc-row{
  display:grid; grid-template-columns:1.5fr 1fr 1fr 14px; gap:8px; align-items:center;
  padding:4px 0 6px; border-bottom:1px solid color-mix(in srgb, var(--brand-2) 11%, transparent);
}
.pc-row:last-child{border-bottom:0}
.pc-row i{height:6px; background:color-mix(in srgb, var(--brand-2) 18%, var(--on-brand))}
.pc-row.th i{height:5px; background:color-mix(in srgb, var(--brand-2) 40%, var(--on-brand))}
.pcard .pc-row b{
  width:10px; height:5px; margin:0 0 2px 2px; border-radius:0;
  border-left:2px solid var(--brand-3); border-bottom:2px solid var(--brand-3);
  rotate:-45deg;
}

/* a filing calendar: three weeks, one date due, and its chip */
.pc-cal{display:grid; grid-template-columns:repeat(7, 1fr); gap:4px}
.pcard .pc-cal i{aspect-ratio:1; border-radius:var(--r-xs); background:color-mix(in srgb, var(--brand-2) 13%, var(--on-brand))}
.pcard .pc-cal i.due{
  background:var(--brand-3);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--brand-3) 24%, transparent);
}
.pc-chip{
  display:flex; align-items:center; gap:6px; margin-top:auto; width:66%;
  padding:6px 8px; border-radius:var(--r-full);
  background:color-mix(in srgb, var(--brand-cool) 26%, var(--on-brand));
}
.pc-chip .pc-dot{width:7px; height:7px; flex:none; background:var(--brand-cool)}
.pc-chip .pc-bar{flex:1; height:6px; background:color-mix(in srgb, var(--brand-cool) 45%, var(--brand-2))}

/* ── the greeting ──────────────────────────────────────────────────────────
   Good morning, Good afternoon or Good evening by India's clock, and under
   it whose door this is — the company this address answers for, or Vetan.
   Set in the display size where a heading and three claims used to be, in
   the regular weight: it is said quietly. Both lines are large text as WCAG
   counts it (24px and up at 400), which is what the liquid's ceiling above
   is worked out for. */
.auth-greeting{margin:0; color:var(--on-brand)}
.auth-greeting span{display:block; width:fit-content}
.auth-greeting .hello{font-size:var(--fs-display); line-height:1.08; letter-spacing:-.025em; font-weight:400}
.auth-greeting .place{margin-top:12px; font-size:var(--fs-2xl); line-height:1.3; font-weight:400}

/* It takes the slot the claims' ticks held, and draws itself as text: a soft
   edge carried left to right across each line, the way a pen puts words
   down. The mask exists only inside the keyframes — three widths wide, its
   first third opaque — so at rest there is none, and a line whose animation
   never runs is simply there. */
.auth-greeting .hello{animation:door-write var(--door-greet) var(--ease) var(--door-greet-at) backwards}
.auth-greeting .place{animation:door-write var(--door-place) var(--ease) var(--door-place-at) backwards}
@keyframes door-write{
  from{
    -webkit-mask-image:linear-gradient(90deg, black 33.3%, transparent 46.7%);
    mask-image:linear-gradient(90deg, black 33.3%, transparent 46.7%);
    -webkit-mask-size:300% 100%; mask-size:300% 100%;
    -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
    -webkit-mask-position:70% 0; mask-position:70% 0;
  }
  to{
    -webkit-mask-image:linear-gradient(90deg, black 33.3%, transparent 46.7%);
    mask-image:linear-gradient(90deg, black 33.3%, transparent 46.7%);
    -webkit-mask-size:300% 100%; mask-size:300% 100%;
    -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
    -webkit-mask-position:0 0; mask-position:0 0;
  }
}
/* The panel stays put when the form changes. If the hour turns while the
   page is open, or a screen names the company, the greeting changes quietly. */
.auth-greeting.door-swap{animation:door-fade var(--door-submit) var(--ease)}
@keyframes door-fade{from{opacity:0}}

/* ── the form side ─────────────────────────────────────────────────────── */
.auth-panel{
  display:flex; align-items:center; justify-content:center;
  padding:48px 40px; background:var(--plane);
}
.auth-form{width:100%; max-width:380px}
.auth-form.wide{max-width:620px}

.auth-mark{display:flex; align-items:center; gap:12px; margin:0 0 32px}
.auth-mark .glyph{
  width:40px; height:40px; border-radius:var(--r); flex:none;
  display:grid; place-items:center; color:var(--on-brand);
  background:linear-gradient(135deg, var(--brand-2), var(--brand-3));
  box-shadow:var(--shadow);
}
.auth-mark .name{font-size:var(--fs-xl); font-weight:600; letter-spacing:-.015em; line-height:1.1; color:var(--ink)}

.auth-heading{margin:0 0 24px}
.auth-form h1{font-size:var(--fs-3xl); letter-spacing:-.015em; margin:0 0 6px}
.auth-form .lede{color:var(--ink-2); font-size:var(--fs-md); line-height:1.6; margin:0}
.auth-heading .note{margin-top:12px}
/* The company this address belongs to, when the instance answers for one —
   quieter than the heading, and wearing the logo the company already chose
   for its payslips. */
.auth-company{display:flex; align-items:center; gap:8px; margin:2px 0 0; font-size:var(--fs-md); color:var(--ink-2)}
.auth-company img{width:24px; height:24px; object-fit:contain; border-radius:var(--r-sm); background:var(--surface)}
.auth-company b{color:var(--ink); font-weight:600}

.auth-form .field{margin-bottom:16px}
.auth-form input, .auth-form select{padding:8px 12px; font-size:var(--fs-md)}
/* Focus lifts the label a little and makes it smaller, in the accent. */
.auth-form .field > label{
  transform-origin:0 100%;
  transition:translate var(--door-focus) var(--ease), scale var(--door-focus) var(--ease),
             color var(--door-focus) var(--ease);
}
.auth-form .field:focus-within > label{translate:0 -2px; scale:.94; color:var(--accent-ink)}

/* The ring grows from the field's leading edge. It is drawn at full size and
   revealed left to right: a ring scaled into place would squash its own
   corners on the way. The field's instant ring from base.css gives way to it. */
.ctl{position:relative}
.auth-form .ctl > input:focus, .auth-form .ctl > select:focus{box-shadow:none}
.ctl > .ring{
  position:absolute; inset:-3px; pointer-events:none;
  border:3px solid color-mix(in srgb, var(--accent) 24%, transparent);
  border-radius:calc(var(--r-sm) + 3px);
  clip-path:inset(0 100% 0 0 round calc(var(--r-sm) + 3px));
  transition:clip-path var(--door-focus) var(--ease);
}
.ctl > :focus ~ .ring{clip-path:inset(0 0 0 0 round calc(var(--r-sm) + 3px))}

/* ── the reveal button ─────────────────────────────────────────────────────
   Ours, not the browser's. Edge draws a native one that is absent until the
   field has content, vanishes when a password manager claims the same corner,
   and does not exist at all in Firefox or Safari — reported as "the view
   password is disappearing in the middle", which is precisely what it does.
   The native control is hidden so the two cannot both appear.

   An eye rather than the words Show and Hide (docs/48 §C.1): a fixed square,
   so nothing moves under the pointer between one click and the next, with the
   two eyes stacked in it and crossfading. The name it is read by changes with
   the state. */
.withreveal{display:flex; align-items:center}
.withreveal > input{padding-right:48px}
.withreveal > input::-ms-reveal,
.withreveal > input::-ms-clear{display:none}
.reveal{
  position:absolute; right:5px;
  width:34px; height:34px; padding:0; border:0; border-radius:var(--r-sm);
  display:grid; place-items:center;
  background:none; color:var(--ink-3); cursor:pointer;
}
.reveal svg{grid-area:1 / 1; transition:opacity var(--door-reveal) var(--ease)}
.reveal .shut,
.reveal[aria-pressed="true"] .open{opacity:0}
.reveal[aria-pressed="true"] .shut{opacity:1}
.reveal:hover{color:var(--accent-ink); background:var(--accent-wash)}
.reveal:focus-visible{outline:none; box-shadow:var(--ring); color:var(--accent-ink)}

/* ── keep me signed in · forgot password ───────────────────────────────── */
.auth-row{display:flex; align-items:flex-start; justify-content:space-between; gap:12px; margin:2px 0 20px}
.auth-form .remember{
  display:grid; grid-template-columns:auto 1fr; column-gap:8px; align-items:center;
  margin:0; font-size:var(--fs-sm); color:var(--ink-2); cursor:pointer; line-height:1.35;
}
.auth-form .remember input{width:auto; margin:0; padding:0; accent-color:var(--accent)}
/* What the box does, where the box is. Thirty days is the trade being made. */
.auth-form .remember small{grid-column:2; font-size:var(--fs-xs); color:var(--ink-3); margin-top:2px}
.auth-form .forgot{
  font-size:var(--fs-sm); font-weight:600; color:var(--accent-ink); white-space:nowrap; line-height:1.35;
  border-bottom:1.5px solid transparent; transition:border-color var(--fast) var(--ease);
}
.auth-form .forgot:hover{border-bottom-color:var(--accent)}

/* ── the button ────────────────────────────────────────────────────────── */
.auth-form .btn{width:100%; justify-content:center; padding:12px 16px; font-size:var(--fs-md)}
/* While the request is out the label slides up and away and a spinner slides
   in from below. The spinner is positioned over the label rather than beside
   it, so the button keeps its size and nothing on the page reflows. */
.auth-submit{position:relative; overflow:hidden}
.auth-submit .btn-label{
  display:block;
  transition:translate var(--door-submit) var(--ease), opacity var(--door-submit) var(--ease);
}
.auth-submit .btn-spin{
  position:absolute; left:50%; top:50%; width:18px; height:18px; margin:-8px 0 0 -8px;
  border-radius:50%;
  border:2px solid color-mix(in srgb, var(--on-accent) 32%, transparent);
  border-top-color:var(--on-accent);
  opacity:0; translate:0 140%;
  transition:translate var(--door-submit) var(--ease), opacity var(--door-submit) var(--ease);
}
.auth-submit.busy .btn-label{translate:0 -140%; opacity:0}
.auth-submit.busy .btn-spin{translate:0 0; opacity:1; animation:door-spin var(--spin) linear infinite}
.auth-submit.busy[disabled]{opacity:1; cursor:progress}
/* The throttle's countdown owns the label, and it has to be read: a person who
   cannot see their wait lengthening is lengthening it. */
.auth-submit.waiting[disabled]{opacity:.74}
@keyframes door-spin{to{rotate:1turn}}

.auth-error:not(:empty){margin-top:12px}
.auth-note{margin:24px 0 0; font-size:var(--fs-sm); line-height:1.6; color:var(--ink-3)}
.auth-note + .auth-note{margin-top:8px}
.auth-note a{color:var(--accent-ink); font-weight:600}
/* Read to a screen reader, never shown: what the busy button is doing. */
.auth-live{position:absolute; width:1px; height:1px; margin:0; overflow:hidden; clip-path:inset(50%); white-space:nowrap}

/* A refusal: 4 px, three times over, 320 ms. */
.door-shake{animation:door-shake var(--door-shake) ease-in-out}
@keyframes door-shake{
  8.33%{translate:-4px 0} 25%{translate:4px 0} 41.67%{translate:-4px 0}
  58.33%{translate:4px 0} 75%{translate:-4px 0} 91.67%{translate:4px 0}
}

/* Choosing a company: a list of real choices, not a grid of cards. Each one
   enters on the same curve as the form it replaced. */
.company{
  display:flex; align-items:center; gap:12px; width:100%; text-align:left;
  padding:12px 16px; border:1px solid var(--line); border-radius:var(--r-lg);
  background:var(--surface); margin-bottom:8px;
  transition:border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease),
             transform var(--fast) var(--ease);
}
.company:hover{border-color:var(--accent); box-shadow:var(--ring); transform:translateY(-1px)}
.company .initials{
  width:36px; height:36px; border-radius:var(--r-sm); flex:none; display:grid; place-items:center;
  background:var(--accent-wash); color:var(--accent-ink);
  font-size:var(--fs-sm); font-weight:600; letter-spacing:.01em;
}
/* Block, not inline. As inline spans the name and the role ran together on one
   line — "Sharma & Co LLP admin" — which reads as a company whose name ends in
   the word admin. */
.company .nm{display:block; font-size:var(--fs-base); font-weight:500; letter-spacing:0}
.company .role{display:block; font-size:var(--fs-sm); color:var(--ink-3); margin-top:2px}
.company .go{margin-left:auto; color:var(--ink-3)}

/* Setup is longer than the others, so it scrolls its own side while the panel
   holds still beside it. */
.auth.setup{grid-template-columns:1fr minmax(320px, 34%)}
.auth.setup .auth-panel{align-items:flex-start; padding-top:48px; padding-bottom:64px}
.auth.setup .auth-brand{position:sticky; top:0; height:100vh}
.auth.setup .auth-cards{height:clamp(190px, 30vh, 270px)}

/* ── leaving: signing in as a transition, not a page swap ──────────────────
   authshell.js's leaveDoor lifts the frame out of the page into this fixed
   layer. The form fades and rises 12 px, the frame fades, and the product's
   bar fades in underneath. The frame's own animations are off, so moving it
   restarts none of them. */
.door-leaving{
  position:fixed; left:0; right:0; top:0; z-index:75; pointer-events:none;
  animation:door-out var(--door-leave) var(--ease) forwards;
}
.door-leaving .auth-form{animation:door-lift var(--door-leave) var(--ease) forwards}
.door-leaving [data-enter], .door-leaving .auth-mesh, .door-leaving .auth-mesh i,
.door-leaving .pcard, .door-leaving .pfloat, .door-leaving .auth-greeting,
.door-leaving .auth-greeting span{animation:none}
@keyframes door-out{to{opacity:0}}
@keyframes door-lift{to{opacity:0; translate:0 -12px}}
body.door-arriving .bar{animation:door-fade var(--slow) var(--ease) backwards}

@media (max-width:900px){
  .auth, .auth.setup{grid-template-columns:1fr}
  .auth-panel, .auth.setup .auth-panel{align-items:flex-start; padding:32px 20px 40px}
  /* Relative, not static. Static undid the setup panel's stickiness and also
     stopped the panel being the box its mesh is positioned and clipped in:
     the mesh's two oversized layers then spread over the form and 56 px past
     the edge of a 400 px screen. */
  .auth-brand, .auth.setup .auth-brand{
    position:relative; height:auto; padding:32px 20px 64px; gap:16px;
  }
  .auth-cards, .auth.setup .auth-cards{display:none}
  .auth-greeting .hello{font-size:var(--fs-4xl)}
}

/* ── reduced motion: off, not faster ───────────────────────────────────────
   Every animation and transition above, by the selector that declared it, so
   none can outrank its own switch. The page is its final state from the first
   frame — the liquid a still gradient, the cards where they rest — and
   walk71 opens it with the preference set and checks exactly that.

   Except the greeting, which fades in once: opacity only, from the first
   frame, no delay, over the time the liquid takes to arrive. base.css cuts
   every animation to nothing under this preference; this one is meant, so
   it says so with its own duration. */
@media (prefers-reduced-motion: reduce){
  .auth [data-enter], .auth-brand > .auth-mesh,
  .auth-mesh i:nth-child(1), .auth-mesh i:nth-child(2), .auth-mesh i:nth-child(3),
  .pcard, .pfloat, .auth-greeting .hello, .auth-greeting .place,
  .auth-greeting.door-swap, .door-shake,
  .door-leaving, .door-leaving .auth-form, .auth-submit.busy .btn-spin,
  body.door-arriving .bar{animation:none}
  .auth-greeting{animation:door-fade var(--door-mesh) var(--ease); animation-duration:var(--door-mesh) !important}
  .auth-form .field > label, .ctl > .ring, .reveal svg,
  .auth-submit .btn-label, .auth-submit .btn-spin{transition:none}
  /* busy, without the slide: the label stays and says what is happening */
  .auth-submit.busy .btn-label{translate:none; opacity:1}
  .auth-submit.busy .btn-spin{display:none}
}

/* ── single sign-on's place in the form (docs/51 kept it; docs/65 fills it) ── */
.sso-buttons{display:grid;gap:8px;margin:0 0 16px}
.sso-buttons .btn.sso{display:flex;flex-direction:column;align-items:center;gap:0;padding:8px 16px}
.sso-buttons .btn.sso small{font-size:var(--fs-xs);color:var(--ink-3);font-weight:400}
.sso-buttons[hidden]{display:none}
