/*!
 * ovcomponents — static global HTML/CSS components; no build or runtime.
 * This is the canonical single stylesheet for the component layer and the
 * native page/prose presentation; a static consumer loads only this file.
 * All classes and tokens are plain globals: no scope namespace, no namespace
 * root, and no collision guard. The default palette is red.
 * Inherited Terminus/Tabi software notices: notices/Terminus-Tabi-MIT.txt.
 * Tabi source: https://github.com/welpo/tabi/blob/93af295/sass/parts/_admonitions.scss
 * Fonts carry separate MIT/OFL notices under fonts/.
 * No outbound project license is chosen for original ovcomponents work.
 */

/* Tokens default on :root and are recomputed on [data-theme] so a themed
   element (including a nested themed region) resolves its own palette. */

/* Keyframe names are document-wide; the finite effects below use them. */

@keyframes terminal-dither {
    0% {
        -webkit-mask-image: repeating-conic-gradient(#000 0 25%, transparent 0 100%);
        mask-image: repeating-conic-gradient(#000 0 25%, transparent 0 100%);
        -webkit-mask-size: 4px 4px;
        mask-size: 4px 4px;
        clip-path: inset(0 75% 0 0);
    }
    33% {
        -webkit-mask-image: repeating-conic-gradient(#000 0 25%, transparent 0 50%);
        mask-image: repeating-conic-gradient(#000 0 25%, transparent 0 50%);
        -webkit-mask-size: 4px 4px;
        mask-size: 4px 4px;
        clip-path: inset(0 50% 0 0);
    }
    66% {
        -webkit-mask-image: repeating-conic-gradient(#000 0 75%, transparent 0 100%);
        mask-image: repeating-conic-gradient(#000 0 75%, transparent 0 100%);
        -webkit-mask-size: 4px 4px;
        mask-size: 4px 4px;
        clip-path: inset(0 25% 0 0);
    }
    100% {
        -webkit-mask-image: none;
        mask-image: none;
        clip-path: inset(0);
    }
}

@keyframes terminal-title-reveal {
    from {
        clip-path: inset(0 100% 0 0);
    }
    to {
        clip-path: inset(0);
    }
}


/* ======================================================================
   1. Tokens
   ----------------------------------------------------------------------
   Static tokens live on :root. The derived colour and fringe tokens are
   declared on :root *and* [data-theme] so that a themed element (including
   a nested themed region) recomputes or resets them from its own palette
   instead of inheriting the ancestor's resolved colours.
   ====================================================================== */

:root,
[data-theme] {
    /* Cozette Vector first (400/800 are self-hosted in fonts.css); Fira
       Code is the optional fallback. The core never loads a font itself. */
    --font-family: 'Cozette Vector', 'Fira Code', ui-monospace, Monaco, Consolas, 'Ubuntu Mono', monospace;

    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-6: 1.5rem;

    /* Square by default: controls, panels, and badges share the pixel
       grid. */
    --radius-control: 0;
    --radius-panel: 0;
    --control-height: 2.5rem;

    --surface: color-mix(in srgb, var(--background-color) 98%, var(--text-color) 2%);
    --border: color-mix(in srgb, var(--text-color) 25%, var(--background-color));

    /* Chromatic fringes. Only the chromatic palette switches these on: the
       hairline image stays `none` in every other palette, so the brand/panel
       decorations that paint it stay invisible, and the two
       terminal-title rule colours fall back to the palette accent exactly as
       those dotted rules always looked. They are redeclared on every themed
       element (this rule matches :root *and* [data-theme]), so a nested
       non-chromatic themed region resets the fringe instead of inheriting
       it. A plain themed element ([data-theme] whose value matches no
       palette) keeps these defaults and inherits the nearest resolved ink
       from its themed ancestor. */
    --fringe-line: none;
    --title-fringe: none;
    --rule-a: var(--accent-color);
    --rule-b: var(--accent-color);
}

/* Site typography tokens from the ported Terminus theme (section 13). They
   stay on :root: the mobile step is viewport-dependent, not theme-dependent,
   while the palette colours above recompute on [data-theme]. */
:root {
    --font-size: 1rem;
    --line-height: 1.54em;
    /* --radius aliases the 0 panel/control radii; kept verbatim from the legacy
       block for consumer custom stylesheets. */
    --radius: 0;
    --external-link-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Cpath d='M11 5h-6v14h14v-6'/%3E%3Cpath d='M13 11l7 -7'/%3E%3Cpath d='M21 3h-6M21 3v6'/%3E%3C/g%3E%3C/svg%3E");
    --code-border: color-mix(in srgb, var(--text-color) 10%, transparent);
    --code-comment: color-mix(in srgb, var(--text-color) 53%, transparent);
}

@media (max-width: 684px) {
    :root {
        --font-size: 0.95rem;
    }
}

/* ======================================================================
   2. Palettes
   ----------------------------------------------------------------------
   Four colour keys: red (default), green, blue, and chromatic. Each
   palette is exposed on :root (the default), on any themed [data-theme]
   element, on the document body's data-theme when it is set there, and
   through the native radio picker.

   A fieldset.theme-picker inside the document holds radios named `color`;
   :has() applies their checked colour to :root without a script or a
   second palette source. The root's data-theme may stay red while the
   radios drive its computed colours.

   :root carries the default red when nothing else sets a palette. A themed
   element ([data-theme] on an ordinary element) keeps the documented
   fallback and inherits the nearest themed ancestor when its attribute is
   unrecognised. Readable ink uses the palette accent.
   ====================================================================== */

:root,
:root[data-theme="red"],
[data-theme="red"],
:root:has(body[data-theme="red"]),
body:has(> .theme-picker .theme-choice[value="red"]:checked),
:root:has(.theme-picker .theme-choice[value="red"]:checked) {
    --background-color: #040404;
    --text-color: #e00000;
    --accent-color: rgb(255, 55, 55);
    --footnote-color: rgb(150, 0, 0);

    --ink: var(--accent-color);

    color-scheme: dark;
}

/* Green — phosphor-green ink on the shared black field. */
:root[data-theme="green"],
[data-theme="green"],
:root:has(body[data-theme="green"]),
body:has(> .theme-picker .theme-choice[value="green"]:checked),
:root:has(.theme-picker .theme-choice[value="green"]:checked) {
    --background-color: #040404;
    --text-color: #00e000;
    --accent-color: rgb(55, 255, 55);
    --footnote-color: rgb(0, 150, 0);

    --ink: var(--accent-color);

    color-scheme: dark;
}

/* Blue — readable CRT-blue ink on the shared black field. */
:root[data-theme="blue"],
[data-theme="blue"],
:root:has(body[data-theme="blue"]),
body:has(> .theme-picker .theme-choice[value="blue"]:checked),
:root:has(.theme-picker .theme-choice[value="blue"]:checked) {
    --background-color: #040404;
    --text-color: #5573e0;
    --accent-color: #6f8fff;
    --footnote-color: #324c96;

    --ink: var(--accent-color);

    color-scheme: dark;
}

/* Chromatic — neutral ink with restrained red/cyan heading and frame
   fringes. */
:root[data-theme="chromatic"],
[data-theme="chromatic"],
:root:has(body[data-theme="chromatic"]),
body:has(> .theme-picker .theme-choice[value="chromatic"]:checked),
:root:has(.theme-picker .theme-choice[value="chromatic"]:checked) {
    --background-color: #040404;
    --text-color: #f5f5f5;
    --accent-color: #f5f5f5;
    --footnote-color: #999999;

    --ink: var(--accent-color);

    --fringe-line: linear-gradient(to right, #ff375d, #37dfff);
    --title-fringe: -1px 0 #ff375d, 1px 0 #37dfff;
    --rule-a: #ff375d;
    --rule-b: #37dfff;

    color-scheme: dark;
}

/* ----------------------------------------------------------------------
   Native palette picker
   ----------------------------------------------------------------------
   JS-free palette switching: the radios themselves drive the :has()
   palette selectors above. Everything here is presentation for a native
   fieldset and native radios; the checked state, the shared name/group
   semantics, and keyboard navigation stay the browser's. The radios keep
   the palette accent. The :has() palette selectors match a picker that is
   a direct child of the body or anywhere below the root. */

.theme-picker {
    box-sizing: border-box;
    margin: 0;
    padding: var(--space-2) var(--space-3);
    color: var(--ink);
    background-color: transparent;
    border: 1px solid var(--border);
    border-radius: var(--radius-control);
}

.theme-picker > legend {
    padding-inline: var(--space-1);
    color: var(--ink);
    font-size: 0.875rem;
    font-weight: 800;
    letter-spacing: 0.02em;
}

/* Labels stay inline-flex so the native radios and their text sit on one
   row and wrap naturally; the fieldset itself keeps its default display so
   the legend renders in the border gap. */
.theme-picker label {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    margin-inline-end: var(--space-4);
    cursor: pointer;
}

.theme-choice {
    inline-size: 1rem;
    block-size: 1rem;
    margin: 0;
    accent-color: var(--accent-color);
    cursor: pointer;
}

/* ======================================================================
   3. Document base and focus
   ----------------------------------------------------------------------
   The html/body foundation is global: base font, background, ink, line
   height, and border-box sizing. Text, actionable control boundaries, and
   focus rings use --ink, the palette's readable accent. Palette text values
   remain available for decoration and provenance.
   ====================================================================== */

html,
body {
    box-sizing: border-box;
    font-family: var(--font-family);
    font-size: var(--font-size);
    line-height: var(--line-height);
    color: var(--ink);
    background-color: var(--background-color);
    accent-color: var(--accent-color);
}

body {
    margin: 0;
    padding: 0;
    text-rendering: optimizeLegibility;
    -webkit-font-smoothing: antialiased;
    -webkit-overflow-scrolling: touch;
    text-size-adjust: 100%;
    -webkit-text-size-adjust: 100%;
    font-feature-settings: 'liga';
}

*,
*::before,
*::after {
    box-sizing: inherit;
}

:is(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: 2px solid var(--ink);
    outline-offset: 2px;
}

/* ======================================================================
   4. Surfaces
   ====================================================================== */

.panel {
    box-sizing: border-box;
    position: relative;
    padding: var(--space-4);
    color: var(--ink);
    background-color: var(--background-color);
    /* Chromatic fringe: top and bottom hairlines painted from a token that
       is `none` in every other palette, so this frame decoration appears
       only in the chromatic palette and never on body text, controls, or
       status. */
    background-image: var(--fringe-line), var(--fringe-line);
    background-repeat: no-repeat, no-repeat;
    background-position: top left, bottom left;
    background-size: 100% 1px, 100% 1px;
    border: 1px solid var(--accent-color);
    border-radius: var(--radius-panel);
}

/* Top-edge scan: a gradient segment wipes once across the panel's top edge
   on hover/focus, then rests hidden. Stepped, finite, decorative-only. */
.panel::before {
    content: '';
    position: absolute;
    inset-block-start: 0;
    inset-inline: 0;
    block-size: 2px;
    pointer-events: none;
    background-image: linear-gradient(to right, transparent, var(--accent-color), transparent);
    clip-path: inset(0 100% 0 0);
    transition: clip-path 360ms steps(8, end);
}

.panel:is(:hover, :focus-within)::before {
    clip-path: inset(0);
}

/* Native disclosure styled as a terminal window frame. Optional: apply
   only where a collapsible frame reads as a window, and keep body content
   inside .window-body. The <summary> keeps its native display and marker
   (no pseudo-element is added there, so no menu caret is collided with);
   opening wakes the frame with a stepped border/top-rail change only. */
.window {
    box-sizing: border-box;
    position: relative;
    margin: 0;
    inline-size: 100%;
    color: var(--ink);
    background-color: var(--background-color);
    border: 1px solid var(--border);
    border-radius: var(--radius-panel);
    box-shadow: inset 0 0 0 0 var(--accent-color);
    transition: border-color 180ms steps(3, end), box-shadow 180ms steps(3, end);
}

.window[open] {
    border-color: var(--ink);
    box-shadow: inset 0 2px 0 0 var(--accent-color);
}

.window > summary {
    padding: var(--space-2) var(--space-3);
    color: var(--ink);
    font-weight: 800;
    letter-spacing: 0.02em;
    cursor: pointer;
}

.window[open] > summary {
    border-block-end: 1px solid var(--border);
}

.window-body {
    margin: 0;
    padding: var(--space-3) var(--space-4);
}

.window-body > :first-child {
    margin-block-start: 0;
}

.window-body > :last-child {
    margin-block-end: 0;
}

/* ======================================================================
   5. Buttons
   ----------------------------------------------------------------------
   Native `button` keeps type, disabled, activation, and form behaviour.
   The primary label uses inverse ink; other labels use --ink. Motion is a
   stepped edge (a box-shadow inset ring that grows in discrete steps on
   hover/focus and deepens on press) so no pseudo-element is added to prose
   or menu buttons and the existing Terminus menu arrow/caret is left
   untouched. The label never moves.
   ====================================================================== */

.button,
.icon-button,
:where(.prose) button {
    box-sizing: border-box;
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: var(--control-height);
    padding: var(--space-1) var(--space-4);
    font: inherit;
    font-weight: 800;
    line-height: 1.25;
    text-align: center;
    text-decoration: none;
    color: var(--ink);
    background-color: transparent;
    border: 1px solid var(--ink);
    border-radius: var(--radius-control);
    /* Stepped edge: the inset ring rests at zero spread and grows in
       discrete steps on hover/focus (see the rule below and the stepped
       transition). */
    box-shadow: inset 0 0 0 0 var(--ink);
    appearance: none;
    cursor: pointer;
    transition:
        color 120ms steps(3, end),
        background-color 120ms steps(3, end),
        border-color 120ms steps(3, end),
        box-shadow 180ms steps(3, end);
}

.button:hover:not(:disabled):not([aria-disabled="true"]),
.button:focus-visible:not(:disabled):not([aria-disabled="true"]),
.icon-button:hover:not(:disabled):not([aria-disabled="true"]),
.icon-button:focus-visible:not(:disabled):not([aria-disabled="true"]),
.prose button:hover:not(:disabled):not([aria-disabled="true"]),
.prose button:focus-visible:not(:disabled):not([aria-disabled="true"]) {
    box-shadow: inset 0 0 0 3px var(--ink);
}

/* Primary: solid inverse ink block with a background-coloured label. */
.button[data-variant="primary"],
.prose button[data-variant="primary"] {
    color: var(--background-color);
    background-color: var(--ink);
    border-color: var(--ink);
}

.button[data-variant="primary"]:hover:not(:disabled):not([aria-disabled="true"]),
.button[data-variant="primary"]:focus-visible:not(:disabled):not([aria-disabled="true"]),
.prose button[data-variant="primary"]:hover:not(:disabled):not([aria-disabled="true"]),
.prose button[data-variant="primary"]:focus-visible:not(:disabled):not([aria-disabled="true"]) {
    box-shadow: inset 0 0 0 3px var(--background-color);
}

/* Secondary (default): ink outline, unchanged from the base rule. */

/* Ghost: transparent, no boundary; the stepped hover/focus ring still
   gives feedback. */
.button[data-variant="ghost"],
.icon-button[data-variant="ghost"],
.prose button[data-variant="ghost"] {
    color: var(--ink);
    background-color: transparent;
    border-color: transparent;
    box-shadow: none;
}

/* Press/release: the stepped inset edge deepens on activation and steps
   back on release. Edge only — the label itself never moves. */
.button:active:not(:disabled):not([aria-disabled="true"]),
.icon-button:active:not(:disabled):not([aria-disabled="true"]),
.prose button:active:not(:disabled):not([aria-disabled="true"]) {
    box-shadow: inset 0 0 0 5px var(--ink);
}

.button[data-variant="primary"]:active:not(:disabled):not([aria-disabled="true"]),
.prose button[data-variant="primary"]:active:not(:disabled):not([aria-disabled="true"]) {
    box-shadow: inset 0 0 0 5px var(--background-color);
}

.button[data-variant="ghost"]:active:not(:disabled):not([aria-disabled="true"]),
.icon-button[data-variant="ghost"]:active:not(:disabled):not([aria-disabled="true"]),
.prose button[data-variant="ghost"]:active:not(:disabled):not([aria-disabled="true"]) {
    box-shadow: inset 0 0 0 5px var(--ink);
}

.icon-button {
    min-width: var(--control-height);
    padding: var(--space-1);
    aspect-ratio: 1 / 1;
}

/* Disabled controls keep their text colour but lose the hover edge. */
.button:disabled,
.button[aria-disabled="true"],
.icon-button:disabled,
.icon-button[aria-disabled="true"],
.prose button:disabled,
.prose button[aria-disabled="true"] {
    box-shadow: none;
    cursor: not-allowed;
}

/* ======================================================================
   6. Fields
   ====================================================================== */

.field {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

.field label {
    color: var(--ink);
    font-size: 0.875rem;
    font-weight: 800;
    line-height: 1.54;
    letter-spacing: 0.02em;
}

.control:where(:not([type="checkbox"], [type="radio"])),
.prose input:where(:not([type="checkbox"], [type="radio"])),
.prose select,
.prose textarea {
    box-sizing: border-box;
    width: 100%;
    min-height: var(--control-height);
    padding: var(--space-2) var(--space-3);
    font: inherit;
    color: var(--ink);
    background-color: transparent;
    border: 1px solid var(--ink);
    border-radius: var(--radius-control);
    transition:
        color 120ms steps(3, end),
        background-color 120ms steps(3, end),
        border-color 120ms steps(3, end),
        box-shadow 120ms steps(3, end);
}

.control::placeholder,
.prose input::placeholder,
.prose textarea::placeholder {
    color: var(--ink);
    opacity: 1;
}

/* Focused field: a decorative underline rail steps in under the control
   while the native focus outline remains. Declared before the invalid rule
   so an error rail still takes precedence for an invalid, focused
   field. */
.control:where(:not([type="checkbox"], [type="radio"])):focus-visible,
.prose input:where(:not([type="checkbox"], [type="radio"])):focus-visible,
.prose select:focus-visible,
.prose textarea:focus-visible {
    box-shadow: inset 0 -2px 0 0 var(--accent-color);
}

.control[aria-invalid="true"],
.prose input[aria-invalid="true"],
.prose select[aria-invalid="true"],
.prose textarea[aria-invalid="true"] {
    border-color: var(--ink);
    box-shadow: inset 3px 0 0 var(--ink);
}

/* Native textarea resizing, vertical only. */
textarea.control,
.prose textarea {
    min-height: 5rem;
    resize: vertical;
}

/* Checkboxes and radios stay native, tinted with the palette accent. */
.control[type="checkbox"],
.control[type="radio"] {
    accent-color: var(--accent-color);
}

/* Hint/error text: full contrast, differentiated by size rather than
   opacity. Sizes stay on whole-ish pixel steps so Cozette stays crisp. */
.hint {
    color: var(--ink);
    font-size: 0.8125rem;
    line-height: 1.54;
}

/* ======================================================================
   7. Tables
   ====================================================================== */

.table-scroll {
    box-sizing: border-box;
    max-width: 100%;
    overflow: auto;
    background-color: var(--background-color);
    border: 1px solid var(--accent-color);
    border-radius: var(--radius-panel);
}

.table,
.prose table {
    width: 100%;
    border-collapse: collapse;
}

.table th,
.table td,
.prose table th,
.prose table td {
    padding: var(--space-2);
    text-align: start;
    vertical-align: top;
    border: 1px solid var(--ink);
}

.table th,
.prose table th {
    color: var(--ink);
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.table-scroll > .table thead th {
    position: sticky;
    inset-block-start: 0;
    z-index: 1;
    background-color: var(--background-color);
}

/* ======================================================================
   8. Pagination, notices, badges, navigation, composition
   ----------------------------------------------------------------------
   The status component is `.notice`: the Zola alert shortcode and the
   generated github_alerts reuse it (section 22), so no legacy
   .alert/.alert-content/.alert-title/.alert-icon markup remains.
   ====================================================================== */

.pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

/* Monochrome status. Notices and badges use only the theme's ink over its
   background; the Tabi tone palette retired with the legacy stylesheet, so no
   tone colour is mapped onto these components. Semantics are carried by the
   text plus a border
   weight/style change, so no tone is signalled by colour alone and every
   family preset stays legible: note (and any unknown tone) is solid, tip
   is double, info is dotted, warning is dashed, and danger doubles with a
   heavier edge. Notice text is always ink on the background so embedded
   children and controls stay readable; only the danger badge inverts. */

.notice {
    box-sizing: border-box;
    padding: var(--space-3) var(--space-4);
    color: var(--ink);
    background-color: var(--surface);
    border: 1px solid var(--ink);
    border-inline-start-width: 4px;
    border-radius: var(--radius-control);
}

.notice > :first-child {
    margin-block-start: 0;
}

.notice > :last-child {
    margin-block-end: 0;
}

.notice[data-tone="tip"] {
    border-style: double;
    border-width: 3px;
    border-inline-start-width: 3px;
}

.notice[data-tone="info"] {
    border-style: dotted;
}

.notice[data-tone="warning"] {
    border-style: dashed;
}

.notice[data-tone="danger"] {
    border-style: double;
    border-width: 3px;
    border-inline-start-width: 6px;
}

.badge {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    min-height: 1.5rem;
    padding: 0 var(--space-2);
    font-size: 0.8125rem;
    font-weight: 800;
    line-height: 1.2;
    letter-spacing: 0.02em;
    white-space: nowrap;
    color: var(--ink);
    background-color: var(--surface);
    border: 1px solid var(--ink);
    border-radius: var(--radius-control);
}

.badge[data-tone="tip"] {
    border-style: double;
    border-width: 3px;
}

.badge[data-tone="info"] {
    border-style: dotted;
}

.badge[data-tone="warning"] {
    border-style: dashed;
}

/* Danger badge emphasis: inverse ink block. Notices never invert. */
.badge[data-tone="danger"] {
    color: var(--background-color);
    background-color: var(--ink);
    border-color: var(--ink);
}

.nav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.nav-link {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    min-height: var(--control-height);
    padding: var(--space-1) var(--space-3);
    color: var(--ink);
    background-color: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-control);
    text-decoration: none;
    transition:
        color 120ms steps(3, end),
        background-color 120ms steps(3, end),
        border-color 120ms steps(3, end);
}

.nav-link:hover {
    background-color: color-mix(in srgb, var(--surface) 99%, var(--accent-color) 1%);
}

.nav-link[aria-current="page"] {
    color: var(--ink);
    font-weight: 800;
    background-color: var(--surface);
    border-color: var(--ink);
    box-shadow: inset 0 -2px 0 0 var(--accent-color);
}

.stack {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.cluster {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.grid {
    display: grid;
    gap: var(--space-4);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
}

/* ======================================================================
   9. Terminal masthead, brand, rule, and title
   ----------------------------------------------------------------------
   Static markup primitives for the reference masthead. Consumers compose
   them as native elements: .terminal-header is a wrapping flex row whose
   children are .terminal-brand, .terminal-rule, and the navigation;
   .terminal-title is applied directly to a heading. The rule is purely
   decorative, so mark it aria-hidden. Both reveals are short, finite,
   CSS-only ordered-dither effects: at rest each element is fully drawn, so
   the reduced-motion rule (animation: none) and browsers without mask
   support fall back to the complete static decoration. In the chromatic
   palette only, the brand and the title's dotted rules carry the restrained
   red/cyan fringe; every other palette resolves those tokens to its own
   accent/none.
   ====================================================================== */

.terminal-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
}

.terminal-brand {
    box-sizing: border-box;
    position: relative;
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
    padding: 0.3125rem 0.625rem;
    font-weight: 800;
    line-height: 1.54;
    color: var(--background-color);
    background-color: var(--ink);
    text-decoration: none;
}

/* Chromatic fringe hairline under the brand block. In every other palette
   the line token is `none`, so nothing is painted. */
.terminal-brand::after {
    content: '';
    position: absolute;
    inset-inline: 0;
    inset-block-end: 0;
    block-size: 2px;
    pointer-events: none;
    background-image: var(--fringe-line);
}

.terminal-rule {
    position: relative;
    flex: 1 1 6rem;
    align-self: center;
    min-inline-size: 1.5rem;
    block-size: 2.165rem;
    background-image: repeating-linear-gradient(
        to right,
        var(--accent-color) 0 2px,
        transparent 2px 10px
    );
    /* Four ordered 2×2 thresholds reveal the decorative bars, never
       text. */
    animation: terminal-dither 480ms steps(2, end) both;
}

.terminal-rule::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-color: var(--background-color);
    -webkit-mask-image: repeating-conic-gradient(#000 0 25%, transparent 0 50%);
    mask-image: repeating-conic-gradient(#000 0 25%, transparent 0 50%);
    -webkit-mask-size: 4px 4px;
    mask-size: 4px 4px;
    clip-path: inset(0 100% 0 0);
    transition: clip-path 240ms steps(8, end);
}

.terminal-header:is(:hover, :focus-within) .terminal-rule::after,
.terminal-rule:hover::after,
.panel:focus-within > .terminal-rule::after {
    clip-path: inset(0);
}

.terminal-title {
    position: relative;
    margin-block: 0 var(--space-3);
    padding-block-end: var(--space-2);
    text-shadow: var(--title-fringe);
    color: var(--ink);
    font-size: 1.125rem;
    font-weight: 800;
    line-height: 1.3;
    letter-spacing: 0.02em;
    /* Dotted rule, doubled by an offset pseudo-element line: the dither
       texture of the reference post titles. The two rule tokens default to
       the palette accent and turn red/cyan only inside the chromatic
       palette. */
    border-block-end: 3px dotted var(--rule-a);
}

.terminal-title::after {
    content: '';
    position: absolute;
    inset-inline: 0;
    inset-block-end: 2px;
    pointer-events: none;
    border-block-end: 3px dotted var(--rule-b);
    animation: terminal-title-reveal 360ms steps(6, end) 120ms both;
}

/* ======================================================================
   10. Reduced motion
   ====================================================================== */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        transition-duration: 0s !important;
        animation: none !important;
        scroll-behavior: auto !important;
    }

    .terminal-rule::after {
        display: none;
    }

    /* Drop the decorative panel top-edge scan entirely rather than leave a
       transition-driven reveal for reduced-motion users. */
    .panel::before {
        display: none;
    }
}

/* ======================================================================
   11. Forced colours
   ----------------------------------------------------------------------
   Drop decoration and defer to the native system palette, keeping native
   outlines and controls intact.
   ====================================================================== */

@media (forced-colors: active) {
    .panel,
    .button,
    .icon-button,
    .prose button,
    .control,
    .nav-link,
    .notice,
    .badge,
    .table-scroll,
    .window {
        box-shadow: none;
        background-image: none;
    }

    /* Decorative-only pseudo elements: drop the panel top-edge scan and the
       chromatic fringe hairline. */
    .panel::before,
    .terminal-brand::after {
        display: none;
    }

    /* New state decoration: drop the hover/focus/press edge rings, the
       field focus rail, and the window wake rail. Native outlines and
       system control colours carry state instead. */
    .button:is(:hover, :focus-visible, :active):not(:disabled):not([aria-disabled="true"]),
    .icon-button:is(:hover, :focus-visible, :active):not(:disabled):not([aria-disabled="true"]),
    .prose button:is(:hover, :focus-visible, :active):not(:disabled):not([aria-disabled="true"]),
    .button[data-variant="primary"]:is(:hover, :focus-visible, :active):not(:disabled):not([aria-disabled="true"]),
    .prose button[data-variant="primary"]:is(:hover, :focus-visible, :active):not(:disabled):not([aria-disabled="true"]),
    .control:focus-visible,
    .prose input:focus-visible,
    .prose select:focus-visible,
    .prose textarea:focus-visible,
    .window[open] {
        box-shadow: none;
    }

    .button,
    .icon-button,
    .prose button {
        color: ButtonText;
        background-color: ButtonFace;
        border-color: ButtonBorder;
    }

    .control:where(:not([type="checkbox"], [type="radio"])),
    .prose input:where(:not([type="checkbox"], [type="radio"])),
    .prose select,
    .prose textarea {
        color: FieldText;
        background-color: Field;
        border-color: ButtonBorder;
    }

    .control[aria-invalid="true"],
    .prose input[aria-invalid="true"],
    .prose select[aria-invalid="true"],
    .prose textarea[aria-invalid="true"] {
        border-color: ButtonBorder;
        box-shadow: none;
    }

    .panel,
    .table-scroll,
    .table th,
    .table td,
    .prose table th,
    .prose table td,
    .nav-link,
    .theme-picker,
    .window,
    .window[open],
    .window[open] > summary {
        border-color: CanvasText;
    }

    .table-scroll > .table thead th {
        background-color: Canvas;
    }

    .nav-link[aria-current="page"] {
        background-color: Canvas;
        border-color: Highlight;
        box-shadow: none;
    }

    .notice,
    .badge,
    .badge[data-tone="danger"] {
        color: CanvasText;
        background-color: Canvas;
        border-color: CanvasText;
        border-inline-start-color: Highlight;
    }

    /* Terminal masthead: keep the inverse brand block and a solid rule, and
       drop the dither masks and decorative stripe pattern. */
    .terminal-brand {
        color: Canvas;
        background-color: CanvasText;
    }

    .terminal-rule {
        animation: none !important;
        -webkit-mask-image: none;
        mask-image: none;
        background-image: none;
        background-color: CanvasText;
    }

    .terminal-rule::after {
        display: none;
    }

    .terminal-title {
        color: CanvasText;
        text-shadow: none !important;
        border-block-end-color: CanvasText;
    }

    .terminal-title::after {
        animation: none !important;
        border-block-end-color: CanvasText;
    }

    :is(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
        outline-color: Highlight;
    }
}

/* ==========================================================================
   Site presentation — ported Terminus page/prose theme
   --------------------------------------------------------------------------
   Plain-CSS port of the legacy Terminus Sass theme (formerly sass/css/*.scss,
   assembled by style.scss into style.css): every Sass variable, mixin, @use
   and @extend is expanded by hand here, in the one primary stylesheet, so no
   second legacy stylesheet is loaded. This is the native site/prose
   presentation beside the component layer above.

   Sections 12-24: 12 site foundation and opt-in column layouts, 13 native
   prose typography, 14 header, 15 responsive popover menu and skip link, 16
   footer and socials, 17 posts/tags/footnotes/post navigation, 18 Giallo code
   chrome and copy button, 19 pagination, 20 taxonomy lists, 21 archive, 22
   alerts as monochrome notices, 23 content shortcodes, 24 theme dropdown and
   screen-reader text.

   The component tokens from section 1 are reused unchanged; the site
   typography tokens (--font-size, --line-height, --radius, --external-link-icon,
   --code-border, --code-comment) live in the section 1 :root token set. Blog
   rhythm and margins are gated behind a zero-specificity :where(.prose) so
   component classes always win and a document without .prose (Farm, gallery,
   demo) keeps its own rhythm and full width; page columns are opt-in through
   body.layout-left/center/full-width.

   Licensing: upstream Terminus (MIT) and the alert derivation from Tabi's
   admonitions (MIT); see notices/Terminus-Tabi-MIT.txt. No outbound project
   grant is added for original ovcomponents work.
   ========================================================================== */

/* ==========================================================================
   12. Site foundation (ported from _main.scss)
   --------------------------------------------------------------------------
   The kit declares the html/body box model, font, ink, background,
   accent-color, the `*{box-sizing:inherit}` reset, and the site typography
   tokens (section 1); this section adds the theme's scroll/scrollbar behaviour
   and the opt-in column layouts. Documents without a layout class (Farm,
   gallery) are untouched and stay full width.
   ========================================================================== */

/* The html/body box model, font, ink, background and box-sizing reset live in
   the kit foundation; only the theme's scrollbar colour and smooth scrolling
   are added here. */
html {
    scrollbar-color: var(--accent-color) transparent;
}

@media (prefers-reduced-motion: no-preference) {
    html {
        scroll-behavior: smooth;
    }
}

body.layout-left,
body.layout-center,
body.layout-full-width {
    display: flex;
    flex-direction: column;
    padding: 40px;
    max-width: 864px;
    min-height: 100vh;
    border-inline-end: 1px solid color-mix(in srgb, var(--accent-color) 10%, transparent);
}

@media (max-width: 684px) {
    body.layout-left,
    body.layout-center,
    body.layout-full-width {
        padding: 20px;
    }
}

body.layout-center,
body.layout-full-width {
    border: none;
    margin: 0 auto;
}

body.layout-full-width {
    max-width: 100%;
}

main {
    overflow-wrap: break-word;
}

main a.external:not(:has(img, svg, video, picture, figure))::after {
    content: '' / '(external link)';
    display: inline-block;
    height: 0.8em;
    width: 0.8em;
    margin-inline-start: 0.1em;
    vertical-align: -0.05em;
    background-color: currentColor;
    mask: var(--external-link-icon);
    mask-size: cover;
}

/* ==========================================================================
   13. Native prose presentation (ported from _main.scss)
   --------------------------------------------------------------------------
   Everything below matches only inside `.prose` and carries a single element's
   specificity via `:where()`, so kit component classes and the library's own
   prose rules always take precedence. This is the native blog/markdown mode.
   ========================================================================== */

:where(.prose) h1 {
    font-size: calc(var(--font-size) * 1.45);
    letter-spacing: 0;
}

:where(.prose) h2 {
    font-size: calc(var(--font-size) * 1.35);
    letter-spacing: 0;
}

:where(.prose) h3 {
    font-size: calc(var(--font-size) * 1.15);
    letter-spacing: 0;
}

:where(.prose) :is(h4, h5, h6) {
    font-size: calc(var(--font-size) * 1);
    letter-spacing: 0;
}

:where(.prose) :is(h1, h2, h3, h4, h5, h6, p, ul, ol, img, figure, video, table) {
    margin: 25px 0;
}

:where(.prose) a {
    color: var(--accent-color);
}

:where(.prose) a.read-more {
    text-decoration: none;
}

:where(.prose) :is(img, video) {
    display: block;
    max-inline-size: 100%;
    block-size: auto;
}

:where(.prose) figure {
    margin: 0 auto;
    width: fit-content;
}

:where(.prose) figure :is(img, video) {
    margin: 0 auto;
}

:where(.prose) figure:not(.mastodon-post) figcaption {
    background: var(--accent-color);
    color: var(--background-color);
    text-align: center;
    font-size: var(--font-size);
    font-weight: normal;
    margin-top: 5px;
    padding: 5px 8px;
    border-radius: 0 0 var(--radius-panel) var(--radius-panel);
}

:where(.prose) figure:not(.mastodon-post) figcaption a {
    color: var(--background-color);
}

:where(.prose) figure:not(.mastodon-post) figcaption p:first-child {
    margin: 0;
}

:where(.prose) :is(ul, ol) {
    margin-inline-start: 4ch;
    padding: 0;
}

:where(.prose) :is(ul, ol) :is(ul, ol) {
    margin-block: 5px;
}

:where(.prose) li {
    position: relative;
}

:where(.prose) li::marker {
    color: var(--accent-color);
}

/* Preformatted text — the legacy `preformatted` mixin, expanded for `code`
   and `kbd`. */
:where(.prose) code {
    font-family: 'Fira Code', Monaco, Consolas, 'Ubuntu Mono', monospace !important;
    font-feature-settings: normal;
    background: color-mix(in srgb, var(--text-color) 5%, transparent);
    border: 1px solid var(--code-border);
    padding: 1px 6px;
    margin: 0 2px;
    font-size: calc(var(--font-size) * 0.95);
    color: var(--accent-color);
}

:where(.prose) code code {
    background: transparent;
    padding: 0;
    margin: 0;
}

:where(.prose) kbd {
    font-family: 'Fira Code', Monaco, Consolas, 'Ubuntu Mono', monospace !important;
    font-feature-settings: normal;
    background: color-mix(in srgb, var(--text-color) 5%, transparent);
    border: 1px solid var(--code-border);
    padding: 1px 6px;
    margin: 0 2px;
    font-size: calc(var(--font-size) * 0.95);
    border-top: 1px solid color-mix(in srgb, var(--accent-color) 25%, transparent);
    border-left: 1px solid var(--accent-color);
    border-right: 1px solid var(--accent-color);
    border-bottom: 4px solid var(--accent-color);
    border-radius: 4px;
}

:where(.prose) pre {
    tab-size: 4;
    background: color-mix(in srgb, var(--text-color) 5%, transparent);
    color: var(--text-color);
    padding: 10px;
    font-size: calc(var(--font-size) * 0.95) !important;
    overflow: auto;
    border-radius: var(--radius-panel);
    border: 1px solid color-mix(in srgb, var(--text-color) 10%, transparent);
    direction: ltr;
}

:where(.prose) pre code {
    background: unset;
    color: unset;
    margin: 0;
    padding: 0;
    border: none;
}

:where(.prose) pre code mark {
    display: block;
    min-width: fit-content;
}

:where(.prose) abbr {
    position: relative;
    text-decoration-style: wavy;
    text-decoration-color: var(--accent-color);
    cursor: help;
}

:where(.prose) sub {
    bottom: -0.25em;
}

:where(.prose) sup {
    line-height: 0;
    top: -0.25em;
}

:where(.prose) mark {
    background: color-mix(in srgb, var(--accent-color) 45%, transparent);
    color: var(--text-color);
}

:where(.prose) blockquote {
    position: relative;
    border-top: 1px solid var(--accent-color);
    border-bottom: 1px solid var(--accent-color);
    margin: 0;
    padding: 25px;
}

:where(.prose) blockquote::before {
    content: '>';
    display: block;
    position: absolute;
    inset-inline-start: 0;
    color: var(--accent-color);
}

:where(.prose) blockquote p:first-child {
    margin-top: 0;
}

:where(.prose) blockquote p:last-child {
    margin-bottom: 0;
}

:where(.prose) hr {
    width: 100%;
    height: 2px;
    border: none;
    background: color-mix(in srgb, var(--text-color) 50%, transparent);
}

:where(.prose) details {
    position: relative;
    margin: 25px 0;
    width: 100%;
    border: 1px solid var(--accent-color);
}

:where(.prose) details > summary {
    padding: 3px 10px;
    color: var(--accent-color);
    transition: background 0.15s linear;
}

:where(.prose) details > summary:hover {
    background: color-mix(in srgb, var(--accent-color) 10%, transparent);
}

:where(.prose) details > summary::marker {
    content: none;
}

/* Down-facing caret drawn with borders; rotates on open. */
:where(.prose) details > summary::before {
    display: inline-block;
    content: '';
    border: 0.35rem solid transparent;
    border-top-color: var(--accent-color);
    margin-inline: 0.3em 0.75rem;
    transform: rotate(-90deg);
    transition: transform 0.1s ease-out;
}

:where(.prose) details[open] > summary::before {
    transform: translateY(0.15rem);
}

:where(.prose) details > :not(img, pre > code, summary) {
    margin-inline: 15px;
}

:where(.prose) details > :not(img, pre > code, summary):first-of-type {
    margin-top: 15px;
}

:where(.prose) details > :not(img, pre > code, summary):last-child {
    margin-bottom: 15px;
}

/* ==========================================================================
   14. Header (ported from _header.scss)
   ========================================================================== */

.header {
    display: flex;
    flex-direction: column;
}

@media (max-width: 684px) {
    .header {
        flex-direction: row;
    }
}

.header-container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex: 1;
}

.header-logo-container {
    display: flex;
    flex: 1;
}

/* Striped rule that fills the space after the logo block. */
.header-logo-container::after {
    content: '';
    display: block;
    margin-inline-start: 8px;
    width: 100%;
    background: repeating-linear-gradient(to right, var(--accent-color), var(--accent-color) 2px, transparent 0, transparent 10px);
}

.header-logo-container a {
    flex: 0 0 auto;
    max-width: 100%;
    text-decoration: none;
}

.logo {
    display: flex;
    align-items: center;
    padding: 5px 10px;
    background: var(--accent-color);
    color: var(--background-color);
    font-weight: bold;
    text-decoration: none;
}

.logo-img {
    display: inline;
    height: var(--line-height);
    margin: 0;
}

@media print {
    .header {
        display: none;
    }
}

/* ==========================================================================
   15. Main menu, responsive popover, skip link (ported from _menu.scss)
   --------------------------------------------------------------------------
   The calendar-dropdown shadow that the legacy mixin derived with relative
   colour syntax is expressed with color-mix() to match the kit.
   ========================================================================== */

.main-menu {
    display: flex;
    justify-content: space-between;
    margin: 20px 1px;
}

@media (max-width: 684px) {
    .main-menu {
        margin: 0;
    }
}

.main-menu-items {
    display: flex;
    flex: 1;
    flex-wrap: wrap;
    gap: 10px 20px;
    overflow: visible;
    border: none;
    margin: 0;
    padding-bottom: 10px;
    background: unset;
    list-style: none;
}

@media (max-width: 684px) {
    .main-menu-items {
        display: none;
    }

    .main-menu-items:popover-open {
        border: 2px solid var(--accent-color);
        box-shadow: 0 10px color-mix(in srgb, var(--accent-color) 70%, transparent), -10px 10px color-mix(in srgb, var(--accent-color) 70%, transparent), 10px 10px color-mix(in srgb, var(--accent-color) 70%, transparent);
        padding: 10px;
        background: var(--background-color);
        color: var(--accent-color);
        position-anchor: --popover-button;
        position-area: block-end span-inline-start;
        display: flex;
        column-gap: 10px;
        flex-direction: column;
        margin-top: 10px;
        margin-inline-start: 20px;
        min-width: min-content;
    }

    .main-menu-items > li > a {
        display: block;
        padding: 5px;
    }
}

.main-menu-dropdown-button {
    display: none;
    border: 2px solid;
    margin-inline-start: 10px;
    padding: 3px 8px;
    anchor-name: --popover-button;
}

@media (max-width: 684px) {
    .main-menu-dropdown-button {
        display: flex;
    }
}

/* Down-facing caret drawn with borders. */
.main-menu-dropdown-button::after {
    content: '';
    border: 0.35rem solid transparent;
    border-top-color: var(--accent-color);
    margin-inline-start: 0.5em;
    transform: translateY(0.15em);
}

.skip-to-content {
    border: 2px solid var(--accent-color);
    box-shadow: 0 10px color-mix(in srgb, var(--accent-color) 70%, transparent), -10px 10px color-mix(in srgb, var(--accent-color) 70%, transparent), 10px 10px color-mix(in srgb, var(--accent-color) 70%, transparent);
    padding: 10px;
    background: var(--background-color);
    color: var(--accent-color);
    position: fixed;
    top: 40px;
    left: -1vw;
    z-index: 99;
    transform: translateX(-100vw);
    text-align: center;
}

@media (max-width: 684px) {
    .skip-to-content {
        top: 20px;
    }
}

.skip-to-content:focus {
    left: 50%;
    transform: translateX(-50%);
    outline: none;
}

/* ==========================================================================
   16. Footer (ported from _footer.scss)
   ========================================================================== */

.footer {
    padding: 40px 0;
}

.footer a {
    color: inherit;
}

.footer .socials {
    padding-bottom: 25px;
}

@media print {
    .footer .socials {
        display: none;
    }
}

.footer .socials ul {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
    justify-content: center;
    margin: 0;
    list-style: none;
}

.footer .socials .social-link {
    display: flex;
    padding: 0.66rem;
}

.footer .socials .social-link > svg {
    aspect-ratio: 1/1;
    width: 1.5rem;
    height: auto;
    margin: 0 auto;
    fill: var(--footnote-color);
}

.footer .socials .social-link:hover {
    background: var(--accent-color);
}

.footer .socials .social-link:hover > svg {
    fill: var(--background-color);
}

.footer .copyright {
    text-align: center;
    margin: 0;
    color: color-mix(in srgb, var(--text-color) 65%, transparent);
}

.footer .copyright > span {
    display: inline-block;
}

.footer .copyright > span:not(:first-child)::before {
    content: ':: ';
}

/* ==========================================================================
   17. Posts, meta, tags, footnotes, post navigation (ported from _post.scss)
   ========================================================================== */

.content ul li {
    list-style: '⦿ ';
}

.content ul li ul li {
    list-style: '■ ';
}

.content ul li ul li ul li {
    list-style: '► ';
}

.content ul li:not(:last-of-type) {
    margin-bottom: 3px;
}

.content ul li:has(> input[type="checkbox"]) {
    list-style: none;
}

.content ul li:has(> input[type="checkbox"]) > input[type="checkbox"] {
    padding: 0.75em;
    margin-block: 0 0.2em;
    margin-inline: -2.25em 0;
}

.framed {
    border: 1px solid var(--accent-color);
    padding: 20px;
    margin: 25px 0;
}

.framed *:first-child {
    margin-top: 0;
}

.framed *:last-child {
    margin-bottom: 0;
}

.post {
    padding: 30px 0;
    width: 100%;
    text-align: start;
}

.post:not(:last-of-type) {
    border-bottom: 1px solid color-mix(in srgb, var(--text-color) 10%, transparent);
}

.post-title {
    position: relative;
    margin-block: 0 15px;
    padding-bottom: 15px;
    border-bottom: 3px dotted var(--accent-color);
    color: var(--accent-color);
}

.post-title::after {
    content: '';
    position: absolute;
    bottom: 2px;
    display: block;
    width: 100%;
    border-bottom: 3px dotted var(--accent-color);
}

.post-title a {
    text-decoration: none;
}

.draft-label {
    padding-block: 2px;
    padding-inline: 8px;
    background-color: var(--accent-color);
    color: var(--background-color);
}

ul.post-meta {
    list-style: none;
    display: block;
    margin: 0 0 8px;
    color: color-mix(in srgb, var(--text-color) 65%, transparent);
}

ul.post-meta > li {
    display: inline;
    list-style: none;
}

ul.post-meta > li[role="separator"] {
    user-select: none;
}

ul.post-meta > li.draft-label {
    display: block;
    float: inline-end;
    margin-top: -2px;
}

.post-tags {
    display: flex;
    flex-wrap: wrap;
    column-gap: 8px;
    margin-bottom: 20px;
    color: var(--accent-color);
}

.post-tags > [role="separator"] {
    user-select: none;
}

:is(h1, h2, h3, h4, h5, h6) .post-anchor:has(> span) {
    margin-inline-start: 10px;
    opacity: 0%;
    color: var(--accent-color);
    text-decoration: none;
    user-select: none;
}

@media screen and (max-width: 684px) {
    :is(h1, h2, h3, h4, h5, h6) .post-anchor:has(> span) {
        opacity: 100%;
    }
}

@media print {
    :is(h1, h2, h3, h4, h5, h6) .post-anchor:has(> span) {
        display: none;
    }
}

:is(h1, h2, h3, h4, h5, h6):focus-within .post-anchor,
:is(h1, h2, h3, h4, h5, h6):hover .post-anchor {
    opacity: 100%;
}

/* Inline footnotes. The legacy `--serif-font` was never declared upstream, so
   that font-family declaration was inert; the reference inherits the body font
   here instead of carrying a dangling token. */
.footnote-reference {
    font-family: inherit;
    font-size: 0.7rem;
}

.footnote-definition {
    color: var(--footnote-color);
    margin-block-end: 0.6rem;
}

.footnote-definition sup {
    color: var(--accent-color);
    margin-inline-end: 0.15rem;
    font-size: 0.75rem;
}

.footnote-definition p {
    display: inline;
}

/* GitHub-style bottom footnotes. */
.footnotes {
    border-top: 2px solid var(--footnote-color);
}

.footnotes .footnotes-list p {
    color: var(--footnote-color);
    text-align: start;
}

@media print {
    .post-navigation {
        display: none;
    }
}

.post-navigation-title {
    display: flex;
    text-align: center;
    position: relative;
    margin: 45px 0 20px;
}

.post-navigation-title h2 {
    text-align: center;
    margin: 0 auto;
    padding: 5px 10px;
    background: var(--background-color);
    color: color-mix(in srgb, var(--text-color) 30%, transparent);
    font-size: calc(var(--font-size) * 0.8);
    font-weight: normal;
    text-transform: uppercase;
    text-decoration: none;
    letter-spacing: 0.1em;
    z-index: 1;
}

.post-navigation-title hr {
    background: var(--accent-color);
    position: absolute;
    inset-inline: 0;
    width: 100%;
    margin-top: 15px;
    z-index: 0;
}

.post-navigation-buttons {
    display: flex;
    flex-flow: row wrap;
    gap: 10px;
    justify-content: center;
    padding-bottom: 30px;
    text-align: center;
}

.post-navigation-buttons > a {
    text-decoration: none;
}

/* ==========================================================================
   18. Code chrome: Giallo header/name, copy button, line numbers
   (ported from _code.scss)
   ========================================================================== */

.copy-button {
    position: absolute;
    z-index: 1;
    top: 6px;
    inset-inline-end: 10px;
    width: 4.5rem;
    padding: 3px 8px;
    border: 1px solid color-mix(in srgb, var(--accent-color) 15%, transparent);
    font-size: calc(var(--font-size) * 0.8);
    font-weight: normal;
    line-height: 1em;
}

@media print {
    .copy-button {
        display: none;
    }
}

pre.giallo:not(:has(code[data-lang="plain"])) {
    display: block;
    position: relative;
    padding: 0;
    overflow-y: hidden;
    direction: ltr;
}

pre.giallo:not(:has(code[data-lang="plain"])) code[data-lang] {
    --code-comment: color-mix(in srgb, currentColor 53%, transparent);
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    padding-bottom: 10px;
    overflow-x: auto;
    overscroll-behavior-x: none;
}

/* Language header bar, driven by the data-lang attribute on <code>. */
pre.giallo:not(:has(code[data-lang="plain"])) code[data-lang]::before {
    content: attr(data-lang);
    position: sticky;
    inset-inline-start: 0;
    width: 100%;
    padding: 6px 10px;
    border-bottom: 1px solid var(--code-border);
    margin-bottom: 10px;
    color: var(--code-comment);
    font-size: calc(var(--font-size) * 0.8);
    text-transform: uppercase;
    line-height: 21px;
}

/* Filename label, positioned in the header bar area. */
pre.giallo:not(:has(code[data-lang="plain"])) code[data-lang][data-name]::after {
    content: attr(data-name);
    position: absolute;
    inset-inline-end: 0;
    overflow: hidden;
    max-width: 60%;
    padding: 6px 10px;
    color: var(--code-comment);
    font-size: calc(var(--font-size) * 0.8);
    line-height: 21px;
    text-overflow: ellipsis;
}

/* Mandatory Giallo styling (https://www.getzola.org/documentation/content/syntax-highlighting/). */
pre.giallo:not(:has(code[data-lang="plain"])) .giallo-l {
    min-height: var(--line-height);
    padding-inline: 10px;
}

/* Monokai (and some other themes) emit `background-color` on whitespace-only
   spans; strip it so spaces do not render as coloured blocks. */
pre.giallo:not(:has(code[data-lang="plain"])) .giallo-l span[style*="background-color"] {
    background-color: unset !important;
}

pre.giallo:not(:has(code[data-lang="plain"])) .giallo-ln {
    display: inline-block;
    min-width: 2ch;
    margin-inline-end: 20px;
    color: var(--code-comment);
    text-align: end;
    user-select: none;
}

@media screen {
    pre.giallo:has(.copy-button) code[data-name]::after {
        inset-inline-end: calc(4.5rem + 10px);
    }
}

/* ==========================================================================
   19. Pagination (ported from _pagination.scss and _main.scss)
   --------------------------------------------------------------------------
   The kit `.pagination` is a flex row for flat markup and its Svelte adapter.
   This theme's pagination is `nav.pagination > ul`, whose centred layout lives
   on the inner list, so the wrapper stays block-level.
   ========================================================================== */

nav.pagination {
    display: block;
}

.pagination {
    margin-top: 50px;
}

@media print {
    .pagination {
        display: none;
    }
}

.pagination ul {
    display: flex;
    flex-flow: row wrap;
    align-items: center;
    justify-content: center;
    margin: 0;
    padding-bottom: 30px;
    text-align: center;
    list-style: none;
}

.pagination ul > *:not(:first-child)::before {
    content: '::';
    margin: 0 10px;
}

.pagination ul li a {
    text-decoration: none;
    text-wrap: nowrap;
}

/* ==========================================================================
   20. Taxonomy lists (ported from _taxonomies.scss)
   ========================================================================== */

ul.taxonomy-list {
    list-style: none;
}

ul.taxonomy-list > li {
    margin-block-end: 1rem;
}

.three-column {
    column-count: 3;
}

.two-column {
    column-count: 2;
}

/* ==========================================================================
   21. Archive (ported from _archive.scss)
   ========================================================================== */

.archive-year h2 {
    margin-block-end: 1rem;
}

.archive-year ul {
    margin-block-start: 1rem;
    list-style: none;
}

.archive-year ul li:not(:last-of-type) {
    margin-bottom: 3px;
}

.archive-year ul li::before {
    content: '⦿';
    position: absolute;
    inset-inline-start: -20px;
    color: var(--accent-color);
}

/* ==========================================================================
   22. Alerts ↔ monochrome notices (ported from _alerts.scss)
   --------------------------------------------------------------------------
   The alert shortcode renders the kit `.notice` component with `data-tone`
   (note/tip/warning unchanged, important→info, caution→danger, default info);
   the tone palette variables from Tabi are intentionally not mapped, because
   every palette is monochrome. Only the shortcode's label layout and the
   content rhythm that the old `.alert-content` provided are restored here; the
   tone border treatment lives in the kit `.notice[data-tone]` rules.
   ========================================================================== */

.notice-title {
    margin-block: 0 var(--space-3);
    font-weight: 800;
    letter-spacing: 0.02em;
}

/* Embedded markdown keeps the tighter 1rem rhythm the alert content used. */
.notice > :is(p, ul, ol, blockquote, pre, table, details, figure):not(.notice-title) {
    margin-block: var(--space-4) 0;
}

/* Body emphasis keeps the legacy 580 weight; the label's own <strong> is left
   at the label weight. */
.notice > :is(p, ul, ol, blockquote, pre, table, details, figure):not(.notice-title) :where(strong) {
    font-weight: 580;
}

.notice :where(code) {
    color: inherit;
}

/* Zola-generated GitHub alerts (github_alerts = true) arrive as
   `<blockquote class="markdown-alert-TYPE"><p>…</p></blockquote>` with no label
   element, so the uppercase tone label is generated in CSS exactly as the
   legacy sheet did, and the blockquote chrome is replaced by the same
   ink/surface shape as `.notice`. */
.markdown-alert-note,
.markdown-alert-tip,
.markdown-alert-important,
.markdown-alert-warning,
.markdown-alert-caution {
    display: block;
    position: relative;
    margin-block: 25px;
    padding: var(--space-3) var(--space-4);
    color: var(--ink);
    background: var(--surface);
    border: 1px solid var(--ink);
    border-inline-start-width: 4px;
    border-radius: var(--radius-control);
}

.markdown-alert-note,
.markdown-alert-important {
    border-style: solid;
}

.markdown-alert-tip {
    border-style: double;
    border-width: 3px;
    border-inline-start-width: 3px;
}

.markdown-alert-warning {
    border-style: dashed;
}

.markdown-alert-caution {
    border-style: double;
    border-width: 3px;
    border-inline-start-width: 6px;
}

/* The prose blockquote `>` marker does not belong on an alert. */
.markdown-alert-note::before,
.markdown-alert-tip::before,
.markdown-alert-important::before,
.markdown-alert-warning::before,
.markdown-alert-caution::before {
    content: none;
}

.markdown-alert-note > p:first-child::before,
.markdown-alert-tip > p:first-child::before,
.markdown-alert-important > p:first-child::before,
.markdown-alert-warning > p:first-child::before,
.markdown-alert-caution > p:first-child::before {
    display: block;
    margin-block-end: var(--space-4);
    color: var(--ink);
    font-weight: 800;
    letter-spacing: 0.02em;
}

.markdown-alert-note > p:first-child::before {
    content: 'NOTE';
}

.markdown-alert-tip > p:first-child::before {
    content: 'TIP';
}

.markdown-alert-important > p:first-child::before {
    content: 'IMPORTANT';
}

.markdown-alert-warning > p:first-child::before {
    content: 'WARNING';
}

.markdown-alert-caution > p:first-child::before {
    content: 'CAUTION';
}

/* ==========================================================================
   23. Content shortcodes (ported from _shortcodes.scss)
   ========================================================================== */

figure.mastodon-post {
    position: relative;
    border: 1px solid var(--accent-color);
    margin: 0;
    padding: 60px 25px 25px;
}

figure.mastodon-post::before {
    content: '> From Mastodon:';
    position: absolute;
    top: 20px;
    inset-inline-start: 20px;
    display: block;
    color: var(--accent-color);
    font-weight: bold;
}

figure.mastodon-post blockquote {
    padding: unset;
    border: unset;
    overflow-wrap: anywhere;
}

figure.mastodon-post blockquote::before {
    content: none;
}

figure.mastodon-post figcaption {
    margin-top: 25px;
}

.references-list p {
    text-indent: -2.4rem;
    margin-inline-start: 2.4rem;
}

.wide-container {
    margin: 0;
}

@media (max-width: 684px) {
    .wide-container {
        overflow-x: auto;
    }
}

/* ==========================================================================
   24. Theme selector and screen-reader text (ported from _theme-selector.scss)
   --------------------------------------------------------------------------
   Markup is generated by theme-switcher.js: .theme-selector > .theme-trigger +
   ul.theme-dropdown > li > a.theme-option(.current), toggled with `.show`.
   ========================================================================== */

.main-menu-items {
    position: relative;
}

.main-menu-items .theme-selector {
    position: relative;
    margin-inline-start: auto;
}

.main-menu-items .theme-selector .theme-trigger {
    text-decoration: none;
    cursor: pointer;
    padding: 2px 4px;
    border-radius: 3px;
    transition: all 0.15s ease;
    color: var(--text-color);
}

.main-menu-items .theme-selector .theme-trigger:hover {
    color: var(--accent-color);
}

.main-menu-items .theme-selector .theme-dropdown {
    position: absolute;
    top: 100%;
    inset-inline-end: 0;
    z-index: 100;
    display: none;
    margin: 0;
    padding: 10px;
    list-style: none;
    text-wrap: nowrap;
    background: var(--background-color);
    border: 2px solid var(--accent-color);
    box-shadow: 0 10px color-mix(in srgb, var(--accent-color) 70%, transparent), -10px 10px color-mix(in srgb, var(--accent-color) 70%, transparent), 10px 10px color-mix(in srgb, var(--accent-color) 70%, transparent);
}

.main-menu-items .theme-selector .theme-dropdown.show {
    display: block;
}

.main-menu-items .theme-selector .theme-dropdown li {
    margin: 0;
}

.main-menu-items .theme-selector .theme-dropdown a {
    display: block;
    padding: 5px 8px;
    color: var(--text-color);
    text-decoration: none;
    transition: all 0.15s ease;
    border-radius: 3px;
}

.main-menu-items .theme-selector .theme-dropdown a:hover {
    background: color-mix(in srgb, var(--accent-color) 15%, transparent);
    color: var(--text-color);
}

.main-menu-items .theme-selector .theme-dropdown a.current {
    color: var(--accent-color);
    background: color-mix(in srgb, var(--accent-color) 10%, transparent);
    font-weight: bold;
}

.main-menu-items .theme-selector .theme-dropdown a.current::before {
    content: '→ ';
}

@media (max-width: 684px) {
    .main-menu-items .theme-selector .theme-dropdown {
        position: static;
        margin: 10px 0 0 0;
        box-shadow: none;
        border: 1px solid var(--accent-color);
    }

    .main-menu-items .theme-selector .theme-dropdown.show {
        display: block;
    }
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}
