/* =============================================================================
   PATCHWORK DEAD × TapNow LP — scroll（通学路の朝 → 校門 → 空へ → 壁）
   設計: DESIGN.md §3。p（0..1）だけで決まる純関数 computeScene() が書き出す
   CSS カスタムプロパティをここで解釈する。JS は transform を直接書かない。
   ========================================================================== */

.cine {
  position: relative;
  height: 4600px; /* デスクトップのローカルスクロール距離。scroll.js が data-travel で上書き */
}
@media (max-width: 1024px) { .cine { height: 3800px; } }
@media (max-width: 640px)  { .cine { height: 2900px; } }

/* v8（実機バグ2件目）: 100dvh は URL バーの出没のたびにステージの実サイズを
   変え、巨大レイヤーの総リラスタを毎回発生させていた。100svh（フォールバック）
   →100lvh（最終値）にすると、URL バーが出ても引っ込んでもステージの高さは
   常に「バー非表示時の最大サイズ」で固定され、リサイズによる再ラスタが起きない。
   その代わり、URL バー表示中は実際に見える範囲が 100svh 分しかないので、
   下寄せの要素（.cine-loc・独白）だけ calc(100lvh - 100svh) 分だけ上へ
   逃がして画面内に留める（下記）。 */
.cine-stage {
  position: sticky; top: 0;
  height: 100svh; min-height: 560px; height: 100lvh;
  overflow: clip; isolation: isolate;
}

.cine-world {
  position: absolute; inset: -6% -6%;
  opacity: var(--op, 0);
  transition: none;
  will-change: opacity;
}
/* v8: 非表示ワールドは visibility:hidden から display:none に変更。
   visibility:hidden はボックスを描画対象から外すだけでコンポジタ上の
   レイヤー・GPU テクスチャは保持され続けるため、4ワールド分の大きな
   レイヤーが常時 GPU メモリと合成コストを食っていた。display:none は
   レイヤーそのものを破棄する。再表示時のデコードひっかかりが出る場合は
   対象ワールドの img に decoding="async" を維持したまま様子を見る
   （現状すべて付与済み）。 */
.cine-world[data-off] { display: none; }

.cine-layer { position: absolute; inset: 0; transform-origin: 50% 50%; will-change: transform; }
.cine-layer img { width: 100%; height: 100%; object-fit: cover; }
.cine-layer[data-depth="far"]  { transform: scale(1.08) translate3d(calc(var(--push,0) * -1.2%), calc(var(--push,0) * -0.6%), 0); }
.cine-layer[data-depth="mid"]  { transform: scale(1.14) translate3d(calc(var(--push,0) * -2.6%), calc(var(--push,0) * -1.4%), 0); }
.cine-layer[data-depth="near"] { transform: scale(1.22) translate3d(calc(var(--push,0) * -4.6%), calc(var(--push,0) * -2.4%), 0); }
/* v8: JS が毎フレーム style.opacity を書き込むクロスフェード対象の img は、
   opacity 変化をコンポジタだけで完結させる（親レイヤーの再ペイントを防ぐ）。 */
img[data-clayer], img[data-zlayer] { will-change: opacity; }

/* ワールド D（壁）の一枚絵は、壁が画面最上部の細い帯にしか写っていない
   （env/town-wall.webp は町の全景＋最上部に壁）。box の縦横比がソース画像より
   横長寄りのため object-fit:cover は縦方向を全部見せる（横だけを切る）——
   つまり object-position の縦成分はそもそも効かない。実際に壁が消えていた
   原因は、.cine-world の inset 拡大 ＋ .cine-layer の transform:scale() が
   「中心基準」でボックスごと拡大され、その分だけ上端が画面外へ押し出されて
   overflow:clip に食われていたこと。対策は transform-origin を上端に固定して
   「上は動かさず、下だけ伸びる」ズームにすること（object-position はもう効かない
   ので削除）。 */
.cine-world[data-world="d"] { inset: 0 -6%; }
/* オーケストレーター実測差し戻し: 壁は「見えてはいるが画面上端のごく薄い帯」
   だった（=ビューポート高の数%）。ユーザー要求は壁の帯がビューポート高の
   15〜25%を占め、はっきり壁だと分かること。実測（img中央列のピクセル走査）で
   壁の帯は元画像の高さの約10.9%（y=105〜230/1152）。top:0 起点のズームで
   image の上から 1/S だけを見せる計算になるので、壁を画面高の約20%にするには
   S≈1.85 が必要（0.109 * 1.85 ≈ 0.20）。 */
.cine-world[data-world="d"] .cine-layer[data-depth="mid"] {
  transform-origin: 50% 0%;
  transform: scale(calc(1.85 - var(--push,0) * 0.15)) !important;
}

/* ワールド C は「昇っていく・引いていく」感覚なので、mid 層はズームアウト
   （push が進むほど縮む）にする。A・B は逆にじわりと押し込む（既定の挙動）。 */
.cine-world[data-world="c"] .cine-layer[data-depth="mid"] {
  transform: scale(calc(1.16 - var(--push,0) * 0.14)) translate3d(0, calc(var(--push,0) * 2%), 0);
}

/* ---- グレード：p が壁パートに入るほど寒色化（DESIGN.md §3） ---------------- */
.cine-grade {
  position: absolute; inset: 0; z-index: var(--z-tint); pointer-events: none; mix-blend-mode: normal;
  /* 壁の帯（画面上端）で寒色を効かせすぎると、淡い石灰色の壁が同じく淡い靄の
     空に溶けて読めなくなる。上端は控えめにし、中〜下段でしっかり効かせる。 */
  background: linear-gradient(180deg, color-mix(in srgb, var(--haze-700) calc(var(--grade,0) * 22%), transparent) 0%,
                                       color-mix(in srgb, var(--haze-700) calc(var(--grade,0) * 40%), transparent) 30%,
                                       transparent 60%),
              color-mix(in srgb, var(--haze-600) calc(var(--grade,0) * 18%), transparent);
  opacity: var(--grade, 0);
}
/* 批評R2: 通学路〜空へ（暖色パート）が全体的に「マッドな暗さ」に見えるとの
   指摘。ヴィネットの濃さを --grade に連動させ、壁のリビールに入るまでは
   ごく薄く、寒色シフトが始まってから通常の濃さまで強める。 */
.cine-vignette {
  position: absolute; inset: 0; z-index: var(--z-tint); pointer-events: none;
  background: radial-gradient(120% 85% at 50% 30%, transparent 40%, rgba(13,10,8,.55) 100%);
  opacity: calc(0.3 + var(--grade, 0) * 0.7);
}
/* A・B・C（暖色パート）はクリーンで明るいトーンを保つ。D だけ元の露出のまま
   （寒色グレードは既にそちらで表現している）。v8: 以前はここで CSS filter を
   毎フレーム再計算させていた（--push で scale が変わるたびに Chrome が新しい
   スケールでレイヤーを再ラスタ化する原因のひとつ）。同じ調整値は該当する
   WebP ファイル自体に焼き込み済み（_backup/pre-v8 に元ファイルを退避）なので
   ここでは filter を一切掛けない。 */

/* ---- ロケーション字幕 -------------------------------------------------------- */
/* v8: ステージは 100lvh 固定（URL バー出没で再ラスタしないように）。バー表示中
   の実際に見える高さは 100svh しかないので、下寄せのロケ字幕は
   calc(100lvh - 100svh) 分だけ余分に「bottom」を持ち上げ、バーが出ていても
   画面内に収まるようにする。 */
.cine-loc {
  position: absolute; left: var(--s-5); bottom: calc(var(--s-7) + (100lvh - 100svh)); z-index: var(--z-copy);
  opacity: var(--op, 0); transform: translateY(calc((1 - var(--op,0)) * 16px));
  color: var(--cream-100);
}
.cine-loc figcaption { display: flex; align-items: baseline; gap: var(--s-3); }
.cine-loc .loc-id { font-family: var(--font-la); font-style: italic; color: var(--mustard-300); font-size: 1.1rem; }
.cine-loc .loc-name { font-weight: 900; font-size: 1.15rem; }
@media (max-width: 640px) { .cine-loc { left: var(--s-4); bottom: calc(var(--s-6) + (100lvh - 100svh)); } .cine-loc .loc-name { font-size: 1rem; } }

/* ---- 独白（ネネの内心の声・別録り・字幕として重ねる） -----------------------
   壁の帯を画面上部に大きく見せるようにした結果（scale 1.85 前後）、壁の下端は
   おおよそビューポート高の47%あたりに来る。独白はそれより下＝土地の上に
   はっきり置く（壁の上に重ねない）。 */
/* 批評R4: 情報量の多い空撮背景に文字が沈んで読みにくかった。文字を少し大きく
   し、影だけでなく柔らかい暗色の「敷板」を背後に敷いて確実な可読性を作る。 */
.cine-monologue {
  position: absolute; left: 50%; top: 68%;
  /* v8: cine-loc と同じ理由で calc(100lvh - 100svh) だけ上へ寄せ、URL バー
     表示中（実際に見える範囲が 100svh 止まり）でも独白が画面内に収まるようにする。 */
  transform: translate(-50%, calc(-50% + (1 - var(--op,0)) * 10px - (100lvh - 100svh)));
  z-index: var(--z-copy); opacity: var(--op, 0);
  max-width: min(90vw, 34em); text-align: center;
  padding: var(--s-5) var(--s-7);
  background: radial-gradient(120% 140% at 50% 50%, rgba(10,8,7,.62) 0%, rgba(10,8,7,.44) 55%, transparent 90%);
  border-radius: var(--r-lg);
  font-size: clamp(1.3rem, 3.8vw, 2.15rem); font-weight: 700; color: var(--cream-100);
  text-shadow: 0 4px 14px rgba(13,10,8,.9), 0 1px 3px rgba(13,10,8,.95);
}
/* v16（ユーザー指示）: 独白①②を同時に並べて表示する。共通の中央アンカー
   （top:68%）から、独白①は上へ・独白②は下へ、stage の --mono-shift
   （＝独白②のフェード量。scroll.js）に応じて開いていく。shift が 0 の間は
   両方とも元の中央位置に重なるが、独白②はその時 opacity 0 なので見えない。
   独白②が現れきる頃には十分な余白で2段に分かれ、末尾で2つ一緒に
   フェードアウトする際は再び中央へ寄っていく（p の純関数のまま）。 */
.cine-monologue[data-mono="1"] {
  transform: translate(
    -50%,
    calc(-50% + var(--mono-shift, 0) * -50% + var(--mono-shift, 0) * -.6em + (1 - var(--op,0)) * 10px - (100lvh - 100svh))
  );
}
.cine-monologue[data-mono="2"] {
  transform: translate(
    calc(-50% + var(--mono-shift, 0) * 10px),
    calc(-50% + var(--mono-shift, 0) * 50% + var(--mono-shift, 0) * .6em + (1 - var(--op,0)) * 10px - (100lvh - 100svh))
  );
}
.cine-monologue .mono-tag { display: block; font-size: var(--t-label); letter-spacing: .3em; color: var(--haze-300); margin-bottom: var(--s-3); text-shadow: 0 2px 8px rgba(13,10,8,.9); }
@media (max-width: 640px) { .cine-monologue { padding: var(--s-4) var(--s-5); } }
/* v10.1: 独白がモバイル幅で単語の途中から折り返されていた
   （「いや…なんか色々…おかしくな」＋「い…？」のような割れ方）。文節ごとに
   inline-block + nowrap の span で包み、折り返しが起きるとしても文節の
   「間」だけにする。文節間には通常の空白文字を1つ置き、そこだけが
   改行可能点になる。 */
.mono-phrase { display: inline-block; white-space: nowrap; }

/* ---- クラッシュズーム（校門 → 窓 → 校長室）の3枚クロスフェード ---------------
   小さい四角のレイヤーを1枚だけ拡大するとハリボテに見えるため、実カメラが
   寄っていくように見える3枚の実写解像度ショット（wide→medium→office）を
   同じ画面いっぱいのフレームの中でクロスフェードさせる。JS が各 img の
   opacity を p から直接計算して書き込む（scroll.js computeScene の zoomL1/2/3）。 */
.cine-world[data-world="b"] .cine-layer[data-depth="mid"] img[data-zlayer] {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}
.cine-world[data-world="b"] .cine-layer[data-depth="mid"] img[data-zlayer="2"],
.cine-world[data-world="b"] .cine-layer[data-depth="mid"] img[data-zlayer="3"] { opacity: 0; }

/* ---- チャプターのケバブ（p ラベル） ------------------------------------------ */
/* v10: 左上に重なっていた B ロール3枚（busstop/flower-shop/parts-post）を削除
   （ユーザー指摘: ケバブの上に載って読めない・壊れたUIに見える）。ケバブが
   単独で空を背景に立つことになったため、独白（.cine-monologue）と同じ考え方の
   柔らかい暗色の敷板を敷いて、どのワールドの背景色の上でも確実に読めるように
   した。 */
/* v10.1: .cine-stage と .site-header はどちらも position:sticky;top:0 で、
   ヘッダーはドキュメントフロー上の高さ（64px・モバイル52px）ぶんも常に
   y=0〜64px を占有し続ける。.cine-kicker が var(--s-6) だけしか離れて
   いないと、ラベル行「物語 STORY」がヘッダーの下に隠れる。ヘッダー高の
   トークンは無い（overall.css に 64px/52px 直書き）ので、同じ実測値を
   ここでも使い、その分だけ top を押し下げる。 */
.cine-kicker {
  position: absolute; top: calc(64px + var(--s-6)); left: var(--s-5); z-index: var(--z-copy);
  color: var(--cream-200);
  padding: var(--s-3) var(--s-4);
  background: radial-gradient(140% 160% at 0% 0%, rgba(10,8,7,.5) 0%, rgba(10,8,7,.32) 55%, transparent 90%);
  border-radius: var(--r-lg);
}
.cine-kicker .label { color: var(--mustard-300); margin-bottom: var(--s-2); }
.cine-kicker h2 { font-size: clamp(1.1rem, 2.6vw, 1.6rem); text-shadow: 0 2px 10px rgba(13,10,8,.7); }
@media (max-width: 640px) { .cine-kicker { left: var(--s-4); top: calc(52px + var(--s-5)); } }

/* ---- reduced-motion: 縦に並ぶ静的パネル ------------------------------------- */
.cine-static { display: none; }
@media (prefers-reduced-motion: reduce) {
  .cine { height: auto; }
  .cine-stage { position: relative; height: auto; overflow: visible; display: none; }
  .cine-static {
    display: grid; gap: var(--s-6); max-width: 1320px; margin-inline: auto; padding: var(--s-8) var(--s-5);
  }
  .cine-static-panel {
    position: relative; border-radius: var(--r-lg); overflow: hidden; aspect-ratio: 16/9;
    background: var(--surface);
  }
  .cine-static-panel img { width: 100%; height: 100%; object-fit: cover; }
  .cine-static-cap { padding: var(--s-4) 0 0; color: var(--ink-muted); }
  .cine-static-cap b { color: var(--ink); }
  .cine-static .mono-block { text-align: center; padding: var(--s-5) 0; font-weight: 700; font-size: 1.2rem; color: var(--haze-400); }
}
