/* netword-app/css/app/shell.css
   The page, the five-band frame, the two windows and the divider between them.
   Joined first into the sheet a browser receives, so everything the members
   after it draw sits inside a box declared here. The contract below is the
   whole folder's, and is stated once where it is read first. */

/* ───────────────────────────────────────────────────────────────────────────
   THE APP SHELL'S STRUCTURE — five bands, and not one colour.

   Every colour, the chrome's font and its radii live in a brand's skin.css
   (brands/<hostname>/skin.css, and brands/default/skin.css first) as custom
   properties; these sheets reference them by name and declare none of their own.
   This is enforced rather than trusted:
   test/skinScan.test.js reads every sheet in this folder, refuses any hex
   triple, any rgb()/hsl() function and any CSS named colour, and carries a
   seeded control proving the scan goes red when one is planted. `currentColor`, `transparent` and `inherit`
   are permitted, because none of them names a colour — they name where to get
   one.

   THE LINE THIS SHEET MAY NOT CROSS
   No rule here may select `.reading-view`, any `.role-*` or any `.element-*`
   class. Those belong to netword-shared/css/reading.css, the PLATFORM's reading
   identity, which the App links unchanged and shares with Studio's preview by
   construction. This is Studio's own chrome/reading separation asked one level
   over, and the App is the half that makes it matter: the day the App restyled
   the reading view there would be two reading identities and only one of them
   was designed.

   MOBILE FIRST
   The audience is low-end Android phones on constrained networks. Portrait is
   the primary form and the base rules below draw it; the one media query widens
   to a side-by-side split, and there is no other breakpoint. No framework, no
   web font, no shadow the GPU has to composite on every scroll frame. Touch
   targets read one floor, `--skin-tap-min`, and it is the reason the icon
   buttons are padded rather than sized to their glyphs.
   ─────────────────────────────────────────────────────────────────────────── */

/* ── The page ─────────────────────────────────────────────────────────────── */

* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  margin: 0;
}

body {
  font-family: var(--skin-chrome-font);
  font-size: var(--skin-chrome-size);
  color: var(--skin-window-ink);
  background: var(--skin-window-surface);
  /* The shell owns the viewport; only the two windows scroll. A body that
     scrolled would carry the chrome bar off the top of a phone screen. */
  overflow: hidden;
  -webkit-text-size-adjust: 100%;
}

.app-shell {
  display: flex;
  flex-direction: column;
  height: 100%;
  /* The settings menu hangs from the chrome bar and is positioned against this
     box. The two windows' pickers hang against `.window` and are
     unaffected — a positioned ancestor further out changes nothing for a box
     that already has a nearer one. */
  position: relative;
  /* Modern viewport unit where it exists, so the mobile browser's collapsing
     address bar does not crop the study window. `height: 100%` above is the
     fallback and stays. */
  height: 100dvh;
}

/* ── The splash ───────────────────────────────────────────────────────────────
   Over the whole page from first paint until js/splash.js hides it: the page
   colour, and the brand's icon in the middle of it. The icon is neither drawn
   nor fetched until the brand is applied, so a hostname wearing another brand
   never shows the default's icon first, and the skin's own token, a relative
   address in a bundle that a browser may resolve against this sheet instead,
   is never asked for. `[hidden]` is restated because `display: flex` on
   the class would otherwise beat the attribute's own `display: none`. The
   layer sits above everything the shell draws, whose highest is 3. Four
   offsets rather than `inset`, which older Android WebViews do not read. */
.splash {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--skin-window-surface);
}

.splash[hidden] {
  display: none;
}

.splash__icon {
  width: 96px;
  height: 96px;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  visibility: hidden;
}

.splash--branded .splash__icon {
  background-image: var(--skin-icon);
  visibility: visible;
}

/* ── Where the App has not started ───────────────────────────────────────────
   The page's own sentence and its "Try again", held in pages/app.html and
   shown by the page's one script where the App's files have not run, the
   start has failed, or twenty seconds pass with nothing drawn; hidden again
   the moment the App draws. It sits along the foot of the screen, above the
   splash's layer of 10, so it is read under the icon through a splash that
   never lifts; and on the page colour, so it reads the same over the splash
   and over a shell that drew and then failed. `[hidden]` is restated for the
   same reason as the splash's. The button wears the lock screen's button
   tokens: it is the same kind of ask, one thing to tap. */
.not-started {
  position: fixed;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 11;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding: 24px;
  font-family: var(--skin-chrome-font);
  color: var(--skin-window-ink);
  text-align: center;
  background: var(--skin-window-surface);
}

.not-started[hidden] {
  display: none;
}

.not-started__words {
  max-width: 32em;
  margin: 0;
  font-size: 16px;
  line-height: 1.4;
}

/* Why, in small letters under the sentence: the file that did not arrive, or
   the first line of what went wrong. Empty until the page has a reason. */
.not-started__why {
  max-width: 32em;
  margin: 0;
  font-size: 13px;
  line-height: 1.4;
}

.not-started__why:empty {
  display: none;
}

.not-started__button {
  min-height: var(--skin-tap-min);
  padding: 0 24px;
  border: 0;
  border-radius: var(--skin-radius-pill);
  font: inherit;
  font-weight: 600;
  color: var(--skin-lock-button-ink);
  background: var(--skin-lock-button-surface);
}

.not-started__button:focus-visible {
  outline: 2px solid var(--skin-focus);
  outline-offset: 2px;
}

/* ───────────────────────────────────────────────────────────────────────────
   HOW THE SPLIT WORKS, because it is the one clever thing here
   The two windows are flex children with `flex-basis: 0`, so their heights are
   exactly their flex-grow numbers in ratio. js/appShell.js sets `--bible-grow`
   on the Bible window and `--study-grow` on the study window and changes nothing
   else — no inline height, no class toggling, no layout arithmetic in
   JavaScript. One consequence is worth the sentence: the same two properties
   drive the ROW direction on a wide screen without a second code path, because
   flex-grow does not care which axis it is growing along.

   Each number is written ON THE WINDOW THAT USES IT, and the pair is registered
   `inherits: false` below — see the block above `.window--bible`, where the numbers are.
   ─────────────────────────────────────────────────────────────────────────── */

/* ── Bands 3 and 5: the two windows, and band 4 between them ──────────────── */

.app-shell__windows {
  display: flex;
  flex-direction: column;
  /* `min-height: 0` is what lets the children scroll instead of the page: a
     flex item's default minimum is its content, so without this the windows
     grow to fit their text and the divider walks off the bottom of the screen.
     It is the single most load-bearing line in this file. */
  flex: 1 1 auto;
  min-height: 0;
}

.window {
  display: flex;
  flex-direction: column;
  /* Basis 0, so the two grow numbers ARE the ratio. js/appShell.js writes them. */
  flex-basis: 0;
  min-height: 0;
  min-width: 0;
  background: var(--skin-window-surface);
}

/* THE TWO GROW NUMBERS ARE REGISTERED, AND `inherits: false` IS THE WHOLE POINT.
   A custom property inherits. Writing the pair on the windows CONTAINER —
   the ancestor of every element in both windows — invalidates the computed style
   of the whole subtree beneath it, and with the whole Bible drawn that is 65,540
   elements. A divider drag writes once per pointermove.

   Measured on the 6x profile against the full 66-book ribbon, twenty writes each:

     the pair on the container, as it was          2,021 ms per write
     a custom property NOBODY READS, same place    1,982 ms per write
     the pair on the two windows, unregistered     1,770 ms per write
     the pair on the two windows, registered here     37 ms per write
     flex-grow written inline instead, as a control   34 ms per write
     nothing written at all, same flush                0 ms per write

   The second line is the finding: a property that changes no geometry whatever
   costs the same as a real drag step, so the price was never the resize — the
   resize dirties eight layout objects in a tree of 240,727 and costs 26 ms. The
   third line is why moving the numbers down is not on its own enough: what
   inherits from the Bible window is still the Bible window's own 65,000
   descendants. The fourth is this block, and it buys back 55x.

   A browser without @property support reads these as ordinary inherited custom
   properties: the split still works exactly as written, because each number is
   on the element that reads it — it just pays the old price. The `, 50` fallback
   below is for that same browser; where the registration is understood, an
   unset property answers `initial-value` and the App opens evenly split. */
@property --bible-grow {
  syntax: '<number>';
  inherits: false;
  initial-value: 500;
}

@property --study-grow {
  syntax: '<number>';
  inherits: false;
  initial-value: 500;
}

.window--bible {
  flex-grow: var(--bible-grow, 50);
}

.window--study {
  flex-grow: var(--study-grow, 50);
}

/* THE APP'S OWN GUTTER. The reading
   paper reaches both edges of the window and the gutter is the paper's own, so
   a phone shows a page rather than a card floating on a background — which is
   why the horizontal padding here is 0 and `--reading-pad-inline` carries the
   whole inline number. Setting both would have inset the text twice, and the
   two would have had to be read together to know what the margin was.

   16px is the near-edge margin: on a 360px phone that is
   328px of text, which is the width a phone reader expects and roughly what
   every native reading app on that screen gives. */
.window__content {
  flex: 1 1 auto;
  min-height: 0;
  --reading-pad-inline: 1rem;
  --reading-pad-block-start: 0.75rem;
  --reading-pad-block-end: 2.5rem;
  /* NOTHING ON THE TOP EDGE. Chrome insets a sticky element's constraint
     rectangle by the SCROLL CONTAINER'S OWN PADDING, so a non-zero padding-top
     here pins the chapter heading below the scrollport's visible edge. The top
     gutter a reader wants is not lost — `--reading-pad-block-start` above puts
     it on the paper, below the heading's sticky rectangle, where it can be
     scrolled away rather than held under the edge. */
  padding: 0;
  overflow-y: auto;
  /* Momentum scrolling on older WebViews. */
  -webkit-overflow-scrolling: touch;
  /* Keeps a drag on the divider from scroll-chaining into the other window. */
  overscroll-behavior: contain;
}

/* EACH BOOK OF THE RIBBON IS CONTAINED, AND `size` IS DELIBERATELY NOT IN IT.
   The Bible window holds sixty-six books at once — 65,540 elements, 240,727
   layout objects — and the divider drag changes that scroller's box once per
   pointermove. What remains on the phone profile is PrePaint: the engine
   walking the whole paint-property tree every frame to conclude that eight
   layout objects had moved.

   Measured on the 6x profile against the full ribbon, twenty pointer moves per
   regime, one press and one release:

                                      PrePaint   worst frame   frames >100ms
     nothing, as it was                2,982ms         483ms              12
     contain: paint                      231ms         133ms               1
     contain: layout paint               190ms          83ms               0

   `layout paint` and not `size` or `content-visibility`, and that is the whole
   care in this line. Size containment makes a box report the height it would
   have if it were EMPTY. `content-visibility: auto` made the ribbon's scrollHeight 15.7% short until a
   book had been seen, and a scroll height that is short is a scrollbar, a jump
   and a locator bar all lying together. Layout and paint containment change no
   intrinsic size — measured, not argued: the ribbon reports 3,120,530px with
   this rule and 3,120,530px without it.

   IT SELECTS A HOOK, WHICH IS WHY IT IS HERE AND NOT IN THE SKIN. `data-book`
   is written by js/appShell.js and carries no look-choice; this rule declares
   what the engine may skip, not what anything looks like; no `--reading-*` token comes with
   it. Nothing about the reading surface's dress lives in this file.

   It does NOT help the side-by-side drag, where the paper really re-wraps: on
   the desk profile the same twenty moves cost 6,648ms of Layout with this rule
   and 6,631ms without.

   THE TWO NAMES ARE BOTH IN js/appShell.js. `pinColumn`
   holds `.reading-view` at its grabbed measure for the length of a divider drag,
   so the paper re-wraps once at the let-go instead of once per pointermove.
   The accepted price is that the wrapper's edge clips the
   held column while the drag lasts, which is THIS RULE doing it: `contain: paint`
   is what cuts the column off at the book's box rather than growing a horizontal
   scrollbar on the scroller. `converge` is the other name: it re-measures the
   ribbon after the let-go in slices under a hundred milliseconds, holding the
   reader's position across every one. The two are welded — a pin without the
   position compensation is required, and the two are welded by design. */
.window__content[data-window="bible"] > [data-book] {
  contain: layout paint;
}

/* THE BOX A BOOK IS MEASURED IN BEFORE IT JOINS THE RIBBON. A visit that opens
   below the first book stands its ribbon from the landing book down;
   js/appShell/readerStand.js draws each book above it in here for the length of
   one measurement and takes it out again. No height and nothing painted, so the
   scroll height and the reader never hear of it; the book inside is laid out at
   the ribbon's own width and contained as a book in the ribbon is, so the
   height read off it is the height it will stand at. */
.window__content[data-window="bible"] > [data-measure] {
  height: 0;
  overflow: hidden;
  visibility: hidden;
  contain: layout paint;
}
.window__content[data-window="bible"] > [data-measure] > [data-book] {
  contain: layout paint;
}

/* The head and the foot over what is not on the page, in the window's own
   paper. The foot sets the page's footnotes at its bottom, at the column's
   width, above the same gutter the page has at its top. */
[data-page-head],
[data-page-foot] {
  position: absolute;
  left: 0;
  right: 0;
  background: var(--reading-paper);
}
[data-page-foot] {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  box-sizing: border-box;
  padding: 0 var(--reading-pad-inline) var(--reading-pad-block-start);
}

/* THE SELECTED VERSE: the verse the study window is showing, marked where the
   reader tapped it. A class on the verse's own span — js/appShell/selectedVerse.js
   sets it on every drawn piece of the verse and takes it off the last one —
   so nothing is wrapped and no glyph moves: the text takes the skin's selected
   ink and a faint tint behind it, and that is the whole of the mark. VERTICAL
   PADDING ONLY, so the tint has a little air above and below the glyphs; an
   inline box's block padding changes no line box, and no margin, weight, size
   or tracking is touched, which is what keeps the pane's height and every
   verse below the selected one exactly where they were. `box-decoration-break:
   clone` closes the tint at the end of every wrapped line rather than only at
   the verse's two ends, with the -webkit- twin for the engines that still
   need it. The verse number keeps its own colour: the shared sheet sets it on
   the number's own pseudo-element, and a colour on the span does not reach it. */
.segment--selected {
  color: var(--skin-selected-ink);
  background-color: var(--skin-selected-tint);
  padding-block: 0.15em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* THE READER'S POSITION IN THIS SCROLLER IS THE APP'S, AND THE BROWSER MAY NOT
   ALSO HOLD IT.

   Scroll anchoring is on by default in every browser that has it: when content
   above the reader changes size, the engine quietly adds the difference to
   `scrollTop` so the text under their eye stays put. That is a kindness on an
   ordinary page and it is a SECOND COMPENSATOR here, because this scroller
   already has one. `restoreAnchor` in js/appShell.js measures where the reader
   stood and puts them back at the end of every convergence slice, and `tendWindow`
   draws and releases books with no compensation at all — on the standing claim
   that a release hands back exactly the height it took, so nothing above anyone
   moves and there is nothing to correct. Two compensators on one scroller, one of
   which cannot be observed from JavaScript, is not a belt and braces: it is two
   answers to "where is the reader" with no way to tell which one moved them.

   WHAT IT COSTS. The picker's chip for Psalms 119 lands thousands of pixels past
   its header when scroll anchoring fires alongside the App's own compensator.
   The forensics: the ribbon stands at 2,966,555px; every book above the target
   changes by 0.063px in total against a miss of 3,842px; the aim is not wrong
   (`bibleWindow.scrollTo` asks for 1,521,851px against a truth of 1,521,850.875px
   — 0.156px out). The App aims true, nothing it owns moves the scroll, and the
   scroll arrives 4,333px–5,172px past the header.

   THE ANIMATION IS THE WINDOW THE DEFECT LIVES IN. `landJump` scrolls with
   `behavior: 'smooth'`, and a smooth scroll across 1.5 million pixels runs for
   hundreds of milliseconds during which `tendWindow` fires on every scroll event,
   swapping book boxes for placeholders and back. Sixteen swaps in one measured
   trip, eight of them entirely above the offset at the moment they happened —
   and every swap REPLACES A NODE, which is the one thing scroll anchoring cannot
   ignore: the element it had chosen as the anchor is removed, it re-anchors, and
   it adjusts. The adjustment does not pass through the `scrollTop` setter, is not
   taken back when the box returns to its old height, and is nondeterministic in
   size because it depends on how many swaps the animation's duration happened to
   contain. The six magnitudes the stop was reported with — 1,214px through
   4,680px — are that duration, not a constant anybody could have found by reading.

   THE DECLARATION IS ON THE SCROLLER AND THE NARROWNESS IS MEASURED. Four regimes,
   the same jump twice each, on the 6x profile after a completed convergence:

     as it ships, anchoring on          worst 9,910.156px      MISSED
     overflow-anchor: none, HERE        worst     0.156px      HELD
     overflow-anchor: none on the kids  worst     0.156px      HELD
     the landing made instant           worst     0.156px      HELD

   The third works for the wrong reason — it leaves the container with no element
   eligible to be an anchor, so the next descendant added without the rule brings
   the defect back — and the fourth changes what a reader sees in order to fix
   something they cannot. This one says the true thing and says it once: in this
   scroller, the App holds the reader.

   IT IS NOT ON THE STUDY WINDOW. That scroller has no ribbon, nothing releases
   boxes under it, and nothing in the App compensates its position — so there is
   no second compensator there to be in conflict with, and a declaration without
   a reason is a declaration nobody can remove later. */
.window__content[data-window="bible"] {
  overflow-anchor: none;
}

/* The chapter header a reader sees is NOT here, and the omission is the header's
   rule doing its job: it is drawn inside `.reading-view`, so it belongs to
   netword-shared/css/reading.css beside the verse number it sits above. What the
   App owns is EMITTING it — js/readingJoin.js writes the `h2`, its class and its
   `data-chapter`. The one
   thing this sheet contributes is the scrollport the header sticks to:
   `.window__content` above declares `overflow-y: auto`, and `position: sticky`
   is measured against the nearest scrolling ancestor. A future change that moved
   the scrolling to another box would move the header with it. */

/* THE TWO HEADINGS IN THIS WINDOW ARE NOW PRESSES, and this is the whole of
   what a reader sees of that: a pointer over them on a screen that has one, and
   an underline while it is there. The chapter header opens the book and
   chapter picker and the section heading opens the section, which is behaviour
   the App owns — js/appShell.js listens, js/readingJoin.js writes the
   `data-section` the section tap is found by.

   SCOPED TO THIS WINDOW AND NOT TO THE HEADING, which is why it is here and not
   in netword-shared/css/reading.css beside the headings' own dress. The same
   two classes are drawn by the workbench and by the Studio's preview, where
   nothing listens for a tap on them; a pointer offered there would be an
   affordance for something that does not happen.

   NOTHING ELSE MOVES. No colour, no weight, no size, no margin — a heading that
   changed shape on the day it became pressable would be a change to the page a
   reader reads, made for the sake of a change to what the page does. */
.window__content[data-window="bible"] .chapter-heading,
.window__content[data-window="bible"] .section-heading {
  cursor: pointer;
}

.window__content[data-window="bible"] .chapter-heading:hover,
.window__content[data-window="bible"] .section-heading:hover {
  text-decoration: underline;
}

/* ── Band 4: the divider ──────────────────────────────────────────────────── */

.divider {
  /* The visible bar is 8px, its two rules inside it; the grab area is the tap
     floor, reached by the invisible ::before, which stands over the edges of
     both windows. The rules are inset shadows and not borders: a border would
     move the padding box the ::before is measured from 1px in on each side,
     and the grab area would fall 2px short of the floor.
     `touch-action: none` is what stops the browser turning a
     drag into a page scroll before the handler ever sees it — without it the
     divider simply does not move on a phone. */
  --divider-bar: 8px;
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  height: var(--divider-bar);
  padding: 0;
  background: var(--skin-divider-surface);
  box-shadow: inset 0 1px var(--skin-rule), inset 0 -1px var(--skin-rule);
  cursor: row-resize;
  touch-action: none;
  -webkit-tap-highlight-color: transparent;
}

/* Half of what the tap floor asks beyond the bar, on each side of it. */
.divider::before {
  content: '';
  position: absolute;
  inset: calc((var(--divider-bar) - var(--skin-tap-min)) / 2) 0;
}

.divider__grip {
  display: block;
  width: 48px;
  height: 4px;
  background: var(--skin-divider-grip);
  border-radius: var(--skin-radius-pill);
  pointer-events: none;
}

.divider:hover .divider__grip,
.divider--dragging .divider__grip,
.divider:focus-visible .divider__grip {
  background: var(--skin-divider-active);
}

.divider:focus-visible {
  outline: 2px solid var(--skin-focus);
  outline-offset: -2px;
}

/* ── Landscape: the two windows sit side by side ──────────────────────────────
 *
 * THE SWITCH IS ORIENTATION AND NOT WIDTH. Orientation asks the question the
 * layout actually turns on — which way there is room. A phone held sideways is
 * 640px, which has the shape for a side-by-side split; a tall desktop window at
 * 800x1200 is portrait and gets a stacked layout its shape asks for.
 *
 * IT IS ALSO WHAT MAKES THE AXIS ORACLE HONEST. js/appShell.js asks this sheet
 * which way the shell is laid out to turn a pointer into a fraction. A width
 * query could disagree — 800x1200 is portrait but is past 44rem — and the drag
 * would compute its split from the wrong coordinate.
 *
 * A settings override is a coming tenant of the menu's structure table. Not here.
 */

@media (orientation: landscape) {
  .app-shell__windows {
    flex-direction: row;
  }

  /* The same two grow numbers, now sharing a horizontal axis — no second code
     path in js/appShell.js, which writes the properties and never the axis. */
  .divider {
    width: var(--divider-bar);
    height: auto;
    box-shadow: inset 1px 0 var(--skin-rule), inset -1px 0 var(--skin-rule);
    cursor: col-resize;
  }

  .divider::before {
    inset: 0 calc((var(--divider-bar) - var(--skin-tap-min)) / 2);
  }

  .divider__grip {
    width: 4px;
    height: 48px;
  }

  .window--bible {
    border-right: 0;
  }
}

/* ── Wide screens: more gutter, which is a different question ─────────────────
 *
 * THIS STAYS A WIDTH QUERY. Padding
 * is a claim about how much room the paper has, and a phone turned sideways is
 * 640px — landscape, so side by side above, and each window then holds about
 * 310px. Giving that 1.5rem gutters on both sides would take a sixth of the
 * measure away from the reading to prove a point about orientation. The two
 * queries answer two different questions.
 */

@media (min-width: 44rem) {
  /* Modestly, and only modestly. A wider viewport is a bigger phone or a small
     tablet, not a desk — `max-width: 34rem` in the shared sheet is already
     holding the measure, so past that width extra gutter is the window's job
     and not the paper's. Studio's 1.5rem is the desk's number and stays
     Studio's. */
  .window__content {
    --reading-pad-inline: 1.5rem;
    --reading-pad-block-start: 1rem;
    --reading-pad-block-end: 3rem;
  }
}
/* netword-app/css/app/chrome.css
   The two bands above the windows — the chrome bar and the navigation bar —
   and the icon buttons both of them hold. */

/* ── Band 1: the chrome bar ───────────────────────────────────────────────── */

.chrome-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex: none;
  gap: 8px;
  padding: 0 8px;
  min-height: var(--skin-band-height);
  color: var(--skin-chrome-ink);
  background: var(--skin-chrome-surface);
  border-bottom: 1px solid var(--skin-chrome-rule);
}

/* The demo band: one quiet line under the chrome bar while notes stand open by
   the master code. Its host is always in the shell and is empty, and so takes
   no room, whenever there is no such unlock. One line, never two: a band that
   wrapped would move the windows under a reader's thumb. */
.demo-band-host {
  flex: none;
}

.demo-band {
  display: flex;
  align-items: center;
  min-height: 30px;
  padding: 0 16px;
  overflow: hidden;
  font-family: var(--skin-chrome-font);
  font-size: var(--skin-chrome-size-small);
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--skin-demo-band-ink);
  background: var(--skin-demo-band-surface);
  border-bottom: 1px solid var(--skin-demo-band-rule);
}

/* The logo is an empty element filled from the skin — no filename in the
   markup, so a new skin is one CSS file plus one image and no HTML edit. */
.chrome-bar__logo {
  flex: none;
  width: 116px;
  height: 32px;
  background-image: var(--skin-logo);
  background-repeat: no-repeat;
  background-position: left center;
  background-size: contain;
}

.chrome-bar__actions {
  display: flex;
  align-items: center;
  gap: 2px;
}

/* ── Band 2: the navigation bar ─────────────────────────────────────────────

   THE VERTICAL PADDING IS ZERO, AND THE ZERO IS THE EQUALITY.
   The tallest child is the 36px field beside 32px icon buttons; 36 + 1px
   border = 37, the token governs, and the two bars are 48 and 48 because they
   read ONE token — not because two numbers are set equal by hand. The field
   stays smaller than its band. The headroom is what the equality test in
   test/densityScan.test.js watches: a taller child would take this bar back
   over the band and the assertion, not a reader, is what would notice. */

.nav-bar {
  display: flex;
  align-items: center;
  flex: none;
  gap: 6px;
  padding: 0 8px;
  min-height: var(--skin-band-height);
  color: var(--skin-nav-ink);
  background: var(--skin-nav-surface);
  border-bottom: 1px solid var(--skin-rule);
}

.nav-bar__history {
  display: flex;
  flex: none;
  gap: 2px;
}

.nav-bar__search {
  flex: 1 1 auto;
  min-width: 0;
}

.nav-bar__field {
  width: 100%;
  min-height: 36px;
  padding: 0 12px;
  font: inherit;
  color: var(--skin-field-ink);
  background: var(--skin-field-surface);
  border: 1px solid var(--skin-rule);
  border-radius: var(--skin-radius-pill);
}

.nav-bar__field::placeholder {
  color: var(--skin-field-placeholder);
  opacity: 1; /* Firefox dims placeholders by default; the token decides, not it. */
}

/* An inert control is dimmed and says why in its title — never hidden, never
   silently dead. House rule: the surface says what it awaits. */
.nav-bar__field:disabled {
  cursor: not-allowed;
  opacity: 0.75;
}

/* ───────────────────────────────────────────────────────────────────────────
   ICONS FOLLOW THE SKIN BECAUSE THEY ARE MASKS, NOT IMAGES
   An `<img>` cannot inherit `color`, so icons loaded as images would need a
   recoloured file per skin. The four SVGs in netword-shared/assets/icons/ are
   used as CSS masks over a `currentColor` background: the file supplies the
   shape, the skin supplies the colour, and a new skin needs no new icons.
   `-webkit-mask` is required on older Android WebViews; dropping it would make
   the icons vanish on that hardware.
   ─────────────────────────────────────────────────────────────────────────── */

/* ── Icon buttons ─────────────────────────────────────────────────────────── */

.icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: var(--skin-tap-min);
  height: var(--skin-tap-min);
  padding: 0;
  color: inherit;
  background: transparent;
  border: 0;
  border-radius: var(--skin-radius);
  cursor: pointer;
  /* iOS/Android WebView paint a grey flash on tap; the hover rule below is the
     feedback this build wants instead. */
  -webkit-tap-highlight-color: transparent;
}

.icon-button__glyph {
  display: block;
  width: 22px;
  height: 22px;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

.icon-button__glyph--library {
  -webkit-mask-image: url('../assets/icons/library.svg');
  mask-image: url('../assets/icons/library.svg');
}

.icon-button__glyph--settings {
  -webkit-mask-image: url('../assets/icons/settings.svg');
  mask-image: url('../assets/icons/settings.svg');
}

.icon-button__glyph--backward {
  -webkit-mask-image: url('../assets/icons/backward.svg');
  mask-image: url('../assets/icons/backward.svg');
}

.icon-button__glyph--forward {
  -webkit-mask-image: url('../assets/icons/forward.svg');
  mask-image: url('../assets/icons/forward.svg');
}

.chrome-bar .icon-button {
  color: var(--skin-control-ink);
}

.chrome-bar .icon-button:hover,
.chrome-bar .icon-button:focus-visible {
  background: var(--skin-control-hover);
}

.nav-bar .icon-button {
  color: var(--skin-nav-control-ink);
}

.nav-bar .icon-button:hover:not(:disabled),
.nav-bar .icon-button:focus-visible {
  background: var(--skin-nav-control-hover);
}

.icon-button:disabled {
  color: var(--skin-control-ink-dim);
  cursor: default;
}

.icon-button:focus-visible,
.nav-bar__field:focus-visible {
  outline: 2px solid var(--skin-focus);
  outline-offset: 1px;
}
/* netword-app/css/app/window-bar.css
   The bar under each window: where the reader is, which edition they are
   reading, the popup that answers for it, and the quiet line the study bar
   writes when a tap finds nothing. */

/* The locator bar sits BELOW its window, for both windows, which is why
   this is one rule and not two placed differently. */
.window__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex: none;
  /* THE BAR IS A CONTAINER, and the version's two forms below are
     what queries it. A media query would have been the wrong instrument and
     this is measured, not assumed: in landscape the two windows sit SIDE BY SIDE
     (see the media queries at the foot of shell.css), so a phone turned sideways
     at 640px gives each bar about 310px — NARROWER than the full-width bar the
     same phone shows at 360px held upright. Viewport width therefore does not
     tell you how wide a bar is; only the bar does.

     `inline-size` and not `size`: the bar's width comes from its window and its
     height comes from its content, and asking for size containment on both axes
     would make a bar that could not grow for a second line of anything. Note it
     brings layout and style containment with it but NOT paint, so nothing here
     clips. */
  container-type: inline-size;
  container-name: window-bar;
  gap: 8px;
  padding: 0 12px;
  min-height: 36px;
  font-size: var(--skin-chrome-size-small);
  font-weight: var(--skin-locator-weight);
  color: var(--skin-locator-ink);
  background: var(--skin-locator-surface);
  border-top: 1px solid var(--skin-rule);
}

/* The locator is a <button> so the picker has a real control to
   hang on. It must go on LOOKING like the label it has always been, which is
   what these five resets are: a button's own font, background, border and
   padding are the browser's, and inheriting them from the bar is what keeps
   the change invisible to a reader and visible to a keyboard. */
.window__locator {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font: inherit;
  color: inherit;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
}

/* THE EDITION ON THE BAR, at two widths.

   `flex: 0 1 auto` and the three-property elision kit are the fix. "IKJV
   New Testament — The Josiah Project · v1" arrived as "KJV New Testament",
   which does not look like damage: it looks like the name of a translation.
   Nothing had mangled it. The bar simply had no way to say it was out of room.

   The version may now shrink and, if it ever runs out of room anyway, ends
   in an ellipsis — a mark that MEANS something was cut. The two forms below are
   the first line of defence and this is the second, because a defence that
   depends on a query the browser might not support is not a defence. */
.window__version {
  flex: 0 1 auto;
  /* The bar holds three things — locator, version, ⓘ — and
     `space-between` would strand the version in the middle of the gap. The auto
     margin eats the free space before `justify-content` sees it, so the locator
     keeps the left edge and these two travel together on the right. It is the
     same device `.window__note` uses below, for the same reason. */
  margin-inline-start: auto;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-weight: var(--skin-chrome-weight);
  color: var(--skin-nav-ink-dim);
}

/* THE SHORT FORM IS THE DEFAULT AND THAT IS THE WHOLE POINT. A browser too old
   for `@container` drops the block below WHOLESALE — so what it is left with is
   the form that fits everywhere, not the form that gets clipped. Low-end
   Android WebViews are exactly that browser, so the fallback is the safe truth
   rather than the rich one.

   Where a publication asserts neither display field the two spans hold the same
   string, so the swap is invisible and correct: `versionTitles` falls both
   forms back to the title, and the App never invents an abbreviation. */
.window__version-full {
  display: none;
}

.window__version-short {
  display: inline;
}

/* 26rem of BAR — not of viewport. It clears the longest form on today's shelf
   ("International King James Version · v1") beside a locator and the info
   button with room to spare, and it is above every phone in portrait: a 412px
   device gives this bar a 388px content box, so a phone held upright gets the
   short form and a phone turned sideways gets the long one. */
@container window-bar (min-width: 26rem) {
  .window__version-full {
    display: inline;
  }

  .window__version-short {
    display: none;
  }
}

/* ── The edition popup ────────────────────────────────────────────────────────
   The attribution used to ride in the bar, glued to the title with an em dash,
   on the one line the App's primary form factor has least of. CC BY's
   attribution duty is real, and a duty discharged by a string that does not fit
   is not discharged — so the credit moved to a surface with room, and the bar
   went back to naming the edition. See `editionCard` in js/readingJoin.js.

   28px AND NOT THE TAP FLOOR the picker's chips honour, and the reason is
   the bar itself: `.window__bar` is 36px tall, so a control at the floor inside
   it would crowd the bar rather than sit in it. It matches `.picker__close` and
   `.window__slot`, which are the two icon-sized controls this build already has.

   THE GLYPH IS `content` AND NOT AN SVG MASK, unlike the four chrome icons. It
   is one character the target devices' fonts carry, and adding an asset — plus
   its two masking declarations and a fetch on a constrained network — to draw a
   character the device already has would be paying for a picture of a letter. */
.window__info {
  flex: none;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: var(--skin-radius);
  background: transparent;
  color: var(--skin-nav-ink-dim);
  cursor: pointer;
}

.window__info::before {
  content: '\24d8';
  font-size: 16px;
  line-height: 1;
}

.window__info:hover {
  background: var(--skin-nav-control-hover);
}

/* The host is always in the markup and empty when closed, exactly as the
   picker's is — see `.picker-host` in picker.css for why that is not a
   `display: none`.

   IT SPANS THE WINDOW AND RIGHT-ALIGNS ITS CHILD rather than being positioned
   against the button. A popup pinned to the ⓘ's own inline offset would have to
   agree with the bar's padding, the version's width and the button's, in a
   second file; a flex row that ends where the bar ends agrees with all three by
   construction, and stays right when the version's two forms swap. */
.info-host {
  position: absolute;
  inset-inline: 0;
  bottom: 36px; /* the bar's min-height: the popup sits on top of the bar */
  z-index: 2;
  display: flex;
  justify-content: flex-end;
  padding: 0 8px 6px;
}

.info {
  max-width: 18rem;
  padding: 10px 12px;
  font-size: var(--skin-chrome-size-small);
  background: var(--skin-info-surface);
  color: var(--skin-info-ink);
  border: 1px solid var(--skin-rule);
  border-radius: var(--skin-radius);
  box-shadow: 0 2px 8px var(--skin-info-shadow);
}

.info__title {
  margin: 0;
  font-weight: var(--skin-locator-weight);
}

/* The two lines below the title are quieter than it on purpose: the edition's
   name is what a reader came to check, and the permission and the credit are
   what the licence requires be available. Both are present and neither competes
   with the other. */
.info__line {
  margin: 4px 0 0;
  color: var(--skin-nav-ink-dim);
}

/* THE QUIET ANSWER. Empty at rest, and it takes no space when it
   is: a bar that reserved a gap for a sentence nobody has said yet would be
   furniture pretending to be information. When a tap finds nothing covering the
   verse, the shell writes one line here and the study window does not move.

   `margin-inline-start: auto` is what puts it on the right, beside the slot,
   rather than in the middle where `.window__bar`'s `space-between` would leave
   it. An auto margin eats the free space before `justify-content` gets to it,
   so the locator keeps the left edge and these two keep the right — and the
   arrangement holds when the note is empty, which is nearly always. */
.window__note {
  flex: 0 1 auto;
  margin-inline-start: auto;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--skin-nav-ink-dim);
}

/* The study bar's one icon slot — assignment ruled later. It holds space
   and is empty on purpose; a slot drawn with a borrowed icon would be a claim
   about a decision nobody has made. */
.window__slot {
  flex: none;
  width: 28px;
  height: 28px;
}
/* netword-app/css/app/picker.css
   The two panels that drop over the reading — the book picker, and the settings
   menu, which carries the picker's class and so wears its dress by
   construction. What is here for the menu is only what differs. */

/* ── The book picker ───────────────────────────────────────────────────────
   It drops OVER the reading like a file menu opens — Nathan's ruling, against
   the Logos pattern of a screen you navigate to. So the host is absolutely
   positioned against the window and the reading underneath is untouched: no
   scroll is lost, and closing the panel restores nothing because nothing was
   replaced.

   The host is always in the markup and empty when closed, which is why there
   is no `display: none` here — an empty div costs no layout, and twenty-seven
   buttons a reader cannot see is exactly the cost a low-end phone refuses. */
/* THE HOST IS THE SPACE ABOVE THE BAR, AND THAT IS WHAT BOUNDS THE PANEL.
   `bottom` alone left the host's height to its contents, so the panel's own
   `max-height` was the only thing deciding how tall it could be — and it was
   measured against the VIEWPORT, which is not the box it hangs in. On a 390 by
   844 phone the Bible window stands 421px above its bar and 60vh is 506px, so
   the panel was 85px taller than the space it had: it grew upwards out of the
   window, and Genesis through Deuteronomy sat above the top edge where no
   scroll reached them. The only way to the first five books was to drag the
   divider — which is a reader being asked to resize the page to read it.

   Pinning `top` gives the host a definite height, and the panel below takes
   its ceiling from that. The grid inside already scrolls, so the books that do
   not fit are reached by scrolling the list rather than by moving the window.

   AND THE HOST IS NOW TRANSPARENT TO A THUMB. It covers the whole window
   rather than only the panel's strip, so a tap anywhere on the reading would
   otherwise land on an empty div. The panel itself takes its taps back. */
.picker-host {
  position: absolute;
  inset-inline: 0;
  top: 0;
  bottom: 36px; /* the bar's min-height: the panel sits on top of the bar */
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  pointer-events: none;
}

.picker-host > * {
  pointer-events: auto;
}

.window {
  position: relative;
}

.picker {
  display: flex;
  flex-direction: column;
  /* Sixty per cent of the viewport where that fits in the window, and the
     window where it does not. Written this way round rather than as a plain
     `100%` so that nothing changes on a screen where the old number already
     fitted: the ceiling only comes down where the panel was overflowing. */
  max-height: min(60vh, 100%);
  background: var(--skin-picker-surface);
  color: var(--skin-picker-ink);
  border-top: 1px solid var(--skin-rule);
  box-shadow: 0 -2px 8px var(--skin-picker-shadow);
}

.picker__head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: none;
  padding: var(--skin-panel-head-pad-block) 12px;
  border-bottom: 1px solid var(--skin-rule);
  font-size: var(--skin-chrome-size-small);
  font-weight: var(--skin-locator-weight);
}

.picker__title {
  flex: 1;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.picker__back,
.picker__close {
  flex: none;
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: var(--skin-radius);
  background: transparent;
  color: inherit;
  cursor: pointer;
}

.picker__back::before { content: '\2039'; font-size: 20px; }
.picker__close::before { content: '\00d7'; font-size: 18px; }

.picker__back:hover,
.picker__close:hover {
  background: var(--skin-picker-chip-hover);
}

/* MOBILE-FIRST AND AUTO-FILLING. The chip width is a floor, not a size, so the
   same grid gives a phone four columns and a tablet ten without a media query
   deciding which. `1 Thess` is the widest standard abbreviation the registry
   carries and 3.75rem holds it.

   THE GAP PAYS FOR ITSELF ON THE CHAPTER GRID. `auto-fill` divides the
   content width by (track floor + gap), so the gap is not only the air between
   cells — it is part of what a column costs. At 360px, dropping the padding to
   8px and the gap to 4px widens the content box to 344px and takes a chapter
   column from 50px to 48px, which fits SEVEN instead of six: 28 chapters land
   in four rows rather than five, and the grid falls 268px to 204px. The book
   grid keeps its five columns — 3.75rem is a wider floor and 344px will not
   hold a sixth — so there the saving is the padding and gaps alone, 318 to
   300.

   WHAT MAKES THE TIGHTER GAP SAFE IS THE TRACK FLOOR, NOT THE GAP. `minmax`
   makes 2rem the least a chapter cell can be and 2rem is 32px, which is
   the tap floor exactly — so no gap this rule could choose draws a cell too
   small for a thumb, and a narrower gap makes the cells WIDER rather than
   narrower. The number to guard is therefore the 2.75rem below and not this
   gap; test/densityScan.test.js asserts that it and `--skin-tap-min` are the
   same number, because the day they part is the day the guarantee goes. */
.picker__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(3.75rem, 1fr));
  gap: var(--skin-grid-gap);
  padding: var(--skin-grid-pad);
  overflow-y: auto;
}

.picker__grid--chapters {
  grid-template-columns: repeat(auto-fill, minmax(2rem, 1fr));
}

/* THE FLOOR IS ONE TOKEN. It is a MINIMUM rather than a height so a long
   abbreviation may wrap. It reads `--skin-tap-min` now so
   the floor is stated once and the chips and the icon buttons cannot drift
   apart; density buys its space from the grid around these, never from these.
   The chip's own `4px 6px` is not what makes a chip tall — against the
   floor it contributes nothing, so a shorter chip is a lower floor. */
.picker__chip {
  min-height: var(--skin-tap-min);
  padding: 4px 6px;
  border: 1px solid var(--skin-rule);
  border-radius: var(--skin-radius);
  background: var(--skin-picker-chip-surface);
  color: inherit;
  font: inherit;
  font-size: var(--skin-chrome-size-small);
  cursor: pointer;
}

/* THE BOOKS BY CATEGORY. bookPicker.js turns the shade over wherever
   bibleBooks.js's category changes, so the law, the histories, the poets and
   the prophets stand as alternate runs. Declared before hover and current so
   both still win over it. */
.picker__chip--shade {
  background: var(--skin-picker-chip-shade);
}

.picker__chip:hover {
  background: var(--skin-picker-chip-hover);
}

.picker__chip--current {
  border-color: var(--skin-picker-chip-current-rule);
  background: var(--skin-picker-chip-current);
  font-weight: var(--skin-locator-weight);
}

.picker__chip:focus-visible,
.picker__back:focus-visible,
.picker__close:focus-visible,
.window__locator:focus-visible {
  outline: 2px solid var(--skin-focus);
  outline-offset: 2px;
}

/* ── The settings menu ─────────────────────────────────────────────────────────

   IT WEARS THE PICKER'S DRESS AND DECLARES NO COLOUR OF ITS OWN. The panel
   carries `class="picker settings"`, so the surface, the ink, the head, the
   shadow and every chip come from the tokens a reader has already met choosing a
   book — and a skin that restyles the picker restyles this in the same edit,
   which is the property a second set of tokens would quietly destroy. What is
   below is only what DIFFERS: the panel hangs from the top instead of sitting on
   a bar, and its options are short rows rather than a grid of twenty-seven.

   The host is always in the markup and empty when closed, exactly like the
   picker's — see the note above it for why there is no `display: none` here. */
.settings-host {
  position: absolute;
  inset-inline: 0;
  /* The chrome bar's own height, read rather than repeated: the menu hangs off
     its lower edge, so a change to the band height updates this automatically. */
  top: var(--skin-band-height);
  z-index: 3;
}

.settings {
  /* The picker's edge and shadow are on its top, because it rises off a bar. This
     one descends from one, so both move to the other side. */
  border-top: 0;
  border-bottom: 1px solid var(--skin-rule);
  box-shadow: 0 2px 8px var(--skin-picker-shadow);
}

.settings__body {
  flex: 1;
  min-height: 0; /* or the flex child refuses to shrink and the panel overflows */
  overflow-y: auto;
  padding-bottom: var(--skin-menu-body-pad-end);
}

.settings__group {
  padding: 0 12px;
}

/* WHAT THIS PHONE HOLDS, said first: a license or the demo, and until when.
   One line each, ruled like a row, with nothing in it to tap. */
.settings__hold {
  margin: 0;
  padding: 10px 0;
  border-top: 1px solid var(--skin-rule);
  line-height: 1.45;
}

/* THE RULED ROAD, DRAWN RATHER THAN WALKED — View › Bible Window as this group's
   heading. js/settingsMenu.js carries the reasoning; what matters here is that
   the separator is CSS and not a character in the markup, the same way the
   picker's back arrow and close × are. */
.settings__path {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
  margin: 0;
  /* The head's border draws the separation a top pad would do twice. */
  padding: var(--skin-menu-path-pad-block) 0;
  font-size: var(--skin-chrome-size-small);
  font-weight: var(--skin-locator-weight);
}

.settings__crumb + .settings__crumb::before {
  content: '\203A';
  padding-inline-end: 4px;
}

/* WRAPPING RATHER THAN TRUNCATING, and the label is what gives way. At 360px a
   long setting name beside three chips has to go somewhere; a second line is
   readable and an ellipsis on the word that says WHAT is being chosen is not. */
.settings__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  /* 4px padding: 53px is the floor. A row is 1px of border plus this padding
     twice plus the 44px chip, so the only way below 53 is through the tap target.
     The menu is as tight as its own thumb-sized options allow. */
  padding: var(--skin-menu-row-pad-block) 0;
  border-top: 1px solid var(--skin-rule);
}

.settings__label {
  flex: 1 1 7rem;
  min-width: 0;
}

/* A ROW AND NOT `.picker__grid`. The grid auto-fills, which is right for
   twenty-seven books and wrong for two options — on a tablet it would stretch
   On and Off across the full width and make a toggle look like a banner. */
.settings__choices {
  display: flex;
  flex-wrap: wrap;
  gap: var(--skin-grid-gap);
}

.settings__choices .picker__chip {
  min-width: 3.75rem;
}

/* "ADD TO HOME SCREEN" under what this phone holds: a chip, on a line of its own. */
.settings__home {
  padding-inline: 12px;
}

/* "UNLOCK WITH MY WHATSAPP" under what this phone holds, while nothing is open:
   a chip, on a line of its own. */
.settings__unlock {
  padding-inline: 12px;
}

/* A COMING OPTION: drawn beside the others so a reader knows it is on its way,
   and not pressable — no hover, no pointer, its name and the word "coming". */
.settings__coming {
  opacity: 0.55;
  cursor: default;
}

.settings__coming:hover {
  background: var(--skin-picker-chip-surface);
}

.settings__comingWord {
  font-size: var(--skin-chrome-size-small);
  font-style: italic;
}
/* netword-app/css/app/study.css
   Inside the study window: the pane that grows to the base of a nearly empty
   window, the sentence a silent verse gets, and the credit pinned under both. */

/* ── The verse window and the credit under it ────────────────────────────────
   The study window stopped holding a document and started holding ONE verse's
   covering span, and that is what makes a footer possible at all: a credit under
   a scrolling commentary would be a line the reader met once, at the bottom of
   Matthew, and never again.

   THE FLEX COLUMN IS ONLY ON THE STUDY SIDE, and the attribute selector is how
   that is said without a second class. `.window__content` is shared with the
   Bible window, which wants nothing to do with any of this — its content is a
   book, it fills its box by being long, and turning it into a flex container
   would change how a chapter of scripture lays out for the sake of a footer that
   is not on that side of the page. */
.window__content[data-window="study"] {
  display: flex;
  flex-direction: column;
}

/* ONE VERSE AT A TIME, whatever the way of reading: the window scrolls down
   and zooms, and the sideways gesture is the swipe's, which
   js/appShell/swipe.js reads as a turn to the next verse or the one before. */
.window__content[data-window="study"] {
  touch-action: pan-y pinch-zoom;
}

/* `1 0 auto` and not `1 1 auto`: the pane must GROW to the base of a nearly
   empty window — that is what pins the credit — and must never SHRINK, because
   a shrunk pane would clip a long note inside a box the scrollport thinks is
   full. Grow for the short case, refuse to shrink for the long one. */
.study-pane {
  display: flex;
  flex-direction: column;
  flex: 1 0 auto;
}

/* THE PANE'S WIDTH, WHATEVER IT HOLDS. The reading view centres its measure
   with auto inline margins, and an auto-margined item in a flex column is
   sized to its content: a short pane drew a column as wide as its longest
   line. The body is a plain block the column stretches edge to edge, and the
   view inside it fills to its measure as it does anywhere else. Stated rather
   than left to the column's default, because the default is the whole fix. */
.study-body {
  align-self: stretch;
}

/* The sentence a silent verse gets. IT SPEAKS IN THE NOTE'S VOICE AND NOT A
   SYSTEM MESSAGE'S, which is a choice and not an oversight: it stands exactly
   where a note would have stood, and dressing it as a system message would tell
   the reader something went wrong. Nothing went wrong — this commentary simply does
   not discuss this verse, which is an ordinary fact about a book. Soft ink is
   the whole of the difference from the prose it replaces. */
.study-quiet {
  margin: 0;
  color: var(--reading-ink-soft);
  font-style: italic;
}

/* ── The two voices ──────────────────────────────────────────────────────────
   The study window holds ONE reading view: the note, then the references, and
   the view pays its bottom padding once. Inside it everything reads in the
   chrome's sans and only a quoted verse in the serif, so a reader tells what
   the edition wrote from what scripture says by the face alone. The skin
   points the pane's reading face at the sans; the quotation takes the
   scripture face.

   THE NOTE IS A BOX INSIDE THE VIEW, and its face, size, leading and ink are
   set on the box rather than on the view: the view's own typography is the
   platform's token reads on the view element, and a token overridden below an
   element that has already used it changes nothing. The paragraph gap and the
   lead-in's weight and colour ARE consumed on the note's own blocks, so those
   three are overridden as tokens in the skin's `.study-note` block and not
   here, where no reading dress is declared. Sizes are structure and are
   written here; every colour is a token. */
.study-note {
  font-family: var(--skin-chrome-font);
  font-size: 0.96875rem;
  line-height: 1.55;
  color: var(--skin-note-ink);
}

/* One quiet section label between the note and the references: the chrome's
   sans, small, spaced, and set in capitals by the sheet rather than by the
   words. A hairline above it closes the note; 16px stand above the hairline,
   12px between the hairline and the words, 6px beneath. Drawn only when
   references exist, which the markup decides. */
.study-label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin: 16px 0 6px;
  padding-block-start: 12px;
  border-block-start: 1px solid var(--skin-label-rule);
  font-family: var(--skin-chrome-font);
  font-size: 11px;
  font-weight: var(--skin-chrome-weight);
  line-height: 1.3;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--skin-label-ink);
}

/* With no note above it there is nothing for a hairline to close and no gap
   to keep: the label opens the view. */
.study-label:first-child {
  margin-block-start: 0;
  padding-block-start: 0;
  border-block-start: 0;
}

/* The count at the right of a label: how many verses stand under it, and the
   button that changes how they are shown. It undoes the label's capitals and
   spacing, because it is a number and a word and not a section's name, and it
   wears the selected ink, which is the ink of the things in this window a
   reader presses to change what the window shows. */
.study-count {
  flex: none;
  margin: 0;
  padding: 2px 0 2px 8px;
  background: none;
  border: 0;
  font-family: var(--skin-chrome-font);
  font-size: var(--skin-chrome-size-small);
  font-weight: normal;
  letter-spacing: normal;
  text-transform: none;
  color: var(--skin-selected-ink);
  cursor: pointer;
}

/* The mark after the count: down while its verses are shown in full, across
   while they are shown as references only. */
.study-count::after {
  content: "\25be";
  margin-inline-start: 4px;
}

[data-xref-verses="refs"] [data-verses-kind="xref"]::after,
[data-term-verses="refs"] [data-verses-kind="term"]::after {
  content: "\25b8";
}

/* What the count switches to, in words for a reader who hears the page and
   out of sight for one who sees it. Both are drawn; the one naming the mode
   already shown is taken out of the page. */
.study-count {
  position: relative;
}

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

[data-xref-verses="full"] [data-verses-kind="xref"] > [data-to="full"],
[data-xref-verses="refs"] [data-verses-kind="xref"] > [data-to="refs"],
[data-term-verses="full"] [data-verses-kind="term"] > [data-to="full"],
[data-term-verses="refs"] [data-verses-kind="term"] > [data-to="refs"] {
  display: none;
}

/* A switchable list is drawn in both its forms and the window's mode for its
   kind shows one: in full unless the mode says references only. */
.study-shown > .study-verses {
  display: none;
}

[data-xref-verses="refs"] [data-verses-of="xref"] > .study-verses,
[data-term-verses="refs"] [data-verses-of="term"] > .study-verses {
  display: flex;
}

[data-xref-verses="refs"] [data-verses-of="xref"] > .study-xrefs__list,
[data-term-verses="refs"] [data-verses-of="term"] > .study-xrefs__list {
  display: none;
}

/* In a term's verses in full, the verse the window is about, in the
   selection's ink. */
.study-xrefs__ref.study-xrefs__ref--here {
  color: var(--skin-selected-ink);
}

.study-count:focus-visible,
.study-xrefs__ref:focus-visible {
  outline: 2px solid var(--skin-focus);
  outline-offset: 2px;
}

/* Each reference: the reference on its own line in the chrome's sans, the
   verse beneath it in the reading's serif, a rule down the entry's left. The
   reference is a button that opens its verse where it stands, stripped
   back to the type it wore when it was a line of text. */
.study-xrefs__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.study-xrefs__entry {
  margin: 0 0 10px;
  padding-inline-start: 10px;
  border-inline-start: 2px solid var(--skin-quote-rule);
}

.study-xrefs__entry:last-child {
  margin-bottom: 0;
}

.study-xrefs__ref {
  display: block;
  margin: 0;
  padding: 0;
  background: none;
  border: 0;
  text-align: start;
  cursor: pointer;
  font-family: var(--skin-chrome-font);
  font-size: var(--skin-chrome-size-small);
  font-weight: var(--skin-locator-weight);
  line-height: 1.4;
  color: var(--skin-reference-ink);
}

/* The verse: the view's own serif, inherited and not restated; a step under
   the reading size; upright, because the skin's emphasis rule reaches it. */
/* A quoted verse is the one text in the study window set in the serif: the
   pane reads the chrome's sans, and Scripture is told from what was written
   about it by the face alone. */
.study-xrefs__quote {
  display: block;
  font-family: var(--skin-scripture-face);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--skin-quote-ink);
}

/* A run's verse number, before its words: the reading pane's own number, by
   the same tokens, so a quoted run reads as the pane reads. */
.study-xrefs__number {
  font-size: var(--reading-super-size);
  line-height: 0;
  vertical-align: super;
  font-family: var(--reading-display-face);
  color: var(--reading-ink-soft);
  margin-right: 0.25em;
  user-select: none;
}

/* THE ONE FOLD under the verse's own things. Its lid is a tinted row, so it
   reads as a thing to open and not as a line of the note; the triangle in front
   of the words is its state, drawn in content so no image and no font beyond
   the chrome's is needed. The browser's own marker goes, because it differs by
   browser and this one turns. The lid pays the tap minimum. */
.study-fold {
  margin-block-start: 16px;
}

.study-fold__summary {
  display: flex;
  align-items: center;
  min-height: var(--skin-tap-min);
  padding: 0 12px;
  border-radius: var(--skin-radius);
  background: var(--skin-nav-surface);
  font-family: var(--skin-chrome-font);
  font-size: var(--skin-chrome-size-small);
  font-weight: var(--skin-locator-weight);
  color: var(--skin-note-ink);
  cursor: pointer;
  list-style: none;
}

.study-fold__summary::-webkit-details-marker {
  display: none;
}

.study-fold__summary::before {
  content: "\25b8\a0";
  color: var(--skin-label-ink);
}

.study-fold[open] > .study-fold__summary::before {
  content: "\25be\a0";
}

.study-fold__summary:focus-visible {
  outline: 2px solid var(--skin-focus);
  outline-offset: 2px;
}

.study-fold__body {
  padding-block-start: 4px;
}

/* The wider paragraphs: each place's own prose under a small line naming it,
   the line in the label's quiet ink so the prose is what the eye reads. */
.study-wider__source {
  margin: 12px 0 3px;
  font-family: var(--skin-chrome-font);
  font-size: var(--skin-chrome-size-small);
  color: var(--skin-label-ink);
}

.study-wider__source:first-child {
  margin-block-start: 8px;
}

/* A reference inside the fold's prose is a landing: the reference's own ink
   and a pointer, the words otherwise as they were drawn. A reference inside the
   note wears the same, so every link in the window is one colour. */
.study-fold [data-landing],
.study-note .study-note__link {
  color: var(--skin-reference-ink);
  cursor: pointer;
}

/* A study and a term: a lid each, the rows ruled by the
   label's hairline so they read as rows to open. The mark before the title
   turns when the lid opens. */
.study-topic,
.study-term {
  border-block-start: 1px solid var(--skin-label-rule);
}

.study-topic:last-of-type,
.study-term:last-of-type {
  border-block-end: 1px solid var(--skin-label-rule);
}

.study-topic__summary,
.study-term__summary {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-height: var(--skin-tap-min);
  padding: 10px 0;
  box-sizing: border-box;
  cursor: pointer;
  list-style: none;
}

.study-topic__summary::-webkit-details-marker,
.study-term__summary::-webkit-details-marker {
  display: none;
}

.study-topic__summary::before,
.study-term__summary::before {
  content: "\25b8";
  flex: 0 0 12px;
  color: var(--skin-selected-ink);
}

.study-topic[open] > .study-topic__summary::before,
.study-term[open] > .study-term__summary::before {
  content: "\25be";
}

.study-topic__summary:focus-visible,
.study-term__summary:focus-visible {
  outline: 2px solid var(--skin-focus);
  outline-offset: 2px;
}

/* A study's title and a term's name are the window's headings and not
   Scripture, so they stand in the chrome's sans as the lettered headings do. */
.study-topic__title,
.study-term__name {
  font-family: var(--skin-chrome-font);
  font-weight: var(--skin-locator-weight);
  color: var(--skin-note-ink);
}

/* What in the study cites the verse, at the lid's right: quiet, on one line,
   cut rather than wrapped, so a long point never pushes the title down. */
.study-topic__cited {
  flex: 1 1 0;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: end;
  font-family: var(--skin-chrome-font);
  font-size: var(--skin-chrome-size-small);
  color: var(--skin-label-ink);
}

.study-term__summary > .study-count {
  margin-inline-start: auto;
}

.study-topic__body {
  padding: 0 0 12px 20px;
}

.study-topic__definition {
  margin: 0 0 8px;
  line-height: 1.5;
}

/* "Expand outline": small, at the body's top right, in the references' ink. It
   pays the tap minimum; pressed, it takes the selection's weight. */
.study-topic__expand {
  display: block;
  min-height: var(--skin-tap-min);
  margin: 0 0 2px;
  padding: 0;
  background: none;
  border: 0;
  text-align: start;
  cursor: pointer;
  font-family: var(--skin-chrome-font);
  font-size: var(--skin-chrome-size-small);
  color: var(--skin-reference-ink);
}

.study-topic__expand[aria-pressed="true"] {
  font-weight: var(--skin-locator-weight);
}

.study-topic__expand:focus-visible {
  outline: 2px solid var(--skin-focus);
  outline-offset: 2px;
}

.study-topic__heading {
  margin: 10px 0 4px;
  font-family: var(--skin-chrome-font);
  font-size: var(--skin-chrome-size-small);
  font-weight: var(--skin-locator-weight);
  color: var(--skin-note-ink);
}

/* The outline's first step: the numbered points stand one step in from the
   lettered headings, which stay at the body's edge. */
.study-topic__points {
  margin: 0;
  padding: 0;
  padding-inline-start: var(--skin-study-indent);
  list-style: none;
}

.study-point {
  margin: 0 0 4px;
}

/* A point is a button that opens its verses under it: stripped to the pane's
   own type and stretched across the row, so the whole row is the tap. Its
   words stand one step down the scale from the definition's, so the outline
   reads as the definition's detail. */
.study-point__text {
  display: block;
  width: 100%;
  margin: 0;
  padding: 2px 0;
  background: none;
  border: 0;
  font: inherit;
  font-size: var(--skin-chrome-size);
  line-height: 1.45;
  color: inherit;
  text-align: start;
  cursor: pointer;
}

.study-point__text:focus-visible {
  outline: 2px solid var(--skin-focus);
  outline-offset: 2px;
}

.study-point__number {
  color: var(--skin-label-ink);
}

.study-point--open > .study-point__text {
  color: var(--skin-selected-ink);
}

/* A line of references a heading owns: its references are its words, in the
   references' face. */
.study-point--line > .study-point__text {
  font-family: var(--skin-chrome-font);
  font-size: var(--skin-chrome-size-small);
  color: var(--skin-reference-ink);
}

/* A point's verses stand under it only while it is open, the outline's
   second step: one step in from the point, so two in from the heading. */
.study-point__verses {
  display: none;
  margin: 6px 0 8px;
  padding-inline-start: var(--skin-study-indent);
}

.study-point--open > .study-point__verses {
  display: block;
}

.study-term__verses {
  padding: 0 0 12px;
}

/* A term's verses as references only: one wrapped line of them, each a
   button in the selection's ink, the verse the window is about in bold. */
.study-verses {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  line-height: 1.6;
}

.study-verses__ref {
  margin: 0;
  padding: 0;
  background: none;
  border: 0;
  font-family: var(--skin-chrome-font);
  font-size: var(--skin-chrome-size-small);
  color: var(--skin-selected-ink);
  cursor: pointer;
}

.study-verses__ref--here {
  font-weight: var(--skin-locator-weight);
}

.study-verses__ref:focus-visible {
  outline: 2px solid var(--skin-focus);
  outline-offset: 2px;
}

/* The attribution. `margin-top: auto` is the pin: in a flex column it eats every
   spare pixel above the footer, so a short or silent verse puts the credit at
   the base of the window and a long one puts it directly after the words. One
   declaration covers both cases the dispatch names, which is why there is no
   media query and no measurement here. */
.study-credit {
  margin-top: auto;
  padding: 10px var(--reading-pad-inline) 16px;
  border-top: 1px solid var(--skin-credit-rule);
  font-family: var(--skin-chrome-font);
  font-size: var(--skin-chrome-size-small);
  color: var(--skin-credit-ink);
}

/* Three short lines rather than one wrapped sentence — the permission, the
   edition and the credit are three separate claims. A duty discharged by a
   string that does not fit is not discharged. */
.study-credit__line {
  margin: 0;
  line-height: 1.45;
}

/* THE EDITION'S NAME, WEIGHTED EXACTLY AS THE POPUP WEIGHTS IT —
   the same token `.info__title` in window-bar.css uses, so the two surfaces
   cannot drift to two different bolds. Weight is the WHOLE of the emphasis here. The popup also
   dims its lower two lines, but it is dimming them from full chrome ink; this
   footer is already quiet in `--skin-credit-ink` from its parent, and a second
   ink under that one would need a new token pair for a difference nobody could
   see against paper. */
.study-credit__title {
  font-weight: var(--skin-locator-weight);
}

/* A REFERENCE READ WHERE IT STANDS. The host spans the study band and takes no
   taps of its own, so an empty host is nothing to a thumb; the popup inside it
   takes them, and the running layer places it by the reference it opened from.
   Four offsets rather than `inset`, for the older Android WebViews. It is told
   from the note under it by its edge and its shadow, not by its surface alone,
   and its corner reference is underlined: the one thing in it that goes. */
.ref-host {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 2;
  pointer-events: none;
}

.ref-layer {
  box-sizing: border-box;
  pointer-events: auto;
  overflow-y: auto;
  padding: 10px 12px 12px;
  font-family: var(--reading-face);
  background: var(--skin-info-surface);
  color: var(--skin-info-ink);
  border: 1px solid var(--skin-rule);
  border-radius: var(--skin-radius);
  box-shadow: 0 2px 8px var(--skin-info-shadow);
  /* A HOME FOR THE READING VIEW, as .window__content is. The verses stand in
     the view inside the layer, so every mark a verse carries is drawn by the
     shared sheet as it is in the study window: the translators' supplied words
     upright by the skin's one token, the Divine Name in small capitals. The
     layer is the box, so the view inside it keeps no gutter; its paper is the
     skin's to give. */
  --reading-pad-block-start: 0;
  --reading-pad-inline: 0;
  --reading-pad-block-end: 0;
}

.ref-layer--popup {
  position: absolute;
  top: 8px;
  left: 8px;
  max-width: min(22rem, calc(100% - 16px));
  max-height: calc(100% - 16px);
}

.ref-layer__go,
.ref-layer__more {
  display: block;
  min-height: var(--skin-tap-min);
  margin: 0;
  padding: 0;
  background: none;
  border: 0;
  text-align: start;
  cursor: pointer;
  font-family: var(--skin-chrome-font);
  color: var(--skin-reference-ink);
  text-decoration: underline;
}

.ref-layer__go {
  margin-bottom: 4px;
  font-weight: var(--skin-locator-weight);
}

.ref-layer__more {
  margin-top: 6px;
  font-size: var(--skin-chrome-size-small);
}

/* A link-like control of the study window ("See more", "Expand outline") at
   the right edge of its row, where the "N verses" count already stands. A
   button takes its content's width, so the auto margin carries it across.
   After both controls' own rules, so this margin is the one that holds. */
.row-end {
  margin-inline-start: auto;
}

.ref-layer__go:focus-visible,
.ref-layer__more:focus-visible {
  outline: 2px solid var(--skin-focus);
  outline-offset: 2px;
}


/* THE MODAL: the whole reference up to a chapter, over a scrim across the
   whole shell. The host takes no taps while empty; the scrim takes every tap
   outside the modal, which closes it. It sits over everything the shell draws
   and under the splash. */
.ref-modal-host {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 4;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  pointer-events: none;
}

.ref-scrim {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  pointer-events: auto;
  background: var(--skin-scrim);
}

.ref-layer--modal {
  position: relative;
  width: 100%;
  max-width: 34rem;
  max-height: 100%;
}

/* The one line that says a longer reference was cut at its first chapter. */
.ref-layer__foot {
  margin: 10px 0 0;
  font-family: var(--skin-chrome-font);
  font-size: var(--skin-chrome-size-small);
  color: var(--skin-nav-ink-dim);
}


/* ── The lock block ──────────────────────────────────────────────────────────
   Where a book's notes are in a publication that is by access code and not
   opened on this device, the block stands in the note's place: with no license,
   one sentence saying the notes are unlocked under Settings; with one, where the
   notes are, what opens them, and a line to notes that are open to everyone
   where there are some. It is a block and not a quiet line because it asks
   something of the reader; the quiet lines only tell. */
.study-lock {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 0 0 18px;
  padding: 16px;
  border-radius: 10px;
  background: var(--skin-lock-surface);
  font-family: var(--skin-chrome-font);
}

.study-lock p {
  margin: 0;
}

.study-lock__where {
  font-size: 15.5px;
  line-height: 1.45;
  color: var(--skin-note-ink);
}

.study-lock__how,
.study-lock__sample {
  font-size: 14px;
  line-height: 1.45;
  color: var(--skin-label-ink);
}

.access-screen__open,
.access-screen__done {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: 0 16px;
  border: 0;
  border-radius: 8px;
  background: var(--skin-lock-button-surface);
  color: var(--skin-lock-button-ink);
  font-family: var(--skin-chrome-font);
  font-size: 15.5px;
  font-weight: 600;
  cursor: pointer;
}

/* The book's name in the sample line, and the lock block's question: a link
   in the line's own size, which goes where the picker would, or opens the
   code screen. */
.study-lock__go {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--skin-reference-ink);
  text-decoration: underline;
  cursor: pointer;
}

.study-lock__go:focus-visible,
.access-screen__open:focus-visible,
.access-screen__done:focus-visible,
.access-screen__close:focus-visible {
  outline: 2px solid var(--skin-focus);
  outline-offset: 2px;
}

/* ── The code screen ─────────────────────────────────────────────────────────
   Over the whole shell, opened by the lock block's button. The host takes no
   taps while empty. The screen covers the page rather than standing on a
   scrim: a keyboard is about to open under it, and a card over a dimmed page
   would be pushed half out of sight by it. */
.access-host {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 5;
  pointer-events: none;
}

.access-screen {
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  height: 100%;
  overflow-y: auto;
  pointer-events: auto;
  background: var(--skin-info-surface);
  color: var(--skin-info-ink);
  font-family: var(--skin-chrome-font);
}

.access-screen__bar {
  display: flex;
  flex: 0 0 52px;
  align-items: center;
  justify-content: space-between;
  box-sizing: border-box;
  width: 100%;
  max-width: 34rem;
  margin: 0 auto;
  padding: 0 16px;
  border-bottom: 1px solid var(--skin-rule);
}

.access-screen__title {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
}

/* The way off the screen, in every state: a word in a frame, not a bare
   glyph, so a reader sees at once that it is a button and what it does. */
.access-screen__close {
  min-width: var(--skin-tap-min);
  min-height: var(--skin-tap-min);
  padding: 0 14px;
  border: 1.5px solid var(--skin-focus);
  border-radius: 8px;
  background: var(--skin-field-surface);
  color: var(--skin-field-ink);
  font-family: var(--skin-chrome-font);
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
}

.access-screen__form {
  display: flex;
  flex-direction: column;
  gap: 16px;
  box-sizing: border-box;
  width: 100%;
  max-width: 34rem;
  margin: 0 auto;
  padding: 24px 20px 0;
}

.access-screen__form p {
  margin: 0;
  font-size: 15.5px;
  line-height: 1.5;
}

.access-screen__label {
  font-size: 13px;
  font-weight: 600;
  color: var(--skin-label-ink);
}

.access-screen__field {
  box-sizing: border-box;
  width: 100%;
  height: 56px;
  margin-top: 6px;
  padding: 0 14px;
  border: 1.5px solid var(--skin-focus);
  border-radius: 8px;
  background: var(--skin-field-surface);
  color: var(--skin-field-ink);
  font-family: var(--skin-chrome-font);
  font-size: 24px;
  font-weight: 600;
  letter-spacing: 0.14em;
}

/* What "Open the notes" answered. Empty until it has, and it takes no room
   while empty. */
.access-screen__form .access-screen__answer:empty {
  display: none;
}

.access-screen__form .access-screen__answer {
  font-weight: 600;
}

.access-screen__form .access-screen__help {
  font-size: 14px;
  color: var(--skin-label-ink);
}

/* The packages a generic code may open, offered under the answer: one
   button each, in the field's dress. Empty until the gate offers them, and
   then it takes no room, as the answer takes none while empty. */
.access-screen__choices {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.access-screen__choices:empty {
  display: none;
}

.access-screen__choice {
  min-height: 46px;
  padding: 0 16px;
  border: 1.5px solid var(--skin-focus);
  border-radius: 8px;
  background: var(--skin-field-surface);
  color: var(--skin-field-ink);
  font-family: var(--skin-chrome-font);
  font-size: 15.5px;
  font-weight: 600;
  cursor: pointer;
}

.access-screen__choice:focus-visible {
  outline: 2px solid var(--skin-focus);
  outline-offset: 2px;
}

/* The fields and what they answer, and the number shown back in their place:
   each a column in the form's own spacing. The fields are set aside while the
   number is shown back, and the place it is shown in takes no room while
   empty. */
.access-screen__asking,
.access-screen__confirm {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.access-screen__asking[hidden],
.access-screen__confirm:empty {
  display: none;
}

.access-screen__form .access-screen__hint {
  margin-top: 6px;
  font-size: 14px;
  color: var(--skin-label-ink);
}

/* Her number shown back, set out as she will read it on her phone. */
.access-screen__form .access-screen__number {
  font-size: 24px;
  font-weight: 600;
  letter-spacing: 0.04em;
}

.access-screen__change {
  min-height: 46px;
  padding: 0 16px;
  border: 1.5px solid var(--skin-focus);
  border-radius: 8px;
  background: var(--skin-field-surface);
  color: var(--skin-field-ink);
  font-family: var(--skin-chrome-font);
  font-size: 15.5px;
  font-weight: 600;
  cursor: pointer;
}

.access-screen__change:focus-visible {
  outline: 2px solid var(--skin-focus);
  outline-offset: 2px;
}

/* The device's word and what is said around it: a column in the form's own
   spacing, empty until the gate has given the word. The word is set large,
   to be read across a room from a computer's screen to a phone. */
.access-screen__whatsapp {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.access-screen__whatsapp:empty {
  display: none;
}

.access-screen__form .access-screen__word {
  font-size: 32px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: 0.06em;
  overflow-wrap: anywhere;
}

a.access-screen__open {
  text-decoration: none;
}

/* The prompt over a locked App at its opening: the same screen, small, a
   card at the top of the page with the reader standing under it, its field
   not focused so no keyboard rises. Closed, it is gone. */
.access-screen--prompt {
  height: auto;
  max-height: calc(100% - 24px);
  margin-top: 12px;
  margin-inline: max(16px, calc((100% - 34rem) / 2));
  padding-bottom: 20px;
  border: 1px solid var(--skin-rule);
  border-radius: 12px;
  box-shadow: 0 2px 8px var(--skin-info-shadow);
}

.access-screen--prompt .access-screen__form {
  padding-top: 16px;
}
/* ── The Library ──────────────────────────────────────────────────────────────
   The App's third room, over both windows and under the chrome bar, so the
   library icon that opened it is the one that closes it and the settings menu
   still hangs over it. The host is always in the markup and empty when closed,
   and takes no taps while it is: the windows under it are untouched.

   EVERY COLOUR AND FACE HERE IS A SKIN TOKEN. A cover is the chrome's own
   surface and ink with the scripture face for its title; the text of a book is
   the reading view's, drawn by the one reading sheet, and nothing here selects
   into it. */
.library-host {
  position: absolute;
  top: var(--skin-band-height);
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 2;
  pointer-events: none;
}

.library {
  position: relative;
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  height: 100%;
  pointer-events: auto;
  background: var(--skin-window-surface);
  color: var(--skin-window-ink);
  font-family: var(--skin-chrome-font);
}

.library__bar {
  display: flex;
  flex: none;
  align-items: center;
  gap: 4px;
  min-height: var(--skin-tap-min);
  padding: 4px 8px;
  border-bottom: 1px solid var(--skin-rule);
  background: var(--skin-nav-surface);
  color: var(--skin-nav-ink);
}

.library__title {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0 4px;
  overflow: hidden;
  font-size: var(--skin-chrome-size);
  font-weight: var(--skin-chrome-weight);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.library__icon,
.library__size {
  flex: none;
  min-width: var(--skin-tap-min);
  min-height: var(--skin-tap-min);
  padding: 0 6px;
  border: 0;
  border-radius: var(--skin-radius);
  background: transparent;
  color: var(--skin-nav-control-ink);
  font: inherit;
  cursor: pointer;
}

.library__icon--back::before { content: '\2039'; font-size: 22px; }
.library__icon--close::before { content: '\00d7'; font-size: 20px; }
.library__icon--contents::before { content: '\2630'; font-size: 16px; }

.library__size--larger { font-size: 1.15em; }

.library__icon:hover,
.library__size:hover:not(:disabled) {
  background: var(--skin-nav-control-hover);
}

.library__size:disabled {
  color: var(--skin-control-ink-dim);
  cursor: default;
}

/* The night mode's place, kept empty: the App has none of its own. */
.library__slot {
  flex: none;
  width: var(--skin-tap-min);
}

.library__icon:focus-visible,
.library__size:focus-visible,
.library-cover:focus-visible,
.library-continue:focus-visible,
.library__chapter:focus-visible,
.library__step:focus-visible,
.library-popup__bible:focus-visible {
  outline: 2px solid var(--skin-focus);
  outline-offset: 2px;
}

/* ── The shelf ── */
.library__shelf {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: var(--skin-grid-pad);
  overscroll-behavior: contain;
}

.library-continue {
  display: flex;
  align-items: center;
  gap: 12px;
  box-sizing: border-box;
  width: 100%;
  margin: 0 0 12px;
  padding: 10px 12px;
  border: 1px solid var(--skin-label-rule);
  border-radius: var(--skin-radius);
  background: var(--skin-locator-surface);
  color: var(--skin-locator-ink);
  font: inherit;
  text-align: start;
  cursor: pointer;
}

.library-continue__words {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  min-width: 0;
}

/* The book's cover beside the words, where it has one. */
.library-continue__art {
  flex: none;
  width: 40px;
  height: 60px;
  object-fit: cover;
  border-radius: var(--skin-radius);
}

.library-continue__label {
  font-size: var(--skin-chrome-size-small);
  color: var(--skin-label-ink);
}

.library-continue__title {
  font-family: var(--skin-scripture-face);
  font-weight: var(--skin-locator-weight);
}

.library-continue__where {
  font-size: var(--skin-chrome-size-small);
}

.library__search {
  box-sizing: border-box;
  width: 100%;
  min-height: var(--skin-tap-min);
  margin: 0 0 12px;
  padding: 0 10px;
  border: 1px solid var(--skin-rule);
  border-radius: var(--skin-radius);
  background: var(--skin-field-surface);
  color: var(--skin-field-ink);
  font: inherit;
}

.library__search::placeholder {
  color: var(--skin-field-placeholder);
}

/* THREE ACROSS ON A PHONE, and more where there is room: a cover's floor is a
   third of a 390px screen less the shelf's padding and gaps. */
.library__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr));
  gap: var(--skin-grid-gap);
}

@media (max-width: 480px) {
  .library__grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.library-cover {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 8px;
  box-sizing: border-box;
  min-width: 0;
  position: relative;
  overflow: hidden;
  aspect-ratio: 2 / 3;
  padding: 10px 8px;
  border: 1px solid var(--skin-chrome-rule);
  border-left-width: 6px;
  border-radius: var(--skin-radius);
  background: var(--skin-chrome-surface);
  color: var(--skin-chrome-ink);
  text-align: start;
  cursor: pointer;
}

.library-cover__title {
  display: -webkit-box;
  overflow: hidden;
  font-family: var(--skin-scripture-face);
  font-size: var(--skin-chrome-size);
  line-height: 1.25;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 5;
}

.library-cover__byline {
  display: -webkit-box;
  overflow: hidden;
  font-family: var(--skin-chrome-font);
  font-size: var(--skin-chrome-size-small);
  line-height: 1.3;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
}

/* A cover's art fills the cover over its title and credit, which show if it never arrives. */
.library-cover__art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* A book its code has not opened: shown greyed, with what it comes with, and not opened. */
.library-cover--greyed {
  cursor: default;
  opacity: 0.5;
  filter: grayscale(1);
}

.library-cover__note {
  position: relative;
  z-index: 1;
  padding: 2px 4px;
  border-radius: var(--skin-radius);
  background: var(--skin-chrome-surface);
  font-family: var(--skin-chrome-font);
  font-size: var(--skin-chrome-size-small);
  font-style: italic;
  line-height: 1.3;
}

.library__none,
.library__line {
  margin: 16px;
  font-size: var(--skin-chrome-size-small);
  color: var(--skin-nav-ink-dim);
}

/* ── The reader ── */
.library__status {
  flex: none;
  margin: 0;
  padding: 4px 12px;
  border-bottom: 1px solid var(--skin-rule);
  font-size: var(--skin-chrome-size-small);
  color: var(--skin-nav-ink-dim);
}

.library__contents {
  flex: 0 1 auto;
  max-height: 50%;
  margin: 0;
  padding: 4px 0;
  overflow-y: auto;
  border-bottom: 1px solid var(--skin-rule);
  list-style: none;
}

.library__chapter {
  box-sizing: border-box;
  width: 100%;
  min-height: var(--skin-tap-min);
  padding: 0 16px;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: start;
  cursor: pointer;
}

.library__chapter--current {
  background: var(--skin-selected-tint);
  color: var(--skin-selected-ink);
}

/* The page is a reading home: it gives the reading view its gutters, as the
   windows do, and scrolls on its own. */
.library__page {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  --reading-pad-inline: 1rem;
  --reading-pad-block-start: 1rem;
  --reading-pad-block-end: 1.5rem;
}

/* A chapter at a time, the page scrolls down and zooms, and the sideways
   gesture is the swipe's, which turns the chapter. */
.library[data-library-way="chapter"] .library__page {
  touch-action: pan-y pinch-zoom;
}

/* A flowing book steps over each chapter drawn above her itself, so the
   browser is not asked to keep the place as well, which would step twice. */
.library[data-library-way="continuous"] .library__page {
  overflow-anchor: none;
}

/* A page at a time, the page moves only as js/appShell/pagedWindow.js moves
   it, a page at a time, and the sideways gesture is the swipe's. The drawn
   chapter holds the head and the foot over what is not on the page, so it is
   their box; and a chapter's heading stands in its place, not held over
   every page. */
.library[data-library-way="page"] .library__page {
  overflow: hidden;
  touch-action: pan-y pinch-zoom;
}
.library[data-library-way="page"] .library__text > * {
  position: relative;
}
.library[data-library-way="page"] .chapter-heading {
  position: static;
}

.library__foot {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  padding: 12px 12px 32px;
}

.library__step {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-width: 48%;
  min-height: var(--skin-tap-min);
  padding: 6px 10px;
  border: 1px solid var(--skin-label-rule);
  border-radius: var(--skin-radius);
  background: var(--skin-window-surface);
  color: var(--skin-window-ink);
  font: inherit;
  text-align: start;
  cursor: pointer;
}

/* A page at a time the foot stands under the page, out of the box the page
   is cut to, and holds only its two steps. */
.library[data-library-way="page"] .library__foot {
  flex: none;
  padding: 8px 12px 12px;
}

.library__step:disabled {
  color: var(--skin-control-ink-dim);
  cursor: default;
}

.library__step[data-library-next] {
  margin-inline-start: auto;
  text-align: end;
}

.library__step-label {
  font-size: var(--skin-chrome-size-small);
  color: var(--skin-label-ink);
}

/* ── A reference's popup, over the page ── */
.library-popup {
  position: absolute;
  right: 12px;
  bottom: 12px;
  left: 12px;
  max-height: 60%;
  overflow-y: auto;
  padding: 8px 12px 12px;
  border: 1px solid var(--skin-rule);
  border-radius: var(--skin-radius);
  background: var(--skin-info-surface);
  color: var(--skin-info-ink);
  box-shadow: 0 2px 8px var(--skin-info-shadow);
}

.library-popup__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.library-popup__name {
  font-weight: var(--skin-chrome-weight);
  color: var(--skin-reference-ink);
}

.library-popup .library__icon {
  color: inherit;
}

.library-popup__bible {
  min-height: var(--skin-tap-min);
  margin-top: 8px;
  padding: 0 14px;
  border: 0;
  border-radius: var(--skin-radius-pill);
  background: var(--skin-lock-button-surface);
  color: var(--skin-lock-button-ink);
  font: inherit;
  cursor: pointer;
}
