/* ══ The ported reader, in Mere Orthodoxy's colour ═══════════════════
   Skin and bones: the corpus owner's reader engine, our palette.

   THE READER CAME OUT GREY (Ian, 2026-09-14: "It's also too gray. I
   liked the warmth of the old reader"). Not because his design is grey
   — `prdl-system.css` is already built from our brand and sets the same
   #f6f3f2 page, the same #d9c6a7 tan rule and the same #c1593c accent
   we do. Two later stylesheets overwrite all of it with a neutral
   scheme:

     read.in01.css:9          :root{--bg:#F0F0ED; --fg:#1C1C1A; …}
     fr-reading-system.css:5  :root,:root[data-site]{--bg:#F0F0ED;
                              --card:#FFFFFF; --border:#D8D8D3; …}

   #F0F0ED is a cool grey-green and #FFFFFF is a white card on top of
   it, which is why the page reads colder than the rest of the library
   and why a highlighted passage sat in a grey band.

   So this restores the values his own system file already holds. It is
   loaded last in custom-faith-port-read.hbs, which is the only reason
   it wins; keep it last.

   WHAT IS DELIBERATELY NOT TOUCHED: --accent. The reading system sets
   it to #1C1C1A, near-black, and in this engine the accent is used on
   running text as well as on controls, so making it burnt orange would
   colour prose rather than furniture. The controls take the accent from
   our own rules instead. If that changes, verify on screen before
   trusting it — this file exists because someone assumed. */

:root,
:root[data-site] {
  /* The page and the paper it sits on */
  --bg: #f6f3f2;
  --bg-warm: #f1e0c9;
  --card: #fffdfa;
  --card-bg: #fffdfa;
  --panel: #fffdfa;
  --paper: #fffdfa;
  --sidebar: #f5efe1;
  --sidebar-bg: #f5efe1;

  /* Ink. #2d2927 is the library's dark; #1C1C1A is a colder black. */
  --fg: #2d2927;
  --head: #2d2927;
  --ink: #2d2927;
  --muted: #6b6660;

  /* The tan rule, everywhere a rule is drawn */
  --border: #d9c6a7;
  --line: #d9c6a7;

  /* A marked passage sits on cream, not on grey */
  --hl: #f5efe1;
  --highlight: #f5efe1;

  /* ONE TOKEN CARRIES MOST OF THE "THIS ISN'T OUR SITE" FEELING.
     --sans was -apple-system/Segoe UI, and it paints every label in the
     tool layer: the Aa row labels, the Outline tabs, the sidebar chips,
     the mobile dock, the century badges, the selection chip. A system
     sans on a page of Garamond is the single loudest tell. */
  --sans: "Source Serif Pro", Georgia, serif;

  /* The white slab behind the About dialog's header and the related
     passages bar. One token, two surfaces. */
  --masthead: #f5efe1;
  --masthead-ink: #2d2927;

  /* Was #B0B0AA, a cool grey, on volume pills and related-passage
     hovers. Our tan rule. */
  --accent-soft: #d9c6a7;

  /* ── ONE TERRACOTTA WAS DOING TWO JOBS ────────────────────────────
     Ian, 2026-09-21: "Buttons where text becomes unreadable on click."

     --color-secondary (#c1593c) is the brand terracotta and it is right
     as a GROUND: the filled, chosen control. This file also spent it as
     INK — the hover colour of every toolbar button, the Outline tab that
     is current, "Remove highlight" — and as ink it is too light to read.
     Measured on the live reader (pld-2741, 2026-09-21, contrast computed
     from the composited ground rather than from the declared colour):

       hover ink on the cream toolbar, light       3.85:1   at 13-14px
       hover ink on the cream toolbar, sepia       3.85:1
       hover ink on the near-black toolbar, dark   3.19:1
       "Outline" tab, current, dark                3.19:1   at 11.5px

     All of them fail AA (4.5:1). The dark ones fail it badly enough to
     answer the report directly: point at a control in the dark reader and
     its label goes from 11.5:1 to 3.19:1 — it gets FAINTER when you touch
     it, which is exactly backwards.

     So the colour is split by job rather than by guesswork.

     --fr-ink-hot is the terracotta when it is TYPE. In daylight it is the
     brand colour taken 85% of the way to the house off-black: 4.58:1 on
     the toolbar's cream, 4.72:1 on the Ask panel, the same hue a shade
     deeper and not a second orange. In dark it goes the other way, to the
     lifted terracotta this file already mixes for #aboutOv: 5.60:1 on the
     near-black bar.

     --fr-fill / --fr-fill-ink are the terracotta when it is a GROUND. In
     daylight they are unchanged, the brand colour under white. In dark the
     fill lifts and the ink becomes the page, which is 6.95:1 and is also
     what the port itself assumes — read.in01.css:1180 already writes
     `[data-theme="dark"] .tgl[aria-pressed=true]{color:var(--bg)}` for a
     lighter fill it never got.

     NOT CHANGED, and stated so the next person does not go looking: white
     on the undarkened #c1593c is 4.41:1, a 0.09 miss. That is the filled
     state of every button in The Faith Received, on every surface
     including a photograph, and moving it is a decision about the brand
     rather than a fix to the reader. It is reported, not smuggled in. */
  --fr-ink-hot: color-mix(in srgb, var(--color-secondary, #c1593c) 85%, var(--color-dark, #2d2927));
  --fr-fill: var(--color-secondary, #c1593c);
  --fr-fill-ink: var(--color-white, #fff);
}

/* Dark only under the explicit toggle, never under the OS preference: see
   "Dark mode is not shipped, so it must not arrive by accident" below. */
:root[data-theme="dark"] {
  --fr-ink-hot: color-mix(in srgb, var(--color-secondary, #c1593c) 65%, #fff);
  --fr-fill: color-mix(in srgb, var(--color-secondary, #c1593c) 65%, #fff);
  --fr-fill-ink: var(--bg, #1a1a18);
}

/* ── The reader inside the shell ────────────────────────────────────
   Both mastheads are position:fixed at top:0 — ours at z-index 20, the
   reader's toolbar at 40 — so until the toolbar is pushed down it
   covers the site nav completely.

   --mo-head is measured by assets/js/page/faith-port-read-boot.js
   rather than written here as a number, because our header is 61px on a
   desktop and taller when it wraps. The fallback is the desktop height,
   which is what an unmeasured first paint should assume. */
.ph.fr-reader-head,
.ph {
  top: var(--mo-head, 61px);
}

/* .app is `height:100dvh; padding-top:var(--phh)` — a full-viewport app
   shell with its own internal scroller. --phh is published at runtime by
   the engine's setPhh() and now carries our masthead as well as the
   reader's toolbar (see the MereO delta in reader-core.js), so the
   padding clears both and the app still measures exactly one viewport.
   border-box is what keeps that true. */
.app {
  box-sizing: border-box;
}

/* The footer sits after the app. The app is exactly one viewport tall,
   so the page itself scrolls to reach it once the reader's own scroller
   hits its end — which is ordinary scroll chaining, not a second
   scrollbar competing with the first. `overscroll-behavior: auto` on the
   reader's scroller is what allows the chain; the reader sets `contain`
   in places to trap it, and on this page we want it to pass through. */
.faith-port-read-page #scroll { overscroll-behavior-y: auto; }
/* ── Our shell is not his chrome ────────────────────────────────────
   read.in01.css styles `.brand` and `.nav`. So does Mere Orthodoxy's
   masthead. Sharing a document, his rules land on our header: measured
   live, they take header.site-header from 61px to 89px by giving our
   brand block 16px of top padding, 11.2px of bottom, and a rule under
   it, and they hand our nav `overflow-y: auto`.

   HIS STYLESHEET IS NOT LAYERED AND THIS FILE IS NOT LAST. An earlier
   version of this comment claimed both, from a cascade-layer experiment
   that was reverted in 30cd646; the claim outlived the code and would
   have sent the next person writing rules that silently lose. The
   rendered order is: his port sheets, then this file, then
   screen.min.css, then faith-received.min.css. So this file BEATS his
   sheets on a tie and LOSES to ours. Anything that has to outrank our
   own site CSS needs specificity, not position — which is why the rules
   below name `header.site-header` and `#app` rather than bare classes.

   These are the shell's own computed values, read off a clean page
   rather than guessed, and verified to restore 61px exactly. */
header.site-header .brand,
header.site-header .nav,
footer.site-footer .brand,
footer.site-footer .nav {
  padding: 0;
  border-bottom: 0;
  position: static;
  flex: 0 1 auto;
  overflow-y: visible;
  scrollbar-width: auto;
  font-family: var(--font-body);
}

/* `.hero` is the third generic class name both sides use, after `.brand`
   and `.nav`. Ours is the dark band with the cathedral behind it —
   screen.min.css paints it `linear-gradient(#2d2927e6, #2d2927 50%)` and
   sets white text. His index.in01.css sets `.hero h1 { color: var(--head) }`,
   and our skin points --head at the library's dark ink, so the heading
   came out #2d2927 on #2d2927: "The library" was there, in the right
   place, and invisible.

   Inside our hero the band's own colour wins. This is not a palette
   choice, it is the rule that light text belongs on a dark ground. */
.hero { color: #fff; }
.hero h1,
.hero h2,
.hero p,
.hero span,
.hero small,
.hero label { color: inherit; }

/* ── Our shell's rules must not reach into his reader ──────────────
   The collision runs both ways. `.nav` and `.brand` are our site
   masthead's class names AND his reader's: `.nav` is the contents
   sidebar, `.brand` the work card. Our screen.min.css loads after his
   read.in01.css, so on a tie our rule wins — which is what we want in
   our header and exactly what we do not want in his sidebar.

   `.nav { display: flex; align-items: center; gap: 10px }` is our site
   menu, and applied to his outline it laid 276 chapter titles out as a
   horizontal row, collapsing each to a 60px column one letter wide
   (Ian, 2026-09-15: "the TOC on the reader is a mess").

   Only the properties that actually collide are restored, and only
   inside #app. Anything more — a cascade layer over his whole
   stylesheet — demotes every rule he has, including the ones that are
   more specific than ours and ought to win, and that cost the outline
   its typography as well as its layout. Check `#app` first when
   something in the reader inherits a site style it should not. */
#app .nav {
  display: block;
  align-items: normal;
  gap: 0;
}
#app .brand {
  display: block;
  align-items: normal;
}

/* The contents belong in the sidebar, not stacked above the text as
   well. The engine prints an inline contents block at the head of any
   work whose outline runs to four entries or more, which for these is
   the whole outline a second time (Ian: "we need it to all be
   sidebar"). The sidebar carries the same tree, with a filter and a
   Show current control the inline copy does not have. */
#reading .inctoc { display: none; }

/* Our site-menu link treatment — 11px, uppercase, letter-spaced — is
   `.nav a`, and his outline entries are links inside a `.nav`. His own
   rules set the family, size and colour, so those came right once the
   layer went; these two he never declares, so there is nothing of his
   to win and ours simply applies. Two hundred and seventy-six chapter
   titles in spaced small caps is not a list anyone reads. */
#app .nav a {
  text-transform: none;
  letter-spacing: normal;
}

/* THE SIDEBAR STAYS OPEN ON A WIDE SCREEN (Ian, 2026-09-15: "we need it
   to all be sidebar and the sidebar to be really really good").

   His sidebar is a drawer: absolutely positioned over the text with a
   scrim behind it, which is right on a phone and wrong on a desktop,
   where there is room for the outline and the text at once and no
   reason to dim what you are reading to look at where you are in it.

   Above 1100px it joins the flex row instead, so the reading column
   starts where the sidebar ends and nothing is covered. Below that it
   remains the drawer it was. */
@media (min-width: 1100px) {
  .app:not(.nosb) #sbScrim { display: none !important; }
  .app:not(.nosb) .sidebar {
    position: relative;
    top: 0;
    /* Stated explicitly. The drawer's translateX(-100%) is applied while
       .nosb is on the element at first paint, and it survives the class
       being removed a moment later — computed transform stayed at -300px
       with no rule matching it. The open state says what open means
       rather than relying on the closed state's rule stopping. */
    transform: none;
    flex: 0 0 300px;
    box-shadow: none;
  }
  .app:not(.nosb) .main { min-width: 0; }
}

/* .app is `height: 100dvh` — one viewport — which was true when the
   reader owned the document. Inside our shell it starts below the
   masthead, so a full viewport of height runs past the fold by exactly
   the masthead's height, and the sidebar and the reading column both
   ended up with their last rows under the bottom edge.

   It gets the viewport MINUS our masthead. --mo-head is measured at
   runtime by faith-port-read-boot.js, so this follows the header when it
   wraps at narrow widths. */
.faith-port-read-page {
  height: calc(100dvh - var(--mo-head, 61px));
}

/* ── Dark mode is not shipped, so it must not arrive by accident ────
   fr-reading-system.css applies its whole dark token set under
   `@media (prefers-color-scheme: dark)` to
   `:root:not([data-theme="light"]):not([data-theme="sepia"])`. On a
   first visit there is no data-theme attribute at all, so A READER
   WHOSE OS IS DARK LANDS ON THE DARK READER WITHOUT TOUCHING A CONTROL
   — under our cream masthead, above our cream footer. Dark content,
   light chrome, no seam between them that anyone chose.

   The reading theme is a property of the reading surface, and a
   masthead carrying the wordmark and a terracotta member button is not
   part of that surface. Light and sepia are both warm and sit under
   that masthead without a seam, which is why they are fine scoped to
   the reader. Dark is different in kind: someone who asks for a dark
   screen is not asking for an 85px cream band at the top of it. Doing
   it properly means taking our own shell dark in OUR dark
   (--color-dark ground, --color-cream ink, the band our heroes already
   use), and that is its own piece of work with its own review.

   Until then the OS preference does not get to choose it. The explicit
   toggle still works — `[data-theme="dark"]` is untouched — so nothing
   is removed, it just stops being the default for a third of visitors.
   The theme control itself should drop to Light/Sepia; that is a
   template change, tracked separately. */
/* NOT SEPIA EITHER (Ian, 2026-09-23: "We've also lost the third light
   tan background"). Written as not-dark, this matched sepia too, so on
   any machine set to dark it repainted sepia in the light tokens: the
   toggle's third state looked exactly like the first. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="dark"]):not([data-theme="sepia"]),
  :root[data-site]:not([data-theme="dark"]):not([data-theme="sepia"]) {
    color-scheme: light;
    --bg: #f6f3f2;
    --bg-warm: #f1e0c9;
    --card: #fffdfa;
    --card-bg: #fffdfa;
    --panel: #fffdfa;
    --paper: #fffdfa;
    --sidebar: #f5efe1;
    --sidebar-bg: #f5efe1;
    --fg: #2d2927;
    --head: #2d2927;
    --ink: #2d2927;
    --muted: #6b6660;
    --border: #d9c6a7;
    --line: #d9c6a7;
    --hl: #f5efe1;
    --highlight: #f5efe1;
  }
}

/* THE READER SUBTREE TAKES THE THEME'S INK, NOT THE SITE'S.
   Any element in here that sets no colour of its own inherits from
   `body`, and `body { color: var(--color-dark) }` comes from
   screen.min.css, which loads after this file. In dark that put
   #2d2927 ink on a #242521 sidebar — the work title measured about
   1.1:1 against its own background, which is invisible, not merely
   low-contrast. Asserting --fg at the roots of the embedded surfaces
   fixes every un-coloured descendant at once. */
#app,
#aboutOv,
aside.relpanel,
#selpop,
#notebook {
  color: var(--fg);
}

/* THE VOLUME LIST NEEDED SAYING TWICE.
   `#volnav` sits inside `#app`, so the rule above should have reached it, and
   `read.in01.css` sets `.vnrow { color: var(--fg) }` besides. It still came out
   #2d2927 on the #242521 sidebar — 1.07:1, which is not low contrast, it is
   invisible — for every one of the forty-six rows in PL 140. Whatever wins that
   cascade, an id in the selector settles it. The list is the way from one work in
   a Migne volume to the rest of it and it is now the first thing under the
   outline, so it cannot be the one part of the sidebar a reader cannot see. */
#app #volnav,
#app #volnav .vnrow,
#app #volnav .vnt,
#app #volnav .vnhead,
#app #volnext,
#app #volprev {
  color: var(--fg);
}
#app #volnav .vni,
#app #volnav .vnc {
  color: var(--muted);
}

/* ── Every overlay was anchored to a viewport it no longer owns ─────
   One defect, five instances. The facsimile pane, the contents scrim,
   the related-passages panel, the research drawer and its scrim are all
   `top: 0` — correct when the reader was the whole document, wrong now
   that our masthead occupies the first 61px. Four of the five carry a
   z-index above our masthead's 20, so they do not merely reach it, they
   cover it: with the contents drawer open at 375px, elementFromPoint at
   our logo returns the scrim, and the hamburger cannot be tapped.

   .facs stays inside the media query on purpose. Above 1100px it is
   position:relative and a bare `top` would shift it in normal flow. */
#sbScrim,
.nb-scrim,
.notebook,
aside.relpanel {
  top: var(--mo-head, 61px);
}
@media (max-width: 1100px) {
  #app .facs { top: var(--mo-head, 61px); }
}

/* ── A MODAL SHEET COVERS; A DOCKED RAIL SITS INSIDE THE WINDOW ─────
   The rule above gives the research drawer our masthead's height, which
   is right for the sheet it is below 1100px: that one is aria-modal,
   it takes the screen, and covering the reader's toolbar is what a
   modal is for.

   Docked it is not a modal. read-tools.js sets role="complementary" and
   drops aria-modal, the text narrows to make room, and the rail is
   furniture standing beside the book. So it has to start where the book
   starts. `html.fr-research-docked #notebook { top: var(--phh) }` in
   read.in01.css gives it the READER TOOLBAR's height alone — 65px —
   which was the whole offset back when the reader owned the viewport.
   Our masthead is 85px, so the rail began twenty pixels ABOVE the
   masthead's own bottom edge and, carrying z-index 10020 against the
   masthead's 20, covered it; below that it ran straight over the
   reader's toolbar, which is what Ian saw (2026-09-18: "it's not
   aligned at the top... needs to sit in the TFR window and not overlap
   the navbar"). Both bars, not one.

   Same specificity as his (1,1,1) and this file loads after, so this
   wins on source order. When the chrome hides on scroll both bars leave
   together — see the transform block at the end of this file — and the
   rail takes the space with them rather than leaving a band of nothing
   where the toolbar used to be. */
@media (min-width: 1100px) {
  /* The docked top is the panel's top whether or not it is open yet.
     read-tools.js adds .open and html.fr-research-docked in the same
     frame, so a top that waited for the docked class started the slide
     at the masthead's line and then eased down 65px to the toolbar's
     (Ian, 2026-09-23: "sliding in tall and then popping down"). Closed,
     the panel is off screen, so where its top sits costs nothing.
     `html #notebook.notebook` is (1,1,1), level with the port's docked
     rule and later. The top still eases when the bars scroll away. */
  html #notebook.notebook {
    top: calc(var(--mo-head, 61px) + var(--phh, 64px));
    transition: transform .18s ease-out, top .28s var(--ease, ease);
  }
  /* The masthead scrolls away and the reader's toolbar stays (see the
     pinned toolbar at the end of this file): the rail sits under it. */
  html.mh-hide #notebook.notebook,
  html.mh-mini #notebook.notebook {
    top: calc(var(--fr-rail-h, 0px) + var(--phh, 64px));
  }
  html.fr-bar-hidden #notebook.notebook {
    top: env(safe-area-inset-top, 0px);
  }
  @media (prefers-reduced-motion: reduce) {
    html #notebook.notebook { transition: transform .18s ease-out; }
  }
}

/* The section title in the toolbar never shrinks — `white-space:nowrap`
   with `flex:none` and no overflow rule, while the sibling link beside
   it got the full ellipsis treatment. At 375px it measures 566px inside
   a 260px container and runs 344px past the right edge, straight under
   the Aa button, which is why "Aa" is unreadable on a phone. Only
   `html{overflow-x:hidden}` hides it from the scrollbar.

   It is removed rather than clipped: it prints the same heading that
   the reading column prints 60px below it, and removing it gives the
   author's name back the room it was being crushed out of. */
#app .fr-reader-head #reader-location { display: none; }

/* The settings panel's height cap subtracts the reader's toolbar and
   nothing else — not our masthead, not the mobile dock. At 320x640 the
   last row, the text-size slider, renders 35px underneath the dock and
   the panel does not scroll, so it cannot be reached at all. */
#app .fr-reader-head .aapop {
  max-height: calc(100dvh - var(--mo-head, 61px) - var(--phh, 62px) - 57px - 24px);
}

/* The contents drawer reserves 52px for a dock that measures 57. */
html.g-mobile #app .sidebar { bottom: calc(57px + env(safe-area-inset-bottom)); }

/* Seven dock labels at 9.6px. 14px cannot fit seven cells at 320px;
   11.5px can, and is the honest floor for a label anyone must read. */
html.g-mobile nav.frthumb button { font-size: 11.5px; }

/* The dock's visibility is decided once at load by the g-mobile class
   and never re-run, so a phone-width load resized to desktop keeps the
   dock AND shows the floating Ask pill on top of the dock's own Ask
   cell. Wherever the dock exists, it owns Ask. */
html.g-mobile .fra-launcher { display: none !important; }

/* The only way to dismiss a panel covering the whole phone screen was a
   26px target. */
#app aside.relpanel .relpanel-x { min-width: 44px; min-height: 44px; }

/* ── The font control pointed at the wrong element entirely ─────────
   It changed our masthead and never touched the work. Both halves of
   that are explainable and one of them is this file's fault.

   OUT: the containment rule above restores `font-family: var(--font-body)`
   on our header and footer — but his sheets REDEFINE --font-body at
   :root for each data-font value, so that line was not restoring our
   face, it was piping his toggle straight into our masthead. Our chrome
   now states its own value for the variable rather than reading a token
   he owns. (That is also why the masthead was EB Garamond at rest on
   this page and Source Serif everywhere else on the site.)

   IN: the work's prose inherits from `body { font-family }` in
   screen.min.css, which the control has no way to outrank, so the
   setting had no path to the text. #reading now reads a variable only
   this block sets, keyed off his data-font attribute, so his control
   drives our element. The serif value is unchanged from today's
   default, so nothing moves until a reader asks it to. */
header.site-header,
footer.site-footer {
  --font-body: "Source Serif Pro", Georgia, serif;
  --font-display: "IM Fell Great Primer", "Source Serif Pro", Georgia, serif;
}
:root[data-font="serif"] { --fr-read-font: "Source Serif Pro", Georgia, serif; }
:root[data-font="sans"]  { --fr-read-font: "Source Sans 3", -apple-system, BlinkMacSystemFont, sans-serif; }
:root[data-font="easy"]  { --fr-read-font: "Atkinson Hyperlegible", "Source Sans 3", sans-serif; }
#app #reading { font-family: var(--fr-read-font, "Source Serif Pro", Georgia, serif); }

/* ── Parchment, not pixels. Stone, not glass. ───────────────────────
   Five surfaces in the tool layer were frosted glass with saturation
   boosts. The brand voice says the opposite in those words. The toolbar
   in particular was a translucent page colour under a 16px blur, so it
   read as a floating pane; opaque cream makes it a band belonging to
   the masthead above it. */
#app .ph,
#app .aapop,
#app .fh,
aside.relpanel .relpanel-h,
html nav.frthumb {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
#app .ph { background: var(--color-cream, #f5efe1); }
#app .aapop { background: var(--card, #fffdfa); }

/* ── The outline is a list, not a wall ──────────────────────────────
   276 entries at weight 600. Weight now means "you are here" and
   nothing else, and the current entry is marked by the tan rule down
   its edge rather than a floating white tile — the editorial row, which
   is what the rest of the library uses.

   His selector is (0,3,0); #app is required or this loses. */
#app .nav-node.nd1 .nn-t { font-weight: 400; }
#app .nav-node.on .nn-t { font-weight: 600; }
#app .nav-node.on {
  background: transparent;
  border-radius: 0;
  border-left-color: var(--fr-ink-hot, var(--color-secondary, #c1593c));
}
#app .nav-node:hover { background: var(--hl); }

/* ── The settings panel, in a column ────────────────────────────────
   The label track was `flex: 0 0 3.4rem` — 54.4px — and "FOOTNOTES"
   renders 74px, so that one row's control started 20px right of the
   other five. A grid guarantees the column instead of hoping every
   label fits the basis. The label itself becomes our eyebrow. */
#app .aapop .aarow {
  display: grid;
  grid-template-columns: 104px minmax(0, 1fr);
  align-items: center;
  column-gap: 14px;
  padding: 6px 0;
}
#app .aapop .aal {
  font: 600 11px/1 var(--font-ui, "Source Serif Pro", Georgia, serif);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Selected means terracotta, not near-black. His --accent is #1C1C1A
   and paints every active state in the reader; it is left alone at the
   root because it also reaches footnote markers and drop caps in the
   prose, which is a house-style decision rather than a bug fix. */
#app .aapop .aaseg .tgl[aria-pressed="true"],
#app .aapop .aaseg .tgl.on {
  background: var(--fr-fill, var(--color-secondary, #c1593c));
  border-color: var(--fr-fill, var(--color-secondary, #c1593c));
  color: var(--fr-fill-ink, #fff);
}
/* The Outline / Pages tabs and the phone's dock: these are TYPE, so they
   take the ink terracotta. Measured at 3.19:1 in dark and 4.09:1 in sepia
   on the raw brand colour — see the token note at the top of this file. */
#app .nav-vt button.on { color: var(--fr-ink-hot, var(--color-secondary, #c1593c)); }
html nav.frthumb button.on { color: var(--fr-ink-hot, var(--color-secondary, #c1593c)); }

/* ── One radius, no shadows ─────────────────────────────────────────
   Twelve pill shapes and nine card shadows across the tool layer. The
   site system is a 6px radius and flat surfaces with a tan rule. */
#app .aapop,
#aboutOv .about-box,
aside.relpanel a.rsr {
  border-radius: 4px;
  box-shadow: none;
}
#aboutOv .about-box { border: 1px solid var(--border); }
aside.relpanel { box-shadow: none; border-radius: 0; }
aside.relpanel a.rsr:hover { transform: none; }
#app .nav-vt,
#app .nav-vt button { border-radius: 0; box-shadow: none; }

/* ── The settings panel stops being a second toolbar ────────────────
   Two blocks at the top of a menu labelled "Reading settings" are not
   settings: Previous/Next duplicate the toolbar arrows eight pixels
   away, About and Related belong on the toolbar, and "Go to section" is
   the THIRD way to move within a work after the outline and the
   toolbar's own number field. Together they are 167px of a panel that
   is supposed to be about type.

   His own stylesheet already hides .aamob; a later rule of his turns it
   back on at every width, which is a rule-order accident rather than a
   decision. It stays on the phone, where the toolbar has no room for
   those controls. */
#app .fr-reader-head .aamob,
#app .fr-reader-head .reader-jump-form { display: none; }
html.g-mobile #app .fr-reader-head .aamob { display: flex; }

/* The welcome banner names three things that do not exist on this
   page: a Latin lane and a Scan button that are both display:none on an
   English-only work, and a command palette whose script this template
   deliberately does not load. It is also set in italic EB Garamond — a
   display face on a working surface — and opens with an em dash. An
   open contents list teaches the interface better than a paragraph
   about controls that are not there. */
#app .coach { display: none; }

/* A lane toggle with one lane. On an English-only work it cannot be
   toggled, and it was rendering underlined as though it were a live
   control you had selected.

   Hiding it was the wrong answer and lasted one commit: it is the only
   thing on screen that says WHICH LANE YOU ARE READING, and a reader
   who opens a parallel work and then an English-only one should not
   have that fact silently disappear (Ian, 2026-09-15). It stays, and
   reads as the statement of fact it is: no underline, no pressed
   state, not a button. */
#app.only-en .fr-reader-head #m-en {
  text-decoration: none;
  cursor: default;
  color: var(--muted);
  pointer-events: none;
}

/* The sidebar's default-open lives in faith-port-read-boot.js, NOT
   here. It was briefly done in CSS by neutralising the transform on
   .nosb — which is the CLOSED state, so open and closed rendered
   identically and the toggle silently stopped working (Ian,
   2026-09-15: "this does not actually collapse/expand the TOC"). Never
   style a state class to look like its opposite; drop the class. */

/* ── The work is named once ─────────────────────────────────────────
   The sidebar printed "Confessions / Augustine of Hippo · 276 sections
   · English · digital text" directly beneath a toolbar printing
   "Confessions / Augustine of Hippo · c. 397–400 AD" — the same work,
   named twice, forty pixels apart, and the lower one clipped by the
   band above it (Ian, 2026-09-15).

   The toolbar's copy wins because it is always visible; this one only
   exists while the sidebar is open. Removing it also gives the outline
   back the 81px it was costing, which is most of a first entry.

   The count line goes with it: "276 contents entries" restates the
   toolbar's "/ 276" and the scrollbar says as much again. */
#app .sidebar .work { display: none; }
#app .sidebar .cc-count { display: none; }

/* ── Rows for things this work does not have ────────────────────────
   MY BUG, AND THE ANSWER TO "these tools don't make sense". His
   stylesheet hides the scan-zoom row on a work with no facsimile
   (`.app.nopdf .aarow:has(.izc)`), but the grid rule above sets
   `display: grid` on every .aarow and carries an id, so it outranks his
   hiding and put the row back. Confessions is a born-digital English
   text: there is no scan to zoom and no second lane to balance, so
   those sliders moved nothing at all.

   His conditions are re-asserted at this file's specificity. */
#app.nopdf .aapop .aarow:has(.izc),
#app.no-facs .aapop .aarow:has(.izc) { display: none; }

/* The two lane-size sliders set the size of one lane RELATIVE to the
   other. With a single lane there is no other, so "En" was a control
   with nothing on the far side of it. The text-size slider above is the
   one that does this job on an English-only work. */
#app.only-en .aapop .aarow:has(.lnz),
#app.only-en .aapop #source-size { display: none; }

/* ── Type size changes the type, not the page ───────────────────────
   `max-width: min(40em, 88%)` is measured in em, so it tracks the
   reading font-size: turning the text down pulled the column in with
   it and left a widening band of empty page on the right, and the
   layout appeared to move when only the type should have (Ian,
   2026-09-15: "it should just change the actual font size in the doc
   but keep it formatted to the page").

   rem is rooted on the document, and the slider sets font-size on
   #reading, so the column now holds its width while the type inside it
   grows and shrinks. 46rem is the same 736px the em measure gave at the
   default size, so nothing moves until someone asks it to. The 88% cap
   is kept: it is what guarantees a margin at every width. */
#app.only-la #reading,
#app.only-en #reading { max-width: min(46rem, 88%); }

/* Wider once the sheet is gone. 46rem was right when the column sat on a
   lit sheet of paper: the paper drew the eye and the space around it read
   as a mat. With the surface removed the same column reads as a narrow
   ribbon stranded in a field, which is what Ian saw. The measure opens on
   wide screens only, so phones and tablets keep the line length they
   have, and 60rem at the reader's body size is still inside a sane
   measure rather than a full-bleed wall of text. */
@media (min-width: 1200px) {
  #app.only-la #reading,
  #app.only-en #reading { max-width: min(60rem, 92%); }
}

/* ── The toolbar's right cluster ────────────────────────────────────
   Four groups with four different rhythms: the arrows cramped against
   each other, a white input box on a cream band, a rule with unequal
   air either side, then two text buttons at a third spacing. Read left
   to right it has no beat (Ian, 2026-09-15).

   One gap between groups, one height for everything in the row, and
   the page field belongs to the toolbar rather than looking like a form
   dropped onto it. */
#app .ph .ctr {
  display: flex;
  align-items: center;
  gap: 18px;
}
#app .ph .ctr .seg {
  display: flex;
  align-items: center;
  gap: 2px;
}
#app .ph .ctr #pPrev,
#app .ph .ctr #pNext {
  min-width: 34px;
  min-height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
#app .ph .ctr #pgJump {
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 3px;
  min-height: 30px;
  padding: 0 6px;
  text-align: right;
  font: inherit;
  color: var(--fg);
}
#app .ph .ctr .pg-total { color: var(--muted); }
#app .ph .ctr #rdFlow,
#app .ph .ctr #rdRel { min-height: 34px; }

/* ── Where the reader stops and the site resumes ────────────────────
   The reading pane is exactly one viewport, so the footer sits below it
   and the join had nothing marking it: text ran to the pane's edge and
   the footer began, with no line to say one had ended (Ian, 2026-09-15:
   "the footer is showing up here weird").

   A rule is what the rest of the library uses between a reading surface
   and what follows it. The Ask pill also stops floating over the
   footer — it belongs to the reader, not to the page below it. */
.faith-port-read-page { border-bottom: 1px solid var(--color-card-border, #d9c6a7); }
body:has(.faith-port-read-page) .fra-launcher { position: absolute; bottom: 18px; }

/* ═══════════════════════════════════════════════════════════════════
   THE TEXT SITS ON THE PAGE, NOT ON A SHEET OF PAPER

   His FR-EDITION pass (read.in01.css, "the Fine Press pass") floats the
   reading column on a paper surface: --card-bg a step lighter than the
   desk, a hairline edge, a soft drop shadow. Ian's call, 2026-09-15: the
   words should be on the page background itself, not on a document-like
   object sitting on top of it.

   Skin, not bones. His file is left alone and the values are stated
   here; our stylesheet loads after his, so equal specificity is enough
   and no !important is needed. The measure and the padding are his and
   stay his — this removes the surface, not the typography.
   ═══════════════════════════════════════════════════════════════════ */
html:not(.fr-plain) .app.only-en #reading,
html:not(.fr-plain) .app.only-la #reading,
html:not(.fr-plain) .app:not(.only-en):not(.only-la) #reading,
html:not(.fr-plain) .app.teiflow:not(.no-facs):not(.only-en):not(.only-la) #reading {
  background: transparent;
  border-inline: 0;
  box-shadow: none;
}

/* ───────────────────────────────────────────────────────────────────
   THE TOOLS POPOVER

   Wears the Aa popover's dress, because it is the same kind of object
   in the same toolbar and a second visual language there would be one
   too many. Rows are buttons rather than menu items: each does its
   thing and says so in the status line at the foot.
   ─────────────────────────────────────────────────────────────────── */
#app .aapop.rdtools {
  display: none;
  width: min(19rem, calc(100vw - 24px));
  padding: 6px;
}
#app .aapop.rdtools.is-open { display: block; }

#app .aapop.rdtools .rdt {
  display: block; width: 100%;
  appearance: none; background: none; border: 0; border-radius: 4px;
  /* 44px of target even at the smaller label size. */
  padding: 9px 10px;
  text-align: left; cursor: pointer;
  font-family: var(--sans); font-size: 0.86rem; line-height: 1.25;
  color: var(--fg);
}
#app .aapop.rdtools .rdt .rdt-l { display: block; }
#app .aapop.rdtools .rdt span:not(.rdt-l) {
  display: block; margin-top: 2px;
  font-size: 0.72rem; line-height: 1.3; color: var(--muted);
}
#app .aapop.rdtools .rdt:hover:not(:disabled) { background: var(--hl); }
#app .aapop.rdtools .rdt:disabled { opacity: 0.5; cursor: default; }
#app .aapop.rdtools .rdt[aria-pressed="true"] { color: var(--accent); }

/* The status line only takes room once it has something to report, so
   the popover does not carry an empty gap at its foot. */
#app .aapop.rdtools .rdt-say {
  margin: 0; padding: 0 10px;
  font-family: var(--sans); font-size: 0.72rem; line-height: 1.35;
  color: var(--muted);
}
#app .aapop.rdtools .rdt-say:empty { display: none; }
#app .aapop.rdtools .rdt-say:not(:empty) {
  padding: 8px 10px; margin-top: 4px;
  border-top: 1px solid var(--border);
}
#app .aapop.rdtools .rdt-say.is-bad { color: var(--accent); }

/* ── The paragraph rail (assets/js/page/faith-port-read-tools.js) ───
   Follows the pointer down the column and acts on the block beside it.
   It lives in the margin, which after the sheet came off is space the
   page had going spare. Pointer devices only: it is a hover affordance,
   and on a touch screen it would either never show or never leave. */
.fr-para-rail {
  position: absolute; left: 0; z-index: 3;
  display: flex; flex-direction: column; gap: 2px;
  opacity: 0; transition: opacity 0.12s ease;
}
#reading:hover .fr-para-rail { opacity: 1; }
.fr-para-rail[hidden] { display: none; }
.fr-para-rail button {
  appearance: none; cursor: pointer;
  width: 24px; height: 24px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 0; border-radius: 4px;
  font: 0.82rem/1 var(--sans); color: var(--muted);
}
.fr-para-rail button:hover { background: var(--hl); color: var(--accent); }
@media (prefers-reduced-motion: reduce) { .fr-para-rail { transition: none; } }

/* Touch-only: a hover affordance there either never appears or never
   leaves. This is the gate; the script no longer asks at load, because a
   wrong answer in that one instant was permanent and silent. */
@media (hover: none) { .fr-para-rail { display: none !important; } }

/* ── No site footer in the reader ───────────────────────────────────
   The reader is a full-height application: the toolbar is fixed, the
   column scrolls inside #scroll, and the page itself does not scroll.
   A site footer under that is unreachable by scrolling and only ever
   appeared as a band of marketing wedged beneath the text.

   :has() on the body rather than a class from JS, so it is right on the
   first paint and there is no moment where the footer flashes. The
   footer is a sibling of <main>, not of #app, so no combinator from
   #app can reach it. */
body:has(#app.faith-port-read-page) .site-footer { display: none; }
/* THE ATLAS IS THE SAME KIND OF PAGE AND NEEDS THE SAME RULE. /web/ is a
   full-viewport app: its body is exactly one screen tall and everything
   in it is positioned, so the footer, still in normal flow, collapsed to
   the top and drew ITSELF UNDER THE MASTHEAD, above the page it belongs
   beneath. Measured before and after: footer at y=0 with a body 900px
   tall on a 900px viewport.

   Checked every other surface rather than assuming this was general: the
   desk, bookmarks, topics, the author room, search, compare and
   all-works all place it correctly at the foot of a scrolling page, and
   the reader already suppresses it by the rule above. Only the atlas was
   wrong. */
body.web-page .site-footer { display: none; }

/* ═══ MOBILE: two layout faults that are arithmetic, not guesswork ═══ */

/* 1. The last lines of a page sat UNDER the thumb bar. nav.frthumb is a
      fixed 57px strip at the foot of the screen and #reading's bottom
      padding was 48px, so the closing paragraph of every page was
      unreachable however far you scrolled. Enough room for the bar, the
      home indicator, and a line of air. */
@media (max-width: 880px) {
  html.g-mobile .app #reading,
  #app.faith-port-read-page #reading {
    padding-bottom: calc(57px + env(safe-area-inset-bottom, 0px) + 28px);
  }
}

/* 2. The contents panel left a band of reading text showing between the
      toolbar and its own top edge.
      
      The panel is positioned from --phh, the toolbar's height, and any
      disagreement between that number and the toolbar's real height
      opens a gap the text shows through. Rather than keep chasing the
      number, the panel now starts ABOVE where the toolbar ends and pads
      its content back down: a gap is then geometrically impossible, and
      the overlap hides behind the toolbar.

      That requires the panel to sit UNDER the toolbar in the stacking
      order. It shipped at z-index 60 against the toolbar's 40, so it
      would have covered it. 30 keeps it above the scrim (25) — which is
      what it must overlay on a phone — and below the toolbar. */
@media (max-width: 1099px) {
  #app .sidebar {
    top: calc(var(--phh, 64px) - 28px);
    padding-top: 28px;
    z-index: 30;
  }
}

/* 3. The toolbar's right-hand strip, on a phone.
      
      Measured at 375px: the row wants 394px and Aa's right edge lands at
      406, so it sits outside the screen with no way to reach it. That is
      the BEST case — a single-lane work. A work with English · Latin ·
      Scan, or one carrying a date under the page box, is far wider
      again, which is why tightening the spacing alone cannot be the
      whole answer.

      So: tighter spacing to make the common case fit outright, and the
      strip scrolls when it still does not. A control that has run off
      the edge is then reachable rather than lost. The scrollbar is
      hidden because this is chrome, not content. */
@media (max-width: 880px) {
  #app .ph .ctr {
    gap: 10px;
    /* overflow-x cannot produce a scroll until the box is actually
       CONSTRAINED. The strip is a flex child, and it was sizing to its
       own content and overflowing .ph instead of scrolling inside it:
       394px of controls reported as a 394px box, so scrollWidth equalled
       clientWidth and nothing scrolled. flex-shrink plus min-width: 0 is
       what lets it be narrower than its contents. */
    flex: 1 1 auto;
    min-width: 0;
    max-width: 100%;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    /* The strip must be able to scroll to its own end, and the last
       control needs air after it rather than being flush to the edge. */
    padding-inline: 8px;
    scroll-padding-inline: 8px;
  }
  #app .ph .ctr::-webkit-scrollbar { display: none; }
  /* Nothing in the strip may be squeezed: a compressed page box or a
     lane label clipped to three letters is worse than a scroll. */
  #app .ph .ctr > * { flex: 0 0 auto; }
}

/* ═══ DARK MODE: the text was on the wrong surface ═══════════════════
   
   Measured on a phone in dark scheme: the reader's own palette switches
   correctly — --fg is #E9E9E5 and the text computes to rgb(233,233,229)
   — but the page underneath it stayed rgb(246,243,242), because the site
   shell has no dark mode of its own. Near-white type on near-white
   paper: eleven points of luminance between them. Unreadable, exactly as
   reported.

   Removing the paper sheet is what exposed it. Until then #reading
   painted --card-bg, which in dark scheme is #2B2C29, so the text sat on
   a dark card and could be read. Taking the sheet away let the light
   body through.

   The reading surface follows the reader's own --bg from here, which is
   the variable the reader's Light/Sepia/Dark control writes too — so
   this answers the OS setting and the in-reader toggle with one rule.
   In light scheme --bg is #f6f3f2, the colour the page already was, so
   nothing moves. */
body:has(#app.faith-port-read-page) { background: var(--bg); }
#app.faith-port-read-page,
#app.faith-port-read-page .main,
#app.faith-port-read-page #scroll { background: var(--bg); }

/* The reader's toolbar is ours, not his, and it was pinned to the cream
   masthead colour in every scheme — a bright band across the top of an
   otherwise dark reader. It takes the dark surface with everything else,
   and only in dark scheme, so the light reader is untouched. */
@media (prefers-color-scheme: dark) {
  #app.faith-port-read-page .ph {
    background: var(--card-bg);
    color: var(--fg);
    border-bottom-color: var(--border);
  }
  #app.faith-port-read-page .ph button,
  #app.faith-port-read-page .ph a,
  #app.faith-port-read-page .ph input { color: var(--fg); }
  #app.faith-port-read-page .ph .pg-total,
  #app.faith-port-read-page .ph .sub,
  #app.faith-port-read-page .ph .ploc { color: var(--muted); }
}

/* ── The contents panel's header scrolls away with everything else ───
   
   Two sticky blocks were stacked at the top of the panel: the
   Outline/Library tabs (56px, pinned at 0) and the tools box beneath
   them (135px, pinned at 57px) — the search field, Expand all / Collapse
   all, and the entry count. 191px of chrome held permanently above the
   list.
   
   On a phone that is a quarter of the screen gone before a single
   contents entry is shown, and it is what was covering the outline.
   Ian's call: it should not stick. You scroll past it to read the
   contents, and scroll back up to search. */
#app .sidebar .nav-vt,
#app .sidebar .rc-contents-tools {
  position: static;
  top: auto;
}

/* The masthead does not change for dark mode. Ian's call, and it is the
   right one: the nav bar is the site's, not the reader's, and it should
   read the same on every page of Mere Orthodoxy whatever the reader
   underneath it is doing. A cream band over a dark reader is a seam
   between two things that genuinely are two things.

   This is also why the logo swap and the hamburger rule that used to sit
   here are gone: both existed only to prop up a dark masthead. The
   shipped logo PNG has the wordmark's dark ink baked in, so if this is
   ever revisited, mere-o-logo-white.png is the light cut, and
   .nav-toggle-bar is painted with background rather than color. */

/* The thumb bar's Research button has nothing to open: its panel was
   removed as dead markup (see custom-faith-port-read.hbs). Hidden rather
   than left as a fifth control that does nothing when tapped. Restore it
   together with a panel that is actually mounted. */
/* The Research panel is mounted again; its dock button uses __frOpenNotebook. */

/* ── The reader, embedded in someone else's panel ───────────────────
   The Ask workspace opens a cited work in an iframe. The masthead and
   the footer are the frame around a PAGE; inside a preview panel they
   are a second Mere Orthodoxy nav bar sitting in the middle of an
   answer. The reader itself is the whole point of the embed, so it
   takes the full height it is given. */
html.mo-embedded header.site-header,
html.mo-embedded .site-footer,
html.mo-embedded #mobile-nav { display: none !important; }
html.mo-embedded { --mo-head: 0px; }

/* ── The curated authors the ported room has no roster for ───────
   Drawn by assets/js/page/faith-author-curated.js only when the shell
   found nothing. Deliberately plain: a name, a line of context, and the
   works. It is a gap-filler, not a second author room, and looking like
   one would invite it to grow into one. */
.fr-curated-author {
  max-width: 720px;
  margin: 0 auto;
  padding: 56px 24px 96px;
  font-family: var(--font-body, "Source Serif Pro", Georgia, serif);
}
.fr-ca-name {
  font-family: var(--font-display, "EB Garamond", Georgia, serif);
  font-weight: 400;
  font-size: clamp(30px, 4vw, 44px);
  line-height: 1.1;
  margin: 0 0 10px;
  color: var(--fg, #2d2927);
}
.fr-ca-meta {
  font-size: 14px;
  letter-spacing: 0.04em;
  color: var(--muted, #6b6660);
  margin: 0 0 28px;
}
.fr-ca-count {
  font-size: 12px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--color-secondary, #c1593c);
  margin: 0 0 14px;
}
.fr-ca-works { list-style: none; padding: 0; margin: 0; }
.fr-ca-works li { border-top: 1px solid var(--border, #d8d8d3); }
.fr-ca-work {
  display: block;
  padding: 16px 0;
  font-family: var(--font-display, "EB Garamond", Georgia, serif);
  font-size: 21px;
  line-height: 1.3;
  color: var(--fg, #2d2927);
  text-decoration: none;
}
.fr-ca-work:hover { color: var(--color-secondary, #c1593c); text-decoration: none; }

/* ── Highlights that cover the words, not the paragraph ──────────
   read-tools.js wraps the selected characters in <mark class="fr-hlx">.
   The port's own .row[data-hl] tints an entire row, which is what Ian
   was objecting to; a row that has marks in it no longer gets that
   tint, so these two never paint at once.

   A <mark> arrives with a browser default of black-on-yellow. Both are
   overridden: the ink is inherited so the text keeps the page's colour
   and its italics, and the grounds are the same three the row tint
   used, so a highlight made before this change looks the same after it.
   Inline padding with a negative margin would misalign wrapped lines,
   so the mark takes its ground and nothing else. */
mark.fr-hlx {
  background: var(--mark-amber, #fbe9c8);
  color: inherit;
  border-radius: 2px;
  padding: 0;
}
mark.fr-hlx[data-hl="sage"] { background: #e7efe0; }
mark.fr-hlx[data-hl="slate"] { background: #e5ecf3; }

[data-theme="dark"] mark.fr-hlx { background: #4d3b1c; }
[data-theme="dark"] mark.fr-hlx[data-hl="sage"] { background: #2c3a2a; }
[data-theme="dark"] mark.fr-hlx[data-hl="slate"] { background: #26313f; }

/* The one highlight control, when it is offering to take the mark back.
   It stops being a swatch and becomes a plain labelled button, because
   an amber chip that means "remove amber" reads as "apply amber". */
#selpop button.sw.is-clear {
  background: transparent;
  border: 1px solid var(--fg);
  color: var(--fg);
}
#selpop button.sw.is-clear:hover {
  border-color: var(--fr-ink-hot, var(--color-secondary, #c1593c));
  color: var(--fr-ink-hot, var(--color-secondary, #c1593c));
}
html.mo-embedded .faith-port-read-page { height: 100dvh; }
html.mo-embedded .ph { top: 0; }

/* ── The reader's own chrome, in dark ──────────────────────────────────
   Putting the theme control back in the bar made dark reachable by a click,
   and dark had never been finished here. The toolbar's ground is painted
   with a literal cream rather than a token, so in dark it held #f5efe1
   under #e9e9e5 ink: the work's own title measured 1.06 against its own
   background, which is invisible rather than merely faint. The tokens were
   right all along — --bg resolves to #222320 in dark — so it is the paint
   that is corrected here and nothing else.

   Our masthead is deliberately left alone. Taking the site shell dark is
   its own piece of work with its own review, as the note above says; this
   is the reader's own furniture only. */
:root[data-theme="dark"] #app .ph.fr-reader-head,
:root[data-theme="dark"] #app .ph {
  background: var(--card-bg, #232320);
  border-bottom-color: color-mix(in srgb, var(--fg) 20%, transparent);
}
:root[data-theme="dark"] #nbSaveReadingPlace {
  background: var(--card-bg, #232320);
  color: var(--fg);
  border-color: color-mix(in srgb, var(--fg) 24%, transparent);
}

/* ── The reader bar on a phone ─────────────────────────────────────────
   At 390px the bar was laying out nine controls in a nowrap row and simply
   running off the side: Tools sat at x=373 and the Aa button at x=449, both
   past the edge of the screen, which is why tapping them did nothing. The
   title block, which is flex:1 against them, was squeezed to nought and the
   work's name disappeared with it.

   The corpus site's reader shows four controls at this width -- home, where
   you are, which text, and Aa -- and hides forty-five. Everything it hides
   is already reachable: reader-core.js proxies Previous, Next, About and
   Related into the Aa menu (see "fold the header controls" there), the lane
   buttons are the same choice as the source picker, and the theme lives in
   that menu as #th. So the bar keeps the four and the title gets its room
   back. Nothing is removed, only moved to where there is space for it. */
@media (max-width: 880px) {
  /* `#app .ph .ctr #pPrev` above is two ids; a selector that means to overrule it
     has to carry two of its own, or it loses however many classes it stacks. */
  html.g-mobile:not(.fr-plain) #app .ph .ctr #pPrev,
  html.g-mobile:not(.fr-plain) #app .ph .ctr #pNext,
  html.g-mobile:not(.fr-plain) #app .ph .ctr #pgJump,
  html.g-mobile:not(.fr-plain) #app .ph .ctr .seg,
  html.g-mobile:not(.fr-plain) #app .ph #m-en,
  html.g-mobile:not(.fr-plain) #app .ph #m-par,
  html.g-mobile:not(.fr-plain) #app .ph #rdTools,
  html.g-mobile:not(.fr-plain) #app .ph #thTop {
    display: none;
  }
  /* The title block is what the freed width is for. */
  html.g-mobile:not(.fr-plain) #app .ph .phl { min-width: 0; flex: 1 1 auto; }
  html.g-mobile:not(.fr-plain) #app .ph .ctr { flex: 0 0 auto; gap: 2px; }
}

/* ── Reading, uninterrupted: the part that is ours ────────────────────────────
   The gesture itself now lives where it belongs, in assets/css/port/read.in01.css,
   ported from the corpus site along with the fix that made it work: the masthead
   restyle there used to end in transform:none, which is exactly the property the
   hide needs. What is left here is the part that is only true of this site.

   This site has its own masthead above the reader's bar, so the bar has to clear
   both itself and that masthead, and the masthead has to leave with it. The port
   moves the reader bar by -101% and knows nothing about ours; these two rules are
   more specific, so they win, and they say the same thing plus the offset.
   Anyone who has asked not to see motion sees them cut instead of slide. */
html header.site-header { transition: transform .28s var(--ease, ease); }
html body,
html #app { transition: padding-top .28s var(--ease, ease); }
html.mh-hide header.site-header,
html.mh-mini header.site-header { transform: translateY(-101%); }
html.mh-hide #app .ph.fr-reader-head,
html.mh-mini #app .ph.fr-reader-head {
  transform: translateY(calc(-101% - var(--mo-head, 61px)));
}
/* Both bars are fixed, so the page is padded to start below them: the body by
   this site's own boot script, which writes the masthead's height as an inline
   style, and #app by the port, which reserves the reader bar's. Leave those in
   place and the departing chrome uncovers a blank band 150px deep instead of the
   text it was covering. They go with it and the prose glides up into the space,
   which is what the corpus site does on a phone and now what both do everywhere.
   !important only because an inline style outranks every selector without one. */
html.mh-hide body,
html.mh-mini body { padding-top: env(safe-area-inset-top, 0px) !important; }
html.mh-hide #app,
html.mh-mini #app { padding-top: env(safe-area-inset-top, 0px); }
/* The reader box is a screen minus our masthead, so moving it up without
   growing it only moves the blank band from the top of the page to the bottom.
   It takes the whole screen while the masthead is away. */
html .faith-port-read-page { transition: height .28s var(--ease, ease); }
html.mh-hide .faith-port-read-page,
html.mh-mini .faith-port-read-page { height: 100dvh; }
@media (prefers-reduced-motion: reduce) {
  html header.site-header, html body, html #app,
  html .faith-port-read-page { transition: none; }
}


/* ── THE READER TOOLBAR, BOXED ──────────────────────────────────────
   Ian, 2026-09-18: "Box the toolbar buttons too."

   The bar was the last surface in the library still speaking in bare
   text. read.in01.css:2049 flattens `.seg button`, `.tgl` and `.sbt` to
   `border: 0` on a transparent ground, which is a defensible reading of
   a reading toolbar and is not the one we are using: every other control
   in The Faith Received is now an outlined box, and a row of unboxed words
   at the top of the page read as labels rather than as the controls they
   are. Same three steps as everywhere else — off-black outlined at rest,
   terracotta outlined when pointed at, terracotta filled when chosen. See the TFR BUTTON block at the
   end of assets/css/faith-received.css; this is that button, stated for
   the one surface whose sheets are too specific for it to reach.

   HIS SELECTOR IS (0,3,1) — `html:not(.fr-plain) .fr-reader-head .tgl`.
   A bare class loses to it however late it is stated, so every rule here
   carries `#app`. That is also why this lives in the skin rather than in
   faith-received.css: it needs the reader's own ids.

   A SEGMENTED GROUP IS ONE BOX WITH DIVIDERS, not boxes in a row — but
   only where the group really is one control. `‹ ›` and `1 / 19` are,
   and they get the group box. THE LANES ARE NOT: their own tooltips say
   "a toggle; combine freely with Latin and the scan", so English, Latin
   and Scan are three independent switches that happen to sit together,
   and a single box around them would promise a single choice. They are
   boxed one by one.

   AND ONE OF THEM IS NOT A BUTTON AT ALL. `#app.only-en … #m-en` is
   `pointer-events: none` and muted — see "the lane you are reading is a
   state, not a button" earlier in this file. Boxed and filled it became
   terracotta ink on a terracotta ground, about 2.3:1, on a control that
   cannot be pressed: a button that looks pressable and is not, which is
   the thing this whole sweep exists to stop. The inert lane keeps its
   quiet label.

   NOT BOXED, deliberately: `.mh-home` ("‹ Library"), which is a back
   link and belongs with the title beside it rather than with the tools,
   and everything inside `.aapop` — the Aa and Tools popovers are panels
   with their own segment design, and they already fill in terracotta
   when a choice is on. */
#app .ph.fr-reader-head .phl > .sbt,
#app .ph.fr-reader-head .ctr > .seg.pnav,
#app .ph.fr-reader-head .ctr > .seg.pgjump,
#app .ph.fr-reader-head .ctr > .seg.lanes > button,
#app .ph.fr-reader-head .ctr > .tgl,
#app .ph.fr-reader-head .ctr > button,
#app .ph.fr-reader-head .ctr > .aaw > .tgl,
#app .ph.fr-reader-head #nbCount {
  box-sizing: border-box;
  height: 40px;
  min-height: 40px;
  border: 1px solid var(--fg);
  border-radius: 3px;
  background: transparent;
  color: var(--fg);
}

/* One box, dividers inside it. The parts give up their own radius so the
   group's corners are the only ones in the row. */
#app .ph.fr-reader-head .ctr > .seg.pnav,
#app .ph.fr-reader-head .ctr > .seg.pgjump {
  gap: 0;
  overflow: hidden;
  padding: 0;
}
#app .ph.fr-reader-head .ctr > .seg.pnav > button {
  height: 100%;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: inherit;
}
#app .ph.fr-reader-head .ctr > .seg.pnav > button + button {
  border-left: 1px solid var(--fg);
}
#app .ph.fr-reader-head .ctr > .seg.lanes { gap: 6px; }
/* The page field IS the group's box. A bordered input inside a bordered
   group is a box in a box, and his `border-right … !important` on .pgjump
   has to be answered in kind or three sides come out terracotta and the
   fourth stays tan. */
#app .ph.fr-reader-head .ctr > .seg.pgjump {
  border-right: 1px solid var(--fg) !important;
  padding: 0 8px;
  gap: 4px;
}
#app .ph.fr-reader-head .ctr .pgjump #pgJump {
  min-height: 0;
  height: 26px;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--fg);
}
/* --fg, not the site's --color-dark: that ink is light-only, and in the dark scheme it set the page
   box and its total near-black on a near-black bar — '/ 698' unreadable (owner, 2026-09-19). The
   skin's own ink flips with the scheme; in light it is the same #2d2927. Same for the borders above. */
#app .ph.fr-reader-head .ctr .pgjump .pg-total {
  color: var(--muted);
}
/* The arrows sat in a group pulled 10px into its neighbour, which reads
   as kerning when the group has no edge and as a collision once it has. */
#app .ph.fr-reader-head .ctr > .seg.pnav { margin-right: 0; }

/* POINTED AT: the terracotta outline the box used to wear at rest.
   Only the two colours move, so the row does not shift under the cursor. */
#app .ph.fr-reader-head .phl > .sbt:hover,
#app .ph.fr-reader-head .ctr > .tgl:hover,
#app .ph.fr-reader-head .ctr > button:hover,
#app .ph.fr-reader-head .ctr > .aaw > .tgl:hover,
#app .ph.fr-reader-head .ctr > .seg.pnav > button:hover,
#app .ph.fr-reader-head .ctr > .seg.lanes > button:hover,
#app .ph.fr-reader-head #nbCount:hover {
  background: transparent;
  /* Hover is the one state here that is terracotta TYPE rather than a
     terracotta ground, so it takes the ink form. On the raw brand colour
     this row measured 3.85:1 in light and sepia and 3.19:1 in dark, which
     made pointing at a button the thing that dimmed its label. */
  border-color: var(--fr-ink-hot, var(--color-secondary, #c1593c));
  color: var(--fr-ink-hot, var(--color-secondary, #c1593c));
}

/* CHOSEN: filled, one step past hover. Flow, the lane you are reading, an
   open popover. Stated after hover so that pointing at the chosen control
   does not un-fill it. */
#app .ph.fr-reader-head .ctr > .seg.lanes > button[aria-pressed="true"],
#app .ph.fr-reader-head .ctr > .tgl[aria-pressed="true"],
#app .ph.fr-reader-head .ctr > .aaw > .tgl[aria-expanded="true"],
#app .ph.fr-reader-head #nbCount[aria-expanded="true"] {
  background: var(--fr-fill, var(--color-secondary, #c1593c));
  border-color: var(--fr-fill, var(--color-secondary, #c1593c));
  color: var(--fr-fill-ink, var(--color-white, #fff));
}

#app .ph.fr-reader-head .phl > .sbt:focus-visible,
#app .ph.fr-reader-head .ctr > .tgl:focus-visible,
#app .ph.fr-reader-head .ctr > button:focus-visible,
#app .ph.fr-reader-head .ctr > .aaw > .tgl:focus-visible,
#app .ph.fr-reader-head .ctr > .seg.pnav > button:focus-visible,
#app .ph.fr-reader-head .ctr > .seg.lanes > button:focus-visible {
  outline: 2px solid var(--fr-ink-hot, var(--color-secondary, #c1593c));
  outline-offset: 2px;
}

/* Three switches, three boxes, and the one that cannot be switched keeps
   the quiet label it already had.

   LAST IN THE BLOCK, AND STATED TWICE. The inert lane also carries
   aria-pressed="true" — it is the lane you are reading — so it matches
   the filled state above. On paper this rule outranks that one (two ids
   against one); in the browser it did not, and terracotta ink sat on a
   terracotta ground at about 2.3:1 until this moved below it. Source
   order settles what a specificity argument did not, and the pressed
   form is spelled out so neither can be read as the closer match. */
#app.only-en .ph.fr-reader-head .ctr > .seg.lanes > #m-en[aria-pressed="true"],
#app.only-la .ph.fr-reader-head .ctr > .seg.lanes > #m-par[aria-pressed="true"],
#app.only-en .ph.fr-reader-head .ctr > .seg.lanes > #m-en,
#app.only-la .ph.fr-reader-head .ctr > .seg.lanes > #m-par {
  border-color: transparent;
  background: transparent;
  color: var(--muted);
}

/* Aa ▸ Spacing has to reach the paragraphs, not just the lane.
 *
 * WHAT WAS BROKEN. Compact / Normal / Relaxed set aria-pressed and wrote
 * html[data-lh], and fr-reading-system.css turns that into
 *
 *     html[data-lh] .app #reading :is(.row:not(.rapp)>.en, … ){line-height:var(--reading-lh)}
 *
 * which styles the LANE. The prose inside it is <p>, and read.in01.css:1754
 * gives every one of them a line-height of its own:
 *
 *     #reading .row .la p,#reading .row .en p{line-height:1.74; … }
 *
 * A declaration on the element always beats a value inherited from its
 * parent, however specific the parent's rule is, so the paragraphs never
 * moved. Measured on the live reader (eebo-266, 2026-09-18): the lane's
 * computed line-height went 31.7px → 33.9px → 40.4px across the three
 * settings while every paragraph stayed at 38.0016px and #reading's height
 * was byte-identical at 399,335px in all three. The control was inert.
 *
 * WHY THIS IS SAFE. It is keyed off [data-lh], and applyLH() REMOVES that
 * attribute for "normal" — so the default reading surface is untouched and
 * keeps read.in01's 1.74. Only a reader who has explicitly asked for
 * compact or relaxed sees anything change. The same lanes the port's own
 * rule names, so the two cannot disagree about scope. */
html[data-lh] .app #reading :is(.row:not(.rapp) > .en, .row:not(.rapp) > .la,
                                .stk > .en, .stk > .la,
                                .zipcol > .en, .zipcol > .la) :is(p, li, blockquote) {
  line-height: var(--reading-lh);
}

/* The research sheet was a viewport tall and did not start at the top.
 *
 * read.in01.css:2224 gives the sheet `height:100dvh` at 880px and below,
 * which was right when the reader owned the window. The block above moves
 * its top edge down by our masthead (`.notebook{top:var(--mo-head,61px)}`),
 * so a full viewport of height now begins below the masthead and ends
 * that far past the fold: measured at 390×844, #notebook's bottom edge
 * sat at 905.
 *
 * Something WAS lost outright. #notebook is `overflow:hidden` and a
 * flex column, and at 390×844 its scrollHeight equalled its clientHeight
 * at 844 — the sheet has no scroll of its own to recover the overhang
 * with. The last child, .nb-destinations, measured y 848 to 905: below
 * the fold entirely, on the Work tab and the Saved tab alike, with
 * elementFromPoint at its centre returning nothing. Those are three
 * links — Personal research, Notebooks, Open Desk — that no reader at
 * or below 880px could reach at all. The .nb-settings row lost its last
 * 4px on the Saved tab on top of that.
 *
 * Not only phones: the masthead is 85px above the 640px breakpoint, so
 * 820px and 880px overhung by 85, not 61. Measured across six widths —
 * 390, 640, 820, 880 all overhung and none could reach the links; 1024
 * and 1440 already sat at 0 and are unchanged by this rule.
 *
 * Its inset is already `61px 0 0 0`; only the explicit height stopped the
 * top and bottom edges from settling it. Handing the height back to them
 * makes the sheet exactly the space below the masthead, and keeps it
 * correct if --mo-head ever changes. */
@media (max-width: 880px) {
  #notebook { height: auto; }
}


/* ── THE ABOUT PANEL: THE WORK, THEN THE PERSON WHO WROTE IT ────────
   Ian, 2026-09-18, on franciscus-junius-opera-theologica-vol-1: "These
   About blocks on works are an absolute mess. They need to be incredibly
   simplified."

   The markup changed with it (reader-core.js, openAbout) — the panel no
   longer emits .about-sec / .about-tags / .about-prose / .about-sig /
   .about-kw, so read.in01.css:123-132 now styles nothing. Those rules
   are left where they are: that file is the corpus owner's and forking
   it costs us his next drop. This block styles the four elements the new
   panel does emit.

   WHAT THE TYPE IS DOING. The h2 is a WORK'S OWN NAME, which is the one
   place the library spends its display face, so it keeps --font-display
   (EB Garamond in this reader, measured) and the blurb keeps --font-body
   — the panel reads in the same voice as the page behind it. Everything
   that is furniture rather than reading goes to Source Serif: the meta
   line under the title was italic EB Garamond at 14.4px, which is a
   display face set in italic on a caption, and the author's name was
   EB Garamond at 17.92px, which made a person's name look like a second
   work title. Hierarchy from size, weight and space instead.

   THE HAIRLINE IS THE ONLY DIVIDER. One work, one author, one rule
   between them; a panel with two items in it does not need a grid. */
#aboutOv .about-box { width: min(600px, 94vw); }

/* THE PANEL SHARED TWO CLASS NAMES WITH /about/ AND LOST BOTH.
   screen.min.css loads after every port sheet, so at equal specificity
   its bare classes win, and Mere Orthodoxy's own About page owns
   `.about-body` (10 rules) and `.about-prose` (12). Measured on the live
   dialog: the panel body was taking `padding: 56px 0 32px` and
   `background-color: #f1e8d5` from screen.css:6009 rather than
   read.in01.css:122's `1.3rem 1.4rem 1.5rem` — which is where the 56px
   of dead space under the title came from, why the body sat on a
   different cream than the box, and why the prose ran flush to the box's
   left edge, 22px outside the title above it. It had been true of every
   About panel in the reader. The new markup drops `.about-prose`
   altogether and this restates the body's own box; `#aboutOv` is (1,1,0)
   and settles it for good. See [[project_port-and-shell-share-class-names]]. */
#aboutOv .about-body {
  padding: 1.35rem 1.4rem 1.5rem;
  background: transparent;
  max-width: none;
  margin: 0;
}

#aboutOv .about-h .ah-meta {
  font: 0.82rem/1.45 var(--sans, "Source Serif Pro", Georgia, serif);
  font-style: normal;
  color: var(--muted, #6b6660);
  margin-top: 0.35rem;
}

/* The close control was rgba(255,255,255,.12) — a white wash designed
   for a dark masthead, invisible on our cream one. Same three steps as
   every other control in the library. */
#aboutOv .about-x {
  background: transparent;
  border: 1px solid transparent;
  color: var(--muted, #6b6660);
}
#aboutOv .about-x:hover { color: var(--tfr-btn, var(--color-secondary, #c1593c)); }
#aboutOv .about-x:focus-visible {
  outline: 2px solid var(--tfr-btn, var(--color-secondary, #c1593c));
  outline-offset: 2px;
}

/* The work. First, because a reader opened a work. */
#aboutOv .about-work p {
  margin: 0;
  font: 1rem/1.62 var(--font-body, Georgia, serif);
  color: var(--fg, #2d2927);
}

/* The author. Context, not a second entry: a name, the two facts that
   place him, one sentence, and the door to the rest. */
#aboutOv .about-who {
  margin-top: 1.35rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--border, #d9c6a7);
}
#aboutOv .about-who:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
#aboutOv .about-who h3 {
  margin: 0;
  font: 600 0.95rem/1.3 var(--sans, "Source Serif Pro", Georgia, serif);
  letter-spacing: 0.01em;
  color: var(--fg, #2d2927);
}
#aboutOv .about-life {
  margin: 0.2rem 0 0;
  font: 0.8rem/1.45 var(--sans, "Source Serif Pro", Georgia, serif);
  color: var(--muted, #6b6660);
}
/* .about-bio and not .about-note — read.in01.css:133 styles .about-note at .72rem under a
   dashed rule, which landed on this line before it was renamed. */
#aboutOv .about-bio {
  margin: 0.55rem 0 0;
  font: 0.94rem/1.58 var(--font-body, Georgia, serif);
  color: var(--fg, #2d2927);
}

/* TFR BUTTON, stated for a surface that sits outside #app.
   The overlay is appended to document.body, so none of the
   `#app .ph.fr-reader-head …` rules above can reach it. Same system,
   same three steps: off-black outlined at rest, terracotta outlined when
   pointed at. See the TFR BUTTON block at the end of
   assets/css/faith-received.css.

   Ink and line read --fg rather than --color-dark so the one rule holds
   in the reader's explicit dark theme, where an off-black outline would
   be an invisible box; --tfr-btn is the lifted terracotta that theme
   needs, and it falls back to the daylight colour when unset. */
#aboutOv .about-more {
  display: inline-block;
  margin-top: 0.9rem;
  padding: 0 13px;
  height: 34px;
  box-sizing: border-box;
  border: 1px solid var(--fg, #2d2927);
  border-radius: 3px;
  background: transparent;
  color: var(--fg, #2d2927);
  font: 13px/32px var(--sans, "Source Serif Pro", Georgia, serif);
  text-decoration: none;
}
#aboutOv .about-more:hover {
  border-color: var(--tfr-btn, var(--color-secondary, #c1593c));
  color: var(--tfr-btn, var(--color-secondary, #c1593c));
}
#aboutOv .about-more:focus-visible {
  outline: 2px solid var(--tfr-btn, var(--color-secondary, #c1593c));
  outline-offset: 2px;
}
/* Dark is scoped to this overlay, never :root — dark-mode.js sets
   data-theme="dark" on every page for an OS-dark reader, and a :root
   token would repaint terracotta controls on a cream page. */
:root[data-theme="dark"] #aboutOv {
  --tfr-btn: color-mix(in srgb, var(--color-secondary, #c1593c) 65%, #fff);
}

/* A long author name is a two-line button, not a clipped one. */
@media (max-width: 640px) {
  #aboutOv .about-more {
    height: auto;
    min-height: 34px;
    line-height: 1.5;
    padding: 6px 13px;
    font-size: 13px;
  }
}

/* ── The Research drawer in the dark scheme (09-19) ──────────────────
   Ian's site sheet inks every notebook control — "Search this work",
   "Ask about this book", "Start a conversation", the work-overview
   links, the destinations, the selection popover — with --tfr-btn and
   falls back to --color-dark (#2d2927), a token the dark scheme never
   changes. On the near-black drawer that ink is invisible (contrast
   1.03). Scoped to the drawer and the popover, never :root (see the
   note above #aboutOv): the drawer only exists on reader pages, whose
   dark scheme is real. */
:root[data-theme="dark"] #notebook,
:root[data-theme="dark"] #selpop {
  --tfr-btn: var(--fg);
  --tfr-btn-ink: var(--bg);
  --color-dark: var(--fg);
}
:root[data-theme="dark"] #notebook a:not([class]) { color: var(--fg); }

/* Toolbar scrolling must not clip its open settings or tools. Keep the
   toolbar above the contents/research panes while one of its menus is open. */
#app .ph.fr-reader-head .ctr:has(.aapop.on, .aapop.is-open) {
  overflow: visible;
}
#app .ph.fr-reader-head:has(.aapop.on, .aapop.is-open) {
  z-index: 10030;
}

/* Tablet readers use the same compact toolbar as phones. Position its
   settings below both mastheads, within the available reading viewport. */
@media (max-width: 1099px) {
  #app .ph.fr-reader-head .aapop {
    --fr-menu-head: var(--mo-head, 61px);
    position: fixed;
    top: calc(var(--fr-menu-head) + var(--phh, 58px) + 8px);
    right: 12px;
    left: auto;
    width: 340px;
    max-width: calc(100vw - 24px);
    max-height: calc(100dvh - var(--fr-menu-head) - var(--phh, 58px) - 80px);
    overflow: auto;
  }
  body:has(> .site-header.is-hidden) #app .ph.fr-reader-head .aapop { --fr-menu-head: 0px; }
}
@media (max-width: 640px) {
  #app .aapop .aarow { grid-template-columns: 80px minmax(0, 1fr); column-gap: 8px; }
  #app .aapop .aaseg { flex-wrap: wrap; }
  #app .aapop .aaseg .tgl { min-height: 44px; }
}

/* Phone reading: retain each existing Latin/original-English pair at full width. */
@media (max-width: 640px) {
  #app:not(.grcwork):not(.en-only):not(.only-en):not(.only-la) #reading {
    font-size: var(--rdszm, 17px) !important;
  }
  #app:not(.grcwork):not(.en-only):not(.only-en):not(.only-la) #reading .row,
  #app:not(.grcwork):not(.en-only):not(.only-en):not(.only-la) #reading .row.seg .sp {
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
  }
  #app:not(.grcwork):not(.en-only):not(.only-en):not(.only-la) #reading :is(.row, .sp) > :is(.la, .en) {
    grid-column: 1;
    padding-inline: 0;
    border-inline: 0;
    min-width: 0;
    max-width: none;
    overflow-wrap: break-word;
  }
  #app:not(.grcwork):not(.en-only):not(.only-en):not(.only-la) #reading .row.soloen > .la,
  #app:not(.grcwork):not(.en-only):not(.only-en):not(.only-la) #reading .row.solola > .en {
    display: none;
  }
  #app:not(.grcwork):not(.en-only):not(.only-en):not(.only-la) #reading :is(.row:not(.rhead):not(.rapp), .sp) > .la::before {
    content: var(--source-label, "Original");
    display: block;
    color: var(--muted);
    font: 12px/1.5 var(--font-body);
    margin: 8px 0;
  }
  #app:not(.grcwork):not(.en-only):not(.only-en):not(.only-la) #reading :is(.row:not(.rhead):not(.rapp), .sp) > .en::before {
    content: "English";
    display: block;
    color: var(--muted);
    font: 12px/1.5 var(--font-body);
    margin: 8px 0;
  }
}

/* One mobile interaction layout through the reader's own 880px breakpoint.
   Keep the open-section link separate from a full-size expansion target. */
@media (max-width: 880px) {
  #app #nav .nav-node { align-items: center; gap: 8px; min-height: 56px; margin-block: 4px; padding: 4px 4px 4px calc(8px + var(--nav-depth, 0) * 12px) !important; }
  #app #nav .nav-node .nav-open { order: 1; min-height: 48px; padding: 8px 4px; font-size: 16px; line-height: 1.45; color: var(--fg); }
  #app #nav .nav-node button.cv { order: 2; align-self: center; flex: 0 0 48px; width: 48px; height: 48px; min-height: 48px; margin: 0; padding: 14px; border: 1px solid var(--border); border-radius: 6px; background: var(--card-bg); color: var(--fg); touch-action: manipulation; }
  #app #nav .nav-node button.cv svg { width: 18px; height: 18px; pointer-events: none; }
  #app #nav .nav-node .cv.leaf { display: none; }
  #app #nav .nav-node .nn-la { order: 3; }
  #app #nav .nav-vt button { min-height: 48px; }
  html.g-mobile nav.frthumb { min-height: 60px; padding: 3px 4px calc(3px + env(safe-area-inset-bottom)); gap: 2px; }
  html.g-mobile nav.frthumb button { min-width: 0; min-height: 54px; padding: 5px 1px; gap: 3px; font-size: 12px; line-height: 1.15; border-radius: 4px; }
  html.g-mobile nav.frthumb button .lb { font-size: 12px; line-height: 1.15; }
  html.g-mobile nav.frthumb button .ic { display: flex; align-items: center; justify-content: center; width: 22px; height: 22px; font-size: 20px; line-height: 1; }
  html.g-mobile nav.frthumb button .ic svg { display: block; width: 20px; height: 20px; }
  html.g-mobile nav.frthumb button.on { background: var(--hl); color: var(--fg); }
  html.g-mobile nav.frthumb button:focus-visible { outline: 2px solid var(--fg); outline-offset: -2px; }
  html.g-mobile #app .sidebar { bottom: calc(60px + env(safe-area-inset-bottom)); }
  html.g-mobile #app .reader-reference { min-width: 0; overflow: hidden; }
  html.g-mobile #app #reader-volume { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; white-space: normal; overflow-wrap: anywhere; }
}
#app .contents-toolbar { display: flex; align-items: center; justify-content: space-between; flex: none; gap: 12px; padding: 0 12px 0 16px; border-bottom: 1px solid var(--border); color: var(--fg); }
#app .contents-toolbar button { width: 48px; height: 48px; padding: 0; border: 0; background: none; color: inherit; font-size: 28px; touch-action: manipulation; }
@media (min-width: 1100px) { #app .contents-toolbar { display: none; } }
#app.fr-work-unavailable .sidebar,
#app.fr-work-unavailable .ph .ctr,
#app.fr-work-unavailable #sbT,
#app.fr-work-unavailable #rdAbout,
#app.fr-work-unavailable #fac,
#app.fr-work-unavailable #dragbar { display: none !important; }

/* ══════════════════════════════════════════════════════════════════════
   THE DOCK SCROLLS, AND THE DISCLOSURE KEEPS ITS MARGINS
   ══════════════════════════════════════════════════════════════════════

   Ian, on the reader at 390px:
     "Bottom of the page toolbar should scroll horizontally with good
      margins instead of being crammed together like that."
     "Translation transparency shouldn't be full width but should have
      margins on either side."

   THE DOCK. Seven cells were being divided into 390px less 8px of
   padding, with a 2px gap: measured, the buttons sat at 4, 59, 114,
   169, 223, 278 and 333, which is 55px each for an icon and a word.
   Nothing could grow and the labels were set at 11.5px to survive it,
   so an eighth control could never be added, which is the wall the Aa
   button has been standing outside of.

   Letting the row scroll turns a fixed division into a queue: each cell
   takes the width its label actually needs, the first five or six are
   on screen, and the rest are a thumb-drag away. The edge padding goes
   up to 14px so the first and last cells are not flush against the
   glass, and the gap to 10px so two labels are not read as one.

   THE DISCLOSURE. It ran 0 to 390, edge to edge, while the text it sits
   above is inset. Being the only full-bleed element on the page made it
   read as a system banner rather than as a note about this work. It now
   takes the reading column's own inset, so its left edge lines up with
   the first letter beneath it. ----------------------------------- */
@media (max-width: 640px) {
  html.g-mobile nav.frthumb {
    justify-content: flex-start;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    gap: 10px;
    padding-left: 14px;
    padding-right: 14px;
  }
  html.g-mobile nav.frthumb::-webkit-scrollbar { display: none; }
  /* Each cell at its natural width. Without this the flex children
     still share the line and the scroll never engages. */
  html.g-mobile nav.frthumb > * {
    flex: 0 0 auto;
    min-width: max-content;
  }
  html.g-mobile nav.frthumb button { padding: 5px 6px; }


  /* Reading settings, once it has joined the dock. The dock styles its
     own children by element rather than by class, so the only thing
     this has to undo is the .tgl box the button wears in the head. */
  html.g-mobile nav.frthumb #aaBtn.frthumb-aa {
    border: 0;
    background: none;
    padding: 5px 6px;
  }
  html.g-mobile nav.frthumb #aaBtn.frthumb-aa .ic {
    font-size: 17px;
    font-weight: 600;
    letter-spacing: 0.01em;
  }
}


/* ── The research panel, boxed (Ian, 2026-09-23) ─────────────────────
   The same thin-line boxes as the author room and the Research hub:
   the work's identity, the reading place, its sources and the analysis
   fold each a card; the passage selection a card under a panel of
   guidance. Theme colours from the port's own variables, so dark mode
   keeps its cards. */
#notebook {
  --nbx-line: var(--border, #d9c6a7);
  --nbx-card: var(--card, #fffdfa);
  --nbx-panel: color-mix(in srgb, var(--card, #fffdfa) 55%, var(--bg, #f6f3f2));
}
#notebook .nb-project { background: var(--nbx-panel); border-bottom: 1px solid var(--nbx-line); }
#notebook #nbWorkPanel > .nb-work-identity,
#notebook #nbWorkPanel > .nb-reading-place,
#notebook #nbWorkPanel > #nbWorkSources:not(:empty),
#notebook #nbSelection {
  border: 1px solid var(--nbx-line);
  border-radius: 3px;
  background: var(--nbx-card);
  padding: 14px 16px;
  margin: 0 0 12px;
}
#notebook #nbWorkPanel > .nb-reading-place { padding-bottom: 10px; }
#notebook #nbWorkPanel > .nb-analysis-fold,
#notebook .nb-settings {
  border: 1px solid var(--nbx-line);
  border-radius: 3px;
  background: var(--nbx-card);
  padding: 0 16px;
  margin: 0 0 12px;
}
#notebook #nbWorkPanel > .nb-analysis-fold > summary,
#notebook .nb-settings > summary { padding: 12px 0; }
#notebook .nb-guidance {
  border: 1px solid var(--nbx-line);
  border-radius: 3px;
  background: var(--nbx-panel);
  padding: 12px 14px;
}

/* ── THE READER TOOLBAR, THIN-LINE (Ian, 2026-09-23) ─────────────────
   "I also just sort of generally find the tool bar to be messy so we need
   to figure out a way to use our new design style to clean it up." The
   boxed toolbar above drew every control in an ink outline, each its own
   box: nine boxes of equal weight in a row. Now, on desktop only (the
   phone has its own bar):
   - every control is a tan hairline, as the rest of TFR is;
   - controls that belong together are ONE joined group, and groups are
     spaced apart: page (arrows and the page box) | reading lanes |
     view (Pages, Find, Aa, theme, Hide bar) | Tools | Research;
   - Research, the one door out of the page, is the only accented
     control;
   - the source row under it is the same joined group.
   Order is set with `order`; no element is moved, so the engine's
   handlers and ids are untouched. The "Hide bar" button and the
   contents overlay are faith-port-read-chrome.js. */
html:not(.g-mobile) #app .ph.fr-reader-head { --tb-line: var(--border, #d9c6a7); --tb-h: 36px; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr { gap: 0; align-items: center; }
html:not(.g-mobile) #app .ph.fr-reader-head .phl > .sbt,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.pnav,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.pgjump,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.lanes > button,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .tgl,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > button,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .aaw > .tgl,
html:not(.g-mobile) #app .ph.fr-reader-head #nbCount,
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tb-focus {
  height: var(--tb-h); min-height: var(--tb-h);
  border: 1px solid var(--tb-line);
  border-radius: 0;
  background: var(--card, transparent);
  color: var(--fg);
  font-size: 13px;
  padding: 0 12px;
}
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.pnav > button + button { border-left: 1px solid var(--tb-line); }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.pgjump { border-right: 1px solid var(--tb-line) !important; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.pnav { padding: 0; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.pnav > button { padding: 0 11px; }
/* order: page | read in | view | settings, tools, report | research | top
   (Ian, 2026-09-23: Aa beside Tools, Report a problem out of the Aa menu
   on Tools' other side, Collapse all in the view group, Top far right) */
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.pnav { order: 1; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.pgjump { order: 2; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.lanes { order: 3; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > #rdFlow { order: 4; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tb-folds { order: 5; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > #rsBtn { order: 6; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > #thTop { order: 7; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tb-focus { order: 8; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .aaw:not(.rdtw) { order: 9; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .rdtw { order: 10; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tb-report { order: 11; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > #frAuth { order: 12; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tb-top { order: 13; }
/* joins: members after the first overlap by the hairline */
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.pgjump,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tb-folds,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > #rsBtn,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > #thTop,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tb-focus,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .rdtw,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tb-report { margin-left: -1px; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.lanes { gap: 0; margin-left: 16px; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.lanes > button + button { margin-left: -1px; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > #rdFlow,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .aaw:not(.rdtw),
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > #frAuth,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tb-top { margin-left: 16px; }
/* group corners */
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.pnav,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.lanes > button:first-child,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > #rdFlow,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .aaw:not(.rdtw) > .tgl { border-radius: 3px 0 0 3px; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.pgjump,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.lanes > button:last-child,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tb-focus,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tb-report { border-radius: 0 3px 3px 0; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .rdtw > .tgl { border-radius: 0; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tb-top,
html:not(.g-mobile) #app .ph.fr-reader-head #nbCount,
html:not(.g-mobile) #app .ph.fr-reader-head .phl > .sbt { border-radius: 3px; }
/* The lens is drawn (faith-port-read-chrome.js); a square box, centred. */
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > #rsBtn { width: var(--tb-h); padding: 0; justify-content: center; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > #rsBtn > .fr-tb-lens { display: block; flex: none; }
/* Report a problem has its own button here; the Aa row is for phones. */
/* Report has its own button on both widths now (the bar's drawer and the
   dock's), so the Aa panel's row goes everywhere. */
#app .ph.fr-reader-head #aaPop .aarow-report { display: none; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tb-report,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tb-top,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tb-folds { white-space: nowrap; cursor: pointer; }
/* the one accented control */
html:not(.g-mobile) #app .ph.fr-reader-head #nbCount { border-color: var(--fr-ink-hot, #b0573a); color: var(--fr-ink-hot, #b0573a); }
/* the source row: the same joined group */
html:not(.g-mobile) #app .reader-witnesses [role="group"] { display: inline-flex; gap: 0; }
html:not(.g-mobile) #app .reader-witnesses [role="group"] > button {
  height: 32px; border: 1px solid var(--tb-line); border-radius: 0; background: var(--card, transparent); color: var(--fg); font-size: 13px; padding: 0 12px;
}
html:not(.g-mobile) #app .reader-witnesses [role="group"] > button + button { margin-left: -1px; }
html:not(.g-mobile) #app .reader-witnesses [role="group"] > button:first-child { border-radius: 3px 0 0 3px; }
html:not(.g-mobile) #app .reader-witnesses [role="group"] > button:last-child { border-radius: 0 3px 3px 0; }
html:not(.g-mobile) #app .reader-witnesses [role="group"] > button[aria-pressed="true"] { background: var(--fr-fill, #b0573a); border-color: var(--fr-fill, #b0573a); color: var(--fr-fill-ink, #fff); position: relative; z-index: 1; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.lanes > button[aria-pressed="true"],
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .tgl[aria-pressed="true"],
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .aaw > .tgl[aria-expanded="true"] { position: relative; z-index: 1; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.lanes { overflow: visible; padding: 0; height: auto; align-items: center; }
/* The port gives #rsBtn a 1.6px right margin, which opened a double
   line between Find and Aa in the joined view group. */
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > #rsBtn { margin-right: 0; }
/* When English is the only reading it is a state, not a button (see
   "the lane you are reading is a state" above): a label before the
   group, not a member of it. */
html:not(.g-mobile) #app.only-en .ph.fr-reader-head .ctr > .seg.lanes > #m-en { border-color: transparent; background: transparent; margin-right: 6px; padding: 0 4px; }
html:not(.g-mobile) #app.only-en .ph.fr-reader-head .ctr > .seg.lanes > #m-en + button { margin-left: 0; border-radius: 3px 0 0 3px; }
/* Hover and chosen keep the terracotta steps of the boxed toolbar. */
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > :is(.fr-tb-focus, .fr-tb-report, .fr-tb-top, .fr-tb-folds):hover { border-color: var(--fr-ink-hot, #b0573a); color: var(--fr-ink-hot, #b0573a); position: relative; z-index: 1; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > :is(.fr-tb-focus, .fr-tb-report, .fr-tb-top, .fr-tb-folds) { cursor: pointer; font: inherit; font-size: 13px; }
html.g-mobile .fr-tb-focus,
html.g-mobile .fr-tb-report,
html.g-mobile .fr-tb-top,
html.g-mobile .fr-tb-folds,
html.g-mobile .fr-sb-actions { display: none !important; }

/* Expand contents: a quiet button at the top of the contents sidebar. */
.fr-sb-actions { padding: 8px 12px 0; }
.fr-read-fold {
  background: none;
  border: 0;
  padding: 4px 0;
  font: inherit;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted, #6b6660);
  cursor: pointer;
}
.fr-read-fold:hover,
.fr-read-fold:focus-visible { color: var(--fg, #2d2927); }

/* Hide toolbar: the scrolled-away state (above), pinned. */
html.fr-bar-hidden header.site-header { transform: translateY(-101%); }
html.fr-bar-hidden #app .ph.fr-reader-head { transform: translateY(calc(-101% - var(--mo-head, 61px))); }
html.fr-bar-hidden body { padding-top: env(safe-area-inset-top, 0px) !important; }
html.fr-bar-hidden #app { padding-top: env(safe-area-inset-top, 0px); }
html.fr-bar-hidden .faith-port-read-page { height: 100dvh; }
html.fr-bar-hidden #app .sidebar { top: 0; }
.fr-read-restore {
  position: fixed;
  top: 10px;
  right: 16px;
  z-index: 60;
  padding: 6px 12px;
  border: 1px solid var(--border, #d9c6a7);
  border-radius: 3px;
  background: var(--card, #fffdfa);
  color: var(--fg, #2d2927);
  font: inherit;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
}
.fr-read-restore[hidden] { display: none; }

/* Expand contents: the outline as thin-line cards over the text, one per
   top-level section, read across in rows; the overlay scrolls down. */
.fr-read-toc {
  position: absolute;
  inset: var(--phh, 64px) 0 0 0;
  z-index: 40;
  overflow-y: auto;
  background: var(--bg, #f6f3f2);
  padding: 18px 28px 64px;
}
html.fr-bar-hidden .fr-read-toc { top: 0; }
.fr-read-toc[hidden] { display: none; }
.fr-read-toc-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin: 0 0 14px;
}
.fr-read-toc-head h2 { margin: 0; font-size: 20px; font-weight: 500; }
.fr-read-toc-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 14px;
  align-items: start;
}
.fr-read-toc-card {
  border: 1px solid var(--border, #d9c6a7);
  border-radius: 3px;
  background: var(--card, #fffdfa);
  padding: 12px 16px 8px;
}
.fr-read-toc-card ul { list-style: none; margin: 6px 0 0; padding: 0; }
.fr-read-toc-card li { border-top: 1px solid var(--border, #d9c6a7); }
.fr-read-toc-entry {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  padding: 6px 0;
  font: inherit;
  font-size: 14px;
  line-height: 1.4;
  color: var(--fg, #2d2927);
  cursor: pointer;
}
.fr-read-toc-entry.fr-read-toc-title { font-size: 16px; font-weight: 600; padding-top: 2px; }
.fr-read-toc-entry:hover,
.fr-read-toc-entry:focus-visible { color: var(--accent, #b0573a); }
.fr-read-toc-entry.is-current { color: var(--accent, #b0573a); }
.fr-read-toc-empty { color: var(--muted, #6b6660); }
/* A flat outline: one ruled list across the width, entries in rows. */
.fr-read-toc-grid.fr-read-toc-flat { gap: 0 28px; align-items: stretch; }
.fr-read-toc-flat > .fr-read-toc-entry {
  padding: 9px 0;
  border-bottom: 1px solid var(--border, #d9c6a7);
}
html.g-mobile .fr-read-restore,
html.g-mobile .fr-read-toc { display: none !important; }

/* ── THE TOOLBAR STAYS WHEN THE MASTHEAD GOES (Ian, 2026-09-23) ──────
   "on scroll down, when the Mere O menu bar goes away, can you have the
   reader toolbar stick to the top of the screen instead of disappearing?"
   Desktop only: on a phone the thumb bar is the reader's controls and
   the head still leaves. Scrolling down (html.mh-mini) takes our
   masthead away as before; the reader's toolbar rises by the masthead's
   height, to the top of the screen, instead of by its own as well. #app
   keeps the toolbar's padding so the text starts under it. The port's
   mini bar hides the title (read.in01.css `html.mh-mini .ph h1`); here
   it stays, so the bar does not change shape as it pins. Hide bar
   (html.fr-bar-hidden) still takes everything away. */
html.mh-mini:not(.g-mobile):not(.fr-bar-hidden) #app .ph.fr-reader-head,
html.mh-hide:not(.g-mobile):not(.fr-bar-hidden) #app .ph.fr-reader-head {
  transform: translateY(calc(-1 * var(--mo-mast, var(--mo-head, 61px))));
}
html.mh-mini:not(.g-mobile):not(.fr-bar-hidden) #app,
html.mh-hide:not(.g-mobile):not(.fr-bar-hidden) #app {
  padding-top: var(--phh, 64px);
}
html.mh-mini:not(.g-mobile) #app .ph.fr-reader-head h1 { display: block; }

/* ── THE RESEARCH PANEL, THIN-LINE (Ian, 2026-09-23) ─────────────────
   "refine the Research sidebar on the reader with the new design." The
   cards above gave it the room's boxes; its controls still spoke the
   older system, every button an ink outline and the one CTA filled
   solid. Now they speak the toolbar's:
   - the five tabs are one joined group, the open tab filled;
   - every button is a tan hairline on the card, 3px corners, the TFR
     hover sweep kept (its :hover rules outrank these);
   - the work's three doors (Search, Ask, Edition details) are one ruled
     list, and Save work / Save reading place one joined pair, filled
     only when the work is saved, so filled always means "on";
   - fields are hairline boxes, and the search field and its button join;
   - the head and the foot links take the quiet small caps of the
     contents sidebar's Expand contents.
   `html #notebook …` selectors are (1,1,2) and up, one element past the
   TFR BUTTON block's (1,1,1) in faith-received.css, whichever file
   loads last. */
#notebook { --nbx-h: 34px; --nbx-fill: var(--tfr-btn, var(--color-secondary, #c1593c)); --nbx-fill-ink: var(--tfr-btn-ink, #fff); }

/* head */
html #notebook .nb-head {
  min-height: 0;
  padding: 14px 16px 12px;
  border-bottom: 1px solid var(--nbx-line);
  font: 500 11px/1.2 var(--font-body, "Source Serif Pro", Georgia, serif);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted, #6b6660);
}
html #notebook .nb-head .nb-x {
  width: 30px;
  height: 30px;
  min-height: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--nbx-line);
  border-radius: 3px;
  background: var(--nbx-card);
  color: var(--fg);
  font: 18px/1 var(--font-body, Georgia, serif);
  letter-spacing: 0;
  padding: 0 0 2px;
}
html #notebook .nb-head .nb-x:hover { border-color: var(--nbx-fill); color: var(--nbx-fill); }

/* tabs: one joined group */
html #notebook .nb-tabs {
  gap: 0;
  padding: 12px 16px;
  border-bottom: 1px solid var(--nbx-line);
  overflow: visible;
}
html #notebook .nb-tabs button {
  flex: 1 1 0;
  min-width: 0;
  min-height: 0;
  height: 32px;
  padding: 0 6px;
  border: 1px solid var(--nbx-line);
  border-radius: 0;
  background: var(--nbx-card);
  color: var(--fg);
  font: 13px/1 var(--font-body, Georgia, serif);
  white-space: nowrap;
}
html #notebook .nb-tabs button + button { margin-left: -1px; }
html #notebook .nb-tabs button:first-child { border-radius: 3px 0 0 3px; }
html #notebook .nb-tabs button:last-child { border-radius: 0 3px 3px 0; }
html #notebook .nb-tabs button:hover { border-color: var(--nbx-fill); color: var(--nbx-fill); position: relative; z-index: 1; }
html #notebook .nb-tabs button[aria-selected="true"] {
  background: var(--nbx-fill);
  border-color: var(--nbx-fill);
  color: var(--nbx-fill-ink);
  position: relative;
  z-index: 2;
}
html #notebook .nb-tabs button::after { content: none; }

/* the notebook picker */
html #notebook .nb-project { padding: 10px 16px 12px; gap: 12px; align-items: end; }
html #notebook .nb-project label {
  font: 500 10.5px/1.2 var(--font-body, Georgia, serif);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted, #6b6660);
}
html #notebook :is(#nbProjectPick, #nbSearch, #nbWorkSearchQuery) {
  height: var(--nbx-h);
  min-height: 0;
  box-sizing: border-box;
  border: 1px solid var(--nbx-line);
  border-radius: 3px;
  background: var(--nbx-card);
  color: var(--fg);
  font: 14px/1.2 var(--font-body, Georgia, serif);
  letter-spacing: 0;
  text-transform: none;
  padding: 0 10px;
  margin-top: 5px;
}
html #notebook :is(#nbSearch, #nbWorkSearchQuery) { margin-top: 0; }
html #notebook :is(#nbProjectPick, #nbSearch, #nbWorkSearchQuery):focus-visible {
  outline: none;
  border-color: var(--nbx-fill);
}
html #notebook #nbProjectDesk { font-size: 12px; text-underline-offset: 3px; }

/* every button: the hairline */
html #notebook .nb-passage-actions button,
html #notebook .nb-work-primary button,
html #notebook .nb-reading-place button,
html #notebook .nb-work-search-form button,
html #notebook .nb-tools button,
html #notebook .nb-highlight-colors button,
html #notebook .nb-book-ask {
  min-height: var(--nbx-h);
  height: auto;
  box-sizing: border-box;
  border: 1px solid var(--nbx-line);
  border-radius: 3px;
  background-color: var(--nbx-card);
  color: var(--fg);
  font: 13px/1.3 var(--font-body, Georgia, serif);
  padding: 7px 12px;
}

/* the work's doors: one ruled list */
html #notebook .nb-work-primary {
  display: flex;
  flex-direction: column;
  gap: 0;
  margin-top: 12px;
  border: 1px solid var(--nbx-line);
  border-radius: 3px;
  overflow: hidden;
}
html #notebook .nb-work-primary button {
  width: 100%;
  border: 0;
  border-top: 1px solid var(--nbx-line);
  border-radius: 0;
  text-align: left;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
html #notebook .nb-work-primary button::after { content: "\203A"; font-size: 16px; line-height: 1; opacity: 0.6; }
html #notebook .nb-work-primary > button:first-child { border-top: 0; }

/* save work | save reading place: one joined pair */
html #notebook .nb-reading-place > div { gap: 0; flex-wrap: nowrap; }
html #notebook .nb-reading-place > div > button { flex: 1 1 auto; }
html #notebook .nb-reading-place > div > button + button { margin-left: -1px; }
html #notebook .nb-reading-place > div > button:not(:last-child) { border-radius: 3px 0 0 3px; }
html #notebook .nb-reading-place > div > button + button { border-radius: 0 3px 3px 0; }
html #notebook .nb-reading-place > div > button:hover { position: relative; z-index: 1; }
/* The TFR block fills this one with the `background` shorthand at (2,1,0),
   which also drops the sweep; both are put back, and its hover with them. */
html #notebook .nb-reading-place #nbSaveReadingPlace {
  background-color: var(--nbx-card);
  background-image: var(--btn-sweep-image);
  background-repeat: no-repeat;
  background-position: 0 0;
  background-size: 0% 100%;
  transition: var(--btn-sweep-transition);
  color: var(--fg);
  border-color: var(--nbx-line);
}
html #notebook .nb-reading-place #nbSaveReadingPlace:hover {
  background-size: 100% 100%;
  color: var(--btn-sweep-ink, #fff);
  border-color: var(--btn-sweep-fill, #c1593c);
}
html #notebook .nb-reading-place #nbSaveWork[aria-pressed="true"] {
  background: var(--nbx-fill);
  border-color: var(--nbx-fill);
  color: var(--nbx-fill-ink);
  position: relative;
  z-index: 1;
}
html #notebook .nb-reading-place p { font-size: 12px; }

/* search: the field and its button join */
html #notebook .nb-work-search-form label {
  display: block;
  margin: 0 0 6px;
  font: 500 10.5px/1.2 var(--font-body, Georgia, serif);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted, #6b6660);
}
html #notebook .nb-work-search-form > div { display: flex; gap: 0; }
html #notebook .nb-work-search-form #nbWorkSearchQuery { flex: 1 1 auto; min-width: 0; border-radius: 3px 0 0 3px; }
html #notebook .nb-work-search-form button { margin-left: -1px; border-radius: 0 3px 3px 0; white-space: nowrap; }

/* passage tools: an even grid; the colours one joined row */
html #notebook .nb-passage-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
html #notebook .nb-passage-actions button { width: 100%; text-align: left; }
html #notebook .nb-highlight-colors { display: flex; flex-wrap: wrap; gap: 0; border: 0; padding: 0; margin: 12px 0 0; }
html #notebook .nb-highlight-colors legend {
  width: 100%;
  margin: 0 0 6px;
  font: 500 10.5px/1.2 var(--font-body, Georgia, serif);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted, #6b6660);
}
html #notebook .nb-highlight-colors button { border-radius: 0; }
html #notebook .nb-highlight-colors button + button { margin-left: -1px; }
html #notebook .nb-highlight-colors legend + button { border-radius: 3px 0 0 3px; }
html #notebook .nb-highlight-colors button:last-child { border-radius: 0 3px 3px 0; }
html #notebook .nb-highlight-colors button:hover { position: relative; z-index: 1; }

/* the single wide buttons */
html #notebook .nb-book-ask { width: 100%; margin-top: 12px; }

/* settings exports */
html #notebook .nb-tools { gap: 6px; }

/* foot: the quiet small caps */
html #notebook .nb-destinations { gap: 18px; padding: 10px 16px max(10px, env(safe-area-inset-bottom)); border-top: 1px solid var(--nbx-line); }
html #notebook .nb-destinations a {
  min-height: 28px;
  font: 500 10.5px/1.2 var(--font-body, Georgia, serif);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--muted, #6b6660);
}
html #notebook .nb-destinations a:hover { color: var(--fg); }
html #notebook .nb-tools button:hover { border-color: var(--nbx-fill); color: var(--nbx-fill); }

/* ── THE RAIL ON THE READER (Ian, 2026-09-23) ────────────────────────
   The TFR rail sits above the toolbar (custom-faith-port-read.hbs) and
   replaces the toolbar's "‹ Library" link. It is in flow under the
   masthead and counted into --mo-head by faith-port-read-boot.js, which
   also publishes --mo-mast, the masthead alone; the difference is the
   rail. When the masthead scrolls away the body's padding goes, so the
   rail rises to the top of the screen; the toolbar rises by the
   masthead only (above) and pins under it, and the page is a screen
   less the rail. Hide bar takes the rail too, and a framed reader (the
   Ask source preview) has none. */
html { --fr-rail-h: calc(var(--mo-head, 61px) - var(--mo-mast, var(--mo-head, 61px))); }
#app .ph.fr-reader-head #mhHome { display: none; }
html.mh-hide .faith-port-read-page,
html.mh-mini .faith-port-read-page { height: calc(100dvh - var(--fr-rail-h, 0px)); }
html.fr-bar-hidden .tfr-rail,
html.mo-embedded .tfr-rail { display: none; }
@media (max-width: 1439px) {
  html:not(.g-mobile) #app .ph.fr-reader-head .fr-tb-report .fr-tb-more { display: none; }
}

/* ── THE RAIL NEVER GOES UNDER THE TOOLBAR (Ian, 2026-09-23) ─────────
   "the navrail is slipping behind the toolbar on scroll. That should
   never happen." The toolbar is fixed at z-index 40 and the rail was in
   flow with none, so any frame in which the two met (a slide, a stale
   cached stylesheet, a drawer opening) put the rail underneath. It now
   stacks above the toolbar, and our masthead above the rail so the
   masthead's menus still drop over both. */
body:has(#app.faith-port-read-page) .tfr-rail { position: relative; z-index: 45; }
body:has(#app.faith-port-read-page) header.site-header { z-index: 50; }

/* ── TOOLS HOLDS THE TOOLS (Ian, 2026-09-23) ─────────────────────────
   faith-port-read-drawer.js moves every tool into #frToolsDrawer, just
   before Tools, and opens it by width on the rail's own curve and
   timing (.tfr-rail-drawer in faith-received.css). Visible at rest:
   contents, title, page, Search, Tools. Desktop only; the phone's dock
   has its own drawer below. */
html:not(.g-mobile) #app .ph.fr-reader-head .ctr { position: relative; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tools-drawer {
  order: 9;
  display: flex;
  align-items: center;
  flex: 0 1 auto;
  min-width: 0;
  gap: 12px;
  width: 0;
  overflow: hidden;
  opacity: 0;
  margin-left: 0;
  transition: width 0.3s cubic-bezier(0.22, 0.61, 0.36, 1),
              opacity 0.22s ease,
              margin-left 0.3s cubic-bezier(0.22, 0.61, 0.36, 1);
}
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tools-drawer.is-open { opacity: 1; margin-left: 16px; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tools-drawer.is-open.is-settled {
  overflow-x: auto;
  scrollbar-width: none;
}
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tools-drawer::-webkit-scrollbar { display: none; }
.fr-tools-drawer[hidden] { display: none !important; }
@media (prefers-reduced-motion: reduce) {
  html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tools-drawer { transition: none; }
}
html:not(.g-mobile) #app .ph.fr-reader-head .fr-td-group { display: flex; align-items: center; flex: none; gap: 0; }
html:not(.g-mobile) #app .ph.fr-reader-head .fr-td-group:empty { display: none; }

/* Every tool in the drawer: the toolbar's hairline. */
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer button,
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer .aaw > .tgl {
  flex: none;
  height: var(--tb-h);
  min-height: var(--tb-h);
  margin: 0;
  padding: 0 12px;
  border: 1px solid var(--tb-line);
  border-radius: 0;
  background: var(--card, transparent);
  color: var(--fg);
  font: inherit;
  font-size: 13px;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
html:not(.g-mobile) #app .ph.fr-reader-head .fr-td-group > * + *,
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer .seg.lanes > button + button { margin-left: -1px; }
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer .seg.lanes { display: flex; gap: 0; padding: 0; border: 0; height: auto; background: none; overflow: visible; }
html:not(.g-mobile) #app .ph.fr-reader-head .fr-td-group > button:first-child,
html:not(.g-mobile) #app .ph.fr-reader-head .fr-td-group > .aaw:first-child > .tgl,
html:not(.g-mobile) #app .ph.fr-reader-head .fr-td-group > .seg:first-child > button:first-child { border-radius: 3px 0 0 3px; }
html:not(.g-mobile) #app .ph.fr-reader-head .fr-td-group > button:last-child,
html:not(.g-mobile) #app .ph.fr-reader-head .fr-td-group > .aaw:last-child > .tgl,
html:not(.g-mobile) #app .ph.fr-reader-head .fr-td-group > .seg:last-child > button:last-child { border-radius: 0 3px 3px 0; }
html:not(.g-mobile) #app .ph.fr-reader-head .fr-td-group > button:only-child { border-radius: 3px; }
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer button:hover,
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer .aaw > .tgl:hover {
  border-color: var(--fr-ink-hot, #b0573a);
  color: var(--fr-ink-hot, #b0573a);
  position: relative;
  z-index: 1;
}
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer [aria-pressed="true"],
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer .aaw > .tgl[aria-expanded="true"] {
  background: var(--fr-fill, #b0573a);
  border-color: var(--fr-fill, #b0573a);
  color: var(--fr-fill-ink, #fff);
  position: relative;
  z-index: 2;
}
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer button:disabled { opacity: 0.45; cursor: default; }
/* The old menu items keep their label and drop the description, which
   became their tooltip. */
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer .rdt > span { display: none; }
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer .rdt > span.rdt-l { display: inline; }
/* Research stays the one accent, now at the end of the drawer. */
html:not(.g-mobile) #app .ph.fr-reader-head .fr-td-research #nbCount { border-radius: 3px; }
/* Aa's menu is anchored to the bar, not the drawer, so the drawer's
   clip never cuts it. */
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer .aaw { position: static; display: flex; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr .aapop { top: calc(100% + 8px); right: 0; }
html:not(.g-mobile) #rdToolsPop { display: none !important; }

/* Search and Tools, the two at rest. */
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > #rsBtn { margin-left: 16px; border-radius: 3px; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .rdtw { margin-left: 16px; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .rdtw > .tgl { border-radius: 3px; }
html:not(.g-mobile) #app .ph.fr-reader-head #rdTools.fr-td-toggle { display: inline-flex; align-items: center; gap: 0; }
html:not(.g-mobile) #app .ph.fr-reader-head #rdTools.fr-td-toggle::after {
  content: "";
  display: inline-block;
  width: 5px;
  height: 5px;
  margin-left: 8px;
  border-right: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  transform: rotate(135deg);
  transition: transform 0.2s cubic-bezier(0.22, 0.61, 0.36, 1);
}
html:not(.g-mobile) #app .ph.fr-reader-head #rdTools.fr-td-toggle[aria-expanded="true"]::after { transform: rotate(-45deg); }
html:not(.g-mobile) #app .ph.fr-reader-head #rdTools.fr-td-toggle[aria-expanded="true"] {
  border-color: var(--fr-ink-hot, #b0573a);
  color: var(--fr-ink-hot, #b0573a);
}

/* While the drawer is open the page controls fold away, on the same
   curve, and the title gives way. */
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.pnav,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .seg.pgjump {
  max-width: 260px;
  transition: max-width 0.3s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.22s ease;
}
html:not(.g-mobile) #app .ph.fr-reader-head.fr-tools-open .ctr > .seg.pnav,
html:not(.g-mobile) #app .ph.fr-reader-head.fr-tools-open .ctr > .seg.pgjump {
  max-width: 0;
  opacity: 0;
  overflow: hidden;
  padding: 0;
  border-width: 0 !important;
  margin: 0;
}
html:not(.g-mobile) #app .ph.fr-reader-head .reader-identity { transition: opacity 0.22s ease; }

/* The copy feedback, as a toast under the bar or over the dock. */
.fr-td-say {
  position: fixed;
  left: 50%;
  top: calc(var(--mo-head, 61px) + var(--phh, 64px) + 10px);
  transform: translateX(-50%);
  z-index: 10040;
  margin: 0;
  padding: 7px 14px;
  border: 1px solid var(--border, #d9c6a7);
  border-radius: 3px;
  background: var(--card, #fffdfa);
  color: var(--fg, #2d2927);
  font-size: 13px;
  pointer-events: none;
}
.fr-td-say:empty { display: none; }
html.g-mobile .fr-td-say { top: auto; bottom: calc(76px + env(safe-area-inset-bottom)); }

/* ── THE PHONE'S DOCK: CONTENTS, SEARCH, TOOLS ───────────────────────
   Three cells at rest. Tools reveals a drawer that lies over Contents
   and Search (faith-port-read-drawer.js sets its right edge at Tools),
   unrolled leftward out of Tools by clip-path on the rail's curve.
   Nothing in the dock changes size, so nothing re-lays out while it
   moves. The drawer scrolls sideways. */
html.g-mobile nav.frthumb.fr-m3 {
  overflow: visible;
  justify-content: space-around;
  gap: 0;
  padding-left: 6px;
  padding-right: 6px;
}
html.g-mobile nav.frthumb.fr-m3 > button { flex: 1 1 0; min-width: 0; transition: opacity 0.22s ease; }
html.g-mobile nav.frthumb.fr-m3.fr-m3-open > [data-t="toc"],
html.g-mobile nav.frthumb.fr-m3.fr-m3-open > [data-t="find"] { opacity: 0; pointer-events: none; }
html.g-mobile nav.frthumb.fr-m3 > .fr-mtools-drawer {
  min-width: 0;
  width: auto;
  position: absolute;
  left: 0;
  top: 0;
  bottom: env(safe-area-inset-bottom, 0px);
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 3px 4px 3px 8px;
  background: var(--card-bg, var(--card, #fffdfa));
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  clip-path: inset(0 0 0 100%);
  visibility: hidden;
  transition: clip-path 0.3s cubic-bezier(0.22, 0.61, 0.36, 1), visibility 0s linear 0.3s;
  will-change: clip-path;
}
html.g-mobile nav.frthumb.fr-m3 > .fr-mtools-drawer.is-open {
  clip-path: inset(0 0 0 0);
  visibility: visible;
  transition: clip-path 0.3s cubic-bezier(0.22, 0.61, 0.36, 1), visibility 0s;
}
html.g-mobile nav.frthumb.fr-m3 > .fr-mtools-drawer::-webkit-scrollbar { display: none; }
html.g-mobile nav.frthumb.fr-m3 .fr-mtools-drawer > button {
  flex: 0 0 auto;
  min-width: 60px;
  padding: 5px 6px;
}
html.g-mobile nav.frthumb.fr-m3 .fr-mtools-drawer > button[hidden] { display: none; }
html.g-mobile nav.frthumb.fr-m3 .fr-mtools-drawer > button:disabled { opacity: 0.45; }
html.g-mobile nav.frthumb.fr-m3 .fr-mtools-drawer #aaBtn.frthumb-aa { border: 0; background: none; }
/* A hairline where the drawer meets Tools, so the edge reads. */
html.g-mobile nav.frthumb.fr-m3 > .fr-mtools-drawer.is-open { box-shadow: inset -1px 0 0 var(--border, #d9c6a7); }
@media (prefers-reduced-motion: reduce) {
  html.g-mobile nav.frthumb.fr-m3 > button,
  html.g-mobile nav.frthumb.fr-m3 > .fr-mtools-drawer { transition: none; }
}

/* ── THE PHONE READER DOES NOT MOVE ITS BOX (Ian, 2026-09-23) ────────
   "everything on mobile is super jumpy ... Scrolling. The navrail
   still moves behind the top." Hiding the chrome on a phone animated
   the body's and #app's padding and the page's height: the whole reader
   re-laid out every frame for .28s, and reader-core's keep-your-place
   observer (it watches the scroller's top edge) wrote scrollTop on every
   one of those frames, against the reader's own momentum. On a phone
   the page is now the whole screen from the top, fixed chrome lies over
   it, and the scroller starts its text below the chrome with its own
   padding. Hiding and showing are transforms only: the masthead up by
   its height, the rail up by the masthead's (so it pins at the top,
   above everything), the toolbar up and out behind the rail. The
   scroller's box never moves, so the observer never corrects, and
   nothing lays out while the chrome slides. */
html.g-mobile body:has(#app.faith-port-read-page) { padding-top: 0 !important; }
html.g-mobile #app.faith-port-read-page,
html.g-mobile.mh-hide #app.faith-port-read-page,
html.g-mobile.mh-mini #app.faith-port-read-page { height: 100dvh; padding-top: 0; transition: none; }
html.g-mobile body:has(#app.faith-port-read-page),
html.g-mobile #app.faith-port-read-page { transition: none; }
html.g-mobile #app.faith-port-read-page #scroll {
  padding-top: calc(var(--mo-head, 61px) + var(--phh, 56px));
  scroll-padding-top: calc(var(--mo-head, 61px) + var(--phh, 56px));
}
html.g-mobile body:has(#app.faith-port-read-page) .tfr-rail {
  position: fixed;
  top: var(--mo-mast, 61px);
  left: 0;
  right: 0;
  z-index: 45;
  transition: transform 0.28s var(--ease, cubic-bezier(0.22, 1, 0.36, 1));
  will-change: transform;
}
html.g-mobile.mh-hide body:has(#app.faith-port-read-page) .tfr-rail,
html.g-mobile.mh-mini body:has(#app.faith-port-read-page) .tfr-rail {
  transform: translateY(calc(-1 * var(--mo-mast, 61px)));
}
/* NO will-change ON THE TOOLBAR. It makes the toolbar the containing
   block for its fixed descendants, and the Aa panel is one: it was
   placed from the toolbar's top instead of the screen's and its height
   cap measured from the wrong line, so it ran off the bottom of a phone
   (Ian, 2026-09-23). The rail has none inside it and keeps the hint. */
@media (prefers-reduced-motion: reduce) {
  html.g-mobile body:has(#app.faith-port-read-page) .tfr-rail { transition: none; }
}

/* ── TRANSPARENCY, IN THE MIDDLE OF THE SCREEN (phone) ───────────────
   The disclosure panel moves into this dialog on a phone. The scrim
   stops at the dock, so Transparency can be pressed again to close it. */
.fr-tt-modal[hidden] { display: none; }
.fr-tt-modal { position: fixed; inset: 0; z-index: 57; display: flex; align-items: center; justify-content: center; padding: 20px 16px calc(84px + env(safe-area-inset-bottom)); }
.fr-tt-scrim { position: absolute; inset: 0; background: rgba(34, 35, 32, 0.45); }
.fr-tt-box {
  position: relative;
  width: 100%;
  max-width: 460px;
  max-height: 100%;
  overflow-y: auto;
  border: 1px solid var(--border, #d9c6a7);
  border-radius: 4px;
  background: var(--card, #fffdfa);
  color: var(--fg, #2d2927);
  padding: 44px 16px 16px;
}
.fr-tt-x {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border, #d9c6a7);
  border-radius: 3px;
  background: var(--card, #fffdfa);
  color: var(--fg, #2d2927);
  font: 20px/1 Georgia, serif;
  padding: 0 0 2px;
  cursor: pointer;
}
.fr-tt-box .faith-reader-status { margin: 0; }
.fr-tt-box .faith-reader-status[hidden] { display: block; }
html.g-mobile.fr-tt-modal-open nav.frthumb { z-index: 58; }

/* Desktop drawer, fitted: the title gives way while the tools are out,
   and the drawer's buttons sit a little closer, so the whole set fits a
   1280px bar without scrolling. When English is the only reading it is
   a label, not a pressed button (as it was on the bar). */
html:not(.g-mobile) #app .ph.fr-reader-head.fr-tools-open .reader-identity { opacity: 0; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tools-drawer { gap: 10px; }
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer button,
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer .aaw > .tgl { padding: 0 10px; }
html:not(.g-mobile) #app.only-en .ph.fr-reader-head .fr-tools-drawer #m-en {
  border-color: transparent;
  background: transparent;
  color: var(--muted);
  pointer-events: none;
  padding: 0 6px 0 0;
}
html:not(.g-mobile) #app.only-en .ph.fr-reader-head .fr-tools-drawer #m-en + button { margin-left: 0; border-radius: 3px 0 0 3px; }

/* Aa is a default button again, joined to Tools (Ian, 2026-09-23:
   "break out Aa tools to be a 4th default button"). Desktop: Search,
   then the drawer when open, then Aa | Tools. Phone: Contents, Search,
   Text, Tools; the open drawer lies over the first three. */
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tools-drawer { order: 8; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .aaw:not(.rdtw) { order: 9; margin-left: 16px; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .aaw:not(.rdtw) > .tgl { border-radius: 3px 0 0 3px; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .rdtw { order: 10; margin-left: -1px; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .rdtw > .tgl { border-radius: 0 3px 3px 0; }
html.g-mobile nav.frthumb.fr-m3.fr-m3-open > #aaBtn { opacity: 0; pointer-events: none; }

/* One language button (Ian, 2026-09-23): English only, Latin/Greek only,
   Both. faith-port-read-drawer.js drives the engine's own lanes; the
   engine's two lane buttons stay in the DOM, out of sight, because
   other code reads them. */
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer .seg.lanes { display: none !important; }
html.g-mobile nav.frthumb.fr-m3 .fr-mtools-drawer > [data-t="en"],
html.g-mobile nav.frthumb.fr-m3 .fr-mtools-drawer > [data-t="par"] { display: none !important; }
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer .fr-td-lang { min-width: 108px; justify-content: center; }
.fr-td-lang[hidden], .fr-td-scan[hidden] { display: none !important; }

/* The phone's panels start under the chrome that is showing (Ian,
   2026-09-23, QA): with the page now full-screen under fixed chrome the
   contents drawer, placed from #app's top, began under the rail and its
   close button could not be pressed. Below the chrome at rest; below
   the rail alone when the chrome has scrolled away. */
html.g-mobile #app.faith-port-read-page .sidebar {
  top: calc(var(--mo-head, 61px) + var(--fr-ph-h, 56px));
}
html.g-mobile.mh-hide #app.faith-port-read-page .sidebar,
html.g-mobile.mh-mini #app.faith-port-read-page .sidebar { top: var(--fr-rail-h, 0px); }
html.g-mobile.mh-hide #sbScrim,
html.g-mobile.mh-hide .nb-scrim,
html.g-mobile.mh-hide #notebook.notebook,
html.g-mobile.mh-hide aside.relpanel { top: var(--fr-rail-h, 0px); }

/* ── THE RAIL IS FIXED TO THE TOP OF THE TOOLBAR (Ian, 2026-09-23) ────
   "The navrail should always be affixed to the top of the toolbar." On a
   phone the toolbar used to leave by its own height plus the masthead's
   while the rail rose by the masthead's alone, so the two crossed on
   the way out and back. Now the toolbar rises by exactly what the rail
   does: they move as one piece, and the toolbar stays under the rail,
   as it does on a desktop. The dock at the bottom still leaves. */
html.g-mobile.mh-hide:not(.fr-bar-hidden) #app .ph.fr-reader-head,
html.g-mobile.mh-mini:not(.fr-bar-hidden) #app .ph.fr-reader-head {
  transform: translateY(calc(-1 * var(--mo-mast, 61px)));
}
html.g-mobile.mh-hide #app.faith-port-read-page .sidebar,
html.g-mobile.mh-mini #app.faith-port-read-page .sidebar {
  top: calc(var(--fr-rail-h, 0px) + var(--fr-ph-h, 56px));
}

/* Theme and Flow/Pages are tools now (the bar's drawer, the dock's
   drawer); the Aa panel keeps text settings only. */
#app .aapop .aarow:has(#th),
#app .aapop .aarow:has(#readerFlowView) { display: none; }

/* ── NOTHING MOVES WHILE THE PAGE LOADS (Ian, 2026-09-23) ─────────────
   "Loading needs to happen near instantly and without any jumpiness."
   The tools used to paint on the bar and then vanish into the drawer
   when faith-port-read-drawer.js ran at the end of the page, and the
   dock painted seven buttons before becoming four. Until they are moved
   they are not drawn: a tool is hidden while it is still a direct child
   of the bar, and the dock is invisible until it has its final shape. */
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > :is(.seg.lanes, #m-modern, #rdFlow, #rdRel, #thTop, #frAuth, .fr-tb-focus, .fr-tb-report, .fr-tb-top, .fr-tb-folds, .fr-tb-paras, .fr-tb-ednotes) { display: none; }
html.g-mobile nav.frthumb:not(.fr-m3) { visibility: hidden; }

/* A FOLDED PLACEHOLDER IS PARKED, NOT HIDDEN. The reader loads an
   unloaded page (.fph) when it is near the viewport, and its scroll
   fallback measures each placeholder's box to decide. display:none gives
   a zero box at the top of the screen, which reads as "near": the first
   scroll after Collapse all loaded every folded page of a long work.
   Parked far above the column, a folded placeholder is never near. */
#reading .fph.fr-sec-hid {
  display: block !important;
  position: absolute !important;
  top: -400000px !important;
  left: 0 !important;
  width: 1px !important;
  visibility: hidden !important;
  pointer-events: none !important;
}

/* Transparency on the desktop bar (Ian, 2026-09-23). The button sits
   before Search; its dialog opens under the toolbar, so the toolbar,
   Transparency included, stays pressable to close it. */
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tb-tt { order: 5; margin-left: 16px; border-radius: 3px; cursor: pointer; font: inherit; font-size: 13px; }
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tb-tt:hover,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > .fr-tb-tt[aria-expanded="true"] { border-color: var(--fr-ink-hot, #b0573a); color: var(--fr-ink-hot, #b0573a); }
.fr-tb-tt[hidden] { display: none !important; }
html:not(.g-mobile) .fr-tt-modal {
  z-index: 39;
  top: calc(var(--mo-head, 61px) + var(--fr-ph-h, 67px));
  padding: 32px 24px;
}
html:not(.g-mobile) .fr-tt-box { max-width: 560px; }
html.g-mobile .fr-tb-tt { display: none !important; }

/* The About dialog sits in the middle of the screen (Ian, 2026-09-23:
   "not in the weird top third"). margin:auto rather than align-items,
   so a box taller than the screen still starts at the top and scrolls.
   Above every reader layer, rail and masthead included. */
#aboutOv.about-ov { z-index: 10045; align-items: flex-start; }
#aboutOv.about-ov > .about-box { margin: auto; }

/* Expand contents takes the page (Ian, 2026-09-23): fixed across the
   whole window under the toolbar, over the sidebar and the text, with
   the outline spread in columns across the width. Top-level parts are
   headings across the grid. */
html:not(.g-mobile) .fr-read-toc {
  position: fixed;
  inset: calc(var(--mo-head, 61px) + var(--fr-ph-h, 67px)) 0 0 0;
  z-index: 35;
  padding: 24px clamp(20px, 4vw, 56px) 72px;
}
html:not(.g-mobile).mh-mini .fr-read-toc { top: calc(var(--fr-rail-h, 0px) + var(--fr-ph-h, 67px)); }
html:not(.g-mobile).fr-bar-hidden .fr-read-toc { top: 0; }
.fr-read-toc-grid { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; }
.fr-read-toc-grid > .fr-read-toc-part {
  grid-column: 1 / -1;
  margin: 14px 0 0;
  padding: 0 0 8px;
  border-bottom: 1px solid var(--border, #d9c6a7);
  font-size: 19px;
  font-weight: 500;
}
.fr-read-toc-grid > .fr-read-toc-part:first-child { margin-top: 0; }

/* ── THE CONTENTS SIDEBAR, THIN-LINE (Ian, 2026-09-23) ───────────────
   "Redo this sidebar to be in line with our new design style." Same
   pieces, the toolbar's grammar:
   - Expand contents is a hairline button, not a caption;
   - the Outline / Pages / Index / Library tabs are one joined group,
     the open tab filled, as the Research panel's tabs are;
   - the search field is a hairline box and Expand all / Collapse all /
     Show current a joined row of small buttons instead of underlined
     words;
   - the entry count is a small-caps note, and entries are set a size
     down with room between them. Desktop; the phone's drawer keeps its
     48px targets. */
html:not(.g-mobile) #app aside.sidebar {
  --sb-line: var(--border, #d9c6a7);
  --sb-fill: var(--fr-fill, #b0573a);
  --sb-fill-ink: var(--fr-fill-ink, #fff);
}
html:not(.g-mobile) #app aside.sidebar .fr-sb-actions { padding: 14px 16px 0; }
html:not(.g-mobile) #app aside.sidebar .fr-sb-actions .fr-read-fold {
  width: 100%;
  height: 32px;
  border: 1px solid var(--sb-line);
  border-radius: 3px;
  background: var(--card, #fffdfa);
  color: var(--fg);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  padding: 0 12px;
}
html:not(.g-mobile) #app aside.sidebar .fr-sb-actions .fr-read-fold:hover { border-color: var(--sb-fill); color: var(--sb-fill); }
html:not(.g-mobile) #app aside.sidebar #nav .nav-vt {
  gap: 0;
  margin: 12px 0 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: var(--sidebar-bg, var(--sidebar));
}
html:not(.g-mobile) #app aside.sidebar #nav .nav-vt button {
  flex: 1 1 0;
  min-width: 0;
  height: 30px;
  padding: 0 4px;
  border: 1px solid var(--sb-line);
  border-radius: 0;
  background: var(--card, #fffdfa);
  color: var(--fg);
  font: 12.5px/1 var(--font-body, "Source Serif Pro", Georgia, serif);
  letter-spacing: 0;
  box-shadow: none;
}
html:not(.g-mobile) #app aside.sidebar #nav .nav-vt button + button { margin-left: -1px; }
html:not(.g-mobile) #app aside.sidebar #nav .nav-vt button:first-child { border-radius: 3px 0 0 3px; }
html:not(.g-mobile) #app aside.sidebar #nav .nav-vt button:last-child { border-radius: 0 3px 3px 0; }
html:not(.g-mobile) #app aside.sidebar #nav .nav-vt button:hover:not(.on) { border-color: var(--sb-fill); color: var(--sb-fill); position: relative; z-index: 1; }
html:not(.g-mobile) #app aside.sidebar #nav .nav-vt button.on {
  background: var(--sb-fill);
  border-color: var(--sb-fill);
  color: var(--sb-fill-ink);
  position: relative;
  z-index: 2;
}
html:not(.g-mobile) #app aside.sidebar #nav .rc-contents-tools {
  padding: 12px 0 12px;
  margin: 0 0 10px;
  border-bottom: 1px solid var(--sb-line);
}
html:not(.g-mobile) #app aside.sidebar #nav .rc-contents-label input {
  min-height: 0;
  height: 34px;
  padding: 0 10px;
  border: 1px solid var(--sb-line);
  border-radius: 3px;
  background: var(--card, #fffdfa);
  font-size: 14px;
}
html:not(.g-mobile) #app aside.sidebar #nav .rc-contents-label input:focus-visible { outline: none; border-color: var(--sb-fill); }
html:not(.g-mobile) #app aside.sidebar #nav .rc-contents-actions { gap: 0; flex-wrap: nowrap; margin-top: 8px; }
html:not(.g-mobile) #app aside.sidebar #nav .rc-contents-actions button {
  flex: 1 1 auto;
  min-height: 0;
  height: 28px;
  padding: 0 8px;
  border: 1px solid var(--sb-line);
  border-radius: 0;
  background: var(--card, #fffdfa);
  color: var(--fg);
  font-size: 12px;
  text-decoration: none;
  white-space: nowrap;
}
html:not(.g-mobile) #app aside.sidebar #nav .rc-contents-actions button + button { margin-left: -1px; }
html:not(.g-mobile) #app aside.sidebar #nav .rc-contents-actions button:first-child { border-radius: 3px 0 0 3px; }
html:not(.g-mobile) #app aside.sidebar #nav .rc-contents-actions button:last-child { border-radius: 0 3px 3px 0; }
html:not(.g-mobile) #app aside.sidebar #nav .rc-contents-actions button:hover:not(:disabled) { border-color: var(--sb-fill); color: var(--sb-fill); position: relative; z-index: 1; }
html:not(.g-mobile) #app aside.sidebar #nav .rc-contents-actions button:disabled { color: var(--muted); opacity: 0.6; }
html:not(.g-mobile) #app aside.sidebar #nav .rc-contents-count {
  margin: 10px 0 0;
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}
html:not(.g-mobile) #app aside.sidebar #nav .nav-node .nn-t { font-size: 14px; line-height: 1.4; }
html:not(.g-mobile) #app aside.sidebar #nav .nav-node { padding-top: 5px; padding-bottom: 5px; }

/* Bookmark (was "Keep this work"): the icon beside its label, filled
   once the work is bookmarked. */
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer #rdKeep > span.rdt-ic { display: inline-flex; }
#rdKeep .rdt-ic svg { display: block; }
#rdKeep[aria-pressed="true"] .rdt-ic path { fill: currentColor; }
html.g-mobile nav.frthumb [data-t="x-keep"].on .ic path { fill: currentColor; }

/* The words a passage link points at (faith-port-read-passage-link.js). */
::highlight(fr-passage-link) { background-color: rgba(193, 89, 60, 0.28); color: inherit; }

/* ── DESKTOP: THE RAIL IS FIXED TOO (Ian, 2026-09-23) ─────────────────
   "The navbar still isn't fixed to the top of the toolbar and it
   scrolls behind it at the top of the page." On a desktop the rail was
   the one piece of chrome in the page's flow: the masthead and toolbar
   are fixed and move by transform, the rail moved by the body's padding
   animating, which is layout, a frame behind the compositor, and any
   scroll or elastic bounce of the page itself carried the rail under
   the fixed bars. Now it is fixed under the masthead and moves by the
   same transform, on the same curve and time, as the masthead and the
   toolbar; #app keeps its place below it with a margin; and the reader
   page itself cannot scroll or bounce (the text scrolls in #scroll). */
html:not(.g-mobile):has(#app.faith-port-read-page),
html:not(.g-mobile) body:has(#app.faith-port-read-page) { overflow: hidden; overscroll-behavior: none; }
html:not(.g-mobile) body:has(#app.faith-port-read-page) .tfr-rail {
  position: fixed;
  top: var(--mo-mast, 61px);
  left: 0;
  right: 0;
  z-index: 45;
  transition: transform 0.28s var(--ease, cubic-bezier(0.22, 1, 0.36, 1));
}
html:not(.g-mobile).mh-mini body:has(#app.faith-port-read-page) .tfr-rail,
html:not(.g-mobile).mh-hide body:has(#app.faith-port-read-page) .tfr-rail {
  transform: translateY(calc(-1 * var(--mo-mast, 61px)));
}
html:not(.g-mobile) #app.faith-port-read-page { margin-top: var(--fr-rail-h, 0px); }
@media (prefers-reduced-motion: reduce) {
  html:not(.g-mobile) body:has(#app.faith-port-read-page) .tfr-rail { transition: none; }
}

/* PRESSED STAYS READABLE UNDER THE POINTER (Ian, 2026-09-23: "text
   unreadable when selected and hovering"). The hover rules paint the
   text terracotta, and on a pressed button that is terracotta on a
   terracotta fill. A pressed or selected control keeps its fill ink and
   darkens a step on hover. Selectors restate the pressed rules plus
   :hover, so they outrank both. */
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer [aria-pressed="true"]:hover,
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer .aaw > .tgl[aria-expanded="true"]:hover,
html:not(.g-mobile) #app .ph.fr-reader-head .ctr > [aria-pressed="true"]:hover,
html:not(.g-mobile) #app .reader-witnesses [role="group"] > button[aria-pressed="true"]:hover,
html #notebook .nb-tabs button[aria-selected="true"]:hover,
html #notebook .nb-reading-place #nbSaveWork[aria-pressed="true"]:hover {
  background: color-mix(in srgb, var(--fr-fill, #b0573a) 82%, #000);
  border-color: color-mix(in srgb, var(--fr-fill, #b0573a) 82%, #000);
  color: var(--fr-fill-ink, #fff);
}

/* The dock's own Ask is replaced by the drawer's gated Ask cell. */
html.g-mobile nav.frthumb.fr-m3 .fr-mtools-drawer > [data-t="ask"] { display: none !important; }
.fr-para-rail button svg { display: block; }

/* ── ASK BESIDE THE BOOK (Ian, 2026-09-23) ───────────────────────────
   "Header too big. Margin too big. Question box too big. Needs to be in
   new design style." and "Ask should expand with the same color mode as
   the page." On the reader, Ask's colours are the reader's own tokens,
   so it opens in whatever the page is in: light, sepia or dark. Its own
   saved theme and the OS preference no longer decide it. The selector
   carries two ids' weight to beat ask-workspace.css's
   `:root[data-theme] :is(.fra, #fra-notices)` (1,2,0).
   Sizes: a working title in the reading face, not a 52px display
   headline; the welcome's margins cut; the question box a hairline box
   with 3px corners and a shorter field. */
html:not(#fr-x) body:has(#app.faith-port-read-page) .fra,
html:not(#fr-x) body:has(#app.faith-port-read-page) .fra[data-theme] {
  --fra-bg: var(--bg);
  --fra-card: var(--card, var(--card-bg));
  --fra-fg: var(--fg);
  --fra-muted: var(--muted);
  --fra-border: var(--border);
  --fra-hl: var(--hl, var(--highlight));
  --fra-detail: var(--muted);
  --fra-detail-rule: var(--border);
  color-scheme: inherit;
}
body:has(#app.faith-port-read-page) .fra .fra-header { min-height: 0; padding: 4px 8px; }
body:has(#app.faith-port-read-page) .fra .fra-welcome { padding: 18px 0 20px; justify-content: flex-start; }
body:has(#app.faith-port-read-page) .fra .fra-welcome h1 {
  font: 500 22px/1.25 var(--font-body, "Source Serif Pro", Georgia, serif);
  letter-spacing: 0;
  margin: 0 0 6px;
}
body:has(#app.faith-port-read-page) .fra .fra-welcome p { font-size: 14px; line-height: 1.5; margin: 0 0 14px; max-width: none; }
body:has(#app.faith-port-read-page) .fra .fra-suggestions { margin-top: 8px; }
body:has(#app.faith-port-read-page) .fra .fra-suggestions button { padding: 9px 8px; font-size: 13px; }
body:has(#app.faith-port-read-page) .fra .fra-compose-area { padding: 8px 14px 10px; }
body:has(#app.faith-port-read-page) .fra .fra-composer {
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 8px 10px 6px;
  box-shadow: none;
}
body:has(#app.faith-port-read-page) .fra .fra-compose-label {
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 0 2px 2px;
}
body:has(#app.faith-port-read-page) .fra .fra-composer textarea {
  min-height: 44px;
  font-size: 15px;
  line-height: 1.45;
  padding: 4px 2px;
}
body:has(#app.faith-port-read-page) .fra .fra-compose-tools { margin-top: 2px; }
body:has(#app.faith-port-read-page) .fra .fra-send { width: 32px; height: 32px; min-height: 32px; border-radius: 3px; }
body:has(#app.faith-port-read-page) .fra .fra-compose-foot { margin-top: 4px; padding-top: 4px; }

/* The subscribe pop-up (feature-gate.js) over every reader layer: the
   toolbar rises to 10030 with a menu open, Research is 10020. */
body:has(#app.faith-port-read-page) .feature-gate-modal { z-index: 10060; }
/* Our Ask skin (faith-ask-workspace.css) paints with the SITE tokens,
   not Ask's own: --color-page for grounds, --color-dark for ink,
   --color-cream for marks. Inside Ask on the reader those tokens are the
   reader's theme, so every surface in it follows the page. */
html:not(#fr-x) body:has(#app.faith-port-read-page) .fra {
  --color-page: var(--card, var(--card-bg));
  --color-white: var(--card, var(--card-bg));
  --color-dark: var(--fg);
  --color-muted: var(--muted);
  --color-cream: var(--hl, var(--highlight));
  --color-card-border: var(--border);
  --color-rule: var(--border);
}

/* Split paragraphs (faith-port-read-paragraphs.js): each piece is a clone
   of its paragraph, so it takes the text's own paragraph style. */
html.g-mobile .fr-tb-paras { display: none !important; }

/* ── THE PRAYER BOOK (1928 BCP) ──────────────────────────────────────
   Ian, 2026-09-24: "clean up its format to make it more intuitive as a
   BCP." A work whose meta carries `liturgy: true` puts .liturgy on #app
   (reader-core.js, beside .flow), and its page markdown uses emphasis for
   one thing each (scripts/build-english-editions-pages.mjs, liturgyRow):
   italic is a rubric, the book's directions, printed red in a prayer
   book and set here in the terracotta ink, a step smaller; bold is the
   people's part in a versicle, a litany or a vow. Its headings take
   the tiers in "SECTION HEADINGS: ONE HIERARCHY" at the end of this file
   (an office is a card, what sits inside it a hairline or a plain head).
   Prose is not indented, as a prayer book sets it. */
#app.liturgy #reading .en em {
  font-size: 0.9em;
  color: var(--fr-ink-hot, #a4503a);
}
#app.liturgy #reading .en strong { font-weight: 600; }
#app.liturgy #reading .en p { text-indent: 0; }
/* Psalms, canticles and versicles are verse lines ("| " in the page
   markdown). The reader stacks a page's rows into one column
   (.stkwrap), which lifts the cells out of .row.rverse and with them the
   hanging indent read.in01.css gives .vl there; set it again on the cell. */
#app.liturgy #reading .en .verse { padding: 0.15em 0; }
#app.liturgy #reading .en .verse .vl {
  display: block;
  line-height: 1.5;
  padding-left: 1.4em;
  text-indent: -1.4em;
}
/* The people's answer to a petition sits in from the petition's own
   turned lines, so the two never read as one. */
#app.liturgy #reading .en .verse .vl.ind { padding-left: 2.4em; text-indent: 0; }

/* ══ SECTION HEADINGS: ONE HIERARCHY (Ian, 2026-09-24) ═══════════════
   "I like the little boxes you've been using ... There still just seems
   to be some inconsistency about what is a header, subheader, and
   eyebrow." faith-port-read-headings.js splits every heading into its
   parts and gives it a tier; this sets each part ONE way everywhere:

     EYEBROW   .fr-hd-eye    11.5px caps, 0.22em, terracotta ink; group
                             separators print as " · "
     TITLE     .fr-hd-title  the reading face at 600, never caps or
                             small caps (capitals recased word by word)
     SUBTITLE  .fr-hd-sub    italic, muted
     ARGUMENT  .fr-hd-arg    italic, muted, the terracotta rule at left

   and each tier one way:

     .fr-hd-card  the top of the outline (book, part, article, chapter,
                  homily, Lord's Day, an office of the prayer book): the
                  TFR thin-line box, as the Topics page sets its head.
                  A title, subtitle or argument printed as its own line
                  continues the box below it, the two joined like the
                  toolbar's button groups (.fr-hd-open + .fr-hd-cont).
     .fr-hd-t2    what sits under those (an office's psalms and
                  collects, sections, heads the outline does not list):
                  a tan hairline over eyebrow and title.
     .fr-hd-t3    the most numerous (a catechism's questions, the
                  prayer book's inner heads): eyebrow and title, no rule.

   Every box sits on the reading column's own edges: the heading element
   is the lane's own content (a p or h3 inside .en/.la) or, where the
   engine puts the h3 straight in the row, sized to the lane's measure.
   The fold caret is placed inside the box by anchor positioning, so it
   follows the box in every lane mode without a measurement.

   The face is the reading face (--fr-read-font, the Aa control's choice),
   not the engine's --font-body, which is EB Garamond in this reader: the
   headings are the text's own, and an h3 in its own row measures its 66ch
   in the same face as the lane, so its box and the text share an edge. */

#app #reading .fr-hd {
  text-align: left !important;
  text-indent: 0 !important;
  font-family: var(--fr-read-font, "Source Serif Pro", Georgia, serif);
  font-weight: 400;
  font-style: normal;
  letter-spacing: 0;
  text-transform: none;
  color: var(--fg);
  line-height: 1.3;
  box-shadow: none;
}
/* An h3 the engine puts straight in its row (the curated confessions,
   the catechisms, the prayer book) takes the lane's size and measure, so
   its box lines up with the text under it: read.in01.css caps it at 66ch
   of its own size, and the English lane is 66ch at 1.04em x --ensz. */
#app #reading h3.fr-hd { font-size: 1em; }
#app #reading .row.rhead > h3.fr-hd { font-size: calc(1.04em * var(--ensz, 1)); }
/* The engine's short rules above and below a main head (read.in01.css,
   .hmain .csub::before/::after) would sit inside the box. */
#app #reading .row.rhead h3.fr-hd::before,
#app #reading .row.rhead h3.fr-hd::after { content: none; display: none; }
/* Its own row carries no margin of its own; the tier sets the room. */
#app #reading .row.rhead:has(> h3.fr-hd),
#app #reading .row.fr-sec-headrow { margin-top: 0; }
#app #reading .row.rhead:has(> h3.fr-hd) { padding-top: 0.01px; }

/* ── The parts ── */
#app #reading .fr-hd .fr-hd-eye,
#app #reading .fr-hd-sublabel {
  display: block;
  margin: 0 0 0.6em;
  font: 600 11.5px/1.45 var(--fr-read-font, "Source Serif Pro", Georgia, serif);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--fr-ink-hot, var(--color-secondary, #c1593c));
}
#app #reading .fr-hd .fr-hd-eye * {
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
}
#app #reading .fr-hd.fr-hd-labelonly .fr-hd-eye { margin-bottom: 0; }
/* "Book I - Chapter I": the gap between groups, however it was printed
   and whatever spaces it held, is one dot with equal room either side.
   The gap's own characters are zero-width AND zero-spaced: letter-spacing
   is inherited as a length, so three hidden characters used to add three
   letter-spaces ("BOOK I  · CHAPTER I"). The letter before the dot
   brings its own 0.22em, hence the smaller margin on the left. */
#app #reading .fr-hd .fr-hd-eye .fr-hd-dot { font-size: 0; letter-spacing: 0; }
#app #reading .fr-hd .fr-hd-eye .fr-hd-dot::after {
  content: "\00B7";
  font-size: 11.5px;
  letter-spacing: 0;
  margin: 0 0.5em 0 0.28em;
}
/* A catechism question numbered bare ("1. What is ...?") reads "Q. 1",
   as the Westminster catechisms print it. Generated, not in the text. */
#app #reading .fr-hd .fr-hd-eye.fr-hd-qn::before { content: "Q.\00A0"; }
#app #reading .fr-hd .fr-hd-sep { display: none; }

#app #reading .fr-hd .fr-hd-title,
#app #reading .fr-hd-promoted:not(h3) {
  display: block;
  font-family: var(--fr-read-font, "Source Serif Pro", Georgia, serif);
  font-weight: 600;
  font-style: normal;
  font-variant: normal;
  letter-spacing: 0;
  text-transform: none;
  line-height: 1.25;
  color: var(--fg);
  text-wrap: balance;
}
#app #reading .fr-hd-promoted { text-align: left !important; text-indent: 0 !important; margin-block: 0; }
/* The engine sets all-capital runs as small caps (.capsrun); inside a
   title that made a caps title a different kind of heading from its
   neighbours. Here it is ordinary type, recased by the spans below. */
#app #reading .fr-hd .fr-hd-title .capsrun,
#app #reading .fr-hd-promoted .capsrun,
#app #reading .fr-hd-sub .capsrun.blk {
  display: inline;
  margin: 0;
  font-size: inherit;
}
#app #reading .fr-hd .fr-hd-title .capsrun,
#app #reading .fr-hd-promoted .capsrun,
#app #reading .fr-hd-sub .capsrun {
  font-variant: normal;
  text-transform: none;
  letter-spacing: 0;
}
/* Headline case for words printed in capitals (headings.js, recase):
   lowered, first letter raised; short connectives lowered whole. */
#app #reading .fr-hd-wc { display: inline-block; text-transform: lowercase; }
#app #reading .fr-hd-wc::first-letter { text-transform: uppercase; }
#app #reading .fr-hd-wl { text-transform: lowercase; }
#app #reading .fr-hd-nb { white-space: nowrap; }
/* A title the page prints wholly in italic (the Heidelberg questions)
   stands upright like every other title. */
#app #reading .fr-hd-upright :is(em, i) { font-style: normal; }

/* The same heading in two languages inside one h3: the second is a quiet
   line under the first, not a second eyebrow and title. */
#app:not(.only-la) #reading .fr-hd-bi > .hla {
  order: 2;
  margin-top: 0.35em;
  font: italic 400 0.86em/1.4 var(--fr-read-font, "Source Serif Pro", Georgia, serif);
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted);
}
#app:not(.only-la) #reading .fr-hd-bi > .hla .fr-hd-eye { display: none; }
#app:not(.only-la) #reading .fr-hd-bi > .hla .fr-hd-title { font: inherit; color: inherit; }

#app #reading .fr-hd-sub {
  text-align: left !important;
  text-indent: 0 !important;
  font-style: italic;
  font-size: 1.02em;
  line-height: 1.45;
  color: var(--muted);
  margin-block: 0.1em 1.2em;
}
#app #reading .fr-hd-arg {
  text-align: left !important;
  text-indent: 0 !important;
  font-style: italic;
  font-size: 0.94em;
  line-height: 1.6;
  color: var(--muted);
  padding-left: 1em;
  border-left: 2px solid var(--fr-ink-hot, var(--color-secondary, #c1593c));
  margin-block: 0.3em 1.6em;
}

/* ── Tier 1: the card ── */
#app #reading .fr-hd.fr-hd-card,
#app #reading .fr-hd-cont {
  background: var(--card, #fffdfa);
  border: 1px solid var(--border, #d9c6a7);
  border-radius: 3px;
}
#app #reading .fr-hd.fr-hd-card {
  padding: 16px 52px 16px 20px;
  margin-block: 2.2em 1.2em;
}
/* Sizes go on the title, not the heading element: an h3 in its own row
   is measured in its own font (66ch), so sizing it would widen its box. */
#app #reading .fr-hd-card .fr-hd-title,
#app #reading .fr-hd-promoted.fr-hd-in-card:not(h3),
#app #reading h3.fr-hd-promoted.fr-hd-in-card .fr-hd-title { font-size: 1.42em; }
/* A heading row that carries its argument after the label (CHAPTER V.--
   On the general custom ...; LIBER PRIMUS. Paganos reprehendit ...): the
   words after the label are an argument, not a title, and read lighter. */
#app #reading .row.fr-sec-headrow--long .fr-hd-card .fr-hd-title { font-size: 1.1em; line-height: 1.45; }
#app #reading .row.fr-sec-headrow--long .fr-hd-card .fr-hd-title { font-weight: 500; }
/* Opened at the bottom and continued on the line below. */
#app #reading .fr-hd.fr-hd-card.fr-hd-open {
  border-bottom-width: 0;
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  padding-bottom: 8px;
  /* Flush, whatever paragraph margin the engine's lane rules give. */
  margin-bottom: 0 !important;
}
#app #reading .fr-hd-cont {
  border-top-width: 0;
  border-top-left-radius: 0;
  border-top-right-radius: 0;
  padding: 0 52px 16px 20px;
  margin-block: 0 1.2em;
  margin-top: 0 !important;
  text-indent: 0 !important;
  text-align: left !important;
}
#app #reading .fr-hd-sub.fr-hd-cont { margin-top: 0; }
#app #reading .fr-hd-sublabel.fr-hd-cont { margin-block: 0 1.2em; padding-top: 2px; }
/* An argument inside the box keeps its terracotta rule, drawn as a
   background so the box keeps its own thin line at the edge. */
#app #reading .fr-hd-arg.fr-hd-cont {
  border-left: 1px solid var(--border, #d9c6a7);
  padding: 2px 52px 16px 36px;
  background:
    linear-gradient(var(--fr-ink-hot, #c1593c), var(--fr-ink-hot, #c1593c)) 20px 2px / 2px calc(100% - 18px) no-repeat,
    var(--card, #fffdfa);
}
/* Two rows joined: no gap between them, and in the side-by-side view both
   lanes of each row run to one height so the Latin and English boxes end
   together. The Latin lane's own rule stands aside for the box. */
#app #reading .row.fr-hd-joinrow { margin-bottom: 0 !important; padding-bottom: 0 !important; }
/* The row it continues onto folded away (a parent's fold, or a page
   whose next row has not come back yet): the card closes on its own
   line, bottom rule and corners restored (Ian, 2026-09-24: "When these
   are collapsed, the bottom line disappears. It shouldn't"). */
#app #reading .row.fr-sec-empty > .fr-sec-toggle { display: none; }
#app #reading .row.fr-hd-joinrow:has(+ .row.fr-sec-hid) .fr-hd.fr-hd-card.fr-hd-open {
  border-bottom-width: 1px;
  border-bottom-left-radius: 3px;
  border-bottom-right-radius: 3px;
  padding-bottom: 16px;
  margin-bottom: 1.2em !important;
}
#app #reading .row.fr-hd-controw { margin-top: 0 !important; padding-top: 0 !important; }
#app #reading .row.fr-hd-joinrow,
#app #reading .row.fr-hd-controw { align-items: stretch; }
/* Only side by side: in a one-lane view the other lane is display:none
   (read.in01.css), and a display here would bring it back. */
#app:not(.only-en):not(.only-la) #reading .fr-hd-lanefill { display: flex; flex-direction: column; }
#app #reading .fr-hd-lanefill > .fr-hd,
#app #reading .fr-hd-lanefill > .fr-hd-cont { flex: 1 1 auto; }
#app #reading .row > .la:has(> .fr-hd-card, > .fr-hd-cont) { border-left-color: transparent; }

/* ── Tier 2: the hairline ── */
#app #reading .fr-hd.fr-hd-t2 {
  border-top: 1px solid var(--border, #d9c6a7);
  padding: 16px 40px 0 0;
  margin-block: 2em 0.8em;
}
#app #reading .fr-hd-t2 .fr-hd-title,
#app #reading .fr-hd-promoted.fr-hd-in-t2:not(h3),
#app #reading h3.fr-hd-promoted.fr-hd-in-t2 .fr-hd-title { font-size: 1.2em; }
#app #reading .fr-hd-promoted:is(.fr-hd-in-t2, .fr-hd-in-t3) { margin-block: 0 0.8em; padding: 0 40px 0 0; }

/* ── Tier 3: the plain head ── */
#app #reading .fr-hd.fr-hd-t3 {
  padding: 0 40px 0 0;
  margin-block: 1.6em 0.45em;
}
#app #reading .fr-hd-t3 .fr-hd-eye { margin-bottom: 0.35em; }
#app #reading .fr-hd-t3 .fr-hd-title,
#app #reading .fr-hd-promoted.fr-hd-in-t3:not(h3),
#app #reading h3.fr-hd-promoted.fr-hd-in-t3 .fr-hd-title { font-size: 1.04em; line-height: 1.4; }

/* ── A division printed at the head of a paragraph ──
   (faith-port-read-headings.js, inlineDivisions.) "[ Cap. I. I, 3.]
   Liber generationis ...": the label becomes the eyebrow, on its own
   line over the paragraph, and a chapter or book takes the tier-two
   hairline above it. A section or question ("§. 1.", "Q. 1.") takes the
   eyebrow only. The paragraph stays body text: its size, its measure.
   The brackets are hidden, never removed. */
#app #reading p.fr-il { text-indent: 0 !important; }
#app #reading p.fr-il--major {
  border-top: 1px solid var(--border, #d9c6a7);
  padding-top: 16px;
  margin-top: 2em;
}
#app #reading p.fr-il--minor { margin-top: 1.4em; }
#app #reading .fr-il-eye {
  display: block;
  margin: 0 0 0.5em;
  font: 600 11.5px/1.45 var(--fr-read-font, "Source Serif Pro", Georgia, serif);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--fr-ink-hot, var(--color-secondary, #c1593c));
}
#app #reading .fr-il-eye * {
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
}
#app #reading .fr-il-br { display: none; }
:root[data-theme="sepia"] #app #reading .fr-il-eye {
  color: color-mix(in srgb, var(--fr-ink-hot, #c1593c) 86%, var(--color-dark, #2d2927));
}

/* ── The fold caret, inside the heading ──
   faith-reader-folds.js appends it to the row, which is wider than the
   reading column in single-lane views (the lane is centred at 66ch), so
   it floated off the column's right edge. Anchored to the first heading
   in the row's last visible lane, it sits in the box's top-right corner,
   level with the eyebrow, in every lane mode and at every size. Without
   anchor positioning it keeps its old place at the row's end. */
@supports (anchor-name: --a) {
  #app #reading .fr-hd-anchor { anchor-name: --fr-hd; }
  #app #reading .row.fr-sec-head:has(.fr-hd-anchor) > .fr-sec-toggle {
    position-anchor: --fr-hd;
    left: auto;
    bottom: auto;
    top: calc(anchor(top) + 8px);
    right: calc(anchor(right) + 10px);
  }
  #app #reading .row.fr-sec-head:has(.fr-hd-anchor.fr-hd-t2) > .fr-sec-toggle { top: calc(anchor(top) + 8px); right: anchor(right); }
  #app #reading .row.fr-sec-head:has(.fr-hd-anchor.fr-hd-t3) > .fr-sec-toggle { top: calc(anchor(top) - 7px); right: anchor(right); }
  /* The phone gave the whole row 40px on its right for the caret; the
     caret now sits in the heading's own right padding. */
  html.g-mobile #app #reading .fr-sec-head:has(.fr-hd-anchor) { padding-right: 0; }
  /* A label row whose fold would close nothing (headings.js) gives the
     box's one caret to the title row under it. */
  #app #reading .row.fr-hd-onecaret > .fr-sec-toggle { display: none; }
  /* A thumb's target (44px) in the heading's own right padding, centred
     on the eyebrow line. */
  html.g-mobile #app #reading .row.fr-sec-head:has(.fr-hd-anchor) > .fr-sec-toggle { width: 44px; height: 44px; }
  html.g-mobile #app #reading .row.fr-sec-head:has(.fr-hd-anchor.fr-hd-card) > .fr-sec-toggle { top: anchor(top); right: calc(anchor(right) + 4px); }
  html.g-mobile #app #reading .row.fr-sec-head:has(.fr-hd-anchor.fr-hd-t2) > .fr-sec-toggle { top: anchor(top); right: calc(anchor(right) - 4px); }
  html.g-mobile #app #reading .row.fr-sec-head:has(.fr-hd-anchor.fr-hd-t3) > .fr-sec-toggle { top: calc(anchor(top) - 14px); right: calc(anchor(right) - 4px); }
}

/* A phone's column is a third as wide: the card's title steps down so a
   long chapter title is not eight lines of display type. */
html.g-mobile #app #reading .fr-hd-card .fr-hd-title,
html.g-mobile #app #reading .fr-hd-promoted.fr-hd-in-card:not(h3),
html.g-mobile #app #reading h3.fr-hd-promoted.fr-hd-in-card .fr-hd-title { font-size: 1.24em; }
html.g-mobile #app #reading .fr-hd-t2 .fr-hd-title,
html.g-mobile #app #reading .fr-hd-promoted.fr-hd-in-t2:not(h3),
html.g-mobile #app #reading h3.fr-hd-promoted.fr-hd-in-t2 .fr-hd-title { font-size: 1.12em; }
html.g-mobile #app #reading .fr-hd.fr-hd-card { padding: 16px 52px 16px 16px; }
html.g-mobile #app #reading .fr-hd-cont { padding-left: 16px; padding-right: 52px; }
html.g-mobile #app #reading .fr-hd-arg.fr-hd-cont { padding-left: 32px; background-position: 16px 2px, 0 0; }

/* A phone shows the two languages stacked inside each row (Latin, then
   English), so a heading row's Latin box and the next row's Latin line
   are not neighbours: each heading closes its own box, and the line under
   it is set plain. Horizontal margins are never set in this block: the
   engine centres an h3 in its row with margin-inline:auto. */
html.g-mobile #app:not(.only-en):not(.only-la) #reading .fr-hd.fr-hd-card.fr-hd-open {
  border-bottom-width: 1px;
  border-radius: 3px;
  padding-bottom: 16px;
  margin-bottom: 0.8em !important;
}
html.g-mobile #app:not(.only-en):not(.only-la) #reading .fr-hd-cont {
  background: none;
  border: 0;
  padding: 0;
}
html.g-mobile #app:not(.only-en):not(.only-la) #reading .fr-hd-arg.fr-hd-cont {
  border-left: 2px solid var(--fr-ink-hot, var(--color-secondary, #c1593c));
  padding-left: 1em;
}
/* Sepia's page is darker than light's: the terracotta eyebrow measured
   4.27:1 on it (4.87:1 in a card). A step toward the house dark brings the
   eyebrow over 4.5:1 on both without leaving the terracotta. */
:root[data-theme="sepia"] #app #reading .fr-hd .fr-hd-eye,
:root[data-theme="sepia"] #app #reading .fr-hd-sublabel {
  color: color-mix(in srgb, var(--fr-ink-hot, #c1593c) 86%, var(--color-dark, #2d2927));
}

/* ── AA: READING AIDS AT THE TOP (Ian, 2026-09-24) ─────────────────────
   "Move these tools to the top of Aa." Modernize and Split paragraphs
   are moved into #frAaTools, the panel's first row, by
   faith-port-read-drawer.js (placeInAa). A joined pair across the full
   width of the panel, no label, a hairline under it to set it apart from
   the type settings. The row disappears while both buttons are hidden
   (Modernize shows only on early modern English). */
#app .aapop .aarow.aarow-tools {
  display: block;
  padding: 2px 0 10px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--border, #d9c6a7);
}
#app .aapop .aarow-tools .aaseg { display: flex; flex-wrap: nowrap; width: 100%; }
#app .aapop .aarow-tools .aaseg > .tgl { flex: 1 1 0; justify-content: center; text-align: center; white-space: nowrap; }
#app .aapop .aarow-tools .aaseg > [hidden] { display: none !important; }
#app .aapop .aarow-tools:not(:has(.aaseg > :not([hidden]))) { display: none; }
/* The phone hid Split paragraphs while it was a bar button with a dock
   cell standing in for it; in Aa it is the control itself. */
html.g-mobile #app .aapop .fr-tb-paras:not([hidden]) { display: inline-flex !important; }
/* The pair in the thin-line joined-group shape (tan rule, 3px corners,
   one divider), as it looked on the bar. */
#app .aapop .aarow-tools .aaseg {
  border: 1px solid var(--border, #d9c6a7);
  border-radius: 3px;
  overflow: hidden;
  gap: 0;
}
#app .aapop .aarow-tools .aaseg > .tgl {
  border: 0;
  border-radius: 0;
  min-height: 40px;
  padding: 8px 12px;
  margin: 0;
}
#app .aapop .aarow-tools .aaseg > .tgl:not([hidden]) ~ .tgl:not([hidden]) { border-left: 1px solid var(--border, #d9c6a7); }

/* Heading titles a step smaller (Ian, 2026-09-24: "shrink the font size
   on those headlines"). Same selectors as the heading block above, later
   so they win. Box titles 1.42 -> 1.18em, tier two 1.2 -> 1.08em. */
#app #reading .fr-hd-card .fr-hd-title,
#app #reading .fr-hd-promoted.fr-hd-in-card:not(h3),
#app #reading h3.fr-hd-promoted.fr-hd-in-card .fr-hd-title { font-size: 1.18em; }
#app #reading .row.fr-sec-headrow--long .fr-hd-card .fr-hd-title { font-size: 1.02em; }
#app #reading .fr-hd-t2 .fr-hd-title,
#app #reading .fr-hd-promoted.fr-hd-in-t2:not(h3),
#app #reading h3.fr-hd-promoted.fr-hd-in-t2 .fr-hd-title { font-size: 1.08em; }
html.g-mobile #app #reading .fr-hd-card .fr-hd-title,
html.g-mobile #app #reading .fr-hd-promoted.fr-hd-in-card:not(h3),
html.g-mobile #app #reading h3.fr-hd-promoted.fr-hd-in-card .fr-hd-title { font-size: 1.1em; }
html.g-mobile #app #reading .fr-hd-t2 .fr-hd-title,
html.g-mobile #app #reading .fr-hd-promoted.fr-hd-in-t2:not(h3),
html.g-mobile #app #reading h3.fr-hd-promoted.fr-hd-in-t2 .fr-hd-title { font-size: 1.04em; }

/* Label-driven chapters (faith-port-read-contents-overlay.js): the
   column a chapter starts on, and any verse reference printed with its
   label, under the entry. */
#nav .nav-node .nn-col {
  display: block;
  flex-basis: 100%;
  margin: 1px 0 0 1.6rem;
  font-size: 0.78em;
  font-style: italic;
  color: var(--muted, #7a6f63);
}

/* ── Front Matter group and title page (Ian, 2026-09-24) ──
   faith-reader-folds.js adds .fr-fm-row before a work's first page when
   its outline opens with the synthetic "Front Matter" group; the label
   is drawn from data-label, so it is not part of the text. A title page
   (.fr-tp, faith-port-read-headings.js) is one centred block with no
   rules or boxes between its lines. */
#app #reading .row.fr-fm-row { display: block; padding: 0; }
#app #reading .fr-fm-card {
  max-width: var(--measure, 66ch);
  margin: 1.4em auto 1.2em;
  padding: 16px 52px 16px 20px;
  background: var(--card, #fffdfa);
  border: 1px solid var(--border, #d9c6a7);
  border-radius: 3px;
  font: 400 1em/1.3 var(--fr-read-font, "Source Serif Pro", Georgia, serif);
  color: var(--ink, inherit);
}
#app #reading .fr-fm-card::before { content: attr(data-label); font-size: 1.18em; font-weight: 600; }
#app #reading .row.fr-tp .fr-tp-line,
#app #reading .row.fr-tp .fr-tp-line.fr-hd {
  border: 0 !important;
  background: none !important;
  padding: 0 !important;
  margin: 0.15em 0 !important;
  text-align: center !important;
  text-indent: 0 !important;
  font-style: normal;
}
#app #reading .row.fr-tp .fr-tp-line:first-child { margin-top: 1.2em !important; }
#app #reading .row.fr-tp .fr-tp-title,
#app #reading .row.fr-tp .fr-tp-title .fr-hd-title { font-size: 1.5em !important; font-weight: 600; line-height: 1.25; }
#app #reading .row.fr-tp .fr-tp-conn,
#app #reading .row.fr-tp .fr-tp-conn .fr-hd-title { font-size: 0.9em !important; font-style: italic; font-weight: 400; color: var(--muted, #7a6f63); }
#app #reading .row.fr-tp .fr-tp-meta,
#app #reading .row.fr-tp .fr-tp-meta .fr-hd-title { font-size: 1.08em !important; font-weight: 500; }
#app #reading .row.fr-tp .fr-tp-line .fr-hd-eye { display: none; }

/* ── ENGLISH LANE: MARKERS, VERSE, LABELS (faith-port-read-verse.js) ──
   Display only; the text in the DOM is unchanged.
   Migne's note and line markers ("myself 6 ,", "herself 16 (5) to") are
   hidden with the space they left. */
#app #reading .fr-nm { display: none; }
/* A bare "1" under "1 METRUM PRIMUM.", a repeated "METER 1 I.", and a
   book's label row once the book heads its first section's card. */
#app #reading .row.fr-vx-hide { display: none !important; }
/* The card that ran on into a hidden row closes on its own line. */
#app #reading .row.fr-hd-joinrow:has(+ .row.fr-vx-hide) .fr-hd.fr-hd-card.fr-hd-open,
#app #reading .row.fr-vx-bookhead .fr-hd.fr-hd-card.fr-hd-open {
  border-bottom-width: 1px;
  border-bottom-left-radius: 3px;
  border-bottom-right-radius: 3px;
  padding-bottom: 16px;
  margin-bottom: 1.2em !important;
}
/* The book, as its own heading above its first section's card. */
#app #reading .row.fr-vx-bookhead > [data-fr-book]::before {
  content: attr(data-fr-book);
  display: block;
  margin: 1.4em 0 0.2em;
  font: 600 1.9em/1.2 var(--fr-read-font, "Source Serif Pro", Georgia, serif);
  letter-spacing: 0;
  text-transform: none;
  color: var(--fg);
  text-align: left;
}
/* Latin labels shown in English: the original stays in the DOM. */
#app #reading .fr-trx > .fr-trx-o { display: none; }
#app #reading .fr-trx::before { content: attr(data-fr-en); }
/* The printed argument, set as every argument on the site is. */
#app #reading .fr-vx-arg {
  display: block;
  font-style: italic;
  font-size: 0.94em;
  line-height: 1.6;
  color: var(--muted);
  padding-left: 1em;
  border-left: 2px solid var(--fr-ink-hot, var(--color-secondary, #c1593c));
  margin-block: 0.3em 1.4em;
  text-indent: 0;
}
#app #reading .fr-vx-arglabel { display: none; }
#app #reading p.fr-vx-argp,
#app #reading p.fr-vx-verse { text-indent: 0 !important; text-align: left !important; }
/* Verse: one line per verse, a run-over line hanging under it. */
#app #reading .fr-vl {
  display: block;
  padding-left: 1.6em;
  text-indent: -1.6em;
}
#app #reading p.fr-vx-verse { padding-left: 0.8em; }
/* Contents: sections under their book (faith-port-read-toc-titles.js). */
#app #nav .nav-node.fr-toc-sub { padding-left: 1.5rem !important; }
@media (max-width: 760px) {
  #app #nav .nav-node.fr-toc-sub { padding-left: calc(20px + var(--nav-depth, 0) * 12px) !important; }
  #app #reading .row.fr-vx-bookhead > [data-fr-book]::before { font-size: 1.6em; }
}

/* Hide editorial notes (faith-port-read-editorial.js; Ian, 2026-09-24).
   The editors' apparatus goes; the author's text and footnotes stay. */
html.fr-hide-editorial #reading :is(section.pld-editorial, .laonly, .row.rapp, .appbank) { display: none !important; }
#app .fr-tb-ednotes[hidden], .fr-mtools-drawer [data-t="x-ednotes"][hidden] { display: none !important; }

/* The Greek Fathers' source row (#reader-witnesses) leaves the head on
   both widths (Ian, 2026-09-24: "Takes up too much space"). One button
   in Tools cycles it (faith-port-read-drawer.js), pressing the engine's
   own pills, which stay in the DOM. */
#app #reader-witnesses { display: none !important; }
html:not(.g-mobile) #app .ph.fr-reader-head .fr-tools-drawer .fr-td-src { min-width: 112px; justify-content: center; }
.fr-td-src[hidden], .fr-mtools-drawer [data-t="x-src"][hidden] { display: none !important; }
/* Hide editorial notes is a desktop bar button; a phone reaches it as the
   Tools cell (x-ednotes), so the bar's own stays off the phone head, as
   Report, Top, Collapse and Focus do. */
html.g-mobile .fr-tb-ednotes { display: none !important; }
