/* The painting shell: sign in, register, password reset, email verification, the Stripe return
   pages and the error pages. They all render through `website/templates/website/_auth_chrome.html`,
   which links `tokens.css` (the design system's palette) and `marketing.css` (the bar, the CTA,
   the textlink and the lead recipe) ahead of this file, so every var() below resolves against the
   design system, never the frozen palette.

   Two deliberate departures from `design-system/docs/guides/marketing.md`, chosen in the design
   and not to be "corrected": the painting carries no wash, and the bar takes a solid `--sand-1`
   ground at rest rather than arriving at one once it sticks (it does not stick here at all). The
   headline plate is likewise an opaque `--sand-1` block with a hairline, not a translucent surface.

   The recipes copied from `design-system/src/components.css` (Panel, MonoLabel, Field) are named
   at the rule that copies them, the way `blog.css` does: the design system's stylesheet only ships
   inside the app bundle, and a server-rendered page cannot link it. */

/* -------------------------------------------------------------- Painting ----

   One `prefers-color-scheme` query and the two `[data-theme]` guards, exactly as `marketing.css`
   switches `--mkt-backdrop-image`: `light-dark()` takes colours, not images, and only the winning
   custom property is substituted, so each visitor fetches one painting. The light painting is a
   top-anchored crop of the sheet (the design pans every light slot to the top), the dark one is a
   landscape and centres. */
:root {
  --auth-painting: url("../images/painting-jasmine.8edb19ea54ef.webp");
  --auth-painting-y: 0%;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --auth-painting: url("../images/painting-moonlit.82b0978fb061.webp");
    --auth-painting-y: 50%;
  }
}

:root[data-theme="dark"] {
  --auth-painting: url("../images/painting-moonlit.82b0978fb061.webp");
  --auth-painting-y: 50%;
}

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

.auth-page {
  position: relative;
  min-height: 100vh;
  background: var(--sand-1);
  color: var(--n-text);
  font-family: var(--font-family-sans);
}

/* `--sand-2` under the image is what shows while it loads, one step off the page so the plate and
   card already read as sitting on something. `z-index: 0` puts the layer with the in-flow content
   that follows it in tree order, which then paints over it. */
.auth-page::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: var(--sand-2) var(--auth-painting) 50% var(--auth-painting-y) / cover no-repeat;
}

/* Everything the page draws sits above the painting: the bar, the plate, the card. The bar is
   `position: static` here (see `.rd-mkt-nav--solid`), so it needs the same lift as the stack. */
.auth-page > .rd-mkt-nav,
.auth-stack {
  position: relative;
  z-index: 1;
}

.auth-stack {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-7);
  padding: var(--space-8) var(--mkt-gutter) var(--space-8);
}

/* The plate: opaque, hairlined, centred. The painting is untouched around it, which is the whole
   composition — the plate is the one quiet rectangle the eye lands on. */
.auth-plate {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  width: 100%;
  max-width: 720px;
  padding: var(--space-5) var(--space-7);
  background: var(--sand-1);
  border: 1px solid var(--n-border-subtle);
  text-align: center;
}

.auth-plate h1 {
  margin: 0;
  max-width: 20ch;
  font: 400 var(--mkt-font-size-display) / 1.08 var(--font-family-serif);
  letter-spacing: -0.015em;
  color: var(--n-text);
  text-wrap: balance;
}

/* Full ink, not the muted step the landing's lead takes: the plate is a small block and its one
   line is the page's explanation, not a standfirst under a headline it repeats. */
.auth-plate .rd-mkt-lead {
  margin: 0;
  max-width: 44ch;
  color: var(--n-text);
  text-wrap: pretty;
}

/* An address quoted inside the lead. Mono at 0.9em, which is how the app quotes one. */
.auth-plate__mono {
  font-family: var(--font-family-mono);
  font-size: 0.9em;
}

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

   `Panel` from `design-system/src/components.css` (`.rd-panel`: hairline `--n-border-subtle`,
   `--radius-sm`), on the page ground rather than `--n-surface-raised` because it sits on a
   painting, not on the page. */
.auth-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  width: 100%;
  max-width: 420px;
  padding: var(--space-6);
  background: var(--sand-1);
  border: 1px solid var(--n-border-subtle);
  border-radius: var(--radius-sm);
}

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

/* A form's CTA sits one breath below its last field; a card with no fields has nothing to breathe
   from, so the rule is on the field group's sibling rather than on every CTA. */
.auth-fieldset + .rd-mkt-cta,
.auth-field + .rd-mkt-cta,
.auth-line + .rd-mkt-cta,
.auth-turnstile + .rd-mkt-cta {
  margin-top: var(--space-2);
}

/* ---------------------------------------------------------------- Fields ----

   `Field` from `design-system/src/components.css`: `.rd-field__label` is a MonoLabel, the control
   owns the ring (`:focus-within` recolours its border, no outline), the message row is mounted
   whether or not it holds anything. The error treatment is the design's ask of Field — the crimson
   border plus a 7% `--n-danger` wash on the control, and the message at `--font-size-small`. */
.auth-field {
  display: block;
}

.auth-field__label {
  display: block;
  margin-bottom: var(--space-2);
  font-family: var(--font-family-mono);
  font-size: var(--font-size-caption);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--n-text-muted);
}

.auth-field__control {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--n-bg);
  border: 1px solid var(--n-border);
  border-radius: var(--radius-sm);
  box-shadow: var(--n-shadow-sm);
  transition:
    border-color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out);
}

.auth-field__control:focus-within {
  border-color: var(--n-focus-ring);
}

.auth-field__control--error,
.auth-fieldset--error .auth-field__control {
  border-color: var(--crimson-7);
  background: color-mix(in srgb, var(--n-danger) 7%, transparent);
}

.auth-field__input {
  flex: 1;
  min-width: 0;
  /* Inputs keep the control's rhythm at 48px total: 8px padding either side of a 30px line box.
     The height is the system's touch floor, `--space-7`, so a tap never lands short. */
  height: 30px;
  border: none;
  outline: none;
  background: none;
  font-family: var(--font-family-sans);
  font-size: var(--mkt-font-size-control);
  color: var(--n-text);
}

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

/* The password reveal: a bare icon button in the adornment slot. Its box is the control's own
   height so the target reaches the floor without changing the control. */
.auth-field__reveal {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 30px;
  height: 30px;
  margin: 0 -6px 0 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--n-text-muted);
  cursor: pointer;
}

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

.auth-field__reveal:focus-visible {
  outline: var(--focus-ring);
  outline-offset: 2px;
}

.auth-field__message {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin-top: var(--space-2);
  font-family: var(--font-family-sans);
  font-size: var(--font-size-small);
  line-height: var(--leading-normal);
  color: var(--n-text-muted);
}

.auth-field__message:empty {
  margin-top: 0;
}

.auth-field__message--error {
  color: var(--n-danger);
}

.auth-field__message svg {
  flex: none;
  margin-top: 3px;
}

/* A message that carries links (the taken-email sentence) keeps the design system's inline-action
   voice for them: the accent text step, underlined on a 40% edge. */
.auth-field__message a,
.auth-line a {
  color: var(--n-accent-text);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--n-accent-text) 40%, transparent);
  text-underline-offset: 3px;
}

/* -------------------------------------------------------- Whole-form lines ----

   Board 4d: a whole-form error tints every control it concerns (`.auth-fieldset--error` above)
   and speaks once, in one line under the group, with a glyph. A flash is the same line in grass
   with a check. Under a field group the line pulls up by one step so it reads as the group's own
   message rather than a new paragraph. */
.auth-fieldset {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.auth-line {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin: 0;
  font: 400 var(--font-size-small) / var(--leading-normal) var(--font-family-sans);
}

.auth-line svg {
  flex: none;
  margin-top: 3px;
}

/* A flash line is mounted empty and filled by auth.js when a resend lands, so the live region
   exists before it has something to say; empty it takes no room. */
.auth-line:empty {
  display: none;
}

.auth-line--error {
  color: var(--n-danger);
}

.auth-line--flash {
  color: var(--grass-11);
}

.auth-fieldset > .auth-line {
  margin-top: calc(-1 * var(--space-2));
}

/* ------------------------------------------------------------- Turnstile ----

   Cloudflare draws into its own iframe at the flexible width, and `appearance=interaction-only`
   keeps it invisible until a challenge is actually needed — so nothing reserves its height; the
   form simply grows when the widget appears. */
.auth-turnstile {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.auth-turnstile:empty {
  display: none;
}

/* -------------------------------------------------------------- Cooldown ----

   Under a resend button while the server's window is open. The clock is mono in full ink so the
   one changing number is the one thing that reads as a number. */
.auth-cooldown {
  margin: calc(-1 * var(--space-1)) 0 0;
  text-align: center;
  font: 400 var(--font-size-small) / var(--leading-normal) var(--font-family-sans);
  color: var(--n-text-muted);
}

.auth-cooldown__clock {
  font-family: var(--font-family-mono);
  font-variant-numeric: tabular-nums;
  color: var(--n-text);
}

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

   The small row under the card's action: a textlink or two, or a sign-out button that has to look
   like one. The marketing textlink is sized for a hero; here it inherits the row's small size. */
.auth-card__foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  font: 400 var(--font-size-small) / var(--leading-normal) var(--font-family-sans);
  color: var(--n-text-muted);
}

.auth-card__foot > span {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-1);
}

.auth-card__foot .rd-mkt-textlink {
  font-size: inherit;
  font-weight: 500;
}

.auth-card__foot button.rd-mkt-textlink {
  background: none;
  border-top: 0;
  border-left: 0;
  border-right: 0;
  padding-top: 0;
  padding-left: 0;
  padding-right: 0;
  font: inherit;
  font-weight: 500;
}

/* ------------------------------------------------------------ Breakpoint ----

   640 is --breakpoint-mobile. Below it the layer has already stepped display to 34px and the
   gutter to 20px (marketing.css); the stack and the two boxes give up their desktop padding, and
   the card meets the gutter. */
@media (max-width: 639px) {
  .auth-stack {
    gap: var(--space-6);
    padding-top: var(--space-6);
    padding-bottom: var(--space-6);
  }

  .auth-plate {
    padding: var(--space-5);
  }

  .auth-card {
    padding: var(--space-5);
  }
}
