/* A published site page: the page FRAME, the BANDS, and what a page wants
 * differently from the block vocabulary /article.css carries. Served, never
 * bundled: a baked site page links it with no SPA.
 *
 * Reads the `--sp-*` palette, which /article.css defines — a document linking
 * this sheet links that one too, and loads it FIRST, which is what lets a rule
 * here override one there at equal specificity. The three band grounds that
 * palette does not carry are defined here, since a band ground belongs to this
 * sheet. */

:root,
:root.light {
  --sp-warm: #a16207;
  --sp-ink: #1c1c1e;
  --sp-ink-fg: #f5f3ef;
  /* What reads on `--sp-primary`. One value for both themes, but named here so
     the CTA states it rather than spelling a colour. */
  --sp-primary-fg: #ffffff;
}
:root.dark {
  --sp-warm: #f5b14c;
  --sp-ink: #101012;
  --sp-ink-fg: #ece9e4;
}
@media (prefers-color-scheme: dark) {
  :root:not(.light):not(.dark) {
    --sp-warm: #f5b14c;
    --sp-ink: #101012;
    --sp-ink-fg: #ece9e4;
  }
}

/* This sheet is delivered to hosts with a CSS reset and hosts without one, so
 * its own boxes declare how they are measured rather than inheriting an answer.
 * Border-box is what the SPA's own front page measures its bands in, so all
 * three surfaces put the band measure in the same place. */
[class^="sp-site"],
[class*=" sp-site"] {
  box-sizing: border-box;
}

/* A baked page loads no framework reset, so the keyboard-focus ring is this
 * sheet's own — drawn on :focus-visible alone, so a pointer press never shows
 * one. `--sp-site-ring` is what a ground retunes when the site accent has
 * nothing to sit against. */
[class^="sp-site"]:focus-visible,
[class*=" sp-site"]:focus-visible,
.sp-site-prose a:focus-visible {
  outline: 1.5px solid var(--sp-site-ring, color-mix(in oklab, var(--sp-primary) 65%, transparent));
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  [class^="sp-site"],
  [class*=" sp-site"] {
    transition: none !important;
  }
}

/* A site page's own ground. `body.sp-site` is the BAKED document — the SPA
 * styles its own shell — and the bare class is the same ground on a canvas
 * inside another app, which is how the editor renders a page as published. */
body.sp-site {
  margin: 0;
}
body.sp-site,
.sp-site {
  background: var(--sp-bg);
  color: var(--sp-fg);
  font-family: var(--sp-sans, var(--font-sans, ui-sans-serif, system-ui, sans-serif));
}

/* ── The page frame ────────────────────────────────────────────────────────
 * A baked page draws the site's authored chrome where the SPA shell draws it:
 * the sidebar as the column beside the document, and the document's own column
 * holding the flow and the footer — so the footer stands BESIDE the sidebar,
 * never under it. The SPA gives its own sidebar column `.sp-site-aside` too, so
 * the measure inside it is one rule rather than a second vocabulary. */

.sp-site-frame {
  display: flex;
  align-items: stretch;
}
.sp-site-column {
  display: flex;
  flex-direction: column;
  flex: 1 1 0;
  min-width: 0;
}
.sp-site-main {
  min-width: 0;
}
.sp-site-aside {
  min-width: 0;
}
.sp-site-frame > .sp-site-aside {
  flex: 0 0 14rem;
  padding-inline: 0.875rem;
  border-inline-end: 1px solid var(--sp-border);
}
/* The SPA stacks its own chrome below `md`, so the baked page does too rather
   than squeezing a column the reader would not draw. */
@media (max-width: 48rem) {
  .sp-site-frame {
    display: block;
  }
  .sp-site-frame > .sp-site-aside {
    border-inline-end: none;
    border-block-end: 1px solid var(--sp-border);
  }
}
/* A column, not a page: its content takes the column's width, and the column
   itself supplies the horizontal inset. */
.sp-site-aside .sp-site-band-inner {
  max-width: none;
  padding: 0.75rem 0;
}

.sp-site-prose > :first-child {
  margin-top: 0;
}
.sp-site-prose > :last-child {
  margin-bottom: 0;
}
.sp-site-prose h2 {
  font-family: var(--sp-serif, var(--font-serif, Georgia, serif));
  font-size: 1.25rem;
  font-weight: 600;
  margin: 1.25rem 0 0.5rem;
}
.sp-site-prose p {
  margin: 0.75rem 0;
  line-height: 1.6;
}
.sp-site-prose a {
  text-decoration: underline;
}
.sp-site-prose ul,
.sp-site-prose ol {
  margin: 0.75rem 0;
  padding-inline-start: 1.5rem;
  list-style: revert;
}
/* ── What a PAGE wants differently ─────────────────────────────────────────
 * The block markup and its rules are /article.css's, one per kind. Everything
 * below states a page's own answer to a rule that sheet already carries; a
 * block absent from here reads on a page exactly as it reads in an article. */

/* A page sets its prose sans and at the page's own size, so the article's
 * serif measure does not follow the markup onto a band. */
.sp-site-prose blockquote,
.sp-site-prose .emphasis,
.sp-site-prose aside.factbox {
  font-size: 1rem;
  line-height: 1.6;
}
/* No lightbox on a page: the picture is not clickable, so it must not offer to
 * be. */
.sp-site-prose figure img {
  max-height: none;
  cursor: auto;
}
.sp-site-prose figure img:hover {
  transform: none;
}
.sp-site-prose figcaption {
  text-align: start;
  font-size: 0.8125rem;
  opacity: 0.7;
}

/* ── Bands ────────────────────────────────────────────────────────────────
 * One section per band, each on its own ground, sharing one measure. Live
 * bands mount an Alpine island inside this same markup (/site.js), so a band's
 * shape does not depend on whether its content arrived yet. */

/* A STRIP is only a ground; a BAND is a ground plus its own measure. Both paint
 * the same way, so a widget reads the same standing on a strip and standing
 * alone. */
.sp-site-band,
.sp-site-strip {
  background: var(--sp-band-ground, var(--sp-bg));
  color: var(--sp-band-ink, inherit);
  font-family: var(--sp-sans, var(--font-sans, ui-sans-serif, system-ui, sans-serif));
}

/* THE BUILT-IN GROUNDS — the eight entries a site's palette seeds with, one rule
 * each. The generated `data/site.css` loads after this sheet, so a retuned entry
 * wins and one carrying no colours of its own falls through to here.
 *
 * Every entry is a LIGHT/DARK PAIR: the first
 * four ride the theme's own tokens, the tinted three state the pair with
 * `light-dark()` (the theme blocks above declare `color-scheme`, which is what
 * resolves it).
 *
 * A pair stays on the SAME SIDE as the page, so the page's own text and muted
 * colours keep reading on it and an entry needs nothing but its ground. `ink`
 * is the one that INVERTS, and it retunes what inverting costs — the ink, the
 * dim every muted part takes, the row rule and the focus ring — right here, so
 * the markup carries no marker and nothing above this sheet knows a ground is
 * dark. */
.sp-site-band-plain {
  --sp-band-ground: var(--sp-bg);
}
.sp-site-band-surface {
  --sp-band-ground: var(--sp-surface);
}
.sp-site-band-cool {
  --sp-band-ground: color-mix(in srgb, var(--sp-primary) 7%, var(--sp-bg));
}
.sp-site-band-warm {
  --sp-band-ground: color-mix(in srgb, var(--sp-warm) 9%, var(--sp-bg));
}
.sp-site-band-sage {
  --sp-band-ground: light-dark(#e8efe6, #1b241d);
}
.sp-site-band-rose {
  --sp-band-ground: light-dark(#f6e9e9, #271b1d);
}
.sp-site-band-plum {
  --sp-band-ground: light-dark(#eee9f4, #221d2b);
}
.sp-site-band-ink {
  --sp-band-ground: var(--sp-ink);
  --sp-band-ink: var(--sp-ink-fg);
  --sp-band-ink-dim: 0.7;
  --sp-band-rule: color-mix(in srgb, currentcolor 20%, transparent);
  --sp-site-ring: color-mix(in oklab, currentcolor 60%, transparent);
}

.sp-site-band-inner {
  max-width: 64rem;
  margin: 0 auto;
  padding: 1.75rem 1.5rem;
}
/* A STRIP carries the measure so its ground stays full width: what stands on
   one is already at that measure and inside its inset, so its own inner adds
   neither, and stacked contents keep their rhythm between them instead. */
.sp-site-band-inner .sp-site-band-inner {
  max-width: none;
  padding: 0;
}
.sp-site-band-inner
  > :is(.sp-site-band, .sp-site-band-inner)
  + :is(.sp-site-band, .sp-site-band-inner) {
  margin-block-start: 1.75rem;
}
.sp-site-band-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 1rem;
}
/* The head row's own LINE takes this whether or not it carries the class: an
 * EDITING surface stands an authored text block in the row, and that element
 * follows the block's own setting, not this sheet's. */
.sp-site-band-title,
.sp-site-band-head > :is(h1, h2, h3, p) {
  margin: 0;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--sp-band-ink, var(--sp-muted));
  opacity: var(--sp-band-ink-dim, 1);
}
.sp-site-more {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  flex-shrink: 0;
  border-radius: 0.25rem;
  font-size: 0.875rem;
  color: var(--sp-band-ink, var(--sp-muted));
  opacity: var(--sp-band-ink-dim, 1);
  text-decoration: none;
  transition:
    color 150ms ease,
    opacity 150ms ease;
}
@media (hover: hover) {
  .sp-site-more:hover {
    color: var(--sp-band-ink, var(--sp-fg));
    --sp-band-ink-dim: 1;
  }
}
.sp-site-center {
  text-align: center;
}

/* ── Shared card parts ───────────────────────────────────────────────────── */

/* The cover is its own frame: the hairline and the drop shadow are one
   box-shadow, so a hover retunes either without a wrapper element. */
.sp-site-cover {
  display: block;
  width: 100%;
  aspect-ratio: 210 / 276;
  object-fit: cover;
  border-radius: 0.25rem;
  background: var(--sp-muted-bg);
  box-shadow:
    0 0 0 1px var(--sp-cover-ring, var(--sp-border)),
    var(--sp-cover-shadow, 0 6px 14px -6px rgb(0 0 0 / 0.28));
  transition:
    box-shadow 200ms ease,
    translate 200ms ease,
    scale 260ms ease;
}
/* A special issue carries a warm hairline wherever this band lists it. */
.sp-site-wide-card .sp-site-cover {
  --sp-cover-ring: color-mix(in srgb, var(--sp-warm) 55%, transparent);
}
@media (hover: hover) {
  :is(.sp-site-issue-card, .sp-site-cover-link, .sp-site-wide-card):hover .sp-site-cover {
    --sp-cover-shadow: 0 16px 30px -10px rgb(0 0 0 / 0.45);
    translate: 0 -2px;
    scale: 1.02;
  }
}
.sp-site-cover-blank {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  text-align: center;
  font-family: var(--sp-serif, var(--font-serif, Georgia, serif));
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--sp-muted);
}
.sp-site-card-title {
  display: block;
  margin-top: 0.5rem;
  font-size: 0.875rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sp-site-card-title-lg {
  font-family: var(--sp-serif, var(--font-serif, Georgia, serif));
  font-size: 1.125rem;
  line-height: 1.35;
  white-space: normal;
  text-wrap: balance;
}
.sp-site-card-meta {
  display: block;
  font-size: 0.75rem;
  color: var(--sp-band-ink, var(--sp-muted));
  opacity: var(--sp-band-ink-dim, 1);
}
.sp-site-kicker {
  display: block;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--sp-primary);
}
.sp-site-badge {
  align-self: start;
  border: 1px solid color-mix(in srgb, var(--sp-warm) 45%, transparent);
  background: color-mix(in srgb, var(--sp-warm) 12%, transparent);
  border-radius: 9999px;
  padding: 0.125rem 0.5rem;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--sp-warm);
}
.sp-site-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  border: 1px solid var(--sp-primary);
  border-radius: 9999px;
  background: var(--sp-primary);
  padding: 0.375rem 0.75rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--sp-primary-fg);
  text-decoration: none;
  transition: filter 150ms ease;
}
@media (hover: hover) {
  .sp-site-cta:hover {
    filter: brightness(1.1);
  }
}
/* An inline icon takes the line's own size and colour. */
.sp-site-icon {
  flex-shrink: 0;
  width: 1em;
  height: 1em;
}

/* A card anchor carries no link colour of its own. `:where` so this costs no
   specificity: a named part — the more link, the CTA, the rail end — states its
   own colour and must win over the reset. */
:where(.sp-site-band, .sp-site-strip) a {
  color: inherit;
  text-decoration: none;
}
:where(.sp-site-band, .sp-site-strip) .sp-site-prose a {
  color: inherit;
  text-decoration: underline;
}

/* ── latest_issue ────────────────────────────────────────────────────────── */

.sp-site-hero {
  display: grid;
  gap: 1.5rem;
}
/* The cover is this band's subject, so it takes the wider half of the split and
   the lead image beside it is trimmed to suit — the cover then stands taller
   than the photo, which is what makes it read as the artefact. */
@media (min-width: 40rem) {
  .sp-site-hero {
    grid-template-columns: 5fr 6fr;
    gap: 2rem;
  }
}
/* The cover column is a stack, so the CTA and the issue's meta line take their
   spacing from it rather than each carrying a margin of its own. */
.sp-site-hero-cover {
  display: grid;
  align-content: start;
  gap: 0.75rem;
}
.sp-site-cover-link {
  display: block;
  border-radius: 0.25rem;
}
.sp-site-hero-body {
  display: grid;
  align-items: start;
  gap: 1.5rem;
  min-width: 0;
}
@media (min-width: 75rem) {
  /* The body splits into two, so the cover keeps its share of the whole rather
     than of the half the lead now stands in. */
  .sp-site-hero {
    grid-template-columns: calc(31% - 1rem) 1fr;
  }
  .sp-site-hero-body {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
    gap: 2rem;
  }
}
/* The list bleeds its first row's padding the way a row bleeds its inline one,
   so the row's thumb starts level with the lead image beside it. */
.sp-site-hero-body > .sp-site-rows {
  margin-block-start: -0.75rem;
}

.sp-site-lead {
  display: block;
  min-width: 0;
  border-radius: 0.5rem;
}
.sp-site-lead-image {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 0.5rem;
  background: var(--sp-muted-bg);
  margin-bottom: 0.75rem;
}
.sp-site-lead-title {
  display: block;
  margin-top: 0.25rem;
  font-family: var(--sp-serif, var(--font-serif, Georgia, serif));
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.2;
  text-wrap: balance;
}
/* Clamped: a blurb is a teaser on every surface that lists one, and an
   unclamped one pushes the card's own meta line out of the fold. */
.sp-site-lead-blurb {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  overflow: hidden;
  margin-top: 0.5rem;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--sp-band-ink, var(--sp-muted));
  opacity: var(--sp-band-ink-dim, 1);
}
.sp-site-lead > .sp-site-card-meta {
  margin-top: 0.5rem;
}

/* ── The per-entry save toggle ────────────────────────────────────────────
   The button stands BESIDE the card's own `<a>` (a button inside an anchor is
   invalid), so the card is wrapped and the wrapper is what positions it. */

.sp-site-savewrap {
  position: relative;
  min-width: 0;
}
.sp-site-savewrap > .sp-site-row {
  padding-inline-end: 3.25rem;
}
.sp-site-save {
  position: absolute;
  inset-block-start: 0.375rem;
  inset-inline-end: 0.375rem;
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 0.375rem;
  background: none;
  color: var(--sp-band-ink, var(--sp-muted));
  cursor: pointer;
  transition:
    color 0.15s,
    background-color 0.15s,
    border-color 0.15s;
}
.sp-site-save:hover {
  border-color: var(--sp-border);
  background: var(--sp-surface);
  color: var(--sp-band-ink, var(--sp-fg));
}
.sp-site-save[aria-pressed="true"] {
  color: var(--sp-primary);
}
.sp-site-save[aria-pressed="true"] svg {
  fill: currentcolor;
}
.sp-site-save .sp-site-icon {
  width: 1rem;
  height: 1rem;
}

/* ── Rows (article teasers, post list) ───────────────────────────────────── */

.sp-site-rows {
  margin: 0;
  padding: 0;
  list-style: none;
  min-width: 0;
}
.sp-site-rows > li + li {
  border-top: 1px solid var(--sp-band-rule, var(--sp-border));
}
/* A list may END in the way out of it, and that link is the row after the last
   teaser: it takes the rows' own vertical rhythm rather than the head row's. */
.sp-site-rows > li > .sp-site-more {
  padding-block: 0.75rem;
}
/* The row bleeds its own inline padding past the list, so the hover ground is
   wider than the text while the rules between rows stay flush with it. */
.sp-site-row {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  margin-inline: -0.75rem;
  padding: 0.75rem;
  border-radius: 0.375rem;
  transition: background-color 150ms ease;
}
@media (hover: hover) {
  .sp-site-row:hover {
    background: color-mix(in srgb, currentcolor 7%, transparent);
  }
}
.sp-site-thumb {
  flex-shrink: 0;
  width: 3.5rem;
  height: 3.5rem;
  object-fit: cover;
  border-radius: 0.25rem;
  background: var(--sp-muted-bg);
}
.sp-site-row-body {
  min-width: 0;
}
.sp-site-row-title {
  display: block;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.35;
}
.sp-site-row-body > .sp-site-card-meta {
  margin-top: 0.125rem;
}

/* ── podcast ─────────────────────────────────────────────────────────────── */

/* Flex, not a grid: the show column hides itself when the feed named neither
   artwork nor a blurb, and the episode list then takes the whole measure. */
.sp-site-podcast {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
}
.sp-site-podcast-show {
  flex: 0 0 auto;
  width: 8rem;
}
.sp-site-podcast-show:not(:has(img, p)) {
  display: none;
}
.sp-site-podcast > .sp-site-rows {
  flex: 1 1 18rem;
}
@media (min-width: 40rem) {
  .sp-site-podcast-show {
    width: 11rem;
  }
}
.sp-site-podcast-art {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 0.5rem;
  background: var(--sp-muted-bg);
}
.sp-site-podcast-about {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  overflow: hidden;
  margin: 0.75rem 0 0;
  font-size: 0.75rem;
  line-height: 1.6;
  color: var(--sp-band-ink, var(--sp-muted));
  opacity: var(--sp-band-ink-dim, 1);
}

/* ── post_list ───────────────────────────────────────────────────────────── */

.sp-site-split {
  display: grid;
  gap: 1.5rem;
}
@media (min-width: 64rem) {
  .sp-site-split {
    grid-template-columns: 1.15fr 1fr;
  }
}
.sp-site-split > .sp-site-savewrap {
  border: 1px solid var(--sp-border);
  border-radius: 0.75rem;
  background: var(--sp-surface);
  padding: 1rem;
  box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
  transition: box-shadow 200ms ease;
}
@media (hover: hover) {
  .sp-site-split > .sp-site-savewrap:hover {
    box-shadow: 0 8px 20px -8px rgb(0 0 0 / 0.28);
  }
}

/* ── Rails (issue_rail, specials) ────────────────────────────────────────── */

/* A rail scrolls, so its edges say so: each one fades out exactly the card that
   edge CUTS, never one standing whole. The MASK is this sheet's; how much of a
   cut card is left is measured in /site.js wherever the markup can run JS. */
@property --sp-rail-fade {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}
@property --sp-rail-fade-start {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}
@property --sp-rail-fade-end {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}

.sp-site-rail {
  --sp-rail-fade: 2.5rem;
  --sp-rail-fade-start: 0px;
  /* UNMEASURED, a rail stands at its start with its content running past the
     trailing edge — where a page runs no JS at all, that stays true. */
  --sp-rail-fade-end: var(--sp-rail-fade);
  display: flex;
  gap: 1rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  /* `overflow-x: auto` clips the block axis too, so the headroom a card's
     hover lift needs is padding here. */
  padding-block: 0.5rem;
  mask-image: linear-gradient(
    to right,
    transparent 0,
    #000 var(--sp-rail-fade-start),
    #000 calc(100% - var(--sp-rail-fade-end)),
    transparent 100%
  );
  transition:
    --sp-rail-fade-start 150ms linear,
    --sp-rail-fade-end 150ms linear;
}
/* The CARDS are the snap stops, and the trailing tile deliberately is not: it is
   the one child standing there before an island's cards arrive, and a snap
   container re-snaps to its selected target after a layout change — which is
   what would leave a freshly-filled rail standing at its END. */
.sp-site-rail > *:not(.sp-site-rail-end) {
  scroll-snap-align: start;
}
.sp-site-issue-card {
  display: block;
  flex: 0 0 auto;
  width: 10.5rem;
  border-radius: 0.25rem;
}
.sp-site-rail-end {
  display: flex;
  flex: 0 0 auto;
  width: 10.5rem;
  aspect-ratio: 210 / 276;
  align-items: center;
  justify-content: center;
  align-self: start;
  border: 1px dashed var(--sp-border);
  border-radius: 0.25rem;
  padding: 0.75rem;
  text-align: center;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--sp-muted);
  transition:
    border-color 150ms ease,
    background-color 150ms ease,
    color 150ms ease;
}
@media (hover: hover) {
  .sp-site-rail-end:hover {
    border-color: var(--sp-muted);
    background: var(--sp-muted-bg);
    color: var(--sp-fg);
  }
}
.sp-site-wide-card {
  display: flex;
  flex: 0 0 auto;
  gap: 1rem;
  width: min(26rem, 80vw);
  border: 1px solid var(--sp-border);
  border-radius: 0.75rem;
  background: var(--sp-surface);
  padding: 0.875rem;
  box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
  transition: box-shadow 200ms ease;
}
@media (hover: hover) {
  .sp-site-wide-card:hover {
    box-shadow: 0 10px 24px -8px rgb(0 0 0 / 0.3);
  }
}
/* Here the cover stands alone beside a blurb, so it keeps the picture's OWN
   shape — the portrait frame belongs to the rail, where a row of covers lines
   up. The ratio is only what reserves the box until the image has loaded. */
.sp-site-wide-card .sp-site-cover {
  width: 8rem;
  flex-shrink: 0;
  align-self: start;
  aspect-ratio: auto 210 / 276;
  object-fit: contain;
}
.sp-site-wide-body {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  min-width: 0;
}

/* ── footer ──────────────────────────────────────────────────────────────── */

.sp-site-footer {
  border-top: 1px solid var(--sp-border);
  font-family: var(--sp-sans, var(--font-sans, ui-sans-serif, system-ui, sans-serif));
  font-size: 0.875rem;
  color: var(--sp-muted);
}
/* A run of prose reads as ONE flow, like every other area: the footer's columns
   are the titled lists an author placed, never an arrangement imposed on
   whatever stands here. */
.sp-site-footer .sp-site-prose h2,
.sp-site-footer .sp-site-prose h3 {
  margin: 0 0 0.5rem;
  font-family: inherit;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}
.sp-site-footer .sp-site-prose ul,
.sp-site-footer .sp-site-prose ol {
  margin: 0 0 1.25rem;
  padding: 0;
  list-style: none;
}
.sp-site-footer .sp-site-prose li {
  margin: 0 0 0.375rem;
}
.sp-site-footer .sp-site-prose a {
  color: inherit;
  text-decoration: none;
}
.sp-site-footer .sp-site-prose a:hover {
  color: var(--sp-fg);
}

/* ── authored navigation ─────────────────────────────────────────────────────
 * The rows the site's chrome authors. One markup for the baked page and for the
 * SPA sidebar, sized to sit under the reader's own fixed destinations. */

.sp-site-nav {
  display: flex;
  flex-direction: column;
  gap: 1px;
  font-family: var(--sp-sans, var(--font-sans, ui-sans-serif, system-ui, sans-serif));
  font-size: 0.875rem;
  font-weight: 500;
}
.sp-site-nav-row {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.5rem 0.625rem;
  border-radius: 0.375rem;
  color: inherit;
  text-decoration: none;
}
.sp-site-nav-row > span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sp-site-nav-row .sp-site-icon {
  width: 1rem;
  height: 1rem;
}
a.sp-site-nav-row:hover {
  background: var(--sp-muted-bg);
}
/* WHERE THE READER STANDS. The shell marks the row whose address names the
   route it recognizes; a baked page carries no mark, having no route. */
.sp-site-nav-row[aria-current="page"] {
  background: var(--sp-muted-bg);
  font-weight: 600;
  box-shadow: inset 2px 0 0 var(--sp-primary);
}
/* A live count the shell hangs on a row it recognizes. */
.sp-site-nav-badge {
  margin-inline-start: auto;
  padding: 0 0.375rem;
  border: 1px solid var(--sp-border);
  border-radius: 9999px;
  font-size: 0.75rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--sp-muted);
}
/* A TITLED list heads its own rows, in the same words the site heads every
   other unit with. In the 14rem aside it simply takes the full width. */
.sp-site-nav-titled {
  margin-top: 1.25rem;
}
.sp-site-nav-titled:first-child {
  margin-top: 0;
}
.sp-site-nav-titled > .sp-site-band-head {
  margin: 0 0 0.5rem;
  padding: 0 0.625rem;
}
.sp-site-nav-titled .sp-site-band-title {
  margin: 0;
  font-family: inherit;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}
/* IN THE FOOTER a run of them reads as COLUMNS. Inline-block rather than a flex
   parent, because the canvas wraps each area in a section of its own and the
   served page does not — this lays out the same under either. */
.sp-site-footer .sp-site-nav-titled {
  display: inline-block;
  vertical-align: top;
  width: 12rem;
  margin: 0 2rem 1.25rem 0;
}
