/* rookery — default styling, modelled on Forester (www.forester-notes.org).
   Deliberately thin: enough that the fold/permalink interaction reads
   correctly out of the box, and nothing that presumes a page design. No
   fonts, no page colors, no typographic scale — only the affordances.

   Nothing here is load-bearing for FUNCTION: linking, transclusion and the
   <details>/<summary> fold all work via native HTML semantics with zero CSS.
   What the CSS carries is the CLICK BUDGET, and that is worth stating once,
   because it is the whole interaction model:

     - the summary of a `#window` folds and unfolds. That is all it does.
     - `.idea-label` — the `[idea:etal]` permalink, on the tab that rules off
       the top of a card (`.idea-tab`) — is the ONLY link inside a window, and it
       goes to the note's standalone page. (`.idea-ref` is the other anchor
       this package emits, but an author asks for that one by writing
       `@idea:other`; it is prose, not window chrome.)

   Override any of it; the classes are the contract.

   THE THEME. Every colour below is `var(--x, <default>)`. The default is the
   literal in the var() call, right here; the override arrives as an inline
   custom property on `.idea-box` / `.idea-window` / `.idea-ref` / a minted
   page's `<h1>`, set by `#show: rookery.with(theme: (...))` (or its granular
   equivalents), and inherits down. So a document that never configures
   anything emits no properties at all and still gets exactly this, and a
   reader with no custom-property support gets it too:

     --idea-link-color   link-color   hover background on ANY rookery link
     --idea-fold-color   fold-color   hover background on a foldable window block
     --idea-id-color     id-color     the [idea:etal] permalink's text
     --idea-date-color   date-color   an idea's/window's date, where shown
     --idea-border-color border-color the left rule on `.idea-box`/`.idea-window`,
                                      and the top tab rule (`.idea-tab`) that
                                      meets it at the corner
     --idea-pad          pad          how far a card's or a window's content sits
                                      from the rule beside it, and a window's own
                                      right padding: ONE indent (0.5em, halved
                                      under 600px). The tab's offset and the top
                                      rule's stub span the same distance and read
                                      this, so the corner closes at any value
     --idea-rule-width   rule-width   how THICK every one of those is, plus the
                                      floor under a FOLDED window's summary and
                                      `#ideas-outline`'s rule and its row
                                      markers: one thickness for the whole frame
                                      (2px). NOT the separators above a
                                      footnotes/references block — those are
                                      apparatus, not the note's frame
     --idea-external-color            the underline an OUTBOUND link takes on
                                      hover, where an internal one takes the
                                      fill above (defaults to the id colour)
     --idea-label-font   label-font   the face EVERY HAT is set in — a note's
                                      `[idea:etal]` id and `#ideas-outline`'s
                                      "Contents" title, which are the same object
                                      wearing the same rule. A CSS font stack, not
                                      a colour and not a length: it is passed
                                      through unvalidated, and an array of family
                                      names is joined for you. Defaults to
                                      `monospace`, the generic family, so it is
                                      whatever face the reader configured rather
                                      than one this package picked. BODY PROSE IS
                                      UNAFFECTED — this package sets no
                                      `font-family` on writing and must not start

   `--idea-border-color` defaults to `--idea-link-color` itself (not to a
   separate literal), so the rule and the link hover read as the same colour
   until a theme sets `border-color` on its own.

   The first two are the look. Both are hover BACKGROUNDS, which is what makes
   them comparable: the lighter blue belongs to the fold (a block that only
   opens and closes), the stronger purple to every link (which actually goes
   somewhere). Forester makes the same split with one blue at two alphas; two
   hues survive being read quickly.

   Setting them yourself in your own stylesheet works just as well, and wins
   nothing over the Typst-side route — they are the same properties. */

/* The permalink, on the tab above `#idea`'s heading and above `#window`'s title
   — the same affordance meaning the same thing in both places, and in prose on
   its own where a nested window ran out of depth. Grey and light so it reads as
   an id rather than as body text, and unstyled by any inherited link decoration
   so it does not shout. `white-space: nowrap`
   keeps "[idea:etal]" from breaking mid-id. (`idea:` is the default prefix;
   `#show: rookery.with(prefix: ...)` changes the TEXT, never the class.)

   The padding is on the element, NOT on :hover — a padding that appeared only
   on hover would shift the surrounding line every time the pointer crossed
   it. Only the background changes. */
.idea-label {
  margin-left: 0.5em;
  padding: 0 2px;
  white-space: nowrap;
  color: var(--idea-id-color, gray);
  font-weight: 200;
  /* Metadata, not content — explicitly smaller than the title beside it
     (`.idea-window-title` and a heading's own text both stay at their
     ambient size), rather than differing only by weight/colour as before.
     `.idea-date` reads this same property, so the date at the hat's other end
     reads as the same kind of thing as the id at this one.

     `rem`, NOT `em` — and this is the whole point of the rule. An id is ONE
     thing wherever it appears, and `em` made it three different sizes: 0.57 of
     an `<h2>` in an `#idea` heading, 0.57 of an `<h1>` on a minted page, 0.57
     of body text in a `#window` summary (smaller again inside the footer,
     which scales down). MEASURED on rookery.ohrg.org: the same id came out
     visibly larger in a heading than in a window beside it. Root-relative, it
     comes out identical in all of them, at the window's size — the smallest
     of the three, which is the one that reads as machinery rather than as
     part of the heading it sits in. */
  font-size: var(--idea-label-size, 0.57rem);
  /* THE HAT'S FACE, shared with `#ideas-outline`'s title, which wears the same
     rule and is therefore the same object. `monospace` is the GENERIC family, so
     the default is the face the reader configured rather than one this package
     chose for them — and an id is machine text, which is what a monospace face
     says without a word of explanation. */
  font-family: var(--idea-label-font, monospace);
  text-decoration: none;
  border-radius: 3px;
}

/* The 0.5em separates the permalink from a TITLE it follows — which, since the
   id moved onto the tab below, is only the case for a permalink standing in
   ordinary prose (a nested window with no depth budget left). Kept for that one,
   and for any stylesheet that positioned the id the old way. */
.idea-label:first-child {
  margin-left: 0;
}

/* THE TOP RULE. A note's id is not a word in its heading — it is the card's top
   edge, as wide as the id needs and no wider, with the id straddling it:

     -[idea:etal]-
     |
     | Note title
     | Body text of the note runs on from here...

   The rule is the same `--idea-border-color` as the left rule below, so the two
   meet at the corner and read as one frame.

   Drawn as a zero-height pseudo-element with a `border-top` rather than as a
   background line behind the text: a line that has to break BEHIND the id would
   need to know the page's background colour, which a package cannot know, and
   guessing it puts a grey box around every id on a dark site.
   `align-items: center` puts the rule through the id's middle, which is right HERE
   — on a minted page the tab is a leader beside the id with no border to meet, and
   a dash at the id's baseline would just hang low. Inside a card or a window,
   where the rule IS the box's top edge, it is overridden to `flex-end` beside the
   lift that depends on it (see the two rules below).

   ONE stub, to the LEFT. The rule runs out of the corner and STOPS at the id —
   it does not resume on the far side. The id is where the frame ends, not a word
   set into a line that continues past it.

   `margin-bottom` here rather than on the heading below it, because the tab owns
   the gap under the rule: whatever comes next — a title, a date, or the note's
   first paragraph when it has neither — sits that far below, and no further. See
   the two rules that zero out what would otherwise be added to it. */
.idea-tab {
  display: flex;
  align-items: center;
  gap: 0.3em;
  margin-bottom: 0.25em;
}

.idea-tab::before {
  content: "";
  flex: 0 0 auto;
  border-top: var(--idea-rule-width, 2px) solid var(--idea-border-color, var(--idea-link-color, rgba(128, 0, 255, 0.12)));
}

/* The stub reaches back across the card's own `padding-left` (0.75em, set on
   `.idea-box`/`.idea-window` below) PLUS the 2px of the left rule itself, so it
   ends on that rule's OUTER edge and the corner has no notch in it. At 1px the
   shortfall was invisible; at 2px it is a gap you can see. */
.idea-tab::before {
  width: calc(var(--idea-pad, 0.5em) + var(--idea-rule-width, 2px));
}

/* `.idea-label`'s 0.5em separates it from a title it follows. In a tab it
   follows nothing. */
.idea-tab .idea-label {
  margin-left: 0;
}

/* `.idea-head` groups the tab with the heading under it, so the two are real
   siblings whatever Typst's HTML export decides about paragraph grouping (see
   `_head` in lib.typ — loose siblings came out `<p>`-wrapped in some cards and
   not others). It is also the theme container on a minted note page, which has no
   `.idea-box` to be one. Structural only: no box, no spacing of its own.

   `flow-root`, NOT `block`, and that is the difference between a closed corner
   and no corner at all. The tab is lifted by a negative `margin-top` (below) to
   straddle the card's top edge. As a plain block this element has no border and
   no padding, so that margin ADJOINS its own — it collapses out through
   `.idea-head`, and then out through `.idea-box`, which has no top border or
   padding either. MEASURED: the whole card moved up by the lift, left rule
   included, so the stub stayed exactly as far below the rule's top end as
   before. `flow-root` makes this a block formatting context, which is precisely
   the rule that stops a child's margin escaping its parent. */
.idea-head {
  display: flow-root;
}

/* A REAL TOP-LEFT CORNER, and both margins are what make it one.
   `margin-left` cancels the card's `padding-left` so the stub starts exactly on
   the left rule's own line. `margin-top` lifts the tab so it STRADDLES the card's
   top edge — half above, half below — because the stub is drawn at the tab's
   vertical middle, and the top END of the left rule is at the edge. Without the
   lift the stub sat half an id BELOW that end and the rule stuck up past it.

   `line-height: 1` is what makes the arithmetic exact rather than a guess: it
   collapses the tab's box to exactly the id's own height, whatever line-height
   the host page sets, so half of it is half of `--idea-label-size`. The lift is
   expressed against that variable for the same reason the id's size is — move the
   variable and the corner follows.

   `font-size` is deliberately NOT set here: the stub widths and the gap below are
   in `em`, and re-basing them on the id's 0.57rem would shrink the rule and break
   `margin-left`'s cancellation of a padding measured in the card's own em.

   Only inside a card. A minted page's `.idea-head` has no border and no padding
   to meet, so its tab stays in flow. */
.idea-box > .idea-head > .idea-tab,
.idea-window-summary > .idea-tab {
  line-height: 1;
  /* THE RULE TO THE BOTTOM OF THE LINE, not through the id's middle, and only in
     these two contexts — the ones with a top border for it to be. A zero-height
     flex item centred lands on the label's own centre line, which is what used to
     leave half the id hanging BELOW the border: MEASURED, 4.55px above the box top
     and 4.58px below it. At `flex-end` the rule sits under the label, so the lift
     below puts the id ON the border rather than through it. */
  align-items: flex-end;
  /* CLOSER TO THE END OF THE HAT. Half the generic tab's `gap` — MEASURED 4.8px
     (0.3em) between the stub's end and the id's box, 6.8px to the id's text once
     the label's own 2px padding is counted; halved it is 2.4px and 4.4px. The id
     reads as sitting ON the end of the rule rather than floating away from it.
     Scoped to these two contexts with the rest of the treatment: a MINTED page's
     tab keeps the wider gap, and keeps its id centred on the stub, because there
     the dash is a leader beside the id rather than a frame's top edge. */
  gap: 0.15em;
  /* A WHOLE label, not half: with the rule at the line's bottom (above), lifting by
     the label's full height lands that rule on the box's top edge and leaves the id
     entirely above it. Half a label is what used to centre the id ON the border.
     From the custom property, never a pixel count, so a project retheming
     `--idea-label-size` keeps the alignment. */
  margin-top: calc(-1 * var(--idea-label-size, 0.57rem) - 1px);
  margin-left: calc(-1 * var(--idea-pad, 0.5em) - var(--idea-rule-width, 2px));
}

/* `.idea-window` puts 2px of padding above the `<summary>`, so the lift there has
   to clear that too or the corner lands 2px low. */
.idea-window-summary > .idea-tab {
  margin-top: calc(-1 * var(--idea-label-size, 0.57rem) - 3px);
}

/* ONE PIXEL OF AIR UNDER THE ID, and on the LABEL rather than on the tab. Lifting
   the tab would take the rule with it — `::before` is a flex sibling aligned to the
   same line bottom — and the rule has to stay ON the box's top edge, because it IS
   that edge and the corner closes on the left rule there. With `align-items:
   flex-end` each item's MARGIN box bottom meets the line's bottom, so a
   `margin-bottom` on the label alone raises the label within that line.
   BUT IT MUST BE PAIRED WITH 1px MORE LIFT, and measuring is the only way to see
   why: the label is the tallest item, so its MARGIN box sets the line's height —
   the tab grew 1px, its bottom moved 1px DOWN into the box, and the id did not
   move at all. MEASURED, `idBelowBoxTop` stayed 0.02px. So every lift below also
   carries `- 1px`: the tab's bottom returns to the box's top edge, the rule with
   it, and the id ends up the 1px higher that was wanted. */
.idea-box > .idea-head > .idea-tab > .idea-label,
.idea-window-summary > .idea-tab > .idea-label {
  margin-bottom: 1px;
}

/* FOLDED, the window has given up its 2px `padding-top` (see the folded rule
   below), so the lift must give up the 2px it added to clear it or the tab lands
   2px high and the hat parts company with the wash under it. */
.idea-window-details:not([open]) > .idea-window-summary > .idea-tab {
  margin-top: calc(-1 * var(--idea-label-size, 0.57rem) - 1px);
}

/* The tab carries the space above a note, so the heading under it contributes
   none of its own — neither the site's heading margin nor this package's. */
.idea-tab + h1.idea,
.idea-tab + h2.idea,
.idea-tab + h3.idea,
.idea-tab + h4.idea,
.idea-tab + h5.idea,
.idea-tab + h6.idea {
  margin-top: 0;
}

/* A HEADING INSIDE THE HEAD CONTRIBUTES NOTHING BELOW IT EITHER, and this one is
   a consequence of `.idea-head` being a block formatting context (see above).
   Margins do not collapse across a BFC boundary, so a heading's own
   `margin-bottom` — which used to collapse with the first body block's
   `margin-top` and disappear into it — now ADDS to it instead.

   MEASURED on rookery.ohrg.org: that site sets `h1..h6 { margin-bottom: 0.5em }`,
   which at heading size plus the browser's own 1em paragraph margin put nearly
   twice the space between "A rookery" and its first line than before the head
   existed. Zero it, and the gap under a note's name is again the first block's to
   set — exactly what the heading rule above has always said it should be. */
.idea-head > h1.idea,
.idea-head > h2.idea,
.idea-head > h3.idea,
.idea-head > h4.idea,
.idea-head > h5.idea,
.idea-head > h6.idea {
  margin-bottom: 0;
}

/* THE SAME GAP FOR A NOTE WITH NO TITLE. Its heading element survives to carry
   the `id` anchor but is empty and takes no space (below), so the thing under the
   rule is the note's first block — a sibling of `.idea-head`, arriving with its
   own margin-top, which is the site's paragraph spacing rather than this gap.
   Zero it and the distance from the rule to the first thing under it is the tab's
   `margin-bottom` in both cases, which is what makes titled and untitled notes
   line up as the same object.

   `:has` rather than a class, because whether the heading is empty is decided by
   the author's arguments (`title:`, `show-date:`) at every call site, not by
   anything the package could put in the markup once. `.idea-page-refs:has(li)`
   already relies on the same selector. */
.idea-head:has(> :empty) + * {
  margin-top: 0;
}

/* A titleless, dateless note's heading survives only to carry the `id` anchor
   every `@idea:etal` fragment link resolves to. It has no content and must take
   no space. */
h1.idea:empty,
h2.idea:empty,
h3.idea:empty,
h4.idea:empty,
h5.idea:empty,
h6.idea:empty {
  margin: 0;
}

/* THE LINK HOVER — every link rookery is responsible for, which is what makes
   the permalink and an `@idea:other` reference read as the same kind of thing:

     .idea-label   the [idea:etal] permalink, in a heading or a window summary;
     .idea-ref a   an `@idea:other` reference rendered by `ref-rule`;
     .idea-box a   an author's own link inside a note;
     .idea-window a  ...and inside a transcluded copy of one;
     .idea-outline a a row of a page's own table of contents.

   Deliberately NOT a bare `a:hover`: this stylesheet is injected into every
   page of a rheo project, and a package has no business restyling a site's
   nav. It reaches the links in rookery's own blocks and nothing else.

   INTERNAL LINKS ONLY. The fill is how a rookery says "this goes somewhere
   else in the rookery" — a permalink, a reference, an outline row, a backlink.
   An outbound link is a different promise, and washing it in the same colour
   claims a continuity that is not there: the reader is leaving. So the fill is
   withheld from anything whose href starts a URL scheme, and those links get
   their own quieter treatment below.
   `[href^="http"]` catches the case that exists in practice. rheo emits every
   in-project link as a depth-relative path, so "has a scheme" and "leaves the
   rookery" are the same set here. A site that writes its OWN pages as absolute
   urls opts them out of the fill; write them relative, which is what rheo's
   own link rewriting produces anyway. */
.idea-label:hover,
.idea-ref a:not([href^="http"]):hover,
.idea-box a:not([href^="http"]):hover,
.idea-window a:not([href^="http"]):hover,
.idea-outline a:not([href^="http"]):hover,
.idea-footnotes a:not([href^="http"]):hover,
.idea-references a:not([href^="http"]):hover,
.idea-page-refs a:not([href^="http"]):hover,
.idea-footer a:not([href^="http"]):hover {
  background-color: var(--idea-link-color, rgba(128, 0, 255, 0.12));
}

/* ...and the outbound half of that pair. A link that leaves gets a change in
   its UNDERLINE rather than a fill behind it: the same information — this is
   live, you are pointing at it — carried by the quieter of the two channels,
   which is the difference a reader should feel between staying and going.
   Only on hover, so outbound links are not permanently marked up in the prose;
   an author who wants that can say so in their own stylesheet.
   `text-decoration-line` is set here because a site whose links are not
   underlined at rest has no underline to recolour otherwise, and a rule that
   did nothing on half of its installs would be worse than one that adds the
   line it needs. `--idea-external-color` defaults to the id grey rather than
   to the link wash: the wash is a translucent fill, and a 2px line drawn in it
   is close to invisible. */
.idea-ref a[href^="http"]:hover,
.idea-box a[href^="http"]:hover,
.idea-window a[href^="http"]:hover,
.idea-outline a[href^="http"]:hover,
.idea-footnotes a[href^="http"]:hover,
.idea-references a[href^="http"]:hover,
.idea-page-refs a[href^="http"]:hover,
.idea-footer a[href^="http"]:hover {
  text-decoration-line: underline;
  text-decoration-color: var(--idea-external-color, var(--idea-id-color, gray));
  text-decoration-thickness: 2px;
  text-underline-offset: 0.15em;
}

/* Radius only, no padding, on links that are ordinary prose — padding would
   change inline metrics of body text. The permalink pads because it is a
   bracketed id sitting apart from the words around it. */
.idea-ref a,
.idea-box a,
.idea-window a,
.idea-outline a,
.idea-footnotes a,
.idea-references a,
.idea-page-refs a,
.idea-footer a {
  border-radius: 3px;
}

/* ---- The footer of a minted note page ------------------------------------
   Two sections of equal standing, either of which may be absent:

     .idea-context    the page the note was written in, linked to the note's
                      own anchor there — the way back to the argument it was
                      written inside, which a minted page strips away;
     .idea-backlinks  the notes that point AT this one, as folded windows.

   They share a markup shape (heading first, then content) and every rule
   below, because they are two answers to the same question about where a note
   sits, not one main thing and one afterthought.

   Ruled off and set small: apparatus, not part of the note. The date colour is
   reused rather than given a knob of its own, since both are the same kind of
   thing — muted metadata about the note rather than the note.

   That colour goes on the footer's OWN parts (below), never on this box. A
   `#window` in Backlinks is a NOTE, and has to read as one — the same thing it
   is anywhere else — but an inherited `color` here reaches inside the
   transcluded copy and tints its title. MEASURED on rookery.ohrg.org: backlink
   titles came out `--idea-date-color` amber where every other window's title
   is the ambient text colour. Per-part is also the only fix that stays theme
   agnostic: a package cannot name the colour a window's title should revert
   TO, only decline to override it. */
.idea-footer {
  margin-top: 2em;
  padding-top: 0.5em;
  /* Neutral grey rather than black-at-low-alpha, so the rule stays visible on
     a dark page as well as a light one. */
  border-top: 1px solid rgba(128, 128, 128, 0.3);
  font-size: 0.85em;
}

/* Both sections have the same shape — a heading, then rows flowing down from
   it — so they take the same spacing and need no rules of their own.

   REJECTED, do not reinstate: (1) the two sections side by side in a grid,
   which gave a one-line fact half the footer's width and a list of unknown
   length the other half, and needed a container query to flip a divider
   between vertical and horizontal; (2) Context as a tinted one-line banner
   across the top, which made the two sections look like different kinds of
   thing when they are the same kind — places this note is reachable from. */
.idea-footer > * + * {
  margin-top: 1.5em;
}

/* A row naming a PAGE — the origin under Context, and any page under
   Backlinks. A page cannot be a `#window`, having no note to fold open, so it is
   a plain link wearing the row shape a `#window` gives a note: the same left
   rule and the same indent. Within one list these are peer entries, and a page
   row hanging flush left beside a ruled, indented note row reads as a
   different list rather than the rest of the same one.

   No bullets: the list is structure, not enumeration. */
.idea-page-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* A ROW THAT IS PART OF THE FRAME, not a piece of metadata beside it. This shape
   serves two things now — a page backlink, and the link a `#window` bottoms out at
   when its depth budget runs out — and both name a place the reader can go, in the
   note's own words. So it takes the frame's own bar and the body's own size:

   - `border-left` from `--idea-rule-width` and the `--idea-border-color` chain, so
     it is the SAME bar an idea and a window draw down their left edge. It was a
     hardcoded `1px solid rgba(128, 128, 128, 0.4)` — a grey hairline that read as
     a different system from every other rule on the page, and ignored a theme.
   - `padding-left` from `--idea-pad`, so the text starts exactly where an open
     idea's or window's text starts. It was `1.25em`, which is more than twice the
     indent and, having no narrow-screen value of its own, stayed 1.25em on a phone
     where everything around it had halved.
   - `font-size: 1rem`, NOT `1em`, and no colour of its own. `1em` is a no-op — it
     means "whatever I inherit", which inside `.idea-footer` is that block's 0.85em.
     MEASURED: the row came out 13.6px, and `--idea-pad`'s `0.5em` measured against
     THAT gave 6.8px of padding instead of 8px, so the text missed an open idea's
     text by 1.2px. Root-relative fixes both at once: the row reads at body size and
     its indent is the same 8px every frame uses. */
.idea-page-row {
  border-left: var(--idea-rule-width, 2px) solid var(--idea-border-color, var(--idea-link-color, rgba(128, 0, 255, 0.12)));
  padding: 2px var(--idea-pad, 0.5em) 2px var(--idea-pad, 0.5em);
  margin-bottom: 0.4em;
  font-size: 1rem;
}

/* Typst wraps every `#window` in a <figure>, and the browser default for that is
   `margin: 1em 40px` — which would push every backlink row 40px off the label
   above it, and off the page rows beside it, which carry no such margin.
   Scoped to the footer deliberately: on an ordinary page that indent is a
   reasonable way for a transclusion to read, and undoing it there would be a
   look this package has no business choosing. The rows bring their own
   vertical spacing (`.idea-window-details`), so the wrapper needs none. */
.idea-footer figure {
  margin: 0;
}

/* Sized to the footer, not to the note: these are labels on an index, not
   sections of the document. Light and letterspaced so they read as a label
   for what follows without competing with the folded rows, which are bold.
   The bottom margin is the gap between the label and the rows under it. */
.idea-footer-title {
  margin: 0 0 0.5em 0;
  font-size: 1em;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--idea-date-color, gray);
}

/* ---- #idea — a note where it was written ---------------------------------
   A light left rule, blockquote-fashion, so a new note is visible as a note
   without a box, a background or a heading style doing the work. Same neutral
   grey as the footer rule, at 1px: enough to follow down the margin, not
   enough to compete with the text.

   `#idea` wraps itself in a <figure> (the marker element the package uses to
   find notes again), and the BROWSER indents that by 40px on both sides by
   default — nothing here asked for it, and nested notes compound it. Halved
   to 20px, and moved off the figure onto the note itself so the rule sits at
   the text margin with the body indented from it, which is what makes it read
   as a blockquote rather than as an indented box with a stripe.

   `:has()` is what lets a package stylesheet touch ONLY its own figures, with
   no class to hook (Typst emits a bare <figure>). Where it is unsupported —
   some EPUB readers — the figure keeps its 40px and the note sits further in
   than intended, with the rule and everything else intact. A worse indent, not
   a broken layout. */
figure:has(> .idea-box),
figure:has(> .idea-window),
/* A `#window` that BOTTOMED OUT at its depth budget is wrapped in a figure like any
   other window, but its content is a `ul.idea-page-list` rather than an
   `.idea-window` — so it matched neither selector above and kept the UA's
   `margin: 1em 40px`. MEASURED on rookery.ohrg.org: the row's bar sat at x=364.5
   where an `.idea-box` on the same page sat at 304.5, 60px out, which read as a
   deeply indented aside rather than as the frame's own row. */
figure:has(> .idea-page-list) {
  margin-left: 0;
  margin-right: 0;
  /* ROOM FOR THE LIFTED ID. The tab is pulled up by a negative margin, which does
     not make this figure any taller, so the id overflows UPWARD out of the box and
     into whatever precedes it. It used to overflow by half a label and land in the
     preceding paragraph's own margin; now that it clears the border entirely it
     overflows by a whole one, so the figure owes it the difference — MEASURED, the
     11.45px gap from preceding text to the id would otherwise fall to about 6.9px.

     PADDING, NOT MARGIN, and this is the trap: a `margin-top` here COLLAPSES with
     the preceding paragraph's `margin-bottom` (16px by default) and would do
     nothing at all. */
  /* The `+ 1px` matches the extra 1px of lift the tab now carries (see the label's
     `margin-bottom`), so raising the id did not quietly spend the clearance above
     it — MEASURED, the 11.44px gap to preceding text fell to 10.44px without it. */
  padding-top: calc(0.5 * var(--idea-label-size, 0.57rem) + 1px);
}

/* WINDOW AFTER WINDOW GETS A GAP, and it has to be said three times because a
   run of windows reaches the page in three different shapes:

     - `#window((<a>, <b>, <c>))`, the array form, emits several `.idea-window`
       divs inside ONE figure. They are plain siblings with nothing between them,
       so they abutted — MEASURED on rookery.ohrg.org's own `ideas/windows.html`,
       where two windows met with no space at all.
     - two separate `#window` calls each get their own figure, which took the
       browser's 1em figure margin: a gap, but a much larger one than the array
       form, so the same sequence read differently depending on how it was
       written.
     - inside a minted page's footer every figure margin is zeroed (see
       `.idea-footer figure` above), which is right for the label above the list
       and wrong between the backlink windows in it.

   One value for all three, so a run of windows looks like a run of windows
   however it was authored.

   `rem`, NOT `em`, and that is the whole reason minted pages used to look
   different. MEASURED across three real pages, when this was `0.5em`:

     rookery.ohrg.org, a minted page's Backlinks   6.8px margin, 11.34px gap
     rookery.ohrg.org, an ordinary page            8px    margin, 20.55px gap
     maths.ohrg.org, the homepage feed             10.67px margin, 28.13px gap

   Three different gaps for the same rule, because `em` reads whatever font-size
   it lands in: `.idea-footer` sets `0.85em`, so a minted page's backlink list
   was spaced by 0.85 of a gap, and a site with a 16pt body got a third more than
   one with a 16px body. The gap between two stacked cards is page rhythm, not
   text spacing — it should not shrink because the text around it did.

   1rem puts an ordinary page and a minted page at ~20.6px ALIKE, where they were
   20.55px and 11.34px: an ordinary page keeps the rhythm it already had, and a
   minted page's backlinks stop being three-quarters of it. Tried 1.5rem first,
   matching maths.ohrg.org's own 28.13px, and it read as too much once every page
   had it.

   IT ONLY BITES WHERE IT EXCEEDS THE FIGURE MARGIN IT COLLAPSES WITH, which is
   worth knowing before tuning it again. Adjacent figures collapse their vertical
   margins and the larger wins, so this competes with the UA's own
   `figure { margin: 1em }` on the card above. MEASURED at `1rem`:

     rookery.ohrg.org, ordinary page   UA 1em = 16px, ours 16px -> 20.55px gap
     rookery.ohrg.org, minted page     footer zeroes the UA margin -> 20.55px gap
     maths.ohrg.org (16pt body)        UA 1em = 21.33px WINS -> 28.13px gap

   So on a site whose body is larger than 16px this value is swallowed and the gap
   is the UA's; the minted page is the one case where it acts alone, because
   `.idea-footer figure` zeroes the margins around it. That is exactly the case
   that was wrong, and fixing it is what this value is for.

   It also has to pay for the id now. Since a note's id sits ABOVE its box rather
   than through the border, the next card's id overhangs into this gap by a whole
   label — at the default that is 9.12px of the 20.6px, which is why the old
   `0.5em` left a run of ids crowding the floor of the card above. */
.idea-window + .idea-window,
figure:has(> .idea-window) + figure:has(> .idea-window),
.idea-footer figure + figure {
  margin-top: 1rem;
}

/* A note and a transclusion of one indent identically, from a rule in the same
   place: they are the same kind of thing, and a `#window` that sat further in
   than the note beside it would read as subordinate to it rather than as
   another note. Nesting still shows, because a window inside a note starts from
   the note's own content edge and adds its rule there — one more rule per
   level, rather than one ever-growing indent. */
.idea-box,
.idea-window,
.idea-head {
  /* ONE VARIABLE FOR THE INDENT, because four rules have to agree about it and a
     fifth just proved they can silently stop agreeing: this padding, the tab's
     `margin-left` that cancels it, `::before`'s width that spans it, and a folded
     window's wash that reaches back across it. The mobile block below halves THIS
     and they all follow — MEASURED, the wash still carried a hardcoded `0.75em`
     and spilled 6px past the frame at 390px wide while the padding beside it was
     6px. Declared on `.idea-head` too, so a MINTED page's tab (not inside a card)
     inherits it rather than falling back to the literal. */
  --idea-pad: 0.5em;
}

/* A CARD'S head must DEFER to the card rather than re-declare the default over it.
   The rule above names `.idea-head` for the minted page's sake, but inside a card
   that element sits INSIDE `.idea-box` — so it shadowed the value the theme sets as
   an inline property on the card itself. MEASURED with `theme: (pad: 2em)`: the
   card's stub came out 11px instead of 35px and its tab started at the content edge
   instead of the frame's, i.e. the corner came apart while the window's held.
   Two classes beats one, so this wins over both the rule above and the
   narrow-screen override, and what it inherits is whichever of those applies to the
   card itself. */
.idea-box > .idea-head {
  --idea-pad: inherit;
}

.idea-box,
.idea-window {
  border-left: var(--idea-rule-width, 2px) solid var(--idea-border-color, var(--idea-link-color, rgba(128, 0, 255, 0.12)));
  padding-left: var(--idea-pad, 0.5em);
}

/* An idea's heading is an <h2>–<h6> (`#idea`'s `level:` + 1) and would
   otherwise take the host site's heading margins, which are sized for section
   headings — a note's own name announcing itself as loudly as the section it
   sits in. Half that (0.75em against the ~1.5em a site typically gives a
   heading), which is the gap this package wants above a note.

   No `margin-bottom` here: the space between a note's name and its first line
   is the site's typography to set, and only the space ABOVE the note is about
   how notes sit in a column. Set `--idea-heading-margin-top` in your own
   stylesheet to go back to your site's scale (or anywhere else). */
h2.idea,
h3.idea,
h4.idea,
h5.idea,
h6.idea {
  margin-top: var(--idea-heading-margin-top, 0.75em);
}

/* ---- #window — a transcluded note -----------------------------------------
   The block gets a faint hover tint, which is what signals "this folds"; the
   disclosure marker is hidden (below), so without the tint the summary would
   look inert. Forester does exactly this. */
/* Radius on the RIGHT corners only: the hover tint wants softening, but the
   left edge is now a rule that has to line up with the one on `.idea-box`
   above and below it, and a rounded 1px border bows away from that line.
   `padding-left` comes from the shared rule above — only the other three
   sides are set here. */
.idea-window {
  border-radius: 0 5px 5px 0;
  padding-top: 2px;
  /* THE SAME `--idea-pad` as the left indent, not a literal of its own: a window's
     content sits the same distance from the rule on its left as from its right
     edge, and one variable is what keeps that true when a project retheme's it. */
  padding-right: var(--idea-pad, 0.5em);
  padding-bottom: 2px;
}

.idea-window:hover {
  background-color: var(--idea-fold-color, rgba(0, 100, 255, 0.05));
}

/* `#idea-body`'s wrapper carries this SECOND CLASS to opt out of the box —
   border, padding, radius, hover tint — while keeping every rule above that
   is keyed to `.idea-window` alone: link colours, raw/code styling,
   footnote/reference layout. `#idea-body` renders a note's body with no
   chrome by design (see its own doc comment in lib.typ), and a consumer
   embedding that body somewhere with a box of its own — `@rheo/rookery-
   search`'s preview pane, say — should not also get THIS box nested inside
   it.
   TWO CLASSES, not a new selector list added to every rule above: this file
   is UNLAYERED throughout, so a plain `.idea-window-plain { border: none }`
   written by a downstream package (even inside ITS OWN `@layer`) can never
   beat an unlayered rule here regardless of specificity — MEASURED. Winning
   requires either matching unlayered specificity, or being MORE specific
   within this same unlayered sheet; `.idea-window.idea-window-plain` is the
   latter, and lives here rather than fighting the cascade from outside it. */
.idea-window.idea-window-plain {
  border-left: none;
  padding: 0;
  border-radius: 0;
}

.idea-window.idea-window-plain:hover {
  background-color: transparent;
}

/* Marker hidden in both spellings — `::marker` for standards-mode browsers,
   `::-webkit-details-marker` for older WebKit, and `list-style: none` on the
   summary itself, which is what actually suppresses it in Safari. The summary
   is the click target as a WHOLE, so a triangle at one end would misdescribe
   where the reader may click.

   `flex` (+ `align-items: baseline`) keeps the row's items on one text baseline
   despite their different weights and sizes. The DATE is no longer one of them —
   it moved into the hat, which is its own flex container and does the
   `margin-left: auto` push itself (see `.idea-tab > .idea-date`) — so this row is
   now the tab on its own line above a bold title, and nothing else. */
.idea-window-summary {
  display: flex;
  /* The tab is now the first item in this row, and without wrapping it would sit
     on the same line as the title instead of above it. */
  flex-wrap: wrap;
  align-items: baseline;
  list-style: none;
  cursor: pointer;
}

/* Its own line above the title, not another item in the title's row. */
.idea-window-summary > .idea-tab {
  flex: 0 0 100%;
}

/* A FOLDED window says so at rest. Closed, a `#window` is its summary row and
   nothing else, and the only sign a body is behind it was the hover tint — which
   a reader has to find with a pointer, and which does not exist at all on a touch
   device or for someone tabbing past. This rule under the summary, the full width
   of the window's content, is the boundary that says "there is more here".
   Complementary to the tint rather than a replacement: the tint says the row
   RESPONDS, the rule says there is CONTENT.

   IT IS THE FLOOR TO THE TAB'S HAT. The hat (`.idea-tab::before` above) reaches
   back across the card's own `padding-left` PLUS the width of the left rule, so it
   lands on that rule's OUTER edge and the corner has no notch in it; the floor is
   the same frame closed at the bottom, and it gets there by being the window's own
   `border-bottom` rather than by reaching:

     -[idea:etal]-        <- the hat, out of the corner, stopping at the id
     |
     | Note title
     +-------------       <- the floor, out of the same corner, full content width

   Two frames' worth of arithmetic in one place, so the two ends cannot drift:
   both use `calc(0.75em + var(--idea-rule-width, 2px))`.

   Keyed to `:not([open])` and not to a class emitted at build time, because
   `folded: true` sets only the INITIAL state — a reader can click it open, and the
   rule has to leave with the disclosure and come back when it shuts. `[open]` is
   present exactly when the body shows, so the browser does that for free, with no
   JS and nothing for `#window` to emit.

   The CHILD combinator is load-bearing: a window nested inside another window's
   body has a summary of its own, and a descendant selector would let a closed
   OUTER window draw a rule under an INNER one's summary too.

   `--idea-rule-width`, THE FRAME'S OWN THICKNESS, because that is what this line
   is. It closes the box the left rule and the tab open, so it is the fourth side
   of a frame rather than a separator laid across content — the distinction the
   header above draws when it excludes the footnotes/references rules from this
   property. One consequence and it is the point: a project setting
   `#show: rookery.with(rule-width: ...)` moves the floor with the left rule, the
   tab and `#ideas-outline`'s markers, so a heavier or lighter frame stays one
   system instead of three-quarters of one.

   TWO PROPERTIES, EACH DOING WHAT IT IS FOR. The floor is `--idea-border-color`,
   the frame colour, because a boundary is what it is. The folded row also takes
   `--idea-fold-color` as a BACKGROUND WASH, which is the colour that already means
   "this folds" — `.idea-window:hover` paints exactly it. So a folded window reads
   as pre-hovered: the affordance is on the row at rest instead of waiting for a
   pointer that a touch device does not have.

   THE WASH, NOT A FOLD-COLOURED LINE, and this is measured rather than taste.
   `--idea-fold-color`'s default is `rgba(0, 100, 255, 0.05)` — 5% alpha, tuned for
   a large background — and MEASURED as a 1px border it composites to
   `rgb(242, 247, 255)` on white, a delta of 13/8/0 and about 1.04:1 contrast:
   invisible, which is the opposite of the point. The same 5% across the whole row
   reads fine, because area is what a 5% wash needs. Alpha that is too low for a
   hairline is exactly right for a wash.

   Hovering a folded window therefore paints the wash twice — once here, once from
   `.idea-window:hover` behind it — compositing to about 9.75%. That is deliberate:
   hover still does something, it just deepens a tint that is already there.

   Inert everywhere it should be: `[open]` exists only in HTML, so the paged
   target (where `folded` is ignored and the body always shows) never sees this,
   and `#idea-body` emits no `<details>`/`<summary>` at all. */
/* THE FLOOR IS THE WINDOW'S OWN BOTTOM BORDER, not a rule under the summary, and
   that is what makes it line up. Two borders of the SAME box meet at their corner
   by construction — no arithmetic, nothing to drift — so the floor ends exactly
   where the left rule ends, and it inherits the box's `border-radius` at the
   bottom-right for free. A `border-bottom` on the summary instead sits one
   `padding-bottom` short of the frame's bottom, and no amount of reaching sideways
   fixes a vertical mismatch.
   `padding-bottom: 0` while folded closes that gap from the other side, and
   `.idea-window-details:not([open])` gives up its own `margin-bottom` for the same
   reason — MEASURED, that margin is `0.2em`, 3.2px at a 16px root, and it sat
   between the wash and the floor as an untinted seam. With both gone the summary's
   bottom IS the floor's top, so the tint runs into the rule. `:has()` is already how this sheet scopes to its own
   figures (see `figure:has(> .idea-window)` above); where it is unsupported a
   folded window simply keeps today's appearance. */
.idea-window:has(> .idea-window-details:not([open])) {
  border-bottom: var(--idea-rule-width, 2px) solid var(--idea-border-color, var(--idea-link-color, rgba(128, 0, 255, 0.12)));
  /* NO PADDING EITHER END. `padding-bottom` so the wash meets the floor;
     `padding-top` so it meets the HAT — MEASURED, that 2px was a visible gap
     between the top of the tint and the rule above it. The paired tab override
     below drops the lift's own +2px, which existed only to clear this padding. */
  padding-top: 0;
  padding-bottom: 0;
  /* SHARP, overriding `.idea-window`'s own `0 5px 5px 0`. That radius exists to
     soften a hover tint on an open block; a folded window is a closed box, and a
     rule that turns a corner reads as a curve rather than as the frame meeting
     itself. Folded only — an OPEN window keeps its rounded right corners. */
  border-radius: 0;
}

/* THE WASH stays on the SUMMARY rather than joining the floor on `.idea-window`,
   and the reason is `:hover`. `.idea-window:hover` paints the same
   `--idea-fold-color` on the window; put the resting wash on that same element and
   the two rules fight over one property — this selector is the more specific, so
   hover would stop doing anything visible at all on a folded window. On separate
   elements they COMPOSITE instead: about 9.75% under the pointer against 5% at
   rest, so hover still deepens what is already there.
   Both ends reach the frame so the wash spans the floor's full length: left to the
   rule's outer edge (the hat's arithmetic, above), right across the window's own
   `padding-right`. No radius on it: the folded window is square (see above), so
   the wash has no rounded corner to stay inside of.

   SUB-PIXEL AT A FRACTIONAL `rule-width`, and it is the same wart `.idea-tab`'s
   stub carries, from the same arithmetic. MEASURED with
   `rookery.with(rule-width: 5pt)`: the calc subtracts 6.67px where the browser
   renders the border at 6px, so the wash's left edge lands 0.66px OUTSIDE the
   frame. Invisible at 5% alpha and it cannot be fixed here without moving the
   wash onto `.idea-window`, which is what the hover paragraph above rules out.
   Whole-pixel widths — including the 2px default — line up exactly. */
.idea-window-details:not([open]) > .idea-window-summary {
  background-color: var(--idea-fold-color, rgba(0, 100, 255, 0.05));
  /* Back to the border's INNER edge, NOT its outer one — the rule's own width is
     deliberately left out of this reach. MEASURED: pulling the wash under the
     2px border made a translucent border composite over the tint, so the folded
     window's left rule came out rgb(227, 217, 255) against the rgb(240, 224, 255)
     of the hat directly above it and of every other rule on the page. Two frame
     pieces that are one colour everywhere else must not part company here. Ending
     at the inner edge leaves the border painting on the page, as it does in a card,
     and the tint starts where the content does. */
  margin-left: calc(-1 * var(--idea-pad, 0.5em));
  padding-left: var(--idea-pad, 0.5em);
  margin-right: calc(-1 * var(--idea-pad, 0.5em));
  padding-right: var(--idea-pad, 0.5em);
  /* BALANCE, and it is a different sum now the id sits ABOVE the border. The tab
     is lifted clear of the box, so what remains inside it above the title is the
     tab's own `margin-bottom` (0.25em) and nothing else — the window's 2px
     `padding-top` is gone too (above). Matching that below gives the title equal
     air on both sides. MEASURED before this: 4px above, 8.55px below, which read
     as bottom-heavy exactly as reported.
     It goes on the SUMMARY, not on `.idea-window`'s `padding-bottom`: the wash is
     the summary's background, so padding here is tinted and still meets the floor,
     where window padding would reopen the untinted seam. */
  padding-bottom: 0.25em;
}

.idea-window-summary::marker,
.idea-window-summary::-webkit-details-marker {
  display: none;
}

.idea-window-title {
  font-weight: bold;
}

/* The note's date, at the FAR RIGHT OF THE HAT — the same object in the same place
   on a card, in a `#window`'s summary, and on a minted note page, so it wears one
   class in one rule. It used to be two: `.idea-window-date` in a window's summary
   row and `.idea-date` inside `#idea`'s own heading, which is why the id it
   belongs beside sat in a third place again.

   Same grey/light treatment as `.idea-label`, and the same size through the same
   property: a date and an id are the two ends of one rule, so they have to be one
   size or the pair reads as two kinds of thing. Setting `--idea-label-size` moves
   both together, which is the only sane way for them to move.

   `margin-left: auto` soaks up the hat's remaining space, pushing the date to the
   frame's right edge while the id stays packed against the stub on the left. It is
   scoped `.idea-tab > .idea-date` rather than left on the class, because the hat is
   the flex container that makes `auto` mean anything — a `.idea-date` anywhere else
   would simply be a nowrap grey span, which is the right thing to degrade to.

   `--idea-window-date-margin` IS GONE, not renamed. It existed to undo the
   push-right for a window's summary specifically (its default WAS `auto`), back
   when the date shared a flex row with the title; the hat has no equivalent need,
   and a project that wants the date to flow after the id instead can say
   `margin-left: 0.5em` in its own CSS without a property to discover.

   MEASURED (chromium headless, 900px viewport): the date's right edge lands on the
   card's own right edge — `dateRight` 770.00 against `boxRight` 770.00 — including
   on a card carrying eight tags. The top rule deliberately does NOT resume on the
   date's far side: the hat draws ONE stub, to the left, and stops at the id (see
   `.idea-tab`), so a date floating free at the right end of the frame is the
   intended look. */
.idea-date {
  color: var(--idea-date-color, gray);
  font-weight: 200;
  font-size: var(--idea-label-size, 0.57rem);
  white-space: nowrap;
}

.idea-tab > .idea-date {
  margin-left: auto;
}

/* An open window needs more room beneath it than a closed one, or a column of
   folded windows reads as one undifferentiated block. */
.idea-window-details {
  margin-bottom: 0.2em;
}

/* FOLDED, the window's own `border-bottom` is the floor and this margin would sit
   between the summary's wash and that rule as an untinted seam — see the folded
   rule above. Nothing needs the gap here: with the body hidden there is nothing
   below the summary to be spaced away from. */
.idea-window-details:not([open]) {
  margin-bottom: 0;
}

.idea-window-details[open] {
  margin-bottom: 0.5em;
}

/* ---- Footnotes — an idea's own, not the page's ----------------------------
   `#footnote` inside an idea numbers against THAT idea and lists its bodies
   here, at the end of the idea, so two notes on one page may each carry a
   footnote 1. The block follows the idea to every surface it appears on — its
   hatch page, every `#window` on it, its minted page — and each of those gets
   its own copy with its own anchors, because a footnote reference is a
   same-page fragment.

   Subordinate, not sectional: smaller than body text, a hairline above to
   separate it from the prose it belongs to, and aligned to the note's TEXT
   margin rather than sitting out at the note's left rule. It is apparatus for
   the note, not a division of the document.

   Nothing here is load-bearing: the reference and its body are an ordinary
   pair of same-page anchors and work with this stylesheet absent. */
.idea-footnotes {
  margin-top: 1em;
  padding-top: 0.4em;
  border-top: 1px solid var(--idea-border-color, var(--idea-link-color, rgba(128, 0, 255, 0.12)));
  font-size: 0.85em;
}

/* An <h4> for document-outline correctness, styled so it does not read as one.
   Size and margins are set explicitly rather than left to inherit: a site's own
   heading scale would otherwise make "Footnotes" compete with the note's title
   directly above it.

   NOT A HAT, and deliberately not. `#ideas-outline`'s title became one (see
   `.idea-outline-title`, which this rule used to be pinned to) because it labels the
   FRAME it sits on. This labels a LIST inside a note that already has its own frame,
   and the separator above it is an apparatus rule rather than a note's edge. Do not
   give it a tab to match. */
.idea-footnotes-title {
  font-size: 1em;
  font-weight: 600;
  margin: 0 0 0.3em;
}

/* The <ol> numbers itself, and each <li> carries the id its reference points
   at — so no ::marker games and no hand-drawn numbers. `padding-left` keeps the
   digits inside the block rather than hanging into the rule at its left. */
.idea-footnote-list {
  margin: 0;
  padding-left: 1.5em;
}

.idea-footnote {
  margin: 0.15em 0;
}

/* The inline reference. `line-height: 0` stops the superscript from opening up
   the line it sits in, which is the usual defect of a raw <sup> in body text. */
.idea-fn-ref {
  line-height: 0;
}

/* The way back up to the reference. Grey and light like the permalink, because
   it is the same kind of thing: a small navigational mark beside content rather
   than part of it. It takes the shared link hover above, so it is not restyled
   here. */
.idea-fn-backlink {
  color: var(--idea-id-color, gray);
  text-decoration: none;
  margin-right: 0.3em;
}

/* ---- References — one bibliography per idea, and the page's own -----------
   Typst partitions citations positionally, so rookery emits one bibliography
   per idea (`.idea-references`) and, where a page cites outside any idea, one
   for the page (`.idea-page-refs`).

   Every rule here is scoped under one of those two classes, never under a bare
   `section[role="doc-bibliography"]`: this stylesheet is injected into every
   page of a rheo project, and a project may have a bibliography of its own that
   this package has no business restyling. Typst renders the <section>, its
   heading and its <ul>, and adds `class="hanging-indent"` under some styles —
   all of that is left alone.

   An idea's block is apparatus for that idea, exactly like its footnotes above:
   smaller than body text, hairline above, aligned to the note's text margin. */
.idea-references {
  margin-top: 1em;
  padding-top: 0.4em;
  border-top: 1px solid var(--idea-border-color, var(--idea-link-color, rgba(128, 0, 255, 0.12)));
  font-size: 0.85em;
}

/* Typst emits an <h2>. Sized explicitly so a site's own heading scale cannot
   let "References" compete with the note's title above it — the same reason
   `.idea-footnotes-title` is pinned. */
.idea-references h2,
.idea-page-refs h2 {
  font-size: 1em;
  font-weight: 600;
  margin: 0 0 0.3em;
}

/* `padding-left: 0` because the entries carry no markers (Typst sets
   `list-style-type: none` inline) and an author-date style has no numbers to
   hang — indenting would leave the list floating away from the rule above it. */
.idea-references ul,
.idea-page-refs ul {
  margin: 0;
  padding-left: 0;
}

.idea-references li,
.idea-page-refs li {
  margin: 0.15em 0;
}

/* THE SWEEP BLOCK, and why this is `:has(li)`.
   `#idea` emits a title-less `.idea-page-refs` BEFORE itself, unconditionally,
   to claim prose citations written above it. It cannot know whether there are
   any — an idea never sees the prose around it, and asking by query is
   circular (see `_sweep-block` in lib.typ). Almost every one is therefore
   empty, and an empty one must occupy NO vertical space, or every idea on the
   page gains a phantom gap above it.

   So the wrapper carries nothing by default and `:has(li)` adds the spacing and
   the rule only when the block lists something. One rule covers all three
   users of the class: an empty sweep (invisible), a sweep that did catch a
   prose citation, and the page's own trailing-citation block.

   Where `:has()` is unsupported the block renders flush and its entries stay
   readable — the same bargain the `figure:has(> .idea-box)` rule above makes. */
.idea-page-refs {
  margin: 0;
  font-size: 0.85em;
}

.idea-page-refs:has(li) {
  margin-top: 1.5em;
  padding-top: 0.4em;
  border-top: 1px solid var(--idea-border-color, var(--idea-link-color, rgba(128, 0, 255, 0.12)));
}

/* ---- #ideas-outline — a page's own notes, as a tree ------------------------
   Wears the same left rule as `.idea-box`/`.idea-window`, from the same
   custom property, so a page's table of contents reads as part of the same
   apparatus as the notes it lists rather than as a stray browser list above
   them. Nesting works the way it does for notes, too: each level adds its own
   rule at the previous level's content edge — one more rule per level, not
   one ever-growing indent.

   The theme reaches this via inline custom properties on the OUTERMOST <ul>
   only (see `_nest-outline` in lib.typ). An outline is a sibling of the
   notes, not a descendant of one, so it is the only thing this package emits
   that has no themed ancestor to inherit from.

   `padding-left` is larger than `.idea-box`'s `.75em` because the row's
   marker lives in it: 0.75em of rule plus 0.5em of gap before the text. */
/* "Contents", above an outline, AND IT IS A HAT — the same object a note's id is,
   drawn the same way: a stub of rule out of the top-left corner with the label
   sitting on its end. The element carries `idea-tab` as well as this class (see
   `#ideas-outline` in lib.typ), so the flex box and the `::before` stub come from
   the tab rules above, and only the differences live here.

   IT IS NO LONGER A SIBLING OF `.idea-footnotes-title`, which it used to be pinned
   to, in size and weight, on the grounds that both label a block of apparatus. That
   claim is now true of that one and false of this one: an outline's title is part of
   the outline's FRAME; a footnotes title is a label above a list. That rule keeps its
   own `1em`/`600` deliberately — see the note there.

   THE REACH-BACK ARITHMETIC DOES NOT ARISE, which is worth stating because the
   card's version of it is delicate. A card's tab sits INSIDE the padded box, so its
   stub needs a negative `margin-left` and a width spanning `--idea-pad` plus the
   rule to reach back out to the corner. This title is a SIBLING of the `<ul>`, above
   it, so its left edge already IS the `<ul>`'s left edge: the stub starts on the
   rule's outer edge with no cancellation at all, and `.idea-tab::before`'s width is
   simply how long the stub looks.

   THAT IS ALSO WHY `.idea-outline`'s `padding-left` STAYS `1.25em` rather than
   adopting `--idea-pad`. The hat does not read it, and the three outline values are
   one geometry — the row marker's `width` plus its `margin-right` IS that padding,
   and its `margin-left` is the negation of it (see the mobile block). Moving it
   would move every row's marker to buy a consistency nothing now depends on.

   THE CORNER CLOSES VERTICALLY BY GIVING UP THE GAP. `align-items: flex-end` puts
   the stub on the line's bottom, which is this element's box bottom, so the rule
   lands exactly on the `<ul>`'s top edge only while nothing separates them — hence
   `margin: 0` here and `margin-top: 0` on the list below. The air that used to be
   this element's `margin-bottom` moves to the list's `padding-top`, INSIDE the
   border, where it cannot push the rule away from the corner.

   UPPERCASE ASSERTED, NOT INHERITED. `rookery.ohrg.org` sets
   `h1..h6 { font-variant: small-caps }`, and any site with a heading rule may do the
   same, so both halves are stated here on the package's own class — which beats an
   element selector on specificity — rather than left to chance. */
.idea-outline-title {
  /* THE LABEL SIZE, the same property an id reads, because they are one object.
     This replaces a `0.85em` that existed to match `.idea-footnotes-title`. */
  font-size: var(--idea-label-size, 0.57rem);
  font-family: var(--idea-label-font, monospace);
  font-variant: normal;
  text-transform: uppercase;
  font-weight: 600;
  /* `1`, so the box collapses to the label's own height and the stub sits on the
     label's own line bottom rather than on the host page's leading — the same
     reason, and the same value, as the card's tab. */
  line-height: 1;
  align-items: flex-end;
  /* Half the generic tab's gap, as a card's and a window's hats take: the label
     reads as sitting ON the end of the rule rather than floating past it. */
  gap: 0.15em;
  margin: 0;
}

.idea-outline-title + .idea-outline {
  margin-top: 0;
  /* The air under the hat, moved off the title — see the corner note above. */
  padding-top: 0.4em;
}

.idea-outline {
  list-style: none;
  margin: 0.4em 0;
  padding-left: 1.25em;
  /* 2px, the same weight as `.idea-box`/`.idea-window`'s rule: an outline is the
     page's notes listed, and its rule is the same object as theirs. Two weights
     on one page read as two different systems. */
  border-left: var(--idea-rule-width, 2px) solid var(--idea-border-color, var(--idea-link-color, rgba(128, 0, 255, 0.12)));
}

/* A nested list is already indented by its parent row; it needs separating
   from the row above it, not from the list as a whole. */
.idea-outline-row > .idea-outline {
  margin: 0.25em 0 0.4em 0;
}

.idea-outline-row {
  margin-bottom: 0.25em;
}

/* THE BULLET, at every level: a short rule rather than a disc, in the same
   colour as the rule it grows out of. The negative `margin-left` is the
   negation of the list's `padding-left`, which puts the hairline's own left
   end exactly ON that rule — so the marker reads as a tick off the rule, the
   two cannot drift apart when the padding changes, and a row that wraps hangs
   its later lines at the text edge rather than under the marker.

   Drawn as a `border-top` on a zero-height box rather than as a glyph in
   `::marker`: the marker is a RULE, matched to the outline's own at 2px
     whatever the font, and `::marker` accepts
   `content` in far fewer readers than `::before`, and a disc scaled down to
   look like a rule is at the mercy of the font's own bullet metrics. Where
   `::before` is unsupported the rows simply lose their markers — the rule and
   the indent still carry the structure.

   IN FLOW, not `position: absolute`, and that is what `vertical-align:
   middle` buys: it puts a zero-height box at the parent's baseline plus half
   its x-height, i.e. exactly through the middle of a lowercase letter, from
   the FONT's metrics rather than from a guessed `top` offset that a host
   page's line-height would throw off. */
.idea-outline-row::before {
  content: "";
  display: inline-block;
  vertical-align: middle;
  width: 0.75em;
  height: 0;
  margin-left: -1.25em;
  margin-right: 0.5em;
  /* 2px, matching the rule it grows out of. A 1px marker on a 2px rule reads as
     a different, thinner kind of line rather than as a branch off that one. */
  border-top: var(--idea-rule-width, 2px) solid var(--idea-border-color, var(--idea-link-color, rgba(128, 0, 255, 0.12)));
}

/* ---- Narrow screens: half the indent ---------------------------------------
   The indent COMPOUNDS. Every nesting level adds another rule and another
   padding at the previous level's content edge, which is what makes structure
   legible on a wide column and what makes it expensive on a phone: a note three
   deep on a 375px screen has given up a visible fraction of its measure to
   apparatus before a word is set. Halving the horizontal spacing buys that back
   without flattening the structure — the rules are all still there, one per
   level, just closer together.

   600px, and not a number invented here: it is the breakpoint
   `rookery.ohrg.org` already uses, and the site that renders this package
   agreeing with the package is worth more than a rounder figure. It also
   leaves 601px and up — tablet and desktop — at exactly today's spacing, which
   is the point: the constraint being answered is phone width, not small
   screens in general.

   THE THREE OUTLINE VALUES ARE ONE GEOMETRY. Do not halve one without the
   others. `::before`'s `margin-left` is the negation of `.idea-outline`'s
   `padding-left` (that is what puts the hairline's left end ON the rule), and
   that same `padding-left` is the hairline's `width` plus its `margin-right`
   (that is what makes the text start exactly where the marker stops). Both
   survive halving — 0.375 + 0.25 = 0.625, and -0.625 negates 0.625 — but
   neither survives halving the padding alone, which detaches the bullet from
   the rule and looks, at a glance, merely a bit tighter.

   `border-left` deliberately does NOT halve: the rule is 2px at every width. A
   phone showing a 1px rule would read as a different design rather than a
   tighter one, and the fractional widths that halving invites render
   inconsistently across displays and on some not at all.

   THE INDENT NO LONGER HALVES AT ALL. It used to, and the reason it stopped is
   that the desktop value came down to `0.5em`: halving that gave `0.25em`, which
   is 4px — less than the 2px rule beside it plus the space a reader reads as
   separation, so a note's content sat almost on its own rule. `--idea-pad` is
   therefore `0.5em` at every width, and this block no longer touches it.
   Nothing else has to change with it: the tab's offset, `::before`'s width and a
   folded window's wash all READ the variable, so they follow whatever it is. That
   is the whole reason it became a variable — see its declaration. */
@media (max-width: 600px) {
  .idea-outline {
    padding-left: 0.625em;
  }

  .idea-outline-row::before {
    width: 0.375em;
    margin-left: -0.625em;
    margin-right: 0.25em;
  }
}
