/* features/reader.css - the immersive chapter reader.
 *
 * WHY THIS FILE EXISTS. Everything below used to live in a <style> block inside
 * pages/reader.html. It is one screen's worth of furniture - a fixed toolbar, a
 * progress rule, a settings drawer, a shortcuts overlay, an end-of-chapter card
 * - and a page-local block that size is a stylesheet with no cache and no name.
 * main.css hands the reader over to a component half; this is that half for the
 * reader alone, loaded only by the reader, after main.css and before the
 * per-site token overrides so a site's theme_json still wins on tokens.
 *
 * THE SHELL IS DARK FOR EVERYBODY, AND THE TOKEN FILE IS WHAT MAKES IT DARK.
 * reader.html carries data-theme="dark" as a literal and ships no theme toggle,
 * so html[data-theme="dark"] in tokens/<theme>.css is live for every visitor,
 * including one reading the rest of the site in light mode. The whole dark ramp
 * therefore already applies - ink, links, borders, elevation, the scrim,
 * color-scheme - and none of it is restated here. What IS reader-scoped is the
 * four shell SURFACES, because they are the one part a site may want to tune
 * for this page alone: var(--reader-*, value) gives Site.theme_json a hook with
 * the dark ramp's own values as the fallback. Those five literals are the only
 * ones in the file and each is a fallback, never a paint decision.
 *
 * THE CACHE RULE. The HTML is identical for every visitor, so every preference
 * is an attribute on <html> stamped before first paint from a cookie:
 *   data-mode   strip | paged     which reading surface
 *   data-fit    (absent) | original   image fit; absent means "fit the column"
 *   data-js     present when scripting ran at all
 * Nothing here may key off a class the server printed per visitor, and every
 * rule that hides something because JavaScript will replace it is written
 * html:not([data-js]) so the no-script reader keeps the plain document.
 *
 * DEGRADATION IS A DESIGN CONSTRAINT, NOT A FALLBACK. With scripting off the
 * toolbar is simply always visible, the chapter links in it work, the pages
 * read top to bottom, and the three controls that cannot work without a script
 * - the page jump, the chapter <select>, the settings drawer - are not printed
 * at all rather than printed dead.
 *
 * MOTION IS CONFINED TO THE CHROME, AND THAT IS A RULE, NOT A PREFERENCE. This
 * page is for reading. The toolbar slides out and back, the foot bar goes with
 * it, the drawer translates in from the edge and the progress rule eases as the
 * page moves - and THE PAGES THEMSELVES ARE NEVER TOUCHED: never faded in,
 * never scaled, never revealed on scroll. A reveal on a chapter image is a
 * reader staring at a blank column waiting for a script, and a scale is the
 * artwork moving under the eye that is reading it. The guard rule under THE
 * PAGES says so in CSS as well as in this comment.
 * Everything that does move moves with transform and opacity only, so no frame
 * of it can lay the document out again while a 40-image strip is scrolling.
 *
 * OWNS: .rprogress .rprogress-fill .rnav (+ -in -mark -id -series -chapter
 * -tools -pick -step -step-word -icon -select) .rbar (+ -in -group -count)
 * .rjump .rjump-wrap .rdrawer (+ -panel -head -title -close -group -label -hint
 * -link)
 * .rseg .rseg-track .rkeys (+ -box -head -title -close -list -row -desc -key)
 * .rstage .rpages .rpage .rzone .rzone-prev .rzone-next .rtitle .rtext .rvideo
 * .rend (+ -title -note -actions) .reader-body .reader-shell.
 * Tokens only - no literal colour that is not a documented shell fallback.
 */


/* ================================================================ MOTION === */

/* The reader's own motion values. It shares no stylesheet with the rest of the
   site's motion (pages/reader.html does not extend base.html and never loads
   features/motion.css or features/interactions.css), so the numbers are named
   here rather than borrowed from a file that is not on this page.
   --rx-in is for something arriving, --rx-out for something leaving, and an
   exit is shorter on purpose: a bar getting out of the way should not make the
   reader wait for it. --rx-fast is the progress rule and the small controls. */
:root {
  --rx-fast: 150ms;
  --rx-in: 240ms;
  --rx-out: 180ms;
  --rx-ease: cubic-bezier(.2, .6, .2, 1);
  --rx-press: translateY(1px);
}


/* ================================================================= SHELL === */

.reader-body {
  /* Two metrics, one place. The fixed chrome reserves its own room through
     them, and paged mode grows the foot bar because the page jump is a --tap
     control and a 40px bar cannot hold one. */
  --rnav-h: 56px;
  --rbar-h: 40px;

  --page-bg: var(--reader-page-bg, #0b1220);
  --surface: var(--reader-surface, #131c2e);
  --surface-alt: var(--reader-surface-alt, #1a2438);
  --surface-control: var(--reader-surface-control, #1f2b42);
  /* The breadcrumb pair is the one thing that genuinely cannot be inherited:
     :root computed --crumb-bg from the root's --surface-alt, so a site that
     retunes --reader-surface-alt would otherwise get a breadcrumb bar in the
     ramp it just replaced. */
  --crumb-bg: var(--surface-alt);
  --crumb-ink: var(--text-2);

  background: var(--page-bg);
  color: var(--text);
  /* The chrome is fixed, so the document has to carry its height itself. */
  padding-bottom: calc(var(--rbar-h) + var(--space-5));
  padding-top: var(--rnav-h);
}

html[data-mode="paged"] .reader-body { --rbar-h: 56px; }
html:not([data-js]) .reader-body { padding-bottom: var(--space-5); }

.reader-shell {
  margin: 0 auto;
  max-width: var(--reader-shell);
  padding: 0 var(--space-3);
  width: 100%;
}

/* THE CRUMBS SIT IN THE SHELL, NOT IN THE SITE'S CONTAINER. components/
   breadcrumbs.html is shared with every other page, so it prints .wrap.wrap-3 -
   the 1280px measure the rest of the site is laid out in. This page is laid out
   in the 980px --reader-shell, and the two disagreeing put the crumbs 150px
   left of the title, the pages and the end card on any screen wide enough to
   show both. The component is not this file's to change and it is right for
   every page that does extend base.html, so the reader states its own measure
   over it: three terms beat .wrap-3's one, and the inset is the shell's
   --space-3 rather than .wrap's --space-4, or the left edges would still miss
   each other by 4px. */
.reader-body .crumbs .wrap-3 {
  max-width: var(--reader-shell);
  padding-inline: var(--space-3);
}

.rtitle { font-size: var(--fs-h2); margin: var(--space-5) 0 var(--space-3); }
.rtitle small {
  color: var(--text-muted);
  display: block;
  font-size: var(--fs-meta);
  font-weight: 400;
  margin-top: var(--space-1);
}


/* ========================================================== PROGRESS RULE === */

/* Pinned to the top edge of the VIEWPORT, not to the toolbar: the toolbar
   hides while you read and the one thing that should never go with it is how
   far through the chapter you are. It sits one layer above the bar so the
   3px reads as the bar's own top edge while the bar is up, and as a hairline
   across the artwork once it has gone.

   The fill is scaled, not resized: transform is the only property here that a
   scroll handler may touch sixty times a second without laying the page out
   again. It starts at zero, so with no script this is a quiet track and never
   a bar claiming a position nobody measured. */
.rprogress {
  background: var(--surface-alt);
  height: 3px;
  left: 0;
  position: fixed;
  right: 0;
  top: 0;
  z-index: 45;
}
/* The same strip main.css rules the top of every other page with, which is why
   it is a token and not three stops written out here for the second time: this
   IS that rule, on a scaleX. */
.rprogress-fill {
  background: var(--grad-rule);
  display: block;
  height: 100%;
  transform: scaleX(0);
  transform-origin: left center;
  /* ease-out, and short: this is driven from a rAF-throttled scroll handler, so
     the easing is only there to smooth the step between two samples. Anything
     longer would leave the rule visibly trailing the thumb. */
  transition: transform var(--rx-fast) ease-out;
  width: 100%;
}


/* =============================================================== TOOLBAR === */

/* One bar, fixed, holding everything that used to be printed twice: the mark,
   what is being read, the chapter walk and the way into the settings. It slides
   out of the way on the way down the page and comes back the moment the reader
   scrolls up, taps the middle of the screen, reaches the top, or puts focus on
   anything inside it - see reader.js, which owns the when and leaves the how
   here. */
.rnav {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  height: var(--rnav-h);
  left: 0;
  position: fixed;
  right: 0;
  top: 0;
  /* COMING BACK is the entrance, so it gets the entrance pair; leaving is the
     rule below, which is shorter and eases out. The bar returns the moment the
     reader scrolls up or taps, and that return is the one the eye follows. */
  transition: transform var(--rx-in) var(--rx-ease);
  z-index: 40;
}
/* Translucent only where the browser can actually blur what is behind it: a
   see-through bar with no blur over artwork is unreadable, so the opaque rule
   above stays the default and this is the enhancement. */
@supports ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  .rnav {
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    background: color-mix(in srgb, var(--surface) 86%, transparent);
  }
}

html[data-chrome-hidden] .rnav {
  transform: translateY(-100%);
  transition-duration: var(--rx-out);
  transition-timing-function: ease-out;
}

.rnav-in {
  align-items: center;
  display: flex;
  gap: var(--space-2);
  height: 100%;
}

/* The wordmark, in the reader's own bar. A plate under a white label, so it is
   the --grad-brand token the header's wordmark wears - one measurement, one
   place to re-derive when a site re-themes. */
.rnav-mark {
  background: var(--grad-brand);
  border-radius: var(--r-card);
  color: var(--on-brand);
  flex: 0 0 auto;
  font-size: var(--fs-body);
  font-weight: 700;
  line-height: 1;
  max-width: 160px;
  overflow: hidden;
  padding: var(--space-2) var(--space-3);
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rnav-mark:hover { color: var(--on-brand); text-decoration: none; }

/* Series over chapter, both truncating. min-width:0 is what lets a long title
   shrink instead of pushing the chapter walk off the end of the bar. */
.rnav-id {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  overflow: hidden;
}
.rnav-id:hover { text-decoration: none; }
.rnav-series,
.rnav-chapter {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rnav-series { color: var(--text); font-size: var(--fs-body); font-weight: 650; }
.rnav-id:hover .rnav-series { color: var(--link-hover); }
.rnav-chapter { color: var(--text-muted); font-size: var(--fs-meta); }

.rnav-tools {
  align-items: center;
  display: flex;
  flex: 0 0 auto;
  gap: var(--space-2);
  margin-left: auto;
}
.rnav .btn { min-height: var(--tap); }
.rnav-step { font-weight: 650; padding: 0 var(--space-3); }
.rnav-tool { padding: 0 var(--space-3); }
.rnav-icon { flex: 0 0 auto; height: 18px; width: 18px; }

.rnav-pick { display: flex; }
.rnav-select {
  background-color: var(--surface-control);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-card);
  color: var(--text);
  cursor: pointer;
  flex: 0 1 220px;
  max-width: 220px;
  min-height: var(--tap);
  min-width: 0;
  padding: 0 var(--space-2);
  transition: border-color var(--rx-fast) ease-out;
}
.rnav-select:hover { border-color: var(--brand); }

/* The three controls that are a script's job. Printed, then hidden, rather
   than branched in the template: the markup is cached once for everybody and
   only the client knows whether it can run them. */
html:not([data-js]) .rnav-pick,
html:not([data-js]) .rnav-settings,
html:not([data-js]) .rbar,
html:not([data-js]) .rprogress { display: none; }


/* ============================================================== FOOT BAR === */

/* Where in the chapter, and - in paged mode - the jump. One copy on the page:
   reader.js binds a single [data-page-jump], and a second select carrying the
   same id would be a duplicate id the label points at the wrong one of. */
.rbar {
  background: var(--surface);
  border-top: 1px solid var(--border);
  bottom: 0;
  color: var(--text-2);
  font-size: var(--fs-meta);
  left: 0;
  position: fixed;
  right: 0;
  transition: transform var(--rx-in) var(--rx-ease);
  z-index: 40;
}
@supports ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  .rbar {
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    background: color-mix(in srgb, var(--surface) 86%, transparent);
  }
}
/* The pair travels together - same duration, same curve, opposite directions -
   so hiding the chrome reads as one gesture rather than two bars racing. */
html[data-chrome-hidden] .rbar {
  transform: translateY(100%);
  transition-duration: var(--rx-out);
  transition-timing-function: ease-out;
}

.rbar-in {
  align-items: center;
  display: flex;
  gap: var(--space-3);
  height: var(--rbar-h);
  justify-content: space-between;
}
.rbar-group { align-items: center; display: flex; gap: var(--space-2); min-width: 0; }
.rbar b { color: var(--text); }

/* --tap like every other control on this page: the page jump is used mid-read,
   one-handed. */
.rjump {
  background-color: var(--surface-control);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-card);
  color: var(--text);
  cursor: pointer;
  min-height: var(--tap);
  padding: 0 var(--space-2);
}
/* ONE READOUT PER MODE, and the pair is why: the jump already reads "Page [3]
   of 6", so the text counter beside it was the same number printed twice on one
   56px bar. The jump is the better of the two where it works, because it also
   ANSWERS - and it only works in paged mode, so long strip keeps the words.
   Both are in the cached HTML for every visitor (the HTML cannot know the mode)
   and the attribute stamped before first paint picks. reader.js keeps writing
   [data-progress] while it is off screen, so a mode switch never reveals a
   stale number. */
html[data-mode="strip"] .rjump-wrap { display: none; }
html[data-mode="paged"] .rbar-count { display: none; }


/* ============================================================ THE DRAWER === */

/* Slides in from the side and owns every reading preference, so the reading
   surface itself carries no controls at all.
 *
 * OPEN AND CLOSED ARE visibility, NOT [hidden]. visibility:hidden takes the
 * whole subtree out of the tab order and out of the accessibility tree, which
 * is exactly the behaviour a closed drawer needs, and unlike display:none it
 * transitions - the panel slides rather than appearing. reader.js traps focus
 * while it is open and hands focus back to whatever opened it. */
/* THE EXIT FINISHES BEFORE THE PANEL LEAVES THE ACCESSIBILITY TREE. visibility
   is a discrete property, so a transition on it holds `visible` for the whole
   duration and flips at the very end - which is why the two durations below are
   the same number in each direction. The scrim fades and the panel slides for
   their 180ms, and only then does the subtree go out of the tab order and out
   of the accessibility tree. Swap this for [hidden] and the exit never plays. */
.rdrawer,
.rkeys {
  background: var(--scrim);
  inset: 0;
  opacity: 0;
  position: fixed;
  transition: opacity var(--rx-out) ease-out, visibility var(--rx-out) ease-out;
  visibility: hidden;
}
.rdrawer { z-index: 60; }
.rkeys { z-index: 65; }
.rdrawer.is-open,
.rkeys.is-open {
  opacity: 1;
  transition-duration: var(--rx-in);
  transition-timing-function: var(--rx-ease);
  visibility: visible;
}

.rdrawer-panel {
  background: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow: var(--shadow-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  height: 100%;
  margin-left: auto;
  max-width: 340px;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-5);
  transform: translateX(100%);
  transition: transform var(--rx-out) ease-out;
  width: 88%;
}
/* Arriving takes the entrance curve and the longer duration; leaving keeps the
   rule above, which is quicker and eases out. Both are the same 180-240ms the
   bars use, so the drawer and the chrome feel like one machine. */
.rdrawer.is-open .rdrawer-panel {
  transform: none;
  transition: transform var(--rx-in) var(--rx-ease);
}

.rdrawer-head,
.rkeys-head {
  align-items: center;
  display: flex;
  gap: var(--space-3);
  justify-content: space-between;
}
.rdrawer-title,
.rkeys-title { font-size: var(--fs-h2); }
.rdrawer-close,
.rkeys-close {
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--r-card);
  color: var(--text-2);
  cursor: pointer;
  flex: 0 0 auto;
  height: var(--tap);
  line-height: 0;
  transition: background var(--rx-fast) ease-out, border-color var(--rx-fast) ease-out,
              color var(--rx-fast) ease-out, transform var(--rx-fast) ease-out;
  width: var(--tap);
}
.rdrawer-close:hover,
.rkeys-close:hover { background: var(--surface-control); border-color: var(--border-strong); color: var(--text); }
.rdrawer-close:active,
.rkeys-close:active { transform: var(--rx-press); }
.rdrawer-close svg,
.rkeys-close svg { height: 18px; margin: 0 auto; width: 18px; }

.rdrawer-group { display: flex; flex-direction: column; gap: var(--space-2); }
.rdrawer-label {
  color: var(--text-muted);
  font-size: var(--fs-meta);
  font-weight: 650;
  letter-spacing: var(--track-chip);
  text-transform: uppercase;
}
.rdrawer-hint { color: var(--text-muted); font-size: var(--fs-meta); }
.rdrawer-link {
  align-items: center;
  background: transparent;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-card);
  color: var(--text-2);
  cursor: pointer;
  display: flex;
  font-family: inherit;
  font-size: var(--fs-body);
  font-weight: 600;
  gap: var(--space-2);
  justify-content: space-between;
  min-height: var(--tap);
  padding: 0 var(--space-3);
  /* Colour and border only on hover - the row is full width inside a 340px
     panel and a size change here would move everything under it. */
  transition: background var(--rx-fast) ease-out, border-color var(--rx-fast) ease-out,
              color var(--rx-fast) ease-out, transform var(--rx-fast) ease-out;
  width: 100%;
}
.rdrawer-link:hover {
  background: var(--surface-control);
  border-color: var(--brand);
  color: var(--link);
  text-decoration: none;
}
.rdrawer-link:active { transform: var(--rx-press); }

/* A segmented control, not two buttons: the two values are one choice, and the
   track is what says so. THE SEGMENT ITSELF IS THE TARGET, so it is --tap and
   the 2px track sits outside that - a thumb landing on the track presses
   nothing. */
.rseg-track {
  background: var(--surface-inset);
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  display: flex;
  gap: 2px;
  padding: 2px;
  position: relative;
}

/* THE PLATE SLIDES BETWEEN THE TWO SEGMENTS instead of one switching off as the
   other switches on. It is a single pseudo element moved by two custom
   properties js/reader.js measures off the pressed segment - --seg-x for the
   distance along the track, --seg-s for the scale of a 100px reference box.
   Transform only: this control lives in a drawer over a chapter, and a width
   animation would lay that page out on every frame.
   [data-seg] is written by the script AFTER it has measured, so the pre-paint
   plate below is still what a visitor sees for the first frame and what they
   keep if the script never runs. */
.rseg-track[data-seg]::before {
  background: var(--brand-fill);
  border-radius: var(--r-pill);
  bottom: 2px;
  box-shadow: var(--shadow-1);
  content: "";
  left: 0;
  position: absolute;
  top: 2px;
  transform: translateX(var(--seg-x, 0px)) scaleX(var(--seg-s, 0));
  transform-origin: left center;
  transition: transform var(--rx-in) var(--rx-ease);
  width: 100px;
}

.rseg {
  background: transparent;
  border: 0;
  border-radius: var(--r-pill);
  color: var(--text-2);
  cursor: pointer;
  flex: 1 1 0;
  font-family: inherit;
  font-size: var(--fs-meta);
  font-weight: 650;
  min-height: var(--tap);
  min-width: 0;
  padding: 0 var(--space-3);
  /* Above the sliding plate. */
  position: relative;
  transition: background var(--rx-fast) ease-out, color var(--rx-in) var(--rx-ease),
              transform var(--rx-fast) ease-out;
  z-index: 1;
}
.rseg:hover { color: var(--text); }
.rseg:active { transform: var(--rx-press); }
/* The pressed segment is painted from the attribute on <html>, which the
   pre-paint script stamps from the cookie BEFORE the first frame - so the
   control is already correct when the page appears. aria-pressed is maintained
   by reader.js for assistive tech and is deliberately not what draws this: the
   two can disagree for one frame, and the attribute that was right first is the
   one that should be visible. "Fit the column" is the default and therefore the
   ABSENCE of data-fit, which is why that half is a :not().
   --ring is overridden here because the ring lands on the track, a filled plane
   this control sits inside - the one case the contract allows. */
html[data-mode="strip"] .rseg[data-mode-set="strip"],
html[data-mode="paged"] .rseg[data-mode-set="paged"],
html[data-fit="original"] .rseg[data-fit-set="original"],
html:not([data-fit="original"]) .rseg[data-fit-set="width"] {
  --ring: var(--on-brand);
  background: var(--brand-fill);
  box-shadow: var(--shadow-1);
  color: var(--on-brand);
}
/* ONE PLATE, NOT TWO. With the indicator live the pressed segment keeps its ink
   and its ring override and gives up its fill, so the control reads as a single
   object travelling between the two seats. This is safe to key off aria-pressed
   even though the rule above deliberately is not: [data-seg] is only ever
   stamped after reader.js has written aria-pressed, so the frame where the two
   could disagree is over before this selector can match anything.
   Specificity: four class/attribute terms beats the three above it, which is
   what lets it undo a rule that is written for the no-script case. */
.rseg-track[data-seg] .rseg[aria-pressed="true"] {
  background: transparent;
  box-shadow: none;
  color: var(--on-brand);
}


/* ==================================================== SHORTCUTS OVERLAY === */

.rkeys {
  align-items: center;
  display: flex;
  justify-content: center;
  padding: var(--space-4);
}
.rkeys-box {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-panel);
  box-shadow: var(--shadow-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-height: 90vh;
  max-width: 420px;
  overflow-y: auto;
  padding: var(--space-5);
  /* A short drop rather than a scale: the box holds a table of text, and text
     that is being scaled is text that is briefly blurred. */
  transform: translateY(8px);
  transition: transform var(--rx-out) ease-out;
  width: 100%;
}
.rkeys.is-open .rkeys-box {
  transform: none;
  transition: transform var(--rx-in) var(--rx-ease);
}
.rkeys-list { display: flex; flex-direction: column; gap: var(--space-2); }
.rkeys-row {
  align-items: center;
  border-top: 1px solid var(--border);
  display: flex;
  gap: var(--space-3);
  justify-content: space-between;
  padding-top: var(--space-2);
}
.rkeys-row:first-child { border-top: 0; padding-top: 0; }
.rkeys-desc { color: var(--text-2); font-size: var(--fs-body); }
.rkeys-keys { display: flex; flex: 0 0 auto; gap: var(--space-1); }
.rkeys-key {
  background: var(--surface-control);
  border: 1px solid var(--border-strong);
  border-bottom-width: 2px;
  border-radius: var(--r-card);
  color: var(--text);
  font-family: inherit;
  font-size: var(--fs-meta);
  font-weight: 650;
  min-width: 26px;
  padding: 3px var(--space-2);
  text-align: center;
}


/* ============================================================= THE PAGES === */

.rstage { margin: var(--space-4) 0; position: relative; }
/* Both are jump targets - the skip link lands on the strip, a page turn scrolls
   a figure to the top - and the toolbar is fixed over the top of the document,
   so without this the thing being jumped to arrives underneath it. */
.rstage,
.rpages,
.rpage { scroll-margin-top: calc(var(--rnav-h) + var(--space-2)); }

/* NO GAPS IN STRIP MODE. The figures are block-level and their margins are
   reset, so consecutive pages of one spread meet exactly; the panel's own
   radius is clipped off the first and last page instead of a border being
   drawn between every pair. */
.rpages {
  background: var(--reader-strip-bg, #05080f);
  border: 1px solid var(--border);
  border-radius: var(--r-panel);
  overflow: hidden;
}
.rpage { display: block; }
/* CLS is zero in BOTH cases, which is why the ratio is a variable and not the
   width/height attributes alone. ChapterPage.width/height DEFAULT TO 0, so a
   chapter ingested without dimensions has no attributes to reserve a box with
   and every image would land at zero height and push the page down as it
   arrives. --page-ratio is set inline per page when the dimensions are known;
   the fallback is the shape of an ordinary manga page, so an unmeasured chapter
   reserves an almost-right box instead of nothing at all. It also gives the
   gated pages (data-src, no src yet) their height. */
/* THE GUARD. Nothing about a chapter page moves, ever - no entrance, no fade as
   it decodes, no scale under the pointer, no reveal on scroll. It is stated as
   a rule and not only as a comment because this is the one thing on the page a
   later edit must not "improve": a faded-in page is a reader waiting on a
   script for something the browser had already painted, and a scaled one is the
   artwork shifting under the eye that is reading it. The chrome above is where
   this page is allowed to move. */
.rpage,
.rpage img {
  animation: none;
  transition: none;
}
.rpage img {
  aspect-ratio: var(--page-ratio, 2 / 3);
  display: block;
  height: auto;
  margin: 0 auto;
  width: 100%;
}
/* "Original" is the page's own pixel width, CAPPED at the column - never a
   naked width:auto. An unmeasured page has no intrinsic width until its bytes
   land, so width:auto would reserve nothing and undo the ratio box above;
   --page-width is printed inline beside --page-ratio and falls back to 100%,
   which makes an unmeasured page behave exactly as it does in fit-to-width. */
html[data-fit="original"] .rpage img { width: min(100%, var(--page-width, 100%)); }

html[data-mode="paged"] .rpage { display: none; }
html[data-mode="paged"] .rpage.is-current { display: block; }
html[data-mode="paged"] .rpages .ad { display: none; }

.rzone { display: none; }
html[data-mode="paged"] .rzone {
  background: transparent;
  border: 0;
  bottom: 0;
  cursor: pointer;
  display: block;
  position: absolute;
  top: 0;
  width: 42%;
  z-index: 2;
}
.rzone-prev { left: 0; }
.rzone-next { right: 0; }
/* The gap between them is the centre tap that shows and hides the chrome, and
   it is deliberately not a button: reader.js reads the click's coordinates, so
   the same gesture works in strip mode where these two do not exist. */

.rtext {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-panel);
  color: var(--text-2);
  font-size: var(--fs-lead);
  line-height: 1.8;
  padding: var(--space-6);
}
.rtext p + p { margin-top: var(--space-4); }
.rvideo { aspect-ratio: 16 / 9; border: 0; border-radius: var(--r-panel); width: 100%; }


/* ====================================================== END OF CHAPTER === */

/* The card that means nobody scrolls back up to a dropdown. In paged mode it
   belongs to the LAST page only - reader.js marks it - and that rule can never
   strand a no-script reader, because data-mode is only ever "paged" when a
   script wrote the cookie that put it there. */
.rend {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-panel);
  box-shadow: var(--shadow-1);
  margin: var(--space-6) 0;
  padding: var(--space-6);
  text-align: center;
}
html[data-mode="paged"] .rend { display: none; }
html[data-mode="paged"] .rend.is-end { display: block; }
.rend-title { font-size: var(--fs-h2); }
.rend-note { color: var(--text-muted); font-size: var(--fs-meta); margin-top: var(--space-2); }
.rend-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  justify-content: center;
  margin-top: var(--space-5);
}
.rend-actions .btn { min-height: var(--tap); }
.rend-next { flex: 0 1 320px; }


/* ========================================================== BREAKPOINTS === */

/* The step buttons lose their WORD, not their NAME: sr-only rather than
   display:none, so "Previous" is still what a screen reader announces on the
   phone where only the chevron is drawn. */
@media (max-width: 860px) {
  .rnav-step-word {
    clip-path: inset(50%);
    height: 1px;
    overflow: hidden;
    position: absolute;
    white-space: nowrap;
    width: 1px;
  }
  .rnav-step { padding: 0 var(--space-2); }
}

/* The phone bar keeps the four things a thumb needs - back a chapter, pick a
   chapter, on a chapter, settings - and drops the three the breadcrumb and the
   end card already carry. The tool cluster becomes the flexible half so the
   chapter select can shrink instead of pushing the settings button off the end
   of a 360px screen; the chapter label takes over as the bar's title, since the
   series name it sat under has gone. */
@media (max-width: 700px) {
  .reader-body { --rnav-h: 52px; }
  .rnav-mark,
  .rnav-series { display: none; }
  .rnav-id { flex: 0 1 auto; }
  .rnav-tools { flex: 1 1 auto; gap: var(--space-1); min-width: 0; }
  .rnav-pick { flex: 1 1 auto; min-width: 0; }
  .rnav-select { flex: 1 1 auto; max-width: none; }
  .rnav-chapter { color: var(--text); font-size: var(--fs-body); font-weight: 650; }
  .rend-next { flex: 1 1 100%; }
}

/* main.css answers this preference once, for every transition and animation on
   the page, with !important - so these are already instant. They are restated
   because everything above that MOVES is state, not decoration: a drawer that
   slides, a bar that leaves, a rule that fills. Restating them is what stops a
   later edit here from reintroducing motion the reader asked not to have. */
@media (prefers-reduced-motion: reduce) {
  /* The press travel is not a duration, so no clamp can reach it: taking the
     token out is the answer, exactly as main.css does with --lift. */
  :root { --rx-press: none; }

  .rnav,
  .rbar,
  .rdrawer,
  .rdrawer-panel,
  .rkeys,
  .rkeys-box,
  .rprogress-fill,
  .rseg-track[data-seg]::before { transition: none; }
}
