/* =========================================================================
   manaruler -- account pages (/auth/register, /auth/login)

   WHY THIS IS A SEPARATE FILE AND NOT PART OF site.css
   ----------------------------------------------------
   site.css is the public site's one stylesheet and these rules belong in it.
   They are here instead because site.css was under concurrent edit by another
   task when these two pages were built, and two owners on one file is the one
   thing this repo's agent policy will not allow. Nothing in this file is
   page-scoped by nature -- .field in particular is a general text-input
   component the site does not have yet, and the next person free to touch
   site.css should fold this whole file into it (see the FOLD-IN notes below)
   and drop the extra <link>.

   It defines NO tokens of its own. Every colour, space, radius and type step
   comes from site.css's :root, including its dark-scheme overrides, so these
   pages inherit light/dark for free and cannot drift from the rest of the
   site.
   ========================================================================= */

/* ---------- Account page shell ------------------------------------------ */

/* FOLD-IN: .auth__panel is geometrically identical to .interstitial__panel on
   purpose, and near-identical to .gate__panel. That is not an accident and it
   is not laziness: /auth/register hands the visitor straight to
   /auth/verify-email, and the panel must not resize, re-centre or change its
   accent edge between those two steps or the flow reads as two websites. When
   this file is folded into site.css these three should collapse into one
   `.panel` primitive with .gate/.auth/.interstitial as modifiers. */

.auth {
  padding-block: var(--space-6) var(--space-7);
}

.auth__panel {
  position: relative;
  max-width: 34rem;
  margin-inline: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  /* Held in a custom property, not written straight into `padding`, because
     the Turnstile widget below has to cancel exactly this value to bleed out
     to the panel edge on a phone. Hardcoding the number in two places is how
     that silently breaks the next time the padding scale is touched. */
  --panel-pad: var(--space-4);
  padding: var(--panel-pad);
  display: grid;
  gap: var(--space-5);
}

/* Same two-step padding growth as .interstitial__panel. */
@media (min-width: 24rem) {
  .auth__panel {
    --panel-pad: var(--space-5);
  }
}

@media (min-width: 34rem) {
  .auth__panel {
    --panel-pad: var(--space-6);
  }
}

/* Grid hygiene, the same rule site.css applies to its own layout children:
   grid items default to min-width: auto, which resolves to min-content, so ONE
   unshrinkable child (here: a third-party iframe with a fixed pixel width) can
   push the whole panel wider than the viewport. Every child of these two grids
   is allowed to shrink. */
.auth__panel > *,
.auth__form > * {
  min-width: 0;
}

/* The site's one ornament, carried over from .ruling and .interstitial__panel. */
.auth__panel::before {
  content: "";
  position: absolute;
  inset-block: var(--space-5);
  inset-inline-start: 0;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--accent);
}

.auth__intro {
  display: grid;
  gap: var(--space-3);
}

.auth__title {
  font-size: var(--fs-h2);
  font-weight: 690;
  letter-spacing: -0.026em;
}

.auth__lead {
  color: var(--text-muted);
  font-size: var(--fs-lead);
}

.auth__form {
  display: grid;
  gap: var(--space-4);
}

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

/* The cross-link between the two account pages, and the "already confirmed?"
   style aside. Left-aligned, unlike .interstitial__aside, because these pages
   are forms: the reader's eye is already at the left margin. */
.auth__aside {
  max-width: 34rem;
  margin: var(--space-4) auto 0;
  font-size: var(--fs-small);
  color: var(--text-muted);
}

/* ---------- Text field ---------------------------------------------------
   FOLD-IN: general component, not account-specific. Label above input, hint
   under the label, error under the input -- the order a screen reader reads
   them in is the order they matter in.

   The native control is styled, never replaced. `font: inherit` is the whole
   trick: browsers ship inputs at 13px Arial by default, which is both off-brand
   and small enough to trigger iOS Safari's zoom-on-focus.
   ------------------------------------------------------------------------ */

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

.field__label {
  font-weight: 620;
  letter-spacing: -0.012em;
}

.field__input {
  font: inherit;
  width: 100%;
  /* 0.7rem block padding + 1.6 line-height + borders clears 44px, so the tap
     target meets WCAG 2.5.8 without a hardcoded height that would break when
     the user scales text up. */
  padding: 0.7rem 0.85rem;
  color: var(--text);
  background: var(--surface);
  /* --control-border, not --border: this outline IS the affordance, so it needs
     3:1 against the surface behind it (WCAG 1.4.11). site.css's token comment
     spells this out. */
  border: 1px solid var(--control-border);
  border-radius: var(--radius-sm);
  transition: border-color 140ms ease;
}

.field__input:hover {
  border-color: var(--accent);
}

/* The global :focus-visible rule (2px accent outline, 3px offset) already
   handles focus. Deliberately not overridden here -- a second, different focus
   treatment on one control type is how a design system starts to rot. */

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

.field__hint {
  color: var(--text-muted);
  font-size: var(--fs-small);
}

/* Colour never carries the meaning on its own: .field__error always contains a
   sentence, and the input carries aria-invalid + aria-describedby, so the
   red border is reinforcement rather than information (WCAG 1.4.1). Colours
   match .alert--error in site.css rather than introducing a third red. */
.field--invalid .field__input {
  border-color: #a3352c;
}

/* The terms checkbox is a .checkfield (site.css), not a .field, so the invalid
   state has to land on the row's own border rather than on an input outline.
   Same red, same reasoning. */
.checkfield.field--invalid {
  border-color: #a3352c;
}

.field__error {
  color: #8c2c24;
  font-size: var(--fs-small);
  font-weight: 560;
}

@media (prefers-color-scheme: dark) {
  .field--invalid .field__input,
  .checkfield.field--invalid {
    border-color: #e2887f;
  }

  .field__error {
    color: #f0aaa2;
  }
}

/* Both scripted pages can put a recovery link inside the error banner (sign in
   instead / resend the confirmation email). The site's default link colour is
   the green accent, which reads as a foreign object inside the one red panel
   on the site. Inheriting the banner's own ink keeps it in the message, and the
   underline is what marks it as a link -- so this is not colour-only
   signalling. Scoped to .auth so it cannot reach .alert--error anywhere else:
   auth.css is loaded by these two pages only, and site.css's owner should not
   have to know this rule exists. */
.auth .alert--error a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
}

/* ---------- Bot check (Cloudflare Turnstile) -----------------------------
   The widget is a third-party iframe with a fixed 300x65 intrinsic size, so
   the slot reserves that height up front. Without the reservation the whole
   form below it jumps down when the widget paints, which is both a CLS hit and
   the single most confusing moment on a registration page.
   ------------------------------------------------------------------------ */

.turnstile {
  display: grid;
  gap: var(--space-2);
  min-height: 4.25rem;
}

/* Turnstile's iframe is a hard 300px wide and does not shrink -- "flexible"
   and "compact" sizes have the same 300px floor. Do the arithmetic for a
   375px phone: 375 minus the container's 24px gutters minus the panel's own
   24px padding on each side leaves 279px of content width. The widget does not
   fit, and because it cannot shrink it drags the whole panel off the right
   edge of the screen. This was real, not theoretical: it was caught in a
   375px screenshot, and it broke every field on the page, not just the widget.

   Two things fix it, in order of preference:
   1. Below 26rem the widget bleeds out through the panel's padding and uses
      the full inner width of the panel. At 375px that is 325px, so the widget
      fits with room to spare and nothing scrolls. Only the widget bleeds --
      the fallback message underneath stays on the text margin with everything
      else, which is why it needs its own wrapper.
   2. Under roughly 350px even the bled width is not enough, so the wrapper is
      a scroll container as a last resort. Scrolling a captcha sideways is a
      poor experience; it is here to stop the page breaking, not as the plan. */
.turnstile__widget {
  min-width: 0;
  overflow-x: auto;
}

@media (max-width: 26rem) {
  .turnstile__widget {
    margin-inline: calc(var(--panel-pad) * -1);
    padding-inline: var(--space-2);
  }
}

/* Shown only when the vendor script never arrived (blocked, offline, ad
   blocker). Hidden by default and revealed by register.js, because a message
   about a failure that has not happened yet is worse than no message. */
.turnstile__fallback[hidden] {
  display: none;
}

/* ---------- Alternative sign-in (OAuth) ----------------------------------
   Login only. The divider is a real labelled separator, not decoration: it is
   the thing that tells a returning Google/Discord user to stop filling in the
   password field.
   ------------------------------------------------------------------------ */

.auth__alt {
  display: grid;
  gap: var(--space-3);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
}

.auth__alt-title {
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--text-muted);
}

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

/* Full-width provider buttons stack on a phone and sit side by side once
   there is room for both labels on one line each. */
@media (min-width: 30rem) {
  .auth__providers {
    grid-template-columns: 1fr 1fr;
  }
}

.auth__providers .btn {
  /* .btn is inline-flex and shrink-to-fit; in this grid the two options are
     equal-weight alternatives and should read as equal-width targets. */
  width: 100%;
  /* The default .btn lands at about 39px tall, under WCAG 2.5.5's 44px target,
     and unlike the terms checkbox there is no larger associated label to
     borrow. site.css solves the same problem on check_email.html by reaching
     for .btn--large, but these two are secondary options and should not carry
     the primary button's type size, so the height is raised on its own. */
  min-height: 2.75rem;
}

/* ---------- Submit button ------------------------------------------------ */

/* .btn sets white-space: nowrap, which is right in a nav and wrong for a
   sentence-length button label on a 320px screen. Same override .resend__button
   already makes in site.css. */
.auth__submit {
  white-space: normal;
  text-align: center;
  width: 100%;
}

/* A disabled submit is the normal state of the register form until the bot
   check passes, so it has to look deliberately-off rather than broken. Muted
   fill, no hover response, and the copy underneath says why.

   --control-border, not --border-strong: WCAG 1.4.11 exempts disabled controls
   from its 3:1 rule, so either would pass, but --border-strong lands at 1.74:1
   against the panel and the button's edge effectively disappears. The whole
   point of this state is that the visitor can see the control they are waiting
   to be able to press. --control-border measures 3.55:1. */
.auth__submit:disabled {
  background: var(--surface-sunken);
  border-color: var(--control-border);
  color: var(--text-muted);
  cursor: not-allowed;
}

.auth__submit:disabled:active {
  transform: none;
}

.auth__submit-note {
  color: var(--text-muted);
  font-size: var(--fs-small);
}
