  * { margin: 0; padding: 0; box-sizing: border-box; }

  /* === Time-of-day color variables ===
     Set on <body data-tod="...">. Default is "morning" (京都の朝).
     The values aren't strong tints — they're whispers — so the world
     reads as a quiet shift in light, not a Photoshop filter.            */
  :root {
    /* i18n(2026-08-15 ハルト): 言語別フォント切替の起点。値は既存の game.css :53 と
       文字列そのまま一致させてある（ja の見た目を1pxも変えないため）。
       言語別の上書きは /i18n/lang.css（html[lang="..."] セレクタ）が担当する。 */
    --ui-font: 'Noto Sans JP', 'Inter', 'Helvetica Neue', sans-serif;

    /* ── レア度★6（神話）の虹＝プリズムグラデーション（2026-08-19 新設）──
       ★1〜★5 は単色（茶/緑/青/紫/金）で色相環をほぼ等間隔に使い切っている。
       残る単色の空きは赤(0°)とシアン(180°)だけだが、★の表示は font-size:9px の
       極小テキストなので 赤は★1の茶(30°)と、シアンは★3の青(219°)と 9px では
       見分けが付かない。加えて赤は業火(gouka)の固有色と衝突し「★6＝業火の色」
       という誤読を生む（世界樹が死ぬ）。
       ⇒ 色相をもう1つ消費するのではなく「単色でない」という**別の次元**へ逃がす。
          虹は特定の色相に属さないので、赤黒の業火にも緑金の世界樹にも中立でいられる。
       --rar6-solid は background-clip:text 非対応環境のフォールバック（下の @supports 参照）。 */
    --rar6-grad: linear-gradient(100deg,
       #ff5ea8   0%,   /* マゼンタ   */
       #ffd15e  25%,   /* 金より明るい黄 */
       #7dffc4  50%,   /* ミント     */
       #5ec8ff  75%,   /* スカイ     */
       #c48bff 100%);  /* ラベンダー */
    --rar6-solid: #ff5ea8;
    /* Morning (default) */
    --tod-mist:    rgba(230, 210, 170, 0.30);
    --tod-grid:    rgba(255, 235, 190, 0.16);
    --tod-grid-major: rgba(255, 235, 190, 0.28);
    --tod-ambient-a: #d4a060;
    --tod-ambient-b: #90b870;
    --tod-ambient-c: #c89050;
    --tod-ambient-d: #88a878;
  }
  body[data-tod="noon"] {
    /* 昼：陽光で明るくなった乾き土 */
    --tod-mist:    rgba(240, 225, 185, 0.22);
    --tod-grid:    rgba(255, 242, 205, 0.15);
    --tod-grid-major: rgba(255, 242, 205, 0.26);
    --tod-ambient-a: #b8d098;
    --tod-ambient-b: #d8c070;
    --tod-ambient-c: #a8c888;
    --tod-ambient-d: #c0b890;
  }
  body[data-tod="dusk"] {
    /* 夕：赤みがかった照り土 */
    --tod-mist:    rgba(190, 110, 65, 0.28);
    --tod-grid:    rgba(255, 215, 155, 0.15);
    --tod-grid-major: rgba(255, 215, 155, 0.28);
    --tod-ambient-a: #c85030;
    --tod-ambient-b: #d08840;
    --tod-ambient-c: #b06848;
    --tod-ambient-d: #986080;
  }
  body[data-tod="night"] {
    /* 夜：暗い湿った土 */
    --tod-mist:    rgba(80, 60, 40, 0.3);
    --tod-grid:    rgba(200, 180, 130, 0.08);
    --tod-grid-major: rgba(200, 180, 130, 0.16);
    --tod-ambient-a: #6a5030;
    --tod-ambient-b: #7a8050;
    --tod-ambient-c: #605040;
    --tod-ambient-d: #485038;
  }

  body {
    background: #0d1520;  /* リサイズ時の1フレーム露出用フォールバック（旧#c8a870茶→夜の深色） */
    width: 100vw;
    height: 100vh;
    overflow: hidden;
    font-family: var(--ui-font);
    cursor: none;
    user-select: none;
    transition: background 1.6s ease;
  }

  /* === Layered background ===
     #bg-paper   — CSS gradient + paper grain (cheapest layer)
     #bg-canvas  — ambient ripples, mist, birds (separate rAF loop)
     #c          — main interactive canvas (untouched logic)            */
  #bg-paper {
    position: fixed;
    inset: 0;
    z-index: -2;
    background: #0d1520;  /* PNG テクスチャ ロード前 fallback（旧#c8a870茶→夜の深色） */
  }

  #bg-canvas {
    position: fixed;
    top: 0; left: 0;
    width: 100%; height: 100%;
    z-index: -1;
    pointer-events: none;
  }

  canvas {
    position: fixed;
    top: 0; left: 0;
    width: 100%; height: 100%;
    touch-action: none;
    z-index: 0;
  }
  canvas#c { background: transparent; }

  /* ── custom cursor ── */
  #cursor {
    position: fixed;
    top: 0; left: 0;
    width: 28px; height: 28px;
    pointer-events: none;
    z-index: 1000;
    transform: translate(-50%, -50%);
    will-change: transform;
  }
  #cursor::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 1.5px solid rgba(30,30,30,0.5);
    transition: transform 0.18s cubic-bezier(0.25,0.46,0.45,0.94),
                border-color 0.18s;
  }
  #cursor::after {
    content: '';
    position: absolute;
    top: 50%; left: 50%;
    width: 3.5px; height: 3.5px;
    background: rgba(30,30,30,0.7);
    border-radius: 50%;
    transform: translate(-50%, -50%);
    transition: transform 0.15s cubic-bezier(0.25,0.46,0.45,0.94),
                background 0.15s;
  }
  body.pressing #cursor::before {
    transform: scale(0.55);
    border-color: var(--my-color);
    opacity: 0.85;
  }
  body.pressing #cursor::after {
    transform: translate(-50%, -50%) scale(2.2);
    background: var(--my-color);
    opacity: 0.6;
  }
  body.dragging #cursor::before {
    transform: scale(0.7);
    border-color: rgba(30,30,30,0.25);
  }
  body[data-mode="axe"]     #cursor::before { border-color: #c07030; }
  body[data-mode="seed"]    #cursor::before { border-color: #40a828; }
  body[data-mode="sapling"] #cursor::before { border-color: #2e7d32; }
  body[data-mode="special"] #cursor::before { border-color: var(--my-color); box-shadow: 0 0 0 2px rgba(193,74,61,0.15); }

  /* ── モーダル表示中はOS標準カーソルを復活 ──
     ゲーム本体は cursor:none + カスタム白カーソルだが、白背景のポップアップ上では
     カスタムカーソルが同化して見えなくなる。モーダルを開いている間（body.modal-open）は
     カスタムカーソルを隠し、OS標準カーソルへ戻す。ボタン/リンクは個別に pointer。 */
  body.modal-open { cursor: auto; }
  body.modal-open #cursor { display: none; }

  /* ── UI overlays ──
     Unified visual language with the login screen: frosted glass
     (rgba(255,253,248,0.78) + backdrop-filter blur), soft 1px borders,
     larger radii (10–20px). Night mode darkens the chip surfaces via
     :body[data-tod="night"] selectors below.                         */
  /* ★2026-08-19（マスター指摘②③ ハルト）: #count は DOM 上 #hud-toprow の子になった。
     ここ（=既定 ≥641px）は position:fixed のまま＝**フローから完全に抜ける**ので、
     行は従来どおり「#user-bar と #hud-topright の2つ」しか並べない。
     ⇒ ≥641px のレイアウトは1pxも動かない（gap も1回しか入らない）。
     狭幅（≤640px）でだけ static に戻して行の3番目の子になる。詳細は下の狭幅ブロック。 */
  /* ══════════════════════════════════════════════════════════════════════
     オンライン数の装飾ダッシュは CSS 側で足す（2026-08-19 お嬢・マスター判断）
     [なぜ辞書から出したか]
       元は i18n 辞書に「— {n} online —」と文字列ごと入っていた。だがダッシュは
       **装飾であって情報ではない**のに、5言語すべてで約21pxの幅を消費していた。
       その21pxのせいで iPhone(390px) では #count がヘッダ行に載らず、2行目へ
       縮退していた（マスター指摘「オンライン数が下にずれている」の残り）。
       辞書に混ぜたままでは「幅が要る所でだけ外す」ができない。CSS へ出せば
       メディアクエリ1行で落とせる。翻訳者が触る対象からも外れる（装飾だから正しい）。
     ★辞書のキーは 'hud.online' のまま、値だけ「{n} online」等へ変更済み。
       ダッシュを増減したくなったら**ここだけ**を触ること。辞書へ戻すな。
     ══════════════════════════════════════════════════════════════════════ */
  #count::before { content: "— "; }
  #count::after  { content: " —"; }

  #count {
    position: fixed;
    bottom: 26px;
    left: 50%;
    transform: translateX(-50%);
    color: rgba(0,0,0,0.42);
    font-size: 11px;
    letter-spacing: 0.24em;
    pointer-events: none;
    z-index: 100;
    white-space: nowrap;
  }

  #status { display: none; }

  /* ── user bar ── */
  /* position:fixed / top / left / z-index は #hud-toprow へ移設（2026-08-19 残課題A）。
     ここは #hud-toprow の flex 子。
     margin-top:2px … 旧 top:14px の再現（行の top は 12px なので差の 2px）。
     ★min-width は auto（＝min-content）で止めること。2026-08-19 以前はここに
       min-width:0 が書いてあった。理由は「#tagline に縮む余地を作るため」だったが、
       #tagline 自身が min-width:0 + ellipsis を持つので**親には不要**であり、
       むしろ有害だった: min-width:0 は flex のアルゴリズムに「左群はいくらでも
       小さくできる」と信じ込ませる。すると右群へ縮む圧力が一切かからず、
       左群の"箱"だけが縮んで中身（flex:0 0 auto のロゴ・使い方・言語切替）が
       箱から溢れ、右群の上に重なる。**レイアウト計算からは見えない溢れ方**なので
       「幅は足りている」という嘘の計算結果が出る。実測でこれが交差95件の正体だった。
       ただし min-width:auto に固定するのも誤りだった。#tagline は white-space:nowrap
       なので、自身に min-width:0 があっても**親の min-content には全文字幅で効く**。
       ＝タグラインが居る幅では左群の床が「タグライン込み」になり、装飾が居座ったまま
       機能を持つ座標だけが削られる（実測: 761px/en で座標が32px欠けた）。
       ⇒ **タグラインが居るかどうかで床を切り替える**のが正しい:
         >760px（タグラインあり）… min-width:0。左群の箱が縮み、内側でタグラインが
           省略される。中身が溢れる前にタグラインという内部の受け皿が働く。
         ≤760px（タグラインなし）… min-width:auto（下の @media で指定）。内部の受け皿が
           無いので床を尊重し、足りないぶんは右群の #coords-val が引き受ける。
       新しい定数は増やしていない。**タグラインが消える境目にそのまま相乗り**している。
     ★overflow:hidden を足さないこと。言語切替のリストボックス（.lang-switch__menu）は
       .lang-switch の中に position:absolute で開くので、ここで刈ると開いたメニューが
       切れて選べなくなる。刈ってよいのは #tagline の内側だけ。 */
  #user-bar {
    position: relative;
    margin-top: 2px;
    /* min-width:0 … タグラインが居る幅ではこちら。箱が縮み、内側でタグラインが痩せる。
       タグラインが消える ≤760px では @media 側で min-width:auto に切り替える。 */
    min-width: 0;
    /* flex-shrink:100 … 右群(1)より100倍痩せやすくする。足りない時はまず
       #tagline が省略され、左群が床に着いてから初めて右群が譲る（2026-08-19 お嬢）。 */
    flex: 0 100 auto;
    pointer-events: auto;
    display: flex;
    align-items: center;
    gap: 10px;
  }
  #user-bar a, #user-bar button { cursor: pointer; }
  /* 縮み代は #tagline だけに集中させる（2026-08-19 残課題A）。
     ここを外すと、足りない時にロゴや「使い方」まで一緒に潰れて字が折り返す。 */
  #user-bar > #brand-logo,
  #user-bar > #howto-link,
  #user-bar > .lang-switch,
  #user-bar > #lang-switch { flex: 0 0 auto; white-space: nowrap; }

  /* ── glass-blur 共通クラス: backdrop-filter blur(12px) saturate(1.1) ── */
  .glass-blur {
    backdrop-filter: blur(12px) saturate(1.1);
    -webkit-backdrop-filter: blur(12px) saturate(1.1);
  }

  /* ── zoom control（画面ズーム ＋/−）既存HUD(nav-tab/coords)と同トーン ── */
  #zoom-hud {
    position: fixed;
    right: 16px; top: 50%;
    transform: translateY(-50%);
    z-index: 200;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    padding: 6px 5px;
    background: rgba(255,253,248,0.78);
    border: 1px solid rgba(255,255,255,0.7);
    border-radius: 24px;
    box-shadow: 0 1px 0 rgba(255,255,255,0.9) inset, 0 4px 14px rgba(40,30,20,0.08);
    pointer-events: auto;
    user-select: none;
  }
  #zoom-hud button {
    width: 40px; height: 40px;
    display: flex; align-items: center; justify-content: center;
    background: none; border: none;
    font-family: inherit; font-size: 21px; line-height: 1;
    color: rgba(0,0,0,0.5);
    border-radius: 50%;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, transform 0.1s;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
  }
  #zoom-hud button:hover { background: rgba(0,0,0,0.06); color: rgba(0,0,0,0.8); }
  #zoom-hud button:active { transform: scale(0.9); }
  #zoom-hud button:disabled { opacity: 0.28; cursor: default; pointer-events: none; }
  #zoom-level {
    font-size: 10px; letter-spacing: 0.02em;
    color: rgba(0,0,0,0.42);
    font-variant-numeric: tabular-nums;
    padding: 1px 0;
  }
  body[data-tod="night"] #zoom-hud {
    background: rgba(20,26,30,0.5);
    border-color: rgba(255,255,255,0.12);
  }
  body[data-tod="night"] #zoom-hud button { color: rgba(255,255,255,0.6); }
  body[data-tod="night"] #zoom-hud button:hover { background: rgba(255,255,255,0.1); color: rgba(255,255,255,0.9); }
  body[data-tod="night"] #zoom-level { color: rgba(255,255,255,0.45); }

  /* ══════════════════════════════════════════════════════════════════════
     右上HUDの行（2026-08-18 依頼② ハルト）
     #coords / #login-tab / #mypage-tab を包む唯一の位置決め要素。
     [なぜ作ったか] 旧実装は3要素それぞれが position:fixed で、#coords の right
       だけが「隣のログインボタンの実測幅」を焼き込んだ定数だった。ところが同座標を
       共有する #mypage-tab は ja で1文字長い（「マイページ」5字 vs「ログイン」4字）ため、
       ログイン中かつ ja かつ ≤480px でだけ #coords に約5.5px 食い込んでいた。
       ＝「隣の幅を定数へ焼く」方式そのものが再発源。
     [不変条件] ★この行の中では right / left / position を子に書かないこと。
       幅の計算はブラウザ（flex + gap）に任せる。ここを破ると同じバグが必ず戻る。
     [z-index] 子（.nav-tab / #coords）の z-index:200 はこのラッパへ集約した。
       .glass-blur の backdrop-filter は要素ごとにスタッキング文脈を作るが、
       ラッパが z-index:200 を持てば外から見た重なり順は従来と同値。
       #toast-container(500) / #item-notif-container(600) は元から上。
     ══════════════════════════════════════════════════════════════════════ */
  /* ══════════════════════════════════════════════════════════════════════
     上部帯の1行（2026-08-19 残課題A ハルト）
     #user-bar（左群）と #hud-topright（右群）を両端に寄せる唯一の位置決め要素。
     [なぜ作ったか]
       この2つは別々の position:fixed で、左は left から右へ・右は right から左へ
       伸びるだけで互いを知らなかった。だから幅を狭めれば必ずどこかで交差する。
       481〜718px の帯で地球儀と「JP ▾」が座標チップの下へ潜っていたのがそれで、
       依頼②より前から在った欠陥。
     [なぜ「何px で消す」で済ませなかったか]
       交差の開始点は文言の長さで決まり、上限が無い。実測（5言語 × ゲスト/ログイン）:
         座標 "0, 0"           … 最悪 730.5px（en / ログイン）
         座標 "-1234, -5678"   … 最悪 779.8px（同）
         座標 "-12345, -67890" … 最悪 793.1px（同）
       #coords の桁に clamp が無いので、定数を置いた瞬間に「次に1字増えたら破れる」
       状態になる。依頼②で廃した #coords{right:94px}（隣のボタン幅の手計算）と同型。
     [対処] 幅の按分をブラウザへ返した。両群が同じ flex 行の子で、かつ
       **行のどこかに縮み代が残っている限り**、片方が伸びれば他方の取り分が
       減るだけで交差は起こらない。
     ★2026-08-19 是正（お嬢／リツの敵対的検証）:
       当初この欄には「交差は構造的に起こり得ない」と書いてあったが**誤り**だった。
       縮み代を #tagline ただ1つに集中させていたところ、その #tagline は
       ≤760px で display:none になる。消えた瞬間に行の縮み代はゼロ＝床になり、
       床を割れば子が箱から溢れて改修前と同一の交差に戻る。
       実測: W≤480px では新旧の交差量が1つ残らず完全に一致していた。
       ⇒ 受け皿を二段にした。#tagline（先に痩せる／flex-shrink:100 側）→
         #coords-val の ellipsis（最後の受け皿／flex-shrink:1 側）。
       ★教訓: 「構造で防いでいる」と書く前に、**その構造が消える条件**を探せ。
     [pointer-events] 行そのものは全幅に伸びるので none。子で auto に戻す。
       これを忘れると画面上部の全幅で波紋が打てなくなる。
     ★不変条件: この行の子に position / left / right を書かないこと。
       書いた瞬間に「隣の幅を手計算する」世界へ戻る。
     ══════════════════════════════════════════════════════════════════════ */
  #hud-toprow {
    position: fixed;
    top: 12px;
    left: 18px;
    right: 18px;
    z-index: 200;
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    pointer-events: none;
  }

  /* position:fixed / top / right / z-index は #hud-toprow へ移設（残課題A）。
     [2026-08-19 お嬢・敵対的検証の是正]
       当初ここは flex:0 0 auto（右群は絶対に縮めない）だった。狙いは「譲るのは
       装飾の #tagline であって機能を持つチップではない」。考え方は正しいが、
       #tagline は ≤760px で display:none になる。**消えた瞬間、行の縮み代は
       ゼロになる**（左群の残りも右群も全て flex:0 0 auto）。床を割った先では
       子が箱から溢れ、改修前とまったく同じ交差に戻っていた。
       実測（リツ）: W≤480px では新旧の交差量が1つ残らず完全に一致。
       ⇒ 右群にも「最後の受け皿」を用意する。縮む順序は flex-shrink の比で決める:
          #user-bar(100) → まず #tagline が省略される
          #hud-topright(1) → 左群が min-content の床に着いて初めて座標が省略される
       機能を持つボタン（.nav-tab）は flex-shrink:0 で最後まで守る。譲るのは
       座標の"数字の末尾"だけ＝当初の意図は保たれている。 */
  #hud-topright {
    flex: 0 1 auto;
    min-width: 0;
    pointer-events: auto;
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 8px;
  }

  /* ── nav tab (login / mypage 共通) ── */
  /* position:fixed / top / right / z-index は #hud-topright へ移設（依頼②）。 */
  .nav-tab {
    /* 右群が縮めるようになった（2026-08-19）ので、機能を持つボタンは明示的に守る。 */
    flex-shrink: 0;
    background: rgba(255,253,248,0.78);
    border: 1px solid rgba(255,255,255,0.7);
    border-radius: 20px;
    padding: 7px 14px 7px 10px;
    cursor: pointer;
    box-shadow: 0 1px 0 rgba(255,255,255,0.9) inset, 0 4px 14px rgba(40,30,20,0.08);
    /* ★この display:none ↔ flex は index.html の loadMe() が inline style で切り替える。
       #hud-topright の flex 子なので display:none 側は幅0・gap も畳まれる。 */
    display: none;
    flex-direction: row;
    align-items: center;
    gap: 6px;
    font-family: inherit;
    font-size: 11px;
    letter-spacing: 0.1em;
    color: rgba(0,0,0,0.55);
    transition: background 0.18s, box-shadow 0.18s, color 0.15s;
  }
  .nav-tab:hover {
    background: rgba(255,253,248,0.92);
    box-shadow: 0 1px 0 rgba(255,255,255,0.9) inset, 0 6px 20px rgba(40,30,20,0.12);
    color: rgba(0,0,0,0.78);
  }
  .nav-tab:active { transform: scale(0.97); }

  /* position:fixed / top / right / z-index は #hud-topright へ移設（依頼②）。 */
  #coords {
    font-size: 11px;
    color: rgba(0,0,0,0.55);
    letter-spacing: 0.06em;
    font-variant-numeric: tabular-nums;
    background: rgba(255,253,248,0.78);
    border: 1px solid rgba(255,255,255,0.7);
    border-radius: 20px;
    padding: 7px 12px 7px 11px;
    box-shadow: 0 1px 0 rgba(255,255,255,0.9) inset, 0 4px 14px rgba(40,30,20,0.08);
    backdrop-filter: blur(12px) saturate(1.1);
    -webkit-backdrop-filter: blur(12px) saturate(1.1);
    display: flex; align-items: center; gap: 6px;
    cursor: pointer;
    white-space: nowrap;
    /* 上限の無い量（座標の桁）を受け止める受け皿（2026-08-19 お嬢）。
       ?warp=X,Y に clamp が無く、URL 一発で6桁以上に到達できる（index.html:3486付近）。
       ピンと＋は flex-shrink:0 で残し、痩せるのは数字の末尾だけ。 */
    min-width: 0;
    overflow: hidden;
    transition: background 0.18s, box-shadow 0.18s, color 0.15s;
    user-select: none;
  }
  #coords:hover {
    background: rgba(255,253,248,0.92);
    box-shadow: 0 1px 0 rgba(255,255,255,0.9) inset, 0 6px 20px rgba(40,30,20,0.12);
    color: rgba(0,0,0,0.78);
  }
  .coords-pin-icon {
    color: #c14a3d;
    flex-shrink: 0;
    display: block;
  }
  /* ここが「上限の無い量」の唯一の逃がし先（2026-08-19 お嬢）。
     flex-shrink:0 のままだと桁が伸びた分がそのまま箱を押し広げ、行の床を割る。 */
  #coords-val { flex-shrink: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  .coords-add {
    font-size: 12px;
    line-height: 1;
    color: rgba(0,0,0,0.28);
    flex-shrink: 0;
    margin-left: 1px;
    transition: color 0.15s;
  }
  #coords:hover .coords-add { color: #c14a3d; }

  /* ── mypage color picker ── */
  .mp-color-row {
    display: flex; flex-wrap: wrap; gap: 8px;
    padding: 10px 14px 14px;
  }
  /* プリセットセクション（「プリセット」小見出し＋7色スウォッチ行） */
  .mp-preset-section {
    border-bottom: 1px solid rgba(255,255,255,0.06);
  }
  .mp-section-header {
    padding: 8px 14px 2px;
  }
  .mp-preset-row {
    padding-bottom: 12px;
  }
  .mp-swatch {
    width: 28px; height: 28px;
    border-radius: 50%;
    /*
     * border を排除し outline + ::after 疑似要素リングで同心円を保証する。
     * border があると box-shadow の spread 起点が border 外縁になるため、
     * 目視で「色丸とリングがズレている」と感じる視覚的な問題が生じやすい。
     * ::after は inset で対称配置するため常に完全な同心円になる。
     */
    border: none;
    box-shadow: 0 1px 3px rgba(0,0,0,0.35);
    cursor: pointer;
    position: relative;
    transition: transform 0.15s cubic-bezier(0.34,1.56,0.64,1);
    flex-shrink: 0;
  }
  .mp-swatch:hover { transform: scale(1.18); }
  /*
   * 選択中リング: ::after 疑似要素を inset:-4px で要素外側4px まで拡張。
   * border-radius:50% で完全な円形。
   * border:2px solid white で白リング（幅2px）。
   * box-shadow で外側に色リング（選択色 var(--my-color)、幅2px）を追加。
   * inset が対称なのでどのサイズ差も生じない＝完全同心円。
   * transition で滑らかな出現。
   */
  .mp-swatch::after {
    content: '';
    display: none;
    position: absolute;
    inset: -4px;          /* 色丸の外側4px = 白リングの内径との隙間2px + 白リング幅2px */
    border-radius: 50%;
    border: 2px solid rgba(255,255,255,0.9);
    box-shadow: 0 0 0 2px var(--my-color, #c14a3d);
    pointer-events: none;
  }
  .mp-swatch.selected::after { display: block; }
  .mp-swatch-custom {
    background: rgba(255,255,255,0.07);
    border: 1.5px dashed rgba(255,255,255,0.22); /* .mp-swatch の border:none を後定義で上書き */
    display: flex; align-items: center; justify-content: center;
    font-size: 14px; color: rgba(255,255,255,0.38);
    overflow: hidden;
    /* 2026-08-18 依頼⑤: 置き場所を「マイカラー見出し行」から「棚(.mp-saved-row)の末尾」へ
       移した。押した場所の真下ではなく、押した場所そのものに丸が増えるようになる。 */
    flex-shrink: 0;
  }
  .mp-swatch-custom:hover { border-color: rgba(255,255,255,0.45); }
  /* 棚が満杯(7色)。native ピッカーは input[disabled] で開かない。
     押した時の告知は mpCustomPlusClick() が既存キー color.error.limit で出す。 */
  .mp-swatch-custom.is-full {
    opacity: 0.38;
    cursor: not-allowed;
  }
  .mp-swatch-custom.is-full:hover {
    border-color: rgba(255,255,255,0.22);
    transform: none;
  }
  .mp-swatch-custom.is-full input[type=color] { cursor: not-allowed; }
  .mp-swatch-custom input[type=color] {
    position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; height: 100%;
  }

  /* ── mypage saved colors (マイカラー) ── */
  .mp-saved-colors-section {
    border-top: 1px solid rgba(255,255,255,0.06);
  }
  .mp-saved-header {
    display: flex; align-items: center; gap: 8px;
    padding: 8px 14px 4px;
  }
  /* ヘッダー左端のラベルが残りスペースを取らないようにし、右側のUI（＋・登録ボタン）を右寄せ */
  .mp-saved-header .mp-saved-label {
    flex: 1;
  }
  .mp-saved-label {
    font-size: 10px; letter-spacing: 0.1em;
    color: rgba(255,255,255,0.35);
    text-transform: uppercase;
  }
  /* 残数 n/7（2026-08-18 依頼⑤）。上限は7に達するまでどこにも書かれておらず、
     唯一の告知が「この色を登録」ボタンの title だった＝タッチ端末では出ない。
     数字だけなので i18n の新規キーは不要。 */
  .mp-saved-count {
    font-size: 10px;
    letter-spacing: 0.06em;
    color: rgba(255,255,255,0.28);
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
  }
  .mp-saved-count.is-full { color: rgba(230,140,120,0.75); }
  /* ★2026-08-18 依頼⑤: このクラスを持つ「この色を登録」ボタンは DOM から廃止した
     （確定＝適用＋自動登録になったため）。現時点で参照はどこにもない＝死にコード。
     R2 を差し戻す時にそのまま使えるので残してあるだけで、**ここを直しても
     画面には何も起きない**。使う予定が無いと判断した時点で丸ごと削除してよい。 */
  .mp-save-color-btn {
    font-size: 11px;
    color: rgba(255,255,255,0.65);
    background: rgba(255,255,255,0.08);
    border: 1px solid rgba(255,255,255,0.14);
    border-radius: 6px;
    padding: 3px 9px;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
    flex-shrink: 0;
  }
  .mp-save-color-btn:hover:not(:disabled) {
    background: rgba(255,255,255,0.15);
    color: rgba(255,255,255,0.9);
  }
  .mp-save-color-btn.mp-save-color-full,
  .mp-save-color-btn:disabled {
    opacity: 0.38; cursor: not-allowed;
  }
  .mp-saved-row {
    border-bottom: none;
    /* ✕ を常時表示にしたので上へ 5px はみ出す。行間で潰れないよう余白を足す
       （旧: padding-top:4px。hover 時だけ出ていたので誰も困っていなかった）。 */
    padding-top: 9px;
    min-height: 44px;
  }
  .mp-saved-empty {
    font-size: 11px; color: rgba(255,255,255,0.25);
    align-self: center;
    padding: 4px 0;
  }
  .mp-saved-swatch {
    width: 28px; height: 28px;
    border-radius: 50%;
    /* プリセットと同様に border を排除して ::after リングで同心円保証 */
    border: none;
    box-shadow: 0 1px 3px rgba(0,0,0,0.35);
    cursor: pointer;
    position: relative;
    flex-shrink: 0;
    transition: transform 0.15s cubic-bezier(0.34,1.56,0.64,1);
  }
  .mp-saved-swatch:hover { transform: scale(1.12); }
  .mp-saved-swatch::after {
    content: '';
    display: none;
    position: absolute;
    inset: -4px;
    border-radius: 50%;
    border: 2px solid rgba(255,255,255,0.9);
    box-shadow: 0 0 0 2px var(--my-color, #c14a3d);
    pointer-events: none;
  }
  .mp-saved-swatch.selected::after { display: block; }
  /* 削除✕（2026-08-18 依頼⑤ R4）
     [旧実装の何が問題だったか] display:none ＋ .mp-saved-swatch:hover で出す方式・14px。
       タッチ端末に hover は無いので、1回目のタップは親の onclick=mpPickColor に入り
       **消そうとしたのに、その色が適用される**。仮に :hover が合成されても同じタップで
       click も飛ぶので結果は変わらない。加えて14pxは推奨タップ標的を大きく下回る。
     [対処] 常時表示（opacity 0.5 → hover/focus で 1）・16px・::before の透明な
       拡張で当たり判定を28px相当にする。見た目は16pxのまま。
     ★これは「確定＝自動登録」(R2)とセットでしか出してはいけない。R2 だけ入れると
       7枠がすぐ埋まるのに捨てる導線がタッチで押せないまま＝出口が無くなる。 */
  .mp-saved-del {
    display: block;
    opacity: 0.5;
    position: absolute; top: -5px; right: -5px;
    width: 16px; height: 16px;
    border-radius: 50%;
    background: rgba(220,80,60,0.85);
    border: none;
    color: #fff;
    font-size: 9px;
    line-height: 16px;
    text-align: center;
    cursor: pointer;
    padding: 0;
    transition: opacity 0.15s, transform 0.15s;
    /* ::after リングより前面に出す（z-index で制御） */
    z-index: 1;
  }
  /* タップ標的の透明な拡張: 16px + 6px×2 = 28px 相当。見た目は変えない。 */
  .mp-saved-del::before {
    content: '';
    position: absolute;
    inset: -6px;
    border-radius: 50%;
  }
  .mp-saved-swatch:hover .mp-saved-del,
  .mp-saved-del:hover,
  .mp-saved-del:focus-visible { opacity: 1; }
  .mp-saved-del:focus-visible { outline: 2px solid rgba(255,255,255,0.7); outline-offset: 1px; }
  .mp-saved-del:active { transform: scale(0.9); }

  /* ── item HUD ── */
  #item-hud {
    position: fixed;
    bottom: 20px; right: 18px;
    display: none;
    align-items: center;
    gap: 8px;
    background: rgba(255,253,248,0.82);
    border: 1px solid rgba(255,255,255,0.7);
    border-radius: 12px;
    padding: 7px 12px;
    z-index: 200;
    box-shadow: 0 1px 0 rgba(255,255,255,0.9) inset, 0 4px 14px rgba(40,30,20,0.08);
    font-size: 12px;
    color: rgba(0,0,0,0.55);
    letter-spacing: 0.04em;
    pointer-events: auto;
  }
  .hud-icon { font-size: 16px; line-height: 1; display: flex; align-items: center; }
  .hud-name { font-size: 12px; color: rgba(0,0,0,0.6); white-space: nowrap; }
  .hud-dur  { display: flex; gap: 3px; align-items: center; }
  .hud-pip  { width: 6px; height: 6px; border-radius: 50%; background: rgba(0,0,0,0.12); }
  .hud-pip.on { background: #c14a3d; }
  .hud-link {
    font-size: 11px; color: rgba(0,0,0,0.28); text-decoration: none;
    border-left: 1px solid rgba(0,0,0,0.1); padding-left: 8px; margin-left: 2px;
    transition: color 0.15s; white-space: nowrap; cursor: pointer;
  }
  .hud-link:hover { color: rgba(0,0,0,0.55); }
  .hud-btn {
    background: none; border: none; font-family: inherit;
    font-size: 11px; color: rgba(0,0,0,0.28); letter-spacing: 0.04em;
    border-left: 1px solid rgba(0,0,0,0.1); padding-left: 8px; margin-left: 2px;
    cursor: pointer; transition: color 0.15s; white-space: nowrap;
  }
  .hud-btn:hover { color: rgba(0,0,0,0.55); }
  .hud-count { font-size: 11px; color: rgba(0,0,0,0.3); letter-spacing: 0; }

  /* ── ripple HUD ── */
  #ripple-hud {
    position: fixed;
    bottom: 20px; right: 18px;
    display: none;
    align-items: center;
    gap: 8px;
    background: rgba(255,253,248,0.82);
    border: 1px solid rgba(193,74,61,0.20);
    border-radius: 12px;
    padding: 6px 12px;
    z-index: 200;
    box-shadow: 0 1px 0 rgba(255,255,255,0.9) inset, 0 4px 14px rgba(40,30,20,0.08);
    font-size: 12px;
    color: rgba(0,0,0,0.55);
    letter-spacing: 0.04em;
    pointer-events: auto;
  }

  /* ── EXP HUD ── */
  #exp-hud {
    position: fixed;
    bottom: 20px; left: 14px;
    display: none;
    align-items: center;
    gap: 10px;
    background: rgba(255,253,248,0.92);
    /* 致命②対策: blur(16px)→blur(8px)。背景canvas再描画(スクロール時)との
       blur再合成コストがゲスト(phantom EXP高頻度更新)で顕著だったため軽量化。
       containで再描画の影響範囲をこのHUD内に閉じ込め、外側レイアウトへ波及させない。 */
    backdrop-filter: blur(8px) saturate(1.2);
    -webkit-backdrop-filter: blur(8px) saturate(1.2);
    contain: layout paint;
    border: 1px solid rgba(255,255,255,0.85);
    border-radius: 16px;
    padding: 9px 14px;
    z-index: 200;
    pointer-events: none;
    min-width: 190px;
    font-size: 13px;
    color: rgba(0,0,0,0.55);
    letter-spacing: 0.04em;
    box-shadow: 0 2px 0 rgba(255,255,255,0.9) inset, 0 6px 20px rgba(40,30,20,0.1);
  }
  .exp-level {
    font-size: 12px; font-weight: 600; letter-spacing: .06em;
    color: rgba(0,0,0,.5); white-space: nowrap; flex-shrink: 0;
  }
  .exp-bar-wrap {
    flex: 1; height: 7px;
    background: rgba(0,0,0,.1); border-radius: 4px; overflow: hidden; min-width: 80px;
  }
  .exp-bar-fill {
    height: 100%; background: linear-gradient(90deg, #6ea84a, #8fcc5e);
    border-radius: 4px;
    transition: width .4s cubic-bezier(0.25,0.46,0.45,0.94);
    box-shadow: 0 0 6px rgba(110,168,74,0.45);
  }
  .exp-frac {
    font-size: 11px; color: rgba(0,0,0,.32);
    white-space: nowrap; flex-shrink: 0; font-variant-numeric: tabular-nums;
  }
  #exp-hud.exp-locked {
    opacity: 0.52;
    filter: grayscale(0.6);
    cursor: pointer;
    pointer-events: auto;
  }
  #exp-hud.exp-locked .exp-bar-fill { background: rgba(0,0,0,.18); box-shadow: none; }
  /* ★2026-08-22: 旧実装は絵文字 U+1F512 を出していた（マスター依頼4「画面の表示に
     絵文字を使うのはやめてほしい。世界観に合っていない」）。
     ただの削除にはせず**CSS で錠前を描いた**。理由: この錠は「まだ貯まらない」という
     状態そのものを一目で伝えており、文字ラベルだけでは弱くなる。CSS 図形なら
     絵文字でもフォント依存でもなく、どの端末でも同じ形が出る（豆腐が構造的に起きない）。
     ★静的な図形のみ。アニメーションも box-shadow も持たない＝描画コストは実質ゼロ。
     ★色は currentColor 追従。下の .exp-locked-label と同じ値を持たせてあるので、
       昼夜切替（body[data-tod="night"]）でも文字と一緒に反転する。 */
  .exp-lock-icon {
    font-size: 13px; flex-shrink: 0; line-height: 1;
    position: relative;
    display: block;
    width: 0.70em; height: 0.58em;
    margin-top: 0.30em;          /* シャックル(::before)のぶん下げて視覚的中心を合わせる */
    border-radius: 0.13em;
    background: currentColor;
    color: rgba(0,0,0,.4);
  }
  .exp-lock-icon::before {       /* シャックル（上の弧） */
    content: '';
    position: absolute;
    left: 50%; bottom: 100%;
    transform: translateX(-50%);
    width: 0.42em; height: 0.30em;
    border: 0.10em solid currentColor;
    border-bottom: none;
    border-radius: 0.28em 0.28em 0 0;
  }
  .exp-locked-label { font-size: 10px; color: rgba(0,0,0,.4); white-space: nowrap; flex-shrink: 0; }

  /* ── EXP HUD: phantom（ゲストの擬似ゲージ・緑が実際に伸びる＋登録誘導）── */
  /* ゲスト状態（未ログイン）では、経験値バーの枠を穏やかに常時点滅させて登録を促す。
     「レベル2到達後」= exp-phantom-earned クラスが付いた瞬間から開始（level>1 で付与される）。
     ログインで自動停止（クラスが外れる）。
     2.8s周期のゆっくりした opacity+境界グロー の明滅。回転・スイープは含まない純粋な明滅。 */
  @keyframes phantom-hud-glow {
    0%, 100% {
      box-shadow: 0 2px 0 rgba(255,255,255,0.9) inset, 0 6px 20px rgba(40,30,20,0.10);
      border-color: rgba(255,255,255,0.85);
      opacity: 1;
    }
    50% {
      box-shadow: 0 2px 0 rgba(255,255,255,0.9) inset, 0 0 12px 3px rgba(100,190,80,0.50), 0 6px 20px rgba(40,30,20,0.10);
      border-color: rgba(130,210,90,0.80);
      opacity: 0.88;
    }
  }
  #exp-hud.exp-phantom {
    cursor: pointer;
    pointer-events: auto;
    /* animation はLv2到達(exp-phantom-earned)まで付けない */
  }
  #exp-hud.exp-phantom-earned {
    animation: phantom-hud-glow 2.8s ease-in-out infinite;
  }
  #exp-hud.exp-phantom .exp-phantom-lv {
    font-size: 12px; font-weight: 600; letter-spacing: .06em;
    color: rgba(0,0,0,.5); white-space: nowrap; flex-shrink: 0;
  }
  /* レベルアップ(Lv2以上)後だけ、Lv表記を緑で光らせて「アイテムを獲得できる」を目立たせる
     （誘導ラベル文言は廃止。光る対象を .exp-phantom-lv に付け替えてCTA性は維持）。 */
  #exp-hud.exp-phantom-earned .exp-phantom-lv {
    color: #5a8a36;
    animation: phantom-pulse 2.4s ease-in-out infinite;
  }
  @keyframes phantom-pulse { 0%,100% { opacity: 0.7; } 50% { opacity: 1; } }

  /* Night モード: exp-phantom-earned の常時点滅をnightパレットに合わせる */
  body[data-tod="night"] #exp-hud.exp-phantom-earned {
    animation: phantom-hud-glow-night 2.8s ease-in-out infinite;
  }
  @keyframes phantom-hud-glow-night {
    0%, 100% {
      box-shadow: 0 1px 0 rgba(255,255,255,0.08) inset, 0 4px 16px rgba(0,0,0,0.30);
      border-color: rgba(255,255,255,0.12);
      opacity: 1;
    }
    50% {
      box-shadow: 0 1px 0 rgba(255,255,255,0.08) inset, 0 0 14px 4px rgba(130,220,80,0.55), 0 4px 16px rgba(0,0,0,0.30);
      border-color: rgba(150,240,90,0.75);
      opacity: 0.88;
    }
  }

  /* ── トースト（雑多な通知） ── */
  #toast-container {
    position: fixed;
    bottom: 100px; left: 50%; transform: translateX(-50%);
    z-index: 500;
    display: flex; flex-direction: column-reverse; align-items: center; gap: 6px;
    pointer-events: none;
  }
  .toast {
    background: rgba(12,12,12,0.82);
    color: rgba(255,255,255,0.88);
    font-size: 12px;
    letter-spacing: 0.05em;
    padding: 8px 18px;
    border-radius: 20px;
    border: 1px solid rgba(255,255,255,0.10);
    opacity: 0;
    transform: translateY(6px);
    transition: opacity 0.3s, transform 0.3s;
    max-width: min(300px, 80vw);
    text-align: center;
    white-space: normal;
    word-break: keep-all;
    backdrop-filter: blur(8px);
  }
  .toast.show { opacity: 1; transform: translateY(0); }

  /* ── レベルアップ（控えめ版・ゲストの phantom ゲージ用）── */
  .toast.lvup-lite {
    color: #dfffa8;
    border-color: rgba(143,204,94,0.45);
    box-shadow: 0 0 18px rgba(110,168,74,0.28);
    font-weight: 600;
    letter-spacing: 0.06em;
  }
  .lvup-lite-star { color: #b5f055; margin-right: 2px; }

  /* ── レベルアップバナー ── */
  .lvup-banner {
    position: fixed;
    bottom: 150px; left: 50%;
    transform: translateX(-50%) translateY(18px);
    z-index: 700;
    background: linear-gradient(160deg, rgba(16,10,2,0.97) 0%, rgba(34,22,4,0.97) 100%);
    border: 1.5px solid rgba(210,162,22,0.80);
    border-radius: 20px;
    padding: 16px 48px 18px;
    text-align: center;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.45s ease, transform 0.45s cubic-bezier(0.22,1,0.36,1);
    box-shadow: 0 0 60px rgba(210,162,22,0.35), 0 8px 32px rgba(0,0,0,0.70);
    backdrop-filter: blur(4px);
  }
  .lvup-banner.show {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
  .lvup-sub {
    color: rgba(210,162,22,0.75);
    font-size: 9px;
    letter-spacing: 0.22em;
    margin-bottom: 6px;
  }
  .lvup-num {
    color: #fff;
    font-size: 28px;
    font-weight: bold;
    line-height: 1;
    text-shadow: 0 0 28px rgba(210,162,22,0.65);
  }
  .lvup-num span {
    color: rgb(255,210,60);
    font-size: 36px;
  }

  /* ── アイテム入手カード R1-R2（右側） ── */
  #item-notif-container {
    position: fixed;
    top: 70px; right: 14px;
    z-index: 600;
    display: flex; flex-direction: column; gap: 8px;
    pointer-events: none;
    align-items: flex-end;
  }
  .item-notif-card {
    display: flex; align-items: center; gap: 10px;
    padding: 10px 14px 10px 12px;
    border-radius: 14px;
    min-width: 148px; max-width: 210px;
    opacity: 0;
    transform: translateX(16px);
    transition: opacity 0.35s ease, transform 0.35s cubic-bezier(0.22,1,0.36,1);
    backdrop-filter: blur(10px);
  }
  .item-notif-card.show { opacity: 1; transform: translateX(0); }
  .item-notif-card.rarity-1 {
    background: rgba(20,16,12,0.90);
    border: 1px solid rgba(139,115,85,0.50);
  }
  .item-notif-card.rarity-2 {
    background: rgba(8,20,12,0.90);
    border: 1px solid rgba(42,157,80,0.60);
    box-shadow: 0 0 12px rgba(42,157,80,0.18);
  }
  /* ★2026-08-19 新設。中央モーダルの境界を「★3以上」→「★4以上」へ移したため、
     ★3（桜の苗木・溜め波・大波・多重波・静波）がこの右上カードへ降りてくる。
     この定義が無いと背景も枠も無い「透明カード」になって壊れて見える。
     色は★3の青(#2060d0)＝モーダル .item-get-popup.rarity-3 と同じ色域で揃えてある。 */
  .item-notif-card.rarity-3 {
    background: rgba(6,10,28,0.92);
    /* 2026-08-21 第2弾: マスター「★3が地味」→ 枠と静的グローを一段濃く
       （0.72→0.90 / 14px 0.22 → 18px 0.42）。**静的なので毎フレームの再ペイントは無い**。
       ⚠ 静的な box-shadow は1層まで。明滅させるな（2026-07-20「実機で重く即差し戻し」）。 */
    border: 1px solid rgba(32,100,220,0.90);
    box-shadow: 0 0 18px rgba(32,100,220,0.42);
  }
  .inc-icon { font-size: 26px; line-height: 1; flex-shrink: 0; }
  .inc-body { flex: 1; min-width: 0; }
  .inc-label { font-size: 9px; color: rgba(255,255,255,0.42); letter-spacing: 0.12em; margin-bottom: 2px; }
  .inc-name  { font-size: 12px; color: #fff; font-weight: bold; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .inc-stars { font-size: 9px; margin-top: 2px; }

  /* ══ レベルアップ報酬パネル（#lvup-panel / .lvp-*）は 2026-08-22 に全削除 ══════
     マスターの裁可:「アイテムまとめて入手のポップアップのデザインが微妙すぎるので、
     単発のカードを複数出す方式に戻したい」。
     ⇒ ここに在った約190行（#lvup-panel / .lvp-head / .lvp-title(+bump) / .lvp-list /
        .lvp-row(.rarity-1〜6) / .lvp-ic / .lvp-nm / .lvp-qty / .lvp-st / .lvp-more /
        パネル版★3の4層 lvp-ig3-pop / -edge / -sheen / -star / 縦の予算の @media 2本）
        は**要素ごと存在しなくなった**ので削除した。
     ⚠ lvp- も lp- も、この一式の再導入以外に使うな。lp- はログイン誘導オーバーレイ
       (#lp-overlay / #lp-card) が既に使っており、当時 .lp-title が二重定義になって
       「なぜか font-size が効かない」事故を起こしている。
     ★「すごい数のカードが出る」問題への現行の答えは CSS ではなく JS にある:
       game-ui.js の LVUP_CARD_STEP_MS(500ms のずらし出し) / LVUP_CARD_MAX(12) /
       aggregateAwards()(同一 type:subtype を ×N へ集約) / sortByRarityDesc()(★降順)。
       同時に画面へ載る枚数は「カード寿命(3.6s) ÷ 間隔 + 1」で頭打ちになる＝約8枚。
       ⚠ .item-notif-card の寿命（transition 0.4s と game-ui.js の 3200ms）を変えると
         この頭打ちの枚数が変わる。片方だけ動かすな。 */
  /* ══ ★3の華（依頼A）— 一閃(A-1) ＋ ★のキラリ(A-2)。合計 0.9 秒以内 ══════
     ★粒子は使わない。「粒子＝★6」は 2026-08-19 に確立したばかりの識別子で、
       ★3へ降ろすと★6の唯一無二性が薄まる（設計 §8-2）。
     ★要素を1つも増やさない（::after 疑似要素と既存の .inc-stars だけ）。
     ★background-position のスライドは使わない（再ペイントを起こす）。必ず transform。
     ★animation-iteration-count は 1（`1 both`）。ループは禁止＝出しっぱなしにならない。
     ★同時に走る一閃は最大2本（3件以上のバッチではカードが出ないため。設計 §5）。
     ★非常口は JS 側の IG3_SHEEN / IG3_STAR_TWINKLE（false でクラスが付かず丸ごと止まる）。
     ★格差の担保: ★4以上は「画面中央を占有し、他の演出を _igModalBusy で待たせる」。
       ★3は「画面の隅で 0.9 秒光って、誰も待たせない」。程度差ではなくカテゴリ差。 */
  .item-notif-card.ig3-sheen {
    position: relative;
    overflow: hidden;              /* 一閃を角丸の内側で切る。★3のカードにだけ効く */
  }
  /* 2026-08-21 第2弾: 一閃を **0.42/56px → 0.72/92px**（白に近い芯を持つ5停止）へ。
     速さ・回数・動かす property（transform/opacity）は一切変えていない。 */
  .item-notif-card.ig3-sheen::after {
    content: '';
    position: absolute;
    top: -10%; left: 0;
    width: 92px; height: 120%;
    background: linear-gradient(90deg,
      rgba(120,180,255,0) 0%,
      rgba(150,205,255,0.34) 30%,
      rgba(236,246,255,0.72) 50%,
      rgba(150,205,255,0.34) 70%,
      rgba(120,180,255,0) 100%);
    transform: translateX(-110px) skewX(-18deg);
    opacity: 0;
    pointer-events: none;
  }
  /* .show が付いた瞬間（＝入場の起点）に1回だけ走らせる */
  .item-notif-card.ig3-sheen.show::after {
    animation: ig3-sheen 0.6s cubic-bezier(0.33,0,0.2,1) 0.12s 1 both;
  }
  @keyframes ig3-sheen {
    0%   { opacity: 0; transform: translateX(-110px) skewX(-18deg); }
    14%  { opacity: 1; }
    86%  { opacity: 1; }
    100% { opacity: 0; transform: translateX(300px) skewX(-18deg); }
  }
  /* 2026-08-21 第2弾で新設: カードの縁が一度だけ点る（パネル L2 と同じ役）。
     **opacity だけ**を動かす。box-shadow の明滅（★4/★5 のやり方）は使わない——
     あれはコンポジタに乗らず毎フレーム広い面積を塗り直す（2026-08-19 の学び③）。
     ⚠ .item-notif-card.ig3-sheen は overflow:hidden なので、この輪は padding box の内側。 */
  .item-notif-card.ig3-sheen::before {
    content: '';
    position: absolute;
    inset: 0;
    border: 1px solid rgba(196,226,255,0.92);
    border-radius: 13px;
    pointer-events: none;
    opacity: 0;
  }
  .item-notif-card.ig3-sheen.show::before {
    animation: ig3-rim 0.62s ease-out 0.10s 1 both;
  }
  @keyframes ig3-rim {
    0%   { opacity: 0; }
    18%  { opacity: 1; }
    48%  { opacity: 1; }
    100% { opacity: 0; }
  }
  .item-notif-card.ig3-tw .inc-stars { transform-origin: 0% 50%; }
  .item-notif-card.ig3-tw.show .inc-stars {
    animation: ig3-twinkle 0.5s ease-out 0.18s 1 both;
  }
  /* 2026-08-21 第2弾: 跳ねを 1.30→1.48、にじみを 9px→15px。**★の文字1つ**が対象なので
     text-shadow を動かしても塗る面積は極小（パネルの行は最大5本同時なので transform だけ）。 */
  @keyframes ig3-twinkle {
    0%   { transform: scale(1);    text-shadow: none; }
    38%  { transform: scale(1.48); text-shadow: 0 0 15px rgba(150,205,255,1); }
    100% { transform: scale(1);    text-shadow: 0 0 5px rgba(140,195,255,0.48); }
  }

  /* ── アイテム入手モーダル R3-R5（中央） ── */
  .item-get-popup {
    position: fixed;
    left: 50%; top: 50%;
    transform: translate(-50%, -50%) scale(0.80);
    z-index: 650;
    pointer-events: none;
    text-align: center;
    padding: 22px 36px 24px;
    border-radius: 22px;
    min-width: 180px;
    /* ★横スクロールを絶対に出さないための安全網（2026-08-19）。★6 は名前 22px なので
       ja「地獄の業火の波紋」8文字 ≒176px + padding 80px = 256px。320px 幅では収まるが、
       zh/ko の訳語が伸びた時に body が横スクロールするのを構造的に防ぐ。
       普段は min-width(180px) 〜 内容幅で決まるのでこの上限には触れない。 */
    max-width: calc(100vw - 32px);
    opacity: 0;
    transition: opacity 0.4s ease, transform 0.4s cubic-bezier(0.22,1,0.36,1);
  }
  .item-get-popup.show {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
  }
  .item-get-popup.rarity-3 {
    background: rgba(6,10,28,0.97);
    border: 2px solid rgba(32,100,220,0.85);
    box-shadow: 0 0 40px rgba(32,100,220,0.50), 0 8px 32px rgba(0,0,0,0.70);
  }
  .item-get-popup.rarity-4 {
    background: rgba(16,6,28,0.97);
    border: 2px solid rgba(150,50,210,0.90);
    animation: ig-pulse-purple 1.6s ease-in-out infinite;
  }
  .item-get-popup.rarity-5 {
    background: rgba(18,12,2,0.98);
    border: 2px solid rgba(210,162,22,0.95);
    animation: ig-pulse-gold 1.3s ease-in-out infinite;
  }
  @keyframes ig-pulse-purple {
    0%,100% { box-shadow: 0 0 30px rgba(150,50,210,0.55), 0 8px 32px rgba(0,0,0,0.70); }
    50%      { box-shadow: 0 0 65px rgba(150,50,210,0.90), 0 0 100px rgba(150,50,210,0.30); }
  }
  @keyframes ig-pulse-gold {
    0%,100% { box-shadow: 0 0 50px rgba(210,162,22,0.60), 0 8px 32px rgba(0,0,0,0.70); }
    50%      { box-shadow: 0 0 90px rgba(210,162,22,1.0),  0 0 150px rgba(210,162,22,0.40); }
  }

  /* ══════════════════════════════════════════════════════════════════════
     ★6（神話）入手モーダル — 2026-08-19 新設
     ──────────────────────────────────────────────────────────────────────
     【2層構造】お嬢の拘束「一律の虹で塗って業火と世界樹の両方を殺すな」への解。
       外層(格)   = 枠線・回転する光輪・星・スクリーンフラッシュ … **虹で固定**
                    → 「これは★6だ」を語る。2アイテムで完全に同一。
       内層(同一性)= 背景・呼吸グロー・粒子・アイコン後光 … **アイテム固有のアクセント色**
                    → 「これは業火／世界樹だ」を語る。CSS変数3本で切り替える。

     【性能の拘束（この現場の最大の失敗パターンは "実機であからさまに重く即差し戻し"）】
       ★ アニメーションさせてよいのは transform と opacity だけ。
         box-shadow / filter:blur / backdrop-filter は**静的に1回**だけ。
         理由: box-shadow の変化はコンポジタで処理できず毎フレームの再ペイントを起こす。
         現行の ★5 `ig-pulse-gold` はまさにそれをやっている（blur 150px の box-shadow を
         1.3秒周期で書き換え＝広い面積を毎フレーム塗り直している）。
         ★6 はそれを疑似要素の transform/opacity に置き換えたので
         **「★5 より派手なのに★5 より軽い」**が成立している。ここを崩すな。
       ★ 同時に動く要素は最悪 36 個（本体1 + 光輪1 + 呼吸グロー1 + 粒子≤32 + フラッシュ1）。
         すべて合成レイヤで、JS の毎フレーム処理はゼロ。canvas には1命令も足していない。
       ★ 粒子数の非常口は public/game-ui.js の IG6_PARTICLE_COUNT（0 で丸ごと停止）。
     ══════════════════════════════════════════════════════════════════════ */
  .item-get-popup.rarity-6 {
    /* 既定値。未知の★6が将来増えても「白い神々しい枠」で破綻せず出る。 */
    --ig6-accent:   #ffffff;
    --ig6-accent-2: #ffffff;
    --ig6-bg:       rgba(10,8,14,0.985);

    /* 虹枠: 内側=素の背景(padding-box) / 外側=虹(border-box) の二重背景。
       border-color を虹にはできないのでこの二重背景が定石。アニメーションはしない。 */
    border: 3px solid transparent;
    border-radius: 24px;
    padding: 26px 40px 28px;
    /* ★width:max-content が要る理由（2026-08-19 実測）。
       .item-get-popup は position:fixed + left:50% なので、幅 auto の shrink-to-fit が
       使える空き幅は「左端50%から右端まで」＝**ビューポートのちょうど半分**になる。
       （中央寄せの translate(-50%) はレイアウト後に効くので幅計算には関与しない）
       その結果 VW=430 では箱が 215px に潰され、まだ 398px 使えるのに名前が2行に折れた。
       ★これは★6固有の新しい欠陥ではなく**着手前から在る挙動**で、★5でも VW≤430 で
         「月明かりの波紋」が2行に折れる（.bak で実測: 旧213px/新214px＝同値）。
         ★3〜★5 は見た目を1pxも変えない方針なので、ここでは★6だけを直してある。
         全レア度で直すなら .item-get-popup 基本形へ同じ2行を移すこと（別案件）。
       max-width（基本形の calc(100vw - 32px)）が上限として効き続けるので、
       本当に幅が足りない時だけ従来どおり折り返す。 */
    width: max-content;
    background:
      linear-gradient(var(--ig6-bg), var(--ig6-bg)) padding-box,
      var(--rar6-grad) border-box;
    /* ★静的な box-shadow（1回だけ塗る）。keyframe では絶対に動かさない。 */
    box-shadow: 0 0 46px rgba(255,255,255,0.14), 0 10px 40px rgba(0,0,0,0.78);
    /* 光輪と粒子を角丸の内側へ閉じ込める。pointer-events は基本形が none。 */
    overflow: hidden;
    isolation: isolate;
    /* 入場: scale(.72) → 1.04 付近を通って 1 へ収まる overshoot。
       ★keyframe ではなく "行き過ぎる" cubic-bezier で作る。理由: .show を外した時の
         退場が既存の transition 機構のまま素直に効く（animation の forwards fill と
         transition が競合して退場がスナップする事故を構造的に避けられる）。 */
    transform: translate(-50%, -50%) scale(0.72) rotate(-1.5deg);
    transition: opacity 0.55s ease,
                transform 0.55s cubic-bezier(0.34, 1.56, 0.64, 1);
  }
  /* ★ .item-get-popup.show（詳細度 0,2,0）より後ろかつ強い 0,3,0 でなければならない。
       ここを .rarity-6 だけにすると「表示されても scale(0.72) のまま」になる。 */
  .item-get-popup.rarity-6.show {
    transform: translate(-50%, -50%) scale(1) rotate(0deg);
  }

  /* アイテム固有のアクセント（内層）。虹には一切触れない。 */
  .item-get-popup.rarity-6.ig6-gouka {
    --ig6-accent:   #ff3a10;              /* 熾火のオレンジレッド */
    --ig6-accent-2: #ffb03a;              /* 火の粉の黄 */
    --ig6-bg:       rgba(18,3,1,0.985);   /* 焦げた黒 */
  }
  .item-get-popup.rarity-6.ig6-world_tree {
    --ig6-accent:   #7dffb0;              /* 生命の緑 */
    --ig6-accent-2: #ffe89a;              /* 樹冠に射す金 */
    --ig6-bg:       rgba(2,14,8,0.985);   /* 深い森の黒緑 */
  }

  /* 外層: 回転する虹の光輪。transform のみ＝コンポジタ完結（再ペイント無し）。 */
  .item-get-popup.rarity-6::before {
    content: '';
    position: absolute;
    inset: -50%;                 /* 200%角。45°回転しても四隅に穴が空かない */
    z-index: 0;
    pointer-events: none;
    background: conic-gradient(from 0deg,
      #ff5ea8, #ffd15e, #7dffc4, #5ec8ff, #c48bff, #ff5ea8);
    opacity: 0.15;
    will-change: transform;
    animation: ig6-spin 6s linear infinite;
  }
  /* 内層: アクセント色の呼吸グロー。opacity + transform のみ。
     ★5 の box-shadow 明滅の置き換え＝同じ「脈打つ」印象を再ペイント無しで出す。 */
  .item-get-popup.rarity-6::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background: radial-gradient(circle at 50% 58%,
      var(--ig6-accent) 0%, rgba(0,0,0,0) 62%);
    opacity: 0.16;
    will-change: transform, opacity;
    animation: ig6-breathe 2.2s ease-in-out infinite;
  }
  @keyframes ig6-spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
  }
  @keyframes ig6-breathe {
    0%,100% { opacity: 0.14; transform: scale(0.92); }
    50%     { opacity: 0.34; transform: scale(1.06); }
  }

  /* 中身は光輪・グロー(z:0)・粒子(z:1) より前へ */
  .item-get-popup.rarity-6 > div { position: relative; z-index: 2; }

  /* 粒子層。要素はモーダルの子なので el.remove() で必ず道連れに消える（リークしない）。 */
  .item-get-popup.rarity-6 .ig6-particles {
    position: absolute; inset: 0;
    z-index: 1;
    pointer-events: none;
    overflow: hidden;
  }
  .ig6-particle {
    position: absolute;
    bottom: -8px;
    width: 5px; height: 5px;
    border-radius: 50%;
    background: var(--ig6-accent);
    opacity: 0;
    will-change: transform, opacity;
    /* mix-blend-mode は ≤32px の小要素にのみ許可（全画面要素には絶対に掛けない） */
    mix-blend-mode: screen;
    animation: ig6-rise var(--p-dur, 3s) linear var(--p-delay, 0s) infinite;
  }
  .ig6-particle.p2 { background: var(--ig6-accent-2); width: 4px; height: 4px; }
  @keyframes ig6-rise {
    0%   { transform: translate3d(0, 0, 0) scale(var(--p-scale, 1)); opacity: 0; }
    12%  { opacity: 0.95; }
    72%  { opacity: 0.50; }
    100% { transform: translate3d(var(--p-dx, 0px), -210px, 0)
                     scale(calc(var(--p-scale, 1) * 0.35)); opacity: 0; }
  }

  /* 星（外層＝虹）。.rar-6 の本体は下の「レア度の★」節にある。
     モーダル内の .ig-stars は div なので、そのままだとグラデーションが
     モーダル幅いっぱいに引き伸ばされ★6文字には中央の一部しか乗らない。
     inline-block で内容幅に縮めて、虹が★6つの上を端から端まで走るようにする。 */
  .item-get-popup.rarity-6 .ig-stars {
    display: inline-block;
    font-size: 15px;
    letter-spacing: 2px;
    line-height: 1.2;
  }
  /* アイコン（内層＝アクセント色の後光）。filter は静的に1回きり。 */
  .item-get-popup.rarity-6 .ig-icon {
    font-size: 56px;
    filter: drop-shadow(0 0 12px var(--ig6-accent))
            drop-shadow(0 0 28px var(--ig6-accent-2));
  }
  /* 名前。虹グラデーション文字 + アクセント色の text-shadow（設計 §C-3 #8）。
     ★調整ダイヤル: 「業火と世界樹の見分けが付きにくい」と感じたら、下の
       @supports 内の .item-get-popup.rarity-6 .ig-name ブロックを1つ消すだけで
       白文字 + アクセント色グローに戻る（＝アイテム固有色が名前まで届く）。 */
  /* ★ここを display:inline-block + max-width:100% にしてはいけない（2026-08-19 実測）。
       モーダル自身の幅は shrink-to-fit（内容で決まる）なので、その中の inline-block に
       百分率の max-width を与えると幅の計算が循環し、日本語のように**1文字単位で
       改行できる**テキストでは min-content（＝1文字幅）まで潰れる。
       実害: W390 で「地獄の業 / 火の波紋」と語の途中で2行に折れた（横幅には余裕があった）。
       block のままなら背景グラデーションは content box 幅に広がるが、名前は中央寄せで
       箱幅とほぼ一致するため見た目の不利は無い。 */
  .item-get-popup.rarity-6 .ig-name {
    font-size: 22px;
    line-height: 1.25;
    overflow-wrap: anywhere;
    color: #fff;
    text-shadow: 0 0 16px var(--ig6-accent), 0 0 32px var(--ig6-accent-2);
  }
  .item-get-popup.rarity-6 .ig-get-label { letter-spacing: 0.24em; }

  /* ══════════════════════════════════════════════════════════════════════
     シークレットレア（地獄の業火の波紋）2026-08-22
     設計: deliverables/secret-rare-design-20260821.md §C（レイ）
     ──────────────────────────────────────────────────────────────────────
     マスター依頼:「破壊が目的の、ダークな、ジョーカー的な波紋だから、なんか
     怖い感じの演出のレアにしてほしい」＋「★6より格上に見せるな」。

     ★設計原理: 「格」を語る3軸と「異質さ」を語る3軸は別物である、という分解。
        格   （光量・尺・粒子）  … **全部★6より下げる** ⇒ 格上には絶対に見えない
        異質 （色相・運動の向き・記号）… **全部反転させる** ⇒ ★4にも★5にも★6にも似ない
     ★決め手は**暗転**。他の全レア度は画面が明るくなる（★5=金 / ★6=虹のフラッシュ）。
       業火だけ画面が**暗くなる**ので、平均輝度は下がる＝派手さでは★6に確実に負けるのに、
       異質さは全レア度中で最大になる。しかも opacity 1本＝この現場で最も安い演出。
     ★性能: 同時に動く要素は **3個**（本体1＋くすぶり1＋暗転1）。★6の最悪36個、
       ★4/★5 の box-shadow 明滅（毎フレーム再ペイント）より**軽い**。
       transform / opacity のみ・回転ゼロ・粒子ゼロ・box-shadow のアニメーションゼロ。
     ★非常口は public/game-ui.js の IG_SECRET（演出全部）/ IG_SECRET_DARKEN（暗転だけ）。
     ★⚠ `.item-get-popup.rarity-6.ig6-gouka` を絶対に消すな。IG_SECRET=false を引いた時の
       復帰先がそこだ。消すと非常口が「白い既定色の★6モーダル」になる。
     ══════════════════════════════════════════════════════════════════════ */
  /* ★クラスは `item-get-popup ig-secret`。**rarity-6 を併記してはいけない**（設計 §C-5）。
       併記すると transform を上書きする .item-get-popup.rarity-6.ig-secret が (0,3,0) となり
       .item-get-popup.rarity-6.show (0,3,0) と同点になって、CSS の記述順だけで勝敗が決まる。
       負けると「表示されているのに scale(1.14) のまま縮まない」。上の :1154 と同じ罠。
       ig-secret 単独なら (0,2,0)/(0,3,0) と★6と全く同じ階段になり構造的に衝突しない。
     ★クラス名を ig6-secret にしなかったのも意図的。ig6- は「★6の変種」を意味する接頭辞で、
       シークレットは★6に属さない（★の物差しの外にある）という設計意図と逆になる。 */
  .item-get-popup.ig-secret {
    --igs-ember:  #ff3a10;                 /* 熾火のオレンジレッド（アイテム固有色ではない） */
    --igs-char:   #0a0200;                 /* 炭。焼けた縁の暗い側 */
    --igs-bg:     rgba(5,0,0,0.995);       /* ほぼ黒。★6の rgba(10,8,14,0.985) よりさらに暗い */

    /* 焼けた縁。★6と同じ二重背景の定石だが**回転しない**（回る光輪は★6の識別子）。 */
    border: 3px solid transparent;
    border-radius: 24px;
    padding: 30px 46px 32px;
    /* ★width:max-content を落とすな（2026-08-19 実測）。position:fixed + left:50% の
       shrink-to-fit はビューポートの半分しか使えず、VW430 で箱が 215px に潰れて
       「地獄の業 / 火の波紋」と語の途中で2行に折れる。max-width（基本形の
       calc(100vw - 32px)）が上限として効き続けるので、本当に足りない時だけ折り返す。 */
    width: max-content;
    max-width: calc(100vw - 32px);
    background:
      linear-gradient(var(--igs-bg), var(--igs-bg)) padding-box,
      linear-gradient(160deg, var(--igs-char), #8f1405 42%, #ff5a1e 50%, #8f1405 58%, var(--igs-char)) border-box;
    /* ★静的な box-shadow（1回だけ塗る）。keyframe では絶対に動かさない。
       2026-08-24: 熾火の照り返しを広げ、落ちる影を深くした。**値を大きくしただけ**で
       アニメーションはしていないので、再ペイントは表示時の1回きり（性能は変わらない）。 */
    box-shadow: 0 0 96px rgba(255,58,16,0.22), 0 22px 80px rgba(0,0,0,0.94);
    /* くすぶりを角丸の内側へ閉じ込め、blend を親へ漏らさない */
    overflow: hidden;
    isolation: isolate;
    /* ★入場の反転（異質の3軸のひとつ）。全レア度は scale(0.72)→1 の overshoot ＝
       「小さい→大きい・行き過ぎて跳ねる」＝めでたい。
       シークレットは scale(1.14)→1 ＝「大きい→小さい・上から降ってきて沈む」。
       overshoot 無し・rotate 無しの cubic-bezier(0.16,1,0.3,1)（減速のみ）。
       ★keyframe ではなく transition で作る理由は★6と同じ ── .show を外した時の退場が
         既存の transition 機構のまま素直に効く（animation の forwards と競合しない）。 */
    /* 2026-08-24: 落差を 1.14 → 1.34 へ、尺を 0.5s → 0.9s へ。**重い物が上から
       ゆっくり降りて沈む**。★6の 0.72→1 の overshoot（跳ねる＝めでたい）と真逆。
       ⚠ この 0.9s は game-ui.js の IG_SECRET_EXIT_MS と一致していなければならない。
         退場は .show を外して transition で戻すので、退場尺＝この transition 尺。 */
    transform: translate(-50%, -50%) scale(1.34);
    transition: opacity 0.9s ease,
                transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
  }
  /* ★ .item-get-popup.show（0,2,0）より後ろかつ強い (0,3,0) でなければならない。
       ここを .ig-secret だけにすると「表示されても scale(1.14) のまま縮まない」。 */
  .item-get-popup.ig-secret.show {
    transform: translate(-50%, -50%) scale(1);
  }
  /* 内層①: くすぶり（箱の底で燃えている熾火）。
     2026-08-24: **遅く・強く**へ振った(5.2s / .16↔.46 / scale 1.00↔1.09)。
     ★6の「呼吸」(2.2s / .14↔.34)より **明らかに遅い** ＝ 鼓動ではなく燻り。
     速さで競わず遅さで不穏にする、が★6との差の作り方。opacity + transform のみ。
     ★6の ::before に当たる**回転する光輪は今も出さない**（回転は★6の識別子）。 */
  .item-get-popup.ig-secret::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background: radial-gradient(circle at 50% 82%,
      var(--igs-ember) 0%, rgba(140,20,4,0.55) 34%, rgba(0,0,0,0) 64%);
    opacity: 0.16;
    will-change: transform, opacity;
    animation: ig-secret-smolder 5.2s ease-in-out infinite;
  }
  /* ★モーダルの寿命 IG_SECRET_MODAL_MS で el.remove() されると本体の疑似要素なので
     必ず道連れに消える（別要素の粒子と違い、リーク経路が構造的に無い）。 */
  @keyframes ig-secret-smolder {
    0%,100% { opacity: 0.16; transform: translate3d(0,0,0) scale(1.00); }
    50%     { opacity: 0.46; transform: translate3d(0,0,0) scale(1.09); }
  }
  /* 内層②: 煤（すす）の滲み。2026-08-24 新設・非常口 IG_SECRET_SOOT → クラス igs-so。
     ★上端から黒が垂れてきて箱を汚す。**亀裂は描かない** ── 波紋本体の亀裂エフェクトは
       マスターが「亀裂OFF」で確定させた表現なので、そこと混同される形を出さない。
     ★z-index 1 ＝ くすぶり(0) の上・本文(2) の下。文字は必ず読める。
     ★7.5s ＝ くすぶり(5.2s) と割り切れない周期。重なり方が毎回ズレて規則性が見えなくなる。 */
  .item-get-popup.ig-secret.igs-so::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: radial-gradient(ellipse 130% 70% at 50% 0%,
      rgba(0,0,0,0.92) 0%, rgba(10,2,0,0.55) 38%, rgba(0,0,0,0) 72%);
    opacity: 0.40;
    will-change: transform, opacity;
    animation: ig-secret-soot 7.5s ease-in-out infinite;
  }
  @keyframes ig-secret-soot {
    0%,100% { opacity: 0.36; transform: translate3d(0,0,0) scale(1.00); }
    50%     { opacity: 0.72; transform: translate3d(0,-4px,0) scale(1.08); }
  }
  /* 中身はくすぶり(z:0)より前へ。粒子層は存在しない（★6の専売を守る）。 */
  .item-get-popup.ig-secret > div { position: relative; z-index: 2; }

  /* 記号。★を1つも出さず `???`（熾火の赤）。★6の虹の★6つとは色相ごと違う。 */
  .item-get-popup.ig-secret .ig-stars {
    display: inline-block;
    font-size: 19px;
    letter-spacing: 0.35em;
    /* letter-spacing は最後の字の後ろにも入るので、その分だけ左へ戻して光学中心を合わせる */
    margin-right: -0.35em;
    line-height: 1.2;
    font-weight: 700;
    color: var(--igs-ember);
    text-shadow: 0 0 12px rgba(255,58,16,0.55);
  }
  /* アイコン。filter は**静的に1回きり**（keyframe で filter を動かすのは禁止）。
     2026-08-24: 後光を強め、さらに**小刻みに震える**ようにした（非常口 IG_SECRET_SHIVER
     → クラス igs-sv）。動かすのは transform だけ。振れ幅は最大 1.4px ＝ 読めなくならない。
     ★2.9s の中に不規則な刻みを置いてある。等間隔にすると「機械的な振動」に見えて怖くない。 */
  .item-get-popup.ig-secret .ig-icon {
    font-size: 64px;
    filter: drop-shadow(0 0 18px var(--igs-ember)) drop-shadow(0 0 4px rgba(0,0,0,0.9));
  }
  .item-get-popup.ig-secret.igs-sv .ig-icon {
    will-change: transform;
    animation: ig-secret-shiver 2.9s ease-in-out infinite;
  }
  @keyframes ig-secret-shiver {
    0%,100% { transform: translate3d(0, 0, 0); }
    13%     { transform: translate3d(-1.2px,  0.7px, 0); }
    29%     { transform: translate3d( 0.9px, -0.5px, 0); }
    47%     { transform: translate3d(-0.6px, -1.1px, 0); }
    62%     { transform: translate3d( 1.4px,  0.4px, 0); }
    81%     { transform: translate3d(-0.9px,  1.0px, 0); }
  }
  /* 名前は**熾火の赤の単色**。虹は使わない ── 最高格の記号（虹）を渡さないため。
     ★ここを display:inline-block + max-width:100% にしてはいけない（2026-08-19 実測）。
       箱の幅が shrink-to-fit なので幅計算が循環し、日本語は min-content（1文字幅）まで潰れる。 */
  .item-get-popup.ig-secret .ig-name {
    font-size: 25px;
    line-height: 1.25;
    overflow-wrap: anywhere;
    color: var(--igs-ember);
    /* 静的な text-shadow（アニメーションしない）。熾火が名前そのものを焼いている見え方。 */
    text-shadow: 0 0 22px rgba(255,58,16,0.75), 0 0 6px rgba(0,0,0,0.95);
  }
  .item-get-popup.ig-secret .ig-get-label {
    letter-spacing: 0.24em;
    color: rgba(255,150,120,0.42);
  }

  /* ★極狭幅の逃がし（2026-08-24）。名前 22→25px・padding 40→46px と一回り大きくした結果、
     ja「地獄の業火の波紋」(8文字) が 320px 幅で 292px 必要になり、max-width(calc(100vw-32px)
     ＝288px) を 4px だけ超えて**語の途中で2行に折れた**（実測）。
     2026-08-19 に潰したのと同じ折れ方なので、狭い時だけ一回り戻す。
     ⚠ 390px（実機の主戦場）はこの分岐に入らない ＝ 大きいままだ。 */
  @media (max-width: 380px) {
    .item-get-popup.ig-secret          { padding: 26px 30px 28px; }
    .item-get-popup.ig-secret .ig-name { font-size: 21px; }
    .item-get-popup.ig-secret .ig-icon { font-size: 54px; }
  }

  /* ── レア度の★（★6 だけ虹）─────────────────────────────
     game-ui.js の getRarityHtml / _igShowModal / showItemGet は
     `class="rar-stars rar-N"` を出す。★1〜★5 は**インライン style の color** で
     塗られる（従来どおり1pxも変えていない）。
     ★6 だけは JS が color を出さない。理由: インライン style は class より詳細度が
     高く、下の color:transparent を殺してしまうため。
     ★不変条件: game-ui.js の RARITY[6].color は null のままにすること。
       ここに色を書き戻した瞬間、★6の星はマゼンタ単色になり虹が消える。
     フォールバック: @supports の外に単色を先に置いてあるので、background-clip:text
       非対応の環境でも「マゼンタ単色の★6」として読める（透明で消えることはない）。 */
  .rar-6 { color: var(--rar6-solid); }
  /* シークレット（業火）の記号。★を1つも出さず `???` を出す。
     ★色は必ずここ（CSS）が持つこと。game-ui.js の getRarityHtml はインライン style で
       color を出さない ── インライン style は class より詳細度が高く、将来グラデーションに
       したくなった時に詰む（★6で実際に踏んだ罠と同型）。 */
  .rar-secret { color: #ff3a10; font-weight: 700; }
  @supports ((-webkit-background-clip: text) or (background-clip: text)) {
    .rar-6 {
      background: var(--rar6-grad);
      -webkit-background-clip: text;
              background-clip: text;
      color: transparent;
      -webkit-text-fill-color: transparent;
    }
    .item-get-popup.rarity-6 .ig-name {
      background: var(--rar6-grad);
      -webkit-background-clip: text;
              background-clip: text;
      color: transparent;
      -webkit-text-fill-color: transparent;
    }
  }
  .ig-get-label {
    font-size: 9px;
    letter-spacing: 0.20em;
    color: rgba(255,255,255,0.45);
    margin-bottom: 8px;
  }
  .ig-stars { font-size: 12px; letter-spacing: 1px; margin-bottom: 8px; }
  .ig-icon  { font-size: 48px; margin: 4px 0 12px; line-height: 1; }
  .ig-name  { color: #fff; font-size: 17px; font-weight: bold; }
  .item-get-popup.rarity-5 .ig-name { font-size: 20px; text-shadow: 0 0 16px rgba(210,162,22,0.80); }

  /* R5 スクリーンフラッシュ */
  .ig-screen-flash {
    position: fixed; inset: 0;
    background: rgba(255,210,30,0.18);
    z-index: 640; pointer-events: none;
    animation: ig-flash 1.0s ease-out forwards;
  }
  @keyframes ig-flash {
    0%   { opacity: 0; }
    15%  { opacity: 1; }
    100% { opacity: 0; }
  }

  /* ★6 スクリーンフラッシュ（虹・2段: 白い瞬き → 虹の余韻）。
     ★アニメーションするのは opacity ただ1つ。background は静的な放射グラデーション。
       全画面要素なので mix-blend-mode も filter も掛けない（§C-4 禁止事項4）。
     ★実尺 1.6s は game-ui.js の IG6_FLASH_MS と**必ず一致させること**。
       ズレると連発抑止 (_igFlashUntil) に穴が空き、2枚目のフラッシュが重なる。
     ピーク不透明度は中心 0.30（背景側のアルファ）。★5 の一様 0.18 より強いが、
     周縁へ向けて透明に落ちるので画面全体の平均輝度上昇は★5とほぼ同等。 */
  .ig-screen-flash.f6 {
    background: radial-gradient(circle at 50% 50%,
      rgba(255,255,255,0.30)   0%,
      rgba(255, 94,168,0.22)  28%,
      rgba(125,255,196,0.16)  52%,
      rgba( 94,200,255,0.13)  72%,
      rgba(0,0,0,0)          100%);
    animation: ig6-flash 1.6s ease-out forwards;
  }
  @keyframes ig6-flash {
    0%   { opacity: 0;    }
    7%   { opacity: 1;    }   /* 白い瞬き */
    20%  { opacity: 0.40; }
    38%  { opacity: 0.78; }   /* 虹の余韻 */
    100% { opacity: 0;    }
  }

  /* ══ シークレットの全画面ステージ（2026-08-22 新設 → 2026-08-24 大幅強化）══════
     マスター:「禍々しさがかなり抑えられている印象。もっと大幅に大胆に怖い演出に。
                アニメーションも長く時間撮ってOK。」
     ── 何を変えたか ────────────────────────────────────────
       ① 暗転が **主役** になった。0.9s の通過儀礼 → **演出の全長(10.7s)を支配する層**。
          濃度も 中心 0 / 周縁 0.55 → **中心 0.34 / 周縁 0.94**（周縁はほぼ黒）。
       ② この層は **灰と火の粉の親** でもある（子なので親を消せば必ず道連れ＝リーク無し）。
       ③ 箱が着地した瞬間だけ **この層ごと ±4px 揺れて 2.2 秒で収まる**（`.sh`）。
          揺らすのは暗転層＝「世界」であって、本文は1pxも動かない ⇒ 読めるし酔わない。
     ── 性能の拘束（2026-07-20「実機であからさまに重く即差し戻し」の再発防止）────
       動かすのは **transform と opacity だけ**。background は静的な放射グラデーション。
       全画面要素に mix-blend-mode / filter / backdrop-filter は一切掛けない。
     ── JS との同期 ─────────────────────────────────────────
       ★実尺は **game-ui.js から inline の `--igs-dur` で渡ってくる**。CSS 側に尺の
         数値を書かない ＝ 08-22 のような「900ms と 0.9s を人力で一致させる」罠が消えた。
       ★暗転の深さは `--igs-dark-peak`（IG_SECRET_DARK_PEAK）。マスターが実機で
         「暗すぎる」と言ったら**そこだけ落とせば構図はそのまま薄まる**。
       ⚠ keyframe の 11% / 92% は preroll(1200) / exit(900) を全長(10700)で割った比率。
         ダイヤルで尺を大きく変える時はこの2つも見直すこと（多少ズレても壊れはしない）。
     ── 非常口 ──────────────────────────────────────────────
       `.nodark` … IG_SECRET_DARKEN=false。暗さを1ピクセルも塗らない（灰と揺れは残る）。
       `.sh`     … IG_SECRET_TREMOR=true の時だけ付く。無ければ揺れない。
       `.igs-ash`… IG_SECRET_ASH_COUNT=0 なら層ごと生成されない。
     ★z-index は 640 のまま（モーダル 650 の下・#reg-overlay 660 の下）。 */
  .ig-screen-flash.fs {
    /* ★inset を負にして、±4px 揺らしても画面の端に隙間が出ないようにする。 */
    inset: -40px;
    background: none;      /* 暗さは ::before が持つ（この要素は opacity 1 のまま） */
    opacity: 1;
    animation: none;       /* 基本形の ig-flash(1.0s) を明示的に打ち消す */
    overflow: hidden;
  }
  .ig-screen-flash.fs::before {
    content: '';
    position: absolute;
    inset: 0;
    /* 中心も 0.34 沈める。08-22 は中心を透明に抜いていたが、それだと
       「箱のまわりだけ明るい島」が残って支配感が出なかった。箱は z:650 で上に浮くので
       中心を沈めても読めなくならない。 */
    background: radial-gradient(circle at 50% 50%,
      rgba(0,0,0,0.34)   0%,
      rgba(0,0,0,0.52)  34%,
      rgba(6,0,0,0.80)  66%,
      rgba(4,0,0,0.94) 100%);
    opacity: 0;
    will-change: opacity;
    animation: ig-secret-dark var(--igs-dur, 10700ms) linear forwards;
  }
  .ig-screen-flash.fs.nodark::before { display: none; }
  @keyframes ig-secret-dark {
    0%   { opacity: 0; }
    11%  { opacity: var(--igs-dark-peak, 1); }   /* 静寂: preroll をかけて沈む */
    92%  { opacity: var(--igs-dark-peak, 1); }   /* 支配: 沈んだまま居座る */
    100% { opacity: 0; }                          /* 退場: 世界に明るさが戻る */
  }
  /* 着地の微振動。ease-out で 2.2 秒かけて収まる（無限ループではない＝酔わない）。
     ★ transform ただ1つ。この要素は暗転と灰の**親**なので、1本の animation で
       画面全体が揺れているように見える＝要素を増やさずに「大胆さ」を得ている。 */
  .ig-screen-flash.fs.sh {
    will-change: transform;
    animation: ig-secret-tremor 2.2s var(--igs-tremor-delay, 1850ms) ease-out 1 both;
  }
  @keyframes ig-secret-tremor {
    0%   { transform: translate3d( 0,     0,    0); }
    4%   { transform: translate3d(-4px,   3px,  0); }
    9%   { transform: translate3d( 4px,  -2px,  0); }
    15%  { transform: translate3d(-3px,  -3px,  0); }
    22%  { transform: translate3d( 3px,   2px,  0); }
    31%  { transform: translate3d(-2.2px, 1.6px,0); }
    42%  { transform: translate3d( 1.8px,-1.4px,0); }
    56%  { transform: translate3d(-1.2px,-1px,  0); }
    72%  { transform: translate3d( 0.7px, 0.6px,0); }
    100% { transform: translate3d( 0,     0,    0); }
  }

  /* ── 灰と火の粉（2026-08-24 新設）──────────────────────────────
     ★★6の粒子との識別:
        ★6 … 虹の輝き・上へ光る・キラキラ（2026-08-19 に確立した★6の識別子）
        業火 … 熾火色の火の粉が**上へ昇る** ＋ 3粒に1粒は無彩色の灰が**下へ落ちる**。
               色相（赤／無彩色）も向き（両方向）も別物なので、並べれば一目で違う。
     ★上限は game-ui.js の IG_SECRET_ASH_MAX(28)。既定 16。
     ★★6の粒子と同じ「生成時に keyframe を1本割り当てて放置」の型。
       rAF で位置を書き換えない ＝ コンポジタで完結し、再ペイントを起こさない。
     ★フェードは親（暗転）と**独立**させてある。IG_SECRET_DARK_PEAK を落としても
       灰は薄くならない。 */
  .ig-screen-flash.fs .igs-ash {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
    opacity: 0;
    animation: igs-ashfade var(--igs-dur, 10700ms) linear forwards;
  }
  @keyframes igs-ashfade {
    0%   { opacity: 0; }
    12%  { opacity: 1; }
    90%  { opacity: 1; }
    100% { opacity: 0; }
  }
  .ig-screen-flash.fs .igs-p {
    position: absolute;
    bottom: -16px;
    width: 5px; height: 5px;
    border-radius: 50%;
    /* box-shadow を使わずグラデーションで柔らかい点にする（影は再ペイントを呼ぶ） */
    background: radial-gradient(circle,
      rgba(255,170,80,0.95) 0%, rgba(255,58,16,0.55) 42%, rgba(255,58,16,0) 72%);
    opacity: 0;
    will-change: transform, opacity;
    animation: igs-rise var(--a-dur, 7s) linear var(--a-delay, 0s) infinite;
  }
  /* 灰: 上から落ちてくる冷たい無彩色。火の粉と逆向き＝「燃えたあとの残骸」 */
  .ig-screen-flash.fs .igs-p.a2 {
    bottom: auto; top: -16px;
    width: 4px; height: 4px;
    background: radial-gradient(circle,
      rgba(196,188,182,0.72) 0%, rgba(118,110,106,0.34) 50%, rgba(0,0,0,0) 74%);
    animation-name: igs-fall;
  }
  @keyframes igs-rise {
    0%   { opacity: 0;    transform: translate3d(0, 0, 0) scale(var(--a-scale, 1)); }
    9%   { opacity: 0.92; }
    68%  { opacity: 0.50; }
    100% { opacity: 0;    transform: translate3d(var(--a-dx, 0), -82vh, 0) scale(calc(var(--a-scale, 1) * 0.45)); }
  }
  @keyframes igs-fall {
    0%   { opacity: 0;    transform: translate3d(0, 0, 0) scale(var(--a-scale, 1)); }
    11%  { opacity: 0.55; }
    74%  { opacity: 0.32; }
    100% { opacity: 0;    transform: translate3d(var(--a-dx, 0), 88vh, 0) scale(calc(var(--a-scale, 1) * 0.8)); }
  }

  /* ── login prompt ── */
  #lp-overlay {
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.25);
    z-index: 400;
    display: flex; align-items: center; justify-content: center;
    opacity: 0; pointer-events: none;
    transition: opacity 0.22s;
  }
  #lp-overlay.open { opacity: 1; pointer-events: auto; }

  #lp-card {
    background: #fff;
    border-radius: 18px;
    box-shadow: 0 8px 40px rgba(0,0,0,0.14), 0 2px 8px rgba(0,0,0,0.07);
    padding: 36px 32px 28px;
    width: 320px;
    text-align: center;
    transform: translateY(16px) scale(0.96);
    transition: transform 0.26s cubic-bezier(0.34,1.56,0.64,1);
  }
  #lp-overlay.open #lp-card { transform: translateY(0) scale(1); }

  /* ロゴマーク（ヘッダーの #brand-logo en 波紋ロゴを流用）── 絵文字アイコンの置き換え。
     「en」の文字は出さず、波紋(circle)が広がるアニメーションのみの円形ロゴ。 */
  .lp-logo {
    display: block;
    width: 84px;
    margin: 2px auto 18px;
    overflow: hidden;
  }
  .lp-logo svg { display: block; width: 100%; height: auto; }
  .lp-title {
    font-size: 16px;
    font-weight: 500;
    letter-spacing: 0.04em;
    color: #1a1a1a;
    margin-bottom: 10px;
  }
  .lp-body {
    font-size: 12.5px;
    color: rgba(0,0,0,0.5);
    line-height: 1.85;
    letter-spacing: 0.03em;
    margin-bottom: 18px;
  }
  /* 安心感の注記（完全無料・個人情報不要）── くどくならないよう小さく添える */
  .lp-note {
    font-size: 11px;
    color: rgba(0,0,0,0.36);
    line-height: 1.65;
    letter-spacing: 0.02em;
    margin-bottom: 22px;
  }
  .lp-btn-login {
    display: block;
    background: #1a1a1a;
    color: #fff;
    border: none;
    border-radius: 8px;
    padding: 12px;
    font-size: 13px;
    font-family: inherit;
    letter-spacing: 0.08em;
    cursor: pointer;
    text-decoration: none;
    transition: background 0.15s;
    margin-bottom: 10px;
  }
  .lp-btn-login:hover { background: #333; }
  .lp-btn-close {
    background: none;
    border: none;
    font-family: inherit;
    font-size: 12px;
    color: rgba(0,0,0,0.3);
    cursor: pointer;
    padding: 6px 0;
    letter-spacing: 0.06em;
    transition: color 0.15s;
  }
  .lp-btn-close:hover { color: rgba(0,0,0,0.6); }

  /* ── その場登録モーダル（reg-overlay）── */
  #reg-overlay {
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.32);
    /* 2026-08-20: 600 → 660。木を育て切った1ヒットで ws.js:1022-1024 が
       「登録フォームを開く」と「報酬予告」を同時に走らせるため、★4以上の
       入手モーダル(.item-get-popup=650)とスクリーンフラッシュ(.ig-screen-flash=640)
       が登録フォームの前面に乗り、★6では8.0秒フォームが見えなくなっていた
       （リツの敵対的検証#1・マスター裁可済み）。新規登録ファネルの最重要地点なので
       フォームを前面へ出す。レベルアップバナー(.lvup-banner=700)より下は維持する。
       ⚠ この値を下げ戻す時は上記2つの z-index との大小関係を必ず確認すること。 */
    z-index: 660;
    display: flex; align-items: center; justify-content: center;
    opacity: 0; pointer-events: none;
    transition: opacity 0.22s;
    backdrop-filter: blur(2px);
  }
  #reg-overlay.open { opacity: 1; pointer-events: auto; }
  #reg-card {
    position: relative;
    background: #fff;
    border-radius: 18px;
    box-shadow: 0 8px 44px rgba(0,0,0,0.18), 0 2px 8px rgba(0,0,0,0.08);
    padding: 34px 30px 24px;
    width: 332px; max-width: calc(100vw - 40px);
    text-align: center;
    transform: translateY(16px) scale(0.96);
    transition: transform 0.26s cubic-bezier(0.34,1.56,0.64,1);
  }
  #reg-overlay.open #reg-card { transform: translateY(0) scale(1); }
  .reg-x {
    position: absolute; top: 12px; right: 14px;
    background: none; border: none; cursor: pointer;
    font-size: 15px; color: rgba(0,0,0,0.28); line-height: 1;
    padding: 4px; transition: color 0.15s;
  }
  .reg-x:hover { color: rgba(0,0,0,0.55); }
  /* ロゴマーク（ヘッダーの #brand-logo en 波紋ロゴを流用）── 絵文字🌱の置き換え。
     「en」の文字は出さず、波紋(circle)が広がるアニメーションのみの円形ロゴ。 */
  .reg-logo { display: block; width: 78px; margin: 2px auto 14px; }
  .reg-logo svg { display: block; width: 100%; height: auto; }
  .reg-title {
    font-size: 16px; font-weight: 600; letter-spacing: 0.04em;
    color: #1a1a1a; margin-bottom: 8px;
  }
  .reg-body {
    font-size: 12.5px; color: rgba(0,0,0,0.5); line-height: 1.8;
    letter-spacing: 0.03em; margin-bottom: 18px;
  }
  /* 安心感の注記（完全無料・個人情報不要）── 登録フォームの直前に小さく添える */
  .reg-note {
    font-size: 11px; color: rgba(0,0,0,0.36); line-height: 1.6;
    letter-spacing: 0.02em; margin-bottom: 16px;
  }
  #reg-form { display: flex; flex-direction: column; gap: 10px; }
  .reg-input {
    width: 100%; padding: 11px 13px; box-sizing: border-box;
    background: rgba(0,0,0,0.03);
    border: 1px solid rgba(0,0,0,0.12); border-radius: 9px;
    color: #1a1a1a; font-size: 14px; font-family: inherit; letter-spacing: 0.02em;
    transition: border-color 0.25s, box-shadow 0.25s, background 0.25s;
  }
  .reg-input::placeholder { color: rgba(0,0,0,0.32); }
  .reg-input:focus {
    outline: none; border-color: #6ea84a; background: #fff;
    box-shadow: 0 0 0 3px rgba(110,168,74,0.14);
  }
  .reg-submit {
    margin-top: 4px; width: 100%; padding: 12px;
    background: #1a1a1a; color: #fff; border: none; border-radius: 9px;
    font-size: 14px; font-family: inherit; font-weight: 500;
    letter-spacing: 0.08em; cursor: pointer;
    transition: background 0.15s, transform 0.15s;
  }
  .reg-submit:hover { background: #333; transform: translateY(-1px); }
  .reg-submit:active { transform: translateY(0); }
  .reg-submit:disabled { opacity: 0.5; cursor: default; transform: none; }
  .reg-error {
    color: #c14a3d; font-size: 12px; min-height: 16px;
    letter-spacing: 0.02em; text-align: center;
  }
  .reg-foot {
    margin-top: 18px; font-size: 12px; color: rgba(0,0,0,0.42);
    letter-spacing: 0.03em;
  }
  .reg-link {
    color: #1a1a1a; text-decoration: none;
    border-bottom: 1px solid rgba(0,0,0,0.25); padding-bottom: 1px;
    transition: border-color 0.15s;
  }
  .reg-link:hover { border-color: #1a1a1a; }
  #reg-card .lp-btn-close { margin-top: 6px; }

  /* ── mypage drawer (dark theme) ── */
  #mp-overlay {
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.45);
    z-index: 300;
    opacity: 0; pointer-events: none;
    transition: opacity 0.22s;
  }
  #mp-overlay.open { opacity: 1; pointer-events: auto; }

  #mp-drawer {
    position: fixed;
    top: 0; right: 0;
    width: 340px; max-width: 100vw;
    height: 100vh;
    background: #19140f;
    z-index: 301;
    transform: translateX(100%);
    transition: transform 0.26s cubic-bezier(0.4,0,0.2,1);
    display: flex; flex-direction: column;
    box-shadow: -4px 0 32px rgba(0,0,0,0.55);
  }
  #mp-drawer.open { transform: translateX(0); }

  .mp-head {
    background: #1e1810;
    border-bottom: 1px solid rgba(255,255,255,0.07);
    padding: 14px 18px;
    display: flex; align-items: center;
    flex-shrink: 0;
    position: sticky; top: 0;
  }
  .mp-head-title { font-size: 12px; letter-spacing: 0.12em; color: rgba(255,255,255,0.28); }
  .mp-close-btn {
    margin-left: auto;
    width: 26px; height: 26px;
    background: none; border: none; cursor: pointer;
    color: rgba(255,255,255,0.30); font-size: 16px;
    border-radius: 6px; line-height: 1;
    transition: background 0.12s, color 0.12s; font-family: inherit;
    display: flex; align-items: center; justify-content: center;
  }
  .mp-close-btn:hover { background: rgba(255,255,255,0.08); color: rgba(255,255,255,0.65); }

  .mp-body { padding: 16px 14px 40px; overflow-y: auto; flex: 1; }

  .mp-card {
    background: #201b13;
    border-radius: 10px;
    box-shadow: 0 1px 6px rgba(0,0,0,0.40);
    margin-bottom: 14px;
    overflow: hidden;
  }
  .mp-card-hd {
    padding: 10px 14px 8px;
    font-size: 10px; letter-spacing: 0.12em;
    color: rgba(255,255,255,0.27); text-transform: uppercase;
    border-bottom: 1px solid rgba(255,255,255,0.05);
  }
  .mp-profile {
    padding: 14px;
    display: flex; align-items: center; gap: 10px;
  }
  .mp-dot {
    width: 28px; height: 28px; border-radius: 50%;
    border: 2px solid rgba(255,255,255,0.08); flex-shrink: 0;
  }
  .mp-uname { font-size: 15px; color: #f1ead8; }
  .mp-logout-btn {
    margin-left: auto; font-size: 11px; color: rgba(255,255,255,0.35);
    background: none; border: 1.5px solid rgba(255,255,255,0.14);
    border-radius: 6px; padding: 5px 10px; cursor: pointer;
    font-family: inherit; letter-spacing: 0.04em;
    transition: border-color 0.15s, color 0.15s;
  }
  .mp-logout-btn:hover { border-color: rgba(255,255,255,0.35); color: rgba(255,255,255,0.65); }

  .mp-item-row {
    padding: 11px 14px;
    display: flex; align-items: center; gap: 9px;
    border-bottom: 1px solid rgba(255,255,255,0.05);
    transition: background 0.1s;
  }
  .mp-item-row:last-child { border-bottom: none; }
  .mp-item-row.equipped { background: rgba(100,150,255,0.10); }

  .mp-iicon {
    width: 30px; height: 30px; border-radius: 7px;
    background: rgba(255,255,255,0.06);
    display: flex; align-items: center; justify-content: center;
    font-size: 15px; flex-shrink: 0;
  }
  /* PNG shrine item icons — サイズはコンテナに合わせてオーバーライド */
  .item-png-icon {
    display: inline-block;
    width: 1.2em; height: 1.2em;
    object-fit: contain;
    vertical-align: middle;
    image-rendering: auto;
  }
  .mp-iicon .item-png-icon    { width: 100%; height: 100%; border-radius: 5px; }
  .ig-icon  .item-png-icon    { width: 1em;  height: 1em; }
  .mp-iinfo { flex: 1; min-width: 0; }
  .mp-iname { font-size: 13px; color: #f0e8d8; display: flex; align-items: center; gap: 5px; }
  /* 名前(.mp-iname-text)だけを縮小・省略対象にする。レア度/×個数/装備中バッジは
     幅が足りないと1文字ずつ縦に潰れて折り返されてしまう（flex子+CJKテキストの典型症状）ため、
     nowrap+flex-shrink:0で常に横一列を維持し、はみ出す分は名前側の省略記号に肩代わりさせる。 */
  .mp-iname-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
  .mp-iname > span:not(.mp-iname-text) { flex-shrink: 0; white-space: nowrap; }
  .mp-ibadge {
    font-size: 9px; letter-spacing: 0.05em; color: #e07060;
    background: rgba(193,74,61,0.22); padding: 2px 6px; border-radius: 20px;
    white-space: nowrap; flex-shrink: 0;
  }
  .mp-icount {
    font-size: 11px; color: rgba(255,255,255,0.38); letter-spacing: 0.02em;
    white-space: nowrap; flex-shrink: 0;
  }
  .mp-idesc { font-size: 11px; color: rgba(255,255,255,0.30); margin-top: 2px; }

  .mp-iacts { display: flex; gap: 4px; flex-shrink: 0; }
  .mp-ibtn {
    font-size: 11px; font-family: inherit; padding: 5px 9px;
    border-radius: 6px; cursor: pointer; letter-spacing: 0.03em;
    transition: background 0.12s, border-color 0.12s, color 0.12s;
  }
  .mp-ibtn-eq  { background:#e8dfc8; color:#16100a; border:1.5px solid transparent; }
  .mp-ibtn-eq:hover { background:#f0e8d0; }
  .mp-ibtn-ueq { background:none; color:rgba(255,255,255,0.42); border:1.5px solid rgba(255,255,255,0.15); }
  .mp-ibtn-ueq:hover { border-color:rgba(255,255,255,0.35); color:rgba(255,255,255,0.70); }

  .mp-empty { padding:24px 14px; text-align:center; color:rgba(255,255,255,0.22); font-size:12px; }
  /* i18n(2026-08-15 ハルト・芽衣裁定): mypage.empty.favorites の辞書値からインライン
     style="opacity:.6" を追い出すためのCSS化。辞書に属性付きタグを残さない
     （i18n.jsのHTML許可タグ判定をホワイトリスト＝属性ゼロの完全形のみに厳格化した
     対になる修正。他に small 要素の競合ルールが無いことを確認済み）。 */
  .mp-empty small { opacity:.6; }

  /* ── お気に入りの場所リスト ── */
  .mp-fav-row {
    padding: 10px 14px;
    display: flex; align-items: center; gap: 8px;
    border-bottom: 1px solid rgba(255,255,255,0.05);
  }
  .mp-fav-row:last-child { border-bottom: none; }
  .mp-fav-coord {
    background: none; border: none; cursor: pointer;
    display: flex; align-items: center; gap: 5px;
    color: #e8d8c0; font-family: inherit; font-size: 13px;
    padding: 0; font-variant-numeric: tabular-nums;
    flex: 1; min-width: 0; text-align: left;
    transition: color 0.12s;
  }
  .mp-fav-coord:hover { color: #f5ead4; }
  /* ★2026-08-22: .mp-fav-icon（絵文字 U+1F4CD のピン）は削除した。マスター依頼4。
     錠前と違い**代替を描いていない**のは、この行が「お気に入りの場所」という見出しの
     下にあり、中身が座標 `(x, y)` そのもので、押せばワープするボタンだからだ。
     ピンが無くても意味は1つも失われない。⇒ 対応する CSS ルールもここで消す
     （JS が出さないクラスの定義を残すと「死にルール」の検査に引っかかる）。 */
  .mp-fav-xy { font-size: 13px; letter-spacing: 0.03em; }
  .mp-fav-date { font-size: 10px; color: rgba(255,255,255,0.22); white-space: nowrap; flex-shrink: 0; }
  .mp-fav-del {
    width: 22px; height: 22px; border-radius: 5px;
    background: none; border: none; cursor: pointer;
    color: rgba(220,80,60,0.45); font-size: 12px;
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0; font-family: inherit;
    transition: background 0.12s, color 0.12s;
    padding: 0;
  }
  .mp-fav-del:hover { background: rgba(220,80,60,0.12); color: rgba(220,80,60,1); }


  /* ── en brand logo ── */
  .en-ripple-h { animation: en-ripple-h 4s linear infinite, en-thin-h 4s linear infinite; }
  .en-rh1 { animation-delay: 0s; }
  .en-rh2 { animation-delay: -2s; }
  @keyframes en-thin-h   { 0% { stroke-width: 1.4; } 100% { stroke-width: 0.4; } }
  @keyframes en-ripple-h { 0% { r: 4; opacity: 0.95; } 100% { r: 48; opacity: 0; } }
  #brand-logo { opacity: 1; line-height: 0; flex-shrink: 0; }
  #brand-logo svg { height: 38px; width: auto; display: block; }

  /* === Tweaks toggle (gear) ===
     Same frosted-glass language as #mypage-tab. Defined in stylesheet
     (not inline) so night-mode rules below can override.              */
  #tweaks-toggle {
    position: fixed;
    top: 12px; right: 130px;
    z-index: 200;
    width: 32px; height: 32px;
    border-radius: 50%;
    background: rgba(255,253,248,0.78);
    border: 1px solid rgba(255,255,255,0.7);
    box-shadow: 0 1px 0 rgba(255,255,255,0.9) inset, 0 4px 14px rgba(40,30,20,0.08);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    color: rgba(0,0,0,0.5);
    transition: background 0.18s, color 0.15s, box-shadow 0.18s;
    font-family: inherit;
    padding: 0;
  }
  #tweaks-toggle:hover {
    background: rgba(255,253,248,0.92);
    color: rgba(0,0,0,0.78);
    box-shadow: 0 1px 0 rgba(255,255,255,0.9) inset, 0 6px 20px rgba(40,30,20,0.12);
  }

  /* === Night-mode chip overrides ===
     Inverts the frosted-glass surfaces so chips remain readable against
     the deep blue paper. Foreground icon/text colors flip to a warm
     off-white. Logo text inverts too.                                  */
  body[data-tod="night"] .nav-tab,
  body[data-tod="night"] #item-hud,
  body[data-tod="night"] #ripple-hud,
  body[data-tod="night"] #exp-hud,
  body[data-tod="night"] #tweaks-toggle {
    background: rgba(40, 50, 70, 0.55);
    border-color: rgba(255,255,255,0.12);
    color: rgba(255,255,255,0.78);
    box-shadow: 0 1px 0 rgba(255,255,255,0.08) inset, 0 4px 16px rgba(0,0,0,0.3);
  }
  body[data-tod="night"] .nav-tab:hover,
  body[data-tod="night"] #tweaks-toggle:hover { background: rgba(50,60,80,0.7); color: rgba(255,255,255,0.95); }
  body[data-tod="night"] #count        { color: rgba(255,255,255,0.55); }
  body[data-tod="night"] .exp-level   { color: rgba(255,255,255,0.55); }
  body[data-tod="night"] .exp-bar-wrap { background: rgba(255,255,255,.15); }
  body[data-tod="night"] .exp-bar-fill { background: linear-gradient(90deg,#7abd52,#a0d96e); box-shadow: 0 0 6px rgba(120,190,80,0.5); }
  body[data-tod="night"] .exp-frac    { color: rgba(255,255,255,.35); }
  body[data-tod="night"] .exp-locked-label { color: rgba(255,255,255,.35); }
  body[data-tod="night"] .exp-lock-icon    { color: rgba(255,255,255,.35); }
  body[data-tod="night"] .exp-phantom-lv  { color: rgba(255,255,255,0.55); }
  body[data-tod="night"] #exp-hud.exp-phantom-earned .exp-phantom-lv { color: #b5f055; }
  body[data-tod="night"] #exp-hud.exp-locked .exp-bar-fill { background: rgba(255,255,255,.15); }
  body[data-tod="night"] #coords {
    background: rgba(25,20,15,0.85);
    border-color: rgba(255,255,255,0.08);
    color: rgba(255,255,255,0.50);
    box-shadow: 0 1px 0 rgba(255,255,255,0.04) inset, 0 3px 10px rgba(0,0,0,0.30);
  }
  body[data-tod="night"] #coords:hover {
    background: rgba(30,25,18,0.92);
    color: rgba(255,255,255,0.72);
  }
  body[data-tod="night"] .coords-pin-icon { color: #e07060; }
  body[data-tod="night"] .coords-add { color: rgba(255,255,255,0.30); }
  body[data-tod="night"] #coords:hover .coords-add { color: #e07060; }
  body[data-tod="night"] .hud-name     { color: rgba(255,255,255,0.85); }
  body[data-tod="night"] #brand-logo svg text,
  body[data-tod="night"] #brand-logo svg circle[stroke="#1a1a1a"],
  body[data-tod="night"] #brand-logo svg line { stroke: #f0e8d8; fill: #f0e8d8; }
  body[data-tod="night"] #brand-logo svg circle[fill="#c14a3d"] { fill: #e08070; }
  body[data-tod="night"] #cursor::before { border-color: rgba(255,255,255,0.55); }
  body[data-tod="night"] #cursor::after  { background: rgba(255,255,255,0.7); }

  /* === Tweaks panel === */
  #tweaks-panel {
    position: fixed;
    top: 60px; right: 18px;
    z-index: 250;
    width: 220px;
    background: rgba(255,253,248,0.92);
    backdrop-filter: blur(14px) saturate(1.1);
    -webkit-backdrop-filter: blur(14px) saturate(1.1);
    border: 1px solid rgba(255,255,255,0.7);
    border-radius: 14px;
    box-shadow: 0 1px 0 rgba(255,255,255,0.9) inset, 0 12px 28px rgba(40,30,20,0.14);
    padding: 14px 14px 12px;
    font-size: 11px;
    letter-spacing: 0.06em;
    color: rgba(0,0,0,0.7);
    display: none;
  }
  #tweaks-panel.open { display: block; }
  #tweaks-panel .tw-title {
    font-size: 10px;
    letter-spacing: 0.18em;
    color: rgba(0,0,0,0.4);
    text-transform: uppercase;
    margin-bottom: 10px;
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
  #tweaks-panel .tw-close {
    background: none; border: none; cursor: pointer;
    color: rgba(0,0,0,0.3); font-size: 14px; line-height: 1;
    padding: 0 4px; font-family: inherit;
  }
  #tweaks-panel .tw-close:hover { color: rgba(0,0,0,0.7); }
  #tweaks-panel .tw-section { margin-bottom: 12px; }
  #tweaks-panel .tw-label {
    font-size: 10px;
    color: rgba(0,0,0,0.45);
    letter-spacing: 0.1em;
    margin-bottom: 6px;
    display: block;
  }
  #tweaks-panel .tw-segment {
    display: flex;
    background: rgba(0,0,0,0.04);
    border-radius: 8px;
    padding: 2px;
    gap: 2px;
  }
  #tweaks-panel .tw-segment button {
    flex: 1;
    background: none;
    border: none;
    padding: 6px 0;
    font-size: 10px;
    font-family: inherit;
    letter-spacing: 0.08em;
    color: rgba(0,0,0,0.5);
    cursor: pointer;
    border-radius: 6px;
    transition: background 0.15s, color 0.15s;
  }
  #tweaks-panel .tw-segment button.on {
    background: rgba(255,255,255,0.95);
    color: rgba(0,0,0,0.85);
    box-shadow: 0 1px 3px rgba(0,0,0,0.06);
  }
  #tweaks-panel input[type="range"] {
    width: 100%;
    accent-color: #c14a3d;
  }
  body[data-tod="night"] #tweaks-panel {
    background: rgba(40,50,70,0.7);
    color: rgba(255,255,255,0.85);
    border-color: rgba(255,255,255,0.12);
  }
  body[data-tod="night"] #tweaks-panel .tw-title,
  body[data-tod="night"] #tweaks-panel .tw-label { color: rgba(255,255,255,0.5); }
  body[data-tod="night"] #tweaks-panel .tw-close { color: rgba(255,255,255,0.35); }
  body[data-tod="night"] #tweaks-panel .tw-close:hover { color: rgba(255,255,255,0.8); }
  body[data-tod="night"] #tweaks-panel .tw-segment { background: rgba(0,0,0,0.25); }
  body[data-tod="night"] #tweaks-panel .tw-segment button { color: rgba(255,255,255,0.55); }
  body[data-tod="night"] #tweaks-panel .tw-segment button.on { background: rgba(255,255,255,0.18); color: #fff; }
  body[data-tod="night"] .hud-link,
  body[data-tod="night"] .hud-btn  { color: rgba(255,255,255,0.3); border-left-color: rgba(255,255,255,0.12); }
  body[data-tod="night"] .hud-link:hover,
  body[data-tod="night"] .hud-btn:hover  { color: rgba(255,255,255,0.7); }
  body[data-tod="night"] .hud-pip   { background: rgba(255,255,255,0.15); }
  body[data-tod="night"] .hud-count { color: rgba(255,255,255,0.35); }

  @media (prefers-reduced-motion: reduce) {
    #bg-canvas { display: none; }

    /* ── ★6 入手演出の低減（2026-08-19）──────────────────────────
       ★6 は回転・呼吸・粒子・強いフラッシュを伴うので、光感受性に配慮して
       「動き」だけを止める。**枠(虹)・星6つ・アイコン・名前・アクセント色は残す**
       ＝★6であることは変わらず伝わり、動かなくなるだけ。 */
    .item-get-popup.rarity-6::before,
    .item-get-popup.rarity-6::after { animation: none; }
    /* 光輪は静止すると帯が偏って見えるので、静止時は薄い一様グローに落とす */
    .item-get-popup.rarity-6::before { opacity: 0.10; }
    .item-get-popup.rarity-6::after  { opacity: 0.22; transform: none; }
    .item-get-popup.rarity-6 .ig6-particles { display: none; }
    /* 入場の overshoot（行き過ぎる bezier）も素直な ease へ落とす */
    .item-get-popup.rarity-6 {
      transform: translate(-50%, -50%) scale(0.94) rotate(0deg);
      transition: opacity 0.35s ease, transform 0.35s ease;
    }
    .ig-screen-flash     { animation-duration: 0.35s; opacity: 0.10; }
    .ig-screen-flash.f6  { animation-duration: 0.35s; opacity: 0.10; }

    /* ── シークレット入手演出の低減（2026-08-22 → 2026-08-24 改訂）──────────
       ★方針は★6・★3と全く同じ:「**動きだけを止め、情報は1つも消さない**」。
         低減設定でも 焼けた縁・`???`・アイコン・熾火の赤の名前・**暗い画面**は残る＝
         「これは異質で禍々しい物だ」は変わらず伝わり、動かなくなるだけ。
       ★2026-08-24 の方針変更: 08-22 は暗転を「0.35s へ短縮＋opacity 0.10」で**実質
         消して**いた。だが暗転はもう演出の主役で、消すと低減設定のユーザーだけ
         「ただの黒い箱」になってしまう。⇒ **アニメーションを完全に外し、静的な暗さを
         演出の全長ぶん置く**。明滅も揺れも無い（＝動きゼロ）が、暗さは伝わる。
         `--igs-dark-rm` は低減時の濃さのダイヤル（既定 0.42・通常時のピークより浅い）。
       ⚠ .item-get-popup.ig-secret / .ig-screen-flash.fs に層を足したら**必ずここへ
         1行足す**こと。書き忘れると低減設定でだけ動きが残る。
       ⚠ ここに並ぶ animation:none は「今ある無限ループを全部数えた結果」だ:
         ①箱::after くすぶり ②箱::before 煤 ③アイコンの震え ④暗転の沈み込み
         ⑤画面の微振動 ⑥灰のフェード ⑦火の粉/灰の粒 ── 計7本。 */
    .item-get-popup.ig-secret::after,
    .item-get-popup.ig-secret.igs-so::before {
      animation: none;
      opacity: 0.20;
      transform: none;
    }
    .item-get-popup.ig-secret.igs-sv .ig-icon { animation: none; transform: none; }
    /* 入場の「沈み込み」も素直な ease へ落とす（縮尺の変化量も 1.34→1.02 に減らす）。
       ⚠ transition を 0.35s へ縮めても JS の IG_SECRET_EXIT_MS(900ms) は変わらない
         ＝「消え終わってから DOM が消える」側にズレるので、途切れては見えない。 */
    .item-get-popup.ig-secret {
      transform: translate(-50%, -50%) scale(1.02);
      transition: opacity 0.35s ease, transform 0.35s ease;
    }
    .ig-screen-flash.fs         { animation: none; transform: none; }
    .ig-screen-flash.fs.sh      { animation: none; transform: none; }
    .ig-screen-flash.fs::before { animation: none; opacity: var(--igs-dark-rm, 0.42); }
    .ig-screen-flash.fs .igs-ash { display: none; animation: none; }
    .ig-screen-flash.fs .igs-p   { animation: none; display: none; }

    /* ── ★3の華 の低減（2026-08-20 / 2026-08-22 パネル廃止に伴い縮小）──────────
       ★方針は★6と同じ:「動きだけを止め、情報は1つも消さない」。
       ★3は一閃とキラリが止まり、★の静的なグローだけが残る＝★3である事は伝わる。
       ⚠ 2026-08-22: ここには #lvup-panel / .lvp-row / .lvp-title の低減指定が5行あったが、
         パネル方式ごと廃止したので削除した（対応する要素もクラスも存在しない）。
       ⚠ .item-notif-card.ig3-* に層を足したら**必ずここへ1行足す**こと。
         書き忘れると低減設定でだけ動きが残る。 */
    .item-notif-card.ig3-sheen::after,
    .item-notif-card.ig3-sheen.show::after { animation: none; opacity: 0; }
    .item-notif-card.ig3-sheen::before,
    .item-notif-card.ig3-sheen.show::before { animation: none; opacity: 0; }
    .item-notif-card.ig3-tw.show .inc-stars {
      animation: none;
      transform: none;
      text-shadow: 0 0 4px rgba(140,195,255,0.40);
    }

    /* ★既存の欠陥（今回のスコープ外・設計書 §E-6 S4）: ★4/★5 の box-shadow 明滅
       (ig-pulse-purple / ig-pulse-gold) は低減設定でも止まらない。止めるなら次の
       1行のコメントを外すだけでよい。マスター判断待ちのため既定では触っていない。
       .item-get-popup.rarity-4, .item-get-popup.rarity-5 { animation: none; }        */
  }

  /* #tagline は #user-bar のなかで唯一の「縮み代」（2026-08-19 残課題A）。
     幅が足りなくなった時に譲るのは装飾であるこのタグラインだけで、
     ロゴ・使い方・言語切替（機能を持つ物）は flex-shrink:0 で守る。
     ellipsis にしてあるのは、削れた時に「壊れた」ではなく「省略された」と
     見えるようにするため。★これが定数に頼らない安全網の本体で、
     下の @media(max-width:760px) は「普段は省略記号すら出さない」ための
     見栄えの調整にすぎない。境目の数字が陳腐化しても、最悪ここで受け止まる。 */
  #tagline {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    position: relative;
    margin-left: 12px;
    padding-left: 12px;
    border-left: 1px solid rgba(26,26,26,0.18);
    font-size: 9px;
    font-family: var(--ui-font);
    font-weight: 300;
    letter-spacing: 0.16em;
    color: rgba(60, 45, 30, 0.38);
    text-shadow: 0 1px 3px rgba(255,255,255,0.5);
    pointer-events: none;
    z-index: 10;
    line-height: 1.6;
    white-space: nowrap;
    user-select: none;
  }
  body[data-tod="night"] #tagline {
    color: rgba(220, 210, 190, 0.28);
    text-shadow: 0 1px 4px rgba(0,0,0,0.6);
    border-left-color: rgba(255,255,255,0.14);
  }
  /* ══════════════════════════════════════════════════════════════════════
     #tagline を消す境目: 480px → 760px（2026-08-19 残課題A ハルト）
     ────────────────────────────────────────────────────────────────────
     [何を測って 760px にしたか — 5言語 × ゲスト/ログインの最悪値]
       タグラインを出したまま左群と右群が触れない下限（群間 12px を確保）:
         en    ログイン  左群 506.5 + 右群 176.0 ⇒ 730.5px  ← 最悪
         en    ゲスト    左群 506.5 + 右群 171.9 ⇒ 726.4px
         ja    ログイン  左群 452.7 + 右群 194.8 ⇒ 695.5px
         zh-CN/TW ログイン                        ⇒ 686.3px
         ko    ログイン                           ⇒ 666.5px
       効いたのは en（タグライン 181.1px ＋ "How to play" 82.4px）。
       760px はここへ 29.5px の余裕を足した値。
     [なぜ余裕をもっと大きく取らないか]
       座標の桁が増えると必要幅は 779.8px（4桁）・793.1px（5桁）まで伸びるが、
       そこまで境目を上げるとノートPC幅でタグラインが消える。上限が無い量に
       定数で追随するのは筋が悪い。**この帯は #tagline の ellipsis に任せる。**
     [この数字が陳腐化したら何が起きるか]
       #tagline が消えた先は #coords-val の ellipsis が受け皿になる（2026-08-19 是正）。
       ※2026-08-19 以前はここに受け皿が無く、桁が伸びると交差に戻っていた。
     ══════════════════════════════════════════════════════════════════════ */
  @media (max-width: 760px) {
    #tagline { display: none; }
    /* ★タグラインが消える＝左群の内部の受け皿が無くなる（2026-08-19 お嬢）。
       ここで min-width を auto（min-content）へ戻し、左群に本当の床を持たせる。
       これが無いと flex は「左群はいくらでも小さくできる」と誤認し、右群へ縮む
       圧力がかからないまま左群の中身だけが箱から溢れて重なる。実測で交差95件の正体。
       床を尊重させれば、足りないぶんは右群の #coords-val の ellipsis が引き受ける。
       [実測 2026-08-19 お嬢] 760条件（5言語×ゲスト/ログイン×幅19×座標4形態、
         座標は最大10桁まで）で交差 95件 → **0件**、右端はみ出し 0件。
       [残差・既知] 320/390px で5桁座標のとき、座標末尾が4〜9px 省略される（600条件中10件）。
         是正前は同条件で6桁から"重なって"いたので、壊れ方が「重なり」→「省略」へ落ちた。
         この幅では物理的に足りないので何かは必ず譲る。譲る順序は
         タグライン → 座標の数字の末尾 → （ボタンは flex-shrink:0 で最後まで守る）。 */
    #user-bar { min-width: auto; }
  }

  /* ══════════════════════════════════════════════════════════════════════
     狭幅モードの境目: 480px → 640px（2026-08-19 残課題A/B ハルト）
     ────────────────────────────────────────────────────────────────────
     [なぜ 480px では足りなかったか]
       480px は「#tagline を消す幅」として置かれた意匠の数字で、上部帯や
       下部HUDが実際に足りなくなる幅とは無関係だった。結果 481px ちょうどから
       全部が原寸に戻り、そこに2つの穴が空いていた。
     [何を測って 640px にしたか — 5言語 × ゲスト/ログインの最悪値]
       ● 残課題A（左群と右群の衝突）… タグラインを消した状態で左右が触れない下限
           座標 "0, 0"            527.4px（en / ログイン）
           座標 "-1234, -5678"    576.7px（en / ログイン）
           座標 "-12345, -67890"  590.0px（en / ログイン）  ← 採用した最悪値
         効いたのは常に en（"How to play" 82.4px ＋ 言語切替 117.3px が最長）。
       ● 残課題B（#count が #exp-hud に潜る）… 衝突しなくなる下限は
           2 × (#exp-hud の右端) + (#count の幅)
         を 5言語 × 到達可能な #exp-hud の3形態で総当たりした最悪が
           611.2px（ko / normal 形態 Lv999 "98765/99999" / #count 103.05px）
         #count 幅は ko の "— 3명 접속 중 —" が最長、#exp-hud は Lv と EXP の
         桁が増えた normal 形態が最長（右端 254.06px）。
         ※ locked 形態は右端 295.81px（ja）でこれより悪いが、updateExpHUD へ
           locked=true を渡す呼び出しが1つも無く**到達不能**なので採らなかった。
           もし将来 locked を使うなら、この境目は 690.3px まで上げる必要がある。
       640px は上の最悪 611.2px に 28.8px の余裕を足した値。
     [この数字が陳腐化したら何が起きるか]
       Aは #hud-toprow（flex）＋ #coords-val の ellipsis が受け止める（2026-08-19 是正。
       それ以前は受け皿が #tagline だけで、消える ≤760px では交差に戻っていた）。
       Bだけは受け皿が無い＝#count が #exp-hud に潜る形で再発する。
       ⇒ #exp-hud の文言や min-width:190px を触ったら、この数字を測り直すこと。
     ══════════════════════════════════════════════════════════════════════ */
  @media (max-width: 640px) {

    /* ── 依頼3(2026-07-13 ハルト): HUDレスポンシブ対応 ──
       #exp-hud(左下)と#item-hud/#ripple-hud(右下)はPC想定の固定pxのみで
       構成されており、狭幅では横方向の占有幅の合計が画面幅を超えて重なる
       （例: 375px幅で exp-hud≈220px + item-hud≈210px は既に画面幅を超える）。
       余白/フォント/最小幅を縮小しつつ、左右それぞれに vw 基準の max-width を
       与えて重なりを避ける。左下/右下という配置自体・世界観（色/質感）は不変。
       item-hud/ripple-hud の bottom 動的切替（20px⇔62px、game-ui.js側でJS制御）
       は高さを変えていないので無調整でそのまま両立する。 */
    #exp-hud {
      left: 8px;
      min-width: 0;
      max-width: calc(56vw - 8px);
      padding: 6px 8px;
      gap: 6px;
      font-size: 11px;
    }
    #exp-hud .exp-bar-wrap { min-width: 32px; }
    #exp-hud .exp-level,
    #exp-hud .exp-phantom-lv { font-size: 11px; }
    #exp-hud .exp-frac { font-size: 10px; }
    #exp-hud .exp-locked-label {
      white-space: normal;
      font-size: 9px;
      line-height: 1.3;
    }

    #item-hud, #ripple-hud {
      right: 8px;
      max-width: calc(40vw - 8px);
      padding: 6px 8px;
      gap: 4px;
      font-size: 11px;
    }
    #item-hud .hud-icon, #ripple-hud .hud-icon { font-size: 14px; flex-shrink: 0; }
    /* 名前だけを可変幅にして省略記号を許可し、アイコン/耐久/カウント/ボタンは
       flex-shrink:0で固定サイズを維持する（CJKテキストのflex縮小対策の定石）。 */
    #item-hud .hud-name, #ripple-hud .hud-name {
      font-size: 11px;
      min-width: 0;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    #item-hud .hud-dur, #item-hud .hud-count,
    #ripple-hud .hud-count { flex-shrink: 0; font-size: 10px; }
    #item-hud .hud-link, #ripple-hud .hud-link,
    #item-hud .hud-btn,  #ripple-hud .hud-btn {
      font-size: 10px;
      padding-left: 6px;
      margin-left: 1px;
      flex-shrink: 0;
      white-space: nowrap;
    }

    /* ── 依頼1(2026-07-14 ハルト): オンライン人数表示(#count)が小画面でHUDに埋もれる対策 ──
       #count は中央下固定(z-index:100)。直上の依頼3対応で#exp-hud(左下)/#item-hud・
       #ripple-hud(右下)が vw 基準で幅広化しており、狭幅では両HUDとも画面中央付近まで
       張り出す上に z-index:200 かつ背景がほぼ不透明のため、#count のテキストが中央で
       HUDの下へ埋もれて見えなくなる（例: 375px幅で#exp-hudは概算8〜210pxまで張り出し、
       画面中央187.5pxを大きく越える。#countは中央揃えなのでこの帯と必ず重なる）。
       文字を縮めるだけでは中央に来る重なり自体は解消しないため、z-index をHUD(200)より
       確実に上げて常に手前に描画されるようにする（pointer-events:noneのままなのでHUD側の
       クリック/タップは一切妨げない）。あわせて文字サイズ/letter-spacingも縮小し、
       重なった際の見た目のうるささを抑える。position(中央下という配置自体)は不変。
       ★2026-08-18 追記: この対処は「手前に描く」だけで重なりを消せていなかった。
         下の依頼①で配置そのものを上部の空き帯へ移し、z-index は既定へ戻した。
         ここに残っている font-size/letter-spacing の縮小だけが今も生きている。 */
    /* ── 2026-08-18 依頼①(ハルト): 「手前に描く」をやめ、空いている帯へ移した ──
       [なぜ z-index:260 では駄目だったか]
         上の対処(2026-07-14)は #count を HUD より手前に描いただけで、重なり自体は
         1mmも消えていない。文字が HUD の上に乗って読みにくいという苦情はそのまま。
       [中央下に空きが無いことの構造的な根拠]
         #exp-hud   … left:8  + max-width:calc(56vw - 8px) ⇒ 右端は最大 0.56W
         #item-hud  … right:8 + max-width:calc(40vw - 8px) ⇒ 左端は最小 0.60W
         ⇒ 中央下に必ず空く帯は 0.04W しかない（W=375px でわずか 15px）。
           #count は5言語で 75〜92px あるので、幅をどう詰めても構造的に入らない。
       ⇒ そこで 2026-08-18 は「上部の空き帯（top:48px）」へ逃がした。
       ★2026-08-19 マスター指摘: **「オンライン数が下にずれている」。**
         top:48px はヘッダ行(y 12〜39)の"下"に独立した2行目として浮いており、
         行の一部に見えなかった。狙いは「2行目に見えないこと」＝同じ視覚的な行に乗せる。

       ══════════════════════════════════════════════════════════════════
       [なぜ top を 48px→20px 前後の定数へ詰めるのではなく、行の子にしたか]
         定数 top で置くと横位置は viewport 中央固定になる。中央に置ける最大幅
           maxCw = 2 × min(中央 − 左群の右端, 右群の左端 − 中央)
         を実測すると、座標が伸びるほど maxCw は縮む:
           座標 "0, 0"              … W=430 で 72.7px（#count は 5言語 65〜75px）
           座標 "-123456, -876543"  … W=480 で **2.2px** / W=390〜450 は **負**
         #coords の桁には clamp が無い（index.html の ?warp=X,Y は parseInt のみ）
         ＝**必要幅が無界**。無界な量に定数で追随するのは原理的に負ける（残課題A で
         #coords{right:94px} を潰したのと同じ罠を、今度は縦位置で埋め直すことになる）。
         ⇒ 幅の按分をブラウザへ返す。#count を #hud-toprow の3番目の flex 子にした。
       [これで何が自動になるか]
         ・縦位置 … align-self:center で行の中心に乗る（**定数ゼロ**。ロゴが 38/22/18px と
                    変わっても、行の高さが変わっても、自分で追随する）
         ・横位置 … justify-content:space-between が左群と右群の"空きの真ん中"へ置く。
                    viewport 中央ではなく**空きの中央**なので、左右が非対称でも偏らない。
         ・重なり … 同じ flex 行に居る以上、交差は起こり得ない（掟A の反省を踏まえ、
                    「この構造が消える条件」も下に書く）
       [壊れ方の設計（掟E）— 譲る順序を flex-shrink で明示する]
         #count(1000) → #user-bar(100・中の #tagline) → #hud-topright(1・座標の末尾)
         幅が足りなくなると **まず #count が省略され、最後に消える**。座標とボタンは
         最後まで守られる。#count は overflow:hidden + text-overflow:ellipsis を
         自分で持つので、min-width:0 が「際限なく縮める」と嘘をついても中身は箱から
         溢れない（掟B/掟C の受け皿を、痩せる本人が持っている形）。
         **重なるくらいなら消える方がマシ**——お嬢の指示どおり。
       [この構造が消える条件（掟A）]
         ・#count が display:none になる経路は無い（textContent の更新のみ）。
         ・#hud-toprow が flex でなくなったら全部壊れる。行の定義を触るなら測り直すこと。
         ・★#count に position / left / right を書き戻すと行から抜けて元の罠へ戻る。
           唯一の例外が上の :152（≥641px 用の position:fixed）で、これは
           **フローから完全に抜ける**ため行の按分に一切影響しない（＝不変条件と両立する）。
       [z-index について]
         親 #hud-toprow が z-index:200 のスタッキング文脈を作るので、#count 自身の
         z-index:100 は文脈内でしか効かない。実害が無いことは確認済み:
         game.css の z-index に 100 と 200 の間の値は1つも無く、#hud-toprow より
         DOM で前に居る要素は #cursor(1000) だけ＝見え方の順序は従来と同値。
       ══════════════════════════════════════════════════════════════════ */
    #count {
      /* 行の子に戻す。top/bottom/left は static では無効になるので打ち消し不要だが、
         transform だけは効き続けるので明示的に消すこと（消し忘れると左へ半分ズレる）。 */
      position: static;
      transform: none;
      align-self: center;
      flex: 0 1000 auto;
      min-width: 0;
      overflow: hidden;
      text-overflow: ellipsis;
      /* マスター指摘②「もっと小さく薄くていい」: 9px/0.14em → 8px/0.10em。
         色は下の夜側で薄める（★index.html は常に夜なので、夜側を直さないと
         画面上は1ミリも変わらない。game-ui.js が body.dataset.tod='night' を無条件代入）。 */
      font-size: 8px;
      letter-spacing: 0.06em;
    }
    /* 昼側（現状 index では到達しないが、対で直しておく＝片側だけ直す事故の予防）。 */
    #count { color: rgba(0,0,0,0.34); }
    /* 夜側＝実際に画面に出る色。0.55 → 0.42。
       これ以上薄くすると月光ハローで空が明るむ帯で読めなくなる（実測は下の注記）。 */
    body[data-tod="night"] #count { color: rgba(255,255,255,0.42); }
  }

  /* ══════════════════════════════════════════════════════════════════════
     ≤440px: ヘッダ行に物理的に入らないので 2行目へ戻す（2026-08-19 ハルト）
     ────────────────────────────────────────────────────────────────────
     [なぜ帯を分けたか — 「入らない幅が必ずある」を測って線を引いた]
       上のブロックで #count を行の3番目の子にすると、狭い所では行の空きを
       食い尽くして省略が始まる。座標 "0, 0"・5言語・ゲスト/ログインの
       320〜640px(10px刻み)で「省略が出た最大の幅」を実測すると:
         en   ログイン … 410px（2px 欠け）  ← 最悪
         zh-CN/zh-TW/ja ログイン・en ゲスト … 400px
         ko   ゲスト/ログイン・ja ゲスト     … 390px
       ⇒ **420px 以上なら1条件も欠けない。** ここを 440px にしたのは
         ① 410 との間に 30px の余裕を持たせるため（座標が1〜2桁伸びても即座には
            欠けない。※ただし桁は無界なので、伸ばし続ければいずれ欠ける＝
            その時は「重なる」ではなく「末尾が省略される」形に落ちる＝掟E）
         ② 440 はこのプロジェクトで既に使っていた境目（〜2026-08-19 まで
            /i18n/lang.css が言語表記の短縮に使っていた値。今日 640 へ移して空いた）。
            新しい数字を発明するより、既に意味を持っていた数字を再利用する。
       [なぜ 390px を諦めたか（マスターへの正直な報告事項）]
         W=390（iPhone 12〜15）はヘッダ行の空きが 62.4〜80.0px しかなく、
         #count は 8px でも 55〜63px 要る。差は 5.8〜17px で、左右の余白(gap 12px×2)
         すら置けない。ロゴ/「使い方」/言語切替のどれかをさらに削らない限り、
         この幅でヘッダ行に載せるのは無理。**「窮屈に載せる」より「2行目で読める」**
         を選んだ（お嬢の指示: 重なる/潰れるくらいなら2行目のままの方がマシ）。
     [これは行の不変条件を壊さない]
       position:fixed はフローから完全に抜けるので、この帯では行は従来どおり
       「#user-bar と #hud-topright の2つ」しか並べない＝残課題A の検証結果
       （交差0・はみ出し0）にも一切影響しない。left/right を"隣の幅の手計算"で
       書いているわけでもない（left:50% は viewport 中央＝隣に依存しない）。
     [なぜ top:48px が安全か]
       12〜39px … ヘッダ行 / 39〜70px … 空き（狭幅で全幅にわたって空く唯一の帯）
       70px〜   … #item-notif-container(top:70px)
       2026-08-18 に実測済みの配置をそのまま据え置いてある（文字サイズ・色だけ更新）。
     ══════════════════════════════════════════════════════════════════════ */
  /* ══════════════════════════════════════════════════════════════════════
     #count が行に載らない最狭帯 → 2行目へ縮退（2026-08-19 お嬢が 440→410 へ是正）
     [なぜ縮退が要るか]
       上の帯では #count を #hud-toprow の3番目の子にして「空きの中央」へ置いている。
       だが左群(ロゴ+使い方+JP)と右群(座標+ボタン)で幅を使い切る帯があり、そこでは
       3つ目が入らない。入れれば ellipsis が働いて**人数の数字そのものが消える**
       ＝情報が失われる。2行目に降ろす方がマシ、という判断。
     [410 の根拠 — 何を測って出した数字か]  ※この数字は下記のとおり 335 へ更新済み
       「切れずに1行に載る最小幅」を5言語×ゲスト/ログインの10通りで二分探索した実測値:
         ja  guest 385 / login 395      en    guest 396 / login **399**  ← 最悪
         zh-CN guest 313 / login 392    zh-TW guest 314 / login 394
         ko  guest 324 / login 386
       最悪 399px（en/ログイン）に余裕 11px を足して **410px** を境にした。
       ★字間を 0.10em→0.06em に詰めたうえでの値。詰める前は最悪 404px だった。
       ★字間をさらに 0.04em・行gapを6pxまで詰めても最悪は 393px までしか下がらない。
         ボトルネックは字間ではなく左右2群の占有幅なので、**iPhone の 390px は
         この手では載らない**。載せるにはロゴ／使い方／言語切替のどれかを削るか、
         文言から装飾のダッシュ「— —」を外す（＝i18n辞書の変更）判断が要る。

     ★2026-08-19 更新（マスター判断でダッシュを外した後の再測定）
       装飾ダッシュ「— —」を辞書から CSS の ::before/::after へ出し、**≤410px で落とす**
       ようにした（下のブロック）。ダッシュは5言語とも約21px を占めており、
       それが 390px で載らない唯一の原因だった。
       落とした状態で「切れずに1行に載る最小幅」を測り直すと:
         ja  guest 312 / login 321     en    guest 321 / login **324** ← 最悪
         zh-CN guest 300 / login 318   zh-TW guest 301 / login 319
         ko  guest 311 / login 313
       最悪 324px に余裕 11px を足して **335px** を縮退の境にした。
       ⇒ iPhone 390px も、360px も、余裕で行に乗る。2行目へ落ちるのは ≤335px だけ。
     ⇒ #count の文言・font-size・左右2群の中身・ダッシュの有無を触ったら測り直すこと。
     ══════════════════════════════════════════════════════════════════════ */
  /* 装飾ダッシュを落とす帯。ここから下は行の幅が本当に足りないので、
     **情報（人数）より先に装飾（ダッシュ）を捨てる**。譲る順序の明示。
     410 の根拠: ダッシュ有りで切れずに載る最小幅の最悪が 399px（en/ログイン）。
     それを下回る帯ではダッシュが載らない原因になるので、ここで外す。 */
  @media (max-width: 410px) {
    #count::before, #count::after { content: none; }
  }

  @media (max-width: 335px) {
    #count {
      position: fixed;
      top: 48px;
      bottom: auto;
      left: 50%;
      transform: translateX(-50%);
      z-index: 100;
      /* fixed は shrink-to-fit なので省略は起きない。上のブロックで付けた
         受け皿を明示的に戻しておく（意図しない切り詰めの予防）。 */
      overflow: visible;
      flex: 0 0 auto;
    }
  }

  /* ══════════════════════════════════════════════════════════════════════
     使い方ページ (/howto) への導線 — 2026-08-12 ハルト
     ────────────────────────────────────────────────────────────────────
     置き場所: #user-bar（左上）内、#tagline の右に置く「独立した兄弟要素」。

     なぜここか（実物を見た上での判断）:
       1) .nav-tab は #login-tab と #mypage-tab が top:12px right:18px を
          "共有" し、ログイン状態でJSがどちらか一方を display させている。
          右上に3つ目を足すと確実に重なる。ゆえに左上へ寄せた。
       2) #tagline は狭幅で display:none になる（2026-08-19 以降 ≤760px）。
          導線を #tagline の"中"に入れるとスマホで丸ごと消えるので、
          必ず兄弟要素にする（下の狭幅ブロックで別途サイズだけ詰める）。
       3) 意味的にも「このサイトは何か」の説明はロゴ/タグライン側の所属で、
          ログイン・マイページ（アカウント操作）とは別の系統。

     #tagline と同じ静かなトーンに揃えるが、こちらは操作できる要素なので
     pointer-events は既定(auto)のまま・hover/focus で下線を出して可触性を示す。
     ══════════════════════════════════════════════════════════════════════ */
  #howto-link {
    position: relative;
    margin-left: 10px;
    padding-left: 12px;
    border-left: 1px solid rgba(26,26,26,0.18);
    font-size: 10px;
    font-family: var(--ui-font);
    font-weight: 300;
    letter-spacing: 0.14em;
    color: rgba(60, 45, 30, 0.52);
    text-decoration: none;
    text-shadow: 0 1px 3px rgba(255,255,255,0.5);
    white-space: nowrap;
    line-height: 1.6;
    z-index: 10;
    /* 2026-08-18 依頼④(ハルト): hover の下線を border-bottom → text-decoration へ移した。
       [根因] border-bottom は「ボーダーボックスの全幅」に引かれる。この要素は
       border-left:1px（区切り線）+ padding-left:12/8/6px を自分自身に載せているので、
       下線がテキストより 13/9/7px ぶん左へ食み出し、区切り線の足元とL字に繋がっていた。
       [対処] text-decoration はインラインボックス（＝テキスト）にしか引かれず padding へ
       伸びない。ゆえに 3つの breakpoint(既定 / ≤480 :1569 / ≤380 :1635) が
       この1箇所で同時に直り、値の二重管理が生まれない。
       [書き方] 常に underline を宣言して色だけ透明↔有色で出し入れする。hover 側で
       `text-decoration: underline` と短縮形を書くと thickness/offset がリセットされうる。
       ※隣の言語切替は「区切りと padding は親(.lang-switch)、下線は子(__trigger)」で
         同じ問題を構造で回避している（/i18n/lang.css :213 / :98）。そちらへ構造を
         揃えるのが代替案だが、今回は DOM を増やさない本案を採った。
       ※右端には letter-spacing 最終字ぶんの余り(0.16〜1.40px)が残るが、これを消すと
         breakpoint ごとの負 margin が要る＝また二重管理になるので許容とする。 */
    text-decoration: underline;
    text-decoration-color: transparent;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
    padding-bottom: 1px;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    transition: color 0.2s, text-decoration-color 0.2s;
  }
  #howto-link:hover {
    color: rgba(60, 45, 30, 0.85);
    text-decoration-color: rgba(60, 45, 30, 0.30);
  }
  #howto-link:focus-visible {
    outline: none;
    color: rgba(60, 45, 30, 0.90);
    text-decoration-color: rgba(193, 74, 61, 0.60);
  }
  body[data-tod="night"] #howto-link {
    color: rgba(220, 210, 190, 0.42);
    text-shadow: 0 1px 4px rgba(0,0,0,0.6);
    border-left-color: rgba(255,255,255,0.14);
  }
  /* ★index.html は常に data-tod="night"（game-ui.js:949 の無条件代入）。
     画面に実際に出るのはこちら。上の昼側だけ直しても1ミリも変わらないので必ず対で直す。 */
  body[data-tod="night"] #howto-link:hover {
    color: rgba(235, 228, 212, 0.85);
    text-decoration-color: rgba(235, 228, 212, 0.35);
  }

  /* i18n(2026-08-15 ハルト): 言語切替UI。#user-bar 直下・#howto-link の右隣の兄弟要素
     （設計 docs/ripple-server/i18n-design.md §6）。#howto-link と同じトーン（透明背景・
     font-size 10px・左の区切り線）をそのまま踏襲し、意匠が浮かないようにする。
     フォントは常に全CJK合成スタック（/i18n/lang.css の --ui-font-all）で、現在の
     言語に関わらず全選択肢が読める。ネイティブ<select>なのでカスタムJS/z-index戦い無し。 */
  #lang-switch {
    position: relative;
    margin-left: 10px;
    padding-left: 12px;
    padding-right: 2px;
    border-left: 1px solid rgba(26,26,26,0.18);
    border-top: none;
    border-right: none;
    border-bottom: none;
    background: transparent;
    appearance: auto;
    font-size: 10px;
    font-weight: 300;
    letter-spacing: 0.06em;
    color: rgba(60, 45, 30, 0.52);
    white-space: nowrap;
    line-height: 1.6;
    z-index: 10;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: color 0.2s;
  }
  #lang-switch:hover,
  #lang-switch:focus-visible {
    color: rgba(60, 45, 30, 0.90);
  }
  body[data-tod="night"] #lang-switch {
    color: rgba(220, 210, 190, 0.42);
    border-left-color: rgba(255,255,255,0.14);
  }
  body[data-tod="night"] #lang-switch:hover,
  body[data-tod="night"] #lang-switch:focus-visible {
    color: rgba(235, 228, 212, 0.85);
  }

  /* 狭幅: #tagline が消えてロゴの直後に来るため、区切り線と間隔を詰める。
     （既存の狭幅ブロックは編集せず、追記のみで完結させる。
       同一メディア・同一詳細度なので後勝ちでこちらが効く。）
     ★2026-08-19: 境目を 480px → 640px（根拠は上の「狭幅モードの境目」の注記）。
       ここだけ 480px に取り残すと 481〜640px で詰めが効かず、A の実測 590.0px を
       満たせなくなる。3つの狭幅ブロックは必ず同じ値に揃えること。 */
  @media (max-width: 640px) {
    #howto-link {
      margin-left: 8px;
      padding-left: 10px;
      font-size: 9px;
      letter-spacing: 0.10em;
    }
    #lang-switch {
      margin-left: 6px;
      padding-left: 8px;
      font-size: 9px;
    }
  }

  /* ══════════════════════════════════════════════════════════════════════
     狭幅（≤640px。2026-08-15 当時は ≤480px）: #user-bar を1行に収めるため、周りを小さくする
     [2026-08-15 依頼② ハルト]
     ────────────────────────────────────────────────────────────────────
     マスター指摘:「レスポンシブ時、言語切替が下に来ているのが気になる」
                  「en のロゴマーク / 使い方 / 位置座標 / ログインボタン /
                    画面の拡大縮小ボタンを小さくしろ」

     【何が起きていたか（実測）】
     左上の #user-bar は fixed で右へ伸び、右上の #coords(right:138px) と
     .nav-tab(right:18px) は fixed で左へ伸びる。狭幅では #tagline が消えるが、
     残る ロゴ(38px高=約74px幅) + 使い方 + 言語切替 が、右から来る2つと
     ぶつかった。前版はこれを flex-wrap で2行に折り返して逃がしていたが、
     マスターの答え（見出しを消し、周りを縮める）の方が良い——**1行のまま収まる**。

     【当時なぜ 480px にしたか / なぜ 2026-08-19 に 640px へ上げたか】
     ★ 2026-08-15 の判断は「#tagline が消える既存の境に揃える」だった。これは
       意匠の都合の数字で、上部帯が実際に足りなくなる幅とは無関係だったため、
       481px ちょうどから原寸に戻る所に穴が空いていた（残課題A/B）。
       現在の 640px は実測から出した値＝上の「狭幅モードの境目」の注記を見ること。
     （以下は 2026-08-15 当時の記録。480px を選んだ理由として残す）
     480px は #tagline が display:none になる当時の境＝このサイトが元から
     「ここから先はスマホ」と決めている線。新しい境を発明せず、そこへ乗せた。
     **481px 以上は1バイトも変わらない**（＝広い画面の見た目は不変。今回の絶対条件）。
     ※ 実測で分かった事: 縮小を ≤440px にして 441〜480px を素のままにすると、
       その帯で #user-bar が #coords へ届いて重なる（en で 39px 超過）。
       **「折り返しをやめる」変更は、折り返していた帯**（前版の flex-wrap:wrap は
       ≤480px だった）**の全域を縮小で受け止めないと、境の内側に穴が空く。**

     【表記の短縮（「日本語 | JP」→「JP」）— 2026-08-19 に ≤440px → ≤640px へ】
     2026-08-15 当時は「縮小さえ効いていれば 441〜480px は全長のままでも収まる
     （実測 gap 8〜69px）。情報は消さずに済むなら消さない」として ≤440px に
     留めていた。だがその "収まる" 判定は左群と右群の衝突しか見ておらず、
     **画面中央の #count** を勘定に入れていなかった。マスター指摘
     「レスポンシブ時は JP だけでいい」を受け、狭幅モードと同じ 640px へ揃えた。
     （実装は /i18n/lang.css の @media (max-width:640px)。根拠はそのファイルの注記）

     【縮小率は「同じ見た目のまま等倍で小さく」を守る】
     色・角丸・影・質感（glass-blur）・配置（左上/右上/右中央）は一切変えない。
     変えるのは寸法だけ。フォントも -1px 刻みで、字が潰れる手前で止めてある。

     【拡大縮小ボタンについて】機能（zoomIn/zoomOut・ZOOM_LEVELS・描画）には
     1バイトも触っていない。CSS の寸法だけ。この現場は過去に地面ズームで実機が
     重くなり差し戻した前科があるので、**描画に関わる物は絶対に触らない**。
     タップ標的は 40px→32px に留めた（それ以下は指で押しづらくなる）。
     ══════════════════════════════════════════════════════════════════════ */
  /* ★2026-08-19: 境目を 480px → 640px（根拠は上の「狭幅モードの境目」の注記）。 */
  @media (max-width: 640px) {
    /* ★ 折り返し禁止。前版の flex-wrap:wrap は廃止した（＝これが依頼②の本体）。
       ここに flex-wrap:wrap を書き戻すと言語切替がまた2行目へ落ちる。 */
    #user-bar {
      flex-wrap: nowrap;
      gap: 5px;
    }
    /* 画面端の余白は行そのものが持つ（残課題A で left/right を #hud-toprow へ集約）。
       ここで #user-bar{left} / #hud-topright{right} を書くと行の外へ出てしまう。 */
    #hud-toprow { left: 12px; right: 12px; }

    /* en のロゴマーク: 38px → 22px（幅は約74px → 約43px） */
    #brand-logo svg { height: 22px; }

    /* 「使い方」: 字間を詰める。en では "How to play" と長くなるのでここが一番効く */
    #howto-link {
      margin-left: 2px;
      padding-left: 8px;
      font-size: 9px;
      letter-spacing: 0.04em;
    }

    /* 言語切替の区切り位置（表記そのものは /i18n/lang.css 側で JP だけになる） */
    #user-bar .lang-switch { margin-left: 0; }

    /* 右上の並び。right は #hud-toprow が持つので gap だけ（残課題A）。 */
    #hud-topright { gap: 6px; }

    /* ログインボタン / マイページボタン（#hud-topright の子・排他表示）*/
    .nav-tab {
      padding: 5px 10px 5px 8px;
      gap: 4px;
      font-size: 10px;
      letter-spacing: 0.05em;
      border-radius: 16px;
    }
    .nav-tab svg { width: 11px; height: 11px; }

    /* 位置座標。旧 right:94px は「ログインボタンの実測幅+4px」の焼き込みで、
       #mypage-tab(ja 5字) が 5.5px 食い込む原因だった。依頼②で削除。 */
    #coords {
      padding: 5px 9px 5px 8px;
      gap: 4px;
      font-size: 10px;
      letter-spacing: 0.02em;
      border-radius: 16px;
    }
    .coords-pin-icon { width: 9px; height: 11px; }
    .coords-add { font-size: 10px; }

    /* 画面の拡大縮小（右中央）。機能は無改造・寸法のみ。 */
    #zoom-hud {
      right: 10px;
      padding: 4px 3px;
      gap: 2px;
      border-radius: 20px;
    }
    #zoom-hud button {
      width: 32px; height: 32px;
      font-size: 17px;
    }
    #zoom-level { font-size: 9px; }
  }

  /* ══════════════════════════════════════════════════════════════════════
     さらに狭い幅（≤380px）: もう一段だけ詰める  [2026-08-15 依頼② ハルト]
     ────────────────────────────────────────────────────────────────────
     【なぜ2段構えにしたか（実測で決めた）】
     上の 440px 段の寸法のままだと、#user-bar の右端と #coords の左端は
       en（"How to play" が最長）で W ≥ 352px までしか離れない。
     つまり 390px は上の段だけで 42px の余裕があり、詰める必要が無い。
     一方 320px は 28px 足りない。**1段で 320px に合わせると、390px の端末まで
     必要のない小ささになる**ので、段を分けた。
     境を 380px にしたのは 375px(iPhone SE2/6/7/8) と 360px(多くのAndroid) を
     こちら側に入れるため——この帯は計算上は入るが余裕が 13〜27px しかなく、
     位置座標が原点から離れて桁が増えると（"-1234, -5678" 等）足りなくなる。
     **余裕の少ない帯は、詰めておく方が安全側。**
     390px(iPhone 12〜15) は上の段のままで、余裕 42px を保つ。

     ★2026-08-19 お嬢: 境を 380 → **387px** へ動かした。意図（390px を大きい段に残す）は不変。
       理由: #count を上部の行の3番目の子にした結果、この段差の**直後だけ**に穴が空いた。
       1px刻みの実測（5言語×ゲスト/ログイン×330〜460px）で、文字が欠けるのは
       **381〜387px のちょうど7pxの帯だけ**（最大7px欠け・en/ログインが最悪。
       他は ja/login 381、zh-CN/login 381、zh-TW/login 381〜383）。
       388px 以上は全条件で欠けない。380px 以下は元から詰めてあるので欠けない。
       ＝「大きい段になった瞬間、#count のぶんだけ足りない」帯。ここを詰め側へ寄せて埋める。
       ★二分探索で下限を出そうとすると**この谷を飛び越える**（段差で単調でないため）。
         私は一度それで 324px という誤った下限を出した。**この種の探索は線形で舐めろ。**
     ══════════════════════════════════════════════════════════════════════ */
  @media (max-width: 387px) {
    #hud-toprow { left: 8px; right: 8px; }
    #user-bar { gap: 3px; }
    #brand-logo svg { height: 18px; }
    #howto-link {
      margin-left: 0;
      padding-left: 6px;
      font-size: 8px;
      letter-spacing: 0.02em;
    }
    #hud-topright { gap: 4px; }
    .nav-tab {
      padding: 4px 7px 4px 6px;
      gap: 2px;
      font-size: 9px;
      letter-spacing: 0.02em;
    }
    .nav-tab svg { width: 10px; height: 10px; }
    /* 旧 right:76px（「ログインボタンの実測幅+4px」の焼き込み）は依頼②で削除。
       #mypage-tab(ja) が 4.9px 食い込んでいた。幅は #hud-topright の flex に任せる。 */
    #coords {
      padding: 4px 7px 4px 6px;
      gap: 2px;
      font-size: 9px;
    }
    .coords-pin-icon { width: 8px; height: 10px; }
    .coords-add { font-size: 9px; }
    #zoom-hud { right: 8px; padding: 3px 3px; }
    #zoom-hud button { width: 30px; height: 30px; font-size: 16px; }
  }
