/* feed (SP-5) — composer + post cards + reactions
   ── 案 B v2.2 (owner 裁定 2026-09-04) ────────────────────────────────────────
   設計の正 = `.claude/design-discovery-archive/26-feed-appllama-research.md` §6.1〜§6.7。
   カードは **X 型の 2 列 grid** (avatar 列 / 内容列)。名前行は avatar と縦中央で揃え、
   本文以下は avatar の**下端 (52px) より下**から始めて「段」を作る (左右のずらしではなく
   縦の段差で著者ブロックと本文を識別させる = owner の理由への解)。
   ⚠ 階層は **サイズでなく weight と色**で作る (§6.3) — 本文 16.5 / 名前 15 / meta 15。
   ⚠ `--t-font-display` はカード内に使わない (§6.3 の表に無い)。 */

/* ── §6.2 の px を 1 箇所に集約 ──────────────────────────────────────────────
   ⚠ 本文左端は **68px 固定** (v2.1 の「16 / 40 / 52 から選ぶ」は撤回済み)。動かす時は
     `--feed-body-left` の 1 行だけを動かす。他の値は全て**上の 4 本**から算術で出す。
   ⚠ 5 本目の `--feed-react-max` は幾何の素ではない (算術に入らない・consumer は `.fc-react`
     1 箇所だけ) が、「値の正を 1 箇所に集める」趣旨は同じなのでここに並べる。
     値の由来 = §6.2 が基準面 390 で意図した行幅 = 内容列 306 × 78% = 238.68 ⇒ **240px**。
     ⚠ 実機の 390 は内容列が **290px** で `78%` = 226.19 なので `min()` はそちらを選び、
       **390 は 1px も動かない**。290 なのは `body` に UA 既定の margin 8px が残るため
       (`* { margin: 0 }` を持つ `core/base.css` を feed 系 5 面はどれも link していない)。
       その 8px が別 unit で是正されれば 390 の行幅も 238.68 になり、全面が同値へ寄る。
     ⚠ **`var()` に fallback を書かない** — 定義が同じ file にあるので fallback は到達不能で、
       240 という数字が 2 箇所へ散るだけになる (値の正が 2 つに見える)。 */
:root { --feed-pad: 16px; --feed-av: 40px; --feed-name-left: 68px; --feed-body-left: 68px;
        --feed-react-max: 240px; }

/* 容器の左右 gutter (= §6.2 の「容器 左右 padding 16px」) は **この 1 本**が持つ。
   ⚠ カード側に 16px を足さない — 二重になって本文左端が 68 ではなく 84 になる。 */
.feed-wrap { max-width: 600px; margin: 0 auto; padding: 1rem var(--feed-pad); }
.feed-composer { background: var(--t-surface); border: 1px solid var(--t-border); border-radius: 14px; padding: 1rem; margin-bottom: 1rem; }
/* 折り畳み時は 1 行だけ。初画面を投稿一覧に使う (展開は focus / 入力 / 添付で起きる) */
.feed-composer.is-collapsed { padding: 0.6rem 0.75rem; }
/* ⚠ **縦 padding は before と同値 (0.45rem) を保つ** — 折り畳み時の textarea が展開の
   hit 領域そのもの (wrapper に onClick は無い) なので、縮めると**投稿導線の入口が縮む**
   (Final 実測 39.38px → 27.78px = −29%)。横は展開時と同じ (下の内側の余白 + 同幅の張り出し)。 */
.feed-composer.is-collapsed .feed-compose-input { min-height: 0; padding-block: 0.45rem; overflow: hidden; }
/* C′ — 入力面の text input は **箱を持たない** (塗り・枠・角丸を落とす)。
   ⚠ **placeholder と min-height は残す** — 箱を外すと「ここに入力できる」の手がかりが
     placeholder と高さだけになるため。
   ⚠ 文字の左端は gutter (`.feed-composer` の padding) に揃えたまま (二重の内側余白を作らない)。
   🔴 **内側の余白は持つ** — 🗄️ 旧: 横 padding 0 で、本文も placeholder も focus の輪に貼り付いた
     (feed と引用の overlay の両方)。⇒ 余白 (`--t-sp-2`) を内側に取り、同じ幅だけ外へ張り出して
     文字の位置は動かさない (輪だけが外へ広がる)。角丸は輪の形のため (箱は描かない)。 */
.feed-compose-input { width: calc(100% + 2 * var(--t-sp-2)); margin-inline: calc(-1 * var(--t-sp-2)); box-sizing: border-box; min-height: 3.5em; resize: vertical; border: none; border-radius: var(--t-r-md); background: none; color: var(--t-fg); padding: var(--t-sp-2); font-family: inherit; font-size: 0.95rem; }
/* 🔴 **placeholder は token 化する** — 箱を外すと「入力できる」の手がかりが placeholder だけになるのに、
   ブラウザ既定色 (`#757575`) は **theme に追随しない**。dark では 2e 前から AA 未達 (4.17) で、
   下地が `--t-bg` → composer surface に変わって **3.96 まで深まる**。
   ⚠ **背景を戻しても直らない** (既定色が固定なので) — 効くのは色の指定。`--t-muted` で light 4.94 / dark 5.69。 */
.feed-compose-input::placeholder,
.fcm-alt::placeholder { color: var(--t-muted); }
/* C′ — 区切りは **入力域と操作域の間の 1 本だけ** (全ブロック間には引かない)。
   ⚠ 裁定の「本文 + カウンタの下」= ここ — 残りの字数 (`.feed-compose-count`) は本文と同じ入力域 (線の上・右寄せ) に
     置く (mobile の `compose-counter` と同じ位置)。🗄️ 操作域 (投稿ボタンの左) に置いた版は、390 の ja で
     公開 + ネタバレ + 字数 + 投稿が 1 行に入らず投稿が 2 行目へ落ちた (実測)。 */
.feed-compose-bar { display: flex; align-items: center; gap: 0.6rem; margin-top: 0.6rem; padding-top: 0.6rem; border-top: 1px solid var(--t-rule); }
/* chip 規則 — **塗りは透明・枠は残す**。
   ⚠ **選択中の accent 枠は当てない** — `<select>` は常に 1 つが選択されているので
     「選択中」に意味が無く、常時 accent になってしまう (hub 裁定 2026-09-03)。 */
.feed-compose-vis { padding: 0.4rem 0.5rem; border-radius: 8px; border: 1px solid var(--t-border); background: none; color: var(--t-fg); font-size: 0.85rem; }
/* 残りの字数 (数だけ) + 投稿 = 右寄せの 1 塊。 */
.feed-compose-btn { margin-left: auto; }
.feed-compose-count { display: block; text-align: right; margin-top: 0.3rem; color: var(--t-muted); font-size: 0.8rem; font-variant-numeric: tabular-nums; }
/* 本文が空の間は **押せない見た目** (mobile の `submitOff` + `submitLabelOff` と同じ token =
   `--t-surface-hover` の地 + `--t-fg-soft` の字)。⚠ 見た目だけ — 押せば「本文を入力してください」が出る。
   ⚠ 地は面 (`--t-surface`) とほぼ同じ明るさなので、縁は `--t-border` で示す。hover の浮き・影も落とす。 */
.btn.feed-compose-btn.is-empty,
.btn.feed-compose-btn.is-empty:hover { background: var(--t-surface-hover); color: var(--t-fg-soft); border-color: var(--t-border); box-shadow: none; transform: none; }
.feed-compose-msg { font-size: 0.8rem; color: var(--t-danger, #ff6b7e); margin-top: 0.4rem; }

/* ── For You / フォロー中 タブ (§6.6) ──────────────────────────────────────── */
/* X Home 型 — 幅 2 等分・sticky・**選択中だけ** 700 + 幅 56px / 高さ 2px の下線。
   ⚠ 文字色は選択中 `--t-fg` / 非選択 `--t-muted`。旧「選択中は `--t-accent`」は撤回 —
     §6.6 が accent を**下線**に割り当てたので、文字にも同じ色を使うと符号化が二重になる
     (accent はモノクロ ink なので文字に当てても `--t-fg` とほぼ見分けが付かない)。
   ⚠ sticky は ancestor に `transform` / `filter` / `mask-image` があると壊れる。
   🔴 **`top: 0` だと site header の裏へ完全に潜る** (実測 2026-09-05: 390 / 1440 とも
     scrollY>0 で重なり **47px = タブの全高**)。`/feed/` は `.site-header-bar`
     (`shared/css/layout/site-header.css` = sticky / top:0 / z-index 1000・不透明) を持ち、
     両方が `top: 0` だと同じ帯を奪い合って z-index 5 のタブが負ける。
     ⇒ `top` は **`--feed-tabs-top` (= header の実高)**。⚠ **magic 定数では振れ幅を追えない**
     (バー実高は言語と折返しで 56〜72px に振れる — 実測 390 = 67.38 / 1440 = 70.59) ので、
     先例の `--dm-top-offset` と同じ ResizeObserver で焼き直す
     (`ui/feed/FeedPage.tsx` の `FeedTabs` / 先例 = `ui/domain/DomainMapPage.tsx`)。
     ⚠ 既定値 `0px` は **sticky バーを持たない面**用 (`/` の `PortalHeader`)。 */
.feed-tabs { display: flex; position: sticky; top: var(--feed-tabs-top, 0px); z-index: 5; background: var(--t-bg); border-bottom: 1px solid var(--t-border); }
.feed-tab { flex: 1; position: relative; background: none; border: none; padding: 14px 8px; font-family: inherit; font-size: 15px; line-height: 1.2; text-align: center; color: var(--t-muted); cursor: pointer; }
.feed-tab.is-active { color: var(--t-fg); font-weight: 700; }
.feed-tab.is-active::after { content: ""; position: absolute; left: 50%; bottom: -1px; transform: translateX(-50%); width: 56px; height: 2px; border-radius: 2px; background: var(--t-accent); }
.feed-list { display: flex; flex-direction: column; }
.feed-empty { text-align: center; color: var(--t-muted); margin: 2.5rem 1rem; }
/* ⚠ 未 claim の案内「プロフィールを作成すると投稿できます。アカウント →」のリンク (`ui/feed/FeedPage.tsx`)。
   色を明示する — 無いと UA 既定の青い下線のまま (WEB-FEED-CLAIM-LINK-COLOR・dark で contrast も落ちる)。
   同じ文言の引用 overlay (`ui/feed/quote-compose-overlay.css` の `.qcv-noprofile a`) と同じ規則:
   `--t-accent` は monochrome ink (両 theme) なので、リンクだと分かるよう下線を残す。
   ⚠ `inline-block` + `nowrap` — リンクを 1 塊にして、折り返すならリンクの手前で折る。
     🗄️ 旧 (無指定): 390 で「ア / カウント →」と語の途中で折れた。nowrap だけだと、リンク先頭の空白で
     折れなくなり、今度は手前の文が「できま / す。」と折れた (どちらも板の実測)。 */
.feed-empty a { display: inline-block; color: var(--t-accent); text-decoration: underline; white-space: nowrap; }
.feed-empty-cta { display: flex; gap: 0.6rem; justify-content: center; flex-wrap: wrap; margin-top: 1rem; }
/* 「もっと見る」/ 続きの再試行 (bucket 3 PR-3a)。⚠ 見た目は共通 `.btn` — ここは配置だけ。
   /search/ の `.sr-more` と同値だが、/feed/ は **search.css を読まない**ので参照できない。
   🔴 強調のアスタリスク 2 個を **スラッシュの直前に置かない** — 2 個目のアスタリスクと
     スラッシュが comment 終端子になり、comment がそこで閉じる。残りの地の文は qualified rule
     の prelude として読まれ、次の中括弧ブロックまで飲み込むので **直後の `.feed-more` 規則が
     丸ごと捨てられていた** (v2.2 で発見・repo 内で唯一の実例)。強調は語の前に置く。 */
.feed-more { display: block; margin: 1.2rem auto 0; }
/* 🔴 D-2 (§6.7) — **一覧が残ったまま再取得に失敗した**時の 1 本のバー。app の `feed.stale`
   (`apps/mobile/src/ui/FeedList.tsx` の `staleBar`) を web にも置いたもの。
   ⚠ **一覧の上に重ねず、`.feed-list` の第 1 子として流れの中に置く** — 覆うと下のカードが
     読めなくなり「取れているものまで失った」に見える (器の型は ART_DIRECTION §4c)。
   ⚠ 押せるので 44px の床を課す (`.fc-react-btn` と同じ根拠)。全幅 block なので高さだけでよい。
   ⚠ 罫線はカードと同じ `--t-rule` 1 本 — ここだけ別の区切り方をしない (§2d)。 */
.feed-stale {
  display: block; width: 100%; box-sizing: border-box;
  min-height: var(--t-tap-min, 44px);
  padding: 0.7rem var(--feed-pad);
  background: none; border: none; border-bottom: 1px solid var(--t-rule);
  font-family: inherit; font-size: 0.85rem; color: var(--t-muted);
  text-align: center; cursor: pointer;
}
.feed-stale:hover { color: var(--t-fg); }

/* ── カード ────────────────────────────────────────────────────────────────── */
/* 🔴 v2.2 で**規則ごと消した 3 class** (役割が消滅・死んだ規則を残さない):
   - `.fc-head` — avatar と名前行が `.feed-card` の **直接の grid child** になったので、
     2 つを囲む flex 行が要らなくなった (囲いが残ると grid の列に乗らない)。
   - `.fc-report-btn` — 通報が `⋯` メニュー (`.fc-menu-item`) の中へ移った。
     ⚠ この規則が持っていた教訓は**残す**: 「**`opacity` を重ねない**」— 実効色は
       `color × opacity` で背景と混ざるので、muted token に 0.45 を掛けると dark 2.12 /
       light 1.84 まで落ちて操作が見えなくなる (非文字要素の下限は 3:1)。控えめさは muted
       token 自身が担う (実効 dark 5.69 / light 4.94)。
       ⇒ `.fc-more` / `.fc-menu-item` も **色の指定だけ**で控えめさを作っている
       (先例として `apps/web/test/app/color-contrast.test.ts:149` がこの実例を引く)。
   - `.fc-delete-btn` — 削除が `⋯` メニューへ移った。元々規則は 0 本 (action を取り違えない
     ための修飾 class) なので、消えるのは comment 上の参照だけ。メニュー側の赤字は
     `.fc-menu-item.fc-menu-danger` が持つ。 */
/* C′ (ART_DIRECTION.md:18) — 面の分離は**罫線が担う**。箱で囲うのは「それ自体が独立した
   単位」の時だけなので、feed item は hairline 区切りにする (composer と .fc-work は箱を残す)。
   ⚠ 区切りは `--t-border` ではなく **`--t-rule`** (罫線用の token・先例 = pages/onboarding.css)。
   ⚠ 横 padding は 0 — 罫線を .feed-wrap の幅いっぱいに引き、本文は composer と左端を揃える。
     (v2.2 でも同じ: 16px の gutter は `.feed-wrap` が持つので、ここで足すと二重になる。
      grid の算術だけが `--feed-pad` を参照する。)
   🔴 2 列 grid = [avatar 40px | 残り]。列間 12px は `68 − 16 − 40` の**算術**で出す
     (magic 定数を置かない = avatar 径や本文左端を変えれば全部が追随する)。
   ⚠ `position: relative` は `⋯` メニュー (`.fc-menu`) の containing block。
     **`transform` は置かない** — 置くと fixed 子孫の containing block が変わる。 */
.feed-card {
  position: relative;
  display: grid;
  grid-template-columns: var(--feed-av) minmax(0, 1fr);
  column-gap: calc(var(--feed-name-left) - var(--feed-pad) - var(--feed-av));
  row-gap: 0;
  padding: 12px 0;
  border-bottom: 1px solid var(--t-rule);
}
/* カード全体の tap → 投稿詳細 (FEED-POST-TAP-SCROLL-RESTORE)。押せるカードにだけ pointer を当てる
   (`/post/` 自身の描画 = `variant='full'` は印が無い = 押せない)。中の文字の選択は妨げない。 */
.feed-card[data-card-tap] { cursor: pointer; }
/* 末尾の 1 本は引かない (リストの下端は .feed-wrap の余白が担う)。
   ⚠ post 詳細は .feed-list に 1 枚だけ置くので、この規則が唯一の card にも効く。 */
.feed-list > .feed-card:last-child { border-bottom: none; }
/* 「〜がリポスト」の via 行 (会話層 B-2)。カードの一番上・著者ブロックの手前。
   ⚠ **導線を付けない** (plain text) — 主導線は著者と permalink で、ここにリンクを足すと
     Tab 順が「リポスト者 → 著者 → 時刻」の 3 本になる。⚠ 1 行に収める (名前で伸びる)。
   ⚠ grid の **第 2 列** (= 内容列と同じ左端 68px) に置く。avatar より上に出す。 */
.fc-via { grid-column: 2; margin: 0 0 3px; font-size: 13px; color: var(--t-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* ⚠ `align-self: start` — 名前行 (`.fc-meta`) が縦中央で揃うので、avatar 側を上端に固定
     しないと行高が変わったときに 2 つの中心がずれる。 */
.fc-av { grid-column: 1; align-self: start; position: relative; width: var(--feed-av); height: var(--feed-av); border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 700; color: var(--t-on-accent); text-decoration: none; background: var(--t-accent); }
/* 🔴 avatar は profile への一次導線なのに実測 **40×40** で 44 床に 4px 足りない。
   ⚠ **視覚サイズは変えない** — `--feed-av` を 44 にすると `column-gap: calc(68−16−40)` /
     avatar 中心 32 / 本文上端 52 の **3 つの不変条件が同時に壊れる** (上のコメント群)。
   ⇒ 透明な `::after` で**当たり判定だけ** 44×44 にする。**規則も理由も先例と同じ**なので
     ここには書き写さない — 正 = `apps/web/src/ui/shell/shell.css` の `.acct-nav-avatar::after`
     (`border-radius` を付けない理由 [円にすると対角の隅が的から外れる] もそこにある)。
     ⚠ 3 例目 (`AUTHOR_COLUMNS` +avatar / `.feed-rail-av`) が出たら共通 class へ畳む。
   ⚠ 本 unit の実測: はみ出しは上下左右 2px ずつで、**容器原点**の当たり右端 58px ⇔ 名前行の
     左端 68px = 重ならない (390 で 66 ⇔ 76 / 1440 で 448 ⇔ 458)。 */
.fc-av::after {
  content: '';
  position: absolute; left: 50%; top: 50%;
  width: var(--t-tap-min, 44px); height: var(--t-tap-min, 44px);
  transform: translate(-50%, -50%);
}
/* ⚠ 名前と handle を **1 行**に並べる — 縦積みは 1 件あたり約 18px を使い、
   20 件では 1 画面分の損になる。
   🔴 旧規則の `flex-wrap: wrap` (「折り返しは許す」) は **撤回できる** — v2.2 は名前行を
     `line-height/min-height 20px` の 1 行に固定し、その**中心 32px を avatar の中心に一致**
     させ、かつ本文の上端を **52px = avatar 下端**に置く。折り返すとこの 2 つの 🔴 不変条件が
     同時に壊れる。⇒ 逃がし方を「行を割る」から「1 行 ellipsis」へ差し替える
     (先例 = `ui/post/reply-thread.css` の `.rt-name`。表示名は 50 文字まで在り得る)。
   ⚠ `align-self: center` が中心 32px を作る (margin で作らない)。 */
.fc-meta { grid-column: 2; align-self: center; display: flex; align-items: center; gap: 5px; min-width: 0; line-height: 20px; min-height: 20px; }
.fc-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 15px; font-weight: 700; color: var(--t-fg); text-decoration: none; }
.fc-name:hover { text-decoration: underline; }
.fc-sub { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 15px; color: var(--t-muted); }
.fc-permalink { color: inherit; text-decoration: none; }
.fc-permalink:hover { text-decoration: underline; }
/* 🔴 `⋯` は**名前行の右端** (§6.4) — action 行には置かない。
   🔴 **hit area は 44 × 40** (hub 裁定 2026-09-05)。⚠ **縦を 40 より大きくしない** — 名前行の
     実効高がそのまま `.fc-meta` の高さになり、40px (= avatar 径) を超えた瞬間に grid 行が
     伸びて **本文上端 52px** (§6.2 の 🔴) が壊れる。40 ちょうどなら行の高さは avatar 律速の
     ままなので、**52px も「名前行の中心 32px」も動かない**。
   ⚠ 見た目は §6.2 の 26px のまま — 箱は塗りも枠も持たないので、広げても視覚は変わらず
     tap 目標だけが戻る (旧 `.fc-report-btn` は mobile で 44px だった)。
   ⚠ `margin-right` の負値は**光学的な端揃え** — 箱の余白ぶんだけ内側に見えるのを戻す。
     44px 幅なので `(44 − 18) / 2 = 13` が字形の外側に付く。容器の右 padding は 0 なので、
     行の右端と字形の右端を揃えるには **その半分強を戻す**。 */
.fc-more { margin-left: auto; flex: none; width: 44px; height: 40px; margin-right: -13px; display: inline-flex; align-items: center; justify-content: center; background: none; border: none; padding: 0; color: var(--t-muted); cursor: pointer; }
.fc-more:hover { color: var(--t-fg); }
/* ⚠ `⋯` も action 行と同じ 1.75 に揃える — `Icon` の既定は 2 で、FeedCard は `size` しか
   渡さない。揃えないと同じカード内で `⋯` だけ線が太く出る (§6.5 は 5 つを 1 つの表で並べる)。 */
.fc-more svg { stroke-width: 1.75; }
/* 本文以下 (本文 / media / 引用元 / 作品ブロック / action 行 / 返信 bar) を grid 全幅で受け、
   左端だけを変数で動かす。⚠ **本文の上端 52px は margin ではなくこの構造の帰結** —
   avatar の径を変えれば追随する (margin で作ると追随しない)。 */
.fc-below { grid-column: 1 / -1; min-width: 0; padding-left: calc(var(--feed-body-left) - var(--feed-pad)); }
/* 本文中の #tag リンク (Hashtags.linkify。 feed / tag / post 全カードで共有) */
.tag-link { color: var(--t-accent); text-decoration: none; font-weight: 600; }
.tag-link:hover { text-decoration: underline; }
.fc-worktag { margin: 0.5rem 0 0.2rem; font-size: 0.82rem; color: var(--t-accent); }
/* 🔴 **カードの面 = カバー画像そのもの** (owner 指示 2026-09-13) — 枠と内側の余白を剥がす。
   ⚠ hover の面 (`:hover` の背景) は**箱が無いと出せない**ので、負の margin ではなく
   `padding: 0` + hover を**文字色**へ移す。⚠ `gap` はカバーと文字の距離 = 参照の 10px。 */
.fc-work { display: flex; gap: 10px; align-items: center; margin: 11px 0 0; padding: 0; border: 0; text-decoration: none; color: var(--t-fg); }
.fc-work:hover .fc-work-name { text-decoration: underline; }
/* カバー統一 PR-2: 実体は components/work-cover.css (.work-cover--s 40px)。配置のみ */
.fc-work-cover { flex: 0 0 auto; }
.fc-work-name { font-size: 14px; font-weight: 600; line-height: 1.35; }
/* ⚠ 色は `--t-accent` から **`--t-muted`** へ (§6.3 の「作品 meta = 12.5px / 400 / muted」)。
   accent はモノクロ ink = 本文色とほぼ同値なので、meta に当てると作品名と同じ重さで出て
   階層 (本文 → 作品名 → 作品 meta) が 1 段潰れる。 */
.fc-work-tier { font-size: 12.5px; color: var(--t-muted); margin-top: 2px; }
/* workAffinity バッジ: この投稿が「あなたの作品」だから上位、を可視化 (taste-native 透明性) */
.fc-work-mine { display: inline-block; font-size: 0.72rem; font-weight: 700; color: var(--t-on-accent, #fff); background: var(--t-accent); border-radius: 999px; padding: 0.05rem 0.5rem; margin-top: 3px; }
/* 🔴 本文はカード内の**最重量** (§6.3) = 16.5px / 400 / 1.6 / `--t-fg`。
   ⚠ `margin-top` は 0 — 上端 52px は `.fc-below` の grid 位置が作る (margin で足すと 52 が狂う)。 */
.fc-body { margin: 0; font-size: 16.5px; line-height: 1.6; color: var(--t-fg); white-space: pre-wrap; word-break: break-word; }
.fc-body.fc-spoiler { filter: blur(6px); cursor: pointer; user-select: none; }
/* 🔴 admin 非表示の注記 (bucket 2 C1)。⚠ **本文と同じ書体で出さない** — 著者自身の
   文章と system の注記が見分けられなくなる。返信面の先例 `.rt-note`
   (`apps/web/src/ui/post/reply-thread.css`) と同じ扱いに揃える。 */
.fc-body.fc-hidden-note { color: var(--t-muted); font-style: italic; }
/* ⚠ 文字色は `--t-muted` ではなく **`--t-fg-soft`** — このバッジは「クリックで表示」の
   **押せるコントロール**であって副次情報ではない。加えて背景が `--t-muted` の 12% tint なので、
   同じ `--t-muted` を文字に使うと light で AA を割る (2b で下地が surface → bg に変わり 3.99)。
   ⚠ **背景 tint を薄くしても直らない** — 0% にしても 4.61 止まり。効くのは文字色の方。
   🔴 実体は `<button>` (`ui/feed/FeedCard.tsx`) — UA 既定の `background` / `border` /
     `padding` / 書体を全部この 1 本で明示する。`font-family: inherit` が要る理由 =
     下の `.fc-react-btn` の注記。
   ⚠ 床は **`--t-tap-sub`** (副次の tap 床・正 = `shared/css/core/tokens.css`) — 伏せを解く
     のは一次動作ではないので `--t-tap-min` は課さない。実測 154.2 × 20px は幅だけ足りて
     いたので、高さの床と `inline-flex` の中央寄せで**見た目の余白を増やさずに**箱を広げる。 */
.fc-spoiler-badge { display: inline-flex; align-items: center; min-height: var(--t-tap-sub, 32px); font-size: 0.78rem; font-family: inherit; color: var(--t-fg-soft); background: color-mix(in srgb, var(--t-muted) 12%, transparent); border: none; border-radius: 6px; padding: 0.2em 0.6em; margin: 0.3rem 0; cursor: pointer; }

/* ── action 行 (§6.4) ──────────────────────────────────────────────────────── */
/* 順序 = 返信 → リポスト → 引用 → ♥ (DOM 順もこの順)。`⋯` はここに置かない。
   ⚠ 枠 (pill) を持たない**アイコンだけ**を置く: 枠で押下状態を示す必要が無く、枠があると
     1 個だけ浮いて見える (押下は色 + stroke で示す)。
   🔴 4 つを `space-between` で送り、行の幅は **`--feed-react-max` の上限 px** が決める。
     ⚠ **`%` 単独に戻さない** — % は列幅に比例するので、同じカードが面ごとに違う送りになる。
       実測 (2026-09-06・匿名 light): `/post/` 1440 は card 928 で送り **166.38px**、390 は
       card 342 で **60.73px** = **2.74 倍**。`/work/` は 1279 → 1280 の 2 カラム化で
       **同一面のまま 166 → 100 に跳ぶ**。⇒ 上限 px にすると全面が 65.33px で揃う。
     ⚠ **`gap` へも置き換えない** — 件数の桁でボタン幅が動くと行の左右の端が浮く
       (`space-between` は端を固定して隙間の側で吸うので、端が動かない)。
     🔴 `min()` の `78%` は **390 でも効いている項**で、飾りではない — 390 の内容列は 290px
       なので `78%` = 226.19 < 240 となり `min()` はこちらを選ぶ。**これが「390 は 1px も
       動かない」の実体**なので、`min()` を外して `max-width: var(--feed-react-max)` に
       すると 390 の行が 226.19 → 240 へ黙って広がる (390 より狭い端末では更に行が容器
       いっぱいに開き、`space-between` が作る「まとまり」も壊れる)。
     ⚠ **「全面 65.33px で揃う」は 4 つの action が出るカードの話** — `canConverse` /
       `canRepost` が false のカード (admin 非表示 / 公開でない post) は 2 つ・1 つになり、
       `space-between` の性質どおり間隔が変わる。⚠ これは本 PR の前から同じで、上限を
       入れたぶん散らばりはむしろ小さくなる (1440 で 543 幅 → 240 幅の中での配置になる)。
     ⚠ 旧注記の「78% ⇒ 送り約 72px」は **44px 床が入る前の mock の値**だった (箱が約 22px の
       前提でのみ 72 になる)。44×44 の箱 (下の「タップ目標」節・owner 裁定 2026-09-04) が入った後の
       実装値は 390 で 60.73px で、72px は一度も出荷されていない。
     ⚠ **件数が長いと箱が縮んでインクが重なる**のは上限の有無に関わらず起きる (箱は
       `min-width: 44px` まで縮み、中身は `overflow` を持たない)。実測 (`/post/`):
       390 の現行 226.19 幅は **5 桁で −3.85px = 既に重なる**、240 幅は **5 桁で +0.78px・
       6 桁で −7.35px**。⇒ 本 PR は重なり始めを 5 桁 → 6 桁へ**遅らせる**側で、根治は
       件数の略記 (12.4K) = web / app 共通の商品判断なので別 unit。 */
.fc-react { display: flex; justify-content: space-between; align-items: center; max-width: min(78%, var(--feed-react-max)); margin-top: 9px; }
/* ⚠ `font-family: inherit` は要る — `<button>` は書体を継承せず UA 既定 (Arial 系) に落ちるので、
     中の件数 (`.fc-react-n`) だけ別書体で出て `tabular-nums` も効かない。 */
.fc-react-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  background: none; border: none; border-radius: 999px;
  padding: 0 2px; cursor: pointer;
  font-family: inherit;
  color: var(--t-muted);
}
/* 🔴 `.fc-react-btn` の規則は **要素セレクタで書かない** (統合者裁定 2026-09-04) — 4 つの
   action は `<button>` (リポスト / 引用 / ♥) と `<a>` / `<span>` (返信件数) に分かれるので、
   `button.` や `a.` で修飾すると**寸法・配置・44px の床が返信件数だけ外れる**。 */
.fc-react-btn:hover { background: color-mix(in srgb, var(--t-fg) 8%, transparent); color: var(--t-fg); }
/* 🔴 押下は **色 (`--t-fg`) + stroke 2.25** の 2 チャネル (§6.4 / ART_DIRECTION §4)。
   ⚠ 押下色を `--t-accent` から **`--t-fg`** へ変えた — accent はモノクロ ink 化で本文色と
     ほぼ同値になり、色**だけ**では無変化に見えた。2 本目のチャネルを stroke に置く。
   🔴 **`font-weight` は動かさない** (旧 `.fc-react-btn.on { font-weight: 600 }` は撤回) —
     4 つが等間隔で並ぶ行なので、文字幅が動くと隣の位置が飛ぶ
     (`.fc-repost-btn.is-on` が同じ理由で最初から色だけにしていた。判断を 1 本に揃える)。
   ⚠ **line icon を塗りに切り替えない** (ART_DIRECTION §4)。
   ⚠ `.fc-react-btn:hover` と同じ詳細度なので **後に置いて**勝たせる (押下済みを hover で
     グレーへ戻さない)。 */
.fc-react-btn.on,
.fc-repost-btn.is-on,
.fc-bookmark-btn.is-on { color: var(--t-fg); }
/* 🔴 **stroke は CSS が持つ** — `ui/icons.tsx` の `Icon` は `strokeWidth` の既定が **2** で、
   FeedCard は `size` しか渡さない。⇒ **CSS が書かないと §6.2 の 1.75 も押下の 2.25 も効かない**。
   ⚠ `stroke-width` は `<svg>` の **presentation attribute** で出る (`stroke-width="2"`) が、
     presentation attribute は author CSS より弱いのでここで上書きできる。値は `<svg>` から
     子 shape へ継承される。
   ⚠ **`width` / `height` はここに書かない** — 寸法は TSX の `size` が持つ (現在 4 つとも 18px)。
     §7 で `quote` だけ 17px に決まった場合に `.fc-quote-btn svg` で上書きする口を塞がないため。 */
.fc-react-btn svg { stroke-width: 1.75; }
.fc-react-btn.on svg,
.fc-react-btn.is-on svg { stroke-width: 2.25; }
/* 🔴 **押した ♥ は塗る** (owner 裁定 2026-09-26「塗りつぶす」) — 上の「line icon を塗りに切り替えない」
   (ART_DIRECTION §4) を **♥ に限って**上書きする。形は足さない: `heart` は閉じた path 1 本なので、`Icon` の
   `fill="none"` (presentation attribute) を押した時だけ CSS で上書きして同じ形を塗る。色は押した色
   (`--t-fg`) のまま。⚠ `.ic-heart` に絞る — リポスト (`.fc-repost-btn.is-on`) と他の icon は線のまま。
   返信の対は `apps/web/src/ui/post/reply-thread.css` の `.rt-react-btn.on .ic-heart`。 */
.fc-react-btn.on .ic-heart { fill: currentColor; }
/* 押した投稿の 🔖 も塗る (owner 裁定 2026-10-02・♥ と同じ扱い = ART_DIRECTION §4 の例外)。`bookmark` も閉じた path 1 本。
   tier の ♡ / 🔖 (`.tr-btn.on`) も同じく塗る (owner 裁定 2026-10-02・`apps/web/src/ui/tierlist/tier-reactions.css`)。 */
.fc-bookmark-btn.is-on .ic-bookmark { fill: currentColor; }
/* ⚠ `.fc-repost-btn` / `.fc-quote-btn` 自体には規則を持たせない — **action を取り違えない
     ための修飾 class**。片方だけ寸法や余白を上書きすると、同じ行に並ぶボタンの高さが揃わない。
   🔴 §7 (視覚重量) の**例外 1 本だけ**を `.fc-quote-btn` に持たせる — Lucide `quote` は
     18px / stroke 1.75 だと**閉じた 2 塊**で隣の 3 つより重く、2 版を同じカードで撮って
     **17px / stroke 1.5 を採った** (2026-09-05 実測)。
     ⚠ **size は TSX 側 (`<Icon size={17}>`)、stroke はここ** — 上の共有規則
       `.fc-react-btn svg { stroke-width: 1.75 }` は presentation attribute より強いので、
       TSX から `strokeWidth` を渡しても負ける。⇒ stroke だけは CSS で上書きするしかない。
     ⚠ これは**インクの密度合わせ**であって寸法・余白ではない — 上の「修飾 class に規則を
       持たせない」が守っている「同じ行のボタンの高さが揃わなくなる」は起きない
       (箱は `.fc-react-btn` の 44×44 のまま)。 */
.fc-quote-btn svg { stroke-width: 1.5; }
/* 件数は数字だけ (0 のときは要素ごと出さない = 反応の無さを強調しない)。
   ⚠ tabular — 桁が変わっても隣の action が動かない。 */
.fc-react-n { font-size: 13px; font-variant-numeric: tabular-nums; line-height: 1; }
/* 作成欄の「ネタバレ」は `ui/shared/Switch.tsx` の `SwitchInline` (CSS は `controls.css`)。 */

/* ── `⋯` メニュー (hub 裁定 2026-09-04) ────────────────────────────────────── */
/* 中身は **リンクをコピー / 通報 / 削除 (自分の投稿のみ)** の 3 つだけ。
   ⚠ 視覚文法は既存先例 `apps/web/src/ui/shell/shell.css:35-40` の `.acct-nav-menu` を踏襲
     (不透明 `--t-surface` + `--t-border` + radius 10 + 影)。**共通部品へ抽出しない** (1 用途)。
   🔴 背景は**不透明 surface token** (`docs/reference/CSS_COLOR_RULES.md §5` — 半透明の浮遊面は
     背後が透けて contrast が保証されない)。
   ⚠ 影は**この浮遊面だけ** — feed item には影・カード・大角丸を付けない (ART_DIRECTION §0)。
   ⚠ containing block は `.feed-card` の `position: relative`。 */
.fc-menu { position: absolute; top: 46px; right: 0; z-index: 1200; width: 230px; max-width: 100%; box-sizing: border-box; background: var(--t-surface); border: 1px solid var(--t-border); border-radius: 10px; padding: 5px; box-shadow: 0 8px 28px rgba(0, 0, 0, 0.3); }
/* ⚠ via 行があるカードは grid 全体が **1 行ぶん (≒19px = 13px の行 + margin 3px)** 下がる。
   `.feed-card` を基準にした `top` は追随しないので、via がある時だけ同じだけ下げる
   (兄弟結合子 = 「`.fc-via` を持つカード」の判定。⚠ `.fc-menu` は DOM 上 via より後ろ)。
   ⚠ 46 / 65 は `⋯` の直下に落とすための**見た目の値**で、不変条件ではない (§6.2 の px 表に
     メニューの位置は無い) — 実機で 1 度合わせたらそこで固定してよい。 */
.fc-via ~ .fc-menu { top: 65px; }
/* ⚠ `min-height: 44px` はここでは**課してよい** — 浮遊面の高さは他の不変条件に載っていない
   (名前行の `⋯` と違い grid 行を伸ばさない)。滅多に使わない操作こそ押しやすくする。 */
.fc-menu-item { display: flex; align-items: center; gap: 11px; width: 100%; box-sizing: border-box; min-height: var(--t-tap-min, 44px); padding: 9px 10px; border: none; border-radius: 6px; background: none; font-family: inherit; font-size: 14.5px; text-align: left; text-decoration: none; color: var(--t-fg); cursor: pointer; }
.fc-menu-item:hover { background: color-mix(in srgb, var(--t-accent) 14%, transparent); }
/* ⚠ 削除だけ `--t-danger`。修飾 class は `.fc-menu-*` 系で揃える (`ui/feed/PostMenu.tsx` と同名)。
   旧 `.fc-delete-btn` は行内ボタンごと役目を終えたので使わない。 */
.fc-menu-item.fc-menu-danger { color: var(--t-danger, #ff6b7e); }
.fc-menu-sep { height: 1px; margin: 4px 0; background: var(--t-border); }

/* ── 他人の盤面の `⋯` メニュー (`ui/tier/TierViewMenu.tsx`・TIER-VIEW-BRUSHUP) ──────────────
   3 面 (`/tier/?u=`・`/tierlist/?b=`・profile の Tier タブ) が使う。3 面とも link するのは
   この file なので、panel の中身 (`.fc-menu` / `.fc-menu-item`) の隣に置く。
   ここが持つのは trigger と panel の位置だけ (panel の見た目は上の `.fc-menu` のまま)。
   🗄️ PR-1 (#1152) では `tier-board.css` に置いた — profile は `tier-board.css` を読まないので移した。
   ⚠ panel は 44px の trigger の包みを containing block にする。`.fc-menu` の `max-width: 100%` が
     44px に解決して潰れるので `max-width: none` で外す (`profile.css` の `.fc-menu.pp-menu` と同じ理由)。
     包みは行の右端に在るので、230px の panel は右端を揃えて左へ開く。
   ⚠ 詳細度を上げて書く (`.fc-menu.tl-view-menu`) — 同じ 1 class では `<link>` の順で勝敗が決まる。 */
.tl-view-more-wrap { position: relative; flex: none; display: inline-flex; }
.fc-menu.tl-view-menu { top: calc(100% + 4px); right: 0; max-width: none; }
/* ⚠ button は background / color / border を明示する (UI 規約)。
   ⚠ 44×44 の一次動作の床 — リンクのコピー / 通報への唯一の入口 (`.pp-more` と同じ)。 */
.tl-view-more {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--t-tap-min, 44px); height: var(--t-tap-min, 44px);
  padding: 0;
  background: none; border: none; border-radius: 999px;
  color: var(--t-muted); cursor: pointer;
}
.tl-view-more:hover { color: var(--t-fg); }
.tl-view-more:focus-visible { outline: 2px solid var(--t-accent); outline-offset: 2px; }

/* ── 画像添付 (5M-PR5)。表示側 (.pm-*) は ui/shared/post-media.css が所有 ─── */
.feed-compose-attach { padding: 0.35rem 0.6rem; display: inline-flex; align-items: center; }
.feed-compose-media { display: flex; align-items: flex-start; gap: 0.5rem; margin: 0.4rem 0; flex-wrap: wrap; }
.fcm-preview { display: block; max-width: 120px; max-height: 120px; border: 1px solid var(--t-border); border-radius: 10px; object-fit: cover; background: var(--t-surface); }
/* alt も text input — 同じ規則 (箱を落とす)。⚠ preview の隣に並ぶので上下の余白だけ残す。 */
.fcm-alt { flex: 1 1 12rem; min-width: 0; border: none; border-radius: 0; background: none; color: var(--t-fg); padding: 0.2rem 0; font-size: 0.85rem; font-family: inherit; }
.fcm-remove { background: none; border: 1px solid var(--t-border); border-radius: 999px; color: var(--t-muted); cursor: pointer; padding: 0.25rem 0.45rem; display: inline-flex; align-items: center; }
.fcm-remove:hover { color: var(--t-danger, #ff6b7e); border-color: var(--t-danger, #ff6b7e); }
.fcm-busy { font-size: 0.82rem; color: var(--t-muted); }
.fcm-error { font-size: 0.82rem; color: var(--t-danger, #ff6b7e); }

/* ── 返信 ────────────────────────────────────────────────────────────────── */
/* 🔴 返信は **件数 + post 詳細への導線だけ** (2f-4)。⚠ post 詳細では `<span>` で出す
   (自分自身への no-op 導線を作らない = mobile `messages.ts` の F4 裁定と同じ理由)。
   🔴 寸法・色・hover は **`.fc-react-btn` が持つ** — `ui/feed/FeedCard.tsx` が
     `class="fc-react-btn fc-reply-count"` で併用し、4 つの action の 44×44 を 1 本の規則に
     畳んだため。ここに残るのは「どの action か」の修飾と、`<a>` の UA 下線を落とす 1 本だけ。
   ⚠ hover の下線は撤回 — アイコン化で下線が掛かる文字が無くなった。 */
.fc-reply-count { text-decoration: none; }
/* 🔴 post 詳細の件数だけ **押せる感じを外す** — そこは `<span>` (自己リンクを作らない F4 裁定)
   なのに `.fc-react-btn` を併用するので、そのままだと `cursor: pointer` と hover の面が付いて
   **「押せて無反応」** = `<span>` にした理由そのものを打ち消す。
   ⚠ 打ち消すのは **affordance だけ**で、寸法・配置・44px の床は `.fc-react-btn` のまま
     (行の 4 つの箱を不揃いにしない)。⚠ 要素セレクタを使うのは `fc-reply-count` の側であって
     `.fc-react-btn` ではない (統合者裁定の禁止対象は後者)。 */
span.fc-reply-count { cursor: default; }
span.fc-reply-count:hover { background: none; color: var(--t-muted); }
/* ⚠ 以下 5 本は **`ui/feed/ReplyCompose.tsx` の composer** — 2f-4 で feed カードから返信 UI が
   消えた後も、post 詳細のスレッド (`ui/post/ReplyThread.tsx`) が同じ部品を使う。 */
.fc-reply-compose { margin-top: 0.35rem; }
/* ⚠ 内側の余白は feed の作成欄 (折り畳み時の `.feed-composer` = 縦 0.6 + 0.45rem / 横 0.75rem) と揃える。
   🗄️ 旧: 横 0.5rem・高さ 2rem で placeholder が枠の左端に貼り付いて見えた (PR-3 before 実測 = 8px / 32px)。
   ⚠ 高さは 44 の床 (`--t-tap-min`) — 1 行の入力欄が返信の入口そのもの。 */
.fc-reply-input { width: 100%; box-sizing: border-box; resize: vertical; min-height: var(--t-tap-min); font-family: inherit; font-size: 0.88rem; padding: 0.6rem 0.75rem; border: 1px solid var(--t-border); border-radius: 8px; background: var(--t-bg); color: var(--t-fg); }
.fc-reply-input::placeholder { color: var(--t-muted); }
.fc-reply-bar { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.3rem; }
.fc-reply-msg { font-size: 0.78rem; color: var(--t-danger, #ff6b7e); margin-right: auto; }
.fc-reply-send { padding: 0.2rem 0.8rem; font-size: 0.82rem; }

/* ── タップ目標 ─────────────────────────────────────────────────────────── */
/* 🔴 (2026-08-30 mobile view 精査 batch 2 / G-4) — 実測 いいね 30×26 / 返信する 59×27 /
   通報 27×24。カード内の**唯一の操作**なので主導線に当たる。
   ⚠ batch 1 (#549) は shell (ヘッダ・フッタ・bnav・バナー) に絞ったのでここは未計測だった。
   ⚠ **見た目を変えない** — `padding` を上げると行が太るので `min-height/min-width` と
     中央寄せだけで箱を広げる (アイコンと文字の位置は動かない)。
   🔴 **`@media (max-width: 767px)` の囲いは撤回** (owner 裁定 2026-09-04) — 44px は
     指の寸法の話で viewport の話ではない。action 行は §6.2 で `space-between` の等間隔に
     なったため、PC で 44px を外すと**幅ごとに当たり判定が変わる**方が事故になる。 */
.fc-react-btn {
  /* ⚠ `min-width` も要る — いいねは アイコン + 件数だけで **実測 40px 幅**しかなかった。 */
  min-width: var(--t-tap-min, 44px);
  min-height: var(--t-tap-min, 44px);
}
/* ⚠ リポスト / 引用は **上の `.fc-react-btn` が既に覆っている** — 両方とも
   `class="fc-react-btn fc-repost-btn"` / `"fc-react-btn fc-quote-btn"` で描くので、
   修飾 class を selector 列へ足す必要は無い (足すと同じ規則が 2 本になる)。 */
/* 🔴 旧 `a.fc-reply-count { min-height }` (「**押せる時だけ**課す」) は **撤回できる** —
   旧規則の理由は「post 詳細の件数は `<span>` なので、44px を課すと**押せない文字が縦に伸びる
   だけ**になる」だった。v2.2 で返信件数はアイコン + 数字になり、`<span>` / `<a>` の両方が
   `.fc-react-btn` を併用して**等間隔に並ぶ 4 つの箱の 1 つ**になったので、床を外す方が行が
   不揃いになる。⇒ 箱は上の `.fc-react-btn` に一本化し、**押せる感じ (cursor / hover) の方を
   `button` / `a` に限定**して「押せない文字が押せて見える」を防ぐ (上の hover 規則)。 */
/* 🔴 PR-3a で**新設**した「もっと見る」も同じ規則に載せる — `.btn` の既定は
   実測 padding 0.65rem 上下 = 44px に届かない。⚠ 既存の不揃い (`/search/` の `.sr-more`)
   を揃えに行くのではなく、**新しく足す主導線を最初から規則内に置く**だけ
   (`/tag/` の `.tag-more` が batch 4 で同じ形を採っている)。
   ⚠ `min-width` は足さない — block + `margin: auto` で既に十分広い。
   ⚠ こちらも media query を外した — `.feed-more` は **block の全幅ボタン**なので自由な寸法は
     高さだけで、PC で 44px を課しても横幅も配置も動かない (= 分岐を持つ理由が無い)。 */
.feed-more { min-height: var(--t-tap-min, 44px); }

/* ── 1280px 以上の 2 カラム = 中央 640 + 右レール (案 B v2.2 PR-B) ────────────
   px の正 = 1440 mock: `.pc-mid { border-right: 1px solid var(--t-border) }` /
   `.pc-side { padding: 20px 20px 0 }` / 中央 **640**。
   🔴 **左の常設ナビは `SiteDrawer` の常時展開 (300px)** — `body[data-drawer-pinned="1"]
     { padding-left: 300px }` (`shared/css/layout/drawer.css`) が既に本文を右へ寄せている。
     ⇒ ここは残りを 中央 640 + 右レール に割るだけ。⚠ **mock は左 220 前提で右レール 580
     だったが、常設ナビが 300 になったぶん右レールはその差だけ狭くなる**
     (viewport 1440 で 1440 − 300 ≈ 1140 → 640 + 約 490)。中央 640 は不変。
   🔴 **開始幅が 1280 なのは右レールの下限から逆算した値** — 300 (drawer) + 640 (中央)
     + 300 (レールの実用下限・Bluesky の右列と同値) ≈ 1240。1200 のままだと
     レールの中身が padding 20×2 を引いて **約 220px** しか残らず、人の行も重みの表も潰れる。
   ⚠ レールの **mount 判定は JS** (`ui/shell/useWideChrome.ts` の `FEED_RAIL_MIN_WIDTH`)。同じ
     1280 を 2 箇所が持つので動かす時は 2 つとも動かす (CSS の値を JS から読む口は無い)。
     ⚠ **consumer は `/feed/` だけではない** — `/post/` (案 B) も同じ閾値で 2 カラムへ切替える
       (容器は `pages/post/index.html` の page 固有 CSS)。動かす時は両面を見ること。
     CSS で隠すだけにしないのは、レールの twin 取得を狭い画面で走らせないため。
   🔴 **素の `.feed-wrap` ではなく修飾子 `.feed-wrap--rail` で引く** — `.feed-wrap` は
     `/feed/` 専用ではなく、`/` の二相容器 (`ui/root/RootPage.tsx:174` の
     `<section id="feed-root" class="feed-wrap" hidden>`) と共有している。素で引くと、
     **常設ナビが出ない root (`variant='portal'`) まで 2 カラムになる** (hub 裁定 =
     root の chrome は現状のまま)。修飾子は `/feed/` の `main.tsx` だけが付ける。 */
@media (min-width: 768px) {
  /* 中央列は mock の 640 (768px 未満は素の `.feed-wrap` と同じ 600)。
     ⚠ 値は `tokens.css` の `--t-page-max-timeline` が持つ (`/tag/` と同値・面ごとに書かない)。 */
  .feed-wrap--rail { max-width: var(--t-page-max-timeline, 640px); }
}
@media (min-width: 1280px) {
  .feed-wrap--rail {
    display: grid;
    grid-template-columns: minmax(0, 640px) minmax(0, 1fr);
    /* ⚠ `align-items` は既定 (stretch) のまま — mock の `.pc` も既定で、中央列の罫線が
       **行の全高**に伸びる。`start` にすると本文が短い時に罫線が途中で切れる。 */
    max-width: 1220px;
    margin: 0 auto;
    /* 🔴 gutter は **中央列へ移す** — 容器に 16px を残すと 1220 の内訳が 640 + 548 になり、
       mock の右レール 580 と合わない。⇒ 容器を 0 にして同じ `1rem var(--feed-pad)` を
       `.feed-col` が持つ (中央列の見えかたは 1280px 未満と 1px も変わらない)。 */
    padding: 0;
  }
  /* 中央列の包み (`ui/feed/FeedPage.tsx` が `withRail` の時だけ描く)。
     ⚠ 1280px 未満では **規則を 1 行も持たない**素通しの block。 */
  .feed-wrap--rail .feed-col {
    min-width: 0;
    padding: 1rem var(--feed-pad);
    /* mock `.pc-mid` の 1 本。⚠ 2 カラムの時だけ引く (1 カラムでは列の境界が無い)。 */
    border-right: 1px solid var(--t-border);
  }
  .feed-wrap--rail .feed-rail { min-width: 0; padding: 20px 20px 0; }
}

/* ── 右レールの中身 (`ui/feed/FeedRail.tsx`) ─────────────────────────────────
   mock: `.pc-panel { margin-bottom: 22px }` / 見出し 13px 700 `--t-font-display` /
   `.rank-row` 12px `--t-muted` + 1px 罫線 / 数値は `--t-fg` + tabular-nums /
   人の行は 丸 avatar 34 + gap 10 + 名前 14px + 補足 11.5px。
   ⚠ mount は `/feed/` の 1280px 以上だけなので media query で囲まない (囲っても結果は同じ)。 */
.feed-rail-panel { margin-bottom: 22px; }
/* ⚠ `h3` を併記する — 見出し段は**面によって違う** (`/feed/` は `h4` / `/post/` は `h1` → `h2`
   → レールなので `h3`)。見た目は同じなので、要素型のまま 2 つ引く (`ui/post/PostRail.tsx`)。 */
.feed-rail-panel h3,
.feed-rail-panel h4 { margin: 0 0 10px; font-family: var(--t-font-display); font-size: 13px; font-weight: 700; letter-spacing: 0.01em; color: var(--t-fg); }
.feed-rail-row { display: flex; justify-content: space-between; gap: 10px; padding: 4px 0; font-size: 12px; color: var(--t-muted); border-bottom: 1px solid var(--t-border); }
/* ⚠ `:last-child` では効かない — 表の後ろに 1 文 (`.feed-rail-note`) が続くので、末尾の行は
   最後の子ではない。要素型で引く (行は div / 1 文は p)。 */
.feed-rail-row:last-of-type { border-bottom: 0; }
.feed-rail-row b { color: var(--t-fg); font-variant-numeric: tabular-nums; }
.feed-rail-person { display: flex; align-items: center; gap: 10px; padding: 6px 0; color: inherit; text-decoration: none; }
.feed-rail-person:hover .feed-rail-name { text-decoration: underline; }
/* ⚠ 画像は出せない (twin の取得列に avatar が無い) ので頭文字だけ。mock も同じ。 */
.feed-rail-av { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; width: 34px; height: 34px; border-radius: 50%; background: var(--t-surface-hover); color: var(--t-fg-soft); font-size: 13px; font-weight: 700; }
.feed-rail-person-main { display: flex; flex-direction: column; min-width: 0; }
/* ⚠ 名前は UGC なので 1 行 ellipsis (レール幅が狭い時に列を割らない)。 */
.feed-rail-name { font-size: 14px; color: var(--t-fg); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.feed-rail-sub { font-size: 11.5px; color: var(--t-muted); font-variant-numeric: tabular-nums; }
.feed-rail-note { margin: 8px 0 0; font-size: 11.5px; line-height: 1.6; color: var(--t-muted); }

/* ── 本文 640 + 右レール 288 の器 (`.pp-cols--rail`) ─────────────────────────
   `/post/` (#728) → `/profile/` (#731) → `/tag/` (#7xx) の **3 面が同じ器**を使う。
   #728 / #731 は同じ 12 行を page-local CSS へ逐語コピーしていた (`pages/post/index.html` の
   inline `<style>` と `pages/profile/profile.css`) ので、3 例目 (`/tag/`) を足すにあたり
   **ここを単一 source にした** (hub 裁定 2026-09-07)。⚠ class 名 (`.pp-*`) は #728 由来の
   まま据え置く — 改名は 3 面の DOM と test に波及するので別 unit。

   🔴 **容器の `max-width` はここが持たない** — 面ごとに違うため各 page が持つ:
     `/post/` `.post-wrap` / `/profile/` `.pp-wrap` は元から `--t-page-max` (960) で、
     `/tag/` `.tag-wrap` は timeline 型 (640) なので **1280px 以上でだけ 960 へ広げる**
     (本文列は 3 面とも 640 のまま = #708 の型分類は動かない)。
   ⚠ 内寸は 960 − padding 1rem×2 = 928 ⇒ **640 + 288**。板の「右 300」より 12px 狭いのは
     容器の gutter を残しているためで、レール中身 (カバー + 1 行) はこの幅で潰れない。
   ⚠ 閾値 1280 は `ui/shell/useWideChrome.ts` の `FEED_RAIL_MIN_WIDTH` と**同値** — JS 側は
     その定数を import している (面ごとに literal を置かない)。動かす時はここと定数の 2 つ
     とも動かす (CSS の値を JS から読む口は無い)。
   ⚠ レールの **mount 判定は JS** (`useMinWidth`)。CSS で隠すだけにすると、狭い画面でも
     レールの取得 (同じ作品の投稿 / viewer の vector / 近いタグ RPC) が走る。
   🔴 **修飾子 `.pp-cols--rail` で引く** — 素の `.pp-cols` はレールが無い時にも付く包みなので、
     素で引くと**レールが無いのに 2 列**になる。1280px 未満と 1 カラム時の見えかたを 1px も
     変えないため、素の `.pp-cols` は規則を 1 行も持たない素通しの block のままにする。 */
@media (min-width: 1280px) {
  .pp-cols--rail {
    display: grid;
    grid-template-columns: minmax(0, var(--t-page-max-timeline, 640px)) minmax(0, 1fr);
    /* ⚠ `align-items` は既定 (stretch) のまま — 中央列の罫線が行の全高に伸びる
       (上の `.feed-wrap--rail` と同じ理由)。 */
  }
  .pp-cols--rail .pp-col {
    min-width: 0;
    padding-right: 20px;
    border-right: 1px solid var(--t-border);
  }
  .pp-cols--rail .pp-rail { min-width: 0; padding: 0 0 0 20px; }
  /* 🔴 **レールが 1 枚も描かれなかったら 1 カラムへ戻す** — `/profile/` の `ProfileRail` は
     「見ている人の vector が無い = 算出不能」の時に `null` を返す (裁定 1-b)。そこを素通しに
     すると **288px の空列 + 罫線**だけが残り、「非ログイン時に空疎になるレール = 死に領域」
     そのものになる。⚠ 呼出側は own vector を持たない (収集は `ProfileRail` の中 = 狭い画面で
     走らせないため) ので、この判定は CSS でしか書けない。
     ⚠ `/post/` `/tag/` は**レールを出す時しか `--rail` を付けない**ので never match = 無害。
     ⚠ `:has()` 非対応の環境では規則ごと落ち、**2 列のまま** = この規則を書く前と同じで
       悪化しない (先例の言い回し = `ui/settings/consent-banner.css:208`)。 */
  .pp-cols--rail:not(:has(.pp-rail)) {
    display: block;
  }
  .pp-cols--rail:not(:has(.pp-rail)) .pp-col {
    padding-right: 0;
    border-right: 0;
  }
}
/* レール内の作品カバー。⚠ `.feed-rail-person` は flex 容器なので、幅 preset
   (`.work-cover--s`) だけでは縮む。⚠ media query の外 — レールは 1280px 以上でしか
   mount されないので囲っても結果は同じ (`.feed-rail-*` と同じ扱い)。 */
.pp-rail-cover { flex: 0 0 auto; }
