/* account-shell.css — shared chrome for the statically-rendered account pages (AccountShell.razor).
   This is a NON-isolated global stylesheet, linked once in App.razor. It is global (not a *.razor.css
   isolated sheet) on purpose: each page renders its panel as AccountShell's ChildContent, which CSS
   isolation cannot reach from the shell's scope; and the form controls are emitted by child components
   (EditForm/InputText/StatusMessage) that carry no page scope. A global sheet sidesteps both — the
   .tv-login__* BEM prefix keeps every selector collision-safe, and there is no ::deep (which is only
   valid in isolated sheets).

   It holds only what is identical across the account pages: the shell, the brand aside, and the
   form/field/status/badge system. Page-specific rules stay in each page's own isolated *.razor.css —
   Login's tabs + SSO picker + CCTC-<Button> submit, and ExternalLogin's plain-<button> submit. */

.tv-login {
    /* Surfaces + accent come from the brand layer; the per-surface white-alpha roles read against
       this dark ink and so are declared here, exactly as the public dark bands do. */
    --tv-canvas: var(--brand-ink);
    --tv-panel: var(--brand-ink-deep);
    --tv-accent: var(--brand-highlight);
    /* Darker accent for solid fills that carry white text (the submit button): the bright
       --tv-accent is only ~2.9:1 against white, below WCAG AA, whereas this clears 4.5:1.
       --tv-accent itself stays bright for focus rings/accents, which sit on the dark panel. */
    --tv-accent-strong: color-mix(in srgb, var(--brand-highlight) 72%, black);
    --tv-text: #fff;
    --tv-muted: rgba(255, 255, 255, 0.72);
    --tv-muted-2: rgba(255, 255, 255, 0.58);
    --tv-rule: rgba(255, 255, 255, 0.10);
    --tv-rule-strong: rgba(255, 255, 255, 0.18);
    --tv-field-bg: rgba(255, 255, 255, 0.04);
    --tv-field-border: rgba(255, 255, 255, 0.18);

    min-height: 100vh;
    background: var(--tv-canvas);
    color: var(--tv-text);
    font-family: var(--primary-font, system-ui, sans-serif);
}

/* ---- layout: single column on small screens, two columns from 64rem ---- */
.tv-login__grid {
    display: grid;
    grid-template-columns: 1fr;
    min-height: 100vh;
}

@media (min-width: 64rem) {
    .tv-login__grid {
        grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    }
}

/* ============================ left / about ============================ */
.tv-login__about {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    /* Let the 1fr grid track shrink below its content's min-size (prevents reflow overflow when the
       browser default font size is raised). */
    min-width: 0;
    /* Anchor + clip the decorative graph backdrop (.tv-login__graph), so it can never extend the
       panel — and therefore the page — height. */
    position: relative;
    overflow: hidden;
    padding: 2rem 1.5rem;
    background:
        radial-gradient(40rem 40rem at -10% -10%, rgba(53, 160, 215, 0.10), transparent 60%),
        var(--tv-canvas);
}

/* The real panel content sits above the graph backdrop (which is z-index:0). */
.tv-login__about > *:not(.tv-login__graph) {
    position: relative;
    z-index: 1;
}

/* Decorative connected-graph backdrop — clipped to the panel, anchored to the right, and faded out
   toward the copy on the left so the text stays legible. Removed from layout flow (absolute) so it
   adds no height; pointer-events:none so it is never interactive. */
.tv-login__graph {
    position: absolute;
    z-index: 0;
    top: 50%;
    right: -6%;
    /* Scale with the panel rather than capping at a fixed size: the 82% preferred term tracks the
       panel width (≈476px at the 1280 desktop viewport, unchanged), and only the much larger 64rem
       ceiling caps it — so on wide/high-resolution monitors the backdrop grows instead of looking
       lost in empty space. */
    width: clamp(28rem, 82%, 64rem);
    aspect-ratio: 1080 / 1350;
    transform: translateY(-25%);
    pointer-events: none;
    opacity: 0.72;
    -webkit-mask-image: linear-gradient(to right, transparent, #000 55%);
            mask-image: linear-gradient(to right, transparent, #000 55%);
}

/* The stage is server-rendered and empty; scripts/trialview-graph.js fills it with the
   generated <svg>. It was an <iframe> until TrialView#44 — see ConnectedGraph.razor for why
   the frame existed and what replaced it. */
.tv-login__graph-stage {
    display: block;
    width: 100%;
    height: 100%;
}

.tv-login__graph-stage svg {
    display: block;
    width: 100%;
    height: 100%;
}

.tv-login__graph-stage .tv-graph__edge {
    fill: none;
    stroke-dasharray: var(--len, 600);
    stroke-dashoffset: 0;
}

.tv-login__graph-stage .tv-graph__star {
    transform-box: fill-box;
    transform-origin: center;
    opacity: var(--o, 1);
}

/* Entrance draw-in. The base rules above are the VISIBLE end state; the hidden start applies
   only while the JS-added --intro class is present, so a graph whose script never runs is
   simply drawn, not invisible. */
.tv-login__graph-stage--intro .tv-graph__edge {
    stroke-dashoffset: var(--len, 600);
}

.tv-login__graph-stage--intro .tv-graph__star {
    opacity: 0;
    transform: scale(0.4);
}

.tv-login__graph-stage--intro.tv-login__graph-stage--play .tv-graph__edge {
    stroke-dashoffset: 0;
    transition: stroke-dashoffset 1.1s cubic-bezier(0.4, 0, 0.2, 1);
    transition-delay: var(--d, 0s);
}

.tv-login__graph-stage--intro.tv-login__graph-stage--play .tv-graph__star {
    opacity: var(--o, 1);
    transform: scale(1);
    transition: opacity 0.55s ease, transform 0.8s cubic-bezier(0.34, 1.32, 0.5, 1);
    transition-delay: var(--d, 0s);
}

/* Continuous, slow, subtle life — motion-gated, as in the frame document. */
@media (prefers-reduced-motion: no-preference) {
    .tv-login__graph-stage .tv-graph__drift {
        transform-box: fill-box;
        transform-origin: center;
        animation: tv-graph-drift var(--dur, 22s) ease-in-out infinite alternate;
        animation-delay: var(--ddl, 0s);
        will-change: transform;
    }

    .tv-login__graph-stage .tv-graph__pulse {
        animation: tv-graph-glow 6.4s ease-in-out infinite alternate;
        transform-box: fill-box;
        transform-origin: center;
    }

    @keyframes tv-graph-drift {
        from { transform: translate(0, 0); }
        to { transform: translate(var(--dx, 0px), var(--dy, 0px)); }
    }

    @keyframes tv-graph-glow {
        from { opacity: 0.6; transform: scale(1); }
        to { opacity: 0.95; transform: scale(1.05); }
    }
}

@media (min-width: 64rem) {
    .tv-login__about {
        padding: 3rem 3.25rem;
        border-right: 1px solid var(--tv-rule);
    }
}

.tv-login__brand {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    margin-bottom: 1rem;
}

.tv-login__brand-logo,
.tv-login__brand-mark {
    height: 2.25rem;
    width: auto;
}

.tv-login__brand-sep {
    width: 1px;
    height: 1.75rem;
    background: var(--tv-rule-strong);
}

/* The CCTC logo links back to the public home page. */
.tv-login__brand-home {
    display: inline-flex;
    border-radius: 4px;
}

.tv-login__brand-home:focus-visible {
    outline: 2px solid var(--tv-accent);
    outline-offset: 3px;
}

.tv-login__eyebrow {
    color: var(--tv-accent);
}

.tv-login__headline {
    font-size: clamp(2rem, 5vw, 3rem);
    font-weight: 700;
    line-height: 1.05;
    letter-spacing: -0.03em;
    margin: 0;
    text-wrap: balance;
}

.tv-login__headline-accent {
    color: var(--tv-accent);
}

.tv-login__lead {
    max-width: 34rem;
    color: var(--tv-muted);
    font-size: 1rem;
    line-height: 1.6;
    margin: 0;
}

/* centre-details grid */
.tv-login__centre {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem 2rem;
    margin: 0.5rem 0 0;
    padding-top: 1.5rem;
    border-top: 1px solid var(--tv-rule);
}

@media (min-width: 30rem) {
    .tv-login__centre {
        grid-template-columns: 1fr 1fr;
    }
}

.tv-login__centre-item dt {
    font-size: 0.6875rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--tv-muted-2);
    margin-bottom: 0.25rem;
}

.tv-login__centre-item dd {
    margin: 0;
    font-size: 0.875rem;
    color: var(--tv-text);
    overflow-wrap: anywhere;
}

/* partners logo row (row two, below the Centre/Support row) */
.tv-login__partners {
    margin-top: 0.25rem;
}

.tv-login__partners-label {
    font-size: 0.6875rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--tv-muted-2);
    margin: 0 0 0.625rem;
    font-weight: 700;
}

.tv-login__partner-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.75rem;
}

/* White chip behind each mark — the source artwork is drawn for light surfaces, so this keeps the
   NHS / CRUK / Cambridge brand marks legible on the dark panel (matches the public footer). */
.tv-login__partner-row img {
    display: block;
    height: 1.75rem;
    width: auto;
    max-width: 100%;
    background-color: rgba(255, 255, 255, 0.65);
    border-radius: 6px;
    padding: 0.4rem 0.6rem;
    box-sizing: content-box;
}

.tv-login__about-footer {
    margin-top: auto;
    padding-top: 1.5rem;
    border-top: 1px solid var(--tv-rule);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 1.25rem;
    font-size: 0.75rem;
    color: var(--tv-muted-2);
}

.tv-login__footer-links {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.tv-login__footer-links a {
    color: var(--tv-muted);
    text-decoration: none;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.tv-login__footer-links a:hover {
    color: var(--tv-text);
    text-decoration: underline;
}

.tv-login__copyright,
.tv-login__version {
    margin: 0;
}

.tv-login__version {
    font-family: var(--bs-font-monospace, monospace);
    letter-spacing: 0.04em;
}

/* ============================ right / auth ============================ */
.tv-login__auth {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    min-width: 0;
    padding: 2rem 1.5rem;
    background: var(--tv-panel);
}

@media (min-width: 64rem) {
    .tv-login__auth {
        padding: 3rem 3.25rem;
    }
}

.tv-login__auth-top {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 0.5rem 1rem;
    font-size: 0.6875rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--tv-muted-2);
}

/* Environment badge (ExternalLogin's auth-top). */
.tv-login__env::before {
    content: "";
    display: inline-block;
    width: 0.5rem;
    height: 0.5rem;
    margin-right: 0.4rem;
    border-radius: 50%;
    background: var(--tv-accent);
    vertical-align: middle;
}

/* In-text links keep a non-colour cue (underline) so they are distinguishable without colour
   (WCAG 1.4.1). */
.tv-login__support a,
.tv-login__inline-link,
.tv-login__switch a,
.tv-login__support a:visited {
    color: var(--tv-accent);
    text-decoration: underline;
}

/* panel + headings */
.tv-login__panel {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
}

.tv-login__title {
    font-size: clamp(1.5rem, 3vw, 2rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.1;
    margin: 0;
}

.tv-login__subtitle {
    margin: -0.5rem 0 0;
    color: var(--tv-muted);
    font-size: 0.9375rem;
    line-height: 1.5;
}

/* Authenticator enrolment — numbered steps, the manual-entry secret, and the one-time recovery codes. */
.tv-login__steps {
    margin: 0;
    padding-left: 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    color: var(--tv-muted);
    font-size: 0.9375rem;
    line-height: 1.5;
}

.tv-login__qr {
    display: block;
    width: 200px;
    height: 200px;
    margin: 0.75rem 0;
    padding: 0.5rem;
    background: #fff;
    border-radius: 0.5rem;
    /* Keep the QR modules crisp when the PNG is scaled to the box. */
    image-rendering: pixelated;
}

.tv-login__sharedkey {
    margin: 0.5rem 0 0;
}

.tv-login__sharedkey kbd {
    display: inline-block;
    padding: 0.5rem 0.75rem;
    border-radius: 0.5rem;
    background: var(--tv-panel);
    border: 1px solid var(--tv-rule);
    color: var(--tv-text);
    font-family: var(--bs-font-monospace, monospace);
    font-size: 1rem;
    letter-spacing: 0.15em;
}

.tv-login__recovery {
    list-style: none;
    margin: 0;
    padding: 1rem;
    border-radius: 0.5rem;
    background: var(--tv-panel);
    border: 1px solid var(--tv-rule);
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.5rem 1rem;
}

.tv-login__recovery code {
    color: var(--tv-text);
    font-family: var(--bs-font-monospace, monospace);
    font-size: 0.9375rem;
    letter-spacing: 0.08em;
}

/* Secondary actions under the recovery codes (copy / download). Outlined rather than accent-filled so
   they read as helpers beside the primary "Continue to sign in" link, not as the page's main action. */
.tv-login__codeactions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

.tv-login__codeaction {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 2.75rem;
    padding: 0 1rem;
    border: 1px solid var(--tv-rule);
    border-radius: 0.5rem;
    background: transparent;
    color: var(--tv-text);
    font-size: 0.9375rem;
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease;
}

.tv-login__codeaction:hover {
    background: var(--tv-panel);
    border-color: var(--tv-accent);
}

.tv-login__codeaction:focus-visible {
    outline: 3px solid var(--tv-accent);
    outline-offset: 2px;
}

.tv-login__codeaction .material-icons {
    font-size: 1.2rem;
    line-height: 1;
}

.tv-login__codestatus {
    margin: 0;
    min-height: 1.25rem;
    font-size: 0.875rem;
    color: var(--tv-muted);
}

@media (prefers-reduced-motion: reduce) {
    .tv-login__codeaction {
        transition: none;
    }
}

/* forms — the <form> is emitted by the child <EditForm> component. In this global sheet there is no
   scope attribute, so a plain descendant selector reaches it (the isolated sheets needed ::deep). */
.tv-login .tv-login__form {
    display: flex;
    flex-direction: column;
    /* Generous vertical rhythm so each label associates clearly with its own input
       (the gap between fields is much larger than the label→input gap within a field). */
    gap: 1.5rem;
}

.tv-login__row {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
}

@media (min-width: 30rem) {
    .tv-login__row {
        grid-template-columns: 1fr 1fr;
    }
}

.tv-login__field {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
}

/* Narrowed single-column fields: full width on mobile, 50% from tablet up — the whole field block
   (label row + input) so they stay aligned. */
@media (min-width: 48rem) {
    .tv-login__field--narrow {
        width: 50%;
    }
}

.tv-login__field label,
.tv-login__label-row label {
    font-size: 0.75rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--tv-muted);
}

.tv-login__label-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.5rem;
    /* The label and its inline link ("Forgot password?") stop fitting one line at a
       raised browser default font; without wrapping the link overflows and the page
       scrolls horizontally (WCAG 1.4.4 / 1.4.10). */
    flex-wrap: wrap;
}

.tv-login__inline-link {
    font-size: 0.75rem;
    text-transform: none;
    letter-spacing: 0;
    /* Keep the tappable box ≥ 24px tall (WCAG 2.2 SC 2.5.8). */
    display: inline-flex;
    align-items: center;
    min-height: 1.5rem;
}

.tv-login__hint {
    margin: 0;
    font-size: 0.75rem;
    color: var(--tv-muted-2);
}

/* text/select controls — emitted by EditForm child components, plus any page's own <input> */
.tv-login input[type="text"],
.tv-login input[type="email"],
.tv-login input[type="password"],
.tv-login select {
    width: 100%;
    min-height: 2.875rem;
    padding: 0.625rem 0.875rem;
    background: var(--tv-field-bg);
    border: 1px solid var(--tv-field-border);
    border-radius: 0.5rem;
    color: var(--tv-text);
    font-size: 1rem;
    font-family: inherit;
}

.tv-login select {
    appearance: none;
    cursor: pointer;
    /* The control is dark-on-light by default, so its native drop-down popup renders on a white
       background — making the white option text invisible. color-scheme:dark tells the browser to
       paint the native popup dark with light text; the explicit option colours below are the
       belt-and-braces fallback for engines that don't honour color-scheme on the popup. */
    color-scheme: dark;
}

/* A <select> has no ::placeholder pseudo, so while the empty placeholder option is the chosen one the
   displayed text must be muted explicitly to match the text inputs' placeholder treatment. */
.tv-login select:has(option[value=""]:checked) {
    color: var(--tv-muted-2);
}

.tv-login option {
    background-color: var(--tv-panel);
    color: var(--tv-text);
}

.tv-login input::placeholder {
    color: var(--tv-muted-2);
}

/* A read-only field (e.g. ExternalLogin's IdP-verified email) is shown but not editable. */
.tv-login input[readonly] {
    color: var(--tv-muted);
    cursor: not-allowed;
}

.tv-login input:focus-visible,
.tv-login select:focus-visible,
.tv-login a:focus-visible {
    outline: 3px solid var(--cctc-focus-color);
    outline-offset: 2px;
}

/* checkbox row */
.tv-login__check {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.625rem;
    align-items: start;
    font-size: 0.875rem;
    color: var(--tv-muted);
}

.tv-login__check input[type="checkbox"] {
    width: 1.15rem;
    height: 1.15rem;
    /* Zero the browser's default checkbox margins (they made the box wider than its grid cell, so it
       spilled left of the input column and below into the button). */
    margin: 0.1rem 0 0 0.3rem;
    accent-color: var(--tv-accent);
    flex-shrink: 0;
}

.tv-login__check label {
    line-height: 1.45;
}

/* validation + status */
.tv-login .validation-message,
.tv-login .tv-login__validation {
    color: #ffb4a8;
    font-size: 0.8125rem;
}

/* Keep the invalid-field outline consistent with the validation text. The global app.css uses a
   saturated #e50000 for both, but these pages lighten the text to #ffb4a8 for AA contrast on the
   dark panel — so the outline must follow it (only the colour is overridden; width/style stay). */
.tv-login .invalid {
    outline-color: #ffb4a8;
}

/* The terms-checkbox row is a 2-col grid (checkbox | label). Span its validation message across both
   columns so it sits full-width beneath the control and label — otherwise it lands in the narrow
   checkbox column, where its text widens that column and shoves the label far to the right. */
.tv-login__check .validation-message {
    grid-column: 1 / -1;
}

/* StatusMessage is a child component; in this global sheet a plain descendant selector reaches it. */
.tv-login .tv-login__status {
    padding: 0.875rem 1rem;
    border-radius: 0.5rem;
    font-size: 0.9375rem;
    line-height: 1.5;
    border: 1px solid var(--tv-rule-strong);
}

/* Danger banner (an authentication failure is an error, not a warning — so it uses the theme's danger
   red, NOT --brand-signal/amber, which is the links-&-warnings colour). Made prominent in the
   GOV.UK / NHS error idiom: a solid red left accent bar + a stronger fill + bold text, so it reads as
   a clear error rather than a faint tint. role="alert" on the element carries it to screen readers. */
.tv-login .tv-login__status--error {
    background: rgba(220, 53, 69, 0.22);
    border-color: rgba(255, 120, 110, 0.6);
    border-left: 4px solid #ff6b6b;
    color: #ffd5cf;
    font-weight: 600;
}

.tv-login .tv-login__status--success {
    background: rgba(53, 160, 215, 0.12);
    color: #cfeaf8;
}

.tv-login__switch {
    margin: 0;
    font-size: 0.875rem;
    color: var(--tv-muted);
}

/* compliance badge */
.tv-login__badge {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin: 0;
    padding-top: 0.5rem;
    color: var(--tv-muted-2);
    font-family: var(--bs-font-monospace, monospace);
    font-size: 0.75rem;
    letter-spacing: 0.02em;
    overflow-wrap: anywhere;
}

.tv-login__badge-icon {
    width: 0.875rem;
    height: 0.875rem;
    border: 1px solid var(--tv-muted-2);
    border-radius: 0.15rem 0.15rem 0 0;
    border-bottom-width: 0.4rem;
    box-sizing: border-box;
}

/* Primary CCTC-<Button> submit — Login's sign-in/register buttons, and the password/email utility
   pages reuse it for a consistent icon'd accent button. `CssClass` lands on the `<cctc-button>` wrapper,
   so the wrapper carries the layout (right-aligned, full width on mobile / 50% from tablet via
   `--narrow`) and the accent fill is applied to the inner real `<button>`. These rules are global (not
   `::deep`-scoped) because the wrapper is a child component rendered inside a page's `AccountShell`
   ChildContent — an isolated rule anchored on `.tv-login` would not reach it. The fill uses
   `--tv-accent-strong` to clear WCAG AA contrast against the white label (commit 2dd55fa0). */
.tv-login .tv-login__submit {
    display: flex;
    justify-content: flex-end;
    width: 100%;
}

@media (min-width: 48rem) {
    .tv-login .tv-login__submit--narrow {
        width: 50%;
    }
}

/* `.tv-login` prefix lifts these above the CCTC <Button>'s own scoped `.button-wrapper[b-…]` rule
   (specificity 0,2,0) on its inner <button>; without it the accent fill loses the cascade and the
   button renders with no background. */
.tv-login .tv-login__submit button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 3rem;
    padding: 0 1.25rem;
    border: 0;
    border-radius: 0.5rem;
    background: var(--tv-accent-strong);
    color: #fff;
    font-weight: 700;
    font-size: 1rem;
    cursor: pointer;
    transition: filter 0.15s ease;
}

.tv-login .tv-login__submit button:hover {
    filter: brightness(1.08);
}

.tv-login .tv-login__submit button:focus-visible {
    outline: 3px solid var(--tv-accent);
    outline-offset: 2px;
}

/* The leading Material-Icons glyph sits flush with the label. */
.tv-login .tv-login__submit .button-icon {
    font-size: 1.2rem;
    line-height: 1;
}

@media (prefers-reduced-motion: reduce) {
    .tv-login .tv-login__submit button {
        transition: none;
    }
}

/* SSO picker — rendered by ExternalLoginPicker on the Login page (child component → global, not ::deep). */
.tv-login__or {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin: 0.5rem 0;
    color: var(--tv-muted-2);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.tv-login__or::before,
.tv-login__or::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--tv-rule);
}

.tv-login__sso-buttons {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.75rem;
}

@media (min-width: 30rem) {
    .tv-login__sso-buttons {
        grid-template-columns: 1fr 1fr;
    }
}

.tv-login__sso-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 3rem;
    padding: 0.625rem 1rem;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid var(--tv-field-border);
    border-radius: 0.5rem;
    color: var(--tv-text);
    font-weight: 600;
    font-size: 0.9375rem;
    cursor: pointer;
}

.tv-login__sso-button:hover {
    background: rgba(255, 255, 255, 0.10);
}

.tv-login__sso-button:focus-visible {
    outline: 3px solid var(--cctc-focus-color);
    outline-offset: 2px;
}

/* The NHS provider has no logo asset; render an accessible NHS wordmark block in CSS. */
.tv-login__sso-button--nhs .tv-login__sso-label::before {
    content: "NHS";
    display: inline-block;
    margin-right: 0.5rem;
    padding: 0.1rem 0.3rem;
    border-radius: 0.2rem;
    background: #005eb8;
    color: #fff;
    font-weight: 800;
    font-size: 0.75rem;
    letter-spacing: 0.02em;
}

/* forced colours — give the form controls a visible boundary in high-contrast mode */
@media (forced-colors: active) {
    .tv-login input,
    .tv-login select,
    .tv-login .tv-login__submit button,
    .tv-login__sso-button,
    .tv-dev__btn {
        border: 1px solid ButtonBorder;
    }

    /* The shell's dark surface is forced to Canvas (white), but the in-text links
       keep the author accent --tv-accent (#35a0d7) — measured 2.93:1 against the
       forced background, where WCAG 1.4.3 needs 4.5:1. Pin them to the system link
       colour so the OS palette wins; the underline set above is unaffected, so the
       non-colour cue (WCAG 1.4.1) still holds. */
    .tv-login__support a,
    .tv-login__inline-link,
    .tv-login__switch a,
    .tv-login__support a:visited {
        color: LinkText;
    }
}

/* ---------------------------------------------------------------------------
   Developer / UAT quick sign-in (DevLogin.razor) — non-production only. Reuses
   the shell's local --tv-* role layer; adds no new tokens.
   --------------------------------------------------------------------------- */
.tv-dev__banner {
    margin: 0 0 1.5rem;
    padding: 0.75rem 1rem;
    border: 1px solid var(--tv-accent);
    border-radius: 0.5rem;
    background: color-mix(in srgb, var(--tv-accent) 12%, transparent);
    color: var(--tv-text);
    font-size: 0.9375rem;
    line-height: 1.45;
}

.tv-dev__list {
    list-style: none;
    margin: 0 0 1.5rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.tv-dev__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.75rem 0;
    border-top: 1px solid var(--tv-rule);
}

.tv-dev__row:first-child {
    border-top: 0;
}

.tv-dev__who {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}

.tv-dev__email {
    color: var(--tv-text);
    font-weight: 600;
    font-size: 0.9375rem;
    word-break: break-word;
}

.tv-dev__role {
    color: var(--tv-muted);
    font-size: 0.8125rem;
}

.tv-dev__actions {
    display: flex;
    gap: 0.5rem;
    flex-shrink: 0;
}

.tv-dev__form {
    margin: 0;
}

.tv-dev__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 2.5rem;
    padding: 0.4rem 0.9rem;
    border: 1px solid var(--tv-field-border);
    border-radius: 0.5rem;
    background: rgba(255, 255, 255, 0.06);
    color: var(--tv-text);
    font-weight: 600;
    font-size: 0.875rem;
    cursor: pointer;
}

.tv-dev__btn--primary {
    border-color: transparent;
    background: var(--tv-accent);
    color: var(--tv-canvas);
}

.tv-dev__btn:hover {
    background: rgba(255, 255, 255, 0.12);
}

.tv-dev__btn--primary:hover {
    background: var(--tv-accent-strong);
}

.tv-dev__btn:focus-visible {
    outline: 3px solid var(--cctc-focus-color);
    outline-offset: 2px;
}

.tv-login__switch--dev {
    font-size: 0.8125rem;
}
