/* Reader mode — folded into ebook.html as a hidden #reader-root
   container. Per-chapter styling lives inside each chapter's shadow root
   (not here) so book CSS can't leak into the reader UI. Body-scoped
   rules sit under `body.reader-mode` so they only kick in once the host
   has flipped that flag — otherwise reader.css can't be loaded alongside
   the dashboard without clobbering its chrome. */

/* --reader-backdrop lives on :root (not .reader-root) because its
   consumer is `body.reader-mode`, and CSS custom properties cascade
   from ancestor to descendant — body cannot read a var defined on
   one of its own descendants. Light value here, dark overrides below. */
:root {
  --reader-backdrop: #ececef;
  /* Mirrored on :root (not only .reader-root) so the body-level annotation
     palette swatches — which sit outside .reader-root — resolve the colours.
     The reader page highlights read these from .reader-root (with dark
     overrides); these :root values are the light defaults for the palette. */
  --ann-hl-y: rgba(255, 214, 64, 0.42);
  --ann-hl-g: rgba(118, 214, 132, 0.42);
  --ann-hl-p: rgba(208, 150, 240, 0.42);
  --ann-hl-b: rgba(120, 190, 250, 0.42);
}
:root[data-theme="dark"] {
  --ann-hl-y: rgba(212, 168, 36, 0.5);
  --ann-hl-g: rgba(72, 168, 92, 0.5);
  --ann-hl-p: rgba(170, 110, 210, 0.5);
  --ann-hl-b: rgba(78, 148, 220, 0.5);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ann-hl-y: rgba(212, 168, 36, 0.5);
    --ann-hl-g: rgba(72, 168, 92, 0.5);
    --ann-hl-p: rgba(170, 110, 210, 0.5);
    --ann-hl-b: rgba(78, 148, 220, 0.5);
  }
}

.reader-root {
  --reader-bg: #f8f5ef;
  --reader-ink: #1c1c1c;
  --reader-muted: #6b6b6b;
  --reader-page-bg: #ffffff;
  --reader-page-ink: #1c1c1c;
  --reader-page-shadow: 0 1px 3px rgba(0, 0, 0, 0.08), 0 8px 24px rgba(0, 0, 0, 0.06);
  --reader-popover-bg: rgba(255, 255, 255, 0.97);
  --reader-popover-ink: #333;
  --reader-popover-border: rgba(0, 0, 0, 0.1);
  --reader-popover-hover-bg: rgba(0, 0, 0, 0.04);
  --reader-popover-hover-border: rgba(0, 0, 0, 0.15);
  --reader-popover-sep: rgba(0, 0, 0, 0.12);
  --reader-popover-active-bg: rgba(0, 0, 0, 0.06);
  --reader-chevron-ink: rgba(0, 0, 0, 0.35);
  --reader-chevron-ink-hover: rgba(0, 0, 0, 0.6);
  --reader-error-bg: #fff0f0;
  --reader-error-ink: #8a1f1f;
  --reader-page-width: 540px;
  --reader-page-gutter: 58px;
  /* iter BS2-fix3 — mirrored from geometry.pageHeight (JS) so the
     slot-clip matches the wrapper's actual outer height (which obeys
     viewport-fit and ASPECT_MIN/MAX clamps, not strictly pageWidth*√2).
     The √2 fallback is used only before geometry runs. */
  --reader-page-outer-height: calc(var(--reader-page-width) * 1.4142);
}

/* Dark backdrop sits one step lighter than the dark-mode page (#2c2c2e)
   so the page card stays visually distinct without a glowing hairline.
   Scoped to :root (not .reader-root) so body.reader-mode can read it. */
:root[data-theme="dark"] {
  --reader-backdrop: #3a3a3c;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --reader-backdrop: #3a3a3c;
  }
}

/* Dark theme — the reader's PAGE surface stays paper-white when
   body.paper-keeps-light is set (default); when the user opts OUT of
   paper-keeps-light, the page surface darkens too. The reader CHROME
   (bg-around-pages, chevrons, popovers, bookmark/TOC panels) always
   follows the theme regardless. */
:root[data-theme="dark"] .reader-root {
  --reader-bg: #1c1c1e;
  --reader-ink: #f2f2f7;
  --reader-muted: #8e8e93;
  --reader-popover-bg: rgba(44, 44, 46, 0.97);
  --reader-popover-ink: #f2f2f7;
  --reader-popover-border: rgba(255, 255, 255, 0.12);
  --reader-popover-hover-bg: rgba(255, 255, 255, 0.06);
  --reader-popover-hover-border: rgba(255, 255, 255, 0.2);
  --reader-popover-sep: rgba(255, 255, 255, 0.15);
  --reader-popover-active-bg: rgba(255, 255, 255, 0.08);
  --reader-chevron-ink: rgba(255, 255, 255, 0.4);
  --reader-chevron-ink-hover: rgba(255, 255, 255, 0.7);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .reader-root {
    --reader-bg: #1c1c1e;
    --reader-ink: #f2f2f7;
    --reader-muted: #8e8e93;
    --reader-popover-bg: rgba(44, 44, 46, 0.97);
    --reader-popover-ink: #f2f2f7;
    --reader-popover-border: rgba(255, 255, 255, 0.12);
    --reader-popover-hover-bg: rgba(255, 255, 255, 0.06);
    --reader-popover-hover-border: rgba(255, 255, 255, 0.2);
    --reader-popover-sep: rgba(255, 255, 255, 0.15);
    --reader-popover-active-bg: rgba(255, 255, 255, 0.08);
    --reader-chevron-ink: rgba(255, 255, 255, 0.4);
    --reader-chevron-ink-hover: rgba(255, 255, 255, 0.7);
  }
}

/* Reader page surface darkens with the theme — UNLESS paper-keeps-light
   is set on body, in which case the page stays paper-white. The default
   page-shadow inherits from light mode; the dark page (#2c2c2e) on the
   lighter dark backdrop (#3a3a3c) defines its own edge. */
:root[data-theme="dark"] body:not(.paper-keeps-light) .reader-root {
  --reader-page-bg: #2c2c2e;
  --reader-page-ink: #f2f2f7;
  /* Highlights track the PAGE surface, not the global theme: on a paper-
     white page (paper-keeps-light, the default) they keep the light palette;
     only when the page itself darkens do they swap to the higher-saturation
     dark variant. */
  --ann-hl-y: rgba(212, 168, 36, 0.5);
  --ann-hl-g: rgba(72, 168, 92, 0.5);
  --ann-hl-p: rgba(170, 110, 210, 0.5);
  --ann-hl-b: rgba(78, 148, 220, 0.5);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) body:not(.paper-keeps-light) .reader-root {
    --reader-page-bg: #2c2c2e;
    --reader-page-ink: #f2f2f7;
    --ann-hl-y: rgba(212, 168, 36, 0.5);
    --ann-hl-g: rgba(72, 168, 92, 0.5);
    --ann-hl-p: rgba(170, 110, 210, 0.5);
    --ann-hl-b: rgba(78, 148, 220, 0.5);
  }
}

/* Reader backdrop is theme-conditional — pale grey in light mode, a step
   lighter than the dark page in dark mode (see --reader-backdrop cascade
   above). Page card(s) still follow paper-keeps-light. */
body.reader-mode {
  margin: 0;
  padding: 0;
  background: var(--reader-backdrop, #ececef);
  color: var(--reader-ink, #1c1c1c);
  overflow: hidden;
}

/* Full-screen mode (iter DS / #269; unified across editor + reader
   under #119). The body class is set by mountChromeLayer's
   `setFullscreen(on)` in reader mode, and by ebook.js's editor-toolbar
   handler in editor mode — the SINGLE `body.fullscreen` class hides
   the main toolbar + footer regardless of which view set it, so the
   visual contract is identical in both modes. Pre-#269 the reader sat
   between the standard toolbar (top 48px) and footer (bottom 24px); in
   fullscreen both are hidden and `.reader-root`'s top/bottom collapse
   to 0 (driven by `applyReaderRootInsets` which reads this body class).
   The chrome layer's chevrons, popover, progress chip, and close-X
   stay visible — they're inside the reader root, which is now full-
   viewport. State is NOT persisted across sessions (per #269); the
   class is cleared on view teardown so a fresh mount starts normal. */
body.fullscreen .toolbar,
body.fullscreen .app-footer {
  display: none !important;
}
body.fullscreen .reader-root {
  top: 0;
  bottom: 0;
}

/* Reader replaces the editor's workspace but keeps the standard toolbar
   and footer visible — the host only hides the dashboard / editor views
   while reader-mode is active. With those gone, the body's flex-column
   layout has nothing between the toolbar and footer to fill the gap, so
   the footer collapses to a row right under the toolbar (the reader-root
   itself is position:fixed and contributes zero flex height). Push the
   footer to the bottom of the column explicitly. */
body.reader-mode #upload-screen,
body.reader-mode #view-review {
  display: none !important;
}
body.reader-mode .app-footer {
  margin-top: auto;
}

/* The reader's pages sit BETWEEN the toolbar and footer. Top/bottom
   inset is recomputed at runtime against the live toolbar/footer rects
   (reader.js :: applyReaderRootInsets) so the responsive wrap on narrow
   viewports doesn't leave the pages overlapping the chrome. The fallback
   values here cover the unwrapped layout for the first paint.

   The reader-root itself never scrolls — overflow:auto lives one level
   down on .reader-scroller so the chrome layer (a sibling of the
   scroller) stays anchored to the viewport. Browser-native zoom is
   handled by the viewport meta tag; this scroller's overflow:auto lets
   the user pan a zoomed page. */
.reader-root {
  position: fixed;
  top: 48px;
  bottom: 24px;
  left: 0;
  right: 0;
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  overflow: hidden;
}

.reader-root .reader-scroller {
  position: absolute;
  inset: 0;
  overflow-x: hidden;
  overflow-y: auto;
  /* Round 111 (#313) — grid + `safe center` gives reliable two-axis
     centring when the page card fits the viewport, AND falls back to
     `start` (top-aligned) when content overflows so native vertical
     scroll reaches the top. Pre-111 used `margin: auto` on the child,
     which doesn't centre vertically inside a block container that has
     `overflow-y: auto` — bug #313/1 (page aligned to top when it
     should be centred). The `safe` keyword is load-bearing: without
     it, grid would centre overflowing content and the user couldn't
     scroll up to see the clipped top. */
  display: grid;
  align-content: safe center;
  justify-content: safe center;
  /* Block the browser's horizontal back-gesture (mac trackpad two-finger
     swipe, edge-swipe on Android) when the user wheels/pans the reader
     horizontally. readerSwipe.js calls preventDefault on those events;
     `overscroll-behavior-x: contain` is belt-and-braces for cases where
     preventDefault arrives too late (non-cancelable wheel ticks, etc). */
  overscroll-behavior-x: contain;
}

/* In reader mode the main toolbar mirrors the editor's open-book toolbar:
   cover, title, author, read-only badge, burger. Editor-only controls
   (progress span, dialect picker) get hidden via these rules. The spread
   toggle and text-zoom controls have moved out of the toolbar entirely
   — iter D will reintroduce them inside a dissolvable popover. */
body.reader-mode #toolbar-progress {
  display: none;
}

/* Burger menu — items that have no meaning while reading (custom dict,
   font picker, settings) get .is-reader-disabled added at enterReader
   time and the class is dropped on exit. The button is also marked
   disabled so click handlers won't fire. */
.burger-menu-item:disabled,
.burger-menu-item.is-reader-disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.reader-root[hidden] {
  display: none;
}

.reader-root .reader {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.reader-root .reader-error {
  font-size: 1rem;
  padding: 1rem 1.25rem;
  text-align: center;
}

/* Floating load indicator (#71 follow-up). A card that floats near the
   bottom of the reader, OVER the grey backdrop, while the book streams in
   and the first page paginates+paints. It is absolutely positioned (not the
   flex-centred child it used to be) so the first page can paint underneath
   it. Mobile-first: box-sizing border-box + width capped to the viewport so
   it never overflows its column on a narrow screen. */
.reader-root .reader-loading {
  position: absolute;
  left: 50%;
  bottom: max(24px, env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: 5;
  box-sizing: border-box;
  width: 18rem;
  max-width: calc(100% - 32px);
  padding: 0.75rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  background: var(--reader-page-bg, #fff);
  color: var(--reader-muted, #6b6b6b);
  border-radius: 10px;
  box-shadow: 0 6px 20px -6px rgba(0, 0, 0, 0.35);
  font-size: 0.85rem;
  text-align: center;
}
.reader-root .reader-loading[hidden] { display: none; }
.reader-root .reader-loading-label {
  font-weight: 500;
}
.reader-root .reader-loading-track {
  position: relative;
  width: 100%;
  height: 4px;
  border-radius: 2px;
  background: rgba(0, 0, 0, 0.12);
  overflow: hidden;
}
.reader-root .reader-loading-fill {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  width: 0;
  border-radius: 2px;
  background: var(--reader-accent, #3a6ea5);
  transition: width 180ms ease;
}

.reader-root .reader-error {
  color: var(--reader-error-ink);
  background: var(--reader-error-bg);
  border: 1px solid currentColor;
  border-radius: 6px;
  max-width: 32rem;
}

/* Round 100 / 111 — CSS-literal geometry. `.reader-pages` is sized
   inline from JS to exactly the scaled page-rect (pageWidth × ppS ×
   scale wide, pageHeight × scale tall). Centring lives on the parent
   `.reader-scroller` (grid + `safe center`), so this element just
   sits at its natural size. `flex-shrink: 0` / `min-height: 0`
   defensive: grid items default to `auto` min-size which would let a
   tall page card collapse to fit; explicit `0` keeps the literal
   height. */
.reader-root .reader-pages {
  position: relative;
  /* JS sets `width`/`height` inline. Defaults match the natural slot-clip
     so the first paint before mountPinchZoom runs isn't visually wrong. */
  width: var(--reader-page-width);
  height: var(--reader-page-outer-height);
  min-width: 0;
  min-height: 0;
  /* Outer clip — same role as before: nothing escapes the pages region
     even on rapid flips. The inner .reader-slot-clip is the tight clip
     that defines the Apple Books page rectangle. iter BS2. */
  overflow: hidden;
}
.reader-root.is-spread .reader-pages {
  width: calc(2 * var(--reader-page-width));
}

/* iter BS2 — clip element sized to the page rectangle (single mode) or
   spread rectangle (two-page mode). Wrappers are positioned ABSOLUTELY
   inside this clip and translate within its coordinate space, so a
   `translateX(-115%)` lands the wrapper one wrapper-width-plus-margin
   to the left — off-screen with the right-edge drop-shadow safely
   beyond the clip's left edge (iter BS2-fix2). The clip is what gives
   the Apple-Books-style page-turn its hard edge.

   Spread-mode override (iter BS2-fix): the clip must wrap BOTH pages
   plus the inner gap so the wrapper's natural outer-width fits and
   `translateX(-115%)` slides one full spread off-screen. Trigger class
   `is-spread` is set by reader.js whenever geometry reports twoPage.
   The inner gap (one outer marginX, half-margin on each page's inside
   edge — see paginateChapter) is ALREADY absorbed into the wrapper's
   2*pageWidth outer-box, so the clip width is exactly 2*pageWidth.
   `--reader-page-gutter` is retained as a semantic hint and resolves
   to 0 in single mode for the same reason — keeping the formula
   uniform makes the relationship to wrapper geometry explicit. */
.reader-root .reader-slot-clip {
  position: relative;
  width: var(--reader-page-width);
  /* iter BS2-fix3 — was `calc(var(--reader-page-width) * 1.4142)`, which
     is the √2 IDEAL but ignores the viewport-fit clamp inside
     pageGeometry() that may shrink or stretch pageHeight to land between
     ASPECT_MIN..ASPECT_MAX and the available viewport. Mirrored from JS
     via --reader-page-outer-height so the clip matches the wrapper's
     real outer rectangle — otherwise the bottom of the page was being
     cropped and the surviving top margin read as an oversized margin. */
  height: var(--reader-page-outer-height);
  overflow: hidden;
  /* Round 100 — pinch-zoom writes `transform: scale(<s>)` here. Origin
     at 0,0 so the scaled box sits flush against the parent's top-left;
     `.reader-pages` is sized literally to the scaled rect, so the visible
     result fills it exactly. */
  transform-origin: 0 0;
}
.reader-root.is-spread .reader-slot-clip {
  width: calc(2 * var(--reader-page-width));
}

.reader-root .reader-chapter {
  /* All chapter wrappers stay in the DOM so their column-fill layout
     can measure; only the slots carrying a stack-state class are
     visible at any time. iter BS2 replaces the old centre+next-*+gone-*
     transform vocabulary with a two-layer stack pinned at the SAME
     on-screen position: bottom layer (the destination of a forward turn
     / the staying page of a back turn) at translateX(0); top layer
     (sliding off LEFT for forward / IN from LEFT for back) at
     translateX(0) or translateX(-115%). The clip element hides the
     off-screen position; the -15% overshoot keeps the trailing-edge
     drop-shadow outside the clip (iter BS2-fix2). */
  position: absolute;
  top: 0;
  left: 0;
  transform: translateX(0);
  width: 100%;
  height: 100%;
  background: var(--reader-page-bg);
  color: var(--reader-page-ink);
  box-shadow: var(--reader-page-shadow);
  box-sizing: border-box;
  padding: var(--reader-page-margin-y, 48px) var(--reader-page-margin-x, 36px);
  overflow: hidden;
  visibility: hidden;
  z-index: 0;
}

/* Page-stack model: the lower-numbered page is always on top with the
   right-edge depth shadow, and is the page that moves in BOTH directions.
   Forward turn: the OLD page sits on top at translateX(0) with the NEW
   page underneath; the OLD page slides off to the left, uncovering the
   NEW page. Backward turn: the NEW page (lower-numbered, previous) parks
   off-screen left and slides in to translateX(0) over the static OLD
   page underneath.
   States:
   - .is-bottom                     — translateX(0), z-index 1. Static
                                       under-layer.
   - .is-top-offscreen-left         — translateX(-115%), z-index 2,
                                       right-edge shadow. Parked for the
                                       backward turn's slide-in.
   - .is-top-onscreen-shadow-right  — translateX(0), z-index 2, right-edge
                                       shadow. The OLD page during a
                                       forward queue and the slide-out
                                       start position.
   The slide is driven by an inline transform that animates to the
   destination (translateX(0) for backward, translateX(-115%) for
   forward). .is-sliding only enables the transition. -115% (not -100%)
   keeps the leading-edge drop-shadow clear of the slot-clip's edge
   while parked. */
.reader-root .reader-chapter.is-bottom,
.reader-root .reader-chapter.is-top-offscreen-left,
.reader-root .reader-chapter.is-top-onscreen-shadow-right {
  visibility: visible;
}
.reader-root .reader-chapter.is-bottom {
  transform: translateX(0);
  z-index: 1;
  box-shadow: var(--reader-page-shadow);
}
.reader-root .reader-chapter.is-top-offscreen-left {
  transform: translateX(-115%);
  z-index: 2;
  box-shadow:
    var(--reader-page-shadow),
    6px 0 14px -4px rgba(0, 0, 0, 0.16);
}
.reader-root .reader-chapter.is-top-onscreen-shadow-right {
  transform: translateX(0);
  z-index: 2;
  box-shadow:
    var(--reader-page-shadow),
    6px 0 14px -4px rgba(0, 0, 0, 0.16);
}

.reader-root .reader-chapter.is-sliding {
  transition: transform 220ms ease;
}
/* Forward uses the time-reverse of `ease` (each control point reflected
   through 0.5,0.5) so forward IS backward played in reverse. */
.reader-root .reader-chapter.is-sliding.is-sliding-forward {
  transition-timing-function: cubic-bezier(0.75, 0, 0.75, 0.9);
}

@media (prefers-reduced-motion: reduce) {
  /* Belt-and-braces: even if reader.js skipped its prefersReducedMotion
     short-circuit (e.g. older browser without matchMedia returning
     `matches: true`), CSS still snaps. */
  .reader-root .reader-chapter,
  .reader-root .reader-chapter.is-sliding { transition: none; }
}

/* Page-internal header lives INSIDE each chapter's shadow root (see
   readerRender.renderChapter — it injects a `.reader-page-header` div
   styled via a <style> sibling). Shadow encapsulation prevents reader.css
   from reaching in, so the styling is shipped with the element itself. */

/* Tap-zone overlays sit ON TOP of the page. Pointer events pass through
   to the shadow root for click-to-Latin (commit 8) — these elements get
   pointer-events only when a click hits a NON-link, NON-event-span area.
   For v1 we keep them invisible and use a single delegated click on
   the reader-pages container instead. */
.reader-root .reader-nav-zones {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* Dissolvable panel chrome — chevrons + settings popover. The whole
   layer fades in on pointer/keyboard activity and fades back out after
   3 s idle (timer managed by reader.js :: mountChromeLayer). The layer
   has pointer-events:none so it doesn't intercept clicks while invisible;
   the per-child opt-in restores pointer events for the actual controls.

   While hidden (no .is-chrome-visible on .reader-root) we ALSO force
   pointer-events:none on every descendant so the invisible chrome can't
   eat clicks that look like they're hitting blank page (round 132 /
   2026-05-27 report). Autoshow-on-hover doesn't help mobile, so the
   fix is: hidden means hidden. The same .is-chrome-visible toggle the
   JS already manages now gates input as well as opacity — no parallel
   handler, no per-button book-keeping. */
.reader-root .reader-chrome-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 200ms ease;
  z-index: 2;
}
.reader-root.is-chrome-visible .reader-chrome-layer { opacity: 1; }
.reader-root:not(.is-chrome-visible) .reader-chrome-layer * { pointer-events: none; }

/* Large stretched chevrons on the left/right of the viewport. Click =
   page turn. The invisible tap zones in bindGlobalNav stay live whether
   or not chrome is showing, so users who don't move their mouse can
   still page through by clicking the page-edge areas. */
.reader-root .reader-chevron {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 48px;
  height: 60vh;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 48px;
  color: var(--reader-chevron-ink);
  background: transparent;
  border: none;
  cursor: pointer;
  pointer-events: auto;
  user-select: none;
  padding: 0;
  font-family: system-ui, -apple-system, sans-serif;
}
.reader-root .reader-chevron.prev { left: 8px; }
.reader-root .reader-chevron.next { right: 8px; }
.reader-root .reader-chevron:hover { color: var(--reader-chevron-ink-hover); }
.reader-root .reader-chevron:disabled { opacity: 0.2; cursor: default; }

/* Settings popover in the top-right corner. Spread toggle, zoom group,
   edit-chapter button. */
.reader-root .reader-popover {
  position: absolute;
  top: 16px;
  right: 16px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 8px;
  background: var(--reader-popover-bg);
  border: 1px solid var(--reader-popover-border);
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  pointer-events: auto;
  font: 13px/1.3 system-ui, -apple-system, sans-serif;
  color: var(--reader-popover-ink);
}
.reader-root .reader-popover-btn {
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  padding: 4px 8px;
  cursor: pointer;
  font: inherit;
  color: var(--reader-popover-ink);
}
.reader-root .reader-popover-btn:hover {
  border-color: var(--reader-popover-hover-border);
  background: var(--reader-popover-hover-bg);
}
.reader-root .reader-popover-sep {
  width: 1px;
  height: 18px;
  background: var(--reader-popover-sep);
  margin: 0 4px;
  display: inline-block;
}
.reader-root .reader-popover-readout {
  min-width: 3.5em;
  text-align: center;
}

/* Full-screen close-X (iter DS / #269). Top-left corner of the chrome
   layer; hidden outside fullscreen so it doesn't add a second close
   affordance to the normal layout. In fullscreen the toolbar's exit-
   reader paths are gone, so this gives the user a clear, always-on
   "leave fullscreen" surface. Fades with the rest of the chrome layer
   via the parent's opacity transition (controlled by .is-chrome-visible
   on .reader-root). */
.reader-root .reader-fullscreen-close {
  position: absolute;
  top: 16px;
  left: 16px;
  display: none;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  background: var(--reader-popover-bg);
  border: 1px solid var(--reader-popover-border);
  border-radius: 50%;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  color: var(--reader-popover-ink);
  pointer-events: auto;
  cursor: pointer;
  padding: 0;
}
body.fullscreen .reader-root .reader-fullscreen-close {
  display: flex;
}
.reader-root .reader-fullscreen-close:hover {
  border-color: var(--reader-popover-hover-border);
  background: var(--reader-popover-hover-bg);
}
.reader-root .reader-fullscreen-close .shave-icon {
  width: 18px;
  height: 18px;
}

/* Two-page mode is unusable on phone-width portrait; hide the toggle to
   avoid a no-op control. The breakpoint matches the spread-fits check in
   pageGeometry() — at viewports narrower than ~720px in portrait, the
   spread layout never satisfies the safe-margin so the button does
   nothing. */
@media (max-width: 720px) and (orientation: portrait) {
  .reader-root [data-role="reader-spread-toggle"] {
    display: none;
  }
}

/* Floating Edit/Download/Fullscreen toolbar (iter DV / #289). Visible
   at ALL viewports — Round 91 (#270) originally gated this on
   (max-width: 720px) and kept Edit/Download in the popover for
   desktop; #289 unifies the surface so the line-art icons read at
   every width. The floating toolbar also now hosts the fullscreen
   toggle (moved out of the popover, was iter DS / #269). Shares
   click handlers with the prior popover buttons (see reader.js). */
.reader-root .reader-floating-toolbar {
  position: absolute;
  /* #119 chrome symmetry swap: floating toolbar moved from bottom-LEFT
     to bottom-RIGHT to match the editor's floating toolbar position.
     The page-info / progress chip moved the opposite way in the same
     change so the two corners' roles are consistent across views. */
  bottom: 16px;
  right: 16px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 8px;
  background: var(--reader-popover-bg);
  border: 1px solid var(--reader-popover-border);
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  pointer-events: auto;
  color: var(--reader-popover-ink);
}
/* Icons inherit color from the button text (currentColor stroke in
   icons.js) so they pick up the light/dark theme automatically — same
   pattern as the spread / bookmark / TOC icons above. */
.reader-root [data-role="reader-floating-edit"] .shave-icon,
.reader-root [data-role="reader-floating-download"] .shave-icon,
.reader-root [data-role="reader-floating-settings"] .shave-icon,
.reader-root [data-role="reader-floating-fullscreen"] .shave-icon {
  width: 18px;
  height: 18px;
  display: block;
}
/* Popover Edit + Download are gone from the popover under #289 — the
   floating toolbar owns them at every viewport. Hide the unused DOM
   holders so they don't paint as ghost buttons. The DOM stays so the
   shared click-handler binding in reader.js keeps working without a
   conditional. */
.reader-root .reader-popover [data-role="reader-edit-chapter"],
.reader-root .reader-popover [data-role="reader-download"] {
  display: none;
}
/* sep3 sat between the bookmarks group and Edit/Download in the
   popover; with both gone the last `.reader-popover-sep` is now a
   dangling divider at the end of the row. Hide it. */
.reader-root .reader-popover .reader-popover-sep:last-of-type {
  display: none;
}

/* Bookmarks (iter BB). The toggle + list chevron sit inline in the
   popover; the bookmarks list panel pops down beneath the popover when
   the list button is clicked. */
/* Spread toggle uses [data-role] (no role-class added by makePopoverButton),
   matching the TOC selector below; bookmark buttons use class selectors
   because the JS adds `reader-bookmark-toggle`/`reader-bookmark-list` to
   the button's className explicitly. Don't change one without the other. */
.reader-root .reader-bookmark-toggle .shave-icon,
.reader-root .reader-bookmark-list .shave-icon,
.reader-root [data-role="reader-spread-toggle"] .shave-icon,
.reader-root [data-role="reader-parallel-toggle"] .shave-icon {
  width: 14px;
  height: 14px;
  display: block;
}
.reader-root .reader-bookmark-list {
  padding: 4px 4px;
  min-width: 0;
}
.reader-root .reader-bookmarks-panel {
  position: absolute;
  top: 56px;
  right: 16px;
  min-width: 240px;
  max-width: 360px;
  max-height: 320px;
  overflow: auto;
  background: var(--reader-popover-bg);
  border: 1px solid var(--reader-popover-border);
  border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
  padding: 6px;
  pointer-events: auto;
  font: 13px/1.3 system-ui, -apple-system, sans-serif;
  color: var(--reader-popover-ink);
}
.reader-root .reader-bookmarks-panel[hidden] {
  display: none;
}
.reader-root .reader-bookmarks-row {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  padding: 6px 8px;
  cursor: pointer;
  font: inherit;
  color: inherit;
}
.reader-root .reader-bookmarks-row:hover {
  background: var(--reader-popover-hover-bg);
  border-color: var(--reader-popover-border);
}
.reader-root .reader-bookmarks-empty {
  padding: 8px 12px;
  color: var(--reader-muted);
  font-style: italic;
}

/* TOC dropdown (iter BT). Mirrors the bookmarks-panel layout but
   anchored to the LEFT of the popover so the chapter list opens
   beneath its toggle button. */
.reader-root [data-role="reader-toc"] .shave-icon {
  width: 14px;
  height: 14px;
  display: block;
}
.reader-root .reader-toc-panel {
  position: absolute;
  top: 56px;
  right: 16px;
  min-width: 260px;
  max-width: 420px;
  max-height: 60vh;
  overflow: auto;
  background: var(--reader-popover-bg);
  border: 1px solid var(--reader-popover-border);
  border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
  padding: 6px;
  pointer-events: auto;
  font: 13px/1.3 system-ui, -apple-system, sans-serif;
  color: var(--reader-popover-ink);
}
.reader-root .reader-toc-panel[hidden] {
  display: none;
}
.reader-root .reader-toc-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  width: 100%;
  text-align: left;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  padding: 6px 8px;
  cursor: pointer;
  font: inherit;
  color: inherit;
}
.reader-root .reader-toc-row:hover {
  background: var(--reader-popover-hover-bg);
  border-color: var(--reader-popover-border);
}
.reader-root .reader-toc-row.is-current {
  background: var(--reader-popover-active-bg);
  font-weight: 600;
}
.reader-root .reader-toc-row-title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.reader-root .reader-toc-row-page {
  flex: 0 0 auto;
  color: var(--reader-muted);
  font-variant-numeric: tabular-nums;
}
.reader-root .reader-toc-empty {
  padding: 8px 12px;
  color: var(--reader-muted);
  font-style: italic;
}

/* Floating progress chip (iter BT3). Sits in the bottom-right of the
   reader viewport as a standalone overlay — pure progress meta, separate
   from the popover toolbar. Dissolves alongside the rest of the chrome
   via the layer's opacity transition. Themed against --reader-popover-*
   so it reads on both light/dark backdrops; opacity 0.85 keeps it
   present-but-recessive. Mobile-respecting: max-width caps the line and
   text-overflow:ellipsis clips on cramped viewports. */
.reader-root .reader-progress-chip {
  position: absolute;
  /* #119 chrome symmetry swap: progress chip moved from bottom-RIGHT
     to bottom-LEFT to match the editor's chrome (no editor-side
     equivalent on the right; bottom-right is the floating-toolbar
     corner). See .reader-floating-toolbar above for the paired swap. */
  bottom: 16px;
  left: 16px;
  pointer-events: auto;
  font: 11px/1.4 system-ui, -apple-system, sans-serif;
  color: var(--reader-popover-ink);
  background: var(--reader-popover-bg);
  border: 1px solid var(--reader-popover-border);
  border-radius: 12px;
  padding: 4px 10px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
  opacity: 0.85;
  max-width: calc(100% - 32px);
  /* Two-row stack (iter DU / #290): the "n pages left in chapter"
     tail wraps to its own row so the chip's first row doesn't
     collide with the bottom-right floating toolbar at narrow widths.
     Left-aligned to keep the visible left edge clean as the rows
     swap length between page-turns. */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
  box-sizing: border-box;
}
.reader-root .reader-progress-headline,
.reader-root .reader-progress-tail {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
/* Empty tail collapses so the chip shrinks to a single row when the
   controller has no pages-left phrase to report (e.g. last page of
   last chapter without the "last page in chapter" copy, or pre-init). */
.reader-root .reader-progress-tail:empty {
  display: none;
}
/* Chip itself collapses only when BOTH rows are empty. The flex
   container can't use :empty (children are always present), so gate
   on a marker class written by refreshProgress when both rows go
   blank — kept simple by hiding via an `:has` rule on the empty
   children. Modern browsers (Safari/Chrome/Firefox latest) all
   support :has; older browsers see a degenerate empty pill, which is
   visually unobtrusive. */
.reader-root .reader-progress-chip:has(.reader-progress-headline:empty):has(.reader-progress-tail:empty) {
  display: none;
}

/* Width-only breakpoint (landscape phones included) so the chrome
   stops drifting toward the page centre on tight viewports. */
@media (max-width: 720px) {
  .reader-root .reader-popover {
    top: 4px;
    right: 4px;
    padding: 4px 6px;
    gap: 2px;
  }
  .reader-root .reader-fullscreen-close {
    top: 4px;
    left: 4px;
  }
  .reader-root .reader-floating-toolbar {
    /* #119: matches the bottom-right swap above. */
    bottom: 4px;
    right: 4px;
    padding: 4px 6px;
    gap: 2px;
  }
  .reader-root .reader-progress-chip {
    /* #119: matches the bottom-left swap above. */
    bottom: 4px;
    left: 4px;
  }
  .reader-root .reader-bookmarks-panel,
  .reader-root .reader-toc-panel {
    top: 44px;
    right: 4px;
  }
}

/* Hover-for-Latin tooltip. Lives at body-level (not inside the chapter
   shadow root) because .reader-chapter has translateX(...) and a
   transformed ancestor would re-anchor position:fixed away from the
   viewport. Intentionally dark on both light and dark themes — it's a
   contrast pill, not part of the page surface. Pointer-events are
   enabled so moving the mouse onto the tooltip cancels its hide timer
   (readerTooltip.js bindHoverLookup). */
.reader-tooltip {
  position: fixed;
  z-index: 50;
  background: #222;
  color: #fff;
  padding: 4px 10px;
  border-radius: 6px;
  font: 14px/1.3 system-ui, -apple-system, sans-serif;
  max-width: min(80vw, 360px);
  transform: translate(-50%, -100%);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.reader-tooltip[data-placement="below"] {
  transform: translate(-50%, 0);
}
.reader-tooltip[hidden] {
  display: none;
}

/* Annotation palette — body-level fixed popover (same containing-block
   rationale as .reader-tooltip: a transformed .reader-chapter ancestor would
   break position:fixed). Styled as the .cw-picker toolbar family: a tidy small
   container of .cw-pick-btn icon buttons, NOT a heavy drop-shadow popover. */
.ann-palette {
  position: fixed;
  z-index: 51;
  display: flex;
  gap: 4px;
  align-items: center;
  padding: 4px;
  border-radius: 4px;
  background: var(--bg);
  border: 1px solid var(--border);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.18);
  transform: translate(-50%, -100%);
}
.ann-palette[data-placement="below"] {
  transform: translate(-50%, 0);
}
.ann-palette[hidden] {
  display: none;
}
/* Colour swatches are standard 28x28 icon-button frames with a small colour
   dot inside — matching .cw-pick-btn, never a raw colour block. Selected =
   a clear accent ring, consistent with the rest of the app's controls. */
.ann-swatch-dot {
  display: block;
  width: 14px;
  height: 14px;
  border-radius: 50%;
}
.ann-swatch-y .ann-swatch-dot { background: var(--ann-hl-y); }
.ann-swatch-g .ann-swatch-dot { background: var(--ann-hl-g); }
.ann-swatch-p .ann-swatch-dot { background: var(--ann-hl-p); }
.ann-swatch-b .ann-swatch-dot { background: var(--ann-hl-b); }
.ann-swatch.selected {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent) inset;
}

/* Highlight wrapper — light DOM (editor panes). The reader's chapters live
   in a shadow root, which can't see this sheet, so readerRender.js injects an
   identical rule into each chapter's shadow baseStyle; both consume the
   --ann-hl-* palette vars defined on :root above. */
.ann-hl { border-radius: 2px; cursor: pointer; }
.ann-hl[data-ann-color="y"] { background: var(--ann-hl-y); }
.ann-hl[data-ann-color="g"] { background: var(--ann-hl-g); }
.ann-hl[data-ann-color="p"] { background: var(--ann-hl-p); }
.ann-hl[data-ann-color="b"] { background: var(--ann-hl-b); }

/* Depressed-toggle state for popover buttons (parallel + spread toggles).
   Darker fill, inset shadow, and contrasted border read clearly as
   "this control is currently engaged" — distinct from a plain hover. */
.reader-root .reader-popover-btn.is-active {
  background: var(--reader-popover-active-bg, rgba(0, 0, 0, 0.18));
  border-color: rgba(0, 0, 0, 0.35);
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.25);
}
:root[data-theme="dark"] .reader-root .reader-popover-btn.is-active {
  background: rgba(255, 255, 255, 0.22);
  border-color: rgba(255, 255, 255, 0.4);
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.5);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .reader-root .reader-popover-btn.is-active {
    background: rgba(255, 255, 255, 0.22);
    border-color: rgba(255, 255, 255, 0.4);
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.5);
  }
}

