/*
 * フィードのページの見た目（2026-09-17）
 *
 * 使うページ: /games/:tag（public/games-by-tag.html）と /games（public/games-index.html）。
 * どちらもサーバーの HTML は全員同じで、ブラウザで JS が動いたときだけ public/js/games-by-tag-feed.js が
 * フィードに組み替える（フィードの中身はタグに関係なく全ゲーム: founder「中身は全部ぶちこんでいるフィードでいい」）。
 * 以前は games-by-tag.html の <style> にあった規則をそのまま移した（2 枚に写さないため）。
 * 読み込みは各ページの本体の <style> の後（狭い画面のヘッダーの規則が本体の基本の値に勝つ順番）。
 */

/* ── 安全領域（ノッチ / ホームインジケータ）の変数（PR #907 レビュー B [重大4]・2026-09-20）──────
   /css/game-social.css は var(--safe-bottom, 0px) / var(--page-safe-top, var(--safe-top, 0px)) を
   参照しているが（コメントシートの送信ボタンとゲーム中の上のバー）、この殻には変数の定義が無かった。
   移行前の public/game.html は body で 0 を置き、html.native-app のときだけ env() に差し替えていた
   （game.html の body / html.native-app body）。`/game/<id>` がこの殻に移った時点で定義ごと落ちていて、
   iOS アプリの WebView ではコメントの送信ボタンがホームインジケータの下に潜る。

   CLAUDE.md「ネイティブ差分の書き方」に従い **ベース → native 上書き**の順で持つ:
     ルール 3「env(safe-area-inset-*) は Web でも非ゼロになりうる（iPhone Safari / PWA）。
     値で分けるのではなくセレクタで分ける」—— なので Web は常に 0px。
   WHY `:root` ではなく game-feed-page.css に置くのか（殻のインライン <style> ではなく）:
     殻は 2 枚（games-index.html / games-by-tag.html）あり、写しを作らないため。
     公開ゲームの反応 UI の CSS（game-social.css）は C2 担当で衝突するので触らない。
   --page-safe-* も定義するのは、game-social.css:1104 がそちら経由で読むため（game.html と同じ 2 段）。
   MOBILE-ONLY: html.native-app の印は各殻の <head> の同期スクリプトが付ける。
   cover が無いと iOS の env() は 0 を返すので、同じスクリプトが viewport-fit=cover も足す。 */
:root {
  --safe-top: 0px;
  --safe-bottom: 0px;
  --page-safe-top: var(--safe-top);
  --page-safe-bottom: var(--safe-bottom);
}
html.native-app {
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
}

/* 狭い画面のヘッダーを 1 行に。リンクは折らない（本体の基本の規則に無いページがあるのでここで持つ） */
.header-nav a { white-space: nowrap; }

/* ── フィード化と 2 つの見え方（2026-09-17・計画書 .claude/plans/tag-feed-entry.md §3）──────────────
   サーバーの HTML は全員同じ（見出し・説明・カード・JSON-LD・ページ送り）。ブラウザで JS が動いたときだけ、
   <main> の先頭にフィード（public/js/modules/game-feed.js）を差し込み、画面を 2 つの見え方に分ける:
     フィード（既定）: 白いバー + フィードが画面ちょうど（100dvh）。ページは下へ流れない（一覧を下に積まない）
     一覧（html.tag-view-list）: サーバーが描いたページそのもの（ヘッダー・見出し・説明・タグ・カード・ページ送り・フッター）
   切り替えはバーの「一覧」と一覧の頭の「フィードで遊ぶ」。URL の印は #list（public/js/modules/tag-feed-views.js の WHY）。
   経緯: 以前はフィードの下に一覧を積んでいた → founder「フィードの下に一覧があるのおかしいよね」（2026-09-17）。
   WHY 一覧を見え方の切り替え（タブと同じ）にしてよいのか: 中身は DOM に残り、人が押せる見える操作（バーの「一覧」）で
     いつでも出せる。クローラーには JS 無しの HTML が今までどおり一覧のページとして届き、canonical も変わらない。
   feed-pending: 一覧直後のインラインスクリプトが立てる「これからフィードになる」予告。一覧が一瞬見えてから
     フィードに切り替わるチラつきを消す。#list で来た人は一覧をそのまま見せる。
   feed-on: games-by-tag-feed.js が立てる。最初のページが取れなかったら外して元の一覧に戻す（見え方の規則も全部外れる）。 */

/* ── チラつき止めは「一覧を隠す」ではなく「上に不透明な板を重ねる」（PR #907 レビュー B [重大6]・2026-09-20）──
   以前（2026-09-17〜）はここで .site-header / .main-content > * / .site-footer を visibility: hidden に
   していた。狙い（一覧が一瞬見えてからフィードが被さるのを消す）は正しいが、副作用が 2 つあった:
     1. **SSR の一覧がフィードの JS 一式に人質に取られる**。予告を外すのは 26 本目の JS
        （games-by-tag-feed.js）なので、それが実行されるまでページは 1 ピクセルも描かれない。
        /games・/games/<tag> は検索の着地ページで、LCP がまるごと JS 待ちになっていた。
     2. 隠している間に CSS が壊れる / 予告のスクリプトだけ通って JS が来ない、といった回で
        「白紙のまま」が既定の姿になる（保険の 5 秒に全部を賭ける形）。
   板方式にすると、一覧は**普通のタイミングで描かれたうえで**上を覆われるだけになる。
   ＝ LCP は SSR の中身で決まり、板が出ない回（CSS が届かない・古い版）は一覧がそのまま使える（fail-open）。
   見え方は今までと同じ（人には白い板しか見えない）ので、founder の画面に出る差は無い。

   保険の 5 秒について（レビュー B が「JS 側の 8 秒とずれている」と読んだ点の訂正）:
     games-by-tag-feed.js は**走り出した瞬間に同期で** feed-pending を外して feed-on を立てる
     （同ファイル「html.classList.remove('feed-pending')」）。最初のページの取得（FIRST_PAGE_TIMEOUT_MS
     = 8 秒）を待つのは feed-on になった**後**なので、この 5 秒と競合しない。
     この 5 秒が効くのは「JS が 5 秒たっても走り出さない（読めていない・落ちた）」回だけで、
     そのときに一覧を返すのは正しい。2 つは別々の失敗に対する別々の期限なので、1 つの値には揃えない。 */
.feed-cover { display: none; }
html.feed-pending:not(.tag-view-list) .feed-cover {
  display: block;
  position: fixed;
  inset: 0;
  /* 舞台 5 / レール 6 / 掴み帯 7 / バー 8 より上、シート（--tl-z-sheet 2110）より下。
     一覧の上にしか出ないので、フィードの部品と重なることはない（feed-on で display:none に戻る） */
  z-index: 2000;
  background: #fff;
  /* JS が走り出さなかった回の保険。visibility なので押せるものも一緒に消える（透明な板を残さない） */
  animation: feed-cover-failsafe 0s linear 5s forwards;
}
@keyframes feed-cover-failsafe { to { visibility: hidden; } }
/* ゲストブックの「遊びに行く」から来た回（html.feed-from-person = games-index.html の予告が ?creator= を見て立てる）。
   板をフィードと同じ見た目（上 44px の白いバー + 暗い舞台 #0D0D0F）にして、ゲストブック側の移り変わり
   （public/js/modules/guestbook-visitor-sheet.js の .gb-go）から白い画面を挟まずにつなぐ。2026-09-25 */
html.feed-pending.feed-from-person:not(.tag-view-list) .feed-cover { background: linear-gradient(#fff 0 44px, #0D0D0F 44px); }
/* ゲストブックから引き継いだ札（games-index.html の予告が組む #dcGoHandoff）。見た目はゲストブック側の移り変わり
   （guestbook-visitor-sheet.js の .gb-go の「伸び切った後」）と同じにする = 画面が切り替わっても絵が動かない。
   値を変えるときは両方。フィードの 1 本目が出たら games-by-tag-feed.js がフェードで外す */
.dc-go-handoff { position: fixed; inset: 0; z-index: 2600; background: #0D0D0F; transition: opacity .18s ease; }
.dc-go-handoff.is-leaving { opacity: 0; pointer-events: none; }
.dc-go-handoff-bar { position: absolute; left: 0; right: 0; top: 0; height: 44px; background: #fff; }
.dc-go-handoff-stage { position: absolute; top: 52px; overflow: hidden; border-radius: 14px; background: #16161A; }
.dc-go-handoff-stage > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.dc-go-handoff-shine { position: absolute; inset: 0; background: linear-gradient(105deg, transparent 35%, rgba(255,255,255,.22) 50%, transparent 65%); transform: translateX(-120%); animation: dcGoShine 1.3s ease-in-out infinite; }
@keyframes dcGoShine { to { transform: translateX(120%); } }
.dc-go-handoff-cap { position: absolute; left: 16px; right: 16px; bottom: 20px; color: #fff; text-shadow: 0 1px 6px rgba(0,0,0,.45); }
.dc-go-handoff-who { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 700; margin-bottom: 6px; }
.dc-go-handoff-face { width: 24px; height: 24px; border-radius: 50%; overflow: hidden; background: #2a2a30; display: flex; align-items: center; justify-content: center; font-size: 13px; }
.dc-go-handoff-face img { width: 100%; height: 100%; object-fit: cover; }
.dc-go-handoff-title { font-size: 19px; font-weight: 800; line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dc-go-handoff-pill { position: absolute; left: 50%; bottom: calc(16px + env(safe-area-inset-bottom, 0px)); transform: translateX(-50%); display: flex; align-items: center; gap: 10px; padding: 10px 18px; border-radius: 999px; background: rgba(255,255,255,.12); color: #fff; font-size: 13px; font-weight: 700; white-space: nowrap; }
.dc-go-handoff-dots { display: flex; gap: 4px; }
.dc-go-handoff-dots i { width: 6px; height: 6px; border-radius: 50%; background: #fff; animation: dcGoDot 1s ease-in-out infinite; }
.dc-go-handoff-dots i:nth-child(2) { animation-delay: .15s; } .dc-go-handoff-dots i:nth-child(3) { animation-delay: .3s; }
@keyframes dcGoDot { 0%, 80%, 100% { transform: translateY(0); opacity: .45; } 40% { transform: translateY(-5px); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .dc-go-handoff-shine, .dc-go-handoff-dots i { animation: none; } .dc-go-handoff { transition: none; } }
.tag-list-play { display: none; }

/* フィードの見え方: ヘッダー・一覧の中身・フッターは退き、フィードの器だけ。ページ自体を動かさない
   （iframe の上の縦スワイプがページのスクロールに連鎖してゲームが止まるのも、これで起きない） */
html.feed-on:not(.tag-view-list), html.feed-on:not(.tag-view-list) body { overflow: hidden; overscroll-behavior: none; }
html.feed-on:not(.tag-view-list) .site-header,
html.feed-on:not(.tag-view-list) .site-footer,
html.feed-on:not(.tag-view-list) .main-content > :not(.tag-feed) { display: none; }
html.feed-on:not(.tag-view-list) .main-content { max-width: none; padding: 0; }
/* フィードの器: 画面の高さちょうど（dvh はアドレスバーの伸び縮みに追従。解釈しないブラウザは vh）。
   スマホは端から端まで、PC はスマホ幅の列を残りの幅の中央に（左の常設サイドバーは body の左の余白: tag-page-nav.js） */
.tag-feed { position: relative; width: 100%; max-width: 480px; margin: 0 auto; height: 100vh; height: 100dvh; overflow: hidden; }

/* 一覧の見え方: 今までの一覧のページ。フィードの器は画面の同じ位置に**見えないまま**残す。
   WHY display:none にしないのか: フィードは「画面に見えていない」と判定するとゲームを外してセッションを閉じる
   （game-feed.js の visibilityObserver）。一覧の間は一時停止（pause('list_view')）で、戻ったら続きから遊べるようにする */
html.feed-on.tag-view-list .tag-feed {
  position: fixed; top: 0; left: 0; right: 0; margin: 0 auto;
  visibility: hidden; pointer-events: none; z-index: -1;
}
/* 一覧の頭の「フィードで遊ぶ」。ブランドの赤の丸い押しボタン（太い枠・硬い影なし）。
   色は var(--red, #FF3B30)（PR #907 レビュー B [中18]・2026-09-20）: WEBLOX は
   /css/brands/weblox.css が --red を青に上書きする。ベタ書きだとここだけ DreamCore の赤で出る。 */
html.feed-on.tag-view-list .tag-list-play {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 0 20px; margin: 0 0 20px;
  border: 0; border-radius: 9999px; background: var(--red, #FF3B30); color: #fff;
  font: inherit; font-size: 15px; font-weight: 700; cursor: pointer;
}
html.feed-on.tag-view-list .tag-list-play:focus-visible { outline: 2px solid #171717; outline-offset: 2px; }

/* ── ゲームへの反応（2026-09-17・タイムラインの動画タブと同じ UI）────────────────
   部品の見た目は /css/game-social.css。ここはフィードの枠の中での置き場所だけ:
   表紙のとき = 右下に縦のレール（題名・作者は左下）/ ゲームが表に出たら = フィードの上の 1 本のバー（題名 + 行動・下）。
   遊んでいる間にレールをゲームの上に残すと、ゲーム自身の右側の操作を塞ぐ（タイムラインで実際に起きた）。
   z-index: 舞台 5 < レール・バー 6 < 下の掴み帯 7 < スワイプの案内 9。シートは画面全体の上（--tl-z-sheet）。 */
.dcf-chrome { position: absolute; inset: 0; z-index: 6; pointer-events: none; }
.dcf-chrome .tl-reel-rail { pointer-events: auto; }
.dcf-chrome .tl-reel-rail { right: 16px; bottom: calc(var(--dcf-strip) + 20px); z-index: auto; }
.dcf-item.is-revealed .dcf-chrome .tl-reel-rail { display: none; }
.tag-feed.dcf-social-off .dcf-chrome { display: none; }

/* フィードの上の 1 本のバー（中身は games-by-tag-feed.js）。表紙でもゲーム中でも同じ高さ・同じ位置。
   経緯: 最初は暗い半透明で作ったが、founder「ヘッダーは DreamCore らしく、白いほうが良くない？」（2026-09-17）で白へ。
   色はこのページのサイトヘッダー（白地・下に 1px の線）と、タイムラインのゲーム中の白い上のバー
   （/css/game-social.css のゲーム中の上のバー = --tl-surface の地 + --tl-hairline-strong の線 + --tl-surface-sunk の丸ボタン）の
   トークンをそのまま引く。game-social.css は非同期で読むので、届く前の 1 コマ用に同じ値をフォールバックに書く。
   --tag-feed-bar-h: 44px = 36px の丸いボタン + 上下 4px（押せる大きさを保つ最小）。
   安全領域（ノッチ）はバーの**内側**の余白で吸う（白い地がノッチの下まで伸びる）。フィードの舞台は --dcf-top-inset で下げる。
   DreamCore の作法: 太い枠・硬い影は付けない。暗いフィードとの境はサイトヘッダーと同じ 1px の線だけ。
   z-index 8: 部品の中の要素（舞台 5 < レール 6 < 掴み帯 7）より上、シート（--tl-z-sheet 2110）より下。 */
.tag-feed {
  --tag-feed-bar-h: 44px;
  --dcf-top-inset: calc(var(--tag-feed-bar-h) + env(safe-area-inset-top, 0px));
}
.tag-feed-bar {
  position: absolute; left: 0; right: 0; top: 0; z-index: 8;
  height: var(--dcf-top-inset);
  padding: env(safe-area-inset-top, 0px) 12px 0;
  display: flex; align-items: center; gap: 10px;
  background: var(--tl-surface, #FFFFFF);
  border-bottom: 1px solid var(--tl-hairline-strong, #E5E5E5);
  color: var(--tl-ink, #171717);
}
/* バーの「一覧」: 格子の印 + 短い文字の丸いボタン（右の行動ボタンと同じ窪みの灰）。ゲーム中は題名の幅を残すため印だけ */
.tag-feed-list {
  flex: none; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 36px; padding: 0 12px 0 10px; border-radius: 9999px;
  background: var(--tl-surface-sunk, #F5F5F5); color: var(--tl-ink, #171717);
  font-size: 13px; font-weight: 700; line-height: 1; white-space: nowrap; text-decoration: none;
}
html.dcf-playing .tag-feed-list { width: 36px; padding: 0; }
html.dcf-playing .tag-feed-list-text { display: none; }
.tag-feed-list:focus-visible, .tag-feed-bar .tl-reel-topbar-btn:focus-visible { outline: 2px solid var(--tl-ink, #171717); outline-offset: 2px; }
.tag-feed-bar-label { flex: 1 1 auto; min-width: 0; font-size: 14px; font-weight: 700; line-height: 1.2; }
.tag-feed-bar-tag { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 表紙のとき = タグの名前（右は空・行動は表紙の上の右レール）/ ゲーム中（部品が html に dcf-playing）= 行動だけ */
.tag-feed-bar-actions { display: none; }
html.dcf-playing .tag-feed-bar-tag { display: none; }
html.dcf-playing .tag-feed-bar-actions { display: block; flex: none; }
/* 遊んでいる本の題名は**読み上げにだけ**残す（2026-09-20 founder 裁定 1: バーに題名は要らない）。
   display:none だと読み上げからも消えるので、1px に潰して切り抜く昔ながらの形にする。
   幅を取らないので、空いた分はそのまま右の行動ボタンの余裕になる（以前は題名が幅を食って
   スマホで「Si…」まで潰れていた）。文字は games-by-tag-feed.js が itemshown ごとに更新し続ける。 */
.tag-feed-bar-title {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
.tag-feed.dcf-social-off .tag-feed-bar-actions { display: none; }
/* 枠の上のお題の名前（.dco-top）は携帯だけ（下の携帯の塊で出す）。PC は上のバーの中央が受け持つ */
.dco-top { display: none; }
/* お題の回（?challenge=・2026-10-06・feed-challenge.js）の PC の置き場: 上のバーの中央に、お題の名前と残り秒 /
   TIME UP（もう一回・次のゲームへ）。携帯は帯（.dcb の余白と TIME UP の顔）が受け持ち、このバーごと出ない。
   ゲーム中も出す（表紙の名前 .tag-feed-bar-tag はゲーム中に退くが、残り秒はゲーム中こそ要る）。ゲームの上には重ねない */
.tag-feed-bar-odai { display: flex; align-items: center; gap: 10px; min-width: 0; white-space: nowrap; }
.tag-feed-bar-odai[hidden] { display: none; }
.tag-feed-bar-odai .dco-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; font-size: 13px; color: var(--tl-ink-muted, #6B6B6B); }
/* 名前は棚へのリンク（PC には ← が無い・2026-10-07 レビュー A 小-5）。見た目は文字のまま・触れたときだけ下線 */
.tag-feed-bar-odai a.dco-title { text-decoration: none; white-space: nowrap; }
.tag-feed-bar-odai a.dco-title:hover, .tag-feed-bar-odai a.dco-title:focus-visible { text-decoration: underline; color: var(--tl-ink, #111); }
/* スポンサーお題の「協賛：◯◯」（PC の上のバー・2026-10-25 everywhere・携帯の .dco-top-sponsor と同じ札） */
.tag-feed-bar-odai .dco-sponsor { flex: 0 1 auto; min-width: 0; max-width: 240px; padding: 3px 9px; border-radius: 999px; background: #F1EEE8; color: #171717; font-size: 12px; font-weight: 800; overflow: hidden; text-overflow: ellipsis; }
.tag-feed-bar-odai .dco-time { font-size: 14px; font-weight: 800; font-variant-numeric: tabular-nums; }
.tag-feed-bar-odai .dco-time[data-level="warn"] { color: #C2410C; }
.tag-feed-bar-odai .dco-time[data-level="urgent"] { color: #C2410C; font-size: 16px; }
.tag-feed-bar-odai .dco-tu { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.tag-feed-bar-odai .dco-tu-title { font-size: 15px; font-weight: 800; }
.tag-feed-bar-odai .dco-tu-sub { font-size: 12px; color: var(--tl-ink-muted, #6B6B6B); overflow: hidden; text-overflow: ellipsis; }
.tag-feed-bar-odai .dco-btn {
  flex: none; height: 32px; padding: 0 14px; border: 0; border-radius: 9999px; cursor: pointer;
  background: var(--tl-surface-sunk, #F5F5F5); color: var(--tl-ink, #171717); font: inherit; font-size: 13px; font-weight: 700;
}
.tag-feed-bar-odai .dco-btn.dco-primary { background: var(--tl-ink, #171717); color: #fff; }
.tag-feed-bar-odai .dco-btn:focus-visible { outline: 2px solid var(--tl-ink, #171717); outline-offset: 2px; }
/* 丸ボタンの見た目はタイムラインの白い上のバーと同じ（game-social.css .tl-reel-topbar-btn: 窪みの灰 + 濃い印、
   押した状態 = 赤の塗り + 白い印）。ここは読み込み前の 1 コマ用のフォールバックだけ */
.tag-feed-bar .tl-reel-topbar-btn { width: 36px; height: 36px; border: 0; border-radius: 50%; background: var(--tl-surface-sunk, #F5F5F5); color: var(--tl-ink-70, #525252); }
.tag-feed-bar .tl-reel-topbar-btn.is-on { background: var(--tl-accent-ink, #CE2820); color: #fff; }
.dcf-creator { display: inline-flex; align-items: center; gap: 8px; min-width: 0; margin-bottom: 4px; color: #fff; font-size: 13px; font-weight: 600; }
.dcf-creator-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dcf-overlay a.tl-profile-link { color: #fff; text-decoration: none; }
/* コメントの中から開くスタンプのシートは、コメントのシートの上に重ねる（タイムラインの #timelineStampSheet と同じ） */
#tagFeedStampSheet { z-index: calc(var(--tl-z-sheet, 2110) + 1); }
html.gs-sheet-open, html.gs-sheet-open body { overflow: hidden; overscroll-behavior: none; }

/* 狭い画面のヘッダーを 1 行に（2026-09-17 founder 実機 349px で右のリンクが 2 行に折れていた）。
   フィードにならない回（JS 無効・フィードの API が返らない・クローラーの描画）で見える形。
   6 言語で一番長い組（es「Todos los juegos」「Crear un juego」）が 320px に 1 行で入る大きさにし、
   それでも入らない端末の文字設定では、折らずにリンクの列だけ横にスクロールさせる（ロゴは縮めない） */
@media (max-width: 480px) {
  .site-header { padding: 12px 16px; gap: 12px; }
  .site-logo { font-size: 17px; flex: none; }
  .header-nav {
    gap: 12px; min-width: 0; overflow-x: auto; scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .header-nav::-webkit-scrollbar { display: none; }
  .header-nav a { font-size: 13px; }
}
@media (max-width: 360px) {
  .site-logo { font-size: 16px; }
  .header-nav { gap: 10px; }
  .header-nav a { font-size: 12px; }
}
/* 左メニューのボタンがヘッダーに入った回（public/js/tag-page-nav.js が .tag-nav-has-toggle を付ける）は、
   400px 以下で「すべてのゲーム」（/games）を出さない。2026-09-17 founder 指摘: 320px の一覧で「つくってみる」が切れて横に流れた。
   WHY このリンクを落とすのか: このページ自体がゲームの一覧で、全タグの索引（/games）へは左メニューからも行ける。
     「つくってみる」は作る側への唯一の入口なので残す。文字をさらに小さくする案は 12px 未満で読みにくくなるので採らない。
   実測（320px・6 言語）: [メニュー][ロゴ][つくってみる] が 1 行に収まり、横のはみ出し 0（レポート参照） */
@media (max-width: 400px) {
  .site-header.tag-nav-has-toggle .header-nav a[href="/games"] { display: none; }
}

/* ── 「プレイ動画が録れた」赤い点（2026-09-18・計画書フェーズ 3-B）─────────────────────────
   印そのもの（大きさ・色・一度だけ脈打つアニメ）の定義は public/css/modules/project-creator.css の
   1 か所だけ（/create → ゲームページ → ここ で同じ物）。あの CSS は .project-creator-view の中でしか
   効かないよう閉じてあるので、rail.js が赤い点を出す回だけシェアのボタン自身にその class を足している。
   ここで足すのは **置き場所（position: relative）だけ**: .tl-reel-topbar-btn は relative を持っておらず、
   絶対配置の点がバーの左上に飛ぶ。色や大きさをここで再定義しないこと（2 か所に割れる）。 */
.tag-feed-bar .tl-reel-topbar-btn[data-reel-share-badge-host] { position: relative; }

/* ── MOBILE-ONLY: アプリ（WebView）の一覧表示でヘッダーがノッチに潜る（2026-09-20・founder 承認済み）──
   実測（iOS シミュレーターの検証用 WKWebView = 本物のアプリと同じ contentInset: never + bridge の印）:
   /games の「List」表示（html.tag-view-list）で header.site-header が top 0〜61pt に出て、
   --safe-top: 62px のダイナミックアイランドに完全に埋まり、ロゴもリンクも読めなかった。
   フィード表示（html.feed-on）はヘッダーを隠して上のセーフエリアを .tag-feed-bar 側で吸っているが、
   一覧の面には吸う場所が無い。viewport-fit=cover は同じ文書（同じ殻）なので外せない ——
   フィードの面がセーフエリアを自分で扱う前提で作られているため。

   CLAUDE.md「ベース → native 上書き」に従い、値は**加算元をベースと合わせる**:
   一覧の殻（games-index.html / games-by-tag.html の <style>）のベースは padding: 16px 24px、
   480px 以下では上の @media がそれを 12px 16px に下げるので、両方ぶんを書く。
   ファイル末尾なのは、同じ詳細度なら後勝ちで、上の @media (max-width: 480px) の 12px より
   後に置かないと広い方の規則が効かないため（public/css/article.css と同じ流儀・同ファイルの WHY 参照）。
   Web（:root の --safe-top: 0px かつ html に native-app が付かない）には 1px も影響しない。 */
html.native-app .site-header { padding-top: calc(16px + var(--safe-top, 0px)); }
@media (max-width: 480px) {
  html.native-app .site-header { padding-top: calc(12px + var(--safe-top, 0px)); }
}


/* ══════════════════════════════════════════════════════════════════════════════════════════
   携帯の見た目 = v3 シアター（/v3/game）と同じ（2026-10-06）
   ──────────────────────────────────────────────────────────────────────────────────────────
   経緯:
     founder「V3のゲーム画面はとりいれたい」→「本番のgame画面の機能を元に、UIのデザインだけ変更するほうが速い」
     → 1 回目（c94030fb9f）は値を「似せた」作りで、founder が Sandbox で見て「まったくV3と違うじゃん。アイコンもこれだった？」
       「アイコンの種類、サイズ、バーのサイズなど。ぜんぜん違うよ」（帯 68px・行 top 12・gap 5・灰色の頭文字の顔・
       本番の線アイコン・「…」・Inter の書体 だった）
     → 2 回目（この塊）は **v3 の規則を値ごと写す**。各規則の上に出典（v3 のファイルと行）を書く。直すときは v3 と同時に。
   決まり（founder・PL 2026-10-06）:
     - 上のバーを無くし、v3 の「下の帯 1 本」: [← 顔 (余白) スタンプ コメント シェア ●つくる]（「…」は無い）
       部品は public/js/modules/feed-band.js（DOM は v3 strip.js と同じ形・class も v3 の名前）
     - 枠は今のまま幅いっぱい（v3 の 390x844 縮小はしない・founder 決定）。角丸・影・地の色は v3 と同じ
     - **PC（1024px 以上）は変えない** = 下の規則は全部 max-width の中。境目は左ドロワーの常設サイドバー
       （tag-page-nav.js DESKTOP_QUERY = min-width: 1024px）のちょうど反対。変えるときは 3 か所（ここ・feed-band.js・tag-page-nav.js）
       WHY hover/pointer ではなく幅か: このページの PC の上のバーは常設サイドバー（幅で出る）と組で並ぶので、境目を
       サイドバーとそろえないと「サイドバーなし + PC の上のバー」の半端な形ができる。結果として PC でも窓を 1024px 未満に
       縮めると携帯の帯になり、横向きの iPad（1024 以上）は PC の形になる（どちらも意図どおり・PR 前レビュー 2026-10-06 で確認）
   WHY v3.css を読み込まずに写すのか: v3.css は :root のトークンと body・button の土台まで持つので、読むと本番の殻の
     他の部品（ヘッダー・シート・ゲストブック）の見た目まで変わる。v3 の規則は **.dcb（帯）と .dcp（帯の顔から開く作者パネル）の
     中だけ**に効く形で写し、トークンもその 2 つの上にだけ置く。
   WHY 優先度を .tag-feed / .dcb で 1〜2 段上げるのか: game-feed.js は自分の見た目を <style> で head の**最後**に足す
     （ensureStyle）ので、同じ強さのセレクタだとあちらが後勝ちする。game-social.css の .tl-reel-topbar-btn にも勝たせる。
   ══════════════════════════════════════════════════════════════════════════════════════════ */
.dcb { display: none; }
/* 帯のランキングのシートの見出し（games-by-tag-social.js addLeaderboardHead・2026-10-06 9 回目）。
   PC（1024px 以上）は本番のシートのまま = 見出しは出さない（部品の「タイトルは無い」の裁定は PC の物）。携帯の塊の中でだけ見せる */
.leaderboard-sheet .dcl-h { display: none; }

@media (max-width: 1023.98px) {
  /* ── v3 のトークン（public/v3/v3.css 23-31 / 39-48 / 61-69 / 72-97 行の写し）。帯と作者パネルの中だけ ──
     .dcl / .leaderboard-clip-overlay = 本番のランキング（leaderboard.js のシート・Top3 変動カード・clip-player.js の再生カード）を
     v3 に着せる分（8 回目・下の「ランキング」の塊）。このファイルはフィードの殻だけが読む = ゲームページ（game.html）には効かない */
  .dcb, .dcp, .dcs, .dcl, .leaderboard-clip-overlay {
    --ground: #F1F1F3; --ground-2: #F5F5F6; --paper: #FFFFFF;
    --ink: #141417; --ink-2: #4A4A52; --mute: #8B8B94; --faint: #A6A6AE; --hair: #F0F0F2;
    --ok: #1F9D55; --ok-ink: #1B7A45;
    /* 赤は「つくる」だけ。値はブランドの --red 系から引く（v3.css 39-40 行と同じ = WEBLOX で青） */
    --rec: var(--red, #FF3B30);
    --rec-rgb: var(--red-rgb, 255, 59, 48);
    --hi-line: inset 0 0 0 1px rgba(20, 20, 23, .05);
    --sh-1: 0 1px 1px rgba(20, 20, 23, .03), 0 2px 6px -2px rgba(20, 20, 23, .06);
    --sh-rec: 0 6px 14px -8px rgba(var(--rec-rgb), .7), 0 2px 4px -2px rgba(var(--rec-rgb), .35);
    --hi: inset 0 1px 0 rgba(255, 255, 255, .75);
    --sh-3: 0 -1px 2px rgba(20, 20, 23, .03), 0 -12px 32px -12px rgba(20, 20, 23, .16), 0 -32px 64px -40px rgba(20, 20, 23, .22);
    --r-xs: 10px; --r-sm: 14px; --r-lg: 22px; --r-pill: 999px; --s-2: 8px;
    --fs-body: 14.5px; --fs-sm: 12.5px; --lh-body: 1.55; --track-cap: .08em;
    --font-mono: "JetBrains Mono", ui-monospace, Menlo, monospace;
    --font-body: "Zen Kaku Gothic New", system-ui, -apple-system, "Hiragino Sans", "Noto Sans JP", sans-serif;
    --font-display: "Bricolage Grotesque", "Zen Kaku Gothic New", system-ui, sans-serif;
    --spring-pop: cubic-bezier(.34, 1.56, .64, 1);
    --ease-out: cubic-bezier(.16, 1, .3, 1);
    --ease-in-out: cubic-bezier(.65, 0, .35, 1);
    --dur-1: 180ms; --dur-2: 280ms; --dur-3: 420ms;
    --press-scale: .96;
    --safe-bottom: env(safe-area-inset-bottom, 0px);
    --safe-left: env(safe-area-inset-left, 0px);
    --safe-right: env(safe-area-inset-right, 0px);
  }
  /* シェアモーダル（.dcs = feed-share-sheet.js・2026-10-06 4 回目）だけが使う v3 のトークン（v3.css 30-31 / 44-45 / 52 / 58 / 61 / 72-74 行）。
     規則そのものは /css/feed-share-sheet.css（開いたときに読む） */
  .dcs {
    --line: #E4E4E8;
    --glass-strong: rgba(255, 255, 255, .86);
    --glass-blur: blur(24px) saturate(180%);
    --sh-2: 0 1px 2px rgba(20, 20, 23, .04), 0 8px 20px -10px rgba(20, 20, 23, .16), 0 20px 40px -28px rgba(20, 20, 23, .20);
    --r-md: 18px; --r-xl: 26px;
    --s-1: 4px; --s-3: 12px; --s-4: 16px; --s-5: 20px; --s-6: 24px;
    --fs-title: 17px; --lh-tight: 1.2;
    --safe-top: env(safe-area-inset-top, 0px);
  }
  .dcb *, .dcb *::before, .dcb *::after, .dcp, .dcp *, .dcp *::before, .dcp *::after, .dcs, .dcs *, .dcs *::before, .dcs *::after { box-sizing: border-box; }

  /* ── 上のバーを無くす ──────────────────────────────────────────────────────────────
     舞台の上端は --dcf-top-inset（game-feed.js .dcf-stage の top）。バーの高さを 0 にすればノッチの分だけ下がる。
     ⚠️ 2026-10-09 から携帯でもゲームの縮尺に舞台の実寸を使う（game-feed.js の再改訂）。ResizeObserver
     （syncStageMetrics）はスクローラーに加えて舞台そのものも観測するので、この値が後から変わっても測り直される。 */
  .tag-feed { --tag-feed-bar-h: 0px; }
  .tag-feed-bar { display: none; }

  /* ── 地と枠（v3 theater.css 15-32 行・game-frame.css 25-35 行・deck.js 68 行 radius 20）──────────────
     v3 の形: 舞台 .th-stage は margin 8px 8px 0 / 帯 60px + 安全領域。枠 .gf-frame は舞台の中の .gf-ring（外周 3px の
     リング）の内側 = 画面の端から 8 + 3 = 11px・帯の上端から 3px。角丸 20px・影 --sh-frame（v3.css 69 行）・地 #0B0B0D。
     本番の舞台（.dcf-stage）はそのまま枠に当たるので、位置を v3 の枠の位置に合わせる。幅は v3 の縮小をせず幅いっぱい。
     帯の高さ（--dcf-strip）は game-feed.js の既定 68px（GRAB_STRIP_PX）を v3 の 60px に。掴み帯（.dcf-strip）も同じ値を
     読むので、掴める範囲 = 帯の範囲のまま。--dcf-ctrl-top は XP カード（game-social.css .xp-card）の縦位置の線 =
     v3 の .th-bar の top 10px に合わせる。 */
  .tag-feed .dcf-scroller { background: #F1F1F3; }
  .tag-feed .dcf-item { --dcf-strip: calc(60px + env(safe-area-inset-bottom, 0px)); --dcf-ctrl-top: 10px; }
  .tag-feed .dcf-stage, .tag-feed .dcf-next {
    left: 11px; right: 11px;
    top: calc(var(--dcf-top-inset, 0px) + 11px);
    bottom: calc(var(--dcf-strip) + 3px);
    border-radius: 20px;
  }
  .tag-feed .dcf-stage { background: #0B0B0D; box-shadow: 0 2px 4px rgba(0, 0, 0, .06), 0 14px 30px -18px rgba(0, 0, 0, .45); }
  .tag-feed .dcf-frame { background: #0B0B0D; }
  /* 表紙の地: サムネが来るまでは淡い灰（v3 theater.css 32 行 .th-slot .gf-cover）。サムネは style の background-image なので色だけ */
  .tag-feed .dcf-cover { background-color: #DCDCE1; }
  .tag-feed .dcf-note { color: #4A4A52; }
  .tag-feed .dcf-note-btn { background: #141417; color: #fff; }
  .tag-feed .dcf-note .dcf-spinner { border-color: rgba(20, 20, 23, .15); border-top-color: #141417; }
  /* ゲストブックから来た回の待ち板（上の .feed-from-person）: 白いバーはもう無いので舞台の色だけ */
  html.feed-pending.feed-from-person:not(.tag-view-list) .feed-cover { background: #0D0D0F; }
  .dc-go-handoff-bar { display: none; }

  /* ── 表紙の右レールは出さない（帯と二重にしない）。作者・題名の行はレールの分の右の空きを返す ── */
  .tag-feed .dcf-chrome .tl-reel-rail { display: none; }
  .tag-feed .dcf-item.has-chrome .dcf-overlay { padding-right: 16px; }

  /* ── 枠ごとの掴み帯の控え（「↑ 上にスワイプ」の札・「前へ」の丸）は帯に席を譲る ──────────────
     掴み帯そのもの（.dcf-strip = 引き上げて次へ・タップで次へ）は残り、帯の余白（.th-hint）と帯の上下の
     余白から指が届く（feed-band.js の「余白を穴にする」WHY）。「前へ」は帯の「←」が受け持つ。
     「掴める」の手がかりは v3 と同じ上端のつまみ（.th-grab）。 */
  .tag-feed .dcf-hint, .tag-feed .dcf-prev { display: none; }
  /* スワイプの案内（feed-swipe-coach.js の指の実演）は暗い地用の白い光。明るい地では墨の線に替える
     （白いままだと帯の周りに薄い輪が出ているだけに見えた・2026-10-06 撮影）。動きと時機は部品のまま */
  .tag-feed .dcfc-box { border-color: rgba(20, 20, 23, .55); box-shadow: 0 0 14px rgba(20, 20, 23, .12); }
  .tag-feed .dcfc-ring { border-color: rgba(20, 20, 23, .7); }
  .tag-feed .dcfc-trail { background: linear-gradient(to top, rgba(20, 20, 23, 0), rgba(20, 20, 23, .35)); }

  /* ── MOBILE-ONLY: iOS アプリ（html.native-app）の帯の下の安全領域（2026-10-06・PL が iOS シミュレータで確認）──
     症状: アプリでだけ帯の下に大きな空き（ボタンの列の下端〜画面の下端 44px。Safari は 6px）があり、
       その空きごとスワイプの案内の灰色の角丸の枠（.dcfc-box・最初の数秒だけ出る）が囲んで「空の器」に見えた。
     原因: 帯の高さが 60px + env(safe-area-inset-bottom) の **安全領域まるごと**（iPhone 17 Pro のアプリ = 34px → 94px）。
       帯（.dcb の --safe-bottom = 上のトークン）・掴み帯と舞台の下端（--dcf-strip）・案内の枠（掴み帯の高さに合わせて
       JS が置く = feed-swipe-coach.js place）の 3 つが同じ 34px を足していた。
       Safari では表示域がツールバーの上で終わり安全領域は 0 なので、同じ規則でも帯の下端がぴったりになる。
       （下のタブの器・app-shell の下のナビの余白はこの殻には無い。二重の余白でもない = 疑いは外れ）
     直し: 34px の安全領域は 14px だけ足し、列の下端を画面の下から 20px に置く。
       20〜21px の安全領域（iPad・横向き iPhone）でも最低 14px を残し、ホーム操作に重ねない。
       --dcf-band-home = min(安全領域, max(14px, 安全領域 − 20px))。
       安全領域 0px のホームボタン機は 0px のまま。14px より小さい安全領域は全量を残す。
       WHY 14px: インジケータ上端（下から約 13px）+ 列の下の余白 6px ≒ 20px となる追加分。
         大きい安全領域は元の「20pxを引く」詰め方を保ち、小さい非ゼロ領域だけ最低限の余白を確保する。
     Web には 1px も効かない（html.native-app はアプリの WebView だけが付ける = CLAUDE.md ルール 1 / 3）。
     作者パネル（.dcp .pp-f）・ランキング（.dcl）・シェア（.dcs）は下から出るシートで、地が画面の下端まで塗られた
     うえで中身が安全領域の上に止まる（iOS の標準のシートと同じ）ので、安全領域まるごとのまま変えない。 */
  html.native-app { --dcf-band-home: min(env(safe-area-inset-bottom, 0px), max(14px, env(safe-area-inset-bottom, 0px) - 20px)); }
  /* 掴み帯の高さ = 舞台の下端（上の .tag-feed .dcf-item と同じ 60px の帯に、安全領域の代わりに --dcf-band-home） */
  html.native-app .tag-feed .dcf-item { --dcf-strip: calc(60px + var(--dcf-band-home)); }
  /* 帯（下の .dcb の height / padding-bottom が読む --safe-bottom を帯の中だけ差し替える。.dcp / .dcs / .dcl のトークンはそのまま） */
  html.native-app .dcb { --safe-bottom: var(--dcf-band-home); }
  /* スワイプの案内: 枠は掴み帯の下端から 6px（Web と同じ）ではなく、ボタンの列を囲む位置まで上げる。
     指・輪・残像の縦の中心も列の中心へ（掴み帯の 50% から --dcf-band-home の半分だけ上） */
  html.native-app .tag-feed .dcfc-box { bottom: calc(6px + var(--dcf-band-home)); }
  html.native-app .tag-feed :is(.dcfc-hand, .dcfc-ring) { top: calc(50% - var(--dcf-band-home) / 2); }
  html.native-app .tag-feed .dcfc-trail { bottom: calc(50% + var(--dcf-band-home) / 2); }

  /* ════════════════════════════════════ 帯（v3 theater.css 35-115 行）════════════════════════════════════ */
  /* .th-strip（36-44 行）: 60px + 安全領域・padding 10 / 10+右 / 6+下 / 8+左。
     本番だけの違い 3 つ:
       - position: absolute（v3 は縦の flex の 1 段。本番はフィードの器の下端に重ねる）・z-index 8 = 舞台 5 / 掴み帯 7 の上、
         シート（--tl-z-sheet 2110）の下
       - pointer-events: none（帯そのものは指を下の掴み帯へ通す。押せる物だけが指を取る = feed-band.js の WHY）
       - 地を塗る（v3 は透明）: 次の本のカード（.dcf-next）は舞台のすぐ下 = 帯の場所で待っている。v3 は舞台の
         overflow: hidden で切るが、本番の舞台は枠ごとの部品なので切れない。塗っても指は通る。色は地と同じ = 見た目は v3 と同じ */
  .dcb {
    display: block;
    position: absolute; left: 0; right: 0; bottom: 0; z-index: 8;
    height: calc(60px + var(--safe-bottom));
    padding: 10px calc(10px + var(--safe-right)) calc(6px + var(--safe-bottom)) calc(8px + var(--safe-left));
    pointer-events: none;
    background: var(--ground);
    color: var(--ink);
    font-family: var(--font-body); font-size: 14.5px; line-height: 1.55; font-feature-settings: "palt" 1;   /* v3.css body（19-24 行） */
    -webkit-font-smoothing: antialiased;
    -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
  }
  .dcb button { font: inherit; color: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent; }   /* v3.css 162-163 行 */
  /* つまみ（47-51 行）= 「引ける」の合図。指は下の掴み帯へ通す */
  .dcb .th-grab {
    position: absolute; top: 4px; left: 50%; width: 34px; height: 4px; margin-left: -17px; border-radius: 4px;
    background: rgba(20, 20, 23, .16);
  }
  /* 題名は読み上げにだけ（上のバーの .tag-feed-bar-title と同じ形・2026-09-20 founder 裁定 1） */
  .dcb .dcb-title {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
  }

  /* 帯の顔（ボタンの列 / スタンプの列 / お知らせ）は同じ場所で入れ替わる（55-64 行）。高さが変わらない = ゲームが跳ねない */
  .dcb .th-bar, .dcb .th-stamps, .dcb .dcb-notice {
    position: absolute; left: calc(8px + var(--safe-left)); right: calc(10px + var(--safe-right));
    top: 10px; height: 44px;
    display: flex; align-items: center; gap: 6px;
    transition: opacity var(--dur-2) var(--ease-out), transform var(--dur-3) var(--spring-pop);
    pointer-events: none;
  }
  .dcb .th-stamps, .dcb .dcb-notice { opacity: 0; transform: translate3d(0, 10px, 0) scale(.97); }
  .dcb[data-mode="stamps"] .th-bar { opacity: 0; transform: translate3d(0, -10px, 0) scale(.97); }
  .dcb[data-mode="stamps"] .th-stamps,
  .dcb[data-mode="notice"] .dcb-notice { opacity: 1; transform: none; }
  /* お知らせの顔（XP カードが出ている間）: 列は**動かさず**、← と顔（カードの下に入る）・「つくる」（✕ と同じ場所）だけ
     消える。スタンプ・コメント・シェアはそのまま押せる。カードの右端は feed-band.js が測ってスタンプの手前に止める
     （下の .xp-card の right）。2026-10-06 までは列ごと退かしていて（opacity 0 + inert）、カード（z 9）が帯の左端から
     ✕ の手前までを覆い、遊び終えた直後の帯のタップが全部カードに吸われていた（PL 実機 iPhone 17 Pro・
     iOS Safari シミュレータの本物のタップで再現: 的が .xp-card-inner）。カードは時間で消えない = ✕ まで帯が死んでいた */
  /* ランキング（6 回目・本番だけ）もスタンプ・コメント・シェアと同じく残る（遊び終えた直後こそ見たい・founder）。
     7 回目（2026-10-06 founder「ランキングはコメントの右がいいな」）からランキングはふだん .dcb-actions の中
     （コメントの直後・feed-band.js placeRank）に居て、器と一緒に残る。下の `> [data-band="ranking"]` は器が空の本で
     待ち場所（.th-bar の直下）に居るときの分 */
  .dcb[data-mode="notice"] .th-bar > :not(.dcb-actions):not([data-band="ranking"]) { opacity: 0; pointer-events: none; }
  /* 押せる物だけ指を取る。列の余白（.th-hint）は下の掴み帯へ素通し */
  .dcb[data-mode="bar"] .th-bar > :not(.th-hint),
  .dcb[data-mode="notice"] .th-bar > .dcb-actions,
  .dcb[data-mode="notice"] .th-bar > [data-band="ranking"],
  .dcb[data-mode="stamps"] .th-stamps,
  .dcb[data-mode="notice"] .dcb-notice .th-rb { pointer-events: auto; }
  /* rail.js が描く器は display: contents = 中のボタンが .th-bar の列に直接並ぶ（gap 6px が v3 と同じに効く） */
  .dcb .dcb-actions, .dcb .dcb-actions .tl-reel-topbar-actions { display: contents; }

  /* 帯のボタン（67-74 行）: 白い丸 40px・--paper + --sh-1 + --hi-line・印 20px。← もどる だけは地に溶ける 34px・印 22px */
  /* padding: revert = ブラウザの既定のボタンの余白に戻す。v3 の .th-rb は padding を書いていない（v3.css にもボタンの余白の
     リセットが無い）= WebKit の既定（上 2px・下 3px の非対称）のまま描かれ、印が 0.5px 上に寄る。本番は rail.js の
     .tl-reel-topbar-btn 等に padding の指定があるので、既定へ戻して v3 と同じ位置にする（2026-10-06 撮影で 0.5px の差を測った） */
  .dcb .th-bar .th-rb, .dcb .dcb-notice .th-rb {
    flex: 0 0 auto; width: 40px; height: 40px; border: 0; border-radius: 50%; padding: revert; margin: 0;
    background: var(--paper); color: var(--ink); display: grid; place-items: center;
    box-shadow: var(--sh-1), var(--hi-line);
  }
  .dcb .th-rb .ic { display: block; flex: 0 0 auto; width: 20px; height: 20px; }   /* .ic = v3.css 168 行 */
  /* 上の display: grid が [hidden] に勝つので戻す（帯のランキングは「もう無い」の枠で hidden になる・6 回目） */
  .dcb .th-bar .th-rb[hidden] { display: none; }
  .dcb .th-bar .th-rb.th-back { width: 34px; height: 34px; background: transparent; box-shadow: none; color: var(--ink-2); }
  .dcb .th-rb.th-back .ic { width: 22px; height: 22px; }
  /* 本番の rail.js の「押してある」（.is-on）は塗りにしない: v3 は押したスタンプの絵を白い丸の上に出す（.th-glyph）だけ */
  .dcb .th-bar .th-rb.is-on { background: var(--paper); color: var(--ink); }
  /* 録画の赤い点（rail.js の .project-complete-clip-badge）の置き場。見た目の定義は project-creator.css の 1 か所だけ */
  .dcb .th-rb[data-reel-share-badge-host] { position: relative; }
  /* 自分が押したスタンプの絵が帯に残る（76-78 行・数は出さない） */
  .dcb .th-glyph { display: block; font-size: 21px; line-height: 1; }
  .dcb .th-rb.has-stamp .th-glyph { animation: th-glyph-in var(--dur-3) var(--spring-pop); }
  .dcb [data-stamp-ic] { display: grid; place-items: center; }
  /* 作者の顔（79-80 行）+ v3.css .av / .av-wrap.paw（379-396 行）。色は feed-band.js faceHtml が人の色 6 色から入れる */
  .dcb .th-auth { flex: 0 0 auto; border: 0; padding: 0; background: none; border-radius: 50%; }
  .dcb .th-auth[hidden] { display: none; }
  .dcb .th-auth .av { --av: 38px; }
  .dcb .av {
    position: relative; flex: 0 0 auto; width: var(--av, 36px); height: var(--av, 36px); border-radius: 50%;
    display: grid; place-items: center; overflow: hidden; color: #fff;
    font: 800 calc(var(--av, 36px) * .4) / 1 var(--font-display); background: var(--mute);
    box-shadow: 0 0 0 2px var(--paper);
  }
  .dcb .av img { width: 100%; height: 100%; object-fit: cover; }
  .dcb .av.bump { animation: av-bump .5s var(--spring-pop); }
  .dcb .av-wrap { position: relative; display: inline-grid; }
  /* あしあとの ✓（遊んだよが届いた）。v3.css 390-395 行の写し（SVG の data URI も 1 文字も変えない） */
  .dcb .av-wrap.paw::after {
    content: ""; position: absolute; right: -3px; bottom: -3px; width: 17px; height: 17px; border-radius: 50%;
    background: var(--ok) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 12.5l4 4 8-9'/%3E%3C/svg%3E") center/11px no-repeat;
    box-shadow: 0 0 0 2px var(--ground); animation: paw-in var(--dur-3) var(--spring-pop);
  }
  /* 余白（82-89 行）。v3 ではプレイ動画の間だけ文字が出る。本番では掴み帯への穴。
     お題の回（?challenge=・2026-10-06・feed-challenge.js）だけ、お題の名前と残り秒が出る（v3 の setHint と同じ場所 =
     ゲームの上に重ねない）。文字が出ても pointer-events は none のまま = 文字の上からも引いて次へ行ける。
     字の大きさ・色は v3 theater.css .th-hint（82-89 行: 700 11px・--mute）。残り秒だけ一段強く（読む物の主役）。
     残り 10 秒で注意色（橙）・5 秒で字を大きく（従来ページの .dcs-timer の warn / urgent と同じ境目）。
     赤（--rec）は使わない: 帯の赤は「● つくる」だけ（test/feed-band.test.js が数で固定）。赤い数字が帯に出ると
     「つくる」と同じ色の物が 2 つ並び、押す物に見える */
  .dcb .th-hint { flex: 1 1 0; min-width: 0; align-self: stretch; }
  .dcb .th-hint.is-on {
    display: flex; align-items: center; justify-content: center;
    min-width: 34px;   /* 時計の印 + 2 桁。これより狭いときは帯の畳み方（fitBand: 詰める → ランキングを退かす → つくるを丸に）に任せる */
    font: 700 11px/1.2 var(--font-body); color: var(--mute); white-space: nowrap; overflow: hidden;
  }
  .dcb .th-hint .dco-sec { display: inline-flex; align-items: center; gap: 2px; color: var(--ink-2); }
  .dcb .th-hint .dco-clock { width: 14px; height: 14px; flex: 0 0 auto; }
  .dcb .th-hint .dco-sec b { font: 800 19px/1 var(--font-display); font-variant-numeric: tabular-nums; color: var(--ink); }
  .dcb .th-hint .dco-sec[data-level="warn"], .dcb .th-hint .dco-sec[data-level="warn"] b { color: #C2410C; }
  .dcb .th-hint .dco-sec[data-level="urgent"], .dcb .th-hint .dco-sec[data-level="urgent"] b { color: #C2410C; }
  .dcb .th-hint .dco-sec[data-level="urgent"] b { font-size: 23px; }

  /* ── お題の名前（枠の上の 1 行・お題の回だけ = .tag-feed.dco-on）──────────────────────
     携帯は上のバーが無い（舞台は上端 11px から）。お題の回だけ舞台を 28px 下げ、空いた所に「お題：〇〇 ›」を置く
     = ゲームの上に重ねない・枠の外に積む（v3 の作法）。押すとお題の棚へ（← の 1 本目と同じ行き先）。
     WHY 帯の余白に名前を出さないのか: 余白は iPhone の幅で 40px 前後しかなく、名前が「お…」に潰れた（2026-10-06 撮影）。
     --tag-feed-bar-h を上げれば舞台・次のカード・掴み帯の計算（--dcf-top-inset）がそのまま追従する（game-feed.js は値を読むだけ） */
  .tag-feed.dco-on { --tag-feed-bar-h: 28px; }
  .tag-feed .dco-top {
    position: absolute; left: 0; right: 0; top: env(safe-area-inset-top, 0px); z-index: 8; height: 28px;
    display: flex; align-items: flex-end; justify-content: center; padding: 0 16px; pointer-events: none;
  }
  .tag-feed .dco-top[hidden] { display: none; }
  .tag-feed .dco-top-link {
    display: inline-flex; align-items: center; gap: 1px; max-width: 100%; height: 24px; padding: 0 4px 0 8px;
    font: 700 12.5px/1 "Zen Kaku Gothic New", system-ui, -apple-system, "Hiragino Sans", "Noto Sans JP", sans-serif;
    color: #4A4A52; text-decoration: none; white-space: nowrap; pointer-events: auto; -webkit-tap-highlight-color: transparent;
  }
  .tag-feed .dco-top-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  /* スポンサーお題の「協賛：◯◯」（2026-10-25 everywhere）= 名前の隣の小さな札。同じ 24px の行の中（舞台の 28px は変えない）。
     長い会社名は最大 45% で切る（お題の名前を押し出さない）。赤は使わない（赤は「つくる」だけ） */
  .tag-feed .dco-top-sponsor {
    flex: 0 1 auto; min-width: 0; max-width: 45%; margin-left: 6px; padding: 2px 7px; border-radius: 999px;
    background: #F1EEE8; color: #171717; font-size: 11px; font-weight: 800; line-height: 1.3;
    overflow: hidden; text-overflow: ellipsis;
  }
  .tag-feed .dco-top-ic { width: 14px; height: 14px; flex: 0 0 auto; color: #8B8B94; }
  .tag-feed .dco-top-link:focus-visible { outline: 2px solid #141417; outline-offset: 2px; border-radius: 6px; }

  /* ── TIME UP の顔（お題の枠が尽きた間・feed-band.js の timeup モード）──────────────
     左に「TIME UP / N 秒後に次のゲームへ」、右に「もう一回」（白い丸のボタンと同じ地）と「次のゲームへ」（墨 = 進行）。
     赤を使わないのは「つくる」と取り違えないため（赤は「つくる」だけ）。高さは他の顔と同じ 44px = ゲームは跳ねない */
  /* 置き方・入れ替わりの動きは他の顔（.th-bar / .th-stamps / .dcb-notice・上の規則）と同じ値。既存の規則に足さず
     別に書くのは、v3 の写しの規則（test/feed-band.test.js が v3 theater.css と突き合わせる）を崩さないため */
  .dcb .dcb-timeup {
    position: absolute; left: calc(8px + var(--safe-left)); right: calc(10px + var(--safe-right));
    top: 10px; height: 44px;
    display: flex; align-items: center; gap: 6px;
    transition: opacity var(--dur-2) var(--ease-out), transform var(--dur-3) var(--spring-pop);
    pointer-events: none;
    opacity: 0; transform: translate3d(0, 10px, 0) scale(.97);
  }
  .dcb[data-mode="timeup"] .th-bar { opacity: 0; transform: translate3d(0, -10px, 0) scale(.97); }
  .dcb[data-mode="timeup"] .dcb-timeup { opacity: 1; transform: none; }
  .dcb[data-mode="timeup"] .dcb-timeup .dco-btn { pointer-events: auto; }
  .dcb .dco-tu { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; justify-content: center; line-height: 1.2; }
  .dcb .dco-tu-title { font: 800 15px/1.1 var(--font-display); color: var(--ink); letter-spacing: .02em; white-space: nowrap; }
  .dcb .dco-tu-sub { font: 700 11px/1.25 var(--font-body); color: var(--mute); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .dcb .dco-btn {
    flex: 0 0 auto; height: 38px; border: 0; border-radius: var(--r-pill); padding: 0 14px; margin: 0;
    background: var(--paper); color: var(--ink); font: 700 13px var(--font-body); white-space: nowrap;
    box-shadow: var(--sh-1), var(--hi-line);
  }
  .dcb .dco-btn.dco-primary { background: var(--ink); color: #fff; box-shadow: var(--sh-1); }
  @media (max-width: 359.98px) {
    .dcb .dco-btn { padding: 0 10px; font-size: 12px; }
    .dcb .dco-tu-sub { display: none; }
  }
  /* ● つくる（v3.css .recmini 287-293 行）。赤い地はここだけ。色はブランドの赤（WEBLOX で青） */
  .dcb .recmini {
    flex: 0 0 auto; height: 38px; border: 0; border-radius: var(--r-pill);
    background: var(--rec); color: #fff; padding: 0 14px 0 11px;
    display: inline-flex; align-items: center; gap: 7px; text-decoration: none;
    font: 700 13px var(--font-body); white-space: nowrap; box-shadow: var(--sh-rec), inset 0 1px 0 rgba(255, 255, 255, .25);
  }
  .dcb .recmini i { width: 10px; height: 10px; border-radius: 50%; background: #fff; display: block; }

  /* 押した手触り（v3.css .press 233-239 行）: 押している間 .96 に縮み、離すとばねで戻る */
  .dcb button, .dcb .press {
    transition: transform var(--dur-2) var(--spring-pop), background-color var(--dur-1) ease, color var(--dur-1) ease, box-shadow var(--dur-2) var(--ease-out), opacity var(--dur-1) ease;
  }
  .dcb button:not(:disabled):active, .dcb .press:active { transform: scale(var(--press-scale)); transition-duration: 90ms; }
  /* 焦点の輪（v3.css 165 行）。丸いボタンは丸いまま（角丸は各規則が持つ） */
  .dcb :focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

  /* ── 狭い画面: 列が収まらないときだけ畳む（data-fit は feed-band.js fitBand が実測して付ける）──
     ゆとりのある幅では属性が付かない = 上の規則のまま = v3 と 1px も変わらない（402px の突き合わせはそのまま）。
     経緯: 2 回目（2026-10-06）は「v3 と同じ」を優先して狭い画面の規則を外していたが、v3 の作りのままだと列の最小幅より
     狭い画面で「● つくる」が画面の外へはみ出して切れた（founder 2026-10-06「こうなっちゃうんだよね」・5 回目）。
     どの幅でも切れないことを v3 との 1px 一致より先にする（v3 側は触らない）。
     段は積み重ね（後の段は前の段を含む）。12 回目（2026-10-06）で順を入れ替え、「つくる」の字を消すのを最後にした
     （WHY は feed-band.js FIT_LEVELS。5〜11 回目は 'dot' = ● だけ が最初の段だった）。
     段 1 'tight' : 列の隙間 6→4px・← を 34→28px（印 22px はそのまま入る）。← は地に溶けるボタンなので見た目の差が小さい
     段 2 'norank': + 帯のランキングを隠す（作者パネルのチップは残る = 顔 → ランキング）
     段 3 'plus'  : + 「● つくる」を 40px の赤い丸の中の ＋ だけに。字は読み上げにだけ残す */
  .dcb[data-fit] .th-bar { gap: 4px; }
  .dcb[data-fit] .th-bar .th-rb.th-back { width: 28px; height: 28px; }
  /* ランキングを退かす（6 回目に帯に足した物。帯の中でいちばん新しく、作者パネルからも同じ物が開ける）。
     v3 の帯の物（スタンプ・コメント・シェア）はどの段でも隠さない */
  .dcb[data-fit="norank"] .th-bar [data-band="ranking"], .dcb[data-fit="plus"] .th-bar [data-band="ranking"] { display: none; }
  /* 「つくる」を丸に畳む。赤い地・影はそのまま、40px = 隣の白い丸と同じ大きさ。
     印は白い ●（<i>）ではなく ＋（v3 icons.js の plus・20px = 隣の白い丸の印と同じ大きさ）。founder「録画ボタンにしかみえないな」
     = 赤い丸に白い ● は録画の記号なので、本番の下のタブ・ドロワーの「＋ つくる」と同じ「新しく作る」の記号にする。
     字は .dcb-title と同じ隠し方で読み上げにだけ残す = 読み上げ名は「つくる」のまま・aria-label を別に持たない（文言が 1 か所）。
     字を display:none にしない（読み上げ名が消える） */
  .dcb .recmini .ic { display: none; }
  .dcb[data-fit="plus"] .recmini { position: relative; width: 40px; height: 40px; padding: 0; gap: 0; justify-content: center; }
  .dcb[data-fit="plus"] .recmini i { display: none; }
  .dcb[data-fit="plus"] .recmini .ic { display: block; flex: 0 0 auto; width: 20px; height: 20px; }
  .dcb[data-fit="plus"] .recmini [data-band-make-text] {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
  }

  /* ── スタンプの列（94-115 行）: 横スクロール。押したスタンプには墨の輪。1 つずつ弾んで出る ── */
  .dcb .th-st-scroll {
    flex: 1 1 auto; min-width: 0; height: 100%;
    display: flex; align-items: center; gap: 6px; overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain;
    scroll-snap-type: x proximity; scrollbar-width: none; touch-action: pan-x;
    padding: 0 2px;
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 10px, #000 calc(100% - 18px), transparent 100%);
    mask-image: linear-gradient(90deg, transparent 0, #000 10px, #000 calc(100% - 18px), transparent 100%);
  }
  .dcb .th-st-scroll::-webkit-scrollbar { display: none; }
  .dcb .th-st {
    flex: 0 0 auto; width: 42px; height: 42px; border: 0; border-radius: 50%; scroll-snap-align: start; padding: revert;
    background: var(--paper); font-size: 22px; line-height: 1; display: grid; place-items: center;
    box-shadow: var(--sh-1), var(--hi-line);
  }
  .dcb[data-mode="stamps"] .th-st { animation: th-st-in var(--dur-3) var(--spring-pop) both; animation-delay: calc(var(--i, 0) * 16ms); }
  .dcb .th-st.is-mine { box-shadow: 0 0 0 2px var(--ink), var(--sh-1); }
  .dcb .th-st-x {
    flex: 0 0 auto; height: 40px; border: 0; background: none; padding: 0 6px 0 8px;
    font: 700 13px var(--font-body); color: var(--mute); white-space: nowrap;
  }

  /* ── お知らせ（本番だけの顔: XP カードが帯の場所に出ている間）: 列は退き、右端の ✕（白い丸 = .th-rb）だけ ── */
  .dcb .dcb-notice { justify-content: flex-end; }
  /* カード（枠の中・z 8）は帯（フィードの器・z 8・地の色あり）より後ろの DOM に居ないので、同じ段だと帯に塗りつぶされる。
     1 段上げて帯の上に出す。カードの右端は ✕ の手前（right: 8 + 44 + 8px）で止まるので ✕ とは重ならない */
  .tag-feed .dcf-item .xp-card { z-index: 9; }
  /* カードの右端 = 行動の列（スタンプ）の手前。値は feed-band.js placeNoticeCard が帯の器（.tag-feed）に置く
     --dcb-notice-right（px）。測れない回（列が空）は game-social.css の従来の right（✕ の手前まで）に落ちる */
  .tag-feed .dcf-item .xp-card { right: var(--dcb-notice-right, calc(8px + var(--dcf-ctrl-h, 44px) + 8px)); }
  /* 360px 未満（iPhone SE 等）はカードが 86px しか取れず「+10 XP」が「+…」に切れた（2026-10-06 撮影）。
     レベルの輪（34px）を畳んで、いちばん伝えたい獲得量を読めるようにする。列は動かさない（ボタンが跳ねない） */
  @media (max-width: 359.98px) {
    .tag-feed .dcf-item .xp-card--strip .xp-card-ring { display: none; }
    .tag-feed .dcf-item .xp-card--strip .xp-card-inner { padding-left: 12px; }
  }
  /* 6 回目（2026-10-06）: 帯にランキング（40px + 隙間 6px）が増え、カードの右端がその分手前に来た。画面の幅で決める上の
     @media では足りなくなった（ja 375px でカード 86px・「+10 XP」が 25px に切れた。WebKit で 6 言語 × 280〜430px を実測）。
     カードの幅は言語（「つくる」の幅 → 畳みの段 → 列の左端）で変わるので、**カード自身の幅**で決める（コンテナクエリ）。
     112px = 輪 34 + 隙間 8 + 左右の余白 5 + 12 + 「+10 XP」（14px 太字）の 48px + 余裕 5。ja 402px（カード 113px）は輪を残す。
     上の @media はコンテナクエリの無い古い Safari（15 以前）のための控え（同じ見た目に落ちる） */
  .tag-feed .dcf-item .xp-card--strip { container-type: inline-size; }
  @container (max-width: 111.98px) {
    .tag-feed .dcf-item .xp-card--strip .xp-card-ring { display: none; }
    .tag-feed .dcf-item .xp-card--strip .xp-card-inner { padding-left: 12px; }
  }
  /* 12 回目（2026-10-06）: 帯の畳む順を「つくる の字を消すのは最後」に入れ替えた（feed-band.js FIT_LEVELS）。XP カード中も
     段は同じ規則なので、字の残った「つくる」（opacity 0 でも幅は取る = 列は跳ねない）の分だけ列の左端が左へ寄り、カードが
     最小 72px（en / pt 300px・zh 340px）まで細った。左右 12px の余白のままだと「+10 XP」（14px 太字 ≈ 50px）が切れたので、
     84px 未満（5〜11 回目の最小 = 84px）のカードだけ左右の余白を 6px に詰める。72px でも字の幅 60px = 「+100 XP」まで入る。
     WHY 列（畳みの段）の方を変えないのか: XP カードが出た瞬間だけ段を変えるとスタンプ・コメント・シェアが横に跳ねる。
     カードの中だけで吸収すれば、押す的は動かない */
  @container (max-width: 83.98px) {
    .tag-feed .dcf-item .xp-card--strip .xp-card-inner { padding-left: 6px; padding-right: 6px; }
  }

  /* ════════════════ 作者パネル（帯の顔 → public/js/modules/feed-creator-panel.js・2026-10-06 3 回目）════════════════
     v3 の作者パネル（creator.js）と押し上げパネル（ui.js panel()）の見た目を写す。値は v3.css .ppanel / .pp-*（507-532 行）・
     .pill（359-366 行）・.btn / .btn-row（296-306 行）・.rowlist（415-422 行）・.av（379-385 行）・.sk（553-556 行）・
     base（129-167 行の a / button / :focus-visible / .ic）と theater.css 116-191 行（.th-pp / .th-chips / .th-rank / .th-maker /
     .th-mini）。規則は .dcp の中だけ（v3.css を読むと本番の殻の他の部品まで変わる = 上の WHY と同じ）。

     置き方（本番だけの違い）: v3 はゲームと帯の間（縦の flex）に差し込む。本番の舞台は枠ごとの絶対配置なので、パネルは
     フィードの器（.tag-feed）の下端に絶対配置で置き、舞台は JS が transform: scale で縮める（feed-creator-panel.js の WHY）。
       - 高さ: v3 の flex-basis 62%（creator.js basis）。v3 は安全領域の上を除いた高さに対する % なので、ここも --dcf-top-inset を引く
       - z-index 10: 帯（8）・XP カード（9）の上、シート（--tl-z-sheet 2110）・ランキング・シェアの下（パネルからそれらを開ける）
       - 帯は隠す（v3 theater.js syncStripHidden: 携帯はパネルの間 帯を隠す）。掴み帯（.dcf-strip）はパネルの下に隠れる */
  .tag-feed.dcp-on .dcb { display: none; }
  /* 縮めた舞台は跳ねない（game-feed.js の .dcf-stage は引いたときの transform に .42s のばねを持つ）。v3 も枠は一度に縮む */
  .tag-feed .dcf-stage.dcp-shrunk { transition: none; }
  .tag-feed > .dcp.ppanel {
    position: absolute; left: 0; right: 0; bottom: 0; z-index: 10;
    height: calc((100% - var(--dcf-top-inset, 0px)) * .62); min-height: 0;
    display: flex; flex-direction: column;
    background: var(--paper); border-radius: var(--r-lg) var(--r-lg) 0 0;
    box-shadow: var(--sh-3), var(--hi);
    animation: dcp-pp-in var(--dur-3) var(--ease-out) both;
    will-change: transform;
    /* v3.css body（133-144 行）: パネルの中の文字の土台 */
    color: var(--ink); font-family: var(--font-body); font-size: var(--fs-body); line-height: var(--lh-body);
    -webkit-font-smoothing: antialiased; font-feature-settings: "palt" 1; -webkit-tap-highlight-color: transparent;
    text-align: left;
  }
  .tag-feed > .dcp.ppanel.out { animation: dcp-pp-out var(--dur-2) var(--ease-out) both; }
  .dcp [hidden] { display: none !important; }
  .dcp a { color: inherit; text-decoration: none; }
  .dcp button { font: inherit; color: inherit; cursor: pointer; }
  .dcp img { display: block; max-width: 100%; }
  .dcp p { margin: 0; }
  .dcp .ic { display: block; flex: 0 0 auto; }
  .dcp :focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; border-radius: 8px; }
  /* 見出し（v3.css 524-530 行）。上端のつまみ = 「下げれば閉じる」 */
  .dcp .pp-h { position: relative; display: flex; align-items: center; gap: 10px; padding: 14px 12px 10px 14px; border-bottom: 1px solid var(--hair); touch-action: none; }
  .dcp .pp-h::before { content: ""; position: absolute; top: 5px; left: 50%; width: 34px; height: 4px; margin-left: -17px; border-radius: 4px; background: rgba(20, 20, 23, .14); }
  .dcp .pp-h .t { flex: 1; min-width: 0; }
  .dcp .pp-h b { display: block; font-size: 14.5px; font-weight: 900; line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .dcp .pp-h small { font-size: 11.5px; color: var(--mute); }
  .dcp .pp-x { border: 0; background: var(--ground); border-radius: var(--r-pill); padding: 6px 12px 6px 9px; font: 700 12px var(--font-body); color: var(--ink-2); display: inline-flex; align-items: center; gap: 3px; white-space: nowrap; }
  .dcp .pp-x .ic { width: 15px; height: 15px; }
  .dcp .pp-b { flex: 1; min-height: 0; overflow-y: auto; padding: 12px 14px; overscroll-behavior: contain; }
  .dcp .pp-f { padding: 8px 12px calc(12px + var(--safe-bottom)); border-top: 1px solid var(--hair); display: flex; flex-direction: column; gap: 8px; }
  /* 顔（v3.css .av 379-385 行・theater.css 117 行 .th-pp .th-pp-av .av / 182 行 .th-maker-h .av）。色は feed-band.js faceHtml */
  .dcp .av {
    position: relative; flex: 0 0 auto; width: var(--av, 36px); height: var(--av, 36px); border-radius: 50%;
    display: grid; place-items: center; overflow: hidden; color: #fff;
    font: 800 calc(var(--av, 36px) * .4) / 1 var(--font-display); background: var(--mute);
    box-shadow: 0 0 0 2px var(--paper);
  }
  .dcp .av img { width: 100%; height: 100%; object-fit: cover; }
  .dcp.th-pp .th-pp-av .av { --av: 30px; box-shadow: none; }
  .dcp .th-muted { margin: 0; font-size: var(--fs-sm); color: var(--mute); }
  /* 作者パネルの中身（theater.css 146-191 行） */
  .dcp .th-paw { display: flex; align-items: center; gap: 6px; margin: 0 0 10px; font-size: var(--fs-sm); font-weight: 700; color: var(--ok-ink); }
  .dcp .th-paw .ic { width: 15px; height: 15px; }
  .dcp .th-from { margin-bottom: 10px; }
  .dcp .th-from button {
    display: flex; align-items: center; gap: 7px; width: 100%; border: 0; text-align: left;
    background: var(--ground-2); border-radius: var(--r-sm); padding: 9px 11px;
    font: 700 12.5px var(--font-body); color: var(--ink-2);
  }
  .dcp .th-from button span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .dcp .th-from .ic { width: 16px; height: 16px; color: var(--mute); }
  /* ピル（v3.css 359-366 行）+ theater.css 156-161 行 */
  .dcp .pill {
    border: 0; background: var(--paper); border-radius: var(--r-pill); padding: 7px 13px;
    font: 700 12.5px var(--font-body); color: var(--ink-2); white-space: nowrap;
    box-shadow: var(--hi-line);
  }
  .dcp .pill.soft { background: var(--ground-2); box-shadow: none; }
  .dcp .pill[aria-pressed="true"] { background: var(--ink); color: #fff; box-shadow: none; }
  .dcp .th-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
  .dcp .th-chips .pill { display: inline-flex; align-items: center; gap: 5px; }
  .dcp .th-chips .pill .ic { width: 15px; height: 15px; }
  .dcp .th-chips .pill[aria-expanded="true"] { background: var(--ink); color: #fff; }
  .dcp .th-chips .pill:disabled { opacity: .5; }
  .dcp .th-chips .pill small { font: 700 9.5px/1 var(--font-mono); letter-spacing: var(--track-cap); text-transform: uppercase; margin-left: 2px; color: var(--mute); }
  /* 本番だけ: 送信中（favorite.js の pending）は薄く。v3 は楽観で塗るだけで送信中の印は無い */
  .dcp .th-chips .pill[aria-busy="true"] { opacity: .6; }
  .dcp .th-chipbody:empty { display: none; }
  .dcp .th-chipbody { margin-bottom: 12px; }
  .dcp .th-chip-sk { display: grid; gap: 8px; padding: 6px 0; }
  /* ランキングのチップの中身は本番の leaderboard.js（8 回目）。6 回目の自前の一覧（.th-rank）の規則は消した。着せ替えは下の「ランキング」の塊 */
  .dcp .th-howto p { margin: 0; font-size: 13.5px; line-height: var(--lh-body); color: var(--ink-2); white-space: pre-line; }
  .dcp .th-blurb { margin: 0 0 12px; font-size: 13.5px; line-height: var(--lh-body); color: var(--ink); }
  .dcp .th-maker { margin-top: 4px; }
  .dcp .th-maker-h { display: flex; gap: 10px; align-items: flex-start; }
  .dcp .th-maker-h .av { --av: 36px; box-shadow: none; }
  .dcp .th-maker-h > div { flex: 1; min-width: 0; }
  .dcp .th-maker-h b { display: block; font-size: 13.5px; font-weight: 800; }
  .dcp .th-bio { margin: 2px 0 0; font-size: var(--fs-sm); color: var(--ink-2); line-height: 1.5; overflow-wrap: anywhere; }
  .dcp .th-bio .sk-line { display: block; margin-top: 4px; }
  .dcp .th-mini { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-top: 12px; }
  .dcp .th-mini > .sk { aspect-ratio: 3 / 4; border-radius: 12px; }
  .dcp .th-mini button {
    border: 0; padding: 0; background: none; text-align: left; display: flex; flex-direction: column; gap: 5px; min-width: 0;
  }
  .dcp .th-mini-th { display: block; width: 100%; aspect-ratio: 3 / 4; border-radius: 12px; overflow: hidden; background: var(--ground-2); box-shadow: var(--sh-1); }
  .dcp .th-mini-th img { width: 100%; height: 100%; object-fit: cover; display: block; }
  .dcp .th-mini-t { font-size: 11.5px; font-weight: 700; color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* .th-how（下の 1 行「つくりかたを見る」）は 2026-10-07 にチップ「作り方」へ移して消した = 規則も消す */
  /* 1 行の並び（v3.css .rowlist 415-422 行）= 本番だけの行 */
  .dcp .rowlist { display: grid; gap: 6px; }
  .dcp .rowlist > button, .dcp .rowlist > a {
    display: flex; justify-content: space-between; align-items: center; gap: 12px; width: 100%;
    border: 0; background: var(--ground-2); border-radius: var(--r-sm); padding: 13px 14px;
    font: 700 13.5px var(--font-body); color: var(--ink); text-align: left;
  }
  .dcp .rowlist small { display: block; font-weight: 500; font-size: 11.5px; color: var(--mute); margin-top: 1px; }
  .dcp .rowlist .ic { width: 18px; height: 18px; color: var(--faint); }
  /* 本番だけの行（お題・系譜・編集・スタッフ）は「つくりかた」の下に同じ形で続く。タグは v3 の .pill.soft の並び */
  .dcp .dcp-extra { margin-top: 14px; display: grid; gap: 10px; }
  .dcp .rowlist > button:disabled { opacity: .5; }   /* スタッフの「順番待ち」等（押せない）は v3 机の .rowlist の押せない形 */
  .dcp .dcp-tags { display: flex; flex-wrap: wrap; gap: 6px; }
  /* ボタン（v3.css 296-306 行） */
  .dcp .btn {
    flex: 1; border: 0; border-radius: var(--r-sm); padding: 12px 14px; min-height: 46px;
    font: 700 14px var(--font-body); background: var(--ground); color: var(--ink);
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  }
  .dcp .btn .ic { width: 18px; height: 18px; }
  .dcp .btn.pri { background: var(--ink); color: #fff; box-shadow: 0 6px 16px -10px rgba(20, 20, 23, .7), inset 0 1px 0 rgba(255, 255, 255, .12); }
  .dcp .btn-row { display: flex; gap: var(--s-2); }
  .dcp .btn.is-busy { opacity: .6; }
  /* 読み込み中（v3.css 553-556 行・光が流れる） */
  .dcp .sk { position: relative; overflow: hidden; background: #E9E9ED; border-radius: var(--r-xs); }
  .dcp .sk::after { content: ""; position: absolute; inset: 0; transform: translateX(-100%); background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .7), transparent); animation: dcp-sk-shine 1.3s var(--ease-in-out) infinite; }
  .dcp .sk-line { height: 11px; border-radius: 6px; }
  /* 押した手触り（v3.css .press 233-239 行） */
  .dcp button, .dcp .press {
    transition: transform var(--dur-2) var(--spring-pop), background-color var(--dur-1) ease, color var(--dur-1) ease, box-shadow var(--dur-2) var(--ease-out), opacity var(--dur-1) ease;
  }
  .dcp button:not(:disabled):active, .dcp .press:active { transform: scale(var(--press-scale)); transition-duration: 90ms; }

  /* ════════════════ ランキング = 本番の leaderboard.js を v3 に着せる（2026-10-06 8 回目）════════════════
     founder「ランキングに動画のせないとね」。6 回目は作者パネルのチップに 10 件の一覧を自前で描いた（2 つ目の実装）。
     8 回目は帯のランキング = 本番のシート（leaderboard.js）・作者パネルのチップ = 同じ部品の中身をチップの中へ移す
     （leaderboard.js mountInline）。中身の DOM（id / class: leaderboard-* / clip-*）は**本番のまま**で、ここは見た目だけ。
     置き場所は 2 つ:
       .leaderboard-sheet.dcl … 帯のランキングから開くシート（面が skinClass:'dcl' を渡す）
       .dcp                   … 作者パネルのチップの中（.leaderboard-content.lb-inline）
     値の出典は v3.css: .ppanel（507-532 行 = 白・上の角丸 --r-lg・--sh-3・つまみ 34x4）・.pill（359-366 行）・
       .btn.pri（305 行 = 墨）・theater.css .th-rank（168-178 行 = 一覧の行の形・順位の書体）・.th-mini-th（白い丸の影 --sh-1・角丸 12）。
     WHY 詳細度を 2 段以上にするのか: game-leaderboard.css は leaderboard.js が開いた時に <head> の**最後**へ差し込む
       （後勝ち）。同じ 1 段のセレクタだとあちらが勝つ。:is(.leaderboard-sheet.dcl, .dcp) は (0,2,0) + 1 段。
     インラインの style 属性を持つ部品（整理のトグル）だけ !important（leaderboard.js が属性で書いている = 本番の字面のまま）。
     動画の再生（clip-player.js）の動き・縦横の判定・ぼかしの背景（.clip-thumb-blurbg）は本番のまま（触らない）。 */

  /* シート（帯のランキングから）= v3 の押し上げパネル。高さは作者パネルと同じ basis 62%（安全領域の上を除いた高さ）。
     ゲームの枠はパネルの上に縮めて残す（games-by-tag-social.js pushStageForLeaderboard）= 暗幕は透明（タップで閉じる働きは残る） */
  .leaderboard-sheet-overlay.dcl { background: transparent; }
  .leaderboard-sheet.dcl {
    height: calc((100dvh - env(safe-area-inset-top, 0px)) * .62);
    background: var(--paper); border-radius: var(--r-lg) var(--r-lg) 0 0;
    box-shadow: var(--sh-3), var(--hi);
    transition: transform var(--dur-3) var(--ease-out);
    color: var(--ink); font-family: var(--font-body); font-size: var(--fs-body); line-height: var(--lh-body);
    -webkit-font-smoothing: antialiased; font-feature-settings: "palt" 1; -webkit-tap-highlight-color: transparent;
  }
  .leaderboard-sheet.dcl .leaderboard-sheet-drag { height: 22px; }
  .leaderboard-sheet.dcl .leaderboard-sheet-handlebar { width: 34px; height: 4px; border-radius: 4px; background: rgba(20, 20, 23, .14); }
  .leaderboard-sheet.dcl .leaderboard-content { padding: 4px 14px calc(16px + var(--safe-bottom)); overscroll-behavior: contain; }
  .leaderboard-sheet.dcl :focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
  /* 見出し「ランキング」+「とじる」（9 回目・追加 B）。値は作者パネルの見出しと同じ（上の .dcp .pp-h / .pp-x = v3.css .pp-h / .pp-x）
     = 帯から開く 2 つのパネルの見出しが同じ形。つまみ（.leaderboard-sheet-drag）は部品の物をそのまま上に残す */
  .leaderboard-sheet.dcl .dcl-h { display: flex; flex: none; align-items: center; gap: 10px; padding: 0 12px 10px 16px; border-bottom: 1px solid var(--hair); }
  .leaderboard-sheet.dcl .dcl-t { flex: 1; min-width: 0; font-size: 14.5px; font-weight: 900; line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .leaderboard-sheet.dcl .dcl-x { border: 0; background: var(--ground); border-radius: var(--r-pill); padding: 6px 12px 6px 9px; font: 700 12px var(--font-body); color: var(--ink-2); display: inline-flex; align-items: center; gap: 3px; white-space: nowrap; cursor: pointer; }
  .leaderboard-sheet.dcl .dcl-x .ic { width: 15px; height: 15px; }
  .leaderboard-sheet.dcl .dcl-x:active { transform: scale(var(--press-scale)); }
  .leaderboard-sheet.dcl .leaderboard-content { padding-top: 12px; }

  /* チップの中（作者パネル）: 中身の塊は器の高さに任せる（スクロールはパネルの .pp-b が持つ） */
  .dcp .leaderboard-content.lb-inline { flex: none; overflow: visible; padding: 2px 0 0; }

  /* 表彰台の帯（上位 3 人のプレイ動画）: 3 枚を 1 本の帯に見せる本番の形のまま、角を v3 の --r-sm・影 --sh-1 に */
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-clip-band { border-radius: var(--r-sm); box-shadow: var(--sh-1); background: var(--paper); }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-clip-card { background: var(--ground-2); }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-clip-card.vacant { background: var(--ground); }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-clip-rank { font-family: var(--font-display); font-weight: 800; }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-clip-score,
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-clip-card.no-clip .no-clip-score { font: 700 13px var(--font-mono); font-variant-numeric: tabular-nums; }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-clip-card.no-clip .leaderboard-clip-rank { color: rgba(20, 20, 23, .16); }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-clip-card.no-clip .no-clip-score { color: var(--ink); }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-clip-names { margin-bottom: 14px; }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-clip-names span { font: 700 11.5px var(--font-body); color: var(--ink-2); }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-clip-invite { margin: -6px 0 14px; font-size: var(--fs-sm); color: var(--mute); }

  /* 一覧（4 位以降）: v3 theater.css .th-rank li の形（地 --ground-2・角丸 --r-xs・行の間 4px・順位は Bricolage 800） */
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-list { gap: 4px; }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-entry {
    gap: 8px; padding: 6px 10px; border-bottom: 0; background: var(--ground-2); border-radius: var(--r-xs); font-size: 13px;
  }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-rank { min-width: 22px; font: 800 13px var(--font-display); font-variant-numeric: tabular-nums; color: var(--mute); }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-avatar { width: 26px; height: 26px; font-size: 15px; background: var(--paper); }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-name { font-size: 13px; font-weight: 700; color: var(--ink); }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-score { font: 700 12.5px var(--font-mono); font-variant-numeric: tabular-nums; color: var(--ink); }
  /* 行の ▶（その人のプレイ動画）= v3 の白い丸（.th-rb と同じ地・影） */
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-clip-btn {
    width: 30px; height: 30px; border: 0; background: var(--paper); color: var(--ink);
    box-shadow: var(--sh-1), var(--hi-line); font-size: 11px;
  }
  /* 自分の順位 = 墨（v3 の「いちばん押しやすい 1 つ」= .btn.pri と同じ地）。押すとゲームへ戻る（本番のまま） */
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-viewer {
    margin-top: 10px; gap: 8px; padding: 8px 10px; border-radius: var(--r-sm);
    background: var(--ink); box-shadow: 0 6px 16px -10px rgba(20, 20, 23, .7), inset 0 1px 0 rgba(255, 255, 255, .12);
  }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-viewer .leaderboard-rank,
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-viewer .leaderboard-name,
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-viewer .leaderboard-score { color: #fff; }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-viewer .leaderboard-avatar { background: rgba(255, 255, 255, .16); }

  /* 所有者の整理（トグル = v3 .pill.soft・一覧の文字 = v3 の書体）。トグルは leaderboard.js が style 属性で書くので !important */
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-manage-toggle {
    margin: 12px auto 0 !important; padding: 7px 13px !important; border-radius: var(--r-pill) !important;
    background: var(--ground-2) !important; color: var(--ink-2) !important; text-decoration: none !important;
    font: 700 12.5px var(--font-body) !important;
  }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-manage-list { font-family: var(--font-body); }

  /* 手紙（所有者に届いたプレイ動画）: 表彰台の帯と同じ角・影。見出しは v3 の小さい見出し */
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-letters { margin-top: 16px; }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-letters-title { font: 700 11.5px var(--font-body); letter-spacing: .02em; color: var(--mute); }
  :is(.leaderboard-sheet.dcl, .dcp) .leaderboard-letters-grid { border-radius: var(--r-sm); box-shadow: var(--sh-1); }

  /* Top3 変動カード（画面の上から降りてくる知らせ）: v3 の白い紙のカード */
  .lb-change-card.dcl .lb-change-card-inner {
    background: var(--paper); border: 0; border-radius: var(--r-sm);
    box-shadow: var(--sh-1), 0 12px 32px -12px rgba(20, 20, 23, .28), var(--hi-line);
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  .lb-change-card.dcl .lb-change-card-avatar { background: var(--ground-2); }
  .lb-change-card.dcl .lb-change-card-text { color: var(--ink); font: 700 13px var(--font-body); }
  .lb-change-card.dcl .lb-change-card-rank { font: 800 15px var(--font-display); }
  .lb-change-card.dcl .lb-change-card-rank[data-rank="1"] { background: var(--ink); }
  .lb-change-card.dcl .lb-change-card-rank[data-rank="2"] { background: var(--ink-2); border: 0; }
  .lb-change-card.dcl .lb-change-card-rank[data-rank="3"] { background: var(--mute); }

  /* プレイ動画の再生カード（clip-player.js）: 枠・文字・閉じるだけ v3 に。動画の段・進み具合の赤・エンドカードの動きは本番のまま */
  .leaderboard-clip-overlay .leaderboard-clip-box {
    border-radius: var(--r-lg); background: var(--paper); box-shadow: var(--sh-3);
    font-family: var(--font-body); -webkit-font-smoothing: antialiased; font-feature-settings: "palt" 1;
  }
  .leaderboard-clip-overlay .clip-player-name { font-weight: 700; color: var(--ink); }
  .leaderboard-clip-overlay .clip-player-sub { color: var(--mute); font-family: var(--font-mono); font-size: 11.5px; }
  .leaderboard-clip-overlay .clip-player-avatar { background: var(--ground-2); }
  .leaderboard-clip-overlay .leaderboard-clip-close { background: var(--ground); color: var(--ink-2); }
  .leaderboard-clip-overlay .leaderboard-clip-endcard .end-rank { font-family: var(--font-display); font-weight: 800; }
  .leaderboard-clip-overlay .leaderboard-clip-endcard .end-score { font-family: var(--font-mono); }
  .leaderboard-clip-overlay .leaderboard-clip-endcard .end-challenge { font: 700 14px var(--font-body); color: var(--ink); background: var(--paper); }
  .leaderboard-clip-overlay .leaderboard-clip-delete { font-family: var(--font-body); color: var(--mute); }

  @media (prefers-reduced-motion: reduce) {
    .leaderboard-sheet.dcl { transition: none; }
  }

  @media (prefers-reduced-motion: reduce) {
    .dcb .th-bar, .dcb .th-stamps, .dcb .dcb-notice { transition: opacity .01s; }
    .dcb .dcb-timeup { transition: opacity .01s; }
    .dcb[data-mode="stamps"] .th-st, .dcb .th-rb.has-stamp .th-glyph, .dcb .av.bump, .dcb .av-wrap.paw::after { animation: none; }
    .tag-feed > .dcp.ppanel, .tag-feed > .dcp.ppanel.out, .dcp .sk::after { animation: none; }
  }
}
/* 動きの形（v3 theater.css 78 / 109 行・v3.css 387 / 396 行）。名前は v3 と同じ（この殻の他の規則に同名は無い） */
@keyframes th-glyph-in { from { transform: scale(.4) rotate(-12deg); opacity: 0; } }
@keyframes th-st-in { from { transform: translateY(12px) scale(.6); opacity: 0; } }
@keyframes av-bump { 40% { transform: scale(1.22) rotate(-6deg); } }
@keyframes paw-in { from { transform: scale(0); } }
/* 作者パネルの出入り（v3.css 521-522 行 pp-in / pp-out・555 行 sk-shine）。名前に dcp- を付ける（この殻の他の CSS と衝突させない） */
@keyframes dcp-pp-in { from { transform: translateY(40%); opacity: .2; } }
@keyframes dcp-pp-out { to { transform: translateY(60%); opacity: 0; } }
@keyframes dcp-sk-shine { to { transform: translateX(100%); } }
