/* ==========================================================================
   auth.css — the sign-in screen, and any other no-login-wall face.

   Loaded ONLY by _LayoutAuth. It is not in app.css because every internal
   screen would then download a split-screen nobody signed in ever sees, and
   app.css is already the desk shell's whole vocabulary.

   ❗ TOKENS ONLY. Every colour below is from tokens.css — the navy scale, the
   surfaces, the ink — plus white at a stated alpha, which is the same thing
   the application header already does. No hex value is invented here, so the
   front door cannot drift away from the system behind it.

   ⚠️ No inline style attributes and no inline script anywhere: the CSP is
   style-src 'self' and script-src 'self', so both are silently discarded and
   an architecture test bans the attribute. Everything on this screen is CSS.
   ========================================================================== */

/* ── The split ────────────────────────────────────────────────────────────
   TWO PANELS, ONE DARK, AND THE BALANCE IS THE WHOLE POINT.

   The old screen was a white card, on a light grey page, under a light
   header, above a light footer — four shades within a few percent of each
   other and nothing for the eye to rest against. Nothing was wrong with any
   one of them; there was simply no anchor.

   The dark half is also what carries the brand. A sign-in screen that says
   only "Sign in" tells somebody who has just been given an account nothing
   about what they have been given an account TO. */

.auth-page {
  /* Matches .auth__panel, so a strip below a short viewport is the same colour
     as the half above it rather than reading as a rendering fault. */
  background: var(--page);
}

.auth {
  display: grid;
  /* ⚠️ <body> is a column flex container now (app.css), so that an admin
     page's footer sits on the bottom edge rather than under short content.
     This screen has no footer, so it simply takes the whole column — without
     this the split stops at 100svh and leaves a strip of --surface below the
     NAVY half wherever dvh is taller, which on a phone is the address bar's
     height exactly. Grow, never shrink: the form must not be squeezed. */
  flex: 1 0 auto;
  /* The dark side takes slightly more, so the form column does not read as
     the leftover space. */
  grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr);
  min-height: 100vh;
  min-height: 100svh;
}

/* ── The dark half ───────────────────────────────────────────────────────── */

.auth__brand {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-6);
  padding: clamp(var(--space-6), 5vw, var(--space-7)) clamp(var(--space-5), 6vw, 4.5rem);
  color: #fff;

  /* Three layers: a lit corner top-left where the wordmark sits, a cooler
     lift from the bottom-right, and the navy the whole thing rests on. A flat
     fill at this size reads as a coloured rectangle rather than a surface. */
  background-color: var(--navy-900);
  background-image:
    radial-gradient(115% 85% at 10% 4%, rgba(44, 99, 168, 0.55) 0%, rgba(44, 99, 168, 0) 58%),
    radial-gradient(95% 75% at 98% 102%, rgba(115, 157, 210, 0.28) 0%, rgba(115, 157, 210, 0) 62%),
    linear-gradient(158deg, var(--navy-700) 0%, var(--navy-900) 62%, var(--navy-900) 100%);
}

/* A blueprint grid, at 5% white and masked so it fades out before it becomes
   a pattern you have to look past. It is the one texture that belongs to a
   maintenance contractor rather than to a design trend. */
.auth__brand::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right, rgba(255, 255, 255, 0.05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
  background-size: 58px 58px;
  -webkit-mask-image: radial-gradient(125% 105% at 18% 0%, #000 0%, transparent 74%);
  mask-image: radial-gradient(125% 105% at 18% 0%, #000 0%, transparent 74%);
  pointer-events: none;
}

/* Everything readable sits above the texture. */
.auth__brand-inner,
.auth__foot {
  position: relative;
  z-index: 1;
}

.auth__brand-inner {
  margin-block: auto;
  max-width: 30rem;
}

.auth__wordmark {
  display: flex;
  flex-direction: column;
  line-height: 1.1;
  margin-bottom: var(--space-6);
}

.auth__wordmark-1,
.auth__wordmark-2 {
  text-transform: uppercase;
  font-weight: 700;
  letter-spacing: 0.22em;
  font-size: clamp(0.9375rem, 1.6vw, 1.125rem);
}

/* The second word steps back rather than repeating the first at full
   strength — a wordmark, not two headings. White at 62% over this navy is
   about 9:1, well clear of the floor. */
.auth__wordmark-2 {
  color: rgba(255, 255, 255, 0.62);
  font-weight: 600;
}

.auth__statement {
  font-size: clamp(1.5rem, 2.9vw, 2.125rem);
  line-height: 1.18;
  letter-spacing: -0.02em;
  font-weight: 650;
  text-wrap: balance;
}

.auth__blurb {
  margin-top: var(--space-4);
  max-width: 34ch;
  font-size: clamp(0.9375rem, 1.2vw, 1.0625rem);
  line-height: 1.55;
  /* --ink-3's job on white, done in white on navy: quieter, never below the
     floor. 74% over the deepest part of the panel is about 8:1. */
  color: rgba(255, 255, 255, 0.74);
}

.auth__foot {
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.52);
}

/* ── The light half ─────────────────────────────────────────────────────── */

.auth__panel {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(var(--space-6), 5vw, var(--space-7)) clamp(var(--space-5), 5vw, 3.5rem);

  /* ⚠️ --page, NOT --surface, and this is the half of the change that makes
     the other half work. 0030 left this white and said a bordered card inside
     a white panel is a box drawn around the only thing on that side — which
     was true, and the consequence was that the form had no edges at all: a
     white input, hairlined in --line, on a white panel. The BOX blended in
     even though the SCREEN did not.

     The three planes 0029 settled are the answer, used properly: the ground
     is --page, the card is --surface, and the card is now a card. */
  background: var(--page);
}

/* ❗ IT IS A CARD NOW, and it is the same card as everywhere else in the
   system — --surface on --page, a --line hairline, --radius-lg.

   The one departure is the elevation: --shadow-2 rather than the --shadow-1
   the admin screens use. That is deliberate and it is about count. A
   coordinator's board carries thirty cards and lifting each of them off the
   page is noise; this screen carries exactly one thing, and it is the thing
   the person came here to use. */
.auth__panel-inner {
  width: 100%;
  /* 26rem, not 23 — the card's own padding is inside this now, so the FORM
     keeps the measure it had rather than losing 3rem of it to the frame. */
  max-width: 26rem;
  padding: clamp(var(--space-5), 4vw, var(--space-6));
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-2);
}

.auth__mark { margin-bottom: var(--space-6); }

.auth__heading {
  margin-top: var(--space-2);
  font-size: 1.75rem;
  letter-spacing: -0.02em;
}

.auth__sub {
  margin-top: var(--space-2);
  color: var(--ink-3);
  font-size: 0.9375rem;
}

/* ⚠️ An alert, not a field error. It says the whole submission failed, so it
   is the width of the form and carries the state's soft fill with a bar down
   its leading edge — colour never carries meaning alone, and the sentence
   inside it is what actually carries it. */
.auth__alert {
  margin-bottom: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius);
  border-inline-start: 3px solid var(--critical);
  background: var(--critical-soft);
  color: var(--critical);
  font-size: 0.875rem;
  font-weight: 600;
}

.auth__submit { margin-top: var(--space-2); }

/* ── The input boxes ──────────────────────────────────────────────────────
   HOVER: the border deepens and a soft navy halo appears behind the box.
   FOCUS: the halo firms up and a 2px bar grows out of the centre of the
   underline.

   ❗ THE FOCUS RING IS NOT REMOVED, IT IS MOVED OUTSIDE THE BOX. app.css puts
   a 2px navy outline INSIDE the input (outline-offset: -1px), which is right
   on a dense admin form and wrong here — it paints over the bar and fights
   the halo. What replaces it is stronger, not weaker: a 3px navy halo, a
   navy-500 border and the bar, all three at once.

   ⚠️ The transparent outline stays deliberately. In Windows High Contrast
   Mode every shadow and every background is discarded, and a transparent
   outline is the one thing forced-colors repaints — remove it and a
   high-contrast user has no focus indicator at all. */

.auth-input {
  position: relative;
  border-radius: var(--radius);
  transition: box-shadow 140ms ease;
}

.auth-input:hover { box-shadow: 0 0 0 4px var(--navy-100); }

.auth-input:focus-within { box-shadow: 0 0 0 3px rgba(44, 99, 168, 0.32); }

/* ❗ THE BOX IS TINTED AT REST, AND CLEARS WHEN YOU ARE IN IT.

   A --surface input inside a --surface card is a white rectangle on white
   with a #D3DBE3 hairline round it, which is roughly 1.4:1 — an edge that is
   present in the markup and very nearly absent to the eye. --surface-2 is the
   plane this system already uses for a band that has to read as a distinct
   region (a card header, a table header), and it does the same job here: the
   two boxes read as boxes before anybody clicks anything.

   Clearing to --surface on focus is then a second signal on top of the halo,
   the border and the bar — the field you are typing in is the one that is
   BRIGHTER than the rest, which is the opposite way round from the usual
   trick and reads more like paper. */
.auth-input input {
  background: var(--surface-2);
  border-color: var(--line);
  transition: border-color 140ms ease, background-color 140ms ease;
}

.auth-input:hover input { border-color: var(--navy-200); }

.auth-input input:focus {
  background: var(--surface);
  border-color: var(--navy-500);
  outline: 2px solid transparent;
  outline-offset: 0;
}

/* The sweep. Inset by the corner radius so it stops where the border curves,
   and scaleX rather than left/right so it is one composited property. */
.auth-input::after {
  content: "";
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: 0;
  height: 2px;
  border-radius: 2px;
  background: var(--navy-500);
  transform: scaleX(0);
  transform-origin: 50% 50%;
  transition: transform 220ms cubic-bezier(0.2, 0.7, 0.3, 1);
  pointer-events: none;
}

.auth-input:focus-within::after { transform: scaleX(1); }

/* Chrome paints its own pale yellow over an autofilled field, which lands on
   this screen as the one box that is a different colour from everything
   else. An inset shadow taller than the box is the only way to override it. */
.auth-input input:-webkit-autofill,
.auth-input input:-webkit-autofill:hover {
  -webkit-box-shadow: 0 0 0 40rem var(--surface-2) inset;
  -webkit-text-fill-color: var(--ink);
}

/* ⚠️ Focus takes its own rule, or an autofilled box stays tinted when you are
   inside it and the one field you are typing in is the one that does not
   respond. The inset shadow is the fill here, not background-color — Chrome's
   own is painted over the background and only a shadow beats it. */
.auth-input input:-webkit-autofill:focus {
  -webkit-box-shadow: 0 0 0 40rem var(--surface) inset;
  -webkit-text-fill-color: var(--ink);
}

/* ── Motion ───────────────────────────────────────────────────────────────
   The screen assembles itself rather than appearing: everything rises 14px
   and fades, one element after another, and it is over in under half a
   second.

   ❗ THE DELAYS ARE WRITTEN OUT RATHER THAN COUNTED BY nth-child ACROSS TWO
   PARENTS. The mark and the note are children of the panel; the fields are
   children of the form. An nth-child sequence restarts inside the form, so
   the second column would deal itself twice. Six lines that say what they
   mean beat a rule that is only correct while the markup does not move.

   `backwards` is what holds an element invisible through its own delay —
   without it every one of them flashes at full opacity first. */

@keyframes auth-rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

.auth__brand-inner > *,
.auth__mark,
.auth__form > * {
  animation: auth-rise 340ms cubic-bezier(0.2, 0.7, 0.3, 1) backwards;
}

.auth__brand-inner > *:nth-child(1) { animation-delay: 0ms; }
.auth__brand-inner > *:nth-child(2) { animation-delay: 70ms; }
.auth__brand-inner > *:nth-child(3) { animation-delay: 130ms; }

.auth__mark                  { animation-delay: 90ms; }
.auth__form > *:nth-child(1) { animation-delay: 150ms; }
.auth__form > *:nth-child(2) { animation-delay: 200ms; }
.auth__form > *:nth-child(3) { animation-delay: 250ms; }
.auth__form > *:nth-child(4) { animation-delay: 300ms; }

/* ⚠️ app.css's reduced-motion block flattens TRANSITIONS to 0.01ms, which
   leaves an animation-delay running — so somebody who has asked for no motion
   would watch an invisible form for a third of a second. Both halves are
   switched off here, and the elements simply start where they finish. */
@media (prefers-reduced-motion: reduce) {
  .auth__brand-inner > *,
  .auth__mark,
  .auth__form > * {
    animation: none;
  }
}

/* ── Narrow ───────────────────────────────────────────────────────────────
   The split becomes a band. It stays dark, because the reason for it does
   not change on a phone — but it gives up the statement's full height and
   the supporting line, which at that size is a paragraph between somebody
   and the box they came here to type in. */

@media (max-width: 62rem) {
  /* minmax(0, 1fr), never a bare 1fr — the same guard the two-column rule
     above carries, for the same reason. `1fr` is `minmax(auto, 1fr)`, and
     `auto` refuses to let a column be narrower than its content's minimum;
     the form panel is a flex container holding a block capped at 26rem, so
     that minimum is a real number rather than zero. The failure it would
     buy is the one this system already knows: the DOCUMENT scrolls sideways
     and the right-hand end of every input leaves the screen. */
  .auth { grid-template-columns: minmax(0, 1fr); }

  /* ⚠️ AND THE ROWS HAVE TO BE STATED, OR THE BAND TAKES HALF THE PHONE.
     The grid is still 100svh tall, and two auto rows share the leftover
     height between them — which put the brand band down 55% of a 390×844
     screen and the Email label below the fold's midpoint. The band is worth
     its own height and not a pixel more; the form takes the rest. */
  .auth { grid-template-rows: auto 1fr; }

  .auth__brand {
    gap: var(--space-4);
    padding: var(--space-6) var(--space-5) var(--space-5);
  }

  .auth__brand-inner { margin-block: 0; }

  .auth__wordmark { margin-bottom: var(--space-4); }

  .auth__blurb { display: none; }

  .auth__foot { display: none; }

  /* The panel's own padding shrinks, because the card inside it now carries
     padding of its own — two frames at desktop width is right and at 390px it
     is most of the screen. */
  .auth__panel { padding: var(--space-5) var(--space-4) var(--space-6); }

  .auth__panel-inner { margin-inline: auto; }
}

/* Short and wide — a laptop screen with a dock and two toolbars on it, and
   the one case where a 100svh split would otherwise scroll. */
@media (max-height: 34rem) and (min-width: 62rem) {
  .auth__statement { font-size: 1.5rem; }
  .auth__blurb { display: none; }
}
