/* ============================================================
   THE WILD WOLF — STYLES (v3, book-sized)
   ------------------------------------------------------------
   The book is a fixed rectangle. You hold it; you turn pages.
   No scrolling. No exception.

   Three voices on the page:
     Special Elite     — the typewriter (the poem itself)
     Biro Script Plus  — the pen (the wolf returning, marking)
     Cedarville Cursive — the hand (reflections beneath)

   Two surfaces:
     paper — for the 60 poem pages
     dark  — for the editorial pages (cover, threshold, etc.)

   One heartbeat: the wolf, at the foot of every page.
   ============================================================ */

/* Biro Script Plus — the pen voice. Licensed font supplied by the
   author and bundled with this build. */
@font-face {
  font-family: "Biro Script Plus";
  src: local("Biro Script Plus Plus Bold"), local("Biro-Script-Plus-Plus-Bold"),
       url("../fonts/BiroScriptPlus-Bold.woff2") format("woff2"),
       url("../fonts/BiroScriptPlus-Bold.woff") format("woff"),
       url("../fonts/BiroScriptPlus-Bold.ttf") format("truetype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  /* paper */
  --paper:        #f3ece0;
  --paper-deep:   #e9dfce;
  --paper-edge:   #d8cbb2;

  /* ink */
  --ink:          #211c17;
  --ink-soft:     #4a4137;
  --ink-faint:    #8a7d6b;

  /* dark surface (the night around the book) */
  --dark-bg:      #0e0c0a;
  --dark-bg-soft: #1a1612;
  --dark-ink:     #e7ddca;
  --dark-ink-soft:#a89c87;
  --dark-ink-faint:#6e6457;

  /* the wild wolf accent — orange #dd9934 */
  --accent:       #dd9934;
  --accent-faint: #b87b25;

  --rule:         rgba(33, 28, 23, 0.22);
  --rule-dark:    rgba(231, 221, 202, 0.22);

  /* the three voices */
  --font-typewriter: "Special Elite", "Courier New", monospace;
  --font-pen:        "Biro Script Plus", "Reenie Beanie", "Comic Sans MS", cursive;
  --font-hand:       "Cedarville Cursive", "Bradley Hand", cursive;
  /* the reflection voice — a clearer handwriting that's easier to read
     in the modal at body text size. */
  --font-reflection: "Reenie Beanie", "Cedarville Cursive", "Bradley Hand", cursive;
  /* biro ink colours — for poem titles and pen-style lines. Two
     variants give the journal a real-world feel (whichever pen was
     on the desk that day). Each poem deterministically picks one
     based on its slug hash. */
  --pen-ink:         #1c3a5c;  /* default = blue, kept for backward-compat */
  --pen-ink-blue:    #1c3a5c;  /* slightly faded Bic blue */
  --pen-ink-black:   #1a1614;  /* warm-black biro, faintly brown in pool */

  /* wood */
  --wood-1: #2a1a10;
  --wood-2: #1c1009;
  --wood-3: #120a05;

  /* page size — the book itself */
  --page-w: min(94vw, 560px);
  --page-h: min(92vh, 820px);
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; overflow: hidden; }
html { -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--font-typewriter);
  color: var(--ink);
  background-color: var(--wood-2);
  /* Forest canopy backdrop — the book sits inside the wild.
     A gentle vignette deepens the edges so the eye lands on the book,
     but the canopy still reads as green and alive. The image is fixed
     so it doesn't shift on mobile scroll. */
  background-image:
    radial-gradient(ellipse 70% 60% at 50% 50%, rgba(0,0,0,0) 0%, rgba(0,0,0,0.15) 60%, rgba(0,0,0,0.45) 100%),
    url("../img/forest-canopy.jpg");
  background-size: cover, cover;
  background-position: center center, center center;
  background-repeat: no-repeat, no-repeat;
  background-attachment: fixed, fixed;
  letter-spacing: 0.3px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* faint film grain over everything */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  opacity: 0.25;
  z-index: 9999;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.035'/%3E%3C/svg%3E");
}

/* the main container holds the book in the middle of the screen */
#app {
  position: relative;
  width: var(--page-w);
  height: var(--page-h);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* The "book base" — an always-present paper surface that sits behind
   every .view. Without this, the 0.4s fadeUp transition between pages
   briefly reveals the forest backdrop through #app, breaking the
   illusion of a continuous book. With it, the surface stays constant
   and only the page content fades. */
#app::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-color: var(--paper);
  background-image:
    /* faint gutter shadow on the left, suggesting a spine where the
       page meets the binding. Subtle enough not to dominate but enough
       to add depth on desktop. */
    linear-gradient(90deg, rgba(60,40,20,0.18) 0%, rgba(60,40,20,0.06) 3%, transparent 7%),
    radial-gradient(ellipse at 50% 50%, transparent 55%, rgba(120,90,50,0.14) 100%);
  border: 1px solid var(--paper-edge);
  border-radius: 2px;
  /* deeper, more cinematic book shadow on desktop — feels like the
     book is sitting on the forest floor in soft light. */
  box-shadow:
    0 1px 0 rgba(255,255,255,0.5) inset,
    0 0 0 1px rgba(0,0,0,0.05),
    0 2px 4px rgba(0,0,0,0.35),
    0 10px 22px rgba(0,0,0,0.45),
    0 28px 60px rgba(0,0,0,0.55),
    0 60px 120px rgba(0,0,0,0.55);
}
/* the stacked-pages edge — three thin layered strips on the right
   suggest a book that has many pages beneath the current one. They
   live on #app so they stay constant during page turns. */
#app::after {
  content: "";
  position: absolute;
  /* outer-most strip */
  top: 10px; bottom: -10px; right: -10px;
  width: 4px;
  background: linear-gradient(180deg, var(--paper-edge), var(--paper-deep));
  box-shadow:
    /* a second strip closer to the page */
    -3px 0 0 0 var(--paper-deep),
    -3px 0 0 1px var(--paper-edge),
    /* a third strip even closer */
    -6px 0 0 0 var(--paper),
    -6px 0 0 1px var(--paper-edge),
    /* and the outer shadow falling onto the forest */
    4px 8px 18px rgba(0,0,0,0.5);
  border-radius: 0 2px 2px 0;
  transform: skewY(-0.5deg);
  z-index: 0;
  pointer-events: none;
}
/* keep .view on top of #app's pseudo-elements during transition */
.view.active { z-index: 1; }

/* on small screens the multi-edge stack looks fussy and the cinematic
   shadow is wasted — keep the paper backing (so page turns don't flash
   the forest) but drop the decorative frame and border. */
@media (max-width: 700px) {
  #app::before {
    background-image: none;
    box-shadow: none;
    border: none;
  }
  #app::after { display: none; }
}

/* ============================================================
   VIEW SYSTEM — one .view is shown at a time
   ============================================================ */
.view {
  display: none;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.view.active {
  display: flex;
  flex-direction: column;
  animation: fadeUp 0.4s ease both;
}
@keyframes fadeUp {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ============================================================
   PAPER PAGE — the body of the book
   The frame (border, shadow, page-edge) lives on #app::before/after
   so it's constant during page turns. This rule only paints the
   paper surface on top, with no border or shadow of its own. */
.view:not(.dark-view) {
  background-color: var(--paper);
  background-image:
    /* faint gutter shadow on the left, suggesting a spine where the
       page meets the binding. Subtle enough not to dominate but enough
       to add depth on desktop. */
    linear-gradient(90deg, rgba(60,40,20,0.16) 0%, rgba(60,40,20,0.05) 3%, transparent 7%),
    radial-gradient(circle at 12% 18%, rgba(120,80,40,0.06) 0, transparent 4%),
    radial-gradient(circle at 88% 32%, rgba(120,80,40,0.05) 0, transparent 3%),
    radial-gradient(circle at 22% 76%, rgba(140,90,40,0.05) 0, transparent 5%),
    radial-gradient(circle at 75% 88%, rgba(120,80,40,0.06) 0, transparent 4%),
    radial-gradient(circle at 18% 22%, rgba(0,0,0,0.045) 0, transparent 38%),
    radial-gradient(circle at 82% 78%, rgba(0,0,0,0.055) 0, transparent 42%),
    radial-gradient(ellipse at 50% 50%, transparent 55%, rgba(120,90,50,0.14) 100%),
    repeating-linear-gradient(0deg, rgba(60,40,20,0.018) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(90deg, rgba(60,40,20,0.012) 0 1px, transparent 1px 4px);

  border-radius: 2px;
  /* More generous side margins so text doesn't crowd the page edges —
     closer to the proportions of a real paperback book. */
  padding: clamp(1.6rem, 4.4vw, 2.8rem) clamp(1.8rem, 6vw, 3.6rem) clamp(3.4rem, 7vw, 4rem);
}

/* the per-view stacked-page edges have been moved to #app to stay
   constant during page turns. Remove them here. */
.view:not(.dark-view)::before,
.view:not(.dark-view)::after { content: none; }

/* the texture overlay on every page */
.page-grain {
  display: block;
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.35;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.6' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.3  0 0 0 0 0.22  0 0 0 0 0.12  0 0 0 0.6 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.07'/%3E%3C/svg%3E");
  border-radius: 2px;
  z-index: 0;
}

/* the content container — fills the page, scrolls only if absolutely needed */
.page-content {
  flex: 1;
  min-height: 0;  /* critical: lets ed-scroll child overflow correctly */
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  overflow: hidden;
  text-align: center;
  width: 100%;
  padding-bottom: 2.6rem;  /* leaves room for wolf-foot */
}

/* ============================================================
   DARK PAGE — editorial gateways
   ============================================================ */
.dark-view {
  background-color: var(--dark-bg);
  background-image:
    /* faint gutter shadow on the left, suggesting the binding seam */
    linear-gradient(90deg, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0.1) 3%, transparent 7%),
    radial-gradient(ellipse at 50% 40%, rgba(40,32,24,0.7) 0%, var(--dark-bg) 70%);
  color: var(--dark-ink);
  border-radius: 2px;
  /* lighter than before — the book's main depth comes from #app's
     pseudo-elements now. Just a subtle edge so the dark page sits
     inside the paper frame cleanly. */
  box-shadow: 0 0 0 1px rgba(0,0,0,0.25);
  padding: clamp(1.4rem, 4vw, 2.4rem) clamp(1.2rem, 4.5vw, 2.4rem) clamp(2.4rem, 5vw, 3rem);
  position: relative;
}
.dark-view::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.35;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.5' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E");
  border-radius: 2px;
}
.dark-view .page-content { z-index: 1; }

/* ============================================================
   COVER — leather hardback with embossed wolf + "his" original poetry
   The cover image is a photo-realistic black leather book with all
   the typography baked in (wolf engraving, @the_wildwolf, "his"
   original poetry). The view just renders the image to fit, then
   anchors a small "open book_" call-to-action and the © at the bottom.
   ============================================================ */
#cover.dark-view {
  background-color: #0a0806;
  background-image:
    url("../img/cover-leather.jpg");
  /* cover (not contain): the leather book fills the page box edge-to-edge,
     no inner black voids. The image has been pre-trimmed to ~0.68 aspect
     so the wolf/title stay safely within view at any sensible viewport.
     background-position-x is shifted right ~6% so that when the image
     is cropped on narrow mobile viewports, the front-cover face stays
     centred (the spine on the left of the image otherwise pushes the
     visual content right). On desktop the page box is wide enough that
     no horizontal cropping happens, so the offset is invisible. */
  background-size: cover;
  background-position: 57% center;
  background-repeat: no-repeat;
  padding: 0;
}
/* cover-content: instead of centering its children, anchor them in the
   lower portion of the cover — but not flush against the bottom edge.
   The leather has its own embossed frame near the bottom; sitting the
   button just above that frame's bottom rail (around 75-80% down)
   places it on clean leather inside the inset area.
   The left padding shifts the button + © text right to align with the
   visual centre of the front-cover face (the spine on the left of the
   image otherwise makes the geometric centre of the page box look
   left-of-centre relative to the embossed frame). */
#cover .cover-content {
  justify-content: flex-end;
  padding-bottom: clamp(4.5rem, 16vh, 8rem);
  padding-top: 0;
  padding-left: 7%;
  padding-right: 0;
}
/* On narrow mobile (portrait), the viewport is narrower than the image
   aspect ratio, so the image is heavily cropped horizontally. With
   center positioning, the natural crop hides most of the spine and
   centres on the front face. The desktop 57% offset would push the
   image too far right here. */
@media (max-width: 700px) {
  #cover.dark-view {
    background-position: 67% center;
  }
  #cover .cover-content {
    padding-left: 0;
    padding-right: 0;
  }
}

.cover-enter {
  display: inline-block;
  font-size: 0.85rem;
  letter-spacing: 3px;
  text-transform: lowercase;
  color: var(--dark-ink);
  text-decoration: none;
  /* the embossed-frame on the leather already gives a clean container,
     so the button just needs a soft outline that reads on dark leather */
  border: 1px solid rgba(231, 221, 202, 0.5);
  padding: 0.65rem 1.6rem;
  cursor: pointer;
  background: rgba(8, 6, 4, 0.55);
  font-family: inherit;
  transition: background 0.4s ease, color 0.4s ease, border-color 0.4s ease, letter-spacing 0.4s ease;
  position: relative;
  z-index: 10;
  /* faint shadow so the button feels lifted from the leather */
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.4);
}
.cover-enter:hover,
.cover-enter:focus-visible {
  background: var(--accent);
  color: var(--dark-bg);
  border-color: var(--accent);
  letter-spacing: 4px;
  outline: none;
}

/* ============================================================
   COVER ICON ROW — three quiet, high-contrast icon buttons under
   "open book": home (back to the wild), about this book, and
   copyright/sharing. Replaces the old low-contrast text links that
   were hard to read on the cover photo. Each is a small round button
   with a soft dark fill + pale stroke so the glyph stays legible on
   any cover; hover lifts to the book's accent, matching "open book".
   about + copyright open the existing in-book modals.
   ============================================================ */
.cover-icons {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.85rem;
  margin-top: 1.3rem;
  flex-shrink: 0;
  position: relative;
  z-index: 10;
}
.cover-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 999px;
  padding: 0;
  cursor: pointer;
  color: #f0e8d6;
  background: rgba(8, 6, 4, 0.55);
  border: 1px solid rgba(231, 221, 202, 0.45);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.4);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  transition: background 0.35s ease, color 0.35s ease,
              border-color 0.35s ease, transform 0.25s ease;
}
.cover-icon-btn svg {
  width: 18px;
  height: 18px;
  display: block;
}
.cover-icon-btn:hover,
.cover-icon-btn:focus-visible {
  background: var(--accent, #d8a44a);
  color: var(--dark-bg, #1a1208);
  border-color: var(--accent, #d8a44a);
  transform: translateY(-2px);
  outline: none;
}

.caret { display:inline-block; width:0.5ch; animation: blink 1.1s steps(1) infinite; }
@keyframes blink { 50% { opacity: 0; } }

/* ============================================================
   ABOUT-THIS-BOOK MODAL — opened from the cover's secondary
   button. Same modal shell as copyright/howto, sized for a
   short framing paragraph. Voice: identical to what used to
   live on the now-removed /his/ landing page.
   ============================================================ */
.modal-card-aboutbook {
  max-width: 460px;
  padding: 1.4rem 1.6rem 1.4rem;
}
.aboutbook-title {
  font-family: var(--font-pen);
  font-style: normal;
  font-size: clamp(2.2rem, 5vw, 3rem);
  color: var(--accent);
  text-align: center;
  font-weight: normal;
  margin: 0.2rem 0 0.2rem;
  letter-spacing: 1px;
  line-height: 1;
}
.aboutbook-subtitle {
  font-family: var(--font-typewriter);
  font-style: italic;
  font-size: 0.92rem;
  color: var(--ink-soft);
  text-align: center;
  letter-spacing: 0.5px;
  margin-bottom: 1.2rem;
}
.aboutbook-body {
  text-align: center;
  max-width: 26rem;
  margin: 0 auto;
}
.aboutbook-body p {
  font-family: var(--font-typewriter);
  font-size: 0.9rem;
  line-height: 1.75;
  color: var(--ink-soft);
  margin: 0 0 0.9rem;
}
.aboutbook-body p:last-child { margin-bottom: 0; }
.aboutbook-body em { color: var(--accent); font-style: italic; }
.aboutbook-body strong { color: var(--ink); font-weight: bold; }
.aboutbook-lede {
  font-family: var(--font-typewriter);
  font-style: italic;
  color: var(--ink) !important;
}
.aboutbook-invite {
  margin-top: 1.2rem !important;
}
.aboutbook-footer {
  margin-top: 1.4rem;
  text-align: center;
  font-family: var(--font-typewriter);
  font-size: 0.6rem;
  letter-spacing: 2.5px;
  color: var(--ink-fainter);
  text-transform: lowercase;
}

/* ============================================================
   THE WOLF HEADER — appears at the top of every page (except
   the cover). Same shape, same position, dark or paper.
   Anchored to the page so its position is consistent.
   ============================================================ */
/* The wolf watermark - the standing wolf himself, faint and centred at
   the top of every interior page. The same quiet seal across all four
   books. No longer a link or a wordmark: just the mark. Leaving the book
   is handled by .home-link (top-left). */
.wolf-header {
  position: absolute;
  top: 1.5rem;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  flex-shrink: 0;
  z-index: 2;
  pointer-events: none; /* a watermark, not a control */
}
.wolf-header img,
.wolf-header .wolf-header-img {
  width: 42px;
  height: auto;
  opacity: 0.42;
  margin-bottom: 0;
}

/* ============================================================
   "back to the wild" — the persistent home control.
   Top-left of every interior page, outside the rendered book so it
   survives page turns. Quiet by default (it must not fight the poem),
   but unmistakably a control: an arrow, a label, a clear hover. This
   is the reader's way out of the book and back to the imprint - the
   bookshelf, the other books, about, press, contact.
   ============================================================ */
.home-link {
  position: fixed;
  top: 1.25rem;
  left: 1.25rem;
  z-index: 20;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.4rem 0.7rem 0.4rem 0.55rem;
  border-radius: 999px;
  text-decoration: none;
  color: var(--ink-soft, #4a4a44);
  background: rgba(245, 240, 230, 0.72);
  border: 1px solid rgba(60, 50, 40, 0.18);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  font-family: var(--font-typewriter, "Courier New", monospace);
  font-size: 0.62rem;
  letter-spacing: 2.5px;
  text-transform: lowercase;
  cursor: pointer;
  transition: color 0.25s ease, background 0.25s ease,
              border-color 0.25s ease, transform 0.25s ease;
}
.home-link svg { display: block; flex-shrink: 0; }
.home-link .home-link-label { line-height: 1; padding-top: 1px; }
.home-link:hover,
.home-link:focus-visible {
  color: var(--accent, #b06a2c);
  border-color: var(--accent, #b06a2c);
  transform: translateX(-1px);
  outline: none;
}
.home-link.hidden { display: none; }
@media (max-width: 700px) {
  .home-link {
    top: calc(0.9rem + env(safe-area-inset-top, 0px));
    left: 0.9rem;
    padding: 0.35rem 0.6rem 0.35rem 0.5rem;
    font-size: 0.58rem;
  }
}

/* When the header is present, push page-content down so it doesn't
   overlap. The header is ~24px top + 32px image + ~10px handle ≈ 66px;
   we leave 4.6rem (~74px) so nothing on a child page ever crosses it. */
.view .page-content { padding-top: 4.6rem; }
/* Cover has no header — full bleed */
#cover .page-content { padding-top: 0; }

/* ============================================================
   EDITORIAL TYPE — eyebrow, body, quote
   ============================================================ */
.ed-eyebrow {
  font-family: var(--font-typewriter);
  font-size: clamp(0.92rem, 2.5vw, 1.1rem);
  font-weight: bold;
  margin-bottom: 1rem;
  letter-spacing: 0.3px;
  text-align: center;
  flex-shrink: 0;
}
.dark-view .ed-eyebrow { color: var(--dark-ink); }
.view:not(.dark-view) .ed-eyebrow { color: var(--ink); }
.ed-eyebrow em { font-style: italic; color: var(--accent); }

/* body text auto-shrinks to fit */
.ed-body {
  font-family: var(--font-typewriter);
  font-size: clamp(0.78rem, 2vw, 0.92rem);
  line-height: 1.7;
  max-width: 100%;
  text-align: left;
}
.ed-body p { margin-bottom: 0.8rem; }
.ed-body p:last-child { margin-bottom: 0; }
.ed-body em { font-style: italic; }
.ed-body strong { font-weight: bold; }
.ed-body.centered { text-align: center; }
.ed-body.centered p { margin-bottom: 0.6rem; }

.dark-view .ed-body { color: var(--dark-ink); }
.view:not(.dark-view) .ed-body { color: var(--ink); }

/* longer-text editorial pages get smaller type */
.ed-body.dense {
  font-size: clamp(0.7rem, 1.7vw, 0.82rem);
  line-height: 1.6;
}
.ed-body.dense p { margin-bottom: 0.6rem; }

/* a scrollable inner region — used on the support-long and hear-howl
   pages so all of the original text is preserved. The page itself
   never scrolls; this region does, within its margins. The accountant
   page no longer uses this — it auto-paginates instead. */
.ed-scroll {
  flex: 1;
  width: 100%;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 0 0.4rem;
  margin: 0.2rem 0 0.6rem;
  /* subtle scroll affordance */
  mask-image: linear-gradient(to bottom, transparent 0, #000 18px, #000 calc(100% - 18px), transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 18px, #000 calc(100% - 18px), transparent 100%);
}
.ed-scroll::-webkit-scrollbar { width: 4px; }
.ed-scroll::-webkit-scrollbar-thumb {
  background: rgba(231, 221, 202, 0.18);
  border-radius: 999px;
}
.view:not(.dark-view) .ed-scroll::-webkit-scrollbar-thumb {
  background: rgba(33, 28, 23, 0.18);
}

/* the accountant page is auto-paginated — its body fills the available
   space and is vertically centered. no scrollbars; nothing clipped. */
.accountant-body {
  width: 100%;
  max-width: 100%;
  margin: 0.4rem 0 1.2rem;
}

.ed-quote {
  background: rgba(255,255,255,0.025);
  border: 1px solid rgba(231,221,202,0.12);
  padding: 1rem 1.1rem;
  margin: 0.8rem 0;
  text-align: center;
  font-family: var(--font-typewriter);
  line-height: 1.7;
  font-size: clamp(0.78rem, 2vw, 0.92rem);
}
.view:not(.dark-view) .ed-quote {
  background: rgba(0,0,0,0.025);
  border: 1px solid var(--rule);
}
.ed-quote p { margin-bottom: 0.35rem; }
.ed-quote p:last-child { margin-bottom: 0; }

.ed-button {
  display: inline-block;
  margin-top: 1.2rem;
  font-size: 0.78rem;
  letter-spacing: 3px;
  text-transform: lowercase;
  color: var(--dark-ink);
  text-decoration: none;
  border: 1px solid rgba(231, 221, 202, 0.4);
  padding: 0.65rem 1.6rem;
  cursor: pointer;
  background: transparent;
  font-family: var(--font-typewriter);
  transition: background 0.4s ease, color 0.4s ease, border-color 0.4s ease, letter-spacing 0.4s ease;
  position: relative;
  z-index: 10;
  flex-shrink: 0;
}
.ed-button:hover {
  background: var(--accent);
  color: var(--dark-bg);
  border-color: var(--accent);
  letter-spacing: 4px;
}
.view:not(.dark-view) .ed-button {
  color: var(--ink);
  border-color: rgba(0,0,0,0.4);
}
.view:not(.dark-view) .ed-button:hover {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}

.ed-signature {
  margin-top: 0.9rem;
  font-family: var(--font-hand);
  font-size: 1.2rem;
  color: var(--accent);
  letter-spacing: 0.5px;
  flex-shrink: 0;
}

/* ============================================================
   FRONT MATTER — dedication, colophon, copyright
   ============================================================ */
.front-matter {
  text-align: center;
}
.front-matter h1 {
  font-size: clamp(1.4rem, 5vw, 2rem);
  line-height: 1.15;
  font-weight: normal;
  letter-spacing: 0.5px;
}
.fm-rule { width: 50px; height: 1px; background: var(--rule); margin: 1.2rem auto; flex-shrink: 0; }

/* The book's last line. NOT "the end." but "the beginning;" -
   because what the reader has just finished is actually the start
   of the wolf's onward journey through whoever reads the words next.
   Rendered slightly larger and in biro-script to land as a declaration,
   not a fade. */
.closing-breath {
  font-family: var(--font-pen);
  font-size: 1.6rem;
  color: var(--accent);
  text-align: center;
  margin-top: 0.4rem;
  letter-spacing: 0.5px;
  line-height: 1.2;
}

/* The single line at the foot of the accountant page that points at
   the full origin tale on the imprint. Sits centred, slightly faded,
   with the link itself in gold so the reader knows it's tappable. */
.accountant-origin-link {
  text-align: center;
  margin-top: 1.6rem !important;
  font-size: 0.82rem;
  color: var(--ink-faint);
  letter-spacing: 0.3px;
}
.accountant-origin-link a {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px dotted rgba(216, 164, 74, 0.4);
  padding-bottom: 1px;
  transition: color 0.3s ease, border-bottom-color 0.3s ease;
}
.accountant-origin-link a:hover,
.accountant-origin-link a:focus-visible {
  color: #ffd97a;
  border-bottom-color: var(--accent);
  outline: none;
}
.fm-label {
  font-size: 0.62rem; letter-spacing: 4px; text-transform: lowercase;
  color: var(--ink-faint); margin-bottom: 1rem;
  flex-shrink: 0;
}
.front-matter p {
  max-width: 360px;
  margin: 0.6rem auto;
  color: var(--ink-soft);
  white-space: pre-line;
  font-size: clamp(0.78rem, 2vw, 0.9rem);
  line-height: 1.6;
}
.dedication-text {
  font-family: var(--font-hand);
  font-size: clamp(1.3rem, 4.5vw, 1.6rem);
  line-height: 1.5;
  color: var(--ink);
}

/* ============================================================
   CONTENTS PAGE — sectioned by volume
   the contents page is the one place where we DO allow some
   internal scroll (it's a list, lists can scroll within a frame)
   ============================================================ */
#contents-view .page-content {
  justify-content: flex-start;
  overflow: hidden; /* the scroll lives in .contents-scroll, not here */
  padding: 4rem 0 0.4rem;
}
@media (max-width: 700px) {
  #contents-view .page-content {
    padding: calc(4rem + env(safe-area-inset-top, 0px)) 0 0.4rem;
  }
}
/* the title sits in a fixed top zone */
.contents-head {
  flex-shrink: 0;
  width: 100%;
}
/* scrollable list area */
.contents-scroll {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  overflow-y: auto;
  overflow-x: hidden;
  /* fade the top and bottom edges so list items don't appear to slam
     into the header / page edge */
  mask-image: linear-gradient(to bottom, transparent 0, #000 14px, #000 calc(100% - 14px), transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 14px, #000 calc(100% - 14px), transparent 100%);
  padding: 0 0.4rem;
}
.contents-scroll::-webkit-scrollbar { width: 6px; }
.contents-scroll::-webkit-scrollbar-thumb {
  background: rgba(33,28,23,0.25);
  border-radius: 999px;
}

.contents-title {
  text-align: center;
  font-size: clamp(1.1rem, 4vw, 1.5rem);
  letter-spacing: 4px;
  text-transform: lowercase;
  margin: 0.4rem 0 1.2rem;
  font-weight: normal;
  flex-shrink: 0;
}

.toc-volume {
  margin: 0.6rem auto 0.2rem;
  text-align: center;
  flex-shrink: 0;
}
.toc-volume-roman {
  font-size: 0.6rem;
  letter-spacing: 4px;
  text-transform: lowercase;
  color: var(--ink-faint);
  margin-bottom: 0.1rem;
}
.toc-volume-name {
  font-family: var(--font-pen);
  color: var(--accent);
  font-size: 1.6rem;
  letter-spacing: 0.5px;
  line-height: 1.1;
}
.toc-volume-rule {
  width: 28px; height: 1px; background: var(--accent); opacity: 0.5;
  margin: 0.3rem auto 0.6rem;
}

.toc { list-style: none; width: 100%; max-width: 380px; margin: 0 auto; }
.toc li { margin: 0; }
.toc a {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  text-decoration: none;
  color: var(--ink);
  padding: 0.32rem 0.4rem;
  border-bottom: 1px dotted var(--rule);
  transition: color 0.25s ease, padding-left 0.25s ease;
  font-size: 0.78rem;
  line-height: 1.3;
}
.toc a:hover { color: var(--accent); padding-left: 0.7rem; }
.toc .toc-num { color: var(--ink-faint); font-size: 0.7rem; min-width: 2.2ch; }
.toc .toc-name { flex: 1; text-align: left; }
.toc .toc-italic { font-style: italic; color: var(--ink-soft); }

/* small subtitle under "contents" — "67 pages · 60 poems" */
.contents-subtitle {
  text-align: center;
  font-size: 0.6rem;
  letter-spacing: 3px;
  color: var(--ink-faint);
  margin: -0.6rem 0 1rem;
  text-transform: lowercase;
}

/* front / back matter section headers — quieter than volume headers */
.toc-section {
  margin: 1rem auto 0.4rem;
  text-align: center;
  flex-shrink: 0;
}
.toc-section-name {
  font-family: var(--font-typewriter);
  font-size: 0.65rem;
  letter-spacing: 5px;
  color: var(--ink-faint);
  text-transform: lowercase;
  margin-bottom: 0.3rem;
}
.toc-section .toc-volume-rule { background: var(--ink-faint); opacity: 0.35; }

/* same italic + section styling for the modal version */
.modal-toc .toc-italic { font-style: italic; color: var(--ink-soft); }

/* ============================================================
   VOLUME DIVIDER PAGE
   ============================================================ */
.volume-divider {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  text-align: center;
}
.volume-divider .roman {
  font-size: 0.7rem;
  letter-spacing: 5px;
  text-transform: lowercase;
  color: var(--ink-faint);
  margin-bottom: 1rem;
}
.volume-divider .name {
  font-family: var(--font-pen);
  color: var(--accent);
  font-size: clamp(2.4rem, 9vw, 3.8rem);
  line-height: 1;
  letter-spacing: 1px;
}
.volume-divider .rule {
  width: 60px; height: 1px;
  background: var(--accent);
  opacity: 0.5;
  margin: 1.6rem auto;
}
.volume-divider .count {
  font-size: 0.7rem;
  letter-spacing: 4px;
  text-transform: lowercase;
  color: var(--ink-faint);
}

/* ============================================================
   POEM PAGE
   Three zones:
     .poem-head      — pinned to the top (volume, title, rule, eyebrow)
     .poem-body-wrap — flexible middle; the poem is centered inside
     .poem-foot      — pinned to the bottom (reflection button or
                       "continued…" indicator for paginated poems)
   The poem itself never scrolls. The font-size is fixed (matching the
   editorial text on the threshold page); if a poem is too long it
   reflows onto subsequent pages — exactly like a real book.
   ============================================================ */
.poem-page {
  justify-content: flex-start;
  padding-top: 0.4rem;
}
.poem-head {
  flex-shrink: 0;
  width: 100%;
}
.poem-foot {
  flex-shrink: 0;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: flex-end;
  min-height: 0;
}
/* the middle zone takes all remaining height; the poem centers within it */
.poem-body-wrap {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  /* breathing space so a full-length poem never touches the title rule
     or the foot — even when the body fills the available area. Generous
     at the top so the poem feels distinct from the title. */
  padding: 1.8rem 0 1.2rem;
}

.poem-volume {
  text-align: center;
  font-size: 0.62rem;
  letter-spacing: 4px;
  text-transform: lowercase;
  color: var(--accent);
  opacity: 0.85;
  margin-bottom: 0.7rem;
}
.poem-title {
  text-align: center;
  font-size: clamp(1.3rem, 4.8vw, 1.8rem);
  line-height: 1.2;
  font-weight: normal;
  margin-bottom: 0.5rem;
}
.poem-title-rule {
  width: 36px; height: 2px; background: var(--accent);
  margin: 0.6rem auto 0.7rem;
}
.poem-eyebrow {
  text-align: center;
  font-size: 0.6rem;
  letter-spacing: 3px;
  text-transform: lowercase;
  color: var(--ink-faint);
  margin-bottom: 0;
}

.poem-body {
  /* Same fixed size as the editorial text on the threshold page so
     poems read at a consistent, comfortable size — like a real book.
     Poems too long for one page are paginated; they don't shrink. */
  font-size: clamp(0.78rem, 2vw, 0.92rem);
  line-height: 1.7;
  color: var(--ink);
  margin: 0 auto;
  /* centred — the way these poems were born on Instagram. each line
     floats to its own axis; the column is constrained so long lines
     don't pull the eye too wide. */
  text-align: center;
  max-width: 30rem;
}

/* the "continued…" footer on poems split across multiple pages */
.poem-continued {
  font-family: var(--font-typewriter);
  font-size: 0.7rem;
  letter-spacing: 3px;
  text-transform: lowercase;
  color: var(--ink-faint);
  text-align: center;
  padding: 0.4rem 0.6rem;
  font-style: italic;
}
.poem-continued .cont-dots {
  display: inline-block;
  margin-left: 0.2ch;
  color: var(--accent);
  letter-spacing: 0;
  font-style: normal;
  /* gentle pulse so the reader's eye lands on it */
  animation: contDots 1.8s ease-in-out infinite;
}
@keyframes contDots {
  0%, 100% { opacity: 0.4; }
  50%      { opacity: 1;   }
}

/* on continuation pages the title is smaller — like a chapter
   running-head in a real book, telling you where you are without
   shouting at you. */
.poem-head-continued .poem-title-small {
  font-size: clamp(1rem, 3.4vw, 1.3rem);
  opacity: 0.9;
  margin-bottom: 0.3rem;
}
.poem-head-continued .poem-title-rule {
  margin: 0.4rem auto 0.5rem;
  opacity: 0.7;
}
.poem-head-continued .poem-eyebrow {
  font-style: italic;
  color: var(--accent);
  opacity: 0.85;
}

.poem-body .tl {
  display: block;
  white-space: pre-wrap;
  text-indent: 0;
}
.poem-body .tl-blank {
  height: 0.8em;
}

/* ink variation */
.poem-body .tl:nth-child(3n)   { opacity: 0.96; letter-spacing: 0.4px; }
.poem-body .tl:nth-child(3n+1) { opacity: 0.99; letter-spacing: 0.25px; }
.poem-body .tl:nth-child(4n)   { transform: translateY(0.4px); }

/* No typewriter reveal — every line is visible immediately. The .typed
   class is kept on the markup for selector compatibility but no longer
   triggers any animation. */

/* ============================================================
   THE PEN VOICE
   ============================================================ */
.pen-line {
  display: block;
  font-family: var(--font-pen);
  color: var(--pen-ink);
  /* relative to .poem-body's font-size so the auto-fit pass scales it too.
     Biro Script Plus has tighter metrics than Reenie Beanie so we run at a
     more modest multiplier with a slight line-height boost for breathing. */
  font-size: 1.35em;
  line-height: 1.3;
  letter-spacing: 0.3px;
  margin-top: 0.4em;
  text-shadow: 0 0 1px rgba(28, 58, 92, 0.12);
}
.pen-line.indent { padding-left: 3ch; }
.pen-line.indent-deep { padding-left: 5ch; }

.poem-title.pen-title {
  font-family: var(--font-pen);
  /* per-instance ink: each poem gets a deterministic blue or black biro
     via the --this-pen-ink custom property set on the element. Falls
     back to the global blue if not set. */
  color: var(--this-pen-ink, var(--pen-ink));
  font-size: clamp(1.7rem, 6vw, 2.6rem);
  line-height: 1.1;
  letter-spacing: 0.3px;
  /* matching subtle ink-bleed glow */
  text-shadow: 0 0 1px color-mix(in srgb, var(--this-pen-ink, var(--pen-ink)) 18%, transparent);
}
/* continuation pages: the smaller running-head version of the title
   inherits the same ink so the poem feels written in one hand */
.poem-head-continued .poem-title-small.pen-title {
  font-family: var(--font-pen);
  color: var(--this-pen-ink, var(--pen-ink));
  font-size: clamp(1.05rem, 3.6vw, 1.4rem);
  letter-spacing: 0.3px;
  text-shadow: 0 0 1px color-mix(in srgb, var(--this-pen-ink, var(--pen-ink)) 15%, transparent);
}

.pen-underline {
  position: relative;
  display: inline-block;
}
.pen-underline::after {
  content: "";
  position: absolute;
  left: -2px;
  right: -4px;
  bottom: -3px;
  height: 7px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 8' preserveAspectRatio='none'><path d='M1,5 C20,2 40,7 60,4 C75,2 90,6 99,4' fill='none' stroke='%231c3a5c' stroke-width='1.4' stroke-linecap='round' opacity='0.85'/></svg>");
  background-repeat: no-repeat;
  background-size: 100% 100%;
}

.pen-circle {
  position: relative;
  display: inline-block;
  padding: 0 4px;
}
.pen-circle::before {
  content: "";
  position: absolute;
  inset: -4px -8px -3px -8px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 40' preserveAspectRatio='none'><ellipse cx='60' cy='20' rx='56' ry='17' fill='none' stroke='%231c3a5c' stroke-width='1.2' opacity='0.7' transform='rotate(-2 60 20)'/></svg>");
  background-repeat: no-repeat;
  background-size: 100% 100%;
  pointer-events: none;
}

/* ============================================================
   THE HAND VOICE — reflections
   The reflection lives in an overlay; the poem gets the page.
   Below the poem, a small understated button offers the option.
   ============================================================ */
.reflection-toggle {
  margin: 1.4rem auto 0;
  background: rgba(28, 58, 92, 0.06);
  border: 1px solid rgba(28, 58, 92, 0.25);
  border-radius: 2px;
  padding: 0.55rem 1rem;
  font-family: var(--font-typewriter);
  font-size: 0.72rem;
  letter-spacing: 2px;
  text-transform: lowercase;
  color: var(--pen-ink);
  cursor: pointer;
  text-align: center;
  transition: background 0.25s ease, color 0.25s ease, border-color 0.25s ease;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.6ch;
}
.reflection-toggle:hover,
.reflection-toggle:focus-visible {
  background: var(--pen-ink);
  color: var(--paper);
  border-color: var(--pen-ink);
  outline: none;
}
.reflection-toggle .ref-arrow {
  display: inline-block;
  font-family: var(--font-typewriter);
  font-size: 0.78rem;
  transition: transform 0.25s ease;
}
.reflection-toggle:hover .ref-arrow,
.reflection-toggle:focus-visible .ref-arrow { transform: translate(2px, -2px); }

/* the overlay that dims the page and holds the reflection card */
.reflection-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(8, 5, 3, 0);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.4rem;
  opacity: 0;
  transition: background 0.28s ease, opacity 0.28s ease;
  pointer-events: none;
}
.reflection-overlay[hidden] { display: none; }
.reflection-overlay.open {
  background: rgba(8, 5, 3, 0.72);
  opacity: 1;
  pointer-events: auto;
  backdrop-filter: blur(3px);
}
.reflection-card {
  background: var(--paper);
  background-image:
    radial-gradient(ellipse at 20% 20%, rgba(120,80,40,0.05) 0, transparent 50%),
    radial-gradient(ellipse at 80% 80%, rgba(120,80,40,0.06) 0, transparent 50%);
  color: #2c2418;
  border: 1px solid var(--paper-edge);
  border-radius: 2px;
  box-shadow:
    0 4px 8px rgba(0,0,0,0.45),
    0 24px 48px rgba(0,0,0,0.55);
  padding: 2.4rem 1.8rem 1.8rem;
  max-width: 480px;
  width: 100%;
  max-height: 80vh;
  overflow-y: auto;
  position: relative;
  transform: scale(0.97);
  transition: transform 0.28s ease;
}
.reflection-overlay.open .reflection-card { transform: scale(1); }

.reflection-close {
  position: absolute;
  top: 0.5rem;
  right: 0.7rem;
  background: transparent;
  border: none;
  font-family: var(--font-typewriter);
  font-size: 1.6rem;
  line-height: 1;
  color: var(--ink-faint);
  cursor: pointer;
  padding: 0.3rem 0.5rem;
  transition: color 0.25s ease;
}
.reflection-close:hover { color: var(--accent); }

.reflection-label {
  text-align: center;
  font-family: var(--font-typewriter);
  font-size: 0.7rem;
  letter-spacing: 4px;
  text-transform: lowercase;
  color: var(--ink-faint);
  margin-bottom: 1.2rem;
}
.reflection-label .reflection-on {
  margin: 0 0.6ch;
  color: var(--accent);
}
.reflection-label .reflection-poem {
  color: var(--ink);
  font-style: italic;
}

.reflection-body {
  font-family: var(--font-reflection);
  /* Reenie Beanie reads small for its em-size, so bump a little.
     Same warm dark ink, slightly looser line-height for breathing. */
  font-size: 1.5rem;
  line-height: 1.35;
  color: #2c2418;
  letter-spacing: 0.4px;
  text-align: left;
  white-space: pre-line;
  text-shadow: 0 0 0.4px rgba(44, 36, 24, 0.18);
}

/* ============================================================
   GENERIC MODAL OVERLAY — used by the contents and share popups.
   Visual language matches the reflection card: paper, soft glow,
   scale-in. Padding accounts for the bottom pager and safe-areas.
   ============================================================ */
.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 210;
  background: rgba(8, 5, 3, 0);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.4rem;
  padding-bottom: calc(5rem + env(safe-area-inset-bottom, 0px));
  padding-top: calc(1.4rem + env(safe-area-inset-top, 0px));
  opacity: 0;
  transition: background 0.28s ease, opacity 0.28s ease;
  pointer-events: none;
}
.modal-overlay[hidden] { display: none; }
.modal-overlay.open {
  background: rgba(8, 5, 3, 0.72);
  opacity: 1;
  pointer-events: auto;
  backdrop-filter: blur(3px);
}
.modal-card {
  background: var(--paper);
  background-image:
    radial-gradient(ellipse at 20% 20%, rgba(120,80,40,0.05) 0, transparent 50%),
    radial-gradient(ellipse at 80% 80%, rgba(120,80,40,0.06) 0, transparent 50%);
  color: #2c2418;
  border: 1px solid var(--paper-edge);
  border-radius: 2px;
  box-shadow:
    0 4px 8px rgba(0,0,0,0.45),
    0 24px 48px rgba(0,0,0,0.55);
  padding: 2.2rem 1.6rem 1.6rem;
  max-width: 520px;
  width: 100%;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  position: relative;
  transform: scale(0.97);
  transition: transform 0.28s ease;
}
.modal-overlay.open .modal-card { transform: scale(1); }

.modal-close {
  position: absolute;
  top: 0.4rem;
  right: 0.6rem;
  background: transparent;
  border: none;
  font-family: var(--font-typewriter);
  font-size: 1.6rem;
  line-height: 1;
  color: var(--ink-faint);
  cursor: pointer;
  padding: 0.3rem 0.5rem;
  transition: color 0.25s ease;
  z-index: 2;
}
.modal-close:hover,
.modal-close:focus-visible { color: var(--accent); outline: none; }

.modal-eyebrow {
  font-family: var(--font-typewriter);
  font-size: 0.6rem;
  letter-spacing: 4px;
  text-transform: lowercase;
  text-align: center;
  color: var(--accent);
  opacity: 0.8;
  margin-bottom: 0.3rem;
  flex-shrink: 0;
}
.modal-title {
  font-family: var(--font-typewriter);
  text-align: center;
  font-size: 1.1rem;
  letter-spacing: 3px;
  text-transform: lowercase;
  font-weight: normal;
  color: var(--ink);
  margin-bottom: 1rem;
  flex-shrink: 0;
}

/* ---------- contents modal ---------- */
.modal-scroll {
  overflow-y: auto;
  flex: 1 1 auto;
  min-height: 0;
  padding-right: 0.2rem;
  /* same soft fade as ed-scroll */
  mask-image: linear-gradient(to bottom, transparent 0, #000 14px, #000 calc(100% - 14px), transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 14px, #000 calc(100% - 14px), transparent 100%);
}
.modal-scroll::-webkit-scrollbar { width: 4px; }
.modal-scroll::-webkit-scrollbar-thumb {
  background: rgba(33, 28, 23, 0.22);
  border-radius: 999px;
}
.modal-toc-volume {
  text-align: center;
  margin: 1rem 0 0.6rem;
}
.modal-toc-volume:first-child { margin-top: 0; }
.modal-toc-roman {
  font-family: var(--font-typewriter);
  font-size: 0.65rem;
  letter-spacing: 4px;
  text-transform: lowercase;
  color: var(--accent);
}
.modal-toc-name {
  font-family: var(--font-typewriter);
  font-size: 0.65rem;
  letter-spacing: 2px;
  text-transform: lowercase;
  color: var(--ink-faint);
  margin-top: 0.15rem;
}
.modal-toc {
  list-style: none;
  margin: 0 0 0.4rem;
  padding: 0;
}
.modal-toc li { margin: 0; }
.modal-toc a {
  display: flex;
  align-items: baseline;
  gap: 0.8rem;
  padding: 0.45rem 0.4rem;
  font-family: var(--font-typewriter);
  font-size: 0.78rem;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px dotted var(--rule);
  transition: background 0.18s ease, color 0.18s ease;
}
.modal-toc a:hover,
.modal-toc a:focus-visible {
  background: rgba(122, 90, 44, 0.08);
  color: var(--accent);
  outline: none;
}
.modal-toc-num {
  flex-shrink: 0;
  font-size: 0.7rem;
  letter-spacing: 1px;
  color: var(--ink-faint);
  min-width: 2ch;
}
.modal-toc-title {
  flex: 1;
  text-align: left;
}

/* ---------- share modal ---------- */
.modal-card-share { max-width: 460px; }
.share-preview {
  width: 100%;
  aspect-ratio: 1 / 1;
  max-height: 38vh;
  background: rgba(33, 28, 23, 0.06);
  border: 1px solid var(--paper-edge);
  margin-bottom: 0.9rem;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  flex: 0 1 auto;
  min-height: 0;
}
.share-preview img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.share-preview-loading {
  font-family: var(--font-typewriter);
  font-size: 0.7rem;
  letter-spacing: 2px;
  text-transform: lowercase;
  color: var(--ink-faint);
}
.share-msg {
  font-family: var(--font-typewriter);
  font-size: 0.78rem;
  line-height: 1.55;
  color: var(--ink);
  text-align: center;
  margin: 0.2rem 0 0.9rem;
  padding: 0.5rem 0.6rem;
  background: rgba(33, 28, 23, 0.04);
  border-left: 2px solid var(--accent);
  border-radius: 1px;
  text-align: left;
}
.share-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem;
  margin-bottom: 0.7rem;
}
.share-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.45rem 0.85rem;
  font-family: var(--font-typewriter);
  font-size: 0.7rem;
  letter-spacing: 2px;
  text-transform: lowercase;
  color: var(--ink);
  background: rgba(243, 236, 224, 0.6);
  border: 1px solid var(--paper-edge);
  border-radius: 2px;
  text-decoration: none;
  transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
.share-link:hover,
.share-link:focus-visible {
  background: var(--accent);
  color: var(--dark-bg);
  border-color: var(--accent);
  outline: none;
}
.share-copy {
  width: 100%;
  background: var(--pen-ink);
  color: var(--paper);
  border: 1px solid var(--pen-ink);
  padding: 0.6rem 0.9rem;
  font-family: var(--font-typewriter);
  font-size: 0.72rem;
  letter-spacing: 2px;
  text-transform: lowercase;
  cursor: pointer;
  border-radius: 2px;
  transition: background 0.2s ease, color 0.2s ease;
}
.share-copy:hover,
.share-copy:focus-visible {
  background: var(--accent);
  color: var(--dark-bg);
  border-color: var(--accent);
  outline: none;
}
.share-copied {
  margin-top: 0.5rem;
  text-align: center;
  font-family: var(--font-typewriter);
  font-size: 0.65rem;
  letter-spacing: 2px;
  text-transform: lowercase;
  color: var(--accent);
  min-height: 1em;
}

/* mobile tightening */
@media (max-width: 520px) {
  .modal-card { padding: 1.8rem 1.1rem 1.2rem; }
  .modal-title { font-size: 1rem; }
  .modal-toc a { font-size: 0.74rem; padding: 0.4rem 0.3rem; gap: 0.6rem; }
  .share-preview { max-height: 32vh; }
  .share-msg { font-size: 0.74rem; }
}

/* ============================================================
   PAGE NAVIGATION — always visible, never hides the page
   ============================================================ */
.pager {
  position: fixed;
  bottom: 0;
  /* Constrain the pager to the same width as the book itself so the
     back/next buttons sit just under the page edges, not at the far
     extremes of the screen. The book is centred via #app, so we mirror
     that with left: 50% + translateX(-50%) and the same --page-w. */
  left: 50%;
  transform: translateX(-50%);
  width: var(--page-w);
  max-width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.7rem clamp(0.7rem, 3vw, 1.6rem);
  /* respect the home-indicator zone on iOS */
  padding-bottom: calc(0.7rem + env(safe-area-inset-bottom, 0px));
  z-index: 100;
  pointer-events: none;
}
.pager.hidden { display: none; }
.pager > * { pointer-events: auto; }

.pager-btn {
  font-family: var(--font-typewriter);
  background: rgba(243, 236, 224, 0.92);
  border: 1px solid rgba(0,0,0,0.35);
  color: var(--ink);
  padding: 0.5rem 0.9rem;
  font-size: 0.72rem;
  letter-spacing: 2px;
  text-transform: lowercase;
  cursor: pointer;
  text-decoration: none;
  border-radius: 2px;
  box-shadow: 0 2px 6px rgba(0,0,0,0.4);
  transition: background 0.25s ease, color 0.25s ease, border-color 0.25s ease, transform 0.15s ease;
  backdrop-filter: blur(2px);
}
.pager-btn:hover {
  background: var(--accent);
  color: var(--dark-bg);
  border-color: var(--accent);
  transform: translateY(-1px);
}
.pager-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
  box-shadow: none;
  background: rgba(243, 236, 224, 0.55);
}
/* the centre cluster: contents · home · share */
.pager-cluster {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.4rem;
  background: rgba(8,5,3,0.55);
  border-radius: 999px;
  backdrop-filter: blur(2px);
}
.pager-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.1rem;
  height: 2.1rem;
  padding: 0;
  border-radius: 999px;
  border: 1px solid rgba(231,221,202,0.28);
  background: rgba(243, 236, 224, 0.92);
  color: var(--ink);
  cursor: pointer;
  box-shadow: 0 2px 6px rgba(0,0,0,0.35);
  transition: background 0.22s ease, color 0.22s ease, border-color 0.22s ease, transform 0.15s ease;
}
.pager-icon-btn:hover,
.pager-icon-btn:focus-visible {
  background: var(--accent);
  color: var(--dark-bg);
  border-color: var(--accent);
  transform: translateY(-1px);
  outline: none;
}
.pager-icon-btn svg { display: block; }

/* Click on margins / empty space to turn the page.
   We do this in JS — see app.js — by listening on document and
   only firing the page-turn when the click was NOT on a button,
   link, or other interactive element. */

/* ---------- copyright modal — "a note from his" ---------- */
.modal-card-copyright {
  max-width: 460px;
  /* the popup feels like a page from the book itself */
  padding: 1.4rem 1.6rem 1.4rem;
}

/* ---------- how-to-read modal — "how to read this book" ----------
   The icon-row list is taller than the copyright body, so give the
   card a bit more height. Width matches copyright for visual rhythm
   across the modal family. */
.modal-card-howto {
  max-width: 460px;
  padding: 1.4rem 1.6rem 1.4rem;
}
.modal-card-howto .modal-scroll {
  /* Mask the scrollable list with a soft top/bottom fade so the
     edges don't visually clip the icon rows. */
  mask-image: linear-gradient(180deg, transparent 0, black 18px, black calc(100% - 18px), transparent 100%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0, black 18px, black calc(100% - 18px), transparent 100%);
}
.modal-card-howto .how-body {
  /* In modal context the body uses the modal's existing width
     constraints — no extra max-width needed. */
  max-width: 100%;
}
/* the wolf signature header — like the page header but inside the modal */
.copyright-mark {
  text-align: center;
  margin: 0.2rem 0 1.4rem; /* generous breathing space below before the title */
  flex-shrink: 0;
}
.copyright-wolf {
  width: 48px;
  height: auto;
  opacity: 0.9;
  display: block;
  margin: 0 auto 0.35rem;
}
.copyright-handle {
  font-family: var(--font-typewriter);
  font-size: 0.7rem;
  letter-spacing: 3px;
  color: var(--ink-faint);
  text-align: center;
}
.copyright-title {
  font-style: italic;
  font-size: 1.05rem;
  letter-spacing: 1.5px;
  line-height: 1.35;
  margin-bottom: 1.1rem;
  color: var(--ink);
  flex-shrink: 0;
}
/* override the shared .modal-scroll mask — the copyright body is short
   so the top fade just washes out the opening sentence (the most
   important sentence). bottom fade stays only if content overflows. */
.modal-card-copyright .modal-scroll {
  mask-image: none;
  -webkit-mask-image: none;
}
.copyright-body {
  font-family: var(--font-typewriter);
  /* match the threshold/poem text size for visual continuity with the book */
  font-size: clamp(0.78rem, 2vw, 0.9rem);
  line-height: 1.7;
  color: var(--ink);
  text-align: center;
}
.copyright-body p { margin: 0 0 0.85rem; }
.copyright-body p:last-child { margin-bottom: 0; }
.copyright-body strong { font-weight: bold; color: var(--ink); }
.copyright-body em { font-style: italic; }

/* faint horizontal rule between sections of the letter */
.copyright-soft-rule {
  height: 1px;
  margin: 1rem auto 1.1rem !important;
  background: linear-gradient(90deg, transparent 0%, var(--rule) 30%, var(--rule) 70%, transparent 100%);
  border: none;
  padding: 0;
}
.copyright-soft-rule::after { content: ""; display: block; }

.copyright-signature {
  margin-top: 1.2rem !important;
  text-align: center;
  /* The signature line itself is gone (the closing call IS the
     signature). Only the small © remains, sized via .copyright-sig-sub. */
  font-size: 0;
  line-height: 1;
}
.copyright-sig-sub {
  display: block;
  margin-top: 0.4rem;
  font-family: var(--font-typewriter);
  font-size: 0.62rem;
  letter-spacing: 2px;
  color: var(--ink-faint);
  text-transform: lowercase;
}

/* ============================================================
   COPYRIGHT PAGE — last page of the book. Same voice as the
   © modal, just laid out as a book page (not a card overlay).
   Reuses the modal's class names (.copyright-mark, .copyright-body,
   .copyright-soft-rule, .copyright-signature) so the two stay
   visually consistent — what differs is the page chrome around it.
   ============================================================ */
.copyright-page {
  /* shrink the inner column slightly so the rights statement reads
     like a letter, not a billboard. matches the modal feel. */
  max-width: 28rem;
  margin: 0 auto;
}
.copyright-page .fm-label {
  margin-bottom: 1.2rem;
}
/* on the page the wolf-mark sits below the "copyright" eyebrow and
   above the title — same vertical order as the modal */
.copyright-mark-page {
  margin: 0 auto 1.1rem;
}
.copyright-mark-page .copyright-wolf {
  width: 42px; /* slightly smaller than modal — the page has more headroom */
}
.copyright-page-title {
  font-family: var(--font-typewriter);
  font-style: italic;
  font-size: clamp(1rem, 3.4vw, 1.2rem);
  letter-spacing: 1.5px;
  line-height: 1.35;
  text-align: center;
  font-weight: normal;
  margin: 0 0 1.2rem;
  color: var(--ink);
}
.copyright-page .copyright-body {
  /* same typography as the modal body */
  text-align: center;
  max-width: 26rem;
  margin: 0 auto;
}
/* each prose block holds its own paragraph margins; the soft rule
   sits between blocks. */
.copyright-block p { margin: 0 0 0.7rem; }
.copyright-block p:last-child { margin-bottom: 0; }

/* ---------- unspoken modal — "your unspoken story" ---------- */
.modal-card-unspoken {
  max-width: 480px;
  padding: 1.4rem 1.6rem 1.4rem;
}
.unspoken-body {
  font-family: var(--font-typewriter);
  font-size: clamp(0.78rem, 2vw, 0.9rem);
  line-height: 1.65;
  color: var(--ink);
  text-align: center;
  /* contain scroll inside the body, not the modal-card */
  overflow-y: auto;
  flex: 1 1 auto;
  min-height: 0;
}
.unspoken-question {
  font-family: var(--font-typewriter);
  font-size: clamp(0.95rem, 2.6vw, 1.15rem);
  line-height: 1.5;
  color: var(--ink);
  margin: 0 0 0.6rem;
  font-style: italic;
}
.unspoken-subtitle {
  font-size: 0.78rem;
  color: var(--ink-soft);
  margin: 0 0 1.4rem;
  line-height: 1.55;
}
.unspoken-form {
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  transition: opacity 0.3s ease;
}
.unspoken-form.done {
  opacity: 0;
}
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.unspoken-text {
  width: 100%;
  font-family: var(--font-typewriter);
  font-size: clamp(0.82rem, 2vw, 0.92rem);
  line-height: 1.7;
  color: var(--ink);
  background: rgba(255, 252, 246, 0.7);
  border: 1px solid var(--paper-edge);
  border-radius: 2px;
  padding: 0.9rem 1rem;
  resize: vertical;
  min-height: 8rem;
  outline: none;
  transition: border-color 0.25s ease, background 0.25s ease;
  /* a faint paper-grain feel via box-shadow inset */
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.05);
}
.unspoken-text:focus {
  border-color: var(--accent);
  background: rgba(255, 252, 246, 1);
}
.unspoken-text::placeholder {
  color: var(--ink-faint);
  font-style: italic;
  opacity: 0.85;
}
.unspoken-counter {
  font-size: 0.62rem;
  letter-spacing: 1px;
  color: var(--ink-faint);
  text-align: right;
  margin-top: -0.2rem;
}
.unspoken-captcha {
  margin: 0.4rem auto 0.2rem;
  min-height: 65px; /* reserve room so layout doesn't jump when it loads */
}
.unspoken-actions {
  display: flex;
  justify-content: center;
  margin-top: 0.4rem;
}
.unspoken-submit {
  font-family: var(--font-typewriter);
  font-size: 0.82rem;
  letter-spacing: 3px;
  text-transform: lowercase;
  color: var(--ink);
  background: rgba(243, 236, 224, 0.6);
  border: 1px solid var(--ink);
  border-radius: 999px;
  padding: 0.7rem 1.8rem;
  cursor: pointer;
  transition: background 0.25s ease, color 0.25s ease, border-color 0.25s ease, letter-spacing 0.25s ease, opacity 0.25s ease;
}
.unspoken-submit:hover:not(:disabled),
.unspoken-submit:focus-visible:not(:disabled) {
  background: var(--accent);
  color: var(--paper);
  border-color: var(--accent);
  letter-spacing: 4px;
  outline: none;
}
.unspoken-submit:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.unspoken-status {
  text-align: center;
  font-size: 0.72rem;
  color: var(--ink-faint);
  font-style: italic;
  min-height: 1.2em;
  letter-spacing: 0.5px;
}
.unspoken-status.err {
  color: #8a3a2a;
}
/* the success state — single line + sub-line, in his voice */
.unspoken-held {
  text-align: center;
  font-family: var(--font-reflection);
  font-size: 1.8rem;
  color: var(--ink);
  margin: 1.6rem 0 0.4rem;
  letter-spacing: 0.5px;
  animation: heldFade 0.6s ease both;
}
.unspoken-held-sub {
  text-align: center;
  font-family: var(--font-typewriter);
  font-size: 0.78rem;
  line-height: 1.65;
  color: var(--ink-soft);
  max-width: 22rem;
  margin: 0 auto;
  animation: heldFade 0.6s ease 0.2s both;
}
@keyframes heldFade {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---------- respond modal — "respond to this poem" ---------- */
.modal-card-respond {
  max-width: 480px;
  padding: 1.4rem 1.6rem 1.4rem;
}
/* Eyebrow label above the poem title — "responding to" */
.respond-eyebrow {
  font-family: var(--font-typewriter);
  font-size: 0.6rem;
  letter-spacing: 4px;
  text-transform: lowercase;
  color: var(--ink-faint);
  text-align: center;
  margin-bottom: 0.3rem;
  flex-shrink: 0;
}
/* The poem title becomes the modal title — re-style for that context */
.respond-poem-title {
  font-style: italic;
  font-size: 1.15rem !important;
  letter-spacing: 1px !important;
  margin-bottom: 1rem !important;
  line-height: 1.35 !important;
}
.respond-body .unspoken-question {
  font-size: clamp(0.88rem, 2.3vw, 1.05rem);
}
/* Handle row — at + input + consent checkbox underneath */
.respond-handle-row {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0.4rem 0 0.2rem;
}
.respond-handle-label {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  background: rgba(255, 252, 246, 0.7);
  border: 1px solid var(--paper-edge);
  border-radius: 2px;
  padding: 0.5rem 0.8rem;
  transition: border-color 0.25s ease, background 0.25s ease;
}
.respond-handle-label:focus-within {
  border-color: var(--accent);
  background: rgba(255, 252, 246, 1);
}
.respond-at {
  font-family: var(--font-typewriter);
  font-size: 0.95rem;
  color: var(--ink-faint);
  user-select: none;
}
.respond-handle {
  flex: 1;
  font-family: var(--font-typewriter);
  font-size: clamp(0.82rem, 2vw, 0.92rem);
  color: var(--ink);
  background: transparent;
  border: none;
  outline: none;
  padding: 0;
  min-width: 0;
}
.respond-handle::placeholder {
  color: var(--ink-faint);
  font-style: italic;
  opacity: 0.85;
}
.respond-consent {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  font-family: var(--font-typewriter);
  font-size: 0.75rem;
  color: var(--ink-soft);
  line-height: 1.55;
  cursor: pointer;
  padding: 0.2rem 0;
  /* a touch of left-padding so the text aligns with the input box */
  padding-left: 0.2rem;
  transition: opacity 0.25s ease;
}
.respond-consent:has(input:disabled) {
  opacity: 0.5;
  cursor: not-allowed;
}
.respond-consent-cb {
  flex-shrink: 0;
  width: 1rem;
  height: 1rem;
  margin-top: 0.15rem;
  accent-color: var(--accent);
  cursor: pointer;
}
.respond-consent-cb:disabled { cursor: not-allowed; }
.respond-consent em { font-style: italic; }

/* ============================================================
   PAGE NUMBER — small "N / Total" indicator at bottom of every
   non-cover page. Sits centred near the bottom edge of the
   page area, above the foot/pager. Quiet, like a real book.
   ============================================================ */
.page-number {
  position: absolute;
  /* lifted well above the pager (which is ~64px tall, fixed at bottom 0).
     This sits the page number in the calm strip of paper between the last
     line of content and the navigation cluster — exactly where a printed
     book would put it. */
  bottom: 4.8rem;
  left: 0;
  right: 0;
  text-align: center;
  font-family: var(--font-typewriter);
  font-size: 0.55rem;
  letter-spacing: 3px;
  color: var(--ink-faint);
  opacity: 0.7;
  pointer-events: none;
  z-index: 2;
  user-select: none;
}
@media (max-width: 700px) {
  .page-number {
    /* on mobile the pager is slightly taller (touch targets) and the
       safe-area inset adds more bottom space, so we lift slightly higher */
    bottom: calc(5.2rem + env(safe-area-inset-bottom, 0px));
    font-size: 0.55rem;
  }
}

/* ============================================================
   HOW TO READ THIS BOOK — quiet guide page
   ============================================================ */
.how-body {
  font-family: var(--font-typewriter);
  font-size: clamp(0.78rem, 2vw, 0.88rem);
  line-height: 1.7;
  color: var(--ink);
  text-align: left;
  max-width: 26rem;
  margin: 0 auto;
}
.how-intro, .how-subintro, .how-outro, .how-final {
  margin: 0 0 1rem;
}
.how-subintro {
  text-align: center;
  color: var(--ink-soft);
  margin: 1.2rem 0 0.8rem;
}
.how-icons {
  list-style: none;
  padding: 0;
  margin: 0 0 1.2rem;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}
.how-row {
  display: flex;
  align-items: flex-start;
  gap: 0.85rem;
  padding: 0.2rem 0;
}
.how-icon {
  flex-shrink: 0;
  width: 1.9rem;
  height: 1.9rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  border: 1px solid var(--paper-edge);
  background: rgba(243, 236, 224, 0.5);
  color: var(--ink);
  margin-top: 0.05rem;
}
.how-icon svg { display: block; width: 14px; height: 14px; }
.how-text {
  display: flex;
  flex-direction: column;
  line-height: 1.45;
}
.how-label {
  font-weight: bold;
  color: var(--ink);
  margin-bottom: 0.1rem;
}
.how-desc {
  font-size: 0.75rem;
  color: var(--ink-soft);
}
.how-outro {
  text-align: center;
  color: var(--ink-soft);
  margin: 1.2rem 0 0.8rem;
  font-size: 0.78rem;
}
.how-final {
  text-align: center;
  color: var(--ink-faint);
  font-size: 0.78rem;
  margin-top: 0.6rem;
}

/* ---------- responsive ---------- */
@media (max-width: 700px) {
  :root {
    --page-w: 100vw;
    /* dvh tracks the *visible* viewport (excludes the mobile browser
       address bar) so the top of the page — and the wolf logo — is
       never pushed up behind the browser chrome. Fallback to vh first. */
    --page-h: 100vh;
    --page-h: 100dvh;
  }
  .view:not(.dark-view), .dark-view {
    border-radius: 0;
    box-shadow: none;
  }
  .view:not(.dark-view)::before, .view:not(.dark-view)::after { display: none; }

  /* Respect notches / status bars: push the whole page content down by
     the safe-area inset so the wolf header always clears the top. */
  .view .page-content { padding-top: calc(4.6rem + env(safe-area-inset-top, 0px)); }
  .wolf-header { top: calc(1.5rem + env(safe-area-inset-top, 0px)); }
}

@media (max-width: 520px) {
  .pager { padding: 0.5rem 0.6rem; }
  .pager-btn { padding: 0.4rem 0.6rem; font-size: 0.66rem; letter-spacing: 0.8px; }
  .pager-cluster { gap: 0.2rem; padding: 0.22rem 0.28rem; }
  .pager-icon-btn { width: 1.75rem; height: 1.75rem; }
  .pager-icon-btn svg { width: 13px; height: 13px; }
}
@media (max-width: 360px) {
  .pager { padding: 0.4rem 0.4rem; }
  .pager-btn { padding: 0.32rem 0.48rem; font-size: 0.6rem; letter-spacing: 0.4px; }
  .pager-cluster { gap: 0.15rem; padding: 0.18rem 0.22rem; }
  .pager-icon-btn { width: 1.55rem; height: 1.55rem; }
  .pager-icon-btn svg { width: 11px; height: 11px; }
}

/* one-time swipe hint */
.swipe-hint {
  position: fixed;
  left: 50%;
  bottom: 4rem;
  transform: translateX(-50%);
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.9rem;
  font-size: 0.68rem;
  letter-spacing: 2px;
  text-transform: lowercase;
  color: var(--dark-ink);
  background: rgba(8,5,3,0.78);
  border: 1px solid rgba(231,221,202,0.25);
  border-radius: 999px;
  pointer-events: none;
  opacity: 0;
  animation: hintInOut 4.2s ease forwards;
}
.swipe-hint .arrow { animation: nudge 1.1s ease-in-out infinite; }
@keyframes nudge { 50% { transform: translateX(-3px); } }
@keyframes hintInOut {
  0% { opacity: 0; }
  12% { opacity: 1; }
  78% { opacity: 1; }
  100% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .view.active { animation: none; }
  .swipe-hint { animation: hintInOut 4.2s linear forwards; }
  .swipe-hint .arrow { animation: none; }
}

/* ---------- print ---------- */
@media print {
  html, body { height: auto; overflow: visible !important; }
  body { background: #fff !important; display: block; }
  body::after, .pager, .swipe-hint, .click-zone, .page-grain, .dark-view::before { display: none !important; }
  #app { width: 100%; height: auto; display: block; }
  .view { display: block !important; position: relative !important; inset: auto !important; width: 100%; height: auto; page-break-after: always; box-shadow: none !important; border: none !important; background: #fff !important; padding: 2rem 1.5rem !important; }
  .view.active { animation: none; }
  .view:not(.dark-view)::before, .view:not(.dark-view)::after { display: none !important; }
  .page-content { overflow: visible !important; }
  .poem-body.typed .tl { opacity: 1 !important; }
  .pen-line { color: var(--pen-ink) !important; }
  .poem-title.pen-title { color: var(--this-pen-ink, var(--pen-ink)) !important; }
  .poem-note { color: #2c2418 !important; }
  .dark-view { background: #fff !important; color: var(--ink) !important; }
  .dark-view .ed-eyebrow, .dark-view .ed-body, .dark-view .cover-handle { color: var(--ink) !important; }
  .dark-view .ed-eyebrow em { color: var(--accent) !important; }
}
