/* ==========================================================================
   Relationships Between Parametric Uniformity and Conditional Structures
   of Relational Probabilistic Knowledge Bases - web edition.

   The design is taken from the thesis itself rather than invented:

   - header.tex:94 sets chapter titles as `2 | Background`, number and title
     divided by a vertical rule. That divider is the site's signature and
     reappears as the current-position marker in the contents.
   - header.tex:191-218 puts a 2pt vertical rule beside every proposition and
     every assumption; :130-159 and :221-231 indent definitions, examples and
     proofs instead. Rule means asserted, indent means elaborated. The site
     keeps that distinction because it carries meaning.
   - header.tex:82 sets a 2.1cm left and a 4.5cm right margin: the print text
     block is left-set with a wide right margin. Prose here holds a measure of
     35rem and the 91 grid blocks extend into the margin beside it.
   - The two coloured truth tables of section 8.7 (22 green cells and 22
     yellow) are the reason the palette is warm-on-cold rather than the other
     way round: both tints have to stay legible in both schemes at low
     opacity.

   Typography. Numerals and the fixed English labels - `Definition 12`,
   `Table 6.1`, the chapter number - are set in KaTeX_Main, the same Computer
   Modern the mathematics is set in, so the structural layer and the formulas
   share letterforms. Everything that can carry a German word, an author's
   title or a mathematical symbol is set in the book serif instead: measured
   on the shipped font files, KaTeX_Main-Regular holds 283 glyphs and has no
   precomposed umlaut, so `Erklärung` would break mid-word. Restricting it to
   digits and ASCII labels is not caution, it is the measurement.

   No JavaScript anywhere on the site. KaTeX runs at build time, the contents
   is a page rather than a drawer, and every state has an address.

   ---------------------------------------------------------------------------
   The class names below section 6 are not this file's invention. They are what
   thesis/body.py and thesis/grids.py emit, read out of those modules, and
   tests/test_templates.py pins every one of them: a stylesheet that quietly
   loses a hook produces a page that looks finished and is not.

   The shapes that matter:

     <section class="thm thm-proposition" id="Proposition.13">
       <p class="thm-head"><span class="thm-name">Proposition 13</span>
          <span class="thm-title">(Maximum Ordered Sum of a C-Conditional)</span></p>
       <div class="thm-body">...</div>
     </section>

     <figure class="gr-figure" id="...">
       <div class="gr-scroll" tabindex="0"><table class="gr-grid">...</table></div>
       <figcaption class="gr-caption">
         <span class="gr-caption-label">Table 6.1:</span> ...</figcaption>
     </figure>

   thesis/grids.py also ships a stylesheet of its own, `grids.CSS`, holding the
   structural half of the tables - column rules, merged cells, brace geometry.
   The build has to include it, and style.css has to come after it. See the
   note above section 8.

   An itemize or an enumerate arrives as a bare <ul> or <ol> with no class and
   takes its dash or its number from here. A list that carries a class is
   furniture and is left alone.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* Dark first: an unconfigured visitor gets the dark scheme, because the
     first keyword of color-scheme wins when the browser reports no
     preference. The light scheme below only takes over on an explicit one. */
  color-scheme: dark light;

  --c-bg: #0f1518;
  --c-bg-lift: #151d21;
  --c-bg-sunk: #0b1013;
  --c-ink: #e5e2d8;
  --c-ink-strong: #f5f2e9;
  --c-ink-dim: #93a09c;
  --c-rule: #26312f;
  --c-rule-firm: #4d5c57;
  --c-accent: #d8a249;
  --c-underline: rgba(216, 162, 73, 0.38);
  --c-target: rgba(216, 162, 73, 0.10);
  --c-tint-green: rgba(106, 176, 120, 0.22);
  --c-tint-amber: rgba(216, 162, 73, 0.20);
  --c-shadow: rgba(0, 0, 0, 0.45);
  /* The edge cue on a scrollable grid. A drop shadow is invisible against a
     near-black ground, so on dark it is a breath of the accent instead. */
  --c-scrollcue: rgba(216, 162, 73, 0.26);
  /* Unresolved reference, unconverted grid: must be visible in both schemes,
     because a build that ships one of these is not finished. */
  --c-alarm: #ff7a70;

  /* Palatino leads the stack for one reason: it is the traditional companion
     of Computer Modern mathematics in printed maths books, and it is the one
     book serif present by default on macOS, Windows and most Linux desktops,
     so the page a visitor sees is the page that was checked. */
  --face-book: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", P052,
    Palatino, Charter, "Bitstream Charter", "Charis SIL", Cambria, Georgia,
    "Nimbus Roman", "Liberation Serif", serif;
  /* Digits and fixed ASCII labels only - see the note at the top. */
  --face-cm: "KaTeX_Main", var(--face-book);

  /* Text size and column width are the two things a reader most often wants
     different, so they are single tokens here and every rule reads them.
     `prefs.js` overrides them by putting data-textsize / data-width on <html>;
     with JavaScript off these defaults are simply what everyone gets. */
  --measure: 46rem;
  --content-max: 64rem;
  --sidebar-w: 16.5rem;
  --masthead-h: 3.25rem;
  --gutter: 1.5rem;

  --step-0: 1.155rem;
  --step-1: 1.2rem;
  --step-2: 1.5rem;
  --step-3: clamp(1.85rem, 1.2rem + 2.4vw, 2.6rem);
  --step-4: clamp(2.6rem, 1.4rem + 5.4vw, 4.6rem);
  --step--1: 0.9rem;
  --step--2: 0.8rem;
}

/* The reader's own choice, set by prefs.js on <html>. Three of each: enough
   to matter, few enough that every combination was actually looked at. The
   middle of each is the default above, so a reader who never touches the
   control and a reader who chooses "medium" get the same page. */
:root[data-textsize="s"] {
  --step-0: 1.0625rem;
}

:root[data-textsize="l"] {
  --step-0: 1.28rem;
}

:root[data-width="narrow"] {
  --measure: 38rem;
  --content-max: 54rem;
}

:root[data-width="wide"] {
  --measure: 58rem;
  --content-max: 78rem;
}

@media (prefers-color-scheme: light) {
  :root {
    --c-bg: #eff1eb;
    --c-bg-lift: #e6e9e1;
    --c-bg-sunk: #f7f8f4;
    --c-ink: #1a211f;
    --c-ink-strong: #0b100f;
    --c-ink-dim: #59665f;
    --c-rule: #d5dad0;
    --c-rule-firm: #97a39c;
    --c-accent: #7a5a12;
    --c-underline: rgba(122, 90, 18, 0.42);
    --c-target: rgba(122, 90, 18, 0.09);
    --c-tint-green: rgba(46, 125, 66, 0.17);
    --c-tint-amber: rgba(184, 134, 11, 0.22);
    --c-shadow: rgba(31, 41, 38, 0.16);
    --c-scrollcue: rgba(31, 41, 38, 0.28);
    --c-alarm: #a3261c;
  }
}

/* --------------------------------------------------------------------------
   2. Reset and base
   -------------------------------------------------------------------------- */

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

html {
  /* Every cross-reference on the site is a same-page or cross-page anchor -
     404 of them - and the masthead is sticky, so without this the target
     heading lands underneath it and the reader sees the wrong line. */
  scroll-padding-top: calc(var(--masthead-h) + 1rem);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--c-bg);
  color: var(--c-ink);
  font-family: var(--face-book);
  font-size: var(--step-0);
  line-height: 1.72;
  text-rendering: optimizeLegibility;
  font-kerning: normal;
  /* The page body never scrolls sideways; wide grids scroll inside their own
     box. This is a floor, not the mechanism - see .gr-scroll. */
  overflow-x: clip;
}

h1,
h2,
h3,
h4 {
  color: var(--c-ink-strong);
  font-weight: 700;
  line-height: 1.22;
  text-wrap: balance;
  margin: 0;
}

p {
  margin: 0 0 1.05em;
}

img,
svg {
  max-width: 100%;
  height: auto;
}

hr {
  border: 0;
  border-top: 1px solid var(--c-rule);
  margin: 2rem 0;
}

/* Links carry no colour of their own. With 404 cross-references in the text a
   coloured link turns the prose into a rash; an underline in the accent at
   38% reads as a link and disappears into the paragraph until wanted. */
a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--c-underline);
  transition: color 120ms ease, border-color 120ms ease;
}

a:hover {
  color: var(--c-accent);
  border-bottom-color: var(--c-accent);
}

a:focus-visible,
:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 2px;
  border-radius: 1px;
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition-duration: 1ms !important;
    animation-duration: 1ms !important;
  }
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 20;
  background: var(--c-bg-lift);
  color: var(--c-ink-strong);
  padding: 0.6rem 1rem;
  border: 1px solid var(--c-rule-firm);
}

.skip:focus {
  left: 0.5rem;
  top: 0.5rem;
}

/* A shared utility for the small upright labels: contents headings, the
   folio, the "in this chapter" caption. Differentiated from the prose by
   size, case and tracking rather than by a second typeface. */
.eyebrow {
  font-size: var(--step--2);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--c-ink-dim);
  margin: 0 0 0.6rem;
}

/* --------------------------------------------------------------------------
   3. Masthead
   -------------------------------------------------------------------------- */

.masthead {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 0.9rem;
  height: var(--masthead-h);
  padding: 0 var(--gutter);
  /* Opaque, not translucent: a 40-column truth table sliding under a blurred
     bar leaves a smear of ghost digits along the top of the page. */
  background: var(--c-bg);
  border-bottom: 1px solid var(--c-rule);
}

.masthead__mark {
  display: flex;
  align-items: center;
  border: 0;
  flex: none;
}

.masthead__mark svg {
  display: block;
  width: 1.35rem;
  height: 1.35rem;
  color: var(--c-accent);
}

.masthead__title {
  margin: 0;
  min-width: 0;
  font-size: var(--step--1);
  font-weight: 400;
  color: var(--c-ink-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.masthead__title a {
  border: 0;
  color: var(--c-ink);
}

.masthead__nav {
  margin-left: auto;
  display: flex;
  gap: 1.1rem;
  font-size: var(--step--1);
  flex: none;
}

.masthead__nav a {
  border-bottom-color: transparent;
  color: var(--c-ink-dim);
}

.masthead__nav a:hover,
.masthead__nav a[aria-current] {
  color: var(--c-accent);
  border-bottom-color: var(--c-underline);
}

/* --------------------------------------------------------------------------
   4. Shell and sidebar
   -------------------------------------------------------------------------- */

.shell {
  display: grid;
  /* minmax(0, 1fr) rather than 1fr: a grid item's automatic minimum size is
     its content, so a 40-column truth table would otherwise widen the whole
     grid and take the page sideways with it. */
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
  gap: 0 3rem;
  max-width: 82rem;
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.sidebar {
  position: sticky;
  top: var(--masthead-h);
  align-self: start;
  max-height: calc(100vh - var(--masthead-h));
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 2rem 0.75rem 3rem 0;
  font-size: var(--step--1);
  line-height: 1.45;
}

.sidebar__group + .sidebar__group {
  margin-top: 1.6rem;
}

.sidebar ol,
.sidebar ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.sidebar a {
  display: block;
  border: 0;
  padding: 0.24rem 0 0.24rem 0.85rem;
  /* The unlit half of the chapter divider from the print edition: every entry
     carries the rule, the current one lights it. */
  border-left: 2px solid transparent;
  color: var(--c-ink-dim);
}

.sidebar a:hover {
  color: var(--c-ink-strong);
  border-left-color: var(--c-rule-firm);
}

.sidebar a[aria-current] {
  color: var(--c-ink-strong);
  border-left-color: var(--c-accent);
}

.sidebar__num {
  font-family: var(--face-cm);
  color: var(--c-ink-dim);
  margin-right: 0.45em;
}

.sidebar a[aria-current] .sidebar__num {
  color: var(--c-accent);
}

.sidebar__sections a {
  padding-left: 1.9rem;
  font-size: var(--step--2);
}

/* --------------------------------------------------------------------------
   5. Main column
   -------------------------------------------------------------------------- */

main {
  min-width: 0;
  padding: 2.5rem 0 4rem;
  max-width: var(--content-max);
}

/* The chapter opener: the print edition's `2 | Background`, kept whole. */
.opener {
  margin-bottom: 2.75rem;
}

.opener__head {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  margin: 0;
  font-size: var(--step-3);
}

.opener__number {
  font-family: var(--face-cm);
  font-size: var(--step-4);
  font-weight: 700;
  line-height: 0.9;
  color: var(--c-ink-strong);
  flex: none;
}

.opener__rule {
  align-self: stretch;
  width: 2px;
  min-height: 2.6rem;
  background: var(--c-accent);
  flex: none;
}

.opener__title {
  font-size: inherit;
  font-weight: 700;
}

.opener__meta {
  margin: 1.1rem 0 0;
  color: var(--c-ink-dim);
  font-size: var(--step--1);
}

/* Section list at the top of a chapter. On a phone this replaces the sidebar;
   on a wide screen the sidebar already shows it, so it is hidden there. */
.inchapter {
  display: none;
  margin: 0 0 2.5rem;
  padding: 1rem 1.1rem;
  background: var(--c-bg-lift);
  border-left: 2px solid var(--c-rule-firm);
}

.inchapter ol {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: var(--step--1);
}

.inchapter li + li {
  margin-top: 0.35rem;
}

.inchapter a {
  border: 0;
}

.inchapter .sidebar__num {
  color: var(--c-ink-dim);
}

/* --------------------------------------------------------------------------
   6. Prose

   From here to section 9 the class names are not this file's own invention:
   they are what thesis/body.py and thesis/grids.py actually emit. The
   stylesheet follows the converter, never the other way round.
   -------------------------------------------------------------------------- */

/* Flow children hold the measure; grids, figures and anything marked .wide
   are allowed into the right margin, exactly as the print geometry does. */
.prose > *,
.thm > *,
.thm-body > * {
  max-width: var(--measure);
}

.prose > .thm,
.prose > .gr-figure,
.prose > .wide,
.thm > .thm-body,
.thm > .gr-figure,
.thm-body > .gr-figure,
.thm-body > .wide {
  max-width: 100%;
}

/* A figure is centred, so like a display formula it has to be centred over the
   column the sentences occupy. Allowed the full content width, it sat right of
   the paragraph that introduced it. The grids above keep the full width on
   purpose - the print geometry sets them into the wide right margin - but a
   diagram belongs with the text. */
.prose > figure,
.thm > figure,
.thm-body > figure {
  max-width: var(--measure);
}

/* A display formula starts at the left edge of the column the sentences
   occupy, on the author's instruction - KaTeX centres it by default, and the
   printed thesis centres it too, but on a screen a centred formula floats away
   from the sentence that introduces it. The box is still capped at the measure
   so it lines up with the prose, and a formula wider than the column scrolls
   inside its own box. */
.prose > .katex-display,
.thm-body > .katex-display {
  max-width: var(--measure);
}

.prose h1,
.prose h2,
.prose h3,
.prose h4 {
  scroll-margin-top: calc(var(--masthead-h) + 1rem);
}

/* body.py emits the chapter heading as <h1 class="chapter">. A builder that
   uses chapter.html's opener instead should drop that h1 rather than print
   the title twice; both are styled so either choice reads correctly. */
.prose h1.chapter {
  font-size: var(--step-3);
  margin: 0 0 2.5rem;
}

.prose h2 {
  font-size: var(--step-2);
  margin: 3rem 0 1rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--c-rule);
}

.prose h3 {
  font-size: var(--step-1);
  margin: 2.2rem 0 0.8rem;
}

.prose h4 {
  font-size: var(--step-0);
  margin: 1.8rem 0 0.6rem;
}

/* The number is digits and dots, so it is safe in Computer Modern; the title
   is not, and stays in the book serif. */
.heading-number {
  font-family: var(--face-cm);
  font-weight: 700;
  color: var(--c-ink-dim);
  margin-right: 0.35em;
}

.prose h1.chapter .heading-number {
  color: var(--c-accent);
}

/* Ten headings in this thesis carry maths, a citation or a cross-reference,
   so the title is its own span in the book serif and never in Computer
   Modern - see the note at the top of the file. */
.heading-title {
  font-family: var(--face-book);
}

/* A \caption that escaped its figure. body.py emits it as a paragraph rather
   than dropping it; it is styled like a caption so it does not read as
   ordinary prose. */
p.caption {
  font-size: var(--step--1);
  color: var(--c-ink-dim);
  max-width: var(--measure);
}

.prose ul,
.prose ol {
  margin: 0 0 1.05em;
  padding-left: 0;
  list-style: none;
}

.prose li {
  margin-bottom: 0.4em;
}

/* Both markers are drawn rather than left to the list: a list item is a
   scroll container here (see the note further down), and Chrome clips an
   outside ::marker against that scroll box, which silently loses every
   footnote number. Drawing the marker inside the item's own padding keeps it.
   Safe for this document: all 12 enumerate environments are plain, none sets
   a label, a start or a value. */
.prose ol.enumerate {
  counter-reset: prose-item;
}

.prose ol.enumerate > li {
  position: relative;
  padding-left: 2rem;
  counter-increment: prose-item;
}

.prose ol.enumerate > li::before {
  content: counter(prose-item) ".";
  position: absolute;
  left: 0.1rem;
  font-family: var(--face-cm);
  color: var(--c-ink-dim);
}

/* header.tex:110 - the author prefers a dash over a bullet. The indent lives
   on the list item, not on the list, so that the marker sits inside the item's
   own box: the items below are scroll containers, and anything positioned
   outside the box - a negative margin, a left of -1.2rem - is cut off by that
   scrolling and the dash disappears.

   The selector names the classes the converter really emits: body.py writes
   <ul class="itemize"> and <ol class="enumerate">. This used to read
   `:not([class])`, on the assumption that a thesis list arrives unclassed -
   so every one of the 31 itemize and 12 enumerate environments rendered with
   no dash, no number and no indent. Furniture - the glossary, the index, the
   back-matter lists - carries its own class and its own layout, and is
   untouched by these rules. */
.prose ul.itemize > li {
  position: relative;
  padding-left: 1.6rem;
}

.prose ul.itemize > li::before {
  content: "\2013";
  position: absolute;
  left: 0.25rem;
  color: var(--c-ink-dim);
}

/* 13 items in the thesis are written `\item[]` - an empty optional label,
   which in LaTeX means "no bullet at all". body.py marks those `nolabel`, and
   an item that brought its own label is marked `labelled`; neither may also
   get the dash. */
.prose ul > li.nolabel,
.prose ul > li.labelled,
.prose ol > li.nolabel,
.prose ol > li.labelled {
  padding-left: 1.6rem;
}

.prose li.nolabel::before,
.prose li.labelled::before {
  content: none;
}

.item-label {
  position: absolute;
  left: 0;
  color: var(--c-ink-dim);
}

.prose li.labelled {
  position: relative;
}

/* Inline mathematics cannot break. KaTeX lays each formula out as one
   unbreakable run, this thesis has 2066 of them inside sentences, and the
   longest is 165 characters of LaTeX. Measured in the browser at 360px: of
   the 71 longest, 3 are wider than the column. The page body may not scroll
   sideways, so those three would be clipped away unseen - which is the exact
   failure this project exists to avoid. Giving the flow element its own
   scroll keeps the formula reachable and the page still; the scrollbar
   appears only where a formula really overruns. */
.prose p,
.prose li,
.prose dd,
.fn-body,
.entry__body,
figcaption {
  overflow-x: auto;
  overflow-y: hidden;
}

.prose blockquote {
  margin: 1.6rem 0;
  padding-left: 1.15rem;
  border-left: 2px solid var(--c-rule-firm);
  color: var(--c-ink-dim);
  font-style: italic;
}

.prose em,
.prose i {
  font-style: italic;
}

/* The theorem styles of header.tex:256 set proposition, definition and
   example bodies in a slanted face. Kept for the short emphasis spans the
   converter marks, but not applied to whole blocks: a slanted screen serif
   over a 71-example thesis is a headache, and the left rule and the indent
   already say which kind of block it is. */
.slanted {
  font-style: italic;
}

.larger {
  font-size: 1.15em;
}

.smaller {
  font-size: 0.9em;
}

.smallest {
  font-size: 0.8em;
}

/* Cross-references, citations, glossary and acronym links. 404 references,
   48 citations, 33 glossary and 26 acronym uses: all of them keep the quiet
   underline of an ordinary link so the prose does not turn into a rash. */
.cite-group,
a.cite,
a.ref,
.fn-mark {
  font-family: var(--face-cm);
  white-space: nowrap;
}

/* `a.ref` was missing from the rule above, so all 405 cross-references set
   their number in the book serif instead of Computer Modern and could break
   across a line - "Definition" at the end of one line and "12" at the start of
   the next. They are the most common link in the document; they have to match
   the numbers they point at. */

a.acr,
a.gls {
  border-bottom-style: dotted;
}

/* An index mark is an anchor with nothing in it - it must stay invisible but
   must still be scrolled to. */
.ix {
  display: inline-block;
  width: 0;
  height: 0;
  overflow: hidden;
  scroll-margin-top: calc(var(--masthead-h) + 1rem);
}

/* A reference, citation or glossary key the converter could not resolve. It
   must look wrong on the page: a build that ships one of these is not
   finished, and the acceptance gate counts them. */
.ref-broken,
.cite-broken,
.gls-broken {
  color: var(--c-alarm);
  border-bottom: 1px dashed currentColor;
}

/* Same reasoning: a grid or a diagram that has not been converted yet leaves
   a placeholder, and a placeholder may never look like content. */
.pending {
  margin: 1.5rem 0;
  padding: 1rem;
  border: 1px dashed var(--c-alarm);
  color: var(--c-alarm);
  font-size: var(--step--1);
}

/* \circled, 34 uses. tikz draws it in print; here it is a ring of text. */
.circled {
  display: inline-block;
  min-width: 1.5em;
  padding: 0 0.15em;
  border: 1px solid currentColor;
  border-radius: 50%;
  text-align: center;
  font-size: 0.85em;
  line-height: 1.5;
}

.footnotes {
  margin-top: 3rem;
  padding-top: 1rem;
  border-top: 1px solid var(--c-rule);
  font-size: var(--step--1);
  color: var(--c-ink-dim);
}

.footnotes-head {
  font-size: var(--step--2);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--c-ink-dim);
  border: 0;
  padding: 0;
  margin: 0 0 0.8rem;
}

.footnote {
  display: flex;
  gap: 0.7rem;
  margin-bottom: 0.5rem;
  scroll-margin-top: calc(var(--masthead-h) + 1rem);
}

.fn-back {
  flex: none;
  font-family: var(--face-cm);
  border: 0;
}

.fn-body p:last-child {
  margin-bottom: 0;
}

.fn-mark a {
  border: 0;
}

/* Anything a cross-reference lands on says so, and keeps saying so, because
   the address is the state. */
:target {
  background: var(--c-target);
  box-shadow: -0.6rem 0 0 var(--c-target), 0.6rem 0 0 var(--c-target);
}

.thm:target,
figure:target,
.gr-figure:target,
.footnote:target {
  background: none;
  box-shadow: none;
  outline: 1px solid var(--c-underline);
  outline-offset: 0.6rem;
}

/* --------------------------------------------------------------------------
   7. Numbered blocks - 50 definitions, 71 examples, 20 propositions,
      7 assumptions, 19 proofs
   -------------------------------------------------------------------------- */

.thm {
  margin: 1.9rem 0;
  scroll-margin-top: calc(var(--masthead-h) + 1rem);
}

.thm > *:last-child,
.thm-body > *:last-child {
  margin-bottom: 0;
}

/* Asserted: proposition, assumption. The 2pt rule of header.tex:237. */
.thm-proposition,
.thm-assumption {
  padding-left: 1.15rem;
  border-left: 2px solid var(--c-rule-firm);
}

/* Elaborated: definition, example, proof. The 12pt indent of header.tex:138,
   :154 and :225, with no rule. */
.thm-definition,
.thm-example,
.thm-proof {
  padding-left: 1.15rem;
}

.thm-head {
  margin: 0 0 0.35rem;
  font-size: var(--step-0);
  line-height: 1.45;
  color: var(--c-ink-strong);
}

/* `Definition 12`, `Example 35`, `Proposition 13` - the kind word and the
   number, always ASCII, so this is one of the two places besides the numerals
   where Computer Modern is safe. */
.thm-name {
  font-family: var(--face-cm);
  font-weight: 700;
  color: var(--c-accent);
  margin-right: 0.3em;
}

.thm-title {
  font-weight: 400;
  color: var(--c-ink);
}

.thm-proof .thm-name {
  font-weight: 400;
  font-style: italic;
  color: var(--c-ink-dim);
}

/* The open square that ends a proof. Drawn rather than set, because the
   printed qedsymbol is an empty box and half the serif stacks below have no
   U+25A1 to give. It floats to the end of the last line, as amsthm does. */
.qed {
  float: right;
  width: 0.62em;
  height: 0.62em;
  margin: 0.5em 0 0 0.6em;
  border: 1px solid currentColor;
  color: var(--c-ink-dim);
}

.thm-proof::after {
  content: "";
  display: block;
  clear: both;
}

/* --------------------------------------------------------------------------
   8. Grids - the 59 truth tables and 32 arrays

   thesis/grids.py ships its own stylesheet as `grids.CSS`, and the build has
   to include it: it holds the structural half - the column rules read out of
   the array spec, the merged cells, the alignment classes, the geometry of a
   row-spanning brace - and this file must not hold a second copy of any of
   that. What follows is only the half that belongs to the page: palette,
   type size, the scroll box and the two coloured tables.

   Order matters. grids.CSS carries colour fallbacks of its own, so style.css
   has to be the later of the two. base.html links it last.
   -------------------------------------------------------------------------- */

.gr-figure {
  margin: 1.9rem 0;
  scroll-margin-top: calc(var(--masthead-h) + 1rem);
}

.gr-scroll {
  /* grids.CSS declares this too, identically. It is repeated here on purpose:
     "the page body never scrolls sideways, the table scrolls inside its own
     box" is the hardest requirement this stylesheet carries, and it must not
     depend on another file being wired in. Two identical declarations cannot
     disagree; the structural rules, which can, are not repeated. */
  overflow-x: auto;
  overflow-y: hidden;
  max-width: 100%;
  padding-bottom: 0.35rem;
  /* A clipped table edge on a phone is not an affordance, and the widest of
     these is 701px inside a 355px box. Two pairs of gradients: the `local`
     pair scrolls with the content and covers the cue at each end, the
     `scroll` pair stays put, so the cue shows exactly on the side that has
     more table. No script involved. */
  background:
    linear-gradient(to right, var(--c-bg) 40%, transparent) 0 0 / 2.5rem 100% no-repeat local,
    linear-gradient(to left, var(--c-bg) 40%, transparent) 100% 0 / 2.5rem 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%, var(--c-scrollcue), transparent) 0 0 / 0.9rem 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, var(--c-scrollcue), transparent) 100% 0 / 0.9rem 100% no-repeat scroll;
}

/* grids.py gives the scroll box a tabindex so it can be reached and scrolled
   from the keyboard; that focus has to be visible. */
.gr-scroll:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 2px;
}

/* Left-set, not centred. The print edition centres a grid inside its text
   block, but here the prose holds a 35rem measure inside a wider column, so a
   centred table drifts away from the paragraph that introduces it and the
   first column - the one carrying the possible world - stops lining up with
   anything. */
.gr-grid,
.gr-array {
  margin-left: 0;
  margin-right: auto;
  font-size: var(--step--1);
  line-height: 1.4;
  --gr-rule-colour: var(--c-rule-firm);
}

.gr-caption {
  margin-top: 0.7rem;
  text-align: left;
  font-size: var(--step--1);
  color: var(--c-ink-dim);
  line-height: 1.5;
  max-width: var(--measure);
}

/* `Table 6.1`, `Figure 2.1` - ASCII, so Computer Modern again. */
.gr-caption-label,
.figure-number {
  font-family: var(--face-cm);
  font-weight: 700;
  color: var(--c-accent);
  margin-right: 0.2em;
}

/* \cellcolor{green} and \cellcolor{yellow}, 22 cells each, in the two tables
   of section 8.7. Raw green on a dark ground is unreadable and raw yellow
   burns, so both become tints that sit under the text without changing it -
   the print edition colours the cell, not the digit. */
.gr-bg-green {
  background: var(--c-tint-green);
  color: inherit;
}

.gr-bg-yellow {
  background: var(--c-tint-amber);
  color: inherit;
}

.gr-brace-mark {
  color: var(--c-ink-dim);
}

/* The three arrow diagrams are cropped out of the rebuilt PDF as SVG by
   thesis/diagrams.py, which writes its own prefers-color-scheme rule into
   each file. Nothing here may repaint them. */
.figure {
  margin: 1.9rem 0;
  scroll-margin-top: calc(var(--masthead-h) + 1rem);
  text-align: center;
}

.figure svg,
.figure img {
  /* These are cut out of the PDF at print size, so figure 4.1 arrives 429px
     wide and sat as a stamp in the middle of the column. They are vector, so
     scaling up costs nothing and loses nothing; the cap keeps a small diagram
     from stretching to absurdity on a wide screen. */
  width: 100%;
  max-width: 100%;
  height: auto;
}

.figure figcaption,
figure > figcaption {
  margin-top: 0.7rem;
  text-align: left;
  font-size: var(--step--1);
  color: var(--c-ink-dim);
  max-width: var(--measure);
}

/* --------------------------------------------------------------------------
   9. Mathematics
   -------------------------------------------------------------------------- */

/* KaTeX's own 1.21em is calibrated against a 10pt sans body. Against a book
   serif at 17px it reads a size too large, and inline maths is in nearly
   every sentence here. */
.katex {
  font-size: 1.09em;
}

.katex-display {
  /* A display formula wider than the column scrolls in its own box, like the
     grids; 360px is narrower than several of them. */
  overflow-x: auto;
  overflow-y: hidden;
  padding: 0.35rem 0;
  margin: 1.4rem 0;
  /* KaTeX's own stylesheet centres both the box and the formula inside it.
     Both have to be undone, or the formula recentres itself inside the box. */
  text-align: left;
}

.katex-display > .katex {
  white-space: nowrap;
  text-align: left;
}

/* --------------------------------------------------------------------------
   10. Entry lists - glossary, acronyms, index, bibliography, back matter
   -------------------------------------------------------------------------- */

.entries {
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: var(--measure);
}

.entry {
  display: grid;
  grid-template-columns: minmax(6.5rem, auto) minmax(0, 1fr);
  gap: 0.2rem 1.1rem;
  padding: 0.65rem 0;
  border-top: 1px solid var(--c-rule);
}

.entry__term {
  font-weight: 700;
  color: var(--c-ink-strong);
}

.entry__body {
  margin: 0;
  color: var(--c-ink);
}

.entry__pages,
.entry__where {
  grid-column: 2;
  margin: 0.15rem 0 0;
  font-family: var(--face-cm);
  font-size: var(--step--1);
  color: var(--c-ink-dim);
}

.entry--sub {
  padding-left: 1.4rem;
  border-top: 0;
  padding-top: 0.1rem;
}

/* The six back-matter lists and the reference list: number, title, where. */
.listing {
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: var(--content-max);
}

.listing li {
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr);
  gap: 0.9rem;
  padding: 0.5rem 0;
  border-top: 1px solid var(--c-rule);
}

.listing__num {
  font-family: var(--face-cm);
  color: var(--c-accent);
  white-space: nowrap;
}

.listing__folio {
  color: var(--c-ink-dim);
  font-family: var(--face-cm);
  font-size: var(--step--1);
}

/* Plain runs of links: front matter, back matter, the way out of a page. */
.linklist {
  list-style: none;
  margin: 0 0 2.5rem;
  padding: 0;
  /* The same width as .toc, so the hairlines of the front, chapter and back
     groups on the contents page line up into one column. */
  max-width: var(--content-max);
}

.linklist li {
  border-top: 1px solid var(--c-rule);
}

.linklist a {
  display: block;
  padding: 0.6rem 0;
  border: 0;
}

.linklist a:hover {
  color: var(--c-accent);
}

/* --------------------------------------------------------------------------
   11. Front page
   -------------------------------------------------------------------------- */

.frontpage {
  padding-top: 1.5rem;
}

.frontpage__pretitle {
  font-size: var(--step--1);
  color: var(--c-ink-dim);
  margin: 0 0 1.4rem;
  max-width: var(--measure);
}

/* The one place the thesis's own face carries running words: the title is
   English and ASCII throughout, checked against the 283-glyph font. */
/* The gap under the title is deliberately wide - the author asked for more air
   there twice. A front page is the one page with nothing to scroll for, so the
   title is allowed to stand on its own before the facts begin. */
.frontpage__title {
  font-family: var(--face-cm);
  font-size: clamp(1.8rem, 0.95rem + 3.1vw, 2.75rem);
  font-weight: 700;
  line-height: 1.16;
  letter-spacing: -0.01em;
  max-width: 25ch;
  margin: 0 0 3.6rem;
}

.frontpage__rule {
  width: 5rem;
  height: 2px;
  background: var(--c-accent);
  margin: 0 0 1.6rem;
}

.frontpage__facts {
  display: grid;
  grid-template-columns: minmax(7rem, auto) minmax(0, 1fr);
  gap: 0.5rem 1.4rem;
  margin: 0 0 2.6rem;
  max-width: var(--measure);
  font-size: var(--step--1);
}

.frontpage__facts dt {
  color: var(--c-ink-dim);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-size: var(--step--2);
  padding-top: 0.15rem;
}

.frontpage__facts dd {
  margin: 0;
  color: var(--c-ink);
}

.frontpage__lede {
  max-width: var(--measure);
  margin-bottom: 2.6rem;
}

/* --------------------------------------------------------------------------
   12. Contents
   -------------------------------------------------------------------------- */

.toc {
  list-style: none;
  margin: 0 0 2.5rem;
  padding: 0;
  max-width: var(--content-max);
}

.toc__chapter {
  border-top: 1px solid var(--c-rule);
  padding: 0.85rem 0;
}

.toc__line {
  display: grid;
  grid-template-columns: 2.6rem minmax(0, 1fr) auto;
  gap: 0.9rem;
  align-items: baseline;
}

.toc__num {
  font-family: var(--face-cm);
  font-size: var(--step-1);
  font-weight: 700;
  color: var(--c-accent);
}

.toc__title {
  font-size: var(--step-1);
  border: 0;
}

.toc__title:hover {
  color: var(--c-accent);
}

.toc__folio {
  font-family: var(--face-cm);
  font-size: var(--step--1);
  color: var(--c-ink-dim);
}

.toc__sections {
  list-style: none;
  margin: 0.5rem 0 0;
  padding: 0;
}

.toc__sections li {
  display: grid;
  grid-template-columns: 2.6rem minmax(0, 1fr) auto;
  gap: 0.9rem;
  align-items: baseline;
  padding: 0.16rem 0;
  font-size: var(--step--1);
}

.toc__sections .toc__num {
  font-size: var(--step--1);
  font-weight: 400;
  color: var(--c-ink-dim);
}

.toc__sections a {
  border: 0;
  color: var(--c-ink);
}

.toc__sections a:hover {
  color: var(--c-accent);
}

/* --------------------------------------------------------------------------
   13. Front-matter prose - declaration, epigraph, dedication
   -------------------------------------------------------------------------- */

.epigraph,
.dedication {
  max-width: var(--measure);
  margin: 0 0 2.2rem auto;
  text-align: right;
  font-style: italic;
  color: var(--c-ink-dim);
}

.epigraph cite {
  display: block;
  font-style: normal;
  font-size: var(--step--1);
  margin-top: 0.4rem;
}

/* The German declaration inside an English document. The language attribute
   is what makes hyphenation and a screen reader behave; the box says it is a
   form, not an argument. */
.declaration {
  max-width: var(--measure);
  border-top: 1px solid var(--c-rule);
  border-bottom: 1px solid var(--c-rule);
  padding: 1.4rem 0;
}

.declaration__fields {
  display: grid;
  grid-template-columns: minmax(7rem, auto) minmax(0, 1fr);
  gap: 0.4rem 1.2rem;
  margin: 0 0 1.6rem;
  font-size: var(--step--1);
}

.declaration__fields dt {
  color: var(--c-ink-dim);
}

.declaration__fields dd {
  margin: 0;
}

.declaration__subject {
  font-weight: 700;
  text-align: center;
  margin: 1.2rem 0;
}

.signature {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  margin-top: 2rem;
  font-size: var(--step--1);
  color: var(--c-ink-dim);
}

.signature span {
  border-bottom: 1px solid var(--c-rule-firm);
  min-width: 9rem;
  padding-bottom: 0.2rem;
}

/* --------------------------------------------------------------------------
   14. Page foot
   -------------------------------------------------------------------------- */

.pagenav {
  display: flex;
  gap: 1rem;
  justify-content: space-between;
  margin-top: 4rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--c-rule);
}

.pagenav a {
  border: 0;
  max-width: 48%;
}

.pagenav__dir {
  display: block;
  font-size: var(--step--2);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--c-ink-dim);
  margin-bottom: 0.2rem;
}

.pagenav__title {
  color: var(--c-ink);
  border-bottom: 1px solid var(--c-underline);
}

.pagenav a:hover .pagenav__title {
  color: var(--c-accent);
  border-bottom-color: var(--c-accent);
}

.pagenav--next {
  margin-left: auto;
  text-align: right;
}

.colophon {
  max-width: 82rem;
  margin: 0 auto;
  padding: 2rem var(--gutter) 3rem;
  border-top: 1px solid var(--c-rule);
  font-size: var(--step--2);
  color: var(--c-ink-dim);
}

.colophon p {
  margin: 0 0 0.4rem;
  max-width: var(--measure);
}

/* --------------------------------------------------------------------------
   15. Narrow screens
   -------------------------------------------------------------------------- */

@media (max-width: 68rem) {
  /* The contents folds away into its own page rather than a drawer: a drawer
     is a state without an address and needs script to open. The masthead
     link and the per-chapter list below carry the same information. */
  .sidebar {
    display: none;
  }

  .shell {
    grid-template-columns: minmax(0, 1fr);
  }

  .inchapter {
    display: block;
  }
}

@media (max-width: 34rem) {
  :root {
    --gutter: 1.1rem;
    --step-0: 1rem;
    --measure: 100%;
  }

  body {
    line-height: 1.68;
  }

  main {
    padding-top: 1.75rem;
  }

  .opener__head {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.55rem;
  }

  /* Stacked, the divider turns from the bar of `2 | Background` into the
     rule underneath the number. Same device, rotated. */
  .opener__rule {
    align-self: flex-start;
    width: 3.2rem;
    min-height: 0;
    height: 2px;
  }

  .opener__number {
    line-height: 1;
  }

  .entry {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.15rem;
  }

  .entry__pages,
  .entry__where {
    grid-column: 1;
  }

  .listing li {
    grid-template-columns: 3.6rem minmax(0, 1fr);
    gap: 0.6rem;
  }

  .toc__line,
  .toc__sections li {
    grid-template-columns: 2.2rem minmax(0, 1fr) auto;
    gap: 0.55rem;
  }

  .frontpage__facts,
  .declaration__fields {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.1rem 0;
  }

  .frontpage__facts dd,
  .declaration__fields dd {
    margin-bottom: 0.7rem;
  }

  .thm-proposition,
  .thm-assumption,
  .thm-definition,
  .thm-example,
  .thm-proof {
    padding-left: 0.85rem;
  }

  .epigraph,
  .dedication {
    text-align: left;
  }

  /* A truth table at 360px is a scroll box and nothing else; the tint and the
     hairlines have to do the work the width used to do. */
  .gr-grid,
  .gr-array {
    font-size: var(--step--2);
  }

  .gr-grid td,
  .gr-array td {
    padding: 0.24rem 0.42rem;
  }
}

/* --------------------------------------------------------------------------
   16. Print
   -------------------------------------------------------------------------- */

@media print {
  .masthead,
  .sidebar,
  .pagenav,
  .inchapter,
  .skip {
    display: none;
  }

  body {
    background: #fff;
    color: #000;
  }

  .shell,
  main {
    display: block;
    max-width: none;
    padding: 0;
  }

  a {
    border: 0;
  }

  .thm-proposition,
  .thm-assumption {
    border-left: 2px solid #000;
  }
}

/* Shown only by a build that ran without a green acceptance gate, so that a
   staged deploy never pretends to be the finished edition. It removes itself:
   once the gate passes, the build stops asking for it. */
.unfinished {
  margin: 0;
  padding: 0.7rem 1.1rem;
  background: var(--c-bg-lift);
  border-bottom: 2px solid #b8863b;
  color: var(--c-ink-dim);
  font-size: var(--step--1);
  line-height: 1.45;
  text-align: center;
}

/* --------------------------------------------------------------------------
   12. Reader preferences
   --------------------------------------------------------------------------
   The control prefs.js builds: one small button in the masthead that opens a
   menu of four entries. It exists only when scripts run, so nothing here may
   reserve space or draw a border of its own - an empty container must be
   invisible. Four buttons standing open used to crowd the masthead enough
   that the width pair had to be hidden on a phone; behind one icon all four
   fit at 360. */

.masthead__prefs:empty {
  display: none;
}

.prefs {
  position: relative;
  display: flex;
  align-items: center;
}

.prefs__toggle {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.1rem;
  height: 1.9rem;
  padding: 0;
  border: 1px solid var(--c-rule-firm);
  border-radius: 0.3rem;
  background: transparent;
  color: var(--c-ink-dim);
  cursor: pointer;
}

.prefs__toggle svg {
  display: block;
  width: 1.15rem;
  height: 1.15rem;
}

.prefs__toggle:hover,
.prefs__toggle[aria-expanded="true"] {
  background: var(--c-bg-lift);
  color: var(--c-ink-strong);
}

.prefs__toggle:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 2px;
}

.prefs__menu {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  min-width: 9rem;
  padding: 0.25rem;
  background: var(--c-bg-lift);
  border: 1px solid var(--c-rule-firm);
  border-radius: 0.4rem;
  box-shadow: 0 0.6rem 1.4rem var(--c-shadow);
}

/* `display: flex` above would otherwise beat the hidden attribute, and the
   menu would stand open on every page for a reader who never opened it. */
.prefs__menu[hidden] {
  display: none;
}

.prefs__item {
  appearance: none;
  border: 0;
  border-radius: 0.25rem;
  background: transparent;
  color: var(--c-ink);
  font: inherit;
  font-size: var(--step--1);
  line-height: 1;
  text-align: left;
  padding: 0.5rem 0.6rem;
  min-height: 2.2rem;
  cursor: pointer;
}

.prefs__item:hover:not(:disabled) {
  background: var(--c-bg);
  color: var(--c-ink-strong);
}

.prefs__item:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: -2px;
}

.prefs__item:disabled {
  opacity: 0.35;
  cursor: default;
}
