/* Ronan Slad — prototype. Sizes come from config.js via custom properties
   (--ratio, --depth-ratio, image urls, colours). Don't hard-code them here. */

@font-face { font-family: "Slad Woodcut"; src: url("assets/fonts/SladWoodcut-Regular.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "EB Garamond"; src: url("assets/fonts/EBGaramond-var.woff2") format("woff2"); font-weight: 400 800; font-display: swap; }
@font-face { font-family: "EB Garamond"; src: url("assets/fonts/EBGaramond-Italic-var.woff2") format("woff2"); font-weight: 400 800; font-style: italic; font-display: swap; }
@font-face { font-family: "Inter"; src: url("assets/fonts/Inter-var.woff2") format("woff2"); font-weight: 100 900; font-display: swap; }

@property --tx { syntax: "<angle>"; inherits: true; initial-value: 0deg; }
@property --ty { syntax: "<angle>"; inherits: true; initial-value: 0deg; }

:root {
  color-scheme: dark;
  --bg: #000;
  --fg: #e7e9ea;           /* X / Grok text */
  --muted: #71767b;        /* X secondary */
  --line: #2f3336;         /* X hairline */

  /* set from CONFIG by main.js (fallbacks here) */
  --ratio: 0.647;          /* bookWidth / bookHeight */
  --depth-ratio: 0.155;    /* spineWidth / bookWidth */
  --page: #ece3cf;
  --page-edge: #d9ceb6;
  --cover-in: #8c6844;
  --ink: #1e1813;
  --img-front: none;
  --img-back: none;
  --img-spine: none;

  /* layout: vertical space reserved for header + footer + hint */
  --chrome-h: clamp(10rem, 7rem + 13vh, 22rem);
  --gutter: clamp(1rem, 4vw, 4rem);
  /* CONFIG.titleInset: wordmark inset from the top-left. Landscape: the photo's left edge falls into deep
     shadow over roughly the first 8-10vw, so the title clears it (scales with width = with the crop). */
  --title-x: var(--title-x-wide, clamp(1.25rem, 11.5vw, 30rem));
  --title-y: var(--title-y-wide, clamp(1rem, 2.4vw, 2.75rem));
  --avail-h: calc(100svh - var(--chrome-h) - var(--pt-room));
  --pt-room: 0px;          /* extra headroom for the product title (only where the space above the book is tight) */

  /* book size: fit height, and make sure the OPEN spread (2x width) fits */
  --book-w-fit: min(calc(var(--avail-h) * var(--ratio)), calc((100vw - var(--gutter) * 2) / 2));
  --book-scale: .85;       /* CONFIG.bookScale */
  --book-w: calc(var(--book-w-fit) * var(--book-scale));
  --book-h: calc(var(--book-w) / var(--ratio));
  --depth: calc(var(--book-w) * var(--depth-ratio));
  --hd: calc(var(--depth) / 2);
  /* paperback: page block flush with the soft cover (no board overhang) */
  --pg-w: var(--book-w);
  --pg-h: var(--book-h);
  --pg-top: 0px;
  --cover-t: 1px;          /* soft-cover thickness used to inset the page-block edges */
  --open-shift: calc(var(--book-w) / 2);   /* centres the spread */

  --ease-out: cubic-bezier(.2, .8, .2, 1);
  --ease-io: cubic-bezier(.65, 0, .35, 1);
  --t-cover: 900ms;
  --t-turn: 1100ms;
}

/* Portrait phones: single-page view. Book is bigger, the open cover/left page
   swings off-screen and the right (snippet) page stays centred. */
@media (max-width: 600px) and (orientation: portrait) {
  :root {
    --chrome-h: clamp(10rem, 22svh, 13rem);
    --book-w-fit: min(calc(var(--avail-h) * var(--ratio)), 76vw);
    --open-shift: calc(var(--book-w) * 0.06);
  }
}
/* Portrait / square-ish: the left edge of the crop is lit flesh, so a small inset is right */
@media (max-aspect-ratio: 1/1) {
  :root { --title-x: var(--title-x-portrait, clamp(1rem, 4vw, 2.5rem)); --title-y: var(--title-y-portrait, clamp(1rem, 2.4vw, 2rem)); }
}
/* portrait phones only: RONAN SLAD drops a touch (CONFIG.titleInset.phonePortraitNudge), clear of the notch/status bar */
@media (max-width: 600px) and (orientation: portrait) {
  :root { --title-y: calc(var(--title-y-portrait, clamp(1rem, 2.4vw, 2rem)) + var(--title-nudge-phone, 10px) + env(safe-area-inset-top, 0px)); }
  /* matching left inset: same distance from the left edge as from the top */
  :root { --title-x: calc(var(--title-y-portrait, clamp(1rem, 2.4vw, 2rem)) + var(--title-nudge-phone, 10px) + env(safe-area-inset-left, 0px)); }
}
/* Landscape phones: chrome overlays the corners so the book gets the height */
@media (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  :root { --chrome-h: 6rem; --gutter: 5.5rem; }
}

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
/* body clips (not the viewport): the carousel swinging off-screen must never widen the page / make phones zoom out */
html { overflow: hidden; }
body { overflow: clip !important; }
body {
  margin: 0; background: var(--bg); color: var(--fg);
  font: 400 15px/1.5 "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  -webkit-font-smoothing: antialiased;
  display: grid; grid-template-rows: auto 1fr auto; min-height: 100svh; overflow: hidden;
}
/* faint grain + vignette so pure black doesn't look flat */
body::before {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 0;
  background: radial-gradient(ellipse 60% 55% at 50% 48%, rgba(255,255,255,.045), transparent 70%);
}

.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ---------- header / footer ---------- */
.site-head { position: relative; z-index: 2; padding: var(--title-y) var(--gutter) 0 var(--title-x); }
.wordmark {
  font-family: "Slad Woodcut", serif; font-feature-settings: "calt" 1, "liga" 1;
  font-size: clamp(1.5rem, 1rem + 1.6vw, 3.6rem); line-height: 1; letter-spacing: .04em;
  color: var(--fg); text-decoration: none; display: inline-block;
}
.wordmark:focus-visible { outline: 1px solid var(--fg); outline-offset: 6px; }

.site-foot {
  position: relative; z-index: 2; display: flex; gap: 1.25rem; align-items: center; justify-content: center;
  /* CONFIG.footPadExtra lifts the buttons (and the book centred above them) off the bottom edge */
  padding: 0 var(--gutter) calc(clamp(1rem, 3vh, 2.25rem) + var(--foot-pad-extra, clamp(12px, 2.6vh, 30px)) + env(safe-area-inset-bottom, 0px)); flex-wrap: wrap;
}
/* buy button: tattoo-flash style text in a hand-inked frame (frame = mask, so it takes the ink colour) */
.ink-btn {
  position: relative; z-index: 0; display: inline-block;
  font-family: "Slad Woodcut", serif; font-feature-settings: "calt" 1;
  font-size: clamp(1.15rem, .85rem + .6vw, 2rem); letter-spacing: .06em; line-height: 1;
  color: var(--ink-ui, var(--fg)); text-decoration: none; background: none;
  padding: 0;
  transition: color .25s ease, text-shadow .25s ease;
}
/* main.js wraps the button content in .ink-k (black ink, the layout box) and lays an aria-hidden copy, .ink-w (white ink),
   exactly over it; the two cross over with the blotchy bleed filters (#btn-k-N / #btn-w-N) */
.ink-btn .ink-k, .ink-btn .ink-w { position: relative; display: block; padding: .72em 1.25em .62em; }
.ink-btn .ink-w { position: absolute; inset: 0; display: none; pointer-events: none; }
.ink-btn .frm { display: none; }
.ink-btn::before, .ink-btn .frm { content: ""; position: absolute; inset: 0; background: currentColor; pointer-events: none;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 60' preserveAspectRatio='none'%3E%3Cg fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath vector-effect='non-scaling-stroke' stroke-width='2.6' d='M7 8 C 60 4, 140 10, 194 5 M192 3 C 197 21, 193 41, 195 56 M197 53 C 140 57, 70 52, 5 55 M7 58 C 3 41, 8 22, 4 4'/%3E%3Cpath vector-effect='non-scaling-stroke' stroke-width='1.3' opacity='.75' d='M3 11 C 70 8, 125 12, 189 9 M10 51 C 80 55, 150 49, 191 52 M188 6 C 190 25, 188 37, 190 50'/%3E%3C/g%3E%3C/svg%3E") center / 100% 100% no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 60' preserveAspectRatio='none'%3E%3Cg fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath vector-effect='non-scaling-stroke' stroke-width='2.6' d='M7 8 C 60 4, 140 10, 194 5 M192 3 C 197 21, 193 41, 195 56 M197 53 C 140 57, 70 52, 5 55 M7 58 C 3 41, 8 22, 4 4'/%3E%3Cpath vector-effect='non-scaling-stroke' stroke-width='1.3' opacity='.75' d='M3 11 C 70 8, 125 12, 189 9 M10 51 C 80 55, 150 49, 191 52 M188 6 C 190 25, 188 37, 190 50'/%3E%3C/g%3E%3C/svg%3E") center / 100% 100% no-repeat; }
.ink-btn::after { /* fresh-tattoo redness on hover/focus */
  content: ""; position: absolute; inset: -35% -14%; z-index: -1; pointer-events: none; opacity: 0; transition: opacity .35s ease;
  background: radial-gradient(closest-side, rgba(196,64,46,.3), rgba(196,64,46,.1) 60%, rgba(200,58,42,0)); }
.ink-btn:hover::after, .ink-btn:focus-visible::after { opacity: 1; }
.ink-btn:focus-visible { outline: 2px dashed currentColor; outline-offset: 7px; }
/* the audiobook button: same tattooed frame, a <button>, small "coming soon" under the label */
button.ink-btn { border: 0; margin: 0; font: inherit; font-family: "Slad Woodcut", serif; font-size: clamp(1.15rem, .85rem + .6vw, 2rem);
  letter-spacing: .06em; line-height: 1; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.audio-btn { display: inline-block; padding: 0; }
.audio-btn .ink-k, .audio-btn .ink-w { display: flex; flex-direction: column; align-items: center; padding: .62em 1.25em .5em; }
.audio-btn .ink-w { display: none; }
.audio-btn .lbl, .audio-btn .sub { display: block; }
.audio-btn .sub { font-size: .52em; letter-spacing: .1em; margin-top: .32em; opacity: .85; }
.audio-btn.has-url .sub { display: none; }
/* selected = the object currently on the disc: a hand-inked underline beneath the frame, ink a touch darker */
.ink-btn .sel, .contact-link .sel { position: absolute; left: 12%; right: 12%; bottom: -.62em; height: .42em; background: currentColor; pointer-events: none;
  opacity: 0; transform: scaleX(.6); transition: opacity .2s ease, transform .2s var(--ease-out);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 12' preserveAspectRatio='none'%3E%3Cpath d='M3 7 C 30 3, 62 9, 92 5 S 113 6, 117 4' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round'/%3E%3Cpath d='M9 9 C 40 7, 75 10, 110 7' fill='none' stroke='%23000' stroke-width='1.1' stroke-linecap='round' opacity='.7'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 12' preserveAspectRatio='none'%3E%3Cpath d='M3 7 C 30 3, 62 9, 92 5 S 113 6, 117 4' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round'/%3E%3Cpath d='M9 9 C 40 7, 75 10, 110 7' fill='none' stroke='%23000' stroke-width='1.1' stroke-linecap='round' opacity='.7'/%3E%3C/svg%3E") center / 100% 100% no-repeat; }
.ink-btn.is-selected .sel { opacity: 1; transform: none; }

@media (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  body { grid-template-rows: 1fr; }
  .site-head { position: fixed; top: 0; left: 0; padding: var(--title-y-phone, .9rem) 1.1rem .9rem var(--title-x); }
  .wordmark { font-size: 1.3rem; }
  .site-foot { position: fixed; right: 0; bottom: 0; flex-direction: column; align-items: flex-end; gap: .45rem;
    padding: .9rem calc(1.1rem + env(safe-area-inset-right, 0px)) calc(.9rem + var(--foot-pad-extra, 12px) * .5 + env(safe-area-inset-bottom, 0px)) 1.1rem; }
  .ink-btn, button.ink-btn { font-size: 1rem; }
  .site-foot { gap: .75rem; }
}

/* ---------- stage ---------- */
/* product title (CONFIG.productTitle / showProductTitle): the page's h1, centred over the object, larger than the wordmark,
   with breathing room above the book's tilt. Landscape desktops get a little headroom (--pt-room: the book is a few %
   shorter and sits that much lower); tall phones/tablets already have the room. */
/* title size: width-led but capped by height; the headroom it needs comes out of the object's height, so book and vinyl
   (vinyl = .8 x book height) shrink together, smoothly, only where vertical space is short */
:root { --pt-fs: clamp(2.6rem, min(1.4rem + 3.3vw, 9.5vh), 7rem); }
html[data-ptitle="on"] { --pt-room: calc(var(--pt-fs) * .35); }
@media (max-aspect-ratio: 1/1) { html[data-ptitle="on"] { --pt-room: 0px; } }
@media (max-height: 500px) and (orientation: landscape) and (pointer: coarse) { html[data-ptitle="on"] { --pt-room: 1.1rem; } }
.product-title {
  position: absolute; left: 50%; z-index: 0; margin: 0; pointer-events: none; white-space: nowrap;
  top: calc((100% - var(--stage-pad) + var(--pt-room)) / 2 - var(--book-h) / 2 - var(--pt-gap));
  transform: translate(-50%, -100%);
  --pt-gap: calc(var(--book-w) * .085 + .35rem);
  font-family: "Slad Woodcut", serif; font-feature-settings: "calt" 1, "liga" 1; font-weight: 400;
  font-size: var(--pt-fs); letter-spacing: .24em; padding-left: .24em; /* balances the trailing tracking so the letters sit centred */ line-height: 1;
  color: var(--ink-ui, var(--fg));
}
.product-title[hidden] { display: none; }
/* portrait phones: the object keeps its centred spot; the title sits up under RONAN SLAD (stage top = header bottom) */
@media (max-width: 600px) and (orientation: portrait) {
  .product-title { font-size: 2.9rem; top: clamp(1.4rem, 4.6svh, 2.9rem); transform: translate(-50%, 0); }
}
@media (max-height: 500px) and (orientation: landscape) and (pointer: coarse) { .product-title { font-size: 2.3rem; --pt-gap: .9rem; } }
.stage { padding-top: var(--pt-room); }
.stage { position: relative; z-index: 1; display: grid; place-items: center; min-height: 0; overflow: visible; }  /* the carousel swings past the stage */
.scene {
  position: relative; width: var(--book-w); height: var(--book-h);
  perspective: calc(var(--book-w) * 5.5); perspective-origin: 50% 40%;
  cursor: pointer; outline: none; -webkit-tap-highlight-color: transparent; border-radius: 4px;
}
.scene:focus-visible::after { content: ""; position: absolute; inset: -14px; transition: left var(--t-cover) var(--ease-io), right var(--t-cover) var(--ease-io); border: 1px solid var(--muted); border-radius: 8px; pointer-events: none; }
.scene.is-busy { cursor: progress; }
.scene.is-open:focus-visible::after { left: calc(var(--open-shift) - var(--book-w) - 14px); right: calc(-1 * var(--open-shift) - 14px); }

.hint {
  /* sits below the book's cast shadow: book bottom + ambient shadow reach (offset .085W + tilt .02W + blur ~.1W)
     + breathing room. --hint-gap tunes it. */
  position: absolute; left: 50%; top: calc(50% + var(--book-h) / 2 + var(--book-w) * .2 + var(--hint-gap));
  transform: translateX(-50%); margin: 0; white-space: nowrap;
  color: var(--ink-ui-soft, var(--muted)); font-family: "Slad Woodcut", serif; font-feature-settings: "calt" 1;
  font-size: clamp(1.02rem, .88rem + .32vw, 1.5rem); letter-spacing: .11em; line-height: 1;
  transition: opacity .8s ease; animation: hint-pulse 3.2s ease-in-out 1.2s infinite;
}
.hint.is-gone { opacity: 0; animation: none; }
@keyframes hint-pulse { 50% { opacity: .8; } }
/* room for the hint under the book's shadow: the book is centred in the stage minus --stage-pad
   (so it rides a little above centre on desktop/tablet where the footer is close) */
.stage { --stage-pad: calc(var(--book-w) * .16 + 1.2rem); --hint-gap: clamp(6px, .15rem + .3vh, .6rem); --hint-reach: .155; padding-bottom: var(--stage-pad); }
/* Preview hint: just under the visible shadow, visibly closer to the book than to the footer */
.hint { top: calc((100% - var(--stage-pad) + var(--pt-room)) / 2 + var(--obj-h, var(--book-h)) / 2 + var(--obj-w, var(--book-w)) * var(--hint-reach) + var(--hint-gap) + var(--obj-shift, 0px)); }
.stage.is-vinyl { --obj-h: var(--vinyl-d); --obj-w: calc(var(--vinyl-d) * .72); }
@media (max-width: 600px) and (orientation: portrait) { .stage { --stage-pad: 0px; --hint-reach: .12; } .hint { font-size: 1.15rem; } }
/* soft light pooled under the hint (skin theme), positioned with it, so the black ink reads on darker skin */
.hint-lift { display: none; }
html[data-theme="skin"][data-hint-ink="black"][data-hint-patch="true"] .hint-lift {
  display: block; position: absolute; left: 50%; pointer-events: none;
  font-size: clamp(1.02rem, .88rem + .32vw, 1.5rem); width: 15em; height: 4.2em;
  top: calc((100% - var(--stage-pad) + var(--pt-room)) / 2 + var(--book-h) / 2 + var(--book-w) * .2 + var(--hint-gap) + .5em + var(--obj-shift, 0px));
  transform: translate(-50%, -50%); mix-blend-mode: soft-light;
  background: radial-gradient(closest-side, rgba(255,228,200,.95), rgba(255,228,200,.45) 55%, rgba(255,228,200,0));
  transition: opacity .8s ease;
}
html[data-theme="skin"] .stage:has(.hint.is-gone) .hint-lift { opacity: 0; }
@media (max-width: 600px) and (orientation: portrait) {   /* darker skin there: a touch of screen light on top */
  html[data-theme="skin"][data-hint-ink="black"][data-hint-patch="true"] .hint-lift { width: 17em; height: 5em;
    background: radial-gradient(closest-side, rgba(255,226,198,.95), rgba(255,226,198,.45) 55%, rgba(255,226,198,0)),
                radial-gradient(closest-side, rgba(255,226,198,.95), rgba(255,226,198,.45) 55%, rgba(255,226,198,0));
    box-shadow: none; }
  html[data-theme="skin"][data-hint-ink="black"][data-hint-patch="true"] .hint-lift::after { content: ""; position: absolute; inset: 0; mix-blend-mode: screen;
    background: radial-gradient(closest-side, rgba(255,214,182,.22), rgba(255,214,182,.08) 60%, rgba(255,214,182,0)); }
}
@media (max-height: 500px) and (orientation: landscape) and (pointer: coarse) { .stage { --stage-pad: 0px; } .hint, html[data-theme="skin"][data-hint-ink="black"][data-hint-patch="true"] .hint-lift { font-size: 1.12rem; } }

.floor-shadow {
  position: absolute; left: 6%; right: 6%; bottom: calc(var(--book-h) * -0.05); height: calc(var(--book-h) * 0.08);
  background: radial-gradient(closest-side, rgba(0,0,0,.95), transparent); filter: blur(10px);
  transition: transform var(--t-cover) var(--ease-io), opacity .6s;
  box-shadow: 0 0 calc(var(--book-w) * .4) rgba(255,255,255,.02);
}
.scene.is-open .floor-shadow { transform: translateX(var(--open-shift)) scaleX(2.1); }

/* soft ambient + tight contact shadow of the book on the surface (skin theme).
   main.js moves them with the tilt (--sx/--sy/--sa) */
.book-shadow { position: absolute; top: 0; left: 1.5%; width: 97%; height: 100%; pointer-events: none; display: none;
  border-radius: 3px; transition: left var(--t-cover) var(--ease-io), width var(--t-cover) var(--ease-io); }
.book-shadow.amb { background: rgba(38,10,4,.72); filter: blur(calc(var(--book-w) * .05));
  transform: translate(calc(var(--book-w) * (.06 + var(--sx, 0))), calc(var(--book-w) * (.085 + var(--sy, 0)))) scale(.99); opacity: var(--sa, 1); }
.book-shadow.contact { background: rgba(22,6,2,.85); filter: blur(calc(var(--book-w) * .01));
  transform: translate(calc(var(--book-w) * (.014 + var(--sx, 0) * .3)), calc(var(--book-w) * (.02 + var(--sy, 0) * .3))); }
.scene.is-open .book-shadow { left: calc(var(--open-shift) - var(--book-w)); width: auto; right: calc(var(--open-shift) * -1); }
/* glitch fix: the shadow only spreads under the left page once the cover is over (it led the cover as a black slab
   on the skin before), and on closing it pulls back while the cover is still lifting */
.book-shadow { width: auto; right: 1.5%; transition: left calc(var(--t-cover) * .4) var(--ease-io), right var(--t-cover) var(--ease-io); }
.scene.is-open .book-shadow { transition: left calc(var(--t-cover) * .55) var(--ease-io) calc(var(--t-cover) * .45), right var(--t-cover) var(--ease-io); }   /* right edge slides with the book, the left spreads once the cover is over */

/* ---------- 3D book ---------- */
.tilt, .book, .book > *, .sheet, .st { transform-style: preserve-3d; }
.tilt { position: absolute; inset: 0; transform: rotateX(var(--tx)) rotateY(var(--ty)); }

.book {
  position: absolute; inset: 0;
  transform: translateX(0) rotateX(4deg) rotateY(18deg);
  transition: transform var(--t-cover) var(--ease-io);
}
.book.is-open   { transform: translateX(var(--open-shift)) rotateX(0deg) rotateY(0deg); }
.book.is-back   { transform: translateX(0) rotateX(4deg) rotateY(162deg); transition-duration: var(--t-turn); }
.book.is-turning{ transform: translateX(0) rotateX(4deg) rotateY(378deg); transition-duration: var(--t-turn); }
.book.no-anim   { transition: none !important; }

/* ---- bendable sheets (soft cover + flicking leaves) ----
   Built by main.js as a chain of thin strips, each hinged on the previous
   one, so the sheet can curl. Every strip shows its slice of a full page. */
.cover-front, .leaves { position: absolute; left: 0; top: 0; width: 0; height: 0; }
.st { position: absolute; top: 0; transform-origin: 0 50%; }
.cover-front > .sheet { visibility: hidden; }
.cover-front.is-flexing > .sheet { visibility: visible; }
.cover-front.is-flexing > .flat { visibility: hidden; }
.fc { position: absolute; inset: 0; overflow: hidden; backface-visibility: hidden; -webkit-backface-visibility: hidden; }
.fc.b { transform: rotateY(180deg); }
.st[data-face="f"] > .fc.b, .st[data-face="b"] > .fc.f { visibility: hidden; }   /* main.js face culling */
.fc > .pg { position: absolute; top: 0; }
.fc > .sh { position: absolute; inset: 0; pointer-events: none; }
.fc.f > .sh { background: linear-gradient(90deg, rgb(28 18 8 / var(--f0, 0)), rgb(28 18 8 / var(--f1, 0))); }
.fc.b > .sh { background: linear-gradient(90deg, rgb(28 18 8 / var(--b1, 0)), rgb(28 18 8 / var(--b0, 0))); }

/* soft cover faces */
.pg.cv-out {
  background:
    linear-gradient(90deg, rgba(0,0,0,.28) 0, rgba(0,0,0,.06) 1.2%, transparent 4.2%, rgba(0,0,0,.16) 4.6%, rgba(255,255,255,.07) 5.1%, transparent 6%),
    radial-gradient(90% 60% at calc(28% - var(--lx, 0) * 30%) calc(18% + var(--ly, 0) * 30%), rgba(255,255,255,.085), transparent 70%),
    linear-gradient(calc(115deg + var(--ty) * 3), rgba(255,255,255,.07), transparent 45%, rgba(0,0,0,.18)),
    #1a1a1a var(--img-front) center / 100% 100% no-repeat;
  /* rim light on the cut edges */
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.07), inset 0 1px 0 rgba(255,255,255,.16), inset -1px 0 0 rgba(255,255,255,.12), inset 0 -1px 0 rgba(0,0,0,.5);
}
.pg.cv-in { background: var(--cover-in); }
.cv-in::after { content: ""; position: absolute; inset: 0; background: linear-gradient(270deg, rgba(60,40,20,.28), transparent 10%); }
.cover-art-back {
  position: absolute; inset: 0; backface-visibility: hidden; -webkit-backface-visibility: hidden; border-radius: 2px 1px 1px 2px;
  background: radial-gradient(90% 60% at calc(72% + var(--lx, 0) * 30%) calc(18% + var(--ly, 0) * 30%), rgba(255,255,255,.08), transparent 70%),
              linear-gradient(calc(245deg - var(--ty) * 3), rgba(255,255,255,.07), transparent 45%, rgba(0,0,0,.18)),
              #1a1a1a var(--img-back) center / 100% 100% no-repeat;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.07), inset 0 1px 0 rgba(255,255,255,.16), inset 1px 0 0 rgba(255,255,255,.12), inset 0 -1px 0 rgba(0,0,0,.5);
}

/* ---- pages ---- */
.page, .pg { width: var(--pg-w); height: var(--pg-h); background: var(--page); color: var(--ink); overflow: hidden; }
.page { position: absolute; left: 0; top: 0; backface-visibility: hidden; -webkit-backface-visibility: hidden; }
.page-right { transform: translateZ(calc(var(--hd) - 8px)); transition: transform .2s ease; }   /* 8px under the cover hinge: at 3px Firefox drew it over the closing cover */
.book.is-open .page-right { transform: translateZ(calc(var(--hd) + 2px)); transition: transform .2s ease calc(var(--t-cover) * .55); }
html[data-open-mode="foldback"] .book.is-open .page-right { transition-delay: calc(var(--t-cover) * .9); }
/* glitch fix (Firefox): the right page used to step forward .25s into the opening, while the cover hinge was still
   below it; Firefox then drew the whole page over the lifting cover (the cover vanished for ~4 frames). It now waits
   until the cover is past edge-on. */
.page-left { left: calc(var(--pg-w) * -1); transform: translateZ(calc(var(--hd) + 2px)); visibility: hidden; }
.page-left.is-shown { visibility: visible; }
/* gutter shading: .r = recto (right-hand page), .l = verso (left-hand page) */
.r::before, .l::before { content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 1; }
.r::before { background: linear-gradient(90deg, rgba(60,40,20,.36), rgba(60,40,20,.09) 6%, transparent 15%), linear-gradient(270deg, rgba(0,0,0,.05), transparent 2.5%); }
.l::before { background: linear-gradient(270deg, rgba(60,40,20,.34), rgba(60,40,20,.08) 6%, transparent 15%), linear-gradient(90deg, rgba(0,0,0,.06), transparent 2.5%); }

/* cast shadows of a turning sheet onto the page beneath */
.cast { position: absolute; top: 0; height: var(--pg-h); width: 0; opacity: 0; pointer-events: none;
  transform: translateZ(calc(var(--hd) + 2.2px)); backface-visibility: hidden; }
.cast-r { left: 0; background: linear-gradient(90deg, rgba(25,15,5,.62), rgba(25,15,5,.28) 70%, rgba(25,15,5,0)); }
.cast-l { right: 100%; left: auto; background: linear-gradient(270deg, rgba(25,15,5,.55), rgba(25,15,5,.24) 70%, rgba(25,15,5,0)); }

/* typeset page contents (shared by static pages and every strip copy) */
.page-inner {
  position: absolute; inset: 0; display: grid; grid-template-rows: auto minmax(0, 1fr) auto;
  padding: 9% 11% 7% 13%;
  font-family: "EB Garamond", Georgia, "Times New Roman", serif;
  font-size: max(12.5px, calc(var(--book-w) * 0.056));
}
.l .page-inner { padding: 9% 13% 7% 11%; }
.run-head {
  font-family: "Slad Woodcut", serif; font-feature-settings: "calt" 1;
  font-size: .62em; letter-spacing: .12em; text-align: center; opacity: .55; margin-bottom: 1.6em; line-height: 1;
}
.folio { font-size: .62em; text-align: center; opacity: .6; letter-spacing: .08em; padding-top: .6em; line-height: 1; }
.body {
  min-height: 0; overflow: hidden; line-height: 1.42; letter-spacing: .003em; hyphens: auto;
  font-variant-numeric: oldstyle-nums; font-feature-settings: "kern", "liga", "onum";
}
.body p { margin: 0; }
.prose { text-align: justify; max-height: calc(var(--lines, 99) * 1.42em); }
.prose p + p { text-indent: 1.2em; }
.snippet { overflow: auto; scrollbar-width: none; text-wrap: pretty; transition: opacity .25s ease; }
.snippet::-webkit-scrollbar { display: none; }
.snippet p { margin: 0 0 .7em; }
.snippet p + p { text-indent: 1.2em; margin-top: -.7em; }
.snippet .label {
  display: block; font-family: "Inter", sans-serif; font-size: .42em; letter-spacing: .16em; text-transform: uppercase;
  color: #9a5a2c; margin-bottom: 1.1em; opacity: .9;
}
.snippet p:first-of-type::first-letter { font-family: "Slad Woodcut", serif; font-size: 2.35em; float: left; line-height: .82; margin: .07em .08em 0 0; }
.titlepage { display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: .6em; padding-bottom: 18%; }
.titlepage .t1 { font-family: "Slad Woodcut", serif; font-feature-settings: "calt" 1; font-size: 2.3em; line-height: .95; }
.titlepage .t2 { font-family: "Slad Woodcut", serif; font-feature-settings: "calt" 1; font-size: .9em; letter-spacing: .1em; opacity: .7; }
.titlepage .rule { width: 2.2em; height: 1px; background: currentColor; opacity: .35; }

/* page-block edges (flush with the soft cover) */
.block-edge { position: absolute; background: var(--page-edge); backface-visibility: hidden; }
.block-edge::after { content: ""; position: absolute; inset: 0;
  background: repeating-linear-gradient(var(--dir, 90deg), rgba(0,0,0,.07) 0 1px, transparent 1px 3px), linear-gradient(var(--dir, 90deg), rgba(0,0,0,.18), transparent 30%, transparent 70%, rgba(0,0,0,.25)); }
.edge-fore, .edge-top, .edge-bottom { --e: calc(var(--depth) - var(--cover-t) * 2); }
.edge-fore { width: var(--e); height: var(--pg-h); top: 0; left: calc(var(--pg-w) - var(--e) / 2); transform: rotateY(90deg); border-radius: 1px; }
.edge-top, .edge-bottom { --dir: 0deg; width: var(--pg-w); height: var(--e); left: 0; }
.edge-top { top: calc(var(--e) / -2); transform: rotateX(90deg); }
.edge-bottom { top: calc(var(--pg-h) - var(--e) / 2); transform: rotateX(-90deg); filter: brightness(.7); }

/* spine: soft rounded paperback profile */
.spine {
  position: absolute; top: 0; height: var(--book-h); width: var(--depth); left: calc(var(--depth) / -2);
  transform: rotateY(-90deg); backface-visibility: hidden; overflow: hidden; border-radius: 2px;
  background: #161616 var(--img-spine) center / cover no-repeat;
  display: flex; flex-direction: column; align-items: center; justify-content: space-between; padding: 10% 0 9%;
}
.spine::after { content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(90deg, rgba(255,255,255,.16) 0, rgba(0,0,0,.45) 3%, rgba(0,0,0,.12) 10%, rgba(255,255,255,.07) 32%, rgba(255,255,255,.11) 46%, rgba(0,0,0,.02) 66%, rgba(0,0,0,.25) 90%, rgba(0,0,0,.5) 97%, rgba(255,255,255,.14) 100%),
    linear-gradient(180deg, rgba(255,255,255,.12), transparent 1.2%, transparent 98.8%, rgba(255,255,255,.08)),
    repeating-linear-gradient(0deg, transparent 0 37px, rgba(0,0,0,.05) 37px 38px, transparent 38px 61px); }
.spine.has-art > span { display: none; }
.spine span {
  writing-mode: vertical-rl; font-family: "Slad Woodcut", serif; font-feature-settings: "calt" 1;
  color: var(--spine-ink, #8e8e8e); opacity: .92; white-space: nowrap;
  font-size: min(calc(var(--depth) * .62), calc(var(--book-h) * .075)); line-height: 1; letter-spacing: .04em;
}
.spine .spine-author { font-size: min(calc(var(--depth) * .42), calc(var(--book-h) * .045)); }

.cover-back { position: absolute; inset: 0; transform: translateZ(calc(var(--hd) * -1)) rotateY(180deg); }

/* ---------- skin theme ---------- */
.bg-skin, .bg-lift, .bg-footlift, .bg-vignette, .bg-grain { display: none; position: fixed; pointer-events: none; z-index: 0; }
html[data-theme="skin"] {
  --bg: #6b4630; --fg: #f1e6dc; --muted: rgba(246,234,224,.82); --line: rgba(255,235,220,.25);
}
html[data-theme="skin"] body::before { display: none; }
html[data-theme="skin"] .bg-skin {
  display: block; inset: -16px;
  background-color: #6b4630; background-repeat: no-repeat; background-size: cover; background-position: var(--skin-focal);
  transform-origin: var(--skin-focal);
  transform: translate3d(var(--px, 0px), var(--py, 0px), 0) scale(var(--skin-zoom));
  filter: var(--skin-filter); will-change: transform;
}
html[data-theme="skin"] .bg-vignette {
  display: block; inset: 0; opacity: var(--skin-vignette);
  background:
    radial-gradient(ellipse 72% 70% at 44% 40%, transparent 38%, rgba(22,9,3,.75) 100%),
    linear-gradient(180deg, transparent 75%, rgba(22,9,3,.3));
}
/* soft light pooled under the tattooed wordmark so the ink reads on lit skin */
html[data-theme="skin"] .bg-lift {
  display: block; inset: 0; mix-blend-mode: soft-light;
  background:
    radial-gradient(ellipse clamp(220px, 34vw, 700px) clamp(120px, 20vw, 380px) at calc(var(--title-x) + clamp(50px, 4.5vw, 130px)) calc(var(--title-y) + clamp(12px, 1.2vw, 30px)), rgba(255,222,190,.75), rgba(255,222,190,0) 100%),
    radial-gradient(ellipse clamp(280px, 44vw, 960px) clamp(120px, 18vh, 280px) at 50% 100%, rgba(255,226,196,.95), rgba(255,226,196,.35) 55%, rgba(255,226,196,0) 100%);
}
@media (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  html[data-theme="skin"] .bg-lift { background:
    radial-gradient(ellipse 260px 140px at calc(var(--title-x) + 45px) 30px, rgba(255,222,190,.75), rgba(255,222,190,0) 100%),
    radial-gradient(ellipse 320px 160px at 100% 100%, rgba(255,226,196,.95), rgba(255,222,190,0) 100%),
    radial-gradient(ellipse 200px 50px at 50% 100%, rgba(255,222,190,.3), rgba(255,222,190,0) 100%); }
}
/* CONFIG.skinFootLift: a very large, very soft lift of the lower band behind the buttons. Soft-light (lifts mids, keeps the
   hue), centred below the screen and feathered over most of the viewport with an eased falloff, so there is no edge to see. */
html[data-theme="skin"][data-foot-lift="on"] .bg-footlift {
  display: block; inset: 0; mix-blend-mode: soft-light; opacity: var(--foot-lift, 0);
  background: radial-gradient(ellipse max(150vw, 900px) 78vh at 50% 112%,
    rgba(255,220,188,.9) 0%, rgba(255,220,188,.82) 16%, rgba(255,220,188,.66) 30%, rgba(255,220,188,.47) 44%,
    rgba(255,220,188,.29) 58%, rgba(255,220,188,.15) 72%, rgba(255,220,188,.055) 86%, rgba(255,220,188,0) 100%);
}
@media (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  html[data-theme="skin"][data-foot-lift="on"] .bg-footlift { background: radial-gradient(ellipse 110vw 120vh at 100% 112%,
    rgba(255,220,188,.9) 0%, rgba(255,220,188,.7) 25%, rgba(255,220,188,.4) 50%, rgba(255,220,188,.14) 75%, rgba(255,220,188,0) 100%); }
}
/* CONFIG.skinTint: colour wash over the skin layers only (they sit before the content in the root stacking context).
   'duotone' = gradient map: the #skin-tint SVG filter on .bg-skin (luminance -> shadow..colour..light table, built in
   index.html). Other modes = one colour sheet (.bg-tint) with that blend mode. */
.bg-tint, .bg-tint2 { display: none; position: fixed; inset: 0; pointer-events: none; z-index: 0; }
html[data-theme="skin"][data-tint] .bg-tint { display: block; background: var(--tint); opacity: var(--tint-op, 1); mix-blend-mode: var(--tint-mode, color); }
html[data-theme="skin"][data-tint="duotone"] .bg-tint { display: none; }   /* duotone is the #skin-tint filter on .bg-skin */
html[data-theme="skin"] .bg-grain {
  display: block; inset: 0; opacity: var(--skin-grain);
  background: url("assets/img/skin/grain-256.png") repeat; background-size: 256px 256px; mix-blend-mode: overlay;
}
html[data-theme="skin"] .floor-shadow { display: none; }
html[data-theme="skin"] .book-shadow { display: block; }
html[data-theme="skin"] .book-shadow.amb { background: rgba(14,4,0,.82); }
html[data-theme="skin"] .book-shadow.contact { background: rgba(8,2,0,.92); }
/* warmer, stronger rim light so the matte black separates from the dark warm skin */
html[data-theme="skin"] .pg.cv-out, html[data-theme="skin"] .cover-art-back {
  box-shadow: inset 0 0 0 1px rgba(255,228,205,.13), inset 0 1px 0 rgba(255,228,205,.3), inset -1px 0 0 rgba(255,228,205,.22), inset 1px 0 0 rgba(255,228,205,.08), inset 0 -1px 0 rgba(0,0,0,.55);
}
/* wordmark as a healed tattoo: blue-black ink sitting under the skin */
html[data-theme="skin"] .site-head { mix-blend-mode: multiply; }
html[data-theme="skin"] .wordmark {
  color: #121a24; opacity: .9; filter: url(#tattoo);
  text-shadow: 0 0 1px rgba(15,30,50,.9), 0 0 5px rgba(25,50,75,.45), 0 0 14px rgba(30,60,85,.25);
}
/* the rest of the UI is tattooed too: same ink, blend and feathering as the wordmark.
   (stage/footer drop their z-index so the blend reaches the skin layers) */
html[data-theme="skin"] .stage, html[data-theme="skin"] .site-foot { z-index: auto; }
html[data-theme="skin"] { --ink-ui: #101822; --ink-ui-soft: #121a24; }
html[data-theme="skin"] .hint { mix-blend-mode: multiply; }
html[data-theme="skin"][data-pt-ink="white"] .product-title {   /* healed white ink: off-white, patchy, no glow/patch */
  mix-blend-mode: normal; color: #f2ede4; opacity: .93; filter: url(#tattoo-white-title); text-shadow: none;
}
html[data-theme="skin"][data-pt-ink="grey"] .product-title {    /* the cover title's grey (sampled from the cover art: ~#848484 with
                                                                   darker mottling), same patchy ink texture, no glow/patch */
  mix-blend-mode: normal; color: #868686; opacity: .97; filter: url(#tattoo-white-title); text-shadow: none;
}
html[data-theme="skin"][data-pt-ink="black"] .product-title {                 /* same healed-tattoo ink as the wordmark */
  mix-blend-mode: multiply; color: #121a24; opacity: .9; filter: url(#tattoo);
  text-shadow: 0 0 1px rgba(15,30,50,.9), 0 0 5px rgba(25,50,75,.45), 0 0 14px rgba(30,60,85,.25);
}
html[data-theme="skin"] .hint {
  filter: url(#tattoo);
  text-shadow: 0 0 1px rgba(15,30,50,.85), 0 0 5px rgba(25,50,75,.4), 0 0 13px rgba(30,60,85,.22);
}
/* footer buttons on skin: black ink layer (multiplied into the skin) + a white ink layer that bleeds up through it on
   hover / keyboard focus / tap. The old red "fresh tattoo" glow is gone: the ink change is the feedback, no patch. */
html[data-theme="skin"] .ink-btn::before, html[data-theme="skin"] .ink-btn::after { display: none; }
html[data-theme="skin"] .ink-btn { z-index: auto; }   /* no stacking context, so the black layer multiplies into the skin */
html[data-theme="skin"] .ink-btn .frm { display: block; }
html[data-theme="skin"] .ink-btn .ink-k {
  color: var(--ink-ui); opacity: .95; mix-blend-mode: multiply; filter: var(--k-filter, url(#tattoo));
  text-shadow: 0 0 1px rgba(15,30,50,.85), 0 0 5px rgba(25,50,75,.4), 0 0 13px rgba(30,60,85,.22);
}
html[data-theme="skin"] .ink-btn.is-selected .ink-k {
  color: #070b10; opacity: 1;
  text-shadow: 0 0 1px rgba(10,20,35,1), 0 0 6px rgba(25,50,75,.55), 0 0 16px rgba(30,60,85,.3);
}
html[data-theme="skin"] .ink-btn .ink-w {
  display: block; color: var(--btn-hover-ink, #c8c5bf); text-shadow: none; mix-blend-mode: normal; filter: var(--w-filter, none); opacity: 0;
  -webkit-text-stroke: .55px currentColor;      /* the woodcut face is thin: a hair of extra body so white holds on lit skin */
}
html[data-theme="skin"] .audio-btn .ink-w { display: flex; }
html[data-theme="skin"] .ink-btn.fx-ready .ink-w { opacity: 1; }     /* the bleed filter's mask does the hiding */
html[data-theme="skin"] .ink-btn:focus-visible { outline-color: #0b1016; }
/* phones (and any coarse pointer): heavier, darker, tighter ink, larger sublabel, thicker frame strokes. No halo, no patch. */
@media (pointer: coarse), (max-width: 700px) {
  html[data-theme="skin"] .ink-btn .ink-k, html[data-theme="skin"] .ink-btn.is-selected .ink-k {
    color: #030508; opacity: 1; -webkit-text-stroke: .45px currentColor;
    text-shadow: 0 0 .6px rgba(3,6,10,.95), 0 0 1.6px rgba(6,12,20,.5);
  }
  html[data-theme="skin"] .ink-btn .ink-w { -webkit-text-stroke: .45px currentColor; }
  html[data-theme="skin"] .ink-btn .frm { -webkit-mask: var(--frame-mask-thick); mask: var(--frame-mask-thick); }
  html[data-theme="skin"] .audio-btn .sub { font-size: .62em; letter-spacing: .12em; opacity: 1; margin-top: .3em; }
}
@media (max-width: 600px) and (orientation: portrait) { html[data-theme="skin"] .ink-btn, html[data-theme="skin"] button.ink-btn { font-size: 1.2rem; } }
/* reduced motion: plain crossfade between the two inks (JS swaps the opacities, the filters stay static) */
html[data-motion="strict"][data-theme="skin"] .ink-btn .ink-k, html[data-motion="strict"][data-theme="skin"] .ink-btn .ink-w { transition: opacity .35s ease; }
html[data-theme="skin"] .hint { opacity: .95; }
html[data-theme="skin"] .hint.is-gone { opacity: 0; }
/* black hint without the light patch: legibility from the ink only (darker, a hair bolder, tight ink spread, no halo) */
html[data-theme="skin"][data-hint-ink="black"] .hint {
  color: #070b10; opacity: 1; -webkit-text-stroke: .35px currentColor;
  text-shadow: 0 0 .6px rgba(8,12,18,.95), 0 0 1.6px rgba(12,20,30,.5);
}
html[data-theme="skin"][data-hint-ink="black"] .hint.is-gone { opacity: 0; }
/* hintInk 'white': creamy white-ink tattoo. Screen blend lets skin texture show through;
   tight bright core + soft pinkish halo reads as healed, slightly raised white ink. */
html[data-theme="skin"][data-hint-ink="white"] .hint {
  mix-blend-mode: screen; color: #f4ead9; opacity: .97;
  filter: url(#tattoo-white);
  text-shadow: 0 -.5px 0 rgba(255,250,240,.55), 0 0 1px rgba(255,240,225,.9), 0 0 6px rgba(255,190,180,.32), 0 0 16px rgba(255,170,160,.16);
  animation-name: hint-pulse-white;
}
html[data-theme="skin"][data-hint-ink="white"] .hint.is-gone { opacity: 0; animation: none; }
@keyframes hint-pulse-white { 0%, 100% { opacity: .97; } 50% { opacity: .84; } }
@media (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  /* landscape phones: the hint sits on the brightest skin, so pool a little shadow under it instead of light */
  html[data-theme="skin"][data-hint-ink="white"] .bg-lift { background:
    radial-gradient(ellipse 260px 140px at calc(var(--title-x) + 45px) 30px, rgba(255,222,190,.75), rgba(255,222,190,0) 100%),
    radial-gradient(ellipse 320px 160px at 100% 100%, rgba(255,226,196,.95), rgba(255,226,196,0) 100%),
    radial-gradient(ellipse 240px 60px at 50% 100%, rgba(30,14,6,.55), rgba(30,14,6,0) 100%); }
}
html[data-theme="skin"] .scene:focus-visible::after { border-color: rgba(255,240,230,.6); }

/* ---------- carousel + vinyl ---------- */
:root { --frame-mask-thick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 60' preserveAspectRatio='none'%3E%3Cg fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath vector-effect='non-scaling-stroke' stroke-width='3.5' d='M7 8 C 60 4, 140 10, 194 5 M192 3 C 197 21, 193 41, 195 56 M197 53 C 140 57, 70 52, 5 55 M7 58 C 3 41, 8 22, 4 4'/%3E%3Cpath vector-effect='non-scaling-stroke' stroke-width='1.8' opacity='.75' d='M3 11 C 70 8, 125 12, 189 9 M10 51 C 80 55, 150 49, 191 52 M188 6 C 190 25, 188 37, 190 50'/%3E%3C/g%3E%3C/svg%3E"); --vinyl-size: 1; --vinyl-d: calc(min(var(--book-w-fit) * .85 / var(--ratio) * .8, 72vw) * var(--vinyl-size));   /* sized off the fitted book at the old .85 scale, so bookScale shrinks only the book */ --label-bg: #e9e1cf; --label-ink: #17130f; }
.slot { translate: 0 var(--obj-shift, 0px);  grid-area: 1 / 1; position: relative; will-change: transform; }
.stage > .slot { align-self: center; justify-self: center; }
.slot[inert] { pointer-events: none; }
.slot.is-away { visibility: hidden; }
.vscene {
  position: relative; width: var(--vinyl-d); height: var(--vinyl-d); --vw: calc(var(--vinyl-d) * .72);
  perspective: calc(var(--vinyl-d) * 5); perspective-origin: 50% 40%;
  cursor: pointer; outline: none; -webkit-tap-highlight-color: transparent; border-radius: 50%;
}
.vscene:focus-visible::after { content: ""; position: absolute; inset: -14px; border: 1px solid var(--muted); border-radius: 50%; pointer-events: none; }
html[data-theme="skin"] .vscene:focus-visible::after { border-color: rgba(255,240,230,.6); }
/* shadows on the surface, like the book's (main.js moves them with the tilt via --sx/--sy/--sa) */
.v-shadow { position: absolute; inset: 1%; border-radius: 50%; pointer-events: none; }
.v-shadow.amb { background: rgba(14,4,0,.8); filter: blur(calc(var(--vw) * .05));
  transform: translate(calc(var(--vw) * (.06 + var(--sx, 0))), calc(var(--vw) * (.085 + var(--sy, 0)))) scale(.99); opacity: var(--sa, 1); }
.v-shadow.contact { background: rgba(8,2,0,.9); filter: blur(calc(var(--vw) * .012));
  transform: translate(calc(var(--vw) * (.014 + var(--sx, 0) * .3)), calc(var(--vw) * (.02 + var(--sy, 0) * .3))); }
.v-shadow.sleeve-sh { inset: auto; border-radius: 2px; left: -13%; top: -6%; width: 98%; height: 98%; rotate: -4deg; background: rgba(14,4,0,.7); }
html:not([data-theme="skin"]) .v-shadow { opacity: .55; }
[data-sleeve="false"] .sleeve, [data-sleeve="false"] .sleeve-sh { display: none; }

.vtilt { position: absolute; inset: 0; transform-style: preserve-3d; transform: rotateX(var(--tx)) rotateY(var(--ty)); }
/* matte black sleeve, peeking out behind and up-left (same black + grey as the book cover) */
.sleeve { position: absolute; left: -13%; top: -6%; width: 98%; height: 98%; rotate: -4deg; transform: translateZ(-6px); border-radius: 1.5px;
  background: radial-gradient(120% 90% at 18% 10%, rgba(255,255,255,.07), transparent 55%), linear-gradient(160deg, #1b1b1d, #0c0c0d 70%);
  box-shadow: inset 0 0 0 1px rgba(255,228,205,.1), inset 1px 1px 0 rgba(255,228,205,.18); overflow: hidden; }
.sleeve::after { content: ""; position: absolute; inset: 0; background: url("assets/img/skin/grain-256.png"); background-size: 128px; opacity: .18; mix-blend-mode: overlay; }
.sleeve-t { position: absolute; left: 7%; top: 6%; font-family: "Slad Woodcut", serif; font-size: calc(var(--vinyl-d) * .045); letter-spacing: .08em;
  color: #8d8a85; opacity: .8; white-space: nowrap; }

.record { position: absolute; inset: 0; transform-style: preserve-3d; container-type: size; }
/* the hole goes through everything: every record layer gets the same mask */
.rec-face, .rec-edge { position: absolute; inset: 0; border-radius: 50%;
  -webkit-mask: radial-gradient(circle closest-side, transparent 0 2.3%, #000 2.55%); mask: radial-gradient(circle closest-side, transparent 0 2.3%, #000 2.55%); }
.rec-edge { background: #19191b; box-shadow: 0 0 0 .5px rgba(255,255,255,.06); }
.rec-edge.e1 { transform: translateZ(-1.2px); }
.rec-edge.e2 { transform: translateZ(-2.4px); background: #101011; }
.rec-face { overflow: hidden; transform: translateZ(0); background: #0b0b0c; }
.disc { position: absolute; inset: 0; border-radius: 50%; transform: rotate(var(--spin, 0deg)); will-change: transform; }
/* fine concentric grooves + track gaps + smooth lead-in rim + run-out area */
.grooves { position: absolute; inset: 0; border-radius: 50%;
  background:
    radial-gradient(circle closest-side, transparent 0 34.5%, rgba(255,255,255,.035) 35%, transparent 36%, transparent 39%, rgba(255,255,255,.05) 39.4%, transparent 40%),
    radial-gradient(circle closest-side, transparent 0 51.6%, rgba(0,0,0,.6) 52%, rgba(255,255,255,.05) 52.4%, transparent 52.9%,
      transparent 63.4%, rgba(0,0,0,.6) 63.8%, rgba(255,255,255,.05) 64.2%, transparent 64.7%,
      transparent 74.6%, rgba(0,0,0,.6) 75%, rgba(255,255,255,.05) 75.4%, transparent 75.9%,
      transparent 85.2%, rgba(0,0,0,.6) 85.6%, rgba(255,255,255,.05) 86%, transparent 86.5%,
      transparent 95.6%, #121214 96.2%, #0d0d0e 98.6%, #222226 99.4%, #0a0a0a 100%),
    repeating-radial-gradient(circle, #0c0c0d 0, #0f0f11 .8px, #0c0c0d 1.6px),   /* low contrast: fine pitch without moire rings */
    #0b0b0c; }
/* subtle non-uniformity that rotates with the record, so the spin reads */
.wobble { position: absolute; inset: 0; border-radius: 50%; mix-blend-mode: screen; opacity: .9;
  background: conic-gradient(from 20deg, rgba(255,255,255,.012), rgba(255,255,255,.035) 40deg, rgba(255,255,255,.008) 90deg, rgba(255,255,255,.03) 150deg,
    rgba(255,255,255,.01) 205deg, rgba(255,255,255,.04) 260deg, rgba(255,255,255,.012) 320deg, rgba(255,255,255,.012));
  -webkit-mask: radial-gradient(circle closest-side, transparent 0 40%, #000 41% 95%, transparent 96%); mask: radial-gradient(circle closest-side, transparent 0 40%, #000 41% 95%, transparent 96%); }
/* centre label (rotates with the record) */
.vlabel { position: absolute; left: 33.5%; top: 33.5%; width: 33%; height: 33%; border-radius: 50%; color: var(--label-ink);
  background: radial-gradient(circle closest-side, transparent 0 82%, rgba(0,0,0,.1) 84%, transparent 86%),
              radial-gradient(circle closest-side, rgba(0,0,0,.25) 0 8.5%, transparent 10.5%),
              radial-gradient(120% 120% at 30% 25%, rgba(255,255,255,.18), transparent 60%), var(--label-bg);
  box-shadow: 0 0 0 .6px rgba(0,0,0,.6), inset 0 0 calc(var(--vinyl-d) * .01) rgba(0,0,0,.25);
  display: grid; grid-template-rows: 1fr auto auto 1fr; justify-items: center; font-family: "Slad Woodcut", serif; overflow: hidden; }
.vlabel::after { content: ""; position: absolute; inset: 0; background: url("assets/img/skin/grain-256.png"); background-size: 96px; opacity: .25; mix-blend-mode: multiply; }
.vlabel.has-image { background: var(--label-img) center / cover; }
.vlabel.has-image > span { display: none; }
.vl-title { grid-row: 1; align-self: end; font-size: 3.9cqw; letter-spacing: .05em; line-height: 1; margin-bottom: 4.6cqw; white-space: nowrap; }
.vl-rule { grid-row: 2; width: 10cqw; height: .25cqw; background: currentColor; opacity: .55; margin-top: -3.4cqw; }
.vl-author { grid-row: 4; align-self: start; font-size: 2.25cqw; letter-spacing: .1em; margin-top: 4.4cqw; white-space: nowrap; }
.vl-small { position: absolute; top: 50%; transform: translateY(-50%); font-size: 1.25cqw; letter-spacing: .08em; opacity: .75; }
.vl-l { left: 14%; } .vl-r { right: 13%; }
/* anisotropic groove sheen: two opposite wedges facing the light, fixed to the light (doesn't rotate with the record) */
.sheen { position: absolute; inset: 0; border-radius: 50%; mix-blend-mode: screen; opacity: var(--sheen-i, .9); pointer-events: none;
  background:
    conic-gradient(from var(--sheen-a, -45deg), rgba(225,232,245,0) 0deg, rgba(225,232,245,.07) 7deg, rgba(235,240,250,.26) 14deg, rgba(225,232,245,.07) 22deg, rgba(225,232,245,0) 32deg,
      rgba(225,232,245,0) 180deg, rgba(225,232,245,.05) 188deg, rgba(235,240,250,.16) 195deg, rgba(225,232,245,.05) 203deg, rgba(225,232,245,0) 213deg),
    conic-gradient(from calc(var(--sheen-a, -45deg) + 60deg), rgba(255,240,225,0) 0deg, rgba(255,240,225,.035) 14deg, rgba(255,240,225,0) 40deg, rgba(255,240,225,0) 180deg, rgba(255,240,225,.03) 196deg, rgba(255,240,225,0) 220deg);
  -webkit-mask: radial-gradient(circle closest-side, transparent 0 34%, rgba(0,0,0,.6) 36%, #000 60% 95.5%, transparent 96.5%);
          mask: radial-gradient(circle closest-side, transparent 0 34%, rgba(0,0,0,.6) 36%, #000 60% 95.5%, transparent 96.5%); }
/* rim bevel lit from the upper left */
.bevel { position: absolute; inset: 0; border-radius: 50%; pointer-events: none;
  box-shadow: inset 1px 1px 0 rgba(255,236,220,.22), inset -1px -1px 0 rgba(0,0,0,.6), inset 0 0 0 1.5px rgba(255,255,255,.035); }
html[data-theme="skin"] .rec-face { box-shadow: 0 0 0 .6px rgba(255,228,205,.12); }

/* reduced motion: crossfade instead of the swing */
.carousel-fade .slot { transition: opacity .45s ease; }

/* ---------- reduced motion (html[data-motion], set in index.html from the OS setting + CONFIG.reducedMotion) ---------- */
html[data-motion="strict"] { --t-cover: 1ms; --t-turn: 1ms; }
html[data-motion="strict"] .hint { animation: none; }
html[data-motion="soft"] { --t-cover: 650ms; --t-turn: 800ms; }   /* 'soften': same moves, a bit quicker and calmer */

/* ---------- product title: spray-paint stencil (CONFIG.productTitleStyle 'spray') ----------
   The h1 keeps its real text (transparent, still selectable / read out); the paint is a pre-rendered image placed over the
   same em box (tools/make_spray_title.py renders with the same font, tracking and line-height). Matte paint, no glow. */
html[data-pt-style="spray"][data-pt-ink] .product-title { color: transparent; filter: none; text-shadow: none; mix-blend-mode: normal; opacity: 1; }
html[data-pt-style="spray"] .product-title::before {
  content: ""; position: absolute; pointer-events: none;
  left: calc(50% - 3.7580em); top: -0.2800em; width: 7.5136em; height: 2.3273em;
  background-position: center; background-size: 100% 100%; background-repeat: no-repeat;
}

/* ---------- PREVIEW hint reveal (CONFIG.hintReveal) ----------
   main.js animates the #hint-bleed filter from a 0..1 progress (blotchy stain -> crisp ink); the text stays in the DOM. */
html[data-theme="skin"][data-hint-reveal] .hint { filter: url(#hint-bleed); animation: none; }
html[data-hint-reveal] .hint.is-dormant { visibility: visible; }
html[data-motion="strict"][data-theme="skin"][data-hint-reveal] .hint { filter: url(#tattoo); }

/* skinFootLiftScope 'phones': only portrait phones get the lower-band lift */
@media not ((max-width: 600px) and (orientation: portrait)) {
  html[data-theme="skin"][data-foot-lift="on"][data-foot-lift-scope="phones"] .bg-footlift { display: none; }
}

/* ---------- fold-back open mode (narrow screens; main.js decides, html[data-open-mode]) ----------
   The cover and left-hand pages wrap right round behind the book, so the book never slides: one page, centred. */
html[data-open-mode="foldback"] { --open-shift: 0px; }
html[data-open-mode="foldback"] .scene.is-open .floor-shadow { transform: none; }
html[data-open-mode="foldback"] .scene.is-open .book-shadow { left: 1.5%; right: 1.5%; }
html[data-open-mode="foldback"] .scene.is-open:focus-visible::after { left: -14px; right: -14px; }
html[data-open-mode="foldback"] .page-left { display: none; }
/* the page is the whole view now: a little larger type, a touch less margin */
html[data-open-mode="foldback"] .page-inner { font-size: max(13.6px, calc(var(--book-w) * .066)); padding: 8.5% 9.5% 6.5% 11%; }
html[data-open-mode="foldback"] .l .page-inner { padding: 8.5% 11% 6.5% 9.5%; }
/* the folded cover wrapping round the spine: a sliver of rounded black board just left of the page block */
/* the folded-back pages at the spine: a narrow, pale stack of page edges curling round behind the visible page
   (paper colour, faint edge lines, a soft shadow onto the skin) - reads as a paperback folded back on itself */
.book.is-fold::before {
  content: ""; position: absolute; top: .5%; bottom: .5%; left: calc(var(--hd) * -.62); width: calc(var(--hd) * .66 + 1px);
  border-radius: 45% 0 0 45% / 2.2% 0 0 2.2%; pointer-events: none; opacity: 0; transform: translateZ(calc(var(--hd) * .5));
  background:
    linear-gradient(90deg, rgba(40,28,14,.42), rgba(40,28,14,.12) 38%, rgba(255,250,238,.16) 62%, rgba(60,40,20,.28) 92%, rgba(60,40,20,.4)),
    repeating-linear-gradient(90deg, rgba(90,70,45,.22) 0 .5px, transparent .5px 1.6px),
    var(--page-edge);
  box-shadow: -1px 0 2.5px rgba(20,10,4,.45), -2px 1px 7px rgba(20,10,4,.25);
  transition: opacity .25s ease;
}
.book.is-fold.is-open::before { opacity: 1; transition: opacity .45s ease calc(var(--t-cover) * 1.05); }
/* fold-back zoom (CONFIG.openZoomPhone, clamped by main.js so it clears the wordmark and the buttons) */
html[data-open-mode="foldback"] .scene { transition: scale calc(var(--t-cover) * 1.5) var(--ease-io); }
html[data-open-mode="foldback"] .scene.is-open { scale: var(--open-zoom, 1); }
/* the book's shadow on the skin narrows with the book as it turns over (main.js --turn-sx), so no book-shaped
   dark slab is left standing behind the edge-on book */
.book-shadow { scale: var(--turn-sx, 1) 1; }
html[data-theme="skin"] .hint.is-gone { opacity: 0 !important; }   /* reduced-motion reveal sets inline opacity; interaction still hides it */

/* touch: the book and the vinyl take the thumb (hold-to-tilt, swipe, tap) - no page scroll/zoom, no callout or selection */
.scene, .vscene, .scene *, .vscene *, .slot { touch-action: none; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }


/* ======================================================================
   SOFTEN (CONFIG.bookSoften, ?soften=0|1): make the box read as a worn, slightly rounded paperback.
   Nothing here touches the art pixels: it only adds a 1px transparent AA ring around each textured face,
   rounded fore-edge corners, edge burn, a matte tilt-driven sheen, a rounded spine and a hinge crease.
   Strengths come from main.js as --sf-* (0..1). ====================================================== */
html[data-soften="on"] {
  --sf-r: calc(var(--book-w) * var(--sf-radius, .022));   /* fore-edge corner radius */
}
/* 1. anti-aliasing: the face geometry keeps its size, but the paint starts 1px inside it, so the jagged polygon edge
      is transparent and the art's own edge is filtered (smooth in Chromium and Firefox) */
html[data-soften="on"] .pg.cv-out,
html[data-soften="on"] .cover-art-back,
html[data-soften="on"] .spine,
html[data-soften="on"] .page-right,
html[data-soften="on"] .block-edge {
  box-sizing: border-box; padding: var(--sf-aa, 1px);
  background-clip: content-box !important; background-origin: content-box !important;
  outline: 1px solid transparent; will-change: transform;
  -webkit-backface-visibility: hidden; backface-visibility: hidden;
}
html[data-soften="on"] .page-right { background-clip: content-box; }
/* 2. rounded, worn corners: fore-edge corners round, the hinge side stays square */
html[data-soften="on"] .pg.cv-out, html[data-soften="on"] .page-right { border-radius: 1px var(--sf-r) var(--sf-r) 1px / 1px calc(var(--sf-r) * .9) calc(var(--sf-r) * .9) 1px; }
html[data-soften="on"] .cover-art-back { border-radius: var(--sf-r) 1px 1px var(--sf-r) / calc(var(--sf-r) * .9) 1px 1px calc(var(--sf-r) * .9); }
html[data-soften="on"] .fc.f, html[data-soften="on"] .fc.b { border-radius: inherit; }
/* the cut-edge rim light moves inside the AA ring (it would sit on the jagged edge otherwise) */
html[data-soften="on"] .pg.cv-out, html[data-soften="on"] .cover-art-back { box-shadow: none; }
html[data-soften="on"] .pg.cv-out::after,
html[data-soften="on"] .cover-art-back::after {
  content: ""; position: absolute; inset: var(--sf-aa, 1px); pointer-events: none; border-radius: inherit;
  /* edge burn: the edges roll off instead of cutting hard; corners a little darker (handled, rubbed) */
  box-shadow:
    inset 0 0 0 1px rgba(255,248,232, calc(.10 * var(--sf-rim, 1))),
    inset 0 0 calc(var(--book-w) * .012) rgba(18,10,4, calc(.55 * var(--sf-burn, .5))),
    inset 0 0 calc(var(--book-w) * .06) rgba(18,10,4, calc(.45 * var(--sf-burn, .5)));
  background:
    radial-gradient(18% 11% at 100% 0%, rgba(20,12,5, calc(.45 * var(--sf-burn, .5))), transparent 100%),
    radial-gradient(18% 11% at 100% 100%, rgba(20,12,5, calc(.5 * var(--sf-burn, .5))), transparent 100%),
    /* matte pulp-paper sheen that drifts with the tilt (--lx/--ly from main.js): broad, soft, low */
    radial-gradient(75% 55% at calc(30% - var(--lx, 0) * 55%) calc(22% + var(--ly, 0) * 45%),
      rgba(255,246,228, calc(.13 * var(--sf-sheen, .5))), rgba(255,246,228, calc(.04 * var(--sf-sheen, .5))) 45%, transparent 75%),
    linear-gradient(calc(120deg + var(--ty, 0deg) * 4), rgba(255,250,240, calc(.05 * var(--sf-sheen, .5))), transparent 40%, rgba(0,0,0, calc(.10 * var(--sf-sheen, .5))));
}
/* back: hinge on the right, fore-edge corners on the left */
html[data-soften="on"] .cover-art-back::after {
  background:
    radial-gradient(18% 11% at 0% 0%, rgba(20,12,5, calc(.45 * var(--sf-burn, .5))), transparent 100%),
    radial-gradient(18% 11% at 0% 100%, rgba(20,12,5, calc(.5 * var(--sf-burn, .5))), transparent 100%),
    radial-gradient(75% 55% at calc(70% - var(--lx, 0) * 55%) calc(22% + var(--ly, 0) * 45%),
      rgba(255,246,228, calc(.13 * var(--sf-sheen, .5))), rgba(255,246,228, calc(.04 * var(--sf-sheen, .5))) 45%, transparent 75%),
    linear-gradient(calc(240deg - var(--ty, 0deg) * 4), rgba(255,250,240, calc(.05 * var(--sf-sheen, .5))), transparent 40%, rgba(0,0,0, calc(.10 * var(--sf-sheen, .5))));
}
/* 3. hinge crease: the soft cover scored and flexed a few mm in from the spine */
html[data-soften="on"] .pg.cv-out::before,
html[data-soften="on"] .cover-art-back::before {
  content: ""; position: absolute; top: var(--sf-aa, 1px); bottom: var(--sf-aa, 1px); width: 9%; pointer-events: none; z-index: 1;
  opacity: var(--sf-hinge, .5);
}
html[data-soften="on"] .pg.cv-out::before { left: var(--sf-aa, 1px);
  background: linear-gradient(90deg, rgba(0,0,0,.42), rgba(0,0,0,.10) 22%, rgba(255,244,226,.13) 34%, rgba(0,0,0,.30) 44%, rgba(0,0,0,.06) 62%, transparent); }
html[data-soften="on"] .cover-art-back::before { right: var(--sf-aa, 1px);
  background: linear-gradient(270deg, rgba(0,0,0,.42), rgba(0,0,0,.10) 22%, rgba(255,244,226,.13) 34%, rgba(0,0,0,.30) 44%, rgba(0,0,0,.06) 62%, transparent); }
/* 4. rounded spine: a cylinder-ish light/dark profile (dark at both joints, a soft highlight just off centre)
      plus a faint vertical crease pair where it flexes; the base overlay keeps its texture lines */
html[data-soften="on"] .spine { border-radius: calc(var(--depth) * .18) / calc(var(--depth) * .06); }
html[data-soften="on"] .spine::before {
  content: ""; position: absolute; inset: var(--sf-aa, 1px); pointer-events: none; z-index: 1; border-radius: inherit;
  opacity: var(--sf-spine, .6);
  background:
    linear-gradient(90deg, rgba(0,0,0,.62) 0%, rgba(0,0,0,.28) 7%, rgba(0,0,0,.05) 20%, rgba(255,246,230,.16) 38%, rgba(255,246,230,.22) 46%,
                    rgba(255,246,230,.08) 56%, rgba(0,0,0,.06) 72%, rgba(0,0,0,.32) 91%, rgba(0,0,0,.66) 100%),
    linear-gradient(90deg, transparent 14%, rgba(0,0,0,.18) 15%, transparent 16.5%, transparent 83.5%, rgba(0,0,0,.18) 85%, transparent 86%);
}
html[data-soften="on"] .spine::after { inset: var(--sf-aa, 1px); border-radius: inherit; }
/* 5. page block: rounded fore-edge corners, finer paper lines, shading that rolls off towards the covers */
html[data-soften="on"] .block-edge { border-radius: calc(var(--depth) * .25) / calc(var(--sf-r) * .8); }
html[data-soften="on"] .block-edge::after {
  inset: var(--sf-aa, 1px); border-radius: inherit;
  background:
    repeating-linear-gradient(var(--dir, 90deg), rgba(70,50,30,.10) 0 .6px, transparent .6px 2.1px),
    linear-gradient(var(--dir, 90deg), rgba(30,18,8,.42), rgba(0,0,0,.06) 18%, rgba(255,250,238,.10) 50%, rgba(0,0,0,.08) 82%, rgba(30,18,8,.48));
}
/* 6. contact shadow: a little softer and deeper where the book meets the skin */
html[data-soften="on"][data-theme="skin"] .book-shadow.contact { filter: blur(calc(var(--book-w) * .055 * var(--bs-b, 1))); }
/* bendable sheets: each strip face reaches a hair past its neighbour, so Firefox's per-strip edge AA leaves no seams */
html[data-soften="on"] .st > .fc { left: -1px; right: -1px; }
/* joints (seam fix 19 Oct): the spine-side edges of the front and back covers and both long edges of the spine get no
   AA inset, no rounding and no edge burn, and the spine runs 1px past each joint (tucked under the covers), so the
   panels overlap instead of leaving a 1-2px gap that showed the page block / skin through as a hairline seam */
html[data-soften="on"] .pg.cv-out { padding-left: 0; border-top-left-radius: 0; border-bottom-left-radius: 0; }
html[data-soften="on"] .cover-art-back { padding-right: 0; border-top-right-radius: 0; border-bottom-right-radius: 0; overflow: hidden; }
html[data-soften="on"] .pg.cv-out::after { left: calc(var(--book-w) * -.2); border-radius: 0 var(--sf-r) var(--sf-r) 0 / 0 calc(var(--sf-r) * .9) calc(var(--sf-r) * .9) 0; }
html[data-soften="on"] .cover-art-back::after { right: calc(var(--book-w) * -.2); border-radius: var(--sf-r) 0 0 var(--sf-r) / calc(var(--sf-r) * .9) 0 0 calc(var(--sf-r) * .9); }
html[data-soften="on"] .pg.cv-out::before { left: 0; }
html[data-soften="on"] .cover-art-back::before { right: 0; }
html[data-soften="on"] .spine {
  padding-left: 0; padding-right: 0; border-radius: 0;
  left: calc(var(--depth) / -2 - 1px); width: calc(var(--depth) + 2px);
}
html[data-soften="on"] .spine::before, html[data-soften="on"] .spine::after { left: 0; right: 0; border-radius: 0; }

/* ======================================================================
   PAGE SOFTEN (CONFIG.pageSoften, ?pagesoften=0|1): old pulp paperback pages instead of flat boxy cards.
   Strengths from main.js as --ps-* (0..1.5). Text is never filtered: grain/tone sit in the page background,
   gutter shading in ::before, edge wear in ::after (both pointer-free, under the text's contrast). ============== */
html[data-pagesoften="on"] {
  --ps-r: calc(var(--book-w) * .02 * var(--ps-corners, 1));       /* outer corner radius */
}
/* 1. paper: warm pulp tone (CONFIG.pageSoftColor) + fine grain (multiply) + yellowed, browned outer edges.
      The veil (page colour at 1 - grain) dials the grain strength. Background positions are page-relative, so the
      strip copies of a turning leaf line up exactly. */
html[data-pagesoften="on"] .page,
html[data-pagesoften="on"] .pg.r,
html[data-pagesoften="on"] .pg.l:not(.cv-in) {
  background-color: var(--page);
  background-image:
    radial-gradient(130% 100% at 38% 50%, transparent 58%, rgba(170,128,62, calc(.20 * var(--ps-tone, 1))) 100%),
    linear-gradient(color-mix(in srgb, var(--page) calc((1 - var(--ps-grain, .9)) * 100%), transparent), color-mix(in srgb, var(--page) calc((1 - var(--ps-grain, .9)) * 100%), transparent)),
    url("assets/img/paper/paper-grain-256.png");
  background-size: 100% 100%, 100% 100%, calc(var(--book-w) * .62) auto;
  background-repeat: no-repeat, no-repeat, repeat;
  background-blend-mode: multiply, normal, multiply;
}
html[data-pagesoften="on"] .pg.l:not(.cv-in), html[data-pagesoften="on"] .page-left {
  background-image:
    radial-gradient(130% 100% at 62% 50%, transparent 58%, rgba(170,128,62, calc(.20 * var(--ps-tone, 1))) 100%),
    linear-gradient(color-mix(in srgb, var(--page) calc((1 - var(--ps-grain, .9)) * 100%), transparent), color-mix(in srgb, var(--page) calc((1 - var(--ps-grain, .9)) * 100%), transparent)),
    url("assets/img/paper/paper-grain-256.png");
}
/* 2. the 1px AA ring on the three outer edges (never the gutter edge, so nothing opens at the spine) */
html[data-pagesoften="on"] .page-right, html[data-pagesoften="on"] .pg.r {
  box-sizing: border-box; padding: 1px 1px 1px 0; background-clip: content-box; background-origin: border-box; }
html[data-pagesoften="on"] .page-left, html[data-pagesoften="on"] .pg.l:not(.cv-in) {
  box-sizing: border-box; padding: 1px 0 1px 1px; background-clip: content-box; background-origin: border-box; }
/* 3. rounded, slightly uneven worn outer corners (the hinge side stays square) */
html[data-pagesoften="on"] .page-right, html[data-pagesoften="on"] .pg.r {
  border-radius: 0 var(--ps-r) calc(var(--ps-r) * 1.35) 0 / 0 calc(var(--ps-r) * .8) calc(var(--ps-r) * 1.1) 0; }
html[data-pagesoften="on"] .page-left, html[data-pagesoften="on"] .pg.l:not(.cv-in) {
  border-radius: var(--ps-r) 0 0 calc(var(--ps-r) * 1.35) / calc(var(--ps-r) * .8) 0 0 calc(var(--ps-r) * 1.1); }
/* 4. gutter shading into the spine (deeper, curved fall-off, a faint lift where the page bows up off the gutter) */
html[data-pagesoften="on"] .r::before { inset: 1px 1px 1px 0; border-radius: inherit;
  background: linear-gradient(90deg, rgba(52,32,12, calc(.44 * var(--ps-gutter, 1))), rgba(52,32,12, calc(.22 * var(--ps-gutter, 1))) 2.6%,
    rgba(52,32,12, calc(.09 * var(--ps-gutter, 1))) 8%, rgba(255,248,230, calc(.08 * var(--ps-gutter, 1))) 15%, transparent 24%); }
html[data-pagesoften="on"] .l:not(.cv-in)::before { inset: 1px 0 1px 1px; border-radius: inherit;
  background: linear-gradient(270deg, rgba(52,32,12, calc(.42 * var(--ps-gutter, 1))), rgba(52,32,12, calc(.21 * var(--ps-gutter, 1))) 2.6%,
    rgba(52,32,12, calc(.085 * var(--ps-gutter, 1))) 8%, rgba(255,248,230, calc(.08 * var(--ps-gutter, 1))) 15%, transparent 24%); }
/* 5. edge wear: outer edges roll off a touch darker, corners rubbed, a faint thumb-soiling on the fore-edge */
html[data-pagesoften="on"] .r::after, html[data-pagesoften="on"] .l:not(.cv-in)::after {
  content: ""; position: absolute; pointer-events: none; z-index: 1; border-radius: inherit; }
html[data-pagesoften="on"] .r::after { inset: 1px 1px 1px 0;
  background:
    radial-gradient(9% 6% at 100% 0%, rgba(110,72,30, calc(.22 * var(--ps-corners, 1))), transparent),
    radial-gradient(11% 7% at 100% 100%, rgba(110,72,30, calc(.26 * var(--ps-corners, 1))), transparent),
    radial-gradient(6% 22% at 100% 64%, rgba(90,62,30, calc(.08 * var(--ps-tone, 1))), transparent),
    linear-gradient(270deg, rgba(120,84,40, calc(.14 * var(--ps-tone, 1))), transparent 2.2%),
    linear-gradient(180deg, rgba(120,84,40, calc(.10 * var(--ps-tone, 1))), transparent 1.4%, transparent 98.6%, rgba(120,84,40, calc(.12 * var(--ps-tone, 1)))); }
html[data-pagesoften="on"] .l:not(.cv-in)::after { inset: 1px 0 1px 1px;
  background:
    radial-gradient(9% 6% at 0% 0%, rgba(110,72,30, calc(.22 * var(--ps-corners, 1))), transparent),
    radial-gradient(11% 7% at 0% 100%, rgba(110,72,30, calc(.26 * var(--ps-corners, 1))), transparent),
    radial-gradient(6% 22% at 0% 64%, rgba(90,62,30, calc(.08 * var(--ps-tone, 1))), transparent),
    linear-gradient(90deg, rgba(120,84,40, calc(.14 * var(--ps-tone, 1))), transparent 2.2%),
    linear-gradient(180deg, rgba(120,84,40, calc(.10 * var(--ps-tone, 1))), transparent 1.4%, transparent 98.6%, rgba(120,84,40, calc(.12 * var(--ps-tone, 1)))); }
html[data-pagesoften="on"] .page-inner { z-index: 2; }   /* text above the overlays: crisp, never tinted */
/* 6. softer cast shadow from the turning leaf: long, smooth fall-off, darkest in the gutter */
html[data-pagesoften="on"] .cast-r { background: linear-gradient(90deg, rgba(30,18,6,.56), rgba(30,18,6,.34) 18%, rgba(30,18,6,.16) 55%, rgba(30,18,6,.05) 85%, rgba(30,18,6,0)); }
html[data-pagesoften="on"] .cast-l { background: linear-gradient(270deg, rgba(30,18,6,.5), rgba(30,18,6,.3) 18%, rgba(30,18,6,.14) 55%, rgba(30,18,6,.04) 85%, rgba(30,18,6,0)); }
/* 7. page-stack thickness at the fore-edge while open: stepped page edges + a soft shadow onto the cover board */
html[data-pagesoften="on"] .book.is-open .page-right {
  box-shadow:
    calc(1px * var(--ps-stack, 1)) 0 0 #ddd1b6, calc(2px * var(--ps-stack, 1)) .5px 0 #c9bb9c, calc(3px * var(--ps-stack, 1)) .5px 0 #dacdb1,
    calc(4px * var(--ps-stack, 1)) 1px 0 #c4b596, calc(5px * var(--ps-stack, 1)) 1px 0 #d5c8aa,
    calc(6px * var(--ps-stack, 1)) 1.5px 3px rgba(40,24,8,.32); }
html[data-pagesoften="on"] .page-left.is-shown {
  box-shadow:
    calc(-1px * var(--ps-stack, 1)) 0 0 #ddd1b6, calc(-2px * var(--ps-stack, 1)) .5px 0 #c9bb9c, calc(-3px * var(--ps-stack, 1)) 1px 0 #d5c8aa,
    calc(-4px * var(--ps-stack, 1)) 1.5px 3px rgba(40,24,8,.3); }
html[data-open-mode="foldback"][data-pagesoften="on"] .book.is-open .page-right {
  box-shadow: calc(1px * var(--ps-stack, 1)) 0 0 #ddd1b6, calc(2px * var(--ps-stack, 1)) .5px 0 #c9bb9c, calc(3px * var(--ps-stack, 1)) 1px 0 #d5c8aa,
    calc(4px * var(--ps-stack, 1)) 1.5px 2.5px rgba(40,24,8,.3); }

/* flat turns (touch): one plane per turning sheet, the curl is faked with shading - a darker band rolling in from the
   lifted edge with a soft highlight just ahead of it (--cx/--hl/--cd from main.js) */
.sheet.is-flat .fc.f > .sh { background:
  linear-gradient(90deg, transparent calc(var(--cx, 100%) - 16%), rgb(255 250 240 / var(--hl, 0)) calc(var(--cx, 100%) - 4%), rgb(28 18 8 / var(--cd, 0)) calc(var(--cx, 100%) + 10%), rgb(28 18 8 / calc(var(--cd, 0) * .6)) 100%),
  linear-gradient(90deg, rgb(28 18 8 / var(--f0, 0)), rgb(28 18 8 / var(--f1, 0))); }
.sheet.is-flat .fc.b > .sh { background:
  linear-gradient(270deg, transparent calc(var(--cx, 100%) - 16%), rgb(255 250 240 / var(--hl, 0)) calc(var(--cx, 100%) - 4%), rgb(28 18 8 / var(--cd, 0)) calc(var(--cx, 100%) + 10%), rgb(28 18 8 / calc(var(--cd, 0) * .6)) 100%),
  linear-gradient(90deg, rgb(28 18 8 / var(--b1, 0)), rgb(28 18 8 / var(--b0, 0))); }
.sheet.is-flat .st > .fc { left: 0; right: 0; }

/* the book's shadows on the skin sit well BEHIND the book in depth (and are scaled back up to the same on-screen size,
   about the scene's perspective origin). Android Chrome sorted the flat shadow at z=0 together with the book's 3D
   planes, so on the back view it drew a dark book-sized slab over the spine and the left third of the back cover
   (the parts that turn behind z=0). At -0.6 x book width nothing of the book can ever be behind it. */
.book-shadow { transform-origin: 50% 40%; }
.book-shadow.amb { transform: translateZ(calc(var(--book-w) * -.6)) scale(1.1091) translate(calc(var(--book-w) * (.06 + var(--sx, 0))), calc(var(--book-w) * (.085 + var(--sy, 0)))) scale(.99); }
.book-shadow.contact { transform: translateZ(calc(var(--book-w) * -.6)) scale(1.1091) translate(calc(var(--book-w) * (.014 + var(--sx, 0) * .3)), calc(var(--book-w) * (.02 + var(--sy, 0) * .3))); }
.fc.b > .pg > .page-inner { opacity: var(--bo, 1); }   /* main.js backFade (fold-back) */
/* load: until the cover is built (after the web fonts), the title page must not show where the cover will be */
.book:not(.is-built) .page-right { visibility: hidden; }
/* the shadows thin out while the book is edge-on during the turn-over (no dark slab beside the spine) */
.book-shadow.contact { opacity: calc(.4 + .6 * var(--turn-sx, 1)); }
.book-shadow.amb { opacity: calc(var(--sa, 1) * (.45 + .55 * var(--turn-sx, 1))); }
/* shadow footprint driven by main.js (--shl/--shw): follows the book's slide and the cover's sweep */
.scene .book-shadow { left: var(--shl, 1.5%) !important; width: var(--shw, 97%) !important; right: auto !important; transition: none !important; }

/* ======================================================================
   FOLD-BACK OPEN (phones), 19 Oct pm: the shown page is the front-most leaf of a book folded back on itself.
   1) no page stack / fore-edge / offset layers to its right or below - only its soft drop shadow
   2) the fold at the left is ONE page bending back: a slim rounded lip in the page's own tone and grain
   Once the opening has settled (main.js .fold-settled), everything folded away behind the page is hidden, so even
   the stronger touch tilt cannot show it; it comes back the moment the book starts to close. ================== */
html[data-open-mode="foldback"] .book.is-open .page-right,
html[data-open-mode="foldback"][data-pagesoften="on"] .book.is-open .page-right {
  box-shadow: 1px 2px 3px rgba(30,18,6,.22), 3px 5px 10px rgba(30,18,6,.16); }
html[data-open-mode="foldback"] .book .block-edge { transition: opacity .2s ease; }
html[data-open-mode="foldback"] .book.is-open .block-edge { opacity: 0; transition: opacity .3s ease calc(var(--t-cover) * .9); }
.book.fold-settled > .spine, .book.fold-settled > .cover-back, .book.fold-settled > .cover-front, .book.fold-settled > .block-edge { visibility: hidden; }
/* the fold lip: a single page curling back round the spine - dark where it turns away, a soft highlight on the
   crown of the curve, then a gentle shade back into the page; paper tone + grain, no lines */
.book.is-fold::before {
  left: calc(var(--hd) * -.30); width: calc(var(--hd) * .30 + 2px); top: .35%; bottom: .35%;
  border-radius: 100% 0 0 100% / 3.2% 0 0 3.2%;
  background-color: var(--page);
  background-image:
    linear-gradient(90deg, rgba(48,30,12,.46) 0%, rgba(48,30,12,.20) 22%, rgba(255,249,236,.26) 50%, rgba(255,249,236,.10) 64%, rgba(48,30,12,.10) 84%, rgba(48,30,12,.20) 100%),
    url("assets/img/paper/paper-grain-256.png");
  background-size: 100% 100%, calc(var(--book-w) * .62) auto;
  background-blend-mode: normal, multiply;
  box-shadow: -1px 0 2px rgba(20,10,4,.30), -2px 1px 6px rgba(20,10,4,.16);
  transform: translateZ(calc(var(--hd) + 1.5px));
}

/* ======================================================================
   SOFT SHADOW POOLS (19 Oct pm): with the stronger touch tilt you could see under the book, and the shadows were
   blurred rectangles - a hard dark slab at the edge. Both are now feathered elliptical pools: darkest under the
   middle of the book, fading to nothing well inside their box, so no straight edge exists at any tilt. Same boxes,
   same JS footprint (--shl/--shw), same depth/offset transforms and opacities as before - only the fill changed. */
.scene .book-shadow.amb, .scene .book-shadow.contact { background: none !important; overflow: visible; }
.book-shadow.amb::before, .book-shadow.contact::before { content: ""; position: absolute; pointer-events: none; border-radius: 50%; }
/* the broad ambient pool: a little larger than the book, very soft */
.book-shadow.amb { filter: blur(calc(var(--book-w) * .08 * var(--bs-b, 1))); }
.book-shadow.amb::before { inset: -9% -14%;
  background: radial-gradient(closest-side, rgba(14,4,0,.80) 0%, rgba(14,4,0,.66) 38%, rgba(14,4,0,.36) 66%, rgba(14,4,0,.12) 86%, rgba(14,4,0,0) 100%); }
/* the contact shadow: tighter, kept inside the book's footprint so it only shows as a soft darkening right at the edges */
.book-shadow.contact, html[data-soften="on"][data-theme="skin"] .book-shadow.contact { filter: blur(calc(var(--book-w) * .055 * var(--bs-b, 1))); }
.book-shadow.contact::before { inset: 1.5% 2%;
  background: radial-gradient(closest-side, rgba(8,2,0,.85) 0%, rgba(8,2,0,.72) 55%, rgba(8,2,0,.32) 82%, rgba(8,2,0,0) 100%); }
html:not([data-theme="skin"]) .book-shadow.amb::before { background: radial-gradient(closest-side, rgba(38,10,4,.66), rgba(38,10,4,.3) 66%, transparent); }

/* fold-back close (19 Oct pm): nothing pops at the start of the close. The fold lip stays put while the cover is
   still behind the book and fades out only as the cover swings round past the spine; the page-block edges fade in
   over the same span (--lipo: 1 -> 0, set from the cover angle in main.js). */
.book.is-fold.fold-closing::before { opacity: var(--lipo, 1); transition: none; }
html[data-open-mode="foldback"] .book.fold-closing .block-edge { opacity: calc(1 - var(--lipo, 1)); transition: none; }

/* ======================================================================
   19 Oct 13:00 - page edges, fold-back block, shadows, buttons
   ---------------------------------------------------------------------- */
/* PAGE EDGES (fore-edge, top, bottom; and the fold side in fold-back): stacked sheets seen edge-on. Warm pulp a shade
   deeper than the page (#eadfc6 family), fine sheet lines running along the edge (two interleaved spacings so they
   are not mechanical), the paper grain, a darker roll-off where the block meets the covers, and a slow uneven
   mottling along the length. Flat faces, no filters (the bottom edge's old brightness() filter is now a gradient). */
.block-edge { --dir: 90deg; --along: 180deg; }
.edge-top, .edge-bottom, .edge-foldside.is-h { --dir: 0deg; --along: 90deg; }
.book > .block-edge { background-color: #e8d8b5 !important; filter: none !important;
  background-image: url("assets/img/paper/paper-grain-256.png") !important; background-size: calc(var(--book-w) * .5) auto !important;
  background-repeat: repeat !important; background-blend-mode: multiply; }
.book > .block-edge::after {
  background:
    repeating-linear-gradient(var(--dir), rgba(110,80,44,.15) 0 .45px, transparent .45px 1.3px),
    repeating-linear-gradient(var(--dir), rgba(255,250,238,.22) 0 .4px, transparent .4px 2.9px),
    repeating-linear-gradient(var(--dir), rgba(70,50,28,.10) 0 .7px, transparent .7px 4.7px),
    linear-gradient(var(--along), rgba(70,48,24,.10), rgba(255,248,232,.06) 9%, rgba(70,48,24,.05) 23%, rgba(255,248,232,.08) 38%,
      rgba(70,48,24,.09) 52%, rgba(255,248,232,.04) 67%, rgba(70,48,24,.07) 81%, rgba(255,248,232,.06) 92%, rgba(70,48,24,.12)),
    linear-gradient(var(--dir), rgba(40,24,10,.45), rgba(40,24,10,.12) 9%, transparent 22%, rgba(255,250,238,.07) 50%, transparent 78%, rgba(40,24,10,.14) 91%, rgba(40,24,10,.5)) !important;
}
.book > .edge-bottom::after { box-shadow: inset 0 0 0 999px rgba(40,24,10,.22); }   /* underside: in its own shade */

/* FOLD-BACK OPEN: the doubled-over book keeps its whole thickness behind the shown page. The page-block faces
   (fore-edge, top, bottom) stay, reaching right up to the page, plus a fold side at the left that ties into the
   lip; the folded cover sits at the back. Straight on, all of them are edge-on/facing away, so nothing pokes out
   to the right or below - they only appear as real side faces when the book is tilted. */
html[data-open-mode="foldback"] .book .block-edge:not(.edge-foldside),
html[data-open-mode="foldback"] .book.is-open .block-edge:not(.edge-foldside),
html[data-open-mode="foldback"] .book.fold-closing .block-edge:not(.edge-foldside) { opacity: 1; transition: none; }
.book.fold-settled > .cover-back, .book.fold-settled > .block-edge { visibility: visible; }   /* the spine stays hidden: the fold side covers it */
html:not([data-engine="webgl"]) .book.fold-settled > .edge-fore { --e: calc(var(--depth) + 2px); transform: translateZ(1px) rotateY(90deg); }
html:not([data-engine="webgl"]) .book.fold-settled > .edge-top { --e: calc(var(--depth) + 2px); left: calc(var(--hd) * -.30); width: calc(var(--pg-w) + var(--hd) * .30); transform: translateZ(1px) rotateX(90deg); }
html:not([data-engine="webgl"]) .book.fold-settled > .edge-bottom { --e: calc(var(--depth) + 2px); left: calc(var(--hd) * -.30); width: calc(var(--pg-w) + var(--hd) * .30); transform: translateZ(1px) rotateX(-90deg); }
.edge-foldside { display: none; }
html .book.is-fold > .edge-foldside {
  display: block; --e: calc(var(--depth) + 1.5px); width: var(--e); height: var(--pg-h); top: 0;
  left: calc(var(--hd) * -.30 - var(--e) / 2 + 1px); transform: translateZ(.75px) rotateY(-90deg); border-radius: 0;
  opacity: 0; transition: opacity .25s ease;
}
html .book.is-fold.is-open > .edge-foldside { opacity: 1; transition: opacity .45s ease calc(var(--t-cover) * 1.05); }
html .book.is-fold.fold-closing > .edge-foldside { opacity: var(--lipo, 1); transition: none; }
/* the fold side reads as the rounded fold of the doubled-over pages: lightest at the front lip, rolling into shade */
.book > .edge-foldside::after {
  background:
    repeating-linear-gradient(90deg, rgba(92,70,42,.16) 0 .45px, transparent .45px 1.4px),
    linear-gradient(90deg, rgba(40,24,10,.38), rgba(40,24,10,.16) 35%, rgba(255,250,238,.10) 78%, rgba(40,24,10,.10)) !important;
}

/* SHADOWS (19 Oct 14:20): same shape, offset and darkness as the vinyl-matched round, but more blur so a hard touch
   tilt never reveals a straight edge. Contact is the one that looked boxy; ambient gets a little more too.
   CONFIG.bookShadow {contact, ambient, blur} -> --bs-c / --bs-a / --bs-b. */
.book-shadow.amb { filter: blur(calc(var(--book-w) * .08 * var(--bs-b, 1))); }
.book-shadow.amb::before { inset: 0 0.5%; border-radius: 20% / 12%;
  background: radial-gradient(closest-side, rgb(14 4 0 / calc(.78 * var(--bs-a, 1))) 70%, rgb(14 4 0 / calc(.66 * var(--bs-a, 1))) 100%),
    rgb(14 4 0 / calc(.66 * var(--bs-a, 1))); }
.book-shadow.contact, html[data-soften="on"][data-theme="skin"] .book-shadow.contact { filter: blur(calc(var(--book-w) * .055 * var(--bs-b, 1))); }
.book-shadow.contact::before { inset: 1.2% 1.6%; border-radius: 14% / 9%;
  background: rgb(8 2 0 / calc(.82 * var(--bs-c, 1))); }
html:not([data-theme="skin"]) .book-shadow.amb::before { opacity: .6; }

/* FOOTER BUTTONS without the ink bleed (CONFIG.buttonInk false, the default): black ink only, no white copy, no
   per-button bleed filters (main.js does not build them); the underline marks the active button and keyboard focus. */
html[data-btn-ink="off"] .ink-btn .ink-w { display: none !important; }
html[data-btn-ink="off"] .ink-btn:focus-visible .sel { opacity: .75; transform: none; }
/* the page-block faces are single flat planes: their ::after (lines/shading) must not be 3D-sorted as a separate,
   coplanar plane - Chromium then dropped whole parts of the face below eye level when the book was tilted */
.book > .block-edge { transform-style: flat !important; }

/* ======================================================================
   19 Oct 13:55 - FOLD-BACK JOINTS + CLOSE HAND-OVER
   One set of edges at every frame: the shown page's depth, the page-block faces' reach and the fold lip/side all
   follow the cover angle (main.js foldVars: --pz, --lipo), in the open and the close alike, instead of switching on
   classes/transitions. The old close stepped the page back 10px at the first frame while the lip and fold side stayed
   forward - that 10px of lip/fold side standing proud of the page was the phantom strip beside the fold.
   Joints: the faces are square and unpadded in fold-back (the 1px anti-alias padding left a transparent 1px band at
   the front of each face = the dark sliver), they sit 1.5px inside the page's outline and reach 1px past its plane,
   so page and faces overlap and no gap can open at any tilt or DPR. */
html .book.is-fold .page-right, html[data-pagesoften="on"] .book.is-fold.is-open .page-right {
  transform: translateZ(calc(var(--hd) - 8px + 10px * var(--pz, 0))) !important; transition: none !important; }
html .book.is-fold > .block-edge { padding: calc(var(--sf-aa, 1px) * (1 - var(--pz, 0))) !important; border-radius: 0 !important; }
html .book.is-fold > .block-edge::after { inset: 0 !important; border-radius: 0 !important; }
html .book.is-fold > .edge-fore, html .book.is-fold > .edge-top, html .book.is-fold > .edge-bottom {
  --e: calc(var(--depth) - var(--cover-t) * 2 + (var(--cover-t) * 2 + 3px) * var(--pz, 0)); --j: calc(1.5px * var(--pz, 0)); }
html .book.is-fold > .edge-fore { left: calc(var(--pg-w) - var(--e) / 2 - var(--j)); transform: translateZ(var(--j)) rotateY(90deg); }
html .book.is-fold > .edge-top, html .book.is-fold > .edge-bottom {
  left: calc(var(--hd) * -.30 * var(--lipo, 0)); width: calc(var(--pg-w) + var(--hd) * .30 * var(--lipo, 0)); }
html .book.is-fold > .edge-top { top: calc(var(--e) / -2 + var(--j)); transform: translateZ(var(--j)) rotateX(90deg); }
html .book.is-fold > .edge-bottom { top: calc(var(--pg-h) - var(--e) / 2 - var(--j)); transform: translateZ(var(--j)) rotateX(-90deg); }
html .book.is-fold > .edge-foldside { --e: calc(var(--depth) + 2.5px); transform: translateZ(1.25px) rotateY(-90deg);
  opacity: var(--lipo, 0) !important; transition: none !important; }
html .book.is-fold::before, html .book.is-fold.is-open::before { opacity: var(--lipo, 0) !important; transition: none !important; }
/* the page's own drop shadow fell on the page plane just outside it, i.e. over the front of the new block faces: at a
   tilt it was a dark line along the joint. The block now carries the depth and the ground shadow does the rest. */
html .book.is-fold.is-open .page-right, html[data-pagesoften="on"] .book.is-fold.is-open .page-right { box-shadow: none !important; }
/* fold side joint: the lip's outer drop shadow drew a dark line onto the fold side face, and the face stood a hair
   taller than the lip (pointed tip at its top). Now the lip carries no outer shadow (the face is its continuation) and
   the face spans exactly the lip's height. */
html .book.is-fold::before { box-shadow: none !important; }
html .book.is-fold > .edge-foldside { top: .35%; height: 99.3%; }

/* ======================================================================
   19 Oct 13:58 - NO BLUE LINK STATES. On Android the "Buy the book" <a> flashed/stayed blue-teal after a tap: the
   browser's tap highlight (rgba(51,181,229,.4)) was still on for the link (only the <button> had it off), and nothing
   pinned the link's ink against :visited/:active states. The ink is black in every state; the frame, underline and
   outline use currentColor, so they follow. Keyboard focus keeps a visible underline + dashed outline in black ink. */
html, a, button, .ink-btn, .ink-btn *, .scene, .scene *, .vscene, .vscene *, .slot, .wordmark { -webkit-tap-highlight-color: transparent !important; }
a.ink-btn, a.ink-btn:link, a.ink-btn:visited, a.ink-btn:hover, a.ink-btn:active, a.ink-btn:focus, a.ink-btn:focus-visible,
button.ink-btn, button.ink-btn:hover, button.ink-btn:active, button.ink-btn:focus, button.ink-btn:focus-visible {
  color: var(--ink-ui, var(--fg)); text-decoration: none; }
a.ink-btn .ink-k, a.ink-btn:visited .ink-k, a.ink-btn:active .ink-k, a.ink-btn:focus .ink-k { color: inherit; }
.ink-btn:focus:not(:focus-visible) { outline: none; }
.ink-btn:focus-visible { outline: 2px dashed #0b1016 !important; outline-offset: 7px; }
html:not([data-theme="skin"]) .ink-btn:focus-visible { outline-color: currentColor !important; }

/* ======================================================================
   19 Oct 14:25 - FOLD-BACK LEFT EDGE = ONE CURVE. The slim lip (::before) plus the flat fold-side face read as two
   parallel slabs with a step at the top. They are replaced by a single half-round fold: six narrow paper strips on a
   half cylinder from the front of the page (z = page plane) round to the back of the block, squashed in x so it stays
   slim straight on. Paper tone + grain throughout, lit on the crown, darkening as it turns away; the strips that
   face sideways/back carry faint page lines (the doubled-over pages), so a tilted view shows the block's side as part
   of the same curve. The top/bottom page-edge faces end in a matching half-ellipse, so the ends are tucked round.
   Fades with the cover angle exactly like the old lip (--lipo), so the open/close hand-over is unchanged. */
html .book.is-fold::before { display: none !important; }
html .book.is-fold > .edge-foldside { display: none !important; }
.fold-curve { display: none; }
html .book.is-fold > .fold-curve {
  --r: calc((var(--depth) + 2.5px) / 2); --w: calc(var(--r) * .5176 + 1px); --sq: .2;
  display: block; position: absolute; left: 0; top: 0; width: 0; height: var(--pg-h); pointer-events: none;
  transform-style: preserve-3d; transform: scaleX(var(--sq)); opacity: var(--lipo, 0); }
html .book.is-fold > .fold-curve > i {
  --a: calc((var(--i) + .5) * 30deg);
  position: absolute; top: 0; height: 100%; left: calc(var(--w) / -2); width: var(--w);
  -webkit-backface-visibility: hidden; backface-visibility: hidden;
  transform: translateZ(1.25px) rotateY(calc(var(--a) * -1)) translateZ(var(--r));
  background-color: var(--page);
  background-image: linear-gradient(var(--shade), var(--shade)), var(--lines, linear-gradient(transparent, transparent)), url("assets/img/paper/paper-grain-256.png");
  background-size: 100% 100%, 100% 100%, calc(var(--book-w) * .62) auto; background-blend-mode: normal, normal, multiply; }
html .book.is-fold > .fold-curve > i:nth-child(1) { --shade: rgba(48,30,12,.05); }
html .book.is-fold > .fold-curve > i:nth-child(2) { --shade: rgba(255,249,236,.20); }
html .book.is-fold > .fold-curve > i:nth-child(3) { --shade: rgba(48,30,12,.08); --lines: repeating-linear-gradient(90deg, rgba(110,80,44,.10) 0 .45px, transparent .45px 1.4px); }
html .book.is-fold > .fold-curve > i:nth-child(4) { --shade: rgba(48,30,12,.18); --lines: repeating-linear-gradient(90deg, rgba(110,80,44,.14) 0 .45px, transparent .45px 1.3px); }
html .book.is-fold > .fold-curve > i:nth-child(5) { --shade: rgba(48,30,12,.28); --lines: repeating-linear-gradient(90deg, rgba(110,80,44,.14) 0 .45px, transparent .45px 1.3px); }
html .book.is-fold > .fold-curve > i:nth-child(6) { --shade: rgba(48,30,12,.36); --lines: repeating-linear-gradient(90deg, rgba(110,80,44,.14) 0 .45px, transparent .45px 1.3px); }
/* top/bottom page-edge faces: reach round under the curve and end in the same half-ellipse */
html .book.is-fold > .edge-top, html .book.is-fold > .edge-bottom {
  left: calc(var(--depth) * -.10 * var(--lipo, 0)); width: calc(var(--pg-w) + var(--depth) * .10 * var(--lipo, 0));
  border-radius: calc(var(--depth) * .10 * var(--lipo, 0) + .01px) 0 0 calc(var(--depth) * .10 * var(--lipo, 0) + .01px) / 50% 0 0 50% !important; }
html .book.is-fold > .edge-top::after, html .book.is-fold > .edge-bottom::after { border-radius: inherit !important; }
/* the curve shades continuously strip to strip (left edge of each strip = further round the fold): matches the page
   at the front (no gutter line - in fold-back the page flows into the fold, so its gutter shadow is dropped), lit on
   the crown, then darkening as it turns away to the back. A light warm tint matches the page's edge tone. */
html .book.is-fold > .fold-curve > i {
  background-image: linear-gradient(90deg, var(--s1), var(--s0)), linear-gradient(rgba(170,128,62,.13), rgba(170,128,62,.13)), var(--lines, linear-gradient(transparent, transparent)), url("assets/img/paper/paper-grain-256.png");
  background-size: 100% 100%, 100% 100%, 100% 100%, calc(var(--book-w) * .62) auto; background-blend-mode: normal, multiply, normal, multiply; }
html .book.is-fold > .fold-curve > i:nth-child(1) { --s0: rgba(255,249,236,0); --s1: rgba(255,249,236,.24); }
html .book.is-fold > .fold-curve > i:nth-child(2) { --s0: rgba(255,249,236,.24); --s1: rgba(48,30,12,.07); }
html .book.is-fold > .fold-curve > i:nth-child(3) { --s0: rgba(48,30,12,.07); --s1: rgba(48,30,12,.22); }
html .book.is-fold > .fold-curve > i:nth-child(4) { --s0: rgba(48,30,12,.22); --s1: rgba(48,30,12,.32); }
html .book.is-fold > .fold-curve > i:nth-child(5) { --s0: rgba(48,30,12,.32); --s1: rgba(48,30,12,.40); }
html .book.is-fold > .fold-curve > i:nth-child(6) { --s0: rgba(48,30,12,.40); --s1: rgba(48,30,12,.46); }
html .book.is-fold.fold-settled .page-right.r::before { background: linear-gradient(90deg, rgba(48,30,12,.04), transparent 5%) !important; }
html .book.is-fold > .fold-curve { left: 1px; }   /* overlap the page by 1px: scaleX shrinks the strips' own overlap */
/* tuning: the front of the fold matches the page's own warm edge tone; gentler crown highlight, then a steady roll into shade */
html .book.is-fold > .fold-curve > i {
  background-image: linear-gradient(90deg, var(--s1), var(--s0)), linear-gradient(rgba(170,128,62,.22), rgba(170,128,62,.22)), var(--lines, linear-gradient(transparent, transparent)), url("assets/img/paper/paper-grain-256.png"); }
html .book.is-fold > .fold-curve > i:nth-child(1) { --s0: rgba(255,249,236,0); --s1: rgba(255,249,236,.10); }
html .book.is-fold > .fold-curve > i:nth-child(2) { --s0: rgba(255,249,236,.10); --s1: rgba(48,30,12,.10); }
html .book.is-fold > .fold-curve > i:nth-child(3) { --s0: rgba(48,30,12,.10); --s1: rgba(48,30,12,.24); }
html .book.is-fold > .fold-curve > i:nth-child(4) { --s0: rgba(48,30,12,.24); --s1: rgba(48,30,12,.33); }
html .book.is-fold > .fold-curve > i:nth-child(1), html .book.is-fold > .fold-curve > i:nth-child(2) { --lines: linear-gradient(transparent, transparent); }

/* ======================================================================
   19 Oct 14:45 - REACTIVE BOOK SHADOW: main.js projects the tilted book onto the ground with a fixed upper-front light
   and hands each layer one matrix (--shm: the slide, stretch and skew, incl. the resting offset). Same depth trick and
   on-screen size compensation as before; at rest the matrix is the old offset, so the resting look is unchanged. */
.book-shadow.amb { transform: translateZ(calc(var(--book-w) * -.6)) scale(1.1091) var(--shm, translate(calc(var(--book-w) * .06), calc(var(--book-w) * .085)) scale(.99)); }
.book-shadow.contact { transform: translateZ(calc(var(--book-w) * -.6)) scale(1.1091) var(--shm, translate(calc(var(--book-w) * .014), calc(var(--book-w) * .02))); }
/* the near-ground side stays tight: the contact layer fades a little as the book leans (its edges lift off), the wide
   pool keeps the weight (--sa, from the tilt, as before) */
.book-shadow.contact { opacity: calc((.4 + .6 * var(--turn-sx, 1)) * (.55 + .45 * var(--sa, 1) * var(--sa, 1) * var(--sa, 1) * var(--sa, 1))); }

/* ---- 15:28 back/front spine joints: the hinge read as a dark gap. The spine runs 1px past each joint (tucked under
   the covers, so the panels never part); its overlays now stop at the joint, so that hidden 1px is plain spine art,
   not the overlays' near-black edge stop (it showed through the covers' 1px AA band as a dark tick above the top
   corner). The hinge shading on both sides of the joint is halved, so the cover and spine read as one wrap. ---- */
html[data-soften="on"] .spine::before, html[data-soften="on"] .spine::after { left: 1px; right: 1px; }
html[data-soften="on"] .spine::before {
  background:
    linear-gradient(90deg, rgba(0,0,0,.26) 0%, rgba(0,0,0,.16) 7%, rgba(0,0,0,.04) 20%, rgba(255,246,230,.16) 38%, rgba(255,246,230,.22) 46%,
                    rgba(255,246,230,.08) 56%, rgba(0,0,0,.05) 72%, rgba(0,0,0,.18) 91%, rgba(0,0,0,.28) 100%),
    linear-gradient(90deg, transparent 14%, rgba(0,0,0,.14) 15%, transparent 16.5%, transparent 83.5%, rgba(0,0,0,.14) 85%, transparent 86%);
}
.spine::after {
  background:
    linear-gradient(90deg, rgba(0,0,0,.14) 0, rgba(0,0,0,.2) 3%, rgba(0,0,0,.08) 10%, rgba(255,255,255,.07) 32%, rgba(255,255,255,.11) 46%, rgba(0,0,0,.02) 66%, rgba(0,0,0,.14) 90%, rgba(0,0,0,.2) 97%, rgba(0,0,0,.14) 100%),
    linear-gradient(180deg, rgba(255,255,255,.12), transparent 1.2%, transparent 98.8%, rgba(255,255,255,.08)),
    repeating-linear-gradient(0deg, transparent 0 37px, rgba(0,0,0,.05) 37px 38px, transparent 38px 61px); }
html[data-soften="on"] .pg.cv-out::before {
  background: linear-gradient(90deg, rgba(0,0,0,.2), rgba(0,0,0,.07) 22%, rgba(255,244,226,.12) 34%, rgba(0,0,0,.18) 44%, rgba(0,0,0,.05) 62%, transparent); }
html[data-soften="on"] .cover-art-back::before {
  background: linear-gradient(270deg, rgba(0,0,0,.2), rgba(0,0,0,.07) 22%, rgba(255,244,226,.12) 34%, rgba(0,0,0,.18) 44%, rgba(0,0,0,.05) 62%, transparent); }

/* ---- 15:28 fold height: the strips ran the full page box (0..pg-h) while the page paints 1px inside it (AA padding)
   and the top/bottom block faces sat 1.5px inside, so the fold stood ~1.5px proud of the page at both ends. The fold
   and both block faces (incl. their half-ellipse caps under the fold) now sit 1.25px inside the page box: flush with
   and just inside the page's painted top and bottom edges. Width (sq .2) unchanged. ---- */
html .book.is-fold > .fold-curve > i { top: 1.25px; height: calc(100% - 2.5px); }
html .book.is-fold > .edge-fore, html .book.is-fold > .edge-top, html .book.is-fold > .edge-bottom { --j: calc(1.25px * var(--pz, 0)); }

/* ---- 15:28 cover-to-page-block joints (closed, and fold-back before the block deepens). The faces were exactly as
   deep as the gap between the covers, but their paint starts 1px inside (soften AA padding), so their painted ends
   stopped ~2px short of each cover: tilted down/up/sideways a hairline of background showed along the bottom, top
   and fore-edge joints. The faces now sit 1.25px inside the cover outline (behind the covers' opaque paint) and their
   paint reaches .5px past each cover plane, so cover and block overlap at every tilt. ---- */
.edge-fore, .edge-top, .edge-bottom { --e: calc(var(--depth) + var(--sf-aa, 1px) * 2 + 1px); --j: 1.25px; }
.edge-fore { left: calc(var(--pg-w) - var(--e) / 2 - var(--j)); }
.edge-top { top: calc(var(--e) / -2 + var(--j)); }
.edge-bottom { top: calc(var(--pg-h) - var(--e) / 2 - var(--j)); }
html .book.is-fold > .edge-fore, html .book.is-fold > .edge-top, html .book.is-fold > .edge-bottom {
  --e: calc(var(--depth) + 1px + var(--sf-aa, 1px) * 2 * (1 - var(--pz, 0)) + 2px * var(--pz, 0)); --j: 1.25px; }
html .book.is-fold > .edge-fore { transform: translateZ(calc(1.25px * var(--pz, 0))) rotateY(90deg); }
html .book.is-fold > .edge-top { transform: translateZ(calc(1.25px * var(--pz, 0))) rotateX(90deg); }
html .book.is-fold > .edge-bottom { transform: translateZ(calc(1.25px * var(--pz, 0))) rotateX(-90deg); }
/* open fold-back: the page-block faces meet square at the fore-edge corners, so the resting top page's worn corner
   round (5-6px) left a tiny see-through notch between page and faces at hard up/down-right tilts. Its fore corners
   now round only as far as the faces' inset allows; the turning leaves keep their worn corners. */
html .book.is-fold.is-open .page-right, html[data-pagesoften="on"] .book.is-fold.is-open .page-right {
  border-radius: 0 1.5px 1.5px 0 !important; }

/* ---- 15:35 CONFIG.buttonGlow (?btnglow=0 off): a large, very soft warm light pooled behind the button row, a little
   stronger behind Audiobook, so the skin there reads lit rather than dim. Two layers: soft-light (lifts the mids, keeps
   the hue and the bruising's contrast) plus a faint screen lift for the darkest tones. Eased many-stop falloff, the skin
   grain sits above it (dithers), and the ellipses extend well past the buttons, so there is no edge, ring or shape.
   main.js places it on the live button centres (--gl-*). Desktop gets a subtler version. ---- */
.bg-btnglow, .bg-btnglow2 { display: none; position: fixed; inset: 0; pointer-events: none; z-index: 0; }
html[data-theme="skin"][data-btn-glow="on"] .bg-btnglow {
  --g: calc(var(--btn-glow, 1) * var(--gl-k, 1));
  display: block; mix-blend-mode: soft-light; opacity: min(1, var(--g));
  background:
    radial-gradient(ellipse var(--gl-arx, 190px) var(--gl-ary, 150px) at var(--gl-ax, 72%) var(--gl-ay, 92%),
      rgba(255,222,190,.55) 0%, rgba(255,222,190,.49) 12%, rgba(255,222,190,.39) 26%, rgba(255,222,190,.27) 40%,
      rgba(255,222,190,.16) 55%, rgba(255,222,190,.08) 70%, rgba(255,222,190,.025) 85%, rgba(255,222,190,0) 100%),
    radial-gradient(ellipse var(--gl-rx, 70vw) var(--gl-ry, 200px) at var(--gl-cx, 50%) var(--gl-cy, 92%),
      rgba(255,224,194,.7) 0%, rgba(255,224,194,.62) 12%, rgba(255,224,194,.5) 26%, rgba(255,224,194,.35) 40%,
      rgba(255,224,194,.21) 55%, rgba(255,224,194,.1) 70%, rgba(255,224,194,.03) 85%, rgba(255,224,194,0) 100%);
}
html[data-theme="skin"][data-btn-glow="on"] .bg-btnglow2 {
  --g: calc(var(--btn-glow, 1) * var(--gl-k, 1));
  display: block; mix-blend-mode: screen; opacity: min(1, var(--g));
  background:
    radial-gradient(ellipse var(--gl-arx, 190px) var(--gl-ary, 150px) at var(--gl-ax, 72%) var(--gl-ay, 92%),
      rgba(120,82,56,.20) 0%, rgba(120,82,56,.17) 15%, rgba(120,82,56,.12) 32%, rgba(120,82,56,.07) 50%,
      rgba(120,82,56,.03) 70%, rgba(120,82,56,.008) 88%, rgba(120,82,56,0) 100%),
    radial-gradient(ellipse var(--gl-rx, 70vw) var(--gl-ry, 200px) at var(--gl-cx, 50%) var(--gl-cy, 92%),
      rgba(120,82,56,.14) 0%, rgba(120,82,56,.12) 15%, rgba(120,82,56,.085) 32%, rgba(120,82,56,.05) 50%,
      rgba(120,82,56,.02) 70%, rgba(120,82,56,.005) 88%, rgba(120,82,56,0) 100%);
}
/* the blend needs a shared backdrop: keep the layer in the root stacking context with the other skin layers */
@media not ((max-width: 600px) and (orientation: portrait)) { html[data-theme="skin"] .bg-btnglow, html[data-theme="skin"] .bg-btnglow2 { --gl-k: .45; } }
/* opening/riffle/close (all open modes): at one moment of the riffle, with the book tilted right, a left-hand leaf meets the right
   page edge-to-edge at the gutter and the two AA edges left a 1-frame background hairline. The left-hand pages now
   paint 1px past their gutter edge (page colour), so the two always overlap. */
html .pg.l:not(.cv-in), html .page-left { box-shadow: 1px 0 0 0 var(--page); }
/* single-panel leaves (.sheet.is-flat) started their faces exactly on the hinge line, so in fold-back mid-open/mid-flick
   (tilted right/up/down) the leaf and the cover/right page met edge-to-edge at the gutter: a full-height background
   hairline. The hinge-side face now reaches 1px past the hinge (like the multi-strip sheets), so they overlap. */
html[data-soften="on"] .sheet > .st > .fc, html[data-soften="on"] .sheet.is-flat > .st > .fc { left: -1px; }

/* ======================================================================
   19 Oct 16:50 - ROUNDED BOX CORNERS + ANTI-ALIASING + STEADY FOLD SHADING
   1. Corners (refined below): the page-block faces ran out to the page box's square corners (top/bottom faces to the fore-edge, the
      fore-edge face to the top/bottom), so a square strip of page jutted past the covers' rounded corners. All three
      faces now stop --j inside the cover outline on every side (j = AA ring + .5px), which lies inside the covers'
      corner curve (radius --sf-r), and they meet each other exactly at the block's own corner. Their depth is exactly
      the covers' spacing (painted ends on the cover planes, tucked behind the covers' paint) - nothing protrudes past
      a cover plane, so no sub-pixel slivers (they aliased as a stepped light line along the tilted top edge).
   2. AA ring 1px -> 1.5px (CONFIG.bookSoftenStrength.aa): every face's texture now ends 1.5px inside its polygon, so
      the visible edge is a filtered texture edge even where the GPU samples the layer coarsely while it moves. */
.edge-fore, .edge-top, .edge-bottom { --e: calc(var(--depth) + var(--sf-aa, 1px) * 2); --j: calc(var(--sf-aa, 1px) + .5px); }
.edge-fore { top: var(--j); height: calc(var(--pg-h) - var(--j) * 2); }
.edge-top, .edge-bottom { width: calc(var(--pg-w) - var(--j)); }
html .book.is-fold > .edge-fore, html .book.is-fold > .edge-top, html .book.is-fold > .edge-bottom {
  --e: calc(var(--depth) + var(--sf-aa, 1px) * 2 * (1 - var(--pz, 0)) + 3px * var(--pz, 0));
  --j: calc((var(--sf-aa, 1px) + .5px) * (1 - var(--pz, 0)) + 1.25px * var(--pz, 0)); }
html .book.is-fold > .edge-fore { top: var(--j); height: calc(var(--pg-h) - var(--j) * 2); }
html .book.is-fold > .edge-top, html .book.is-fold > .edge-bottom { width: calc(var(--pg-w) - var(--j) + var(--depth) * .10 * var(--lipo, 0)); }
/* 3. Fold-back open: the page's full gutter shading (a dark 25%-wide ramp) stayed on the resting page until the
      settle class landed ~1s after the riffle, then the page swapped to a near-flat version: the shading popped off.
      One soft shading now applies to every right-hand page in fold-back, moving or resting, and the fold's front strip
      starts at the same tone, so the page rolls softly into the lit crown of the fold and nothing changes on settle. */
html[data-open-mode="foldback"][data-pagesoften="on"] .r::before,
html[data-open-mode="foldback"] .book.is-fold.fold-settled .page-right.r::before {
  background: linear-gradient(90deg, rgba(52,32,12,.13), rgba(52,32,12,.08) 3%, rgba(52,32,12,.035) 8%, rgba(255,248,230,.04) 13%, transparent 20%) !important; }
html .book.is-fold > .fold-curve > i:nth-child(1) { --s0: rgba(52,32,12,.13); --s1: rgba(255,249,236,.10); }
/* refinement: the long edges sit exactly at the covers' AA ring (j = ring), not deeper - a deeper block let the far
   cover's inner edge peek over the near cover as a sub-pixel light line along the top when tilted (the stepped line).
   The corners are cleared separately: each face stops --c short of the block corner (c = .42 x the cover corner radius,
   never less than j), which keeps the block's corner inside the covers' rounded corner on phone and desktop. */
.edge-fore, .edge-top, .edge-bottom { --j: calc(var(--sf-aa, 1px) + .1px); --c: max(var(--j), calc(var(--sf-r, 5px) * .42)); }
.edge-fore { top: var(--c); height: calc(var(--pg-h) - var(--c) * 2); }
.edge-top, .edge-bottom { width: calc(var(--pg-w) - var(--c)); }
html .book.is-fold > .edge-fore, html .book.is-fold > .edge-top, html .book.is-fold > .edge-bottom {
  --j: calc((var(--sf-aa, 1px) + .1px) * (1 - var(--pz, 0)) + 1.25px * var(--pz, 0));
  --c: calc(max(var(--sf-aa, 1px) + .1px, var(--sf-r, 5px) * .42) * (1 - var(--pz, 0)) + 1.25px * var(--pz, 0)); }
html .book.is-fold > .edge-fore { top: var(--c); height: calc(var(--pg-h) - var(--c) * 2); }
html .book.is-fold > .edge-top, html .book.is-fold > .edge-bottom { width: calc(var(--pg-w) - var(--c) + var(--depth) * .10 * var(--lipo, 0)); }
/* the inside of the front cover (.pg.cv-in) had no AA ring: it painted right to its box edge while every other cover
   face starts 1.5px in, so from behind/above its raw edge stood ~1.5px proud of the back cover as a thin light line
   along the top (the stepped line on Android). It now gets the same ring and the same rounded fore corners. */
html[data-soften="on"] .pg.cv-in {
  box-sizing: border-box; padding: var(--sf-aa, 1px) 0 var(--sf-aa, 1px) var(--sf-aa, 1px);
  background-clip: content-box !important; background-origin: content-box !important;
  border-radius: var(--sf-r) 0 0 var(--sf-r) / calc(var(--sf-r) * .9) 0 0 calc(var(--sf-r) * .9); }
html[data-soften="on"] .cv-in::after { inset: var(--sf-aa, 1px) 0 var(--sf-aa, 1px) var(--sf-aa, 1px); border-radius: inherit; }
/* the fore-edge face runs the block's full height (j..pg-h-j) and closes the block corner; only the top/bottom faces
   stop short (--c), since they are the ones seen running out past the cover's rounded corner */
.edge-fore, html .book.is-fold > .edge-fore { top: var(--j); height: calc(var(--pg-h) - var(--j) * 2); }
/* a hair more overlap with the covers'/spine's AA ring (j = ring + .35px): at ring + .1px the bottom face's spine end met
   the spine's painted edge almost exactly and left a 1-3px pinhole at the spine-side bottom corner at hard down tilts */
.edge-fore, .edge-top, .edge-bottom { --j: calc(var(--sf-aa, 1px) + .35px); }
html .book.is-fold > .edge-fore, html .book.is-fold > .edge-top, html .book.is-fold > .edge-bottom {
  --j: calc((var(--sf-aa, 1px) + .35px) * (1 - var(--pz, 0)) + 1.25px * var(--pz, 0));
  --c: calc(max(var(--sf-aa, 1px) + .35px, var(--sf-r, 5px) * .42) * (1 - var(--pz, 0)) + 1.25px * var(--pz, 0)); }
/* top/bottom faces tuck .5px past the hinge line under the spine, so their hinge end is never an exposed edge */
.edge-top, .edge-bottom { left: -.5px; width: calc(var(--pg-w) - var(--c) + .5px); }

/* ---------- 18:54 vinyl PREVIEW label / live waveform (rides the vinyl slot; bleeds in via #vprev-bleed) ---------- */
.vprev {
  position: absolute; left: 50%; top: calc(100% + clamp(10px, 2.2vh, 22px)); transform: translateX(-50%);
  width: clamp(84px, 22vw, 112px); height: 30px; display: grid; place-items: center; pointer-events: none;
  color: var(--ink-ui-soft, var(--muted)); filter: url(#vprev-bleed); mix-blend-mode: multiply;
}
.vprev[hidden] { display: none; }
.vp-word {
  grid-area: 1 / 1; font-family: "Slad Woodcut", serif; font-feature-settings: "calt" 1; font-size: clamp(13px, 1.5vw, 16px);
  letter-spacing: .11em; text-transform: uppercase; line-height: 1; white-space: nowrap;
}
.vp-wave { grid-area: 1 / 1; width: 100%; height: 26px; display: none; }
.vprev.is-wave .vp-word { display: none; }
.vprev.is-wave .vp-wave { display: block; }
/* 19:04 PREVIEW: ~1.4-1.5x larger (a touch under the main button text) and full button-strength ink; waveform footprint unchanged */
.vprev { height: 34px; mix-blend-mode: multiply; }
.vp-word { font-size: clamp(18.5px, .88rem + .6vw, 22.5px); justify-self: center; }
html[data-theme="skin"] .vprev { color: var(--ink-ui); }
html[data-theme="skin"] .vp-word { opacity: .95; text-shadow: 0 0 1px rgba(15,30,50,.85), 0 0 5px rgba(25,50,75,.4), 0 0 13px rgba(30,60,85,.22); }
@media (pointer: coarse), (max-width: 700px) {
  html[data-theme="skin"] .vprev { color: #030508; }
  html[data-theme="skin"] .vp-word { opacity: 1; -webkit-text-stroke: .45px currentColor; text-shadow: 0 0 .6px rgba(3,6,10,.95), 0 0 1.6px rgba(6,12,20,.5); }
}
/* 21:24 the label's initial state IS the hidden pre-reveal state; main.js raises it only when the record has landed */
.vprev { opacity: 0; }
/* 21:29 load gate (main.js): book + vinyl and their shadows hidden until the textures decode, then one shared fade */
html.obj-wait .scene, html.obj-wait .vscene { opacity: 0; animation: obj-failsafe 0s 8s forwards;   /* only if main.js never runs */ }
html.obj-in .scene, html.obj-in .vscene { transition: opacity .45s ease; }
html[data-motion="strict"].obj-in .scene, html[data-motion="strict"].obj-in .vscene { transition-duration: .3s; }
@keyframes obj-failsafe { to { opacity: 1; } }
/* 21:33 feathered silhouette (CONFIG.bookSoftenStrength.feather, ?feather=px): instead of a hard step at the inside of the
   transparent AA ring, each outer face fades from 0 at the ring to full over --sf-fe px. A per-face mask (cheap: no filter,
   the faces are flat leaves so preserve-3d is untouched); the art itself is not blurred, only its last ~1px rolls off. */
html[data-soften="on"] {
  --sf-fmask:
    linear-gradient(90deg, transparent var(--sf-aa, 1px), #000 calc(var(--sf-aa, 1px) + var(--sf-fe, 0px)), #000 calc(100% - var(--sf-aa, 1px) - var(--sf-fe, 0px)), transparent calc(100% - var(--sf-aa, 1px))),
    linear-gradient(180deg, transparent var(--sf-aa, 1px), #000 calc(var(--sf-aa, 1px) + var(--sf-fe, 0px)), #000 calc(100% - var(--sf-aa, 1px) - var(--sf-fe, 0px)), transparent calc(100% - var(--sf-aa, 1px)));
}
html[data-soften="on"][data-feather="on"] .pg.cv-out,
html[data-soften="on"][data-feather="on"] .cover-art-back,
html[data-soften="on"][data-feather="on"] .spine,
html[data-soften="on"][data-feather="on"] .book:not(.is-fold) > .block-edge {
  -webkit-mask: var(--sf-fmask); -webkit-mask-composite: source-in; mask: var(--sf-fmask); mask-composite: intersect;
}
/* 21:50 feather only where it is the outer silhouette: the front/back cover faces, never on their hinge side (spine joint)
   and not the block-edges / spine (feathering both faces of a joint opened a see-through seam in the magenta scan) */
html[data-soften="on"] {
  --sf-fh: linear-gradient(180deg, transparent var(--sf-aa, 1px), #000 calc(var(--sf-aa, 1px) + var(--sf-fe, 0px)), #000 calc(100% - var(--sf-aa, 1px) - var(--sf-fe, 0px)), transparent calc(100% - var(--sf-aa, 1px)));
  --sf-fl: linear-gradient(90deg, #000 calc(100% - var(--sf-aa, 1px) - var(--sf-fe, 0px)), transparent calc(100% - var(--sf-aa, 1px)));   /* fore edge on the right */
  --sf-fr: linear-gradient(270deg, #000 calc(100% - var(--sf-aa, 1px) - var(--sf-fe, 0px)), transparent calc(100% - var(--sf-aa, 1px)));  /* fore edge on the left */
}
html[data-soften="on"][data-feather="on"] .spine,
html[data-soften="on"][data-feather="on"] .book:not(.is-fold) > .block-edge { -webkit-mask: none; mask: none; }
html[data-soften="on"][data-feather="on"] .pg.cv-out { -webkit-mask: var(--sf-fh); mask: var(--sf-fh); }   /* strips: top/bottom only (no seams between strips) */
html[data-soften="on"][data-feather="on"] .st.flat .pg.cv-out { -webkit-mask: var(--sf-fh), var(--sf-fl); mask: var(--sf-fh), var(--sf-fl); }
html[data-soften="on"][data-feather="on"] .cover-art-back { -webkit-mask: var(--sf-fh), var(--sf-fr); mask: var(--sf-fh), var(--sf-fr); }
html[data-soften="on"][data-feather="on"] .st.flat .pg.cv-out,
html[data-soften="on"][data-feather="on"] .cover-art-back { -webkit-mask-composite: source-in; mask-composite: intersect; }
/* 22:40 page-edge tone, closed vs open. Both states use the SAME faces and the same texture/shading (one rule set);
   closed, the block sits beside the near-black cover and catches the rest angle's light, so it reads paler than the
   open book's edges (which sit among the stepped page stack and the page shade). Closed-only warm shade over the
   edge texture (CONFIG.pageEdgeClosedDim, ?edgedim=), faded out as the book opens so there is no pop. */
.book > .block-edge::after { transition: box-shadow .5s ease; }
.book:not(.is-open) > .edge-fore::after, .book:not(.is-open) > .edge-top::after {
  box-shadow: inset 0 0 0 999px rgba(66,42,18, calc(var(--edge-dim, .14) * .85)); }
.book:not(.is-open) > .edge-fore::after { box-shadow: inset 0 0 0 999px rgba(66,42,18, var(--edge-dim, .14)); }
.book:not(.is-open) > .edge-bottom::after { box-shadow: inset 0 0 0 999px rgba(40,24,10, calc(.22 + var(--edge-dim, .14) * .5)); }
/* 23:06 page-block corners: the block faces' own rounding (soften step 5: depth*.25 / r*.8) cut a wedge out of every
   face end, and where the top/bottom face meets the fore-edge the two wedges left a see-through notch (skin / back cover
   showing through at the top-right corner). The faces meet square now (the round corner reads from the covers);
   the --c inset that keeps the block inside the covers' rounded corner is bridged by a small diagonal face. */
html[data-soften="on"] .book > .block-edge { border-radius: 0 !important; }
html[data-soften="on"] .book > .block-edge::after { border-radius: 0 !important; }
.book > .edge-chamf { position: absolute; padding: 0 !important; -webkit-mask: none !important; mask: none !important;
  --j: calc(var(--sf-aa, 1px) + .35px); --c: max(var(--j), calc(var(--sf-r, 5px) * .42));
  --e: calc(var(--depth) + var(--sf-aa, 1px) * 2); --L: calc((var(--c) - var(--j)) * 1.4142 + 1.6px);
  width: var(--L); height: var(--e); left: calc(var(--pg-w) - (var(--c) + var(--j)) / 2 - var(--L) / 2); }
.book > .edge-chamf.t { top: calc((var(--j) + var(--c)) / 2 - var(--e) / 2); transform: rotateZ(45deg) rotateX(90deg); }
.book > .edge-chamf.b { top: calc(var(--pg-h) - (var(--j) + var(--c)) / 2 - var(--e) / 2); transform: rotateZ(-45deg) rotateX(-90deg); }
.book > .edge-chamf.b::after { box-shadow: inset 0 0 0 999px rgba(40,24,10,.22); }
html .book.is-fold > .edge-chamf {
  --j: calc((var(--sf-aa, 1px) + .35px) * (1 - var(--pz, 0)) + 1.25px * var(--pz, 0));
  --c: calc(max(var(--sf-aa, 1px) + .35px, var(--sf-r, 5px) * .42) * (1 - var(--pz, 0)) + 1.25px * var(--pz, 0)); }
html .book > .block-edge.edge-chamf { padding: 0 !important; }
.book:not(.is-open) > .edge-chamf.t::after { box-shadow: inset 0 0 0 999px rgba(66,42,18, calc(var(--edge-dim, .14) * .85)); }
/* the fore-edge face's own AA ring at its top/bottom ends left a ring-wide see-through slot under the corner faces;
   those ends sit inside the corner (never silhouette), so they paint to the box edge */
html .book > .block-edge.edge-fore { padding-top: 0 !important; padding-bottom: 0 !important; }
html .book > .block-edge.edge-fore::after { top: 0 !important; bottom: 0 !important; }
/* fold-back open uses its own block geometry (faces pushed to the page, --c -> 1.25px): no corner faces there */
html .book.is-fold.is-open > .edge-chamf, html .book.is-fold.fold-closing > .edge-chamf, .book.fold-settled > .edge-chamf { visibility: hidden !important; }
/* 23:19 (tried, reverted): feathering the spine's top/bottom opened see-through pinholes where the bottom/top page faces
   tuck under the spine (magenta scan, closed down-tilts) - the spine ends stay on the hard 1.5px AA ring */
/* ---------- ?engine=webgl (phase 2): webgl-book.js mirrors the CSS book and draws the cover outside, back cover, spine,
   page-block faces and fold curve itself; the CSS copies of those faces are clipped away (geometry, visibility and
   opacity stay readable for the mirror). Pages, cover inside and leaves stay CSS. The CSS book is the default/fallback. ---------- */
.gl-book { display: none; }
html[data-engine="webgl"] .gl-book { display: block; visibility: hidden; }
html[data-engine="webgl"].gl-live .gl-book { visibility: visible; }
html[data-engine="webgl"].gl-live .cover-front .fc.f, html[data-engine="webgl"].gl-live .cover-art-back,
html[data-engine="webgl"].gl-live .book > .spine, html[data-engine="webgl"].gl-live .book > .block-edge,
html[data-engine="webgl"].gl-live .fold-curve > i { clip-path: inset(50%) !important; }

/* ---------- CONTACT drop-down (tap the wordmark; CONFIG.contactUrl) ----------
   Same face and ink as the wordmark; main.js bleeds it in/out through #contact-bleed (ends on the #tattoo look). */
.site-head { --cl-gap: .32em; }
.contact-link { position: absolute; left: var(--title-x); display: block; width: max-content;
  font-family: "Slad Woodcut", serif; font-feature-settings: "calt" 1, "liga" 1; line-height: 1; letter-spacing: .04em;
  font-size: calc(clamp(1.5rem, 1rem + 1.6vw, 3.6rem) * .5); color: var(--fg); text-decoration: none;
  margin-top: var(--cl-gap); padding: .25em 0; visibility: hidden; pointer-events: none; filter: url(#contact-bleed); }
@media (max-width: 600px) and (orientation: portrait) { .contact-link { font-size: .92rem; left: var(--title-x); } }
.contact-link.is-shown { visibility: visible; pointer-events: auto; }
.contact-link:focus-visible { outline: 1px solid var(--fg); outline-offset: 4px; }
html[data-theme="skin"] .contact-link { color: #121a24; opacity: .9;
  text-shadow: 0 0 1px rgba(15,30,50,.9), 0 0 5px rgba(25,50,75,.45), 0 0 14px rgba(30,60,85,.25); }
html[data-motion="strict"] .contact-link { filter: url(#tattoo); transition: opacity .3s ease; }
/* 14:07 desktop PREVIEW + waveform: exactly the button label's ink (.ink-k: --ink-ui, .95, multiply, the #tattoo end state
   via #vprev-bleed: displacement 2.2 / blur .7). No stroke, no glow text-shadow: those hid the ragged bled edge on desktop.
   Phones keep their own (stroked, near-black) ink from the coarse-pointer block above. */
@media (hover: hover) and (pointer: fine) and (min-width: 701px) {
  html[data-theme="skin"] .vprev { color: var(--vprev-ink, #070b11); opacity: 1; mix-blend-mode: multiply; }   /* the label is one ink layer; the button text reads darker (two layers), so a touch deeper */
  html[data-theme="skin"] .vp-word { opacity: 1; -webkit-text-stroke: 0; text-shadow: none; }
}
/* 12:36 WebGL fold-back: the open page's spine-side corners rounded like its fore-edge ones (the GL fold strip ends match) */
html[data-engine="webgl"][data-open-mode="foldback"] .book.is-open .page-right { border-radius: 0 var(--open-fr, var(--sf-r)) var(--open-fr, var(--sf-r)) 0; }   /* 14:16 fore-edge corners ~65% of the cover radius (webgl-book.js sets --open-fr; the GL block corners use the same) */
/* 14:25 resting PREVIEW / waveform: exactly the button label's ink path (.ink-k: filter url(#tattoo) on the text element
   itself, multiply), so it paints in Gecko (Firefox / Zen) too; the wrapper's animated bleed filter is off once settled */
.vprev.is-inked { filter: none !important; }
html[data-theme="skin"] .vprev.is-inked .vp-word, html[data-theme="skin"] .vprev.is-inked .vp-wave { filter: url(#tattoo); mix-blend-mode: multiply; }
/* 17:57 the resting open page (fold-settled) kept the old 1.5px !important corner from the square-faced block era, so the
   ~65% cover-radius rounding only showed mid-animation. The GL block corners now round with it (--open-fr), so rest uses it too. */
html[data-engine="webgl"][data-open-mode="foldback"] .book.is-fold.is-open .page-right,
html[data-engine="webgl"][data-open-mode="foldback"][data-pagesoften="on"] .book.is-fold.is-open .page-right {
  border-radius: var(--open-lr, 2px) var(--open-fr, var(--sf-r)) var(--open-fr, var(--sf-r)) var(--open-lr, 2px) !important; }   /* 19:03 a small fillet so the page's top/bottom edges ease down into the curl's (no step) */
/* 18:30 desktop PREVIEW + waveform ink = the button label's ink exactly (.ink-k: --ink-ui, .95, multiply, #tattoo AND its
   bled glow). The glow was dropped at 14:07, which is what read as "no ink bleed" next to the buttons. No hover/pointer
   media query gate any more (Zen / Firefox setups that report odd pointer/hover values got the bare style): desktop is the
   default and phones re-assert their own block below. The canvas waveform gets the same glow as drop-shadows. */
html[data-theme="skin"] .vprev { color: var(--ink-ui); }
html[data-theme="skin"] .vp-word { opacity: .95; -webkit-text-stroke: 0;
  text-shadow: 0 0 1px rgba(15,30,50,.85), 0 0 5px rgba(25,50,75,.4), 0 0 13px rgba(30,60,85,.22); }
html[data-theme="skin"] .vprev.is-inked .vp-word { filter: url(#tattoo); mix-blend-mode: multiply; }
html[data-theme="skin"] .vprev .vp-wave { opacity: .95; filter: drop-shadow(0 0 1px rgba(15,30,50,.85)) drop-shadow(0 0 5px rgba(25,50,75,.4)) drop-shadow(0 0 13px rgba(30,60,85,.22)); }
html[data-theme="skin"] .vprev.is-inked .vp-wave { filter: url(#tattoo) drop-shadow(0 0 1px rgba(15,30,50,.85)) drop-shadow(0 0 5px rgba(25,50,75,.4)) drop-shadow(0 0 13px rgba(30,60,85,.22)); mix-blend-mode: multiply; }
@media (pointer: coarse), (max-width: 700px) {
  html[data-theme="skin"] .vprev { color: #030508; }
  html[data-theme="skin"] .vp-word { opacity: 1; -webkit-text-stroke: .45px currentColor; text-shadow: 0 0 .6px rgba(3,6,10,.95), 0 0 1.6px rgba(6,12,20,.5); }
  html[data-theme="skin"] .vprev .vp-wave { opacity: 1; filter: none; }
  html[data-theme="skin"] .vprev.is-inked .vp-wave { filter: url(#tattoo); }
}
/* 19:05 PREVIEW ink = button ink, take 2: #tattoo's filter region is the element box +5% / +20%, so on the small .vp-word box
   the displaced glow (13px) was clipped to a hard rectangle-ish edge and the ragged bleed read as plain text. The button
   labels carry .72em/1.25em padding, which is what gives their bleed room. Same room here (padding, cancelled by margin). */
html[data-theme="skin"] .vp-word { padding: .72em 1.25em .62em; margin: -.72em -1.25em -.62em; }
html[data-theme="skin"] .vprev { overflow: visible; }
/* 19:05 the button label reads as two ink layers (black .ink-k over the multiplied skin), so a single PREVIEW layer in --ink-ui
   came out bluer and lighter than BUY THE BOOK / the wordmark: one step deeper, full opacity (desktop; phones keep theirs) */
html[data-theme="skin"] .vprev { color: #080c12; }
html[data-theme="skin"] .vp-word, html[data-theme="skin"] .vprev .vp-wave { opacity: 1; }
@media (pointer: coarse), (max-width: 700px) { html[data-theme="skin"] .vprev { color: #030508; } }
/* 20:55 opening nub: the riffle leaves ride a hair nearer the camera than the page under them, so in perspective
   their top/bottom edges projected ~1px above/below the page at the gutter (the pale nub Charlie saw while opening).
   Scale the leaf stack 1.4% about the page's mid-height so they never reach past the page/cover edges. */
/* 21:40 replaced by the per-pose perspective clip in main.js (makeSheet pose) */
/* 22:00 Firefox painted the inset(50%)-clipped CSS faces (GL draws them) as a dark 1px speck at the page's top-left
   while opening; also zero their paint (filter, not opacity: the GL mirror reads opacity) */
html[data-engine="webgl"].gl-live .cover-front .fc.f, html[data-engine="webgl"].gl-live .cover-art-back,
html[data-engine="webgl"].gl-live .book > .spine, html[data-engine="webgl"].gl-live .book > .block-edge,
html[data-engine="webgl"].gl-live .fold-curve > i { filter: opacity(0) !important; }

/* 01:50 CONTACT: the active-button underline (.sel, same mask/ink/transition, under the link's own ink filter) on hover / focus;
   touch: while the drop-down is open */
.contact-link .sel { bottom: -.5em; }
@media (hover: hover) and (pointer: fine) { .contact-link:hover .sel, .contact-link:focus-visible .sel { opacity: 1; transform: none; } }
@media (pointer: coarse) { .contact-link.is-open .sel { opacity: 1; transform: none; } }
/* 01:50 desktop PREVIEW + waveform = the button label's ink, literally: .ink-k's colour, .95, multiply, #tattoo and the
   same glow text-shadow, applied to the label wrapper (settled); the bleed-in (#vprev-bleed) carries the same colour/glow */
@media (hover: hover) and (pointer: fine) and (min-width: 701px) {
  html[data-theme="skin"] .vprev { color: var(--ink-ui) !important; }
  html[data-theme="skin"] .vp-word { opacity: .95 !important; text-shadow: 0 0 1px rgba(15,30,50,.85), 0 0 5px rgba(25,50,75,.4), 0 0 13px rgba(30,60,85,.22) !important; }
  html[data-theme="skin"] .vprev.is-inked { filter: url(#tattoo) !important; }
  html[data-theme="skin"] .vprev.is-inked .vp-word, html[data-theme="skin"] .vprev.is-inked .vp-wave { filter: none !important; }
  html[data-theme="skin"] .vprev .vp-wave { opacity: .95; }
}
/* 11:30 a leaf face drawn by the GL renderer (webgl-book.js ownLeaf): its CSS face is hidden like the other GL-owned faces */
html[data-engine="webgl"].gl-live #leaves .fc.gl-own { clip-path: inset(50%) !important; filter: opacity(0) !important; }
html[data-engine="webgl"].gl-live.gl-pages #leaves { opacity: 0 !important; }
/* 12:45 WebGL book: softer cast shadow onto the right page - an eased penumbra (no hard leading band), plus a slight blur on the tail */
html[data-engine="webgl"]:not([data-glx-oldcast]) .cast-r { background: linear-gradient(90deg, rgba(28,17,6,.5), rgba(28,17,6,.4) 10%, rgba(28,17,6,.27) 28%, rgba(28,17,6,.15) 50%, rgba(28,17,6,.07) 70%, rgba(28,17,6,.02) 88%, rgba(28,17,6,0)); filter: blur(1.5px); }
/* 13:05 PREVIEW + waveform = the buttons' ink recipe exactly (.ink-k): same ink, multiply, the halo goes through #tattoo with the
   glyphs (so it reads as bleed into the skin, not a glow), no blue tint, no text-stroke. Same font size as the button labels. */
html[data-theme="skin"] .vprev .vp-word, html[data-theme="skin"] .vprev.is-inked .vp-word {
  color: var(--ink-ui); opacity: .95; -webkit-text-stroke: 0; mix-blend-mode: multiply; filter: url(#tattoo);
  text-shadow: 0 0 1px rgba(15,30,50,.85), 0 0 5px rgba(25,50,75,.4), 0 0 13px rgba(30,60,85,.22); }
html[data-theme="skin"] .vprev .vp-wave, html[data-theme="skin"] .vprev.is-inked .vp-wave {
  opacity: .95; mix-blend-mode: multiply; filter: drop-shadow(0 0 1px rgba(15,30,50,.85)) drop-shadow(0 0 5px rgba(25,50,75,.4)) drop-shadow(0 0 13px rgba(30,60,85,.22)) url(#tattoo); }
html[data-theme="skin"] .vprev { color: var(--ink-ui); }
/* 13:15 open page spine-side corners square (flush with the fold-back sheet's square ends): the 2px fillet against the square fold read as a notch/step at the corner. ?glx=openlr keeps the fillet */
html[data-engine="webgl"][data-open-mode="foldback"]:not(.glx-openlr) { --open-lr: 0px; }
/* 13:20 turning leaves carry the resting open page's exact corners (square spine side, --open-fr fore edge), so the handoff from page to leaf shows no corner change */
html[data-engine="webgl"][data-open-mode="foldback"] .book.is-fold.is-open #leaves .pg { border-radius: 0 var(--open-fr, var(--sf-r)) var(--open-fr, var(--sf-r)) 0 !important; }
/* 13:30 PREVIEW + waveform (all pointers): black button ink, no blue glow/halo, rough bled edges (#tattoo-sm) on the settled label */
html[data-theme="skin"] .vprev, html[data-theme="skin"] .vprev.is-inked { color: #070b10 !important; }
html[data-theme="skin"] .vprev .vp-word, html[data-theme="skin"] .vprev.is-inked .vp-word { text-shadow: none !important; -webkit-text-stroke: .35px currentColor !important; opacity: 1 !important; }
html[data-theme="skin"] .vprev.is-inked { filter: url(#tattoo-sm) !important; }
html[data-theme="skin"] .vprev.is-inked .vp-word, html[data-theme="skin"] .vprev.is-inked .vp-wave, html[data-theme="skin"] .vprev .vp-wave { filter: none !important; opacity: 1 !important; }
.vlabel.has-image { box-shadow: none; }   /* 13:40 the label PNG carries its own worn edge */
/* 13:50 Firefox (phones): the frame mask had no size/repeat, so Gecko tiled the viewBox-only SVG at its default 300x150 and the box repeated through "coming soon" */
.ink-btn::before, .ink-btn .frm { -webkit-mask-size: 100% 100% !important; mask-size: 100% 100% !important; -webkit-mask-repeat: no-repeat !important; mask-repeat: no-repeat !important; -webkit-mask-position: 0 0 !important; mask-position: 0 0 !important; }
/* 14:45 PREVIEW / waveform ink density = the buttons': full-strength near-black (no .95, multiply kept), a hair heavier stroke; #tattoo-sm now dilates + bleeds instead of eroding */
html[data-theme="skin"] .vprev, html[data-theme="skin"] .vprev.is-inked { color: #05080c !important; opacity: 1 !important; }
html[data-theme="skin"] .vprev .vp-word, html[data-theme="skin"] .vprev.is-inked .vp-word { -webkit-text-stroke: .3px currentColor !important; opacity: 1 !important; }
/* 17:30 PREVIEW bleed-in = the settled label exactly: while it soaks in, the word carried its own #tattoo under the wrapper's
   #vprev-bleed (double-filtered: softer, lighter), then snapped to the single #tattoo-sm pass on settle ~1.4s in. One pass only. */
html[data-theme="skin"] .vprev .vp-word { filter: none !important; }
/* 17:55 webgl fold-back: the resting open book = the opening's last frame. fold-settled hid the folded-round front cover, whose
   page-side rim frames the open page under tilt during the whole animation, so at settle the page's silhouette jumped
   ~1-1.5 css px (smaller or larger vs the fold depending on the tilt: desktop vs phone). It stays exactly as it was. */
html[data-engine="webgl"][data-open-mode="foldback"] .book.is-fold.is-open.fold-settled > .cover-front { visibility: visible; }

/* 17:90 PREVIEW + waveform = the buttons' black ink (.ink-k: --ink-ui, .95, the same glow, settled through #tattoo = btn-k's
   resting displacement 2.2 / blur .7). Kept on the v1760 path that paints in Gecko (Zen) and Chromium: the bleed-in and the
   settled filter both sit on the wrapper (v1775 put the filter on the word itself and Gecko painted nothing). #vprev-bleed
   now ends exactly on #tattoo, so the hand-over at the end of the soak changes nothing. */
html[data-theme="skin"] .vprev, html[data-theme="skin"] .vprev.is-inked { color: #070b10 !important; }   /* the selected button label's ink */
html[data-theme="skin"] .vprev.is-inked { filter: url(#tattoo) !important; }
html[data-theme="skin"] .vprev .vp-word, html[data-theme="skin"] .vprev.is-inked .vp-word { -webkit-text-stroke: 0 !important; opacity: .95 !important;
  text-shadow: 0 0 1px rgba(15,30,50,.85), 0 0 5px rgba(25,50,75,.4), 0 0 13px rgba(30,60,85,.22) !important; }
html[data-theme="skin"] .vprev .vp-wave, html[data-theme="skin"] .vprev.is-inked .vp-wave { opacity: .95 !important;
  filter: drop-shadow(0 0 1px rgba(15,30,50,.85)) drop-shadow(0 0 5px rgba(25,50,75,.4)) drop-shadow(0 0 13px rgba(30,60,85,.22)) !important; }
/* 17:75 CONTACT underline: its top sits .2em under the text baseline, the same .2em gap the active-button underline keeps
   under its frame (measured: btn .200em; contact was .529em under the baseline = too low). Pure em, so it holds at every size. */
.contact-link .sel { bottom: -.171em; }

/* 18:05 PREVIEW + waveform ink = the near-black bleed Charlie sees on the buttons (Zen): #05080c at full strength, a neutral
   (not blue) halo, a hair of stroke for the same weight; still settled through #tattoo on the wrapper. #vprev beats the older
   --ink-ui / blue-glow rules (1472, 1501). */
html[data-theme="skin"] body #vprev, html[data-theme="skin"] body #vprev.is-inked { color: #05080c !important; }
html[data-theme="skin"] body #vprev .vp-word { color: #05080c !important; opacity: 1 !important; -webkit-text-stroke: .3px currentColor !important;
  text-shadow: 0 0 1px rgba(5,8,12,.9), 0 0 4px rgba(5,8,12,.3) !important; }
html[data-theme="skin"] body #vprev .vp-wave { opacity: 1 !important; filter: drop-shadow(0 0 1px rgba(5,8,12,.9)) drop-shadow(0 0 4px rgba(5,8,12,.3)) !important; }
