/*
  ═══════════════════════════════════════════════════════════
  styles.css - Portfolio Bookshelf Styles
  ═══════════════════════════════════════════════════════════

  WHAT:         All visual styles for the bookshelf portfolio
  WHY:          Creates immersive library aesthetic with warm wood tones
  DEPENDENCIES: Google Fonts (Alegreya, Alegreya SC, Cormorant Garamond)
  HOW:          CSS custom properties, 3D transforms, layered shadows

  ═══════════════════════════════════════════════════════════
*/

/* ═══════════════════════════════════════════════════════════
   THE BOOKSHELF - An Immersive Portfolio Experience
   ═══════════════════════════════════════════════════════════

   TABLE OF CONTENTS:
   ------------------
   1. VARIABLES & BASE ........... Line ~54
   2. COLLAPSED NAVIGATION ....... Line ~140
   3. BOOKSHELF SCENE ............ Line ~220
      - Atmosphere & Bulb
      - Books Container
      - Book Spines
      - Shelf Surface & Utility
   4. BOOK VIEW (Open Book) ...... Line ~1550
      - Page Layout
      - Page-Turn Leaf
      - Page Content Styles
   5. ANIMATIONS ................. Line ~3520
   6. RESPONSIVE ................. Line ~3540

   ═══════════════════════════════════════════════════════════ */

*, *::before, *::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

:root {
  /* room */
  --bg: #0a0908;
  --bg-warm: #12100c;
  --wall: #100d0b;
  --wall-edge: #070605;
  --accent: #c4956a;
  --accent-dim: rgba(196, 149, 106, 0.15);
  --accent-glow: rgba(196, 149, 106, 0.3);
  --text: #f5f0e8;
  --text-secondary: #c4b8a8;
  --text-tertiary: #978673; /* was #8a7a6a; 5.6:1 on --bg */

  /* wood + brass */
  --wood-face: #3a2416;
  --wood-top: #5a3a22;
  --wood-lip: #7a5232;  /* the board's lit front edge */
  --wood-edge: #241609;
  --brass-hi: #e6c98c;
  --brass-mid: #b8935a;
  --brass-lo: #6f5230;

  /* leathers */
  --book-work: #5a1e22;
  --book-about: #1f3a44;
  --book-contact: #21402d;
  --book-references: #3a2447;
  --book-colophon: #2a2c33;
  --gilt-hi: #f1dc9a;
  --gilt-mid: #c9a24f;
  --gilt-lo: #7a5a28;
  --pewter: #a9aeb6;

  /* paper */
  --page-bg: #f4efe1;
  --page-text: #26201a;
  --page-secondary: #3d3832;
  --page-tertiary: #5a554c;
  --page-rule: rgba(26, 23, 20, 0.14);
  --paper-hi: #f4efe1;
  --paper-mid: #efe8d6;
  --paper-lo: #e9e0cd;
  --paper-edge: #ddd2bc;
  --paper-pool: radial-gradient(ellipse 78% 55% at 50% 0%, rgba(255, 252, 244, 0.45) 0%, transparent 60%);
  --gutter-width: 4px; /* was 18px */
  --accent-maroon: #800000;
  --accent-gold: #d4a855;

  /* type */
  --font-text: 'Alegreya', 'Alegreya Fallback', 'Iowan Old Style', Georgia, serif;
  --font-sc: 'Alegreya SC', 'Alegreya', 'Alegreya Fallback', serif;
  --font-display: 'Cormorant Garamond', 'Cormorant Fallback', 'Alegreya', serif;
  /* legacy aliases, removed by WP6 once no selector uses them */
  --font-serif: var(--font-display);
  --font-sans: var(--font-text);
  --font-mono: var(--font-sc);

  /* page height the type scale is keyed to (WP1 sets it on
     .book-container; WP3 moves it to .open-book-wrap) */
  --page-h: 660px;

  /* spacing */
  --space-xs: 0.5rem;
  --space-sm: 1rem;
  --space-md: 1.5rem;
  --space-lg: 2.5rem;
  --space-xl: 4rem;

  /* motion */
  --ease-object: cubic-bezier(0.32, 0.72, 0, 1);      /* heavy object coming to rest */
  --ease-hinge: cubic-bezier(0.62, 0.04, 0.30, 0.98); /* board or sheet on a hinge */
  --ease-room: cubic-bezier(0.40, 0, 0.20, 1);        /* ambient: overlays, shadows */
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);     /* buttons only */
  --ease-out-back: cubic-bezier(0.34, 1.56, 0.64, 1); /* legacy; still referenced */
  --ease-in-out: cubic-bezier(0.76, 0, 0.24, 1);      /* legacy; still referenced */
  --ease-tip: cubic-bezier(0.42, 0.03, 0.18, 1);     /* a spine tipping: slow start (mass), no bounce */
  --dur-hover: 420ms;
  --dur-hover-out: 640ms;  /* a tipped book rocks back slower than it tipped */
  --dur-open: 900ms;
  --dur-open-again: 650ms;
  --dur-close: 560ms;
  --dur-close-again: 440ms;
  --dur-open-m: 450ms;
  --dur-close-m: 380ms;
  --dur-turn: 600ms;       /* Decision III */
  --dur-turn-chase: 450ms; /* 0.75 x the single turn */
  --dur-turn-m: 320ms;
  --duration-turn: 0.6s;   /* read by book.js until WP4 renames */
  --ease-page-turn: var(--ease-hinge);
  --duration-fast: 0.2s;   /* WP5 deletes these four */
  --duration-medium: 0.4s;
  --duration-slow: 0.8s;
  --duration-book: 1.2s;

  /* shelf layout: stacked below 1100px, two columns at >= 1100px.
     --spine-h is the tallest volume (Work); the others are --vol-h of it. */
  --spine-h-fluid: clamp(250px, min(100vh - 280px, 78vw), 475px);
  --spine-h: var(--spine-h-fluid);
  --group-u: 0.7997; /* sum of --vol-w x --vol-h; the books stand flush (make-shelf-spines.py) */
  --group-w: calc(var(--spine-h) * var(--group-u));
  --board-w: calc(var(--group-w) + 2 * clamp(30px, 4.5vw, 60px));
  --board-top: 9px;    /* the visible top face of the board: the eye is a little above it */
  --board-front: 21px;
}

@media (min-width: 1100px) {
  :root {
    --spine-h-fluid: clamp(300px, min(100vh - 240px, 42vw), 525px);
  }
}

/* TILE RULE: the spine height snaps DOWN to a multiple of 25px.
   Every spine draws at --spine-h / 1000 CSS px per unit, and its texture
   tiles repeat every 320, 480, 80, 160 and 120 units. A tile's size on
   screen is (tile units) x (px per unit) x DPR device pixels, and that must
   be an integer, or Chrome resamples each repeat at a drifting sub-pixel
   phase and the lower part of every tile goes soft. With --spine-h = 25k
   px the tiles are 8k, 12k, 2k, 4k and 3k CSS px: whole pixels at DPR 1,
   2 and 3. At DPR 1.5 only periods that are multiples of 80 units stay
   whole; the 40 x 120-unit joint tile does not when k is odd. Rounding down,
   never up, keeps every layout budget.
   If you resize the shelf, keep the snap; if you add a tile, give it a
   period in units that is a multiple of 40. Without round() support the
   fluid value is used and the tiles only lose a little crispness. */
@supports (width: round(down, 101px, 25px)) {
  :root {
    --spine-h: round(down, var(--spine-h-fluid), 25px);
  }
}

/* Page type scale, keyed to page height. A custom property's var()
   resolves where it is declared, so the scale is declared again on the
   element that sets --page-h; declared on :root alone it would freeze at
   the default height. */
:root,
.book-container {
  --t-xs: clamp(13px, calc(var(--page-h) * 0.0197), 14px);
  --t-sm: clamp(14.5px, calc(var(--page-h) * 0.0235), 15.5px);
  --t-md: clamp(16px, calc(var(--page-h) * 0.0265), 18px);
  --t-lg: clamp(19px, calc(var(--page-h) * 0.0333), 22px);
  --t-xl: clamp(22px, calc(var(--page-h) * 0.0394), 26px);
  --t-2xl: clamp(30px, calc(var(--page-h) * 0.0576), 38px);
  --t-3xl: clamp(38px, calc(var(--page-h) * 0.0788), 52px);
  --t-num: clamp(64px, calc(var(--page-h) * 0.1576), 104px);
  --v1: calc(var(--t-md) * 1.5);
  --v-half: calc(var(--v1) / 2);
  --v2: calc(var(--v1) * 2);
}

/* Metric-matched local fallbacks so the web fonts swap in without a
   reflow. Two blocks per family: one size-adjust cannot fit both
   Iowan Old Style (macOS) and Georgia (Windows). */
@font-face {
  font-family: 'Alegreya Fallback';
  src: local('Iowan Old Style');
  size-adjust: 103%;
  ascent-override: 96%;
  descent-override: 28%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Alegreya Fallback';
  src: local('Georgia');
  size-adjust: 97%;
  ascent-override: 94%;
  descent-override: 26%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Cormorant Fallback';
  src: local('Iowan Old Style');
  size-adjust: 90%;
  ascent-override: 92%;
  descent-override: 26%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Cormorant Fallback';
  src: local('Georgia');
  size-adjust: 88%;
  ascent-override: 92%;
  descent-override: 26%;
  line-gap-override: 0%;
}

html {
  font-size: 16px;
  overflow-x: hidden;
  overscroll-behavior-x: none;
}

body {
  font-family: var(--font-text);
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
  overflow-x: hidden;
  overscroll-behavior-x: none;
  -webkit-font-smoothing: antialiased;
}

::selection {
  background: var(--accent);
  color: var(--bg);
}

/* ═══════════════════════════════════════════════════════════
   COLLAPSED NAVIGATION
   ═══════════════════════════════════════════════════════════ */

.collapsed-nav {
  position: fixed;
  top: var(--space-md);
  left: var(--space-md);
  z-index: 1000;
  opacity: 0;
  transform: translateX(-10px);
  visibility: hidden;
  transition: transform var(--duration-slow) var(--ease-out-expo),
              opacity var(--duration-slow) var(--ease-out-expo),
              visibility 0s var(--duration-slow);
}

.collapsed-nav.is-visible {
  transform: translateX(0);
  opacity: 1;
  visibility: visible;
  transition-delay: 0s;
}

/* Narrow desktop windows: the open book reaches x 60, under the top-left
   Shelf button, so the button drops to the bottom-left corner */
@media (min-width: 901px) and (max-width: 1340px) {
  .collapsed-nav {
    top: auto;
    bottom: 20px;
  }
}

.nav-shelf-btn {
  height: 36px;
  padding: 0 var(--space-sm) 0 var(--space-xs);
  background: transparent;
  border: 1px solid var(--text-tertiary);
  border-radius: 2px;
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  transition: border-color var(--duration-fast) var(--ease-out-expo),
              color var(--duration-fast) var(--ease-out-expo);
}

.nav-shelf-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.nav-shelf-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.nav-shelf-btn svg {
  width: 16px;
  height: 16px;
}

.nav-books {
  display: flex;
  gap: var(--space-md);
}

.nav-book-btn {
  background: transparent;
  border: none;
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding: var(--space-xs) var(--space-sm);
  transition: color var(--duration-fast) var(--ease-out-expo);
}

.nav-book-btn:hover,
.nav-book-btn.is-active {
  color: var(--accent);
}

.nav-book-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ═══════════════════════════════════════════════════════════
   BOOKSHELF SCENE
   A page with one lit shelf on it: the stage (spines on a walnut
   board under a top light) and, beside it at >= 1100px or under it
   below that, the name, role, three facts and the fast-path links.
   Nothing on the shelf loops; hover is the only motion at rest.
   ═══════════════════════════════════════════════════════════ */

/* The shared spine paint (gradients, tiles, tool symbols) takes no space */
.svg-defs {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.bookshelf-scene {
  position: relative;
  isolation: isolate;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 34px;
  padding: 24px 16px;
  overflow: hidden;
  background: radial-gradient(ellipse 90% 70% at 50% 40%, var(--wall) 0%, var(--wall-edge) 100%);
  transition: opacity var(--duration-book) var(--ease-in-out); /* the hide fade; WP5 replaces it */
}

.bookshelf-scene.is-hidden {
  opacity: 0;
  pointer-events: none;
}

/* The entrance is CSS-only, so first paint is dim, never bright-then-dark:
   the room starts at .85 dark and the light comes up. The text column
   sits above this layer, so the facts are readable from the first frame. */
.scene-dim {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: var(--bg);
  opacity: 0;
  pointer-events: none;
  /* backwards, not forwards: the .85 start holds through the delay, and
     once the animation ends the layer falls back to its base opacity: 0.
     A finished fill-forwards opacity animation stays composited forever. */
  animation: sceneLight 520ms var(--ease-room) 80ms backwards;
}

@keyframes sceneLight {
  from { opacity: 0.85; }
  to { opacity: 0; }
}

.shelf-stage {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* The only evidence of the light, and the wall's plaster, on one box.

   The pool is a warm radial gradient from above the frame. The plaster is a
   dark-only, band-limited tile (scripts/tools/make-textures.py), baked at its
   final strength and drawn at 1. Black on purpose: the wall's darkest pixel
   is below the shared DARK tone, so any lighter tone could only lighten it,
   and light points on near-black read as dust on the glass. 128 CSS px =
   384 / 256 / 128 device px at DPR 3 / 2 / 1, all integer.

   The plaster must paint ABOVE the pool, otherwise the lamp washes it out
   where the wall is most looked at. So both live on this box, the plaster as
   the top layer. The box reaches past every edge of the scene, which clips
   it, so there is one plaster layer everywhere and no seam. The pool layer
   keeps its old rect: 2.8x the stage wide and centred, from 320px above the
   stage, --spine-h + 460px tall. 2.8x the stage = 280% of the box less 5.6
   reaches, because the box is the stage plus one reach on each side. */
.shelf-stage::before {
  --reach-x: 100vw;
  --reach-y: 300vh;
  content: '';
  position: absolute;
  inset: calc(-1 * var(--reach-y)) calc(-1 * var(--reach-x));
  pointer-events: none;
  background:
    url(assets/textures/wall-plaster-128.png) 0 0 / 128px 128px,
    radial-gradient(
      34% calc((var(--spine-h) + 130px) * 0.95) at 50% 250px,
      rgba(255, 196, 130, 0.20) 0%,
      rgba(255, 186, 120, 0.125) 24%,
      rgba(255, 180, 110, 0.065) 48%,
      rgba(255, 180, 110, 0.025) 70%,
      rgba(255, 180, 110, 0.007) 86%,
      transparent 100%
    ) 50% calc(var(--reach-y) - 320px) / calc(280% - 5.6 * var(--reach-x)) calc(var(--spine-h) + 460px) no-repeat;
}

/* ─── Shadows: anchored at the group's centre, on the board's top edge ── */

/* Painted, not computed: baked sprites, no filters. The spans carry each
   book's x0, width, height and lamp offset u from make-shelf-spines.py. */
.wall-shadows,
.ground-shadows {
  position: absolute;
  left: 50%;
  bottom: calc(var(--board-top) + var(--board-front));
  width: 0;
  height: 0;
  pointer-events: none;
}

.wall-shadows {
  z-index: 1;
}

.ground-shadows {
  z-index: 3;
}

/* Each book's shadow on the wall: its own rect, pushed away from the lamp
   (x by --u) and down (the lamp is above and in front). The 9-slice keeps
   the penumbra one width on every book. */
.wall-shadows > span {
  position: absolute;
  bottom: -6px;
  left: calc((var(--x0) - var(--group-u) / 2) * var(--spine-h) - 6px);
  width: calc(var(--bw) * var(--spine-h) + 12px);
  height: calc(var(--bh) * var(--spine-h) - 4px);
  transform: translate(calc(var(--u) * 18px), 17px);
  border-image: url(assets/textures/shadow-soft-96.png) 40 fill / 40px stretch;
  border-width: 40px;
  border-style: solid;
  /* the end volumes (Work, Colophon) throw a darker flank than Contact */
  opacity: calc(0.78 + 0.14 * var(--au));
}

/* The row settles on one continuous shadow along the ledge ... */
.ground-shadows::before {
  content: '';
  position: absolute;
  top: 0;
  left: calc(-0.5 * var(--group-w) - 8px);
  width: calc(var(--group-w) + 16px);
  height: var(--board-top);
  background: linear-gradient(180deg, rgba(0, 0, 0, 0.42), rgba(0, 0, 0, 0.12) 55%, transparent);
}

/* ... and each spine has a contact shadow where it meets the board */
.ground-shadows > span {
  position: absolute;
  top: -1px;
  left: calc((var(--x0) - var(--group-u) / 2) * var(--spine-h) - 3px);
  width: calc(var(--bw) * var(--spine-h) + 6px);
  height: calc(var(--board-top) + 4px);
  background: url(assets/textures/contact-256x48.png) 0 0 / 100% 100% no-repeat;
  opacity: 0.85;
}

/* ─── Spines ─────────────────────────────────────────────── */

.books {
  position: relative;
  z-index: 2;
  display: flex;
  justify-content: center;
  align-items: flex-end;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  perspective: 1400px;
}

.books > li {
  display: contents;
}

.book {
  appearance: none;
  position: relative;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
  transform: none;
  transform-origin: 50% 100%;
  transition: transform var(--dur-hover-out) cubic-bezier(0.3, 0.55, 0.25, 1);
  -webkit-tap-highlight-color: transparent;
}

/* Hover tips the volume forward on its tail edge. It does not lift (a
   tipped book does not rise off the board), it starts slowly because it
   has mass, never bounces, and rocks back slower than it tipped. */
.book:hover,
.book:focus-visible {
  z-index: 3;
  transform: rotateX(-7deg);
  transition-duration: var(--dur-hover);
  transition-timing-function: var(--ease-tip);
}

/* Touch has no hover: a press gives the settle and the spreading shadow */
.book:active {
  transform: rotateX(-2.5deg);
  transition-duration: 110ms;
}

.book:active .book-shadow {
  opacity: 0.55;
  transition-duration: 110ms;
}

.book:active .tip-lit {
  opacity: 0.4;
  transition-duration: 110ms;
}

.book:focus {
  outline: none;
}

/* Ring the visible spine, not the taller button box, so the ring stays
   above the board's top edge */
.book:focus-visible {
  outline: none;
}

.book:focus-visible .spine {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
  border-radius: 2px;
}

/* Every spine draws at --spine-h / 1000 px per unit (viewBox H = 1000 x
   --vol-h, W = H x --vol-w), so the box and the viewBox share one scale.
   Its shadow is painted on the wall (.wall-shadows), not a box-shadow,
   because the silhouette is rounded. */
.spine {
  display: block;
  height: calc(var(--spine-h) * var(--vol-h));
  width: calc(var(--spine-h) * var(--vol-h) * var(--vol-w));
  overflow: visible;
}

/* Lettered lengthwise in gilt: one <text> per title, sized in spine units */
.spine-title {
  font: 600 calc(1px * var(--title-u)) var(--font-display);
  letter-spacing: 0.18em;
  font-kerning: normal;
}

/* The tipped face turns up toward the lamp (the overlay is in the SVG) */
.tip-lit {
  opacity: 0;
  transition: opacity var(--dur-hover-out) var(--ease-room);
}

.book:hover .tip-lit,
.book:focus-visible .tip-lit {
  opacity: 1;
  transition-duration: var(--dur-hover);
}

/* The tipped book's shadow spreads forward on the board */
.book-shadow {
  position: absolute;
  left: -14px;
  right: -14px;
  bottom: -18px;
  height: 30px;
  z-index: -1;
  opacity: 0;
  pointer-events: none;
  border-image: url(assets/textures/shadow-soft-96.png) 40 fill / 40px stretch;
  border-width: 40px;
  border-style: solid;
  transition: opacity var(--dur-hover-out) var(--ease-room);
}

.book:hover .book-shadow,
.book:focus-visible .book-shadow {
  opacity: 0.8;
  transition-duration: var(--dur-hover);
}

/* ─── The board ──────────────────────────────────────────── */

/* Walnut: a top face seen from a little above, a lit lip and the front
   face. The lamp falls off toward both ends, on the top face more than on
   the front. */
.shelf-board {
  position: relative;
  width: var(--board-w);
  max-width: 100%;
  height: calc(var(--board-top) + var(--board-front));
  border-radius: 0 0 2px 2px;
  background:
    linear-gradient(90deg, rgba(0, 0, 0, 0.34) 0, rgba(0, 0, 0, 0.1) 22%, transparent 42%, transparent 58%, rgba(0, 0, 0, 0.1) 78%, rgba(0, 0, 0, 0.34) 100%) 0 0 / 100% var(--board-top) no-repeat,
    linear-gradient(90deg, rgba(0, 0, 0, 0.22) 0, transparent 25%, transparent 75%, rgba(0, 0, 0, 0.22) 100%) 0 var(--board-top) / 100% var(--board-front) no-repeat,
    linear-gradient(180deg,
      #6a4529 0, #5e3d24 var(--board-top),
      var(--wood-lip) var(--board-top), #4a2f1c calc(var(--board-top) + 2px),
      var(--wood-face) calc(var(--board-top) + 6px), #2e1c10 100%);
  box-shadow: inset 0 1px 0 rgba(255, 214, 170, 0.18), 0 8px 18px -4px rgba(0, 0, 0, 0.6);
}

.shelf-board::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: rgba(0, 0, 0, 0.5);
}

/* The board's shadow on the wall */
.shelf-board::after {
  content: '';
  position: absolute;
  left: -8%;
  right: -8%;
  top: 100%;
  height: 56px;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(ellipse 56% 100% at 50% 0%, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0.24) 45%, transparent 100%);
}

/* ─── Name, role, facts, links ───────────────────────────── */

.shelf-text {
  position: relative;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  width: min(100%, 36rem);
  text-align: center;
  container-type: inline-size; /* the role line breaks by the column's width, below */
}

.shelf-name {
  margin: 0;
  font: 500 30px/1.12 var(--font-display);
  letter-spacing: 0.02em;
  color: #ecdfc8;
}

/* Small caps throughout (the text is lowercased so capitals and
   acronyms set as small caps too, not as full caps among them) */
.shelf-title {
  margin: 0;
  font: 400 14px/1.45 var(--font-sc);
  letter-spacing: 0.1em;
  text-transform: lowercase;
  color: var(--text-secondary); /* name, then role, then the links */
}

.shelf-title-part {
  display: block;
  white-space: nowrap;
}

.shelf-title-sep {
  display: none;
}

/* The role takes one line only where the column holds all of it;
   otherwise it breaks after the employer, never shrinks */
@container (min-width: 480px) {
  .shelf-title-part {
    display: inline;
  }

  .shelf-title-sep {
    display: inline;
  }
}

.shelf-facts {
  margin: 0;
  font: 400 15px/1.45 var(--font-text);
  color: var(--text-secondary);
  text-wrap: balance;
}

.shelf-facts .fact {
  white-space: nowrap;
}

.shelf-facts .sep {
  margin: 0 0.2em;
  color: var(--accent);
}

/* narrow column: one fact per line, so no line ends on a dangling dot */
@container (max-width: 399px) {
  .shelf-facts .fact {
    display: block;
  }

  .shelf-facts .sep {
    display: none;
  }
}

.shelf-utility {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0 6px;
  margin-top: 6px;
}

.shelf-utility-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 8px;
  font: 400 15px/1 var(--font-sc);
  letter-spacing: 0.1em;
  text-transform: lowercase;
  color: var(--text-tertiary); /* the quietest line until hovered */
  text-decoration: none;
  transition: color var(--dur-hover-out) var(--ease-room);
}

.shelf-utility-link:hover {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
}

.shelf-utility-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}

.shelf-utility-sep {
  font: 400 15px/1 var(--font-text);
  color: var(--text-tertiary);
  user-select: none;
}

/* ─── Two columns: a page with a shelf on it ─────────────── */

@media (min-width: 1100px) {
  .bookshelf-scene {
    /* the shelf and the text are one group, centred on the page; the
       text column gives way first (down to 320px) when space runs out */
    display: grid;
    grid-template-columns: auto minmax(320px, 30rem);
    justify-content: center;
    column-gap: clamp(56px, 6vw, 96px);
    align-items: center;
    padding: 24px clamp(32px, 6vw, 120px);
  }

  .shelf-text {
    align-items: flex-start;
    justify-self: start;
    gap: 12px;
    width: 100%;
    margin-top: calc(var(--spine-h) * 0.07); /* optical centre: the block sits a little below the books' mid-height */
    text-align: left;
  }

  .shelf-name {
    font-size: clamp(36px, 3.2vw, 44px);
    line-height: 1.1;
  }

  .shelf-facts {
    font-size: clamp(15px, 1.1vw, 17px);
  }

  .shelf-utility {
    justify-content: flex-start;
    margin: 10px 0 0 -8px;
  }

  .shelf-utility-link {
    min-height: 32px;
  }
}

/* ─── Phones and tablets ─────────────────────────────────── */

@media (max-width: 900px) {
  .bookshelf-scene {
    gap: 24px;
    padding: 20px 12px;
    max-width: 100%;
    overflow-x: hidden;
  }

  /* The spines stand flush, as at every width: each is >= 24px wide
     (Colophon 32px at 390), which meets WCAG 2.5.8 without padding */
  .shelf-stage {
    --board-top: 7px;
    --board-front: 17px;
  }

  /* the board overhangs the spines by 26px. A plain calc() capped by the
     base max-width: 100%, not min(..., 100%): the percentage inside min()
     is cyclic, so the stage would shrink-wrap to the books */
  .shelf-board {
    width: calc(var(--group-w) + 2 * 26px);
  }

  .shelf-name {
    font-size: 26px;
  }

  .shelf-title {
    font-size: 13px;
  }

  .shelf-utility-link {
    min-width: 44px;
    justify-content: center;
  }
}

@media (prefers-reduced-motion: reduce) {
  .scene-dim {
    animation: none;
    opacity: 0;
  }

  .book,
  .tip-lit,
  .book-shadow {
    transition: none;
  }

  .book:hover,
  .book:focus-visible,
  .book:active {
    transform: none;
  }

  /* the ground shadow and the lit face follow the tip, so no tip means neither */
  .book:hover .book-shadow,
  .book:focus-visible .book-shadow,
  .book:active .book-shadow,
  .book:hover .tip-lit,
  .book:focus-visible .tip-lit,
  .book:active .tip-lit {
    opacity: 0;
  }
}

/* ═══════════════════════════════════════════════════════════
   BOOK VIEW (Open Book State)
   ═══════════════════════════════════════════════════════════ */

.book-view {
  position: fixed;
  inset: 0;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: var(--space-md);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0.3s ease;
}

.book-view.is-visible {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  cursor: pointer;
}

/* Book container shouldn't trigger close */
.book-view .book-container,
.book-view .page-nav {
  cursor: default;
}

/* Warm ambient light from above, continuing the shelf's top light */
.book-view::before {
  content: '';
  position: fixed;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 800px;
  height: 500px;
  background: radial-gradient(
    ellipse 60% 80% at 50% 0%,
    rgba(255, 190, 130, 0.12) 0%,
    rgba(255, 170, 100, 0.06) 40%,
    transparent 70%
  );
  pointer-events: none;
  z-index: 0;
}

/* Book Container */
.book-container {
  display: flex;
  align-items: center;
  justify-content: center;
  max-width: 1200px;
  width: 100%;
  height: calc(100vh - 140px);
  max-height: 800px;
  --page-h: min(calc(100vh - 140px), 800px); /* the .open-book height, capped as max-height is; WP3 moves it to .open-book-wrap */
  perspective: 1800px;
  perspective-origin: 50% 45%;
}

/* Page Edge Effects - solid cover with page edges */
.page-edge {
  width: 20px;
  height: 92%;
  flex-shrink: 0;
  position: relative;
  display: flex;
}

/* Left edge: Cover (outer) + Pages (inner) */
.page-edge-left {
  border-radius: 4px 0 0 4px;
  overflow: hidden;
}

/* Solid cover portion - left */
.page-edge-left::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 10px;
  background: var(--book-work);
  border-radius: 4px 0 0 4px;
  box-shadow: 
    inset -2px 0 4px rgba(0, 0, 0, 0.4),
    inset 2px 0 3px rgba(255, 255, 255, 0.1);
}

/* Page edges portion - left */
.page-edge-left::after {
  content: '';
  position: absolute;
  right: 0;
  top: 2px;
  bottom: 2px;
  width: 10px;
  background:
    /* two soft warm leaf-line periods overlaid → irregular stacked paper */
    repeating-linear-gradient(
      to bottom,
      transparent 0px,
      rgba(120, 95, 60, 0.11) 1.5px,
      transparent 4px
    ),
    repeating-linear-gradient(
      to bottom,
      transparent 0px,
      rgba(90, 70, 45, 0.06) 2px,
      transparent 6.5px
    ),
    linear-gradient(90deg, #cdc2ab 0%, #efe7d6 100%);
  box-shadow: inset 2px 0 3px rgba(0, 0, 0, 0.1);
}

/* Right edge: Pages (inner) + Cover (outer) */
.page-edge-right {
  border-radius: 0 4px 4px 0;
  overflow: hidden;
}

/* Page edges portion - right */
.page-edge-right::before {
  content: '';
  position: absolute;
  left: 0;
  top: 2px;
  bottom: 2px;
  width: 10px;
  background:
    /* two soft warm leaf-line periods overlaid → irregular stacked paper */
    repeating-linear-gradient(
      to bottom,
      transparent 0px,
      rgba(120, 95, 60, 0.11) 1.5px,
      transparent 4px
    ),
    repeating-linear-gradient(
      to bottom,
      transparent 0px,
      rgba(90, 70, 45, 0.06) 2px,
      transparent 6.5px
    ),
    linear-gradient(90deg, #efe7d6 0%, #cdc2ab 100%);
  box-shadow: inset -2px 0 3px rgba(0, 0, 0, 0.1);
}

/* Solid cover portion - right */
.page-edge-right::after {
  content: '';
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  width: 10px;
  background: var(--book-work);
  border-radius: 0 4px 4px 0;
  box-shadow: 
    inset 2px 0 4px rgba(0, 0, 0, 0.4),
    inset -2px 0 3px rgba(255, 255, 255, 0.1);
}

/* Overall edge shadows */
.page-edge-left {
  box-shadow: -4px 0 12px rgba(0, 0, 0, 0.35);
}

.page-edge-right {
  box-shadow: 4px 0 12px rgba(0, 0, 0, 0.35);
}

/* Book-specific cover colors */
.book-view[data-active-book="work"] .page-edge-left::before,
.book-view[data-active-book="work"] .page-edge-right::after {
  background: var(--book-work);
}

.book-view[data-active-book="about"] .page-edge-left::before,
.book-view[data-active-book="about"] .page-edge-right::after {
  background: var(--book-about);
}

.book-view[data-active-book="contact"] .page-edge-left::before,
.book-view[data-active-book="contact"] .page-edge-right::after {
  background: var(--book-contact);
}

.book-view[data-active-book="references"] .page-edge-left::before,
.book-view[data-active-book="references"] .page-edge-right::after {
  background: var(--book-references);
}

.book-view[data-active-book="colophon"] .page-edge-left::before,
.book-view[data-active-book="colophon"] .page-edge-right::after {
  background: var(--book-colophon);
}

/* Open Book - mild V shape like holding a real book */
.open-book {
  flex: 1;
  height: 100%;
  min-height: 500px; /* Ensure readable height on ultrawide monitors */
  display: flex;
  background: var(--page-bg);
  box-shadow:
    /* Soft ambient shadow - furthest */
    0 25px 60px rgba(0, 0, 0, 0.25),
    /* Medium spread shadow */
    0 15px 35px rgba(0, 0, 0, 0.2),
    /* Tight contact shadow */
    0 5px 15px rgba(0, 0, 0, 0.15),
    /* Soft glow for depth */
    0 0 80px rgba(0, 0, 0, 0.2);
  position: relative;
  z-index: 1;
  transform-style: preserve-3d;
  isolation: isolate; /* contain the 3D leaf's stacking context (Safari) */
}

/* Warm light hitting the top of the book */
.open-book::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 150px;
  background: linear-gradient(
    180deg,
    rgba(255, 200, 150, 0.08) 0%,
    rgba(255, 190, 140, 0.03) 50%,
    transparent 100%
  );
  pointer-events: none;
  z-index: 10;
  border-radius: 2px 2px 0 0;
}

/* Pages */
.page {
  flex: 1;
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  background:
    /* Top-lit pool over a warm parchment gradient */
    var(--paper-pool),
    linear-gradient(
      180deg,
      var(--paper-hi) 0%,
      var(--paper-mid) 50%,
      var(--paper-lo) 100%
    );
}

/* Book margins, shared by the static pages and the turning leaf's faces
   so a turn never shows a padding jump (WP4 keeps these selectors).
   Tschichold-lite: narrow inner, wide outer, deeper foot than head.
   The margins are fractions of the spread (the .page containing block).
   They are written in cqw against .open-book so the leaf faces, whose
   containing block is only half the spread, resolve to the same pixels,
   and so the running heads and folios (top/left resolve against the
   page, not the spread) line up with the text block. */
.open-book {
  container-type: inline-size;
}

.page,
.turn-leaf-face {
  /* the spread the margins are measured against: the real spread, but
     never wider than two 0.72 pages of this height (WP3's proportion) */
  --spread-w: min(100cqw, var(--page-h) * 1.44 + var(--gutter-width));
  --m-in: calc(var(--spread-w) * 0.065);
  --m-out: calc(var(--spread-w) * 0.11);
  --m-top: calc(var(--spread-w) * 0.06);
  --m-bot: calc(var(--spread-w) * 0.095);
  /* How far a chapter opening sinks below the head margin: the page's
     spare height, not a % (which resolves against the width): ~50px on a
     760px page, ~25px at 580, 0 below ~400, so a short page never pushes
     its foot off the page. Shared by chapter versos and the title page. */
  --chapter-drop: calc(var(--m-top) + clamp(0px, var(--page-h) * 0.14 - 56px, 92px));
}

.page-left,
.turn-leaf-face.is-left {
  padding: var(--m-top) var(--m-in) var(--m-bot) var(--m-out);
}

.page-right,
.turn-leaf-face.is-right {
  padding: var(--m-top) var(--m-out) var(--m-bot) var(--m-in);
}

/* Book-grade text rendering on the parchment: kerning, ligatures,
   hyphenation, balanced rag and oldstyle figures (Alegreya default).
   The leaf faces match so a turn never rewraps a line. */
.page,
.turn-leaf-face {
  -webkit-font-smoothing: auto;
  font-kerning: normal;
  font-variant-ligatures: common-ligatures;
  font-variant-numeric: oldstyle-nums;
  hyphens: auto;
  hyphenate-limit-chars: 7 4 3;
  -webkit-hyphenate-limit-before: 4; /* Safari */
  -webkit-hyphenate-limit-after: 3;
  -webkit-hyphenate-limit-lines: 2; /* Safari: no two hyphens in a row */
  text-wrap: pretty;
  text-rendering: optimizeLegibility;
}

/* Display lines and short list values never hyphenate: a broken word in
   a tagline, summary, lead, quote or two-line value reads as a typo.
   Body copy keeps hyphens: auto. */
.page h2,
.turn-leaf-face h2,
.role-tagline,
.chapter-summary,
.about-lead,
.reference-role,
.reference-context,
.contact-note,
.quote-text,
.toc-entry-meta,
.currently-value,
.technical-skills,
.chapter-backing {
  hyphens: manual;
}

/* Paper tooth: a dark-only pre-rendered tile, baked and drawn at 1, no blend
   (spec G9: no live filters, no blend modes). 128 CSS px is an integer
   device-px tile at every DPR. Overlays the copy, which it darkens by <= 2 levels. */
.page::after {
  content: '';
  position: absolute;
  inset: 0;
  background: url(assets/textures/paper-tooth-128.png) 0 0 / 128px 128px;
  pointer-events: none;
}

/* Left page - flat at rest (crisp text); depth comes from the inset gutter
   shadow + falloff gradient, not a 3D tilt */
.page-left {
  border-right: none;
  box-shadow:
    inset -30px 0 40px -12px rgba(0, 0, 0, 0.22),
    inset -5px 0 10px -2px rgba(0, 0, 0, 0.12);
  background:
    /* Top-lit pool + light falloff toward the spine */
    var(--paper-pool),
    linear-gradient(
      90deg,
      var(--paper-hi) 0%,
      var(--paper-mid) 60%,
      var(--paper-edge) 100%
    ),
    linear-gradient(180deg, var(--paper-hi) 0%, var(--paper-lo) 100%);
}

/* Right page - flat at rest (crisp text); depth comes from the inset gutter
   shadow + falloff gradient, not a 3D tilt */
.page-right {
  border-left: none;
  box-shadow:
    inset 30px 0 40px -12px rgba(0, 0, 0, 0.22),
    inset 5px 0 10px -2px rgba(0, 0, 0, 0.12);
  background:
    /* Top-lit pool + light falloff toward the spine */
    var(--paper-pool),
    linear-gradient(
      90deg,
      var(--paper-edge) 0%,
      var(--paper-mid) 40%,
      var(--paper-hi) 100%
    ),
    linear-gradient(180deg, var(--paper-hi) 0%, var(--paper-lo) 100%);
}

/* Page Content Area */
.page-content {
  font-family: var(--font-text);
  font-size: var(--t-md);
  line-height: 1.5;
  color: var(--page-text);
  max-width: 34em;
  flex: 1;
  min-height: 0; /* Safari flexbox fix */
  overflow-y: auto; /* a page that cannot hold its copy scrolls; it never clips */
}

/* A scrolling page fades its cut line into the foot margin instead of
   slicing it; the fade lifts once the reader reaches the end.
   (book.js markOverflow sets the classes.) */
.page-content.is-overflowing:not(.is-at-end) {
  -webkit-mask-image: linear-gradient(#000 calc(100% - var(--v1)), transparent);
  mask-image: linear-gradient(#000 calc(100% - var(--v1)), transparent);
}

/* An always-visible 6px thumb on the scrolling page. Chromium honours
   these only while scrollbar-width / scrollbar-color are unset, and the
   standard macOS overlay scrollbar hides itself at rest. */
.page-content::-webkit-scrollbar {
  width: 6px;
}

.page-content::-webkit-scrollbar-track {
  background: transparent;
}

.page-content::-webkit-scrollbar-thumb {
  background: rgba(42, 37, 32, 0.28);
  border-radius: 3px;
}

.page-content::-webkit-scrollbar-thumb:hover {
  background: rgba(42, 37, 32, 0.45);
}

/* Page Curl Effect - Interactive page turn triggers */
.page-curl {
  position: absolute;
  bottom: 0;
  width: 80px;
  height: 80px;
  pointer-events: auto;
  cursor: pointer;
  transition: transform var(--duration-fast) var(--ease-out-expo),
              filter var(--duration-fast) var(--ease-out-expo);
  z-index: 10;
}

.page-curl:hover {
  transform: scale(1.1);
  filter: brightness(0.95);
}

.page-curl:active {
  transform: scale(1.05);
}

.page-curl.is-disabled {
  pointer-events: none;
  opacity: 0.3;
  cursor: default;
}

.page-curl:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.page-left .page-curl {
  left: 0;
  background:
    /* Paper underside — exposed by curl */
    radial-gradient(
      circle at 0% 100%,
      #d5cdc0 0%,
      #e0d8cc 12%,
      #ebe5db 22%,
      transparent 23%
    ),
    /* Shadow cast by lifted paper edge */
    radial-gradient(
      circle at 0% 100%,
      transparent 22%,
      rgba(0, 0, 0, 0.08) 23%,
      rgba(0, 0, 0, 0.03) 32%,
      transparent 42%
    );
}

.page-left .page-curl:hover {
  transform: scale(1.1) rotate(-3deg);
}

.page-right .page-curl {
  right: 0;
  background:
    /* Paper underside — exposed by curl */
    radial-gradient(
      circle at 100% 100%,
      #d5cdc0 0%,
      #e0d8cc 12%,
      #ebe5db 22%,
      transparent 23%
    ),
    /* Shadow cast by lifted paper edge */
    radial-gradient(
      circle at 100% 100%,
      transparent 22%,
      rgba(0, 0, 0, 0.08) 23%,
      rgba(0, 0, 0, 0.03) 32%,
      transparent 42%
    );
}

.page-right .page-curl:hover {
  transform: scale(1.1) rotate(3deg);
}

/* Folios - bottom, outer corner of the text block, oldstyle figures */
.page-number {
  position: absolute;
  bottom: calc(var(--m-bot) / 2 - 0.5em);
  font-family: var(--font-text);
  font-size: var(--t-sm);
  font-variant-numeric: oldstyle-nums;
  line-height: 1;
  color: var(--page-secondary);
  pointer-events: none;
}

.page-number-left {
  left: var(--m-out);
}

.page-number-right {
  right: var(--m-out);
}

/* Running heads - verso: the book's title; recto: the chapter (the
   left page's [data-running-head]). Centred over the text block in the
   head margin. */
.running-header {
  position: absolute;
  top: calc(var(--m-top) / 2);
  transform: translateY(-50%);
  text-align: center;
  white-space: nowrap;
  font-family: var(--font-sc);
  font-size: var(--t-xs);
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.14em;
  color: var(--page-secondary);
  pointer-events: none;
}

.running-header-left {
  left: var(--m-out);
  right: var(--m-in);
}

.running-header-right {
  left: var(--m-in);
  right: var(--m-out);
}

/* Center Spine - the gutter crease where the two pages dive into the
   binding: a smooth shadow valley (darkest at the centre fold) over the
   page colour, no stitching stripes */
.book-spine-center {
  width: var(--gutter-width);
  background:
    linear-gradient(
      90deg,
      rgba(24, 15, 6, 0.06) 0%,
      rgba(24, 15, 6, 0.20) 32%,
      rgba(24, 15, 6, 0.34) 50%,
      rgba(24, 15, 6, 0.20) 68%,
      rgba(24, 15, 6, 0.06) 100%
    ),
    var(--page-bg);
  box-shadow:
    inset 9px 0 16px -8px rgba(0, 0, 0, 0.4),
    inset -9px 0 16px -8px rgba(0, 0, 0, 0.4);
  flex-shrink: 0;
  position: relative;
}

/* Spine highlight from above */
.book-spine-center::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 60px;
  background: linear-gradient(
    180deg,
    rgba(255, 220, 180, 0.15) 0%,
    transparent 100%
  );
  pointer-events: none;
}

/* ═══════════════════════════════════════════════════════════
   PAGE-TURN LEAF (single-leaf 3D flip engine)
   A reusable leaf flips about the spine; its faces carry the page
   we turn from (front) and land on (back). Static pages stay flat
   and crisp. All timing is driven from JS via the Web Animations
   API reading --duration-turn / --ease-page-turn, so there is no
   setTimeout-vs-CSS drift.
   ═══════════════════════════════════════════════════════════ */

/* Dynamic shadow overlays — one per static half, opacity driven by JS */
.page-shadow {
  position: absolute;
  top: 0;
  bottom: 0;
  width: calc((100% - var(--gutter-width)) / 2);
  pointer-events: none;
  opacity: 0;
  z-index: 4;
}

.page-shadow-left {
  left: 0;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(20, 12, 4, 0.05) 55%,
    rgba(20, 12, 4, 0.30) 100%
  );
}

.page-shadow-right {
  left: calc(50% + var(--gutter-width) / 2);
  background: linear-gradient(
    270deg,
    transparent 0%,
    rgba(20, 12, 4, 0.05) 55%,
    rgba(20, 12, 4, 0.30) 100%
  );
}

/* The turning leaf */
.turn-leaf {
  position: absolute;
  top: 0;
  bottom: 0;
  width: calc((100% - var(--gutter-width)) / 2);
  transform-style: preserve-3d;
  pointer-events: none;
  z-index: 6;
}

.turn-leaf[hidden] {
  display: none;
}

.turn-leaf--next {
  left: calc(50% + var(--gutter-width) / 2);
  transform-origin: left center;
}

.turn-leaf--prev {
  left: 0;
  transform-origin: right center;
}

/* Leaf faces — each is styled to read as one page half */
.turn-leaf-face {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  background: linear-gradient(180deg, var(--paper-hi) 0%, var(--paper-lo) 100%);
}

.turn-leaf-back {
  transform: rotateY(180deg);
}

/* Gutter-side falloff + inset shadow to match the static pages */
.turn-leaf-face.is-left {
  background:
    var(--paper-pool),
    linear-gradient(90deg, var(--paper-hi) 0%, var(--paper-mid) 60%, var(--paper-edge) 100%),
    linear-gradient(180deg, var(--paper-hi) 0%, var(--paper-lo) 100%);
  box-shadow:
    inset -30px 0 40px -12px rgba(0, 0, 0, 0.22),
    inset -5px 0 10px -2px rgba(0, 0, 0, 0.12);
}

.turn-leaf-face.is-right {
  background:
    var(--paper-pool),
    linear-gradient(90deg, var(--paper-edge) 0%, var(--paper-mid) 40%, var(--paper-hi) 100%),
    linear-gradient(180deg, var(--paper-hi) 0%, var(--paper-lo) 100%);
  box-shadow:
    inset 30px 0 40px -12px rgba(0, 0, 0, 0.22),
    inset 5px 0 10px -2px rgba(0, 0, 0, 0.12);
}

/* Specular sheen that sweeps the leaf near mid-flip (opacity driven by JS).
   backface-visibility hides it once the leaf passes edge-on. */
.turn-leaf-shade {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  background: linear-gradient(
    105deg,
    rgba(255, 250, 240, 0.30) 0%,
    rgba(255, 250, 240, 0) 38%,
    rgba(20, 12, 4, 0) 60%,
    rgba(20, 12, 4, 0.22) 100%
  );
}

/* Hide the resting corner curls while a turn is in flight */
.book-view.is-turning .page-curl {
  opacity: 0;
  pointer-events: none;
}

/* ═══════════════════════════════════════════════════════════
   PAGE NAVIGATION
   ═══════════════════════════════════════════════════════════ */

.page-nav {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  margin-top: var(--space-lg);
}

/* One-spread books (Contact) have nowhere to turn. Hidden rather than
   removed, so the open book keeps the same position as every other book */
.book-view.is-single-spread .page-nav {
  visibility: hidden;
}

.page-nav-btn {
  width: 44px;
  height: 44px;
  background: transparent;
  border: 1px solid var(--text-tertiary);
  border-radius: 2px;
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color var(--duration-fast) var(--ease-out-expo),
              color var(--duration-fast) var(--ease-out-expo),
              transform var(--duration-fast) var(--ease-out-expo),
              opacity var(--duration-fast) var(--ease-out-expo);
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

.page-nav-btn:hover:not(:disabled) {
  border-color: var(--accent);
  color: var(--accent);
  transform: scale(1.05);
}

.page-nav-btn:active:not(:disabled) {
  transform: scale(0.98);
}

.page-nav-btn:disabled {
  opacity: 0.3;
}

.page-nav-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.page-nav-btn svg {
  width: 20px;
  height: 20px;
}

.page-indicator {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--text-secondary);
  display: flex;
  gap: 0.5em;
}

.page-sep {
  color: var(--text-tertiary);
}

/* ═══════════════════════════════════════════════════════════
   TWO-PAGE SPREADS - Chapter Dividers & Role Details
   ═══════════════════════════════════════════════════════════ */

/* Spread container */
.spread-left,
.spread-right {
  height: 100%;
  min-height: 0; /* Safari flexbox fix */
}

/* Versos start at the head margin. Only Work versos (chapters and the
   title page) drop the head down the page (the classic chapter opening). */
.title-page,
.chapter-divider,
.about-chapter,
.contact-chapter,
.reference-attribution {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: flex-start;
  height: 100%;
}

/* Chapter Divider (Left Page) */
.chapter-divider {
  padding-top: var(--chapter-drop);
  position: relative;
}

/* Chapter numeral — real ink at the head of the verso */
.chapter-divider[data-chapter]::before {
  content: attr(data-chapter);
  display: block;
  position: static;
  font-family: var(--font-display);
  font-size: var(--t-num);
  font-weight: 600;
  font-style: italic;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--page-text);
  opacity: 0.85;
  margin-bottom: var(--v-half);
  pointer-events: none;
}

.chapter-period {
  font-family: var(--font-sc);
  font-size: var(--t-xs);
  font-weight: 500;
  letter-spacing: 0.12em;
  color: var(--page-secondary);
  margin-bottom: var(--v-half);
}

.chapter-company {
  font-family: var(--font-display);
  font-size: var(--t-2xl);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.005em;
  color: var(--page-text);
  margin-bottom: 4px;
}

/* Keyboard focus on any page link: page ink, not the UA blue ring */
.page-content a:focus-visible {
  outline: 2px solid var(--accent-maroon);
  outline-offset: 3px;
}

/* Display-size links (chapter and engagement titles): a fine underline,
   not the dotted hairline, which reads as a dashed rule at this size.
   Body-size links keep the dotted hairline. */
.chapter-company a,
.engagement-title a {
  color: inherit;
  text-decoration: underline 1px rgba(26, 23, 20, 0.35);
  text-underline-offset: 0.12em;
  text-decoration-skip-ink: auto;
  transition: text-decoration-color var(--duration-fast) ease;
}

.chapter-company a:hover,
.engagement-title a:hover {
  text-decoration-color: var(--accent-maroon);
}

.chapter-backing a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px dotted var(--page-tertiary);
  transition: border-color var(--duration-fast) ease, border-style var(--duration-fast) ease;
}

.chapter-backing a:hover {
  border-bottom-color: var(--accent-maroon);
  border-bottom-style: solid;
}

.chapter-role {
  font-family: var(--font-text);
  font-size: var(--t-lg);
  font-weight: 500;
  font-style: italic;
  line-height: 1.35;
  color: var(--page-secondary);
  margin-bottom: 0;
}

.chapter-meta {
  align-self: stretch;
  display: flex;
  flex-direction: column;
  gap: 2px;
  border-top: 1px solid var(--page-rule);
  padding-top: var(--v-half);
  margin-top: var(--v1);
}

.chapter-location {
  font-family: var(--font-sc);
  font-size: var(--t-xs);
  font-weight: 500;
  letter-spacing: 0.12em;
  color: var(--page-secondary);
}

.chapter-backing {
  font-family: var(--font-text);
  font-size: var(--t-md);
  line-height: 1.5;
  color: var(--page-text);
}

.chapter-summary {
  font-family: var(--font-text);
  font-size: var(--t-lg);
  font-weight: 400;
  font-style: italic;
  line-height: 1.4;
  color: var(--page-secondary);
  margin-top: var(--v1);
}

/* ═══════════════════════════════════════════════════════════
   TABLE OF CONTENTS - Classic Book ToC
   ═══════════════════════════════════════════════════════════ */

/* Contents verso: a title page - title, then author, then span */
.title-page {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding-top: var(--chapter-drop); /* the title sits on the chapter-opening line */
}

.book-title-label {
  font-family: var(--font-display);
  font-size: var(--t-3xl);
  font-weight: 500;
  line-height: 1.02;
  letter-spacing: -0.005em;
  color: var(--page-text);
  margin: 0;
}

.book-title-name {
  font-family: var(--font-sc);
  font-size: var(--t-lg);
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: 0.06em;
  color: var(--page-secondary);
  margin: var(--v1) 0 0;
}

.book-title-span {
  margin: auto 0 0;
  font: 400 var(--t-sm) / 1.3 var(--font-sc);
  letter-spacing: 0.14em;
  color: var(--page-secondary);
}

/* Contents recto: two-line entries. Line 1: title, dotted leader, the
   verso folio of the chapter. Line 2: role (italic) and period. */
.toc-title {
  font-family: var(--font-display);
  font-size: var(--t-3xl);
  font-weight: 500;
  font-style: italic;
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--page-text);
  margin-bottom: var(--v1);
}

.toc-list {
  display: flex;
  flex-direction: column;
  gap: var(--v1);
}

.toc-entry {
  display: block;
  width: 100%;
  padding: 0;
  border: none;
  background: transparent;
  color: inherit;
  font: inherit; /* not the UA button default (13.33px Arial) */
  cursor: pointer;
  text-align: left;
}

.toc-entry:focus {
  outline: none;
}

.toc-entry:focus-visible {
  outline: 2px solid var(--accent-maroon);
  outline-offset: 4px;
}

.toc-entry-line {
  display: flex;
  align-items: baseline;
}

.toc-entry-title {
  flex: 1;
  display: flex;
  align-items: baseline; /* the text and its leader share one baseline */
  font-family: var(--font-text);
  font-size: var(--t-xl);
  font-weight: 600;
  line-height: 1.25;
  color: var(--page-text);
  hyphens: manual;
  transition: color var(--duration-fast) ease;
}

/* Dot leader from the title to the folio: round dots, like a row of
   full stops, seated on the title's baseline (an empty flex item's
   baseline is its bottom edge, so the dots sit on the line of type) */
.toc-entry-title::after {
  content: '';
  flex: 1;
  min-width: 1.5em;
  height: 4px;
  margin: 0 0.5em;
  align-self: baseline;
  background: radial-gradient(circle, rgba(26, 23, 20, 0.45) 1.1px, transparent 1.6px) left bottom / 8px 4px;
  background-repeat: space no-repeat;
}

.toc-entry:hover .toc-entry-title {
  color: var(--accent-maroon);
}

.toc-entry-page {
  font-family: var(--font-text);
  font-size: var(--t-lg);
  font-weight: 400;
  line-height: 1;
  font-variant-numeric: oldstyle-nums;
  color: var(--page-text);
}

.toc-entry-meta {
  display: block;
  font-family: var(--font-text);
  font-size: var(--t-sm);
  font-style: normal;
  line-height: 1.4;
  color: var(--page-secondary);
  margin-top: 0.1em;
}

.toc-entry-meta em {
  font-style: italic;
}

.toc-entry-period {
  white-space: nowrap;
}

/* ═══════════════════════════════════════════════════════════ */

/* Engagement blocks - textbook style */
.engagement-block + .engagement-block {
  border-top: 1px solid var(--page-rule);
  padding-top: var(--v-half);
  margin-top: var(--v-half);
}

.engagement-label {
  font-family: var(--font-sc);
  font-size: var(--t-xs);
  font-weight: 500;
  letter-spacing: 0.12em;
  color: var(--page-secondary);
  display: block;
  margin-bottom: 4px;
}

.engagement-title {
  font-family: var(--font-text);
  font-size: var(--t-xl);
  font-weight: 500;
  line-height: 1.2;
  font-variant-numeric: lining-nums;
  color: var(--page-text);
  margin-bottom: 2px;
}

.engagement-role {
  font-family: var(--font-sc);
  font-size: var(--t-sm);
  font-weight: 400;
  letter-spacing: 0.05em;
  color: var(--page-secondary);
  margin-bottom: 4px;
}

.engagement-desc {
  font-family: var(--font-text);
  font-size: var(--t-md);
  line-height: 1.5;
  color: var(--page-text);
  margin-bottom: 0;
}

.engagement-others-block .engagement-desc {
  font-style: italic;
  color: var(--page-tertiary);
}

/* Engagement metrics - inline */
.engagement-metrics {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1.2em;
  margin-top: var(--v-half);
}

.engagement-metric {
  font-family: var(--font-text);
  font-size: var(--t-sm);
  color: var(--page-secondary);
}

.engagement-metric strong {
  font-family: var(--font-text);
  font-size: var(--t-md);
  font-weight: 600;
  font-variant-numeric: lining-nums tabular-nums;
  color: var(--page-text);
}

/* Role sections for multi-part roles */
.role-section {
  margin-bottom: 0;
}

.role-section + .role-section {
  margin-top: var(--v-half);
}

.role-section-title {
  font-family: var(--font-sc);
  font-size: var(--t-sm);
  font-weight: 400;
  letter-spacing: 0.05em;
  color: var(--page-text);
  margin-bottom: 4px;
}

.role-section-desc {
  font-family: var(--font-text);
  font-size: var(--t-md);
  line-height: 1.5;
  color: var(--page-text);
}

/* Role Details (Right Page) */
.spread-right {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}

.role-tagline {
  font-family: var(--font-text);
  font-size: var(--t-lg);
  font-weight: 500;
  font-style: italic;
  line-height: 1.35;
  color: var(--page-text);
  margin-bottom: var(--v1);
}

.role-details {
  margin-bottom: var(--space-sm);
  flex: 1;
}

.role-details p {
  font-family: var(--font-text);
  font-size: var(--t-md);
  line-height: 1.5;
  color: var(--page-text);
  margin-bottom: var(--v1);
}

.role-details p:last-child {
  margin-bottom: 0;
}

/* Role Metrics */
.role-metrics {
  display: flex;
  gap: var(--space-xs);
  padding: var(--v-half) 0 0;
  border-top: 1px solid var(--page-rule);
  margin-top: auto;
  flex-shrink: 0;
}

.metric {
  text-align: center;
  flex: 1;
}

.metric-value {
  font-family: var(--font-text);
  font-size: var(--t-lg);
  font-weight: 600;
  line-height: 1.15;
  font-variant-numeric: lining-nums tabular-nums;
  display: block;
  color: var(--page-text);
}

.metric-label {
  font-family: var(--font-sc);
  font-size: var(--t-sm);
  font-weight: 400;
  letter-spacing: 0.05em;
  display: block;
  color: var(--page-secondary);
  margin-top: 1px;
}

/* Author portrait — printed on the page, not uploaded to a profile */
.about-headshot {
  width: 110px;
  height: 132px;
  border-radius: 0;
  object-fit: cover;
  object-position: center top;
  margin-bottom: var(--v1);
  border: none;
  box-shadow: none;
  /* Subtle printed-on-paper feel */
  filter: saturate(0.8) contrast(1.05);
  outline: 1px solid var(--page-rule);
  outline-offset: 4px;
}

.about-chapter-label {
  font-family: var(--font-sc);
  font-size: var(--t-xs);
  font-weight: 500;
  letter-spacing: 0.12em;
  color: var(--page-secondary);
  margin-bottom: var(--v-half);
}

/* On a spread the verso's running head already names the book, so the
   eyebrow label would say it twice. Phones have no running head: keep it. */
@media (min-width: 901px) {
  .about-chapter-label,
  .reference-label {
    display: none;
  }
}

.about-chapter-title {
  font-family: var(--font-text);
  font-size: var(--t-xl);
  font-weight: 500;
  line-height: 1.2;
  color: var(--page-text);
  margin-bottom: var(--v-half);
}

.about-chapter-note {
  font-family: var(--font-text);
  font-size: var(--t-md);
  line-height: 1.5;
  font-style: italic;
  color: var(--page-secondary);
}

.contact-chapter-title {
  font-family: var(--font-display);
  font-size: var(--t-2xl);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.005em;
  color: var(--page-text);
  margin-bottom: var(--v-half);
}

.contact-chapter-note {
  font-family: var(--font-text);
  font-size: var(--t-md);
  line-height: 1.5;
  font-style: italic;
  color: var(--page-secondary);
}

/* About Pages */
.about-header {
  margin-bottom: var(--v1);
  padding-bottom: var(--v-half);
  border-bottom: 1px solid var(--page-rule);
  position: relative;
}

.about-header h2 {
  font-family: var(--font-display);
  font-size: var(--t-2xl);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.005em;
  color: var(--page-text);
}

.about-lead {
  font-family: var(--font-text);
  font-size: var(--t-lg);
  font-weight: 500;
  font-style: italic;
  line-height: 1.4;
  color: var(--page-text);
  margin-bottom: var(--v1);
}

/* Running-text paragraphs. :where() keeps this at zero specificity so
   classed lines (.about-lead, .engagement-desc ...) keep their own scale. */
:where(.page-content p) {
  font-size: var(--t-md);
  line-height: 1.5;
  margin: 0 0 var(--v1);
}

:where(.page-content p:last-child) {
  margin-bottom: 0;
}

/* Currently Section */
.currently-section {
  margin-bottom: var(--v1);
}

.currently-item {
  display: flex;
  gap: var(--space-md);
  padding: var(--v-half) 0;
  border-bottom: 1px solid var(--page-rule);
}

.currently-item:last-child {
  border-bottom: none;
}

.currently-label {
  font-family: var(--font-sc);
  font-size: var(--t-xs);
  font-weight: 500;
  letter-spacing: 0.12em;
  color: var(--page-secondary);
  min-width: 70px;
  padding-top: 3px;
}

.currently-value {
  font-family: var(--font-text);
  font-size: var(--t-md);
  line-height: 1.5;
  color: var(--page-text);
}

.currently-value a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px dotted var(--page-tertiary);
  transition: border-color var(--duration-fast) ease, border-style var(--duration-fast) ease;
}

.currently-value a:hover {
  border-bottom-color: var(--accent-maroon);
  border-bottom-style: solid;
}

.education-note {
  font-family: var(--font-text);
  font-size: var(--t-md);
  line-height: 1.5;
  margin-top: var(--v1);
  color: var(--page-secondary);
}

/* Technical Section (About Page 2) */
.technical-list {
  display: flex;
  flex-direction: column;
  gap: var(--v-half);
  margin-top: var(--v-half);
}

.technical-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-bottom: var(--v-half);
  border-bottom: 1px solid var(--page-rule);
}

.technical-item:last-child {
  border-bottom: none;
}

/* Colophon "How it's built": tighter rows so four short entries fit the
   page instead of scrolling */
.book-view[data-active-book="colophon"] .technical-list {
  gap: 8px;
}

.book-view[data-active-book="colophon"] .technical-item {
  padding-bottom: 8px;
}

.technical-category {
  font-family: var(--font-sc);
  font-size: var(--t-xs);
  font-weight: 500;
  letter-spacing: 0.12em;
  color: var(--page-secondary);
}

.technical-skills {
  font-family: var(--font-text);
  font-size: var(--t-md);
  line-height: 1.5;
  color: var(--page-text);
}

/* Projects row: name (a body link), one sentence, an optional detail line */
.technical-project {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.technical-project + .technical-project {
  margin-top: var(--v-half);
}

.technical-project-name {
  align-self: flex-start;
  font-family: var(--font-text);
  font-size: var(--t-md);
  font-weight: 600;
  line-height: 1.4;
  color: var(--page-text);
  text-decoration: none;
  border-bottom: 1px dotted var(--page-tertiary);
  transition: border-color var(--duration-fast) ease, border-style var(--duration-fast) ease;
}

.technical-project-name:hover {
  border-bottom-color: var(--accent-maroon);
  border-bottom-style: solid;
}

.technical-project-detail {
  font-family: var(--font-text);
  font-size: var(--t-sm);
  line-height: 1.4;
  color: var(--page-secondary);
}

/* Personal Page (About Book) */
.personal-content {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.personal-content p {
  font-family: var(--font-text);
  font-size: var(--t-md);
  line-height: 1.5;
  color: var(--page-text);
}

/* Contact Page */
.contact-header {
  margin-bottom: var(--v1);
}

.contact-header h2 {
  font-family: var(--font-display);
  font-size: var(--t-3xl);
  font-weight: 500;
  font-style: italic;
  line-height: 1.05;
  letter-spacing: -0.01em;
  color: var(--page-text);
}

.contact-note {
  font-family: var(--font-text);
  font-size: var(--t-lg);
  font-weight: 400;
  font-style: normal;
  line-height: 1.5;
  color: var(--page-secondary);
  margin-bottom: var(--v1);
  max-width: 38ch;
}

.contact-email {
  font-family: var(--font-text);
  font-size: var(--t-xl);
  font-weight: 500;
  display: inline-block;
  align-self: flex-start; /* flex item of .spread-right: don't stretch the rule */
  color: var(--page-text);
  text-decoration: none;
  border-bottom: 1px solid var(--page-text);
  padding-bottom: 2px;
  margin-bottom: var(--v1);
  transition: color var(--duration-fast) var(--ease-out-expo),
              border-color var(--duration-fast) var(--ease-out-expo);
}

.contact-email:hover {
  color: var(--accent-maroon);
  border-color: var(--accent-maroon);
}

.contact-email:focus-visible {
  outline: 2px solid var(--accent-maroon);
  outline-offset: 4px;
}

.social-links {
  display: flex;
  gap: var(--v1);
  margin-bottom: var(--v1);
}

.social-link {
  font-family: var(--font-sc);
  font-size: var(--t-sm);
  font-weight: 500;
  letter-spacing: 0.08em;
  color: var(--page-secondary);
  text-decoration: none;
  border-bottom: 1px dotted var(--page-tertiary);
  transition: color var(--duration-fast) var(--ease-out-expo), border-color var(--duration-fast) ease, border-style var(--duration-fast) ease;
}

.social-link:hover {
  color: var(--page-text);
  border-bottom-color: var(--accent-maroon);
  border-bottom-style: solid;
}

.social-link:focus-visible {
  outline: 2px solid var(--accent-maroon);
  outline-offset: 2px;
}

/* The imprint line: the one copyright notice, set small on the Colophon */
.colophon-imprint {
  font-family: var(--font-sc);
  font-size: var(--t-xs);
  font-weight: 500;
  letter-spacing: 0.12em;
  color: var(--page-secondary);
  margin-top: var(--v1);
}

/* ═══════════════════════════════════════════════════════════
   REFERENCES PAGE - Testimonials & Quotes
   ═══════════════════════════════════════════════════════════ */

.reference-quote {
  padding: var(--space-md);
  border-left: 2px solid var(--accent-gold);
  background: linear-gradient(90deg, rgba(218, 165, 32, 0.03) 0%, transparent 100%);
}

.quote-text {
  font-family: var(--font-text);
  font-size: var(--t-lg);
  font-weight: 400;
  font-style: italic;
  line-height: 1.45;
  color: var(--page-text);
  margin-bottom: var(--v-half);
  quotes: '\201C' '\201D' '\2018' '\2019';
  text-indent: -0.45em;
}

.quote-text::before {
  content: open-quote;
}

.quote-text::after {
  content: close-quote;
}

.references-note {
  font-family: var(--font-text);
  font-size: var(--t-md);
  line-height: 1.5;
  font-style: italic;
  color: var(--page-secondary);
  margin-top: var(--v1);
  padding-top: var(--v-half);
  border-top: 1px solid var(--page-rule);
  text-align: left;
}

.reference-label {
  font-family: var(--font-sc);
  font-size: var(--t-xs);
  font-weight: 500;
  letter-spacing: 0.12em;
  color: var(--page-secondary);
  margin-bottom: var(--v-half);
}

.reference-author {
  font-family: var(--font-display);
  font-size: var(--t-2xl);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.005em;
  color: var(--page-text);
  margin-bottom: var(--v-half);
}

.reference-role {
  font-family: var(--font-text);
  font-size: var(--t-lg);
  font-weight: 500;
  font-style: italic;
  color: var(--page-secondary);
  margin-bottom: 0;
}

.reference-context {
  font-family: var(--font-text);
  font-size: var(--t-md);
  line-height: 1.5;
  font-style: italic;
  color: var(--page-tertiary);
}

/* Reference Quote Page (right side) */
.reference-quote-page {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}

.reference-quote-page .reference-quote {
  padding: 0 0 0 0.45em; /* room inside the scroll box for the hung open quote */
  border-left: none;
  background: none;
  margin-bottom: 0;
}

.reference-quote-page .quote-text {
  color: var(--page-text);
}

/* ═══════════════════════════════════════════════════════════
   ANIMATIONS
   ═══════════════════════════════════════════════════════════ */

/* ─── Page-turn engine (single-leaf 3D flip) ───────────────────────
   The turning leaf, its faces, the sheen, and the dynamic page shadows
   are defined in the PAGE-TURN LEAF block below. Static pages carry NO
   transform at rest so their text rasterises crisp. */

/* ═══════════════════════════════════════════════════════════
   RESPONSIVE DESIGN
   ═══════════════════════════════════════════════════════════ */

@media (max-width: 900px) {
  /* Mobile: constrain book view to fit viewport with fixed nav at bottom */
  .book-view {
    display: flex;
    flex-direction: column;
    padding: env(safe-area-inset-top, 0) env(safe-area-inset-right, 0)
             env(safe-area-inset-bottom, 0) env(safe-area-inset-left, 0);
    overflow-x: hidden;
  }

  .book-container {
    flex-direction: column;
    flex: 1;
    min-height: 0;
    padding-top: 56px;   /* Fixed space for shelf button */
    padding-bottom: 80px; /* Fixed space for page nav */
    display: flex;
    align-items: center;
    justify-content: center;
    max-width: 100%;
    overflow-x: hidden;
    height: auto;        /* Override desktop calc(100vh - 140px) */
    max-height: none;    /* Override desktop max-height: 800px */
  }

  .open-book {
    flex: none;
    flex-direction: column;
    width: calc(100% - 24px);
    max-width: 400px;
    margin: 0 auto;
    border-radius: 4px 8px 8px 4px;
    overflow: hidden;
    /* Tier 1: CSS fallback using svh (smallest viewport height) */
    height: clamp(400px, 65svh, 580px);
    /* Tier 2: JS-computed height bypasses all viewport unit bugs on real Safari */
    height: var(--mobile-book-height, clamp(400px, 65svh, 580px));
    min-height: 0;     /* Kill base min-height: 500px — Safari flex quirk */
    max-height: none;
    display: flex;
    /* Add book-like left edge (spine indicator) */
    border-left: 6px solid var(--book-work); /* Default, overridden per book */
    box-shadow:
      0 15px 40px rgba(0, 0, 0, 0.3),
      0 5px 15px rgba(0, 0, 0, 0.2),
      inset 3px 0 8px -3px rgba(0, 0, 0, 0.15);
  }

  /* Book-specific spine colors on mobile */
  .book-view[data-active-book="work"] .open-book { border-left-color: var(--book-work); }
  .book-view[data-active-book="about"] .open-book { border-left-color: var(--book-about); }
  .book-view[data-active-book="contact"] .open-book { border-left-color: var(--book-contact); }
  .book-view[data-active-book="references"] .open-book { border-left-color: var(--book-references); }
  .book-view[data-active-book="colophon"] .open-book { border-left-color: var(--book-colophon); }

  .page {
    transform: none; /* Remove desktop 3D rotation */
    border-radius: 0 4px 4px 0;
    min-height: 0;    /* Safari flex containment — prevent content push */
    overflow: hidden;
  }

  .page-left {
    display: none;
  }

  /* The left page, folded into the single mobile column above the right
     content. Its chapter divider/headshot/heading get a rule below them. */
  .mobile-left-inline {
    display: block;
    margin-bottom: var(--v1);
    padding-bottom: var(--v1);
    border-bottom: 1px solid var(--page-rule);
    min-height: 0;
    text-align: left;
  }

  /* A one-page chapter (empty recto) ends on its summary: no rule below */
  .mobile-left-inline:has(+ .spread-right:empty) {
    border-bottom: 0;
    padding-bottom: 0;
    margin-bottom: 0;
  }

  /* Compact chapter opening: no chapter drop; the numeral sits inline
     before the company; location and backing stay on separate lines. */
  .mobile-left-inline.chapter-divider {
    display: flex;
    flex-flow: row wrap;
    align-items: baseline;
    padding-top: 0;
  }

  .mobile-left-inline.title-page {
    padding-top: 0;
  }

  .mobile-left-inline.chapter-divider > * {
    flex: 0 0 100%;
  }

  .mobile-left-inline .chapter-period {
    order: -1;
    margin-bottom: 0.25em;
  }

  .mobile-left-inline.chapter-divider::before {
    display: inline-block;
    flex: none;
    font-size: 40px;
    margin: 0 0.3em 0 0;
    vertical-align: -0.05em;
  }

  .mobile-left-inline.chapter-divider > .chapter-company {
    flex: 1 1 0;
    min-width: 0;
  }

  .mobile-left-inline .chapter-meta {
    padding-top: 8px;
    margin-top: 8px;
  }

  .mobile-left-inline .chapter-summary {
    font-size: var(--t-md);
    margin-top: 8px;
  }

  .mobile-left-inline .about-headshot {
    display: block;
    width: 88px;
    height: 106px;
  }

  .page-right {
    transform: none; /* Remove 3D tilt */
    box-shadow: none;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    position: relative;
  }

  /* Scroll-fade indicator. background is reset here because .page::after (the paper-tooth tile on the same pseudo slot) would otherwise paint over the fade. */
  .page-right::after {
    content: '';
    position: sticky;
    bottom: -40px; /* sticky insets by the container's padding-bottom; cancel it so the fade sits on the sheet's foot */
    left: 0;
    right: 0;
    display: block;
    height: 64px;
    margin: 0 -20px; /* span the sheet's padding box (.page-right side padding) */
    /* The sheet's own paper, masked to fade upward, so no edge of the band shows */
    background: linear-gradient(90deg, var(--paper-edge) 0%, var(--paper-mid) 40%, var(--paper-hi) 100%);
    -webkit-mask-image: linear-gradient(to top, #000 32%, transparent);
    mask-image: linear-gradient(to top, #000 32%, transparent);
    pointer-events: none;
    z-index: 5;
    flex-shrink: 0;
  }

  /* No fade on a sheet that fits: a sticky fade on a short page sits in
     flow under the copy and paints as a grey band. At the end of a long
     sheet the fade only goes transparent, because removing it would
     shorten the scroll and jump the copy. (book.js markOverflow sets the
     classes.) */
  .page-right:not(.is-overflowing)::after {
    display: none;
  }

  .page-right.is-at-end::after {
    opacity: 0;
  }

  .book-spine-center {
    display: none;
  }

  .page-edge {
    display: none;
  }

  /* No page-curl affordance on mobile — the fixed prev/next bar is the
     nav, and the curl ghosted over the last line of body text. */
  .page-curl {
    display: none;
  }

  /* Nav shelf button positioning */
  .nav-shelf-btn {
    position: fixed;
    top: calc(12px + env(safe-area-inset-top, 0));
    left: 16px;
    z-index: 100;
    background: rgba(10, 9, 8, 0.9);
    backdrop-filter: blur(8px);
  }

  /* The sheet: fixed page sizes (no height-keyed scale on a phone) and
     the spec's sheet padding */
  .book-container {
    --t-xs: 13px;
    --t-sm: 14.5px;
    --t-md: 16.5px;
    --t-lg: 19px;
    --t-xl: 22px;
    --t-2xl: 30px;
    --t-3xl: 38px;
    --t-num: 64px;
  }

  .page-right {
    padding: 22px 20px 40px; /* 40px foot keeps the last line clear of the folio */
  }

  /* FIX: Allow spread-right content to flow and trigger page scroll.
     Desktop uses overflow:hidden + height:100% to clip within the fixed book,
     but on mobile we need content to grow so .page-right can scroll it. */
  .spread-left,
  .spread-right {
    height: auto;
    overflow: visible;
  }

  .spread-right {
    overflow: visible;
    min-height: 0;
  }

  /* FIX: page-content must also allow content to grow on mobile
     so that .page-right overflow-y:auto can produce a scrollbar. */
  .page-content {
    overflow: visible;
    flex: none;       /* Don't constrain to parent flex height */
    min-height: 0;
  }

  /* Ensure page numbers don't overlap with shelf button */
  .page-number {
    bottom: 8px;
    z-index: 6; /* above the scroll fade, which is opaque at the foot */
  }

  .page-number-right {
    right: 20px;
  }

  /* Fixed page navigation at bottom of screen */
  .page-nav {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    justify-content: center;
    margin-top: 0;
    z-index: 100;
    background: rgba(10, 9, 8, 0.9);
    backdrop-filter: blur(8px);
    padding: 12px 0;
    padding-bottom: calc(20px + env(safe-area-inset-bottom, 0));
    border-radius: 0;
  }
}

@media (max-width: 600px) {
  .collapsed-nav {
    padding: 0 var(--space-md);
  }

  .nav-books {
    gap: var(--space-sm);
  }

  .role-metrics {
    flex-wrap: wrap;
    gap: var(--space-sm);
  }

  /* Three equal columns: a 45% basis orphaned the third stat on its own row */
  .metric {
    flex: 1 1 0;
    min-width: 0;
  }

  /* A third of the sheet must still hold "Engagements" at 360px */
  .metric-label {
    font-size: var(--t-xs);
  }

  .contact-email {
    padding: var(--space-sm) 0;
    overflow-wrap: anywhere;
  }
}

/* ═══════════════════════════════════════════════════════════
   REDUCED MOTION
   ═══════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
