/* fx base layer: cross-cutting browser surfaces.
 * Loads after tokens.css and bootstrap, before the surface stylesheet, so a
 * surface file can still override anything here. */

/* Bootstrap bridge.
 * Bootstrap declares its palette on :root as plain values, so it wins over an
 * equal-specificity rule in tokens.css even though tokens.css loads first. The
 * remap therefore has to live here, after the framework, to take effect.
 * Without it .card, .modal, .list-group and other components resolve their own
 * text from a fixed light-grey constant, painting dark ink onto a dark surface in
 * dark mode. Remapping the contract variables once carries every component with the
 * theme instead of patching each one. */
:root {
    --bs-body-color: var(--ink);
    --bs-body-bg: var(--canvas);
    --bs-emphasis-color: var(--ink);
    --bs-heading-color: var(--ink);
    --bs-secondary-color: var(--ink-2);
    --bs-tertiary-color: var(--ink-muted);
    --bs-border-color: var(--rule);
}

/* Bootstrap's colour utilities read fixed constants that ignore the theme: its
 * text-danger is 3.4:1 on the dark surfaces, text-dark disappears on them, and the
 * text-bg pairs and btn-danger sit outside the palette. They are pointed at the
 * tokens here, globally, because modals and alerts render outside .app-content. */
.text-danger {
    color: var(--danger) !important;
}

.text-dark {
    color: var(--ink) !important;
}

.text-bg-success {
    background-color: var(--accent-wash) !important;
    color: var(--accent-ink) !important;
}

.text-bg-warning {
    background-color: var(--warn-soft) !important;
    color: var(--warn-ink) !important;
}

.text-bg-secondary {
    background-color: var(--surface-2) !important;
    color: var(--ink-muted) !important;
}

/* Hover and press step the red toward the ink: darker in light mode, lighter in dark,
 * so each state is visible and its --on-danger text gains contrast rather than losing it. */
.btn-danger {
    --danger-step: color-mix(in srgb, var(--danger) 85%, var(--ink));
    --danger-press: color-mix(in srgb, var(--danger) 75%, var(--ink));
    --bs-btn-color: var(--on-danger);
    --bs-btn-bg: var(--danger);
    --bs-btn-border-color: var(--danger);
    --bs-btn-hover-color: var(--on-danger);
    --bs-btn-hover-bg: var(--danger-step);
    --bs-btn-hover-border-color: var(--danger-step);
    --bs-btn-active-color: var(--on-danger);
    --bs-btn-active-bg: var(--danger-press);
    --bs-btn-active-border-color: var(--danger-press);
    --bs-btn-disabled-color: var(--on-danger);
    --bs-btn-disabled-bg: var(--danger);
    --bs-btn-disabled-border-color: var(--danger);
}

::selection {
    background: var(--brand-veil);
    color: var(--ink);
}

::-moz-selection {
    background: var(--brand-veil);
    color: var(--ink);
}

/* The select caret.
 *
 * Two things have to be true for a select to actually look like a select, and
 * Bootstrap only supplies one of them. It draws the caret from
 * --bs-form-select-bg-img, which it declares on .form-select itself — so a value
 * set on :root loses to it and the element must be targeted directly. And the
 * caret then has to survive the surface layer's own background shorthand, which
 * resets background-image to none and takes the glyph with it (see app.css).
 * Restoring the stock variable alone therefore buys a caret that renders in light
 * mode at Bootstrap's own grey and disappears against the dark surface; the token
 * supplies a stroke from the palette instead, so both themes are legible. */
select.form-select {
    --bs-form-select-bg-img: var(--select-caret);
}

.skip-link {
    position: absolute;
    left: 1rem;
    top: -100%;
    z-index: 2000;
    padding: 0.75rem 1.15rem;
    background: var(--brand);
    color: var(--on-brand);
    border-radius: var(--radius-sm);
    font-weight: 600;
    text-decoration: none;
    transition: top var(--dur-fast) var(--ease-out);
}

.skip-link:focus-visible {
    top: 1rem;
    color: var(--on-brand);
}

a:focus-visible,
button:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible,
.btn:focus-visible {
    outline: 3px solid var(--brand);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

::-webkit-scrollbar-track {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    background: var(--rule);
    border: 2px solid transparent;
    border-radius: var(--radius-pill);
    background-clip: content-box;
}

::-webkit-scrollbar-thumb:hover {
    background: var(--rule-strong);
    background-clip: content-box;
}

/* Reduced motion removes movement, not feedback. Transforms and sliding stop, so the
 * drawer and lifts land instantly, while colour, border, shadow and opacity changes
 * keep their short fade and a state change still reads as a change. Keyframe
 * animations, including third-party ones such as SweetAlert's icons, jump to their end
 * state. A Bootstrap spinner is the loading state itself, so it keeps turning at
 * Bootstrap's slower reduced-motion speed (1.5s) instead of freezing into what looks like a hang. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        transition-property: color, background-color, border-color, outline-color, box-shadow, opacity !important;
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        scroll-behavior: auto !important;
    }

    .spinner-border,
    .spinner-grow {
        animation-duration: 1.5s !important;
        animation-iteration-count: infinite !important;
    }
}
