/* Blog index — a death-metal album sleeve under a black sun. Hard black with ash in the air and darkness pressing in
   from the edges; a black blackletter logo in capitals edged in blood red, at the foot of a skyline of black spires
   that rise into an eclipse with a faint skull in it; a riveted iron band under it; barbed wire between the releases, a chain to close, and a simulated mist
   along the foot of the screen that the pointer pushes around (blog-index-mist.js, a small fluid on a canvas).
   Everything decorative is CSS or inline SVG; text stays bone on black, so none of it costs legibility.
   Each project is a release: a square cover drawn in the project's own tokens (--plate-paper / --plate-ink /
   --plate-accent / --plate-font, set inline from project.json "plate") in an iron bevel with rivets, drained of colour
   until pointed at or focused, beside its liner notes and a track list of its sections. Releases alternate sides.
   The not-found page (NotFound.cshtml) shares the layout and the .shelf-header classes.
   These base rules are the shadow theme. Synthwave, the DEFAULT theme, is one override block near the end
   (":root[data-theme=synthwave]"); the server renders data-theme from the theme cookie (BlogIndexThemeCookie), and
   the theme switch (blog-index-theme.js) flips it. */

:root {
    --pit: #000000;
    /* Softened bone (the user found near-white too harsh): 13.4:1 on --pit; --bone-dim 9.4:1. */
    --bone: #d4cec2;
    --bone-dim: #b3ada1;
    --steel: #a3a9b0;
    --steel-dark: #3b3f45;
    /* Both ends of the chain and the barbed wire fade out over a few links, so neither stops on a cut link. */
    --rule-taper: linear-gradient(90deg, transparent 0, #000 7%, #000 93%, transparent 100%);
    /* The track-list blades' colour stops, tip first (each rule sets its own direction). */
    --blade: var(--bone), var(--steel) 55%, var(--steel-dark);
    /* Hit: the interaction colour (hover, focus), 6.2:1 on --pit, so it can carry text. --gore is decoration only. */
    --hit: #ff4545;
    --gore: #6e0008;
    /* The logo's red glows, at half the brightness of the first spires pass (the user wanted them twice as dark). */
    --aura: rgb(75 0 6 / 0.8);
    --rim-glow: rgb(128 10 14 / 0.9);
    --corona: rgb(226 228 232 / 0.75);
    /* Cover of a project whose project.json sets no "plate". Accent 7.4:1 on the paper. */
    --cover-paper: #d9d4c4;
    --cover-ink: #111111;
    --cover-accent: #7a0e14;
    /* Live display text (release names, the not-found title): hard, condensed capitals with no curves to speak of.
       The index's "BLOG" is not set in a font at all: it is drawn (Index.cshtml, .shelf-title-letters). */
    --font-logo: "Barlow Condensed", "Arial Narrow", sans-serif;
    --font-body: "Barlow Semi Condensed", "Arial Narrow", sans-serif;
    /* The logo's size: the black sun is sized and placed against it. */
    --logo-size: clamp(3.75rem, 15vw, 8.5rem);

    /* Black spires: a symmetric skyline of tall needle towers, tallest at the centre, each with a jagged ledge, on a
       broken ridge. Black, rimmed in blood red. Its box is 4.2em x 1.6em of the logo (2.625:1, the viewBox ratio). */
    --spires: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1050 400' preserveAspectRatio='none'%3E%3Cg fill='%23050505' stroke='%23520007' stroke-width='3' stroke-linejoin='miter'%3E%3Cpolygon points='22,400 32,355 27,352 36,332 40,310 44,332 53,352 48,355 58,400'/%3E%3Cpolygon points='93,400 105,322 98,318 111,284 115,245 119,284 132,318 125,322 137,400'/%3E%3Cpolygon points='179,400 193,285 185,278 200,228 205,170 210,228 225,278 217,285 231,400'/%3E%3Cpolygon points='275,400 292,245 282,236 299,168 305,90 311,168 328,236 318,245 335,400'/%3E%3Cpolygon points='381,400 400,200 390,188 408,100 415,0 422,100 440,188 430,200 449,400'/%3E%3Cpolygon points='495,400 512,210 503,198 519,115 525,20 531,115 547,198 538,210 555,400'/%3E%3Cpolygon points='669,400 650,200 660,188 642,100 635,0 628,100 610,188 620,200 601,400'/%3E%3Cpolygon points='775,400 758,245 768,236 751,168 745,90 739,168 722,236 732,245 715,400'/%3E%3Cpolygon points='871,400 857,285 865,278 850,228 845,170 840,228 825,278 833,285 819,400'/%3E%3Cpolygon points='957,400 945,322 952,318 939,284 935,245 931,284 918,318 925,322 913,400'/%3E%3Cpolygon points='1028,400 1018,355 1023,352 1014,332 1010,310 1006,332 997,352 1002,355 992,400'/%3E%3Cpolygon points='0,400 0,380 60,372 120,384 180,370 260,382 340,368 420,380 525,366 630,380 710,368 790,382 870,370 930,384 990,372 1050,380 1050,400'/%3E%3C/g%3E%3C/svg%3E");

    /* Decorative SVGs (backgrounds, so no accessibility tree). */
    --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .3 -.12'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
    --ash: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='260'%3E%3Cfilter id='a' color-interpolation-filters='sRGB' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.55' numOctaves='1' seed='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .62 0 0 0 0 .6 0 0 0 0 .57 16 0 0 0 -12.6'/%3E%3C/filter%3E%3Crect width='260' height='260' filter='url(%23a)'/%3E%3C/svg%3E");
    --iron-band: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='18'%3E%3Crect width='200' height='18' fill='%2317181a'/%3E%3Crect width='200' height='2' fill='%238c939a'/%3E%3Crect y='16' width='200' height='2' fill='%23000'/%3E%3Ccircle cx='50' cy='9' r='3.5' fill='%23a3a9b0' stroke='%23000'/%3E%3Ccircle cx='150' cy='9' r='3.5' fill='%23a3a9b0' stroke='%23000'/%3E%3C/svg%3E");
    --wire: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='40'%3E%3Cg fill='none' stroke-linecap='round'%3E%3Cpath d='M0 20C15 11 25 11 40 20S65 29 80 20S105 11 120 20M0 20C15 29 25 29 40 20S65 11 80 20S105 29 120 20' stroke='%23000' stroke-width='5'/%3E%3Cpath d='M0 20C15 11 25 11 40 20S65 29 80 20S105 11 120 20M0 20C15 29 25 29 40 20S65 11 80 20S105 29 120 20' stroke='%23a3a9b0' stroke-width='2.5'/%3E%3Cpath d='M51 8L69 32M69 8L51 32' stroke='%23000' stroke-width='5'/%3E%3Cpath d='M51 8L69 32M69 8L51 32' stroke='%23dfe2e5' stroke-width='2.5'/%3E%3C/g%3E%3C/svg%3E");
    /* The chain: an upright oval link per tile, and a flat link that runs from inside this oval, across the tile edge,
       into the next oval, drawn on top of both so the links read as threaded through each other. The flat link is
       drawn twice (its start at the tile's right, its end at the tile's left) so it continues across the seam. */
    --chain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='28'%3E%3Crect x='3' y='5' width='36' height='18' rx='9' fill='none' stroke='%23000' stroke-width='7'/%3E%3Crect x='3' y='5' width='36' height='18' rx='9' fill='none' stroke='%23a3a9b0' stroke-width='4'/%3E%3Cg fill='%236d737a' stroke='%23000' stroke-width='1.5'%3E%3Crect x='27' y='10.5' width='44' height='7' rx='3.5'/%3E%3Crect x='-37' y='10.5' width='52' height='7' rx='3.5'/%3E%3C/g%3E%3Cg fill='%23c9cdd2'%3E%3Crect x='30' y='11.5' width='34' height='1.5' rx='.75'/%3E%3Crect x='0' y='11.5' width='12' height='1.5' rx='.75'/%3E%3C/g%3E%3C/svg%3E");
    /* A domed rivet: a whole circle inside its 16px box. "closest-side" ends the circle at the nearest edge of the box,
       so its rim is never cut off (the old "farthest-corner" circle ran past the box and was clipped flat). The
       centre sits a little up and left, where the highlight is. One gradient, so it can be sized and placed. */
    --rivet: radial-gradient(circle closest-side at 46% 44%, #f2f4f6 0, #a3a9b0 28%, #4a4e54 62%, #16171a 86%, transparent 100%);
}

*,
*::before,
*::after {
    box-sizing: border-box;
}

/* Hard black and grain. The body is the containing block of the darkness layer (.shelf-page::before). */
.blog-index-body {
    position: relative;
    margin: 0;
    min-height: 100vh;
    background: var(--grain), var(--pit);
    color: var(--bone);
    font-family: var(--font-body);
    font-size: 1.0625rem;
    line-height: 1.5;
}

.blog-index-body a {
    color: inherit;
}

.blog-index-body a:focus-visible {
    outline: 3px solid var(--hit);
    outline-offset: 4px;
}

/* No overflow clipping here: glows and the eclipse must be free to fade out on their own, never cut off by a box edge.
   Nothing in the column is wider than the column, so nothing scrolls sideways.
   Width (the user's calls, 2026-10-22 and -23): from 64rem up the page leaves 20% free at each end, so the column is
   60% of the viewport (the same breakpoint as the project skins' --blog-page-width in blog-components.css); below
   that it is the full width less a 1rem gutter. The covers scale with the viewport (--cover-size), so a cover and
   its notes still fit side by side in a 60% column at 1024px. */
.shelf-page {
    --cover-size: clamp(16rem, 20vw, 30rem);
    max-width: 76rem;
    margin: 0 auto;
    padding: 2rem 1rem 3rem;
}

@media (min-width: 64rem) {
    .shelf-page {
        max-width: 60vw;
    }
}

/* Darkness closing in, over the whole page behind everything: ash in the air, black pressing in from both sides and
   down from the top. */
.shelf-page::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background:
        var(--ash) 0 0 / 260px 260px,
        linear-gradient(90deg, rgb(0 0 0 / 0.9), transparent 24%, transparent 76%, rgb(0 0 0 / 0.9)),
        linear-gradient(180deg, rgb(0 0 0 / 0.7), transparent 12rem);
}

/* The closing chain, full width under the last release. "round" fits a whole number of links into the width (each
   stretched a little), and both ends taper off instead of stopping on a cut link. */
.shelf-page::after {
    content: "";
    display: block;
    height: 28px;
    margin-top: 3rem;
    background: var(--chain) 0 0 / 64px 28px round no-repeat;
    -webkit-mask: var(--rule-taper);
    mask: var(--rule-taper);
}

/* ---- Masthead: the band logo before a black sun. A column, so the iron band (::after) sits between the logo and
   the intro ---- */

.shelf-header {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-bottom: 4rem;
    text-align: center;
}

.shelf-header > .shelf-intro {
    order: 2;
}

.shelf-header > .shelf-title {
    align-self: stretch;
}

.shelf-home {
    font-size: 1.125rem;
    font-weight: 900;
    letter-spacing: 0.08em;
    text-decoration: none;
}

.blog-index-body .shelf-home {
    color: var(--steel);
}

.shelf-home:hover {
    color: var(--hit);
}

/* The black sun: an eclipse behind the spires and the logo. Its top edge sits just under the site link (the header's
   logo area starts 1.95rem down) and its foot ends behind the logo's letters, above the iron band and the intro, so
   the corona never crosses any readable text. */
.shelf-header::before {
    content: "";
    position: absolute;
    left: 50%;
    top: 1.95rem;
    z-index: -1;
    width: calc(1.6 * var(--logo-size));
    aspect-ratio: 1;
    border-radius: 50%;
    transform: translateX(-50%);
    background: radial-gradient(circle closest-side, #000 0 76%, var(--corona) 79%, rgb(226 228 232 / 0.25) 86%, transparent 100%);
    box-shadow: 0 0 5rem 1.5rem rgb(0 0 0 / 0.9), 0 0 9rem 3rem rgb(55 0 4 / 0.35);
    pointer-events: none;
}

/* The skull is the dark face of the moon, not a sticker on it. The same box as the black sun, painted after it:
   - a rim-lit skull photo (generated, blog-index-skull.webp, grey on black) SCREEN-blended, so its black drops out
     and only the bone adds light to the disc, and the page's grain and ash show through it;
   - cooled and dimmed by its filter to the corona's colour, the one light source in the scene, so it reads as lit
     by the eclipse rather than pasted in;
   - masked to a soft disc that is gone well before the corona, so the bone dissolves into the black at its edges.
   Index only (the not-found page has no skull). */
.black-sun-skull {
    position: absolute;
    left: 50%;
    top: 1.95rem;
    z-index: -1;
    width: calc(1.6 * var(--logo-size));
    aspect-ratio: 1;
    transform: translateX(-50%);
    background: url("blog-index-skull.webp") 50% 18% / 70% auto no-repeat;
    mix-blend-mode: screen;
    filter: brightness(0.7) contrast(1.3) sepia(0.25) hue-rotate(180deg) saturate(0.6);
    -webkit-mask: radial-gradient(circle closest-side at 50% 40%, #000 0 40%, rgb(0 0 0 / 0.5) 58%, transparent 72%);
    mask: radial-gradient(circle closest-side at 50% 40%, #000 0 40%, rgb(0 0 0 / 0.5) 58%, transparent 72%);
    pointer-events: none;
}

/* The logo: black capitals edged in blood red, standing at the foot of a skyline of black spires that rise 0.75em
   above it into the black sun. On the index the capitals are drawn (.shelf-title-letters); the not-found page sets
   its title in --font-logo with the same black fill and red edge. The letters paint over the spires. The dark red
   glows are small enough to fade out inside the free space around the logo, and nothing above clips overflow, so no
   glow is ever cut off. */
.shelf-title {
    position: relative;
    margin: calc(0.75 * var(--logo-size)) 0 0;
    font-family: var(--font-logo);
    font-size: var(--logo-size);
    font-weight: 800;
    line-height: 1;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    overflow-wrap: break-word;
    color: #0b0b0d;
    -webkit-text-stroke: 0.022em var(--hit);
    filter: drop-shadow(0 0 0.03em var(--rim-glow)) drop-shadow(0 0 0.16em var(--aura));
}

/* "BLOG", drawn: tall, condensed, hard-cut capitals with pointed spurs and notched stems, every edge a straight line.
   Cap height 300 of the viewBox's 362 units, so the drawing's height is 362/300 of the logo size. */
.shelf-title-letters {
    display: block;
    width: auto;
    height: calc(362 / 300 * 1em);
    margin: 0 auto;
    overflow: visible;
    fill: #0b0b0d;
    stroke: var(--hit);
    stroke-width: 6;
    stroke-linejoin: miter;
    stroke-miterlimit: 8;
}

/* Text for screen readers only (the drawn title's real text). */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* The spires, behind the letters (the title's filter makes it a stacking context, so -1 stays inside it). */
.shelf-title::before {
    content: "";
    position: absolute;
    left: 50%;
    bottom: 0.12em;
    z-index: -1;
    width: 4.2em;
    height: 1.6em;
    max-width: 100%;
    transform: translateX(-50%);
    background: var(--spires) 50% 100% / 100% 100% no-repeat;
}

/* The iron band: a flat riveted iron slab with a steel top edge. No spikes (the user's call). */
.shelf-header::after {
    content: "";
    order: 1;
    align-self: stretch;
    height: 18px;
    margin-top: 1.5rem;
    background: var(--iron-band) 0 0 / 200px 18px repeat-x;
}

.shelf-intro {
    max-width: 34em;
    margin: 1.25rem auto 0;
    font-size: clamp(1.25rem, 2.6vw, 1.625rem);
    font-weight: 900;
    line-height: 1.3;
    color: var(--bone);
    text-shadow: 0 2px 0 #000;
}

.shelf-empty {
    color: var(--bone-dim);
    text-align: center;
}

/* ---- The mist: fixed along the foot of the screen, behind everything. It is simulated, not drawn:
   blog-index-mist.js runs a small 2D fluid (advection and pressure projection on a coarse grid) in which mist is
   fed in along the floor, carried by a slowly turning wind of curl noise, rises a little and thins out as it goes up;
   the pointer pushes the fluid, so it physically shoves the mist aside and leaves swirls behind. The grid is drawn
   into the canvas at its own small resolution and scaled up softly by the browser. Without JS or canvas there is no
   mist, and the page is unchanged otherwise. ---- */

.mist {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: -1;
    /* The whole screen: the mist rises from the floor and may drift anywhere (the user, 2026-10-23). */
    top: 0;
    overflow: hidden;
    pointer-events: none;
}

/* The front layer floats over the page, half see-through, under the theme switch; clicks pass through it. */
.mist-front {
    z-index: 5;
    opacity: 0.5;
}

.mist-canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    filter: blur(5px);
}


/* ---- Releases: barbed wire between them; sides alternate ---- */

.shelf {
    margin: 0;
    padding: 0;
    list-style: none;
}

.release {
    display: grid;
    grid-template-columns: minmax(0, var(--cover-size)) minmax(0, 1fr);
    gap: 2rem clamp(1.5rem, 3vw, 3.5rem);
    align-items: center;
    position: relative;
    padding: 4.5rem 0 3rem;
}

/* The barbed wire over each release: a layer of its own so its ends can taper off (see the chain) without masking the
   release's content. */
.release::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: 40px;
    background: var(--wire) 0 0 / 120px 40px round no-repeat;
    -webkit-mask: var(--rule-taper);
    mask: var(--rule-taper);
    pointer-events: none;
}

.release:nth-child(even) {
    grid-template-columns: minmax(0, 1fr) minmax(0, var(--cover-size));
}

.release:nth-child(even) .plate {
    order: 2;
}

.release:nth-child(even) .plate-label {
    text-align: right;
}

.release:nth-child(even) .plate-label-summary,
.release:nth-child(even) .plate-label-sections {
    margin-left: auto;
}

/* The cover: the project's own plate tokens in an iron bevel, four rivets, a printed-grain overlay. Drained of colour
   until pointed at or focused; the contrast lift keeps its own text (the kind label in particular) above 4.5:1. */
.plate {
    --plate-paper: var(--cover-paper);
    --plate-ink: var(--cover-ink);
    --plate-accent: var(--cover-accent);
    --plate-font: var(--font-body);
    position: relative;
    container-type: inline-size;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    aspect-ratio: 1 / 1;
    padding: 2.25rem 1.75rem 2.5rem;
    overflow: hidden;
    border: 12px solid transparent;
    border-image: linear-gradient(135deg, #e9ecef, #6d737a 22%, #1d1f22 45%, #a3a9b0 62%, #2b2e32 82%, #c9cdd2) 1;
    background: var(--plate-paper);
    box-shadow:
        inset 0 0 0 1px rgb(0 0 0 / 0.6),
        0 0 0 2px #000,
        0.6rem 0.6rem 0 #000;
    color: var(--plate-ink);
    text-decoration: none;
    filter: grayscale(0.9) brightness(0.9) contrast(1.15);
    transition: box-shadow 160ms ease-out, transform 160ms ease-out, filter 400ms ease-out;
}

/* The plate is stacked in four layers: the project's preview picture (if any), then this layer (the four rivets, the
   accent bar along the foot, and the paper colour rising from the foot so the name and tagline always sit on the
   project's own paper), then the text, then the printed grain (::after). Without a preview the plate is plain paper. */
.plate-preview {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Keep the top of the picture when a wide (phone) plate crops it: the foot is under the name anyway. */
    object-position: 50% 0;
}

.plate::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    background:
        var(--rivet) 6px 6px / 16px 16px no-repeat,
        var(--rivet) calc(100% - 6px) 6px / 16px 16px no-repeat,
        var(--rivet) 6px calc(100% - 0.9rem - 6px) / 16px 16px no-repeat,
        var(--rivet) calc(100% - 6px) calc(100% - 0.9rem - 6px) / 16px 16px no-repeat,
        linear-gradient(var(--plate-accent), var(--plate-accent)) 0 100% / 100% 0.9rem no-repeat,
        linear-gradient(0deg, var(--plate-paper) 0 34%, transparent 70%);
    pointer-events: none;
}

.plate::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 3;
    background: var(--grain);
    opacity: 0.35;
    mix-blend-mode: overlay;
    pointer-events: none;
}

.blog-index-body .plate {
    color: var(--plate-ink);
}

.plate:hover,
.plate:focus-visible {
    filter: none;
}

.plate:hover {
    transform: rotate(-1.5deg) scale(1.02);
    box-shadow:
        inset 0 0 0 1px rgb(0 0 0 / 0.6),
        0 0 0 3px var(--hit),
        0 0 3rem 0.5rem var(--aura);
}

/* The kind label sits on a chip of the plate's paper, so it reads the same over any preview. */
.plate-kind {
    position: absolute;
    top: 2rem;
    left: 1.75rem;
    z-index: 2;
    padding: 0.1rem 0.45rem;
    background: var(--plate-paper);
    font-family: var(--font-body);
    font-size: 0.9375rem;
    font-weight: 900;
    letter-spacing: 0.06em;
    color: var(--plate-accent);
}

.plate-name {
    position: relative;
    z-index: 2;
    font-family: var(--plate-font);
    /* Sized to the cover, not the viewport, so a long name still fits on one line. */
    font-size: clamp(1.75rem, 14cqi, 3.75rem);
    font-weight: 800;
    line-height: 0.95;
    letter-spacing: -0.01em;
    overflow-wrap: break-word;
}

.plate-tagline {
    position: relative;
    z-index: 2;
    margin-top: 0.75rem;
    font-family: var(--font-body);
    font-size: 1rem;
    font-weight: 700;
    line-height: 1.3;
    max-width: 22em;
}

/* ---- Liner notes ---- */

.plate-label {
    min-width: 0;
}

/* The release name in the logo face's capitals: bone, a hard black shadow over a dried-blood one. */
.plate-label-name {
    margin: 0;
    font-family: var(--font-logo);
    font-size: clamp(2.5rem, 6.5vw, 5rem);
    font-weight: 800;
    line-height: 1;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    overflow-wrap: break-word;
    text-shadow: 0.04em 0.04em 0 #000, 0.08em 0.08em 0 var(--gore);
}

.plate-label-name a {
    text-decoration: none;
}

.plate-label-name a:hover {
    color: var(--hit);
}

.plate-label-summary {
    max-width: 34em;
    margin: 1.25rem 0 0;
    font-size: 1.25rem;
    line-height: 1.45;
    text-shadow: 0 1px 0 #000;
}

/* The track list: heavy iron rows, each led by a steel blade that grows on hover. */
.plate-label-sections {
    max-width: 28rem;
    margin: 2rem 0 0;
    padding: 0;
    list-style: none;
}

.plate-label-sections li + li {
    margin-top: 0.5rem;
}

.plate-label-sections a {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem 1rem;
    border: 2px solid var(--steel-dark);
    background: linear-gradient(180deg, rgb(255 255 255 / 0.08), rgb(0 0 0 / 0.5)), #0c0c0d;
    box-shadow: 0.3rem 0.3rem 0 #000;
    font-size: 1.625rem;
    font-weight: 900;
    line-height: 1.15;
    text-decoration: none;
    transition: border-color 120ms linear, box-shadow 120ms linear;
}

.release:nth-child(even) .plate-label-sections a {
    flex-direction: row-reverse;
}

.plate-label-sections a::before {
    content: "";
    flex: none;
    width: 1.4rem;
    height: 0.75rem;
    background: linear-gradient(90deg, var(--blade));
    clip-path: polygon(0 0, 100% 50%, 0 100%, 22% 50%);
    transition: width 120ms linear;
}

.release:nth-child(even) .plate-label-sections a::before {
    background: linear-gradient(270deg, var(--blade));
    clip-path: polygon(100% 0, 0 50%, 100% 100%, 78% 50%);
}

.plate-label-sections a:hover {
    border-color: var(--hit);
    box-shadow: 0.3rem 0.3rem 0 #000, 0 0 1.25rem var(--aura);
    color: var(--hit);
}

.plate-label-sections a:hover::before {
    width: 2.4rem;
}

/* ---- Phones: notes under the cover, everything left-aligned ---- */

@media (max-width: 760px) {
    .shelf-page {
        padding-top: 1.25rem;
    }

    .shelf-header {
        margin-bottom: 2.5rem;
    }

    .release,
    .release:nth-child(even) {
        grid-template-columns: minmax(0, 1fr);
        padding: 3.75rem 0 2rem;
    }

    .release:nth-child(even) .plate {
        order: 0;
    }

    .release:nth-child(even) .plate-label {
        text-align: left;
    }

    .release:nth-child(even) .plate-label-sections a {
        flex-direction: row;
    }

    .release:nth-child(even) .plate-label-sections a::before {
        background: linear-gradient(90deg, var(--blade));
        clip-path: polygon(0 0, 100% 50%, 0 100%, 22% 50%);
    }

    .plate {
        aspect-ratio: 4 / 3;
        padding: 2rem 1.5rem 2.25rem;
    }

    .plate-kind {
        top: 1.6rem;
        left: 1.5rem;
    }
}

/* ==== The theme switch ====
   One control for both themes (blog-index-theme.js): a pill fixed top right, a skull on the left (the default shadow
   theme) and a striped setting sun on the right (synthwave). A sliding plate sits under the icon of the active theme.
   It is a role="switch" button named "Synthwave theme", hidden until the script runs, so it never shows dead. */

/* The knob's travel is derived from the same sizes as the icon slots, so it lands exactly on the sun (the old fixed
   2.25rem ignored the padding of a content-box switch and stopped short). */
.theme-switch {
    --switch-width: 4.75rem;
    --switch-padding: 0.35rem;
    --switch-border: 1px;
    --switch-slot: 1.8rem;
    position: fixed;
    top: 0.75rem;
    right: 0.75rem;
    z-index: 10;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: var(--switch-width);
    height: 2.5rem;
    padding: 0 var(--switch-padding);
    border: var(--switch-border) solid var(--steel-dark);
    border-radius: 999px;
    background: rgb(10 10 12 / 0.85);
    box-shadow: 0 0 0 1px #000, 0 0.4rem 1rem rgb(0 0 0 / 0.6);
    cursor: pointer;
}

.theme-switch[hidden] {
    display: none;
}

.theme-switch:focus-visible {
    outline: 3px solid var(--hit);
    outline-offset: 3px;
}

.theme-switch-icon {
    position: relative;
    z-index: 1;
    display: grid;
    place-items: center;
    width: var(--switch-slot);
    height: var(--switch-slot);
    color: #6f6a72;
    transition: color 200ms ease-out;
}

.theme-switch-icon svg {
    width: 1.15rem;
    height: 1.15rem;
    fill: currentColor;
}

.theme-switch-knob {
    position: absolute;
    top: 50%;
    left: var(--switch-padding);
    width: var(--switch-slot);
    height: var(--switch-slot);
    border-radius: 50%;
    background: radial-gradient(circle at 35% 30%, #4a4d53, #17181b 70%);
    box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.12), 0 0 0.6rem var(--aura);
    transform: translate(0, -50%);
    transition: transform 220ms ease-out, background 220ms ease-out, box-shadow 220ms ease-out;
}

.theme-switch[aria-checked="false"] .theme-switch-skull,
.theme-switch[aria-checked="true"] .theme-switch-sun {
    color: var(--bone);
}

.theme-switch[aria-checked="true"] .theme-switch-knob {
    transform: translate(calc(var(--switch-width) - 2 * var(--switch-padding) - 2 * var(--switch-border) - var(--switch-slot)), -50%);
}

/* The synthwave floor: a neon grid on a tilted plane that runs toward the viewer, inside the mist's fixed box (so it
   pauses with the mist when the tab is hidden). Shown only in the synthwave theme. The grid is a pseudo-element one tile taller than its box that
   slides by one tile with a transform, so the loop is seamless and costs no repaint. */
.mist-grid {
    position: absolute;
    inset: auto 0 0;
    height: clamp(14rem, 45vh, 26rem);
    display: none;
    overflow: hidden;
    perspective: 18rem;
    perspective-origin: 50% 0;
    -webkit-mask: linear-gradient(180deg, transparent 0, #000 35%);
    mask: linear-gradient(180deg, transparent 0, #000 35%);
}

.mist-grid::before {
    --grid-tile: 64px;
    content: "";
    position: absolute;
    left: -60%;
    right: -60%;
    top: 0;
    height: calc(260% + var(--grid-tile));
    transform-origin: 50% 0;
    background:
        repeating-linear-gradient(90deg, rgb(255 61 154 / 0.75) 0 2px, transparent 2px var(--grid-tile)),
        repeating-linear-gradient(0deg, rgb(45 226 245 / 0.55) 0 2px, transparent 2px var(--grid-tile));
    /* One tile every 0.45s: the floor rushes toward the viewer, as if driving forward fast. */
    animation: grid-run 0.45s linear infinite;
    will-change: transform;
}

@keyframes grid-run {
    from {
        transform: rotateX(68deg) translateY(calc(-1 * var(--grid-tile)));
    }

    to {
        transform: rotateX(68deg) translateY(0);
    }
}

.mist.is-paused .mist-grid::before {
    animation-play-state: paused;
}

/* ==== Theme: synthwave (the default) ====
   The theme the server renders unless the theme cookie says shadow (data-theme on <html>, BlogIndexThemeCookie): a
   1980s neon night. It restyles in place everything the shadow theme above draws (the same markup, the same layers);
   this block only overrides. A violet night sky with stars, a striped setting sun where the black sun was (the skull's
   layer becomes the sun's glow), neon mountains where the spires were, "BLOG" in night-violet edged in cyan and
   leaning forward, neon rules for the iron band and barbed wire, a racing stripe where the chain was, covers in full
   colour, and a running neon grid where the mist was.
   Text: --bone 15.6:1 on the darkest sky, --bone-dim 10.9:1, --hit (cyan, focus and hover) 11.6:1. */

:root[data-theme="synthwave"] {
    --pit: #120326;
    --bone: #f3e9ff;
    --bone-dim: #d3c2ea;
    --steel: #9fe3ef;
    --steel-dark: #5b2a8c;
    --hit: #2de2f5;
    --gore: #ff3d9a;
    --aura: rgb(255 61 154 / 0.7);
    --rim-glow: rgb(45 226 245 / 0.9);
    --blade: #ffe36b, #ff3d9a 55%, #7a2bd6;
    --spires: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1050 400' preserveAspectRatio='none'%3E%3Cpolygon fill='%23160433' stroke='%23ff3d9a' stroke-width='4' stroke-linejoin='miter' points='0,400 0,330 90,250 170,310 260,190 340,280 420,150 525,40 630,150 710,280 790,190 880,310 960,250 1050,330 1050,400'/%3E%3Cpolyline fill='none' stroke='%232de2f5' stroke-width='2.5' points='0,372 120,334 240,362 400,302 525,250 650,302 810,362 930,334 1050,372'/%3E%3Cpath fill='none' stroke='%23ff3d9a' stroke-opacity='.5' stroke-width='2' d='M260 190L300 300M790 190L750 300'/%3E%3C/svg%3E");
    --iron-band: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='18'%3E%3Crect width='200' height='18' fill='%23160433'/%3E%3Crect width='200' height='3' fill='%23ff3d9a'/%3E%3Crect y='15' width='200' height='3' fill='%232de2f5'/%3E%3C/svg%3E");
    --wire: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='40'%3E%3Crect y='17' width='120' height='3' fill='%23ff3d9a'/%3E%3Crect y='22' width='120' height='1.5' fill='%232de2f5'/%3E%3C/svg%3E");
    /* The footer is not a chain here: an 80s racing stripe, four bands from yellow to violet, thinning downward and
       cut into slanted segments, so it reads as speed. */
    --chain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='28'%3E%3Cpolygon points='10,2 64,2 59.2,8 5.2,8' fill='%23ffe36b'/%3E%3Cpolygon points='3.6,10 57.6,10 53.6,15 -0.4,15' fill='%23ff9e3d'/%3E%3Cg fill='%23ff3d9a'%3E%3Cpolygon points='-2,17 52,17 48.8,21 -5.2,21'/%3E%3Cpolygon points='62,17 66,17 66,21 58.8,21'/%3E%3C/g%3E%3Cg fill='%239b3dff'%3E%3Cpolygon points='-6.8,23 47.2,23 44.8,26 -9.2,26'/%3E%3Cpolygon points='57.2,23 66,23 66,26 54.8,26'/%3E%3C/g%3E%3C/svg%3E");
}

:root[data-theme="synthwave"] .blog-index-body {
    background: var(--grain), linear-gradient(180deg, #0b0220 0%, #1d0638 55%, #2b0a4a 100%);
}

/* Stars only: no dark band down the sides (the user's call). */
:root[data-theme="synthwave"] .shelf-page::before {
    background: var(--ash) 0 0 / 260px 260px;
}

/* The setting sun: yellow to hot pink, solid at the crown and cut into stripes from a third of the way down, so the
   stripes show above the mountains. */
:root[data-theme="synthwave"] .shelf-header::before {
    background: linear-gradient(180deg, #ffe36b 0%, #ffab3d 30%, #ff3d9a 62%, #c4167a 100%);
    box-shadow: none;
    -webkit-mask:
        linear-gradient(#000 0 30%, transparent 30%),
        repeating-linear-gradient(180deg, #000 0 4.5%, transparent 4.5% 7%);
    mask:
        linear-gradient(#000 0 30%, transparent 30%),
        repeating-linear-gradient(180deg, #000 0 4.5%, transparent 4.5% 7%);
}

/* The skull's layer becomes the sun's glow (the mask on the sun would cut a glow of its own). */
:root[data-theme="synthwave"] .black-sun-skull {
    background: radial-gradient(circle closest-side, rgb(255 61 154 / 0.45), rgb(255 61 154 / 0.15) 60%, transparent 100%);
    mix-blend-mode: normal;
    filter: none;
    -webkit-mask: none;
    mask: none;
    transform: translateX(-50%) scale(1.45);
}

:root[data-theme="synthwave"] .shelf-title-letters {
    fill: #160433;
    transform: skewX(-8deg);
}

/* The grid is the synthwave floor; the mist is not drawn there (the script also stops simulating it). */
:root[data-theme="synthwave"] .mist-canvas {
    display: none;
}

:root[data-theme="synthwave"] .mist-grid {
    display: block;
}

:root[data-theme="synthwave"] .plate {
    filter: none;
}

:root[data-theme="synthwave"] .plate-label-name {
    font-style: italic;
}

:root[data-theme="synthwave"] .plate-label-sections a {
    background: linear-gradient(180deg, rgb(255 255 255 / 0.06), rgb(0 0 0 / 0.35)), #1d0838;
}

:root[data-theme="synthwave"] .theme-switch {
    background: rgb(22 4 51 / 0.85);
}

:root[data-theme="synthwave"] .theme-switch-knob {
    background: radial-gradient(circle at 35% 30%, #ff7bbd, #6a1a8c 75%);
}

/* Windows high contrast: plain logo, no decorative layers. */
@media (forced-colors: active) {
    .shelf-title {
        background: none;
        -webkit-text-fill-color: CanvasText;
        -webkit-text-stroke: 0;
        filter: none;
    }

    .shelf-title-letters {
        fill: CanvasText;
        stroke: none;
    }

    .shelf-page::before,
    .shelf-header::before,
    .shelf-title::before,
    .black-sun-skull,
    .mist {
        display: none;
    }
}

/* Motion is deliberate: the mist, the grid and the hovers always animate, prefers-reduced-motion included (the user's
   ruling, 2026-10-22). Only a hidden tab pauses them. */
