/* The reader (#/read/{document_id}) — src/reader.js, src/pdfview.js, src/epub.js.
   Its own file rather than more of search.css: it is the app's only full-bleed surface, it carries
   pdf.js's text-layer contract, and none of it is reachable from any other view.

   Layout follows .blob-view — fixed, inset past the left rail, its own column-flex column — because
   the reading position is read from a real scroller's geometry, and a view that scrolled with the
   page body would have the app chrome moving inside that measurement. */

.rd {
  position: fixed; inset: 0 0 0 56px; z-index: 40;
  display: flex; flex-direction: column;
  background: var(--bg, #fafbfc); color: var(--ink);
}

/* --- chrome ------------------------------------------------------------------------------- */

.rd-bar {
  display: flex; align-items: center; gap: 12px; flex: none;
  padding: 9px 14px; border-bottom: 1px solid var(--line); background: var(--surface);
}
.rd-back {
  flex: none; width: 34px; height: 34px; border-radius: 10px; cursor: pointer;
  border: 1px solid var(--line); background: var(--surface-2); color: var(--ink-2); font-size: 17px;
}
.rd-back:hover { color: var(--ink); }
.rd-titles { flex: 1; min-width: 0; }
.rd-title { font-size: 14px; font-weight: 620; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rd-sub { margin-top: 1px; font-size: 11.5px; color: var(--ink-3); }

/* Three modes, offered separately (§6). A mode that is off is off because of a PROPERTY of the
   book — a scan has nothing to narrate — and says so, rather than being hidden. */
.rd-modes { flex: none; display: flex; gap: 2px; padding: 2px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface-2); }
.rd-mode {
  cursor: pointer; border: none; background: transparent; border-radius: 999px;
  padding: 5px 13px; font-size: 12px; font-weight: 560; color: var(--ink-3);
}
.rd-mode.on { background: var(--surface); color: var(--ink); box-shadow: 0 1px 2px rgba(16,24,40,.08); }
.rd-mode[data-why] { color: var(--dim, #9aa1ac); cursor: help; }
.rd-toc-btn {
  flex: none; cursor: pointer; font-size: 12px; font-weight: 560; color: var(--ink-2);
  border: 1px solid var(--line); background: var(--surface-2); border-radius: 999px; padding: 6px 13px;
}
.rd-toc-btn[aria-expanded="true"] { color: var(--ai); border-color: color-mix(in srgb, var(--ai) 45%, var(--line)); }

/* Completion, not scroll position: `furthest / total`, which only ever rises. */
.rd-prog { flex: none; height: 3px; background: var(--surface-2); }
.rd-prog i { display: block; height: 100%; background: linear-gradient(90deg, var(--ai), var(--ai2));
  transition: width .3s ease; }

/* `position: relative` so the narrow-screen drawer, which is absolutely positioned, is contained by
   the PAGE COLUMN rather than by .rd. Without it `inset: 0` resolves against the fixed .rd and the
   drawer covers the bar, the player and the footer — including the Contents button that closes it. */
.rd-body { position: relative; flex: 1; display: flex; min-height: 0; }
.rd-foot {
  flex: none; display: flex; align-items: center; gap: 7px; justify-content: center;
  padding: 7px 14px calc(7px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--line); background: var(--surface);
  font-size: 11.5px; color: var(--ink-3);
}
.rd-dot { opacity: .5; }
/* A scan is a PROPERTY, not an error (§10) — styled exactly like .lib-prop, deliberately neutral. */
.rd-prop {
  display: inline-flex; align-items: center; padding: 2px 9px; border-radius: 999px;
  font-size: 11px; font-weight: 560; border: 1px solid var(--line);
  background: var(--surface-2); color: var(--ink-3);
}

/* --- the player bay (listen + immersive) --------------------------------------------------- */
/* Between the page column and the footer, and always in the DOM: showing it must not relayout the
   scroller, because the reading position is measured from that scroller's geometry. */

.rd-bay { flex: none; border-top: 1px solid var(--line); background: var(--surface); }
.rd-bay[hidden] { display: none; }
.rd-player { display: flex; align-items: center; gap: 10px; padding: 8px 14px; }
.rd-player.off { opacity: .55; }
.rd-player button {
  flex: none; cursor: pointer; border-radius: 999px; border: 1px solid var(--line);
  background: var(--surface-2); color: var(--ink-2); font-size: 11.5px; font-weight: 600;
  padding: 0 10px; height: 32px;
}
.rd-player button:hover:not(:disabled) { color: var(--ink); }
.rd-player button:disabled { cursor: not-allowed; opacity: .5; }
.rd-pl-play { width: 40px; padding: 0 !important; font-size: 13px !important;
  background: var(--ai) !important; border-color: var(--ai) !important; color: #fff !important; }
.rd-pl-chap { font-size: 10px !important; letter-spacing: -1px; }
.rd-pl-mid { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.rd-pl-seek { width: 100%; accent-color: var(--ai); height: 4px; cursor: pointer; }
.rd-pl-line { display: flex; align-items: baseline; gap: 10px; font-size: 11px; color: var(--ink-3); }
.rd-pl-clock { flex: none; font-variant-numeric: tabular-nums; }
.rd-pl-note { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rd-pl-note.err { color: #c0392f; }
/* Re-voice. Quiet, because it is rarely the right thing — but reachable, because `library.voice` is
   idempotent and audio predating the sync map can be replaced no other way. */
.rd-pl-revoice {
  flex: none; cursor: pointer; font-size: 11px; color: var(--ink-3); background: none;
  border: none; padding: 0 4px; text-decoration: underline; text-underline-offset: 2px;
}
.rd-pl-revoice:hover { color: var(--ai); }
/* Pause / resume / jump the queue. Same quiet weight as re-voice — they steer a background job, not
   playback — but present whenever a narration is queued, running or paused, because that is exactly
   when a reader wants to reorder it. */
.rd-pl-vc {
  flex: none; cursor: pointer; font-size: 11px; color: var(--ink-3); background: none;
  border: none; padding: 0 4px; text-decoration: underline; text-underline-offset: 2px;
  white-space: nowrap;
}
.rd-pl-vc:hover { color: var(--ai); }
.rd-pl-vc:disabled { opacity: .5; cursor: default; }
.rd-pl-rate {
  flex: none; height: 32px; border-radius: 999px; border: 1px solid var(--line);
  background: var(--surface-2); color: var(--ink-2); font-size: 11.5px; padding: 0 6px; cursor: pointer;
}

/* --- the marks overlay: immersive read-along and annotation highlights ---------------------- */
/* One surface for both, because both are a char range from the persisted text (§10). The rects are
   DERIVED on every paint from the anchor — never stored — which is what lets an anchor survive a
   re-render at a different zoom. */

.rd-mark { position: absolute; border-radius: 2px; pointer-events: none; }
/* The passage being spoken. Deliberately not one of the highlight colours: it is transient, and a
   reader must be able to tell it apart from something they chose to mark. */
.rd-mark.now {
  background: color-mix(in srgb, var(--ai) 22%, transparent);
  box-shadow: inset 0 -1.5px 0 color-mix(in srgb, var(--ai) 65%, transparent);
  transition: opacity .12s linear;
}
/* A search hit. Drawn through the same overlay as the spoken sentence and every highlight, and
   deliberately distinct from both: it is neither something you chose to keep nor something being
   read to you, it is where you just looked. */
.rd-mark.found {
  background: color-mix(in srgb, #f0a020 30%, transparent);
  box-shadow: inset 0 -1.5px 0 color-mix(in srgb, #f0a020 70%, transparent);
}
.rd-mark.c-yellow { background: rgba(255, 214, 0, .34); }
.rd-mark.c-green  { background: rgba( 52, 199, 89, .28); }
.rd-mark.c-blue   { background: rgba( 10, 132, 255, .24); }
.rd-mark.c-pink   { background: rgba(255,  55, 95, .22); }
.rd-mark.c-purple { background: rgba(175,  82, 222, .24); }
/* Made on this device, not yet acknowledged. The highlight is real either way — the user made it —
   so this is a hairline, not a warning. */
.rd-mark.unsynced { outline: 1px dashed color-mix(in srgb, var(--ink-3) 60%, transparent); }

/* The bar over a live selection. Inside the scroller, so it travels with the page. */
.rd-pop {
  position: absolute; z-index: 6; display: flex; align-items: center; gap: 5px;
  padding: 5px 7px; border-radius: 999px; border: 1px solid var(--line); background: var(--surface);
  box-shadow: 0 4px 16px rgba(16,24,40,.16);
}
.rd-pop-c {
  width: 20px; height: 20px; border-radius: 50%; cursor: pointer; padding: 0;
  border: 1px solid rgba(16,24,40,.18);
}
.rd-pop-c.on { box-shadow: 0 0 0 2px var(--ai); }
.rd-pop-c.c-yellow { background: rgba(255, 214, 0, .85); }
.rd-pop-c.c-green  { background: rgba( 52, 199, 89, .8); }
.rd-pop-c.c-blue   { background: rgba( 10, 132, 255, .75); }
.rd-pop-c.c-pink   { background: rgba(255,  55, 95, .7); }
.rd-pop-c.c-purple { background: rgba(175,  82, 222, .75); }
.rd-pop-note {
  cursor: pointer; border: none; background: transparent; color: var(--ink-2);
  font-size: 11.5px; font-weight: 600; padding: 2px 6px;
}

/* --- the drawer: the author's index of the book, and the reader's ---------------------------- */

.rd-outline {
  flex: none; width: 290px; overflow: auto; padding: 0 0 24px;
  border-right: 1px solid var(--line); background: var(--surface);
}
.rd-outline[hidden] { display: none; }
.rd-tabs {
  position: sticky; top: 0; z-index: 1; display: flex; gap: 2px; padding: 8px 8px 6px;
  background: var(--surface); border-bottom: 1px solid var(--line);
}
.rd-tab {
  flex: 1; cursor: pointer; border: none; background: transparent; border-radius: 8px;
  padding: 6px 8px; font-size: 12px; font-weight: 600; color: var(--ink-3);
}
.rd-tab:hover { color: var(--ink); }
.rd-tab.on { background: var(--surface-2); color: var(--ai); }
.rd-aside-close {
  flex: none; width: 30px; height: 30px; border-radius: 8px; cursor: pointer;
  border: none; background: transparent; color: var(--ink-3); font-size: 13px;
}
.rd-aside-close:hover { background: var(--surface-2); color: var(--ink); }
.rd-aside-body { padding: 8px 6px 0; }

/* --- find in this book ---------------------------------------------------------------------- */
/* `library.search` scoped to one document. A hit is a PLACE, so every row is a jump — the same
   char-offset seek the outline and the highlight list use. */
.rd-find { padding: 2px 4px 8px; }
.rd-find-q {
  width: 100%; box-sizing: border-box; font: inherit; font-size: 13px; padding: 8px 11px;
  border-radius: 10px; border: 1px solid var(--line); background: var(--surface); color: var(--ink);
}
.rd-find-q:focus { outline: none; border-color: color-mix(in srgb, var(--ai) 50%, var(--line)); }
.rd-finds { list-style: none; margin: 0; padding: 0; }
.rd-find-i {
  display: block; width: 100%; text-align: left; cursor: pointer; border: none; background: none;
  border-radius: 9px; padding: 8px 10px; color: var(--ink-2);
}
.rd-find-i:hover { background: var(--surface-2); }
.rd-find-i.on { background: color-mix(in srgb, #f0a020 12%, var(--surface-2)); }
.rd-find-s { display: block; font-size: 12.5px; line-height: 1.5; }
.rd-find-w { display: block; margin-top: 3px; font-size: 11px; color: var(--ink-3); }
.rd-toc-retry {
  cursor: pointer; font-size: 12px; color: var(--ai); background: none; border: none;
  padding: 0 2px; text-decoration: underline; text-underline-offset: 2px;
}

/* The reader's own index: every highlight, in document order, each a jump to its place in the
   book — the same char-offset seek the outline uses, which is the practical payoff of anchoring on
   offsets rather than on a page. */
.rd-anns { list-style: none; margin: 0; padding: 0; }
.rd-ann { border-radius: 10px; margin-bottom: 3px; }
.rd-ann:hover { background: var(--surface-2); }
.rd-ann-row { display: flex; align-items: flex-start; gap: 4px; }
.rd-ann-go {
  flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; text-align: left;
  border: none; background: transparent; cursor: pointer; padding: 8px 4px 8px 10px;
  border-left: 3px solid transparent; border-radius: 10px 0 0 10px;
}
.rd-ann.c-yellow .rd-ann-go { border-left-color: rgba(255, 214, 0, .9); }
.rd-ann.c-green  .rd-ann-go { border-left-color: rgba( 52, 199, 89, .9); }
.rd-ann.c-blue   .rd-ann-go { border-left-color: rgba( 10, 132, 255, .9); }
.rd-ann.c-pink   .rd-ann-go { border-left-color: rgba(255,  55, 95, .9); }
.rd-ann.c-purple .rd-ann-go { border-left-color: rgba(175,  82, 222, .9); }
.rd-ann-q { font-size: 12.5px; line-height: 1.45; color: var(--ink); }
.rd-ann-n { font-size: 11.5px; line-height: 1.4; color: var(--ink-2); font-style: italic; }
.rd-ann-m { display: flex; gap: 7px; font-size: 10.5px; color: var(--ink-3); }
.rd-ann-pending { color: var(--dim, #9aa1ac); }
.rd-ann-acts { flex: none; display: flex; gap: 1px; padding-top: 6px; }
.rd-ann-acts button {
  cursor: pointer; border: none; background: transparent; color: var(--ink-3);
  font-size: 12px; width: 24px; height: 24px; border-radius: 7px;
}
.rd-ann-acts button:hover { background: var(--surface); color: var(--ink); }
.rd-ann-del:hover { color: #c0392f; }
.rd-ann-edit { padding: 0 10px 10px; }
.rd-ann-edit[hidden] { display: none; }
.rd-ann-edit textarea {
  width: 100%; box-sizing: border-box; resize: vertical; font: inherit; font-size: 12px;
  border-radius: 8px; border: 1px solid var(--line); background: var(--bg); color: var(--ink);
  padding: 6px 8px;
}
.rd-ann-colors { display: flex; align-items: center; gap: 5px; margin-top: 6px; }
.rd-ann-save {
  margin-left: auto; cursor: pointer; border: 1px solid var(--line); background: var(--surface-2);
  color: var(--ink-2); border-radius: 999px; font-size: 11.5px; font-weight: 600; padding: 4px 12px;
}
.rd-outline-empty { padding: 16px 14px; font-size: 12.5px; color: var(--ink-3); line-height: 1.5; }
.rd-toc { list-style: none; margin: 0; padding: 0; }
.rd-toc-i {
  display: flex; align-items: baseline; gap: 8px; width: 100%; text-align: left;
  border: none; background: transparent; cursor: pointer; border-radius: 8px;
  padding: 6px 10px; font-size: 12.5px; line-height: 1.4; color: var(--ink-2);
}
.rd-toc-i:hover { background: var(--surface-2); color: var(--ink); }
.rd-toc-i.on { background: color-mix(in srgb, var(--ai) 10%, var(--surface)); color: var(--ai); font-weight: 600; }
/* An entry with neither a char offset nor a page cannot be navigated to; it renders as a label so a
   tap that could do nothing is never offered. */
.rd-toc-i.dead { cursor: default; color: var(--ink-3); }
.rd-toc-t { flex: 1; min-width: 0; }
.rd-toc-p { flex: none; font-size: 11px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.rd-toc-i.lv1 { font-weight: 600; color: var(--ink); }
.rd-toc-i.lv2 { padding-left: 22px; }
.rd-toc-i.lv3 { padding-left: 34px; }
.rd-toc-i.lv4 { padding-left: 46px; }
.rd-toc-i.lv5, .rd-toc-i.lv6 { padding-left: 58px; }

/* --- the page column ---------------------------------------------------------------------- */

.rd-scroll { flex: 1; overflow: auto; overscroll-behavior: contain; position: relative;
  scroll-behavior: auto; }
.rd-pages { display: flex; flex-direction: column; align-items: center; gap: 16px; padding: 16px 12px 64px; }
.rd-status {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  max-width: 34ch; text-align: center; font-size: 13px; color: var(--ink-2); line-height: 1.5;
  padding: 12px 18px; border-radius: 12px; border: 1px solid var(--line); background: var(--surface);
}
.rd-status[hidden] { display: none; }
.rd-status.err { color: #c0392f; border-color: color-mix(in srgb, #e0524d 45%, var(--line)); }
.rd-status.note { color: var(--ink-2); }

/* One rendered PDF page. The box keeps its size when the canvas is released on scroll-away —
   otherwise everything below it would shift under a reader who is looking at it. */
.rd-page {
  position: relative; flex: none; background: #fff; border-radius: 3px;
  box-shadow: 0 1px 2px rgba(16,24,40,.10), 0 8px 22px rgba(16,24,40,.08);
}
.rd-canvas { display: block; border-radius: 3px; }
.rd-folio {
  position: absolute; bottom: -14px; right: 2px; font-size: 10px; color: var(--dim, #9aa1ac);
  font-variant-numeric: tabular-nums; pointer-events: none;
}
/* The overlay the immersive read-along and annotation highlights will draw into. Empty today, and
   present today so the stacking order is settled before anything needs it. */
.rd-marks { position: absolute; inset: 0; pointer-events: none; z-index: 2; }

/* --- reflowed content: EPUB chapters and txt/md -------------------------------------------- */

/* `position: relative` because the marks overlay for reflowed content lives INSIDE the flow — there
   are no page boxes here to hang it on, and the highlight rects are measured against it. */
.rd-flow {
  position: relative;
  width: min(72ch, 100%); margin: 0 auto; padding: 8px 4px 40vh;
  font-size: 17px; line-height: 1.68; color: var(--ink);
}
.rd-flow img { max-width: 100%; height: auto; display: block; margin: 20px auto; }
.rd-flow h1, .rd-flow h2, .rd-flow h3, .rd-flow h4 { line-height: 1.25; margin: 1.8em 0 .6em; }
.rd-flow h1 { font-size: 1.5em; } .rd-flow h2 { font-size: 1.3em; } .rd-flow h3 { font-size: 1.12em; }
.rd-flow p { margin: 0 0 1em; }
.rd-flow blockquote { margin: 1em 0; padding-left: 16px; border-left: 3px solid var(--line); color: var(--ink-2); }
.rd-flow pre, .rd-flow code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .87em; }
.rd-flow pre { overflow-x: auto; padding: 12px 14px; border-radius: 10px; background: var(--surface-2);
  border: 1px solid var(--line); }
.rd-flow table { width: 100%; border-collapse: collapse; margin: 1.2em 0; font-size: .92em; }
.rd-flow th, .rd-flow td { border: 1px solid var(--line); padding: 6px 9px; text-align: left; }
.rd-flow hr { border: none; border-top: 1px solid var(--line); margin: 2em 0; }
.rd-note { color: var(--ink-3); font-style: italic; }
/* txt/md: the persisted linear text verbatim, so whitespace is content and every paragraph carries
   the char offset it starts at. */
.rd-text { font-size: 16px; }
.rd-text .rd-para { white-space: pre-wrap; margin: 0 0 1.15em; }

/* --- pdf.js text layer -------------------------------------------------------------------- */
/* Trimmed from pdfjs-dist@6.3.289 web/pdf_viewer.css. Only the selection rules are kept — no
   annotation, XFA or editor layers are rendered. pdf.js positions every span with the
   --total-scale-factor / --font-height / --scale-x / --rotate custom properties it sets inline, so
   these declarations are a CONTRACT with the vendored build: re-check them when re-vendoring. */
.textLayer {
  position: absolute; inset: 0; overflow: clip; opacity: 1; z-index: 1;
  text-align: initial; line-height: 1; letter-spacing: normal; word-spacing: normal;
  text-size-adjust: none; -webkit-text-size-adjust: none; forced-color-adjust: none;
  transform-origin: 0 0; caret-color: CanvasText; color-scheme: only light;
  --min-font-size: 1;
  --text-scale-factor: calc(var(--total-scale-factor) * var(--min-font-size));
  --min-font-size-inv: calc(1 / var(--min-font-size));
}
.textLayer :is(span, br) {
  color: transparent; position: absolute; white-space: pre; cursor: text;
  transform-origin: 0% 0%; user-select: text; -webkit-user-select: text;
}
.textLayer > :not(.markedContent), .textLayer .markedContent span:not(.markedContent) {
  z-index: 1; --font-height: 0; --scale-x: 1; --rotate: 0deg;
  font-size: calc(var(--text-scale-factor) * var(--font-height));
  transform: rotate(var(--rotate)) scaleX(var(--scale-x)) scale(var(--min-font-size-inv));
}
.textLayer .markedContent { display: contents; }
.textLayer span[role="img"] { user-select: none; -webkit-user-select: none; cursor: default; }
.textLayer ::selection { background: color-mix(in srgb, AccentColor, transparent 50%); color: transparent; }
.textLayer br::selection { background: transparent; }

/* --- narrow screens ------------------------------------------------------------------------ */

@media (max-width: 760px) {
  /* The rail is a bottom bar here, so the reader takes the full width and stops above it. */
  .rd { inset: 0 0 calc(56px + env(safe-area-inset-bottom, 0px)) 0; }
  .rd-bar { gap: 8px; padding: 8px 10px; flex-wrap: wrap; }
  /* The switcher WRAPS to its own row rather than being hidden. It used to be display:none with a
     note saying it moved to the footer, which it did not — so listen and immersive were simply
     unreachable on a phone, which is the device most of a narration is played on. */
  .rd-modes { order: 3; width: 100%; justify-content: center; }
  .rd-mode { flex: 1; text-align: center; }
  .rd-toc-btn { padding: 6px 11px; }
  /* The player is the primary control on a phone, and it is inside the fixed .rd — so it stays put
     while the page scrolls under it, which is what "reachable while scrolling" needs. The seek row
     moves ABOVE the transport buttons so the buttons sit at the thumb end of the screen. */
  .rd-player { flex-wrap: wrap; gap: 6px; padding: 8px 10px calc(8px + env(safe-area-inset-bottom, 0px)); }
  .rd-pl-mid { order: -1; width: 100%; flex-basis: 100%; }
  /* 44px is the minimum comfortable touch target, and the transport row spreads to fill the width
     rather than huddling at the left where a thumb cannot reach it. */
  .rd-player button { height: 44px; min-width: 44px; flex: 1; }
  .rd-pl-play { flex: 1.4; }
  .rd-pl-rate { height: 44px; flex: none; }
  .rd-pl-seek { height: 22px; }        /* a bigger hit area than the 4px track it draws */
  .rd-pop { gap: 8px; padding: 8px 10px; }
  .rd-pop-c { width: 30px; height: 30px; }
  .rd-pop-note { font-size: 13px; padding: 6px 8px; }
  /* The drawer covers the page here, so it needs its own way out — and it must clear the bar. */
  .rd-outline { padding-bottom: 40px; }
  .rd-tabs { padding: 10px 8px 8px; }
  .rd-tab { padding: 10px 8px; font-size: 13px; }
  .rd-toc-i { padding: 10px; font-size: 13.5px; }
  .rd-ann-go { padding: 11px 6px 11px 12px; }
  .rd-ann-acts button { width: 34px; height: 34px; }
  .rd-mark { border-radius: 1px; }
  /* Immersive on a small screen: the same colour reads much weaker at phone brightness on a white
     page, so the spoken passage is stronger here rather than fainter. */
  .rd-mark.now { background: color-mix(in srgb, var(--ai) 30%, transparent); }
  /* The drawer covers the page instead of sitting beside it — 290px of a phone is the page. It is
     contained by .rd-body (which is `position: relative` for exactly this), so it covers the page
     column only and leaves the bar, the player and the footer reachable. Above .rd-pop, so a
     selection popover left over from before the drawer opened cannot float on top of it. */
  .rd-outline { position: absolute; inset: 0; width: auto; z-index: 8; border-right: none; }
  .rd-pages { padding: 8px 4px 48px; gap: 10px; }
  .rd-flow { font-size: 17.5px; padding-bottom: 45vh; }
}
