/* =====================================================================
   Scenario Console — design tokens
   Grounded in the subject: a holographic command-room editor for
   building visual-novel style scenario screens.
   ===================================================================== */
:root {
  --bg-void: #05070d;
  --bg-panel: #0e1526;
  --bg-panel-raised: #161f36;
  --bg-input: #0c1220;

  --line-cyan: #45d6ff;
  --line-cyan-dim: rgba(69, 214, 255, 0.22);
  --line-cyan-dimmer: rgba(69, 214, 255, 0.1);

  --text-primary: #e9f2ff;
  --text-muted: #7c8bab;
  --text-faint: #4d5875;

  --accent-gold: #d8b26a;
  --accent-gold-dim: rgba(216, 178, 106, 0.18);

  --danger: #ff6b76;
  --danger-dim: rgba(255, 107, 118, 0.15);

  /* シナリオ/動画保存など、動画関連の機能だけを他と見分けやすくする
     ためのアクセント（既存のcyan/goldとは別系統の色にしている） */
  --accent-video: #ff6ad5;
  --accent-video-dim: rgba(255, 106, 213, 0.16);

  --radius-s: 6px;
  --radius-m: 10px;
  --radius-l: 16px;
  --console-width: 360px;

  --font-ui: -apple-system, "Hiragino Sans", "Yu Gothic UI", "Segoe UI", system-ui, sans-serif;
  --font-mono: ui-monospace, "SFMono-Regular", "Consolas", "Menlo", monospace;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
}

body {
  background: var(--bg-void);
  color: var(--text-primary);
  font-family: var(--font-ui);
  overflow: hidden;
}

button, input, textarea {
  font-family: inherit;
  color: inherit;
}

:focus-visible {
  outline: 2px solid var(--line-cyan);
  outline-offset: 2px;
}

/* subtle ambient grid on the void, evokes the bridge/monitor room */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(var(--line-cyan-dimmer) 1px, transparent 1px),
    linear-gradient(90deg, var(--line-cyan-dimmer) 1px, transparent 1px);
  background-size: 48px 48px;
  opacity: 0.35;
  z-index: 0;
}

.app {
  position: relative;
  z-index: 1;
  display: flex;
  height: 100vh;
  width: 100vw;
}

/* ================= サーヴァント詳細専用の定型表記フローティングツール =================
   画面左下に固定——キャンバスやコンソールの通常のレイアウトとは独立に
   常時表示する（サーヴァント詳細タブの間だけ）。 */
.template-toolbar {
  position: fixed;
  left: 16px;
  bottom: 16px;
  z-index: 50;
  width: 220px;
  background: rgba(10, 14, 26, 0.92);
  border: 1px solid var(--line-cyan-dim);
  border-radius: var(--radius-m);
  padding: 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.template-toolbar.is-hidden { display: none; }
.template-toolbar.is-collapsed .template-toolbar__row { display: none; }
.template-toolbar__title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin: -10px -10px 8px;
  padding: 8px 10px;
  cursor: move;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  border-bottom: 1px solid var(--line-cyan-dim);
}
.template-toolbar__collapse-btn {
  border: none;
  background: none;
  color: var(--text-muted);
  font-size: 10px;
  line-height: 1;
  padding: 2px 4px;
  cursor: pointer;
  touch-action: auto;
}
.template-toolbar__collapse-btn:hover { color: var(--text-primary); }
.template-toolbar__row {
  display: flex;
  align-items: center;
  gap: 6px;
}
.template-toolbar__row--grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
}
.template-toolbar__btn {
  flex: 1;
  min-width: 0;
  border: 1px solid var(--line-cyan-dim);
  border-radius: var(--radius-s);
  background: var(--bg-panel-raised);
  color: var(--text-primary);
  font-size: 12px;
  padding: 6px 8px;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: border-color .15s ease, background .15s ease;
}
.template-toolbar__btn:hover {
  border-color: var(--line-cyan);
  background: var(--line-cyan-dimmer);
}
.template-toolbar__btn--wide {
  font-size: 11px;
}
.template-toolbar .field__input--number-small {
  flex: 0 0 auto;
}

/* ================= 画面切り替えタブ（シナリオ / サーヴァント詳細） =================
   CHALDEA CONSOLE内、背景パネルより上に置く——タブ自体は常に表示され続ける
   必要がある（隠れると切り替えられなくなるため）ので、切り替えの対象
   （プレビュー側のキャンバス描画内容・コンソール側の.console__scroll）
   とは別に、常設のヘッダー直下に置いている。 */
.mode-tabs {
  display: flex;
  flex-shrink: 0;
  gap: 6px;
  padding: 14px 22px;
  border-bottom: 1px solid var(--line-cyan-dim);
}
.mode-tab {
  flex: 1;
  appearance: none;
  border: 1px solid var(--line-cyan-dim);
  background: var(--bg-input);
  color: var(--text-muted);
  border-radius: var(--radius-s);
  padding: 8px 10px;
  font-size: 12.5px;
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease, color .15s ease;
}
.mode-tab:hover { border-color: var(--line-cyan); color: var(--text-primary); }
.mode-tab.is-active {
  background: var(--line-cyan-dimmer);
  border-color: var(--line-cyan);
  color: var(--line-cyan);
  font-weight: 600;
}

/* サーヴァント詳細タブの間、コンソール（.console__scroll）の中身を隠し、
   代わりにプレースホルダーを表示する。プレビュー側はキャンバス自体は
   常に表示したまま、描く内容をJS側で切り替える（.stage__hintだけは
   シナリオ専用の操作説明なのでここで隠す）。
   ※!importantが必要——「body.console-wide .console__scroll」（コンソール
   幅を広げた時の2列化ルール、下記参照）はbody要素ぶん詳細度が高く、
   後から書いても素の.is-hiddenでは負けてしまう。負けると、コンソールを
   広げてconsole-wideになった瞬間、隠しているはずのシナリオ側の
   コンソール（背景/キャラクター/動画パネル）がdisplay:flexで復活し、
   サーヴァント詳細のコンソールと重なって干渉して見える不具合になる。 */
.console__scroll.is-hidden,
.stage__hint.is-hidden {
  display: none !important;
}
.mode-page__placeholder {
  color: var(--text-faint);
  font-size: 14px;
  letter-spacing: 0.05em;
}

/* ================= STAGE (canvas area) ================= */
.stage {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 28px;
  min-width: 0;
}

.stage__header {
  width: 100%;
  max-width: 1100px;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}

.stage__eyebrow {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.22em;
  color: var(--line-cyan);
  text-transform: uppercase;
}

.stage__res {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-faint);
  letter-spacing: 0.05em;
}

.stage__header-right {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* スマホ幅でだけ現れるプレビュー表示切替スイッチ（下のメディアクエリ内で
   display切り替え）。デスクトップではプレビューとコンソールが横並びで
   常に両方見えるので不要。他の「〇〇を表示」系スイッチと見た目・挙動を
   揃えるため、独自ボタンではなく共通の.switchコンポーネントを使う。 */
.stage__preview-switch {
  display: none;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  color: var(--text-muted);
  letter-spacing: 0.05em;
  cursor: pointer;
}

.monitor {
  position: relative;
  width: 100%;
  /* +28pxは左右パディング(14px×2)の分。中身のフレームが1100pxで頭打ちになるのは元と同じ */
  max-width: calc(1100px + 28px);
  padding: 14px;
}

.monitor__frame {
  position: relative;
  width: 100%;
  /* aspect-ratioはここに置く。.monitor側に置くと固定14pxパディングの比率が
     縮小時に無視できなくなり、コンソール幅を変えるとわずかに16:9からズレていた */
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-m);
  background: #000;
  box-shadow:
    0 0 0 1px var(--line-cyan-dim),
    0 30px 80px -20px rgba(0,0,0,0.7),
    inset 0 0 40px rgba(69, 214, 255, 0.05);
  overflow: hidden;
}

#sceneCanvas {
  width: 100%;
  height: 100%;
  display: block;
  cursor: grab;
  /* デフォルトのtouch-action:autoのままだと、立ち絵のドラッグ移動/拡縮を
     ブラウザがページのスクロール/ピンチズームのジェスチャーと誤認して
     横取りしてしまう。すべてこちらのpointerイベントで処理するので、
     ブラウザ側のタッチジェスチャーは無効化する。 */
  touch-action: none;
}
#sceneCanvas.is-dragging { cursor: grabbing; }

/* corner brackets — the signature HUD element */
.monitor__corner {
  position: absolute;
  width: 26px;
  height: 26px;
  border: 2px solid var(--line-cyan);
  opacity: 0.85;
  z-index: 2;
}
.monitor__corner--tl { top: 0; left: 0; border-right: none; border-bottom: none; border-top-left-radius: 4px; }
.monitor__corner--tr { top: 0; right: 0; border-left: none; border-bottom: none; border-top-right-radius: 4px; }
.monitor__corner--bl { bottom: 0; left: 0; border-right: none; border-top: none; border-bottom-left-radius: 4px; }
.monitor__corner--br { bottom: 0; right: 0; border-left: none; border-top: none; border-bottom-right-radius: 4px; }

.stage__hint {
  margin: 0;
  font-size: 12.5px;
  color: var(--text-muted);
  letter-spacing: 0.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 何か選択中/操作中のときは、通常の操作ヒントの代わりに
   「立ち絵：○○　/　シーンN: ○○」を表示する（updateStageStatus参照） */
.stage__hint.is-status {
  color: var(--line-cyan);
}

/* ================= RESIZER (drag handle between stage/console) ================= */
.resizer {
  flex-shrink: 0;
  width: 6px;
  cursor: col-resize;
  background: transparent;
  position: relative;
  z-index: 2;
  touch-action: none;
}
.resizer::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 1px;
  transform: translateX(-50%);
  background: var(--line-cyan-dim);
  transition: background .15s ease, width .15s ease;
}
.resizer:hover::after,
.resizer.is-dragging::after {
  background: var(--line-cyan);
  width: 2px;
}

body.is-resizing-console {
  cursor: col-resize;
  user-select: none;
}

/* ================= CONSOLE (sidebar) ================= */
.console {
  width: var(--console-width);
  flex-shrink: 0;
  background: var(--bg-panel);
  border-left: 1px solid var(--line-cyan-dim);
  display: flex;
  flex-direction: column;
  height: 100vh;
}

.console__header {
  padding: 20px 22px 14px;
  border-bottom: 1px solid var(--line-cyan-dim);
  flex-shrink: 0;
}

.console__title {
  display: block;
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.18em;
  color: var(--text-primary);
}

.console__sub {
  display: block;
  font-size: 11px;
  color: var(--text-faint);
  letter-spacing: 0.05em;
  margin-top: 2px;
}

/* .console__body（パネル一覧）と.console__terms（利用規約）をまとめて
   スクロールさせるための外枠。PC幅では実際にここがスクロールコンテナに
   なり、.console__footer（画像保存等の常時表示欄）はその外に固定される。
   スマホ幅ではdisplay:contentsで箱ごと消え、中身が.console__footerと
   直接並ぶ扱いになる（下のメディアクエリ参照）。 */
.console__scroll {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
}

/* UIの色合いに馴染む、控えめなスクロールバー。トラック（掴む部分以外）は
   透明にして地味にし、つまみ（実際に掴んで動かす部分）だけ薄いcyanで
   見えるようにする——ホバー時だけ少し明るくして掴める場所だと分かる
   ようにしている。.console__scrollに限らず、2列時に個別スクロールする
   .console__col--left/--right・.console__termsにも同じ見た目を使う。 */
.console__scroll,
.console__col--left,
.console__col--right,
.console__terms {
  scrollbar-width: thin; /* Firefox */
  scrollbar-color: var(--line-cyan-dimmer) transparent; /* Firefox: thumb track */
}
.console__scroll::-webkit-scrollbar,
.console__col--left::-webkit-scrollbar,
.console__col--right::-webkit-scrollbar,
.console__terms::-webkit-scrollbar {
  width: 6px;
}
.console__scroll::-webkit-scrollbar-track,
.console__col--left::-webkit-scrollbar-track,
.console__col--right::-webkit-scrollbar-track,
.console__terms::-webkit-scrollbar-track {
  background: transparent;
}
.console__scroll::-webkit-scrollbar-thumb,
.console__col--left::-webkit-scrollbar-thumb,
.console__col--right::-webkit-scrollbar-thumb,
.console__terms::-webkit-scrollbar-thumb {
  background: var(--line-cyan-dimmer);
  border-radius: 4px;
}
.console__scroll::-webkit-scrollbar-thumb:hover,
.console__col--left::-webkit-scrollbar-thumb:hover,
.console__col--right::-webkit-scrollbar-thumb:hover,
.console__terms::-webkit-scrollbar-thumb:hover {
  background: var(--line-cyan-dim);
}

.console__body {
  padding: 10px 22px 18px;
  overflow-x: hidden;
}

/* デフォルト（1列）では単なる縦積みの入れ物——.console__col--leftの
   全パネル、続けて.console__col--right（シナリオ＝動画関連）の順に
   ブロックとして積み上がるだけで、今までの見た目と変わらない。
   container-type/nameは.console__bodyではなくここ（左列）に付けている
   ——2列化した状態で.console__bodyに付けたままだと、表情差分シートの
   レイアウト切り替え（@container console、下記）が「2列化前の全幅」を
   基準に判定されてしまい、実際に表示に使える左列の幅より広いと誤認して
   画像を横に並べるレイアウトを強行し、範囲指定UIがつぶれていた。 */
.console__col--left {
  min-width: 0;
  overflow-x: hidden;
  container-type: inline-size;
  container-name: console;
}
.console__col--right {
  min-width: 0;
  overflow-x: hidden;
}

/* コンソール幅を広げてプレビューと半々に近づくくらいになったら、
   動画関連（シナリオパネル）を右列に分けた2列レイアウトにする。
   @containerクエリで試したが実際には反映されなかったため、
   #consoleResizerのドラッグ中にJS側でbody.console-wideを直接
   切り替える確実な方式にしている（initConsoleResizer参照、しきい値も
   そちらのCONSOLE_WIDE_THRESHOLD参照）。
   スマホ幅（横方向のリサイズ自体が存在しない）ではドラッグ後に幅を
   広げたまま画面を狭めた場合でも2列化が誤って効かないよう、
   デスクトップ幅のメディアクエリの中に限定している。 */
@media (min-width: 861px) {
  /* 2列それぞれを独立してスクロールさせる——.console__scroll自体は
     もう自分でスクロールせず、下へ高さを伝えるだけの縦積みflexにし、
     実際のスクロールは各列とconsole__termsにそれぞれ持たせる
     （min-height:0が無いとflexアイテムは中身の分だけ伸びてしまい、
     はみ出してスクロールが起きない）。 */
  body.console-wide .console__scroll {
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
  body.console-wide .console__body {
    display: flex;
    align-items: stretch;
    gap: 20px;
    flex: 1;
    min-height: 0;
  }
  body.console-wide .console__col--left,
  body.console-wide .console__col--right {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
  }
}

/* 2列時、利用規約(.console__terms)は独立した帯として別枠を取らず、
   左列の最後尾に含めてスクロールと一緒に流れるようにする（別枠だと
   場所を取るため）。実際の要素の移動はJS側（updateTermsPlacement）が
   行い、ここでは移動先（.console__col--left内）でのpaddingだけ調整する
   ——.console__bodyの左右padding(22px)を既に持っているので、.console__terms
   自身の左右paddingは重複しないよう打ち消す。 */
.console__col--left > .console__terms {
  padding-left: 0;
  padding-right: 0;
}

/* シナリオ再生（＝録画）中は、位置/拡縮を保持しない行のスナップショット
   が壊れないよう、動画保存タブ以外の操作を全て無効化する（.console__footer
   の動画保存パネルはconsole__bodyの外にあるため、再生開始/中止ボタンは
   引き続き押せる） */
body.is-scenario-playing .console__body {
  pointer-events: none;
  opacity: 0.5;
}

.console__footer {
  flex-shrink: 0;
  padding: 16px 22px 20px;
  border-top: 1px solid var(--line-cyan-dim);
}
/* .console__footerも他のパネルと同じく<details>にして畳めるようにし、
   使わない時は保存欄の分だけ画面を狭くできるようにしている
   （.panel > summaryと同じ見た目のシェブロンにしている） */
.console__footer > summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 8px;
  border-radius: var(--radius-s);
  margin: -8px -10px 12px;
  padding: 8px 10px;
  transition: background .15s ease;
  user-select: none;
  -webkit-user-select: none;
}
.console__footer[open] > summary {
  margin-bottom: 12px;
}
.console__footer:not([open]) > summary {
  margin-bottom: -8px;
}
.console__footer > summary:hover {
  background: var(--line-cyan-dimmer);
}
.console__footer > summary::-webkit-details-marker { display: none; }
.console__footer > summary::marker { content: ""; }
.console__footer > summary::before {
  content: "";
  width: 0;
  height: 0;
  flex-shrink: 0;
  border-style: solid;
  border-width: 4px 0 4px 6px;
  border-color: transparent transparent transparent var(--line-cyan);
  transition: transform 0.15s ease;
  margin-top: -12px;
}
.console__footer[open] > summary::before {
  transform: rotate(90deg);
}
.console__footer-title {
  flex: 1;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--text-primary);
}

.console__terms {
  /* .console__bodyの兄弟要素なので、その左右padding(22px)を継承しない
     ——ここで明示的に合わせないと左右がconsole__bodyより詰まって見える */
  margin: 18px 0 0;
  padding: 16px 22px 0;
  border-top: 1px solid var(--line-cyan-dimmer);
  font-size: 10.5px;
  line-height: 1.5;
  color: var(--text-faint);
  letter-spacing: 0.01em;
}
.console__terms a {
  color: var(--line-cyan);
  word-break: break-all;
}
.console__terms a:hover {
  text-decoration: none;
}

.footer-tabs {
  display: flex;
  gap: 6px;
  margin-bottom: 12px;
}

.footer-tab {
  flex: 1;
  appearance: none;
  border: 1px solid var(--line-cyan-dim);
  background: var(--bg-input);
  color: var(--text-muted);
  border-radius: var(--radius-s);
  padding: 8px 10px;
  font-size: 12.5px;
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease, color .15s ease;
}
.footer-tab:hover { border-color: var(--line-cyan); color: var(--text-primary); }
.footer-tab.is-active {
  background: var(--line-cyan-dimmer);
  border-color: var(--line-cyan);
  color: var(--line-cyan);
  font-weight: 600;
}
/* 動画保存タブだけは、動画関連機能であることが分かるよう他と違う
   アクセント色にする（シナリオパネルの色帯・バッジと揃えている） */
#footerTabVideoBtn.is-active {
  background: var(--accent-video-dim);
  border-color: var(--accent-video);
  color: var(--accent-video);
}

/* Both panels occupy the same grid cell so the container's height is
   always the taller of the two, regardless of which tab is active —
   switching tabs only changes visibility, not layout, so the footer
   never resizes. */
.footer-tab-panels {
  display: grid;
}
.footer-tab-panel {
  grid-area: 1 / 1;
}
.footer-tab-panel.is-hidden {
  visibility: hidden;
  pointer-events: none;
}

.panel {
  padding: 18px 0 26px;
  border-bottom: 1px solid var(--line-cyan-dimmer);
}
.panel:last-child { border-bottom: none; }

/* ファイルをドラッグ中に該当パネル/保存欄の上に来たときの見た目 */
.panel.is-drag-over,
.console__footer.is-drag-over {
  background: var(--line-cyan-dimmer);
  box-shadow: inset 0 0 0 2px var(--line-cyan);
  border-radius: var(--radius-s);
}

/* シナリオ（動画保存機能一式）パネルだけ、他の静止画向けパネルと
   ひと目で区別できるよう左に色帯を付ける。console__bodyの左右padding
   （22px）の内側に収まる分だけ左へ張り出すので、中身の位置は動かない */
.panel--video {
  margin-left: -12px;
  padding-left: 12px;
  border-left: 3px solid var(--accent-video);
}

.panel__badge {
  display: inline-block;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.03em;
  padding: 2px 7px;
  border-radius: 999px;
  vertical-align: middle;
}
.panel__badge--video {
  color: var(--accent-video);
  border: 1px solid var(--accent-video);
  background: var(--accent-video-dim);
}

/* .panel is a <details> element so each section can be collapsed to cut
   down on how much is on screen at once — everything after <summary> is
   just the section's existing content, hidden/shown natively by the
   browser when closed/open. */
.panel > summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 8px;
  border-radius: var(--radius-s);
  margin: -8px -10px 0;
  padding: 8px 10px;
  transition: background .15s ease;
  /* rapid/repeated clicks on the toggle otherwise get read as a
     double-click and select the title text instead of just collapsing */
  user-select: none;
  -webkit-user-select: none;
}
.panel > summary:hover {
  background: var(--line-cyan-dimmer);
}
.panel > summary::-webkit-details-marker { display: none; }
.panel > summary::marker { content: ""; }
.panel > summary::before {
  content: "";
  width: 0;
  height: 0;
  flex-shrink: 0;
  border-style: solid;
  border-width: 4px 0 4px 6px;
  border-color: transparent transparent transparent var(--line-cyan);
  transition: transform 0.15s ease;
  /* a border-triangle's visual weight sits slightly below its own
     geometric box, so align-items:center alone still reads as too low */
  margin-top: -12px;
}
.panel[open] > summary::before {
  transform: rotate(90deg);
}
.panel > summary .panel__title-row,
.panel > summary .panel__title {
  flex: 1;
}

/* summary内に置く小さいON/OFFボタン共通——.panel__titleがflex:1で
   場所を取るため、後ろに置くだけで自然と右端に寄る。summaryの中に
   置くと素のクリックで折りたたみが開閉してしまうため、押した時は
   JS側でpreventDefault/stopPropagationしている。 */
.panel__inline-btn {
  flex: 0 0 auto;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text-muted);
  background: var(--bg-panel-raised);
  border: 1px solid var(--line-cyan-dim);
  border-radius: var(--radius-s);
  padding: 5px 10px;
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease, color .15s ease;
}
.panel__inline-btn:hover {
  border-color: var(--line-cyan);
  color: var(--text-primary);
}
.panel__inline-btn.is-active {
  color: var(--line-cyan);
  border-color: var(--line-cyan);
  background: var(--line-cyan-dimmer);
}

/* .panelの折りたたみシェブロンと同じ見た目の、より小さい入れ子用
   折りたたみ（例: 表情差分シートの詳細設定）。コンソールの大枠パネルと
   同じ操作感にしつつ、ラベル用のサイズ感（11px/大文字/字間広め）に揃える */
details.collapsible-sub {
  margin-top: 22px;
}
details.collapsible-sub > summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 4px 6px;
  margin: 0 -6px;
  border-radius: var(--radius-s);
  transition: background .15s ease;
  user-select: none;
  -webkit-user-select: none;
}
details.collapsible-sub > summary:hover {
  background: var(--line-cyan-dimmer);
}
details.collapsible-sub > summary::-webkit-details-marker { display: none; }
details.collapsible-sub > summary::marker { content: ""; }
details.collapsible-sub > summary::before {
  content: "";
  width: 0;
  height: 0;
  flex-shrink: 0;
  border-style: solid;
  border-width: 4px 0 4px 6px;
  border-color: transparent transparent transparent var(--line-cyan);
  transition: transform 0.15s ease;
}
details.collapsible-sub[open] > summary::before {
  transform: rotate(90deg);
}

/* 優先度の低い設定（宝具アイコンの文字調整など）を、通常のウインドウ
   項目と見分けがつくよう一段階沈んだ見た目にする——背景を敷いて枠で
   囲い、見出しも一回り小さく暗めにする。 */
details.collapsible-sub--minor {
  background: rgba(0, 0, 0, 0.18);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: var(--radius-s);
  padding: 8px 10px;
}
details.collapsible-sub--minor > summary {
  font-size: 10px;
  color: var(--text-faint);
  margin: 0;
}
details.collapsible-sub--minor[open] > summary {
  margin-bottom: 6px;
}

.panel__title {
  margin: 0 0 12px;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--text-primary);
}

.panel__title-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
}

.panel__count {
  font-family: var(--font-mono);
  color: var(--line-cyan);
  letter-spacing: 0;
  text-transform: none;
}

.panel__row {
  margin-top: 8px;
}

.panel__divider {
  height: 1px;
  background: var(--line-cyan-dimmer);
  margin: 16px 0;
}

/* ---- buttons ---- */
.btn {
  appearance: none;
  border: 1px solid var(--line-cyan-dim);
  background: var(--bg-panel-raised);
  color: var(--text-primary);
  border-radius: var(--radius-s);
  padding: 10px 14px;
  font-size: 13px;
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease, transform .05s ease;
  width: 100%;
}
.btn:hover { border-color: var(--line-cyan); }
.btn:active { transform: translateY(1px); }
.btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
  border-color: var(--line-cyan-dimmer);
}
.btn:disabled:hover { border-color: var(--line-cyan-dimmer); }

.btn--sm { padding: 7px 10px; font-size: 12px; width: auto; }
.btn--ghost { background: transparent; }
.btn--danger { border-color: var(--danger-dim); color: var(--danger); }
.btn--danger:hover { border-color: var(--danger); }

.btn--primary {
  background: linear-gradient(180deg, var(--accent-gold), #b98f47);
  color: #1a1204;
  border: none;
  font-weight: 600;
  letter-spacing: 0.03em;
  padding: 13px 14px;
}
.btn--primary:hover { filter: brightness(1.06); }

/* この場所だけ、下の説明文との間隔が窮屈に見えていたため広げている */
#scenarioAddLineBtn {
  margin-bottom: 14px;
}

.btn-row { display: flex; gap: 8px; }
.btn-row .btn { flex: 1; }

/* 「再生開始」ボタンを押すと出てくる、書き出し形式（WebM/GIF）を
   選ぶポップアップメニュー */
.video-save-menu-wrap {
  position: relative;
  flex: 1;
}
.video-format-menu {
  /* display:flexを直接指定すると、同じ詳細度のUA既定スタイル[hidden]
     （display:none）より後から効いてしまいhidden属性が無視されるため、
     既定は非表示にしておき.is-openの時だけflexにする */
  display: none;
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(100% + 6px);
  z-index: 20;
  background: var(--bg-panel-raised);
  border: 1px solid var(--line-cyan);
  border-radius: var(--radius-s);
  padding: 4px;
  flex-direction: column;
  gap: 2px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
}
.video-format-menu.is-open {
  display: flex;
}
.video-format-menu__item {
  appearance: none;
  border: none;
  background: transparent;
  color: var(--text-primary);
  text-align: left;
  font-size: 12.5px;
  padding: 9px 10px;
  border-radius: var(--radius-s);
  cursor: pointer;
}
.video-format-menu__item:hover {
  background: var(--line-cyan-dimmer);
  color: var(--line-cyan);
}

.filebtn {
  display: block;
  text-align: center;
  border: 1px dashed var(--line-cyan-dim);
  border-radius: var(--radius-s);
  padding: 10px;
  font-size: 12.5px;
  color: var(--line-cyan);
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.filebtn:hover { border-color: var(--line-cyan); background: var(--line-cyan-dimmer); }

/* ---- character list ---- */
.charlist {
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.charlist__item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-s);
  border: 1px solid transparent;
  background: var(--bg-panel-raised);
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.charlist__item:hover { border-color: var(--line-cyan-dim); }
.charlist__item.is-selected { border-color: var(--line-cyan); background: var(--line-cyan-dimmer); }

.charlist__thumb {
  width: 30px;
  height: 30px;
  border-radius: 4px;
  overflow: hidden;
  background: #000;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.charlist__thumb img { width: 100%; height: 100%; object-fit: cover; }

.charlist__name {
  flex: 1;
  font-size: 12.5px;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.charlist__name-input {
  flex: 1;
  min-width: 0;
  font-size: 12.5px;
  color: var(--text-primary);
  background: var(--bg-input);
  border: 1px solid var(--line-cyan);
  border-radius: 3px;
  padding: 1px 4px;
}

.charlist__active-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--text-faint);
  flex-shrink: 0;
}
.charlist__item.is-active .charlist__active-dot {
  background: var(--line-cyan);
  box-shadow: 0 0 6px var(--line-cyan);
}

.charlist__item.is-hidden {
  opacity: 0.45;
}

/* セイントグラフフレームなど、実物の見た目を見ながら選びたい選択肢を
   横スクロールのサムネイル一覧で見せる時に使う（.charlist__thumbとは
   別に、もっと大きいプレビューを横に並べる想定）。 */
.frame-select {
  display: flex;
  gap: 8px;
  margin-top: 8px;
  padding-bottom: 4px;
  overflow-x: auto;
}

.frame-select__item {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  width: 72px;
  padding: 6px;
  border-radius: var(--radius-s);
  border: 1px solid transparent;
  background: var(--bg-panel-raised);
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.frame-select__item:hover { border-color: var(--line-cyan-dim); }
.frame-select__item.is-selected { border-color: var(--line-cyan); background: var(--line-cyan-dimmer); }

.frame-select__thumb {
  width: 60px;
  height: 102px;
  border-radius: 4px;
  overflow: hidden;
  background: #000;
  display: flex;
  align-items: center;
  justify-content: center;
}
.frame-select__thumb img { width: 100%; height: 100%; object-fit: contain; }

/* スキルアイコン候補一覧など、正方形に近い画像を並べる時はこちらを使う
   （セイントグラフフレームのような縦長カードと違い、縦に間延びさせない）。 */
.frame-select__thumb--square { width: 60px; height: 60px; }

/* 画像を消すための「なし」選択肢——実画像のサムネイルと見分けがつくよう
   点線枠+テキストのみにする。 */
.frame-select__thumb--none {
  background: transparent;
  border: 1px dashed var(--text-muted);
  color: var(--text-muted);
  font-size: 11px;
}

.frame-select__label {
  font-size: 12px;
  color: var(--text-primary);
  white-space: nowrap;
}

.charlist__del {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  border: 1px solid var(--danger-dim);
  background: transparent;
  color: var(--danger);
  border-radius: var(--radius-s);
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
}
.charlist__del:hover {
  border-color: var(--danger);
  background: rgba(255, 80, 80, 0.12);
}

/* 不透明度スライダーとは別の、シーンへの登場/退場そのものを切り替える
   ON/OFFボタン。削除ボタンの隣に置き、あらかじめ用意したキャラを
   シーンごとに出し入れしやすくする */
.charlist__visibility-btn {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  border: 1px solid var(--line-cyan-dim);
  background: transparent;
  color: var(--line-cyan);
  border-radius: var(--radius-s);
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.charlist__visibility-btn:hover {
  border-color: var(--line-cyan);
  background: var(--line-cyan-dimmer);
}
.charlist__visibility-btn.is-off {
  color: var(--text-faint);
  border-color: var(--line-cyan-dimmer);
}

/* シナリオ行の「現在の状態でこの行を更新」ボタン。「行として追加」の
   大きなボタンと見た目・位置を分けて混同を防ぐため、キャラクターの
   表示切替ボタンと同じ小さな正方形アイコンボタンにしている */
.charlist__update-btn {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  border: 1px solid var(--line-cyan-dim);
  background: transparent;
  color: var(--line-cyan);
  border-radius: var(--radius-s);
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.charlist__update-btn:hover {
  border-color: var(--line-cyan);
  background: var(--line-cyan-dimmer);
}

/* ---- scenario line list ---- */
/* シナリオの行には画像サムネイルが無いので、.charlist__thumb/.charlist__name
   の代わりにテキストのプレビューを縦に並べる */
.charlist__scenario-preview {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.charlist__scenario-speaker {
  font-size: 12.5px;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.charlist__scenario-body {
  font-size: 11px;
  color: var(--text-faint);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* 掴んで上下に並び替えるためのハンドル。touch-action:noneはドラッグ中に
   ページのスクロールジェスチャーへ横取りされないようにするため */
.charlist__drag-handle {
  flex-shrink: 0;
  cursor: grab;
  color: var(--text-faint);
  font-size: 16px;
  line-height: 1;
  padding: 2px 4px;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}
.charlist__drag-handle:hover {
  color: var(--line-cyan);
}
.charlist__item.is-dragging {
  opacity: 0.5;
  border-color: var(--line-cyan);
}

/* ---- BGM list ---- */
/* 行クリックでの選択操作は無い（開始/終了はセレクトボックスで指定する）ため
   cursor:defaultにし、セレクト行は常に折り返して2段目に表示する */
.charlist__item--bgm {
  cursor: default;
  flex-wrap: wrap;
}
.charlist__item--bgm .charlist__name {
  cursor: pointer; /* 選択状態を持たないので、名前クリックでの改名を常に受け付ける */
}
.bgm-range {
  flex-basis: 100%;
  display: flex;
  align-items: center;
  gap: 6px;
}
.bgm-range__select {
  flex: 1;
  min-width: 0;
  font-size: 11.5px;
  color: var(--text-primary);
  background: var(--bg-input);
  border: 1px solid var(--line-cyan-dim);
  border-radius: 4px;
  padding: 3px 4px;
}
.bgm-range__select:focus { border-color: var(--line-cyan); outline: none; }
.bgm-range__sep {
  flex-shrink: 0;
  color: var(--text-faint);
  font-size: 11px;
}
/* 他のBGMと範囲が重なっている間だけ出す警告——追加直後はデフォルトで
   全区間になり既存のBGMと重なりがちなので、ここを見て手動で調整する */
.charlist__item--bgm.has-overlap { border-color: var(--danger-dim); }
.charlist__item--bgm .bgm-range__warning {
  flex-basis: 100%;
  margin: 2px 0 0;
  font-size: 11px;
  color: var(--danger);
}
.bgm-volume {
  flex-basis: 100%;
  display: flex;
  align-items: center;
  gap: 6px;
}
.bgm-volume__label {
  flex-shrink: 0;
  color: var(--text-faint);
  font-size: 11px;
}
.bgm-volume__range {
  flex: 1;
  min-width: 0;
  height: 16px !important; /* 通常のinput[type=range]より一回り細く、範囲セレクトの高さに揃える */
}
.bgm-volume__value {
  flex-shrink: 0;
  width: 2.4em;
  text-align: right;
  color: var(--text-faint);
  font-size: 11px;
}

/* シナリオの先頭/末尾に自動挿入される「シナリオ開始」「シナリオ終了」
   （暗転）行。並び替え・削除ができないことが分かるよう、他の行と少し
   見た目を変えている（点線の枠＋ドラッグハンドル分の余白なし） */
.charlist__item--scenario-special {
  border-style: dashed;
  border-color: var(--line-cyan-dimmer);
  cursor: default; /* 行全体のクリックには意味が無い（有効/無効ボタンのみ操作可能） */
}
.charlist__item--scenario-special .charlist__scenario-speaker {
  color: var(--text-muted);
}

/* 「場面転換」行——削除・並び替えは通常の行と同じくできるので、
   点線の枠だけで見た目を区別する（開始/終了の特殊行とは別の色で、
   一覧上でひと目で見分けられるようにする） */
.charlist__item--scene-transition {
  border-style: dashed;
  border-color: var(--accent-gold-dim);
}
.charlist__item--scene-transition:hover {
  border-color: var(--accent-gold);
}
.charlist__item--scene-transition .charlist__scenario-speaker {
  color: var(--accent-gold);
}

/* ---- character editor ---- */
.char-editor__hint {
  font-size: 11px;
  color: var(--text-faint);
  margin: 4px 0 0;
}

.char-editor--empty .char-editor__empty-msg {
  font-size: 12px;
  color: var(--text-faint);
  margin: 4px 0 0;
}

.char-editor__row {
  display: flex;
  gap: 10px;
  margin-bottom: 10px;
}
/* .field's margin-top is only zeroed for :first-child (meant for fields
   stacked vertically) — inside a .char-editor__row they sit side by side
   instead, so every non-first .field would otherwise start lower than its
   neighbors (visible as e.g. the departure fade end/start inputs). */
.char-editor__row > .field {
  margin-top: 0;
}

.char-editor__row--toggles {
  gap: 8px;
  margin-bottom: 14px;
}
.mini-toggle {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.expr-editor {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.expr-editor__fields-col {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* コンソール幅が十分あるときだけ、プレビューを横に固定表示して
   数値をいじりながら見比べられるようにする */
@container console (min-width: 560px) {
  .expr-editor {
    flex-direction: row;
    align-items: flex-start;
    gap: 16px;
  }
  .expr-editor__preview-col {
    flex: 0 0 300px;
    position: sticky;
    top: 4px;
  }
  .expr-editor__fields-col {
    flex: 1;
    min-width: 0;
  }
  .expr-editor__quad,
  .expr-editor__triple {
    gap: 10px;
  }
  .expr-editor__quad .field__input,
  .expr-editor__triple .field__input {
    padding: 10px 11px;
    font-size: 13.5px;
  }
}

@container console (min-width: 760px) {
  .expr-editor__preview-col {
    flex-basis: 340px;
  }
}

.expr-editor__preview {
  display: block;
  width: 100%;
  height: auto;
  margin-top: 8px;
  border: 1px solid var(--line-cyan-dim);
  border-radius: var(--radius-s);
  background-color: #2a2a2a;
  background-image:
    linear-gradient(45deg, #1a1a1a 25%, transparent 25%, transparent 75%, #1a1a1a 75%),
    linear-gradient(45deg, #1a1a1a 25%, transparent 25%, transparent 75%, #1a1a1a 75%);
  background-size: 16px 16px;
  background-position: 0 0, 8px 8px;
}

/* each group's border/label color matches its overlay rect color in the
   preview canvas (see renderExprPreview's strokeRect calls), so it's
   obvious at a glance which fields drive which colored box on screen */
.expr-editor__group {
  border: 1px solid var(--group-border);
  background: var(--group-bg);
  border-radius: var(--radius-s);
  padding: 10px 10px 12px;
  margin-top: 16px;
}
.expr-editor__group:first-child { margin-top: 0; }
.expr-editor__group > .char-editor__label:first-child { margin-top: 0; }
.expr-editor__group .char-editor__label { color: var(--group-border); }

.expr-editor__group--body { --group-border: #45d6ff; --group-bg: rgba(69, 214, 255, 0.07); }
.expr-editor__group--face { --group-border: #ff45d6; --group-bg: rgba(255, 69, 214, 0.07); }
.expr-editor__group--grid { --group-border: #ffd645; --group-bg: rgba(255, 214, 69, 0.07); }

/* neutral version of .expr-editor__group — just a bordered box to visually
   tie a slider to the toggles it controls, without any color-coding */
.field-box {
  border: 1px solid var(--line-cyan-dim);
  border-radius: var(--radius-s);
  padding: 10px 10px 12px;
  margin-top: 16px;
}
.field-box:first-child { margin-top: 0; }
.field-box > .char-editor__label:first-child { margin-top: 0; }

.expr-editor__quad {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  margin-top: 10px;
}
.expr-editor__quad .field,
.expr-editor__triple .field {
  margin-top: 0;
}

.expr-editor__triple {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  margin-top: 8px;
}

.expr-editor__thumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

.expr-editor__thumb-btn {
  border: 1px solid var(--line-cyan-dim);
  background: var(--bg-input);
  border-radius: var(--radius-s);
  padding: 4px;
  font-size: 11px;
  color: var(--text-muted);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.expr-editor__thumb-btn.is-selected {
  border-color: var(--line-cyan);
  color: var(--line-cyan);
  box-shadow: 0 0 0 1px var(--line-cyan);
}
.expr-editor__thumb-canvas {
  display: block;
  border-radius: 2px;
}

.mini-toggle .char-editor__label {
  margin: 0;
  text-align: center;
  font-size: 10px;
}
.mini-toggle .toggle-btn {
  width: 100%;
  padding: 6px 4px;
  font-size: 11px;
}

.char-editor__label {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin: 14px 0 7px;
  display: block;
}

.toggle-btn {
  flex: 1;
  border: 1px solid var(--line-cyan-dim);
  background: var(--bg-input);
  color: var(--text-muted);
  border-radius: var(--radius-s);
  padding: 8px 6px;
  font-size: 12px;
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease, color .15s ease;
}
.toggle-btn:hover {
  border-color: var(--line-cyan);
  color: var(--text-primary);
}
.toggle-btn.is-on {
  border-color: var(--line-cyan);
  color: var(--line-cyan);
  background: var(--line-cyan-dimmer);
}
.toggle-btn.is-on:hover {
  color: var(--line-cyan);
}

/* ---- form fields ---- */
.field {
  display: block;
  margin-top: 14px;
}
.field:first-child { margin-top: 0; }
/* .fieldも.filebtnも自前でdisplayを指定しているため、hidden属性（UA既定
   スタイルの[hidden]{display:none}）だけでは同じ詳細度で後勝ちして隠れ
   ない——.video-format-menuと同じ理由でclass切り替え方式にしている。 */
.field.is-hidden,
.filebtn.is-hidden {
  display: none;
}

/* 保存欄（フッター）のシナリオ用/サーヴァント詳細用の切り替え */
.footer-mode-body.is-hidden {
  display: none;
}

.field__label {
  display: block;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  letter-spacing: 0.06em;
  margin-bottom: 7px;
  text-transform: uppercase;
}

.field__input {
  width: 100%;
  background: var(--bg-input);
  border: 1px solid var(--line-cyan-dim);
  border-radius: var(--radius-s);
  padding: 9px 10px;
  font-size: 13px;
  color: var(--text-primary);
  resize: vertical;
}
.field__input:focus { border-color: var(--line-cyan); }
.field__input:disabled { opacity: 0.55; cursor: not-allowed; }
.field__input--area { line-height: 1.5; }

.field__hint {
  display: block;
  margin-top: 6px;
  font-size: 11px;
  color: var(--text-faint);
  letter-spacing: 0.01em;
}

.field__color {
  -webkit-appearance: none;
  appearance: none;
  width: 60px;
  height: 36px;
  border: 1px solid var(--line-cyan-dim);
  border-radius: var(--radius-s);
  background: var(--bg-input);
  padding: 3px;
  cursor: pointer;
}
.field__color::-webkit-color-swatch { border: none; border-radius: 4px; }

.field__input--number {
  width: 100% !important;
  padding: 9px 10px;
}

.field__input--number-small {
  width: 50px !important;
  padding: 7px 6px !important;
  font-size: 12px !important;
  min-width: 50px;
}

.field--compact {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.field--compact .field__label {
  margin-bottom: 0;
}

.field-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-top: 12px;
}
.field-grid .field {
  /* :first-child only zeroes the left column — without this the right
     column keeps its 12px margin-top and sits visibly lower than the left */
  margin-top: 0;
}

/* 文字サイズ column needs the room (slider + number input); 文字色 is just
   a small fixed-size swatch, so give it only as much width as it needs
   instead of an equal 1fr that starves the slider and leaves the color
   column mostly empty. */
.field-grid--fontrow {
  grid-template-columns: 1fr auto;
  align-items: start;
}

input[type="range"] {
  width: 100%;
  accent-color: var(--line-cyan);
  height: 20px;
}

/* ---- dual-range (二点つまみスライダー、グラデーション編集のような見た目) ---- */
.dual-range {
  position: relative;
  height: 28px;
  margin: 8px 0 4px;
}
.dual-range__track {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  height: 10px;
  border-radius: 999px;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.35);
}
/* つまみはinput[type=range]を2つ重ねる方式ではなく、divを2つ自前で
   ドラッグ制御する——ネイティブレンジ2つ重ね方式だと、二つの値が同じ位置
   に重なった時にどちらの要素がクリックを受け取るかがブラウザの
   ヒットテスト（JS実行前に確定済み）任せになり、z-indexをJS側でいくら
   調整しても「押した瞬間には手遅れ」で片方のつまみが操作不能になる
   問題が解消できなかったため。divなら pointerdown 時に自前で最寄りの
   つまみを判定してsetPointerCaptureで掴み続けられる。 */
.dual-range__thumb {
  position: absolute;
  top: 50%;
  width: 18px;
  height: 18px;
  margin-left: -9px;
  border-radius: 50%;
  background: #f2f2f2;
  border: 2px solid #1b1f27;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
  cursor: pointer;
  transform: translateY(-50%);
  touch-action: none;
}
.dual-range__thumb:focus-visible {
  outline: 2px solid var(--line-cyan);
  outline-offset: 2px;
}

/* ---- switch ---- */
.switch-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 12.5px;
  color: var(--text-primary);
  cursor: pointer;
  padding: 6px 8px;
  margin: 0 -8px;
  border-radius: var(--radius-s);
  transition: background .15s ease;
}
.switch-row:hover {
  background: var(--line-cyan-dimmer);
}

.switch {
  position: relative;
  display: inline-block;
  width: 38px;
  height: 21px;
  flex-shrink: 0;
}
.switch input {
  opacity: 0;
  width: 0;
  height: 0;
}
.switch__track {
  position: absolute;
  inset: 0;
  background: var(--bg-input);
  border: 1px solid var(--line-cyan-dim);
  border-radius: 12px;
  transition: background .15s ease;
}
.switch__track::before {
  content: "";
  position: absolute;
  width: 15px;
  height: 15px;
  left: 2px;
  top: 2px;
  border-radius: 50%;
  background: var(--text-faint);
  transition: transform .15s ease, background .15s ease;
}
.switch input:checked + .switch__track {
  border-color: var(--line-cyan);
  background: var(--line-cyan-dimmer);
}
.switch input:checked + .switch__track::before {
  transform: translateX(17px);
  background: var(--line-cyan);
  box-shadow: 0 0 6px var(--line-cyan);
}

/* responsive: stack on narrow viewports */
@media (max-width: 860px) {
  /* .appにoverflow-y:autoを付けていると、実際には（heightがautoで内容が
     常に収まるため）overflowが起きないにも関わらず、position:stickyの
     基準となる「最も近いスクロールコンテナ」としてブラウザに扱われて
     しまい、.stageが本来追従すべきbodyのスクロールに対して追従しなく
     なる。実際にスクロールするのはbody側なので、.appはoverflow指定を
     持たせない。 */
  .app { flex-direction: column; height: auto; }
  body { overflow: auto; }
  .resizer { display: none; }
  .console { width: 100%; height: auto; border-left: none; border-top: 1px solid var(--line-cyan-dim); }

  /* スマホ幅では.console全体がページと一緒に流れるだけで、.console__scroll
     自身が独立してスクロールすることはない（heightがautoなので）。そこで
     箱そのものを消し、中身（パネル一覧＋利用規約）を.console__footerと
     直接並ぶ扱いにした上で、順序だけ「パネル→保存欄→利用規約」に
     並べ替える（PC幅では.console__scrollが実際のスクロールコンテナに
     なるので、ここでは触らない）。 */
  .console__scroll {
    display: contents;
  }
  .console__footer {
    order: 1;
  }
  .console__terms {
    order: 2;
  }

  /* コンソールの長い操作パネル/表情差分編集をスクロールしながら触る間も
     プレビューを画面上部に追従させる。stage自身が背景色を持つのは、
     下にスクロールしてきたコンソールの内容が透けて見えないようにするため。 */
  .stage {
    position: sticky;
    top: 0;
    z-index: 5;
    background: var(--bg-void);
    padding: 12px 16px;
    gap: 10px;
  }
  .stage__preview-switch {
    display: flex;
  }
  /* スマホ幅ではプレビューの横幅も狭くなり、ヒント文言が長いと窮屈に
     見えるため、この幅でだけ少し小さくする */
  .stage__hint {
    font-size: 10.5px;
  }
  /* オフの間は見た目だけ畳む——プレビューを再描画する処理自体は
     動き続けるので、再度ONにした時点ですぐ最新の内容が表示される */
  .stage--collapsed .monitor,
  .stage--collapsed .stage__hint {
    display: none;
  }
}

/* タッチ操作が主な入力手段の環境（スマホ/タブレット）向けに、指では
   狙いにくい小さめのコントロール類だけ当たり判定を広げる。画面幅では
   なくpointer:coarseで判定するので、タッチ対応の大画面タブレット等でも
   同様に適用される。 */
@media (pointer: coarse) {
  .charlist__del,
  .charlist__visibility-btn,
  .charlist__update-btn {
    width: 32px;
    height: 32px;
    font-size: 15px;
  }
  .toggle-btn {
    padding: 11px 8px;
  }
  .mini-toggle .toggle-btn {
    padding: 11px 6px;
  }
  .footer-tab {
    padding: 11px 10px;
  }
  .expr-editor__thumb-btn {
    padding: 6px;
  }
  .switch {
    width: 44px;
    height: 24px;
  }
  .switch__track::before {
    width: 18px;
    height: 18px;
    left: 3px;
    top: 3px;
  }
  .switch input:checked + .switch__track::before {
    transform: translateX(19px);
  }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}
