/* ═══════════════════════════════════════════════════════════════════
   Docket — the ledger design language.
   Ported from the design prototype (~/Projects/Code/sigil/docket-design).
   Rationale: folio topics/docket-visual-design
   Contract: folio procedures/docket-render-handoff
   Glyph constraints: folio topics/docket-font-glyph-coverage
   ═══════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════
   Docket — the ledger design language.  Prototype stylesheet.
   Tokens per issue-first-forge-design §12.5; layout re-derived
   against real content (see topics/docket-visual-design).
   ═══════════════════════════════════════════════════════════════════ */

/* ── type ──────────────────────────────────────────────────────── */

/* `block`, not `swap`, for the display face ALONE: it is the only one of
   the three that carries ❦ (U+2766).  Under `swap` the fleuron paints in
   whatever fallback the OS picks first — on this machine a colour emoji
   leaf — and then flips to the real mark.  A brief blank is better than
   a wrong glyph, and the mark is small enough that nothing else waits. */
@font-face {
  font-family: "EB Garamond";
  src: url("./fonts/eb-garamond.ttf") format("truetype");
  font-weight: 400 800;
  font-style: normal;
  font-display: block;
}
@font-face {
  font-family: "Literata";
  src: url("./fonts/literata.ttf") format("truetype");
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("./fonts/ibm-plex-mono.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ── tokens ────────────────────────────────────────────────────── */

:root {
  /* colour — ink, paper, cinnabar, graphite (§12.5) + two derived */
  --paper:      #fafaf7;
  --ink:        #1a1917;
  --rubric:   #e34234;   /* the ROLE. cinnabar is the ink that fills it by default. */
  --graphite:   #6b6b66;
  /* derived.  #e34234 on paper is 3.94:1 — fine for large type (AA needs
     3:1) but SHORT of 4.5:1 for text at reading size.  Small cinnabar runs
     use this darker draw of the same hue: 5.04:1. */
  --rubric-text: #ce2b1c;
  --rule:       #e0ded5;   /* the faintest possible hairline */
  --sunk:       #f2f1ea;   /* specimen ground, used sparingly */

  /* faces */
  --display: "EB Garamond", Georgia, serif;
  --written: "Literata", Georgia, serif;
  --measured: "IBM Plex Mono", ui-monospace, monospace;

  /* the page frame */
  --band:    8.5rem;   /* apparatus band — narrow, a margin not a column */
  --gutter:  1.75rem;  /* close enough to associate */
  --measure: 34.5rem;  /* the TEXT column only (≈66ch of Literata) */
  /* NOTE: do NOT hoist the leaf width into a custom property here.  A
     custom property holding calc(var(--measure) …) declared on :root
     resolves its inner var()s against :ROOT, so a page-level override
     like .leaf--code{--measure:46rem} would be silently ignored.  The
     calc lives on .leaf, where it resolves per element. */

  /* rhythm */
  --step: 1.55rem;
  /* ONE step for every kind of set-in matter. Before this there were four
     arbitrary values doing the same job -- paragraph 1.35em, lists 1.5em,
     blockquote 1.2em, and a specimen indent of 1.6rem I was about to add as
     a fifth. An indent that varies by element reads as a margin someone
     picked; an indent that is always the same reads as a level.

     In REM, not em, and that distinction is load-bearing: em resolves
     against each ELEMENT's font-size, so the same 1.5em produced 21.6px on
     a specimen, 24.3px on a table and 27px on a list -- three different
     steps from one token. Measured, not assumed. A block indent must be
     constant across the page so blocks line up with each other; a
     paragraph's FIRST-LINE indent stays in em below, because that one
     should scale with its own text. Same number, different unit, for a
     reason. */
  --step-in: 1.5rem;

  color-scheme: light dark;
}

html[data-mode="dark"],
:root:not([data-mode="light"]) {
  /* placeholder so the cascade below is symmetric; see @media block */
}

/* ── the themes ────────────────────────────────────────────────── */
/*
   A theme is PAPER + INK + RUBRIC.  Everything else — graphite, rule,
   sunk — is DERIVED by mixing that theme's own ink into its own paper,
   so the greys always sit correctly on the stock they are printed on.
   Three declared values per mode, not seven knobs.

   Rules, all of them within-page rather than cross-project, so they hold
   for a standalone single-project Docket too:

     · NO GREEN RUBRIC, EVER.  The rubric means unresolved / needs
       attention, and the design pays for that meaning by having no green
       anywhere (a pass is ink, not a green tick).  A green rubric makes
       "needs attention" read as success on that project's own pages.
       A teal `celadon` was drawn up and DROPPED for this reason: it
       measured fine (4.52:1) and looked good, but a bright-line rule bent
       once is not a rule.

     · GOLD CANNOT BE A RUBRIC ON LIGHT PAPER.  Measured: gold leaf
       #d4af37 is 2.01:1 on paper, bright gold 1.34:1, old gold 2.31:1 —
       all below the 3:1 floor for LARGE text, never mind 4.5:1 for the
       state words.  The historical answer is also the design answer:
       gold in a manuscript is not a yellow ink, it is gold leaf laid over
       a BOLE ground.  So `gilt` puts the warm metallic tone in the PAPER,
       where it carries no contrast burden, and its rubric is the bole
       beneath the leaf.  In dark mode the gold comes forward (8.25:1),
       because on a near-black ground it has contrast to spare.

     · Every derived value is checked against ITS OWN paper, not the
       default paper.  Ratios are in the per-theme comments.
*/

/* azoth     — vermilion, the ore of mercury    ink 16.8 · rubric 3.94 · rubric-text 4.53 · graphite 5.02 */
[data-theme="azoth"] {
  --paper: #fafaf7; --ink: #1a1917;
  --rubric: #e34234; --rubric-text: #dc2d1e;
  --graphite: #6d6c6a; --rule: #dfdfdc; --sunk: #eeeeeb;
}
/* foolscap  — ultramarine, ground lapis        ink 16.5 · rubric 6.09 · rubric-text 6.28 · graphite 4.99 */
[data-theme="foolscap"] {
  --paper: #f4f7fa; --ink: #14181f;
  --rubric: #2f5bab; --rubric-text: #2e59a8;
  --graphite: #676b70; --rule: #d9dce0; --sunk: #e8ebee;
}
/* porphyry  — Tyrian purple, from the murex    ink 15.5 · rubric 6.82 · rubric-text 6.88 · graphite 4.80 */
[data-theme="porphyry"] {
  --paper: #f7f2f1; --ink: #1f1a1b;
  --rubric: #8a2f7b; --rubric-text: #892f7a;
  --graphite: #6f6a6a; --rule: #ddd8d7; --sunk: #ebe6e5;
}
/* gilt      — gold leaf over its bole ground   ink 16.2 · rubric 5.48 · rubric-text 5.67 · graphite 4.93 */
[data-theme="gilt"] {
  --paper: #faf6ec; --ink: #1c1913;
  --rubric: #8a5a12; --rubric-text: #875812;
  --graphite: #6e6b63; --rule: #dfdbd2; --sunk: #eeeae0;
}
/* madder    — madder root, the rose lake       ink 16.3 · rubric 5.92 · rubric-text 6.09 · graphite 4.96 */
[data-theme="madder"] {
  --paper: #fbf4f5; --ink: #1d1719;
  --rubric: #a8325a; --rubric-text: #a53158;
  --graphite: #6f696a; --rule: #e0d9db; --sunk: #efe8e9;
}
/* indigo    — indigo, the vat dye              ink 16.2 · rubric 8.49 · rubric-text 8.64 · graphite 4.98 */
[data-theme="indigo"] {
  --paper: #f3f4f8; --ink: #16171f;
  --rubric: #3b3d8f; --rubric-text: #3a3c8d;
  --graphite: #68696f; --rule: #d8d9de; --sunk: #e7e8ec;
}
/* umber     — burnt umber, an earth            ink 16.0 · rubric 6.78 · rubric-text 6.78 · graphite 4.91 */
[data-theme="umber"] {
  --paper: #f7f4f0; --ink: #1c1915;
  --rubric: #7a4a1f; --rubric-text: #7a4a1f;
  --graphite: #6d6a66; --rule: #dddad6; --sunk: #ebe8e4;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-mode="light"])[data-theme="azoth"],
  :root:not([data-mode="light"]) [data-theme="azoth"] {
    --paper: #1a1917; --ink: #f3f1ec;
    --rubric: #e33f31; --rubric-text: #e54b3e;
    --graphite: #a3a19d; --rule: #343331; --sunk: #262523;
  }
  :root:not([data-mode="light"])[data-theme="foolscap"],
  :root:not([data-mode="light"]) [data-theme="foolscap"] {
    --paper: #14181f; --ink: #eceff4;
    --rubric: #5b8ada; --rubric-text: #5988d9;
    --graphite: #9c9fa5; --rule: #2e3239; --sunk: #20242b;
  }
  :root:not([data-mode="light"])[data-theme="porphyry"],
  :root:not([data-mode="light"]) [data-theme="porphyry"] {
    --paper: #1f1a1b; --ink: #f0eaec;
    --rubric: #c765b6; --rubric-text: #c662b5;
    --graphite: #a39d9f; --rule: #383334; --sunk: #2a2526;
  }
  :root:not([data-mode="light"])[data-theme="gilt"],
  :root:not([data-mode="light"]) [data-theme="gilt"] {
    --paper: #1a1712; --ink: #f2ede0;
    --rubric: #d9a93f; --rubric-text: #d8a73b;
    --graphite: #a29e94; --rule: #34312b; --sunk: #26231d;
  }
  :root:not([data-mode="light"])[data-theme="madder"],
  :root:not([data-mode="light"]) [data-theme="madder"] {
    --paper: #1d1719; --ink: #f3e9ec;
    --rubric: #e07898; --rubric-text: #e07697;
    --graphite: #a49b9e; --rule: #373032; --sunk: #292325;
  }
  :root:not([data-mode="light"])[data-theme="indigo"],
  :root:not([data-mode="light"]) [data-theme="indigo"] {
    --paper: #16171f; --ink: #eaebf2;
    --rubric: #8b8ee0; --rubric-text: #8a8de0;
    --graphite: #9c9da4; --rule: #2f3038; --sunk: #22232b;
  }
  :root:not([data-mode="light"])[data-theme="umber"],
  :root:not([data-mode="light"]) [data-theme="umber"] {
    --paper: #1c1915; --ink: #f0eae2;
    --rubric: #c98a4a; --rubric-text: #c88846;
    --graphite: #a29d96; --rule: #35322e; --sunk: #282420;
  }
}
html[data-mode="dark"][data-theme="azoth"],
html[data-mode="dark"] [data-theme="azoth"] {
  --paper: #1a1917; --ink: #f3f1ec;
  --rubric: #e33f31; --rubric-text: #e54b3e;
  --graphite: #a3a19d; --rule: #343331; --sunk: #262523;
}
html[data-mode="dark"][data-theme="foolscap"],
html[data-mode="dark"] [data-theme="foolscap"] {
  --paper: #14181f; --ink: #eceff4;
  --rubric: #5b8ada; --rubric-text: #5988d9;
  --graphite: #9c9fa5; --rule: #2e3239; --sunk: #20242b;
}
html[data-mode="dark"][data-theme="porphyry"],
html[data-mode="dark"] [data-theme="porphyry"] {
  --paper: #1f1a1b; --ink: #f0eaec;
  --rubric: #c765b6; --rubric-text: #c662b5;
  --graphite: #a39d9f; --rule: #383334; --sunk: #2a2526;
}
html[data-mode="dark"][data-theme="gilt"],
html[data-mode="dark"] [data-theme="gilt"] {
  --paper: #1a1712; --ink: #f2ede0;
  --rubric: #d9a93f; --rubric-text: #d8a73b;
  --graphite: #a29e94; --rule: #34312b; --sunk: #26231d;
}
html[data-mode="dark"][data-theme="madder"],
html[data-mode="dark"] [data-theme="madder"] {
  --paper: #1d1719; --ink: #f3e9ec;
  --rubric: #e07898; --rubric-text: #e07697;
  --graphite: #a49b9e; --rule: #373032; --sunk: #292325;
}
html[data-mode="dark"][data-theme="indigo"],
html[data-mode="dark"] [data-theme="indigo"] {
  --paper: #16171f; --ink: #eaebf2;
  --rubric: #8b8ee0; --rubric-text: #8a8de0;
  --graphite: #9c9da4; --rule: #2f3038; --sunk: #22232b;
}
html[data-mode="dark"][data-theme="umber"],
html[data-mode="dark"] [data-theme="umber"] {
  --paper: #1c1915; --ink: #f0eae2;
  --rubric: #c98a4a; --rubric-text: #c88846;
  --graphite: #a29d96; --rule: #35322e; --sunk: #282420;
}

/* The estate's own rubric, which a project may NOT take. */
:root { --estate-rubric: #e34234; }
@media (prefers-color-scheme: dark) { :root:not([data-mode="light"]) { --estate-rubric: #e33f31; } }
html[data-mode="dark"] { --estate-rubric: #e33f31; }

/* ── reset-ish ─────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

html {
  font-size: 18px;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--written);
  font-size: 1rem;
  line-height: 1.62;
  font-variant-numeric: oldstyle-nums proportional-nums;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; }

a {
  color: inherit;
  text-decoration-line: underline;
  text-decoration-color: var(--graphite);
  text-decoration-thickness: 0.5px;
  text-underline-offset: 0.19em;
}
a:hover { text-decoration-color: var(--rubric); text-decoration-thickness: 1px; }

:focus-visible {
  outline: 2px solid var(--rubric);
  outline-offset: 3px;
  border-radius: 1px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── the leaf: one page of the ledger ──────────────────────────── */

/* border-box means the padding must be ADDED to the max-width, or the
   grid inside overflows its own container and the composed assembly
   stops being centred. */
.leaf {
  max-width: calc(var(--band) + var(--gutter) + var(--measure) + 3rem);
  margin: 0 auto;
  padding: 3.5rem 1.5rem 6rem;
}

/* every block on the page is a row of the same two-column frame:
   apparatus in the band, written matter in the measure.  minmax(0, …)
   lets the measure give way between the breakpoints instead of
   overflowing the viewport. */
.row {
  display: grid;
  grid-template-columns: var(--band) minmax(0, var(--measure));
  column-gap: var(--gutter);
}

.note {
  grid-column: 1;
  text-align: right;          /* right-aligned, so the note kisses its text */
  font-family: var(--measured);
  font-size: 0.7rem;
  line-height: 1.5;
  letter-spacing: 0.02em;
  color: var(--graphite);
  font-variant-numeric: lining-nums tabular-nums;
  word-break: break-word;
  padding-top: 0.42em;        /* optically settle against the serif baseline */
}

.said {
  grid-column: 2;
  min-width: 0;
}

.row > .spread { grid-column: 1 / -1; min-width: 0; }

/* a section label is navigation — measured matter — so it lives in the
   band, not as a shouting heading in the text column (S11-B5). */
.label {
  font-family: var(--measured);
  font-size: 0.66rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--graphite);
}

.note .label { display: block; }

/* a stack of facts in the band; a wrapping run of them on a phone */
.facts { display: flex; flex-direction: column; gap: 0.95rem; align-items: flex-end; }
.fact { display: block; }

/* ── masthead ──────────────────────────────────────────────────── */

.estate {
  font-family: var(--measured);
  font-size: 0.7rem;
  letter-spacing: 0.05em;
  color: var(--graphite);
  margin-bottom: 3.2rem;
  display: flex;
  align-items: baseline;
  gap: 0.55rem;
  flex-wrap: wrap;
}
.estate a { text-decoration: none; }
.estate a:hover { text-decoration: underline; text-decoration-color: var(--rubric); }
.estate .mark {
  font-family: var(--display);
  font-size: 1.28rem;
  letter-spacing: 0.005em;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}
.estate .mark .fleuron {
  color: var(--estate-rubric);
  margin-right: 0.16em;
  font-size: 1.1em;
}
.estate .sep { opacity: 0.5; }

.masthead { margin-bottom: 1.2rem; }

.masthead h1 {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(2.7rem, 7vw, 3.9rem);
  line-height: 1.02;
  letter-spacing: -0.012em;
  margin: 0 0 0.28em;
}
.masthead h1 .of {
  color: var(--graphite);
  font-size: 0.42em;
  letter-spacing: 0.01em;
  display: block;
  margin-bottom: 0.35em;
  font-weight: 400;
}

.tagline {
  font-size: 1.16rem;
  line-height: 1.45;
  margin: 0 0 1.15em;
  max-width: 30rem;
  color: var(--ink);
}

.install {
  font-family: var(--measured);
  font-size: 0.82rem;
  color: var(--graphite);
  margin: 0 0 1.5em;
}
.install b { color: var(--ink); font-weight: 400; }
.install span { user-select: none; opacity: 0.55; }

/* the report CTA: prominent by TYPE, never a filled button (S11-B7) */
.cta {
  display: inline-block;
  font-family: var(--display);
  font-size: 1.62rem;
  font-weight: 500;
  line-height: 1.2;
  color: var(--rubric);
  text-decoration: none;
  padding-bottom: 0.1em;
  border-bottom: 1.5px solid var(--rubric);
  transition: border-bottom-width 90ms linear;
}
.cta .fleuron { margin-right: 0.32em; }
.cta:hover { border-bottom-width: 4px; }
.cta:focus-visible { border-bottom-color: transparent; }

/* ── written matter (prose, README, descriptions) ──────────────── */

.prose > :first-child { margin-top: 0; }
.prose > :last-child { margin-bottom: 0; }

.prose p {
  margin: 0;
  text-indent: 1.35em;          /* book setting: indent, not blank line */
  hyphens: auto;
}
.prose > p:first-of-type,
.prose h1 + p, .prose h2 + p, .prose h3 + p, .prose h4 + p,
.prose ul + p, .prose ol + p, .prose pre + p,
.prose table + p, .prose blockquote + p, .prose hr + p {
  text-indent: 0;
}

.prose h1, .prose h2, .prose h3, .prose h4 {
  font-family: var(--display);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.006em;
  margin: 2.1em 0 0.5em;
}
.prose h1 { font-size: 1.95rem; font-weight: 500; margin-top: 0; }
.prose h2 { font-size: 1.42rem; }
.prose h3 { font-size: 1.12rem; }
.prose h4 { font-size: 1rem; }

.prose ul, .prose ol {
  margin: 0.85em 0;
  padding-left: 1.15em;
}
.prose li { margin: 0.24em 0; }
.prose li > ul, .prose li > ol { margin: 0.24em 0; }
.prose ul { list-style: none; padding-left: 1.5em; }
.prose ul > li { position: relative; }
.prose ul > li::before {
  content: "—";
  position: absolute;
  left: -1.5em;
  width: 1.5em;
  color: var(--graphite);
  opacity: 0.5;
  font-size: 0.7em;
  top: 0.08em;
}
.prose ol { padding-left: 1.5em; }
.prose ol > li::marker { color: var(--graphite); font-family: var(--measured); font-size: 0.8em; }

.prose strong { font-weight: 650; }
.prose em { font-style: italic; }

/* a document's opening line, set as an epigraph rather than a stray bold run */
.prose .lede {
  font-family: var(--display);
  font-size: 1.42rem;
  font-style: italic;
  font-weight: 400;
  line-height: 1.3;
  color: var(--ink);
  text-indent: 0;
  margin: 0 0 1.1em;
}
.prose .lede strong { font-weight: 400; }

.prose blockquote {
  margin: 1.1em 0 1.1em 1.2em;
  color: var(--graphite);
  font-style: italic;
}

.prose hr {
  border: 0;
  margin: 2.4em 0;
  text-align: center;
}
.prose hr::after {
  content: "❦";
  color: var(--graphite);
  opacity: 0.6;
  font-family: var(--display);
  font-size: 1.25rem;
}

/* inline code: measured matter inside written matter */
code, .mono {
  font-family: var(--measured);
  font-variant-numeric: lining-nums tabular-nums;
}
/* no fill, no pill — the face is the difference (fewer boxes) */
.prose :not(pre) > code {
  font-size: 0.84em;
  color: var(--ink);
  word-break: break-word;
}

/* ── specimens: code blocks step IN, as bookwork sets quoted matter ── */
/*
   No fill, no border, no cage -- that finding held and is the point.
   But they used to break LEFT out of the measure to the apparatus band,
   and David was right that it looked broken: it abandoned the prose edge
   by ~10rem with nothing beside it, so it read as a layout fault rather
   than as a change of register.

   The justification was backwards. Bookwork indents quoted and set-in
   matter INWARD; breaking outward is a modern web idiom (full-bleed
   images), not a fine-press one. And the width argument was weak anyway:
   at the measure a mono line still fits ~86 characters.

   Conflating "does not need a cage" with "should escape the column" is
   the error; only the first was ever true.
*/

.prose pre, pre.specimen {
  margin: 1.5em 0 1.5em var(--step-in);
  padding: 0 0 0 0;
  font-family: var(--measured);
  font-size: 0.8rem;
  line-height: 1.62;
  color: var(--ink);
  overflow-x: auto;
  background: none;
  border: 0;
  tab-size: 2;
  scrollbar-width: thin;
}
.prose pre code, pre.specimen code {
  background: none;
  padding: 0;
  font-size: inherit;
  display: block;
  min-width: max-content;
}

/* sigil-markdown puts a fenced block's info string on the element as
   lang="scheme", so the specimen label comes straight off the attribute --
   no wrapper element, and it cannot drift from the fence it labels. */
pre[lang]::before {
  content: attr(lang);
  margin-left: var(--step-in);
  margin-left: var(--step-in);
  display: block;
  font-family: var(--measured);
  font-size: 0.62rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--graphite);
  opacity: 0.55;
  margin-bottom: 0.7em;
}

/* the specimen's own quiet label, set in the band it now occupies */
.specimen-lang {
  font-family: var(--measured);
  font-size: 0.62rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--graphite);
  opacity: 0.55;
  margin-left: var(--step-in);
  margin-bottom: -1.15em;
  margin-top: 1.7em;
  display: block;
}

/* ── tables: also break left, they are measured matter ─────────── */

.prose table, table.ledger {
  margin: 1.6em 0 1.6em var(--step-in);
  width: calc(100% - var(--step-in));
  border-collapse: collapse;
  font-size: 0.9rem;
}
/* two rules only — head and foot, as a book sets a table.            */
.prose th, table.ledger th {
  text-align: left;
  font-family: var(--measured);
  font-weight: 400;
  font-size: 0.64rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--graphite);
  padding: 0 1.4em 0.45em 0;
  vertical-align: bottom;
  border-bottom: 1px solid var(--rule);
}
.prose td, table.ledger td {
  padding: 0.42em 1.4em 0.42em 0;
  vertical-align: baseline;
  border: 0;
}
.prose thead + tbody tr:first-child td,
table.ledger thead + tbody tr:first-child td { padding-top: 0.75em; }
.prose tbody tr:last-child td,
table.ledger tbody tr:last-child td {
  padding-bottom: 0.75em;
  border-bottom: 1px solid var(--rule);
}
.prose td:last-child, .prose th:last-child { padding-right: 0; }
.prose td:first-child { white-space: nowrap; }

/* a commit subject is written matter, and it is the page's title */
.commit-subject {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(1.9rem, 4.4vw, 2.5rem);
  line-height: 1.14;
  letter-spacing: -0.008em;
  margin: 0;
}

/* a diffstat is measured matter: mono, tabular, right-aligned */
table.files td.num, table.files th.num {
  font-family: var(--measured);
  font-size: 0.78rem;
  font-variant-numeric: lining-nums tabular-nums;
  text-align: right;
  white-space: nowrap;
  width: 1%;
  color: var(--graphite);
  padding-right: 0;
  padding-left: 1.2em;
}
table.files th.num { text-align: right; }
table.files td:first-child {
  font-family: var(--measured);
  font-size: 0.8rem;
  white-space: normal;
  word-break: break-all;
}

/* an entry quoted inside another page's section sheds its own band */
.entry.cited { padding-top: 0; }

/* ── the entry: one line of the ledger ─────────────────────────── */

.entries { margin: 0; }

.entry {
  display: grid;
  grid-template-columns: var(--band) minmax(0, var(--measure));
  column-gap: var(--gutter);
  padding: 0.52rem 0;
}
.entry + .entry { border-top: 1px solid transparent; }

.entry .subject {
  font-size: 1rem;
  line-height: 1.4;
  margin: 0;
}
/* A subject that is ENTIRELY a link needs no underline — the whole line is
   the target.  A link INSIDE a sentence still has to look like one. */
.entry .subject > a:only-child { text-decoration: none; }
.entry .subject > a:only-child:hover {
  text-decoration: underline;
  text-decoration-color: var(--rubric);
}

.under {
  font-family: var(--measured);
  font-size: 0.72rem;
  color: var(--graphite);
  margin: 0.1rem 0 0;
  font-variant-numeric: lining-nums tabular-nums;
}

/* the digest is the page's written matter — it earns a paragraph, and a
   larger subject, because it is the thing a reader came for (S11-B2) */
.entry.digest { padding: 1.1rem 0 1.6rem; }
.entry.digest .subject {
  font-family: var(--display);
  font-size: 1.6rem;
  font-weight: 500;
  line-height: 1.18;
  margin-bottom: 0.5rem;
}
.digest-body { margin-bottom: 0.6rem; }

/* the band's two registers: the day groups the run, provenance is per entry */
.day { display: block; color: var(--ink); }
.day:empty::before { content: "\00a0"; }
.prov { display: block; }
.prov .kind { color: var(--graphite); }

/* ── search ────────────────────────────────────────────────────── */

.search-form { margin: 0 0 0.8rem; }
input[type="search"] {
  width: 100%;
  font-family: var(--display);
  font-size: clamp(1.9rem, 4.5vw, 2.6rem);
  font-weight: 500;
  line-height: 1.15;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--graphite);
  border-radius: 0;
  padding: 0 0 0.12em;
  -webkit-appearance: none;
  appearance: none;
}
input[type="search"]:focus {
  outline: 0;
  border-bottom-color: var(--rubric);
  border-bottom-width: 2px;
  padding-bottom: calc(0.12em - 1px);
}

/* the hit itself, in the reader's own words */
.excerpt {
  margin: 0.15rem 0 0;
  font-size: 0.94rem;
  line-height: 1.5;
  color: var(--graphite);
  text-indent: 0;
}
.excerpt code { font-size: 0.86em; color: var(--graphite); }

/* a match is marked the way a reader marks a book: underlined, not
   highlighted in a colour that belongs to living things */
mark {
  background: none;
  color: inherit;
  box-shadow: inset 0 -0.42em 0 var(--sunk);
  border-bottom: 1px solid var(--graphite);
}
.subject mark { box-shadow: inset 0 -0.36em 0 var(--sunk); }

/* ── the release ripple (§12.3's signature) ────────────────────── */
/* One mark per dependent, not a bar chart.  It is a tally, which is what
   a ledger keeps, and it stays honest at any count because you can
   literally count it. */

.ripples { margin-top: 0.9rem; }
.ripple-row + .ripple-row { margin-top: 1.6rem; }

.ripple-line {
  margin: 0 0 0.4rem;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.7rem;
}
.ripple-what { font-size: 0.95rem; color: var(--ink); }
.ripple-count {
  font-family: var(--measured);
  font-size: 0.68rem;
  letter-spacing: 0.02em;
  color: var(--graphite);
}

.ripple-marks {
  margin: 0 0 0.3rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.34rem;
  line-height: 1;
}
.rip { display: inline-flex; align-items: center; }
.rip.done { color: var(--ink); }
.rip.done .att-mark { margin-right: 0; width: 0.72rem; height: 0.72rem; stroke-width: 2.2; }
.rip.wait {
  font-family: var(--measured);
  color: var(--graphite);
  opacity: 0.55;
  width: 0.72rem;
  justify-content: center;
}

/* ── cards: the ONE page where a box earns its keep (§12.5) ────── */
/* Even here it is a ground, not a frame: no border, no shadow, no
   radius worth naming.  The box exists because the content is genuinely
   tabular, and for no other reason. */

.leaf--wide { --measure: 46rem; }

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15.5rem, 1fr));
  gap: 0.8rem;
  margin-top: 0.4rem;
}

.card {
  display: block;
  background: var(--sunk);
  padding: 0.95rem 1.1rem 1.05rem;
  border-radius: 2px;
  text-decoration: none;
  /* NO background transition. Its value comes from --paper, and a
     transitioned property whose value is a custom property does not
     reliably re-resolve when that property changes -- the computed
     background stays STALE at the old theme's colour until something
     forces a reflow. It cost me time twice: once as a mid-transition
     screenshot I nearly "fixed" as a bug, and once as a genuinely stale
     computed value while checking the estate swatches. A real visitor
     never switches mode mid-page, so it buys nothing and lies to anyone
     who does. */
}
.card:hover { background: var(--rule); }

.card-name {
  display: block;
  font-family: var(--measured);
  font-size: 0.92rem;
  color: var(--ink);
  margin-bottom: 0.3rem;
}
/* A project card on a cross-project surface is a SWATCH of that project's
   own stock: its paper, its ink, its rubric.  Honest — the card shows you
   what the page it links to actually looks like.  A hairline in the card's
   own rule colour is needed because a swatch of near-white paper sitting on
   near-white paper has no edge otherwise; this is the one place a card gets
   a frame, and it is doing real work. */
.card[data-theme] {
  background: var(--paper);
  color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--rule);
}
.card[data-theme]:hover { background: var(--sunk); }
.card[data-theme] .card-name { color: var(--rubric-text); }
.card[data-theme] .card-line { color: var(--ink); }
.card[data-theme] .card-facts { color: var(--graphite); }
.card:hover .card-name { color: var(--rubric-text); }

.card-line {
  display: block;
  font-size: 0.94rem;
  line-height: 1.42;
  color: var(--ink);
  margin-bottom: 0.65rem;
}

.card-facts {
  display: flex;
  flex-direction: column;
  gap: 0.16rem;
  font-family: var(--measured);
  font-size: 0.68rem;
  letter-spacing: 0.02em;
  color: var(--graphite);
  font-variant-numeric: lining-nums tabular-nums;
}

/* ── the report form ───────────────────────────────────────────── */
/* An input is a SINGLE BASELINE RULE, not a filled well: the ledger sets
   matter on ruled paper, and a boxed field would be the one control-panel
   gesture on a page that is otherwise a book. The multi-line textarea gets a
   --sunk ground because it holds a block of matter rather than a line of it.
   Focus turns the baseline rubric and thickens it, which is the same move
   .cta makes on hover -- one idea, two places.

   The label sits ABOVE its field and is measured matter, so it takes the
   mono at label size. That keeps the form inside the same serif/mono split
   as every other page instead of inventing a third register for itself. */

.field { margin: 0 0 1.45rem; }
.field label {
  display: block;
  font-family: var(--measured);
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--graphite);
  margin-bottom: 0.3rem;
}
.field input,
.field select,
.field textarea {
  display: block;
  width: 100%;
  font-family: var(--written);
  font-size: 1rem;
  line-height: 1.5;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1.5px solid var(--rule);
  border-radius: 0;
  padding: 0.35rem 0;
  /* border-box, or the 100% width plus padding overflows the measure --
     the same trap the .leaf padding has (handoff §6 trap 3). */
  box-sizing: border-box;
}
.field textarea {
  background: var(--sunk);
  border-bottom-color: var(--rule);
  padding: 0.7rem 0.85rem;
  font-family: var(--measured);
  font-size: 0.86rem;
  resize: vertical;
}
.field select {
  /* the native arrow is the one affordance worth keeping: it is how a reader
     knows this is a list rather than a text field, with no script involved */
  appearance: auto;
  padding-left: 0;
}
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-bottom: 3px solid var(--rubric);
}
.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible { outline: none; }
.field .hint {
  display: block;
  font-family: var(--written);
  font-size: 0.85rem;
  font-style: italic;
  color: var(--graphite);
  margin-top: 0.4rem;
}

/* A checkbox is the one field whose label belongs BESIDE it, because the box
   is the thing and the words describe it rather than name it. */
.field--check { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: 0.6rem; }
.field--check input {
  width: auto;
  border: 0;
  margin-top: 0.15rem;
  accent-color: var(--rubric);
}
.field--check label {
  font-family: var(--written);
  font-size: 1rem;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
  margin-bottom: 0;
}
.field--check .hint { grid-column: 2; }

.compose-actions {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 1.4rem;
  margin: 1.9rem 0 0;
}
/* A submit BUTTON wearing .cta: the stylesheet already handles the element,
   and the design's rule is that a CTA is a line of type with a rubric
   baseline and NEVER a filled button (S11-B7). */
button.cta { background: transparent; padding-left: 0; padding-right: 0; cursor: pointer; }

/* The copy button is an ENHANCEMENT over the textarea, never a replacement:
   it ships hidden and inline script reveals it. With script off the reader
   selects and copies the pre-filled textarea, which is what a textarea is
   for. `[hidden]` is spelled out because the flex display above would
   otherwise win over the UA sheet. */
.quiet {
  font-family: var(--measured);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  color: var(--graphite);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule);
  padding: 0.1rem 0;
  cursor: pointer;
}
.quiet:hover { color: var(--rubric-text); border-bottom-color: var(--rubric); }
.compose-actions .quiet[hidden] { display: none; }

/* An anchored group row must not land FLUSH against the top of the viewport.
   Found by following the index's own links and looking, not by a gate: the
   anchors resolve exactly (measured, delta 0 for all seven), and arriving at
   one still reads badly, because the label sits jammed on the top edge with
   no breathing room and nothing above it to say where you are.

   Technically correct and practically annoying is still annoying. One line,
   no script, and it restores exactly the whitespace .section was designed to
   have above it. */
.section[id] { scroll-margin-top: 3rem; }

/* ── the group index (project page) ────────────────────────────── */
/* Cards answer "which repository is this"; an INDEX answers "what is in
   here". At 71 repos the project page needs the second, and the repos
   page keeps the first. So this is a book's index, not a smaller grid of
   cards: a name, a leader rule, a count, in the reading order the host's
   own .docket.json declares.

   Group name is WRITTEN matter and takes the serif; the count is MEASURED
   and takes the mono, right-aligned and tabular so the column of numbers
   lines up. Same serif/mono split as everywhere else, so it needed no new
   decision.

   auto-fill collapses to one column on a phone without a breakpoint of its
   own -- 14rem cannot fit twice in a 390px screen. */

.group-index {
  list-style: none;
  margin: 0.7rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  column-gap: var(--gutter);
}
.group-index li { min-width: 0; }
.group-index a {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  padding: 0.42rem 0;
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
}
.group-index a:hover { border-bottom-color: var(--rubric); }
.gx-name {
  font-family: var(--written);
  font-size: 0.98rem;
  color: var(--ink);
  min-width: 0;
}
.group-index a:hover .gx-name { color: var(--rubric-text); }
.gx-count {
  margin-left: auto;
  font-family: var(--measured);
  font-size: 0.78rem;
  color: var(--graphite);
  font-variant-numeric: lining-nums tabular-nums;
}

/* Deliberately NOT .cta. A CTA is the page asking for an action and is set
   at 1.62rem in the display face; this is a quiet way onward from an index
   the reader has just finished. Same cinnabar baseline, a third the voice. */
.more { margin: 1.2rem 0 0; text-align: right; }
.more a {
  font-family: var(--written);
  font-size: 0.95rem;
  color: var(--rubric-text);
  text-decoration: none;
  padding-bottom: 0.08em;
  border-bottom: 1.5px solid var(--rubric);
  transition: border-bottom-width 90ms linear;
}
.more a:hover { border-bottom-width: 3px; }

/* ── attestation: the one surviving pill (✓ / ✗) ───────────────── */
/* no green anywhere: a pass is ink, a failure is cinnabar.        */

/* The marks are DRAWN, not typed.  U+2717 ✗ is in none of the three
   self-hosted faces and U+2713 ✓ exists only in IBM Plex Mono, where it
   reads as a radical sign.  An inline SVG is deterministic, needs no
   third-party bytes, and lets the stroke match the mono's weight. */

.att {
  font-family: var(--measured);
  font-size: 0.7rem;
  letter-spacing: 0.01em;
}
.att-mark {
  width: 0.78em;
  height: 0.78em;
  display: inline-block;
  vertical-align: -0.02em;
  margin-right: 0.34em;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.1;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.att.pass { color: var(--graphite); }
.att.pass .att-mark { color: var(--ink); stroke-width: 2.3; }
.att.fail { color: var(--rubric-text); }
.att.pending { color: var(--graphite); }
.att-when { display: block; color: var(--graphite); }
.att.pending .att-mark { opacity: 0.5; }

.sr {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* a state word: cinnabar ONLY while something is still alive */
.state { font-family: var(--measured); }
.state.open, .state.confirmed, .state.unresolved { color: var(--rubric-text); }
.state.resolved, .state.closed, .state.complete { color: var(--ink); }
/* Curation status is never rubric: the rubric means unresolved across the whole
   estate, and a finished or archived repo is a badge, not a problem. */
.state.active, .state.stable { color: var(--ink); }
.state.archived, .state.deprecated { color: var(--graphite); }

/* A long README folds after roughly one screen. <details>, so no script: the
   render refuses inline JS, and details is keyboard-operable and announced by
   screen readers without any help from us. */
.unroll { display: block; }

/* The gradient sits OVER the end of the visible text, so the fold reads as
   "there is more" rather than as the text simply stopping. Negative margin
   pulls it up over the preceding block; pointer-events lets clicks through. */
.unroll:not([open])::before {
  content: "";
  display: block;
  height: 5.5rem;
  margin-top: -5.5rem;
  background: linear-gradient(to bottom, transparent, var(--paper) 85%);
  pointer-events: none;
}

.unroll > summary {
  font-family: var(--measured);
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--rubric-text);
  cursor: pointer;
  padding: 0.35rem 0;
  border-bottom: 1px solid var(--rule);
  list-style: none;
  width: 100%;
}
.unroll > summary::-webkit-details-marker { display: none; }
.unroll > summary::after { content: " \2193"; }        /* ↓ */
.unroll[open] > summary::after { content: " \2191"; }  /* ↑ */
.unroll[open] > summary { margin-bottom: 1rem; }
.unroll > summary:hover { color: var(--rubric); }
.unroll > summary:focus-visible {
  outline: 2px solid var(--rubric);
  outline-offset: 2px;
}

/* The visible feed link, in the band beside its section label. */
.feed-link {
  display: block;
  font-family: var(--measured);
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--graphite);
  text-decoration: none;
  margin-top: 0.35rem;
}
.feed-link:hover { color: var(--rubric); }
.feed-link::before { content: "\2933  "; }   /* ⤳ */

.quoted { font-style: normal; }

.atts { display: flex; flex-wrap: wrap; gap: 0.25rem 1.1rem; margin-top: 0.35rem; }

/* ── the section: space separates, rules do not ────────────────── */

.section { margin-top: 3rem; }
.section-tight { margin-top: 2.2rem; }

/* a note about the page itself is still WRITTEN matter — serif, not mono */
.footnote {
  font-family: var(--written);
  font-size: 0.92rem;
  font-style: italic;
  color: var(--graphite);
  text-indent: 0;
  margin: 0;
}

/* ── clone line ────────────────────────────────────────────────── */

.clone {
  font-family: var(--measured);
  font-size: 0.8rem;
  line-height: 1.9;
  color: var(--ink);
  margin: 0;
}
.clone span { color: var(--graphite); user-select: none; }
.clone .alt { color: var(--graphite); }

/* ── the listing: a file at tip ────────────────────────────────── */
/* On this page the BODY is measured matter, so the frame inverts: the
   band narrows to hold line numbers and the measure widens to hold code.
   Line numbers in the margin is what a critical edition does with verse. */

/* Only the MEASURE changes: code wants width, and the band stays exactly
   where it is on every other page so the listing's left edge lines up
   with the masthead's.  Line numbers hang at the band's right edge like
   any other note. */
.leaf--code {
  --measure: 46rem;
}

.filename {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(1.6rem, 3.6vw, 2.1rem);
  line-height: 1.15;
  margin: 0 0 0.7em;
  word-break: break-word;
}
.filename .dir {
  display: block;
  font-family: var(--measured);
  font-size: 0.72rem;
  letter-spacing: 0.02em;
  color: var(--graphite);
  margin-bottom: 0.5em;
  word-break: break-all;
}

/* The tree index.  Same band, same gutter, same grid as .cline, so a
   directory's names sit at exactly the x a file's code does and the two
   pages read as one place.  The KIND of a row ("dir"/"file") is measured
   matter and hangs in the band; the NAME is what you came for and lives
   in the measure. */
/* A README reference the renderer could not resolve keeps its TEXT and loses
   its href.  It must also lose the LOOK of a link: every `a` in this
   stylesheet is underlined and recolours on hover, so an anchor with no href
   was a dead thing wearing a link's clothes -- worse for a reader than the
   404 it replaced, because a 404 at least reports itself. */
a[data-unresolved], a[data-refused-scheme] {
  color: inherit;
  text-decoration: none;
  cursor: default;
}
a[data-unresolved]:hover, a[data-refused-scheme]:hover { color: inherit; text-decoration: none; }

/* ── the diff ──────────────────────────────────────────────────── */
/* SAME GRID AS .cline, deliberately: a +/- marker and a line number are
   measured matter and hang in the apparatus band at the same x as the file
   view's numbers, and the code sits in the measure set exactly as the file
   view sets it.  A reader moving between a file and a diff of that file sees
   one place, not two.

   NO TRAFFIC LIGHTS.  A changed line takes the SUNK ground that
   `.cline:target` already uses for a cited line, and the marker in the band
   carries the direction.  Colour in this design means a LIVING thing and
   there are no greens anywhere; a green add would make "needs attention" read
   as success on the same page. */
.dfile { margin: 0 0 1.4rem; }
.dfile > summary {
  cursor: pointer;
  font-family: var(--measured);
  font-size: 0.78rem;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--rule);
  display: flex;
  justify-content: space-between;
  gap: 1rem;
}
.dfile > summary::-webkit-details-marker { display: none; }
.dpath { word-break: break-all; }
.dfrom { color: var(--graphite); }
.dkind { color: var(--graphite); flex: none; }
.dnote {
  font-family: var(--measured);
  font-size: 0.72rem;
  color: var(--graphite);
  margin: 0.6rem 0 0;
}
.diff {
  font-family: var(--measured);
  font-size: 0.78rem;
  line-height: 1.72;
  overflow-x: auto;
  scrollbar-width: thin;
  tab-size: 2;
  margin-top: 0.5rem;
}
.dline {
  display: grid;
  grid-template-columns: var(--band) minmax(0, 1fr);
  column-gap: var(--gutter);
  min-width: max-content;
}
.dnum {
  text-align: right;
  color: var(--graphite);
  opacity: 0.62;
  font-variant-numeric: lining-nums tabular-nums;
  user-select: none;
  position: sticky;
  left: 0;
  background: var(--paper);
}
.dmark { display: inline-block; width: 1ch; margin-right: 0.4ch; }
.dline code { white-space: pre; }
/* the change itself: a sunk ground, the same one a cited line takes */
.dadd, .ddel { background: var(--sunk); }
.dadd .dnum, .ddel .dnum { background: var(--sunk); opacity: 1; }
.ddel code { text-decoration: line-through; text-decoration-color: var(--graphite); }
.dhunk {
  color: var(--graphite);
  padding: 0.5rem 0 0.1rem;
  border-top: 1px solid var(--rule);
  margin-top: 0.4rem;
  font-size: 0.72rem;
}

.tree { font-variant-numeric: lining-nums tabular-nums; }
/* THE EDGE of a truncated listing.  An alphabetically-cut listing that simply
   stops is indistinguishable from a complete one, so the edge is drawn: a
   rule above it, and the rubric, because an incomplete listing is an
   unresolved thing and the rubric is what this design uses to say so. */
.tree-omitted {
  grid-column: 1 / -1;
  margin: 0.9rem 0 0;
  padding-top: 0.7rem;
  border-top: 1px solid var(--rule);
  font-family: var(--measured);
  font-size: 0.72rem;
  line-height: 1.6;
  color: var(--rubric-text);
  max-width: var(--measure);
}
.tree-row {
  display: grid;
  grid-template-columns: var(--band) minmax(0, 1fr);
  column-gap: var(--gutter);
  padding: 0.2rem 0;
}
.tree-name {
  font-family: var(--measured);
  font-size: 0.82rem;
  line-height: 1.6;
  min-width: 0;
  word-break: break-all;
}
.tree-row--excluded .tree-name { color: var(--graphite); }
.tree-row--excluded .note { color: var(--rubric-text); }
.tree-name a { text-decoration: none; }
.tree-name a:hover {
  text-decoration: underline;
  text-decoration-color: var(--rubric);
}

.listing {
  font-family: var(--measured);
  font-size: 0.78rem;
  line-height: 1.72;
  overflow-x: auto;
  scrollbar-width: thin;
  tab-size: 2;
}
.cline {
  display: grid;
  grid-template-columns: var(--band) minmax(0, 1fr);
  column-gap: var(--gutter);
  min-width: max-content;
  position: relative;
}
.lno {
  text-align: right;
  color: var(--graphite);
  opacity: 0.62;
  text-decoration: none;
  font-variant-numeric: lining-nums tabular-nums;
  user-select: none;
  position: sticky;      /* numbers hold their place when a long line scrolls */
  left: 0;
  background: var(--paper);
}
.lno:hover { opacity: 1; color: var(--rubric-text); }
.cline:target .lno { background: var(--sunk); }
.cline code { white-space: pre; }

/* a cited line: the fragment IS the citation, so it must be visible */
.cline:target { background: var(--sunk); }
.cline:target .lno { opacity: 1; color: var(--rubric-text); }
.cline:target::before {
  content: "";
  position: absolute;
  left: -0.75rem;
  top: 0.22em;
  width: 2px;
  height: 1.2em;
  background: var(--rubric);
}

/* ── the form: fields are ruled lines, not sunken boxes ────────── */
/* A form is where "fewer boxes" is hardest to hold, because an input has
   to look enterable.  A single baseline rule does that: it is the ruled
   line of a paper form, and it earns its ink because it marks where you
   write.  A filled well would be the fifth box on a page that has none. */

.field { margin-bottom: 2.4rem; }
.field label.note { cursor: pointer; }

input[type="text"], input[type="email"], textarea {
  width: 100%;
  display: block;
  font-family: var(--written);
  font-size: 1rem;
  line-height: 1.55;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--graphite);
  border-radius: 0;
  padding: 0.15rem 0 0.45rem;
  margin-bottom: 0.5rem;
  resize: vertical;
}
textarea {
  background: var(--sunk);
  padding: 0.65rem 0.8rem;
  border-radius: 2px 2px 0 0;
}
input::placeholder, textarea::placeholder {
  color: var(--graphite);
  opacity: 0.72;
  font-style: italic;
}
input:focus, textarea:focus {
  outline: 0;
  border-bottom-color: var(--rubric);
  border-bottom-width: 2px;
  padding-bottom: calc(0.45rem - 1px);
}
textarea:focus { padding-bottom: calc(0.65rem - 1px); }
input:focus-visible, textarea:focus-visible { outline: 0; }

.choice { display: block; }
.choice label { display: inline-flex; gap: 0.5rem; align-items: baseline; cursor: pointer; }
.choice input[type="checkbox"] { accent-color: var(--rubric); }

button.cta {
  background: none;
  border: 0;
  border-bottom: 1.5px solid var(--rubric);
  padding: 0 0 0.1em;
  cursor: pointer;
  font-family: var(--display);
}


/* The ingress form's submit button is generated by sigil-web's sg-form, so
   it cannot carry a class of ours. It is still the primary action of an
   issue-first product and must not be a filled grey system button -- that
   was S11-B7, and it is the one element that looks like every other website.
   Same typographic treatment as .cta, matched on the element instead. */
form button[type="submit"] {
  display: inline-block;
  font-family: var(--display);
  font-size: 1.45rem;
  font-weight: 500;
  line-height: 1.2;
  color: var(--rubric);
  background: none;
  border: 0;
  border-bottom: 1.5px solid var(--rubric);
  border-radius: 0;
  padding: 0 0 0.1em;
  margin: 0.6rem 0 0.9rem;
  cursor: pointer;
  transition: border-bottom-width 90ms linear;
}
form button[type="submit"]:hover { border-bottom-width: 4px; }
form button[type="submit"]:focus-visible { border-bottom-color: transparent; }

/* the generated field labels are written matter and take the book face */
form label {
  display: block;
  font-family: var(--written);
  font-size: 0.94rem;
  color: var(--graphite);
  margin-bottom: 0.15rem;
}

/* ── colophon ──────────────────────────────────────────────────── */

.colophon {
  margin-top: 5.5rem;
  font-family: var(--measured);
  font-size: 0.68rem;
  line-height: 1.9;
  color: var(--graphite);
  letter-spacing: 0.02em;
}
.colophon .fleuron { color: var(--estate-rubric); font-size: 1.35rem; line-height: 1; }

/* Two feet, because they are two different objects.
   A RUNNING FOOT appears on every leaf and says where you are and how to
   get back. A COLOPHON is the note at the end of a VOLUME stating how the
   thing was made -- the types, the paper, the printer -- and in bookwork it
   appears once. Scattering the types across arbitrary pages was conflating
   the two, which is why it read as inconsistent rather than as considered. */

.colophon .foot-where { display: block; }
.colophon .foot-links { display: block; margin-top: 0.15rem; }

.colophon--full { margin-top: 6rem; }

/* The colophon is PROSE ABOUT HOW THE THING WAS MADE, so it is written
   matter and takes the serif -- the design's own rule, which I did not
   follow the first time. The running foot stays mono because it is
   navigation, i.e. measured matter. The two feet differ in FACE for the
   same reason they differ in content. */
.colophon--full .colophon-line {
  font-family: var(--written);
  font-size: 0.92rem;
  line-height: 1.5;
  letter-spacing: 0;
  margin: 0 0 0.5em;
  max-width: 32rem;
  text-indent: 0;
}
.colophon--full .colophon-line:last-child { margin-bottom: 0; }
.colophon--full b { color: var(--ink); font-weight: 600; }
/* The RUNNING foot's links are navigation and sit undecorated -- the whole
   line is signposting and reads as such. The COLOPHON's links are inside
   prose sentences and must look like links: the clone link in particular is
   the only thing making "the record is git" a checkable claim rather than an
   assertion, so hiding it would defeat the sentence. */
.colophon a { text-decoration: none; }
.colophon a:hover { text-decoration: underline; }
.colophon--full a {
  text-decoration: underline;
  text-decoration-color: var(--graphite);
  text-decoration-thickness: 0.5px;
  text-underline-offset: 0.19em;
}
.colophon--full a:hover {
  text-decoration-color: var(--rubric);
  text-decoration-thickness: 1px;
}
/* The RUNNING foot's links are navigation and sit undecorated -- the whole
   line is signposting and reads as such. The COLOPHON's links are inside
   prose sentences and must look like links: the clone link in particular is
   the only thing making "the record is git" a checkable claim rather than an
   assertion, so hiding it would defeat the sentence. */
.colophon a { text-decoration: none; }
.colophon a:hover { text-decoration: underline; }
.colophon--full a {
  text-decoration: underline;
  text-decoration-color: var(--graphite);
  text-decoration-thickness: 0.5px;
  text-underline-offset: 0.19em;
}
.colophon--full a:hover {
  text-decoration-color: var(--rubric);
  text-decoration-thickness: 1px;
}

.fleuron { font-family: var(--display); font-style: normal; }

/* ── dark: ink and paper invert, cinnabar holds ────────────────── */

/* Dark mode is handled per THEME above: each theme declares its own dark
   paper, ink and rubric, and derives its own greys.  There is deliberately
   no generic dark block here — it would fight the themes, and a theme that
   cannot own its own dark mode is not a theme. */

/* ── narrow: the band folds above its text ─────────────────────── */
/* px, not rem — rem in a media query resolves against the browser's
   initial 16px, never against the root font-size set above. */

@media (max-width: 680px) {
  html { font-size: 16.5px; }
  .leaf { padding: 2.2rem 1.15rem 4rem; }
  .row, .entry {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 0.2rem;
  }
  /* the repo's NAME comes before its facts on a phone; a label
     ("Readme", "Clone") still belongs above the thing it labels. */
  .masthead { display: flex; flex-direction: column; }
  .masthead .note { order: 2; margin-top: 1.6rem; }
  .masthead .said { order: 1; }
  .note {
    grid-column: 1;
    text-align: left;
    padding-top: 0;
  }
  .said, .row > .spread { grid-column: 1; }
  /* THE FILE VIEW AND THE TREE INDEX KEEP THEIR TWO COLUMNS, but the band
     stops being 8.5rem.
     .cline and .tree-row are deliberately NOT collapsed above: a line number
     beside its line and a kind beside its name are the whole point, and
     stacking them would make a listing unreadable.  But they were also not
     NARROWED, so at 16.5px root a phone spent ~140px of band plus ~29px of
     gutter -- about 43% of a 390px screen -- before the first character of
     code, and `min-width: max-content` then forced a horizontal scroll on top.
     Reported from a phone: "the line numbers are almost in the center".

     docket-render-handoff §1 says --band is CONSTANT on every page type
     including the file view, and this does not break that rule, it keeps its
     intent: the band's own stated purpose here is "narrow, a margin not a
     column", and at 390px 8.5rem is not a margin, it is a column.  A gutter
     holding three or four digits does not need 8.5rem at any width where the
     text has none to spare.

     Breakpoint in PX, never rem -- a rem media query resolves against the
     browser's initial 16px, not the root size set above (handoff §6 trap 2). */
  .cline, .tree-row, .dline {
    grid-template-columns: 2.9rem minmax(0, 1fr);
    column-gap: 0.85rem;
  }
  .prose pre, pre.specimen, .specimen-lang,
  .prose table, table.ledger { margin-left: 0; }
  .prose table, table.ledger { width: 100%; }
  pre[lang]::before { margin-left: 0; }
  .entry { padding: 0.7rem 0; }
  .masthead h1 { font-size: 2.5rem; }
  .facts {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: 1.5rem;
    row-gap: 0.9rem;
  }
}
