/**
 * KVブロック
 *
 * 参照実装: docs/kv-motion.html（トップKVの確定版）
 * 設計の意図（transform/translateの使い分け・will-changeを付けない理由・
 * マスクを使う理由）は docs/implementation-handoff.md の5章を必ず読むこと。
 *
 * 数値トークンは theme.json settings.custom.kv（--wp--custom--kv--*）を参照する。
 * ブレークポイントは settings.viewport.tablet（WP7.1デフォルトの782px）に揃えている。
 * @tablet は 480px < width <= 782px なので、ここは783pxから切り替える
 * （782pxにすると@tabletの範囲と1px重なり、コアの@tabletレスポンシブスタイルと
 * 二重管理になる）。
 */

.kv {
	/* ---- 調整用トークン（実体は theme.json） ---- */
	--amp: var(--wp--custom--kv--amp);
	--speed: var(--wp--custom--kv--speed);
	--spin: var(--wp--custom--kv--spin);
	--noise: var(--wp--custom--kv--noise);
	--title: var(--wp--custom--kv--title-sm);
	--shape-scale: var(--wp--custom--kv--shape-scale-sm);
	--panel-inset: var(--wp--custom--kv--panel-inset-sm);
	--intro-from: var(--wp--custom--kv--intro-from);
	--intro-dur: var(--wp--custom--kv--intro-dur);
	--intro-content-delay: var(--wp--custom--kv--intro-content-delay);

	/* ---- 色（ブランドパレットのエイリアス） ---- */
	--c-cyan: var(--wp--preset--color--cyan);
	--c-blue: var(--wp--preset--color--blue);
	--c-tarosky-blue: var(--wp--preset--color--tarosky-blue);
	--c-bg: var(--wp--preset--color--beige);
	--c-ink: var(--wp--preset--color--ink);
	/* KVパネル内の文言色。実測でAA達成済みの確定値。
	   変更する場合はコントラストを再測定すること（本文4.5:1 / 大きい文字3:1）。 */
	--c-text: #2E3336;

	position: relative;
	isolation: isolate; /* ブレンドの合成範囲をKV内に閉じる */
	height: 100vh;
	height: 100svh; /* モバイルのURLバー分を含まない高さ */
	min-height: 600px; /* 極端に低いビューポートでも中身が潰れないように */
	overflow: hidden;
}

/* hamelpのAI回答（.hamelp-ai-overview__turn）が現れたら、ビューポート高さ固定を解除。
   .kv__content は通常フロー内の子（position:relativeだが絶対配置ではない）なので、
   heightをautoにすると回答の実際の高さぶんKV自体が伸びる。長文の回答が
   overflow:hiddenで見切れるのを防ぐのが目的。
   .kv__panel（ベージュ地）は`inset`で.kvの上下端を参照しているだけなので、
   .kvが伸びれば追従して一緒に伸びる（別途高さ指定は不要）。
   JSでの監視（MutationObserver等）ではなく:has()にしているのは、
   「そのDOMが存在するか」だけの条件でJSを増やす理由が無いため
   （:has()は既にcss/global.css・core-group.cssで使用実績あり）。 */
.kv:has(.hamelp-ai-overview__turn) {
	height: auto;
	/* 通常時のmin-height: 600pxのままだと回答が短い時にKVが小さくなり得るため、
	   最低でも1画面ぶんは確保する。 */
	min-height: 100vh;
	min-height: 100svh;
}

/* ヘッダー（.header、position:sticky、透過）の下に潜り込ませ、上端を
   ヘッダーの上端＝ページ最上部に揃える。.kv__panel側のinsetがheader-hぶん
   確保しているので、二重に空けないようここで相殺する。
   !important が必要な理由：コアの
   `:root :where(.is-layout-constrained) > :first-child{margin-block-start:0}`
   は、:first-child が :where() の外にあるため詳細度は(0,2,0)。
   単純なクラス／type+classでは上回れず、読み込み順でも負ける
   （このCSSファイルはglobal-styles-inline-cssより先に読み込まれるため）。
   --wp--style--block-gap ぶんも追加で引いているのは、.kv（mainの最初の子）の
   負のマージンが親のmainのマージンと相殺（マージン相殺）されるとき、
   mainがブロック間の標準ギャップ（16px）を持ち込んでくるため。 */
.kv {
	margin-top: calc(-1 * var(--header-h) - var(--wp--style--block-gap, 16px)) !important;
}

@media (min-width: 783px) {
	.kv {
		--title: var(--wp--custom--kv--title-lg);
		--shape-scale: var(--wp--custom--kv--shape-scale-lg);
		--panel-inset: var(--wp--custom--kv--panel-inset-lg);
	}
}

/* ベージュのパネル。見た目だけを担当し、クリップはしない。
   図形はこのパネルより手前に置かれるので、外周を突破して白地へはみ出せる。
   overflow:hidden は ::after のノイズを角丸の内側だけに収めるため。 */
.kv__panel {
	position: absolute;
	inset: var(--header-h) var(--panel-inset) var(--panel-inset);
	background: var(--c-bg);
	border-radius: 16px;
	overflow: hidden;
}

/* ========== グレイン（ノイズ） ==========
   Figmaのノイズ設定を再現。ブレンドモードは使わない（毎フレーム広範囲の
   再合成が発生して重いため）。画像として1回描かれるだけなので、動いても
   負荷が増えない。

   グレインはベージュのパネルと、幾何学の弧（リング状のもの）にだけかける。
   何もない余白まで含めた全面には敷かない。

   以前はSVGのfeTurbulenceフィルターをCSSのbackground-imageとして直接
   埋め込んでいたが、baseFrequencyが高い（=2）ためブラウザの実際の描画
   解像度（devicePixelRatio・ズーム倍率）によってノイズの再サンプリングの
   され方が変わり、環境によって粒がまだらな三角形状に化ける不具合があった。
   4倍解像度でレンダリングしてから縮小（アンチエイリアス）することで
   解像度非依存の安定した見た目にした静止画（assets/images/grain-noise.webp）
   に差し替えている。これによりrender.php側の「SVG内部参照url(#n)が壊れる
   問題を回避するための本物の<style>直接出力」という特殊対応も不要になった。 */
.kv__panel::after {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	opacity: var(--noise);
	background-image: url("../../assets/images/grain-noise.webp");
	background-size: 220px 220px;
}

/* ========== 読み込み時のズームイン ==========
   弧をまとめて1枚の層として、遠く（小さく）から定位置へ寄せる。
   1回きりなので、検索窓のタイピング演出（未実装）と時間的に競合しない。
   transform と opacity だけなのでGPUで完結する。 */
.kv__arcs {
	position: absolute;
	inset: 0;
	pointer-events: none;
	transform-origin: 50% 45%;
	animation: kv-intro var(--intro-dur) cubic-bezier(.16, 1, .3, 1) both;
}

@keyframes kv-intro {
	from { transform: scale(var(--intro-from)); opacity: 0; }
	to   { transform: scale(1); opacity: 1; }
}

/* コンテンツは弧より少し遅れて出す（弧が着地してから読ませる） */
.kv__content,
.kv__title {
	animation: kv-fade-up .9s cubic-bezier(.16, 1, .3, 1) both;
	animation-delay: var(--intro-content-delay);
}

@keyframes kv-fade-up {
	from { opacity: 0; transform: translateY(16px); }
	to   { opacity: 1; transform: translateY(0); }
}

/* ========== 弧レイヤー ========== */
.arc {
	position: absolute;
	pointer-events: none; /* 背景がクリックを食わないように */
}

/* conic-gradient は SVG の stroke に使えないので、divの背景に敷いて
   radial-gradientのマスクでリング状にくり抜く。マスクは回転対称なので、
   中身（.arc__grad）を回してもリングの形は崩れない。 */
.arc--ring {
	border-radius: 50%;
	mix-blend-mode: multiply;
	-webkit-mask: radial-gradient(closest-side,
		#0000 calc(100% - var(--ring-thickness)),
		#000 calc(100% - var(--ring-thickness)) 100%, #0000 100%);
	mask: radial-gradient(closest-side,
		#0000 calc(100% - var(--ring-thickness)),
		#000 calc(100% - var(--ring-thickness)) 100%, #0000 100%);
}

/* リング状の弧のグレイン。マスクは親（.arc--ring）にかかっているので、
   ::after もリング形状に自動でクリップされる（マスクは要素の描画結果
   全体＝子要素・疑似要素を含めて切り抜くため）。回転はしない
   （ノイズ自体は静的な1枚絵のままでよく、動かす必要がない）。 */
.arc--ring::after {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	opacity: var(--noise);
	background-image: url("../../assets/images/grain-noise.webp");
	background-size: 220px 220px;
}

/* 左上：緑のリング。塗りは子要素側（回転させるため） */
.arc--ring-green {
	aspect-ratio: 1;
	--ring-thickness: 36%;
	mix-blend-mode: normal; /* 緑は乗算だと沈むので通常合成 */
}

/* このリングだけグレインを外す。透明にフェードする面積が広く、色が薄い分
   ノイズの粒だけが目立ってザラついて見えたため（他のリング・パネルは
   ベタ塗りの面積が広く馴染むので、そちらは残す）。 */
.arc--ring-green::after {
	content: none;
}

/* 緑→透明のconic。境目はタイトに切る。
   透明は transparent キーワードではなく同色のアルファ0（#8CD96B00）を使う。
   こうしないとブラウザによっては黒方向に濁って抜ける。 */
.arc__grad--green {
	background: conic-gradient(from 140deg,
		var(--wp--preset--color--green) 0deg,
		var(--wp--preset--color--green) 190deg,
		#8CD96B00 208deg,
		#8CD96B00 360deg);
	animation-duration: calc(54s * var(--spin)); /* 他と揃わないようズラす */
}

/* 左：343×335。外径171.32/内径112.093 → 太さ34.57% */
.arc--ring-left {
	aspect-ratio: 343 / 335;
	--ring-thickness: 34.57%;
}

/* 右下：1055×1030。外径527.3/内径410.32 → 内径は外径の77.82%、太さ22.18% */
.arc--ring-br {
	aspect-ratio: 1055 / 1030;
	--ring-thickness: 22.18%;
	/* 自分のサイズ基準でずらす。1つ目=横、2つ目=縦。
	   位置指定なので、アニメーションが使う transform とは競合しない独立した
	   translate プロパティを使う（translate → transform の順に適用される）。
	   縦だけ calc() で40px分引いて、少し上に上げている。 */
	translate: 50% calc(75% - 40px);
}

/* グラデ層の共通。マスクは回転対称なので中身を回しても形は崩れない。
   insetを少し外に出しているのは、回転時に四隅が足りなくなる保険。 */
.arc__grad {
	position: absolute;
	inset: -4%;
	border-radius: 50%;
	animation-name: spin;
	animation-timing-function: linear;
	animation-iteration-count: infinite;
}

/* 左リング：conic。Figmaは from 90deg ＋ 行列で90°回転なので素のCSSでは180degが等価 */
.arc__grad--left {
	background: conic-gradient(from 180deg at 50% 50%,
		#98d9fe 0deg,
		#99daff 192.079deg,
		#007fd5 209.423deg,
		#0080d6 334.038deg,
		#98d9fe 334.8deg,
		#98d9fe 360deg);
	animation-duration: calc(72s * var(--spin));
}

/* 右下リング：linear。軸が回ることで光の帯がリングを一周する */
.arc__grad--br {
	background:
		linear-gradient(0deg, #00A200 0%, #00A200 100%),
		linear-gradient(0deg, #F00 0%, #F00 100%),
		linear-gradient(222deg, #096AAC 12.58%, #4C62DF 50.92%);
	background-blend-mode: luminosity, saturation, normal;
	animation-duration: calc(95s * var(--spin)); /* 左と揃わないようズラす */
}

/* グラデ矩形をグラデの向き（297deg）に沿って往復させる。
   境目だけが弧の中を行ったり来たりして見える。
   往復運動なので ease-in-out が自然（周回と違って折り返しがある）。 */
.arc__sweep {
	animation: sweep calc(19s * var(--speed)) ease-in-out infinite;
}

/* 右上の弧（SVG）のグレイン。フィルター本体はrender.php側のSVG内に直接書いている
   （同じ<g>・同じclip-pathの中に置くことで弧の輪郭からはみ出さない）。
   ここでは透明度だけ他のグレインと揃える。回転・移動はしない。 */
.arc__noise {
	opacity: var(--noise);
	pointer-events: none;
}

@keyframes sweep {
	0%, 100% { transform: translate(0, 0); }
	50% {
		transform: translate(
			calc(-178px * var(--amp)),
			calc(-91px * var(--amp))
		);
	}
}

/* 周回は等速。加減速すると「止まった」と誤解されるので linear。 */
@keyframes spin {
	to { transform: rotate(360deg); }
}

/* ========== 停止まわり ========== */
/* OS設定：完全に止める */
@media (prefers-reduced-motion: reduce) {
	.kv .arc, .kv .arc__grad, .kv .arc__sweep { animation: none; }
	.kv__arcs, .kv__content, .kv__title { animation: none; opacity: 1; transform: none; }
}

/* ボタン：その場で止める（初期位置に戻さない） */
.kv.is-paused .arc,
.kv.is-paused .arc__grad,
.kv.is-paused .arc__sweep { animation-play-state: paused; }

/* ========== コンテンツ ========== */
.kv__content {
	position: relative;
	z-index: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	padding-top: calc(var(--header-h) + 28vh);
}

/* position: relative はタロちゃんの絶対配置の基準にするため。
   タロちゃんをフローから外すことで、.kv__call の実質の幅はテキストだけになり、
   親（.kv__content）の中央寄せがテキスト単体を中央に置くようになる。 */
.kv__call {
	position: relative;
	display: flex;
	align-items: flex-end;
	margin-bottom: 14px;
}

.kv__call-text {
	color: var(--c-tarosky-blue);
	font-weight: 700;
	font-size: 18px;
	padding-bottom: 6px;
	margin: 0;
}

/* タロちゃん枠。中身は core/image（InnerBlocks）が出す figure/img。
   差し替え後の画像サイズがまちまちでも枠に収まるよう固定サイズにする。
   絶対配置で .kv__call の左（＝テキストの左）にタロちゃんの幅ぶん出す。 */
/* モバイルでは通常のフロー内（呼びかけ文と横並び）に置く。狭い画面で
   position:absoluteのまま左にはみ出すと、余白が足りず見切れるため。
   広い画面（--tablet超）だけ、テキストを中央に見せるためフローの外に出す。 */
.kv__call-icon {
	flex-shrink: 0;
	width: 76px;
	height: 96px;
}

@media (min-width: 783px) {
	.kv__call-icon {
		position: absolute;
		right: 100%;
		bottom: 0;
		margin-right: 8px;
	}
}

.kv__call-icon img {
	width: 100%;
	height: 100%;
	object-fit: contain;
}

.kv__search {
	width: min(560px, 80vw);
}

/* AI回答（.hamelp-ai-overview__turn）表示中は、回答ボックスぶんの余白を
   検索窓側に持たせておく（.kv__titleが.kvの下端基準の絶対配置なので、
   回答とタイトルが詰まって見えないようにするため）。 */
.kv:has(.hamelp-ai-overview__turn) .kv__search {
	padding-bottom: 240px;
}

/* クレジット文（例：「このチャットはPubPla AI Help Centerでできています。」）。
   hamelp本体の.hamelp-ai-overview__hint（font-size:12px;opacity:.6）に
   見た目を揃えつつ、検索窓全体の直下・中央寄せで独立した1行として出す。 */
.kv__search-credit {
	margin: 12px 0 0;
	font-size: 12px;
	line-height: 1.4;
	text-align: center;
	opacity: .6;
}

/* ========== フォールバック（hamelp無効時のネイティブinput） ==========
   タイピング演出は未実装。ネイティブのplaceholderで表示している。 */
.kv__search-native {
	display: flex;
	align-items: center;
	background: #fff;
	border: 1px solid var(--wp--preset--color--input-border);
	border-radius: 999px;
	padding: 6px 6px 6px 24px;
	box-shadow: 0 0 0 8px rgba(255, 255, 255, .55);
}

.kv__search-input {
	flex: 1;
	border: none;
	background: none;
	color: var(--c-text);
	font-size: 15px;
	padding: 0;
}

.kv__search-input:focus {
	outline: none;
}

.kv__search-btn {
	width: 44px;
	height: 44px;
	border-radius: 50%;
	border: none;
	flex-shrink: 0;
	background: linear-gradient(160deg, var(--c-cyan), var(--c-blue));
	color: #fff;
	font-size: 18px;
	cursor: pointer;
}

/* ========== hamelp（PubPla AI ヘルプセンター）のAI Overviewブロック ==========
   「タロちゃんに、なんでも聞いてみて！」に対応する実際のQ&A機能。
   矢印アイコン・スクリーンリーダー用ラベルはブロック本体に既に用意されている
   （render.php参照）ので、こちらは配色・角丸の上書きだけでよい。
   プラグイン側のCSSは見た目の宣言を全部 :where() で包んであり詳細度0。
   専用のCSSカスタムプロパティ（--hamelp-*）も用意されているので、
   テーマ側は変数を上書きするだけで自動的に勝てる（プラグイン側のコメントに
   その設計意図が明記されている）。ボタンの見た目（角丸・枠線・グラデ・影）は
   確定値をそのまま再現したいので、直接プロパティを上書きしている
   （:where()より詳細度が高いので必ず勝つ）。アイコン（矢印SVG）はプラグイン側の
   ままで触っていない。 */
.kv .hamelp-ai-overview {
	--hamelp-surface: #fff;
	--hamelp-border: var(--wp--preset--color--input-border);
	--hamelp-radius: 20px;
	--hamelp-accent: var(--c-blue);
}

.kv .hamelp-ai-overview__input {
	color: var(--c-text);
	border-radius: 9999px;
	box-shadow: 0 0 0 8px rgba(255, 255, 255, .55);
}

/* エラー時は質問文をhamelp側のエラーカラーに揃える。 */
.kv .hamelp-ai-overview__turn.has-error .hamelp-ai-overview__question {
	color: var(--hamelp-error);
}

.kv .hamelp-ai-overview__button {
	border-radius: 48px;
	border: 2px solid #FFF;
	background: linear-gradient(180deg, #0086D9 0%, #00A9D9 100%);
	box-shadow: 0 4px 12px 0 rgba(0, 169, 212, 0.25);
	transition: background .2s ease;
}

/* hoverはグラデを上下反転 */
.kv .hamelp-ai-overview__button:hover {
	background: linear-gradient(180deg, #00A9D9 0%, #0086D9 100%);
}

/* AI回答本文の文字サイズ。PC/スマホで指定（ユーザー指示）。 */
.kv .hamelp-ai-overview__answer {
	font-size: 18px;
}

@media (max-width: 781px) {
	.kv .hamelp-ai-overview__answer {
		font-size: 14px;
	}
}

.kv__title {
	position: absolute;
	left: 45px;
	/* 一時停止ボタン（.motion-toggle、bottom:52px固定）と下端を揃える。 */
	bottom: 52px;
	/* --title が vw単位の係数。モバイル7.1 / PC4.2 */
	font-size: clamp(20px, calc(1vw * var(--title)), 130px);
	font-weight: 800;
	line-height: 1.45;
	margin: 0;
	color: var(--c-text);
	/* palt = プロポーショナルメトリクス。かなや約物の余白が詰まって
	   日本語の見出しが締まる。ヒラギノ / Noto Sans JP などが対応。
	   本番フォントがpaltに対応しているか要確認（非対応だと無視される）。 */
	font-feature-settings: "palt";
	/* paltで詰まる分を少し戻す */
	letter-spacing: 0.02em;
	z-index: 1;
}

/* 一時停止ボタン（.motion-toggle）のCSSはcss/global.cssに移した。
   このstyle.cssはKVブロックのstyle（block.json）としてKVブロックが
   実際に使われているページでしか自動エンキューされないが、ボタンは
   フッター（parts/footer.html）にあり全ページ共通のため、ここに置くと
   KVが無いページでスタイル無しの素の<button>になってしまっていた
   （実際に発生を確認）。 */

/* ==========================================
   エディタ用の簡易プレビュー（index.js の edit() が出すマークアップ）
   弧・ノイズ・モーションは出さない方針なので、専用の簡易表示のみ。
   ========================================== */
.kv-editor-preview {
	position: relative;
	background: var(--wp--preset--color--beige);
	border-radius: 16px;
	padding: 40px 24px;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 16px;
}

/* フロント側（.kv__call）と同じ考え方。アイコンを絶対配置でフローから外し、
   テキスト単体が中央に来るようにする。 */
.kv-editor-preview__call {
	position: relative;
	display: flex;
	align-items: center;
}

.kv-editor-preview__icon {
	position: absolute;
	right: 100%;
	top: 50%;
	transform: translateY(-50%);
	margin-right: 8px;
	width: 76px;
	height: 96px;
}

.kv-editor-preview__icon img {
	width: 100%;
	height: 100%;
	object-fit: contain;
}

.kv-editor-preview__call-text {
	color: var(--wp--preset--color--tarosky-blue);
	font-weight: 700;
	margin: 0;
}

.kv-editor-preview__search {
	width: min(560px, 80%);
	text-align: center;
	padding: 12px 24px;
	border-radius: 999px;
	background: #fff;
	border: 1px solid var(--wp--preset--color--input-border);
	color: var(--wp--preset--color--body-text);
}

/* フロント側（.kv__title）は左寄せ絶対配置。呼びかけ行・検索窓は中央寄せで
   合っているが、見出しだけはこのプレビューでも左寄せに揃えておく
   （中央寄せのままだと編集画面とフロントの見た目差が気になるため）。 */
.kv-editor-preview__title {
	align-self: flex-start;
	width: 100%;
	font-size: clamp(20px, 4vw, 48px);
	font-weight: 800;
	text-align: left;
	margin: 0;
}
