/* 「プロダクトから探す」一覧（/product/）とプロダクト個票（/product/<id>/）だけの CSS。
 *
 * ⚠ **色を発明しない。** `app.css` のトークン（--surface-1 / --text-* / --border /
 *   --step-1..4 / --series-1..3 / --radius*）だけを使う。
 * ⚠ ライトモードで --series-3（GTM 緑）は surface 比 2.67:1。**色だけで意味を
 *   持たせない。** 区別すべき情報は必ず文字が持つ。
 * ⚠ **生の `font-size: NNpx` を書かない。** 文字の大きさは `app.css` の
 *   `--fs-xs` / `--fs-sm` / `--fs-md` / `--fs-base` / `--fs-lede` / `--fs-h2`
 *   の段からだけ選ぶ。実測で画面の font-size が 20種まで増えて「カードや表、
 *   フォントの大きさがバラバラで読みづらい」と言われた。**--fs-xs（11.5px）が
 *   可読性の下限。** 表を詰めたいときは文字を小さくせず `padding` で詰める。
 * ⚠ このファイルは `/product/` と `/product/<id>/` にだけ配られる
 *   （`render.py` の `stylesheets_for`）。共有したいものは `app.css` へ。
 *   セレクタは必ず `.sx` / `.sum` / `.co` / `.psec` / `.pipe` の中に閉じること。
 *   素の `section` や `table` に書かない（この2面の中でも全体が動く）。
 */

/* ⚠ **ここから下は `app.css` から移したもの。** この画面でしか使わないのに
 *   共有ファイルに置いてあり、`app.css` を読む人に「全ページで効く」と
 *   誤解させていた。**移し先の先頭**に置くのは、`app.css` が STYLESHEETS の
 *   1番目だから —— 末尾に足すと、このファイルの既存の上書きより後ろに回って
 *   カスケードが逆転する。 */

/* ------------------------------------------------- 月ごとの増減（発散棒） */

/* ⚠ 上＝検出しはじめた（series-1）、下＝検出できなくなった（ミュート）。
   **緑赤の good/bad を使わない。** 非検出は推論なので弱く出す。 */
/* ⚠ **横に伸ばしすぎない**（棒が間延びして読めなくなる）ので幅に上限を置く。 */
.pipe__svg { width: 100%; max-width: 760px; height: auto; display: block; }
.pipe__axis { stroke: var(--gridline); stroke-width: 1; }
.pipe__up { fill: var(--series-1); }
.pipe__down { fill: var(--baseline); }
.pipe__tick { font-size: var(--fs-xs); fill: var(--text-muted); text-anchor: middle; font-family: inherit; }

/* 推移（横軸＝時間 / 縦軸＝検知数）。
   ⚠⚠ **`vector-effect: non-scaling-stroke` を落とさない。** SVG を
   `preserveAspectRatio="none"` で横に引き伸ばしているので、
   これが無いと**線の太さまで横に伸びて潰れる**。
   ⚠ 点（`<circle>`）も同じ理由で**楕円になる**ので、
     `vector-effect` では防げない（半径はスケールされる）。
     **当面はこれで良しとする** —— r=2.5 なので潰れても読める。
     気になったら点を CSS で描く（`/method/` のフロー図と同じ手）。 */
.trend__svg { width: 100%; height: 132px; display: block; }
.trend__line {
  fill: none; stroke: var(--series-1); stroke-width: 2;
  stroke-linejoin: round; stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
.trend__dot { fill: var(--series-1); }
/* 月の目盛り。⚠ **SVG の中に `<text>` を置かない**（横に潰れる）ので、
   HTML で点と同じ数だけ等分して並べる。 */
.trend__ticks {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  font-size: var(--fs-xs); color: var(--text-muted); margin-top: 2px;
}
.trend__ticks span { text-align: center; white-space: nowrap; }
.pipe__key { display: flex; gap: var(--gap-4); margin-top: 10px; font-size: var(--fs-xs); color: var(--text-muted); }
.pipe__key span { display: inline-flex; align-items: center; gap: var(--gap-ic); }
.pipe__sw { width: 10px; height: 10px; border-radius: var(--radius-xs); display: block; }
.pipe__sw--up { background: var(--series-1); }
.pipe__sw--down { background: var(--baseline); }


/* 見出しだけの page-head（`/product/` の一覧）。探しに来た人の視線を表まで最短で運ぶ。
 * ⚠ 個票（`/product/<id>/`）はこれを使わない。あちらは下の `.phero` が主役。 */
.page-head--tight { margin-bottom: 14px; }
.page-head--tight h1 { margin-bottom: 0; }

/* --- 個票の冒頭（このページの主役） ------------------------------------- */

/* ⚠ **ここを面にした理由。** 以前の冒頭は素の `.page-head--tight` で、背景も
 *   余白も持たないただの `<h1>` だった。一方いちばん下の「よくある質問」は
 *   `.panel.glass` の面を持っていて、**補足のほうが主役より重い**状態だった
 *   （指摘:「一番下の FAQ が変に目立っています。その割に一番トップのやつは
 *   全然小さいね」）。面はこちらへ、FAQ からは外す（下の `.pqa`）。
 * ⚠ **新しい文字サイズを作らない。** `<h1>` は `app.css` の `--fs-h1` のまま。
 *   大きくしたのは**面・余白・アイコン**で、段を増やしてはいない。
 *   例外は下の `.phero__n`（主役の数字の `clamp()`）だけ。 */
.phero { padding: var(--pad-panel); margin-bottom: 14px; }
/* ⚠⚠ **左に名前、右に件数（2026-10-09）。**
   ⚠ `align-items: baseline` にしない —— 左は2段（中分類＋見出し）あるので、
     ベースラインを揃えると件数が見出しの行まで持ち上がる。**下端で揃える。**
   ⚠ `flex-wrap` を外さない。390px では件数が名前の下へ回る。 */
.phero__top {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--gap-3) var(--gap-5); flex-wrap: wrap;
}
.phero__name { min-width: 0; }
/* 見出しの行。アイコンは一覧（28px）より一段大きくして、「このページは何の話か」を
 * 1目で決める。⚠ 文字ではないので px でよい。
 * ⚠ **これ以上大きくしない。** 中身は 16〜32px の favicon なので、CSS で
 *   引き伸ばすほどぼやける（`web/view/icons.py` が無い製品はモノグラムに倒す）。
 *   冒頭の重さは面と下の数字が持っているので、ここを稼ぎどころにしないこと。 */
.phero .head-ic { gap: var(--gap-4); margin-bottom: 0; }
.phero .pico--lg { width: 44px; height: 44px; }
.phero .pico--lg img { width: 28px; height: 28px; }

/* 主役の数字。**1画面に1つだけ。**
 * ⚠ `clamp()` が許されるのはここだけ（`docs/design/web_design.md` §7.3 の
 *   「主役の数字」）。トップの `.hero-title` / `.home-geo__nums dd` と同じ扱いで、
 *   **3つ目をこの面の中に作らないこと。** */
/* ⚠⚠ **`line-height` を落とさない（2026-10-09）。** 中に 44px の数字
   （`.phero__n`）がいるので、既定の行送りだと**1行で 75px の箱**になり、
   `<h1>` とのあいだが実際の余白よりずっと広く見える
   （「「XXXを導入している企業」と「X社」の間の間隔が大きすぎます」）。
   ⚠ 数字そのものは小さくしない —— このページの主役。詰めるのは箱のほう。 */
/* 右の件数。⚠ **折り返させない。** 折れると右端が不揃いになって、見出しとの
   左右の対が崩れる（狭い画面では `.phero__top` ごと縦に回る）。 */
.phero__lede {
  margin: 0; font-size: var(--fs-md); color: var(--text-secondary);
  line-height: 1.3; white-space: nowrap;
}
/* ⚠⚠ **`clamp()` をやめた（2026-10-09）。** 44px の数字が冒頭の縦を1人で決めていて、
   「検出は文字は小さい感じで」と言われた。ここは**数えた結果**であって、
   このページの主役は下の企業一覧のほう。
   ⚠ **`docs/design/web_design.md` §7.3 の「主役の数字」枠を1つ空けた**ことになる。
     この面で `clamp()` を使ってよい要素は、いま0個。復活させるなら
     「この画面の主役は何か」から決め直すこと。 */
.phero__n {
  /* ⚠⚠ **`<h1>` を短くしたぶん、ここが主役（2026-10-10、指摘「数字の部分はもっと
     大きくして」）。** `<h1>` から「を導入している企業」を外して名前だけにしたので、
     左の段が短くなり、右に余裕ができた。
     ⚠ **それでも 44px の旧 `clamp()` には戻さない。** あれは冒頭の縦を一人で決めていて、
       パネルだけで 200px あった。`<h1>`（`--fs-h1` 32px）を**超えない**範囲に収める。
     ⚠ `.phero__top` の行の高さ（左の2段）に収まることを 1440 / 700 / 390px で実測すること。 */
  font-size: clamp(27px, 3vw, 32px);
  font-weight: var(--fw-bold);
  letter-spacing: -0.01em;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  margin-right: 1px;
}
.phero__u { margin-right: 2px; }
.phero__lede .muted { font-size: var(--fs-sm); margin-left: 5px; }

/* 個票の段組み。
 *
 * ⚠ **`app.css` の `section { margin: 0 0 40px }` を上書きするためのクラス。**
 *   個票はパネルが5段あるので 40px × 5 = 200px が余白に消えていた（「余白が
 *   大きすぎる」の正体）。企業個票（`company.css` の `.prof` / `.shared`）が
 *   パネル間 10〜16px で組んでいるので、そちらに揃える。
 * ⚠ `section` 自体に書かないこと。このファイルは全ページに配られる。 */
.psec { margin-bottom: 20px; }
.psec:last-child { margin-bottom: 0; }
/* パネルの内側も企業個票（18px 22px）に合わせる。20px 22px から 2px 詰まる。 */
/* ⚠ **`app.css` の `.panel` と同じトークン。** 以前は 20px と 18px で割れていて、
   ここがその打ち消しだった。いまは両方 `--pad-panel` なのでこの行は要らない —— が、
   個票だけ詰めたくなったときの入口として名前だけ残す。**値を直書きしない。** */
.psec .panel { padding: var(--pad-panel); }
/* 表カードの上の隙間。`app.css` は 12px。見出しとの間はもう少し詰めていい。 */
.psec .tablecard { margin-top: 10px; }
.psec .sec-head { margin-bottom: 8px; }

/* ⚠ **横に並べたパネルの高さを揃える。** `app.css` の `.two-col` は
 *   `align-items: start` なので、「よく併用されているプロダクト」（最大10行）と
 *   「どこの会社が使っているか」（都道府県の数ぶん）が**中身の件数で別々の高さ**に
 *   なり、2枚のカードの下端が 200px 以上ずれていた（指摘「パネルの高さなどが
 *   合っていないです」）。段を揃えるのは面の仕事で、中身の件数の仕事ではない。
 * ⚠ **`app.css` の `.two-col` を書き換えない。** あちらは共有物（いまの利用は
 *   この画面だけだが、次に誰かが使ったときに `start` が要る場面はありうる）。
 *   ここは個票の中だけを強い特異度で上書きする。
 * ⚠ 行（`.brow` / `.co li`）を縦に引き伸ばさないこと。**余るのは面の下**で、
 *   中身は上から詰める（`.panel` は block のままなので自然にそうなる）。 */
.psec .two-col { align-items: stretch; }

/* 0件のときの説明。**空の表・空のリスト・空のグラフを出さない。**
 *
 * ⚠ 組は `static/app.css` の `.bars__none` に揃える（行間 1.8 / 72ch）。
 *   見た目は同じだが、**セレクタは分ける** —— あちらは「出せるものが無い」、
 *   こちらは「観測はしたが検出できなかった」で、言っていることが違う。
 * ⚠ **「使われていない」と書く場所ではない。** 文面の約束は README 原則1。 */
.pnone {
  margin: 2px 0 0;
  font-size: var(--fs-sm);
  line-height: 1.8;
  color: var(--text-secondary);
  max-width: 72ch;
}
.pnone a { white-space: nowrap; }
/* 表の代わりに出すときは、表カードと同じ位置から始める。 */
.psec > .pnone { margin-top: 10px; }

/* --- 一覧の絞り込み ------------------------------------------------------ */

/* 件数と「絞り込みを解除」。**題（`<h1>`）の横**に置く（`.page-head__top`）。
 *
 * ⚠⚠ **2026-10-09 に表カードの中の帯（`.sx-bar`）から引っ越した（指摘）。**
 *     「『1,133 プロダクト』って、**『プロダクトを探す（1,133プロダクト対応）』
 *       とかで上に書いたら？ 表に入らないと思う**」。
 *   あの数は「どう絞ったか」ではなく「**この画面が何を相手にしているか**」なので、
 *   表に付いている操作のように見える場所に置いてはいけない。
 *   ⚠ **`.sx-bar` を作り直さない。** 戻すと同じ数が題の横と表の中の2箇所に出る。
 *
 * ⚠⚠ **ここに検索入力を戻さない（2026-10-09・作り直し2回目）。**
 *   以前は表の中の帯に「プロダクト名・提供元でしぼり込む」の入力（虫眼鏡付き）が
 *   立っていたが、**名指しで否定された**:
 *     「絞り込みの画面のイメージが全然違う。**軸をクリックするとチェックボックスが
 *       出てきてフィルタ出来るイメージ**です。**検索ボックスみたいなのは
 *       入れないでよ。**」
 *   絞り込みは列見出しの ▾（`.sx-menu`）だけが受ける。
 *
 * ⚠ **数はテンプレートが焼く**（`pages/product_index.html`）。JS が死んでも
 *   「1,133 プロダクト」は読めていなければならない。JS は絞ったときに
 *   `21 / 1,133 プロダクト` へ書き換えるだけ。
 * ⚠ `role="status"` が付いているので、空になっても箱を消さないこと
 *   —— `display: none` の要素の更新は読み上げられない。
 * ⚠ **このページの live 領域はここ1つだけ。** `<caption>` にも足すと
 *   同じことが二重に読まれる（`/search/` の `.fd-count` と同じ約束）。
 * ⚠ 絞り込んでいるあいだだけ字を強める（`.is-on`）。**色だけで変えない** ——
 *   数そのものが「21 / 1,133」に変わるので、変化は色が無くても読める。
 * ⚠ **題と足元で揃える。** 親（`.page-head__top`）が `align-items: baseline`。 */
.sx-n {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.sx-n.is-on { color: var(--text-primary); font-weight: var(--fw-semibold); }
/* まとめて解除。**絞り込んでいるあいだだけ出る**（JS が作る）。
 * ⚠ **これが唯一の戻り道になる場面がある。** 0件まで絞ると表そのものが下がって
 *   列見出しの ▾ ごと画面から消えるので、ここが無いと**リロードするしかない。**
 * ⚠ **件数のすぐ後ろに置く**（親は `.page-head__end`）。右端へ飛ばすと
 *   1440px では 1,000px 以上離れて、何を解除するボタンなのか読めなくなる
 *   （実際にそう置いてから戻した）。 */
.sx-clear {
  appearance: none;
  padding: var(--pad-btn-sm);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface-1);
  color: var(--text-secondary);
  cursor: pointer;
  white-space: nowrap;
}
.sx-clear:hover { color: var(--link); border-color: var(--series-1); }
.sx-clear:focus-visible { outline: 2px solid var(--series-1); outline-offset: 2px; }
/* ⚠ 打ち消しを先に書いておく。いまは `display` を持たないので UA の
 *   `[hidden]` が効くが、**ここに `display: inline-flex` を足した瞬間に
 *   「絞り込んでいないのにボタンが出ている」になる**（`app.css` の `[hidden]` の節）。 */
.sx-clear[hidden] { display: none; }

/* 1件も残らなかったとき。⚠ **列見出しだけの表を見せない**（JS が表ごと下げる）。 */
.sx-empty {
  margin: 0;
  padding: 18px 16px;
  font-size: var(--fs-md);
  color: var(--text-secondary);
}

/* --- 一覧の表 ------------------------------------------------------------ */

/* ⚠ **列幅を宣言しておく。** auto に任せると数の列が右端に張り付き、
 *   プロダクト名と社数のあいだに 400px の空白ができる（実測）。 */
/* ⚠ **5列になった（2026-10-09）。** 先頭に「カテゴリ」列を足したので、
   合計が 100% になるよう割り直してある（足し忘れると数の列が右端に張り付く）。
   ⚠ カテゴリ列は添え物なので狭く。主役はプロダクト名。 */
.sx-c--group { width: 15%; }
.sx-c--name { width: 32%; }
.sx-c--vendor { width: 25%; }
.sx-c--n { width: 14%; }

/* 長い表はここで高さを畳む（`parts/_saas.html` の `.sx-scroll`）。

   ⚠ **「プロダクトを探す」が長すぎる、と言われた（2026-10-09）。** 1,133 行が
     縦に全部並ぶので、実測で**ページの高さが 47,000px**（画面 50 枚ぶん）あり、
     ホイールを回しても終わりが見えなかった。
   ⚠ **行を減らすのではない。高さだけを畳む。** ここは集客の本命ページで、
     1,133 件ぶんのリンクが本体（既定を閉じないのと同じ理由）。
     企業個票の `.ct-scroll` が同じことを同じ形でやっている ——
     **同じサイトで2つ目の作法を作らない。**
   ⚠ **高さは `vh` で取る。** 固定 px にすると、小さい画面で器が画面より高くなって
     「畳んだのに畳まれていない」状態になる。`min()` の第2項は大きい画面での
     上限（27インチで器だけが伸び続けないように）。
   ⚠ **`overflow: auto`（両軸）。** 狭い画面では `app.css` が
     `.tablecard table { min-width: 660px }` を当てるので、横もここで受ける。
     外側（`.tablecard`）に横スクロールを任せると、貼り付いた列見出しだけが
     取り残される形になりうる。
   ⚠ **業務カテゴリの畳みと喧嘩させない。** 畳んで行が減れば器も縮む
     （`max-height` なので中身が低ければそのまま）。畳みが `row.hidden` を
     触っているだけなのは変わらない。
   ⚠ `<caption>`（並べ替えの説明）は一緒に流れて消える。**それでよい** ——
     常に見えていなければならない数は題の横の `.sx-n` が持っている。 */
.sx-scroll {
  /* ⚠ 70vh。**器の底を画面の中に収める**ための値で、適当な数ではない ——
     1440×900 でカードの上端が 205px、帯と題で 66px あるので、78vh だと
     底が 73px だけ画面の外に出て「畳んだのに最後まで見えない」になった。 */
  max-height: min(70vh, 820px);
  overflow: auto;
  overscroll-behavior: contain;
}
/* 列フィルタの一覧が開いているあいだだけの下限。
 * ⚠ **絞り込んだ後に ▾ を開くと器が数十 px しか無い。** 11 件まで絞った状態で
 *   「提供元」を開くと、器の高さ＝11行ぶんなので**一覧がほとんど見えない**
 *   （`overflow: auto` が切る）。開いているあいだだけ器を伸ばす。
 * ⚠ **`max-height` を超えない値にする。** 70vh より大きいと、小さい画面で
 *   下限が上限を追い越して器が画面からはみ出す。 */
.sx-scroll.has-menu { min-height: min(420px, 70vh); }
/* ⚠ **`border-collapse: separate` が要る。** `app.css` の `table` は `collapse` で、
   **collapse のままだと `<th>` の `position: sticky` が効かない**（罫線をセルから
   剥がして表の側で描くので、セルを動かせない）。`.ct-scroll` で実測済み。
   `border-spacing: 0` を添えてセル間の隙間を消す —— 罫線は `th` / `td` の
   `border-bottom` が持っているので見た目は変わらない。 */
.sx-scroll .sx { border-collapse: separate; border-spacing: 0; }
/* ⚠ **sticky の基準はビューポートではなく、この器の上端（`top: 0`）。**
   スクロール容器ができた時点で、ビューポート基準の sticky は効かなくなる
   （`static/finder.css` の `.fd-table` は容器が無いのでヘッダーの高さぶん
   下げている。**あちらの `top` をここへ写さないこと**）。
   ⚠ **背景を不透明にする。** `app.css` の `.tablecard th { background: transparent }`
   が効いていると、貼り付いた見出しの下を行が**透けて通る**。

   ⚠⚠ **境目は `/search/` の列見出しと1文字も違えない**（2026-10-09・4回目）。
   地 `--surface-1`（面と同じ）＋ 1px の `--baseline` ＋ `--shadow-lid`。
   経緯と、なぜ「濃い地 + 太い罫」をやめたかは `static/finder.css` の
   `.fd-result .fd-table thead th` に全部書いてある。**片方だけ触らないこと** ——
   実際、このファイルだけ `--plane` + 2px のまま取り残されていた。
   `tests/web/test_stylesheet.py::test_the_two_sticky_table_heads_are_cut_from_the_same_cloth`
   が2つの一致を縛っている。

   ⚠⚠ **縁を `inset` の影ではなく実体の `border-bottom` にした。** 以前は
   `inset 0 -2px 0` で描いていたので、**`.sx-h`（セルいっぱいのボタン）に
   hover の地が付いた瞬間、その列だけ縁が子の背景に隠れて消えた** ——
   だから `.sx-h` 側にも同じ縁を描き直す行が要った（＝同じ線の定義が2箇所）。
   `border` はセルの外側なので子の背景では覆えない。**`inset` に戻さないこと。** */
.sx-scroll .sx thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--surface-1);
  border-bottom: 1px solid var(--baseline);
}
/* ⚠⚠ **影は「貼り付いているときだけ」出す（2026-10-09・5回目の指摘）。**
   常に出していたら**「この shadow が強すぎるね」**と言われた。経緯と、なぜ
   濃さではなく**出すタイミング**で解いたかは `static/finder.css` の
   `.fd-result .fd-table.is-stuck thead th` に書いてある。**片方だけ触らないこと。**
   ⚠ ここは器（`.sx-scroll`）の中で貼り付くので、判定は `scrollTop > 0` だけで済む
     （`pages/product_index.html`）。`/search/` 側はビューポート基準なので
     `IntersectionObserver` を使っている。**手段が違うだけで、形は同じ。** */
.sx-scroll .sx.is-stuck thead th { box-shadow: var(--shadow-lid); }
/* ⚠ **大分類の見出し行（`.sx-sec`）を sticky にしない。** 一度書いてから外した:
   - 貼るには `background` が要るが、**そこは `.sx-sec > th` が「書くな」と
     言っている場所**（書くと `app.css` の `.tablecard tbody tr:hover` が
     見出し行だけ効かなくなり、**押せる行なのに反応しない**ように見える）。
   - `top` に列見出しの高さが要るので、JS で測って変数に入れる段が増える。
     文字の大きさが変われば黙ってずれる。
   どのカテゴリを見ているかは、**見出し行が器の中に必ず1つは入っている**
   （カテゴリあたりの行数より器のほうが高い）ので実害が出ていない。 */

/* 表の説明。**見える側はほぼ空**（`/search/` の `.fd-cap` と同じ組）。
 * ⚠ **`display: none` にしない。** 支援技術からも消える。
 * ⚠ **`font-size: 0` が要る。** `<caption>` の中には改行とインデントの空白ノードが
 *   残るので、これが無いと**文字を消しても行が1行ぶん残る**。 */
.sx__cap { caption-side: top; text-align: left; padding: 0; font-size: 0; line-height: 0; }
/* 並び順・絞り込みの1文。**目からだけ隠す。**
 * ⚠ 「数の列の見出しを押すと並べ替わります（3回押すとカテゴリ順に戻ります）」を
 *   見える側に出していて、**この辺の触ればわかるようなやつはいらない**と言われた。
 *   消したのは**表示だけ** —— いまどの基準で並んでいるかを支援技術へ渡す口は
 *   `<caption>` しかない（`aria-sort` と対）。隠し方は `app.css` の `.vh` と同じ。 */
.sx__cap-t {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
/* 見える側に残す唯一の1文。**並べ替えているあいだだけ出る。**
 * ⚠ 「分かっていないものは向きに関わらず末尾」は `missing()` の挙動で、
 *   **押しても気づけない**（昇順にしたのに `—` が先頭に来ない理由が
 *   どこにも出ない）。これだけは触っても分からないので残す。 */
.sx__cap-note {
  display: block; padding: 10px 16px 0;
  font-size: var(--fs-sm); line-height: 1.6; color: var(--text-muted);
}
.sx__cap-note[hidden] { display: none; }

/* --- 列見出し（絞り込みの ▾ と、並べ替えの ↕）------------------------------ */

/* ⚠⚠ **「表の header のデザインが本当に微妙です」**（2026-10-09）。作り直した。
 *
 * 何が微妙だったか。**4つの列に3種類の押しかたが並んでいた:**
 *   - プロダクト / 提供元 … 文字は素のまま、隣に**枠のある丸い小さなボタン**
 *     （「絞り込む」）がくっついて、押すと表の上の入力へ飛ぶ
 *   - 検出できた社数 / 検出できなくなった … **見出しの文字そのもの**がボタンで、
 *     右に ↕ が付く
 *   - どれも**セルのうち一部しか押せない**（文字の幅だけ）
 * 列見出しの列なのに、押せる範囲も押したときに起きることも列ごとに違う。
 *
 * 作り直しの決めごとは3つ:
 *   1. **1セル＝1ボタン**（`.sx-h`）。セルの余白まで含めてどこを押しても効く。
 *      行（`.sx tbody tr`）とカテゴリ見出し（`.sx-fold`）も**クリック範囲は
 *      要素まるごと**にしてあるので、表の中で約束が揃う。
 *   2. **骨格を共通にして、違いは右端の印1文字だけ**にする
 *      （▾ = チェックボックスが出る / ↕ = 並べ替わる）。
 *   3. **効いている列は見ただけで分かる**（`.is-on` で選んだ数を出す）。
 *      前回の失敗は「絞り込みが効いている手応えが無い」だったので、
 *      手応えを**見出しの位置**にも置く。
 *
 * ⚠ **内側の余白はこのボタンが持つ**（`.sx thead th { padding: 0 }`）。
 *   `<th>` 側に残すと、余白の部分だけ押せない帯になる。
 * ⚠ 文字は **`/search/` の列見出しと同じ組**（`--fs-xs` / `--fw-semibold` /
 *   `letter-spacing: .04em` / `--text-secondary`）。2026-10-09 まで
 *   ここだけ `--fs-sm` で、同じサイトの貼り付く見出しが2つとも違う字だった。
 *   見出しは**ラベル**であって本文ではない。`app.css` の `th` は `--text-muted` だが、
 *   **押せるものを一番弱い色で出さない**ので `--text-secondary` に上げる。 */
/* ⚠⚠ **行の中で上下中央（2026-10-09）。** `app.css` の `th, td` は
   `vertical-align: top` が既定。この表は**プロダクト名のセルだけ
   アイコンで背が高い**ので、top のままだとカテゴリ・提供元・数字が
   全部行の上に寄り、プロダクト名と横が揃わない
   （「上下真ん中にしてね。行にたいして上によってるよね」）。
   ⚠ **`app.css` の既定を変えない。** あちらは2段組のセル（企業名＋ドメイン）
     を持つ表も使っていて、そちらは top が正しい。 */
.sx thead th { padding: 0; position: relative; vertical-align: middle; }
.sx-h {
  appearance: none;
  background: none;
  border: 0;
  margin: 0;
  padding: 10px 16px;
  font: inherit;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: .04em;
  color: var(--text-secondary);
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: var(--gap-ic);
  width: 100%;
  text-align: left;
}
/* 数の列は右揃え（セルの数字と頭を揃える）。 */
.sx thead th.num .sx-h { justify-content: flex-end; }
/* ⚠⚠ **縦罫（列の切れ目）をやめた（2026-10-09・4回目の作り直し）。**
 *   `inset 1px 0 0 var(--gridline)` で列ごとに縦線を立てていたが、
 *   **「色とか、下線を太くしているところがダサすぎ」**の半分がこれだった。
 *   押せる単位が列であることは**セルいっぱいの hover の地**（下の行）が
 *   既に言っていて、線は要らない。`/search/` の見出しに縦罫が無いので、
 *   揃えるという意味でもこちらを落とすのが正しい。**戻さないこと。**
 * ⚠ **蓋の縁をここに描き直す行も消した。** `<th>` 側が `inset` の影ではなく
 *   実体の `border-bottom` を持つようになったので、子の背景では覆えない
 *   （上の `.sx-scroll .sx thead th` の注記）。同じ線の定義を2箇所に持たない。 */
.sx-h:hover { color: var(--text-primary); background: var(--tint-1); }
/* ⚠ **枠線は内側に出す**（`outline-offset` を負にする）。外に出すと、貼り付いた
 *   見出しの下辺が切れて、キーボードで回したときだけ罫が消えたように見える。 */
.sx-h:focus-visible { outline: 2px solid var(--series-1); outline-offset: -2px; }

.sx-h__t { overflow: hidden; text-overflow: ellipsis; }
/* 右端の印。**1文字だけ。** ▾ は「中身が出てくる」、↕ は「並びが変わる」。
 *
 * ⚠ **修飾クラス（`.sx-h--menu`）に疑似要素を付けない。** `--menu::after` は
 *   `tests/web/test_stylesheets.py` の走査に**カスタムプロパティの定義**として
 *   拾われる（`(--[\w-]+)\s*:` が `--menu:` に当たる）。どちらの見出しかは
 *   `aria-expanded` / `data-sort` が**定義そのもの**として持っているので、
 *   そちらを見る（クラスはその写しになるだけ）。 */
.sx-h[aria-expanded]::after { content: "▾"; font-size: var(--fs-xs); color: var(--text-muted); }
.sx th[data-sort] .sx-h::after { content: "↕"; font-size: var(--fs-xs); color: var(--text-muted); opacity: .55; }
.sx-h[aria-expanded="true"] { background: var(--tint-1); color: var(--text-primary); }
.sx-h[aria-expanded="true"]::after { color: var(--link); }
.sx th[aria-sort] .sx-h { color: var(--text-primary); }
.sx th[aria-sort="ascending"] .sx-h::after { content: "↑"; opacity: 1; }
.sx th[aria-sort="descending"] .sx-h::after { content: "↓"; opacity: 1; }
/* いくつ選んでいるか。**絞り込んでいる列だけに出る小さな数。**
 * ⚠ 空のときは箱ごと消す（出たり消えたりで見出しの幅が動かないよう、
 *   文字は JS 側が空文字にしている）。 */
.sx-h__n {
  padding: var(--pad-chip);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  line-height: 1.5;
  border-radius: var(--radius-pill);
  background: var(--tint-1);
  color: var(--link);
  font-variant-numeric: tabular-nums;
}
.sx-h__n:empty { display: none; }
.sx-h.is-on { color: var(--text-primary); }
.sx-h.is-on::after { color: var(--link); opacity: 1; }

/* --- 列フィルタの一覧（チェックボックス）----------------------------------- */

/* ▾ を押すと出てくる一覧。**JS が作る**（`pages/product_index.html`）。
 *
 * ⚠⚠ **中にテキスト入力を置かない。** 「検索ボックスみたいなのは入れないでよ」。
 *   Excel の列フィルタにある「検索」欄も**作らない**。代わりに選択肢の数を
 *   押せる範囲に抑えてある（業務カテゴリ7＋中分類46 / 提供元は上位20社）。
 * ⚠ **`<th>` の中に置く（`position: absolute`）。** `.sx-scroll` は
 *   `overflow: auto` なので、`position: fixed` でページ側へ逃がさないかぎり
 *   器の外へは出られない。逃がすと今度は**器を横スクロールしたときに
 *   列から外れて浮く**ので、器の中で収まる大きさにするほうを選んだ。
 *   見出しは sticky なので、器を縦に送っても一覧は列の真下に貼り付いたまま。
 * ⚠ **器の高さが足りないときは器を伸ばす**（`.sx-scroll.has-menu`）。
 *   絞り込んで数行になった状態で開くと、器が数十 px しか無くて一覧が切れる。
 * ⚠ **ここのぼかし影は消さないこと。** 「header の shadow が変」と言われたのは
 *   *貼り付いた見出しの下辺*の話で、**浮いている面には逆に影が要る**
 *   （無いと表の行の上に文字が散らばっているようにしか見えない）。 */
.sx-menu {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 4;
  display: flex;
  flex-direction: column;
  min-width: 15rem;
  /* ⚠ **狭い画面では窓より細くする。** 器（`.sx-scroll`）は横スクロールするので、
   *   22rem のままだと 390px で右半分が器の外に出る（位置は JS の `fit()` が
   *   寄せるが、**幅そのものが入らない**とどうにもならない）。 */
  max-width: min(22rem, calc(100vw - 56px));
  background: var(--surface-1);
  border: 1px solid var(--baseline);
  border-radius: var(--radius-sm);
  box-shadow: 0 10px 24px var(--glass-edge);
  text-align: left;
  font-weight: var(--fw-normal);
}
.sx-menu[hidden] { display: none; }
/* 開いている列を前に出す。⚠ `thead th` は `z-index: 2` で**列ごとに
 *   積み重ね文脈を作る**ので、右の列の地が左の列の一覧を覆う（狭い画面で実測）。 */
.sx thead th.is-open { z-index: 5; }
/* 何の一覧かの1行。⚠ **提供元を上位で切ったことはここで言う。**
 *   黙って切ると「自社の提供元が無い＝カタログに無い」と読まれる。 */
.sx-menu__note {
  margin: 0;
  padding: 10px 12px 0;
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: var(--text-muted);
}
/* 「N 件選択中」＋「すべて外す」。**1件以上選んでいるときだけ出る**
 * （`hidden` の出し入れは `pages/product_index.html` の `syncBoxes()`）。
 *
 * ⚠⚠ **「すべて」は 2026-10-09 に消した（指摘）。** `/search/` の「すべて選ぶ」と
 *   同じ理由 —— 選択肢を全部つけるのは絞らないのと同じで、押しても表が変わらない。
 *   「指定なし」に当たる字も置かない（チェックが0個なのは一覧を見れば分かる）。
 * ⚠ **「すべて外す」は必ず置く。** 46 個の中分類をチェック1つずつ外させない。
 * ⚠ **文言を `/search/` と違えない**（「解除」と呼んでいたのを揃えた）。
 * ⚠ **`display` を持つので `[hidden]` の打ち消しが要る**（`app.css` の `[hidden]` の節）。 */
.sx-menu__tools {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-2);
  padding: 8px 12px 9px;
  border-bottom: 1px solid var(--gridline);
}
.sx-menu__tools[hidden] { display: none; }
.sx-menu__picked {
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--link);
  font-variant-numeric: tabular-nums;
}
.sx-menu__tool {
  appearance: none;
  padding: var(--pad-btn-sm);
  font: inherit;
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface-1);
  color: var(--text-secondary);
  cursor: pointer;
}
.sx-menu__tool:hover { color: var(--link); border-color: var(--series-1); }
.sx-menu__tool:focus-visible { outline: 2px solid var(--series-1); outline-offset: 2px; }
/* ⚠ **一覧そのものをスクロールさせる。** 中分類まで入れると 53 行になるので、
 *   器（`.sx-scroll`）の高さに収まらない。外側ではなく**ここで**畳む。 */
.sx-menu__list {
  list-style: none;
  margin: 0;
  padding: 5px 0 6px;
  max-height: min(40vh, 290px);
  overflow: auto;
  overscroll-behavior: contain;
}
/* ⚠ **`--fs-sm`（2026-10-09 に `--fs-md` から下げた）。**
   「フィルタの中の文字が大きすぎます」と言われた。ここは**選ぶための一覧**で、
   読み物ではない —— 表本体（`--fs-md`）と同じ大きさだと、メニューのほうが
   本文に見えて、一度に見渡せる件数も減る。
   ⚠ **`--fs-xs`（11.5px）まで下げない。** そこは可読性の下限で、
     押す対象の文字に使う段ではない（`docs/design/web_design.md` §7.3）。
   ⚠ 行の高さ（`padding`）は詰めない。指で押す最低限を割る。 */
.sx-menu__lab {
  display: flex;
  align-items: center;
  gap: var(--gap-2);
  padding: 5px 12px;
  font-size: var(--fs-sm);
  color: var(--text-primary);
  cursor: pointer;
}
.sx-menu__lab:hover { background: var(--tint-1); }
.sx-menu__lab input {
  flex: none;
  width: 14px;
  height: 14px;
  margin: 0;
  accent-color: var(--series-1);
  cursor: pointer;
}
/* ⚠ **中分類は親の下に字下げして出す。** 同じ平面に並べると、業務カテゴリと
 *   中分類が**同じ粒度の 53 個の選択肢**に見える（右端の「カテゴリ」列を
 *   やめたときと同じ失敗）。 */
.sx-menu__row > .sx-menu__lab { font-weight: var(--fw-semibold); }
.sx-menu__row--sub > .sx-menu__lab {
  padding-left: 32px;
  /* ⚠ 親を `--fs-sm` へ下げたので、こちらも 1段下げて親子の差を保つ。
     同じにすると「同じ粒度の 53 個の選択肢」に戻る。 */
  font-size: var(--fs-xs);
  font-weight: var(--fw-normal);
  color: var(--text-secondary);
}
/* ⚠ **名前は省略して出す**（提供元に 20 文字級が来る）。全文は `title` にある。 */
.sx-menu__t { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* その選択肢で何件残るか。**他の列で絞った後の数**（0 なら押せない）。 */
.sx-menu__n { flex: none; font-size: var(--fs-xs); color: var(--text-muted); font-variant-numeric: tabular-nums; }
.sx-menu__row.is-empty > .sx-menu__lab { opacity: .45; cursor: default; }
.sx-menu__row.is-empty > .sx-menu__lab:hover { background: none; }

/* ⚠ **行の高さを詰める。** 141行あるので `app.css` の 10px では表が 7,300px に
 *   なる。ただし詰めすぎない —— 「企業を探す」で詰めすぎて「情報がぎゅっと
 *   しすぎて見づらい」と言われた。行の高さは 28px の `.pico` が決めているので、
 *   上下 6px で 41px（もとは 52px）。アイコンの上下に余白が残る量にしてある。 */
/* ⚠ 列見出しの内側の余白は**ここではなく `.sx-h`（ボタン）が持つ** ——
 *   セルの余白まで押せるようにするため（上の「列見出し」の節）。
 *   `.sx thead th { padding: 0 }` はそちらに書いてある。**ここに戻さないこと。** */
.sx tbody td { padding: 6px 16px; line-height: 1.4; vertical-align: middle; }
.sx .num { font-variant-numeric: tabular-nums; }

/* プロダクト名と中分類。**同じセルに並べる**（右端の列をやめた理由は `_saas.html`）。
 * 区切りは点や記号ではなく細い罫にした。全角中点だと1文字ぶんの空きが要るうえ、
 * プロダクト名に含まれる `・` と見分けがつかない。 */
.pcell__main { display: flex; align-items: baseline; gap: var(--gap-2); min-width: 0; }
/* カテゴリ（中分類）列。
   ⚠⚠ **`border-left` を戻さない（2026-10-09）。** プロダクト名の隣に
   添えていたころの区切り線で、**独立した列になったいまは意味が無い**
   （列と列の境は表の罫線が言う）。行に縦棒が混ざるとそれだけで煩い。
   ⚠ **添え物の濃さに保つ。** 主役はプロダクト名で、ここが濃いと
     目が先にカテゴリへ行く。 */
.sx__g {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 大分類の見出し行。**企業個票の「観測できた技術スタック」と同じ形**にする。
 *
 * ⚠ `.area-head`（`app.css`）を借りている。あちらは苦情の出ていない見せ方で、
 *   2画面で同じ形にするほうが覚えやすい。**`app.css` 側は触らない**ので、
 *   ここでは表の中で要らなくなるもの（下マージン）だけを外す。
 * ⚠ 面（背景）と色帯をやめた。以前は surface-1 の帯＋左の色帯で、
 *   **見出し行が本文の行より目立っていた。**「見づらい」の一因。
 *   いまは上の余白と細い罫だけで切れ目を作る。
 * ⚠ **`background` を書かない。** 書くと `app.css` の `.tablecard tbody tr:hover`
 *   が見出し行だけ効かなくなり、**押せる行なのに反応しない**ように見える。 */
.sx-sec > th {
  border-bottom: 1px solid var(--border);
  padding: 20px 16px 5px;
}
/* 表の1行目は上に余白が要らない（caption と見出し行のあいだが空きすぎる）。 */
.sx tbody tr:first-child.sx-sec > th { padding-top: 12px; }
.sx-sec .area-head { margin: 0; width: 100%; }

/* ⚠ **件数と開閉の印を右端に飛ばさない。**（一度そうしてから戻した）
 *   - 右端の「カテゴリ」列をやめたのは、大分類と中分類が画面の左右に割れて
 *     読めなかったからで、件数を右端へ置くのは**同じ失敗をやり直すだけ**だった。
 *   - 狭い画面では `app.css` の `.tablecard table { min-width: 660px }` で
 *     表が横スクロールになり、右端の「5製品 ▾」が**画面の外に出て一度も
 *     見えない**（実測）。畳む手段がスマホから消える。
 *   - 企業個票の「観測できた技術スタック」も名前の隣に件数を置いている。 */

/* 業務カテゴリを畳むボタン。**JS が付ける**（`pages/product_index.html`）。
 * ⚠ 見出しの中身をまるごと包むので、**見出し行のどこを押しても畳める。**
 *   小さな三角だけを押させる作りにしない（クリック範囲を揃える約束）。 */
.sx-fold {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  display: flex;
  align-items: baseline;
  gap: var(--gap-2);
  width: 100%;
  text-align: left;
}
.sx-fold::after {
  /* 開閉の向き。**色ではなく形**で示す（緑の読めなさと同じ理由）。 */
  content: "▾";
  font-size: var(--fs-xs);
  color: var(--text-muted);
}
.sx-fold[aria-expanded="false"]::after { content: "▸"; }
.sx-fold:hover .with-ic { text-decoration: underline; }
.sx-fold:focus-visible { outline: 2px solid var(--series-1); outline-offset: 3px; }

/* ⚠ **クリック範囲は行全体。** 「カードのクリックできる場所がバラバラ」と
 *   言われた。`<tr>` を `position: relative` にして、プロダクト名のリンクに
 *   透明な覆いを敷く。
 * ⚠ **行の中にリンクを増やさないこと。** 覆いに隠れて押せなくなる
 *   （提供元・社数はいずれも素のテキストのままにしてある）。 */
.sx tbody tr { position: relative; }
.sx tbody tr:not(.sx-sec) { cursor: pointer; }
.sx tbody tr:not(.sx-sec) .cname::after {
  content: "";
  position: absolute;
  inset: 0;
}

@media (prefers-reduced-motion: no-preference) {
  .sx tbody tr:not(.sx-sec) { transition: background .12s ease; }
}

/* --- 個票のサマリ表 ------------------------------------------------------ */

/* 2列の定義表。**左が項目名、右が値。** 数字を散らさない。
 * ⚠ 行の余白は `app.css` の 10px から 6px へ。6行あるので、これだけで
 *   カードが 290px → 210px になる（「余白が大きすぎる」への効き幅が一番大きい）。 */
/* ⚠ 面は呼び出し元（`.phero glass`）が持つので、ここは罫線だけ。
   上のリード文とのあいだに1本引いて、「ここから詳細」を示す。 */
/* 定義表。⚠ 面は `.phero` が持つので、ここは冒頭の行と区切る罫線だけ。 */
.sum-wrap { margin-top: 10px; border-top: 1px solid var(--border); }
.sum { width: 100%; margin: 0; }
/* ⚠⚠ **行の中で上下中央（2026-10-09）。** `app.css` の `th, td` の既定は
   `vertical-align: top`。この表は行ごとに背の高さが違う（シェアの帯・
   `--fs-lede` の数字・リンク）ので、top のままだと**項目名だけが行の上に寄る**
   （「各行について上下真ん中にしたいね」）。 */
.sum th, .sum td { padding: 7px 16px; vertical-align: middle; }
.sum th {
  width: 15em;
  text-align: left;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--text-muted);
  white-space: nowrap;
}
.sum td { font-size: var(--fs-md); }
/* ⚠ **長い URL を折り返せるようにする（2026-10-10）。** 「公式サイト」の行は URL を
   そのまま出すので、600〜899px では値の列（実測で約 290px）に入りきらない。
   折り返せないと**表ごと面からはみ出してページが横に動く** ——
   `overflow-x: hidden` で蓋をするのではなく、はみ出す当人を直す
   （`docs/design/responsive.md` §4.6）。 */
.sum td a { overflow-wrap: anywhere; }
/* ⚠ 20px だと行の高さがこの数字だけで決まって、他の行と揃わない。表の中の
 *   数字なので、見出しの段（`--fs-h2`）ではなくリードの段（`--fs-lede`）に置く。 */
.sum__n { font-size: var(--fs-lede); font-weight: var(--fw-semibold); letter-spacing: -.01em; }
/* ⚠ **添え書きも `--fs-sm` まで。** このページは 32/17/15/13.5 の4段で
   回すと決めてある（「文字がとても気持ち悪い。大きかったり小さかったり」）。
   `--fs-xs`（11.5px）を混ぜると段が5つになる。 */
.sum td .muted { font-size: var(--fs-sm); margin-left: 8px; }
/* 「カタログ上の同じ用途の製品」。併用リストとの間だけ空ける。
   ⚠⚠ **`max-width: none`（2026-10-09）。** `app.css` の散文向けの既定
   `p { max-width: 72ch }`（≈582px）がここにも乗り、**チップが 582px で折り返して
   右半分が空いていた**（「また左によりすぎてるよ。右にも使ってね」）。
   ⚠ **この罠は4件目。** `.nearby__list` / `/faq/` の本文 / `.co` / ここ。
     `<p>` と `<ul>` の既定が「散文」を前提にしているのに、**パネルの中の
     1行や一覧にも効く**のが原因。器の幅が決まっているものには毎回これが要る。 */
/* ⚠ **チップを並べるので flex にする（2026-10-10）。**
   素の文脈だと、改行を刈ったところで**隣のチップとくっつく**
   （「Azure DNSCSC DBS」になっていた）。間隔は `gap` が持つ。
   ⚠ `align-items: baseline` にしない —— 先頭のラベルとチップの高さが違うので、
     center のほうが行として落ち着く。 */
.sum__rivals {
  margin-top: 12px; max-width: none;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--gap-ic) var(--gap-2);
  /* ⚠ **最後の行の下に余白を残す（2026-10-10、指摘「下の部分が空いてなくて気持ち悪い」）。**
     チップは `inline-flex` で行の高さぶんしか取らないので、パネルの `padding` に
     そのまま接して見える。**`margin-bottom` ではなく `padding-bottom`** にするのは、
     隣接マージンの相殺でパネルの内側に効かない形を避けるため。 */
  padding-bottom: 4px;
}
/* 「打ち切っています、全件はこちら」の1行。表の真上に置く。 */
.psec__rest { margin: 0 0 8px; }

/* ⚠⚠ **720px → 599px に寄せた（2026-10-10）。** 段は **599 / 899 の2つだけ**
   （`docs/design/responsive.md` §2 / `tests/web/test_responsive.py`）。
 * ⚠ **機械的に置換したのではない。** 600〜899px は**2列のままで潰れない** ——
 *   600px の画面でも `.phero` の内側に 480px 残り、項目名の列（`--fs-sm` の 15em
 *   ≈ 187px）を引いて値に 290px ある。畳むのは指1本で読む幅（≤599px）だけでよい。
 * ⚠⚠ **`display` を変えると、支援技術から表として読まれなくなる。** だから
 *   `parts/_saas.html` の `<table class="sum">` に `role="table"` / `row` /
 *   `rowheader` / `cell` を明示してある（`docs/design/responsive.md` §4.1）。
 *   **ここの `display` を触るときは、あちらの `role` も一緒に見ること。**
 * ⚠ **畳んでよいのは、これが「項目名と値の2列」だから。** 一覧（`.sx`）と
 *   企業リスト（`.ct`）は**畳まない** —— 列が5本あって畳むと意味が落ちるので、
 *   横スクロールで逃がす（下の「狭い画面での表」の節）。 */
@media (max-width: 599px) {
  /* 狭い画面では2列だと値が潰れる。行ごとに縦へ畳む。 */
  .sum, .sum tbody, .sum tr, .sum th, .sum td { display: block; width: auto; }
  .sum tr { padding: 8px 0; border-bottom: 1px solid var(--border); }
  .sum tr:last-child { border-bottom: 0; }
  .sum th, .sum td { border: 0; padding: 0 16px; }
  .sum td { margin-top: 2px; }
}

/* --- よく併用されている製品 ---------------------------------------------- */

/* ⚠ 社数だけだと上位が全社基盤で埋まる。**併用率の棒を必ず並べる。**
 * ⚠ クリック範囲は行全体（一覧の表と同じ作り）。 */
/* ⚠⚠ **`max-width: none` を落とさない（2026-10-09）。** `app.css` の散文向けの既定
   `ul { max-width: 72ch }`（≈582px）がここにも乗り、**パネルが 1,052px あるのに
   リストが 582px で止まって左に詰まっていた**（「左に詰まっちゃってるけど
   右にもできるようにしてね」）。
   ⚠ **同じ罠は3件目。** `.nearby__list`（grid）、`/faq/` の `<p>`、そしてここ。
     検査（`tests/web/test_stylesheet.py`）は最初 grid/flex のリストしか見ておらず、
     **`<ul>` 自身が `display: block` のこれを見逃した。** いまは
     「`list-style: none` ＋ `padding: 0`」＝散文ではない、で拾っている。 */
.co { list-style: none; padding: 0; margin: 8px 0 0; max-width: none; }
.co li {
  position: relative;
  display: grid;
  grid-template-columns: minmax(8em, 1fr) minmax(60px, 90px) auto;
  align-items: center;
  gap: var(--gap-3);
  padding: 5px 0;
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-md);
  line-height: 1.5;
  cursor: pointer;
}
.co li:last-child { border-bottom: 0; }
.co__name {
  display: inline-flex;
  align-items: center;
  gap: var(--gap-ic);
  text-decoration: none;
  min-width: 0;
}
.co__name:hover { text-decoration: underline; }
.co__name::after { content: ""; position: absolute; inset: 0; }
/* ⚠ **`.mini`（`static/app.css`）と同じ見た目にする。** 同じ「割合を示す極小バー」で、
   このページでは**同じ画面に並ぶ**。以前は 6px と 5px で微妙に違っていた。 */
.co__track { height: var(--meter-h-sm); background: var(--gridline); border-radius: var(--radius-pill); overflow: hidden; }
.co__fill { display: block; height: var(--meter-h-sm); border-radius: var(--radius-pill); background: var(--step-3); }
.co__n {
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  white-space: nowrap;
  text-align: right;
}
.co__pct { margin-left: 6px; color: var(--text-muted); }

/* ⚠⚠ **併用率の棒（`.co__track`）を消さない（2026-10-10）。**
 *
 * 直前まで 560px 以下で `display: none` にしていた。**これは情報を画面から
 * 消していた** —— 「同じカテゴリで何%が併用しているか」は右の数字（`.co__pct`）と
 * 同じ値に見えて、**別の読まれ方をする**（棒は**他の行との長さの比**を一目で出す。
 * 数字は1行ずつ読まないと比べられない）。この一覧の並びは社数順なので、
 * 「どこでも出るプロダクト」と「この製品特有の組み合わせ」を分けているのは棒のほう
 * （`parts/_saas.html` の `co_used` に「社数だけだと上位が全社基盤で埋まる」）。
 *
 * **横に並べるのをやめるだけにする。** 行を2段のグリッドに畳んで、
 * 1行目に名前と数字、2行目に棒を**全幅で敷く**（`docs/design/responsive.md` §3.3）。
 * 型は `home.css` の `.afeed`（唯一正しく畳めている表）に合わせた。
 * ⚠ **`minmax(0, 1fr)` と書く。** `1fr` は `minmax(auto, 1fr)` の略で、
 *   **中身の min-content より縮まない** —— 長いプロダクト名が入った行だけ
 *   右の数字を押し出して、器からはみ出す。
 * ⚠ **閾値は 560 → 599**（段は 599 / 899 の2つだけ。`docs/design/responsive.md` §2）。
 *   561〜599px もスマホ縦の中なので、畳み方は同じでよい。 */
@media (max-width: 599px) {
  .co li {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--gap-1) var(--gap-3);
  }
  .co__name { grid-area: 1 / 1; }
  .co__n { grid-area: 1 / 2; justify-self: end; }
  /* ⚠ **`1 / -1` で最後の列まで伸ばす。** 幅を `100%` で与えると、grid の
     1列目に収まったままになって「名前の下の半端な棒」になる。 */
  .co__track { grid-area: 2 / 1 / auto / -1; }
}

/* --- 月ごとの増減 -------------------------------------------------------- */

/* ⚠ **観測範囲を必ず書く。** これが無いと、棒の並びが「毎月観測した結果」に
 *   見えてしまう（実際には観測した月だけを詰めて並べている）。 */
.pipe__range {
  margin: 10px 0 0;
  font-size: var(--fs-xs);
  line-height: 1.6;
  color: var(--text-secondary);
  max-width: 68ch;
}
/* 数値の代替（`parts/_chart.html` の `<details>`）。**SVG は `aria-hidden` で、
 * 値はこの表が持つ。** 既定は畳んでおく（読みたい人だけが開く）。
 * ⚠ 12か月ぶん並ぶと縦に伸びるので、開いたときだけスクロールさせる。 */
.pipe__data { margin-top: 12px; font-size: var(--fs-sm); }
.pipe__data summary { cursor: pointer; color: var(--text-secondary); font-size: var(--fs-xs); }
.pipe__data table { max-width: 420px; margin: 8px 0 0; }
.pipe__data caption { caption-side: top; text-align: left; font-size: var(--fs-xs); color: var(--text-muted); padding-bottom: 6px; }

/* --- 企業リストの表（`parts/_table.html` の `.ct`） --------------------- */

/* このページでいちばん縦に長いもの。**150行 × 1px が 150px** になるので、
 * 行の高さは1つずつ数えて決める。
 *
 * ⚠ **`.psec .tablecard td` で当てない。** 同じ入れ物にサマリ表（`.sum`）も
 *   入っていて、あちらは 6px に詰めてある。セレクタが強いほうが勝ってしまうので、
 *   この表だけのクラス（`.ct`）に当てる。
 * ⚠ **`app.css` の `.tablecard` を書き換えない。** あれは共有物で、
 *   企業個票と `/search/` の表も載っている。 */
/* 表の題。⚠ **見た目は `.sx__cap` と同じ組**（同じページに2種類の作法を置かない）。
 *   `<caption>` は「この表が何か」を支援技術へ最初に渡す唯一の口なので、
 *   スクリーンリーダー用に隠さず、そのまま読める文字として出す。 */
.ct__cap {
  caption-side: top;
  text-align: left;
  padding: 12px 16px 0;
  font-size: var(--fs-xs);
  line-height: 1.6;
  color: var(--text-muted);
}
/* 長い表はここでスクロールさせる（`parts/_table.html` の `.ct-scroll`）。

   ⚠ **行を減らすのではない。高さだけを畳む。** 150 行を素で積むと、この表1枚で
     画面10枚ぶんになり、下の節（検出できなくなった企業・よくある質問）に辿り着けない。
   ⚠ **`thead` を sticky にする。** 畳んだ中をスクロールする以上、列見出しが
     消えると「この数字は何の列か」が分からなくなる（`/search/` の表が同じ理由で
     sticky にしてある）。
   ⚠ **`background` を `transparent` のままにしない。** `app.css` の
     `.tablecard th { background: transparent }` が効いていると、sticky の下を
     行が**透けて通る**。不透明な面を敷く。
   ⚠ **`overflow: auto`（両軸）。** 狭い画面では `app.css` が
     `.tablecard table { min-width: 660px }` を当てるので、横もここで受ける
     （外側の `.tablecard` に横スクロールを任せると、sticky の列見出しだけが
     取り残される形になりうる）。
   ⚠ `<caption>` は一緒にスクロールして消える。**それでよい** —— 並び順の説明は
     表に入る前に読むもので、常時出し続ける必要はない（`.fd-count` のような
     動く数字はここには無い）。 */
.ct-scroll {
  max-height: min(72vh, 780px);
  overflow: auto; overscroll-behavior: contain;
}
/* ⚠ **`border-collapse: separate` が要る。** `app.css` の `table` は
   `collapse` で、**collapse のままだと `<th>` の `position: sticky` が効かない**
   （罫線をセルから剥がして表の側で描くので、セルを動かせない）。実測で
   列見出しがそのまま流れていった。`border-spacing: 0` を添えてセル間の隙間を消す
   —— 罫線は `th` / `td` の `border-bottom` が持っているので見た目は変わらない。 */
.ct-scroll .ct { border-collapse: separate; border-spacing: 0; }
.ct-scroll .ct thead th {
  position: sticky; top: 0; z-index: 1;
  background: var(--surface-1);
  box-shadow: inset 0 -1px 0 var(--gridline);
}

/* 同じドメインを共有している法人の印（`parts/_table.html` の `_name_cell`）。
   ⚠ **ドメインの隣に置く。** 共有しているのは**サイト**であって会社ではないので、
     社名の隣に付けると「この会社がN社ある」と読める。
   ⚠ 色で警告しない。事実の注記なので、ドメインと同じ弱さに保つ。 */
.dom__share {
  margin-left: 6px; padding: var(--pad-chip); border-radius: var(--radius-pill);
  border: 1px solid var(--border); color: var(--text-secondary);
  white-space: nowrap;
}

.ct th, .ct td { padding: 7px 16px; }
/* 2段組（企業名＋ドメイン / 都道府県＋市区）の行間を詰める。本文の 1.7 は
   1段ぶんが 24px で、2段だと 48px になる。 */
/* ⚠⚠ **上下中央（2026-10-09）。** `app.css` の `th, td` の既定は
   `vertical-align: top`。企業のセルだけ2段（社名＋ドメイン）で背が高いので、
   top のままだと**所在地・初観測・最後に検出できた月が全部行の上に寄る**
   （「値は上下中央ぞろえにして」）。 */
.ct td { line-height: 1.5; vertical-align: middle; }

/* ⚠ **クリック範囲は行全体。** 一覧（`.sx`）と同じ作法にそろえる —— 同じ形の
 *   表なのに、こちらは名前の文字だけが押せる状態だった（指摘 v2）。
 * ⚠ **個票が無い会社の行は押せない。** 名前が `<span class="cname">` になるので
 *   覆いが生まれず、`:has()` で cursor も出さない。**`<tr>` 側に
 *   クリックハンドラを付けない**（JS ゼロのまま、リンクの有無と一致させる）。
 * ⚠ **行の中にリンクを増やさないこと。** 覆いに隠れて押せなくなる。 */
.ct tbody tr { position: relative; }
.ct tbody tr:has(a.cname) { cursor: pointer; }
.ct tbody a.cname::after { content: ""; position: absolute; inset: 0; }


/* ============================================================ よくある質問

   `pages/product.html` の末尾。**同じ文が `FAQPage` として申告されている**ので、
   ここを消すなら head の JSON ごと消すこと（見えない FAQ の申告はガイドライン違反）。

   ## 面を外した（2026-10-08）

   ⚠ **以前は `.panel.glass` だった。** 「一番下の FAQ が変に目立っています」と
     言われた。補足でしかないのに、上の「月ごとの増減」や「よく併用されている
     プロダクト」と**まったく同じ重さのカード**で、しかもページの最後にあるぶん
     いちばん印象に残る位置に座っていた。面を外して罫線1本に落とす。
   ⚠ **`<h2>` を小さくしない。** `static/app.css` が「パネルの中だからといって
     見出しを小さくしない」「階層を下げたいときは `h2` ではなく `h3` を書く」と
     決めている。ここは `<main>` 直下の節なので h2 が正しい階層で、弱めるのは
     **面と色**でやる（`--text-secondary` に落とすだけ）。
   ⚠ **`/faq/` の `.qa` を借りない。** あちらは `static/method.css` にあり、この面には
     配られていない（`web/emit/render.py` の `STYLESHEETS_BY_TEMPLATE`）。借りると
     「全ページに全部配られているから効く」という偶然に戻る。
   ⚠ **畳まない**（`<details>` にしない）。3〜4本しかないので、畳むと読まれないまま
     申告だけが残る。`/faq/` が畳んでいるのは質問が10本以上あるから。
   ⚠ 新しい文字サイズを作らない（`--fs-md` / `--fs-sm` の2段で足りる）。 */

/* 本文との間を広めに取る。**面が無いぶん、ここが「別の話」だと分かる唯一の印。** */
.pqa { margin-top: 28px; padding-top: 16px; border-top: 1px solid var(--border); }
.pqa > h2 { color: var(--text-secondary); }
.pqa__list { margin-top: 8px; }
.pqa__item { padding: 9px 0; border-bottom: 1px solid var(--border); }
.pqa__item:last-child { padding-bottom: 0; border-bottom: 0; }
.pqa__q { margin: 0; font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--text-secondary); }
.pqa__a {
  /* ⚠ `--fs-xs` まで落とさない。**補足でも読ませる文**で、しかも `FAQPage` として
     申告している内容そのもの（読めない大きさで出すのは申告と食い違う）。 */
  margin: 4px 0 0; font-size: var(--fs-sm); color: var(--text-secondary);
  line-height: 1.8; max-width: 80ch;
}

/* ⚠ 個票の断り書き（「検出できなかった ≠ 使っていない」「日付は初観測」）。
   2026-10-09 までページ末尾の FAQ の中にしか無く、FAQ を消すときにここへ移した。
   ⚠ **弱く出すが、読めなくはしない。** 法務上の線なので `--text-muted` には落とさない
     （コントラストの実測で AA を割る）。 */
.psec__note {
  margin: var(--gap-2) 0 0; max-width: 72ch;
  font-size: var(--fs-sm); line-height: 1.7; color: var(--text-secondary);
}
.psec__note b { color: var(--text-primary); font-weight: var(--fw-semibold); }


/* ====================================================== 狭い画面での表

   設計は `docs/design/responsive.md` §3.3（この2面ぶん）と §4.1（表の規則）。

   ## 段ごとの扱い

   | 段 | `.sx`（一覧）/ `.ct`（企業リスト） |
   |---|---|
   | wide ≥900 | そのまま。器に収まるので横スクロールは出ない |
   | medium 600–899 | **横スクロール。** 器（`.sx-scroll` / `.ct-scroll`）が常時受ける |
   | compact ≤599 | 同じく横スクロール。**`.sx` の列見出しは貼り付けない**（下） |

   ⚠⚠ **本物の `<table>` を `display: block` で畳まない。** `display` を変えると
     支援技術から**表として読まれなくなる**（行と列の関係が消え、セルが縦に
     並んだだけのものになる）。列を `display: none` で落とすのも**論外** ——
     消した根拠はどこにも残らない（§1.2）。**横に振らせる。**
     カードに畳んでよいのは `<div>` / `<ul>` + grid で組んだ行だけで、この2面では
     併用プロダクトの `.co`（上の節）がそれ。2列の定義表（`.sum`）だけは例外で、
     畳むかわりに `role` を補ってある。
   ⚠ **`overflow-x: hidden` で蓋をしない。** 原因が画面から見えなくなるうえ、
     同じ軸の `position: sticky` が死ぬ（§4.6）。
   ⚠ **1列目（カテゴリ）を sticky にしない。** `docs/design/responsive.md` §3.3 は
     「1列目を sticky に」と書いているが、**この表の1列目は添え物のカテゴリで、
     行の身元はプロダクト名（2列目）**。身元の列を貼り付けようとすると、
     `position: sticky` がそのセルを**包含ブロックにしてしまい**、行全体を覆っている
     `.cname::after`（上の「クリック範囲は行全体」）が**名前のセルぶんに縮む** ——
     「カードのクリックできる場所がバラバラ」で2回直したものが戻る。
     しかも medium で横に振れる量は実測で 0〜130px（表の最小 660px −
     600〜744px の器）しかなく、名前の列はそもそも画面から出ない。
     **貼り付けるなら、行クリックを JS 以外の手で持ち直してから。** */

@media (max-width: 599px) {
  /* ⚠⚠ **compact では一覧の列見出しを貼り付けない（2026-10-10）。**
     実測（390×844）で `/product/` の固定物は **301px＝画面の 36%**、うち 164px が
     この列見出しだった。⚠ **164px は `th` を4本ぶん足した数で、見えている帯は
     41px の1段**（`web/tools/qa_mobile.py` の `chrome` は貼り付いたセルを
     1つずつ数える）。数字のほうを割り引いても貼るのをやめるのは、
     **390px では表を 270px 横に振らないと右端の列に届かず（最小幅 660px − 器 390px）、
     縦に貼り付いた帯のぶんだけ見える行が減る**から。
     `docs/design/responsive.md` §3.3 の「compact では `thead` の sticky はやめる」。
     ⚠⚠ **`position: static` にしない。** 列フィルタの一覧（`.sx-menu`）は
       `<th>` の中に `position: absolute` で出るので、`static` にすると
       **器を飛び出してページの左上へ落ちる**。素の `.sx thead th` と同じ
       `relative` に戻す。
     ⚠ **企業リスト（`.ct-scroll`）は貼ったまま。** あちらは個票の下のほうにいて
       最初の画面に入らない（固定物として場所を取らない）し、150行の中を
       スクロールする以上「この数字は何の列か」が消えると読めなくなる
       —— その理由は `.ct-scroll` の節に書いてある。 */
  .sx-scroll .sx thead th { position: relative; }
  /* 貼り付いていないのだから蓋の影も要らない（`.is-stuck` は JS が付け外しする）。 */
  .sx-scroll .sx.is-stuck thead th { box-shadow: none; }
}


/* ================================================ 指で触る端末の当たり判定

   ⚠⚠ **幅で決めない。** 幅はレイアウト（何列か / 畳むか / 横に逃がすか）、
   当たり判定は `pointer`（`docs/design/responsive.md` §1.1）。幅で代用すると
   **両方向に外す** —— iPad 横（1024px・指）では小さいまま、窓を狭めた PC
   （マウス）では無駄に大きくなる。
   ⚠ **「`(hover: none)` は検証しにくい」はもう理由にならない。**
     `web/tools/qa_mobile.py` が `has_touch` / `is_mobile` を渡すので、
     タッチ端末としての描画を機械で見られる。

   実測（2026-10-10・390×844 / iPad）で 44px に足りなかったもの:

   | もの | 実測 | 直し方 |
   |---|---|---|
   | `button.sx-fold`（業務カテゴリの開閉） | 24px | 上下に余白 |
   | `button.sx-h`（列見出し） | 40px | `min-height` |
   | `summary`（推移の「数値で見る」） | 24px | 上下に余白＋`min-height` |
   | `a.cname`（表の中のリンク） | 19〜20px・幅は1文字だと 8px | **行ごと**当たり判定にする |

   ⚠ **本文中のインラインリンクは対象外**（WCAG 2.5.8 も除外している）。
     文の途中のリンクを 44px にすると行間が壊れるので、`.pnone` / `.pqa__a` /
     `.psec__note` の中のリンクには当てない。
   ⚠ **文字は大きくしない。** このページは 32/17/15/13.5/11.5 の段で回すと
     決めてある（ファイル冒頭）。広げるのは余白。
   ⚠ 基準は **44px が目標、24px が WCAG 2.2 AA の必須ライン**。 */

@media (pointer: coarse) {
  /* 列見出し。セル全体がボタンなので、背を伸ばせばそのまま当たり判定になる。 */
  .sx-h { min-height: 44px; }
  /* 業務カテゴリの開閉。⚠ **`align-items: baseline` を外さない** ——
     名前（`--fs-md`）と件数（`--fs-xs`）は大きさが違うので、揃えるのは
     ベースライン（`tests/web/test_stylesheet.py` の `.area-head` の節と同じ話）。
     だから `min-height` ではなく**上下の余白**で背を作る（`min-height` だと
     中身が上に寄って、下に 20px の空白が残る）。12 + 22 + 12 = 46px。 */
  .sx-fold { padding: var(--gap-3) 0; }
  /* 絞り込みの一覧。⚠ **枠（14px）は大きくしない。** `<label>` の行を 44px にする
     （`docs/design/responsive.md` §4.2）。チェックボックスそのものを拡大すると
     OS の描画と合わなくなる。 */
  .sx-menu__lab { min-height: 44px; }
  .sx-clear, .sx-menu__tool { min-height: 44px; }
  /* 「数値で見る」。⚠ **`display` を変えない** —— `list-item` から外すと
     開閉の三角（`::marker`）が消えて、押せるものに見えなくなる。 */
  .pipe__data summary { min-height: 44px; padding: var(--gap-3) 0; }
  /* 表の中のリンク。**行ごと当たり判定にする。**
     ⚠ `display: block` が要るのは**横も足りない**から —— 1文字の社名は
       実測 8px しか無かった（`a.cname` 8x20）。block にするとセルの幅ぶん広がる。
     ⚠ **行の高さが伸びるのは承知のうえ。** 指で押す面では 41px の行は細すぎる。
     ⚠ 押せる範囲そのものは `.cname::after` が行全体に敷いている（上の節）。
       ここで広げているのは**リンク自身の箱**で、支援技術と
       `web/tools/qa_mobile.py` が見ているのはこちら。 */
  .sx tbody .cname,
  .ct tbody .cname { display: block; padding: var(--gap-3) 0; }
  /* ⚠ **一覧側は入れ物まで広げないと横が効かない。** `.pcell` は `inline-flex`、
     `.pcell__main` も中身の幅しか持たないので、中のリンクを `block` にしても
     **文字の幅のまま**（「Box」なら 30px）。セルの幅まで伸ばす。
     ⚠ **`app.css` の `.pcell` は触らない**（企業個票でも使っている共有物）。
       ここは `.sx tbody` の中だけを上書きする。 */
  .sx tbody .pcell { display: flex; }
  .sx tbody .pcell__main { flex: 1 1 auto; }
  /* 併用プロダクトの行。`inline-flex` なので `min-height` がそのまま効く。 */
  .co__name { min-height: 44px; }
  /* 「カタログ上の同じ用途のプロダクト」のチップ。親が `align-items: center` の
     flex なので、背だけ伸ばせば文字は中央に残る。 */
  .sum__rivals .chip { display: inline-flex; align-items: center; min-height: 44px; }
  /* 「公式サイト」の URL。表の中の単独のリンクなので、本文のインラインとは別物。 */
  .sum td a { display: inline-block; padding: var(--gap-2) 0; min-height: 44px; }
}
