.toc {
    position: fixed;
    top: 1em;
    margin-left: -28%;
    width: 26%;
    border: 1px solid var(--text-color);
    padding: 10px;
    padding-top: 1.4em;
    overflow: visible;
}
.toc-scroll {
    overflow-y: auto;
    max-height: 90vh;
    line-height: 1.4;
    word-break: break-all;
}

/* CALLOUT */
.callout {
    font-style: italic;
    border: 3px outset var(--text-color);
    margin-left: 3ch;
    position: relative;
    /* Generous inner padding: text must not touch the border (top keeps
       clearance for the floating .box-title). */
    padding: 1.4em 1.5em 1.2em;
    margin-top: 1.5em;
    margin-bottom: 1.5em;
}
.callout p {
    padding-left: 0;
}
/* Callout title behaves like a real <legend>: it sits IN the flow (not
   absolute), pulled up by a negative margin so its first line straddles the
   top border. A title that wraps grows downward and pushes the quote down,
   instead of covering the text above and inside the box.
   Margins derive from the first line's half-height (--callout-title-half):
   with a one-line title the layout is identical to the old absolute one. */
.callout {
    /* Match the TL;DR box-title size (h3 ≈ 1.17em of body): callout titles
       ("Example", "NOTE", …) must be as large as TL;DR, not smaller. */
    --callout-title-size: 1.17em;
    --callout-title-lh: 1.3;
}
.callout .box-title {
    --callout-title-half: calc(var(--callout-title-size) * var(--callout-title-lh) / 2);
    position: static;
    transform: none;
    width: fit-content;
    max-width: 100%;
    margin: calc(-1.4em - var(--callout-title-half)) 0 calc(1.4em - var(--callout-title-half)) -0.8em;
    font-style: normal;
    text-align: left;
    justify-content: flex-start;
    /* Icon aligned with the first line, not centered on the whole block. */
    align-items: flex-start;
}
.callout .box-title img {
    margin-top: calc(var(--callout-title-half) - 16px);
}
.callout h4 {
    display: inline-block;
    font-size: var(--callout-title-size);
    line-height: var(--callout-title-lh);
}
.callout .source,
.callout_empty .source {
    text-align: right;
    margin-top: 5px;
}

.callout_empty {
    font-style: italic;
    border: 3px outset var(--text-color);
    margin-left: 3ch;
    margin-top: 1.5em;
    margin-bottom: 1.5em;
    padding: 1.4em 1.5em 1.2em;
}
.callout_empty p {
    padding-left: 0;
}
/* --- */


/* Use "body X" prefix (specificity 0,0,2) to reliably beat the element rules
   in base.css (specificity 0,0,1), regardless of load order. */

body p {
    padding-left: 3ch;
    padding-bottom: 3px;
    margin: 5px;
}

body b {
    color: var(--bold_color);
}

.tldr {
    border-style: double;
    border-width: 5px;
    position: relative;
    /* Generous inner padding: text must not touch the border (top keeps
       clearance for the floating .box-title). */
    padding: 1.4em 1.5em 1.2em;
    margin-top: 1.5em;
    margin-bottom: 1em;
}
.tldr p {
    padding-left: 0;
}

html body {
    margin-left: 30%;
    margin-right: 5%;
}
/* Posts have no fixed sidebar TOC: reclaim the 30% left gutter. Keyed on
   :not(:has(.toc)) so it still applies when the expandable TOC is commented
   out of the template. Scoped to above the mobile breakpoint — under 950px
   the mobile block flattens margins. */
@media only screen and (min-width: 951px) {
    html body:not(:has(.toc)) {
        margin-left: 9.6%;
        margin-right: 9.6%;
    }
    /* The 3ch/5ch body indents balance the fixed TOC on old posts; without
       the gutter they are just random offsets — flatten them. */
    html body:not(:has(.toc)) p {
        padding-left: 0;
        margin-left: 0;
    }
    html body:not(:has(.toc)) ul {
        padding-left: 1.6ch;
    }
    html body:not(:has(.toc)) h4 {
        margin-left: 0;
    }
}

body h2, body h3 {
    text-align: left;
}
/* Section headers need clear air above them (UA h2 top margin is tiny). */
body h2 {
    margin-top: 2.4em;
}
/* Subheaders (└─ …) keep their tree symbol but need more breathing room
   from the paragraph above: 1.8em × 1.2. */
body h3 {
    margin-top: 2.16em;
}
.subtitle {
    text-align: center;
    margin-bottom: 1ch;
}

body h2 a, body h3 a, body h4 a {
    padding-right: 20px;
    background: transparent url(../img/icon/link.webp) no-repeat right;
    background-size: 15px 15px;
    color: var(--text-color);
}
body h2 a:hover, body h3 a:hover, body h4 a:hover {
    color: var(--link-color);
}

body h4 {
    text-align: left;
    margin-left: 3ch;
}


/* Section rule: equal air on both sides. The following h2 must not add its
   usual large top margin — that would push the rule up toward the text above. */
body hr {
    border-width: 1px 1px 0;
    border-style: double;
    width: 30%;
    margin-top: 2em;
    margin-bottom: 2em;
    margin-left: auto;
    margin-right: auto;
}
body hr + h2 {
    margin-top: 0;
}

body ul {
    padding-left: 5ch;
    text-align: left;
    list-style-type: disc;
    /* No extra air before the list (the preceding <p> margin is enough);
       0.7em only after it. UA default was margin: 1em 0. */
    margin-top: 0;
    margin-bottom: 0.7em;
}


/* Gallery / image caption container */
.center-padding {
    padding: 13px;
}

/* ── Post header: epistemic line under the date ── */
/* Secondary epistemic line under the date: abbreviated label ("ES"), slightly
   smaller but full opacity — readable, not a ghost. */
.epistemic {
    font-size: 0.85em;
    margin-top: 0.3em;
    color: var(--text-color);
}
/* ES label: link colour, plain italic — never the site-wide <i> yellow.
   The description after "ES:" also uses <i>; pin it to text colour so the
   whole line stays free of #FBFFAD. */
.epistemic em {
    color: var(--link-color);
    font-style: italic;
}
.epistemic i {
    color: var(--text-color);
    font-style: italic;
}

/* ── Expandable TOC (disabled while the <details> is commented) ── */
/* In-flow <details>, collapsed by default, after the TL;DR box. */
.toc-details {
    position: relative;
    border: 1px solid var(--text-color);
    margin-top: 2em;
    /* Room for the floating summary on the top edge when collapsed. */
    min-height: 2.8em;
}
.toc-details > summary {
    cursor: pointer;
    position: absolute;
    top: 0;
    left: 50%;
    transform: translate(-50%, -50%);
    padding: 0 0.3em;
    background-color: var(--background-color);
    white-space: nowrap;
    list-style: none;
}
.toc-details > summary::-webkit-details-marker {
    display: none;
}
.toc-details > summary::after {
    content: " ▾";
}
.toc-details[open] {
    padding: 1.4em 10px 10px;
}
.toc-details[open] > summary::after {
    content: " ▴";
}
/* No fixed-height scroll area: the expandable TOC flows with its content. */
.toc-details .toc-scroll {
    max-height: none;
    overflow: visible;
    line-height: 1.4;
    word-break: break-all;
}

/* Mobile styles */
@media only screen and (max-width: 950px) {
    html body {
        margin-left: 1%;
        margin-right: 1%;
    }
    /* On desktop the 3ch/5ch left indents visually balance the fixed TOC in
       the left gutter. On mobile there is no gutter, so they are just wasted
       space on the left edge: flatten them. */
    body p {
        padding-left: 0;
        margin-left: 0;
    }
    /* base.css turns .justify back to left-align on mobile (site-wide default).
       In blog posts we want the body text justified on the phone too, edge to
       edge. hyphens: auto is needed here: without it, justifying a monospace
       font on a narrow line opens big gaps between words. body-prefixed to
       beat base.css's `.justify` in the same 950px breakpoint. */
    body p.justify {
        text-align: justify;
        -webkit-hyphens: auto;
        hyphens: auto;
    }
    body ul {
        padding-left: 1.6ch;
    }
    body h4 {
        margin-left: 0;
    }
    .callout,
    .callout_empty {
        margin-left: 0;
    }
    .toc {
        position: relative;
        margin: 1.5em auto 0;
        width: 98%;
        border: 1px solid var(--text-color);
        padding: 10px;
        padding-top: 1.4em;
    }
    .toc-scroll {
        line-height: 1.4;
        word-break: break-all;
    }
    .toc-details {
        width: 98%;
        margin-left: auto;
        margin-right: auto;
    }
    /* On a phone, content images fill the screen width instead of showing at
       their (often much smaller) native size. `max-height` keeps a tall image
       from taking over the whole viewport; `object-fit: contain` scales it
       down within that box without cropping. Tweet screenshots keep their own
       rule (capped at native px to stay sharp) and inline icons are untouched. */
    figure img,
    .center-padding img {
        width: 100%;
        max-height: 80vh;
        object-fit: contain;
    }
}

/* ── Quoted tweets ──────────────────────────────────────────────────── */
/* Screenshots hosted here rather than embedded from platform.twitter.com:
   an embed is a third-party script that can set cookies, and it leaves a
   blank gap when the script is blocked. The image links to the original,
   and its alt text carries the full wording of the tweet. */
.tweet-shot {
    display: block;
    width: fit-content;
    max-width: min(700px, 100%);
    margin: 1.5em auto;
}

/* `width: auto` + `max-width: 100%` lets each screenshot grow up to its own
   native size and no further: scaling one past its real pixels only makes it
   blurry. The tall screenshot is 416px wide natively and stays there; the wide
   one fills the 700px the container allows. */
.tweet-shot img {
    width: auto;
    max-width: 100%;
    height: auto;
    border-radius: 12px;
    border: 1px solid var(--text-color);
}

.tweet-shot:hover img {
    border-color: var(--link-color);
}

/* Tweet screenshot with its caption directly underneath: the default
   .tweet-shot bottom margin leaves the caption floating too far from the
   image, while the caption itself sits almost glued to the next paragraph.
   Pull the caption nearer the image, push the paragraph further down. */
a.tweet-shot:has(+ .center-padding) {
    margin-bottom: 18px;
}

.tweet-shot + .center-padding {
    padding-top: 10px;
    padding-bottom: 26px;
}

/* Phone: smaller callout titles, so long attributions wrap onto fewer lines. */
@media only screen and (max-width: 768px) {
    .callout {
        --callout-title-size: 1em;
    }
}
