/* auth/shell.css - Nocturne preview.
   Split out of the former single 67 KB styles.css by MEASURED
   CONSUMPTION: every rule here is consumed only by pages whose shell
   loads this sheet. Load order is common -> family -> page, mirroring
   the application shells. */

.field .err { font-size: var(--t-xs); color: var(--danger); }

/* ---- THE AUTH SHELL'S OWN GEOMETRY ---------------------------------------
   `auth/base.html` renders `div.auth > [aside.auth-aside] > main.auth-main >
   div.auth-card` for EIGHT pages, and until now this sheet defined NONE of those
   three boxes. Five pages survived only because each carried a per-view sheet that
   re-declared the whole layout; the three that did not - `password-setup`,
   `reset-password-change`, `reset-password-verify` - rendered edge-to-edge with no
   gutter and no measure at all (MEASURED: .auth-card w=1280 x=0 at 1280px, w=360
   x=0 at 360px, text touching both viewport edges). NOTHING OVERFLOWED, so every
   probe reported those three pages clean.

   WHY IT WAS MISSING, and the shape of the repair. This sheet once held FIVE
   conflicting `.auth-card` rules (420 / 860 / 384 / 400 / 440px) in one file, so
   last-one-wins rendered EVERY auth page at 440px - recorded defect P1. The repair
   deleted all five, and deleted the shared layout with them. The fix is not to put
   them back: it is the split CONVENTION.md §4 already records as the deviation on
   record for `css/auth/` -

     THE FAMILY SHEET (here) owns the LAYOUT, once.
     A PER-VIEW SHEET owns only that view's own MEASURE, and only where it DIFFERS.

   Per-view sheets load after this one, so a view that states its own measure wins
   cleanly with no specificity trick and no second copy of the layout.

   THE DEFAULT COLUMN IS SINGLE, not the two-up split: the aside is optional markup
   (`{% block auth_aside %}`), and a page without it must not inherit a phantom empty
   track. The split is OPT-IN, through `auth--split` on the stage - see the next block.

   THE DEFAULT MEASURE IS 400px because that is the recorded canonical exemplar of
   this pattern, not a new number: ORCH-B-PREVIEW-RULES.md §2A names
   `forgot-password.html` the canonical auth-card page and prints
   `.auth-card { width: min(400px, 100%) }` as the pattern's CSS. `min()` keeps the
   card inside the `--edge` gutter below 400px rather than forcing a scrollbar.

   THE STAGE FILLS THE SPACE THAT IS ACTUALLY AVAILABLE, AND THAT IS NOT THE VIEWPORT.
   `min-height: 100vh` stood on `.auth` here, carried across from the preview, where
   `auth/base.html` IS the whole document and the stage is a direct child of the body with
   no chrome above or below it. This app nests the same stage inside `public_base.html`,
   BETWEEN a header and the site footer, so a viewport-height stage is added ON TOP of
   both. MEASURED at 1440x1200 on every view that extends this shell: `.auth` rendered at
   exactly 1200 with the header 59 above it and the footer 373.52 below, for a document
   1633 tall against the preview's 1200 - 433px of dead space, at every width and
   independent of content (2134 at 360, where the footer stacks to 875). Nothing
   overflowed and nothing threw: the page was simply taller than the screen for no reason,
   and the card it centres sat correspondingly high in the fold.

   THE CHROME'S HEIGHTS ARE NOT SUBTRACTED, AND MUST NOT BE. `calc(100vh - header -
   footer)` needs two numbers and neither is honestly available: `--pub-head-h` exists but
   the bar's real height is that token PLUS its bottom border, and the footer has no token
   at all and is not ONE height - it measures 373.52 at 1440 and 875 at 360 because its
   columns stack. Any subtraction is a literal that goes stale the first time the footer
   reflows. So the shell states the RELATIONSHIP instead: the body is a column, the
   content row takes the slack, and the stage inherits whatever that turns out to be.

   SCOPED BY A BODY CLASS, NOT APPLIED TO `body.public-shell`. Every other page of that
   shell is already taller than the viewport, so the column would change nothing for them
   - and on a short one it would silently start pinning the footer to the bottom, which is
   a change to pages this repair was not asked to touch. `auth-shell` is emitted by
   `auth/base.html` alone and is read only here. */
.auth { display: grid; grid-template-columns: minmax(0, 1fr); }
body.auth-shell { min-height: 100vh; display: flex; flex-direction: column; }
/* The content row takes the slack; `display: grid` on that row is what makes the stage
   its ITEM, so `.auth` stretches to the row instead of shrink-wrapping around its card.
   The header, the flash region and the footer stay auto-sized siblings of that row. */
body.auth-shell > main { flex: 1 1 auto; display: grid; }
.auth-main { display: grid; place-items: center; padding: var(--sp-2xl) var(--edge); }
.auth-card { width: min(400px, 100%); }

/* ---- THE OPT-IN SPLIT, AND IT IS TWO PAGES, NOT SIX ------------------------
   `auth/base.html` documents `auth--split` as the handle a view adds when it fills
   `auth_aside`, so the stage gains its second track. TWO templates emit it -
   login.html and register.html - and that is the whole list BY THE PREVIEW'S OWN RULE:
   bundle/css/auth/shell.css:33 states the aside is "filled by `login` and `register`
   ONLY", and bundle/css/auth/login.css:5 / register.css:6 scope the two-up split to those
   two pages precisely because they are the ones with a second track to give.

   FOUR MORE TEMPLATES USED TO EMIT IT - unsubscribe, forgot_password, password_setup and
   reset_password_change - and all four were app inventions with no counterpart anywhere in
   the preview: every one of those four bundle pages is a single column. Their asides are
   removed and their copy re-sited into the column (the preview's own head takes the
   heading, lead and chips; the rest becomes `stack` blocks below the form), with every
   translatable string preserved and every per-file extraction total unchanged. The stage
   handle now has exactly the emitters the preview has.

   THE VALUES ARE THE PREVIEW'S OWN, not new ones - bundle/css/auth/login.css:9,13 and
   bundle/css/auth/register.css:8,15 are byte-identical to each other, which is exactly
   the "repeated byte-identically across pages of this shell" test this sheet already
   uses to decide what it owns. It is declared ONCE, here, keyed on the handle the two
   templates emit, and the two page sheets carry no copy of it.

   BELOW THE SPLIT'S USABLE WIDTH THE ASIDE IS DROPPED and the stage returns to the family
   default - the preview's own answer, and already the shipped behaviour of login and
   register. Stacking it instead would put the pitch above the task on a phone, which is
   the arrangement auth/login.html:15-19 records as RETIRED for exactly that reason. MUST
   stay after the base rule: same specificity, later wins. */
.auth--split { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
@media (max-width: 820px) {
  .auth--split { grid-template-columns: minmax(0, 1fr); }
  .auth--split .auth-aside { display: none; }
}

/* --- promoted from page-local <style> blocks: rules that repeated
       byte-identically across pages of this shell --- */
.auth-aside { border-right: 1px solid var(--base-700); padding: var(--sp-3xl) var(--sp-2xl);
    display: flex; flex-direction: column; justify-content: space-between; position: relative; overflow: clip; }
.auth-aside .node-bg { position:absolute; inset:auto -8% -12% -4%; width:520px; max-width:88%; opacity:.6; pointer-events:none;
    -webkit-mask-image: radial-gradient(60% 60% at 30% 70%, #000, transparent 78%); mask-image: radial-gradient(60% 60% at 30% 70%, #000, transparent 78%); }
.auth-aside > * { position: relative; z-index: 1; }
.vp { display:flex; gap: var(--space-4); }
.vp .i { width:19px;height:19px;color:var(--accent-400);flex:0 0 auto;margin-top:2px }

/* ---- THE ASIDE'S TWO INLINE-STYLED PARTS, CARRIED ACROSS AS RULES ----------
   The preview writes both as a `style=""` attribute on a SHARED primitive
   (bundle/templates/auth/login.html:16-17, bundle/templates/auth/register.html:18-19,
   bundle/templates/partials/_auth_aside.html:11-12 - three copies, identical values).
   This app ships `style-src 'self'` with no `unsafe-inline`, so each has to be NAMED.

   THEY ARE CO-CLASSES ON THE SAME ELEMENT, NOT A WIDENING OF THE PRIMITIVE. The preview
   applies both PER INSTANCE; moving them onto `.accent-mark` or `.stack-sm` themselves
   would repoint every other use of those two across the whole product. The convention is
   the one css/billing/index.css:56 and app/templates/dashboard/index.html:122 already
   set: a named class beside the shared one, citing the bundle element it carries.

   NEITHER RENDERED AS A *WRONG* VALUE - both rendered as NOTHING. The headline ran the
   full width of the aside column (~half the viewport at desktop) instead of its 16ch
   measure, and the value-prop group sat at `.stack`'s ordinary `--space-5` instead of the
   larger step the preview gives it. No overflow, no clip, no error. */
/* bundle/templates/auth/login.html:16 - `style="max-width:16ch"` on `h2.h2.accent-mark`. */
.auth-aside__title { max-width: 16ch; }
/* bundle/templates/auth/login.html:17 - `style="margin-top:var(--space-6)"` on the
   `.stack-sm` holding the `.vp` list. Beats `.stack > * + *` (css/shared/common.css:185)
   on load order at equal specificity: common -> family, and this is the family sheet. */
.auth-aside__points { margin-top: var(--space-6); }

/* ---- THE ACTIONS THAT CLOSE A BLOCK OF BODY COPY --------------------------
   bundle/templates/vps/unsubscribe.html:32 - `<div class="cluster"
   style="margin-top:var(--space-6)">`, the Sign in / Return home pair closing a card
   whose body is a heading plus one paragraph.

   THE APP SPELLS THAT BLOCK AS `.stack-sm`, whose `--space-3` is a WORD gap, not a gap
   between prose and the button that acts on it: the buttons sat 8.4px under the sentence
   on auth/forgot_password.html and auth/password_setup.html, which compose this exact
   idiom (`h2.h3` + `p.small.muted` + a `.cluster` of buttons, all inside one `.stack-sm`).
   ONE RULE, because they are one idiom.

   auth/unsubscribe.html WAS THE THIRD EMITTER AND IS NO LONGER ONE. That view now renders
   the preview's own single-column public page instead of an auth card, so it does not load
   this sheet; the same rung on its card is owned by css/auth/unsubscribe.css. The value is
   identical because it is the same value in the same preview, but the two are different
   surfaces on different shells and neither can reach the other.

   NOT APPLIED to a `.cluster` that is already a direct child of `.auth-card.stack-lg`
   (auth/reset_password_verify.html:22): `.stack-lg` gives it `--sp-xl` already, and a
   smaller value there would be a REDUCTION the bundle never asks for. */
.auth-actions-row { margin-top: var(--space-6); }

/* ---- THE AUTH FORM AND ITS HELP ROW ---------------------------------------
   Ported from the preview by TREATMENT, under the names the templates already emit.

   THE BUNDLE'S AUTH FORM IS `<form class="stack">` and nothing else - a plain vertical
   rhythm (bundle/reset-password-change.html:81, bundle/login.html:98,
   bundle/mfa-enroll.html:70). THE APPLICATION CANNOT SPELL IT THAT WAY. `.auth-form` is a
   FE<->BE-grade carrier, not a presentational name: app/static/js/public/shell.js:12 reads
   the element as `querySelector('.auth-form')` to focus the first invalid control, and
   scripts/form-dimension-baseline.json records it as `form_class` on twelve routes. So the
   handle stays on the element and THIS SHEET gives it the rhythm the bundle gives via
   `.stack` - the same value from the same token, not a second, divergent one.

   WHY THE FAMILY SHEET AND NOT `public/shell.css`, WHERE THE RULE HISTORICALLY LIVED.
   Every one of the eight emitters is an `app/templates/auth/` template, and seven of them
   extend `auth/base.html`, which loads THIS sheet in the same call as public/shell.css
   (auth/base.html:29) - so the family sheet reaches every emitter the public shell reaches,
   and the class is named for the family that owns it. The eighth, `auth/mfa_enroll.html`,
   extends `base.html` and loads neither; it already carries `.stack` beside the handle for
   exactly that reason, and its own comment records the decision.

   IDENTICAL TO `.stack` ON PURPOSE - `> * + *`, one token, no second rhythm. A form that
   ever wears both classes therefore cannot render two different gaps.
   NOTE the hidden-input behaviour is `.stack`'s too and is inherited deliberately: a
   `hidden_tag()` input is `display:none` by UA stylesheet, so it paints no gap of its own
   while the first visible field still takes a top margin. Diverging here to "fix" that
   would put a second, subtly different rhythm on the same idiom. */
.auth-form > * + * { margin-top: var(--space-5); }

/* THE HELP ROW - the secondary way out of the page, under the form.
   The bundle spells it `class="between small"` (bundle/reset-password-change.html:98,
   the "Back to sign in" row) and, on login, the same idiom inline beside the password
   label. The application keeps its own two names because THE ROW IS NOT INLINE-STYLED
   HERE: the bundle carries its gap in a `style=""` attribute, which the app's CSP
   (`style-src 'self'`) bars outright, so the gap has to live in a sheet. `space-between`
   is carried over from `.between` rather than dropped: every current emitter has one
   child, where it resolves to flex-start, and the bundle's own row has two. */
.auth-help-link-row { display: flex; align-items: center; justify-content: space-between;
    gap: var(--space-5); }
/* The link takes the row's TYPE only. Colour, hover and focus ring come from the global
   `a` / `a:hover` / `a:focus-visible` owners in css/shared/common.css - a link's identity
   is colour and underline, and restating it here would be a second owner of both. */
.auth-help-link { font-size: var(--t-sm); }

/* `.unsub-status` MOVED OUT OF THIS SHEET, to css/auth/unsubscribe.css. It was the status
   chips' own rung and auth/unsubscribe.html was its only emitter; that view now renders
   the preview's single-column public page (`.shell.section` + `.page-head` + a two-card
   grid) rather than this stage, so it no longer loads this sheet and the rule would have
   been styling nothing here. Moved, not copied - one owner, one home. */
