/* ============================================================================
   MERALCO IR — FLIPBOOK READER  ·  Direction: EDITORIAL LIGHT
   A bright art-book reading room. Warm-white gallery paper, navy structural
   type, Meralco orange used ONLY for the live/active state. Chrome is thin,
   hairline-ruled, glass-quiet, and auto-hides so the book is alone with its
   shadow.

   SELF-CONTAINED: this file bundles its own fonts, brand tokens and a scoped
   reset, so the reader works WITHOUT the site-wide App.css / Destyle.css. That
   keeps it drop-in / iframe-embeddable on the client's Drupal 10 instance with
   no dependency on (or conflict with) the host theme.
   ========================================================================= */

/* Fonts — paths resolve relative to THIS file (web/css/ → web/fonts/). */
@font-face {
  font-family: 'TASA Explorer Regular';
  src: url('../fonts/TASAExplorer-Regular.ttf') format('truetype');
  font-display: swap;
}
@font-face {
  font-family: 'TASA Explorer Bold';
  src: url('../fonts/TASAExplorer-Bold.ttf') format('truetype');
  font-display: swap;
}
@font-face {
  font-family: 'TASA Explorer Extra Bold';
  src: url('../fonts/TASAExplorer-ExtraBold.ttf') format('truetype');
  font-display: swap;
}

:root {
  /* EDITORIAL LIGHT — reader tokens */
  --reader-bg: #F4F2EE;
  --reader-bg-center: #FAF8F4;
  --reader-bg-edge: #ECE9E2;
  --reader-paper: #FFFFFF;
  --reader-skeleton: #F1EEE8;
  --reader-shimmer: #FBFAF7;

  /* Brand palette — own values, with App.css vars as an override if present */
  --navy: var(--primary-color, #2C5283);
  --accent: var(--secondary-color, #ED7734);
  --accent-hover: var(--secondary-color-hover, #D9662D);

  /* Brand fonts (self-defined so the reader needs no external stylesheet) */
  --header-font-family: 'TASA Explorer Extra Bold', sans-serif;
  --body-font-family: 'TASA Explorer Regular', sans-serif;
  --accent-font-family: 'TASA Explorer Bold', sans-serif;

  /* Deep-navy tint (#24344A) for hairlines + warm-cool shadows (never gray) */
  --ink: 36, 52, 74;

  /* House easing — one "soft settle" curve for all chrome motion */
  --ease: cubic-bezier(.22, 1, .36, 1);

  /* navy-tinted muted text — clears WCAG AA (4.5:1) on the warm-white paper */
  --reader-muted: #5A6473;

  --top-h: 56px;
}

/* Scoped reset — replaces the dependency on Destyle.css. Only touches the
   reader subtree, so it never affects the surrounding Drupal page. */
.reader, .reader *, .reader *::before, .reader *::after { box-sizing: border-box; }
.reader button { font: inherit; color: inherit; background: none; border: 0; }

/* ---- Document baseline ---------------------------------------------------- */
html, body {
  height: 100%;
  margin: 0;
  overflow: hidden;            /* the reader owns the viewport */
  overscroll-behavior: none;   /* no pull-to-refresh / rubber-band stealing a swipe */
  background: var(--reader-bg);
}

/* ============================================================================
   ENVIRONMENT — gallery-white wash + cold-pressed paper grain
   ========================================================================= */
.reader {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  font-family: var(--body-font-family);
  color: var(--navy);
  background: radial-gradient(120% 90% at 50% 38%,
      var(--reader-bg-center) 0%, var(--reader-bg) 55%, var(--reader-bg-edge) 100%);
  /* faint top-edge vignette anchors the masthead */
  box-shadow: inset 0 6px 30px -18px rgba(var(--ink), .10);
  overflow: hidden;
}

/* 2.5% fractal-noise grain so the white reads as fine-art paper, not #fff */
.reader::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  opacity: .025;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence baseFrequency='0.9'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ============================================================================
   TOP MASTHEAD — slim, hairline-ruled, auto-hides
   PERF (grafted from gallery-noir): NO backdrop-filter on the masthead. Blur
   is reserved exclusively for the small bottom capsule to keep blur surface
   area off the animating flip canvas.
   ========================================================================= */
.reader__top {
  /* Floats over the top of the stage (absolute) so it reserves NO layout space when
     auto-hidden — the masthead was `position: relative`, leaving a permanent ~52px dead
     band at the top even while idle. Now the stage fills the full height and the page
     centers in it; the bar floats in the top margin. padding-top clears the iOS notch /
     Dynamic Island (matches the safe-area handling on the bottom capsule). */
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 30;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  min-height: var(--top-h);
  padding: 0 18px;
  padding-top: env(safe-area-inset-top, 0px);
  background: rgba(244, 242, 238, .92);
  border-bottom: 1px solid rgba(var(--ink), .10);
  transition: transform .32s var(--ease), opacity .32s var(--ease);
}
.reader.is-idle .reader__top {
  transform: translateY(-100%);
  opacity: 0;
}

.reader__top-left {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}
.reader__close {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--navy);
  text-decoration: none;
  font-family: var(--accent-font-family);
  font-size: 13px;
  letter-spacing: .04em;
  border-radius: 8px;
  padding: 6px 8px;
  transition: background .17s var(--ease);
}
.reader__close:hover { background: rgba(var(--ink), .06); }
.reader__close-chevron { transition: transform .18s var(--ease); }
.reader__close:hover .reader__close-chevron { transform: translateX(-2px); }
.reader__close-label { line-height: 1; }

.reader__top-divider {
  width: 1px;
  height: 20px;
  background: rgba(var(--ink), .12);
}
.reader__brand {
  font-family: var(--header-font-family);
  font-size: 13px;
  letter-spacing: .14em;
  color: var(--navy);
}

.reader__top-center {
  text-align: center;
  min-width: 0;
  padding: 0 8px;
}
.reader__title {
  font-family: var(--header-font-family);
  font-size: 15px;
  line-height: 1.25;
  letter-spacing: .02em;
  color: var(--navy);
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.reader__sub {
  font-family: var(--body-font-family);
  font-size: 12px;
  line-height: 1.25;
  letter-spacing: .02em;
  color: var(--reader-muted);
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.reader__top-right {
  display: flex;
  justify-content: flex-end;
}
/* Download-PDF button (replaces the old page-count pill, top-right) */
.reader__top-download {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--navy);
  text-decoration: none;
  font-family: var(--accent-font-family);
  font-size: 13px;
  letter-spacing: .03em;
  padding: 7px 14px;
  border: 1px solid rgba(var(--ink), .18);
  border-radius: 999px;
  background: rgba(var(--ink), .03);
  white-space: nowrap;
  transition: background .17s var(--ease), border-color .17s var(--ease), color .17s var(--ease);
}
.reader__top-download:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.reader__top-download svg { transition: transform .17s var(--ease); }
.reader__top-download:hover svg { transform: translateY(1px); }
.reader__top-download:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ============================================================================
   STAGE + BOOK — object resting on paper. Warm, layered, navy-tinted shadow.
   ========================================================================= */
.reader__stage {
  position: relative;
  z-index: 1;
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(24px, 5vh, 72px) clamp(20px, 6vw, 96px);
  min-height: 0;                 /* allow flex child to shrink */
}

/* Large PORTRAIT screens (e.g. portrait LED kiosks). On a portrait stage sizeBookToStage()
   never satisfies wantSpread (availW < availH*1.42), so it already shows ONE page — but the big
   default padding wastes the tall screen. Trim it so the single page fills the kiosk. */
@media (orientation: portrait) {
  .reader__stage { padding: clamp(12px, 2vh, 32px) clamp(8px, 2vw, 24px); }
}

/*
  WRAPPER carries the shadow (see HTML comment). It sizes to the book via JS.
  Dual-layer realism (grafted from gallery-noir): a broad ambient cast PLUS a
  tight contact shadow — both static box-shadows, cheap, no animated blur.
*/
.flipbook-wrap {
  position: relative;
  flex-shrink: 0;          /* never let flexbox squish the JS-sized book off its aspect ratio */
  border-radius: 3px;
  /* barely-there outer vignette lifting it off the paper backdrop */
  box-shadow:
    0 2px 6px rgba(var(--ink), .10),                /* tight contact */
    0 12px 24px -16px rgba(var(--ink), .14),        /* mid */
    0 30px 60px -24px rgba(var(--ink), .22),        /* broad ambient */
    0 0 120px -40px rgba(var(--ink), .06);          /* soft halo */
}

/* elliptical floor-contact shadow under the book (grafted: brand-immersive) */
.flipbook-wrap::after {
  content: "";
  position: absolute;
  left: 6%;
  right: 6%;
  bottom: -22px;
  height: 26px;
  pointer-events: none;
  background: radial-gradient(60% 100% at 50% 0%,
      rgba(var(--ink), .16) 0%, rgba(var(--ink), 0) 70%);
  filter: blur(2px);
  z-index: -1;
}

.flipbook {
  position: relative;
  width: 100%;
  height: 100%;
  margin: 0 auto;
  /* NEVER put box-shadow/filter here — it fights the StPageFlip canvas. */
}

/* Touch tuning: hand StPageFlip the WHOLE gesture (touch-action: none) so a drag-across
   completes the page-turn instead of the browser claiming it for a vertical pan and snapping
   the fold back. Also suppress the iOS long-press image menu, tap-flash, and drag-selection.
   These are touch-only — no effect on mouse/trackpad. */
.flipbook,
.flipbook .page,
.flipbook canvas {
  touch-action: none;
}
.flipbook {
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
}

/* Each page is paper-white with a hairline border + 2px radius so cropped
   scans never bleed into the backdrop. */
.flipbook .page {
  /* Portrait/single-page mode keeps relative: our .page IS StPageFlip's .stf__item, and
     in portrait the engine sizes the page via the in-flow (relative) item — forcing it
     absolute collapses the page to 0. Spread mode overrides to absolute below. */
  position: relative;
  width: 100%;
  height: 100%;
  background: var(--reader-paper);
  border: 1px solid rgba(var(--ink), .08);
  border-radius: 2px;
  overflow: hidden;
  box-sizing: border-box;
}
.reader.is-spread .flipbook .page {
  position: absolute;
}
/* Portrait fold guard: during a swipe-fold the engine transforms a second page; because
   the base page is relative in portrait, that page can momentarily land in normal flow and
   protrude below the book. Clipping the book area hides that stray sliver without affecting
   the in-bounds fold (the floor-contact shadow lives on .flipbook-wrap, outside this clip). */
.flipbook { overflow: hidden; }

/* faint inner page-curl shading toward the gutter (sells the binding) */
.flipbook .page::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 22px;
  pointer-events: none;
  z-index: 3;
  opacity: 0;
  transition: opacity .2s var(--ease);
}
/* right-hand pages (odd index in spread) get the crease on their LEFT edge */
.flipbook .page[data-side="left"]::before {
  right: 0;
  background: linear-gradient(to left, rgba(0, 0, 0, .05), rgba(0, 0, 0, 0));
}
.flipbook .page[data-side="right"]::before {
  left: 0;
  background: linear-gradient(to right, rgba(0, 0, 0, .05), rgba(0, 0, 0, 0));
}
.reader.is-spread .flipbook .page::before { opacity: 1; }

.flipbook .page__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;       /* never crop the scan */
  object-position: center;
  background: var(--reader-paper);
  opacity: 0;
  transition: opacity .32s var(--ease);  /* cross-fade in over the skeleton */
  z-index: 2;
  /* During a soft page curl the far edge rotates past 90°; without this the page
     content's mirrored backface shows through as a stray "flipping" strip.
     StPageFlip only hides backfaces on hard (cover) pages, so we do it here. */
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}
.flipbook .page__img.is-loaded { opacity: 1; }

/* spine seam in two-page mode — a soft vertical gradient at the gutter */
.reader.is-spread .flipbook::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 2px;
  transform: translateX(-50%);
  pointer-events: none;
  z-index: 50;
  background: linear-gradient(to right,
      rgba(var(--ink), 0), rgba(var(--ink), .10), rgba(var(--ink), 0));
}

/* COVER-ALONE stacked page-edge — visibly conveys the document's depth.
   Three thin offset lines on the right edge of the lone cover. */
.flipbook .page.is-cover {
  box-shadow:
    3px 0 0 -1px rgba(var(--ink), .06),
    6px 0 0 -2px rgba(var(--ink), .05),
    9px 0 0 -3px rgba(var(--ink), .045);
}

/* ---- Per-page skeleton: paper shimmer + page-number watermark ------------ */
.page__skeleton {
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: 2px;
  display: grid;
  place-items: center;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  background: linear-gradient(110deg,
      var(--reader-bg) 8%, var(--reader-shimmer) 18%, var(--reader-bg) 33%);
  background-size: 200% 100%;
  animation: shimmer 1.6s var(--ease) infinite;
  transition: opacity .32s var(--ease);
}
.page__skeleton.is-hidden { opacity: 0; }
.page__watermark {
  font-family: var(--accent-font-family);
  font-size: 13px;
  letter-spacing: .04em;
  color: rgba(var(--ink), .12);
}
@keyframes shimmer { to { background-position: -200% 0; } }

/* graceful failure — "page unavailable" glyph instead of a broken image */
.page.is-failed .page__skeleton { animation: none; background: var(--reader-skeleton); }
.page.is-failed .page__watermark::after {
  content: " · unavailable";
  color: rgba(var(--ink), .22);
}

/* ============================================================================
   BOTTOM CONTROL CAPSULE — floating frosted glass, auto-hides
   ========================================================================= */
.reader__bottom {
  /* Floats over the book (absolute). Was `position: relative`, which kept it in the flex
     flow and reserved ~78px at the very bottom even when auto-hidden — that was the dead
     space below the page on mobile. Centered via auto margins (NOT transform) so the
     reduced-motion `transform: none` rule can't knock it off-center, and the idle
     translateY slide still works unchanged. bottom clears the iOS home-indicator inset. */
  position: absolute;
  left: 0;
  right: 0;
  bottom: max(clamp(16px, 3vh, 28px), env(safe-area-inset-bottom, 0px));
  margin: 0 auto;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  max-width: min(680px, calc(100vw - 48px));
  width: max-content;
  background: rgba(255, 255, 255, .72);
  backdrop-filter: blur(18px) saturate(1.1);
  -webkit-backdrop-filter: blur(18px) saturate(1.1);
  border: 1px solid rgba(var(--ink), .10);
  border-radius: 16px;
  box-shadow: 0 8px 28px -10px rgba(var(--ink), .22);
  transition: transform .32s var(--ease), opacity .32s var(--ease);
}
.reader.is-idle .reader__bottom {
  transform: translateY(120%);
  opacity: 0;
}
/* PERF guard: drop the blur while a flip is animating (changeState=flipping) */
.reader.is-flipping .reader__bottom {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

.reader__btn {
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 10px;
  color: var(--navy);
  background: transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background .17s var(--ease), opacity .17s var(--ease);
}
.reader__btn svg { transition: transform .17s var(--ease); }
.reader__btn:hover { background: rgba(var(--ink), .06); }
.reader__btn:hover svg { transform: translateY(-1px); }
/* active / live state — the ONLY place orange appears in the chrome */
.reader__btn.is-active,
.reader__btn[aria-pressed="true"] {
  background: rgba(var(--ink), .05);
  color: var(--accent);
}
/* explicit disabled edge states (grafted: brand-immersive) */
.reader__btn:disabled,
.reader__btn[aria-disabled="true"] {
  /* muted navy (not opacity:.35) so the edge arrow stays clearly visible */
  color: rgba(var(--ink), .5);
  cursor: default;
  pointer-events: none;
}
/* orange focus ring, rendered INSTANTLY (no transition) for accessibility */
.reader__btn:focus-visible,
.reader__close:focus-visible,
.reader__range:focus-visible,
.reader__thumb:focus-visible,
.reader__chapter:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.reader__bar-divider {
  flex: 0 0 auto;
  width: 1px;
  height: 24px;
  margin: 0 2px;
  background: rgba(var(--ink), .12);
}
.reader__cluster { display: flex; align-items: center; gap: 6px; }

/* download tooltip */
.reader__download { position: relative; }
.reader__download::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 10px);
  right: 0;
  white-space: nowrap;
  font-family: var(--body-font-family);
  font-size: 12px;
  color: var(--reader-muted);
  background: rgba(255, 255, 255, .96);
  border: 1px solid rgba(var(--ink), .10);
  border-radius: 8px;
  padding: 5px 9px;
  box-shadow: 0 8px 20px -8px rgba(var(--ink), .22);
  opacity: 0;
  transform: translateY(4px);
  pointer-events: none;
  transition: opacity .16s var(--ease), transform .16s var(--ease);
}
.reader__download:hover::after,
.reader__download:focus-visible::after { opacity: 1; transform: translateY(0); }

/* ---- SLIDER (the centerpiece) -------------------------------------------- */
.reader__slider {
  position: relative;
  flex: 1 1 auto;
  min-width: 120px;
  display: flex;
  align-items: center;
  padding: 0 8px;
}
.reader__range {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 16px;
  background: transparent;
  cursor: pointer;
  margin: 0;
}
/* track */
.reader__range::-webkit-slider-runnable-track {
  height: 3px;
  border-radius: 999px;
  /* JS sets --pct; filled portion navy, rest navy-16% */
  background: linear-gradient(to right,
      var(--navy) 0 var(--pct, 0%), rgba(var(--ink), .16) var(--pct, 0%) 100%);
}
.reader__range::-moz-range-track {
  height: 3px;
  border-radius: 999px;
  background: rgba(var(--ink), .16);
}
.reader__range::-moz-range-progress {
  height: 3px;
  border-radius: 999px;
  background: var(--navy);
}
/* thumb */
.reader__range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  margin-top: -6.5px;
  border-radius: 50%;
  background: var(--navy);
  border: 3px solid #fff;
  box-shadow: 0 1px 4px rgba(var(--ink), .35);
  transition: transform .14s var(--ease);
}
.reader__range::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--navy);
  border: 3px solid #fff;
  box-shadow: 0 1px 4px rgba(var(--ink), .35);
}
.reader__slider.is-grabbing .reader__range::-webkit-slider-thumb { transform: scale(1.15); }
/* orange thumb when the slider rests on the live page (grafted: brand-immersive) */
.reader__slider.is-live .reader__range::-webkit-slider-thumb { background: var(--accent); }
.reader__slider.is-live .reader__range::-moz-range-thumb { background: var(--accent); }

/* live destination bubble (number + tiny thumbnail preview) */
.reader__bubble {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 0;
  transform: translate(-50%, 6px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 6px;
  background: var(--navy);
  border-radius: 8px;
  box-shadow: 0 8px 20px -8px rgba(var(--ink), .4);
  opacity: 0;
  pointer-events: none;
  transition: opacity .14s var(--ease), transform .14s var(--ease);
}
.reader__slider.is-grabbing .reader__bubble { opacity: 1; transform: translate(-50%, 0); }
.reader__bubble::after {                       /* caret */
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-top-color: var(--navy);
}
.reader__bubble-thumb {
  width: 46px;
  height: auto;
  aspect-ratio: 0.7727;
  object-fit: cover;
  background: var(--reader-skeleton);
  border-radius: 3px;
  display: block;
}
.reader__bubble-thumb:not([src]) { display: none; }
.reader__bubble-num {
  font-family: var(--accent-font-family);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: #fff;
  line-height: 1;
}

.reader__more { display: none; }   /* phone-only */

/* ============================================================================
   THUMBNAILS DRAWER (right) + scrim
   ========================================================================= */
.reader__scrim {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(var(--ink), .18);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  opacity: 0;
  transition: opacity .36s var(--ease);
}
.reader__scrim.is-open { opacity: 1; }
.reader__scrim[hidden] { display: none; }

.reader__drawer {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 50;
  height: 100%;
  width: clamp(280px, 30vw, 380px);
  display: flex;
  flex-direction: column;
  background: #FBFAF7;
  border-left: 1px solid rgba(var(--ink), .10);
  box-shadow: -18px 0 40px -24px rgba(var(--ink), .4);
  transform: translateX(100%);
  transition: transform .36s var(--ease);
}
.reader__drawer.is-open { transform: translateX(0); }

.reader__drawer-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 16px 14px;
  border-bottom: 1px solid rgba(var(--ink), .10);
}
.reader__drawer-title {
  font-family: var(--header-font-family);
  font-size: 14px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--navy);
  margin: 0;
}
.reader__drawer-count {
  font-family: var(--body-font-family);
  font-size: 12px;
  color: var(--reader-muted);
}
.reader__drawer-close { margin-left: auto; width: 34px; height: 34px; }

.reader__thumbs {
  flex: 1 1 auto;
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  padding: 14px;
  -webkit-overflow-scrolling: touch;
}
@media (min-width: 1100px) {
  .reader__thumbs { grid-template-columns: repeat(3, 1fr); }
}

.reader__thumb {
  display: block;
  border: 0;
  background: transparent;
  padding: 0;
  cursor: pointer;
  text-align: center;
}
.reader__thumb-card {
  display: block;            /* span is inline by default → width/aspect-ratio ignored */
  position: relative;
  width: 100%;
  aspect-ratio: 0.7727;
  background: #fff;
  border: 1px solid rgba(var(--ink), .10);
  border-radius: 3px;
  overflow: hidden;
  box-shadow: 0 2px 6px rgba(var(--ink), .10);
  transition: box-shadow .17s var(--ease);
}
/* shimmer placeholder behind each thumb until its WebP decodes.
   Animation runs ONLY while .is-pending (set by the IntersectionObserver as a card
   nears the viewport) so off-screen cards don't run ~294 animations at once. */
.reader__thumb-card::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(110deg,
      var(--reader-bg) 8%, var(--reader-shimmer) 18%, var(--reader-bg) 33%);
  background-size: 200% 100%;
}
.reader__thumb-card.is-pending::before {
  animation: shimmer 1.6s var(--ease) infinite;
}
.reader__thumb-card.is-loaded::before { display: none; }
.reader__thumb-card canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity .32s var(--ease);
}
.reader__thumb-card.is-loaded canvas { opacity: 1; }
.reader__thumb-cap {
  display: block;
  margin-top: 5px;
  font-family: var(--accent-font-family);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--reader-muted);
}
/* current page / spread — orange ring + navy-bold caption */
.reader__thumb.is-current .reader__thumb-card { box-shadow: 0 0 0 2px var(--accent); }
.reader__thumb.is-current .reader__thumb-cap { color: var(--navy); }

/* ============================================================================
   CHAPTERS POPOVER — printed table-of-contents feel, dotted leaders
   ========================================================================= */
.reader__chapters {
  position: fixed;
  z-index: 50;
  width: 300px;
  max-height: 60vh;
  display: flex;
  flex-direction: column;
  background: #FBFAF7;
  border: 1px solid rgba(var(--ink), .10);
  border-radius: 14px;
  box-shadow: 0 16px 40px -12px rgba(var(--ink), .24);
  transform-origin: bottom center;
  transform: translateY(6px) scale(.96);
  opacity: 0;
  transition: transform .24s var(--ease), opacity .24s var(--ease);
}
.reader__chapters[hidden] { display: none; }
.reader__chapters.is-open { transform: translateY(0) scale(1); opacity: 1; }

.reader__chapters-head {
  flex: 0 0 auto;
  font-family: var(--header-font-family);
  font-size: 13px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--navy);
  margin: 0;
  padding: 14px 16px 10px;
  border-bottom: 1px solid rgba(var(--ink), .10);
}
.reader__chapters-list {
  list-style: none;
  margin: 0;
  padding: 6px 0;
  overflow-y: auto;
}
.reader__chapter {
  display: flex;
  align-items: baseline;
  width: 100%;
  border: 0;
  background: transparent;
  cursor: pointer;
  padding: 12px 16px;
  text-align: left;
  border-left: 3px solid transparent;
  transition: background .17s var(--ease);
}
.reader__chapter:hover { background: rgba(var(--ink), .05); }
.reader__chapter-title {
  font-family: var(--accent-font-family);
  font-size: 14px;
  color: var(--navy);
  white-space: nowrap;
  transition: transform .17s var(--ease);
}
.reader__chapter:hover .reader__chapter-title { transform: translateX(3px); }
/* dotted leader between title and page number */
.reader__chapter-leader {
  flex: 1 1 auto;
  margin: 0 6px;
  border-bottom: 1px dotted rgba(var(--ink), .28);
  transform: translateY(-3px);
}
.reader__chapter-page {
  flex: 0 0 auto;
  font-family: var(--body-font-family);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--reader-muted);
}
/* the chapter containing the current page — orange left accent + navy-bold # */
.reader__chapter.is-current { border-left-color: var(--accent); }
.reader__chapter.is-current .reader__chapter-page {
  font-family: var(--accent-font-family);
  color: var(--navy);
}

/* ============================================================================
   ZOOM STAGE — "lean in to read the fine print"
   ========================================================================= */
.reader__zoom {
  position: fixed;
  inset: var(--top-h) 0 0 0;
  z-index: 35;
  background: rgba(var(--ink), .06);   /* chrome dims slightly to focus */
  overflow: hidden;
}
.reader__zoom[hidden] { display: none; }
.reader__zoom-viewport {
  width: 100%;
  height: 100%;
  overflow: auto;                       /* NATIVE pan: the browser scrolls the spread */
  -webkit-overflow-scrolling: touch;
  touch-action: pan-x pan-y pinch-zoom; /* one-finger pan + native pinch on touch */
  overscroll-behavior: contain;
  display: flex;
  align-items: safe center;             /* centre when it fits; when zoomed-in, scroll to all of it */
  justify-content: safe center;
  cursor: grab;
}
.reader__zoom-viewport.is-panning { cursor: grabbing; }
.reader__zoom-img {
  display: block;
  flex: 0 0 auto;                       /* keep the JS-set size so it overflows -> scrolls */
  background: var(--reader-paper);
  border: 1px solid rgba(var(--ink), .08);
  box-shadow: 0 20px 50px -20px rgba(var(--ink), .35);
  user-select: none;
  -webkit-user-drag: none;
}
.reader__zoom-hud {
  position: absolute;
  bottom: 96px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 8px 6px 14px;
  background: rgba(255, 255, 255, .82);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid rgba(var(--ink), .10);
  border-radius: 999px;
  box-shadow: 0 8px 24px -10px rgba(var(--ink), .3);
}
.reader__zoom-level {
  font-family: var(--accent-font-family);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--navy);
}
.reader__zoom-reset {
  border: 0;
  background: rgba(var(--ink), .06);
  color: var(--navy);
  font-family: var(--accent-font-family);
  font-size: 13px;
  letter-spacing: .04em;
  padding: 6px 12px;
  border-radius: 999px;
  cursor: pointer;
  transition: background .17s var(--ease);
}
.reader__zoom-reset:hover { background: rgba(var(--ink), .12); }
.reader__zoom-reset:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ============================================================================
   GLOBAL LOADING — calm title-page state with a determinate hairline
   ========================================================================= */
.reader__loading {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  background: radial-gradient(120% 90% at 50% 38%,
      var(--reader-bg-center) 0%, var(--reader-bg) 55%, var(--reader-bg-edge) 100%);
  transition: opacity .3s var(--ease);
}
.reader__loading.is-done { opacity: 0; pointer-events: none; }
.reader__loading[hidden] { display: none; }
.reader__loading-inner { text-align: center; max-width: 80vw; }
.reader__loading-title {
  font-family: var(--header-font-family);
  font-size: 22px;
  letter-spacing: .02em;
  color: var(--navy);
  margin: 0 0 4px;
}
.reader__loading-sub {
  font-family: var(--body-font-family);
  font-size: 14px;
  letter-spacing: .02em;
  color: var(--reader-muted);
  margin: 0 0 22px;
}
.reader__loading-track {
  width: min(280px, 60vw);
  height: 2px;
  margin: 0 auto 16px;
  background: rgba(var(--ink), .12);
  border-radius: 999px;
  overflow: hidden;
}
.reader__loading-bar {
  display: block;
  height: 100%;
  width: 0%;
  background: var(--navy);
  border-radius: 999px;
  transition: width .3s var(--ease);
}
.reader__loading-hint {
  font-family: var(--body-font-family);
  font-size: 12px;
  color: var(--reader-muted);
  margin: 0;
  font-variant-numeric: tabular-nums;
}
.reader__loading-retry {
  margin-top: 18px;
  font-family: var(--accent-font-family);
  font-size: 13px;
  letter-spacing: .03em;
  color: #fff;
  background: var(--navy);
  border: 0;
  border-radius: 999px;
  padding: 10px 22px;
  cursor: pointer;
  transition: background .17s var(--ease);
}
.reader__loading-retry:hover { background: var(--accent); }
.reader__loading-retry:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.reader__loading-retry[hidden] { display: none; }

/* ============================================================================
   FALLBACK — the browser's native PDF viewer, full-bleed in the stage
   (used on tiny screens or if PDF.js / StPageFlip are unavailable)
   ========================================================================= */
.reader__fallback {
  width: 100%;
  height: 100%;
  display: block;
}
.reader__fallback[hidden] { display: none; }
.reader__pdf-frame {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  background: var(--reader-paper);
}

/* ============================================================================
   RESPONSIVE — phones / portrait
   ========================================================================= */
@media (max-width: 700px) {
  :root { --top-h: 52px; }

  /* Tighter stage padding on phones → the page is as large as the screen width allows
     (the floating masthead/capsule sit in the top/bottom margins, so they don't need
     reserved padding here). */
  .reader__stage { padding: 10px 10px; }

  .reader__brand,
  .reader__top-divider { display: none; }

  .reader__title { font-size: 14px; }
  .reader__sub { font-size: 11px; }

  /* icon-only download to save masthead width on phones */
  .reader__top-download-label { display: none; }
  .reader__top-download { padding: 7px 9px; gap: 0; }

  /* collapse secondary cluster into a sheet behind the "More" button */
  .reader__cluster {
    position: absolute;
    bottom: calc(100% + 10px);
    right: 0;
    flex-direction: column;
    gap: 4px;
    padding: 8px;
    background: rgba(255, 255, 255, .92);
    backdrop-filter: blur(18px) saturate(1.1);
    -webkit-backdrop-filter: blur(18px) saturate(1.1);
    border: 1px solid rgba(var(--ink), .10);
    border-radius: 14px;
    box-shadow: 0 12px 32px -12px rgba(var(--ink), .3);
    transform-origin: bottom right;
    transform: translateY(6px) scale(.96);
    opacity: 0;
    pointer-events: none;
    transition: transform .24s var(--ease), opacity .24s var(--ease);
  }
  .reader.is-sheet-open .reader__cluster {
    transform: translateY(0) scale(1);
    opacity: 1;
    pointer-events: auto;
  }
  .reader__bar-divider { display: none; }
  .reader__more { display: grid; }

  .reader__bottom { gap: 4px; padding: 6px 10px; }
  .reader__drawer { width: min(86vw, 360px); }
  .reader__chapters { width: min(86vw, 320px); }
}

/* ============================================================================
   REDUCED MOTION — buttery becomes instant
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  .reader__top,
  .reader__bottom,
  .reader__drawer,
  .reader__chapters,
  .reader__zoom-img,
  .reader__cluster {
    transition: opacity .12s linear !important;
    transform: none !important;
  }
  .reader.is-idle .reader__top,
  .reader.is-idle .reader__bottom { transform: none !important; }
  .page__skeleton,
  .reader__thumb-card::before {
    animation: none !important;
    background: var(--reader-skeleton) !important;
  }
  .reader__count.is-rolling { animation: none !important; }
  .page__img,
  .reader__thumb-card canvas { transition: opacity .12s linear !important; }
}
