/* ══ the reading sheet — the node path ═══════════════════════════════════════
   linked from src/layouts/Print.astro only, after site.css, and nothing but a
   print loads it. everything here is the post layout: the masthead plate, the
   offset node cards, the trace between them, and the marginalia that hangs off
   them. site.css keeps the site; this keeps the read.

   the shape, the owner's steer for v3.2: the body is no longer one sheet of paper.
   it is a path — a card at a time, each stepped left or right of the one above
   it, joined by a single orange trace with a dot at each junction. the ground
   is alive in the gaps, which is why the cards had to stop being one sheet.

   the geometry is four numbers (and two paddings) and they are all here:

     --card   the width of a card. its text measure plus its padding.
     --shift  how far a stepped card moves. the lane is --card + --shift, so
              the two sides of the path exactly fill it and nothing overflows.
     --pad-x  the card's own padding. the marginalia's negative margins are
              measured from the card's content box, so they need it.
     --x-in   how far in from a card's left edge the trace runs. it rides the
              padding band, left of the type, and the card numeral sets on it.

   src/lib/nodepath.mjs does the grouping and knows none of them: it emits
   sides `a`/`b` and turns `lr`/`rl` and leaves every distance here.
   ════════════════════════════════════════════════════════════════════════ */

.sheet-wrap {
  /* 38rem of card less 2rem of pad on each side is a 544px measure, which sets
     at about 68 characters in archivo at 17px. the old sheet ran 680px and
     about 85, which is a long line to walk back on a card this wide. */
  --card: 38rem;
  --shift: 4rem;
  --pad-x: 2rem;
  --pad-y: 1.75rem;
  --x-in: 1.15rem;
  --trace-h: 3.4rem;
}

/* the sheet stops being a sheet. it was the one plate on the page — paper
   under the whole read, with a hairline trim around it — and the cards have
   taken that job one at a time. what is left is a lane. */
.sheet {
  background: none;
  box-shadow: none;
}

/* the ground must be reachable between the cards. .body claimed the pointer
   for its whole rect, which was harmless while it was solid paper and is not
   now: in the gaps the thing under the cursor is the ground, and the ground
   is real selectable text. the cards take the pointer back for themselves. */
.sheet .body { pointer-events: none; }
.sheet .node,
.sheet .body .mnote,
.sheet .body blockquote,
.sheet .margin-rail { pointer-events: auto; }

/* the path and the trace are lane-wide, not measure-wide: site.css sets every
   direct child of .body to the old text measure. */
.sheet .body > .path,
.sheet .body > .trace { max-width: none; }

/* ── the masthead ──────────────────────────────────────────────────────────
   unchanged in spirit and in every type size — title, lede, folio, passes. it
   is a plate now instead of the top of a sheet, so it has to carry its own
   edge: the same hairline trim the cards have, and the same paper. */

.print-head {
  box-shadow: none;
  border: 1px solid var(--rule);
  padding: 2.2rem var(--pad-x) 1.6rem;
  margin: 0;
}

/* ── the cards ─────────────────────────────────────────────────────────────
   a sharp cutout: square corners, one hairline, the plate ground, and a
   comfortable pad. the offset is a margin, so a card is always exactly
   --card wide and the lane is always exactly --card + --shift. */

.path { position: relative; }

.node {
  position: relative;
  width: 100%;
  max-width: var(--card);
  background: var(--bg);
  /* .plate's half-em paper bleed would fog the cut edge and half-fill the
     gaps between cards with paper. the cards keep the class for the ground
     cap under them and drop the halo. */
  box-shadow: none;
  /* no visible trim: the owner's call, 2026-09-23. the border stays as a
     transparent pixel because the marginalia offsets count it. */
  border: 1px solid transparent;
  padding: 2.5rem var(--pad-x) var(--pad-y);
  margin: 0;
}
.node[data-side="b"] { margin-left: var(--shift); }

/* the card's number, set on the trace's line at the head of the card. it is
   the reading order made countable — the same job the section marks in the
   spine used to do, moved onto the thing being counted. */
.node::before {
  content: attr(data-n);
  position: absolute;
  top: .95rem;
  left: var(--x-in);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .16em;
  color: var(--dim);
  opacity: .7;
  font-variant-numeric: tabular-nums;
}

/* the first thing in a card sits at the top of it. h2 carries a rule and a
   two-and-a-half-em lead-in for a heading inside a column of prose; at the
   head of its own card both are a second edge under the first. */
.node-in > :first-child { margin-top: 0; }
.node-in > :last-child { margin-bottom: 0; }
/* an h2 always opens a card — nodepath.mjs splits on it — so its rule and its
   lead-in are both spent: the card's own top edge is the separation, and a
   second hairline half an inch under the first is just a mistake. it is not
   always the *first* child, because a margin note travels forward to sit
   beside the section it introduces, so this cannot be a :first-child rule. */
.node-in > h2 {
  border-top: 0;
  padding-top: 0;
  margin-top: 0;
}
.node-in > h3:first-child { margin-top: 0; }

/* a code block or a table runs the full width of the card. it is already a
   held-attention block and the card's pad is its margin. */
.node-in > pre,
.node-in > .table-scroll,
.node-in > table { max-width: none; }

/* ── the trace ─────────────────────────────────────────────────────────────
   one thin orange line from the bottom edge of a card to the top edge of the
   next, with an elbow across the step and a node dot at each junction. two
   pseudo-elements draw it: ::before is an L — the vertical out of the card
   above and the horizontal across the step — and ::after is the vertical down
   into the card below. exact verticals and horizontals, 1px, --acc, no svg
   and no script anywhere in it.

     --x1  where it leaves the card above, from the lane's left edge
     --x2  where it enters the card below

   both are one card inset (--x-in) from their own card's left edge, so the
   trace runs up the same band of every card in the path however it steps. */

.trace {
  position: relative;
  height: var(--trace-h);
  max-width: none;
  --x1: var(--x-in);
  --x2: var(--x-in);
}
.trace[data-turn="lr"] { --x1: var(--x-in); --x2: calc(var(--shift) + var(--x-in)); }
.trace[data-turn="rl"] { --x1: calc(var(--shift) + var(--x-in)); --x2: var(--x-in); }
/* the head of the path and its end. both run straight — the masthead and the
   colophon are lane-wide, so there is nothing to step around. the end sets on
   the stepped inset, which is the one x inside a card on either side. */
.trace[data-turn="start"] { --x1: var(--x-in); --x2: var(--x-in); }
.trace[data-turn="end"] {
  --x1: calc(var(--shift) + var(--x-in));
  --x2: calc(var(--shift) + var(--x-in));
}

.trace::before,
.trace::after {
  content: '';
  position: absolute;
}
/* the vertical out of the card above, and the horizontal across the step.
   the box is the span between the two x's; the border-bottom is the elbow. */
.trace::before {
  top: 0;
  height: 50%;
  border-bottom: 1px solid var(--acc);
}
.trace[data-turn="lr"]::before {
  left: var(--x1);
  right: calc(100% - var(--x2));
  border-left: 1px solid var(--acc);
}
.trace[data-turn="rl"]::before {
  left: var(--x2);
  right: calc(100% - var(--x1));
  border-right: 1px solid var(--acc);
}
/* straight: no elbow to draw, so the box has no width and no bottom rule */
.trace[data-turn="start"]::before,
.trace[data-turn="end"]::before {
  left: var(--x1);
  width: 0;
  border-bottom: 0;
  border-left: 1px solid var(--acc);
}
/* the vertical down into the card below */
.trace::after {
  top: 50%;
  bottom: 0;
  width: 0;
  left: var(--x2);
  border-left: 1px solid var(--acc);
}

/* the junctions. small squares, straddling the card edge the trace meets —
   sharp, like everything else on the path. */
.trace i {
  position: absolute;
  width: 5px;
  height: 5px;
  background: var(--acc);
}
.trace i:first-child { top: -3px; left: calc(var(--x1) - 2px); }
.trace i:last-child { bottom: -3px; left: calc(var(--x2) - 2px); }

/* ── the end of the path ───────────────────────────────────────────────────
   the colophon is the terminal node: the width of the lane, no step. the last
   card of a print may be on either side, so a card that stepped could not be
   promised a trace that lands on it — and a terminus that squares up under
   the path reads as an ending rather than as one more beat. */

.sheet > .trace[data-turn="end"],
.colophon.node-end {
  max-width: calc(100% - var(--gutter));
}
.colophon.node-end {
  margin: 0;
  padding: 2.5rem var(--pad-x) var(--pad-y);
}

.pager {
  box-shadow: none;
  border: 1px solid var(--rule);
  padding: 1.1em 1.2em;
  margin-top: 2.6em;
}

/* ── the marginalia ────────────────────────────────────────────────────────
   below 1100px every one of these reads inline inside its card, in order, and
   the rules for that are site.css's and unchanged. above it they hang off the
   card into the lane the sheet reserves, and both of those live down in the
   1100 block. what is here is what is true either way: hanging or folded, a
   note now sits over live ground and has to carry its own paper. */

.body .mnote,
.body blockquote.pull {
  background: var(--bg);
}

@media (min-width: 1100px) {
  /* the lane is the path's width, so the sheet is the path plus the reserved
     margin. site.css computes --gutter from the same three tokens, which is
     why only --sheet is restated here. */
  .sheet-wrap[data-margin="ruled"] {
    --sheet: calc(var(--card) + var(--shift) + var(--marg) + var(--marg-gap) + var(--spine));
  }
  .sheet-wrap[data-margin="bare"] {
    --sheet: calc(var(--card) + var(--shift) + var(--spine));
  }

  /* the press block hangs in the lane like a note and needs the same paper */
  [data-margin="ruled"] .margin-rail {
    box-shadow: none;
    background: var(--bg);
    border: 1px solid var(--rule);
    padding: .8em .9em;
  }
  /* with nothing riding, the press block is a slug line across the head of
     the lane instead of a column beside it — and the path starts under it, so
     it loses the three-em gap that used to hold it off the prose. the trace
     leaves its bottom rule the way it leaves any other card. */
  [data-margin="bare"] .margin-rail {
    box-shadow: none;
    background: var(--bg);
    border-top: 1px solid var(--rule);
    border-bottom: 1px solid var(--rule);
    padding: .7em .9em;
    margin-bottom: 0;
  }

  /* the section marks in the spine are retired. they counted the h2s from the
     edge of a single sheet; with the sheet gone they would be measuring from
     the edge of whichever card the heading happened to land in. the card
     numerals count the same thing, on the thing itself. */
  .sheet .body h2::before,
  .sheet .body h2::after { content: none; }

  /* the notes leave the card. site.css floats them out of .body; inside a card
     the same float has to clear the card's own padding as well, and a stepped
     card has to clear its step too — so both sides land on one column, flush
     to the same trim, whichever way their card stepped.

     the column is beyond the lane, never inside it. that is deliberate: a note
     that tracked its own card's edge would sit in the x-range of the card
     below it, and a card is a positioned box painted over any float. one
     column, no collisions, and the tie-line below says which card it belongs
     to. */
  [data-margin="ruled"] .node-in > .mnote,
  [data-margin="ruled"] .node-in > blockquote.pull {
    float: right;
    clear: right;
    width: var(--marg);
    max-width: none;
    margin-left: 0;
    /* the trailing 1px is the card's own border. without it the notes column
       sits one pixel inside the press block's, which is a visible jog in a
       page ruled this finely. */
    margin-right: calc(-1 * (var(--marg) + var(--marg-gap) + var(--pad-x) + 1px));
  }
  [data-margin="ruled"] .node[data-side="a"] .node-in > .mnote,
  [data-margin="ruled"] .node[data-side="a"] .node-in > blockquote.pull {
    margin-right: calc(-1 * (var(--marg) + var(--marg-gap) + var(--pad-x) + var(--shift) + 1px));
  }

  [data-margin="ruled"] .node-in > .mnote {
    margin-top: .35em;
    margin-bottom: 1.6em;
    border-left: 1px solid var(--rule);
    padding: .7em .9em;
  }
  [data-margin="ruled"] .node-in > blockquote.pull {
    margin-top: .35em;
    margin-bottom: 1.6em;
    font-size: 14px;
    line-height: 1.5;
    opacity: 1;
    border-left: 2px solid var(--acc);
    padding: .7em .9em;
  }
  [data-margin="ruled"] .node-in > blockquote.pull p { margin: 0 0 .6em; }
  [data-margin="ruled"] .node-in > blockquote.pull p:last-child { margin-bottom: 0; }

  /* the tie-line: a hairline from the card's edge to the note's, on the first
     line of the note. annotation grammar — it is the note saying which card it
     came out of, and it is how a note beside a stepped card still reads as
     attached across the wider gap. */
  [data-margin="ruled"] .node-in > .mnote,
  [data-margin="ruled"] .node-in > blockquote.pull { position: relative; }
  [data-margin="ruled"] .node-in > .mnote::before,
  [data-margin="ruled"] .node-in > blockquote.pull::before {
    content: '';
    position: absolute;
    top: 1.1em;
    right: 100%;
    width: var(--marg-gap);
    border-top: 1px solid var(--rule);
  }
  [data-margin="ruled"] .node[data-side="a"] .node-in > .mnote::before,
  [data-margin="ruled"] .node[data-side="a"] .node-in > blockquote.pull::before {
    width: calc(var(--marg-gap) + var(--shift));
  }

  /* the running folio in the spine sits on live ground now */
  .sheet .body > .mr-spine span {
    background: var(--bg);
    padding: .5em .15em;
  }
}

@media (min-width: 1500px) {
  .sheet-wrap {
    --card: 40rem;
    --shift: 4.5rem;
    --pad-x: 2.3rem;
    --pad-y: 1.9rem;
  }
}

/* the press block sits in the flow at the head of the path here, not in a
   lane beside it, so the path leaves from its bottom rule and the gap that
   used to hold it off the prose would strand the first junction dot. */
@media (max-width: 1099px) {
  .sheet .margin-rail { margin-bottom: 0; }
}

@media (max-width: 820px) {
  /* the path flattens. no step, so every trace is a straight left rule between
     two cards — the elbow has nothing to cross and the geometry says so on its
     own, with --shift at zero. */
  .sheet-wrap {
    --shift: 0px;
    --pad-x: 1.2rem;
    --pad-y: 1.3rem;
    --x-in: .8rem;
    --trace-h: 2.4rem;
  }
  .sheet { box-shadow: none; }
  .node { max-width: none; }
  .print-head { padding: 1.5rem var(--pad-x) 1.2rem; }
  .node { padding: 2.1rem var(--pad-x) var(--pad-y); }
  .colophon.node-end { padding: 2.1rem var(--pad-x) var(--pad-y); }
  .pager { padding: 1em var(--pad-x); }
}

/* ── the contents ──────────────────────────────────────────────────────────
   a long print's jump list, built in src/layouts/Print.astro and set at the
   foot of the head. a cap, a hairline, then one row per section: the number
   dim, the name in ink, the whole row one link that turns accent. two columns
   once the sheet can hold them, read down the first and then the second, the
   way a contents page reads. */
.contents {
  margin: 2.2rem 0 0;
  font-family: var(--mono);
  font-size: 12.5px;
  line-height: 1.4;
}
.contents-cap {
  font-size: 10px;
  letter-spacing: .16em;
  color: var(--dim);
  margin: 0 0 .7rem;
  font-variant-numeric: tabular-nums;
}
.contents ol {
  list-style: none;
  margin: 0;
  padding: 0;
  columns: 2;
  column-gap: 2.4rem;
  /* a hairline, not ink: the document block's ink rule above is the one
     strong line on a report's head */
  border-top: 1px solid var(--rule);
}
.contents li {
  break-inside: avoid;
  border-bottom: 1px solid var(--rule);
}
.contents a {
  display: grid;
  grid-template-columns: 2.4em 1fr;
  gap: .5em;
  padding: .45em 0 .42em;
  color: var(--fg);
  text-decoration: none;
}
.contents-n {
  color: var(--dim);
  letter-spacing: .08em;
  font-variant-numeric: tabular-nums;
}
.contents a:hover,
.contents a:hover .contents-n,
.contents a:focus-visible,
.contents a:focus-visible .contents-n { color: var(--acc); }

/* one column on a narrow sheet: two would break every name onto three lines */
@media (max-width: 820px) {
  .contents ol { columns: 1; }
}

/* a jump lands the heading clear of the top edge, and clear of the mobile
   strip where there is one */
.body h2 { scroll-margin-top: calc(var(--chrome) + 2.4rem); }

/* ══ the report ══════════════════════════════════════════════════════════════
   a print with `format: report` in its frontmatter. same path, same cards,
   same trace: what changes is the type. the head becomes a document block,
   the sections are numbered, the tables are instruments. mono leads, archivo
   keeps the title and the section names, and orange is spent on state only
   (the filed stamp, the newest log line, the fig tag).

   the diagram and log figures below are not report-only: src/lib/report.mjs
   builds them in any print that fences a ```diagram or a ```log.
   ════════════════════════════════════════════════════════════════════════ */

/* ── the head ──────────────────────────────────────────────────────────── */

/* the document block: five cells, a cap over a value, hairlines between. a
   heavier ink rule on top is the one strong line on the page, the way a
   title block on a drawing sheet opens. */
.doc-block {
  display: grid;
  grid-template-columns: repeat(5, auto);
  justify-content: start;
  margin: 0 0 2.2rem;
  border-top: 1px solid var(--fg);
  border-bottom: 1px solid var(--rule);
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}
.doc-block > div {
  padding: .55rem 1.6rem .6rem .7rem;
  border-left: 1px solid var(--rule);
}
.doc-block > div:first-child { border-left: 0; padding-left: 0; }
.doc-block dt {
  font-size: 10px;
  letter-spacing: .16em;
  color: var(--dim);
  margin: 0 0 .35rem;
}
.doc-block dd {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: .04em;
  white-space: nowrap;
}
.doc-state dd { color: var(--acc); }

[data-format="report"] .print-title {
  font-size: 52px;
  letter-spacing: -.01em;
  margin-bottom: .4em;
}
[data-format="report"] .print-sum {
  font-family: var(--mono);
  font-size: 13.5px;
  line-height: 1.55;
  /* the abstract reads at full ink: .quiet dims by opacity, which this
     print does not */
  opacity: 1;
  color: var(--fg);
  max-width: 56ch;
  margin-bottom: 0;
}

/* ── the sections ──────────────────────────────────────────────────────── */

/* one number system on a report: the section's. the card numerals would
   count the same h2s a second time, a few of them off by one wherever a long
   section splits into two cards. */
[data-format="report"] .node::before { content: none; }
[data-format="report"] .node { padding-top: var(--pad-y); }

[data-format="report"] .body h2 {
  display: flex;
  align-items: baseline;
  gap: .9rem;
  font-size: 26px;
  font-weight: 900;
  line-height: 1.05;
  letter-spacing: -.005em;
  margin-bottom: 1rem;
}
/* the pseudo is the one site.css spends on the spine's tick at 1100 and up,
   so every part of that placement is undone here */
[data-format="report"] .body h2[data-sect]::before {
  content: attr(data-sect);
  position: static;
  width: auto;
  border: 0;
  opacity: 1;
  flex: none;
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: .12em;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
}
[data-format="report"] .body h3 {
  font-family: var(--mono);
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: .08em;
}

[data-format="report"] .body ul { list-style: square; }
[data-format="report"] .body li::marker { color: var(--dim); }

/* the closing status line: a lone paragraph of code, set as a readout */
[data-format="report"] .node-in > p:only-child > code:only-child,
[data-format="report"] .node-in > p:last-child > code:only-child {
  background: none;
  padding: 0;
  margin: 0;
  font-size: 12.5px;
  letter-spacing: .04em;
}
[data-format="report"] .node-in > p:only-child > code:only-child::before,
[data-format="report"] .node-in > p:only-child > code:only-child::after,
[data-format="report"] .node-in > p:last-child > code:only-child::before,
[data-format="report"] .node-in > p:last-child > code:only-child::after { content: none; }

/* ── the instrument table ─────────────────────────────────────────────── */

.body .table-scroll { margin: 1.4em 0; max-width: none; }
.body table.instr {
  margin: 0;
  font-family: var(--mono);
  font-size: 12.5px;
  line-height: 1.45;
  font-variant-numeric: tabular-nums;
  border-top: 1px solid var(--fg);
}
.body table.instr th,
.body table.instr td {
  padding: .5em 1.4em .5em 0;
  vertical-align: baseline;
}
.body table.instr th:last-child,
.body table.instr td:last-child { padding-right: 0; }
.body table.instr th {
  font-size: 10px;
  letter-spacing: .16em;
  font-weight: 500;
  opacity: 1;
  color: var(--dim);
  padding-top: .6em;
}
.body table.instr .num { text-align: right; white-space: nowrap; }
.body table.instr code { background: none; padding: 0; margin: 0; font-size: 1em; }
/* the table is already all mono; the brackets would only mark every cell */
.body table.instr code::before,
.body table.instr code::after { content: none; }

/* ── the diagram plate ─────────────────────────────────────────────────────
   the drawing runs the full width of its card, edge to edge through the
   card's own pad, so seventy-two columns fit at a readable size: the type is
   sized off the plate (a mono column is .6em) and stops at 13px. on a phone
   it bottoms out at 10px and the drawing scrolls sideways inside the plate,
   never the page. the head is the site's figure grammar: the orange tag, the
   caption, a readout of the drawing's own size. */

.body figure.rfig {
  container-type: inline-size;
  max-width: none;
  margin: 1.8em calc(-1 * var(--pad-x));
  background: var(--bg);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}
.rfig-head {
  display: flex;
  gap: 10px;
  align-items: baseline;
  padding: .5rem var(--pad-x);
  border-bottom: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 10.5px;
  line-height: 1.4;
  letter-spacing: .1em;
  color: var(--dim);
}
.rfig-head .fig-no { color: var(--acc); flex: none; }
.rfig-cap { min-width: 0; color: var(--fg); }
.rfig-rt {
  margin-left: auto;
  flex: none;
  font-variant-numeric: tabular-nums;
}
.body pre.rfig-art {
  margin: 0;
  border: 0;
  background: var(--bg);
  padding: 1.1rem var(--pad-x) 1.2rem;
  font-family: var(--mono);
  font-weight: 400;
  /* 72 columns of .6em, plus the pad on both sides */
  font-size: clamp(10px, calc((100cqi - 2 * var(--pad-x)) / 43.4), 13px);
  /* the box-drawing glyphs run 1.52em tall, so at 1.4 the verticals meet
     the next line's and a drawn box closes without a gap */
  line-height: 1.4;
  letter-spacing: 0;
  white-space: pre;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  font-variant-ligatures: none;
  tab-size: 4;
}

/* ── the image plate ────────────────────────────────────────────────────────
   a fig-captioned image, the same plate as a diagram: figure.rfig carries the
   frame and the head, and the image sits where pre.rfig-art would. one frame
   per figure, run edge to edge across the card with no pad of its own, so a
   phone gets every pixel of its width. an image caption is a sentence, not a
   slug: the tag and the readout share the first line, and the caption takes
   the whole width under them at a size a phone can read. */

.body img.rfig-pic-art {
  display: block;
  width: 100%;
  height: auto;
  margin: 0;
  border: 0;
  padding: 0;
  background: var(--bg);
}
.rfig-pic .rfig-head {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .35rem 10px;
  padding: .65rem var(--pad-x) .75rem;
}
.rfig-pic .rfig-rt { grid-column: 2; grid-row: 1; justify-self: end; }
.rfig-pic .rfig-cap {
  grid-column: 1 / -1;
  font-size: 13px;
  line-height: 1.5;
  letter-spacing: .02em;
}

/* ── the table plate ────────────────────────────────────────────────────────
   a caption line over a table (see report.mjs): the same plate and head as a
   diagram, the instrument table set inside it on the diagram's own pad. */

.body .rfig-table > .table-scroll {
  margin: 0;
  padding: 1.1rem var(--pad-x) 1.2rem;
}
.body .rfig-table table { width: 100%; margin: 0; }
/* on a phone four columns share about three hundred pixels: the gutters
   tighten and the type steps down a size so the last column is not left a
   word wide */
@container (max-width: 520px) {
  .body .rfig-table table.instr { font-size: 11.5px; }
  .body .rfig-table table.instr th,
  .body .rfig-table table.instr td { padding-right: .8em; }
  .body .rfig-table table.instr th { font-size: 9.5px; letter-spacing: .1em; }
}

/* ── the log ───────────────────────────────────────────────────────────────
   a table, because it is one: time, subsystem, message. the stamps are dim
   and tabular, the subsystem is the column you scan, and the newest line
   carries the trace's own junction square in the gutter. a readout (status
   lines with no clock) is the same table less its time column. */

.body figure.rlog {
  max-width: none;
  margin: 1.4em 0;
  background: var(--bg);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}
.rlog-scroll {
  overflow-x: auto;
  overscroll-behavior-x: contain;
}
.body table.rlog-t {
  margin: 0;
  width: 100%;
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.5;
  font-variant-numeric: tabular-nums;
}
.body table.rlog-t td {
  border: 0;
  padding: .28em 1.3em .28em 0;
  vertical-align: baseline;
}
.body table.rlog-t tr:first-child td { padding-top: .75em; }
.body table.rlog-t tr:last-child td { padding-bottom: .75em; }
.body table.rlog-t td:first-child {
  position: relative;
  padding-left: 1.1rem;
}
.body table.rlog-t td:last-child { padding-right: 0; }
.rlog-t .l-t { color: var(--dim); white-space: nowrap; }
.rlog-t .l-s { font-weight: 500; white-space: nowrap; }
.rlog-t .l-m { width: 100%; }
[data-kind="readout"] .rlog-t .l-s { color: var(--dim); font-weight: 400; }

/* the newest line: full ink across, and the junction square in the gutter */
.rlog-t tr[aria-current] .l-t { color: var(--fg); }
.rlog-t tr[aria-current] td:first-child::before {
  content: '';
  position: absolute;
  left: .2rem;
  top: 50%;
  width: 5px;
  height: 5px;
  margin-top: -2.5px;
  background: var(--acc);
}
.body table.rlog-t tr:first-child[aria-current] td:first-child::before { margin-top: calc(.235em - 2.5px); }
.body table.rlog-t tr:last-child[aria-current] td:first-child::before { margin-top: calc(-.235em - 2.5px); }

@media (max-width: 820px) {
  .doc-block { grid-template-columns: repeat(3, auto); }
  .doc-block > div:nth-child(4) { border-left: 0; padding-left: 0; }
  .doc-block > div:nth-child(n + 4) { border-top: 1px solid var(--rule); }
  [data-format="report"] .print-title { font-size: 38px; }
  [data-format="report"] .body h2 { font-size: 22px; }
}

/* ── the outline ───────────────────────────────────────────────────────────
   the print's h2s live in the depth rail now, nested under the post's own
   row (DepthRail.astro, marked by outline.js). wherever the rail is on the
   page (980px and up) the inline contents block in the head would be a second
   copy, so it steps aside; below that the rail is a drawer and the inline
   block is as it always was. */
@media (min-width: 980px) {
  .sheet-wrap[data-outline="on"] .print-head .contents { display: none; }
}

/* fog: scrambled glyphs where a print stops, fading into the ground.
   decoration only (aria-hidden), made at build by src/lib/fog.mjs. the
   fade is a mask, so it is a still image: nothing moves, reduced motion or
   not. */
.body .fog {
  margin: 1.6em 0 0;
  user-select: none;
  -webkit-user-select: none;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, rgba(0, 0, 0, .55) 35%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0%, rgba(0, 0, 0, .55) 35%, transparent 100%);
}
.body .fog p { margin: 0 0 1.2em; opacity: .7; }
.body .fog p:nth-child(n+2) { opacity: .45; }
.body .fog p:nth-child(n+3) { opacity: .25; }
