/**
 * Design tokens.
 *
 * The site was built with ~260 separate hardcoded instances of #1a1a1a and a
 * dozen near-identical greys, so pages had quietly drifted apart. These are the
 * values that were already dominant, named once so they stay consistent — and
 * so a dark theme is a matter of redefining a dozen variables rather than
 * editing 7,000 lines of CSS.
 *
 * Loaded before every page stylesheet.
 *
 * ── Theming ───────────────────────────────────────────────────────────────
 * Three states, not two: an explicit choice stamps data-theme="dark"/"light"
 * on <html>, and the default (no choice made) follows the OS via
 * prefers-color-scheme. Every colour is defined on bare :root first, so a
 * token always resolves even in the un-stamped state.
 *
 * --ink and --surface are a *pair* that swaps together. A black button with
 * white text is `background: var(--ink); color: var(--surface)`, which in dark
 * mode becomes a light button with dark text — still the strongest thing on
 * the page. Inverting only one of the two is what makes naive dark modes
 * unreadable.
 */

:root {
    color-scheme: light;

    /* Ink — near-black with a faint blue cast rather than pure grey */
    --ink:            #1a1a1a;
    --ink-2:          #4a4f57;
    --ink-3:          #6b7280;
    --ink-muted:      #999999;

    /* Chevron drawn into <select> backgrounds. A data: URI cannot read
       currentColor, so the colour is a token that swaps with the theme. */
    --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");

    /* Surfaces */
    --surface:        #ffffff;
    --surface-sunken: #f7f7f8;
    --surface-raised: #ffffff;

    /* Lines */
    --line:           #e5e5e5;
    --line-strong:    #d4d4d4;

    /* Semantic — kept distinct from the brand's monochrome so state reads
       instantly without relying on an accent that is otherwise absent */
    --ok:             #1f7a43;
    --ok-bg:          #eaf6ee;
    --warn:           #8a6d1f;
    --warn-bg:        #fdf6e3;
    --danger:         #b3261e;
    --danger-bg:      #fdeceb;
    --info:           #1d4e89;
    --info-bg:        #eaf0f8;

    /* Type scale — a ratio rather than the 30-odd ad-hoc sizes in use */
    --text-xs:        11px;
    --text-sm:        12px;
    --text-base:      14px;
    --text-md:        16px;
    --text-lg:        20px;
    --text-xl:        26px;
    --text-2xl:       34px;
    --text-3xl:       clamp(32px, 4.5vw, 48px);

    /* Spacing */
    --space-1:        4px;
    --space-2:        8px;
    --space-3:        12px;
    --space-4:        16px;
    --space-5:        24px;
    --space-6:        32px;
    --space-7:        48px;

    /* Radii — three steps, not the seven currently in use */
    --radius-sm:      4px;
    --radius:         8px;
    --radius-lg:      12px;
    --radius-pill:    999px;

    /* Elevation, kept soft — this is a document-like UI, not a card gallery */
    --shadow-sm:      0 1px 2px rgba(16, 20, 28, 0.05);
    --shadow:         0 2px 8px rgba(16, 20, 28, 0.07);
    --shadow-lg:      0 12px 32px rgba(16, 20, 28, 0.12);

    --focus-ring:     0 0 0 3px rgba(26, 26, 26, 0.18);

    /* Hover shade for inverted (filled) buttons — --ink nudged toward
       --surface. Light mode lifts near-black to a mid grey; dark mode drops
       near-white to a soft grey. Either way the label stays --surface, so the
       button visibly changes without the contrast collapsing. --ink-2 used to
       do this job and could not: in dark mode it *darkens* the fill under
       already-dark text. */
    --ink-hover:      color-mix(in srgb, var(--ink) 82%, var(--surface));
    --ink-press:      color-mix(in srgb, var(--ink) 70%, var(--surface));

    /* Motion */
    --ease-out:       cubic-bezier(0.16, 1, 0.3, 1);
    --dur-fast:       140ms;
    --dur:            240ms;
    --dur-slow:       520ms;
}

/**
 * Dark palette, defined once and applied from two places: the OS preference
 * (when the viewer has not chosen), and an explicit data-theme="dark".
 *
 * Not an inversion — a true dark ground with a slight blue cast, lifted
 * surfaces for cards, and semantic colours re-picked for contrast against dark
 * rather than merely lightened.
 */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        color-scheme: dark;

        --ink:            #e9eaec;
        --ink-2:          #a8afba;
        --ink-3:          #7d8592;
        --ink-muted:      #6b7280;
        --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%237d8592' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");

        --surface:        #0f1115;
        --surface-sunken: #15181e;
        --surface-raised: #1a1e25;

        --line:           #262b33;
        --line-strong:    #363c46;

        --ok:             #4ade80;
        --ok-bg:          #10231a;
        --warn:           #e8c56a;
        --warn-bg:        #241f10;
        --danger:         #f87171;
        --danger-bg:      #2a1416;
        --info:           #7fb3e8;
        --info-bg:        #111d2b;

        --shadow-sm:      0 1px 2px rgba(0, 0, 0, 0.4);
        --shadow:         0 2px 10px rgba(0, 0, 0, 0.5);
        --shadow-lg:      0 16px 40px rgba(0, 0, 0, 0.6);

        --focus-ring:     0 0 0 3px rgba(233, 234, 236, 0.25);
    }
}

:root[data-theme="dark"] {
    color-scheme: dark;

    --ink:            #e9eaec;
    --ink-2:          #a8afba;
    --ink-3:          #7d8592;
    --ink-muted:      #6b7280;
    /* This block was missing the chevron, so a viewer who *chose* dark kept the
       light-mode stroke on every <select>. The count looked right only because
       the @media block declared it twice. */
    --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%237d8592' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");

    --surface:        #0f1115;
    --surface-sunken: #15181e;
    --surface-raised: #1a1e25;

    --line:           #262b33;
    --line-strong:    #363c46;

    --ok:             #4ade80;
    --ok-bg:          #10231a;
    --warn:           #e8c56a;
    --warn-bg:        #241f10;
    --danger:         #f87171;
    --danger-bg:      #2a1416;
    --info:           #7fb3e8;
    --info-bg:        #111d2b;

    --shadow-sm:      0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow:         0 2px 10px rgba(0, 0, 0, 0.5);
    --shadow-lg:      0 16px 40px rgba(0, 0, 0, 0.6);



    --focus-ring:     0 0 0 3px rgba(233, 234, 236, 0.25);
}

/* ── Focus ────────────────────────────────────────────────────────────────
   There was no visible focus style anywhere on the site, which makes it
   unusable by keyboard. :focus-visible shows the ring for keyboard users
   without putting an outline on every mouse click. */

:focus-visible {
    outline: 2px solid var(--ink);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--ink);
    outline-offset: 2px;
}

/* ── Selects ──────────────────────────────────────────────────────────────
   One treatment for every dropdown on every page. The native control drew
   itself with the browser's own colours and arrow, which in dark mode meant
   a pale box with a black arrow sitting in a dark form. `color-scheme` on
   :root already makes the popup list follow the theme; this handles the
   closed control. */
select {
    appearance: none;
    -webkit-appearance: none;
    background-color: var(--surface);
    background-image: var(--select-chevron);
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 16px 16px;
    padding-right: 34px;
    color: var(--ink);
    border: 1px solid var(--line-strong);
    border-radius: 6px;
    font: inherit;
    line-height: 1.3;
    cursor: pointer;
    transition: border-color var(--dur-fast, 140ms) ease, box-shadow var(--dur-fast, 140ms) ease;
}

select:hover {
    border-color: var(--ink-3);
}

select:focus {
    outline: none;
    border-color: var(--ink);
    box-shadow: 0 0 0 3px var(--line);
}

select:disabled {
    cursor: not-allowed;
    color: var(--ink-muted);
    background-color: var(--surface-sunken);
}

/* Options inherit the control's colours where the platform allows it. */
select option {
    background: var(--surface);
    color: var(--ink);
}

/* Legacy Edge/IE drew its own arrow on top. */
select::-ms-expand {
    display: none;
}

/* ── Motion ───────────────────────────────────────────────────────────────
   Honour the OS-level request to reduce motion. Animation is decoration here;
   for a viewer with vestibular sensitivity it is not. Entrance animations are
   neutralised to their finished state rather than removed, so nothing that
   animates in ends up invisible. */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }

    [data-reveal] {
        opacity: 1 !important;
        transform: none !important;
    }
}

/* ── Base ─────────────────────────────────────────────────────────────── */

/* Inter, self-hosted (no external font requests — the CSP only allows
   font-src 'self'). One variable file covers every weight we use, and
   font-display: swap paints text immediately in the system font, then swaps. */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('/fonts/inter-latin-wght.woff2') format('woff2');
}

/* The app's type stack. Inter first, then the platform UI fonts as a fallback
   for the brief moment before it loads (and if it ever fails to). */
:root {
    --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
}

html {
    -webkit-text-size-adjust: 100%;
}

body {
    /* The face and the page ground live here rather than only in the ten page
       stylesheets that each restate them. They were repeated per page, so a
       page rewritten without that block fell back to the browser's default
       serif on a white ground — which is exactly what happened to About and
       the FAQ. A page can still override either; it just cannot lose them by
       omission. */
    font-family: var(--font-sans);
    background: var(--surface-sunken);
    color: var(--ink);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    /* Themed colours change instantly on toggle unless this is eased. */
    transition: background-color var(--dur) var(--ease-out),
                color var(--dur) var(--ease-out);
}

/* Long hashes, addresses and URLs must not push the page sideways. */
code,
pre,
.mono {
    overflow-wrap: anywhere;
}

img,
svg,
video {
    max-width: 100%;
}

/* Headings read better with balanced line breaks than a one-word last line. */
h1, h2, h3 {
    text-wrap: balance;
}

::selection {
    background: var(--ink);
    color: var(--surface);
}

/* Scrollbars follow the theme instead of staying stark white in dark mode. */
* {
    scrollbar-color: var(--line-strong) transparent;
}

/* ── Theme toggle ─────────────────────────────────────────────────────────
   Three states, one button. Only the icon for the active preference is
   shown; the other two are removed from the layout entirely so the button
   keeps a fixed size. */

.theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--ink-2);
    cursor: pointer;
    flex: 0 0 auto;
    transition: color var(--dur-fast) var(--ease-out),
                border-color var(--dur-fast) var(--ease-out),
                background-color var(--dur-fast) var(--ease-out);
}

.theme-toggle:hover {
    color: var(--ink);
    border-color: var(--line-strong);
    background: var(--surface-sunken);
}

.theme-icon { display: none; }

.theme-toggle[data-theme-state="light"]  .theme-icon--sun,
.theme-toggle[data-theme-state="dark"]   .theme-icon--moon,
.theme-toggle[data-theme-state="system"] .theme-icon--auto {
    display: block;
}

/* Before the script has stamped a state, show the auto icon rather than
   nothing at all. */
.theme-toggle:not([data-theme-state]) .theme-icon--auto {
    display: block;
}

/* ── Entrance animations ──────────────────────────────────────────────────
   Elements marked [data-reveal] start slightly low and transparent, and are
   released by an IntersectionObserver. The resting state is the *visible*
   one - if the observer never runs (script error, very old browser), nothing
   is left permanently invisible.

   The reduced-motion block above neutralises these to their finished state. */

@media (prefers-reduced-motion: no-preference) {
    [data-reveal] {
        opacity: 0;
        transform: translateY(14px);
        transition: opacity var(--dur-slow) var(--ease-out),
                    transform var(--dur-slow) var(--ease-out);
        transition-delay: var(--reveal-delay, 0ms);
        will-change: opacity, transform;
    }

    [data-reveal].is-revealed {
        opacity: 1;
        transform: none;
        will-change: auto;
    }
}

/* The footer used to stay dark in both themes, which forced its buttons onto
   the --inverse-* pair so they would not come out the same colour as the band
   (in light mode a normal --ink button measured 1.00:1 against it). The footer
   now follows the theme, so those overrides are gone and its buttons use the
   ordinary inverted pair like every other button on the site. */

/* ── Landing hero ─────────────────────────────────────────────────────────────
   Shared by About, FAQ, Privacy, Terms and Compliance so every top-level page
   opens with the same landing-style banner: a soft gradient with a slow
   professional sheen, and the heading + subtitle rising into place on load. */
.hero {
    position: relative;
    overflow: hidden;
    padding: 96px 24px 84px;
    text-align: center;
    border-bottom: 1px solid var(--line);
    background:
        radial-gradient(1100px 380px at 50% -12%, color-mix(in srgb, var(--ink) 7%, transparent), transparent 70%),
        linear-gradient(135deg, var(--surface) 0%, var(--surface-sunken) 100%);
}

/* A slow diagonal light sweep — subtle, never distracting. */
.hero::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(115deg, transparent 34%, color-mix(in srgb, var(--ink) 6%, transparent) 50%, transparent 66%);
    background-size: 240% 100%;
    animation: hero-sheen 9s ease-in-out infinite;
    pointer-events: none;
}

.hero > * {
    position: relative;
    z-index: 1;
}

.hero h1 {
    font-size: 48px;
    font-weight: 700;
    margin: 0 0 16px;
    color: var(--ink);
    letter-spacing: -0.02em;
    opacity: 0;
    animation: hero-rise 0.7s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

.hero p,
.hero .subtitle,
.hero .last-updated {
    font-size: 18px;
    color: var(--ink-2);
    max-width: 640px;
    margin: 0 auto;
    line-height: 1.6;
    opacity: 0;
    animation: hero-rise 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.12s forwards;
}

@keyframes hero-rise {
    from { opacity: 0; transform: translateY(16px); }
    to   { opacity: 1; transform: none; }
}

/* A neutral kicker above a page's heading, sharing the status page's badge
   shape and its entrance so every banner resolves the same way. The status
   page's own .status-pill carries a state colour and a live dot; this one is
   only a label, so it takes neither. */
.hero-pill {
    display: inline-flex;
    align-items: center;
    margin-bottom: 18px;
    padding: 7px 15px;
    border-radius: var(--radius-pill);
    background: var(--surface-sunken);
    color: var(--ink-2);
    border: 1px solid var(--line);
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    opacity: 0;
    animation: hero-rise 0.7s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

@keyframes hero-sheen {
    0%, 100% { background-position: 210% 0; }
    50%      { background-position: -50% 0; }
}

@media (prefers-reduced-motion: reduce) {
    .hero::before { animation: none; }
    .hero h1,
    .hero p,
    .hero .subtitle,
    .hero .last-updated { animation: none; opacity: 1; }
}

@media (max-width: 768px) {
    .hero { padding: 60px 20px 52px; }
    .hero h1 { font-size: 32px; }
    .hero p,
    .hero .subtitle,
    .hero .last-updated { font-size: 16px; }
}

@media (max-width: 480px) {
    .hero h1 { font-size: 26px; }
}

/* ── Footer entrance ──────────────────────────────────────────────────────
   Every page carries the same footer, so this lives here rather than in the
   ten page stylesheets that each define .footer-link for themselves. Each
   column arrives behind the one before it, and its links then run down the
   list.

   The stagger is nth-child arithmetic rather than a JavaScript cascade, so the
   footer animates with nothing extra loaded - and because the resting state is
   the visible one, it stays readable even if nothing loads at all.

   reveal.js decides *when*: a footer below the fold is released as it scrolls
   into view, and one already on screen when the page loads is shown at once
   without animating, so nothing plays a entrance the visitor has already
   scrolled past.

   The links are siblings of their column's h4, so the first is :nth-child(2). */

@media (prefers-reduced-motion: no-preference) {
    .footer-section .footer-link {
        opacity: 0;
        transform: translateX(-10px);
        /* colour carries no delay, so hover answers at once in both directions
           instead of lagging by up to a quarter of a second. */
        transition: opacity var(--dur) var(--ease-out) var(--link-delay, 0ms),
                    transform var(--dur-slow) var(--ease-out) var(--link-delay, 0ms),
                    color var(--dur) var(--ease-out);
    }

    .footer-section.is-revealed .footer-link {
        opacity: 1;
        transform: none;
    }

    .footer-section .footer-link:nth-child(2) { --link-delay: 60ms; }
    .footer-section .footer-link:nth-child(3) { --link-delay: 120ms; }
    .footer-section .footer-link:nth-child(4) { --link-delay: 180ms; }
    .footer-section .footer-link:nth-child(5) { --link-delay: 240ms; }
}
