/*
 * Reconciles the fox design system with the wiki themes.
 *
 * fox.css is a whole design system, not a font bundle: it carries a global
 * reset, a colour palette, heading scales, a dark mode of its own, and the
 * @font-face rules for the three self-hosted families. Material is also a whole
 * design system. Loading both means deciding, once, which one owns what -
 * otherwise the two fight in ways that depend on stylesheet order.
 *
 * The split: fox owns colour and typography, Material owns layout and the
 * light/dark switch. Concretely, that is three moves:
 *
 *   1. Material's --md-* colour variables are redefined from fox tokens, so
 *      every surface, rule and accent on the page resolves to a fox colour.
 *   2. Material's palette toggle stays the source of truth for light vs dark,
 *      because its `slate` scheme carries dark values for the long tail of
 *      --md-* variables this file does not remap (--md-code-hl-*,
 *      --md-typeset-kbd-*, the --md-*-bg-color--light family). Replacing that
 *      with fox's own toggle would mean either duplicating the palette
 *      literals per scheme or leaving those variables stranded in light mode.
 *   3. theme/mkdocs/main.html mirrors body[data-md-color-scheme] onto
 *      html[data-theme], which is what fox.css flips on - so the fox tokens
 *      below are never in the opposite mode from Material's own.
 *
 * Because (3) keeps the fox tokens in step, almost everything here can be
 * written once rather than once per scheme: `var(--ink)` already means #26343f
 * in light and #e7edf1 in dark. The primary pair is the documented exception.
 *
 * This file is loaded last (see extra_css in mkdocs.yml.tmpl) and everything
 * below relies on that.
 */

/*
 * Material resolves --md-text-font-family from --md-text-font, and because
 * `theme.font: false` is set it ships no value of its own - these two lines are
 * the entire typography configuration of the site.
 *
 * --wiki-code-font is the settings panel's escape hatch (#4): none of the fox
 * alternates is monospace, so --font-mono never moves with the body font, and
 * a reader who wants code in a system-monospace stack needs a knob of its own.
 * Unset (the default) resolves to exactly what shipped before this existed.
 */
:root {
    --md-text-font: var(--font-sans);
    --md-code-font: var(--wiki-code-font, var(--font-mono));

    /*
     * The settings panel's font-size control (#4). `zoom` rather than a
     * font-size override: Material sets html's font-size itself, per
     * breakpoint (see theme/mkdocs/fox-layout.css and Material's own
     * stylesheet), so redeclaring it here would fix it at one value and lose
     * the responsive scaling underneath. zoom multiplies whatever that
     * resolves to instead, without touching it - and 1 is a true no-op.
     */
    zoom: var(--wiki-font-scale, 1);
}

/*
 * The reader-facing font menu. Set by the inline script in theme/main.html
 * from ?font= or localStorage, applied to <html> before first paint - so there
 * is no flash of the wrong family, and so Gotenberg, which loads the page with
 * ?font=serif, gets a correctly styled document on its first and only render.
 *
 * Headings used to be pinned to Sylexiad regardless of this toggle - fox.css's
 * own h1-h6 rule, not a decision this file made. As of fox-cdn v39 that rule
 * reads var(--font-heading, var(--font-sans)) instead: unset by default, so
 * headings now follow whichever face is active here, including the three
 * accessibility alternates below. The typography settings panel's heading
 * control is what sets --font-heading for a reader who wants Sylexiad back.
 *
 * opendyslexic/luciole/lexend need no selector of their own: fox.css v39
 * already repoints --font-sans (and --font-serif) for those three data-font
 * values, and the :root rule above only ever reads var(--font-sans) - so the
 * resolved value is already correct by the time it gets here.
 */
[data-font="serif"] {
    --md-text-font: var(--font-serif);
}

/*
 * Not a fox family - fox-cdn ships no system-stack option, and #4 asks for one
 * "so it works with no network". Only the body face changes: fox.css's
 * h1-h6 rule reads its own --font-sans (Atkinson), which this does not touch,
 * so headings stay fox's default unless the settings panel's heading control
 * is also used.
 */
[data-font="system"] {
    --md-text-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
}

/*
 * fox.css sets `body { font-family: var(--font-sans) }` directly, which would
 * pin body-level text to sans no matter what the toggle says - Material only
 * applies --md-text-font-family further down, on .md-typeset. Routing body
 * through Material's variable puts both under the toggle.
 *
 * fox.css's companion `body { background: var(--dusk); color: var(--ink) }` is
 * deliberately left alone: it now agrees with --md-default-bg-color /
 * --md-default-fg-color below rather than fighting them.
 */
body {
    font-family: var(--md-text-font-family);
}

/* ================================================ typography settings
 *
 * The rest of what the settings panel offers (#4), beyond the body font
 * above. wiki.js only ever sets these as inline custom properties on <html>
 * when a reader picks a non-default value, and removes them again on reset -
 * so every fallback below has to be the value this site already rendered
 * before this block existed, confirmed against Material's own compiled CSS
 * rather than guessed:
 *
 *   .md-typeset      line-height: 1.6, no letter-/word-spacing of its own
 *   .md-typeset p    no margin/text-align/text-indent of its own, so the
 *                    fallbacks are the UA defaults (1em block margin, start,
 *                    no indent)
 *   .md-content__inner  no max-width of its own
 *
 * A reader who has never opened the panel must see exactly what shipped
 * before it existed.
 */
.md-typeset {
    letter-spacing: var(--wiki-letter-spacing, normal);
    word-spacing: var(--wiki-word-spacing, normal);
    line-height: var(--wiki-line-height, 1.6);
}

.md-typeset p {
    margin-block: var(--wiki-paragraph-spacing, 1em);
    text-align: var(--wiki-text-align, start);
    text-indent: var(--wiki-paragraph-indent, 0);
}

/* The UI chrome knob (#4): the sidebar, its menus and the back-to-top button,
   which otherwise just inherit body's font like everything else - `inherit`
   is what makes an unset preference a no-op. */
.wiki-sidebar,
.wiki-top,
.md-typeset .wiki-menu,
.md-typeset .wiki-settings {
    font-family: var(--wiki-ui-font, inherit);
}

/* ============================================================ palette
 *
 * One block for both schemes. The tokens on the right resolve through
 * html[data-theme], which theme/main.html keeps equal to the scheme, so each
 * line below is already both its light and its dark value.
 *
 * The selector targets <body>, where Material puts the scheme attribute, while
 * Material's own defaults sit on :root. Same specificity, but custom properties
 * inherit, so the body-level value is the one everything inside the page sees.
 */
[data-md-color-scheme="default"],
[data-md-color-scheme="slate"] {
    /* Text. --lighter/--lightest back dividers and disabled chrome, which is
       what --tint-hairline exists for. */
    --md-default-fg-color: var(--ink);
    --md-default-fg-color--light: var(--ink-soft);
    --md-default-fg-color--lighter: rgba(var(--tint-hairline), 0.8);
    --md-default-fg-color--lightest: rgba(var(--tint-hairline), 0.25);

    /* Surfaces. fox splits these two: --dusk is the layout backdrop and --snow
       is a card face. Material has no card, so .md-content__inner is given one
       below - without it the backdrop reads as a flat grey page. */
    --md-default-bg-color: var(--dusk);
    --md-default-bg-color--light: rgba(var(--overlay-glass), 0.7);
    --md-default-bg-color--lighter: rgba(var(--overlay-glass), 0.3);
    --md-default-bg-color--lightest: rgba(var(--overlay-glass), 0.12);

    /* Accent = the hover/active step. fox has no accent hue for this: the
       palette's coloured tokens are category signals, not interaction states,
       and .fox-btn steps through --ink-soft instead. */
    --md-accent-fg-color: var(--ink-soft);
    --md-accent-fg-color--transparent: rgba(var(--tint-hairline), 0.15);
    --md-accent-bg-color: var(--snow);
    --md-accent-bg-color--light: var(--snow);

    --md-typeset-color: var(--ink);
    /* Links are ink, not a hue: none of the accent tokens clears 4.5:1 as text
       on --snow (--ice 1.9:1, --slate 2.9:1, --dawn 3.9:1), and the design
       system's rule is that hue is never the only carrier of meaning. The
       underline further down is what marks a link. */
    --md-typeset-a-color: var(--ink);
    --md-typeset-mark-color: rgba(var(--tint-ice), 0.5);
    --md-typeset-del-color: rgba(var(--tint-dawn), 0.3);
    --md-typeset-ins-color: color-mix(in srgb, var(--moss) 30%, transparent);
    --md-typeset-table-color: var(--hairline);

    /* Code sits inside the --snow card, so its fill is a hairline tint rather
       than a second surface colour. The --md-code-hl-* token colours are left
       to Material's per-scheme values. */
    --md-code-fg-color: var(--ink);
    --md-code-bg-color: rgba(var(--tint-hairline), 0.18);

    /* Admonitions are inside the card too, so they take --snow rather than the
       --dusk backdrop; their border and title colour come from the register
       encoding further down. */
    --md-admonition-fg-color: var(--ink);
    --md-admonition-bg-color: var(--snow);

    /* The version banner. Not enabled here (no extra.version), but leaving it
       Material orange would be a loose end if it ever is. */
    --md-warning-fg-color: var(--ink);
    --md-warning-bg-color: rgba(var(--tint-dawn), 0.35);

    /* Derived from the primary pair below, so the footer always matches the
       header rather than needing its own per-scheme block. */
    --md-footer-fg-color: var(--md-primary-bg-color);
    --md-footer-fg-color--light: color-mix(in srgb, var(--md-primary-bg-color) 70%, transparent);
    --md-footer-fg-color--lighter: color-mix(in srgb, var(--md-primary-bg-color) 45%, transparent);
    --md-footer-bg-color: var(--md-primary-fg-color);
    --md-footer-bg-color--dark: color-mix(in srgb, var(--md-primary-fg-color) 88%, #000);

    /* --shadow-ink is a triple rather than a resolved rgba() precisely so each
       call site keeps its own alpha; it stays black-based in dark mode because
       a shadow is occluded light, not a themed surface. */
    --md-shadow-z1: 0 0.2rem 0.5rem rgba(var(--shadow-ink), 0.05), 0 0 0.05rem rgba(var(--shadow-ink), 0.1);
    --md-shadow-z2: 0 0.2rem 0.5rem rgba(var(--shadow-ink), 0.1), 0 0 0.05rem rgba(var(--shadow-ink), 0.25);
    --md-shadow-z3: 0 0.2rem 0.5rem rgba(var(--shadow-ink), 0.2), 0 0 0.05rem rgba(var(--shadow-ink), 0.35);
}

/*
 * The one thing that cannot be written once. Everywhere else an inverting token
 * is what we want; here it is not. --ink is #26343f in light and #e7edf1 in
 * dark, so a header pinned to it flips to a near-white bar in dark mode - which
 * is right for .fox-btn-primary, and wrong for a page header. Dark mode instead
 * gets the elevated --snow surface (#1e262d) on the --dusk backdrop (#12171b),
 * which is how fox stacks surfaces in the dark palette.
 *
 * Do not fold these back into the block above.
 */
[data-md-color-scheme="default"] {
    --md-primary-fg-color: var(--ink);
    --md-primary-fg-color--light: var(--ink-soft);
    --md-primary-fg-color--dark: var(--btn-primary-hover);
    --md-primary-bg-color: var(--snow);
    --md-primary-bg-color--light: rgba(var(--overlay-glass), 0.7);
}

[data-md-color-scheme="slate"] {
    --md-primary-fg-color: var(--snow);
    --md-primary-fg-color--light: var(--hairline);
    --md-primary-fg-color--dark: var(--dusk);
    --md-primary-bg-color: var(--ink);
    --md-primary-bg-color--light: var(--ink-soft);
}

/* ============================================================ surfaces */

/*
 * The card. Material lays its content straight onto the page background; fox
 * puts a --snow panel on the --dusk backdrop (see .fox-settings). This is the
 * rule that makes --md-default-bg-color: var(--dusk) read as a backdrop.
 * Flattened again for print, at the bottom of this file.
 */
.md-content__inner {
    background: var(--snow);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-card);
    padding: 0.8rem 1.2rem 1.2rem;
    /* The settings panel's measure control (#4). No max-width of its own
       today, so "none" is a true no-op for an unset preference. */
    max-width: var(--wiki-measure, none);
}

/*
 * Material sets `fill: currentcolor` on the logo <svg>, which is fine for its
 * own solid glyphs and fatal for ours: a CSS declaration beats the fill="none"
 * presentation attribute the mark carries, flooding every stroked path and
 * rendering the fox head as a blob. Put it back.
 *
 * The nose keeps its fill because fill="currentColor" is a presentation
 * attribute *on that path*, which beats a value inherited from the <svg>.
 */
.md-header__button.md-logo svg,
.md-nav__title .md-nav__button.md-logo svg {
    fill: none;
}

/*
 * Material draws h1 in --md-default-fg-color--light. fox draws every heading in
 * --ink, and the h1 is the one place the two disagree.
 */
.md-typeset h1 {
    color: var(--ink);
}

/* ============================================================ links */

/*
 * Scoped to .md-typeset so the nav, the table of contents and the header are
 * left alone - underlining those would be noise. The underline is the accessible
 * carrier here, per the --md-typeset-a-color comment above.
 */
.md-typeset a {
    text-decoration: underline;
    text-decoration-color: var(--hairline);
    text-underline-offset: 0.15em;
}

.md-typeset a:hover,
.md-typeset a:focus {
    color: var(--ink);
    text-decoration-color: var(--ink);
}

/*
 * With --md-typeset-a-color pinned to --ink, Material's "you are here" marker
 * in the nav and the table of contents became invisible - it was colour-only.
 * Rebuilt out of weight plus a rule, so it survives at any vision.
 */
.md-nav__item .md-nav__link--active,
.md-nav__item .md-nav__link--active:hover {
    font-weight: 700;
    box-shadow: inset 0.15rem 0 0 var(--ice);
    /* Cancelled by the negative margin, so the marker does not shift the text
       of the active item out of line with its siblings. */
    padding-left: 0.4rem;
    margin-left: -0.4rem;
}

/* Matches .fox-btn:focus-visible in fox.css. */
.md-typeset a:focus-visible,
.md-nav__link:focus-visible,
.md-typeset .md-button:focus-visible,
.md-header__button:focus-visible,
.md-search__input:focus-visible {
    outline: 2px solid var(--ice);
    outline-offset: 2px;
}

/* ============================================================ buttons */

/*
 * .md-button rebuilt as .fox-btn. This is also what restyles the font and PDF
 * buttons in .wiki-actions below, which are .md-buttons inside .md-typeset.
 */
.md-typeset .md-button {
    background: var(--snow);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-ui);
    color: var(--ink);
    transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275),
                background-color 0.2s ease,
                border-color 0.2s ease,
                box-shadow 0.2s ease;
}

.md-typeset .md-button:hover,
.md-typeset .md-button:focus {
    background: rgba(var(--tint-hairline), 0.1);
    border-color: var(--ink-soft);
    color: var(--ink);
    transform: translateY(-1px);
    box-shadow: 0 4px 8px rgba(var(--shadow-ink), 0.05);
}

.md-typeset .md-button:active {
    transform: translateY(0);
    box-shadow: none;
}

.md-typeset .md-button--primary {
    background: var(--ink);
    border-color: var(--ink);
    color: var(--snow);
}

.md-typeset .md-button--primary:hover,
.md-typeset .md-button--primary:focus {
    background: var(--btn-primary-hover);
    border-color: var(--btn-primary-hover);
    color: var(--snow);
    box-shadow: 0 4px 12px rgba(var(--shadow-ink), 0.15);
}

.wiki-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin: 0 0 1.2rem;
}

.wiki-actions .md-button {
    padding: 0.3em 0.8em;
    font-size: 0.78rem;
}

/* ---------------------------------------------------------- action menu
 *
 * A <details> disclosure, so the open/close state, the focus behaviour and the
 * keyboard all come from the element rather than from script. The only styling
 * decisions here are removing the default marker, which would sit next to a
 * button label and read as a bullet, and putting the panel on a layer.
 */
/*
 * Material draws every <details> inside .md-typeset as a collapsible
 * admonition: a bordered card whose <summary> is a title bar with a per-type
 * icon and a chevron. That is right for `??? note` and wrong for a menu, and
 * the admonition block further down would tint it as well - hence the
 * :not(.wiki-menu) on those selectors. This puts the element back to nothing so
 * the .md-button rule above can style the summary as the button it is.
 */
.md-typeset details.wiki-menu {
    position: relative;
    display: inline-block;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
    font-size: inherit;
}

.md-typeset .wiki-menu > summary {
    display: inline-block;
    padding: 0.3em 0.8em;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-ui);
    background: var(--snow);
    cursor: pointer;
    font-size: 0.78rem;
    list-style: none;
    user-select: none;
}

/* Material's own marker and admonition icon, both drawn with pseudo-elements
   and both positioned absolutely inside the title bar this no longer has. */
.md-typeset .wiki-menu > summary::before,
.md-typeset .wiki-menu > summary::-webkit-details-marker {
    display: none;
}

.md-typeset .wiki-menu > summary::after {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    /* Material draws its chevron by masking a background colour through an
       inline SVG. Left in place, that mask clips our text glyph to the shape of
       the chevron and the caret renders as a sliver. */
    background: none;
    -webkit-mask-image: none;
    mask-image: none;
    content: " ▾";
    transform: none;
}

.md-typeset .wiki-menu[open] > summary::after {
    content: " ▴";
}

.wiki-menu__panel {
    position: absolute;
    z-index: 3;
    top: calc(100% + 0.25rem);
    left: 0;
    display: flex;
    min-width: 12rem;
    flex-direction: column;
    padding: 0.25rem;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-ui);
    background: var(--snow);
    box-shadow: 0 6px 16px rgba(var(--shadow-ink), 0.12);
}

/* Written as one selector for <button> and <a> alike: the copy action cannot be
   a link because it has no target, and the other three cannot be buttons
   because they are downloads - but they are one menu and must not look like
   two. The .md-typeset prefix is what beats Material's own anchor styling. */
.md-typeset .wiki-menu__item {
    padding: 0.4em 0.6em;
    border: 0;
    border-radius: var(--radius-ui);
    margin: 0;
    background: none;
    color: var(--ink);
    font: inherit;
    font-size: 0.72rem;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
}

.md-typeset .wiki-menu__item:hover,
.md-typeset .wiki-menu__item:focus-visible {
    background: rgba(var(--tint-hairline), 0.14);
    color: var(--ink);
}

/* ====================================================== print page
 *
 * /print_page/ is built by bin/build-print-page.py from templates/
 * print-page.html.tmpl, not by either engine, so it carries no theme chrome and
 * needs its own cover, contents and section rules. Everything else on it -
 * typography, admonitions, tables, code - is the shared styling above, which is
 * why it sets .md-typeset on <body>.
 */
.print-page {
    max-width: 46rem;
    margin: 0 auto;
    padding: 1.5rem;
    background: var(--snow);
    color: var(--ink);
}

.print-page__cover {
    padding-bottom: 1.5rem;
    border-bottom: 2px solid var(--ink);
    margin-bottom: 1.5rem;
}

.print-page__meta {
    margin: 0.2rem 0 0;
    color: var(--ink-soft);
    font-size: 0.75rem;
}

.print-page__contents {
    margin-bottom: 2rem;
}

/* Each page starts on a fresh sheet, which is what makes the concatenation read
   as a document rather than as eight pages run together. */
.print-page__section {
    margin-bottom: 2.5rem;
}

.print-page__title {
    padding-bottom: 0.3rem;
    border-bottom: 1px solid var(--hairline);
}

@media print {
    .print-page {
        max-width: none;
        padding: 0;
    }

    .print-page__section {
        break-before: page;
    }

    .print-page__cover {
        break-after: page;
    }
}

/* ==================================================== sidebar chrome
 *
 * Search and the settings button, which used to live in the top bar (issue
 * #1) - the settings modal it opens also holds the light/dark toggle (#8),
 * duplicated as an icon button in the page header (see .wiki-page-header
 * below). The markup is ours and the Hugo theme emits the same class names,
 * so this block styles both engines.
 */
.wiki-sidebar {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    /* The top margin is not decoration: Material's sidebar title is sticky and
       carries a 0.4rem background-coloured box-shadow to mask the nav scrolling
       under it, which without a gap bleeds over the search field. */
    margin: 0.5rem 0 0.6rem;
    padding: 0 0.6rem 0.6rem;
    border-bottom: 1px solid var(--hairline);
}

.wiki-sidebar__search {
    position: relative;
}

/* Present for screen readers and for the accessible name; the placeholder
   carries the visible affordance. */
.wiki-sidebar__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
}

.wiki-sidebar__input {
    width: 100%;
    padding: 0.4em 0.6em;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-ui);
    background: var(--snow);
    color: var(--ink);
    font: inherit;
    font-size: 0.78rem;
}

.wiki-sidebar__input:focus {
    border-color: var(--ink-soft);
    outline: none;
}

.wiki-search__results:not(:empty) {
    display: flex;
    flex-direction: column;
    max-height: 60vh;
    margin-top: 0.3rem;
    padding: 0.25rem;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-ui);
    background: var(--snow);
    overflow-y: auto;
}

.wiki-search__hit {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    padding: 0.4em 0.5em;
    border-radius: var(--radius-ui);
    color: var(--ink);
    text-decoration: none;
}

.wiki-search__hit:hover,
.wiki-search__hit:focus-visible {
    background: rgba(var(--tint-hairline), 0.14);
}

.wiki-search__title {
    font-size: 0.78rem;
    font-weight: 700;
}

.wiki-search__empty {
    font-size: 0.7rem;
    color: var(--ink-soft);
}

.wiki-search__snippet {
    font-size: 0.7rem;
    color: var(--ink-soft);
    line-height: 1.4;
}

.wiki-search__empty {
    margin: 0;
    padding: 0.4em 0.5em;
}

.wiki-sidebar__options {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

/*
 * The settings modal (#4, #6, #8). A <dialog> rather than the old <details>
 * popover, whose width (max(16rem, 100%)) always overflowed the sidebar's own
 * column and could be clipped by the sidebar's own sticky/overflow:auto
 * scroll container - see wiki-settings.html. showModal() renders in the top
 * layer instead, which has neither problem.
 *
 * It replaces what used to be a single two-way toggle button: five font
 * variants is a menu, not something a click can cycle through, and #4's other
 * knobs (plus the light/dark toggle, #8) live in the same modal rather than a
 * handful of separate controls next to it.
 */
.wiki-sidebar__font {
    display: block;
    width: 100%;
    padding: 0.3em 0.6em;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-ui);
    background: var(--snow);
    color: var(--ink);
    cursor: pointer;
    font: inherit;
    font-size: 0.7rem;
    text-align: left;
}

.wiki-sidebar__font:hover {
    background: rgba(var(--tint-hairline), 0.1);
    border-color: var(--ink-soft);
}

dialog.wiki-settings {
    position: fixed;
    inset: 0;
    z-index: 3;
    width: min(28rem, 92vw);
    max-height: min(80vh, 44rem);
    margin: auto;
    padding: 0;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-card);
    background: var(--snow);
    color: var(--ink);
    box-shadow: 0 12px 32px rgba(var(--shadow-ink), 0.25);
}

dialog.wiki-settings::backdrop {
    background: rgba(var(--shadow-ink), 0.45);
}

.wiki-settings__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.6rem 0.8rem;
    border-bottom: 1px solid var(--hairline);
}

.wiki-settings__header h2 {
    margin: 0;
    font-size: 0.85rem;
}

.wiki-settings__close {
    padding: 0.2em 0.6em;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-ui);
    background: var(--snow);
    color: var(--ink);
    cursor: pointer;
    font: inherit;
    line-height: 1;
}

.wiki-settings__close:hover {
    background: rgba(var(--tint-hairline), 0.1);
    border-color: var(--ink-soft);
}

.wiki-settings__panel {
    display: flex;
    max-height: calc(min(80vh, 44rem) - 2.6rem);
    flex-direction: column;
    gap: 0.5rem;
    padding: 0.6rem 0.8rem;
    overflow-y: auto;
}

.wiki-settings__group {
    padding: 0;
    border: 0;
    margin: 0;
}

.wiki-settings__group legend {
    padding: 0 0 0.15rem;
    color: var(--ink-soft);
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.wiki-settings__group select {
    width: 100%;
    padding: 0.3em 0.5em;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-ui);
    background: var(--snow);
    color: var(--ink);
    font: inherit;
    font-size: 0.76rem;
}

.wiki-settings__check {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.76rem;
}

.wiki-settings__note {
    padding-top: 0.4rem;
    border-top: 1px solid var(--hairline);
    margin: 0;
    color: var(--ink-soft);
    font-size: 0.7rem;
}

/*
 * The light/dark toggle (#8): one look, used both as a labelled control
 * inside the settings modal and, with --quick, as an icon-only button in the
 * page header. The icon itself is injected by wiki.js from fox-cdn's icon
 * set; the label stays in the DOM either way for screen readers and as a
 * fallback if that fetch fails.
 */
.wiki-theme-toggle {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.3em 0.6em;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-ui);
    background: var(--snow);
    color: var(--ink);
    cursor: pointer;
    font: inherit;
    font-size: 0.76rem;
}

.wiki-theme-toggle:hover {
    background: rgba(var(--tint-hairline), 0.1);
    border-color: var(--ink-soft);
}

.wiki-theme-toggle__icon svg {
    display: block;
    width: 1.1rem;
    height: 1.1rem;
}

.wiki-theme-toggle--quick {
    padding: 0.4em;
}

.wiki-theme-toggle--quick .wiki-theme-toggle__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
}

.wiki-top {
    position: fixed;
    right: 1rem;
    bottom: 1rem;
    z-index: 4;
    padding: 0.4em 0.8em;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-ui);
    background: var(--snow);
    color: var(--ink);
    cursor: pointer;
    font: inherit;
    font-size: 0.68rem;
    box-shadow: 0 4px 12px rgba(var(--shadow-ink), 0.12);
}

.wiki-top[hidden] {
    display: none;
}

/* ======================================================= page furniture
 *
 * The meta line and the prev/next footer (issue #1). Both render values
 * bin/manifest.py wrote into the page's front matter; neither of the rules
 * below know that, which is why the same block styles the Hugo theme's output
 * too - it emits the same class names deliberately.
 *
 * Hidden in print, at the bottom of this file, along with .wiki-actions: a
 * "next page" link means nothing in a PDF.
 */
/*
 * The export menu, the meta line and the theme quick-toggle share one row
 * (#8) instead of each taking a full-width row of their own - .wiki-meta
 * takes the space left over, and the toggle pins to the far edge.
 */
.wiki-page-header {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.6rem;
    margin: 0 0 1.2rem;
    padding-bottom: 0.6rem;
    border-bottom: 1px solid var(--hairline);
}

.wiki-page-header .wiki-theme-toggle {
    flex: 0 0 auto;
}

.wiki-meta {
    display: flex;
    flex: 1 1 auto;
    flex-wrap: wrap;
    gap: 0.2rem 0.9rem;
    margin: 0;
    font-size: 0.78rem;
    color: var(--ink-soft);
}

/* The link inside the meta line keeps the underline that marks every link on
   this site - the row is quiet, but a link in it is still a link. */
.md-typeset .wiki-meta a {
    color: var(--ink-soft);
}

.wiki-nextprev {
    display: flex;
    gap: 0.6rem;
    margin: 2rem 0 0;
    padding-top: 1rem;
    border-top: 1px solid var(--hairline);
}

.md-typeset .wiki-nextprev__link {
    display: flex;
    flex: 1 1 0;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.6rem 0.8rem;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-ui);
    color: var(--ink);
    text-decoration: none;
    transition: border-color 0.2s ease, background-color 0.2s ease;
}

/* A lone "next" link sits on the right, where it would be if there were two. */
.wiki-nextprev__link--next {
    margin-left: auto;
    text-align: right;
}

.md-typeset .wiki-nextprev__link:hover {
    background: rgba(var(--tint-hairline), 0.1);
    border-color: var(--ink-soft);
}

.wiki-nextprev__dir {
    font-size: 0.62rem;
    color: var(--ink-soft);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.wiki-nextprev__title {
    font-size: 0.75rem;
}

/* ============================================================ admonitions
 *
 * The 7-way register encoding from the fox usage guide, which exists precisely
 * because three signal hues are not enough to separate this many categories.
 * Colour is never the only carrier: Material's per-type glyph and the printed
 * title stay exactly as they were.
 *
 * Each family only assigns --fox-admonition; the four generic rules underneath
 * do the drawing. They carry an extra [class] to reach the specificity of
 * Material's own per-type rules (.md-typeset .admonition.note), which they
 * would otherwise lose to.
 */
.md-typeset .admonition.note, .md-typeset details.note,
.md-typeset .admonition.info, .md-typeset details.info,
.md-typeset .admonition.todo, .md-typeset details.todo {
    --fox-admonition: var(--ice);
}

.md-typeset .admonition.tip, .md-typeset details.tip,
.md-typeset .admonition.hint, .md-typeset details.hint,
.md-typeset .admonition.important, .md-typeset details.important,
.md-typeset .admonition.success, .md-typeset details.success,
.md-typeset .admonition.check, .md-typeset details.check,
.md-typeset .admonition.done, .md-typeset details.done {
    --fox-admonition: var(--moss);
}

.md-typeset .admonition.warning, .md-typeset details.warning,
.md-typeset .admonition.caution, .md-typeset details.caution,
.md-typeset .admonition.attention, .md-typeset details.attention {
    --fox-admonition: var(--birch);
}

/* --dawn is the palette's "wichtig / urgent crisis" signal, so it is reserved
   for the families that actually mean something went wrong - warning above is
   only cautionary and gets --birch. */
.md-typeset .admonition.danger, .md-typeset details.danger,
.md-typeset .admonition.error, .md-typeset details.error,
.md-typeset .admonition.failure, .md-typeset details.failure,
.md-typeset .admonition.fail, .md-typeset details.fail,
.md-typeset .admonition.missing, .md-typeset details.missing,
.md-typeset .admonition.bug, .md-typeset details.bug {
    --fox-admonition: var(--dawn);
}

.md-typeset .admonition.question, .md-typeset details.question,
.md-typeset .admonition.help, .md-typeset details.help,
.md-typeset .admonition.faq, .md-typeset details.faq {
    --fox-admonition: var(--aurora);
}

.md-typeset .admonition.abstract, .md-typeset details.abstract,
.md-typeset .admonition.summary, .md-typeset details.summary,
.md-typeset .admonition.tldr, .md-typeset details.tldr,
.md-typeset .admonition.example, .md-typeset details.example {
    --fox-admonition: var(--slate);
}

.md-typeset .admonition.quote, .md-typeset details.quote,
.md-typeset .admonition.cite, .md-typeset details.cite {
    --fox-admonition: var(--hairline);
}

/* An admonition of an unrecognised type gets --hairline rather than nothing. */
.md-typeset .admonition[class],
.md-typeset details[class]:not(.wiki-menu) {
    border-color: var(--fox-admonition, var(--hairline));
    border-radius: var(--radius-card);
}

.md-typeset .admonition[class] > .admonition-title,
.md-typeset details[class]:not(.wiki-menu) > summary {
    /* color-mix rather than an rgba() over the card, so the fill stays opaque
       and survives Gotenberg's printBackground pass unchanged. */
    background-color: color-mix(in srgb, var(--fox-admonition, var(--hairline)) 16%, var(--snow));
}

.md-typeset .admonition[class] > .admonition-title::before,
.md-typeset details[class]:not(.wiki-menu) > summary::before,
.md-typeset .admonition[class] > .admonition-title::after,
.md-typeset details[class]:not(.wiki-menu) > summary::after {
    background-color: var(--fox-admonition, var(--hairline));
    color: var(--fox-admonition, var(--hairline));
}

.md-typeset .admonition[class]:focus-within,
.md-typeset details[class]:not(.wiki-menu):focus-within {
    box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--fox-admonition, var(--hairline)) 20%, transparent);
}

/* ============================================================ radii
 *
 * fox rounds to exactly two radii - --radius-ui for controls, --radius-card for
 * surfaces - where Material rounds nearly everything to .1rem/.2rem.
 */
.md-typeset code,
.md-search__form,
.md-search__output {
    border-radius: var(--radius-ui);
}

.md-typeset pre > code,
.md-typeset .highlight > pre,
.md-typeset .highlighttable,
.md-typeset table:not([class]) {
    border-radius: var(--radius-card);
}

/* Tables sit on the card, not on the --dusk backdrop. */
.md-typeset table:not([class]) {
    background-color: var(--snow);
}

.md-typeset table:not([class]) th {
    background-color: rgba(var(--tint-hairline), 0.2);
    color: var(--ink);
}

/*
 * Gotenberg is told preferCssPageSize=true, so this rule - not Gotenberg's own
 * Letter default - decides the page geometry. The bottom margin is wider than
 * the top to leave room for the Chromium footer template
 * (templates/footer.html.tmpl); without the space the footer is simply not
 * drawn, with no error anywhere.
 *
 * Deliberately NOT inside @media print: @page only ever applies to paged
 * output, and nesting it would make the margin-box resets below stop applying
 * the moment something renders with screen emulation.
 */
@page {
    size: A4;
    /* Asymmetric: the extra bottom margin is where the Gotenberg footer
       template from templates/footer.html.tmpl is drawn. Nothing competes for
       the margin boxes any more - mkdocs-print-site-plugin used to declare its
       own page numbers there and needed cancelling, and it is gone. */
    margin: 16mm 15mm 20mm;
}

@media print {
    /*
     * Gotenberg renders with printBackground=true, so the --dusk backdrop would
     * tint every sheet edge to edge. --snow rather than a literal white because
     * on paper snow *is* the substrate - it separates to roughly 0/0/0/0, which
     * is the correct thing to ask a press for.
     */
    [data-md-color-scheme] {
        --md-default-bg-color: var(--snow);
    }

    /* No backdrop to sit on any more, so the card has nothing to be. */
    .md-content__inner {
        background: none;
        border: 0;
        box-shadow: none;
        padding: 0;
    }

    /* Screen furniture that means nothing on paper. The copy-to-clipboard
       button comes with content.code.copy and used to hide in Material's own
       7%-black --md-default-fg-color--lightest; against the fox hairline tint
       it is visible enough to print, so it is named here explicitly. */
    .wiki-page-header,
    .wiki-actions,
    .wiki-drawer,
    .wiki-sidebar,
    .wiki-top,
    .wiki-meta,
    .wiki-nextprev,
    .md-header,
    .md-sidebar,
    .md-footer,
    .md-top,
    .md-search,
    .md-clipboard,
    .md-code__button {
        display: none !important;
    }

    .md-main__inner,
    .md-content {
        margin: 0 !important;
        max-width: none !important;
    }

    /* Keep a heading with the text it introduces. */
    h1, h2, h3, h4, h5, h6 {
        break-after: avoid;
        page-break-after: avoid;
    }

    pre, blockquote, table {
        break-inside: avoid;
        page-break-inside: avoid;
    }
}
