/* ============================================================
   AIOM_web.css
   VERSION: 0.6  (the body face becomes Archivo)
   DATE:    2026-08-14

   The web presentation layer. Companion to AIOM_book.css, which remains the
   sole control of the PRINT appearance and is not touched by anything here.

   v0.2 (2026-08-13) is the reader design. What changed from v0.1 and why:

   (a) THE TEXT COLUMN IS NOW DEAD CENTRED AND NOTES FLOAT OUT OF IT. v0.1 made
       the article the measure PLUS a sidenote gutter and centred that, so the
       prose sat left of optical centre and the empty gutter read as a mistake
       wherever a stretch of prose called no note. The reading area is now a
       three-track grid, the article occupies the middle track at exactly the
       measure, and a sidenote floats into the track beside it. With no note the
       page is symmetrical. This also stops a note from landing on the right
       border of a full-measure box such as .dated or .model.
   (b) Slot openings became a real beat rather than a small label.
   (c) The apparatus was tightened: definition, theorem, dated, model.
   (d) Motion was added, and it is applied BY SCRIPT so a reader without
       JavaScript sees everything rather than nothing. See section 16.
   (e) Measure narrowed from 34rem to 32rem. The header claimed 66 characters at
       this size until v0.4 measured it in a browser against this chapter's own
       prose in its own face and found 71. The claim was arithmetic from a rule
       of thumb rather than a measurement, which is the failure this repository
       keeps finding in its own checks.

   TOKENS ARE INHERITED, NOT CHOSEN, with one measured accessibility correction
   and a designed dark palette. See section 2, which carries the numbers.

   Two rules carried over from the print stylesheet's header, and they hold here
   for the same reason:
     - This file is the sole control of web appearance. Chapter HTML carries
       content only, and no chapter ever gains a scoped <style> block.
     - A Unicode hex escape in a content: string consumes the following space as
       an escape terminator. Use literal UTF-8 characters.

   v0.3 (2026-08-13) adds dark mode and the figure token pass. The header
   previously said dark mode was deliberately absent; that is no longer true and
   the sentence is removed rather than left to mislead. Chapter figures are
   retokenized on the way to the web by web_build.tokenize_svg, so they follow
   the theme without the locked chapter being edited. Gate W12 checks that every
   SVG colour on every page is a token; gate W13 checks contrast in both themes
   and that the two dark blocks agree.

   v0.4 (2026-08-13) is the reading scale. THE COLUMN WAS NEVER TOO NARROW. It
   measures 71 characters, near the top of the 45 to 75 band, and it was reported
   as thin because at 1920px it occupied 28 per cent of the window with 556px of
   air on each side. Three things can move that column: the measure, the type
   size, and the alignment rule. Capping the reading area cannot, because a
   centred child of a centred container lands in the same place at every cap,
   and a variant that capped it rendered pixel-identical to the build it was
   meant to improve.

   What changed:

   (f) THE ROOT SIZE IS FLUID FROM 1440px UP, 17px to 20px. The column grows to
       640px at 1920px while staying 71 characters, so presence is bought with
       type size rather than with measure, and no readability is spent. Below
       1440px nothing moves at all. See section 3.
   (g) --note narrows from 15.5rem to 14rem, and --rail does NOT. This is not
       taste. Fluid type scales the sidenote along with the column, which pushes
       the width at which a margin note fits; leaving both at 15.5rem moved the
       breakpoint to about 1565px and a 1512px laptop would have lost its margin
       notes. The rail was narrowed too in the first attempt and the contents
       wrapped: "Ch. 3 A Science and Its Discipline" broke across two lines and
       so did the word count. The rail is content and the note track is
       clearance, so the clearance is what gives way. Section 17 now solves to
       1411px, and the query sits at 1420px rather than the 1440px it was, so a
       1440px window GAINS margin notes it did not have.

   v0.5 (2026-08-13) makes the body roman a true Regular 400. Dan read the page
   at 1920 in Chrome and said the type felt heavy, and that the weight seemed to
   change with the window. THE WEIGHT NEVER CHANGED: computed font-weight is 400
   at every width and nothing here varies it. What changed was the v0.4 size,
   and the same face set larger reads heavier. Chasing it found a defect older
   than v0.4, described at the @font-face in section 1: the roman was Plex Sans
   Text at usWeightClass 450 while its italic was a true 400, so the two had
   never matched. Print keeps Text and only the web moves.

   v0.6 (2026-08-14) MAKES THE WEB BODY FACE ARCHIVO. Ruled by Dan. v0.5 fixed
   the weight and left the shape, and the shape was the remaining objection: Plex
   is the face of a technology company's documentation and reads as the default
   choice rather than a chosen one. Archivo is a grotesque cut by Omnibus-Type
   for text and headline at once, and it does three things here. It has a shape
   without being mannered. Its x-height is 0.526 em against Plex Regular's 0.516
   and its x-to-cap ratio is the highest of the seven faces compared, so it holds
   presence at 17px without the extra weight v0.4 to v0.5 was spending to get
   there. And it sets a grotesque under a geometric display, which is a contrast
   with Jost rather than an echo of it.

   THE MEASURE IS 73 CHARACTERS AT v0.6, MEASURED IN A BROWSER: 72.7, from the
   average glyph advance of this chapter's own prose in this face at this size,
   the same method v0.4 used to find 71. Archivo sets 2.4 per cent narrower than
   Plex Regular, so the same 32rem column holds more of them, and it reads the
   same at 1440 and at 1920 because both terms scale together. The column itself
   did not move: --measure is unchanged, and so is every
   other term of the section 17 sum, which is why the 1420px breakpoint stands.
   Do not restate this number from memory; it is a property of this face at this
   measure and it moves whenever either does.

   PRINT IS UNCHANGED AND STAYS ON PLEX SANS TEXT. This is now the third division
   between the two stylesheets, after colour and after the v0.5 roman, and it is
   the same reasoning each time: the print system is locked at v7.1 and a change
   there re-runs Stage 5 and G2 on every chapter. The print build was re-run for
   this change so that gate 5 could report that no Archivo face is embedded
   anywhere in the book, because "print is unaffected" is a claim until a gate
   has said so.

   THE FAMILY IS NAMED ONCE, IN --body-face. Three places consume it: this file
   twice, and web_build.tokenize_svg, which remaps the chapter figures'
   font-family on the way to the web the same way it remaps their colours. A
   policy repeated in three places is a policy that is wrong in two of them, so
   the three read one token rather than three copies of a name.
   ============================================================ */

/* ---------- 1. FONTS ---------- */
/* Self-hosted from fonts/use/, copied into assets/fonts/ by web_build.py.
   No CDN, no network at render time, same six faces the print book embeds. */
@font-face { font-family: "Jost"; src: url("fonts/Jost-Medium.ttf");   font-weight: 500; font-display: swap; }
@font-face { font-family: "Jost"; src: url("fonts/Jost-SemiBold.ttf"); font-weight: 600; font-display: swap; }
/* THE BODY FACE IS ARCHIVO ON THE WEB AND IBM PLEX SANS TEXT IN PRINT, AND THAT
   DIVERGENCE IS DELIBERATE. Ruled by Dan 2026-08-14, superseding the v0.5 swap
   to Plex Regular, which fixed the weight and left the shape. All four faces are
   Archivo 2.001, one release, which is the same standard v0.5 applied to Plex:
   mixing releases of a family is how a roman and its own italic stop matching.

   THE WEIGHT LADDER IS INTACT AND THAT IS WHY THIS FACE AND NOT ANOTHER. The
   design needs a true Regular 400, a drawn italic at that same 400, a 500 and a
   600. Two of the seven faces compared carried no 600 and one had no static
   italic at all, which rules them out on structure rather than on taste.

   Print keeps Plex Sans Text. Its physics are different, ink on paper gains no
   weight the way a backlit screen does, the print design system is locked at
   v7.1, and a change there re-runs Stage 5 and G2 on every chapter. This is the
   same division already in force for colour: five foreground tokens are darkened
   here for WCAG while AIOM_book.css keeps the print values of record.

   THE PLEX FACES ARE STILL DECLARED BELOW AND ARE NO LONGER USED BY THIS FILE.
   They are kept because fonts/use/ is shared with print, which loads them, and
   because a declared face is fetched only when something asks for it, so a dead
   @font-face costs a reader nothing. Delete these four lines the moment print
   and web stop sharing a directory, and not before. */
@font-face { font-family: "Archivo"; src: url("fonts/Archivo-Regular.ttf");  font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Archivo"; src: url("fonts/Archivo-Italic.ttf");   font-weight: 400; font-style: italic; font-display: swap; }
@font-face { font-family: "Archivo"; src: url("fonts/Archivo-Medium.ttf");   font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: "Archivo"; src: url("fonts/Archivo-SemiBold.ttf"); font-weight: 600; font-style: normal; font-display: swap; }
@font-face { font-family: "Plex"; src: url("fonts/IBMPlexSans-Regular.ttf");  font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Plex"; src: url("fonts/IBMPlexSans-Italic.ttf");   font-weight: 400; font-style: italic; font-display: swap; }
@font-face { font-family: "Plex"; src: url("fonts/IBMPlexSans-Medium.ttf");   font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: "Plex"; src: url("fonts/IBMPlexSans-SemiBold.ttf"); font-weight: 600; font-style: normal; font-display: swap; }

/* ---------- 2. DESIGN TOKENS ---------- */
/* TOKENS ARE INHERITED FROM AIOM_book.css, WITH ONE DOCUMENTED CORRECTION.
   Five of the print palette's foreground colours fail WCAG AA for normal text
   against the paper and its tints, measured rather than guessed:

     amber      #B4551F  worst 3.69 : 1   ->  #9E4B1B  4.52
     amber-fig  #C0521A  worst 3.52      ->  #A44616  4.53
     teal       #0E7A72  worst 3.88      ->  #0D6F68  4.50
     folio      #9B8F7C  worst 2.38      ->  #696154  4.57
     axis       #6E6353  worst 4.40      ->  #6C6151  4.53

   Print has no WCAG floor and different physics, so THE PRINT VALUES ABOVE
   REMAIN THE VALUES OF RECORD and AIOM_book.css is untouched. These are web text
   derivatives, darkened by the minimum needed and no more: four of the five move
   by 2 to 15 percent and are imperceptible side by side. Only --folio moves
   visibly, and it moves toward legibility. Gate W13 enforces the floor in both
   themes, so this cannot silently regress.

   DARK MODE IS DESIGNED, NOT INVERTED. The warm paper has no correct automatic
   inverse. The ground becomes a deep navy black derived from the book's own
   navy, which keeps the two-colour identity: this is the same book, at night.
   Every dark value was checked against every dark surface before being written.

   THE DARK BLOCK APPEARS TWICE, once for the system preference and once for the
   explicit toggle, and gate W13 fails the build if the two ever disagree. CSS
   has no way to declare it once. */
:root {
  --paper:     #F4ECDD;
  --navy:      #16314F;
  --amber:     #9E4B1B;   /* print #B4551F */
  --amber-fig: #A44616;   /* print #C0521A */
  --teal:      #0D6F68;   /* print #0E7A72 */
  --ink:       #2B2620;
  --folio:     #696154;   /* print #9B8F7C */
  --axis:      #6C6151;   /* print #6E6353 */
  --tint-def:  #EDE3D0;
  --tint-thm:  #F7EDE2;
  --tint-fig:  #E7DECB;
  --hairline:  #DCCFB4;
  --kt-head:   #DCCFB4;
  /* The inverted band has its own tokens because in dark mode it cannot simply
     be "navy ground, paper text": that would render as a glaring light block on
     a dark page. It is a surface that is always a step away from the ground. */
  --invert-bg:    #16314F;
  --invert-fg:    #F4ECDD;
  --invert-muted: #E7DECB;
  /* The accent ON the inverted band is not --amber. In the light theme --amber
     is #9E4B1B, and dark amber on a navy ground measures 2.19:1, which gate W13
     caught the moment the gate itself was fixed. The band is dark in BOTH
     themes, so its accent is the light amber in both. */
  --invert-accent: #E08A55;
  --shadow:    rgba(43, 38, 32, 0.10);
  /* Paper tooth. Not a colour, so W13's hex regex cannot see it and cannot
     police the two dark blocks agreeing on it: keep them in step by hand. */
  --grain:     0.13;

  --measure:   32rem;    /* the text column, 73 characters, measured not assumed */

  /* THE BODY FACE IS NAMED HERE AND NOWHERE ELSE IN THIS FILE. The rules that
     set running text read this token, and web_build.tokenize_svg substitutes it
     into the chapter figures' font-family so a figure label cannot end up in a
     different face from the prose beside it. Changing the face is this one line
     plus its @font-face block in section 1. */
  --body-face: "Archivo", system-ui, sans-serif;
  --note:      14rem;    /* the sidenote */
  --note-gap:  2.25rem;  /* text column to sidenote */
  --rail:      15.5rem;  /* the contents rail */
  --bar:       3.25rem;  /* sticky topbar height, for scroll-padding */
  --step:      1.55rem;  /* vertical rhythm unit */
  --beat:      calc(var(--step) * 2.6);  /* space above a slot opening */
}

/* DARK, BLOCK 1 OF 2: the system preference, unless the reader has chosen light. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper:     #0F1D2B;
    --navy:      #F2F7FB;
    --amber:     #E08A55;
    --amber-fig: #E08A55;
    --teal:      #57BDB1;
    --ink:       #E3E9EF;
    --folio:     #93A7B8;
    --axis:      #B3C4D2;
    --tint-def:  #16283A;
    --tint-thm:  #1A2E42;
    --tint-fig:  #1E3348;
    --hairline:  #2C4459;
    --kt-head:   #2C4459;
    --invert-bg:    #21374C;
    --invert-fg:    #E3E9EF;
    --invert-muted: #A9BCCC;
    --invert-accent: #E08A55;
    --shadow:    rgba(0, 0, 0, 0.35);
    /* Lower on a dark ground: identical noise reads as banding rather than
       as tooth once the surface it sits on is dark. */
    --grain:     0.08;
  }
}

/* DARK, BLOCK 2 OF 2: the explicit toggle. Identical to block 1 by rule. */
:root[data-theme="dark"] {
    --paper:     #0F1D2B;
    --navy:      #F2F7FB;
    --amber:     #E08A55;
    --amber-fig: #E08A55;
    --teal:      #57BDB1;
    --ink:       #E3E9EF;
    --folio:     #93A7B8;
    --axis:      #B3C4D2;
    --tint-def:  #16283A;
    --tint-thm:  #1A2E42;
    --tint-fig:  #1E3348;
    --hairline:  #2C4459;
    --kt-head:   #2C4459;
    --invert-bg:    #21374C;
    --invert-fg:    #E3E9EF;
    --invert-muted: #A9BCCC;
    --invert-accent: #E08A55;
    --shadow:    rgba(0, 0, 0, 0.35);
    --grain:     0.08;
}

/* ---------- 3. RESET AND PAGE ---------- */
*, *::before, *::after { box-sizing: border-box; }

/* THE ROOT SIZE IS THE READING SCALE, AND EVERY LENGTH IN THIS FILE IS IN rem,
   so this one declaration sets the size of the whole page. It is fluid from
   1440px up and flat below, which is the v0.4 change.

   THE STOPS ARE ARITHMETIC. 8px + 0.625vw passes through 17px at exactly 1440px
   and 20px at exactly 1920px, so the clamp floor takes over below 1440 and the
   ceiling above 1920, and neither bound is a place where the size jumps. A
   1512px laptop lands at 17.45px. Recompute both stops if either bound moves.

   The measure stays 32rem throughout, so the column grows from 544px to 640px
   while holding 71 characters. Growing a column by growing its type costs no
   readability; growing it by widening the measure does.

   The unit is px rather than rem, which is the v0.1 choice kept deliberately.
   Browser zoom and text-size-adjust both still work. A reader's default font
   SIZE setting is ignored, and making it fluid does not change that either way:
   it would be a separate ruling, and it would make the section 17 sum depend on
   a value this file cannot see. */
html {
  font-size: clamp(17px, 8px + 0.625vw, 20px);
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--bar) + 1.5rem);
  -webkit-text-size-adjust: 100%;
}

/* THE PAPER COLOUR MOVES TO html AND THE GRAIN SITS BETWEEN html AND body.
   A fixed overlay painted ON TOP of the page would put noise over every line of
   type; at this opacity that is nearly invisible, but "nearly" is not a standard
   worth adopting for a book. Painting it behind the content instead means the
   tooth belongs to the ground, and a tinted panel covers it, which is right:
   a panel is a different stock laid on the paper. */
html { background: var(--paper); }

body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: var(--grain);
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='120'%20height='120'%3E%3Cfilter%20id='g'%3E%3CfeTurbulence%20type='fractalNoise'%20baseFrequency='0.9'%20numOctaves='4'%20stitchTiles='stitch'/%3E%3CfeColorMatrix%20type='saturate'%20values='0'/%3E%3C/filter%3E%3Crect%20width='120'%20height='120'%20filter='url%28%23g%29'/%3E%3C/svg%3E");
  background-size: 120px 120px;
}

body {
  margin: 0;
  background: transparent;
  color: var(--ink);
  font-family: var(--body-face);
  font-weight: 400;
  line-height: 1.62;
  text-rendering: optimizeLegibility;
  font-kerning: normal;
}

a { color: var(--navy); text-decoration-color: var(--hairline); text-underline-offset: 0.18em; }
a:hover { text-decoration-color: var(--amber); }

:focus-visible { outline: 2px solid var(--amber); outline-offset: 3px; }

/* ---------- 4. CHROME ---------- */
.progress { position: fixed; inset: 0 0 auto 0; height: 2px; z-index: 40; }
.progress i {
  display: block; height: 100%; background: var(--amber);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 0.08s linear;
}

.topbar {
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  height: var(--bar); padding: 0 1.5rem;
  /* Opaque, not translucent. At 88 percent with an 8px blur the body text read
     straight through the bar on a raster check, which is the kind of defect
     that survives every mechanical gate and dies only to looking at the page. */
  background: var(--paper);
  border-bottom: 1px solid var(--hairline);
}
.brand {
  font-family: "Jost", sans-serif; font-weight: 600;
  font-size: 0.8rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--navy); text-decoration: none;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.topbar-here {
  font-size: 0.78rem; color: var(--folio);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  flex: 1; text-align: right;
}
.rail-toggle {
  font-family: "Jost", sans-serif; font-weight: 500; font-size: 0.76rem;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--navy); background: none;
  border: 1px solid var(--hairline); border-radius: 2px;
  padding: 0.32rem 0.7rem; cursor: pointer;
}
.rail-toggle:hover { border-color: var(--amber); color: var(--amber); }

.preview-flag {
  margin: 0; padding: 0.55rem 1.5rem;
  background: var(--amber); color: var(--paper);
  font-family: "Jost", sans-serif; font-weight: 500; font-size: 0.8rem;
  letter-spacing: 0.04em;
}

.foot {
  border-top: 1px solid var(--hairline);
  margin-top: calc(var(--step) * 4);
  padding: 2rem 1.5rem 5rem;
  color: var(--folio); font-size: 0.8rem;
}
.foot-inner { max-width: var(--measure); margin-inline: auto; }
.foot p { margin: 0 0 0.4rem; }
.keyhint kbd {
  font-family: "Jost", sans-serif; font-size: 0.72rem; font-weight: 500;
  border: 1px solid var(--hairline); border-radius: 2px;
  padding: 0.05rem 0.3rem; margin: 0 0.1rem; color: var(--axis);
}

/* ---------- 5. LAYOUT ---------- */
.layout { display: grid; grid-template-columns: var(--rail) minmax(0, 1fr); }

/* Three tracks. The article sits in the middle at exactly the measure, so it is
   optically centred in the reading area. The right track is where a sidenote
   goes, and it is empty when no note is called, which is the correct result
   rather than a hole. */
.reading {
  display: grid;
  grid-template-columns:
    minmax(0, 1fr) minmax(0, var(--measure)) minmax(0, 1fr);
  padding: calc(var(--step) * 2) 1.5rem 0;
}
#chapter-text { grid-column: 2; min-width: 0; }

/* ---------- 6. THE RAIL ---------- */
.rail {
  position: sticky; top: var(--bar);
  max-height: calc(100vh - var(--bar));
  overflow-y: auto; overscroll-behavior: contain;
  padding: calc(var(--step) * 2) 1.1rem 3rem 1.5rem;
  font-size: 0.8rem; line-height: 1.45;
}
.rail-head {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.7rem;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--amber); margin: 0 0 0.15rem;
}
.rail-title {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 1rem;
  line-height: 1.2; color: var(--navy); margin: 0 0 0.7rem;
}
.rail-meta {
  margin: 0 0 1.2rem; padding-bottom: 1rem;
  border-bottom: 1px solid var(--hairline);
  color: var(--folio); font-size: 0.73rem; line-height: 1.5;
}
.rail ol { list-style: none; margin: 0; padding: 0; }
.rail-slots > li { margin-bottom: 0.5rem; }
.rail a {
  display: block; padding: 0.16rem 0 0.16rem 0.75rem;
  border-left: 2px solid var(--hairline);
  color: var(--axis); text-decoration: none;
  transition: color 0.18s, border-color 0.18s;
}
.rail-slots > li > a {
  font-family: "Jost", sans-serif; font-weight: 500;
  letter-spacing: 0.01em; color: var(--navy);
}
.rail a:hover { color: var(--amber); }
.rail a.here { color: var(--amber); border-left-color: var(--amber); }
.rail-sections { margin: 0.25rem 0 0.7rem 0.75rem; }
.rail-sections a { font-size: 0.76rem; padding-left: 0.7rem; }
.rail-num { color: var(--folio); font-variant-numeric: tabular-nums; }
.rail a.here .rail-num { color: var(--amber); }

/* ---------- 7. CHAPTER OPENING ---------- */
.part-label {
  font-family: "Jost", sans-serif; font-weight: 500; font-size: 0.76rem;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--amber); margin: 0 0 0.7rem;
}
.chapter-title {
  font-family: "Jost", sans-serif; font-weight: 600;
  font-size: clamp(2.3rem, 6vw, 3.4rem); line-height: 1.05;
  letter-spacing: -0.02em; color: var(--navy);
  margin: 0 0 var(--beat);
  padding-bottom: var(--step);
  border-bottom: 2px solid var(--navy);
  text-wrap: balance;
}

/* A slot opening is a beat in the chapter, not a caption. The six-slot skeleton
   is the book's structural signature and the web can show it plainly, which the
   PDF cannot without spending a page on it. */
.slot-label {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.72rem;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--amber);
  margin: var(--beat) 0 0.9rem;
  display: flex; align-items: center; gap: 0.9rem;
}
.slot-label::after {
  content: ""; flex: 1; height: 1px; background: var(--hairline);
}
.case-title {
  font-family: "Jost", sans-serif; font-weight: 600;
  font-size: 1.75rem; line-height: 1.15; color: var(--navy);
  margin: 0 0 0.5rem; text-wrap: balance;
}
.provenance {
  font-family: "Jost", sans-serif; font-weight: 500; font-size: 0.78rem;
  line-height: 1.45; color: var(--axis);
  margin: 0 0 var(--step);
  padding-left: 0.85rem; border-left: 2px solid var(--amber);
}

h3.section {
  font-family: "Jost", sans-serif; font-weight: 600;
  font-size: 1.32rem; line-height: 1.22; color: var(--navy);
  margin: calc(var(--step) * 2.1) 0 0.7rem;
  display: flex; gap: 0.8rem; align-items: baseline;
  text-wrap: balance; scroll-margin-top: calc(var(--bar) + 1.5rem);
}
h3.section .num {
  color: var(--amber); font-variant-numeric: tabular-nums; flex: none;
}

.tail-head, .keyterms-head {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.72rem;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--amber);
  margin: var(--beat) 0 0.9rem;
  display: flex; align-items: center; gap: 0.9rem;
}
.tail-head::after, .keyterms-head::after {
  content: ""; flex: 1; height: 1px; background: var(--hairline);
}
.summary-sec, .keyterms, .problems-sec { scroll-margin-top: calc(var(--bar) + 1.5rem); }
p.slot-label { scroll-margin-top: calc(var(--bar) + 1.5rem); }

/* ---------- 8. BODY PROSE ---------- */
#chapter-text p { margin: 0 0 var(--step); }
#chapter-text b { font-weight: 600; color: var(--navy); }

/* A bolded key term links to the definition that owns it. The anchor is added
   by web_build.link_terms(), never in the chapter, which carries no links.

   THE TERM MUST NOT READ AS A LINK UNTIL THE READER LOOKS FOR ONE. Bold marks
   a term at first use, and it already carries meaning in the prose; painting it
   amber like an ordinary link would put a second signal on the same word and
   turn a page of definitions into a page of link decoration, which is close to
   what standing rule 5 forbids. The resting state is therefore identical to
   unlinked bold, and the affordance is a hairline that only fills in on hover.
   The underline is set in the accent so the hover state names the apparatus it
   leads to, matching the amber rule on the callout itself. */
a.termlink {
  color: inherit; text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color 0.18s ease-out;
}
a.termlink:hover, a.termlink:focus-visible { border-bottom-color: var(--amber); }
a.termlink:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }

/* The landing spot. Same device the sidenote, the glossary row and the sources
   entry already use, so arriving at a definition feels like arriving anywhere
   else in the book rather than like a new mechanism. */
.definition:target, .kt:target { background: var(--tint-thm); }
/* .nb switches hyphenation off for a proper noun (Decision 58). The web is not
   justified so it does not hyphenate, and the class is inert here. It is styled
   to nothing deliberately: removing it from the chapter HTML would break print. */
.nb { }

/* ---------- 9. SIDENOTES ---------- */
/* The note floats out of the text column into the track beside it. Float rather
   than absolute positioning, because float with clear:right cannot overlap a
   preceding note and absolute positioning can. */
.fnref { text-decoration: none; }
.fnref sup {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.64em;
  color: var(--amber); padding-left: 0.1em;
}
.fnref:hover sup, .fnref.lit sup { color: var(--navy); }

.note {
  display: block; float: right; clear: right;
  width: var(--note);
  margin-right: calc((var(--note) + var(--note-gap)) * -1);
  margin-bottom: 1rem;
  font-size: 0.75rem; line-height: 1.5; color: var(--axis);
  border-top: 1px solid var(--hairline); padding-top: 0.5rem;
  transition: background-color 0.4s;
}
.note .note-n {
  font-family: "Jost", sans-serif; font-weight: 600;
  color: var(--amber); text-decoration: none; padding-right: 0.15em;
}
.note i { font-style: italic; }
.note.lit, .note:target { background: var(--tint-thm); }

/* ---------- 10. APPARATUS ---------- */
.definition {
  background: var(--tint-def);
  border-left: 3px solid var(--amber);
  padding: 1rem 1.2rem;
  margin: 0 0 var(--step);
}
.definition .lab, .theorem .lab, .model .mlab, .dated .date {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.66rem;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--amber);
  margin: 0 0 0.5rem;
}
.definition .term {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 1.08rem;
  color: var(--navy); margin: 0 0 0.35rem;
}
.definition p:last-child { margin-bottom: 0; }
.definition p { font-size: 0.95rem; }

.theorem {
  background: var(--tint-thm);
  border: 1px solid var(--hairline); border-left: 3px solid var(--navy);
  padding: 1.15rem 1.35rem;
  margin: var(--step) 0;
}
.theorem .lab { color: var(--navy); }
.theorem .stmt {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 1.08rem;
  line-height: 1.28; color: var(--navy); margin: 0 0 0.8rem;
  padding-bottom: 0.7rem; border-bottom: 1px solid var(--hairline);
}
.theorem .cond { margin: 0 0 0.6rem; }
.theorem .conseq { margin: 0.2rem 0 0; }
.theorem ol.ante { list-style: none; margin: 0 0 0.5rem; padding: 0; }
.theorem ol.ante li {
  display: flex; gap: 0.65rem; margin-bottom: 0.35rem; padding-left: 0.9rem;
}
.theorem .mk {
  color: var(--amber); flex: none; font-variant-numeric: tabular-nums;
  min-width: 1.6rem;
}
.theorem p, .theorem li { font-size: 0.95rem; }

.dated {
  border: 1px solid var(--hairline);
  padding: 1rem 1.2rem; margin: var(--step) 0;
}
.dated p:last-child { margin-bottom: 0; }

.model {
  background: var(--tint-fig);
  padding: 1.1rem 1.3rem; margin: var(--step) 0;
}
.model p:last-child { margin-bottom: 0; }
.model .mlab:not(:first-child) {
  margin-top: 1.2rem; padding-top: 0.9rem; border-top: 1px solid var(--hairline);
}

.diagnostic {
  margin: 0 0 0.45rem !important;
  padding-left: 1.1rem;
  border-left: 2px solid var(--teal);
  color: var(--navy);
}

/* ---------- 11. FIGURES ---------- */
#chapter-text figure { margin: calc(var(--step) * 1.7) 0; }
#chapter-text figure svg { width: 100%; height: auto; display: block; }
figcaption {
  font-size: 0.78rem; line-height: 1.5; color: var(--axis);
  margin-top: 0.7rem; padding-top: 0.55rem;
  border-top: 1px solid var(--hairline);
}
.fignum {
  font-family: "Jost", sans-serif; font-weight: 600;
  color: var(--amber-fig); padding-right: 0.4em;
}

/* ---------- 12. KEY TERMS ---------- */
.kt-list {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px; background: var(--hairline);
  border: 1px solid var(--hairline);
}
.kt { background: var(--paper); padding: 0 1rem 0.9rem; display: flex; flex-direction: column; }
.kt-h {
  background: var(--kt-head); margin: 0 -1rem 0.7rem; padding: 0.4rem 1rem;
}
.kt-t {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.92rem;
  color: var(--navy);
}
.kt p { margin: 0 !important; font-size: 0.87rem; line-height: 1.5; }

/* ---------- 13. QUESTIONS AND PROBLEMS ---------- */
.dq { display: grid; grid-template-columns: 2rem 1fr; gap: 0.7rem; margin-bottom: 1.1rem; }
.dq-n {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 1.1rem;
  color: var(--amber); font-variant-numeric: tabular-nums; line-height: 1.5;
}
.dq-b p { margin: 0 !important; }

.problem {
  border-top: 1px solid var(--hairline);
  padding-top: 1.2rem; margin-top: calc(var(--step) * 1.4);
}
.plab {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.68rem;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--amber);
  margin: 0 0 0.35rem !important;
}
.ptitle {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 1.15rem;
  color: var(--navy); margin: 0 0 0.7rem !important;
}
.pnote { font-size: 0.85rem; color: var(--axis); }

/* The table scrolls inside its own box rather than widening the page. Below
   about 390px four columns cannot fit, and without this the whole document
   scrolled sideways, which breaks every other block on the phone instead of
   just the table. The wrapper is added by web_build.wrap_tables. */
.table-scroll { overflow-x: auto; margin: var(--step) 0; }
table.inv {
  width: 100%; min-width: 26rem;
  border-collapse: collapse; font-size: 0.78rem;
}
table.inv th, table.inv td {
  border: 1px solid var(--hairline); padding: 0.5rem 0.6rem;
  text-align: left; vertical-align: top;
}
table.inv th {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.7rem;
  letter-spacing: 0.06em; text-transform: uppercase;
  background: var(--kt-head); color: var(--navy);
}
table.inv td.blank { background: var(--tint-fig); min-width: 6rem; }

.summary { border-left: 3px solid var(--teal); padding-left: 1.2rem; }
.summary p:last-child { margin-bottom: 0; }

/* ---------- 14. THE RAIL, WHOLE BOOK ---------- */
/* Adopted from the inspiration site: the rail carries the WHOLE book, not the
   current chapter, so a reader always sees the shape of the thing they are in.
   Fifteen chapters in four parts is a selling point and the previous rail hid it. */
.rail-back {
  display: block; padding: 0 0 0.9rem; margin-bottom: 0.9rem;
  border-bottom: 1px solid var(--hairline); border-left: 0;
  font-family: "Jost", sans-serif; font-weight: 500; font-size: 0.74rem;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--folio);
  text-decoration: none;
}
.rail-back::before { content: "\2190"; padding-right: 0.45em; }
.rail-back:hover { color: var(--amber); }

.rail-part {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.66rem;
  letter-spacing: 0.15em; text-transform: uppercase; color: var(--amber);
  margin: 1.3rem 0 0.5rem;
}
.rail-part span { color: var(--folio); }
.rail-chapters { list-style: none; margin: 0; padding: 0; }
.rail-ch {
  display: block; padding: 0.22rem 0 0.22rem 0.75rem;
  border-left: 2px solid var(--hairline);
  color: var(--navy); text-decoration: none; font-size: 0.79rem;
  transition: color 0.18s, border-color 0.18s;
}
a.rail-ch:hover { color: var(--amber); border-left-color: var(--amber); }
.rail-ch.soon { color: var(--folio); border-left-color: transparent; }
.rail-ch.here {
  color: var(--amber); border-left-color: var(--amber);
  font-family: "Jost", sans-serif; font-weight: 600;
}
.rail-current { background: var(--tint-thm); padding: 0.3rem 0.6rem 0.5rem; margin: 0.2rem 0; }
.rail-current .rail-ch.here { padding-left: 0.55rem; }

/* ---------- 15. THE FRONT DOOR ---------- */
/* Rebuilt after the editorial review. The old page was four hairline grids in
   one value: squint at it and you saw four grey rectangles. Three things fix
   that, and they are structural rather than decorative. The hero is asymmetric
   and carries a live figure. One band is INVERTED, navy ground, which is the
   only strong value change on the page and the reason it now has a middle. And
   the argument, the proof and the author all come before the table of contents,
   because a contents list is inventory and inventory does not persuade. */
.home main { padding: 0 1.5rem; }
.topnav { display: flex; gap: 1.6rem; margin-left: auto; }
.topnav a {
  font-family: "Jost", sans-serif; font-weight: 500; font-size: 0.76rem;
  letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--navy); text-decoration: none;
}
.topnav a:hover { color: var(--amber); }
.cta {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.74rem;
  letter-spacing: 0.08em; text-transform: uppercase;
  background: var(--navy); color: var(--paper); text-decoration: none;
  padding: 0.45rem 0.9rem; border-radius: 2px; white-space: nowrap;
}
.cta:hover { background: var(--amber); }

/* THE DEPARTMENT LINE. A magazine rubric: letterspaced small caps with a short
   rule running into it. The rule is currentColor, so it follows the eyebrow
   wherever the eyebrow goes, including onto the inverted band where the text is
   --invert-muted rather than --amber. inline-block rather than flex on purpose:
   flex would change the layout model of every <p class="eyebrow"> on the site. */
.eyebrow {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.7rem;
  letter-spacing: 0.2em; text-transform: uppercase; color: var(--amber);
  margin: 0 0 0.85rem;
}
.eyebrow::before {
  content: "";
  display: inline-block;
  width: 1.5rem; height: 1px;
  background: currentColor;
  opacity: 0.5;
  vertical-align: 0.3em;
  margin-right: 0.6rem;
}
/* The part card already carries a large numeral directly above this line, so a
   rule as well is one mark too many in a space that is already spoken for. */
.part-card .eyebrow::before { content: none; }

/* THE SPOT MARK. Sits above the department line, small and quiet, and always
   MEANS something: each one is drawn from the section it heads. See
   web_templates/_marks.html.j2 for why they are instruments rather than jokes.

   COLOUR COMES THROUGH TWO SCOPED PROPERTIES, never literally. On the inverted
   band --navy is a dark blue in the light theme and the band is navy, so a
   hardcoded mark would paint dark on dark: the same defect gate W13 found in
   the theorem panel's roman numerals. Redirecting the two properties on .invert
   is the whole fix, and it costs one rule. */
.mark {
  --mark-ink:    var(--navy);
  --mark-accent: var(--amber);
  display: block;
  width: 2.35rem; height: 2.35rem;
  margin: 0 0 0.6rem;
}
.invert .mark {
  --mark-ink:    var(--invert-fg);
  --mark-accent: var(--invert-accent);
}
/* The hero and the author band are deliberately unmarked. Each already carries
   its own object, the live model figure and the monogram, and a second mark
   would be competing for the same eye rather than adding to it. */


/* Hero: text left, live model right, and it uses the whole measure. */
.hero {
  max-width: 76rem; margin: 0 auto;
  padding: calc(var(--step) * 3.4) 0 calc(var(--step) * 3);
  display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: 3.5rem; align-items: center;
}
.hero h1 {
  font-family: "Jost", sans-serif; font-weight: 600;
  font-size: clamp(2.1rem, 3.5vw, 3.15rem); line-height: 1.05;
  letter-spacing: -0.022em; color: var(--navy);
  margin: 0 0 1.3rem; text-wrap: balance;
}
.lede { font-size: 1.08rem; line-height: 1.55; margin: 0 0 1.7rem; color: var(--ink); }
.hero-actions { display: flex; flex-wrap: wrap; gap: 0.7rem; margin: 0 0 1rem; }
.hero-meta { margin: 0; font-size: 0.8rem; color: var(--folio); }
.btn {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.82rem;
  letter-spacing: 0.03em;
  background: var(--amber); color: var(--paper); text-decoration: none;
  padding: 0.72rem 1.25rem; border-radius: 2px;
}
.btn:hover { background: var(--navy); }
.btn-quiet {
  background: none; color: var(--navy);
  box-shadow: inset 0 0 0 1px var(--hairline);
}
.btn-quiet:hover { background: none; color: var(--amber); box-shadow: inset 0 0 0 1px var(--amber); }

/* The live model. */
.hero-fig { margin: 0; }
.fig-frame {
  background: var(--tint-thm); border: 1px solid var(--hairline);
  padding: 1rem 1.1rem 1.2rem;
}
.hero-fig svg { width: 100%; height: auto; display: block; }
.fig-control {
  display: flex; align-items: center; gap: 0.8rem; margin: 0.6rem 0 0.7rem;
}
.fig-control label {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.68rem;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--axis);
}
#usage { flex: 1; accent-color: var(--amber); }
.fig-read {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.85rem;
  color: var(--navy); min-width: 3ch; text-align: right;
  font-variant-numeric: tabular-nums;
}
.fig-say {
  margin: 0; min-height: 3.6em; font-size: 0.85rem; line-height: 1.5;
  color: var(--axis); transition: color 0.3s;
}
.fig-say.over { color: var(--amber); }
.hero-fig figcaption {
  font-size: 0.75rem; line-height: 1.5; color: var(--folio);
  margin-top: 0.6rem; padding-top: 0.5rem; border-top: 1px solid var(--hairline);
}

/* The inverted band. The only strong value change on the page. */
.invert {
  background: var(--invert-bg); color: var(--invert-fg);
  margin: calc(var(--step) * 2) calc(50% - 50vw) 0;
  padding: calc(var(--step) * 3) calc(50vw - 50% + 1.5rem);
}
.invert-inner { max-width: 68rem; margin: 0 auto; }
.invert .eyebrow { color: var(--invert-muted); }
.invert h2 {
  font-family: "Jost", sans-serif; font-weight: 600;
  font-size: clamp(1.7rem, 3.2vw, 2.5rem); line-height: 1.1;
  letter-spacing: -0.015em; color: var(--invert-fg); margin: 0 0 1rem;
  text-wrap: balance;
}
.invert-lede { max-width: 44rem; margin: 0 0 1.8rem; color: var(--invert-muted); font-size: 1rem; line-height: 1.6; }
.invert-note { max-width: 44rem; margin: 1.5rem 0 0; color: var(--invert-muted); font-size: 0.88rem; }
/* The theorem panel is the chapter's own markup, so its colours are overridden
   here rather than the panel being rebuilt. Rule 4a: the panel is a rendering of
   the registry statement and is never re-set in different words. */
.invert-panel .theorem {
  background: color-mix(in srgb, var(--invert-fg) 6%, transparent);
  border: 1px solid color-mix(in srgb, var(--invert-fg) 22%, transparent);
  border-left: 3px solid var(--invert-accent);
  padding: 1.4rem 1.6rem; margin: 0; max-width: 52rem;
}
.invert-panel .theorem .lab { color: var(--invert-muted); }
.invert-panel .theorem .stmt {
  color: var(--invert-fg);
  border-bottom-color: color-mix(in srgb, var(--invert-fg) 22%, transparent);
  font-size: 1.15rem;
}
.invert-panel .theorem .cond,
.invert-panel .theorem .conseq,
.invert-panel .theorem li { color: var(--invert-muted); }
.invert-panel .theorem .mk { color: var(--invert-accent); }

.band { max-width: 68rem; margin: 0 auto; padding: calc(var(--step) * 2.6) 0; border-top: 1px solid var(--hairline); }
.invert + .band { border-top: 0; }
.band-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0 1.5rem; margin-bottom: calc(var(--step) * 1.2); }
.band-head .eyebrow { flex-basis: 100%; margin-bottom: 0.5rem; }
.band h2 {
  font-family: "Jost", sans-serif; font-weight: 600;
  font-size: clamp(1.6rem, 3.2vw, 2.4rem); line-height: 1.1;
  letter-spacing: -0.015em; color: var(--navy); margin: 0; text-wrap: balance;
}
.band-meta { margin: 0 0 0 auto; color: var(--folio); font-size: 0.84rem; }

/* The specimen: a real paragraph with its real sidenote, beside the register
   entry that produced it. Shown rather than claimed. */
.specimen {
  display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: 1px; background: var(--hairline); border: 1px solid var(--hairline);
  margin-top: calc(var(--step) * 1.3);
}
.spec-page, .spec-reg { background: var(--paper); padding: 1.4rem 1.5rem; }
.spec-reg { background: var(--tint-def); }
.spec-tag {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.64rem;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--amber);
  margin: 0 0 0.9rem;
}
.spec-page p:not(.spec-tag) { margin: 0; font-size: 0.95rem; line-height: 1.6; }
/* Inside the specimen the sidenote sits inline and ruled: there is no margin to
   float into at this width, and the point is to show that the note exists. */
.spec-page .note {
  float: none; width: auto; margin: 0.9rem 0 0; border-top: 0;
  border-left: 2px solid var(--amber); padding: 0.4rem 0 0.4rem 0.9rem;
  font-size: 0.78rem;
}
.reg-key {
  font-family: "Jost", sans-serif; font-size: 0.72rem; letter-spacing: 0.05em;
  color: var(--navy); background: var(--tint-fig); display: inline-block;
  padding: 0.12rem 0.45rem; margin: 0 0 0.6rem;
}
.reg-title { font-family: "Jost", sans-serif; font-weight: 600; font-size: 1rem; color: var(--navy); margin: 0 0 0.3rem; }
.reg-acc { margin: 0 0 0.8rem; font-size: 0.78rem; color: var(--folio); }
.reg-note {
  margin: 0 0 0.9rem; font-size: 0.8rem; line-height: 1.55; color: var(--axis);
  max-height: 12.5rem; overflow-y: auto;
}
.reg-more { margin: 0; font-size: 0.8rem; }

/* Author. */
.author-grid { display: grid; grid-template-columns: 9rem minmax(0, 1fr); gap: 2rem; align-items: start; }
.author-mark {
  aspect-ratio: 1; display: grid; place-items: center;
  background: var(--invert-bg); color: var(--invert-fg);
}
.author-mark span {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 2.2rem;
  letter-spacing: 0.06em;
}
.author-name { font-family: "Jost", sans-serif; font-weight: 600; font-size: 1.4rem; color: var(--navy); margin: 0 0 0.15rem; }
.author-role {
  font-family: "Jost", sans-serif; font-weight: 500; font-size: 0.72rem;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--amber);
  margin: 0 0 1rem;
}
.author-text p:not(.author-name):not(.author-role) {
  margin: 0 0 0.8rem; font-size: 0.98rem; line-height: 1.6; max-width: 44rem;
}

/* Parts. */
.parts-grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px; background: var(--hairline); border: 1px solid var(--hairline);
}
.part-card { background: var(--paper); padding: 1.5rem 1.3rem; }
.part-numeral {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 2.6rem;
  line-height: 1; color: var(--hairline); margin: 0 0 0.9rem;
}
.part-card h3 {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 1.3rem;
  line-height: 1.15; color: var(--navy); margin: 0 0 0.7rem; text-wrap: balance;
}
.part-purpose { font-size: 0.86rem; line-height: 1.5; color: var(--axis); margin: 0 0 1.1rem; }
.part-chapters { list-style: none; margin: 0; padding: 0.9rem 0 0; border-top: 1px solid var(--hairline); }
.part-chapters li { margin-bottom: 0.5rem; font-size: 0.86rem; line-height: 1.35; }
.part-chapters a { color: var(--navy); text-decoration: none; }
.part-chapters a:hover { color: var(--amber); }
.part-chapters .soon { color: var(--folio); }
.ch-n {
  display: inline-block; min-width: 1.5rem;
  font-family: "Jost", sans-serif; font-weight: 600; color: var(--amber);
  font-variant-numeric: tabular-nums;
}
.part-chapters .soon .ch-n { color: var(--hairline); }

.note-line { margin: calc(var(--step) * 1.2) 0 0; color: var(--axis); font-size: 0.86rem; max-width: 44rem; }

.editions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1px; background: var(--hairline); border: 1px solid var(--hairline); margin-top: calc(var(--step) * 1.2); }
.edition { background: var(--paper); padding: 1.5rem; }
.edition h3 { font-family: "Jost", sans-serif; font-weight: 600; font-size: 1.2rem; color: var(--navy); margin: 0 0 0.6rem; }
.edition p { margin: 0 0 0.7rem; font-size: 0.94rem; line-height: 1.55; color: var(--axis); }
.price {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.72rem;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--amber);
  margin: 0 !important;
}
.edition-cta { margin: 1.1rem 0 0 !important; }

/* ---------- 16. THE REFERENCE LAYER ---------- */
.ref main { padding: 0 1.5rem; }
.band-first { border-top: 0; padding-top: calc(var(--step) * 2.4); }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

/* Glossary. A definition list, because that is what it is. */
.glossary { margin: calc(var(--step) * 1.4) 0 0; }
.gl-row {
  display: grid; grid-template-columns: 16rem minmax(0, 1fr); gap: 0 2rem;
  padding: 1.1rem 0; border-top: 1px solid var(--hairline);
  scroll-margin-top: calc(var(--bar) + 1.5rem);
}
.gl-row:target { background: var(--tint-thm); }
.glossary dt {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 1.08rem;
  color: var(--navy);
}
.gl-owner {
  display: block; margin-top: 0.3rem;
  font-family: "Jost", sans-serif; font-weight: 500; font-size: 0.68rem;
  letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--amber); text-decoration: none;
}
.gl-owner.soon { color: var(--folio); }
.glossary dd { margin: 0; font-size: 0.94rem; line-height: 1.55; }

/* Sources. Chicago note form, hanging indent, key and status beneath. */
.src-list { list-style: none; margin: calc(var(--step) * 1.4) 0 0; padding: 0; counter-reset: src; }
.src-list li {
  padding: 1rem 0 1rem 2.4rem; border-top: 1px solid var(--hairline);
  position: relative; scroll-margin-top: calc(var(--bar) + 1.5rem);
  counter-increment: src;
}
.src-list li::before {
  content: counter(src); position: absolute; left: 0; top: 1rem;
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.85rem;
  color: var(--amber); font-variant-numeric: tabular-nums;
}
.src-list li:target { background: var(--tint-thm); }
.src-list li.soon .src-text { color: var(--axis); }
.src-text { margin: 0 0 0.4rem; font-size: 0.95rem; line-height: 1.55; max-width: 46rem; }
.src-text .url { word-break: break-all; color: var(--axis); font-size: 0.9em; }
.src-meta { margin: 0; display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; align-items: baseline; }
.src-key {
  font-family: "Jost", sans-serif; font-size: 0.7rem; letter-spacing: 0.06em;
  color: var(--navy); background: var(--tint-fig); padding: 0.1rem 0.4rem;
}
.src-flag {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.66rem;
  letter-spacing: 0.13em; text-transform: uppercase; color: var(--teal);
}
.src-flag.soon { color: var(--folio); }
.src-url { font-size: 0.76rem; color: var(--axis); }

/* Objects and promises. */
.obj-list, .promise-list { list-style: none; margin: calc(var(--step) * 1.4) 0 0; padding: 0; }
.obj-list li, .promise-list li {
  padding: 1.1rem 0; border-top: 1px solid var(--hairline);
  scroll-margin-top: calc(var(--bar) + 1.5rem);
}
.obj-list li:target { background: var(--tint-thm); }
.obj-id {
  font-family: "Jost", sans-serif; font-weight: 600; font-size: 0.78rem;
  letter-spacing: 0.12em; color: var(--navy); margin: 0 0 0.35rem;
}
.obj-gloss { margin: 0 0 0.4rem; font-size: 1.02rem; line-height: 1.45; max-width: 46rem; color: var(--ink); }
.obj-where, .promise-route { margin: 0; font-size: 0.78rem; }
.obj-where a { color: var(--amber); text-decoration: none; }
.obj-where.soon { color: var(--folio); }
.promise-route {
  font-family: "Jost", sans-serif; font-weight: 600; color: var(--navy);
  margin-bottom: 0.3rem; display: flex; gap: 0.7rem; align-items: baseline;
}
.promise-status {
  font-size: 0.64rem; letter-spacing: 0.13em; text-transform: uppercase;
  padding: 0.1rem 0.45rem; border: 1px solid var(--hairline); color: var(--folio);
}
.promise-status.paid { color: var(--teal); border-color: var(--teal); }
.promise-status.open { color: var(--amber); border-color: var(--amber); }
.promise-text { margin: 0; font-size: 0.94rem; line-height: 1.55; max-width: 46rem; color: var(--axis); }

/* Search. */
.search-box { margin: calc(var(--step) * 1.2) 0; }
#q {
  width: 100%; max-width: 40rem;
  font-family: var(--body-face); font-size: 1.05rem; color: var(--ink);
  background: var(--paper); border: 1px solid var(--hairline);
  border-radius: 2px; padding: 0.75rem 0.9rem;
}
#q:focus { outline: none; border-color: var(--amber); }
.results { list-style: none; margin: calc(var(--step) * 1.2) 0 0; padding: 0; }
.results li { padding: 1rem 0; border-top: 1px solid var(--hairline); }
.results a { text-decoration: none; display: block; }
.res-kind {
  display: block; font-family: "Jost", sans-serif; font-weight: 600;
  font-size: 0.66rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--amber); margin-bottom: 0.2rem;
}
.res-title { font-family: "Jost", sans-serif; font-weight: 600; font-size: 1.08rem; color: var(--navy); }
.results a:hover .res-title { color: var(--amber); }
.res-body { margin: 0.35rem 0 0; font-size: 0.88rem; line-height: 1.5; color: var(--axis); max-width: 48rem; }
.res-body mark { background: var(--tint-fig); color: var(--ink); }

/* ---------- 17. RESPONSIVE ---------- */
/* Below the threshold the sidenote returns inline, indented and ruled, rather
   than being hidden. An apparatus a reader cannot reach on a phone is an
   apparatus the book does not have. */
/* THE BREAKPOINT IS ARITHMETIC, NOT TASTE, AND IT IS SOLVED IN rem BECAUSE THE
   ROOT SIZE IS NOW FLUID. Every term scales with the root, so the sum is a
   multiple of it rather than a pixel count.

   A margin note needs --note + --note-gap = 16.25rem of side track. The side
   track is (viewport - --rail - 2 x .reading padding - --measure) / 2, which is
   (viewport - 15.5 - 3 - 32 rem) / 2 = (viewport - 50.5rem) / 2. So the note
   fits from (50.5 + 2 x 16.25) = 83rem up.

   The root is 17px wherever this can bind, because the clamp in section 3 is
   flat below 1440px, so 83rem = 1411px and the query sits at 1420px. Above
   1440px the root grows but the viewport grows faster: the condition there is
   viewport >= 83 x (8 + 0.00625 x viewport), which solves to 1380px and is
   therefore satisfied everywhere the fluid range exists. The flat region is the
   binding one, and that is the only case this sum has to state.

   TWO EARLIER VERSIONS OF THIS SUM WERE WRONG. The first set it at 1240px by
   eye, leaving a 170px band where the note ran off the right edge of the
   window. The second computed 15.5 + 32 + 2 x 17.75 = 83rem and omitted the
   .reading padding entirely, which the 1440px query then covered by accident
   rather than by design.

   THAT SECOND SUM ALSO CAME TO 83rem, AND THE MATCH IS A COINCIDENCE, NOT A
   COPIED LINE. It reached it by dropping 3rem of padding from a 17.75rem note
   track; this one reaches it by carrying the padding and a 16.25rem note track.
   The two agree on the total and disagree about every term in it. Anyone
   checking this sum should re-derive it rather than recognise the number.

   Any change to --note, --note-gap, --measure, --rail, .reading's padding, or
   either stop of the section 3 clamp must redo this. */
@media (max-width: 1420px) {
  .reading { grid-template-columns: minmax(0, 1fr); justify-items: center; }
  #chapter-text, .toc { grid-column: 1; width: 100%; max-width: var(--measure); }
  .note {
    float: none; width: auto; margin-right: 0;
    margin: 0.8rem 0 1.1rem; padding: 0.6rem 0 0.2rem 0.9rem;
    border-top: 0; border-left: 2px solid var(--hairline);
  }
}
@media (max-width: 1100px) {
  .parts-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .hero { grid-template-columns: minmax(0, 1fr); gap: 2.2rem; }
  .specimen { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 900px) {
  .layout { grid-template-columns: minmax(0, 1fr); }
  .topnav { display: none; }
  .rail {
    display: none; position: static; max-height: none;
    padding: 1.2rem 1.5rem 1.5rem; border-bottom: 1px solid var(--hairline);
  }
  .rail.open { display: block; }
  .topbar-here { display: none; }
}
@media (min-width: 901px) { .rail-toggle { display: none; } }
@media (max-width: 620px) {
  /* THIS OVERRIDES THE SECTION 3 CLAMP AND IS MEANT TO. It wins on order, not
     on specificity, so it must stay below section 3 in the file. A phone reads
     at 16px, which sets 49 characters at 390px and 45 at 360px, and the fluid
     range never reaches this far down anyway. The measure never binds here:
     the column is the viewport less the padding, so type size is the only
     lever a phone has. */
  html { font-size: 16px; }
  :root { --step: 1.35rem; }
  .reading { padding-inline: 1.15rem; }
  .topbar { padding-inline: 1.15rem; }
  .brand { font-size: 0.7rem; letter-spacing: 0.06em; }
  .kt-list { grid-template-columns: minmax(0, 1fr); }
  .dq { grid-template-columns: 1.6rem 1fr; }
  .parts-grid, .editions { grid-template-columns: minmax(0, 1fr); }
  .author-grid { grid-template-columns: minmax(0, 1fr); gap: 1.2rem; }
  .author-mark { width: 6rem; }
  .invert { padding-inline: 1.15rem; }
  .gl-row { grid-template-columns: minmax(0, 1fr); gap: 0.5rem; }
  .ref main { padding-inline: 1.15rem; }
  .home main { padding-inline: 1.15rem; }
  .cta { font-size: 0.68rem; padding: 0.4rem 0.7rem; }
  /* The chapter bar already carries a brand and a Contents button, and a third
     item overflowed the row at 320px. Gate W6 found it. The CTA is not lost: the
     chapter footer carries it at every width. */
  body:not(.home) .topbar .cta { display: none; }
  table.inv { font-size: 0.72rem; }
}

/* ---------- 18. MOTION ---------- */
/* The .reveal class is added BY SCRIPT, never in the markup. A reader with
   JavaScript disabled therefore sees every block at full opacity instead of a
   blank page, which is what a markup-side opacity:0 would have produced. */
.reveal { opacity: 0; transform: translateY(10px); }
.reveal.shown {
  opacity: 1; transform: none;
  transition: opacity 0.5s ease-out, transform 0.5s ease-out;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal, .reveal.shown { opacity: 1; transform: none; transition: none; }
  .progress i { transition: none; }
  * { animation-duration: 0.01ms !important; }
}

/* ---------- 19. PRINT FROM THE BROWSER ---------- */
/* Not the book. The book is AIOM_build.py and WeasyPrint. This only stops a
   browser print of a web page from carrying the site chrome. */
@media print {
  [data-chrome] { display: none !important; }
  .layout, .reading { display: block; }
  #chapter-text { max-width: none; }
  .note { float: none; width: auto; margin: 0.5rem 0; }
  .reveal { opacity: 1; transform: none; }
}

/* Reference links in the chapter footer. */
.foot-links { display: flex; flex-wrap: wrap; gap: 0.4rem 1.2rem; margin: 0 0 0.9rem; }
.foot-links a { color: var(--navy); font-size: 0.82rem; }
.foot-cta { margin: 0.4rem 0 0; }

/* ---------- 20. THE THEME TOGGLE ---------- */
/* Small, quiet, and always the last control in the bar. The label says what a
   click WILL do, not what the theme currently is, which is the version people
   read correctly without thinking about it. */
.theme-toggle {
  font-family: "Jost", sans-serif; font-weight: 500; font-size: 0.72rem;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--axis); background: none;
  border: 1px solid var(--hairline); border-radius: 2px;
  padding: 0.32rem 0.6rem; cursor: pointer; white-space: nowrap;
}
.theme-toggle:hover { border-color: var(--amber); color: var(--amber); }
@media (max-width: 620px) {
  /* The chapter bar already carries a brand and a Contents button. A fourth
     control overflowed the row at 320px once and gate W6 caught it. */
  body:not(.home) .theme-toggle { display: none; }
}
