/* ══ THE ACCOUNT PAGES ══════════════════════════════════════════════════════════════════════════════════
   Sign in, MFA, password reset, reset confirm, sign out, SSO error. These render OUTSIDE the Blazor shell
   (Pages/Shared/_AuthLayout.cshtml), so none of the app's component CSS reaches them — which is why they
   had grown five private copies of the same card, field, button and banner.

   WHY THIS FILE EXISTS. Each page used to carry its own <style> block declaring its own `--navy`/`--accent`
   and its own `.btn`, `.field`, `.error`. Five copies of one design drift, and they had: the button radius
   was a hard-coded `9px` on sign-out against a token everywhere else, and the same error banner was
   `.error` on three pages and `.msg.err` on a fourth. This is CLAUDE.md U2 ("never redeclare a shared
   class") applied to the one family that escaped it.

   THE BUG THAT MADE IT URGENT. _AuthLayout linked app.css and nothing else, so `cobblestone-theme.css`
   never reached these pages — every `var(--ci-radius)`, `var(--ci-ring)` and `var(--ci-transition)` in
   them was an UNDEFINED custom property. An undefined var makes the whole declaration invalid at
   computed-value time, so the property silently fell back to its initial value: every card, button and
   input on the app's front door rendered with SQUARE corners, no transitions, and — the real defect — no
   focus ring at all, while the one button with a literal radius (sign-out's `9px`) looked correct and hid
   the pattern. The layout now links the theme, so the tokens below resolve.

   RULES FOR EDITING THIS FILE
   · TOKENS ONLY, never a colour literal (U12). That is also what gets these pages dark mode: the theme's
     `:root[data-theme="dark"]` block redefines the tokens and everything here follows, with no second
     copy of anything to drift. The ONE deliberate exception is the brand panel's navy gradient and the
     white ink on it — see .auth-brand.
   · A page keeps in its own <style> block only what is genuinely its own: the sign-in page's marketing
     deck and announcements, and nothing else.
   ══════════════════════════════════════════════════════════════════════════════════════════════════════ */

.auth-body {
    margin: 0;
    /* The app's own stack. The account pages hard-coded 'Segoe UI' locally while the signed-in app runs on
       Inter, so the door was set in a different typeface from the building. */
    font-family: Inter, 'Segoe UI', system-ui, -apple-system, sans-serif;
    color: var(--ci-ink-body);
    background: var(--ci-content-bg);
    -webkit-font-smoothing: antialiased;
}
.auth-body * { box-sizing: border-box; }

/* ══ The two-column shell (sign in, MFA) ════════════════════════════════════════════════════════════════
   One grid, three rows — a gutter, the content band, a gutter. Both panels span all three and subgrid the
   rows, so the brand copy and the card sit in the SAME row 2 and therefore share one top line: the
   headline's cap-height lands on the card's top edge. Without that, the two columns each centre their own
   content, and because they are never the same height (the card grows with a banner, the brand column
   with a client's announcements) nothing lines up.
   The band stays optically centred because the gutters are 1fr. */
.auth-shell {
    min-height: 100vh;
    display: grid;
    grid-template-columns: 46fr 54fr;
    grid-template-rows: minmax(2rem, 1fr) auto minmax(2rem, 1fr);
}
/* Vertical padding on either panel would offset ITS OWN row-1 track and pull the shared line apart again,
   which is why the gutters live in the shell's rows and each panel is padded on the inline axis only. */
@supports (grid-template-rows: subgrid) {
    .auth-brand { grid-template-rows: subgrid; align-content: normal; }
    .auth-brand-inner { grid-row: 2; }
}

/* ── THE CARD IS CENTRED IN THE WINDOW, not aligned to the brand headline ────────────────────────────────
   It used to share the brand column's row 2, so the headline's cap-height landed exactly on the card's top
   edge. A nice line — and wrong in the one way that gets noticed: the two columns are never the same
   height (the panel grows with a client's announcements, the card with a banner), so the taller one set
   the band and the card sat high with a visible gap under it. Owner's call, 2026-09-09, from a screenshot
   of that gap. The panel still centres its own content; the two just no longer share a top line.

   SAFE centring, not plain centring: on a window shorter than the card, `center` overflows in BOTH
   directions and takes the logo and the username field off the top of the screen, where they cannot be
   scrolled back to. `safe` gives up and aligns to the start instead, which is the correct failure. The
   plain value stays as the fallback for anything that doesn't know the keyword. */
.auth-form { align-content: center; }
@supports (align-content: safe center) {
    .auth-form { align-content: safe center; }
}

/* ── The brand panel ────────────────────────────────────────────────────────────────────────────────────
   THE ONE PLACE IN THIS FILE THAT IS DELIBERATELY NOT TOKENISED. The gradient is the product's identity
   and it is already dark, so it stays as it is in both modes and the ink on it stays white. Exactly the
   nav rail's argument (U12: "anything on the nav rail, which is dark in both modes"). Tokenising it would
   mean a light-mode dark panel and a dark-mode darker panel, i.e. the brand changing colour with a
   personal preference. --ci-navy/--ci-accent are FILLS and do not invert, so they are the right two
   tokens to build it from. */
.auth-brand {
    grid-column: 1; grid-row: 1 / -1; position: relative; overflow: hidden; color: #fff;
    background: linear-gradient(150deg, var(--ci-navy) 0%, #23407e 42%, var(--ci-accent) 100%);
    display: grid; align-content: center; padding: 0 3.5rem;
}
/* Layered glow, then a dot texture masked off toward the bottom right. */
.auth-brand::before {
    content: ""; position: absolute; inset: 0;
    background: radial-gradient(circle at 78% 18%, rgba(0,169,247,.35), transparent 42%),
                radial-gradient(circle at 12% 88%, rgba(255,255,255,.10), transparent 40%);
}
.auth-brand::after {
    content: ""; position: absolute; inset: 0; opacity: .35;
    background-image: radial-gradient(rgba(255,255,255,.14) 1px, transparent 1px);
    background-size: 22px 22px;
    -webkit-mask-image: linear-gradient(120deg, #000 0%, transparent 70%);
    mask-image: linear-gradient(120deg, #000 0%, transparent 70%);
}
.auth-brand-inner { position: relative; z-index: 1; max-width: 440px; }

/* The masthead: the product named once, above whatever the panel is showing, so it holds still. The
   negative top margin is optical, not spacing — the line box carries half-leading above the caps, so a
   box-top alignment still reads as sitting low. Pulling it up puts the INK on the card's top edge. */
.auth-mast {
    margin: -.2rem 0 1.2rem; font-size: .95rem; font-weight: 700; letter-spacing: .08em;
    text-transform: uppercase; opacity: .78; line-height: 1;
}
.auth-mast sup { font-size: .62em; letter-spacing: 0; vertical-align: super; }
.auth-headline {
    font-size: 2.15rem; font-weight: 800; line-height: 1.15; margin: -.4rem 0 1rem; letter-spacing: -.02em;
}
.auth-brand-sub { font-size: 1.02rem; opacity: .85; line-height: 1.55; margin: 0 0 2rem; }
/* A mark on a 2.15rem headline: proportionally smaller than the masthead's and nudged off the cap line,
   so it reads as a mark rather than as a character in the word. */
.auth-rmark { font-size: .38em; vertical-align: super; line-height: 0; opacity: .75; margin-left: .06em; }

/* ── The form column and its card ───────────────────────────────────────────────────────────────────────
   The card gives the column an edge. Without it this column carries a logo, a heading, a form, a help
   line, a confidentiality notice and a copyright with no boundary anywhere, floating on flat grey, which
   turns the space around it from "margin" into "the page failed to fill". */
.auth-form {
    grid-column: 2; grid-row: 1 / -1; display: grid; align-content: center; justify-items: center;
    background: var(--ci-content-bg); padding: 0 2rem;
}
.auth-col { width: 100%; max-width: 420px; }

/* --auth-card-pad is a variable rather than a constant because the fit script trims it as a last resort
   on a short window (see Login.cshtml). */
.auth-card {
    --auth-card-pad: 2.5rem;
    background: var(--ci-surface); border: 1px solid var(--ci-line);
    border-radius: var(--ci-radius-lg); padding: var(--auth-card-pad) calc(var(--auth-card-pad) - .25rem);
    box-shadow: var(--ci-shadow-lg);
}
/* ── The single-column pages ────────────────────────────────────────────────────────────────────────────
   Password reset, reset confirm, sign out and the SSO error card: one centred card, no shell, no brand
   panel. The SAME card as the sign-in column, which is the point — leaving looks like arriving, and a
   reset link opens something recognisably part of the same set.
   Centring the TEXT is a separate class, because it is right for an outcome card and wrong for a form:
   centred labels above left-aligned fields read as a mistake. */
.auth-solo { display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 2rem; }
.auth-solo .auth-col { max-width: 420px; }
.auth-center { text-align: center; }

/* The logo opens the column at every width, above the heading and the first field. Sized by WIDTH: the
   2026 lockup dropped the "software" tagline the 2025 one carried, so an equal HEIGHT would spend all of
   it on the wordmark and print it half again as large. */
.auth-logo { display: flex; align-items: center; margin-bottom: 1.6rem; }
.auth-solo .auth-logo { justify-content: center; }
.auth-logo img { width: 220px; max-width: 100%; height: auto; }

/* Under the card, not pinned to the panel's bottom edge: pinned, it sat ~180px below the last thing it
   had anything to do with and read as a line that had come loose. */
.auth-copy { margin-top: 1.25rem; text-align: center; font-size: .78rem; color: var(--ci-ink-faint); }

.auth-h1 {
    font-size: 1.55rem; margin: 0 0 .35rem; color: var(--ci-brand-ink); letter-spacing: -.01em;
    font-weight: 700; line-height: 1.25;
}
.auth-sub { color: var(--ci-ink-support); margin: 0 0 1.75rem; font-size: .92rem; line-height: 1.5; }

/* ── Fields ─────────────────────────────────────────────────────────────────────────────────────────── */
.auth-field { margin-bottom: 1.1rem; }
.auth-field label {
    display: block; font-size: .82rem; color: var(--ci-ink-2); margin-bottom: .4rem; font-weight: 600;
}
.auth-in {
    width: 100%; padding: .72rem .85rem; border: 1px solid var(--ci-line-strong);
    border-radius: var(--ci-radius); font-size: .95rem; background: var(--ci-surface);
    color: var(--ci-ink-body);
    transition: border-color var(--ci-transition), box-shadow var(--ci-transition);
}
.auth-in::placeholder { color: var(--ci-ink-faint); }
.auth-in:focus { outline: none; border-color: var(--ci-accent); box-shadow: var(--ci-ring); }

/* ── The password reveal ────────────────────────────────────────────────────────────────────────────────
   U12 is strict about welding buttons onto inputs, and this qualifies under its own test: it acts on THE
   FIELD'S OWN VALUE (it changes how that value is displayed) rather than performing an action of its own,
   which is the line the rule draws. It is a GHOST — no resting border or fill — and that is right here
   for the other half of the same rule: a ghost is wrong for "the only door", and this is not a door at
   all. The field works exactly as before without ever touching it, so an outlined end-cap would announce
   a control that matters more than it does. Inset rather than attached for the same reason: the eye
   should still count one control on this row.
   Deliberately NOT type=submit's neighbour: it sits inside the field's own box. */
.auth-in-wrap { position: relative; display: block; }
.auth-in-wrap .auth-in { padding-right: 2.6rem; }
.auth-reveal {
    position: absolute; top: 0; bottom: 0; right: 0; width: 2.5rem; padding: 0;
    display: flex; align-items: center; justify-content: center;
    background: none; border: 0; border-radius: var(--ci-radius);
    color: var(--ci-ink-support); cursor: pointer;
    transition: color var(--ci-transition), background var(--ci-transition);
}
.auth-reveal:hover { color: var(--ci-accent-ink); background: var(--ci-hover); }
.auth-reveal:focus-visible { outline: none; box-shadow: var(--ci-ring); color: var(--ci-accent-ink); }
/* One glyph shown at a time, swapped by the script's aria-pressed. */
.auth-reveal .ico-off { display: none; }
.auth-reveal[aria-pressed="true"] .ico-on { display: none; }
.auth-reveal[aria-pressed="true"] .ico-off { display: block; }

/* ── Buttons ────────────────────────────────────────────────────────────────────────────────────────────
   No hover that MOVES and no press that shifts the label (U12): the previous version used
   `transform: translateY(1px)` on :active, which nudges the text under a cursor already on it. Answer
   "am I on it?" with the fill, and a press with brightness. */
.auth-btn {
    width: 100%; padding: .8rem; margin-top: .3rem; background: var(--ci-accent);
    color: var(--ci-ink-on-brand); border: 0; border-radius: var(--ci-radius);
    font-family: inherit; font-size: 1rem; font-weight: 600; cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
    transition: filter var(--ci-transition), box-shadow var(--ci-transition);
    box-shadow: 0 4px 14px color-mix(in srgb, var(--ci-accent) 28%, transparent);
}
.auth-btn:hover { filter: brightness(.94); box-shadow: 0 6px 18px color-mix(in srgb, var(--ci-accent) 34%, transparent); }
.auth-btn:active { filter: brightness(.88); }
.auth-btn:focus-visible { outline: none; box-shadow: var(--ci-ring); }
/* The working state. A sign-in is not instant — it validates, writes a session row, evicts the permission
   cache, reads the SSO configuration and may dispatch an MFA code — and with no feedback at all people
   click again, which posts the form twice. Disabled AND relabelled: the label is what actually answers
   "did it take?", the spinner only says something is happening. */
/* not-allowed, not default: U14 makes every disabled control in the app answer the same way, whatever its
   tier. Here it is also the truthful answer — the second press really is being refused. */
.auth-btn[disabled] { cursor: not-allowed; filter: none; box-shadow: none; opacity: .85; }
.auth-btn[disabled]:hover { filter: none; }
.auth-spin { flex: none; animation: auth-spin 850ms linear infinite; transform-origin: 50% 50%; }
@keyframes auth-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
    /* The spinner stops turning but stays, because it is also the "still working" marker. */
    .auth-spin { animation: none; }
}
/* A quiet, link-weight action inside the card (MFA's "send a new code"). */
.auth-btn-quiet {
    display: inline-block; width: 100%; background: none; border: 0; box-shadow: none; padding: .5rem;
    margin-top: .4rem; color: var(--ci-accent-ink); font-family: inherit; font-size: .85rem;
    font-weight: 600; cursor: pointer;
}
.auth-btn-quiet:hover { text-decoration: underline; }
.auth-btn-quiet[disabled] { cursor: not-allowed; opacity: .6; text-decoration: none; }

/* ── Banners ────────────────────────────────────────────────────────────────────────────────────────────
   Three, and the distinction matters: an ERROR is something the person must fix, a NOTICE explains why
   they are looking at this page (an inactivity timeout is not a failure), and OK confirms something
   worked. They were `.error`/`.notice` on some pages and `.msg.err`/`.msg.ok` on others. */
.auth-banner {
    padding: .7rem .85rem; border-radius: var(--ci-radius); margin-bottom: 1.25rem;
    font-size: .88rem; line-height: 1.5; border: 1px solid transparent;
}
.auth-banner-error { background: var(--ci-danger-surface); border-color: var(--ci-danger-line); color: var(--ci-danger); }
.auth-banner-note { background: var(--ci-hover); border-color: var(--ci-line-strong); color: var(--ci-accent-ink); }
.auth-banner-ok { background: var(--ci-ok-surface); border-color: var(--ci-ok-line); color: var(--ci-ok); }

/* ── The outcome badge (sign out, SSO error) ────────────────────────────────────────────────────────────
   One badge, three meanings, and picking the wrong one is a copy bug: a green tick is a SUCCESS mark and
   belongs only to a sign-out the person asked for. Over "an administrator ended your session" it
   congratulates somebody on being kicked out, so an involuntary sign-out gets the neutral brand-tinted
   badge — and never the red, since nothing went wrong and nobody needs alarming. */
.auth-badge {
    width: 52px; height: 52px; border-radius: var(--ci-radius-pill); display: flex; align-items: center;
    justify-content: center; margin: 0 auto 1.25rem;
}
.auth-badge-ok { background: var(--ci-ok-surface); color: var(--ci-ok); }
.auth-badge-info { background: var(--ci-hover); color: var(--ci-brand-ink); }
.auth-badge-warn { background: var(--ci-danger-surface); color: var(--ci-danger); }

/* ── Small print under the form ─────────────────────────────────────────────────────────────────────── */
.auth-links { margin-top: 1rem; text-align: center; font-size: .85rem; }
.auth-links a { color: var(--ci-accent-ink); text-decoration: none; font-weight: 600; }
.auth-links a:hover { text-decoration: underline; }
/* Two things on the row the password link used to have to itself: the remember tick on the left, the link on the
   right. Sharing it rather than stacking is what keeps the card off the scrollbar at 722px (see the note in
   Login.cshtml). Wraps back to centred stacking when the card is narrow enough that they would collide. */
.auth-links-split {
    display: flex; align-items: center; justify-content: space-between; gap: .6rem; flex-wrap: wrap;
    text-align: left;
    /* Further off the button than the shared .auth-links margin: the button carries a glow, and at 1rem the row
       sat inside it — it read as part of the button rather than as the line under it. */
    margin-top: 1.4rem;
}
/* NEITHER PHRASE MAY BREAK IN THE MIDDLE. Without this the row's last resort was wrapping "password?" onto a
   line of its own, which reads as a layout fault rather than as two items that didn't fit. If they genuinely
   cannot share the row (a narrow card, a large text size, a zoomed browser) the whole link drops to the next
   line intact — that is what flex-wrap is here for, and it is the only acceptable second state. */
.auth-links-split > * { flex: 0 1 auto; white-space: nowrap; }
/* The label IS the hit area, so the words are clickable and not just the box (U14: the pointer is on everything
   that acts). Normal weight against the link's 600 — it is a setting, not an action, and the link should still
   be the thing the eye lands on. */
.auth-check {
    display: inline-flex; align-items: center; gap: .45rem;
    color: var(--ci-ink-support); font-weight: 400; cursor: pointer;
}
.auth-check input { accent-color: var(--ci-accent); width: .95rem; height: .95rem; margin: 0; cursor: pointer; }
.auth-check input:focus-visible { outline: none; box-shadow: var(--ci-ring); }
.auth-check:hover { color: var(--ci-ink-body); }
.auth-foot { margin-top: 1.5rem; font-size: .78rem; color: var(--ci-ink-faint); text-align: center; }
/* Guidance that belongs to the field above it (the client's password policy), so it is left-aligned with the
   field and sits directly above the commit, which is when it actually gets read. */
.auth-hint { margin: -.4rem 0 1.1rem; font-size: .8rem; line-height: 1.45; color: var(--ci-ink-support); }
.auth-foot a { color: var(--ci-accent-ink); text-decoration: none; }
.auth-foot a:hover { text-decoration: underline; }
/* The administrator-authored LoginConfidentiality notice: a legal notice, not a call to action, so it is
   quiet and below the fold of attention but still on screen without scrolling, as it was in legacy. */
.auth-conf {
    margin-top: 1rem; padding-top: .9rem; border-top: 1px solid var(--ci-line); font-size: .74rem;
    line-height: 1.5; color: var(--ci-ink-faint); text-align: center; overflow-wrap: break-word;
}
.auth-conf p { margin: .25rem 0; }
.auth-conf a { color: var(--ci-ink-support); }
/* A machine-readable reference somebody reads out to support. */
.auth-ref {
    font-family: ui-monospace, 'Cascadia Code', Consolas, monospace; font-size: .85rem;
    color: var(--ci-ink-2); background: var(--ci-surface-2); border: 1px solid var(--ci-line);
    border-radius: var(--ci-radius-sm); padding: .35rem .6rem; display: inline-block; margin: 0 0 1.5rem;
}
/* A stacked pair of destinations, where neither is a form submit (the SSO error page). */
.auth-actions { display: flex; flex-direction: column; gap: .6rem; }
.auth-actions .auth-btn { margin-top: 0; }
.auth-btn-secondary {
    display: inline-flex; align-items: center; justify-content: center; padding: .75rem 1.75rem;
    background: var(--ci-surface); color: var(--ci-brand-ink); border: 1px solid var(--ci-line-strong);
    border-radius: var(--ci-radius); font-size: .96rem; font-weight: 600; text-decoration: none;
    transition: background var(--ci-transition), border-color var(--ci-transition);
}
.auth-btn-secondary:hover { background: var(--ci-hover); border-color: var(--ci-accent); }
/* A link that renders as the card's primary action (no form to submit). */
a.auth-btn { text-decoration: none; }

/* ══ Short viewports: the card gives back its padding ════════════════════════════════════════════════════
   HEIGHT is what bites on these pages, not width (the app's tier is 1250x722). The card's chrome costs
   ~64px of vertical space it did not cost as a bare column, which is enough to push a 722px laptop into
   scrolling — and the sign-in page must never scroll. Trimmed here rather than kept small everywhere, so
   a full-height monitor still gets the roomier card. */
@media (max-height: 800px) {
    /* The vertical give is in the shell's gutter rows, not the panel's padding: a block padding on one
       panel would offset that panel's row track and break the shared top line. */
    .auth-shell { grid-template-rows: minmax(1.25rem, 1fr) auto minmax(1.25rem, 1fr); }
    .auth-form { padding: 0 1.25rem; }
    .auth-card { --auth-card-pad: 1.75rem; }
    .auth-logo { margin-bottom: 1.15rem; }
    .auth-copy { margin-top: .9rem; }
    .auth-sub { margin-bottom: 1.25rem; }
}

/* ══ Narrow but still two columns: 861px to 1100px ═══════════════════════════════════════════════════════
   The panel is 46% of the viewport, so at 960px wide its column is only ~330px and the copy wraps onto
   half again as many lines. That was the one band that still scrolled with everything else already at its
   floor, because the TEXT was the problem. So the type steps down and the panel gives back some of its
   inline padding, which widens the column by ~48px and takes lines out of every block at once. */
@media (max-width: 1100px) {
    .auth-brand { padding: 0 2rem; }
    .auth-mast { font-size: .85rem; margin-bottom: .9rem; }
    .auth-headline { font-size: 1.7rem; }
    .auth-brand-sub { font-size: .92rem; }
}

/* ══ One column: hide the brand panel ════════════════════════════════════════════════════════════════════
   The logo above the form is already there at every width, so nothing is lost. The card sheds its chrome
   here: with the panel gone the whole viewport is the sign-in screen, and a card on a bare page is an
   outline around nothing — there is no surrounding surface left for it to sit on. */
@media (max-width: 860px) {
    .auth-brand { display: none; }
    /* The hidden panel's 46fr column would otherwise still hold its share of the width. */
    .auth-shell { grid-template-columns: 1fr; }
    .auth-form { grid-column: 1; background: var(--ci-surface); }
    .auth-card { box-shadow: none; border: 0; padding: 0; }
    .auth-solo .auth-card { box-shadow: none; border: 0; }
    .auth-solo { background: var(--ci-surface); }
}
