/* ═══════════════════════════════════════════════════════════
   AUTH GATE — Fullscreen frosted glass login overlay
   ═══════════════════════════════════════════════════════════ */

.auth-gate {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Keyboard-shrink safety: _syncGateToKeyboard() clamps this element to the
     visible viewport; content taller than that must scroll, not silently
     overflow off both edges of a centered flexbox. */
  overflow-y: auto;
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease);
}

.auth-gate.hidden {
  opacity: 0;
  transform: scale(1.02);
  pointer-events: none;
}

.auth-gate-bg {
  /* fixed, not absolute: with the keyboard up the gate scrolls, and an
     absolute backdrop scrolled away with it, showing the app underneath. */
  position: fixed;
  inset: 0;
  /* The black scrim rides ON TOP of the tile (first background layer wins),
     knocking the checker back so it reads as texture rather than pattern.
     Done as a layer instead of opacity so the ::before/::after colour blobs,
     which are children, aren't dimmed along with it. */
  background-color: #000;
  background-image:
    linear-gradient(rgba(0, 0, 0, 0.58), rgba(0, 0, 0, 0.58)),
    url('../assets/splash-bg-dark.png?v=2');
  background-size: auto, 150px 150px;
  background-repeat: repeat, repeat;
  overflow: hidden;
}

.auth-gate-bg::before {
  content: '';
  position: absolute;
  top: -30%;
  left: -20%;
  width: 80vw;
  height: 80vw;
  background: radial-gradient(circle, rgba(64, 64, 96, 0.20) 0%, rgba(64, 64, 96, 0) 70%);
  filter: blur(80px);
  animation: float1 20s infinite alternate ease-in-out;
}

.auth-gate-bg::after {
  content: '';
  position: absolute;
  bottom: -20%;
  right: -25%;
  width: 90vw;
  height: 90vw;
  background: radial-gradient(circle, rgba(40, 58, 54, 0.13) 0%, rgba(40, 58, 54, 0) 70%);
  filter: blur(90px);
  animation: float2 25s infinite alternate ease-in-out;
}

.auth-gate-content {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 340px;
  padding: 0 28px;
  text-align: center;
}

/* ── Logo with fold animation ── */
.auth-gate-logo-wrap {
  width: 78px;
  height: 78px;
  margin: 0 auto 22px;
  perspective: 600px;
  box-sizing: border-box;
  background: none;
  border: none;
  border-radius: 0;
  overflow: visible;
}

.auth-gate-logo-img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: none;
  border-radius: 0;
  filter: none;
  animation: logoUnfold 1.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

@keyframes logoUnfold {
  0% {
    opacity: 0;
    transform: rotateY(-90deg) scale(0.85);
  }
  50% {
    opacity: 1;
    transform: rotateY(-10deg) scale(0.97);
  }
  100% {
    opacity: 1;
    transform: rotateY(0deg) scale(1);
  }
}

/* ── Wordmark ── */
.auth-gate-wordmark {
  font-family: 'Swansea', var(--font);
  font-size: 34px;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: #fff;
  margin-bottom: 36px;
  opacity: 0;
  animation: wordmarkFade 0.8s ease 0.8s forwards;
}

@keyframes wordmarkFade {
  0% { opacity: 0; transform: translateY(6px); }
  100% { opacity: 1; transform: translateY(0); }
}

.auth-gate-subtitle {
  font-size: 13px;
  font-weight: 400;
  color: var(--text-tertiary);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-bottom: 24px;
  opacity: 0;
  animation: wordmarkFade 0.8s ease 1s forwards;
}

/* ── Form Container (Borderless & Animated) ── */
.auth-gate-card {
  width: 100%;
  padding: 0;
  opacity: 0;
  animation: wordmarkFade 0.8s ease 1.1s forwards;
}

.auth-title {
  font-family: var(--font);
  font-size: 22px;
  font-weight: 600;
  color: #fff;
  margin: 0 0 18px;
  letter-spacing: -0.02em;
}

.auth-subtext {
  font-family: var(--font);
  font-size: 14px;
  color: var(--text-tertiary);
  line-height: 1.4;
  margin-bottom: 32px;
}

/* ── Inputs ──
   Near-opaque background (alpha .92) + backdrop-blur so the auth-gate-bg
   chevron pattern can't bleed through the field. The original rgba(255,
   255,255,0.05) let the tile show through clearly inside the input
   boxes, which read as broken on TestFlight. An interim .72 still let a
   faint pattern read on busy tiles; .92 is solid-feeling while keeping
   the glass-elevated aesthetic. */
.auth-gate-input {
  width: 100%;
  padding: 15px 16px;
  margin-bottom: 12px;
  /* Fully opaque — final act of the saga above: two alpha bumps (.72, .92)
     still bled the animated tile through WKWebView's backdrop-filter on
     device. A solid fill ends it; the blur is dropped as inert over opaque. */
  background: #14161c;
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: var(--radius-12);
  color: #fff;
  font-family: var(--font);
  font-size: 15px;
  outline: none;
  transition: border-color 0.2s, background 0.2s;
}

.auth-gate-input:focus {
  border-color: rgba(255, 255, 255, 0.22);
  background: #1a1c22;
}

.auth-gate-input::placeholder {
  color: var(--text-tertiary);
}

/* ── Legal checkbox ── */
.auth-gate-legal {
  margin: 12px 0 8px;
  padding: 12px;
  /* Opaque for the same reason as .auth-gate-input — this one was never
     re-bumped alongside the inputs and leaked the pattern worst of all. */
  background: #14161c;
  border-radius: var(--radius-12);
  border: 1px solid rgba(255, 255, 255, 0.08);
}

.auth-gate-legal-label {
  display: flex;
  gap: 10px;
  cursor: pointer;
  align-items: flex-start;
  font-size: 11px;
  color: var(--text-tertiary);
  line-height: 1.45;
  text-align: left;
}

.auth-gate-legal-label input[type="checkbox"] {
  margin-top: 2px;
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  accent-color: var(--gain);
}

.auth-gate-link {
  text-decoration: underline;
  color: var(--text-secondary);
}

/* ── Error ── */
.auth-gate-error {
  color: var(--loss);
  font-size: 12px;
  margin-bottom: 8px;
  min-height: 16px;
}

/* ── Buttons ── */
.auth-gate-btn {
  width: 100%;
  padding: 15px;
  border: none;
  border-radius: var(--radius-12);
  font-family: var(--font);
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  transition: opacity 0.15s, transform 0.15s;
  margin-top: 14px;
  margin-bottom: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.auth-gate-btn:active {
  opacity: 0.8;
  transform: scale(0.98);
}

.auth-gate-btn.primary {
  background: #fff;
  color: #000;
}

.auth-gate-btn.secondary {
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
}

.auth-gate-btn.apple {
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.auth-gate-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* ── Divider ── */
/* ── Actions & Toggles ── */
.auth-toggle-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-top: 32px;
  font-size: 13px;
  color: var(--text-secondary);
}

.auth-gate-text-btn {
  background: none;
  border: none;
  padding: 12px 16px;
  margin: -12px -8px;
  color: #fff;
  font-family: var(--font);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: opacity 0.2s;
  min-height: 44px;
}

.auth-gate-text-btn:hover {
  opacity: 0.7;
}

/* ── Forgot-password link (under the sign-in button) ── */
.auth-forgot-row {
  display: flex;
  justify-content: center;
  margin-top: 2px;
}

/* Tighter than the marketing subtext — sits just above the reset inputs. */
.reset-subtext {
  margin-bottom: 18px;
}

/* ── Confirmation state ── */
.auth-gate-confirm-icon {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: rgba(29, 242, 139, 0.1);
  border: 1px solid rgba(29, 242, 139, 0.3);
  color: var(--gain);
  font-size: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 16px;
}

.auth-gate-confirm-title {
  font-size: 18px;
  font-weight: 700;
  color: #fff;
  margin-bottom: 8px;
}

.auth-gate-confirm-text {
  font-size: 13px;
  color: var(--text-secondary);
  line-height: 1.5;
  margin-bottom: 20px;
}

/* Light mode: see the 2026-10 redesign block at the end (CSS variables). */

/* ── Password field with show/hide eye ── */
.auth-pw-wrap {
  position: relative;
}
.auth-pw-wrap .auth-gate-input {
  padding-right: 48px;
}
.auth-pw-eye {
  position: absolute;
  top: 0;
  right: 0;
  /* Matches the input's height (15 + 15 padding + ~18 line + 2 border) minus
     its 12px bottom margin, so the icon centres on the field, not the gap. */
  height: calc(100% - 12px);
  width: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  padding: 0;
  color: var(--text-tertiary);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.auth-pw-eye:active { color: #fff; }
.auth-pw-eye .eye-shut { display: none; }
.auth-pw-eye[aria-pressed="true"] .eye-open { display: none; }
.auth-pw-eye[aria-pressed="true"] .eye-shut { display: block; color: #fff; }

/* ── Keyboard up: compact the header so the form fits above the keyboard ── */
.auth-gate.gate-kb-open {
  align-items: flex-start;
  box-sizing: border-box;
  padding: calc(env(safe-area-inset-top, 0px) + 8px) 0 16px;
  -webkit-overflow-scrolling: touch;
}
.auth-gate.gate-kb-open .auth-gate-logo-wrap {
  width: 44px;
  height: 44px;
  margin-bottom: 10px;
}
.auth-gate.gate-kb-open .auth-gate-wordmark {
  display: none;
}
/* No transition on the logo size: _syncGateToKeyboard measures the layout
   right after toggling .gate-kb-open, and an animating logo made it measure
   the pre-shrink height and park the form ~30px too high. The content
   column's own transform transition carries the motion instead. */
.auth-gate-content {
  transition: transform 0.25s var(--ease);
}

/* ═══════════════════════════════════════════════════════════
   Sign-in, direction A (chosen 2026-10-01 from researched mockups).
   - Visible labels ABOVE fields, label closer to its field than to the next
     group (NN/g: placeholders-as-labels and white-space grouping).
   - "Forgot password?" beside the password label (Baymard, sign-in).
   - iOS text styles: Large Title 34/41, Body 17, labels 15, footnote 13.
   - Motion is feedback, not decoration: entrance stagger, focus ring,
     press scale, error shake, success check. Reduce Motion = fades only.
   ═══════════════════════════════════════════════════════════ */
.auth-gate {
  --ag-bg: #0a0a0a;
  --ag-field: #1c1c1e;
  --ag-field-focus: #232326;
  --ag-ring: rgba(255, 255, 255, 0.28);
  --ag-text: #ffffff;
  --ag-text-2: #a1a1a6;
  --ag-placeholder: #8e8e93;
  --ag-btn-bg: #ffffff;
  --ag-btn-text: #000000;
  --ag-ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  align-items: stretch;
  justify-content: flex-start;
}
[data-theme="light"] .auth-gate {
  --ag-bg: #ffffff;
  --ag-field: #f2f2f7;
  --ag-field-focus: #ebebf0;
  --ag-ring: rgba(0, 0, 0, 0.28);
  --ag-text: #000000;
  --ag-text-2: #6e6e73;
  --ag-placeholder: #8a8a8e;
  --ag-btn-bg: #000000;
  --ag-btn-text: #ffffff;
}

.auth-gate-bg { background: var(--ag-bg); }
.auth-gate-bg::before,
.auth-gate-bg::after { content: none; animation: none; }

.auth-gate-content {
  width: 100%;
  max-width: 440px;
  min-height: 100%;
  margin: 0 auto;
  box-sizing: border-box;
  padding: calc(env(safe-area-inset-top, 0px) + 48px) 24px calc(env(safe-area-inset-bottom, 0px) + 24px);
  display: flex;
  flex-direction: column;
  text-align: left;
  color: var(--ag-text);
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif;
}

/* Logo: the mark on dark, the app-icon tile on light (never inverted). */
.auth-gate-logo-wrap { width: 44px; height: 44px; margin: 0; perspective: none; }
.auth-gate-logo-img { width: 100%; height: 100%; animation: none; filter: none; }
.ag-logo-tile { display: none; }
[data-theme="light"] .auth-gate-logo-wrap { width: 48px; height: 48px; }
[data-theme="light"] .ag-logo-mark { display: none; }
[data-theme="light"] .ag-logo-tile { display: block; border-radius: 11px; }
.auth-gate-wordmark { display: none; }

.auth-gate-card { opacity: 1; animation: none; flex-grow: 1; display: flex; flex-direction: column; }
.auth-title {
  margin: 24px 0 0; text-align: left;
  font-size: 34px; line-height: 41px; font-weight: 700; letter-spacing: 0.01em;
  color: var(--ag-text);
}
.auth-subtext { margin: 8px 0 0; text-align: left; font-size: 17px; line-height: 22px; color: var(--ag-text-2); }

#auth-gate-form { margin-top: 32px; display: flex; flex-direction: column; }
.auth-field-label { display: block; margin-bottom: 8px; font-size: 15px; line-height: 20px; font-weight: 600; color: var(--ag-text); }
.auth-label-row { margin-top: 20px; display: flex; justify-content: space-between; align-items: baseline; }
.auth-label-row .auth-field-label { margin-bottom: 8px; }
.auth-forgot-row { margin: 0; }
.auth-confirm-group { margin-top: 20px; animation: agExpand 0.32s var(--ag-ease) both; }

.auth-gate-input {
  height: 52px; margin: 0; padding: 0 16px; box-sizing: border-box; width: 100%;
  font-size: 17px; font-family: inherit; color: var(--ag-text);
  background: var(--ag-field); border: none; border-radius: 12px;
  box-shadow: 0 0 0 0 var(--ag-ring);
  transition: background-color 0.18s var(--ag-ease), box-shadow 0.18s var(--ag-ease);
}
.auth-gate-input:focus { outline: none; background: var(--ag-field-focus); box-shadow: 0 0 0 2px var(--ag-ring); border: none; }
.auth-gate-input::placeholder { color: var(--ag-placeholder); }
.auth-pw-wrap .auth-gate-input { padding-right: 52px; }
.auth-pw-eye { top: 4px; right: 4px; width: 44px; height: 44px; color: var(--ag-placeholder); }
.auth-pw-eye svg { transition: opacity 0.15s var(--ag-ease), transform 0.15s var(--ag-ease); }
.auth-pw-eye:active svg { transform: scale(0.88); }
.auth-pw-eye[aria-pressed="true"] .eye-shut { color: var(--ag-text); }

.auth-gate-legal {
  margin: 20px 0 0; padding: 12px 16px;
  background: var(--ag-field); border: none; border-radius: 12px;
}
.auth-gate-legal-label { font-size: 13px; line-height: 18px; color: var(--ag-text-2); }
.auth-gate-link { color: var(--ag-text); }

.auth-gate-error { margin: 0; min-height: 0; font-size: 15px; line-height: 20px; color: #ff6961; text-align: left; }
.auth-gate-error:not(:empty) { margin-top: 12px; animation: agRise 0.24s var(--ag-ease) both; }
[data-theme="light"] .auth-gate-error { color: #d70015; }

.auth-gate-btn {
  position: relative; margin-top: 32px; height: 52px; width: 100%;
  border-radius: 14px; font-size: 17px; font-weight: 600; font-family: inherit;
  display: flex; align-items: center; justify-content: center;
  transition: transform 0.16s var(--ag-ease), opacity 0.16s var(--ag-ease);
}
.auth-gate-btn.primary { background: var(--ag-btn-bg); color: var(--ag-btn-text); border: none; }
.auth-gate-btn.primary:active:not(:disabled) { transform: scale(0.97); }
.auth-gate-btn:disabled { opacity: 1; }
.auth-gate-btn.is-loading, .auth-gate-btn.is-success { cursor: default; }
.ag-spinner {
  width: 20px; height: 20px; border-radius: 50%;
  border: 2.4px solid currentColor; border-right-color: transparent;
  animation: agSpin 0.7s linear infinite;
}
.ag-check { animation: agPop 0.32s var(--ag-ease) both; }
.ag-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* Tall tap target (12 + 20 + 12 = 44pt) without shifting the text: the
   base rule's -8px side margin pushed it 8px out of line. */
.auth-gate-text-btn { font-size: 15px; line-height: 20px; font-weight: 600; color: var(--ag-text); text-decoration: none; padding: 12px 0; margin: -12px 0; }
.auth-forgot-row .auth-gate-text-btn { font-weight: 500; }
.auth-toggle-row {
  margin-top: auto; padding-top: 24px; justify-content: center; gap: 6px;
  font-size: 15px; line-height: 20px; color: var(--ag-text-2);
}
.auth-gate-confirm-title { color: var(--ag-text); }
.auth-gate-confirm-text { color: var(--ag-text-2); }

/* Entrance: staggered rise, top to bottom. */
.auth-gate:not(.hidden) .auth-gate-logo-wrap { animation: agRise 0.42s var(--ag-ease) both; }
.auth-gate:not(.hidden) .auth-title { animation: agRise 0.42s var(--ag-ease) 0.05s both; }
.auth-gate:not(.hidden) .auth-subtext { animation: agRise 0.42s var(--ag-ease) 0.1s both; }
.auth-gate:not(.hidden) #auth-gate-form { animation: agRise 0.42s var(--ag-ease) 0.15s both; }
.auth-gate:not(.hidden) .auth-toggle-row { animation: agFade 0.42s var(--ag-ease) 0.25s both; }
/* Sign in <-> Create account: the heading crossfades. */
.ag-swap .auth-title, .ag-swap .auth-subtext { animation: agFade 0.22s var(--ag-ease) both; }
/* Wrong credentials: the iOS passcode shake, on the form as one unit.
   Animating the <input>s themselves left WebKit drawing the email
   placeholder ~8px low after the shake (seen on the iOS 26.5 Simulator). */
.auth-gate:not(.hidden) #auth-gate-form.ag-shake { animation: agShake 0.42s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; }

@keyframes agRise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes agFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes agExpand { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
@keyframes agPop { 0% { transform: scale(0.4); opacity: 0; } 70% { transform: scale(1.12); opacity: 1; } 100% { transform: scale(1); } }
@keyframes agSpin { to { transform: rotate(360deg); } }
@keyframes agShake {
  10%, 90% { transform: translateX(-2px); }
  20%, 80% { transform: translateX(5px); }
  30%, 50%, 70% { transform: translateX(-8px); }
  40%, 60% { transform: translateX(8px); }
}

@media (prefers-reduced-motion: reduce) {
  .auth-gate:not(.hidden) .auth-gate-logo-wrap,
  .auth-gate:not(.hidden) .auth-title,
  .auth-gate:not(.hidden) .auth-subtext,
  .auth-gate:not(.hidden) #auth-gate-form,
  .auth-gate:not(.hidden) .auth-toggle-row,
  .auth-confirm-group, .auth-gate-error:not(:empty) { animation: agFade 0.2s linear both; }
  .auth-gate:not(.hidden) #auth-gate-form.ag-shake, .ag-check { animation: none; }
  .auth-gate-btn.primary:active:not(:disabled) { transform: none; }
}

/* Keyboard up: drop the logo and tighten the top so the fields fit. */
.auth-gate.gate-kb-open .auth-gate-content { padding-top: calc(env(safe-area-inset-top, 0px) + 12px); min-height: 0; }
.auth-gate.gate-kb-open .auth-gate-logo-wrap { display: none; }
.auth-gate.gate-kb-open .auth-title { margin-top: 0; font-size: 28px; line-height: 34px; }
.auth-gate.gate-kb-open .auth-toggle-row { margin-top: 24px; }

/* ── Sign in with Apple / Google ── */
.auth-oauth[hidden], .auth-oauth [hidden] { display: none !important; }
.auth-oauth-divider {
  display: flex; align-items: center; gap: 12px; margin-top: 24px;
  font-size: 13px; color: var(--ag-text-2);
}
.auth-oauth-divider::before, .auth-oauth-divider::after {
  content: ''; flex: 1; height: 1px; background: currentColor; opacity: 0.25;
}
.auth-gate-btn.oauth {
  margin-top: 12px; gap: 10px;
  background: var(--ag-field); color: var(--ag-text); border: none;
}
.auth-oauth .auth-gate-btn.oauth:first-of-type { margin-top: 20px; }
.auth-gate-btn.oauth:active:not(:disabled) { transform: scale(0.97); }
.auth-gate-btn.oauth:disabled { opacity: 0.5; }
.auth-oauth-legal { margin: 14px 0 0; font-size: 12px; line-height: 16px; color: var(--ag-text-2); text-align: center; }
