/* ==========================================================================
 * FMS スマホ縦向きUI (WebGL格子切り出し + カルーセル) スタイル
 * --------------------------------------------------------------------------
 * 設計書: docs/SP-tate-redesign.md / 本体: js/fms-portrait-webgl.js
 *
 * スコープ規約: 既存UIへの影響を確実にゼロにするため、
 *  - 縦UI部品(.fmsPortrait*)は既定 display:none とし、body.fmsPortraitActive
 *    が付いた時だけ表示する(横向き/PCでは body クラスが無い=素の表示に完全復帰)。
 *  - 既存要素(video/クリックポイント等)への上書きは必ず body.fmsPortraitActive
 *    配下のセレクタで行う。
 * トークンは css/fms-tokens.css の var(--fms-*) をフォールバック付きで参照。
 * ========================================================================== */

/* ---- 非活性時は縦UI部品を完全に伏せる ---- */
.fmsPortraitCarousel,
.fmsPortraitControls,
canvas.fmsPortraitMain,
canvas.fmsPortraitSubs {
  display: none;
}

/* ==========================================================================
 * 1. プレーヤー領域の器 (設計書§2)
 * ========================================================================== */

/* 幅100%固定・高さはコンテンツ成り行き(仕様1)。
   adjustPlayerHeight が書く inline width より優先させるため !important。 */
body.fmsPortraitActive #fvPlayer {
  width: 100% !important;
  background: var(--fms-gray-950, #0D0D0D);
}

/* 既存videoは133.334%(4/3倍)に拡大し .fvVideoView(overflow:hidden)でクリップ
   = 格子のうちメイン領域(左上3/4)だけが見える(§2.2。シアターモードと同じ手法)。
   resize() が書く inline width/height より優先させるため !important。 */
body.fmsPortraitActive .fvVideoView > video.fvVideo {
  width: 133.334% !important;
  height: 133.334% !important;
}

/* 格子タップUI(クリックポイント)は縦UIでは不要(§2.1)。DOMは温存(選択状態の真実)。 */
body.fmsPortraitActive .fvVideoView ul.fvClickPointWrapper {
  display: none !important;
}

/* 切替中の既存ローディングスピナーは縦UIでは控えめに小型化(§5.2)。
   セレクタは common.css の既定(80px)/max-width:768px(40px)の
   `div.fvVideoView > div.fvLodingView > .sk-fading-circle`(0,3,2)に詳細度で
   勝つ形にする(従来の `.fvVideoView .sk-fading-circle` は(0,3,1)で負けており
   実効40pxだった。2026-07-14 修正。横UI=fms-landscape-webgl.css と同形) */
body.fmsPortraitActive div.fvVideoView > div.fvLodingView > .sk-fading-circle {
  width: 32px !important;
  height: 32px !important;
}

/* ==========================================================================
 * 1b. WebGL転写canvas (設計書§3。Phase 2 → 2026-07-14 縮小)
 *    初回描画成功まで opacity:0(下のvideo素通し/背景を見せる)。
 *    alpha:false の未描画canvasは不透明黒になるため isReady 付与後に可視化。
 *    メイン転写(canvas.fmsPortraitMain)は 2026-07-14 に廃止: 上の §2.2 の
 *    「video 133.334% 拡大+クリップ」がそのまま本番表示(canvas は生成されない)。
 * ========================================================================== */

/* サブ: .fmsPortraitTrack 全面(タイル位置にのみ描画される)。カード(z1)の下 */
body.fmsPortraitActive canvas.fmsPortraitSubs {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
}

body.fmsPortraitActive canvas.fmsPortraitSubs.isReady {
  opacity: 1;
  transition: opacity 0.15s ease-out;
}

/* ==========================================================================
 * 1bb. ローディング中のスプラッシュ画像 (2026-07-30 発注者報告)
 * --------------------------------------------------------------------------
 * 症状: 再生ボタンのタップ直後、最初の絵が出るまでの間に出る画像(チュートリアル
 *   画像)が、メイン画面領域からはみ出して右と下が切れていた。
 * 原因: その画像の出所は video の poster 属性(index.php の v1/v2)。縦UIは §2.2 で
 *   video を 133.334%(4/3倍)に拡大して .fvVideoView で左上3/4だけを見せているため、
 *   poster もその拡大された video ボックス基準で描かれ、器からはみ出していた。
 * 対処: poster 属性は JS(stripPosters/restorePosters)が縦UIの間だけ外し
 *   (=絵が無い間の video は透明)、画像はここで器 .fvVideoView の背景として
 *   contain で敷く。器はメイン画面領域そのものなので画像は必ず領域内に収まる。
 *   映像が出れば前面の video が覆う=自動的に隠れるので表示制御のJSは要らない。
 * 差し替え: 将来 縦UI専用画像にするときは --fms-portrait-poster の1行だけ変える
 *   (index.php の poster 属性は 横向き/PC/旧UI 用なのでそのまま)。
 * ========================================================================== */
:root {
  /* 縦UIのローディング中に見せる絵。暫定で現行のチュートリアル画像を流用しており、
     将来は縦UI専用画像へ差し替える予定(2026-07-30 ユーザー決定)。 */
  --fms-portrait-poster: url("https://d2fj9zflbpcrik.cloudfront.net/f-keiba/tutorial.jpg");
}

/* background-color は video_fv.css の `div.fvVideoView`(#000 !important)がそのまま
   残る=画像の余白は黒。ここでは image 系だけを足す(!important は不要=競合なし)。 */
body.fmsPortraitActive div.fvVideoView {
  background-image: var(--fms-portrait-poster);
  background-repeat: no-repeat;
  background-position: 50% 50%;
  background-size: contain;
}

/* ==========================================================================
 * 1c. メイン映像ダブルタップシーク オーバーレイ
 *    (仕様書 docs/sp_tate_webgl/メイン画面タップシーク仕様書.md §0)
 *    .fvVideoView へ append。映像上(z60=ローディングz50より上)に数値+矢印を重畳。
 * ========================================================================== */

/* iOSのダブルタップズームを抑止(縦UI時のみ・非破壊)。§0.8 */
body.fmsPortraitActive .fvVideoView {
  touch-action: manipulation;
}

/* ±10 連打の累積オーバレイ。2026-07-22: センター±10ボタンの隣スロットへ取付先を移設
   (mountForward/mountBackward)。isForward=+10 の右 / isBackward=−10 の左(横UIと同一)。 */
body.fmsPortraitActive .fmsPortraitTapSeek {
  position: absolute;
  top: 50%;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 0 4px;
  transform: translateY(-50%);
  color: #fff;
  font-size: clamp(15px, 4vw, 19px);
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.7);
  pointer-events: none;
  opacity: 0; /* 表示は isShown で 1、消去は isFading で 0 */
  transition: opacity 90ms ease-out; /* 初回フェードイン(§13) */
}
body.fmsPortraitActive .fmsPortraitTapSeek[hidden] {
  display: none;
}
body.fmsPortraitActive .fmsPortraitTapSeek.isShown {
  opacity: 1;
}
/* 最後に定義=最優先。フェードアウト時間は JS TAP_FADE と一致(§9) */
body.fmsPortraitActive .fmsPortraitTapSeek.isFading {
  opacity: 0;
  transition: opacity 120ms ease-out;
}

/* センター±10ボタンの隣スロット(position:relative)基準で外側へ配置(横UIと同一) */
body.fmsPortraitActive .fmsPortraitTapSeek.isForward {
  left: 100%;
}
body.fmsPortraitActive .fmsPortraitTapSeek.isBackward {
  right: 100%;
}

/* 数値領域は固定幅でレイアウトを揺らさない(§11。+120=4桁まで収まる) */
body.fmsPortraitActive .fmsPortraitTapSeekValue {
  display: inline-block;
  min-width: 3ch; /* -20〜-90 の通常域を基準(±100超は自然に広がる) */
}
body.fmsPortraitActive .fmsPortraitTapSeek.isForward .fmsPortraitTapSeekValue {
  text-align: right;
}
body.fmsPortraitActive .fmsPortraitTapSeek.isBackward .fmsPortraitTapSeekValue {
  text-align: left;
}

/* 矢印: 静止時 opacity 0.7(アニメ中のみ 1.0=WAAPIが上書き)。移動は transform(§0.5) */
body.fmsPortraitActive .fmsPortraitTapSeekArrow {
  display: inline-block;
  min-width: 1.2ch;
  text-align: center;
  opacity: 0.7;
  will-change: transform, opacity;
}

/* ==========================================================================
 * センター再生操作 −10/⏯/+10(2026-07-22 依頼(3): 横UIと同等)
 * メイン映像シングルタップ(body.fmsPortraitSkipOpen)+ canSeek(JSが hidden 制御)で
 * メイン映像中央に白の3ボタンを重ねる。z-index はネイティブ .fvPlayScreenView(=1500)
 * より前(=1550)で一時停止中も操作可能。クラスタ自体は pointer-events:none(ボタンのみ auto)。
 * ========================================================================== */
body.fmsPortraitActive .fmsPortraitSkipCluster {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 1550;
  display: none;
  align-items: center;
  gap: clamp(24px, 12vw, 80px);
  transform: translate(-50%, -50%);
  pointer-events: none;
}
body.fmsPortraitActive.fmsPortraitSkipOpen .fmsPortraitSkipCluster:not([hidden]) {
  display: flex;
}
/* ±10ボタンのラッパ。累積オーバレイ(.fmsPortraitTapSeek)の位置基準(隣に絶対配置) */
body.fmsPortraitActive .fmsPortraitSkipSlot {
  position: relative;
  display: inline-flex;
  pointer-events: none;
}
body.fmsPortraitActive .fmsPortraitSkipBtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  padding: 0;
  margin: 0;
  background: none;
  border: 0;
  color: #fff;
  cursor: pointer;
  pointer-events: auto;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  filter: drop-shadow(0 1px 5px rgba(0, 0, 0, 0.55));
}
body.fmsPortraitActive .fmsPortraitSkipBtn:active {
  transform: scale(0.92);
  opacity: 0.85;
}
body.fmsPortraitActive .fmsPortraitSkipBtn svg {
  display: block;
  width: 38px;
  height: 38px;
}
body.fmsPortraitActive .fmsPortraitSkipPlay {
  position: relative;
  font-size: 30px;
}
/* ⏯は当たり判定を広めに(見た目は不変)。拡大14pxは最小gap(24px)未満=±10には被らない */
body.fmsPortraitActive .fmsPortraitSkipPlay::before {
  content: '';
  position: absolute;
  top: -14px;
  right: -14px;
  bottom: -14px;
  left: -14px;
}
body.fmsPortraitActive .fmsPortraitSkipPlay .fa {
  line-height: 1;
}

/* ==========================================================================
 * 2. サブ映像カルーセル (設計書§4)
 *    寸法: タイル幅38vw / 列間8px / 行間8px / 左右padding12px → 右端peek約16vw
 *    (機能説明バナーは発注者フィードバック 2026-07-10 で廃止。縦幅圧縮のため
 *     タイル38vw・各行間/余白も圧縮済み)
 * ========================================================================== */

body.fmsPortraitActive .fmsPortraitCarousel {
  display: block;
  /* メイン映像の下端とサブ映像1行目の間に黒の余白(サブ画面の左右間隔と同幅=計8px)。
     内訳: margin 5px(親 #fvPlayer の暗背景が透ける) + padding-top 3px。
     padding 側に3px確保するのは、選択中タイルの緑枠線(box-shadow 2px外側)の
     上辺が overflow-y:hidden の clip 境界(=padding ボックス)で切れないようにするため。
     見た目の黒余白量は従来(8px)と不変。2026-07-11 */
  margin-top: 5px;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  padding: 3px var(--fms-space-3, 12px) 0;
  /* スナップは1行表示のときだけ(2026-07-28 発注者報告で 2行表示を none 化)。
     [2行表示で無効にした理由] スナップ点は奇数列(2列=1ページ)と拡大列(.fmsPortraitColLarge)
     だけに置いているため、拡大(x2)の右に x1 が2つ残る並びだと、右側の x1 列(偶数列)は
     スナップ点を持たない。mandatory は必ず最寄りのスナップ点で止まるので、右へスワイプしても
     手前の拡大列の先頭へ引き戻され、右端の x1 が半分しか見えない状態になっていた。
     1行表示はカード単位のスナップ点が全カードに付く(§1行化)ため同じ問題が起きず、
     レイアウトを揃える利点があるので従来どおり残す。付与は下の §1行化 セクション。
     スナップ点の指定(scroll-snap-align)は残置=none 中は無視され、1行化で復活する。 */
  scroll-snap-type: none;
  scroll-padding-left: var(--fms-space-3, 12px);
  /* スクロールバーは非表示(スワイプ可能の手掛かりは右端peekが担う) */
  scrollbar-width: none;
}
body.fmsPortraitActive .fmsPortraitCarousel::-webkit-scrollbar {
  display: none;
}

body.fmsPortraitActive .fmsPortraitTrack {
  position: relative; /* Phase 2 で canvas.fmsPortraitSubs (absolute z:0) の基準になる */
  display: flex;
  gap: var(--fms-space-2, 8px);
  width: max-content;
}

body.fmsPortraitActive .fmsPortraitCol {
  display: flex;
  flex-direction: column;
  gap: var(--fms-space-15, 6px); /* 1行目と2行目の縦間隔(F3で8→6px) */
  width: 38vw;
  flex: 0 0 auto;
}

/* ページ先頭列(1,3,5…列目)をスナップ点にする。track先頭の canvas.fmsPortraitSubs を
   数えないよう nth-child ではなく div の nth-of-type を使う */
body.fmsPortraitActive .fmsPortraitTrack > div.fmsPortraitCol:nth-of-type(odd) {
  scroll-snap-align: start;
}

/* ---- タイル拡大(2026-07-12): 右上インジケータで2x2⇄復元 ---- */

/* 拡大中タイルの列: 通常タイルの縦横2倍。幅=2列分+列間gap
   (タイルは16:9なので高さも自動的に上下2段分に一致)。
   偶数列に来ても単独ページを成せるよう常にスナップ点にする。 */
body.fmsPortraitActive .fmsPortraitColLarge {
  width: calc(76vw + var(--fms-space-2, 8px));
  scroll-snap-align: start;
}

/* 拡大中(2x)タイルはメイン選択の対象外(Option A・2行時のみ)。本体タップは無反応=
   ボタンではないのでカーソルも通常に(「x1」バッジのみ操作可能)。
   .fmsPortraitCard[data-tag]{cursor:pointer} に詳細度で勝つため属性も含める。 */
body.fmsPortraitActive .fmsPortraitCard.fmsPortraitCardLarge[data-tag] {
  cursor: default;
}

/* メイン選択中のタイルには拡大インジケータを出さない(意味の混同を避ける)。
   ただし「選択中かつ拡大中」は縮小(戻す)アイコンまで消すと復元手段が
   無くなるため、非表示は未拡大のときのみ。 */
body.fmsPortraitActive .fmsPortraitSelected:not(.fmsPortraitCardLarge) .fmsPortraitExpandBtn {
  display: none;
}

/* 拡大インジケータ(タイル右上)。「x2」⇄「x1」の白テキストバッジ:
   メイン選択(緑)と意味・色が被らない「サイズ切替」の表示。カード(z1)の上・タップ対象 */
body.fmsPortraitActive .fmsPortraitExpandBtn {
  -webkit-appearance: none;
  appearance: none;
  position: absolute;
  top: 2px;
  right: 2px;
  z-index: 2;
  min-width: 28px;
  height: 22px;
  padding: 0 6px;
  border: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(13, 13, 13, 0.55); /* 映像上でも視認できる薄い暗地 */
  color: #fff;
  border-radius: 6px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

body.fmsPortraitActive .fmsPortraitCard {
  position: relative;
  z-index: 1; /* 背後の canvas.fmsPortraitSubs(z0) より上(タップ対象・選択枠用) */
}

body.fmsPortraitActive .fmsPortraitCard[data-tag] {
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* タイルは透過枠。映像は背後の canvas.fmsPortraitSubs に描かれる(Phase 2〜)。
   canvas 描画前は #fvPlayer の暗背景が見える。 */
body.fmsPortraitActive .fmsPortraitTile {
  position: relative; /* 「選択中」バッジ(::after)の基準 */
  width: 100%;
  aspect-ratio: 16 / 9;
  background: transparent;
}

/* ---- 選択中表示(仕様6): 映像を隠さない緑枠のみ(バッジは映像を隠すため廃止)。
       状態の真実は li.fvSelected(syncSelection が写す) ---- */
body.fmsPortraitActive .fmsPortraitSelected .fmsPortraitTile {
  box-shadow: 0 0 0 2px var(--fms-green-400, #5DCAA5);
}

/* 選択中はキャプション名の頭に緑ドット([・ライブ]の・と同じ意匠、枠線と同色)を付す */
body.fmsPortraitActive .fmsPortraitSelected .fmsPortraitName::before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 4px;
  border-radius: 50%;
  background: var(--fms-green-400, #5DCAA5);
  vertical-align: middle;
  flex: 0 0 auto;
}

/* 選択中のキャプション名も同系色でアクセント */
body.fmsPortraitActive .fmsPortraitSelected .fmsPortraitName {
  color: var(--fms-green-300, #7ED7B8);
}

/* ---- 切替中パルス(§5.2 控えめローディング表現): 枠の明滅のみ ---- */
@keyframes fmsPortraitSwitchPulse {
  0%, 100% { box-shadow: 0 0 0 2px rgba(var(--fms-color-active-rgb, 93, 202, 165), 1); }
  50%      { box-shadow: 0 0 0 2px rgba(var(--fms-color-active-rgb, 93, 202, 165), 0.3); }
}

body.fmsPortraitActive .fmsPortraitSwitching .fmsPortraitTile {
  animation: fmsPortraitSwitchPulse 0.9s ease-in-out infinite;
}

/* 空きスロット: 暗色プレートのみ(§4.4。canvasには描画されない) */
body.fmsPortraitActive .fmsPortraitCardEmpty .fmsPortraitTile {
  background: var(--fms-gray-900, #1A1A1A);
  border-radius: 8px;
}

/* キャプション専用領域(映像に重ねない。仕様5)。
   番号バッジは廃止・名前のみのスリム行(発注者フィードバック 2026-07-10) */
body.fmsPortraitActive .fmsPortraitCaption {
  display: flex;
  align-items: center;
  min-height: 18px;
  padding: var(--fms-space-05, 2px) var(--fms-space-05, 2px) 0;
}

body.fmsPortraitActive .fmsPortraitName {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--fms-gray-200, #E0E0E3);
  font-size: var(--fms-text-2xs, 11px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* (ページインジケータ・ヒント文言は F1/F2 フィードバックで廃止。
   スワイプ可能の手掛かりは右端 peek のみ) */

/* ==========================================================================
 * 3. コントロールバー (設計書§6)
 *    Phase 1 は骨格のみ: isDummy で操作不能にして寸法・配置を確認する。
 * ========================================================================== */

/* 縦UI時は既存ネイティブバーを非表示にし、その高さ(LIVE40/DVR47px)を回収する(Phase 5)。
   操作は新バーからネイティブボタンへ trigger('click') で委譲するため、
   display:none でも機能は保たれる(jQueryハンドラは可視性に依らず発火)。 */
body.fmsPortraitActive .fvControlView {
  display: none !important;
}

/* 上下バランス(F3): モード行の上マージンが狭く下が広く見えるため、
   上に4px足し下を4pxに縮める(総高さは不変) */
body.fmsPortraitActive .fmsPortraitControls {
  /* 縦積み。行順は order で制御し、1行目=シークバー、2行目=モード行にする
     (.fmsPortraitSeek に order:-1)。DOM順・JS結線は不変。 */
  display: flex;
  flex-direction: column;
  padding: var(--fms-space-1, 4px) var(--fms-space-3, 12px) var(--fms-space-1, 4px);
}

/* ボタン要素のリセット(chip/trans はネイティブ button で組む) */
body.fmsPortraitActive .fmsPortraitChip,
body.fmsPortraitActive .fmsPortraitTransBtn {
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
  font-family: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* --- モード行 --- */
body.fmsPortraitActive .fmsPortraitMode {
  display: flex;
  align-items: center;
  gap: var(--fms-space-2, 8px);
}

body.fmsPortraitActive .fmsPortraitChip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--fms-space-15, 6px);
  height: 36px;
  padding: 0 var(--fms-space-3, 12px);
  border: 1px solid var(--fms-gray-600, #454545);
  border-radius: 999px;
  color: #fff;
  font-size: var(--fms-text-sm, 13px);
  white-space: nowrap;
}

/* ●ライブ表示(F8): YouTube式の枠なしドット+テキスト。
   [ライブ](赤ドット)⇄[ライブに戻る](グレードット・タップで復帰)の2状態 */
body.fmsPortraitActive .fmsPortraitLive {
  -webkit-appearance: none;
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: var(--fms-space-15, 6px);
  height: 36px; /* タップ当たり確保(見た目は文字のみ) */
  padding: 0 var(--fms-space-1, 4px);
  border: 0;
  background: transparent;
  color: #fff;
  font-family: inherit;
  font-size: var(--fms-text-sm, 13px);
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* LIVEモード中はインジケータであってボタンではない */
body.fmsPortraitActive .fmsPortraitControls.isStateLive .fmsPortraitLive {
  cursor: default;
}

body.fmsPortraitActive .fmsPortraitLiveDot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #E5484D; /* 赤=ライブ先頭(既存 .fvLiveCaption の意味色) */
  flex: 0 0 auto;
}

/* DVR後方: グレードット(YouTubeの巻戻し中表示と同じ意味論) */
body.fmsPortraitActive .fmsPortraitControls.isStateDvrRewind .fmsPortraitLiveDot {
  background: var(--fms-gray-disabled, #7C848C);
}

/* 右端アイコン群([シアター][⚙]) */
body.fmsPortraitActive .fmsPortraitModeRight {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--fms-space-1, 4px);
}

body.fmsPortraitActive .fmsPortraitMenuWrap {
  position: relative;
}

body.fmsPortraitActive .fmsPortraitIconBtn {
  -webkit-appearance: none;
  appearance: none;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--fms-gray-200, #E0E0E3);
  font-size: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* 表示切替アイコン(CSS描画・依存フォント不要)。図柄は「押した先の状態」を示す:
   OFF(カルーセル表示中)   = 単一長方形(押すと1画面化)
   ON (1画面=シアター表示中) = 2x2の4分割(押すと分割表示へ戻す) */
body.fmsPortraitActive .fmsPortraitTheaterIcon {
  position: relative;
  display: inline-block;
  width: 18px;
  height: 14px;
}
/* 既定(OFF): 単一長方形を表示 */
body.fmsPortraitActive .fmsPortraitTheaterSingle {
  display: block;
  width: 18px;
  height: 13px;
  border: 1.5px solid currentColor;
  border-radius: 2px;
  box-sizing: border-box;
}
body.fmsPortraitActive .fmsPortraitTheaterGrid {
  display: none;
}
/* バー右端の表示切替(シアター)ボタンは非表示(2026-07-19 ユーザー指示):
   右端は[⚙ギア]になる。シアター切替はチャットヘッダ側の入口
   (youtube-comments.js → FmsPortraitWebgl.toggleTheater)が残る。
   DOM・結線・状態同期は温存=復活はこの規則を消すだけ。 */
body.fmsPortraitActive .fmsPortraitTheaterBtn {
  display: none !important;
}
/* ON: 4分割(2x2の塗り四角)を表示、単一長方形は隠す */
body.fmsPortraitActive .fmsPortraitTheaterBtn.isOn .fmsPortraitTheaterSingle {
  display: none;
}
body.fmsPortraitActive .fmsPortraitTheaterBtn.isOn .fmsPortraitTheaterGrid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 2px;
  width: 18px;
  height: 14px;
}
body.fmsPortraitActive .fmsPortraitTheaterGrid > i {
  display: block;
  background: currentColor;
  border-radius: 1px;
}

/* ⚙ギアメニュー(F8: 画質選択のみ収容)。
   下開きだと後続のチャット欄に隠れる(スタッキング競合)ため、
   YouTube同様にボタンの上=映像側へ開く。 */
body.fmsPortraitActive .fmsPortraitMenu {
  position: absolute;
  z-index: 20;
  bottom: calc(100% + 6px);
  right: 0;
  min-width: 128px;
  padding: var(--fms-space-1, 4px);
  background: var(--fms-gray-900, #1A1A1A);
  border: 1px solid var(--fms-gray-700, #333);
  border-radius: 10px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
}
body.fmsPortraitActive .fmsPortraitMenu[hidden] {
  display: none;
}

body.fmsPortraitActive .fmsPortraitMenuHead {
  padding: 6px 12px 2px;
  color: var(--fms-gray-400, #A0A0A5);
  font-size: var(--fms-text-2xs, 11px);
}

body.fmsPortraitActive .fmsPortraitQualityOption {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  padding: 10px 12px 10px 8px;
  border: 0;
  background: transparent;
  color: #fff;
  font-family: inherit;
  font-size: var(--fms-text-sm, 13px);
  text-align: left;
  border-radius: 6px;
  cursor: pointer;
}
/* チェック欄(選択有無でテキストがズレないよう固定幅を確保) */
body.fmsPortraitActive .fmsPortraitQualityOption::before {
  content: "";
  display: inline-block;
  width: 18px;
}
body.fmsPortraitActive .fmsPortraitQualityOption.isSelected::before {
  content: "\2713"; /* ✓ */
}
body.fmsPortraitActive .fmsPortraitQualityOption.isSelected {
  color: var(--fms-green-300, #7ED7B8);
  font-weight: 700;
}

/* --- シークバー(視覚は細く・当たりは44px。仕様10) --- */
body.fmsPortraitActive .fmsPortraitSeek {
  display: block;
  order: -1; /* コントロール1行目に配置(モード行を2行目へ。2026-07-11) */
  margin: -6px 0; /* 44px当たりを保ちつつ隣接行との視覚間隔を詰める */
}

body.fmsPortraitActive .fmsPortraitSeekHit {
  position: relative;
  height: 44px; /* タッチ当たり判定 */
  display: flex;
  align-items: center;
  padding: 0 8px;
  touch-action: none; /* ドラッグ中の縦スクロール抑止 */
}

body.fmsPortraitActive .fmsPortraitSeekBar {
  position: relative;
  width: 100%;
  height: 4px;
  border-radius: 2px;
  background: var(--fms-gray-600, #454545);
}

body.fmsPortraitActive .fmsPortraitSeekFill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 0;
  border-radius: 2px;
  background: #E5484D;
}

body.fmsPortraitActive .fmsPortraitSeekHandle {
  position: absolute;
  left: 0;
  top: 50%;
  width: 16px;
  height: 16px;
  margin: -8px 0 0 -8px;
  border-radius: 50%;
  background: #E5484D;
}

body.fmsPortraitActive .fmsPortraitSeekTip {
  position: absolute;
  bottom: calc(100% - 6px);
  transform: translateX(-50%);
  padding: 2px 6px;
  background: var(--fms-gray-950, #0D0D0D);
  border: 1px solid var(--fms-gray-700, #333);
  border-radius: 4px;
  color: #fff;
  font-size: var(--fms-text-2xs, 11px);
  white-space: nowrap;
  pointer-events: none;
}
body.fmsPortraitActive .fmsPortraitSeekTip[hidden] {
  display: none;
}

/* ==========================================================================
 * トランスポート行 一時非表示(2026-07-11)
 *   -30/-10/再生停止/+10/+30 の行全体を隠す。ダブルタップシーク(±10)と
 *   シークバーで代替でき、YouTube同様にボタン行を持たない方針。
 *   ★復活方法: 直下の「.fmsPortraitTransport { display:none }」ルール1つを削除するだけ。
 *   DOM(buildControls)と操作結線(wireControls)は温存しているため即復帰する。
 *   下段(状態別の可視性・寸法)の各ルールはそのまま残す。
 * ========================================================================== */
body.fmsPortraitActive .fmsPortraitTransport {
  display: none !important;
}

/* --- トランスポート行(左右対称・再生中央。仕様8)。
   F8: 画質チップはギアメニューへ移設したため、±群のみの単純な中央寄せに戻す --- */
body.fmsPortraitActive .fmsPortraitTransport {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: var(--fms-space-3, 12px);
  padding-top: var(--fms-space-05, 2px);
}

body.fmsPortraitActive .fmsPortraitTransBtn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--fms-space-05, 2px);
  padding: 0;
  border: 0;
}

body.fmsPortraitActive .fmsPortraitTransCircle {
  width: 44px;
  height: 44px;
  border: 1.5px solid var(--fms-gray-300, #CFCFD2);
  border-radius: 50%;
  color: #fff;
  font-size: var(--fms-text-sm, 13px);
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}

body.fmsPortraitActive .fmsPortraitTransPlay {
  width: 52px;
  height: 52px;
  background: var(--fms-gray-100, #F5F5F6);
  border-color: var(--fms-gray-100, #F5F5F6);
  color: var(--fms-gray-950, #0D0D0D);
  font-size: var(--fms-text-lg, 16px);
}

body.fmsPortraitActive .fmsPortraitTransLabel {
  color: var(--fms-gray-400, #A0A0A5);
  font-size: 10px;
}

/* ==========================================================================
 * 状態別の可視性(設計書§6.4。F8改定)。状態クラスは JS(syncControlState)が付与、
 * 可視性判定はここに集約する。
 *  live      : モード行のみの1行構成(●ライブ/巻戻し/シアター/⚙)。
 *              見たい馬/シーク行/トランスポート行を隠す
 *  dvrNear   : 全部表示(●赤ドット「ライブ」)
 *  dvrRewind : 全部表示(●グレードット「ライブに戻る」・タップで復帰)
 *  recorded  : ●ライブ/巻戻し/見たい馬を隠し、シーク+トランスポート(VODレンジ)
 * ========================================================================== */

/* 既定(dvrNear/dvrRewind)は全要素表示。以下で状態ごとに隠す。 */

/* LIVE: 1行構成(F8)。シーク行・トランスポート行・見たい馬を行ごと隠す */
body.fmsPortraitActive .fmsPortraitControls.isStateLive .fmsPortraitSeek,
body.fmsPortraitActive .fmsPortraitControls.isStateLive .fmsPortraitTransport,
body.fmsPortraitActive .fmsPortraitControls.isStateLive .fmsPortraitChipSeeker {
  display: none;
}

/* 録画(VOD): ●ライブ・巻戻し・見たい馬を隠す */
body.fmsPortraitActive .fmsPortraitControls.isStateRecorded .fmsPortraitLive,
body.fmsPortraitActive .fmsPortraitControls.isStateRecorded .fmsPortraitChipDvr,
body.fmsPortraitActive .fmsPortraitControls.isStateRecorded .fmsPortraitChipSeeker {
  display: none;
}

/* ==========================================================================
 * VOD(録画)用コントロール群(2026-07-16 発注者指示)
 *   モード行の左側を [▶/⏸][-10][+10][現在時刻/尺] に差し替える(右端の⚙/□は共通)。
 *   デザインはPC版アーカイブのバー構成に準拠しつつ、部品は縦UIの意匠
 *   (アイコンボタン=fmsPortraitIconBtn相当/円形アウトライン=TransCircle縮小版)で組む。
 *   表示は録画状態(isStateRecorded)のときだけ。ボリューム制御は置かない(スマホ不要)。
 * ========================================================================== */
body.fmsPortraitActive .fmsPortraitVod {
  display: none;
  align-items: center;
  gap: var(--fms-space-2, 8px);
  min-width: 0;
}
body.fmsPortraitActive .fmsPortraitControls.isStateRecorded .fmsPortraitVod {
  display: inline-flex;
}

/* ▶/⏸ : アイコンのみ(枠なし。fmsPortraitIconBtn と同じ作法・タップ当たり40px) */
body.fmsPortraitActive .fmsPortraitVodPlay {
  -webkit-appearance: none;
  appearance: none;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  background: transparent;
  color: #fff;
  font-size: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* -10/+10 : 円形アウトライン(トランスポート行の TransCircle 縮小版) */
body.fmsPortraitActive .fmsPortraitVodSeek {
  -webkit-appearance: none;
  appearance: none;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 1.5px solid var(--fms-gray-300, #CFCFD2);
  border-radius: 50%;
  background: transparent;
  color: #fff;
  font-family: inherit;
  font-size: var(--fms-text-xs, 12px);
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* 現在時刻/尺(±10の右隣。ネイティブ fvTimeLabel と同じ HH:MM:SS/HH:MM:SS) */
body.fmsPortraitActive .fmsPortraitVodTime {
  color: #fff;
  font-size: var(--fms-text-xs, 12px);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* VOD(録画)時、縦向きはコメント(チャット)領域自体を表示しない(2026-07-16 発注者指示)。
   「チャットを表示」トグル・再表示バーも同様に隠す。fmsVodMode は index.php が
   配信モード=VOD(player_mode=2)のとき body へサーバー出力する */
body.fmsVodMode.fmsPortraitActive #youtube-comments-wrapper,
body.fmsVodMode.fmsPortraitActive #chat-mobile-toggle,
body.fmsVodMode.fmsPortraitActive #chat-reopen-bar {
  display: none !important;
}

/* ==========================================================================
 * 一時停止時のプレイスクリーン(.fvPlayScreenView)差し替え(2026-07-16 発注者指示)
 *   ネイティブは「再生ボタン画像(play.png=青▶)+告知サムネイル」の2枚重ね+黒50%だが、
 *   初回再生後(body.fmsPlayedOnce=index.php が 'playing' 初回で付与)の一時停止では
 *   ・▶をプレーヤー配色の緑(#5DCAA5)に(元画像と同じ白角丸下地+三角のSVGデータURI)
 *   ・サムネイル/黒幕を敷かず、止めた場面が見えるままにする
 *   再生前(初回タップ前)は従来どおり(告知サムネイル+ネイティブ画像)。
 *   サイズ/位置はネイティブ規則(background-size:80px・中央)をそのまま使う。
 * ========================================================================== */
body.fmsPlayedOnce.fmsPortraitActive div.fvVideoView > div.fvPlayScreenView {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' rx='12' fill='rgba(255,255,255,0.9)'/%3E%3Cpath d='M38 28 L74 50 L38 72 Z' fill='%235DCAA5'/%3E%3C/svg%3E") !important;
  background-color: transparent !important;
}
/* センター −10/⏯/+10 表示中(fmsPortraitSkipOn=JSがcanSeek時に付与)は緑▶を隠す:
   ⏯ボタン(fa-play表示)と役割が重複するため。クリックでの再開層としては生かす(2026-07-22 依頼(3)) */
body.fmsPortraitSkipOn.fmsPlayedOnce.fmsPortraitActive div.fvVideoView > div.fvPlayScreenView {
  background-image: none !important;
}
/* メインビューのネイティブclickpoint(即時1画面切替)は縦UI中はタップ不能に=
   メイン映像タップは自前 onPortraitPlayerTap(センタークラスタ表示)へ一本化する(2026-07-22 依頼(3)) */
body.fmsPortraitActive #clickpoint_main {
  pointer-events: none;
}

/* 見たい馬が使用不可(native HLS / seeker禁止 / van_dvr)のときは常に隠す */
body.fmsPortraitActive .fmsPortraitControls.isSeekerHidden .fmsPortraitChipSeeker {
  display: none;
}

/* DVR使用許可=禁止(console.php van_dvr=1)のときは[巻戻し]チップを常に隠す
   (2026-07-16。期待表示: [・ライブ] ⚙ □ の1行。付与元 syncControlState) */
body.fmsPortraitActive .fmsPortraitControls.isDvrDisabled .fmsPortraitChipDvr {
  display: none;
}

/* 巻戻しトグルの ON/OFF 見た目(DVR中は緑寄りに) */
body.fmsPortraitActive .fmsPortraitControls.isStateDvrNear .fmsPortraitChipDvr,
body.fmsPortraitActive .fmsPortraitControls.isStateDvrRewind .fmsPortraitChipDvr {
  border-color: var(--fms-green-400, #5DCAA5);
  color: var(--fms-green-300, #7ED7B8);
}

/* ==========================================================================
 * 縦シアターモード(F8 → 2026-07-14 試験変更): サブ映像カルーセルを
 * 「全消し」ではなく 1行へ変形する(2行分→1行分の高さが浮き、チャットは
 * youtube-comments.js の「チャット上端→画面下端」実測式で自動的に拡大される)。
 * 必ず fmsPortraitActive との複合で効かせる(横向き/PC/縦UI無効時は無影響)。
 *
 * 1行化の方法: 列(.fmsPortraitCol)を display:contents で解体し、全カードを
 * .fmsPortraitTrack(flex row)の直下アイテムにする。
 *
 * 並び順は「列優先」= 左端の列から右へ、各列は上→下(2026-07-28 ユーザー決定):
 *   [[4,3,6,1],[2,7,5,null]] → 4,2,3,7,6,5,1
 * これは DOM の文書順そのもの(列ごとに 1行目→2行目 が入っている)なので、
 * order による並べ替えを行わない。**横向きUIのカメラリスト(縦並び)の順序
 * (fms-landscape-webgl.js resolveCamOrder の列優先平坦化)と一致する**のが狙い。
 * 旧実装は「元の1行目(左→右)→2行目(左→右)」の行優先で、order:0/1 で並べ替えていた。
 * WebGL(canvas.fmsPortraitSubs)はタイル実測位置へ描くため再実測だけで追従する。
 * ========================================================================== */

/* スナップは1行表示のときだけ効かせる(2026-07-28 発注者決定)。既定(2行表示)は none
   にしてある(§カルーセルの scroll-snap-type のコメント参照)。1行表示は下の
   .fmsPortraitCard に全カード分のスナップ点が付き、拡大(x2)も無効なので、
   「スナップ点を持たないカードが取り残される」問題は起きない。 */
body.fmsPortraitActive.fmsPortraitTheater .fmsPortraitCarousel {
  scroll-snap-type: x mandatory;
}

body.fmsPortraitActive.fmsPortraitTheater .fmsPortraitCol {
  display: contents;
}
body.fmsPortraitActive.fmsPortraitTheater .fmsPortraitCard {
  width: 38vw;
  flex: 0 0 auto;
  /* order は指定しない = 文書順(列優先: 左の列から順に上→下)。上のコメント参照。
     2026-07-28 に行優先(order:0/1)から変更した。 */
  scroll-snap-align: start; /* 列由来のスナップ点が消えるためカード単位に */
}
/* 空きスロットは1行モードでは意味が無い(行末に空箱が並ぶ)ため隠す */
body.fmsPortraitActive.fmsPortraitTheater .fmsPortraitCardEmpty {
  display: none;
}
/* 拡大(2x)は1行モードでは無効(見た目は通常サイズ=上の width:38vw が
   colLarge の 76vw より優先される)。切替バッジも隠す。
   クラス自体は温存されるためシアターOFFで元の拡大状態に復帰する */
body.fmsPortraitActive.fmsPortraitTheater .fmsPortraitExpandBtn {
  display: none !important;
}
/* 1行(シアター)では 2x が視覚的に無効化されるため、拡大扱いのカードも
   通常カード同様にタップでメイン切替できる(JS側も theaterOn 時は抑止しない)。
   上の cursor:default(2行時の据え置き表現)を打ち消し pointer に戻す。 */
body.fmsPortraitActive.fmsPortraitTheater .fmsPortraitCard.fmsPortraitCardLarge[data-tag] {
  cursor: pointer;
}

/* ==========================================================================
 * 狭幅フィット(幅389px以下 = SE2/12mini級)。DVR後方時の
 * [●ライブに戻る][巻戻し][見たい馬][シアター][⚙] を1行に収める(F8)
 * ========================================================================== */

@media (max-width: 389px) {
  body.fmsPortraitActive .fmsPortraitMode {
    gap: var(--fms-space-15, 6px);
  }
  body.fmsPortraitActive .fmsPortraitChip {
    padding: 0 var(--fms-space-2, 8px);
    font-size: var(--fms-text-xs, 12px);
  }
  body.fmsPortraitActive .fmsPortraitLive {
    font-size: var(--fms-text-xs, 12px);
    padding: 0 var(--fms-space-05, 2px);
  }
  body.fmsPortraitActive .fmsPortraitIconBtn {
    width: 34px;
    height: 36px;
    font-size: 16px;
  }
}

/* ==========================================================================
 * 4. コンパクト段 (画面高さ700px以下 = iPhone SE/8世代。F2フィードバック)
 *    メディアクエリの height はURLバー表示状態の実レイアウトビューポートに追従する。
 *    タイルを約29vw化して3枚全表示+4枚目peek(約5vw)、ボタン類も一段縮小し、
 *    トランスポート行までを初期表示に収める。
 * ========================================================================== */

@media (max-height: 700px) {
  /* 【仮処置(F3・可逆)】SE2級ではお知らせテロップ(#ticker)を非表示にして
     チャット開閉バーまでを初期表示に収める。戻す場合はこのルールを削除するだけ。
     body.fmsPortraitActive スコープのため横向き/PC/縦UI無効時には一切影響しない。 */
  body.fmsPortraitActive #ticker {
    display: none;
  }
  body.fmsPortraitActive .fmsPortraitCarousel {
    /* コンパクト段は計6px(margin 3px + padding-top 3px)。padding は緑枠線の上辺確保用 */
    margin-top: 3px;
    padding: 3px var(--fms-space-2, 8px) 0;
    scroll-padding-left: var(--fms-space-2, 8px);
  }
  body.fmsPortraitActive .fmsPortraitTrack {
    gap: var(--fms-space-15, 6px);
  }
  body.fmsPortraitActive .fmsPortraitCol {
    width: 29vw;
    gap: var(--fms-space-1, 4px); /* 1行目と2行目の縦間隔(F3で6→4px) */
  }
  body.fmsPortraitActive .fmsPortraitColLarge {
    width: calc(58vw + var(--fms-space-15, 6px)); /* コンパクト段: 29vw×2+列間6px */
  }
  body.fmsPortraitActive .fmsPortraitExpandBtn {
    min-width: 24px;
    height: 20px;
    padding: 0 5px;
    font-size: 11px;
  }
  body.fmsPortraitActive .fmsPortraitCaption {
    min-height: 15px;
    padding-top: 1px;
  }
  body.fmsPortraitActive .fmsPortraitName {
    font-size: 10px;
  }
  body.fmsPortraitActive .fmsPortraitControls {
    padding-top: var(--fms-space-05, 2px);
    padding-bottom: var(--fms-space-05, 2px);
  }
  body.fmsPortraitActive .fmsPortraitChip {
    height: 32px;
  }
  body.fmsPortraitActive .fmsPortraitSeek {
    margin: -8px 0;
  }
  body.fmsPortraitActive .fmsPortraitTransCircle {
    width: 40px;
    height: 40px;
    font-size: var(--fms-text-xs, 12px);
  }
  body.fmsPortraitActive .fmsPortraitTransPlay {
    width: 46px;
    height: 46px;
  }
  /* ラベル(「30秒戻し」等)は円内の数字で自明のため省略して1行分を稼ぐ */
  body.fmsPortraitActive .fmsPortraitTransLabel {
    display: none;
  }
}

/* iOS WebKit: 回転後の初回バッファリングでスピナーが全点灯(アニメ停止)する対策。
   表示された瞬間に index.php がこのクラスを1フレームだけ付け、::before の
   アニメーションを外して再適用=負の animation-delay 込みで再始動させる。
   (fms-landscape-webgl.css にも同じ規則あり=どちらか一方のみ読込でも効くように) */
.sk-fading-circle.fmsSpinnerRestart .sk-circle:before {
  -webkit-animation: none !important;
  animation: none !important;
}

/* =========================================================================
   設定ボトムシート(⚙。2026-07-19 ユーザー決定)
   設計: docs/sp_tate_setting_bottomseat/スマホ縦向き_設定ボトムシート案.md。
   見た目は横UI(fms-landscape-webgl.css の設定ボトムシート節)と同一系:
   シート白背景 / 区切り#E5E5E5 / 説明背景#F2FAF6 / トグルON#00A05A / OFF#BDBDBD。
   縦向きは全幅シート(§9: inset-inline:0)で、横シートとの相違は幅と max-height のみ。
   ========================================================================= */
/* バックドロップ(暗転。背面操作の遮断はJS側 stopPropagation+ここの touch-action) */
body.fmsPortraitActive .fmsPortraitSheetBackdrop {
  position: fixed;
  inset: 0;
  z-index: 9999; /* 凍結梯子のモーダル層(.modal と同値。ハンバーガーパネル/画質DD等の
                    一時オーバーレイ層9998より前面。新数値は発明しない=style.css冒頭の規約) */
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(0, 0, 0, 0);
  transition: background 220ms ease; /* SHEET_ANIM_MS(JS)と合わせる */
  touch-action: none; /* 暗転部から背面ページをスクロールさせない(§15。document には触らない) */
}
/* hidden の確実化はスコープ外でも効かせる(回転で fmsPortraitActive が外れた直後の保険) */
.fmsPortraitSheetBackdrop[hidden] {
  display: none !important;
}
body.fmsPortraitActive .fmsPortraitSheetBackdrop.isOpen {
  background: rgba(0, 0, 0, 0.6); /* §9: 黒・不透明度50〜70% */
}

/* シート本体(§9: 全幅・上部角丸24px・safe-area) */
body.fmsPortraitActive .fmsPortraitSheet {
  width: 100%;
  max-height: min(78vh, 640px);  /* dvh 非対応環境のフォールバック */
  max-height: min(78dvh, 640px);
  display: flex;
  flex-direction: column;
  background: #fff;
  color: #111111;
  border-radius: 24px 24px 0 0;
  box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.35);
  padding-bottom: max(16px, env(safe-area-inset-bottom)); /* Safari下部バー中でも末尾へ到達(§9) */
  transform: translateY(100%);
  transition: transform 220ms ease-out;
}
body.fmsPortraitActive .fmsPortraitSheetBackdrop.isOpen .fmsPortraitSheet {
  transform: translateY(0);
}
body.fmsPortraitActive .fmsPortraitSheet.isDragging {
  transition: none; /* 下ドラッグ追従中はJSの translate を即時反映 */
}
@media (prefers-reduced-motion: reduce) {
  body.fmsPortraitActive .fmsPortraitSheetBackdrop,
  body.fmsPortraitActive .fmsPortraitSheet {
    transition: none; /* §7.3 */
  }
}

/* ヘッダ(ハンドル/タイトル/×)。下ドラッグで閉じる起点はここに限定 */
body.fmsPortraitActive .fmsPortraitSheetHead {
  position: relative;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  padding: 10px 10px 0 24px;
  touch-action: none; /* ヘッダのドラッグをスクロールに奪わせない */
}
body.fmsPortraitActive .fmsPortraitSheetHandle {
  position: absolute;
  top: 8px;
  left: 50%;
  width: 44px;
  height: 4px;
  margin-left: -22px;
  border-radius: 2px;
  background: #d9d9d9;
}
body.fmsPortraitActive .fmsPortraitSheetTitle {
  flex: 1 1 auto;
  margin: 10px 0 0;
  font-size: 20px;
  font-weight: 700;
  line-height: 1.2;
  color: #111111;
}
body.fmsPortraitActive .fmsPortraitSheetClose {
  flex: 0 0 auto;
  width: 44px;   /* タップ領域 最低44×44(§9/§14) */
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: 2px;
  padding: 0;
  background: none;
  border: none;
  color: #111111;
  font-size: 20px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* 本文(画面高が低い端末は内部スクロール。§9) */
body.fmsPortraitActive .fmsPortraitSheetBody {
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y; /* 本文の縦スクロールのみ許可(バックドロップの none を上書き) */
  padding: 0 20px 16px; /* シート内部左右余白 20〜24px(§9) */
}

/* 設定行 */
body.fmsPortraitActive .fmsPortraitSetItem {
  border-top: 1px solid #e5e5e5;
}
body.fmsPortraitActive .fmsPortraitSetItem:first-child {
  border-top: none;
}
body.fmsPortraitActive .fmsPortraitSetRow {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 60px; /* §9: 設定行 60〜64px(タップ領域44px は維持) */
}
body.fmsPortraitActive .fmsPortraitSetIcon {
  flex: 0 0 auto;
  width: 24px;
  text-align: center;
  color: #111111;
  font-size: 17px;
}
body.fmsPortraitActive .fmsPortraitSetLabel {
  flex: 1 1 auto;
  font-size: 16px;
  font-weight: 600;
  color: #111111;
}
body.fmsPortraitActive .fmsPortraitSetInfo {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: none;
  border: none;
  color: #6b7280;
  font-size: 17px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
/* 「1行」選択不可中の補足(ユーザー決定D。色以外でも無効を示す=§14) */
body.fmsPortraitActive .fmsPortraitSetHint {
  margin: -6px 0 12px 0;
  font-size: 12px;
  color: #6b7280;
}
/* ⓘ説明(§7.3) */
body.fmsPortraitActive .fmsPortraitSetHelp {
  margin: 0 0 12px 34px;
  padding: 12px 14px;
  border-radius: 8px;
  background: #f2faf6; /* rgba(0,138,91,.08)相当 */
  color: #2f7a57;
  font-size: 13px;
  line-height: 1.6;
}

/* トグルスイッチ(ON=ブランドグリーン/OFF=グレー。input は透明で全面タップ) */
body.fmsPortraitActive .fmsPortraitSwitch {
  flex: 0 0 auto;
  position: relative;
  display: inline-block;
  width: 51px;
  height: 31px;
}
body.fmsPortraitActive .fmsPortraitSwitch input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
body.fmsPortraitActive .fmsPortraitSwitch input:disabled {
  cursor: default;
}
body.fmsPortraitActive .fmsPortraitSwitchVisual {
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: #bdbdbd;
  transition: background 150ms ease;
  pointer-events: none;
}
body.fmsPortraitActive .fmsPortraitSwitchVisual::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 27px;
  height: 27px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  transition: transform 150ms ease;
}
body.fmsPortraitActive .fmsPortraitSwitch input:checked + .fmsPortraitSwitchVisual {
  background: #00a05a;
}
body.fmsPortraitActive .fmsPortraitSwitch input:checked + .fmsPortraitSwitchVisual::after {
  transform: translateX(20px);
}
@media (prefers-reduced-motion: reduce) {
  body.fmsPortraitActive .fmsPortraitSwitchVisual,
  body.fmsPortraitActive .fmsPortraitSwitchVisual::after {
    transition: none;
  }
}

/* セグメント(カメラ一覧 2行/1行・画質。選択中=塗りつぶし+太字) */
body.fmsPortraitActive .fmsPortraitSetItemSeg .fmsPortraitSetRow {
  min-height: 48px; /* 見出し行(トグル無し)は詰める */
}
body.fmsPortraitActive .fmsPortraitSegGroup {
  display: flex;
  margin: 2px 0 16px;
  border: 1px solid #d1d5db;
  border-radius: 10px;
  overflow: hidden;
}
body.fmsPortraitActive .fmsPortraitSegBtn {
  flex: 1 1 0;
  min-height: 44px;
  padding: 0;
  background: #fff;
  border: none;
  border-left: 1px solid #d1d5db;
  color: #111111;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
body.fmsPortraitActive .fmsPortraitSegBtn:first-child {
  border-left: none;
}
body.fmsPortraitActive .fmsPortraitSegBtn.isActive {
  background: #111111;
  color: #fff;
  font-weight: 700;
}
/* チャットOFF中の「1行」(ユーザー決定D): 薄く+押せない */
body.fmsPortraitActive .fmsPortraitSegBtn:disabled {
  opacity: 0.4;
  cursor: default;
}

/* =========================================================================
   再生エラー画面(.fvErrorView)の前面化(2026-07-27 発注者報告。横UIと同内容)
   ネイティブのエラー画面は .fvVideoView 内の z-index:1000(fvLivePlayer/css/common.css)で、
   本UIが映像に重ねるレイヤー(ネイティブのプレイスクリーン1500 /
   センター −10/⏯/+10 1550)より背面にある。そのためエラー表示中もそれらが上に乗り、
   リロードボタン(.fvErrorReload)を押せなかった。
   1600 は上記より前面・設定シートのバックドロップ(9999=モーダル層)より背面。
   [対で必要] タップがクラスタのトグルへ流れる件は、エラー画面が .fvVideoView の子で
   click が親まで伝播するため z-index では止まらない。JS 側(onPortraitPlayerTap の
   isErrorShown 早期return)で止めている。
   ========================================================================= */
body.fmsPortraitActive div.fvVideoView > div.fvErrorView {
  z-index: 1600 !important;
}

/* ---- 再生エラー中はサブ画面(カルーセル)を黒く伏せる(2026-07-28 発注者報告) ----
   メインが「再生エラー」なのにサブだけ絵が残って見える件の表示側の対処。
   サブは video を texture 源にした WebGL 転写なので、エラーで video が止まると
   描画が更新されなくなるだけで canvas には直前のフレームが残る。
   フックは body.fmsPortraitError(付与元: fms-portrait-webgl.js の syncErrorState。
   .fvErrorView の表示を MutationObserver で監視)。描画自体も renderFrame で止める。
   [伏せ方] トラックごと visibility:hidden にして canvas・タイル枠・カメラ名を
   まとめて隠し、親のカルーセルを黒で塗る。タイルは透過枠なので canvas を隠すだけでは
   枠とラベルが残ってしまう。visibility:hidden はタップも無効になるが、エラー中に
   カメラを切り替えても意味がないため都合がよい。 */
body.fmsPortraitActive.fmsPortraitError .fmsPortraitCarousel {
  background: #000;
}
body.fmsPortraitActive.fmsPortraitError .fmsPortraitTrack {
  visibility: hidden;
}
