/* Open Sans is the family app/frontend loads through next/font, so the login and
   the app it hands off to render in the same type. */
@font-face {
    font-family: 'Open Sans';
    font-style: normal;
    font-weight: 300 800;
    font-display: swap;
    src: url('../fonts/open-sans-variable.woff2') format('woff2');
}

:root {
    /* Brand scale, mirrored from the --fide-orange-* tokens the brand site
       publishes. A shade Bootstrap needs as a bare triplet is declared as the
       triplet, and whoever wants a colour builds it with rgb(); never the
       reverse. CSS cannot read a triplet out of a hex, so a declared hex would
       leave the two notations independent and one palette edit would move the
       fills but not the focus rings. The trailing hex is for eyeballing against
       the brand doc; nothing reads it. */
    --fide-orange-300: #F58A4F;
    --fide-orange-500-rgb: 242, 101, 34;    /* #F26522 */
    --fide-orange-600: #D9531A;
    --fide-orange-700-rgb: 180, 66, 15;     /* #B4420F */
    --fide-orange-700: rgb(var(--fide-orange-700-rgb));

    /* Two roles, split by the contrast a white label needs. Against white,
       orange-500 is 3.15:1 - enough for a border or a filled control (3:1,
       WCAG 1.4.11) and enough for a label that counts as large text (3:1,
       1.4.3), but short of the 4.5:1 that normal-size text owes.
         -fill  the brand shade: the primary button, borders, focus rings,
                checked controls. Its label is -on-fill and must stay large.
         -ink   orange-700, the darkest published shade: normal-size text on
                white, and any fill that carries a normal-size white label.
       The -fill ladder darkens, the way the brand site's own button does: with
       a white label, contrast grows as the fill darkens. */
    --fide-brand-fill-rgb: var(--fide-orange-500-rgb);
    --fide-brand-fill: rgb(var(--fide-brand-fill-rgb));
    --fide-brand-fill-hover: var(--fide-orange-600);
    --fide-brand-fill-active: var(--fide-orange-700);
    --fide-brand-on-fill: #fff;
    --fide-brand-focus: var(--fide-orange-300);
    --fide-brand-ink-rgb: var(--fide-orange-700-rgb);
    --fide-brand-ink: rgb(var(--fide-brand-ink-rgb));
    /* orange-700 is the only published shade that clears 4.5:1 on white, so a
       hover state for text has to be derived below the scale. */
    --fide-brand-ink-hover-rgb: 154, 54, 9;     /* #9A3609 */
    --fide-brand-ink-hover: rgb(var(--fide-brand-ink-hover-rgb));

    /* Neutrals, from Bootstrap's own palette. Not brand: they carry the
       affordances that must not compete with the primary action. -neutral is for
       icon glyphs, -neutral-strong for the secondary button and hover states.
       Both clear their own threshold, which the values they replaced did not. */
    --fide-neutral: #6c757d;                    /* 4.69:1 on white */
    --fide-neutral-strong-rgb: 73, 80, 87;      /* #495057 */
    --fide-neutral-strong: rgb(var(--fide-neutral-strong-rgb));

    --bs-primary: var(--fide-brand-fill);
    --bs-primary-rgb: var(--fide-brand-fill-rgb);
    --bs-body-font-family: 'Open Sans', system-ui, -apple-system, sans-serif;
    --bs-body-color: #1a1a1a;
    --bs-border-color: #e6e8ef;
    --bs-border-radius: 0.5rem;
    --bs-border-radius-sm: 0.375rem;
    --bs-border-radius-lg: 0.75rem;
    /* Bootstrap colours <a> from the -rgb pair; the colour pair reaches only
       .btn-link, .nav and .pagination, none of which this theme renders. Both
       are set so the ink role governs the links whichever one is read. */
    --bs-link-color: var(--fide-brand-ink);
    --bs-link-color-rgb: var(--fide-brand-ink-rgb);
    --bs-link-hover-color: var(--fide-brand-ink-hover);
    --bs-link-hover-color-rgb: var(--fide-brand-ink-hover-rgb);
}

body {
    font-family: var(--bs-body-font-family);
    /* One soft neutral glow rising from the bottom edge; the flat #f0f2f5 is the
       fallback and what paints outside the glow. */
    background: radial-gradient(900px 420px at 50% 110%, rgba(26, 26, 26, 0.07), rgba(26, 26, 26, 0) 70%), #f0f2f5;
    /* Logo + card top-anchor at a fixed offset (the wrapper's margin-top), so the logo
       holds the same Y across views of different heights instead of jumping the way
       centring a variable-height block would. min-height (not height) lets a tall view
       (TOTP set-up) grow past the viewport and scroll; dvh keeps the mobile URL bar out
       of the maths, vh is the fallback. */
    min-height: 100vh;
    min-height: 100dvh;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    padding: 1.5rem 0;
    /* The "remember me" checkbox is a bare <input type="checkbox">, so this is
       the only thing that reaches it. */
    accent-color: var(--fide-brand-fill);
}

/* 470px card plus the px-3 gutters kcLoginClass carries. */
.container-login {
    width: 100%;
    max-width: 31.375rem;
    margin-top: clamp(2rem, 9vh, 7rem);
    margin-bottom: auto;
}

/* The logo is the brand, not the task. It takes 64% of the card's width on every
   tier - the idiomatic band for a horizontal wordmark over a sign-in card is 50-70%,
   never edge to edge - so the proportion holds by itself when the card narrows on a
   phone or widens on a large monitor. The cap is the number the fold pays for: on
   the notebook tier 300px is ~98px tall and the submit still clears 650px. */
#kc-header-wrapper {
    padding-bottom: 1.5rem;
}

#kc-header-wrapper img {
    display: block;
    margin: 0 auto;
    width: 64%;
    max-width: 300px;
}

.card {
    --bs-card-border-color: var(--bs-border-color);
    --bs-card-border-radius: 0.875rem;
    --bs-card-inner-border-radius: 0.875rem;
    box-shadow: 0 18px 50px rgba(20, 24, 40, 0.10);
}

.card-body {
    padding: 1.25rem 2.5rem 1.5rem;
}

/* A view that opens with a subtitle takes a smaller top padding: the subtitle sits
   tight under the title and carries its own spacing. `:has()` targets the condition
   itself (a card that contains a subtitle), so any new subtitle view is covered with
   nothing to add. It replaced a per-`data-page-id` list, which was a maintenance trap:
   the id doubles the prefix (the reset page is `login-login-reset-password`, since
   pageId is the template filename), easy to get wrong when adding a view. */
.card-body:has(.kc-page-subtitle) {
    padding-top: 0.5rem;
}

/* One heading rule for every auth page (kcPageTitleClass): login, reset, OTP and
   update-password share it, so the same role never renders two ways. The login page's
   only difference is the inline brand accent on one word (.text-brand below). */
.kc-page-title {
    margin: 0;
    padding: 1.75rem 2.5rem 0;
    font-size: 1.5rem;
    font-weight: 600;
    line-height: 1.25;
    text-wrap: pretty;
}

/* Brand shade on the title's one branded word (login only). At the 24px title size it
   is large text, where orange-on-white 3.15:1 clears WCAG 1.4.3. Never at body size. */
.text-brand {
    color: var(--fide-brand-fill);
}

.kc-page-subtitle {
    margin: 0.5rem 0 1.25rem;
    color: var(--fide-neutral);
    font-size: 0.9375rem;
    line-height: 1.5;
    text-wrap: pretty;
}

.form-label {
    margin-bottom: 0.375rem;
    font-size: 0.875rem;
    font-weight: 600;
}

/* 46px controls: 16px text, 10px vertical padding, 1px borders. */
.form-control {
    padding: 0.625rem 0.875rem;
}

/* "Forgot your password?" right under the password field, then "keep me signed
   in" next to the submit it modifies. Stacked on purpose: side by side the two
   labels do not fit the 390px the card leaves, and wrapping put them in the wrong
   order. */
.kc-form-setting {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.375rem;
}

.checkbox label {
    display: flex;
    align-items: center;
    gap: 0.625rem;
}

.checkbox input[type="checkbox"] {
    width: 1.125rem;
    height: 1.125rem;
    margin: 0;
}

/* The single "what changed" pointer under the card (template.ftl). */
.kc-whats-new {
    margin: 1.25rem 0 0;
    text-align: center;
    font-size: 0.875rem;
    color: var(--fide-neutral);
}

/* Body copy of every base-theme template we do NOT override (error, page-expired,
   logout-confirm, verify-email). Branding them costs this rule instead of a copy of each
   FTL - see auth/keycloak/CLAUDE.md before adding one. */
.instruction {
    margin-bottom: 1rem;
    color: var(--bs-body-color);
}

/* Paired actions split the row evenly. */
@media (min-width: 576px) {
    #kc-form-buttons > .btn {
        flex: 1 1 0;
    }
}

.input-error {
    display: block;
    color: #dc3545;
    margin-top: .25rem;
    font-size: 0.8125rem;
    width: 100%;
}

/* Field help / hint sits in the same small, input-adjacent tier as the error (13px),
   muted rather than red: a hint annotates the field, it does not compete with the 16px
   input value. `kcInputHelpClass` maps here; multi-line body copy uses `.instruction`. */
.kc-input-help {
    font-size: 0.8125rem;
    color: var(--fide-neutral);
}

/* 48px control: 17px label, 10px vertical padding, 1px borders. Radius follows
   app/frontend's Button (src/components/ui/button.tsx). */
.btn {
    --bs-btn-font-weight: 600;
    --bs-btn-font-size: 1.0625rem;
    --bs-btn-padding-y: 0.625rem;
    --bs-btn-padding-x: 1rem;
    --bs-btn-border-radius: 0.375rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.625rem;
    transition-duration: .2s;
}

.btn .btn-icon {
    flex: none;
}

/* The primary action carries the brand orange fill with a white label. White on
   the fill is 3.16:1: it clears WCAG 1.4.3 for large text (3:1) but not the 4.5:1
   of body text, so the label must stay at the large button size, never shrink to
   body. The sub-4.5:1 fill is an accepted brand tradeoff, not a defect to fix
   back to a dark fill. */
.btn-primary {
    --bs-btn-bg: var(--fide-brand-fill);
    --bs-btn-hover-bg: var(--fide-brand-fill-hover);
    --bs-btn-active-bg: var(--fide-brand-fill-active);
    --bs-btn-border-color: var(--fide-brand-fill);
    --bs-btn-hover-border-color: var(--fide-brand-fill-hover);
    --bs-btn-active-border-color: var(--fide-brand-fill-active);
    /* Bootstrap leaves the disabled and focus states on its own blue, and both
       are reachable: login.ftl disables the button on submit, and Tab draws the
       focus ring. */
    --bs-btn-disabled-bg: var(--fide-brand-fill);
    --bs-btn-disabled-border-color: var(--fide-brand-fill);
    --bs-btn-disabled-color: var(--fide-brand-on-fill);
    --bs-btn-focus-shadow-rgb: var(--fide-brand-fill-rgb);
    --bs-btn-color: var(--fide-brand-on-fill);
    --bs-btn-hover-color: var(--fide-brand-on-fill);
    --bs-btn-active-color: var(--fide-brand-on-fill);
}

.btn-outline-primary {
    /* Its border carries the brand shade; the label is orange on white and its
       filled states carry a white label at the body size, so both take the ink
       role rather than -fill, which would leave them at 3.15:1. */
    --bs-btn-color: var(--fide-brand-ink);
    --bs-btn-border-color: var(--fide-brand-fill);
    --bs-btn-hover-bg: var(--fide-brand-ink);
    --bs-btn-hover-border-color: var(--fide-brand-ink);
    --bs-btn-hover-color: var(--fide-brand-on-fill);
    --bs-btn-active-bg: var(--fide-brand-ink-hover);
    --bs-btn-active-border-color: var(--fide-brand-ink-hover);
    --bs-btn-active-color: var(--fide-brand-on-fill);
    --bs-btn-focus-shadow-rgb: var(--fide-brand-fill-rgb);
}

/* The only secondary action the theme renders (doCancel on the two
   app-initiated-action views). Bootstrap's own secondary is #6c757d, which is
   4.69:1 on white - 0.19 above the minimum, and grey enough next to a filled
   brand button to read as disabled. The darker neutral of the same palette is
   8.18:1 and reads as an action that is available but not the one to take. It
   stays neutral rather than an outline of the brand shade on purpose: a
   saturated secondary puts two saturated buttons side by side and neither the
   designer nor the user can tell which one matters more. */
.btn-outline-secondary {
    --bs-btn-color: var(--fide-neutral-strong);
    --bs-btn-border-color: var(--fide-neutral-strong);
    --bs-btn-hover-bg: var(--fide-neutral-strong);
    --bs-btn-hover-border-color: var(--fide-neutral-strong);
    --bs-btn-active-bg: var(--fide-neutral-strong);
    --bs-btn-active-border-color: var(--fide-neutral-strong);
    --bs-btn-disabled-color: var(--fide-neutral-strong);
    --bs-btn-disabled-border-color: var(--fide-neutral-strong);
    --bs-btn-focus-shadow-rgb: var(--fide-neutral-strong-rgb);
}

.pointer {
    cursor: pointer;
}

.form-control:focus,
.form-check-input:focus {
    border-color: var(--fide-brand-focus);
    box-shadow: 0 0 0 .25rem rgba(var(--fide-brand-fill-rgb), .25);
}

/* Radios of the OTP authenticator picker (kcLoginOTPListInputClass). */
.form-check-input:checked {
    background-color: var(--fide-brand-fill);
    border-color: var(--fide-brand-fill);
}

.input-group > .input-group-text,
.input-group > .btn.input-group-text {
    background-color: #fff;
    /* The glyph is the only visual affordance of the show/hide-password toggle,
       so it owes 3:1 (WCAG 1.4.11). The #9aa0ac this replaces was 2.63:1. */
    color: var(--fide-neutral);
    border-color: var(--bs-border-color);
    box-shadow: none;
}

.input-group > .btn.input-group-text:hover,
.input-group > .btn.input-group-text:focus {
    background-color: #f8f9fa;
    color: var(--fide-neutral-strong);
    border-color: var(--bs-border-color);
    outline: none;
    box-shadow: none;
}

.input-group > .form-control:focus ~ .input-group-text,
.input-group > .form-control:focus ~ .btn.input-group-text {
    border-color: var(--fide-brand-focus);
}

/* ---------------------------------------------------------------------------
   Viewport tiers. Controls keep their 46/48px everywhere; only the logo, the
   paddings and the type scale move. Kept at the end of the file so no later
   rule of equal specificity overrides them by accident.
   --------------------------------------------------------------------------- */

/* Phones. The 2.5rem side padding of the card leaves ~280px of line on a 360px
   screen. The logo needs nothing here: 64% of the narrower card is ~230px. */
@media (max-width: 575.98px) {
    body {
        padding: 1rem 0;
    }

    /* Tighter top-anchor on phones: still fixed across views, but it gives the form
       back the vertical room the 9vh offset would spend above the logo. */
    .container-login {
        margin-top: 1.5rem;
    }

    #kc-header-wrapper {
        padding-bottom: 1rem;
    }

    .kc-page-title {
        padding-left: 1.25rem;
        padding-right: 1.25rem;
    }

    .card-body {
        padding-left: 1.25rem;
        padding-right: 1.25rem;
    }

    .kc-whats-new {
        margin-bottom: 0.75rem;
    }
}

/* Laptops. The submit is the only action on the page and has to be visible
   without scrolling on the 600-650px a 1366x768 or 1280x720 leaves after the
   browser chrome; paddings and gaps tighten, the logo keeps its 64% (the ratio was
   settled by a five-role vote against 51/81/100%, #921). The ceiling is 820 so that 1536x864 at 125% (~760-775px,
   depending on the bookmarks bar) lands on this side whatever the bar does,
   instead of flipping designs with it. min-width keeps phones out: they have
   their own tier above. */
@media (min-width: 576px) and (max-height: 820px) {
    body {
        padding: 1.5rem 0;
    }

    #kc-header-wrapper {
        padding-bottom: 1rem;
    }

    .kc-page-title {
        padding-top: 1.25rem;
    }

    .kc-page-subtitle {
        margin: 0.375rem 0 0.875rem;
    }

    #kc-content-wrapper .mb-3 {
        margin-bottom: 0.75rem;
    }

    .card-body {
        padding-bottom: 1.25rem;
    }

    .kc-whats-new {
        margin-top: 0.75rem;
    }
}

/* Large monitors. At 1920 and 2560 the 470px card reads as a floating dialog: it
   widens a step and the type follows. Vertical position stays the shared top-anchor. */
@media (min-width: 1600px) and (min-height: 900px) {
    .container-login {
        max-width: 34rem;
    }

    #kc-header-wrapper {
        padding-bottom: 2rem;
    }

    #kc-header-wrapper img {
        max-width: 340px;
    }

    .kc-page-subtitle {
        font-size: 1rem;
    }
}
