/* ============================================================
   Spiritual LP — 管理画面 ライブプレビュー / SEO・LLMO 拡張スタイル
   既存 style.css とは完全独立（編集禁止の競合回避のため別ファイル）。
   style.css のカラートークン（--accent / --success / --warn-border 等）と
   余白・ボタン・トースト・スピナーのデザイン言語を踏襲する。
   prefers-color-scheme は style.css 側 :root で定義済みのため継承する。
   ============================================================ */

/* ── 追加トークン（既存トークンから派生・ハードコード回避）─────────────
   ステータスバッジ・文字数カウンタ等の状態色は既存の意味色から導出する。
   未定義時のフォールバックを必ず添えて単独でも破綻しないようにする。 */
:root {
  --pv-ok:        var(--success, #2e7d32);
  --pv-ok-bg:     var(--success-bg, #e8f5e9);
  --pv-warn:      var(--warn-border, #f9a825);
  --pv-warn-bg:   var(--warn-bg, #fff8e1);
  --pv-neutral:   var(--text-muted, #7a7068);
  --pv-neutral-bg: color-mix(in srgb, var(--text-muted, #7a7068) 12%, transparent);
  --pv-danger:    var(--danger, #c0392b);
  /* Google 検索スニペットの色（ライト基調・ダーク時は下で上書き） */
  --pv-serp-title:  #1a0dab;
  --pv-serp-url:    #006621;
  --pv-serp-desc:   #4d5156;
}

@media (prefers-color-scheme: dark) {
  :root {
    --pv-serp-title:  #8ab4f8;
    --pv-serp-url:    #6ee29a;
    --pv-serp-desc:   #9aa0a6;
  }
}

/* ============================================================
   1. 分割ビュー — 左=編集フォーム / 右=ライブプレビュー
   既存 .admin-main（grid 1fr 300px）を上書きせず、
   .admin-main--split を body 側で付与して切替える想定。
   ============================================================ */

/* 分割モード時のメインレイアウト
   左=編集カラム / 仕切り / 右=プレビューカラム。バージョン履歴はプレビュー内タブへ移す。
   既定は 42:58 でプレビューを主役に（編集者の主訴＝プレビューが小さすぎる）。
   比率は仕切りのドラッグで可変・localStorage に保持（app.js の SPLIT_RATIO_KEY）。 */
.admin-main--split {
  grid-template-columns:
    minmax(320px, var(--split-left, 42fr))
    var(--splitter-w, 10px)
    minmax(360px, var(--split-right, 58fr));
}

/* ── 左右の仕切り（ドラッグハンドル）─────────────────
   分割モード時のみ表示。キーボード（←→）でも比率を変えられるようにする。 */
.split-handle {
  display: none;
  align-self: stretch;
  min-height: 240px;
  position: sticky;
  top: 76px;
  height: calc(100vh - 100px);
  border: 0;
  padding: 0;
  background: transparent;
  cursor: col-resize;
  touch-action: none;
  border-radius: 999px;
}
.admin-main--split .split-handle { display: block; }

/* つまみの視覚表現（細い縦線＋中央のグリップ） */
.split-handle::before {
  content: "";
  position: absolute;
  inset: 0 50% 0 50%;
  width: 2px;
  transform: translateX(-1px);
  background: var(--border);
  border-radius: 999px;
  transition: background var(--transition);
}
.split-handle::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 6px;
  height: 40px;
  transform: translate(-50%, -50%);
  background: var(--border);
  border-radius: 999px;
  transition: background var(--transition);
}
.split-handle:hover::before,
.split-handle:hover::after,
.split-handle:focus-visible::before,
.split-handle:focus-visible::after,
.split-handle.is-dragging::before,
.split-handle.is-dragging::after { background: var(--accent); }
.split-handle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ドラッグ中は iframe がポインタを奪うので全面的に無効化する */
body.is-splitting { cursor: col-resize; user-select: none; }
body.is-splitting iframe { pointer-events: none; }

@media (max-width: 900px) {
  .split-handle,
  .admin-main--split .split-handle { display: none; }
}

/* プレビューカラム（右）— 画面に追従して固定高スクロール */
.preview-column {
  position: sticky;
  top: 76px;
  align-self: start;
  display: flex;
  flex-direction: column;
  gap: 16px;
  max-height: calc(100vh - 100px);
  min-width: 0;
}

/* プレビューパネル共通枠（form-area / sidebar-panel と同じカード言語） */
.preview-panel {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* パネル見出し（sidebar-panel h3 と同じトーン） */
.preview-panel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  font-size: .85rem;
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: .06em;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-sidebar);
}

.preview-panel__head-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  text-transform: none;
  letter-spacing: 0;
}

.preview-panel__body {
  padding: 14px 16px;
  overflow-y: auto;
  min-height: 0;
}

/* ── ライブプレビュー枠（iframe 入れ子）─────────────────────── */
.live-preview-frame {
  position: relative;
  flex: 1;
  min-height: 320px;
  background: var(--bg);
  /* overflow は指定しない: iframe 要素に overflow:hidden を掛けると Chrome では clip 扱いになり
     内部ドキュメントのスクロールごと封じてしまう（プレビューを下へスクロールできなくなる）。
     内部スクロールを iframe 自身に任せる。desktop は下の transform:scale で縮小表示する。 */
}

/* （旧: .live-preview-frame__iframe 向けの幅切替は実 DOM に存在しないクラスで死にコードのため撤去。
    実際の幅切替は .live-preview-mount[data-viewport] > iframe.live-preview-frame で行う・後述） */

.live-preview-frame__iframe {
  display: block;
  width: 100%;
  height: 100%;
  min-height: 320px;
  margin: 0 auto;
  border: 0;
  background: #fff;
  transition: width var(--transition);
}

/* ヘッド右側の操作群（スクロール同期トグル＋ビューポート切替）をまとめる */
.preview-head-controls {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-transform: none;
  letter-spacing: 0;
}

/* 左右スクロール同期トグル（チェックボックス＋ラベル） */
.sync-toggle {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: .72rem;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.sync-toggle input[type="checkbox"] {
  width: 14px;
  height: 14px;
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
  flex-shrink: 0;
}
.sync-toggle:hover { color: var(--accent); }
.sync-toggle input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ビューポート切替トグル（ヘッド内のボタン群） */
.viewport-toggle {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.viewport-toggle button {
  background: var(--bg-card);
  color: var(--text-muted);
  border: none;
  padding: 4px 9px;
  font-size: .72rem;
  font-weight: 500;
  line-height: 1.4;
  border-right: 1px solid var(--border);
}
.viewport-toggle button:last-child { border-right: none; }
.viewport-toggle button:hover { background: var(--accent-light); color: var(--accent); }
.viewport-toggle button.active {
  background: var(--accent);
  color: #fff;
}

/* 左右配分プリセット（viewport-toggle と同じセグメント言語） */
.split-preset {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.split-preset button {
  background: var(--bg-card);
  color: var(--text-muted);
  border: none;
  border-right: 1px solid var(--border);
  padding: 4px 9px;
  font-size: .72rem;
  font-weight: 500;
  line-height: 1.4;
}
.split-preset button:last-child { border-right: none; }
.split-preset button:hover { background: var(--accent-light); color: var(--accent); }
.split-preset button.active { background: var(--accent); color: #fff; }
/* 分割モード（右にプレビューが出ている時）だけ意味を持つ操作なので、それ以外では隠す */
.split-preset { display: none; }
.admin-main--split .split-preset,
.admin-main--preview-full .split-preset { display: inline-flex; }

/* プレビュー最大化: 編集カラムと仕切りを畳み、プレビューだけを全幅で見せる。
   （編集内容は保持したまま「大きく確認する」ためのモード） */
/* 編集カラムと仕切りは display:none で grid から外れるため、残る preview-column が
   自動配置される「1列だけ」の定義にする。
   （0 0 1fr の3列にすると preview が先頭の 0px 列へ落ちて潰れる） */
.admin-main--preview-full {
  grid-template-columns: minmax(0, 1fr);
}
.admin-main--preview-full > .editor-column,
.admin-main--preview-full > .split-handle { display: none; }
.admin-main--preview-full > .preview-column { max-height: calc(100vh - 100px); }

/* ── プレビュー更新中ローディング表現 ───────────────────────
   live-preview-frame に .is-loading を付与すると半透明オーバーレイ＋スピナー。
   既存 .spinner / @keyframes spin を再利用する。 */
.live-preview-frame__loader {
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 10px;
  background: color-mix(in srgb, var(--bg-card) 78%, transparent);
  backdrop-filter: blur(1.5px);
  color: var(--text-muted);
  font-size: .82rem;
  z-index: 5;
}
.live-preview-frame.is-loading .live-preview-frame__loader { display: flex; }

/* 上端プログレスバー（更新トリガ時に流れる細いバー） */
.live-preview-frame__progress {
  position: absolute;
  top: 0; left: 0;
  height: 2px;
  width: 0;
  background: var(--accent);
  z-index: 6;
  opacity: 0;
  transition: opacity var(--transition);
}
.live-preview-frame.is-loading .live-preview-frame__progress {
  opacity: 1;
  animation: pv-progress 1.1s ease-in-out infinite;
}
@keyframes pv-progress {
  0%   { width: 0;    left: 0;    }
  50%  { width: 70%;  left: 0;    }
  100% { width: 0;    left: 100%; }
}

/* ============================================================
   2. ステータスバッジ（公開中 / 下書きあり / 未保存）
   ============================================================ */
.status-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .02em;
  padding: 3px 10px 3px 8px;
  border-radius: 999px;
  border: 1px solid transparent;
  line-height: 1.5;
  white-space: nowrap;
}

/* バッジ内の状態ドット */
.status-badge::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}

/* 公開中＝緑系 */
.status-badge--published {
  color: var(--pv-ok);
  background: var(--pv-ok-bg);
  border-color: color-mix(in srgb, var(--pv-ok) 35%, transparent);
}

/* 下書きあり（未公開の編集が保存済）＝橙系 */
.status-badge--draft {
  color: var(--pv-warn);
  background: var(--pv-warn-bg);
  border-color: color-mix(in srgb, var(--pv-warn) 40%, transparent);
}

/* 未保存変更あり＝グレー（点滅で注意喚起） */
.status-badge--unsaved {
  color: var(--pv-neutral);
  background: var(--pv-neutral-bg);
  border-color: color-mix(in srgb, var(--pv-neutral) 30%, transparent);
}
.status-badge--unsaved::before {
  animation: pv-pulse 1.4s ease-in-out infinite;
}
@keyframes pv-pulse {
  0%, 100% { opacity: 1;  }
  50%      { opacity: .35; }
}

/* 保存中（処理進行中）＝アクセント */
.status-badge--saving {
  color: var(--accent);
  background: var(--accent-light);
  border-color: color-mix(in srgb, var(--accent) 35%, transparent);
}

/* モーション抑制設定への配慮 */
@media (prefers-reduced-motion: reduce) {
  .status-badge--unsaved::before,
  .live-preview-frame.is-loading .live-preview-frame__progress { animation: none; }
}

/* ============================================================
   3. 文字数カウンタ（title 32 / description 120 の閾値で色変化）
   フィールド直下に置く小さなカウンタ。data-state で色を切替。
   ============================================================ */
.char-counter {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 4px;
  font-size: .72rem;
  font-weight: 500;
  color: var(--text-muted);
  line-height: 1.4;
}

.char-counter__count { font-variant-numeric: tabular-nums; }
.char-counter__count strong { font-weight: 700; }
.char-counter__hint { opacity: .75; }

/* 余裕あり（閾値の ~90% 未満）＝既定の muted */
.char-counter[data-state="ok"]      { color: var(--text-muted); }
/* 閾値接近（~90%〜100%）＝橙で警告 */
.char-counter[data-state="warn"]    { color: var(--pv-warn); }
.char-counter[data-state="warn"] .char-counter__count strong { color: var(--pv-warn); }
/* 超過（閾値オーバー）＝danger で強調 */
.char-counter[data-state="over"]    { color: var(--pv-danger); }
.char-counter[data-state="over"] .char-counter__count strong { color: var(--pv-danger); }

/* 閾値接近・超過時は入力枠にも色のヒントを与える（任意・JSで .is-warn/.is-over 付与） */
input.is-counter-warn, textarea.is-counter-warn {
  border-color: color-mix(in srgb, var(--pv-warn) 60%, var(--border)) !important;
}
input.is-counter-over, textarea.is-counter-over {
  border-color: color-mix(in srgb, var(--pv-danger) 60%, var(--border)) !important;
}

/* ============================================================
   4. SEO / LLMO プレビューパネル
   ============================================================ */

/* パネル内のサブセクション区切り（section-label に準ずる） */
.seo-subhead {
  font-size: .72rem;
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: .07em;
  margin: 4px 0 8px;
}
.seo-subhead:not(:first-child) { margin-top: 18px; }

/* ── Google 検索スニペット枠 ───────────────────────────── */
.seo-snippet {
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  font-family: Arial, 'Helvetica Neue', 'Noto Sans JP', sans-serif;
}

.seo-snippet__url {
  display: block;
  font-size: .74rem;
  color: var(--pv-serp-url);
  line-height: 1.4;
  margin-bottom: 2px;
  word-break: break-all;
}

.seo-snippet__title {
  font-size: 1.05rem;
  font-weight: 400;
  color: var(--pv-serp-title);
  line-height: 1.3;
  margin-bottom: 3px;
  /* 検索結果のタイトル省略を再現 */
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.seo-snippet__desc {
  font-size: .8rem;
  color: var(--pv-serp-desc);
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* 値が空のときのプレースホルダ表現 */
.seo-snippet__title:empty::before,
.seo-snippet__desc:empty::before,
.seo-snippet__url:empty::before {
  content: "（未入力）";
  color: var(--text-muted);
  opacity: .6;
  font-style: italic;
}

/* ── OGP カード（SNS シェア時の見た目）─────────────────── */
.og-card {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg-input);
  max-width: 480px;
}

.og-card__img {
  display: block;
  width: 100%;
  aspect-ratio: 1200 / 630;
  object-fit: cover;
  background: var(--bg-sidebar);
  color: var(--text-muted);
}

/* 画像未設定時のプレースホルダ（img の代わりに div を置く運用も可） */
.og-card__img--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .78rem;
  color: var(--text-muted);
  text-align: center;
  border-bottom: 1px solid var(--border);
}

.og-card__body {
  padding: 10px 14px 12px;
  border-top: 1px solid var(--border);
}

.og-card__domain {
  font-size: .7rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: .03em;
  margin-bottom: 3px;
  word-break: break-all;
}

.og-card__title {
  font-size: .9rem;
  font-weight: 700;
  color: var(--text);
  line-height: 1.35;
  margin-bottom: 3px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.og-card__desc {
  font-size: .78rem;
  color: var(--text-muted);
  line-height: 1.45;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ── JSON-LD ステータス ─────────────────────────────────
   構造化データのパース可否・型をひと目で示すインジケータ。 */
.jsonld-status {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 9px 12px;
}

.jsonld-status__icon {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .8rem;
  font-weight: 700;
  color: #fff;
  flex-shrink: 0;
}

.jsonld-status__text {
  font-size: .8rem;
  line-height: 1.4;
  min-width: 0;
}
.jsonld-status__text strong { display: block; font-weight: 700; }
.jsonld-status__types {
  font-size: .72rem;
  color: var(--text-muted);
  word-break: break-word;
}

/* 妥当（パース可・必須充足）＝緑 */
.jsonld-status[data-state="valid"] {
  background: var(--pv-ok-bg);
  border-color: color-mix(in srgb, var(--pv-ok) 35%, transparent);
}
.jsonld-status[data-state="valid"]  .jsonld-status__icon { background: var(--pv-ok); }
.jsonld-status[data-state="valid"]  .jsonld-status__text strong { color: var(--pv-ok); }

/* 警告（パース可だが必須欠落）＝橙 */
.jsonld-status[data-state="warn"] {
  background: var(--pv-warn-bg);
  border-color: color-mix(in srgb, var(--pv-warn) 40%, transparent);
}
.jsonld-status[data-state="warn"]   .jsonld-status__icon { background: var(--pv-warn); }
.jsonld-status[data-state="warn"]   .jsonld-status__text strong { color: var(--pv-warn); }

/* エラー（パース不可）＝danger */
.jsonld-status[data-state="error"] {
  background: color-mix(in srgb, var(--pv-danger) 8%, var(--bg-card));
  border-color: color-mix(in srgb, var(--pv-danger) 45%, transparent);
}
.jsonld-status[data-state="error"]  .jsonld-status__icon { background: var(--pv-danger); }
.jsonld-status[data-state="error"]  .jsonld-status__text strong { color: var(--pv-danger); }

/* 検査中（ニュートラル）＝spinner を icon の代わりに */
.jsonld-status[data-state="checking"] .jsonld-status__icon {
  background: transparent;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  animation: spin .7s linear infinite;
}

/* ============================================================
   5. バージョン履歴のタブ化／折りたたみ
   分割ビューでは右カラムに「プレビュー / 履歴」タブを置き、
   履歴をプレビューパネル内へ収める。
   ============================================================ */
.preview-tabs {
  display: flex;
  gap: 0;
  border-bottom: 1px solid var(--border);
  background: var(--bg-sidebar);
}

.preview-tabs__btn {
  flex: 1;
  background: none;
  border: none;
  padding: 9px 12px;
  font-size: .8rem;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color var(--transition), border-color var(--transition);
  font-family: inherit;
}
.preview-tabs__btn:hover { color: var(--text); }
.preview-tabs__btn.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
  background: var(--bg-card);
}

/* タブパネルの表示制御（.hidden 併用でも可） */
.preview-tabpanel[hidden] { display: none; }

/* 折りたたみ版（<details> を使う場合の体裁調整） */
.versions-collapsible > summary {
  cursor: pointer;
  list-style: none;
  padding: 10px 16px;
  font-size: .82rem;
  font-weight: 700;
  color: var(--text-muted);
  background: var(--bg-sidebar);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.versions-collapsible > summary::-webkit-details-marker { display: none; }
.versions-collapsible > summary::after {
  content: "▸";
  transition: transform var(--transition);
}
.versions-collapsible[open] > summary::after { transform: rotate(90deg); }

/* ============================================================
   6. アクセシビリティ — フォーカス可視（既存 :focus-visible 規約に追従）
   ============================================================ */
.viewport-toggle button:focus-visible,
.preview-tabs__btn:focus-visible,
.versions-collapsible > summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* スクリーンリーダー専用テキスト（ステータス読み上げ用） */
.pv-sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ============================================================
   7. レスポンシブ — 狭幅で左右を上下積みに
   既存 .admin-main は max-width:900px で 1 カラム化するため、
   分割ビューもそれに合わせてプレビューを下段へ。
   ============================================================ */
@media (max-width: 1100px) {
  .admin-main--split {
    /* minmax(0,1fr) であること。生の `1fr` は minmax(auto,1fr) と同義で、トラックが
       子孫の min-content 幅まで膨らむ。プレビュー iframe は実 PC 幅 1180px 固定で
       描かれるため、`1fr` だと列が 1180px へ伸びて画面外へはみ出す（狭幅で実測）。
       style.css:1504 が .admin-main に対して同じ理由で minmax(0,1fr) を入れているが、
       実運用でほぼ常時付く .admin-main--split には効いていなかった（後読みで負ける）。 */
    grid-template-columns: minmax(0, 1fr);
  }
  .preview-column {
    position: static;
    max-height: none;
  }
  .live-preview-frame {
    min-height: 420px;
  }
}

@media (max-width: 600px) {
  .preview-panel__head {
    flex-wrap: wrap;
    gap: 6px;
  }
  .preview-head-controls { flex-wrap: wrap; gap: 6px; width: 100%; justify-content: space-between; }
  .viewport-toggle { flex: 1 1 auto; }
  .viewport-toggle button { flex: 1; }
  .og-card { max-width: 100%; }
  .char-counter { flex-direction: column; align-items: flex-start; gap: 2px; }
}

/* ════════════════════════════════════════════════════════════════════════
   Stage1 統合追加: live-preview-mount / SEO・LLMO 出力（seo-checks.js のクラス）
   / 文字数カウンタ。既存トークン（--border/--bg-card/--success/--danger 等）参照。
   ════════════════════════════════════════════════════════════════════════ */

/* ライブプレビュー: preview.js が <iframe class="live-preview-frame"> を mount 内に生成 */
.live-preview-mount {
  position: relative;
  width: 100%;
  height: calc(100vh - 200px);
  min-height: 360px;
  overflow: auto;
  background: var(--bg);
}
.live-preview-mount > iframe.live-preview-frame { display: block; width: 100%; height: 100%; }
/* レスポンシブ確認の幅切替（preview.js の inline width:100% を上書きするため !important）。
   幅は実機相当（tablet 768 / mobile 390）で固定し、パネルが狭いときは desktop と同じ
   transform:scale で縮める（B10）。scale を付けないと iframe が実機幅のまま描かれ、
   パネルより広い分が見切れて横スクロールが出る＝実機の見え方と食い違う。
   高さ補正 calc(100% / var(--pv-zoom)) を必ずセットで持つこと（欠けると scale 分だけ
   縮んで「プレビューが下半分出ない」状態になる。desktop で実際に踏んだ不具合）。 */
.live-preview-mount[data-viewport="tablet"] > iframe.live-preview-frame {
  width: 768px !important;
  height: calc(100% / var(--pv-zoom, 1)) !important;
  transform: scale(var(--pv-zoom, 1));
  transform-origin: top left;
  margin: 0 auto;
}
.live-preview-mount[data-viewport="mobile"] > iframe.live-preview-frame {
  width: 390px !important;
  height: calc(100% / var(--pv-zoom, 1)) !important;
  transform: scale(var(--pv-zoom, 1));
  transform-origin: top left;
  margin: 0 auto;
}
/* PC幅: iframe を実PC幅(1180px)で描画し、パネル幅に合わせて transform:scale で縮小（横スクロール無し）。
   こうしないと iframe 実効幅がパネル半幅(~600px)になり styles.css の @media(max-width:720px) が
   誤発火して「モバイル表示（quickmenu 6枠が出て CTA が消える）」になり、実 PC 画面と食い違う。
   --pv-zoom は app.js が clientWidth/1180 で算出して付与（リサイズ追従）＝そのまま scale 係数に使う。
   旧実装は zoom を使っていたが、Chrome の zoom は iframe 内部の scrollTop 座標系を壊し
   プログラムスクロール（win.scrollTo/scrollIntoView）の可動域が数pxにクランプされてプレビューが
   下へ動かせなかった。transform:scale は layout 座標を保つので内部スクロールが正しく効く。
   transform-origin:top left＋scale=パネル幅/1180 なので視覚幅はちょうどパネル幅に一致（左上基準）。 */
.live-preview-mount[data-viewport="desktop"] > iframe.live-preview-frame {
  width: 1180px !important;
  /* scale 後の視覚高さ = マウント高さ100%。!important は width と同じ理由（インライン style や
     基底ルールに負けると scale 分だけ縮んで「プレビューが半分しか出ない」状態になる）。 */
  height: calc(100% / var(--pv-zoom, 1)) !important;
  transform: scale(var(--pv-zoom, 1));
  transform-origin: top left;
  margin: 0;
}
/* transform は layout ボックス（1180×高さ/scale）を縮めないため、はみ出す空き領域をマウントで
   クリップする（横スクロールバー抑止）。実コンテンツのスクロールは iframe 内部が担う。 */
.live-preview-mount[data-viewport="desktop"],
.live-preview-mount[data-viewport="tablet"],
.live-preview-mount[data-viewport="mobile"] { overflow: hidden; }

/* 固定倍率モード（倍率セレクトで 50/75/100% を選んだとき）。
   既定の「幅に合わせる」では is-zoom-manual が付かないので、ここは一切効かない＝従来挙動不変。
   transform:scale はレイアウトボックスを縮めないため、app.js が算出した負のマージンで
   実寸ぶんを引き戻す。こうしないと縮小時に「中身が無いのにスクロールバーだけ出る」状態になる。
   上の [data-viewport] ルールと同詳細度なので、必ずこの後ろに置くこと（後勝ちで上書きする）。 */
.live-preview-mount.is-zoom-manual { overflow: auto; }
.live-preview-mount.is-zoom-manual > iframe.live-preview-frame {
  height: var(--pv-frame-h, 100%) !important;
  margin-right: var(--pv-frame-mr, 0px) !important;
  margin-bottom: var(--pv-frame-mb, 0px) !important;
}

/* クリック・トゥ・エディットの案内文（プレビューは編集の入口である、という告知） */
.preview-cte-hint {
  margin: 0 0 8px;
  padding: 8px 12px;
  font-size: .86rem;
  line-height: 1.6;
  color: var(--text);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  border-radius: var(--radius-sm);
}

/* ホバー中セクションの上に重ねるフローティングバッジ。
   プレビュー iframe の中には要素を足さない（実サイトとの見た目 drift を作らないため）ので、
   親側に position:fixed で置き、iframe の rect と倍率から座標を計算して重ねる。 */
.cte-badge {
  position: fixed;
  z-index: 900;
  pointer-events: none;
  padding: 4px 10px;
  border-radius: 999px;
  background: #b4551f;
  color: #fff;
  font-size: 12px;
  line-height: 1.5;
  white-space: nowrap;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .25);
}
.cte-badge[hidden] { display: none; }

/* 倍率セレクト（右ペイン見出し行） */
.pv-zoom { display: inline-flex; align-items: center; gap: 6px; }
.pv-zoom__lab { font-size: 12px; color: var(--text-muted, #6b6257); }
.pv-zoom__select {
  min-height: 32px; padding: 4px 8px; font: inherit; font-size: 13px;
  color: var(--text); background: var(--bg-card); border: 1px solid var(--border);
  border-radius: 8px; cursor: pointer;
}
.pv-zoom__val {
  min-width: 3.4em; text-align: right; font-size: 13px; font-variant-numeric: tabular-nums;
  color: var(--text-muted, #6b6257);
}

/* タブパネルの表示制御（data-pvpanel）。live は高さいっぱいの flex に */
.preview-tabpanel[data-pvpanel="live"] { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.preview-tabpanel[data-pvpanel="live"][hidden],
.preview-tabpanel[data-pvpanel="seo"][hidden],
.preview-tabpanel[data-pvpanel="versions"][hidden] { display: none; }

/* SEO/LLMO 出力枠 */
.seo-mount { padding: 14px 16px; overflow-y: auto; display: flex; flex-direction: column; gap: 14px; }
.seo-empty { color: var(--text-muted); font-size: .85rem; }

/* Googleスニペット / JSON-LD 共通カード（seo-checks.js: .seo-preview） */
.seo-preview { border: 1px solid var(--border); border-radius: var(--radius); padding: 12px 14px; background: var(--bg-card); }
.seo-preview__url { color: var(--pv-serp-url); font-size: .72rem; word-break: break-all; }
.seo-preview__title { color: var(--pv-serp-title); font-size: 1rem; line-height: 1.3; margin: 2px 0; }
.seo-preview__desc { color: var(--text-muted); font-size: .82rem; line-height: 1.5; }
.seo-preview__meter { display: flex; gap: 10px; margin-top: 8px; }
.seo-meter { font-size: .72rem; color: var(--text-muted); }
.seo-meter--over { color: var(--danger); font-weight: 700; }

/* OGカード（seo-checks.js: .seo-og__*） */
.seo-preview--og { padding: 0; overflow: hidden; }
.seo-og__imgwrap { aspect-ratio: 1200 / 630; background: var(--bg-sidebar); display: flex; align-items: center; justify-content: center; }
.seo-og__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.seo-og__noimg { color: var(--text-muted); font-size: .8rem; }
.seo-og__body { padding: 10px 14px; }
.seo-og__site { color: var(--text-muted); font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; }
.seo-og__title { font-weight: 700; font-size: .9rem; margin: 2px 0; }
.seo-og__desc { color: var(--text-muted); font-size: .8rem; }

/* JSON-LD 状態（seo-checks.js: .seo-jsonld__*） */
.seo-jsonld__note { color: var(--text-muted); font-size: .82rem; }
.seo-jsonld__list { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.seo-jsonld__item { display: flex; align-items: center; gap: 8px; font-size: .82rem; }
.seo-jsonld__mark--ok { color: var(--success); font-weight: 700; }
.seo-jsonld__mark--ng { color: var(--danger); font-weight: 700; }
.seo-jsonld__label { color: var(--text); }

/* チェック結果ボックス（app.js renderSeoPanel） */
.seo-checkbox { border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 12px; }
.seo-checkbox[data-state="error"] { border-color: var(--danger); }
.seo-checkbox[data-state="warn"]  { border-color: #d9a300; }
.seo-checkbox[data-state="ok"]    { border-color: var(--success); }
.seo-check-head { font-weight: 700; font-size: .85rem; margin: 0 0 6px; }
.seo-check-item { font-size: .8rem; line-height: 1.5; }
.seo-check-item.is-error { color: var(--danger); }
.seo-check-item.is-warn  { color: #8a6d00; }

.preview-vers-h { font-size: .9rem; margin: 0; padding: 12px 16px 0; }
.preview-tabpanel[data-pvpanel="versions"] { padding-bottom: 12px; }

/* 文字数カウンタ（app.js updateCharCounters） */
.char-counter { font-size: .72rem; color: var(--text-muted); text-align: right; margin-top: 2px; }
.char-counter[data-state="warn"] { color: #8a6d00; }
.char-counter[data-state="over"] { color: var(--danger); font-weight: 700; }

/* ════════ Stage2: 下書き/公開 保存バー・状態バッジ ════════ */
#save-bar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
#save-bar .save-actions { display: flex; gap: 8px; margin-left: auto; }
.publish-badge { font-size: 12px; font-weight: 700; padding: 3px 10px; border-radius: 999px; border: 1px solid transparent; white-space: nowrap; }
.publish-badge[data-state="live"]  { background: #e8f5ec; color: #1d6b3a; border-color: #b9e0c6; }
.publish-badge[data-state="draft"] { background: #fef6e0; color: #8a6310; border-color: #f0dca0; }
.publish-badge[data-state="dirty"] { background: #fdecec; color: #9a2a2a; border-color: #f3c4c4; }

/* コラム一覧の公開状態バッジ */
.cols-admin-badge { font-size: 11px; padding: 2px 8px; border-radius: 10px; margin-left: 8px; white-space: nowrap; }
.badge-draft     { background: #fde2e2; color: #a33; }
.badge-scheduled { background: #fff3cd; color: #8a6d00; }
.badge-live      { background: #e2f6e9; color: #1c7c43; }
.badge-trashed   { background: #e5e0da; color: #6b6259; }
/* ゴミ箱ビューの記事は淡く表示（通常一覧と視覚的に区別・P0-3 trash方式） */
.cols-admin-item.is-trashed .cols-admin-title { color: var(--text-muted, #7a7068); text-decoration: line-through; }
.cols-admin-trash-toggle:disabled { opacity: .5; cursor: default; }

/* ─────────────────────────────────────────────────
   フルコンパイル・プレビュー モーダル
   （本番と同一 11ty ビルドの確認専用。構造/CSS/レイアウト変更用）
───────────────────────────────────────────────── */
.fp-modal { position: fixed; inset: 0; z-index: 1000; display: flex; align-items: center; justify-content: center; }
.fp-modal.hidden { display: none; }
.fp-modal__backdrop { position: absolute; inset: 0; background: rgba(20, 22, 28, 0.55); backdrop-filter: blur(2px); }
.fp-modal__panel {
  position: relative; z-index: 1; display: flex; flex-direction: column;
  width: min(1180px, 94vw); height: min(88vh, 920px);
  background: #fff; border-radius: 14px; box-shadow: 0 24px 70px rgba(0,0,0,.32);
  overflow: hidden;
}
.fp-modal__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 16px 20px; border-bottom: 1px solid #eee; }
.fp-modal__title { margin: 0; font-size: 17px; font-weight: 700; color: #222; }
.fp-modal__hint { margin: 12px 20px 0; padding: 10px 12px; font-size: 12.5px; line-height: 1.7; color: #5a5a5a; background: #f6f4ef; border-radius: 8px; }
.fp-modal__note { margin: 12px 20px; padding: 12px 14px; font-size: 13px; line-height: 1.7; color: #5a4a2a; background: #fdf6e9; border: 1px solid #e8d9b8; border-radius: 8px; }
.fp-modal__status { margin: 10px 20px 0; min-height: 18px; font-size: 12.5px; color: #7a6a3a; }
.fp-modal__frame-wrap { flex: 1 1 auto; margin: 12px 20px; min-height: 0; border: 1px solid #e3e3e3; border-radius: 10px; overflow: hidden; background: #fafafa; }
.fp-modal__frame { width: 100%; height: 100%; border: 0; display: block; }
.fp-modal__actions { display: flex; gap: 10px; justify-content: flex-end; padding: 12px 20px 18px; }

@media (max-width: 640px) {
  .fp-modal__panel { width: 96vw; height: 92vh; border-radius: 10px; }
  .fp-modal__actions { flex-wrap: wrap; }
}

/* ══════════════════════════════════════════════════════════════════════
   a11y / レスポンシブ是正（実測に基づく）
   監査で 390px の横スクロール・タップ領域44px未達・AAコントラスト不足を計測。
   数値はすべて実測値に対する是正であり、見た目の好みではない。
   ══════════════════════════════════════════════════════════════════════ */

/* 390px で scrollWidth 445px > clientWidth 390px（55px はみ出し）だった。
   原因は grid の `1fr`（= minmax(auto,1fr)）が子孫の最小コンテンツ幅でトラックごと
   押し広げられること。右ペイン見出し行の操作群が縮み切らないのが実体。 */
.editor-column,
.preview-column,
.preview-panel,
.preview-panel__head,
.preview-head-controls,
.viewport-toggle,
.pv-zoom { min-width: 0; }

/* タップ領域 44px（実測: 24.1px だった）。プレビュー幅切替と配分プリセットは中核操作。 */
.viewport-toggle button,
.split-preset button { min-height: 44px; padding: 10px 9px; }

/* 倍率セレクトも 44px（実測 32px）。「プレビューが小さすぎる」を自力で直すための操作なので
   ここが押しにくいと機能そのものが届かない。 */
.pv-zoom__select { min-height: 44px; padding: 10px 8px; }

/* 倍率ラベル/値のコントラスト: --text-muted は --bg-sidebar 上で 4.14:1（AA 4.5 未達）だった。
   小さい文字なので大文字例外も使えない。ライトだけ一段濃いトークンへ寄せる。 */
.pv-zoom__lab,
.pv-zoom__val { color: var(--text-muted-strong, #6b6259); }

@media (max-width: 480px) {
  /* この幅では分割そのものが無いので、配分プリセットは意味を持たない */
  .viewport-toggle { flex: 1 1 100%; }
}

/* ── 右ペイン見出し行の折返し（見切れ防止・実測に基づく）───────────────────
   倍率セレクトを足した結果、1101〜1440px で「モバイル幅」📱 と「最大化」◨ が
   静かにクリップされていた（1101px で可視率 9.7% / 6.0%）。
   原因: .viewport-toggle / .split-preset は角丸クリップのため overflow:hidden を持ち、
   Flexbox 仕様で自動 min-width が min-content ではなく 0 になる。結果この2つだけが
   優先的に潰され、スクロールバーも警告も出ないまま中身が切れる。
   対処: セグメント群は縮ませず、行のほうを折り返させる。 */
.preview-panel__head,
.preview-head-controls { flex-wrap: wrap; row-gap: 6px; }
.viewport-toggle,
.split-preset,
.pv-zoom { flex-shrink: 0; }

/* 「プレビュー」タブが 1920px でも単語途中で2行に折れていた（実効幅 77.6px 固定）。
   .preview-tabs__btn{flex:1} で均等割りされ、shrink-to-fit 幅が必要幅を下回るのが原因。
   縮ませず、入り切らない幅では行ごと折り返させる。 */
.preview-tabs__btn { white-space: nowrap; flex: 0 1 auto; }
