/* ==========================================================================
   joejordan-young-again — after Shinedown's "Young Again" (2026).

   The song is a look back at a suburban summer: cul-de-sac kingdoms,
   blacktop, bottle rockets, mixtapes, the streetlights coming on, and the
   light changing at the end of the season before anyone noticed.

   Look:   golden hour (light) / streetlights on (dark). A striped sunset
           behind a cul-de-sac skyline, feature images as date-stamped
           drugstore prints, hand-lettered stickers and labels, a lit fuse
           for reading progress, and every page ending at nightfall with
           the streetlight flickering on.
   Type:   Big Shoulders Display (punchy condensed poster headlines)
           Bowlby One (the home greeting only)
           Literata (body: built for long-form screen reading)
           Permanent Marker (hand-lettered labels and stickers)
           IBM Plex Mono (meta, code)
           Self-hosted (OFL); the @font-face rules are in fonts.css.
   Modern: tokens swapped by [data-theme] (set pre-paint in default.hbs,
           toggled by main.js), fluid type,
           view transitions, scroll-driven fuse and sunset, reduced-motion
           stops every animation.
   ========================================================================== */

/* ---------- Tokens ---------- */

:root {
    /* Settings → Design fills --site-font-*; ours are the default. */
    --font-display: var(--site-font-heading, "Big Shoulders Display"), "Oswald", "Arial Narrow", Impact, sans-serif;
    /* The home greeting only: wide, rounded 70s-signage caps where everything
       else is condensed. */
    --font-greeting: "Bowlby One", "Arial Black", "Helvetica Neue", Arial, sans-serif;
    --font-body: var(--site-font-body, "Literata"), Georgia, "Times New Roman", serif;
    --font-marker: "Permanent Marker", "Marker Felt", "Comic Sans MS", cursive;
    --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

    --measure: 40rem;
    --wide: 54rem;
    --gutter: clamp(1rem, 4vw, 2rem);

    /* Colours that don't change with the scheme: night sky, the footer's
       blacktop, code blocks, the snapshot paper, and the dark ink and lamp
       glow used on the stickers and the always-dark footer. */
    --night: #0b0a1a;
    --blacktop: #07060f;
    --code-bg: #17152a;
    --code-ink: #efe6d6;
    --paper: #f6f0e3;
    --paper-ink: #2a2340;
    --cream: #fff3df;
    --stamp: #ff8a1f;
    --ink-fixed: #211c2c;
    --lamp-glow: #ffcf6b;
    --cream-soft: #b8ad9e;
}

/* Golden-hour sky. s1 is the sun, s5 the top of the sky. */
:root {
    --s1: #ffd27a; --s2: #ff9a4d; --s3: #ef5f6b; --s4: #8a4a9e; --s5: #2e2a5a;
}

/* The ribbon: the gradient on the header rule, the post list's spine, the
   reading fuse, title sweeps, quotes and rules. By day it's the sunset
   (g1-g4 = s1-s4); after dark it dims to sodium amber, dusky rose, deep
   violet, midnight teal (see [data-theme="dark"]). The stops are registered so the
   toggle can fade them; a gradient itself can't transition. */
@property --g1 { syntax: "<color>"; inherits: true; initial-value: #ffd27a; }
@property --g2 { syntax: "<color>"; inherits: true; initial-value: #ff9a4d; }
@property --g3 { syntax: "<color>"; inherits: true; initial-value: #ef5f6b; }
@property --g4 { syntax: "<color>"; inherits: true; initial-value: #8a4a9e; }
/* The page colours are registered too, so the toggle fades them once, at
   the root, and every element follows on the same clock. Fading each
   element's own colour instead chained: a child finished its fade, then
   picked up its parent's colour mid-fade and faded again. */
@property --bg { syntax: "<color>"; inherits: true; initial-value: #fbf1df; }
@property --panel { syntax: "<color>"; inherits: true; initial-value: #fffaf0; }
@property --ink { syntax: "<color>"; inherits: true; initial-value: #211c2c; }
@property --ink-soft { syntax: "<color>"; inherits: true; initial-value: #5d5263; }
@property --rule { syntax: "<color>"; inherits: true; initial-value: #e5d4b8; }
@property --link { syntax: "<color>"; inherits: true; initial-value: #b23a1b; }
@property --accent { syntax: "<color>"; inherits: true; initial-value: #c2410c; }
@property --title-shadow { syntax: "<color>"; inherits: true; initial-value: #ff9a4d; }
@property --plank-glint { syntax: "<color>"; inherits: true; initial-value: rgb(255 255 255 / 0.38); }
@property --plank-lip { syntax: "<color>"; inherits: true; initial-value: rgb(60 18 50 / 0.34); }
@property --title-drop { syntax: "<color>"; inherits: true; initial-value: rgb(60 18 50 / 0.28); }
@property --horizon { syntax: "<color>"; inherits: true; initial-value: #2a2148; }
@property --lamp { syntax: "<color>"; inherits: true; initial-value: #ffcf6b; }
:root {
    --sunset: linear-gradient(90deg, var(--g1), var(--g2), var(--g3), var(--g4));
    --sunset-v: linear-gradient(180deg, var(--g1), var(--g2), var(--g3), var(--g4));

    /* Day and night skies are both always defined: gradients can't animate,
       so the night sky is laid over the day sky and faded in (.sky::before,
       .nightfall::before). The page colours are literal here because the
       two layers have to show both at once. */
    --sky-day:
        linear-gradient(180deg, var(--s5) 0%, var(--s4) 38%, var(--s3) 70%, var(--s2) 88%, var(--s1) 100%);
    --sky-night:
        linear-gradient(180deg, var(--night) 0%, #141233 45%, #2a1d4a 80%, #4a2a55 100%);
    --dusk-day:
        linear-gradient(180deg, #fbf1df 18%, var(--s1) 32%, var(--s2) 46%, var(--s3) 60%, var(--s4) 74%, var(--s5) 88%, var(--night) 100%);
    --dusk-night:
        linear-gradient(180deg, #12111f 18%, #2a1d4a 38%, #3a2352 56%, #2a1d4a 74%, #171433 88%, var(--night) 100%);

    /* Day ↔ night: colours fade over --fade. The sun takes --fade-sun to
       set or rise, and the sky's light follows it on the same clock. The
       moon (at dusk) and the sun (at dawn) wait --sun-delay so they cross. */
    --fade: 1.4s;
    --fade-sun: 2s;
    --sun-delay: 0.6s;
    /* At dusk the windows and streetlight come on as the sun reaches the
       rooftops, about 60% of the way through its set. */
    --dusk-lights: calc(var(--fade-sun) * 0.6);
}

/* Golden hour. */
:root,
:root[data-theme="light"] {
    color-scheme: light;
    --bg: #fbf1df;
    --g1: var(--s1); --g2: var(--s2); --g3: var(--s3); --g4: var(--s4);
    --panel: #fffaf0;
    --ink: #211c2c;
    --ink-soft: #5d5263;
    --rule: #e5d4b8;
    --link: #b23a1b;
    --accent: #c2410c;
    --title-shadow: var(--s2);
    --plank-glint: rgb(255 255 255 / 0.38);
    --plank-lip: rgb(60 18 50 / 0.34);
    --title-drop: rgb(60 18 50 / 0.28);
    --tint: color-mix(in srgb, var(--s1) 38%, transparent);
    --horizon: #2a2148;
    --lamp: #ffcf6b;
    /* Cheap paperback stock: a faint uneven tone, short fibres running with
       the grain, and the odd fleck of recycled pulp. Day only. */
    --pulp: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='520' height='520'%3E %3Cfilter id='m' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.009' numOctaves='3' seed='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .62 0 0 0 0 .46 0 0 0 0 .24 0 0 0 .2 -.07'/%3E%3C/filter%3E %3Cfilter id='f' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.09 .6' numOctaves='2' seed='8' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .45 0 0 0 0 .36 0 0 0 0 .24 0 0 0 2.4 -1.78'/%3E%3C/filter%3E %3Cfilter id='s' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.7' numOctaves='1' seed='21' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .25 0 0 0 0 .19 0 0 0 0 .14 0 0 0 9 -6.75'/%3E%3C/filter%3E %3Crect width='100%25' height='100%25' filter='url%28%23m%29'/%3E%3Crect width='100%25' height='100%25' filter='url%28%23f%29'/%3E%3Crect width='100%25' height='100%25' filter='url%28%23s%29'/%3E%3C/svg%3E");
}

/* Streetlights on. */
:root[data-theme="dark"] {
    color-scheme: dark;
    --bg: #12111f;
    --panel: #1b1a2d;
    --ink: #f3e9d8;
    --ink-soft: #b8ad9e;
    --rule: #2f2b47;
    --link: #ffad5a;
    --accent: #ffad5a;
    --title-shadow: var(--s4);
    --plank-glint: rgb(255 255 255 / 0.28);
    --plank-lip: rgb(0 0 0 / 0.45);
    --title-drop: rgb(0 0 0 / 0.5);
    --tint: color-mix(in srgb, var(--accent) 22%, transparent);
    --horizon: var(--blacktop);
    --lamp: #ffb347;
    --pulp: none;
    --g1: #e19639; --g2: #d34b77; --g3: #8252ce; --g4: #42a0b6;
}

/* ---------- Base ---------- */

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

html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
    scroll-padding-top: 5rem;
}
/* Takes over the canvas colour from default.hbs's inline style (same
   weight, later), so it fades with the palette on a toggle. */
html[data-theme] { background-color: var(--bg); }

body {
    /* default.hbs hides the body until this file has loaded. */
    opacity: 1;
    animation: none;
    margin: 0;
    color: var(--ink);
    background: var(--bg);
    font-family: var(--font-body);
    font-size: clamp(1.0625rem, 0.98rem + 0.35vw, 1.1875rem); /* 17px → 19px */
    line-height: 1.7;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

img, svg, video { max-width: 100%; height: auto; }
img { display: block; }

a {
    color: var(--link);
    text-decoration-thickness: 0.08em;
    text-underline-offset: 0.2em;
}
a:hover { color: var(--ink); background: var(--tint); }

:focus-visible {
    outline: 3px solid var(--s3);
    outline-offset: 3px;
    border-radius: 2px;
}

::selection { background: var(--s1); color: var(--ink-fixed); }

h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-display);
    font-weight: 800;
    line-height: 1;
    letter-spacing: 0.005em;
    text-wrap: balance;
    margin: 0;
}

p, li { text-wrap: pretty; }

.skip-link {
    position: absolute;
    left: 1rem;
    top: -4rem;
    z-index: 300;
    padding: 0.5rem 1rem;
    background: var(--ink);
    color: var(--bg);
}
.skip-link:focus { top: 1rem; }

/* For screen readers only (e.g. the search result count). */
.visually-hidden {
    position: absolute !important;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* Film grain: an SVG-noise tile layered into the surfaces (page, skies,
   footer) rather than laid over the whole page, so photos and text keep
   their true colour. Dark noise by day, faint light noise by night. */
:root { --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .12 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }
:root[data-theme="dark"] { --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .1 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }
body { background-image: var(--grain), var(--pulp); background-size: 180px 180px, 520px 520px; }

/* ---------- Building blocks ---------- */

.kicker {
    margin: 0;
    color: var(--accent);
    font-family: var(--font-marker);
    font-size: clamp(1.1rem, 0.9rem + 0.8vw, 1.45rem);
    line-height: 1.2;
    text-wrap: balance;
    transform: rotate(-2deg);
}

.meta {
    margin: 0;
    color: var(--ink-soft);
    font-family: var(--font-mono);
    font-size: 0.75rem;
    letter-spacing: 0.06em;
    line-height: 1.5;
    text-transform: uppercase;
}
.meta a { color: inherit; }
.meta-sep { margin: 0 0.6em; opacity: 0.6; }
/* Each item stays on one line; lines break only at a separator (<wbr>). */
.meta > time, .meta > span:not(.meta-sep) { white-space: nowrap; }

/* Punchy poster button: ink slab, hard sunset shadow, presses in. */
.btn {
    display: inline-flex;
    align-items: center;
    gap: 0.5em;
    padding: 0.6em 1.15em 0.55em;
    border: 2px solid var(--ink);
    border-radius: 6px;
    background: var(--ink);
    color: var(--bg);
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 800;
    letter-spacing: 0.06em;
    line-height: 1;
    text-decoration: none;
    text-transform: uppercase;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.btn:hover { color: var(--bg); background: var(--link); border-color: var(--link); }
.btn-ghost { background: transparent; color: var(--ink); }
.btn-ghost:hover { color: var(--bg); }

.icon-btn {
    display: inline-grid;
    place-items: center;
    width: 2.5rem;
    height: 2.5rem;
    padding: 0;
    border: 2px solid var(--ink);
    border-radius: 999px;
    background: transparent;
    color: var(--ink);
    cursor: pointer;
    transition: background 0.15s ease, transform 0.15s ease;
}
.icon-btn:hover { background: var(--tint); transform: rotate(-8deg); }
.icon-btn svg { width: 1.15rem; height: 1.15rem; }

.theme-toggle .when-dark { display: none; }
[data-theme="dark"] .theme-toggle .when-light { display: none; }
[data-theme="dark"] .theme-toggle .when-dark { display: contents; }
[data-theme="dark"] .theme-toggle { color: var(--lamp); border-color: var(--lamp); box-shadow: 0 0 14px -2px var(--lamp); }

/* Hand-lettered tag, slapped on at an angle. */
.sticker,
.new-sticker {
    display: inline-block;
    border-radius: 3px;
    background: var(--s1);
    color: var(--ink-fixed);
    font-family: var(--font-marker);
    box-shadow: 2px 2px 0 var(--ink-fixed);
}
.sticker {
    padding: 0.2em 0.7em 0.1em;
    font-size: 0.95rem;
    line-height: 1.5;
    text-decoration: none;
    transform: rotate(-3deg);
    transition: transform 0.15s ease;
}
.sticker:nth-child(even) { transform: rotate(2deg); background: var(--s2); }
.sticker:nth-child(3n) { background: color-mix(in srgb, var(--s3) 70%, #fff); }
a.sticker:hover { color: var(--ink-fixed); background: var(--s1); transform: rotate(0) scale(1.06); }

.new-sticker {
    margin-left: 0.45em;
    padding: 0.15em 0.45em 0.05em;
    font-size: 0.8rem;
    font-weight: 400;
    letter-spacing: 0.02em;
    line-height: 1.4;
    vertical-align: 0.35em;
    transform: rotate(-6deg);
}

.empty { color: var(--ink-soft); font-style: italic; text-align: center; }

/* Card: an ink-outlined panel with a hard shadow in the ribbon colour.
   The shadow shrinks on a phone, where 8px is a lot of a narrow card. */
:root { --card-shadow: clamp(5px, 1.4vw, 8px) clamp(5px, 1.4vw, 8px) 0 var(--g2); }
.post-list,
.subscribe {
    border: 2px solid var(--ink);
    border-radius: 8px;
    background: var(--panel);
    box-shadow: var(--card-shadow);
}

/* ---------- Stars (dark hero, nightfall, 404) ---------- */

.stars {
    position: absolute;
    inset: 0 0 35% 0;
    pointer-events: none;
    opacity: 0;
    transition: opacity var(--fade-sun) ease-in-out; /* rides with the sky */
    background-image:
        radial-gradient(1px 1px at 23px 31px, #fff 50%, transparent 52%),
        radial-gradient(1px 1px at 131px 87px, #fde 50%, transparent 52%),
        radial-gradient(1.5px 1.5px at 187px 163px, #fff 50%, transparent 52%),
        radial-gradient(1px 1px at 71px 197px, #ffd 50%, transparent 52%),
        radial-gradient(1px 1px at 211px 17px, #dde 50%, transparent 52%),
        radial-gradient(1.5px 1.5px at 41px 113px, #fff 50%, transparent 52%);
    background-size: 227px 227px;
}
.stars::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image:
        radial-gradient(2px 2px at 53px 71px, #fff 50%, transparent 55%),
        radial-gradient(1.5px 1.5px at 277px 191px, #ffe9a8 50%, transparent 55%),
        radial-gradient(1.5px 1.5px at 331px 43px, #fff 50%, transparent 55%);
    background-size: 353px 353px;
    animation: twinkle 3.5s ease-in-out infinite alternate;
}
@keyframes twinkle { from { opacity: 0.2; } to { opacity: 1; } }
[data-theme="dark"] .stars,
.nightfall .stars,
.error-page .stars { opacity: 1; }

/* ---------- The cul-de-sac skyline ---------- */

.horizon {
    position: absolute;
    inset: auto 0 0 0;
    /* Keep the viewBox's proportions on wide screens: a capped height made
       the slice crop the top off, lamp head first. Narrow screens hit the
       floor and crop the sides instead. The explicit width keeps that floor
       from widening the strip to match (72px tall at this ratio is 617px
       wide, which pushed phone pages sideways). */
    width: 100%;
    aspect-ratio: 1200 / 140;
    min-height: 72px;
    pointer-events: none;
}
.horizon svg { display: block; width: 100%; height: 100%; }
.horizon .land { fill: var(--horizon); }
.horizon .lights { fill: var(--lamp); }
/* Set here, not on the <stop>s: SVG presentation attributes can't read var(). */
.horizon stop { stop-color: var(--lamp); }
.horizon .lights,
.horizon .beam,
.horizon .beam-pool { opacity: 0; transition: opacity 0.4s ease; }
.horizon .bulb { filter: drop-shadow(0 0 6px var(--lamp)) drop-shadow(0 0 14px var(--lamp)); }

/* Lit: always in the footer and on the 404, and in the hero after dark.
   The flicker is the sodium-vapour lamp catching. */
.horizon.is-lit .lights,
.horizon.is-lit .beam,
.horizon.is-lit .beam-pool,
[data-theme="dark"] .horizon .lights,
[data-theme="dark"] .horizon .beam,
[data-theme="dark"] .horizon .beam-pool { opacity: 1; }
.horizon.is-lit .beam,
.horizon.is-lit .beam-pool,
.horizon.is-lit .bulb { animation: lamp-catch 1.6s steps(1, end) both; }
/* At dusk the hero's lights fade up as the sun reaches the rooftops. */
[data-theme="dark"] .hero .horizon :is(.lights, .beam, .beam-pool) { transition-duration: var(--fade); transition-delay: var(--dusk-lights); }

/* The beam: a soft outer cone that breathes like a sodium lamp's hum, a
   brighter core that sways a hair, light shafts that shimmer out of step,
   a haze of night air, dust drifting up through the light, and a pool of
   light on the road. Each layer keeps its own rhythm so the whole never
   repeats in an obvious loop. Reduced motion stops all of it (below). */
.horizon .beam-outer,
.horizon .beam-core,
.horizon .beam-ray { transform-box: view-box; transform-origin: 613px 37px; }
.horizon .beam-outer { animation: beam-breathe 5.3s ease-in-out infinite; }
.horizon .beam-core { opacity: 0.75; animation: beam-sway 3.7s ease-in-out infinite; }
.horizon .beam-ray { fill: var(--lamp); opacity: 0.16; animation: beam-shimmer 2.9s ease-in-out infinite; }
.horizon .beam-ray.r2 { animation-duration: 3.7s; animation-delay: -1.2s; }
.horizon .beam-ray.r3 { animation-duration: 4.4s; animation-delay: -2.6s; }
.horizon .beam-ray.r4 { animation-duration: 5.1s; animation-delay: -0.7s; }
.horizon .beam-haze { fill: var(--lamp); opacity: 0.22; animation: beam-haze 8s ease-in-out infinite alternate; }
.horizon .beam-pool { mix-blend-mode: screen; }
.horizon .mote {
    fill: var(--lamp);
    opacity: 0;
    filter: drop-shadow(0 0 1.5px var(--lamp));
    animation: mote-drift var(--d, 10s) linear var(--delay, 0s) infinite;
}
@keyframes beam-breathe {
    0%, 100% { opacity: 0.86; }
    17% { opacity: 1; }
    34% { opacity: 0.78; }
    49% { opacity: 0.95; }
    68% { opacity: 0.82; }
    84% { opacity: 1; }
}
@keyframes beam-sway {
    0%, 100% { transform: scaleX(1); opacity: 0.75; }
    30% { transform: scaleX(1.04) skewX(0.6deg); opacity: 0.9; }
    55% { transform: scaleX(0.97) skewX(-0.4deg); opacity: 0.68; }
    80% { transform: scaleX(1.02); opacity: 0.85; }
}
@keyframes beam-shimmer {
    0%, 100% { opacity: 0.08; transform: skewX(0deg); }
    40% { opacity: 0.26; transform: skewX(1.2deg); }
    65% { opacity: 0.12; transform: skewX(-0.8deg); }
}
@keyframes beam-haze {
    from { opacity: 0.14; }
    to { opacity: 0.3; }
}
@keyframes mote-drift {
    0% { opacity: 0; transform: translate(0, 0); }
    15% { opacity: 0.9; }
    50% { opacity: 0.45; }
    80% { opacity: 0.8; }
    100% { opacity: 0; transform: translate(var(--dx, 0), var(--dy, -40px)); }
}
/* The beam and the twinkling stars only animate while they can be seen:
   the beam when lit (dark mode, or a lit skyline in view), the twinkle in a
   night sky. Off, they would repaint every frame for nothing. */
.horizon .beam *,
.stars::before { animation-play-state: paused; }
.horizon.is-lit .beam *,
[data-theme="dark"] .horizon .beam *,
[data-theme="dark"] .stars::before,
.nightfall .stars::before,
.error-page .stars::before { animation-play-state: running; }

@keyframes lamp-catch {
    0% { opacity: 0; }
    12% { opacity: 1; }
    18% { opacity: 0.15; }
    30% { opacity: 0.9; }
    36% { opacity: 0.3; }
    55% { opacity: 1; }
}

/* ---------- Reading progress: a lit wire ----------
   A thin line in the accent colour (deliberately not the ribbon, which sits
   just below it under the header) draws across the top while you read, with
   a sun at its head by day and, after dark, a lamp that glows and breathes
   like the skyline's streetlight.
   Pure CSS where scroll-driven animations exist; main.js drives the same two
   transforms elsewhere. The lamp travels in cqw of the bar, so it lands on
   the end of the line rather than under the scrollbar. */

.progress {
    position: fixed;
    inset: 0 0 auto 0;
    z-index: 150;
    height: 2px;
    display: none;
    pointer-events: none;
    container-type: inline-size;
}
.post-template .progress { display: block; }
.progress-fuse {
    position: absolute;
    inset: 0;
    background: var(--accent);
    box-shadow: 0 0 6px color-mix(in srgb, var(--lamp) 60%, transparent);
    /* Slides in from the left rather than growing, so its end can sit at
       the sun's centre all the way: the sun runs from 14px off-screen
       (centre at -8.5px) to the right edge (centre at 100% - 5.5px). */
    transform: translateX(calc(-100% - 8.5px));
}
.progress-spark {
    position: absolute;
    top: -3px;
    left: 0;
    width: 11px;
    height: 11px;
    border-radius: 50%;
    transform: translateX(-14px);
}
/* By day the wire carries a little sunset sun, softly ink-ringed
   so it holds its own on the cream header. */
.progress-spark {
    background: linear-gradient(180deg, var(--s1) 15%, var(--s2) 55%, var(--s3) 100%);
    box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--ink) 55%, var(--bg));
}
/* After dark it's a streetlight: a pale bulb whose glow breathes. The glow
   is its own layer, so breathing it never moves the lamp. */
[data-theme="dark"] .progress-spark { background: #fff4d6; box-shadow: none; }
[data-theme="dark"] .progress-spark::after {
    content: "";
    position: absolute;
    inset: -7px;
    border-radius: 50%;
    background: radial-gradient(circle, color-mix(in srgb, var(--lamp) 85%, transparent) 0 30%, transparent 70%);
    animation: lamp-breathe 4.2s ease-in-out infinite;
}
@keyframes lamp-breathe {
    0%, 100% { opacity: 0.7; }
    50% { opacity: 1; }
}

@supports (animation-timeline: scroll()) {
    .post-template .progress-fuse {
        animation: fuse-burn linear both;
        animation-timeline: scroll(root);
    }
    .post-template .progress-spark {
        animation: spark-run linear both;
        animation-timeline: scroll(root);
    }
    @keyframes fuse-burn { to { transform: translateX(-5.5px); } }
    @keyframes spark-run { to { transform: translateX(calc(100cqw - 11px)); } }
}

/* ---------- Layout ---------- */

.site {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
}
.site-main { flex: 1; padding-bottom: clamp(3rem, 8vw, 5rem); }
/* A post ends on Older/Newer, whose links carry their own 1.1rem below:
   less here keeps the nightfall close without crowding them (~4rem in all). */
.post-template .site-main { padding-bottom: clamp(2rem, 6vw, 3rem); }

.post-list,
.pagination,
.archive-header {
    width: min(var(--measure) + 6rem, 100% - 2 * var(--gutter));
    margin-inline: auto;
}
.article-footer,
.post-nav,
.subscribe {
    width: min(var(--measure), 100% - 2 * var(--gutter));
    margin-inline: auto;
}

/* ---------- Masthead ---------- */

.masthead {
    position: sticky;
    top: 0;
    z-index: 50;
    background: color-mix(in srgb, var(--bg) 86%, transparent);
    -webkit-backdrop-filter: blur(12px) saturate(1.2);
    backdrop-filter: blur(12px) saturate(1.2);
}
.masthead::after {
    content: "";
    position: absolute;
    inset: auto 0 0 0;
    height: 3px;
    background: var(--sunset);
}

.masthead-inner {
    display: flex;
    align-items: center;
    gap: 0.75rem 1.5rem;
    width: min(var(--wide) + 8rem, 100% - 2 * var(--gutter));
    margin-inline: auto;
    padding-block: 0.7rem 0.85rem;
}

.brand {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    margin-right: auto;
    color: var(--ink);
    text-decoration: none;
}
.brand:hover { color: var(--ink); background: none; }
/* A tiny striped sunset sun, the same one from the hero. Hover and it does
   a happy dance: hop, squash on landing, sway, hop again. After dark it
   slow-dances instead: a lazy lean from side to side, rocking on its feet. */
.brand-sun {
    width: 1.75rem;
    height: 1.75rem;
    flex: none;
    border-radius: 50%;
    background: linear-gradient(180deg, var(--s1) 10%, var(--s2) 55%, var(--s3) 100%);
    -webkit-mask-image: linear-gradient(180deg, #000 52%, transparent 52% 60%, #000 60% 70%, transparent 70% 77%, #000 77% 86%, transparent 86% 91%, #000 91%);
    mask-image: linear-gradient(180deg, #000 52%, transparent 52% 60%, #000 60% 70%, transparent 70% 77%, #000 77% 86%, transparent 86% 91%, #000 91%);
    transform-origin: 50% 100%;
}
[data-theme="dark"] .brand-sun { background: linear-gradient(180deg, #ffe7a8, var(--lamp)); }
@media (hover: hover) {
    .brand:hover .brand-sun { animation: sun-dance 0.9s ease-in-out infinite; }
    [data-theme="dark"] .brand:hover .brand-sun { animation: sun-sway 3.2s infinite; }
}
/* Eases out of rest into the first lean, swings through the middle, and
   eases back to rest, so every loop starts and ends upright. */
@keyframes sun-sway {
    0%   { transform: translate(0, 0) rotate(0); animation-timing-function: cubic-bezier(.3, 0, .4, 1); }
    25%  { transform: translate(-3px, 0) rotate(-14deg); animation-timing-function: cubic-bezier(.45, 0, .55, 1); }
    75%  { transform: translate(3px, 0) rotate(14deg); animation-timing-function: cubic-bezier(.6, 0, .7, 1); }
    100% { transform: translate(0, 0) rotate(0); }
}
@keyframes sun-dance {
    0%, 100% { transform: translate(0, 0) rotate(0) scale(1, 1); }
    10%      { transform: translate(0, 0) rotate(0) scale(1.12, 0.86); }
    25%      { transform: translate(-2px, -6px) rotate(-10deg) scale(0.94, 1.08); }
    40%      { transform: translate(0, 0) rotate(0) scale(1.1, 0.9); }
    50%      { transform: translate(0, 0) rotate(0) scale(1.12, 0.86); }
    65%      { transform: translate(2px, -6px) rotate(10deg) scale(0.94, 1.08); }
    80%      { transform: translate(0, 0) rotate(0) scale(1.1, 0.9); }
}
.brand-name {
    font-family: var(--font-display);
    font-size: 1.55rem;
    font-weight: 900;
    letter-spacing: 0.04em;
    line-height: 1;
    text-transform: uppercase;
}

.site-nav ul {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1.25rem;
    margin: 0;
    padding: 0;
    list-style: none;
}
/* The navigation menus (Settings → Navigation). */
.site-nav a {
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-decoration: none;
    text-transform: uppercase;
    background: linear-gradient(var(--s2), var(--s2)) no-repeat 0 100% / 0 3px;
    transition: background-size 0.25s ease;
}
.site-nav a:hover,
.site-nav .nav-current a { background-size: 100% 3px; color: var(--ink); }

.masthead-actions { display: flex; gap: 0.5rem; }
/* The buttons are 40px to look at; this makes them 44px to tap (the
   inset counts from inside the 2px border). */
.masthead .icon-btn { position: relative; }
.masthead .icon-btn::before { content: ""; position: absolute; inset: -4px; border-radius: 50%; }

/* A phone keeps the masthead (no hiding on scroll) but tightens it, so
   it takes less of a short screen. */
@media (max-width: 640px) {
    .masthead-inner { flex-wrap: wrap; row-gap: 0.35rem; padding-block: 0.45rem 0.55rem; }
    .brand-name { font-size: 1.35rem; }
    /* 24px rows: the smallest comfortable tap height for a text link. */
    .site-nav ul { line-height: 1.5; }
    .site-nav a { font-size: 1rem; }
    .site-nav { order: 3; width: 100%; overflow-x: auto; }
    .site-nav ul { flex-wrap: nowrap; }
    .site-nav li { flex: none; }
}

/* ---------- Home hero: golden hour over the cul-de-sac ---------- */

.hero,
.error-page {
    position: relative;
    overflow: hidden;
    isolation: isolate;
    /* Never anchor scrolling on the sky. The sun moves on a day/night
       switch, and a browser that anchors on it scrolls the page to follow,
       so the posts below bob up and down. */
    overflow-anchor: none;
    color: var(--cream);
    text-align: center;
}
.hero { background: var(--sky-day); }
.hero .sky,
.error-page .sky { position: absolute; inset: 0; z-index: -1; }
.hero .sky::before {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--sky-night);
    opacity: 0;
    transition: opacity var(--fade-sun) ease-in-out;
}
[data-theme="dark"] .hero .sky::before { opacity: 1; }
.hero .sky::after,
.error-page .sky::after,
.nightfall::after {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--grain) 0 0 / 180px 180px;
    pointer-events: none;
}

.hero-copy {
    width: min(var(--wide), 100% - 2 * var(--gutter));
    margin-inline: auto;
    /* The hero leaves room for the whole sun under the copy, so the text never
       sits on its pale face. The 404 has no sun and only clears the skyline. */
    padding-block: clamp(3.5rem, 9vw, 6.5rem) var(--sun-clear, clamp(10rem, 22vw, 16rem));
}
.hero-copy { container-type: inline-size; }
.hero .kicker,
.error-page .kicker { color: var(--s1); }

.hero-title {
    margin: 0.75rem 0 0;
    font-family: var(--font-greeting);
    /* Fills 40rem on desktop and the copy column on a phone. --greeting-em is
       the greeting's width in ems: 6.61 for the default "Hi, I'm Joe." in
       Bowlby One. Retune it if the greeting setting changes much; a longer
       greeting simply wraps. */
    --greeting-em: 6.61;
    font-size: calc(min(40rem, 96cqi) / var(--greeting-em));
    font-weight: 400;
    line-height: 0.95;
    letter-spacing: 0;
    text-transform: uppercase;
    text-shadow: 0.035em 0.035em 0 var(--s3), 0.07em 0.07em 0 var(--s5);
}
.hero-lede {
    max-width: 32rem;
    margin: 1.6rem auto 0;
    font-size: 1.1em;
    line-height: 1.55;
    text-shadow: 0 1px 14px color-mix(in srgb, var(--s5) 70%, transparent);
}

/* The sun sits on the rooftops with its bottom half cut into bands, and
   sinks behind them as the hero scrolls away. After dark it has set all
   the way and a full moon has risen in its place. */
.hero {
    --sun-size: clamp(9rem, 22vw, 15rem);
    --sun-lift: clamp(24px, 4vw, 48px);
    --sun-clear: calc(var(--sun-lift) + var(--sun-size) + 1.75rem);
}
.sun {
    position: absolute;
    left: 50%;
    bottom: var(--sun-lift);
    width: var(--sun-size);
    aspect-ratio: 1;
    border-radius: 50%;
    background: linear-gradient(180deg, #fff3c4 0%, var(--s1) 30%, var(--s2) 70%, var(--s3) 100%);
    box-shadow: 0 0 80px 10px color-mix(in srgb, var(--s1) 55%, transparent);
    -webkit-mask-image: linear-gradient(180deg, #000 50%, transparent 50% 56%, #000 56% 66%, transparent 66% 71%, #000 71% 80%, transparent 80% 84%, #000 84%);
    mask-image: linear-gradient(180deg, #000 50%, transparent 50% 56%, #000 56% 66%, transparent 66% 71%, #000 71% 80%, transparent 80% 84%, #000 84%);
    transform: translateX(-50%);
    transition: translate var(--fade-sun) ease-in-out, opacity var(--fade-sun) ease-in-out;
}
/* Just below the hero's bottom edge, and faded out so its glow goes too.
   Stopping right at the edge keeps the whole move visible, so the sky
   (which runs on the same clock) darkens exactly as the sun goes down. */
[data-theme="dark"] .sun { translate: 0 calc(100% + var(--sun-lift)); opacity: 0; }

/* The moon waits below the rooftops by day and rises off to the right,
   so it doesn't climb straight through the setting sun. Phones skip it:
   at that size it swamps the hero. */
.moon {
    --moon-size: calc(var(--sun-size) * 0.55);
    position: absolute;
    left: calc(50% + var(--sun-size) * 0.95);
    bottom: calc(var(--sun-lift) + var(--sun-size) * 0.3);
    width: var(--moon-size);
    aspect-ratio: 1;
    border-radius: 50%;
    background:
        radial-gradient(circle at 34% 38%, rgb(150 140 120 / 0.35) 0 9%, transparent 10%),
        radial-gradient(circle at 62% 30%, rgb(150 140 120 / 0.28) 0 6%, transparent 7%),
        radial-gradient(circle at 56% 64%, rgb(150 140 120 / 0.3) 0 12%, transparent 13%),
        radial-gradient(circle at 28% 66%, rgb(150 140 120 / 0.22) 0 5%, transparent 6%),
        radial-gradient(circle at 38% 34%, #fffbea, #efe6cc 55%, #d6cbb0 100%);
    box-shadow: 0 0 40px 6px rgb(255 244 210 / 0.28), 0 0 120px 30px rgb(200 190 255 / 0.12);
    transform: translateX(-50%);
    translate: 0 calc(100% + var(--sun-lift) + var(--sun-size) * 0.3);
    opacity: 0;
    transition: translate var(--fade-sun) ease-in-out, opacity var(--fade-sun) ease-in-out;
}
@media (max-width: 719px) {
    .moon { display: none; }
}
[data-theme="dark"] .moon { translate: 0 0; opacity: 1; }

@supports (animation-timeline: view()) {
    .hero .sun {
        animation: sun-sink linear both;
        animation-timeline: view();
        animation-range: exit 0% exit 80%;
    }
    @keyframes sun-sink { to { transform: translateX(-50%) translateY(45%); } }
}

/* ---------- Post list ---------- */

.post-list {
    position: relative;
    margin-top: clamp(2rem, 6vw, 3.5rem);
    padding: clamp(1rem, 2.5vw, 1.5rem) clamp(1rem, 3vw, 2rem) 0.75rem clamp(1.75rem, 4vw, 2.75rem);
}
/* A sunset spine down the left edge. */
.post-list::before {
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: clamp(0.6rem, 1.5vw, 0.9rem);
    border-radius: 6px 0 0 6px;
    background: var(--sunset-v);
}

.post-list-head {
    padding-bottom: 0.6rem;
    border-bottom: 3px solid var(--ink);
}
.post-list-label {
    color: var(--accent);
    font-family: var(--font-marker);
    font-size: clamp(1.7rem, 1.3rem + 1.6vw, 2.4rem);
    font-weight: 400;
    line-height: 1;
    transform: rotate(-2deg);
    transform-origin: 0 50%;
}

.post-items { margin: 0; padding: 0; list-style: none; }

.post-item {
    position: relative;
    padding: 1.2rem 0.25rem;
    border-bottom: 1px dashed var(--rule);
}
.post-item:last-child { border-bottom: 0; }

.post-item-title {
    font-size: clamp(1.55rem, 1.2rem + 1.3vw, 2.1rem);
    font-weight: 800;
    line-height: 1.02;
}
.post-item-title a {
    color: var(--ink);
    text-decoration: none;
    /* The padding drops the highlighter below the descenders. */
    padding-bottom: 0.12em;
    background: var(--sunset) no-repeat 0 100% / 0 0.14em;
    -webkit-box-decoration-break: clone;
    box-decoration-break: clone;
    transition: background-size 0.45s cubic-bezier(.6, 0, .2, 1);
}
/* The whole post is the link, but only the title reacts: the sunset
   highlighter (the one the post page uses) sweeps in under it. Nothing
   between here and .post-item may take a transform: that would shrink
   this cover to the title. */
.post-item-title a::after { content: ""; position: absolute; inset: 0; }
.post-item:hover .post-item-title a,
.post-item:focus-within .post-item-title a { color: var(--ink); background-size: 100% 0.14em; }
.post-item-excerpt {
    display: -webkit-box;
    margin: 0.45rem 0 0.5rem;
    overflow: hidden;
    color: var(--ink-soft);
    font-size: 0.93em;
    line-height: 1.6;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
}
.post-item .meta { margin-top: 0.35rem; }

/* No posts (yet): a line or two in the card where the list would be. */
.post-list > .empty {
    margin: 0;
    padding: clamp(1.75rem, 4vw, 2.5rem) 0.25rem clamp(1.25rem, 3vw, 1.75rem);
    font-size: 1.05em;
    line-height: 1.6;
    text-wrap: balance;
}


/* ---------- Pagination ---------- */

.pagination {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 1rem;
    margin-top: 2.5rem;
}
.pagination > :first-child { justify-self: start; }
.pagination > :last-child { justify-self: end; }

/* ---------- Archive headers ---------- */

.archive-header { padding-block: clamp(3rem, 8vw, 5rem) 0.5rem; text-align: center; }
.archive-title {
    margin-top: 0.5rem;
    font-size: clamp(3rem, 1.6rem + 6vw, 6rem);
    font-weight: 900;
    line-height: 0.92;
    text-transform: uppercase;
    text-shadow: 0.05em 0.05em 0 var(--title-shadow);
}
.archive-lede { max-width: 32rem; margin: 1.25rem auto 0; color: var(--ink-soft); }
/* The search page's own field: the dialog's field with its button beside it. */
.search-page-form { max-width: 30rem; margin: 1.75rem auto 0; }
.search-page-form .signup-field { margin: 0; }
.search-page-row { display: flex; gap: 0.6rem; }
.search-page-row input { flex: 1; min-width: 0; }
.search-page-row .btn { flex: none; }
.author-header { display: grid; justify-items: center; gap: 1.25rem; }
.author-header .meta { margin-top: 1rem; }

/* ---------- Snapshot: feature images as drugstore prints ---------- */

.snapshot {
    margin: 0;
    padding: clamp(0.5rem, 1.2vw, 0.85rem) clamp(0.5rem, 1.2vw, 0.85rem) 0;
    border-radius: 3px;
    background: var(--paper);
    box-shadow: 0 1px 2px rgb(0 0 0 / 0.15), 0 18px 40px -18px rgb(40 20 40 / 0.55);
    transform: rotate(-1deg);
    transition: transform 0.4s cubic-bezier(.3, 1.4, .5, 1);
}
.snapshot:hover { transform: rotate(0); }
.snapshot-frame { position: relative; overflow: hidden; }
.snapshot img {
    width: 100%;
    filter: saturate(1.08) sepia(0.12) contrast(1.04);
}
/* A warm light leak across one corner. */
.snapshot-frame::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: radial-gradient(ellipse 60% 70% at 100% 0%, color-mix(in srgb, var(--s2) 30%, transparent), transparent 70%);
    mix-blend-mode: screen;
}
.date-stamp {
    position: absolute;
    right: 1.1em;
    bottom: 0.9em;
    z-index: 1;
    color: var(--stamp);
    font-family: var(--font-mono);
    font-size: clamp(0.8rem, 0.6rem + 0.7vw, 1.15rem);
    font-weight: 600;
    letter-spacing: 0.12em;
    text-shadow: 0 0 2px #ff5a00, 0 0 8px rgb(255 120 0 / 0.75);
    opacity: 0.92;
}
.snapshot figcaption {
    margin: 0;
    padding: 0.7rem 0.25rem 0.8rem;
    color: var(--paper-ink);
    font-family: var(--font-marker);
    font-size: 1rem;
    line-height: 1.35;
    text-align: center;
}
.snapshot:not(:has(figcaption)) { padding-bottom: clamp(1.75rem, 4vw, 2.75rem); }

.snapshot.snapshot-sm { width: 8rem; padding: 0.45rem 0.45rem 1.4rem; transform: rotate(-4deg); }

/* Your portrait above the greeting: a cream ring, a sunset ring outside it,
   and a soft glow, so it sits in the sky rather than on top of it. */
.hero-face {
    display: block;
    width: clamp(5.5rem, 12vw, 7rem);
    height: auto;
    aspect-ratio: 1;
    margin: 0 auto 1.25rem;
    border: 3px solid var(--cream);
    border-radius: 50%;
    object-fit: cover;
    box-shadow:
        0 0 0 3px var(--s2),
        0 0 28px 4px color-mix(in srgb, var(--s1) 45%, transparent);
}
[data-theme="dark"] .hero-face { box-shadow: 0 0 0 3px var(--lamp), 0 0 28px 4px color-mix(in srgb, var(--lamp) 35%, transparent); }

/* ---------- Article ---------- */

.article-header {
    width: min(var(--wide), 100% - 2 * var(--gutter));
    margin: 0 auto;
    padding-block: clamp(2.75rem, 8vw, 5rem) clamp(2rem, 5vw, 3rem);
    text-align: center;
}
/* The title stands in the middle of a sunset plank: a strip of floor with
   a lit far edge and a darker front lip, the letters' shadows falling on
   it. The plank sweeps in on arrival, then the shadows come up.

   The plank is drawn by a hidden copy of the title (.title-floor) set in
   the same grid cell as the heading, so both wrap identically; each line
   gets its own plank (box-decoration-break). Its em offsets are measured
   from Big Shoulders' 1.2em content box (baseline 0.99em down): the plank
   runs 0.86em to 1.135em, the letters' feet just behind its middle. */
@property --sweep { syntax: "<percentage>"; inherits: true; initial-value: 100%; }
@property --drop { syntax: "<number>"; inherits: true; initial-value: 1; }
.article-title {
    display: grid;
    margin-top: 1rem;
    font-family: var(--font-display);
    font-size: clamp(2.75rem, 1.4rem + 5.5vw, 5.25rem);
    font-weight: 850;
    line-height: 0.95;
    letter-spacing: 0.005em;
    text-wrap: balance;
}
.article-title > * { grid-area: 1 / 1; margin: 0; font: inherit; letter-spacing: inherit; }
.article-title > * > span {
    padding-inline: 0.06em;
    -webkit-box-decoration-break: clone;
    box-decoration-break: clone;
}
/* The mask keeps the shadows on the plank, off the paper: one band per
   0.95em line, the plank's top-face (content box 0.86em = line box
   0.735em). A mask makes the floor its own layer, hence .title-ink's
   position, which keeps the letters above it. */
.title-floor {
    -webkit-mask: repeating-linear-gradient(#000 0 0.215em, transparent 0.215em 0.95em) 0 0.735em;
    mask: repeating-linear-gradient(#000 0 0.215em, transparent 0.215em 0.95em) 0 0.735em;
    user-select: none;
    pointer-events: none;
    animation: sweep 0.9s 0.2s cubic-bezier(.6, 0, .2, 1) both;
}
.title-floor > span {
    color: transparent;
    background:
        linear-gradient(var(--plank-glint), transparent) no-repeat 0 0.86em / var(--sweep) 0.06em,
        linear-gradient(var(--plank-lip), var(--plank-lip)) no-repeat 0 1.075em / var(--sweep) 0.06em,
        var(--sunset) no-repeat 0 0.86em / var(--sweep) 0.275em;
    text-shadow: 0 0.03em 0.02em color-mix(in srgb, var(--title-drop) calc(var(--drop) * 100%), transparent);
}
.title-ink { position: relative; }
@keyframes sweep { from { --sweep: 0%; --drop: 0; } 70% { --drop: 0; } to { --sweep: 100%; --drop: 1; } }
@media (forced-colors: active) { .title-floor { display: none; } }
.article-lede {
    max-width: var(--measure);
    margin: 1.4rem auto 0;
    color: var(--ink-soft);
    font-size: 1.15em;
    font-style: italic;
    line-height: 1.55;
}
.article-tag { margin: 1.6rem 0 0; }

.article-image {
    width: min(var(--wide), 100% - 2 * var(--gutter));
    margin: 0 auto clamp(2.5rem, 6vw, 4rem);
}

/* Content grid: prose in `main`; wide images get extra room and full ones
   run edge to edge. */
.content {
    display: grid;
    grid-template-columns:
        [full-start] minmax(var(--gutter), 1fr)
        [wide-start] minmax(0, 7rem)
        [main-start] min(var(--measure), 100% - 2 * var(--gutter))
        [main-end] minmax(0, 7rem)
        [wide-end] minmax(var(--gutter), 1fr)
        [full-end];
}
.content > * { grid-column: main; }
:is(.content, .ai-body) > * { margin-block: 0 1.5rem; }
.content > .width-wide { grid-column: wide; }
.content > .width-full { grid-column: full; }
.width-full img { width: 100%; }

/* Drop cap: the first letter in the poster face, three lines deep. Not
   when the post opens on an AI mark (render.ts marks the paragraph): the
   robot leads it. ::first-letter keeps the word whole for screen readers. */
.post-template .content > p:first-child:not(.starts-with-ai)::first-letter {
    float: left;
    /* Sized so the cap (0.8em tall in Big Shoulders) runs from the first
       line's cap height to the third line's baseline: 2 × 1.7 + 0.7 em. */
    margin: 0.13em 0.08em 0 0;
    color: var(--accent);
    font-family: var(--font-display);
    font-size: 5.125em;
    font-weight: 900;
    line-height: 0.8;
}
@supports (initial-letter: 3) {
    .post-template .content > p:first-child:not(.starts-with-ai)::first-letter {
        float: none;
        margin: 0 0.4em 0 0;
        font-size: inherit;
        line-height: inherit;
        initial-letter: 3;
    }
}

:is(.content, .ai-body) > h2,
:is(.content, .ai-body) > h3,
:is(.content, .ai-body) > h4 { margin-top: 1.5rem; margin-bottom: 0.75rem; } /* + prior 1.5rem: grid rows don't collapse margins */
:is(.content, .ai-body) > h2 {
    font-size: clamp(1.9rem, 1.5rem + 1.5vw, 2.6rem);
    font-weight: 850;
}
:is(.content, .ai-body) > h3 { font-size: clamp(1.45rem, 1.25rem + 0.7vw, 1.8rem); }
:is(.content, .ai-body) > h4 { font-size: 1.25rem; letter-spacing: 0.04em; text-transform: uppercase; }
/* An AI article's headings sit a level down (render.ts), so its h4s become h5s. */
.ai-body > :is(h5, h6) { margin-top: 1.5rem; margin-bottom: 0.75rem; font-size: 1.1rem; letter-spacing: 0.04em; text-transform: uppercase; }

.content ul, .content ol { padding-left: 1.4em; }
.content li { margin-block: 0.4em; }
.content ul > li::marker { content: "✦  "; color: var(--accent); font-size: 0.8em; }
.content ol > li::marker { color: var(--accent); font-family: var(--font-mono); font-size: 0.85em; font-weight: 600; }

.content blockquote:not([class]) {
    position: relative;
    margin-inline: 0;
    padding: 0.2rem 0 0.2rem 1.4rem;
    border-left: 5px solid;
    border-image: var(--sunset-v) 1;
    color: var(--ink);
    font-size: 1.08em;
    font-style: italic;
}
.content blockquote.blockquote-alt {
    margin-inline: 0;
    padding: 1rem 0;
    color: var(--accent);
    font-family: var(--font-display);
    font-size: clamp(1.8rem, 1.4rem + 1.6vw, 2.6rem);
    font-style: normal;
    font-weight: 850;
    line-height: 1.05;
    text-align: center;
    text-transform: uppercase;
}

.content hr {
    width: min(14rem, 50%);
    height: 4px;
    margin: 2.5rem auto 3rem;
    border: 0;
    border-radius: 2px;
    background: var(--sunset);
}

.content :not(pre) > code {
    padding: 0.12em 0.4em;
    border-radius: 4px;
    background: color-mix(in srgb, var(--s1) 32%, var(--panel));
    color: var(--ink);
    font-family: var(--font-mono);
    font-size: 0.86em;
}
[data-theme="dark"] .content :not(pre) > code { background: var(--rule); }

/* Code blocks: a dark panel with a paper label across the top, the
   language hand-written on it (main.js fills data-lang). */
.content pre {
    position: relative;
    overflow-x: auto;
    padding: 3.1rem 1.35rem 1.35rem;
    border-radius: 10px;
    background: var(--code-bg);
    color: var(--code-ink);
    box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.06), 0 14px 30px -18px rgb(10 5 30 / 0.7);
    font-family: var(--font-mono);
    font-size: 0.85rem;
    line-height: 1.65;
    tab-size: 4;
}
.content pre::before {
    content: "code";
    position: absolute;
    top: 0.7rem;
    left: 0.85rem;
    right: 0.85rem;
    height: 1.55rem;
    padding: 0 0.8rem;
    border-radius: 4px;
    background:
        var(--sunset) no-repeat 0 100% / 100% 4px,
        var(--paper);
    color: var(--paper-ink);
    font-family: var(--font-marker);
    font-size: 0.9rem;
    line-height: 1.55rem;
    white-space: nowrap;
}
.content pre[data-lang]::before { content: attr(data-lang); }
.content pre code { font: inherit; background: none; padding: 0; }

/* Syntax colours for Prism (bundled, see main.js) and highlight.js. Sunset
   on blacktop; every colour clears AA on --code-bg. */
.content pre .token.comment, .content pre .token.prolog, .content pre .hljs-comment { color: #9a91ad; font-style: italic; }
.content pre .token.keyword, .content pre .token.atrule, .content pre .hljs-keyword { color: #ff8a5c; }
.content pre .token.string, .content pre .token.char, .content pre .token.attr-value, .content pre .hljs-string { color: #ffd27a; }
.content pre .token.function, .content pre .hljs-title { color: #7fd6c2; }
.content pre .token.number, .content pre .token.boolean, .content pre .token.constant, .content pre .hljs-number, .content pre .hljs-literal { color: #f7a1a8; }
.content pre .token.class-name, .content pre .token.builtin, .content pre .hljs-built_in, .content pre .hljs-type { color: #cfa8ff; }
.content pre .token.punctuation, .content pre .token.operator { color: #bdb3cc; }
.content pre .token.property, .content pre .token.tag, .content pre .hljs-attr, .content pre .hljs-name { color: #ffb07a; }

.content table {
    display: block;
    overflow-x: auto;
    border-collapse: collapse;
    font-size: 0.9em;
}
.content th, .content td { padding: 0.55rem 0.85rem; border-bottom: 1px solid var(--rule); text-align: left; }
.content th {
    border-bottom: 3px solid var(--ink);
    font-family: var(--font-mono);
    font-size: 0.78em;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.content figure { margin-inline: 0; }
.content figcaption {
    margin-top: 0.7rem;
    color: var(--ink-soft);
    font-family: var(--font-marker);
    font-size: 0.95rem;
    text-align: center;
}
.content .image-card img { margin-inline: auto; border-radius: 4px; }
.content .width-full.image-card img { border-radius: 0; }

/* Callouts: an emoji and a few lines in a tinted box. */
.content .callout {
    display: flex;
    gap: 0.9rem;
    padding: 1.1rem 1.3rem;
    border-radius: 8px;
    background: var(--tint);
}
.content .callout-emoji { flex: none; font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif; font-size: 1.3em; line-height: 1.5; }
/* After dark the amber tint went muddy on the panel: a faint lamp wash
   and a lamp-coloured edge instead. */
[data-theme="dark"] .content .callout {
    background: color-mix(in srgb, var(--lamp) 9%, var(--panel));
    box-shadow: inset 3px 0 0 var(--lamp);
}
.content .callout-text { min-width: 0; }
.content .callout-text > * { margin-block: 0 0.75rem; }
.content .callout-text > :last-child { margin-bottom: 0; }


/* ---------- AI marking ----------
   Every post is Joe's own writing. Anything an AI wrote (quotes, snippets,
   whole articles, all code) is marked with the robot and set apart, so a
   reader can skip it. Code is AI-written as a matter of course and isn't
   marked. The editor's AI block, AI article and bot highlighter render as
   the marks below (packages/content/src/render.ts), and so does a 🤖
   typed in the text. A post with any of them gets the post-level badges. */

.robot { display: inline-block; flex: none; width: 1.2em; height: 1.2em; vertical-align: -0.22em; }
.robot .robot-line { stroke: currentColor; fill: none; }
.robot .robot-ink { fill: currentColor; }
.robot .robot-head { fill: var(--s1); }
.robot .robot-eye { fill: var(--cream); }
.robot .robot-face { fill: var(--ink-fixed); }
.robot .robot-face-line { stroke: var(--ink-fixed); }
.robot .robot-grille { stroke: var(--s1); }
[data-theme="dark"] .robot .robot-head { fill: var(--lamp); }
[data-theme="dark"] .robot .robot-grille { stroke: var(--lamp); }

/* Post-level marks (any AI in the post): in the list, and in the post header. */
.ai-flag { display: inline-flex; align-items: center; gap: 0.4em; color: var(--ink); }
.ai-flag .robot { width: 1.35em; height: 1.35em; }
.article-ai { margin: 1.1rem 0 0; }
.ai-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.5em;
    padding: 0.4em 0.9em 0.4em 0.6em;
    border: 1px dashed var(--ink-soft);
    border-radius: 999px;
    color: var(--ink);
    font-family: var(--font-mono);
    font-size: 0.72rem;
    letter-spacing: 0.08em;
    text-decoration: none;
    text-transform: uppercase;
}
.ai-badge .robot { width: 1.6em; height: 1.6em; }
.ai-badge:hover { color: var(--ink); background: var(--tint); }

/* AI-written passages sit quietly in the column: no box, just a dashed
   rule down the left in dusk (the far end of the ribbon: violet by day,
   teal after dark) and a small label. Dashed, so it never reads as one of
   Joe's quotes, which get the solid sunset rule. */
/* 74% keeps the dashes at 3:1 against the page by day (3.2:1) and night (3.9:1). */
:root { --ai: color-mix(in srgb, var(--g4) 74%, var(--bg)); }
.content .ai-block,
.content .ai-article {
    display: block;
    padding: 0.1rem 0 0.1rem 1.3rem;
    border: 0;
    background: repeating-linear-gradient(180deg, var(--ai) 0 6px, transparent 6px 11px) 0 0 / 2px 100% no-repeat;
    color: var(--ink);
}
/* A short excerpt is a step quieter than the text around it. */
.content .ai-block .ai-body { color: var(--ink-soft); font-size: 0.95em; }
.content .ai-block .ai-body > * { margin-block: 0 1rem; }
.content .ai-body > :last-child { margin-bottom: 0; }

.ai-label {
    display: flex;
    align-items: center;
    gap: 0.5em;
    margin: 0 0 0.6rem;
    color: var(--ink-soft);
    font-family: var(--font-mono);
    font-size: 0.75rem;
    letter-spacing: 0.1em;
    line-height: 1.3;
    text-transform: uppercase;
}
.ai-label .robot { width: 1.45em; height: 1.45em; color: var(--ink-soft); }
.ai-label-end { margin: 1rem 0 0; scroll-margin-top: 6rem; }
.ai-skip { margin-left: auto; color: var(--ink-soft); text-decoration-style: dotted; }
.ai-skip:hover { color: var(--link); }

/* The bot highlighter: a phrase or sentence inside a paragraph, led by
   the robot and underlined in the same dusk dashes. */
.content .ai-inline {
    text-decoration: underline dashed var(--ai);
    text-decoration-thickness: 2px;
    text-underline-offset: 0.28em;
    text-decoration-skip-ink: none;
}
/* A link inside keeps its solid underline, drawn above the dashes. */
.content .ai-inline a { text-underline-offset: 0.12em; }
.content .ai-inline .robot { width: 1em; height: 1em; margin-right: 0.2em; vertical-align: -0.14em; color: var(--ink-soft); }

/* The footer legend: the rule in one line, on every page. */
.ai-legend { margin: 0; }
.ai-legend a {
    display: inline-flex;
    align-items: center;
    gap: 0.5em;
    color: var(--cream-soft);
    font-family: var(--font-mono);
    font-size: 0.72rem;
    letter-spacing: 0.06em;
    text-decoration: none;
    text-transform: uppercase;
}
.ai-legend a:hover { color: var(--lamp-glow); background: none; }
.ai-legend .robot { width: 1.7em; height: 1.7em; color: var(--cream); }
.ai-legend .robot .robot-head { fill: var(--lamp-glow); }
.ai-legend .robot .robot-grille { stroke: var(--lamp-glow); }

/* ---------- Article footer ---------- */

.article-footer { margin-top: 3rem; }
.tag-list { display: flex; flex-wrap: wrap; gap: 0.6rem; margin: 0 0 2rem; }

.byline {
    display: flex;
    gap: 1rem;
    align-items: center;
    padding-top: 1.5rem;
    border-top: 3px solid var(--ink);
    font-size: 0.95em;
}
.byline p { margin: 0; }
.byline-avatar {
    width: 3.75rem;
    height: 3.75rem;
    flex: none;
    border-radius: 50%;
    object-fit: cover;
    box-shadow: 0 0 0 3px var(--bg), 0 0 0 6px var(--s2);
}

.post-nav {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
    margin-top: 2.5rem;
}
.post-nav-link {
    display: grid;
    align-content: start;
    gap: 0.45rem;
    padding: 1rem 0 1.1rem;
    border-top: 1px solid var(--rule);
    color: var(--ink);
    text-decoration: none;
}
.post-nav-link:hover { color: var(--ink); background: none; }
.post-nav-link:hover .post-nav-title { color: var(--link); }
.post-nav-link.prev { grid-column: 1; }
.post-nav-link.next { grid-column: 2; text-align: right; }
.post-nav-label { color: var(--accent); font-family: var(--font-mono); font-size: 0.72rem; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; }
.post-nav-title { font-family: var(--font-display); font-size: 1.4rem; font-weight: 800; line-height: 1.05; }
@media (max-width: 560px) {
    .post-nav { grid-template-columns: 1fr; }
    .post-nav-link.next { grid-column: 1; }
}

/* ---------- Error page: night in the cul-de-sac ---------- */

.error-page { --horizon: var(--blacktop); background: var(--sky-night); }
.error-code {
    margin: 0.5rem 0 0;
    font-family: var(--font-display);
    font-size: clamp(7rem, 3rem + 20vw, 15rem);
    font-weight: 900;
    line-height: 0.85;
    color: transparent;
    background: var(--sunset-v);
    -webkit-background-clip: text;
    background-clip: text;
    filter: drop-shadow(0 0 30px color-mix(in srgb, var(--s2) 45%, transparent));
}
.error-page .archive-title { color: var(--cream); text-shadow: 0.05em 0.05em 0 var(--s4); font-size: clamp(2rem, 1.4rem + 3vw, 3.5rem); }
.error-page .hero-lede { margin-bottom: 2rem; }
.error-page .btn { background: var(--cream); color: var(--ink-fixed); border-color: var(--cream); }
.error-page .btn:hover { background: var(--link); color: var(--cream); border-color: var(--link); }

/* At the end of a post (the footer leaves its own out), in the prose
   column. */
.site-main > .subscribe { margin: clamp(2rem, 5vw, 3rem) auto 2rem; }

/* ---------- Footer: every page ends at nightfall ---------- */

.site-footer { margin-top: auto; }

.subscribe {
    margin-bottom: clamp(3rem, 8vw, 5rem);
    padding: clamp(1.5rem, 4vw, 2.25rem);
    text-align: center;
}
.subscribe-title { font-size: clamp(1.9rem, 1.5rem + 1.5vw, 2.5rem); font-weight: 900; text-transform: uppercase; }
.subscribe p { margin: 0.6rem 0 1.4rem; color: var(--ink-soft); }

/* Newsletter signup dialog: the subscribe card, lifted over a dusky,
   blurred page. */
.signup {
    width: min(28rem, 100% - 2 * var(--gutter));
    max-height: calc(100dvh - 2rem);
    margin: auto;
    padding: clamp(1.75rem, 5vw, 2.5rem) clamp(1.25rem, 5vw, 2.25rem) clamp(1.5rem, 4vw, 2rem);
    overflow: auto;
    border: 2px solid var(--ink);
    border-radius: 8px;
    background: var(--panel);
    color: var(--ink);
    box-shadow: var(--card-shadow);
    text-align: center;
}
.signup::backdrop {
    background: linear-gradient(180deg, color-mix(in srgb, var(--s4) 30%, transparent), color-mix(in srgb, var(--s5) 62%, transparent));
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
}
.signup[open] { animation: signup-in 0.32s cubic-bezier(.2, 1.4, .4, 1); }
.signup[open]::backdrop { animation: signup-fade 0.25s ease; }
@keyframes signup-in { from { opacity: 0; transform: translateY(14px) scale(0.97); } }
@keyframes signup-fade { from { opacity: 0; } }
.signup-close { position: absolute; top: 0.75rem; right: 0.75rem; width: 2.1rem; height: 2.1rem; }
.signup-close svg { width: 0.95rem; height: 0.95rem; }
.signup-sun { display: block; width: 2.75rem; height: 2.75rem; margin: 0 auto 0.9rem; }
.signup-title { margin: 0; font-size: clamp(1.7rem, 1.4rem + 1.2vw, 2.2rem); font-weight: 900; line-height: 1.05; text-transform: uppercase; }
.signup-lede { margin: 0.6rem 0 1.4rem; color: var(--ink-soft); }
.signup-field { display: block; margin-bottom: 0.9rem; text-align: left; }
.signup-field span {
    display: block;
    margin-bottom: 0.3rem;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}
.signup-field em { font-style: normal; color: var(--ink-soft); text-transform: none; letter-spacing: 0; }
.signup-field input {
    width: 100%;
    padding: 0.65em 0.8em;
    border: 2px solid var(--ink);
    border-radius: 6px;
    background: var(--bg);
    color: var(--ink);
    font: inherit;
}
.signup-field input:focus { outline: none; box-shadow: 4px 4px 0 var(--g3); }
.signup-submit { width: 100%; justify-content: center; margin-top: 0.4rem; padding-block: 0.8em 0.75em; }
.signup-wait,
.signup-form.loading .signup-go { display: none; }
.signup-form.loading .signup-wait { display: inline; }
.signup-form.loading .signup-submit { pointer-events: none; opacity: 0.75; }
.signup-error { margin: 0.75rem 0 0; color: var(--link); font-size: 0.9rem; }
.signup-error:empty { display: none; }
.signup-done,
.signup-form.success .signup-ask { display: none; }
.signup-form.success .signup-done { display: block; }

/* Search: the same lifted card, higher up, with the results under the box. */
.search {
    width: min(36rem, 100% - 2 * var(--gutter));
    margin-top: min(12vh, 6rem);
    text-align: left;
}
.search-title { margin: 0 0 1rem; font-size: clamp(1.5rem, 1.3rem + 1vw, 1.9rem); font-weight: 900; line-height: 1.05; text-transform: uppercase; }
.search .signup-field { margin: 0; }
.search-results { margin: 1rem 0 0; padding: 0; list-style: none; }
.search-results a {
    display: block;
    padding: 0.7rem 0.6rem;
    border-bottom: 1px dashed var(--rule);
    border-radius: 4px;
    color: var(--ink);
    text-decoration: none;
}
.search-results a:hover,
.search-results a:focus-visible { background: var(--tint); outline: none; }
.search-result-title { display: block; font-family: var(--font-display); font-size: 1.2rem; font-weight: 800; letter-spacing: 0.02em; line-height: 1.15; text-transform: uppercase; }
.search-result-excerpt {
    display: -webkit-box;
    margin-top: 0.25rem;
    overflow: hidden;
    color: var(--ink-soft);
    font-size: 0.9rem;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
}
/* Each result's date, under its title (posts only; pages aren't dated). */
.search-result-meta { display: block; margin-top: 0.3rem; font-size: 0.7rem; }
.search-empty { margin: 1rem 0 0; color: var(--ink-soft); font-family: var(--font-marker); }
.search-empty:empty { display: none; }

.nightfall {
    position: relative;
    overflow-anchor: none;
    height: clamp(11rem, 24vw, 18rem);
    background: var(--dusk-day);
    --horizon: var(--blacktop);
}
.nightfall::before {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--dusk-night);
    opacity: 0;
    transition: opacity var(--fade-sun) ease-in-out;
}
[data-theme="dark"] .nightfall::before { opacity: 1; }
.nightfall .stars {
    inset: 0;
    -webkit-mask-image: linear-gradient(180deg, transparent 45%, #000 85%);
    mask-image: linear-gradient(180deg, transparent 45%, #000 85%);
}

.footer-ground {
    display: grid;
    justify-items: center;
    gap: 1.25rem;
    padding: 1.5rem var(--gutter) 3rem;
    background: var(--grain) 0 0 / 180px 180px, var(--blacktop);
    color: var(--cream);
    text-align: center;
}
.footer-line {
    margin: 0;
    color: var(--lamp-glow);
    font-family: var(--font-marker);
    font-size: clamp(1.4rem, 1rem + 2.2vw, 2.4rem);
    line-height: 1.2;
    text-shadow: 0 0 18px rgb(255 170 60 / 0.45);
    text-wrap: balance;
    transform: rotate(-1.5deg);
}
.footer-ground ul {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.4rem 1.4rem;
    margin: 0;
    padding: 0;
    list-style: none;
}
.footer-ground ul a {
    color: var(--cream);
    font-family: var(--font-display);
    font-size: 1.1rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-decoration: none;
    text-transform: uppercase;
}
.footer-ground ul a:hover { color: var(--lamp-glow); background: none; }
.footer-meta {
    margin: 0;
    color: var(--cream-soft);
    font-family: var(--font-mono);
    font-size: 0.72rem;
    letter-spacing: 0.06em;
    line-height: 1.8;
    text-transform: uppercase;
}
.footer-meta a { color: var(--cream); }
.footer-meta a:hover { color: var(--ink-fixed); background: var(--lamp-glow); }

/* The hit counter in the footer: odometer wheels in a little bezel, like the
   one at the bottom of every GeoCities page. Each digit is its own tile
   with a seam across the middle, and the last one rolls up into place
   when the count arrives. */
.hit-counter {
    display: grid;
    justify-items: center;
    gap: 0.5rem;
    margin: 0.25rem 0 0;
}
.hit-counter[hidden] { display: none; }
.hit-label {
    color: var(--lamp-glow);
    font-family: var(--font-marker);
    font-size: 1.05rem;
    line-height: 1.2;
    transform: rotate(-1.5deg);
}
.hit-digits {
    display: inline-flex;
    gap: 3px;
    padding: 4px;
    border-radius: 5px;
    background: linear-gradient(180deg, #3a3550, #17152a);
    box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.12), 0 2px 0 #000, 0 0 22px rgb(255 170 60 / 0.18);
}
.hit-digit {
    position: relative;
    display: inline-grid;
    place-items: center;
    width: 1.35rem;
    height: 1.9rem;
    overflow: hidden;
    border-radius: 2px;
    background: linear-gradient(180deg, #000 0%, #26222f 48%, #0b0a12 52%, #000 100%);
    color: var(--cream);
    font-family: var(--font-mono);
    font-size: 1.15rem;
    font-weight: 600;
    line-height: 1;
}
/* The seam between the top and bottom of the wheel. */
.hit-digit::after {
    content: "";
    position: absolute;
    inset: 50% 0 auto;
    height: 1px;
    background: rgb(0 0 0 / 0.8);
    box-shadow: 0 1px 0 rgb(255 255 255 / 0.06);
}
.hit-digit:last-child { color: var(--lamp-glow); }
.hit-digit:last-child span { animation: hit-roll 0.7s cubic-bezier(0.2, 0.9, 0.3, 1.15) both; }
@keyframes hit-roll { from { transform: translateY(110%); } }

/* ---------- Motion ---------- */

/* Colour-scheme toggle: main.js sets .theme-fade while the switch plays, so
   colours fade instead of snapping. The palette fades at the root (below);
   per element, only the properties that switch between palette colours and
   that children don't inherit (backgrounds, borders, shadows), so nothing
   fades twice. Text colour is never transitioned per element: it inherits,
   and that's what chained. The sky pieces (sun, moon, the night-sky layers,
   the stars and the skyline) keep the transitions declared with them, so
   they're left out here. */
.theme-fade :not(.sun, .moon, .stars, .horizon *),
.theme-fade :not(.sky, .nightfall)::before,
.theme-fade *::after {
    transition: background-color var(--fade) ease, border-color var(--fade) ease, box-shadow var(--fade) ease;
}

/* The palette and the ribbon's stops, faded once for the whole page. */
:root.theme-fade {
    transition-property: --bg, --panel, --ink, --ink-soft, --rule, --link, --accent, --title-shadow, --plank-glint, --plank-lip, --title-drop, --horizon, --lamp, --g1, --g2, --g3, --g4;
    transition-duration: var(--fade);
    transition-timing-function: ease;
}

/* The sun and moon cross: at dusk the sun starts down first and the moon
   follows; at dawn the moon goes first and the sun, the sky's light and the
   stars follow it. Transitions take their timing from the state they head
   into, so each delay sits on that state. */
[data-theme="dark"] .moon,
[data-theme="light"] .sun,
[data-theme="light"] .hero .sky::before,
[data-theme="light"] .nightfall::before,
[data-theme="light"] .stars { transition-delay: var(--sun-delay); }

/* ...but only when the reader flips the switch. Any other theme change
   (a late fix-up on load, a prerendered page catching up, Dark Reader
   turning up, the OS switching) snaps, so the moon never sets on arrival. */
:root:not(.theme-fade) :is(.sun, .moon, .stars, .horizon .land, .hero .horizon :is(.lights, .beam, .beam-pool)),
:root:not(.theme-fade) :is(.sky, .nightfall)::before { transition: none; }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation: none !important;
        transition-duration: 0.01ms !important;
    }
    .post-template .progress { display: none; }
    .snapshot, .sticker, .kicker { transform: none; }
    .horizon .mote { display: none; }
}

/* ---------- Print ---------- */

@media print {
    .progress, .masthead, .post-nav, .site-footer, .hero .sky, .horizon { display: none !important; }
    body { background: #fff; color: #000; }
    .hero { background: none; color: #000; }
    .hero-title { text-shadow: none; }
    .snapshot { transform: none; box-shadow: none; }
}
