/* CSS Reset */
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

/* CSS Variables - Minimal Set */
/* White and near-black with neutral greys; orange is the only colour */
:root {
    --bg: #ffffff;
    --bg-alt: #f5f5f5;
    --text: #171717;
    --text-body: #3a3a3a; /* 11.4:1 on --bg */
    --text-muted: #6b6b6b; /* 5.3:1 on --bg */
    --border: #e5e5e5;
    /* Orange for bars, borders and the logo; --accent-text is the darker orange that
       reads as text (5.2:1 on --bg, --accent is 3.1:1) */
    --accent: #ff5a00;
    --accent-text: #c2410c;
    --note: #525252; /* Note callouts, 7:1 on their tint */
    --code-bg: #f0f0f0; /* inline code; --bg-alt is too close to --bg to show */
    --font-code:
        "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
        "Liberation Mono", "Courier New", monospace;
    /* Typography scale */
    --body-size: 16.5px;
    --body-lh: 1.7;
    --measure: 70ch; /* text column width, about 65-70 characters per line */
    --code-size: 13px;
    --code-lh: 1.5;
    --container-pad: 2rem; /* pairs with mobile bleed */
}

[data-theme="dark"] {
    --bg: #131312;
    --bg-alt: #1c1c1b;
    --text: #f2f1ee;
    --text-body: #d3d1cc; /* 12.2:1 on --bg */
    --text-muted: #9c9992; /* 6.5:1 on --bg */
    --border: #2f2e2b;
    --accent: #ff6b1a;
    --accent-text: #ff8a3d; /* 7.9:1 on --bg */
    --note: #a8a49c;
    --code-bg: var(--bg-alt);
}

/* Fonts, all served from static/fonts/.
   Headings: New Computer Modern Bold, cut down to Latin by scripts/heading-font.py.
   Text, code and logo: Latin files downloaded by scripts/vendor-fonts.sh. */
@font-face {
    font-family: "NewCM Heading";
    font-weight: 700;
    font-style: normal;
    font-display: swap;
    src: url("fonts/newcm-heading-bold.5c2fce535c2a488e8949.woff2") format("woff2");
}

@font-face {
    font-family: "IBM Plex Serif";
    font-weight: 400;
    font-style: normal;
    font-display: swap;
    src: url("fonts/ibm-plex-serif-latin-400-normal.c34dc21a56fefb211fb9.woff2") format("woff2");
}

@font-face {
    font-family: "IBM Plex Serif";
    font-weight: 400;
    font-style: italic;
    font-display: swap;
    src: url("fonts/ibm-plex-serif-latin-400-italic.8bf647f692e083adb3ce.woff2") format("woff2");
}

@font-face {
    font-family: "IBM Plex Serif";
    font-weight: 500;
    font-style: normal;
    font-display: swap;
    src: url("fonts/ibm-plex-serif-latin-500-normal.d28da6a53deac3972e36.woff2") format("woff2");
}

@font-face {
    font-family: "IBM Plex Serif";
    font-weight: 600;
    font-style: normal;
    font-display: swap;
    src: url("fonts/ibm-plex-serif-latin-600-normal.7252fb22d2fa9328c632.woff2") format("woff2");
}

@font-face {
    font-family: "IBM Plex Serif";
    font-weight: 700;
    font-style: normal;
    font-display: swap;
    src: url("fonts/ibm-plex-serif-latin-700-normal.e959630b85ce042bca6b.woff2") format("woff2");
}

@font-face {
    font-family: "JetBrains Mono";
    font-weight: 400;
    font-style: normal;
    font-display: swap;
    src: url("fonts/jetbrains-mono-latin-400-normal.2744e71bc74f1dc8874c.woff2") format("woff2");
}

@font-face {
    font-family: "JetBrains Mono";
    font-weight: 400;
    font-style: italic;
    font-display: swap;
    src: url("fonts/jetbrains-mono-latin-400-italic.671645c796ea61d81791.woff2") format("woff2");
}

@font-face {
    font-family: "JetBrains Mono";
    font-weight: 700;
    font-style: normal;
    font-display: swap;
    src: url("fonts/jetbrains-mono-latin-700-normal.83d14b3f2d45090e4e06.woff2") format("woff2");
}

@font-face {
    font-family: "JetBrains Mono";
    font-weight: 700;
    font-style: italic;
    font-display: swap;
    src: url("fonts/jetbrains-mono-latin-700-italic.3cbe6a3671ecb9a4c429.woff2") format("woff2");
}

@font-face {
    font-family: "IBM Plex Mono";
    font-weight: 400;
    font-style: normal;
    font-display: swap;
    src: url("fonts/ibm-plex-mono-latin-400-normal.07eb027add2a92d49ea9.woff2") format("woff2");
}

/* Base Typography */
body {
    font-family: "IBM Plex Serif", Georgia, serif;
    line-height: var(--body-lh);
    background-color: var(--bg);
    color: var(--text);
    font-size: var(--body-size);
    -webkit-font-smoothing: antialiased;
    /* Footer at the bottom of short pages */
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

::selection {
    background-color: color-mix(in srgb, var(--accent) 25%, transparent);
}

/* Paragraph spacing */
p {
    margin: 0 0 14px 0;
    /* Splits long words at line ends; the dictionary follows <html lang> */
    hyphens: auto;
    /* Avoids a lone word on the last line */
    text-wrap: pretty;
}

/* A phone column is too narrow to justify without wide gaps between words */
@media (min-width: 769px) {
    p,
    .tldr {
        text-align: justify;
    }

    /* Justification stretches the spaces inside inline code; an inline-block
       keeps them, at the price that such a span no longer breaks across lines */
    p code {
        display: inline-block;
        line-height: 1.3;
    }
}

h1,
h2,
h3,
h4,
h5,
h6 {
    font-family: "NewCM Heading", "IBM Plex Serif", Georgia, serif;
    /* The heading font has one weight */
    font-weight: 700;
    line-height: 1.3;
    color: var(--text);
}

/* 32px on a phone, 44px from about 800px */
h1 {
    font-size: clamp(2rem, 1rem + 3.5vw, 2.75rem);
    line-height: 1.15;
    letter-spacing: -0.01em;
    margin: 2.2rem 0 1rem 0;
    text-wrap: balance;
}

/* 24px on a phone, 34px from about 900px */
h2 {
    font-size: clamp(1.5rem, 0.9rem + 2.2vw, 2.125rem);
    line-height: 1.2;
    letter-spacing: -0.005em;
    /* More than the gap around a block inside a section */
    margin: 2.75rem 0 0.75rem 0;
    text-wrap: balance;
}

h3 {
    font-size: 1.5rem;
    margin: 2rem 0 0.75rem 0;
}

h4 {
    font-size: 1.25rem;
    margin: 1.25rem 0 0.5rem 0;
}

h5,
h6 {
    font-size: 1rem;
    margin: 1rem 0 0.5rem 0;
}

/* Layout */
/* One narrow column for header, posts, and footer, so the logo lines up with the text */
.container {
    max-width: calc(var(--measure) + 2 * var(--container-pad));
    margin: 0 auto;
    padding: 0 var(--container-pad);
}

/* Header */
.site-header {
    background-color: var(--bg);
    border-bottom: 1px solid var(--border);
    padding: 1.5rem 0;
}

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

.logo {
    font-size: 1.5rem;
    font-weight: 400;
    color: var(--text);
    text-decoration: none;
    font-family:
        "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
        "Liberation Mono", "Courier New", monospace;
    display: inline-block;
    /* Keeps the hover area: a link that shrank under the pointer would lose hover and unfold */
    min-width: 15ch;
}

.logo-highlight {
    color: var(--accent);
}

/* Hover or keyboard focus folds the logo down to its orange letters, slides the prompt "$ ./"
   in before them, and types ".sh" after them like a terminal: the cursor stands still while
   keys land at an uneven pace, then blinks. "0xdeafbeef blog" becomes "$ ./dfb.sh".
   Widths are in ch, exact in the monospace logo font. Leaving clears ".sh" and the cursor
   at once and unfolds the rest. The rules here set the states; the motion between them is
   in the prefers-reduced-motion: no-preference block below. */

.logo > span {
    display: inline-block;
    /* An inline-block with hidden overflow sits on its bottom edge, not the baseline */
    vertical-align: top;
    white-space: pre;
    overflow: hidden;
}

.logo-fold {
    width: calc(var(--chars) * 1ch);
}

.logo-prompt {
    width: 0;
    opacity: 0;
    color: var(--text-muted);
}

.logo-tld {
    width: 0;
    color: var(--accent);
}

.logo-cursor {
    width: 0;
    height: 1.1em;
    /* Centres the block in the 1.7 line box */
    margin-top: 0.3em;
    background-color: var(--accent);
}

.logo:is(:hover, :focus-visible) .logo-fold {
    width: 0;
    opacity: 0;
}

.logo:is(:hover, :focus-visible) .logo-prompt {
    width: 4ch;
    opacity: 1;
}

.logo:is(:hover, :focus-visible) .logo-tld {
    width: 3ch;
}

.logo:is(:hover, :focus-visible) .logo-cursor {
    width: 0.6ch;
    margin-left: 0.1ch;
}

@media (prefers-reduced-motion: no-preference) {
    /* Unfolds after the prompt has slid out */
    .logo-fold {
        transition:
            width 0.3s ease 0.15s,
            opacity 0.2s ease 0.15s;
    }

    .logo-prompt {
        transition:
            width 0.2s ease,
            opacity 0.15s ease;
    }

    .logo:is(:hover, :focus-visible) .logo-fold {
        transition:
            width 0.3s ease,
            opacity 0.2s ease;
    }

    /* The prompt is printed, not typed: it slides in once the fold is done */
    .logo:is(:hover, :focus-visible) .logo-prompt {
        transition:
            width 0.25s ease 0.3s,
            opacity 0.2s ease 0.35s;
    }

    /* The cursor shows up after the prompt and moves with each typed key, since it follows .logo-tld */
    .logo:is(:hover, :focus-visible) .logo-tld {
        animation: logo-type 0.5s step-end 0.75s both;
    }

    .logo:is(:hover, :focus-visible) .logo-cursor {
        transition: width 0s 0.55s;
        /* Solid while typing, blinking once typing stops */
        animation: logo-cursor-blink 1.1s steps(1) 1.5s infinite;
    }
}

/* Three keys at uneven intervals, as a hand types */
@keyframes logo-type {
    0% {
        width: 0;
    }

    22% {
        width: 1ch;
    }

    64% {
        width: 2ch;
    }

    100% {
        width: 3ch;
    }
}

@keyframes logo-cursor-blink {
    50% {
        opacity: 0;
    }
}

/* A device without hover never sees the fold. There it plays once after the page loads
   and then unfolds, in the order and at the pace of the hover version.
   The keyframe offsets are the hover version's times as percentages of 5 seconds,
   so 1% is 50 ms. Retune the two together.
   Hover or focus ends the demo on every part at once and the rules above take over. */
@media (hover: none) and (prefers-reduced-motion: no-preference) {
    .logo:not(:hover, :focus-visible) .logo-fold {
        animation: logo-demo-fold 5s ease 1.2s;
    }

    .logo:not(:hover, :focus-visible) .logo-prompt {
        animation: logo-demo-prompt 5s ease 1.2s;
    }

    .logo:not(:hover, :focus-visible) .logo-tld {
        animation: logo-demo-type 5s step-end 1.2s;
    }

    .logo:not(:hover, :focus-visible) .logo-cursor {
        animation: logo-demo-cursor 5s step-end 1.2s;
    }
}

/* The frames left out at 0% and 100% take the part's own style. That is the resting
   state, because the demo never runs under hover or focus. */
@keyframes logo-demo-fold {
    4% {
        opacity: 0;
    }

    6% {
        width: 0;
    }

    89% {
        width: 0;
        opacity: 0;
    }

    93% {
        opacity: 1;
    }

    95% {
        width: calc(var(--chars) * 1ch);
    }
}

@keyframes logo-demo-prompt {
    6% {
        width: 0;
        opacity: 0;
    }

    11%,
    86% {
        width: 4ch;
        opacity: 1;
    }

    90% {
        width: 0;
        opacity: 0;
    }
}

@keyframes logo-demo-type {
    17% {
        width: 1ch;
    }

    21% {
        width: 2ch;
    }

    25% {
        width: 3ch;
    }

    86% {
        width: 0;
    }
}

@keyframes logo-demo-cursor {
    11% {
        width: 0.6ch;
        margin-left: 0.1ch;
    }

    41%,
    63%,
    85% {
        opacity: 0;
    }

    52%,
    74% {
        opacity: 1;
    }

    86% {
        width: 0;
        margin-left: 0;
        opacity: 1;
    }
}

/* Navigation */
nav {
    display: flex;
    align-items: center;
    gap: 2rem;
}

nav a {
    color: var(--text-muted);
    text-decoration: none;
    font-weight: 500;
    transition: color 0.2s ease;
}

nav a:hover,
nav a.active {
    color: var(--accent-text);
}

/* The social icons sit together, apart from Home and the theme toggle */
.social {
    display: flex;
    gap: 0.25rem;
}

/* Icon links */
.icon-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 3px;
    color: var(--text-muted);
}

.icon-link:hover {
    color: var(--accent-text);
}

.icon {
    width: 20px;
    height: 20px;
    fill: currentColor;
    display: block;
}

/* Theme Toggle */
.theme-toggle {
    background: none;
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 0.5rem;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 1.2rem;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition:
        border-color 0.2s ease,
        color 0.2s ease;
}

.theme-toggle:hover {
    color: var(--accent-text);
    border-color: var(--accent);
}

.theme-toggle .icon-sun,
[data-theme="dark"] .theme-toggle .icon-moon {
    display: none;
}

[data-theme="dark"] .theme-toggle .icon-sun {
    display: block;
}

/* Main Content */
main {
    flex: 1;
    padding: 3rem 0;
}

/* Posts on the home page: a plain list */
.post-preview {
    margin-bottom: 2.75rem;
}

.post-preview h2 {
    font-size: 1.5rem;
    margin: 0 0 0.5rem;
}

.post-preview h2 a {
    color: var(--text);
    text-decoration: none;
}

.post-preview h2 a:hover {
    color: var(--accent-text);
}

.post-preview p {
    margin-bottom: 0.5rem;
    color: var(--text-muted);
}

/* Post page: plain text column, no card */
.post-header h1 {
    margin-top: 0;
}

.post .content {
    color: var(--text-body);
    position: relative; /* holds the .read-mark elements */
}

/* Invisible points at 25/50/75/100% of a post's text; templates/base.html
   reports to Umami when the viewport reaches each one */
.read-mark {
    position: absolute;
    left: 0;
    width: 1px;
    height: 1px;
    pointer-events: none;
}

/* Article Meta */
.article-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem;
    margin: 1rem 0 2rem 0;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--border);
}

/* Labels (date, reading time, TL;DR, contents, Copy): small uppercase code type */
time,
.reading-time,
.tldr-label,
.toc summary,
.copy-button {
    font-family: var(--font-code);
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 0.75em;
}

time,
.reading-time {
    color: var(--text-muted);
}

.tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.tag {
    background-color: var(--accent);
    color: white;
    padding: 0.25rem 0.75rem;
    border-radius: 9999px;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
}

/* Content */
.content > *:first-child {
    margin-top: 0;
}

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

/* Numbered sections, like a paper: 01, 02, 02.1, in small orange code type */
.post .content {
    counter-reset: section;
}

.post .content h2 {
    counter-increment: section;
    counter-reset: subsection;
}

.post .content h3 {
    counter-increment: subsection;
}

.post .content h2::before,
.post .content h3::before {
    margin-right: 0.6em;
    font-family: var(--font-code);
    font-weight: 400;
    font-size: 0.55em;
    letter-spacing: 0.04em;
    vertical-align: 0.35em;
    color: var(--accent-text);
}

.post .content h2::before {
    content: counter(section, decimal-leading-zero);
}

.post .content h3::before {
    content: counter(section, decimal-leading-zero) "." counter(subsection);
}

.content img {
    max-width: 100%;
    height: auto;
    border-radius: 3px;
    margin: 1.5rem 0;
}

.content hr {
    border: none;
    border-top: 1px solid var(--border);
    margin: 3rem 0;
}

/* Links */
a {
    color: var(--accent-text);
    text-decoration: underline;
    text-decoration-color: var(--accent);
    text-decoration-thickness: 2px;
    text-underline-offset: 3px;
}

a:hover {
    text-decoration-thickness: 3px;
}

/* Code */
code {
    font-family: var(--font-code);
    font-variant-ligatures: common-ligatures contextual;
    font-feature-settings:
        "liga" 1,
        "calt" 1;
    background-color: var(--code-bg);
    color: var(--text);
    padding: 0.15em 0.4em;
    border-radius: 2px;
    font-size: 0.875em;
    /* Paragraphs hyphenate; a command or a name must not get a hyphen it does not have */
    hyphens: none;
}

pre {
    background-color: var(--bg-alt);
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 1rem;
    overflow-x: auto;
    margin: 1.5rem 0;
    /* Set on <pre> too: its line box sets the minimum row height of the code inside */
    font-size: var(--code-size);
    line-height: var(--code-lh);
    tab-size: 4;
}

/* Read by screen readers, not shown */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* `cowsay` output on the 404 page: text art, not a code block */
pre.cowsay {
    background: none;
    border: none;
    padding: 0;
    overflow: visible;
    /* Code blocks bleed to the screen edge on phones; the cow keeps the text's margin */
    margin-left: 0;
    margin-right: 0;
}

pre code {
    background: none;
    padding: 0;
    font-size: inherit;
    line-height: inherit;
    font-variant-ligatures: common-ligatures contextual;
    font-feature-settings:
        "liga" 1,
        "calt" 1;
}

/* Giallo line markup, required by Zola's highlighter */
.giallo-l {
    display: inline-block;
    min-height: 1lh;
    width: 100%;
    /* An empty line has no text baseline; top alignment keeps it one row tall */
    vertical-align: top;
}

.giallo-ln {
    display: inline-block;
    user-select: none;
    margin-right: 0.4em;
    /* Horizontal only: vertical padding on this inline-block makes every row taller */
    padding: 0 0.4em;
    min-width: 3ch;
    text-align: right;
}

/* The rules below carry two classes to win over the giallo stylesheets, which load later */

/* The themes' own line numbers are 1.9:1 (github-light) and 2.1:1 (one-dark-pro on --bg-alt) */
pre.giallo .giallo-ln {
    color: var(--text-muted);
}

/* github-light's orange, #E36209, is 3.49:1 on white. The class is numbered by Zola:
   after a Zola or theme change, check .z-l-9 in the built giallo-light.css */
:root:not([data-theme="dark"]) pre.giallo .z-l-9 {
    color: var(--accent-text);
}

/* one-dark-pro's own grey block; --bg-alt matches inline code */
[data-theme="dark"] pre.giallo {
    background-color: var(--bg-alt);
}


/* The themes' highlight differs from the block by 1.08:1 */
.giallo-l:is(.z-l-hl, .z-d-hl) {
    background-color: color-mix(in srgb, var(--accent) 8%, transparent);
    box-shadow: inset 3px 0 var(--accent);
}

/* Label under a highlighted line, added by the script in base.html.
   Its own row, so it stays in view when the code scrolls sideways */
.code-note {
    display: block;
    text-align: right;
    white-space: normal;
    color: var(--accent-text);
    font-weight: 700;
    user-select: none;
}

/* Source link above an embedded GitHub snippet, 0.5rem above the block */
.github-code-source {
    margin: 1.5rem 0 -1rem;
    font-size: 0.78em;
}

/* Blockquotes: a grey bar, the orange one is the TL;DR's */
blockquote {
    border-left: 4px solid var(--border);
    margin: 1.5rem 0;
    padding: 1rem 1.5rem;
    background-color: var(--bg-alt);
    font-style: italic;
    color: var(--text-body);
}

blockquote p {
    margin: 0;
}

/* Lists */
ul,
ol {
    margin: 1rem 0;
    padding-left: 2rem;
}

li {
    margin-bottom: 0.5rem;
}

/* Tables */
table {
    width: 100%;
    border-collapse: collapse;
    margin: 1.5rem 0;
    background-color: var(--bg);
}

th,
td {
    padding: 0.5rem 0.75rem;
    vertical-align: top;
    text-align: left;
    border-bottom: 1px solid var(--border);
}

th {
    background-color: var(--bg-alt);
    font-weight: 600;
}

tr:hover {
    background-color: var(--bg-alt);
}

/* Post Navigation */
.post-navigation {
    display: flex;
    justify-content: space-between;
    margin-top: 3rem;
    gap: 1rem;
}

.prev-post,
.next-post {
    flex: 1;
    padding: 1rem 1.5rem;
    background-color: var(--bg-alt);
    border: 1px solid var(--border);
    border-radius: 3px;
    color: var(--text);
    text-decoration: none;
}

.prev-post:hover,
.next-post:hover {
    background-color: var(--border);
    text-decoration: none;
}

.next-post {
    text-align: right;
}

/* Author Info */
.article-footer {
    margin-top: 3rem;
    padding-top: 2rem;
    border-top: 1px solid var(--border);
}

.author-info p {
    color: var(--text-muted);
}

/* Footer */
footer {
    border-top: 1px solid var(--border);
    padding: 1.5rem 0;
}

footer p {
    color: var(--text-muted);
    font-size: 0.875em;
}

/* Responsive */
@media (max-width: 768px) {
    .site-header {
        padding: 0.75rem 0;
    }

    .logo {
        font-size: 1.15rem;
    }

    /* Narrower buttons keep the logo on one line next to four icons at 360px */
    nav {
        gap: 0.25rem;
    }

    .icon-link {
        width: 32px;
        height: 32px;
    }

    /* The logo already links home */
    .nav-home {
        display: none;
    }

    main {
        padding: 1.5rem 0;
    }

    h3,
    .post-preview h2 {
        font-size: 1.25rem;
    }

    h4 {
        font-size: 1.125rem;
    }

    .post-navigation {
        flex-direction: column;
    }

    .next-post {
        text-align: left;
    }

    /* A wide table scrolls by itself instead of widening the whole page */
    table {
        display: block;
        overflow-x: auto;
    }
}

/* Focus ring for the keyboard only, in the text orange: --accent is 3.1:1 on white, just over the 3:1 a ring needs */
:is(a, button, summary):focus-visible {
    outline: 2px solid var(--accent-text);
    outline-offset: 2px;
}

/* GitHub-style alerts: > [!NOTE], > [!TIP], > [!IMPORTANT], > [!WARNING], > [!CAUTION] */
blockquote[class^="markdown-alert-"] {
    --alert: var(--note);
    font-style: normal;
    color: var(--text-body);
    margin: 1.5rem 0;
    padding: 0.75rem 1rem;
    border: 1px solid var(--alert);
    border-left-width: 4px;
    border-radius: 3px;
    background-color: color-mix(in srgb, var(--alert) 7%, transparent);
}

blockquote[class^="markdown-alert-"]::before {
    display: block;
    margin-bottom: 0.5rem;
    font-weight: 600;
    color: var(--alert);
}

blockquote[class^="markdown-alert-"] > :first-child {
    margin-top: 0;
}

blockquote[class^="markdown-alert-"] > :last-child {
    margin-bottom: 0;
}

/* Title colours are at least 4.5:1 on their tint in each theme */
.markdown-alert-note::before { content: "Note"; }
.markdown-alert-tip { --alert: #166534; }
.markdown-alert-tip::before { content: "Tip"; }
.markdown-alert-important { --alert: #7c3aed; }
.markdown-alert-important::before { content: "Important"; }
.markdown-alert-warning { --alert: #854d0e; }
.markdown-alert-warning::before { content: "Warning"; }
.markdown-alert-caution { --alert: #b91c1c; }
.markdown-alert-caution::before { content: "Caution"; }
[data-theme="dark"] .markdown-alert-tip { --alert: #3fb950; }
[data-theme="dark"] .markdown-alert-important { --alert: #a371f7; }
[data-theme="dark"] .markdown-alert-warning { --alert: #d29922; }
[data-theme="dark"] .markdown-alert-caution { --alert: #f85149; }

/* "#" link after headings, from templates/anchor-link.html */
.zola-anchor {
    margin-left: 0.4em;
    color: var(--text-muted);
    text-decoration: none;
    opacity: 0;
    transition: opacity 0.15s;
}

:is(h1, h2, h3, h4, h5, h6):hover .zola-anchor,
.zola-anchor:focus {
    opacity: 1;
}

.zola-anchor:hover {
    color: var(--accent-text);
}

/* No hover on touch screens: keep the link faintly visible */
@media (hover: none) {
    .zola-anchor {
        opacity: 0.4;
    }
}

/* Copy button on code blocks, added by the script in base.html */
.code-block {
    position: relative;
}

.copy-button {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    padding: 0.2rem 0.6rem;
    color: var(--text-muted);
    background-color: var(--bg-alt);
    border: 1px solid var(--border);
    border-radius: 2px;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.15s;
}

.code-block:hover .copy-button,
.copy-button:focus {
    opacity: 1;
}

/* Always shown on a touch screen, so it gets a strip of its own above the code */
@media (hover: none) {
    .copy-button {
        opacity: 1;
    }

    .code-block pre {
        padding-top: 2.25rem;
    }
}

/* TL;DR minimal callout: just an accent bar + label */
.tldr {
    border-left: 4px solid var(--accent);
    padding-left: 0.75rem;
    margin: 1.25rem 0 1.5rem;
    hyphens: auto;
}

.tldr-label {
    color: var(--accent-text);
    font-weight: 700;
    margin-right: 0.25rem;
}

.tldr p {
    /* if body renders a <p>, keep it inline */
    display: inline;
    margin: 0;
}

/* A spoiler in a post: the title takes the link colour, so it reads as something to click. */
.content details:not(.toc) {
    margin: 0 0 14px;
}

.content details:not(.toc) > summary {
    color: var(--accent-text);
    font-weight: 600;
    cursor: pointer;
}

.content details:not(.toc) > summary:hover {
    text-decoration: underline;
    text-decoration-color: var(--accent);
    text-decoration-thickness: 2px;
    text-underline-offset: 3px;
}

.content details[open]:not(.toc) > summary {
    margin-bottom: 14px;
}

/* Table of contents after the TL;DR, collapsed until opened */
.toc {
    margin: 0 0 1.5rem;
}

/* On the list, not on .toc: the "Contents" label keeps the size of the other labels */
.toc > ol {
    font-size: 0.875em;
}

.toc summary {
    color: var(--text-muted);
    cursor: pointer;
}

.toc ol {
    margin: 0.5rem 0 0;
    /* room for "10." inside the text column */
    padding-left: 1.75rem;
}

.toc a {
    color: var(--text-body);
    text-decoration: none;
}

.toc a:hover {
    color: var(--accent-text);
    text-decoration: underline;
    text-decoration-color: var(--accent);
}

.toc ol ol {
    margin-top: 0.25rem;
}

.toc li {
    margin: 0.25rem 0;
}

/* Themed images */
.themed-image {
    max-width: 100%;
    height: auto;
    display: block;
    margin: 2rem auto;
}

/* Mobile code blocks */
@media (max-width: 768px) {
    :root { --container-pad: 1rem; }

    pre { tab-size: 2; }

    /* Bleed code blocks edge-to-edge on mobile */
    pre {
        margin-left: calc(-1 * var(--container-pad));
        margin-right: calc(-1 * var(--container-pad));
        border-radius: 0;
        border-left: none;
        border-right: none;
    }
}

/* A deliberately tasteless "AI sparkle" on one word of the Claude Desktop post. */
.ai-sparkle {
    display: inline-block;
    white-space: nowrap;
    filter: drop-shadow(0 0 5px rgb(168 85 247 / 0.55)) hue-rotate(0deg);
}

.ai-sparkle-word {
    background: linear-gradient(90deg, #a855f7, #3b82f6, #ec4899);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}

.ai-sparkle-star { display: inline-block; }

/* It moves only if the reader has not asked for less motion: slowly on its own, like a GIF, and faster under a pointer. */
@media (prefers-reduced-motion: no-preference) {
    .ai-sparkle { animation: ai-sparkle-sway 1.6s ease-in-out infinite, ai-sparkle-hue 4s linear infinite; }

    .ai-sparkle-star { animation: ai-sparkle-spin 3s linear infinite; }
}

@media (hover: hover) and (prefers-reduced-motion: no-preference) {
    .ai-sparkle:hover {
        animation: ai-sparkle-wobble 0.6s ease-in-out infinite, ai-sparkle-hue 1.5s linear infinite;
    }

    .ai-sparkle:hover .ai-sparkle-star { animation: ai-sparkle-spin 0.9s linear infinite; }
}

@keyframes ai-sparkle-wobble {
    0%, 100% { rotate: -4deg; scale: 1.15; }
    50% { rotate: 4deg; scale: 1.3; }
}

@keyframes ai-sparkle-sway {
    25% { rotate: -3deg; }
    75% { rotate: 3deg; }
}

@keyframes ai-sparkle-hue {
    to { filter: drop-shadow(0 0 8px rgb(236 72 153 / 0.8)) hue-rotate(360deg); }
}

@keyframes ai-sparkle-spin {
    to { rotate: 360deg; }
}
