/* =========================================================
   WAVE ZONE - style.css
   ========================================================= */

:root {
	--c_black: #050505;
	--c_white: #ffffff;
	--c_gray_bg: #f5f5f5;

	/* (zone の本文で使っていた色。story では使わないが、他で参照があるため残す) */
	/* まだ読み進めていない文字の色。薄すぎると未読部分が
	   抜けて見え、濃すぎると変化が見えない。 */
	--c_brand_pending: #c0c0c0;

	/* changeling-neo は Adobe Fonts(Web プロジェクト)での書体名。
	   zone.phtml の Typekit ローダーが読み込む */
	--font_display: 'changeling-neo', 'Zalando Sans SemiExpanded', sans-serif;
	--font_ui: 'Montserrat', sans-serif;
	--font_jp: 'Noto Sans JP', sans-serif;

	--side_padding: 0;

	/* story を最後まで貼り付けたまま footer を上へ被せる距離。footer 自身の高さを
	   js/main_zone.js が実測して入れる。0 のままでも壊れない(被せが無くなるだけ)。 */
	--footer_overlap: 0px;

	/* スクロール演出の速さの倍率 ―― 体感の速さを決めるただ1つの数字(1 = デザインどおり。
	   大きくするほどゆっくり)。.tuneout_lockin_section の高さ / .detail_section の負マージン /
	   #section_3d の高さ は倍率を掛けたあとの実数で書いてあるので、ここを変えたら
	   スマホ側のメディアクエリにあるその3つも一緒に直すこと。 */
	--sp_scroll_stretch: 1;
	/* pin_section が読む名前(js は --pin_scroll_stretch を読む)。上の1つに束ねるための別名。
	   数字を直接書けば pin_section だけ分けられるが、セクションごとに速さが変わる状態に戻る。 */
	--pin_scroll_stretch: var(--sp_scroll_stretch);
	/* pin_section の「間」(整列しきったあと何も動かさずに見せておくスクロール量)の倍率。
	   1 で 0.8 画面ぶん。効くのはスマホだけ(PC は js がスクロールごと止めるので 0 になる)。 */
	--pin_dwell_stretch: 1;
	/* products スライダーの倍率。ここは「1スワイプ = 写真1枚」で受け止めている区間なので
	   体感の速さには出ず、変わるのはページの長さと受け止めの余地の広さだけ。 */
	--sp_slider_stretch: var(--sp_scroll_stretch);
	/* 3D の倍率。1 で可動域 1002vh・ポイントの間隔 約2.06画面(下の --cam_range_vh)。 */
	--cam_stretch: var(--sp_scroll_stretch);

	/* tuneout と 3D の実際の長さ。この2つは負マージンで重ねてあり、.tuneout_lockin_section の
	   高さ / .detail_section の負マージン / #section_3d の高さ が必ず連動する(ずれると負マージンが
	   余って detail が tuneout の下に潜り込む)。1002 は倍率 1 のときの長さ = デザインの基準。 */
	/* tuneout_lockin_inner が sticky で固定されている間の長さ(vh)。ここだけ倍率を掛けない ――
	   780 + 100(固定される前のせり上がり)= 880vh を js/main_zone.js の TUNEOUT_SECTION_VH 8.8
	   と必ず揃える。区間の内訳(尺)は js の GRID / DWELL / CLOSE が持つ。 */
	--tuneout_hold_vh: 780;
	/* 開口の最終段 ―― 上下から潰れて線になって消える「目を閉じる」ところ ―― の長さの倍率。
	   0.85 で 1.50画面 → 1.27画面。js/main_zone.js の TUNEOUT_SHUT_STRETCH が読み、ms と
	   割り当てスクロールの両方を同じ比で詰めるので、手前の①〜③の速さと尺は変わらない。
	   詰めたぶんは下の --cam_start_t に入れてある ―― 片方だけだと引き継ぎ地点が食い違う。
	   PC / スマホ共通(@media では上書きしない)。 */
	--tuneout_shut_stretch: 0.85;
	/* 3D 側の可動域(vh)。ポイントの間隔とカメラの速さは同じものなので、ここが進みの速さその
	   もの。js/3d_zone.js のしきい値は可動域に対する割合なので、js 側に直す場所は無い。 */
	--cam_range_vh: calc(1002 * var(--cam_stretch));
	/* 3D への引き継ぎ地点 = カメラが動き出す地点。js/main_zone.js の __tuneout3dStartScrollY と
	   同じ地点で、固定区間 780vh に対する割合 670.508/780 = 0.859626(上の
	   --tuneout_shut_stretch 0.85 のぶん、倍率 1 のときの 693vh より手前に来る)。js 側の
	   GRID / DWELL / CLOSE / RESOLVE 系の定数を変えたらここも合わせること
	   (ずれるとポイントの間隔だけが変わる)。PC / スマホ共通。 */
	--cam_start_t: 0.859626;
	/* #section_3d の上端が引き継ぎ地点より下に来るぶん = detail_section の上パディングの vh 換算
	   (おおよそ)。clamp なので画面サイズで変わり、スマホ側は @media で入れ替える。 */
	--detail_pad_vh: 9;
	/* tuneout_lockin_section が pin_section の上にかぶさってくる区間の長さ(画面数)。実寸なので
	   スマホの @media でも入れ替えない。.pin_section の高さに足して同じぶん負マージンで引き上げて
	   あるので全体の長さは変わらない。js/main_zone.js の PIN_COVER_VIEWPORTS も同じ値にすること。 */
	--pin_cover_viewports: 1;
}
@media (max-width: 1024px) {
	:root {
		--side_padding: clamp(20px, 7.96vw, 80px);

		/* =========================================================
		   スマホのスクロール量つまみ。1 = PC と同じ長さで、大きくするとゆっくりになる。
		   いまは全部 1(PC と同じセクション間のバランス)。個別に変えるときは
		   var(--sp_scroll_stretch) を数字に置き換える。演出が 3.8 画面(強くはらったときの
		   慣性)より短くなると、1回のはらいで丸ごと通り過ぎるので注意。
		   ========================================================= */
		/* 下の各行の既定値。ここを変えると全部が一緒に動く */
		--sp_scroll_stretch: 1;

		/* pin_section の演出 (1 = 2.4画面) */
		--pin_scroll_stretch: var(--sp_scroll_stretch);
		/* pin_section の「間」は :root の --pin_dwell_stretch(1 = 0.8画面)。
		   数字を2か所に置かないよう、ここでは上書きしない */
		/* 3D の可動域 (1 = 10画面 / ポイントの間隔 2.06画面)。ここだけ 1 を下回らせてある ――
		   スマホは1回のはらいで進む距離が短く、10画面だと 3D だけでページの半分を占めるため。
		   しきい値は可動域に対する割合なので js 側は触らない。これ以上詰めると読み終える前に進む。 */
		/* 0.65 → 0.57。必要なスクロール量をおよそ 12% 減らす。
		   この1つが「カメラの可動域に割り当てるスクロール量」なので、減らすと同じ道のりを
		   短い距離で進む = 指に対する進みはそのぶん速くなる(切り離せない)。12% は速さの差が
		   気づきにくい範囲で選んだ値。もっと縮めたい場合は速さも一緒に上がる。 */
		--cam_stretch: 0.57;
		/* products スライダー (1 = 2.8画面)。ここは体感の速さに出ない(「1スワイプ = 写真1枚」)。
		   変わるのはページの長さと、払って飛び込んできたときに受け止める余地の広さだけ。 */
		--sp_slider_stretch: var(--sp_scroll_stretch);

		/* 開口の最終段(目を閉じるところ)は :root の --tuneout_shut_stretch(0.85)のまま。
		   PC と同じ詰め具合に揃えてあるので、ここでは上書きしない(--cam_start_t も同じ)。 */

		/* これは倍率ではなく実測値。detail_section の padding-top の vh 換算で、この幅では下限の
		   48px に張り付く(画面の高さ 800px とみて約 6vh)。#section_3d の高さの式が使う。 */
		--detail_pad_vh: 6;
	}
}

* {
	box-sizing: border-box;
}

/* data-reveal: スクロールで画面内に入ったら現れる要素の共通の初期状態。実際の値は
   js/main_zone.js が毎フレーム書くので、ここは JS 実行前に完成形が見えないようにするだけ。 */
[data-reveal] {
	opacity: 0;
	transform: translateY(36px);
}

html {
	scroll-behavior: smooth;
	/* スクロールを「ここで一度止める」ための土台。止める位置は .pin_scroll_stop ただ1つ。
	   mandatory だとページ全体が常にその1点へ引き寄せられるので proximity にしてある。 */
	scroll-snap-type: y proximity;
	/* タップしたときに要素が青く光るのを止める(継承するので1か所でページ全体に効く)。
	   フォーカスの輪郭(:focus-visible)は、操作位置が分からなくなるので消していない。 */
	-webkit-tap-highlight-color: transparent;
}

/* 読み込みの間は smooth を切る(zone.phtml の head で付け、load の少しあとに外す)。更新したときの
   位置の復元は、ページの組み上がりを待って遅れて走ることがあり、smooth のままだと先頭から
   目的の位置まで流れて見える(実測: 12760 へ戻るのに 1.5 秒かけて流れた)。 */
html.is_restoring {
	scroll-behavior: auto;
}

body {
	margin: 0;
	/* 暗い背景のセクションが大半なので body の地色は黒にしておく。iOS Safari はスクロール中に
	   fixed/sticky の全画面要素がビューポートを覆いきれず隙間が見えることがあり、黒にしておけば
	   そこが白く光らない(このページは全面が黒地)。 */
	background: var(--c_black);
	color: var(--c_black);
	font-family: var(--font_jp);
	line-height: 1.6;
	/* 共通css(/life/cmn/css/style.css)の body { letter-spacing:0.05em } を打ち消す。
	   字間はこのページ側で必要な箇所だけ指定している */
	letter-spacing: normal;
	-webkit-font-smoothing: antialiased;
	/* 横あふれを切る。hidden ではなく clip を使うこと ―― hidden はスクロール枠(スクロール
	   コンテナ)を作るので、iOS Safari ではページ中の position:sticky の基準がそちらへ移り、
	   貼り付きが軒並み効かなくなる(実機で確認。切るのをやめると全部直った)。
	   clip は「切るだけでスクロールはさせない」ので、枠を作らず sticky に触らない。
	   前の行の hidden は clip を知らない古いブラウザ向けの保険で、対応していれば下の clip が勝つ。 */
	overflow-x: hidden;
	overflow-x: clip;
	/* 上が hidden で解決されたブラウザでは body がスクロールコンテナになり、スナップ位置を
	   探すときの「いちばん近いスクロールコンテナ」がここになるため、html と同じ指定を置く。 */
	scroll-snap-type: y proximity;
}

img {
	max-width: 100%;
	display: block;
	/* 共通css(/life/cmn/css/style.css)の img { width:100% } を打ち消す。
	   このページの絵は各所で幅を決めているので、既定は auto のままにする */
	width: auto;
}

a {
	color: inherit;
	text-decoration: none;
}

ul {
	list-style: none;
	margin: 0;
	padding: 0;
}

h1, h2, h3, p {
	margin: 0;
}

/* 見出し(h1)。ページの字はほぼ絵で組んであるので、読み上げと検索のためだけに置き、
   画面には出さない。display:none / visibility:hidden だと読み上げからも消えるため、
   1px に畳んで隠す。 */
.zone_page_title {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

section {
	position: relative;
}

/* footer を本文へ重ねる仕掛けは story では使わない ―― 本文は区間の中で
   入れ替わり、最下部で止まらないため。footer はそのまま下に続く。 */
/* =========================================================
   Header / Navigation
   =========================================================
   ヘッダーは共通ヘッダー(applicationJpPc/views/quarry/wavelifeBodyHeader.phtml)
   に置き換えたため、体裁は /life/cmn/css/style.css が受け持つ。
   このページ側で上書きすると position:fixed などを打ち消してしまうので、
   ここには何も置かない。
   ========================================================= */

/* =========================================================
   Hero (mv)
   ========================================================= */

/* hero_stage は通常フロー上に 100vh 分の場所を確保するだけの箱。中の hero_section は js が
   付け外しする .is_pinned で「画面に固定」⇔「役目を終えて非表示」を切り替える。 */
.hero_stage {
	position: relative;
	height: 100vh;
	height: 100lvh; /* スマホでURLバーの表示/非表示によって高さが変わらないよう固定する */
	overflow: hidden;
}

.hero_section {
	width: 100%;
	height: 100vh;
	height: 100lvh;
	overflow: hidden;
	background: #111;
	z-index: 20;
}

.hero_section.is_pinned {
	position: fixed;
	top: 0;
	left: 0;
	visibility: visible;
}

.hero_section:not(.is_pinned) {
	position: absolute;
	top: 0;
	left: 0;
	visibility: hidden;
	pointer-events: none;
}

.hero_bg {
	position: absolute;
	inset: 0;
}

/* picture は既定でインライン。中の img の height:100% が親の高さを参照できるよう block にする。 */
.hero_bg picture {
	display: block;
	width: 100%;
	height: 100%;
}

.hero_bg img,
.hero_movie {
	width: 100%;
	height: 100%;
	object-fit: cover;
	/* js/main_zone.js の updateHeroMouseParallax がマウス位置に応じて毎フレーム書き換える
	   (静止画・動画の2枚とも同じだけ動かすので、入れ替わっても絵が動かない) */

	/* 下の transform は「カーソルが中央にあるとき」= js が書く静止時の姿と同じ値。ここを
	   空にしておくと、最初の1フレームで scale(1.06) が当たって画がパッと寄って見える
	   (読み込み画面を出さないときは、その寄りがそのまま目に入る)。
	   1.06 は、視差でずらしたぶん縁が透けないようあらかじめ広げてある量(js 側と同じ)。 */
	transform: translate(0, 0) scale(1.06);
	will-change: transform;
}

/* MV の動画。静止画の上にぴったり重ねてあり、ローディングの ENTER で再生が始まったところで
   濃さだけ入れ替える(js が .is_movie を付ける)。再生できない端末では静止画のまま。 */
.hero_movie {
	position: absolute;
	inset: 0;
	opacity: 0;
	transition: opacity 900ms ease;
	pointer-events: none;
}

.hero_section.is_movie .hero_movie {
	opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
	.hero_movie {
		transition: none;
	}

}

/* =========================================================
   Pinned scroll section
   ---------------------------------------------------------
   画面に貼り付いている間のスクロール量だけで進むタイムライン。パネルの区切りは無く、重ねた
   各レイヤーがそれぞれ別のタイミングで現れ/消える。進み具合(0〜1)は js/main_zone.js の
   PIN_TIMELINE が --pin_<名前> として書き込んでくるので、ここではそれを opacity や blur の
   計算に使うだけ(transition は使わない)。var() の第2引数は js が動かなかったときの見え方。
   ========================================================= */

.pin_section {
	position: relative;
	/* 貼り付く 1 画面ぶん + アニメーションぶん + 本文を読み進めるぶん。値は js/main_zone.js の
	   PIN_SCROLL_VIEWPORTS / PIN_DWELL_VIEWPORTS が書き込む(ここにあるのは js が動かなかったときの
	   同じ値)ので、長さを変えるときは js 側だけを触ればよい。最後に --pin_cover_viewports ぶんを
	   足してあるのは focus の写真がせり上がってくる区間で、負マージンで引き戻すので全長は不変。 */
	--pin_scroll_viewports: 2.4;
	--pin_dwell_viewports: 0.6;
	height: calc((1 + var(--pin_scroll_viewports) + var(--pin_dwell_viewports) + var(--pin_cover_viewports)) * 100vh);
	height: calc((1 + var(--pin_scroll_viewports) + var(--pin_dwell_viewports) + var(--pin_cover_viewports)) * 100lvh); /* スマホでURLバーの表示/非表示によって高さが変わらないよう固定する */
}

.pin_section_inner {
	position: sticky;
	top: 0;
	height: 100vh;
	height: 100lvh;
	overflow: hidden;
	z-index: 30;
	/* 背景は、この中のいちばん奥に敷いた .pin_text_field(canvas)が
	   持っている */
}

/* tuneout が画面に貼り付いたら隠す。この層は z-index:30 で #section_3d より手前にいるため、
   tuneout が開口の外側を削った先にこれが残っていると 3D ではなく pin の画面が覗いてしまう。
   opacity ではなく visibility なのは、中で回っている canvas の描画まで止めるため。 */
.pin_section_inner.is_covered {
	visibility: hidden;
}

/* タイムラインを進み切ったあとの1画面ぶんは sticky が外れてただの余白になる。この間も
   z-index の高い pin_section_inner が残るので、is_done でクリックを透過させておく。 */
.pin_section_inner.is_done {
	pointer-events: none;
}

/* ---------------------------------------------------------
   pin_section_scaler: 入場中の「広がりながら入ってくる」動き
   ---------------------------------------------------------
   下から入ってくる間は画面より一回り小さい「板」として見せ、貼り付く直前に 100% へ届かせる
   (傾きから正位置へ戻る回転も一緒に掛かる。値は js の PIN_ENTER)。width ではなく scale なのは、
   width だとレイアウトが動いて中の canvas が文字画像を作り直してしまうため。倍率は js が毎
   フレーム style.scale に書くので、ここには scale を書かない(js が動かなければ等倍が正解)。
   --------------------------------------------------------- */
.pin_section_scaler {
	position: absolute;
	inset: 0;
	/* 小さく・傾いている間、板の縁で中身(canvas・本文)を切る。rotate も掛かるので、
	   切り口は「傾いた長方形」になる。 */
	overflow: hidden;
}

/* 動きを控える設定では拡大そのものを行わない(js が動かなかったときの保険)。 */
@media (prefers-reduced-motion: reduce) {
	.pin_section_scaler {
		scale: 1 !important;
		rotate: 0deg !important;
	}
}

/* 本文が整列しきったところでスクロールを一旦止めるための、見えない目印。位置は js の
   updatePinProgress が進行度 1 と判定する点と同じ。scroll-snap-stop:always により、1回の
   スクロール操作ではここを飛び越えられなくなる。js で位置を動かして止めないのは iOS で
   sticky/fixed の固定が外れるため。「一度だけ」止めたいので js が .is_off を付け外しする。
   高さ 1px なのは、高さ 0 の要素をスナップ領域として扱わないブラウザがあるため。 */
.pin_scroll_stop {
	position: absolute;
	left: 0;
	top: calc(var(--pin_scroll_viewports) * 100vh);
	top: calc(var(--pin_scroll_viewports) * 100lvh);
	width: 1px;
	height: 1px;
	scroll-snap-align: start;
	scroll-snap-stop: always;
	pointer-events: none;
	/* visibility:hidden は使わない ―― その箱をスナップ領域として扱わないブラウザがあるため
	   (1px × 1px で背景も枠も持たないので、見えるものは何も無い)。 */
}

/* 整列位置へ着いた瞬間の、完全な一時停止(長さは js の PIN_STOP_HOLD_MS)。スナップは整列位置へ
   引き寄せるだけで止め切ってはくれず、はらいの残りの勢いでそのまま通り過ぎる(scroll-snap-stop は
   proximity では効かず、mandatory は静止状態で掛けた瞬間に吸い寄せるので使えない)。html の
   overflow を切る手も走っている慣性には効かないため、実際に止めているのは js の押さえ込み。 */

/* 止めるのは「整列しきったところへ来たとき、その1回だけ」。用が済んだら js(updatePinProgress)が
   .is_off を付けてスナップ位置ごと取り下げる ―― 残したままだと proximity の磁石が効いて、
   読み進めようと少し送るたびに元の位置へ引き戻されてしまう。上へ戻れば js がまた外す。 */
.pin_scroll_stop.is_off {
	scroll-snap-align: none;
}

/* 押さえ込んでいる間だけ掛ける、ブラウザ側の足止め(js が付け外しする)。毎フレームの scrollTo
   だけではスマホの慣性は止まらないが、mandatory にすると整列位置でその慣性が死ぬ。常時掛けられ
   ないのは「どこにいても整列位置へ吸い寄せてしまう」ため。実機ではこれだけでは足りず、下の
   @media (pointer: coarse) でスクロールそのものを止めている。 */
html.is_pin_hold,
html.is_pin_hold body,
html.is_pin_hold_native,
html.is_pin_hold_native body {
	scroll-snap-type: y mandatory;
}

/* 止めの仕掛けを下ろしているブラウザ(iOS。js の SCROLL_STOP_MODE が 'off')ではスナップも無くす。
   Safari は mandatory でも proximity でも「進行方向の次のスナップ位置へ寄せる」ため、残すと
   整列位置を通り過ぎたあと次の目印(3D の直前)まで一気に運ばれてしまう。 */
html.is_scroll_stop_off,
html.is_scroll_stop_off body {
	scroll-snap-type: none;
}

/* is_pin_hold_native は iOS(WebKit)用で、付くのはこの mandatory だけ。iOS では overflow:hidden が
   スクロール位置ごと壊れ、慣性も js からは止められないので、js から一切引っ張らずここまでで
   止める ―― 効けばブラウザ自身が整列位置で止め、効かなければ止まらないだけで何も壊れない。 */

/* タッチ端末での足止め本体。overflow:hidden は「ユーザー操作によるスクロールだけを断り、js からの
   scrollTo は通す」ので、慣性はここで死に押さえ込みの引き戻しはそのまま効く。body 側も一緒に
   書き換えるのが要 ―― body は overflow-x:hidden でスクロールコンテナになっており、html だけを
   hidden にすると sticky の基準が body へ移って pin の中身が飛ぶ。PC に掛けないのはスクロール
   バーが消えてビューポート幅が変わり、vw 基準の寸法と文字の位置がずれるため。 */
@media (pointer: coarse) {
	html.is_pin_hold {
		overflow: hidden;
	}

	html.is_pin_hold body {
		overflow: visible;
	}
}

/* 押さえている間の蓋。足止めが効き始めるまでの1〜2フレーム、慣性が整列位置を通り過ぎることが
   あり、そのとき画面に出てくるのはこのセクションだけなので出さない。整列位置ではこのセクションは
   画面の下端の外にいるので、隠しても見た目は何も変わらない。 */
html.is_pin_hold .tuneout_lockin_section {
	visibility: hidden;
}

/* 動きを控える設定では散らばりも集約も無く最初から組んだ位置なので、止める理由が無い。 */
@media (prefers-reduced-motion: reduce) {
	.pin_scroll_stop {
		scroll-snap-align: none;
	}
}

/* =========================================================
   pin_text_field: 「氾濫した文字の中にいる」3D 演出(canvas)
   ---------------------------------------------------------
   pin_section のいちばん奥に敷く1枚。絵はすべて js/main_zone.js の「pin_text_field」が
   Canvas 2D に描くので、css 側は置き場所だけを面倒みる。sticky な .pin_section_inner の中で
   絶対配置しているだけなので、せり上がり・貼り付き・流れ去りは親の sticky がそのまま担う。
   ========================================================= */

.pin_text_field {
	position: absolute;
	inset: 0;
	z-index: 0; /* 同じ inner の中の本文・About より背面(いちばん奥の1枚) */
	overflow: hidden;
	pointer-events: none;
	/* スクロール中の描画落ち対策(iOS Safari)で GPU 合成レイヤーに昇格させる */
	transform: translateZ(0);
	-webkit-transform: translateZ(0);
	backface-visibility: hidden;
	-webkit-backface-visibility: hidden;
	/* canvas の描画が間に合わない一瞬でも下が透けないよう、地の色を
	   canvas 側の暗部と同じにしておく */
	background: #08080b;
}

.pin_text_field_canvas {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	display: block;
}

/* --- レイヤー --- 本文・ZONEロゴ・About は pin_section_inner に重ねただけの独立したレイヤーで、
   どれも自前の背景を持たず、いちばん奥の .pin_text_field(canvas)がそのまま透けて見える。
   現れ方・消え方は各要素が --pin_* を読んで自分で決める(始まりと終わりは js の PIN_TIMELINE)。 */

/* 本文(pin_copy_text)だけは他と違い、最初から最後まで出したままにして、ぼかしの量だけを変える。 */
.pin_copy_text {
	position: absolute;
	left: 50%;
	top: 50%;
	/* ここでは中央寄せのままにし、上揃えへの切り替えは .pin_copy_text.is_flow が持つ。
	   「本文だけを上へ送る量」は transform ではなく translate プロパティ側に載る(js が毎フレーム
	   書き込む)。カスタムプロパティで渡すと継承のせいで 187 個の .pin_copy_char すべてのスタイルが
	   作り直され、1フレームあたり 6.8〜12.5ms 掛かっていた。要素自身の translate は継承しない。 */
	transform: translate(-50%, -50%);
	/* 折り返しの境目。基準は最終行(28文字)で、結びの一文が途中で折れると読み終わりの据わりが
	   悪いため、この行が1行で収まる幅を上限にする。1文字ぶんの送りは font-size × 1.4 なので
	   28 × 1.4em に1文字ぶんの余裕を足して 40.6em。字間を変えたらこの値も一緒に直すこと
	   (基準にする行を変えたら 28 も)。96vw のほうは、40.6em すら入らない狭い画面での保険。 */
	max-width: min(96vw, 40.6em);
	width: max-content;
	/* 上揃え(.is_flow)にしたときの、画面上端から本文までの余白。本文が画面をどれだけ超えて
	   いるかを測るときに js(measurePinCopyRead)も読む。下端にも同じだけ空く。 */
	--pin_copy_pad_top: clamp(56px, 21vh, 260px);
	/* letter-spacing は行末の1文字のうしろにも入るため箱の右端に 0.4em ぶんの空きが残り、そのまま
	   中央に置くと見えている文字の列が 0.2em だけ左へ寄る。そのぶんを右へ戻す。
	   スマホ側では下のメディアクエリで 0 に戻している。 */
	margin-left: 0.2em;
	font-family: var(--font_jp);
	font-weight: 300;
	font-size: clamp(10px, 2.25vw, 20px);
	letter-spacing: 0.4em;
	line-height: 5;
	color: var(--c_white);
	text-align: left;
	/* 濃さはここでは一定にしておく(フェードインとぼかしは .pin_copy_char 側が1文字ずつ持つ)。
	   この1要素にまとめて掛けると、フィルタの範囲が実質画面いっぱいになって処理落ちする。 */
	opacity: 0.9;
	pointer-events: none;
}

/* 本文が画面(pin_section_inner = 1 画面)より高いときだけ js が付ける。中央寄せのままでは
   上下が切れた真ん中から始まってしまうので、上揃えにして1行目から読ませ、続きは js が書き込む
   translate で上へ送る(スクロール量と 1:1 なので、背景は止まったまま本文だけが動いて見える)。
   送る距離は js の measurePinCopyRead() が実測し、そのぶんだけ「間」を伸ばす。 */
.pin_copy_text.is_flow {
	top: var(--pin_copy_pad_top);
	/* 送り量は translate プロパティ側(js が書き込む)。ここは左右の中央寄せだけ */
	transform: translateX(-50%);
}

/* 本文中のブランド名だけ欧文書体(--font_display)へ切り替える。和文書体に入っている欧文字形は
   和文に馴染ませるための添え物で、ブランド名として置くには字面が弱いため。 */
.wave_zone_mark {
	font-family: var(--font_display);
}

/* =========================================================
   本文の集約: .pin_copy_char が大きく散った状態から正規の位置・原寸へ集まってくる。
   背景の canvas では文字の筒が外へ流れ去るので、「ノイズが流れ去る一方で、伝えたい言葉だけが
   中心に集まってくる」という対比になる。
   ========================================================= */

/* --- 本文の1文字 --- js/main_zone.js の buildPinCopyChars() が包み、散らばった状態を
   インライン変数で書き込む。
	--cx / --cy … 散らばりの向きと距離(vw / vh)   --cs … 散らばり時の追加の拡大量
	--cd … 集約の出遅れ(0〜1)   --ck … 1 / (1 - --cd)   --ci … 現れはじめる時刻(0〜1)
   --t が集約の進み具合、--rest(= 1 - --t)がまだ散らばっている量、--appear がフェードインの
   進み具合。位置・大きさ・濃さをすべてこれらから出しているので、止めればその状態で止まる。 */
.pin_copy_char {
	display: inline-block;
	--t: clamp(0, calc((var(--pin_copy_gather, 1) - var(--cd, 0)) * var(--ck, 1)), 1);
	--rest: calc(1 - var(--t));
	/* --pin_copy_in_k は1文字ぶんのフェードの長さの逆数(js が渡す) */
	--appear: clamp(0, calc((var(--pin_copy_in, 1) - var(--ci, 0)) * var(--pin_copy_in_k, 3)), 1);
	/* 散らばりぶんのずれ */
	--sx: calc(var(--cx, 0px) * var(--rest));
	--sy: calc(var(--cy, 0px) * var(--rest));
	translate: var(--sx) var(--sy);
	scale: calc(1 + var(--cs, 0) * var(--rest));
	/* 現れ具合(--appear)に、散らばっている側ほど少し薄くする分を掛ける。全部が同じ濃さで
	   散らばると、文字数ぶんの巨大な字で画面が埋まって重たく見えるため。 */
	opacity: calc(var(--appear) * (1 - 0.3 * var(--rest)));
	/* 大きく散っている文字ほどぼかす。filter は transform より先に要素のローカル座標で掛かるので、
	   ここに書く 1px は「拡大前の 1px」で、その結果を scale が一緒に引き伸ばす ―― 倍率に比例して
	   粗くなる。--rest を掛けてあるので、集約が終わった文字から順にぼけも抜けていく。 */
	filter: blur(calc(var(--rest) * var(--copy_blur, 0.9px)));
}

/* 晴れきったら filter ごと外す。blur(0) でも filter がある限りレイヤーを1枚持ち続けるため、
   値を 0 にするだけでは足りない。.is_sharp は js が --pin_copy_clear が 1 になったときに付ける。 */
.pin_copy_text.is_sharp .pin_copy_char {
	filter: none;
}

/* 動きを控える設定では、本文は散らさず最初から組んだ位置・原寸で見せる。 */
@media (prefers-reduced-motion: reduce) {
	.pin_copy_char {
		translate: none;
		scale: 1;
		opacity: 1;
		animation: none;
	}
}

/* ノイズに合わせて本文もカクカクとずれ、映像が安定していないように見せる(1枚目の間だけ)。
   ずれるのは塊ではなく1文字ずつで、js が選んだ文字に .is_shake を付け周期・位相・振れ幅を配る。
   ずらしは transform ではなく相対配置(left/top)―― transform 系は散らばりと集約に使っていて
   競合するうえ、inline 要素には効かないため。相対配置なら行組みに一切影響しない。 */
.pin_section_inner.is_unstable .pin_copy_char.is_shake {
	position: relative;
	animation-name: pin_copy_shake;
	animation-timing-function: steps(1, end);
	animation-iteration-count: infinite;
	animation-duration: var(--jitter_dur, 2.9s);
	animation-delay: var(--jitter_delay, 0s);
}

/* 震える文字の選び方と、1文字ごとの周期・位相・振れ幅は js の PIN_COPY_SHAKE /
   markPinCopyShakeChars()。秒数は割り切れない値なので、ずれた文字同士はそのまま重ならない。 */

/* 動きを控える設定では、乱れは出さず組んだ位置のままにする */
@media (prefers-reduced-motion: reduce) {
	.pin_section_inner.is_unstable .pin_copy_char.is_shake {
		animation: none;
	}
}

/* 1周のうちずれているのはごく短い間だけ。残りは止めておくことで、たまに一か所だけ跳ねて見える。 */
@keyframes pin_copy_shake {
	0%, 20% { left: 0; top: 0; }
	21% { left: calc(var(--jitter_x, 3px) * -1); top: 0; }
	23% { left: var(--jitter_x, 3px); top: -1px; }
	24%, 56% { left: 0; top: 0; }
	57% { left: calc(var(--jitter_x, 3px) * 0.7); top: 0; }
	59%, 79% { left: 0; top: 0; }
	80% { left: calc(var(--jitter_x, 3px) * -0.5); top: 1px; }
	82%, 100% { left: 0; top: 0; }
}

/* ロゴは本文(pin_copy_text)の中、1行目の上に置く ―― 本文の位置・文字サイズ・折り返しが変わっても
   左上に張り付いたままにするため(固定オフセットだと画面幅でずれる)。Z O N E の4文字は本文の文字と
   まったく同じ扱いで、散らばった状態から集約してくる。1枠は画像(1305x146)を横に4等分したもので、
   同じ画像を background-size:400% で敷き、position で見せる枠をずらしている。 */
.zone_text_logo {
	/* 本文は行送りを広く取ってあるため、インラインのままだとロゴも行ボックスに乗って上下に行送りぶんの
	   空きが付く。flex にして行ボックスから外し、ロゴと本文の間隔は margin-bottom だけで決める。 */
	display: flex;
	width: clamp(120px, 12vw, 227px);
	margin-bottom: clamp(10px, 2.18vw, 42px);
}

.zone_text_logo_char {
	/* 4等分。1枠 = 1305 / 4 = 326.25px 相当 */
	flex: 0 0 25%;
	aspect-ratio: 326.25 / 146;
	background-image: url(../img/zone_text_logo.png);
	background-repeat: no-repeat;
	/* 横は4枚ぶんに拡大しておき、下の position でどの1文字を見せるか決める */
	background-size: 400% 100%;
}

/* background-position の % は「画像の X% を枠の X% に合わせる」指定。画像が枠の4倍幅なので、
   0 / 1/3 / 2/3 / 1 でちょうど1枠ぶんずつ送れる。 */
.zone_text_logo_char:nth-child(1) { background-position: 0% 0; }
.zone_text_logo_char:nth-child(2) { background-position: 33.3333% 0; }
.zone_text_logo_char:nth-child(3) { background-position: 66.6667% 0; }
.zone_text_logo_char:nth-child(4) { background-position: 100% 0; }

/* 終盤に現れる(--pin_about_in)。出ていない間は js が .is_off を付ける */
.zone_text_about_link {
	position: absolute;
	right: clamp(20px, 5vw, 90px);
	top: 50%;
	transform: translateY(-50%) rotate(90deg);
	transform-origin: center;
	font-family: var(--font_ui);
	font-weight: 500;
	font-size: 16px;
	color: var(--c_white);
	letter-spacing: 0.06em;
	display: flex;
	align-items: center;
	gap: 14px;
	opacity: var(--pin_about_in, 0);
}

/* 完全に消えている間は描画ごと止める(js が付け外しする)。visibility なら中で回っている
   無限アニメーションの描画も止まり、About はクリックも拾わなくなる。 */
.zone_text_about_link.is_off {
	visibility: hidden;
}

.zone_text_about_link::before {
	content: '';
	display: inline-block;
	width: 1px;
	height: 26px;
	background: var(--c_white);
}

/* =========================================================
   focus の写真(tuneout の下地)
   tuneout_lockin_inner の中に敷いてある、開口が閉じていく下地そのもの。
   16:9 にしているのは画像の切り取りを起こさないため ―― 写真がデザインと同じ 1920x1080 で
   書き出されているので、枠が 16:9 なら object-fit: cover でも1pxも切り取られない。
   ピントを合わせる位置(--focus_inset)も角枠まわりの % も、この 1920x1080 に対する割合。
   ========================================================= */

/* 開口の内側に残る下地の層。地色2層とまったく同じ --tuneout_backdrop_clip で切り取るので、写真は
   「開口の内側 = まだ見えている世界の側」にだけ残り、削れた先は素通しで #section_3d が見える。
   重なり順は 0:縁と地色 / 1:写真 → 粒子ノイズ → ヴィネット(DOM 順)/ 2:見出し。 */
.tuneout_photo {
	position: absolute;
	inset: 0;
	z-index: 1;
	overflow: hidden;
	clip-path: var(--tuneout_backdrop_clip, none);
}

/* 16:9 を保ったまま画面を覆う枠。画面の縦横比は 16:9 とは限らないので幅か高さは必ず画面より
   大きくなり、はみ出したぶんは overflow:hidden で切り落とす。切れるのは端だけでセルの比は
   16:9 のままなので、写真そのものが object-fit で切り取られることはない。 */
.tuneout_photo_frame {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	/* 画面より小さくならない側を基準にする(= background-size:cover と同じ) */
	width: max(100vw, calc(100vh * 16 / 9));
	width: max(100vw, calc(100lvh * 16 / 9));
	height: max(100vh, calc(100vw * 9 / 16));
	height: max(100lvh, calc(100vw * 9 / 16));
	background: var(--c_black);
}

/* 写真は1枚。tuneout_photo_frame(16:9)をそのまま埋める。ピント合わせの「いまの姿」は js の
   applyFocusAf() が毎フレーム書き込む(下にある値は js が動かなかったときの姿)。 */
.focus_item {
	position: relative;
	height: 100%;
	overflow: hidden;
	/* ぼけの段の重なり(1 = その段を出しきる) */
	--f_b10: 0;
	--f_b04: 0;
	--f_sharp: 0;
	/* 角枠。最初から出ていて、ピントの寄り引きに合わせて動く。
	   --focus_af … 濃さ / --focus_af_out … 外側へ開いている量(1 = 目いっぱい外)/
	   --focus_af_hit … 決まった合図の「ピッ」(1 で太く白くなる) */
	--focus_af: 1;
	--focus_af_out: 1;
	--focus_af_hit: 0;
	/* 合わせている間の + マーク */
	--focus_ui: 1;
	--focus_mark: 1.35;
}

.focus_item img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* ぼけの段。同じ写真をぼかし量だけ変えて4枚重ねてある(下から 20/10/4/0 px。1920x1080 に対する
   半径)。出したいぼけ量は、それをはさむ隣り合う2段の濃さで作る ―― 離れた段どうしを混ぜると
   二重に見えるので4段用意してある。filter: blur() を毎フレーム動かすと全画面のぼかしを作り直す
   ことになるが、重ねる方は濃さを変えるだけなので描画のやり直しが起きない。 */
.focus_item_photo {
	position: absolute;
	inset: 0;
}

/* いちばん下。ここだけは出しっぱなしで、後ろの地色を隠す役目も持つ */
.focus_item_photo_b20 {
	background-image: url(../img/focus_grain.png), url(../img/focus_nagase_wide_blur20.jpg);
	opacity: 1;
}

.focus_item_photo_b10 {
	background-image: url(../img/focus_grain.png), url(../img/focus_nagase_wide_blur10.jpg);
	opacity: var(--f_b10, 0);
}

.focus_item_photo_b04 {
	background-image: url(../img/focus_grain.png), url(../img/focus_nagase_wide_blur04.jpg);
	opacity: var(--f_b04, 0);
}

.focus_item_photo_clear {
	opacity: var(--f_sharp, 0);
}

/* 粒子。ぼけの段には焼き込まず、192x192 のタイルを段ごとに background として重ねている
   (焼き込むと粒が容量の大半を占める)。段ごとに background-blend-mode で持たせるのは、上に1枚
   かぶせる作りだと段を混ぜている途中だけ暗部が持ち上がるため。difference は地色の明暗によらず
   同じ量の粒を出せる唯一の合成で、引く量を打ち消すためぼけの段3枚は焼くときに +28 明るくしてある
   (タイルの中心も 28)。鮮明な段は img のままで粒も +28 も持たない。 */
.focus_item_photo_b20,
.focus_item_photo_b10,
.focus_item_photo_b04 {
	background-repeat: repeat, no-repeat;
	background-position: 0 0, center;
	background-size: 10% auto, cover;
	background-blend-mode: difference, normal;
}

/* ピントを合わせる位置(画像に対する割合)。1920x1080 のうち x 620〜1340 / y 390〜730 ――
   眉の上から鼻の付け根まで、両目を収めた帯。動きの尺は js 側の FOCUS_AF_* が持つ。 */
.focus_item_nagase {
	/* 左右は 31.25% ずつの均等(幅 37.5% は変えずに、横だけ画面の中央へ)。
	   もとは 左 32.29% / 右 30.21% で、被写体に合わせて中心が 1.04% ぶん右に寄っていた。
	   上下は測った値のまま ―― 縦は被写体の目元の高さに合わせてある。 */
	--focus_inset: 36.11% 31.25% 32.41% 31.25%;
}

/* =========================================================
   グリッド(せり上がってきた時点で見えている3枚)。左の1枚が2行ぶち抜き、右が上下の2枚。
   ---------------------------------------------------------
   sticky の中ではなく、その手前に置いた「1画面ぶんの普通のブロック」。スクロールすると
   そのまま上へ抜け、入れ替わりに次のブロック(.tuneout_lockin_inner = 写真)が上がってくる。
   送りはブラウザのスクロールそのものなので、js も transform もアニメーションも要らない ――
   慣性の止まり際にずれたり、ホイールを止めたあとも動き続けたりしない。
   高さは js の TUNEOUT_GRID_VH(= 1画面)と必ず揃えること。
   ========================================================= */
.focus_grid {
	position: relative;
	z-index: 1;
	width: 100%;
	height: 100vh;
	height: 100lvh;
	display: grid;
	grid-template-columns: 1fr 1fr;
	grid-template-rows: 1fr 1fr;
	overflow: hidden;
	pointer-events: none;
}

.focus_grid_cell {
	position: relative;
	overflow: hidden;
	background: var(--c_black);
}

/* picture は既定でインライン。中の img の height:100% が親の高さを参照できるよう block にする。 */
.focus_grid_cell picture {
	display: block;
	width: 100%;
	height: 100%;
}

.focus_grid_cell img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* 左が2行ぶち抜き、右が上下の2枚(Figma のとおり) */
.focus_grid_bianca {
	grid-area: 1 / 1 / 3 / 2;
}

.focus_grid_elena {
	grid-area: 1 / 2 / 2 / 3;
}

.focus_grid_keita {
	grid-area: 2 / 2 / 3 / 3;
}

/* ピント合わせの表示ひとまとめ。位置と大きさは上の枠。 */
.focus_af {
	position: absolute;
	inset: var(--focus_inset);
	z-index: 1;
	pointer-events: none;
	/* 角を画面の端からあける距離。縦長の画面ではこの枠(= 開口の行き先)が画面より広くなるので、js が
	   --focus_af_edge_l / _r に「はみ出したぶん + この余白」を書き込み、角だけを画面の中へ寄せる
	   (枠そのものは動かさない)。0 にしてあるのは開口が止まる位置と角の位置を合わせるため。スマホ幅は
	   割合(--af_edge_ratio)のほうで寄せる。js は getComputedStyle で読むので px か素の数字で置くこと。 */
	--af_edge_margin: 0px;
	--af_edge_ratio: 0;
}

/* ピントを合わせている範囲を示す角枠。線でつないだ四角ではなく4隅だけで、ローダーの ENTER
   (.loader_af)と同じ作り。ぼけている間は開き、合いに行くほど寄る(--focus_af_out が 1 で目いっぱい
   外、0 で着地)。決まった合図の「ピッ」は --focus_af_hit で、線を太く白くしきる(2度入る)。 */
.focus_af_corner {
	position: absolute;
	width: clamp(11px, 1.2vw, 18px);
	height: clamp(11px, 1.2vw, 18px);
	border-style: solid;
	border-width: calc(1px + var(--focus_af_hit, 0) * 1px);
	border-color: rgba(255, 255, 255, calc(0.7 + var(--focus_af_hit, 0) * 0.3));
	opacity: var(--focus_af, 0);
	/* 寄り引きの幅。ぼけきっているときにこの距離だけ外へ開く。横だけは --focus_af_out_x を先に見る
	   ―― 角を画面の端へ寄せているときは js がこれを 0 にするので、横へは開かない。 */
	transform: translate(
		calc(var(--focus_af_out_x, var(--focus_af_out)) * var(--dx) * 26px),
		calc(var(--focus_af_out) * var(--dy) * 26px)
	);
}

/* 各隅の向き(--dx / --dy は、外側の斜め方向) */
/* 左右は、画面からはみ出したぶんだけ内側へ寄せる(js が書き込む) */
.focus_af_tl {
	top: 0;
	left: var(--focus_af_edge_l, 0px);
	border-right-width: 0;
	border-bottom-width: 0;
	--dx: -1;
	--dy: -1;
}

.focus_af_tr {
	top: 0;
	right: var(--focus_af_edge_r, 0px);
	border-left-width: 0;
	border-bottom-width: 0;
	--dx: 1;
	--dy: -1;
}

.focus_af_bl {
	bottom: 0;
	left: var(--focus_af_edge_l, 0px);
	border-right-width: 0;
	border-top-width: 0;
	--dx: -1;
	--dy: 1;
}

.focus_af_br {
	bottom: 0;
	right: var(--focus_af_edge_r, 0px);
	border-left-width: 0;
	border-top-width: 0;
	--dx: 1;
	--dy: 1;
}

/* 合わせている間の + マーク。「いまここを測っている」ことを示すもので、ピントが決まった瞬間に
   入れ替わりで角枠へ役目を渡して消える(--focus_ui)。ぼけが深いほど少し大きくなる(--focus_mark)。 */
.focus_plus {
	position: absolute;
	left: 50%;
	top: 50%;
	/* 細く大きい十字。線は角枠と同じ細さなので、伸ばしても主張せず照準らしく見える。
	   下限の 30px はスマホで見えている大きさ ―― 画面がこの式より狭い幅では常にこの値。
	   通常幅はそこから 2.2vw で伸ばし、42px で頭打ちにする。 */
	width: clamp(30px, 2.2vw, 42px);
	height: clamp(30px, 2.2vw, 42px);
	opacity: var(--focus_ui, 1);
	transform: translate(-50%, -50%) scale(var(--focus_mark, 1));
}

/* 十字。線2本を疑似要素で引く。大きさは上の枠が持つ。
   濃さは角枠(.focus_af_corner)と同じ式で、決まった合図の「ピッ」(--focus_af_hit)でも
   角と一緒に白くなる。ただし太さは 1px のまま ―― 角枠は短い線なので太ると引き締まって
   見えるが、画面をまたぐ長さの十字で同じことをすると線が主張しすぎるため。 */
.focus_plus::before,
.focus_plus::after {
	content: '';
	position: absolute;
	background: rgba(255, 255, 255, calc(0.7 + var(--focus_af_hit, 0) * 0.3));
}

.focus_plus::before {
	left: 50%;
	top: 0;
	width: 1px;
	height: 100%;
	transform: translateX(-50%);
}

.focus_plus::after {
	top: 50%;
	left: 0;
	height: 1px;
	width: 100%;
	transform: translateY(-50%);
}

/* =========================================================
   tuneout_lockin: 見出しはこのセクションに入って初めて表示される
   (写真がせり上がってくる間は表示しない)。
   ========================================================= */

/* tuneout_lockin_section はスペーサー。中の tuneout_lockin_inner が sticky で画面に固定され続け、
   少し間(ダウェル)を置いてから、フードの開口部にあたる窓が四方から一点へ絞られていく。 */
.tuneout_lockin_section {
	position: relative;
	/* 貼り付いたままの pin_section_inner(30)の上へせり上がってくる側なので、それより手前にする。
	   z-index を指定しないと auto(= 0 相当)になり、pin の裏に隠れて見えなくなる。 */
	z-index: 45;
	/* せり上がりのための引き上げ。.pin_section は末尾に --pin_cover_viewports ぶんの高さを余分に
	   持っていて、その間ずっと pin_section_inner が貼り付いたままになる。同じぶんだけ上へ引き戻すと、
	   このセクションの先頭(固定される前のせり上がり1画面)がその区間とぴったり重なる。引き上げと
	   足し込みは同じ量なので、以降の位置もページ全体の長さも変わらない。 */
	margin-top: calc(var(--pin_cover_viewports) * -100vh);
	margin-top: calc(var(--pin_cover_viewports) * -100lvh);
	/* 高さを変えたら js/main_zone.js の TUNEOUT_SECTION_VH も必ず合わせること
	   (1ビューポート分の高さをここから逆算しているため) */
	/* 内訳(画面高さを1とする)。前後の「間」を増やしたいときはこの高さと js の
	   TUNEOUT_SECTION_VH / TUNEOUT_DWELL_VH を動かす(CLOSE を動かすと降下の速さそのものが変わる)。
		1.0  … グリッドがせり上がってくるぶん(このセクションの負マージンぶん。高さには含まない)
		1.0  … グリッドが普通にスクロールして抜け、写真が上がってくるぶん(.tuneout_grid の高さ)
		2.8  … ピント合わせ(TUNEOUT_DWELL_VH)
		2.38 … 開口が閉じきるまで(TUNEOUT_CLOSE_VH x HOOD_FRACTION)
		1.62 … 像が結ばれて見出しが引くまでと、その後の余白(戻るときの「間」も兼ねる) */
	height: calc((100 + var(--tuneout_hold_vh)) * 1vh);
	height: calc((100 + var(--tuneout_hold_vh)) * 1lvh); /* スマホでURLバーの表示/非表示によって高さが変わらないよう固定する */
}

/* 閉じきる地点の目印(スナップの的)。.pin_scroll_stop と同じ作りで、上からの距離は js が書き込む
   ―― 位置の元になる数字は js 側が持っているため、こちらに書くと二重管理になる。 */
.tuneout_scroll_stop {
	position: absolute;
	left: 0;
	top: 0;
	width: 1px;
	height: 1px;
	scroll-snap-align: start;
	scroll-snap-stop: always;
	pointer-events: none;
}

/* 用が済んだら磁石を外す。残したままだと、このあと 3D を見ていくあいだじゅうこの位置へ
   引き戻されてしまう(.pin_scroll_stop.is_off と同じ理由)。上へ十分戻ると js が付け直す。 */
.tuneout_scroll_stop.is_off {
	scroll-snap-align: none;
}

/* 押さえ込んでいる間だけ掛ける、ブラウザ側の足止め(js が付け外しする)。理由と効き方は
   html.is_pin_hold と同じ。掛けるのは止めている 0.9 秒の間だけ。 */
html.is_tuneout_hold,
html.is_tuneout_hold body,
html.is_tuneout_hold_native,
html.is_tuneout_hold_native body {
	scroll-snap-type: y mandatory;
}

/* is_tuneout_hold_native は iOS(WebKit)用で、付くのは上の mandatory だけ。iOS では js から
   引っ張らない(理由は html.is_pin_hold_native のコメントと js の SCROLL_STOP_MODE を参照)。 */

html.is_tuneout_hold {
	touch-action: pan-x pinch-zoom;
}

/* 動きを控える設定では止めない(.pin_scroll_stop と同じ扱い)。 */
@media (prefers-reduced-motion: reduce) {
	.tuneout_scroll_stop {
		scroll-snap-align: none;
	}
}

.tuneout_lockin_inner {
	position: sticky;
	top: 0;
	height: 100vh;
	height: 100lvh;
	overflow: hidden;
	/* 地色はこの要素に直接持たせず、下の ::before / ::after で描く。2層とも js が毎フレーム書き込む
	   --tuneout_backdrop_clip で「開口の内側だけ残す」形に切り取られるため、外側は素通しになって背後の
	   #section_3d が見える。黒を被せるのではなく地色を削るので、閉じきると地色が無くなり全面 3D になる。 */
	background: transparent;
	/* ---------------------------------------------------------
	   開口(マスク)について。形と大きさは js が持つ ―― 行き先が「写真のピントが合った範囲」
	   (.focus_af)なので、数字ではなく実測から決まる(buildTuneoutMaskClip() が矩形の多角形を
	   --tuneout_backdrop_clip へ書き込む)。輪郭の飾り(縁・にじみ)は持っていない。
	   --------------------------------------------------------- */
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	padding: 0 20px;
	text-align: center;
}

/* 地色の2層。どちらも「開口の内側だけ残す」形に切り取られ、::before(縁の色)を敷いて ::after
   (地色)をひとまわり内側で切り取って重ねた差分が、輪郭に沿った一定の太さの輪になる。js が
   動かないときは clip-path が none になり、2層が画面全体を覆う = 従来どおりの地色一色になる。 */
.tuneout_lockin_inner::after {
	content: '';
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
}

/* 開口の境目は下のにじみ(ブルーム)だけで見せる。中間色の縁の層は、開口の内側が写真になった
   いまは「額縁」として目立つだけなので置いていない。 */
.tuneout_lockin_inner::after {
	background: var(--c_gray_bg);
	clip-path: var(--tuneout_backdrop_clip, none);
}

/* ---------------------------------------------------------
   幕1「雑音が引く」の粒子ノイズ。「フードが外の雑音を切っている」という因果を絵にするため、
   画面全体ではなく地色の2層と同じ --tuneout_backdrop_clip で切り取る(開口が絞られるほど雑音の
   面積そのものが減っていく)。濃さは js が見出しのぼかしと共通の focus から書き込むので、
   ぼかしが澄みきる瞬間とノイズが消えきる瞬間が必ず一致する。
   --------------------------------------------------------- */
.tuneout_noise {
	display: block;
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	/* 地色(ほぼ白)の上に乗せるので multiply で暗い粒だけを残す(screen や normal では埋もれる)。 */
	mix-blend-mode: multiply;
	/* 粒は SVG の feTurbulence で作る。画像を1枚増やさずに済み、拡大しても目が粗くならない。
	   baseFrequency を上げるほど細かい粒になる(0.85 はフィルムのグレインに近い細かさ)。 */
	background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/></filter><rect width='140' height='140' filter='url(%23n)' opacity='0.55'/></svg>");
	background-size: 140px 140px;
	clip-path: var(--tuneout_backdrop_clip, none);
	opacity: var(--tuneout_noise_alpha, 0);
}

/* 雑音が最も強い区間だけ粒を細かく踊らせる(止まっている粒は「汚れ」に見えて雑音として読めない)。
   1コマを 3 段階に留めているのは、なめらかに動かすとグレインではなく霧のように見えるため。 */
@keyframes tuneout_noise_shift {
	0%   { background-position: 0 0; }
	33%  { background-position: -37px 23px; }
	66%  { background-position: 21px -31px; }
	100% { background-position: 0 0; }
}
.tuneout_noise {
	animation: tuneout_noise_shift 0.5s steps(1, end) infinite;
}
/* 動きに敏感な設定では粒を止める(濃さの変化だけは残す) */
@media (prefers-reduced-motion: reduce) {
	.tuneout_noise { animation: none; }
}

/* ---------------------------------------------------------
   視界が狭まる周辺減光(ヴィネット)
   --------------------------------------------------------- */

/* 開口が絞られるのに合わせて濃くなり、同時にわずかに縮むことで「四方から視界が閉じてくる」感覚を
   作る。縮む量はごく控えめにして、濃さ(opacity)の変化に主役を持たせている。画面よりずっと大きく
   作ってあるのは縮んだときでも四隅まで黒が回りきるようにするため(中心は完全に透明のまま)。 */
.tuneout_vignette {
	display: block;
	position: absolute;
	left: 50%;
	top: 50%;
	width: 160vw;
	height: 160vh;
	/* closest-side なので各停止位置は「要素の半分の幅/高さ」に対する割合。透明を 30% までに留めて
	   いるのは、画面の端(要素の半分に対して約 61% の位置)がしっかり減光の範囲に入るようにするため。
	   見出しは中心から画面幅の 24% ほどまでなので、この透明部分の中に収まる。 */
	background: radial-gradient(
		closest-side ellipse at 50% 50%,
		rgba(5, 5, 5, 0) 30%,
		rgba(5, 5, 5, 0.45) 62%,
		rgba(5, 5, 5, 0.95) 100%
	);
	/* js/main_zone.js が opacity と transform の scale を毎フレーム書き換える */
	opacity: 0;
	transform: translate(-50%, -50%) scale(1.15);
	z-index: 1;
	pointer-events: none;
	will-change: opacity, transform;
}

/* 見出しテキストより確実に手前のレイヤーになるよう z-index を明示するラッパー。文字色は白のまま、
   下地との排他的論理和ブレンドで自動的に反転させる(color は子要素に継承される)。 */
.tuneout_caption_text {
	position: relative;
	z-index: 2;
	color: var(--c_white);
	mix-blend-mode: exclusion;
	/* js がフードの進行度に合わせて filter:blur() と transform:scale()(寄り)を毎フレーム書き換える。
	   ぼかしを個々ではなくここ(まとめた親)に掛けているのは、2行を一度に処理できて毎フレームの再描画が
	   1要素ぶんで済むため。filter と mix-blend-mode を同じ要素に指定すると先にぼかしが適用されるので、
	   下地との反転は壊れない。 */
	transform: scale(1);
	will-change: filter, transform, opacity;
}

.tuneout_heading {
	font-family: var(--font_display);
	font-weight: 700;
	font-size: clamp(24px, 4.5vw, 52px);
	/* 字間は js が --tuneout_track に毎フレーム書き込む。絞りはじめは広く、開口が閉じて暗転しきるまでに
	   本来の字間(0.12em)へ詰まっていく。フォールバックを本来の字間にしてあるのは、js が動かないときに
	   広い字間のまま(狭い画面では折り返したまま)残らないようにするため。 */
	letter-spacing: var(--tuneout_track, 0.12em);
	opacity: 0.92;
	/* 幕1の色ずれ。ぼかしと同じ focus で引くので、ピントが合いきると同時に消える。ずらし量が 0 のときは
	   text-shadow ごと消したいので、色ではなく位置に変数を持たせてある。 */
	text-shadow:
		calc(var(--tuneout_split, 0px) * -1) 0 rgba(255, 64, 64, 0.55),
		var(--tuneout_split, 0px) 0 rgba(0, 220, 255, 0.55);
}

.tuneout_subheading {
	margin-top: 12px;
	font-family: var(--font_ui);
	font-weight: 500;
	font-size: clamp(12px, 1vw, 18px);
}

/* =========================================================
   detail
   ========================================================= */

.detail_section {
	background: var(--c_black);
	/* 下は 0。すぐ下に続く .story_stage も黒地で、こちらの1画面ぶんの余白がそのまま
	   セクションの切れ目になるため(ここで足すと黒が二重に空く)。 */
	padding: clamp(48px, 6vw, 100px) var(--side_padding) 0;
	/* tuneout_lockin_section の全域に重ねる。台形の開口の中から 3D を見せるには、台形が動いている間に
	   #section_3d の sticky なキャンバスがすでに固定されている必要があるため(sticky はセクションに
	   入ってからでないと効かない)。重ねたぶんは #section_3d の高さに足し戻してあるのでページ全体の
	   長さは変わらない。重ねる量は tuneout の高さと必ず同じでなければならない(余ると detail が潜り込む)。 */
	margin-top: calc((100 + var(--tuneout_hold_vh)) * -1vh);
	margin-top: calc((100 + var(--tuneout_hold_vh)) * -1lvh);
}

/* 見出しの丸括弧は、そのままだと中の文字に張り付いて窮屈に見えるため内側にだけ余白を入れる。
   CSS には特定の1文字を指す手段がないので、括弧を span で包んでいる。 */
.title_paren_open {
	margin-right: 0.1em;
}

.title_paren_close {
	margin-left: 0.1em;
}

/* products: DEEP FOCUS HOOD の説明に代えて、スクロール連動の 3D(Three.js)を表示する。
   detail_section の左右パディングを突き抜けて画面幅いっぱいにするため、打ち消しの負マージンを入れる。 */
#section_3d {
	position: relative;
	/* 3D のスクロール量。進みの速さを決めているのはこの高さではなく、式の最後にある可動域
	   (--cam_range_vh)。内訳は 100vh(貼り付いている canvas の表示ぶん)+ 引き継ぎ地点までの距離
	   (.detail_section の負マージンで重ねたぶんの足し戻し)+ 可動域。js/3d_zone.js が扱う可動域は
	   「この高さ - 100vh - getHoodOffset()」の実測で、上の式はそれに一致するよう組んである。
	   整列の尺(js の TUNEOUT_RESOLVE_*)を変えたら --cam_start_t も一緒に直すこと ―― 足し戻さないと
	   可動域だけが縮み、ポイントの間隔とカメラの速さが一緒に速くなる。1002vh で間隔は約 2.06画面。 */
	height: calc((100 + var(--tuneout_hold_vh) * var(--cam_start_t)
	              - var(--detail_pad_vh) + var(--cam_range_vh)) * 1vh);
	/* スマホでURLバーの表示/非表示によって高さが変わらないよう固定する */
	height: calc((100 + var(--tuneout_hold_vh) * var(--cam_start_t)
	              - var(--detail_pad_vh) + var(--cam_range_vh)) * 1lvh);
	margin-left: calc(-1 * var(--side_padding));
	margin-right: calc(-1 * var(--side_padding));
}

.canvas_sticky {
	position: sticky;
	top: 0;
	width: 100%;
	height: 100vh;
	height: 100lvh;
	overflow: hidden;
}

/* セクションの終わりで canvas の下端だけを溶かす。canvas は alpha:true で地色を持たないため、
   固定が外れて上へ流れ出すと下端がモデルを横一直線に切りながら上がっていく。帯を重ねる/箱ごと
   不透明度を落とす、ではなくマスクにしているのは、動く別要素が生まれず 3D も消えないため。
   --outro は js/3d_zone.js が入れる(0 のときはマスクが効かない状態になる)。 */
.canvas_sticky {
	-webkit-mask-image: linear-gradient(to top,
		rgba(0, 0, 0, 0) 0%,
		#000 calc(var(--outro, 0) * 22%));
	mask-image: linear-gradient(to top,
		rgba(0, 0, 0, 0) 0%,
		#000 calc(var(--outro, 0) * 22%));
}

#canvas_container {
	position: absolute;
	inset: 0;
	z-index: 1;
}

/* ポイント(注釈)の入れ物。canvas_sticky の外(= #section_3d の直下)に置いてあるので sticky に
   貼り付かず、セクションの高さいっぱいに広がる。z-index は canvas(1)・雨(5)より手前。 */
#labels_container {
	position: absolute;
	inset: 0;
	z-index: 10;
	pointer-events: none;
}

/* ポイント1点ぶんの「持ち場」。sticky が止まっていられるのは自分の箱の中だけなので、
   この箱の高さがそのまま「画面の中央で止まっている距離 = 箱の高さ - ポイントの高さ」を決める。
   top と height は js/3d_zone.js の layoutLabels() が px で書き込む。 */
.hotspot_hold {
	position: absolute;
	left: 0;
	width: 100%;
}

/* ポイント1枚。position:sticky で画面の中央に止める ―― transform でスクロールを打ち消す方式は
   メインスレッドから書くためコンポジタ側のスクロールとフレーム単位で揃わず、止まっているはずの
   区間ほどガタつく。top は js が入れる(高さは書体や折り返しで変わるので実測)。左右の位置は
   margin-left で持つ(sticky では left が「止まる閾値」になって位置指定に使えない)。 */
.hotspot_label {
	position: sticky;
	top: 0;
	/* タイトルと本文のひとまとまり全体でモーダルを開けるようにする(js が data-modal-open を付ける)。
	   出入りで薄いあいだ押せないようにするのは @keyframes point_travel 側。ここが auto なのは、
	   スクロール駆動アニメーション非対応(sticky で動く)ブラウザではポイントが薄くならないため。 */
	pointer-events: auto;
	cursor: pointer;
	width: min(720px, 92vw);
	text-align: center;
}

/* =========================================================
   ポイントの動き(スクロール駆動アニメーション)
   ---------------------------------------------------------
   sticky だけでは「下から出て上へ抜ける」速さが 1倍にしかならず、transform で打ち消すと
   メインスレッドから毎フレーム書くことになってガタつく。そこで同じ計算をブラウザの合成側に
   任せる。時間軸は「持ち場の箱が画面を通り過ぎる間」(view() の cover 範囲)で、箱の高さ・位置と
   --pt_delta(1点に使うスクロール距離)/ --pt_cross(実際に動く距離)/ --pt_shift は
   js/3d_zone.js の layoutLabels() が入れる。
   区間は 0〜39% が下から中央へ、39〜61% が静止、61〜100% が中央から上へ。濃さは 0→18% で現れ
   82→100% で消える。もっと遅くしたいときは #section_3d の height を伸ばすか js の LABEL_TRAVEL を
   下げる。止まる割合を変えるときは下の 39% / 61%(差の 0.22 が止まっている割合)。
   ========================================================= */
@keyframes point_travel {
	0% {
		opacity: 0;
		/* 薄いあいだはクリックの的にしない。pointer-events は段階のないプロパティなので、キーフレームの
		   中間点(0→18% なら 9%)で切り替わる ―― つまり半分ほど見えたところから押せるようになる。 */
		pointer-events: none;
		transform: translateY(calc(var(--pt_shift) * -1));
	}
	18% {
		opacity: 1;
		pointer-events: auto;
	}
	39% {
		transform: translateY(
			calc(var(--pt_delta) * 0.39 - var(--pt_cross) * 0.5 - var(--pt_shift))
		);
	}
	61% {
		transform: translateY(
			calc(var(--pt_delta) * 0.61 - var(--pt_cross) * 0.5 - var(--pt_shift))
		);
	}
	82% {
		opacity: 1;
		pointer-events: auto;
	}
	100% {
		opacity: 0;
		pointer-events: none;
		transform: translateY(
			calc(var(--pt_delta) - var(--pt_cross) - var(--pt_shift))
		);
	}
}

/* 対応していないブラウザではこのブロックが丸ごと無効になり、上の sticky のまま動く。その場合は
   横切る速さが 1倍に戻り、代わりに中央で長く止まる(js 側も同じ判定で箱の高さを切り替える)。 */
@supports (animation-timeline: view()) {
	.hotspot_hold {
		view-timeline-name: --point_view;
		view-timeline-axis: block;
	}

	.hotspot_label {
		/* sticky はやめて、箱の中の通常の位置に置く */
		position: static;
		animation-name: point_travel;
		animation-timing-function: linear;
		animation-fill-mode: both;
		/* スクロール駆動では長さは時間ではなく範囲で決まる */
		animation-duration: auto;
		animation-timeline: --point_view;
		animation-range: cover;
	}
}

.label_title {
	font-family: var(--font_display);
	font-weight: 500;
	color: var(--c_white);
	font-size: clamp(20px, 6.25vw, 120px);
	/* 英字はページ内で 0.06em に揃えている */
	letter-spacing: 0.06em;
	margin: 0 0 20px;
	line-height: 1.1;
}

/* 本文の箱と(+)ボタンを横に並べる入れ物。この2つの間で改行させないため nowrap にしてあるが、
   本文そのものは折り返してほしいので .label_desc_wrap で normal に戻す。 */
.label_foot {
	white-space: nowrap;
}

.label_desc_wrap {
	display: inline-block;
	max-width: 640px;
	white-space: normal;
}

.label_desc {
	display: block;
	font-family: var(--font_jp);
	font-size: clamp(10px, 1.04vw, 20px);
	color: #fff;
	/* 行間。字が小さいので広めに取る */
	line-height: 2.6;
	letter-spacing: 0.08em;
}

/* ポイントの文字は1行ずつ span.label_line に包んである(js の wrapLabelLines)。inline-block に
   しているのは、行が折り返したときの扱いをブラウザ間で揃えるため(inline のままだと割れる)。 */
.label_line {
	display: inline-block;
	/* inline-block の既定(baseline)だと、折り返しが起きたときに「最後の行の下端」で高さを揃えに
	   いって上の行に食い込む。top にしておけば行の高さがそのぶん増えるだけで済む。 */
	vertical-align: top;
}

/* 文字の影。地色(黒)との境目がわかる程度で十分 ―― モデルの明るい部分に文字が重なったときの
   可読性のためだけに置いている。 */
.label_title .label_line {
	text-shadow: 0 3px 18px rgba(0, 0, 0, 0.32);
}

/* スマホ幅だけで効かせる改行。タイトル・本文は js 側で1つの文字列として組んでいるため、幅ごとに
   文字列を作り分ける代わりに <br> を display で出し入れして改行の有無を切り替える。 */
.label_br_sp,
.br_sp {
	display: none;
}

/* モーダルを開く(+)ボタン。本文のブロックの右外に並べる ―― 最後の行の文字尾に付けると、行の
   長さが行ごとに違うぶんボタンの位置がポイントごとにばらついて見えるため。inline-flex にしている
   のは、本文の箱と同じ行に乗せながら中の「+」を中央に置くため(block だと次の行に落ちる)。
   見た目はモーダルの閉じるボタンと揃えてあり、大きさは 1920 幅で 44px(Figma の 30px は小さすぎた)。 */
.label_more {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: clamp(32px, 2.3vw, 44px);
	height: clamp(32px, 2.3vw, 44px);
	/* 本文の箱との間隔。ボタン自身の大きさに合わせて詰まるよう vw で持つ */
	margin: 0 0 0 clamp(8px, 0.7vw, 14px);
	border: 1px solid var(--c_white);
	border-radius: 50%;
	background: none;
	cursor: pointer;
	/* 縦は本文の箱の下端に揃える。middle だと「行の中心」が基準になるため、本文が複数行あるときに
	   ボタンだけが中途半端な高さに浮く。 */
	vertical-align: bottom;
	/* 当たり判定はラベルから継承する。ここに auto を書くと、ラベルが薄くて押せないはずのときでも
	   ボタンだけが押せてしまう(pointer-events は祖先が none でも子が auto なら子は当たる)。 */
	transition: background 0.25s, transform 0.25s;
	padding: 0;
}

.label_more img {
	display: block;
	width: 33.333%; /* Figma の 10 / 30 と同じ比 */
	height: auto;
	pointer-events: none;
	/* 塗りの変化と同じ速さで色が反転するように */
	transition: filter 0.25s;
}

/* ホバーの反応はボタン単体ではなくテキスト一式(.hotspot_label)に乗ったときに出す。押せる範囲が
   テキスト全体なので、ボタンの上だけで反応すると「押せるのはボタンだけ」と誤解させる。 */
.hotspot_label:hover .label_more {
	background: #fff;
	transform: rotate(90deg);
}

/* ホバー中は「+」を黒に。中身は白い線の SVG を img で置いていて色を直接は変えられないので、
   invert で白を黒へ反転させる(透明な部分は alpha を触らないのでそのまま残る)。 */
.hotspot_label:hover .label_more img {
	filter: invert(1);
}

/* モーダル(フード詳細) */
/* =========================================================
   3Dポイントのモーダル(Figma「20260904_PC」準拠。1920x1080 に対して板 1120x840、角丸 20px、
   地色 rgba(51,51,51,0.9) + backdrop-filter: blur(15px))。
   上下の余白が 120px ずつで等しいので縦は中央、左右は等しくないため右端からの余白(6.667%)を
   固定して左へ伸ばす。大きさは --pm_w(板の幅)ひとつで決まり、中の図版も文字もすべてこの幅に
   対する割合。文字を vw ではなく --pm_w から出しているのが要点で、横長で背の低い画面でも
   板と文字の比が崩れない。
   ========================================================= */

/* 開閉の組み立て(「枠を描いてから中身が満ちる」)。
	開く   0.00s 枠線(0.6s)/ 0.50s 地色とぼかし / 0.70s 閉じるボタン / 0.78s 図版 / 0.86s 本文
	閉じる 0.00s 中身 / 0.10s 地色とぼかし / 0.25s 枠線   …0.6s で見えなくなる
   順番はすべて transition-delay で作ってあるので js にタイマーは無い。閉じているあいだは
   visibility: hidden ―― opacity: 0 だけでは backdrop-filter の合成が走り続けるおそれがあり、
   板は4枚あって大きいため見えていないあいだは描画対象から外す。 */
.modal_overlay {
	/* 板の幅。1920 幅なら 58.333vw = 1120px。縦が足りない画面では縦横比を保ったまま高さ 84vh で
	   頭打ちにする。板・閉じるボタン・文字の大きさはすべてこの1つから決まる。 */
	--pm_w: min(58.333vw, calc(84vh * 1120 / 840));
	/* 閉じるボタンの直径。Figma は 30px(角丸16px = 実質は円)だが小さすぎたので 44px 相当まで
	   上げてある(44 / 1120)。狭い画面でも押せる大きさを保つため下限を置く。 */
	--pm_btn: max(34px, calc(var(--pm_w) * 0.0392857));
	/* 板の地色。地色そのものは薄めにして、板の中の暗さは backdrop-filter のぼかしに任せる ――
	   濃くすると背後の 3D が完全に隠れて「別の画面が出た」になり、板の向こうにモデルが在る関係が切れる。 */
	--pm_face: rgba(51, 51, 51, 0.6);

	position: fixed;
	inset: 0;
	/* 共通ヘッダー(.site_header = 9000)より手前に置く。閉じるボタンは板の右上にあり、横に広く
	   縦の低い画面ではヘッダーの帯(PC 128px / スマホ 80px)に入る。このページは body.page_top で
	   帯が透明なので見た目には何も無いが、出ているあいだ(.is_visible)は当たり判定を持つため、
	   スクロールの向きでヘッダーが出た状態だけ閉じるボタンが押せなくなっていた。 */
	z-index: 9500;
	/* 地色は敷かない(透明)。板の外は 3D がそのまま見えたままで、背後を落とすのは板自身の
	   backdrop-filter だけ。透明でも画面全体を覆っているので、板の外を押して閉じる動作は効く。 */
	background: none;
	visibility: hidden;
	pointer-events: none;
	transition: visibility 0s linear 0.6s;
	/* 板の中の文字の基準。板が 1120px のとき 18px(18 / 1120 = 0.0160714) */
	font-size: max(11px, calc(var(--pm_w) * 0.0160714));
}

.modal_overlay.is_open {
	visibility: visible;
	pointer-events: auto;
	transition: visibility 0s linear 0s;
}

/* 板と同じ位置・大きさの箱(透明)。中の図版と本文はこの箱に対する割合で置いてある。板の外を
   押して閉じられるよう、箱自体は当たり判定を持たない。画面の中央に置く(Figma は右寄せだが、
   あれは板の左にポイントの文字が見えている前提の構図だった)。 */
.pm_stage {
	position: absolute;
	left: 50%;
	top: 50%;
	width: var(--pm_w);
	aspect-ratio: 1120 / 840;
	transform: translate(-50%, -50%);
	pointer-events: none;
}

/* 板の枠線。stroke-dashoffset を「周長 → 0」と動かすと一周描かれる。周長は js の
   layoutModalFrame() が getTotalLength() で実測して --pm_frame_len に入れる(pathLength 属性は
   <rect> での扱いに環境差があるため使わない)。viewBox と rect の寸法も同じ関数が板の実寸から
   入れるので、rx=20 が板の border-radius と一致し、縦横比が変わっても角が歪まない。 */
.pm_frame {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	overflow: visible;
	pointer-events: none;
}

.pm_frame_line {
	fill: none;
	/* 白。地色が満ちたあとも板の縁に細い輪郭として残る(板と同じ --pm_face だと暗すぎた)。 */
	stroke: var(--c_white);
	stroke-width: 1;
	/* 既定値は js が動かなかったときの控え(枠が出たままになるより無害) */
	stroke-dasharray: var(--pm_frame_len, 4000);
	stroke-dashoffset: var(--pm_frame_len, 4000);
	/* 閉じるとき: 中身と地色が引いたあとに戻る */
	transition: stroke-dashoffset 0.35s ease 0.25s;
}

.modal_overlay.is_open .pm_frame_line {
	stroke-dashoffset: 0;
	/* 開くとき: いちばん最初。終わりぎわで静かに詰まる */
	transition: stroke-dashoffset 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}

.modal_content {
	position: absolute;
	inset: 0;

	/* 閉じている状態 = 地色もぼかしも無し。枠だけが描かれる段階の見え方 */
	background: rgba(51, 51, 51, 0);
	backdrop-filter: blur(0px);
	-webkit-backdrop-filter: blur(0px);
	border: none;
	border-radius: 20px;
	/* 板を浮かせる影。地色が薄いので影も濃くすると板だけが強く前へ出て見える。
	   輪郭がわずかに持ち上がる程度に留める。 */
	box-shadow: 15px 15px 5px 0 rgba(0, 0, 0, 0.12);
	padding: 0;
	max-width: none;

	/* 当たり判定は開いているあいだだけ持つ。pointer-events は祖先が none でも子が auto なら子が
	   当たるので、ここに auto を書いたままにすると閉じていて見えていない板がクリックを奪う。 */
	pointer-events: none;
	transition: background 0.2s ease 0.1s,
	            backdrop-filter 0.2s ease 0.1s,
	            -webkit-backdrop-filter 0.2s ease 0.1s;
}

.modal_overlay.is_open .modal_content {
	background: var(--pm_face);
	backdrop-filter: blur(15px);
	-webkit-backdrop-filter: blur(15px);
	pointer-events: auto;
	/* 枠が描き終わるころに満ちる */
	transition: background 0.25s ease 0.5s,
	            backdrop-filter 0.25s ease 0.5s,
	            -webkit-backdrop-filter 0.25s ease 0.5s;
}

/* 中身は地色が満ちたあと、閉じるボタン → 図版 → 本文の順に少しだけ下から上がってくる。
   持ち上がりを transition ではなくキーフレーム(pm_rise)で作っているのは、transition の行き帰りだと
   閉じるときに transform を戻す瞬間が必ず見えて 8px ぶんガクッと動くため。キーフレームなら
   閉じるときはアニメーションが外れるだけで、戻す動きがそもそも存在しない。 */
@keyframes pm_rise {
	from {
		transform: translateY(8px);
	}
	to {
		transform: none;
	}
}

.modal_figure,
.modal_desc {
	opacity: 0;
	/* 閉じるときは濃さだけが引く */
	transition: opacity 0.15s ease;
}

.modal_overlay.is_open .modal_figure {
	opacity: 1;
	transition: opacity 0.28s ease 0.78s;
	animation: pm_rise 0.28s ease 0.78s both;
}

.modal_overlay.is_open .modal_desc {
	opacity: 1;
	transition: opacity 0.28s ease 0.86s;
	animation: pm_rise 0.28s ease 0.86s both;
}

/* 閉じるボタン。Figma では白1pxの枠に角丸16px、中は 10px の横線1本(「+」ではなく「−」)。
   板の右上、内側に置く。 */
.modal_close {
	position: absolute;
	/* Figma では 30px の枠が右から 42px・上から 41px(中心は右 57 / 上 56)。大きくしたぶん
	   中心を保つよう、中心位置から半径を引いて置く。 */
	right: calc(5.089% - var(--pm_btn) / 2);  /* 57 / 1120 */
	top: calc(6.667% - var(--pm_btn) / 2);    /* 56 / 840 */
	bottom: auto;
	display: flex;
	align-items: center;
	justify-content: center;
	/* 開くボタンと同じ大きさ。Figma は 30px だが小さすぎたので上げてある */
	width: var(--pm_btn);
	height: var(--pm_btn);
	padding: 0;
	border: 1px solid var(--c_white);
	/* Figma の角丸 16px は直径 30px に対して半径以上 = 円 */
	border-radius: 50%;
	background: none;
	cursor: pointer;
	z-index: 3;
	/* 当たり判定は板(.modal_content)から継承する。閉じているあいだは
	   板が none なので、ここで auto を書くと同じ罠を踏む */
}

.modal_close img {
	display: block;
	width: 33.333%; /* 10 / 30 */
	height: auto;
	/* クリックの判定は js が e.target のクラスで見ている(closeAllModals の委譲)。この img が的に
	   なると判定から外れて閉じられないため、当たり判定はボタン自身に通す。 */
	pointer-events: none;
}

.modal_close:hover {
	border-color: #9a9a9a;
}

.modal_close {
	transition: rotate 0.45s cubic-bezier(0.22, 1, 0.36, 1), border-color 0.2s ease;
}

/* 閉じるボタンも中身と同じ段組みで出すが、こちらは濃さだけを動かす ―― 板の右上に固定で置く
   ものなので、8px の持ち上がりを付けると出入りのたびに位置がずれて目につく。ホバーの回転と
   枠色はそのまま効かせたいので、同じ transition の並びに足している。 */
.modal_close {
	opacity: 0;
	transition: rotate 0.45s cubic-bezier(0.22, 1, 0.36, 1),
	            border-color 0.2s ease,
	            opacity 0.15s ease;
}

.modal_overlay.is_open .modal_close {
	opacity: 1;
	transition: rotate 0.45s cubic-bezier(0.22, 1, 0.36, 1),
	            border-color 0.2s ease,
	            opacity 0.28s ease 0.7s;
}

/* 動きを控える設定では段組みをやめ、全部いっしょに出す。 */
@media (prefers-reduced-motion: reduce) {
	.pm_frame_line,
	.modal_overlay.is_open .pm_frame_line {
		transition: none;
		stroke-dashoffset: 0;
	}

	.modal_content,
	.modal_overlay.is_open .modal_content,
	.modal_close,
	.modal_overlay.is_open .modal_close,
	.modal_figure,
	.modal_overlay.is_open .modal_figure,
	.modal_desc,
	.modal_overlay.is_open .modal_desc {
		transition-duration: 0.15s;
		transition-delay: 0s;
		/* 持ち上がりもやめる */
		animation: none;
	}

	.modal_overlay {
		transition-delay: 0.15s;
	}
}

.modal_close:hover {
	rotate: 180deg;
}

/* 本文。位置はポイントごとに違うので、共通はここ、上下左右は下の #modal_* 側で持つ。 */
.modal_desc {
	position: absolute;
	width: 58.75%; /* 658 / 1120 */
	margin: 0;
	font-family: var(--font_jp);
	/* 板の外の文字(ポイントの本文 .label_desc など)と同じ太さ。板の中だけ太いと
	   同じ本文なのに別の書体に見える。 */
	font-weight: 400;
	/* 大きさは板の幅から(.modal_overlay の 1em = 18 / 1120)。ポイントの本文と同じ式に
	   したこともあるが、字が大きくなって行が増え、板の中の構図が崩れたため戻してある。
	   スマホ幅だけは下の @media でポイントと同じ大きさにしている。 */
	font-size: 1em;
	line-height: 2.5;
	letter-spacing: 0.04em; /* 0.72 / 18 */
	color: var(--c_white);
}

/* 本文中の数字。Figma では欧文書体に切り替わっている(太さは本文と揃える) */
.pm_num {
	font-family: var(--font_ui);
	font-weight: 400;
}

/* 通常幅だけさらに細くする。板が大きく出るぶん 400 でも字面が重く見えるため。
   スマホは字が小さく、これ以上細くすると読みにくくなるので 400 のまま。 */
@media (min-width: 1025px) {
	.modal_desc,
	.pm_num {
		font-weight: 300;
	}
}

/* 図版の入れ物。板いっぱいに広げ、中身はこれに対する % で置く */
.modal_figure {
	position: absolute;
	inset: 0;
	pointer-events: none;
}

.modal_figure > span,
.pm_g > span {
	position: absolute;
	display: block;
}

/* 図版のまとまり。本文を挟んで上下に分かれるので、上の組と下の組をそれぞれ一つの箱にまとめてある。
   箱は図版と同じ大きさ・同じ比なので中の span は Figma の % をそのまま使える。通常幅では素通しの
   箱で、スマホだけこの箱の transform で組ごとに拡大と寄せをしている(下の @media を参照)。 */
.pm_g {
	left: 0;
	top: 0;
	width: 100%;
	aspect-ratio: 1120 / 840;
}

.modal_figure img {
	display: block;
	width: 100%;
	height: 100%;
}

/* 1040x341 の3枚(p1_hood / p2_wave / p2_fabric)は、1枚の絵から別々の場所を切り出して使う
   共通素材。入れ物で切って中の img をずらす(Figma の指定をそのまま持ってきている)。 */
.pm_hood,
.pm_wave_out,
.pm_wave_in,
.pm_fabric,
.pm_zone,
.pm_cloth {
	overflow: hidden;
}

.pm_hood img,
.pm_wave_out img,
.pm_wave_in img,
.pm_fabric img,
.pm_zone img,
.pm_cloth img {
	position: absolute;
	max-width: none;
}

/* --- 01 DEEP FOCUS HOOD --- */
#modal_hood .modal_desc {
	left: 22.232%;
	top: 43.571%;
}

.figure_hood .pm_ring {
	left: 39.196%;
	top: 9.881%;
	width: 21.429%;
	aspect-ratio: 1;
}

.figure_hood .pm_hood {
	left: 40.982%;
	top: 16.071%;
	width: 19.643%;
	height: 16.786%;
}

.figure_hood .pm_hood img {
	left: -96.08%;
	top: -0.06%;
	width: 196.08%;
	height: 100.12%;
}

.figure_hood .pm_gaze {
	left: 34.821%;
	top: 18.81%;
	width: 11.429%;
	height: 9.881%;
}

.figure_hood .pm_zone {
	left: 36.518%;
	top: 62.738%;
	width: 26.786%;
	height: 26.786%;
}

.figure_hood .pm_zone img {
	left: -17.36%;
	top: 0;
	width: 133.12%;
	height: 100%;
}

/* --- 02 NOISELESS FABRIC --- */
#modal_fabric .modal_desc {
	left: 22.232%;
	top: 47.143%;
}

.figure_fabric .pm_ring {
	left: 53.839%;
	top: 10.952%;
	width: 19.643%;
	aspect-ratio: 1;
}

/* 騒音の波。同じ絵の別の場所を2つ切り出して、外側(60dB)と内側(40dB)に使う
   (Figma では左右反転して置かれている)。 */
.figure_fabric .pm_wave_out,
.figure_fabric .pm_wave_in {
	transform: scaleX(-1);
}

.figure_fabric .pm_wave_out {
	left: 30.268%;
	top: 14.048%;
	width: 14.286%;
	height: 20%;
}

.figure_fabric .pm_wave_out img {
	left: -26.95%;
	top: -0.03%;
	width: 319.76%;
	height: 100.05%;
}

.figure_fabric .pm_wave_in {
	left: 56.875%;
	top: 14.524%;
	width: 13.661%;
	height: 20%;
}

.figure_fabric .pm_wave_in img {
	left: -176.73%;
	top: -0.03%;
	width: 335.85%;
	height: 100.05%;
}

.figure_fabric .pm_db {
	top: 38.571%;
	font-family: var(--font_ui);
	font-weight: 400;
	font-size: calc(var(--pm_w) * 0.0178571); /* 20 / 1120 */
	line-height: 1;
	letter-spacing: 0.06em;
	color: var(--c_white);
	white-space: nowrap;
}

.figure_fabric .pm_db_out {
	left: 35%;
}

.figure_fabric .pm_db_in {
	left: 61.25%;
}

/* 生地の断面を挟む2本の破線。下側は上下反転 */
.figure_fabric .pm_seam {
	left: 35.893%;
	width: 30.536%;
	height: 3.571%;
}

.figure_fabric .pm_seam_top {
	top: 73.333%;
}

.figure_fabric .pm_seam_bottom {
	top: 81.786%;
	transform: scaleY(-1);
}

.figure_fabric .pm_fabric {
	left: 40.982%;
	top: 68.929%;
	width: 17.857%;
	height: 20.476%;
}

.figure_fabric .pm_fabric img {
	left: -80.3%;
	top: 0;
	width: 262.63%;
	height: 100%;
}

/* --- 03 ADAPTIVE MOBILITY --- */
#modal_mobility .modal_desc {
	left: 22.232%;
	top: 47.143%;
}

.figure_mobility .pm_zoom {
	left: 40.982%;
	top: 15.357%;
	width: 17.857%;
	aspect-ratio: 1;
	border: 1px solid var(--c_white);
}

.figure_mobility .pm_zoom img {
	object-fit: cover;
}

.figure_mobility .pm_icon {
	top: 70.595%;
	width: 11.229%;
	aspect-ratio: 1;
}

.figure_mobility .pm_icon_stretch {
	left: 37.232%;
}

.figure_mobility .pm_icon_uv {
	left: 51.339%;
}

/* --- 04 PRECISION 3-LAYER FABRIC --- */
#modal_layer .modal_desc {
	left: 20.536%;
	top: 70.833%;
}

/* 撥水 / 耐水 / 防風 の3つの丸 */
.figure_layer .pm_specs {
	left: 29.643%;
	top: 18.929%;
	width: 40.536%;
	display: flex;
	gap: 2.857%; /* 32 / 1120 */
}

.figure_layer .pm_spec {
	position: relative;
	display: block;
	flex: 1 1 0;
	aspect-ratio: 1;
}

.figure_layer .pm_spec_label {
	position: absolute;
	left: 50%;
	top: 50%;
	transform: translate(-50%, -50%);
	font-family: var(--font_jp);
	font-weight: 500;
	font-size: 1em;
	line-height: 1;
	letter-spacing: 0.04em;
	color: var(--c_white);
	white-space: nowrap;
}

.figure_layer .pm_cloth {
	left: 31.518%;
	top: 45.238%;
	width: 17.857%;
	height: 15.974%;
	transform: scaleX(-1);
}

.figure_layer .pm_cloth img {
	left: 0;
	top: -24.16%;
	width: 100%;
	height: 148.96%;
}

/* 画像(point_p4_hassui.jpg)は Figma の切り取りどおりに書き出した正方形。
   入れ物いっぱいに敷くだけでよい(.modal_figure img の width/height:100%) */
.figure_layer .pm_hassui {
	left: 55%;
	top: 44.286%;
	width: 13.393%;
	aspect-ratio: 1;
}

/* スマホ。Figma は PC のみなので、板を画面幅いっぱいに寄せ、図版と本文を縦に積み替える。図版の
   中の位置はすべて図版自身に対する % なので、箱に Figma と同じ縦横比を持たせれば配置はそのまま縮む。 */
@media (max-width: 1024px) {
	/* スマホ用のキーフレーム。位置は動かさず、濃さだけを変える ―― スマホは「動かさない」ので
	   打ち消しの量とスクロール量が完全に一致していなければならず、わずかな誤差がそのまま位置の
	   ずれになって小刻みに震えて見える。そこで transform を使わず、位置は下の position:fixed で固定する。 */
	@keyframes point_fade {
		0% {
			opacity: 0;
			pointer-events: none;
		}
		18% {
			opacity: 1;
			pointer-events: auto;
		}
		82% {
			opacity: 1;
			pointer-events: auto;
		}
		100% {
			opacity: 0;
			pointer-events: none;
		}
	}

	/* ポイントは画面の下側に固定して、濃さだけで出入りさせる(通常幅とは作りごと分けてある)。
	   position:fixed の基準は画面だが、持ち場の箱はセクションの中に置いたままなので、いつ出るかは
	   通常幅と同じ仕組みで決まる。出ていないあいだは濃さ 0 かつ当たり判定なし。 */
	@supports (animation-timeline: view()) {
		.hotspot_label {
			position: fixed;
			left: 0;
			right: 0;
			/* 画面の上端から数えて置く。bottom の % はビューポートの高さ基準なので、URLバーの出入りで基準
			   そのものが変わって位置がずれる。lvh は出入りで変わらない固定の長さなので、上端から数えれば
			   位置は動かない。88lvh は 3D の箱(100lvh)の下から 12lvh の位置。 */
			top: 88vh;
			top: 88lvh;
			bottom: auto;
			transform: translateY(-100%);
			animation-name: point_fade;
		}
	}

	/* 開閉の段組みを短くする(通常幅の約6割 ―― 開く 約0.82s / 閉じる 0.35s)。
	   指で開け閉めする場面では、通常幅の間合いだと待たされる感じになる。 */
	.modal_overlay {
		transition: visibility 0s linear 0.35s;
	}

	.pm_frame_line {
		transition: stroke-dashoffset 0.2s ease 0.15s;
	}

	.modal_overlay.is_open .pm_frame_line {
		transition: stroke-dashoffset 0.35s cubic-bezier(0.16, 1, 0.3, 1);
	}

	.modal_overlay.is_open .modal_close {
		transition: rotate 0.45s cubic-bezier(0.22, 1, 0.36, 1),
		            border-color 0.2s ease,
		            opacity 0.2s ease 0.42s;
	}

	.modal_overlay.is_open .modal_figure {
		transition: opacity 0.2s ease 0.48s;
		animation: pm_rise 0.2s ease 0.48s both;
	}

	.modal_overlay.is_open .modal_desc {
		transition: opacity 0.2s ease 0.54s;
		animation: pm_rise 0.2s ease 0.54s both;
	}

	/* (+)ボタンは本文の下、中央に置く。通常幅では本文の箱の右外に横並びにしているが、スマホは
	   本文の幅が画面いっぱいで横に余地が無い。改行を止めていた指定も外す。 */
	.label_foot {
		white-space: normal;
	}

	.label_more {
		display: flex;
		/* 上の本文は行間 2.6 で、最後の行の下に 0.8em ぶんの余りが付く。そのぶんを見込んで
		   詰めておかないと、本文とボタンのあいだだけが開いて見える。 */
		/* 上下の間隔は下の「見た目で揃える」ほうで置く */
		margin: 0 auto;
	}

	.pm_stage {
		/* 板の幅。上限を置いてあるのは、この @media がタブレット幅(1024px)まで効くため ―― 92vw の
		   ままだと板が 940px ほどになり、中の図版も本文もそのまま巨大になる。 */
		--pm_w: min(92vw, 520px);
		left: 50%;
		right: auto;
		width: var(--pm_w);
		aspect-ratio: auto;
		height: auto;
		margin-top: 0;
		top: 50%;
		transform: translate(-50%, -50%);
		/* font-size はここでは持たない。板の幅から出すと 5〜7px にしかならないためで、この幅では
		   本文も図版の中の文字もそれぞれ自分の指定を持っている(1em を使う側がいない)。 */
	}

	.modal_content {
		/* 中身の高さで伸びる箱にする(図版と本文を縦に積む) */
		position: relative;
		inset: auto;
		max-height: 86vh;
		overflow-y: auto;
		/* 端まで流したあと、ページ側のスクロールへ繋がらないようにする */
		overscroll-behavior: contain;
		/* 板の内側の余白。上は閉じるボタン(34px + 12px)を避ける高さから始める。左右は本文の margin が持つ。 */
		padding: clamp(52px, 14vw, 76px) 0 clamp(36px, 10vw, 56px);
		/* 板ごとずらす指定は持たない。枠線が一周してから地色が満ちる出しかたなので板の位置は枠が決め、
		   ずらす必要がない(通常幅の .modal_content も同じ理由で transform を持たない)。 */
	}

	/* 図版。Figma の板は PC 用の横長の構図で、上の組と下の組の間に本文が入る前提の空きがある。
	   スマホは本文を下へ送るのでその空きがそのまま余白として残るため、この箱を「見えている高さ」だけの
	   入れ物に変え(枚ごとの aspect-ratio)、中の2つの組は下の transform で拡大して詰めている。
	   中の span の % は .pm_g(1120x840 のまま)に対して効くので、この箱を低くしても図版は潰れない。 */
	.modal_figure {
		position: relative;
		inset: auto;
		width: 100%;
		/* 拡大した組の箱は板の外まで伸びるので、ここで切る
		   (切らないと板に横スクロールバーが出る) */
		overflow: hidden;
		/* 図版と本文の間 */
		margin-bottom: clamp(28px, 8vw, 44px);
	}

	/* 組の拡大。倍率は「横に広いほうの組が板幅の約 70% になる」ように枚ごとに決めてある(図版の
	   元の大きさが枚ごとに違うため)。translateY は .pm_g の高さ(= 板幅 x 0.75)に対する割合。 */
	/* 01 と 03 は他の2枚より倍率をかなり低くしてある。02 と 04 の上の組は離れて並ぶので横に広げても
	   一つの塊には見えないが、01 の丸フードと 03 の生地は塗りの詰まった一枚で、同じ幅にすると重すぎる。
	   幅ではなく図版の高さを 02 / 04 と揃える形にしてある。 */
	#modal_hood .modal_figure {
		aspect-ratio: 1120 / 764;
	}

	#modal_hood .pm_g_top {
		transform-origin: 47.723% 24.167%;
		transform: translateY(-3.452%) scale(1.45);
	}

	#modal_hood .pm_g_bottom {
		transform-origin: 49.911% 76.131%;
		transform: translateY(-4.568%) scale(1.45);
	}

	#modal_fabric .modal_figure {
		aspect-ratio: 1120 / 777;
	}

	#modal_fabric .pm_g_top {
		transform-origin: 51.875% 25.952%;
		transform: translateY(-1.655%) scale(1.62);
	}

	#modal_fabric .pm_g_bottom {
		transform-origin: 51.161% 79.167%;
		transform: translateY(-3.274%) scale(1.62);
	}

	/* 03 も上と同じ理由(生地は正方形の一枚絵)。 */
	#modal_mobility .modal_figure {
		aspect-ratio: 1120 / 693;
	}

	/* 03 だけは組を transform: scale() ではなく .pm_g 自身の幅で大きくする。中の位置も大きさも
	   すべて .pm_g に対する % なので見え方は scale(1.85) と同じになるが、生地アップの枠線
	   (.pm_zoom の 1px)だけは拡大されずに 1px のまま残る(scale だと 1.85px に太る)。
	   left / margin-top は scale(1.85) 後の位置をそのまま置き換えた値。縦のずらしに top では
	   なく margin-top を使うのが要 ―― margin の % は「入れ物の幅」基準なので、図版の縦横比
	   (この板は 1120/693)が変わってもずれない(top の % は高さ基準で合わなくなる)。
	   倍率を変えるときは 3つとも直すこと: width = 100 x 倍率、
	   left = -(倍率 - 1) x 原点X、margin-top = -((倍率 - 1) x 原点Y x 0.75 + ずらし量 x 0.75)。 */
	#modal_mobility .pm_g_top {
		left: -42.4244%;
		margin-top: -21.308%;
		width: 185%;
	}

	#modal_mobility .pm_g_bottom {
		left: -42.415%;
		margin-top: -56.8804%;
		width: 185%;
	}

	#modal_layer .modal_figure {
		aspect-ratio: 1120 / 596;
	}

	#modal_layer .pm_g_top {
		transform-origin: 49.911% 27.423%;
		transform: translateY(-12.726%) scale(1.73);
	}

	#modal_layer .pm_g_bottom {
		transform-origin: 49.955% 53.214%;
		transform: translateY(2.339%) scale(1.73);
	}

	/* 図版の中の文字は組といっしょに拡大される。Figma の比のまま大きくなってほしいので、本文の em
	   ではなく板幅から出す(dB = 20 / 1120、丸の中のラベル = 18 / 1120)。 */
	.figure_layer .pm_spec_label {
		font-size: calc(var(--pm_w) * 0.0160714); /* 18 / 1120 */
	}

	.modal_desc {
		position: static;
		width: auto;
		/* 左右の余白。図版の組(板幅の約70%)より外側に来る */
		margin: 0 clamp(30px, 9vw, 50px);
		/* この幅でもポイントの本文と同じ大きさにする(.label_desc と必ず同じ値にすること) */
		font-size: clamp(10px, 3.48vw, 14px);
		line-height: 1.9;
	}

	.modal_close {
		width: 34px;
		height: 34px;
		right: 12px;
		top: 12px;
	}

	.modal_close img {
		width: 12px;
	}
}

/* 3D の位置に合わせたポイントの左右配置。モデルが寄っている側の反対に置く
   (hood:左 / fabric:右 ※この1つだけ反転 / standard:中央 / defy:左)。どちら側にモデルが来るかは
   js/3d_zone.js の camKeys が決めている。縦位置はここでは持たない ―― layoutLabels() が top に
   px で書き込む。縦位置がそのまま「カメラが到達するタイミング」になるので、ずらすと合図がずれる。 */
#point_hood,
#point_defy {
	margin-left: 6%;
	text-align: left;
}

/* ポイント2だけ左右が反転する。モデルを画面の左へ持ってきているので注釈は右側に置くが、行揃えは
   他と同じ左のまま ―― タイトルは2つの inline-block に分かれていて枠より広いため、右揃えにすると
   行ごとに開始位置がばらけて階段状にずれる。left で置いているのは、その「左端」が位置の基準に
   なるため(right だとはみ出す量が文字サイズで変わって見た目の位置が安定しない)。 */
#point_fabric {
	/* margin-left の実値は js/3d_zone.js の layoutFabricPoint() が実測して px で書き込む
	   (「切れない範囲でできるだけ右」)。50% は js が動かなかったときの控え。 */
	margin-left: 50%;
	text-align: left;
}

#point_hood,
#point_fabric {
	width: min(440px, 46vw);
}

#point_defy {
	width: min(460px, 46vw);
}

#point_standard {
	margin-left: auto;
	margin-right: auto;
	text-align: center;
}

.scroll_indicator_3d {
	/* スクロールが進むと js が opacity を 0 にするだけなので、当たり判定を切っておく。切らないと
	   見えなくなったあともここだけクリックを奪う(z-index 20 で #labels_container より手前のため)。 */
	pointer-events: none;
	position: absolute;
	bottom: 32px;
	left: 50%;
	transform: translateX(-50%);
	text-align: center;
	z-index: 20;
	/* 色は白、動きは下のレールを走る線だけ(跳ねる動きは持たない)。跳ねる動きは戻りの上向きが入る
	   ぶん「下へ」が読みにくく、寒色のグレーは 3D の白い線に埋もれていた。 */
	color: #fff;
	/* 見出し系と同じ書体(changeling-neo)に揃える */
	font-family: var(--font_display);
	font-weight: 700;
	font-size: 10px;
	letter-spacing: 0.25em;
	opacity: 1;
	transition: opacity 0.4s;
}

/* 矢印は使わず、下のレールに置き換える */
.scroll_indicator_3d svg {
	display: none;
}

/* 通常幅では合図ごと出さない。js/3d_zone.js はこの要素の opacity を書くだけなので、
   display で下ろしてしまえば足りる(js 側に手を入れる必要はない)。 */
@media (min-width: 1025px) {
	.scroll_indicator_3d {
		display: none;
	}
}

/* 「下へスクロール」の合図。矢印の代わりに置く縦の線で、薄いレールの中を明るい区間が上から下へ
   走り抜ける(走る側は ::after で、はみ出した部分は overflow:hidden で隠れる)。 */
.scroll_line {
	display: block;
	position: relative;
	width: 1px;
	height: 44px;
	margin: 12px auto 0;
	overflow: hidden;
	background: rgba(255, 255, 255, 0.22);
}

.scroll_line::after {
	content: '';
	position: absolute;
	left: 0;
	top: 0;
	width: 100%;
	height: 45%;
	background: #fff;
	animation: scroll_line_run 2.6s cubic-bezier(0.5, 0, 0.5, 1) infinite;
}

/* レールの中を明るい区間が上から下へ走り抜ける。移動量の 222% は「レールの高さ ÷ 明るい区間の
   高さ」でちょうど下端から出きる量、-100% は上端の外(どちらも overflow:hidden で隠れる)。
   60% で走り終えたあと 100% まで止めているのは、続けざまに繰り返さず一拍おくため。 */
@keyframes scroll_line_run {
	0%   { transform: translateY(-100%); }
	60%  { transform: translateY(222%); }
	100% { transform: translateY(222%); }
}

/* body に 3D モーダル表示中だけスクロールを止める */
/* 見出しだけで画面1枚ぶんの高さを取り、その中で上下中央に置く。
   前後のセクションから完全に切り離して、ここだけの間にする。 */
.products_heading {
	text-align: center;
	margin: 0;
	min-height: 100vh;
	min-height: 100lvh;
	display: flex;
	flex-direction: column;
	justify-content: center;
}

/* ---------------------------------------------------------
   見出しの出方。1行ずつ動かない枠(.heading_line)に入れ、その中で文字が1つずつ下からのぼって
   くる(枠が切り取っているので「下から現れる」ように見える)。1文字ずつの span は js の
   buildHeadingChars() が作り、何番目かを --ci に入れる。.is_in は js が一度だけ付ける。
   --------------------------------------------------------- */

.heading_line {
	display: block;
	overflow: hidden;
	/* 行送りを詰めてあるぶん枠が文字の外形より内側に来る。逃がしたぶんは負の margin で戻し、行の
	   間隔は変えない(逃げは中身側に持たせるので、待機中の文字が枠からのぞかない)。 */
	margin-bottom: -0.14em;
}

.heading_line_inner {
	display: block;
	padding-bottom: 0.14em;
}

/* 1文字ぶん。--ci は並び順(js が入れる)、--cd は1文字あたりの遅れ */
.heading_char {
	display: inline-block;
	--cd: 0.035s;
	transform: translateY(110%);
	transition: transform 1s cubic-bezier(0.22, 1, 0.36, 1);
	transition-delay: calc(var(--ci, 0) * var(--cd));
}

.products_heading.is_in .heading_char {
	transform: translateY(0);
}

/* 日本語の1行は、欧文より少し速く送る(文字数が多いため) */
.products_heading_ja .heading_char {
	--cd: 0.028s;
}

/* 動きを減らす設定のときは、そのまま出す */
@media (prefers-reduced-motion: reduce) {
	.heading_char {
		transform: none;
		transition: none;
	}
}

.products_heading_en {
	font-family: var(--font_display);
	font-weight: 500;
	font-size: clamp(32px, 7vw, 80px);
	letter-spacing: 0.06em;
	line-height: 1.05;
	color: var(--c_white);
}

.products_heading_ja {
	margin-top: clamp(16px, 3.33vw, 64px);
	font-family: var(--font_jp);
	font-size: clamp(14px, 1.4vw, 26px);
	letter-spacing: 0.06em;
	color: var(--c_white);
	opacity: 0.85;
}

/* =========================================================
   products: slider
   ---------------------------------------------------------
   3型を1画面ぶんの枠に固定(sticky)し、スクロールで中身だけを入れ替える。3型を縦に並べると
   同じ組み方の面が3つ続くだけの区間になるため、枠は動かさず中身が変わる形にしている。
   写真を1枚だけ大きく置くと型の違いがそのポーズ次第になってしまうので、全身・フード・生地の
   3枚をグリッドに敷き詰めて1型ぶんの情報を1画面に収めている。値は js の updateProductSlider が
   書き込み、ここでは配置と js が触らない見た目だけを持つ。
   ========================================================= */

.product_slider {
	position: relative;
	/* 100lvh(固定して見せているぶん)+ 3型を渡り切るための距離(1型あたり 80vh)。ここを変えるときは、
	   1型ぶんが短くなりすぎて切り替わりが飛んで見えないかを確かめること。 */
	height: calc(100vh + 240vh * var(--sp_scroll_stretch));
	height: calc(100lvh + 240vh * var(--sp_scroll_stretch));
	margin-top: clamp(40px, 6vw, 120px);
	/* detail_section の左右パディングを打ち消して画面幅いっぱいに使う */
	margin-left: calc(var(--side_padding) * -1);
	margin-right: calc(var(--side_padding) * -1);
}

.product_slider_stage {
	position: sticky;
	top: 0;
	height: 100vh;
	height: 100lvh;
	overflow: hidden;

	/* 型が入れ替わるときの動き。枠(マス目・文字の行)は動かさず中身だけを下から上へ送る。出てくる側と
	   去る側を同じ速さ・同じ向きで動かすことで、2枚が重ならずベルトのように入れ替わる
	   (--slide_from = これから出てくる待ち位置 / --slide_to = 去っていく行き先)。
	   戻しているときは js が data-dir="up" を入れる ―― 向きが逆だと先へ送られたように見えるため。 */
	--slide_from: 100%;
	--slide_to: -100%;
	--slide_dur: 0.55s;
	--slide_ease: cubic-bezier(0.62, 0.02, 0.2, 1);
	/* 文字はこの2つで前半・後半に分ける(合計が写真の尺とほぼ同じ) */
	--line_out_dur: 0.28s;
	--line_in_dur: 0.36s;
	/* MORE は文字とは別の出方をする。文字が「ぜんぶ」収まって(色見本の行が 0.8s)から
	   ワンテンポ置いて、中央から広がって出る。消えるときは先に畳む。
	   ここを変えたら js の SLIDE_MOTION_MS / MORE_SETTLE_MS も合わせること
	   (入れ替えが終わるまで次の型を出さない足止めの長さがこれで決まる)。 */
	--more_in_delay: 0.8s;
	--more_in_dur: 0.32s;
	--more_out_dur: 0.18s;
	--more_ease: cubic-bezier(0.22, 1, 0.36, 1);
}

.product_slider_stage[data-dir="up"] {
	--slide_from: -100%;
	--slide_to: 100%;
}

/* ---------------------------------------------------------
   スライド: 3枚を同じ場所に重ねて置き、現在の1枚だけを出す。
   --------------------------------------------------------- */

.product_slide {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	/* 上下の余白は取らない(コラージュを枠の高さいっぱいまで使わせるため)。
	   文字側の上下は .product_slide_body が中央寄せで持つ。 */
	padding: 0;
	/* 出ていないスライドは visibility で隠す(透明にするだけだと、中の MORE や色タイルがタブ移動で
	   拾われる)。透明度での入れ替えはしない ―― 2枚がベルトのように入れ替わるので、途中で薄くなると
	   下の1枚が透けて濁って見える。去っていく1枚だけは動き終わるまで見えたままにする(.is_leaving)。 */
	visibility: hidden;
	pointer-events: none;
}

.product_slide.is_current {
	visibility: visible;
	pointer-events: auto;
	/* 出てくる側が上。去る側に重なりながら送り出す */
	z-index: 2;
}

.product_slide.is_leaving {
	visibility: visible;
	z-index: 1;
}

/* 戻るときは重ね順も逆にする。進むときの「下から上がって被さる」をそのまま巻き戻した形に
   するため、いま出ている側が上のまま下へ抜ける。 */
[data-dir="up"] .product_slide.is_current {
	z-index: 1;
}

[data-dir="up"] .product_slide.is_leaving {
	z-index: 2;
}

/* 並びは3型とも同じ(左にコラージュ、右に商品名)。枠が動かないぶん、型ごとに左右を入れ替えると
   視線の置き場所が毎回変わってしまうため。 */
.product_slide_inner {
	/* 画面幅いっぱいを使い、左半分ちょうどをコラージュに渡す(左に余白は置かない)。
	   文字側は残りの半分で、内側の余白は .product_slide_body が自分で持つ。 */
	width: 100%;
	height: 100%;
	display: grid;
	grid-template-columns: 50vw minmax(0, 1fr);
	/* 行は画面の高さちょうどに固定する。自動のままだと行の高さが「中に入っている写真の元の大きさ」で
	   決まり、画面が低いときだけ行が画面より高くなる。しかも UV PARKA は写真を重ねて置いてあるぶん
	   元の大きさを主張しないので、この型だけ行が伸びず、小さいマスの高さが他と食い違って見える。 */
	grid-template-rows: minmax(0, 1fr);
	align-items: stretch;
	gap: 0;
	/* 画面の高さが足りないとき、行の高さが中身に押し広げられてコラージュが枠の外へ伸びる。
	   ここで切って、上下の余白から写真がはみ出さないようにする。 */
	overflow: hidden;
}

/* ---------------------------------------------------------
   コラージュ(グリッド): 左に全身を縦長のまま1枚、右にフードと生地を上下に2枚。
   傾けたり重ねたりせず、マス目に敷き詰める。
   --------------------------------------------------------- */

.product_slide_collage {
	/* マス目は grid ではなく「枠の中の絶対配置」で置いている ―― クリック/タップで1枚をマス目
	   いっぱいまで広げるため。grid のマス目のままでは広がる途中の形を作れないが、absolute + inset なら
	   inset を 0 へ動かすだけでなめらかに広がる。各マスの inset は、もとの grid とまったく同じ位置に
	   なるよう計算してある(内訳は .collage_piece_a / _b / _c のコメント)。 */
	position: relative;
	--collage_gap: clamp(6px, 0.6vw, 12px);
	height: 100%;

	/* 広がり/戻りの尺と曲線。触ったときの「軽さ」はほぼここで決まる。
	   --collage_open_dur は 1画面ぶんの大きさまで開くので、短いと絵が飛ぶように見える。
	   --collage_open_ease は前半・後半のどちらにも寄せない曲線で、体感速度をいちばん左右する ――
	   強い ease-out(0.2,0.7,0.2,1)だと尺を伸ばしても半分に達するまで 165ms で、残りは這うだけになる。
	   速さを触るときは尺だけを動かし、曲線はこのままにしておくこと。 */
	--collage_open_dur: 0.58s;
	--collage_open_ease: cubic-bezier(0.4, 0, 0.2, 1);

	/* 開いていないマスにかぶせる幕。似た色の写真どうしだと、開いた1枚と隣のマスの境目が読めず
	   どこが大きくなったのか分からなくなるため。尺は開く尺より短くして、先に周りが落ちてから絵が
	   広がる順にする(同時だと暗くなりきる前に絵が覆ってしまって効き目が薄い)。 */
	--collage_dim_color: rgba(51, 51, 51, 0.72);
	--collage_dim_dur: 0.28s;
}

.collage_piece {
	/* 位置は .collage_piece_a / _b / _c が inset で持つ */
	position: absolute;
	display: block;
	/* 押して開くので、そう見えるようにしておく(判定は枠側で受ける) */
	cursor: pointer;
	/* はみ出させない枠。中身(.collage_media)はこの中を通り抜ける */
	overflow: hidden;
	/* 広がり/戻りの動き。inset を動かすので写真の切り取り(object-fit:cover)も一緒に変わり、
	   「枠が開いて中身が見えてくる」ように見える。尺と曲線は枠側がまとめて持っている。 */
	transition: inset var(--collage_open_dur, 0.58s) var(--collage_open_ease, ease);
}

/* 1枚を写真群いっぱいまで広げた状態。PC のクリックもスマホのタップも同じで、
   js/main_zone.js が .is_expanded を付け外しして効かせる。 */
.collage_piece.is_expanded {
	inset: 0;
	/* 開いた1枚を最前面に。他のマス(と、そのマスに乗る幕)はいずれも z-index なし = 0 相当なので、
	   ここが 0 より大きければ必ず前に来る。 */
	z-index: 3;
}

/* 縮んでいる途中の1枚。マスは DOM 順に重なるので、z-index を戻した瞬間に「まだ大きいのに後ろの
   マスより下」になって潜って見える。縮みきるまでは他のマスより前に置くが、次に開く1枚(z-index: 3)
   よりは後ろにして、新しく開くほうが必ず前に出るようにする。付け外しは js の expand()。 */
.collage_piece.is_collapsing {
	z-index: 2;
}

/* 開いていないマスにかぶせる、モーダルの幕のような灰色。マスの中(overflow:hidden)に敷くので
   マスの形に切り取られる。z-index は付けない ―― ::after は最後の子なので自然に前に来るし、
   付けてしまうと開いた1枚(z-index:3)と同じ土俵で競ってしまう。 */
.collage_piece::after {
	content: '';
	position: absolute;
	inset: 0;
	background: var(--collage_dim_color, rgba(51, 51, 51, 0.72));
	opacity: 0;
	transition: opacity var(--collage_dim_dur, 0.28s) linear;
	/* 当たり判定は js が枠の上で見ているので、幕は触らせない */
	pointer-events: none;
}

.product_slide_collage.has_expanded .collage_piece:not(.is_expanded)::after {
	opacity: 1;
}

/* 1枚でも開いているあいだは写真群そのものを一段持ち上げる。枠の中で最前面にするだけでは、
   同じ型の中に置いた文字組(.product_slide_body)より前に来る保証が無いため。 */
.product_slide_collage.has_expanded {
	z-index: 4;
}

/* 拡大したときに見せる専用の1枚(.collage_zoom)。マス目の写真をそのまま大きくすると写真群いっぱいまで
   引き伸ばして粗くなるので、「広げたとき用」の別の1枚を重ねておき広がった瞬間からこちらを見せる。
   当てているのは img/product_*.jpg の同名ファイル(写真そのものが広げたときの縦横比で書き出してある)。
   切り替えに transition を掛けていないのは、重なっている間だけ下の引き伸ばした姿が透けるため。 */
.collage_zoom {
	position: absolute;
	inset: 0;
	display: block;
	overflow: hidden;
	opacity: 0;
	/* 切り替えのフェードは開く尺よりずっと短く保つ ―― 長くすると、重なっているあいだ下のマス目の
	   写真(まさに出したくない「拡大された姿」)が透けて見える。目安は --collage_open_dur のおよそ 1/8。
	   尺を変えたときはここも同じ比で合わせること(0 にしても破綻はしない)。 */
	transition: opacity 0.07s linear;
	/* 開いていない間は無いものとして扱う(当たり判定は js が枠の上で見る) */
	pointer-events: none;
}

.collage_piece.is_expanded .collage_zoom {
	opacity: 1;
}

.collage_zoom_img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

@media (prefers-reduced-motion: reduce) {
	.collage_piece,
	.collage_piece::after,
	.collage_piece img,
	#parka_collage .collage_img,
	.collage_zoom {
		transition: none;
	}
}

/* マスの中で動く1枚。写真そのものではなくこの入れ物を動かすのは、UV PARKA のように1マスに写真が
   2枚重なっている型でもまとめて同じだけ動かすため。地の色は枠ではなくこちらが持つ ―― 枠に置くと
   入ってくる側の黒が去っていく側の写真に覆いかぶさり、通り道が黒く抜ける。 */
.collage_media {
	position: relative;
	display: block;
	width: 100%;
	height: 100%;
	/* 画像が届く前に黒地の中で四角だけが白く抜けないように */
	background: #101010;
}

/* 全身は左の列を上下いっぱいに使う */
.collage_piece_a {
	/* 左の列(1fr)いっぱい・2行ぶん。右辺の位置 = 枠幅 - (枠幅 - 間隔) / 2 = 50% + 0.5 x 間隔。
	   左右を等分にしているのはデザイン(Figma)のマス割りがそうだから。 */
	inset: 0 calc(50% + 0.5 * var(--collage_gap)) 0 0;
}

.collage_piece_b {
	/* 右の列(1fr)の上の行。左辺 = (枠幅 - 間隔) / 2 + 間隔 = 50% + 0.5 x 間隔。
	   下辺 = 枠高 - (枠高 - 間隔) / 2 = 50% + 0.5 x 間隔。 */
	inset: 0 0 calc(50% + 0.5 * var(--collage_gap)) calc(50% + 0.5 * var(--collage_gap));
}

.collage_piece_c {
	/* 右の列の下の行。上辺は _b の下辺と同じ値。 */
	inset: calc(50% + 0.5 * var(--collage_gap)) 0 0 calc(50% + 0.5 * var(--collage_gap));
}

.collage_piece img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 1.2s cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* 1枚目(_a、全身)だけは高さで合わせ、横は成り行きにする。この1枚だけ「全身が入っていること」が
   中身そのものなので頭と足を切ってはいけないが、object-fit: cover は枠の形が変わるたびに寄りを
   計算し直すため、広げると横長の枠に合わせて寄りが強まり上下が 12〜15% ほど切れる。高さで合わせて
   おけば寄りは一切変わらない。_b / _c は寄りの写真で多少切れても中身が変わらないため cover のまま。 */
.collage_piece_a .collage_media img,
.collage_piece_a .collage_zoom_img {
	width: auto;
	/* マスの中(枠のほうが狭い)では、幅を枠で頭打ちにして object-fit: cover に任せる ―― つまり
	   今までと同じ中央の切り取りになる。この見せ方の要なのでここにも書いておく。 */
	max-width: 100%;
	/* 広げて枠のほうが横に広くなったら、余りを左右へ均等に振る */
	margin-inline: auto;
}

/* _a だけは広げても写真の寄りが変わらない(上の「高さで合わせる」指定の結果。意図どおり)ため、
   押しても大きくなった手応えが無い。そこでほんの少しだけ寄る。1.05 は「足元が切れない」上限から
   決めた値 ―― いちばん余白が薄い FOCUS COAT の足元でも 1.5% ほど残る(1.08 が限界)。
   尺と曲線は .collage_piece img の 1.2s のまま。_b / _c は広げれば 2 倍以上になるので要らない。 */
.collage_piece_a.is_expanded .collage_media img,
.collage_piece_a.is_expanded .collage_zoom_img {
	/* 他の2枚は枠が2倍以上に広がるので押した手応えが出るが、_a は高さ合わせで framing が
	   変わらず、広げてもほとんど同じ絵のまま残る。そこでこの1枚だけ写真側を寄せて、他と
	   同じくらいの「拡大した」手応えにする。
	   寄る向き(原点)は下の規則が持つ(縮むあいだも同じ値でないと、閉じた瞬間に原点だけが
	   中央へ戻って写真が飛ぶ)。 */
	transform: scale(1.45);
}

/* 寄り引きの尺と向き。尺は枠(0.58s)と揃える ―― 写真側の既定は 1.2s(PC のホバー用)で、
   そのままだと枠が開ききったあとも写真だけ動き続け「押してからゆっくり拡大する」ように見える。
   寄る位置を変えたいときは、この 14% ひとつを動かせばよい(小さいほど上へ寄る)。 */
.collage_piece_a.is_expanded .collage_media img,
.collage_piece_a.is_expanded .collage_zoom_img,
.collage_piece_a.is_collapsing .collage_media img,
.collage_piece_a.is_collapsing .collage_zoom_img {
	transform-origin: center 14%;
	transition: transform var(--collage_open_dur, 0.58s) var(--collage_open_ease, ease);
}

/* 通常幅では、上と同じ原点を状態によらず持たせる。ホバー(1.04)と拡大(1.45)で原点が違うと、
   ホバーから拡大へ移る瞬間・縮みきってホバーへ戻る瞬間に、倍率はそのままで原点だけが飛んで
   写真がずれる。倍率 1 のときは効かないので、待っているあいだの見え方は変わらない。
   縦積み(1024px 以下)には入れない ―― あちらは出のときの引き(scale: 1.3)が原点を中央で使う。 */
@media (min-width: 1025px) {
	.collage_piece_a .collage_media img,
	.collage_piece_a .collage_zoom_img {
		transform-origin: center 14%;
	}
}

/* UV PARKA の色の入れ替えは、いま出ている写真と次の色の写真を重ねて同時にすり替える(片方が
   消えてから次を出すと、あいだに黒い枠だけが見える瞬間ができる)。そのためこの型の3マスだけ写真が
   2枚あり、どちらを見せるかは js が .is_current の付け替えで決める。 */
#parka_collage .collage_img {
	position: absolute;
	inset: 0;
	opacity: 0;
	/* 消えていく側。両方をまったく同じ速さで動かすと重なりの真ん中でどちらも半透明になり、下の黒地が
	   透けて一瞬暗く沈む。少し待ってから引くことで明るさを保ったまますり替わる(終わる時刻は揃えてある)。 */
	transition: opacity 0.4s ease 0.15s,
							transform 1.2s cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* 出てくる側。押した瞬間から立ち上げる */
#parka_collage .collage_img.is_current {
	opacity: 1;
	transition: opacity 0.55s ease,
							transform 1.2s cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* 広げ/縮みのあいだだけ、寄り引きの尺を 1、2型目と同じ --collage_open_dur に戻す。上の2つは色の
   すり替えのため id 付きで、そのままだと .collage_piece_a.is_expanded / .is_collapsing の 0.58s に
   勝つ ―― この型だけ枠が閉じきったあとも写真が 1.2s で縮み続け、その途中で .is_collapsing が外れて
   transform-origin が中央へ戻るので、縮むあいだに一度飛んで見える。opacity は色の尺のまま残す。 */
#parka_collage .collage_piece_a.is_expanded .collage_img,
#parka_collage .collage_piece_a.is_collapsing .collage_img {
	transition: opacity 0.4s ease 0.15s,
							transform var(--collage_open_dur, 0.58s) var(--collage_open_ease, ease);
}

#parka_collage .collage_piece_a.is_expanded .collage_img.is_current,
#parka_collage .collage_piece_a.is_collapsing .collage_img.is_current {
	transition: opacity 0.55s ease,
							transform var(--collage_open_dur, 0.58s) var(--collage_open_ease, ease);
}

/* ---------------------------------------------------------
   商品名 / 色 / MORE: 文字は動かない枠(.slide_line / .name_line)に入れ、中身(..._inner)だけを
   下から送り込む。商品名は行ごとに枠を持つので、1行ずつ順に入れ替わる。
   --------------------------------------------------------- */

.slide_line {
	display: block;
	max-width: 100%;
	overflow: hidden;
}

/* 商品名は1行ずつ枠を持つ(まとめて1つの枠に入れると、2〜3行が1枚の板として動く)。line-height を
   詰めてあるぶん行の枠は文字の外形より内側に来るので、中身の下に逃げを持たせ、その厚みぶんを枠の
   負の margin で戻す ―― 逃げを中身側に付けることで枠と中身の高さが一致し、待機中の1行がのぞかない。 */
.name_line {
	display: block;
	overflow: hidden;
	margin-bottom: -0.12em;
}

.name_line_inner {
	display: block;
	padding-bottom: 0.12em;
}

/* 動き終わったら枠での切り取りをやめる。MORE の丸はホバーで枠が広がるので、切り取ったままだと
   縁が削れて見える(.is_settled は js が動きの終わりに付ける)。 */
.product_slide.is_settled .slide_line {
	overflow: visible;
}

.product_slide_body {
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-items: flex-start;
	gap: clamp(16px, 2vw, 36px);
	/* 左はコラージュとのあいだ(grid の gap をやめたぶんをここで持つ)。右は縦に並ぶインジケーターの
	   逃げで、右端からの位置 + 線の幅ぶんを空ける。 */
	padding-left: clamp(24px, 4vw, 80px);
	padding-right: clamp(72px, 8vw, 140px);
}

.product_slide_no {
	font-family: var(--font_display);
	font-weight: 400;
	font-size: clamp(12px, 1.7vw, 33px);
	letter-spacing: 0.06em;
	line-height: 1.04;
	color: var(--c_white);
}

.product_slide_size {
	font-family: var(--font_display);
	font-weight: 400;
	font-size: clamp(11px, 1.42vw, 20px);
	letter-spacing: 0.06em;
	line-height: 1.04;
	color: var(--c_white);
}

/* 総数の目安なので、番号より弱く置く */

/* 商品名。3D のポイント名(.label_title)と同じ大きさで置くが、こちらは画面の半分の幅に収める
   必要があるので字間だけ詰めてある。 */
.product_slide_name {
	margin: 0;
	font-family: var(--font_display);
	font-weight: 500;
	/* 3D のポイント名と同じ大きさ。ただし UV PARKA は3行になるので、横長で背の低い画面では
	   画面の高さ側でも頭打ちにしておく。 */
	font-size: clamp(20px, min(6.25vw, 10.5vh), 112px);
	line-height: 1.02;
	letter-spacing: 0.06em;
	color: var(--c_white);
	/* 改行は html 側の <br> で決めている。幅の足りない画面で単語の途中から折り返して形が崩れるのを
	   防ぐため、自動の折り返しは止めておく。 */
	white-space: nowrap;
}

/* ---------------------------------------------------------
   型が入れ替わるときの動き。枠(マス目・文字の行)は動かさず、中身だけを下から上へ送る
   (写真は3枚それぞれが自分のマスの中を通り、文字は行ごとに入れ替わる)。
   --------------------------------------------------------- */

/* 写真の待機中。次に出てくる向きへ置いておくだけで、ここでは動かさない
   (transition を持たせない = 出番の前後で位置が飛んでも見えない)。 */
.collage_media {
	transform: translateY(var(--slide_from));
}

/* 戻るときは、出てくる側は動かさない(その場で待っている)。動くのはいま出ている側だけで、
   これが下へ抜けて下の1枚が現れる ―― 進むときの動きをそのまま巻き戻した形。 */
[data-dir="up"] .collage_media {
	transform: translateY(0);
}

/* 文字の行は枠の高さちょうどではなく少し余分に動かす。ちょうどだと、色見本の選択中のタイルや
   1px の枠線が、抜けきったはずの枠の縁に髪の毛のような線になって残る。 */
.slide_line_inner,
.name_line_inner {
	transform: translateY(calc(var(--slide_from) * 1.12));
}

/* 出てくる側は定位置へ */
.product_slide.is_current .collage_media,
.product_slide.is_current .slide_line_inner,
.product_slide.is_current .name_line_inner {
	transform: translateY(0);
}

/* 進むとき、写真の去る側は動かさない。次の写真が上に被さって隠れるまでその場に居てもらう
   (動かすと、下から出てくる1枚と一緒に流れて見える)。 */
.product_slide.is_leaving .collage_media {
	transform: translateY(0);
}

/* 戻るときは逆。去る側(いま出ている写真)が下へ抜ける */
[data-dir="up"] .product_slide.is_leaving .collage_media {
	transform: translateY(100%);
}

/* 文字の去る側は、行の枠の外へ抜けきる */
.product_slide.is_leaving .slide_line_inner,
.product_slide.is_leaving .name_line_inner {
	transform: translateY(calc(var(--slide_to) * 1.12));
}

/* 写真: 動くのは片側だけ(進むときは出てくる側、戻るときは去る側)。
   3枚は同時ではなく、上の段から少しずつ遅らせて送る(--cell_stagger)。 */
.product_slide.is_current .collage_media,
[data-dir="up"] .product_slide.is_leaving .collage_media {
	transition: transform var(--slide_dur) var(--slide_ease) var(--cell_stagger, 0s);
	will-change: transform;
}

/* 戻るときの出てくる側は、その場に現れるだけ(動かさない) */
[data-dir="up"] .product_slide.is_current .collage_media {
	transition: none;
}

/* 左の全身 → 右上のフード → 右下の生地 の順に上がってくる */
.collage_piece_a { --cell_stagger: 0s; }
.collage_piece_b { --cell_stagger: 0.055s; }
.collage_piece_c { --cell_stagger: 0.11s; }

/* 文字: 去る(前半)→ 入る(後半)の順に分ける */
.product_slide.is_leaving .slide_line_inner,
.product_slide.is_leaving .name_line_inner {
	transition: transform var(--line_out_dur) var(--slide_ease) var(--line_stagger);
}

.product_slide.is_current .slide_line_inner,
.product_slide.is_current .name_line_inner {
	transition: transform var(--line_in_dur) var(--slide_ease)
							calc(var(--line_out_dur) + var(--line_stagger));
}

/* ---------------------------------------------------------
   1型目の文字は、枠が画面の半分まで来てから出す。近づいてくる途中でずっと出ていると、読む間が
   長いわりに何も起きないため。写真は先に出しておく(data-text="hold" は js が付け外しする)。
   --------------------------------------------------------- */

.product_slider_stage[data-text="hold"] .product_slide.is_current .slide_line_inner,
.product_slider_stage[data-text="hold"] .product_slide.is_current .name_line_inner {
	transform: translateY(var(--slide_from));
	transition: none;
}

.product_slider_stage[data-text="hold"] .product_slide.is_current .more_pop {
	transform: scale(0);
	transition: none;
}

/* 文字も上から順に。番号 → 商品名(1行ずつ)→ 色見本の並び */
.slide_line { --line_stagger: 0s; }
.name_line { --line_stagger: 0.04s; }
.name_line:nth-child(2) { --line_stagger: 0.07s; }
.name_line:nth-child(3) { --line_stagger: 0.1s; }
/* 色見本(UV PARKA だけ)は商品名のあと */
/* サイズ表記は商品名のあと */
.slide_line_size { --line_stagger: 0.13s; }
/* 色見本(UV PARKA だけ)はさらにあと */
.product_slide_actions .slide_line { --line_stagger: 0.16s; }

/* 通常幅(PC)だけ、入れ替えと表示の尺をゆっくりにする。

   この幅と スマホ(〜1024px)とで出し方がまったく違うので、尺も分けている。スマホは3型を
   縦に積んで要素ごとに出しており、そちらで効いているのは --line_in_dur / --line_stagger /
   --more_in_dur の3つ(写真は秒数を直に持っている)。上の既定値はスマホ側の速さで、
   ここはそれを上書きするだけなので、この塊を消せばスマホと同じ速さに戻る。

   数字はもとの比を保ったまま約 1.35 倍にしてある。--more_in_delay は「文字がぜんぶ収まる時刻」
   (= --line_out_dur + 最後の --line_stagger + --line_in_dur ≒ 1.07s)のすぐあと。
   ここを変えたら js の SLIDE_MOTION_MS / MORE_SETTLE_MS も合わせること。

   置き場所は「打ち消す既定値より後ろ」でなければならない ―― メディアクエリは詳細度を足さないので、
   同じ詳細度どうしでは後ろに書いたほうが勝つ。 */
@media (min-width: 1025px) {
	.product_slider_stage {
		--slide_dur: 0.75s;
		--line_out_dur: 0.38s;
		--line_in_dur: 0.48s;
		--more_in_delay: 1.08s;
		--more_in_dur: 0.43s;
		--more_out_dur: 0.24s;
	}

	/* 写真3枚のずらし */
	.collage_piece_b { --cell_stagger: 0.075s; }
	.collage_piece_c { --cell_stagger: 0.15s; }

	/* 文字の行のずらし */
	.name_line { --line_stagger: 0.055s; }
	.name_line:nth-child(2) { --line_stagger: 0.095s; }
	.name_line:nth-child(3) { --line_stagger: 0.135s; }
	.slide_line_size { --line_stagger: 0.175s; }
	.product_slide_actions .slide_line { --line_stagger: 0.215s; }
}

/* 動きを減らす設定のときは、送らずにその場で出す */
@media (prefers-reduced-motion: reduce) {
	.collage_media,
	.slide_line_inner,
	.name_line_inner,
	.product_slide.is_leaving .collage_media,
	.product_slide.is_leaving .slide_line_inner,
	.product_slide.is_leaving .name_line_inner,
	[data-dir="up"] .product_slide.is_leaving .collage_media {
		transform: none;
		transition: none;
	}
}

/* ---------------------------------------------------------
   MORE の出方。文字と同じ行送りにはしない ―― 上下に動くと丸が枠を出入りする途中で欠けて見え、
   文字と一緒に流れて「押せるもの」に見えなくなる。文字が収まったあと、ひと呼吸置いて中央から広がる。
   --------------------------------------------------------- */

.more_pop {
	display: block;
	/* 広がる動きは切り取らない */
	overflow: visible;
}

.more_pop,
.product_slide.is_leaving .more_pop {
	transform: scale(0);
}

.product_slide.is_current .more_pop {
	transform: scale(1);
	transition: transform var(--more_in_dur) var(--more_ease) var(--more_in_delay);
}

/* 消えるときは待たずに畳む(次の型の文字より先に場所を空ける) */
.product_slide.is_leaving .more_pop {
	transition: transform var(--more_out_dur) var(--more_ease);
}

@media (prefers-reduced-motion: reduce) {
	.more_pop,
	.product_slide.is_current .more_pop,
	.product_slide.is_leaving .more_pop {
		transform: none;
		transition: none;
	}
}

/* UV PARKA だけ、色見本と MORE を1行に並べる。商品名が3行になるぶん、この2つまで縦に積むと
   枠の高さを超えてしまうため。 */
.product_slide_actions {
	/* 選択中の色タイルが浮き上がる量。下の .slide_line と
	   .product_color.is_current .product_color_tile の両方が読む。 */
	--color_lift: 4px;
	display: flex;
	align-items: center;
	gap: clamp(20px, 2.6vw, 52px);
}

/* 選択中のタイルは --color_lift ぶん上へ浮く。行の枠は動きの終わりに overflow:visible へ切り替わるが、
   切り替わるまでのあいだ(js の MORE_SETTLE_MS)は枠が切り取ったままでタイルの上が削れて見えていた。
   枠の上に同じだけ padding で余裕を作り、その分を負マージンで戻す(内容の位置と枠の外形は元のまま、
   切り取りの範囲だけが上へ広がる)。行は下から送り込まれてくるので、上を広げても見え方は変わらない。 */
.product_slide_actions .slide_line {
	padding-top: var(--color_lift, 4px);
	margin-top: calc(var(--color_lift, 4px) * -1);
}

.product_color_list {
	display: flex;
	gap: clamp(10px, 1.1vw, 20px);
	margin: 0;
	padding: 0;
	list-style: none;
}

.product_color {
	appearance: none;
	-webkit-appearance: none;
	background: none;
	border: 0;
	padding: 0;
	display: grid;
	justify-items: center;
	gap: 8px;
	font: inherit;
	color: inherit;
	cursor: pointer;
}

.product_color_tile {
	display: block;
	position: relative;
	width: clamp(48px, 4.4vw, 76px);
	aspect-ratio: 1 / 1;
	overflow: hidden;
	/* 選んでいない色も生地の色そのものはそのまま見せる(色を選ぶためのタイルなので、沈めると
	   黒とグレーと白の区別がつかなくなる)。選択中かどうかは枠線・浮き上がり・色名の明るさで示す。 */
	opacity: 0.85;
	transition: opacity 0.35s ease, transform 0.35s ease;
}

.product_color_tile::after {
	content: '';
	position: absolute;
	inset: 0;
	border: 1px solid rgba(255, 255, 255, 0.2);
}

.product_color_tile img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.product_color:hover .product_color_tile,
.product_color:focus-visible .product_color_tile {
	opacity: 1;
}

.product_color.is_current .product_color_tile {
	opacity: 1;
	transform: translateY(calc(var(--color_lift, 4px) * -1));
}

.product_color.is_current .product_color_tile::after {
	border-color: rgba(255, 255, 255, 0.85);
}

.product_color_name {
	font-family: var(--font_ui);
	font-weight: 500;
	font-size: clamp(8px, 0.72vw, 11px);
	letter-spacing: 0.2em;
	color: rgba(255, 255, 255, 0.45);
	transition: color 0.35s ease;
}

.product_color.is_current .product_color_name {
	color: var(--c_white);
}

/* MORE は元が写真の上に重ねる前提の絶対配置なので、ここでは本文の流れの中に置き直す。 */
.view_more_btn.product_slide_more {
	position: relative;
	right: auto;
	bottom: auto;
	flex: 0 0 auto;
	/* Figma(1920px 基準)の btn は 80x80。80 / 1920 = 4.1667vw。
	   下限の 56px は、この式で 1344px を下回る幅のときの受け止め。 */
	--more_size: clamp(56px, 4.17vw, 80px);
	width: var(--more_size);
}

/* ---------------------------------------------------------
   写真に付いて回るカーソル。写真の上にカーソルが乗っているあいだ、その位置に丸い「+」を出す
   (押して大きく見られることの合図)。位置は js が毎フレーム少しずつ近づける ―― そのまま貼り付けると
   速く動かしたとき硬く感じるため。
   --------------------------------------------------------- */

.collage_cursor {
	/* 枠(.product_slider_stage)の中に置く。画面基準(fixed)にすると、下に敷かれている写真と
	   重ね合わせの土俵が分かれてしまい、色の反転が効かなくなる(白いまま出てしまう)。 */
	position: absolute;
	left: 0;
	top: 0;
	/* 拡大した写真(z-index: 4)より前 */
	z-index: 5;
	/* 下の写真の色を反転させて出す。反転は外側(この要素)に掛ける ―― 中の丸に掛けると、位置決めの
	   transform が作る「重ね合わせの箱」の中だけで完結して写真と混ざらない。 */
	mix-blend-mode: difference;
	/* 飾りなので、下の写真やボタンの操作を邪魔しない */
	pointer-events: none;
	display: none;
}

/* 指で触る画面にはカーソルが無いので出さない */
@media (hover: hover) {
	.collage_cursor {
		display: block;
	}
}

.collage_cursor_btn {
	display: flex;
	align-items: center;
	justify-content: center;
	/* 大きさは sample02 の値のまま(1440px 幅で約 82px)。zone の MORE(--more_size)は一段大きいが、
	   カーソルに付いて回るものとしてはこの方が邪魔にならないので揃えていない。 */
	width: clamp(64px, 5.69vw, 109px);
	aspect-ratio: 1 / 1;
	border-radius: 50%;
	border: 1px solid var(--c_white);
	background: none;
	color: var(--c_white);
	/* カーソルの真ん中に重ねる(位置は外側、ここでは中心合わせと出入り) */
	transform: translate(-50%, -50%) scale(0.6);
	opacity: 0;
	transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1),
	            opacity 0.25s ease;
}

.collage_cursor.is_visible .collage_cursor_btn {
	transform: translate(-50%, -50%) scale(1);
	opacity: 1;
}

/* 拡大した写真の上では「+」ではなく「−」を出す(押すと閉じるので、同じ印のままだと意味が逆になる)。
   「+」は .view_more_btn_plus の2本の棒でできていて ::after が縦棒なので、それだけを消せば
   「−」になる。透かして消すのは切り替わりを尺付きで見せるため。付け外しは js が行う。 */
.collage_cursor .view_more_btn_plus::after {
	transition: opacity 0.2s ease;
}

.collage_cursor.is_close .view_more_btn_plus::after {
	opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
	.collage_cursor_btn,
	.collage_cursor .view_more_btn_plus::after {
		transition: none;
	}
}

/* ---------------------------------------------------------
   インジケーター。PC では右端に縦に並べる ―― 下端に横並びで置くと、コラージュと商品名の下に
   もう1行ぶんの余白が要り、1画面に収める余地が減るため。丸はいま出ている型のものだけを塗る。
   --------------------------------------------------------- */

.product_slider_nav {
	position: absolute;
	/* Figma: 画面の右端から 128px(1920 の画面) */
	right: clamp(20px, 6.67vw, 128px);
	top: clamp(28px, 8vh, 90px);
	z-index: 3;
	display: flex;
	flex-direction: column;
	/* 丸を縦に揃える(型名の長さは揃っていない) */
	align-items: flex-start;
	/* 行の間隔(Figma の 50px = 行 12px + 38px を 1.36 倍した 68px ぶん) */
	gap: clamp(18px, 2.7vw, 52px);
}

.product_slider_tab {
	appearance: none;
	-webkit-appearance: none;
	background: none;
	border: 0;
	padding: 0;
	display: flex;
	align-items: center;
	/* 丸と型名のあいだ(Figma の 16px × 1.36) */
	gap: clamp(8px, 1.14vw, 22px);
	text-align: left;
	font: inherit;
	color: inherit;
	cursor: pointer;
}

.product_slider_tab_dot {
	display: block;
	/* Figma の 10px × 1.36 */
	width: clamp(7px, 0.71vw, 14px);
	aspect-ratio: 1 / 1;
	border-radius: 50%;
	border: 1px solid var(--c_white);
	background: transparent;
	transition: background-color 0.4s ease, box-shadow 0.4s ease;
}

.product_slider_tab_name {
	font-family: var(--font_display);
	font-weight: 400;
	font-size: clamp(9px, 0.85vw, 16px);
	letter-spacing: 0.06em;
	line-height: 1.04;
	color: var(--c_white);
	white-space: nowrap;
	transition: opacity 0.4s ease;
}

.product_slider_tab.is_current .product_slider_tab_dot {
	background: var(--c_white);
	box-shadow: 0 0 10px 6px rgba(255, 255, 255, 0.25);
}

.product_slider_tab:not(.is_current) .product_slider_tab_name {
	opacity: 0.7;
}

.product_slider_tab:hover .product_slider_tab_name {
	opacity: 1;
}

/* ---------------------------------------------------------
	 ホバー
	 グリッドは崩さず、写真だけをわずかに寄せる。
	 --------------------------------------------------------- */

@media (hover: hover) {
	/* 写真だけをわずかに寄せるホバー(1.04 倍)。マスの枠は動かさず、押して開けることの合図でもある。
	   開いている1枚は対象から外す ―― 拡大した絵は引き伸ばさない方針(そのための .collage_zoom)なので、
	   そこへさらに scale を掛けてはいけない。
	   縮んでいる途中(.is_collapsing)も外す ―― この rule のほうが詳細度で勝つので、押して閉じた
	   マスの上にカーソルが残っていると写真が 1 まで戻らず、縮み終わりに transform-origin だけが
	   中央へ戻って(_a は center 14%)そのぶん位置が飛ぶ。
	   拡大用の重ね(.collage_zoom_img)にも同じだけ掛ける ―― 押した 0.07 秒後にこちらへすり替わる
	   ので、片方だけ 1.04 だとその瞬間に大きさが 4% 変わって見える。 */
	.product_slide.is_current .collage_piece:not(.is_expanded):not(.is_collapsing):hover .collage_media img,
	.product_slide.is_current .collage_piece:not(.is_expanded):not(.is_collapsing):hover .collage_zoom_img {
		transform: scale(1.04);
	}

	.view_more_btn.product_slide_more::before {
		transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
	}

	/* 中身は動かさず、丸の枠だけを広げる */
	.view_more_btn.product_slide_more:hover::before {
		transform: scale(1.16);
	}
}

/* MORE の丸ボタン。細い白枠の丸に「+」と MORE を置く(中は塗らない)。写真やコラージュの上に
   重ねる前提の絶対配置で、置き場所ごとに上書きして使う(.product_slide_more など)。 */
.view_more_btn {
	position: absolute;
	right: 8%;
	bottom: 8%;
	width: clamp(56px, 4.17vw, 80px);
	aspect-ratio: 1 / 1;
	color: var(--c_white);
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	/* 「+」と MORE のあいだ。Figma で 8px(= 0.4167vw) */
	gap: clamp(4px, 0.42vw, 8px);
	text-decoration: none;
	transition: opacity 0.4s ease;
}

/* 丸の枠。中身(「+」と MORE)とは別に持たせてある ―― ホバーで枠だけを広げるため
   (中身まで一緒に拡げると文字がぼやけて見える)。 */
.view_more_btn::before {
	content: '';
	position: absolute;
	inset: 0;
	border-radius: 50%;
	border: 1px solid var(--c_white);
}

/* 真ん中の「+」。字ではなく線2本で作る(書体によって太さや位置が変わらないように)。 */
.view_more_btn_plus {
	position: relative;
	display: block;
	/* Figma で 13x13(= 0.6771vw) */
	width: clamp(9px, 0.68vw, 13px);
	height: clamp(9px, 0.68vw, 13px);
}

.view_more_btn_plus::before,
.view_more_btn_plus::after {
	content: '';
	position: absolute;
	left: 50%;
	top: 50%;
	background: currentColor;
}

.view_more_btn_plus::before {
	width: 100%;
	height: 1px;
	transform: translate(-50%, -50%);
}

.view_more_btn_plus::after {
	width: 1px;
	height: 100%;
	transform: translate(-50%, -50%);
}

.view_more_btn_text {
	font-family: var(--font_ui);
	font-weight: 500;
	/* Figma で 10px(= 0.5208vw) */
	font-size: clamp(7px, 0.52vw, 10px);
	letter-spacing: 0.06em;
	color: inherit;
	text-align: center;
	line-height: 1;
}

/* =========================================================
   story: ZONE ロゴ → ブランドの文章
   ---------------------------------------------------------
   ロゴと本文をひとつづきの区間にまとめ、区間のあいだ枠を画面へ貼り付けて(sticky)中身だけを
   入れ替える。スクロールそのものは止めない ―― スマホの慣性は js から止められず、止めようと
   すると必ず綱引きになる(このページで何度も行き着いた結論)。

   区間の長さは画面6枚ぶん。進み具合 0〜1 を3つに分けて使う ―― はじめでロゴが奥へ下がって
   薄くなり、まん中で文章4つがその手前で入れ替わり、終わりでロゴが手前へ戻る。ロゴは
   区間のあいだ消えない。文章は位置を動かさず、濃さとピントの合い具合で入れ替える。
   その値は js(story)が毎フレーム書く。css は置き場所と、js が動かないときでも読める状態
   だけを持つ。
   ========================================================= */

.story_stage {
	position: relative;
	/* footer(z-index:1)より奥にして、上を通過させる */
	z-index: 0;
	background: var(--c_black);
	/* 貼り付けて見せる1画面 + 中身を進めるための5画面(ロゴ1 + 文章4)。
	   末尾に足した --footer_overlap のぶんは、中身を進めずに貼り付いたまま footer が
	   上がってくる区間(js 側も進み具合の分母からこのぶんを外している)。 */
	--story_travel: 500;
	height: calc((100 + var(--story_travel)) * 1vh + var(--footer_overlap));
	height: calc((100 + var(--story_travel)) * 1lvh + var(--footer_overlap));
}

/* 区間のあいだ画面に貼り付く枠。中身はこの中で上下中央に置く */
.story_pin {
	position: sticky;
	top: 0;
	height: 100vh;
	height: 100lvh;
	display: flex;
	align-items: center;
	justify-content: center;
	/* 左右の余白。旧 brand_statement と同じ持たせ方(通常幅では 0 で、下の 62.5% が余白を
	   作る。スマホでは --side_padding が入り、本文は幅いっぱいでこの余白だけを残す)。 */
	padding: 0 var(--side_padding);
	/* ここに overflow は置かない。sticky な要素を同時にスクロールコンテナにすると、
	   WebKit(iOS)で貼り付きの計算が崩れ、ページ全体の sticky まで巻き込むことがある。
	   中身(ロゴ・本文)はどちらも1画面に収まるので、はみ出しを切る必要もない。 */
}

/* ---------------------------------------------------------
   ロゴ。区間のあいだ消えずに残り、奥へ下がって(縮小して)薄くなり、ピントも外れる。
   文章の背後でその姿のまま待ち、最後の文章が消えたあと手前へ戻る。
   縮小・濃さ・ぼけは js が毎フレーム書く。
   --------------------------------------------------------- */
.story_logo {
	position: absolute;
	/* span なので、貼り付きをやめる見え方(下の html:not(.has_js) / 動きを控える設定)で
	   position:static に戻したときに幅が効くよう、block にしておく。 */
	display: block;
	/* 撤去した zone_footer のロゴ(.footer_zone_logo)と同じ式。画面幅によらず同じ大きさ感 */
	width: clamp(220px, 46.8vw, 900px);
	aspect-ratio: 1305 / 146;
	/* js が書く前の姿(手前・ほぼ不透明)。js はここから下げはじめる */
	opacity: 0.9;
}

/* 絵は2枚を同じ場所に置き、「ぼけ」をどちらで出すかを環境で切り替える。

   通常幅 …… ::before に実行時の filter: blur を掛ける(::after は出さない)。見え方は
             こちらのほうが綺麗なので、使える環境では従来どおりこちらを使う。
   スマホ幅 / iOS Safari …… ::after の「ぼかし済みの絵」と濃さを入れ替える方式に切り替える。

   切り替えるのは、iOS Safari では実行時の filter が使えないため ―― ぼかした面の倍率が

   変わるたびに絵を作り直す必要があり(ぼかしてから縮めた絵と、縮めてからぼかした絵は違うので
   使い回せない)、
   その作り直しがスクロールに追いつかず、前の絵が横へ伸びた筋になって残る。実機で確認済み。
   ぼかし量を固定して2層にしても、倍率が変わる以上は同じだった。

   ぼかし済みの絵なら中身は動かないので、縮むのはただの画像の拡大縮小になり、作り直しが
   起きない。ぼかしの強さは img/detail_zone_logo_blur.png を作り直して変える(作り方は
   その絵と同じ場所の README ではなくここに記す ―― 元絵 1305px に対して σ = 15.66、
   にじみのぶん上下左右 47px の余白付き。画面上のぼかし量は「ロゴ幅の 1.2%」で、表示幅に
   比例していたため、元絵の座標では画面幅によらず同じ値になる = 素材は1つで足りる)。 */
.story_logo::before,
.story_logo::after {
	content: '';
	position: absolute;
	background-repeat: no-repeat;
	background-size: contain;
	background-position: center;
}

/* くっきりした側。奥へ行くほど引く */
/* くっきりした元絵。通常幅ではこの1枚だけを使い、ここでぼかす
   (量は js が --story_logo_blur へ px で書く)。 */
.story_logo::before {
	inset: 0;
	background-image: url(../img/detail_zone_logo.png);
	filter: blur(var(--story_logo_blur, 0px));
}

/* ぼけた側。絵はにじみのぶん元より大きいので、その差だけ枠を外へ広げて字の位置を合わせる
   (左右 47/1305、上下 47/146。左右は枠の幅、上下は枠の高さに対する割合)。 */
.story_logo::after {
	inset: -32.1918% -3.6015%;
	background-image: url(../img/detail_zone_logo_blur.png);
	/* 通常幅では使わない。下の2つの条件のどちらかで出番が来る */
	display: none;
}

/* iOS Safari。幅では拾えない(横向きの iPad は通常幅に入る)ので、そちらだけを指せる
   -webkit-touch-callout の有無で見分ける。 */
@supports (-webkit-touch-callout: none) {
	.story_logo::before {
		/* 実行時のぼかしはやめ、濃さの入れ替えに回る */
		filter: none;
		opacity: calc(1 - var(--story_logo_away, 0));
	}

	.story_logo::after {
		display: block;
		opacity: var(--story_logo_away, 0);
	}
}
/* ---------------------------------------------------------
   文章。全部を同じ場所に重ね、出ている1つだけを見せる。
   grid の同じマスに置いてあるので、入れ物の高さはいちばん高い文章に合う
   (絶対配置で重ねると、長さの違う文章が下にはみ出す)。
   --------------------------------------------------------- */
.story_texts {
	display: grid;
	/* 薄くなったロゴは絶対配置で同じ場所にいる。本文はその手前に置かないと読みにくい */
	position: relative;
	z-index: 1;
	/* 字の大きさはここで持ち、本文は継ぐ。下の幅を em(= 和文1文字ぶん)で書くため。 */
	font-size: clamp(10px, 1.87vw, 36px);
	/* 1行の文字数で幅を決める。em は和文1文字ぶんなので、36em + 字送り 0.04em で
	   どの画面幅でもちょうど 34文字。%で持つと画面ごとに文字数が変わり、行の長さが
	   揃わない(和文は 30〜40文字が読みやすい)。入りきらない幅では 100% に収める。 */
	width: min(36em, 100%);
}

.story_text {
	margin: 0;
	color: var(--c_white);
	font-family: var(--font_jp);
	/* 黒地に白抜きなので、白地のときより1段細くする。同じ太さだと光がにじんで
	   線が太って見え、字面がつぶれる(旧 brand_statement は白地だったので 400)。 */
	font-weight: 300;
	/* 大きさは .story_texts から継ぐ(幅を文字数で決めるため) */
	font-size: inherit;
	/* 白抜きは行が詰まって見えるので、白地のとき(1.88)より開ける */
	line-height: 2.05;
	/* 和文の字送り。開けすぎると語のまとまりが崩れるので、1文字の 4% まで */
	letter-spacing: 0.04em;
	/* 同じマスへ重ねる。位置は動かさず、濃さとピントの合い具合で入れ替える */
	grid-area: 1 / 1;
	/* js が濃さを書く前の状態。重ねてあるので、これが無いと4つとも出て潰れて見える */
	opacity: 0;
}

.story_text:first-child {
	opacity: 1;
}

/* will-change はここでは使わない。付けっぱなしは合成レイヤーを抱え続けるので避けたいが、
   スクロール中に付け外しすると今度はレイヤーを作り直すことになり、WebKit では貼り付きの
   計算がその拍子に狂う。濃さ・ぼかし・拡大は掛かった時点で合成に回るので、無くても困らない。 */

/* js が動かないときの見え方。貼り付けも入れ替えもせず、ロゴと文章をただ縦に並べる
   ―― 何も見えない面になるより、動かないだけのほうがましなため。
   目印(html.has_js)は head のインラインで付けるので、最初の組版の時点で貼り付く側/
   並べる側のどちらかに決まる。js の実行後に切り替えると、組版が終わったあとでページの丈が
   数千px変わり、iOS では貼り付きの基準が古いままになって全部外れる。 */
html:not(.has_js) .story_stage {
	height: auto;
}

html:not(.has_js) .story_stage .story_pin {
	position: static;
	height: auto;
	display: block;
	padding: clamp(40px, 12vh, 160px) var(--side_padding);
}

html:not(.has_js) .story_stage .story_logo {
	position: static;
	margin: 0 auto clamp(40px, 10vh, 120px);
}

html:not(.has_js) .story_stage .story_texts {
	/* 重ねるのをやめて、上から順に並べる */
	display: block;
	width: auto;
}

/* 重ねないので、4つとも出しておく(js が濃さを書く前の opacity: 0 を戻す) */
html:not(.has_js) .story_stage .story_text {
	opacity: 1;
}

html:not(.has_js) .story_stage .story_text + .story_text {
	margin-top: clamp(24px, 4vh, 64px);
}

/* 動きを控える設定では、js が用意できていても上と同じ「ただ並べる」見え方にする */
@media (prefers-reduced-motion: reduce) {
	.story_stage {
		height: auto;
	}

	.story_pin {
		position: static;
		height: auto;
		display: block;
		padding: clamp(40px, 12vh, 160px) var(--side_padding);
	}

	.story_logo {
		position: static;
		margin: 0 auto clamp(40px, 10vh, 120px);
		opacity: 0.9 !important;
		scale: none !important;
		--story_logo_blur: 0px !important;
		--story_logo_away: 0 !important;
	}

	.story_logo {
		scale: none !important;
	}

	.story_texts {
		display: block;
		width: auto;
	}

	.story_text {
		opacity: 1 !important;
		filter: none !important;
		scale: none !important;
	}

	.story_text + .story_text {
		margin-top: clamp(24px, 4vh, 64px);
	}

	/* 貼り付けないので、footer を引き戻すと本文に重なってしまう。
	   !important なのは、この指定より後に .site_footer の負マージンが来るため
	   (@media は詳細度を足さないので、後ろの指定に負ける)。 */
	.site_footer {
		margin-top: 0 !important;
	}
}

/* =========================================================
   footer
   =========================================================
   サイト共通フッター(applicationJpPc/views/quarry/wavelifeBodyFooter.phtml)のみ。
   ZONE ロゴの帯は置かない(story の末尾でロゴが手前へ戻るので、同じ絵が二度続くため)。

   共通フッターの体裁そのものは /life/cmn/css/style.css が持っている。
   ここでは「このページだけ黒地・白文字にする」ための色だけを上書きし、
   余白や並びには手を出さない(共通フッターの組みが変わったときに、
   このページだけ崩れることがないようにするため)。
   ========================================================= */

/* ---------------------------------------------------------
   共通フッターの色替え(このページのみ)
   ---------------------------------------------------------
   共通フッターは薄グレー地に黒文字。このページは上の story(黒地)から
   そのまま続くので、地色と文字・線の色を反転させて揃える。
   色の指定だけに絞っているので、共通css 側の値と競合するのは色のみ。
--------------------------------------------------------- */

.site_footer {
	/* story(z-index:0)より手前の層に上げる。位置指定なしのままだと story の下へ潜って
	   見えなくなる。 */
	position: relative;
	z-index: 1;
	/* story の末尾に足した余地のぶんだけ引き戻して、貼り付いたままの story の上へ重ねる
	   (ページ全体の長さは変わらない)。量は js/main_zone.js が実測して入れる。 */
	margin-top: calc(-1 * var(--footer_overlap));
	/* 地色は敷かない。上の story へ重ねて出てくるので、塗ってしまうと戻ってきた ZONE ロゴを
	   隠してしまう。透かしても背後は story(黒地)と body(黒地)なので、見た目の地色は変わらない。
	   共通css(/life/cmn/css/style.css)の #eeeeee を打ち消す必要があるので、指定自体は残す。 */
	background-color: transparent;
	color: var(--c_white);
}

/*
	WAVE ロゴ(/life/cmn/img/nav_pc.png)は黒い絵しかないため、共通ヘッダーが
	暗い背景で使っているのと同じやり方(body.page_top .nav_logo_pc)で反転させる。
*/
.site_footer .footer_logo img {
	filter: invert(1);
}

.site_footer .footer_sns svg {
	stroke: var(--c_white);
}

.site_footer .footer_links a,
.site_footer .footer_links a:hover,
.site_footer .copyright {
	color: var(--c_white);
}

/* =========================================================
   Responsive: tablet
   ========================================================= */

@media (max-width: 1024px) {
	.label_more {
		/* 指で押しやすい大きさ(44px 以上)にする。通常幅は 44px 相当 */
		width: 52px;
		height: 52px;
		font-size: 20px;
	}

	.label_br_sp,
	.br_sp {
		display: inline;
	}

	/* Products の見出し。Figma の SP 版にはこのセクションが無いため、同じ役割・同じ書体だった
	   (DETAIL) の見出しに合わせた値。 */
	/* PC は見出しだけで画面1枚ぶんの高さを取っているが、この幅でそれをやると文字の上下に画面の
	   半分ずつが空いてしまう。1枚ぶんの高さは外して、余白は padding で持つ。margin ではなく padding
	   なのは、隣の .product_slider の margin-top と相殺させないため。 */
	.products_heading {
		min-height: 0;
		margin: 0;
		padding: min(30vw, 140px) 0;
	}

	/* 見出しの下の余白は上の padding が持つので、スライダー側の margin-top は落とす(これを残すと
	   下だけ 40px 広くなる)。左右の負マージンは画面幅いっぱいに使うためのものなので触らない。 */
	.product_slider {
		margin-top: 0;
	}

	.products_heading_en {
		/* 上限は PC へ切り替わる 1025px で PC 側が出す値。1024px と 1025px で大きさが揃う */
		font-size: min(8.96vw, 71.75px);
	}

	/* ここから下は Figma の SP 版(402px 幅で作成)の値。px 値をそのまま上限にし、それより狭い画面
	   では画面幅に比例して縮める(402px 以上ではその px に張り付く)。 */
	.tuneout_heading {
		/* Figma: 42px / 行送り 1.2 / tracking 2.52px = 0.06em */
		font-size: min(10.45vw, 42px);
		line-height: 1.2;
		letter-spacing: 0.06em;
		/* Figma は Changeling Neo の Regular。基準側(PC)は 700 なので、この幅だけ細字にする。 */
		font-weight: 400;
	}

	.tuneout_subheading {
		/* Figma: 14px / 見出しからの間隔 7px */
		font-size: min(3.48vw, 14px);
		margin-top: min(1.74vw, 7px);
	}

	/* スマホでも PC と同じ読ませ方にする。字間と行送りを広く取ると本文は画面 1 枚に収まらなくなるので
	   .is_flow(上揃え + translate の送り)が自動で効く ―― ここを詰めると本文が画面に収まってしまい、
	   送りが起きなくなる。字間・行送りは PC ほどは開けない(同じ値では1行に数文字しか入らない)。 */
	/* スマホでは本文を1画面に必ず収める。収まりを決めているのは 14 行ぶんの高さ + ロゴで、文字の
	   大きさを幅からだけ決めると背の低い端末で溢れる(390x844 は収まり 375x667 は 119px 溢れる)。
	   そこで大きさに高さ側の上限(lvh)も掛け、min で小さい方を採る。lvh を使うのは URL バーが出入り
	   しても値が変わらないため。行送りは 3.6 だと文字が 11px 前後まで小さくなるので 2.6 へ詰めてある。 */
	.pin_copy_text {
		font-size: clamp(10px, min(3.98vw, 2.1lvh), 20px);
		letter-spacing: 0.1em;
		line-height: 2.6;
		/* 幅は画面に対する割合で決める(基準側の max-content = 折り返さない
		   幅は使わない。スマホでは折り返して縦に伸ばす) */
		width: 88%;
		/* font-weight は指定せず、基準側の 300 をそのまま使う */
		/* 行末の空きぶんの戻し(基準側の -0.4em)も、字間の狭いこちらでは不要 */
		margin-left: 0;
	}

	/* ロゴは本文(pin_copy_text)の左上に張り付く(基準側のコメント参照)。スマホでは本文の文字サイズ・
	   行送りを別に組んでいるので、ロゴの大きさと下の余白もこの幅用に指定する。 */
	.zone_text_logo {
		width: min(42.2vw, 227px);
		margin-bottom: clamp(10px, 4.18vw, 24px);
	}

	.zone_text_about_link {
		display: none;
	}

	/* 写真の敷き方は通常幅と同じ ―― 16:9 のまま cover で覆う。ただし画面が縦長なぶん、写真の左右は
	   画面の外へ出る。 */

	/* グリッドはこの幅では縦に積む(Figma のスマホデザイン photo_sp と同じ構成)。横2列のままだと
	   1枚が画面幅の半分 = 200px 前後になり、どの写真も顔が判別できなくなるため。3等分なのは写真を
	   この幅用に切り出した別画像(_sp)へ差し替えてあるから ―― 縦位置の通常幅用を使っていた頃は
	   1行目だけ背を高くして上下の切れを逃していた。
	   3枚で1画面ぶんという点は通常幅と同じなので、上へ送る動きの側はこの幅でも何も変えない。 */
	.focus_grid {
		grid-template-columns: 1fr;
		grid-template-rows: 1fr 1fr 1fr;
	}

	/* この幅だけ並びを bianca → keita → elena にする(通常幅の2列組みはそのまま) */
	.focus_grid_bianca { grid-area: 1 / 1 / 2 / 2; }
	.focus_grid_keita  { grid-area: 2 / 1 / 3 / 2; }
	.focus_grid_elena  { grid-area: 3 / 1 / 4 / 2; }

	/* この幅でも角枠を出す。縦長の画面ではピントを合わせる枠が画面より広くなるので、js が左右だけを
	   画面の内側へ寄せる(--af_edge_ratio)。寄せ先を距離ではなく画面幅の割合で持つのは、一定の距離だと
	   どの端末でも角が画面の縁に貼り付いて「縁の飾り」に見えてしまうため。枠そのもの(= 開口の行き先)は
	   動かさない。大きさは通常幅の式だとこの幅で下限に張り付いて小さすぎるため、別に持つ。 */
	.focus_af {
		--af_edge_ratio: 0.18;
	}

	.focus_af_corner {
		width: clamp(13px, 4.2vw, 20px);
		height: clamp(13px, 4.2vw, 20px);
	}

	/* 3D の長さは、この @media の先頭にある :root の --cam_stretch で決まる(この幅だけ 0.65)。
	   tuneout の高さ・負マージン・#section_3d の3つは通常幅と同じ式が組み立てるので差し替え不要。 */

	/* この幅では 3D モデルが画面の高さいっぱい(実測で約105%)に写るため、どこにテキストを置いても
	   モデルと重なる。そこで画面の下から暗幕をかけ、その上に文字を載せる(.canvas_sticky::after)。 */
	.hotspot_label {
		/* 縦の位置はここでは持たない(上の @supports の中で top: 88lvh として持っている)。ここに bottom を
		   書くとあちらの bottom:auto を打ち消してしまい、top と bottom が両方入って高さが上下いっぱいに
		   引き伸ばされるので、書かないこと。 */
		width: calc(100% - 32px);
	}

	/* 下からのグラデーション暗幕。重ね順は モデル(z:1)→ 雨(z:5)→ ここ(z:7)→ ラベル(z:10)→
	   SCROLL DOWN(z:20)なので、雨も一緒に沈み SCROLL DOWN は前に残る。画面の最下部(下から約14%)には
	   文字が乗らないので濃くする必要がなく、黒く見える面積のほとんどはこの帯なので先に薄くするのが効く。
	   ぼかし(backdrop-filter)は使っていない ―― 毎フレーム描画されている領域をさらにぼかす負荷が大きい。 */
	/* SCROLL DOWN の合図はこの幅だけ出す(通常幅は上の @media で下ろしてある) */

	.canvas_sticky::after {
		content: '';
		position: absolute;
		inset: 0;
		z-index: 7;
		pointer-events: none;
		/* 濃さは js/3d_zone.js が --veil に書き込み、最後のポイントが消えるのと同じ区間で 1 → 0 に引く。
		   引かないと、固定が外れたときに canvas ごと上へ流れて黒い帯だけが画面の上部に現れて見える。 */
		opacity: var(--veil, 1);
		background: linear-gradient(to top,
			rgba(5, 5, 5, 0.72) 0%,
			rgba(5, 5, 5, 0.6) 22%,
			rgba(5, 5, 5, 0.38) 42%,
			rgba(5, 5, 5, 0.12) 58%,
			rgba(5, 5, 5, 0) 70%);
	}

	.label_desc_wrap {
		max-width: 100%;
	}

	/* この幅から 3D のポイント表示は中央寄せの縦組みレイアウトになる。文字サイズもそのレイアウト用に
	   vw 基準で組み直す。 */
	.label_title {
		/* 上限は PC へ切り替わる 1025px で PC 側が出す値。1024px と 1025px で大きさが揃う */
		font-size: clamp(10px, 13.93vw, 64.06px);
	}

	.label_desc {
		/* ここだけは PC と揃えない。PC が 1025px で出す 10.66px はこの幅では小さすぎるため、
		   上限を 14px に置く(切替の前後で 14px → 10.66px の差は残るが、読めるほうを採る)。 */
		font-size: clamp(10px, 3.48vw, 14px);
		/* 行間は Figma の SP 版(32 / 14.5)。通常幅の 2.6 のままだと行が離れて 3行が
		   ひとまとまりに見えず、字がばらけて読みにくい。 */
		line-height: 2.2;
	}

	/* タイトル / 本文 / ボタンの間隔は Figma の SP 版(402px 幅)の実寸から出す。
	   タイトルの行の高さも Figma と同じ 1.05 にする ―― 通常幅の 1.1 のままだと英字の行が
	   離れ、下に続く本文と合わせて全体がばらけて見える。
	   タイトル下 = 10 / 56(タイトル自身の em。字が伸縮しても同じ詰まり具合になる)
	   本文下     = 23 / 402(= 5.72vw。上下は狭い端末とタブレット幅での歯止め) */
	.label_title {
		line-height: 1.05;
		margin-bottom: 0.179em;
	}

	.label_more {
		margin-top: clamp(18px, 5.72vw, 26px);
	}

	/* 暗幕の上に、さらに文字自身の影を足す。暗幕は上へいくほど薄くなるため、その領域でも小さな文字が
	   沈まないようにする(タイトルには通常幅から影が入っているので、ここでは本文に足す)。 */
	.label_desc .label_line {
		text-shadow: 0 2px 10px rgba(0, 0, 0, 0.42);
	}

	/* 縦位置は js/3d_zone.js の layoutLabels() が sticky の top と持ち場の箱に書き込むので、ここでは
	   左右と幅だけを持つ(基準側の margin-left は js が外す。layoutFabricPoint 参照)。 */
	#point_hood,
	#point_fabric,
	#point_defy {
		margin-left: auto;
		margin-right: auto;
		text-align: center;
		width: calc(100% - 32px);
	}

	/* -------------------------------------------------------
	   products: slider (SP)。横に2枚並べる幅が無いので、コラージュと商品名を縦に積む。
	   1画面に収めるため、コラージュは「残り」を受け取る行(minmax(0, 1fr))に置き、商品名から下は
	   中身の高さぶんだけ取る。

	   さらにこの幅では、3型を「枠に固定したまま入れ替える」のをやめて**そのまま縦に積む**。
	   スマホの慣性スクロールは js から止められないので、ひと動きの送り・寄せ・慣性の受け止めは
	   どれも慣性との綱引きになり、「止まったり止まらなかったり」「払った向きと逆の型が出る」が
	   避けられなかった。スクロールに触る仕掛けごと下ろして、ふつうのページとして流す
	   (js 側も SP では動かない ―― main_zone.js の sliderStacked() を参照)。
	   ------------------------------------------------------- */

	.product_slider {
		/* 渡り切るための軌道は要らない。高さは積んだ3型が持つ */
		height: auto;
	}

	.product_slider_stage {
		position: static;
		height: auto;
		overflow: visible;
		/* 文字が収まってから、ボタンが広がるまでのひと呼吸 */
		--sp_more_delay: 0.42s;
	}

	/* 写真群は画面の上端から始める(この幅では写真そのものが見出しの役目を負うので、上に余白を置くと
	   「上に何か置き忘れた面」に見える)。下の余白は、通常幅でインジケーターに渡していたぶんが
	   そのまま型と型の間隔になる。足している (100lvh - 100svh) / 2 はブラウザ UI(URL バー)ぶんの
	   逃げ ―― 1型を 100lvh で取ってあるのでバーが出ているあいだは下端が裏に回る。ただし静的な値で
	   いまバーが出ているかは見ないため、丸ごと引かず半分だけ渡してある。
	   高さを 1画面ちょうどに固定しているので、box-sizing: border-box とあわせて
	   「1型 = 1画面(下の余白こみ)」になる。 */
	.product_slide {
		/* 重ねるのをやめ、ふつうに縦へ並べる */
		position: relative;
		inset: auto;
		visibility: visible;
		pointer-events: auto;
		height: 100vh;
		height: 100lvh;
		padding: 0 0 clamp(60px, 8.2vh, 104px);
		padding: 0 0 calc((100lvh - 100svh) / 2 + clamp(60px, 8.2vh, 104px));
	}

	/* -------------------------------------------------------
	   縦積みの出し方。js(updateStackedSlides)が .is_in を付ける。

	   出す単位は「写真群(.product_slide_collage)」と「文字群(.product_slide_body)」の2つ。
	   型ごと(1型まるごと)にすると、型の上端が入った時点で下のほうの文字まで動いてしまい、
	   文字が画面へ入る頃には動き終わっている。逆に要素ごと(マス1枚・行1本)にすると、
	   3枚の写真や文字の行がばらばらに出る。

	   きっかけは同じではない ―― **画面の位置を見るのは写真群だけ**で、文字群は同じ組の
	   写真群が出きったところで続く。文字群は型の下のほうにあるので、位置で出すと
	   写真より先に出たり、逆に遅れすぎたりする。

	   まとまりの中の出方は下の rule が持つ ―― 写真は3枚同時、文字はボタン以外が同時で、
	   ボタンだけひと呼吸おく。
	   ------------------------------------------------------- */

	/* 写真の出し方。下から上へマスクが開き、同時に写真が少し引く(1.3 → 1)。
	   マスクは枠(.collage_media)、引きは中の写真(下)が持つ。

	   パララックスもこの枠が持つ。中の写真ではなく枠を動かすのが要 ――
	   写真側の transform は拡大(.collage_piece_a.is_expanded)と PC のホバーが 1.2s で使っていて、
	   そこへ毎フレームの書き換えを足すと動きが1秒遅れて付いてくる。枠なら transition は
	   clip-path にしか掛けていないので、ずらしはそのまま即座に効く。
	   UV PARKA の重ね2枚(#parka_collage .collage_img)も、この枠の中なので一緒に動く。

	   ずらす余地は枠をマスより 6% 高く取って作る(上下に 3% ずつ)。js が書く --px はマスに対する
	   **px** で、最大でマスの高さの ±2.12%。余地の中に収まるので隙間が出ない。
	   px なのは、広げているあいだ高さが変わってもずらし量を変えないため(js 側のコメント参照)。
	   量を上げるときは height と top も一緒に増やすこと ―― 写真の縦の余白は 1枚目(全身)で
	   いちばん少なく、頭と足が切れない範囲がこのあたりで頭打ちになる。 */
	.collage_media {
		top: -3%;
		height: 106%;
		transform: translate3d(0, var(--px, 0px), 0);
		clip-path: inset(100% 0 0 0);
		transition: clip-path 0.7s cubic-bezier(0.16, 1, 0.3, 1);
	}

	/* 拡大したときに見せる重ねの1枚。**下の1枚(.collage_media)とまったく同じ枠にする**。

	   枠の高さが違うと object-fit: cover の拡大率も変わるので、押して 0.07 秒で下から重ねへ
	   すり替わる瞬間に写真の大きさが変わって見える(106% と 100% で 6% のずれ)。
	   上下のはみ出し(パララックスの余地)もずらし量も、2枚でまったく同じにしておく。

	   そのぶん広げたときの切り取りは上下 3% ずつ強くなるが、いちばん余白の薄い1枚目(全身)でも
	   頭上に 3.7%・足元に 1.4% 残る。 */
	.collage_zoom {
		inset: -3% 0;
		transform: translate3d(0, var(--px, 0px), 0);
	}

	/* 右の2枚は余地を広く取る。マスが左の半分の高さしかないので、同じ割合で動かすと
	   動く量も半分にしかならず、動いているのが分かりにくい(js 側で倍率を掛けている)。
	   寄りの写真なので、切り取りが上下 5% ずつ増えても中身は変わらない。
	   下の1枚と重ねの1枚は、ここでも必ず同じ値にすること(違うとすり替えで大きさが変わる)。 */
	.collage_piece_b .collage_media,
	.collage_piece_c .collage_media {
		top: -6%;
		height: 112%;
	}

	.collage_piece_b .collage_zoom,
	.collage_piece_c .collage_zoom {
		inset: -6% 0;
	}

	/* 3枚同時。マスごとのずらし(--cell_stagger)は使わない */
	.product_slide_collage.is_in .collage_media {
		clip-path: inset(0 0 0 0);
	}

	/* 文字は通常幅と同じ「行の枠の下から上げる」。待ち位置(枠の外)は通常幅の rule のまま。
	   行ごとのずらし(--line_stagger)は使わず、ボタン以外は同時に上がる。 */
	.product_slide_body.is_in .slide_line_inner,
	.product_slide_body.is_in .name_line_inner {
		transform: translateY(0);
		transition: transform var(--line_in_dur) var(--slide_ease);
	}

	/* 動き終わったら行の枠での切り取りをやめる(1px の枠線や色見本の縁が削れて見えるため) */
	.product_slide_body.is_settled .slide_line,
	.product_slide_body.is_settled .name_line {
		overflow: visible;
	}

	/* ボタンだけ、文字が収まったあとにひと呼吸おいて広がる */
	.more_pop {
		transform: scale(0);
	}

	.product_slide_body.is_in .more_pop {
		transform: scale(1);
		transition: transform var(--more_in_dur) var(--more_ease) var(--sp_more_delay);
	}

	/* 出るときの写真の引き(1.3 → 1)。マスクが開くのと同時に動く。

	   引きは transform ではなく独立プロパティの scale で持たせる。transform は写真の拡大
	   (.collage_piece_a.is_expanded / PC のホバー)が使っていて、そちらの 1.2s と尺が違うため。
	   元の transition も残して、拡大の動きは通常幅と同じままにしておく。 */
	.collage_piece .collage_media img {
		scale: 1.3;
		transition: transform 1.2s cubic-bezier(0.2, 0.7, 0.2, 1),
							scale 1s cubic-bezier(0.215, 0.61, 0.355, 1);
	}

	.product_slide_collage.is_in .collage_media img {
		scale: 1;
	}

	/* UV PARKA は色の入れ替えのために1マスに写真を2枚重ねてあり、その指定が id 付きで強い
	   (#parka_collage .collage_img)。引きも同じようにこちらへ渡す。色をすり替える opacity は残す。 */
	#parka_collage .collage_piece .collage_img {
		scale: 1.3;
		transition: opacity 0.4s ease 0.15s,
							transform 1.2s cubic-bezier(0.2, 0.7, 0.2, 1),
							scale 1s cubic-bezier(0.215, 0.61, 0.355, 1);
	}

	#parka_collage .collage_piece .collage_img.is_current {
		transition: opacity 0.55s ease,
							transform 1.2s cubic-bezier(0.2, 0.7, 0.2, 1),
							scale 1s cubic-bezier(0.215, 0.61, 0.355, 1);
	}

	#parka_collage.is_in .collage_img {
		scale: 1;
	}

	/* 縦積みでも同じ ―― こちらの id 付きの指定は通常幅の分より後ろにあるので、ここでも戻す。
	   scale を書かないのは 1、2型目(.collage_piece_a.is_expanded ...)に揃えるため。 */
	#parka_collage .collage_piece_a.is_expanded .collage_img,
	#parka_collage .collage_piece_a.is_collapsing .collage_img {
		transition: opacity 0.4s ease 0.15s,
							transform var(--collage_open_dur, 0.58s) var(--collage_open_ease, ease);
	}

	#parka_collage .collage_piece_a.is_expanded .collage_img.is_current,
	#parka_collage .collage_piece_a.is_collapsing .collage_img.is_current {
		transition: opacity 0.55s ease,
							transform var(--collage_open_dur, 0.58s) var(--collage_open_ease, ease);
	}

	/* 左右の余白はここでは持たない ―― 縦積みのこの幅では横幅がそのまま写真の大きさになるので、
	   写真群を画面の端から端まで使わせる。文字側の余白は .product_slide_body が自分で持つ。 */
	.product_slide_inner {
		width: 100%;
		padding-left: 0;
		padding-right: 0;
		grid-template-columns: minmax(0, 1fr);
		grid-template-rows: minmax(0, 1fr) auto;
		/* ここを詰めたぶんも写真群の高さになる */
		gap: clamp(12px, 2.4vw, 24px);
	}

	.product_slide_body {
		/* 最終行(MORE / 色見本)の高さ。1〜2型目は MORE だけ、3型目は色見本と MORE が並ぶので、
		   高さが違うと下の行(auto)の高さが型ごとに変わり、そのぶん写真群の行(1fr)が縮んで3型目だけ
		   写真が低くなる(実測で 11px)。両方をこの1つの値に合わせて、型をまたいで揃える。 */
		--sp_action_size: clamp(56px, 16vw, 96px);
		justify-content: flex-start;
		/* 行と行のあいだ。下の品番の行だけ、この値を基準に上下を振り分ける */
		--sp_body_gap: clamp(12px, 2.6vw, 22px);
		gap: var(--sp_body_gap);
		/* 縦積みでは左右の余白をここで持つ(.product_slide_inner に持たせると写真群まで内側へ寄る)。 */
		padding-left: var(--side_padding);
		padding-right: var(--side_padding);
	}

	/* 品番の行。写真群と商品名のちょうど真ん中にいると写真側へ寄って見えるので、上を広く
	   下を狭くする。下は gap 自体を変えると他の行にも効いてしまうため、負マージンで削る。
	   上に足す側は .product_slide_inner の gap(写真群との間)へ重なる。 */
	.product_slide_body > .slide_line:first-child {
		margin-top: var(--sp_body_gap);
		margin-bottom: calc(var(--sp_body_gap) * -0.5);
	}

	/* 品名はこの幅では1行に並べる。2つの語を包む .name_line は出のときの切り取り枠なので
	   消さず、横並びにするだけ ―― 語の間の空白は html の改行がそのまま効く。

	   vertical-align: top が要る。inline-block の既定(baseline)では、overflow が hidden の
	   ときだけ基準線が「下の余白の縁」に変わる決まりがあり、動き終わりに overflow を visible へ
	   戻す(.is_settled)瞬間に行の高さが変わってしまう。この幅では品名の上下が auto の行なので、
	   その変化が写真の行(1fr)へ回り、写真の大きさごと動いて見える。top なら overflow に
	   左右されない(同じ理由で .label_line にも入れてある)。 */
	.name_line {
		display: inline-block;
		vertical-align: top;
	}

	/* 1行に並べたぶん、収まるところまで小さくする。いちばん長いのは FOCUS JACKET で、
	   本文の幅(画面 - --side_padding の左右)に対しておよそ 8.3 文字ぶん。 */
	.product_slide_name {
		/* 上限は PC へ切り替わる 1025px で PC 側が出す値。1024px と 1025px で大きさが揃う */
		font-size: min(8.5vw, 64.06px);
	}

	/* 押すと拡大することを示す目印。指では「押せる」ことが伝わらないので、この幅だけ置く。
	   ::after は暗くする幕に使っているのでこちらは ::before。幕より前に出すため z-index を付ける。 */
	.collage_piece::before {
		content: '';
		position: absolute;
		right: clamp(6px, 1.8vw, 10px);
		bottom: clamp(6px, 1.8vw, 10px);
		width: clamp(20px, 6.4vw, 30px);
		height: clamp(20px, 6.4vw, 30px);
		/* 塗りは持たず線だけ。円も「+」も currentColor なので、濃さはここ1か所で決まる。
		   写真の邪魔にならないよう薄めに置く(出るときの opacity とは別物なので、
		   下の .is_in / .has_expanded の出し入れとはぶつからない)。 */
		color: rgba(255, 255, 255, 0.6);
		border: 1px solid currentColor;
		border-radius: 50%;
		/* 「+」は線2本。要素を増やさずに済むよう背景で描く(地色は敷かない) */
		background:
			linear-gradient(currentColor, currentColor) no-repeat center / 40% 1px,
			linear-gradient(currentColor, currentColor) no-repeat center / 1px 40%;
		z-index: 3;
		/* 当たり判定はマス自身が持つので、印は触らせない */
		pointer-events: none;
		/* 写真より先に出てしまわないよう、はじめは消しておく(下の .is_in で出す) */
		opacity: 0;
		transition: opacity 0.45s linear;
	}

	/* 写真のマスクが開ききるころに出す。写真は 0.7s で開くので、そのあとから遅れて現れる。
	   閉じたあとに戻るときもこの遅れが効き、枠が縮みきってから出る。 */
	.product_slide_collage.is_in .collage_piece::before {
		opacity: 1;
		transition-delay: 0.6s;
	}

	/* どれかが開いているあいだは引っ込める(開いた1枚の上に印が残らないように)。
	   消えるのは押した瞬間 ―― transition を切っているのは、上の .is_in が持つ 0.6s の遅れが
	   こちらにも効いてしまい、押してから印が消えるまで間が空くため。戻るときは .has_expanded が
	   外れてこの規則ごと効かなくなるので、上の遅れつきの出方に戻る。 */
	.product_slide_collage.has_expanded .collage_piece::before {
		opacity: 0;
		transition: none;
	}

	.product_color_tile {
		/* 正方形は aspect-ratio が持つので、高さを渡せば幅は付いてくる */
		width: auto;
		height: 100%;
	}

	.product_color_name {
		font-size: clamp(9px, 2.2vw, 12px);
	}

	/* MORE は PC ほど主張させない。写真群が画面幅いっぱいになったぶん、同じ大きさだと文字側で丸だけが
	   目立つ。中の「+」と文字は vw の下限に張り付いているので、丸だけが締まる。 */
	.view_more_btn.product_slide_more {
		--more_size: var(--sp_action_size);
	}

	/* 色見本も最終行の高さに収める。高さを決めてタイルに残りを受けさせるので(色名は成り行き)、
	   色名の行送りが変わってもずれない。 */
	.product_color {
		height: var(--sp_action_size);
		grid-template-rows: minmax(0, 1fr) auto;
		gap: clamp(4px, 1.2vw, 8px);
	}

	/* この幅は3型を縦に積んでいて、どれも見えている。いま何型目かを示すものも、押して型を
	   飛ばす先も無いので置かない(押したときの送りは js 側でも止めてある)。 */
	.product_slider_nav {
		display: none;
	}

	/* -------------------------------------------------------
	   story(SP)。作りは通常幅と同じで、大きさと余白だけこの幅に合わせる。
	   区間の長さ(--story_travel)も出し方も共通 ―― ここでスクロールに触っていないので、
	   スマホでも綱引きが起きない。
	   ------------------------------------------------------- */
	/* 幅は通常幅と同じ min(36em, 100%) のまま。この幅では 36em が画面に入らないので
	   100%(= .story_pin の padding を除いた幅)が効き、1行は 20文字になる。 */
	.story_texts {
		/* 上限は PC へ切り替わる 1025px で PC 側が出す値。1024px と 1025px で大きさが揃う */
		font-size: clamp(10px, 3.98vw, 19.17px);
	}

	/* ぼかし済みの絵へ切り替える(理由は .story_logo::before のところに書いてある)。
	   この幅は指で触る端末が主で、iOS 以外でも実行時のぼかしは負担が大きい。 */
	.story_logo::before {
		/* 実行時のぼかしはやめ、濃さの入れ替えに回る */
		filter: none;
		opacity: calc(1 - var(--story_logo_away, 0));
	}

	.story_logo::after {
		display: block;
		opacity: var(--story_logo_away, 0);
	}

	/* PC でだけ入れている改行(FOCUS / UV)は、この幅では落とす */
	.br_pc {
		display: none;
	}

	.product_slider_tab_name {
		font-size: clamp(8px, 2.2vw, 11px);
	}

	.noise_light {
		width: 20%;
	}
}
/* =========================================================
   loader: 読み込みが終わるまで全面に出す画面。地は黒一色、文字はサイトと同じディスプレイ書体、
   進み具合は 1px の線。読み終わると LOADING が TIME TO LOCK IN. に、進み具合の線が ENTER に
   入れ替わる(2つの状態は同じマスに重ねてあり、opacity で入れ替わる)。
   ========================================================= */

/* 読み終わると ENTER のピント枠の内側だけ黒地が四角く抜け、その窓から MV がのぞく。押すと窓が
   四角のまま画面いっぱいまで広がる。穴はひとつだけで、窓の大きさ(--cut_w / --cut_h)と位置
   (--cut_x / --cut_y)を動かすだけ。枠の実測値は js/main_zone.js の measureCut が書き込む。 */
.loader {
	/* ENTER のピント合わせが始まる時刻(進み具合の線が引いたあと) */
	--af_start: 0.62s;
	/* 読み込みの進み具合(0..1)。js が毎フレーム書き込む。見出しのぼけに使う */
	--load_p: 0;
	/* ピント枠が寄ってくる距離。--af_far から --af_mid を経て 0 へ */
	--af_far: clamp(12px, 1.8vw, 26px);
	--af_mid: clamp(5px, 0.7vw, 10px);
	/* ホバー/フォーカスでさらに内へ詰める量。窓もこのぶんだけ狭くなる */
	--af_tight: clamp(3px, 0.45vw, 7px);
	/* いま窓を詰めている量。ふだんは 0 で、押せるときだけ --af_tight になる */
	--cut_tight: 0px;
	/* 窓が広がりきるまでの時間。js もこの尺に合わせて後片付けする */
	--reveal_sweep: 1.05s;
	/* ENTER を切り抜く窓。ピント枠(.loader_af)の実測値を js が書き込む。
	   --cut_c* は窓の中心で、窓が開く前(大きさ 0)の置き場所に使う。 */
	--cut_x: 50%;
	--cut_y: 50%;
	--cut_w: 0px;
	--cut_h: 0px;
	--cut_cx: 50%;
	--cut_cy: 50%;
	/* 窓が開く時刻と尺。ピントが合う瞬間(af_lock の 64%)に合わせてある */
	--cut_open_at: calc(var(--af_start) + 0.64s);
	--cut_open: 0.5s;
	position: fixed;
	inset: 0;
	/* 共通ヘッダー(9000)・モーダル(10000)よりさらに手前 */
	z-index: 100000;
	/* 地色は持たない。黒く覆うのは中の .loader_hood で、そこだけが窓の形に抜けていく。 */
	pointer-events: auto;
	/* 窓が広がりきってから、当たり判定ごと片付ける */
	transition: visibility 0s linear var(--reveal_sweep);
}

/* 2回目以降。出さずに丸ごと畳む ―― .is_done の「窓が広がって黒地を持っていく」動きは
   見せる必要がないので、最初から無かったことにする。
   目印(html.loader_seen)は zone.phtml の head で付ける。js の本体で付けると、
   そこに届くまでに .loader がいちど描かれて一瞬ちらつく。 */
html.loader_seen .loader {
	display: none;
}

/* 2回目以降に出す短い読み込み画面。黒一色で全面を覆い、読み終わってスクロール位置の復元が
   済んだところでフェードアウトする(合図は js/main_zone.js の loader が .is_done を付ける)。
   これが無いと、更新したときに位置の復元が済むまでの一瞬 MV が映ってちらつく。
   出すのは .loader と入れ替わりの html.loader_seen のときだけ ―― head で付くので最初の描画から覆える。 */
.loader_short {
	display: none;
	position: fixed;
	inset: 0;
	z-index: 100000;
	background: var(--c_black);
	pointer-events: none;
}

html.loader_seen .loader_short {
	display: block;
}

.loader_short.is_done {
	opacity: 0;
	transition: opacity 1s cubic-bezier(0.455, 0.03, 0.515, 0.955);
}

@media (prefers-reduced-motion: reduce) {
	.loader_short.is_done {
		transition-duration: 0.3s;
	}
}

/* ENTER を押したあと */
.loader.is_done {
	pointer-events: none;
	visibility: hidden;
}

.loader_hood {
	position: absolute;
	inset: 0;
	background: var(--c_black);
}

/* 窓の抜き方。全面(1層目)から窓(2層目)を subtract するだけなので、
   動かすのは窓の大きさと位置のふたつきり。 */
@supports (mask-composite: subtract) {
	.loader_hood {
		mask-image: linear-gradient(#000, #000), linear-gradient(#000, #000);
		mask-repeat: no-repeat;
		mask-composite: subtract, add;
		/* はじめは枠の中心に畳んである(大きさ 0 = 穴なし) */
		mask-size: 100% 100%, 0 0;
		mask-position: 0 0, var(--cut_cx) var(--cut_cy);
	}

	/* 読み終わり。窓は枠の内側いっぱい(--cut_tight ぶんだけ内へ詰めた大きさ)で、ピントが合う瞬間まで
	   transition-delay で待たせてから開く。animation ではなく transition なのは、開ききる前に ENTER を
	   押されたとき、animation だと取り消した時点の見た目から続けられず飛ぶため。 */
	.loader.is_ready .loader_hood {
		mask-size:
			100% 100%,
			calc(var(--cut_w) - var(--cut_tight) * 2) calc(var(--cut_h) - var(--cut_tight) * 2);
		mask-position:
			0 0,
			calc(var(--cut_x) + var(--cut_tight)) calc(var(--cut_y) + var(--cut_tight));
		transition:
			mask-size var(--cut_open) cubic-bezier(0.2, 0.7, 0.2, 1) var(--cut_open_at),
			mask-position var(--cut_open) cubic-bezier(0.2, 0.7, 0.2, 1) var(--cut_open_at);
	}

	/* 登場が終わったあと(js が .is_locked を付ける)。待ち時間を外して、ホバーの出入りが遅れずに
	   追いつくようにする。4隅の枠(--af_tight)と同じ尺・同じ曲線。 */
	.loader.is_locked .loader_hood {
		transition:
			mask-size 0.45s cubic-bezier(0.2, 0.7, 0.2, 1),
			mask-position 0.45s cubic-bezier(0.2, 0.7, 0.2, 1);
	}

	/* ENTER。同じ窓が四角のまま画面いっぱいへ広がる。数 px はみ出させるのは、端でちょうど止めると
	   縁に黒が一本残って見えるため。開いている途中で押された場合は、いまいる大きさからそのまま続く。 */
	.loader.is_done .loader_hood {
		mask-size: 100% 100%, calc(100% + 4px) calc(100% + 4px);
		mask-position: 0 0, -2px -2px;
		transition:
			mask-size var(--reveal_sweep) cubic-bezier(0.32, 0, 0.1, 1),
			mask-position var(--reveal_sweep) cubic-bezier(0.32, 0, 0.1, 1);
	}

	/* 窓が開くと ENTER の文字の下は MV の静止画(白っぽい)になるので、開くのと同時に黒へ替える。
	   窓は中央から広がり文字はその真ん中にあるので、窓の尺より短く替えきる。
	   窓が開かない環境(下の @supports not)では黒地のままなので白のまま。 */
	.loader.is_ready .loader_enter_label {
		color: var(--c_black);
		transition:
			opacity 0.4s ease,
			color 0.25s ease var(--cut_open_at);
	}
}

/* mask-composite が使えない環境。窓は開かないが、押したあとは黒地がそのまま引いていくので
   行き止まりにはならない。 */
@supports not (mask-composite: subtract) {
	.loader.is_done .loader_hood {
		opacity: 0;
		transition: opacity var(--reveal_sweep) ease;
	}
}

/* 文字と ENTER を置く面。黒地(.loader_hood)の外に出してあるのは、黒地の方を窓の形に切り抜くため
   ―― 中に置いたままだと ENTER の文字や枠まで一緒に消えてしまう。 */
.loader_stage {
	position: absolute;
	inset: 0;
	z-index: 1;
	display: grid;
	place-items: center;
	padding: 0 clamp(20px, 6vw, 80px);
}

/* 中身は穴に飲まれる前に引く(ふちで文字が半端に切れたままにならないように) */
.loader.is_done .loader_inner {
	opacity: 0;
	transition: opacity 0.3s ease;
}

/* 画面の四隅を落として中央へ視線を集め、ごく薄い走査線を重ねる。他のセクションのノイズ表現と
   同じ質感を画像を使わずに出す(読み込み中の画面なので、それ自体が重くなっては本末転倒)。 */
.loader_grain {
	position: absolute;
	inset: 0;
	pointer-events: none;
	background: radial-gradient(115% 85% at 50% 50%, rgba(255, 255, 255, 0.055), rgba(0, 0, 0, 0) 62%);
}

.loader_grain::after {
	content: '';
	position: absolute;
	inset: -4px;
	background: repeating-linear-gradient(
		to bottom,
		rgba(255, 255, 255, 0.03) 0 1px,
		rgba(0, 0, 0, 0) 1px 3px
	);
	animation: loader_scan 6s linear infinite;
}

@keyframes loader_scan {
	to {
		transform: translateY(3px);
	}
}

.loader_inner {
	position: relative;
	z-index: 1;
	display: grid;
	justify-items: center;
	gap: clamp(36px, 7vh, 88px);
	width: 100%;
}

.loader_head,
.loader_foot {
	display: grid;
	justify-items: center;
	width: 100%;
}

/* 進み具合の線と ENTER の2つを同じマスに重ねて置く。枠の高さは背の高い方(ENTER のピント枠)で
   決まるので、入れ替わっても見出しとの間合いが動かない。 */
.loader_state {
	grid-area: 1 / 1;
	/* 枠は背の高い方に合わせて決まるので、低い方は中央に置く */
	place-self: center;
	text-align: center;
}

/* 出ていない側は、透明でも押せてしまわないようにしておく */
.loader_state_ready {
	pointer-events: none;
}

.loader.is_ready .loader_state_load {
	pointer-events: none;
}

.loader.is_ready .loader_state_ready {
	pointer-events: auto;
}

/* 入れ替わるのは進み具合の線と ENTER だけ(見出しは最初から出ている)。かたまりごとではなく要素
   ひとつずつで、まず数字が引き、線が続いて場が空き、そこへ ENTER が入る ―― 同時だと一瞬重なって
   濁るのと、順に動いた方が「合図が伝わっていく」ように見えるため。順番は transition-delay で決める。 */
.loader_meter_num,
.loader_meter_track {
	transition: opacity 0.5s ease,
	            transform 0.5s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.loader.is_ready .loader_meter_num,
.loader.is_ready .loader_meter_track {
	opacity: 0;
	transform: translateY(-12px);
}

/* 引く側 */
.loader.is_ready .loader_meter_num { transition-delay: 0s; }
.loader.is_ready .loader_meter_track { transition-delay: 0.07s; }

/* 見出しは最初から出ていて、はじめはぼけている。進み具合(--load_p)がそのままぼけの量になり、
   読み終わったところで像を結ぶ ―― 待たせている時間そのものが「ピントを合わせている時間」になる。
   ぼかす量が字の大きさに対して同じ割合になるよう、見出しと日本語で --load_blur を分けてある。 */
.loader_ready_en,
.loader_ready_ja {
	--load_blur: 18px;
	filter: blur(calc((1 - var(--load_p)) * var(--load_blur)));
	/* ぼけているあいだは少し引かせる。像を結ぶにつれて出てくる */
	opacity: calc(0.42 + var(--load_p) * 0.58);
	will-change: filter;
}

.loader_ready_ja {
	--load_blur: 7px;
}

/* ENTER は自分でピント合わせの動き(af_lock / af_sharpen)を持っていてその中で現れきるので、
   ここでは動きが始まる時刻に合わせて置くだけにする。 */
.loader_enter {
	opacity: 0;
}

.loader.is_ready .loader_enter {
	opacity: 1;
	transition: opacity 0s linear var(--af_start);
}

/* --- 読み込み中 --- */

.loader_meter {
	display: grid;
	justify-items: center;
	gap: clamp(10px, 1.6vh, 18px);
}

.loader_meter_num {
	font-family: var(--font_display);
	font-weight: 700;
	font-size: clamp(10px, 0.9vw, 14px);
	letter-spacing: 0.24em;
	text-indent: 0.24em;
	color: rgba(255, 255, 255, 0.7);
	/* 数字の桁が変わっても線が動かないように、等幅の数字で出す */
	font-variant-numeric: tabular-nums;
}

.loader_meter_track {
	display: block;
	position: relative;
	width: clamp(180px, 26vw, 420px);
	height: 1px;
	background: rgba(255, 255, 255, 0.2);
	overflow: hidden;
}

/* 伸び具合は js/main_zone.js が scaleX で毎フレーム書き込む */
.loader_meter_fill {
	position: absolute;
	inset: 0;
	background: var(--c_white);
	transform: scaleX(0);
	transform-origin: 0 50%;
}

/* --- 見出し(読み込み中から出ている) --- */

.loader_ready_en {
	margin: 0;
	font-family: var(--font_display);
	font-weight: 500;
	font-size: clamp(34px, 7.4vw, 132px);
	line-height: 1.05;
	letter-spacing: 0.06em;
	text-indent: 0.04em;
	color: var(--c_white);
}

.loader_ready_ja {
	margin: clamp(16px, 2.6vh, 34px) 0 0;
	font-family: var(--font_jp);
	font-size: clamp(11px, 1.15vw, 20px);
	/* サイト内の同じ言い回しに合わせた字間 */
	letter-spacing: 0.45em;
	text-indent: 0.45em;
	color: rgba(255, 255, 255, 0.78);
}

/* ENTER は、消えた線とちょうど同じ幅の線を連れている。線はその場に残ったまま上の文字だけが
   変わったように見え、進み具合の線がそのまま入口になる。 */
.loader_enter {
	appearance: none;
	-webkit-appearance: none;
	background: none;
	border: 0;
	padding: 0;
	display: block;
	font: inherit;
	color: inherit;
	cursor: pointer;
}

.loader_enter_label {
	display: block;
	font-family: var(--font_display);
	font-weight: 700;
	font-size: clamp(11px, 1vw, 15px);
	letter-spacing: 0.42em;
	text-indent: 0.42em;
	color: var(--c_white);
	transition: opacity 0.4s ease;
}

/* ENTER は、カメラがピントを合わせる所作で現れる ―― 4隅の枠が外から寄ってきて2度またたき、
   同時に文字のぼけが取れて像を結ぶ。下の線は読み込み中のバーがそのまま残ったものなので、
   ここでは動かさない(動かすと、バーから入れ替わった連なりが切れて見える)。 */
.loader_af {
	position: relative;
	display: block;
	padding: clamp(12px, 1.4vw, 21px) clamp(22px, 2.8vw, 46px);
}

.loader_af_corner {
	position: absolute;
	width: clamp(11px, 1.2vw, 18px);
	height: clamp(11px, 1.2vw, 18px);
	border: 1px solid var(--c_white);
	transition: transform 0.45s cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* 各隅は、それぞれ外側の斜め方向から寄ってくる(--dx / --dy がその向き) */
.loader_af_tl {
	top: 0;
	left: 0;
	border-right: 0;
	border-bottom: 0;
	--dx: -1;
	--dy: -1;
}

.loader_af_tr {
	top: 0;
	right: 0;
	border-left: 0;
	border-bottom: 0;
	--dx: 1;
	--dy: -1;
}

.loader_af_bl {
	bottom: 0;
	left: 0;
	border-right: 0;
	border-top: 0;
	--dx: -1;
	--dy: 1;
}

.loader_af_br {
	bottom: 0;
	right: 0;
	border-left: 0;
	border-top: 0;
	--dx: 1;
	--dy: 1;
}

/* ピントが合う動き。fill-mode を backwards にしてあるので、待ち時間のあいだは 0%(外側でまだ
   見えていない状態)、終わったあとは各要素の素の指定(= 合った状態)へ戻る。 */
.loader.is_ready .loader_af_corner {
	animation: af_lock 1.05s cubic-bezier(0.2, 0.7, 0.2, 1) var(--af_start) backwards;
}

@keyframes af_lock {
	/* 迷っている(まだ遠い) */
	0% {
		opacity: 0;
		transform: translate(calc(var(--dx) * var(--af_far)), calc(var(--dy) * var(--af_far)));
	}
	22% {
		opacity: 0.55;
	}
	/* 手前まで寄る */
	40% {
		opacity: 1;
		transform: translate(calc(var(--dx) * var(--af_mid)), calc(var(--dy) * var(--af_mid)));
	}
	/* ピッ(1回目) */
	47% {
		opacity: 0.2;
	}
	54% {
		opacity: 1;
	}
	/* 合った */
	64% {
		transform: translate(0, 0);
	}
	/* ピッ(2回目) */
	71% {
		opacity: 0.2;
	}
	78% {
		opacity: 1;
	}
	100% {
		opacity: 1;
		transform: translate(0, 0);
	}
}

/* 枠が合うのに合わせて、文字のぼけも取れていく */
.loader.is_ready .loader_enter_label {
	animation: af_sharpen 1.05s cubic-bezier(0.2, 0.7, 0.2, 1) var(--af_start) backwards;
}

@keyframes af_sharpen {
	0% {
		opacity: 0;
		filter: blur(7px);
	}
	40% {
		opacity: 0.85;
		filter: blur(2.6px);
	}
	64% {
		opacity: 1;
		filter: blur(0);
	}
	100% {
		opacity: 1;
		filter: blur(0);
	}
}

/* 押せることは、4隅だけがもう一段内へ寄ることで示す(もう一度ピントを詰める動き)。文字は動かさない。 */
@media (hover: hover) {
	.loader.is_locked .loader_enter:hover .loader_af_corner {
		transform: translate(
			calc(var(--dx) * var(--af_tight) * -1),
			calc(var(--dy) * var(--af_tight) * -1)
		);
	}
}

.loader.is_locked .loader_enter:focus-visible .loader_af_corner {
	transform: translate(
		calc(var(--dx) * var(--af_tight) * -1),
		calc(var(--dy) * var(--af_tight) * -1)
	);
}

/* 4隅が内へ寄るのに合わせて窓もそのぶん狭くなる(枠と窓のふちが離れると「枠の内側が抜けている」
   という関係が崩れるため)。変えるのは詰める量(--cut_tight)だけ。効き始めるのは登場が終わってから
   (.is_locked)―― カーソルが最初から ENTER の上にあると、登場の途中から詰まって食い違って見える。 */
@media (hover: hover) {
	.loader.is_locked:has(.loader_enter:hover) {
		--cut_tight: var(--af_tight);
	}
}

.loader.is_locked:has(.loader_enter:focus-visible) {
	--cut_tight: var(--af_tight);
}

@media (prefers-reduced-motion: reduce) {
	.loader.is_ready .loader_af_corner,
	.loader.is_ready .loader_enter_label {
		animation: none;
	}

	.loader_af_corner {
		transition-duration: 0.01ms;
	}
}

/* キーボードで Tab してきた時だけ出す枠。ブラウザ標準の枠は文字のすぐ外に密着して窮屈に見えるので、
   余白を取った細い線に置き換える(マウスで押した時やスクリプトからの focus では出ない)。 */
.loader_enter:focus {
	outline: none;
}

.loader_enter:focus-visible {
	outline: 1px solid rgba(255, 255, 255, 0.5);
	outline-offset: clamp(12px, 1.6vw, 24px);
}

/* 読み込み中はスクロールを止めておく(js が付け外しする) */
html.is_loading {
	/* PC のホイールはこれで止まる */
	overflow: hidden;
	/* 指でのパン。ただし iOS はルート要素(html)に掛けた touch-action を見てくれないので、
	   これだけでは止まらない ―― 実際に効かせているのは js/main_zone.js の blockLoaderTouch
	   (touchmove を preventDefault で断つ)。ここは他のブラウザ向けの保険。 */
	touch-action: pan-x pinch-zoom;
}

@media (prefers-reduced-motion: reduce) {
	.loader_grain::after {
		animation: none;
	}

	/* 尺だけ 0 にしても待ち時間は残るので、そちらも外す */
	.loader.is_ready .loader_hood,
	.loader.is_ready .loader_enter_label {
		transition-delay: 0s;
	}

	/* ぼけたままにはせず、はじめから像を結んだ状態で出す */
	.loader_ready_en,
	.loader_ready_ja {
		filter: none;
		opacity: 1;
	}

	.loader,
	.loader.is_ready .loader_hood,
	.loader.is_done .loader_hood,
	.loader_meter_num,
	.loader_meter_track,
	.loader_af_corner {
		transition-duration: 0.01ms;
	}
}

@media (max-width: 1024px) {
	.loader_ready_ja {
		letter-spacing: 0.3em;
		text-indent: 0.3em;
	}

	.loader_meter_track {
		width: min(62vw, 320px);
	}
	.story_text {
		line-height: 2.55;
	}
}
