/* ------------------------------------------------------------------ *
   The Book — chronological reader
   Light is a leaf of vellum on a table; dark is the same room unlit.
   Both are defined as complete palettes so neither depends on the other.
 * ------------------------------------------------------------------ */

/* A control filled with the accent takes the *ground* colour for its type,
   never a literal white. The accent is a deep purple in light and a pale
   pink in dark, so white on it measures 10.5:1 in one theme and 2.3:1 in
   the other -- and 1.7:1 on the hover accent, which is a button whose label
   has effectively gone. It was written correctly once, on the player's play
   button, with a comment saying why, and five other rules went on using
   #fff: the skip link, the contents toggle, an open verse menu, a pressed
   chip, and the primary chip that carries "Open in Google Maps".
   tests/python/test_palette.py now reads the literals out of this file and
   measures them, which is the check that should have caught it. */

/* Two accents, and the difference between them is the whole system.

   RUBRIC is the red a scribe changed pens for. In a manuscript it marks
   the structure of the text and nothing else — the chapter number, the
   verse number, the heading, the initial — which is where the word
   rubric comes from, and it does exactly that job here.

   TYRIAN is the site's own machinery: a link, a focus ring, the control
   you just pressed. It is the argaman of Exodus 26 and the trade of
   Lydia in Acts 16, the dye of the coast these texts were written on.

   So a red mark on this site is the book speaking and a purple one is
   the reader speaking, and neither is ever used for the other's work.
   The rule is easy to state and was quietly broken in three places — a
   thread card ruled in rubric, a callout ruled in rubric, the player's
   own progress bar drawn in rubric — none of which is the structure of
   a text. They are the site's furniture, and they are purple now.

   GILT is the third material and the one held back: gold leaf, which a
   scribe put on neither the text nor the rubric but on the border of the
   leaf. It rules the editorial callouts — the volume's own asides, which
   are neither scripture nor a control — and it does nothing else. It sat
   in this file defined and used nowhere at all.

   Everything else follows from materials: unbleached parchment for the
   ground, a brighter leaf raised off it, and iron-gall ink — which
   oxidises violet-black rather than grey — for type. Dark inverts the
   two, which is what a photographic negative of a manuscript looks
   like: the leaf goes to the colour of the ink and the ink to the
   colour of the leaf.

   No font, image or texture is fetched. The site ships no dependencies
   and its single-file build has to open from file:// with the network
   off, so the grain of the paper is a gradient and the type is whatever
   the device already has. */

:root {
  --paper:      #eee7d9;
  --paper-2:    #e4dbc9;
  --raised:     #fcf9f2;
  --ink:        #1d1822;
  --ink-soft:   #554d5c;
  /* Measured rather than eyeballed. This was #837a89, which is 3.34:1 on
     the page and 2.99:1 on the row a table highlights under the pointer --
     under WCAG AA for body text at every size this palette uses it at, and
     under the 3:1 floor for anything at all on that last ground. It carries
     .muted, .tiny, the crumbs, the table heads, every count and every date,
     which is to say most of the small type on the site. */
  --ink-faint:  #655e6a;
  --rule:       #d4cab8;
  --rule-soft:  #e3dac9;
  --accent:     #632a55;
  --accent-2:   #83406f;
  --accent-bg:  #efe3ec;
  --rubric:     #9b2f21;
  --rubric-2:   #b8503f;
  --gilt:       #906b23;
  --good:       #2f6b5f;
  --good-bg:    #dfeae6;
  --warn:       #8a5a12;
  --warn-bg:    #f2e7cf;
  --fix:        #33587e;
  --fix-bg:     #e0e7f0;
  --mark:       #f4dd9c;

  /* The gutter of a bound leaf, and the grain across it. Both are drawn
     rather than photographed, and both are nearly invisible on purpose:
     texture a reader notices is texture in the way. */
  --spine:      rgba(74, 55, 30, .17);
  --grain:      rgba(74, 55, 30, .022);
  --wash-1:     rgba(255, 253, 246, .75);
  --wash-2:     rgba(99, 42, 85, .045);

  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua",
           Georgia, "Times New Roman", serif;
  --sans:  ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
           "Helvetica Neue", Arial, sans-serif;
  --mono:  ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --shadow: 0 1px 2px rgba(58, 44, 24, .07), 0 10px 30px rgba(58, 44, 24, .09);
  --radius: 10px;
  --measure: 34rem;
  /* The leaf the reader is set on, and the width every control above it
     lines up with. One number, so they cannot drift apart. */
  --leaf: calc(var(--measure) + 5rem);
  --reader-size: 1.075rem;

  /* One vertical rhythm, so the page has a beat rather than a hundred
     hand-picked margins. Named for what they separate rather than for how
     big they are: the sizes may change, the relationships may not. */
  --gap-hair:  .3rem;    /* parts of one thing */
  --gap-tight: .6rem;    /* a label and its value */
  --gap:       1.1rem;   /* one block from the next */
  --gap-wide:  1.9rem;   /* one group of blocks from the next */
  --gap-part:  3rem;     /* one part of the page from the next */

  /* Native widgets -- select dropdowns, scrollbars -- are drawn by the
     browser itself, and follow this rather than the palette above. */
  color-scheme: light;
}

/* The unlit room. Kept as one block and applied twice, because the theme
   can be chosen as well as inherited and neither route may be the poor
   relation of the other. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper:     #14121a;
    --paper-2:   #1c1925;
    --raised:    #211d2b;
    --ink:       #ece3d3;
    --ink-soft:  #aea5b1;
    --ink-faint: #8b8393;
    --rule:      #383140;
    --rule-soft: #2b2535;
    --accent:    #d29ac1;
    --accent-2:  #e7b8d5;
    --accent-bg: #2d2231;
    --rubric:    #e2836b;
    --rubric-2:  #f0a893;
    --gilt:      #d9b46b;
    --good:      #78c0b0;
    --good-bg:   #162623;
    --warn:      #d9b269;
    --warn-bg:   #262015;
    --fix:       #8ab3d8;
    --fix-bg:    #182231;
    --mark:      #5a4520;
    --spine:     rgba(0, 0, 0, .55);
    --grain:     rgba(255, 250, 235, .014);
    --wash-1:    rgba(60, 52, 78, .40);
    --wash-2:    rgba(210, 154, 193, .05);
    --shadow: 0 1px 2px rgba(0, 0, 0, .45), 0 12px 34px rgba(0, 0, 0, .40);
    color-scheme: dark;
  }
}

:root[data-theme="light"] { color-scheme: light; }

:root[data-theme="dark"] {
  --paper:     #14121a;
  --paper-2:   #1c1925;
  --raised:    #211d2b;
  --ink:       #ece3d3;
  --ink-soft:  #aea5b1;
  --ink-faint: #8b8393;
  --rule:      #383140;
  --rule-soft: #2b2535;
  --accent:    #d29ac1;
  --accent-2:  #e7b8d5;
  --accent-bg: #2d2231;
  --rubric:    #e2836b;
  --rubric-2:  #f0a893;
  --gilt:      #d9b46b;
  --good:      #78c0b0;
  --good-bg:   #162623;
  --warn:      #d9b269;
  --warn-bg:   #262015;
  --fix:       #8ab3d8;
  --fix-bg:    #182231;
  --mark:      #5a4520;
  --spine:     rgba(0, 0, 0, .55);
  --grain:     rgba(255, 250, 235, .014);
  --wash-1:    rgba(60, 52, 78, .40);
  --wash-2:    rgba(210, 154, 193, .05);
  --shadow: 0 1px 2px rgba(0, 0, 0, .45), 0 12px 34px rgba(0, 0, 0, .40);
  color-scheme: dark;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.62;
  -webkit-text-size-adjust: 100%;
}

/* The ground the leaves sit on: two soft washes and the laid lines of a
   sheet of paper, drawn with gradients because nothing here may be
   fetched. Fixed and behind everything, so it does not scroll with the
   text and does not repaint as the page grows. Dropped for a reader who
   has asked for less: it is decoration and nothing depends on it. */
body::before {
  content: "";
  position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background:
    repeating-linear-gradient(0deg, var(--grain) 0 1px, transparent 1px 3px),
    radial-gradient(120% 80% at 8% -15%, var(--wash-1), transparent 62%),
    radial-gradient(90% 65% at 100% 0%, var(--wash-2), transparent 58%),
    var(--paper);
}
@media (prefers-reduced-transparency: reduce) {
  body::before { background: var(--paper); }
}

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--accent-2); }

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

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

/* ---------- top bar ---------- */

.topbar {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: 1rem;
  padding: .55rem clamp(.75rem, 3vw, 1.6rem);
  background: color-mix(in srgb, var(--paper) 86%, transparent);
  backdrop-filter: blur(12px) saturate(1.1);
  border-bottom: 1px solid var(--rule);
  flex-wrap: wrap;
}
/* The head rule a printer sets under a running head: a hairline of the
   book's own red, not another grey line. */
.topbar::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: linear-gradient(90deg,
    var(--rubric) 0, color-mix(in srgb, var(--rubric) 30%, transparent) 38%,
    transparent 72%);
  opacity: .55; pointer-events: none;
}

/* The wordmark. The subtitle is the whole argument of the project in five
   words, so it belongs in the mark rather than buried on the home page. */
.brand {
  display: inline-flex; align-items: center; gap: .5rem;
  color: var(--ink); text-decoration: none; white-space: nowrap;
}
.brand-mark { color: var(--rubric); display: flex; align-items: center; }
.brand:hover .brand-mark { color: var(--rubric-2); }
.brand-text { display: flex; flex-direction: column; line-height: 1.05; }
.brand-name {
  font-family: var(--serif); font-size: 1.16rem; font-weight: 600;
  letter-spacing: .005em;
}
.brand-sub {
  font-size: .62rem; color: var(--ink-faint);
  letter-spacing: .07em; text-transform: uppercase;
}
.brand:hover .brand-name { color: var(--accent); }

/* Visible only to screen readers. */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

.nav { display: flex; gap: .15rem; flex: 1; flex-wrap: wrap; }
.nav a {
  padding: .34rem .68rem; border-radius: 999px;
  color: var(--ink-soft); text-decoration: none;
  font-size: .875rem; white-space: nowrap;
}
.nav a:hover { background: var(--paper-2); color: var(--ink); }
.nav a[aria-current="page"] {
  background: var(--accent-bg); color: var(--accent); font-weight: 600;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 22%, transparent);
}

.tools { display: flex; gap: .3rem; align-items: center; }

button.ghost {
  font: inherit; font-size: .84rem;
  background: transparent; color: var(--ink-soft);
  border: 1px solid var(--rule); border-radius: 999px;
  padding: .3rem .7rem; cursor: pointer;
}
button.ghost:hover { background: var(--paper-2); color: var(--ink); border-color: var(--ink-faint); }

/* ---------- layout ---------- */

main { padding: clamp(1.2rem, 4vw, 2.6rem) clamp(.9rem, 4vw, 2rem) 4rem; }
.wrap { max-width: 60rem; margin: 0 auto; }
.wrap-wide { max-width: 74rem; margin: 0 auto; }

h1, h2, h3, h4 {
  font-family: var(--serif); line-height: 1.18; font-weight: 600;
  text-wrap: balance;
}
h1 {
  font-size: clamp(1.9rem, 5.2vw, 3rem); margin: 0 0 var(--gap-tight);
  letter-spacing: -.018em;
}
h2 {
  font-size: 1.5rem; margin: var(--gap-part) 0 var(--gap-tight);
  letter-spacing: -.008em;
}
h3 { font-size: 1.12rem; margin: var(--gap-wide) 0 var(--gap-hair); }

/* Everything the volume says in its own voice is set in the volume's own
   type. The scripture always was; the prose around it -- the lead
   paragraphs, the notes on a work, the reasoning under a thread, the
   footer -- was in the interface's sans, which meant the codex stopped at
   the edge of the leaf and the rest of the site read like a form. The
   division now is the one a printed book uses: text face for anything
   written to be read, sans for the apparatus that operates it. Labels,
   buttons, table heads, counts and dates stay sans, because they are not
   prose and are read by glance rather than by line. */
.lede,
.era-intro,
.thread-card p,
.stop-why,
.stance .why,
.note-block,
.callout,
.finding p,
.lex-text,
.foot p,
.empty {
  font-family: var(--serif);
}

.lede {
  font-size: 1.16rem; line-height: 1.6; color: var(--ink-soft);
  max-width: 42rem; text-wrap: pretty;
}
.muted { color: var(--ink-faint); font-size: .9rem; }
.tiny  { font-size: .78rem; color: var(--ink-faint); }

.rule {
  border: 0; border-top: 1px solid var(--rule); margin: var(--gap-wide) 0;
}
/* A rule and the heading under it are one gesture: the heading does not
   also need its own three rems of air above it. */
.rule + h2, .rule + .group-head h2 { margin-top: var(--gap-wide); }

/* The canon table's own footnotes: why a book is absent, or which part of
   one is here. Closed by default -- the table is a table first. */
.why { margin-top: .3rem; max-width: 34rem; }
.why > summary { cursor: pointer; color: var(--accent); }
.why p { margin: .35rem 0 0; }

/* ---------- home ---------- */

/* A title page. The rule above the title is the one a printer sets there,
   and the mark on it is the same five rectangles as the tab icon. */
.hero { padding: 1.6rem 0 .5rem; position: relative; }
.hero::before {
  content: "";
  display: block; width: 3.2rem; height: 2px; margin: 0 0 1.3rem;
  background: var(--rubric); opacity: .8;
}
.hero h1 { max-width: 18ch; }
.hero .lede { margin-top: 1rem; }

/* The numbers are a colophon rather than a dashboard: a row of figures
   under a rule, in the book's own type, with nothing boxed. */
.stats {
  display: grid; gap: 0 1.6rem; margin: 2.2rem 0 .5rem;
  grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
  border-top: 1px solid var(--rule);
  padding-top: 1rem;
}
.stat { padding: .35rem 0; }
.stat b {
  display: block; font-family: var(--serif); font-size: 1.75rem;
  font-weight: 600; letter-spacing: -.02em; line-height: 1.1;
  font-variant-numeric: tabular-nums lining-nums;
}
.stat span {
  display: block; margin-top: .15rem;
  font-size: .7rem; color: var(--ink-faint);
  text-transform: uppercase; letter-spacing: .09em;
}

/* The volume's own aside: not scripture, not a control. Gold leaf, which
   is the one material here that was neither. */
/* The day's passage: a real verse, picked by what the reader has been
   searching for. Set as a quotation rather than as a card of furniture,
   because it is scripture and the page has a way of setting scripture. */
.today {
  margin: var(--gap-wide) 0 0;
  padding: var(--gap) 0 0;
  border-top: 1px solid var(--rule);
  max-width: 42rem;
}
.today-eyebrow {
  margin: 0 0 var(--gap-tight); font-family: var(--sans);
  font-size: .72rem; font-weight: 600; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink-faint);
}
.today-text {
  font-family: var(--serif); font-size: 1.22rem; line-height: 1.55;
  margin: 0; padding-left: var(--gap); border-left: 2px solid var(--gilt);
  text-wrap: pretty;
}
.today-foot {
  display: flex; align-items: baseline; gap: var(--gap); flex-wrap: wrap;
  margin: var(--gap-tight) 0 0; padding-left: calc(var(--gap) + 2px);
}
.today-ref { font-family: var(--sans); font-size: .82rem; }
.today-forget {
  font: inherit; font-family: var(--sans); font-size: .74rem;
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--ink-faint); text-decoration: underline;
  text-underline-offset: 2px; margin-left: auto;
}
.today-forget:hover { color: var(--ink); }

.callout {
  border-left: 2px solid var(--gilt);
  background: var(--paper-2);
  padding: var(--gap) calc(var(--gap) + .1rem);
  border-radius: 0 var(--radius) var(--radius) 0;
  margin: var(--gap-wide) 0; font-size: 1rem; line-height: 1.6;
  max-width: 46rem;
}
.callout p { margin: .35rem 0; }
.callout p:first-child { margin-top: 0; }
.callout p:last-child { margin-bottom: 0; }

/* ---------- timeline ---------- */

.timeline { position: relative; margin: 2rem 0 0; padding-left: 1.6rem; }
.timeline::before {
  content: ""; position: absolute; left: .34rem; top: .6rem; bottom: .6rem;
  width: 2px; background: linear-gradient(var(--rule), var(--rule-soft));
}

.era { position: relative; margin: 0 0 .5rem; }
.era::before {
  content: ""; position: absolute; left: -1.6rem; top: 1.15rem;
  width: .72rem; height: .72rem; border-radius: 50%;
  background: var(--paper); border: 2px solid var(--accent);
}
.era[data-collection="1"]::before { border-color: var(--ink-faint); }

.era-head {
  width: 100%; text-align: left; cursor: pointer;
  background: transparent; border: 0; border-radius: var(--radius);
  padding: .75rem .8rem; font: inherit; color: inherit;
  display: flex; align-items: baseline; gap: .7rem; flex-wrap: wrap;
}
.era-head:hover { background: var(--paper-2); }
/* A section numeral is the structure of the volume, which is rubric's one
   job. Declared once: this was two blocks, the second overriding the accent
   the first had just set. */
.era-num {
  font-family: var(--mono); font-size: .72rem;
  color: var(--rubric);
  border: 1px solid color-mix(in srgb, var(--rubric) 35%, transparent);
  border-radius: 4px; padding: .05rem .3rem; letter-spacing: .04em;
}
.era[data-collection="1"] .era-num { color: var(--ink-faint); border-color: var(--rule); }
.era-name { font-family: var(--serif); font-size: 1.14rem; font-weight: 600; }
.era-date { color: var(--ink-faint); font-size: .84rem; font-variant-numeric: tabular-nums; }
.era-count { margin-left: auto; color: var(--ink-faint); font-size: .78rem; }

.era-body { padding: 0 .8rem 1.1rem 1.5rem; display: none; }
.era[open] .era-body, .era.open .era-body { display: block; }
.era-intro { font-size: .93rem; color: var(--ink-soft); max-width: 46rem; margin: 0 0 1rem; }

.works { display: grid; gap: .4rem; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); }
.work {
  display: block; text-decoration: none; color: inherit;
  background: var(--raised); border: 1px solid var(--rule-soft);
  border-radius: 8px; padding: .55rem .7rem;
  transition: border-color .15s, background-color .15s, transform .15s;
}
.work:hover {
  border-color: var(--accent); background: var(--accent-bg);
  transform: translateY(-1px);
}
@media (prefers-reduced-motion: reduce) {
  .work { transition: none; }
  .work:hover { transform: none; }
}
.work-title { font-family: var(--serif); font-size: .97rem; display: block; }
.work-meta { font-size: .74rem; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.work.note-only { background: transparent; border-style: dashed; }
.work.note-only .work-meta { font-style: italic; }

/* ---------- contents ---------- */

.toolbar {
  display: flex; gap: .5rem; align-items: center; flex-wrap: wrap;
  margin: 1.4rem 0;
}
.seg { display: inline-flex; border: 1px solid var(--rule); border-radius: 999px; overflow: hidden; }
.seg button {
  font: inherit; font-size: .82rem; padding: .34rem .85rem;
  background: transparent; color: var(--ink-soft); border: 0; cursor: pointer;
}
.seg button[aria-pressed="true"] { background: var(--accent); color: var(--paper); }

input[type="search"], input[type="text"], select {
  font: inherit; font-size: .92rem; color: var(--ink);
  background: var(--raised); border: 1px solid var(--rule);
  border-radius: 8px; padding: .45rem .7rem;
}
input[type="search"] { width: 100%; }

table.grid { width: 100%; border-collapse: collapse; font-size: .9rem; }
table.grid th, table.grid td {
  text-align: left; padding: .5rem .7rem;
  border-bottom: 1px solid var(--rule-soft);
  vertical-align: baseline;
}
/* A column of figures is read down, so it is aligned down: right, lining,
   and one width per digit. Left-ragged numbers in a table are a column you
   have to read rather than one you can compare. */
table.grid th.num, table.grid td.num {
  text-align: right;
  font-variant-numeric: tabular-nums lining-nums;
  white-space: nowrap;
  /* Shrink to their content and give the slack to the column carrying the
     names, rather than each column taking a fifth of a sixty-rem table and
     leaving a hand's width of nothing between a work and its date. */
  width: 1%;
}
table.grid th:first-child, table.grid td:first-child { width: 1%; white-space: nowrap; }
/* The work is the thing being listed, so it is the thing set in the book's
   own type -- everything beside it is a fact about it and stays sans. */
table.grid td a { font-family: var(--serif); font-size: 1.02em; }
/* The head is not sticky, and cannot be. It was, at top: 3.2rem, to clear
   the bar -- but a wide table is wrapped in .scroller so a phone can push it
   sideways, and a box that scrolls in one axis is a scrollport in both. A
   sticky offset is measured from the scrollport rather than the viewport,
   and sticky pushes an element *down* to its offset even at scroll zero, so
   the head was landing 51px into the table and sitting on top of the first
   row -- The Song of the Sea on the contents, Genesis on the canons: in
   each case the first line of the thing being listed. Nothing in CSS gets
   both, because the wrapper that makes the table scrollable is the same box
   that redefines what the head is sticky to. The row is worth more than the
   head, so the head goes. */
table.grid thead th {
  border-bottom: 1px solid var(--rule); font-size: .78rem;
  text-transform: uppercase; letter-spacing: .05em; color: var(--ink-faint);
  font-weight: 600;
}
table.grid tbody tr:hover { background: var(--paper-2); }
/* The last row's rule is the table's own bottom edge twice over. */
table.grid tbody tr:last-child td { border-bottom: 0; }
.scroller { overflow-x: auto; border-radius: var(--radius); }
/* Focusable so a keyboard can scroll it, which means it also has to show
   that it has the focus. */
.scroller:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.yes { color: var(--good); font-weight: 700; }
.no  { color: var(--ink-faint); }
.part { color: var(--warn); font-weight: 700; }

/* ---------- threads ---------- */

.thread-cards {
  display: grid; gap: .8rem; margin: 1.8rem 0;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
}
/* A card is a way in, which makes it the reader's machinery rather than
   the book's -- so the rule down its edge is purple. It was red, which
   said "this is the structure of a text" about a link. */
.thread-card {
  display: block; text-decoration: none; color: inherit;
  background: var(--raised); border: 1px solid var(--rule-soft);
  border-left: 2px solid var(--accent);
  border-radius: var(--radius); padding: var(--gap) calc(var(--gap) + .1rem);
  box-shadow: var(--shadow);
  transition: border-color .15s, background-color .15s;
}
.thread-card:hover { border-color: var(--accent); background: var(--accent-bg); }
@media (prefers-reduced-motion: reduce) { .thread-card { transition: none; } }
.thread-card h2 {
  margin: 0 0 var(--gap-tight); font-size: 1.2rem; line-height: 1.22;
  text-wrap: balance;
}
.thread-card p {
  margin: 0 0 var(--gap); font-size: .97rem; line-height: 1.55;
  color: var(--ink-soft);
}
.thread-meta {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-faint);
}

/* The spine down the left is the passage of time; each stop hangs off it. */
.thread { list-style: none; margin: 2rem 0 0; padding: 0; position: relative; }
.thread::before {
  content: ""; position: absolute; left: 3.1rem; top: .5rem; bottom: 2rem;
  width: 2px; background: linear-gradient(var(--accent), var(--rule-soft));
}

.stop { display: flex; gap: 1.1rem; margin: 0 0 1.7rem; position: relative; }

.stop-when {
  flex: 0 0 5.4rem; text-align: right; padding-top: .15rem;
  display: flex; flex-direction: column; align-items: flex-end; gap: .1rem;
}
.stop-era {
  font-family: var(--mono); font-size: .74rem; color: var(--accent);
  border: 1px solid var(--accent); border-radius: 4px;
  padding: .05rem .34rem; background: var(--paper);
  position: relative; z-index: 1;
}
.stop-date {
  font-size: .68rem; color: var(--ink-faint);
  font-variant-numeric: tabular-nums; max-width: 5.2rem;
}

.stop-card { flex: 1; min-width: 0; padding-left: .9rem; }
.stop-ref {
  display: inline-block; font-size: .78rem; font-weight: 600;
  text-decoration: none; margin-bottom: .5rem;
  text-transform: uppercase; letter-spacing: .04em;
}
.stop-text {
  font-family: var(--serif); font-size: 1.03rem; line-height: 1.6;
  margin: 0 0 .6rem; padding: 0; color: var(--ink);
}
.stop-vnum {
  font-family: var(--sans); font-size: .62em; font-weight: 600;
  color: var(--accent); vertical-align: .4em; margin-right: .3em;
}
.stop-why { margin: 0; font-size: .875rem; color: var(--ink-soft); }
.stop-aside {
  margin: .6rem 0 0; font-size: .78rem; color: var(--warn);
  background: var(--warn-bg); border-radius: 6px; padding: .5rem .65rem;
}

@media (max-width: 620px) {
  .thread::before { left: 2.2rem; }
  .stop { gap: .7rem; }
  .stop-when { flex-basis: 3.6rem; }
  .stop-date { font-size: .62rem; max-width: 3.6rem; }
  .stop-card { padding-left: .5rem; }
}

/* ---------- reader ---------- */

/* Everything on a reading page is the same column: the leaf sets the
   width and the head, the controls and the pager line up with it, so the
   page reads as one object rather than as a wide header with a page
   floating somewhere under it. */
.reader-head, .pager, .witnesses {
  max-width: var(--leaf); margin-left: auto; margin-right: auto;
}
.reader-head {
  border-bottom: 1px solid var(--rule);
  padding-bottom: var(--gap); margin-bottom: var(--gap);
}
.reader-head h1 { margin-bottom: var(--gap-hair); }
.crumbs { font-size: .8rem; color: var(--ink-faint); margin-bottom: .35rem; }
.crumbs a { color: var(--ink-faint); }

/* The way into the other chapters, and it used to take four rows of the
   screen before a word of scripture -- fifty numbers on Genesis, a hundred
   and fifty on Psalms, above the thing you came to read. It is two rows
   now and scrolls past that, and the reader puts the chapter you are in
   into view, which the old box did not: opening Psalm 119 showed you the
   first sixty numbers and left you to find it.

   Kept as a wall of numbers rather than turned into a menu, because it is
   also how you see how long a book is. */
.chapter-strip {
  /* Positioned so the links inside measure their offsetTop against this box
     rather than against the page: the reader scrolls the current chapter
     into view by that number, and against the page it is the distance from
     the top of the document, which puts the strip at its end every time. */
  position: relative;
  display: flex; gap: .3rem; flex-wrap: wrap;
  margin: var(--gap-tight) 0 0;
  max-height: 4.6rem; overflow-y: auto;
  padding: .15rem .15rem var(--gap-hair);
  scrollbar-width: thin;
  overscroll-behavior: contain;
  /* The half-row showing under the second is the whole point -- it says
     there are more -- but cut flat it reads as a clipping mistake. Faded,
     it reads as a page continuing. Purely decorative: a browser without
     mask-image gets the flat cut and loses nothing it needs. */
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 1.1rem), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 1.1rem), transparent);
}
/* Not while it is being used: a keyboard tabbing through the numbers would
   be tabbing into the faded part and appear to lose the focus ring. */
.chapter-strip:focus-within {
  -webkit-mask-image: none; mask-image: none;
}
.chapter-strip a {
  min-width: 2rem; text-align: center; padding: .18rem .4rem;
  border: 1px solid var(--rule-soft); border-radius: 6px;
  font-size: .8rem; line-height: 1.35; text-decoration: none;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums lining-nums;
}
.chapter-strip a:hover { border-color: var(--accent); color: var(--accent); }
.chapter-strip a[aria-current="true"] {
  background: var(--accent); color: var(--paper); border-color: var(--accent);
  font-weight: 600;
}

/* The text is set on a leaf rather than on the page's own ground: a
   brighter surface, a hairline, and a gutter shadow down the bound edge.
   That is the mark of this volume drawn at full size -- a spine and the
   leaves hanging off it -- and it is what tells the eye where the book
   stops and the apparatus around it starts.

   The measure is unchanged. The leaf is the measure plus its margins,
   which is why every control above it is sized from the same token. */
.reader {
  position: relative;
  /* The leaf is read and selected from, not clicked. Declared here rather
     than three hundred lines further down, where it was a second .reader
     block on its own. */
  cursor: text;
  font-family: var(--serif);
  font-size: var(--reader-size);
  line-height: 1.75;
  max-width: var(--leaf);
  margin: 0 auto;
  padding: clamp(1.3rem, 4vw, 2.5rem) clamp(1rem, 4vw, 2.5rem);
  background: var(--raised);
  border: 1px solid var(--rule-soft);
  border-radius: 2px var(--radius) var(--radius) 2px;
  /* Two leaves under this one, drawn as offset hairlines rather than as
     an image, so the chapter reads as a page in a book with more of the
     book behind it. */
  box-shadow:
    3px 3px 0 -1px var(--raised), 3px 3px 0 0 var(--rule-soft),
    6px 6px 0 -1px var(--raised), 6px 6px 0 0 var(--rule-soft),
    var(--shadow);
  hanging-punctuation: first;
  text-wrap: pretty;
  margin-top: .9rem;
}
.reader::before {
  content: "";
  position: absolute; left: 0; top: 0; bottom: 0; width: 9px;
  border-radius: 2px 0 0 2px;
  background: linear-gradient(90deg, var(--spine), transparent);
  pointer-events: none;
}
/* Set out this way the verse is a line, and a line's number belongs in
   the margin beside it rather than in front of it. */
.reader.verse-per-line .v {
  display: block; margin: 0 0 .5rem;
  padding-left: 2.1rem; text-indent: -2.1rem;
}
.reader.verse-per-line .vnum {
  display: inline-block; min-width: 1.7rem; text-align: right;
  margin-right: .4rem; vertical-align: baseline; font-size: .74em;
}
.reader .v { transition: background-color .25s; }
.reader .v.target { background: var(--mark); border-radius: 3px; }
.reader p { margin: 0 0 1.05rem; }

/* The verse number is a button now, but must still read as a superscript
   numeral inside flowing text rather than as a control. */
.vnum {
  font-family: var(--sans); font-size: .66em; font-weight: 700;
  color: var(--rubric); vertical-align: .38em;
  margin-right: .24em; font-variant-numeric: tabular-nums lining-nums;
  background: none; border: 0; padding: 0 .1em; cursor: pointer;
  line-height: 1;
}
.vnum:hover { color: var(--rubric-2); text-decoration: underline; }
/* Opened, it is a control rather than a numeral, so it changes colour
   as well as ground: purple is the site talking. */
.vnum[aria-expanded="true"] {
  background: var(--accent); color: var(--paper); border-radius: 3px;
}

/* A saved verse keeps a quiet marker in the margin of the text. */
.v.is-saved {
  background: linear-gradient(transparent 60%, var(--mark) 60%);
  border-radius: 2px;
}

.vmenu {
  position: absolute; z-index: 50;
  margin-top: .3rem;
  display: flex; flex-direction: column;
  background: var(--raised); border: 1px solid var(--rule);
  border-radius: var(--radius); box-shadow: var(--shadow);
  min-width: 15rem; padding: .25rem;
  font-family: var(--sans);
}
.vmenu button {
  font: inherit; font-size: .85rem; text-align: left;
  background: transparent; border: 0; border-radius: 6px;
  padding: .5rem .6rem; cursor: pointer; color: var(--ink);
}
.vmenu button:hover { background: var(--paper-2); }

.v { position: relative; }

/* ---------- saved ---------- */

.saved-row {
  border-bottom: 1px solid var(--rule-soft);
  padding: 1rem 0;
  display: flex; flex-direction: column; align-items: flex-start; gap: .5rem;
}
.saved-text {
  font-family: var(--serif); font-size: 1rem; line-height: 1.62;
  margin: 0; padding-left: .9rem;
  border-left: 3px solid var(--accent-bg);
  color: var(--ink);
}
.saved-note {
  font: inherit; font-size: .87rem; width: 100%;
  background: var(--paper-2); color: var(--ink);
  border: 1px solid var(--rule-soft); border-radius: 8px;
  padding: .45rem .6rem; resize: vertical;
}
.saved-note::placeholder { color: var(--ink-faint); }

.pager {
  display: flex; justify-content: space-between; gap: 1rem;
  margin: 2.6rem auto 0; max-width: var(--measure); align-items: center;
}
.pager a {
  text-decoration: none; font-size: .88rem; padding: .45rem .8rem;
  border: 1px solid var(--rule); border-radius: 8px; color: var(--ink-soft);
  max-width: 45%;
}
.pager a:hover { border-color: var(--accent); color: var(--accent); }
.pager .spacer { flex: 1; }

/* The editor's note on the work: prose about the book, so it is set in the
   book's type. It was in the interface's sans, which put a sentence of
   commentary in the same voice as the buttons under it. */
.note-block {
  font-family: var(--serif); font-size: 1rem; line-height: 1.6;
  color: var(--ink-soft);
  background: transparent; border-left: 2px solid var(--rule);
  border-radius: 0;
  padding: .2rem 0 .2rem var(--gap); margin: 0 auto var(--gap-wide);
  max-width: var(--leaf);
}

.reader-controls {
  display: flex; gap: .4rem; align-items: center; justify-content: flex-end;
  flex-wrap: wrap; margin: .9rem auto 0; max-width: var(--leaf);
}
/* The chapter's own heading, in the red a scribe would have changed pens
   for, with the hairline that separates it from the leaf above. */
.chapter-title {
  margin: 0 0 1.2rem;
  color: var(--rubric);
  letter-spacing: .16em; text-transform: uppercase; font-size: .72rem;
  font-family: var(--sans); font-weight: 700;
  padding-bottom: .5rem; border-bottom: 1px solid var(--rule-soft);
}
.note-block p { margin: .4rem 0; }
.note-block p:first-child { margin-top: 0; }
.note-block p:last-child { margin-bottom: 0; }

/* ---------- who wrote this, and when ----------
   Two columns, deliberately identical in weight. Neither tradition is
   styled as the default reading; the reader compares and decides. */

.positions { margin: 0 auto 1.6rem; max-width: var(--leaf); }

.positions-head {
  width: 100%; text-align: left; cursor: pointer; font: inherit; color: inherit;
  background: transparent; border: 1px solid var(--rule); border-radius: var(--radius);
  padding: .6rem .85rem; display: flex; align-items: center; gap: .6rem;
  font-size: .9rem;
}
.positions-head:hover { background: var(--paper-2); }
.positions-head .caret { color: var(--ink-faint); font-size: .75rem; margin-left: auto; }

.gap-tag {
  font-size: .68rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .05em; padding: .1rem .45rem; border-radius: 4px;
}
.gap-tag.none   { background: var(--good-bg); color: var(--good); }
.gap-tag.narrow { background: var(--fix-bg);  color: var(--fix); }
.gap-tag.wide   { background: var(--warn-bg); color: var(--warn); }

.positions-body {
  display: none; flex-direction: column; gap: .7rem; margin-top: .6rem;
}
.positions.open .positions-body { display: flex; }

/* The two views sit side by side where there is room and stack where there
   is not; the date card above them always runs the full width, because the
   whole point of it is the distance between the two. */
.stances {
  display: grid; gap: .7rem;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

/* ---------- the date card ----------
   Two spans on one scale. Reading it should take about a second: if the bars
   overlap the positions agree about the date, and if they do not, the gap on
   the page is the gap in the scholarship. */
.datecard {
  background: var(--raised); border: 1px solid var(--rule-soft);
  border-radius: var(--radius); padding: .8rem .9rem;
}

.datescale { display: flex; flex-direction: column; gap: .45rem; }

.daterow { display: grid; align-items: center; gap: .5rem;
           grid-template-columns: 5.5rem 1fr 8.5rem; }

.datelabel {
  font-family: var(--sans); font-size: .68rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em; color: var(--ink-faint);
}

.datetrack {
  position: relative; height: 1.15rem; border-radius: 3px;
  background: var(--paper-2); overflow: hidden;
}

.datebar {
  position: absolute; top: 0; bottom: 0; border-radius: 3px; min-width: 3px;
}
.daterow.trad .datebar { background: var(--warn); }
.daterow.crit .datebar { background: var(--fix); }

/* A span read from a century or a named period is a looser claim than one
   read from a year, and is drawn as one rather than pretending to an
   exactness the position never had. */
.datebar.century,
.datebar.period,
.datebar.decade { opacity: .62; }
.datebar.period {
  background-image: repeating-linear-gradient(
    45deg, transparent 0 4px, rgba(255, 255, 255, .35) 4px 8px);
}

.dateunknown {
  position: absolute; inset: 0; display: flex; align-items: center;
  padding-left: .4rem; font-size: .7rem; color: var(--ink-faint);
  font-style: italic;
}

.datespan {
  font-family: var(--sans); font-size: .74rem; color: var(--ink-soft);
  text-align: right; font-variant-numeric: tabular-nums;
}

.dateverdict {
  margin: .6rem 0 0; font-size: .84rem; color: var(--ink-soft);
}

.datecite {
  margin: .45rem 0 0; padding-top: .45rem;
  border-top: 1px solid var(--rule-soft);
  font-size: .74rem; color: var(--ink-faint);
}
.datecite a { color: inherit; }

/* On a phone the three-column row has nowhere to go, so the figure moves
   under the bar rather than squeezing it to nothing. */
@media (max-width: 30rem) {
  .daterow { grid-template-columns: 5rem 1fr; row-gap: .15rem; }
  .datespan { grid-column: 2; text-align: left; }
}

.stance {
  background: var(--raised); border: 1px solid var(--rule-soft);
  border-radius: var(--radius); padding: .8rem .9rem;
}
.positions-h { margin: 0; font-size: inherit; font-weight: inherit; }

.stance h3 {
  margin: 0 0 .3rem; font-family: var(--sans); font-size: .7rem;
  text-transform: uppercase; letter-spacing: .06em; color: var(--ink-faint);
  font-weight: 700;
}
.stance .claim { font-family: var(--serif); font-size: 1rem; margin: 0 0 .4rem; }
.stance .why { font-size: .84rem; color: var(--ink-soft); margin: 0 0 .5rem; }

/* The citation is the point of the panel: it is what makes an editorial
   claim checkable rather than merely asserted. */
.stance .cite {
  font-size: .76rem; color: var(--ink-faint); margin: 0;
  padding-top: .45rem; border-top: 1px solid var(--rule-soft);
  font-style: italic;
}

.positions-foot {
  font-size: .78rem; color: var(--ink-faint); margin: 0;
}

/* ---------- lexicon panel ----------
   A sheet rather than a tooltip: entries run long and carry links, which a
   hover bubble cannot hold. Side panel on desktop, bottom sheet on a phone,
   where thumbs reach the bottom of the screen and not the right edge. */

.lex {
  position: fixed; z-index: 60;
  background: var(--raised);
  border: 1px solid var(--rule);
  box-shadow: var(--shadow);
  display: flex; flex-direction: column;
  right: 1rem; bottom: 1rem; top: auto;
  width: min(24rem, calc(100vw - 2rem));
  max-height: min(28rem, 70vh);
  border-radius: var(--radius);
  animation: lex-in .16s ease-out;
}

@keyframes lex-in { from { opacity: 0; transform: translateY(.4rem); } }
@media (prefers-reduced-motion: reduce) { .lex { animation: none; } }

.lex-head {
  display: flex; align-items: baseline; gap: .6rem;
  padding: .7rem .9rem .5rem;
  border-bottom: 1px solid var(--rule-soft);
}
.lex-head h2 {
  font-family: var(--serif); font-size: 1.06rem; flex: 1; margin: 0;
}
.lex-close {
  background: transparent; border: 0; cursor: pointer;
  color: var(--ink-faint); font-size: 1rem; padding: .1rem .3rem;
  line-height: 1;
}
.lex-close:hover { color: var(--ink); }

.lex-body { overflow-y: auto; padding: .8rem .9rem 1rem; }
.lex-text { margin: 0 0 .7rem; font-size: .92rem; line-height: 1.6; }
.lex-none { margin: 0; font-size: .9rem; color: var(--ink-soft); }

.lex-flag {
  margin: 0 0 .7rem; font-size: .8rem;
  padding: .5rem .65rem; border-radius: 6px;
  background: var(--warn-bg); color: var(--warn);
  border-left: 3px solid var(--warn);
}
.lex-flag.measure { background: var(--fix-bg); color: var(--fix); border-color: var(--fix); }

.lex-cite {
  margin: 0 0 .8rem; font-size: .76rem; font-style: italic;
  color: var(--ink-faint);
  padding-top: .5rem; border-top: 1px solid var(--rule-soft);
}

@media (max-width: 620px) {
  .lex {
    left: 0; right: 0; bottom: 0; width: auto;
    border-radius: var(--radius) var(--radius) 0 0;
    border-left: 0; border-right: 0; border-bottom: 0;
    max-height: 62vh;
  }
}

/* A quiet hint that the text responds to a tap at all. */

.apparatus {
  font-family: var(--sans); font-size: .8rem; color: var(--ink-faint);
  border-top: 1px solid var(--rule-soft); padding-top: .8rem;
  margin: 2.4rem auto 0; max-width: var(--measure);
}
.apparatus code { font-family: var(--mono); font-size: .95em; background: var(--paper-2); padding: 0 .25em; border-radius: 3px; }

/* ---------- search ---------- */

/* The query and the book it is asked of, on one line, wrapping to two on a
   phone rather than squeezing the field down to nothing. */
.search-bar { display: flex; gap: var(--gap-tight); flex-wrap: wrap; }
.search-bar input[type="search"] { flex: 1 1 16rem; width: auto; }
.search-bar select { flex: 0 1 15rem; max-width: 100%; }

/* A reference is an answer, not a result, so it is set apart from the list
   of verses below rather than being the first row of it. */
.jump-box {
  margin: var(--gap-wide) 0 0; padding: var(--gap) calc(var(--gap) + .1rem);
  background: var(--raised); border: 1px solid var(--rule-soft);
  border-left: 2px solid var(--accent); border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.jump-head {
  margin: 0 0 var(--gap-tight); font-family: var(--sans);
  font-size: .72rem; font-weight: 600; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink-faint);
}
.jump-link {
  display: flex; align-items: baseline; gap: var(--gap-tight);
  flex-wrap: wrap; padding: .35rem 0; text-decoration: none; color: inherit;
  border-top: 1px solid var(--rule-soft);
}
.jump-link:first-of-type { border-top: 0; }
.jump-where {
  font-family: var(--serif); font-size: 1.06rem; color: var(--accent);
  text-decoration: underline; text-underline-offset: 2px;
}
.jump-link:hover .jump-where { color: var(--accent-2); }
.jump-era {
  font-family: var(--sans); font-size: .74rem; color: var(--ink-faint);
  margin-left: auto;
}

.results { margin-top: 1.6rem; }
.result {
  border-bottom: 1px solid var(--rule-soft); padding: .85rem 0;
}
.result-ref {
  display: flex; gap: .5rem; align-items: baseline; flex-wrap: wrap;
  font-size: .8rem; margin-bottom: .2rem;
}
.result-ref a { font-weight: 600; text-decoration: none; }
.result-era { color: var(--ink-faint); }
.result-text { font-family: var(--serif); font-size: 1rem; line-height: 1.62; }
mark { background: var(--mark); color: inherit; padding: 0 .1em; border-radius: 2px; }

.progress { height: 2px; background: var(--rule-soft); border-radius: 2px; overflow: hidden; margin: 1rem 0; }
.progress i { display: block; height: 100%; background: var(--accent); width: 0; transition: width .2s; }

/* ---------- accuracy ---------- */

.finding {
  border: 1px solid var(--rule-soft); border-radius: var(--radius);
  padding: .85rem 1rem; margin: .6rem 0; background: var(--raised);
}
.finding h4 { margin: 0 0 .3rem; font-size: .98rem; }
.finding p { margin: 0; font-size: .9rem; color: var(--ink-soft); }
.badge {
  display: inline-block; font-size: .68rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em;
  padding: .12rem .45rem; border-radius: 4px; margin-right: .5rem;
  vertical-align: .1em;
}
.badge.pass      { background: var(--good-bg); color: var(--good); }
.badge.fixed     { background: var(--fix-bg);  color: var(--fix); }
.badge.corrected { background: var(--warn-bg); color: var(--warn); }
.badge.gap       { background: var(--warn-bg); color: var(--warn); }
.badge.note      { background: var(--paper-2); color: var(--ink-faint); }

.group-head { display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap; }
.group-head h2 { margin-bottom: .2rem; }

/* ---------- misc ---------- */

.loading { color: var(--ink-faint); font-size: .9rem; padding: 2rem 0; }
.empty { color: var(--ink-faint); padding: 2rem 0; font-size: .95rem; }

.chips { display: flex; gap: .35rem; flex-wrap: wrap; margin: .8rem 0; }
.chip {
  font-size: .78rem; padding: .2rem .6rem; border-radius: 999px;
  border: 1px solid var(--rule); color: var(--ink-soft);
  background: var(--raised); cursor: pointer; font-family: inherit;
  text-decoration: none;
}
.chip:hover { border-color: var(--accent); color: var(--accent); }
.chip[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--paper); }

.foot {
  border-top: 1px solid var(--rule); padding: 1.6rem clamp(.9rem, 4vw, 2rem) 3rem;
  font-size: .84rem; color: var(--ink-soft);
}
.foot p { max-width: 52rem; margin: .4rem 0; }

.keys { margin: 1.2rem 0 0; max-width: 52rem; }
.keys summary {
  cursor: pointer; font-size: .84rem; color: var(--ink-soft);
  padding: .3rem 0;
}
.keys summary:hover { color: var(--ink); }
.keys dl {
  display: grid; grid-template-columns: auto 1fr; gap: .4rem .9rem;
  margin: .7rem 0; font-size: .84rem; align-items: baseline;
}
.keys dt { margin: 0; }
.keys dd { margin: 0; color: var(--ink-soft); }
.keys kbd {
  font-family: var(--mono); font-size: .78rem;
  background: var(--paper-2); border: 1px solid var(--rule);
  border-radius: 4px; padding: .1rem .35rem; color: var(--ink);
}

@media (max-width: 620px) {
  /* The nav has to claim lines of its own. `width: 100%` cannot make it: the
     base rule's `flex: 1` sets a basis of 0%, which beats width on a flex
     item, so the nav collapsed into whatever was left beside the brand --
     ninety pixels on a phone -- and crushed all seven links into a sliver at
     the right edge. The basis is the thing that has to change.

     Given its own width it wraps to two rows and every link is visible. A
     link behind a sideways swipe is a feature most people never find out
     about, which is too high a price for one row; the height it costs is
     given back below by tucking the whole bar away as you read. */
  .topbar { gap: .5rem .6rem; padding: .45rem .7rem; }
  .nav {
    flex: 1 0 100%; order: 3;
    gap: .12rem .15rem;
  }
  .nav a { padding: .3rem .58rem; font-size: .84rem; flex: 0 0 auto; }

  /* Reading is what the screen is for. The bar leaves as you go down the
     page and comes back the moment you turn back up, so the two rows of
     links cost nothing while you are actually reading. */
  .topbar { transition: transform .2s ease; }
  .topbar.tucked { transform: translateY(-100%); }


  /* Keep the name, drop only the strapline. A lone icon is not a wordmark. */
  .brand-sub { display: none; }
  .brand-name { font-size: 1.02rem; }
  .tools { margin-left: auto; }
  table.grid thead th { top: 5.6rem; }
}

@media print {
  .topbar, .foot, .pager, .chapter-strip, .toolbar { display: none; }
  body { background: #fff; color: #000; }
  .reader { max-width: none; }
}

/* The threads block on the home page: the argument, before the filing. */
.threads-hero { margin: 2.2rem 0 .5rem; }
.threads-hero h2 { margin: 0 0 .3rem; font-size: 1.34rem; }
.threads-hero .thread-cards { margin-top: 1rem; }
.threads-hero .thread-card h3 {
  margin: 0 0 .45rem; font-family: var(--serif); font-size: 1.1rem;
  font-weight: 600; line-height: 1.25; text-wrap: balance;
}

/* Chapter jump, for books too long to scan as a grid. */
.chapter-jump {
  display: flex; gap: var(--gap-hair); align-items: center;
  margin: var(--gap-tight) 0 0;
}
.chapter-jump input {
  width: 6.5rem; font: inherit; font-size: .85rem;
  background: var(--raised); color: var(--ink);
  border: 1px solid var(--rule); border-radius: 8px; padding: .32rem .55rem;
}
.chapter-jump button { cursor: pointer; }

/* Content arriving should settle rather than snap. */
main > * { animation: rise .18s ease-out; }
@keyframes rise { from { opacity: 0; transform: translateY(.25rem); } }
@media (prefers-reduced-motion: reduce) {
  main > * { animation: none; }
  .topbar { transition: none; }
}

.loading::after {
  content: ""; display: inline-block; width: .5rem; height: .5rem;
  margin-left: .4rem; border-radius: 50%;
  background: var(--accent); animation: pulse 1s ease-in-out infinite;
}
@keyframes pulse { 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) { .loading::after { animation: none; } }

/* ---------- place, in the definition panel ----------
   Colour carries how firm the identification is, so a region never looks
   like a pin and a guess never looks like a survey point. */

.place {
  background: var(--paper-2); border-radius: var(--radius);
  padding: .75rem .85rem; margin: 0 0 .9rem;
  border-left: 3px solid var(--good);
}
.place-approximate { border-left-color: var(--warn); }
.place-region      { border-left-color: var(--fix); }
.place-within      { border-left-color: var(--ink-faint); }

.place-kind {
  display: flex; align-items: center; gap: .4rem;
  font-size: .7rem; text-transform: uppercase; letter-spacing: .06em;
  font-weight: 700; color: var(--good); margin-bottom: .4rem;
}
.place-approximate .place-kind { color: var(--warn); }
.place-region .place-kind      { color: var(--fix); }
.place-within .place-kind      { color: var(--ink-faint); }

.place-dot {
  width: .5rem; height: .5rem; border-radius: 50%;
  background: currentColor; flex: 0 0 auto;
}
.place-region .place-dot { border-radius: 2px; width: .62rem; height: .42rem; }
.place-approximate .place-dot { opacity: .55; }

.place-modern { margin: 0 0 .3rem; font-size: .9rem; font-weight: 600; }
.place-note   { margin: 0 0 .4rem; font-size: .82rem; color: var(--ink-soft); }
.place-coords {
  margin: 0 0 .6rem; font-family: var(--mono); font-size: .74rem;
  color: var(--ink-faint); font-variant-numeric: tabular-nums;
}
.place-links { display: flex; gap: .35rem; flex-wrap: wrap; }
.place-links .chip { text-decoration: none; }
.chip.primary {
  background: var(--accent); border-color: var(--accent); color: var(--paper);
}
.chip.primary:hover { background: var(--accent-2); border-color: var(--accent-2); color: var(--paper); }
.place-cite {
  margin: .6rem 0 0; font-size: .72rem; font-style: italic;
  color: var(--ink-faint);
}

/* ---------- surviving manuscripts ----------
   Links out, never reproductions: these objects are all rights reserved.
   Closed by default so it never competes with the text itself. */

.witnesses {
  margin: 0 auto 1.6rem; max-width: var(--leaf);
  border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--raised);
}
.witnesses summary {
  cursor: pointer; padding: .6rem .85rem; font-size: .88rem;
  color: var(--ink-soft); list-style-position: inside;
}
.witnesses summary:hover { color: var(--ink); }
.witnesses[open] summary {
  border-bottom: 1px solid var(--rule-soft); color: var(--ink);
}

.witness { padding: .85rem; border-bottom: 1px solid var(--rule-soft); }
.witness:last-child { border-bottom: 0; }
.witness h3 {
  margin: 0 0 .25rem; font-size: 1rem;
}
.witness h3 a { text-decoration: none; }
.witness h3 a::after { content: " ↗"; font-size: .7em; opacity: .6; }
.witness-when {
  margin: 0 0 .45rem; font-size: .74rem; color: var(--ink-faint);
  text-transform: uppercase; letter-spacing: .04em;
}
.witness-holds { margin: 0 0 .4rem; font-size: .88rem; }
.witness-why   { margin: 0 0 .5rem; font-size: .85rem; color: var(--ink-soft); }
.witness-rights {
  margin: 0; font-size: .72rem; font-style: italic; color: var(--ink-faint);
}

/* ---------- read aloud ----------
   The passage being spoken is marked twice: the whole verse takes a quiet
   ground so you can find your place after looking away, and the individual
   word takes the highlighter, so following along is possible at speed.
   Word marking uses the Custom Highlight API — where it is missing the
   verse marking alone still carries the position. */

.chapter-title.is-speaking,
.reader .v.is-speaking,
.reader p.is-speaking {
  background: var(--accent-bg);
  border-radius: 3px;
  box-shadow: 0 0 0 .18em var(--accent-bg);
}

::highlight(book-speaking) {
  background: var(--mark);
  color: var(--ink);
}

/* Said out loud where the button is, not only to the live region. */
.listen-note {
  max-width: var(--leaf);
  margin: .5rem auto 0;
  font-family: var(--sans); font-size: .82rem; line-height: 1.5;
  color: var(--warn); background: var(--warn-bg);
  border-radius: var(--radius); padding: .55rem .75rem;
}

.chip[disabled] { opacity: .55; cursor: default; }
.chip[disabled]:hover { border-color: var(--rule); color: var(--ink-soft); }

.player {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  isolation: isolate;
  background: var(--raised); border-top: 1px solid var(--rule);
  box-shadow: var(--shadow);
  font-family: var(--sans);
  padding: .5rem max(.8rem, env(safe-area-inset-left))
           calc(.5rem + env(safe-area-inset-bottom))
           max(.8rem, env(safe-area-inset-right));
  display: flex; flex-direction: column; gap: .4rem;
}
.player[hidden] { display: none; }

.player-line { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }

.player-btn {
  font: inherit; font-size: .95rem; line-height: 1;
  background: transparent; color: var(--ink);
  border: 1px solid var(--rule); border-radius: 999px;
  width: 2.2rem; height: 2.2rem; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  flex: none;
}
.player-btn:hover { border-color: var(--accent); color: var(--accent); }
/* The accent is a deep purple in light and a pale one in dark, so the glyph
   takes the ground colour rather than a fixed white and stays legible in both. */
.player-play {
  background: var(--accent); border-color: var(--accent); color: var(--paper);
  width: 2.6rem; height: 2.6rem; font-size: 1.05rem;
}
.player-play:hover {
  background: var(--accent-2); border-color: var(--accent-2); color: var(--paper);
}
.player-cont[aria-pressed="true"] { background: var(--accent-bg); border-color: var(--accent); color: var(--accent); }

.player-pos {
  display: flex; flex-direction: column; min-width: 0; line-height: 1.25;
  flex: 1;
}
.player-where {
  font-size: .84rem; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.player-unit { font-size: .74rem; color: var(--ink-faint); }

/* How far through the chapter, as a hairline along the top edge — the same
   place a player puts it, and out of the way of the controls. */
.player-bar {
  position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: var(--rule-soft); overflow: hidden;
}
.player-bar i {
  display: block; height: 100%; width: 0;
  background: var(--accent); transition: width .3s linear;
}
@media (prefers-reduced-motion: reduce) { .player-bar i { transition: none; } }

.player-opts select {
  font: inherit; font-size: .78rem; color: var(--ink);
  background: var(--paper-2); border: 1px solid var(--rule-soft);
  border-radius: 8px; padding: .28rem .4rem; max-width: 11rem;
}
.player-opts { justify-content: flex-start; }
.player-close { margin-left: auto; }

/* The voice drawer is grouped by how the voices sound; the headings carry
   that, so they have to read as headings and not as choices. */
.player-opts optgroup { font-style: normal; font-weight: 600; }
.player-opts option { font-weight: 400; }

/* Try-this-voice sits with the drawer it belongs to, and smaller than the
   transport: it is a convenience, not a control. */
.player-try { width: 2rem; height: 2rem; font-size: .85rem; }

/* Only shown when the device has nothing good installed, which is a fact
   about the device and not a failure of the page. It opens rather than
   hovering: the phone that most needs it has no tooltips. */
.player-hint {
  margin: 0; font-size: .72rem; line-height: 1.45; color: var(--ink-faint);
  max-width: 42rem;
}
.player-hint[hidden] { display: none; }
.player-hint > summary { cursor: pointer; }
.player-hint > summary:hover { color: var(--ink); }
.player-hint > p { margin: .4rem 0 0; }
.player-hint > p strong { color: var(--ink-soft); font-weight: 600; }
/* Opened, it is a paragraph or five, and the player is already at the
   bottom of the screen. */
.player-hint[open] { max-height: 40vh; overflow-y: auto; }

/* The player covers the last inch of the page; the reader gets that back.
   Measured rather than assumed, because the player is a different height
   with the hint up, and on a narrow phone where the options wrap. */
body.listening { padding-bottom: calc(var(--player-h, 7.5rem) + 1rem); }

@media (max-width: 620px) {
  .player-opts select { max-width: 7.5rem; }
  .player-where { font-size: .8rem; }
}

@media print { .player { display: none; } }


/* ---------- the timeline ----------
   Every work as a bar on one axis. The length of a bar is the length of the
   claim behind it, which is the thing a list of dates cannot show. */

.tl-axis {
  position: relative; height: 1.4rem; margin: .3rem 0 .2rem;
  border-bottom: 1px solid var(--rule);
}

.tl-tick {
  position: absolute; bottom: .15rem; transform: translateX(-50%);
  font-family: var(--sans); font-size: .66rem; color: var(--ink-faint);
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.tl-tick::after {
  content: ""; position: absolute; left: 50%; bottom: -.35rem;
  width: 1px; height: .3rem; background: var(--rule);
}

.tl-rows { display: flex; flex-direction: column; }

.tl-row {
  display: grid; align-items: center; gap: .5rem; padding: .12rem .25rem;
  grid-template-columns: 13rem 1fr 8rem;
  color: inherit; text-decoration: none; border-radius: 4px;
}
.tl-row:hover, .tl-row:focus-visible { background: var(--paper-2); }

.tl-name {
  font-size: .78rem; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis;
}

.tl-track {
  position: relative; height: .62rem; border-radius: 2px;
  background: var(--rule-soft);
}

.tl-bar {
  position: absolute; top: 0; bottom: 0; border-radius: 2px;
  background: var(--accent); min-width: 2px;
}

/* A span read from a century or a period commits to less than one read from
   a year, and a work placed by its era commits to less still. Both are drawn
   as the looser claims they are rather than being levelled up. */
.tl-bar.century, .tl-bar.period, .tl-bar.decade { opacity: .7; }
.tl-row.placed-section .tl-bar { background: var(--ink-faint); opacity: .45; }

/* An open end runs off the edge instead of stopping at a year nobody stated. */
.tl-bar.open-before {
  border-top-left-radius: 0; border-bottom-left-radius: 0;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 3rem);
  mask-image: linear-gradient(to right, transparent, #000 3rem);
}
.tl-bar.open-after {
  border-top-right-radius: 0; border-bottom-right-radius: 0;
  -webkit-mask-image: linear-gradient(to left, transparent, #000 3rem);
  mask-image: linear-gradient(to left, transparent, #000 3rem);
}

.tl-when {
  font-family: var(--sans); font-size: .68rem; color: var(--ink-faint);
  text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums;
}

.tl-note {
  margin: .9rem 0 0; padding-top: .6rem; border-top: 1px solid var(--rule-soft);
  font-size: .8rem; color: var(--ink-soft);
}
.tl-note a { color: inherit; }

.tl-undated { margin-top: .8rem; font-size: .82rem; }
.tl-undated summary { cursor: pointer; color: var(--ink-soft); }
.tl-undated-list { display: flex; flex-wrap: wrap; gap: .3rem; margin-top: .5rem; }

/* On a phone the title needs the width more than the figure does, so the
   figure goes under the bar. */
@media (max-width: 40rem) {
  .tl-row { grid-template-columns: 8.5rem 1fr; row-gap: .1rem; }
  .tl-when { grid-column: 2; text-align: left; font-size: .64rem; }
  .tl-name { font-size: .72rem; }
}

/* ---------- the chapter map ----------
   Land, water, and the places the chapter names. The canvas is the picture;
   the list under it is the content, and is what a keyboard and a screen
   reader use. Both are always present. */

/* The count beside "Where this chapter happens", so a chapter with nothing
   to draw says so on the closed panel rather than after a click. */
.map-tally {
  font-family: var(--sans); font-size: .74rem; color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
.map-tally.none { font-style: italic; }

.chapter-map {
  margin: 1.4rem 0 .4rem;
  border-top: 1px solid var(--rule-soft);
  padding-top: .7rem;
}

.chapter-map > summary {
  cursor: pointer;
  display: flex; align-items: baseline; gap: var(--gap-tight);
  font-family: var(--sans);
  font-size: .82rem;
  color: var(--ink-soft);
}
.chapter-map > summary:hover { color: var(--ink); }

.map-body { margin-top: .7rem; }

/* --map-aspect is set from the frame being drawn. Capping the height and
   then deriving the width from it is what keeps the box the shape of the
   map, rather than a wide letterbox with the map adrift in the middle. */
.map-stage {
  position: relative;
  border: 1px solid var(--rule);
  border-radius: 6px;
  overflow: hidden;
  background: var(--paper);
  --map-aspect: 1.2;
  --map-height: 26rem;
  aspect-ratio: var(--map-aspect);
  max-height: var(--map-height);
  max-width: calc(var(--map-height) * var(--map-aspect));
  width: 100%;
  margin: 0 auto;
}

.map-canvas {
  display: block;
  width: 100%;
  height: 100%;
  touch-action: none;   /* the canvas handles its own drag */
  cursor: grab;
}
.map-canvas:active { cursor: grabbing; }

@media (max-width: 40rem) {
  .map-stage { --map-height: 17rem; }
}

.map-tools {
  display: flex;
  gap: .4rem;
  margin: .5rem 0 .2rem;
}

.map-caption {
  font-size: .76rem;
  color: var(--ink-faint);
  line-height: 1.5;
  margin: .5rem 0 .7rem;
}

.map-detail { margin: .7rem 0; }
.map-detail-name {
  font-family: var(--sans);
  font-size: .9rem;
  margin: 0 0 .3rem;
}

.map-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .3rem;
}

.map-place {
  display: inline-flex;
  align-items: baseline;
  gap: .35rem;
  font-family: var(--sans);
  font-size: .74rem;
  padding: .2rem .5rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: var(--raised);
  color: var(--ink);
  cursor: pointer;
}
.map-place:hover, .map-place:focus-visible {
  border-color: var(--accent);
  color: var(--accent);
}

/* The same three grades the canvas draws, so the list is not a lesser copy:
   solid for identified, dashed for approximate, faint for a region. */
.map-place::before {
  content: "";
  width: .5rem; height: .5rem;
  border-radius: 50%;
  background: var(--accent);
  flex: none;
}
.map-place.map-approximate::before {
  background: transparent;
  border: 1px dashed var(--accent);
}
.map-place.map-region::before {
  background: var(--accent);
  opacity: .3;
}
.map-place.map-within::before {
  background: var(--accent);
  opacity: .6;
}

.map-place-kind, .map-place-first {
  /* Named for the screen reader, not shown: the dot carries it for the eye. */
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* The list's copy of the canvas's dotted outer ring. A ring rather than a
   fill, so it reads as something added around the grade rather than as a
   fourth grade of its own -- the place is still whatever it was. */
.map-place.map-first {
  box-shadow: 0 0 0 1px var(--accent);
}

/* ---- what a place is named beside ---- */

.map-kin { margin-top: .9rem; }
.map-kin h4 {
  font-family: var(--sans);
  font-size: .72rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 .4rem;
}
.map-kin-list {
  list-style: none;
  margin: 0; padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .3rem;
}
.map-kin-list li { display: flex; }
.map-kin-here, .map-kin-name {
  font-family: var(--sans);
  font-size: .74rem;
  padding: .2rem .5rem;
  border-radius: 999px;
  border: 1px solid var(--rule);
  background: var(--raised);
  color: var(--ink);
}
/* Only the ones already on this canvas are buttons; the rest are named but
   not offered, because there is nothing here to point at. */
.map-kin-here { cursor: pointer; }
.map-kin-here:hover, .map-kin-here:focus-visible {
  border-color: var(--accent);
  color: var(--accent);
}
.map-kin-name {
  border-style: dashed;
  color: var(--ink-faint);
  text-transform: capitalize;
}
.map-kin-count { color: var(--ink-faint); }
.map-kin-note, .map-kin-none, .map-arrival {
  font-size: .76rem;
  line-height: 1.5;
  color: var(--ink-faint);
  margin: .5rem 0 0;
}
.map-arrival a { color: var(--accent); }
.map-arrival-note { color: var(--ink-faint); }
