/* ============================================================================
   Orbit Axis — the sign-in gate and the startup gate
   ----------------------------------------------------------------------------
   The first screen anyone sees, so it is the screen that has to be most plainly
   itself: a card, one action, and the plain sentences about birth data that
   belong before the data is asked for rather than after.

   The gradient-filled submit button and the indigo wash behind the card are
   gone with the rest of the decorative layer. One accent, one pill.
   ========================================================================== */

.auth-gate {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  padding: var(--space-lg);
  background: color-mix(in oklab, var(--color-bg) 88%, transparent);
  backdrop-filter: var(--blur-frosted);
  -webkit-backdrop-filter: var(--blur-frosted);
  /* The gate scrolls rather than clipping at 200% zoom, on a short phone in
     landscape, or simply once the privacy explanation made the card taller.
     BOTH properties are needed: `align-content` positions the single grid
     track, `align-items` positions the card inside it, and `safe` is what makes
     each fall back to start-alignment exactly when centring would push content
     out of reach. */
  overflow-y: auto;
  align-content: safe center;
  align-items: safe center;
}
.auth-gate[hidden] { display: none; }

.auth-card {
  position: relative; /* anchors .auth-close */
  width: min(440px, 100%);
  max-height: none;
  display: grid;
  gap: var(--space-md);
  justify-items: center;
  padding: var(--space-xl) var(--space-lg);
  background: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-xl);
}
.auth-card--wide { width: min(760px, 100%); justify-items: stretch; position: relative; }

/* The mark itself lives in orbit-mark.css — one definition shared with the
   password-reset page, so the app and its standalone pages cannot end up with
   two logos. */

.auth-intro { display: grid; gap: var(--space-xs); }
.auth-card h1 {
  font-family: var(--font-display);
  font-size: var(--type-section);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--track-display);
  line-height: var(--lead-display);
  color: var(--color-primary);
  text-align: center;
}
.auth-card p {
  color: var(--color-secondary);
  text-align: center;
  font-size: var(--type-body);
  line-height: var(--lead-body);
}

/* ── The way out ─────────────────────────────────────────────────────────────
   The gate is dismissible now, so a mouse user needs a control and not just the
   Escape key. "Not now" rather than an X: it declines an offer, which is what
   this actually is, and it says the offer will still be there. */
.auth-close {
  position: absolute;
  top: var(--space-sm);
  right: var(--space-sm);
  padding: var(--space-xxs) var(--space-xs);
  min-height: 44px;
  background: none;
  border: 0;
  border-radius: var(--radius-sm);
  color: var(--color-secondary);
  font-size: var(--type-fine);
  cursor: pointer;
}
.auth-close:hover { color: var(--color-primary); }

/* ── What the account buys ───────────────────────────────────────────────────
   The half of the exchange the old gate never showed. Left-aligned against the
   centred headline on purpose: a list is read down its left edge, and centring
   these three lines turned them into decoration. */
.auth-benefits {
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--space-xs);
}
.auth-benefits li {
  position: relative;
  padding-left: calc(var(--space-md) + 2px);
  text-align: left;
  font-size: var(--type-fine);
  line-height: 1.5;
  color: var(--color-secondary);
}
.auth-benefits li::before {
  content: "";
  position: absolute;
  left: var(--space-xs);
  top: 0.55em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--color-accent, currentColor);
}

/* The mode switch is the segmented control, not a bespoke pair of buttons. */
.auth-tabs { width: 100%; }

.auth-form { width: 100%; display: grid; gap: var(--space-sm); }

/* Labels are separate elements associated by `for`, rather than wrapping their
   input. A wrapping label reads its whole subtree as the accessible name, so
   the "Show"/"Hide" button inside the password row became part of the field's
   name — "Password Show" — for every screen reader user. */
.auth-form > label,
#auth-confirm-wrap label {
  justify-self: start;
  margin-bottom: calc(var(--space-xs) * -1);
  color: var(--color-secondary);
  font-size: var(--type-caption);
  letter-spacing: var(--track-caption);
}

.password-row { display: grid; grid-template-columns: 1fr auto; gap: var(--space-xs); }
/* Fixed width so the row does not reflow between "Show" and "Hide", and so the
   field beside it keeps a predictable size. 68px + the gap fits beside the
   input at 375px, so the row stays one row. */
.password-row button { min-width: 68px; min-height: 44px; }

/* The confirm-password pair is one grid child so `hidden` still hides both. */
#auth-confirm-wrap { display: grid; gap: var(--space-xxs); }
#auth-confirm-wrap[hidden] { display: none; }

#auth-submit { margin-top: var(--space-xs); }

/* Status text carries values the layout did not choose: a download filename, a
   message forwarded from the server. Without a wrapping rule one long unbroken
   token widens the whole page — measured at 375px, where a long filename pushed
   the layout viewport to 921px. `anywhere` rather than `break-word` so the break
   is allowed to count toward the intrinsic width, which is what actually stops
   the expansion. */
.auth-message {
  min-height: 20px;
  color: var(--color-accent);
  font-size: var(--type-caption);
  text-align: center;
  overflow-wrap: anywhere;
  min-width: 0;
}

.auth-pending {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
}

.auth-pending__mark {
  display: block;
  width: 28px;
  height: 28px;
  flex: none;
}

/* What is collected and why, before it is asked for — now behind a summary.
   Still ahead of the submit button, still in full, but no longer the largest
   element on a card whose headline had fallen below the fold. */
.auth-privacy {
  width: 100%;
  padding: var(--space-sm) var(--space-md);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
}
.auth-privacy p { margin: var(--space-xs) 0 0; font-size: var(--type-fine); line-height: 1.55; text-align: left; }
.auth-privacy summary {
  cursor: pointer;
  text-align: left;
  color: var(--color-secondary);
  /* A 14px line of text is not a 44px target. The padding is what makes this
     tappable; the negative margin keeps it from inflating the collapsed box,
     which is the whole reason this became a summary. */
  padding: var(--space-xs) 0;
  margin: calc(var(--space-xs) * -1) 0;
}
/* --focus-ring is a box-shadow value in tokens.css, not an outline one. */
.auth-privacy summary:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-xs); }

/* ── Terms, privacy, and support ─────────────────────────────────────────────
   These sit inline inside a sentence, where a 44px-tall box would break the
   line. WCAG 2.5.8 exempts links in a block of text for exactly that reason —
   but "exempt" is not the same as "comfortable on a phone", and these are the
   links a person taps when they want to know what happens to their birth data.

   So the tap area grows with padding, and the LINE HEIGHT grows with it. The
   obvious version of this — padding plus a cancelling negative margin, to keep
   the sentence compact — was measured at 375px and rejected: it produced 43px
   boxes whose tops were 19px apart, so "Terms of Use" overlapped the two links
   on the line below. Overlapping targets are worse than small ones, because a
   confident tap lands on the wrong document.

   The sentence is allowed to get taller. It is four lines of small print on the
   one screen where being unhurried is the point. */
.auth-legal { margin-top: var(--space-xxs); font-size: var(--type-fine); line-height: 3.8; }
/* Vertical padding only. Horizontal padding is what makes a comma or a full
   stop appear to float away from the link it follows. */
.auth-legal a { display: inline-block; padding: 13px 1px; border-radius: var(--radius-xs); }

.auth-form .linklike { min-height: 44px; padding: 0 var(--space-xs); }

/* Dismiss control on the onboarding gate. */
.gate-dismiss {
  position: absolute; top: var(--space-sm); right: var(--space-sm);
  width: 44px; height: 44px;
  display: grid; place-items: center;
  color: var(--color-secondary);
  background: var(--color-surface-ghost);
  border: 0;
  border-radius: var(--radius-full);
  cursor: pointer;
}
.gate-dismiss svg { width: 18px; height: 18px; }
.gate-dismiss:hover { color: var(--color-primary); }
.gate-dismiss:active { transform: scale(var(--press-scale)); }

/* ── Startup gate ───────────────────────────────────────────────────────────
   Shown from first paint until auth and the saved-chart request resolve, so a
   returning user never sees the chart-setup form flash. */
.startup-gate {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: grid;
  place-items: center;
  padding: var(--space-lg);
  background: var(--color-bg);
}
.startup-gate[hidden] { display: none; }
.startup-card { display: grid; gap: var(--space-md); justify-items: center; text-align: center; }
.startup-status { color: var(--color-muted); font-size: var(--type-caption); }
.startup-gate .startup-actions { display: flex; gap: var(--space-sm); flex-wrap: wrap; justify-content: center; }

@media (max-width: 560px) {
  .auth-gate { padding: var(--space-sm); }
  .auth-card { padding: var(--space-lg) var(--space-md); }
}

/* The shell keeps its layout while inert; it must not become interactive again
   through a stray pointer event. */
.app-shell[inert] { pointer-events: none; user-select: none; }

@media (forced-colors: active) {
  .auth-card, .auth-privacy { border: 1px solid CanvasText; }
}

/* ── The starfield (Dev Update 4.3) ───────────────────────────────────────
   Behind the startup card, opacity-only twinkle, static under both
   reduced-motion refusals. Positions, sizes, and phases are inline from the
   deterministic generator in app.js — the same sky every open. */
.starfield { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.starfield i {
  position: absolute;
  border-radius: 50%;
  background: var(--brand-celestial-highlight, #b9a7ff);
  opacity: 0.16;
  animation: star-twinkle 3s ease-in-out infinite;
}
@keyframes star-twinkle {
  0%, 100% { opacity: 0.10; }
  50%      { opacity: 0.60; }
}
/* The card stacks above the field. */
.startup-card { position: relative; }
@media (prefers-reduced-motion: reduce) {
  .starfield i { animation: none; opacity: 0.28; }
}
:root[data-motion="reduced"] .starfield i { animation: none; opacity: 0.28; }
