/* ============ FAUNA CIRCUIT — competitive 3D card UI ============ */
* { box-sizing: border-box; margin: 0; padding: 0; }

/*
 * 配色は盤面のネオンと同じものを使う。
 * じぶん=シアン / あいて=マゼンタ という決まりは
 * scripts/make-playmat.mjs (マットの絵) と src/v2/crowd.js (ふちの光) にも
 * 同じ値で入っている。片方だけ変えると盤面とUIの色がずれる。
 */
:root {
    /*
     * 書体。外部フォントは読まない (完全オフラインを保つため) ので、
     * OSに必ず載っているものだけで組む。
     * --font-ui : 本文。丸ゴシックは「かわいい」側に寄りすぎるので使わない。
     * --font-num: 数字とアルファベット。DIN系の細長い書体で、大会の
     *             スコア表示らしくする。Bahnschrift=Windows / DIN Alternate=Mac。
     */
    --font-ui: 'Hiragino Sans', 'Noto Sans JP', 'Yu Gothic UI', 'Yu Gothic', Meiryo, system-ui, sans-serif;
    --font-num: Bahnschrift, 'DIN Alternate', 'Avenir Next Condensed', 'Roboto Condensed', var(--font-ui);
    --you: #3fd8ff;
    --opp: #ff4fb0;
    --panel-bg: rgba(7, 13, 24, 0.86);
    --panel-border: rgba(120, 190, 255, 0.22);
    --accent: #3fd8ff;       /* 目を引かせたいもの */
    --warn: #ffc23d;         /* 急がせたいもの (決着間近・選択中) */
    --primary: #22c3f0;
    --text: #eaf3ff;
    --text-dim: #8ba3c2;
    --radius: 10px;
    font-size: 15px;

    /*
     * 手札の大きさは1か所で決める。ここから高さ(--hand-h)を計算し、
     * 手札の上に置くもの (トースト・ログ・縦持ちの行動ボタン) の位置に使う。
     * px を散らすと、手札の大きさを変えたとたんに重なる。
     */
    --hand-w: clamp(82px, 9.5vw, 132px);
    --hand-h: calc(var(--hand-w) * 522 / 374);   /* .hand-card の aspect-ratio と同じ比 */
    --hand-drop: 26px;                           /* 画面の下へはみ出させる量 */
    --hand-top: calc(var(--hand-h) - var(--hand-drop));   /* 手札の見えている高さ */
    /* 縦持ちの帯の位置。中身で高さが変わるので hud.js が実測して書く */
    --band-top: 0px;                          /* スコア帯の下端 (画面上からの高さ) */
    --band-bottom: 0px;                       /* 行動まとまりの上端 (画面下からの高さ) */
    /*
     * 操作の案内帯の高さ。**hud.js が実測して書く** (中身と折り返しで変わる)。
     * 帯は画面のいちばん左下に置くので、左下に積んであるもの
     * (ログ・LOG/MENU の列) をこのぶん押し上げる。パッドを使っていなければ 0。
     */
    --pad-bar-h: 0px;
    /*
     * 左右の列の幅。**3か所が同じ数字を持っていた** (情報列・ログ枠・案内帯)。
     * 案内帯が「列の幅に収まっていれば手札の扇に潜らない」に頼っているので、
     * 狭い画面で列だけ細くなると、その根拠がその画面でだけ崩れる。
     */
    --rail-w: 216px;

    /*
     * ■ UIの大きさ (設定「UIサイズ」)
     *
     * このCSSは font-size が px で163件・rem は1件しかないので、**ルートの
     * font-size を動かしても何も起きない**。効くのは `zoom` で、これは
     * CSS Viewport Module で標準化された正式なプロパティ
     * (Chrome 128 / Firefox 126 で挙動がそろった)。かつての hack ではない。
     *
     * **`#hud` にだけ掛ける。** canvas (`#three-container`) は兄弟なので
     * 盤面の大きさは変わらない ―― コンシューマーゲームの「UIサイズ」と同じ形。
     *
     * `zoom` を選ぶ決め手は**当たり判定**だった。`zoom` の中では
     * `getBoundingClientRect()` が**画面そのものの座標**を返すので、3Dから
     * 投影した座標とそのまま比べられる (方向ナビが座標変換なしで動く)。
     * `transform: scale()` は組み直しが起きないので、`flex-wrap` と `order` で
     * 縦横を組み替えているこのHUDでは使えない (はみ出したぶんが消える)。
     *
     * ⚠ **ズームの中では vh/vw も掛かる。** 「画面に収める」意図の寸法
     * (height / max-height / width / max-width) は `/ var(--ui-scale)` で
     * 打ち消してある。字や余白の vw/vh は**打ち消さない** ―― 大きくなるのが
     * まさに狙いなので。
     * ⚠ **測って書き戻す値は割ること。** `hud.js updateBands()` が典型で、
     * `getBoundingClientRect()` は画面の座標を返すのに、書き戻す先は
     * ズームの中なので、割らないと倍率ぶん二重に効く。
     *
     * 段は決め打ちにする。半端な倍率は 1px の枠が消えたり二重になったりする。
     */
    --ui-scale: 1;

    /*
     * ■ テレビのふちで切れるぶんの余白 (オーバースキャン)
     * 家庭用テレビは画面のふちを数%切り落とすことがある。困るのは
     * **端に寄せたもの**だけなので、`env(safe-area-inset-*)` と同じ
     * `max()` の中へ足す (大きいほうが効く)。
     */
    --safe-x: 0px;
    --safe-y: 0px;
}

html {
    /*
     * iOS Safari は縦→横に回すと本文の字を勝手に大きくする。
     * これをやられると回すたびにパネルの高さが変わり、レイアウトがずれていく。
     */
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

html, body {
    width: 100%;
    height: 100%;
    height: 100dvh;              /* モバイルのツールバーぶんを含めた「いま見えている高さ」 */
    overflow: hidden;
    overscroll-behavior: none;   /* 引っぱって更新・ゴムのような跳ね返りで盤面がずれるのを防ぐ */
    font-family: var(--font-ui);
    color: var(--text);
    background: radial-gradient(120% 90% at 50% 0%, #12294a 0%, #0a1220 45%, #04070d 100%);
}

/*
 * ---------- OSのジェスチャーを切る (アプリ全体で1か所) ----------
 *
 * このアプリは自前の長押し(350ms・input.js)でカードを拡大する。
 * OSの長押し(約500ms)を切らずに自前の長押しを持つと、指を置いたままの状態で
 * **OS側があとから割り込む**: iPad は画像の「保存/コピー」の吹き出し、
 * Android と PC は右クリックメニュー、どちらも文字のなぞり選択が起きる。
 *
 * `html, body` に user-select を書くだけでは足りなかった:
 *  - 吹き出し(-webkit-touch-callout) と 画像のドラッグ(-webkit-user-drag) は別の口
 *  - タップのたび出る灰色の四角 (-webkit-tap-highlight-color) も別の口
 *  - 継承を当てにすると、UAスタイルが個別指定を持つ要素だけすり抜ける
 * なので `*` で全部落とし、**コピーが要る所だけ下で戻す**。
 * JS側の口 (contextmenu / dragstart / selectstart) は input.js の
 * installGestureGuard が塞ぐ。CSSとJSは両方要る (片方だけでは残りの口が開く)。
 */
*, *::before, *::after {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    /*
     * **拡大させないのも既定にする (縦パンだけOSへ渡す)。**
     * 以前は入れ物ごと (#hud・盤面・手札…) に書いていたが、WebKit は
     * **祖先の pan-y をダブルタップ拡大に効かせないことがある**うえ、
     * このゲームの操作は「2回タップで入れる」なので必ず踏む。
     * 全要素に直接書けば、触った要素そのものが拡大を断る (祖先頼みをやめる)。
     * このアプリはスクロールが全部縦で、拡大されると戻す手が無い (原則37)。
     * `none` が要る所 (盤面 canvas・手札) は個別指定が勝つのでそのまま。
     */
    touch-action: pan-y;
}
img, canvas, svg {
    -webkit-user-drag: none;     /* つまむとゴースト画像がついてくるのを止める */
}
/*
 * ここだけは選べる。コードは手で写す・貼り付けることがあるので、
 * 選択もコピーも吹き出しも**わざと生かしてある**。
 * 新しくコピーさせたい所ができたら `.selectable` を付けること
 * (個別に user-select を書き足すと、また同じ知識が散る)。
 */
input, textarea, [contenteditable="true"], .selectable, .selectable * {
    -webkit-touch-callout: default;
    -webkit-user-select: text;
    user-select: text;
}

/*
 * **入力欄の字は 16px 未満にしないこと。**
 *
 * iOS は 16px 未満の入力欄に触れると、読めるようにと**ページごと拡大する**。
 * ふつうのサイトなら指で戻せるが、このアプリは全画面が position:fixed で
 * スクロールする所が無いので、**拡大されたら戻す手が無い**
 * (「iPadで急に拡大されて、画面が戻らない」の正体)。
 * 個別に書くと次に足した入力欄でまた起きるので、ここでまとめて下限を引く。
 *
 * `:where()` で詳細度ゼロにしてある。素の `input:not(...)` は (0,1,1) で、
 * `.online-code-input` (0,1,0) のような**わざと大きくした指定に勝ってしまい**、
 * CODE入力の30pxが16pxへ潰れていた (max() は同じ宣言の中の比較であって、
 * 他の規則の値と比べてはくれない)。下限はここが引き、大きくしたい欄は
 * 自分のクラスで上書きする。**16px未満の font-size を入力欄に書かないこと**
 * (書くとこの下限に勝ってしまい、iOSの拡大が戻ってくる)。
 * 見張りは `tests/responsive.spec.js` の「入力欄の字が小さすぎない」と
 * `tests/css-audit.spec.js` (網に負けている専用指定の総当たり)。
 */
:where(input:not([type="range"]), textarea, select) {
    font-size: max(16px, 1rem);
}

/*
 * canvas の見た目の大きさは **CSS だけ** が決める (scene.js は setSize(w,h,false))。
 * three.js に px を書かせると、回転直後の古い寸法がインライン指定として焼き付き、
 * 100% に勝って画面とずれたままになる。
 */
#three-container {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    height: 100dvh;
}
#three-container canvas {
    display: block;
    width: 100%;
    height: 100%;
    touch-action: none;          /* ダブルタップ拡大・スクロールで盤面が動かないように */
}

/*
 * **つまんで動かすものは、OSにジェスチャーを渡さない。**
 * `#hud` は `touch-action: manipulation` にしてある (モーダルを指で
 * スクロールできる必要があるため) が、`manipulation` が切るのは
 * ダブルタップ拡大だけで、**縦の引っぱりはブラウザが持っていく**。
 * そのため手札を下へドラッグすると、ドラッグではなく
 * ページの引っぱり (更新のジェスチャー) になっていた。
 * html/body の `overscroll-behavior: none` はページが跳ねるのを止めるだけで、
 * 指のジェスチャーそのものは取られたままなので、ここで断ち切る。
 */
.hand-card,
.hud-hand {
    touch-action: none;
}
/*
 * デッキ編集の一覧の札は**ここに入れないこと**。一覧はカードで敷き詰められて
 * いるので、`none` にすると指がほぼ必ずカードの上に乗り、タブレットで
 * 一覧が1ミリもスクロールできなくなる (すき間に指を当てたときだけ動く。
 * 実際に起きた)。この札はドラッグで運ばない (タップ=選ぶ / 長押し=拡大) ので、
 * 縦の引っぱりは OS に渡してよい。つまむ拡大とダブルタップは pan-y が塞ぐ。
 */
.deck-card { touch-action: pan-y; }

#hud {
    /* UIの大きさ。canvas は兄弟なので盤面は変わらない (:root の説明を参照) */
    zoom: var(--ui-scale);
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    height: calc(100dvh / var(--ui-scale));
    pointer-events: none;
    z-index: 10;
    /*
     * 縦のスクロールだけ残す。
     * `none` にはしない — モーダルの中身は縦に長くなることがあり、
     * 指でスクロールできる必要がある。
     * かつては `manipulation` だったが、あれが切るのは**ダブルタップ拡大だけ**で、
     * **2本指でつまむ拡大は通っていた**。このアプリはスクロールする所が無いので、
     * 一度拡大されると戻す手が無い (iPadで実際に起きた)。
     * `pan-y` なら縦スクロールだけ通り、つまむ拡大もダブルタップも来ない。
     */
    touch-action: pan-y;
}
#hud > * { pointer-events: auto; }
/*
 * クリックを受けない層は、必ずこの `#hud > .x` の形で書くこと。
 * `.x { pointer-events: none }` だけでは上の `#hud > *` (ID指定) に
 * 詳細度で負けて効かず、画面全体をおおう層が操作を丸ごと遮ってしまう。
 */
#hud > .hud-topstack,    /* ターン・持ち時間・やること。押すものではない */
#hud > .hand-drag,       /* ドラッグ中の分身。指の下の盤面を隠してはいけない */
#hud > .hud-hand,        /* カード間の隙間から盤面をクリックできるように */
#hud > .hud-confetti,    /* 全画面をおおう演出レイヤー */
#hud > .hud-vignette,
#hud > .hud-zoom,        /* 長押しで出すカード詳細 (開いている間だけ :not(.hidden) で受ける) */
#hud > .hud-toasts,
#hud > .hud-banner,      /* 盤面のまん中に重なる */
#hud > .hud-sidebar,     /* 左右の列は入れ物。中の押せるものだけが受ける */
#hud > .hud-rightbar {
    pointer-events: none;
}
/*
 * 入れ物の中でも、押せる必要があるものは受ける。
 * クラス名で並べていると新しいボタンを足すたび漏れる (実際あいさつボタンで漏れた) ので、
 * 「押すためのもの」= button/input をまとめて受ける形にしてある。
 */
.hud-sidebar button, .hud-sidebar input,
.hud-rightbar button, .hud-rightbar input {
    pointer-events: auto;
}

.hidden { display: none !important; }

/* ---------- start screen ---------- */
/*
 * タイトル画面。
 *
 * **中身が入りきらない画面でも、上端と下端に手が届くこと。**
 * かつては `justify-content: center` ＋ スクロールは縦画面だけ、だった。
 * 横向きスマホ (844×390) では中身が画面より高くなり、はみ出したぶんは
 * 上へも下へも出たまま**スクロールできない** ―― 下段の「SETTINGS / DECK /
 * HOW TO PLAY / CARD EDITOR」が y 405〜434 (画面高 390) に置かれ、
 * 設定にもデッキにも入れなかった (巡回テストがクリックで4回タイムアウトした)。
 *
 * 直しかたは `justify-content` を使わないこと。上下の端の子に `margin: auto` を
 * 置くと、**余っているときだけ**中央に寄り、あふれた瞬間に auto が 0 へ潰れて
 * 全部がスクロールで届くようになる (safe center と違い、どの版でも同じに効く)。
 */
.start-screen {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: 14px;
    /*
     * **画面ごとスクロールさせない。** 下の `.start-panel` だけが縮んで
     * スクロールし、SETTINGS / MY DECKS / HOW TO PLAY の下段は必ず居残る。
     *
     * ここは長く画面ごと `overflow-y: auto` で、入口が1つ増えるたびに
     * 下段が画面の外へ押し出されていた ―― 実際「トーナメント」を足した回に
     * 横向きスマホ (852×393) で下段が y=450 に落ち、**設定にもデッキにも
     * 入れなくなった**。スクロールはできるが、**見えないものを人は
     * スクロールして探さない**ので、直したことにならない。
     *
     * 詰めもの (@media max-height) でその場は収まるが、入口が増えるたびに
     * 実測し直す形なので、いつか必ずまた溢れる。**下段を居残らせるほうを
     * 構造で決める** —— 縦並びが何行になっても、向きが縦でも横でも変わらない。
     */
    overflow: hidden;
    /* 余白は UIサイズ (`--ui-scale`) とテレビのふち (`--safe-y`) を見る (GP-06/07) */
    padding: max(16px, calc(env(safe-area-inset-top) / var(--ui-scale)), var(--safe-y)) 12px max(16px, calc(env(safe-area-inset-bottom) / var(--ui-scale)), var(--safe-y));
    background: rgba(7, 10, 20, 0.62);
    backdrop-filter: blur(7px);
    z-index: 50;
}
.start-screen > :first-child { margin-top: auto; }
.start-screen > :last-child { margin-bottom: auto; }
.start-title {
    font-family: var(--font-num);
    font-size: clamp(34px, 6.7vw, 72px);
    font-weight: 700;
    font-style: italic;            /* 前へ傾けて速さを出す (大会ロゴの定番) */
    letter-spacing: 0.08em;
    text-align: center;
    background: linear-gradient(180deg, #ffffff 12%, #7fe8ff 58%, #1f9dd6 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    text-shadow: 0 0 60px rgba(63, 216, 255, 0.45);
}
.start-subtitle { color: var(--accent); font-weight: 700; letter-spacing: 0.35em; }

/*
 * パネルの上辺だけ細く光らせる。放送のスコア表示のように
 * 「板が置いてある」感じが出て、暗い背景でも輪郭が見える。
 */
.start-panel, .modal-box, .deck-panel, .hud-logwrap, .hud-preview, .hud-player, .hud-say {
    box-shadow: inset 0 1px 0 rgba(150, 215, 255, 0.18);
}
.start-panel {
    margin-top: 20px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 22px 26px;
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: 12px;
    /*
     * **幅は決めうちにする。** 縦に積む flex の中で `align-items: center` の
     * 子は「中身のぶんだけ」の幅になるので、`max-width` だけ書いても伸びない ――
     * 中の格子 (`auto-fit`) は入れ物の幅から列数を決めるため、
     * **広い画面でも1列に潰れて縦へ伸びていた** (Steam Deck で 396px)。
     * 横に広い画面ほど札を横へ並べたい (背が低いのはたいてい横長なので、
     * 縦に積むより横へ伸ばすほうが収まる)。
     */
    /*
     * **`vw` は倍率で割る** (原則51)。`zoom` の中では `94vw` が画面そのものの
     * 94% を指すので、UIサイズ 1.3 では実寸で 122% に描かれて画面からはみ出す
     * ―― 1.0 では絶対に出ない壊れかた。
     */
    width: min(660px, calc(94vw / var(--ui-scale)));
    flex: 0 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;   /* 端まで来たら後ろの画面へ流さない */
    /*
     * **縮んでスクロールするのはここだけ** (`.start-screen` の注を参照)。
     * `min-height: 0` が要る —— flex の子は既定で中身より小さくならないので、
     * これが無いと `overflow-y` を書いても縮まず、下段を押し出したままになる。
     * 入口は「つづき」「はじめてのバトル」で増減するので、**行数は決めうちできない**。
     *
     * ただしこれは**落ちないための網であって、ふだん使うものではない**。
     * ここに棒が出ている時点で「入りきっていない」ので、実際に出うる最大の
     * 組み合わせ (主役 + 札4枚) が6通りの画面すべてで**棒を出さずに収まる**ことを
     * `tests/responsive.spec.js` の
     * 「入口はどの画面でも、内側にスクロールを出さずに収まる」が見張る。
     * 網を残すのは、入口を足した日に「入りきらないが遊べる」で済ませるため。
     */
}
/*
 * 小さい札は格子に並べる。**列数は画面が決める** (`auto-fit`) ――
 * 縦長では2列、横長では4列まで自動で伸びるので、背の低い横画面では
 * 1行に収まって縦を食わない。列数を決めうちすると、そのどちらかで必ず溢れる。
 */
.start-tiles {
    display: grid;
    /*
     * 下限を小さめに取る。**いちばん狭い所で2列に届くこと**が要点 ――
     * スマホ縦 (幅393・UIサイズ1.3) では中身の幅が 232px しかなく、
     * 132px では1列に落ちて4枚が縦に積まれ、そのぶん溢れる。
     */
    grid-template-columns: repeat(auto-fit, minmax(108px, 1fr));
    gap: 8px;
}
.start-label { text-align: center; color: var(--text-dim); margin-bottom: 4px; }
.start-diff-btn {
    /*
     * **font-family を書くこと。** ここだけ指定が無く、<button> の
     * ブラウザ既定 (計測では Arial 13.3px) で描かれていた ―― 押しどころの中で
     * ここだけアプリの書体から外れ、日本語も別の字面に落ちていた。
     */
    font-family: inherit;
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 12px;
    padding: 12px 18px;
    border-radius: 12px;
    border: 1px solid var(--panel-border);
    background: rgba(255, 255, 255, 0.05);
    color: var(--text);
    cursor: pointer;
    text-align: left;
    transition: all 0.15s ease;
}
.start-diff-icon { width: 34px; height: 34px; flex: 0 0 34px; display: block; }
.start-diff-body { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 2px; }
.start-diff-btn:hover {
    background: rgba(63, 216, 255, 0.20);
    border-color: var(--you);
    transform: translateY(-1px);
}
/*
 * **主役はこの1枚だけ。** 調べたカードゲームはどれも、周りより明確に大きい
 * ボタンを1つ持っている (Master Duel の DUEL / Marvel Snap の Play /
 * Hearthstone / Slay the Spire の CONTINUE)。中身が何になるかは
 * `main.js` が状態から決めるので、見た目は `kind` で変えない ――
 * 変えると「つづき のときだけ目立つ」というちぐはぐが生まれる。
 */
.start-diff-btn.primary {
    padding: 15px 20px;
    background: linear-gradient(160deg, rgba(34, 195, 240, 0.42), rgba(12, 92, 140, 0.5));
    border-color: rgba(63, 216, 255, 0.7);
}
.start-diff-btn.primary:hover { background: linear-gradient(160deg, rgba(63, 216, 255, 0.55), rgba(12, 92, 140, 0.62)); }
.start-diff-btn.primary .start-diff-icon { width: 42px; height: 42px; flex: 0 0 42px; }
.start-diff-btn.primary .start-diff-label { font-size: 21px; }
.start-diff-btn.primary .start-diff-desc { font-size: 12.5px; }
/*
 * 小さい札。**絵を上・字を下**に積む ―― 横に並べると、いちばん狭い列
 * (スマホ縦で 2列 = 約130px) で絵のぶん字が押し出されて、
 * 「オンライン対戦」が3行に割れる。
 */
.start-diff-btn.tile {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 5px;
    padding: 10px 8px;
}
.start-diff-btn.tile .start-diff-icon { width: 28px; height: 28px; flex: 0 0 28px; }
.start-diff-btn.tile .start-diff-body { flex: none; align-items: center; }
.start-diff-btn.tile .start-diff-label { font-size: 14px; }
.start-diff-btn.tile .start-diff-desc { font-size: 11px; }
.start-diff-label { font-size: 17px; font-weight: 700; }
/*
 * 標識として組む見出し (START / RESUME / TUTORIAL)。
 * 日本語のまま残すメニュー (「ひとりと たたかう」) には付けない ――
 * 日本語に 0.1em の字間をかけると間延びして見える。
 * 付ける判断は hud.js の `isTagLabel()` 1か所が持つ。
 */
.start-diff-label.tag { font-family: var(--font-num); font-size: 19px; letter-spacing: 0.12em; }
/*
 * 説明の1行。**語の途中で割らない** (`.pl-note` と同じ話・原則43)。
 * 日本語は既定でどこでも折れるので、狭い画面では
 * 「全員が2試合たたか / う」と1文字だけ落ちていた。
 * `keep-all` で空白まで、`anywhere` は**どうしても入らないときだけ**の逃げ道。
 */
.start-diff-desc {
    font-size: 12px;
    color: var(--text-dim);
    word-break: keep-all;
    overflow-wrap: anywhere;
}
.start-footer { margin-top: 18px; color: var(--text-dim); font-size: 12px; }
.start-link { display: inline-flex; align-items: center; gap: 5px; }
.start-link-icon { width: 15px; height: 15px; display: block; }

/*
 * 背の低い画面 (横向きスマホなど) ではタイトルまわりを詰める。
 * 下段が居残るのは上の作りで決まっているので、ここは**見た目の話だけ** ――
 * 一画面に入るなら、そのほうがスクロールさせるより気持ちがよい。
 *
 * **ここを「入るように」調整しないこと。** かつて入口が1つ増えるたびに
 * 実測して詰め直す形にしかけたが、それは増えるたびに必ず溢れる作りで、
 * しかも溢れたことに気づけるのは実機を回した人だけだった。
 */
/*
 * 背の低い画面 (横向きスマホなど) ではタイトルまわりを詰める。
 * **媒体クエリではなく `.ui-short`** —— 判定は UIサイズを割ってから行う
 * (`hud.js` の `_markShort` を参照。媒体クエリは実寸しか見られないので、
 * UIを大きくした人のところでだけ詰めが効かなかった)。
 */
/*
 * 背の低い画面では、モーダルの枠じたいを詰める。**高さを増やすのではなく
 * 余白を削る** —— 増やすと画面のふちに貼りつき、押しどころが端に寄る。
 * `92dvh` はオンラインの画面が先に使っていた値で、そこと同じにそろえた。
 */
.ui-short .modal-box { max-height: calc(92dvh / var(--ui-scale)); padding: 14px; gap: 7px; }
.ui-short .modal-title { margin-bottom: 2px; }
/*
 * 背の低い画面では、押しどころも詰める。**押せる大きさは保つ** ――
 * 指で押す下限 (44px 前後) を割らない範囲で、上下の余白だけを削る。
 */
.ui-short .modal-box .hud-btn { padding: 7px 16px; }
.ui-short .modal-box .hud-btn.big { padding: 9px 22px; font-size: 15px; }
.ui-short .start-screen {
    gap: 6px;
    padding: max(10px, calc(env(safe-area-inset-top) / var(--ui-scale))) 12px max(10px, calc(env(safe-area-inset-bottom) / var(--ui-scale)));
}
/*
 * **字の大きさは、持っている高さから決める。**
 * `4.2vw` だけだと横幅しか見ないので、同じ横幅でも背が低いほど窮屈になる ――
 * とくに UIサイズを上げたときは入る高さが倍率ぶん減るので、
 * `dvh` を倍率で割ったぶんを上限に足す (原則51)。段を増やして詰めるより、
 * **持っている高さに連れて縮む**ほうが、次に何か足した日にも耐える。
 */
.ui-short .start-title { font-size: clamp(20px, min(4.2vw, calc(9dvh / var(--ui-scale))), 34px); }
.ui-short .start-subtitle { font-size: 11px; letter-spacing: 0.22em; }
.ui-short .start-panel { margin-top: 6px; padding: 10px 16px; gap: 6px; }
.ui-short .start-diff-btn { padding: 7px 14px; gap: 10px; }
.ui-short .start-diff-icon { width: 28px; height: 28px; flex: 0 0 28px; }
.ui-short .start-diff-label { font-size: 16px; }
.ui-short .start-diff-label.tag { font-size: 17px; }
.ui-short .start-diff-btn.primary { padding: 8px 16px; }
.ui-short .start-diff-btn.primary .start-diff-icon { width: 32px; height: 32px; flex: 0 0 32px; }
.ui-short .start-diff-btn.primary .start-diff-label { font-size: 17px; }
.ui-short .start-diff-btn.primary .start-diff-desc { font-size: 11px; }
.ui-short .start-diff-btn.tile { padding: 6px 8px; gap: 3px; }
.ui-short .start-diff-btn.tile .start-diff-icon { width: 20px; height: 20px; flex: 0 0 20px; }
.ui-short .start-diff-btn.tile .start-diff-label { font-size: 13px; }
/*
 * **札の説明だけは落とす。** 背の低い画面ではここが2行ぶん×札の数を食い、
 * 主役か下段のどちらかが必ず押し出される。落としても札の名前
 * (フリー対戦 / オンライン対戦) だけで用は足りるし、主役の説明は残るので
 * 「いま何をする画面か」は消えない。
 * **これは「入るように詰める」調整ではない** —— 収まりを決めているのは
 * 主役と格子という骨格のほうで、ここは要らない字を落としているだけ。
 */
.ui-short .start-diff-btn.tile .start-diff-desc { display: none; }
.ui-short .start-badges { margin-top: 4px; }
.ui-short .start-badges { gap: 6px; }
.ui-short .start-badge { width: 18px; height: 18px; }
.ui-short .start-record { font-size: 11px; margin-top: 2px; }
.ui-short .start-footer { margin-top: 6px; }

/* ---------- turn chip (top center, minimal) ---------- */
/*
 * 上中央の帯。**中身は px で位置を決めず、縦に積むだけ。**
 * 出ているものだけが順に並ぶので、持ち時間が出たり消えたりしても重ならない。
 * 押すものではないので、層ごと当たり判定を切る (盤面の操作をさえぎらない)。
 */
.hud-topstack {
    position: absolute;
    top: 10px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    z-index: 12;
    pointer-events: none;
    max-width: min(calc(92vw / var(--ui-scale)), 720px);
}

/*
 * 標識 (場所・状態・1語のボタン) は大文字の英語で出すので、
 * 数字と同じ細長い書体をあてる。日本語の本文とは別の役どころだと
 * ひと目で分かり、放送のスコア表示に近づく。
 * どの語を英語にするかの決まりは strings.js の EN にある。
 */
.hud-turnchip, .pl-counts, .start-link, .settings-tab, .tool-label, .online-code-label,
.go-row-label, .deck-col-title, .versus-you, .start-record, .pl-note, #boot-loader {
    font-family: var(--font-num);
    letter-spacing: 0.1em;
}
/*
 * 名札は「じぶん = YOU」だけが英語で、あいてはトレーナーの日本語名。
 * 混ざるので、英語のときだけ標識として組む (判定は hud.js の isTagLabel)。
 */
.pl-name.tag { font-family: var(--font-num); letter-spacing: 0.12em; }

.hud-turnchip {
    padding: 6px 22px;
    border-radius: 999px;
    font-size: 13px;
    font-weight: 700;
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    backdrop-filter: blur(6px);
    z-index: 11;
    pointer-events: none;
}
.hud-turnchip.mine { color: var(--accent); border-color: rgba(63, 216, 255, 0.5); }
.hud-turnchip.theirs { color: var(--opp); }

/*
 * ---------- 持ち時間 (オンラインのみ) ----------
 * ターンチップのすぐ下。**いま動いている人のぶんだけ**を出し、
 * 誰の時間かは陣地の色で示す (じぶん=シアン / あいて=マゼンタ)。
 */
.hud-clock {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 4px 14px;
    border-radius: 999px;
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    backdrop-filter: blur(6px);
    font-family: var(--font-num);
    z-index: 11;
    pointer-events: none;
}
.hud-clock .clock-turn { font-size: 15px; font-weight: 700; display: inline-flex; align-items: center; gap: 4px; }
.clock-icon { width: 16px; height: 16px; display: block; }
.hud-clock .clock-total { font-size: 11px; color: var(--text-dim); }
.hud-clock.mine { color: var(--accent); border-color: rgba(63, 216, 255, 0.45); }
.hud-clock.theirs { color: var(--opp); border-color: rgba(255, 79, 176, 0.45); }
/* のこり10秒。**色だけでなく脈を打たせる** — 数字は盤面を見ていると読み落とす */
.hud-clock.hurry { color: var(--warn); border-color: var(--warn); animation: clock-hurry 1s ease-in-out infinite; }

/*
 * 場のスタジアム (継続効果の常設表示)。上の帯の一員なので位置は積む入れ物に任せ、
 * ここでは見た目だけを決める (px で置くと、持ち時間が出た瞬間に重なる)。
 * どちらの持ち物でもない共有の札なので、陣地の色 (シアン/マゼンタ) は使わない。
 */
}
/* 積む形になったので translateX は要らない (足すと中央から外れる) */
@keyframes clock-hurry {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.09); }
}

/* ---------- prize chip (残りサイド = 勝敗までの距離) ---------- */

/* どちらかが残り2枚 = 決着間近。金色にして緊張を伝える */





/* ---------- battle log drawer (toggle) ---------- */
.hud-logwrap {
    position: absolute;
    left: max(12px, calc(env(safe-area-inset-left) / var(--ui-scale)), var(--safe-x));
    bottom: calc(66px + var(--pad-bar-h));   /* LOG/MENU の列の上。帯のぶんも上げる */
    width: var(--rail-w);
    max-height: calc(46dvh / var(--ui-scale));
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: var(--radius);
    padding: 10px 12px;
    backdrop-filter: blur(8px);
    display: flex;
    flex-direction: column;
    z-index: 25;
}
.hud-log { overflow-y: auto; font-size: 12px; line-height: 1.65; flex: 1; }
.hud-log::-webkit-scrollbar { width: 5px; }
.hud-log::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.2); border-radius: 3px; }
.log-line { color: #c9d4e6; }
.log-turn { color: var(--accent); margin-top: 5px; font-weight: 700; }
.log-important { color: #ffb1b1; font-weight: 700; }

/* ---------- opponent (だれと戦っているか) ---------- */






/* 相手のひとこと */





/* ---------- VS 演出 ---------- */
.versus {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    animation: versus-in 0.4s ease;
}
.versus-you { font-size: 26px; font-weight: 700; color: var(--accent); letter-spacing: 0.1em; }
.versus-vs {
    font-family: var(--font-num);
    font-size: 46px;
    font-weight: 700;
    font-style: italic;
    color: #fff;
    text-shadow: 0 0 26px var(--opp-color, #fff);
    letter-spacing: 0.06em;
}
.versus-opp { display: flex; flex-direction: column; align-items: center; gap: 4px; }
/*
 * **人のふちは1か所で決める。** 出会いの場面 (`.pages-meet img`) と
 * VS画面は 1.9秒差で続けて出るので、別々の数で描くと同じ人の
 * 枠が2種類あることになる。大きさだけそれぞれで上書きする。
 */
.versus-opp img, .versus-icon, .pages-meet img {
    width: 132px;
    height: 132px;
    border-radius: 14px;
    border: 3px solid var(--opp-color, #fff);
    box-shadow: 0 0 34px -6px var(--opp-color, #fff);
}
/* オンラインのあいては肖像が無いので、役割の絵を同じ枠で出す */
.versus-icon {
    display: grid;
    place-items: center;
    font-size: 64px;
    background: rgba(255, 255, 255, 0.06);
}
.versus-title { font-size: 12px; color: var(--text-dim); margin-top: 6px; }
.versus-name { font-size: 26px; font-weight: 700; color: var(--opp-color, #fff); }
.versus-line {
    margin-top: 6px;
    font-size: 13px;
    color: var(--text-dim);
    max-width: 320px;
    text-align: center;
    line-height: 1.7;
}
@keyframes versus-in {
    from { opacity: 0; transform: scale(0.86); }
    to { opacity: 1; transform: scale(1); }
}

/* ---------- 対戦相手をえらぶ ---------- */
.modal-box.trainer-select { width: min(560px, calc(95vw / var(--ui-scale))); }
.ts-grid { display: flex; flex-direction: column; gap: 8px; max-height: calc(58dvh / var(--ui-scale)); overflow-y: auto; }
.ts-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 9px 14px 9px 9px;
    border-radius: 10px;
    border: 1px solid var(--panel-border);
    border-left: 4px solid var(--opp-color, var(--panel-border));
    background: rgba(255, 255, 255, 0.05);
    color: var(--text);
    font-family: inherit;
    cursor: pointer;
    text-align: left;
    transition: all 0.14s ease;
}
.ts-item:hover:not(:disabled) { background: rgba(63, 216, 255, 0.18); transform: translateX(3px); }
.ts-item.locked { opacity: 0.4; cursor: not-allowed; }
.ts-item img { width: 54px; height: 54px; border-radius: 12px; display: block; flex-shrink: 0; }
/*
 * 倒した印。**肖像と同じ大きさにしない** —— 主役は相手の顔で、
 * バッジは「もう勝った」という一言でしかない。右端に小さく添える。
 * `margin-left: auto` なので、説明がどれだけ長くても右端に張りつく。
 */
.ts-item img.ts-badge {
    width: 30px;
    height: 30px;
    margin-left: auto;
    border-radius: 0;
    filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.6));
}
.ts-title { font-size: 10px; color: var(--text-dim); }
.ts-name { font-size: 17px; font-weight: 700; color: var(--opp-color, var(--text)); }
.ts-desc { font-size: 11px; color: var(--text-dim); margin-top: 2px; }

/* 勝ち抜き戦のメニュー */
.start-diff-btn.gauntlet {
    background: linear-gradient(160deg, rgba(250, 204, 21, 0.28), rgba(180, 83, 9, 0.24));
    border-color: rgba(250, 204, 21, 0.7);
}
.start-diff-btn.gauntlet:hover { background: linear-gradient(160deg, rgba(250, 204, 21, 0.42), rgba(180, 83, 9, 0.34)); }

/* ---------- card preview ---------- */

.pv-img { width: 100%; border-radius: 9px; display: block; }
/*
 * 触る画面には ホバーが無いので、詳細の入口は**長押しだけ**。
 * それを画面のどこにも書いていなかった (あそびかたには書いてある)。
 *
 * **パッドには言わない。** TVのブラウザも `hover: none` を名乗るが、パッドの人が
 * 押すのは長押しではなく「カードを見る」のボタンで、それは案内帯 (`setPadHints`) が
 * すでに出している。ここでも言うと、同じことを2か所が**違う言いかたで**言うことになる
 * (しかも片方は嘘)。**出す条件そのものに除外を入れること** ―― あとから
 * `display: none` で打ち消す形にすると、可視かどうかがソースの順番で決まり、
 * 3か所を読んで頭の中で合成しないと分からなくなる (`.pad-glyph` と同じ書きかた)。
 *
 * 図鑑を出さないのは CSS ではなく `cardDetailHTML(..., {dex:false})` の仕事。
 */
.pv-hold { display: none; }
@media (hover: none) {
    html:not([data-input="gamepad"]) .pv-hold {
        display: block;
        margin-top: 8px;
        padding-top: 7px;
        border-top: 1px solid rgba(150, 215, 255, 0.18);
        font-size: 11px;
        color: var(--text-dim);
    }
}
.pv-name { font-weight: 700; font-size: 16px; margin: 8px 0 2px; }
.pv-hp { color: var(--text-dim); font-size: 12px; margin-bottom: 6px; }
.pv-ex { color: var(--accent); font-weight: 700; }
.pv-inline-icon { width: 13px; height: 13px; vertical-align: -2px; }
.pv-attack {
    border-top: 1px solid var(--panel-border);
    padding: 7px 0;
    font-size: 13px;
}
.pv-ability { color: #f87171; font-weight: 700; font-size: 11px; }

/*
 * とくしゅじょうたいの札。色は engine.js の STATUS が持っている値を
 * インラインの --st で受け取る (色の定義を CSS 側にも書くと二重管理になる)。
 */
.pv-statuses { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 6px; }
.pv-status {
    font-size: 10px;
    font-weight: 700;
    padding: 2px 7px;
    border-radius: 999px;
    color: var(--st, #fff);
    border: 1px solid color-mix(in srgb, var(--st, #fff) 55%, transparent);
    background: color-mix(in srgb, var(--st, #fff) 16%, transparent);
    white-space: nowrap;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.pv-status-icon { width: 13px; height: 13px; display: block; }
/* あそびかたの とくしゅじょうたい一覧 (本文は tutorial.js が STATUS から組み立てる) */
.ht-status { margin: 8px 0; padding-left: 18px; }
.ht-status li { margin-bottom: 8px; line-height: 1.5; }
.ht-sub { font-size: 11px; color: var(--text-dim); }

/* 治りかたの1行。札(.pv-status)だけでは「何をすれば治るか」が分からない */
.pv-ability-kind { display: inline; margin-left: 6px; opacity: 0.85; }
.pv-status-note {
    font-size: 10.5px;
    line-height: 1.45;
    color: var(--text-dim, #9aa4bf);
    margin-bottom: 4px;
}
.pv-dmg { float: right; font-family: var(--font-num); font-weight: 700; color: var(--accent); font-size: 16px; }
/*
 * 「カードに刷ってある値 → いま効いている値」。
 * ワザ選択・カード詳細のどちらもこの見た目 (card-view.js の effectiveHTML)。
 * 消したほうを弱く、いまの値を強く。色を変えるだけだと、どちらが
 * 「いま」なのか分からない ので、消したほうに線を引く。
 */
.val-was { text-decoration: line-through; opacity: 0.5; font-weight: 400; }
.val-now { color: var(--accent); }
.pv-text { font-size: 11px; color: var(--text-dim); margin-top: 3px; line-height: 1.5; }
/*
 * 図鑑 (フレーバー) は**字の見た目で分ける**。かつて `FIELD NOTE // 図鑑` と
 * 冠していたが、フレーバーに札を貼るカードゲームは無い ―― どれも斜体と
 * 区切りで示す。見出しを外したぶん、ここが「ルールではない文」だと
 * 分かる手がかりを字のほうに持たせる。
 */
.pv-dex {
    font-style: italic;
    opacity: 0.82;
    margin-top: 9px;
    padding-top: 8px;
    border-top: 1px solid rgba(150, 215, 255, 0.16);
}
/*
 * **上に何も無いなら区切らない。** 拡大では図鑑だけが残ることがあり
 * (減っていない・どうぐも付いていない札)、そこで線を引くと
 * 「何かが上にあるはず」と読ませる線だけが浮く。
 */
.pv-dex:first-child { margin-top: 0; padding-top: 0; border-top: none; }
.pv-meta { font-size: 11px; color: var(--text-dim); margin-top: 5px; }
.cost { display: inline-flex; gap: 3px; margin-right: 6px; vertical-align: middle; }
.pip {
    display: inline-block;
    width: 13px;
    height: 13px;
    border-radius: 50%;
    border: 1px solid rgba(0, 0, 0, 0.4);
    box-shadow: inset 0 1px 1px rgba(255,255,255,0.4);
}

/* ---------- hand (DOM 2D card row) ---------- */
.hud-hand {
    position: absolute;
    bottom: calc(-1 * var(--hand-drop));
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    justify-content: center;
    align-items: flex-end;
    pointer-events: none;          /* 隙間は盤面クリックを透過 */
    z-index: 14;
    transition: transform 0.3s ease, opacity 0.3s ease;
}
/* 下げる(tucked)と押させない(no-input)は別のこと。判断は main.js の入力モード表 */
.hud-hand.tucked {
    /* 78% まで下げると画面に5pxしか残らず、押せる状態でも実際には押せない */
    transform: translateX(-50%) translateY(45%);
    opacity: 0.55;
}
/*
 * **「押せない」と「読めない」は別。**
 * ここは長く pointer-events: none で、あいてのターン・サイド選択・昇格のあいだ
 * 手札を**1枚も読めなかった** (長押しの拡大もホバーの詳細も一緒に死んでいた)。
 * 次の一手を考える時間そのものなのに、いちばん自然に触る場所が無反応だった。
 * 押して場が動く経路は main.js 側に二重の門 (HAND_PICK_MODES と busy 判定) が
 * すでにあるので、ここで入力ごと止める必要は無い。見た目だけ落とす。
 */
.hud-hand.no-input .hand-card { cursor: default; }
.hand-card {
    /*
     * **`<button>` である** (キーボード/コントローラーで焦点を当てるため)。
     * 既定の装飾をここで全部打ち消す —— 打ち消さないと、灰色の下地と枠が付き、
     * 内側に余白が入って扇状の重なりが崩れる。
     */
    appearance: none;
    -webkit-appearance: none;
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: inherit;
    /* 既定の中央寄せ・字間・変換も戻す (いまは効かないが、字を足した日に効く) */
    text-align: left;
    letter-spacing: inherit;
    word-spacing: inherit;
    text-indent: 0;
    text-transform: none;
    display: block;
    position: relative;
    width: var(--hand-w);
    aspect-ratio: 374 / 522;
    margin: 0 clamp(-14px, -1vw, -8px);
    border-radius: 8px;
    transform: rotate(var(--rot, 0deg)) translateY(var(--dy, 0px));
    transform-origin: 50% 110%;
    transition: transform 0.18s ease, filter 0.18s ease;
    cursor: pointer;
    pointer-events: auto;
    /* 指でつまんで運ぶ札なので、ブラウザのスクロール/拡大に取られてはいけない */
    touch-action: none;
    filter: drop-shadow(0 6px 10px rgba(0, 0, 0, 0.45));
}
/*
 * **持ち上げは「指している」ことの語彙。「選んでいる」ことの語彙ではない。**
 *
 * 長く `.hover` と `.selected` が同じ transform を共有し、コントローラーの
 * カーソル (`.gp-focus`) もまったく同じ値だった。そのため札を1枚選んでから
 * カーソルを別の札へ動かすと、**2枚が同時に持ち上がって**どちらが選んだ札か
 * 形では区別できず、差は枠の色 (金 / 氷色) だけになっていた ―― 実際そう報告された。
 *
 * 典拠は2つ:
 *   W3C ARIA APG (Developing a Keyboard Interface)
 *     "There is only one point of focus at any time"
 *     "**The selected state must be visually distinct from the focus indicator.**"
 *   Apple HIG (tvOS) Focus and Selection … Focused =「前面へ持ち上げる・光らせる・動かす」、
 *     Selected =「焦点が当たっていてもいなくても、選ばれた/実行されたことを示す」
 *
 * だから持ち上げるのは `.hover` と `.gp-focus` だけにして、選択は
 * **枠 (金) と形の印 (右上の丸)** で示す ―― 色だけに意味を持たせないのは
 * XAG 103 / Game Accessibility Guidelines / WCAG 1.4.1 の共通要件でもある。
 */
.hand-card.hover {
    transform: rotate(0deg) translateY(-44px) scale(1.32);
    z-index: 300 !important;
    filter: drop-shadow(0 14px 22px rgba(0, 0, 0, 0.6));
}
.hand-card.selected { outline: 3px solid var(--warn); outline-offset: -1px; border-radius: 9px; }
/*
 * 選んだ札の**形の印**。
 *
 * ⚠ **持ち上げは使えない。** あれは「指している」ことの語彙 (上の注) なので、
 * ここに残る非色覚の手がかりは**この印だけ**。枠の色 (金) だけで示すと、
 * 指している札の枠 (氷色) との差が色だけになる (WCAG 1.4.1 / XAG 103)。
 *
 * ⚠ **中身の無い図形にしないこと。** ここは長く塗りつぶしの丸だけで、
 * 遊んだ人に「この丸は何?」と聞かれた ―― 意味を持たない図形は状態の合図に
 * ならず、視覚的な雑音になる (NN/g "Icon Usability")。
 * チェックの印を入れると「選ばれている」が形そのものから読める ――
 * 焦点と選択が分かれる画面 (テレビ・コンソール) では、選択にチェックを出すのが
 * 標準の作法 (Apple HIG tvOS)。
 *
 * 絵は SVG を焼きこむ ―― 字 (✓) だと端末の書体で太さも位置も変わる
 * (`roleBadgeSVG` と同じ事情)。札の中ではなく角に出すので、絵も字も隠さない。
 */
.hand-card.selected::after {
    content: '';
    position: absolute;
    top: 5px;
    right: 5px;
    width: 30%;
    aspect-ratio: 1;
    border-radius: 50%;
    background: var(--warn);
    box-shadow: 0 0 0 2px rgba(4, 10, 20, 0.75), 0 2px 6px rgba(0, 0, 0, 0.6);
    /* チェックの印。色は札の下地 (濃紺) で、金の丸に抜いて見せる */
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5' fill='none' stroke='%23040a14' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-size: 66%;
    background-position: center;
    background-repeat: no-repeat;
}
/*
 * 伏せてある (`tucked`) あいだも、選んだ札だけは読めるようにする。
 * **持ち上げでは示さないこと** ―― 上の決まりが崩れる。薄墨を外すだけでよい。
 */
.hud-hand.tucked .hand-card.selected { opacity: 1; z-index: 300; }
.hand-card.not-playable { filter: grayscale(0.55) brightness(0.75) drop-shadow(0 6px 10px rgba(0,0,0,0.45)); }
.hand-card.not-playable.hover { filter: grayscale(0.3) brightness(0.9) drop-shadow(0 14px 22px rgba(0,0,0,0.6)); }
.hand-card-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 8px;
    display: block;
    /* 選択・ドラッグ・吹き出しはファイル冒頭の `*` の規則がまとめて切っている */
    pointer-events: none;   /* 押されるのは .hand-card 本体。絵が押下を横取りしない */
}
.hand-card.img-fallback::after {
    content: attr(data-label);
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    background: linear-gradient(180deg, #37474f, #263238);
    color: #eceff1;
    font-size: 12px;
    font-weight: 700;
    border-radius: 8px;
    padding: 6px;
    text-align: center;
}
@keyframes hand-card-in {
    from { transform: translateY(90px) rotate(var(--rot, 0deg)); opacity: 0; }
    to { transform: rotate(var(--rot, 0deg)) translateY(var(--dy, 0px)); opacity: 1; }
}
.hand-card.drawn { animation: hand-card-in 0.38s ease backwards; }

/* ---------- ドラッグ&ドロップ ---------- */
/*
 * つまみ上げた札は**分身**を出して指について来させ、本体はその場に薄く残す。
 * 本体そのものを動かすと手札の flex がその場で組み替わり、
 * 隣の札が横へ滑って「どこから持ち上げたか」が分からなくなる。
 */
.hand-card.dragging { opacity: 0.28; filter: grayscale(0.5); }
.hand-drag {
    position: fixed;
    top: 0;
    left: 0;
    /*
     * 手札(14)より前・モーダル(65)より奥。**数字と注が食い違っていた** ――
     * ここは長く 400 で、コメントの言うとおりに読むと逆転していた
     * (`.hand-drag` と `.hud-modal` は どちらも `#hud` の直接の子なので、
     * 数値はそのまま比べられる)。つまむ最中にモーダルが開くと分身が前に出る。
     * 45 は ガイド(38)・紙吹雪(44) より前で、タイトル(50) より奥。
     */
    z-index: 45;
    border-radius: 9px;
    overflow: hidden;
    box-shadow: 0 18px 30px rgba(0, 0, 0, 0.55);
    outline: 3px solid var(--warn);
    outline-offset: -1px;
    transform: translate(-100vw, -100vw);   /* 最初の1フレームで左上に出さない */
    will-change: transform;
}
.hand-drag img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hand-drag.img-fallback::after {
    content: attr(data-label);
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    background: linear-gradient(180deg, #37474f, #263238);
    color: #eceff1;
    font-size: 12px;
    font-weight: 700;
    padding: 6px;
    text-align: center;
}

/* ---------- prompt (top center) & buttons (bottom right) ---------- */

.hud-prompt {
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    padding: 7px 18px;
    border-radius: 999px;
    font-size: 14px;
    font-weight: 700;
    color: var(--accent);
    backdrop-filter: blur(6px);
    max-width: 100%;
    text-align: center;
    z-index: 12;
}

/*
 * ボタンの文字を**箱の外に出さない**。決まりは2つ:
 *   ・ラベル (1行目) は折り返さない ―― 短く作る設計なので、折り返す状況が異常。
 *     収まらないときだけ「…」で箱の中に切る (.btn-row / .btn-label 側)。
 *   ・文章 (押せない理由の赤字 .btn-sub) だけ折り返す ―― 10.5px の文を
 *     読める形はそれしか無い。実在の最長文でも2行で収まる。
 * 以前は `.hud-btn { white-space: nowrap }` が**ボタン全体**に効いていて、
 * 理由の文がボタンの右へあふれていた。直しかたも「あふれた場所にだけ
 * normal を書き足す」(deck-nav がそうだった) だったので、長文が増えるたび
 * 再発した。nowrap をボタン全体に書かないこと。
 * `overflow-wrap: anywhere` は保険 ―― 区切りの無い長い語も箱の端で折る。
 * `min-width: 0` は横に並べたとき (flex) にボタンが中身より縮めるようにする。
 * これが無いと折り返しの前に**行の入れ物のほう**からはみ出す。
 * 見張りは tests/responsive.spec.js の「押せない理由がボタンからあふれない」。
 */
.hud-btn {
    white-space: normal;
    overflow-wrap: anywhere;
    min-width: 0;
    padding: 10px 18px;
    border-radius: 12px;
    border: 1px solid var(--panel-border);
    background: rgba(20, 28, 48, 0.92);
    color: var(--text);
    font-size: 14px;
    font-weight: 700;
    font-family: inherit;
    cursor: pointer;
    transition: all 0.13s ease;
    backdrop-filter: blur(6px);
}
.hud-btn:hover:not(:disabled) { transform: translateY(-2px); border-color: var(--you); background: rgba(20, 74, 104, 0.95); }
.hud-btn:disabled { opacity: 0.42; cursor: not-allowed; }
.hud-btn.primary {
    background: linear-gradient(160deg, #57e2ff, #0b8fc4);
    border-color: #8beeff;
    color: #03121c;                      /* 明るい面には暗い文字。いちばん強いボタンにする */
    text-shadow: none;
}
.hud-btn.primary:hover:not(:disabled) { background: linear-gradient(160deg, #7eeaff, #14a8dd); }
.hud-btn.ghost { background: transparent; }
.hud-btn.big { font-size: 17px; padding: 13px 30px; }

/* ---------- banner ---------- */
/*
 * できごとの名前を出す帯。
 *
 * **字の大きさを px で固定しないこと。** 30px 決め打ち＋nowrap だったため、
 * 「🃏 ふしぎなアメあまあま」のような長い札名がスマホの画面幅を超え、
 * 左右にはみ出して読めなくなっていた。カード名は人が足すものなので、
 * 長さの上限は決められない ―― 箱のほうを画面に合わせる。
 * 上限を vw と vh の**両方**で抑えるのは、横向きスマホ (高さ390px) で
 * vw だけ見ると字が巨大になり、盤面が隠れてしまうため。
 */
.hud-banner {
    position: absolute;
    top: 18%;
    left: 50%;
    transform: translateX(-50%);
    padding: clamp(8px, 2vw, 14px) clamp(16px, 5vw, 46px);
    font-size: clamp(17px, min(5.2vw, 4.6vh), 30px);
    font-weight: 700;
    line-height: 1.25;
    border-radius: 999px;
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    backdrop-filter: blur(8px);
    animation: banner-pop 0.35s ease;
    max-width: calc(92vw / var(--ui-scale));
    text-align: center;
    overflow-wrap: anywhere;
    z-index: 30;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
}
.banner-icon { width: 1.25em; height: 1.25em; flex: 0 0 1.25em; display: block; }
.banner-text { min-width: 0; }
/* ---------- ワザ発動のカットイン ---------- */
/*
 * 「いま どのカードが 何を撃ったか」を毎回見せる層。
 * 盤面のカードは小さく斜めなので、ここでしか札の顔は見えない。
 * クリックは通す (演出中に操作を殺さない)。
 */
#hud > .hud-cutin { pointer-events: none; }
.hud-cutin {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    z-index: 32;
    overflow: hidden;
}
/* 走る線。速さと勢いはほぼこれが作る */
.cutin-streaks {
    position: absolute;
    inset: -20% -40%;
    background: repeating-linear-gradient(
        105deg,
        transparent 0 14px,
        rgba(255, 255, 255, 0.055) 14px 16px,
        transparent 16px 34px);
    animation: cutin-streaks var(--cutin-ms, 620ms) linear;
}
.hud-cutin.mine .cutin-streaks { background-color: rgba(63, 216, 255, 0.10); }
.hud-cutin.theirs .cutin-streaks { background-color: rgba(255, 79, 176, 0.10); }

.cutin-body {
    display: flex;
    align-items: center;
    gap: clamp(12px, 3vw, 40px);
    padding: clamp(10px, 2vw, 22px) clamp(14px, 4vw, 54px);
    /* 画面をはみ出させない。はみ出したぶんは overflow:hidden に切られて読めなくなる */
    max-width: min(calc(94vw / var(--ui-scale)), 1000px);
    background: linear-gradient(90deg, rgba(5, 9, 18, 0) 0%, rgba(5, 9, 18, 0.92) 18%, rgba(5, 9, 18, 0.92) 82%, rgba(5, 9, 18, 0) 100%);
    animation: cutin-body var(--cutin-ms, 620ms) cubic-bezier(.16, .9, .3, 1);
}
/*
 * カードの大きさは**画面の高さ**で決める。
 * 3D側の「手札から起こして見せる」(board3d の REVEAL_FRACTION) も高さ基準なので、
 * DOMのカットインと3Dの見せかたが、どの端末でも同じくらいの大きさでそろう。
 * 幅 (vw) で決めると、縦長のスマホでは小さく、横長のPCでは巨大になる。
 */
.cutin-card {
    height: clamp(96px, calc(32vh / var(--ui-scale)), 240px);
    width: auto;
    aspect-ratio: 374 / 522;
    object-fit: cover;
    flex: 0 0 auto;
    border-radius: 8px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.7);
    animation: cutin-card var(--cutin-ms, 620ms) cubic-bezier(.16, .9, .3, 1);
}
.hud-cutin.mine .cutin-card { box-shadow: 0 0 0 2px var(--you), 0 12px 40px rgba(0, 0, 0, .7); }
.hud-cutin.theirs .cutin-card { box-shadow: 0 0 0 2px var(--opp), 0 12px 40px rgba(0, 0, 0, .7); }
/*
 * ex のカットインは金。金は「勝ちに直結するもの」(決着間近・コイン・勝ち抜き戦)
 * の色で、ex はサイド2枚 = 勝敗そのものを賭けた札なので同じ仲間に入れる。
 * どちらの側の ex でも金 ―― 陣地の色 (シアン/マゼンタ) は帯と斜線が言い続ける。
 */
.hud-cutin.ex .cutin-card {
    box-shadow: 0 0 0 2px #f4c542, 0 0 34px rgba(244, 197, 66, .5), 0 12px 40px rgba(0, 0, 0, .7);
}
.hud-cutin.ex .cutin-name { color: #ffe08a; text-shadow: 0 0 18px rgba(244, 197, 66, .55); }

.cutin-text { animation: cutin-text 0.62s cubic-bezier(.16, .9, .3, 1); min-width: 0; }
.cutin-owner { font-size: clamp(10px, 1.4vh, 12px); letter-spacing: .3em; color: var(--text-dim); }
.cutin-name { font-size: clamp(13px, min(2vw, 2.4vh), 22px); font-weight: 700; color: var(--text); }
/*
 * ワザ名は **折り返させる**。nowrap のままだと「エレキブラストキャノン」のような
 * 長い名前がスマホで画面幅を超え、overflow:hidden に切り落とされて読めなかった。
 * 名前の長さはカードを足す人が決めるので、上限は決められない。
 */
.cutin-attack {
    font-size: clamp(20px, min(4.4vw, 5.2vh), 54px);
    font-weight: 800;
    line-height: 1.15;
    overflow-wrap: anywhere;
}
.hud-cutin.mine .cutin-attack { color: var(--you); text-shadow: 0 0 26px rgba(63, 216, 255, .55); }
.hud-cutin.theirs .cutin-attack { color: var(--opp); text-shadow: 0 0 26px rgba(255, 79, 176, .55); }
.cutin-dmg {
    font-family: var(--font-num);
    font-size: clamp(24px, min(5vw, 6vh), 60px);
    font-weight: 800;
    color: #fff;
}
/* 大技のときだけ、もう一段強く */
.hud-cutin.big .cutin-attack { font-size: clamp(23px, min(5.4vw, 6.2vh), 66px); }
/* 「タップでとばせる」ことを小さく出す (毎回は出さない。最初の数回だけ) */
.cutin-skip { position: absolute; bottom: 12%; width: 100%; text-align: center;
    font-size: 11px; letter-spacing: .2em; color: var(--text-dim); opacity: .75; }

@keyframes cutin-streaks {
    0%   { opacity: 0; transform: translateX(-8%); }
    18%  { opacity: 1; }
    100% { opacity: 0; transform: translateX(8%); }
}
@keyframes cutin-body {
    0%   { opacity: 0; transform: scaleY(0.2); }
    9%   { opacity: 1; transform: scaleY(1); }
    88%  { opacity: 1; }
    100% { opacity: 0; }
}
/*
 * 出入りは速く、**止まっている時間を長く**。
 * 以前は 22%→82% しか静止しておらず、620ms のうち読めるのは 372ms だけだった。
 * カード名とワザ名の2行を読むには足りない。
 * 総時間を伸ばすのではなく配分を変える (総時間はJS側が重さに応じて決める)。
 */
@keyframes cutin-card {
    0%   { transform: translateX(-56px) rotate(-7deg); opacity: 0; }
    13%  { transform: translateX(0) rotate(-3deg); opacity: 1; }
    88%  { transform: translateX(0) rotate(-3deg); opacity: 1; }
    100% { transform: translateX(20px) rotate(-3deg); opacity: 0; }
}
@keyframes cutin-text {
    0%   { transform: translateX(48px); opacity: 0; }
    14%  { transform: translateX(0); opacity: 1; }
    88%  { opacity: 1; }
    100% { opacity: 0; }
}
/*
 * 縦画面ではカードを上・文字を下に積む。
 * 横に並べたままだと、スマホ縦(390px)ではカードに幅を取られて
 * 文字の入る場所が 110px ほどしか残らず、ワザ名が縦一列に崩れる。
 */
@media (orientation: portrait) {
    .cutin-body {
        flex-direction: column;
        text-align: center;
        gap: clamp(8px, 1.6vh, 18px);
        padding: clamp(10px, 2vh, 20px) clamp(14px, 4vw, 32px);
        background: linear-gradient(180deg, rgba(5, 9, 18, 0) 0%, rgba(5, 9, 18, 0.92) 12%, rgba(5, 9, 18, 0.92) 88%, rgba(5, 9, 18, 0) 100%);
    }
    .cutin-card { height: clamp(90px, calc(26vh / var(--ui-scale)), 220px); }
    /* 縦では文字に幅があるので、幅(vw)ではなく高さで抑える */
    .cutin-attack { font-size: clamp(22px, 4.2vh, 46px); }
    .cutin-dmg { font-size: clamp(24px, 4.6vh, 52px); }
    /* 「タップでとばせる」を行動まとまりの上へ逃がす (帯の高さは hud.js が実測) */
    .cutin-skip { bottom: calc(var(--band-bottom) + 6px); }
}

/* 「がめんの ゆれ」を切っている人には、動きを止めて出すだけにする */
@media (prefers-reduced-motion: reduce) {
    .cutin-streaks, .cutin-body, .cutin-card, .cutin-text { animation: none; }
}

.hud-banner.mine { color: var(--accent); border-color: rgba(63, 216, 255, 0.55); }
.hud-banner.theirs { color: var(--opp); }
.hud-banner.skip { color: #c084fc; }
@keyframes banner-pop {
    0% { transform: translateX(-50%) scale(0.7); opacity: 0; }
    100% { transform: translateX(-50%) scale(1); opacity: 1; }
}

/* ---------- toasts ---------- */
.hud-toasts {
    position: absolute;
    bottom: calc(var(--hand-h) + 26px);   /* 手札の上に出す。重ねると札が読めない */
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    z-index: 68;    /* モーダルの上 (設定画面から出す案内が隠れないように) */
}
.toast {
    background: rgba(190, 40, 50, 0.92);
    color: #fff;
    font-size: 13px;
    font-weight: 700;
    padding: 8px 20px;
    border-radius: 999px;
    opacity: 0;
    transform: translateY(8px);
    transition: all 0.3s ease;
    box-shadow: 0 6px 18px rgba(0,0,0,0.4);
}
.toast.show { opacity: 1; transform: translateY(0); }

/* ---------- modal ---------- */
.hud-modal {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    background: rgba(5, 8, 16, 0.55);
    backdrop-filter: blur(4px);
    /* スタート画面(50)・デッキ画面(52) より前に出す。
       ここが低いと、タイトルから開いた設定や「あそびかた」がクリックできない。
       **注に書く番号は、実際にある宣言だけにすること** —— かつてここには
       「右上ギア(60)」と書いてあったが、`z-index: 60` はファイル中に1つも無く、
       消したUIの注だけが残っていた (数字の注は実装に追従しない典型) */
    z-index: 65;
}
.modal-box {
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: 12px;
    padding: 22px;
    width: min(430px, calc(92vw / var(--ui-scale)));
    display: flex;
    flex-direction: column;
    gap: 9px;
    max-height: calc(80dvh / var(--ui-scale));
    /*
     * **箱そのものは流れない。溢れるのは中身だけ、ボタン列は必ず居残る。**
     *
     * ここは長く `overflow-y: auto` で、箱ごと流れていた。すると背の低い画面で
     * 「キャンセル」や「閉じる」が箱の下端の向こうへ行き、**先へ進む唯一の手が
     * 押せなくなる**。実測でデッキえらびは PC (1440x900) ですら
     * キャンセルが y=901 ―― 画面の外にあった。
     * この形はオンラインの画面だけが `.online-scroll` で先に解いていたが、
     * **例外にしておくと、次に増えた画面で必ず再発する**ので既定にした。
     * 長い中身を持つ画面は `.modal-scroll` で包むこと (包み忘れると切れるので、
     * `tests/fit.spec.js` が6通りの画面で見張る)。
     */
    overflow: hidden;
}
/*
 * 溢れを引き受ける中身。**ボタン列はこの外に置く。**
 * `min-height: 0` が要る —— flex の子は既定で中身より縮まないので、
 * これが無いと `overflow-y` が効かず、結局ボタンが押し出される。
 * `.online-scroll` は同じもの (先に生まれた名前なので残してある)。
 */
.modal-scroll, .online-scroll {
    display: flex;
    flex-direction: column;
    gap: 9px;
    min-height: 0;
    overflow-y: auto;
    /*
     * **`scrollbar-gutter: stable` は書かない。**
     * あれは棒のぶん (実測15px) を**溢れていなくても常に**空けるので、
     * この中に入っている札だけが、箱に直に置いたボタン (キャンセル・閉じる) より
     * 15px 細くなる ―― 同じ列に並んでいるのに幅が違う、という形で必ず目につく。
     * 実際「ボタンによって幅が違うのは仕様?」と聞かれた。
     * 溢れたときだけ棒のぶん狭くなるのは、どの画面でも起きるふつうのことで、
     * そこを避けるために**溢れていない画面の並びを崩す**のは割に合わない。
     */
}
/*
 * ボタン列。**背の低い横画面では横に並べる。**
 * 縦積みだと3つで 165px ―― 箱が 312px しかない横向きスマホ (390px) では
 * 半分以上をボタンが占め、コードも名札もスクロールの向こうへ消えていた。
 * 幅は足りている (844px) ので、そこは横に使う。
 * 境目の 480px は「横向きスマホ」の高さ。タブレット横 (768〜) は縦積みのまま。
 */
.online-actions { display: flex; flex-direction: column; gap: 9px; }
@media (max-height: 480px) {
    .online-actions { flex-direction: row; flex-wrap: wrap; }
    /* いちばん進める行動を広めに (どれも同じ幅だと、目が迷う) */
    .online-actions .hud-btn { flex: 1 1 auto; }
    .online-actions .hud-btn.primary { flex: 2 1 auto; }
    /*
     * **コードの枠を詰める。** 44px の字は箱 312px のうち 103px を食い、
     * それだけでスクロール域 (112px) が埋まって**コードが見きれていた**。
     * ―― この画面でいちばん見せたいものが、いちばん場所を取って自分を隠す。
     * 手に持った端末で読み上げる字なので、30px でも十分に大きい
     * (Jackbox や Kahoot が巨大なのは、離れたテレビに映すため)。
     */
    .modal-box.online { max-height: calc(92dvh / var(--ui-scale)); }
    .online-code { padding: 8px; margin: 2px 0; }
    .online-code-value { font-size: 30px; }
}
.modal-title { font-size: 18px; font-weight: 700; text-align: center; margin-bottom: 6px; }
.attack-option {
    text-align: left;
    padding: 12px 14px;
    border-radius: 12px;
    border: 1px solid var(--panel-border);
    background: rgba(255, 255, 255, 0.05);
    color: var(--text);
    font-size: 15px;
    font-family: inherit;
    cursor: pointer;
    transition: all 0.13s ease;
}
.attack-option:hover:not(.disabled) { background: rgba(63, 216, 255, 0.20); border-color: var(--you); }
.attack-option.disabled { opacity: 0.45; cursor: not-allowed; }
/*
 * えらぶ画面の格子。**横に広い画面では2〜3列に並べる。**
 * デッキえらびは7件あり、1列だとどの端末でも溢れる (実測で PC でも 160px)。
 * 列数は入れ物の幅が決める (`auto-fit`) ので、狭い画面では自然に1列へ戻る。
 */
/*
 * えらぶ画面の並び。**1列のまま**にしてある。
 *
 * 横に広い画面では格子 (2〜3列) にすると縦は詰まるが、**コントローラーの
 * カーソルが行き止まる** —— 方向ナビは矩形の距離で次を選ぶので、
 * 7件が3列に折り返すと、下→右→上→左 と押しても回り込めない組が出る
 * (実測でデッキえらび7件のうち3件にしか届かなかった)。
 * 縦に伸びるぶんは `.modal-scroll` が引き受け、キャンセルは箱に残るので
 * 「進む唯一の手が押せない」形にはならない。
 */
.choices-list { display: flex; flex-direction: column; gap: 8px; }
/*
 * **取り返しのつかない選択肢。**
 *
 * 赤は「意味の色」で、陣地の2色 (シアン/マゼンタ) とは別の役目 (原則15)。
 * **枠と字だけを赤くし、塗らない** —— 塗ると `primary` と同じ強さに見えて、
 * 「目立つから」という理由で読まずに押される (Apple HIG が destructive を
 * primary ロールに割り当てるなと明記しているのはこのため)。
 * 色だけに頼らないよう、呼ぶ側は文言に**何が起きるか**を書くこと
 * (WCAG 1.4.1 ―― 赤緑の見分けは男性の約8人に1人に影響する)。
 */
.attack-option.danger, .hud-btn.danger {
    border-color: rgba(248, 113, 113, 0.75);
    color: #fca5a5;
    background: rgba(248, 113, 113, 0.10);
}
.attack-option.danger:hover:not(.disabled), .hud-btn.danger:hover:not(:disabled) {
    background: rgba(248, 113, 113, 0.22);
    border-color: #f87171;
}
.choice-option-main { display: flex; align-items: center; gap: 10px; font-weight: 700; }
.choice-option-icon { width: 1.7em; height: 1.7em; flex: 0 0 1.7em; display: block; }
.choice-theme-icon {
    width: 38px;
    height: 30px;
    flex: 0 0 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 3px;
    border: 1px solid rgba(219, 234, 254, 0.3);
    border-radius: 7px;
    background: #0b1220;
    box-shadow: inset 0 0 0 1px rgba(103, 232, 249, 0.08);
}
.choice-theme-icon .type-sigil { width: 23px; height: 23px; display: block; }
.choice-theme-icon.types-2 .type-sigil { width: 21px; height: 21px; }
.choice-theme-icon.types-2 .type-sigil + .type-sigil { margin-left: -5px; }
.choice-theme-more { margin-left: 1px; color: var(--text-dim); font: 700 10px var(--font-num); }
.atk-name { font-weight: 700; }
.atk-dmg { float: right; font-family: var(--font-num); font-weight: 700; color: var(--accent); font-size: 19px; }
.atk-text { font-size: 12px; color: var(--text-dim); margin-top: 4px; }
.atk-reason { font-size: 11px; color: #f87171; margin-top: 4px; }
.atk-tags { margin-top: 5px; display: flex; gap: 6px; flex-wrap: wrap; }
.atk-tag { font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 999px; }
.atk-tag.weak { background: rgba(251, 146, 60, 0.22); color: #fdba74; }
.atk-tag.lethal { background: rgba(239, 68, 68, 0.24); color: #fca5a5; }
.atk-tag.none { background: rgba(148, 163, 184, 0.2); color: #cbd5e1; }
.atk-tag.coin { background: rgba(250, 204, 21, 0.2); color: #fde047; }
.atk-dmg b { color: #ff8f4d; }
/*
 * ワザを選ぶ前の断り (こんらん)。色は状態そのものの色を継ぐ (--st)。
 * **日本語は語の途中で割らない** (原則13 と同じ話がここにも要る)。
 */
.atk-warn {
    display: flex; align-items: center; gap: 7px;
    margin: 0 0 10px; padding: 8px 11px; border-radius: 10px;
    background: color-mix(in srgb, var(--st) 16%, transparent);
    border: 1px solid color-mix(in srgb, var(--st) 45%, transparent);
    font-size: 12px; line-height: 1.5; color: var(--text);
    word-break: keep-all; overflow-wrap: anywhere;
}
.atk-warn b { color: var(--st); margin-right: 3px; }
.atk-warn-icon { width: 17px; height: 17px; flex: none; }

/* ---------- card list (trash viewer) ---------- */
.modal-box.cardlist { width: min(680px, calc(94vw / var(--ui-scale))); position: relative; }
.cardlist-empty { text-align: center; color: var(--text-dim); padding: 26px 0; }
/* セル固定の理由は .deck-pool と同じ (aspect-ratio だと行がつぶれて重なる) */
.cardlist-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, 82px);
    grid-auto-rows: 114px;
    justify-content: center;
    gap: 8px;
    max-height: calc(52dvh / var(--ui-scale));
    overflow-y: auto;
    padding: 2px;
}
.cardlist-item {
    position: relative;
    width: 82px;
    height: 114px;
    border-radius: 7px;
    overflow: hidden;
    cursor: pointer;
    background: rgba(255, 255, 255, 0.06);
    transition: transform 0.13s ease, box-shadow 0.13s ease;
}
.cardlist-item:hover { transform: translateY(-3px); box-shadow: 0 8px 16px rgba(0, 0, 0, 0.5); }
.cardlist-item img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cardlist-item.img-fallback::after {
    content: attr(data-label);
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    background: linear-gradient(180deg, #37474f, #263238);
    font-size: 10px;
    font-weight: 700;
    text-align: center;
    padding: 4px;
}
.cardlist-zoom {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    align-content: center;
    gap: 10px;
    background: rgba(5, 8, 16, 0.88);
    border-radius: 12px;
    cursor: zoom-out;
    z-index: 2;
}
.cardlist-zoom img { width: min(240px, 60%); border-radius: 12px; display: block; }
.cardlist-zoom-name { font-weight: 700; font-size: 16px; }

/* ---------- game over ---------- */
/*
 * 結果画面は行が増えがち (相手のひとこと・道のり・内訳表)。
 * **溢れを引き受けるのは中身 (`.modal-scroll`)、ボタンは箱に残る** ――
 * ボタンが押せない結果画面は行き止まりになる。
 *
 * ここは長く「箱ごと流して、ボタンを `position: sticky` で貼りつける」形だった。
 * 貼りつければ見えはするが、**箱そのものにスクロール棒が出る**ので、
 * 「入りきっていない」ことに変わりはない (実測でスマホ横 192px)。
 * いまはモーダル共通の骨格に合わせてある。
 */
.modal-box.gameover {
    align-items: center;
    text-align: center;
    padding: 32px 28px;
    max-height: calc(92dvh / var(--ui-scale));
}
.modal-box.gameover > .modal-scroll { align-items: center; width: 100%; }
.modal-box.gameover .hud-btn { width: 100%; flex: none; }
/* 背の低い画面では、ごほうびの絵を小さくして中身自体を縮める */
@media (max-height: 700px) {
    .modal-box.gameover { padding: 20px 22px; }
}
.go-title { font-family: var(--font-num); font-size: 44px; font-weight: 700; letter-spacing: 0.04em; }
.go-title.win { color: var(--accent); text-shadow: 0 0 30px rgba(63, 216, 255, 0.55); }
.go-title.lose { color: #93a0b8; }
.go-reason { color: var(--text-dim); margin-bottom: 6px; }
.go-summary {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 6px 0 12px;
    padding: 12px 14px;
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.05);
}
.go-row { display: flex; justify-content: space-between; gap: 14px; font-size: 13px; padding: 3px 0; }
.go-row-label { color: var(--text-dim); }
.go-row-value { font-weight: 700; }

/* タイトルの通算成績 */
.start-record { color: var(--text-dim); font-size: 13px; margin-top: 6px; }

/* ---------- settings ---------- */
.modal-box.settings { width: min(460px, calc(94vw / var(--ui-scale))); gap: 12px; }
.settings-tabs { display: flex; gap: 6px; }
.settings-tab {
    flex: 1;
    padding: 9px 4px;
    border-radius: 10px;
    border: 1px solid var(--panel-border);
    background: rgba(255, 255, 255, 0.04);
    color: var(--text-dim);
    font-family: inherit;
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
    transition: all 0.13s ease;
}
.settings-tab.active { background: rgba(63, 216, 255, 0.22); border-color: var(--you); color: var(--text); }
/*
 * 設定の中身。**溢れを引き受けるのはここ** (「閉じる」は箱に残る・`.modal-box` の注)。
 * 下限を `min()` にしてあるのは、背の低い画面 (スマホ横 393px) では 208px が
 * そのまま溢れの原因になるから ―― 下限はタブが切り替わるたびに箱の高さが
 * 跳ねないためのもので、収まりより優先するものではない。
 */
.settings-body {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-height: min(208px, calc(24dvh / var(--ui-scale)));
    overflow-y: auto;
}
.settings-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 12px;
    border-radius: 11px;
    background: rgba(255, 255, 255, 0.04);
}
.settings-row.column { flex-direction: column; align-items: stretch; gap: 8px; }
.settings-head { display: flex; align-items: center; justify-content: space-between; }
.settings-label { font-size: 14px; font-weight: 700; }
/* 安全側を切る設定の但し書き。切ると何が起きるかをその場で読ませる */
.settings-note { font-size: 12px; color: var(--text-dim); line-height: 1.5; }
.settings-value { color: var(--accent); font-weight: 700; font-size: 13px; }
.settings-slider { width: 100%; accent-color: var(--primary); cursor: pointer; height: 24px; }
/*
 * ON/OFF の行。**行ぜんたいがボタン。**
 * 見た目は `.settings-row` に乗せ、ここは「押せる矩形を行いっぱいにする」ぶんだけ。
 * 理由は hud.js の `_switch` にある ―― 右端の小さな島は方向ナビで素通りされる。
 */
.settings-toggle {
    width: 100%;
    border: 0;
    color: var(--text);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
/* 入れ子で使うときは、外側がもう行なので背景を二重にしない */
.settings-row > .settings-toggle, .settings-head > .settings-toggle { background: none; padding: 0; }
.settings-switch {
    /* 中の丸薬。**押す口ではない** (行ぜんたいが押せる) */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    min-width: 62px;
    padding: 8px 0;
    border-radius: 999px;
    border: 1px solid var(--panel-border);
    background: rgba(255, 255, 255, 0.07);
    color: var(--text-dim);
    font-family: inherit;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
    transition: all 0.13s ease;
}
.settings-switch.on { background: linear-gradient(160deg, #3fd8ff, #0b8fc4); border-color: #8beeff; color: #03121c; }
.settings-choices { display: flex; gap: 6px; }
.settings-choice {
    flex: 1;
    padding: 9px 4px;
    border-radius: 10px;
    border: 1px solid var(--panel-border);
    background: rgba(255, 255, 255, 0.05);
    color: var(--text-dim);
    font-family: inherit;
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
    transition: all 0.13s ease;
}
.settings-choice.active { background: rgba(63, 216, 255, 0.22); border-color: var(--you); color: var(--text); }

/*
 * ボタンの割り当ての一覧。**2列の格子**にする ―― 役どころは8つあるので、
 * 1行1項目で縦に並べると、背の低い画面 (横向きスマホ) で「もとにもどす」が
 * 画面の外へ落ちる。落ちると**触って分からなくなった子が戻れない**。
 */
.pad-map {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 6px;
}
.pad-map-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    min-width: 0;
}
.pad-map-name {
    font-size: 12px;
    color: var(--text-dim);
    /* 日本語は語の途中で割らない (原則13) */
    word-break: keep-all;
    overflow-wrap: anywhere;
    min-width: 0;
}
/* 見た目は `.settings-choice` に乗せ、絵との間隔と「伸びない」ことだけ足す */
.pad-map-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    flex: 0 0 auto;
    padding: 6px 9px;
    color: var(--text);
}
.pad-map-btn .pad-glyph { width: 1.4em; height: 1.4em; color: var(--focus-ring); }
/* 待ち受け中。**色だけで示さない** ―― 枠も点滅させて、動いていることを形で出す */
.pad-map-btn.capturing {
    border-color: var(--you);
    background: rgba(63, 216, 255, 0.18);
    animation: pad-capture 0.9s ease-in-out infinite;
}
@keyframes pad-capture {
    50% { border-color: rgba(63, 216, 255, 0.35); }
}
.settings-info {
    padding: 10px 12px;
    color: var(--text-dim);
    font-size: 12px;
    line-height: 1.9;
    text-align: center;
}

/* ---------- corner ---------- */




/* 右上: 設定/ポーズ (タイトル画面より手前に出す) */


/* タイトル画面のサブリンク */
.start-link {
    background: transparent;
    border: none;
    color: var(--text-dim);
    font-family: inherit;
    font-size: 12px;
    cursor: pointer;
    padding: 6px 10px;
    border-radius: 8px;
    transition: color 0.13s ease;
}
.start-link:hover { color: var(--text); text-decoration: underline; }

/* ---------- deck builder ---------- */
.deck-screen {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    background: rgba(7, 10, 20, 0.9);
    backdrop-filter: blur(6px);
    z-index: 52;
    padding: 16px;
}
.deck-panel {
    /* 親 (.deck-screen) が左右 16px の余白を持つので、vw で指定すると
       16px×2 ぶん必ずはみ出す (320px幅で右端が 323px になっていた)。
       100% = 余白を引いたあとの幅 */
    width: min(560px, 100%);
    max-height: calc(92dvh / var(--ui-scale));
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 20px;
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: 12px;
    overflow: hidden;
}
/* 3列 (一覧/図鑑/デッキ) になったぶん広げる。図鑑のカードを大きく出すため広めに取る */
.deck-panel.wide {
    width: min(1240px, 100%);
    /*
     * 編集画面は**入れ物の高さを固定し、中身は flex の配分だけで決める**。
     * 高さを中身に任せると、カードを選ぶ・デッキに足すたびに図鑑や内訳の
     * ぶんだけパネルごと伸び縮みして画面全体が跳ねる (実際に起きた)。
     * 中の箱に height を書いても直らない — 箱は `flex: 1` (= basis 0) なので
     * **height は flex の配分に負けて無視される**。だから入れ物side で固定する。
     */
    height: min(calc(92dvh / var(--ui-scale)), 860px);
}
.deck-title {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    font-size: 20px;
    font-weight: 700;
    text-align: center;
}
.deck-title-icon { width: 28px; height: 28px; display: block; }
.deck-note { font-size: 11px; color: var(--text-dim); text-align: center; }
.deck-empty { color: var(--text-dim); font-size: 13px; text-align: center; padding: 22px 8px; }

.deck-list { display: flex; flex-direction: column; gap: 8px; overflow-y: auto; }
.deck-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 11px 14px;
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid transparent;
}
.deck-row.invalid { border-color: rgba(248, 113, 113, 0.45); }
.deck-row-name { font-weight: 700; font-size: 15px; }
.deck-row-meta { font-size: 11px; color: var(--text-dim); margin-top: 2px; }
.deck-row.invalid .deck-row-meta { color: #f87171; }
.deck-row-acts { display: flex; gap: 6px; flex-shrink: 0; }
.deck-row-acts .hud-btn { padding: 7px 11px; font-size: 12px; min-height: 36px; }

.deck-editor-head { display: flex; align-items: center; gap: 12px; }
.deck-editor-icon { width: 30px; height: 30px; flex: 0 0 30px; display: block; }
.deck-name-input {
    flex: 1;
    /* min-width が既定 (auto) のままだと入力欄が縮まず、
       となりの枚数カウンタを画面の外へ押し出す (320px幅で右端 352px) */
    min-width: 0;
    padding: 9px 13px;
    border-radius: 10px;
    border: 1px solid var(--panel-border);
    background: rgba(255, 255, 255, 0.07);
    color: var(--text);
    font-family: inherit;
    /* font-size は共通の下限 (16px) に任せる。16px未満を書くとiOSの拡大が戻る */
    font-weight: 700;
}
.deck-counter { font-family: var(--font-num); font-weight: 700; font-size: 16px; color: #f87171; white-space: nowrap; }
.deck-counter.ok { color: #4ade80; }

/*
 * デッキ編集は3列: 一覧 / 図鑑 / デッキのなかみ。
 * **flex-wrap は使わないこと**。せまい画面用に flex-direction: column を
 * かけてあるので、wrap を足すと「縦に積んで入りきらないぶんを右の列へ送る」
 * 動きになり、一覧の横にデッキ一覧が並んで図鑑だけ下へ落ちる (実際になった)。
 */
.deck-cols { display: flex; gap: 12px; min-height: 0; flex: 1; }
/* 左(カード選び)を広めに。作業のほとんどはこちらで行う */
.deck-col { flex: 1; display: flex; flex-direction: column; gap: 8px; min-height: 0; }
.deck-col:first-child { flex: 1.5; min-width: 220px; }
/*
 * 図鑑の列。**カードそのものが情報の本体**なので、業界の構築画面と同じく
 * 「選んだカードは読める大きさで出す」を最優先にする (絵に HP・ワザ・弱点が
 * 刷ってあり、それが読めないなら図鑑の意味が無い)。
 */
.deck-col-detail { flex: 1.35; min-width: 240px; }

/* 図鑑。対戦中のカード詳細と同じ .pv-* を使うので、見た目は勝手にそろう
   高さは flex の配分だけで決まる (.deck-panel.wide 参照)。中身では動かない */
.deck-detail {
    flex: 1 1 0;
    min-height: 101px;
    overflow-y: auto;
    padding: 8px;
    border-radius: 10px;
    border: 1px solid var(--panel-border);
    background: rgba(255, 255, 255, 0.04);
}
/*
 * 絵は列の幅いっぱいまで大きく出す (373×521 の実寸に近づける)。
 * 150px 上限だったころは、カードに刷ってあるワザも HP も読めず
 * 「小さなサムネイルの下に同じ内容の文字」という二度手間になっていた。
 * 高さの上限だけは残す — 背の低い横画面で絵が枠を食いつぶすと、
 * ワザの説明が下へ押し出されて見えなくなる (スマホで実際にそうなった)。
 * 縦画面は下の @media が 112px の横並びに切り替える。
 */
.deck-detail .pv-img {
    width: 100%;
    max-width: 330px;
    max-height: calc(52dvh / var(--ui-scale));
    object-fit: contain;
    margin: 0 auto 6px;
    display: block;
    border-radius: 10px;
}
.deck-detail-nav { display: flex; gap: 6px; }
.deck-detail-nav button { flex: 1; padding: 9px 4px; font-size: 12px; }
.deck-detail-nav button:disabled { opacity: 0.35; cursor: default; }

/* 検索と並べ替え。カードが増えると、絵を目で探すのは無理になる */
.deck-tools { display: flex; gap: 6px; }
.deck-search, .deck-sort {
    padding: 7px 9px;
    border-radius: 9px;
    border: 1px solid var(--panel-border);
    background: rgba(255, 255, 255, 0.06);
    color: var(--text);
    font-family: inherit;
    /* font-size は共通の下限 (16px) に任せる (iOSの拡大よけ) */
}
/*
 * 検索欄は `placeholder` に `<img>` を入れられないので、**背景の絵**として出す。
 * (ここだけ `🔍` の絵文字が残っていた ―― 端末で形が変わるうえ、
 *  UIアイコンの配色を継げない)
 */
.deck-search {
    flex: 1; min-width: 0;
    background-image: url('../../assets/ui/icons/utility-search.svg');
    background-repeat: no-repeat;
    background-position: 9px center;
    background-size: 16px 16px;
    padding-left: 31px;
}
.deck-sort { flex: none; cursor: pointer; }

/* デッキの内訳。合計だけでは強い弱いが分からない */
.deck-stats { display: flex; flex-wrap: wrap; gap: 4px 8px; }
.deck-stat { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--text-dim); }
.deck-stat.zero { opacity: 0.4; }

/* いま足りないもの。保存を待たずにその場で出す */
.deck-warn {
    font-size: 11px;
    line-height: 1.5;
    color: #fca5a5;
    padding: 5px 8px;
    border-radius: 8px;
    background: rgba(248, 113, 113, 0.1);
}
.deck-warn.ok { color: #86efac; background: rgba(74, 222, 128, 0.1); }

/*
 * 強くするヒント。**門ではなく診断**なので deck-warn とは別の見た目にする。
 *
 * 色は中立の紫 (`#a78bfa`)。陣地の色 (シアン/マゼンタ) は「じぶん/あいて」の
 * 意味を持っていて使えず、赤は「まだ遊べない」・緑は「使えます」の色なので
 * どちらも使えない。金は「急がせたいもの」専用 (設計原則15)。
 * 行頭に絵文字は付けない ―― 左の線だけで、warn とは別のものだと分かる。
 * 動きも音も付けない (1枚足すたびに paint() が走るので、光ると耐えられない)。
 */
.deck-tips { display: flex; flex-direction: column; gap: 4px; }
.deck-tips-head {
    font-size: 10px;
    letter-spacing: .08em;
    color: var(--text-dim);
}
.deck-tip {
    font-size: 12px;      /* この画面でいちばん長い文になるので warn より1段上げる */
    line-height: 1.45;
    padding: 4px 8px;
    border-left: 2px solid #a78bfa;
    background: rgba(167, 139, 250, .08);
    border-radius: 0 6px 6px 0;
}
.deck-tip-why { color: var(--text-dim); font-size: 11px; margin-top: 2px; }

/*
 * 図鑑の拡大。カードは**画面の高さいっぱい**まで大きくする。
 * 小さな枠に収めても結局読めないので、鑑賞のときは枠のほうを譲る。
 * デッキ画面(52)より前に出す必要がある。
 */
.deck-zoom {
    position: fixed;
    inset: 0;
    z-index: 66;
    display: grid;
    place-items: center;
    gap: 10px;
    padding: 20px;
    background: rgba(4, 8, 18, 0.86);
    backdrop-filter: blur(6px);
    cursor: zoom-out;
    animation: deckZoomIn 0.16s ease-out;
}
@keyframes deckZoomIn { from { opacity: 0; } to { opacity: 1; } }
/*
 * **カードが主役。** 説明を横に置くと、そのぶんカードが小さくなる ――
 * 「大きくして見る」目的と正面からぶつかる。縦に積んで、幅はカードに使う。
 */
.deck-zoom-img {
    height: min(calc(72dvh / var(--ui-scale)), 700px);
    width: auto;
    max-width: 100%;
    object-fit: contain;
    border-radius: 12px;
    box-shadow: 0 18px 60px rgba(0, 0, 0, 0.7);
}
.deck-zoom-hint { font-size: 12px; color: var(--text-dim); }

/* 絵は押せる = 大きくなる、と分かるようにする */
.deck-detail .pv-img.zoomable { cursor: zoom-in; transition: transform 0.12s ease; }
.deck-detail .pv-img.zoomable:hover { transform: scale(1.04); }

/*
 * せまい画面。**もう横に何も置いていない**ので、絵に高さを全部あげてよい。
 * 以前は横に説明の板があり、そのぶん 56dvh まで縮めていた。
 */
@media (max-width: 860px), (orientation: portrait) {
    .deck-zoom-img { height: auto; max-height: calc(78dvh / var(--ui-scale)); }
}

/* いま図鑑に出している札が一覧のどれなのか、ひと目で分かるようにする */
.deck-card.selected { border-color: var(--you); box-shadow: 0 0 0 2px rgba(63, 216, 255, 0.35); }
.deck-chosen-row.selected { border-color: var(--you); }
.deck-col-title { font-size: 12px; color: var(--text-dim); font-weight: 700; }
.deck-col-title-icon { display: flex; align-items: center; gap: 6px; }
.deck-col-title-icon img { width: 17px; height: 17px; display: block; }
.deck-filters { display: flex; gap: 5px; }
.deck-filter {
    flex: 1;
    padding: 7px 2px;
    border-radius: 9px;
    border: 1px solid var(--panel-border);
    background: rgba(255, 255, 255, 0.04);
    color: var(--text-dim);
    font-family: inherit;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
}
.deck-filter.active { background: rgba(63, 216, 255, 0.22); border-color: var(--you); color: var(--text); }

/*
 * セルの大きさは固定にする。grid アイテムに aspect-ratio を直接かけると
 * 行の高さが実際のカード高さより小さく計算され、カードが行からはみ出して
 * 上下に重なってしまう (68px幅 → 95px高 が 62px の行に入ろうとする)。
 */
.deck-pool {
    display: grid;
    grid-template-columns: repeat(auto-fill, 68px);
    grid-auto-rows: 95px;
    justify-content: center;
    gap: 6px;
    overflow-y: auto;
    /* 高さは列の残り全部 (入れ物が固定なので、中身に関係なく一定になる) */
    flex: 1 1 0;
    min-height: 101px;
    padding: 2px;
}
.deck-card {
    position: relative;
    width: 68px;
    height: 95px;
    border-radius: 6px;
    overflow: hidden;
    border: 2px solid transparent;
    background: rgba(255, 255, 255, 0.06);
    padding: 0;
    cursor: pointer;
    transition: transform 0.12s ease, border-color 0.12s ease;
}
.deck-card:hover { transform: translateY(-2px); }
.deck-card.picked { border-color: var(--accent); }
.deck-card img { width: 100%; height: 100%; object-fit: cover; display: block; }
.deck-card.img-fallback::after {
    content: attr(data-label);
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    background: linear-gradient(180deg, #37474f, #263238);
    color: #eceff1;
    font-size: 9px;
    font-weight: 700;
    text-align: center;
    padding: 3px;
}
.deck-card-badge {
    position: absolute;
    right: 2px;
    bottom: 2px;
    background: rgba(0, 0, 0, 0.8);
    color: var(--accent);
    font-size: 11px;
    font-weight: 700;
    border-radius: 5px;
    padding: 1px 5px;
}

/*
 * たいかいで もらった札の印。
 *
 * **持っていない札の見た目は変えない。** 灰色に落とすのは「使えない」の意味で、
 * このゲームは全96枚が最初から使えるので嘘になる (設計原則24)。
 * 置き場所は空いている右上 ―― 左上はレアリティ、右下はデッキの枚数が使っている。
 * **数字は入れない**。9pxでは読めないうえ、右下の ×N (デッキ枚数) と紛れる。
 * 正確な枚数は中央の図鑑が言う。
 * 色はシアン = じぶんのもの (設計原則15)。マゼンタは相手の色なので使わない。
 */
#hud .deck-card.owned::after {
    content: '';
    position: absolute;
    right: 3px;
    top: 3px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--you);
    box-shadow: 0 0 4px rgba(63, 216, 255, .8);
}
/* 図鑑の1行。まだの札にも出す (叱らずに仕組みを教える) */
.deck-owned { font-size: 11px; color: var(--text-dim); margin-top: 6px; }
.deck-owned.has { color: var(--you); }

/* 高さは列の残り全部 (.deck-pool と同じ話。内訳 stats の行数が変わっても吸収する) */
.deck-chosen { display: flex; flex-direction: column; gap: 3px; overflow-y: auto; flex: 1 1 0; min-height: 0; }
.deck-chosen-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 10px;
    border-radius: 8px;
    border: none;
    background: rgba(255, 255, 255, 0.05);
    color: var(--text);
    font-family: inherit;
    font-size: 13px;
    cursor: pointer;
    text-align: left;
}
.deck-chosen-row:hover { background: rgba(248, 113, 113, 0.2); }
.deck-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.deck-chosen-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.deck-chosen-n { font-weight: 700; color: var(--accent); }

.deck-errors {
    display: none;
    font-size: 12px;
    color: #fecaca;
    background: rgba(190, 40, 50, 0.28);
    border-radius: 10px;
    padding: 9px 13px;
    white-space: pre-line;
    line-height: 1.6;
}
.deck-errors.show { display: block; }
.deck-nav { display: flex; gap: 8px; }
/* 折り返しと min-width は .hud-btn の既定に任せる (かつてここにあった
   white-space: normal の書き足しが、nowrap 時代の場当たり修正の名残だった) */
.deck-nav .hud-btn { flex: 1; }

/*
 * スマホの幅では、図鑑を「絵は左・文字は右」の横並びにする。
 * 縦に積むと絵だけで一画面ぶん使ってしまい、説明を読むのに
 * 毎回スクロールが要る = 詳細を見ながら選べない。
 */
@media (max-width: 720px) {
    .deck-detail { display: flex; align-items: flex-start; gap: 10px; }
    /* 92px では絵がただの色板だった。読める下限まで上げる (長押し拡大もある) */
    .deck-detail .pv-img { width: 118px; max-height: none; margin: 0; flex: none; }
    .deck-detail .pv-body { flex: 1; min-width: 0; }
}

/* せまい画面と縦画面では、デッキ編集の3列を上下に積む (一覧 → 図鑑 → デッキ)。
   各段の高さは列の flex 比 (1.5 / 1.35 / 1) がそのまま配分になる。
   入れ物 (.deck-panel.wide) が固定なので、ここに高さの決め打ちは要らない */
@media (max-width: 720px), (orientation: portrait) {
    .deck-cols { flex-direction: column; flex-wrap: nowrap; }
    /* 積んだときは幅の指定が効くと横に伸びないので外す */
    .deck-col:first-child, .deck-col-detail { min-width: 0; }
}
/* タブレット縦: 列は積むが図鑑は縦組みのまま。絵が箱 (30dvh) からあふれない高さに抑える */
@media (min-width: 721px) and (orientation: portrait) {
    .deck-detail .pv-img { max-height: calc(24dvh / var(--ui-scale)); }
}
/*
 * 背の低い横画面 (スマホ横 = 高さ390px級)。3列は保つが、一覧と図鑑の最低高を
 * 下げないと列が縮めず、はみ出したぶんが保存ボタンの上へ重なっていた
 * (縦積みの min-height と同じ落とし穴の横画面版)。
 */
@media (max-height: 520px) {
    .deck-detail { min-height: 90px; }
    .deck-detail .pv-img { max-height: calc(46dvh / var(--ui-scale)); }
}

/* ---------- screen effects (vignette / confetti) ---------- */
.hud-vignette {
    position: absolute;
    inset: 0;
    pointer-events: none;
    opacity: 0;
    z-index: 35;
    box-shadow: inset 0 0 130px 30px rgba(var(--vig-color, 255, 70, 70), 0.75);
}
.hud-vignette.flash { animation: vignette-flash 0.5s ease-out; }
@keyframes vignette-flash {
    0% { opacity: 0; }
    18% { opacity: 1; }
    100% { opacity: 0; }
}

.hud-confetti {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
    z-index: 44;
}
.confetti-piece {
    position: absolute;
    top: -20px;
    width: 9px;
    height: 14px;
    border-radius: 2px;
    animation: confetti-fall linear forwards;
}
@keyframes confetti-fall {
    0% { transform: translate(0, 0) rotate(0deg); opacity: 1; }
    100% { transform: translate(var(--drift, 0), 105vh) rotate(var(--spin, 360deg)); opacity: 0.9; }
}

/* ---------- card zoom (long press) ---------- */
.hud-zoom {
    position: absolute;
    inset: 0;
    /* grid だと画像と説明が別々の行に割り当てられ、行が画面いっぱいに
       引き伸ばされて両者が大きく離れてしまう。flex で寄せる。
       横に並べるのは、カードを大きく出しても説明が読めるようにするため
       (縦積みだと どちらかが必ず小さくなり、右上のカード詳細と差がつかない) */
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 26px;
    /*
     * ぼかし (backdrop-filter) は使わない。詳細は閉じるまで残る層になったので、
     * 裏で回り続ける3D描画に**毎フレーム全画面ブラー**が乗り、モバイルで一番
     * 効く種類のコストになる。濃い下地だけで同じ読みやすさになる。
     */
    background: rgba(5, 8, 16, 0.85);
    z-index: 55;
    pointer-events: none;      /* 閉じているあいだ。開いたら下の :not(.hidden) が受ける */
    padding: 20px;
}
/* 開いているあいだは押して閉じられる (タップかESCか✕)。z:55 のままなので
   モーダル (z:65) が上に出ても塞がない — モーダルの上に出すのは .over-modal だけ */
#hud > .hud-zoom:not(.hidden) {
    pointer-events: auto;
    cursor: zoom-out;
}
/* 画像＋テキストで画面からはみ出さないよう、画像の高さに上限をつける
   (横向きスマホのように高さが足りない場面がある) */
/*
 * **拡大では絵が主役。** ここは長く 34vw で、右に同じ内容の字が 38vw 並び、
 * 「大きく見る」と言いながら**カードより説明のほうが場所を取っていた**。
 * カードゲームの作法では、拡大の主役はカードそのもの (ハースストーンは
 * テキスト欄そのものが無く、カードが本文)。字は添えものに戻す。
 */
.hud-zoom .pv-img {
    width: min(520px, calc(46vw / var(--ui-scale)));
    max-height: calc(88dvh / var(--ui-scale));
    object-fit: contain;
    border-radius: 12px;
    margin: 0;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.7);
}
.hud-zoom .pv-body {
    width: min(320px, calc(28vw / var(--ui-scale)));
    max-height: calc(88dvh / var(--ui-scale));
    overflow-y: auto;
    text-align: left;
    background: rgba(10, 16, 30, 0.9);
    border: 1px solid var(--panel-border);
    border-radius: 12px;
    padding: 20px 22px;
    font-size: 15px;
}
.hud-zoom .pv-name { font-size: 27px; margin-bottom: 8px; }
.hud-zoom .pv-hp { font-size: 15px; margin-bottom: 10px; }
.hud-zoom .pv-attack { padding: 11px 0; font-size: 16px; }
.hud-zoom .pv-meta { font-size: 13px; }
.hud-zoom .pv-text { display: block; font-size: 13.5px; }

/*
 * せまい画面では横に並べきれないので縦に積む。
 *
 * ⚠ **縦画面のときだけ。** 幅だけで決めていたので、スマホ横 (852x393) も
 * 縦積みになり、**高さ 42dvh = 165px でカードが潰れていた**
 * (`object-fit: contain` なので実際に描かれるのは 118px 幅 = 本文 4.1px)。
 * 横に広い画面は横に並べたほうがカードを大きく出せる ―― 393px の高さを
 * まるごと使えば 258px 幅 = 本文 9px になる。
 */
@media (max-width: 900px) and (orientation: portrait) {
    .hud-zoom { flex-direction: column; }
    .hud-zoom .pv-body { padding: 14px 16px; }
    .hud-zoom .pv-name { font-size: 21px; }
}

/*
 * ■ 縦画面の「大きく見せる」は、**大きくすること**が仕事
 *
 * 上の指定は幅で 52vw = スマホ縦 (393px) で 204px しか使っておらず、
 * 拡大なのに**盤面の札より少し大きい程度**にしかならなかった。
 * 高さは 42dvh (358px) 空けてあるのに、幅で頭打ちになって届いていない
 * ―― 縦画面は幅が足りない代わりに**高さが余っている**のだから、
 * 高さのほうを使い切る (原則28「大きさは画面の何割で決める」と同じ考え)。
 *
 * 説明は下に続くので、字は読める大きさのまま**入る量を減らす** ――
 * 全部を一度に見せる必要はなく、足りなければその場でスクロールできる。
 */
/*
 * ⚠ **寸法はこのブロックだけが持つ。** 上の 900px のブロックにも同じ選択子で
 * 幅と高さを書いていたが、詳細度が同点なので**後ろのこちらが必ず勝つ**。
 * 実測して決めた数値が一度も効かないまま残り、次に「スマホ縦だけ大きく」と
 * 上をいじっても画面は動かない ―― 検算と実体がずれて片方だけ古くなる形
 * (原則13/46/51 が繰り返し禁じているもの)。上は**並べかた**だけを持つ。
 */
@media (orientation: portrait) {
    .hud-zoom { gap: 10px; padding: 12px; }
    /* 画面に収める寸法は UIサイズで割る (`test:uiscale` の決まり) */
    .hud-zoom .pv-img { width: min(420px, calc(88vw / var(--ui-scale))); max-height: calc(60dvh / var(--ui-scale)); }
    .hud-zoom .pv-body { width: min(400px, calc(92vw / var(--ui-scale))); max-height: calc(28dvh / var(--ui-scale)); }
    /*
     * ✕ は画面の右上に浮いている。縦ではそこにスコア帯があり、
     * 下地ごしに重なって「パネルのボタン」に見えるので、少し内側へ寄せる。
     */
    .zoom-close {
        top: max(8px, calc(env(safe-area-inset-top) / var(--ui-scale)));
        right: max(8px, calc(env(safe-area-inset-right) / var(--ui-scale)));
    }
}

/* ---------- tutorial guide bubble ---------- */
/*
 * 案内は必ず画面上部の帯に出す。
 * 盤面のまん中や手札の上に置くと「タップしてほしいもの」を自分で隠してしまう。
 */
/*
 * ⚠ **`left: 50%` で中央に置かない。**
 * 絶対配置の箱の幅は「入る幅まで縮む」ので、`left: 50%` にすると
 * **入れ物の右半分しか使えない** ―― `max-width` で 340px を許していても、
 * スマホ縦 (393px) では実測 153px しか無かった。中身が2倍に折り返され、
 * そのぶん盤面を覆う。`transform` で見た目だけ中央へ戻しても、
 * 幅の計算はもう終わっている。
 * 両端を 0 にして `margin-inline: auto` で寄せると、入れ物の幅ぜんぶが
 * 候補になったうえで中央に来る (`::after` のしっぽは箱の中の話なので無関係)。
 */
.hud-guide {
    position: absolute;
    top: 92px;
    left: 0;
    right: 0;
    margin-inline: auto;
    width: fit-content;
    max-width: min(380px, calc(88vw / var(--ui-scale)));
    padding: 14px 20px 12px;
    border-radius: 16px;
    background: linear-gradient(160deg, rgba(13, 108, 150, 0.96), rgba(10, 40, 78, 0.96));
    border: 2px solid rgba(63, 216, 255, 0.7);
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
    z-index: 38;
    text-align: center;
    animation: guide-in 0.3s ease;
}
.hud-guide::after {          /* ふきだしのしっぽ */
    content: '';
    position: absolute;
    left: 50%;
    margin-left: -10px;
    border: 10px solid transparent;
}
/* しっぽは「下のほう(手札)を見て」という向きのときだけ出す */
/*
 * **しっぽは出さない。** ふきだしは画面の上端に固定で、手札は下端・
 * ボタンは右。どちらを向けても指す先には届かないので、下向きの三角は
 * 「何も無いところ」を指すだけだった。指す役目は下の `.guide-point` が持つ。
 */
.hud-guide::after { display: none; }

/*
 * **ガイドが指している先。** ふきだしを動かす代わりに、触ってほしい場所の
 * ほうを光らせる (盤面で置ける枠を光らせるのと同じ作法)。
 * 入れ物に枠を足すだけなので、縦横どちらの並びでも位置の取り合いが起きない。
 */
/*
 * **指す光は、画面に入っている範囲に描く。**
 *
 * ここは長く対象そのものへ `inset` の輪を掛けていた。ところが手札の入れ物は
 * **わざと画面の下へはみ出させてある** (`.hud-hand { bottom: calc(-1 * var(--hand-drop)) }`)
 * ので、輪の下辺が画面の外に落ちて**見切れていた** ―― しかも
 * 「はじめてのバトルで手札を見て」というときに指す先がそこなので、
 * いちばん出る場面でいちばん崩れていた。
 *
 * 輪は擬似要素に持たせ、はみ出しているぶんだけ内側へ寄せる。
 * **`position` は対象の側に持たせる。** `.guide-point` に書くと
 * `.hud-hand` の absolute を上書きして飛ぶので、ここには書かない
 * (`.hud-hand` はもともと absolute、`.hud-buttons` には relative を足してある)。
 */
.guide-point::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 12px;
    pointer-events: none;
    animation: guide-point 1.5s ease-in-out infinite;
}
/* 手札だけは、画面の外へ落としているぶん (--hand-drop) を差し引く */
.hud-hand.guide-point::before { bottom: var(--hand-drop); }
@keyframes guide-point {
    0%, 100% { box-shadow: inset 0 0 0 2px rgba(103, 232, 249, 0); }
    50%      { box-shadow: inset 0 0 0 2px rgba(103, 232, 249, 0.85); }
}
/* 動きを減らす設定では、点滅させずに出しっぱなしにする (指す役目は残す) */
@media (prefers-reduced-motion: reduce) {
    .guide-point::before {
        animation: none;
        box-shadow: inset 0 0 0 2px rgba(103, 232, 249, 0.7);
    }
}
/*
 * **誰が言っているか。** 吹き出しは長く無地で、文だけが天から降ってきていた。
 * 教材は「人が教えてくれる」形のほうが入る (物語の中に先生がいるのだから)。
 */
.guide-speaker {
    display: flex;
    align-items: center;
    gap: 9px;
    padding-bottom: 8px;
    margin-bottom: 8px;
    border-bottom: 1px solid rgba(150, 215, 255, 0.22);
    text-align: left;
}
.guide-face {
    width: 34px; height: 34px; flex: 0 0 34px;
    border-radius: 9px; object-fit: cover;
    border: 1px solid rgba(150, 215, 255, 0.45);
}
.guide-who { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.guide-name { font-size: 13px; font-weight: 700; }
.guide-title { font-size: 10.5px; color: var(--text-dim); }
/*
 * **`keep-all` と `<wbr>` は対。** 印だけ置いてもブラウザは日本語を
 * どこでも折ってよいと思っているので無視され、規則だけ掛けると
 * 折れる場所が1つも無くなる (日本語には空白が無い)。両方でようやく
 * 「text-wrap.js が許した所だけで折る」になる。
 */
.guide-text {
    font-size: 15px;
    font-weight: 700;
    line-height: 1.65;
    white-space: pre-line;
    word-break: keep-all;
}
.guide-skip {
    margin-top: 9px;
    background: transparent;
    border: none;
    color: rgba(168, 224, 255, 0.9);
    font-family: inherit;
    font-size: 11px;
    cursor: pointer;
    text-decoration: underline;
}
/* 中央寄せは `margin-inline: auto` の仕事になったので、動かすのは縦だけ */
@keyframes guide-in {
    from { opacity: 0; transform: translateY(-10px); }
    to { opacity: 1; transform: translateY(0); }
}

/* ---------- how to play (paged) ---------- */
.modal-box.pages { width: min(520px, calc(94vw / var(--ui-scale))); }

/*
 * 絵のあるページ (章の扉・出会い・ぬしの開示)。
 *
 * **絵は敷く。字は絵の下に並べず、下の帯に重ねる** (`.pages-panel`)。
 * 絵は 16:9 で「上の3分の1には情報を置かない」条件で描いてあるが、
 * **字を置くのは上ではなく下** ―― ノベルゲームの作法に合わせた
 * (経緯は `.hud-modal.story` の注)。空けてある上は、そのまま絵を見せる場所。
 *
 * 字が読めることを絵に頼らない: 帯そのものが暗い覆いを持つ。
 */
/*
 * **物語は全画面。** 絵は 1280x720 で描いてあるのに、長く
 * `min(660px, 94vw)` の箱で出していた ―― 実測で PC(1440x900) は
 * 658x369 = **画面の19%**、しかも原寸の半分に縮んでいて、背後には
 * 盤面が透けたままだった。スマホ横では箱が 658x201 になり、16:9 の絵の
 * 上下を大きく切って**比 3.27**で見せていた。
 * 「背景」として描かれた絵を、モーダルの中の小さな板として出さない。
 *
 * ⚠ **vw/vh ではなく % で伸ばす。** ここは `#hud` の `zoom` の中なので
 * vw/vh には倍率が掛かる (原則51)。親 (`.hud-modal`) が `inset: 0` なので、
 * % なら打ち消しが要らない ―― `/ var(--ui-scale)` を書き忘れる余地を作らない。
 */
.hud-modal.story {
    /* 覆いもぼかしも要らない (絵が画面を埋めるので、透ける先が無い) */
    background: #05080f;
    backdrop-filter: none;
    place-items: stretch;
}
.hud-modal.story .modal-box.pages.art {
    /*
     * **中身を下へ寄せる。** 帯 (`pages-panel`) を下端に置くのは、
     * `margin-top: auto` を誰かに付けて回るのではなく**並べかたで**決める ――
     * 肖像のあるページだけ押し下がって、扉のページでは字が画面の上8%に
     * 貼りついたままになっていた (`.pages-meet` が `display:none` なので、
     * そこに付けた auto が効かない)。
     */
    justify-content: flex-end;
    width: 100%;
    height: 100%;
    max-height: none;
    border: 0;
    border-radius: 0;
    /* 下は「すすむ」が画面のふちに貼りつかないぶん。切り欠きも避ける
       (env() もズームの中では倍率が掛かるので打ち消す・原則51) */
    padding: 20px 20px max(20px, calc(env(safe-area-inset-bottom) / var(--ui-scale)), var(--safe-y));
}
/*
 * **字は画面の下の帯にまとめる (ノベルゲームの ADV 形式)。**
 *
 * 調べたかぎり、ノベルゲームは例外なく字を画面の下に置く ―― 半透明の箱を
 * 敷いて、その上の絵は透かして見せる。上に置くと、絵のいちばん見せたい所と
 * 目線が競合する。全画面にした時点で、字だけが上に取り残されていた。
 *
 * 幅は読める長さで止める (全画面だと1行が1400px まで伸び、目が次の行の頭へ
 * 戻れなくなる)。帯そのものは全幅に敷き、**中身だけ**を絞る ――
 * 箱が画面の途中で切れると、字の下の絵だけ明るくて読めなくなる。
 */
.hud-modal.story .pages-panel {
    /* 帯そのものを読める幅で絞る。**中身を絞るのではない** ――
       全幅の帯の中で本文だけ中央に寄ると、帯の左右が大きく空いて据わりが悪い。
       ノベルゲームの標準は**下部フレーム型**で、枠は画面の幅いっぱい近くまで
       広げる (1000px だと広い画面で「浮いた小箱」に見え、実測で画面幅の60%
       しか無かった)。行が長くなりすぎないよう上限は残す */
    width: min(1240px, 100%);
    margin-inline: auto;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 14px 18px 4px;
    border-radius: 14px;
    /* 帯そのものを敷く。**覆いの傾き (`.pages-art::after`) だけでは足りない** ――
       絵の下側は草も机も細かいので、字がその上に直に乗ると読めない */
    background: linear-gradient(180deg, rgba(6, 10, 18, 0) 0%, rgba(6, 10, 18, 0.82) 14%, rgba(6, 10, 18, 0.92) 100%);
}
/* めくる道具とボタンは字より狭く (全幅に伸ばすと的が大きすぎる) */
.hud-modal.story .pages-panel > .pages-nav {
    width: min(420px, 100%);
    margin-left: auto;
    margin-right: auto;
}
/*
 * **字の大きさは画面の高さから決める** (原則28)。長く 14px 固定で、
 * PC でも 14px のままだった ―― Xbox のアクセシビリティ指針 (104) は
 * 既定の字を 1080p で 32px 以上と定めていて、900px 高に直すと約27px。
 * 実測で**半分以下**だったので、高さの 2.9% を基準にして上下を挟む。
 */
.hud-modal.story .pages-body {
    font-size: clamp(16px, 3.1dvh, 38px);
    line-height: 1.9;
    /*
     * **高さの上限はここ1か所。** 長く `.modal-box.pages.art .pages-body`
     * にも上限があり、そちらのほうが詳細度が高かったので (0,4,0 対 0,3,0)、
     * ここに書いた値は**一度も効いていなかった** ―― 直そうとした人が
     * この行を変えて「何も起きない」と悩む形になっていた。
     * 高さを画面の割合で決めるのは設計原則28 (px だと横向きスマホで潰れる)。
     */
    max-height: calc(34dvh / var(--ui-scale));
    text-align: left;
}
.hud-modal.story .modal-title {
    font-size: clamp(15px, 2.2dvh, 22px);
    /* 見出しは場面の名 ―― 台詞より前に出るが、主役は本文なので落ち着かせる */
    color: var(--text-dim);
    font-weight: 600;
    margin-bottom: 0;
    text-align: left;
}
/*
 * 名乗りの札。**本文とのあいだに線を引く** ―― ノベルゲームのメッセージ枠が
 * 名前とテキストを見た目で分ける定石で、これが無いと台詞の1行目に見える。
 */
.pages-plate {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 0 0 4px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.14);
}
.pages-plate-role { font-size: clamp(11px, 1.5dvh, 14px); color: var(--text-dim); }
.pages-plate-name {
    font-size: clamp(19px, 3.1dvh, 30px);
    font-weight: 700;
    color: var(--opp-color, #fff);
    text-shadow: 0 2px 12px rgba(0, 0, 0, 0.9);
}
/* 台詞は本文と同じ大きさ (小さくすると、いちばん読ませたい一言が沈む) */
.pages-said { margin-bottom: 0; }

/* 敷いた絵の基準。**幅と溢れはここで決めない** ―― 幅は下の
 * `.hud-modal.story` が 100% にし、溢れは `.modal-box` の既定が隠す */
.modal-box.pages.art { position: relative; }
.pages-art {
    position: absolute;
    inset: 0;
    background-size: cover;
    background-position: center;
    z-index: 0;
}
/*
 * 絵をわずかに沈めるだけの覆い。**字のためではない。**
 *
 * 長く「上は濃く (0.90)・下もまた濃く (0.78)」だった ―― 字が絵の上に
 * 直に乗っていたころの形。いまは字もボタンも帯 (`.pages-panel`) の中で、
 * 帯は自前の暗さを持っているので、**下を二重に暗くしていた**。上は
 * もっと悪く、**全画面にしてまで見せたかった絵の空**をいちばん濃く
 * 塗りつぶしていた (この変更が何のためだったのかを打ち消す形)。
 * 残すのは、明るい絵で名乗りのふちが飛ばない程度の一枚だけ。
 */
.pages-art::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg,
        rgba(6, 10, 18, 0.34) 0%,
        rgba(6, 10, 18, 0.10) 34%,
        rgba(6, 10, 18, 0.10) 62%,
        rgba(6, 10, 18, 0.30) 100%);
}
/* 絵の上に来るもの。敷いた絵より前に出す */
.modal-box.pages.art > *:not(.pages-art) { position: relative; z-index: 1; }
.modal-box.pages.art .pages-body {
    /* 高さの上限は上の `.hud-modal.story .pages-body` が持つ (1か所) */
    min-height: 0;
    text-shadow: 0 2px 6px rgba(0, 0, 0, 0.9);
}
.modal-box.pages.art .modal-title { text-shadow: 0 2px 8px rgba(0, 0, 0, 0.9); }

/*
 * 出会いの場面の人。**章の扉の絵は5枚とも風景で、人が1人も写っていない** ――
 * だから相手と初めて顔を合わせるのが 1.9秒で自動的に消える VS画面だけになり、
 * 「対戦画面でいきなり対面する」形になっていた (計画書の SM-06)。
 *
 * 大きさは**画面の割合で決める** (原則28)。px で置くと、いちばん引きの
 * 小さいスマホでいちばん小さく出る ―― 人と会う場面でそれは逆。
 * 上下の `auto` で、字とボタンのあいだの空きを人が受け取る。
 */
.pages-meet {
    display: flex;
    justify-content: center;
    /* 帯のすぐ上に立たせる (ノベルゲームの立ち絵と同じ置きかた)。
       下寄せは箱の `justify-content` が決めるので、ここに auto は書かない */
    margin-bottom: 10px;
    animation: versus-in 0.45s ease;
}
.pages-meet img {
    /* ふちと色は上の `.versus-opp img` と共有。ここは大きさだけ ――
       画面の割合で決める (原則28。px だといちばん狭い画面で最小になる) */
    width: auto;
    height: clamp(96px, calc(34dvh / var(--ui-scale)), 300px);
    aspect-ratio: 1;
    object-fit: cover;
    /* 立ち絵として置くので、卓上の影を1枚足す */
    box-shadow: 0 0 34px -6px var(--opp-color, #fff), 0 10px 30px rgba(0, 0, 0, 0.6);
}
/*
 * **背の低い画面 (横向きスマホは高さ390px) では、帯と人が高さを取り合う。**
 * 字を削るのではなく、人を小さくして帯を詰める ―― 削ると、いちばん狭い
 * 画面の人だけが物語を読めなくなる。`.ui-short` は高さ480px以下。
 * **媒体クエリを使わないこと** ―― ズームの中では実寸の境目が動く (原則51)。
 */
.ui-short .pages-meet { margin-bottom: 4px; }
.ui-short .pages-meet img { height: clamp(84px, calc(30dvh / var(--ui-scale)), 150px); }
.ui-short .hud-modal.story .modal-box.pages.art { padding: 8px 12px; gap: 2px; }
.ui-short .hud-modal.story .pages-panel { padding: 8px 14px 2px; gap: 2px; }
.ui-short .hud-modal.story .pages-body { max-height: calc(30dvh / var(--ui-scale)); line-height: 1.7; }

.pages-body {
    /*
     * 下限は「ページを送っても箱の高さが跳ねない」ため。**背の低い画面では
     * それ自体が溢れの原因**になるので `min()` で抑える (`.settings-body` と同じ話)。
     */
    min-height: min(230px, calc(20dvh / var(--ui-scale)));
    max-height: calc(54dvh / var(--ui-scale));
    overflow-y: auto;
    font-size: 14px;
    line-height: 1.85;
    padding: 4px 2px;
}
.pages-body p { margin-bottom: 10px; }
.pages-body ul { margin: 0 0 10px 20px; }
.pages-body li { margin-bottom: 3px; }
.pages-body b { color: var(--accent); }
.pages-dots { display: flex; justify-content: center; gap: 6px; }
.page-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.22);
}
.page-dot.on { background: var(--accent); }
.pages-nav { display: flex; gap: 8px; }
.pages-nav .hud-btn { flex: 1; }
.start-diff-btn.tutorial {
    background: linear-gradient(160deg, rgba(74, 222, 128, 0.4), rgba(21, 128, 61, 0.4));
    border-color: #4ade80;
}
.start-diff-btn.tutorial:hover { background: linear-gradient(160deg, rgba(74, 222, 128, 0.55), rgba(21, 128, 61, 0.5)); }

/* ---------- responsive / safe area ---------- */



.hud-logwrap { left: max(14px, calc(env(safe-area-inset-left) / var(--ui-scale)), var(--safe-x)); }



@media (max-width: 720px) {
    
    
    
           /* サイドは数字だけにして幅を詰める */
       /* せまい画面では長押しの拡大表示を使う */
    .hud-banner { font-size: 22px; padding: 10px 30px; }
    
}
@media (max-width: 1000px) {
    /* 対戦中の右側は幅が無いので、ワザの説明は長押しの拡大に任せる */
    .pv-text { display: none; }
    /* ただしデッキ編集の図鑑では必ず出す。読むために置いている場所なので */
    .deck-detail .pv-text { display: block; }
}

/* ---------- review-driven polish ---------- */
/* 出せるカードは緑にやさしく光る (Hearthstoneパターン) */
.hand-card.playable {
    box-shadow: 0 0 0 2px rgba(74, 222, 128, 0.65), 0 0 16px 4px rgba(74, 222, 128, 0.35);
    animation: playable-pulse 1.6s ease-in-out infinite;
}
.hand-card.playable.hover { animation: none; }
@keyframes playable-pulse {
    0%, 100% { box-shadow: 0 0 0 2px rgba(74, 222, 128, 0.65), 0 0 14px 3px rgba(74, 222, 128, 0.3); }
    50% { box-shadow: 0 0 0 2px rgba(74, 222, 128, 0.9), 0 0 22px 7px rgba(74, 222, 128, 0.5); }
}

/*
 * 押せないが、押すと理由をトーストするボタン (ツールチップはタッチに届かない)。
 *
 * **不透明度でまとめて薄くしないこと。** 以前は `opacity: 0.45` だけで、
 *  ① 面まで薄くなるので、明るい primary と重なると「押せないのに いちばん目立つ」
 *  ② いちばん読ませたい**押せない理由**まで一緒に薄くなる (実測 1.24:1)
 * の2つが同時に起きていた。面は暗く落とし、理由は落とさない。
 */
.hud-btn.looks-disabled {
    background: rgba(20, 28, 48, 0.55);
    border-color: rgba(120, 190, 255, 0.16);
    color: var(--text-dim);
}
.hud-btn.looks-disabled:hover:not(:disabled) {
    transform: none;
    background: rgba(20, 28, 48, 0.55);
    border-color: rgba(120, 190, 255, 0.16);
}
.hud-btn.looks-disabled .btn-badge { color: var(--text-dim); }
/*
 * 明るい面 (primary) の上では、うすい字の色は使えない。
 * `--text-dim` のままシアンのグラデに乗ると 1.41:1 で読めなかった。
 * 面が明るいので、字は面と同じ暗い色にする (5.2:1)。
 */
.hud-btn.primary .btn-sub { color: #03121c; opacity: 0.78; }
.hud-btn.primary .btn-badge { color: #03121c; }
/* キーの合図は字の色に従わせる (白のふちは明るい面の上で沈む) */
.btn-key { border-color: currentColor; }

/* 案内トースト (青) はエラー (赤) と区別する */
.toast.info { background: rgba(11, 143, 196, 0.94); }

/* 自分のターンのあいだ画面端に金の縁取り */
body.my-turn::after {
    content: '';
    position: fixed;
    inset: 0;
    border: 3px solid rgba(63, 216, 255, 0.42);
    pointer-events: none;
    z-index: 9;
}

/* タッチターゲットを48px基準に */
.hud-btn { min-height: 46px; }



/* OSの「視差効果を減らす」設定を尊重する (3D側は settings.allowShake が担当) */
@media (prefers-reduced-motion: reduce) {
    .hand-card.playable { animation: none; }
    .hud-banner { animation: none; }
    .confetti-piece { animation-duration: 3s !important; }
    #boot-loader .spin { animation-duration: 2s; }
}

/* 起動ローダー */
#boot-loader {
    position: fixed;
    inset: 0;
    display: grid;
    place-items: center;
    background: #050a12;
    color: var(--text-dim);
    z-index: 100;
    font-size: 15px;
    flex-direction: column;
}
#boot-loader .spin {
    width: 44px;
    height: 44px;
    margin: 0 auto 14px;
    border: 4px solid rgba(255, 255, 255, 0.15);
    border-top-color: #3fd8ff;
    border-radius: 50%;
    animation: boot-spin 0.9s linear infinite;
}
@keyframes boot-spin { to { transform: rotate(360deg); } }


/* ============================================================
   画面レイアウト: 左=情報列 / 中央=盤面 / 右=カード詳細と行動
   絶対配置どうしが重ならないよう、左右は flex の列で組む。
   (以前は 相手パネル・セリフ・カード詳細 が同じ座標に出ていた)
   ============================================================ */
.hud-sidebar {
    position: absolute;
    top: max(12px, calc(env(safe-area-inset-top) / var(--ui-scale)), var(--safe-y));
    /* 案内帯のぶん押し上げる (帯が画面のいちばん下・左端に居る) */
    bottom: calc(max(12px, calc(env(safe-area-inset-bottom) / var(--ui-scale)), var(--safe-y))
        + var(--pad-bar-h));
    left: max(12px, calc(env(safe-area-inset-left) / var(--ui-scale)), var(--safe-x));
    width: var(--rail-w);
    display: flex;
    flex-direction: column;
    gap: 8px;
    z-index: 22;
}
.hud-rightbar {
    position: absolute;
    top: max(12px, calc(env(safe-area-inset-top) / var(--ui-scale)), var(--safe-y));
    bottom: max(12px, calc(env(safe-area-inset-bottom) / var(--ui-scale)), var(--safe-y));
    right: max(12px, calc(env(safe-area-inset-right) / var(--ui-scale)), var(--safe-x));
    width: 236px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    z-index: 22;
}
.hud-spacer { flex: 1; min-height: 0; }

/* ---------- 対戦者パネル (あいて / じぶん) ---------- */
.hud-player {
    padding: 9px 12px;
    border-radius: 10px;
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-left: 4px solid var(--pl-color, var(--panel-border));
    backdrop-filter: blur(6px);
    transition: box-shadow 0.2s ease, border-color 0.2s ease;
}
/* ターンの側だけを光らせる。「あなたのターン」という文字を出さずに済む */
.hud-player.active {
    border-color: var(--pl-color, var(--accent));
    /* 上辺の細い光は残したまま、ターンの側だけ外へ光らせる */
    box-shadow: inset 0 1px 0 rgba(150, 215, 255, 0.18), 0 0 22px -4px var(--pl-color, var(--accent));
}
.hud-player.bump { animation: pl-bump 0.4s ease; }
@keyframes pl-bump {
    0% { transform: scale(1); }
    35% { transform: scale(1.045); }
    100% { transform: scale(1); }
}
.pl-head { display: flex; align-items: center; gap: 9px; }
.pl-face { width: 42px; height: 42px; border-radius: 10px; display: block; flex-shrink: 0; }
/*
 * 肖像のかわりに絵文字を出す欄 (じぶん / オンラインのあいて)。
 * ふちをパネルの色にしておくと、顔だけ見てもどちらの席か分かる。
 */
.pl-face.icon {
    display: grid;
    place-items: center;
    font-size: 22px;
    /* 記号は文字なので**陣地の色をそのまま継げる** (絵文字だと色が変えられない) */
    color: var(--pl-color, var(--text));
    background: rgba(255, 255, 255, 0.08);
    box-shadow: inset 0 0 0 1.5px var(--pl-color, var(--panel-border));
    text-shadow: 0 0 12px var(--pl-color, transparent);
}
.pl-id { min-width: 0; }
/*
 * 名札の行。**名前が行を独り占めし、役割の札は下へ回る。**
 *
 * 1行に同居させると、役割の札 (44px) のぶん名前が 136 → 64px まで削られ、
 * いちばん長い名札は4行になった。名前は誰かを指す唯一の字なので、
 * 幅の取り合いでは必ず名前を勝たせる。
 */
.pl-nameline { display: flex; flex-wrap: wrap; align-items: center; gap: 3px 6px; min-width: 0; }
/*
 * 名札。**切らずに折り返す。**
 *
 * ここは `nowrap` + `…` だったので、配られた名前 (「ゆうやけの カマキリ」= 138px)
 * が **64px** に押しこまれ、「ゆうや…」としか出なかった ―― 切り落とされるのは
 * *いきもの*のほうで、そこが見分けのつく半分。名前の空間が
 * **1600通りから実質40通りへ潰れ**、同じ形容詞を引いた 2.5% の対戦では
 * 両者がまったく同じ名札になる (実際に「ゆうや…」「ゆうか…」が並んだ)。
 *
 * 押しこんでいたのは、同じ行の役割の札を `flex: 0 0 auto` で
 * 「縮ませない」としていたから ―― **守る順番が逆**。名前は誰かを指す唯一の字で、
 * 役割は添えもの。行が2行になるぶんパネルは伸びるが、そこは空いている。
 * 割るのは語の切れ目だけ (`keep-all`)。名前は「ようす + いきもの」の2語なので、
 * ちょうど意味の切れ目で折れる。
 */
.pl-name {
    font-size: 15px;
    font-weight: 700;
    color: var(--pl-color, var(--text));
    flex: 1 1 100%;
    min-width: 0;
    word-break: keep-all;
    overflow-wrap: anywhere;
}
/* オンラインの役割札 (ホスト/ゲスト)。名前が長くても消えないように縮ませない */
.pl-role {
    flex: 0 0 auto;
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: 0.06em;
    padding: 2px 7px;
    border-radius: 999px;
    color: var(--pl-color, var(--text));
    background: rgba(255, 255, 255, 0.08);
    box-shadow: inset 0 0 0 1px var(--pl-color, var(--panel-border));
}
.pl-note { font-size: 10px; color: var(--accent); }
.pl-stats { margin-top: 7px; display: flex; flex-direction: column; gap: 3px; }
.pl-prize { display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--text-dim); }
.pl-prize b { font-family: var(--font-num); color: var(--text); font-size: 15px; }
.pl-prize.near, .pl-prize.near b { color: var(--warn); }
.pl-dots { font-style: normal; letter-spacing: 0.1em; font-size: 11px; }
.pl-counts { font-size: 11px; color: var(--text-dim); }
.pl-counts b { color: var(--text); font-weight: 700; }

/* ---------- 相手のひとこと (列の中に流れるので重ならない) ---------- */
.hud-say {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 9px 13px;
    border-radius: 12px;
    background: rgba(15, 23, 42, 0.95);
    border: 1px solid var(--panel-border);
    font-size: 12.5px;
    font-weight: 700;
    line-height: 1.6;
}
.say-icon { width: 22px; height: 22px; flex: 0 0 22px; display: block; }
.hud-say.pop { animation: say-pop 0.28s ease; }
@keyframes say-pop {
    from { opacity: 0; transform: translateY(-6px); }
    to { opacity: 1; transform: translateY(0); }
}

/* ---------- 道具ボタン (左列の下) ---------- */
.hud-tools { display: flex; gap: 6px; }
.tool-btn {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    padding: 9px 6px;
    min-height: 44px;
    border-radius: 11px;
    border: 1px solid var(--panel-border);
    background: var(--panel-bg);
    color: var(--text);
    font-family: inherit;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
    backdrop-filter: blur(6px);
    transition: all 0.13s ease;
}
.tool-btn:hover { border-color: var(--you); transform: translateY(-1px); }
.tool-icon { font-size: 15px; }
.tool-icon-img { width: 1.3em; height: 1.3em; display: block; }

/* ---------- 行動ボタン (右列の下) ---------- */
/* `position` はガイドの光の受け皿 (`.guide-point::before` が inset:0 で重なる) */
.hud-buttons { display: flex; flex-direction: column; gap: 8px; position: relative; }
/* 1行目は折り返さない (折り返すとボタンの高さが状態ごとに揺れる)。
   収まらない異常時は … で箱の中に切る。文章は .btn-sub の役目 */
.btn-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; white-space: nowrap; }
/*
 * `iconLabel()` が絵を入れた入れ物の、**既定の並べかた**。
 *
 * `iconLabel` は長く「絵と字の要素を作る」だけで、並べかたは親まかせだった。
 * 親が flex の列になっている所 (`.online-title` / `.pl-note` / `.hud-say`) は
 * 意図どおりだが、**素の `.hud-btn` は flex ではない**ので、`display: block` の
 * `<img>` が自分の行を取り、字はその下に残る ―― 物語の「次へ」で
 * **矢印だけがボタンの左上に浮いていた**のがこれ。
 *
 * **`:where()` で詳細度ゼロにしてある** (CLAUDE.md「網の規則は :where()」)。
 * これは「何も言われていない所の既定」であって、自前で並べたい親
 * (`.online-title` の 0,1,0 など) には必ず負ける。
 *
 * `inline-flex` ではなく `flex` にしてあるのは、**書いた値と計算値をそろえる**ため
 * ―― 呼び先の多くは flex の子なので `inline-flex` は `flex` にブロック化され、
 * `tests/css-audit.spec.js` が「書いたのに負けている」と読んでしまう。
 * 効きめは同じで、監査が嘘の指摘を出さなくなるぶんこちらがよい。
 */
:where(.has-icon) {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}
/*
 * ボタンの絵の大きさは、**となりの字から決める** (px で固定しない)。
 *
 * ここは長く 22px 固定で、ボタンの字が 14px でも 17px (`.big`) でも同じだった。
 * 大きいボタンほど絵だけが取り残されて小さく見える ―― 「アイコンが小さすぎる
 * ときがある」の正体。1.55em にすると 14px の字で 21.7px = いままでと同じ、
 * 17px の字では 26.4px と、字といっしょに育つ。
 */
.btn-icon { width: 1.55em; height: 1.55em; flex: 0 0 1.55em; display: block; }
.btn-label { flex: 1; text-align: left; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.btn-badge { font-family: var(--font-num); font-size: 21px; font-weight: 700; color: var(--accent); line-height: 1; }
.btn-sub {
    display: block;
    margin-top: 3px;
    font-size: 10.5px;
    font-weight: 400;
    color: var(--text-dim);
    text-align: left;
    line-height: 1.4;
}
.hud-btn.looks-disabled .btn-sub { color: #fca5a5; }

/* ---------- カード詳細 (右列の上) ---------- */
.hud-preview {
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: var(--radius);
    padding: 11px;
    backdrop-filter: blur(6px);
    max-height: calc(68dvh / var(--ui-scale));
    overflow-y: auto;
}
.pv-img { width: 100%; border-radius: 9px; display: block; }

@media (max-width: 900px) {
    /* 狭い画面では列を細く。**変数を動かす** (読む側は3か所とも追随する) */
    :root { --rail-w: 170px; }
    .hud-rightbar { width: 194px; }
    .pl-face { width: 34px; height: 34px; }
    .tool-label { display: none; }
}

/* ============================================================
   縦持ち (スマホ・タブレットの縦画面)
   ============================================================
   左右に列を置く余地がないので、3列を「上下の帯」に組み替える。

     上 = スコア帯 (あいて | ターン | じぶん)
     中 = 盤面
     下 = 手札と、その上のカード詳細・行動ボタン

   盤面は縦画面では画面の3〜4割にしかならない (正方形の盤面を細い画面に
   入れるので、上下が必ず余る)。**その余りにUIを置く**のが要点で、
   こうすると帯が盤面を隠さない。余白の大きさは scene.js の fitCamera が
   決めているので、片方だけ動かすと重なる。

   DOMは横持ちと同じ。並べ替えは order と flex-wrap だけで行うので、
   横持ちのレイアウトには一切さわらない。
   ============================================================ */
@media (orientation: portrait) {
    /*
     * 手札は7枚が画面幅に収まる大きさに落とす。
     *
     * **上限を幅だけで決めないこと。** ここは長く `clamp(52px, 15.5vw, 92px)` で、
     * 92px の頭打ちが**縦長でも横に広い画面** (折りたたみの内画面 1129x1259 や
     * タブレット縦) にそのまま効いていた ―― 実測で手札が画面幅の **43%** しか
     * 使っておらず、7枚が団子になって何を持っているか読めない。
     * 上限を上げるだけだと札が高くなりすぎて盤面を食うので、
     * **高さの予算 (`dvh`) も一緒に見る** (原則28「大きさは画面の何割で決める」)。
     * `dvh` はズームの中では倍率ぶん大きく描かれるので割る (原則51)。
     *   スマホ縦 393x852 … min(61, 109) = 61px (これまでと同じ)
     *   タブレット縦 820x1180 … min(127, 151) = 127px
     *   折りたたみ内 1129x1259 … min(175, 161) → 150px (上限)
     */
    :root {
        --hand-w: clamp(52px, min(15.5vw, calc(12.8dvh / var(--ui-scale))), 150px);
        --hand-drop: calc(var(--hand-h) * 0.16);
    }

    /* ---- 上: スコア帯 ---- */
    .hud-sidebar {
        top: max(8px, calc(env(safe-area-inset-top) / var(--ui-scale)), var(--safe-y));
        left: max(8px, calc(env(safe-area-inset-left) / var(--ui-scale)), var(--safe-x));
        right: max(8px, calc(env(safe-area-inset-right) / var(--ui-scale)), var(--safe-x));
        bottom: auto;
        width: auto;
        flex-direction: row;
        flex-wrap: wrap;
        /*
         * あいて側にだけ回線の具合が出る (接続SVG + 「つながっています」)。
         * 幅が無いので2行に折り返し、片側だけ背が高い不ぞろいな帯になっていた。
         * 高さをそろえて受けとめる — 回線の状態は消したくない情報なので、
         * 文字を削るのではなく箱のほうを合わせる。
         */
        align-items: stretch;
        gap: 6px;
    }
    /* そろえたいのは左右のスコアだけ。2行目のセリフと道具は中身なりの高さでよい */
    .hud-sidebar > .hud-say, .hud-sidebar > .hud-tools { align-self: flex-start; }
    /*
     * 行分けは order で決める。知らない子が増えても**まず折り返し行へ落ちる**ように、
     * 既定値を 6 にしてから、1行目に置きたいものだけを名指しする。
     * 名指しした子だけを並べる書き方だと、新しい要素が既定の order:0 で
     * 1行目に割り込み、いちばん幅の無いスコア帯を潰す (原則8と同じ落とし穴)。
     */
    .hud-sidebar > * { order: 6; }
    .hud-sidebar > .hud-player {
        order: 1;
        flex: 1 1 0;
        min-width: 0;
        padding: 7px 9px;
        overflow: hidden;
    }
    /*
     * **まん中を空けない。道具 (LOG/MENU) をそこへ入れる。**
     *
     * ここは長く「まん中はターン表示のために空けておく」と 48px×2 を空け、
     * 道具は折り返して2行目の右端に置いていた。ところが**ターン表示は
     * そこへ来ない** ―― `.hud-topstack` は縦画面では帯の**下**に出す決まりで
     * (すぐ下の注。以前パネルの裏に隠れた事故がある)、空けた枠には
     * 何も入らないまま残っていた。しかも2行目は左の279pxが丸ごと空き、
     * 帯が 158px と、盤面のいちばん惜しい縦を食っていた。
     *
     * 3つを1行に並べると帯は 102px に落ちる (実測) ―― 空きが消え、
     * そのぶん盤面が広がる。放送のスコアボードでも真ん中は空白ではなく
     * 何かが載っている場所で、空けること自体が目的ではなかった。
     */
    .hud-sidebar > .hud-tools { order: 2; flex: 0 0 auto; }
    /* 折り返し用の仕切り。セリフ (order 6) を2行目へ落とすために残す */
    .hud-sidebar > .hud-spacer { order: 5; flex: 1 0 100%; height: 0; }
    .hud-sidebar > .hud-say { flex: 1 1 auto; min-width: 0; font-size: 12px; padding: 7px 11px; }
    .tool-btn { flex: 0 0 auto; min-width: 46px; padding: 8px 11px; }
    .pl-face { width: 30px; height: 30px; border-radius: 8px; }
    .pl-face.icon { font-size: 17px; }
    .pl-name { font-size: 13px; }
    .pl-stats { margin-top: 5px; }
    /*
     * 縦画面のスコア帯は1人ぶん 136px しかない。
     * 3つ並べると 150px になってはみ出すので、いちばん急がない
     * トラッシュだけ落とす (字を削るより、出す数を減らすほうが読める)。
     * 字間も標識ぶんは要らない。
     */
    .pl-counts { font-size: 9.5px; white-space: nowrap; letter-spacing: 0.04em; }
    .pl-counts .c-disc { display: none; }

    .hud-turnchip {
        top: max(14px, calc(calc(env(safe-area-inset-top) / var(--ui-scale)) + 6px));
        padding: 5px 9px;
        font-size: 11px;
        max-width: 96px;
        overflow: hidden;
        white-space: nowrap;
    }
    /*
     * 縦画面では詰めるだけ。**位置は書かない。**
     *
     * ここには `top` / `left` / `right` / `transform` が並んでいたが、
     * `.hud-clock` は `.hud-topstack` (flex) の子で `position` を持たないので、
     * **4つとも1ピクセルも効いていなかった** (効いていたのは padding だけ)。
     * すぐ下の `.hud-topstack` の注が、`.hud-prompt` でまったく同じ事故を
     * 記録している ―― 直したのはプロンプトだけで、同じ箱に入れた
     * こちらは死んだ指定のまま残っていた。位置は箱にだけ書くこと。
     */
    .hud-clock {
        padding: 3px 10px;
    }
    .hud-clock.hurry {
        animation: none;   /* 中央寄せを前提にした脈打ちは、右寄せでは使えない */
        box-shadow: 0 0 0 2px rgba(255, 196, 61, 0.35);
    }

    /* 帯の下端 (--band-top は hud.js が実測して書く) から順に並べる。
       セリフの有無で帯の高さが変わるので px の決め打ちでは必ずどこかで重なる。
       ■ 動かすのは**積み重ね箱 (.hud-topstack) のほう**。プロンプトと持ち時間は
       いまこの箱の中にいるので、子の top を書いても1pxも動かない ―― 実際、
       古い直下時代の .hud-prompt { top: ... } が死んだ指定のまま残り、
       箱が横画面用の top:10px のままスコア帯のうしろに挟まっていた
       (スマホ縦で「たねモンスターをバトル場へ」がパネルに隠れて読めなかった) */
    .hud-topstack { top: calc(var(--band-top) + 8px); }
    /*
     * ■ トーストは「やること」の真下へ (縦画面)
     *
     * 既定は手札の上から数えるが、縦ではそこが**盤面のまん中**になる ――
     * 「エネルギーは1ターンに1枚だけ」が自分のバトル場の札を覆っていた。
     * 断られた理由を読みたいのに、何が断られたのかが隠れる。
     *
     * 縦であいているのは、帯とマットのふちのあいだ (やることの真下) だけ。
     * しかも**そこは遊ぶ人がいま目を置いている場所**でもある (やることが出る所)。
     * 高さは `--stack-bottom` の実測 ―― やることは1行にも2行にもなる。
     */
    .hud-toasts {
        top: calc(var(--stack-bottom) + 8px);
        bottom: auto;
        max-width: calc(92vw / var(--ui-scale));
    }
    .toast { font-size: 12.5px; padding: 7px 13px; }
    .hud-prompt {
        font-size: 13px;
        padding: 6px 15px;
        max-width: calc(92vw / var(--ui-scale));
        white-space: normal;
        text-align: center;
    }
    .hud-guide { top: calc(var(--band-top) + 46px); max-width: min(340px, calc(90vw / var(--ui-scale))); }

    /* ---- 下: 手札の上にカード詳細と行動ボタン ---- */
    /* 持ち上げは控えめに (右下のボタンを覆いすぎない) */
    .hand-card.hover { transform: rotate(0deg) translateY(-30px) scale(1.18); }

    .hud-rightbar {
        top: auto;
        left: auto;
        right: max(8px, calc(env(safe-area-inset-right) / var(--ui-scale)), var(--safe-x));
        bottom: calc(var(--hand-top) + 8px);
        width: min(calc(54vw / var(--ui-scale)), 240px);
        justify-content: flex-end;
    }
    .hud-rightbar .hud-spacer { display: none; }
    /*
     * **あいさつの一覧は下へ開く。** 道具の並びは縦画面では**上の帯**に来るので、
     * 上へ開くと画面の外へ出る (横画面では左列の下にあるので上へ開くのが正しい)。
     */
    .hud-tools .emote-menu { top: calc(100% + 6px); bottom: auto; }
    /*
     * カード詳細は「絵を横に、文字を右に」の細長い形にする。
     * 縦持ちで盤面の下に取れる高さは200pxほどしかなく、そこは行動ボタンが使う。
     * 大きく見たいときは長押しの拡大表示(.hud-zoom)がある。
     */
    .hud-preview {
        display: flex;
        flex-direction: row;
        align-items: flex-start;
        gap: 8px;
        padding: 8px;
        max-height: calc(17dvh / var(--ui-scale));
        overflow: hidden;
    }
    .hud-preview .pv-img { width: 62px; flex: 0 0 auto; }
    .hud-preview .pv-body { flex: 1 1 auto; min-width: 0; max-height: 100%; overflow-y: auto; }
    .hud-preview .pv-name { font-size: 13px; margin: 0 0 2px; }
    .hud-preview .pv-hp { font-size: 11px; margin-bottom: 4px; }
    .hud-preview .pv-attack { padding: 4px 0; font-size: 12px; }
    .hud-preview .pv-dmg { font-size: 14px; }
    .hud-preview .pv-meta { font-size: 10px; margin-top: 3px; }
    .hud-buttons { gap: 6px; }
    .hud-rightbar .hud-btn { padding: 9px 12px; font-size: 13px; }

    /* トーストとログは、行動まとまり(高さは中身しだい)の上に出す */
    .hud-toasts { bottom: calc(var(--band-bottom) + 10px); }
    .hud-logwrap {
        left: max(8px, calc(env(safe-area-inset-left) / var(--ui-scale)), var(--safe-x));
        bottom: calc(var(--hand-top) + 8px);
        width: min(216px, calc(62vw / var(--ui-scale)));
        max-height: calc(34dvh / var(--ui-scale));
        z-index: 26;   /* 行動ボタンより前 (右下と高さが重なることがある) */
    }

    /* ---- タイトル・デッキ編集 ---- */
    .start-screen { padding-top: max(20px, calc(calc(env(safe-area-inset-top) / var(--ui-scale)) + 12px)); }
    .start-subtitle { font-size: 11px; letter-spacing: 0.16em; text-align: center; }
    .start-panel { min-width: 0; width: min(360px, calc(94vw / var(--ui-scale))); margin-top: 12px; padding: 16px 14px; }
}

/*
 * スマホの縦画面では、スコア帯の1人ぶんが 140px ほどしかない。
 * 役割の札まで並べると名前が数文字で切れてしまうので、札は落とす。
 * 役割は顔のアイコン (🏠 / 🚪) とパネルの色が引き続き伝える。
 * タブレットの縦画面は幅があるので札を残す。
 */
@media (orientation: portrait) and (max-width: 560px) {
    .pl-role { display: none; }
}

/* 幅がとても狭い縦画面では、スコア帯の枚数表示まで入りきらない */
@media (orientation: portrait) and (max-width: 380px) {
    .pl-counts { display: none; }
    .hud-player.opp { margin-right: 40px; }
    .hud-player.me { margin-left: 40px; }
}


/* ---------- オンライン対戦の接続画面 ---------- */
.modal-box.online { width: min(460px, calc(94vw / var(--ui-scale))); }
.online-title { display: flex; align-items: center; justify-content: center; gap: 9px; }
.online-title-icon { width: 28px; height: 28px; display: block; }
.online-body { font-size: 13px; line-height: 1.8; color: var(--text-dim); }
.online-body b { color: var(--text); }
.online-code {
    margin: 6px 0;
    padding: 14px;
    border-radius: 10px;
    background: rgba(63, 216, 255, 0.1);
    border: 1px solid rgba(63, 216, 255, 0.45);
    text-align: center;
}
.online-code-label { font-size: 11px; color: var(--text-dim); letter-spacing: 0.2em; }
.online-code-value {
    font-size: 44px;
    font-weight: 700;
    letter-spacing: 0.24em;
    color: var(--accent);
    font-family: var(--font-num);
    margin-top: 4px;
}
.online-note {
    min-height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    font-size: 12px;
    color: var(--text-dim);
    text-align: center;
}
.online-note-icon { width: 19px; height: 19px; flex: 0 0 19px; display: block; }

/*
 * 通信の健康しんだん (コードサーバー / 中継 / 経路)。
 *
 * **縦に積む。** 横に並べると3つとも文字が入りきらず、いちばん大事な
 * 「なぜ切れるのか」の後半 (「携帯回線どうしは切れることがあります」) が
 * 真っ先に落ちる。読み物ではなく点検表なので、行で並ぶほうが目も走る。
 * 色は状態の強さだけを言う ―― 陣地の2色 (シアン/マゼンタ) は席の意味なので使わない。
 */
/*
 * 通信の様子。**3行の表**で、名前の列をそろえて中身を右へ流す
 * (開発者ツール・OSのネットワーク状態・ゲームの接続情報と同じ形)。
 *
 * 列の幅は**中身から決めさせる** (`max-content`)。`7ch` のような決め打ちだと、
 * いちばん長い名前 (コードサーバー) が入りきらず、そこだけ列がずれる ――
 * 実際そうなった。軸を1本足した日に測り直す形にはしない。
 */
.online-diag {
    display: grid;
    grid-template-columns: auto max-content 1fr;
    align-items: center;
    gap: 5px 8px;
    padding: 8px 9px;
    border-radius: 10px;
    background: rgba(3, 12, 22, 0.55);
    border: 1px solid rgba(148, 163, 184, 0.16);
}
/* 色は必ず状態クラスが持つ (hud が good|warn|bad|idle のどれかを必ず付ける)。
   ここに基本色を書いても一度も効かず、「灰を直したいのにどちらを触るのか」だけが増える */
/* 3つの枠をそのまま親のグリッドへ流す (行の入れ物は色を運ぶだけ) */
.online-chip {
    display: contents;
    font-size: 11px;
    line-height: 1.45;
    text-align: left;
    /*
     * **語の途中で割らない** (`.pl-note` と同じ話・原則43)。ここは長く1行に
     * 収まっていたので折り返しの作法を持っていなかったが、状態の説明に
     * 困りごとを足した (「つながりません ・ コードで相手を見つけられません」)
     * ぶんスマホ縦で2行になる。既定のままだと日本語はどこでも折れるので、
     * 「コードで相手を見つけら / れません」と1文字だけ落ちる。
     * 区切りの ・ の前後に空白があるので、keep-all ならそこで折れる。
     */
    word-break: keep-all;
    overflow-wrap: anywhere;
}
.online-chip-icon { width: 17px; height: 17px; flex: 0 0 17px; display: block; }
/*
 * 名前の列。**そろえるための固定幅**で、3行の中身が同じ x から始まるようにする。
 * 状態を並べる画面の作法 (開発者ツール・OSのネットワーク状態と同じ形)。
 * `ch` にしてあるのは字の大きさが変わっても崩れないため。
 */
.online-chip-key { color: var(--text-dim); }
/* 中身。狭ければ折り返す (語の途中では割らない — 親が keep-all を持っている) */
.online-chip-val { min-width: 0; }
.online-chip.good { color: #86efac; }
.online-chip.warn { color: var(--warn); }
.online-chip.bad { color: #fca5a5; }
.online-chip.idle { color: #94a3b8; }

.modal-box.online .hud-btn .hud-btn, .emote-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}
.online-control-icon {
    width: 25px;
    height: 25px;
    flex: 0 0 25px;
    display: block;
    padding: 2px;
    border-radius: 6px;
    background: rgba(3, 18, 28, 0.18);
    box-sizing: border-box;
}
.online-paste {
    width: 100%;
    height: 96px;
    resize: vertical;
    border-radius: 10px;
    border: 1px solid var(--panel-border);
    background: rgba(255, 255, 255, 0.06);
    color: var(--text);
    font-family: monospace;
    /* font-size は共通の下限 (16px) に任せる (iOSの拡大よけ) */
    padding: 8px;
}
.start-diff-btn.online {
    background: linear-gradient(160deg, rgba(56, 189, 248, 0.3), rgba(2, 132, 199, 0.26));
    border-color: rgba(56, 189, 248, 0.7);
}
.start-diff-btn.online:hover { background: linear-gradient(160deg, rgba(56, 189, 248, 0.45), rgba(2, 132, 199, 0.36)); }

.online-code-input {
    width: 100%;
    padding: 14px;
    border-radius: 12px;
    border: 1px solid var(--panel-border);
    background: rgba(255, 255, 255, 0.07);
    color: var(--accent);
    font-family: var(--font-num);
    font-size: 30px;
    font-weight: 700;
    letter-spacing: 0.22em;
    text-align: center;
    text-transform: uppercase;
}


/* ---------- オンライン: なまえ・接続状態・あいさつ ---------- */
/* 見た目は既存の .hud-btn / .settings-row に乗せ、位置と幅だけをここで決める */
.settings-text {
    flex: 1;
    min-width: 0;
    padding: 7px 10px;
    border-radius: 9px;
    border: 1px solid var(--panel-border);
    background: rgba(255, 255, 255, 0.07);
    color: var(--text);
    /* font-size は共通の下限 (16px) に任せる (iOSの拡大よけ) */
    font-family: inherit;
}
/*
 * 注記は アイコン＋字。**字は語の途中で割らない。**
 * 日本語は既定でどこでも折り返すので、縦画面の狭いパネル (118px) では
 * 「相手のワ / ザ 80」と**カタカナ語の真ん中で割れて**いた (原則43 と同じ話)。
 * `keep-all` にすると空白でだけ折り返す = 「相手のワザ / 80」になる。
 */
.pl-note { display: flex; align-items: center; gap: 5px; word-break: keep-all; overflow-wrap: anywhere; }
.pl-note-icon { width: 14px; height: 14px; flex: 0 0 14px; display: block; }
.pl-note.warn { color: #fca5a5; }
.pl-note.wait { color: var(--accent); }

.emote-bar { position: relative; }
.emote-toggle { width: 100%; }
/*
 * 「道具」の並び (LOG / MENU) に入ったときは、その仲間と同じ形で並ぶ。
 * `.hud-tools` は横に並ぶ flex なので、幅の取り分もそろえる。
 */
.hud-tools .emote-bar { flex: 1; min-width: 0; }
.hud-tools .emote-toggle { min-height: 44px; padding: 9px 6px; font-size: 12px; }
.emote-menu {
    position: absolute;
    right: 0;
    bottom: calc(100% + 6px);
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 6px;
    border-radius: 12px;
    background: var(--panel);
    border: 1px solid var(--panel-border);
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
    z-index: 30;
}
.emote-menu.hidden { display: none; }
.emote-item { display: flex; align-items: center; justify-content: flex-start; gap: 8px; text-align: left; white-space: nowrap; }

/*
 * 送ったが、まだホストの返事が来ていない札 (オンラインのゲスト側)。
 * ホストが審判なので結果を先取りして消すことはできない。
 * **「送った」ことだけを見せる** — これが無いと、置いたのに札が残るので
 * 「ドロップに失敗した」と区別できず、もう一度つまみ直すことになる。
 */
.hand-card.sending {
    opacity: 0.45;
    filter: grayscale(0.5);
    pointer-events: none;          /* 二度押しを防ぐ */
}
.hand-card.sending::after {
    content: 'おくったよ…';
    position: absolute;
    inset: auto 0 6px;
    text-align: center;
    font-size: 10px;
    font-weight: 700;
    color: var(--accent);
    text-shadow: 0 1px 3px #000;
}

/* ============ いま指している場所 (コントローラー / キーボード) ============ */
/*
 * **カーソルが見えないと、コントローラーでは何も操作できない。**
 * ここは長いあいだ `:focus-visible` の指定が1件も無く (outline の指定は
 * `.hand-card.selected` の2件だけ)、キーボードで Tab を押しても
 * どこにいるのか分からない状態だった。
 *
 * **「選んでいる」(`.selected` = 金) と「指している」(ここ = 氷色) は別の意味。**
 * 同じ見た目にすると読み分けられない。3Dのカーソル (scene.js `setCursor`) は
 * 四隅のかぎ括弧で、こちらは縁取り —— **色だけでなく形でも分ける**
 * (色だけに意味を持たせないのはアクセシビリティの基本要件)。
 */
:root {
    --focus-ring: #dbeafe;
    --focus-glow: rgba(103, 232, 249, 0.85);
}

/*
 * 詳細度ゼロの網 (`:where()`) ではなく、**確実に勝たせたい**ので `#hud` を
 * 前置する (設計原則8)。カーソルが見えないのは操作不能と同じなので、
 * ここだけは他のどの指定にも負けてはいけない。
 */
#hud .gp-focus,
#hud button:focus-visible,
#hud input:focus-visible,
#hud select:focus-visible,
#hud textarea:focus-visible {
    /*
     * **枠は札の内側に描く。外へはみ出させない。**
     *
     * ここは長く `outline-offset: 2px` + `box-shadow: 0 0 0 6px` で、
     * 札の外へ 11px ぶん張り出していた。押しどころはたいてい入れ物の幅いっぱいに
     * 広がるので、張り出したぶんは**入れ物のふちで切られる** ―― とくに
     * 溢れを引き受ける箱 (`.modal-scroll`) は `overflow-y: auto` なので、
     * 仕様上よこも `visible` ではなくなり、枠の左右が切り落とされる。
     * 結果、指している札だけが**ふちからはみ出した歪な形**に見えていた。
     *
     * 入れ物ごとに余白を足して回る手はある (が、入れ物を1つ足すたびに漏れる)。
     * **外に場所を要求しない形にすれば、どの入れ物の中でも同じに見える** ――
     * テレビやコンソールの画面が焦点をインセットで描くのも同じ事情。
     * WCAG 2.2 の焦点の見えかた (2.4.11) は内側でも満たせる ――
     * 太さ (3px) と 3:1 の明暗差があればよく、外側である必要は無い。
     *
     * `border-radius` は**書かない**。`outline` は札そのものの角丸に沿うので、
     * ここで 8px と決めると角丸 12px の札の形が**指した瞬間に変わる**。
     */
    outline: 3px solid var(--focus-ring);
    outline-offset: -3px;
    box-shadow: inset 0 0 0 6px rgba(103, 232, 249, 0.22);
}

/* 手札は扇状に重なっているので、指している札は前へ出さないと縁が隠れる */
#hud .hand-card.gp-focus {
    transform: rotate(0deg) translateY(-44px) scale(1.32);
    z-index: 320;
    outline-offset: -1px;
    filter: drop-shadow(0 14px 22px rgba(0, 0, 0, 0.6));
}
/*
 * 「選んでいる」札を指しているときは、金の枠を殺さずに氷色を重ねる。
 * **手札だけは外へ光らせてよい** —— 手札は入れ物の外へ持ち上がる
 * (`translateY(-44px) scale(1.32)`) 層なので、切られる相手がいない。
 */
#hud .hand-card.selected.gp-focus {
    outline-color: var(--warn);
    box-shadow: 0 0 0 6px rgba(103, 232, 249, 0.45), 0 0 18px var(--focus-glow);
}

/*
 * ポインタで遊んでいる人に焦点の枠を見せない。**最後に触ったものが勝つ。**
 * `:focus-visible` はブラウザが「キーボードらしい操作か」を判定してくれるが、
 * パッドの操作は `el.focus()` を通るだけなのでブラウザからは区別がつかない。
 * だから入力源を自分で持って (`main.js setInputSource`)、ここで出し分ける。
 */
html[data-input="pointer"] #hud .gp-focus,
html[data-input="pointer"] #hud button:focus-visible,
html[data-input="pointer"] #hud input:focus-visible,
html[data-input="pointer"] #hud select:focus-visible,
html[data-input="pointer"] #hud textarea:focus-visible {
    outline: none;
    box-shadow: none;
}

/*
 * いちばん進める行動に添える押しかたの合図。
 *
 * **出すのは「押せるものがある画面」だけ** — タブレットに「Space」と書いても
 * 押すものが無い。キーボードのある画面か、コントローラーを触っている画面。
 *
 * 中身は**キーの字とパッドの絵の両方**が刷ってあり、ここで出し分ける。
 * JSで選んで刷ると、入力源を切り替えた瞬間だけ古い合図が残る
 * (ボタンは行動が変わったときしか作り直されないため)。
 */
/*
 * ボタンの右端の合図。**既定は出さない。中身があるときだけ出す。**
 *
 * ⚠ 印は「有ることの印」(`has-*`) にすること。「無いことの印」にすると
 * 「いったん出して打ち消す」形になり、勝敗が詳細度と並び順で決まる ――
 * そこが1つ崩れると**中身の無い空の枠**が戻る (実測 14×4px の枠線が
 * 「バトル場に出す」の右端に出ていた)。
 *
 *   has-kbd       … キーボードの字 (Space) がある = いちばん進める行動
 *   has-pad       … 固定席の物理ボタンがある → パッドでは常に出す
 *   has-pad-focus … 固定席が無い → **指しているあいだだけ**出す。
 *                   キーボードの Space は画面のどこからでも主行動を押すが、
 *                   パッドの決定は**カーソルが乗っているものしか押さない**ので、
 *                   常に出すと嘘になる。
 */
.btn-key { display: none; }
@media (hover: hover) and (pointer: fine) {
    .btn-key.has-kbd { display: inline-flex; }
}
html[data-input="gamepad"] .btn-key { display: none; }
html[data-input="gamepad"] .btn-key.has-pad,
html[data-input="gamepad"] .hud-btn.gp-focus .btn-key.has-pad-focus { display: inline-flex; }
.btn-key {
    align-items: center;
    margin-left: auto;
    padding: 1px 6px;
    border: 1px solid rgba(255, 255, 255, 0.45);
    border-radius: 4px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.04em;
    opacity: 0.75;
}
/* パッドを触っているあいだはキーの字を引っこめ、絵に替える (逆も同じ) */
html[data-input="gamepad"] .key-kbd { display: none; }
html:not([data-input="gamepad"]) .pad-glyph { display: none; }
.btn-key .pad-glyph { width: 15px; height: 15px; }

/* ============ 操作の案内帯 (コントローラー) ============ */
/*
 * **場所は画面の下に固定し、並び順は変えない** (数だけ変わる) ―― コンシューマー
 * の作法。位置が動くと目が毎回探し直すことになる。
 * **絵だけにしない。必ず字を添える** ―― 記号を知らない人と読み上げに届かない。
 *
 * 手札の上に置く。手札に重ねると、いちばん触るものが隠れる。
 * `#hud > .x` の形で書く (設計原則8) ―― `#hud > *` に詳細度で負けると、
 * 画面ぜんたいを覆う層になって操作を丸ごと遮る。
 */
/*
 * 操作の案内帯。**画面の下端・左寄せに固定する。**
 *
 * ⚠ **どの画面でも同じ場所・同じ並びにすること。数だけ変える。**
 * Xbox のガイドラインが「案内の数と中身は画面ごとに変わってよいが、
 * **位置と相対順は変えない**」と定めていて、位置が動くこと自体が違反になる
 * (WCAG 3.2.3 の「くり返し出る部品は毎回同じ相対順で」も同じ話)。
 *
 * ⚠ **手札の高さを基準にしないこと。** ここは長く `--hand-top` を基準に
 * していたが、あれは**実測ではなく定数式** (`clamp(82px, 9.5vw, 132px)` から
 * 計算する) なので、手札の無い画面にも効くうえ、画面幅と UIサイズで
 * 98〜168px のあいだを動く。実際タイトルでは入口のタイルに重なり、
 * モーダルでは箱の中に入りこんでいた。避けるのは盤面だけの例外にする
 * ―― 調べた範囲で「手札を避けて中途半端な高さへ浮かせる」タイトルは
 * 1つも無く、避けるときは**横へどける** (Master Duel は右下隅) か、
 * **帯を持たない** (Balatro) かのどちらかだった。
 *
 * 左寄せなのは Xbox の作法 (Sea of Thieves は全画面で左下固定) で、
 * この作品では右下に行動ボタンとカード詳細が既に居るため。
 * **中央揃えの前例は見つからなかった** ―― しかもスマホ横持ちでは
 * ホームインジケータが下端中央に来るので、いちばん当たる置きかたでもある。
 */
#hud > .pad-hints {
    /*
     * **13 = 手札(14) のすぐ奥。** 注が「ふだんは13」と言っているのに宣言が
     * 無く、DOMの並び任せで**たまたま**そうなっていた (数字だけが注の中に
     * 生きている状態)。指している手札の上に帯を被せないための位置なので、
     * 意図を数字で書いておく。
     */
    z-index: 13;
    display: none;
    position: absolute;
    left: max(10px, calc(env(safe-area-inset-left) / var(--ui-scale)), var(--safe-x));
    bottom: max(10px, calc(env(safe-area-inset-bottom) / var(--ui-scale)), var(--safe-y));
    gap: 14px;
    padding: 5px 14px;
    border-radius: 999px;
    background: rgba(6, 12, 22, 0.72);
    border: 1px solid var(--panel-border);
    pointer-events: none;      /* 見せるだけ。押す口ではない */
    /*
     * ⚠ **切らずに折り返すこと。** 前は `nowrap` + `overflow:hidden` で、
     * スマホの幅では**帯が自分の字を切り落としていた** (対戦中は6つ出るので
     * 390px の画面では最後の2つが消える)。この帯の役目は「絵だけにしない」
     * ことなので、切れるくらいなら2行になったほうがよい。
     */
    flex-wrap: wrap;
    row-gap: 4px;
    max-width: calc(80vw / var(--ui-scale));
}
html[data-input="gamepad"] #hud > .pad-hints { display: flex; }
/*
 * ⚠ **全画面の層が出ているあいだは、案内帯を前に出す。**
 * ふだんは 13 (手札より奥) だが、全画面の層 ―― タイトル(50)・デッキ画面(52)・
 * カード詳細(55)・モーダル(65)・図鑑の拡大(66) ―― はどれも画面ぜんたいを
 * ぼかすか暗幕を敷くので、そのままだと案内帯が**その下に沈んで読めない**。
 * いちばん読みたいときに、いちばん読めない。実際
 * 「ぼやけた所に何か映っている」と報告された。
 *
 * ⚠ **ぼかしの有無で数えないこと。** `backdrop-filter` を持たない層
 * (カード詳細) も 0.85 の暗幕で同じことになる。基準は
 * **「全画面の層が出ているか」= `focus.js` の `LAYERS`** で、
 * `activeLayer()` が書き出す `data-layer` を見る (盤面だけが `board`)。
 * 上げっぱなしにはしないこと ―― 13 なのは「指している手札の上に帯を
 * 被せない」ためで、そこを崩すと以前直した事故が戻る。
 */
#hud > .pad-hints { z-index: 71; }
/*
 * **盤面だけの例外。** ここだけは手札が画面の下端を専有するので持ち上げる。
 * 例外を1つに閉じこめておくこと ―― 画面ごとに `bottom` を書いて回ると、
 * 画面を1つ足した日に必ず漏れる (原則8)。
 */
/*
 * **盤面だけの例外は、ここに集める。**
 *
 * 位置は全画面で同じ (いちばん左下) だが、盤面では2つだけ違う:
 *   z-index … 指した手札 (`.hud-hand` の積み重ねの文脈) に譲る。帯は飾りで、
 *             札のほうが主役
 *   max-width … 手札は画面の下中央に扇で広がり、**指した札は
 *             `translateY(-44px) scale(1.32)` で持ち上がる**ので、帯が横に
 *             伸びると札の下に潜る。左右の列の幅に収まっていれば当たらない
 *             (実測 1440×900 で、指した札は x321 から始まる)
 *
 * ⚠ **縦に逃がして避けないこと。** 上へ空けると帯が画面の真ん中まで上がる
 * (「案内が上すぎる」に逆戻りする)。横へどけるのが業界の答え
 * (Master Duel は右下隅にまとめ、手札は下中央)。
 */
/*
 * 対戦画面では、帯の足もとに空いている幅 = 手札の左端まで。
 * `--rail-w` (上に積んであるものの幅) で頭打ちにしていたため、
 * PC横では 321px あいているのに 216px で折り返していた。
 * 入らないぶんは `_fitPadHints()` が後ろから落とす (必ず1行)。
 */
#hud[data-layer="board"] > .pad-hints {
    z-index: 13;
    max-width: calc(var(--hand-left, var(--rail-w)) - 16px);
}
.pad-hint {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    /*
     * ⚠ **12px を下回らないこと。** Steam Deck は 1280×800 で、Valve の
     * 対応要件が「画面上のいちばん小さい字は 9px を切らないこと・推奨12px」と
     * 実寸で決めている。ここは長く 11px で、**Deck の実寸でその下限を割っていた**
     * (`--ui-scale` が 1.0 のとき CSS の px がそのまま実寸になる)。
     */
    font-size: 12px;
    color: var(--text-dim);
}
/* 絵は倍率に追いつかせる (字だけ大きくすると絵が取り残される) */
.pad-hint .pad-glyph { width: 1.45em; height: 1.45em; color: var(--focus-ring); }
.pad-hint-label { letter-spacing: 0.02em; }

/**
 * 読み上げにだけ届かせる字。**`display:none` にしないこと** ―― 消すと
 * 読み上げにも届かない。位置だけ画面の外へ出す昔ながらの形にしてある。
 */
.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/*
 * パッドを使っているあいだは、マウスの矢印を消す。
 * 置きっぱなしの矢印が盤面に刺さっていると「そこを指している」と読めてしまい、
 * カーソル (`.gp-focus`) と**2つ目の指し手**になる。
 * ポインタを1px でも動かせば `data-input` が戻るので、見失うことはない。
 */
html[data-input="gamepad"] { cursor: none; }

/* 縦持ちでは行動のまとまりが下にあるので、その上へ逃がす */
@media (orientation: portrait) {
    #hud[data-layer="board"] > .pad-hints { bottom: calc(var(--band-bottom) + 8px); }
}

/*
 * モーダルの上に出すカード詳細 (ごほうびの札を押したとき)。
 * ふだんの拡大 (z-index 55) はモーダル(65)の下なので、そのままでは隠れる。
 *
 * **`#hud > .hud-zoom` の形で書くこと (設計原則8)。**
 * 上のほうに `#hud > .hud-zoom { pointer-events: none }` があり、
 * ID指定のぶん詳細度で勝つ。`.hud-zoom.over-modal` と書いていたため
 * 押しても閉じられず、**拡大したら戻れなくなっていた**。
 */
#hud > .hud-zoom.over-modal {
    z-index: 70;
    pointer-events: auto;      /* 押して閉じる */
    cursor: zoom-out;
}
/*
 * 押せば閉じるが、**閉じ方が見えていること**。字だけの案内では気づけない。
 * 見た目は `.hud-btn ghost` に乗せる (色・字・押した感じ・無効の見た目が
 * 他のボタンと同じになる)。ここでは置き場所と形だけを足す。
 */
.zoom-close {
    position: absolute;
    top: max(12px, calc(env(safe-area-inset-top) / var(--ui-scale)), var(--safe-y));
    right: max(12px, calc(env(safe-area-inset-right) / var(--ui-scale)), var(--safe-x));
    width: 44px;
    padding: 0;
    border-radius: 50%;
    font-size: 20px;
    line-height: 1;
}

/*
 * ■ ごほうびの見せ場
 * カードゲームのごほうびは、結果の内訳に混ぜず**専用の間**を取る。
 * 裏から表へめくることで「札が増えた」と分かる ― 絵を大きくするだけでは
 * 記録の1行に見えてしまう。
 */
.modal-box.reward {
    align-items: center;
    text-align: center;
    gap: 10px;
    background: radial-gradient(ellipse at 50% 34%, rgba(250, 204, 21, 0.20), rgba(10, 14, 24, 0.96) 62%);
    border-color: rgba(250, 204, 21, 0.5);
}
.reward-title {
    font-size: 20px;
    font-weight: 700;
    color: #facc15;
    text-shadow: 0 0 22px rgba(250, 204, 21, 0.5);
}
/* めくる箱。高さで決める ― 横幅で決めると縦画面で画面外へ出る */
.reward-flip {
    position: relative;
    height: min(calc(46dvh / var(--ui-scale)), 360px);
    aspect-ratio: 374 / 522;
    transform-style: preserve-3d;
    transform: rotateY(180deg) scale(0.86);
    transition: transform 0.62s cubic-bezier(0.2, 0.9, 0.3, 1.4);
    cursor: pointer;
    filter: drop-shadow(0 0 26px rgba(250, 204, 21, 0.45));
}
.reward-flip.revealed { transform: rotateY(0deg) scale(1); }
.reward-face {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
    border-radius: 10px;
    backface-visibility: hidden;
}
.reward-face.back { transform: rotateY(180deg); }
.reward-name { font-size: 19px; font-weight: 700; }
.reward-note { font-size: 12px; color: var(--text-dim); }
/* 集めた数。もらった瞬間に増えるのが見える (色はシアン = じぶんのもの) */
.reward-progress { font-size: 12px; color: var(--you); letter-spacing: .06em; margin-top: 2px; }
.reward-hint { font-size: 11px; color: var(--accent); opacity: 0.9; }
.reward-hint.used { visibility: hidden; }
/* 背の低い画面では札を縮める (ボタンが画面の外に出ないように) */
@media (max-height: 620px) {
    .reward-flip { height: min(calc(38dvh / var(--ui-scale)), 240px); }
    .reward-title { font-size: 16px; }
}
/* 結果画面のごほうびも押せる (あとからもう一度見たいとき) */

/*
 * 「このカードが実際にすること」の行。手書きの説明文 (.pv-text) と違い、
 * **エンジンの表から出てくる** ので、実装とずれることがない。
 * 色を分けてあるのは、刷ってある文と出どころが違うことを見せるため。
 */
.pv-effect {
    margin-top: 3px;
    font-size: 11.5px;
    line-height: 1.45;
    color: var(--accent);
}

/* 背の低い画面でも、カードはできるだけ大きく */
@media (max-height: 640px) {
    .deck-zoom-img { height: min(calc(70dvh / var(--ui-scale)), 420px); }
}
/* (ここに対応しない「}」が1つ残っていた。ブラウザは読み飛ばすが、
   この下に足した規則が「どのブロックの中か」を誤読させるので取り除いた) */

/* ---------- レアリティ (段) ---------- */
/*
 * 段の決めかたは card-view.js の rarityOf 1か所 (カードの版面と同じ式)。
 * 色は版面の虹の下地 (62e7ff / b67cff / ffd66c) から取り、絵と地続きにする。
 */
.pv-rarity {
    display: inline-block;
    font-family: var(--font-num);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.1em;
    padding: 1px 7px;
    border-radius: 8px;
    border: 1px solid currentColor;
    vertical-align: 1px;
}
.pv-rarity.r-c { color: #9fb0c2; }
.pv-rarity.r-u { color: #7dd3a7; }
.pv-rarity.r-r { color: #ffd66c; }
.pv-rarity.r-xr {
    color: #e9b6ff;
    background: linear-gradient(100deg, rgba(98, 231, 255, 0.16), rgba(182, 124, 255, 0.22), rgba(255, 214, 108, 0.16));
}
/* 図鑑タイルの段の札 (.pv-rarity の使い回し)。×n バッジは右下なので左上に置く。
   **#hud を付けて詳細度で勝つ** (原則8の作法) — 同点の後勝ちに頼ると、
   あとから末尾に足された .pv-rarity 系の調整で XR の虹下地が復活して読めなくなる。
   z-index は絵なし札の名前プレート (::after) より上に出すため */
#hud .deck-card .pv-rarity {
    position: absolute;
    left: 2px;
    top: 2px;
    z-index: 1;
    padding: 0 4px;
    font-size: 9px;
    border-radius: 5px;
    background: rgba(8, 12, 18, 0.78);
}

/* ごほうびの見せ場もレアリティで段をつける (当たりは光りかたが違う) */
.modal-box.reward.tier-r { border-color: rgba(98, 231, 255, 0.55); }
.modal-box.reward.tier-r .reward-flip { filter: drop-shadow(0 0 30px rgba(98, 231, 255, 0.55)); }
.modal-box.reward.tier-xr {
    border-color: rgba(182, 124, 255, 0.65);
    background: radial-gradient(ellipse at 50% 34%, rgba(182, 124, 255, 0.24), rgba(10, 14, 24, 0.96) 62%);
}
.modal-box.reward.tier-xr .reward-flip { animation: reward-shine 2.2s ease-in-out infinite; }
@keyframes reward-shine {
    0%, 100% { filter: drop-shadow(0 0 26px rgba(98, 231, 255, 0.55)); }
    50% { filter: drop-shadow(0 0 42px rgba(255, 214, 108, 0.6)); }
}
.reward-name .pv-rarity { font-size: 11px; vertical-align: 2px; }

/* ---------- 勝ち抜き戦の道のり (結果画面の顔ならび) ---------- */
.go-road {
    display: flex;
    justify-content: center;
    gap: 10px;
    margin: 2px 0 4px;
}
.go-road {
    flex-wrap: wrap;
    max-width: 100%;
}
.go-road-step {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    /*
     * **`min-width: 0` が要る。** flex の子は既定で「中身より小さくならない」ので、
     * `width: 52px` と書いても名前 (「こんちゅうはかせ」= 9pxで約72px) のぶんまで
     * 広がる。5人ぶん積もると箱より横に広くなり、結果画面が横スクロールする。
     * 名前は下の `text-overflow` で切る (顔と印のほうが情報として先)。
     */
    flex: 0 0 52px;
    min-width: 0;
}
.go-road-step img {
    width: 40px;
    height: 40px;
    border-radius: 9px;
    border: 2px solid var(--opp-color, #556);
}
.go-road-step.beaten img { filter: grayscale(0.8) brightness(0.75); }
/* まだ先の相手は顔を落とす (会っていない相手はそもそも顔を渡さない・`_gauntletSteps`) */
.go-road-step.later img { filter: brightness(0.22); border-color: rgba(255, 255, 255, 0.14); }
/*
 * 会っていない相手の枠。**顔は出さない** —— 暗くするだけだと薄ら映って、
 * 結果画面の道のりでぬしの正体が割れていた。場所は空けておく
 * (何人いるかは見えていてよい・タイトルのバッジと同じ作法)。
 */
.go-road-blank {
    width: 40px;
    height: 40px;
    border-radius: 9px;
    border: 1px dashed rgba(150, 215, 255, 0.22);
}
.go-road-step.next img { box-shadow: 0 0 14px -2px var(--opp-color, #fff); }
.go-road-mark {
    position: absolute;
    top: -4px;
    right: 0;
    font-size: 13px;
    font-weight: 700;
    color: #4ade80;
    text-shadow: 0 0 6px rgba(0, 0, 0, 0.9);
}
.go-road-name {
    font-size: 9px;
    color: var(--text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}
.go-road-step.next .go-road-name { color: var(--text); font-weight: 700; }

/* ---------- オンラインの役割バッジ (カード裏面のエンブレムと同じ六角) ---------- */
/* 文字グリフは端末の書体で太さが変わるので、SVGで線まで決める。
   色は currentColor で陣地の色を継ぐ (strings.js roleBadgeSVG) */
.pl-face.icon { display: grid; place-items: center; }
.pl-face.icon .role-badge {
    width: 68%;
    height: 68%;
    color: var(--pl-color, #eaf2ff);
    filter: drop-shadow(0 0 6px currentColor);
}
.versus-icon .role-badge {
    width: 58%;
    height: 58%;
    color: var(--opp-color, #fff);
    filter: drop-shadow(0 0 12px currentColor);
}

/* ---------- 回戦の名前 (VS画面のあたま) ---------- */
.versus-round {
    font-family: var(--font-num);
    font-size: 14px;
    font-weight: 700;
    letter-spacing: 0.3em;
    color: var(--accent);
}
/* 決勝だけ金。場の重さは色が言う (文言は「決勝」の2文字のまま) */
.versus-round.final {
    font-size: 18px;
    color: #facc15;
    text-shadow: 0 0 18px rgba(250, 204, 21, 0.65);
}

/* ===== デッキ選択: 戦い方 (型) と 中身の内訳 ===== */
/*
 * テーマの違いが色だけに見えると「どれを選んでも同じ」と思われる。
 * 型の名前と、モンスター/トレーナーズ/エネルギーの比を並べて、
 * **選ぶ前に中身の違いが分かる**ようにする。
 */
.choice-style { display: flex; align-items: center; gap: 8px; margin-top: 6px; flex-wrap: wrap; }
/* 既存の .atk-tag に乗せ、型ごとに変えるのは色だけ (同じ画面でピルの高さを揃える) */
.style-badge { background: none; border: 1px solid currentColor; }
.style-hint { margin: 0; }
.style-aggro    { color: #ff8a5c; }
.style-evolve   { color: #9be6a6; }   /* モンスターの帯 (#7ee787) と別の緑にする */
.style-endure   { color: #6fd3ff; }
.style-control  { color: #c78bff; }
.style-midrange { color: #e8c65c; }

.style-mix { display: flex; gap: 2px; margin-top: 5px; height: 14px; }
.mix-seg {
    display: flex; align-items: center; justify-content: center;
    font-size: 9px; font-weight: 700; color: #05121c;
    border-radius: 3px; min-width: 0; overflow: hidden;
    gap: 4px; padding: 0 4px;
}
.mix-mon { background: #7ee787; }
.mix-trainer { background: #c78bff; }
.mix-energy { background: #facc15; }   /* デッキ編集の内訳と同じ黄 */
.mix-name { font-weight: 500; opacity: .75; white-space: nowrap; }

/* ---------------- 大会 (4人) ---------------- */
/*
 * 盤は**全員が同じものを見る**ので、自分の卓だけが目で拾えればよい。
 * 色は陣地の2色を使わない ―― あれは「どちらの席か」の意味なので、
 * 大会の盤に持ちこむと盤面の色と食い違う (設計原則15)。
 */
/* 盤と順位は行が並ぶので、対戦の画面より少しだけ広い */
.modal-box.bracket, .modal-box.lobby { width: min(420px, calc(94vw / var(--ui-scale))); }
.bracket-round { margin-top: 10px; }
.bracket-round-name {
    font-size: 11px;
    letter-spacing: 0.12em;
    color: var(--text-dim);
    margin-bottom: 4px;
}
.bracket-table {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 8px;
    padding: 7px 10px;
    border-radius: 8px;
    background: rgba(3, 12, 22, 0.5);
    border: 1px solid rgba(148, 163, 184, 0.14);
    margin-bottom: 5px;
    font-size: 13px;
}
/* 自分の卓。**枠で示す** — 塗ると、勝敗の色 (下) と読み分けられない */
.bracket-table.mine { border-color: var(--accent); }
.bracket-table.done { opacity: 0.75; }
.bracket-name { text-align: center; color: var(--text-dim); }
.bracket-name.won { color: var(--text); font-weight: 700; }
.bracket-vs { font-size: 10px; color: var(--text-dim); letter-spacing: 0.1em; }

/*
 * 大会のロビー。**打つ欄は無い** —— 各自が自分の端末の名札を持って入ってくる
 * (理由は naming.js の冒頭)。1人目は「じぶん」なので、番号の欄は数字より広い。
 *
 * **空いている席も必ず出すこと。** 入った人だけを並べると、あと何人待てるのか・
 * 空席に CPU が入るのかが読み取れない (行が増えたり減ったりもする)。
 */
.lobby-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 10px;
    border-radius: 10px;
    border: 1px solid var(--panel-border);
    /* まだ来ていない席は沈める。入ったら浮く = 増えたことが動きで分かる */
    background: rgba(255, 255, 255, 0.02);
    color: var(--text-dim);
}
.lobby-row.in {
    background: rgba(63, 216, 255, 0.10);
    border-color: rgba(63, 216, 255, 0.35);
    color: var(--text);
}
.lobby-no {
    flex: 0 0 auto;
    min-width: 34px;
    text-align: center;
    font-size: 11px;
    color: var(--text-dim);
}
/* 名札がこの行の主役なので、残りの幅を全部取る */
.lobby-name {
    flex: 1;
    min-width: 0;
    font-weight: 700;
    /* 語の途中で割らない (原則43)。区切りの空白でだけ折れる */
    word-break: keep-all;
    overflow-wrap: anywhere;
}

/* 順位表。卓 (2人が向かい合う) とは別の形 —— こちらは1列に並ぶ */
.standing {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    border-radius: 8px;
    background: rgba(3, 12, 22, 0.5);
    border: 1px solid rgba(148, 163, 184, 0.14);
    margin-bottom: 5px;
}
.standing.mine { border-color: var(--accent); }
/* 優勝だけ金。ここは試合ぜんたいでいちばん重いできごと (設計原則38) */
.standing.top { border-color: var(--warn); }
.standing-rank {
    width: 26px;
    text-align: center;
    font-family: var(--font-num, inherit);
    font-size: 17px;
    font-weight: 700;
    color: var(--text-dim);
}
.standing.top .standing-rank { color: var(--warn); }
.standing-name { flex: 1; font-size: 14px; }
.standing-cpu {
    font-size: 10px;
    letter-spacing: 0.1em;
    color: var(--text-dim);
    border: 1px solid rgba(148, 163, 184, 0.3);
    border-radius: 4px;
    padding: 1px 5px;
}

/* まだ会っていない相手 (フリー対戦で伏せる)。肖像と同じ場所・同じ大きさ */
.ts-unknown {
    width: 54px;
    height: 54px;
    border-radius: 12px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 26px;
    font-weight: 700;
    color: var(--text-dim);
    background: rgba(255, 255, 255, 0.06);
    border: 1px dashed var(--panel-border);
}

/*
 * 倒した番人の印 (タイトル)。
 * **まだの枠も出す** —— 何個あるのかが見えているから埋めたくなる。
 * 主役はタイトルとボタンなので、印は小さく・伏せた枠はさらに薄く。
 */
.start-badges {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin-top: 8px;
}
/*
 * いくつ取ったか。**印そのものは押せないままにする** —— カーソル
 * (focus.js) の立ち寄り先が5つ増えるだけで、行き先はどれも同じになる。
 * 代わりに数を字で出す。長く `title` 属性だけが正体を持っていたが、
 * 学校で使うのはタブレットで、そこではツールチップが出ない。
 */
.start-badge-count {
    font-family: var(--font-num);
    font-size: 12px;
    color: var(--text-dim);
    margin-left: 2px;
}
.start-badge {
    width: 26px;
    height: 26px;
    border-radius: 6px;
    border: 1px dashed rgba(150, 215, 255, 0.22);
}
.start-badge.got {
    border: none;
    filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.6));
}
.start-badge img { width: 100%; height: 100%; display: block; }

/*
 * 相手の最後のひとこと (結果画面)。
 *
 * **肖像に大きさを必ず書くこと。** ここを書き忘れていたため、512×512 の
 * 肖像が素の大きさで出て、結果画面を丸ごと覆っていた ―― セリフもバッジも
 * その下に押し出されて読めなかった。絵は「誰が言ったか」の目じるしでしかない。
 */
.go-say {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 2px 0 4px;
    padding: 8px 12px;
    border-radius: 10px;
    border-left: 3px solid var(--opp-color, var(--panel-border));
    background: rgba(255, 255, 255, 0.05);
    text-align: left;
}
.go-say-face {
    width: 34px;
    height: 34px;
    flex: 0 0 34px;
    border-radius: 8px;
    object-fit: cover;
    display: block;
}
.go-say-text {
    font-size: 13px;
    line-height: 1.55;
    color: var(--text);
    min-width: 0;
}

/* ============ オンラインでの名前 (打たずに配られる) ============ */
.name-preview {
    font-size: 18px;
    font-weight: 700;
    color: var(--accent);
    padding: 8px 0;
    letter-spacing: 0.02em;
}
.name-icons { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 10px; }
.name-icon {
    appearance: none;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid var(--panel-border);
    border-radius: 8px;
    padding: 4px;
    line-height: 0;
    cursor: pointer;
    opacity: 0.55;
}
.name-icon.on { opacity: 1; border-color: var(--accent); background: rgba(63, 216, 255, 0.14); }
.name-icon .type-sigil { width: 28px; height: 28px; }

/* ============ コードを打つ格子 (コントローラー) ============ */
/*
 * **唯一、打たずには済まない場所。** コードは相手からもらう使い捨ての合い札
 * なので、生成にも定型にもできない。ただし英数字だけなので盤は小さくて済む
 * (五十音だと 3倍の広さと、濁点・小書きの作法が要る)。
 * ポインタとキーボードの人には出さない ―― そちらは直に打つほうが速い。
 */
.code-pad { display: none; }
html[data-input="gamepad"] .code-pad {
    display: grid;
    grid-template-columns: repeat(9, 1fr);
    gap: 5px;
    margin: 10px 0 4px;
}
.code-key {
    appearance: none;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid var(--panel-border);
    border-radius: 7px;
    color: var(--text);
    font-family: var(--font-num);
    font-size: 17px;
    font-weight: 700;
    padding: 7px 0;
    cursor: pointer;
}
.code-key.wide { grid-column: span 9; font-family: var(--font-ui); font-size: 13px; }

/* あいてが選んだ印 (naming.js の番号から引いたタイプ記号)。
 * 役割の札 (ホスト/ゲスト) とは別の軸なので、名前の前に小さく添える */
/*
 * 名札のタイプ記号 (だれの席かを示す identity)。**縮ませない。**
 *
 * すぐ上の `.pl-role` には「名前が長くても消えないように縮ませない」と
 * 書いてあるのに、**identity そのものであるこちらに同じ指定が無かった** ――
 * 配られる名前は最長13字あり (`あわてん坊の テントウムシ`)、長い名前が来ると
 * flex の既定 (`0 1 auto`) で記号のほうが潰れていた。
 *
 * この手のゲームの名札は**顔/記号が主で、名前は従**  ―― 名前は切られてよいが、
 * 見分けるための絵は最後まで残す、が標準の形。しかもこの名前は
 * **前半が修飾語**なので、切れると後半の「いきもの」から先に消える =
 * 記号まで潰れると見分ける手がかりが1つも残らない。
 *
 * 置き場所の `.pl-nameline` は flex なので、ここは**必ず flex アイテム**になる。
 * `inline-flex` と書いても仕様でブロック化されて `flex` になるだけなので、
 * **効かない宣言を残さない** (算出値と食い違う宣言は、次に読む人を探しに行かせる)。
 */
.pl-icon { display: flex; line-height: 0; flex: 0 0 auto; }
.pl-icon .type-sigil { width: 16px; height: 16px; }
