/* ============================================================================
   HiWS — Hiswill Web Stack
   The "Ember" look: burnt orange warming to gold, a rose third accent in the
   gradient, a drifting glow, hairline gradients and soft depth. Warm ink for
   the page instead of the cold navy it started with, so HiWS no longer reads
   as a twin of its sibling site hika. Laid on Bootstrap 5.3.3
   primitives. Dark by default; on a first visit the visitor's system decides,
   and the switch in the masthead remembers whatever they choose.

   Nothing here rebuilds a Bootstrap component. Colours, radii and shadows are
   published as --bs-* tokens, so every built-in picks up the brand on its own.
   The bespoke classes are only the pieces Bootstrap has no primitive for:
     · the brand mark and the quiet button (.brand-mark, .btn-ghost)
     · the accents (.eyebrow, .aurora, .hero-name, .mono)
     · the icon tile the cards and tool headers share (.badge.bg-primary-subtle)
     · the code window the long tool answers scroll inside
     · the reveal-on-scroll motion
     · the ambient background (a drifting glow and a faint grid)

   One token is HiWS's own. `bg-body` reads --bs-body-bg, and the markup puts
   that utility on every card, so here --bs-body-bg is the PANEL surface and
   --page is the shade the <body> itself paints. Rebranding the site is a
   change to the :root block alone; --brand perhaps most of all, because the
   buttons, the brand mark and the progress bar all share that one gradient.
   ========================================================================== */

/* ---------------------------------------------------------------------------
   1. Fonts. Plus Jakarta Sans for the body, Fraunces for the one editorial
   heading, and a monospace stack for the technical details. Every face ships
   as a local file, so nothing is fetched from a third party.
   --------------------------------------------------------------------------- */
@font-face {
    font-family: 'Plus Jakarta Sans';
    font-style: normal;
    font-weight: 200 800;
    font-display: swap;
    src: url('../webfonts/plus-jakarta-sans-latin.woff2') format('woff2');
}
@font-face {
    font-family: 'Fraunces';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../webfonts/fraunces-latin.woff2') format('woff2');
}

/* ---------------------------------------------------------------------------
   2. Tokens — dark by default.
   --------------------------------------------------------------------------- */
:root {
    color-scheme: dark;

    --bs-font-sans-serif: 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;
    --bs-font-monospace: ui-monospace, 'SFMono-Regular', 'JetBrains Mono', Menlo, Consolas, 'Liberation Mono', monospace;
    --bs-body-font-family: var(--bs-font-sans-serif);
    --bs-body-font-size: 1rem;
    --bs-body-line-height: 1.7;

    /* The page, a shade deeper than every panel that sits on it — a warm
       near-black, the ink the ember glows against. */
    --page: #0b0908;
    --page-rgb: 11, 9, 8;

    /* Surfaces. --bs-body-bg doubles as the panel colour, because the markup
       asks for `bg-body` on its cards. */
    --bs-body-bg: #16110e;
    --bs-body-bg-rgb: 22, 17, 14;
    --surface: #16110e;
    --surface-2: #1e1815;
    --bs-body-color: #e7dcd3;
    --bs-body-color-rgb: 231, 220, 211;
    --bs-heading-color: #fdf6f0;
    /* Pinned, because tables, nav links and list-group hovers all read it and
       a black value would vanish against these surfaces. */
    --bs-emphasis-color: #fdf6f0;
    --bs-emphasis-color-rgb: 253, 246, 240;
    --bs-secondary-color: #a8998e;
    --bs-secondary: #a8998e;
    --bs-secondary-rgb: 168, 153, 142;
    --bs-secondary-bg: #110d0b;
    --bs-tertiary-bg: #1a1412;
    --bs-border-color: rgba(236, 176, 124, .15);
    --bs-border-color-translucent: rgba(236, 176, 124, .08);

    /* Brand — ember: burnt orange warming to gold. */
    --bs-primary: #ff8f3f;
    --bs-primary-rgb: 255, 143, 63;
    --bs-primary-text-emphasis: #ffc291;
    --bs-primary-bg-subtle: rgba(255, 143, 63, .13);
    --bs-primary-border-subtle: rgba(255, 143, 63, .33);
    --on-primary: #1c0c03;
    --primary-hover: #f78333;
    --primary-active: #e97527;

    /* The two other accents, used in gradients rather than on their own. */
    --gold: #ffd166;
    --gold-rgb: 255, 209, 102;
    --rose: #ff5f8f;
    --rose-rgb: 255, 95, 143;

    /* One gradient for every branded surface — buttons, the brand mark, the
       progress bar. A theme can retune this in a single line. */
    --brand: linear-gradient(135deg, var(--bs-primary), var(--gold) 78%);

    --bs-warning: #f6b93b;
    --bs-warning-rgb: 246, 185, 59;
    --bs-warning-text-emphasis: #fcd285;
    --bs-warning-bg-subtle: rgba(246, 185, 59, .14);
    --bs-warning-border-subtle: rgba(246, 185, 59, .32);

    --bs-danger: #ff5c57;
    --bs-danger-rgb: 255, 92, 87;
    --bs-success: #52c46e;
    --bs-success-rgb: 82, 196, 110;
    --bs-info: #58a8e6;
    --bs-info-rgb: 88, 168, 230;
    --bs-dark: #140d09;
    --bs-dark-rgb: 20, 13, 9;

    --bs-link-color-rgb: var(--bs-primary-rgb);
    --bs-link-hover-color-rgb: 255, 194, 145;
    --bs-link-decoration: none;
    --bs-focus-ring-color: rgba(var(--bs-primary-rgb), .3);

    /* Shape */
    --bs-border-radius: .8rem;
    --bs-border-radius-sm: .5rem;
    --bs-border-radius-lg: 1.05rem;
    --bs-border-radius-xl: 1.4rem;
    --bs-border-radius-xxl: 1.8rem;

    /* Depth — softer and larger than before, so panels feel lifted. */
    --bs-box-shadow-sm: 0 1px 2px rgba(0, 0, 0, .4), 0 10px 26px -14px rgba(0, 0, 0, .72);
    --bs-box-shadow: 0 2px 8px rgba(0, 0, 0, .45), 0 24px 52px -22px rgba(0, 0, 0, .82);
    --bs-box-shadow-lg: 0 8px 18px rgba(0, 0, 0, .5), 0 40px 78px -32px rgba(0, 0, 0, .88);

    --ease: cubic-bezier(.4, 0, .2, 1);
    --snap: .2s var(--ease);
    --focus: 0 0 0 .22rem rgba(var(--bs-primary-rgb), .3);
}

/* The switch lifts the whole palette rather than dimming it. The brand
   gradient stays on the burnt side of the wheel, because the white text that
   carries a light-theme button would be lost on the dark theme's ink. */
[data-theme="light"] {
    color-scheme: light;

    --page: #fdf3ea;
    --page-rgb: 253, 243, 234;

    --bs-body-bg: #ffffff;
    --bs-body-bg-rgb: 255, 255, 255;
    --surface: #ffffff;
    --surface-2: #fdf1e6;
    --bs-body-color: #2a1a10;
    --bs-body-color-rgb: 42, 26, 16;
    --bs-heading-color: #1a0e06;
    --bs-emphasis-color: #160c05;
    --bs-emphasis-color-rgb: 22, 12, 5;
    --bs-secondary-color: #8a7466;
    --bs-secondary: #8a7466;
    --bs-secondary-rgb: 138, 116, 102;
    --bs-secondary-bg: #fdf1e6;
    --bs-tertiary-bg: #f7e7da;
    --bs-border-color: rgba(38, 20, 10, .13);
    --bs-border-color-translucent: rgba(38, 20, 10, .07);

    --bs-primary: #b85110;
    --bs-primary-rgb: 184, 81, 16;
    --bs-primary-text-emphasis: #97400b;
    --bs-primary-bg-subtle: #ffe7d5;
    --bs-primary-border-subtle: #f7c9a5;
    --on-primary: #ffffff;
    --primary-hover: #a4470c;
    --primary-active: #8f3d09;

    --gold: #c07d02;
    --gold-rgb: 192, 125, 2;
    --rose: #d43d74;
    --rose-rgb: 212, 61, 116;

    --brand: linear-gradient(135deg, var(--bs-primary), var(--primary-active));

    --bs-warning: #9c600a;
    --bs-warning-rgb: 156, 96, 10;
    --bs-warning-text-emphasis: #8a5210;
    --bs-warning-bg-subtle: #fdefd3;
    --bs-warning-border-subtle: #f6d596;

    --bs-danger: #d9402f;
    --bs-danger-rgb: 217, 64, 47;
    --bs-success: #2a8049;
    --bs-success-rgb: 42, 128, 73;
    --bs-info: #1f6fb2;
    --bs-info-rgb: 31, 111, 178;

    --bs-link-color-rgb: 184, 81, 16;
    --bs-link-hover-color-rgb: 143, 61, 9;

    --bs-box-shadow-sm: 0 1px 2px rgba(38, 20, 10, .06), 0 10px 24px -14px rgba(38, 20, 10, .2);
    --bs-box-shadow: 0 2px 6px rgba(38, 20, 10, .08), 0 22px 46px -24px rgba(38, 20, 10, .3);
    --bs-box-shadow-lg: 0 6px 14px rgba(38, 20, 10, .1), 0 36px 68px -32px rgba(38, 20, 10, .36);

    --focus: 0 0 0 .22rem rgba(184, 81, 16, .26);
}

/* ---------------------------------------------------------------------------
   3. Base & typography.
   --------------------------------------------------------------------------- */
html { scroll-behavior: smooth; }

body {
    min-height: 100vh;
    background-color: var(--page);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    scrollbar-color: rgba(var(--bs-body-color-rgb), .28) transparent;
}

/* The ambient glow, and the faint grid over it. Both are fixed, so the page
   slides across them; both sit behind everything, so nothing has to fight them
   for a click. The glow drifts slowly to keep the page feeling alive. */
body::before {
    content: "";
    position: fixed;
    inset: -10%;
    z-index: -2;
    pointer-events: none;
    background-image:
        radial-gradient(52rem 38rem at 82% -10%, rgba(var(--bs-primary-rgb), .16), transparent 58%),
        radial-gradient(48rem 34rem at -8% 2%, rgba(var(--gold-rgb), .14), transparent 56%),
        radial-gradient(42rem 30rem at 50% 116%, rgba(var(--rose-rgb), .12), transparent 60%);
    animation: drift 28s ease-in-out infinite alternate;
}

body::after {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background-image:
        linear-gradient(rgba(var(--bs-body-color-rgb), .035) 1px, transparent 1px),
        linear-gradient(90deg, rgba(var(--bs-body-color-rgb), .035) 1px, transparent 1px);
    background-size: 46px 46px;
    -webkit-mask-image: radial-gradient(circle at 50% 0%, #000, transparent 76%);
    mask-image: radial-gradient(circle at 50% 0%, #000, transparent 76%);
}

@keyframes drift {
    from { transform: translate3d(-1.5%, -1%, 0) scale(1); }
    to   { transform: translate3d(1.5%, 1.5%, 0) scale(1.06); }
}

h1, h2, h3, h4, h5, h6,
.display-1, .display-2, .display-3, .display-4, .display-5, .display-6 {
    font-weight: 700;
    letter-spacing: -.025em;
    color: var(--bs-heading-color);
}

.lead { color: var(--bs-secondary-color); }
hr { opacity: .12; }
::selection { background: rgba(var(--bs-primary-rgb), .3); }
.text-body-secondary { color: var(--bs-secondary-color) !important; }

/* The one serif face on the site, kept for the page that introduces the
   project — a little editorial warmth against all the monospace around it. */
.hero-name {
    font-family: 'Fraunces', Georgia, 'Times New Roman', serif;
    font-weight: 600;
    letter-spacing: -.028em;
    line-height: 1.04;
}

.eyebrow {
    font-family: var(--bs-font-monospace);
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .2em;
    text-transform: uppercase;
    color: var(--bs-primary);
}

.mono { font-family: var(--bs-font-monospace); }

/* Three accents flowing across the text, sliding gently so the gradient is
   never quite still. */
.aurora {
    background-image: linear-gradient(100deg, var(--bs-primary), var(--gold) 48%, var(--rose));
    background-size: 220% 100%;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    animation: shimmer 9s ease-in-out infinite alternate;
}

@keyframes shimmer {
    from { background-position: 0% 0; }
    to   { background-position: 100% 0; }
}

/* ---------------------------------------------------------------------------
   4. Links.
   --------------------------------------------------------------------------- */
a {
    text-decoration: none;
    text-underline-offset: .18em;
    text-decoration-thickness: .08em;
    transition: color var(--snap);
}
a:not(.btn):not(.nav-link):not(.navbar-brand):not(.dropdown-item):not(.page-link):not(.list-group-item):not(.badge):hover {
    text-decoration: underline;
    text-decoration-color: rgba(var(--bs-link-color-rgb), .5);
}

/* ---------------------------------------------------------------------------
   5. Buttons. Bootstrap bakes each variant's colours at build time, so
   .btn-primary is re-skinned by hand; every other button follows the tokens.
   --------------------------------------------------------------------------- */
.btn {
    --bs-btn-font-weight: 600;
    --bs-btn-border-radius: 999px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5em;
    transition: transform var(--snap), box-shadow var(--snap), color var(--snap),
                background-color var(--snap), border-color var(--snap);
}
.btn:active { transform: translateY(1px); }
.btn:focus-visible { box-shadow: var(--focus); }

/* The primary button paints the shared brand gradient, so it matches the mark
   and the progress bar rather than a flat fill. */
.btn-primary {
    --bs-btn-color: var(--on-primary);
    --bs-btn-bg: transparent;
    --bs-btn-border-color: transparent;
    --bs-btn-hover-color: var(--on-primary);
    --bs-btn-hover-bg: transparent;
    --bs-btn-hover-border-color: transparent;
    --bs-btn-active-color: var(--on-primary);
    --bs-btn-active-bg: transparent;
    --bs-btn-active-border-color: transparent;
    --bs-btn-disabled-color: var(--on-primary);
    --bs-btn-disabled-bg: transparent;
    --bs-btn-disabled-border-color: transparent;
    --bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
    background-image: var(--brand);
    border: 1px solid transparent;
}
.btn-primary:hover,
.btn-primary:active,
.btn-primary:disabled {
    background-image: var(--brand);
    filter: brightness(1.06);
}
.btn-primary:active { filter: brightness(.95); }
.btn-primary:hover { box-shadow: 0 14px 32px -14px rgba(var(--bs-primary-rgb), .75); }

/* A quiet button that borrows the page surface rather than a colour. */
.btn-ghost {
    --bs-btn-color: var(--bs-body-color);
    --bs-btn-bg: transparent;
    --bs-btn-border-color: var(--bs-border-color);
    --bs-btn-hover-color: var(--bs-primary);
    --bs-btn-hover-bg: var(--surface-2);
    --bs-btn-hover-border-color: rgba(var(--bs-primary-rgb), .6);
    --bs-btn-active-color: var(--bs-primary);
    --bs-btn-active-bg: var(--surface-2);
    --bs-btn-active-border-color: rgba(var(--bs-primary-rgb), .6);
    --bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
}

/* The outline pairs are baked too, and they carry the project cards, every
   copy button and the Bible's chapter arrows, so both are re-skinned. */
.btn-outline-primary {
    --bs-btn-color: var(--bs-primary);
    --bs-btn-border-color: rgba(var(--bs-primary-rgb), .5);
    --bs-btn-hover-color: var(--on-primary);
    --bs-btn-hover-bg: var(--bs-primary);
    --bs-btn-hover-border-color: var(--bs-primary);
    --bs-btn-active-color: var(--on-primary);
    --bs-btn-active-bg: var(--primary-active);
    --bs-btn-active-border-color: var(--primary-active);
    --bs-btn-disabled-color: rgba(var(--bs-primary-rgb), .55);
    --bs-btn-disabled-border-color: rgba(var(--bs-primary-rgb), .3);
    --bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
}

.btn-outline-secondary {
    --bs-btn-color: var(--bs-body-color);
    --bs-btn-border-color: var(--bs-border-color);
    --bs-btn-hover-color: var(--bs-primary);
    --bs-btn-hover-bg: var(--surface-2);
    --bs-btn-hover-border-color: rgba(var(--bs-primary-rgb), .6);
    --bs-btn-active-color: var(--on-primary);
    --bs-btn-active-bg: var(--bs-primary);
    --bs-btn-active-border-color: var(--bs-primary);
    --bs-btn-disabled-color: var(--bs-secondary-color);
    --bs-btn-disabled-border-color: var(--bs-border-color);
    --bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
}

/* The round icon buttons — the theme switch and "back to top". Bootstrap sizes
   a button by its padding, which a circle cannot use; set the box instead. */
.btn.rounded-circle {
    --bs-btn-padding-x: 0;
    --bs-btn-padding-y: 0;
    width: 2.5rem;
    height: 2.5rem;
}
.btn-sm.rounded-circle { width: 2rem; height: 2rem; }

/* ---------------------------------------------------------------------------
   6. Fields take the same pill shape as the buttons; a textarea is a
   paragraph box, not a line, so it stays rounded without going fully pill.
   --------------------------------------------------------------------------- */
.form-control,
.form-select {
    border-radius: 999px;
    min-width: 0;
}
textarea.form-control { border-radius: .8rem; }
/* A colour swatch is not a line either — a pill would make it an oval. */
.form-control-color { border-radius: .55rem; }

/* Focus and the last few built-ins that bake their colours at build time. Each
   is pointed back at a token, so the brand reaches it like everything else. */
.form-control:focus,
.form-select:focus {
    border-color: rgba(var(--bs-primary-rgb), .55);
    box-shadow: 0 0 0 .25rem var(--bs-focus-ring-color);
}
.nav-pills {
    --bs-nav-pills-link-active-bg: var(--bs-primary);
    --bs-nav-pills-link-active-color: var(--on-primary);
}
.pagination {
    --bs-pagination-active-bg: var(--bs-primary);
    --bs-pagination-active-border-color: var(--bs-primary);
    --bs-pagination-active-color: var(--on-primary);
    --bs-pagination-focus-box-shadow: 0 0 0 .25rem var(--bs-focus-ring-color);
}

/* ---------------------------------------------------------------------------
   7. Cards & tables.
   --------------------------------------------------------------------------- */
.card {
    --bs-card-border-width: 1px;
    --bs-card-border-color: var(--bs-border-color);
    --bs-card-bg: var(--surface);
    --bs-card-cap-bg: transparent;
    --bs-card-title-color: var(--bs-heading-color);
    background-image: linear-gradient(180deg, rgba(255, 255, 255, .035), transparent 42%);
    box-shadow: var(--bs-box-shadow-sm);
    transition: transform var(--snap), box-shadow var(--snap), border-color var(--snap);
}

/* A card that is itself a link lifts a little when the pointer is over it, and
   takes a brand-tinted ring on the way. */
@media (hover: hover) {
    a.card:hover {
        transform: translateY(-5px);
        box-shadow: 0 0 0 1px rgba(var(--bs-primary-rgb), .38), var(--bs-box-shadow);
        border-color: rgba(var(--bs-primary-rgb), .5);
    }
}

/* A table lives on a card, so its cells must stay transparent. Bootstrap
   paints each cell with --bs-table-bg (the page colour), which would lay a
   square block over the card's rounded corners. */
.table { --bs-table-bg: transparent; }

/* The rounded icon tile the project cards, the tools index and every tool
   header share. It is the one badge the site dresses up, so it is styled by
   its variant rather than by a class of its own. */
.badge.bg-primary-subtle {
    background-image: linear-gradient(140deg, rgba(var(--bs-primary-rgb), .2), rgba(var(--gold-rgb), .16));
    border: 1px solid var(--bs-primary-border-subtle);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .08);
    line-height: 1;
}

/* A meter, borrowed from hika's skill bars, for the progress bars the facts
   pages show. */
.progress { --bs-progress-bg: rgba(var(--bs-body-color-rgb), .12); }
.progress-bar { background-image: var(--brand); }

/* ---------------------------------------------------------------------------
   8. Masthead. The sticky bar is translucent, so the glow shows through it as
   the page moves underneath, and a hairline gradient runs along its base.
   --------------------------------------------------------------------------- */
.site-header {
    position: sticky;
    top: 0;
    z-index: 1030;
    background: rgba(var(--page-rgb), .78);
    backdrop-filter: blur(16px) saturate(1.4);
    -webkit-backdrop-filter: blur(16px) saturate(1.4);
    border-bottom: 1px solid var(--bs-border-color);
}
.site-header::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -1px;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(var(--bs-primary-rgb), .45), rgba(var(--gold-rgb), .3), transparent);
    pointer-events: none;
}
.site-header .navbar { --bs-navbar-padding-y: .6rem; }
.site-header .nav-link {
    font-weight: 500;
    position: relative;
}
/* The active or hovered section grows a short gradient underline from the
   left, so the current page reads without shouting. */
.site-header .nav-link::after {
    content: "";
    position: absolute;
    left: .75rem;
    right: .75rem;
    bottom: .35rem;
    height: 2px;
    border-radius: 2px;
    background-image: var(--brand);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform var(--snap);
}
.site-header .nav-link:hover::after,
.site-header .nav-link.active::after { transform: scaleX(1); }
.site-header .nav-link.active { color: var(--bs-primary) !important; }

.brand-mark {
    width: 2.6rem;
    height: 2.6rem;
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: .85rem;
    color: var(--on-primary);
    background-image: var(--brand);
    box-shadow: 0 10px 24px -12px rgba(var(--bs-primary-rgb), .85);
    transition: transform var(--snap), box-shadow var(--snap);
}
.navbar-brand:hover .brand-mark {
    transform: translateY(-1px) rotate(-3deg);
    box-shadow: 0 14px 30px -12px rgba(var(--bs-primary-rgb), .95);
}
.brand-name { font-weight: 700; letter-spacing: -.01em; color: var(--bs-heading-color); line-height: 1.05; }
.brand-tagline { font-family: var(--bs-font-monospace); font-size: .66rem; letter-spacing: .12em; color: var(--bs-secondary-color); }
.navbar-brand:hover .brand-name { color: var(--bs-primary); }

/* One icon shows at a time; the button says which way it will go. */
.theme-toggle .fa-sun { display: none; }
[data-theme="light"] .theme-toggle .fa-sun { display: inline-flex; }
[data-theme="light"] .theme-toggle .fa-moon { display: none; }

/* ---------------------------------------------------------------------------
   9. Footer & back-to-top.
   --------------------------------------------------------------------------- */
.site-footer { border-top: 1px solid var(--bs-border-color); background: var(--page); }
#top {
    position: fixed;
    right: 1.25rem;
    bottom: 1.25rem;
    z-index: 1040;
    box-shadow: var(--bs-box-shadow);
}
#top[hidden] { display: none; }

/* ---------------------------------------------------------------------------
   10. Code. Inline snippets take the brand; the window scrolls instead of
   stretching the page when a tool prints thousands of lines.
   --------------------------------------------------------------------------- */
code {
    font-family: var(--bs-font-monospace);
    color: var(--bs-primary);
    background: rgba(var(--bs-primary-rgb), .1);
    padding: .15em .4em;
    border-radius: var(--bs-border-radius-sm);
}
pre {
    padding: 1rem 1.15rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    background: var(--surface-2);
    overflow: auto;
    scrollbar-width: thin;
}
pre code { background: none; color: var(--bs-body-color); padding: 0; }

.code-window { max-height: 34rem; overflow: auto; scrollbar-width: thin; }

/* ---------------------------------------------------------------------------
   11. Motion. Anything marked .reveal rises into place once, when scrolled to.
   The `js` class is set before the first paint, so with scripting off the
   content is simply there.
   --------------------------------------------------------------------------- */
html.js .reveal {
    opacity: 0;
    transform: translateY(22px) scale(.995);
    filter: blur(5px);
    transition: opacity .7s var(--ease), transform .7s var(--ease), filter .7s var(--ease);
}
html.js .reveal.in { opacity: 1; transform: none; filter: none; }

a:focus-visible, .btn:focus-visible, .form-control:focus-visible, .form-select:focus-visible {
    outline: 2px solid var(--bs-primary);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
        scroll-behavior: auto !important;
    }
    html.js .reveal { opacity: 1; transform: none; filter: none; }
    body::before { animation: none; }
}
