h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/*
  REL-012 §6.2 / SEC-NFR-A11Y-001 (Phase-2 a11y BASELINE — WCAG 1.4.10 Reflow) — the approval queue table
  (.kl-queue on /approvals) was unstyled, so each row's full record-group GUID (36 chars) + the timestamp forced
  the table's intrinsic min-width to ~643px, which produced a HORIZONTAL SCROLLBAR at the 320px/375px mobile
  viewports (the §6.2 viewport sweep caught this — Ui_AccessibilityMatrix). This is the minimal, a11y-only fix:
  fix the table layout to the available inline-size and let the long opaque tokens WRAP inside their cells
  (overflow-wrap/word-break) instead of dictating the table width — so the queue reflows to a single column with
  NO horizontal scrolling, usable at 320px (WCAG 1.4.10). Logical properties only (RTL-safe). Scoped to .kl-queue
  so nothing else is affected. (The FULL WCAG-2.2-AA conformance gate + VPAT ride REL-016 / Phase-6.)
*/
.kl-queue {
    inline-size: 100%;
    max-inline-size: 100%;
    table-layout: fixed;
    border-collapse: collapse;
}

.kl-queue th,
.kl-queue td {
    text-align: start; /* logical alignment (mirrors under RTL) */
    /* Long opaque tokens (the record-group GUID, the ISO timestamp) wrap within the cell rather than forcing
       the table wider than the viewport — this is what removes the horizontal scroll at 320px/375px. */
    overflow-wrap: anywhere;
    word-break: break-word;
}

/*
  WCAG 2.2 AA 2.5.8 (Target Size, minimum) — the approval-queue row link (the record-group GUID) was a bare inline
  anchor whose clickable box was < 24x24 CSS px (axe 'target-size'). Render it inline-block with enough block-size
  + vertical padding to meet the 24px minimum target, so the supervisor can reliably tap the row link on touch.
  (a11y-only; scoped to the queue link.)
*/
.kl-queue a {
    display: inline-block;
    min-block-size: 24px;
    padding-block: 0.25rem;
}

/*
  WCAG 2.2 AA 2.5.8 (Target Size, minimum) — the record-entry Save button (.kf-submit-bar button, data-testid
  find-submit) rendered as a bare <button> whose clickable box was < 24x24 CSS px (axe 'target-size' at 375w).
  Give it the 24px minimum block/inline target with comfortable padding. (a11y-only; scoped to the submit bar.)
*/
.kf-submit-bar button {
    min-block-size: 24px;
    min-inline-size: 24px;
    padding-block: 0.35rem;
    padding-inline: 0.9rem;
}

/*
  WCAG 2.2 AA 2.5.8 (Target Size, minimum) — the dev-login persona submit buttons (.kl-btn inside the dev-login
  form: data-persona; and the dev sign-out: data-action="dev-sign-out") are bare <button>s whose clickable box
  could fall < 24x24 CSS px at the 375w mobile viewport (axe 'target-size'). Give them the 24px minimum target with
  comfortable padding so a developer can reliably tap a persona on touch. (a11y-only; scoped to the dev-login
  buttons. This is the DEV persona seam, not production auth — OIDC/API-010 is P5.)
*/
button[data-persona],
button[data-action="dev-sign-out"] {
    min-block-size: 24px;
    min-inline-size: 24px;
    padding-block: 0.35rem;
    padding-inline: 0.9rem;
}

/* ---------------------------------------------------------------------------
   Shell nav drawer (narrow widths) — keep the topbar's BACK + HAMBURGER visible
   while the rail drawer is open. UI-GUAR-015 follow-up (owner report 2026-06-27).
   The open drawer (.kl-shellnav-rail.is-open) is a fixed full-height overlay at
   z-index:60; the topbar (.kl-shellnav-topbar) is static with no z-index, so the
   open drawer rendered OVER the topbar — covering the very hamburger used to close
   it, plus the back arrow. Fix: pin the topbar ABOVE the drawer (sticky + higher
   z-index) and start the drawer BELOW the topbar so both controls stay visible and
   tappable while the menu is open. (Kept in app.css — loaded after, wins the cascade
   — to avoid touching the shared kanine-design-system.css the build agent is editing.)
   Topbar box = min-block-size:48px + padding-block 2x--k-space-1(4px) + 1px border ~= 56px.
   MUST TRACK the drawer breakpoint in kanine-design-system.css §7 (raised 1024 -> 1280 by the owner ruling
   2026-07-24, so a ~1280 landscape tablet gets the drawer). The COLLAPSED-rail state carries the same pairing at
   every width, declared in the shared sheet so the native head gets it too.
   --------------------------------------------------------------------------- */
@media (max-width: 1280px) {
    .kl-shellnav-topbar {
        position: sticky;
        inset-block-start: 0;
        z-index: 70; /* above the open drawer's z-index:60 so back + hamburger stay on top */
    }

    /* P4: the bar is pinned in THIS band, so an in-page sticky element must start below it. Declared here, beside
       the rule that creates the need, so the offset can never drift from the sticky-ness that requires it.
       See kanine-design-system.css §7 for the token contract. */
    :root {
        --k-sticky-top: var(--k-topbar-h);
    }

    .kl-shellnav-rail.is-open {
        inset-block-start: 56px; /* open BELOW the topbar, not over it */
    }
}
/* =============================================================================
   Dev sign-in (/dev/login) — the tester-facing persona picker (REL-012 seam).
   Brand-token only (kanine-design-system.css custom properties), so all four
   theme modes (light / dark / outdoor variants) re-skin it automatically; the
   one dark-specific rule below uses a bare `html.dark` selector (NEVER
   :global(html.dark) — dead-rule trap). Cards lean on the design-system
   [class$="-card"] surface family; buttons stay real form-POST submits
   (button[data-persona]) — the static-SSR cookie sign-in mechanism.
   ========================================================================== */
.kl-devlogin {
    max-inline-size: var(--k-content-max);
    margin-inline: auto;
}

.kl-devlogin-hero { padding-block: var(--k-space-4) 0; }

.kl-devlogin-brand {
    display: flex;
    align-items: center;
    gap: var(--k-space-2);
    margin-block-end: var(--k-space-4);
}

.kl-devlogin-brand-icon { font-size: 26px; color: var(--k-accent); }

.kl-devlogin-wordmark {
    font-family: var(--k-font-display);
    font-size: 19px;
    font-weight: 800;
    letter-spacing: .14em;
    color: var(--k-text);
}

.kl-devlogin-phase-chip { margin-inline-start: var(--k-space-1); }

.kl-devlogin-title {
    margin: 0 0 var(--k-space-3);
    font-family: var(--k-font-display);
    font-size: clamp(22px, 4.5vw, 30px);
    line-height: 1.15;
}

.kl-devlogin-intro {
    max-inline-size: 72ch;
    margin: 0 0 var(--k-space-4);
    font-size: 15px;
    line-height: 1.6;
    color: var(--k-text);
}

/* The isolation / gate-scope callout: a quiet teal-washed aside, token-mixed so it adapts per mode. */
.kl-devlogin-isolation {
    max-inline-size: 72ch;
    margin: 0 0 var(--k-space-6);
    padding: var(--k-space-3) var(--k-space-4);
    border-inline-start: 3px solid var(--k-accent);
    border-radius: var(--k-radius-sm);
    background: color-mix(in srgb, var(--k-accent) 8%, var(--k-surface));
    font-size: 14px;
    line-height: 1.55;
    color: var(--k-text);
}

/* Dark: nudge the wash stronger so the callout still reads as a distinct surface on the dark field. */
html.dark .kl-devlogin-isolation {
    background: color-mix(in srgb, var(--k-accent) 15%, var(--k-surface));
}

.kl-devlogin-current {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--k-space-3);
    margin-block-end: var(--k-space-6);
    padding: var(--k-space-3) var(--k-space-4);
    border: 1px solid var(--k-border);
    border-radius: var(--k-radius-md);
    background: var(--k-surface-2);
}

.kl-devlogin-current-text { margin: 0; font-size: 14px; }

/* Group fieldsets: strip the UA fieldset chrome; the legend becomes a section header. */
.kl-devlogin-group {
    border: 0;
    padding: 0;
    margin: 0 0 var(--k-space-8);
    min-inline-size: 0;
}

.kl-devlogin-group-head {
    display: flex;
    align-items: baseline;
    gap: var(--k-space-2);
    padding: 0;
    margin-block-end: var(--k-space-3);
    font-family: var(--k-font-display);
}

.kl-devlogin-group-head .ki { color: var(--k-accent); font-size: 18px; align-self: center; }

.kl-devlogin-group-name { font-size: 18px; font-weight: 700; color: var(--k-text); }

.kl-devlogin-group-sub { font-size: 13px; font-weight: 500; color: var(--k-text-muted); }

/* Persona cards: grouped grid on desktop, a single stacked column under 640px. */
.kl-devlogin-cards {
    display: grid;
    gap: var(--k-space-4);
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}

.kl-shell-main .kl-devlogin-card {
    display: flex;
    flex-direction: column;
    gap: var(--k-space-2);
    margin-block-end: 0; /* the grid gap spaces the cards; drop the family's trailing margin */
    padding: var(--k-space-4);
    transition: border-color var(--k-dur-1) var(--k-ease), box-shadow var(--k-dur-1) var(--k-ease);
}

.kl-shell-main .kl-devlogin-card:hover {
    border-color: var(--k-accent);
    box-shadow: var(--k-elev-2);
}

.kl-devlogin-card-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--k-space-2);
}

.kl-devlogin-card-icon { font-size: 18px; color: var(--k-accent); }

.kl-devlogin-card-name {
    font-family: var(--k-font-display);
    font-size: 15px;
    font-weight: 700;
    color: var(--k-text);
}

.kl-devlogin-role-chip { margin-inline-start: auto; }

.kl-devlogin-card-desc {
    flex-grow: 1; /* pushes the sign-in button to a common baseline across the row */
    margin: 0;
    font-size: 13.5px;
    line-height: 1.55;
    color: var(--k-text-muted);
}

.kl-devlogin-signin { inline-size: 100%; }

/* The Platform (vendor) group: present but visually de-emphasized — a separated, single, narrower card. */
.kl-devlogin-platform {
    border-block-start: 1px solid var(--k-border);
    padding-block-start: var(--k-space-6);
}

.kl-devlogin-platform .kl-devlogin-cards { grid-template-columns: minmax(250px, 420px); }

.kl-devlogin-stamp { margin-block: var(--k-space-6); font-size: 12.5px; color: var(--k-text-muted); }

@media (max-width: 640px) {
    .kl-devlogin-cards { grid-template-columns: 1fr; }
}

/* Gate-login row (AWS basic-auth deployments only): the current gate user + the "Switch gate user"
   ghost action riding under the isolation/gate callout. Hidden entirely when the gate header is
   absent (local dev / LAN), so ungated hosts never see it. */
.kl-devlogin-gate-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--k-space-3);
    margin-block: calc(-1 * var(--k-space-3)) var(--k-space-6);
    max-inline-size: 72ch;
}

.kl-devlogin-gate-user { font-size: 13.5px; color: var(--k-text-muted); }

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   D19-R2 — the /signup SIGNER-SCOPE CHOICE (Components/Signup/SignerScopeChoice.razor).

   WHY IT LIVES HERE AND NOT IN THE RCL: BILL-014 keeps every payment surface off the native head, so a
   seat-purchase control is web-only BY RULING, which is exactly A1's "deliberate web-only" lane
   (Kanine.Web/wwwroot/app.css). It also keeps this clear of the RCL scoped-CSS fingerprint trap.

   NO NEW PALETTE — every colour is an existing --k-* token and the established navy/teal. The boldness is
   spent on STRUCTURE (turning six lines of prose into a comparable pair), not on chrome.

   ⚠ T7: every class below was checked against the shared sheet's 117 [class$="…"] rules BEFORE naming.
   `kl-plan-facts` was the original name for the bullet list and is REJECTED: kanine-design-system.css:1077
   sweeps any kl-*[class$="-facts"] into `display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr))`,
   which would have silently turned a 3-item list into a multi-column grid inside a ~186px card. It is
   `kl-plan-points` for that reason. Verified 0 matching suffix rules: -choice -option -option-name -price
   -points -caveat -seats -pair -legend -neutral -solo -team.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */

.kl-plan-choice {
    /* A fieldset needs its UA border/margin/padding reset before it can be laid out as a plain block. */
    border: 0;
    margin: 0;
    padding: 0;
    min-inline-size: 0; /* fieldset defaults to min-content; without this it refuses to shrink below its text. */
    display: flex;
    flex-direction: column;
    gap: var(--k-space-3);
}

.kl-plan-legend {
    /* Styled, never replaced — it stays a real <legend> so the group keeps its grouping semantics. */
    padding: 0;
    font-family: var(--k-font-display);
    font-size: 15px;
    font-weight: 700;
    line-height: 1.3;
    color: var(--k-text);
}

.kl-plan-pair {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--k-space-3);
}

.kl-plan-option {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--k-space-1);
    padding: var(--k-space-3);
    /* The radio is visually replaced by the card's own selected state, so the card carries the affordance.
       min-block-size keeps every option a full touch target even when its content is short (A6). */
    min-block-size: var(--k-touch);
    background: var(--k-surface);
    border: 1px solid var(--k-border);
    border-radius: var(--k-radius-md);
    cursor: pointer;
}

/* prefers-reduced-motion: the transition is opt-IN, so a reduced-motion user simply gets the instant state. */
@media (prefers-reduced-motion: no-preference) {
    .kl-plan-option { transition: border-color 120ms ease, box-shadow 120ms ease, background-color 120ms ease; }
}

.kl-plan-option--static { cursor: default; }

/* The native radio stays in the accessibility tree and in the tab order — it is NOT display:none, which would
   remove it from both. It is visually collapsed and the card paints the state instead. */
.kl-plan-option-input {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    margin: 0;
    opacity: 0;
    pointer-events: none;
}

.kl-plan-option:has(.kl-plan-option-input:checked) {
    border-color: var(--k-accent);
    background: color-mix(in srgb, var(--k-accent) 6%, var(--k-surface));
    box-shadow: inset 0 0 0 1px var(--k-accent);
}

/* Focus must be visible on the CARD, because the input itself is visually collapsed. :focus-visible only,
   so a mouse click does not leave a ring behind. */
.kl-plan-option:has(.kl-plan-option-input:focus-visible) {
    outline: 2px solid var(--k-accent);
    outline-offset: 2px;
}

.kl-plan-option-name {
    font-family: var(--k-font-display);
    font-size: 15px;
    font-weight: 700;
    line-height: 1.25;
    color: var(--k-text);
}

.kl-plan-price {
    font-size: 13px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--k-accent);
}

.kl-plan-points {
    margin: var(--k-space-1) 0 0;
    padding-inline-start: 1.05em;
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-size: 12.5px;
    line-height: 1.4;
    color: var(--k-text-muted);
}

.kl-plan-caveat {
    margin: var(--k-space-1) 0 0;
    font-size: 11.5px;
    line-height: 1.35;
    color: var(--k-text-muted);
    opacity: 0.85;
}

/* ── the seat count ────────────────────────────────────────────────────────────────────────────────────
   VISIBLE BY DEFAULT, hidden when free is chosen. That polarity is deliberate: a browser with no :has()
   support matches neither rule and therefore shows the field always — harmless, because the radio is
   authoritative and a stale seats value is never read. The reverse polarity would make the paid path
   UNREACHABLE in such a browser, which is the failure this whole design rejected. */
.kl-plan-seats { display: block; }
.kl-plan-choice:has(#signup-scope-me:checked) .kl-plan-seats { display: none; }

/* ── the submit label (A3) ─────────────────────────────────────────────────────────────────────────────
   Three spans, one shown. The NEUTRAL one is the rendered default and the two specific ones start hidden,
   so a browser without :has() shows "Continue" — true in every outcome — rather than a label that could
   contradict where the button goes. With :has(), the label sharpens in BOTH directions with no JavaScript,
   which is what makes it correct with JS disabled. */
.kl-plan-cta-solo, .kl-plan-cta-team { display: none; }
.kl-login-form:has(#signup-scope-me:checked) .kl-plan-cta-neutral,
.kl-login-form:has(#signup-scope-team:checked) .kl-plan-cta-neutral { display: none; }
.kl-login-form:has(#signup-scope-me:checked) .kl-plan-cta-solo { display: inline; }
.kl-login-form:has(#signup-scope-team:checked) .kl-plan-cta-team { display: inline; }

/* Phone: stack the pair. Two ~140px columns cannot hold a readable bullet, and §A6 forbids buying width
   back from the hit target. Stacking is what keeps both options legible and fully tappable. */
@media (max-width: 420px) {
    .kl-plan-pair { grid-template-columns: minmax(0, 1fr); }
}
