/*
 * Troy Web IdentityServer.
 *
 * Layered on top of Bootstrap 4.5.3, which stays loaded so the pages that have not been
 * restyled keep working. There is no SCSS build step in this project -- this file is the
 * source and it is what ships. The page CSP is `default-src 'self'` with no style-src, so
 * everything must live here: no inline <style>, no style="" attributes, no webfonts.
 */

:root {
    /*
     * The Troy Web brand orange is #e77436, but it measures only 3.02:1 on white -- fine for a
     * non-text mark, and a WCAG AA failure for text or a button fill. So the brand appears here
     * only as this darkened form, at 5.18:1 on white. Do not swap #e77436 back in for anything
     * carrying text.
     */
    --tw-brand-strong: #c2410c;
    --tw-brand-strong-hover: #9a3412;

    --tw-page-bg: #f9fafb;
    --tw-surface: #ffffff;
    --tw-surface-sunken: #f3f4f6;
    --tw-border: #e5e7eb;
    --tw-input-border: #d1d5dc;

    /* 17.6:1, 10.3:1 and 7.56:1 on --tw-surface. */
    --tw-text-strong: #101828;
    --tw-text: #364153;
    --tw-text-muted: #4a5565;

    --tw-danger: #c10007;
    --tw-danger-hover: #9a0006;
    --tw-danger-tint: #fef2f2;
    --tw-danger-border: #fecaca;
    --tw-success: #0a6b41;

    --tw-radius: 12px;
    --tw-radius-sm: 8px;
    --tw-card-shadow: 0 1px 2px rgba(16, 24, 40, 0.06), 0 8px 24px rgba(16, 24, 40, 0.06);
}

body {
    background-color: var(--tw-page-bg);
    color: var(--tw-text);
    display: flex;
    flex-direction: column;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    font-size: 15px;
    line-height: 1.5;
    min-height: 100dvh;
    -webkit-font-smoothing: antialiased;
}

a {
    color: var(--tw-brand-strong);
}

a:hover,
a:focus {
    color: var(--tw-brand-strong-hover);
}

/* One visible focus treatment for every interactive element on these pages. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
summary:focus-visible {
    outline: 2px solid var(--tw-brand-strong);
    outline-offset: 2px;
    border-radius: 3px;
}

/* ---------------------------------------------------------------- header */

.site-header {
    background-color: var(--tw-surface);
    border-bottom: 1px solid var(--tw-border);
}

.site-header__inner {
    align-items: center;
    display: flex;
    gap: 16px;
    justify-content: space-between;
    padding: 14px 20px;
}

.site-header__brand,
.site-header__brand:hover,
.site-header__brand:focus {
    align-items: center;
    color: var(--tw-text-strong);
    display: inline-flex;
    font-size: 15px;
    font-weight: 600;
    gap: 10px;
    letter-spacing: 0.01em;
    text-decoration: none;
}

.site-header__mark {
    height: 28px;
    width: auto;
}

.site-header__account {
    align-items: center;
    display: flex;
    font-size: 13px;
    gap: 10px;
    min-width: 0;
}

.site-header__avatar {
    border-radius: 50%;
    flex: none;
    height: 24px;
    object-fit: cover;
    width: 24px;
}

.site-header__email {
    color: var(--tw-text-strong);
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ---------------------------------------------------------------- shell */

.body-container {
    display: flex;
    flex: 1 0 auto;
    flex-direction: column;
}

.auth-shell {
    display: flex;
    justify-content: center;
    padding: 48px 0 64px;
}

/*
 * Only the short cards opt in to sitting mid-viewport; long ones (connected apps) keep flowing
 * from the top. The auto margins collapse to zero once a card outgrows the viewport, so tall
 * content scrolls rather than clips.
 */
.auth-shell--centered {
    flex: 1 0 auto;
    padding: 32px 0;
}

.auth-shell--centered .auth-card {
    margin: auto;
}

.auth-card {
    background-color: var(--tw-surface);
    border: 1px solid var(--tw-border);
    border-radius: var(--tw-radius);
    box-shadow: var(--tw-card-shadow);
    padding: 40px;
    width: 100%;
    max-width: 520px;
}

.auth-card--wide {
    max-width: 680px;
}

.auth-card__logo {
    display: block;
    height: 48px;
    width: auto;
    margin: 0 auto 20px;
}

.auth-card__title {
    color: var(--tw-text-strong);
    font-size: 22px;
    font-weight: 600;
    line-height: 1.3;
    margin: 0;
    text-align: center;
}

.auth-card__subtitle {
    color: var(--tw-text-muted);
    font-size: 15px;
    margin: 6px 0 0;
    text-align: center;
}

.auth-card__footnote {
    border-top: 1px solid var(--tw-border);
    color: var(--tw-text-muted);
    font-size: 13px;
    margin: 28px 0 0;
    padding-top: 20px;
    text-align: center;
}


/* ---------------------------------------------------------------- signed-in row */

.auth-identity {
    align-items: baseline;
    background-color: var(--tw-surface-sunken);
    border-radius: var(--tw-radius-sm);
    display: flex;
    flex-wrap: wrap;
    gap: 4px 12px;
    font-size: 13px;
    margin-top: 24px;
    padding: 12px 16px;
}

.auth-identity__label {
    color: var(--tw-text-muted);
}

.auth-identity__value {
    color: var(--tw-text-strong);
    font-weight: 600;
    word-break: break-all;
}

/* ---------------------------------------------------------------- scopes */

.consent-lead {
    color: var(--tw-text-strong);
    font-size: 14px;
    font-weight: 600;
    margin: 28px 0 12px;
}

.scope-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.scope {
    align-items: center;
    border-top: 1px solid var(--tw-border);
    display: flex;
    gap: 12px;
    padding: 11px 2px;
}

.scope:has(.scope__desc) {
    align-items: flex-start;
}

.scope:last-child {
    border-bottom: 1px solid var(--tw-border);
}

.scope__check {
    flex: none;
    height: 18px;
    margin: 1px 0 0;
    width: 18px;
    accent-color: var(--tw-brand-strong);
}

/*
 * Required scopes render as an affirmative check rather than a disabled checkbox -- a greyed,
 * unticked-looking box reads as broken rather than as always-granted. The value is carried by
 * a hidden input in the markup, so exactly one control still posts per scope.
 */
.scope__granted {
    color: var(--tw-success);
    flex: none;
    font-size: 15px;
    font-weight: 700;
    height: 18px;
    line-height: 18px;
    margin-top: 1px;
    text-align: center;
    width: 18px;
}

.scope__body {
    flex: 1 1 auto;
    min-width: 0;
}

.scope__name {
    color: var(--tw-text-strong);
    display: block;
    font-size: 14px;
    font-weight: 600;
    margin: 0;
}

label.scope__name {
    cursor: pointer;
}

.scope__desc {
    color: var(--tw-text-muted);
    font-size: 13px;
    margin: 3px 0 0;
}

/*
 * "Always included" replaces the uppercase pill that used to sit here. The row already reads as
 * granted-and-locked from the check icon and the missing checkbox, so this only has to explain
 * why there is nothing to untick -- it does not need to shout.
 */
.scope__note {
    color: var(--tw-text-muted);
    font-size: 12px;
    font-weight: 500;
    margin-left: 8px;
    white-space: nowrap;
}

/* ---------------------------------------------------------------- form bits */

.consent-field {
    margin-top: 24px;
}

.field-label {
    color: var(--tw-text-strong);
    display: block;
    font-size: 13px;
    font-weight: 600;
    margin-bottom: 6px;
}

.field-input {
    background-color: var(--tw-surface);
    border: 1px solid var(--tw-input-border);
    border-radius: var(--tw-radius-sm);
    color: var(--tw-text-strong);
    display: block;
    font-size: 14px;
    padding: 9px 12px;
    width: 100%;
}

.field-input::placeholder {
    color: var(--tw-text-muted);
    opacity: 1;
}

.field-input:focus {
    border-color: var(--tw-brand-strong);
    outline: 2px solid var(--tw-brand-strong);
    outline-offset: -1px;
}

.field-hint {
    color: var(--tw-text-muted);
    font-size: 12px;
    margin: 6px 0 0;
}

.consent-remember {
    align-items: flex-start;
    display: flex;
    gap: 10px;
    margin-top: 20px;
}

.consent-remember__check {
    flex: none;
    height: 18px;
    margin: 1px 0 0;
    width: 18px;
    accent-color: var(--tw-brand-strong);
}

.consent-remember__label {
    color: var(--tw-text-strong);
    cursor: pointer;
    font-size: 14px;
    font-weight: 600;
    margin: 0;
}

/* ---------------------------------------------------------------- actions */

.auth-actions {
    display: flex;
    gap: 12px;
    margin-top: 28px;
}

.auth-actions--stacked {
    flex-direction: column;
}

.auth-actions--stacked .btn-tw {
    flex: none;
}

.btn-tw {
    border: 1px solid transparent;
    border-radius: var(--tw-radius-sm);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.2;
    padding: 11px 20px;
    text-align: center;
    text-decoration: none;
    transition: background-color 0.12s ease, border-color 0.12s ease;
}

.btn-tw--primary {
    background-color: var(--tw-brand-strong);
    color: #ffffff;
    flex: 1 1 auto;
}

.btn-tw--primary:hover,
.btn-tw--primary:focus {
    background-color: var(--tw-brand-strong-hover);
    color: #ffffff;
    text-decoration: none;
}

/*
 * "Cancel" is deliberately lighter than "Allow" rather than an equal-weight second button,
 * but it stays a bordered control with 7.56:1 text so it never reads as disabled.
 */
.btn-tw--ghost {
    background-color: var(--tw-surface);
    border-color: var(--tw-input-border);
    color: var(--tw-text-muted);
    flex: 0 0 auto;
    min-width: 120px;
}

.btn-tw--ghost:hover,
.btn-tw--ghost:focus {
    background-color: var(--tw-surface-sunken);
    color: var(--tw-text-strong);
    text-decoration: none;
}

.btn-tw--danger {
    background-color: var(--tw-danger);
    color: #ffffff;
}

.btn-tw--danger:hover,
.btn-tw--danger:focus {
    background-color: var(--tw-danger-hover);
    color: #ffffff;
    text-decoration: none;
}

.btn-tw--block {
    width: 100%;
}

.btn-tw--compact {
    font-size: 13px;
    min-width: 0;
    padding: 6px 12px;
}

/* ---------------------------------------------------------------- alerts */

.tw-alert {
    border: 1px solid transparent;
    border-radius: var(--tw-radius-sm);
    font-size: 14px;
    margin-top: 20px;
    padding: 12px 16px;
}

.tw-alert__title {
    display: block;
    font-weight: 600;
    margin-bottom: 2px;
}

.tw-alert--danger {
    background-color: var(--tw-danger-tint);
    border-color: var(--tw-danger-border);
    color: var(--tw-danger);
}

.tw-alert--info {
    background-color: var(--tw-surface-sunken);
    border-color: var(--tw-border);
    color: var(--tw-text);
}

.tw-alert ul {
    margin: 0;
    padding-left: 18px;
}

/* ---------------------------------------------------------------- external providers */

.auth-divider {
    align-items: center;
    color: var(--tw-text-muted);
    display: flex;
    font-size: 13px;
    gap: 12px;
    margin-top: 24px;
}

.auth-divider::before,
.auth-divider::after {
    background-color: var(--tw-border);
    content: '';
    flex: 1 1 auto;
    height: 1px;
}

.auth-disclosure {
    margin-top: 20px;
}

.auth-disclosure__summary {
    color: var(--tw-brand-strong);
    cursor: pointer;
    font-size: 14px;
    font-weight: 600;
    list-style: none;
    text-align: center;
}

.auth-disclosure__summary::-webkit-details-marker {
    display: none;
}

.auth-disclosure__summary:hover {
    color: var(--tw-brand-strong-hover);
    text-decoration: underline;
}

.provider-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    list-style: none;
    margin: 24px 0 0;
    padding: 0;
}

/*
 * Fallback for a provider that ships no button of its own. It borrows the pill shape and
 * metrics of the Google button below so a mixed provider list reads as one set, without
 * borrowing any provider's mark.
 */
.provider-btn {
    background-color: var(--tw-surface);
    border: 1px solid var(--tw-input-border);
    border-radius: 20px;
    color: var(--tw-text-strong);
    display: block;
    font-size: 14px;
    font-weight: 500;
    letter-spacing: 0.25px;
    padding: 10px 20px;
    text-align: center;
    text-decoration: none;
}

.provider-btn:hover,
.provider-btn:focus {
    background-color: var(--tw-surface-sunken);
    color: var(--tw-text-strong);
    text-decoration: none;
}

/* ---------------------------------------------------------------- grants */

.grant {
    border: 1px solid var(--tw-border);
    border-radius: var(--tw-radius-sm);
    margin-top: 16px;
    padding: 20px;
}

.grant__head {
    align-items: center;
    display: flex;
    gap: 12px;
}

.grant__logo {
    flex: none;
    height: 40px;
    width: 40px;
    object-fit: contain;
}

.grant__name {
    color: var(--tw-text-strong);
    font-size: 16px;
    font-weight: 600;
    margin: 0;
}

.grant__meta {
    list-style: none;
    margin: 14px 0 0;
    padding: 0;
}

.grant__meta div {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 10px;
    font-size: 13px;
    padding: 4px 0;
}

.grant__meta dt {
    color: var(--tw-text-muted);
    font-weight: 500;
    margin: 0;
    min-width: 140px;
}

.grant__meta dd {
    color: var(--tw-text-strong);
    margin: 0;
}

.grant__title {
    min-width: 0;
}

.grant__label {
    color: var(--tw-text-muted);
    font-size: 13px;
    margin: 2px 0 0;
}

.grant__scopes {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    list-style: none;
    margin: 0;
    padding: 0;
}

.grant__scope {
    background-color: var(--tw-surface-sunken);
    border-radius: 999px;
    color: var(--tw-text);
    font-size: 12px;
    font-weight: 500;
    line-height: 1.5;
    padding: 1px 9px;
    white-space: nowrap;
}

/*
 * Revocation is a two-step disclosure rather than a confirm() dialog: the page CSP forbids inline
 * scripts, and a <details> keeps the destructive control one deliberate click away without any.
 */
.grant__revoke {
    margin-top: 16px;
}

.grant__revoke-summary {
    list-style: none;
}

.grant__revoke-summary::-webkit-details-marker {
    display: none;
}

.grant__revoke-confirm {
    align-items: center;
    background-color: var(--tw-danger-tint);
    border: 1px solid var(--tw-danger-border);
    border-radius: var(--tw-radius-sm);
    display: flex;
    flex-wrap: wrap;
    gap: 10px 16px;
    margin-top: 12px;
    padding: 12px 16px;
}

.grant__revoke-text {
    color: var(--tw-danger);
    flex: 1 1 260px;
    font-size: 13px;
    margin: 0;
}

/* ---------------------------------------------------------------- misc pages */

.logged-out-page iframe {
    display: none;
    height: 0;
    width: 0;
}

.code-value {
    color: var(--tw-text-strong);
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    font-size: 15px;
    word-break: break-all;
}

/* ---------------------------------------------------------------- small screens */

@media (max-width: 575.98px) {
    .site-header__inner {
        padding: 12px 15px;
    }

    /* Visually hidden rather than display:none so the account name still reaches screen readers. */
    .site-header__email {
        clip: rect(0 0 0 0);
        height: 1px;
        overflow: hidden;
        position: absolute;
        white-space: nowrap;
        width: 1px;
    }

    .auth-shell {
        padding: 20px 0 40px;
    }

    .auth-shell--centered {
        padding: 20px 0;
    }

    .auth-card {
        border-left: 0;
        border-radius: 0;
        border-right: 0;
        padding: 28px 20px;
    }

    .auth-actions {
        flex-direction: column;
    }

    .btn-tw {
        width: 100%;
    }

    .btn-tw--compact {
        width: auto;
    }
}

/* ---------------------------------------------------------------- Sign in with Google
 *
 * Google's own button styles, per https://developers.google.com/identity/branding-guidelines.
 * Copied verbatim from Google's generated snippet -- the logo, colours (#FFFFFF ground,
 * #747775 1px stroke), 20px icon, 12px padding and Roboto Medium type are Google's spec and
 * must not be altered. Google Sans is not publicly distributable, which is why Google's own
 * output falls back to Roboto then Arial; no webfont is loaded here because the page CSP is
 * default-src 'self'.
 *
 * Two adaptations, both required and neither visual: the control is an <a> rather than a
 * <button> because it navigates to the challenge endpoint, and Google's inline
 * style="display:block" / style="display:none" attributes are expressed as classes because
 * inline styles are blocked by the CSP.
 */

.gsi-material-button {
    -moz-user-select: none;
    -webkit-user-select: none;
    -ms-user-select: none;
    -webkit-appearance: none;
    background-color: #ffffff;
    background-image: none;
    border: 1px solid #747775;
    border-radius: 20px;
    box-sizing: border-box;
    color: #1f1f1f;
    cursor: pointer;
    font-family: 'Roboto', arial, sans-serif;
    font-size: 14px;
    height: 40px;
    letter-spacing: 0.25px;
    outline: none;
    overflow: hidden;
    padding: 0 12px;
    position: relative;
    text-align: center;
    transition: background-color 0.218s, border-color 0.218s, box-shadow 0.218s;
    vertical-align: middle;
    white-space: nowrap;
    width: 100%;
    max-width: 400px;
    min-width: min-content;
}

/* Anchor adaptation: reproduce the <button> box without touching Google's metrics. */
a.gsi-material-button {
    display: flex;
    align-items: center;
    margin: 0 auto;
    text-decoration: none;
}

a.gsi-material-button:hover,
a.gsi-material-button:focus {
    color: #1f1f1f;
    text-decoration: none;
}

.gsi-material-button .gsi-material-button-icon {
    height: 20px;
    margin-right: 12px;
    min-width: 20px;
    width: 20px;
}

.gsi-material-button .gsi-material-button-icon svg {
    display: block;
}

.gsi-material-button .gsi-material-button-content-wrapper {
    align-items: center;
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    height: 100%;
    justify-content: space-between;
    position: relative;
    width: 100%;
}

.gsi-material-button .gsi-material-button-contents {
    flex-grow: 1;
    font-family: 'Roboto', arial, sans-serif;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: top;
}

.gsi-material-button .gsi-material-button-state {
    transition: opacity 0.218s;
    bottom: 0;
    left: 0;
    opacity: 0;
    position: absolute;
    right: 0;
    top: 0;
}

.gsi-material-button:not(:disabled):active .gsi-material-button-state,
.gsi-material-button:not(:disabled):focus .gsi-material-button-state {
    background-color: #303030;
    opacity: 12%;
}

.gsi-material-button:not(:disabled):hover {
    box-shadow: 0 1px 2px 0 rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);
}

.gsi-material-button:not(:disabled):hover .gsi-material-button-state {
    background-color: #303030;
    opacity: 8%;
}
