/* Stoneledger — THE DRAWING SET.
   ════════════════════════════════════════════════════════════════════════════════════════════════
   THE IDEA. Accounting and architecture are the same discipline twice: both are structures that
   must balance, both are drawn before they are built, and both are read by a stranger who has to be
   able to trust the drawing. So this site is a DRAWING SET. Twelve sheets, numbered, each with a
   title block, each developing further than the last — Sheet 00 is pencil on vellum, pure graphite,
   and by Sheet 11 the drawing is fully rendered. That progression is the owner's brief ("start with
   grey scale then start to introduce color as you go further into the website") turned into the
   spine of the thing rather than a coat of paint on it.

   HOW THE PROGRESSION IS MECHANISED. One attribute on <html> — `data-sheet="04"` — selects a hue
   and a saturation floor. Everything downstream reads those two variables: the washes, the rules,
   the accents, and the WebGL structure's own tint. No page hard-codes a colour. Adding a sheet is
   adding a row to one table.

   WHAT ANIMATES. `transform` and `opacity`, and nothing else — the two properties a compositor can
   run without touching layout or paint. Scroll-linked effects use `animation-timeline: view()`
   inside an @supports, so a browser without it gets the finished, fully-visible page rather than a
   page waiting for an observer that never fires. NOTHING is parked at opacity 0: the first frame of
   this site, before a single script runs, is a complete readable document.

   REDUCED MOTION stops all of it — the parallax, the kinetic type, the WebGL — and the drawing
   stays. That is the test of whether the motion was decoration: if removing it removes meaning, it
   was never decoration. */

/* ── 1. THE FACES ─────────────────────────────────────────────────────────────────────────────── */
/* Self-hosted, because the CSP is `font-src 'self'` and widening it for three files would be a
   worse trade than 187 KB served from our own edge and cached for the whole set.
     ARCHIVO   variable weight AND width — a drafting grotesque. The width axis is what makes the
               kinetic type possible: a heading can compress under scroll velocity the way a pen
               presses harder, which is one axis, not a keyframe.
     FRAUNCES  variable optical size — the bookkeeping voice. Old-style, slightly wonky, and it
               carries the editorial lines that a grotesque would make sound like a product page.
     SPLINE SANS MONO  the ledger's own voice. Every figure on this site is tabular and mono,
               because a column of numbers that does not line up is not a column. */
@font-face { font-family: "Archivo"; src: url("/assets/fonts/archivo.woff2") format("woff2-variations");
             font-weight: 100 900; font-stretch: 62% 125%; font-display: swap; }
@font-face { font-family: "Fraunces"; src: url("/assets/fonts/fraunces.woff2") format("woff2-variations");
             font-weight: 100 900; font-display: swap; }
@font-face { font-family: "SplineMono"; src: url("/assets/fonts/splinemono.woff2") format("woff2-variations");
             font-weight: 300 700; font-display: swap; }

/* ── 2. THE SHEET TABLE ───────────────────────────────────────────────────────────────────────── */
/* The whole colour argument of the site, in one table. `--sheet-sat` is how developed the sheet is;
   `--hue` is what it develops INTO. The arc is deliberate and is not a rainbow: cold blueprint →
   through teal and sap green into brass, oxide and vermilion as the sheets get more operational →
   then back to a deep authoritative indigo and violet for the two sheets that are about proof and
   identity (a drawing that has been stamped and sealed) → and one restrained gold for the sheet
   where you decide. */
/* BRIGHTENED, on the owner's note. The first set was mixed like pigment — earth reds, sap greens,
   muted brass — which is honest to a drawing board and too quiet on a screen. These are the same
   arc, same order, same argument, pitched up: a drawing that has been INKED rather than one left in
   wash. Sheet 00 stays pencil, because the whole set depends on there being somewhere to develop
   FROM. */
/* THE MIX IS PER SHEET, AND IT IS MEASURED. `--accent` is derived — the hue mixed toward the ink —
   and one ratio over seven hues cannot be right for all of them: at the old 82% the gold sheet's
   accent came out #cfb356 and landed at 1.73:1 on paper, a serious WCAG failure on every pricing
   heading, every "free" and every purchase link (SL-AUD-006). A lighter hue needs MORE ink, not the
   same amount. Each --accent-mix below is the largest share of the hue that still clears 4.5:1
   against every ground that hue's sheet actually paints — page, panel, sunk panel, the hue-tinted
   head and the footer — computed by `node tools/contrast.mjs`, which reads these very numbers back
   out of this file. Change a hue and re-run it; do not guess a mix.
   Dark needs no override: the same formula mixes toward a LIGHT ink there, so every sheet already
   clears the bar, and `--accent-mix-dark` exists for the day one does not. */
:root { --hue: #698FC8; --sheet-sat: 0; --accent-mix: 57%; }
:root[data-sheet="00"] { --hue: #698FC8; --sheet-sat: 0.00; --accent-mix: 57%; }  /* overview   — pencil */
/* KORA IS THE SPECTRUM SHEET (owner). Its base hue is ultramarine so anything that needs one colour
   has one, but the sheet itself runs through the whole set's palette section by section — see the
   spectrum block further down. Its saturation is lifted off the ramp on purpose: at the 0.17 this
   position would otherwise carry, the sheet is still almost entirely graphite and a spectrum you
   cannot see is not a spectrum. */
:root[data-sheet="01"] { --hue: #AD74FF; --sheet-sat: 0.55; --accent-mix: 54%; }  /* kora       — spectrum; violet where one colour is needed */
:root[data-sheet="02"] { --hue: #5D77FF; --sheet-sat: 0.33; --accent-mix: 60%; }  /* foundation — indigo */
:root[data-sheet="03"] { --hue: #47AFEE; --sheet-sat: 0.50; --accent-mix: 48%; }  /* workflows  — blueprint */
:root[data-sheet="04"] { --hue: #6781FF; --sheet-sat: 0.67; --accent-mix: 56%; }  /* modules    — ultramarine */
:root[data-sheet="05"] { --hue: #FF66B2; --sheet-sat: 0.83; --accent-mix: 50%; }  /* expansions — madder */
:root[data-sheet="06"] { --hue: #FFDA60; --sheet-sat: 1.00; --accent-mix: 39%; }  /* pricing    — gold leaf */

/* Kora's spectrum is not here. It is the POINTER WASH, in gl.js - the sheet develops a different
   part of the run wherever the cursor is. The type on this sheet stays one accent like every other
   sheet's, because a headline that is eight colours at once is a headline nobody reads. */


/* ── 3. THE PALETTE ───────────────────────────────────────────────────────────────────────────── */
/* THE NEUTRALS ARE BIASED COLD. A drafting sheet is not cream; it is a blue-grey paper under a
   graphite line, and a warm neutral here would fight every hue in the table above. Declared
   completely on bare :root so the un-stamped (system-default) document is already correct, then
   redefined — TOKENS ONLY — under the dark media query and the explicit stamp. */
:root {
  --paper:      #EDEEF1;
  --paper-2:    #E4E6EA;
  --paper-3:    #D8DBE1;
  --ink:        #14161A;
  --ink-2:      #2C3038;
  --graphite:   #5C626C;
  --graphite-2: #5F666F;   /* was #848B96 — 2.96:1 on paper, and .spec .n is text a reader reads */
  --hair:       #C2C7CF;
  --hair-2:     #D6DAE0;
  --plate:      rgba(255,255,255,.62);
  --plate-edge: rgba(20,22,26,.10);
  --shadow:     0 1px 0 rgba(20,22,26,.05);
  --gl-paper:   #EDEEF1;
  --gl-ink:     #14161A;
  --gl-hue:     #698FC8;
  --gl-dark:    0;
  --accent:     color-mix(in oklab, var(--hue) var(--accent-mix, 57%), var(--ink));
  --accent-dim: color-mix(in oklab, var(--hue) 34%, var(--paper));
  /* THE LOGO'S GOLD IS ITS OWN, not the sheet's. Every other coloured thing on a page takes
     --accent, which is a different hue on each of the twelve sheets — and a logo that changes colour
     as you move through a site is not a logo. This one value is fixed in each theme. */
  /* THE STONE, SAMPLED FROM THE MARK: #9E9E9D, the mean of 15,758 pixels of its cut-stone face.
     ONE VALUE ON BOTH SHEETS (owner, 2026-09-17). It was darkened to #71716F on paper for contrast,
     but the mark beside it is now unfiltered on both, and a lockup whose two halves disagree about
     their own colour is worse than a lockup that is quiet on one background. */
  --stone:      #9E9E9D;
  /* THE WORD IS NOT THE MARK. --stone is the colour sampled off the mark and is what the artwork
     itself is; the WORD "Ledger" beside it is live type, and at #9E9E9D it measured 2.16:1 in the
     footer on every page (SL-AUD-006). A logo exemption does not exist for text a reader has to
     read, so the word gets its own token: the same stone, taken down until it clears 4.5:1 against
     the footer's ground, and left exactly as the mark in dark where it already clears it. */
  --stone-word: #616160;
  --brand-gold: #7E6426;
  /* ONE HEIGHT FOR THE STICKY HEADER, because three things have to agree with it: the ladder's own
     sticky head, where an in-page anchor lands, and anything else pinned beneath it. The sheet index
     lives INSIDE the bar now, so on a phone the bar is two rows tall and on a wide screen one - the
     index is hidden there and the links sit in the top row instead. */
  --navh: 5.85rem;   /* measured, not guessed: the two-row bar is 93px */
  --measure:    66ch;
  --gut:        clamp(1.15rem, 4vw, 2.6rem);
  color-scheme: light dark;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper:      #0C0E12;
    --paper-2:    #12151A;
    --paper-3:    #1A1E25;
    --ink:        #E7EAEF;
    --ink-2:      #C3C9D2;
    --graphite:   #939AA5;   /* +1 step: #8C939E was 4.47:1 on the gold sheet's lit panel */
    --graphite-2: #7B828D;   /* was #676E79 — 3.76:1 on the dark sheet */
    --hair:       #2A2F38;
    --hair-2:     #1E232B;
    --plate:      rgba(255,255,255,.028);
    --plate-edge: rgba(231,234,239,.10);
    --shadow:     0 1px 0 rgba(0,0,0,.4);
    --gl-paper:   #0C0E12;
    --gl-ink:     #E7EAEF;
    --gl-dark:    1;
    --accent:     color-mix(in oklab, var(--hue) var(--accent-mix-dark, 74%), var(--ink));
    --accent-dim: color-mix(in oklab, var(--hue) 30%, var(--paper));
    --stone:      #9E9E9D;   /* the mark's own colour, unaltered */
    --stone-word: #9E9E9D;   /* on the dark sheet the word already clears 4.5:1 as the mark */
    --brand-gold: #C8A24A;
  }
}
:root[data-theme="dark"] {
  --paper: #0C0E12; --paper-2: #12151A; --paper-3: #1A1E25;
  --ink: #E7EAEF; --ink-2: #C3C9D2; --graphite: #939AA5; --graphite-2: #7B828D;
  --hair: #2A2F38; --hair-2: #1E232B;
  --plate: rgba(255,255,255,.028); --plate-edge: rgba(231,234,239,.10);
  --shadow: 0 1px 0 rgba(0,0,0,.4);
  --gl-paper: #0C0E12; --gl-ink: #E7EAEF; --gl-dark: 1;
  --accent: color-mix(in oklab, var(--hue) var(--accent-mix-dark, 74%), var(--ink));
  --accent-dim: color-mix(in oklab, var(--hue) 30%, var(--paper));
  --stone: #9E9E9D;   /* the mark's own colour, unaltered */
  --stone-word: #9E9E9D;
  --brand-gold: #C8A24A;
}
:root { --gl-hue: var(--hue); }

/* ── 4. GROUND ────────────────────────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: calc(var(--navh) + .6rem);
       /* The bar is sticky, so an anchor jump would land its target underneath it. */
       scroll-padding-top: 4.4rem; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: "Archivo", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  font-variation-settings: "wght" 400, "wdth" 100;
  font-size: clamp(1rem, .96rem + .22vw, 1.09rem);
  line-height: 1.62;
  overflow-x: clip;
}

/* ── 4b. THE THREE DEPTHS ─────────────────────────────────────────────────────────────────────── */
/* The owner's note, and it is the correct definition: the foreground must move FASTER than the
   background. Three planes, each moving at its own rate, and only one of them is actually being
   scrolled:
     FAR    .structure — fixed to the viewport. It does not scroll at all; the CAMERA descends
            through it, which is a fraction of the page's own motion. Slowest.
     MIDDLE .tooth     — the ruled sheet and the hue washes, fixed but drifting against --p.
     NEAR   the content — scrolls at 1:1, the fastest thing on screen.
   Nothing here is choreographed to imitate depth. There are three rates because there are three
   distances, which is why it holds together instead of feeling like an effect. */
.structure {
  position: fixed; inset: 0; width: 100%; height: 100%;
  z-index: 0; pointer-events: none;
  /* No opacity trick: the shader paints the paper itself, so this IS the ground the page sits on. */
}
.tooth {
  position: fixed; inset: -14vh 0; z-index: 1; pointer-events: none;
  /* THE SHEET IS PAPER. It used to carry two washes of the sheet's own hue bled in from the corners,
     which tinted the whole page and made the colour something the reader sat inside rather than
     something they could see. The colour belongs to the DRAWING now — a slight tint on the frame
     that deepens under the pointer — and the ground it is drawn on is just ruled paper, on every
     sheet in the set. */
  /* THE RULING MOVED (owner 2026-09-15). It used to cover the whole sheet, and with twelve different
     structures now drawn behind it the grid was competing with the thing it was supposed to sit
     under — a globe and a rain of figures both read worse through a lattice. So the paper is plain
     and the RULING IS ON THE CARDS, where it belongs: a drawing is pinned to ruled paper, not
     printed on it.
     This layer still exists and still parallaxes, because it carries the depth the scroll depends
     on; it simply no longer paints anything. */
  transform: translate3d(0, calc(var(--p, 0) * -12vh), 0);
}
@media (prefers-reduced-motion: reduce) { .tooth { transform: none; } }
/* Everything a reader reads is in FRONT of both.
   NOT `.nav` — and that omission is the point. Lumping the bar in here with `position: relative`
   silently overrode its own `position: sticky` and the top bar stopped sticking. The nav already
   carries z-index 50, which is in front of both planes, so it needs nothing from this rule at all. */
main, .foot { position: relative; z-index: 2; }
img, canvas, svg { max-width: 100%; display: block; }
[hidden] { display: none !important; }
a { color: inherit; text-decoration-color: color-mix(in oklab, var(--accent) 55%, transparent); text-underline-offset: .22em; }
a:hover { text-decoration-color: var(--accent); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }
::selection { background: color-mix(in oklab, var(--hue) 30%, var(--paper)); }

.skip { position: absolute; left: -9999px; top: 0; padding: .7rem 1rem; background: var(--ink); color: var(--paper); z-index: 200; }
.skip:focus { left: .6rem; top: .6rem; }

/* ── 5. THE DRAFTING VOICE ────────────────────────────────────────────────────────────────────── */
/* Anything that would be hand-lettered on a drawing — a sheet number, a dimension, a key, a figure
   — is mono, uppercase and tracked out. Anything that is prose is not. The two never mix, which is
   what keeps the page from looking like a dashboard wearing a serif. */
.mono, .tick, .dim, .stat b, .key, .titleblock, .num {
  font-family: "SplineMono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}
.tick { font-size: .655rem; letter-spacing: .17em; text-transform: uppercase; color: var(--graphite); }
.tick b { font-weight: 600; color: var(--accent); font-style: normal; }

h1, h2, h3, h4 { font-weight: 500; line-height: 1.04; margin: 0; text-wrap: balance; letter-spacing: -.018em; }
h1 { font-size: clamp(2.6rem, 1.2rem + 6.2vw, 6.4rem); font-variation-settings: "wght" 480, "wdth" 92; }
h2 { font-size: clamp(1.85rem, 1.1rem + 2.7vw, 3.5rem); font-variation-settings: "wght" 500, "wdth" 96; }
h3 { font-size: clamp(1.12rem, 1rem + .6vw, 1.5rem); font-variation-settings: "wght" 560, "wdth" 100; }
h4 { font-size: .95rem; font-variation-settings: "wght" 620, "wdth" 104; }
p { margin: 0 0 1.05em; max-width: var(--measure); }
.lede { font-family: "Fraunces", Georgia, serif; font-size: clamp(1.15rem, 1rem + .85vw, 1.62rem);
        line-height: 1.44; font-variation-settings: "opsz" 40, "wght" 350; color: var(--ink-2); max-width: 46ch; }
.say  { font-family: "Fraunces", Georgia, serif; font-variation-settings: "opsz" 96, "wght" 300;
        font-size: clamp(1.5rem, 1rem + 2.1vw, 2.9rem); line-height: 1.22; letter-spacing: -.012em;
        max-width: 24ch; text-wrap: balance; }
.say em { font-style: normal; color: var(--accent); font-variation-settings: "opsz" 96, "wght" 500; }

/* ── 6. LAYOUT ────────────────────────────────────────────────────────────────────────────────── */
.wrap { width: min(1220px, 100% - var(--gut) * 2); margin-inline: auto; }
section { padding-block: clamp(4rem, 9vw, 9.5rem); position: relative; }
.rule { border: 0; border-top: 1px solid var(--hair); margin: 0; }
/* The section head is a drawing convention, not a heading style: a tick, a rule, then the title —
   the way a sheet announces a detail. */
.head { display: grid; gap: .9rem; margin-bottom: clamp(1.6rem, 3.5vw, 3.2rem); }
.head .tick { display: flex; align-items: center; gap: .8rem; }
.head .tick::after { content: ""; flex: 1; height: 1px; background: var(--hair); }

.cols { display: grid; gap: clamp(1.4rem, 3vw, 3rem); }
@media (min-width: 900px) { .cols.two { grid-template-columns: 1fr 1fr; } .cols.side { grid-template-columns: minmax(0,1.05fr) minmax(0,.95fr); align-items: start; } }

/* BENTO. Not "cards" — DETAILS on a sheet, which is why they share edges and a grid rather than each
   floating in its own shadow. One border colour, one radius, and the emphasis is spent on span and
   on the accent rule, never on more chrome. */
/* THE GREY BOXES WERE THE GRID SHOWING THROUGH. This container painted itself hairline-grey and let
   the cells sit on top with a 1px gap — which draws the rules between tiles for free, and also
   paints every square the tiles do NOT cover. Three tiles of width 3 in a six-column grid leave one
   third of a row uncovered, and that leftover read as an empty box nobody put there.
   The rules are drawn by the CELLS now, so an uncovered track is simply paper. */
.bento { display: grid; gap: 1px; background: transparent; border: 1px solid var(--hair);
         border-radius: 3px; overflow: clip; grid-auto-flow: row dense; }
.bento > .cell { box-shadow: 0 0 0 1px var(--hair); }
@media (min-width: 720px)  { .bento { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1040px) { .bento { grid-template-columns: repeat(6, 1fr); } }
.cell { background-color: var(--paper); padding: clamp(1.15rem, 2.2vw, 1.9rem); display: grid; gap: .55rem; align-content: start; min-width: 0; }
@media (min-width: 1040px) {
  .cell { grid-column: span 2; }
  .cell.w3 { grid-column: span 3; } .cell.w4 { grid-column: span 4; } .cell.w6 { grid-column: span 6; }
}
.cell p { margin: 0; font-size: .935rem; color: var(--ink-2); max-width: 44ch; }
.cell.lit { background: color-mix(in oklab, var(--hue) calc(6% + var(--sheet-sat) * 7%), var(--paper)); }
.cell .tick { color: color-mix(in oklab, var(--accent) 80%, var(--graphite)); }
.cell.tall { min-height: 15rem; }

/* THE PLATE: a floating sheet, used where something is literally a document — the evidence pack,
   a price, a specimen. Faint, because a drawing set has one paper and things sit ON it. */
.plate { background: var(--plate); border: 1px solid var(--plate-edge); border-radius: 3px;
         padding: clamp(1.2rem, 2.4vw, 2.1rem); backdrop-filter: blur(6px); box-shadow: var(--shadow); }

/* ── 7. THE FIGURES ───────────────────────────────────────────────────────────────────────────── */
.stats { display: grid; gap: 1px; background: var(--hair); border-block: 1px solid var(--hair); }
@media (min-width: 640px) { .stats { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px){ .stats { grid-template-columns: repeat(4, 1fr); } }
.stat { background: var(--paper); padding: clamp(1.1rem, 2.4vw, 1.9rem); display: grid; gap: .35rem; }
.stat b { font-size: clamp(1.9rem, 1.2rem + 2.2vw, 3.2rem); font-weight: 400; line-height: 1;
          letter-spacing: -.03em; color: var(--ink); display: block; }
.stat span { font-size: .8rem; color: var(--graphite); line-height: 1.4; max-width: 30ch; }
.stat i { font-style: normal; color: var(--accent); }

/* ── 8. THE LEDGER ────────────────────────────────────────────────────────────────────────────── */
/* A real table, ruled the way a ledger is ruled: hairlines, tabular figures, a double rule under the
   total. This is the one place on the site where accounting is not a metaphor. */
.ledger { width: 100%; border-collapse: collapse; font-family: "SplineMono", ui-monospace, monospace;
          font-variant-numeric: tabular-nums; font-size: .86rem; }
.ledger th { text-align: left; font-weight: 500; font-size: .655rem; letter-spacing: .16em;
             text-transform: uppercase; color: var(--graphite); padding: .55rem .7rem;
             border-bottom: 1px solid var(--ink); white-space: nowrap; }
.ledger td { padding: .62rem .7rem; border-bottom: 1px solid var(--hair); vertical-align: baseline; }
.ledger .r { text-align: right; }
.ledger tbody tr:hover td { background: color-mix(in oklab, var(--hue) 7%, var(--paper)); }
.ledger tfoot td { border-top: 1px solid var(--ink); border-bottom: 3px double var(--ink);
                   font-weight: 600; padding-block: .7rem; }
.scroller { overflow-x: auto; border: 1px solid var(--hair); border-radius: 3px; background: var(--paper); }
.scroller > .ledger th:first-child, .scroller > .ledger td:first-child { padding-left: 1rem; }
.scroller > .ledger th:last-child,  .scroller > .ledger td:last-child  { padding-right: 1rem; }

/* ── 9. THE TITLE BLOCK ───────────────────────────────────────────────────────────────────────── */
/* Bottom-right of every sheet, exactly where a drawing carries it. It is also — and this is the
   joke that is also the argument — a ledger header: issuer, sheet, revision, date, scale. The two
   conventions are the same convention. */
.titleblock {
  position: fixed; right: 0; bottom: 0; z-index: 40;
  display: none; font-size: .58rem; letter-spacing: .12em; text-transform: uppercase;
  background: var(--paper); border-top: 1px solid var(--ink); border-left: 1px solid var(--ink);
  color: var(--graphite); pointer-events: none;
}
@media (min-width: 1100px) { .titleblock { display: grid; grid-auto-flow: column; } }
.titleblock div { padding: .45rem .8rem; border-left: 1px solid var(--hair); display: grid; gap: .12rem; }
.titleblock div:first-child { border-left: 0; }
.titleblock b { color: var(--ink); font-weight: 600; letter-spacing: .1em; }
.titleblock .no { background: var(--ink); color: var(--paper); }
.titleblock .no b { color: var(--paper); }

/* ── 10. NAVIGATION — THE SHEET INDEX ─────────────────────────────────────────────────────────── */
.nav { position: sticky; top: 0; z-index: 50; background: color-mix(in oklab, var(--paper) 86%, transparent);
       backdrop-filter: blur(14px) saturate(1.2); border-bottom: 1px solid var(--hair); }
.nav .wrap { display: flex; align-items: center; gap: .6rem; min-height: 3.4rem; }
/* ── THE WORDMARK (owner 2026-09-16) ───────────────────────────────────────────────────────────
   Two words: Stone heavy, Ledger light and gold. The ruled SL square that came with option 06 has
   been taken off at the owner's word, and the words are 20% larger for it — a wordmark that is only
   words can afford the size the square was using, and it reads further across a bar.

   Worth knowing before it is ever wanted back: the square was the one part that detached for a
   favicon, an app icon or a signature block. Without it the mark needs its words to be legible
   wherever it goes, so it should not be set smaller than this anywhere.

   No new font is loaded — both faces are already on every page, so the mark can never fall back to
   a face the page around it is not using. */
/* ── THE BRAND LOCKUP ──────────────────────────────────────────────────────────────────────────
   The 2026-09 mark: the SL monogram, then the words to its RIGHT and larger (owner). The supplied
   artwork stacks them — monogram over wordmark over tagline — which is a square lockup built for a
   profile picture. A site header is a wide, short space, so the same three parts are relaid
   horizontally: the mark sets the height, the words sit beside it.

   THE MARK IS AN <img> AND THE WORDS ARE LIVE TEXT, deliberately. A single flattened image would
   turn the company name into something a screen reader announces as "logo", something a browser
   cannot find with Cmd-F, and something that goes soft on a display the artwork was not exported
   for. The words are also the one part that must stay crisp at 13px in a footer.

   IT DEGRADES TO THE WORDMARK ALONE. Until the mark file exists the img is hidden by `:not([src])`
   and the header looks exactly as it did — no broken-image icon, no layout jump. */
.brandlock { display: inline-flex; align-items: center; gap: .62rem; text-decoration: none;
             margin-right: auto; min-width: 0; }
.brandlock-mark { display: block; height: 2.05rem; width: auto; flex: none; }
.brandlock-mark:not([src]), .brandlock-mark[src=""] { display: none; }

/* THE MARK KEEPS ITS OWN COLOUR ON BOTH SHEETS (owner, 2026-09-17).
   It was darkened on the light sheet to lift it off paper — the logo's grey sits at about 2.3:1
   there — but a logo is not body text, and the owner's call is that the mark is the mark: one
   colour, the artwork's own, whichever way the site is set. So no filter, either way. */

/* The words. All caps and widely tracked, as the artwork sets them — the tracking is most of the
   character here, and at this size it is what stops two ordinary words reading as body copy. */
.brandlock-word { font-family: "Archivo", system-ui, sans-serif;
                  font-variation-settings: "wght" 560, "wdth" 112;
                  font-size: 1.52rem; letter-spacing: .13em; text-transform: uppercase;
                  line-height: 1; color: var(--ink); white-space: nowrap; }
/* LEDGER wears the STONE, not the gold (owner, 2026-09). The gold was the site's accent and made
   the wordmark a third colour the logo does not contain; the stone ties the two words to the mark
   beside them, which is the whole point of a lockup. */
.brandlock-word em { font-style: normal; color: var(--stone-word); }

/* The footer wants the mark quieter and the words smaller: it is a sign-off, not an entrance. */
.brand-foot .brandlock-mark { height: 1.72rem; }
.brand-foot .brandlock-word { font-size: 1.24rem; }

/* NARROW: SHRINK FIRST, HIDE ONLY WHEN IT GENUINELY WILL NOT FIT.
   The lockup is wider than the text wordmark it replaced, and on a phone it ran underneath the theme
   toggle. Worth recording HOW that hid: getBoundingClientRect on the anchor reported ten pixels of
   CLEARANCE, because `min-width: 0` lets a flex item shrink below its content and the nowrap text
   spilled out of a box that still measured 183px while the glyphs reached 244. The screenshot showed
   it; the measurement did not.

   Measured, rather than guessed at: at full size the words fit to about 500px and collide below it.
   My first fix hid them under 720px, which was a conservative number I picked instead of testing —
   and it threw the company's name away on tablets and in every narrow preview pane for no reason.
   Smaller type buys most of that back, so the name survives down to a 360px phone. */
@media (max-width: 560px) {
  .brandlock { gap: .42rem; }
  .brandlock-mark { height: 1.78rem; }
  /* NEVER BELOW THE OLD WORDMARK. The brief was "larger", and my first narrow setting was 1.04rem —
     16.6px against the 1.272rem (20.4px) the plain text wordmark used at every width. So on a phone
     the new lockup had made the company name SMALLER than the thing it replaced, which is the one
     outcome the instruction ruled out. 1.34rem is above the old size at every width the words show. */
  .brandlock-word { font-size: 1.34rem; letter-spacing: .085em; }
}
/* PHONE PORTRAIT: SMALLER AND TIGHTER, NOT GONE (owner, 2026-09-17).
   A 390px portrait phone fell under the previous cut and lost the words entirely — the owner saw the
   mark alone and asked for them back, "slightly smaller and the letters a pixel closer".
   That is the right call and the previous rule was mine being cautious twice over: hiding a company's
   name is a bigger loss than setting it a point smaller. Tracking is where the width is — at .085em
   over twelve characters it spends about 20px on air alone — so most of the saving comes from
   closing it up rather than from the type size. */
@media (max-width: 458px) {
  .brandlock { gap: .3rem; }
  .brandlock-mark { height: 1.5rem; }
  .brandlock-word { font-size: 1.02rem; letter-spacing: .012em; }
}

/* THE NARROWEST PHONES: THE WORDS SURVIVE, THE MARK STANDS DOWN.
   Below about 385px there is genuinely not room for a mark, twelve tracked characters and two
   buttons — at 360px the name still ran 16px under the toggle even fully tightened. Something has to
   go, and between the two the NAME is what identifies the company to somebody reading it; a mark
   nobody can yet associate with the business identifies nothing on its own. So the mark steps aside
   and the words stay, which is also the owner's instruction read literally: make them visible.
   The anchor still carries aria-label="Stone Ledger, home", so nothing changes for a screen reader. */
@media (max-width: 385px) {
  .brandlock-mark { display: none; }
  .brandlock-word { font-size: 1.06rem; letter-spacing: .02em; }
}
/* And the oldest small phones (320px — an SE 1, a budget Android). One more notch rather than
   letting the name run under the button, which is the state the owner reported. */
@media (max-width: 340px) {
  .brandlock-word { font-size: .88rem; letter-spacing: 0; }
  .nav .navcta { padding-inline: .7rem; }   /* the two buttons give up a little width too */
}
  .brandlock-mark { height: 1.9rem; }
}
/* The footer has the full width to itself — no toggle, no call to action beside it. */
.brand-foot .brandlock-word { display: inline; }
  .brandlock-mark { height: 1.9rem; }
  .brand-foot .brandlock-word { display: inline; font-size: 1.1rem; }  /* the footer has the room */
}

.brand { display: flex; align-items: center; gap: .49rem; text-decoration: none; margin-right: auto; }
.brand b { font-variation-settings: "wght" 620, "wdth" 88; letter-spacing: -.03em; font-size: 1.272rem;
           color: var(--ink); }   /* +20% (owner) */
.brand i { font-style: normal; font-variation-settings: "wght" 250, "wdth" 88; letter-spacing: -.03em;
           font-size: 1.272rem; color: var(--brand-gold); }   /* +20% (owner) */
.navlinks { display: none; gap: 0; align-items: center; min-width: 0; overflow: hidden; }
@media (min-width: 1180px) { .navlinks { display: flex; } }
.navlinks a { font-family: "SplineMono", monospace; font-size: .66rem; letter-spacing: .1em;
              text-transform: uppercase; text-decoration: none; color: var(--graphite);
              padding: .42rem .5rem; border-radius: 2px; white-space: nowrap; }
.navlinks a:hover { color: var(--ink); background: var(--paper-2); }
.navlinks a[aria-current="page"] { color: var(--ink); box-shadow: inset 0 -2px 0 var(--accent); }
.navcta { flex: none; font-family: "SplineMono", monospace; font-size: .66rem; letter-spacing: .1em; text-transform: uppercase;
          text-decoration: none; padding: .48rem .95rem; border: 1px solid var(--ink); border-radius: 2px;
          background: var(--ink); color: var(--paper); white-space: nowrap; }
.navcta:hover { background: var(--accent); border-color: var(--accent); }
/* The index, open on small screens as a plain scrolling row: a sheet set has an index, it does not
   have a hamburger. */
.sheetrow { display: flex; gap: .1rem; overflow-x: auto; border-top: 1px solid var(--hair);
            padding: .35rem var(--gut); scrollbar-width: none; }
.sheetrow::-webkit-scrollbar { display: none; }
@media (min-width: 1180px) { .sheetrow { display: none; } :root { --navh: 3.4rem; } }
.sheetrow a { font-family: "SplineMono", monospace; font-size: .62rem; letter-spacing: .08em;
              text-transform: uppercase; text-decoration: none; color: var(--graphite);
              padding: .3rem .55rem; white-space: nowrap; border-radius: 2px; }
.sheetrow a[aria-current="page"] { color: var(--paper); background: var(--ink); }

/* ── 11. THE HERO ─────────────────────────────────────────────────────────────────────────────── */
/* NO RULE UNDER THE HERO (owner). It carried a hairline for as long as the section cards had a 3px
   double border and needed help ending; at 6px they end themselves, and the hero is already a
   lighter plate over the drawing. Three separations doing one job, and on a sheet with open paper
   behind it the flat grey one was the only thing you could see. */
.hero { position: relative; min-height: clamp(34rem, 84svh, 60rem); display: grid; align-items: end;
        overflow: clip; }
.hero .wrap { position: relative; z-index: 2; padding-block: clamp(2.6rem, 7vw, 6rem); }
/* The plate the wordmark sits on: enough to guarantee contrast over any frame of the drawing behind
   it, not enough to look like a box. */
.hero .plate { max-width: 54rem; background: color-mix(in oklab, var(--paper) 80%, transparent); }
.hero h1 .l2 { display: block; color: var(--accent); }
.heroSub { margin-top: 1.4rem; }
/* Sheet 00 gets the deep hero; the inner sheets get a shorter one, so the set has a rhythm rather
   than twelve identical openings. */
.hero.inner { min-height: clamp(24rem, 62svh, 40rem); }

/* ── 12. KINETIC TYPOGRAPHY ───────────────────────────────────────────────────────────────────── */
/* --v is scroll VELOCITY, written once per frame by site.js and read here as a width-axis offset.
   Scrolling fast compresses the display type; stopping lets it breathe back out. It is one variable
   font axis, not an animation, which is why it costs nothing and why it feels like a material
   rather than an effect. */
.kin { font-variation-settings: "wght" calc(480 - var(--v, 0) * 90), "wdth" calc(92 - var(--v, 0) * 26); }
h2.kin { font-variation-settings: "wght" calc(500 - var(--v, 0) * 70), "wdth" calc(96 - var(--v, 0) * 22); }
@media (prefers-reduced-motion: reduce) { .kin { font-variation-settings: "wght" 480, "wdth" 92; } }

/* ── 13. PARALLAX + REVEAL ────────────────────────────────────────────────────────────────────── */
/* --p is a single normalised scroll position written once per frame. Layers read it at different
   multipliers, so the depth is one number resolved twelve ways rather than twelve listeners. */
.par  { transform: translate3d(0, calc(var(--p, 0) * 1px * var(--k, 40)), 0); will-change: transform; }
@media (prefers-reduced-motion: reduce) { .par { transform: none; } }

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* THE ENTRANCE, and note where it starts: at opacity 1 and a 10px offset. The page is complete
       and readable in its first frame; the scroll timeline only settles it. Nothing here can leave
       content invisible, which is the failure mode of every observer-driven reveal. */
    .rise { animation: rise linear both; animation-timeline: view(); animation-range: entry 0% entry 42%; }
    @keyframes rise { from { transform: translate3d(0, 14px, 0); opacity: .55; } to { transform: none; opacity: 1; } }
    /* A hairline that draws itself as it enters — the closest this site gets to an animated flourish,
       and it is a rule being ruled. */
    .draws { animation: draws linear both; animation-timeline: view(); animation-range: entry 0% entry 55%; transform-origin: left; }
    @keyframes draws { from { transform: scaleX(0); } to { transform: scaleX(1); } }
  }
}

/* ── 14. THE DOUBLE-ENTRY FIGURE ──────────────────────────────────────────────────────────────── */
/* The one piece of interactive storytelling on Sheet 00: a transaction arrives, splits, and the two
   sides balance. It is scroll-driven, it is SVG, and it says the thing the copy would otherwise have
   to claim. */
.entry { display: grid; gap: 1px; background: var(--hair); border: 1px solid var(--hair); border-radius: 3px; }
@media (min-width: 760px) { .entry { grid-template-columns: 1fr 1fr; } }
.entry > div { background: var(--paper); padding: clamp(1rem, 2.2vw, 1.7rem); }
.entry .side { display: flex; justify-content: space-between; gap: 1rem; font-family: "SplineMono", monospace;
               font-size: .85rem; font-variant-numeric: tabular-nums; padding-block: .45rem;
               border-bottom: 1px solid var(--hair-2); }
.entry .side:last-child { border-bottom: 0; }
.entry .side b { font-weight: 500; }
.entry .dr { color: var(--ink); } .entry .cr { color: var(--accent); }
/* The footing row spans the whole figure — it is the statement the two columns above make together.
   As a class, not an inline `grid-column:1/-1`, which the parser declined to honour unspaced. */
.entry .foots { grid-column: 1 / -1; display: flex; justify-content: space-between; gap: 1rem;
                flex-wrap: wrap; align-items: baseline;
                background: color-mix(in oklab, var(--hue) calc(6% + var(--sheet-sat) * 8%), var(--paper)); }
.entry .foots b { font-size: 1.1rem; }

/* ── 15. BUTTONS + THE DOORS ──────────────────────────────────────────────────────────────────── */
.btns { display: flex; flex-wrap: wrap; gap: .7rem; margin-top: 1.8rem; }
.btn { font-family: "SplineMono", monospace; font-size: .72rem; letter-spacing: .1em; text-transform: uppercase;
       text-decoration: none; padding: .8rem 1.4rem; border: 1px solid var(--ink); border-radius: 2px;
       background: var(--ink); color: var(--paper); display: inline-flex; align-items: center; gap: .6rem;
       transition: background .18s ease, border-color .18s ease, transform .18s ease; }
.btn:hover { background: var(--accent); border-color: var(--accent); transform: translateY(-1px); }
.btn.ghost { background: transparent; color: var(--ink); border-color: var(--hair); }
.btn.ghost:hover { border-color: var(--ink); background: transparent; }
@media (prefers-reduced-motion: reduce) { .btn:hover { transform: none; } }

/* ── 16. LISTS THAT ARE SPECIFICATIONS ────────────────────────────────────────────────────────── */
.spec { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
.spec li { display: grid; grid-template-columns: 2.6rem 1fr; gap: 1rem; padding: .78rem 0;
           border-top: 1px solid var(--hair-2); align-items: baseline; }
.spec li:last-child { border-bottom: 1px solid var(--hair-2); }
.spec .n { font-family: "SplineMono", monospace; font-size: .64rem; letter-spacing: .1em; color: var(--graphite-2); }
.spec p { margin: .2rem 0 0; font-size: .9rem; color: var(--ink-2); }
.spec b { font-variation-settings: "wght" 600; }

/* ── 17. FOOTER ───────────────────────────────────────────────────────────────────────────────── */
.foot { border-top: 1px solid var(--ink); padding-block: clamp(2.4rem, 5vw, 4rem) 6rem; background: var(--paper-2); }
.foot .wrap { display: grid; gap: 2rem; }
@media (min-width: 860px) { .foot .wrap { grid-template-columns: 1.3fr 1fr 1fr; } }
/* THE FOOTER'S SECTION HEADINGS ARE h2, NOT h4. They were <h4> after a page whose deepest heading
   was an <h3>, which is a skipped level on EVERY page of the set (SL-AUD-006) — an outline that
   reads as two missing sections to anyone navigating by heading. They are top-level sections of the
   footer, so they are h2; the size below is what makes them look like a footer label, and that was
   always the only job the h4 was doing. */
.foot h2 { margin-bottom: .7rem; color: var(--graphite); font-family: "SplineMono", monospace;
           font-size: .6rem; letter-spacing: .17em; text-transform: uppercase; font-variation-settings: normal; }
.foot ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .42rem; }
.foot a { font-size: .89rem; text-decoration: none; color: var(--ink-2); }
.foot a:hover { color: var(--accent); }
.fine { font-size: .78rem; color: var(--graphite); max-width: 44ch; }

/* ── 18. THE PROGRESS GAUGE ───────────────────────────────────────────────────────────────────── */
/* A dimension line down the left margin showing how far through the sheet you are. It is the one
   piece of chrome that earns its place: this is a long set, and a reader who cannot see how much is
   left stops scrolling — which is the exact failure the owner asked to fix. */
.gauge { position: fixed; left: 0; top: 0; bottom: 0; width: 2px; z-index: 45; background: var(--hair-2); }
.gauge i { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: var(--accent);
           transform: scaleY(var(--p, 0)); transform-origin: top; }
@media (max-width: 1099px) { .gauge { display: none; } }

/* ── 19. THE CONTENTS SWATCH ──────────────────────────────────────────────────────────────────── */
/* On the cover, each sheet in the index carries its own hue as a chip. The point is not decoration:
   it lets a reader SEE the set develop from graphite to gold before opening any of it, which is the
   difference between a contents page and a reason to keep going. */
.swatch { display: block; width: 3.2rem; height: 1.15rem; border-radius: 2px; border: 1px solid var(--hair);
          background: linear-gradient(105deg, var(--sw, var(--graphite)) 0%, color-mix(in oklab, var(--sw, var(--graphite)) 40%, var(--paper)) 100%); }
[data-sheet-hue="00"] { --sw: #698FC8; }  /* overview   — pencil */
[data-sheet-hue="01"] { --sw: #AD74FF; }  /* kora       — spectrum; violet stands for it in a wash */
[data-sheet-hue="02"] { --sw: #5D77FF; }  /* foundation — indigo */
[data-sheet-hue="03"] { --sw: #47AFEE; }  /* workflows  — blueprint */
[data-sheet-hue="04"] { --sw: #6781FF; }  /* modules    — ultramarine */
[data-sheet-hue="05"] { --sw: #FF66B2; }  /* expansions — madder */
[data-sheet-hue="06"] { --sw: #FFDA60; }  /* pricing    — gold leaf */
.spec li a { color: inherit; }
.spec li a:hover { color: var(--accent); }
[data-foots].bad { color: #B23A2E; }
/* A price, wherever one is printed: big, tabular, and never rounded for effect. */
.price { font-family: "SplineMono", monospace; font-variant-numeric: tabular-nums; font-size: clamp(1.7rem,1.1rem+2vw,2.7rem);
         line-height: 1; letter-spacing: -.03em; display: block; }
.price small { font-size: .38em; letter-spacing: .1em; text-transform: uppercase; color: var(--graphite); display: block; margin-top: .5rem; }

/* ── 20. THE UTILITY SET, AND WHY IT EXISTS ───────────────────────────────────────────────────── */
/* Every one of these replaced a `style="…"` attribute, and they were not a style preference: this
   site ships `style-src 'self'` with no `unsafe-inline`, so the browser DROPS inline style
   attributes silently. Forty-two of them on the cover alone did nothing at all, which is how a
   `grid-column:1/-1` came to have no effect and took a while to explain.
   Programmatic CSSOM writes — `el.style.setProperty('--p', …)` — are NOT blocked by that directive,
   which is what lets the scroll loop keep working. Measured in the page rather than assumed.
   The alternative was to widen the policy for the convenience of the person writing the markup.
   Not worth it: there is no user-supplied content on this site, so the attribute bought nothing a
   class does not. */
.ac    { color: var(--accent); }
.plain { text-decoration: none; }
.mt1   { margin-top: .6rem; }
.mt2   { margin-top: .8rem; }
.mt3   { margin-top: 1.3rem; }
.mt4   { margin-top: 1.7rem; }
.tiny  { padding: .4rem .75rem; font-size: .58rem; }
.tight-top { padding-top: clamp(1.4rem, 3vw, 2.4rem); }
.note  { margin: .6rem 0 0; color: var(--graphite); font-size: .9rem; }
.brand-foot { margin-bottom: .9rem; }

/* The pull line: the Fraunces voice, given air on both sides because it is the one thing on the
   sheet that is meant to be read slowly. */
.pull  { padding-block: clamp(3rem, 7vw, 7rem); }
.pullq { margin: 0; max-width: 30ch; }

/* The next sheet — the single most important link on a page nobody has finished reading. */
.nextsheet { padding-block: clamp(3rem, 6vw, 6rem); }
.nextcard  { display: grid; gap: .5rem; text-decoration: none; transition: border-color .2s ease, transform .2s ease; }
.nextcard:hover { border-color: var(--accent); transform: translateY(-2px); }
@media (prefers-reduced-motion: reduce) { .nextcard:hover { transform: none; } }
.nextcard h2 { font-size: clamp(1.6rem, 1rem + 2.4vw, 3rem); }
.nextdesc  { margin: 0; color: var(--graphite); max-width: 52ch; }

/* The inner sheets' hero: one step down from the cover's, so the set has a rhythm. */
.h1-inner { margin-top: .7rem; font-size: clamp(2.2rem, 1.2rem + 4.4vw, 4.6rem); }
.h1-cover { margin-top: .7rem; }

/* The cover's contents page: a third column for the hue chip. */
.spec.index li { grid-template-columns: 2.6rem 1fr auto; align-items: center; }
.pricecard { display: grid; gap: .4rem; max-width: 34rem; }
/* THE ANNUAL SUM, SHOWN AS A SUM. The card used to print one figure with the comparison buried in a
   small grey caption, and the saving nowhere at all — so the one question the section exists to
   answer, what does paying up front actually come to, had to be done in the reader's head. Three
   ruled lines: what twelve months costs monthly, what it costs up front, and the difference. The
   last line is the answer, so it is the one that is inked. */
.annualsums { margin: 1.1rem 0 .2rem; display: grid; gap: 0; font-size: .9rem; }
.annualsums > div { display: flex; justify-content: space-between; align-items: baseline; gap: 1.5rem;
                    padding: .5rem 0; border-bottom: 1px solid var(--hair); }
.annualsums dt { margin: 0; color: var(--ink-2); }
.annualsums dd { margin: 0; font-family: "SplineMono", monospace; font-variant-numeric: tabular-nums;
                 color: var(--ink); white-space: nowrap; }
.annualsums > .save { border-bottom: 3px double var(--ink); border-top: 1px solid var(--ink);
                      margin-top: .1rem; }
.annualsums > .save dt { color: var(--ink); font-weight: 600; }
.annualsums > .save dd { color: var(--accent); font-weight: 700; font-size: 1.08em; }
.nopad-bottom { padding-bottom: 0; }

/* ── 21. WIDE TABLES SCROLL; THEY DO NOT SQUEEZE ──────────────────────────────────────────────── */
/* `overflow-x: auto` on the container is only half the instruction. Without a min-width the table
   happily shrinks to the container instead of overflowing it, and a prose column collapses to eight
   characters and runs for a thousand pixels — which is what the pricing schedule did on a phone.
   The min-width is what turns "can scroll" into "does scroll". */
.scroller { position: relative; }
.scroller > .ledger { min-width: 46rem; }
.scroller > .ledger td:last-child { min-width: 20rem; }
/* The affordance: a fade on the right edge while there is more table to the right. Purely visual,
   and it sits above the scrollbar rather than inside the scrolling area, so it cannot be scrolled
   away and cannot be mistaken for content. */
@media (max-width: 860px) {
  .scroller::after { content: ""; position: absolute; top: 0; right: 0; bottom: 0; width: 3rem;
                     pointer-events: none; background: linear-gradient(90deg, transparent, var(--paper)); }
  .scroller { --hint: 1; }
  .scroller > .ledger { font-size: .8rem; }
}
/* The entry figure's two sides stack on a phone; the footing still spans whatever it lands in. */
@media (max-width: 759px) { .entry .foots { grid-column: auto; } }

/* ── 22. COMING OUT OF THE STRUCTURE ──────────────────────────────────────────────────────────── */
/* Each block arrives out of the drawing rather than sliding in from the side: it starts slightly
   further away — down, back, and not yet at full contrast — and settles onto the near plane as it
   enters. That is the same depth the three planes above describe, applied to one element.

   IT NEVER STARTS AT ZERO. The lowest opacity here is .38, and the whole rule sits behind
   `@supports (animation-timeline: view())` — so a browser that cannot drive it, or a reader who has
   asked for less motion, gets the finished page rather than a page waiting for something to fire.
   A reveal that can leave content invisible is a bug wearing a design. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .head, .bento, .stats, .scroller, .spec, .entry, .plate, .pullq {
      animation: emerge linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 46%;
    }
    @keyframes emerge {
      from { transform: translate3d(0, 34px, 0) scale(.982); opacity: .38; }
      to   { transform: none; opacity: 1; }
    }
    /* The hero is already on screen when the page loads, so it is excluded: an opening that animates
       on arrival animates for nobody. */
    .hero .plate { animation: none; }
  }
}

/* ── 23. VELLUM, NOT CARD ─────────────────────────────────────────────────────────────────────── */
/* Now that the drawing runs the full height of the sheet, an opaque panel would bury it. Anything
   holding DATA — a cell, a figure, a table — is a leaf of vellum laid on the drawing: solid enough
   to read small type against, sheer enough that the structure is still visibly underneath. Running
   prose needs no panel at all; it sits straight on the drawing, which is the whole point. */
.cell, .stat, .scroller, .entry > div, .plate {
  background: color-mix(in oklab, var(--paper) 90%, transparent);
  backdrop-filter: blur(2px);
}
.cell.lit { background: color-mix(in oklab, var(--hue) calc(7% + var(--sheet-sat) * 8%), color-mix(in oklab, var(--paper) 92%, transparent)); }
.entry .foots { background: color-mix(in oklab, var(--hue) calc(6% + var(--sheet-sat) * 8%), color-mix(in oklab, var(--paper) 92%, transparent)); }
.nav { background: color-mix(in oklab, var(--paper) 82%, transparent); }
.foot { background: color-mix(in oklab, var(--paper-2) 92%, transparent); }
.hero .plate { background: color-mix(in oklab, var(--paper) 84%, transparent); }
.titleblock { background: color-mix(in oklab, var(--paper) 92%, transparent); }

/* ── 24. THE LEVEL MARKER ─────────────────────────────────────────────────────────────────────── */
/* A dimension line is not much use without a dimension on it. The marker rides the gauge down as you
   descend and reads the storey you are level with, ending at GND — which is the one piece of chrome
   on this site that tells you there is a bottom and that you are getting there. */
.gauge b { position: absolute; left: .55rem; top: calc(var(--p, 0) * 100%);
           transform: translateY(-50%);
           font-family: "SplineMono", ui-monospace, monospace; font-size: .56rem;
           letter-spacing: .14em; color: var(--accent); background: var(--paper);
           padding: .18rem .34rem; border: 1px solid var(--hair); border-radius: 2px;
           white-space: nowrap; }

/* ── 25. THE LEAF ─────────────────────────────────────────────────────────────────────────────── */
/* A drawing office does not letter over the drawing. It leaves a clear area and letters on that, and
   the drawing runs on around it — which is exactly the arrangement this page needs now that the
   structure runs the full height of the sheet.

   So each section's reading matter sits on a leaf of vellum, and the drawing shows in the margins,
   between the leaves, and behind the hero. The panel is sheer enough that the frame is still
   visible underneath — you can see what the page is standing on — and solid enough that nobody has
   to read small type through a lattice. */
.leaf {
  /* The vellum is ONE colour for every section on every sheet. It carried a per-section tint for a
     while — each leaf stamped a little darker than the one above it — and that was the wrong reading
     of the brief: it shaded the section's ground rather than shading the section. The fill is back
     to what it was, and the shading is a thing that happens AS YOU SCROLL (@see `centred`). */
  --leaf-bg:    var(--paper);                                     /* opaque, for the panels inside */
  --leaf-edge:  color-mix(in oklab, var(--ink) 32%, transparent);  /* the double rule's own colour */
  --leaf-shade: color-mix(in oklab, var(--hue) 34%, var(--ink));   /* what it casts */
  background: color-mix(in oklab, var(--paper) 88%, transparent);
  /* A double rule is the mark a ledger puts under a figure that is final, and the line a drawing
     puts around a detail that is complete. 3px is the width at which `double` renders as
     line-gap-line rather than as a thick smudge. */
  /* DOUBLE THE WEIGHT (owner): 3px to 6px. A double rule needs the extra room anyway - at 3px the
     two lines and the gap between them share three pixels and it reads as one thick smudge; at 6px
     it reads as what it is, the mark a ledger puts under a figure that is final. */
  border: 6px double var(--leaf-edge);
  border-radius: 3px;
  padding: clamp(1.3rem, 3.3vw, 3rem);
  backdrop-filter: blur(7px) saturate(1.05);
  box-shadow: var(--shadow);
}
/* Inside a leaf the nested panels stop being separate objects — one sheet, not a sheet of cards. */
.leaf .cell, .leaf .stat, .leaf .scroller, .leaf .entry > div { background: var(--leaf-bg); backdrop-filter: none; }
.leaf .cell.lit { background: color-mix(in oklab, var(--hue) calc(9% + var(--sheet-sat) * 9%), var(--leaf-bg)); }
.leaf .entry .foots { background: color-mix(in oklab, var(--hue) calc(8% + var(--sheet-sat) * 9%), var(--leaf-bg)); }
.leaf .head:last-child { margin-bottom: 0; }

/* The pull line is the one thing DELIBERATELY left on the bare drawing: a single sentence in a
   sheer face, big enough to read straight off the structure. It is the moment the page and the
   thing behind it are the same picture. */
.pull .pullq { max-width: 26ch; }

/* ── 26. THE SECTION SHADES AS YOU SCROLL ─────────────────────────────────────────────────────── */
/* The leaf you are actually reading lights its own edge, and dims it again as it leaves. On a long
   set this is the thing that tells you which detail on the sheet is live — the drawing-office
   equivalent of putting your finger on the one you are working from.

   Driven by the scroll timeline, not by an observer: `cover 50%` is the moment the leaf's centre and
   the viewport's centre coincide, which is exactly the definition asked for and is a number the
   browser already knows. No listener, no measurement, no class toggling, and it stays correct
   through a resize or a reflow because it was never measured in the first place.

   The keyframes go dim → lit → dim, so a leaf is only highlighted while it is genuinely the one in
   the middle. Everything here is border and shadow: the text does not move and the contrast of the
   reading matter does not change, because a passage that dims as you scroll past it is a passage you
   have to hurry. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .leaf {
      animation: centred linear both;
      animation-timeline: view();
      /* Nearly the section's whole travel through the viewport, which is what makes it SLOW: the
         shade comes up over most of a screen of scrolling rather than snapping on near the middle. */
      animation-range: cover 6% cover 94%;
    }
    @keyframes centred {
      /* One gesture, not two effects. A leaf rises out of the sheet as it comes up the screen —
         gaining the shade it casts — reaches full lift with its rule lit when its centre and the
         viewport's centre coincide, and settles back down as it leaves. The SHADE is the thing that
         develops slowly; the lit rule is the moment at the top of it. Nothing here touches the
         leaf's own colour: the paper it is printed on does not change while you read it. */
      0%, 100% { border-color: var(--leaf-edge);
                 box-shadow: var(--shadow); }
      50%      { border-color: var(--accent);
                 box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent) 30%, transparent),
                             0 30px 64px -34px color-mix(in oklab, var(--leaf-shade) 88%, transparent),
                             0 8px 22px -14px color-mix(in oklab, var(--leaf-shade) 48%, transparent); }
    }
    /* THE LADDER'S BOXES TAKE THE HIGHLIGHT THEMSELVES. On the pricing sheet the section card was
       stripped of its fill and its border so the drawing shows between the boxes — and that stripped
       the highlight with it: the animation was still running, on a border that is not there. Each box
       now runs it, so what lights as you come down the page is the section you are reading. The head
       box is excluded because it is sticky: pinned to the top, it never passes the centre, so it
       would either never light or never stop. */
    .ladbox:not(.ladhead) { animation: ladboxCentred linear both; animation-timeline: view();
                            animation-range: cover 6% cover 94%; }
    @keyframes ladboxCentred {
      0%, 100% { border-color: var(--hair); box-shadow: none; }
      50%      { border-color: var(--accent);
                 box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent) 30%, transparent),
                             0 30px 64px -34px color-mix(in oklab, var(--leaf-shade) 88%, transparent); }
    }

    /* The tick above a heading picks it up too — one accent, two places, so the highlight reads as
       "this section" rather than as a box that happens to have changed colour. */
    .leaf .head .tick::after { animation: centredRule linear both; animation-timeline: view();
                               animation-range: cover 6% cover 94%; }
    @keyframes centredRule {
      0%, 100% { background: var(--hair); }
      50%      { background: color-mix(in oklab, var(--accent) 55%, var(--hair)); }
    }
  }
}

/* ── 27. THE BAR CARRIES EACH SHEET'S OWN COLOUR ──────────────────────────────────────────────── */
/* Hover a sheet in the bar and it lights in THAT sheet's colour, not in this one's — so the bar is a
   preview of where you are about to go rather than a row of identical links. It reads the same
   `--sw` table the contents swatches read, because a colour that lives in two places is a colour
   that will eventually be two colours.
   The TEXT is mixed toward the ink: several of these hues are bright enough to be illegible as small
   type on paper (gold on off-white is about two to one), and a hover state you cannot read is worse
   than none. The pure colour goes where it is safe — the underline and a faint wash behind it. */
.navlinks a:hover, .sheetrow a:hover {
  color: color-mix(in oklab, var(--sw, var(--ink)) 74%, var(--ink));
  background: color-mix(in oklab, var(--sw, var(--ink)) 13%, transparent);
  box-shadow: inset 0 -2px 0 var(--sw, var(--accent));
}
/* The sheet you are ON keeps its mark in its own colour, which is this page's accent. */
.navlinks a[aria-current="page"] { box-shadow: inset 0 -2px 0 var(--accent); }
.sheetrow a[aria-current="page"]:hover { color: var(--paper); background: var(--ink); box-shadow: none; }
/* Kora has no one colour, so the rule under it in the bar is the whole run. It has to come after the
   hover rule above: that one sets the `background` SHORTHAND, which resets background-image. */
.navlinks a[data-sheet-hue="01"]:hover,
.navlinks a[data-sheet-hue="01"][aria-current="page"],
.sheetrow a[data-sheet-hue="01"]:hover,
.sheetrow a[data-sheet-hue="01"][aria-current="page"] {
  box-shadow: none;
  background-image: linear-gradient(95deg, #6781FF, #50D1C4 18%, #6ED068 34%, #FBBE52 50%,
                                    #FF9A4E 64%, #FF7656 78%, #FF66B2 90%, #AD74FF);
  background-size: 100% 2px; background-position: 0 100%; background-repeat: no-repeat;
}
/* the index chip keeps its ink ground AND the run under it - the shorthand above would have wiped
   the image, so the ground is set as a colour longhand here instead */
.sheetrow a[data-sheet-hue="01"][aria-current="page"] { background-color: var(--ink); color: var(--paper); }

/* ── 28. WHAT IS ON THIS PAGE ─────────────────────────────────────────────────────────────────── */
/* A plain list of the page's contents, right under the headline. Every sheet carries one, because a
   visitor who has only seen the menu bar should not have to scroll a page to find out whether it is
   the one they want. */
.covers { display: flex; flex-wrap: wrap; gap: .4rem .5rem; align-items: baseline;
          margin: 1.4rem 0 0; max-width: 56ch; }
.covers span { font-family: "SplineMono", ui-monospace, monospace; font-size: .6rem;
               letter-spacing: .17em; text-transform: uppercase; color: var(--graphite);
               margin-right: .3rem; }
.covers b { font-family: "SplineMono", ui-monospace, monospace; font-weight: 400; font-size: .68rem;
            letter-spacing: .04em; color: var(--ink-2); padding: .26rem .55rem;
            border: 1px solid var(--hair); border-radius: 2px;
            background: color-mix(in oklab, var(--hue) 8%, transparent); }

/* ── 15. THE LADDER ───────────────────────────────────────────────────────────────────────────── */
/* Plans across the top, what each one gets underneath. It is a ledger with a second axis, so it
   keeps the ledger's rules — hairlines, tabular figures, uppercase row heads — and adds the two
   things a wide comparison actually needs: the plan names stay put while you scroll down, and the
   row labels stay put while you scroll sideways. Without both, a matrix this wide is a puzzle.
   Sticky needs an explicit background or the cells scroll THROUGH each other; --leaf-bg is the
   section's own fill, so it matches whichever sheet this lands on. */
.ladderwrap { --lad-bg: var(--leaf-bg, var(--paper)); }
.ladder { width: 100%; border-collapse: separate; border-spacing: 0;
          font-family: "SplineMono", ui-monospace, monospace; font-variant-numeric: tabular-nums;
          font-size: .82rem; }

/* the row-label column: sticky, and ruled off from the cells so the eye knows where data starts */
.ladder .lad-rowhead {
  position: sticky; left: 0; z-index: 2; background: var(--lad-bg);
  text-align: left; vertical-align: top;
  padding: .6rem .9rem .6rem 1rem; border-right: 1px solid var(--ink);
  border-bottom: 1px solid var(--hair); font-weight: 500;
}
/* A table cell treats max-width as a suggestion and grows to fit its content, which on a phone let
   the label column swallow the whole viewport. Constrain the BLOCK inside the cell instead, which
   honours it, and let the note wrap. */
.ladder .lad-lab { display: block; width: 14.5rem; max-width: 14.5rem; }
.ladder .lad-rowhead b { display: block; font-size: .8rem; letter-spacing: -.01em; color: var(--ink);
                         text-transform: none; font-weight: 600; }
.ladder .lad-rowhead .sub { display: block; margin-top: .18rem; font-family: inherit; font-size: .66rem;
                            line-height: 1.4; color: var(--graphite); text-transform: none; letter-spacing: 0; }

/* The header is four rows now — name, price, seats, the button. Only the NAMES pin: four sticky
   rows would hold a third of a phone screen before a single feature appeared, and the name is the
   one you need while reading down. The rest scrolls away like any heading. */
.ladder thead th, .ladder thead td {
  background: var(--lad-bg); text-align: center;
  padding: .5rem .7rem; border-bottom: 1px solid var(--hair);
}
.ladder thead .lad-name th, .ladder thead .lad-name td { position: sticky; top: 0; z-index: 3; }
.ladder thead .lad-cta th, .ladder thead .lad-cta td { border-bottom: 1px solid var(--ink); padding-bottom: .85rem; }
.ladder thead .lad-rowhead { z-index: 4; }

.ladder .lad-name th b { font-family: "Fraunces", Georgia, serif; font-size: 1.02rem; font-weight: 600;
                         letter-spacing: -.015em; color: var(--ink); text-transform: none; }
.ladder .fig { display: block; font-size: .96rem; font-weight: 600; color: var(--ink); letter-spacing: -.02em; }
.ladder .lad-price .sub, .ladder .lad-seats .sub {
  display: block; font-size: .6rem; line-height: 1.35; color: var(--graphite);
  letter-spacing: .04em; margin-top: .1rem;
}
.ladder .lad-seats .fig { font-size: .86rem; }
/* the row heads inside thead are labels, not names — quiet them back down */
.ladder thead .lad-price.lad-rowhead, .ladder thead .lad-seats.lad-rowhead,
.ladder thead tr > th.lad-rowhead {
  font-size: .625rem; letter-spacing: .16em; text-transform: uppercase; color: var(--graphite); font-weight: 500;
}

/* ── EACH SECTION ITS OWN BOX ─────────────────────────────────────────────────────────────────
   Owner, twice: separate boxes with the drawing showing between them. Every section is its own
   TABLE in its own bordered box, and the half inch between them is page, not panel — which is the
   whole point, because that is where the dollar sign behind the sheet comes through.

   FIXED LAYOUT IS WHAT MAKES IT POSSIBLE. Separate tables normally size their columns
   independently and the plan names stop lining up down the page; declaring the widths in a colgroup
   and switching off auto layout means every box aligns by construction rather than by luck. */
/* THE SECTION CARD HAS TO GET OUT OF THE WAY. The boxes were genuinely separate — four of them,
   forty-eight pixels apart, each with its own border — and the gap still showed a flat panel,
   because the .leaf wrapping the whole section is 88% opaque and sits between the gap and the
   drawing. Separating the boxes was never going to be enough while something solid was behind them.
   On this one section the leaf carries no fill, no border and no ruling: the boxes provide all
   three themselves, and what shows between them is the sheet. */
#ladder > .leaf {
  background: transparent;
  background-image: none;
  border: 0;
  backdrop-filter: none;
  padding-left: 0;
  padding-right: 0;
  /* AND ITS SHADOW, AND ITS SCROLL HIGHLIGHT. Stripping the fill, the border and the ruling was not
     enough: the leaf still cast `--shadow` at rest and the `centred` animation still drew its
     0-0-0-2px accent ring as the section passed the middle of the screen. That ring wraps the WHOLE
     stack of boxes, so it ran down both sides THROUGH every half-inch gap — a line joining the
     squares the gaps exist to separate. The boxes carry their own border and their own highlight
     now (see .ladbox), so the leaf carries neither. The ID selector beats the .leaf rule inside the
     scroll-timeline media block, which is why animation:none takes here. */
  box-shadow: none;
  animation: none;
}
.ladderwrap { overflow-x: auto; background: transparent; border: 0; }
.ladbox {
  background: var(--lad-bg, var(--leaf-bg, var(--paper)));
  border: 2px solid var(--hair);
  border-radius: 3px;
  min-width: 64rem;
}
.ladbox + .ladbox { margin-top: 0.5in; }
.ladder { table-layout: fixed; width: 100%; border-collapse: collapse; }
.ladder col.c-lab  { width: 15.5rem; }
.ladder col.c-plan { width: auto; }
/* the header box carries the sticky plan names; the section boxes scroll normally */
.ladhead { position: sticky; top: var(--navh); z-index: 5; }   /* under the bar, not behind it */

/* a group divider — the drawing's section mark, spanning the sheet */
.ladder .lad-group th {
  position: sticky; left: 0; background: var(--lad-bg);
  padding: 1.15rem 1rem .4rem; text-align: left; border-bottom: 1px solid var(--ink);
}
.ladder .lad-group .tick { margin: 0; }

.ladder tbody td { text-align: center; padding: .5rem .7rem; border-bottom: 1px solid var(--hair);
                   vertical-align: middle; }
.ladder tbody tr:hover .lad-rowhead,
.ladder tbody tr:hover td { background: color-mix(in oklab, var(--hue) 8%, var(--lad-bg)); }

/* included: the sheet's own colour, so the shape of a plan reads as a block of colour down a column */
.ladder .mk { font-size: 1.5rem; line-height: 1;   /* half as big again (owner) */ color: var(--accent); font-weight: 700; }
.ladder .mk.no { color: color-mix(in oklab, var(--graphite) 55%, transparent); font-weight: 400; }
/* a tick that carries a COUNT — Suite's two entities. Set like the price beneath a charged cell,
   so a limit and a price read as the same kind of qualification on the mark above them. */
.ladder .inc { display: block; margin-top: .18rem; font-size: .7rem; line-height: 1.25;
               color: var(--ink-2); white-space: nowrap; }
.ladder .inc small { display: block; font-size: .58rem; color: var(--graphite); letter-spacing: .04em; }

/* purchasable: the price, because a cross that hides a number is not an answer */
.ladder .buy { display: inline-block; font-size: .7rem; line-height: 1.25; color: var(--ink-2); white-space: nowrap; }
.ladder .buy small { display: block; font-size: .58rem; color: var(--graphite); letter-spacing: .04em; }
.ladder .c-no { background: color-mix(in oklab, var(--graphite) 5%, transparent); }

/* the one column worth pointing at */
.ladder .lit { background: color-mix(in oklab, var(--hue) calc(7% + var(--sheet-sat) * 8%), var(--lad-bg)); }
.ladder thead .lad-name th.lit b { color: var(--accent); }
.ladder tbody tr:hover td.lit { background: color-mix(in oklab, var(--hue) calc(13% + var(--sheet-sat) * 8%), var(--lad-bg)); }

/* the button under each seat count */
.ladbuy {
  display: block; text-align: center; text-decoration: none;
  font-family: "Archivo", system-ui, sans-serif; font-size: .7rem; font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase; white-space: nowrap;
  /* Owner 2026-09-14: white box, the sheet's own colour for the rule and the word. On a sheet whose
     accent is already the page's one loud thing, a filled black button fought it; outlined, the row
     of buttons reads as one gesture in the sheet's colour and fills only on hover. */
  padding: .5rem .6rem; border: 1px solid var(--accent); border-radius: 2px;
  background: var(--paper); color: var(--accent);
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.ladbuy:hover, .ladbuy:focus-visible { background: var(--accent); border-color: var(--accent); color: var(--paper); }
.ladder .lad-cta .sub { display: block; margin-top: .3rem; font-size: .6rem; line-height: 1.3;
                        color: var(--graphite); letter-spacing: .04em; }
/* THE SCROLLING TABLE'S FOCUS RING. The wrapper is a keyboard region wherever the table is wider
   than the screen (site.js decides, per viewport), and a region a keyboard can land in must SHOW
   that it has landed — an invisible focus stop is the same bug in a different direction. Inset,
   because the ring sits on the panel's own edge. */
.scroller:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: 2px; }

/* THE PRELAUNCH LINE. It sits under the hero buttons and says the one thing a reader needs before
   they read a price list: there is nothing to buy today. Ruled off rather than coloured, because a
   warning colour would read as an error and this is not one. */
.prelaunch { margin-top: 1.1rem; padding-left: .9rem; border-left: 2px solid var(--accent);
             font-size: .92rem; }

/* visually hidden, still read aloud */
.vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

.ladderwrap > .ladder { min-width: 64rem; }
@media (max-width: 720px) {
  .ladder { font-size: .76rem; }
  .ladder .lad-lab { width: 10rem; max-width: 10rem; }
  .ladder .lad-name th b { font-size: .9rem; }
}
/* THE HERO IS EXEMPT. Owner 2026-09-15: ruling on the cards, not on the top box. A 3rem headline
   over a 1.6rem grid reads as interference, and the hero is the one place on a sheet that should be
   quiet behind the words. The background/foreground split is done with background-image rather than
   a wrapper so nothing needs re-nesting. */
.hero .leaf, .hero .plate, .hero .spec, .hero .cell, .hero .stat { background-image: none; }

.lad-foot { margin: .85rem 0 0; font-size: .82rem; line-height: 1.5; color: var(--ink-2); max-width: 68ch; }
.ladder .lad-groupnote { display: block; max-width: 60ch; margin-top: .35rem; font-family: "Inter", system-ui, sans-serif;
                         font-size: .78rem; line-height: 1.5; color: var(--ink-2); letter-spacing: 0; text-transform: none; }

/* THE LADDER ON A PHONE.
   The label column was 15.5rem - 248px of a 375px screen - against a table insisting on 64rem. Two
   thirds of the phone went to row labels, and the plan columns you scrolled toward arrived
   UNDERNEATH them with barely a hundred pixels left to stand in. A sticky column earns its keep only
   if there is something to read beside it: the label narrows, the row note steps out (it is the
   longest text on the sheet and it describes a line that has a page of its own), and the table stops
   demanding 64rem. Three plan columns are legible at once instead of one and a bit. */
@media (max-width: 760px) {
  .ladbox { min-width: 42rem; }
  .ladder col.c-lab { width: 8.6rem; }
  .ladder .lad-lab { width: 7.8rem; max-width: 7.8rem; }
  .ladder .lad-rowhead { padding: .5rem .45rem .5rem .55rem;
                         box-shadow: 2px 0 4px -2px rgba(0,0,0,.18); }
  .ladder .lad-rowhead b { font-size: .72rem; line-height: 1.25; }
  .ladder .lad-rowhead .sub { display: none; }
  .ladder tbody td { padding: .45rem .3rem; }
  .ladder .buy { font-size: .6rem; }
  .ladder .buy small { font-size: .52rem; }
  .ladder .mk { font-size: 1.15rem; }
  .ladder .lad-name th b { font-size: .84rem; }
  /* The group note sits in a sticky, left-pinned header cell inside a table wider than the screen,
     so a max-width in ch let it run straight off the right edge and get clipped. Tie it to the
     VIEWPORT instead of to the table and it wraps where it can actually be read. */
  .ladder .lad-groupnote { max-width: calc(100vw - 3.4rem); font-size: .72rem; }
  .ladder .lad-group th { padding: .9rem .55rem .35rem .55rem; }
}


/* ── THE RULING, AT SECTION LEVEL ───────────────────────────────────────────────────────────────
   Owner 2026-09-15, twice. First it came off the background and onto the cards; that went a level
   too far in — ruling every small tile made the page busy and lost the thing the grid is for, which
   is to say "this whole section is a sheet of paper". So it sits on the LEAF, the section box, at
   the same level the hero box occupies. One sheet per section, cards floating clean on top of it.

   THE HERO IS STILL EXEMPT. It is the one box that should be quiet behind the words.

   LAST IN THE FILE ON PURPOSE: .leaf and its children set the shorthand `background`, and a
   shorthand resets background-image to none. An earlier rule here was silently wiped by a later one
   setting a colour, and the card the eye goes to first was the last to be fixed. */
.leaf {
  background-image:
    linear-gradient(var(--hair-2) 1px, transparent 1px),
    linear-gradient(90deg, var(--hair-2) 1px, transparent 1px);
  background-size: 100% 2.0rem, 2.0rem 100%;
}
.hero .leaf { background-image: none; }

/* ── THE CARD ANSWERS THE POINTER ──────────────────────────────────────────────────────────────
   Hover a section and its rule lights in THIS page's colour, so the thing under the cursor is the
   thing that is lit. !important is not laziness here and it is the whole reason this works: .leaf
   carries the scroll-driven centred animation, which sets border-color on every keyframe, and an
   animation beats a normal author declaration in the cascade. Author-important is the one weight
   that outranks it. */
.leaf:hover { border-color: var(--accent) !important; }
.ladbox:hover { border-color: var(--accent) !important; }
@media (prefers-reduced-motion: no-preference) {
  .leaf, .ladbox { transition: border-color .18s ease; }
}
