/* Inter, for headings and for an idea's own title — and here also for the body,
   which is where this site diverges from rookery.ohrg.org (see `body` below).
   `@import` has to be the FIRST rule in the file — before the `@font-face`
   blocks — or browsers drop it. Fetched rather than self-hosted, matching
   rheo.ohrg.org and ohrg.org; Berkeley Mono is self-hosted below because it is
   licensed and not on any CDN. */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;400;500;600;700&display=swap');

/* ============================================
   Berkeley Mono

   Four faces, following rookery.ohrg.org and cftw.ohrg.org. The urls are
   relative to this stylesheet, which rheo emits at `build/html/style.css` — so
   the files have to end up at `build/html/fonts/`. rheo copies no static
   directories into the HTML root (`copy` under `[html.assets]` handles
   `assets/`, not this), so build.sh and the Justfile do that copy after
   compiling; see the notes there. Until one has run, the wordmark and the idea
   ids fall back to the generic `monospace`.
   ============================================ */
@font-face {
  font-family: 'Berkeley Mono';
  src: url('./fonts/BerkeleyMono-Regular.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
}

@font-face {
  font-family: 'Berkeley Mono';
  src: url('./fonts/BerkeleyMono-Bold.ttf') format('truetype');
  font-weight: 700;
  font-style: normal;
}

@font-face {
  font-family: 'Berkeley Mono';
  src: url('./fonts/BerkeleyMono-Oblique.ttf') format('truetype');
  font-weight: 400;
  font-style: oblique;
}

@font-face {
  font-family: 'Berkeley Mono';
  src: url('./fonts/BerkeleyMono-Bold-Oblique.ttf') format('truetype');
  font-weight: 700;
  font-style: oblique;
}

/* ============================================
   CSS Variables
   ============================================ */
:root {
  --background-color: #fdfdfd;
  --text-color: #1a1a1a;
  --link-color: #1a1a1a;
  --blockquote-border: #e6e6e6;
  --blockquote-text: #606060;
  --muted: #6b6b6b;
  --accent: #1e7a55;
  --rule: #e6e6e6;
  /* Two families, split by what a thing IS rather than by where it sits.

     Berkeley Mono is site furniture and identifiers — the wordmark and an
     idea's `[idea:26w32-etal]` id. It marks the parts of the page that are
     machinery rather than writing.

     Inter is everything that is writing: every heading, and an idea's own
     title, which is its name. */
  --mono-font: 'Berkeley Mono', monospace;
  --heading-font: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  /* The wordmark and idea ids are the same kind of thing — small mono labels —
     so they are the same size, declared once. In `rem`, not `em`: an id sits
     inside headings of two levels and inside a `#window` summary the footer has
     already scaled down, and only a root-relative unit comes out the same in
     all of them. */
  --label-size: 0.85rem;
  /* The hover fill an idea id takes, so the header can take the same one. The
     package injects this value as `--idea-link-color` on its OWN elements,
     from `THEME.link-color` in content/template.typ — but the header has no
     `.idea-*` ancestor to inherit it from, so it is written once more here.
     Keep the two in step.

     Translucent, and `--accent` above is the same hue solid: one green at two
     strengths. The wash goes behind a link on hover; the solid draws every
     hairline the package and this stylesheet put on the page. */
  --hover-fill: rgba(30, 130, 90, 0.16);
  /* What an OUTBOUND link's underline takes on hover, where an internal one
     takes `--hover-fill` behind it. Read by rookery's own stylesheet for links
     inside an idea, and by the `a[href^="http"]` rule below for the prose
     outside one, so both halves of the site agree. The accent rather than the
     fill: the fill is translucent, and a 2px line drawn in it barely shows. */
  --idea-external-color: var(--accent);

  /* Must match the Typst `set text(font, size)` in content/template.typ — the
     KP justifier measures against these metrics (see that file's comment). */
  --body-font: Inter;
  --font-size: 16pt;
}

/* ============================================
   Header

   Rendered by `site-header` in content/template.typ. The wordmark's anchor is
   Typst's, wrapped in the class-carrying element, so the selectors here reach
   through to `a` — see the note in template.typ about why the href cannot be
   written by hand.
   ============================================ */
/* Sticky, so the way back to the index is reachable from anywhere in a long
   page — and these pages are long: a week is a whole week, and an idea's
   standalone page carries its body plus a context/backlinks footer.

   It needs an opaque `background-color` of its own to sit on: `body`'s
   background paints the canvas, not this box, so without one the text
   scrolling underneath would read straight through the bar.

   The rule under it is the SAME colour as the left rule on an idea and on a
   window — the accent, which is what `THEME.border-color` in
   content/template.typ injects as `--idea-border-color` on the package's own
   elements. The header has no `.idea-*` ancestor to inherit that from, so it
   names the value itself; keep the two in step. The site's one horizontal
   hairline and its many vertical ones then read as one system. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background-color: var(--background-color);
  border-bottom: 1px solid var(--accent);
  padding-top: 0.6rem;
  margin-bottom: 1.5rem;
}

.site-header-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem 1.5rem;
  padding-bottom: 0.6rem;
}

/* Search modal, themed green. The properties hang on `.site-header-inner`,
   not on the trigger: the trigger and its `<dialog>` are siblings, so they need
   a common ancestor. (Top-layer paint order does not affect inheritance.) */
.site-header-inner {
  --rookery-search-fg: var(--text-color);
  --rookery-search-bg: var(--background-color);
  --rookery-search-border: var(--accent);
  --rookery-search-radius: 3px;
  --rookery-search-hover: var(--hover-fill);
  --rookery-search-name-color: var(--muted);
  --rookery-search-mark: var(--hover-fill);
  /* Neutral, not the theme's green: a backdrop dims the whole page behind it,
     and a green dim would tint every colour the theme never touches. No
     modal width/height override — the package's own defaults already fit
     this site with no measurement pointing to a better number. */
  --rookery-search-backdrop: rgba(0, 0, 0, 0.4);
}

/* Mono and small, like the wordmark and the subscribe label beside it: the
   search input is site furniture, not writing. */
.rookery-search-input {
  font-family: var(--mono-font);
  font-size: var(--label-size);
}

.rookery-search-input::placeholder {
  color: var(--muted);
}

/* A result's title takes Inter like every idea title on the site, with the id
   beside it in mono — the same division of labour the rest of the site
   uses. */
.rookery-search-title {
  font-family: var(--heading-font);
}

.rookery-search-id {
  font-family: var(--mono-font);
}

/* The package already asks for an undecorated row, but from inside
   `@layer rookery-search`, and any `a { text-decoration: underline }` this
   stylesheet carried would be unlayered and win regardless of order — so if
   a result ever grows an underline, this is the rule to check. Written
   defensively; there is no such rule on this site today. */
.rookery-search-row {
  text-decoration: none;
}

/* Takes the subscribe button's own language — muted, brightening to the
   accent on hover — so the two controls read as one family of header
   buttons, not two different ones bolted together. `margin-left: auto`
   moves here from `.subscribe-btn` below: the trigger is now the FIRST of
   the two right-aligned controls, so it is the one that has to claim the
   push: an `auto` margin on the second item alone would leave the trigger
   stranded beside the wordmark instead of beside subscribe. */
.rookery-search-trigger {
  margin-left: auto;
  color: var(--muted);
  opacity: 0.5;
  transition: opacity 0.2s, color 0.2s;
}

.rookery-search-trigger:hover {
  opacity: 1;
  color: var(--accent);
}

.rookery-search-icon {
  width: 1.1em;
  height: 1.1em;
}

.rookery-search-key {
  font-family: var(--mono-font);
}

/* Uppercase, not small-caps. Berkeley Mono is a monospace face: small-caps in
   it are synthesised by the browser, which scales the capitals down and leaves
   them sitting at the wrong weight for the rest of the face. Setting the text
   upper outright gets the real glyphs at their designed proportions. */
.wordmark a {
  font-family: var(--mono-font);
  font-size: 1rem;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--text-color);
  text-decoration: none;
}

.wordmark.active a,
.wordmark a:hover {
  color: var(--accent);
}

/* The package ships only a neutral button reset for the trigger — placement
   and typography are deliberately left to each site. This is ours: the same
   uppercase mono as the search trigger beside it, so the two read as one
   family of header controls. */
.subscribe-btn {
  gap: 0.45em;
  font-family: var(--mono-font);
  font-size: var(--label-size);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
  transition: opacity 0.2s, color 0.2s;
}

.subscribe-btn:hover {
  color: var(--accent);
}

/* ============================================
   Subscribe dialog

   The modal itself is @rheo/feeds's `feeds-modal`, which ships its own layered
   defaults; only this site's colours stay here, handed over as the package's
   `--feeds-modal-*` custom properties. Unlayered, so they beat the package's
   `@layer feeds-modal` without `!important`.

   A modal `<dialog>` is drawn in the top layer, above every stacking context on
   the page including the sticky header's — which is why the header can carry it
   without its `z-index: 10` mattering either way.
   ============================================ */
.subscribe-dialog {
  --feeds-modal-font: var(--body-font), -apple-system, BlinkMacSystemFont, sans-serif;
  --feeds-modal-fg: var(--text-color);
  --feeds-modal-border: var(--rule);
  --feeds-modal-accent: var(--accent);
  --feeds-modal-hover: var(--hover-fill);
  --feeds-modal-shadow: 0 4px 24px rgba(0, 0, 0, 0.12);
  max-width: 22em;
  padding: 1.25rem;
  border: 1px solid var(--accent);
  border-radius: 3px;
  background-color: var(--background-color);
  line-height: 1.4;
}

.subscribe-option { border-radius: 3px; }

.subscribe-option-desc a {
  color: inherit;
  text-decoration: underline;
}

.subscribe-option-desc a[href^="http"]:hover {
  text-decoration-color: currentColor;
  text-decoration-thickness: auto;
}

/* ============================================
   Base Layout
   ============================================ */
/* Every navigational affordance on this site lands on a fragment — an idea's
   `[idea:26w32-etal]` permalink, an outline row, a backlink, the Context link —
   and a sticky header would otherwise cover whatever each of them jumped to.
   Clears the bar plus a little air. */
html {
  scroll-padding-top: 4rem;
}

/* Inter at 16pt for the BODY, where rookery.ohrg.org sets system sans at 1em.
   Not a preference: the KP justifier emits `--body-font`/`--font-size` as the
   `data-font`/`data-size` its runtime reads and measures line lengths against,
   so the browser has to be rendering the same face at the same size that Typst
   was told about in content/template.typ. Three values, kept in step. */
body {
  background-color: var(--background-color);
  color: var(--text-color);
  font-family: var(--body-font), -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: var(--font-size);
  line-height: 1.4;
  margin: 0 auto;
  padding: 50px;
  max-width: 36em;
}

/* ============================================
   Typography
   ============================================ */
/* Site headings wear the wordmark's face: Berkeley Mono, at the wordmark's
   tracking — mono at display sizes opens up without it. On this site almost
   every heading IS an idea's name, and the face alone is enough to mark it as
   the same kind of object as the header's wordmark.

   CASE IS THE AUTHOR'S. The heading prints whatever the source says, so a name
   that is written mixed-case stays mixed-case; nothing here uppercases it.
   `font-variant: normal` for a related reason: Berkeley Mono has no small-caps,
   so the browser would synthesise them by scaling capitals down, leaving them
   at the wrong weight for the rest of the face.

   TIGHT. A heading here labels the card directly beneath it, and the card's
   own frame already separates one section from the last, so the old 1.5em/0.5em
   pair was spacing a gap that was drawn twice. */
h1, h2, h3, h4, h5, h6 {
  color: var(--text-color);
  font-family: var(--mono-font);
  font-variant: normal;
  letter-spacing: -0.02em;
  font-weight: normal;
  margin-top: 0.75em;
  margin-bottom: 0.25em;
}

/* An idea's heading is an `h1` only on the standalone page rookery mints for
   it, where it is the first thing under the header rather than a section break
   in a longer page. The margin above is the space between one section and the
   last, and there is no last one here — it just pushed the title down the
   screen. Mirrors the margin below it instead. */
h1.idea {
  margin-top: 0.25em;
}

/* The gap above a section's own name, INSIDE its card. The rule above cannot
   set it: rookery gives `h2[data-rookery="idea"]` its own `margin-top` and an
   element selector carrying an attribute outranks a bare `h2`. The package
   exposes this property for exactly that reason, and its 0.75em default is
   half of the ~1.5em a site typically gives a heading — still too much here,
   where the card's own left rule and its hat already mark where a section
   starts, so the gap is drawn three times over. */
:root {
  --idea-heading-margin-top: 0.15em;
}

/* An idea's own title, in both the shapes it is shown in: `.idea-title` inside
   `#idea`'s own heading, and `.idea-window-title` in a `#window`'s summary — a
   span only because a fold control cannot contain an `<h2>`, which is why it
   needs the heading treatment stated again rather than inherited. */
.idea-title,
.idea-window-title {
  font-family: var(--mono-font);
  font-variant: normal;
  letter-spacing: -0.02em;
}

/* A span, not a block: the summary lays its parts out on one line and these
   margins would break that. */
.idea-window-title {
  margin: 0;
}

/* A week's opening note is tagged `intro` (see the `<tag:intro>` label on its
   `== Intro` heading). The title earns its place in `#ideas-outline` — that is
   the only handle a reader has on the section — but printing it again as a
   heading directly under "Week N", with a hat of its own ruling off the top of
   the card, says nothing the position doesn't already say: the intro is the
   prose a week opens with, and it should read as that.

   Everything here is scoped to the INLINE card. The note's own minted page
   sets its title as `h1.idea` and hangs its hat on `.idea-head` rather than
   inside it, and that page has no surrounding week to name it, so both survive
   untouched — as do the outline row and any `#window` summary. */
.idea-box.idea-tag-intro > .idea-head > .idea-tab {
  display: none;
}

/* NOT `display: none` on the heading: it carries `id="idea:intro"`, the anchor
   a Context link or a backlink from another page lands on, and an element with
   no box has no position to scroll to. Zero height keeps it in flow, with the
   package's own 0.75em above it zeroed so the card starts on its first line. */
h2.idea.idea-tag-intro {
  margin: 0;
  height: 0;
  overflow: hidden;
}

h2.idea.idea-tag-intro .idea-title {
  display: none;
}

/* With the hat and the heading both gone the card's first line is whatever the
   author wrote, and its own top margin is now the only thing between the intro
   and the week's title above it. The package normally hands that gap to the
   tab's `margin-bottom`; here there is no tab to own it. `+ *` rather than
   `+ p` so a week that opens on a list or a figure starts flush too. */
.idea-box.idea-tag-intro > .idea-head + * {
  margin-top: 0;
  padding-top: 0;
}

/* `weeknote` in content/template.typ emits the package's own outline
   markup, but not the package's inline `style` attribute — only rookery can
   write that, and only on elements it emits itself. Inside an idea box the
   custom property inherits down and this changes nothing; where the list sits
   outside one, it is what keeps the row rules green instead of falling through
   to rookery's default purple. */
.idea-outline {
  --idea-border-color: var(--accent);
}

/* An outline row names a section, and the heading it points at now wears the
   wordmark's face — so the row does too, or the contents list and the sections
   under it read as two different vocabularies. `> a` so a row styles its own
   link and leaves a nested list's rows to this same rule at their own level.
   Case is left alone here for the same reason the headings leave it alone: a
   row prints the section's name as written, so the two agree letter for letter.
   "Contents" above them still arrives mono and upper from the package, off
   `--idea-label-font` (`THEME.label-font` in content/template.typ) — it is a
   label rather than one of the names. */
.idea-outline-row > a {
  font-family: var(--mono-font);
  letter-spacing: -0.02em;
}

/* Font and size come from rookery's own `--idea-label-font`/`--idea-label-size`
   now, set via `THEME.label-font`/`THEME.label-size` in content/template.typ —
   matching `--mono-font`/`--label-size` above, so the id reads as the same
   family and size as the wordmark. Setting them here directly, bypassing the
   theme, used to leave the hat's geometry (calc()'d against
   `--idea-label-size`) tuned for rookery's default 0.57rem while the label
   itself rendered at 0.85rem — the corner never quite closed at some
   viewport widths. Only `font-variant` stays: left as written, neither
   small-caps nor uppercased, since `[idea:26w32-etal]` is an identifier to be
   copied verbatim into `#window("...")`, and a reader who retyped what an
   uppercased id appeared to say would get it wrong. */
.idea-label {
  font-variant: normal;
}

/* ============================================
   Links
   ============================================ */
a {
  color: var(--link-color);
  text-decoration: underline;
}

/* Two kinds of link, two weights of response. Staying inside the rookery is the
   ordinary case and keeps the ordinary hover — the whole link dims, the same
   gesture the wordmark makes. Leaving is the exceptional one, and gets the
   quieter signal: the underline takes the accent and thickens, the text itself
   untouched. The difference should be felt rather than read, which is why it is
   a change of channel and not a louder version of the same change.

   `[href^="http"]` is the test, and it holds because rheo emits every
   in-project link as a depth-relative path — nothing internal carries a scheme.
   Inside an idea, rookery's own stylesheet draws the same distinction with the
   same colours (see `--idea-external-color` above); these rules are for the
   prose that sits outside one. */
a:not([href^="http"]):hover {
  opacity: 0.7;
}

a[href^="http"]:hover {
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.15em;
}

/* ============================================
   Lists
   ============================================ */
ul, ol {
  padding-left: 2em;
  margin: 1em 0;
}

/* ============================================
   Media
   ============================================ */
img, video {
  max-width: 100%;
  height: auto;
  display: block;
  margin: 1.5em 0;
}

/* ============================================
   Code
   ============================================ */
code {
  font-family: var(--mono-font);
  background-color: #f5f5f5;
  padding: 0.2em 0.4em;
  border-radius: 3px;
  font-size: 0.85em;
}

pre {
  background-color: #f5f5f5;
  padding: 1em;
  border-radius: 3px;
  overflow-x: auto;
}

pre code {
  background-color: transparent;
  padding: 0;
  border-radius: 0;
  font-size: 1em;
}

/* ============================================
   Tables

   Typst's HTML export emits a bare `<table>` and drops everything passed to
   `#table` as styling — `columns`, `align`, `inset`, `stroke` all vanish — so
   the whole appearance of a table on this site is decided here.

   The shape these tables take is a term and a paragraph about it, so the first
   column shrinks to its content (`width: 1%` against `table-layout: auto` is
   the idiom for "as narrow as the text allows") and the second takes the rest.
   A cell's text starts at the top of its row rather than floating in the
   middle of it, which is what keeps a one-word term level with the first line
   of the description beside it.
   ============================================ */
table {
  width: 100%;
  margin: 1.5em 0;
  border-collapse: collapse;
  text-align: left;
}

th, td {
  vertical-align: top;
  padding: 0.6em 0.8em;
  border-bottom: 1px solid var(--rule);
}

/* The header is a label for the column, not writing, so it takes the same
   small mono treatment as the site's other labels. */
th {
  font-family: var(--mono-font);
  font-size: var(--label-size);
  font-weight: 400;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-bottom-color: var(--text-color);
}

/* The term column reads as an identifier — these are package names — and stays
   on one line so the rule under each row is the only thing dividing them. */
th:first-child, td:first-child {
  width: 1%;
  white-space: nowrap;
  padding-left: 0;
}

th:last-child, td:last-child {
  padding-right: 0;
}

tbody tr:last-child th, tbody tr:last-child td {
  border-bottom: none;
}

/* Justification is set on the prose container, and a narrow cell justified into
   a two-word line comes out as gaps. */
td {
  text-align: left;
  text-wrap: pretty;
}

/* ============================================
   Blockquotes
   ============================================ */
blockquote {
  margin: 1.5em 0;
  padding-left: 1em;
  border-left: 2px solid var(--blockquote-border);
  color: var(--blockquote-text);
  font-style: italic;
}

hr {
  height: 1px;
  background-color: var(--blockquote-border);
  border: none;
}

/* ============================================
   Endnotes

   Footnotes written inside an idea belong to that idea and are listed in its
   own block by rookery, so this only catches a `#footnote` written outside one
   — where the package proxies Typst's native function.
   ============================================ */
section[role="doc-endnotes"] {
  margin-top: 2em;
  padding-top: 1em;
  border-top: 1px solid var(--blockquote-border);
}

section[role="doc-endnotes"] ol li a[role="doc-backlink"] {
  padding-right: 0.2em;
}

/* rookery's ideas rely on the browser's default figure margin to separate
   stacked ideas, which isn't enough when the previous idea ends with a
   footnotes/references block — the next idea's id hat ends up crowded. */
.idea-box {
  margin-top: 1.2em;
}

/* ============================================
   Footer

   The header's mirror, and deliberately built out of the same parts: the same
   inner flex row, the same 0.6rem/1.5rem gap, the same accent hairline (on top
   here rather than underneath), and the same small mono labels. What the
   wordmark and the feed icon are to the header, the site links and the
   colophon are to this — one at each end of the row.
   ============================================ */
.site-footer {
  margin-top: 3rem;
  border-top: 1px solid var(--accent);
  padding-bottom: 2rem;
}

.site-footer-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem 1.5rem;
  padding-top: 0.6rem;
}

/* Three slots, and the outer two share the leftover space equally — that is
   what puts the middle one on the CONTAINER's centre line rather than on the
   centre of whatever the other two happen to leave. `margin-left: auto` on the
   last item would right-align it just as well but would centre the middle one
   only by accident, and only while the two ends were the same width. */
.footer-start,
.colophon {
  flex: 1 1 0;
}

.footer-center {
  flex: 0 1 auto;
  text-align: center;
}

.colophon {
  text-align: right;
}

/* The slots take the header's typography — mono, uppercase, `--label-size` —
   because that is what makes the footer read as the header's mirror.
   `--muted` is for the prose around the links ("Built with"), which is a label
   rather than a link; the anchors override it below.

   The LINKS take nothing of the header's. Every one of them leaves the site,
   so hovering one draws the same accent underline an outbound link draws in a
   sentence. */
.site-footer-inner {
  font-family: var(--mono-font);
  font-size: var(--label-size);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
}

/* At rest they carry no underline. Three of them sit in a row of small mono
   capitals, and underlining all three turns the row into a rule with gaps in
   it — where the same underline under one link in a paragraph is what marks it
   out from the prose. */
.site-footer-inner a {
  text-decoration: none;
}

/* The LINE only. Its colour, thickness and offset come from the outbound-link
   hover in the Links section above, which reaches these because every footer
   link carries a scheme — so the green here cannot drift from the green in the
   prose. That is also the dependency: a footer link WITHOUT an `http` href
   would hover with a plain underline instead of the accent one. */
.site-footer-inner a:hover {
  text-decoration-line: underline;
}

/* Bigger and bolder than rookery's own default (0.57rem, weight 200) — a
   window's date is meant to read as a real piece of information on the
   homepage, not a faint label. `!important`: rheo emits this stylesheet
   BEFORE rookery/core/core.css in <head>, so the package's own
   `.idea-date` rule (same specificity) would otherwise win the cascade by
   loading later — same fix as `.rheo-kp` below. */
.idea-date {
  font-size: 0.8rem !important;
  font-weight: 700 !important;
}

/* ============================================
   Homepage

   The stack of folded weeks. Typst emits each `#window` inside a bare
   `<figure>`, so the gap between two of them is the UA's own `figure { margin:
   1em 40px }` — the package zeroes the horizontal half of that (and only for
   its own figures, via `:has()`), but leaves the vertical, and 1em of it
   between ten folded one-line summaries reads as ten separate things rather
   than one list. Halved. Adjacent margins collapse, so 0.5em on each side of
   the boundary is a 0.5em gap, not 1em.

   Scoped to figures that are DIRECT children of the content div, which on this
   site means exactly the homepage's windows: the only other windows are the
   ones rookery renders in an idea page's Backlinks block, and those sit inside
   `.idea-backlinks`, several levels down. Specificity (0,2,1) beats the
   package's own (0,1,1), and rookery.css uses no `@layer`, so nothing else is
   in play.
   ============================================ */
.rheo-feed-content > figure:has(> .idea-window) {
  margin-top: 0.5em;
  margin-bottom: 0.5em;
}

/* ============================================
   Responsive
   ============================================ */
@media (max-width: 600px) {
  body {
    padding: 12px;
    font-size: 14pt;
  }

  /* Three slots do not fit on one line at this width, and left/centre/right
     stops meaning anything once they wrap — so they stack, all centred, and
     the centre slot keeps its place in the middle of the stack. */
  .site-footer-inner {
    flex-direction: column;
    gap: 0.4rem;
  }

  .footer-start,
  .footer-center,
  .colophon {
    flex: none;
    text-align: center;
  }

  /* No justified text on mobile. index.js tags the content container with
     `.rheo-kp-skip` so the KP client leaves paragraphs alone (natural
     wrapping). This `!important` is the no-JS fallback: it beats the package's
     `.rheo-kp { text-align: justify }` (which loads after this stylesheet). */
  .rheo-kp {
    text-align: left !important;
  }

  /* Icon-only once the header row is this tight. The button keeps its title
     attribute and the dialog says what it is the moment it opens, so the label
     is the part that can go. */

  /* A bottom sheet rather than a centred box: the UA's dialog centring drifts
     off-centre on mobile, where a collapsing toolbar keeps changing what the
     viewport is. Pinned to the bottom instead, full width, sliding up.

     `width: auto` is load-bearing — it clears the base rule's `calc(100% -
     2rem)` (and the UA's `dialog { width: fit-content }`) so `left: 0; right:
     0` alone solve for width. Any explicit width over-constrains the box, and
     `right` is the one dropped: the sheet would sit flush left with a gap on
     the right, and a `100%` resolved against a layout viewport wider than the
     screen would overshoot and give the page a horizontal scrollbar. */
}
