/* ============================================================================
   Ecochat / 株式会社リサイクルマイスター  ―  統合スタイルシート  app.css
   ----------------------------------------------------------------------------
   これは唯一のスタイルシートです。HTML / JS は一切変更していません。
   既存のクラス名・ID・DOM 構造・app.js が書き込むインライン style を
   そのまま前提にしています。

   ■ 対応バージョン
      index.html : 現行（<meta name="color-scheme" content="light"> / h1.chat-head-name /
                   #pinBar / #newPill / .more-wrap + #composerMore / .panel-close /
                   .ch-title + #btnHangupTop / .cb-sub / 各ボタンの <span aria-hidden>）
      app.js     : 現行（2,650 行 / 131KB）
      第2次 差分対応ぶんを取り込み済み。新機能は下記のとおり本文系セクションの
      中に配置してあり、末尾追記のパッチ層は存在しません。

   ■ 第2次で新規対応した機能（どのセクションに入っているか）
      固定メッセージ（ピン留め）バー .pin-*            → 09
      アンケート / 出欠確認カード     .poll-*           → 10
      メッセージのインライン編集      .edit-ta/.edit-btns → 10
      新着メッセージ誘導ピル          .new-pill         → 10
      オーバーフローメニュー          .more-wrap/.more-menu → 11 と 22
      右パネル再設計                  .panel-room/.panel-info/.panel-leave/
                                      .panel-add/.panel-tabbar/.panel-close → 13
      予約投稿の一覧行                .sched-*          → 14
      通話ヘッダ / 共有中の状態       .ch-title/.btn-hangup-top/.call-ctrl button.on → 15
      接続断バナーの補足文            .cb-sub           → 16
      エラートースト                  .toast-error      → 16
      空表示 / 読み込み失敗           .list-empty(.err/.sm) → 08

   ■ 構成（上から順に読む / 下にあるものほど強い）
      00 デザイントークン（ライト）
      01 ダークモードのトークン上書き
      02 リセット・ベース要素
      03 ボタン
      04 スクロールバー
      05 認証画面
      06 レイアウト骨格
      07 サイドバー
      08 チャットヘッダー / 空状態 / 空表示（.list-empty）
      09 固定メッセージ（ピン留め）バー
      10 メッセージ領域（本文・アンケート・インライン編集・新着ピル）
      11 入力欄（composer / オーバーフローメニュー）
      12 TODO リスト
      13 右パネル
      14 モーダル / 絵文字ピッカー / 予約投稿行
      15 通話画面
      16 トースト / 接続断バナー
      17 アニメーション
      18 フォーカスリング
      19 ダークモード：コンポーネント個別の上書き
      20 レスポンシブ（1100px / 760px / 520px / 420px / タップ端末）
      21 アクセシビリティ（コントラスト / forced-colors / モーション低減）
      22 絵文字ボタンの SVG アイコン化
      23 app.js のインライン style 救済

   ■ ダークモードの仕組み
      - 自動:  @media (prefers-color-scheme: dark) { html:not([data-theme="light"]) { … } }
      - 手動:  html[data-theme="dark"] { … }   （将来 JS で data-theme を差すだけで効く）
      - 固定:  html[data-theme="light"]        （OS がダークでもライトを保つ）
      この 3 つは必ず「対」で書くこと。自動用と手動用は同一の値を二重定義している。
      値を触るときは必ず両方直すこと（01 節・19 節）。

   ■ 編集時の注意
      1. 生の 16 進カラーを書いてよいのは 00 節・01 節（トークン定義）と
         22 節の SVG data URI の中だけ。それ以外は必ず var() を経由すること。
      2. --brand-strong は「濃緑のサーフェス（面）」。文字色には使わない。
         濃緑を文字色に使いたいときは --brand-ink（ダークでは明緑に反転する）を使う。
         --brand-strong の上に載せる文字は --on-brand-strong（常に白）。
      3. --green-900 / --green-700 / --bg / --panel / --line / --txt / --txt-sub /
         --red / --amber / --blue / --radius / --shadow は app.js のインライン style
         からも参照されている。名前を消さないこと。
      4. フォーカスリングは 18 節で全域一括定義。個別コンポーネントでは
         色を再定義せず、必要なら outline-offset だけ調整する。
      5. !important を使ってよいのは .hidden / .mobile-only / モーション低減 /
         forced-colors / インライン style の救済（23 節と、14 節の
         .modal-foot > span[style*="flex"] の 1 件）だけ。
      6. モバイル（760px 以下）の input / textarea / select は font-size 16px 以上を
         下回らせないこと。16px 未満だと iOS がフォーカス時に勝手に拡大する。
      7. app.js が書き込むインライン style は上書きしない。
         とくに .poll-bar の style="width:○%"（得票率そのもの）と
         .pollOpt の style="flex:1"、アバター / ルームアイコンの background は
         CSS 側から絶対に触らないこと。
      8. 状態クラスは JS が付け外しする。CSS 側で別名を作らない。
         .on / .off / .done / .over / .mine / .closed / .force / .chat-open /
         .tapped / .hidden / .pin-flash / .toast-error / .muted / .err / .sm
      9. .err .sm .closed .muted は単独で出現しない。必ず親クラスとの複合
         （.list-empty.err / .poll-opt.closed / .badge.muted / .panel-desc .muted）
         で書くこと。
     10. `.c` というクラスは実在しない（app.js の三項演算子を抽出器が誤検出した
         もの。実出力は class="on" か class="" のみ）。定義を足さないこと。

   ■ 前提ブラウザと、古い環境での落ち方
      2023 年以降の Chrome / Edge / Safari / Firefox を前提にしている。
      古い環境でも「読めなくなる」ことはなく、装飾から順に落ちるようにしてある。
      - color-mix()   … 面の淡い色づけ（引用・コード・タグ・タスク枠・通話画面）。
                        非対応だと色が付かないだけで、文字は地の色を継いで読める。
      - :has()        … 未読行の名前を太くする強調 / 編集中の pre-wrap 解除。
                        非対応でも未読バッジは出る。編集中は 1 行ぶん余白が残るだけ。
      - mask-image    … 22 節のアイコン化。非対応時は @supports not 側が働き、
                        元の絵文字がそのまま表示される（22 節末尾）。

   ■ 検証済みの範囲（Chromium で実描画して計測）
      ・表示: 1440 / 1000 / 390px × ライト / ダーク
        （ピン留めバー / アンケート 3 状態 / 予約一覧 / インライン編集 /
          その他メニュー展開 / 右パネル 4 タブ / 通話画面 / 接続断バナー /
          新着ピル / 空表示・読み込み失敗 を含む）
      ・横はみ出し: 320 / 360 / 390 / 520 / 760 / 1000 / 1280 / 1440 / 1920px
        の全幅で scrollWidth == innerWidth（横スクロールなし）
      ・コントラスト: 文字色は computedStyle、背景は「文字を透明にした
        実レンダリング」からピクセル採取して実測。新機能の文字は
        すべて WCAG AA（本文 4.5:1 / 大文字 3:1）以上。
      色を変えるときは必ずコントラストを測り直すこと。
   ============================================================================ */


/* ============================================================
   00. デザイントークン（ライト）
   コントラスト実測値（WCAG 2.1 相対輝度）は行末コメントに記載。
   ============================================================ */
:root {
  color-scheme: light;

  /* 下バーのぶんとして空ける高さ。
     ★ 固定値にしないこと。下バーの中身 (絵 23px・字 10px) は文字の大きさ設定
     (--ui-scale) で伸びるため、「最大」にすると帯が 82px を超え、
     68px しか空けていないと送信ボタンや保存ボタンが帯の裏に隠れる。
     実際の高さは app.js が測って書き換える。ここはその前の初期値。 */
  --nav-h: 68px;

  /* --- ブランド緑（既存名。app.js からも参照されるので絶対に消さない） --- */
  --green-900: #1e5138;   /* 濃緑サーフェス   白文字と 9.17:1 */
  --green-700: #2f7d55;   /* 主操作色         白文字と 5.02:1 */
  --green-600: #3a9265;   /* hover */
  --green-500: #3aa06b;   /* アクセント罫線 / app.js のアバター既定色 */
  --green-100: #e2f2e9;   /* 選択・チップの面 */
  --green-50:  #f2f9f5;   /* 極薄 hover 面 */

  /* --- ブランド意味トークン（他はこちらを優先して使う） --- */
  --brand:            var(--green-700);  /* 主操作の面/線 */
  --brand-hover:      var(--green-600);
  --brand-active:     #276a48;
  --brand-strong:     var(--green-900);  /* 濃緑「サーフェス」。文字色には使わない */
  --brand-ink:        var(--green-900);  /* 濃緑「文字色」。ダークでは明緑に反転する */
  --brand-weak:       var(--green-100);  /* 選択中・チップの面 */
  --brand-tint:       var(--green-50);   /* 最も薄い hover 面 */
  --on-brand:         #ffffff;           /* --brand の上の文字        5.02:1 */
  --on-brand-strong:  #ffffff;           /* --brand-strong の上の文字 9.17:1（常に白） */
  --on-brand-weak:    #1a4a33;           /* --brand-weak の上の文字   8.74:1 */
  --on-accent:        #ffffff;           /* --red/--amber/--blue の上（各 4.7:1 以上） */

  /* --- サーフェス --- */
  --bg:         #f2f6f3;  /* アプリ地。ほんのり緑に振ったニュートラル */
  --bg-sunken:  #e8eeea;  /* 一段沈んだ面（入力欄・行ホバー・空状態） */
  --panel:      #ffffff;  /* カード / サイドバー / ヘッダー */
  --panel-2:    #f8fbf9;  /* パネル内の副次面 */
  --field:      #ffffff;  /* 入力欄の既定地（:where() の素の値） */
  --field-focus:#ffffff;
  --hover-bg:   #eef4f0;  /* 予備: 行ホバー（現状は --bg-sunken を使用） */
  --active-bg:  var(--brand-weak);
  --scrim:      rgba(20, 40, 30, .45);   /* モーダル背面 */

  /* --- 罫線 --- */
  --line:        #dde5df;  /* 標準の区切り線（既存名） */
  --line-strong: #c3d1c8;  /* 入力欄・ゴーストボタンの縁 */

  /* --- テキスト --- */
  --txt:       #1f2b25;  /* 本文     panel 14.68:1 / bg 13.46:1 */
  --txt-sub:   #57665e;  /* 補助     panel  6.06:1 / bg  5.55:1 */
  /* 補助の下段（時刻・小見出し・placeholder）。
     旧値 #626f68 は --bg-sunken の上が実測 4.47:1 で AA を割っていた
     （コメントの 4.82:1 は誤り）。輝度をわずかに落として全面で 4.5 を確保。
     実測: panel 5.56:1 / panel-2 5.34:1 / bg 5.10:1 / bg-sunken 4.73:1 /
           mention-me の琥珀地 4.68:1 */
  --txt-faint: #5f6b64;

  /* --- 状態色（いずれも白と 4.5:1 以上 = 文字色でも面としても使える） --- */
  --red:   #bf3b3b;  /* 白と 5.38:1 */
  --amber: #8f6210;  /* 白と 5.35:1 / --warn-bg 上 5.05:1 */
  --blue:  #30699b;  /* 白と 5.80:1（予備） */
  --online:  #2f9c58;
  --offline: #a8b6ad;
  --avatar-fallback: #647268;   /* 白文字と 5.06:1 */

  /* --- 状態サーフェス（淡い面 + その上の文字） --- */
  --danger-bg:   #fdecec;
  --danger-line: #f2cccc;
  --danger-txt:  #9b2c2c;   /* danger-bg 上で 6.59:1 */
  --warn-bg:     #fdf8ec;
  --warn-line:   #ecd9ae;
  --warn-txt:    #6f4e0c;   /* warn-bg 上で 7.15:1 */
  --warn-solid:  #9c5f22;   /* 接続断バナーの地。白文字と 5.16:1 */
  --ok-bg:       #eef8f1;
  --ok-line:     #cfe6d6;
  --info-bg:     #e7f6ec;

  /* --- メンション / TO --- */
  --mention-bg:      #fdf6e8;
  --mention-chip-bg: #f7e2b8;
  --mention-chip-txt:#6f4f0f;   /* chip-bg 上で 5.90:1 */

  /* --- コードブロック（予備。実体は --l3-code-* を使用） --- */
  --code-bg:  #263129;
  --code-txt: #d9e8dd;          /* 10.64:1 */

  /* --- 認証画面のグラデーション --- */
  --auth-grad-1: #eaf5ee;
  --auth-grad-2: #d7ebde;
  --auth-grad-3: #cfe6e2;

  /* --- ボタン無効 --- */
  --btn-disabled-bg:  #d3ded7;
  --btn-disabled-txt: #56635b;   /* 4.56:1 */

  /* --- スクロールバー --- */
  --scroll-thumb:       #c6d4ca;
  --scroll-thumb-hover: #a9bdb0;

  /* --- 角丸 --- */
  --radius-xs:   6px;
  --radius-sm:   8px;
  --radius:     10px;   /* 既存名 */
  --radius-lg:  14px;
  --radius-pill: 999px;

  /* --- 影 --- */
  --shadow-1: 0 1px 2px rgba(24, 48, 36, .06), 0 1px 3px rgba(24, 48, 36, .08);
  --shadow-2: 0 4px 18px rgba(30, 60, 45, .12);
  --shadow-3: 0 18px 48px rgba(20, 45, 33, .20);
  --shadow:   var(--shadow-2);   /* 既存名 */
  --shadow-press: inset 0 2px 5px rgba(0, 0, 0, .18);

  /* --- 余白（4px グリッド） --- */
  --space-1:  4px;
  --space-2:  8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;

  /* --- タイポ --- */
  --font-ja: system-ui, -apple-system, "Segoe UI", "Hiragino Kaku Gothic ProN",
             "Yu Gothic UI", "Meiryo", "Noto Sans JP", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Consolas, "Courier New",
               "Hiragino Kaku Gothic ProN", monospace;
  /* 文字の大きさの倍率。画面の「文字の大きさ」から書き換える。
     1 = 標準 / 1.15 = 大きめ / 1.3 = 特大 / 0.9 = 小さめ
     ここ1か所を変えれば、下の生の px 指定もまとめて追従する。 */
  --ui-scale: 1;
  --fs-2xs: calc(10.5px * var(--ui-scale));
  --fs-xs:  calc(11.5px * var(--ui-scale));
  --fs-sm:  calc(12.5px * var(--ui-scale));
  --fs-md:  calc(13.5px * var(--ui-scale));
  --fs-lg:  calc(15px   * var(--ui-scale));
  --fs-xl:  calc(17px   * var(--ui-scale));
  --fs-2xl: calc(22px   * var(--ui-scale));
  --lh-tight: 1.35;
  --lh:       1.6;
  --lh-loose: 1.75;

  /* --- モーション --- */
  --ease:      cubic-bezier(.2, .7, .35, 1);
  --ease-out:  cubic-bezier(.16, 1, .3, 1);
  --dur-fast:  110ms;
  --dur:       190ms;
  --dur-slow:  280ms;

  /* --- フォーカス --- */
  --focus:      #2f7d55;                          /* リングの実線色 */
  --focus-ring: 0 0 0 3px rgba(47, 125, 85, .30); /* 予備: box-shadow 版 */
  --focus-on-dark: var(--on-brand-strong);        /* 濃緑サーフェス上のリング色 */

  /* --- 本文まわり（メッセージ領域のローカルトークン / --l3-*） --- */
  --l3-msg-fs:      14px;   /* 日本語本文 */
  --l3-msg-lh:      1.8;    /* 長時間読んでも疲れない行間 */
  --l3-msg-track:   .015em; /* わずかな字間で密着を防ぐ */
  --l3-measure:     46em;   /* 行長: 全角約46文字で折り返す */
  --l3-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
             "Roboto Mono", "Noto Sans Mono", "Osaka-Mono", "MS Gothic", monospace;

  --l3-msg-hover:   color-mix(in srgb, var(--txt) 5%, transparent);
  --l3-mine-bg:     color-mix(in srgb, var(--brand) 6%, transparent);
  --l3-mention-bg:  color-mix(in srgb, var(--amber) 13%, var(--panel));
  --l3-mention-bar: var(--amber);
  --l3-sys-bg:      color-mix(in srgb, var(--brand) 7%, var(--bg-sunken));

  /* コードブロック: 明暗どちらでも「コード」として読める深色面 */
  --l3-code-bg:     color-mix(in srgb, var(--green-900) 26%, var(--txt));
  --l3-code-fg:     color-mix(in srgb, white 84%, var(--brand));
  --l3-code-line:   color-mix(in srgb, white 14%, transparent);

  /* 装飾記法 */
  --l3-tag-bg:      color-mix(in srgb, var(--brand) 16%, var(--panel));
  --l3-tag-fg:      var(--brand-ink);
  --l3-tag-line:    color-mix(in srgb, var(--brand) 34%, transparent);
  --l3-tagme-bg:    color-mix(in srgb, var(--amber) 24%, var(--panel));
  --l3-tagme-fg:    color-mix(in srgb, var(--amber) 40%, var(--txt));
  --l3-tagme-line:  color-mix(in srgb, var(--amber) 58%, transparent);
  --l3-quote-bg:    color-mix(in srgb, var(--brand) 6%, var(--bg-sunken));
  --l3-info-bg:     var(--panel-2);
  --l3-info-head:   color-mix(in srgb, var(--brand) 13%, var(--panel-2));
  --l3-task-bg:     color-mix(in srgb, var(--amber) 10%, var(--panel));
  --l3-task-line:   color-mix(in srgb, var(--amber) 38%, transparent);
  --l3-taskdone-bg: color-mix(in srgb, var(--brand) 9%, var(--panel));
  --l3-taskdone-line: color-mix(in srgb, var(--brand) 30%, transparent);

  /* リアクション */
  --l3-chip-bg:     var(--panel);
  --l3-chip-line:   var(--line-strong);
  --l3-chipmine-bg: color-mix(in srgb, var(--brand) 14%, var(--panel));
  --l3-chipmine-line: var(--brand);
  --l3-chipmine-fg: var(--brand-ink);

  /* 危険色テキスト（ライトでは濃く落として可読性を確保） */
  --l3-danger-ink:  color-mix(in srgb, var(--red) 72%, var(--txt));
  /* 本文リンク色（ダークでは白寄りに持ち上げる） */
  --l3-link:        var(--brand-ink);

  /* 入力欄 */
  --l3-field-bg:    var(--bg-sunken);
  --l3-field-focus-bg: var(--panel);

  /* アイコン既定サイズ（ストローク幅 1.7 は data URI 内に固定） */
  --icon-size: 18px;

  font-size: calc(14px * var(--ui-scale));
}


/* ============================================================
   01. ダークモードのトークン上書き
   真っ黒にせず、緑寄りニュートラルの #12181x 系。
   bg(#121815) → panel(#1a221d) → panel-2(#212b25) で段差を明示する。
   ------------------------------------------------------------
   ※ 自動（@media）版と手動（html[data-theme="dark"]）版は
     完全に同一の値を二重定義している。片方だけ直さないこと。
   ============================================================ */
@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]) {
    color-scheme: dark;

    /* ブランド緑: ダークで沈まないよう明度を上げる */
    --green-900: #1e4634;   /* 濃緑サーフェスのまま（白文字と 10.60:1） */
    --green-700: #4fb583;   /* panel 上で 6.41:1 = 文字にも使える */
    --green-600: #63c795;
    --green-500: #57bd8b;
    --green-100: #22392e;
    --green-50:  #1a231e;

    --brand:            var(--green-700);
    --brand-hover:      var(--green-600);
    --brand-active:     #45a173;
    --brand-strong:     var(--green-900);
    --brand-ink:        var(--green-700);   /* 濃緑文字 → 明緑に反転 */
    --brand-weak:       var(--green-100);
    --brand-tint:       var(--green-50);
    --on-brand:         #08130d;   /* --brand の上   7.46:1 */
    --on-brand-strong:  #ffffff;   /* --brand-strong の上 10.60:1 */
    --on-brand-weak:    #a9e3c3;   /* --brand-weak の上   8.54:1 */
    --on-accent:        #0d1411;   /* --red の上 6.38:1 ほか */

    --bg:         #121815;
    --bg-sunken:  #0d1210;
    --panel:      #1a221d;
    --panel-2:    #212b25;
    --field:      #141b17;
    --field-focus:#171f1a;
    --hover-bg:   #1e2823;
    --active-bg:  var(--brand-weak);
    --scrim:      rgba(0, 0, 0, .70);

    --line:        #2b3630;
    --line-strong: #3d4b44;

    --txt:       #e8efea;  /* panel 13.92:1 / bg 15.39:1 / panel-2 12.50:1 */
    --txt-sub:   #a4b4ab;  /* panel  7.51:1 / bg  8.31:1 / panel-2  6.75:1 */
    --txt-faint: #8b9a92;  /* panel  5.53:1 / panel-2 4.97:1 */

    --red:   #e07a6f;  /* panel 5.57:1 */
    --amber: #dfa94f;  /* panel 7.69:1 */
    --blue:  #74afd4;  /* panel 6.84:1 */
    --online:  #4fc57e;
    --offline: #5c6a62;
    --avatar-fallback: #46534c;   /* 白文字と 8.07:1 */

    --danger-bg:   #2a1a18;
    --danger-line: #4d2e2a;
    --danger-txt:  #f0a89e;   /* 8.58:1 */
    --warn-bg:     #241f14;
    --warn-line:   #4a3d20;
    --warn-txt:    #e2c17e;   /* 9.49:1 */
    --warn-solid:  #96591a;   /* 白文字と 5.61:1 */
    --ok-bg:       #14251b;
    --ok-line:     #2c4433;
    --info-bg:     #162a1f;

    --mention-bg:      #262013;
    --mention-chip-bg: #3a2f14;
    --mention-chip-txt:#f2cf8c;   /* 8.82:1 */

    --code-bg:  #0e1411;
    --code-txt: #cfe3d6;          /* 13.85:1 */

    --auth-grad-1: #16241c;
    --auth-grad-2: #101a15;
    --auth-grad-3: #0e1a1a;

    --btn-disabled-bg:  #262f2a;
    --btn-disabled-txt: #909d95;   /* 4.89:1 */

    --scroll-thumb:       #35443c;
    --scroll-thumb-hover: #47594f;

    --shadow-1: 0 1px 2px rgba(0, 0, 0, .5);
    --shadow-2: 0 6px 22px rgba(0, 0, 0, .55);
    --shadow-3: 0 22px 56px rgba(0, 0, 0, .70);
    --shadow:   var(--shadow-2);
    --shadow-press: inset 0 2px 5px rgba(0, 0, 0, .45);

    --focus:      #6ecf9f;
    --focus-ring: 0 0 0 3px rgba(110, 207, 159, .32);

    /* --- 本文まわり --- */
    --l3-msg-hover:   color-mix(in srgb, var(--txt) 7%, transparent);
    --l3-mine-bg:     color-mix(in srgb, var(--brand) 10%, transparent);
    --l3-mention-bg:  color-mix(in srgb, var(--amber) 10%, var(--panel));
    --l3-sys-bg:      color-mix(in srgb, var(--brand) 8%, var(--panel-2));

    --l3-code-bg:     color-mix(in srgb, black 38%, var(--panel));
    --l3-code-fg:     color-mix(in srgb, white 74%, var(--brand));
    --l3-code-line:   color-mix(in srgb, white 10%, transparent);

    --l3-tag-bg:      color-mix(in srgb, var(--brand) 20%, var(--panel));
    --l3-tag-fg:      color-mix(in srgb, var(--brand) 55%, white);
    --l3-tag-line:    color-mix(in srgb, var(--brand) 42%, transparent);
    --l3-tagme-bg:    color-mix(in srgb, var(--amber) 18%, var(--panel));
    --l3-tagme-fg:    color-mix(in srgb, var(--amber) 72%, white);
    --l3-tagme-line:  color-mix(in srgb, var(--amber) 55%, transparent);
    --l3-quote-bg:    color-mix(in srgb, var(--brand) 8%, var(--panel-2));
    --l3-info-bg:     var(--panel-2);
    --l3-info-head:   color-mix(in srgb, var(--brand) 16%, var(--panel-2));
    --l3-task-bg:     color-mix(in srgb, var(--amber) 12%, var(--panel));
    --l3-task-line:   color-mix(in srgb, var(--amber) 32%, transparent);
    --l3-taskdone-bg: color-mix(in srgb, var(--brand) 11%, var(--panel));
    --l3-taskdone-line: color-mix(in srgb, var(--brand) 28%, transparent);

    --l3-chip-bg:     var(--panel-2);
    --l3-chip-line:   var(--line-strong);
    --l3-chipmine-bg: color-mix(in srgb, var(--brand) 20%, var(--panel));
    --l3-chipmine-line: var(--brand);
    --l3-chipmine-fg: color-mix(in srgb, var(--brand) 50%, white);

    --l3-danger-ink:  var(--red);
    --l3-link:        color-mix(in srgb, var(--brand) 82%, white);

    --l3-field-bg:    color-mix(in srgb, black 24%, var(--panel));
    --l3-field-focus-bg: var(--panel-2);
  }
}

/* 手動切替フック（将来 JS で html[data-theme] を差すだけで効く） */
html[data-theme="dark"] {
  color-scheme: dark;

  --green-900: #1e4634;
  --green-700: #4fb583;
  --green-600: #63c795;
  --green-500: #57bd8b;
  --green-100: #22392e;
  --green-50:  #1a231e;

  --brand:            var(--green-700);
  --brand-hover:      var(--green-600);
  --brand-active:     #45a173;
  --brand-strong:     var(--green-900);
  --brand-ink:        var(--green-700);
  --brand-weak:       var(--green-100);
  --brand-tint:       var(--green-50);
  --on-brand:         #08130d;
  --on-brand-strong:  #ffffff;
  --on-brand-weak:    #a9e3c3;
  --on-accent:        #0d1411;

  --bg:         #121815;
  --bg-sunken:  #0d1210;
  --panel:      #1a221d;
  --panel-2:    #212b25;
  --field:      #141b17;
  --field-focus:#171f1a;
  --hover-bg:   #1e2823;
  --active-bg:  var(--brand-weak);
  --scrim:      rgba(0, 0, 0, .70);

  --line:        #2b3630;
  --line-strong: #3d4b44;

  --txt:       #e8efea;
  --txt-sub:   #a4b4ab;
  --txt-faint: #8b9a92;

  --red:   #e07a6f;
  --amber: #dfa94f;
  --blue:  #74afd4;
  --online:  #4fc57e;
  --offline: #5c6a62;
  --avatar-fallback: #46534c;

  --danger-bg:   #2a1a18;
  --danger-line: #4d2e2a;
  --danger-txt:  #f0a89e;
  --warn-bg:     #241f14;
  --warn-line:   #4a3d20;
  --warn-txt:    #e2c17e;
  --warn-solid:  #96591a;   /* 白文字と 5.61:1 */
  --ok-bg:       #14251b;
  --ok-line:     #2c4433;
  --info-bg:     #162a1f;

  --mention-bg:      #262013;
  --mention-chip-bg: #3a2f14;
  --mention-chip-txt:#f2cf8c;

  --code-bg:  #0e1411;
  --code-txt: #cfe3d6;

  --auth-grad-1: #16241c;
  --auth-grad-2: #101a15;
  --auth-grad-3: #0e1a1a;

  --btn-disabled-bg:  #262f2a;
  --btn-disabled-txt: #909d95;

  --scroll-thumb:       #35443c;
  --scroll-thumb-hover: #47594f;

  --shadow-1: 0 1px 2px rgba(0, 0, 0, .5);
  --shadow-2: 0 6px 22px rgba(0, 0, 0, .55);
  --shadow-3: 0 22px 56px rgba(0, 0, 0, .70);
  --shadow:   var(--shadow-2);
  --shadow-press: inset 0 2px 5px rgba(0, 0, 0, .45);

  --focus:      #6ecf9f;
  --focus-ring: 0 0 0 3px rgba(110, 207, 159, .32);

  --l3-msg-hover:   color-mix(in srgb, var(--txt) 7%, transparent);
  --l3-mine-bg:     color-mix(in srgb, var(--brand) 10%, transparent);
  --l3-mention-bg:  color-mix(in srgb, var(--amber) 10%, var(--panel));
  --l3-sys-bg:      color-mix(in srgb, var(--brand) 8%, var(--panel-2));

  --l3-code-bg:     color-mix(in srgb, black 38%, var(--panel));
  --l3-code-fg:     color-mix(in srgb, white 74%, var(--brand));
  --l3-code-line:   color-mix(in srgb, white 10%, transparent);

  --l3-tag-bg:      color-mix(in srgb, var(--brand) 20%, var(--panel));
  --l3-tag-fg:      color-mix(in srgb, var(--brand) 55%, white);
  --l3-tag-line:    color-mix(in srgb, var(--brand) 42%, transparent);
  --l3-tagme-bg:    color-mix(in srgb, var(--amber) 18%, var(--panel));
  --l3-tagme-fg:    color-mix(in srgb, var(--amber) 72%, white);
  --l3-tagme-line:  color-mix(in srgb, var(--amber) 55%, transparent);
  --l3-quote-bg:    color-mix(in srgb, var(--brand) 8%, var(--panel-2));
  --l3-info-bg:     var(--panel-2);
  --l3-info-head:   color-mix(in srgb, var(--brand) 16%, var(--panel-2));
  --l3-task-bg:     color-mix(in srgb, var(--amber) 12%, var(--panel));
  --l3-task-line:   color-mix(in srgb, var(--amber) 32%, transparent);
  --l3-taskdone-bg: color-mix(in srgb, var(--brand) 11%, var(--panel));
  --l3-taskdone-line: color-mix(in srgb, var(--brand) 28%, transparent);

  --l3-chip-bg:     var(--panel-2);
  --l3-chip-line:   var(--line-strong);
  --l3-chipmine-bg: color-mix(in srgb, var(--brand) 20%, var(--panel));
  --l3-chipmine-line: var(--brand);
  --l3-chipmine-fg: color-mix(in srgb, var(--brand) 50%, white);

  --l3-danger-ink:  var(--red);
  --l3-link:        color-mix(in srgb, var(--brand) 82%, white);

  --l3-field-bg:    color-mix(in srgb, black 24%, var(--panel));
  --l3-field-focus-bg: var(--panel-2);
}

/* 明示的にライト固定（OS がダークでもライトを保つ） */
html[data-theme="light"] { color-scheme: light; }


/* ============================================================
   02. リセット / ベース要素
   ============================================================ */
* { box-sizing: border-box; margin: 0; padding: 0; }

html, body { height: 100%; }

html {
  scrollbar-color: var(--scroll-thumb) transparent;
  scrollbar-width: thin;
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--font-ja);
  color: var(--txt);
  background: var(--bg);
  overflow: hidden;
  line-height: var(--lh);
  letter-spacing: .01em;
  /* 日本語の約物詰め（palt）と字形の安定化。外部フォントは使わない */
  font-feature-settings: "palt" 1;
  font-kerning: normal;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease);
}

/* 等幅が要る場所は palt を切る */
:where(code, pre, kbd, samp) { font-feature-settings: normal; font-family: var(--font-mono); }

/* 見出しは本文サイズを継承（アプリ UI なのでブラウザ既定を殺す） */
:where(h1, h2, h3, h4, h5, h6) { font-size: inherit; font-weight: 700; line-height: var(--lh-tight); }

:where(ul, ol) { list-style: none; }
:where(img, svg, video, canvas) { max-width: 100%; }
:where(svg) { display: block; flex-shrink: 0; }
:where(hr) { border: none; border-top: 1px solid var(--line); }

.hidden { display: none !important; }

a {
  color: var(--brand-ink);
  text-decoration: none;
  text-underline-offset: 2px;
  transition: color var(--dur-fast) var(--ease);
}
a:hover { color: var(--brand-hover); text-decoration: underline; }

::selection { background: var(--brand-weak); color: var(--on-brand-weak); }

/* --- フォーム要素 --- */
button {
  font-family: inherit; cursor: pointer; border: none; background: none; color: inherit;
  font-size: inherit;
  line-height: var(--lh-tight);
  -webkit-tap-highlight-color: transparent;
}
button:disabled { cursor: default; }

input, textarea, select { font-family: inherit; font-size: calc(14px * var(--ui-scale)); color: var(--txt); }

/* 入力欄の既定の面と縁。:where() で詳細度 0 なので各コンポーネントが自由に上書きできる。
   app.js がインラインで生成する textarea もこれで最低限の見た目になる。 */
:where(input:not([type=checkbox]):not([type=radio]):not([type=file]):not([type=range])),
:where(textarea),
:where(select) {
  background-color: var(--field);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  line-height: var(--lh);
}
::placeholder { color: var(--txt-faint); opacity: 1; }

:where(input[type=checkbox], input[type=radio]) {
  accent-color: var(--brand-ink);
  cursor: pointer;
}

/* --- 共通トランジション ---
   :where() で詳細度 0。各コンポーネントが個別に書いた transition が常に勝つので、
   これは「取りこぼしの穴埋め」として働く。 */
:where(a, button, summary, [tabindex], input[type="checkbox"], input[type="radio"]) {
  transition:
    background-color var(--dur-fast) var(--ease),
    color            var(--dur-fast) var(--ease),
    border-color     var(--dur-fast) var(--ease),
    box-shadow       var(--dur-fast) var(--ease),
    outline-color    var(--dur-fast) var(--ease),
    opacity          var(--dur-fast) var(--ease),
    transform        var(--dur-fast) var(--ease);
}
:where(input, textarea, select) {
  transition:
    background-color var(--dur-fast) var(--ease),
    border-color     var(--dur-fast) var(--ease),
    box-shadow       var(--dur-fast) var(--ease),
    outline-color    var(--dur-fast) var(--ease);
}
/* 行・カード・チップ類（クリックできる「面」） */
:where(.chat-item, .msg, .react-chip, .file-row, .member-row, .pick-row,
       .search-result, .file-chip, .task-card, .todo-row, .color-dots span,
       .avatar, .room-icon, .msg-actions button, .load-more button) {
  transition:
    background-color var(--dur-fast) var(--ease),
    color            var(--dur-fast) var(--ease),
    border-color     var(--dur-fast) var(--ease),
    box-shadow       var(--dur-fast) var(--ease),
    opacity          var(--dur-fast) var(--ease),
    transform        var(--dur-fast) var(--ease);
}


/* ============================================================
   03. ボタン
   押した瞬間に 1px 沈む。影は「浮いている量」を表す。
   ============================================================ */
.btn-primary,
.btn-ghost,
.btn-danger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-size: var(--fs-md);
  font-weight: 600;
  line-height: var(--lh-tight);
  white-space: nowrap;
  user-select: none;
}

/* --- 主操作 --- */
.btn-primary {
  background: var(--brand);
  color: var(--on-brand);            /* ライト 5.02:1 / ダーク 7.46:1 */
  padding: 9px 18px;
  box-shadow: var(--shadow-1);
}
.btn-primary:hover { background: var(--brand-hover); }
.btn-primary:active {
  background: var(--brand-active);
  transform: translateY(1px);
  box-shadow: var(--shadow-press);
}
.btn-primary:disabled {
  background: var(--btn-disabled-bg);
  color: var(--btn-disabled-txt);
  cursor: default;
  box-shadow: none;
  transform: none;
}

/* --- 副操作（枠線） --- */
.btn-ghost {
  border: 1px solid var(--line-strong);
  padding: 8px 14px;
  background: var(--panel);
  color: var(--txt);
}
.btn-ghost:hover {
  background: var(--brand-tint);
  border-color: var(--brand);
  color: var(--on-brand-weak);
}
.btn-ghost:active { background: var(--brand-weak); transform: translateY(1px); }
.btn-ghost:disabled {
  background: var(--panel);
  border-color: var(--line);
  color: var(--btn-disabled-txt);
  cursor: default;
  transform: none;
}

/* --- 小サイズ（.btn-primary / .btn-ghost / .btn-danger と併用） --- */
.btn-sm { padding: 5px 12px; font-size: var(--fs-sm); border-radius: var(--radius-sm); }

/* --- 破壊的操作 --- */
.btn-danger {
  background: var(--red);
  color: var(--on-accent);
  padding: 8px 14px;
  box-shadow: var(--shadow-1);
}
.btn-danger:hover { filter: brightness(1.07); }
.btn-danger:active { transform: translateY(1px); box-shadow: var(--shadow-press); filter: none; }
.btn-danger:disabled {
  background: var(--btn-disabled-bg);
  color: var(--btn-disabled-txt);
  cursor: default;
  box-shadow: none;
  transform: none;
  filter: none;
}


/* ============================================================
   04. スクロールバー
   ここで全域確定。個別コンポーネントでは再定義しない
   （例外: .box-code は暗い面なので専用配色を持つ）。
   ============================================================ */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--scroll-thumb);
  border-radius: var(--radius-pill);
  border: 2px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover {
  background: var(--scroll-thumb-hover);
  border: 2px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-corner { background: transparent; }


/* ============================================================
   05. 認証画面
   グラデーションは --auth-grad-1/2/3 が明暗で切り替わるので
   ダーク用の上書きは不要。
   ============================================================ */
.auth {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  background-color: var(--auth-grad-2);
  background-image:
    radial-gradient(1100px 620px at 12% -10%, color-mix(in srgb, var(--brand) 14%, transparent) 0%, transparent 62%),
    radial-gradient(900px 560px at 92% 108%, color-mix(in srgb, var(--brand-strong) 16%, transparent) 0%, transparent 60%),
    linear-gradient(158deg, var(--auth-grad-1) 0%, var(--auth-grad-2) 58%, var(--auth-grad-3) 100%);
}

.auth-card {
  width: 380px;
  max-width: 100%;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-3);
  padding: var(--space-6) calc(var(--space-5) + var(--space-1));
  animation: eco-modal-in var(--dur-slow) var(--ease-out) both;
}

.auth-logo {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  justify-content: center;
}
.auth-logo svg { flex-shrink: 0; }
.auth-logo h1 {
  font-size: calc(26px * var(--ui-scale));
  line-height: 1.15;
  color: var(--brand-ink);
  letter-spacing: .04em;
  font-weight: 700;
}

.auth-sub {
  text-align: center;
  color: var(--txt-sub);
  margin: var(--space-2) 0 var(--space-5);
  font-size: var(--fs-sm);
  line-height: 1.6;
}

.auth-card label {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--txt-sub);
  letter-spacing: .02em;
  margin: var(--space-3) 0 var(--space-1);
}

.auth-card input {
  width: 100%;
  padding: 11px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--bg-sunken);
  color: var(--txt);
}
.auth-card input::placeholder { color: var(--txt-faint); }
.auth-card input:hover { border-color: var(--line-strong); }
.auth-card input:focus,
.auth-card input:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
  border-color: transparent;
  background: var(--panel);
}

.auth-card .btn-primary {
  width: 100%;
  margin-top: var(--space-5);
  padding: 12px;
}

.auth-switch {
  text-align: center;
  margin-top: var(--space-4);
  font-size: var(--fs-sm);
  color: var(--txt-sub);
}
.auth-switch a {
  color: var(--brand-ink);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--brand) 45%, transparent);
  padding-bottom: 1px;
}
.auth-switch a:hover { border-bottom-color: var(--brand); }

.auth-error {
  background: var(--danger-bg);
  border: 1px solid var(--danger-line);
  color: var(--danger-txt);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  font-size: var(--fs-sm);
  line-height: 1.55;
  margin-bottom: var(--space-1);
}

/* ---------------- サーバー停止時の案内 ----------------
   Service Worker がキャッシュを返すため、サーバーが止まっていても
   ページ自体は開いてしまう。何も出さないと真っ白な画面になり、
   利用者には「壊れた」としか見えないので必ず理由と直し方を出す。
   背景は .auth と揃えて、別のアプリに見えないようにする。 */
.server-down {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  overflow-y: auto;
  background-color: var(--auth-grad-2);
  background-image:
    radial-gradient(1100px 620px at 12% -10%, color-mix(in srgb, var(--brand) 14%, transparent) 0%, transparent 62%),
    radial-gradient(900px 560px at 92% 108%, color-mix(in srgb, var(--brand-strong) 16%, transparent) 0%, transparent 60%),
    linear-gradient(158deg, var(--auth-grad-1) 0%, var(--auth-grad-2) 58%, var(--auth-grad-3) 100%);
}

.sd-card {
  width: 100%;
  max-width: 460px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-3);
  padding: var(--space-6) calc(var(--space-5) + var(--space-1));
  text-align: center;
  animation: eco-modal-in var(--dur-slow) var(--ease-out) both;
}

.sd-icon { font-size: calc(44px * var(--ui-scale)); line-height: 1; }
.sd-card h1 {
  font-size: calc(20px * var(--ui-scale));
  color: var(--brand-ink);
  margin: var(--space-3) 0 10px;
  font-weight: 700;
}
.sd-lead {
  font-size: var(--fs-sm);
  color: var(--txt-sub);
  line-height: 1.8;
  margin-bottom: var(--space-5);
}

/* 手順は「読むもの」なので左寄せ。
   全体リセットの :where(ul, ol) { list-style: none } で番号が消えるため、
   ここだけ番号を戻す (「上から順に」の案内が意味を成さなくなる) */
.sd-steps {
  text-align: left;
  background: var(--brand-tint);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 14px 16px 14px 34px;
  margin-bottom: var(--space-4);
  list-style: decimal;
}
.sd-steps li { font-size: var(--fs-sm); line-height: 1.9; color: var(--txt); }
.sd-steps b { color: var(--brand-ink); font-weight: 700; }

.sd-note {
  font-size: var(--fs-sm);
  color: var(--warn-txt);
  background: var(--warn-bg);
  border: 1px solid var(--warn-line);
  border-radius: var(--radius-sm);
  padding: 9px 12px;
  margin-bottom: var(--space-5);
  line-height: 1.7;
}
.server-down .btn-primary { width: 100%; padding: 12px; font-size: var(--fs-md); }
.sd-sub { font-size: var(--fs-xs); color: var(--txt-sub); margin-top: var(--space-3); }


/* ============================================================
   06. レイアウト骨格
   ============================================================ */
/* 上のバーを画面の横いっぱいに置くため、.app は縦積みにして
   「上のバー」+「3カラム(.app-body)」の2段にしている。
   3カラム側の並び方はこれまでと同じなので、下の指定はすべてそのまま効く。 */
.app {
  display: flex;
  flex-direction: column;
  height: 100vh;
  background: var(--bg);
}
.app-body {
  flex: 1;
  display: flex;
  min-height: 0;      /* これが無いと中の一覧がスクロールせず画面外へ伸びる */
}

.sidebar {
  width: var(--side-w, 300px);
  min-width: var(--side-w, 300px);
  background: var(--panel);
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.main {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: var(--bg);
}

/* .chat-pane が縦フレックスでないとメッセージ領域がスクロールしなくなる。
   position: relative は #newPill（10 節）の z-index 解決を素直にするため。
   ⚠ .panel は .chat-pane の子孫ではない（.app > .main > .chat-pane / .app > .panel）
     ので、20 節の .panel.force の absolute には影響しない。 */
.chat-pane {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  position: relative;
}

.panel {
  width: 290px;
  min-width: 290px;
  background: var(--panel);
  border-left: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* モバイル専用要素（#btnBack / #btnPanelClose）。760px 以下でだけ現れる。
   JS 側が display を触らないため !important で確実に切り替える。 */
.mobile-only { display: none !important; }


/* ============================================================
   07. サイドバー
   ------------------------------------------------------------
   濃緑ヘッダー（--brand-strong サーフェス）の上の文字・アイコンは
   必ず --on-brand-strong（常に白）を使う。--on-brand はダークで
   暗色に反転する設計なので、ここで使うと約 1.4:1 まで落ちて読めない。
   ============================================================ */
.side-head,
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3) var(--space-2) var(--space-4);
  color: var(--on-brand-strong);
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--green-900) 84%, var(--green-700)) 0%,
      var(--green-900) 100%);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--on-brand-strong) 15%, transparent),
    inset 0 -1px 0 color-mix(in srgb, var(--green-900) 60%, transparent),
    0 1px 0 color-mix(in srgb, var(--green-900) 22%, transparent);
  position: relative;
  z-index: 2;
  flex-shrink: 0;
}

/* ロゴはサイドバーの幅にそろえる。真ん中の検索欄が
   チャット一覧との境目から始まって見えるようにするため。 */
.topbar .brand { width: calc(var(--side-w, 300px) - var(--space-4) - var(--space-3)); flex-shrink: 0; }

/* 上のバーの検索欄。1本で「一覧の絞り込み」と「発言の中身の検索」を兼ねる。 */
.topbar-search {
  /* flex-basis は 0 + min-width:0。auto のままだと中の <input> の既定幅が
     縮まらない下限になり、上のバーが画面からはみ出す(スマホで実際に起きた)。 */
  flex: 1 1 0;
  min-width: 0;
  max-width: 560px;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 10px;
  height: 34px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--on-brand-strong) 16%, transparent);
  border: 1px solid color-mix(in srgb, var(--on-brand-strong) 22%, transparent);
}
.topbar-search:focus-within {
  background: var(--panel);
  border-color: var(--panel);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--on-brand-strong) 35%, transparent);
}
.topbar-search .ts-ico { width: 16px; height: 16px; flex-shrink: 0; fill: currentColor; opacity: .85; }
.topbar-search input {
  flex: 1;
  min-width: 0;
  border: none;
  background: none;
  color: var(--on-brand-strong);
  font-size: var(--fs-sm);
  height: 100%;
}
.topbar-search input::placeholder { color: color-mix(in srgb, var(--on-brand-strong) 78%, transparent); }
.topbar-search input:focus { outline: none; }
/* 入力中は白地になるので、文字色も地に合わせて反転させる */
.topbar-search:focus-within .ts-ico { opacity: 1; }
.topbar-search:focus-within input { color: var(--txt); }
.topbar-search:focus-within input::placeholder { color: var(--txt-faint); }
.ts-clear {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  border: none;
  background: none;
  color: inherit;
  font-size: calc(16px * var(--ui-scale));
  line-height: 1;
  border-radius: 50%;
  cursor: pointer;
  opacity: .8;
}
.ts-clear:hover { background: color-mix(in srgb, currentColor 18%, transparent); opacity: 1; }
.topbar-search:focus-within .ts-clear { color: var(--txt-sub); }

.brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: 700;
  font-size: var(--fs-lg);
  letter-spacing: .04em;
  min-width: 0;
  color: var(--on-brand-strong);
}
.brand svg { flex-shrink: 0; filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .25)); }
.brand span {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .22);
}

.side-actions {
  display: flex;
  gap: 2px;
  align-items: center;
  flex-shrink: 0;
}
.side-actions button {
  position: relative;
  font-size: var(--fs-lg);
  line-height: 1;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: var(--radius-sm);
  color: var(--on-brand-strong);
}
.side-actions button:hover { background: color-mix(in srgb, var(--on-brand-strong) 16%, transparent); }
.side-actions button:active { transform: scale(.93); }

/* 小バッジ: 小さくても必ず読めるサイズを維持し、濃緑ヘッダー上で
   輪郭が消えないようノッチリング（box-shadow）を付ける。 */
.mini-badge {
  position: absolute;
  top: -2px;
  right: -2px;
  background: var(--red);
  color: var(--on-accent);
  font-size: calc(11px * var(--ui-scale));
  line-height: 18px;
  min-width: 18px;
  height: 18px;
  border-radius: var(--radius-pill);
  text-align: center;
  padding: 0 4px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  box-shadow: 0 0 0 2px var(--green-900);
  pointer-events: none;
}

.side-search {
  display: flex;
  gap: var(--space-2);
  padding: var(--space-3);
  border-bottom: 1px solid var(--line);
  flex-shrink: 0;
}
.side-search input {
  flex: 1;
  min-width: 0;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--bg-sunken);
  color: var(--txt);
}
.side-search input::placeholder { color: var(--txt-faint); }
.side-search input:hover { border-color: var(--line-strong); }
.side-search input:focus,
.side-search input:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
  border-color: transparent;
  background: var(--panel);
}
.side-search button {
  width: 36px;
  min-width: 36px;
  border-radius: var(--radius-sm);
  background: var(--brand-strong);
  color: var(--on-brand-strong);
  font-size: calc(18px * var(--ui-scale));
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.side-search button:hover { background: var(--brand); color: var(--on-brand); }
.side-search button:active { transform: scale(.95); }

/* 絞り込みタブ。5 つ（すべて/未読/To/ダイレクト/タスクあり）あるので
   幅 300px のサイドバーでは 2 段に折り返る。これは意図した挙動で、
   横スクロールに逃がすとタブが画面外に隠れて気づけなくなるため折返しを選んでいる。
   （モバイルは全幅になるので 1 段に収まる） */
/* 絞り込みタブ + 「＋ 新しいチャット」を1行に置く。
   検索欄が上のバーへ移ったので、その行の代わりになる。 */
.side-tabs-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3) var(--space-1);
  border-bottom: 1px solid var(--line);
  flex-shrink: 0;
}
.side-tabs-row > #btnNewChat {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-lg);
  line-height: 1;
  border-radius: var(--radius-sm);
  background: var(--brand);
  color: var(--on-brand-strong);
  font-weight: 700;
}
.side-tabs-row > #btnNewChat:hover { background: var(--brand-hover); }
.side-tabs-row > #btnNewChat:active { transform: scale(.93); }

.side-tabs {
  display: flex;
  gap: var(--space-1);
  padding: 0;
  flex: 1;
  min-width: 0;
  flex-wrap: wrap;
  flex-shrink: 1;
}
.side-tabs button {
  font-size: var(--fs-xs);
  line-height: 1;
  padding: 6px 10px;
  border-radius: var(--radius-pill);
  color: var(--txt-sub);
  font-weight: 600;
  border: 1px solid transparent;
}
.side-tabs button:hover { background: var(--bg-sunken); color: var(--txt); }
.side-tabs button:active { transform: scale(.93); }
/* 選択中。app.js 463行が class="on" と aria-selected を必ず同時に更新するので
   属性側も併記する（JS が片方だけ更新した場合の保険）。 */
.side-tabs button.on,
.side-tabs button[aria-selected="true"] {
  background: var(--brand-tint);
  border-color: color-mix(in srgb, var(--brand) 28%, transparent);
  color: var(--brand-ink);
  font-weight: 700;
}

/* --- チャット一覧 --- */
.chat-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-gutter: stable;
  padding: var(--space-2) var(--space-2) var(--space-6);
}

.chat-item {
  display: flex;
  /* 名前 / 旗 / 時刻 / バッジが 300px の一覧に同居するので隙間は詰める */
  gap: var(--space-2);
  padding: 10px 10px 10px 12px;
  border-radius: var(--radius);
  cursor: pointer;
  align-items: center;
  position: relative;
}
/* 未読アクセントバーの土台（既定は高さ 0 = 非表示） */
.chat-item::before {
  content: "";
  position: absolute;
  left: 3px;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 0;
  border-radius: var(--radius-pill);
  background: var(--brand);
  transition: height var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.chat-item:hover { background: var(--bg-sunken); }
.chat-item:active { transform: scale(.994); }
/* 選択中。app.js 523行が class="on" と aria-selected を同時に出力する。 */
.chat-item.on,
.chat-item[aria-selected="true"] { background: var(--brand-tint); }
.chat-item.on::before,
.chat-item[aria-selected="true"]::before { height: 60%; background: var(--brand-ink); }

.chat-item .ci-txt { flex: 1; min-width: 0; }

.ci-top {
  display: flex;
  align-items: baseline;
  gap: 5px;
  min-width: 0;
  overflow: hidden;   /* 縮むのは名前だけ（旗と時刻は原寸のまま） */
}
.ci-name {
  font-weight: 600;
  font-size: var(--fs-md);
  line-height: 1.35;
  color: var(--txt);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1 1 auto;
  /* 旗+時刻に押されて 1〜2 文字まで潰れるのを防ぐ下限。
     ただし下限を上げすぎると行があふれて「時刻」が切れるので、
     旗 3 個 + To + 未読バッジが全部乗る最悪ケースが収まる値にしてある。 */
  min-width: 3.4em;
}
/* 📌🔕📞 の状態旗。絵文字は途中で切れると「壊れた四角」に見えるので、
   縮ませずに必ず丸ごと描く（幅が足りないときは名前側が「…」で詰まる＝
   意図した省略に見える）。旗が 0 個のときは gap ごと消す。 */
.ci-flags {
  font-size: calc(10px * var(--ui-scale));
  line-height: 1;
  flex: 0 0 auto;
  letter-spacing: -1px;
  opacity: .85;
}
.ci-flags:empty { display: none; }
.ci-time {
  font-size: var(--fs-xs);
  color: var(--txt-faint);
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}
.ci-last {
  font-size: var(--fs-sm);
  color: var(--txt-sub);
  line-height: 1.45;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-top: 2px;
}

/* 未読の可視化: JS が未読クラスを付けないので :has() でバッジの有無から判定する。
   ⚠ .badge.muted（通知ミュート中チャットの未読 / app.js 534行）はここから除外する。
     renderBadges() でも総未読から外される「見なくてよい未読」なので、
     行まで強調すると .badge.muted を淡くした意味が消える。
     .badge.mention には .muted が付かないので、To 付きの行は従来どおり強調される。
   :has() 非対応環境ではバッジだけで判別できるフォールバック挙動になる。 */
.chat-item:has(.badge:not(.task):not(.muted))::before { height: 62%; }
.chat-item:has(.badge:not(.task):not(.muted)) .ci-name { font-weight: 700; color: var(--txt); }
.chat-item:has(.badge:not(.task):not(.muted)) .ci-last { color: var(--txt); font-weight: 500; }
.chat-item:has(.badge:not(.task):not(.muted)) .ci-time { color: var(--brand-ink); font-weight: 700; }
.chat-item:has(.badge.mention)::before { background: var(--red); }
.chat-item:has(.badge.mention) .ci-time { color: var(--red); }
/* メッセージがまだ 1 件も無い行（app.js 519行 <span class="ci-none">）。
   親の .ci-last が既に --txt-sub なので、一段落として斜体で
   「実データではない」ことを示す。
   ⚠ 上の .chat-item:has(.badge:not(.task)) .ci-last は【.ci-last 要素そのもの】に
     効くので、子を直接指すこちらとは詳細度勝負にならず必ず勝つ。
     継承してくる font-weight だけ 400 に戻しておく。 */
.chat-item .ci-last .ci-none {
  color: var(--txt-faint);
  font-style: italic;
  font-weight: 400;
}


/* バッジ: 最小可読サイズを死守する */
.badge {
  background: var(--brand-strong);
  color: var(--on-brand-strong);
  border-radius: var(--radius-pill);
  font-size: calc(11px * var(--ui-scale));
  min-width: 20px;
  height: 20px;
  line-height: 20px;
  text-align: center;
  padding: 0 6px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
  align-self: center;
  letter-spacing: .01em;
  box-shadow: 0 1px 2px color-mix(in srgb, var(--green-900) 22%, transparent);
}
.badge.mention { background: var(--red); color: var(--on-accent); }
/* 琥珀のベタ塗りは白文字が読めないので、淡い面 + 内側リング + 濃色文字にする */
.badge.task {
  background: color-mix(in srgb, var(--amber) 16%, var(--panel));
  color: color-mix(in srgb, var(--amber) 72%, var(--txt));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--amber) 45%, transparent);
  font-weight: 700;
}
/* 通知ミュート中チャットの未読（app.js 534行）。renderBadges() でも総未読から
   除外される「見なくてよい未読」なので、ブランド濃緑のベタ塗りをやめて
   沈んだ面 + 枠線だけにする。数は読めるが視線は奪わない。 */
.badge.muted {
  background: var(--bg-sunken);
  color: var(--txt-sub);      /* --bg-sunken 上 5.15:1 / ダーク 8.73:1 */
  box-shadow: inset 0 0 0 1px var(--line-strong);
  font-weight: 600;
}

/* --- アバター / ルームアイコン ---
   background は app.js のインライン style で入るため絶対に上書きしない。
   内側リング + 文字影で、どんな地色でも頭文字が読めるようにする。 */
.avatar {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--on-brand-strong);
  font-weight: 700;
  font-size: calc(15px * var(--ui-scale));
  line-height: 1;
  flex-shrink: 0;
  position: relative;
  user-select: none;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .38);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, .24),
    inset 0 -8px 14px rgba(0, 0, 0, .10),
    0 0 0 1px color-mix(in srgb, var(--txt) 8%, transparent);
}
.avatar-s { width: 26px; height: 26px; font-size: calc(11px * var(--ui-scale)); }
.avatar-l {
  width: 64px;
  height: 64px;
  font-size: calc(26px * var(--ui-scale));
  box-shadow:
    inset 0 0 0 1.5px rgba(255, 255, 255, .24),
    inset 0 -14px 24px rgba(0, 0, 0, .12),
    0 2px 8px color-mix(in srgb, var(--green-900) 20%, transparent);
}

.avatar .dot {
  position: absolute;
  bottom: -1px;
  right: -1px;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--offline);
  border: 2px solid var(--panel);
  box-shadow: none;
  transition: background-color var(--dur) var(--ease);
}
.avatar .dot.on { background: var(--online); }
.avatar-s .dot { width: 9px; height: 9px; border-width: 1.5px; }
.avatar-l .dot { width: 16px; height: 16px; border-width: 3px; }

.room-icon {
  width: 38px;
  height: 38px;
  border-radius: var(--radius);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--on-brand-strong);
  font-weight: 700;
  font-size: var(--fs-lg);
  line-height: 1;
  flex-shrink: 0;
  user-select: none;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .38);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, .24),
    inset 0 -8px 14px rgba(0, 0, 0, .10),
    0 0 0 1px color-mix(in srgb, var(--txt) 8%, transparent);
}


/* ============================================================
   08. チャットヘッダー / 空状態 / 空表示
   ============================================================ */
.chat-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  min-height: 56px;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  flex-shrink: 0;
  position: relative;
  z-index: 1;
}

.chat-head-txt { flex: 1; min-width: 0; }
/* index.html 93行で <div> → <h1> になった。ブラウザ既定の font-size:2em /
   margin:.67em は 02 節（* リセット / :where(h1..h6){font-size:inherit}）で
   既に潰れているが、02 節が将来削られても崩れないよう念押しする。
   ⚠ 詳細度は (0,1,0) のまま保つこと。.chat-head-txt h1.chat-head-name のように
     強めると 20 節（≤760px）の font-size 縮小に勝ってしまう。 */
.chat-head-name {
  margin: 0;
  padding: 0;
  font-weight: 700;
  font-size: var(--fs-lg);
  line-height: 1.3;
  color: var(--txt);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.chat-head-sub {
  font-size: var(--fs-xs);
  color: var(--txt-sub);
  line-height: 1.4;
  margin-top: 1px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.chat-head-actions {
  display: flex;
  gap: 2px;
  flex-shrink: 0;
}
.chat-head-actions button {
  font-size: var(--fs-lg);
  line-height: 1;
  width: 34px;
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: var(--radius-sm);
  color: var(--txt-sub);
}
.chat-head-actions button:hover { background: var(--bg-sunken); color: var(--txt); }
.chat-head-actions button:active { transform: scale(.93); }
/* ピン留め中 / ミュート中。app.js 660-663行が .on と aria-pressed を同時に更新する。
   ⚠ 通話コントロール（15 節）の aria-pressed は意味が反転するものがあるため、
     同じ書き方をそちらへ持ち込まないこと。 */
.chat-head-actions button.on,
.chat-head-actions button[aria-pressed="true"] {
  color: var(--brand-ink);
  background: var(--brand-tint);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--brand) 26%, transparent);
}

.call-bar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  background: var(--brand-tint);
  border-bottom: 1px solid color-mix(in srgb, var(--brand) 24%, var(--line));
  box-shadow: inset 3px 0 0 var(--brand);
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--brand-ink);
  flex-shrink: 0;
  animation: eco-slide-down var(--dur) var(--ease) both;
}
.call-bar span { flex: 1; min-width: 0; }

.empty-state {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  color: var(--txt-sub);
  padding: var(--space-6);
  text-align: center;
  background:
    radial-gradient(720px 420px at 50% 42%, color-mix(in srgb, var(--brand) 6%, transparent) 0%, transparent 70%);
}
.empty-state p {
  font-size: var(--fs-md);
  line-height: 1.7;
  letter-spacing: .02em;
}

/* --- 空表示 / 読み込み中 / 読み込み失敗（.list-empty） ---
   出現箇所は 7 つあり、置かれる面は 3 種類。
     #chatList  (--panel / 幅 300px)   #msgList (--bg / 広い)   #panelBody (--panel / 幅 290px)
   どこに置いても成立する「中央寄せブロック」として組む。
   子は <p> が常に1個、<span> が 0〜1個、<button> が 0〜1個。
   ⚠ .err / .sm は単独では出現しない。必ず .list-empty との複合で書く。 */
.list-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-6) var(--space-4);
  text-align: center;
  color: var(--txt-sub);
}
.list-empty p {
  font-size: var(--fs-md);
  font-weight: 700;
  line-height: 1.6;
  color: var(--txt);
}
.list-empty span {
  max-width: 30em;
  font-size: var(--fs-sm);
  line-height: 1.7;
  color: var(--txt-faint);    /* --panel 上 5.26:1 / --bg 上 4.82:1 / ダーク 5.53:1 */
}
/* 導線ボタン（.btn-primary.btn-sm / .btn-ghost.btn-sm）は 03 節に任せ、
   文章とのあいだだけ空ける。ボタンが無いケースで下が空きすぎない。 */
.list-empty button { margin-top: var(--space-2); }

/* メッセージ領域だけは面積があるので、上端に貼り付かせず視野の中央に置く */
#msgList > .list-empty { min-height: min(48vh, 320px); }

/* 通信失敗。app.js 1290行のコメント「通信失敗を『0件』と同じ見た目にしない」に対応。
   色（--danger-*）だけでなく【丸い警告アイコン】という形でも区別する。 */
.list-empty.err::before {
  content: "⚠";
  flex: 0 0 auto;              /* 縦フレックスの中で潰れないように */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-pill);
  background: var(--danger-bg);
  color: var(--danger-txt);
  box-shadow: inset 0 0 0 1px var(--danger-line);
  font-size: calc(18px * var(--ui-scale));
  line-height: 1;
}
.list-empty.err p {
  color: var(--danger-txt);   /* --panel 上 7.53:1 / --bg 上 6.90:1 / ダーク 8.37:1 */
}

/* 右パネル内の控えめ版（幅 290px。余白を詰める） */
.list-empty.sm {
  padding: var(--space-4) var(--space-2);
  gap: var(--space-1);
}
.list-empty.sm p {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--txt-sub);      /* 6.06:1 / ダーク 7.51:1 */
}


/* ============================================================
   09. 固定メッセージ（ピン留め）バー
   ------------------------------------------------------------
   #pinBar は .chat-pane の縦フレックスアイテム（.chat-head の直後 /
   #callBar の直前）。「流れて消えない大事な連絡」＝付箋の質感を出すため、
   --warn-* 系（琥珀）の面を使う。本文領域（--bg）と明確に分離しつつ、
   メッセージ本体の視線を奪わないよう文字は 12.5px に留める。
   ============================================================ */
.pin-bar {
  /* 縦フレックスの中で潰れないように必ず明示する */
  flex: 0 0 auto;
  max-height: 132px;          /* 3行ぶん。件数が増えても高さが暴れない */
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-gutter: stable;
  padding: var(--space-1) var(--space-2) var(--space-1) var(--space-3);
  background: var(--warn-bg);
  border-bottom: 1px solid var(--warn-line);
  /* 「上に貼り付いている」感。本文側へごく薄く落とす */
  box-shadow: var(--shadow-1);
  position: relative;
  z-index: 1;
}

.pin-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 30px;
  padding: 3px var(--space-1) 3px 2px;
  border-radius: var(--radius-xs);
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--warn-txt);            /* --warn-bg 上で 7.15:1 / ダーク 9.49:1 */
  cursor: pointer;
  /* .pin-row は 02 節の :where(...) 面用トランジション対象外なので明示する */
  transition:
    background-color var(--dur-fast) var(--ease),
    color            var(--dur-fast) var(--ease);
}
.pin-row:hover {
  background: color-mix(in srgb, var(--amber) 16%, var(--warn-bg));  /* 上の文字 5.79:1 / ダーク 6.92:1 */
}

.pin-ico {
  flex: 0 0 auto;
  width: 1.25em;
  text-align: center;
  font-size: var(--fs-sm);
  line-height: 1;
}

.pin-txt {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;       /* 1行省略が要件（本文はジャンプ先で読む） */
  font-weight: 500;
}

/* 投稿者名。色でなく「サイズ + 太さ + 中黒」で階層を作る。
   color-mix 非対応環境では宣言が落ちて .pin-row の --warn-txt を継ぐ（安全側）。 */
.pin-who {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 8em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--fs-xs);
  font-weight: 400;
  color: color-mix(in srgb, var(--warn-txt) 85%, var(--warn-bg));  /* 4.95:1 / ダーク 7.24:1 */
}
.pin-who::before {
  content: "・";
  margin-right: 1px;
}

/* 固定解除。行クリック（ジャンプ）と独立した操作なので面で分離する。
   .chat-head-actions button 等の共通指定は当たらないため単独で組む。 */
.pin-off {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border-radius: var(--radius-xs);
  font-size: var(--fs-lg);
  line-height: 1;
  color: var(--warn-txt);
}
.pin-off:hover {
  background: color-mix(in srgb, var(--amber) 26%, var(--warn-bg));  /* 上の文字 5.03:1 / ダーク 5.50:1 */
}
.pin-off:active { transform: scale(.92); }
.pin-off:focus-visible { outline-offset: -2px; }

/* --- ジャンプ先のハイライト ---
   app.js 703-705行:
     el.classList.remove('pin-flash'); void el.offsetWidth; el.classList.add('pin-flash');
   リフローを挟んでアニメーションを再起動する方式。クラスは【外れない】ので
   animation-fill-mode を付けてはいけない（付けると最終フレームが固定され、
   以後 .msg:hover / .msg.mention-me の背景が二度と出なくなる）。
   色だけに頼らないよう、面 + 内側の枠線の 2 つで示す。
   @keyframes eco-pin-flash の実体は 17 節。 */
.msg.pin-flash {
  outline: 2px solid transparent;
  outline-offset: -2px;
  animation: eco-pin-flash 1.6s var(--ease-out);   /* fill-mode は付けない */
}

/* ============================================================
   10. メッセージ領域
   本文は 14px / 行間 1.8 / 行長 46em。サイズを上げるのではなく
   行間・行長・字間で読みやすくし、1画面あたりの情報密度は保つ。
   ============================================================ */
.msg-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* 上パディングは .msg-actions（上方向にせり出す）のクリップ回避も兼ねる */
  padding: var(--space-4) var(--space-5) var(--space-2);
  scroll-padding-block: var(--space-5);
}

.load-more {
  text-align: center;
  margin-bottom: var(--space-3);
}
.load-more button {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--txt-sub);
  background: var(--panel);
  border: 1px solid var(--line);
  padding: 6px 16px;
  border-radius: var(--radius-pill);
}
.load-more button:hover {
  color: var(--txt);
  border-color: var(--line-strong);
  background: var(--panel-2);
}
.load-more button:active { transform: scale(.99); }

/* --- メッセージ行 --- */
.msg {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  /* 左は 12px 固定: .mention-me の 3px アクセントバーが入っても行がずれない */
  padding: 6px 10px 6px 12px;
  border-radius: var(--radius);
  position: relative;
}
/* 出現アニメーションは「末尾の数件」だけに絞る。
   JS はルーム切替時に innerHTML を丸ごと差し替えるので、全 .msg に付けると
   数十件が一斉にアニメートして重くなる。新着は必ず末尾に足されるため、
   末尾 4 件に限定しても「新しく届いた 1 件がふわっと出る」挙動は保たれる。
   過去ログの読み込み（先頭への追加）は静かに入る＝スクロール位置が暴れない。 */
.msg:nth-last-child(-n + 4) {
  animation: eco-msg-in var(--dur-fast) var(--ease) both;
}
.msg + .msg { margin-top: 1px; }
.msg:hover { background: var(--l3-msg-hover); }

/* 自分宛て: 面の色 + 左アクセントバー（色だけに頼らない） */
.msg.mention-me {
  background: var(--l3-mention-bg);
  box-shadow: inset 3px 0 0 var(--l3-mention-bar);
}
.msg.mention-me:hover {
  background: color-mix(in srgb, var(--txt) 5%, var(--l3-mention-bg));
}

/* 自分の発言（将来用フック）: ごく薄いブランドティント */
.msg.mine-bg { background: var(--l3-mine-bg); }
.msg.mine-bg:hover { background: color-mix(in srgb, var(--txt) 5%, var(--l3-mine-bg)); }
.msg.mine-bg.mention-me { background: var(--l3-mention-bg); }

.msg-body {
  flex: 1;
  min-width: 0;
  padding-top: 1px;
}

.msg-meta {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  flex-wrap: wrap;
  line-height: 1.4;
}
.msg-name {
  font-weight: 700;
  font-size: calc(13.5px * var(--ui-scale));
  color: var(--txt);
  letter-spacing: .01em;
}
.msg-name small {
  font-weight: 400;
  font-size: calc(11px * var(--ui-scale));
  color: var(--txt-faint);
  margin-left: 5px;
  letter-spacing: 0;
}
.msg-time {
  font-size: calc(11px * var(--ui-scale));
  color: var(--txt-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* --- 本文: ここが最重要 --- */
.msg-text {
  margin-top: 3px;
  max-width: var(--l3-measure);
  font-size: var(--l3-msg-fs);
  line-height: var(--l3-msg-lh);
  letter-spacing: var(--l3-msg-track);
  color: var(--txt);
  white-space: pre-wrap;
  word-break: break-word;
  overflow-wrap: break-word;
  line-break: strict;
}
.msg-text > :first-child { margin-top: 0; }
.msg-text > :last-child { margin-bottom: 0; }
.msg-text a {
  color: var(--l3-link);
  overflow-wrap: anywhere;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
.msg-text a:hover { text-decoration-thickness: 2px; }

.msg-text img.inline-img {
  max-width: 320px;
  max-height: 240px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  display: block;
  margin-top: var(--space-2);
  cursor: zoom-in;
  background: var(--bg-sunken);
  transition: box-shadow var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.msg-text img.inline-img:hover {
  border-color: var(--line-strong);
  box-shadow: var(--shadow-2);
}

.msg-deleted {
  margin-top: 3px;
  color: var(--txt-faint);
  font-style: normal;
  font-size: var(--fs-sm);
  line-height: 1.7;
  padding: 2px 10px;
  border-left: 2px solid var(--line);
}
.msg-edited {
  font-size: calc(10px * var(--ui-scale));
  /* 10px と最小なので、最下層(--txt-faint)ではなく 1 段上の --txt-sub を使う。
     mention-me の琥珀地の上でも 5.09:1 を確保できる。 */
  color: var(--txt-sub);
  margin-left: 2px;
}

/* --- システムメッセージ --- */
.msg.sys {
  padding: 3px 10px;
  justify-content: center;
}
.msg.sys:hover { background: transparent; }
.sys-inner {
  font-size: var(--fs-xs);
  line-height: 1.7;
  color: var(--txt-sub);
  background: var(--l3-sys-bg);
  border: 1px solid color-mix(in srgb, var(--line) 70%, transparent);
  border-radius: var(--radius-sm);
  padding: 7px 12px;
  width: 100%;
  text-align: center;
  word-break: break-word;
}

/* ------------------------------------------------------------
   09-b. メッセージ内の装飾記法（Ecochat 記法）
   ------------------------------------------------------------ */
/* To / RE タグ */
.tag-to {
  display: inline-block;
  background: var(--l3-tag-bg);
  color: var(--l3-tag-fg);
  box-shadow: inset 0 0 0 1px var(--l3-tag-line);
  border-radius: var(--radius-sm);
  padding: 1px 7px;
  margin-right: 1px;
  font-weight: 700;
  font-size: calc(12px * var(--ui-scale));
  line-height: 1.6;
  letter-spacing: .01em;
  vertical-align: baseline;
  white-space: nowrap;
}
/* 自分宛ては別色 + 枠を強めて「色以外」でも差が出るように */
.tag-to.me {
  background: var(--l3-tagme-bg);
  color: var(--l3-tagme-fg);
  box-shadow: inset 0 0 0 1.5px var(--l3-tagme-line);
}

/* 囲み枠 [info] */
.box-info {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  margin: var(--space-2) 0;
  background: var(--l3-info-bg);
  overflow: hidden;
  max-width: 100%;
}
.box-info-title {
  background: var(--l3-info-head);
  border-bottom: 1px solid color-mix(in srgb, var(--line) 80%, transparent);
  color: var(--txt);
  font-weight: 700;
  padding: 6px 12px;
  font-size: var(--fs-sm);
  letter-spacing: .01em;
}
.box-info-body {
  padding: 9px 12px;
  font-size: var(--fs-md);
  line-height: 1.75;
  color: var(--txt);
}

/* 引用 [qt] */
.box-quote {
  border-left: 3px solid var(--brand);
  background: var(--l3-quote-bg);
  padding: 8px 12px;
  margin: var(--space-2) 0;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  font-size: var(--fs-md);
  line-height: 1.75;
  color: var(--txt-sub);
  max-width: 100%;
}
.box-quote .q-meta {
  font-size: var(--fs-xs);
  /* 引用は面自体が色付き（--l3-quote-bg）なので --txt-faint だと
     ライト 4.16:1 / ダーク 4.34:1 で AA を割る。--txt-sub にする。 */
  color: var(--txt-sub);
  margin-bottom: 4px;
  font-weight: 700;
  letter-spacing: .01em;
}

/* コード [code] */
.box-code {
  background: var(--l3-code-bg);
  color: var(--l3-code-fg);
  border: 1px solid var(--l3-code-line);
  border-radius: var(--radius-sm);
  padding: 11px 13px;
  margin: var(--space-2) 0;
  font-family: var(--l3-mono);
  font-size: calc(12.5px * var(--ui-scale));
  line-height: 1.65;
  letter-spacing: 0;
  overflow-x: auto;
  white-space: pre;
  tab-size: 2;
  -webkit-font-smoothing: antialiased;
}
/* 暗い面なので、この要素だけスクロールバーを専用配色にする */
.box-code::-webkit-scrollbar { height: 8px; }
.box-code::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--l3-code-fg) 26%, transparent);
  border: none;
  border-radius: 4px;
}

/* ---- コード枠の折りたたみ + コピー ----
   長文を貼られるとチャットが埋め尽くされて前の発言まで戻れなくなるため、
   一定行数を超えたら畳んでおく。枠の見た目 (.box-code) は変えず、
   外側の .code-block に余白と操作ボタンだけを足す。 */
.code-block { position: relative; margin: var(--space-2) 0; max-width: 100%; }
/* 余白は外側が持つ。コピーボタンの下に本文が潜らないよう右だけ広げる */
.code-block .box-code { margin: 0; padding-right: 44px; }

/* 畳んだ状態: 先頭だけ見せて、下を薄くぼかす */
.code-block.folded .box-code {
  max-height: 108px; overflow: hidden;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  -webkit-mask-image: linear-gradient(#000 58%, rgba(0, 0, 0, .15));
  mask-image: linear-gradient(#000 58%, rgba(0, 0, 0, .15));
}
/* 開いた状態でも「折りたたむ」ボタンが下に付くので、角は上だけ丸める。
   短くてボタンが付かないものは元どおり四隅を丸めたいので、
   ボタンの有無を :has() で見る (基準行の未読判定と同じ手) */
.code-block:not(.folded):has(.code-toggle) .box-code {
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}

.code-toggle {
  display: block; width: 100%; text-align: center;
  background: color-mix(in srgb, var(--l3-code-bg) 88%, black);
  color: color-mix(in srgb, var(--l3-code-fg) 82%, transparent);
  border: 1px solid var(--l3-code-line);
  border-top: none;
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  padding: 7px 10px;
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .3px;
  transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.code-toggle:hover { background: color-mix(in srgb, var(--l3-code-bg) 74%, black); color: var(--l3-code-fg); }
.code-toggle:focus-visible { outline: 2px solid var(--green-500); outline-offset: -2px; }
.code-caret { font-size: calc(10px * var(--ui-scale)); }

.code-copy {
  position: absolute; top: 6px; right: 6px;
  background: color-mix(in srgb, var(--l3-code-fg) 14%, transparent);
  color: var(--l3-code-fg);
  border-radius: 6px; padding: 3px 9px;
  font-size: var(--fs-xs); font-weight: 700;
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}
.code-block:hover .code-copy, .code-copy:focus-visible { opacity: 1; }
.code-copy:hover { background: color-mix(in srgb, var(--l3-code-fg) 26%, transparent); }
.code-copy.done { background: var(--green-500); color: var(--on-brand-strong); opacity: 1; }
.code-copy.ng { background: var(--red); color: var(--on-brand-strong); opacity: 1; }
/* 指で操作する端末はホバーが無いので、常に出しておく */
@media (hover: none) { .code-copy { opacity: 1; } }

/* 罫線 [hr] */
.tag-hr {
  border: none;
  border-top: 1px solid var(--line);
  margin: var(--space-3) 0;
  max-width: 100%;
}

/* タスク [task] / [done] */
.box-task {
  border: 1px solid var(--l3-task-line);
  border-left: 3px solid var(--amber);
  background: var(--l3-task-bg);
  color: var(--txt);
  border-radius: var(--radius-sm);
  padding: 8px 12px;
  margin: var(--space-1) 0;
  font-size: var(--fs-md);
  line-height: 1.7;
}
.box-task.done {
  border-color: var(--l3-taskdone-line);
  border-left-color: var(--brand);
  background: var(--l3-taskdone-bg);
  color: var(--txt-sub);
}

/* ------------------------------------------------------------
   09-c. リアクション
   ------------------------------------------------------------ */
.msg-reactions {
  display: flex;
  gap: var(--space-1);
  margin-top: var(--space-2);
  flex-wrap: wrap;
}
/* リアクション 0 件のときは余白を作らない（JS は常に空 div を出力する） */
.msg-reactions:empty { display: none; margin: 0; }

.react-chip {
  border: 1px solid var(--l3-chip-line);
  border-radius: var(--radius-pill);
  padding: 2px 9px;
  min-height: 24px;
  font-size: calc(12px * var(--ui-scale));
  font-variant-numeric: tabular-nums;
  color: var(--txt-sub);
  background: var(--l3-chip-bg);
  display: inline-flex;
  gap: 4px;
  align-items: center;
  cursor: pointer;
  user-select: none;
  line-height: 1.5;
}
.react-chip:hover {
  border-color: var(--brand);
  background: var(--brand-tint);
  color: var(--txt);
  box-shadow: var(--shadow-1);
  transform: translateY(-1px);
}
.react-chip:active { transform: scale(.94); box-shadow: none; }

/* 選択済み: 塗り + 枠 + 内側リング + 太字の 4 点で判別できるようにする */
.react-chip.mine {
  border-color: var(--l3-chipmine-line);
  background: var(--l3-chipmine-bg);
  color: var(--l3-chipmine-fg);
  font-weight: 700;
  box-shadow: inset 0 0 0 1px var(--l3-chipmine-line);
}
.react-chip.mine:hover {
  background: color-mix(in srgb, var(--brand) 22%, var(--panel));
  color: var(--l3-chipmine-fg);
}

/* ------------------------------------------------------------
   09-d. ホバーアクション（メッセージ操作ツールバー）
   ------------------------------------------------------------ */
.msg-actions {
  position: absolute;
  top: -13px;
  right: var(--space-3);
  /* 左右にはみ出さない */
  max-width: calc(100% - var(--space-5));
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  display: none;
  overflow: hidden;
  white-space: nowrap;
  box-shadow: var(--shadow-2);
  z-index: 5;
}
/* .msg-actions は .msg の子孫なので、ツールバー上にポインタがあっても
   .msg:hover は維持される = 表示のちらつきは起きない */
.msg:hover .msg-actions,
.msg:focus-within .msg-actions,
.msg.tapped .msg-actions {
  display: flex;
  transform-origin: top right;
  animation: eco-pop-in var(--dur-fast) var(--ease-out) both;
}

.msg-actions button {
  padding: 6px 9px;
  font-size: var(--fs-sm);
  line-height: 1.2;
  color: var(--txt-sub);
  border-radius: 0;
}
.msg-actions button + button {
  border-left: 1px solid color-mix(in srgb, var(--line) 70%, transparent);
}
.msg-actions button:hover {
  background: var(--brand-tint);
  color: var(--txt);
}
.msg-actions button:active {
  background: color-mix(in srgb, var(--brand) 18%, var(--panel));
  transform: scale(.93);
}

/* ------------------------------------------------------------
   09-e. 日付セパレータ / 未読ライン / 入力中
   ------------------------------------------------------------ */
.date-sep {
  text-align: center;
  margin: var(--space-4) 0 var(--space-2);
  /* スクロールしても「いつの会話か」を見失わない */
  position: sticky;
  top: 0;
  z-index: 2;
  pointer-events: none;
}
.date-sep span {
  display: inline-block;
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--txt-sub);
  background: var(--panel);
  border: 1px solid var(--line);
  padding: 3px 13px;
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-1);
}

.unread-sep {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--l3-danger-ink);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: .04em;
  margin: var(--space-3) 0 var(--space-2);
}
.unread-sep::before,
.unread-sep::after {
  content: "";
  flex: 1;
  /* 色だけでなく線の太さでも差をつける */
  border-top: 1.5px solid var(--red);
  opacity: .55;
}


/* ------------------------------------------------------------
   アンケート / 出欠確認カード（.poll-card）
   挿入先は #msgList .msg .msg-body .msg-text（app.js 818-820行）。
   .msg-text の white-space: pre-wrap が継承すると、app.js のテンプレート内の
   改行 + インデントが【可視の空行】になるため .poll-card で normal に戻す。
   （.msg-text 側の pre-wrap は本文の改行保持に必須なので絶対に外さない。）
   ------------------------------------------------------------ */
.poll-card {
  white-space: normal;        /* ← 必須 */
  max-width: min(480px, 100%);
  margin-top: var(--space-1);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel);
  box-shadow: var(--shadow-1);
  font-size: var(--fs-md);
  line-height: var(--lh);
  letter-spacing: normal;     /* 本文の字間指定を持ち込まない（数字が間延びする） */
}

.poll-q {
  font-size: var(--fs-lg);
  font-weight: 700;
  line-height: var(--lh-tight);
  color: var(--txt);          /* --panel 上 14.68:1 / ダーク --panel-2 上 12.50:1 */
}

.poll-sub {
  margin: 3px 0 var(--space-3);
  font-size: var(--fs-xs);
  line-height: 1.6;
  color: var(--txt-sub);      /* 6.06:1 / ダーク 6.75:1 */
}

/* 締め切り済みタグ。色 + ピル形 + 枠線の 3 点で示す（色だけに頼らない） */
.poll-closed-tag {
  display: inline-block;
  margin-left: 2px;
  padding: 0 8px;
  border-radius: var(--radius-pill);
  background: var(--warn-bg);
  color: var(--warn-txt);     /* --warn-bg 上 7.15:1 / ダーク 9.49:1 */
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--amber) 45%, transparent);
  font-weight: 700;
  white-space: nowrap;
}

/* 選択肢。.poll-bar を敷くため position: relative + overflow: hidden が前提。
   面そのものが「投票率のトラック」になるので --bg-sunken で一段沈める。 */
.poll-opt {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 38px;
  padding: 7px 11px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--bg-sunken);   /* = バーの背景トラック */
  cursor: pointer;
}
/* ⚠ .poll-card の子はすべて <div> なので :last-of-type は .poll-foot に当たる。
   選択肢どうしの間隔は隣接セレクタで作り、最後の選択肢に余分な下余白を残さない。
   （最初の選択肢の上の余白は .poll-sub の margin-bottom が担当する） */
.poll-opt + .poll-opt { margin-top: var(--space-2); }

.poll-opt:hover {
  border-color: var(--brand);
  box-shadow: var(--shadow-1);
}

/* 自分が選んだ選択肢:
   ① ラベル頭の ✅（app.js が出力）② 枠線がブランド色 + 内側リング
   ③ ラベルが太字 ④ バーが濃い —— の 4 点で判別できる。 */
.poll-opt.mine,
.poll-opt[aria-checked="true"] {
  border-color: var(--brand);
  box-shadow: inset 0 0 0 1px var(--brand);
}
.poll-opt.mine .poll-label,
.poll-opt[aria-checked="true"] .poll-label { font-weight: 700; }

/* 締め切り後は押せない（app.js 974行が toast で弾く / tabindex="-1"）。
   ホバーの反応そのものを消して「操作対象ではない」ことを示す。
   ⚠ opacity や淡色化で表現しないこと。集計結果は締め切ってからが本番なので、
     可読性を落とす表現は使わない。締め切りの告知は .poll-closed-tag（ピル形）と
     .poll-foot の「集計は確定しました」が担う。 */
.poll-opt.closed { cursor: default; }
.poll-opt.closed:hover {
  border-color: var(--line-strong);
  box-shadow: none;
}
.poll-opt.mine.closed:hover,
.poll-opt[aria-checked="true"].closed:hover {
  border-color: var(--brand);
  box-shadow: inset 0 0 0 1px var(--brand);
}

/* 得票バー。
   ⚠ width は app.js が style="width:○%" で書く。ここでは【絶対に指定しない】。
   ・面 : トラック(--bg-sunken)に --brand を 26%（自分の票は 42%）混ぜた色
   ・右端: --brand の 2px の縁。トラックとの境界コントラストは
           4.26:1（ライト）/ 7.44:1（ダーク）で、色覚に依らず「どこまで」が分かる。
           面の色差だけだと 1.38:1 しかないので、この inset shadow は消さないこと。
   ・伸びる動きは transform: scaleX() で表現する（@keyframes eco-poll-grow / 17 節）。
     .poll-opt は再描画のたびに DOM ごと作り直されるため width の transition は
     発火しない。@keyframes 側が「投票するたび伸びる」体験の本体になる。 */
.poll-bar {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  z-index: 0;
  background: color-mix(in srgb, var(--brand) 26%, var(--bg-sunken));
  box-shadow: inset -2px 0 0 var(--brand);
  border-radius: 0 var(--radius-xs) var(--radius-xs) 0;
  transform-origin: left center;
  animation: eco-poll-grow var(--dur-slow) var(--ease-out) both;
  transition: background-color var(--dur) var(--ease);
}
.poll-opt.mine .poll-bar,
.poll-opt[aria-checked="true"] .poll-bar {
  background: color-mix(in srgb, var(--brand) 42%, var(--bg-sunken));
}

/* バーの上に載る文字は必ず z-index: 1。
   ⚠ 文字色に --txt-sub を使うとバーの上で 3.52:1（ライト）/ mine の濃いバー上では
     2.75:1 まで落ちて AA を割る。ラベル・票数・投票者名はすべて --txt を使い、
     階層は「サイズと太さ」で作ること。実測:
       トラック上   12.48:1 / ダーク 16.17:1
       バー 26% 上   9.05:1 / ダーク 10.32:1
       バー 42% 上   7.28:1 / ダーク  7.19:1 */
.poll-label,
.poll-count,
.poll-who {
  position: relative;
  z-index: 1;
  color: var(--txt);
}
.poll-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
  font-size: var(--fs-md);
  font-weight: 500;
  line-height: 1.5;
}
.poll-count {
  flex: 0 0 auto;
  font-size: var(--fs-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* 投票者名。長くなるので上限を切って省略する。
   全員ぶんは .poll-opt の title 属性と aria-label に入っているので、
   省略しても情報は失われない。 */
.poll-who {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 42%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--fs-xs);
  font-weight: 400;
}

.poll-foot {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  margin-top: var(--space-3);
  padding-top: var(--space-2);
  border-top: 1px solid var(--line);
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: var(--txt-sub);
}
.poll-foot > span {
  flex: 1 1 auto;
  min-width: 0;
}
/* 「締め切る」/「再開する」。クラスが付いていない素の <button> なので単独で組む。 */
.poll-foot button {
  flex: 0 0 auto;
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 30px;
  padding: 4px 14px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  background: var(--panel);
  color: var(--txt);
  font-size: var(--fs-xs);
  font-weight: 700;
  white-space: nowrap;
}
.poll-foot button:hover {
  background: var(--brand-tint);
  border-color: var(--brand);
  color: var(--on-brand-weak);   /* --brand-tint 上でも 8:1 以上 */
}
.poll-foot button:active { transform: translateY(1px); }


/* ------------------------------------------------------------
   メッセージのインライン編集（.edit-ta / .edit-btns）
   app.js 1048-1056行が .msg-text の innerHTML を丸ごと差し替える。
   自動高さ調整の JS が無いので min-height と resize は CSS 側の責務。
   ------------------------------------------------------------ */

/* .msg-text の white-space: pre-wrap は、textarea と .edit-btns の【間にある
   空白テキストノード】まで可視の空行にしてしまう。編集中だけ normal に戻す。
   :has() 非対応環境では .edit-btns 側の white-space: normal が効き、
   textarea と保存ボタンの間に 1 行ぶんの余白が残るだけで機能は保たれる。 */
.msg-text:has(> .edit-ta) { white-space: normal; }

.edit-ta {
  display: block;
  box-sizing: border-box;
  width: 100%;
  /* 3 行ぶん。box-sizing: border-box なので min-height には padding(10+10)と
     border(1+1)が含まれる。5.4em（= 1.8 行送り × 3 行）だけだと内容領域が
     2.2 行ぶんしか残らず、3 行の本文が下端で切れて読めなくなる。
     枠ぶんの 22px を足して「3 行が必ず収まる」状態にする。 */
  min-height: calc(5.4em + 22px);
  max-height: 40vh;
  resize: vertical;             /* 自動リサイズが無いので手で伸ばせるようにする */
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--l3-field-bg);
  color: var(--txt);
  /* 編集前の本文とまったく同じ組版にして、行の折り返し位置をずらさない */
  font-family: inherit;
  font-size: var(--l3-msg-fs);
  line-height: var(--l3-msg-lh);
  letter-spacing: var(--l3-msg-track);
  white-space: pre-wrap;
}
.edit-ta:hover { border-color: var(--line-strong); }
/* .composer-row textarea とまったく同じフォーカス表現に揃える */
.edit-ta:focus,
.edit-ta:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
  border-color: transparent;
  background: var(--l3-field-focus-bg);
}

.edit-btns {
  white-space: normal;          /* ← 必須 */
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
}


/* ------------------------------------------------------------
   新着メッセージ誘導ピル（#newPill）
   .chat-pane の【直接のフレックスアイテム】（.msg-scroll の後 / #typing の前 /
   index.html 119行）。素のままだと幅いっぱいのボタンが割り込んで
   メッセージ領域がずれる。

   ここでは position: absolute を使わず、
     「フレックスアイテムのまま、自分の高さぶんの負マージンで浮かせる」
   方式を採る。理由:
     ・composer の高さ（返信プレビュー・ツールバーの折り返しで変動する）に
       依存しない。absolute + bottom 指定だと composer が伸びた瞬間に
       ピルが入力欄に潜り込む。
     ・ボタンがフローに残るのでタブ順・クリック判定が素直。
   上下方向の占有量は 0（-(--pill-h + --space-3) + --pill-h + --space-3）なので、
   .msg-scroll / #typing / .composer のレイアウトはまったく動かない。
   位置指定の基準（position: relative）は 06 節の .chat-pane に入れてある。
   ------------------------------------------------------------ */
.new-pill {
  --pill-h: 34px;

  align-self: center;                 /* 幅いっぱいに伸びるのを止めて中央に置く */
  position: relative;
  z-index: 6;                         /* .msg-actions(5) より上 / .panel.force(30) より下 */
  height: var(--pill-h);
  margin-top: calc(-1 * (var(--pill-h) + var(--space-3)));
  margin-bottom: var(--space-3);
  max-width: calc(100% - var(--space-5) * 2);

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  padding: 0 var(--space-4);
  border-radius: var(--radius-pill);
  background: var(--brand);
  color: var(--on-brand);             /* --brand 上 5.02:1 / ダーク 7.46:1 */
  font-size: var(--fs-sm);
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  overflow: hidden;
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--on-brand-strong) 22%, transparent),
    var(--shadow-2);
  animation: eco-newpill-in var(--dur) var(--ease-out) both;
}
.new-pill:hover {
  background: var(--brand-hover);
  transform: translateY(-1px);
}
.new-pill:active {
  background: var(--brand-active);
  transform: translateY(0);
  box-shadow: var(--shadow-1);
}
/* 18 節の汎用ハローは box-shadow を丸ごと置き換えてしまい、浮いている影が
   消える。影とハローを両立させる。 */
.new-pill:focus-visible {
  box-shadow:
    0 0 0 4px color-mix(in srgb, var(--focus) 26%, transparent),
    var(--shadow-2);
}


/* 入力中インジケータ: 文頭に脈打つドットを置く（テキストは JS 側のまま）
   JS が el.textContent で直接入れるため中身は無名のテキストノード。
   display:flex だと無名フレックスアイテム扱いになり text-overflow が効かず、
   長い名前が「…」ではなく途中でぶつ切りになる。block + inline-block で組む。 */
.typing {
  display: block;
  padding: 2px var(--space-5) 5px;
  font-size: var(--fs-xs);
  line-height: 1.6;
  color: var(--txt-faint);
  font-style: normal;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.typing::before {
  content: "";
  display: inline-block;
  vertical-align: middle;
  margin-right: 6px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  animation: eco-typing-dot 1.15s var(--ease) infinite;
}


/* ============================================================
   11. 入力欄（composer / オーバーフローメニュー）
   ============================================================ */
.composer {
  border-top: 1px solid var(--line);
  background: var(--panel);
  padding: var(--space-2) var(--space-4) var(--space-3);
}

/* 返信プレビュー */
.reply-preview {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-2);
  background: var(--brand-tint);
  border-left: 3px solid var(--brand);
  padding: 6px 10px;
  font-size: var(--fs-sm);
  line-height: 1.6;
  color: var(--txt-sub);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  margin-bottom: var(--space-2);
  animation: eco-slide-down var(--dur) var(--ease) both;
}
.reply-preview > span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.reply-preview button {
  flex-shrink: 0;
  font-size: calc(15px * var(--ui-scale));
  line-height: 1;
  color: var(--txt-sub);
  padding: 3px 6px;
  border-radius: var(--radius-sm);
}
.reply-preview button:hover { background: color-mix(in srgb, var(--txt) 8%, transparent); color: var(--txt); }

/* ツールバー: 視覚ノイズを下げ、入力に集中できるように */
.composer-tools {
  display: flex;
  gap: 1px;
  align-items: center;
  margin-bottom: var(--space-2);
  flex-wrap: wrap;
}
.composer-tools button {
  font-size: var(--fs-sm);
  padding: 5px 9px;
  border-radius: var(--radius-sm);
  color: var(--txt-faint);
  font-weight: 600;
  line-height: 1.3;
}
.composer-tools button:hover {
  background: var(--brand-tint);
  color: var(--txt);
}
.composer-tools button:active {
  background: color-mix(in srgb, var(--brand) 18%, var(--panel));
  transform: scale(.93);
}

/* ------------------------------------------------------------
   オーバーフローメニュー（.more-wrap / #composerMore.more-menu）
   質感は 14 節の .emoji-picker と揃える（--panel 面 / --radius-lg /
   --shadow-3 / eco-pop-in）。「同じ種類の浮くパネル」として読ませる。

   ■ 位置
     composer は画面下端にあるので **上向き**（bottom:100%）に出す。
     .more-wrap の position:relative が無いと基準が body になり、
     ポップオーバーが画面のどこかに飛ぶ。必須。

   ■ z-index = 20 の根拠（既存スケール）
       .msg-actions 5 / .new-pill 6 / .panel.force 30(≤1100) 40(≤760) /
       .modal-wrap 50 / .emoji-picker 60 / .call-view 70 / .toast 80 /
       .conn-banner 90
     メッセージ領域より上、右パネルのオーバーレイより下。

   ■ アイコン
     メニュー項目 5 つの線画アイコンは 22 節（@supports mask）で与える。
     mask 非対応環境では <span aria-hidden> の絵文字がそのまま出る。
   ------------------------------------------------------------ */
.more-wrap {
  position: relative;
  display: inline-flex;
}

.more-menu {
  position: absolute;
  bottom: calc(100% + var(--space-2));
  left: 0;
  right: auto;
  z-index: 20;
  min-width: 236px;
  max-width: min(280px, calc(100vw - var(--space-5)));
  max-height: min(340px, 52vh);
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: var(--space-1);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-3);
  /* .msg-text 由来の pre-wrap は届かないが、composer 側の将来変更に備えて明示 */
  white-space: normal;
  transform-origin: bottom left;
  animation: eco-pop-in var(--dur) var(--ease-out) both;
}

.more-menu hr {
  border: none;
  border-top: 1px solid var(--line);
  margin: var(--space-1) var(--space-2);
}

/* メニュー項目の面。
   .composer-tools button が子孫セレクタで当たり、小さすぎ・淡すぎる
   「ツールバーのアイコン」の見た目になってしまうのでここで上書きする。
   詳細度 .more-menu button(0,2,0) > .composer-tools button(0,1,1) なので
   連結順に依存しない。
   コントラスト実測: --txt / --panel = 14.68:1（ダーク 13.92:1）
                     hover の --brand-tint 上でも 14:1 前後で AA 余裕あり */
.more-menu button {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: var(--space-2);
  width: 100%;
  min-height: 36px;
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  text-align: left;
  background: none;
  font-size: var(--fs-md);
  line-height: var(--lh-tight);
  letter-spacing: .01em;
  white-space: nowrap;
  color: var(--txt);
  font-weight: 600;
}
.more-menu button:hover {
  background: var(--brand-tint);
  color: var(--txt);
}
/* ⚠ .composer-tools button:active の scale(.93) は行メニューに合わない。
   詳細度 (0,2,1) > (0,1,2) で確実に打ち消す。 */
.more-menu button:active {
  background: var(--brand-weak);
  color: var(--on-brand-weak);        /* --brand-weak 上 8.74:1 */
  transform: none;
}
.more-menu button:focus-visible { outline-offset: -2px; }

/* トリガー（＋ その他）の開状態。
   aria-expanded は app.js 1139-1143 / closeMore() が必ず同期している。 */
#btnMore[aria-expanded="true"] {
  background: var(--brand-weak);
  color: var(--brand-ink);            /* --brand-weak 上 7.91:1 / ダーク 4.89:1 */
}


.sendkey {
  margin-left: auto;
  font-size: var(--fs-xs);
  color: var(--txt-faint);
  display: flex;
  gap: 5px;
  align-items: center;
  cursor: pointer;
  user-select: none;
  padding: 3px 4px;
  border-radius: var(--radius-sm);
}
.sendkey:hover { color: var(--txt-sub); }
.sendkey input[type=checkbox] {
  width: 14px;
  height: 14px;
  accent-color: var(--brand-ink);
  cursor: pointer;
  margin: 0;
}

.composer-row {
  display: flex;
  gap: var(--space-3);
  align-items: flex-end;
}
.composer-row textarea {
  flex: 1;
  min-width: 0;
  /* 入力欄は最初から3行ぶんの高さを確保する。1行だと書き始めが窮屈で、
     長文のときも全体が見えないため。伸びる上限も広げてある。 */
  min-height: 92px;
  max-height: 320px;
  resize: none;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 11px 13px;
  font-size: var(--fs-md);
  line-height: 1.7;
  letter-spacing: var(--l3-msg-track);
  color: var(--txt);
  background: var(--l3-field-bg);
}
.composer-row textarea::placeholder { color: var(--txt-faint); }
.composer-row textarea:hover { border-color: var(--line-strong); }
.composer-row textarea:focus,
.composer-row textarea:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
  border-color: transparent;
  background: var(--l3-field-focus-bg);
}
/* 送信ボタンは textarea（最小46px）と下端で揃う */
.composer-row .btn-primary { min-height: 46px; }

/* 添付ファイルチップ */
.file-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 7px 12px;
  margin-top: var(--space-2);
  background: var(--panel);
  font-size: var(--fs-sm);
  line-height: 1.5;
  text-decoration: none;
  color: var(--txt);
  max-width: 100%;
  word-break: break-all;
  /* .file-chip は <a> なので、02節の a{transition:color} が
     :where() の面用トランジション（詳細度0）に勝ってしまう。ここで明示する。 */
  transition: background-color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease),
              box-shadow var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease);
}
.file-chip small { color: var(--txt-faint); flex-shrink: 0; }
/* 添付の容量表示。.file-chip small でほぼ足りているが、
   "(2.4" / "MB)" に割れるのだけ防ぐ。 */
.file-chip .file-size {
  white-space: nowrap;
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
}
.file-chip:hover {
  border-color: var(--brand);
  background: var(--brand-tint);
  box-shadow: var(--shadow-1);
}
.file-chip:active { transform: scale(.99); }


/* ============================================================
   12. TODO リスト（やることリスト）
   ============================================================ */
.todo-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 9px 8px;
  border-radius: var(--radius-sm);
  border-bottom: 1px solid color-mix(in srgb, var(--line) 75%, transparent);
}
.todo-row:last-child { border-bottom: none; }
.todo-row:hover { background: var(--l3-msg-hover); }
.todo-row input[type=checkbox] {
  width: 16px;
  height: 16px;
  accent-color: var(--brand-ink);
  flex-shrink: 0;
  cursor: pointer;
}
.todo-row .td-body {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-md);
  line-height: 1.65;
  color: var(--txt);
  word-break: break-word;
  overflow-wrap: break-word;
}
.todo-row.done { opacity: .72; }
.todo-row.done .td-body {
  text-decoration: line-through;
  text-decoration-color: color-mix(in srgb, var(--txt-faint) 70%, transparent);
  color: var(--txt-sub);
}
.td-limit {
  font-size: var(--fs-xs);
  color: var(--txt-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  flex-shrink: 0;
}
.td-limit.over {
  color: var(--l3-danger-ink);
  font-weight: 700;
}
/* 期限超過は「赤いだけ」にせず記号でも示す */
.td-limit.over::before,
.task-card .t-limit.over::before {
  content: "!";
  display: inline-block;
  margin-right: 3px;
  font-weight: 700;
}
.td-del {
  font-size: calc(13px * var(--ui-scale));
  line-height: 1;
  color: var(--txt-faint);
  padding: 5px 7px;
  border-radius: var(--radius-sm);
  flex-shrink: 0;
  opacity: .7;
  transition: background var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease);
}
.todo-row:hover .td-del { opacity: 1; }
.td-del:hover {
  background: var(--danger-bg);
  color: var(--danger-txt);
  opacity: 1;
}
.td-del:active { transform: scale(.93); }
.td-del:focus-visible { opacity: 1; }


/* ============================================================
   13. 右パネル
   ============================================================ */
.panel-tabs {
  display: flex;
  border-bottom: 1px solid var(--line);
  background: var(--panel);
  flex-shrink: 0;
}
.panel-tabs button {
  flex: 1;
  min-width: 0;
  padding: 12px 2px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--txt-sub);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.panel-tabs button:hover { color: var(--txt); background: var(--bg-sunken); }
.panel-tabs button:active { transform: scale(.93); }
/* 選択中。app.js 1271行が .on と aria-selected を同時に更新する。
   ⚠ #btnPanelClose には aria-selected が付かない（app.js 1265行が data-p 無しを
     弾いている）ので、この規則は閉じるボタンには当たらない。 */
.panel-tabs button.on,
.panel-tabs button[aria-selected="true"] {
  color: var(--brand-ink);
  font-weight: 700;
  border-bottom-color: var(--brand);
  background: color-mix(in srgb, var(--brand-tint) 55%, transparent);
}

/* 「閉じる」ボタン。#btnPanelClose は class="mobile-only" → class="panel-close" に
   変わり、.mobile-only{display:none!important}（06 節）の対象から外れて
   **PC 幅でも常時表示**になった。上の .panel-tabs button{flex:1} がそのまま当たると
   290px のパネルを 5 等分してタブ 1 つ 58px =「メンバー」が入らない。

   対処: 閉じるボタンだけ等分から外す（flex:0 0 auto + 実寸 38px）。
   残り 290-38=252px を 4 タブで割ると 63px。--fs-sm(12.5px) の全角 4 文字は
   50px + 左右 padding 4px = 54px なので確実に収まる。

   閉じるはタブではないので「選択されうる要素」に見せない:
     - border-bottom は透明のまま維持し、タブ行のベースラインに段差を作らない
     - .on / aria-selected は JS が付けない（app.js 1265行が data-p 無しを弾く）
     - 左に髪の毛一本の区切りを入れて「タブ群の外側」であることを示す
       （box-shadow の inset なのでボックスサイズに影響しない）
   ※ 760px 以下は 20 節の #btnPanelClose(1,0,0) が
     この .panel-tabs .panel-close(0,2,0) に勝つので、従来どおり大きいまま。 */
.panel-tabs .panel-close {
  flex: 0 0 auto;
  width: 38px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: calc(17px * var(--ui-scale));
  line-height: 1;
  color: var(--txt-sub);              /* --panel 上 6.06:1 / ダーク 7.51:1 */
  border-bottom: 2px solid transparent;
  box-shadow: inset 1px 0 0 0 var(--line);
  border-radius: 0;
}
.panel-tabs .panel-close:hover {
  color: var(--txt);                  /* --bg-sunken 上 12.9:1 / ダーク 14:1 */
  background: var(--bg-sunken);
}

.panel-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-4);
  scrollbar-gutter: stable;
}

.panel-sec-title {
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--txt-faint);
  letter-spacing: .06em;
  margin: var(--space-5) 0 var(--space-2);
  padding-bottom: var(--space-1);
  border-bottom: 1px solid var(--line);
}
.panel-body > .panel-sec-title:first-child { margin-top: 0; }

.panel-desc {
  font-size: var(--fs-md);
  line-height: 1.8;
  color: var(--txt);
  white-space: pre-wrap;
  word-break: break-word;
}
/* 「概要は設定されていません」（app.js 1314行）。.ci-none と同じ語彙で揃える。
   ⚠ .muted は 2 用途あるので必ず親で絞る（もう一方は 07 節の .badge.muted）。 */
.panel-desc .muted {
  color: var(--txt-faint);
  font-style: italic;
}

/* --- 概要タブ --- */

/* ルーム見出し行。中身は .room-icon（38px）のことも .avatar+.dot（38px）のことも
   ある。どちらも inline-flex なのでベースライン揃えだとガタつく。flex で潰す。
   背景色は app.js のインライン style（safeColor 検証済み）なので触らない。 */
.panel-room {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-2);
  min-width: 0;
}
.panel-room > b {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-lg);
  font-weight: 700;
  line-height: var(--lh-tight);
  color: var(--txt);
  word-break: break-word;
  overflow-wrap: anywhere;
}

/* 情報ブロック。<br> 区切りの素のテキスト塊なので、沈んだ面に載せて
   「一覧表」に見せる。数字は tabular-nums で桁を揃える。
   コントラスト実測: --txt-sub / --bg-sunken = 5.15:1 / ダーク 8.72:1（AA 合格） */
.panel-info {
  font-size: var(--fs-sm);
  line-height: 2;
  color: var(--txt-sub);
  background: var(--bg-sunken);
  border-radius: var(--radius);
  padding: var(--space-2) var(--space-3);
  font-variant-numeric: tabular-nums;
  word-break: break-word;
}

/* 退席ボタンの器。破壊的操作なので本文から離し、区切り線で
   「ここから先は別の話」を示す。グループチャット以外では DOM ごと存在しない。 */
.panel-leave {
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}
/* .btn-ghost のままだと「無害な副操作」に見えるので危険側に寄せる。
   面は据え置き・文字と縁だけ赤に振る = 押す前に一拍置かせるトーン。
   コントラスト実測: --l3-danger-ink / --panel = 7.45:1 / ダーク 5.57:1 */
.panel-leave #pLeave {
  color: var(--l3-danger-ink);
  border-color: color-mix(in srgb, var(--red) 45%, var(--line-strong));
}
.panel-leave #pLeave:hover {
  background: var(--danger-bg);
  border-color: var(--red);
  color: var(--danger-txt);           /* 6.59:1 / ダーク 8.58:1 */
}
.panel-leave #pLeave:active {
  background: color-mix(in srgb, var(--red) 16%, var(--danger-bg));
}

/* --- タスクタブの導線 ---
   290px の狭いパネルでは全幅ボタンのほうが収まる。
   .btn-primary が inline-flex なので display から上書きする。
   詳細度 .panel-body .panel-add(0,2,0) > .btn-primary(0,1,0) で順序に依存しない。 */
.panel-body .panel-add {
  display: flex;
  width: 100%;
  justify-content: center;
  margin-bottom: var(--space-3);
}

/* .tabbar 本体（14 節）はモーダル内でも使われているので絶対に触らない。
   .panel-tabbar は「狭い幅に収めるための上書き」だけ。
   ラベルは「未完了 (128)」まで伸びうるので、等分 + 省略で必ず 1 行に収める。
   詳細度 (0,2,0) / (0,2,1) で 14 節の .tabbar / .tabbar button に必ず勝つ。 */
.tabbar.panel-tabbar {
  flex-wrap: nowrap;
  gap: 2px;
  margin-bottom: var(--space-2);
}
.tabbar.panel-tabbar button {
  flex: 1 1 0;
  min-width: 0;
  padding: 8px 6px;
  font-size: var(--fs-sm);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-variant-numeric: tabular-nums;
}

/* --- タスクカード --- */
.task-card {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 10px 12px;
  margin-bottom: var(--space-2);
  background: var(--panel);
  box-shadow: var(--shadow-1);
}
.task-card:hover { border-color: var(--line-strong); box-shadow: var(--shadow-2); }
.task-card.done { opacity: .62; box-shadow: none; }
.task-card.done:hover { opacity: .85; }

.task-card .t-body {
  font-size: var(--fs-md);
  line-height: 1.6;
  color: var(--txt);
  white-space: pre-wrap;
  word-break: break-word;
}
.task-card .t-meta {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-2);
  font-size: var(--fs-xs);
  color: var(--txt-sub);
  flex-wrap: wrap;
  align-items: center;
}
.task-card .t-limit {
  font-variant-numeric: tabular-nums;
  padding: 1px 7px;
  border-radius: var(--radius-pill);
  background: var(--bg-sunken);
}
/* 期限切れ。--red をそのまま置くと自分の淡い面（red 12% + panel）の上で
   4.49:1 とギリギリ AA を割るため、TODO 側と同じ --l3-danger-ink を使う
   （実測 ライト 6.26:1 / ダーク 6.09:1）。 */
.task-card .t-limit.over {
  color: var(--l3-danger-ink);
  font-weight: 700;
  background: color-mix(in srgb, var(--red) 12%, var(--panel));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--red) 32%, transparent);
}
.task-card .t-actions {
  margin-top: var(--space-2);
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.task-check {
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
}
.task-check input[type=checkbox] {
  width: 17px;
  height: 17px;
  accent-color: var(--brand-ink);
  margin-top: 2px;
  flex-shrink: 0;
  cursor: pointer;
}
.task-check > *:last-child { flex: 1; min-width: 0; }
/* .task-main は .task-check の最後の子なので上の規則が既に当たっている。
   構造ラッパーなので装飾はしない。将来兄弟が増えたときの保険だけ置く。 */
.task-check > .task-main { min-width: 0; }

/* --- ファイル一覧 --- */
.file-row {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  padding: var(--space-2);
  border-radius: var(--radius-sm);
}
.file-row + .file-row { border-top: 1px solid var(--line); }
.file-row:hover { background: var(--bg-sunken); }
.file-ico {
  font-size: calc(20px * var(--ui-scale));
  line-height: 1;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  border-radius: var(--radius-sm);
  background: var(--bg-sunken);
}
.file-row:hover .file-ico { background: var(--brand-tint); }
/* 構造ラッパー。装飾は不要だが flex / min-width:0 が【必須】。これが無いと
   長いファイル名で .file-row が横に伸び、右端の ⬇ がはみ出す
   （.file-name の word-break は親が縮まないと効かない）。 */
.file-row .file-txt {
  flex: 1 1 auto;
  min-width: 0;
}
.file-name {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--txt);
  line-height: 1.4;
  word-break: break-all;
}
.file-sub {
  font-size: var(--fs-xs);
  color: var(--txt-sub);
  margin-top: 2px;
  line-height: 1.4;
}

/* --- メンバー一覧 --- */
.member-row {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  padding: var(--space-2) var(--space-1);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.member-row:hover { background: var(--bg-sunken); }
.member-row:active { transform: scale(.99); }
.member-name {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--txt);
  flex: 1;
  min-width: 0;
  line-height: 1.4;
}
.member-name .pick-sub { font-weight: 400; margin-top: 1px; }
.member-role {
  font-size: var(--fs-xs);
  color: var(--txt-sub);
  background: var(--bg-sunken);
  border: 1px solid var(--line);
  padding: 2px 9px;
  border-radius: var(--radius-pill);
  flex-shrink: 0;
  white-space: nowrap;
  line-height: 1.5;
}
.member-role.admin {
  background: var(--brand-tint);
  border-color: color-mix(in srgb, var(--brand) 30%, transparent);
  color: var(--brand-ink);
  font-weight: 700;
}


/* ============================================================
   14. モーダル / 絵文字ピッカー / 予約投稿行
   ============================================================ */
.modal-wrap {
  position: fixed;
  inset: 0;
  background: var(--scrim);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  animation: eco-fade var(--dur) var(--ease) both;
}

.modal {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-3);
  width: 460px;
  max-width: 94vw;
  max-height: 88vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  animation: eco-modal-in var(--dur-slow) var(--ease-out) both;
}

.modal-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  /* ファイルを見る画面の「← 戻る」を左端に置くための基準 */
  position: relative;
  gap: var(--space-3);
  padding: var(--space-4) calc(var(--space-4) + var(--space-1));
  border-bottom: 1px solid var(--line);
  font-weight: 700;
  font-size: var(--fs-lg);
  color: var(--txt);
  background: var(--panel);
  flex-shrink: 0;
}
.modal-head button {
  font-size: calc(18px * var(--ui-scale));
  line-height: 1;
  color: var(--txt-sub);
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}
.modal-head button:hover { background: var(--bg-sunken); color: var(--txt); }
.modal-head button:active { transform: scale(.93); }

/* 本文だけがスクロールする（ヘッダ・フッタは固定） */
.modal-body {
  padding: var(--space-4) calc(var(--space-4) + var(--space-1)) var(--space-5);
  overflow-y: auto;
  overscroll-behavior: contain;
  flex: 1 1 auto;
  min-height: 0;
}

.modal-foot {
  padding: var(--space-3) calc(var(--space-4) + var(--space-1));
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;              /* ボタンが4個並ぶ画面(自分のプロフィール)で溢れるのを防ぐ */
  justify-content: flex-end;
  align-items: center;
  gap: var(--space-2);
  background: var(--panel-2);
  flex-shrink: 0;
}
/* 折り返した行では「幅を埋めるだけのスペーサー(span[style*=flex])」を無効化する */
.modal-foot > span[style*="flex"] { flex: 1 1 0 !important; min-width: 0; }

.modal label.f-label {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--txt-sub);
  letter-spacing: .02em;
  margin: var(--space-4) 0 var(--space-1);
}
.modal-body > .f-label:first-child { margin-top: 0; }

.modal input[type=text], .modal input[type=email], .modal input[type=password], .modal input[type=date],
.modal textarea, .modal select {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--bg-sunken);
  color: var(--txt);
}
.modal input::placeholder, .modal textarea::placeholder { color: var(--txt-faint); }
.modal input:hover, .modal textarea:hover, .modal select:hover { border-color: var(--line-strong); }
.modal textarea { resize: vertical; min-height: 72px; line-height: 1.6; }
.modal select { cursor: pointer; }
.modal input:focus, .modal textarea:focus, .modal select:focus,
.modal input:focus-visible, .modal textarea:focus-visible, .modal select:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
  border-color: transparent;
  background: var(--panel);
}

/* --- 選択行（メンバー選択・設定トグル等） --- */
.pick-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.pick-row:hover { background: var(--bg-sunken); }
.pick-row:active { transform: scale(.99); }
.pick-row input[type=checkbox] {
  accent-color: var(--brand-ink);
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  cursor: pointer;
}
.pick-name {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--txt);
  flex: 1;
  min-width: 0;
  line-height: 1.45;
}
.pick-sub {
  font-size: var(--fs-xs);
  color: var(--txt-sub);
  line-height: 1.45;
}
/* アンケート作成モーダルの選択肢入力。style="flex:1" が app.js から入るので
   flex は書かない。長い選択肢で .pick-row を押し広げないための保険だけ。 */
.modal-body .pick-row .pollOpt { min-width: 0; }

/* --- カラー選択 --- */
.color-dots {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-top: var(--space-1);
}
.color-dots span {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  cursor: pointer;
  display: inline-block;
  border: 2px solid transparent;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .10);
}
.color-dots span:hover { transform: scale(1.1); }
.color-dots span.on {
  border-color: transparent;
  box-shadow:
    inset 0 0 0 1px rgba(0, 0, 0, .10),
    0 0 0 2px var(--panel),
    0 0 0 4px var(--txt);
}

/* --- 検索結果 --- */
.search-result {
  padding: 10px var(--space-2);
  border-radius: var(--radius-sm);
  cursor: pointer;
  border-bottom: 1px solid var(--line);
}
.search-result:last-child { border-bottom: none; }
.search-result:hover { background: var(--bg-sunken); }
.search-result:active { transform: scale(.99); }
.sr-room {
  font-size: var(--fs-xs);
  color: var(--brand-ink);
  font-weight: 700;
  letter-spacing: .02em;
}
.sr-body {
  font-size: var(--fs-sm);
  margin-top: 3px;
  color: var(--txt);
  line-height: 1.6;
  word-break: break-word;
}
.sr-meta {
  font-size: var(--fs-xs);
  color: var(--txt-faint);
  margin-top: 3px;
  font-variant-numeric: tabular-nums;
}

/* --- モーダル内タブ --- */
.tabbar {
  display: flex;
  gap: var(--space-1);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--space-3);
  flex-wrap: wrap;
}
/* 画面の中のタブは、下へたどっても上に貼り付いたままにする。
   管理メニューの「ユーザー」は社員の数だけ縦に長くなるため、
   貼り付けないとタブが上へ流れて消え、
   いま何のタブを見ているのか分からなくなる。他のタブへも戻れない。
   ★ 背景を必ず敷くこと。敷かないと下の行が透けて重なって見える。
   ★ z-index は行(pick-row)より上・ダイアログ(50)より下。 */
.modal-body > .tabbar {
  position: sticky;
  top: calc(var(--space-4) * -1);
  z-index: 3;
  background: var(--panel);
  padding-top: var(--space-2);
  margin-top: calc(var(--space-2) * -1);
}
.tabbar button {
  padding: 9px 13px;
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--txt-sub);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}
.tabbar button:hover { color: var(--txt); background: var(--bg-sunken); }
/* 選択中。app.js 1336-1337行が class="on" と aria-selected を同時に出力する。 */
.tabbar button.on,
.tabbar button[aria-selected="true"] {
  color: var(--brand-ink);
  font-weight: 700;
  border-bottom-color: var(--brand);
}


/* --- 予約投稿の一覧行 ---
   出現は 2 箇所。(a) 予約投稿モーダル #scList（.sched-where 無し）
                  (b) やることリストモーダル（.sched-where 有り）
   どちらも .modal-body の中。「いつ送られるか」が主役なので
   .sched-when だけをチップ化して視線を集める。 */
.sched-row {
  display: flex;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  flex-wrap: wrap;
  padding: var(--space-2) var(--space-1);
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-md);
  line-height: 1.5;
}
.sched-row:last-child { border-bottom: none; }

/* 日時 = 主役。--brand-weak のチップに載せる（8.74:1 / ダーク 8.54:1）。
   等幅数字で桁が揃うので、複数件を上下に並べたとき時系列が読み取りやすい。 */
.sched-when {
  flex: 0 0 auto;
  padding: 3px 9px;
  border-radius: var(--radius-xs);
  background: var(--brand-weak);
  color: var(--on-brand-weak);
  font-size: var(--fs-sm);
  font-weight: 700;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.sched-body {
  flex: 1 1 12em;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--txt);
}

/* ルーム名。(a) では出力されないので、無くても崩れない幅指定にする。 */
.sched-where {
  flex: 0 0 auto;
  max-width: 11em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--fs-xs);
  color: var(--txt-sub);      /* --panel 上 6.06:1 / ダーク 7.51:1 */
}

/* 取消 = 破壊的操作。
   ① .sched-body との間に余白を足して誤タップしにくくする
   ② 平常時は主張させない（枠線だけの静かなボタン）
   ③ hover / focus / active で初めて危険色（--danger-*）に変わる
   .btn-danger 等のクラスが付いていないので単独で組む。 */
.sched-del {
  flex: 0 0 auto;
  /* auto にして常に行の右端へ寄せる。
     .sched-row は flex-wrap: wrap なので、幅が足りず「取消」だけが 2 行目へ
     落ちたときに margin-left が固定値だと左端に取り残されて主従が崩れる
     （予約投稿モーダルの実測幅 440px で発生）。auto なら折り返しても右端。 */
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 32px;
  padding: 4px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--txt-sub);
  font-size: var(--fs-xs);
  font-weight: 600;
  white-space: nowrap;
}
.sched-del:hover,
.sched-del:focus-visible {
  background: var(--danger-bg);
  border-color: var(--danger-line);
  color: var(--danger-txt);   /* --danger-bg 上 6.59:1 / ダーク 8.58:1 */
}
.sched-del:active { transform: translateY(1px); }

/* --- 絵文字ピッカー --- */
.emoji-picker {
  position: fixed;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-3);
  padding: var(--space-2);
  width: 264px;
  z-index: 60;
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 2px;
  transform-origin: bottom left;
  animation: eco-pop-in var(--dur) var(--ease-out) both;
}
.emoji-picker button {
  font-size: calc(18px * var(--ui-scale));
  line-height: 1;
  aspect-ratio: 1;
  padding: 0;
  border-radius: var(--radius-sm);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.emoji-picker button:hover { background: var(--brand-tint); transform: scale(1.12); }
.emoji-picker button:active { transform: scale(.93); }


/* ============================================================
   15. 通話画面（ライト / ダークを問わず常に暗色）
   ローカル変数はすべて --green-* から color-mix で生成しているので
   テーマに追随せず、ブランド色相だけを保つ。
   ============================================================ */
.call-view {
  --call-bg:        color-mix(in srgb, var(--green-900) 46%, black);
  --call-bg-2:      color-mix(in srgb, var(--green-900) 22%, black);
  --call-tile:      color-mix(in srgb, var(--green-900) 62%, black);
  --call-line:      color-mix(in srgb, var(--green-500) 22%, transparent);
  /* --green-100 はダークで暗色に反転するため文字色の素材には使わない。
     常に白（--on-brand-strong）を基準にし、緑はごく僅かに混ぜるだけにする。 */
  --call-txt:       color-mix(in srgb, var(--on-brand-strong) 90%, var(--green-500));
  --call-txt-sub:   color-mix(in srgb, var(--on-brand-strong) 78%, transparent);
  --call-ctrl:      color-mix(in srgb, var(--green-700) 34%, black);
  --call-ctrl-hover:color-mix(in srgb, var(--green-700) 52%, black);
  /* --red はダークで明るいサーモンに反転し白文字が 2.92:1 まで落ちるため、
     常に暗色側へ寄せた専用の面を使う（ライト 8.30:1 / ダーク 4.99:1）。 */
  --call-danger:      color-mix(in srgb, var(--red) 74%, black);
  --call-danger-hover:color-mix(in srgb, var(--red) 58%, black);

  /* 通話画面だけはテーマに関係なく常に暗色なので、中のネイティブ UI
     （スクロールバー等）も暗色系で描かせる。04 節「個別コンポーネントでは
     スクロールバーを再定義しない」の 2 例目の例外（1 例目は .box-code）。 */
  color-scheme: dark;
  scrollbar-color: color-mix(in srgb, var(--on-brand-strong) 26%, transparent) transparent;

  position: fixed;
  inset: 0;
  z-index: 70;
  display: flex;
  flex-direction: column;
  color: var(--call-txt);
  background:
    radial-gradient(1200px 700px at 50% -12%, var(--call-bg) 0%, transparent 62%),
    linear-gradient(180deg, var(--call-bg) 0%, var(--call-bg-2) 100%);
  background-color: var(--call-bg-2);
  animation: eco-fade var(--dur-slow) var(--ease) both;
}
.call-view ::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--on-brand-strong) 26%, transparent);
  border: 2px solid transparent;
  background-clip: padding-box;
}
.call-view ::-webkit-scrollbar-thumb:hover {
  background: color-mix(in srgb, var(--on-brand-strong) 40%, transparent);
  border: 2px solid transparent;
  background-clip: padding-box;
}

.call-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  color: var(--call-txt);
  font-size: var(--fs-md);
  font-weight: 600;
  letter-spacing: .02em;
  flex-shrink: 0;
}
/* 通話ヘッダの子は 3 つ: .ch-title(span) / #callTimer(span) / #btnHangupTop(button)。
   justify-content:space-between のままだと 3 つが均等散開してしまうので、
   タイトルを伸縮させて「左タイトル / 右にタイマーと終了」に固定する。 */
.call-head .ch-title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 700;
  letter-spacing: .02em;
  color: var(--call-txt);
}
.call-head #callTimer { flex: 0 0 auto; }

.call-head #callTimer,
.call-head span + span {
  font-variant-numeric: tabular-nums;
  color: var(--call-txt-sub);
  background: color-mix(in srgb, var(--green-900) 55%, transparent);
  border: 1px solid var(--call-line);
  border-radius: var(--radius-pill);
  padding: 3px 12px;
  font-size: var(--fs-sm);
}

/* 下の `.call-head span + span` は「span 直後の span」。現行では #callTimer にしか
   当たらないが、.ch-title の中の #callRoomName が将来 span 兄弟を持つと誤爆する。
   ルーム名側を明示的に素に戻して免疫を付ける（今は見た目が変わらない保険）。 */
.call-head .ch-title span {
  background: none;
  border: none;
  border-radius: 0;
  padding: 0;
  font-size: inherit;
  color: inherit;
}

/* 上部の終了ボタン（#btnHangupTop）。終了ボタンが 2 箇所あるので役割を階層化する。
     下部 #btnHangup   … 主。塗り(--call-danger) + 大きめ(--fs-lg) + アイコン付き。
     上部 #btnHangupTop … 副。**枠線のみ**の控えめなピル。小さめ(--fs-sm)。
   どちらも Call.leave() だが、「操作の本拠は下のコントロールバー、上は映像が
   大きいときの保険」という関係が形で読めるようにする。
   上部にはアイコンを付けない（22 節でも #btnHangupTop は対象外）。
   文頭の ✕ が既に否定を表しているので情報は欠けない。
   常時暗色の面（--call-bg-2 はほぼ黒）に対して 15:1 を優に超える。 */
.call-head .btn-hangup-top {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  font-size: var(--fs-sm);
  font-weight: 700;
  line-height: var(--lh-tight);
  letter-spacing: .02em;
  color: color-mix(in srgb, var(--red) 30%, var(--on-brand-strong));
  background: color-mix(in srgb, var(--call-danger) 34%, transparent);
  border: 1px solid color-mix(in srgb, var(--red) 58%, transparent);
}
.call-head .btn-hangup-top:hover {
  background: var(--call-danger);     /* 白文字とライト 8.30:1 / ダーク 4.99:1 */
  border-color: var(--call-danger);
  color: var(--on-brand-strong);
}
.call-head .btn-hangup-top:active {
  background: var(--call-danger-hover);
  transform: translateY(1px);
}
/* フォーカスリングは 18 節の .call-head button:focus-visible
   （--focus-on-dark / outline-offset:3px）がそのまま当たる。再定義しない。 */

.call-grid {
  flex: 1;
  min-height: 0;
  display: grid;
  gap: var(--space-3);
  padding: 0 var(--space-5);
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  align-content: center;
  overflow-y: auto;
}

.call-tile {
  position: relative;
  background: var(--call-tile);
  border-radius: var(--radius-lg);
  overflow: hidden;
  aspect-ratio: 4 / 3;
  box-shadow:
    inset 0 0 0 1px var(--call-line),
    0 6px 20px rgba(0, 0, 0, .35);
}
.call-tile video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  background: var(--call-tile);
}
.call-tile .ct-name {
  position: absolute;
  left: 10px;
  bottom: 9px;
  max-width: calc(100% - 20px);
  background: rgba(0, 0, 0, .55);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: var(--call-txt);
  font-size: var(--fs-sm);
  font-weight: 600;
  padding: 4px 11px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .5);
}
/* タイル右上の状態チップ (マイクオフ・接続中など)。app.js が .ct-state に文字を入れる。
   注意色なのでライト用の --amber ではなく、暗い通話面で映える明るい琥珀を使う。 */
.call-tile .ct-state {
  position: absolute;
  right: 10px;
  top: 9px;
  max-width: calc(100% - 20px);
  background: rgba(0, 0, 0, .62);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: #ffdfa0;                     /* 黒62%地の上で 12.4:1 (AA余裕) */
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: .02em;
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, #ffdfa0 26%, transparent);
  text-shadow: 0 1px 2px rgba(0, 0, 0, .5);
}

/* iPhone 等で自動再生がブロックされたときの案内。タイル全面を覆い、押せると分かるようにする。 */
.call-tile.needs-tap { cursor: pointer; }
.call-tile.needs-tap::after {
  content: '▶ タップして再生';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, .55);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  color: var(--call-txt);
  font-size: var(--fs-sm);
  font-weight: 700;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .6);
  z-index: 2;
}
.call-tile.needs-tap:hover::after { background: rgba(0, 0, 0, .44); }

.call-tile .ct-avatar {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background:
    radial-gradient(60% 60% at 50% 45%, color-mix(in srgb, var(--green-700) 20%, transparent) 0%, transparent 70%);
}

.call-ctrl {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-5);
  flex-shrink: 0;
}
.call-ctrl button {
  width: 54px;
  height: 54px;
  border-radius: 50%;
  background: var(--call-ctrl);
  font-size: calc(20px * var(--ui-scale));
  line-height: 1;
  color: var(--call-txt);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow:
    inset 0 0 0 1px var(--call-line),
    0 2px 10px rgba(0, 0, 0, .3);
}
.call-ctrl button:hover { background: var(--call-ctrl-hover); }
.call-ctrl button:active { transform: scale(.92); }
/* ミュート中 / カメラ停止中。app.js 2566行の syncCtrlLabels() が
   btnMic / btnCam に aria-pressed = !on（= .off と同義）を入れるので、
   JS がクラスを付け損ねても状態が消えないよう属性側も併記する。 */
.call-ctrl button.off,
.call-ctrl #btnMic[aria-pressed="true"],
.call-ctrl #btnCam[aria-pressed="true"] {
  background: color-mix(in srgb, var(--red) 40%, black);
  color: color-mix(in srgb, var(--red) 25%, white);
  opacity: .95;
}
.call-ctrl button.off:hover,
.call-ctrl #btnMic[aria-pressed="true"]:hover,
.call-ctrl #btnCam[aria-pressed="true"]:hover { background: color-mix(in srgb, var(--red) 52%, black); }

/* 共有中 = 有効の状態（app.js 2599行が #btnShare に .on を付ける）。
   .off（赤 = 止めている）とは逆に、緑寄りの明るい面で「動いている」を示す。
   aria-pressed も併記する（app.js 2571行が sharing と同値で入れている）。
   ⚠ #btnMic / #btnCam の aria-pressed="true" は「ミュート中 = .off」なので
     意味が逆。上の .off 側にまとめてある。一括で 1 本にしてはいけない。
   ※ #btnShare.off（22 節）は app.js 2467行が join 時に .off を除去するため
     永久に当たらない死にルールだが、害がないので残置している。
   ※ 面の色だけでは通常時と 1.37:1 しか差が付かない。状態の判別は
     22 節の #btnShare.on / [aria-pressed="true"] のアイコン差し替え
     （斜線入りモニター）が担っている。22 節を消すとここも意味を失う。 */
.call-ctrl button.on,
.call-ctrl #btnShare[aria-pressed="true"] {
  background: color-mix(in srgb, var(--green-500) 42%, black);
  color: var(--on-brand-strong);
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--green-500) 62%, transparent),
    0 2px 10px rgba(0, 0, 0, .3);
}
.call-ctrl button.on:hover,
.call-ctrl #btnShare[aria-pressed="true"]:hover {
  background: color-mix(in srgb, var(--green-500) 56%, black);
}

.call-ctrl button.hangup {
  background: var(--call-danger);
  color: var(--on-brand-strong);   /* 常に白 */
  width: auto;
  min-width: 54px;
  border-radius: var(--radius-pill);
  padding: 0 24px;
  font-size: var(--fs-lg);
  font-weight: 700;
}
.call-ctrl button.hangup:hover { background: var(--call-danger-hover); }


/* ============================================================
   16. トースト / 接続断バナー
   ============================================================ */
.toast {
  position: fixed;
  bottom: 26px;
  /* ★ 指が通り抜けるようにする。
     これが無いと、消えるまでの数秒間、下に隠れたボタンが押せない。
     押したはずのボタンが反応しないのは、原因が分からず一番困る。 */
  pointer-events: none;
  left: 50%;
  transform: translateX(-50%);
  background: var(--green-900);
  color: var(--on-brand-strong);
  padding: 11px 22px;
  border-radius: var(--radius-pill);
  font-size: var(--fs-md);
  font-weight: 600;
  line-height: 1.5;
  max-width: min(92vw, 520px);
  text-align: center;
  z-index: 80;
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--on-brand-strong) 14%, transparent),
    var(--shadow-3);
  animation: eco-toast-in var(--dur-slow) var(--ease-out) both;
}

/* エラートースト（app.js 87行 classList.toggle('toast-error', kind === 'error')）。
   成功と同じ濃緑だと「失敗したこと」が伝わらないので、面ごと危険色に振る。
   --red はダークで明るいサーモンに反転し白文字が 2.92:1 まで落ちるため、
   通話画面と同じく常に暗色側へ寄せた式を使う（ライト 8.30:1 / ダーク 4.99:1）。
   詳細度 (0,2,0) は 19 節の html[data-theme="dark"] .toast(0,1,1) に勝つので、
   ダークでも赤いまま出る。 */
.toast.toast-error {
  background: color-mix(in srgb, var(--red) 74%, black);
  color: var(--on-brand-strong);
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--red) 45%, transparent),
    var(--shadow-3);
}

/* 接続断バナーはヘッダーの真上に重なるので、クリックを吸わせない。
   これが無いと電波が弱いときに上部のボタンが一切押せなくなり、
   スマホでは「←戻る」も押せずチャット画面から出られなくなる。 */
.conn-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 90;
  pointer-events: none;
  /* 明るい側を白で持ち上げると白文字が 4.1:1 まで落ちるため、
     一番明るい部分を --warn-solid そのものに固定し、下側だけ沈める。 */
  background: linear-gradient(180deg,
    var(--warn-solid) 0%,
    color-mix(in srgb, var(--warn-solid) 86%, black) 100%);
  color: var(--on-brand-strong);   /* ライト 5.16:1 / ダーク 5.61:1 */
  text-align: center;
  font-size: var(--fs-sm);
  font-weight: 600;
  line-height: 1.5;
  padding: 8px 14px;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .28);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .22);
  animation: eco-drop-in var(--dur-slow) var(--ease-out) both;
}

/* バナー本文に添える補足（index.html 196行 <span class="cb-sub">）。
   親は --warn-solid の上に白文字で **ライト 5.16:1 / ダーク 5.61:1** しか
   余裕が無いので、色を薄めて階層を作るのは危険。
   → 太さ（600→400）と大きさ（--fs-sm→--fs-xs）で階層を付け、
     色は 92% までしか抜かない（ライト 4.64:1 / ダーク 4.91:1 で AA 維持）。
   親の text-shadow も継承するので実際の可読性はもう少し高い。 */
.conn-banner .cb-sub {
  display: inline-block;
  font-size: var(--fs-xs);
  font-weight: 400;
  line-height: 1.5;
  color: color-mix(in srgb, var(--on-brand-strong) 92%, transparent);
  margin-left: var(--space-2);
  padding-left: var(--space-2);
  border-left: 1px solid color-mix(in srgb, var(--on-brand-strong) 38%, transparent);
}

/* バナーが出ている間は本体をその高さぶん下げて、隠れる部分を作らない。
   帯の高さは文字の折り返しで変わる (スマホでは2行になる) ため、
   app.js の showConnBanner() が実測して --conn-h に入れる。 */
body.conn-down .app,
body.conn-down .auth {
  margin-top: var(--conn-h, 0px);
  height: calc(100% - var(--conn-h, 0px));
}
@media (max-width: 760px) {
  body.conn-down .app { height: calc(100dvh - var(--conn-h, 0px)); }
}


/* ============================================================
   17. アニメーション
   .hidden が display:none!important のため transition は効かない。
   よって「出現時のみ」@keyframes で演出し、消える演出は作らない。
   ============================================================ */
@keyframes eco-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
/* モーダル本体 / 認証カード: わずかに下から起き上がる */
@keyframes eco-modal-in {
  from { opacity: 0; transform: translateY(10px) scale(.985); }
  to   { opacity: 1; transform: none; }
}
/* トースト: .toast は translateX(-50%) を持つので必ず含めて上書きする */
@keyframes eco-toast-in {
  from { opacity: 0; transform: translateX(-50%) translateY(12px) scale(.98); }
  60%  { opacity: 1; }
  to   { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
}
/* ポップオーバー（絵文字ピッカー / メッセージ操作） */
@keyframes eco-pop-in {
  from { opacity: 0; transform: translateY(6px) scale(.96); }
  to   { opacity: 1; transform: none; }
}
/* 接続断バナー: 上から降りる */
@keyframes eco-drop-in {
  from { opacity: 0; transform: translateY(-100%); }
  to   { opacity: 1; transform: translateY(0); }
}
/* 通話バー・返信プレビュー: 要素の高さぶんを上から差し込む */
@keyframes eco-slide-down {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
/* 右パネルのオーバーレイ表示: 右から差し込む */
@keyframes eco-panel-in {
  from { opacity: 0; transform: translateX(18px); }
  to   { opacity: 1; transform: none; }
}
/* メッセージ 1 件の着地（ごく短く） */
@keyframes eco-msg-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}
/* バッジの出現（跳ねすぎない） */
@keyframes eco-badge-pop {
  from { opacity: 0; transform: scale(.6); }
  70%  { transform: scale(1.06); }
  to   { opacity: 1; transform: scale(1); }
}
/* 入力中インジケータのドット */
@keyframes eco-typing-dot {
  0%, 100% { opacity: .28; transform: scale(.8); }
  40%      { opacity: 1;   transform: scale(1); }
}

/* ピン留めメッセージへジャンプしたときの一時ハイライト（09 節）。
   .pin-flash クラスは app.js が外さないので fill-mode は絶対に付けない。 */
@keyframes eco-pin-flash {
  0%, 55% {
    background-color: color-mix(in srgb, var(--amber) 22%, var(--panel));
    outline-color: var(--amber);
  }
  100% {
    background-color: transparent;
    outline-color: transparent;
  }
}
/* 得票バーが伸びる（10 節）。width はインライン style なので transform で出す。 */
@keyframes eco-poll-grow {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}
/* 新着メッセージ誘導ピルの出現（10 節） */
@keyframes eco-newpill-in {
  from { opacity: 0; transform: translateY(8px) scale(.96); }
  to   { opacity: 1; transform: none; }
}

/* 出現アニメーションの残りの割り当て */
.badge,
.mini-badge { animation: eco-badge-pop var(--dur) var(--ease-out) both; }


/* ============================================================
   18. フォーカスリング
   キーボード操作時に「今どこにいるか」を常に同じ形で示す。
   ここで全域を一括定義する。個別コンポーネントでは色を再定義せず、
   必要なら outline-offset だけ調整すること。
   ============================================================ */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible,
[contenteditable]:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
/* チェックボックス / ラジオは面が小さいので角丸を合わせる */
input[type="checkbox"]:focus-visible,
input[type="radio"]:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}
/* マウスクリック時はリングを出さない（ボタン類のみ。入力欄は残す） */
button:focus:not(:focus-visible),
[tabindex]:focus:not(:focus-visible) { outline: none; }

/* 面が詰まっている要素はリングを内側に寄せて隣とぶつけない */
.chat-item:focus-visible,
.msg-actions button:focus-visible,
.emoji-picker button:focus-visible { outline-offset: -2px; }
.panel-tabs button:focus-visible,
.tabbar button:focus-visible { outline-offset: -3px; }
.msg-scroll:focus-visible,
.chat-list:focus-visible,
.panel-body:focus-visible,
.modal-body:focus-visible { outline-offset: -3px; }

/* リングの外側にごく薄いハローを足し、濃い面でも輪郭が消えないようにする */
@supports (color: color-mix(in srgb, red 50%, transparent)) {
  a:focus-visible,
  button:focus-visible,
  input:focus-visible,
  textarea:focus-visible,
  select:focus-visible,
  [tabindex]:focus-visible {
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--focus) 22%, transparent);
  }
  /* もともと box-shadow を持つ要素にはハローを付けない（影が消えるため） */
  .msg-actions button:focus-visible,
  .call-ctrl button:focus-visible,
  .emoji-picker button:focus-visible { box-shadow: none; }

  /* 主ボタンは面と同系色なので、透けるハローで輪郭を立てる */
  .btn-primary:focus-visible,
  .btn-danger:focus-visible {
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--focus) 26%, transparent);
  }
  .side-head button:focus-visible,
  .side-actions button:focus-visible {
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--focus-on-dark) 26%, transparent);
  }
}

/* --- 濃緑サーフェス上のフォーカス（ヘッダー / 通話オーバーレイ） ---
   --focus はダークでも明色だが、濃緑の上では明色固定の方が確実に見える。
   #btnMe も .side-head button として自動的に含まれる（個別指定はしない）。 */
.side-head a:focus-visible,
.side-head button:focus-visible,
.side-head [tabindex]:focus-visible,
.side-actions button:focus-visible {
  outline: 2px solid var(--focus-on-dark);
  outline-offset: 2px;
}
.call-view button:focus-visible,
.call-ctrl button:focus-visible,
.call-head button:focus-visible {
  outline: 2px solid var(--focus-on-dark);
  outline-offset: 3px;
}

/* ラベル内チェックボックス（Enterで送信）はラベル側にリングを出す */
.sendkey:focus-within {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}
.sendkey input[type="checkbox"]:focus-visible { outline: none; box-shadow: none; }


/* ============================================================
   19. ダークモード：コンポーネント個別の上書き
   ※ 自動（@media）版と手動（html[data-theme="dark"]）版は同一内容。
     片方だけ直さないこと。
   ============================================================ */
@media (prefers-color-scheme: dark) {
  /* サイドバーの濃緑ヘッダーはさらに沈める */
  html:not([data-theme="light"]) .side-head {
    background: linear-gradient(180deg,
      color-mix(in srgb, var(--green-900) 88%, black) 0%,
      color-mix(in srgb, var(--green-900) 74%, black) 100%);
    box-shadow:
      inset 0 1px 0 color-mix(in srgb, var(--on-brand-strong) 9%, transparent),
      0 1px 0 var(--line);
  }
  html:not([data-theme="light"]) .mini-badge {
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--green-900) 80%, black);
  }
  /* アバター / ルームアイコンの外周リングを明るい側に */
  html:not([data-theme="light"]) .avatar,
  html:not([data-theme="light"]) .room-icon {
    box-shadow:
      inset 0 0 0 1px rgba(255, 255, 255, .18),
      inset 0 -8px 14px rgba(0, 0, 0, .18),
      0 0 0 1px color-mix(in srgb, var(--txt) 16%, transparent);
  }
  /* トーストは暗背景に埋もれるので「浮いた面」として扱う */
  html:not([data-theme="light"]) .toast {
    background: var(--panel-2);
    color: var(--txt);
    box-shadow:
      inset 0 0 0 1px var(--line-strong),
      var(--shadow-3);
  }
  /* ⚠ 上の 1 本は :not([data-theme]) が属性セレクタとして数えられるため
     詳細度 (0,2,1)。16 節の .toast.toast-error (0,2,0) より強く、そのままだと
     ダークでエラートーストが「ただの灰緑の面」になって失敗が伝わらない。
     ここで赤い面を復帰させる（(0,3,1) で確実に勝つ）。値は 16 節と同一。 */
  html:not([data-theme="light"]) .toast.toast-error {
    background: color-mix(in srgb, var(--red) 74%, black);
    color: var(--on-brand-strong);
    box-shadow:
      inset 0 0 0 1px color-mix(in srgb, var(--red) 45%, transparent),
      var(--shadow-3);
  }
  /* 白面が浮きすぎるので、小さな面は panel-2 に寄せる */
  html:not([data-theme="light"]) .date-sep span,
  html:not([data-theme="light"]) .load-more button,
  html:not([data-theme="light"]) .msg-actions,
  html:not([data-theme="light"]) .file-chip { background: var(--panel-2); }
  html:not([data-theme="light"]) .react-chip.mine:hover {
    background: color-mix(in srgb, var(--brand) 28%, var(--panel));
  }
  html:not([data-theme="light"]) .msg-text img.inline-img { background: var(--panel-2); }
  /* アンケートカード: 白面が浮きすぎるので --panel-2 へ。
     .poll-opt のトラック（--bg-sunken）との段差も稼げる。 */
  html:not([data-theme="light"]) .poll-card {
    background: var(--panel-2);
    border-color: var(--line-strong);
  }
  /* カードが --panel-2 になるぶん、締切ボタンは --panel で一段沈めて輪郭を出す */
  html:not([data-theme="light"]) .poll-foot button { background: var(--panel); }
  /* 琥珀の帯は暗所で沈みやすいので、上端に細いハイライトを足して段差を作る */
  html:not([data-theme="light"]) .pin-bar {
    box-shadow:
      inset 0 1px 0 color-mix(in srgb, var(--amber) 22%, transparent),
      var(--shadow-1);
  }
  /* オーバーフローメニュー: .toast と同じ考え方。ダークでは --panel が背景と
     近すぎて「浮いている」ことが読めないので --panel-2 に上げ、内側 1px の
     リングで輪郭を立てる。.emoji-picker より一段強く浮かせるのは、こちらが
     「操作の分岐点」で滞在時間が長いため。 */
  html:not([data-theme="light"]) .more-menu {
    background: var(--panel-2);
    box-shadow:
      inset 0 0 0 1px var(--line-strong),
      var(--shadow-3);
  }
  /* 概要タブの情報ブロック: --bg-sunken はダークで --panel より暗いので沈み方は
     正しい。ただし境目が消えるので薄いリングを足す。 */
  html:not([data-theme="light"]) .panel-info { box-shadow: inset 0 0 0 1px var(--line); }
}

html[data-theme="dark"] .side-head {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--green-900) 88%, black) 0%,
    color-mix(in srgb, var(--green-900) 74%, black) 100%);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--on-brand-strong) 9%, transparent),
    0 1px 0 var(--line);
}
html[data-theme="dark"] .mini-badge {
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--green-900) 80%, black);
}
html[data-theme="dark"] .avatar,
html[data-theme="dark"] .room-icon {
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, .18),
    inset 0 -8px 14px rgba(0, 0, 0, .18),
    0 0 0 1px color-mix(in srgb, var(--txt) 16%, transparent);
}
html[data-theme="dark"] .toast {
  background: var(--panel-2);
  color: var(--txt);
  box-shadow:
    inset 0 0 0 1px var(--line-strong),
    var(--shadow-3);
}
/* 自動版と同じ理由でエラートーストを赤に戻す（値は 16 節と同一）。 */
html[data-theme="dark"] .toast.toast-error {
  background: color-mix(in srgb, var(--red) 74%, black);
  color: var(--on-brand-strong);
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--red) 45%, transparent),
    var(--shadow-3);
}
html[data-theme="dark"] .date-sep span,
html[data-theme="dark"] .load-more button,
html[data-theme="dark"] .msg-actions,
html[data-theme="dark"] .file-chip { background: var(--panel-2); }
html[data-theme="dark"] .react-chip.mine:hover {
  background: color-mix(in srgb, var(--brand) 28%, var(--panel));
}
html[data-theme="dark"] .msg-text img.inline-img { background: var(--panel-2); }

/* アンケートカード: 白面が浮きすぎるので --panel-2 へ。
   .poll-opt のトラック（--bg-sunken）との段差も稼げる。 */
html[data-theme="dark"] .poll-card {
  background: var(--panel-2);
  border-color: var(--line-strong);
}
/* カードが --panel-2 になるぶん、締切ボタンは --panel で一段沈めて輪郭を出す */
html[data-theme="dark"] .poll-foot button { background: var(--panel); }
/* 琥珀の帯は暗所で沈みやすいので、上端に細いハイライトを足して段差を作る */
html[data-theme="dark"] .pin-bar {
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--amber) 22%, transparent),
    var(--shadow-1);
}
/* オーバーフローメニュー: .toast と同じ考え方。ダークでは --panel が背景と
   近すぎて「浮いている」ことが読めないので --panel-2 に上げ、内側 1px の
   リングで輪郭を立てる。.emoji-picker より一段強く浮かせるのは、こちらが
   「操作の分岐点」で滞在時間が長いため。 */
html[data-theme="dark"] .more-menu {
  background: var(--panel-2);
  box-shadow:
    inset 0 0 0 1px var(--line-strong),
    var(--shadow-3);
}
/* 概要タブの情報ブロック: --bg-sunken はダークで --panel より暗いので沈み方は
   正しい。ただし境目が消えるので薄いリングを足す。 */
html[data-theme="dark"] .panel-info { box-shadow: inset 0 0 0 1px var(--line); }


/* ============================================================
   20. レスポンシブ
   ============================================================ */

/* --- 中間幅: 右パネルは退避し、開いた時だけオーバーレイ --- */
/* 右パネルの出し方は「画面幅」ではなく「利用者が開いているかどうか(.open)」で決める。
   以前は 1100px を切ると問答無用で隠していたため、1000px 級のノートPCでは
   右パネルの存在ごと気づけなかった。
   ・900px 以上 … 一覧・トーク・右パネルの3列を並べる (Chatwork と同じ)
   ・900px 未満 … トークが潰れるので、右から重ねて出す
   開いているかどうかは覚えていて、次に開いたときも同じ状態になる。 */
.panel:not(.open) { display: none !important; }

@media (max-width: 900px) {
  .panel.open {
    position: absolute;
    right: 0;
    top: 0;
    bottom: 0;
    z-index: 30;
    box-shadow: var(--shadow-3);
    border-left: 1px solid var(--line-strong);
    animation: eco-panel-in var(--dur-slow) var(--ease-out) both;
  }
}

/* 3列に並べるとトークの幅が 360px 級になり、チャット名が数文字まで潰れる。
   顔の並びとルームアイコンを先に畳んで、名前に幅を回す。 */
@media (max-width: 1023px) {
  .member-strip { display: none !important; }
  .chat-head .room-icon,
  #chHeadIcon { display: none; }
  .chat-head-actions button { width: 32px; height: 32px; }
}

/* --- タップ端末（ホバーがない）: ホバーの代わりにタップで操作を出す --- */
@media (hover: none) {
  .msg:hover { background: transparent; }
  .msg.mention-me:hover { background: var(--l3-mention-bg); }
  .msg:hover .msg-actions { display: none; }
  .msg.tapped { background: var(--l3-msg-hover); }
  .msg.tapped.mention-me {
    background: color-mix(in srgb, var(--txt) 5%, var(--l3-mention-bg));
  }
  .msg.tapped .msg-actions { display: flex; }
  .msg-actions button { padding: 10px 12px; font-size: var(--fs-md); }
  .react-chip { min-height: 28px; padding: 3px 11px; }
  /* タップ後にホバー状態が残るのを防ぐ */
  .react-chip:hover {
    background: var(--l3-chip-bg);
    color: var(--txt-sub);
    box-shadow: none;
    transform: none;
  }
  .react-chip.mine:hover { background: var(--l3-chipmine-bg); color: var(--l3-chipmine-fg); }
  .chat-item:not(.on):hover { background: transparent; }
  .chat-item:not(.on):active { background: var(--bg-sunken); }
  .td-del { opacity: 1; }

  /* 追加コンポーネント: タップ後にホバー状態が残らないようにする */
  .pin-row:hover { background: transparent; }
  .pin-row:active { background: color-mix(in srgb, var(--amber) 16%, var(--warn-bg)); }
  .poll-opt:hover { border-color: var(--line-strong); box-shadow: none; }
  .poll-opt.mine:hover,
  .poll-opt[aria-checked="true"]:hover {
    border-color: var(--brand);
    box-shadow: inset 0 0 0 1px var(--brand);
  }
  .new-pill:hover { background: var(--brand); transform: none; }
}

/* --- モバイル（760px 以下）: タップ領域は最低 44px --- */
@media (max-width: 760px) {
  :root {
    /* 小画面では1行が短いぶん少し大きく、行長制限は解除 */
    --l3-msg-fs: 15px;
    --l3-msg-lh: 1.78;
    --l3-measure: none;
  }

  .app, .auth, .call-view { height: 100dvh; }

  /* モバイル専用要素をここで初めて出す */
  .mobile-only {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
  }

  /* 1画面切り替え: 一覧 ⇄ トーク */
  .sidebar { width: 100%; min-width: 0; border-right: none; }
  .main { display: none; }
  .app.chat-open .sidebar { display: none; }
  .app.chat-open .main { display: flex; }

  /* 右パネルは全画面オーバーレイ */
  .panel.open {
    position: fixed;
    inset: 0;
    width: 100%;
    min-width: 0;
    z-index: 40;
    border-left: none;
  }
  #btnPanelClose {
    flex: 0 0 52px;
    min-height: 44px;
    font-size: calc(20px * var(--ui-scale));
    color: var(--txt-sub);
  }
  .panel-tabs button { min-height: 46px; padding: 12px 2px; }
  .panel-body { padding: var(--space-3); }

  /* サイドバー */
  .side-head { padding: var(--space-2) var(--space-3); }
  .side-actions button { width: 44px; height: 44px; font-size: calc(19px * var(--ui-scale)); }
  .mini-badge { top: 2px; right: 2px; }
  .side-search { padding: var(--space-2) var(--space-3); }
  .side-search input { font-size: max(16px, calc(16px * var(--ui-scale))); padding: 11px 12px; min-height: 44px; } /* iOSの自動ズーム防止 */
  .side-search button { width: 44px; min-width: 44px; min-height: 44px; font-size: calc(20px * var(--ui-scale)); }
  .side-tabs { padding: var(--space-2) var(--space-3) var(--space-1); }
  .side-tabs button { min-height: 34px; padding: 8px 12px; font-size: var(--fs-sm); }

  /* チャット一覧 */
  .chat-item { padding: 12px 10px 12px 13px; min-height: 60px; }

  /* チャットヘッダー */
  .chat-head { padding: var(--space-2); gap: var(--space-2); min-height: 52px; }
  #btnBack {
    font-size: calc(20px * var(--ui-scale));
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border-radius: var(--radius-sm);
    color: var(--brand-ink);
    flex-shrink: 0;
  }
  #btnBack:active { background: var(--bg-sunken); }
  /* 6個 × 44px + 戻る + ルームアイコンで 390px を超え、
     チャット名(.chat-head-txt)が幅0まで潰れて完全に読めなくなっていた。
     - ルームアイコンは戻るボタンの隣で情報量が薄いので小画面では隠す
     - アイコンの実寸は 38px に落とす（タップ領域は
       @media (pointer: coarse) の ::after が 44px まで広げるので確保される） */
  /* DM では app.js が #chHeadIcon を .avatar に差し替えるので id でも押さえる */
  .chat-head .room-icon,
  #chHeadIcon { display: none; }
  /* 320px 級（iPhone SE 第1世代など）では 38px × 6 + 戻る + チャット名が
     入りきらず、ページ全体に横スクロールが出て一番右のボタン
     (#btnTogglePanel) が画面外に落ちていた。
     ブレークポイントを増やさず「入らないときだけ縮む」ようにする:
       ・.chat-head-actions を縮小可（flex-shrink:1 / min-width:0）にする
       ・ボタンは width:38px を保ったまま最小 30px までなら縮む
     .chat-head-txt は flex-basis:0 なので縮み量の配分がここには回らず、
     390px 以上では 38px のまま一切変わらない（実測で確認）。
     タップ領域は @media (pointer: coarse) の ::after が 44px まで広げる。 */
  .chat-head-actions {
    gap: 0;
    flex-shrink: 1;
    min-width: 0;
  }
  .chat-head-actions button {
    font-size: calc(17px * var(--ui-scale));
    width: 38px;
    height: 38px;
    flex: 0 1 auto;
    min-width: 30px;
  }
  .chat-head-txt { min-width: 4.5em; }
  .chat-head-name { font-size: var(--fs-md); }
  .chat-head-sub { display: none; }

  /* メッセージ領域 */
  .msg-scroll { padding: var(--space-4) var(--space-2) var(--space-1); }
  .msg { padding: 6px 6px 6px 10px; gap: var(--space-2); }
  .msg-text { max-width: 100%; }
  .msg-text img.inline-img { max-width: 100%; max-height: 320px; }
  .msg-actions { right: var(--space-2); max-width: calc(100% - var(--space-3)); }
  .sys-inner { font-size: var(--fs-sm); }
  .typing { padding: 2px var(--space-3) 5px; }

  /* 入力欄 */
  .composer {
    padding: var(--space-2) var(--space-2)
             max(var(--space-3), env(safe-area-inset-bottom));
  }
  .composer-row textarea { font-size: max(16px, calc(16px * var(--ui-scale))); padding: 10px 12px; } /* iOSの自動ズーム防止 */
  .composer-row { gap: var(--space-2); }
  .composer-tools button { padding: 8px 11px; font-size: var(--fs-md); }
  .sendkey { display: none; }
  .btn-primary { padding: 10px 16px; }

  /* TODO / 添付 */
  .todo-row { padding: 12px 6px; gap: var(--space-2); }
  .td-del { padding: 8px 10px; }
  .file-chip { padding: 9px 12px; }

  /* 認証 */
  .auth { padding: var(--space-3); }
  .auth-card { width: min(380px, 92vw); padding: var(--space-5) var(--space-4); }
  .auth-card input { font-size: max(16px, calc(16px * var(--ui-scale))); min-height: 46px; }
  .auth-card .btn-primary { min-height: 48px; }

  /* 通話 */
  .call-grid { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); padding: 0 var(--space-3); gap: var(--space-2); }
  .call-head { padding: var(--space-3); font-size: var(--fs-sm); }
  .call-ctrl { gap: var(--space-3); padding: var(--space-4) var(--space-3); }
  .call-ctrl button { width: 52px; height: 52px; }
  .call-ctrl button.hangup { padding: 0 18px; min-width: 52px; }

  /* モーダル */
  /* ★ スマホでは「画面いっぱいのページ」として開く。
     小さな箱が浮くポップアップだと、
       ・後ろが透けて、いまどこを見ているのか分からない
       ・一覧が短くしか出ず、何度もスクロールが要る
       ・端を押すと勝手に閉じて、書きかけが消える
     という声があった。パソコンはこれまでどおり中央の箱のまま。 */
  .modal-wrap {
    padding: 0;
    align-items: stretch;
    justify-content: stretch;
    background: var(--panel);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    /* ★ 下バーは隠さない。ページを開いたまま、下バーで行き来できるようにする。
       そのため下バー(z-index:60)より奥に置き、下バーの高さぶん空けておく。 */
    z-index: 55;
    /* ★ --vv-top / --vv-bottom は、キーボードや日付の選択盤で
       「見えている範囲」が縮んだぶん。app.js の syncViewportVars() が入れる。
       これを足さないと、iPhoneで日付の欄を押したときに
       画面がふわふわ動く (「うにゃうにゃ動く」と報告を受けた)。
       選択盤が出ていないときは両方 0px なので、見た目は変わらない。 */
    top: var(--vv-top, 0px);
    bottom: calc(var(--nav-h) + env(safe-area-inset-bottom, 0px) + var(--vv-bottom, 0px));
  }
  .modal {
    width: 100%;
    max-width: none;
    max-height: none;
    height: 100%;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    display: flex;
    flex-direction: column;
  }
  /* 見出しは上に貼り付けて、閉じるボタンをいつでも押せるようにする */
  /* 見出しは中央に大きく。左右のボタンは端に置く。
     チャットワークのアプリと同じ並びにして、迷わないようにする。 */
  .modal-head {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--panel);
    border-bottom: 1px solid var(--line);
    justify-content: center;
    text-align: center;
    font-size: calc(17px * var(--ui-scale));
    font-weight: 700;
    min-height: 52px;
  }
  .modal-head button[data-close] {
    position: absolute;
    right: var(--space-2);
    top: 50%;
    transform: translateY(-50%);
  }
  .modal-body { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; }
  /* 決定ボタンは下に貼り付ける。長い一覧の一番下まで
     スクロールしないと押せない、という状態を作らない。 */
  .modal-foot {
    position: sticky;
    bottom: 0;
    background: var(--panel);
    border-top: 1px solid var(--line);
    padding-bottom: max(var(--space-3), env(safe-area-inset-bottom));
  }
  .modal input, .modal textarea, .modal select { font-size: max(16px, calc(16px * var(--ui-scale))); min-height: 46px; }
  /* 日付の見本も、本物と同じ大きさにする。
     ずれると、触った瞬間に文字の大きさが変わって見える */
  .modal .date-ph { font-size: max(16px, calc(16px * var(--ui-scale))); }
  .modal textarea { min-height: 96px; }
  .modal-head { padding: var(--space-3) var(--space-4); }
  .modal-head button { width: 44px; height: 44px; font-size: calc(22px * var(--ui-scale)); }
  /* 下バーから開いたページには × を出さない。
     行き来は下バーでするので、閉じるボタンは要らない。
     ただし、チャットの設定など下バー以外から開いた画面には残す。
     残さないと、開いたあと戻る手段が無くなってしまう。 */
  .modal-wrap.nav-page .modal-head button[data-close] { display: none; }
  .modal-body { padding: var(--space-3) var(--space-4) var(--space-4); }
  .modal-foot { padding: var(--space-3) var(--space-4); }
  .pick-row { min-height: 46px; padding: var(--space-2); }
  .color-dots span { width: 32px; height: 32px; }
  .search-result { padding: 12px var(--space-2); min-height: 46px; }
  .tabbar button { min-height: 44px; padding: 10px 14px; }

  /* パネル内リスト */
  .file-row { min-height: 52px; }
  .file-row .btn-ghost { min-height: 40px; display: inline-flex; align-items: center; }
  .member-row { min-height: 52px; }
  .task-check input[type=checkbox] { width: 20px; height: 20px; }

  /* オーバーレイ類 */
  .emoji-picker { width: min(264px, 92vw); padding: var(--space-2); }
  .emoji-picker button { font-size: calc(22px * var(--ui-scale)); }
  .toast { bottom: 18px; font-size: var(--fs-sm); }

  /* 固定メッセージ / アンケート / 予約行 / 空表示 / 新着ピル */
  .poll-who { display: none; }   /* 全員ぶんは title / aria-label に入っている */
  .poll-card { max-width: 100%; padding: var(--space-3); }
  .poll-count { font-size: var(--fs-md); }

  /* iOS はフォーカス時に 16px 未満の入力欄を勝手に拡大する。
     .composer-row textarea と同じ 16px に揃える（--l3-msg-fs は 15px）。 */
  .edit-ta { font-size: max(16px, calc(16px * var(--ui-scale))); line-height: 1.7; padding: 10px 12px; }

  /* 予約行は 2 段に折る。
     1段目 = 日時チップ + ルーム名 +（右端に）取消
     2段目 = 本文（flex-basis 100% で必ず改行し、省略せず 2〜3 行まで見せる）
     取消ボタンを本文から物理的に引き離すことで、狭い画面でも誤タップしにくい。 */
  .sched-row { align-items: center; padding: var(--space-3) var(--space-1); }
  .sched-when  { order: 1; }
  .sched-where { order: 2; }
  .sched-del   { order: 3; margin-left: auto; }
  .sched-body  {
    order: 4;
    flex: 1 1 100%;
    white-space: normal;
    overflow: visible;
    overflow-wrap: anywhere;
    font-size: var(--fs-sm);
  }

  .list-empty { padding: var(--space-5) var(--space-3); }
  #msgList > .list-empty { min-height: min(40vh, 260px); }
  .new-pill { max-width: calc(100% - var(--space-4) * 2); }

  /* オーバーフローメニュー: .more-wrap はツールバーの 5 番目。390px 幅では
     左端から約 180px の位置にあるので、left:0 のままだとメニューの右端が
     画面外に出る。右合わせに切り替えて内側へ倒す。
     （btnMore は .sendkey が display:none になるためツールバーの最右要素。
       右端 ≒ 256px、メニュー幅 220px → 左端 36px で収まる） */
  .more-menu {
    left: auto;
    right: 0;
    min-width: 220px;
    max-width: calc(100vw - var(--space-4));
    transform-origin: bottom right;
  }
  .more-menu button { min-height: 44px; font-size: var(--fs-lg); }
}

/* --- 指で操作する端末: 最小タップ領域 44px ---
   レイアウトを壊さないよう、::after の透明オーバーレイで当たり判定だけ広げる。
   横方向は「隣のボタンの領域を奪わない」上限（+8px）を設けている。 --- */
@media (pointer: coarse) {
  .side-actions button,
  .chat-head-actions button,
  .composer-tools button,
  .modal-head button,
  .td-del,
  #btnNewChat,
  #btnBack,
  #btnPanelClose,
  #btnCancelReply { position: relative; }

  .side-actions button::after,
  .chat-head-actions button::after,
  .composer-tools button::after,
  .modal-head button::after,
  .td-del::after,
  #btnNewChat::after,
  #btnBack::after,
  #btnPanelClose::after,
  #btnCancelReply::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 44px;
    height: 44px;
    min-width: 100%;
    min-height: 100%;
    max-width: calc(100% + 8px);
    transform: translate(-50%, -50%);
    background: transparent;   /* 見た目には出さない。当たり判定だけ */
    border-radius: inherit;
    pointer-events: auto;
  }

  /* ヘッダーのアイコンは実寸も少し大きくする（サイドバーは横に余裕がある） */
  .side-actions button { width: 40px; height: 40px; }
  #btnNewChat { min-width: 40px; }

  /* 絵文字ピッカーは 8列だとセルが 30px 弱になるので、列を減らして指で押せる大きさに */
  .emoji-picker {
    grid-template-columns: repeat(6, 1fr);
    width: min(304px, 92vw);
  }
  .emoji-picker button { min-height: 42px; }

  /* 面で押す要素は素直に高さを確保する */
  .btn-primary,
  .btn-ghost,
  .btn-danger { min-height: 44px; }
  .btn-sm { min-height: 38px; }
  .side-tabs button,
  .panel-tabs button,
  .tabbar button { min-height: 44px; }
  .msg-actions button { min-height: 44px; }
  .chat-item,
  .member-row,
  .pick-row,
  .file-row,
  .search-result { min-height: 48px; }
  .todo-row input[type="checkbox"],
  .task-check input[type="checkbox"],
  .pick-row input[type="checkbox"] { width: 20px; height: 20px; }
  .color-dots span { width: 32px; height: 32px; }
}

/* --- 520px 以下: 接続断バナーの補足文を 2 行に落とす ---
   区切り線のまま折り返すと中途半端な位置で切れるので、線をやめて改行させる。 --- */
@media (max-width: 520px) {
  .conn-banner .cb-sub {
    display: block;
    margin-left: 0;
    padding-left: 0;
    margin-top: 2px;
    border-left: none;
  }
}

/* --- 420px 以下: 通話コントロールを折り返す ---
   #btnHangup の文言が「✕ 退出」→「✕ 通話を終了」に伸びたため、
   --fs-lg + アイコン 19px + gap 7px + padding 0 24px で約 164px。
   丸ボタン 3 個（モバイル 52px）と gap を足すと 360px 級で溢れる。
   最終手段として折り返しも許す（終了ボタンが 2 段目に落ちても押せる）。 --- */
@media (max-width: 420px) {
  .call-ctrl {
    flex-wrap: wrap;
    gap: var(--space-2);
    row-gap: var(--space-2);
    padding: var(--space-3) var(--space-2)
             max(var(--space-3), env(safe-area-inset-bottom));
  }
  .call-ctrl button.hangup {
    padding: 0 14px;
    font-size: var(--fs-md);
    gap: 5px;
    --icon-size: 17px;
  }
}


/* ============================================================
   21. アクセシビリティ
   ============================================================ */

/* --- prefers-contrast: more  境界線と文字コントラストを底上げする --- */
@media (prefers-contrast: more) {
  /* 面の境界を必ず見せる */
  .btn-ghost,
  .react-chip,
  .file-chip,
  .task-card,
  .box-info,
  .box-task,
  .modal,
  .emoji-picker,
  .msg-actions,
  .side-search input,
  .composer-row textarea,
  .auth-card input,
  .modal input[type="text"],
  .modal input[type="email"],
  .modal input[type="password"],
  .modal input[type="date"],
  .modal textarea,
  .modal select {
    border-color: var(--line-strong);
  }
  .sidebar { border-right-color: var(--line-strong); }
  .panel   { border-left-color:  var(--line-strong); }
  .chat-head, .composer, .side-search, .panel-tabs, .modal-head, .modal-foot,
  .tabbar, .call-bar { border-color: var(--line-strong); }

  /* 弱い文字色を一段濃くする */
  .ci-time, .ci-last, .msg-time, .msg-edited, .file-sub, .pick-sub,
  .sr-meta, .td-limit, .member-role, .chat-head-sub, .auth-sub,
  .panel-sec-title, .typing, .msg-deleted { color: var(--txt-sub); }
  ::placeholder { color: var(--txt-sub); opacity: 1; }

  /* 選択中の状態は背景色だけでなく枠でも示す */
  .chat-item.on,
  .chat-item[aria-selected="true"] { box-shadow: inset 0 0 0 2px var(--brand); }
  .side-tabs button.on,
  .side-tabs button[aria-selected="true"] { box-shadow: inset 0 0 0 1.5px var(--brand); }
  .chat-head-actions button.on,
  .chat-head-actions button[aria-pressed="true"] { box-shadow: inset 0 0 0 1.5px var(--brand); }
  .react-chip.mine { box-shadow: inset 0 0 0 1.5px var(--brand); }
  .task-card.done { opacity: 1; }

  /* メンション行は背景色頼みなので左に帯を立てる */
  .msg.mention-me { box-shadow: inset 3px 0 0 0 var(--amber); }

  /* フォーカスリングを太く / リンクは下線で判別できるように */
  a:focus-visible,
  button:focus-visible,
  input:focus-visible,
  textarea:focus-visible,
  select:focus-visible,
  [tabindex]:focus-visible { outline-width: 3px; }
  a { text-decoration: underline; }

  /* 追加コンポーネントの境界と弱い文字を底上げする */
  .poll-card,
  .poll-opt,
  .sched-del,
  .poll-foot button,
  .edit-ta { border-color: var(--line-strong); }
  .pin-bar { border-bottom-color: var(--warn-txt); }
  .poll-sub,
  .poll-foot,
  .sched-where,
  .list-empty span,
  .list-empty.sm p,
  .chat-item .ci-last .ci-none,
  .panel-desc .muted { color: var(--txt-sub); }
  /* 「自分が選んだ」を枠の太さでも示す */
  .poll-opt.mine,
  .poll-opt[aria-checked="true"] { box-shadow: inset 0 0 0 2px var(--brand); }
}

/* --- forced-colors（Windows ハイコントラスト）: システム色に譲り、
       形と境界だけ担保する --- */
@media (forced-colors: active) {
  a:focus-visible,
  button:focus-visible,
  input:focus-visible,
  textarea:focus-visible,
  select:focus-visible,
  [tabindex]:focus-visible {
    outline: 3px solid Highlight;
    outline-offset: 2px;
    box-shadow: none;
  }
  .btn-primary,
  .btn-ghost,
  .btn-danger,
  .btn-sm { border: 1px solid ButtonText; }

  /* 背景色で状態を示している箇所を境界線に置き換える */
  .chat-item.on,
  .chat-item[aria-selected="true"],
  .side-tabs button.on,
  .side-tabs button[aria-selected="true"],
  .chat-head-actions button.on,
  .chat-head-actions button[aria-pressed="true"],
  .panel-tabs button.on,
  .panel-tabs button[aria-selected="true"],
  .tabbar button.on,
  .tabbar button[aria-selected="true"],
  .react-chip.mine { outline: 2px solid Highlight; outline-offset: -2px; }
  .msg.mention-me { outline: 1px solid Highlight; outline-offset: -1px; }

  /* 面が消える要素に輪郭を与える */
  .badge, .mini-badge, .avatar, .room-icon, .react-chip, .file-chip,
  .task-card, .box-info, .box-task, .box-code, .modal, .emoji-picker,
  .msg-actions, .toast, .conn-banner, .call-tile {
    border: 1px solid CanvasText;
    box-shadow: none;
  }
  .avatar .dot { border-color: CanvasText; background: Canvas; }
  .avatar .dot.on { background: Highlight; }
  /* マスクアイコンはシステム文字色で描く */
  .side-actions button::before,
  .chat-head-actions button::before,
  .composer-tools button::before,
  .more-menu button::before,
  .call-ctrl button::before { background-color: CanvasText; }
  .modal-wrap { background: Canvas; }

  /* 追加コンポーネント: システム色に譲り、形と境界だけ担保する */
  .pin-bar,
  .poll-card,
  .poll-opt,
  .new-pill,
  .sched-del,
  .poll-foot button,
  .sched-when,
  .poll-closed-tag,
  .more-menu,
  .list-empty.err::before {
    border: 1px solid CanvasText;
    box-shadow: none;
  }
  /* 面の塗りは強制的に Canvas になるので、得票バーは「下端のレール」に組み替える。
     width（インライン style）はそのまま得票率として生きる。 */
  .poll-bar {
    top: auto;
    bottom: 0;
    height: 4px;
    background: Highlight;
    box-shadow: none;
    border-radius: 0;
  }
  .poll-opt.mine,
  .poll-opt[aria-checked="true"] { outline: 2px solid Highlight; outline-offset: -3px; }
  .msg.pin-flash { outline-color: Highlight; }
}

/* --- モーション低減（必須）: すべての動きを止める --- */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-fast: 1ms;
    --dur: 1ms;
    --dur-slow: 1ms;
  }
  *,
  *::before,
  *::after {
    animation-delay: -1ms !important;
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-delay: 0s !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
  /* 移動・拡大の演出そのものを消す（1ms でも一瞬跳ねるため） */
  .modal-wrap, .modal, .toast, .emoji-picker, .conn-banner,
  .call-bar, .reply-preview, .panel.open, .call-view, .auth-card,
  .msg, .badge, .mini-badge,
  .msg:hover .msg-actions, .msg.tapped .msg-actions { animation: none !important; }
  .typing::before { animation: none !important; opacity: 1; transform: none; }

  .chat-item:active, .react-chip:active, .react-chip:hover,
  .file-chip:active, .load-more button:active, .search-result:active,
  .member-row:active, .pick-row:active,
  .btn-primary:active, .btn-ghost:active, .btn-danger:active,
  .side-actions button:active, .chat-head-actions button:active,
  .composer-tools button:active, .emoji-picker button:active,
  .emoji-picker button:hover, .color-dots span:hover,
  .msg-actions button:active, .panel-tabs button:active,
  .side-tabs button:active, .modal-head button:active,
  .td-del:active, .call-ctrl button:active { transform: none; }

  /* 第2次で足した動きは 1ms でも一瞬跳ねるので名指しで殺す。
     ⚠ .new-pill は translateX(-50%) を使わない設計（align-self: center）なので、
       transform を消してもレイアウトはずれない。 */
  .msg.pin-flash,
  .poll-bar,
  .new-pill,
  .more-menu { animation: none !important; }
  /* .poll-bar は animation を消すと transform 初期値（= scaleX(1)）に戻る。
     width（インライン style）だけで正しい長さになる。 */
  .poll-bar { transform: none; }
  .pin-off:active,
  .poll-foot button:active,
  .sched-del:active,
  .new-pill:hover,
  .new-pill:active,
  .more-menu button:active,
  .panel-tabs .panel-close:active,
  .panel-leave #pLeave:active,
  .call-head .btn-hangup-top:active { transform: none; }
}


/* ============================================================
   22. 絵文字アイコンの SVG 化 (CSSのみ / index.html の固定ボタンのみ)
   手法: 対象ボタンを font-size:0 で文字ノードごと潰し、::before に
         mask-image (data URI SVG) + background-color: currentColor で線画を描く。
         色は必ず currentColor 経由なので、.on / .off / ホバーの色変化が
         そのままアイコンに反映される。
   マスク内の SVG は「アルファ」しか使われないため色指定は不要
   (stroke='currentColor' は画像文書側の初期色に解決される)。
   非対応ブラウザでは @supports が丸ごと効かず、絵文字のまま表示される。
   ============================================================ */
@supports ((-webkit-mask-image: none) or (mask-image: none)) {

  /* --- アイコン描画の共通実装 --- */
  /* ⚠ #btnInsInfo / #btnInsCode / #btnInsHr はこのグループに入れないこと。
     現行マークアップではこの 3 つが #composerMore の中の「アイコン + ラベル」
     のメニュー項目になったため、font-size:0 にするとラベルごと消える。
     絵文字だけを畳む指定は下の .more-menu button > span[aria-hidden] にある。 */
  #btnGlobalSearch, #btnMyTasks, #btnContacts,
  #btnCall, #btnPin, #btnMute, #btnRoomSearch, #btnRoomSettings, #btnTogglePanel,
  #btnEmoji, #btnAttach,
  #btnMic, #btnCam, #btnShare {
    font-size: 0;
    line-height: 0;
    letter-spacing: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  #btnGlobalSearch::before, #btnMyTasks::before, #btnContacts::before,
  #btnCall::before, #btnPin::before, #btnMute::before, #btnRoomSearch::before,
  #btnRoomSettings::before, #btnTogglePanel::before,
  #btnEmoji::before, #btnAttach::before,
  .more-menu button::before,
  #btnMic::before, #btnCam::before, #btnShare::before,
  #btnHangup::before {
    content: "";
    display: block;
    flex: 0 0 auto;
    width: var(--icon-size);
    height: var(--icon-size);
    background-color: currentColor;
    -webkit-mask-image: var(--icon);
            mask-image: var(--icon);
    -webkit-mask-repeat: no-repeat;
            mask-repeat: no-repeat;
    -webkit-mask-position: center;
            mask-position: center;
    -webkit-mask-size: contain;
            mask-size: contain;
  }

  /* --- ヘッダー左上 (濃緑サーフェス上 / 32px ボタン) --- */
  #btnGlobalSearch, #btnMyTasks, #btnContacts { --icon-size: 19px; }

  /* 親を font-size:0 にしたので、バッジ側で明示的に文字サイズを戻す。
     ※ 値は 07 節の .mini-badge と同値。07 節を変更したらここも合わせること。 */
  #btnMyTasks .mini-badge,
  #btnContacts .mini-badge {
    font-size: calc(10px * var(--ui-scale));
    line-height: 16px;
    letter-spacing: normal;
  }

  #btnGlobalSearch {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20.5 20.5 16 16'/%3E%3C/svg%3E");
  }
  #btnMyTasks {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.5 2.8H6.6a2 2 0 0 0-2 2v14.4a2 2 0 0 0 2 2h10.8a2 2 0 0 0 2-2V7.7z'/%3E%3Cpath d='M14.5 2.8v5h5'/%3E%3Cpath d='M8.4 13h7.2'/%3E%3Cpath d='M8.4 16.7h4.6'/%3E%3C/svg%3E");
  }
  #btnContacts {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9.3' cy='7.6' r='3.6'/%3E%3Cpath d='M2.8 20.4c0-3.4 2.9-5.6 6.5-5.6s6.5 2.2 6.5 5.6'/%3E%3Cpath d='M16.4 4.4a3.6 3.6 0 0 1 0 6.8'/%3E%3Cpath d='M18 15.2c1.9.8 3.2 2.5 3.2 5.2'/%3E%3C/svg%3E");
  }

  /* --- チャットヘッダー右側 (34px ボタン) --- */
  #btnCall, #btnPin, #btnMute, #btnRoomSearch,
  #btnRoomSettings, #btnTogglePanel { --icon-size: 18px; }
  /* ピンだけは一回り大きく (見つけやすさを優先) */
  #btnPin { --icon-size: 21px; }
  /* 留めているときは中を塗って、離れて見ても状態が分かるようにする */
  #btnPin.on {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 3.4h6'/%3E%3Cpath d='M10 3.4 9.2 10l-3 3.4a1 1 0 0 0 .8 1.6h10a1 1 0 0 0 .8-1.6L14.8 10 14 3.4'/%3E%3Cpath d='M12 15v5.8' fill='none'/%3E%3C/svg%3E");
  }

  #btnCall {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21.5 16.9v3a2 2 0 0 1-2.2 2 19.8 19.8 0 0 1-8.6-3.1 19.5 19.5 0 0 1-6-6A19.8 19.8 0 0 1 1.6 4.2 2 2 0 0 1 3.6 2h3a2 2 0 0 1 2 1.7c.1 1 .4 1.9.7 2.8a2 2 0 0 1-.5 2.1L7.6 9.9a16 16 0 0 0 6 6l1.3-1.3a2 2 0 0 1 2.1-.4c.9.3 1.8.6 2.8.7a2 2 0 0 1 1.7 2z'/%3E%3C/svg%3E");
  }
  #btnPin {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 3.4h6'/%3E%3Cpath d='M10 3.4 9.2 10l-3 3.4a1 1 0 0 0 .8 1.6h10a1 1 0 0 0 .8-1.6L14.8 10 14 3.4'/%3E%3Cpath d='M12 15v5.8'/%3E%3C/svg%3E");
  }
  #btnMute {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 8.6a6 6 0 0 0-12 0c0 6.4-2.5 8.4-2.5 8.4h17S18 15 18 8.6'/%3E%3Cpath d='M13.7 20.5a2 2 0 0 1-3.4 0'/%3E%3C/svg%3E");
  }
  /* ミュート中 (.on) はベルに斜線 */
  #btnMute.on {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M13.7 20.5a2 2 0 0 1-3.4 0'/%3E%3Cpath d='M18.6 13.6A18.6 18.6 0 0 1 18 8.6'/%3E%3Cpath d='M6.3 6.9A6 6 0 0 0 6 8.6C6 15 3.5 17 3.5 17h13'/%3E%3Cpath d='M18 8.6a6 6 0 0 0-9.4-4.9'/%3E%3Cpath d='M2.6 2.6 21.4 21.4'/%3E%3C/svg%3E");
  }
  #btnRoomSearch {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20.5 20.5 16 16'/%3E%3C/svg%3E");
  }
  #btnRoomSettings {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3Cpath d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z'/%3E%3C/svg%3E");
  }
  #btnTogglePanel {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4.5' width='18' height='15' rx='2.5'/%3E%3Cpath d='M14.6 4.5v15'/%3E%3C/svg%3E");
  }

  /* --- 入力欄ツールバー（直に並ぶ 2 つ） --- */
  #btnEmoji, #btnAttach {
    --icon-size: 17px;
    padding-left: 7px;
    padding-right: 7px;
  }

  #btnEmoji {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M8.3 14.1a4.4 4.4 0 0 0 7.4 0'/%3E%3Cpath d='M9.2 9.4h.01'/%3E%3Cpath d='M14.8 9.4h.01'/%3E%3C/svg%3E");
  }
  #btnAttach {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21.4 11.1 12.2 20.2a6 6 0 0 1-8.5-8.5l9.2-9.2a4 4 0 0 1 5.7 5.7l-9.2 9.2a2 2 0 0 1-2.8-2.8l8.5-8.5'/%3E%3C/svg%3E");
  }
  /* --- ここから下の 3 つは #composerMore（オーバーフローメニュー）の中の項目。
     ツールバーには直接並ばないので padding / font-size は .more-menu button に任せ、
     ここでは --icon だけを与える。 --- */
  #btnInsInfo {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4.5' width='18' height='15' rx='2.5'/%3E%3Cpath d='M3 9.4h18'/%3E%3Cpath d='M6.8 13.2h8.4'/%3E%3Cpath d='M6.8 16.2h5.4'/%3E%3C/svg%3E");
  }
  #btnInsCode {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15.5 5.5 20.8 12l-5.3 6.5'/%3E%3Cpath d='M8.5 5.5 3.2 12l5.3 6.5'/%3E%3C/svg%3E");
  }
  /* 罫線: 中央の実線が「罫線」、上下の薄い線が「前後の本文」。
     mask では SVG の opacity がそのままアルファに効くので濃淡が出せる。 */
  #btnInsHr {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.2 12h17.6'/%3E%3Cg opacity='.42'%3E%3Cpath d='M6.2 6.6h11.6'/%3E%3Cpath d='M6.2 17.4h11.6'/%3E%3C/g%3E%3C/svg%3E");
  }

  /* --- オーバーフローメニューの 5 項目 ---
     この 5 つは「アイコン + テキストラベル」の行なので、上のボタン群と違って
     font-size:0 で潰してはいけない（潰すとラベルが消える）。
     絵文字だけを畳んで ::before の線画に置き換え、5 項目とも同じ語彙に揃える。
     mask 非対応環境ではこの @supports ごと効かないので、5 項目すべてが
     元の絵文字のまま出る（このセクション末尾と同じ落ち方）。 */
  .more-menu button > span[aria-hidden="true"] {
    font-size: 0;
    line-height: 0;
    letter-spacing: 0;
  }
  .more-menu button { --icon-size: 17px; }
  .more-menu button::before { opacity: .72; }   /* ラベルを主、アイコンを従にする */
  .more-menu button:hover::before { opacity: 1; }

  /* アンケート: 棒グラフ */
  #btnPoll {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.8 20.4h16.4'/%3E%3Cpath d='M7.4 20.4v-6.2'/%3E%3Cpath d='M12 20.4V6.2'/%3E%3Cpath d='M16.6 20.4v-9.4'/%3E%3C/svg%3E");
  }
  /* 予約投稿: 時計 */
  #btnSchedule {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 6.9V12l3.4 2'/%3E%3C/svg%3E");
  }

  /* --- 通話コントロール (54px 丸ボタン) --- */
  #btnMic, #btnCam, #btnShare { --icon-size: 22px; }

  #btnMic {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='9' y='2.4' width='6' height='11.6' rx='3'/%3E%3Cpath d='M19 11.4a7 7 0 0 1-14 0'/%3E%3Cpath d='M12 18.4v3.2'/%3E%3Cpath d='M8.6 21.6h6.8'/%3E%3C/svg%3E");
  }
  #btnMic.off,
  #btnMic[aria-pressed="true"] {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 9.4v2.2a3 3 0 0 0 5.1 2.1'/%3E%3Cpath d='M15 11.2V5.4a3 3 0 0 0-5.9-.8'/%3E%3Cpath d='M17.5 16.4A7 7 0 0 1 5 11.4'/%3E%3Cpath d='M12 18.4v3.2'/%3E%3Cpath d='M8.6 21.6h6.8'/%3E%3Cpath d='M2.6 2.6 21.4 21.4'/%3E%3C/svg%3E");
  }
  #btnCam {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.5' y='6' width='13.5' height='12' rx='2.5'/%3E%3Cpath d='M16 10.4 21.5 7.4v9.2L16 13.6z'/%3E%3C/svg%3E");
  }
  #btnCam.off,
  #btnCam[aria-pressed="true"] {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M16 13.4V15.5a2.5 2.5 0 0 1-2.5 2.5H5a2.5 2.5 0 0 1-2.5-2.5v-7A2.5 2.5 0 0 1 5 6h1.4'/%3E%3Cpath d='M10.8 6h2.7A2.5 2.5 0 0 1 16 8.5v1.9l5.5-3v9.2'/%3E%3Cpath d='M2.6 2.6 21.4 21.4'/%3E%3C/svg%3E");
  }
  #btnShare {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.5' y='4' width='19' height='13' rx='2.5'/%3E%3Cpath d='M12 17v3.5'/%3E%3Cpath d='M8.5 20.5h7'/%3E%3C/svg%3E");
  }
  /* 共有中は「画面共有をやめる」= 斜線入りのモニターに差し替える。
     ⚠ これは飾りではなく必須。app.js 2571行は共有中に span の絵文字を
       🖥️ → 🛑 に差し替えて形でも状態を示しているが、このセクションは
       その span を font-size:0 で畳んで ::before の線画に置き換えるため、
       --icon を切り替えないと「形の変化」が丸ごと消える。
       残るのは 15 節の面の色だけで、通常時 rgb(16,42,29) と
       共有中 rgb(24,67,45) の差は実測 1.37:1 しかなく状態が判別できない
       （WCAG 1.4.1 / 1.4.11）。
     app.js は共有開始で .on を足し（2599行）、aria-pressed も true になる
     （2571行の set() は !on を入れるので sharing のとき true）。
     .off は join 時に必ず除去される（2467行）ので実際には当たらないが、
     万一の取りこぼしに備えて同じ絵を当てておく。 */
  #btnShare.on,
  #btnShare[aria-pressed="true"],
  #btnShare.off {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21.5 15.6V6.5A2.5 2.5 0 0 0 19 4H7.4'/%3E%3Cpath d='M2.6 5.7A2.5 2.5 0 0 0 2.5 6.5v8A2.5 2.5 0 0 0 5 17h13.4'/%3E%3Cpath d='M12 17v3.5'/%3E%3Cpath d='M8.5 20.5h7'/%3E%3Cpath d='M2.6 2.6 21.4 21.4'/%3E%3C/svg%3E");
  }

  /* --- 退出ボタンだけはテキスト「✕ 退出」を残し、アイコンを添える ---
     ボタンの文字がすでに「✕」で否定を表しているので、アイコン側には
     斜線を入れない。受話器を伏せた向き（通話終了の定番の形）だけで示す。 */
  #btnHangup {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    --icon-size: 19px;
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 9.5A15 15 0 0 1 12 7a15 15 0 0 1 8.5 2.5'/%3E%3Cpath d='M20.5 9.5c1.6 1.2 2 2.4 1.2 3.3l-1.6 1.8a1.6 1.6 0 0 1-2.1.2l-2-1.4a1.6 1.6 0 0 1-.7-1.6l.2-1.4'/%3E%3Cpath d='M3.5 9.5C1.9 10.7 1.5 11.9 2.3 12.8l1.6 1.8a1.6 1.6 0 0 0 2.1.2l2-1.4a1.6 1.6 0 0 0 .7-1.6l-.2-1.4'/%3E%3C/svg%3E");
  }

  /* --- 文字のままにするボタン: 字形だけ整える --- */
  /* #btnMe は中に .avatar が入るので font-size を潰さない */
  #btnNewChat, #btnNewTask, #btnTo, #btnBack, #btnPanelClose, #btnCancelReply {
    font-feature-settings: "palt" 1;
    letter-spacing: .02em;
  }
}

/* mask 非対応環境では絵文字のまま。せめて字形の縦位置だけ揃える。 */
@supports not ((-webkit-mask-image: none) or (mask-image: none)) {
  .side-actions button,
  .chat-head-actions button,
  .composer-tools button,
  .call-ctrl button { line-height: 1; }
  /* メニュー行はラベルが主なので行の line-height は保ち、絵文字だけ揃える */
  .more-menu button > span[aria-hidden="true"] { line-height: 1; }
}

/* ============================================================
   23. app.js のインライン style 救済
   HTML / JS は触れないため、属性セレクタ + !important でトークンに寄せる。
   （author の !important はインライン style より強い）
   対象は app.js 内の
     style="color:#999" / "color:#888" / "color:#b3722e" / "color:#7a5a16" /
     "border:1px solid #ecd9ae;background:#fdf8ec" / "background:#aaa"
   ※ ここは唯一「ライト/ダーク共通で常時効かせる」救済。
     スコープを絞った重複ルールは統合時に削除済み。

   ⚠ 文字色の救済は必ず "color:" まで含めて照合すること。
     色コードだけで照合すると background: 側にも当たる。とくに #b3722e は
     app.js 47行の COLORS（アバター / ルームアイコン / カラードットの
     パレット）に入っていて style="background:#b3722e" として出力される。
     [style*="#b3722e"] で書くと頭文字の色まで --amber になり、
     地の #b3722e との差が 1.29:1 になって文字が完全に消える（実測で確認）。
   ============================================================ */
[style*="color:#999"],
[style*="color:#888"] { color: var(--txt-sub) !important; }

[style*="color:#b3722e"] { color: var(--amber) !important; }

[style*="color:#7a5a16"] { color: var(--mention-chip-txt) !important; }

[style*="#ecd9ae"] {
  border-color: var(--warn-line) !important;
  background: var(--warn-bg) !important;
  color: var(--txt) !important;
}

[style*="background:#aaa"] { background: var(--avatar-fallback) !important; }


/* ============================================================
   24. 写真アイコン / 写真の切り抜き / 初回ガイド            (v2.8)
   ------------------------------------------------------------
   ■ 写真アイコン
     .avatar / .room-icon の中に <img> を1枚入れるだけにして、
     角丸・大きさ・オンライン点の位置は既存ルールをそのまま使う。
     地色(インラインstyle)は残す。読み込みが終わるまでの一瞬と、
     画像が壊れていたときに、穴が空いて見えないようにするため。

   ■ z-index の並び（既存スケールの続き）
     modal 50 / emoji 60 / 70 / toast 80 / conn-banner 90
       → guide 94（案内。トーストは上に出したいので下に置く）
       → cropper 96（モーダルの中から開くので modal(50) より必ず上）
   ============================================================ */

/* 写真は頭文字の「上に重ねる」。写真が読めなかったときに
   下の頭文字がそのまま出る = 丸が空白にならない。
   overflow:hidden にするとオンライン点(.dot)まで欠けるので、
   角丸は img 側で border-radius を継ぐ。 */
.avatar.has-photo,
.room-icon.has-photo { position: relative; }
.avatar.has-photo > img,
.room-icon.has-photo > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;      /* 縦長・横長どちらでも中央を切り出す */
  border-radius: inherit;
  display: block;
  /* 白い写真が白い面に溶けないよう、輪郭を1本だけ残す。
     img の inset box-shadow は画像そのものに隠れて見えないため outline を使う
     (outline は border-radius に沿って丸くなる)。 */
  outline: 1px solid color-mix(in srgb, var(--txt) 12%, transparent);
  outline-offset: -1px;
}
/* .dot は .avatar の直下に絶対配置されている。img が後から重なっても
   隠れないよう、点だけ前面に出す。 */
.avatar.has-photo > .dot { z-index: 1; }

/* グループ設定の大きいプレビュー */
.room-icon-l {
  width: 64px;
  height: 64px;
  font-size: calc(26px * var(--ui-scale));
  border-radius: var(--radius-lg, 14px);
}

/* ユーザー管理の行。写真ボタンが増えて4つになり、名前が縦に潰れて
   読めなくなっていたので、ボタン側だけを折り返してよいことにする。 */
.pick-btns {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  justify-content: flex-end;
  flex-shrink: 0;
  max-width: 55%;
}
.pick-row .pick-name { min-width: 130px; }

/* ---- プロフィール / グループ設定の写真編集ブロック ---- */
.photo-edit {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  padding: var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-sunken);
}
.photo-edit-prev { flex-shrink: 0; display: inline-flex; }
.photo-edit-side { min-width: 0; }
.photo-edit-btns { display: flex; gap: 8px; flex-wrap: wrap; }
.photo-edit-note {
  margin-top: 6px;
  font-size: var(--fs-xs, 11px);
  color: var(--txt-sub);
  line-height: 1.6;
}

/* ---- 写真の切り抜き画面 ---- */
.cropper-root {
  position: fixed;
  inset: 0;
  z-index: 96;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(12, 26, 19, .58);
  backdrop-filter: blur(2px);
}
.cropper-card {
  background: var(--panel);
  border-radius: var(--radius-lg, 14px);
  box-shadow: var(--shadow-3);
  padding: var(--space-4, 16px);
  max-width: 100%;
  max-height: 100%;
  overflow: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}
.cropper-head {
  font-weight: 700;
  font-size: var(--fs-lg, 16px);
  color: var(--txt);
  align-self: flex-start;
}
.cropper-stage {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg-sunken);
  flex-shrink: 0;
}
.cropper-canvas {
  display: block;
  cursor: grab;
  touch-action: none;      /* 指のドラッグを画面スクロールに取られない */
  user-select: none;
}
.cropper-canvas:active { cursor: grabbing; }
.cropper-canvas:focus-visible { outline: 3px solid var(--focus, #2e8fbf); outline-offset: -3px; }
/* 丸く切り抜かれる範囲を示す。canvas の操作を邪魔しないよう当たり判定は無し。 */
.cropper-ring {
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: var(--radius);
  box-shadow: inset 0 0 0 9999px rgba(12, 26, 19, .45);
  -webkit-mask: radial-gradient(circle at 50% 50%, transparent 0 calc(50% - 1px), #000 calc(50% - 1px));
  mask: radial-gradient(circle at 50% 50%, transparent 0 calc(50% - 1px), #000 calc(50% - 1px));
}
.cropper-zoom {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  font-size: var(--fs-sm, 13px);
  color: var(--txt-sub);
}
.cropper-zoom input { flex: 1; min-height: 32px; }
.cropper-hint {
  margin: 0;
  font-size: var(--fs-xs, 11px);
  color: var(--txt-sub);
  text-align: center;
  line-height: 1.6;
}
.cropper-foot {
  display: flex;
  gap: 8px;
  width: 100%;
  justify-content: flex-end;
}

/* ---- 初回ガイド ---- */
#guideRoot { position: fixed; inset: 0; z-index: 94; }
/* 案内中に背後を触られないようにする受け皿。
   .guide-spot の box-shadow はクリックを受け取らないので、別に1枚必要。 */
.guide-block { position: absolute; inset: 0; }
/* 対象の周りだけ明るく残し、外側を巨大な影で覆う。 */
.guide-spot {
  position: fixed;
  box-shadow: 0 0 0 9999px rgba(10, 24, 17, .62);
  border-radius: 12px;
  pointer-events: none;
  transition: left var(--dur, .18s) var(--ease, ease),
              top var(--dur, .18s) var(--ease, ease),
              width var(--dur, .18s) var(--ease, ease),
              height var(--dur, .18s) var(--ease, ease);
  outline: 2px solid rgba(255, 255, 255, .85);
  outline-offset: 0;
}
/* 特定の場所を指さない回 (最初と最後の挨拶)。画面全体を暗くするだけにする。 */
.guide-spot.center { outline: none; transition: none; }
.guide-card {
  position: fixed;
  width: min(340px, calc(100vw - 24px));
  background: var(--panel);
  color: var(--txt);
  border-radius: var(--radius-lg, 14px);
  box-shadow: var(--shadow-3);
  padding: 16px;
  transition: left var(--dur, .18s) var(--ease, ease), top var(--dur, .18s) var(--ease, ease);
}
.guide-step {
  font-size: var(--fs-xs, 11px);
  font-weight: 700;
  color: var(--txt-sub);
  letter-spacing: .04em;
}
.guide-title {
  margin: 4px 0 6px;
  font-size: var(--fs-lg, 16px);
  font-weight: 700;
  line-height: 1.5;
}
.guide-body {
  margin: 0;
  font-size: var(--fs-sm, 13px);
  line-height: 1.8;
  color: var(--txt-sub);
}
.guide-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
}

@media (max-width: 520px) {
  .guide-card { width: calc(100vw - 24px); }
  .photo-edit { flex-direction: column; align-items: flex-start; }
}

@media (prefers-reduced-motion: reduce) {
  .guide-spot, .guide-card { transition: none; }
}

/* 白黒反転などの強制配色では影が消えるため、線で位置を示す */
@media (forced-colors: active) {
  .guide-spot { outline: 3px solid Highlight; box-shadow: none; }
  .guide-card, .cropper-card { border: 1px solid CanvasText; }
  .avatar.has-photo > img, .room-icon.has-photo > img { border: 1px solid CanvasText; }
}


/* ============================================================
   25. スマホで「アプリとして」開いたときの見え方              (v2.8)
   ------------------------------------------------------------
   ホーム画面から起動するとブラウザのアドレスバーが無くなり、
   画面のいちばん端まで使える代わりに、iPhone の
     ・上部の切り欠き(ノッチ / ダイナミックアイランド)
     ・下部の横棒(ホームインジケーター)
     ・横向きにしたときの左右の丸み
   の下に中身が潜り込む。index.html の viewport-fit=cover と
   ここの env(safe-area-inset-*) を合わせて、そこだけ余白を足す。

   env() は対応していない環境や余白が不要な端末では 0 になるので、
   max() で「今までの余白」を下限にしておけば PC の見た目は一切変わらない。
   ============================================================ */

/* 画面の外まで指を滑らせたときの白いはみ出し(バウンス)を止める。
   全画面表示だとこれが「アプリが浮いて剥がれる」ように見えて気になる。 */
html, body { overscroll-behavior: none; }

@media (max-width: 760px) {
  /* 上端: サイドバーの見出しとチャットのヘッダー */
  .side-head { padding-top: max(var(--space-2), env(safe-area-inset-top)); }
  .chat-head { padding-top: max(var(--space-2), env(safe-area-inset-top)); }

  /* 右パネルは全画面で覆いかぶさるので、こちらにも上端の余白が要る */
  .panel.open .panel-tabs { padding-top: env(safe-area-inset-top); }

  /* 通話画面は上下ともに端まで広がる */
  .call-head { padding-top: max(var(--space-3), env(safe-area-inset-top)); }
  .call-ctrl { padding-bottom: max(var(--space-3), env(safe-area-inset-bottom)); }

  /* 横向きにしたときの左右。縦向きでは 0 になるので影響しない */
  .sidebar, .main, .panel.open, .call-view { padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right); }

  /* 画面に浮くもの: 下端に寄るものはホームバーの分だけ持ち上げる */
  .toast { bottom: max(26px, calc(env(safe-area-inset-bottom) + var(--space-3))); }
  .conn-banner { padding-top: max(8px, env(safe-area-inset-top)); }

  /* 一覧のいちばん下の行がホームバーに隠れないようにする */
  .chat-list { padding-bottom: env(safe-area-inset-bottom); }
  .panel-body { padding-bottom: max(var(--space-3), env(safe-area-inset-bottom)); }

  /* モーダルの操作ボタンがホームバーに重ならないようにする。
     .modal 側に margin を足すと縦位置がずれて上が切れるので、
     いちばん下の帯(.modal-foot)の内側で吸収する。 */
  .modal-foot { padding-bottom: max(var(--space-3), env(safe-area-inset-bottom)); }
}

/* ---- 「ホーム画面に追加」の案内 ---- */

/* 画面下からせり上がる帯。1回だけ出て、閉じたら二度と出ない。 */
.a2hs-bar {
  position: fixed;
  left: max(10px, env(safe-area-inset-left));
  right: max(10px, env(safe-area-inset-right));
  bottom: max(10px, calc(env(safe-area-inset-bottom) + 10px));
  z-index: 85;                       /* トースト(80)より上 / 接続断バナー(90)より下 */
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border-radius: var(--radius-lg, 14px);
  background: var(--panel);
  box-shadow: var(--shadow-3);
  border: 1px solid var(--line);
  animation: eco-drop-in var(--dur-slow, .28s) var(--ease-out, ease) both;
}
.a2hs-ico {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  flex-shrink: 0;
}
/* flex-basis は 0。auto にすると文章の長さが基準になり、折り返し可の親では
   アイコンと同じ行に収まらず、アイコンだけが1行目に取り残される。 */
.a2hs-txt { flex: 1 1 0; min-width: 0; font-size: var(--fs-sm, 13px); line-height: 1.6; }
.a2hs-txt b { display: block; font-size: var(--fs-md, 14px); }
.a2hs-btns { display: flex; gap: 8px; flex-shrink: 0; margin-left: auto; }

/* 文字とボタンを1行に並べると、iPhoneの幅では文言が
   3〜4行に折り返って読みづらくなる。狭い画面ではボタンを下の段へ落とす。 */
@media (max-width: 520px) {
  .a2hs-bar { flex-wrap: wrap; }
  .a2hs-btns { flex: 1 0 100%; justify-content: flex-end; margin-left: 0; }
  .a2hs-bar .btn-sm { min-height: 40px; padding-inline: 16px; }
}

/* 手順の説明 */
.a2hs-steps { counter-reset: a2hs; margin: 0; padding: 0; list-style: none; }
.a2hs-steps li {
  counter-increment: a2hs;
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 9px 0;
  font-size: var(--fs-sm, 13px);
  line-height: 1.75;
  border-bottom: 1px solid var(--line);
}
.a2hs-steps li:last-child { border-bottom: none; }
.a2hs-steps li::before {
  content: counter(a2hs);
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--brand-weak, var(--bg-sunken));
  color: var(--brand-ink, var(--txt));
  font-weight: 700;
  font-size: calc(12px * var(--ui-scale));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: 2px;
}
.a2hs-note {
  margin: 10px 0 0;
  font-size: var(--fs-xs, 11px);
  color: var(--txt-sub);
  line-height: 1.7;
}


/* ------------------------------------------------------------
   サーバーが古いままのときの警告帯                        (v2.8)
   public/ を差し替えてもサーバーを再起動していないと、
   画面には新しいボタンが出るのに押すと動かない、という
   一番わかりにくい壊れ方をする。原因と直し方をそのまま出す。
   z-index は接続断バナー(90)の下・トースト(80)の上。
   ------------------------------------------------------------ */
.stale-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 89;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 4px 10px;
  padding: 8px 44px 8px 14px;
  padding-top: max(8px, env(safe-area-inset-top));
  background: linear-gradient(180deg,
    var(--warn-solid) 0%,
    color-mix(in srgb, var(--warn-solid) 86%, black) 100%);
  color: var(--on-brand-strong);
  font-size: var(--fs-sm);
  font-weight: 600;
  line-height: 1.5;
  text-align: center;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .28);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .22);
  animation: eco-drop-in var(--dur-slow) var(--ease-out) both;
}
.stale-bar .sb-sub {
  font-weight: 400;
  font-size: var(--fs-xs);
  /* 親の地色に対して 4.6:1 以上を保つため、抜きは 92% までに留める
     (--warn-solid の上の白文字は元々余裕が少ない) */
  color: color-mix(in srgb, var(--on-brand-strong) 92%, transparent);
}
.stale-bar button {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  width: 34px;
  height: 34px;
  border: none;
  background: none;
  color: inherit;
  font-size: calc(20px * var(--ui-scale));
  line-height: 1;
  cursor: pointer;
  border-radius: 50%;
}
.stale-bar button:hover { background: rgba(0, 0, 0, .16); }


/* ============================================================
   90. 2026-08 追加分
   ・サイドバーの幅を変えるつまみ
   ・ファイルのドロップ案内
   ・写真のプレビュー (拡大表示)
   ・名前にマウスを乗せたときのプロフィールカード
   ============================================================ */

/* ---- サイドバーの幅つまみ ---------------------------------- */
.side-resizer {
  flex: 0 0 5px;
  cursor: col-resize;
  background: transparent;
  border-left: 1px solid var(--line);
  transition: background .12s ease;
  touch-action: none;
}
.side-resizer:hover,
.side-resizer:focus-visible {
  background: color-mix(in srgb, var(--green-700, #2f7d55) 35%, transparent);
  outline: none;
}
body.resizing { cursor: col-resize; user-select: none; }
@media (max-width: 760px) { .side-resizer { display: none; } }

/* ---- ファイルのドロップ案内 -------------------------------- */
.drop-zone {
  position: fixed;
  inset: 0;
  z-index: 900;
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, #0b1a12 45%, transparent);
  backdrop-filter: blur(1.5px);
  pointer-events: none;                 /* 枠は見せるだけ。drop は window で拾う */
}
.drop-zone.hidden { display: none; }
.drop-inner {
  width: min(680px, 78vw);
  padding: 44px 28px;
  border: 3px dashed #fff;
  border-radius: 14px;
  background: color-mix(in srgb, #0b1a12 30%, transparent);
  color: #fff;
  text-align: center;
}
.drop-title { margin: 14px 0 4px; font-size: calc(20px * var(--ui-scale)); font-weight: 700; }
.drop-sub { margin: 0; font-size: calc(13px * var(--ui-scale)); opacity: .85; }

/* 読み込めなかった写真の差し替え表示。原因が分かるよう目立たせる */
.file-chip-broken {
  border-color: var(--danger-line);
  background: var(--danger-bg);
  color: var(--danger-txt);
}

/* ---- スマホ用の下バー -------------------------------------------------
   パソコンでは出さない (上のバーで足りるため)。
   760px以下でだけ表示し、指で押しやすい高さを確保する。 */
.bottom-nav { display: none; }

/* ---- スマホの地色 ------------------------------------------------------
   パソコンでは、会話のところは白い面 (--panel) で、
   その外側だけが薄い地色 (--bg) になっている。
   スマホは画面いっぱいが会話なので、地色がそのまま広く見えて
   「薄い・くすんで見える」状態だった。
   ★ 新しい色は足さない。パソコンと同じ白 (--panel) を使う。 */
@media (max-width: 760px) {
  body,
  .main,
  .app-body { background: var(--panel); }
}

@media (max-width: 760px) {
  /* 画面の下に「浮いている丸い帯」として置く。
     画面幅いっぱいの平らな帯より、押す場所がはっきりする。 */
  .bottom-nav {
    display: flex;
    position: fixed;
    left: 10px; right: 10px;
    bottom: calc(8px + env(safe-area-inset-bottom, 0px));
    z-index: 60;
    gap: 2px;
    padding: 6px 6px;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 30px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, .10), 0 1px 3px rgba(0, 0, 0, .06);
  }
  .bottom-nav button {
    position: relative;
    flex: 1 1 0;
    min-width: 0;
    min-height: 48px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    padding: 5px 2px;
    background: none;
    border: 0;
    border-radius: 22px;
    color: var(--txt-sub);
    cursor: pointer;
  }
  .bottom-nav button:active { background: var(--bg-sunken); }
  .bottom-nav .bn-ico {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: calc(23px * var(--ui-scale));
    height: calc(23px * var(--ui-scale));
  }
  .bottom-nav .bn-ico svg { width: 100%; height: 100%; display: block; }
  .bottom-nav .bn-txt {
    font-size: calc(10px * var(--ui-scale));
    letter-spacing: -0.02em;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
  }

  /* いま見ている場所。うすい面を敷いて、絵を塗りつぶす。
     色だけの違いだと、明るい屋外では見分けが付かない。 */
  .bottom-nav button.on {
    background: var(--bg-sunken);
    color: var(--txt);
    font-weight: 700;
  }
  .bottom-nav button.on .bn-ico svg { fill: currentColor; stroke: currentColor; }
  /* 顔写真は塗りつぶさない */
  .bottom-nav button.on .bn-me svg { fill: none; }

  /* 自分の顔写真 (アカウント) */
  .bottom-nav .bn-me .avatar {
    width: 100%;
    height: 100%;
    font-size: calc(10px * var(--ui-scale));
  }

  /* 赤い丸の数字。絵の右上に重ねる */
  .bottom-nav .bn-badge {
    position: absolute;
    top: 2px;
    left: 50%;
    margin-left: 2px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 9px;
    background: #e8383d;
    color: #fff;
    font-size: calc(10px * var(--ui-scale));
    line-height: 18px;
    text-align: center;
    font-weight: 700;
    box-shadow: 0 0 0 2px var(--panel);
  }
  .bottom-nav .bn-badge.hidden { display: none; }

  /* 下バーのぶんだけ本体を縮める。
     padding ではなく高さを削ること。app-body は flex で min-height:0 のため、
     padding を足すと中身がその分はみ出して、下バーの裏に隠れてしまう。 */
  .app-body { margin-bottom: calc(var(--nav-h) + env(safe-area-inset-bottom, 0px)); }
}

/* 文字の大きさ選び。いま選ばれているものをはっきり示す */
.fs-pick { border: 1px solid var(--line); border-radius: var(--radius-sm); margin-bottom: 6px; background: var(--panel); }
.fs-pick:hover { border-color: var(--line-strong); }
.fs-pick.on { border-color: var(--accent, #3aa06b); background: var(--bg-sunken); }

/* ---- 写真のプレビュー -------------------------------------- */
.img-btn {
  display: inline-block;
  padding: 0;
  margin: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  line-height: 0;
  border-radius: 10px;
}
.img-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(8, 12, 10, .9);
}
.lightbox.hidden { display: none; }
.lightbox img {
  max-width: 92vw;
  max-height: 82vh;
  object-fit: contain;
  border-radius: 6px;
  cursor: zoom-out;
}
.lb-bar {
  position: absolute;
  top: 0; left: 0; right: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  color: #fff;
  background: linear-gradient(180deg, rgba(0,0,0,.55), transparent);
}
.lb-name { flex: 1; font-size: calc(14px * var(--ui-scale)); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lb-count { font-size: calc(13px * var(--ui-scale)); opacity: .8; font-variant-numeric: tabular-nums; }
.lb-btn {
  color: #fff;
  background: rgba(255,255,255,.14);
  border: 0;
  border-radius: 8px;
  padding: 6px 12px;
  font-size: calc(14px * var(--ui-scale));
  cursor: pointer;
  text-decoration: none;
}
.lb-btn:hover { background: rgba(255,255,255,.26); }
.lb-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 46px; height: 76px;
  font-size: calc(34px * var(--ui-scale)); line-height: 1;
  color: #fff;
  background: rgba(255,255,255,.12);
  border: 0;
  border-radius: 10px;
  cursor: pointer;
}
.lb-nav:hover { background: rgba(255,255,255,.24); }
.lb-nav.hidden { display: none; }
.lb-prev { left: 16px; }
.lb-next { right: 16px; }

/* ---- プロフィールカード (名前にマウスを乗せたとき) ---------- */
/* 名前に乗せたときの吹き出し。名前だけを小さく出す。
   当たり判定を持たせない(pointer-events:none)ので、下のボタンを覆っても押せる。
   ※以前はここに所属・メール・ボタンを載せた大きなカードを出していて、
     ダイアログ(z-index 50)より手前(1100)に居座って押せなくする不具合があった。 */
.hover-card {
  position: fixed;
  z-index: 1100;
  max-width: 240px;
  padding: 5px 10px;
  background: var(--panel, #fff);
  border: 1px solid var(--line, #dfe5e0);
  border-radius: 8px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .14);
  font-size: calc(12.5px * var(--ui-scale));
  font-weight: 700;
  color: var(--txt);
  line-height: 1.5;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
}
.hover-card.hidden { display: none; }
@media (max-width: 760px) { .hover-card { display: none !important; } }


/* ============================================================
   26. メンバーの一覧 / アイコンからプロフィールへ          (v2.8)
   ============================================================ */

/* --- ヘッダーに並ぶ顔 --- */
.member-strip {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  gap: 0;
  padding: 3px 6px 3px 3px;
  margin-right: var(--space-1);
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: none;
  cursor: pointer;
}
.member-strip:hover { background: var(--bg-sunken); border-color: var(--line); }
.member-strip:active { transform: translateY(1px); }
/* 顔を少しずつ重ねる。左の人ほど上に来るよう、後ろの要素を下に敷く。 */
.member-strip .avatar { margin-left: -8px; border: 2px solid var(--panel); }
.member-strip .avatar:first-child { margin-left: 0; }
.member-strip .ms-more {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 30px;
  height: 30px;
  margin-left: -8px;
  padding: 0 6px;
  border-radius: var(--radius-pill);
  border: 2px solid var(--panel);
  background: var(--bg-sunken);
  color: var(--txt-sub);
  font-size: var(--fs-xs);
  font-weight: 700;
  line-height: 1;
}

/* チャット名の下の「メンバー ○人」。押すと一覧が開く。
   小さな画面では顔の並びを隠すので、ここが唯一の入口になる。 */
.sub-link {
  border: none;
  background: none;
  padding: 0;
  font: inherit;
  color: var(--brand-ink);
  font-weight: 600;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}
.sub-link:hover { text-decoration-thickness: 2px; }

/* --- メンバー一覧ダイアログ --- */
.mem-tools {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  margin-bottom: var(--space-2);
}
.mem-tools input[type="search"] { flex: 1 1 0; min-width: 0; }
.mem-tools select { flex: 0 0 auto; max-width: 46%; }
/* 人数が多くても一覧の高さが暴れないよう、ここだけでスクロールさせる */
.mem-list {
  max-height: min(52vh, 420px);
  overflow-y: auto;
  overscroll-behavior: contain;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-1);
}
.mem-list .member-row { padding: var(--space-2); }

/* --- アイコン・名前からプロフィールへ --- */
/* 押せる場所であることを、形を変えずにカーソルだけで示す */
.msg > .avatar,
#chHeadIcon[data-uid] { cursor: pointer; }
.msg > .avatar:hover,
#chHeadIcon[data-uid]:hover { filter: brightness(1.06); }

/* 発言者の名前。見た目は今までどおりのまま、中身だけボタンにしてある
   (キーボードだけで操作する人がプロフィールへ辿れるようにするため) */
button.msg-name {
  border: none;
  background: none;
  padding: 0;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
}
button.msg-name:hover { text-decoration: underline; text-underline-offset: 2px; }

@media (max-width: 760px) {
  /* ヘッダーは戻る・チャット名・操作6個で既にいっぱい。顔の並びは出さず、
     「メンバー ○人」から開いてもらう。 */
  .member-strip { display: none !important; }

  /* 小さな画面では .chat-head-sub を丸ごと隠しているが(横幅の都合)、
     グループのときだけは「メンバー ○人」を出す。ここを隠すと、
     スマホからメンバー一覧へ行く手段が無くなってしまう。
     概要の文は長くて折り返すので、こちらは引き続き隠す。 */
  .chat-head-sub.has-members { display: block; }
  .chat-head-sub .sub-desc { display: none; }
  .mem-tools { flex-wrap: wrap; }
  .mem-tools input[type="search"] { flex: 1 0 100%; font-size: max(16px, calc(16px * var(--ui-scale))); }  /* iOSの自動ズーム防止 */
  .mem-tools select { max-width: 100%; flex: 1 0 100%; min-height: 40px; }
  .mem-list { max-height: 46vh; }
}


/* ============================================================
   27. 上のバー(横いっぱい) / ピン / オンライン表示の取りやめ  (v2.8)
   ============================================================ */

/* --- 横幅が中くらいのとき: ロゴ幅の固定をやめて検索欄に幅を回す --- */
@media (max-width: 1100px) {
  .topbar .brand { width: auto; }
  .topbar-search { max-width: none; }
}

@media (max-width: 760px) {
  /* 一覧を見ているときだけ上のバーを出す。
     トークを開いたら縦を1行でも多くメッセージに使いたいので隠す
     (戻ればまた出る)。 */
  .app.chat-open .topbar { display: none; }
  .topbar {
    padding: max(var(--space-2), env(safe-area-inset-top)) var(--space-2) var(--space-2);
    gap: var(--space-2);
  }
  .topbar .brand { width: auto; font-size: var(--fs-md); }
  .topbar .brand span { display: none; }      /* 文字は省いて丸ロゴだけ */
  .topbar-search { height: 38px; }
  .topbar-search input { font-size: max(16px, calc(16px * var(--ui-scale))); }   /* iOSの自動ズーム防止 */
  .side-actions button { width: 40px; height: 40px; }
  .side-tabs-row { padding: var(--space-2) var(--space-3); }
  .side-tabs-row > #btnNewChat { width: 40px; height: 40px; min-height: 40px; }
}

/* --- ピン留め ---
   Chatwork と同じ「押しピン」の形にそろえ、絵文字より一回り大きくする。
   絵文字は端末ごとに形も色も変わるので、SVGで固定する。 */
.pin-ico {
  width: 20px;
  height: 20px;
  display: inline-block;
  vertical-align: -3px;
  flex-shrink: 0;
  pointer-events: none;
}
/* 留めている行だけ中を塗る。ヘッダーのボタンと同じ見え方にそろえてある。 */
.ci-pin.on .pin-ico { fill: currentColor; }

/* 一覧の行に出るピン。ふだんは隠れていて、
   ・その行にマウスを乗せたとき
   ・キーボードでその行に来たとき
   ・すでにピン留めしてあるとき
   に出る。スマホは「乗せる」が無いので常に出す。 */
.ci-pin {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  border-radius: var(--radius-sm);
  color: var(--txt-faint);
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--dur) var(--ease), color var(--dur) var(--ease);
}
.chat-item:hover .ci-pin,
.chat-item:focus-within .ci-pin,
.ci-pin.on { opacity: 1; }
.ci-pin:hover { background: var(--bg-sunken); color: var(--txt-sub); }
.ci-pin.on { color: var(--brand-ink); }
.ci-pin.on:hover { color: var(--brand-ink); }
/* 触って操作する端末には「乗せる」が無いので、隠れたままだと押せない */
@media (hover: none) {
  .ci-pin { opacity: 1; color: var(--txt-faint); }
  .ci-pin.on { color: var(--brand-ink); }
}
/* 強制配色(白黒反転など)では opacity での出し分けが伝わらないので常時表示 */
@media (forced-colors: active) {
  .ci-pin { opacity: 1; }
}

/* --- オンライン/オフラインの表示はやめた ---
   誰が今つないでいるかは業務上の必要が薄く、
   「見られている」感じが出るため表示しない。
   古い画面が残っていても点が出ないよう、CSS側でも止めておく。 */
.avatar .dot { display: none !important; }

/* ピン留め中のヘッダーのボタン。押した状態が形ではなく色で分かるようにする */
.chat-head-actions #btnPin.on { color: var(--brand-ink); }

@media (max-width: 760px) {
  /* 絞り込みタブは折り返さず横に流す。
     「タスクあり」だけが2行目に落ちて縦を1行ぶん食っていた。 */
  .side-tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .side-tabs::-webkit-scrollbar { display: none; }
  .side-tabs button { flex-shrink: 0; }
}


/* ============================================================
   28. 一覧の下に続く「まだ話していない人・入っていないグループ」 (v2.8)
   ============================================================ */

/* 区切り。ここから下は「これから始められる相手」であることを示す。 */
.ci-sep {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: 10px var(--space-3) 6px;
  margin-top: var(--space-2);
  border-top: 1px solid var(--line);
  background: var(--panel);
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--txt-sub);
  letter-spacing: .02em;
}

/* まだ会話が無い行。既存のチャットより一段控えめにして、混ざらないようにする。 */
.chat-item.ci-new { opacity: .82; }
.chat-item.ci-new:hover { opacity: 1; }
.chat-item.ci-new .ci-last { color: var(--txt-faint); }
.ci-new-act {
  flex: 0 0 auto;
  align-self: center;
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--brand-ink);
  background: var(--brand-tint);
  border: 1px solid color-mix(in srgb, var(--brand) 26%, transparent);
  border-radius: var(--radius-pill);
  padding: 4px 10px;
  white-space: nowrap;
  /* ふだんは控えめ。行に触れたときにはっきり出す。 */
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.chat-item.ci-new:hover .ci-new-act,
.chat-item.ci-new:focus-within .ci-new-act { opacity: 1; }
@media (hover: none) { .ci-new-act { opacity: 1; } }
@media (forced-colors: active) { .ci-new-act { opacity: 1; } }

/* 送信中は二度押しできないようにする */
.chat-item.busy { pointer-events: none; opacity: .5; }

/* まだ会話が無い行にピンは要らない (固定できるのは自分のチャットだけ) */
.chat-item.ci-new .ci-pin { display: none; }


/* ============================================================
   31. ブックマーク / 一斉送信                               (v2.9)
   ============================================================ */
.bm-note, .bc-note {
  font-size: var(--fs-sm);
  color: var(--txt-sub);
  line-height: 1.75;
  margin-bottom: var(--space-2);
}
.bm-note b, .bc-note b { color: var(--txt); }
/* 「いまのままでは使えません」と伝えるときの注意書き。
   ただ薄い文字で書くと読み飛ばされるため、左に赤い線を入れる。 */
.bm-note.note-warn {
  border-left: 3px solid var(--red);
  padding: var(--space-2) 0 var(--space-2) var(--space-3);
  background: var(--bg-sunken);
  border-radius: var(--radius-sm);
  color: var(--txt);
}

.bm-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  margin-bottom: var(--space-2);
  cursor: pointer;
  background: var(--panel);
}
.bm-row:hover { background: var(--bg-sunken); border-color: var(--line-strong); }
.bm-main { flex: 1; min-width: 0; }
/* 「誰が」を先に、太く。同じ苗字の人が多い会社では、
   名前だけでなく顔写真も並べないと見分けが付かない。 */
.bm-who {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--txt);
  margin-bottom: 2px;
  min-width: 0;
}
.bm-row .avatar { flex: 0 0 auto; }
.bm-room {
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--brand-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.bm-body {
  font-size: var(--fs-sm);
  color: var(--txt);
  line-height: 1.7;
  /* 3行で打ち切る。長文をそのまま出すと一覧が縦に伸びて探しにくい */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.bm-meta { font-size: var(--fs-xs); color: var(--txt-faint); margin-top: 4px; }
/* 発言の操作列にある🔖。付いているときだけ色を付ける。 */
.msg-actions button[data-a="bm"].on { color: var(--brand-ink); }

/* ---- 一斉送信 ---- */
.bc-tools { display: flex; gap: var(--space-2); align-items: center; margin-bottom: var(--space-2); }
.bc-tools input[type="search"] { flex: 1 1 0; min-width: 0; }
.bc-list {
  max-height: min(38vh, 300px);
  overflow-y: auto;
  overscroll-behavior: contain;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-1);
}
.bc-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.bc-row:hover { background: var(--bg-sunken); }
.bc-row input[type=checkbox] {
  accent-color: var(--brand-ink);
  width: 18px; height: 18px;
  flex-shrink: 0;
  cursor: pointer;
}
.bc-name { flex: 1; min-width: 0; font-size: var(--fs-md); font-weight: 600; line-height: 1.45; }
.bc-name .pick-sub { font-weight: 400; margin-top: 1px; }
.bc-count { font-size: var(--fs-sm); font-weight: 700; color: var(--brand-ink); }

@media (max-width: 520px) {
  .bc-tools { flex-wrap: wrap; }
  .bc-tools input[type="search"] { flex: 1 0 100%; font-size: max(16px, calc(16px * var(--ui-scale))); }
}


/* ============================================================
   アカウント画面 (スマホの下バーから開く)
   自分にかかわるものを1枚に縦に並べる。
   これまではプロフィールの編集画面の一番下にボタンが横一列に並んでいて、
   何がどこにあるのか分からなかった。
   ============================================================ */
.ac-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) 0 var(--space-4);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--space-3);
}
.ac-head-txt { min-width: 0; }
.ac-name {
  font-size: calc(17px * var(--ui-scale));
  font-weight: 700;
  line-height: 1.3;
  word-break: break-word;
}
.ac-sub {
  font-size: calc(12px * var(--ui-scale));
  color: var(--txt-sub);
  line-height: 1.6;
  word-break: break-all;
}
/* 行の絵。幅をそろえないと、文字の頭が1行ずつずれて読みにくい */
.ac-ico {
  width: calc(24px * var(--ui-scale));
  text-align: center;
  font-size: calc(17px * var(--ui-scale));
  flex: 0 0 auto;
}
/* 「押すと次の画面へ進む」ことを示す矢印 */
.ac-arrow {
  color: var(--txt-sub);
  font-size: calc(20px * var(--ui-scale));
  line-height: 1;
  flex: 0 0 auto;
}


/* スマホでは、下バーの上に出す。
   下バーと同じ高さに出すと、消えるまでの数秒間
   ブックマーク・タスク・コンタクトが隠れて押せない。 */
@media (max-width: 760px) {
  .toast {
    bottom: calc(var(--nav-h) + env(safe-area-inset-bottom, 0px) + 14px);
    z-index: 62;                       /* 下バー(60)より上に出す */
  }
}


/* ============================================================
   マイプロフィールの「設定」ボタン
   これまでは下の帯にボタンを7つ横並びにしていたため、
   幅が足りずに 3個 / 3個 / 1個 と不ぞろいに折り返し、
   「保存」だけが右下に離れて置かれていた。
   マス目にして、幅の広さにかかわらず頭がそろうようにする。
   ============================================================ */
.pf-tools {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--space-2);
}
.pf-tools button {
  /* 絵と文字の頭をそろえる。中央そろえにすると、
     文字数の違うボタンで絵の位置がばらばらに見える。 */
  justify-content: flex-start;
  text-align: left;
  width: 100%;
  padding: 10px 12px;
}
/* 幅の狭い画面では1列にする。2列にすると文字が折り返って高さがそろわない */
@media (max-width: 420px) {
  .pf-tools { grid-template-columns: 1fr; }
}


/* ============================================================
   画面が勝手に動かないようにする

   ・拡大 (指2本・2回叩き) を止める
     止めないと、画面が拡大したまま左右に動いてボタンの位置が定まらない。
     文字を大きくしたい場合は「アカウント → 文字の大きさ」で5段階選べる。
   ・端まで来たときの跳ね返り (ゴムのように戻る動き) を止める
     一覧の一番下で指を動かすと画面全体が持ち上がり、
     下バーの位置がずれて見える。
   ============================================================ */
html {
  /* pan-x pan-y = 上下左右にたどるのは許すが、拡大はさせない。
     manipulation にすると2本指の拡大が残るので、ここでは使わない。 */
  touch-action: pan-x pan-y;
  overscroll-behavior: none;
}
body {
  overscroll-behavior: none;
  /* 横にだけは絶対に動かさない。何かが1px はみ出しただけで
     画面全体が左右に揺れて見えるため。 */
  overflow-x: hidden;
}


/* ============================================================
   狭い画面 + 大きい文字でも、行の中身がはみ出さないようにする

   管理メニューの「ユーザー」は、1行に
   顔写真・名前・ボタン4つ が横並びで入る。
   文字の大きさを「最大」にするとボタンが右へはみ出し、
   画面が横に動いて見える原因になっていた (実測で確認)。
   横に伸ばすのをやめ、行の中で折り返すようにする。
   ============================================================ */
@media (max-width: 760px) {
  /* 上下2段にする。名前が上、ボタンが下。
     横に押し込むより、1行が高くなるほうが押しやすい。 */
  .pick-row {
    flex-wrap: wrap;
    row-gap: var(--space-2);
  }
  .pick-btns {
    /* 55% の制限を外す。狭い画面では、そもそも横に並べきれない */
    max-width: 100%;
    width: 100%;
    justify-content: flex-start;
  }
  /* ボタン自体も、文字が長いときは折り返して収める */
  .pick-btns > button,
  .pick-btns > a {
    max-width: 100%;
    white-space: normal;
    text-align: center;
  }
  /* 名前とメールアドレスは、長くても行から出さない */
  .pick-name, .pick-sub { overflow-wrap: anywhere; }
}


/* ============================================================
   やることリストの入力欄

   以前は「やること」と「日付」を横に並べていた。
   幅の狭い画面では日付の欄が細くなり、
   入れた日付が切れて読めなくなっていた
   (ホーム画面から開くと画面がさらに狭く、ほぼ見えない)。
   日付の欄は縦に分け、何の日付かが分かる見出しを付ける。
   ============================================================ */
.todo-add { display: flex; gap: var(--space-2); align-items: flex-end; }
.todo-add > input[type=text] { flex: 1; min-width: 0; }
.todo-due { display: flex; flex-direction: column; gap: 2px; flex: 0 0 auto; }
.todo-due-label {
  font-size: calc(11px * var(--ui-scale));
  color: var(--txt-sub);
  font-weight: 600;
  white-space: nowrap;
}
/* 日付が切れないだけの幅を必ず確保する。
   yyyy/mm/dd とカレンダーの絵の両方が入る大きさ。
   文字を大きくしたときも一緒に広がるよう、--ui-scale を掛ける。 */
.todo-due > .date-wrap {
  width: calc(158px * var(--ui-scale));
  min-width: calc(158px * var(--ui-scale));
}
.todo-due input[type=date] { font-variant-numeric: tabular-nums; }

@media (max-width: 760px) {
  /* 横に並べきれないので、上下に分ける */
  .todo-add { flex-direction: column; align-items: stretch; }
  .todo-due > .date-wrap { width: 100%; min-width: 0; }
}

/* ============================================================
   管理メニューの「利用状況」
   ============================================================ */
.us-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-2);
}
.us-card {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  text-align: center;
  background: var(--bg-sunken);
}
.us-card.us-big { border-color: var(--accent); background: var(--panel); }
.us-num { font-size: calc(26px * var(--ui-scale)); font-weight: 700; line-height: 1.2; }
.us-big .us-num { color: var(--accent); }
.us-unit { font-size: calc(12px * var(--ui-scale)); font-weight: 600; margin-left: 2px; }
.us-lbl { font-size: calc(11.5px * var(--ui-scale)); color: var(--txt-sub); margin-top: 2px; }
.us-names {
  font-size: calc(12px * var(--ui-scale));
  color: var(--txt-sub);
  margin-top: var(--space-2);
  line-height: 1.7;
}
.us-note { font-size: calc(12px * var(--ui-scale)); color: var(--txt-sub); margin-top: var(--space-2); }
.us-dim { font-size: calc(12px * var(--ui-scale)); color: var(--txt-sub); line-height: 1.7; }

.us-bar {
  height: 14px;
  border-radius: 7px;
  background: var(--bg-sunken);
  border: 1px solid var(--line);
  overflow: hidden;
}
.us-bar-in { display: block; height: 100%; background: var(--accent); }
.us-bar-in.warn { background: var(--amber); }
.us-bar-in.over { background: var(--red); }
.us-bar-txt { font-size: calc(13px * var(--ui-scale)); margin-top: 6px; }
.us-free { color: var(--txt-sub); }

.us-tbl { width: 100%; border-collapse: collapse; margin-top: var(--space-3); }
.us-tbl td {
  border-top: 1px solid var(--line);
  padding: 8px 4px;
  font-size: calc(13px * var(--ui-scale));
}
.us-tbl td:nth-child(2) { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; }
.us-tbl td:nth-child(3) { text-align: right; color: var(--txt-sub); width: 30%; }

.us-host {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  font-size: calc(13px * var(--ui-scale));
  line-height: 1.8;
}
.us-btns { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-top: var(--space-3); }
.us-ok { color: var(--accent); }
.us-ng { color: var(--red); }

@media (max-width: 760px) {
  /* 4つ横並びは狭すぎる。「いま開いている」を1行占有にして残りを3つ並べる */
  .us-grid { grid-template-columns: repeat(3, 1fr); }
  .us-card.us-big { grid-column: 1 / -1; }
  .us-btns > button { flex: 1 1 auto; }
}

/* ============================================================
   Ecochat の中でファイルを開く画面
   ------------------------------------------------------------
   以前は別の画面(Safari)に飛ばしていたため、
   ホーム画面から開いた状態では戻れなくなっていた。
   ここに出せば、必ず「← 戻る」で会話に帰れる。
   ============================================================ */
.fv-back {
  position: absolute;
  left: var(--space-3);
  top: 50%;
  transform: translateY(-50%);
  font-size: calc(14px * var(--ui-scale));
  font-weight: 700;
  color: var(--accent);
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  min-height: 44px;            /* 指で押せる大きさを必ず確保する */
}
.fv-back:hover { background: var(--bg-sunken); }
.fv-title {
  display: block;
  padding: 0 96px;             /* 「← 戻る」に重ならないように空ける */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fv-body { display: flex; flex-direction: column; gap: var(--space-3); }
.fv-media {
  display: block;
  width: 100%;
  max-height: 62vh;
  object-fit: contain;
  background: var(--bg-sunken);
  border-radius: var(--radius-sm);
}
.fv-audio { width: 100%; }
.fv-frame {
  width: 100%;
  height: 62vh;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--bg-sunken);
}
.fv-tools { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.fv-note { font-size: calc(12px * var(--ui-scale)); color: var(--txt-sub); line-height: 1.7; }

@media (max-width: 760px) {
  /* 画面いっぱいに開くので、見る場所をできるだけ広く取る */
  .fv-media { max-height: 58vh; }
  .fv-frame { height: 58vh; }
  .fv-title { padding: 0 92px 0 96px; }
  .fv-tools > button { flex: 1 1 auto; }
}

/* ============================================================
   日付の欄の「yyyy/mm/dd」の見本
   ------------------------------------------------------------
   iPhone は空の日付欄に何も出さないため、空の四角に見えてしまう。
   自分で見本を重ねて、何を入れる欄なのか分かるようにする。
   本物の表示と二重にならないよう、
   ★ 空で、かつ触っていない間だけ ★ 本物の文字を透明にする。
   触っている間 (:focus) は本物に戻す。戻さないと、
   パソコンで数字を打っている最中に、打った数字が見えなくなる。
   ============================================================ */
.date-wrap { position: relative; display: block; }
.date-ph {
  position: absolute;
  left: 13px;                      /* 枠線1px + 内側の余白12px */
  top: 50%;
  transform: translateY(-50%);
  color: var(--txt-faint);         /* 他の入力欄の見本と同じ濃さ */
  font-size: calc(14px * var(--ui-scale));
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  pointer-events: none;            /* 見本を押しても欄が開くように */
}
.date-wrap:not(.filled) > input[type=date]:not(:focus) { color: transparent; }
.date-wrap.filled > .date-ph,
.date-wrap > input[type=date]:focus ~ .date-ph { display: none; }
