/* snake-balloon 基本スタイル(ビルドなし・1ファイル) */
/* テーマ: 既定はOS設定に追従。html[data-theme="light"|"dark"] で手動固定(app.jsが設定)。
   ライト/ダークの値は light-dark(ライト, ダーク) で**1箇所に**定義し、手動固定は
   color-scheme の切り替えだけで全変数へ効かせる(以前はメディアクエリ版と data-theme 版の
   2ブロックを「同内容を維持すること」のコメント頼みで手同期していた)。
   layout.php が描画前に data-theme を立てる仕組みはそのまま生きる(切り替わるのは
   color-scheme だけになった)。新しい色は必ずこの :root に light-dark で足すこと */
:root {
  color-scheme: light dark;
  --bg: light-dark(#f6f7f9, #15181c);
  --fg: light-dark(#1f2429, #e3e7eb);
  --muted: light-dark(#6b7480, #8b95a1);
  --border: light-dark(#d9dee4, #2e353d);
  --card: light-dark(#ffffff, #1c2127);
  --accent: light-dark(#2563eb, #4f8ef7);
  --accent-fg: #ffffff;
  --danger: light-dark(#dc2626, #f07171);
  --danger-bg: light-dark(#fef2f2, #2c1a1c);
  --danger-border: light-dark(#fca5a5, #6f3038);
  --ok-fg: light-dark(#15803d, #6fcf8f);
  --ok-border: light-dark(#86efac, #2c5237);
  --ok-bg: light-dark(#f0fdf4, #17241b);
  --warn-fg: light-dark(#b45309, #e0b25c);
  --warn-border: light-dark(#fcd34d, #64511f);
  --warn-bg: light-dark(#fffbeb, #272113);
  /* 新着(そのフィードを最後に開いたあとに届いた未読記事)の地色。--accent の淡いほう */
  --new-bg: light-dark(#e6f0fe, #1a2740);
  --new-bg-hover: light-dark(#d3e4fd, #213152);
  /* 表の縞(奇数偶数の濃淡)。--card に対して読み違い防止に足る濃さ(#fafbfd では視認できなかった) */
  --stripe: light-dark(#f2f5f8, #22272e);
}
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Hiragino Sans", "Noto Sans JP", sans-serif;
  background: var(--bg);
  color: var(--fg);
  line-height: 1.6;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* 上部メニューは本文と独立させて画面上端に留める。高さは --header-h でCSSへ渡る
   (.site-nav が flex-wrap するので定数にできない。app.jsがResizeObserverで同期)。
   z-indexは記事本文(1〜5)より上・行メニュー(50)より下 — メニューやツールチップは
   ヘッダーに重なって出てよい。モーダル(100)とトースト(300)はさらに上。
   スマホの浮動ボタン(.sidebar-toggle / .nav-toggle)は30、開いた上部メニューは70、
   ドロワーの背幕89・ドロワー90(800px以下のmedia内)、サイドバーの右クリックメニューは
   ドロワーの中から開くので95。/feeds の一括操作バー(.feed-bulk-actions、画面下端にsticky)は20。
   元ページ画像の拡大プレビュー(.page-image-lightbox)は記事ポップアップの中から開くので200 */
.site-header {
  background: var(--card);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 40;
}
/* ページ内リンクの着地点が固定ヘッダーの下に潜らないようにする(/settings#analysis など) */
html { scroll-padding-top: calc(var(--header-h, 0px) + 1rem); }

.site-nav {
  max-width: 1500px;
  margin: 0 auto;
  padding: 0.6rem 1rem;
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
}

.site-nav .brand { font-weight: 700; color: var(--fg); }
.site-nav .logout-form { margin-left: auto; }

.theme-toggle {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: none;
  color: var(--muted);
  cursor: pointer;
  font-size: 0.85rem;
  padding: 0.2rem 0.6rem;
  white-space: nowrap;
}
.theme-toggle:hover { color: var(--fg); border-color: var(--muted); }

.container {
  max-width: 1500px;
  margin: 0 auto;
  padding: 1rem;
}

.button, .link-button {
  display: inline-block;
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--card);
  color: var(--fg);
  cursor: pointer;
  font-size: 0.95rem;
}

.button.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fg);
}

.button:disabled, .watch-later-add:disabled { cursor: default; opacity: 0.6; }

.link-button {
  border: none;
  background: none;
  color: var(--accent);
  padding: 0;
}

.login-box {
  max-width: 420px;
  margin: 15vh auto 0;
  padding: 2rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  text-align: center;
}

.login-box .detail {
  word-break: break-all;
  color: var(--muted);
  font-size: 0.85rem;
}

/* --- 汎用 --- */
.page-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.detail { color: var(--muted); font-size: 0.85rem; word-break: break-all; }

.alert.danger {
  padding: 0.6rem 0.9rem;
  border: 1px solid var(--danger);
  border-radius: 6px;
  color: var(--danger);
  background: var(--danger-bg);
}

.alert.ok {
  padding: 0.6rem 0.9rem;
  border: 1px solid var(--ok-border);
  border-radius: 6px;
  color: var(--ok-fg);
  background: var(--ok-bg);
}

.badge {
  display: inline-block;
  padding: 0.05rem 0.5rem;
  border-radius: 999px;
  font-size: 0.8rem;
  border: 1px solid var(--border);
}
.badge.ok { color: var(--ok-fg); border-color: var(--ok-border); background: var(--ok-bg); }
.badge.warn { color: var(--warn-fg); border-color: var(--warn-border); background: var(--warn-bg); }
.badge.danger { color: var(--danger); border-color: var(--danger-border); background: var(--danger-bg); }

.button.danger { color: var(--danger); border-color: var(--danger-border); }

/* --- テーブル --- */
.table-wrap { overflow-x: auto; }

.list-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 0.92rem;
}

.list-table th, .list-table td {
  padding: 0.5rem 0.7rem;
  border-bottom: 1px solid var(--border);
  text-align: left;
  vertical-align: middle;
}

.list-table th { color: var(--muted); font-weight: 600; white-space: nowrap; }
.list-table input[type="text"] { width: 100%; }
input.narrow { width: 5rem; }

/* 数値セル単位の右寄せ(.numericと違いテーブル全体には効かせない) */
.list-table td.num { font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.table-note { color: var(--muted); font-size: 0.85rem; margin: 0 0 0.6rem; }

/* フィード実績(/feeds/stats)のフォルダ見出し行(ソース種別の見出しは表の外のh2)。
   縞の色(--stripe)と地色が近いので、境界は上の太線で示す */
.stats-folder-row th { background: var(--bg); color: var(--fg); border-top: 2px solid var(--border); }
/* 縞(奇数偶数の濃淡)。tbodyはフォルダごとに分かれていて見出し行が必ず1行目なので、
   :nth-child の偶奇がフォルダの先頭からそろう(2行目=最初のデータ行は素の --card)。
   フィード一覧(/feeds)・ゴミ箱(/feeds/deleted)・保存した検索(/searches)は絞り込みタブが行を
   hidden にして :nth-child が崩れるため、app.js の各 applyFilter が表示中の行へ is-stripe を振り直す
   (1行目=素、2行目=縞)。JS無効時は全行表示なので :nth-child(even) が同じ見た目の
   フォールバックになる。**行を hidden にする表に素の :nth-child の縞を付けないこと**
   (以前ゴミ箱が使っていた汎用の .list-table.striped はこの理由で撤去した) */
.stats-table tbody tr:nth-child(odd):not(.stats-folder-row),
html:not(.has-js) #feed-table tbody tr:nth-child(even),
html:not(.has-js) #deleted-table tbody tr:nth-child(even),
html:not(.has-js) #saved-search-table tbody tr:nth-child(even),
#feed-table tbody tr.is-stripe,
#deleted-table tbody tr.is-stripe,
#saved-search-table tbody tr.is-stripe { background: var(--stripe); }

/* --- フィード管理 --- */
/* フィード一覧は全行を1行の高さに保つ(一覧性)。フィード名だけでなくフォルダ名・日時・
   状態バッジ・「ログ」も画面幅しだいで折り返して行が2〜3段に膨れるため、テーブル全体を
   nowrap にし、収まらない幅は .table-wrap の横スクロールへ逃がす。
   このルールは /feeds 専用(#feed-table)に留めること — .list-table は共有クラスで、
   折り返しに任せたい長文セルを持つ画面もある */
#feed-table td { white-space: nowrap; }
/* 12列あるので左右パディングの合計だけで約100pxを食う。この表だけ詰めて、
   1366px級のノートPC幅でも横スクロールなしでログ・同期まで収まるようにする */
#feed-table th, #feed-table td { padding: 0.5rem 0.4rem; }
/* 並び替えできる列見出し(?sort=)。見出しの見た目(muted・600)をそのまま保ち、
   選択中の列だけ地の文字色と矢印で示す。矢印は選択中の1列にしか出さない。
   **矢印は幅を1pxも占めないこと**(`width: 0` で右のパディングへはみ出させる) —
   上の「1366px級で横スクロールなし」には余りが無く(タイトル列は min-width に張り付いている)、
   素直に inline で置くと 受信/日・新着率のような「見出しの方がデータより広い」列で
   矢印ぶん(実測13px)がそのまま横スクロールになる。日時の列だけ無害、では条件依存すぎる。
   はみ出した矢印は隣の見出しから3pxしか離れないので、**選択中の見出しの下線が
   「どちらの列の矢印か」を担っている** — 下線を外すなら矢印の置き方から考え直すこと。
   ゴミ箱(#deleted-table)も同じ見た目を束ねで共有する(幅の事情は無いが見た目をそろえる) */
#feed-table th > a, #deleted-table th > a { color: inherit; text-decoration: none; }
#feed-table th > a:hover, #deleted-table th > a:hover { text-decoration: underline; }
#feed-table th[aria-sort]:not([aria-sort="none"]),
#deleted-table th[aria-sort]:not([aria-sort="none"]) { color: var(--fg); }
#feed-table th[aria-sort]:not([aria-sort="none"]) > a,
#deleted-table th[aria-sort]:not([aria-sort="none"]) > a { text-decoration: underline; }
#feed-table .sort-mark, #deleted-table .sort-mark { display: inline-block; width: 0; font-size: 0.75em; }
/* タイトル列は「余った幅」だけを使って切り詰める — 固定の上限幅だと画面幅しだいで表が
   コンテナからはみ出して横スクロールになり、右端のログ・同期ボタンが遠くなる。
   width:100% で余り幅をこの列に集め、max-width:0 で「内容ぶんの幅が欲しい」という
   自動レイアウトの主張を消す(td の max-width が効かない問題もこの0指定は例外的に通る)。
   min-width は名前が潰れて読めなくならないための下限で、これを下回る狭さのときだけ
   従来どおり .table-wrap の横スクロールへ逃がす。全文はホバーのtitle属性と編集画面で読める */
#feed-table td.cell-title { width: 100%; max-width: 0; min-width: 12em; }
.list-table td.cell-title a { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 一括停止/再開のチェックボックス。**独立した列にしない** — 列を1本足すだけで約30pxかかり、
   上の「1366px級で横スクロールなし」の余裕を食う(実測: 現データで1366px幅の表は既に
   13pxはみ出しており、列を足すと44pxになる)。タイトル列(余り幅を全部使う列)の中に
   同居させれば表の総幅は変わらず、狭いときは名前の切り詰めが少し早まるだけで済む。
   JSでしか動かないので .has-js のときだけ出す(無効時は名前だけの従来表示) */
.feed-select-all, .feed-select-box { display: none; }
.has-js .feed-select-all, .has-js .feed-select-box {
  display: inline-block; width: 1.05rem; height: 1.05rem; margin: 0; cursor: pointer; vertical-align: middle;
}
.has-js #feed-table .cell-title-inner { display: flex; align-items: center; gap: 0.45rem; }
/* flex項目になった名前が min-width:auto で縮まなくなるのを防ぐ(切り詰めが始まる条件) */
.has-js #feed-table .cell-title-inner > a { min-width: 0; flex: 1; }
/* 操作バーは選択が1件以上あるときだけ画面下端に留まる(app.jsが hidden を外す)。
   テンプレート側で .table-wrap の外に置いてあるのが前提 — overflow-x:auto の箱の中では
   sticky の基準がその箱になり、表と一緒に横スクロールしてしまう。
   [hidden] は display:flex と同じ詳細度なので後置しないと消えない(.select-actions と同じ) */
.has-js .feed-bulk-actions {
  display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap;
  position: sticky; bottom: 0.5rem; z-index: 20;
  margin-top: 0.6rem; padding: 0.5rem 0.7rem;
  background: var(--card); border: 1px solid var(--border); border-radius: 6px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);
}
.feed-bulk-actions[hidden] { display: none; }
.feed-bulk-count { color: var(--muted); font-size: 0.88rem; font-variant-numeric: tabular-nums; }
.feed-bulk-actions .link-button { font-size: 0.85rem; }
/* 次回巡回の「N分後」入力。停止/再開のボタン群と区切りが分かるよう左に薄い縦線を置く */
.feed-bulk-schedule { display: inline-flex; align-items: center; gap: 0.4rem; padding-left: 0.6rem; border-left: 1px solid var(--border); }
/* 削除は巡回操作と分け、同じ縦線で区切る(停止と同じ danger でも誤操作しにくくする) */
.feed-bulk-delete-wrap { padding-left: 0.6rem; border-left: 1px solid var(--border); }
.feed-bulk-minutes-label { display: inline-flex; align-items: center; gap: 0.3rem; color: var(--muted); font-size: 0.88rem; white-space: nowrap; }
.feed-bulk-minutes {
  width: 4.5em; padding: 0.3rem 0.4rem; border: 1px solid var(--border); border-radius: 6px;
  background: var(--card); color: var(--fg); font-variant-numeric: tabular-nums;
}
.sync-button {
  white-space: nowrap;
  font-size: 0.8rem;
  padding: 0.2rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--card);
  cursor: pointer;
  color: var(--muted);
}
.sync-button:disabled { cursor: default; opacity: 0.6; }
.sync-result { font-size: 0.8rem; color: var(--muted); white-space: nowrap; }
.sync-result.danger { color: var(--danger); }

/* --- フォーム --- */
.form { max-width: 560px; display: flex; flex-direction: column; gap: 0.9rem; margin: 1rem 0; }
.form label { display: flex; flex-direction: column; gap: 0.25rem; }
.form label.inline, fieldset label.inline { flex-direction: row; align-items: center; gap: 0.4rem; display: inline-flex; margin-right: 0.8rem; }
.form input[type="text"], .form input[type="url"], .form input[type="number"], .form select, .form textarea,
.inline-form input[type="text"], .filter-bar input[type="search"], .page-images-min-input {
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 0.95rem;
  background: var(--card);
}
.form fieldset { border: 1px solid var(--border); border-radius: 6px; }
/* 複数行の設定(画像の取得範囲のセレクタ。1行1つ)。フォントは input と同じにし縦だけ伸ばせる */
.form textarea { font: inherit; font-size: 0.95rem; resize: vertical; }
.form-actions { display: flex; gap: 0.6rem; }
.inline-form { display: flex; flex-direction: row; gap: 0.5rem; align-items: center; }
/* バックアップの比較フォーム。世代名+日時のセレクト2つ(各370px前後)が .form の560px上限を
   超え、唯一縮められる「違いを見る」ボタンがflexに押し潰されて縦書き状態になっていた。
   上限を外し、入り切らない幅ではボタンを縮めず折り返す */
.backup-compare { max-width: none; flex-wrap: wrap; }
/* 分析の設定のカテゴリ追加(名前+説明+ボタン)。375px幅では1行に収まらないので折り返す */
.insight-category-add { flex-wrap: wrap; }
.insight-category-add input[type="text"] { min-width: 0; flex: 1 1 10rem; }
/* 設定画面のAI分析タブ。5列のフォルダ表(タグアーカイブのダウンロード列)が .form の560px上限に
   収まらないので、フォームの上限だけ外して表(.table-wrap)に幅を使わせる。入力欄と説明文は
   従来どおり560pxに保つので、他の設定の見え方は変わらない */
.form-wide { max-width: none; }
.form-wide > :not(.table-wrap) { max-width: 560px; }
/* 保存した検索のツール画面(/searches)。コピー先フォルダのチェック群は折り返して並べる。
   名前列は .list-table input[type="text"] の width:100% が効くので最小幅だけ確保する。
   条件列は .detail の word-break: break-all を外す — 表が狭いと列が1文字幅まで潰れて行が数百pxに伸びる
   (実測: 477px幅で1行450px)。min-width を切って .table-wrap の横スクロールへ逃がす */
.saved-search-targets { display: flex; flex-wrap: wrap; gap: 0.3rem 0.4rem; border: 1px solid var(--border); border-radius: 6px; padding: 0.6rem 0.9rem; margin: 0.8rem 0 0.4rem; }
.saved-search-targets legend { color: var(--muted); font-size: 0.85rem; padding: 0 0.3rem; }
.saved-search-overwrite { display: inline-flex; align-items: center; gap: 0.4rem; margin: 0 0 0.8rem; font-size: 0.92rem; }
#saved-search-table td.cell-name { min-width: 14em; }
#saved-search-table td.cell-target { min-width: 10.5em; }
#saved-search-table td.cell-target a { white-space: nowrap; }
#saved-search-table td.cell-cond, #saved-search-diff-table td.cell-cond { min-width: 18em; word-break: normal; overflow-wrap: break-word; }
#saved-search-table td.cell-save { white-space: nowrap; }
/* フォルダ間の差分(/searches/diff)。フォルダ選択は .inline-form の束ね(ラベル付きセレクト2つが狭い幅で折り返せるように)、
   同期の radio 列は行ごとに縦に並べる。削除の選択肢だけ赤(--danger)で示し、「同名が複数」の行は灰色 */
.saved-search-diff-pick { flex-wrap: wrap; margin: 0 0 1rem; }
.saved-search-diff-pick label { display: inline-flex; align-items: center; gap: 0.4rem; }
#saved-search-diff-table td.cell-name { min-width: 10em; }
#saved-search-diff-table td.cell-name a { margin-left: 0.3em; }
.diff-dir { display: flex; flex-direction: column; gap: 0.2rem; white-space: nowrap; }
.diff-dir .is-delete { color: var(--danger); }
#saved-search-diff-table tr.is-ambiguous td { color: var(--muted); }

/* --- リーダー画面 --- */
.reader-layout { display: grid; grid-template-columns: 280px 1fr; gap: 1.2rem; }
/* 長いタイトル(nowrap)の最小幅が1frトラックを押し広げないようにする */
.article-list { min-width: 0; }

/* サイドバーと記事一覧のスクロールを独立させる。ページのスクロールバーは記事一覧を送り、
   フィードが増えて画面に収まらなくなったサイドバーは自分の中だけでスクロールする。
   - align-self:start が必須。グリッドの既定(stretch)だと行の高さいっぱいに伸びて
     position:sticky が効かない
   - サイト全体を100vhの2ペインにする作りにはしない。.container は全画面で共有していて
     overflow:hidden を入れると他の画面が壊れるし、.site-nav は flex-wrap するので
     ヘッダーの高さを定数として引けない
   - overscroll-behavior でサイドバーの端に達してもページ側へスクロールが伝播しないようにする */
.sidebar {
  position: sticky;
  /* 固定した上部メニューの下から始める。--header-h はapp.jsが実測して入れる */
  top: calc(var(--header-h, 0px) + 1rem);
  align-self: start;
  max-height: calc(100vh - var(--header-h, 0px) - 2rem);
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* スマホ用の開閉ボタン群。PCでは存在ごと消す(下のmedia内で出す)。
   フィルタバーの .filter-toggle は全幅共通になったので、ここではなく .filter-bar の節で扱う */
.sidebar-toggle, .sidebar-backdrop, .nav-toggle { display: none; }
/* 折りたたみ対象のラッパーは display:contents で中身を親のflex直下に並べる。
   **ラッパー自体を1つのflex項目にしないための指定**で、これによりPCのレイアウトは
   1pxも変わらない。スマホでだけ none / flex に切り替える。
   この技を使うのは上部メニューだけ(フィルタバーは全幅の開閉パネルへ移行し、この前提を意図的に外した) */
.site-nav-menu { display: contents; }

/* スマホの折りたたみは **JSが有効なときだけ**(has-js は layout.php のインラインスクリプトが
   描画前に付ける)。付いていなければ従来どおり全部が縦に並ぶだけで、開くボタンが無いのに
   メニューが消えるという最悪の状態にはならない。.tabs の is-tabbed と同じ考え方 */
@media (max-width: 800px) {
  .reader-layout { grid-template-columns: 1fr; }
  /* 狭い画面ではメニューが2〜3段に折り返すため、留めると画面の2割を占める。
     縦が貴重なので通常どおり流す */
  .site-header { position: static; }
  /* JSが無いときは従来どおり記事一覧の上に積む(ドロワーにすると開けなくなる) */
  .sidebar { position: static; max-height: none; overflow-y: visible; }

  /* --- 上部メニュー: ロゴと☰だけ出し、☰は画面右上に固定してスクロールしても押せるようにする ---
     .site-header 自体は static のまま(留めると縦を食う)。代わりに☰だけを fixed で右上に置く。
     top/right はヘッダーの padding(0.6rem 1rem)とブランド行の高さから決めていて、
     スクロール位置0ではフロー内にあったときとほぼ同じ場所に見える(ボタンがflexから抜けて
     ヘッダーは約4px低くなる)。ヘッダーの外に出るので背景は none ではなく不透明にする。
     z-index 30 は .sidebar-toggle と同じ位置づけ(記事より上・行メニュー(50)より下) */
  .has-js .nav-toggle {
    display: block;
    position: fixed; top: 0.45rem; right: 1rem; z-index: 30;
    border: 1px solid var(--border); border-radius: 6px; background: var(--card);
    color: var(--fg); font-size: 1.1rem; line-height: 1; padding: 0.35rem 0.6rem; cursor: pointer;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  }
  .has-js .site-nav-menu { display: none; }
  /* 開いたメニューは☰の直下に固定のドロップダウンで出す。ヘッダーは static なので、
     スクロールした先で☰を押したときにヘッダー内で開いても画面の外で見えない。
     オーバーレイなので外側タップ・Esc・ドロワーを開く操作で閉じる(app.js)。
     z-index 70 は行メニュー(50)・右クリックメニュー(60)より上、背幕(89)より下。
     横向きなど低い画面では max-height で中をスクロールさせる(dvh はアドレスバー分を除いた実高) */
  .has-js .site-nav-menu.open {
    display: flex; flex-direction: column; align-items: flex-start; gap: 0.6rem;
    position: fixed; top: 2.85rem; right: 1rem; z-index: 70;
    min-width: 11rem; max-width: calc(100vw - 2rem);
    max-height: calc(100vh - 4rem); max-height: calc(100dvh - 4rem); overflow-y: auto;
    padding: 0.7rem 1rem;
    background: var(--card); border: 1px solid var(--border); border-radius: 8px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.18);
  }
  /* PCでは右寄せのためのmargin-left:autoが、縦並びでは上方向の余白になってしまう */
  .has-js .site-nav-menu.open .logout-form { margin-left: 0; }

  /* --- サイドバー: ドロワー --- */
  /* 開くボタンはスクロールしても左上に留める(記事が多いフィードでは、次のフィードを選ぶために
     先頭まで戻らないと押せなかった)。fixed ではなく sticky なのは、スクロール位置0では
     画面左上に .site-header のブランドがあって重なるため — sticky なら先頭では今の場所
     (ヘッダー直下)に収まり、自分の場所が上端を過ぎた瞬間から左上に留まって記事の上に浮く。
     フローの枠も残るのでレイアウトが跳ねない。sticky の範囲は .article-list 全体で、
     祖先に overflow を持つ要素が無いことが前提。
     z-index 30 は記事行・サムネイル(1〜5)より上、行メニューのポップオーバー(50)より下
     (開いたメニューは浮動ボタンより上に出るべき)。ドロワー(90)と背幕(89)が開いている間は隠れる。
     影は stuck 状態をCSSだけで判別できないので常時付ける(先頭でも軽い影が付くが許容) */
  .has-js .sidebar-toggle {
    display: block; margin-bottom: 0.6rem;
    position: sticky; top: 0.45rem; z-index: 30;
    border: 1px solid var(--border); border-radius: 6px; background: var(--card);
    color: var(--fg); font-size: 0.9rem; padding: 0.4rem 0.7rem; cursor: pointer;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  }
  .has-js .sidebar {
    position: fixed; top: 0; left: 0; bottom: 0;
    width: min(86vw, 320px);
    max-height: none;
    /* **PC用の align-self: start を必ず打ち消すこと** — 位置指定ボックスにも
       Box Alignment が効くため、start のままだと top/bottom を両端に留めても
       高さが内容ぶん(実測17,472px)に伸びてスクロール箱にならず、
       ドロワーの中で選択中フィードへ寄せる処理も動かない */
    align-self: stretch;
    margin: 0; padding: 1rem;
    background: var(--card); border-right: 1px solid var(--border);
    overflow-y: auto; overscroll-behavior: contain;
    /* 画面外へ逃がす。display:none にしないのは、選択中フィードへ寄せるapp.jsの計算
       (getBoundingClientRect)がレイアウト済みであることを前提にしているため。
       transformは中身の相対位置を変えないので、閉じた状態で測っても値は正しい */
    transform: translateX(-100%);
    /* 画面外にいる間はTabでも拾わせない。visibilityは閉じるアニメーションが
       終わってから切り替える(即座にhiddenにするとスライドせず消えるだけになる) */
    visibility: hidden;
    transition: transform 0.2s ease, visibility 0s linear 0.2s;
    z-index: 90;
  }
  .has-js .sidebar.open {
    transform: none;
    visibility: visible;
    transition: transform 0.2s ease, visibility 0s linear 0s;
  }
  /* タッチは指で押し分けられるよう当たり判定を広げる。.drag-handle の同種の上書きは**基底の後ろ**にある
     (同じ詳細度 (0,2,0) なので、このブロックに書くと後方の基底に負けて効かない) */
  .has-js .feed-fav { padding: 0.35rem 0.3rem; }
  /* 基底の .folder-toggle 定義はこのブロックより後ろにあるため、(0,2,0) にしないと後勝ちで負ける */
  .tree-folder-row > .folder-toggle { padding: 0.35rem 0.5rem; font-size: 1rem; }
  /* 背幕はドロワー(90)の下、モーダル(100)より下 */
  .has-js .sidebar-backdrop {
    display: block; position: fixed; inset: 0; background: rgba(0, 0, 0, 0.45); z-index: 89;
  }
  .has-js .sidebar-backdrop[hidden] { display: none; }
}

/* 動きを減らす設定ではスライドさせない(開閉自体は同じ) */
@media (prefers-reduced-motion: reduce) {
  .sidebar { transition: none; }
}

.sidebar-title a { color: var(--fg); }
.sidebar-section h3 { color: var(--muted); font-size: 0.85rem; margin: 1rem 0 0.3rem; display: flex; justify-content: space-between; align-items: center; }
.unread-only-toggle {
  border: 1px solid var(--border); border-radius: 6px; background: none;
  color: var(--muted); font-size: 0.7rem; padding: 0.1rem 0.45rem; cursor: pointer;
}
/* タグクラウドの並び替え(名前順/未読数順)。連結の形状は「連結ボタン」の共通ブロック、
   選択色は「選択中の共通見た目」ブロックにあり、ここはサイズだけ
   (.unread-only-toggleに合わせる)。.view-buttonを流用しないのは
   app.jsの表示モード切替がクラスで拾うため(見た目の共有はセレクタの束ねで行う) */
.tag-sort { display: inline-flex; }
.tag-sort-button {
  border: 1px solid var(--border); background: none;
  color: var(--muted); font-size: 0.7rem; padding: 0.1rem 0.45rem; cursor: pointer;
}

/* --- サイドバーのタブ(フィード/検索/タグ/ブックマーク) ---
   フィードとタグがどちらも縦に長くなったため、節を全部積まずに1パネルずつ見せる。
   表示状態は .sidebar の data-current-pane 属性が唯一の持ち場(ボタンの active も
   パネルの表示もここから引く。JSは属性とlocalStorageの管理だけを担う)。
   JS無効ならタブ列ごと出ず、従来どおり全節が縦に並ぶ(has-jsゲート) */
.sidebar-tabs { display: none; }
.has-js .sidebar-tabs { display: flex; margin-top: 0.4rem; }
.sidebar-tab {
  /* 等幅(flex: 1)ではなく内容幅を基準に余りを分ける — 4つ目の「検索」を足したとき、280pxの
     サイドバーで等幅だと「ブックマーク」が1タブ70pxに収まらず途中で折り返した(2026-09) */
  flex: 1 1 auto; white-space: nowrap;
  border: 1px solid var(--border); background: var(--card);
  color: var(--muted); font-size: 0.8rem; padding: 0.3rem 0.2rem; cursor: pointer;
}
.has-js .sidebar[data-current-pane="feeds"] .sidebar-tab[data-pane="feeds"],
.has-js .sidebar[data-current-pane="searches"] .sidebar-tab[data-pane="searches"],
.has-js .sidebar[data-current-pane="tags"] .sidebar-tab[data-pane="tags"],
.has-js .sidebar[data-current-pane="bookmarks"] .sidebar-tab[data-pane="bookmarks"] {
  background: var(--accent); color: var(--accent-fg); border-color: var(--accent);
}
.has-js .sidebar-section[data-pane] { display: none; }
.has-js .sidebar[data-current-pane="feeds"] .sidebar-section[data-pane="feeds"],
.has-js .sidebar[data-current-pane="searches"] .sidebar-section[data-pane="searches"],
.has-js .sidebar[data-current-pane="tags"] .sidebar-section[data-pane="tags"],
.has-js .sidebar[data-current-pane="bookmarks"] .sidebar-section[data-pane="bookmarks"] { display: block; }
/* 選択中の対象が無いページ(data-current-pane="")の最初の描画: 保存値を html.sidebar-pane-*
   (layout.phpのインラインスクリプト)から引く。app.jsが起動時に data-current-pane を具体値へ
   正規化するので、この4本は描画前の一瞬のためだけにある(タブ側のactiveは正規化後に決まれば足りる) */
html.has-js:not(.sidebar-pane-searches):not(.sidebar-pane-tags):not(.sidebar-pane-bookmarks) .sidebar[data-current-pane=""] .sidebar-section[data-pane="feeds"] { display: block; }
html.has-js.sidebar-pane-searches .sidebar[data-current-pane=""] .sidebar-section[data-pane="searches"] { display: block; }
html.has-js.sidebar-pane-tags .sidebar[data-current-pane=""] .sidebar-section[data-pane="tags"] { display: block; }
html.has-js.sidebar-pane-bookmarks .sidebar[data-current-pane=""] .sidebar-section[data-pane="bookmarks"] { display: block; }

/* 未読なし(かつ選択中でもない)フィード/フォルダを隠す */
.tree.unread-only li:not(.has-unread):not(.has-active) { display: none; }
.tree { list-style: none; padding-left: 0; margin: 0; font-size: 0.92rem; }
.tree ul { list-style: none; padding-left: 0.9rem; margin: 0; }
.tree a { display: flex; justify-content: space-between; gap: 0.4rem; padding: 0.15rem 0.3rem; border-radius: 4px; color: var(--fg); }
.tree a:hover { background: var(--border); text-decoration: none; }
.tree a.active { background: var(--accent); color: var(--accent-fg); }
.tree-label { color: var(--muted); }
/* メタデータ取得待ちの動画の警告(⚠)。サイドバーのフィード行と記事メタ行の両方で使う。
   絵文字自体が黄色なので色は付けず、周囲の文字サイズより少し小さくして騒がせない。
   取得が終わると次の読み込みで自然に消える */
.video-pending-flag, .video-failed-flag, .article-paywall-flag { font-size: 0.8em; margin-right: 0.2em; cursor: help; }
/* 🔒(有料記事)は記事メタ行の**先頭**(★の前)に置くので、末尾用の margin の振り替えには入れない
   (先頭に置く理由は「開く前に気づく」目印だから — 一覧・履歴・詳細の3画面で同じ位置。→ rules/paywall.md) */
.article-meta .video-pending-flag, .article-meta .video-failed-flag { margin-right: 0; margin-left: 0.3em; }
/* ❌(取得できなかった)は⚠(取得待ち)より一段小さくする — 絵文字の見た目の重量が違い、
   同じサイズだと赤だけが行の中で浮いて騒がしい */
.video-failed-flag { font-size: 0.72em; }
/* 巡回停止中(feeds.is_active=0)の🚫。⚠/❌と同じく .tree-name の中に置く(項目を足さない)。
   名前の灰色化は has-new の色指定より後ろ(.tree li.is-stopped)で行う */
.feed-stopped-flag { font-size: 0.8em; margin-right: 0.2em; cursor: help; }
/* 一覧から直接メタデータを取り直す🔄ボタン。メタ行に混ぜるので枠も地色も付けない
   (押せることはホバーのカーソルとtitleで示す) */
.video-requeue-icon {
  border: none; background: none; padding: 0 0.1em; margin-left: 0.15em;
  font-size: 0.78em; line-height: 1; cursor: pointer;
}
.video-requeue-icon:hover { filter: brightness(1.15); }
.video-requeue-icon:disabled { cursor: default; opacity: 0.5; }

/* 長いフィード名・フォルダ名は1行に切り詰める(折り返すと行の高さが不揃いになって
   一覧性が落ち、ドラッグの位置判定も跳ねやすくなる)。名前をテンプレート側で span
   (.tree-name)に包んでいるのは、flexの匿名テキストノードには overflow が効かないため。
   min-width: 0 が無いとflex項目は内容幅より縮まず、切り詰め自体が始まらない */
.tree a .tree-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 名前を縮める側に寄せ、未読バッジは潰さない(保存した検索の未読数バッジも同じ) */
.tree a .unread-count, .tree a .saved-search-unread { flex-shrink: 0; }

/* 新着(そのフィードを最後に開いたあとに届いた未読記事がある)の強調。
   フォルダ行は配下フィードの論理和で、フィードを1件ずつ開いていくと消える。
   色だけに頼らないよう太字を併用する。
   左の縦線を ::before や <span> で作らないこと — .tree a は「名前+未読バッジ」の2項目を
   justify-content: space-between で置くflexなので、項目を足すと名前が中央へ寄って並びが崩れる。
   box-shadow: inset なら行の箱に描くだけで項目が増えない。
   子結合子(>)で書くのはフォルダの li が配下のフィードの li を含むため */
.tree li.has-new > .tree-feed-row,
.tree li.has-new > .tree-folder-row { box-shadow: inset 3px 0 0 var(--accent); border-radius: 4px; }
.tree li.has-new > .tree-feed-row > a,
.tree li.has-new > .tree-folder-row > a,
.tree li.has-new > .tree-folder-row > .tree-label { font-weight: 700; }
/* 選択中(active)はアクセント色の背景なので文字色は触らない(可読性が落ちる) */
.tree li.has-new > .tree-feed-row > a:not(.active),
.tree li.has-new > .tree-folder-row > a:not(.active) { color: var(--accent); }
.tree li.has-new > .tree-folder-row > .tree-label { color: var(--fg); }
/* 巡回停止中(feeds.is_active=0)のフィードは名前を灰色にする(🚫は .feed-stopped-flag)。
   has-new と同じ詳細度 (0,4,2) なので**必ずこの後ろに置く** — 停止中かつ新着の行は太字と
   左の縦線は残しつつ、文字色は灰色を勝たせる(止まっていることの方が読み手に重要)。
   選択中(active)はアクセント背景なので has-new と同じく触らない */
.tree li.is-stopped > .tree-feed-row > a:not(.active) { color: var(--muted); }

/* 自動リフレッシュ(app.js の「記事一覧の自動リフレッシュ」ブロック。サイドバーだけをその場で書き換える)で
   未読数が変わった行のフラッシュ。行に .count-changed を約2.5秒だけ付ける(外すのはJSのタイマーで、
   animationend には頼らない — 動きを減らす設定では animation 自体が無い)。has-new の左縦線(box-shadow inset)と別プロパティで
   衝突せず、子の a.active のアクセント地の上にも描かれるよう、行の内側2pxの outline を主役にして
   地色は補助。色は --new-bg-hover を再利用し新しい色は足さない。このファイル唯一の @keyframes。
   3拍(0.7s×3=2.1s)で自然に消え、fill-mode は付けない */
@keyframes sidebar-count-flash {
  0%, 100% { outline-color: transparent; background-color: transparent; }
  50%      { outline-color: var(--accent); background-color: var(--new-bg-hover); }
}
.tree-feed-row.count-changed,
.tree-folder-row.count-changed {
  outline: 2px solid transparent; outline-offset: -2px; border-radius: 4px;
  animation: sidebar-count-flash 0.7s ease-in-out 3;
}
/* 動きを減らす設定では点滅させず、付いている間だけ静かに枠を出す(状態は残す) */
@media (prefers-reduced-motion: reduce) {
  .tree-feed-row.count-changed,
  .tree-folder-row.count-changed { animation: none; outline-color: var(--accent); }
}

/* フォルダのアコーディオン開閉 */
.tree-folder-row { display: flex; align-items: center; }
.tree-folder-row > a, .tree-folder-row > .tree-label { flex: 1; }
/* 「(フォルダなし)」の行と、保存した検索(サイドバー「検索」タブ)のフォルダ見出し(.saved-search-group も
   折りたたみを共有するため同じ li.tree-folder + .tree-folder-row で組む)が同じ見た目 */
.tree-folder-row > .tree-label { display: flex; justify-content: space-between; gap: 0.4rem; padding: 0.15rem 0.3rem; }
/* 保存した検索のフィード名(フィード紐づきの行だけ)。.tree-name の中なので名前と一緒に切り詰められる。
   選択中(active)はアクセント背景で muted が読めないので文字色を継承して薄くする(has-new と同じ扱い) */
.saved-search-feed { color: var(--muted); font-size: 0.8em; margin-left: 0.35em; }
.tree a.active .saved-search-feed { color: inherit; opacity: 0.8; }
.folder-toggle {
  border: none;
  background: none;
  cursor: pointer;
  padding: 0 0.35rem;
  font-size: 0.9rem;
  line-height: 1;
  display: inline-flex;
  /* 当たり判定は行の全高(行高は <a> の padding が決めるので行は太らない) */
  align-self: stretch;
  align-items: center;
  justify-content: center;
}
/* 開閉の状態は ::before の絵文字を .collapsed で出し分ける — JSはクラスと aria-expanded だけ触ればよく、
   スプリングロード・選択中フィードの自動展開も自動で追随する(テキスト差し替えにしないこと) */
.folder-toggle::before, .tree-search-heading .tree-name::before { content: "📂"; }
.tree-folder.collapsed > ul { display: none; }
.tree-folder.collapsed .folder-toggle::before, .tree-search-heading.collapsed .tree-name::before { content: "📁"; }

/* 保存した検索の見出し行(名前が `=名前=` の検索=サブフォルダ表現 → rules/saved-search.md)。DOM はフラットな
   ul のままで、配下(次の見出しの手前まで)の出し分けは app.js が li[hidden] で行う(.tree li は display を
   上書きしていないので UA の [hidden] が効く)。📂/📁 は上のフォルダ開閉と同じ束ねで、**<a> ではなく
   .tree-name の ::before** に置く(.tree a は「名前+チップ」の2項目 flex。<a> に項目を足すと並びが崩れる)。
   件数チップは未読数ではないので .unread-count を使わない(既読トグルと自動リフレッシュがあちらを書き換える) */
.tree-search-heading > .tree-search-row > a { cursor: pointer; font-weight: 700; }
.tree-search-heading .tree-name::before { margin-right: 0.3em; font-weight: 400; }
.heading-count { flex-shrink: 0; color: var(--muted); font-size: 0.8em; font-weight: 400; }
/* 配下の行は1段下げる(最初の見出しより上=見出しなし区画は下げない)。幅は .tree ul の段下げと同じ */
.saved-search-tree li.tree-search-heading ~ li.tree-search:not(.tree-search-heading) { padding-left: 0.9rem; }

/* フィード行。フォルダ行(.tree-folder-row)と同じ作りにして、左に☆・右にドラッグハンドルを置く。
   リンク側の display:flex; justify-content:space-between はそのまま活きるので未読バッジの位置は変わらない */
/* 保存した検索の行(.tree-search-row、「検索」タブ)も同じ作り(左の☆は無く、右にドラッグハンドル) */
.tree-feed-row, .tree-search-row { display: flex; align-items: center; }
.tree-feed-row > a, .tree-search-row > a { flex: 1; min-width: 0; }
.feed-fav {
  border: none; background: none; cursor: pointer;
  color: var(--muted); padding: 0 0.15rem; font-size: 0.8rem; line-height: 1;
  display: inline-flex;
}
.feed-fav.on { color: var(--accent); }
/* ドラッグは **JSが有効なときだけ**(has-js は layout.php のインラインスクリプトが描画前に付ける)。
   付いていなければハンドル自体を出さない — 掴んでも何も起きないグリップを見せないため */
.drag-handle { display: none; }
.has-js .drag-handle {
  display: inline-flex;
  border: none; background: none; color: var(--muted);
  padding: 0 0.2rem; font-size: 0.85rem; line-height: 1;
  cursor: grab;
  /* ハンドルの上だけタッチスクロールを殺す。サイドバー全体に付けるとドロワーが動かなくなる。
     pointerdown 後に付けても手遅れなので静的に指定すること */
  touch-action: none;
  opacity: 0;
  transition: opacity 0.1s;
}
.has-js .tree-feed-row:hover .drag-handle,
.has-js .tree-search-row:hover .drag-handle,
.has-js .tree-folder-row:hover .drag-handle,
.has-js .drag-handle:focus-visible,
/* 掴んでいる行のハンドルは出したままにする。行がポインタの下から外れると
   :hover が切れて消え、何を掴んでいるのか分からなくなるため */
.has-js li.dragging > * > .drag-handle { opacity: 1; }
/* タッチにホバーが無いのでハンドルは常時表示にし、指で押し分けられるよう当たり判定も広げる。
   **基底の後ろに置くこと** — 前方の800pxブロック(ドロワー)に書くと同じ詳細度 (0,2,0) で後ろの基底に負ける
   (.page-image-zoom と同じ扱い) */
@media (max-width: 800px) {
  .has-js .drag-handle { opacity: 1; padding: 0.35rem 0.4rem; }
}
/* ドラッグ中: 掴んでいる行に枠を出す。行のホバー装飾は消す(掴んでいる行と紛らわしい) */
.tree li.dragging > .tree-feed-row,
.tree li.dragging > .tree-search-row,
.tree li.dragging > .tree-folder-row {
  outline: 1px solid var(--accent); outline-offset: -1px; border-radius: 4px;
  background: var(--card);
}
.reordering { cursor: grabbing; }
.reordering .tree a:hover { background: none; }
.reordering .drag-handle { cursor: grabbing; }
/* 折りたたみ中のフォルダの上で止まっている合図(そのまま待つと開く) */
.tree-folder.drop-into > .tree-folder-row { outline: 2px dashed var(--accent); outline-offset: -1px; border-radius: 4px; }
/* .saved-search-unread は保存した検索の未読数(app.js が後から入れる)。見た目だけ共有し、クラスを分けるのは
   既読トグルと自動リフレッシュが .unread-count を書き換えるため(→ rules/saved-search.md「未読数バッジ」) */
.unread-count, .saved-search-unread {
  background: var(--accent);
  color: var(--accent-fg);
  border-radius: 999px;
  font-size: 0.75rem;
  padding: 0 0.45rem;
  align-self: center;
}

.filter-bar { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; margin-bottom: 0.8rem; }
/* 記事一覧と読んだ履歴のバーは「件数行 / 検索行 / 操作行 / 絞り込みパネル」の4段。行を全幅の
   項目にすることで、画面幅に関係なく検索欄と一括操作(既読・未読・タグ)が同じ行に混ざらない
   (ユーザー指定。高さが増えるのは許容)。中の折り返しは行ごとに閉じる。
   .filter-bar 自体はタグ・サムネイルの各画面(1段のまま)とも共有なので触らないこと —
   段分けはこの行クラスを足した画面にだけ効く */
.filter-bar-row { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; width: 100%; }
.order-toggle, .singleton-toggle { white-space: nowrap; }
.filter-bar input[type="search"] { flex: 1; min-width: 160px; }
.filter-bar select { padding: 0.4rem 0.5rem; border: 1px solid var(--border); border-radius: 6px; background: var(--card); }
/* 履歴画面のフィード/フォルダ絞り込み。selectの幅は最長のフィード名で決まるので、器に
   合わせて上限を切らないと狭い画面で横スクロールが出る(実測: 375px幅で444pxのセレクトが
   ページを460pxへ広げた)。.tag-add / .bookmark-add の幅の手当てと同じ事情で、min-width:0 は
   flex項目の「内容幅より縮まない」既定を外すため。PCでは自然幅が器より狭いので1pxも変わらない */
.history-scope-select { min-width: 0; max-width: 100%; }
/* .day-input はステータス画面の日付ピッカー。/status 用に5行複製するより、
   同じ見た目を1箇所で決めて二度と食い違わない方を採る */
.filter-bar input[type="date"], .day-input, .filter-bar .duration-input { padding: 0.35rem 0.5rem; border: 1px solid var(--border); border-radius: 6px; background: var(--card); color: var(--fg); font-size: 0.9rem; }
/* 再生時間の手入力(1h30mなど)。固定幅ならバーの幅を食わない(flex:1を持つのは検索ボックスだけ) */
.filter-bar .duration-input { width: 7em; }
.date-range-sep { color: var(--muted); }
.result-count { color: var(--muted); font-size: 0.88rem; }
/* 件数行(記事一覧の1段目)。項目は .result-count の見た目をそのまま共有し、区切りの「·」だけ
   ::before で足す(新しい色変数は作らない)。項目単位で折り返すよう nowrap — 「合計 1:23:45」が
   途中で割れない。::before は span の中なので .filter-bar-row の flex 項目数は増えない */
.result-summary .result-count { white-space: nowrap; }
.result-summary .result-niconico { white-space: normal; overflow-wrap: anywhere; min-width: 0; }
.result-summary .result-niconico.is-warning { color: var(--warn-fg); }
.result-niconico a { color: inherit; text-decoration: underline; white-space: nowrap; }
.result-summary .result-count + .result-count::before { content: "·"; margin-right: 0.5rem; }
/* 件数の左の「分析内容」ボタン(分析するフォルダ / フィードを開いているときだけ)。.button の見た目のまま、
   件数行の高さを押し広げないよう小さめにする(.toast-actions .button と同じ寸法) */
.result-summary .button.result-analysis { padding: 0.2rem 0.7rem; font-size: 0.85rem; white-space: nowrap; }
/* 「🔒 有料記事 n件」は絞り込み(?paywall=only)へのリンク。行の他の項目と同じ muted の見た目を保ち、
   押せることは点線の下線で示す(アクセント色にすると件数行で1項目だけ浮く)。
   読んだ履歴の「タグ: 名前 ✕」(絞り込みの解除)も同じ見た目 */
.result-summary a.result-paid, .result-summary a.result-tag, .result-summary a.result-insight { color: var(--muted); text-decoration: underline dotted; }
.result-summary a.result-paid:hover, .result-summary a.result-tag:hover, .result-summary a.result-insight:hover { color: var(--accent); }

/* --- 絞り込みパネル(全幅の折りたたみ。元はスマホ専用だった機構を行分けと合わせて全幅化) ---
   出し分けは **JSが有効なときだけ**(has-js は layout.php のインラインスクリプトが描画前に付ける)。
   付いていなければボタンが出ず、パネルは常時表示に退行する(.tabs の is-tabbed と同じ考え方) */
.filter-toggle { display: none; }
.has-js .filter-toggle {
  display: block;
  border: 1px solid var(--border); border-radius: 6px; background: var(--card);
  color: var(--fg); font-size: 0.9rem; padding: 0.4rem 0.7rem; cursor: pointer;
}
/* 適用中の条件数バッジ。ボタンがアクセント地(active)のときは同色で消えるので反転する */
.filter-count {
  display: inline-block; margin-left: 0.35rem; padding: 0 0.4rem;
  border-radius: 999px; background: var(--accent); color: var(--accent-fg); font-size: 0.75rem;
}
.filter-toggle.active .filter-count { background: var(--accent-fg); color: var(--accent); }
/* パネルは全幅の項目で、中はラベル付きのフラット3行(絞り込み/範囲/ソート)+
   動画グループ(親見出し+サブ行の入れ子)を縦に積む。縦積みの形は3つの器で同一なので束ねる */
.filter-advanced, .filter-group, .filter-group-rows {
  display: flex; flex-direction: column; gap: 0.45rem;
}
.filter-advanced {
  width: 100%;
  padding: 0.6rem 0.7rem; border: 1px solid var(--border); border-radius: 8px;
}
/* 閉じていても中の input は送信されるので、畳んだまま検索しても絞り込みは維持される(disabledにしないこと) */
.has-js .filter-advanced { display: none; }
/* html.filter-open は開いた状態の復元(layout.phpが描画前に付け、app.jsが要素の .open へ引き継ぐ)。
   display:none に競り勝つよう、必ずこの順(後置)を保つこと */
html.filter-open .filter-advanced,
.has-js .filter-advanced.open { display: flex; }
.filter-row { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
/* 行ラベルと動画グループの親見出しは同じ地の文字。見出しだけ太字で一段強くする */
.filter-row-label, .filter-group-label { color: var(--muted); font-size: 0.8rem; }
.filter-row-label { min-width: 4em; } /* 最長ラベル「絞り込み」(4文字)で列がそろう幅 */
.filter-group-label { font-weight: 600; }
/* サブ行はインデント+左の縦線で親見出しへの従属を示す */
.filter-group-rows { margin-left: 0.2rem; padding-left: 0.8rem; border-left: 2px solid var(--border); }

.articles { list-style: none; padding: 0; margin: 0; border: 1px solid var(--border); border-radius: 8px; background: var(--card); }
.article-row { display: flex; align-items: center; border-bottom: 1px solid var(--border); }
.article-row:last-child { border-bottom: none; }
.article-main { flex: 1; display: flex; flex-direction: column; padding: 0.5rem 0.8rem; min-width: 0; }
.article-row:hover { background: var(--bg); }
.article-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fg); align-self: flex-start; max-width: 100%; }
/* メタ行は器で、中のフィード名リンクと日付リンクがそれぞれ別の行き先を持つ。
   下線はa:hoverの基本スタイルに任せる(器に掛けると行全体に引かれる) */
.article-meta a { color: var(--muted); }
/* お気に入りフィードの目印。サイドバーの .feed-fav.on と同じ色にそろえる。
   font-sizeは指定しない(.article-metaの0.8remを継承する) */
.article-feed-fav { color: var(--accent); }
.article-row.read .article-title { color: var(--muted); font-weight: 400; }
.article-row.unread .article-title { font-weight: 600; }
/* 新着(そのフィードを最後に開いたあとに届いた記事)。サイドバーの新着マークと同じ視覚言語で、
   色だけに頼らないよう左の縦線を併せる。既読のあいだ光らせないのは .unread で表現していて、
   app.jsの既読トグルがクラスを付け替えるだけで追随する(JS側に処理を足さない)。
   **先頭に .articles を付けて (0,4,0) にしていることに意味がある** — あとに来る
   `.article-row:hover` と `.articles.cards .article-row` の background に競り勝つため。
   カードもリストも同じ地色にしたいので、この1本で両方を賄う */
.articles .article-row.is-new.unread { background: var(--new-bg); box-shadow: inset 3px 0 0 var(--accent); }
.articles .article-row.is-new.unread:hover { background: var(--new-bg-hover); }
.articles.cards .article-row.is-new.unread { border-color: var(--accent); }
.article-meta { color: var(--muted); font-size: 0.8rem; }
/* メタ行のフィード名も1行に切り詰める(スマホ幅で名前+日付が2行に折り返すのを防ぐ)。
   メタ行でフィードを指すのは編集画面へのリンクだけなので、マークアップは変えず href で絞る
   (一覧・履歴・詳細の3画面のメタ行はマークアップをそろえる規約のため。この指定も3画面に効く)。
   inline-blockのぶん vertical-align で基線を戻す */
.article-meta a[href^="/feeds/"] {
  display: inline-block; max-width: 18em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom;
}
/* 記事一覧で記事へ添えるタグバッジ(.tagのピルスタイルを流用)。
   inline-flexのままではtext-overflowが効かないためinline-blockに切り替え、長いタグ名は「…」で省略する */
.article-tag-badges { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.15rem; }
.article-tag-badges .tag { display: inline-block; font-size: 0.75rem; padding: 0 0.5rem; max-width: 12em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.read-toggle, .chip-link, .watch-later-add { display: inline-block; margin: 0 0.6rem; white-space: nowrap; font-size: 0.8rem; padding: 0.2rem 0.5rem; border: 1px solid var(--border); border-radius: 6px; background: var(--card); cursor: pointer; color: var(--muted); }
a.chip-link:hover { text-decoration: none; border-color: var(--accent); color: var(--accent); }

/* 「後で読む」リボン。オフ=灰色の輪郭、オン=アクセント色の塗り(app.jsが .on と data-on を切り替える)。
   枠・地は付けない — 行内では既読トグルの隣に置くだけの小さな目印で、ボタンの箱が並ぶと騒がしい */
.read-later-toggle {
  display: inline-flex; align-items: center;
  border: none; background: none; padding: 0.25rem; cursor: pointer; color: var(--muted);
}
.read-later-toggle svg { fill: none; stroke: currentColor; stroke-width: 2; stroke-linejoin: round; }
.read-later-toggle:hover { color: var(--accent); }
.read-later-toggle.on { color: var(--accent); }
.read-later-toggle.on svg { fill: currentColor; }

.pagination { display: flex; gap: 0.8rem; align-items: center; justify-content: center; margin: 1rem 0; }
.empty-note { color: var(--muted); }

/* フォルダを開いているときだけ出る「新着を確認済み」。JSでしか動かないので、
   JSが無効なら押しても何も起きないボタンを見せない(.drag-handle と同じ規約) */
.folder-visited { display: none; }
.has-js .folder-visited { display: inline-block; font-size: 0.88rem; color: var(--accent); }
.has-js .folder-visited:hover { border-color: var(--accent); }

/* --- ブックマーク表示の複数選択モード・一括タグ操作・検索の保存の入口 --- */
/* JSでしか動かないので入口のボタンは .has-js のときだけ見せる(.folder-visited と同じ規約) */
.select-toggle, .bulk-tag-open, .saved-search-open { display: none; }
.has-js .select-toggle, .has-js .bulk-tag-open, .has-js .saved-search-open { display: inline-block; }
/* 操作の器(ブックマーク表示と読んだ履歴が共有)。将来の一括操作(移動など)はここへボタンを足す。
   履歴はボタンが2つ(削除 / 削除して未読に戻す)あり狭い画面で1行に収まらないので折り返す */
.select-actions { display: inline-flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }
.select-actions[hidden] { display: none; } /* display指定がhidden属性に競り勝たないように */
.select-all-label { display: inline-flex; align-items: center; gap: 0.3rem; color: var(--muted); font-size: 0.88rem; cursor: pointer; }
/* 行のチェックボックスは選択モード(ul.articles.selecting)のときだけ見える */
.article-select { display: none; }
.articles.selecting .article-select { display: flex; align-items: center; align-self: stretch; padding: 0 0.2rem 0 0.6rem; cursor: pointer; }
.article-select-box { width: 1.05rem; height: 1.05rem; cursor: pointer; }
/* カード表示では左上に重ねる(右上の既読トグルと対角。カードは position: relative 済み) */
.articles.cards.selecting .article-select {
  position: absolute; top: 0.4rem; left: 0.4rem; z-index: 1;
  padding: 0.25rem; background: var(--card); border: 1px solid var(--border); border-radius: 6px;
}

/* --- 一括既読・一括未読(見た目は同じ1組。クラスを分けているのはJSの衝突回避のため)。
   記事プレビューの「要約…」(.summary-select)も同じ「選ぶと実行するセレクト」なので束ねる --- */
.bulk-read-select,
.bulk-unread-select,
.summary-select {
  padding: 0.4rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--card);
  color: var(--muted);
  font-size: 0.88rem;
}

.row-menu { position: relative; margin-right: 0.5rem; }
.row-menu-toggle {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--card);
  color: var(--muted);
  cursor: pointer;
  padding: 0.2rem 0.45rem;
  font-size: 0.8rem;
  line-height: 1.4;
}
.row-menu-toggle:hover { color: var(--fg); }
/* 行メニューとサイドバーの右クリックメニューの共通の見た目(器と項目)。
   クラス名を分けるのはJSの衝突回避のためで、見た目の定義はこのカンマ束ねに集める。
   別definitionで残すのは位置の取り方(absolute / fixed)と z-index(50 / 95)だけ */
.row-menu-list, .sidebar-context-menu {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.2rem;
  white-space: nowrap;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.25);
}
.row-menu-list[hidden], .sidebar-context-menu[hidden] { display: none; }
.row-menu-item, .sidebar-context-menu-item {
  display: block;
  color: var(--fg);
  padding: 0.35rem 0.6rem;
  border-radius: 4px;
  font-size: 0.85rem;
}
.row-menu-item:hover, .sidebar-context-menu-item:hover { background: var(--bg); }

.row-menu-list {
  position: absolute;
  right: 0;
  top: calc(100% + 2px);
  z-index: 50;
}
/* 行メニューの項目は常にbutton(下のbutton.sidebar-context-menu-itemと同じ打ち消し) */
.row-menu-item {
  width: 100%;
  border: none;
  background: none;
  cursor: pointer;
  text-align: left;
}

/* フィード・フォルダの右クリックメニュー(サイドバー)。見た目は上の束ねで行メニューと共通。
   カーソル位置に出すのでpositionはfixed。z-indexは行メニュー(50)より上・記事ポップアップ(100)より下。
   **スマホのドロワー(90)と背幕(89)より上でもあること** — サイドバーの中から開くので、
   それより下だとドロワーの裏に描かれてタップが背幕に吸われ、メニューが押せない
   (以前は60で、Androidの長押しで実際に起きた) */
.sidebar-context-menu {
  position: fixed;
  z-index: 95;
}
/* フィード用/フォルダ用の項目の出し分け(app.jsがhiddenを付ける)。
   **クラスと同じ強さで打ち消すこと** — 上の display: block はクラス指定なので、
   ブラウザ既定の [hidden] { display: none } では消えない(器と同じ理由)。
   見た目の束ねへ移すリファクタで一度この1行だけが落ち、フィード用・フォルダ用の
   全項目が常に出る退行が起きた — 束ねを触るときもこの行は残すこと */
.sidebar-context-menu-item[hidden] { display: none; }
.sidebar-context-menu-item:hover { text-decoration: none; }
/* 並び替えの項目は button だが、リンクの項目と見分けが付かないようにそろえる */
button.sidebar-context-menu-item {
  width: 100%;
  border: 0;
  background: none;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}
/* 既に端にいるときは選べない(app.jsがdisabledを付ける) */
button.sidebar-context-menu-item:disabled { color: var(--muted); cursor: default; }
button.sidebar-context-menu-item:disabled:hover { background: none; }

/* --- 表示切替(リスト/カード) --- */
.view-toggle { display: inline-flex; }
.view-button {
  padding: 0.4rem 0.7rem;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--muted);
  cursor: pointer;
  font-size: 0.85rem;
}
/* --- 連結ボタン(セグメンテッドコントロール)の形状 ---
   .tag-sort-button / .sidebar-tab / .view-button で共有する。クラス名を分けるのは
   app.jsの表示モード切替が .view-button をクラスで拾うためで、見た目の定義はこの1組に集める。
   中間の境界線は隣接結合子で消す(:last-childでのborder-left消しと違い3ボタン以上でも正しい) */
.tag-sort-button:first-child, .sidebar-tab:first-child, .view-button:first-child, .insight-provider-tab:first-child { border-radius: 6px 0 0 6px; }
.tag-sort-button:last-child, .sidebar-tab:last-child, .view-button:last-child, .insight-provider-tab:last-child { border-radius: 0 6px 6px 0; }
.tag-sort-button + .tag-sort-button, .sidebar-tab + .sidebar-tab, .view-button + .view-button, .insight-provider-tab + .insight-provider-tab { border-left: none; }

/* サムネイルはリスト表示では出さない(カード表示時のみ可視化) */
.article-thumb-link { display: none; }

/* ul.articles.cards でカードグリッドに切り替える(app.jsがlocalStorageの選択を適用) */
.articles.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 0.8rem;
  border: none;
  border-radius: 0;
  background: none;
}
.articles.cards .article-row {
  position: relative;
  flex-direction: column;
  align-items: stretch;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  /* overflow: hiddenは使わない(⋮メニューのドロップダウンがカード枠で切れるため)。
     サムネイルのはみ出しは.article-thumb側の角丸で防ぐ */
}
.articles.cards .article-row:last-child { border-bottom: 1px solid var(--border); }
.articles.cards .article-thumb-link { display: block; position: relative; }
/* 画像の上に乗せるバッジの器。テーマに依存しない半透明の黒地(明るい画像でも暗い画像でも読める)。
   動画サムネイルの再生時間・ショートと、元ページ画像パネルの通し番号・実寸が共有する。
   左右の振り分けだけを下で分ける(同じ角に2つ置かない) */
.video-duration, .video-short, .page-image-no, .page-image-dim {
  position: absolute;
  bottom: 0.35rem;
  padding: 0 0.3rem;
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.75);
  color: #fff;
  font-size: 0.75rem;
  line-height: 1.5;
}
.video-duration, .page-image-dim { right: 0.35rem; }
.video-short, .page-image-no { left: 0.35rem; }
/* メタ行のショートバッジ。上の.video-shortはサムネイル上=カード表示専用なので、
   既定のリスト表示ではこちらが出る。カードでは二重になるので隠す。
   4割の行に付くため、アクセント色ではなく控えめな--mutedにして一覧を騒がせない */
.video-short-inline {
  display: inline-block;
  margin-left: 0.4rem;
  padding: 0 0.35rem;
  border: 1px solid var(--border);
  border-radius: 4px;
  font-size: 0.72rem;
  line-height: 1.6;
  color: var(--muted);
}
.articles.cards .video-short-inline { display: none; }
.articles.cards .article-thumb-link:hover .article-thumb { opacity: 0.85; }
.articles.cards .article-thumb {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  background: var(--bg);
  /* カードの角丸(8px)に合わせて上側だけ丸める */
  border-radius: 8px 8px 0 0;
}
.articles.cards .article-main { padding: 0.6rem 0.8rem; }
.articles.cards .article-title {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  white-space: normal;
  align-self: auto;
  min-height: 2.6em;
}
.articles.cards .article-meta { margin-top: 0.3rem; }
.articles.cards .read-toggle {
  position: absolute;
  top: 0.4rem;
  right: 0.4rem;
  margin: 0;
  background: var(--card);
}
.articles.cards .row-menu {
  position: absolute;
  top: 0.4rem;
  right: 3.2rem;
  margin: 0;
}
/* リボンは⋮のさらに左。サムネイルに重なるので既読トグルと同じくカードの地色を敷く */
.articles.cards .read-later-toggle {
  position: absolute;
  top: 0.4rem;
  right: 5.4rem;
  margin: 0;
  padding: 0.25rem 0.35rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 6px;
}
/* ドロップダウンはカード右端(0.4rem内側)に揃えて開く。⋮基準の右寄せのままだと
   左端カラムのカードでメニューが画面外へはみ出すため */
.articles.cards .row-menu-list { right: -2.8rem; }
/* カードのサムネ右上3ボタンはホバー可能なポインタ(マウスのあるPC)だけ半透明にする。
   常時不透明だとサムネの重要部分を隠す。タッチ端末はホバーで戻せないので対象外。
   opacityはトグル自身に付ける — .row-menu に掛けるとドロップダウンまで薄くなる */
@media (hover: hover) and (pointer: fine) {
  .articles.cards .read-toggle,
  .articles.cards .read-later-toggle,
  .articles.cards .row-menu-toggle {
    opacity: 0.28;
    transition: opacity 0.15s ease;
  }
  .articles.cards .article-row:hover .read-toggle,
  .articles.cards .article-row:hover .read-later-toggle,
  .articles.cards .article-row:hover .row-menu-toggle,
  .articles.cards .article-row:focus-within .read-toggle,
  .articles.cards .article-row:focus-within .read-later-toggle,
  .articles.cards .article-row:focus-within .row-menu-toggle,
  .articles.cards .row-menu:has(.row-menu-list:not([hidden])) .row-menu-toggle {
    opacity: 1;
  }
}

/* --- 元ページの画像パネル(記事画面) --- */
.page-images { margin: 0.8rem 0; border: 1px solid var(--border); border-radius: 8px; background: var(--card); padding: 0.8rem; }
.page-images-toolbar { display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap; margin-bottom: 0.5rem; }
.page-images-label { color: var(--muted); font-size: 0.85rem; }
/* ボタンに無い閾値の直接入力。器は上のフォーム入力の束ねと共有し、
   隣の連結ボタンに高さをそろえるため文字サイズだけ詰める */
.page-images-min-input { width: 6.5em; font-size: 0.85rem; line-height: 1.375; }
.page-images-status { color: var(--muted); font-size: 0.88rem; margin: 0.2rem 0 0; }
.page-images-hint { color: var(--muted); font-size: 0.8rem; margin: 0.15rem 0 0.6rem; }
/* タイルの大きさは data-tile-size から引く。色ではないのでパレット変数は増やさない */
.page-images-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 0.5rem;
  /* Shift+クリックとドラッグでテキスト選択が走らないようにする(選択の見た目が二重になる) */
  user-select: none;
}
.page-images[data-tile-size="sm"] .page-images-grid { grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); }
.page-images[data-tile-size="lg"] .page-images-grid { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
.page-image {
  position: relative;
  aspect-ratio: 1;
  border-radius: 6px;
  border: 2px solid transparent;
  background: var(--bg);
  cursor: pointer;
  overflow: hidden;
}
.page-image img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* 縦長や文字の多い画像は正方形の切り抜きでは中身が判らないので全体表示へ切り替えられる */
.page-images[data-fit="contain"] .page-image img { object-fit: contain; }
.page-image.selected { border-color: var(--accent); }
.page-image:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* 番号(ZIPのファイル名の連番と同じもの)と実寸のバッジ。器は動画サムネイルのバッジと共有する。
   実寸は load するまで判らないので、空の間は器ごと出さない */
.page-image-dim:empty { display: none; }
/* ボーダー色だけだと選択が飛び飛びのとき目で追えないのでチェックマークも重ねる */
.page-image-check {
  position: absolute;
  left: 0.25rem;
  top: 0.25rem;
  width: 1.15rem;
  height: 1.15rem;
  display: none;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-fg);
  font-size: 0.75rem;
  line-height: 1;
}
.page-image.selected .page-image-check { display: flex; }
.page-image-zoom {
  position: absolute;
  right: 0.25rem;
  top: 0.25rem;
  border: none;
  border-radius: 6px;
  background: var(--card);
  color: var(--fg);
  font-size: 0.8rem;
  line-height: 1;
  padding: 0.2rem 0.3rem;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.1s;
}
.page-image:hover .page-image-zoom, .page-image:focus-within .page-image-zoom { opacity: 1; }
/* タッチにはホバーが無いので常時表示にし、指で押し分けられるよう当たり判定も広げる
   (.drag-handle / .feed-fav / .folder-toggle と同じ扱い)。**基底の後ろに置くこと** —
   前方の800pxブロックへ足すと同じ詳細度で後ろの基底に負ける */
@media (max-width: 800px) {
  .page-image-zoom { opacity: 1; padding: 0.4rem 0.5rem; font-size: 0.95rem; }
}
/* ドラッグ中はホバー装飾を殺す(サイドバー並び替えの .reordering と同じ) */
.page-image-painting { cursor: crosshair; }
.page-image-painting .page-image-zoom { opacity: 0; }
/* サイズで隠した側を見ているときは、通常の一覧と取り違えないよう地色を落とす */
.page-images[data-filter-view="excluded"] .page-images-grid {
  background: var(--bg);
  border: 1px dashed var(--border);
  border-radius: 6px;
  padding: 0.4rem;
}
/* 「範囲を選ぶ」モード。始点は破線の枠にして「いまどこから」を見せる */
.page-images[data-range-mode] .page-image { cursor: cell; }
.page-images[data-range-mode] .page-image.range-start { border-color: var(--accent); border-style: dashed; }

/* 取得範囲の状態(「取得範囲: …」)。見つからなかった注記は danger で赤く */
.page-images-scope { color: var(--muted); font-size: 0.85rem; margin: 0 0 0.5rem; word-break: break-all; }
.page-images-scope.danger { color: var(--danger); }

/* 拡大プレビューと取得範囲の選択ツール。器は .app-modal 系と同形(下の「ポップアップの器」の
   定義がクラス名で効く)だが、記事ポップアップ(z-index:100)の中から開くので上に重ねる。
   2つは同時に開かないので同じ段でよい */
.page-image-lightbox, .page-scope-picker { position: fixed; inset: 0; z-index: 200; }
.page-image-lightbox[hidden], .page-scope-picker[hidden] { display: none; }
/* 選択ツールは元ページを見せる場所なので幅いっぱいに使う。ダイアログ自身はスクロールさせず
   iframe の中だけをスクロールさせる(ツールバーを常に見せるため) */
.page-scope-picker .app-modal-dialog {
  max-width: none;
  width: calc(100% - 2rem);
  height: 92vh;
  max-height: 92vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.page-scope-crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: 0.15rem; min-height: 1.8rem; margin-bottom: 0.4rem; font-size: 0.85rem; }
.page-scope-crumb {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--card);
  color: var(--fg);
  padding: 0.15rem 0.45rem;
  font-size: 0.82rem;
  cursor: pointer;
}
.page-scope-crumb.active { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }
.page-scope-crumb-sep { color: var(--muted); padding: 0 0.15rem; }
.page-scope-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; margin-bottom: 0.6rem; }
.page-scope-info { color: var(--muted); font-size: 0.88rem; }
.page-scope-selector { flex: 1; min-width: 12rem; font-size: 0.8rem; color: var(--muted); word-break: break-all; }
/* 保存する範囲の一覧(和集合)。チップ1つ=セレクタ1本、✕で外す */
.page-scope-list { flex: 1; display: flex; flex-wrap: wrap; gap: 0.3rem; align-items: center; min-width: 12rem; }
.page-scope-empty { color: var(--muted); font-size: 0.82rem; }
.page-scope-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  border: 1px solid var(--accent);
  border-radius: 6px;
  background: var(--new-bg);
  color: var(--fg);
  padding: 0.1rem 0.2rem 0.1rem 0.45rem;
  font-size: 0.8rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.page-scope-chip-remove { border: none; background: none; color: var(--muted); font-size: 1rem; line-height: 1; padding: 0 0.25rem; cursor: pointer; }
.page-scope-chip-remove:hover { color: var(--danger); }
.page-scope-frame { flex: 1; width: 100%; min-height: 0; border: 1px solid var(--border); border-radius: 6px; background: #fff; }
.page-image-lightbox .app-modal-dialog { max-width: 1100px; }
.page-image-lightbox-body { display: flex; align-items: center; gap: 0.4rem; margin: 0.6rem 0; }
.page-image-lightbox-img {
  flex: 1;
  min-width: 0;
  max-height: 70vh;
  object-fit: contain;
  background: var(--bg);
  border-radius: 6px;
}
.page-image-lightbox-nav {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--card);
  color: var(--muted);
  font-size: 1.4rem;
  line-height: 1;
  padding: 0.6rem 0.4rem;
  cursor: pointer;
}
.page-image-lightbox-nav:hover:not(:disabled) { color: var(--fg); }
.page-image-lightbox-nav:disabled { opacity: 0.35; cursor: default; }
.page-image-lightbox-url { color: var(--muted); font-size: 0.8rem; word-break: break-all; margin: 0; }

/* --- 記事閲覧 --- */
.article-view h1 { margin-bottom: 0.2rem; }
.article-tools { display: flex; gap: 0.6rem; flex-wrap: wrap; margin: 0.8rem 0 0.2rem; }
/* プレイヤーの下地はテーマに依存しない黒。新しい配色変数は増やさない。
   幅を抑えないとワイド画面で高さが700px超になり説明文が画面外へ落ちる */
.video-embed {
  aspect-ratio: 16 / 9;
  max-width: 960px;
  margin-top: 1rem;
  background: #000;
  border-radius: 8px;
  overflow: hidden;
}
.video-embed iframe { width: 100%; height: 100%; border: 0; display: block; }
/* モーダル内は本文も読めるように高さを抑える */
.article-modal .video-embed { max-height: 60vh; }
/* 要約内容(.article-summary)は受信内容と同じカードで見せる(定義はこの束ねの1組だけ) */
.article-content,
.article-summary {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 1rem 1.4rem;
  margin-top: 1rem;
  overflow-wrap: break-word;
}
.article-content img { max-width: 100%; height: auto; }
.article-content pre { overflow-x: auto; background: var(--bg); padding: 0.7rem; border-radius: 6px; }
/* 受信内容 / 要約内容のタブ(→ rules/summary.md)。タブ列の見た目は .is-tabbed .tab-list / .tab の共有定義で、
   is-tabbed は要約があるときだけ付く(無ければタブ列は出ず従来の見た目のまま)。タブ列の下線とカードをつなげる */
.article-panes.is-tabbed > [data-pane] { margin-top: 0; border-top-left-radius: 0; }
.article-summary-meta { color: var(--muted); font-size: 0.85rem; margin: 0 0 0.6rem; }
/* 要約はHTML(見出し・段落・箇条書き・引用。.is-html)か、プレーンテキスト(改行をそのまま見せる)のどちらか */
.article-summary-text { line-height: 1.7; }
.article-summary-text:not(.is-html) { white-space: pre-wrap; }
.article-summary-text.is-html > :first-child { margin-top: 0; }
.article-summary-text.is-html h3 { font-size: 1.05rem; margin: 1.4rem 0 0.5rem; padding-bottom: 0.25rem; border-bottom: 1px solid var(--border); }
.article-summary-text.is-html h4 { font-size: 0.95rem; margin: 1rem 0 0.4rem; }
.article-summary-text.is-html p { margin: 0.5rem 0; }
.article-summary-text.is-html ul, .article-summary-text.is-html ol { margin: 0.5rem 0; padding-left: 1.4rem; }
.article-summary-text.is-html li + li { margin-top: 0.25rem; }
.article-summary-text.is-html blockquote {
  margin: 0.5rem 0;
  padding: 0.4rem 0.8rem;
  border-left: 3px solid var(--border);
  background: var(--bg);
  border-radius: 0 6px 6px 0;
}
.summary-select { min-width: 0; max-width: 100%; }
.summary-status { align-self: center; color: var(--muted); font-size: 0.85rem; }
.summary-status:empty { display: none; }

/* --- 記事ポップアップ --- */
/* 器・背幕・ダイアログ・閉じるボタンの共通見た目は .app-modal 系の節(カンマ束ね)にあり、
   そこに .article-modal の差分(本文向けに幅を860pxへ絞る、ボタンのsticky追従)が続く。
   ここには記事ポップアップ固有の進捗表示だけを置く */
/* 進行中は n/m の進捗表示になる。font-size×line-heightで通常時と同じ高さを保つ。
   sticky配置で本文に重なるため、opacityではなく不透明背景のまま文字色だけ抑える */
.article-modal-download:disabled { cursor: default; font-size: 0.8rem; line-height: 1.375; }
.modal-open, .modal-open body { overflow: hidden; }

/* --- 類似記事(バッジ+ポップアップ/記事詳細のブロック) --- */
.similar-badges { display: inline-flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.15rem; }
.similar-badge {
  display: inline-block;
  font-size: 0.75rem;
  padding: 0 0.5rem;
  border: 1px solid var(--accent);
  border-radius: 999px;
  background: var(--bg);
  color: var(--accent);
  cursor: pointer;
  white-space: nowrap;
}
.similar-badge:hover { background: var(--accent); color: var(--accent-fg); }
.similar-badge-read { border-color: var(--warn-border); background: var(--warn-bg); color: var(--warn-fg); }
.similar-badge-read:hover { background: var(--warn-fg); border-color: var(--warn-fg); color: var(--warn-bg); }
.similar-source { color: var(--muted); font-size: 0.85rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.similar-section { margin-top: 1.2rem; }
.similar-section h2 { font-size: 1rem; margin: 0 0 0.4rem; }
.similar-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.similar-item { display: flex; gap: 0.6rem; align-items: baseline; }
.similar-score { flex: 0 0 auto; font-size: 0.75rem; color: var(--muted); border: 1px solid var(--border); border-radius: 6px; padding: 0 0.3rem; }
.similar-main { display: flex; flex-direction: column; min-width: 0; }
.similar-title { overflow-wrap: anywhere; }
.similar-meta { color: var(--muted); font-size: 0.8rem; }
.similar-item .read-toggle { margin: 0 0 0 auto; flex: 0 0 auto; }

/* --- タグ --- */
.tag-cloud { display: flex; flex-wrap: wrap; gap: 0.3rem; }

/* --- 読んだ履歴 --- */
/* タグ一覧は素の <details> で畳む(既定=閉。summaryの見た目は .chart-table summary の束ねと共有) */
.history-tags { margin: 0.8rem 0 1.2rem; }
.history-tags .tag-cloud { margin-top: 0.4rem; }
.tag {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.05rem 0.6rem;
  font-size: 0.85rem;
  color: var(--fg);
}
a.tag:hover, button.tag:hover { border-color: var(--accent); text-decoration: none; }
button.tag { cursor: pointer; font-family: inherit; }
.tag small { color: var(--accent); font-weight: 700; }
/* タグ操作UIとブックマーク操作UI(bookmark-*)は同形。クラス名を分けるのはJS委譲の衝突を
   避けるためで、見た目の定義はこの1組に集める(以前は5行まるごと2箇所に重複していた) */
.tag-remove, .bookmark-remove { border: none; background: none; cursor: pointer; color: var(--muted); font-size: 0.9rem; padding: 0; }
.tag-remove:hover, .bookmark-remove:hover { color: var(--danger); }
.tag-editor, .bookmark-editor { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; margin: 0.6rem 0; }
.tag-list, .bookmark-list { display: inline-flex; flex-wrap: wrap; gap: 0.3rem; }
/* セレクトの幅は中身(最長のタグ名)で決まるため、幅を内容から切り離さないと狭い画面で
   行ごと画面外へはみ出し、ページ全体に横スクロールが出る(375pxで scrollWidth=700 だった)。
   flex-wrap で中を折り返せるようにし、min-width: 0 で「内容幅より縮まない」flex項目の既定を外す。
   セレクトが自然幅に収まる広さでは1行のまま縮まないので、PCの見た目は変わらない */
.tag-add, .bookmark-add { display: inline-flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; min-width: 0; }
.tag-add-search, .tag-add-name, .bookmark-add-select, .bookmark-add-name { padding: 0.3rem 0.5rem; border: 1px solid var(--border); border-radius: 6px; background: var(--card); min-width: 0; }
.tag-add-name, .bookmark-add-name { width: 9rem; }
.tag-add-search { width: 11rem; }
.tag-add-hint { color: var(--muted); font-size: 0.8rem; }
/* 候補は .tag-editor(flex-wrap)の全幅の子にして必ず入力欄の下の行に出す。
   候補が無いときは高さを持たせない(:empty で行ごと消す) */
.tag-add-results { width: 100%; }
.tag-add-results:empty { display: none; }

.suggestion-box { margin: 1.2rem 0; }
.bulk-suggestion-actions { margin-top: 0.6rem; }
.tag-merge-form { margin: 0.8rem 0; flex-wrap: wrap; }
.tag-merge-form .merge-arrow { color: var(--muted); }
/* --- 選択中(アクセント地)の共通見た目 ---
   トグル・タブ類の active はすべてこの1組に集める(以前はプロパティ順まで揺れた同じ3行が
   9箇所に散り、grepで「トグルの選択色」を一括で見つけられなかった)。
   サイドバータブの選択色だけは data-current-pane 属性から引くため「サイドバーのタブ」の節にある */
.unread-only-toggle.active, .tag-sort-button.active, .order-toggle.active, .singleton-toggle.active,
.has-js .filter-toggle.active, .select-toggle.active, .view-button.active, .insight-provider-tab.active,
.page-images-fit.active, .page-images-range.active, .page-images-excluded.active,
a.tag.active, .merge-pick.active, .tag-suggest-item.active {
  background: var(--accent); color: var(--accent-fg); border-color: var(--accent);
}
.analysis-box { margin: 1.2rem 0; }
.analysis-box .inline-form { margin: 0.6rem 0 0.3rem; }

/* --- ポップアップの器(.app-modal / .pending-modal / .article-modal) --- */
/* .pending-modal が先にあった器で、同じ見た目を他画面(フィード編集の「生の取得結果」)でも
   使うため .app-modal を並記した。記事ポップアップ(.article-modal)も器は同形なのでここへ
   束ね、差分(幅・ボタンのsticky)だけをこの節の末尾で上書きする。名前を付け替えると各画面の
   テンプレートと app.js の両方を触るので、既存側は据え置き。新しいポップアップは .app-modal 系を使うこと */
.pending-modal, .app-modal, .article-modal { position: fixed; inset: 0; z-index: 100; }
/* .article-modal-read[hidden] も要る — 兼ねている .read-toggle が display: inline-block を持つので
   UA の [hidden] では消えない(.sidebar-context-menu-item[hidden] と同じ事故クラス) */
.pending-modal[hidden], .app-modal[hidden], .article-modal[hidden], .article-modal-read[hidden] { display: none; }
.pending-modal-backdrop, .app-modal-backdrop, .article-modal-backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.55); }
.pending-modal-dialog, .app-modal-dialog, .article-modal-dialog {
  position: relative;
  margin: 4vh auto;
  /* メインコンテンツ(.container: 最大1500px)の85%程度に合わせる */
  max-width: 1275px;
  width: 85%;
  max-height: 92vh;
  overflow-y: auto;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.8rem 1.4rem 1.2rem;
}
.pending-modal-head, .app-modal-head { display: flex; align-items: center; gap: 0.8rem; }
.pending-modal-head h2, .app-modal-head h2 { flex: 1; margin: 0; font-size: 1.1rem; }
.pending-modal-close, .app-modal-close,
.article-modal-close, .article-modal-newtab, .article-modal-download, .article-modal-read,
.article-modal-history-remove, .article-history-remove {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--card);
  color: var(--muted);
  font-size: 1.1rem;
  line-height: 1;
  padding: 0.3rem 0.55rem;
  cursor: pointer;
}
.pending-modal-close:hover, .app-modal-close:hover,
.article-modal-close:hover, .article-modal-newtab:hover,
.article-modal-download:hover:not(:disabled) { color: var(--fg); }
/* 既読アイコン・ゴミ箱はカラー絵文字で color を無視するので、hover は枠色で示す(a.chip-link:hover と同じ語彙) */
.article-modal-read:hover, .article-modal-history-remove:hover:not(:disabled),
.article-history-remove:hover:not(:disabled) { border-color: var(--accent); }
/* ゴミ箱は応答待ち(ページでは削除済みも)だけ disabled になる */
.article-modal-history-remove:disabled, .article-history-remove:disabled { cursor: default; opacity: 0.5; }
/* 一括タグ操作の差分: 中身は検索欄と候補チップだけなので、既定の1275pxでは広すぎる
   (器そのものは .app-modal の束ねを共有する。定義をコピーしない) */
.bulk-tag-modal .app-modal-dialog, .saved-search-modal .app-modal-dialog { max-width: 560px; width: calc(100% - 2rem); }
/* 保存した検索のモーダル(.saved-search-*)は一括タグ操作と同じ部品の束ねを共有する(定義をコピーしない) */
.bulk-tag-picker, .saved-search-field { display: flex; flex-wrap: wrap; gap: 0.4rem 0.8rem; align-items: baseline; margin: 0.8rem 0 0.5rem; }
/* セレクトと同じ事情で min-width: 0 が要る(狭い画面で器からはみ出さないように) */
.bulk-tag-search-label, .saved-search-name-label { display: inline-flex; align-items: center; gap: 0.4rem; min-width: 0; }
.bulk-tag-search, .saved-search-name { padding: 0.3rem 0.5rem; border: 1px solid var(--border); border-radius: 6px; background: var(--card); min-width: 0; }
.saved-search-name { flex: 1; }
.saved-search-name-label { flex: 1; }
.bulk-tag-hint { color: var(--muted); font-size: 0.82rem; }
/* 候補欄は一括タグ操作と記事のタグ編集(.tag-add-results)で共有する。最大30件が縦に伸びて
   ボタンや本文を押し下げないよう、ここだけスクロールさせる */
.tag-suggest-results { display: flex; flex-wrap: wrap; gap: 0.3rem; max-height: 40vh; overflow-y: auto; }
.bulk-tag-results { margin-bottom: 0.6rem; }
.tag-suggest-empty { color: var(--muted); font-size: 0.85rem; }
.bulk-tag-selected { margin: 0.4rem 0 0.8rem; }
.bulk-tag-actions, .saved-search-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; }

/* 記事ポップアップの差分: 本文向けに幅を読みやすい860pxへ絞り、
   閉じる/新しいタブ/一括DL/既読アイコン/ゴミ箱のボタンは長い本文をスクロールしても追従させる
   (float: right なので DOM 順の逆に並ぶ。左から 既読アイコン・一括DL・新しいタブ・閉じる。
   ゴミ箱だけ float: left で左上) */
.article-modal-dialog { max-width: 860px; width: calc(100% - 2rem); }
.article-modal-close, .article-modal-newtab, .article-modal-download, .article-modal-read,
.article-modal-history-remove {
  position: sticky; top: 0; float: right; z-index: 1;
}
.article-modal-history-remove { float: left; margin-right: 0.6rem; }
/* 記事ページのゴミ箱は「← 戻る」の横(sticky にはしない) */
.article-history-remove { margin-left: 0.6rem; }
.article-modal-newtab { text-decoration: none; margin-right: 0.4rem; }
.article-modal-download, .article-modal-read { margin-right: 0.4rem; }
/* 兼ねている .read-toggle の margin: 0 0.6rem の左だけを打ち消す(右は上の 0.4rem が勝つ) */
.article-modal-read { margin-left: 0; }
.pending-modal-meta, .app-modal-meta { color: var(--muted); font-size: 0.85rem; margin: 0.4rem 0 0.8rem; }
.pending-list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--border); border-radius: 8px; background: var(--card); }
.pending-row { display: flex; gap: 0.8rem; align-items: baseline; padding: 0.45rem 0.8rem; border-bottom: 1px solid var(--border); }
.pending-row:last-child { border-bottom: none; }
.pending-row .pending-title { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pending-row .pending-item-meta { color: var(--muted); font-size: 0.78rem; white-space: nowrap; }
.pending-cards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 0.8rem;
}
.pending-card { border: 1px solid var(--border); border-radius: 8px; background: var(--card); }
.pending-card .pending-thumb,
.pending-card .pending-thumb-none {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  background: var(--bg);
  /* カードの角丸(8px)に合わせて上側だけ丸める */
  border-radius: 8px 8px 0 0;
}
.pending-card .pending-thumb-none { display: flex; align-items: center; justify-content: center; color: var(--muted); font-size: 0.8rem; }
.pending-card .pending-title {
  padding: 0.5rem 0.7rem 0.1rem;
  font-size: 0.9rem;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
.pending-card .pending-item-meta { padding: 0.2rem 0.7rem 0.6rem; color: var(--muted); font-size: 0.75rem; }
/* 狭い画面では85%だと余白がもったいないため、ほぼ全幅にする */
@media (max-width: 800px) {
  .pending-modal-dialog, .app-modal-dialog { width: calc(100% - 2rem); max-width: none; }
}

/* --- フィード編集「生の取得結果」(.feed-raw-modal) --- */
/* リクエストごとに1ブロック。URLはクエリが長いので折り返す。本文は <pre> で生のまま、
   ダイアログの中で自分だけスクロールする(1本が数百KBになることがある) */
.feed-raw-request { border: 1px solid var(--border); border-radius: 8px; background: var(--card); margin-bottom: 0.9rem; }
.feed-raw-request-head { display: flex; flex-wrap: wrap; gap: 0.3rem 0.8rem; align-items: baseline; padding: 0.5rem 0.8rem; border-bottom: 1px solid var(--border); font-size: 0.85rem; }
.feed-raw-request-head code { word-break: break-all; }
.feed-raw-request-head .feed-raw-status { font-variant-numeric: tabular-nums; white-space: nowrap; }
.feed-raw-request-head .feed-raw-status.danger { color: var(--danger); }
.feed-raw-request-head .feed-raw-size { color: var(--muted); white-space: nowrap; }
.feed-raw-request-tools { display: flex; gap: 0.6rem; align-items: center; margin-left: auto; }
.feed-raw-request-tools label { display: inline-flex; align-items: center; gap: 0.3rem; color: var(--muted); font-size: 0.82rem; cursor: pointer; }
.feed-raw-pre {
  margin: 0; padding: 0.7rem 0.8rem; max-height: 60vh; overflow: auto;
  font-size: 0.8rem; line-height: 1.45; white-space: pre-wrap; word-break: break-all;
  background: var(--bg); border-radius: 0 0 8px 8px;
}
.feed-raw-summary { font-size: 0.9rem; margin: 0 0 0.8rem; }
.feed-raw-summary .badge { margin-right: 0.3rem; }
.feed-raw-note { color: var(--muted); font-size: 0.82rem; margin: 0.3rem 0 0.8rem; }

/* --- ログ閲覧画面 --- */
.log-controls { flex-wrap: wrap; }
.log-controls select { padding: 0.4rem 0.5rem; border: 1px solid var(--border); border-radius: 6px; background: var(--card); color: var(--fg); }
.log-meta { color: var(--muted); font-size: 0.85rem; margin: 0.4rem 0; }
/* メタ表示とアーカイブボタンを1行に。狭い画面では折り返して縦に積む */
.log-meta-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.5rem; }
/* ボタン同士は隣り合わせにする(space-betweenで引き離されないよう1つの項目にまとめる) */
.log-meta-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.log-textarea {
  width: 100%;
  height: 70vh;
  font-family: ui-monospace, SFMono-Regular, Consolas, "Courier New", monospace;
  font-size: 0.78rem;
  line-height: 1.5;
  background: var(--card);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.6rem;
  resize: vertical;
  box-sizing: border-box;
}
/* clickableはJSが付与(行クリックでのチェック切替が効くときだけクリック可能に見せる) */
.suggestion-row.clickable { cursor: pointer; }
.suggestion-row.clickable:hover { background: var(--bg); }

/* --- トースト通知・確認ダイアログ(モーダルz-index:100より上に重ねる) --- */
.toast-container {
  position: fixed;
  top: 1rem;
  right: 1rem;
  z-index: 300;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.5rem;
}
.toast {
  max-width: min(22rem, calc(100vw - 2rem));
  background: var(--card);
  color: var(--fg);
  border: 1px solid var(--border);
  border-left: 4px solid var(--accent);
  border-radius: 8px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.18);
  padding: 0.6rem 0.9rem;
  font-size: 0.9rem;
  cursor: pointer;
  opacity: 0;
  transform: translateX(calc(100% + 1.5rem));
  transition: transform 0.3s ease, opacity 0.3s ease;
}
.toast.show { opacity: 1; transform: none; }
.toast.ok { border-left-color: var(--ok-fg); }
.toast.danger { border-left-color: var(--danger); }
.toast.warn { border-left-color: var(--warn-fg); }
/* 操作ボタン付きトースト(一括既読の「既読操作を巻き戻す」)。ボタン列の並びは確認ダイアログと束ね、
   トーストの文字サイズに合わせてボタンだけ縮める(.feed-bulk-actions .link-button と同じ文脈指定) */
.toast-actions { margin-top: 0.4rem; }
.toast-actions .button { font-size: 0.85rem; padding: 0.25rem 0.7rem; }

.app-confirm-overlay {
  position: fixed;
  inset: 0;
  z-index: 310;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}
.app-confirm {
  background: var(--card);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
  padding: 1.2rem 1.4rem;
  max-width: 26rem;
  width: 100%;
}
.app-confirm-message { margin: 0 0 1rem; white-space: pre-line; }
.app-confirm-actions, .toast-actions { display: flex; justify-content: flex-end; gap: 0.6rem; }

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

/* --- ブックマーク(タグ操作UIと同形) ---
   .bookmark-editor 系の見た目はタグ操作UIの節(.tag-editor 系とのカンマ束ね)にある */

/* --- ステータス画面 --- */
/* 系列色はカード背景(#ffffff / #1c2127)に対して検証済みのカテゴリカル3色。
   順序そのものが色覚多様性への安全機構なので、入れ替えたり4色目を足したりしないこと。
   ライト/ダークの切り替えはファイル冒頭のパレットと同じ light-dark() 方式 */
:root {
  --viz-1: light-dark(#2a78d6, #3987e5);
  --viz-2: light-dark(#eb6834, #d95926);
  --viz-3: light-dark(#1baf7a, #199e70);
}

/* DB容量の警告状態色(80/90/99%、しきい値の定義は DbSizeReport)。系列色ではなく
   「状態色」— バー単位で series-N を置き換えるだけで系列は増やさないので、上の
   4色目禁止(カテゴリカル系列の規約)には触れない。黄は --viz-2 の橙と見分けられる
   色味にしてある。99%の黒は両テーマとも黒(ユーザー指定)で、ダークでは背景に
   沈むため縁取り(--viz-forced-edge)で視認性を確保する(ライトは fill と同色=実質なし) */
:root {
  --viz-caution: light-dark(#c9a20a, #d9b83f);
  --viz-danger: var(--danger);
  --viz-forced: #000000;
  --viz-forced-edge: light-dark(#000000, #aeb7c2);
}

.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 0.8rem;
  margin: 0.8rem 0 1.4rem;
}
.stat-tile {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.7rem 0.9rem;
}
.stat-label { color: var(--muted); font-size: 0.8rem; }
/* 大きい数字は等幅数字にしない(表示サイズだと字間が間延びするため) */
.stat-value { font-size: 1.6rem; font-weight: 600; line-height: 1.2; }
.stat-sub { color: var(--muted); font-size: 0.78rem; }
.stat-sub.is-alert, .stat-value.is-alert { color: var(--danger); }
/* 使用率タイルの注意段階(80%以上90%未満)。90%以上は既存の is-alert(赤) */
.stat-value.is-caution { color: var(--warn-fg); }

/* DB容量の警告バナー(/status のDBデータサイズのセクション先頭。文言はテンプレートが
   DbSizeReport の定数から組む)。is-forced は黒地+白文字で「最も重い警告」を示す */
.db-size-banner {
  margin: 0.8rem 0 0;
  padding: 0.6rem 0.9rem;
  border: 1px solid;
  border-radius: 8px;
  font-size: 0.9rem;
}
.db-size-banner.is-caution { color: var(--warn-fg); border-color: var(--warn-border); background: var(--warn-bg); }
.db-size-banner.is-danger { color: var(--danger); border-color: var(--danger-border); background: var(--danger-bg); }
.db-size-banner.is-forced { color: #ffffff; border-color: var(--viz-forced-edge); background: var(--viz-forced); }

.status-range, .feed-stats-range, .web-search-log-months { margin: 0 0 1.2rem; flex-wrap: wrap; }
.status-range .range-label, .feed-stats-range .range-label, .web-search-log-months .range-label { color: var(--muted); font-size: 0.85rem; }
/* 実区間の注記はボタン群の次の行へ回す(inline-formのflexに乗せて折り返させる) */
.status-range .status-range-dates { flex-basis: 100%; margin: 0; }

.chart-card {
  margin: 0 0 1.4rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.9rem 1rem 0.7rem;
}
.chart-card figcaption { font-size: 0.92rem; font-weight: 600; margin-bottom: 0.6rem; }
.chart-note { display: block; font-weight: 400; color: var(--muted); font-size: 0.78rem; margin-top: 0.15rem; }
.chart-canvas { position: relative; }
.chart-svg { display: block; width: 100%; height: auto; }
.chart-svg:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.chart-empty { color: var(--muted); font-size: 0.85rem; padding: 2rem 0; text-align: center; }

/* 目盛りと軸はデータより後ろに退かせる。等幅数字は縦に揃える列なので目盛りには使う */
.chart-grid { stroke: var(--border); stroke-width: 1; }
.chart-axis-text { fill: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; }
.chart-band { fill: var(--fg); opacity: 0; }
.chart-band.is-active { opacity: 0.06; }
.chart-hit { fill: transparent; }
.chart-crosshair { stroke: var(--muted); stroke-width: 1; }

/* 積み上げの区切りは2pxのサーフェス色ギャップで作る(枠線は引かない) */
.chart-fill.series-1 { fill: var(--viz-1); }
.chart-fill.series-2 { fill: var(--viz-2); }
.chart-fill.series-3 { fill: var(--viz-3); }
/* 警告状態のバー(DBサイズグラフ)。is-* は series-N の置き換えで JS が付ける。
   is-forced の縁取りはダークテーマでの視認性用(ライトは fill と同色) */
.chart-fill.is-caution { fill: var(--viz-caution); }
.chart-fill.is-danger { fill: var(--viz-danger); }
.chart-fill.is-forced { fill: var(--viz-forced); stroke: var(--viz-forced-edge); stroke-width: 1.5; }
/* 予測系列(DBサイズグラフ)の薄い表示。棒・凡例・ツールチップの色見本を同じ濃さでそろえる */
.chart-fill.is-faint, .chart-legend-key.is-faint, .chart-tooltip-key.is-faint { opacity: 0.4; }
.chart-line { fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.chart-line.series-1 { stroke: var(--viz-1); }
.chart-line.series-2 { stroke: var(--viz-2); }
.chart-line.series-3 { stroke: var(--viz-3); }
.chart-dot { stroke: var(--card); stroke-width: 2; }
.chart-dot.series-1 { fill: var(--viz-1); }
.chart-dot.series-2 { fill: var(--viz-2); }
.chart-dot.series-3 { fill: var(--viz-3); }

.chart-legend { display: flex; flex-wrap: wrap; gap: 0.9rem; margin-top: 0.6rem; }
.chart-legend-item { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.82rem; color: var(--muted); }
.chart-legend-key { width: 12px; height: 12px; border-radius: 3px; flex: none; }
.chart-legend-key.is-line { height: 2px; border-radius: 1px; }
.chart-legend-key.series-1 { background: var(--viz-1); }
.chart-legend-key.series-2 { background: var(--viz-2); }
.chart-legend-key.series-3 { background: var(--viz-3); }
/* 警告状態の色見本(凡例はデータに現れたレベルのぶんだけJSが足す)。
   is-forced の inset 影はバーの縁取りの再現 */
.chart-legend-key.is-caution, .chart-tooltip-key.is-caution { background: var(--viz-caution); }
.chart-legend-key.is-danger, .chart-tooltip-key.is-danger { background: var(--viz-danger); }
.chart-legend-key.is-forced, .chart-tooltip-key.is-forced { background: var(--viz-forced); box-shadow: inset 0 0 0 1px var(--viz-forced-edge); }

.chart-tooltip {
  position: absolute;
  z-index: 5;
  min-width: 9rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
  padding: 0.5rem 0.6rem;
  font-size: 0.8rem;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.08s linear;
}
.chart-tooltip.is-visible { opacity: 1; }
.chart-tooltip-title { color: var(--muted); margin-bottom: 0.3rem; }
.chart-tooltip-row { display: flex; align-items: center; gap: 0.4rem; margin-top: 0.15rem; }
.chart-tooltip-key { width: 10px; height: 2px; border-radius: 1px; flex: none; }
.chart-tooltip-key.series-1 { background: var(--viz-1); }
.chart-tooltip-key.series-2 { background: var(--viz-2); }
.chart-tooltip-key.series-3 { background: var(--viz-3); }
/* 値が主役・系列名が従(凡例と逆の階層)。読み手は系列を知っていて数字を知りたい */
.chart-tooltip-value { font-weight: 600; color: var(--fg); font-variant-numeric: tabular-nums; margin-left: auto; }
.chart-tooltip-name { color: var(--muted); }
/* 警告レベルの日にツールチップへ足す文言行(色だけに頼らない)。
   is-forced の文字を黒にしないのはタイルと同じ理由(ダークのカード背景で消える) */
.chart-tooltip-status { font-weight: 600; }
.chart-tooltip-status.is-caution { color: var(--warn-fg); }
.chart-tooltip-status.is-danger, .chart-tooltip-status.is-forced { color: var(--danger); }

/* 畳んだ表。バックアップ比較の「並び順だけ」と読んだ履歴のタグ一覧(.history-tags)も
   同じ見出しでよいので summary のセレクタを共有する(marginは用途ごとに別なので束ねない) */
.chart-table, .diff-fold { margin: -0.6rem 0 1.4rem; }
/* アカウント同期の「一致」の畳みと、OPMLエディタの「登録中」の畳み、保存した検索の差分の「一致」の畳み。
   いずれも直前が表そのものではない(実行ボタン / 未登録表+注記)ので負のマージンで詰めない */
.sync-matches, .opml-registered-fold, .saved-search-diff-same { margin: 1rem 0 1.4rem; }
.sync-del-mode { border: 1px solid var(--border); border-radius: 6px; margin: 0 0 0.8rem; padding: 0.4rem 0.8rem; }
.sync-del-mode legend { font-size: 0.85rem; color: var(--muted); }
.chart-table summary, .diff-fold summary, .sync-matches summary, .opml-registered-fold summary, .saved-search-diff-same summary, .history-tags summary, #token-count-result summary, .takeout-console-help summary { cursor: pointer; color: var(--muted); font-size: 0.85rem; }
.list-table.numeric td { font-variant-numeric: tabular-nums; text-align: right; }
.list-table.numeric td:first-child { text-align: left; }

.price-fields { display: flex; flex-wrap: wrap; gap: 0.8rem; align-items: flex-end; }

/* トークン数試算の結果(設定画面AI分析タブ)と、フィード登録YouTubeタブの
   コンソールスクリプト。長くなるのでスクロール箱に閉じ込める */
#token-count-result pre,
.takeout-console-help pre {
  max-height: 16em;
  overflow: auto;
  margin: 0.4rem 0 0;
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--bg);
  font-size: 0.85rem;
}

/* フィード登録YouTubeタブの「コンソールで取り出す」ヘルプ(Takeoutがデータなしのときの代替手順) */
.takeout-console-help { margin: 0 0 1.2rem; }
/* コピーはJSでしか動かないので入口のボタンはJS有効時だけ見せる(.folder-visited と同じ規約) */
html:not(.has-js) .console-copy { display: none; }

/* プロバイダ別モデル名の入力群(設定画面のAIプロバイダタブ) */
.provider-models { display: flex; flex-direction: column; gap: 0.6rem; padding: 0.6rem 0.8rem 0.8rem; }
.provider-models legend { font-size: 0.9rem; color: var(--muted); padding: 0 0.3rem; }

/* --- ステータス画面「特定の日を見る」 --- */
.status-day-jump { margin: -0.6rem 0 1.4rem; font-size: 0.9rem; }
.status-day h3 { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.6rem; margin: 1.6rem 0 0.8rem; }
/* 今日は途中経過で前日と単純に比べられない。見出しに必ず添える注記 */
.day-partial { color: var(--muted); font-size: 0.82rem; font-weight: 400; }
.day-detail-empty { color: var(--muted); padding: 1.5rem 0; }

.day-picker {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.9rem 1rem;
  max-width: 26rem;
}
.cal-nav { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.6rem; }
.cal-nav-title { font-weight: 600; }
.cal-nav-link { font-size: 0.88rem; }
.cal-nav-link.is-disabled { color: var(--muted); opacity: 0.5; }

.cal { width: 100%; border-collapse: collapse; table-layout: fixed; }
.cal-caption { caption-side: bottom; color: var(--muted); font-size: 0.78rem; text-align: left; padding-top: 0.5rem; }
.cal-head { color: var(--muted); font-size: 0.75rem; font-weight: 500; padding-bottom: 0.2rem; }
.cal-cell { padding: 1px; }

.cal-day {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.05rem;
  min-height: 2.5rem;
  border-radius: 6px;
  color: var(--fg);
  text-decoration: none;
  font-variant-numeric: tabular-nums;
}
/* 濃淡は「順序そのものが意味」の連続スケールなので、カテゴリカルな --viz-1..3 の並びには
   手を付けず --viz-1 の濃度だけを4段にする。不透明度で作るのは .chart-band と同じ機構で、
   下地(--card)がテーマで変わっても自動で追従する(色を2セット定義しなくてよい)。
   最上段を0.55に抑えているのは、その上に載る --fg がライト/ダーク両方で読める上限だから。
   .tree a で ::before を禁じているのは flex項目が増えるからで、こちらは absolute なので該当しない */
.cal-day::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 6px;
  background: var(--viz-1);
  opacity: 0;
  pointer-events: none;
}
.cal-day > * { position: relative; }
.cal-level-1::before { opacity: 0.12; }
.cal-level-2::before { opacity: 0.26; }
.cal-level-3::before { opacity: 0.40; }
.cal-level-4::before { opacity: 0.55; }
/* 今日と選択中は色ではなく枠線で示す(グレースケールでも濃淡と混ざらずに読める) */
.cal-day.is-today { box-shadow: inset 0 0 0 1px var(--muted); }
.cal-day.is-selected { box-shadow: inset 0 0 0 2px var(--accent); font-weight: 700; }
.cal-day.is-outside { color: var(--muted); opacity: 0.45; }
a.cal-day:hover { text-decoration: none; box-shadow: inset 0 0 0 1px var(--accent); }
a.cal-day.is-selected:hover { box-shadow: inset 0 0 0 2px var(--accent); }
a.cal-day:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.cal-day-num { font-size: 0.85rem; line-height: 1.1; }
/* 色だけに頼らないための実数。段階が読めない環境でもここで比べられる */
.cal-day-count { font-size: 0.65rem; line-height: 1; color: var(--muted); }
.cal-day.is-selected .cal-day-count { color: var(--fg); }

.cal-legend { display: flex; align-items: center; gap: 0.25rem; margin: 0.7rem 0 0; color: var(--muted); font-size: 0.75rem; }
.cal-legend-swatch { position: relative; width: 14px; height: 14px; border-radius: 3px; flex: none; }
.cal-legend-swatch::before { content: ""; position: absolute; inset: 0; border-radius: 3px; background: var(--viz-1); }
.cal-legend-swatch.cal-level-1::before { opacity: 0.12; }
.cal-legend-swatch.cal-level-2::before { opacity: 0.26; }
.cal-legend-swatch.cal-level-3::before { opacity: 0.40; }
.cal-legend-swatch.cal-level-4::before { opacity: 0.55; }

.day-input-form { margin: 0.8rem 0 0.6rem; flex-wrap: wrap; }
.detail-time { font-variant-numeric: tabular-nums; white-space: nowrap; }
.detail-model { text-align: left; word-break: break-all; }
.detail-message { color: var(--muted); font-size: 0.85rem; word-break: break-word; max-width: 32rem; }
.detail-row.is-error td { color: var(--danger); }

@media (prefers-reduced-motion: reduce) {
  .chart-tooltip { transition: none; }
}

/* --- タブ --- */
/* is-tabbed はapp.jsが付ける。JSが無効ならタブ列は出ず、
   .tabs(パネルの出し分け)なら全パネルが縦に並び、フィード一覧なら全行が並ぶ。
   タブ列とタブ自体の見た目は .tabs とフィード一覧の絞り込みタブで共有する */
.tab-list { display: none; }
.is-tabbed .tab-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  border-bottom: 1px solid var(--border);
  margin: 1rem 0 0;
}
/* 表示中でない段(フィード一覧の2段目)は display:flex より hidden を優先させる */
.is-tabbed .tab-list[hidden] { display: none; }
.is-tabbed .tab {
  position: relative;
  padding: 0.45rem 0.9rem;
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: 6px 6px 0 0;
  background: none;
  color: var(--muted);
  cursor: pointer;
  font-size: 0.95rem;
  /* 選択時に太字化すると幅が動いてタブが揺れるので、太さは先に確保しておく */
  margin-bottom: -1px;
}
.is-tabbed .tab:hover { color: var(--fg); }
.is-tabbed .tab[aria-selected="true"] {
  background: var(--card);
  border-color: var(--border);
  color: var(--fg);
  font-weight: 600;
}
.is-tabbed .tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* 未保存の変更があるタブに印を出す。タブは他フォームを隠すので、
   編集したまま別タブで保存して失うことに気づけるようにする */
.tabs.is-tabbed .tab.is-dirty::after {
  content: "";
  position: absolute;
  top: 0.45rem;
  right: 0.35rem;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
}
.tabs.is-tabbed .tab-panel[hidden] { display: none; }
.tabs.is-tabbed .tab-panel > h2 {
  /* タブのラベルが見出しの役割を果たすので、パネル内の見出しは支援技術向けに残して視覚的には隠す */
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- 絞り込みのサブタブ(フィード一覧の2〜3段目・フィード実績のフォルダ列) --- */
/* 1段目=ソース種別(下線でテーブルとつながるタブ)、2段目=フォルダ(ピル型のチップ)。
   同じ見た目にすると2段のどちらを操作しているのか分からなくなるので階層差を付ける。
   フィード実績(.tabs のパネル内のフォルダ列)も同じ見た目を束ねで使う */
.feed-tabs.is-tabbed .tab-list-sub,
.tabs.is-tabbed .tab-list-sub {
  border-bottom: none;
  margin: 0.5rem 0 0;
}
.feed-tabs.is-tabbed .tab-list-sub .tab,
.tabs.is-tabbed .tab-list-sub .tab {
  padding: 0.25rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 0.85rem;
  margin-bottom: 0;
}
.feed-tabs.is-tabbed .tab-list-sub .tab[aria-selected="true"],
.tabs.is-tabbed .tab-list-sub .tab[aria-selected="true"] {
  border-color: var(--accent);
  color: var(--fg);
}
/* 2段目(フォルダ)と3段目(状態)はピルの見た目が同じで紛れるので、行頭のラベルで区別する。
   .tab-list の中にあるのでJS無効時はタブ列ごと出ない */
.feed-tabs.is-tabbed .tab-list-label,
.tabs.is-tabbed .tab-list-label {
  align-self: center;
  color: var(--muted);
  font-size: 0.8rem;
  margin-right: 0.2rem;
}
.tab-count {
  margin-left: 0.35rem;
  color: var(--muted);
  font-size: 0.85em;
  font-variant-numeric: tabular-nums;
  font-weight: 400;
}
.feed-tabs.is-tabbed + .table-wrap,
.tabs.is-tabbed .tab-list-sub + .table-wrap { margin-top: 0.8rem; }
/* フィルタは行(フィード一覧)または tbody(フィード実績のフォルダ)の hidden 属性で行う。
   UA既定でも隠れるが、テーブル行の display は後から足したCSSで壊しやすいので明示しておく */
.list-table tbody tr[hidden],
.list-table tbody[hidden] { display: none; }
.empty-filter { color: var(--muted); font-size: 0.9rem; margin: 1rem 0; }

/* --- タグ提案の代替候補 --- */
.alt-tags { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; margin-top: 0.4rem; }
.alt-tags-label { color: var(--muted); font-size: 0.8rem; }
.alt-tags-select {
  padding: 0.25rem 0.4rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--card);
  color: var(--fg);
  max-width: 16rem;
}
.alt-tags .button { padding: 0.25rem 0.6rem; font-size: 0.85rem; }

/* サムネイルキャッシュの詳細一覧(/thumbnails)。nowrap 詰めは #feed-table 専用の規約なので、
   ここは折り返しに任せて幅上限だけ絞る(.detail-message と同じ流儀) */
.thumb-detail-preview img { display: block; width: 72px; aspect-ratio: 16 / 9; object-fit: cover; border-radius: 4px; background: var(--bg); }
.thumb-detail-article { max-width: 24rem; }
.thumb-detail-article .detail { display: block; }
.thumb-detail-error { color: var(--danger); font-size: 0.85rem; word-break: break-word; max-width: 12rem; }
.thumb-detail-url { max-width: 18rem; }
.thumb-detail-url a { font-size: 0.8rem; color: var(--muted); word-break: break-all; }
.thumb-detail-status { white-space: nowrap; }
.thumb-requeue-bar { display: flex; gap: 0.8rem; align-items: center; flex-wrap: wrap; margin: 0 0 0.6rem; }
/* 「すべて選択」はJSでしか動かないので has-js のときだけ出す(feed-select-all と同じ規約) */
.thumb-select-all-label { display: none; align-items: center; gap: 0.35rem; font-size: 0.9rem; color: var(--muted); }
.has-js .thumb-select-all-label { display: inline-flex; }
.thumb-detail-select { text-align: center; }

/* Web検索の利用履歴(/settings/web-search/logs → rules/summary.md)。状態の補足(HTTP・メッセージ)はバッジの下に行を分ける */
.web-search-log-table .detail, .web-search-log-table .detail-message { display: block; }
.web-search-log-hits summary { cursor: pointer; }
.web-search-log-hits ol { margin: 0.3rem 0 0; padding-left: 1.4rem; font-size: 0.85rem; }
.web-search-log-hits li { overflow-wrap: anywhere; }

/* --- 分析画面(上部メニュー「分析」= 傾向分析 → rules/insight.md) ---
   ゲージは行ごとに「ラベル(HTML)| 10区画の SVG | 数値(HTML)」。各行が同じ列幅の独立した grid なので、
   display: contents で listitem の意味を落とさずに列がそろう。SVG は区画の rect だけで文字を持たず、
   幅に合わせて伸縮させても歪まない。点灯は系列色の1色目(--viz-1)だけ — カテゴリは系列ではなく行なので、
   ステータス画面の「4色目禁止」には触れない。数値を必ず添えて色だけに頼らない */
.insight-heading { display: flex; align-items: center; justify-content: space-between; gap: 0.8rem; flex-wrap: wrap; }
.insight-provider-tabs { display: inline-flex; flex-wrap: wrap; margin: 0.2rem 0 0.9rem; }
.insight-provider-tab {
  padding: 0.35rem 0.75rem; border: 1px solid var(--border); background: var(--card);
  color: var(--muted); font-size: 0.85rem; text-decoration: none;
}
.insight-card { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 0.9rem 1rem; margin: 0 0 1rem; }
.insight-card h2 { font-size: 1.05rem; margin: 0 0 0.5rem; }
.insight-card h3 { font-size: 0.9rem; margin: 0.2rem 0 0.4rem; }
.insight-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.3rem 0.8rem; flex-wrap: wrap; }
.insight-card-body { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 1.2rem; align-items: start; }
@media (max-width: 800px) { .insight-card-body { grid-template-columns: minmax(0, 1fr); } }
.insight-gauge { display: grid; gap: 0.3rem; }
.insight-gauge-row { display: grid; grid-template-columns: clamp(5em, 32%, 12em) minmax(4rem, 1fr) 2em; gap: 0.6rem; align-items: center; }
.insight-gauge-label { font-size: 0.85rem; line-height: 1.3; overflow-wrap: anywhere; }
.insight-gauge-bar { display: block; width: 100%; height: 12px; }
.insight-gauge-bar .is-on { fill: var(--viz-1); }
.insight-gauge-bar .is-off { fill: var(--border); }
.insight-gauge-value { font-size: 0.85rem; color: var(--muted); font-variant-numeric: tabular-nums; text-align: right; }
.insight-memos { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.7rem; }
.insight-memo p { margin: 0.15rem 0 0; font-size: 0.9rem; line-height: 1.6; }
.insight-memo-brief { margin: 0.4rem 0; font-size: 0.85rem; line-height: 1.55; }
.insight-buckets { display: flex; flex-wrap: wrap; gap: 0.3rem 0.8rem; font-size: 0.85rem; }
.insight-bucket-list { list-style: none; margin: 0 0 0.5rem; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: 0.25rem 1rem; }
.insight-bucket-list .count { color: var(--muted); font-variant-numeric: tabular-nums; }
.insight-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.insight-skip-list { margin: 0.4rem 0; padding-left: 1.2rem; font-size: 0.88rem; line-height: 1.55; }
.insight-skip-list li { overflow-wrap: anywhere; }
.insight-feed-list { list-style: none; margin: 0; padding: 0; }
.insight-feed-list > li { border-top: 1px solid var(--border); padding: 0.45rem 0; }
.insight-feed-list details > .insight-gauge { margin: 0.6rem 0; }
.insight-feed-list summary { cursor: pointer; }
