/*
 * The sign-in screen (Auth.js) — the hero, the provider buttons, the email
 * form and the foot.
 *
 * Constrained to the shell width rather than the window, same as every other
 * takeover; two layers that stay apart for the reason the onboarding's do —
 * `.auth` fades and is the ground, `.auth__sheet` rises.
 *
 * Everything it draws is the app's own material. The wordmark is the app
 * bar's, three sizes up; the fields are the search overlay's `.search-field`
 * card with a glyph in it; the submit is the onboarding's `.ob-cta`, spinner
 * and all; the mode switch is `.segmented`; the crests are `Logo` discs. What
 * is new here is the hero's scatter, the provider buttons, and the divider.
 *
 * Motion is all off two attributes. `data-open` on the root runs the
 * entrance as one choreography: the crests spring onto the arc, and each
 * block under them — wordmark, title, subtitle, card, foot — rises 8px
 * through a fade one `--stagger-step` after the last, so the screen
 * assembles top to bottom rather than appearing. `data-leaving` runs the
 * exit the other way, lifting the sheet out. Inside the card, rows that
 * come and go fold through the accordion's grid collapse, a button's
 * success is a checkmark drawing in, and a refused field shakes with the
 * shared `is-invalid`. Transform and opacity only; the tokens own every
 * duration, and reduced motion zeroes them.
 */

.auth {
  --enter-y: 12px;

  position: fixed;
  inset: 0;
  /* Above the onboarding's 101: a first run opens both, and this one is answered first. */
  z-index: 102;
  display: flex;
  max-width: var(--app-max-width);
  margin-inline: auto;
  background: var(--bg);
  opacity: 0;
  transition: opacity var(--duration) var(--easing);
}

.auth[hidden] {
  display: none;
}

.auth[data-open="true"] {
  --enter-y: 0px;

  opacity: 1;
}

.auth__sheet {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding-top: var(--safe-top);
  transform: translateY(var(--enter-y)) scale(var(--enter-scale, 1));
  transition: transform var(--duration) var(--easing);
}

/* Leaving lifts and shrinks a touch, the way a sheet hands off to the page
   under it — not sinking back the way it arrived, which would read as a
   cancel. Only ever set while `data-open` is false. */
.auth[data-leaving="true"] {
  --enter-y: -8px;
  --enter-scale: 0.985;
}

.auth__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-4) var(--space-4) calc(var(--space-6) + var(--safe-bottom));
}

/* --- Hero ----------------------------------------------------------------- */

.auth-hero {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding-top: 112px;
  text-align: center;
}

/*
 * The choreography. Every block that is not a crest starts 8px low and
 * clear, and rises into place on `--duration` with `--easing` — the tab
 * switch's own arrival — one stagger step after the block above it. The
 * crests lead (their delays are below), so the sequence reads: the badges,
 * the name, the claim, the card, the foot. `--i` is the block's place in
 * the line, set per block below; the delay is computed from it here once.
 */
.auth-hero__mark,
.auth-hero__title,
.auth-hero__subtitle,
.auth-card,
.auth-foot {
  opacity: 0;
  transform: translateY(8px);
  transition:
    opacity var(--duration) var(--easing),
    transform var(--duration) var(--easing);
  transition-delay: calc(var(--stagger-step) * (6 + var(--i, 0)));
}

.auth-hero__mark { --i: 0; }
.auth-hero__title { --i: 1; }
.auth-hero__subtitle { --i: 2; }
.auth-card { --i: 3; }
.auth-foot { --i: 5; }

.auth[data-open="true"] .auth-hero__mark,
.auth[data-open="true"] .auth-hero__title,
.auth[data-open="true"] .auth-hero__subtitle,
.auth[data-open="true"] .auth-card,
.auth[data-open="true"] .auth-foot {
  opacity: 1;
  transform: translateY(0);
}

/* Leaving, everything goes together with the sheet — no reverse stagger,
   which would hold the page hostage for a quarter second on the way out. */
.auth[data-leaving="true"] .auth-hero__mark,
.auth[data-leaving="true"] .auth-hero__title,
.auth[data-leaving="true"] .auth-hero__subtitle,
.auth[data-leaving="true"] .auth-card,
.auth[data-leaving="true"] .auth-foot {
  transition-delay: 0ms;
}

/*
 * Seven crests on an arc over the wordmark, each on the tray's disc. Slots
 * are placed by hand — a formula would space them evenly, and evenly spaced
 * badges read as a menu, not a crowd. The outer ones sit lower and fainter
 * so the arc has depth; the middle one, highest, is the peak.
 */
.auth-hero__crests {
  position: absolute;
  top: 0;
  left: 50%;
  width: 320px;
  height: 120px;
  transform: translateX(-50%);
  pointer-events: none;
}

.auth-hero__crest {
  position: absolute;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-card);
  opacity: 0;
  transform: translateY(14px) scale(0.6);
  /* Objects arriving, so the spring: they land with a little overshoot, the
     way the onboarding tray's crests pop in. The fade is plain. */
  transition:
    opacity var(--duration) var(--easing),
    transform var(--spring-duration) var(--spring);
}

.auth[data-open="true"] .auth-hero__crest {
  opacity: 1;
  transform: translateY(0) scale(1);
}

/*
 * Once landed, the badges drift — a slow bob, each on its own phase so the
 * arc never moves as one. On the picture inside the disc, not the disc:
 * the disc's transform is the entrance's, and a keyframe on the same
 * element would outrank it and swallow the spring. The only thing on this
 * screen that moves on its own, and it is decorative, so reduced motion
 * takes it off entirely.
 */
.auth-hero__crest .logo {
  animation: auth-float 4.2s ease-in-out infinite alternate;
  animation-delay: calc(var(--phase, 0) * -0.7s);
}

.auth-hero__crest[data-slot="1"] .logo,
.auth-hero__crest[data-slot="5"] .logo { --phase: 1; }
.auth-hero__crest[data-slot="2"] .logo,
.auth-hero__crest[data-slot="4"] .logo { --phase: 2; }
.auth-hero__crest[data-slot="3"] .logo { --phase: 3; }
.auth-hero__crest[data-slot="6"] .logo { --phase: 4; }

@keyframes auth-float {
  from {
    transform: translateY(-1.5px);
  }
  to {
    transform: translateY(1.5px);
  }
}

/* The crest on no plate of its own — the disc is the plate, the onboarding
   tile's own arrangement. */
.auth-hero__crest .logo:not(.logo--monogram) {
  background: none;
  border-radius: 0;
}

.auth-hero__crest .logo--monogram {
  border-radius: var(--radius-full);
}

.auth-hero__crest[data-slot="0"] { left: 0; top: 64px; opacity: 0; transition-delay: calc(var(--stagger-step) * 1); }
.auth-hero__crest[data-slot="1"] { left: 46px; top: 30px; transition-delay: calc(var(--stagger-step) * 2); }
.auth-hero__crest[data-slot="2"] { left: 96px; top: 8px; transition-delay: calc(var(--stagger-step) * 3); }
.auth-hero__crest[data-slot="3"] { left: 137px; top: 0; width: 52px; height: 52px; transition-delay: calc(var(--stagger-step) * 4); }
.auth-hero__crest[data-slot="4"] { left: 184px; top: 8px; transition-delay: calc(var(--stagger-step) * 5); }
.auth-hero__crest[data-slot="5"] { left: 232px; top: 30px; transition-delay: calc(var(--stagger-step) * 6); }
.auth-hero__crest[data-slot="6"] { left: 274px; top: 64px; transition-delay: calc(var(--stagger-step) * 7); }

.auth[data-open="true"] .auth-hero__crest[data-slot="0"],
.auth[data-open="true"] .auth-hero__crest[data-slot="6"] {
  opacity: 0.75;
}

/* No stagger on the way out, for the same reason the blocks have none. */
.auth[data-leaving="true"] .auth-hero__crest {
  transition-delay: 0ms;
}

/* The app bar's wordmark, three sizes up: this screen is the brand's one moment. */
.auth-hero__mark .wordmark {
  --mark-height: 34px;
}

.auth-hero__mark .wordmark__text {
  font-size: 30px;
}

.auth-hero__title {
  font-size: var(--text-xl);
  font-weight: var(--weight-bold);
  letter-spacing: -0.02em;
  line-height: 1.2;
  text-wrap: balance;
}

.auth-hero__subtitle {
  max-width: 32ch;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  line-height: 1.45;
  text-wrap: pretty;
}

/* --- Stage and the two cards ------------------------------------------------------ */

/*
 * The sign-in card and the reset panel, one in the layout at a time. The
 * switch is the onboarding's step switch: the leaving card fades on the
 * press timing, the arriving one rises 8px through its fade on the
 * ordinary duration, never both at once.
 */
.auth__stage > .auth-card[hidden] {
  display: none;
}

.auth__stage > .auth-card[data-state="leave"] {
  opacity: 0;
  transition-duration: var(--duration-press);
}

.auth__stage > .auth-card[data-state="enter"] {
  opacity: 0;
  transform: translateY(8px);
}

/* The entrance choreography is the sign-in card's; the reset panel arrives
   by the switch above, so once the gate is open it is exempt. */
.auth[data-open="true"] .auth-reset {
  transition:
    opacity var(--duration) var(--easing),
    transform var(--duration) var(--easing);
  transition-delay: 0ms;
}

/* --- Card ------------------------------------------------------------------- */

.auth-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-card);
}

.auth-providers {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/*
 * A provider button: the card's own height and radius, the brand mark in a
 * fixed slot on the left, the label centred across the whole width so the
 * two buttons' labels line up whatever their marks. A hairline rather than
 * the accent — the accent is the email submit's, the one button that is
 * ours; these carry someone else's brand.
 */
.auth-provider {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 50px;
  padding-inline: 52px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  color: var(--text);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  transition:
    background-color var(--duration-press) var(--easing),
    border-color var(--duration-press) var(--easing);
}

.auth-provider[data-pressed="true"] {
  background: var(--surface-sunken);
}

.auth-provider__mark {
  position: absolute;
  top: 50%;
  left: 14px;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  transform: translateY(-50%);
}

.auth-mark {
  display: block;
}

/* Inside Telegram the button is the person: tinted, and the mark is their face. */
.auth-provider--telegram[data-person="true"] {
  background: var(--accent-soft);
  border-color: transparent;
  color: var(--accent);
}

.auth-provider--telegram[data-person="true"][data-pressed="true"] {
  background: var(--accent-tint);
}

.auth-provider__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: opacity var(--duration) var(--easing);
}

.auth-provider__spinner {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 18px;
  height: 18px;
  margin: -9px 0 0 -9px;
  border: 2px solid rgb(var(--text-rgb) / 0.15);
  border-top-color: var(--text);
  border-radius: var(--radius-full);
  opacity: 0;
  transition: opacity var(--duration) var(--easing);
}

.auth-provider[data-loading="true"] .auth-provider__label {
  opacity: 0;
}

.auth-provider[data-loading="true"] .auth-provider__spinner {
  opacity: 1;
  animation: boot-spin 0.9s linear infinite;
}

/* Done: the label gives way to the checkmark, drawn in the success colour. */
.auth-provider[data-state="done"] .auth-provider__label {
  opacity: 0;
}

.auth-provider[data-state="done"] {
  border-color: var(--success);
}

/*
 * The checkmark on a button: centred where the label was, two legs on a
 * dash offset, drawn on `[data-state="done"]` with the spring timing and the
 * plain ease — a line being drawn does not overshoot. 20 is the path's
 * length, rounded up.
 */
.auth-check {
  position: absolute;
  top: 50%;
  left: 50%;
  margin: -11px 0 0 -11px;
  opacity: 0;
  pointer-events: none;
}

.auth-check__tick {
  fill: none;
  stroke: var(--success-strong);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 20;
  stroke-dashoffset: 20;
}

.auth-check--inverse .auth-check__tick {
  stroke: var(--text-inverse);
}

[data-state="done"] .auth-check {
  opacity: 1;
}

[data-state="done"] .auth-check__tick {
  animation: auth-draw var(--spring-duration) var(--easing) forwards;
}

@keyframes auth-draw {
  to {
    stroke-dashoffset: 0;
  }
}

/* A provider's refusal, above the buttons it belongs to. It arrives with
   the shake the field errors get, so the eye is sent to it. */
.auth-error {
  padding: var(--space-2) var(--space-3);
  background: var(--error-soft);
  border-radius: var(--radius-sm);
  color: var(--error-strong);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  line-height: 1.4;
  animation: shake var(--duration-slow) var(--easing);
}

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

/* --- Divider ------------------------------------------------------------------ */

.auth-divider {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  color: var(--text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
}

.auth-divider::before,
.auth-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}

/* --- Form -------------------------------------------------------------------- */

.auth-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.auth-form .segmented {
  margin-bottom: var(--space-1);
}

/*
 * A row that folds. The accordion's collapse — grid-template-rows 1fr → 0fr,
 * the inner clipped, the fade on the same duration — so the fields under it
 * slide rather than jump. The gap the row would leave goes with it: the
 * form's gap is on the wrapper's neighbours, and the inner carries no
 * margin of its own, so a folded row is zero tall and takes its gap along.
 */
.auth-collapse {
  display: grid;
  grid-template-rows: 1fr;
  transition:
    grid-template-rows var(--duration) var(--easing),
    opacity var(--duration) var(--easing),
    margin-top var(--duration) var(--easing);
}

.auth-collapse__inner {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

.auth-collapse[data-collapsed="true"] {
  grid-template-rows: 0fr;
  margin-top: calc(-1 * var(--space-3));
  opacity: 0;
  pointer-events: none;
}

/* The forgot link's own pull-up, kept when it folds so the two do not add. */
.auth-collapse:has(.auth-forgot) {
  margin-top: calc(-1 * var(--space-1));
}

.auth-collapse:has(.auth-forgot)[data-collapsed="true"] {
  margin-top: calc(-1 * var(--space-3) - var(--space-1));
}

.auth-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

/* First and last name on one line, each field half the width. A message
   under either sits under its own half. */
.auth-names {
  display: grid;
  /* minmax(0, …): an input's intrinsic width would otherwise hold each
     column open past its half and push the second field off the card. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-2);
}

.auth-names .auth-field {
  min-width: 0;
}

.auth-names .auth-field__box {
  padding-inline: var(--space-3) var(--space-2);
}

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

/* The search overlay's field, grounded on the card: sunken rather than
   floating, and the focus ring on the box for the reason its own comment gives. */
.auth-field__box {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  height: 48px;
  padding-inline: var(--space-3);
  background: var(--surface-sunken);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  cursor: text;
  transition:
    border-color var(--duration-press) var(--easing),
    background-color var(--duration-press) var(--easing);
}

.auth-field__box:focus-within {
  background: var(--surface);
  border-color: var(--accent);
}

.auth-field[data-invalid="true"] .auth-field__box {
  border-color: var(--error);
}

.auth-field__icon {
  flex: none;
  display: grid;
  place-items: center;
  color: var(--text-muted);
}

.auth-field__box:focus-within .auth-field__icon {
  color: var(--accent);
}

.auth-field__input {
  flex: 1;
  min-width: 0;
  height: 100%;
  border: 0;
  background: none;
  color: var(--text);
  font-size: var(--text-md);
  user-select: text;
  -webkit-user-select: text;
}

.auth-field__input:focus-visible {
  outline: none;
}

.auth-field__input::placeholder {
  color: var(--text-muted);
}

/* The eye. Quiet until pressed: it is a convenience, not an action. */
.auth-field__reveal {
  flex: none;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  margin-right: calc(-1 * var(--space-2));
  border-radius: var(--radius-full);
  color: var(--text-muted);
}

.auth-field__reveal[aria-pressed="true"] {
  color: var(--text);
}

/* The line under a field, folding the same way a row does: a message
   arriving pushes the next field down over the duration, and one leaving
   lets it back up. A hint is muted, an error the error colour — the same
   words in a different voice. */
.auth-field__line {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  transition:
    grid-template-rows var(--duration) var(--easing),
    opacity var(--duration) var(--easing);
}

.auth-field__line[data-shown="true"] {
  grid-template-rows: 1fr;
  opacity: 1;
}

.auth-field__line-inner {
  min-height: 0;
  overflow: hidden;
}

.auth-field__message {
  display: block;
  padding: var(--space-1) var(--space-1) 0;
  color: var(--text-muted);
  font-size: var(--text-xs);
  line-height: 1.4;
  transition: color var(--duration) var(--easing);
}

.auth-field[data-invalid="true"] .auth-field__message {
  color: var(--error-strong);
}

/* The field's gap to its line lives in the line, so an empty line costs nothing. */
.auth-field {
  gap: 0;
}

.auth-submit {
  margin-top: var(--space-1);
}

/* The words under a fade: out on the press timing, swapped, back on it. */
.auth-submit .ob-cta__label {
  transition: opacity var(--duration-press) var(--easing);
}

.auth-submit .ob-cta__label[data-swapping="true"] {
  opacity: 0;
}

.auth-submit[data-state="done"] .ob-cta__label {
  opacity: 0;
}

/* --- Reset panel ------------------------------------------------------------ */

.auth-reset {
  gap: var(--space-4);
}

/* The back arrow beside the words, on the card's own top line. */
.auth-reset__head {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  /* The arrow's 34px control sits a hair above the title's cap height;
     pulling the row up puts the two on one line. */
  margin: calc(-1 * var(--space-1)) 0 0 calc(-1 * var(--space-2));
}

.auth-reset__words {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
  padding-top: 6px;
}

.auth-reset__title {
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  letter-spacing: -0.02em;
  line-height: 1.2;
}

.auth-reset__subtitle {
  color: var(--text-secondary);
  font-size: var(--text-sm);
  line-height: 1.45;
  text-wrap: pretty;
  /* The address is long and the line changes on the step switch; a fixed
     two-line footprint keeps the fields under it from jumping. */
  min-height: calc(2 * 1.45em);
}

.auth-reset__verify {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

/* Six digits, spaced like a code rather than a word. */
#auth-reset-code {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.12em;
}

#auth-reset-code::placeholder {
  letter-spacing: normal;
}

/* --- Foot ------------------------------------------------------------------ */

.auth-foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  margin-top: auto;
  text-align: center;
}

.auth-guest {
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-full);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

.auth-guest[data-pressed="true"] {
  background: var(--surface-sunken);
}

.auth-legal {
  max-width: 30ch;
  color: var(--text-muted);
  font-size: var(--text-2xs);
  line-height: 1.45;
}

/* --- Page behind ---------------------------------------------------------- */

body[data-auth-open] {
  overflow: hidden;
}

@media (prefers-reduced-motion: reduce) {
  .auth-hero__crest {
    transition-delay: 0ms;
  }

  .auth-hero__crest .logo,
  .auth-error {
    animation: none;
  }

  /* Drawn already, rather than never drawn. */
  [data-state="done"] .auth-check__tick {
    animation: none;
    stroke-dashoffset: 0;
  }
}
