/* ═══ SFTi — THE AUTH SURFACE. Log in · sign up · forgot · reset · verify · account · billing.
                                                                                              ═══
   ★ THIS FILE NO LONGER DECLARES A PALETTE, AND THAT WAS THE DEFECT (operator 2026-08-12:
   "the auth pages and sign on are not our theme and not full screen"). It used to open with its
   own `:root` — green `#3aff8a`, cyan `#6cf8ff`, a cyan border, a green page wash — under a
   first line claiming it "matches the main PWA style". That claim was FALSE: the deck is
   red → gold → silver (app/shared/css/tokens.css, whose own header states the storefront is the
   reference). So these seven documents were the one part of the site wearing a different brand,
   and a visitor met it at the first screen that asks for a password.

   THE NAMES BELOW ARE KEPT — forty-odd rules in this file already speak them, and renaming would
   touch every one — and every VALUE is now a deck token. That makes this an ALIAS LAYER rather
   than a second registry: change the deck and auth follows, which is what stops the drift
   recurring rather than merely correcting it once.

   ⚠ THE CLAIM, STATED SO IT CAN BE CHECKED RATHER THAN BELIEVED: **no HUE is declared in this
   file.** 24 rgba literals became `color-mix` off a deck token (11 green → --accent-gold,
   2 cyan → --accent-silver, 6 pink → --danger, 5 well → --bg-void) and 3 `#050810` became
   --bg-void. What remains is two NEUTRAL scrims — `rgba(0,0,0,0.5)` on the card's drop shadow and
   `rgba(0,0,0,0.3)` on the key-reveal well, which are shade not hue — plus the two hexes quoted in
   the paragraph above, which are PROSE describing what was deleted. A check for this file must look
   for a declared hue, not for the character `#`, or it fires on its own documentation. */
:root {
  --bg-deep:  var(--bg-void);
  --bg-glass: var(--glass-bg);
  --border:   var(--glass-border);

  /* THE STOREFRONT'S OWN PAIR. Gold → silver is the wordmark and `.section-title`, so the primary
     control wears the site's existing accent rather than one invented here. It is also the
     readable choice with the dark ink this button already had: gold measures 8.9:1 and silver
     11:1 against --bg-void, where the brand red would have been ~4.4:1 under 15px bold text. */
  --accent:   var(--accent-gold);
  --accent-2: var(--accent-silver);

  --text:     var(--text-primary);
  --dim:      var(--text-secondary);
  /* the deck's BRIGHT red, deliberately not --accent-red: the brand red is structural here (card
     borders, the section spine), and an error that reads as chrome is not an error. */
  --danger:   var(--accent-red-bright);
}
* { box-sizing: border-box; }
html, body {
  margin: 0; padding: 0;
  /* the page wash is the deck's own red, mixed rather than written as a literal — the old one was
     a green that no token declares. */
  background: radial-gradient(ellipse at top,
              color-mix(in srgb, var(--accent-red) 7%, transparent), var(--bg-deep) 70%);
  color: var(--text);
  font-family: 'Rajdhani', system-ui, -apple-system, sans-serif;
  min-height: 100vh;
  /* THE DOCUMENT RUBBER-BAND (same fix as app/system/css/shell.css and index/shop's own
     reset.css, operator 2026-08-12: "the same lock… the scroll lock you built earlier"): body IS
     the real scroller on these seven pages too — no separate .view-container the way the cockpit
     has — so the lock belongs here directly. */
  overflow-x: hidden;
  overscroll-behavior: none;
}
/* ★ THE STICKY FOOTER, THE ACTUAL FIX (operator 2026-08-13, on a screenshot of login.html: "the
   gap is from the bottom of the words in the footer to the bottom of my viewport" — a SHORT page
   left the footer floating right under a short card, with the rest of the viewport a dead void
   below it). `min-height: 100vh` on `.auth-shell` alone (the PREVIOUS fix's predecessor) forced
   this dead void's mirror-image defect: on a LONG page the shell claimed the full 100vh even when
   its own content needed less, so the footer — a SIBLING after the shell closes — never started
   until the full 100vh was spent (account.html measured 101px of that). Neither a forced height
   on the shell NOR no height at all is correct; the shell has to GROW to fill whatever the
   viewport leaves over, on a page short enough to have any left over, and simply BE its content's
   height otherwise. That is what flex accomplishes and a single min-height cannot: `body` is the
   flex column, `.auth-shell` is the ONE child that grows (`flex: 1 0 auto`), and `footer` — the
   next sibling, ungrown by default — is pushed to sit at the true bottom of a short page and
   simply follows the content on a long one, never a fixed height either way. */
body {
  display: flex;
  flex-direction: column;
}
/* ── THE SAFE AREA — the other half of "not full screen" ─────────────────────────────────
   `viewport-fit=cover` in the document lets the page paint under the notch and past the home
   indicator; it does NOTHING without the padding that keeps content out from under them. Both
   halves or neither — the same pairing index/shop/system already state in their own heads.
   `max()` on the sides so a landscape notch cannot eat the card's gutter. */
.auth-shell {
  display: flex; flex-direction: column; align-items: center;
  /* ★ CENTRED, NOT TOP-ALIGNED (operator 2026-08-13: "sign in page reset password page and
     verify email page have the long footer… fix that to be the same size footer as billing.html"
     — billing.html never shows this because its own content is tall enough to reach the bottom
     on its own; a short page's flex-grown shell dumped its ENTIRE leftover space as one block
     between the card and the footer, measured at 223px on login.html, which is what read as the
     footer sitting "long" / detached from the page rather than as a normal composed layout.
     `justify-content: center` splits that same leftover space evenly above and below the card
     instead of leaving it in one visible lump — the total whitespace does not change, only
     whether it reads as deliberate (centred) or accidental (one gap). */
  justify-content: center;
  flex: 1 0 auto;
  padding: calc(30px + env(safe-area-inset-top, 0px))
           max(16px, env(safe-area-inset-right, 0px))
           max(16px, env(safe-area-inset-bottom, 0px))
           max(16px, env(safe-area-inset-left, 0px));
}
/* the wordmark, as the real header draws it: Orbitron, gold → silver through the text, gold
   bloom. app/shared/css/header.css owns the header's own copy; this is the same treatment on a
   document that has no header. */
.auth-brand {
  font-family: 'Orbitron', monospace;
  font-size: 1.6rem; font-weight: 900; letter-spacing: 0.18em;
  background: linear-gradient(90deg, var(--accent-gold), var(--accent-silver));
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  filter: drop-shadow(var(--glow-gold));
  margin-bottom: 14px;
}
.auth-card {
  background: var(--bg-glass);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 24px 22px;
  width: 100%; max-width: 420px;
  box-shadow: 0 24px 64px rgba(0,0,0,0.5), inset 0 0 80px color-mix(in srgb, var(--accent-silver) 3%, transparent);
}
.auth-h1 {
  font-size: 1.4rem; font-weight: 700; margin: 0 0 6px;
  letter-spacing: 0.04em;
}
.auth-sub {
  color: var(--dim); font-size: 0.85rem; margin-bottom: 16px;
}
.auth-field { margin-bottom: 14px; }
.auth-field label {
  display: block; font-size: 0.7rem; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--dim); margin-bottom: 6px;
}
.auth-field input {
  width: 100%; padding: 12px 14px;
  background: color-mix(in srgb, var(--bg-void) 60%, transparent);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  font-size: 0.95rem;
  font-family: inherit;
}
.auth-field input:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-gold) 18%, transparent);
}
/* min-height is the FINGER FLOOR, stated once. Several call sites narrow this button with an
   inline `padding:10px 16px` for a compact inline control, which measured 37px at 390px — under
   the 44px touch target. Putting the floor on the class means a per-site padding override can
   never take a control below it, rather than each site remembering. inline-flex so the floor
   still centres the label. */
.auth-btn {
  width: 100%; padding: 12px 18px; margin-top: 8px;
  min-height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  border: none; border-radius: 8px;
  color: var(--bg-void); font-weight: 800; font-size: 0.95rem;
  letter-spacing: 0.04em; cursor: pointer;
}
.auth-btn:hover { filter: brightness(1.1); }
.auth-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.auth-msg { margin-top: 14px; padding: 10px 12px;
            border-radius: 8px; font-size: 0.85rem; }
.auth-msg.ok    { background: color-mix(in srgb, var(--accent-gold) 12%, transparent); color: var(--accent);
                   border: 1px solid color-mix(in srgb, var(--accent-gold) 40%, transparent); }
.auth-msg.err   { background: color-mix(in srgb, var(--danger) 12%, transparent); color: var(--danger);
                   border: 1px solid color-mix(in srgb, var(--danger) 40%, transparent); }
/* ★ GOLD, NOT SILVER, AND THIS WAS CAUGHT IN THE SCREENSHOT RATHER THAN THE STYLESHEET. The first
   pass of the deck mapping put links on `--accent-2`, which is a faithful translation of the old
   cyan `--accent-2` and still WRONG: silver against `--text-primary` (#c0c0c0 vs #e8e8f0) is a
   ~1.3:1 separation, so "create an account" and "Forgot password?" rendered as plain sentence text
   with no affordance at all. An accent that does not separate from body copy is not an accent. */
.auth-link { color: var(--accent); text-decoration: none;
             font-size: 0.85rem; }
.auth-link:hover { text-decoration: underline; }
.auth-foot { margin-top: 16px; text-align: center; color: var(--dim);
             font-size: 0.8rem; }

/* ── THE IDENTITY LINE — email and tier on one row (operator 2026-08-13: "I should be able to
   see my Email and Level on the same line"). Email truncates before tier ever does: the tier
   word is short and fixed (Free/Starter/Pro/Enterprise), the email is the one side that can run
   long, so it is the one side that gets `min-width:0` + ellipsis rather than the row wrapping to
   a second line on a narrow phone. */
.acct-identity {
  display: flex; align-items: baseline; gap: 8px;
  margin-top: 8px; font-size: 0.92rem;
}
.acct-identity #acct-email {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--dim);
}
.acct-sep { color: var(--dim); opacity: 0.5; flex: 0 0 auto; }
.acct-tier-badge {
  flex: 0 0 auto; font-weight: 800; letter-spacing: 0.03em;
  color: var(--accent);
}

/* ── THE BILLING TAGLINE (operator 2026-08-13: "center and style the pick a tier... it doesn't
   match the page") — .auth-h1 alone is the plain left-aligned treatment "Account"/"Log in" use,
   sized for a short one-or-two-word title. "Pick a Tier, Cancel any time." is a full sentence now,
   reading more like a tagline than a title, so it gets the tagline treatment the rest of the site
   already uses for exactly that role: the SAME gold→silver gradient + glow app/shared/css's own
   .auth-brand (the SFTi wordmark) carries, centered rather than left-hung. */
.billing-tagline {
  text-align: center;
  background: linear-gradient(90deg, var(--accent-gold), var(--accent-silver));
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  filter: drop-shadow(var(--glow-gold));
}

/* ── ISSUE KEY + CHANGE PASSWORD, ONE ROW, EQUAL WIDTH (operator 2026-08-13: "next to each
   other in the same sized box") — .auth-btn defaults to width:100%, so each needs flex:1 to
   share the row rather than each claiming the full width and stacking. */
.acct-btn-row {
  display: flex;
  gap: 10px;
  margin-top: 10px;
}
.acct-btn-row .auth-btn {
  width: auto;
  flex: 1 1 0;
  min-width: 0;
  padding: 10px 10px;
  font-size: 0.82rem;
  margin-top: 0;
}

/* ── THE PASSWORD MODAL — a lightweight overlay, not the cockpit's modal-sheet system (that one
   is wired to app.js's own state machine and drag-to-dismiss; these seven documents load none of
   system.html's JS at all, so it is not reachable here). Tap the backdrop or ✕ to close, same as
   every other dismissible surface on the site. */
.modal-backdrop {
  display: none;
  position: fixed; inset: 0; z-index: 500;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  align-items: center; justify-content: center;
  padding: max(20px, env(safe-area-inset-top, 0px)) 20px max(20px, env(safe-area-inset-bottom, 0px));
}
.modal-backdrop.active { display: flex; }
body.modal-open { overflow: hidden; }
.modal-card {
  background: var(--bg-glass); border: 1px solid var(--border);
  border-radius: 16px; padding: 22px 20px;
  width: 100%; max-width: 380px;
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.6),
              inset 0 0 80px color-mix(in srgb, var(--accent-silver) 3%, transparent);
}
.modal-card-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 16px;
  font-weight: 800; font-size: 1.05rem; letter-spacing: 0.02em;
}
.modal-close {
  background: none; border: none; color: var(--dim);
  font-size: 1rem; line-height: 1; cursor: pointer;
  min-width: 32px; min-height: 32px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 6px;
}
.modal-close:hover { color: var(--text); background: color-mix(in srgb, var(--text) 8%, transparent); }
.modal-card .auth-field:last-of-type { margin-bottom: 18px; }

/* ── THE FOOTER'S NAV CLEARANCE IS DEAD WEIGHT HERE (operator 2026-08-13: "no need to scroll,
   right now it's clunky and big"). app/shared/css/footer.css's `padding-bottom` reserves ~80px+
   for the floating bottom nav on index/shop/system — these seven pages carry NO nav at all, so
   that reserve is pure unused space stacked under a footer that is already the document's last
   element. `.auth-footer` (a class, specificity 0,1,0) beats footer.css's bare `footer` element
   selector (0,0,1) regardless of which stylesheet loads second, so this does not need `!important`
   and does not need to live inside footer.css itself — which stays the one file that knows
   nothing about auth pages, exactly as its own header insists. */
.auth-footer {
  padding-bottom: max(20px, env(safe-area-inset-bottom, 0px));
}
.tier-grid { display: grid; gap: 10px; margin: 12px 0; }
.tier-card {
  background: color-mix(in srgb, var(--bg-void) 60%, transparent); border: 1px solid var(--border);
  border-radius: 10px; padding: 12px 16px;
  display: flex; justify-content: space-between; align-items: center;
}
.tier-card.active { border-color: var(--accent); box-shadow: 0 0 24px color-mix(in srgb, var(--accent-gold) 20%, transparent); }
.tier-name { font-weight: 800; letter-spacing: 0.04em; }
.tier-price { color: var(--accent); font-weight: 800; }
.tier-meta { color: var(--dim); font-size: 0.78rem; margin-top: 4px;
             font-family: ui-monospace, SFMono-Regular, monospace; }
.api-key-row {
  background: color-mix(in srgb, var(--bg-void) 60%, transparent); border: 1px solid var(--border);
  border-radius: 8px; padding: 10px 12px; margin-bottom: 8px;
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 0.78rem;
  display: flex; justify-content: space-between; align-items: center;
}
.api-key-revoke { background: transparent; border: 1px solid color-mix(in srgb, var(--danger) 40%, transparent);
                   color: var(--danger); padding: 4px 10px; border-radius: 6px;
                   font-size: 0.7rem; cursor: pointer; }

/* ── Loading state ── */
.auth-btn[data-loading] {
  pointer-events: none; opacity: 0.75; position: relative; color: transparent;
}
.auth-btn[data-loading]::after {
  content: ''; position: absolute;
  width: 14px; height: 14px;
  border: 2px solid color-mix(in srgb, var(--bg-void) 30%, transparent);
  border-top-color: var(--bg-void);
  border-radius: 50%;
  animation: btn-spin 0.6s linear infinite;
  left: 50%; top: 50%; margin: -7px 0 0 -7px;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }

/* ── Copy button ── */
.copy-btn {
  background: transparent; border: 1px solid var(--border);
  color: var(--accent-2); padding: 2px 8px; border-radius: 4px;
  font-size: 0.68rem; font-family: ui-monospace, monospace;
  cursor: pointer; transition: background 0.15s, color 0.15s;
  white-space: nowrap;
}
.copy-btn:hover { background: color-mix(in srgb, var(--accent-silver) 10%, transparent); }
.copy-btn.copied { color: var(--accent); border-color: color-mix(in srgb, var(--accent-gold) 40%, transparent); }

/* ── Key reveal panel (replaces alert() for new key) ── */
.key-reveal-panel {
  background: color-mix(in srgb, var(--accent-gold) 6%, transparent); border: 1px solid color-mix(in srgb, var(--accent-gold) 30%, transparent);
  border-radius: 10px; padding: 14px 16px; margin: 12px 0; display: none;
}
.key-reveal-panel.active { display: block; }
.key-reveal-label {
  font-size: 0.68rem; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--accent); margin-bottom: 6px;
}
.key-reveal-value {
  font-family: ui-monospace, SFMono-Regular, monospace; font-size: 0.78rem;
  word-break: break-all; color: var(--text); margin: 6px 0;
  background: rgba(0,0,0,0.3); padding: 8px 10px; border-radius: 6px;
}
.key-reveal-actions { display: flex; gap: 8px; align-items: center; margin-top: 8px; }
.key-reveal-note { font-size: 0.72rem; color: var(--dim); flex: 1; }

/* ── Inline label form ── */
.label-issue-form { display: none; margin: 8px 0; }
.label-issue-form.active { display: flex; gap: 8px; align-items: center; }
.label-issue-form input {
  flex: 1; padding: 8px 10px;
  background: color-mix(in srgb, var(--bg-void) 60%, transparent); border: 1px solid var(--border);
  border-radius: 6px; color: var(--text); font-size: 0.85rem; font-family: inherit;
}
.label-issue-form input:focus { outline: none; border-color: var(--accent); }
.btn-sm {
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  border: none; border-radius: 6px; color: var(--bg-void);
  font-weight: 700; font-size: 0.78rem; padding: 7px 14px; cursor: pointer;
  white-space: nowrap;
}
.btn-ghost-sm {
  background: transparent; border: 1px solid var(--border); color: var(--dim);
  padding: 7px 12px; border-radius: 6px; font-size: 0.78rem; cursor: pointer;
}

/* ── Inline revoke confirm ── */
.revoke-confirm { display: none; padding: 6px 0; }
.revoke-confirm.active { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.revoke-confirm-msg { font-size: 0.78rem; color: var(--danger); flex: 1; min-width: 120px; }
.btn-danger-sm {
  background: transparent; border: 1px solid color-mix(in srgb, var(--danger) 50%, transparent);
  color: var(--danger); padding: 4px 10px; border-radius: 6px;
  font-size: 0.7rem; cursor: pointer; white-space: nowrap;
}
.btn-cancel-sm {
  background: transparent; border: 1px solid var(--border);
  color: var(--dim); padding: 4px 10px; border-radius: 6px;
  font-size: 0.7rem; cursor: pointer; white-space: nowrap;
}

/* ── Tier badge ── */
.tier-badge {
  font-size: 0.65rem; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; background: color-mix(in srgb, var(--accent-gold) 12%, transparent);
  color: var(--accent); border: 1px solid color-mix(in srgb, var(--accent-gold) 35%, transparent);
  border-radius: 4px; padding: 2px 7px; display: inline-block;
}

/* ── API key row: extend for copy + revoke + confirm ── */
.api-key-row { flex-wrap: wrap; gap: 6px; align-items: flex-start; }
.api-key-row-main { display: flex; justify-content: space-between;
  align-items: center; width: 100%; gap: 8px; }
.api-key-row-actions { display: flex; gap: 6px; align-items: center; flex-shrink: 0; }

/* ── Upgrade banner (from Stripe redirect) ── */
.upgrade-banner {
  padding: 10px 14px; border-radius: 8px; margin-bottom: 16px; font-size: 0.85rem;
}
.upgrade-banner.success {
  background: color-mix(in srgb, var(--accent-gold) 10%, transparent); color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent-gold) 30%, transparent);
}
.upgrade-banner.cancelled {
  background: color-mix(in srgb, var(--danger) 7.0%, transparent); color: var(--dim);
  border: 1px solid color-mix(in srgb, var(--danger) 20%, transparent);
}
