/* ── カスケードレイヤー ──
   優先順は宣言順で決まる（後ろほど強い）。記述位置に依存した暗黙ルールを排除する。
   external(サードパーティCSS) < reset < tokens < base < components(各partial)
   < modes(レイアウトモード上書き) < utilities
   注意: レイヤー外のスタイルはどのレイヤーよりも強い。外部CSS（Google Fonts の
   .material-symbols-rounded 等）は各ページで @import layer(external) により
   最弱レイヤーに入れている。<link> で読むとレイヤー外になり上書きが逆転するので不可 */
@layer external, reset, tokens, base, components, modes, utilities;

@layer reset {
  *,
  *::before,
  *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
  }
}

@layer tokens {
  :root {
    /* ブランド素材の変数（--brand-logo / --brand-bg-photo）は pwa-head.php の
       インラインで定義する。理由: このファイル（css/）で url() を書くと、Chrome が
       変数の使用場所（ページ側インライン）基準で相対解決するため、本番の
       /webreal/ 配下でパスがずれて404になる。ページ相対ならどちらの解釈でも正しい */
    /* ── ベース背景 ── */
    --bg-page: #0F172A;
    /* ページ背景（最暗） */
    --bg-panel: #1E293B;
    /* パネル・カード背景 */
    --bg-darker: #0F1929;
    /* モーダル等の極暗背景 */
    --bg-disabled: #374151;
    /* 無効・非アクティブ状態 */
    --bg-alarm: #292000;
    /* アラーム発火時背景 */

    /* ── ボーダー ── */
    --border: #6B7280;
    /* 通常ボーダー */
    --border-light: #E5E7EB;
    /* 明るいボーダー */
    --border-dark: #2D3E55;
    /* パネル内の暗いボーダー */

    /* ── テキスト ── */
    --text: #E5E7EB;
    /* 基本テキスト */
    --text-dark: #1E293B;
    /* 暗背景上のテキスト（ボタン等） */
    --text-muted: #9CA3AF;
    /* 補助テキスト・無効テキスト */
    --gray-dim: #4B5563;
    /* スクロールバー等の暗いグレー */

    /* ── アクセント ── */
    --accent: #3B82F6;
    /* アクセント青 */
    --accent-light: #93C5FD;
    /* 薄い青（レーンバッジ等） */
    --navy: #002978;
    /* 紺（レーンバッジ文字・成約バッジ文字） */

    /* ── セマンティック ── */
    --yellow: #FEE101;
    /* 訂正リボン・訂正バナー */
    --red: #E3002C;
    /* うりきりリボン・アラーム */
    --green: #79F509;
    /* シグナルランプ */

    /* ── 応札ボタングラデーション ── */
    --bid-from: #FFEF03;
    --bid-mid: #FFDC45;
    --bid-to: #FDB00C;

    /* ── 会場レーンコンポーネント ── */
    --venue-lane-bg: #FFFFFF;
    --venue-lane-text: #1E293B;

    /* ── フォント ── */
    --font: 'Noto Sans JP', sans-serif;
    --font-wide: 'BIZ UDPGothic', 'BIZ UDP Gothic', 'Noto Sans JP', sans-serif;

    /* ── ボタン高さ ── */
    --btn-h-xs: 20px;
    --btn-h-sm: 28px;
    --btn-h-md: 36px;
    --btn-h-lg: 44px;
    --btn-h-xl: 60px;

    /* ── フォントサイズ ── */
    --fs-xs: 12px;
    /* カード内補助テキスト・バッジ・ピルボタン */
    --fs-sm: 14px;
    /* コンパクトパネルのラベル・タブ・テーブル行 */
    --fs-base: 16px;
    /* 通常テキスト */
    --fs-lg: 20px;
    /* 大きめテキスト・ラベル */
    --fs-xl: 24px;
    /* 見出し・ボタン・出品番号 */
    --fs-price: 64px;
    /* 価格 */

    /* ── スペーシング ── */
    --sp-xs: 4px;
    --sp-sm: 8px;
    --sp-md: 12px;
    --sp-lg: 16px;

    /* ── 派生色（color-mix で基色から生成。基色を変えると自動追従） ── */
    --hover-overlay: color-mix(in srgb, white 10%, transparent);
    /* ホバーの白オーバーレイ（背景を持たないボタンに重ねる） */
    --hover-solid: color-mix(in srgb, var(--bg-page) 88%, white);
    /* 枠付きで塗りのあるコントロール（プルダウンの現在値など）のホバー */
    --alarm-highlight: color-mix(in srgb, #FFC800 15%, transparent);
    /* アラーム発火・アイコン強調の黄 */
    --error-bg: color-mix(in srgb, var(--red) 12%, transparent);

    /* ── 影（濃度バラバラだった生値を3段階に正規化） ── */
    --shadow-sm: 0 4px 8px color-mix(in srgb, black 35%, transparent);
    /* ボタン・スナックバー */
    --shadow-md: 0 4px 16px color-mix(in srgb, black 50%, transparent);
    /* ドロップダウン */
    --shadow-lg: 0 8px 32px color-mix(in srgb, black 50%, transparent);
    /* ダイアログ・カード */

    /* ── トランジション時間 ──
       頻度の高い操作ほど短く。ポップアップ（ドロップダウン・ダイアログ）は連続操作や
       セリ進行中の即時性を優先して短め、パネルは大きい要素なのでやや長め */
    --dur-popup: 0.3s;
    --dur-panel: 0.5s;

    /* ── レイアウト ── */
    --header-height: 68px;
    --main-padding: 8px;
    --panel-gap: 8px;
    /* サイドパネル1枚の幅。キャンバスは常に 1920px 固定（下記「固定キャンバス」）なので
       画面幅の 1/3（要件 F-03）は定数で出せる。index の3列グリッドが作る幅と同じ値を
       venue でも使い、画面を移動してもパネルの位置と大きさが変わらないようにする */
    --side-panel-w: calc((1920px - var(--main-padding) * 2 - var(--panel-gap) * 2) / 3);
  }

  /* ── 文字サイズ設定（デフォルト設定の「文字サイズ」）が効く範囲 ──
     --fs-scale は partials/viewport-scale.php が localStorage の default_settings.fontSize
     から読んで <html> に設定する（標準1 / 大1.10）。
     サイドパネルは会場選択画面・セリ画面のどちらでも追従する。BidPanel は --fs-* を
     倍率に追従させない（車両画像・価格表示が px 固定の格子に乗っている）。
     車名・年式グレードの見出し・フッターだけを枠に収まる範囲で個別に大きくする
     （partials/bid-panel.php「文字サイズ「大」で大きくする部品」）。
     --fs-* を宣言し直すのは、カスタムプロパティは宣言した要素で値が確定し、
     子で --fs-k を変えても親で確定した --fs-* は再計算されないため */
  .side-panel {
    --fs-k: var(--fs-scale, 1);
    --fs-xs: calc(12px * var(--fs-k));
    --fs-sm: calc(14px * var(--fs-k));
    --fs-base: calc(16px * var(--fs-k));
    --fs-lg: calc(20px * var(--fs-k));
    --fs-xl: calc(24px * var(--fs-k));

    /* 表見出しの上限。.alarm-table（アラーム・自社出品）の見出しは幅10%の列に
       「アラーム」4文字を1行で収める必要があり、実測 1.06 を超えると2行になる
       （2026-09-11 指摘）。大(1.10)では2行になるため 1.05 で止める */
    --fs-k-th: min(var(--fs-k), 1.05);
  }

}

@layer base {
  html {
    width: 100%;
    height: 100%;
    background: var(--bg-page);
  }

  body {
    width: 100%;
    height: 100dvh;
    overflow: hidden;
    background: var(--bg-page);
    color: var(--text);
    font-family: var(--font);
    font-size: var(--fs-base);
    display: flex;
    flex-direction: column;
    /* 操作画面のためテキスト・画像の選択を抑止。入力欄は下で選択可に戻す */
    -webkit-user-select: none;
    user-select: none;
  }

  /* 入力欄は文字選択・カーソル移動が必要なので選択可に戻す */
  input,
  textarea {
    -webkit-user-select: text;
    user-select: text;
  }

  /* ── メインレイアウト ── */
  #app {
    display: flex;
    flex-direction: column;
    height: 100%;
  }

  #main {
    display: grid;
    /* デスクトップ2枚モード: bid : bid : セリ状況 = 1:1:1（1920px 基準の要件）。
       セリ状況は全モードで画面幅の 1/3 を維持する */
    grid-template-columns: 1fr 1fr 1fr;
    gap: var(--panel-gap);
    padding: var(--main-padding);
    flex: 1;
    min-height: 0;
    /* パネルが縦方向いっぱいに伸びるよう */
    grid-template-rows: 1fr;
    align-items: stretch;
  }
}

@layer modes {
  /* ── 固定キャンバス（html.is-scaled は viewport-scale.php が付与） ──
     デスクトップは 1920×1080 のキャンバスを transform で等比拡縮し、余りは
     ページ背景色の帯にする。レイアウトサイズは常に 1920×1080 のため、
     コンテナクエリ等は解像度によらず設計値で発火する。
     方式の理由は viewport-scale.php のコメント参照 */
  .is-scaled body {
    background: var(--bg-page);
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100dvh;
    overflow: hidden;
  }

  .is-scaled #app,
  .is-scaled #venue-app,
  .is-scaled #login-app,
  .is-scaled #admin-app {
    width: 1920px;
    height: 1080px;
    flex: none;
    transform: scale(var(--app-scale, 1));
    transform-origin: center;
  }

  /* ── 表示枚数モード（data-layout は panel-layout.js が設定） ──
     サイドパネル群（status/vehicle-info/alarm/settings/about）は
     各 partial 内で grid-column:3 / grid-row:1 をハードコードしているため、
     1枚モードは列位置、4枚モードは行スパンをここで上書きする。 */
  /* 1枚モード: 3等分グリッドのまま bid が2列分を占める。
     2fr 1fr にするとギャップ本数の差でサイドパネル列が 2/4枚モードと
     数px ずれるため、列定義は共通のままスパンで表現する
     （サイドパネル群は各 partial ハードコードの grid-column:3 のまま動く） */
  #main[data-layout="1"]>.bid-panel {
    grid-column: 1 / 3;
  }

  #main[data-layout="4"] {
    grid-template-columns: 1fr 1fr 1fr;
    grid-template-rows: 1fr 1fr;
  }

  /* サイドパネルは .side-panel で一括指定する。ID 列挙だとパネルを足したとき漏れて
     上半分だけになる（出品リストで発生）。#status-panel は index では .side-panel を
     持たない（venue.php でだけ付く）ため個別に残す */
  #main[data-layout="4"]>#status-panel,
  #main[data-layout="4"]>.side-panel {
    grid-row: 1 / -1;
  }

  /* 4枚モード: パネル高さが半減するため出品表行（grid-row:3 の
     vehicle-sheet / chosei-overlay）を 0 に潰し、panel-body に高さを譲る
     （design-guidelines.md「幅不足時はリア画像を出さない」方針の高さ版） */
  /* vehicle-sheet は grid-row:3 明示のため 0px 行で自然に消える。
     display:none にすると後続 footer の自動配置が繰り上がり 0px 行に落ちるので不可 */
  #main[data-layout="4"] .bid-panel .panel-grid {
    grid-template-rows: 52px minmax(0, 1fr) 0px 36px 36px;
  }

  /* 0px 行に潰すとき padding（16px）が残って行高になるため一緒に消す。
     拡大ボタンは absolute のため 0px 行でも 30px 分はみ出す → 明示的に消す */
  #main[data-layout="4"] .bid-panel .vehicle-sheet {
    padding: 0;
  }

  #main[data-layout="4"] .bid-panel .sheet-zoom-btn {
    display: none;
  }

  /* 4枚モードの写真幅: panel-body が 1fr（316px）に伸びるため、bid-panel.php の
     280px 行前提の min() 計算では写真下に縦余りが出る。固定キャンバス
     （パネル実寸 623×488、vehicle-info 110px）から画像高 230px × 4/3 を決め打ち */
  #main[data-layout="4"] .bid-panel .panel-left {
    width: calc(230px * 4 / 3);
  }

  /* ── 4枚モードの自社出品（調整オーバーレイ）── Slide14 準拠。
     出品表用の 0px 行のままではオーバーレイが巻き添えでクリップされ消えるため、
     自社出品中のパネルだけ行3を自然高に戻す。高さが半減するので
     マトリックスは表示せず、テーブル+ボタン行のみに圧縮する。
     前/次フッターは Slide14 どおり出さない（行3明示配置のため自動配置は崩れない） */
  #main[data-layout="4"] .bid-panel .panel-grid:has(> .chosei-overlay:not(.hidden)) {
    grid-template-rows: 52px minmax(0, 1fr) auto 0px 0px;
  }

  #main[data-layout="4"] .bid-panel .panel-grid:has(> .chosei-overlay:not(.hidden)) panel-footer {
    display: none;
  }

  #main[data-layout="4"] .bid-panel .chosei-bid-grid {
    display: none;
  }

  /* 写真サイズは他パネルと同一（230px×4/3）を保つため、行3側を圧縮する。
     使える高さは 488 - header52 - 本文364(padding16+info110+gap8+写真230) = 72px */
  #main[data-layout="4"] .bid-panel .chosei-bottom {
    padding: 2px var(--sp-md);
  }

  #main[data-layout="4"] .bid-panel .chosei-nagare {
    gap: 0;
  }

  #main[data-layout="4"] .bid-panel .chosei-nagare-count {
    width: 36px;
    height: 36px;
    font-size: var(--fs-lg);
  }

  #main[data-layout="4"] .bid-panel .chosei-table th {
    padding: 1px var(--sp-sm);
    font-size: var(--fs-xs);
  }

  #main[data-layout="4"] .bid-panel .chosei-table td {
    padding: 1px var(--sp-sm);
    font-size: var(--fs-base);
  }

  #main[data-layout="4"] .bid-panel .chosei-table td.saishuu {
    font-size: var(--fs-lg);
  }

  /* 自社出品中は応札ボタンの場所にスロー/うりきりを出す（Slide14）。
     応札ボタンは visibility で不可視化してレイアウト位置を保ち（display:none だと
     space-between で spec 表が下がり重なる）、chosei-actions をその位置へ絶対配置する。
     配置値は固定キャンバス（パネル488px・row3=114px・panel-body の padding 8px）決め打ち */
  #main[data-layout="4"] .bid-panel .panel-grid:has(> .chosei-overlay:not(.hidden)) .bid-btn {
    visibility: hidden;
  }

  #main[data-layout="4"] .bid-panel .chosei-actions {
    position: absolute;
    right: var(--sp-md);
    /* 応札ボタン（高さ60・下端は行3の直上）の枠内に縦センター */
    bottom: 96px;
    padding: 0;
    gap: var(--sp-md);
  }

  /* 4枚モードのスロー/うりきりは横長のピル（応札ボタンの枠 約297×60 に2つ並べる）。
     正方形用の SVG 下地を横に伸ばすと角丸が歪むため、同じ配色のグラデーションで描き、
     アイコンとラベルは絶対配置をやめて横並びにする。文字は --fs-base（「スロー解除」5文字が収まる上限） */
  #main[data-layout="4"] .bid-panel .chosei-slow,
  #main[data-layout="4"] .bid-panel .chosei-urikiri {
    width: 136px;
    height: 52px;
    padding: 0 6px;
    border-radius: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    font-size: var(--fs-base);
  }

  #main[data-layout="4"] .bid-panel .chosei-slow::before,
  #main[data-layout="4"] .bid-panel .chosei-urikiri::before,
  #main[data-layout="4"] .bid-panel .chosei-slow::after,
  #main[data-layout="4"] .bid-panel .chosei-urikiri::after {
    border-radius: inherit;
    mask: none;
  }

  #main[data-layout="4"] .bid-panel .chosei-slow::before {
    background: linear-gradient(180deg, var(--bid-from) 0%, var(--bid-mid) 50%, var(--bid-to) 100%);
    box-shadow: 0 4px 4px color-mix(in srgb, black 25%, transparent);
  }

  #main[data-layout="4"] .bid-panel .chosei-urikiri::before {
    background: linear-gradient(180deg, #E00000 0%, #FF0000 40%, #FF0000 60%, #C00000 100%);
    box-shadow: 0 4px 4px color-mix(in srgb, black 25%, transparent);
  }

  #main[data-layout="4"] .bid-panel .chosei-slow:disabled::before,
  #main[data-layout="4"] .bid-panel .chosei-urikiri:disabled:not(.is-sent)::before {
    background: #6B7280;
    box-shadow: none;
  }

  #main[data-layout="4"] .bid-panel .chosei-icon,
  #main[data-layout="4"] .bid-panel .chosei-label {
    position: static;
    translate: none;
  }

  /* アイコンは高さ 27px 基準。箱の比は bid-panel.php と同じ（描画部分の比を保つ） */
  #main[data-layout="4"] .bid-panel .chosei-icon {
    flex-shrink: 0;
    width: 34px;
    height: 27px;
  }

  #main[data-layout="4"] .bid-panel .chosei-slow[data-cmd="4"] .chosei-icon {
    width: 30px;
    height: 20px;
  }

  #main[data-layout="4"] .bid-panel .chosei-urikiri .chosei-icon {
    width: 18px;
    height: 19px;
  }

  /* 写真列が広がった分 panel-right が縮む（約300px）ため価格を縮小（6桁+千円が収まる上限）。
     リボン/ランプも固定104px×3(=324px)では見切れるため flex 3等分で常に収める
     （panel-narrow と同じ手法。4枚のパネル幅623pxは narrow 閾値620を僅かに超えるため個別対応） */
  #main[data-layout="4"] .bid-panel .price-value {
    font-size: 48px;
  }

  #main[data-layout="4"] .bid-panel .status-lights {
    align-self: stretch;
  }

  #main[data-layout="4"] .bid-panel .ribbon {
    width: auto;
    flex: 1 1 0;
    min-width: 0;
    font-size: var(--fs-sm);
    overflow: hidden;
  }

  #main[data-layout="4"] .bid-panel .light {
    width: auto;
    flex: 1 1 0;
  }

  /* ── スマホ（html.is-mobile は index.php の viewport 切替スクリプトが付与） ──
     縦1カラム積み。パネルは最大2枚（実効枚数は panel-layout.js が丸める）。
     出品表は幅が足りないため非表示（design-guidelines.md のスマホ方針）。 */
  .is-mobile #main,
  .is-mobile #main[data-layout] {
    grid-template-columns: 1fr;
    grid-template-rows: none;
    grid-auto-rows: minmax(0, 1fr);
  }

  .is-mobile #main .bid-panel {
    grid-column: 1;
  }

  .is-mobile #main .bid-panel .panel-grid {
    grid-template-rows: 52px minmax(0, 1fr) 0px 36px 36px;
  }

  /* 価格行は縮ませない。スマホの本文行は 234px しかなく、flex の自然縮小に任せると
     リボン+ランプ帯が高さを取って価格が 10px に潰れ、数字が読めなくなる */
  .is-mobile #main .bid-panel .price-area {
    flex: none;
  }

  /* 本文右列の縦配分を明示する（価格=内容なり / 表=残り / 応札=56px 固定）。
     flex の自然縮小に任せると、表の min-content が応札ボタンを本文行の下へ押し出す。
     行の 60px は .bid-btn の固定高（これより小さくすると行からはみ出す） */
  .is-mobile #main .bid-panel .spec-bid-wrap {
    display: grid;
    grid-template-rows: minmax(0, 1fr) 60px;
    gap: var(--sp-sm);
    min-height: 0;
  }

  .is-mobile #main .bid-panel .vehicle-spec {
    min-height: 0;
  }

  /* 価格を確保した分、年式グレード表は文字なりの高さに詰める */
  .is-mobile #main .bid-panel .vehicle-spec th,
  .is-mobile #main .bid-panel .vehicle-spec td {
    padding: 2px 8px;
    line-height: 1.2;
  }

  .is-mobile #main .bid-panel .vehicle-spec th {
    font-size: var(--fs-xs);
  }

  .is-mobile #main .bid-panel .vehicle-spec td {
    font-size: var(--fs-base);
  }

  /* ヘッダーは 372px に「チャンネル・会場レーン・音量・参戦切替・拡大」が並ぶ。
     既定の gap 8px とロゴ 26px では会場レーンの取り分が 108px しかなく、レーンバッジと
     プルダウンの ▼ が右に見切れる（会場名は既に幅0まで縮んでいる）。
     余白とロゴで幅を作る。ヘッダーの左右 padding は触らない（規則 I4 の整列格子） */
  .is-mobile #main .bid-panel .panel-header {
    gap: var(--sp-xs);
  }

  .is-mobile #main .bid-panel .venue-logo {
    height: 20px;
  }

  /* 0px 行の padding 残り対策と拡大ボタンのはみ出し対策（4枚モードと同じ） */
  .is-mobile #main .bid-panel .vehicle-sheet {
    padding: 0;
  }

  .is-mobile #main .bid-panel .sheet-zoom-btn {
    display: none;
  }

  .is-mobile #main > #status-panel {   /* venue ではサイドパネルとして開けるので index に限る */
    display: none !important;
  }

  /* スマホ: ヘッダーの中身（アラームメッセージ・設定バー等）は縮まないため、
     はみ出しをヘッダー内の横スクロールに閉じ込める。
     これを怠るとページ全体の scrollWidth が広がり、ブラウザが
     initial-scale=1 を無視してズームアウトする（画面全体が縮小表示になる） */
  .is-mobile #header {
    overflow-x: auto;
  }

  /* デスクトップの .header-left { flex:1; min-width:0 }（alarm-message を
     アカウント左端まで伸ばす）はスクロール前提のモバイルでは逆効果
     （左ブロックが潰れ右ブロックが重なる）ため自然幅に戻す */
  .is-mobile #header .header-left {
    flex: 0 0 auto;
    min-width: max-content;
  }

  /* スマホのパネル内部の縮小は bid-panel.php のコンテナクエリ（幅620px未満）に一元化 */

  /* サイドパネル（車両情報/アラーム/設定/about）を開いたら応札パネルを隠して単独表示 */
  .is-mobile #main>#vehicle-info-panel,
  .is-mobile #main>#alarm-panel,
  .is-mobile #main>#own-vehicles-panel,
  .is-mobile #main>#about-panel,
  .is-mobile #main>#menu-panel,
  .is-mobile #main>#settings-panel {
    grid-column: 1;
    grid-row: 1 / -1;
  }

  .is-mobile #main:has(#vehicle-info-panel.visible) .bid-panel,
  .is-mobile #main:has(#alarm-panel.visible) .bid-panel,
  .is-mobile #main:has(#own-vehicles-panel.visible) .bid-panel,
  .is-mobile #main:has(#about-panel.visible) .bid-panel,
  .is-mobile #main:has(#menu-panel.visible) .bid-panel,
  .is-mobile #main:has(#settings-panel.visible) .bid-panel {
    display: none !important;
  }
}

@layer base {
  /* ── アラーム音の試聴ボタン（アラームパネル・設定パネル共用） ── */
  .tone-preview-btn {
    width: 30px;
    height: 30px;
    border-radius: 6px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    color: var(--accent-light);
    font-size: 26px;
    font-family: 'Material Symbols Rounded';
    line-height: 1;
    cursor: pointer;
    flex-shrink: 0;
  }

  .tone-preview-btn:hover {
    background: var(--hover-overlay);
  }

  /* ── スクロールバー ── */
  ::-webkit-scrollbar {
    width: 6px;
    height: 6px;
  }

  ::-webkit-scrollbar-track {
    background: transparent;
  }

  ::-webkit-scrollbar-thumb {
    background: #4B5563;
    border-radius: 3px;
  }

  ::-webkit-scrollbar-thumb:hover {
    background: #6B7280;
  }

  /* ── グリッド ── */
  .row {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: var(--sp-md);
  }

  .row.gap-xs {
    gap: var(--sp-xs);
  }

  .row.gap-sm {
    gap: var(--sp-sm);
  }

  .row.gap-lg {
    gap: var(--sp-lg);
  }

  .row.no-gap {
    gap: 0;
  }

  .col-1 {
    grid-column: span 1;
  }

  .col-2 {
    grid-column: span 2;
  }

  .col-3 {
    grid-column: span 3;
  }

  .col-4 {
    grid-column: span 4;
  }

  .col-5 {
    grid-column: span 5;
  }

  .col-6 {
    grid-column: span 6;
  }

  .col-7 {
    grid-column: span 7;
  }

  .col-8 {
    grid-column: span 8;
  }

  .col-9 {
    grid-column: span 9;
  }

  .col-10 {
    grid-column: span 10;
  }

  .col-11 {
    grid-column: span 11;
  }

  .col-12 {
    grid-column: span 12;
  }

  /* ── ボタン基底 ── */
  button[size] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    cursor: pointer;
    font-family: var(--font);
    font-weight: 700;
    line-height: 1;
    white-space: nowrap;
  }

  button[size="xs"] {
    height: var(--btn-h-xs);
    padding: 0 var(--sp-sm);
    font-size: var(--fs-xs);
    border-radius: 50px;
  }

  button[size="sm"] {
    height: var(--btn-h-sm);
    padding: 0 var(--sp-md);
    font-size: var(--fs-sm);
    border-radius: 5px;
  }

  button[size="md"] {
    height: var(--btn-h-md);
    padding: 0 var(--sp-lg);
    font-size: var(--fs-base);
    border-radius: 6px;
  }

  button[size="lg"] {
    height: var(--btn-h-lg);
    padding: 0 var(--sp-lg);
    font-size: var(--fs-lg);
    border-radius: 8px;
  }

  button[size="xl"] {
    height: var(--btn-h-xl);
    padding: 0 24px;
    font-size: var(--fs-xl);
    border-radius: 15px;
  }

  /* ── toggle-btn コンポーネント ── */
  toggle-btn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    background: #374151;
    border-radius: 50px;
    padding: 4px 8px;
    cursor: pointer;
    border: 1px solid var(--border-light);
    width: 100px;
    height: 36px;
    overflow: hidden;
  }

  toggle-btn[active] {
    background: var(--accent);
  }

  toggle-btn[readonly] {
    cursor: default;
    pointer-events: none;
  }

  /* ベタ塗りのため白オーバーレイではなく明度を上げる（ON/OFF どちらの色でも効く） */
  toggle-btn:hover:not([readonly]) {
    filter: brightness(1.15);
  }

  toggle-btn[size="mini"] {
    width: 68px;
    height: 22px;
    padding: 0 5px;
    gap: 3px;
  }

  toggle-btn .toggle-knob {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: white;
    flex-shrink: 0;
  }

  toggle-btn[size="mini"] .toggle-knob {
    width: 14px;
    height: 14px;
  }

  toggle-btn[active] .toggle-knob {
    order: 1;
    margin-left: auto;
  }

  toggle-btn .toggle-label {
    font-size: var(--fs-base);
    font-weight: 500;
    color: var(--text);
    /* 丸スイッチを除いた残り幅の中央にラベルを置く（ON/OFF どちらの側でも同じ位置） */
    flex: 1;
    text-align: center;
    min-width: 0;
  }

  toggle-btn[size="mini"] .toggle-label {
    font-size: var(--fs-xs);
  }

  /* ── ラジオの選択肢（設定・アラーム・管理画面で共用） ── */
  .radio-group {
    display: flex;
    align-items: center;
    gap: var(--sp-md);
  }

  .radio-opt {
    display: flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
    color: var(--text);
    font-family: var(--font);
    font-size: var(--fs-base);
    padding: 4px 2px;
    border-radius: 6px;
  }

  /* 選択肢の行全体が押せるため、言語切替（lang-bar）と同じ座布団を出す */
  .radio-opt:hover {
    background: var(--bg-panel);
  }

  /* ネイティブ radio をブランド色で描画（checked 状態・キーボード操作はブラウザ任せ） */
  .radio-opt input[type="radio"] {
    accent-color: var(--accent);
    width: 18px;
    height: 18px;
    margin: 0;
    cursor: pointer;
  }
}

@layer utilities {
  /* 最上位レイヤー: どのコンポーネント・モードよりも強い */
  .hidden {
    display: none !important;
  }

  .d-flex {
    display: flex;
  }

  .align-center {
    align-items: center;
  }

  .align-start {
    align-items: flex-start;
  }

  .align-end {
    align-items: flex-end;
  }

  .justify-center {
    justify-content: center;
  }

  .justify-start {
    justify-content: flex-start;
  }

  .justify-end {
    justify-content: flex-end;
  }

  .flex-column {
    flex-direction: column;
  }
}
