/* ==========================================================================
   One book, one camera — scene layout for the persistent 3D book.
   html.has3d  → WebGL book drives the scenes (copy fades are set by book3d.js)
   html.no3d   → no WebGL / reduced motion: scenes become a plain illustrated document
   ========================================================================== */
.story3d{position:relative}
/* under the stage at the very end: when the stage slides up with the footer a frame late (Safari), the gap shows dark, not page paper */
html.has3d .story3d::before{content:"";position:absolute;left:0;right:0;bottom:0;height:200vh;z-index:0;background:var(--silence);pointer-events:none}
.stage3d{position:fixed;inset:0;z-index:0;pointer-events:none;display:none}
html.has3d .stage3d{display:block}
.stage3d{overflow:hidden}
.stage3d__bg{position:absolute;inset:0;background:#0B0A09}
/* a pool of warm light behind the book in the dark scenes (book3d.js sets --pool 0…1 and --lx from the key light) */
.stage3d__bg::after{content:"";position:absolute;inset:0;opacity:var(--pool,0);background:radial-gradient(52% 58% at var(--lx,50%) var(--ly,56%),rgba(255,178,128,.2) 0%,rgba(150,52,40,.1) 42%,rgba(60,20,16,0) 72%)}
.stage3d__dust{position:absolute;inset:0;width:100%;height:100%;display:block}
/* the film starts: fade up from black while the lens finds focus (once, when the book is ready) */
.stage3d__curtain{position:absolute;inset:0;background:#070605;transition:opacity 1.7s cubic-bezier(.4,0,.2,1) .1s}
html.book3d-ready .stage3d__curtain{opacity:0}
html.book3d-ready .stage3d__canvas{animation:focus-in 2s cubic-bezier(.2,.7,.2,1) both}
@keyframes focus-in{0%{filter:blur(16px);transform:scale(1.045)}100%{filter:blur(0);transform:scale(1)}}
/* covered by an ordinary section: nothing to composite, nothing to animate */
/* preloader: a quiet title while the WebGL book loads (html.has3d is set before first paint; book3d.js feeds --pl 0…1).
   The show itself is the real book: it arrives open, closes and turns into place (book3d.js, "intro").
   If the script never finishes, the sheet lifts by itself. */
.preloader{position:fixed;inset:0;z-index:9999;display:none;align-items:center;justify-content:center;background:#070605;color:#EFE9DF;text-align:center;transition:opacity .7s cubic-bezier(.4,0,.2,1),visibility 0s .7s;animation:pl-failsafe .9s 20s forwards}
html.has3d .preloader{display:flex}
html.book3d-ready .preloader{opacity:0;visibility:hidden;pointer-events:none}
.preloader__in{display:flex;flex-direction:column;align-items:center;padding:0 24px;animation:pl-in .9s cubic-bezier(.2,.7,.2,1) both}
.preloader__kicker{font-family:var(--sans);font-size:11px;font-weight:500;letter-spacing:.32em;text-transform:uppercase;opacity:.62}
.preloader__title{margin-top:14px;font-family:var(--serif);font-style:italic;font-weight:400;font-size:clamp(30px,5vw,46px);line-height:1.1}
.preloader__bar{position:relative;display:block;width:min(220px,56vw);height:1px;margin-top:34px;background:rgba(239,233,223,.16);overflow:hidden}
.preloader__bar i{position:absolute;inset:0;background:var(--cloth,#C42C40);transform-origin:0 50%;transform:scaleX(var(--pl,.04));transition:transform .7s cubic-bezier(.3,.7,.2,1)}
@keyframes pl-in{0%{opacity:0;transform:translateY(8px)}100%{opacity:1;transform:none}}
@keyframes pl-failsafe{to{opacity:0;visibility:hidden}}
/* during the intro the stage belongs to the book alone: the hero copy and the header come in once it has settled */
html.has3d #top-scene .scene__sticky,html.has3d .site-header{transition:opacity 1.3s cubic-bezier(.4,0,.2,1)}
html.has3d:not(.book3d-ready) #top-scene .scene__sticky,html.is-intro #top-scene .scene__sticky,html.has3d:not(.book3d-ready) .site-header,html.is-intro .site-header{opacity:0;pointer-events:none}
/* asleep: nothing renders, but the backdrop stays, so a section edge never uncovers bare page paper */
.stage3d.is-asleep>:not(.stage3d__bg){visibility:hidden}
.stage3d.is-asleep .stage3d__grain{animation-play-state:paused}
.stage3d__canvas{position:absolute;inset:0;width:100%;height:100%;display:block}
.stage3d__grain{position:absolute;inset:-64px;opacity:calc(.05 + (1 - var(--paper,0)) * .07);mix-blend-mode:overlay;background:url(../img/grain.png) 0 0/128px;pointer-events:none;animation:grain .9s steps(6) infinite}
@keyframes grain{0%{transform:translate(0,0)}17%{transform:translate(-31px,14px)}33%{transform:translate(22px,-37px)}50%{transform:translate(-12px,41px)}67%{transform:translate(39px,7px)}83%{transform:translate(-44px,-21px)}100%{transform:translate(0,0)}}
/* vignette: dense in the dark scenes, a breath on paper (book3d.js sets --paper) */
.stage3d__vig{position:absolute;inset:0;pointer-events:none;background:radial-gradient(120% 95% at 50% 46%,rgba(0,0,0,0) 48%,rgba(6,4,3,.62) 100%);opacity:calc(.22 + (1 - var(--paper,0)) * .78)}
/* letterbox: cinemascope bars for the key moments (book3d.js sets --bars 0…1 from the timeline) */
.letterbox{position:fixed;inset:0;z-index:55;pointer-events:none;display:none}
.letterbox i{position:absolute;left:0;right:0;height:calc(var(--bars,0) * 11vh);background:#070605}
.letterbox i:first-child{top:0}
.letterbox i:last-child{bottom:0}
@media (prefers-reduced-motion:reduce){.stage3d__grain{animation:none}}
@media (max-width:760px),(max-aspect-ratio:4/5){.letterbox i{height:calc(var(--bars,0) * 7vh)}.stage3d{--ly:30%}}
.zoomplate{position:absolute;inset:0;display:flex;align-items:center;justify-content:flex-end;padding:calc(var(--hdr) + 4vh) 7vw 6vh;background:var(--paper) url(../img/paper-tile.jpg) 0 0/300px;opacity:0;visibility:hidden}
.zoomplate img{height:auto;width:auto;max-height:78vh;max-width:50vw;transform-origin:50% 45%;will-change:transform}

.scene{position:relative;z-index:1;height:calc(var(--len,200) * 1vh)}
.scene--short{--len:160}
.scene[data-scene="arrival"]{--len:240}
.scene[data-scene="opening"]{--len:240}
.scene[data-scene="story"]{--len:280}
.scene[data-scene="enter"]{--len:180}
.scene[data-scene="songs"]{--len:440}
.scene[data-scene="object"]{--len:320}
.scene[data-scene="epilogue"]{--len:300}
.scene__sticky{position:sticky;top:0;height:100vh;height:100svh;overflow:hidden}
.scene__fallback{display:none}

/* ---------- copy blocks */
.copy{position:absolute;z-index:2;color:var(--ink)}
html.has3d .copy{opacity:0;visibility:hidden}
html.has3d .copy[data-in="0"]{opacity:1;visibility:inherit}
.scene--dark .copy{color:#EDE6DA}
.copy__kicker{display:block;font:600 12px/1 var(--sans);letter-spacing:.24em;text-transform:uppercase;color:#C9BFB1}
.copy__kicker--cloth{color:var(--cloth-deep)}
.copy__kicker--rose{color:var(--rose)}
.copy__h1{margin:18px 0 0;font:800 clamp(40px,5.2vw,82px)/.93 var(--sans);text-transform:uppercase;letter-spacing:-.012em;text-wrap:balance;max-width:10.5em}
.copy__h2{margin:14px 0 0;font:700 clamp(34px,4vw,60px)/1 var(--sans);letter-spacing:-.01em;text-wrap:balance}
.copy__h2--caps{text-transform:uppercase;font-weight:800}
.copy__h2--song{font-size:clamp(24px,2.3vw,34px);font-weight:600;line-height:1.2}
.copy__lead{margin:22px 0 0;max-width:30em;font:400 clamp(17px,1.35vw,20px)/1.6 var(--serif);color:#C9C1B5}
.copy__lead--ink{color:var(--ink-soft)}
.copy__body{margin:18px 0 0;max-width:32em;font:400 17px/1.65 var(--serif);color:var(--ink-soft)}
.copy__body--light{color:#D4CCBF}
.copy__small{margin:10px 0 0;font:700 16px/1.3 var(--sans);text-transform:uppercase;letter-spacing:.04em}
.copy__statement{margin:18px 0 0;font:500 clamp(26px,2.7vw,42px)/1.22 var(--sans);letter-spacing:-.005em;text-wrap:balance}
.copy__note{margin:18px 0 0}
.copy__src{margin:22px 0 0;font:400 italic 15px/1.5 var(--serif);color:var(--ink-mute)}
.copy__gloss{margin:16px 0 0;font:400 italic 16px/1.55 var(--serif);color:var(--ink-soft)}
.copy__cta{display:flex;flex-wrap:wrap;gap:12px;margin-top:34px}
.copy__cta--center{justify-content:center}
.copy__scroll{display:flex;align-items:center;gap:12px;margin-top:48px;font:500 11px/1 var(--sans);letter-spacing:.24em;text-transform:uppercase;color:#9C9387}
.copy__scroll i{width:44px;height:1px;background:currentColor;transform-origin:0 50%;animation:cue 2.4s var(--ease) infinite}
@keyframes cue{0%{transform:scaleX(0)}55%{transform:scaleX(1)}100%{transform:scaleX(1);opacity:0}}

.copy--hero{left:max(24px,6vw);bottom:12vh;max-width:min(46vw,640px)}
.copy--caption{left:0;right:0;bottom:6vh;text-align:center}
.copy--left{left:max(24px,6vw);top:50%;transform:translateY(-50%);max-width:min(40vw,560px)}
.copy--right{right:max(24px,5vw);top:50%;transform:translateY(-50%);width:min(34vw,470px);max-height:calc(100vh - var(--hdr) - 48px);overflow:auto}
.copy--plate{left:max(24px,6vw);top:50%;transform:translateY(-50%);max-width:min(38vw,560px)}
.copy--product{right:max(24px,5vw);top:calc(var(--hdr) + 3vh);bottom:3vh;width:min(38vw,520px);overflow:auto;padding-right:6px;scrollbar-width:thin}
.copy--finale{left:0;right:0;bottom:9vh;text-align:center;padding:0 24px}
.copy__finale{margin:18px auto 0;max-width:15em;font:400 italic clamp(36px,4.6vw,68px)/1.12 var(--serif);text-wrap:balance}

/* ---------- editorial type (chapter numerals, statements, ruled kickers) */
.copy__kicker{letter-spacing:calc(.24em + (1 - var(--in,1)) * .34em)}
.copy__kicker::before{content:"";display:inline-block;width:28px;height:1px;margin:0 12px 0 0;vertical-align:.32em;background:currentColor;transform-origin:0 50%;transform:scaleX(var(--in,1))}
.copy__num{display:block;margin:0 0 14px -.03em;font:300 clamp(96px,10vw,168px)/.8 var(--serif);letter-spacing:-.02em;color:var(--cloth);user-select:none}
.copy__num--sm{font-size:clamp(64px,5.6vw,92px);margin-bottom:10px}
.copy__num--light{color:var(--rose)}
.copy--chapter{max-width:min(44vw,640px)}
.copy__h2--chapter{font-size:clamp(46px,5.4vw,88px);line-height:.95;text-transform:uppercase;font-weight:800;letter-spacing:-.015em}
.copy__statement--chapter{margin-top:26px;max-width:17em;font:400 clamp(22px,2vw,32px)/1.32 var(--serif);color:var(--ink-soft);letter-spacing:0}
.colophon--big{margin-top:24px;max-width:560px;gap:22px 36px}
.colophon--big dt{font-size:11px}
.colophon--big dd{font-size:clamp(20px,1.7vw,26px);line-height:1.2;font-weight:600}
/* staggered, scroll-driven entrance: book3d.js writes --in (0…1) on each copy block, so it reverses exactly */
html.has3d .copy>*{transform:translate3d(0,calc((1 - var(--in,1)) * var(--k,1) * 22px),0)}
html.has3d .copy>:nth-child(2){--k:1.6}
html.has3d .copy>:nth-child(3){--k:2.3}
html.has3d .copy>:nth-child(4){--k:3}
html.has3d .copy>:nth-child(n+5){--k:3.6}
html.has3d .copy__num{transform:translate3d(calc((1 - var(--in,1)) * -40px),0,0);opacity:var(--in,1)}

.colophon--row{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px 28px;margin:32px 0 0;max-width:520px}
.songlist{list-style:none;margin:20px 0 0;padding:0;font:600 15px/1.3 var(--sans)}
.songlist li{display:flex;justify-content:space-between;gap:16px;padding:8px 0;border-bottom:1px dotted #A9A196}
.songlist li span:last-child{color:var(--cloth-deep);font-variant-numeric:tabular-nums}
.allsongs{margin-top:10px}
.allsongs summary{cursor:pointer;min-height:44px;display:flex;align-items:center;font:600 14px/1 var(--sans);letter-spacing:.06em;color:var(--cloth-deep)}
.verse--scene{margin:20px 0 0;font:700 clamp(24px,2.3vw,36px)/1.22 var(--sans)}
.verse--scene .line:last-child{color:var(--cloth-deep)}
.specs--dark{margin-top:26px}
.specs--dark div{border-top-color:rgba(237,230,218,.28)}
.copy--product .buy--cloth .buy__price{border-color:rgba(237,230,218,.28)}
.copy--product .btn--paper{background:var(--cloth);color:#fff}
.copy--product .btn--paper:hover{background:var(--cloth-deep);color:#fff}
.copy--product .cloth-sec__more{color:#EDE6DA}
.copy__thumbs{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin-top:28px}
.copy__thumbs figure{margin:0}
.copy__thumbs img{width:100%;aspect-ratio:4/5;object-fit:cover}

/* exhibition / collection / journal stay ordinary sections over the stage */
.story3d>.expo,.story3d>.coll,.story3d>.cont{position:relative;z-index:1}
html.has3d .story3d>.expo{background:transparent}
.epi--after{position:relative;z-index:1;background:var(--silence);color:#EDE6DA}
/* the page ends on the dark footer: the rubber-band overscroll past it stays dark too */
html:has(.epi--after){background:var(--silence)}
.epi--after .epi__in{padding-top:40px}

/* header over dark scenes */

/* ---------- phones: book in the upper part of the screen, copy in a reading panel */
@media (max-width:760px),(max-aspect-ratio:4/5){
  .scene[data-scene="songs"]{--len:480}
  .copy--hero,.copy--left,.copy--right,.copy--plate,.copy--product{left:0;right:0;top:auto;bottom:0;transform:none;width:auto;max-width:none;max-height:58vh;max-height:58svh;overflow:auto;padding:28px 20px calc(24px + env(safe-area-inset-bottom,0px))}
  .copy--hero{bottom:0;padding-bottom:40px;background:linear-gradient(0deg,rgba(11,10,9,.94) 62%,rgba(11,10,9,0))}
  .copy--left,.copy--right,.copy--plate{background:linear-gradient(0deg,rgba(243,241,236,.97) 78%,rgba(243,241,236,0));padding-top:56px}
  .copy--product{top:auto;max-height:62vh;max-height:62svh;background:linear-gradient(0deg,rgba(20,18,16,.97) 82%,rgba(20,18,16,0));padding-top:48px}
  /* the contents panel must fit under the book with nothing to scroll: short title, no paragraph, as many songs as the screen holds.
     Opened ("all 25 songs") it scrolls inside itself, and the mask keeps the scrolled lines from ever riding up over the book. */
  .copy--toc{max-height:50vh;max-height:50svh;padding-top:44px;background:rgba(243,241,236,.97);-webkit-mask-image:linear-gradient(180deg,transparent 0,#000 40px);mask-image:linear-gradient(180deg,transparent 0,#000 40px);overflow:hidden;overscroll-behavior:auto}
  .copy--toc:has(details[open]){overflow:auto}
  .copy--toc .copy__h2{font-size:24px;margin-top:14px}
  .copy--toc .copy__body{display:none}
  .copy--toc .songlist{margin-top:14px}
  .copy--toc .songlist li{padding:7px 0}
  .copy--toc>.songlist li:nth-child(n+4){display:none}
  .copy--toc:has(details[open])>.songlist li{display:flex}
  .copy--toc .allsongs{margin-top:6px}
  .copy__h1{font-size:40px}
  .copy__h2{font-size:32px}
  .copy__lead{font-size:16px;margin-top:14px}
  .copy__cta{margin-top:22px}
  .copy__scroll{margin-top:22px}
  .copy__statement{font-size:24px}
  .copy__num{font-size:72px;margin-bottom:6px}
  .copy__num--sm{display:none}
  .copy__h2--chapter{font-size:40px}
  .copy__statement--chapter{font-size:19px;margin-top:14px}
  .colophon--big dd{font-size:18px}
  .copy--chapter{max-width:none}
  .colophon--row{margin-top:20px;gap:12px 20px}
  .verse--scene{font-size:24px}
  .copy__thumbs{display:none}
  .copy--caption{bottom:4vh}
  .copy--finale{bottom:6vh}
  .zoomplate{justify-content:center;align-items:flex-start;padding-top:calc(var(--hdr) + 3vh)}
  .zoomplate img{height:auto;width:min(88vw,60vh);max-width:none;max-height:none}
}
@media (max-width:760px) and (min-height:700px),(max-aspect-ratio:4/5) and (min-height:700px){.copy--toc>.songlist li:nth-child(4){display:flex}}
@media (max-width:760px) and (min-height:760px),(max-aspect-ratio:4/5) and (min-height:760px){.copy--toc>.songlist li:nth-child(5){display:flex}}
@media (max-width:760px) and (min-height:820px),(max-aspect-ratio:4/5) and (min-height:820px){.copy--toc>.songlist li:nth-child(6){display:flex}}
/* phones: a reading panel is never a scroll box. On iOS a swipe that starts on a scrollable panel scrolls the panel,
   not the page, so the book stalls and the text gets cut off. Each panel is sized to fit instead (below). */
@media (max-width:760px),(max-aspect-ratio:4/5){
  .copy--hero,.copy--left,.copy--right,.copy--plate,.copy--product{overflow:hidden}
  .copy--hero{max-height:none;padding-top:24px}
  .copy--hero .copy__cta{flex-wrap:nowrap;gap:10px}
  .copy--hero .copy__cta .btn{flex:1 1 auto;min-width:0;min-height:48px;padding:0 12px;font-size:14px;letter-spacing:.02em;white-space:nowrap}
  .copy--product{max-height:none}
  .copy--product .specs,.copy--product .copy__thumbs{display:none}
  .copy--product .copy__body{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;overflow:hidden}
}
@media (max-width:760px) and (max-height:760px),(max-aspect-ratio:4/5) and (max-height:760px){
  .copy--hero .copy__h1{font-size:34px}
  .copy--hero .copy__scroll{display:none}
  .copy--product .copy__h2{font-size:28px}
  .copy--product .copy__body{-webkit-line-clamp:3;margin-top:12px}
}
/* narrow portrait: the panel cannot hold everything, so price and the buy button come before the spec table (which scrolls) */
@media (max-width:760px),(max-width:767px) and (max-aspect-ratio:4/5){
  .copy--product{display:flex;flex-direction:column;align-items:stretch}
  .copy--product>*{flex-shrink:0}
  .copy--product .buy{order:1}
  .copy--product .cloth-sec__more{order:2;align-self:flex-start}
  .copy--product .specs{order:3;margin-top:18px}
  .copy--product .copy__thumbs{order:4}
}
@media (max-width:760px) and (max-height:700px){.copy--product .copy__body{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;overflow:hidden}}
/* tablet portrait: same stacked layout, but type and gutters sized for the wider page */
@media (min-width:600px) and (max-aspect-ratio:4/5){
  .copy--hero,.copy--left,.copy--right,.copy--plate,.copy--product{padding-left:clamp(32px,6vw,56px);padding-right:clamp(32px,6vw,56px);padding-bottom:calc(40px + env(safe-area-inset-bottom,0px))}
  .copy--left,.copy--right,.copy--plate{padding-top:72px}
  .copy__h1{font-size:56px}
  .copy__h2{font-size:40px}
  .copy__lead{font-size:19px}
  .copy__statement{font-size:31px}
  .copy__h2--chapter{font-size:52px}
  .copy__statement--chapter{font-size:23px}
  .verse--scene{font-size:31px}
  .zoomplate{padding-top:calc(var(--hdr) + 4vh)}
  .copy--product{max-height:56vh;padding-top:40px;padding-bottom:calc(24px + env(safe-area-inset-bottom,0px))}
  .copy--product .specs{grid-template-columns:repeat(3,minmax(0,1fr));max-width:none}
  .copy--product .copy__body{max-width:none}
}

/* ---------- no WebGL / reduced motion: an illustrated document */
html.no3d .scene{height:auto}
html.no3d .scene__sticky{position:relative;height:auto;overflow:visible;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:clamp(24px,4vw,64px);align-items:center;max-width:1320px;margin:0 auto;padding:clamp(72px,9vw,130px) clamp(16px,4vw,56px)}
html.no3d .copy{position:relative;inset:auto;transform:none;width:auto;max-width:none;max-height:none;overflow:visible;padding:0;background:none;opacity:1;visibility:visible}
html.no3d .copy+.copy{grid-column:1}
html.no3d .scene__fallback{display:block;margin:0;grid-column:2;grid-row:1/span 3;align-self:start}
html.no3d .scene__fallback img{width:100%;height:auto}
html.no3d .scene--dark{background:var(--silence)}
html.no3d .scene:not(.scene--dark){background:var(--paper) url(../img/paper-tile.jpg) 0 0/300px}
html.no3d .scene--short{display:none}
html.no3d .copy--caption,html.no3d .copy--finale{text-align:left}
html.no3d .copy__cta--center{justify-content:flex-start}
@media (max-width:760px){html.no3d .scene__sticky{grid-template-columns:1fr}html.no3d .scene__fallback{grid-column:1;grid-row:auto}}

/* ordinary sections between scenes carry their own paper so the stage never shows through behind their text */
.story3d>.coll,.story3d>.cont{background:var(--paper) url(../img/paper-tile.jpg) 0 0/300px}
.stage3d{will-change:transform}
.scene--dark .ph{color:#F3B9C0;border-color:var(--rose);background:rgba(226,112,125,.08)}
