/* ============================================================================
   L2Everdream — account pages (login · register · dashboard)
   ----------------------------------------------------------------------------
   Layered ON TOP of site.css — every color, font and radius here is an existing
   token. No new palette, no admin-dashboard theme: these pages are part of the
   site, so they inherit the blurple-on-twilight ground and use the lantern only
   where it earns it (the single warm "your light" accent, used sparingly).
   ========================================================================== */

/* ---------- The narrow column both auth forms sit in ---------- */
.auth-wrap {
  max-width: 460px;
  margin: 0 auto;
  padding: 72px 28px 96px;
}
.auth-head { text-align: center; margin-bottom: 34px; }
.auth-head .eyebrow {
  font-family: var(--mono); font-size: 11.5px; letter-spacing: 0.3em;
  text-transform: uppercase; color: var(--blurple-lit);
  margin: 0 0 14px;
}
.auth-head h1 {
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(30px, 5vw, 40px); line-height: 1.15;
  margin: 0 0 12px; color: var(--starlight);
}
.auth-head p { color: var(--body); margin: 0; font-size: 15.5px; }

/* ---------- The card ---------- */
.auth-card {
  background: linear-gradient(180deg, var(--surface) 0%, var(--field) 100%);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 30px 28px;
}

/* ---------- Fields ---------- */
.field { margin-bottom: 20px; }
.field label {
  display: block; font-size: 13px; font-weight: 600; letter-spacing: 0.02em;
  color: var(--light-blurple); margin-bottom: 7px;
}
.field input, .field select {
  width: 100%;
  background: var(--void);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  color: var(--starlight);
  font-family: var(--sans);
  font-size: 16px; /* 16px avoids iOS zoom-on-focus */
  padding: 12px 14px;
  transition: border-color 140ms ease, box-shadow 140ms ease;
}
.field input:focus, .field select:focus {
  outline: none;
  border-color: var(--blurple-hi);
  box-shadow: 0 0 0 3px rgba(88, 101, 242, 0.22);
}
.field .hint { display: block; margin-top: 7px; font-size: 12.5px; color: var(--greyple); }
/* "Forgot password?" — same slot/typography as .hint, but a real link. */
.field .field-link { display: inline-block; margin-top: 7px; font-size: 12.5px; color: var(--blurple-lit); }
.field .field-link:hover { color: var(--light-blurple); text-decoration: underline; }

/* ---------- Buttons ---------- */
/* ⚠️ BLURPLE, not amber (Chris 2026-08-28: "create game account would change to
   secondary button colors, like the blurple"). Amber is now reserved for the ONE
   download CTA (.btn-launcher below, matching .connect-btn on the homepage) so
   there is one amber "the thing you came here to do" per page; this form's
   submit is real but secondary to that, same footing as .discord-btn elsewhere
   on the site. Was the amber gradient (dark ink) this file used before that CTA
   existed — /login and /register still use THIS class too, and neither of
   those pages has a download button competing with it, so blurple reads fine
   there as their one real action. */
.btn-primary {
  display: block; width: 100%;
  background: var(--blurple); color: #fff;
  border: 0; border-radius: var(--radius-sm);
  font-family: var(--sans); font-size: 15.5px; font-weight: 600;
  padding: 13px 20px; cursor: pointer;
  transition: background 140ms ease, transform 140ms ease;
}
@media (hover: hover) {
  .btn-primary:hover { background: #4752C4; } /* Discord's own hover blurple, matching .btn-launcher/.discord-btn */
}
.btn-primary:active { transform: translateY(1px); }
.btn-primary:disabled { opacity: 0.55; cursor: not-allowed; }

/* ---------- Messages ---------- */
.alert {
  border-radius: var(--radius-sm);
  padding: 12px 15px; margin-bottom: 22px;
  font-size: 14.5px; line-height: 1.5;
}
.alert-error {
  background: rgba(240, 122, 122, 0.10);
  border: 1px solid rgba(240, 122, 122, 0.34);
  color: #F5C6C6;
}
.alert-ok {
  background: rgba(147, 192, 172, 0.10);
  border: 1px solid rgba(147, 192, 172, 0.34);
  color: var(--verdance);
}
.alert-note {
  background: var(--wash);
  border: 1px solid var(--line);
  color: var(--body);
}

.auth-alt { text-align: center; margin: 22px 0 0; font-size: 14.5px; color: var(--greyple); }

/* ---------- Dashboard ---------- */
.dash-head {
  border-bottom: 1px solid var(--line-soft);
  padding: 54px 0 26px; margin-bottom: 34px;
}
.dash-head .dash-in {
  display: flex; justify-content: space-between; align-items: flex-end;
  gap: 20px; flex-wrap: wrap;
}
.dash-head h1 {
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(28px, 4.4vw, 38px); margin: 0 0 6px; color: var(--starlight);
}
.dash-head .who { font-family: var(--mono); font-size: 13px; color: var(--greyple); }

/* A quiet secondary action — sign out shouldn't compete with the primary CTA. */
.btn-quiet {
  background: transparent; color: var(--greyple);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  font-family: var(--sans); font-size: 14px; font-weight: 500;
  padding: 9px 16px; cursor: pointer;
  transition: color 140ms ease, border-color 140ms ease;
}
.btn-quiet:hover { color: var(--light-blurple); border-color: var(--blurple-hi); }

/* ---------- The dashboard's DESKTOP shape ---------- */
/* ⚠️ THE STACK WAS THE ONLY SHAPE THERE EVER WAS (Chris 2026-08-30, from a
   wide-monitor screenshot: "the content sections u cant even see create
   account at the bottom. looks good for mobile not for desktop").
   Four full-width sections stacked down a 1360px column, each holding a single
   ~270px card, left ~1000px of dead space beside every card and pushed "Create
   a game account" a whole screen below the fold — the page was mobile-first
   and never got a second shape.
   The split is by ROLE, not by size: what you READ (server status, the
   launcher) goes to a right rail; what you DO (your game accounts, creating
   one) takes the main column, so the create form lands above the fold at every
   desktop height.
   ⚠️ DOM ORDER IS side-THEN-main ON PURPOSE — the mobile stack then keeps the
   exact order Chris already approved (status, launcher, accounts, create)
   with no `order` juggling, and desktop places the rail second via grid. */
.dash-grid { display: grid; }
/* ⚠️ `.section-title:not(:first-of-type)` is scoped to the PARENT, so wrapping
   the sections in two columns silently zeroed the gap above the FIRST heading
   in each — in the stacked layout that put "Game accounts" flush against the
   launcher card. Stated explicitly here rather than left to the sibling rule. */
.dash-main > .section-title:first-of-type { margin-top: 44px; }
@media (min-width: 1000px) {
  .dash-grid {
    grid-template-columns: minmax(0, 1fr) 344px;
    column-gap: 40px;
    align-items: start;
  }
  .dash-main { grid-column: 1; grid-row: 1; }
  .dash-side { grid-column: 2; grid-row: 1; }

  /* Section rhythm inside a column comes from the heading's own 44px top
     margin alone. The grids' 44px bottom margin is for the STACK, where it is
     the only separator; leaving both stacked an 88px hole between a card and
     the next heading, which in a 344px rail reads as a broken layout. */
  .dash-main > .acct-grid, .dash-main > .empty, .dash-side > .status-grid { margin-bottom: 0; }
  /* Side by side, the two columns start level — no gap above either heading. */
  .dash-main > .section-title:first-of-type { margin-top: 0; }

  /* In the rail the launcher is a stacked card, not a row — 344px cannot hold
     the sentence and the button side by side. Same shape the phone breakpoint
     below already gives it, at a different width. */
  .dash-side .launcher-card { flex-direction: column; align-items: stretch; gap: 14px; }
  .dash-side .btn-launcher { width: 100%; }

  /* Flush to BOTH edges of its column now, so it anchors against the account
     grid above it rather than floating (Chris 2026-08-28 made it flush left
     for that reason; in a column the same argument takes it full width). */
  .dash-main .create-card { max-width: none; }
  /* ⚠️ .btn-primary is width:100% because it was written for the 460px auth
     card. Stretched across a full-width panel it stops reading as a button. */
  .dash-main .create-card .btn-primary { width: auto; min-width: 232px; }
}

.section-title {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin: 0 0 18px;
}
/* ⚠️ BREATHING ROOM BETWEEN SECTIONS (Chris 2026-08-23, from a screenshot:
   "'game accounts' need top margin"). The first section-title ("The launcher")
   already gets its gap from .dash-head's own bottom margin; every section
   AFTER the first was sitting flush against whatever card/grid came before it. */
.section-title:not(:first-of-type) { margin-top: 44px; }
/* The companion can stand on the card directly below a heading (Server
   status, Game accounts, Create a game account are all data-critter-surface
   platforms) — he's 44px tall standing at the card's own top edge, and the
   base 18px gap above wasn't enough room, so he rendered on top of the
   heading text itself. Verified from a live screenshot, 2026-09-04: "napping
   on the server status card" with the sprite covering the word "Server".
   Scoped to .dash-grid, not the shared .section-title rule other pages
   (features.astro etc.) also use — this is specifically about giving a
   44px-tall creature room to stand, which only matters here. */
.dash-grid .section-title { margin-bottom: 46px; }
.section-title h2 {
  font-family: var(--serif); font-weight: 400; font-size: 23px;
  margin: 0; color: var(--starlight);
}
.section-title .count { font-family: var(--mono); font-size: 12.5px; color: var(--greyple); }

/* ---------- The account grid ---------- */
.acct-grid {
  display: grid;
  /* auto-FIT for the same reason .status-grid uses it: with one account on a
     wide column, auto-fill holds the phantom tracks open and the card sits
     marooned beside ~600px of nothing, unanchored to the full-width create
     panel under it. Fitting the tracks makes the column read as one stack of
     panels — and with 2+ accounts the two behave identically. */
  grid-template-columns: repeat(auto-fit, minmax(268px, 1fr));
  gap: 16px;
  margin-bottom: 44px;
}
.acct-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 20px;
  transition: border-color 160ms ease;
}
.acct-card:hover { border-color: rgba(136, 148, 247, 0.28); }

/* ⭐ THE LAUNCHER CARD — the download's home, behind the login (2026-07-26).
   A row rather than a stacked card, because it holds one action and reads better
   beside its explanation. */
.launcher-card { display: flex; align-items: center; gap: 20px; justify-content: space-between; }
.launcher-t { margin: 0 0 4px; font-weight: 600; color: var(--starlight, #F5F6FF); font-size: 15.5px; }
.launcher-d { margin: 0; color: var(--greyple, #9096B8); font-size: 14px; line-height: 1.5; max-width: 52ch; }
/* The game client is a SECOND step and is styled to read as one: smaller than the
   launcher's own description, no button, no card of its own. Two equally-weighted
   download buttons would make a new player choose, and the wrong choice — client
   first, no launcher — leaves them with 3 GB and nothing to run it with. */
.launcher-client { margin: 10px 0 0; font-size: 13px; color: var(--greyple, #9096B8); }
/* ⚠️ A DISABLED CONTROL, NOT A DEAD LINK. There is no binary yet, so this must
   not be an <a> that goes nowhere — a link that does nothing is worse than a
   control that says why. Swap it for the real anchor when the launcher ships.
   ⚠️ STYLED LIKE THE REAL DOWNLOAD BUTTON (Chris 2026-08-23: "I want at least
   a download button in the download color. even tho we dont have a download
   link yet"). Was a muted, dashed, low-contrast pill; now matches the nav's
   own solid blurple CTA (.nav-right .nav-cta) so it reads as the real thing
   even though it can't be clicked yet — "Not released yet" is what still
   signals that, not a washed-out color. */
.btn-disabled { flex: none; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 42px; padding: 0 20px; border-radius: 10px; white-space: nowrap;
  font-size: 14.5px; font-weight: 600; color: #fff;
  background: var(--blurple); border: 1px solid transparent;
  box-shadow: 0 6px 18px -10px rgba(88, 101, 242, .7);
  cursor: not-allowed; }
/* ⚠️ AMBER now, matching the homepage's actual Download Everdream button
   (Chris 2026-08-28: "download everdream colors to match that same button as
   on homepage"). This card used to preview the download in blurple because
   that was .btn-disabled's placeholder color before a real download existed
   (2026-08-23 note above) — now that /download is real, this is THE download
   CTA and should carry the site's one amber "do this" identity (.connect-btn),
   not the blurple that .btn-primary below has moved into instead. Same dark-
   ink-stays-on-hover rule as .connect-btn (Chris: pale text on amber "hurts my
   eyes and is hard to read") — the background alone carries the hover state. */
.btn-launcher { flex: none; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 42px; padding: 0 20px; border-radius: 10px; white-space: nowrap;
  font-size: 14.5px; font-weight: 600; color: #2a1c07; text-decoration: none;
  background: linear-gradient(180deg, var(--ember), var(--lantern)); border: 1px solid transparent;
  box-shadow: 0 6px 18px -10px rgba(246, 198, 122, .7); }
@media (hover: hover) {
  .btn-launcher:hover { background: linear-gradient(180deg, #FFD79A, var(--ember)); color: #2a1c07; }
}
@media (max-width: 560px) {
  .launcher-card { flex-direction: column; align-items: stretch; gap: 14px; }
  .btn-disabled, .btn-launcher { width: 100%; }
}
.acct-card .acct-top {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 12px; margin-bottom: 6px;
}
.acct-card .login {
  font-family: var(--mono); font-size: 16px; color: var(--starlight);
  word-break: break-all;
}
.acct-card .server {
  font-size: 12.5px; color: var(--greyple); margin-bottom: 16px;
}

/* Status pill — the one place the lantern earns its warmth (a pending account
   is literally "the light is on, waiting"). */
.pill {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.08em;
  text-transform: uppercase; white-space: nowrap;
  padding: 4px 9px; border-radius: 999px;
}
.pill-active  { background: rgba(147, 192, 172, 0.14); color: var(--verdance);  border: 1px solid rgba(147,192,172,0.32); }
.pill-pending { background: rgba(240, 182, 122, 0.13); color: var(--lantern);   border: 1px solid rgba(240,182,122,0.30); }
.pill-failed  { background: rgba(240, 122, 122, 0.12); color: #F0A0A0;          border: 1px solid rgba(240,122,122,0.30); }

/* ---------- The card's own actions (2026-09-01) ---------- */
/* ⭐ SMALL, SECONDARY, AND OFF TO THE SIDE (Chris, 2026-09-01: "Make the button
   smaller. Using secondary button color. And it doesn't need to be at the
   bottom can be more off to the side").
   It began as a full-width bar under a hairline, which gave a rarely-used
   action the visual weight of the card's main event. Now it sits right-aligned
   on its own line: present when you look for it, invisible when you aren't.

   ⚠️ Still NOT .btn-primary. A prominent button beside an account name invites
   exactly the accidental click this whole emailed-link flow exists to survive. */
.acct-actions {
  margin-top: 14px;
  display: flex; align-items: center; justify-content: flex-end;
  gap: 12px; flex-wrap: wrap;
}
/* The site's SECONDARY identity is blurple — .btn-quiet's grey is the muted
   variant used for "Sign out", which should recede further than this does. */
.btn-reset {
  flex: none;
  font-size: 12px; padding: 5px 11px; border-radius: var(--radius-sm);
  color: var(--blurple-lit);
  border: 1px solid rgba(136, 148, 247, 0.30);
  background: rgba(136, 148, 247, 0.07);
}
@media (hover: hover) {
  .btn-reset:hover { color: #fff; background: var(--blurple); border-color: var(--blurple); }
}
/* A state note about the LAST reset request on this card. Sits to the LEFT of
   the button and takes the leftover width, so the two read as one row rather
   than a stacked block.
   Never a pill — a pill here would sit beside the account's own status pill and
   read as a second opinion about the ACCOUNT, which is the exact confusion to
   avoid: a queued or failed password change says nothing about whether the
   account works. */
.acct-note {
  flex: 1 1 12ch; min-width: 12ch;
  margin: 0; font-size: 12px; line-height: 1.45; color: var(--greyple);
}
/* Same red family as .pill-failed / .alert-error, so "didn't go through" reads
   as the same severity everywhere on the page. */
.acct-note-warn { color: #F0A0A0; }

/* ---------- Server status ---------- */
/* Chris: color alone must never be the only signal (WCAG colorblind
   accessibility) — every row carries the real word "Online"/"Offline" as
   text; the dot is decorative (aria-hidden in the markup) and purely
   reinforces it for a sighted reader who isn't colorblind. */
.status-grid {
  display: grid;
  /* auto-FIT, not auto-fill: with one server on the roster, auto-fill keeps the
     empty tracks and leaves a 240px card marooned in a full-width row. */
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
  margin-bottom: 44px;
}
.status-card { padding: 18px 20px; }
.status-server {
  margin: 0 0 4px; font-size: 12.5px; color: var(--greyple);
}
/* What the world is RUNNING — rates, release channel, version. A build stamp,
   so it takes the monospace treatment and sits quietly under the server name
   rather than competing with the online/offline rows below it. It wraps on a
   narrow card instead of overflowing: the three parts are independently
   readable, so a break between them costs nothing. */
.status-build {
  margin: 0 0 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11.5px; line-height: 1.5; color: var(--greyple);
  overflow-wrap: anywhere;
}
/* ⚠️ NO `opacity` HERE, and that is deliberate. Dimming this to .85 read nicely
   and measured 4.58:1 against the card — over WCAG AA's 4.5:1 for a hair, on
   11.5px text, which is not a margin. At full colour it is 5.84:1, the same as
   the server name above it. The smaller monospace size already makes it read as
   subordinate; the opacity was buying nothing the type scale had not. */
.status-row {
  display: flex; align-items: center; gap: 9px;
  padding: 5px 0; font-size: 14px;
}
.status-dot {
  flex: none; width: 8px; height: 8px; border-radius: 50%;
}
/* Same green as a character's own online dot (.char-row .online), so
   "online" reads consistently across the whole dashboard. */
.status-online { background: var(--verdance); box-shadow: 0 0 6px var(--verdance); }
/* Same red family as .alert-error/.pill-failed, so "offline" reads as the
   dashboard's one existing "something's wrong" color rather than a new one. */
.status-offline { background: #F0A0A0; box-shadow: 0 0 6px rgba(240, 122, 122, 0.55); }
.status-label { flex: none; color: var(--body); min-width: 46px; }
.status-word {
  font-family: var(--mono); font-size: 12.5px; font-weight: 600;
  letter-spacing: 0.02em; text-transform: uppercase;
}
.status-row:has(.status-online) .status-word { color: var(--verdance); }
.status-row:has(.status-offline) .status-word { color: #F0A0A0; }

/* ---------- How busy the world is (population + open trade shops) ----------
   A quieter tier BELOW the login/game dots, separated by the same hairline the
   characters list uses. The dots answer "can I get in"; these answer "is there
   anything happening when I do" — a different question, so it reads as its own
   band rather than as two more status rows.

   ⚠️ The rows here carry NO dot, deliberately. .status-dot is the up/down
   signal, and a coloured dot beside a population count would imply a threshold
   ("is 6,000 good?") that nothing here defines. */
.status-world {
  margin-top: 10px; padding-top: 10px;
  border-top: 1px solid var(--line-soft);
}
/* Wider than the 46px the Login/Game labels need — "Standing population" is a
   far longer label than "Login", and inheriting the narrow track would wrap it.
   Both rows share one track so their values line up as a column. */
.status-world .status-label { min-width: 132px; color: var(--greyple); }
.status-world .status-word { color: var(--body); }
/* The "/ 7,500" half: present for scale, never competing with the live number
   it qualifies. */
.status-of { color: var(--greyple-dim); font-weight: 400; }

/* ---------- Characters on an account ---------- */
.chars { border-top: 1px solid var(--line-soft); padding-top: 14px; }
.chars .chars-label {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--greyple-dim); margin-bottom: 10px;
}
.char-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 5px 0; font-size: 14px;
}
.char-row .cname { color: var(--body); }
.char-row .cmeta { font-family: var(--mono); font-size: 12px; color: var(--greyple); }
.char-row .online {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--verdance); box-shadow: 0 0 6px var(--verdance);
  margin-right: 7px; vertical-align: middle;
}
.chars .none { font-size: 13.5px; color: var(--greyple-dim); font-style: italic; }

/* ---------- Empty state ---------- */
.empty {
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  padding: 40px 28px; text-align: center;
  color: var(--greyple); margin-bottom: 44px;
}
.empty p { margin: 0 0 6px; }

/* ---------- The create form on the dashboard ---------- */
.create-card {
  background: linear-gradient(180deg, var(--surface) 0%, var(--field) 100%);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 28px;
  max-width: 560px;
  /* ⚠️ BACK TO FLUSH LEFT (Chris 2026-08-28, reversing the 2026-08-23 note
     above: on a real desktop viewport, a 560px card floating in the middle of
     a wide page read as "a mobile layout forced into desktop" — an island with
     nothing anchoring it, unlike "The launcher"/"Game accounts" above it,
     which both run the page's full left edge). Matching those instead. */
}
.create-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
@media (max-width: 620px) { .create-grid { grid-template-columns: 1fr; gap: 0; } }

/* Turnstile widget spacing — the widget itself is an iframe we don't style. */
.turnstile-slot { margin: 4px 0 20px; min-height: 65px; }

/* Test-mode banner: a deploy must never quietly ship an ungated form, so say so. */
.test-banner {
  font-family: var(--mono); font-size: 11.5px; letter-spacing: 0.04em;
  color: var(--lantern); background: rgba(240, 182, 122, 0.08);
  border: 1px solid rgba(240, 182, 122, 0.26);
  border-radius: var(--radius-sm); padding: 9px 13px; margin-bottom: 20px;
}

/* ============================================================================
   AUTH v2 — the shell for /login and /register
   ----------------------------------------------------------------------------
   ⚠️ REVISED 2026-08-23 (Chris, live): "the form need to be centered. I do not
   like the 'form on left, image on right'. The form should be centered, and
   the image we can perhaps enlarge and have it behind." The two-column split
   below is GONE on desktop — the render is now a full-bleed background layer
   behind a centered card, not a competing column. Everything about the render
   itself (the feathered mask, the alpha-derived edges, `contain` vs `cover`,
   the caption) is UNCHANGED reasoning, just re-anchored to the whole viewport
   instead of a half-width panel — see the comments inline below for what
   changed and why.

   ORIGINAL RULING, kept for history (superseded above, desktop half only):
   Chris 2026-07-27, from a phone screenshot of /register: "the account
   registration was built before we settled on a style for the site … on desktop
   it could be like a split design, kinda like the hero, where you have a login
   form on the right and on the left is like a render."

   THE DEFECT WAS ORDER, NOT DECORATION. Above the fold the old page stacked nav
   → kicker → serif headline → four-line paragraph → dev warning box, and only
   then the first input. Each piece was defensible; the stack was not.

   MOBILE  — card FIRST, prose after it. One field group visible on landing.
   DESKTOP — two columns from 900px: render left, form right.

   ⚠️ Every field, button and Turnstile style is REUSED from the block above.
   This section adds the shell only; if you find yourself restyling an input
   here, it belongs up there instead.
   ========================================================================== */

.auth2 { position: relative; }

/* ---------- The render panel ---------- */
/* Hidden on mobile: at 393px a decorative half-screen image is what pushes the
   form under the fold, which is the whole bug being fixed. It earns its space
   only once there IS space. */
.auth2-art { display: none; }

/* ⚠️ WIDTH *AND* HEIGHT (Chris 2026-07-27: "I don't think we support landscape
   mode on mobile for the login and register pages — it keeps it the same width,
   it doesn't expand. It's not broken, it's just not optimized").
   MEASURED, and it was two problems wearing one coat:
     · iPhone landscape 852x393 — art stayed hidden (the old test was
       min-width:900px), so a 460px column sat on an 852px screen. That is the
       "doesn't expand".
     · Pixel landscape 915x412 — the split DID engage, and the submit button was
       still below the fold, because 412px of height cannot hold a hero image and
       a form.
   A phone in landscape is WIDE AND VERY SHORT, so a width-only query cannot tell
   it apart from a laptop. The split now requires 760px of width and 520px of
   height; below either, the compact single column wins, which is the right
   layout for a short viewport regardless of how wide it is. */
@media (min-width: 760px) and (min-height: 520px) {
  .auth2 {
    /* ⚠️ NO LONGER A GRID (2026-08-23) — the two-column split above is retired.
       The art is now a full-bleed layer BEHIND the panel (see .auth2-art below,
       now position:absolute over the whole section) and the panel is centered
       over it, so this box only needs to establish the stacking context and
       give the centered content somewhere tall enough to sit in. */
    position: relative;
    max-width: var(--wrap); margin-inline: auto; padding-inline: 26px;
    /* ⚠️ min-height, NOT height: the register form is taller than a 900px laptop
       viewport once Turnstile renders, so a hard height would clip it. */
    min-height: calc(100dvh - var(--nav-h, 72px));
    display: flex; align-items: center; justify-content: center;
  }
  .auth2-art {
    display: block;
    /* ⚠️ FULL-BLEED, BEHIND THE FORM (Chris 2026-08-23, live: "the form should
       be centered, and the image we can perhaps enlarge and have it behind").
       Was a side column at order:2; is now an absolutely-positioned backdrop
       spanning the whole section, ignoring the page gutter above (inset:0 on
       the SECTION, not the max-width wrap) so the render reaches the viewport
       edges the way a hero background does. */
    position: absolute; inset: 0; z-index: 0; overflow: hidden;
  }
  /* The caption now names the backdrop rather than a side panel — same corner,
     same mono register, just anchored to the whole section instead of a column. */
  .auth2-art-cap {
    position: absolute; left: 26px; bottom: 22px; z-index: 1; margin: 0;
    font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em;
    text-transform: uppercase; color: var(--greyple); line-height: 1;
  }
  .auth2-art-img {
    position: absolute; inset: 0;
    /* ⚠️ OUR OWN GENERATED GEODATA RENDER — the same art the homepage hero uses,
       so these pages share a visual root with the site rather than just a
       palette. Decorative: the element is aria-hidden in the component. */
    /* ⚠️ `contain`, NOT `cover` (Chris 2026-07-27: "well this can't be right").
       `cover` on this near-square panel (1070x1007) scaled the 1478x1521 render
       up to fill and cropped the rest, so the visitor saw a small centre slice at
       high magnification — abstract squiggles rather than a map of anywhere.
       `contain` shows the whole render; the panel's own dark ground fills what is
       left, which is the same treatment the homepage plates use. */
    /* ⚠️ TALKING ISLAND, WHOLE, TO THE WATER (Chris 2026-07-28: "the render image
       for login and register — let's do Talking Island, the whole island, zoomed
       out to the water edges"). It is where a new character starts, which is the
       right subject for the page where an account is made.
       Rendered at r=26000 with NO --zones (he asked for the polygons gone, and
       they were what made it read as a blob) and upscaled to 3252px so the
       village walls, harbour piers and buildings stay crisp linework rather than
       mush. 98KB. `contain` shows the whole island — never `cover`, which crops
       the coastline off and is the bug this panel already had once. */
    /* ⚠️ THE PNG CARRIES ITS OWN ALPHA — the void is TRANSPARENT, not painted
       (Chris 2026-07-28: "I still see hard edges, and I think something is just
       causing it to be in general brighter when really it should be blending
       with the background colors").
       Both halves of that were one cause. The render shipped as opaque RGB, so
       the lightened void (20,17,30) filled all 3252x3252 as a SOLID RECTANGLE
       over the page ground — that rectangle was the brightness, and its edge was
       the hard line. The CSS mask could not save it: `contain` letterboxes the
       square render inside a taller panel, so the image's own opaque edge landed
       INSIDE the mask's fade and stayed visible.
       Fixed at the source instead of dimming it further: alpha is now derived
       from each pixel's distance from the void colour, so only inked geometry
       paints and the page ground IS the ocean. The mask below now feathers the
       island itself, which is what it was always meant to do. */
    background: url('/assets/generated/auth-talking-island.png') center / contain no-repeat;
    /* Higher than the old .5 because there is no longer a bright plate to hold
       down — this now sets the ISLAND's weight against the page, nothing else. */
    opacity: .62;
    /* ⚠️ FEATHER ALL FOUR EDGES (Chris 2026-07-28: "need blended into background
       — transparent edges I think, like hero"). Without it the render's own
       rectangular frame cuts a hard line against the page, which is the same
       thing he called out on the homepage on 2026-07-21: "just looks like a hard
       image and not fitting well."
       Identical treatment to .launch-art in index.astro:1097 — two gradients
       intersected so the CORNERS feather too, rather than one gradient that
       leaves two hard sides. The page ground shows through the fade and the art
       dissolves into it. */
    -webkit-mask-image:
      linear-gradient(90deg,  transparent 0, #000 14%, #000 84%, transparent 100%),
      linear-gradient(180deg, transparent 0, #000 12%, #000 88%, transparent 100%);
    mask-image:
      linear-gradient(90deg,  transparent 0, #000 14%, #000 84%, transparent 100%),
      linear-gradient(180deg, transparent 0, #000 12%, #000 88%, transparent 100%);
    -webkit-mask-composite: source-in;
    mask-composite: intersect;
  }
  /* ⚠️ VIGNETTE, NOT A SIDE FADE (2026-08-23). The old veil darkened one inner
     edge to blend two side-by-side boxes into one surface; there is no more
     "inner edge" once the render is a centered backdrop. Its job now is the
     opposite direction: stay light at the CORNERS (where the render should
     read) and go dark toward the CENTER (where the heading/blurb sit directly
     on the page ground, outside the card). The card itself doesn't need this —
     it carries its own solid gradient — but the eyebrow/heading/blurb above and
     below it do. */
  .auth2-art-veil {
    position: absolute; inset: 0;
    /* Same edge feather as the image below, so the vignette's own rectangle
       doesn't reintroduce the hard frame the mask exists to remove. */
    -webkit-mask-image:
      linear-gradient(90deg,  transparent 0, #000 14%, #000 84%, transparent 100%),
      linear-gradient(180deg, transparent 0, #000 12%, #000 88%, transparent 100%);
    mask-image:
      linear-gradient(90deg,  transparent 0, #000 14%, #000 84%, transparent 100%),
      linear-gradient(180deg, transparent 0, #000 12%, #000 88%, transparent 100%);
    -webkit-mask-composite: source-in;
    mask-composite: intersect;
    background: radial-gradient(
      ellipse 60% 55% at center,
      rgba(11,10,24,.88) 0%, rgba(11,10,24,.62) 45%, rgba(11,10,24,0) 100%
    );
  }
}

/* ---------- The form column ---------- */
.auth2-panel { display: flex; align-items: center; justify-content: center; }
.auth2-inner {
  display: flex; flex-direction: column;
  width: 100%; max-width: 440px;
  padding: clamp(28px, 5vw, 56px) 26px clamp(48px, 6vw, 72px);
}
/* ⚠️ CENTERED, ABOVE THE BACKDROP (2026-08-23). Was a left-aligned column that
   deliberately ate the grid's own gutter (padding-left:0) to sit flush with the
   art beside it. There's no gutter to share now — the panel just needs to sit
   above .auth2-art in the stacking order and stay centered like it already is
   on mobile. */
@media (min-width: 760px) and (min-height: 520px) {
  .auth2-panel { position: relative; z-index: 1; width: 100%; }
  .auth2-inner { max-width: 460px; }
}

/* ⚠️ ORDER IS THE FIX. The card is order:1 so the form is the first thing under
   the heading on a phone; the explanatory prose follows it. Both live in the
   same column on desktop, where the order is visually moot. */
/* ⚠️ HEADLINE ABOVE THE EYEBROW (Chris 2026-07-27: "Join the dream should be
   FIRST and create your master account up under it — the headline should be on
   top"). Flex order does the swap so the DOM keeps its reading order: the <h1>
   stays the first heading a screen reader meets either way, and the eyebrow
   remains associated prose rather than becoming a pseudo-heading. */
.auth2-h       { order: 0; }
.auth2-eyebrow { order: 1; }   /* margin lives in the styling block below */
.auth2-card    { order: 2; }
.auth2-blurb   { order: 3; }
.auth2-alt     { order: 4; }

.auth2-eyebrow {
  font-family: var(--mono); font-size: 11px; letter-spacing: .26em;
  text-transform: uppercase; color: var(--blurple-lit);
  /* ⚠️ TOP MARGIN IS LOAD-BEARING (Chris 2026-07-27: "there needs to be a little
     bit more space between the header and the 'welcome back' and the 'sign in to
     your master account' — they're too close to each other"). Measured flush at
     0px before this: the order:1 rule above USED to carry `margin: 10px 0 22px`
     and this block silently overrode it — equal specificity, later wins. The
     margin now lives in exactly one place. */
  margin: 14px 0 22px;
}
/* ⚠️ ONE ACCENTED WORD — "master" (Chris 2026-07-27: "maybe emphasizing master
   in a different colour or label"). It is the word that separates this account
   from a game account, which the password hint below already leans on.
   The treatment is the SITE'S OWN, not a new idea: the wordmark accents "L2" in
   lantern against blurple, so a lantern word inside a blurple line already
   reads as Everdream. Not italic — the <em> is a semantic hook, and italics in
   a letter-spaced mono line at 11px just look broken. */
.auth2-eyebrow em { font-style: normal; color: var(--lantern); }
.auth2-h {
  font-family: var(--serif); font-weight: 600;
  font-size: clamp(30px, 4.4vw, 42px); line-height: 1.08;
  margin: 0; color: var(--starlight); text-wrap: balance;
}

/* The card idiom from /features — same gradient ground, same hairline, same
   radius — so an account page reads as one of the site's cards. */
.auth2-card {
  position: relative;
  background: linear-gradient(168deg, #141230, #100E22);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: clamp(20px, 3vw, 28px);
}
.auth2-card::before {
  content: ""; position: absolute; inset: 0 0 auto; height: 2px;
  border-radius: 16px 16px 0 0;
  background: var(--blurple-lit); opacity: .5;
}
/* The last field's margin would otherwise double the card's bottom padding. */
.auth2-card .field:last-of-type { margin-bottom: 16px; }
.auth2-card .btn-primary { width: 100%; }

.auth2-blurb {
  margin: 20px 0 0; color: var(--greyple);
  font-size: 14px; line-height: 1.6;
}
.auth2-alt {
  margin: 14px 0 0; color: var(--greyple);
  font-size: 14px;
}
.auth2-alt a { color: var(--blurple-lit); }

/* The compact column — everything that is not a tall-enough desktop. */
@media (max-width: 759px), (max-height: 519px) {
  /* Centre the head on mobile to match the rest of the site's narrow pages,
     but keep the card left-to-right full width. */
  .auth2-eyebrow, .auth2-h { text-align: center; }
  .auth2-inner { max-width: 460px; margin: 0 auto; }
}

/* ---------------------------------------------------------------------------
   AUTH v2 — FIELD VISIBILITY + WCAG NON-TEXT CONTRAST
   ---------------------------------------------------------------------------
   Chris 2026-07-27: "the login form is too hard to see … I wanna make sure it's
   ADA compliant, I wanna make sure you SEE THE TEXT FIELDS and they don't blend
   in."

   ⚠️ HE WAS RIGHT AND THE a11y GATE HAD SAID PASS. Measured on /login before
   this block:
     · input background vs card ............ 1.00:1  (IDENTICAL — invisible)
     · border, alpha COMPOSITED ............ 1.22:1  (WCAG 1.4.11 needs 3.0)
     · focus border vs unfocused ........... 1.22:1  (no visible focus at all)
   The border READ as 7.12:1 if you measure the declared rgba(136,148,247,.14)
   without compositing the alpha over its backdrop. That number is a lie — the
   real edge is rgb(33,33,64). Always composite before judging an alpha border.

   ⚠️ WHY axe PASSED ANYWAY: axe-core does not check 1.4.11 non-text contrast by
   default, and it cannot see "focused looks like unfocused" at all. A green a11y
   gate is not evidence a form is usable. The gate now carries an explicit
   contrast assertion (tools/contrast.mjs) so this cannot regress silently.

   THE FIX IS SEPARATION, NOT BRIGHTNESS — the page's calm is the thing Chris
   likes. The field sits DARKER than the card it is on (a well, not a glow), and
   the border is a solid colour rather than a 14%-alpha whisper.
   ------------------------------------------------------------------------- */

.auth2-card .field input,
.auth2-card .field select {
  /* Darker than the card's #141230→#100E22 gradient, so the field reads as a
     recess even before you notice its border. */
  background: #08070F;
  /* ⚠️ #64687D IS COMPUTED, NOT CHOSEN. My first pick (#3A3A63) looked right and
     measured 1.88:1 — still a fail. Rather than guess a third time I swept a
     blurple-leaning ramp for the first value clearing 3.0:1 against BOTH the
     field well and the card gradient. This one is 3.64 / 3.37. Do not "tone it
     down" without re-running that measurement. */
  border: 1px solid #64687D;
}

.auth2-card .field input::placeholder {
  /* Was #757575 — a UA default that is neither ours nor readable. This is the
     site's own greyple, and it clears 4.5:1 on the darker field. */
  color: var(--greyple);
  opacity: 1;                      /* Firefox dims placeholders by default. */
}

/* ⚠️ FOCUS MUST BE OBVIOUS, not merely present. outline:none is kept because the
   ring is drawn with box-shadow (it follows border-radius, which an outline does
   not), but the BORDER now changes to a bright blurple as well — so focus is
   legible even where box-shadow is suppressed, and in forced-colors mode the
   outline below takes over. */
/* ⚠️ .auth2-card twice, deliberately. The generic `.field input:focus` rule
   lives LATER in this file at equal specificity, so it was winning the cascade
   and focus rendered with no ring at all (measured: box-shadow "none", focus
   border identical to unfocused). Specificity, not source order, is what makes
   this survive future edits above it. */
.auth2-card.auth2-card .field input:focus,
.auth2-card.auth2-card .field select:focus {
  border-color: var(--light-blurple);
  box-shadow: 0 0 0 3px rgba(139, 148, 247, 0.45);
}

/* Windows High Contrast / forced-colors: our colours are discarded, so restore a
   real outline rather than relying on a box-shadow the OS will drop. */
@media (forced-colors: active) {
  .auth2-card .field input:focus,
  .auth2-card .field select:focus { outline: 3px solid Highlight; outline-offset: 1px; }
}

/* ---------------------------------------------------------------------------
   SHORT VIEWPORTS — a phone in landscape (852x393, 915x412) has plenty of width
   and almost no height. Measured before this block: the submit button sat at
   590-742px on a 393-412px tall screen, i.e. the whole form was below the fold
   and you had to scroll a login page to find its button.
   The fix is to spend less vertical space, not less width: trim the outer
   padding, shrink the display heading (it is decorative here — the eyebrow
   carries the meaning), and tighten the field rhythm. Nothing is hidden.
   ------------------------------------------------------------------------- */
@media (max-height: 519px) {
  .auth2-inner { padding-top: 16px; padding-bottom: 24px; max-width: 520px; }
  .auth2-h { font-size: clamp(22px, 3.4vw, 27px); }
  .auth2-eyebrow { margin: 8px 0 12px; }
  .auth2-card { padding: 16px 18px; }
  .auth2-card .field { margin-bottom: 12px; }
  .auth2-card .field label { margin-bottom: 4px; }
  .auth2-card .field input { padding: 9px 12px; }
  .auth2-card .field .hint { margin-top: 4px; }
  .auth2-blurb { margin-top: 12px; }
  /* The Turnstile widget has a fixed 65px slot that is pure air on a short
     screen until it renders. */
  .turnstile-slot { min-height: 0; margin: 0 0 12px; }
}

/* ⚠️ SHORT **AND WIDE** — use the width, since the height is not there.
   Trimming alone was not enough: /register carries three fields plus a Turnstile
   widget, and at 393px of height a single column cannot fit them however tight
   the rhythm (measured: submit still at 531px). A landscape phone has 850-915px
   of width doing nothing, so the fields become two columns and the form halves
   its height. The submit and the Turnstile span both columns — a submit button is
   the page's one real action and should not be half-width.
   ⚠️ Only from 700px wide: below that the screen is short AND narrow (a small
   phone in landscape), where two columns would be unreadable. */
@media (max-height: 519px) and (min-width: 700px) {
  .auth2-card form {
    display: grid; grid-template-columns: 1fr 1fr; column-gap: 16px;
    align-items: start;
  }
  .auth2-card form > .field { margin-bottom: 10px; }
  /* Anything that is not a field spans the row: the Turnstile slot and the
     submit button. */
  .auth2-card form > .turnstile-slot,
  .auth2-card form > .btn-primary { grid-column: 1 / -1; }
  .auth2-inner { max-width: 640px; }
}

/* =============================================================================
   /account-access — the tabbed sign-in/sign-up page, with the download beside it
   -----------------------------------------------------------------------------
   Chris 2026-07-28, from Reborn: "their sign in form with tabs for register vs
   login, same page. And download button for the actual exe on the right side."

   ⚠️ THIS PAGE SHIPPED WITH NO STYLES AT ALL. The .astro was written and the
   build passed — Astro does not care that `.aa-tabs` matches nothing — so the
   page rendered as raw HTML: stacked labels, full-bleed inputs, an ordered list
   showing "1. 1" because the <ol> marker and the <span class="aa-n"> both drew.
   A passing build is not a rendered page, and only opening it in a browser
   found this.
   ============================================================================= */
.aa {
  max-width: var(--wrap); margin-inline: auto;
  padding: 40px 26px 72px;
  display: grid; gap: 34px;
}
/* Sized down from the /register hero treatment: there the headline IS the page,
   here it sits above a tab strip and has to leave room for it. */
.aa-h { font-size: clamp(26px, 3.4vw, 34px); margin: 0 0 20px; }
/* ---------- tabs ---------- */
.aa-tabs { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 18px; }
.aa-tab {
  display: block; text-align: left; cursor: pointer;
  padding: 13px 16px; border-radius: var(--radius);
  background: rgba(136, 148, 247, 0.05);
  border: 1px solid var(--line);
  color: var(--greyple); font: inherit;
  transition: background .16s ease, border-color .16s ease, color .16s ease;
}
/* ⚠️ aria-selected IS the styling hook, not a parallel .is-active class — the
   state a screen reader is told and the state an eye sees cannot drift apart. */
.aa-tab[aria-selected="true"] {
  background: rgba(136, 148, 247, 0.11);
  border-color: rgba(136, 148, 247, 0.38);
  color: #fff;
}
@media (hover: hover) {
  .aa-tab:hover { border-color: rgba(136, 148, 247, 0.30); color: #fff; }
}
.aa-tab:focus-visible { outline: 2px solid var(--blurple); outline-offset: 2px; }
.aa-tab-t { display: block; font-weight: 650; font-size: 15px; }
.aa-tab-d { display: block; font-size: 12.5px; margin-top: 2px; color: var(--greyple); }
.aa-tab[aria-selected="true"] .aa-tab-d { color: var(--greyple); }

.aa-card { border: 1px solid var(--line); border-radius: var(--radius); padding: 22px; }
.aa-panel[hidden] { display: none; }

/* ---------- the steps + download ---------- */
.aa-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 22px; }
.aa-steps li { display: grid; grid-template-columns: 34px 1fr; gap: 14px; align-items: start; }
/* ⚠️ The number is a <span>, so the <ol> marker must be suppressed or the page
   reads "1. 1" — which is exactly what shipped. */
.aa-n {
  display: grid; place-items: center;
  width: 34px; height: 34px; border-radius: 9px;
  background: rgba(136, 148, 247, 0.10); border: 1px solid var(--line);
  font-family: var(--mono); font-size: 13px; color: var(--greyple);
}
.aa-steps h3 { font-size: 16px; margin: 6px 0 4px; line-height: 1.25; }
.aa-steps p { font-size: 14px; color: var(--greyple); margin: 0; line-height: 1.55; }

.aa-dl {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  margin-top: 28px; padding: 13px 22px; border-radius: var(--radius);
  background: linear-gradient(180deg, #F7C97E, #EBB463);
  color: #241a07; font-weight: 700; text-decoration: none;
  min-height: 44px;   /* WCAG 2.5.5 */
}
.aa-dl svg { width: 15px; height: 15px; flex: none; }
/* ⚠️ THE PRE-RELEASE STATE, matching .btn-disabled on /account — dashed, muted,
   not-allowed. It must not look like the amber action above; a control that
   cannot be used has to say so at a glance. */
.aa-dl-off {
  background: rgba(136, 148, 247, 0.06);
  border: 1px dashed rgba(136, 148, 247, 0.3);
  color: var(--greyple); font-weight: 500; cursor: not-allowed;
}
@media (hover: hover) {
  /* :not(.aa-dl-off) — a disabled control must not brighten under the cursor. */
  .aa-dl:not(.aa-dl-off):hover { background: linear-gradient(180deg, #FFD79A, #F6C67A); }
}
.aa-dl:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
.aa-note { font-size: 13px; color: var(--greyple); margin: 14px 0 0; line-height: 1.55; }

/* ---------- two columns, same breakpoint as the auth split ---------- */
@media (min-width: 860px) {
  .aa {
    grid-template-columns: minmax(420px, 1fr) minmax(320px, 420px);
    gap: 64px; align-items: start;
    padding-top: 56px;
  }
  .aa-side { padding-top: 6px; }
}
