:root {
    --opfa-accent: #0d6efd;
    --opfa-accent-contrast: #ffffff;

    --opfa-danger: #dc3545;
    /* the %23 hex below is baked into the svg: restate it when --opfa-danger changes */
    --opfa-icon-invalid: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");

    /* white, like bootstrap's own glyph: restate the whole url to recolour it */
    --opfa-icon-check: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e");

    --opfa-accent-hover: color-mix(in srgb, var(--opfa-accent) 85%, #000);
    --opfa-accent-subtle: color-mix(in srgb, var(--opfa-accent) 10%, transparent);

    --opfa-elevation: 0 10px 18px -5px #7090b033;
    /* the raised rows of the social list and the organization chooser */
    --opfa-social-bg: var(--opfa-surface-bg);

    --opfa-checkbox-size: 1.25em;
    --opfa-checkbox-gap: 0.5em;

    --opfa-font-family: "Open Sans", Helvetica, Arial, sans-serif;
    --opfa-heading-color: #333333;

    /* the logo goes in the background; themes using one hide the realm name over it */
    --opfa-header-background: none;
    --opfa-header-text: block;

    --opfa-body-bg: var(--bs-body-bg);

    /* the login card. Transparent and square by default, which is the stock look; a theme gives
       it a surface with these, and a min-height when it wants the actions pinned to its bottom
       rather than sitting under the content (on a phone the viewport already does that). Set
       them inside a media query to have any of it apply on one viewport only. */
    --opfa-card-border-color: var(--opfa-accent);
    --opfa-card-bg: transparent;
    --opfa-card-radius: 0;
    --opfa-card-shadow: none;
    --opfa-card-max-width: 400px;
    --opfa-card-padding: 15px;
    --opfa-card-min-height: auto;

    /* bootstrap compiles .btn-primary as literal hexes and reads --bs-primary nowhere */
    --opfa-primary: var(--opfa-accent);
    --opfa-primary-contrast: var(--opfa-accent-contrast);
    --opfa-primary-border: var(--opfa-primary);
    --opfa-primary-hover: color-mix(in srgb, var(--opfa-primary) 85%, #000);
    --opfa-primary-active: color-mix(in srgb, var(--opfa-primary) 80%, #000);
    --opfa-primary-disabled: var(--opfa-primary);

    /* secondary button: bootstrap's own grey by default, and the same derivation, so a theme
       that sets nothing here renders exactly as bootstrap does */
    --opfa-secondary: #6c757d;
    --opfa-secondary-contrast: #ffffff;
    --opfa-secondary-border: var(--opfa-secondary);
    --opfa-secondary-hover: color-mix(in srgb, var(--opfa-secondary) 85%, #000);
    --opfa-secondary-active: color-mix(in srgb, var(--opfa-secondary) 80%, #000);
    --opfa-secondary-disabled: var(--opfa-secondary);

    /* what bootstrap paints its fields, menus and raised rows with, and the text on them */
    --opfa-surface-bg: #ffffff;
    --opfa-body-color: #212529;

    /* cards=true */
    --opfa-left-background: none;
    --opfa-cards-inset: 1.5em;

    --bs-body-font-family: var(--opfa-font-family);
    --bs-heading-color: var(--opfa-heading-color);
}

/* the two bootstrap colours the tokens above drive. Guarded rather than declared in :root,
   which would out-specify bootstrap's own [data-bs-theme=dark] block and pin the theme to
   light: this way dark mode still reaches them. */
:root:not([data-bs-theme="dark"]) {
    --bs-body-bg: var(--opfa-surface-bg);
    --bs-body-color: var(--opfa-body-color);
}


body {
    height: 100%;
    width: 100%;
    background: var(--opfa-body-bg);
}

.keycloak-container {
    --bs-gutter-x: 1.5rem;
    --bs-gutter-y: 0;
    width: 100%;
    height: 100%;
    margin-right: auto;
    margin-left: auto;
    display: flex;
    flex-direction: column;

    @media (min-width: 576px) {
        max-width: 540px;
    }
}

.keycloak-header {
    font-size: 29px;
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 3px;
    line-height: 1.2em;
    color: var(--bs-heading-color);
    text-align: center;
    margin: 0 auto;
    background: var(--opfa-header-background);
}

#kc-header-wrapper {
    display: var(--opfa-header-text);
}

.keycloak-form-header {
    h1 {
        line-height: 1.2em;
        font-size: 26px;
        text-align: center;
        margin-bottom: 15px;
    }
}

#kc-content-wrapper {
    display: flex;
    flex-direction: column;

    > #kc-page-subtitle {
        order: -1;
    }
}

#kc-page-subtitle {
    font-size: 1rem;
    font-weight: 400;
    text-align: center;
    margin-bottom: 15px;
}

#kc-page-title:empty,
#kc-page-subtitle:empty {
    display: none;
}

/* wrapper div and inner span both carry .subtitle: size and colour go on the span */
.subtitle {
    text-align: right;
}

span.subtitle {
    font-size: 0.875em;
    color: var(--bs-secondary-color);
}

.keycloak-card {
    border-top: 4px solid;
    border-color: var(--opfa-card-border-color);
    border-radius: var(--opfa-card-radius);
    background: var(--opfa-card-bg);
    box-shadow: var(--opfa-card-shadow);
    width: 100%;
    max-width: var(--opfa-card-max-width);
    min-height: var(--opfa-card-min-height);
    padding: var(--opfa-card-padding);
    margin: 0 auto;
    position: relative;
    display: flex;
    flex-direction: column;

    /* the chain that leaves the slack above the action row, so the actions sit at the bottom of
       a card taller than its content: the viewport on a phone, a min-height on a desktop. With
       neither there is no slack and nothing moves - except that flex does not collapse margins,
       so the gap above a row grows by its own padding on the pages that had one. */
    #kc-content,
    #kc-content-wrapper,
    #kc-form,
    #kc-form-wrapper,
    #kc-form-webauthn,
    .content-area,
    form,
    /* a group wrapping a list of buttons is a chooser, not an action row */
    .form-group:has(input[type=submit], input[type=button], button:not(.input-group > button)):not(:has(ul)) {
        display: flex;
        flex-direction: column;
        flex: 1;
    }

    .form-group:has(input[type=submit], input[type=button], button:not(.input-group > button)):not(:has(ul)),
    .form-actions:has(input[type=submit], input[type=button], button:not(.input-group > button)):not(:has(> *:not(.btn, input[type="hidden"]))),
    /* a button-only container claiming free space floats a split pair mid-card */
    form:has(> .btn):not(:has(> *:not(.btn, input[type="hidden"]))),
    #kc-form-buttons {
        flex: 0;
        margin-top: auto;
        /* the gap to the block above, which an auto margin cannot give once the slack is gone */
        padding-top: 1rem;
    }

    /* ...unless what sits above is the other half of a split pair */
    .btn + form:has(> .btn):not(:has(> *:not(.btn, input[type="hidden"]))) {
        padding-top: 0;
    }

    /* the chain above would make a column of an action row; the margin is restated because
       :has(> .btn ~ .btn) out-specifies the pin */
    form.form-actions:not(:has(> *:not(.btn, input[type="hidden"]))),
    :is(form, .form-group):has(> .btn ~ .btn):not(:has(> *:not(.btn, input[type="hidden"]))) {
        flex-direction: row;
        margin-top: auto;
    }

    /* the card fills a phone: there the viewport is the card */
    @media (hover: none), (max-width: 767.98px) {
        flex: 1;
    }
}

.form-label {
    margin-bottom: 0;
}

.form-control {
    padding: 8px 12px;

    &:focus {
        border-color: var(--bs-border-color);
        box-shadow: none;
    }
}

.input-group {
    > input {
        border-right: 0;
    }

    > .btn {
        color: var(--opfa-accent);
        border: 1px solid var(--bs-border-color);
        border-left: 0;

        &:active {
            color: var(--opfa-accent);
            border-color: var(--bs-border-color);
        }
    }
}

.form-group {
    margin-bottom: 1rem;
}

.form-group:has([aria-invalid="true"]) {

    :is(.form-control[aria-invalid="true"], .input-group > .btn) {
        border-color: var(--opfa-danger);
    }

    .form-control[aria-invalid="true"] {
        padding-right: calc(1.5em + .75rem);
        background-image: var(--opfa-icon-invalid);
        background-repeat: no-repeat;
        background-position: right calc(.375em + .1875rem) center;
        background-size: calc(.75em + .375rem) calc(.75em + .375rem);
    }

    .invalid-feedback {
        --bs-form-invalid-color: var(--opfa-danger);
        display: block;
    }
}

/* bootstrap locks control, gutter and offset together: derive all three from the size
   (at 1em these reproduce bootstrap) */
.form-check,
.checkbox {
    display: block;
    min-height: max(1.5rem, var(--opfa-checkbox-size));
    padding-left: calc(var(--opfa-checkbox-size) + var(--opfa-checkbox-gap));
    margin-bottom: 0.125rem;
}

/* (0,2,1): bootstrap's own `.form-check .form-check-input` is (0,2,0) */
:is(.form-check, .checkbox) :is(input[type="checkbox"], input[type="radio"]) {
    float: left;
    width: var(--opfa-checkbox-size);
    height: var(--opfa-checkbox-size);
    margin-left: calc(-1 * (var(--opfa-checkbox-size) + var(--opfa-checkbox-gap)));
    margin-top: calc((1.5em - var(--opfa-checkbox-size)) / 2);
}

/* register's terms box and the recovery-codes confirmation ship no wrapper for the gutter */
input.form-check-input[type="checkbox"]:not(:is(.form-check, .checkbox) *) {
    float: left;
    width: var(--opfa-checkbox-size);
    height: var(--opfa-checkbox-size);
    margin-top: calc((1.5em - var(--opfa-checkbox-size)) / 2);
    margin-right: var(--opfa-checkbox-gap);

    /* its own block beside the float, so the box sits on the first line and a second line
       indents - the geometry the wrapped flavours get from padding */
    + label {
        display: block;
        overflow: hidden;
        margin-bottom: 0.5rem;
    }
}

/* base pages hardcode a classless <input type=checkbox> in .checkbox, and a macro can forget
   .form-check-input: skin both, the rule is byte-identical to bootstrap's */
:is(.form-check, .checkbox) :where(input[type="checkbox"]),
input.form-check-input[type="checkbox"] {
    appearance: none;
    vertical-align: top;
    background-color: var(--bs-body-bg);
    background-repeat: no-repeat;
    background-position: center;
    background-size: contain;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.25em;
    print-color-adjust: exact;

    &:checked {
        background-color: var(--opfa-accent);
        border-color: var(--opfa-accent);
        background-image: var(--opfa-icon-check);
    }
}

.btn-primary {
    --bs-btn-color: var(--opfa-primary-contrast);
    --bs-btn-bg: var(--opfa-primary);
    --bs-btn-border-color: var(--opfa-primary-border);
    --bs-btn-hover-color: var(--opfa-primary-contrast);
    --bs-btn-hover-bg: var(--opfa-primary-hover);
    --bs-btn-hover-border-color: var(--opfa-primary-hover);
    --bs-btn-active-color: var(--opfa-primary-contrast);
    --bs-btn-active-bg: var(--opfa-primary-active);
    --bs-btn-active-border-color: var(--opfa-primary-active);
    --bs-btn-disabled-color: var(--opfa-primary-contrast);
    --bs-btn-disabled-bg: var(--opfa-primary-disabled);
    --bs-btn-disabled-border-color: var(--opfa-primary-disabled);
}

/* 
   an action row, in the four shapes upstream builds one; the gate keeps a container that
   also holds fields out of it. flex-column opts a row out. the recovery-codes warning 
   is patternfly markup: an icon that resolves to nothing, and a heading that is an 
   h4 inside an alert 
*/
.alert:has(.pf-c-alert__description) {
    > .pf-c-alert__icon {
        display: none;
    }

    > .pf-c-alert__title {
        font-size: 1rem;
        font-weight: 600;
        margin-bottom: 0.5rem;
        color: var(--bs-warning-text-emphasis);        
    }

    p:last-child {
        margin-bottom: 0;
    }
}

.keycloak-recovery-codes-list {
    font-family: var(--bs-font-monospace);
    font-size: 0.8125rem;
    > li > span:first-child {
        color: var(--bs-secondary-color);
    }
}

/* upstream hardcodes patternfly classes here, so no kc*Class reaches them */
.keycloak-recovery-codes-actions {
    justify-content: center;
    gap: 1rem;
    margin: 0.75rem 0 1.25rem;

    > button {
        padding: 0.25rem 0.5rem;
        border: 0;
        background: none;
        color: var(--opfa-accent);
        text-decoration: none;

        &:hover,
        &:focus-visible {
            color: var(--opfa-accent-hover);
            text-decoration: underline;
        }

        > i[class^="pficon"] {
            display: none;
        }
    }
}

/* upstream's section divider inside a field group; a floated label would land on it */
.form-group > hr {
    display: none;
}

/* not an mt-2 in kcButtonBlockClass: utilities carry !important, and the row rule below
   could not take the margin back off a pair sharing a line */
.keycloak-button-block {
    margin-top: 0.5rem;
}

/* upstream does not always give a stacked pair the block class */
.btn + .btn {
    margin-top: 0.5rem;
}

/* a container mixing fields in with its buttons cannot be a row: a line each instead */
:is(form, .form-group):has(> .btn ~ .btn):has(> *:not(.btn, input[type="hidden"])) {
    /* the pin's floor belongs above the buttons, not above the field this box happens to start
       with, where it only spaces that field off whatever precedes the box */
    padding-top: 0;

    > .btn {
        display: block;
        width: 100%;
        margin-top: 0.5rem;
    }

    > .btn:not(.btn + .btn) {
        margin-top: 1rem;
    }
}

.btn-secondary {
    --bs-btn-color: var(--opfa-secondary-contrast);
    --bs-btn-bg: var(--opfa-secondary);
    --bs-btn-border-color: var(--opfa-secondary-border);
    --bs-btn-hover-color: var(--opfa-secondary-contrast);
    --bs-btn-hover-bg: var(--opfa-secondary-hover);
    --bs-btn-hover-border-color: var(--opfa-secondary-hover);
    --bs-btn-active-color: var(--opfa-secondary-contrast);
    --bs-btn-active-bg: var(--opfa-secondary-active);
    --bs-btn-active-border-color: var(--opfa-secondary-active);
    --bs-btn-disabled-color: var(--opfa-secondary-contrast);
    --bs-btn-disabled-bg: var(--opfa-secondary-disabled);
    --bs-btn-disabled-border-color: var(--opfa-secondary-disabled);
}

.btn-outline-secondary {
    --bs-btn-color: var(--opfa-secondary);
    --bs-btn-border-color: var(--opfa-secondary-border);
    --bs-btn-hover-color: var(--opfa-secondary-contrast);
    --bs-btn-hover-bg: var(--opfa-secondary);
    --bs-btn-hover-border-color: var(--opfa-secondary-border);
    --bs-btn-active-color: var(--opfa-secondary-contrast);
    --bs-btn-active-bg: var(--opfa-secondary-active);
    --bs-btn-active-border-color: var(--opfa-secondary-active);
    --bs-btn-disabled-color: var(--opfa-secondary);
    --bs-btn-disabled-border-color: var(--opfa-secondary-disabled);
}

#kc-form-buttons,
.form-actions:not(:has(> *:not(.btn, input[type="hidden"]))),
:is(form, .form-group):has(> .btn ~ .btn):not(:has(> *:not(.btn, input[type="hidden"]))) {
    display: flex;
    flex-direction: row;
    gap: 1rem;

    > * {
        flex: 1;
    }

    /* the row owns the gap above, and a pair must not be offset against itself */
    > .btn {
        margin-top: 0;
    }
}

#kc-username {
    display: flex;
    gap: 1rem;
    justify-content: space-between;
}

#kc-registration {
    text-align: center;
}

#kc-info {
    margin: 1rem 0 0;
}

.keycloak-locale-main {
    display: flex;
    justify-content: flex-end;
}

#kc-locale-dropdown {
    position: relative;

    > button {
        background: none;
        border: 0;
        padding: 0 0 .5rem;
        color: var(--opfa-accent);
        font-size: .9rem;
        text-decoration: underline;

        &:hover,
        &:focus-visible {
            color: var(--opfa-accent-hover);
        }
    }

    .keycloak-locale-list {
        display: none;
        position: absolute;
        right: 0;
        top: 100%;
        z-index: 1000;
        min-width: 8rem;
        margin: 0;
        padding: .5rem 0;
        list-style: none;
        background: var(--bs-body-bg);
        border: 1px solid var(--bs-border-color);
        border-radius: var(--bs-border-radius);
        box-shadow: var(--opfa-elevation);

        .keycloak-locale-item {
            display: block;
            padding: .25rem 1rem;
            color: var(--bs-body-color);
            text-decoration: none;
            white-space: nowrap;

            &:hover,
            &:focus {
                background: var(--opfa-accent-subtle);
                color: var(--opfa-accent-hover);
            }
        }
    }

    &:focus-within .keycloak-locale-list,
    &:hover .keycloak-locale-list {
        display: block;
    }
}

/* otp tiles */

.keycloak-otp-tile {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .75rem 1rem;
    margin-bottom: .5rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    cursor: pointer;

    .keycloak-otp-tile-title {
        font-weight: 600;
    }
}

#kc-otp-reset-form,
#kc-otp-login-form {

    /* not display:none: the radio must stay focusable and arrow-key operable */
    input[type="radio"] {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
        border: 0;
    }

    input:checked + .keycloak-otp-tile {
        border-color: var(--opfa-accent);
    }

    input:focus-visible + .keycloak-otp-tile {
        border-color: var(--opfa-accent);
        outline: 2px solid var(--opfa-accent);
        outline-offset: 1px;
    }
}

/* select-organization builds its buttons from the same kcFormSocialAccount* properties */
#kc-social-providers,
#kc-user-organizations {
    > hr {
        display: none;
    }

    > h2 {
        text-align: center;
        margin: 22px auto;
        font-weight: 400;
    }

    > ul {
        padding: 0;
        display: flex;
        flex-direction: column;
        align-items: center;

        li {
            display: contents;
        }

        :is(a, button) {
            background: var(--opfa-social-bg);
            border: none;
            border-radius: 7px;
            box-shadow: var(--opfa-elevation);
            margin-bottom: 12px;
            padding: 9px 13px;
            text-align: left;
            font-size: 18px;

            i {
                margin-right: 30px;
                font-size: 23px;
            }
        }
    }
}

.alert-error {
    --bs-alert-color: var(--bs-danger-text-emphasis);
    --bs-alert-bg: var(--bs-danger-bg-subtle);
    --bs-alert-border-color: var(--bs-danger-border-subtle);
    --bs-alert-link-color: var(--bs-danger-text-emphasis);
}

body:has(> .left) {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto 1fr;
    align-items: stretch;

    @media (max-width: 991px) {
        display: block;
    }

    > .left {
        grid-column: 1;
        grid-row: 1 / 3;
        display: flex;
        flex-direction: column;
        justify-content: flex-end;
        background: var(--opfa-left-background);

        @media (max-width: 991px) {
            display: none;
        }
    }

    > .keycloak-container {
        grid-column: 2;
        width: min(100% - 2 * var(--opfa-cards-inset), 540px);

        @media (max-width: 991px) {
            width: min(100%, 540px);
        }
    }

    > .footer-card {
        grid-column: 2;
        margin: auto var(--opfa-cards-inset) 40px var(--opfa-cards-inset);

        @media (max-width: 991px) {
            margin-left: 0;
            margin-right: 0;
        }
    }
}

[data-page-id=login-login-recovery-authn-code-config] {
    .alert-warning {
        flex-direction: column;

        h4 {
            font-size: 1.2rem;
        }
    }
}
