/* auth-base.css — the cross-cutting accessibility layer every hosted auth page loads.
 *
 * Each page keeps its own <style nonce> for layout and palette. What lives here is the
 * part that must be identical on all of them: a visible focus indicator, a reduced-motion
 * escape, the screen-reader-only utility, and target sizing. Served from /static, which
 * the page CSP already allows under style-src 'self'.
 *
 * Loaded BEFORE the page's own <style>, so a page can override a layout value here while
 * the focus and motion rules below still win through :focus-visible specificity and the
 * media query. */

/* WCAG 2.4.7 Focus Visible / 2.4.11 Focus Not Obscured. Pages style input:focus with a
 * box-shadow and set outline:none, which leaves buttons, links and checkboxes with no
 * indicator at all and erases the indicator entirely under forced-colors. One
 * :focus-visible ring on everything focusable, drawn outside the element so a filled
 * button still shows it. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: 3px solid #93c5fd;
    outline-offset: 2px;
    /* the ring must survive a page rule that sets box-shadow on :focus */
    box-shadow: none;
}

/* forced-colors (Windows High Contrast) discards author colors; Highlight is the system
 * focus color and is the only one guaranteed to contrast with the forced background. */
@media (forced-colors: active) {
    :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
        outline-color: Highlight;
    }
}

/* Links. Every hosted page renders on the same near-black panel, and this file previously
 * set no anchor color at all — so 22 of the 29 templates fell back to the browser's default
 * link blue, which against #111827 is barely legible. The seven that did style anchors each
 * patched it privately and disagreed: two different blues, and signin.html used both.
 *
 * #93c5fd clears WCAG AAA on both surfaces these pages use — 9.84:1 on the #111827 body and
 * 8.14:1 on the #1f2937 card. The darker #3b82f6 fails AA on the card at 3.99:1, which is why
 * the choice is not simply "the brand blue".
 *
 * The underline stays. These pages already refuse to carry state by color alone (see the
 * invalid-field rule below), and a link distinguished from body text only by hue fails the
 * same test — for anyone who cannot separate those hues, and for anyone reading a screenshot
 * in grayscale.
 *
 * :visited is deliberately the same color. On an authentication surface the visited state
 * would say which recovery or verification paths this browser has been down, which is a
 * disclosure the page has no reason to make. */
a {
    color: #93c5fd;
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

a:visited {
    color: #93c5fd;
}

a:hover, a:focus-visible {
    color: #bfdbfe;
    text-decoration-thickness: 2px;
}

/* WCAG 2.3.3 Animation from Interactions. The pages animate buttons on hover with a
 * translate + shadow transition; vestibular-sensitive users get neither. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
    button:hover, button:active, a:hover, a:active {
        transform: none !important;
    }
}

/* sr-only: in the accessibility tree and the reading order, off-screen visually. Used for
 * text that a sighted user gets from layout or from a live-updating element that is itself
 * hidden from assistive technology. Not clip: rect() — that breaks line wrapping in some
 * screen readers; the 1px + clip-path form is the current safe idiom. */
.sr-only {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip-path: inset(50%) !important;
    white-space: nowrap !important;
    border: 0 !important;
}

/* a sr-only element that becomes focusable must become visible when focused (a skip link),
 * else a keyboard user is on a control they cannot see. */
.sr-only-focusable:focus, .sr-only-focusable:focus-visible {
    position: static !important;
    width: auto !important;
    height: auto !important;
    margin: 0 !important;
    overflow: visible !important;
    clip-path: none !important;
    white-space: normal !important;
}

/* WCAG 2.5.8 Target Size (Minimum). Checkboxes and radios render around 13px by default,
 * under the 24px floor, and they are the smallest targets on these pages. */
input[type="checkbox"], input[type="radio"] {
    min-width: 1.5rem;
    min-height: 1.5rem;
}

/* the error slot the engine fills (presentation.SlotError). It carries role="alert" and
 * tabindex="-1" from the injector; the outline is suppressed because focus lands here
 * programmatically to force the announcement, not through the tab sequence, and a ring on
 * a message block reads as an editable field. */
[data-pwh="error"]:focus {
    outline: none;
}

/* a field the page has marked invalid, so the state is not carried by color alone
 * (WCAG 1.4.1) — the border thickens as well. */
[aria-invalid="true"] {
    border-color: #f87171 !important;
    border-width: 2px !important;
}

/* The card. Every hosted page centers one panel in a flex body, and the panel's own rule set
 * a max-width and no width. A flex item with no width sizes to its CONTENT, so the box
 * visibly changed width between pages — narrower on a one-field sign-in than on password
 * reset, and narrower again on a page whose longest line was short. width: 100% pins it to
 * the max instead of the contents.
 *
 * border-box is part of the same fix rather than tidying: 12 of the templates set
 * `* { box-sizing: border-box }` and the rest did not, so the same `max-width: 500px` drew a
 * 500px card on some pages and a 564px one (500 plus 2rem of padding either side) on others.
 *
 * The margin is the gutter on a narrow viewport. It survives width: 100% because the panel is
 * a flex item and shrinks to fit — the same pair on an ordinary block would overflow, which is
 * what the nested rule below exists for.
 *
 * Loaded before the page's own <style>, so a page that needs a different size states one
 * there. Two do: device.html at 380px for a short code, account_passkeys.html at 560px for a
 * list of credentials. */
.container, .card {
    width: 100%;
    max-width: 500px;
    box-sizing: border-box;
    margin: 1rem;
}

/* A card inside a container is not the panel — the container is, and it already carries the
 * gutter. The nested card must not take one too: it is an ordinary block, not a flex item, so
 * width: 100% plus a margin would push it out of the box that holds it. */
.container > .card {
    margin: 0;
}

/* Secondary actions: the one-link paragraph under the primary form — forgot your password,
 * email me a sign-in link, can't access your passkey, get help.
 *
 * Six class names carried this one thing across the templates (forgot-password, magic-link,
 * recovery-link, recovery, redress, and signin.html's own second copy), and only some of them
 * were styled. On the sign-in page `.forgot-password` was centered at 0.875rem while
 * `.magic-link` had no rule at all, so "Email me a sign-in link" rendered left-aligned at body
 * size directly beneath it. They are the same kind of thing in the same place, so they are one
 * class with one rule. */
.secondary-action {
    margin-top: 1rem;
    text-align: center;
    font-size: 0.875rem;
}

/* The support route is the last secondary action on a page and leads off it entirely, so it
 * sits below a separator rather than in the run of them. */
.secondary-action.redress {
    margin-top: 1.5rem;
    padding-top: 1rem;
    border-top: 1px solid #374151;
}
