/* ============================================================================
   CINEMATIC LAYER — v3 (blockout / animatic stage)
   One fixed canvas behind the whole page (STORYBOARD.md). Everything here is
   scoped to `.gl-ready`, which scene.js sets only once the scene has actually
   rendered — with no WebGL, reduced motion or a failure, none of this applies
   and the page is the certified v2 site exactly.
   ========================================================================= */
#gl {
  position: fixed; inset: 0; z-index: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  opacity: 0; transition: opacity 600ms var(--e-out, ease-out);
}
.gl-ready #gl { opacity: 1; }
.gl-ready #gl.is-resting { opacity: 0; }

main, .footer { position: relative; z-index: 1; }

/* Beats 1–3: the sections the book is seen through. */
.gl-ready .cover,
.gl-ready .pages.ruled:first-of-type,
.gl-ready .deck-wrap { background: transparent; }
.gl-ready .cover__fallback,
.gl-ready .cover__canvas { display: none; }
.gl-ready .cover__veil { display: none; }   /* ends at the cover's edge — a seam over a continuous scene */

/* The deck's own pages stay opaque — the deck is untouched (board beat 4). */
.gl-ready .deck-stage { background: var(--c-buckram); }

/* Beats 2–3: the first page's words are PRINTED on the leaf. The section
   keeps its height as the runway (the cover opens, holds while the book
   closes over the words, then the page scrolls on to the styles — owner,
   26 Sep), but the words themselves are fixed to the screen and drawn by
   book.js into the leaf's perspective each frame, in the same frame as the
   book, and masked under the cover (owner, 30 Sep). Out of the book's range
   they are transparent and take no pointer. */
.gl-ready .opening { --close-run: 100svh; padding: 0; height: calc(100svh + var(--close-run)); }
.gl-ready .opening__pin {
  position: fixed; top: 0; left: 0; width: 100%; height: 100svh;
  display: flex; align-items: center;
  pointer-events: none;
}
.gl-ready .opening__pin > .wrap {
  flex: 1 1 auto; min-width: 0; width: auto; max-width: none;
  /* the page's own margins, inside the leaf's edges as book.js finds them */
  margin: 0 var(--leaf-r, 0px) 0 var(--leaf-l, 0px);
  padding-inline: clamp(24px, 5vw, 88px);
  will-change: transform, opacity; opacity: 0; transform-origin: 0 0;
}
.gl-ready .opening__pin.is-printed > .wrap { pointer-events: auto; }

/* Sections that took their paper from <body> now sit in front of a fixed
   canvas, so they carry the ground themselves. */
.gl-ready #method, .gl-ready #prices, .gl-ready #faq, .gl-ready .trades { background: var(--ground); }

/* Phones and tablets (owner's iPhone, 27 Sep): the styles are paged one
   swipe at a time by book.js, so each is at least a full screen and none
   lets the next peek in; and nothing may push the page 2px sideways. */
.gl-ready .deck-wrap { overflow-x: clip; }
@media (pointer: coarse) {
  .gl-ready .style-page { min-height: 100svh; }
}

/* The title's rule and line sit below the book, not across it (owner, 27 Sep).
   `top` rather than a transform: the reveal animations own the transform. */
.gl-soon .cover__rule, .gl-soon .cover__sub,
.gl-ready .cover__rule, .gl-ready .cover__sub { position: relative; top: 33svh; }

/* The Reel's caption hangs 30px under its film strip; on a phone the next
   line sat underneath it (owner's iPhone, 27 Sep). */
@media (pointer: coarse), (max-width: 900px) {
  .gl-ready .sp--reel .sp__strip { margin-bottom: 44px; }
}

/* The figure captions ("scroll ↓ scene 03 / 05", "one page becoming the
   next") hung under their figures, which on a phone put them mid-page among
   the text (owner, 27 Sep). They now sit at the foot of their style: bottom
   right on a desk, clear of the deck's foot bar; bottom centre on a phone,
   where that bar is not shown. */
.sp__pagecap {
  position: absolute; z-index: 3; right: var(--gutter); bottom: calc(var(--s-5) + env(safe-area-inset-bottom, 0px));
  white-space: nowrap; pointer-events: none;
  font-family: var(--f-mono); font-size: var(--t-micro);
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-3);
}
/* the Reel's --text-3 is 4.3:1 on its black (axe, 27 Sep): one step lighter, 4.8:1 */
.t-reel .sp__pagecap { color: #837f78; }
@media (pointer: coarse), (max-width: 760px) {
  .sp__pagecap { right: auto; left: 50%; transform: translateX(-50%); bottom: calc(14px + env(safe-area-inset-bottom, 0px)); }
  /* room kept for it, so it can never sit on the style's last line (owner, 27 Sep) */
  .gl-ready .style-page:has(.sp__pagecap) { padding-bottom: calc(clamp(72px, 10vh, 112px) + 28px); }
}

/* The Estate fits one iPhone screen (owner, 27 Sep): ~47px of its white space
   taken out on phones, measured at 390×664 (an iPhone with Safari's bars). */
@media (pointer: coarse), (max-width: 760px) {
  .gl-ready .sp--estate { padding-top: 12px; padding-bottom: 12px; }
  .gl-ready .sp--estate .sp__for { margin-bottom: 16px; }
  .gl-ready .sp--estate .sp__foot { margin-top: 8px; }
}

/* Phones: the styles stop at every head and every foot (owner, 27 Sep).
   Safari's momentum cannot be stopped by script, but it obeys snap points:
   a snap area taller than the screen leaves free scrolling in its middle, and
   `scroll-snap-stop: always` means a fling cannot fly past a head or a foot.
   The foot markers are added by book.js, after each style. */
@media (pointer: coarse) {
  /* mandatory, but only while the reader is IN the styles: book.js sets
     .snap-deck there and takes it off for the book and for the page below */
  html.gl-ready.snap-deck { scroll-snap-type: y mandatory; }
  .gl-ready .deck-intro, .gl-ready .style-page { scroll-snap-align: start; scroll-snap-stop: always; }
  .gl-ready .snap-foot { height: 1px; margin-top: -1px; scroll-snap-align: end; scroll-snap-stop: always; }
  /* Chrome for Android flies past the foot markers (book.js → snap-a): a tall
     style snaps at its own head and foot instead, so a fling lands on a head */
  .gl-ready.snap-a .snap-foot { scroll-snap-align: none; }
  .gl-ready.snap-a .style-page.is-tall { scroll-snap-align: start end; }
}

.snap-foot { display: block; height: 0; }

/* The name is on the book's cover now; the heading stays in the page for
   search engines and screen readers, but is not drawn over the book twice —
   nor drawn at all while the book loads (`.gl-soon`, set in <head>): the
   wordmark flashing up first read as the old home screen (owner, 27 Sep). */
.gl-soon .cover__name,
.gl-ready .cover__name {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* ============================================================================
   THE SKY (owner, 27 Sep): the cover, the book's run and the styles' title
   page sit on a clear, cool light blue instead of the dark cloth — the blue a
   book's feint ruling is printed in, taken to full strength. It is CSS, not
   a lit surface in the scene: one smooth gradient the browser dithers, the
   same behind the book as behind the words. It holds with or without WebGL,
   so the page shown while the book loads is already this cover.
   ========================================================================= */
:root {
  --c-sky:       #8fc3ee;   /* the feint ruling, at full strength */
  --c-sky-hi:    #b8dbf7;   /* the same blue where the light falls */
  --c-sky-deep:  #6ea7de;   /* and toward the edges, away from it */
  --c-sky-shade: #0e3558;   /* its shadow: the book's on it, and type set on it */
  --sky: radial-gradient(110% 85% at 50% 42%, var(--c-sky-hi) 0%, var(--c-sky) 50%, var(--c-sky-deep) 100%);
}

/* Type on the sky is ink, not paper (every pair ≥ 4.5:1 on the deepest blue). */
.cover,
.deck-intro {
  --ground:       var(--c-sky);
  --surface:      var(--c-sky-hi);
  --surface-hi:   #cfe6fa;
  --surface-deep: var(--c-sky-deep);
  --line:         rgb(14 53 88 / .32);
  --line-soft:    rgb(14 53 88 / .16);
  --text:         var(--c-ink);
  --text-2:       #13304c;
  --text-3:       #1b3a5a;
  --mark:         var(--c-proof);
  --focus:        var(--c-ink);
  background: var(--sky) var(--c-sky);
}
.cover__fallback, .cover__veil { display: none; }   /* the cloth panel and its shade were the dark cover's */

/* With the scene running the sky is one fixed layer behind the clear canvas,
   so the book and the words scroll over the same light. */
.gl-ready body::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background: var(--sky) var(--c-sky);
}
.gl-ready .deck-intro { background: transparent; }

/* The nav starts on the sky, so it is ink from the top, with an ink button. */
.nav { color: var(--c-ink); }
.nav__cta { --btn-fg: var(--c-sheet-hi); --btn-bg: var(--c-ink); }
.nav__cta::before { background: var(--c-bar); }
.nav__cta:hover, .nav__cta:focus-visible { color: var(--c-ink); }

/* ============================================================================
   THE OBJECT (owner, 28 Sep) — the style that replaced The Curtain: real-time
   3D. A lit display case: a blue-black ground so the steel carries the light,
   ivory type like the dial's printing, and one accent — the blue of a
   heat-blued screw. The object is the largest thing on the page.
   ========================================================================= */
.t-object { --ground:#0b0d12; --surface:#11151c; --surface-hi:#171c25; --surface-deep:#06070a; --line:#2c323d; --line-soft:#1b2029; --text:#ece8e0; --text-2:#b0b3ba; --text-3:#80858e; --mark:#6b92ea; --focus:#ece8e0; }
.sp--object { background: radial-gradient(90% 70% at 72% 45%, #171b24 0%, var(--ground) 65%); }
.sp--object .style-page__inner {
  display: grid; width: 100%; max-width: 1320px; margin-inline: auto;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: clamp(24px, 3.5vw, 64px); align-items: center;
}
.sp--object .sp__name { font-weight: 300; letter-spacing: 0.01em; }
.sp--object .sp__n { color: var(--mark); }
.sp__stage--object { width: min(100%, 660px); aspect-ratio: 1; max-height: 76vh; border: 0; background: none; overflow: visible; justify-self: center; }
.sp__stage--object .sp__still, .sp__stage--object .sp__gl { position: absolute; inset: 0; width: 100%; height: 100%; }
.sp__stage--object .sp__still { object-fit: contain; transition: opacity 800ms ease; }
.sp__stage--object .sp__gl { opacity: 0; transition: opacity 800ms ease; touch-action: pan-y; cursor: grab; }
.sp__stage--object .sp__gl:active { cursor: grabbing; }
.sp__stage--object.is-gl .sp__gl { opacity: 1; }
.sp__stage--object.is-gl .sp__still { opacity: 0; }
.sp__stage--object.is-instant .sp__still, .sp__stage--object.is-instant .sp__gl { transition: none; }
.sp__controls { position: absolute; left: 50%; bottom: 1%; transform: translateX(-50%); display: none; gap: 10px; white-space: nowrap; }
.sp__stage--object.is-gl .sp__controls { display: flex; }
.sp__btn {
  font-family: var(--f-mono); font-size: var(--t-micro); letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--text-2); background: rgb(11 13 18 / 0.62); border: 1px solid var(--line);
  padding: 10px 14px; cursor: pointer; -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  transition: color 200ms, border-color 200ms;
}
.sp__btn[aria-pressed="true"], .sp__btn:hover, .sp__btn:focus-visible { color: var(--text); border-color: var(--text-3); }
.sp__aside { font-size: var(--t-small); color: var(--text-3); text-decoration: underline; text-underline-offset: 3px; }
.sp__aside:hover, .sp__aside:focus-visible { color: var(--text); }
@media (max-width: 900px) {
  .sp--object .style-page__inner { grid-template-columns: 1fr; gap: var(--s-5); }
  .sp__stage--object { width: min(100%, 440px); max-height: 46vh; }
}
/* entrance: the object first, then the words, unhurried */
.sp--object.is-live .sp__stage { animation: sp-fade 1400ms var(--e-out) both; }
.sp--object.is-live .sp__n    { animation: sp-rise 700ms var(--e-out) 300ms both; }
.sp--object.is-live .sp__name { animation: sp-rise 800ms var(--e-out) 380ms both; }
.sp--object.is-live .sp__def  { animation: sp-rise 800ms var(--e-out) 460ms both; }
.sp--object.is-live .sp__for  { animation: sp-rise 800ms var(--e-out) 540ms both; }
.sp--object.is-live .trait    { animation: sp-rise 700ms var(--e-out) both; }
.sp--object.is-live .trait:nth-child(1) { animation-delay: 620ms; }
.sp--object.is-live .trait:nth-child(2) { animation-delay: 690ms; }
.sp--object.is-live .trait:nth-child(3) { animation-delay: 760ms; }
.sp--object.is-live .trait:nth-child(4) { animation-delay: 830ms; }
.sp--object.is-live .sp__foot { animation: sp-rise 700ms var(--e-out) 900ms both; }
@media (prefers-reduced-motion: reduce) {
  .sp--object.is-live .sp__stage, .sp--object.is-live .sp__n, .sp--object.is-live .sp__name, .sp--object.is-live .sp__def,
  .sp--object.is-live .sp__for, .sp--object.is-live .trait, .sp--object.is-live .sp__foot { animation: none; }
}

/* 3D sites, apart from the four prices (owner, 28 Sep): set in The Object's
   display case below the care plans, so it reads as something separate for a
   particular kind of business — not as a fifth, dearer step up the ladder. */
.threed { margin-top: clamp(64px, 11vh, 128px); background: radial-gradient(90% 120% at 85% 30%, #171b24 0%, #0b0d12 70%); color: #b0b3ba; }
.threed__in { display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(0, 0.7fr); gap: clamp(24px, 4vw, 64px); padding: clamp(32px, 5vw, 72px); align-items: center; }
.threed__label { font-family: var(--f-mono); font-size: var(--t-micro); letter-spacing: 0.22em; text-transform: uppercase; color: #6b92ea; margin-bottom: var(--s-4); }
.threed h3 { font-family: var(--f-display); font-weight: 300; font-size: clamp(1.8rem, 1.2rem + 2vw, 3rem); line-height: 1.08; letter-spacing: -0.01em; color: #ece8e0; margin-bottom: var(--s-4); }
.threed p { max-width: 60ch; }
.threed p b { color: #ece8e0; font-variation-settings: "wght" 550; }
.threed a:not(.btn) { color: #ece8e0; }
.threed__tiers { list-style: none; margin: var(--s-6) 0 var(--s-5); padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border-top: 1px solid #2c323d; }
.threed__tiers li { padding: var(--s-4) var(--s-4) var(--s-2) 0; border-right: 1px solid #1f2530; }
.threed__tiers li + li { padding-left: var(--s-4); }
.threed__tiers li:last-child { border-right: 0; }
.threed__name { font-family: var(--f-mono); font-size: var(--t-micro); letter-spacing: 0.18em; text-transform: uppercase; color: #80858e; }
.threed__price { font-family: var(--f-display); font-size: clamp(1.1rem, 0.85rem + 0.7vw, 1.5rem); color: #ece8e0; margin: 6px 0 8px; white-space: nowrap; }
.threed__tiers li p:last-child { font-size: var(--t-small); line-height: 1.55; }
.threed__care { font-size: var(--t-small); margin-bottom: var(--s-5); }
.threed .btn { --btn-fg: #0b0d12; --btn-bg: #ece8e0; }
.threed__img { width: 100%; height: auto; max-width: 440px; justify-self: center; }
@media (max-width: 900px) {
  .threed__in { grid-template-columns: 1fr; }
  .threed__tiers { grid-template-columns: 1fr; }
  .threed__tiers li { border-right: 0; border-bottom: 1px solid #1f2530; padding-left: 0; }
  .threed__tiers li + li { padding-left: 0; }
  .threed__img { order: -1; max-width: 300px; }
}

/* phones: the object's two controls and its pricing link, a thumb's height
   (44 px) — see site.css, PHONES: TOUCH AND READING */
@media (max-width: 900px), (pointer: coarse) {
  .sp__btn { min-height: 44px; }
  .sp__aside { display: inline-block; padding-block: 12px; }
}
