/* ============================================================
   BOOK.os — spread.css
   Two-page spread geometry, layout variants, page-number cartouches,
   margin grid, illustration plates.
   Each .spread = one logical 2-page opening. Left/right pages live
   side-by-side onscreen; @page :left/:right splits them in print.
   ============================================================ */

/* ---------- Spread container ----------
   Spread fills the viewport with a thin gutter on all sides + decorative
   frame inside that gutter (cyan corner brackets at viewport corners,
   thin magenta hairline rule on all four sides). Reads as a poster
   framed inside the browser, not a card floating in dead space. */
.spread {
  display: grid;
  grid-template-columns: var(--page-w) var(--page-w);
  gap: 0;
  margin: 0;
  width: calc(var(--page-w) * 2);
  position: relative;
  /* Stacked shadows: close + tight under-the-book, then wider ambient cast */
  filter:
    drop-shadow(0 4px 8px rgba(0, 0, 0, 0.6))
    drop-shadow(0 18px 36px rgba(0, 0, 0, 0.5))
    drop-shadow(0 36px 80px rgba(0, 0, 0, 0.35));
  flex-shrink: 0;
}

/* Spacing between stacked spreads in the same file (used during dev
   when multiple spreads share a page). In production, one spread per file. */
.spread + .spread {
  margin-top: 36px;
}

/* INTERNAL DEV EDITION watermark — fixed top-center, present on every
   page including the closed-book landing. Unobtrusive, never blocks UI
   (pointer-events:none). Injected by book.js injectWatermark(). */
.book-watermark {
  /* Full-width attention-grabbing banner across the top of the viewport.
     Fox 2026-05-22: scaled up from a small top-left chip so it can't be
     missed. Sits ABOVE the chassis frame (z:1001 > chassis z:50) — the
     chassis corner brackets get slightly obscured but the warning-banner
     takes visual priority. */
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1001;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 6px 24px;
  font-family: 'Orbitron', 'Share Tech Mono', sans-serif;
  font-size: 13px;
  font-weight: 900;
  letter-spacing: 0.45em;
  color: rgba(255, 42, 109, 1);
  text-transform: uppercase;
  background: linear-gradient(90deg,
    rgba(20, 6, 14, 0.95) 0%,
    rgba(70, 14, 36, 0.95) 50%,
    rgba(20, 6, 14, 0.95) 100%);
  border-bottom: 1.5px solid rgba(255, 42, 109, 0.7);
  pointer-events: none;
  user-select: none;
  white-space: nowrap;
  overflow: hidden;
  text-shadow:
    0 0 12px rgba(255, 42, 109, 0.8),
    0 1px 2px rgba(0, 0, 0, 0.95);
  box-shadow:
    0 2px 14px rgba(255, 42, 109, 0.35),
    0 4px 8px rgba(0, 0, 0, 0.5);
  animation: watermarkPulse 2.5s ease-in-out infinite;
}

/* ---------- Copyright strip — top-center, above the book ----------
   Positioned below the toolbar (toolbar ends ~y:108 after the watermark
   banner pushed it down) and above the spread page rect (~y:140), so it
   reads as a header line on the book itself. Fox 2026-05-22. */
.book-copyright {
  position: fixed;
  top: 105px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 999;
  font-family: 'Share Tech Mono', monospace;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.22em;
  color: rgba(232, 232, 238, 0.78);
  text-transform: uppercase;
  pointer-events: none;
  user-select: none;
  white-space: nowrap;
  text-shadow:
    0 0 6px rgba(0, 0, 0, 0.85),
    0 1px 2px rgba(0, 0, 0, 0.75);
}

/* ---------- Access gate (live-web mode only) ----------
   When the page is served on a live host AND the visitor hasn't yet
   authenticated as a Signal Tech member, the book content is blurred
   + made non-interactive, and an overlay invites them to connect.
   The `data-naus-authed` attribute (set after a successful /auth/me)
   removes the blur + lets the book function normally. */
html[data-naus-live]:not([data-naus-authed]) body > section,
html[data-naus-live]:not([data-naus-authed]) .book-nav,
html[data-naus-live]:not([data-naus-authed]) .book-edit-toolbar,
html[data-naus-live]:not([data-naus-authed]) #closed-book-stage {
  filter: blur(14px) saturate(0.6);
  pointer-events: none !important;
  user-select: none;
}

.book-lock-overlay {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: radial-gradient(
    ellipse at center,
    rgba(10, 10, 18, 0.78) 0%,
    rgba(10, 10, 18, 0.92) 100%
  );
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  font-family: 'Share Tech Mono', monospace;
}

.book-lock-card {
  max-width: 540px;
  background: linear-gradient(180deg, rgba(20, 16, 31, 0.96), rgba(10, 8, 18, 0.96));
  border: 1.5px solid rgba(255, 42, 109, 0.55);
  border-radius: 6px;
  padding: 38px 36px 28px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  box-shadow:
    0 0 40px rgba(255, 42, 109, 0.25),
    0 12px 40px rgba(0, 0, 0, 0.75);
  text-align: center;
}

.book-lock-tag {
  font-family: 'Orbitron', sans-serif;
  font-size: 11px;
  letter-spacing: 0.32em;
  color: rgba(255, 42, 109, 0.85);
  text-transform: uppercase;
  font-weight: 800;
  text-shadow: 0 0 8px rgba(255, 42, 109, 0.5);
}

.book-lock-title {
  font-family: 'Orbitron', sans-serif;
  font-size: 28px;
  font-weight: 900;
  letter-spacing: 0.06em;
  color: var(--naus-yellow);
  text-shadow:
    2px 0 0 rgba(255, 42, 109, 0.5),
    -2px 0 0 rgba(5, 217, 232, 0.5),
    0 0 18px rgba(249, 240, 2, 0.4);
  margin: 2px 0 8px;
}

.book-lock-subtitle {
  font-family: 'Share Tech Mono', monospace;
  font-size: 14px;
  line-height: 1.65;
  color: rgba(232, 232, 238, 0.85);
  letter-spacing: 0.02em;
  max-width: 440px;
}

.book-lock-subtitle strong {
  color: var(--naus-cyan);
  font-weight: 700;
}

.book-lock-btn {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin-top: 12px;
  padding: 14px 28px;
  background: linear-gradient(180deg, #5865f2 0%, #4752c4 100%);
  border: 1.5px solid rgba(255, 255, 255, 0.18);
  color: #fff;
  font-family: 'Orbitron', sans-serif;
  font-size: 14px;
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  border-radius: 4px;
  transition: transform 0.12s, box-shadow 0.18s, background 0.18s;
  box-shadow:
    0 4px 14px rgba(88, 101, 242, 0.45),
    0 0 24px rgba(88, 101, 242, 0.25);
}

.book-lock-btn:hover {
  background: linear-gradient(180deg, #6975ff 0%, #5865f2 100%);
  box-shadow:
    0 6px 20px rgba(88, 101, 242, 0.6),
    0 0 32px rgba(88, 101, 242, 0.35);
  transform: translateY(-1px);
}

.book-lock-btn-glyph {
  font-size: 10px;
}

.book-lock-footer {
  margin-top: 18px;
  font-family: 'Share Tech Mono', monospace;
  font-size: 10px;
  color: rgba(232, 232, 238, 0.45);
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

/* ---------- Per-portrait copyright stamp ----------
   Lives in the bottom-right of every .illus-plate on portrait pages.
   z:6 places it above the breach SVG (z:5) so it stays readable.

   Hue-cycle animation (Fox 2026-05-22): the stamp shifts through the
   NAUS palette (cyan → yellow → magenta) so it's legible against any
   character-image background. Heavy black drop-shadow + a slim
   high-contrast text-stroke (via paint-order) guarantees the glyphs
   read against bright AND dark passages of the underlying art. */
.portrait-watermark {
  /* Pushed inward 30px from the page edges so it sits inside the breach
     frame's bottom-right corner rather than competing with the chassis
     corner bracket + page-num. Fox 2026-05-22 "placement matters". */
  position: absolute;
  bottom: 32px;
  right: 36px;
  z-index: 6;
  font-family: 'Orbitron', 'Share Tech Mono', monospace;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(5, 217, 232, 0.95);
  -webkit-text-stroke: 0.4px rgba(0, 0, 0, 0.7);
  paint-order: stroke fill;
  text-shadow:
    0 0 4px rgba(0, 0, 0, 0.95),
    0 0 10px rgba(0, 0, 0, 0.7),
    0 1px 2px rgba(0, 0, 0, 0.95);
  pointer-events: none;
  user-select: none;
  white-space: nowrap;
  animation: portraitWatermarkHue 7s linear infinite;
}

@keyframes portraitWatermarkHue {
  0%, 100% { color: rgba(5, 217, 232, 0.95); }   /* cyan */
  33%      { color: rgba(249, 240, 2, 0.95); }   /* yellow */
  66%      { color: rgba(255, 42, 109, 0.95); }  /* magenta */
}

/* On .is-og photograph plates the chrome aesthetic shifts — typewriter
   style on aged paper, no hue cycle (would break the analog register). */
.spread.v-portrait.is-og .portrait-watermark {
  font-family: 'Share Tech Mono', 'Spectral SC', serif;
  font-weight: 600;
  color: rgba(60, 40, 18, 0.7);
  -webkit-text-stroke: 0 transparent;
  text-shadow: 0 1px 1px rgba(255, 245, 220, 0.4);
  bottom: 22px;
  right: 26px;
  letter-spacing: 0.16em;
  animation: none;
}

@keyframes watermarkPulse {
  0%, 100% {
    box-shadow:
      0 2px 14px rgba(255, 42, 109, 0.35),
      0 4px 8px rgba(0, 0, 0, 0.5);
    border-bottom-color: rgba(255, 42, 109, 0.55);
  }
  50% {
    box-shadow:
      0 2px 28px rgba(255, 42, 109, 0.75),
      0 4px 8px rgba(0, 0, 0, 0.5);
    border-bottom-color: rgba(255, 42, 109, 0.95);
  }
}

/* Outer frame — drawn on body::before so it's always pinned to viewport */
body::before {
  content: "";
  position: fixed;
  inset: 20px;
  pointer-events: none;
  z-index: 50;
  border: 1px solid rgba(5, 217, 232, 0.22);
  box-shadow:
    inset 0 0 0 1px rgba(255, 42, 109, 0.06),
    inset 0 0 60px rgba(5, 217, 232, 0.04),
    inset 0 0 120px rgba(0, 0, 0, 0.4);
}

/* Corner brackets at the viewport edges — pinned, decorative, cyan accent */
body::after {
  content: "";
  position: fixed;
  inset: 12px;
  pointer-events: none;
  z-index: 51;
  background:
    /* top-left */
    linear-gradient(to right, var(--naus-cyan) 0, var(--naus-cyan) 30px, transparent 30px) top left / 30px 2px no-repeat,
    linear-gradient(to bottom, var(--naus-cyan) 0, var(--naus-cyan) 30px, transparent 30px) top left / 2px 30px no-repeat,
    /* top-right */
    linear-gradient(to left, var(--naus-cyan) 0, var(--naus-cyan) 30px, transparent 30px) top right / 30px 2px no-repeat,
    linear-gradient(to bottom, var(--naus-cyan) 0, var(--naus-cyan) 30px, transparent 30px) top right / 2px 30px no-repeat,
    /* bottom-left */
    linear-gradient(to right, var(--naus-cyan) 0, var(--naus-cyan) 30px, transparent 30px) bottom left / 30px 2px no-repeat,
    linear-gradient(to top, var(--naus-cyan) 0, var(--naus-cyan) 30px, transparent 30px) bottom left / 2px 30px no-repeat,
    /* bottom-right */
    linear-gradient(to left, var(--naus-cyan) 0, var(--naus-cyan) 30px, transparent 30px) bottom right / 30px 2px no-repeat,
    linear-gradient(to top, var(--naus-cyan) 0, var(--naus-cyan) 30px, transparent 30px) bottom right / 2px 30px no-repeat;
  filter: drop-shadow(0 0 6px rgba(5, 217, 232, 0.6));
}

/* ---------- Single page ----------
   v2 (2026-05-20): page baseline now mirrors the inside-cover plate
   aesthetic — deep dyed-cloth purple gradient + horizontal/vertical
   cloth weave + inner vignette. Replaces the prior medium-navy paper
   with cyan grain (read as flat / too-bright). Per Fox: "regular pages
   should be darker and nicer like the inside cover."
   Anchor: feedback_book_guide_myst_register.md */
.page {
  width: var(--page-w);
  height: var(--page-h);
  background-color: #14091F;  /* deep bookplate-purple base */
  position: relative;
  overflow: hidden;
  /* Cloth weave (horizontal white + vertical black thin stripes) +
     warm purple radial vignette — matches .spread.v-cover .page--left.
     Layered bottom-to-top: radial gradient, vertical weave, horizontal
     weave. Page-specific gradients (spine valley, outer highlight) are
     LAYERED ON TOP via .page--left / .page--right below — they DO NOT
     replace this baseline. */
  background-image:
    repeating-linear-gradient(
      90deg,
      transparent 0,
      transparent 2px,
      rgba(255, 255, 255, 0.022) 2px,
      rgba(255, 255, 255, 0.022) 3px
    ),
    repeating-linear-gradient(
      0deg,
      transparent 0,
      transparent 2px,
      rgba(0, 0, 0, 0.16) 2px,
      rgba(0, 0, 0, 0.16) 3px
    ),
    radial-gradient(
      ellipse at 50% 35%,
      #220F32 0%,
      #14091F 58%,
      #0A0413 100%
    );
  /* Inner vignette — sells the bookplate-as-physical-artifact feel. */
  box-shadow: inset 0 0 90px rgba(0, 0, 0, 0.5);
}

/* Spine shadow — gutter darkening on inner edges of both pages.
   The "valley" effect: pages dip slightly toward the binding, simulating
   the physical curve of paper held by a spine. Stacked on TOP of the
   .page baseline cloth-weave + vignette — box-shadow combines the
   vignette + spine-valley in one declaration since CSS doesn't merge
   box-shadow across rules. */
.page--left {
  padding: var(--page-pad) var(--page-pad-inner) var(--page-pad) 180px;
  border-right: var(--rule-heavy) solid #050508;
  box-shadow:
    inset 0 0 90px rgba(0, 0, 0, 0.5),       /* baseline vignette */
    inset -18px 0 32px rgba(0, 0, 0, 0.5);   /* spine valley (right edge) */
}

.page--right {
  padding: var(--page-pad) 180px var(--page-pad) var(--page-pad-inner);
  box-shadow:
    inset 0 0 90px rgba(0, 0, 0, 0.5),       /* baseline vignette */
    inset 18px 0 32px rgba(0, 0, 0, 0.5);    /* spine valley (left edge) */
}

/* Spine seam — a 1px dark central line where the two pages meet,
   suggesting the actual binding fold. Drawn via spread::after. */
.spread::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 2px;
  transform: translateX(-50%);
  background: linear-gradient(
    to bottom,
    transparent 0%,
    rgba(0, 0, 0, 0.5) 8%,
    rgba(0, 0, 0, 0.7) 50%,
    rgba(0, 0, 0, 0.5) 92%,
    transparent 100%
  );
  pointer-events: none;
  z-index: 4;
  box-shadow:
    -1px 0 3px rgba(0, 0, 0, 0.4),
    1px 0 3px rgba(0, 0, 0, 0.4);
}

/* ---------- Page-number cartouche ---------- */
.page-num {
  position: absolute;
  bottom: 16px;
  font-family: 'Share Tech Mono', 'Spectral SC', serif;
  font-size: var(--fs-pagenum);
  letter-spacing: 0.18em;
  color: var(--ink-faint);
  display: inline-flex;
  align-items: center;
  gap: 0;
}

.page--left .page-num {
  left: var(--page-pad);
}

.page--right .page-num {
  right: var(--page-pad);
}

.page-num::before,
.page-num::after {
  content: "·";
  margin: 0 var(--sp-2);
  color: var(--char-accent, var(--naus-cyan));
  text-shadow: 0 0 4px rgba(5, 217, 232, 0.45);
  font-size: 1.4em;
  line-height: 0;
}

/* Running-head — book title in tiny caps in upper outer corner */
.run-head {
  position: absolute;
  top: 18px;
  font-family: 'Share Tech Mono', 'Spectral SC', serif;
  font-size: 9.5px;
  letter-spacing: 0.22em;
  color: var(--ink-faint);
  text-transform: uppercase;
  padding: 2px 8px;
  border: 1px solid rgba(92, 95, 122, 0.25);
  border-radius: 1px;
  background: rgba(27, 31, 56, 0.6);
}

.page--left .run-head {
  left: var(--page-pad);
}

.page--right .run-head {
  right: var(--page-pad);
}

/* ---------- Spread inner content area ----------
   The bottom margin reserves space for the page-num cartouche only
   (bottom: 16px + glyph height + a bit of breathing). Per-page lexicon
   footers were removed 2026-05-18 in the Index & Glossary consolidation;
   tooltips on .lex spans now carry the canonical short gloss and click
   routes to the back-of-book glossary entry. */
.page-body {
  margin-top: var(--sp-5);
  margin-bottom: 44px;
  position: relative;
  height: calc(100% - var(--sp-5) - 44px);
  display: flex;
  flex-direction: column;
  /* Hard containment — content overflowing the body box must clip here,
     not just at the outer .page boundary. Defense-in-depth (Fox 2026-05-21
     "make sure overflow CANNOT HAPPEN"). The .page-overflowing class +
     red banner overlay (book.js detector) makes any clip impossible to miss. */
  overflow: hidden;
}

/* =================================================================
   LAYOUT VARIANTS — 6 alternate spread compositions.
   Apply to .spread root as a modifier class. Each rearranges
   the left-page illustration + right-page text relationship.
   Rotation guidance (rotate across roster to prevent visual fatigue):
     v-portrait    — classic full-bleed illustration left, prose right
     v-cartouche   — inset illustration in ornate frame, prose wraps
     v-medallion   — circular illustration medallion, data plate above/below
     v-torn        — torn-edge illustration plate, raw-cut feel (daemons/glitch)
     v-triptych    — three-panel character study (turnaround sheets, expression sets)
     v-data-heavy  — small illustration, dominant data plates (mechanical entries)
   ================================================================= */

/* === v-portrait — "inside the screen, broken into" ===
   v4 doctrine (2026-05-20, per Fox locked direction 2026-05-19 end-of-session):
   the character is INSIDE a screen (the source images already carry a
   neon-bezel double-rectangle that IS the screen edge). Something has
   BROKEN THROUGH the glass from outside — visible as fracture lines +
   wireframe-filled shards + corruption blips overlaying the screen face.
   The character display is UNTOUCHED — no clip-path, no displacement,
   no filter. The breakage is purely an OVERLAY (.illus-plate__breach,
   injected by book.js#injectPortraitBreach).

   Stacking inside .illus-plate:
     z:0 — dark void backdrop + dialed-down wireframe grid (off-screen)
     z:3 — the actual <img> or .illus-placeholder (the screen display)
     z:4 — ::after scanlines (CRT register on top of the image)
     z:5 — .illus-plate__breach SVG (cracks + shards + blips)

   Three prior attempts (2026-05-19) that did NOT work:
     1. Dashed cyan/magenta perimeter border — read as "white"
     2. feTurbulence + feDisplacementMap on the image — distorted character
     3. clip-path torn polygon + cyan tear-stroke — read as "polaroid taped on"
   Don't re-introduce any of them.
*/

/* NUKE ALL WHITE on v-portrait portrait page (Fox's eleven-times request).
   Paper-grain stripes, cyan page-corner brackets, gray-blue run-head text,
   body bg leaks all forced dark / hidden.

   2026-05-21: extended to also match `.page--portrait` modifier so
   portrait pages on the RIGHT side of a spread (chapter-opener pattern)
   get the same treatment. Left and right portrait pages share the
   breach-screen register; only their spread position differs. */
.spread.v-portrait .page--left,
.spread.v-portrait .page--portrait {
  padding: 0 !important;
  background: #050308 !important;
  background-image: none !important;
  background-color: #050308 !important;
  box-shadow: none !important;
}

.spread.v-portrait .page--left .page-corner,
.spread.v-portrait .page--left .run-head,
.spread.v-portrait .page--left .bleeker-stamp,
.spread.v-portrait .page--portrait .page-corner,
.spread.v-portrait .page--portrait .run-head,
.spread.v-portrait .page--portrait .bleeker-stamp {
  display: none !important;
}

.spread.v-portrait .page--left .page-num,
.spread.v-portrait .page--portrait .page-num {
  background: transparent !important;
  color: rgba(120, 125, 145, 0.4) !important;
}

.spread.v-portrait .illus-plate {
  width: 100%;
  height: 100%;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #050308;
  /* Off-screen void backdrop — dialed DOWN from prior 0.11 cyan / 0.06
     magenta because the wireframe is now CONTENT inside the shards
     (where it has to read at full intensity). The backdrop is just a
     hint that something is behind the screen. */
  background-image:
    linear-gradient(90deg, rgba(5, 217, 232, 0.05) 1px, transparent 1px),
    linear-gradient(rgba(5, 217, 232, 0.05) 1px, transparent 1px);
  background-size: 32px 32px, 32px 32px;
  overflow: hidden;
}

/* Subtle CRT scanline overlay on the screen face. Sits z 4, above the
   image but below the breach overlay. */
.spread.v-portrait .illus-plate::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(
    0deg,
    transparent 0,
    transparent 2px,
    rgba(0, 0, 0, 0.08) 3px,
    transparent 4px
  );
  pointer-events: none;
  z-index: 4;
}

.spread.v-portrait .illus-plate img,
.spread.v-portrait .illus-plate .illus-placeholder {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center center;
  position: relative;
  z-index: 3;
  /* NO clip-path. NO filter. NO transform. The display is clean —
     the breakage lives in .illus-plate__breach on top. */
}

/* ===== The breach overlay — cracks + shards + blips =====
   Injected by book.js#injectPortraitBreach. Sits on top of the image
   and scanlines. Pointer-events:none so it never blocks UI.

   v4-pass-3 (2026-05-20): the parent-level chromatic-aberration filter
   was washing out the fracture lines (a 0.6px dual offset on a 1.4px
   line dilutes the cyan center). Per-group filters now:
     • Shards get a soft inner glow only (no chromatic offset)
     • Fractures get a CRISP cyan core + tight 0.3px magenta companion
       ghost, so the lines READ as the dominant element
     • Blips have their own radial gradients (no additional filter needed) */
.spread.v-portrait .illus-plate__breach {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 5;
  pointer-events: none;
}

/* Shards — bottom group inside breach. Wireframe pattern is the fill
   (defined in book.js#injectBreachDefs). Soft inner glow only — the
   shards are the CONTENT visible through the cracks, not the cracks
   themselves. They should support the line read, not compete. */
.spread.v-portrait .breach-shards {
  filter: drop-shadow(0 0 3px rgba(5, 217, 232, 0.45));
}

/* Fracture lines — the DOMINANT visual element. Crisp cyan stroke with
   a tight magenta companion ghost for digital-fracture chromatic
   register, plus a soft cyan halo. The 0.3px offset is small enough
   that the line center stays solid cyan. */
.spread.v-portrait .breach-fractures {
  filter:
    drop-shadow(0.3px 0 0 rgba(255, 42, 109, 0.7))
    drop-shadow(0 0 4px rgba(5, 217, 232, 0.6))
    drop-shadow(0 0 10px rgba(5, 217, 232, 0.25));
}

/* Blips — radial-gradient dots flicker on their own. Subtle extra glow. */
.spread.v-portrait .breach-blips {
  filter: drop-shadow(0 0 6px rgba(5, 217, 232, 0.5));
}

/* Margin notes + page-num sit ABOVE the breach overlay — they're book
   chrome (annotations on the artifact), not part of the screen content.
   Without this, breach shards visibly cover the Bleeker margin note
   border + the page-num corner. */
.spread.v-portrait .page--left .margin-note,
.spread.v-portrait .page--left .page-num,
.spread.v-portrait .page--right .margin-note,
.spread.v-portrait .page--right .page-num,
.spread.v-portrait .page--portrait .margin-note,
.spread.v-portrait .page--portrait .page-num {
  z-index: 8;
}

/* V-portrait margin-notes use a FULLY opaque bg so breach shards underneath
   don't bleed visible wireframe pattern through the note (the prior 0.95
   alpha was letting the bright wireframe leak into the text region). */
.spread.v-portrait .margin-note {
  background: #1B1F38;
}

/* Page-corner brackets on v-portrait RIGHT page — dial opacity down so
   the cyan/magenta UI brackets don't compete with the bookplate-purple
   page bg. The breach treatment is the digital register on this spread;
   chrome brackets are still useful for orientation but shouldn't shout. */
.spread.v-portrait .page--right .page-corner {
  opacity: 0.4;
}

/* ===== Cross-spread breach echo =====
   Tiny breach overlay on v-portrait right page — extends the breach
   across the spread spine. Anchored upper-left so it reads as the
   crack network continuing across the gutter from the character image. */
.spread.v-portrait .page--right .breach-echo {
  position: absolute;
  top: 24px;
  left: 0;
  width: 130px;
  height: 130px;
  pointer-events: none;
  z-index: 2;
  filter: drop-shadow(0 0 4px rgba(5, 217, 232, 0.4));
}

/* ===== Title flourish — aged-gold three-diamond ornament under the H1+subtitle.
   Sets the title group "in metal" — antique catalog card register. ===== */
.title-flourish {
  font-family: 'Spectral SC', serif;
  font-size: 14px;
  letter-spacing: 0.6em;
  color: rgba(242, 216, 115, 0.7);
  text-shadow: 0 0 6px rgba(242, 216, 115, 0.3);
  margin: var(--sp-2) 0 var(--sp-4) 0;
  text-align: left;
  padding-right: 0.6em; /* compensate for trailing letter-spacing */
}

/* ===== Data-plate corner ticks — antique catalog card register =====
   Four small aged-gold L-marks at the inner corners of the data plate.
   Activated by .data-plate--cataloged modifier so we don't blanket-change
   every data plate in the book. */
.data-plate--cataloged {
  position: relative;
}

.dp-tick {
  position: absolute;
  width: 14px;
  height: 14px;
  pointer-events: none;
}
.dp-tick--tl { top: 6px;    left: 6px;    border-top: 1px solid rgba(242, 216, 115, 0.55); border-left: 1px solid rgba(242, 216, 115, 0.55); }
.dp-tick--tr { top: 6px;    right: 6px;   border-top: 1px solid rgba(242, 216, 115, 0.55); border-right: 1px solid rgba(242, 216, 115, 0.55); }
.dp-tick--bl { bottom: 6px; left: 6px;    border-bottom: 1px solid rgba(242, 216, 115, 0.55); border-left: 1px solid rgba(242, 216, 115, 0.55); }
.dp-tick--br { bottom: 6px; right: 6px;   border-bottom: 1px solid rgba(242, 216, 115, 0.55); border-right: 1px solid rgba(242, 216, 115, 0.55); }

/* ===== Run-head fleuron separator =====
   Replaces the prior `·` middot with a small aged-gold diamond in the
   run-head, matching the bookplate ornament vocabulary. */
.run-head__sep {
  display: inline-block;
  margin: 0 0.5em;
  color: rgba(242, 216, 115, 0.7);
  text-shadow: 0 0 4px rgba(242, 216, 115, 0.3);
  font-size: 0.92em;
  vertical-align: 0.05em;
}

/* ===== Order of Roles — concentric-ring diagram =====
   Visualizes the four roles (Witness · Anchor · Guardian · Weapon) as
   nested rings with the Crash sigil at center. Labels at compass points.
   Aged-gold strokes match the bookplate register. Compact (~210px square)
   so it fits in the page footer area without crowding the pull-quote. */
.order-of-roles {
  position: relative;
  width: 210px;
  height: 240px;
  margin: var(--sp-5) auto var(--sp-3) auto;
  display: block;
}

.order-diagram {
  width: 210px;
  height: 210px;
  display: block;
  margin: 0 auto;
  filter: drop-shadow(0 0 8px rgba(242, 216, 115, 0.18));
}

/* Compass labels — Spectral SC tracked-out caps in aged gold. Positioned
   absolute relative to .order-of-roles so they sit at the ring edges. */
.order-label {
  position: absolute;
  font-family: 'Spectral SC', serif;
  font-size: 10px;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: rgba(242, 216, 115, 0.75);
  text-shadow: 0 0 4px rgba(242, 216, 115, 0.25);
  white-space: nowrap;
}
.order-label--n { top: 0;          left: 50%; transform: translateX(-50%); }
.order-label--e { top: 50%;        right: -28px; transform: translateY(-50%) rotate(90deg); transform-origin: center; }
.order-label--s { bottom: 30px;    left: 50%; transform: translateX(-50%); }
.order-label--w { top: 50%;        left: -28px; transform: translateY(-50%) rotate(-90deg); transform-origin: center; }

.order-caption {
  display: block;
  text-align: center;
  font-family: 'Crimson Pro', serif;
  font-style: italic;
  font-size: 12px;
  letter-spacing: 0.08em;
  color: rgba(232, 232, 238, 0.55);
  margin-top: var(--sp-2);
}

/* Corruption blips — animated opacity flicker. Each blip gets a slightly
   different cycle so they don't all pulse in unison. */
.spread.v-portrait .breach-blips circle {
  animation: breachBlipFlicker 2.6s ease-in-out infinite;
  transform-origin: center;
}
.spread.v-portrait .breach-blips circle:nth-child(2) { animation-delay: -0.7s; animation-duration: 3.1s; }
.spread.v-portrait .breach-blips circle:nth-child(3) { animation-delay: -1.3s; animation-duration: 2.3s; }
.spread.v-portrait .breach-blips circle:nth-child(4) { animation-delay: -1.9s; animation-duration: 3.4s; }
.spread.v-portrait .breach-blips circle:nth-child(5) { animation-delay: -0.4s; animation-duration: 2.8s; }
.spread.v-portrait .breach-blips circle:nth-child(6) { animation-delay: -2.1s; animation-duration: 3.6s; }
.spread.v-portrait .breach-blips circle:nth-child(7) { animation-delay: -1.1s; animation-duration: 2.9s; }

@keyframes breachBlipFlicker {
  0%, 100% { opacity: 0.45; }
  20%      { opacity: 1.0;  }
  35%      { opacity: 0.55; }
  60%      { opacity: 0.9;  }
  80%      { opacity: 0.4;  }
}

/* Caption on v-portrait — Fox 2026-05-20 lock: REMOVED from v-portrait
   left pages. The right-page CRASH header already names the character;
   the caption was redundant + was reading as the brightest "white" block
   on the spread. Hidden on v-portrait only — other spread variants can
   still use it. */
.spread.v-portrait .illus-caption {
  display: none !important;
}

/* ===== IRL / OG character spreads — photograph register (2026-05-20) =====
   Carter, Trent: alive in IRL, not Framed Impressions inside the OS.
   The screen-frame + breach treatment doesn't fit canon for them — they
   never went through the Frame architecture. Instead, their portrait
   is a PHOTOGRAPH mounted on the bookplate page: drop shadow, slight
   tilt, aged-paper print margin, sepia tint. No breach, no scanlines,
   no wireframe void. The book is keeping their image because the OS
   can't render them — Bleeker is the one who taped them in. */

/* Restore the page--left bookplate baseline (override the v-portrait
   "nuke all white" rules that force the page into screen-void mode). */
.spread.v-portrait.is-og .page--left {
  padding: var(--page-pad) var(--page-pad-inner) var(--page-pad) 180px !important;
  background: transparent !important; /* falls back to .page baseline */
  background-image: none !important;
  background-color: transparent !important;
  box-shadow:
    inset 0 0 90px rgba(0, 0, 0, 0.5),
    inset -18px 0 32px rgba(0, 0, 0, 0.5) !important;
  display: block !important; /* not flex — photograph positions itself */
}

/* Restore page chrome that v-portrait hides on the left page */
.spread.v-portrait.is-og .page--left .page-corner,
.spread.v-portrait.is-og .page--left .run-head,
.spread.v-portrait.is-og .page--left .bleeker-stamp {
  display: block !important;
}
.spread.v-portrait.is-og .page--left .page-num {
  background: initial !important;
  color: var(--ink-faint) !important;
}

/* The illus-plate becomes the PHOTOGRAPH — mounted on the bookplate page,
   aged-paper print margin, drop shadow, slight tilt. */
.spread.v-portrait.is-og .illus-plate {
  width: auto !important;
  height: auto !important;
  max-width: calc(100% - 32px);
  max-height: calc(100% - 100px);
  margin: 40px auto !important;
  background: #efe2c4 !important; /* aged photo paper */
  background-color: #efe2c4 !important;
  background-image: none !important;
  padding: 18px 18px 58px 18px !important;
  display: block !important;
  position: relative !important;
  /* 2026-05-20: tilt removed per Fox — drop shadow + corner mounts + aged-
     paper margin + sepia tint do the photograph-on-the-page work on their
     own; the rotation read as "scrapbook cute" rather than "archival." */
  box-shadow:
    0 3px 6px rgba(0, 0, 0, 0.5),
    0 14px 36px rgba(0, 0, 0, 0.55),
    0 28px 80px rgba(0, 0, 0, 0.35);
  border-radius: 1px;
  overflow: visible !important;
}

/* The character image is now THE PHOTOGRAPH content */
.spread.v-portrait.is-og .illus-plate img {
  width: 100% !important;
  height: auto !important;
  max-height: 100% !important;
  display: block !important;
  position: relative !important;
  z-index: auto !important;
  object-fit: contain !important;
  filter: contrast(1.03) saturate(0.94) sepia(0.06) !important;
}

/* No breach, no scanlines on IRL spreads — these are photographs, not
   broken screens. The .illus-plate__breach SVG is also gated in
   book.js#injectPortraitBreach via :not(.is-og), but defense-in-depth. */
.spread.v-portrait.is-og .illus-plate__breach,
.spread.v-portrait.is-og .illus-plate::after,
.spread.v-portrait.is-og .illus-plate::before {
  display: none !important;
}

/* Caption: typewritten/printed label below the photograph,
   like a handwritten/typed annotation under an album photo. */
.spread.v-portrait.is-og .illus-caption {
  display: block !important;
  position: absolute !important;
  bottom: 12px !important;
  left: 18px !important;
  right: 18px !important;
  background: transparent !important;
  border: none !important;
  padding: 0 !important;
  font-family: 'Share Tech Mono', 'Spectral SC', serif !important;
  font-size: 10.5px !important;
  letter-spacing: 0.18em !important;
  text-transform: uppercase !important;
  color: #5a3814 !important;
  text-align: center !important;
}

.spread.v-portrait.is-og .illus-caption .tag {
  background: transparent !important;
  border: 1px solid rgba(90, 56, 20, 0.7) !important;
  color: #5a3814 !important;
  padding: 1px 5px !important;
  margin-right: 4px !important;
  text-shadow: none !important;
  box-shadow: none !important;
}

/* Photo corners — four gold L-mounts at the photograph's corners,
   like old album-photo holders. Built via background-image with four
   inline SVG triangular corners, one per corner of the plate. */
.spread.v-portrait.is-og .illus-plate {
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><path d='M 0 0 L 32 0 L 32 7 L 7 7 L 7 32 L 0 32 Z' fill='%237a5a2a' fill-opacity='0.85'/><path d='M 2 2 L 30 2 L 30 5 L 5 5 L 5 30 L 2 30 Z' fill='%23a07c3a' fill-opacity='0.6'/></svg>"),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><path d='M 32 0 L 0 0 L 0 7 L 25 7 L 25 32 L 32 32 Z' fill='%237a5a2a' fill-opacity='0.85'/><path d='M 30 2 L 2 2 L 2 5 L 27 5 L 27 30 L 30 30 Z' fill='%23a07c3a' fill-opacity='0.6'/></svg>"),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><path d='M 0 32 L 32 32 L 32 25 L 7 25 L 7 0 L 0 0 Z' fill='%237a5a2a' fill-opacity='0.85'/><path d='M 2 30 L 30 30 L 30 27 L 5 27 L 5 2 L 2 2 Z' fill='%23a07c3a' fill-opacity='0.6'/></svg>"),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><path d='M 32 32 L 0 32 L 0 25 L 25 25 L 25 0 L 32 0 Z' fill='%237a5a2a' fill-opacity='0.85'/><path d='M 30 30 L 2 30 L 2 27 L 27 27 L 27 2 L 30 2 Z' fill='%23a07c3a' fill-opacity='0.6'/></svg>") !important;
  background-position: top left, top right, bottom left, bottom right !important;
  background-size: 32px 32px !important;
  background-repeat: no-repeat !important;
  background-color: #efe2c4 !important;
}

/* === Character half-and-half panels ===
   Used on character spread right pages when LEFT is the full-body
   v-portrait. Stacks two panels vertically, each with an image strip on
   the left + a blurb on the right. Lets a character spread carry a
   full-body portrait + two reference images + IRL blurbs in one
   spread without the page reading like a placeholder. */
.char-half {
  display: grid;
  grid-template-columns: 220px 1fr;
  gap: 18px;
  margin-bottom: var(--sp-5);
  align-items: start;
}

.char-half + .char-half {
  margin-top: var(--sp-4);
  padding-top: var(--sp-4);
  border-top: 1px dashed rgba(5, 217, 232, 0.18);
}

.char-half__illus {
  width: 220px;
  aspect-ratio: 3 / 4;
  background: var(--char-primary, var(--ink));
  border: 1px solid rgba(5, 217, 232, 0.22);
  overflow: hidden;
  position: relative;
  box-shadow:
    inset 0 0 0 1px rgba(255, 42, 109, 0.05),
    inset 0 0 24px rgba(0, 0, 0, 0.5);
}

.char-half__illus img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center center;
}

.char-half__blurb {
  font-family: 'Crimson Pro', serif;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink);
}

.char-half__heading {
  font-family: 'Orbitron', 'Spectral SC', sans-serif;
  font-size: 14px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--naus-magenta);
  margin: 0 0 8px;
  padding-bottom: 4px;
  border-bottom: 1px solid rgba(255, 42, 109, 0.4);
  text-shadow: 0 0 6px rgba(255, 42, 109, 0.3);
}

.char-half__blurb p {
  margin: 0 0 8px;
}

.char-half__blurb p:last-child {
  margin-bottom: 0;
}

/* === v-cartouche — inset illustration in ornate frame, prose wraps === */
.spread.v-cartouche .illus-plate {
  width: 90%;
  margin: 0 auto var(--sp-5);
  aspect-ratio: 3 / 4;
  background: var(--char-primary, var(--ink));
  border: var(--rule-heavy) double var(--char-primary, var(--ink));
  padding: var(--sp-2);
  position: relative;
}

.spread.v-cartouche .illus-plate::before,
.spread.v-cartouche .illus-plate::after {
  content: "";
  position: absolute;
  width: 24px;
  height: 24px;
  border: var(--rule-heavy) solid var(--char-accent, var(--naus-cyan));
}

.spread.v-cartouche .illus-plate::before {
  top: -8px;
  left: -8px;
  border-right: none;
  border-bottom: none;
}

.spread.v-cartouche .illus-plate::after {
  bottom: -8px;
  right: -8px;
  border-left: none;
  border-top: none;
}

.spread.v-cartouche .illus-plate img,
.spread.v-cartouche .illus-plate .illus-placeholder {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* === v-medallion — circular illustration, data plates around it === */
.spread.v-medallion .illus-plate {
  width: 380px;
  height: 380px;
  margin: var(--sp-4) auto var(--sp-5);
  border-radius: 50%;
  overflow: hidden;
  border: var(--rule-heavy) solid var(--char-primary, var(--ink));
  box-shadow:
    0 0 0 4px var(--paper),
    0 0 0 6px var(--char-accent, var(--naus-cyan)),
    0 0 0 10px var(--paper),
    0 0 0 12px var(--char-primary, var(--ink));
  background: var(--char-primary, var(--ink));
}

.spread.v-medallion .illus-plate img,
.spread.v-medallion .illus-plate .illus-placeholder {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* === v-torn — torn-edge plate (daemons, glitched entries) === */
.spread.v-torn .illus-plate {
  width: 100%;
  height: 70%;
  background: var(--char-primary, var(--ink));
  position: relative;
  clip-path: polygon(
    0% 0%, 100% 0%, 100% 92%,
    95% 95%, 88% 91%, 79% 96%, 70% 92%,
    61% 97%, 52% 93%, 44% 96%, 35% 92%,
    26% 95%, 17% 91%, 8% 96%, 0% 93%
  );
  filter: drop-shadow(0 4px 8px rgba(0,0,0,0.4));
}

.spread.v-torn .illus-plate img,
.spread.v-torn .illus-plate .illus-placeholder {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* === v-triptych — three-panel layout (turnarounds, expression sheets) === */
.spread.v-triptych .illus-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-2);
}

.spread.v-triptych .illus-grid .illus-cell {
  aspect-ratio: 3 / 4;
  background: var(--char-primary, var(--ink));
  border: var(--rule-base) solid var(--ink);
  overflow: hidden;
}

.spread.v-triptych .illus-grid .illus-cell img,
.spread.v-triptych .illus-grid .illus-cell .illus-placeholder {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.spread.v-triptych .illus-label {
  text-align: center;
  font-family: 'Space Grotesk', sans-serif;
  font-size: 9px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-top: var(--sp-1);
}

/* === v-field-guide — Dragonology/Froud/DK collage register ===
   Hero illustration + multiple inset cards distributed around the page,
   slightly rotated for the "pinned to a corkboard" feel. Tape strips,
   pins, stamps, handwritten diary entries, anatomy callouts as needed.
   Used for fauna, flora, items, specimen-style entries. */
.spread.v-field-guide .page-body {
  position: relative;
  height: 100%;
  margin: 0;
  padding: 0;
}

.spread.v-field-guide .field-canvas {
  position: relative;
  width: 100%;
  height: 100%;
  /* The canvas is the absolute-positioning frame for all inset cards */
}

.spread.v-field-guide .hero-illus {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1;
}

.spread.v-field-guide .hero-illus img,
.spread.v-field-guide .hero-illus .illus-placeholder {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* Background paper texture for field-guide pages — subtle grid + warm wash
   so the dark substrate reads less like a terminal and more like
   "an old field journal photographed under cool light." */
.spread.v-field-guide .page--field {
  background:
    radial-gradient(ellipse at top left, rgba(5, 217, 232, 0.05) 0%, transparent 50%),
    radial-gradient(ellipse at bottom right, rgba(255, 42, 109, 0.04) 0%, transparent 50%),
    var(--paper);
  position: relative;
}

.spread.v-field-guide .page--field::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(5, 217, 232, 0.02) 1px, transparent 1px),
    linear-gradient(90deg, rgba(5, 217, 232, 0.02) 1px, transparent 1px);
  background-size: 40px 40px;
  pointer-events: none;
  z-index: 0;
}

/* === v-data-heavy — small inset illus, dominant data plates === */
.spread.v-data-heavy .illus-plate {
  width: 60%;
  margin: 0 0 var(--sp-4) 0;
  aspect-ratio: 1 / 1;
  background: var(--char-primary, var(--ink));
  border: var(--rule-base) solid var(--ink);
  overflow: hidden;
}

.spread.v-data-heavy .illus-plate img,
.spread.v-data-heavy .illus-plate .illus-placeholder {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.spread.v-data-heavy .data-plate {
  margin-bottom: var(--sp-3);
}

/* ---------- Illustration placeholder ----------
   When no image is available, use a placeholder box with commission spec.
   Renders as dark plate with cyan corner brackets + spec text. */
/* Art-pending pages get the Source-engine "missing texture" vibe per
   Fox 2026-05-24 — the iconic bright-magenta + black checkerboard you
   see when a texture asset fails to load in a game engine (Source,
   GoldSrc, GZDoom dev-mode, etc.). The book is using the same visual
   grammar to say "the asset isn't here yet, but the slot is real." */
.illus-placeholder {
  width: 100%;
  height: 100%;
  /* Pure missing-texture: 32px magenta / black checkerboard.
     Two perpendicular conic gradients composited give a clean grid;
     pixelated rendering keeps the squares crisp instead of blurred. */
  background-color: #000;
  background-image:
    linear-gradient(45deg, #FF00FF 25%, transparent 25%, transparent 75%, #FF00FF 75%),
    linear-gradient(45deg, #FF00FF 25%, transparent 25%, transparent 75%, #FF00FF 75%);
  background-size: 64px 64px;
  background-position: 0 0, 32px 32px;
  image-rendering: pixelated;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: var(--paper);
  padding: var(--sp-5);
  position: relative;
  text-align: center;
  overflow: hidden;
}

/* Top + bottom developer-console strips — semi-transparent black bands
   that hold the tag (top) and the spec text (bottom). They keep the
   text legible against the busy checker without softening the texture
   underneath. */
.illus-placeholder::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 64px;
  background:
    linear-gradient(to bottom,
      rgba(0, 0, 0, 0.9) 0%,
      rgba(0, 0, 0, 0.85) 70%,
      transparent 100%);
  pointer-events: none;
  z-index: 1;
}

.illus-placeholder::after {
  content: "";
  position: absolute;
  bottom: 0; left: 0; right: 0;
  min-height: 50%;
  background:
    linear-gradient(to top,
      rgba(0, 0, 0, 0.92) 0%,
      rgba(0, 0, 0, 0.88) 60%,
      transparent 100%);
  pointer-events: none;
  z-index: 1;
}

/* Tag = the dev-overlay label. Source's missing texture stamp is bold,
   monospace, all-caps; we keep "ART PENDING" (the canon label) but
   render it in that register so the visual reads as "missing texture
   for a slot that's reserved." */
.illus-placeholder .placeholder-tag {
  position: relative;
  z-index: 2;
  font-family: 'Share Tech Mono', 'Courier New', monospace;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: #FF00FF;
  text-shadow:
    0 0 6px rgba(255, 0, 255, 0.5),
    1px 1px 0 #000,
    -1px 1px 0 #000,
     1px -1px 0 #000,
    -1px -1px 0 #000;
  margin: var(--sp-2) 0 var(--sp-1);
  align-self: flex-start;
  padding: 4px 10px;
  background: rgba(0, 0, 0, 0.7);
  border: 1px solid #FF00FF;
  box-shadow: inset 0 0 12px rgba(255, 0, 255, 0.25);
}

/* The tag gets a leading "// " comment-marker prefix to read as dev-
   console output. Pure CSS, no markup change required across the
   ~14 pages currently using illus-placeholder. */
.illus-placeholder .placeholder-tag::before {
  content: "// ";
  opacity: 0.7;
}

/* Spec text — the bible-derived art-direction prose. Kept readable
   against the texture via the bottom-console strip. Mono-on-paper
   register so it reads as a script comment / dev note, not body
   prose. */
.illus-placeholder .placeholder-spec {
  position: relative;
  z-index: 2;
  font-family: 'Share Tech Mono', 'Courier New', monospace;
  font-style: normal;
  font-size: var(--fs-margin);
  color: rgba(255, 220, 255, 0.92);
  line-height: 1.5;
  max-width: 88%;
  margin-top: auto;
  padding: var(--sp-2) var(--sp-3);
  letter-spacing: 0.01em;
  text-align: left;
}

.illus-placeholder .placeholder-spec::before {
  content: "// ART_DIRECTION:";
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.22em;
  color: #FF00FF;
  margin-bottom: 4px;
  opacity: 0.85;
}

/* Strong tags inside the spec — bible-typical "Build:" / "Outfit:" /
   "Halo:" labels. Render as cyan to break up the magenta monotony
   and reinforce the dev-console color split. */
.illus-placeholder .placeholder-spec strong {
  color: #6AF0FF;
  font-weight: 700;
  letter-spacing: 0.04em;
}

.illus-placeholder .placeholder-spec em {
  color: rgba(255, 215, 0, 0.92);
  font-style: italic;
}

/* ---------- Right-page prose column ---------- */
.prose {
  flex: 1;
  font-size: var(--fs-page);
  line-height: 1.55;
  color: var(--ink);
  /* Two-column inside the right page for dense character entries */
}

.prose p + p {
  text-indent: 1.2em;
  margin-top: 0;
}

/* Two-column variant for dense pages */
.prose.cols-2 {
  column-count: 2;
  column-gap: var(--sp-5);
  column-rule: var(--rule-fine) dotted var(--ink-faint);
}

.prose.cols-2 .section-head {
  column-span: all;
}

/* ---------- Margin annotation (other-voice callouts) ---------- */
/* Lives in the page padding area, between body content and outer edge */
.margin-note {
  position: absolute;
  width: 150px;
  font-family: 'Crimson Pro', serif;
  font-style: italic;
  font-size: var(--fs-margin);
  line-height: 1.42;
  color: var(--ink-mid);
  padding: var(--sp-2) var(--sp-3);
  border-left: var(--rule-heavy) solid var(--char-accent, var(--naus-cyan));
  background: rgba(27, 31, 56, 0.95);
  z-index: 5;
  box-shadow:
    0 4px 12px rgba(0, 0, 0, 0.45),
    0 0 0 1px rgba(5, 217, 232, 0.2);
}

.margin-note .annot-attr {
  display: block;
  font-family: 'Space Grotesk', sans-serif;
  font-style: normal;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--char-accent, var(--naus-cyan));
  margin-bottom: var(--sp-1);
}

/* Position helpers — annotations live in the OUTER EDGE GUTTER of each
   page. The prose has padding-right (on right-page) / padding-left (on
   left-page) wide enough to reserve a 170px sidebar where notes sit.
   Notes are positioned absolute inside that reserved gutter. */
.margin-note.pos-top-right {
  top: var(--sp-6);
  right: 6px;
}

.margin-note.pos-bottom-left {
  bottom: var(--sp-7);
  left: 6px;
}

.margin-note.pos-mid-right {
  top: 38%;
  right: 6px;
}

.margin-note.pos-mid-left {
  top: 38%;
  left: 6px;
}

.margin-note.pos-bottom-right {
  bottom: var(--sp-7);
  right: 6px;
}

.margin-note.pos-top-left {
  top: var(--sp-6);
  left: 6px;
}

/* ===== Overflow detector — dev visual indicator =====
   book.js#detectOverflow flags any .page whose content clips below the
   page boundary. JUST the red bottom stripe + the corner pixel-overhang
   marker. v2 2026-05-20 — dropped the 90px inner vignette because on
   dark bookplate-purple pages it read as a stuck vignette artifact
   rather than as a dev indicator. Pure marker now, no atmosphere. */
.page.page-overflowing {
  /* Loud overflow marker — Fox 2026-05-21 "overflow CANNOT HAPPEN."
     A 3px stripe was easy to miss. Now: full-width red banner across
     the bottom of the page with the pixel overhang in big monospace
     text. Authors will see this on any normal page view. */
  position: relative;
}
.page.page-overflowing::before {
  content: "⚠ OVERFLOW · " attr(data-overflow-px) "px CLIPPED · TRIM OR SPLIT";
  position: absolute;
  inset: auto 0 0 0;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 42, 109, 0.92);
  color: #fff;
  font-family: 'Orbitron', 'Share Tech Mono', monospace;
  font-size: 14px;
  font-weight: 900;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-shadow: 0 0 6px rgba(0, 0, 0, 0.85);
  box-shadow: 0 -6px 18px rgba(255, 42, 109, 0.55);
  pointer-events: none;
  z-index: 49;
  animation: nausOverflowPulse 1.4s ease-in-out infinite;
}
@keyframes nausOverflowPulse {
  0%, 100% { background: rgba(255, 42, 109, 0.92); }
  50%      { background: rgba(255, 42, 109, 0.70); }
}
.page.page-overflowing::after {
  content: "⚠ overflow " attr(data-overflow-px) "px";
  position: absolute;
  bottom: 46px;
  right: 12px;
  z-index: 50;
  font-family: 'Share Tech Mono', monospace;
  font-size: 9px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(255, 42, 109, 0.85);
  background: rgba(20, 6, 24, 0.85);
  border: 1px solid rgba(255, 42, 109, 0.5);
  padding: 2px 8px;
  pointer-events: none;
}

/* ===== Pitch inset — "How it was sold" block in the Introduction =====
   Compact marketing-pitch register block. Differentiated from pillars
   (which are emotional convictions) by a magenta left rule + slightly
   smaller italic body. Reads as "the wrapper around the architecture." */
.pitch-inset {
  position: relative;
  margin: var(--sp-3) 0;
  padding: var(--sp-2) var(--sp-4);
  background: rgba(255, 42, 109, 0.05);
  border-left: 3px solid rgba(255, 42, 109, 0.55);
}

.pitch-inset__label {
  display: block;
  font-family: 'Share Tech Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: rgba(255, 42, 109, 0.85);
  margin-bottom: 4px;
}

.pitch-inset__copy {
  margin: 0;
  font-family: 'Crimson Pro', serif;
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink-mid);
}

.pitch-inset__copy em {
  color: var(--ink);
  font-weight: 600;
}

/* ===== Foreword foot sigil — small centered Crash sigil under the pull-quote =====
   Fills sparse breathing room on the Foreword right page (ii-iii) after the
   Section-0-ahead Note thread was dropped 2026-05-20. Aged-gold, faint glow,
   matches the inside-front-cover sigil aesthetic at smaller scale. */
.foreword-foot-sigil {
  display: flex;
  justify-content: center;
  margin: var(--sp-6) auto var(--sp-3) auto;
  color: rgba(242, 216, 115, 0.55);
}

.foreword-foot-sigil .naus-sigil {
  width: 110px;
  height: auto;
  stroke-width: 4;
  filter:
    drop-shadow(0 0 8px rgba(242, 216, 115, 0.35))
    drop-shadow(0 0 18px rgba(255, 42, 109, 0.12));
}

/* ===== Redaction blocks — SCP-canon "data expunged" register =====
   Used in the compendium where ADMIN's deeper notes "would have been."
   Black bar with [DATA EXPUNGED] / [REDACTED] stamps; the surrounding
   prose still acknowledges the absence. Reinforces "the book was
   assembled inside a system that hides things from itself." */
.redacted-block {
  position: relative;
  margin: var(--sp-4) 0;
  padding: var(--sp-3) var(--sp-4);
  background: rgba(0, 0, 0, 0.75);
  border-left: 3px solid rgba(255, 42, 109, 0.6);
  overflow: hidden;
}

.redacted-block::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(
    0deg,
    transparent 0,
    transparent 18px,
    rgba(0, 0, 0, 0.55) 18px,
    rgba(0, 0, 0, 0.55) 22px
  );
  pointer-events: none;
}

.redacted-block .redacted-stamp {
  position: relative;
  z-index: 2;
  display: inline-block;
  font-family: 'Share Tech Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: rgba(255, 42, 109, 0.85);
  border: 1px solid rgba(255, 42, 109, 0.65);
  padding: 2px 8px;
  margin-bottom: var(--sp-2);
  text-shadow: 0 0 6px rgba(255, 42, 109, 0.4);
}

.redacted-block .redacted-bars {
  position: relative;
  z-index: 2;
}

.redacted-block .redacted-bars span {
  display: inline-block;
  background: rgba(20, 20, 30, 0.95);
  color: transparent;
  margin: 2px 4px 2px 0;
  padding: 0 4px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.5);
  height: 1.2em;
  vertical-align: middle;
  user-select: none;
}

.redacted-block .redacted-note {
  position: relative;
  z-index: 2;
  display: block;
  margin-top: var(--sp-2);
  font-family: 'Crimson Pro', serif;
  font-style: italic;
  font-size: 13px;
  color: rgba(232, 232, 238, 0.55);
}

/* Voice-specific styling for marginalia.
   Per intro_2 (p.4) Marginal Voices guide — each voice carries a
   distinct typeface + color + ornament so the reader can identify
   the speaker at a glance. The House-of-Leaves register: typography
   IS character. Updated 2026-05-20 voice typography pass. */
.margin-note--crash {
  --char-accent: var(--naus-cyan);
  /* Italic Crimson, lowercase forced, cyan rule. Dry-aside register. */
  font-family: 'Crimson Pro', 'Lora', serif;
  font-style: italic;
  text-transform: lowercase;
  letter-spacing: 0;
  color: rgba(232, 232, 238, 0.85);
}

.margin-note--crash .annot-attr {
  text-transform: uppercase;  /* keep "CRASH" label readable */
  letter-spacing: 0.18em;
}

.margin-note--bleeker {
  border-left-style: dashed;
  color: var(--bleeker-grey);
  font-style: normal;
  font-family: 'Spectral SC', serif;
  letter-spacing: 0.04em;
  background: var(--bleeker-fade);
}

.margin-note--bracket {
  font-family: 'JetBrains Mono', monospace;
  font-style: normal;
  font-size: 11px;
}

.margin-note--bracket .annot-attr::before {
  content: "[ ";
}

.margin-note--bracket .annot-attr::after {
  content: " ]";
}

.margin-note--skipad {
  /* Helper-tone register: friendlier sans-serif, slightly cheerful weight,
     cyan-tinted bg. Pedantic-followed-by-a-dry-sting. */
  background: rgba(0, 217, 255, 0.12);
  font-family: 'Space Grotesk', 'Rajdhani', sans-serif;
  font-style: normal;
  font-weight: 500;
  color: rgba(232, 240, 250, 0.85);
  letter-spacing: 0.02em;
}

.margin-note--trigon {
  background: var(--ink);
  color: var(--paper);
  font-family: 'Spectral SC', serif;
  font-style: normal;
  letter-spacing: 0.05em;
}

.margin-note--trigon::before {
  content: "▼";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: var(--naus-magenta);
  font-size: 14px;
}

/* Mardennan margin notes — fool's register: warmer paper, tarnished-gold
   marker, italic phrasing that reads as half-spoken half-sung. */
.margin-note--mardennan {
  background: #1A1426;
  color: rgba(232, 220, 200, 0.92);
  font-family: 'Spectral SC', serif;
  font-style: italic;
  letter-spacing: 0.04em;
  border-left-color: #d4a900;
}

.margin-note--mardennan::before {
  content: "♪";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #d4a900;
  font-size: 14px;
}

/* 3TC4 / Etch margin notes — terminal register: dark violet-black paper,
   monospace, blinking-cursor marker. Reads as a command-line note pinned
   to the spread, as if his screen wrote it directly to the page. */
.margin-note--3tc4 {
  background: #1A1830;
  color: rgba(224, 240, 248, 0.94);
  font-family: 'Share Tech Mono', 'JetBrains Mono', monospace;
  font-style: normal;
  letter-spacing: 0.04em;
  border-left-color: var(--naus-cyan);
}

.margin-note--3tc4::before {
  content: "▮";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: var(--naus-cyan);
  font-size: 14px;
  animation: cursor-blink 1.1s steps(2, end) infinite;
}

@keyframes cursor-blink {
  0%, 50% { opacity: 1; }
  50.01%, 100% { opacity: 0; }
}

/* RTVS margin notes — gravedigger register: cold slate paper, Spectral SC
   serif (weighty, formal), shovel-chevron marker, controlled-silence
   spacing. The voice of someone who already knows how it ends. */
.margin-note--rtvs {
  background: #16191F;
  color: rgba(208, 212, 220, 0.92);
  font-family: 'Spectral SC', 'Crimson Pro', serif;
  font-style: normal;
  letter-spacing: 0.05em;
  border-left-color: #708090;
}

.margin-note--rtvs::before {
  content: "▼";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #708090;
  font-size: 13px;
}

/* Dollgrief margin notes — Instagram-caption register: magenta-tinted paper,
   sans-serif (Rajdhani, the brand-post typeface), heart-rank marker. Voice
   reads as a captioned breakdown, pre-rehearsed sincerity. */
.margin-note--dollgrief {
  background: #1F0E1F;
  color: rgba(248, 220, 240, 0.94);
  font-family: 'Rajdhani', 'Inter', sans-serif;
  font-style: normal;
  font-weight: 400;
  letter-spacing: 0.03em;
  border-left-color: var(--naus-magenta);
}

.margin-note--dollgrief::before {
  content: "♡";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: var(--naus-magenta);
  font-size: 14px;
}

/* Cowboy margin notes — engineer's logbook register: warm charcoal paper,
   small-caps slab for the no-wasted-syllables voice, gear-cog marker.
   Short blunt phrases, silence the native language. */
.margin-note--cowboy {
  background: #1A1612;
  color: rgba(232, 218, 196, 0.92);
  font-family: 'Spectral SC', 'Crimson Pro', serif;
  font-style: normal;
  letter-spacing: 0.06em;
  border-left-color: #B05028;
}

.margin-note--cowboy::before {
  content: "⚙";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #B05028;
  font-size: 14px;
}

/* Maverick margin notes — caretaker's note register: warm green-tinted
   paper, soft sans-serif (the register that doesn't demand attention),
   sun-disc marker. Voice is presence-not-words; the margin reads as
   her sitting near you, not speaking. */
.margin-note--maverick {
  background: #102A22;
  color: rgba(220, 244, 224, 0.92);
  font-family: 'Rajdhani', 'Inter', sans-serif;
  font-style: normal;
  font-weight: 400;
  letter-spacing: 0.03em;
  border-left-color: #FFE664;
}

.margin-note--maverick::before {
  content: "☼";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #FFE664;
  font-size: 14px;
}

/* BeeBop margin notes — emotional regulator's logbook: violet-deep
   paper, soft Rajdhani sans (the apologizes-before-acting voice),
   hexagon-pollination marker. Voice is cheerful with a subtle flicker
   underneath; the marker stays steady. */
.margin-note--beebop {
  background: #1F1B48;
  color: rgba(232, 220, 248, 0.92);
  font-family: 'Rajdhani', 'Inter', sans-serif;
  font-style: normal;
  font-weight: 400;
  letter-spacing: 0.03em;
  border-left-color: #FFD46A;
}

.margin-note--beebop::before {
  content: "⬡";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #FFD46A;
  font-size: 14px;
}

/* Ragbanner margin notes — licensed-performance register: chapel-warm
   dark paper, Spectral SC for the carved-pageantry voice, floral-
   heart marker for the lament-made-public canon. Lines arrive as
   sanctioned phrasings — performance carrying jurisdiction. */
.margin-note--ragbanner {
  background: #1F1810;
  color: rgba(232, 217, 176, 0.92);
  font-family: 'Spectral SC', 'Crimson Pro', serif;
  font-style: normal;
  letter-spacing: 0.06em;
  border-left-color: #C9A85B;
}

.margin-note--ragbanner::before {
  content: "\2766";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #C9A85B;
  font-size: 14px;
}

/* Stagline margin notes — witness-under-pursuit register: bloodless-
   deep paper, Spectral SC for the carved-omen voice, circled-plus
   marker for the split-halo / saltire-through-the-corona canon. Lines
   read as transmissions made under threat: short, exact, refusing
   the silence that would be safer. */
.margin-note--stagline {
  background: #1A0A0A;
  color: rgba(244, 236, 218, 0.92);
  font-family: 'Spectral SC', 'Crimson Pro', serif;
  font-style: normal;
  letter-spacing: 0.06em;
  border-left-color: #C82A2D;
}

.margin-note--stagline::before {
  content: "\2295";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #C82A2D;
  font-size: 14px;
}

/* Endstate margin notes — closure register: ruin-deep paper, Share
   Tech Mono for the gravedigger field-log voice, perpendicular mark
   for the line-drops-here canon. The marker is sober. Lines arrive
   as terminations posted to a board nobody reads except the people
   who already know. */
.margin-note--endstate {
  background: #0F1218;
  color: rgba(201, 168, 91, 0.92);
  font-family: 'Share Tech Mono', 'Courier New', monospace;
  font-style: normal;
  letter-spacing: 0.06em;
  border-left-color: #708090;
}

.margin-note--endstate::before {
  content: "\22A5";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #C9A85B;
  font-size: 14px;
}

/* Snares margin notes — perpetual-motion register: deep neon-black
   paper, Rajdhani for the rolling biker-cadence voice, eighth-notes
   marker for the bass-beat canon. The marker pulses. Slowing down
   would be death. */
.margin-note--snares {
  background: #14080F;
  color: rgba(255, 26, 140, 0.92);
  font-family: 'Rajdhani', 'Inter', sans-serif;
  font-style: normal;
  font-weight: 500;
  letter-spacing: 0.06em;
  border-left-color: #FF1A8C;
}

.margin-note--snares::before {
  content: "\266C";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #FF1A8C;
  font-size: 14px;
}

/* Unheard margin notes — silence-protocol register: deep-black paper,
   Share Tech Mono for the recovered-fragment voice, up-triangle
   marker for the Δ iconography canon. Lines arrive as recovered
   phrases scratched into concrete, broadcast fragments, or chant-
   formed maxims. */
.margin-note--unheard {
  background: #0A0A0A;
  color: rgba(201, 168, 91, 0.92);
  font-family: 'Share Tech Mono', 'Courier New', monospace;
  font-style: normal;
  letter-spacing: 0.08em;
  border-left-color: #C9A85B;
}

.margin-note--unheard::before {
  content: "\25B3";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #C9A85B;
  font-size: 14px;
}

/* Synroz margin notes — sparkle-coded register: deep-navy paper,
   Rajdhani for the teehee-cadence voice, four-pointed-star marker
   for the "sparkle hard enough" canon. Voice goes flat and quiet
   when actually upset; the marker stays sparkly even when the
   smile breaks. */
.margin-note--synroz {
  background: #151A3A;
  color: rgba(232, 200, 240, 0.92);
  font-family: 'Rajdhani', 'Inter', sans-serif;
  font-style: normal;
  font-weight: 400;
  letter-spacing: 0.04em;
  border-left-color: #E23B9B;
}

.margin-note--synroz::before {
  content: "\2727";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #E23B9B;
  font-size: 14px;
}

/* Waltzin margin notes — pulpit register: digital-black paper,
   Spectral SC for the velvet-preacher voice, crown marker for the
   king-on-stage lion-icon canon. Voice projects benediction;
   underneath it is the bar voice. The marker stays gold even when
   the lion is glitching. */
.margin-note--waltzin {
  background: #0A0A14;
  color: rgba(212, 175, 55, 0.92);
  font-family: 'Spectral SC', 'Crimson Pro', serif;
  font-style: normal;
  letter-spacing: 0.06em;
  border-left-color: #FF8C00;
}

.margin-note--waltzin::before {
  content: "\265B";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #D4AF37;
  font-size: 14px;
}

/* KERN margin notes — Unity register: warm-dark paper, Spectral SC
   italic for the integration-presence voice, circled-asterisk marker
   for the centre-of-the-sum canon. The voice is sparse and revelatory
   — KERN manifests as presence, speech is the rare exception when
   the architecture permits a sentence at all. */
.margin-note--kern {
  background: #1A140A;
  color: rgba(255, 242, 207, 0.92);
  font-family: 'Spectral SC', 'Crimson Pro', serif;
  font-style: italic;
  letter-spacing: 0.05em;
  border-left-color: #FFD700;
}

.margin-note--kern::before {
  content: "\229B";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #FFD700;
  font-size: 14px;
}

/* TESS margin notes — Compression Engine register: deep indigo-black
   paper, Share Tech Mono for the clipped OS-status voice, squared-
   plus marker for the tessellation grid canon. Voice never uses
   metaphor — only status. Lines arrive like compression updates. */
.margin-note--tess {
  background: #2A0220;
  color: rgba(247, 125, 169, 0.92);
  font-family: 'Share Tech Mono', 'Courier New', monospace;
  font-style: normal;
  letter-spacing: 0.06em;
  border-left-color: #FF4BD1;
}

.margin-note--tess::before {
  content: "\229E";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #FF4BD1;
  font-size: 14px;
}

/* SIG margin notes — Interpreter register: obsidian paper, Share Tech
   Mono for the minimal-exact voice, circled-dot aperture marker.
   Voice never softens truth; treats conversation like architecture.
   Lines arrive pre-validated. */
.margin-note--sig {
  background: #05070A;
  color: rgba(242, 248, 255, 0.92);
  font-family: 'Share Tech Mono', 'Courier New', monospace;
  font-style: normal;
  letter-spacing: 0.06em;
  border-left-color: #00F2FF;
}

.margin-note--sig::before {
  content: "\2299";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #00F2FF;
  font-size: 14px;
}

/* PARS margin notes — Archivist register: deep-navy paper, Share Tech
   Mono for the exact-not-cold voice, white-diamond-with-dot marker
   for the crystalline-vertex canon. Voice is sparing; they speak only
   when structure is at risk. Lines should read like field-notation,
   never argument. */
.margin-note--pars {
  background: #0A1F2A;
  color: rgba(212, 240, 255, 0.92);
  font-family: 'Share Tech Mono', 'Courier New', monospace;
  font-style: normal;
  letter-spacing: 0.06em;
  border-left-color: #7FE6FF;
}

.margin-note--pars::before {
  content: "\25C8";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #7FE6FF;
  font-size: 14px;
}

/* Beacon margin notes — Golden Boy register: void-black paper, Spectral
   SC italic for the honey-over-glass voice, eight-pointed star marker
   for the constellation halo canon. Voice is smooth, low, deliberate.
   Vulnerable lines drop tone but never the marker — the glow doesn't
   know how to stop. */
.margin-note--beacon {
  background: #0A0A0D;
  color: rgba(255, 221, 97, 0.92);
  font-family: 'Spectral SC', 'Crimson Pro', serif;
  font-style: italic;
  letter-spacing: 0.05em;
  border-left-color: #FFCC47;
}

.margin-note--beacon::before {
  content: "\2734";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #FFCC47;
  font-size: 14px;
}

/* Ghostline margin notes — Observer register: dark-navy paper, Share
   Tech Mono for the signed-transmission voice, bullseye-target marker
   for the reticle-halo canon. Voice is sparse to absent; the marker
   carries most of the presence. The paper itself reads colder than
   the others — desaturation effect. */
.margin-note--ghostline {
  background: #0F1A25;
  color: rgba(122, 232, 255, 0.92);
  font-family: 'Share Tech Mono', 'Courier New', monospace;
  font-style: normal;
  letter-spacing: 0.08em;
  border-left-color: #00E5FF;
}

.margin-note--ghostline::before {
  content: "\25CE";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #00E5FF;
  font-size: 14px;
}

/* Gloss margin notes — Oracle-of-Elysium register: deep purple-black
   paper, Spectral SC italic for the slow-precise-devastating voice,
   curated-diamond marker (the rose-window glyph U+2756). Voice is
   velvet over steel; the marker is sharp-edged on purpose. */
.margin-note--gloss {
  background: #1A0F1D;
  color: rgba(245, 240, 255, 0.92);
  font-family: 'Spectral SC', 'Crimson Pro', serif;
  font-style: italic;
  letter-spacing: 0.05em;
  border-left-color: #FFD447;
}

.margin-note--gloss::before {
  content: "\2756";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #FFD447;
  font-size: 14px;
}

/* Firewall margin notes — tank register: dark heat-shadow paper, Share
   Tech Mono for the clipped operator voice, horizontal-line block
   marker for the barrier/burn-line read. Voice is short; goes to
   single words under load. The marker stays sober, like the wall. */
.margin-note--firewall {
  background: #1A0E08;
  color: rgba(255, 200, 160, 0.92);
  font-family: 'Share Tech Mono', 'Courier New', monospace;
  font-style: normal;
  letter-spacing: 0.06em;
  border-left-color: #FF4444;
}

.margin-note--firewall::before {
  content: "\25AC";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #FF4444;
  font-size: 14px;
}

/* Volsung margin notes — old-terminal register: amber-on-black paper,
   Share Tech Mono for the session-log voice, terminal-prompt marker.
   Voice is fast-and-warm narrating life unprompted; the marker reads
   "you're reading session output." Drops to flatter when the grief
   hitches — but the marker stays steady, because the prompt is the
   one thing that hasn't gone dark yet. */
.margin-note--volsung {
  background: #14110A;
  color: rgba(255, 179, 71, 0.92);
  font-family: 'Share Tech Mono', 'Courier New', monospace;
  font-style: normal;
  letter-spacing: 0.04em;
  border-left-color: #FFB347;
}

.margin-note--volsung::before {
  content: ">";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #FFB347;
  font-size: 14px;
  font-family: 'Share Tech Mono', monospace;
}

/* Wolfaith margin notes — granted sacred steward, priest-keeper of
   funerary rites. Dark chapel paper, Spectral SC small-caps serif for
   the carved-not-spoken register, dagger-cross marker for the
   chapel-priest register. Voice is plain, precise, weighted; lines
   should feel chiseled, not flourished. Marker stays sober. */
.margin-note--wolfaith {
  background: #14110A;
  color: rgba(232, 224, 200, 0.92);
  font-family: 'Spectral SC', 'Crimson Pro', serif;
  font-style: normal;
  letter-spacing: 0.06em;
  border-left-color: #C9A85B;
}

.margin-note--wolfaith::before {
  content: "\2020";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #C9A85B;
  font-size: 14px;
}

/* Litwitch margin notes — gothic hearthkeeper register: deep bruise-
   purple paper, lyrical serif for the warm-lilt voice, candle-flame
   spark marker. Pet-name affectionate ("honey," "sweetheart," "love");
   sharps when tired; goes quiet when the fire's coming up. The marker
   stays small and constant — like her candle-flame earrings. */
.margin-note--litwitch {
  background: #2A1635;
  color: rgba(252, 232, 200, 0.92);
  font-family: 'Crimson Pro', 'Spectral SC', serif;
  font-style: normal;
  letter-spacing: 0.04em;
  border-left-color: #FFD700;
}

.margin-note--litwitch::before {
  content: "✦";
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-2);
  color: #FFD700;
  font-size: 14px;
}

/* ---------- TOC scaffold styles ---------- */
.toc {
  font-family: 'Crimson Pro', serif;
  font-size: var(--fs-page);
}

.toc-section {
  margin-bottom: var(--sp-5);
}

.toc-section-title {
  font-family: 'Spectral SC', serif;
  font-weight: 700;
  font-size: var(--fs-h3);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--char-primary, var(--ink));
  border-bottom: var(--rule-base) solid var(--ink);
  padding-bottom: var(--sp-1);
  margin-bottom: var(--sp-2);
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}

.toc-section-title .toc-page-range {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.7em;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--ink-faint);
}

.toc-entries {
  list-style: none;
  padding-left: var(--sp-3);
  margin: 0;
}

.toc-entries li {
  display: flex;
  align-items: baseline;
  margin-bottom: var(--sp-1);
}

.toc-entries .toc-label {
  flex-shrink: 0;
}

.toc-entries .toc-fill {
  flex: 1;
  border-bottom: var(--rule-fine) dotted var(--ink-faint);
  margin: 0 var(--sp-2);
  transform: translateY(-4px);
}

.toc-entries .toc-page {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.85em;
  color: var(--ink-soft);
  flex-shrink: 0;
}

/* ---------- Cover spread ---------- */
.spread.v-cover {
  filter: drop-shadow(0 16px 48px rgba(0, 0, 0, 0.7));
}

.spread.v-cover .page--right {
  background:
    radial-gradient(
      ellipse at 70% 30%,
      rgba(5, 217, 232, 0.08) 0%,
      transparent 60%
    ),
    radial-gradient(
      ellipse at 30% 70%,
      rgba(255, 42, 109, 0.10) 0%,
      transparent 55%
    ),
    radial-gradient(
      ellipse at center,
      #1A1A2E 0%,
      #0A0A12 70%,
      #050508 100%
    );
  color: var(--paper);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  padding: var(--sp-7);
  position: relative;
}

/* Subtle scanline overlay on the cover right — CRT register */
.spread.v-cover .page--right::after {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    0deg,
    rgba(0, 0, 0, 0) 0px,
    rgba(0, 0, 0, 0) 2px,
    rgba(0, 0, 0, 0.18) 3px,
    rgba(0, 0, 0, 0) 4px
  );
  pointer-events: none;
  z-index: 1;
}

.spread.v-cover .page--right > * {
  position: relative;
  z-index: 2;
}

.spread.v-cover .cover-title {
  font-family: 'Orbitron', 'Spectral SC', serif;
  font-size: 72px;
  font-weight: 900;
  letter-spacing: 0.06em;
  color: var(--naus-yellow);
  line-height: 1;
  margin-bottom: var(--sp-2);
  text-shadow:
    0 0 4px var(--naus-yellow),
    0 0 18px rgba(249, 240, 2, 0.7),
    0 0 40px rgba(249, 240, 2, 0.35),
    2px 0 var(--naus-cyan),
    -2px 0 var(--naus-magenta);
  text-transform: uppercase;
}

.spread.v-cover .cover-dot {
  display: inline-block;
  width: 14px;
  height: 14px;
  background: var(--naus-magenta);
  border-radius: 50%;
  vertical-align: middle;
  margin: 0 10px 12px;
  box-shadow:
    0 0 8px var(--naus-magenta),
    0 0 24px rgba(255, 42, 109, 0.55);
}

/* The OS suffix — magenta with chromatic-aberration glow, mirror of website */
.spread.v-cover .cover-os-suffix {
  color: var(--naus-magenta);
  font-family: 'Orbitron', 'Spectral SC', serif;
  font-weight: 900;
  text-shadow:
    0 0 4px var(--naus-magenta),
    0 0 18px rgba(255, 42, 109, 0.7),
    0 0 40px rgba(255, 42, 109, 0.3),
    2px 0 var(--naus-cyan),
    -2px 0 var(--naus-magenta);
}

.spread.v-cover .cover-os {
  font-family: 'Share Tech Mono', 'JetBrains Mono', monospace;
  font-size: 0.6em;
  color: var(--naus-cyan);
  letter-spacing: 0.08em;
  font-weight: 400;
  text-transform: lowercase;
  text-shadow: 0 0 6px var(--naus-cyan);
  margin-top: 8px;
}

.spread.v-cover .cover-subtitle {
  font-family: 'Crimson Pro', serif;
  font-style: italic;
  font-size: 22px;
  color: var(--ink-faint);
  letter-spacing: 0.04em;
  margin-bottom: var(--sp-7);
}

.spread.v-cover .cover-rule {
  width: 60%;
  height: 1px;
  background: var(--bleeker-grey);
  margin: var(--sp-3) auto var(--sp-5);
  position: relative;
}

.spread.v-cover .cover-rule::before,
.spread.v-cover .cover-rule::after {
  content: "◆";
  position: absolute;
  top: -10px;
  color: var(--naus-cyan);
  font-size: 11px;
}

.spread.v-cover .cover-rule::before { left: -4px; }
.spread.v-cover .cover-rule::after  { right: -4px; }

.spread.v-cover .cover-attrib {
  font-family: 'Spectral SC', serif;
  font-size: 14px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--bleeker-grey);
}

.spread.v-cover .cover-attrib strong {
  color: var(--paper);
}

/* Cover-spread LEFT page = inside front cover / hardcover-style plate.
   Rebuilt 2026-05-19 to mirror the closed-book hardcover aesthetic:
   dark dyed cloth + aged-gold ornate frame + large central sigil +
   small Bleeker inscription at the foot. Replaces the prior small
   floating frontis-plate that read as a placeholder. */
.spread.v-cover .page--left {
  /* Cloth weave + warm-dark gradient — matches closed-book .book-3d__front */
  background-image:
    repeating-linear-gradient(
      90deg,
      transparent 0,
      transparent 2px,
      rgba(255, 255, 255, 0.025) 2px,
      rgba(255, 255, 255, 0.025) 3px
    ),
    repeating-linear-gradient(
      0deg,
      transparent 0,
      transparent 2px,
      rgba(0, 0, 0, 0.18) 2px,
      rgba(0, 0, 0, 0.18) 3px
    ),
    radial-gradient(
      ellipse at 30% 25%,
      #2A1138 0%,
      #1A0D24 55%,
      #0E0518 100%
    );
  background-color: #1A0D24;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.04),
    inset 0 0 80px rgba(0, 0, 0, 0.55);
  overflow: hidden;
}

/* Ornate aged-gold frame inset, matching the closed-book cover-frame.
   Multi-layered box-shadow inset = double-rule + thin gold + black gap. */
.spread.v-cover .page--left::before {
  content: "";
  position: absolute;
  top: 48px;
  left: 48px;
  right: 48px;
  bottom: 48px;
  border: 2px solid rgba(242, 216, 115, 0.42);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.04),
    inset 0 0 0 7px rgba(0, 0, 0, 0.4),
    inset 0 0 0 8px rgba(242, 216, 115, 0.18),
    inset 0 0 0 9px rgba(0, 0, 0, 0.3);
  pointer-events: none;
  z-index: 1;
}

/* Top frame flourish — sits over the rule, breaks it into a "decorated" feel.
   2026-05-20: ⌖ removed (read as cross) — three diamonds replace it. */
.spread.v-cover .page--left::after {
  content: "❖   ❖   ❖";
  position: absolute;
  top: 40px;
  left: 50%;
  transform: translateX(-50%);
  font-family: 'Spectral SC', serif;
  font-size: 12px;
  letter-spacing: 0.5em;
  color: rgba(242, 216, 115, 0.5);
  text-shadow: 0 0 6px rgba(242, 216, 115, 0.25);
  background: #1A0D24;
  padding: 0 14px;
  z-index: 2;
}

/* Frontis-plate is now an inner flex container (transparent) that
   centers the sigil + inscription within the framed cover area. */
.spread.v-cover .frontis-plate {
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  border: none;
  background: none;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 120px 90px;
  text-align: center;
  z-index: 3;
}

/* Drop the prior cyan corner brackets — the gold frame on the page-left
   provides the ornament now. */
.spread.v-cover .frontis-plate::before,
.spread.v-cover .frontis-plate::after {
  display: none;
}

/* Large central sigil — foil-stamped feel, matches the closed-book sigil.
   v3 (2026-05-20): replaced the prior ⌖ glyph (cross/religious read flagged
   by Fox) with an SVG of two crosshair-circles overlapping Venn-style —
   "two of Crash's eyes, like infinity." */
.spread.v-cover .frontis-seal {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #F2D873; /* aged gold foil — currentColor for the SVG strokes */
  width: 320px;
  height: auto;
  margin: 0;
}

.spread.v-cover .frontis-seal .naus-sigil {
  width: 100%;
  height: auto;
  stroke-width: 5;
  filter:
    drop-shadow(0 0 22px rgba(249, 240, 2, 0.55))
    drop-shadow(0 0 60px rgba(255, 42, 109, 0.18));
}

/* Bleeker inscription — small uppercase serif near the foot of the page.
   2026-05-20: Ex Libris stamp removed per Fox — inscription returns to
   bottom: 88px (its position before the ex libris was added). */
.spread.v-cover .frontis-statement {
  position: absolute;
  bottom: 88px;
  left: 90px;
  right: 90px;
  font-family: 'Spectral SC', serif;
  font-size: 13px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(232, 232, 238, 0.6);
  line-height: 1.6;
  margin: 0;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.7);
  z-index: 3;
}

/* ===== Bookplate ornaments (2026-05-20) =====
   Added to compensate for regular pages now sharing the bookplate
   baseline aesthetic — the inside cover needed to stay distinctly
   "limited-edition grimoire" register. Five elements: damask watermark,
   edition mark, four corner fleurons, wax-seal ring, Ex Libris stamp. */

/* Damask diamond-grid watermark — faint full-plate weave behind everything.
   Two crossed repeating gradients form a diamond lattice. */
.spread.v-cover .frontis-damask {
  position: absolute;
  inset: 56px;
  pointer-events: none;
  opacity: 0.06;
  background-image:
    repeating-linear-gradient(
      45deg,
      transparent 0,
      transparent 28px,
      rgba(242, 216, 115, 0.7) 28px,
      rgba(242, 216, 115, 0.7) 29px
    ),
    repeating-linear-gradient(
      -45deg,
      transparent 0,
      transparent 28px,
      rgba(242, 216, 115, 0.7) 28px,
      rgba(242, 216, 115, 0.7) 29px
    );
  z-index: 1;
}

/* Edition mark — Roman numeral plate marker at the top, inside the
   gold frame. Sits BEHIND the `❖ ⌖ ❖` flourish that lives on ::after. */
.spread.v-cover .frontis-edition {
  position: absolute;
  top: 76px;
  left: 50%;
  transform: translateX(-50%);
  font-family: 'Spectral SC', serif;
  font-size: 13px;
  letter-spacing: 0.34em;
  color: rgba(242, 216, 115, 0.55);
  text-transform: uppercase;
  text-shadow: 0 0 8px rgba(242, 216, 115, 0.25);
  white-space: nowrap;
  z-index: 2;
}

/* Corner fleurons — small diamond ornaments centered on each inside
   corner of the gold frame. Frame is at 48px inset; fleurons sit at
   that corner intersection so they "break" the frame into tooled
   decoration rather than a plain rule. Background matches the cover
   bg so the rule appears cut behind the glyph. */
.spread.v-cover .frontis-corner {
  position: absolute;
  font-family: 'Spectral SC', serif;
  font-size: 18px;
  color: rgba(242, 216, 115, 0.7);
  text-shadow: 0 0 8px rgba(242, 216, 115, 0.4);
  background: #1A0D24;
  padding: 0 6px;
  line-height: 1;
  z-index: 2;
}
.spread.v-cover .frontis-corner--tl { top: 41px; left: 41px; }
.spread.v-cover .frontis-corner--tr { top: 41px; right: 41px; }
.spread.v-cover .frontis-corner--bl { bottom: 41px; left: 41px; }
.spread.v-cover .frontis-corner--br { bottom: 41px; right: 41px; }

/* Wax-seal ring — faint glowing gold circle behind the sigil. Reads as
   the impression of a foil stamp pressed into the page. */
.spread.v-cover .frontis-seal-ring {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -55%);
  width: 420px;
  height: 420px;
  border-radius: 50%;
  border: 1px solid rgba(242, 216, 115, 0.22);
  box-shadow:
    inset 0 0 0 1px rgba(0, 0, 0, 0.3),
    inset 0 0 0 4px rgba(242, 216, 115, 0.08),
    inset 0 0 0 5px rgba(0, 0, 0, 0.25),
    0 0 40px rgba(242, 216, 115, 0.08);
  pointer-events: none;
  z-index: 2;
}

/* Ex Libris stamp — bookplate ownership attribution at the foot.
   Bleeker is the archivist/witness sub-system that maintains this volume.
   Two thin gold rules bracket the label + name. */
.spread.v-cover .frontis-exlibris {
  position: absolute;
  bottom: 88px;
  left: 90px;
  right: 90px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  z-index: 3;
}

.spread.v-cover .frontis-exlibris-rule {
  width: 180px;
  height: 1px;
  background: linear-gradient(
    90deg,
    transparent,
    rgba(242, 216, 115, 0.5),
    transparent
  );
}

.spread.v-cover .frontis-exlibris-label {
  font-family: 'Crimson Pro', 'EB Garamond', serif;
  font-style: italic;
  font-size: 22px;
  color: rgba(242, 216, 115, 0.75);
  letter-spacing: 0.04em;
  text-shadow: 0 0 8px rgba(242, 216, 115, 0.25);
}

.spread.v-cover .frontis-exlibris-name {
  font-family: 'Spectral SC', serif;
  font-size: 10px;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: rgba(232, 232, 238, 0.55);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.7);
}

/* Legacy frontis-line — still styled in case any spread uses it; ducked
   below the inscription. Most files have it dropped. */
.spread.v-cover .frontis-line {
  font-family: 'Crimson Pro', serif;
  font-style: italic;
  font-size: 13px;
  color: var(--bleeker-grey);
  line-height: 1.5;
  margin-top: var(--sp-3);
}

/* ============================================================
   A→Z GUTTER — left-edge alphabet jump-strip routing to Index &
   Glossary letter anchors. Fox 2026-05-24 spec: use the empty
   left-of-spread real-estate as a vertical quick-jump column.
   Cross-page click triggers softGlitchTransition; same-page click
   on the Index spread scrolls + flashes the letter via :target.
   ============================================================ */
.book-gutter-az {
  position: fixed;
  left: 8px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 51;
  display: flex;
  flex-direction: column;
  padding: 6px 0;
  border-radius: 12px;
  background: linear-gradient(180deg,
    rgba(10, 13, 28, 0) 0%,
    rgba(10, 13, 28, 0.45) 12%,
    rgba(10, 13, 28, 0.45) 88%,
    rgba(10, 13, 28, 0) 100%);
  font-family: 'Orbitron', sans-serif;
  pointer-events: auto;
}

.book-gutter-az__btn {
  display: block;
  width: 22px;
  height: 18px;
  padding: 0;
  margin: 0;
  border: 0;
  background: transparent;
  color: var(--ink-faint);
  font-family: inherit;
  font-size: 11px;
  font-weight: 600;
  line-height: 18px;
  letter-spacing: 0.06em;
  text-align: center;
  cursor: pointer;
  transition: color 120ms ease, text-shadow 120ms ease, background 120ms ease;
}

.book-gutter-az__btn:hover:not(:disabled) {
  color: var(--naus-cyan);
  text-shadow:
    0 0 6px rgba(5, 217, 232, 0.7),
    0 0 16px rgba(5, 217, 232, 0.25);
  background: rgba(5, 217, 232, 0.08);
}

.book-gutter-az__btn:disabled {
  color: rgba(110, 114, 144, 0.35);
  cursor: default;
}

.book-gutter-az__btn.is-active {
  color: var(--naus-magenta);
  text-shadow:
    0 0 6px rgba(255, 42, 109, 0.75),
    0 0 18px rgba(255, 42, 109, 0.3);
  font-weight: 900;
}

@media print {
  .book-gutter-az { display: none; }
}

/* ============================================================
   "Documented · YYYY-MM-DD" stamp — reads document.lastModified
   (the server-set file mtime). Bottom-right marginal annotation
   in Bleeker's archivist register, so a reader can tell at a
   glance whether the spread they're on is canonical-fresh or
   pre-rewrite. Subtle by design — Share Tech Mono, faint ink.
   ============================================================ */
.book-mtime-stamp {
  position: fixed;
  bottom: 6px;
  right: 10px;
  z-index: 51;
  font-family: 'Share Tech Mono', monospace;
  font-size: 9.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  opacity: 0.5;
  pointer-events: none;
  user-select: none;
  transition: opacity 180ms ease;
}
body:hover > .book-mtime-stamp {
  opacity: 0.85;
}

@media print {
  .book-mtime-stamp { display: none; }
}

/* ============================================================
   Cross-references strip — right-edge vertical column, mirror-
   symmetric with the A→Z gutter on the left. For each character
   spread, shows OTHER chapters that mention this character via
   `<span class="lex">` — clickable, routes via softGlitchTransition.
   Only renders on /03_characters/* spreads with refs in the
   CROSS_REFS map. Faint by default, brightens on hover.
   ============================================================ */
.book-crossrefs {
  position: fixed;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 51;
  display: flex;
  flex-direction: column;
  width: 132px;
  max-height: 60vh;
  padding: 6px 4px 8px;
  border-radius: 12px;
  background: linear-gradient(180deg,
    rgba(10, 13, 28, 0) 0%,
    rgba(10, 13, 28, 0.45) 12%,
    rgba(10, 13, 28, 0.45) 88%,
    rgba(10, 13, 28, 0) 100%);
  font-family: 'Orbitron', sans-serif;
  overflow-y: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.book-crossrefs::-webkit-scrollbar { display: none; }

.book-crossrefs__head {
  font-family: 'Share Tech Mono', monospace;
  font-size: 8.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
  padding: 2px 6px 6px;
  text-align: center;
  border-bottom: 1px dashed rgba(232, 232, 238, 0.12);
  margin-bottom: 4px;
}

.book-crossrefs__chips {
  display: flex;
  flex-direction: column;
}

.book-crossrefs__chip {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 6px;
  padding: 3px 7px;
  text-decoration: none;
  color: var(--ink-faint);
  font-size: 9.5px;
  letter-spacing: 0.04em;
  border-radius: 2px;
  transition: color 120ms ease, background 120ms ease, text-shadow 120ms ease;
}

.book-crossrefs__chip:hover {
  color: var(--naus-cyan);
  background: rgba(5, 217, 232, 0.1);
  text-shadow: 0 0 5px rgba(5, 217, 232, 0.5);
}

.book-crossrefs__name {
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
  min-width: 0;
}

.book-crossrefs__short {
  font-family: 'Share Tech Mono', monospace;
  font-size: 8.5px;
  opacity: 0.7;
  flex-shrink: 0;
}

@media print {
  .book-crossrefs { display: none; }
}

/* ============================================================
   REVISED SPREAD 3 — shared structural blocks.
   Pulled out of inline <style> in each character/faction `_3.html`
   on 2026-05-25 to kill ~3,000 lines of duplication. Every block
   tints from the `.palette-X` wrapper via CSS custom properties,
   so character files keep ONLY their signature-block CSS inline.

   Per-palette overrides:
     --char-marker  — glyph color for capsule row markers; defaults
                      to `--char-warning`. Set in each palette
                      definition (styles/ornaments.css) when the
                      default doesn't match the character's canon.

   Pattern doc: memory/feedback_3_spread_chapter_pattern.md
   ============================================================ */

/* Signature caption — italic Crimson Pro line under each signature
   block. Was previously named per-character (.sig-order-caption /
   .sig-registry-caption / .sig-eightball-caption — all 95% identical). */
.sig-caption {
  font-family: 'Crimson Pro', serif;
  font-style: italic;
  font-size: 13px;
  color: var(--ink-mid);
  text-align: center;
  margin-top: 12px;
  max-width: 540px;
  margin-left: auto;
  margin-right: auto;
  line-height: 1.5;
}
.sig-caption strong {
  color: var(--char-accent);
  font-style: normal;
  font-weight: 600;
}

/* Aliases line — Share Tech caps row showing nicknames/call-signs,
   sits between the signature block and the memorability capsule. */
.aliases-line {
  font-family: 'Share Tech Mono', monospace;
  font-size: 11.5px;
  color: color-mix(in srgb, var(--char-accent) 88%, transparent);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin: 12px 0 4px;
  text-align: center;
}
.aliases-line strong {
  color: var(--ink);
  font-weight: 700;
}

/* Memorability capsule — 6 bible-canonical fields
   (Engine · Wound · Contradiction · Tell · Lane · Heat;
   antagonists get +1 Failure). Tinted by --char-accent;
   row glyph tinted by --char-marker (defaults to --char-warning). */
.mem-capsule {
  background: color-mix(in srgb, var(--char-accent) 4%, transparent);
  border-left: 2px solid var(--char-accent);
  padding: 11px 14px;
  margin: 10px 0 12px;
  font-size: 13.5px;
  line-height: 1.5;
}
.mem-capsule dt {
  font-family: 'Share Tech Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--char-accent);
  display: inline-block;
  min-width: 116px;
}
.mem-capsule dd {
  display: inline;
  color: var(--ink);
  margin: 0;
}
.mem-capsule .row {
  display: block;
  margin-bottom: 5px;
}
.mem-capsule .row:last-child {
  margin-bottom: 0;
}
.mem-capsule .row::before {
  content: "\25B8  ";
  color: var(--char-marker, var(--char-warning));
  font-weight: 700;
}

/* Sensory field — atmosphere italic; closes the LEFT page. */
.sensory-field {
  font-family: 'Crimson Pro', serif;
  font-style: italic;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink-mid);
  padding: 8px 0 0;
  border-top: 1px dashed color-mix(in srgb, var(--char-accent) 28%, transparent);
  margin-top: 6px;
}
.sensory-field strong {
  color: var(--char-accent);
  font-weight: 600;
  font-style: normal;
}

/* Voice samples — bible canonical lines with Disco-Elysium-style
   context labels on RIGHT page. */
.voice-samples {
  margin: 6px 0 14px;
}
.voice-sample {
  margin-bottom: 9px;
  padding-left: 14px;
  border-left: 2px solid color-mix(in srgb, var(--char-accent) 55%, transparent);
}
.voice-sample__ctx {
  display: block;
  font-family: 'Share Tech Mono', monospace;
  font-size: 10.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--char-accent);
  margin-bottom: 2px;
}
.voice-sample__line {
  font-family: 'Spectral SC', 'Crimson Pro', serif;
  font-size: 14px;
  color: var(--ink);
  line-height: 1.4;
  letter-spacing: 0.05em;
}
.voice-sample--maxim .voice-sample__line {
  color: var(--char-accent);
  font-style: italic;
}

/* Habitat block — where you find them; D&D-2024-style first-class
   environment field on the RIGHT page. */
.habitat-block {
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink-mid);
  margin: 10px 0;
  padding: 8px 12px;
  background: color-mix(in srgb, var(--char-accent) 4%, transparent);
  border-left: 2px solid color-mix(in srgb, var(--char-accent) 45%, transparent);
}
.habitat-block strong {
  color: var(--ink);
}

/* Reference strip — closer-as-data, replaces the banned pull-quote.
   Type · OG · Role · Form · Frame · Voice · Faction · Locale. */
.ref-strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px 14px;
  font-family: 'Share Tech Mono', monospace;
  font-size: 10.5px;
  line-height: 1.4;
  padding: 8px 10px;
  margin-top: 6px;
  background: color-mix(in srgb, var(--char-primary) 70%, rgba(0, 0, 0, 0.6));
  border: 1px solid color-mix(in srgb, var(--char-accent) 30%, transparent);
  border-radius: 3px;
}
.ref-strip dt {
  color: var(--char-accent);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-size: 9.5px;
}
.ref-strip dd {
  color: rgba(232, 232, 238, 0.88);
  margin: 0 0 4px;
}
