/* ---------------------------------------------------------------------------
   Site styles for Dirk Primbs Unprompted.

   Extracted from templates/base.html so a style tweak touches ONE file instead
   of being inlined into every generated page (which made lftp re-upload the
   whole site on any change). Served from /style.css exactly like /fonts.css.

   Theming is driven entirely by the CSS custom properties in :root. Dark mode
   is applied by setting data-theme="dark" on <html> (done by the no-flash
   script in base.html, which resolves the reader's saved choice or their OS
   setting before first paint). Never hardcode a color below — add a variable.

   <html> also carries data-theme-mode="auto|light|dark" — the reader's choice
   rather than the resolved scheme. Only the toggle's own icon rules read it;
   everything else keys off data-theme, so colours stay a single source.
--------------------------------------------------------------------------- */

:root {
    color-scheme: light;
    --text-main: #242424;
    --text-muted: #6B6B6B;
    --text-quote: rgba(41, 41, 41, 0.8);
    --accent: #0C7C74;            /* deep teal-green, sampled from the avatar */
    --accent-fg: #FFFFFF;         /* text/icon on an --accent fill */
    --bg: #FFFFFF;
    --header-bg: rgba(255, 255, 255, 0.95);
    --border: #F2F2F2;
    --surface: #FAFAFA;           /* subtly raised bg: inputs, code blocks, pills */
    --surface-strong: #F2F2F2;    /* tag badges, inline code */
    --surface-hover: #E5E5E5;
    --code-inline: #C2255C;
    --hll: #ffffcc;               /* highlighted code line */
}

:root[data-theme="dark"] {
    color-scheme: dark;
    --text-main: #E6E6E6;
    --text-muted: #9B9B9B;
    --text-quote: rgba(230, 230, 230, 0.8);
    --accent: #44A49C;            /* same tone from the avatar, lightened for dark */
    --accent-fg: #181818;
    --bg: #181818;                /* grey, not pure black */
    --header-bg: rgba(24, 24, 24, 0.95);
    --border: #2E2E2E;
    --surface: #222222;
    --surface-strong: #2A2A2A;
    --surface-hover: #333333;
    --code-inline: #FF7EB6;
    --hll: #3A3A1A;
}

body {
    font-family: "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    color: var(--text-main);
    background-color: var(--bg);
    margin: 0;
    padding: 0;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}
header {
    border-bottom: 1px solid var(--border);
    padding: 15px 20px;
    position: sticky;
    top: 0;
    background: var(--header-bg);
    backdrop-filter: blur(5px);
    z-index: 100;
}
/* --- BRANDING BAND (only when site.yaml sets site.tagline) ---
   The site name set large above the menu, the way a masthead reads, rather
   than as one more item in a row of links. It is part of <header>, so the
   whole block would otherwise stick to the top and eat the viewport on every
   scroll. Instead the header un-sticks and the nav row inside it takes over
   the stickiness: the masthead is shown once at the top of the page and
   scrolls away, and the menu stays reachable. */
header:has(.site-branding) {
    position: static;
    padding: 0;
    border-bottom: 0;
    background: none;
    backdrop-filter: none;
}
.site-branding {
    padding: 42px 20px 30px 20px;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
}
.branding-wrap {
    max-width: 1000px;
    margin: 0 auto;
}
.site-title {
    display: inline-block;
    font-family: "Plus Jakarta Sans", sans-serif;
    font-size: 44px;
    font-weight: 700;
    line-height: 1.1;
    /* Uppercase with the letters opened up: at this size a wordmark reads as a
       mark rather than as a heading, which is what tells a reader they are at
       the front door of a site and not partway into an article. */
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-main);
    text-decoration: none;
}
.site-tagline {
    margin: 8px 0 0 0;
    font-size: 16px;
    color: var(--text-muted);
}
@media (max-width: 600px) {
    .site-branding { padding: 28px 20px 22px 20px; }
    .site-title { font-size: 30px; }
    .site-tagline { font-size: 15px; }
}
header:has(.site-branding) .nav-container {
    position: sticky;
    top: 0;
    z-index: 100;
    padding: 0 20px;
    background: var(--header-bg);
    backdrop-filter: blur(5px);
    border-bottom: 1px solid var(--border);
}
/* The masthead already says whose site this is, so the compact logo in the nav
   row would be the same words twice. The band stays at every width, so this
   does too. */
header:has(.site-branding) .logo { display: none; }

.nav-container {
    max-width: 1000px;
    margin: 0 auto;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.nav-container > div {
    display: flex;
    align-items: baseline;
    gap: 20px;
}
.logo {
    font-weight: 700;
    font-size: 22px;
    letter-spacing: -0.5px;
    text-decoration: none;
    color: var(--text-main);
}
.header-links {
    display: flex;
    gap: 15px;
    font-size: 14px;
    align-items: center;
}
.header-links a {
    color: var(--text-muted);
    text-decoration: none;
    transition: color 0.2s ease;
}
.header-links a:hover {
    color: var(--accent);
}

/* Subscribe in the header, on every page of a podcast site. Filled rather than
   another muted link: it is the one action the whole site exists to invite, and
   a listener who wants it should not have to find the podcast page first. Kept
   to the same height as its neighbours so the row still reads as one bar of
   controls rather than as a banner dropped into it. */
/* The right-hand group: subscribing and searching sit together, opposite the
   menu. Subscribe belongs here rather than among the nav links because it is
   not a place on the site - it is the thing a reader leaves with. */
.nav-right {
    display: flex;
    align-items: center;
    gap: 14px;
}

.subscribe-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    /* Spelled out rather than inherited: this link lives in .nav-right now,
       outside the .header-links rule that removes underlines from the menu. */
    text-decoration: none;
    font-size: 14px;
    padding: 5px 12px;
    border-radius: 999px;
    background: var(--accent);
    color: var(--accent-fg) !important;
    font-weight: 600;
    white-space: nowrap;
    transition: filter 0.2s ease;
}
.subscribe-link:hover {
    filter: brightness(1.08);
    color: var(--accent-fg) !important;
}

/* --- CONFIGURED MENU (site.yaml `nav:`) ---
   Only rendered when the author configured one; a site without `nav:` gets the
   plain .header-links row above and none of this applies. */
.site-nav .nav-menu,
.site-nav .submenu {
    list-style: none;
    margin: 0;
    padding: 0;
}
.site-nav .nav-menu {
    display: flex;
    align-items: center;
    gap: 22px;
}
.site-nav li {
    position: relative;
    /* The hover target has to include the gap between a parent and its
       submenu, or the menu closes while the pointer crosses it. */
    padding: 14px 0;
}
.site-nav a,
.site-nav .submenu-parent {
    color: var(--text-main);
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    transition: color 0.2s ease;
}
.site-nav a:hover,
.site-nav li:hover > .submenu-parent,
.site-nav li:focus-within > .submenu-parent {
    color: var(--accent);
}
/* A section that groups links without linking anywhere itself is a <span>, not
   an <a> - see _nav_link_html(). It still needs to look like the rest of the
   row, and it must be focusable so a keyboard can open the submenu under it. */
.site-nav span.submenu-parent {
    cursor: default;
}
.site-nav .has-submenu > .submenu-parent::after {
    content: "";
    display: inline-block;
    margin-left: 6px;
    vertical-align: 2px;
    border: 4px solid transparent;
    border-top-color: currentColor;
    border-bottom: 0;
}
.site-nav .submenu {
    position: absolute;
    top: 100%;
    left: -16px;
    min-width: 220px;
    padding: 6px 0;
    background: var(--bg);
    border: 1px solid var(--border);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.07);
    /* Hidden with opacity+visibility rather than display:none so the panel can
       fade, and so its links stay in the tab order' reach only while it is
       open - visibility:hidden takes them out of it, display:none would too but
       cannot transition. */
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.15s ease, visibility 0.15s ease;
    z-index: 110;
}
.site-nav li:hover > .submenu,
.site-nav li:focus-within > .submenu {
    opacity: 1;
    visibility: visible;
}
.site-nav .submenu li {
    padding: 0;
}
.site-nav .submenu a {
    display: block;
    padding: 9px 18px;
    font-size: 14px;
    white-space: normal;
}
.site-nav .submenu a:hover {
    background: var(--surface);
}

@media (max-width: 900px) {
    /* A hover-revealed panel cannot be opened by a finger, so below the width
       where the row still fits on one line the submenus stop being panels: they
       sit inline under their parent, permanently open, indented behind a rule.
       That makes the whole menu one flat list - taller, but every link is
       reachable by tap, and none of it depends on a script the engine does not
       ship. */
    .nav-container {
        flex-wrap: wrap;
        gap: 10px;
    }
    .nav-container > div {
        flex-wrap: wrap;
    }
    /* The menu takes a whole row to itself and comes first. Without this it
       shares a flex line with the RSS link and the theme toggle, which - being
       centred against a menu many lines tall - come to rest halfway down the
       podcast list, reading as though they belonged to it. The wrap has to go
       on .header-links itself: that is the flex container those three are in,
       and 'flex: 1 1 100%' does nothing to a line that cannot break. */
    .header-links {
        flex-wrap: wrap;
        align-items: flex-start;
    }
    .site-nav {
        flex: 1 1 100%;
        order: -1;
    }
    /* Subscribe and search stay paired when the menu wraps above them. */
    .nav-right {
        gap: 10px;
    }
    .site-nav .nav-menu {
        flex-wrap: wrap;
        align-items: flex-start;
        gap: 8px 20px;
    }
    .site-nav li { padding: 6px 0; }
    .site-nav .has-submenu {
        flex: 1 1 100%;
    }
    .site-nav .has-submenu > .submenu-parent::after { display: none; }
    .site-nav .submenu {
        position: static;
        opacity: 1;
        visibility: visible;
        min-width: 0;
        margin: 6px 0 0 2px;
        padding: 0 0 0 14px;
        border: 0;
        border-left: 2px solid var(--border);
        box-shadow: none;
        display: flex;
        flex-wrap: wrap;
        gap: 2px 18px;
    }
    .site-nav .submenu a { padding: 4px 0; }
    .site-nav .submenu a:hover { background: none; }
}

/* --- THEME TOGGLE (auto / light / dark) --- */
.theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 4px;
    margin: 0;
    background: none;
    border: 0;
    border-radius: 6px;
    color: var(--text-muted);
    cursor: pointer;
    line-height: 0;
    transition: color 0.2s ease, background-color 0.2s ease;
}
.theme-toggle:hover {
    color: var(--accent);
    background: var(--surface-strong);
}
/* The button shows the mode in effect, so the icon keys off data-theme-mode
   (the reader's choice), NOT data-theme (the resolved colours) - auto and
   explicit-light both paint light and would otherwise be indistinguishable.
   The auto icon is the default, so with no attribute set (JS disabled, or
   before the pre-paint script runs) the button still shows the truth: no
   saved preference, following the system. */
.theme-toggle svg { display: none; }
.theme-toggle .icon-auto { display: block; }
:root[data-theme-mode="light"] .theme-toggle .icon-auto,
:root[data-theme-mode="dark"] .theme-toggle .icon-auto { display: none; }
:root[data-theme-mode="light"] .theme-toggle .icon-sun { display: block; }
:root[data-theme-mode="dark"] .theme-toggle .icon-moon { display: block; }

.container {
    max-width: 760px;
    margin: 50px auto;
    padding: 0 20px;
}
h1 {
    font-size: 42px;
    line-height: 1.2;
    letter-spacing: -1px;
    margin-bottom: 10px;
}
.meta {
    font-size: 14px;
    color: var(--text-muted);
    margin-bottom: 35px;
    display: flex;
    gap: 10px;
    align-items: center;
    flex-wrap: wrap;
}
.meta a.tag-badge {
    background: var(--surface-strong);
    padding: 2px 8px;
    border-radius: 10px;
    font-size: 12px;
    color: var(--text-main);
    text-decoration: none;
    transition: background 0.2s ease;
}
.meta a.tag-badge:hover {
    background: var(--surface-hover);
    color: var(--accent);
}
.article-content {
    font-family: "Source Serif 4", Georgia, Cambria, serif;
    font-size: 20px;
    line-height: 1.65;
    color: var(--text-main);
    letter-spacing: -0.003em;
}
.article-content p { margin-bottom: 24px; }
.article-content h2 { font-size: 26px; margin-top: 40px; letter-spacing: -0.5px; font-family: "Plus Jakarta Sans", sans-serif; }
.article-content h3 { font-size: 22px; margin-top: 30px; font-family: "Plus Jakarta Sans", sans-serif; }
.article-content a { color: var(--text-main); text-decoration: underline; text-underline-offset: 4px; }
.article-content a:hover { color: var(--accent); }

.article-content img {
    max-width: 100%;
    height: auto;
    display: block;
    margin: 30px auto;
    border-radius: 4px;
}

/* Consecutive images (no blank line between them in Markdown, so they land in
   one paragraph) render as a responsive row; a blank line keeps them stacked
   full-width. The row collapses to a single full-width column on narrow
   screens, so nothing shrinks to mush on a phone. */
.article-content p:has(img + img) {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    margin: 30px auto;
}
.article-content p:has(img + img) img {
    margin: 0;
    flex: 1 1 0;
    min-width: 0;
}
@media (max-width: 600px) {
    .article-content p:has(img + img) { display: block; }
    .article-content p:has(img + img) img { margin: 20px auto; }
}

.post-card {
    border-bottom: 1px solid var(--border);
    padding: 25px 0;
    display: flex;
    flex-direction: column;
}
.post-card h2 { margin: 0 0 8px 0; font-size: 22px; line-height: 1.3; }
.post-card h2 a { text-decoration: none; color: var(--text-main); }
.post-card h2 a:hover { color: var(--text-muted); }
.post-card .summary { color: var(--text-muted); font-size: 16px; margin: 0 0 12px 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

.search-form {
    display: flex;
    align-items: center;
    position: relative;
}
.search-input {
    border: 1px solid var(--border);
    background-color: var(--surface);
    color: var(--text-main);
    padding: 6px 12px;
    border-radius: 20px;
    font-size: 14px;
    outline: none;
    width: 160px;
    transition: width 0.2s ease, background-color 0.2s ease;
}
.search-input:focus {
    width: 220px;
    background-color: var(--bg);
    border-color: var(--text-muted);
}

/* Client-side search results dropdown (see static/search.js). */
.search-results {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    width: min(360px, 90vw);
    max-height: 70vh;
    overflow-y: auto;
    background-color: var(--bg);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
    z-index: 1000;
    padding: 6px;
}
.search-hit {
    display: block;
    padding: 10px 12px;
    border-radius: 8px;
    text-decoration: none;
    color: var(--text-main);
}
.search-hit:hover,
.search-hit:focus {
    background-color: var(--surface-hover);
}
.search-hit-title {
    display: block;
    font-weight: 600;
    font-size: 15px;
    margin-bottom: 2px;
}
.search-hit-snippet {
    display: block;
    color: var(--text-muted);
    font-size: 13px;
    line-height: 1.4;
}
.search-empty {
    margin: 0;
    padding: 10px 12px;
    color: var(--text-muted);
    font-size: 14px;
}

.tag-cloud-container {
    margin: 30px 0 40px 0;
    padding-bottom: 20px;
    border-bottom: 1px solid var(--border);
}
.tag-cloud-title {
    font-size: 13px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    margin-bottom: 15px;
}
.tag-cloud {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
}
.tag-cloud a.tag-pill {
    background: var(--surface);
    border: 1px solid var(--border);
    padding: 6px 14px;
    border-radius: 20px;
    font-size: 14px;
    color: var(--text-main);
    text-decoration: none;
    transition: all 0.2s ease;
}
.tag-cloud a.tag-pill:hover {
    border-color: var(--text-muted);
    background: var(--bg);
    color: var(--accent);
}
.tag-count {
    color: var(--text-muted);
    font-size: 12px;
    margin-left: 4px;
}

/* COLLAPSIBLE TAGS STYLING */
details.more-tags {
    width: 100%;
    margin-top: 10px;
}
details.more-tags summary {
    font-size: 13px;
    color: var(--accent);
    cursor: pointer;
    outline: none;
    user-select: none;
    margin-bottom: 10px;
}
details.more-tags summary:hover {
    text-decoration: underline;
}
.tags-hidden-wrapper {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    padding-top: 5px;
}

/* Per-tag "Subscribe" RSS link in a tag page's heading. */
.feed-subscribe {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    vertical-align: middle;
    margin-left: 10px;
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
    color: var(--text-muted);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 3px 12px;
    transition: color 0.2s ease, border-color 0.2s ease;
}
.feed-subscribe:hover {
    color: var(--accent);
    border-color: var(--accent);
}

/* PAGINATION NAV STYLING */
.pagination {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 35px;
    font-size: 15px;
}
.pagination a {
    color: var(--accent);
    text-decoration: none;
    font-weight: 600;
}
.pagination a:hover {
    text-decoration: underline;
}
.pagination .disabled {
    color: var(--text-muted);
    font-weight: normal;
}

/* --- ARTICLE ADJACENCY NAVIGATION --- */
.article-nav-bounds {
    margin-top: 60px;
    padding-top: 30px;
    border-top: 1px solid var(--border);
    display: flex;
    justify-content: space-between;
    gap: 20px;
}
.article-nav-block {
    flex: 1;
    display: flex;
    flex-direction: column;
    text-decoration: none !important;
}
.article-nav-block.next {
    text-align: right;
}
.article-nav-label {
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    margin-bottom: 4px;
}
.article-nav-title {
    font-size: 16px;
    font-weight: 600;
    color: var(--text-main);
    line-height: 1.4;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.article-nav-block:hover .article-nav-title {
    color: var(--accent);
}

/* --- TABLES --- */
.article-content table {
    width: 100%;
    border-collapse: collapse;
    margin: 35px 0;
    font-family: "Plus Jakarta Sans", sans-serif;
    font-size: 16px;
    line-height: 1.5;
}
.article-content th {
    border-bottom: 2px solid var(--text-main);
    text-align: left;
    padding: 12px 10px;
    font-weight: 600;
    color: var(--text-main);
}
.article-content td {
    border-bottom: 1px solid var(--border);
    padding: 12px 10px;
    color: var(--text-muted);
}
.article-content tr:hover td {
    color: var(--text-main);
}

/* --- SITE FOOTER / AI TRANSPARENCY LABEL --- */
.site-footer {
    max-width: 760px;
    margin: 60px auto 40px auto;
    padding: 20px;
    border-top: 1px solid var(--border);
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-muted);
}
.site-footer .ai-label {
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-main);
}
.site-footer .ai-explainer {
    margin-top: 2px;
}
.site-footer a {
    color: var(--accent);
    text-decoration: none;
}
.site-footer a:hover {
    text-decoration: underline;
}

/* --- BLOCKQUOTES --- */
.article-content blockquote {
    border-left: 3px solid var(--text-main);
    padding-left: 20px;
    margin: 35px 0;
    font-style: italic;
    color: var(--text-quote);
}

/* --- CODE BLOCKS WITH SYNTAX COLORING --- */
.article-content pre {
    background: var(--surface);
    border: 1px solid var(--border);
    padding: 20px;
    border-radius: 4px;
    overflow-x: auto;
    margin: 35px 0;
}
.article-content pre code {
    font-family: "Space Mono", SFMono-Regular, Consolas, monospace;
    font-size: 15px;
    line-height: 1.5;
    background: transparent;
    padding: 0;
    border-radius: 0;
}
.article-content :not(pre) > code {
    font-family: "Space Mono", SFMono-Regular, Consolas, monospace;
    background: var(--surface-strong);
    padding: 3px 6px;
    border-radius: 4px;
    font-size: 15px;
    color: var(--code-inline);
}

/* Pygments Light Color Matrix (.codehilite map) */
.codehilite .hll { background-color: var(--hll) }
.codehilite .c   { color: #727272; font-style: italic }
.codehilite .err { color: #a61717; background-color: #e3d2d2 }
.codehilite .k   { color: #1A8917; font-weight: bold }
.codehilite .o   { color: #242424 }
.codehilite .ch  { color: #727272; font-style: italic }
.codehilite .cm  { color: #727272; font-style: italic }
.codehilite .cp  { color: #008080 }
.codehilite .cpf { color: #727272; font-style: italic }
.codehilite .c1  { color: #727272; font-style: italic }
.codehilite .cs  { color: #727272; font-style: italic }
.codehilite .gd  { color: #000000; background-color: #ffdddd }
.codehilite .ge  { color: #000000; font-style: italic }
.codehilite .gr  { color: #aa0000 }
.codehilite .gh  { color: #999999 }
.codehilite .gi  { color: #000000; background-color: #ddffdd }
.codehilite .go  { color: #888888 }
.codehilite .gp  { color: #555555 }
.codehilite .gs  { font-weight: bold }
.codehilite .gu  { color: #aaaaaa }
.codehilite .gt  { color: #aa0000 }
.codehilite .kc  { color: #1A8917; font-weight: bold }
.codehilite .kd  { color: #1A8917; font-weight: bold }
.codehilite .kn  { color: #1A8917; font-weight: bold }
.codehilite .kp  { color: #1A8917; font-weight: bold }
.codehilite .kr  { color: #1A8917; font-weight: bold }
.codehilite .kt  { color: #445588; font-weight: bold }
.codehilite .m   { color: #009999 }
.codehilite .s   { color: #b85c00 }
.codehilite .na  { color: #008080 }
.codehilite .nb  { color: #0086B3 }
.codehilite .nc  { color: #445588; font-weight: bold }
.codehilite .no  { color: #008080 }
.codehilite .nd  { color: #3c5d5d; font-weight: bold }
.codehilite .ni  { color: #800080 }
.codehilite .ne  { color: #990000; font-weight: bold }
.codehilite .nf  { color: #0044dd; font-weight: bold }
.codehilite .nl  { color: #990000; font-weight: bold }
.codehilite .nn  { color: #555555 }
.codehilite .nt  { color: #000080 }
.codehilite .nv  { color: #008080 }
.codehilite .ow  { color: #000000; font-weight: bold }
.codehilite .w   { color: #bbbbbb }
.codehilite .mb  { color: #009999 }
.codehilite .mf  { color: #009999 }
.codehilite .mh  { color: #009999 }
.codehilite .mi  { color: #009999 }
.codehilite .mo  { color: #009999 }
.codehilite sa  { color: #b85c00 }
.codehilite .sb  { color: #b85c00 }
.codehilite .sc  { color: #b85c00 }
.codehilite .dl  { color: #b85c00 }
.codehilite .sd  { color: #b85c00; font-style: italic }
.codehilite .s2  { color: #b85c00 }
.codehilite .se  { color: #b85c00 }
.codehilite .sh  { color: #b85c00 }
.codehilite .si  { color: #b85c00 }
.codehilite .sx  { color: #b85c00 }
.codehilite .sr  { color: #009926 }
.codehilite .s1  { color: #b85c00 }
.codehilite .ss  { color: #990073 }
.codehilite .bp  { color: #999999 }
.codehilite .fm  { color: #0044dd; font-weight: bold }
.codehilite .vc  { color: #008080 }
.codehilite .vg  { color: #008080 }
.codehilite .vi  { color: #008080 }
.codehilite .vm  { color: #008080 }
.codehilite .il  { color: #009999 }

/* Pygments Dark override — a light syntax theme on a dark background is the
   ugliest failure mode, so remap the token palette when data-theme="dark". */
:root[data-theme="dark"] .codehilite .err { color: #E06C75; background-color: transparent }
:root[data-theme="dark"] .codehilite .c,
:root[data-theme="dark"] .codehilite .ch,
:root[data-theme="dark"] .codehilite .cm,
:root[data-theme="dark"] .codehilite .cpf,
:root[data-theme="dark"] .codehilite .c1,
:root[data-theme="dark"] .codehilite .cs { color: #7F848E; font-style: italic }
:root[data-theme="dark"] .codehilite .cp { color: #56B6C2 }
:root[data-theme="dark"] .codehilite .k,
:root[data-theme="dark"] .codehilite .kc,
:root[data-theme="dark"] .codehilite .kd,
:root[data-theme="dark"] .codehilite .kn,
:root[data-theme="dark"] .codehilite .kp,
:root[data-theme="dark"] .codehilite .kr { color: #C678DD; font-weight: bold }
:root[data-theme="dark"] .codehilite .kt,
:root[data-theme="dark"] .codehilite .nc,
:root[data-theme="dark"] .codehilite .nn,
:root[data-theme="dark"] .codehilite .ni,
:root[data-theme="dark"] .codehilite .bp { color: #E5C07B }
:root[data-theme="dark"] .codehilite .o,
:root[data-theme="dark"] .codehilite .ow,
:root[data-theme="dark"] .codehilite .nb { color: #56B6C2 }
:root[data-theme="dark"] .codehilite .m,
:root[data-theme="dark"] .codehilite .mb,
:root[data-theme="dark"] .codehilite .mf,
:root[data-theme="dark"] .codehilite .mh,
:root[data-theme="dark"] .codehilite .mi,
:root[data-theme="dark"] .codehilite .mo,
:root[data-theme="dark"] .codehilite .il,
:root[data-theme="dark"] .codehilite .na,
:root[data-theme="dark"] .codehilite .no,
:root[data-theme="dark"] .codehilite .nv,
:root[data-theme="dark"] .codehilite .vc,
:root[data-theme="dark"] .codehilite .vg,
:root[data-theme="dark"] .codehilite .vi,
:root[data-theme="dark"] .codehilite .vm { color: #D19A66 }
:root[data-theme="dark"] .codehilite .s,
:root[data-theme="dark"] .codehilite .sa,
:root[data-theme="dark"] .codehilite .sb,
:root[data-theme="dark"] .codehilite .sc,
:root[data-theme="dark"] .codehilite .dl,
:root[data-theme="dark"] .codehilite .sd,
:root[data-theme="dark"] .codehilite .s2,
:root[data-theme="dark"] .codehilite .se,
:root[data-theme="dark"] .codehilite .sh,
:root[data-theme="dark"] .codehilite .si,
:root[data-theme="dark"] .codehilite .sx,
:root[data-theme="dark"] .codehilite .sr,
:root[data-theme="dark"] .codehilite .s1 { color: #98C379 }
:root[data-theme="dark"] .codehilite .ss { color: #C678DD }
:root[data-theme="dark"] .codehilite .nf,
:root[data-theme="dark"] .codehilite .fm,
:root[data-theme="dark"] .codehilite .nd { color: #61AFEF }
:root[data-theme="dark"] .codehilite .nt,
:root[data-theme="dark"] .codehilite .ne,
:root[data-theme="dark"] .codehilite .nl { color: #E06C75 }
:root[data-theme="dark"] .codehilite .gd { color: #E6E6E6; background-color: #3A1C1C }
:root[data-theme="dark"] .codehilite .gi { color: #E6E6E6; background-color: #1C3A1C }
:root[data-theme="dark"] .codehilite .gr,
:root[data-theme="dark"] .codehilite .gt { color: #E06C75 }
:root[data-theme="dark"] .codehilite .gh { color: #61AFEF }
:root[data-theme="dark"] .codehilite .gu { color: #56B6C2 }
:root[data-theme="dark"] .codehilite .go,
:root[data-theme="dark"] .codehilite .gp { color: #9B9B9B }
:root[data-theme="dark"] .codehilite .w { color: #3A3A3A }

/* Click-to-play YouTube facade: shows the thumbnail only, and loads
   YouTube's iframe (and its cookies/JS) exclusively after a click. */
.yt-facade {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    margin: 1.5em 0;
    border-radius: 8px;
    overflow: hidden;
    cursor: pointer;
    background: #000;
}
.yt-facade .yt-thumb {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.yt-facade .yt-play {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 68px;
    height: 48px;
    border-radius: 12px;
    background: rgba(20, 20, 20, 0.75);
    transition: background 0.15s ease;
}
.yt-facade:hover .yt-play,
.yt-facade:focus-visible .yt-play { background: var(--accent); }
.yt-facade .yt-play::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-40%, -50%);
    border-style: solid;
    border-width: 11px 0 11px 19px;
    border-color: transparent transparent transparent #fff;
}
.yt-facade iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

/* Mastodon-powered comments (loaded client-side on click). */
.comments {
    margin: 3em 0 1em;
    padding-top: 1.5em;
    border-top: 1px solid var(--border);
}
.comments-title { margin: 0 0 0.25em; }
.comments-intro { color: var(--text-muted); margin: 0 0 1em; font-size: 0.95em; }
.comments-load {
    font: inherit;
    font-weight: 600;
    color: var(--accent-fg);
    background: var(--accent);
    border: 0;
    border-radius: 999px;
    padding: 8px 18px;
    cursor: pointer;
}
.comments-load:hover { filter: brightness(0.93); }
.comments-load[disabled] { opacity: 0.6; cursor: default; }
.comments-status { color: var(--text-muted); font-size: 0.95em; margin: 1em 0; }
.comment {
    display: flex;
    gap: 12px;
    padding: 1em 0;
    border-top: 1px solid var(--border);
}
.comment.comment-reply { margin-left: 2em; }
.comment-avatar {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    flex-shrink: 0;
    object-fit: cover;
    background: var(--border);
}
.comment-body { flex: 1; min-width: 0; }
.comment-head { font-size: 0.9em; margin-bottom: 0.25em; }
.comment-author { font-weight: 600; color: var(--text-main); text-decoration: none; }
.comment-author:hover { text-decoration: underline; }
.comment-instance { color: var(--text-muted); }
.comment-op-badge {
    display: inline-block;
    font-size: 0.72em;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--accent);
    border: 1px solid var(--accent);
    border-radius: 4px;
    padding: 0 5px;
    margin-left: 4px;
    vertical-align: 1px;
}
/* Origin badge. Replies from both networks blend into one chronological list,
   so this is what stops two different handle formats reading as a bug. Muted
   rather than accent-coloured: it should be findable, not competing with the
   OP badge beside it. */
.comment-network {
    display: inline-block;
    font-size: 0.72em;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 0 5px;
    margin-left: 6px;
    vertical-align: 1px;
}
.comment-date { color: var(--text-muted); text-decoration: none; }
.comment-date:hover { text-decoration: underline; }
.comment-content { line-height: 1.55; }
.comment-content p:first-child { margin-top: 0; }
.comment-content p:last-child { margin-bottom: 0; }
.comment-content img.emoji {
    height: 1.1em;
    width: auto;
    vertical-align: -0.15em;
    display: inline;
}
.comment-favs {
    display: inline-block;
    margin-top: 0.4em;
    font-size: 0.85em;
    color: var(--text-muted);
    text-decoration: none;
}
.comment-favs:hover { text-decoration: underline; }

/* ---------------------------------------------------------------------------
   Standalone pages (about, colophon): rendered from content_pipeline/pages/
   through the same base.html as everything else, so they only need the few
   bits an article doesn't have.
--------------------------------------------------------------------------- */
.page-content > h1:first-of-type { margin-bottom: 0.6em; }

/* --- PANEL LAYOUT ('layout: panel' in a page's frontmatter) ---
   Title in a narrow left column, body beside it. The wider measure this needs
   is granted to the page rather than to .container generally, so an article
   keeps its 760px reading column. */
.container:has(.page-panel) {
    max-width: 1000px;
}
/* The footer's rule is a full-width line under the page, so it has to match
   whatever measure the page above it is using or it starts partway in from the
   text it is closing off. */
body:has(.page-panel) .site-footer {
    max-width: 1000px;
}
.page-panel {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.9fr);
    column-gap: 56px;
    /* Sans, not the article serif. A panel page is signage - who this is, what
       is here, where to go next - read in glances rather than settled into, and
       the serif's job on an article page is the opposite of that. */
    font-family: "Plus Jakarta Sans", sans-serif;
    font-size: 17px;
    line-height: 1.7;
    letter-spacing: 0;
}
/* Every vertical margin here is set on both sides rather than left to the
   browser default, because a grid container does not collapse its children's
   margins: the gap between two blocks is the sum of the two, so an unset
   margin-top is a gap silently added to the one below it. */
.page-panel p { margin: 0 0 20px 0; }
/* Headings scaled to the panel's smaller body text. The article sizes are set
   against a 20px serif measure and, dropped in here, read as a page of titles
   with captions under them. */
.page-panel h2 { font-size: 21px; margin: 40px 0 12px 0; letter-spacing: -0.2px; }
.page-panel h3 { font-size: 16px; margin: 30px 0 10px 0; letter-spacing: 0; }
.page-panel h2 + h3 { margin-top: 20px; }
/* Every child sits in the right-hand column except the title. Grid's own
   placement then stacks them from the first row down, which is what puts the
   opening paragraph level with the heading instead of below it. */
.page-panel > * { grid-column: 2; }
.page-panel > .panel-title { grid-column: 1; }
.panel-title {
    /* Small, bold and opened up: a label for the section rather than a headline
       competing with the masthead above it. */
    font-family: "Plus Jakarta Sans", sans-serif;
    font-size: 15px;
    font-weight: 700;
    line-height: 1.5;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin: 6px 0 0 0;
}
/* The body starts level with the title. Child 1 is .panel-title (which sits in
   the other column), so child 2 is the first thing in this one - NOT
   ':first-of-type', which matches the first element of every type and would
   also flatten the first heading against whatever precedes it. */
.page-panel > *:nth-child(2) { margin-top: 0; }

@media (max-width: 782px) {
    /* One column: the left rail has nowhere to go, and a title stacked over
       its own body is the same reading order the grid was producing. */
    .page-panel { display: block; }
    .panel-title { margin-bottom: 1.2em; }
}

/* --- PICTURE GRID (a page's own markup, e.g. the speaker pictures) ---
   Thumbnails at their natural size, each linking to the full file. Sized in
   columns rather than by a fixed width so portrait, square and landscape crops
   sit on one baseline grid without being stretched to match. */
.speaker-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 26px 20px;
    align-items: end;
    margin: 24px 0 28px 0;
}
.speaker-grid figure {
    margin: 0;
}
/* The article rule centres images and gives them 30px of vertical margin,
   which inside a grid cell is a gap the grid already provides. */
.page-content .speaker-grid img {
    margin: 0;
    width: 100%;
    height: auto;
    border-radius: 3px;
}
.speaker-grid a {
    display: block;
    text-decoration: none;
}
.speaker-grid a:hover img {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.speaker-grid figcaption {
    margin-top: 7px;
    font-size: 13px;
    line-height: 1.4;
    color: var(--text-muted);
}
.about-portrait {
    float: right;
    width: 180px;
    max-width: 40%;
    margin: 0 0 1.5em 1.75em;
    border-radius: 12px;
    border: 1px solid var(--border);
}

@media (max-width: 600px) {
    /* Floating it beside two lines of text looks cramped on a phone; centre it
       above the prose instead. */
    .about-portrait {
        float: none;
        display: block;
        width: 150px;
        max-width: 60%;
        margin: 0 auto 1.5em;
    }
}

/* Optional per-tag emoji (display.tag_emoji in site.yaml). Decorative only -
   the markup carries aria-hidden, so this just needs spacing. */
.tag-emoji {
    margin-right: 0.3em;
    font-style: normal;
    /* Most emoji are colour glyphs and ignore this, but a few have a
       text-presentation fallback that would inherit the link's hover colour.
       Pin it to the body colour so those stay legible in both themes - NOT
       'initial', which resolves to black and disappears on the dark theme. */
    color: var(--text-main);
}

/* ===========================================================================
   PODCAST
   ---------------------------------------------------------------------------
   The show header on /podcast.html, the episode list under it, and the player
   card an episode page carries. All of this markup is generated - see
   build_podcast_page(), _episode_row_html() and _player_html() in
   build_blog.py.

   Shape is taken from schlanada.kopfstim.me (Podlove Publisher): a show header
   with cover art and subscribe buttons, an episode list keyed by a date chip,
   and an episode page whose player is a card - cover, show name, title, one
   big play control, and a row of secondary actions under a dotted rule.

   Colour is NOT taken from there. Every value here is one of the theme's own
   custom properties, so both light and dark mode are correct for free and the
   podcast does not become a second visual identity inside the same site.
   =========================================================================== */

/* --- Show header ---------------------------------------------------------- */

.podcast-hero {
    display: grid;
    grid-template-columns: 200px minmax(0, 1fr);
    gap: 32px;
    align-items: start;
    margin: 0 0 44px 0;
    padding: 0 0 36px 0;
    border-bottom: 1px solid var(--border);
}
.podcast-hero img {
    width: 100%;
    height: auto;
    margin: 0;
    border-radius: 4px;
    /* The cover is artwork, not a photograph in the flow of an article, so it
       keeps a hairline instead of floating on the page background - it has to
       read as a bounded object at both themes, and dark artwork on a dark page
       otherwise has no edge at all. */
    border: 1px solid var(--border);
}
.podcast-eyebrow {
    font-family: "Plus Jakarta Sans", sans-serif;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--accent);
    margin: 0 0 10px 0;
}
.podcast-hero h1 {
    font-family: "Plus Jakarta Sans", sans-serif;
    font-size: 38px;
    line-height: 1.15;
    letter-spacing: -0.5px;
    margin: 0 0 8px 0;
}
.podcast-hero .podcast-strapline {
    font-size: 17px;
    color: var(--text-muted);
    margin: 0 0 18px 0;
}
.podcast-hero p {
    margin: 0 0 18px 0;
}

/* The compact header on episode-list pages after the first. Same face and
   weight as the hero's title, so page 2 reads as the same page minus the
   introduction rather than as a different template. */
.podcast-pagehead {
    margin: 0 0 26px 0;
    padding: 0 0 22px 0;
    border-bottom: 1px solid var(--border);
}
.podcast-pagehead h1 {
    font-family: "Plus Jakarta Sans", sans-serif;
    font-size: 32px;
    line-height: 1.15;
    letter-spacing: -0.5px;
    margin: 0;
}

/* Subscribe row. Every directory gets the same weight except the feed itself,
   which is the only one of these links that does not depend on somebody else's
   platform still existing - so it is the filled one. */
.podcast-subscribe {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin: 22px 0 0 0;
}
.podcast-subscribe a {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 9px 16px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface);
    color: var(--text-main);
    font-family: "Plus Jakarta Sans", sans-serif;
    font-size: 14px;
    font-weight: 600;
    text-decoration: none;
    transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}
.podcast-subscribe a:hover {
    border-color: var(--accent);
    color: var(--accent);
    background: var(--surface-hover);
}
.podcast-subscribe a.is-feed {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--accent-fg);
}
.podcast-subscribe a.is-feed:hover {
    background: var(--accent);
    color: var(--accent-fg);
    filter: brightness(1.08);
}

/* --- Episode list --------------------------------------------------------- */

.episode-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.episode-row {
    display: grid;
    grid-template-columns: 58px 92px minmax(0, 1fr);
    gap: 22px;
    align-items: start;
    padding: 22px 0;
    border-bottom: 1px solid var(--border);
}
.episode-row:last-child {
    border-bottom: 0;
}

/* The date chip, lifted straight from the reference: day large, month small and
   uppercase, year quietest of the three. It is a block rather than a line of
   text because the list is scanned by date far more often than it is read. */
.episode-date {
    text-align: center;
    padding: 8px 0 6px 0;
    background: var(--surface);
    border-left: 3px solid var(--accent);
    font-family: "Plus Jakarta Sans", sans-serif;
    line-height: 1.1;
}
.episode-date .d {
    display: block;
    font-size: 21px;
    font-weight: 700;
    color: var(--text-main);
}
.episode-date .m {
    display: block;
    margin-top: 3px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.episode-date .y {
    display: block;
    margin-top: 3px;
    font-size: 11px;
    color: var(--text-muted);
    opacity: 0.75;
}

.episode-row .episode-art {
    width: 92px;
    height: auto;
    margin: 0;
    border-radius: 3px;
    border: 1px solid var(--border);
}
.episode-body h2 {
    font-family: "Plus Jakarta Sans", sans-serif;
    font-size: 22px;
    line-height: 1.25;
    letter-spacing: -0.2px;
    margin: 0 0 8px 0;
}
.episode-body h2 a {
    color: var(--text-main);
    text-decoration: none;
    border-bottom: 2px solid transparent;
    transition: border-color 0.2s ease, color 0.2s ease;
}
.episode-body h2 a:hover {
    color: var(--accent);
    border-bottom-color: var(--accent);
}
.episode-body p {
    margin: 0 0 10px 0;
    font-size: 17px;
    color: var(--text-muted);
}
/* Number, duration, size: the things a listener decides on before playing. Kept
   to one quiet line so they never compete with the title. */
.episode-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 14px;
    font-family: "Plus Jakarta Sans", sans-serif;
    font-size: 13px;
    color: var(--text-muted);
}
.episode-meta .sep {
    opacity: 0.4;
}

/* --- Player card (episode page) ------------------------------------------- */

.episode-player {
    margin: 30px 0 26px 0;
    padding: 26px 28px 20px 28px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 6px;
}
.episode-player-head {
    display: grid;
    grid-template-columns: 108px minmax(0, 1fr);
    gap: 20px;
    align-items: center;
}
.episode-player-head img {
    width: 108px;
    height: auto;
    margin: 0;
    border-radius: 3px;
    border: 1px solid var(--border);
}
.episode-show {
    font-family: "Plus Jakarta Sans", sans-serif;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.06em;
    color: var(--accent);
    margin: 0 0 4px 0;
}
.episode-player-head .episode-name {
    font-family: "Plus Jakarta Sans", sans-serif;
    font-size: 20px;
    font-weight: 700;
    line-height: 1.3;
    color: var(--text-main);
    margin: 0;
}

/* One big control rather than the browser's default bar. The native element is
   kept in the markup and only visually hidden, so the page still works as an
   audio page with the script missing - see podcast.js. */
.episode-controls {
    display: flex;
    align-items: center;
    gap: 18px;
    margin: 22px 0 16px 0;
}
.episode-play {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    flex: 0 0 auto;
    padding: 12px 24px 12px 20px;
    border: 0;
    border-radius: 999px;
    background: var(--accent);
    color: var(--accent-fg);
    font-family: "Plus Jakarta Sans", sans-serif;
    font-size: 16px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    transition: filter 0.2s ease;
}
.episode-play:hover {
    filter: brightness(1.08);
}
.episode-play svg {
    flex-shrink: 0;
}
/* The `hidden` attribute does NOT hide an <svg>: the UA stylesheet's
   [hidden] { display: none } rule is scoped to the HTML namespace, so an SVG
   carrying it renders anyway. The play/pause pair swap by that attribute, so
   without this rule the button shows both glyphs at once. */
.episode-play svg[hidden] {
    display: none;
}
/* The seek bar is 6px of visible groove inside a 22px hit area. Drawing the
   groove with ::before rather than as the element's own background is what
   separates the two: a 6px-tall click target is one nobody can hit, so clicking
   to seek reads as broken even though the handler is right there. The hit area
   has to be tall enough to aim at, and the groove has to stay thin to look like
   a progress bar. */
.episode-progress {
    flex: 1 1 auto;
    position: relative;
    height: 22px;
    display: flex;
    align-items: center;
    cursor: pointer;
    /* No text selection while scrubbing: a drag across the bar would otherwise
       start selecting the duration text beside it. */
    user-select: none;
    -webkit-user-select: none;
    touch-action: none;
}
.episode-progress::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    height: 6px;
    border-radius: 3px;
    background: var(--surface-hover);
}
.episode-progress:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
    border-radius: 3px;
}
.episode-progress .bar {
    position: relative;
    display: block;
    height: 6px;
    width: 0;
    border-radius: 3px;
    background: var(--accent);
}
/* A thumb, so the bar reads as something you can grab rather than as a read-out.
   It sits at the end of the filled portion and only appears once there is a
   pointer on the control or focus in it. */
.episode-progress .bar::after {
    content: "";
    position: absolute;
    right: 0;
    top: 50%;
    width: 13px;
    height: 13px;
    margin-right: -6px;
    border-radius: 50%;
    background: var(--accent);
    transform: translateY(-50%) scale(0);
    transition: transform 0.12s ease;
}
.episode-progress:hover .bar::after,
.episode-progress:focus-visible .bar::after,
.episode-progress.is-scrubbing .bar::after {
    transform: translateY(-50%) scale(1);
}
.episode-elapsed {
    flex: 0 0 auto;
    font-family: "Space Mono", monospace;
    font-size: 13px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* Secondary actions, under the dotted rule the reference uses. Dotted rather
   than solid on purpose: it separates without reading as the end of the card. */
.episode-actions {
    display: flex;
    gap: 26px;
    padding-top: 14px;
    border-top: 1px dotted var(--border);
}
.episode-actions a {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-family: "Plus Jakarta Sans", sans-serif;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-muted);
    text-decoration: none;
    transition: color 0.2s ease;
}
.episode-actions a:hover {
    color: var(--accent);
}

/* Shownotes: a chapter list is a table of contents for audio, so it is numbered
   by timestamp rather than bulleted. */
.episode-chapters {
    list-style: none;
    margin: 26px 0;
    padding: 0;
}
.episode-chapters li {
    display: grid;
    grid-template-columns: 74px minmax(0, 1fr);
    gap: 14px;
    padding: 7px 0;
    border-bottom: 1px solid var(--border);
    font-size: 17px;
}
.episode-chapters li:last-child {
    border-bottom: 0;
}
.episode-chapters .t {
    font-family: "Space Mono", monospace;
    font-size: 13px;
    color: var(--accent);
    padding-top: 3px;
}

@media (max-width: 700px) {
    .podcast-hero {
        grid-template-columns: 140px minmax(0, 1fr);
        gap: 20px;
    }
    .podcast-hero h1 { font-size: 28px; }
    /* The thumbnail is the first thing to go: at this width the date chip still
       earns its column, but a 92px cover repeated down the list does not. */
    .episode-row {
        grid-template-columns: 52px minmax(0, 1fr);
        gap: 16px;
    }
    .episode-row .episode-art { display: none; }
    .episode-player {
        padding: 20px 18px 16px 18px;
    }
    .episode-player-head {
        grid-template-columns: 76px minmax(0, 1fr);
        gap: 14px;
    }
    .episode-player-head img { width: 76px; }
    .episode-controls {
        flex-wrap: wrap;
        gap: 12px;
    }
    .episode-progress { order: 3; flex-basis: 100%; }
    .episode-actions { gap: 18px; flex-wrap: wrap; }
}

@media (max-width: 520px) {
    /* The hero stacks. Two columns survive down to about here, but below it the
       text beside a cover is running at twenty-odd characters a line, which is
       narrower than the episode blurbs underneath it - the header would be the
       hardest thing on the page to read. */
    .podcast-hero {
        grid-template-columns: minmax(0, 1fr);
        gap: 18px;
    }
    .podcast-hero img {
        width: 150px;
    }
}

/* The vendored Podlove subscribe button renders itself into an iframe, so it
   is styled from inside and all this can do is give it space. Kept beside the
   plain pills rather than replacing them: the pills work with JavaScript off
   and name the two directories most listeners actually use, while the button
   is what puts a feed into an app nobody has a web link for. */
.podcast-button {
    margin: 18px 0 0 0;
    min-height: 40px;
}
