/**
 * Shared page-turning book reader chrome for 27 Pictures toons (Erin, Jax, …).
 * Pairs with the Vue FlipFrame reader (src/toons/shared/book-reader.ts). Each toon's own <style> block keeps only its
 * book-specific tokens (--book-width/--book-height aspect math, --page-bg,
 * --spine, --cover) and any page-specific extras (e.g. Jax music button).
 * Language switcher chrome is shared here (.toon-lang-*).
 */

/* Prevent side “black band” resize: nav buttons / chrome must not expand
   document scroll width and change 100vw-based book sizing. */
html:has(body.toons-reader) {
  overflow: hidden;
  height: 100%;
  max-width: 100%;
}

body.toons-reader {
  min-height: 100dvh;
  height: 100dvh;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  color: var(--text);
  /* No document scrollbars — nav chrome sits outside the book box */
  overflow: hidden;
  user-select: none;
}

.reader {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  /* Side padding >= the page-arrow radius (22px): .reader shrinks to the book
     and clips at its padding box, so a narrower gutter slices the outer half
     of each disc off. */
  padding: 2.75rem 1.5rem 0.75rem;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  position: relative;
  z-index: 1;
  overflow: hidden;
}

/* Site logo — same mark as main nav (styles.css .nav-logo-img), fixed top-left */
.toons-back {
  position: fixed;
  top: 1.25rem;
  left: 1.25rem;
  z-index: 50;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  line-height: 0;
  /* Reader defines its own logo height so it works even if nav tokens differ */
  --nav-logo-h: clamp(2rem, 1.75rem + 0.6vw, 2.5rem);
  transition:
    opacity 0.2s var(--transition),
    filter 0.2s var(--transition);
}

.toons-back:hover {
  opacity: 0.92;
  filter: brightness(1.08);
}

.toons-back:focus-visible {
  outline: 2px solid var(--red-smile);
  outline-offset: 3px;
}

.toons-back-logo,
.toons-back .nav-logo-img {
  display: block;
  height: var(--nav-logo-h, 40px);
  width: var(--nav-logo-h, 40px);
  object-fit: contain;
  border: 1px solid var(--red-smile);
  padding: 4px;
  box-sizing: border-box;
  background: var(--bg-dark);
}

.title-bar {
  text-align: center;
}

.title-bar .section-tag {
  margin-bottom: 6px;
}

.title-bar h1 {
  font-family: "Playfair Display", serif;
  font-size: clamp(1.35rem, 4.5vw, 2rem);
  font-weight: 900;
  line-height: 0.95;
  letter-spacing: 0;
  color: var(--text);
}

/* ── Reading progress ──
   Slim bar replacing the numeric page indicator. Above the top-right
   controls' stacking context so it survives fullscreen, where the rest of
   the chrome hides. Desktop pins it to the top; mobile moves it to the very
   bottom, clear of the notch and out of thumb range. */
.toon-progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  z-index: 60;
  background: color-mix(in srgb, var(--text) 8%, transparent);
  pointer-events: none;
}

.toon-progress-fill {
  height: 100%;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left center;
  background: linear-gradient(90deg, color-mix(in srgb, var(--red-smile) 55%, transparent), var(--red-smile));
  box-shadow: 0 0 8px color-mix(in srgb, var(--red-smile) 55%, transparent);
  transition: transform 0.45s var(--transition);
  will-change: transform;
}

@media (prefers-reduced-motion: reduce) {
  .toon-progress-fill {
    transition: none;
  }
}

/* Top-right controls (fullscreen always; language/sound/music are additive
   per-page — see each toon's own <style> block) */
.toon-top-controls {
  position: fixed;
  top: 1.5rem;
  right: 1.5rem;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.25rem;
  border-radius: 6px;
  /* Contain highlight paint; never let the intro flash touch page layout */
  isolation: isolate;
}

/* One-shot intro: flash the whole menu group 3×.
   Animate only opacity / color (no box-shadow growth, no springy
   --transition easing) so the page doesn’t look like it wobbles. */
@keyframes toon-menu-ring-flash {
  0%,
  100% {
    opacity: 0;
  }
  50% {
    opacity: 1;
  }
}

@keyframes toon-menu-btn-flash {
  0%,
  100% {
    border-color: var(--border);
    color: var(--silver);
  }
  50% {
    border-color: var(--red-smile);
    color: var(--red-smile);
  }
}

.toon-top-controls.is-highlight-pulse {
  position: fixed; /* keep stacking context for ::before */
}

.toon-top-controls.is-highlight-pulse::before {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 8px;
  border: 2px solid var(--red-smile);
  background: color-mix(in srgb, var(--red-smile) 20%, transparent);
  pointer-events: none;
  z-index: -1;
  animation: toon-menu-ring-flash 0.48s ease-in-out 3;
}

.toon-top-controls.is-highlight-pulse .toon-fs-btn {
  /* Color-only pulse on every control in the group */
  animation: toon-menu-btn-flash 0.48s ease-in-out 3;
  /* Kill the normal 0.2s border transition so the flash is crisp */
  transition: none;
}

@media (prefers-reduced-motion: reduce) {
  .toon-top-controls.is-highlight-pulse::before {
    animation: none;
    opacity: 1;
  }

  .toon-top-controls.is-highlight-pulse .toon-fs-btn {
    animation: none;
    border-color: var(--red-smile);
    color: var(--red-smile);
  }
}

.toon-fs-btn {
  font-family: "Inter", sans-serif;
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--silver);
  background: var(--bg-card);
  border: 1px solid var(--border);
  /* Icon-only chrome — labels stay in DOM for a11y/JS but are not shown */
  padding: 0.45rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0;
  min-width: 1.9rem;
  min-height: 1.9rem;
  transition:
    color 0.2s var(--transition),
    border-color 0.2s var(--transition),
    background 0.2s var(--transition);
}

.toon-fs-btn:hover {
  color: var(--text);
  border-color: var(--border-light);
}

.toon-fs-btn.is-active {
  border-color: var(--red-smile);
  color: var(--red-smile);
}

/* Sound icon: hide wave arcs until enabled (matches front-cover control). */
.toon-fs-btn .toon-fs-sound-waves {
  display: none;
}

.toon-fs-btn.is-active .toon-fs-sound-waves {
  display: inline;
}

.toon-fs-btn:focus-visible {
  outline: 2px solid var(--red-smile);
  outline-offset: 2px;
}

.toon-fs-btn svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

.toon-fs-btn .toon-fs-label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

/* Fullscreen chrome: hide nav; shrink title; keep top-right controls */
body.is-fullscreen .toons-back,
body.is-fullscreen .controls,
body.is-fullscreen .page-nav-btn,
body.is-fullscreen .hint {
  display: none !important;
}

body.is-fullscreen .title-bar {
  margin: 0;
}

body.is-fullscreen .title-bar .section-tag {
  font-size: 8px;
  letter-spacing: 3px;
  margin-bottom: 4px;
}

body.is-fullscreen .title-bar h1 {
  font-size: clamp(1.1rem, 2.8vw, 1.65rem);
}

body.is-fullscreen .reader {
  min-height: 100dvh;
  padding: 0.5rem 0.5rem 0.5rem;
  justify-content: center;
  gap: 0.5rem;
}

/* ── Book container ──
   Sizes off --book-width/--book-height, which each toon defines locally
   (different page aspect ratios), including the body.is-fullscreen and
   body.single-page overrides of those same custom properties. */
.book-scene {
  perspective: 2200px;
  width: var(--book-width);
  height: var(--book-height);
  max-width: 100%;
  position: relative;
  /* Nav buttons sit slightly outside the box; keep them from growing the page */
  flex-shrink: 0;
}

.book {
  width: 100%;
  height: 100%;
  position: relative;
  transform-style: preserve-3d;
}

.book-shadow {
  position: absolute;
  bottom: -18px;
  left: 5%;
  width: 90%;
  height: 30px;
  background: radial-gradient(ellipse, rgba(0, 0, 0, 0.55) 0%, transparent 70%);
  filter: blur(8px);
  pointer-events: none;
}

.spread {
  width: 100%;
  height: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr;
  position: relative;
  border-radius: 2px 6px 6px 2px;
  border: 1px solid var(--border);
  box-shadow:
    0 2px 4px rgba(0, 0, 0, 0.3),
    0 12px 40px rgba(0, 0, 0, 0.55);
}

.page-slot {
  position: relative;
  overflow: hidden;
  background: var(--page-bg);
}

/* Folio: small page number, bottom-left of every content page.
   Pure CSS off the `data-page-num` attribute BookSlot / FlipLeaf / VerticalStrip
   already set, so covers (which carry no attribute) stay unnumbered and no
   plate on the CDN is touched. Sits above .nav-zone (30) but below the word
   overlay layer (35) so captions always win a click. */
.page-slot[data-page-num]::after {
  content: attr(data-page-num);
  position: absolute;
  left: 0.55rem;
  bottom: 0.4rem;
  z-index: 33;
  font-family: "VT323", monospace;
  font-size: clamp(11px, 1.5vh, 16px);
  line-height: 1;
  letter-spacing: 0.08em;
  color: color-mix(in srgb, var(--text) 52%, transparent);
  text-shadow:
    0 1px 2px color-mix(in srgb, var(--bg-dark) 85%, transparent),
    0 0 6px color-mix(in srgb, var(--bg-dark) 60%, transparent);
  pointer-events: none;
  user-select: none;
}

.page-slot.right {
  border-radius: 0 4px 4px 0;
  box-shadow: inset -8px 0 16px rgba(0, 0, 0, 0.06);
}

.page-slot.left {
  border-radius: 4px 0 0 4px;
  box-shadow: inset 8px 0 16px rgba(0, 0, 0, 0.06);
}

.page-slot img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
  /* Matches .page-slot's own background so any sub-pixel letterbox
     gap from object-fit:contain blends in instead of showing white. */
  background: var(--page-bg);
  -webkit-user-drag: none;
}

.page-slot.blank {
  background: linear-gradient(135deg, #f0ebe3 0%, #e8e2d8 100%);
}

.page-slot.blank::after {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    0deg,
    transparent,
    transparent 28px,
    rgba(0, 0, 0, 0.015) 28px,
    rgba(0, 0, 0, 0.015) 29px
  );
}

.spine {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 14px;
  height: 100%;
  background: linear-gradient(
    90deg,
    var(--bg-dark) 0%,
    var(--spine) 30%,
    #4a3f32 50%,
    var(--spine) 70%,
    var(--bg-dark) 100%
  );
  z-index: 10;
  box-shadow:
    -2px 0 6px rgba(0, 0, 0, 0.4),
    2px 0 6px rgba(0, 0, 0, 0.4);
  pointer-events: none;
}

.spine-glow {
  position: absolute;
  top: 0;
  left: calc(50% - 20px);
  width: 40px;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.12) 50%, transparent);
  z-index: 9;
  pointer-events: none;
}

/* Hold page art until caption paint finishes (avoids bare-page flash after flips). */
.page-slot.is-captions-pending > img:not(.cover-texture-img),
.flip-face.is-captions-pending > img:not(.cover-texture-img) {
  opacity: 0;
}

/* ── Flip overlay ── */
.flip-page {
  position: absolute;
  top: 0;
  width: 50%;
  height: 100%;
  transform-style: preserve-3d;
  transform-origin: left center;
  /* Above .nav-zone (30) and any word-caption overlay a page might paint
     (e.g. Jax's .jax-word-layer at 35) so the incoming page's content stays
     covered until the flip animation finishes instead of flashing through. */
  z-index: 40;
  pointer-events: none;
}

.flip-page.from-right {
  right: 0;
  transform-origin: left center;
}

.flip-page.from-left {
  left: 0;
  transform-origin: right center;
}

.flip-face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  overflow: hidden;
  background: var(--page-bg);
  /* Caption layer is position:absolute relative to this face */
  isolation: isolate;
}

.flip-face img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: var(--page-bg);
}

.flip-face.back {
  transform: rotateY(180deg);
}

.flip-face.inside-cover {
  background: linear-gradient(135deg, var(--cover) 0%, var(--bg-dark) 100%);
}

/* has-cover-texture background rules live with .page-slot.inside-cover above */

.flip-page.from-right .flip-face.front {
  border-radius: 0 4px 4px 0;
  box-shadow: -4px 0 12px rgba(0, 0, 0, 0.15);
}

.flip-page.from-left .flip-face.front {
  border-radius: 4px 0 0 4px;
  box-shadow: 4px 0 12px rgba(0, 0, 0, 0.15);
}

.flip-page.flipping.from-right {
  animation: flip-right 0.7s var(--transition) forwards;
}

.flip-page.flipping.from-left {
  animation: flip-left 0.7s var(--transition) forwards;
}

@keyframes flip-right {
  0% {
    transform: rotateY(0deg);
  }
  100% {
    transform: rotateY(-180deg);
  }
}

@keyframes flip-left {
  0% {
    transform: rotateY(0deg);
  }
  100% {
    transform: rotateY(180deg);
  }
}

/* LTR book: left = prev, right = next */
.nav-zone {
  position: absolute;
  top: 0;
  width: 50%;
  height: 100%;
  z-index: 30;
  cursor: pointer;
}

.nav-zone.prev {
  left: 0;
}

.nav-zone.next {
  right: 0;
}

.nav-zone:hover::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(255, 255, 255, 0.03);
  transition: background 0.2s var(--transition);
}

@media (prefers-reduced-motion: reduce) {
  .flip-page.flipping.from-right,
  .flip-page.flipping.from-left {
    animation-duration: 0.01ms;
  }
}

/* ── Controls ── */
.controls {
  display: flex;
  align-items: center;
  gap: 1.5rem;
}

.reader-btn {
  background: var(--bg-card);
  border: 1px solid var(--border);
  color: var(--text);
  width: 44px;
  height: 44px;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  font-family: "Inter", sans-serif;
  transition:
    background 0.2s var(--transition),
    border-color 0.2s var(--transition),
    color 0.2s var(--transition);
}

.reader-btn:hover:not(:disabled) {
  border-color: var(--red-smile);
  color: var(--red-smile);
}

.reader-btn:focus-visible {
  outline: 2px solid var(--red-smile);
  outline-offset: 2px;
}

.reader-btn:disabled {
  opacity: 0.25;
  cursor: default;
}

/* Prev/next arrows sit centred on the page edges, above the full-page
   .nav-zone click areas (z-index 30), instead of in a row below the book.
   Each disc straddles the page edge — centred on it, half over the plate and
   half over the margin. That costs a gutter: .reader clips at its padding box,
   so --book-width must leave at least the disc's radius on each side (see the
   100vw - 64px term in every toon's <style>), or the outer half gets sliced. */
.page-nav-btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 32;
  opacity: 0.9;
  /* Red outline + red glyph on a dark disc; inverts on hover/press. */
  background: color-mix(in srgb, var(--bg-dark) 72%, transparent);
  border-color: var(--red-smile);
  color: var(--red-smile);
  transition:
    background 0.18s var(--transition),
    border-color 0.18s var(--transition),
    color 0.18s var(--transition),
    opacity 0.18s var(--transition);
}

/* Beat .reader-btn:hover, which only recolours the border and glyph. */
.page-nav-btn:hover:not(:disabled),
.page-nav-btn:focus-visible:not(:disabled),
.page-nav-btn:active:not(:disabled) {
  opacity: 1;
  background: var(--red-smile);
  border-color: var(--text);
  color: var(--text);
}

.page-nav-btn.prev {
  /* Half the 44px disc — centres it on the page edge. */
  left: -22px;
}

.page-nav-btn.next {
  right: -22px;
}

.page-indicator {
  font-family: "Inter", sans-serif;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.15em;
  min-width: 6.5rem;
  text-align: center;
  color: var(--silver);
}

.hint {
  font-family: "Inter", sans-serif;
  font-size: 0.65rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-align: center;
  color: var(--silver);
  opacity: 0.7;
}

.page-slot.inside-cover {
  background: linear-gradient(135deg, var(--cover) 0%, var(--bg-dark) 100%);
}

/* Optional hardcover board texture — <img.cover-texture-img> injected by
   the book engine under the instructions / back-cover link. */
.page-slot.inside-cover.has-cover-texture,
.flip-face.inside-cover.has-cover-texture {
  background: var(--cover, var(--bg-dark));
}

img.cover-texture-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  z-index: 0;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
  /* Mesh is very dark — lift it slightly so it reads on the cover */
  filter: brightness(1.35) contrast(1.08);
}

/* Light scrim only where type sits — keep mesh visible around it */
.page-slot.inside-cover.has-cover-texture .front-cover-instructions,
.flip-face.inside-cover.has-cover-texture .front-cover-instructions {
  background: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--bg-dark) 35%, transparent) 0%,
    transparent 38%,
    color-mix(in srgb, var(--bg-dark) 40%, transparent) 100%
  );
}

.page-slot.inside-cover.has-cover-texture .back-cover-link,
.flip-face.inside-cover.has-cover-texture .back-cover-link {
  z-index: 32;
}

.front-cover-instructions {
  /* Shared content column — story, separator, FlipFrame all share this width */
  --front-cover-col: min(22rem, 88%);
  position: absolute;
  inset: 0;
  /* Above .nav-zone (30) — otherwise nav-zone silently swallows real
     clicks meant for any interactive control inside this panel
     (e.g. .front-cover-sound-btn). */
  z-index: 32;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Title → scrollable story → separator → FlipFrame / how-to */
  justify-content: flex-start;
  gap: 0.4rem;
  padding: 1.05rem 1rem 1.1rem;
  text-align: center;
  color: var(--silver);
  font-family: "Inter", sans-serif;
  /* Plate itself does not scroll — story body does */
  overflow: hidden;
  box-sizing: border-box;
  max-width: 100%;
}

/* Toon series title at the top of the front-cover manual (Jax / Erin). */
.front-cover-title {
  font-family: "Playfair Display", serif;
  font-size: clamp(1.45rem, 4vw, 1.95rem);
  font-weight: 900;
  line-height: 0.95;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text);
  margin: 0;
  flex-shrink: 0;
  width: 100%;
  max-width: var(--front-cover-col);
}

/* Small label under the title (e.g. "Experiment") — stays at the top. */
.front-cover-subtitle {
  font-family: "Inter", sans-serif;
  font-size: clamp(0.7rem, 0.64rem + 0.2vw, 0.82rem);
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--red-smile);
  margin: 0.05rem 0 0;
  flex-shrink: 0;
  width: 100%;
  max-width: var(--front-cover-col);
}

/* Higher specificity than .page-slot img (width/height/object-fit
   100%/contain) — the logo lives inside a .page-slot and would otherwise
   silently inherit page-image sizing instead of its own. */
.front-cover-instructions img.front-cover-logo {
  width: 44px;
  height: auto;
  object-fit: initial;
  opacity: 0.92;
  margin: 0.1rem 0 0;
  flex-shrink: 0;
}

/* Story block: fills space from title down to the separator before FlipFrame */
.front-cover-story {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  max-width: var(--front-cover-col);
  text-align: left;
  align-self: center;
  padding-top: 0.45rem;
  box-sizing: border-box;
}

.front-cover-separator {
  flex-shrink: 0;
  width: 100%;
  max-width: var(--front-cover-col);
  height: 0;
  margin: 0.75rem 0;
  border: none;
  border-top: 1px solid var(--border-light);
  opacity: 0.95;
}

/* FlipFrame + logo + how-to — same column width as story */
.front-cover-manual {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
  flex-shrink: 0;
  width: 100%;
  max-width: var(--front-cover-col);
  padding-top: 0.25rem;
}

.front-cover-brand {
  margin: 0;
  flex-shrink: 0;
  width: 100%;
  text-align: center;
}

.front-cover-brand-line {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  margin: 0;
  font-family: "Inter", sans-serif;
  font-weight: 800;
  /* Product mark — readable, secondary only to title / story */
  font-size: clamp(0.95rem, 0.88rem + 0.35vw, 1.15rem);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text);
}

.front-cover-brand-word {
  line-height: 1;
}

.front-cover-brand-info {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.35rem;
  height: 1.35rem;
  padding: 0;
  border: 1px solid var(--border-light);
  border-radius: 50%;
  background: transparent;
  color: var(--silver);
  cursor: pointer;
  flex-shrink: 0;
  transition:
    color 0.2s var(--transition),
    border-color 0.2s var(--transition),
    background 0.2s var(--transition);
}

.front-cover-brand-info svg {
  width: 0.8rem;
  height: 0.8rem;
}

.front-cover-brand-info:hover {
  color: var(--text);
  border-color: var(--silver);
  background: color-mix(in srgb, var(--text) 8%, transparent);
}

.front-cover-brand-info:focus-visible {
  outline: 2px solid var(--red-smile);
  outline-offset: 2px;
}

.front-cover-brand-build {
  display: block;
  margin: 0.2rem 0 0;
  font-family: "Inter", ui-monospace, monospace;
  font-weight: 500;
  font-size: clamp(0.55rem, 0.52rem + 0.1vw, 0.62rem);
  letter-spacing: 0.06em;
  line-height: 1.2;
  text-transform: none;
  color: var(--silver);
  opacity: 0.85;
}

.front-cover-brand-by {
  display: block;
  margin: 0.25rem 0 0;
  font-family: "Inter", sans-serif;
  font-weight: 600;
  font-size: clamp(0.7rem, 0.66rem + 0.16vw, 0.8rem);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--silver);
}

/* Primary action in reader dialogs may be a link (e.g. FlipFrame contact). */
a.sound-prompt__btn {
  display: block;
  text-decoration: none;
  text-align: center;
  box-sizing: border-box;
}

.sound-prompt__panel strong {
  color: var(--text);
  font-weight: 600;
}

/* Visual how-to: arrow keys + click schema + short caption */
.front-cover-howto {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  width: 100%;
  max-width: var(--front-cover-col);
  margin: 0.25rem 0 0;
  padding: 0.35rem 0 0.15rem;
  flex-shrink: 0;
  box-sizing: border-box;
}

.front-cover-howto-icons {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.85rem 1.25rem;
  width: 100%;
}

.front-cover-howto-caption {
  margin: 0;
  max-width: 18rem;
  font-family: "Inter", sans-serif;
  font-size: clamp(0.78rem, 0.72rem + 0.22vw, 0.9rem);
  font-weight: 400;
  line-height: 1.35;
  letter-spacing: 0.02em;
  text-align: center;
  text-wrap: pretty;
  color: var(--text-muted);
}

.front-cover-howto-svg {
  display: block;
  height: clamp(2.75rem, 2.4rem + 1.2vw, 3.5rem);
  width: auto;
  flex-shrink: 0;
  overflow: visible;
}

.front-cover-howto-keys {
  height: clamp(2.5rem, 2.2rem + 1vw, 3.15rem);
}

.front-cover-howto-click {
  height: clamp(3rem, 2.6rem + 1.2vw, 3.75rem);
}

/* Keyboard keys — inactive base uses silver; .is-active uses accent */
.front-cover-howto-key {
  fill: color-mix(in srgb, var(--bg-card) 70%, transparent);
  stroke: var(--border-light);
}

.front-cover-howto-key.is-active {
  fill: color-mix(in srgb, var(--red-smile) 18%, var(--bg-card));
  stroke: var(--red-smile);
}

.front-cover-howto-key-glyph {
  stroke: var(--silver);
  fill: none;
}

.front-cover-howto-key-glyph.is-active {
  stroke: var(--text);
}

/* Book / page click diagram */
.front-cover-howto-page {
  stroke: var(--border-light);
  fill: color-mix(in srgb, var(--bg-card) 55%, transparent);
}

.front-cover-howto-zone {
  stroke: none;
}

.front-cover-howto-zone--prev {
  fill: color-mix(in srgb, var(--text) 4%, transparent);
}

.front-cover-howto-zone--next {
  fill: color-mix(in srgb, var(--red-smile) 22%, transparent);
}

.front-cover-howto-pointer {
  fill: var(--text);
  stroke: var(--bg-dark);
}

.front-cover-howto-click-dot {
  fill: var(--red-smile);
  stroke: none;
}

.front-cover-synopsis {
  margin: 0;
  width: 100%;
  /* Fill .front-cover-story down to the separator; scroll only when copy overflows */
  flex: 1 1 auto;
  min-height: 0;
  max-height: none;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0.1rem 0.45rem 0.35rem 0;
  scrollbar-width: thin;
  scrollbar-color: var(--border-light) transparent;
  font-family: "Inter", sans-serif;
  font-size: clamp(1rem, 1rem + 0.22vw, 1.3rem);
  font-weight: 400;
  line-height: 1.45;
  letter-spacing: 0.01em;
  text-align: left;
  text-wrap: pretty;
  color: color-mix(in srgb, var(--text) 82%, transparent);
  white-space: normal;
  overflow-wrap: break-word;
  box-sizing: border-box;
}

.front-cover-synopsis::-webkit-scrollbar {
  width: 5px;
}

.front-cover-synopsis::-webkit-scrollbar-thumb {
  background: var(--border-light);
  border-radius: 4px;
}

.front-cover-synopsis::-webkit-scrollbar-track {
  background: transparent;
}

/* Optional CTA rendered by the book engine when a toon passes opts.soundHint */
.front-cover-sound-btn.is-enabled {
  border-color: var(--red-smile);
  color: var(--red-smile);
}

.front-cover-sound-btn .front-cover-sound-waves {
  display: none;
}

.front-cover-sound-btn.is-enabled .front-cover-sound-waves {
  display: inline;
}

.front-cover-sound-btn {
  font-size: clamp(0.8rem, 0.72rem + 0.2vw, 0.9rem);
  padding: 0.6rem 1rem;
  margin-top: 0.35rem;
  /* Icon + “Turn the sound on” label — need space (base .toon-fs-btn has gap: 0). */
  gap: 0.55rem;
  min-width: 0;
}

.front-cover-sound-btn span {
  line-height: 1.2;
}

.front-cover-sound-note {
  font-family: "Inter", sans-serif;
  font-size: clamp(0.8rem, 0.72rem + 0.2vw, 0.9rem);
  letter-spacing: 0.03em;
  text-align: center;
  color: var(--silver);
  opacity: 0.8;
  max-width: 16rem;
}

/* ── Sound enable prompt (modal) ── */
.sound-prompt {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  background: rgba(0, 0, 0, 0.72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.sound-prompt[hidden] {
  display: none !important;
}

.sound-prompt__panel {
  width: min(100%, 380px);
  background: var(--bg-card);
  border: 1px solid var(--border-light);
  padding: 1.75rem 1.5rem 1.4rem;
  text-align: center;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
}

.sound-prompt__icon {
  width: 40px;
  height: 40px;
  margin: 0 auto 1rem;
  color: var(--red-smile);
}

.sound-prompt__panel h2 {
  font-family: "Inter", sans-serif;
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text);
  margin: 0 0 0.75rem;
}

.sound-prompt__panel p {
  font-family: "Inter", sans-serif;
  font-size: 0.85rem;
  font-weight: 300;
  line-height: 1.55;
  letter-spacing: 0.02em;
  color: var(--text-muted);
  margin: 0 0 1.35rem;
}

.sound-prompt__actions {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}

.sound-prompt__btn {
  font-family: "Inter", sans-serif;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--silver);
  padding: 0.7rem 1rem;
  transition:
    color 0.2s var(--transition),
    border-color 0.2s var(--transition),
    background 0.2s var(--transition);
}

.sound-prompt__btn:hover {
  color: var(--text);
  border-color: var(--border-light);
}

.sound-prompt__btn:focus-visible {
  outline: 2px solid var(--red-smile);
  outline-offset: 2px;
}

.sound-prompt__btn--primary {
  background: var(--red-smile);
  border-color: var(--red-smile);
  color: var(--text);
}

.sound-prompt__btn--primary:hover {
  background: var(--text);
  border-color: var(--text);
  color: var(--bg);
}

/* ── Vertical scroll reading mode ──
   Match (or beat) single-page book width so pages don’t look shrunk vs flip view.
   Portrait plates read well up to ~720–800px wide on desktop. */
.vertical-strip {
  display: none;
  width: min(98vw, 720px);
  margin: 0 auto;
  flex-direction: column;
  gap: 1rem;
  padding: 0 0 0.5rem;
}

/* Inner wrapper from VerticalStrip.vue — pass flex layout through */
.vertical-strip .vertical-strip-pages {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  width: 100%;
}

body.view-vertical .vertical-strip {
  display: flex;
}

body.view-vertical .book-scene,
body.view-vertical .controls {
  display: none !important;
}

/*
 * Vertical mode: true window/document scroll only.
 * Do NOT put height:100% + overflow-y:scroll on html — that makes html a
 * nested scrollport. Fast flings on iOS Safari then die mid-momentum when
 * plates reflow (lazy images) or audio work hits the main thread.
 * Classic freeze: html{overflow:hidden} + body{height:100dvh;overflow-y:auto}.
 * !important beats HeadlessUI leftover inline overflow after dialogs.
 */
html:has(body.toons-reader.view-vertical) {
  overflow-x: hidden !important;
  overflow-y: visible !important;
  height: auto !important;
  min-height: 100%;
  -webkit-overflow-scrolling: touch;
}

body.view-vertical.toons-reader {
  height: auto !important;
  min-height: 100%;
  max-width: 100%;
  overflow-x: hidden !important;
  overflow-y: visible !important;
  justify-content: flex-start;
  align-items: center;
  -webkit-overflow-scrolling: touch;
  /* contain traps flings when content reflows under the finger */
  overscroll-behavior-y: auto;
  position: relative !important;
  top: auto !important;
  width: auto !important;
}

body.view-vertical .reader {
  justify-content: flex-start;
  overflow: visible !important;
  min-height: auto;
  height: auto !important;
  width: 100%;
  padding-top: 2.25rem;
  padding-bottom: 1rem;
  touch-action: pan-y;
}

/*
 * Page plates + caption bubbles: pan-y so a finger that starts on a bubble
 * still scrolls. Default touch-action on clickable nodes delays the fling
 * until the browser decides it is not a tap — feels “stuck” on fast scrolls.
 * Interactive bubbles still use pan-y; WordCaption plays on pointerup with a
 * movement slop so a slightly jittery tap is not lost when click is cancelled.
 */
body.view-vertical .vertical-page,
body.view-vertical .vertical-page img,
body.view-vertical .jax-word-layer,
body.view-vertical .jax-word {
  touch-action: pan-y;
  /* Stop iOS long-press “Save Image / Share” sheet eating scroll gestures */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

/* Larger finger hit target on mobile strip (visual box stays small via inset). */
body.view-vertical .jax-word[role="button"]::after {
  content: "";
  position: absolute;
  /* ~44px min target without shifting glyph/bubble layout */
  inset: -0.65em;
  min-width: 2.75rem;
  min-height: 2.75rem;
  margin: auto;
}

body.view-vertical.is-fullscreen .reader {
  padding-top: 1.75rem;
}

.vertical-page {
  position: relative;
  width: 100%;
  background: var(--page-bg, var(--bg-card));
  border: 1px solid var(--border);
  overflow: hidden;
  /* page-slot uses absolute img in book mode; vertical stack needs flow layout */
}

.vertical-page > img {
  display: block;
  width: 100%;
  height: auto;
  vertical-align: top;
  user-select: none;
  -webkit-user-select: none;
  -webkit-user-drag: none;
  -webkit-touch-callout: none;
}

/* Book page-slots position images absolutely; vertical pages must not */
.vertical-page.page-slot {
  position: relative;
  width: 100%;
  /* Reserve plate height before lazy images decode — without this, fast
     flings jump/stop as each plate expands from 0 under the scroll position. */
  aspect-ratio: 1008 / 1792;
  height: auto;
  min-height: 0;
  flex: none;
  /* Let burst/AI bubbles breathe past the panel edge a little */
  overflow: visible;
}

.vertical-page.page-slot > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100% !important;
  max-height: none;
  object-fit: contain;
}

#viewModeBtn.is-active {
  border-color: var(--red-smile);
  color: var(--red-smile);
}

/* --------------------------------------------------------------------------
   Word overlay / bubble chrome (all experiments)
   Classes are still named .jax-word* for history; WordOverlay emits them for
   every toon. Load Bangers + VT323 on the toon page when using captions.
   -------------------------------------------------------------------------- */

.jax-word-layer,
.jax-word,
.jax-word-text {
  font-family: "Bangers", cursive;
  font-weight: 400;
  text-transform: uppercase;
}

/* Base placement/rotation comes from --jax-transform (set inline per word);
   kept out of the `transform` shorthand itself so the hover rule below can
   append scale() without clobbering position. */
.jax-word {
  transform: var(--jax-transform);
}

.jax-word--sfx {
  transition: transform 0.18s cubic-bezier(0.16, 1, 0.3, 1);
  transform-origin: center;
}

.jax-word--sfx:hover {
  transform: var(--jax-transform) scale(1.22);
}

/* Auto-read: the caption currently being spoken. Same zoom as hover plus a
   soft brand-red glow, so the eye follows the page as it reads itself. */
.jax-word.is-speaking {
  transform: var(--jax-transform) scale(1.18);
  filter: drop-shadow(0 0 0.5em color-mix(in srgb, var(--red-smile) 85%, transparent));
  animation: jax-word-speaking 1.1s ease-in-out infinite;
  z-index: 1;
}

@keyframes jax-word-speaking {
  0%,
  100% {
    filter: drop-shadow(0 0 0.35em color-mix(in srgb, var(--red-smile) 70%, transparent));
  }
  50% {
    filter: drop-shadow(0 0 0.85em color-mix(in srgb, var(--red-smile) 95%, transparent));
  }
}

@media (prefers-reduced-motion: reduce) {
  .jax-word.is-speaking {
    animation: none;
  }
}

/* Sketchy dialog bubble variant (also base for ai / badai / burst) */
.jax-word--bubble {
  display: inline-block;
  position: absolute;
  max-width: inherit;
}

.jax-word--bubble .jax-bubble-svg {
  /* Slightly larger than the text box so the white fill always fully wraps
     glyphs + padding. Tail coords sit outside viewBox. */
  position: absolute;
  z-index: 0;
  overflow: visible;
  pointer-events: none;
  left: -0.35em;
  top: -0.3em;
  width: calc(100% + 0.7em);
  height: calc(100% + 0.6em);
}

.jax-word--bubble[data-tail^="bottom"] .jax-bubble-svg {
  height: calc(100% + 1.15em);
}

/* Top tails point up, so the extra room goes above the glyph box, not below. */
.jax-word--bubble[data-tail^="top"] .jax-bubble-svg {
  top: -0.85em;
  height: calc(100% + 1.15em);
}

.jax-word--bubble[data-tail="left"] .jax-bubble-svg {
  left: -0.95em;
  width: calc(100% + 1.3em);
}

.jax-word--bubble[data-tail="right"] .jax-bubble-svg {
  width: calc(100% + 1.3em);
}

/* Thought bubbles have no pointed lobe — the dotted trail is drawn outside the
   viewBox and painted via overflow:visible. Undo the per-tail box offsets so the
   ellipse body stays centred on the glyphs instead of drifting toward the tail. */
.jax-word--thought .jax-bubble-svg {
  left: -0.35em;
  top: -0.3em;
  width: calc(100% + 0.7em);
  height: calc(100% + 0.6em);
}

.jax-word--bubble .jax-word-text {
  position: relative;
  z-index: 1;
  display: block;
  white-space: pre-line;
  /* Keep multi-line comic caps from packing too tight in the fill */
  line-height: 1.2;
}

/* Good AI HUD + hostile badai share monospace face; badai keeps dark ink via JS */
.jax-word--ai .jax-word-text {
  font-family: "VT323", monospace;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  text-align: center;
}

/* Shared caption credit style (end cards, colophons).
   Same face as comic captions (Bangers) — quieter weight/tracking only. */
.jax-word--credit,
.jax-word--credit .jax-word-text {
  font-family: "Bangers", cursive !important;
  font-weight: 400 !important;
  text-transform: none !important;
  letter-spacing: 0.06em !important;
  line-height: 1.35 !important;
  /* Readable on black end-card footers; avoid washed-out silver */
  color: color-mix(in srgb, var(--text) 72%, transparent) !important;
  text-shadow: 0 1px 2px color-mix(in srgb, var(--bg-dark) 55%, transparent);
  opacity: 1;
}

.back-cover-link {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: "Inter", sans-serif;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--silver);
  text-decoration: none;
  transition: color 0.2s var(--transition);
}

.back-cover-link:hover {
  color: var(--red-smile);
}

.page-slot.inside-cover.blank::after {
  display: none;
}

/* Single-page (mobile) layout — --book-width/--book-height overrides live
   in each toon's own <style> (different page aspect ratios) */
body.single-page .spread {
  grid-template-columns: 1fr;
  border-radius: 4px;
}

body.single-page .page-slot.left,
body.single-page .spine,
body.single-page .spine-glow {
  display: none !important;
}

body.single-page .page-slot.right {
  border-radius: 4px;
  box-shadow: none;
}

body.single-page .page-slot img {
  object-fit: contain;
}

body.single-page .nav-zone {
  width: 42%;
}

body.single-page .flip-page {
  width: 100%;
}

body.single-page .flip-page.from-right,
body.single-page .flip-page.from-left {
  left: 0;
  right: 0;
  transform-origin: center center;
}

body.single-page .flip-page.flipping.from-right {
  animation: single-next 0.35s var(--transition) forwards;
}

body.single-page .flip-page.flipping.from-left {
  animation: single-prev 0.35s var(--transition) forwards;
}

@keyframes single-next {
  0% {
    transform: translateX(0);
    opacity: 1;
  }
  100% {
    transform: translateX(-18%);
    opacity: 0;
  }
}

@keyframes single-prev {
  0% {
    transform: translateX(0);
    opacity: 1;
  }
  100% {
    transform: translateX(18%);
    opacity: 0;
  }
}

@media (max-width: 768px) {
  .page-slot[data-page-num]::after {
    left: 0.4rem;
    bottom: 0.3rem;
    font-size: 11px;
  }

  .reader {
    /* >= the 20px mobile arrow radius, same reason as desktop. */
    padding: 2rem 1.25rem 0.75rem;
    gap: 0.7rem;
  }

  /* Bottom edge on phones; padding-bottom keeps the fill above the home bar. */
  .toon-progress {
    top: auto;
    bottom: 0;
    height: auto;
    padding-bottom: env(safe-area-inset-bottom, 0px);
    background: none;
  }

  .toon-progress::before {
    content: "";
    position: absolute;
    inset: 0 0 auto;
    height: 4px;
    background: color-mix(in srgb, var(--text) 8%, transparent);
  }

  .toon-progress .toon-progress-fill {
    height: 4px;
  }

  /* Mobile: plates run edge to edge — no page frame line (book or scroll mode) */
  .spread,
  .vertical-page {
    border: none;
  }

  .toons-back {
    top: 1rem;
    left: 1rem;
  }

  .controls {
    gap: 1rem;
  }

  .reader-btn {
    width: 40px;
    height: 40px;
  }

  .page-nav-btn.prev {
    /* Half the 40px mobile disc. */
    left: -20px;
  }

  .page-nav-btn.next {
    right: -20px;
  }

  .front-cover-instructions {
    gap: 0.85rem;
    padding: 1rem;
  }

  .front-cover-howto-icons {
    gap: 1rem 1.4rem;
  }

  .front-cover-howto-svg {
    height: clamp(3rem, 2.6rem + 1.4vw, 3.75rem);
  }

  .front-cover-howto-caption {
    font-size: clamp(0.82rem, 0.76rem + 0.25vw, 0.95rem);
  }

  .front-cover-brand-line {
    font-size: clamp(1rem, 0.92rem + 0.35vw, 1.2rem);
  }

  .title-bar .section-tag {
    display: none;
  }

  .title-bar h1 {
    display: none;
  }

  .toon-top-controls {
    top: 1rem;
    right: 1rem;
    max-width: calc(100vw - 2rem);
    flex-wrap: wrap;
    justify-content: flex-end;
    row-gap: 0.35rem;
  }
}

/* Headless UI Dialog root for sound prompt (portal).
   Must outrank .cover-guide-dialog (220): on mobile the About dialog is opened
   from inside the cover guide and portals as a SIBLING in #headlessui-portal-root,
   so a lower z-index paints it behind the guide backdrop. */
.sound-prompt-dialog {
  position: relative;
  z-index: 240;
}
.sound-prompt-enter,
.sound-prompt-leave {
  transition: opacity 0.2s var(--transition);
}
.sound-prompt-enter-from,
.sound-prompt-leave-to {
  opacity: 0;
}
.sound-prompt-enter-to,
.sound-prompt-leave-from {
  opacity: 1;
}

/* ── Mobile cover guide (story + how-to popup) ──
   Short phones (e.g. iPhone 13 mini): one outer scrollport must include
   title, synopsis, FlipFrame brand, and how-to — not a nested story-only scroll.
   Panel uses a definite max-height so flex children shrink and overflow-y works
   on iOS WebKit (max-height alone is unreliable for that). */
.cover-guide-dialog {
  position: relative;
  z-index: 220;
}

.cover-guide-backdrop {
  position: fixed;
  inset: 0;
  z-index: 0;
  background: color-mix(in srgb, var(--bg-dark) 78%, transparent);
  backdrop-filter: blur(6px);
}

.cover-guide-center {
  position: fixed;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Prefer svh so mobile browser chrome doesn’t steal the scroll region */
  padding: max(0.5rem, env(safe-area-inset-top, 0px)) 0.75rem max(0.5rem, env(safe-area-inset-bottom, 0px));
  box-sizing: border-box;
  /* Let the panel own vertical pan; avoid the page behind stealing gestures */
  overscroll-behavior: none;
}

.cover-guide-panel {
  width: min(22rem, 100%);
  /* Cap height so .cover-guide-scroll becomes the scrollport on short screens */
  max-height: min(92svh, 92dvh, 720px);
  max-height: min(92dvh, 720px);
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--bg-card);
  border: 1px solid var(--border-light);
  border-radius: 12px;
  box-shadow: 0 20px 50px color-mix(in srgb, var(--bg-dark) 70%, transparent);
  overflow: hidden;
  position: relative;
}

/* Close sits over shared CoverFirstPage — does not own its own header copy */
.cover-guide-toolbar {
  position: absolute;
  top: 0.65rem;
  right: 0.65rem;
  z-index: 2;
}

.cover-guide-close {
  flex-shrink: 0;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: color-mix(in srgb, var(--bg-card) 88%, transparent);
  color: var(--silver);
  font-size: 1.35rem;
  line-height: 1;
  cursor: pointer;
}

.cover-guide-close:hover {
  color: var(--text);
  border-color: var(--border-light);
}

/* Single scrollport for title + story + FlipFrame + how-to */
.cover-guide-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 1rem 1rem 0.75rem;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
  scrollbar-width: thin;
  scrollbar-color: var(--border-light) transparent;
}

/* Flow layout for CoverFirstPage inside the dialog (not absolute book fill).
   Block layout avoids nested flex “story fills space, manual clipped” traps. */
.front-cover-instructions--modal {
  position: relative;
  inset: auto;
  z-index: auto;
  display: block;
  padding: 0 0.25rem 0.75rem;
  overflow: visible;
  max-width: none;
  width: 100%;
  height: auto;
  max-height: none;
  --front-cover-col: 100%;
  text-align: left;
  color: var(--silver);
  box-sizing: border-box;
}

.front-cover-instructions--modal .front-cover-title {
  padding-right: 2.5rem; /* room for absolute close */
  text-align: left;
  max-width: none;
  margin-bottom: 0.15rem;
}

.front-cover-instructions--modal .front-cover-subtitle {
  text-align: left;
  max-width: none;
  margin-bottom: 0.15rem;
}

.front-cover-instructions--modal .front-cover-story {
  display: block;
  flex: none;
  min-height: 0;
  max-height: none;
  max-width: none;
  width: 100%;
  padding-top: 0.35rem;
}

.front-cover-instructions--modal .front-cover-synopsis {
  display: block;
  flex: none;
  overflow: visible;
  max-height: none;
  min-height: 0;
  padding: 0.1rem 0 0.25rem;
  font-size: clamp(0.88rem, 0.82rem + 0.35vw, 1rem);
  line-height: 1.5;
}

.front-cover-instructions--modal .front-cover-separator {
  max-width: none;
  width: 100%;
  margin: 0.65rem 0;
}

.front-cover-instructions--modal .front-cover-manual,
.front-cover-instructions--modal .front-cover-howto {
  max-width: none;
  width: 100%;
}

.front-cover-instructions--modal .front-cover-manual {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  flex: none;
  flex-shrink: 0;
  gap: 0.55rem;
  padding-top: 0.15rem;
  padding-bottom: 0.25rem;
}

.front-cover-instructions--modal .front-cover-brand {
  text-align: left;
  flex-shrink: 0;
}

.front-cover-instructions--modal .front-cover-brand-line {
  justify-content: flex-start;
  font-size: clamp(1rem, 0.94rem + 0.3vw, 1.15rem);
}

.front-cover-instructions--modal .front-cover-howto {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  flex-shrink: 0;
}

.front-cover-instructions--modal .front-cover-howto-icons {
  justify-content: flex-start;
}

.front-cover-instructions--modal .front-cover-howto-caption {
  text-align: left;
  max-width: none;
}

/* Sticky start CTA — stays visible while the body above scrolls */
.cover-guide-footer {
  flex-shrink: 0;
  padding: 0.75rem 1rem max(0.85rem, env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--border);
  background: var(--bg-card);
}

.cover-guide-cta {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0.75rem 1rem;
  border: none;
  border-radius: 8px;
  background: var(--red-smile);
  color: var(--text);
  font-family: "Inter", sans-serif;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  transition: filter 0.15s var(--transition);
}

.cover-guide-cta:hover {
  filter: brightness(1.08);
}

.cover-guide-enter,
.cover-guide-leave {
  transition: opacity 0.2s var(--transition);
}

.cover-guide-enter-from,
.cover-guide-leave-to {
  opacity: 0;
}

.cover-guide-enter-to,
.cover-guide-leave-from {
  opacity: 1;
}

.cover-guide-panel-enter-from {
  opacity: 0;
  transform: translateY(12px) scale(0.98);
}

.cover-guide-panel-leave-to {
  opacity: 0;
  transform: translateY(8px) scale(0.99);
}

.cover-guide-panel-enter-from,
.cover-guide-panel-leave-to {
  transition:
    opacity 0.2s var(--transition),
    transform 0.22s var(--transition);
}

@media (max-width: 420px) {
  .cover-guide-toolbar-btn .toon-fs-label {
    display: none;
  }

  /* Extra room on small phones (13 mini / SE): taller panel, tighter chrome */
  .cover-guide-panel {
    max-height: min(94svh, 96dvh);
    max-height: min(94dvh, 100%);
    border-radius: 10px;
  }

  .cover-guide-scroll {
    padding: 0.85rem 0.85rem 0.65rem;
  }

  .front-cover-instructions--modal .front-cover-howto-svg {
    height: clamp(2.6rem, 2.3rem + 2vw, 3.25rem);
  }

  .front-cover-instructions--modal .front-cover-synopsis {
    font-size: 0.9rem;
    line-height: 1.48;
  }
}

/* ── Language selector (Jax, Nero, …) ── */
.toon-lang-switcher {
  display: flex;
  align-items: center;
}

.toon-lang-dropdown {
  position: relative;
}

.toon-lang-toggle {
  min-width: 2.4rem;
  gap: 0.2rem;
  padding: 0.45rem 0.4rem;
  font-size: 0.7rem;
  letter-spacing: 0.08em;
}

.toon-lang-toggle-label {
  font-family: "Inter", sans-serif;
  font-weight: 700;
  text-transform: uppercase;
  line-height: 1;
}

.toon-lang-chevron {
  width: 9px;
  height: 9px;
  flex-shrink: 0;
  opacity: 0.75;
  transition: transform 0.18s var(--transition);
}

.toon-lang-dropdown.is-open .toon-lang-toggle {
  border-color: var(--red-smile);
  color: var(--red-smile);
}

.toon-lang-dropdown.is-open .toon-lang-chevron {
  transform: rotate(180deg);
  opacity: 1;
}

.toon-lang-menu {
  position: absolute;
  top: calc(100% + 0.35rem);
  right: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  min-width: 100%;
  background: var(--bg-card);
  border: 1px solid var(--border-light);
  box-shadow: 0 12px 28px color-mix(in srgb, var(--bg-dark) 70%, transparent);
}

.toon-lang-menu[hidden] {
  display: none !important;
}

.toon-lang-option {
  font-family: "Inter", sans-serif;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--silver);
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border);
  padding: 0.55rem 0.75rem;
  cursor: pointer;
  text-align: center;
  transition:
    color 0.15s var(--transition),
    background 0.15s var(--transition);
}

.toon-lang-option:last-child {
  border-bottom: none;
}

.toon-lang-option:hover {
  color: var(--text);
  background: var(--bg);
}

.toon-lang-option.is-active {
  color: var(--red-smile);
}

.toon-lang-option:focus-visible {
  outline: 2px solid var(--red-smile);
  outline-offset: -2px;
}

/* ── Crawlable fallback ──
   Lives inside #app, so Vue replaces it the moment the reader mounts. Search
   engines and no-JS visitors get the premise, page count and languages instead
   of an empty document; nothing here is hidden from anyone. */
.reader-fallback {
  max-width: 46rem;
  margin: 0 auto;
  padding: 6rem 1.5rem 3rem;
  color: var(--text-muted);
  font-family: "Inter", sans-serif;
  font-weight: 300;
  line-height: 1.75;
}

.reader-fallback-tag {
  font-size: 0.7rem;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--red-smile);
  font-weight: 700;
  margin-bottom: 1rem;
}

.reader-fallback h1 {
  font-family: "Playfair Display", serif;
  font-size: clamp(2rem, 7vw, 3.5rem);
  line-height: 0.95;
  color: var(--text);
  margin-bottom: 0.5rem;
}

.reader-fallback-sub {
  color: var(--silver);
  letter-spacing: 2px;
  text-transform: uppercase;
  font-size: 0.75rem;
  margin-bottom: 1.5rem;
}

.reader-fallback p + p {
  margin-top: 1rem;
}

.reader-fallback a {
  color: var(--text-muted);
  text-decoration: none;
  border-bottom: 1px solid var(--border);
}

.reader-fallback a:hover {
  color: var(--red-smile);
  border-color: var(--red-smile);
}
