/* ============================================================================
 * FVJAPAN CRM — 部品（docs/DESIGN.md §4-B の実体の素の CSS 版）
 *
 * 命名規則: `c-<部品>` ／ 子要素 `c-<部品>__<要素>` ／ 見た目の差 `c-<部品>--<バリアント>`。
 *   例: <a class="c-button c-button--secondary c-button--sm">
 * **状態は修飾クラスで持たず、意味を持つ属性で持つ**（aria-disabled / aria-current /
 * aria-selected / aria-sort / aria-invalid / :checked / data-status 等）。
 * 見た目と支援技術への伝わり方が同じ1つの源から決まり、片方だけ付け忘れることが起きない。
 *
 * 出典は web/components/{ui,crm,customers}/*.tsx の Tailwind クラス（各節の先頭に元のファイル）。
 * **値は tokens.css の変数でのみ参照する。** 生の色・任意の px を書かない（DESIGN.md §5-D）。
 * 余白は calc(var(--spacing) * N)。N は Tailwind の `p-N` と同じ数なので、元のクラスと突き合わせられる。
 *
 * **スノーフレーク防止**（DESIGN.md §3 / §4-B）: 新しい見た目が要るときは既存の部品に
 * `--バリアント` を足し、§4-B の表を同じ変更で更新する。`c-button-primary` のような別部品を作らない。
 * ========================================================================== */


/* ============================================================================
 * Button（web/components/ui/button.tsx）
 *
 * <button> にも <a> にも同じクラスを当てる（リンクをボタンに見せる形。API契約 v1.1 裁定8）。
 * ========================================================================== */
.c-button {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  gap: calc(var(--spacing) * 1.5);
  height: var(--control-h-compact); /* h-8 = 32px（§4-A: 標準は 32px） */
  padding-inline: calc(var(--spacing) * 2.5);
  border: var(--border-w) solid transparent;
  border-radius: var(--radius-md);
  background-clip: padding-box;
  font-size: var(--text-sm);
  /* Tailwind 版は `font-medium`（500）。DESIGN.md §5-C は 400/600 の2種と定めており食い違うが、
     実装を優先して移した（報告済みのずれ） */
  font-weight: 500;
  white-space: nowrap;
  user-select: none;
  /* cursor は指定しない。Tailwind v4 の preflight はボタンを cursor: default にしており、
     shadcn の Button も cursor-pointer を持たない（リンクに当てたときはリンクの既定の指になる） */
  text-decoration: none;
  /* outline-color を含む。base.css の `* { outline-color }` がこの遷移の始点を揃えている */
  transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke;
  transition-timing-function: var(--ease-standard);
  transition-duration: var(--duration-colors);
}
.c-button:focus-visible {
  border-color: var(--ring);
  /* shadcn 由来の `focus-visible:ring-2 ring-ring/50`。輪郭（outline）は base.css が描き、これは内側の淡い帯 */
  box-shadow: 0 0 0 var(--ring-w) color-mix(in oklab, var(--ring) 50%, transparent);
}
.c-button:active:not([aria-haspopup]):not([aria-disabled="true"]) {
  transform: translateY(var(--press-offset));
}
.c-button:disabled {
  pointer-events: none;
  opacity: 0.5; /* ネイティブ disabled の既定。**押せない操作は RestrictedAction（aria-disabled）で出す**ので業務画面では使わない */
}
.c-button svg {
  pointer-events: none;
  flex-shrink: 0;
  width: calc(var(--spacing) * 4);
  height: calc(var(--spacing) * 4);
}

/* ---- variant ---- */
/* 主 CTA（1画面1つ）。teal-700 背景＋白文字 */
.c-button--default {
  background-color: var(--primary);
  color: var(--primary-foreground);
}
.c-button--default:hover {
  background-color: var(--color-primary-hover);
}
/* 副次操作（CSV出力・戻る・編集） */
.c-button--secondary {
  background-color: var(--secondary);
  color: var(--secondary-foreground);
}
.c-button--secondary:hover {
  background-color: color-mix(in oklch, var(--secondary), var(--foreground) 5%);
}
.c-button--secondary[aria-expanded="true"] {
  background-color: var(--secondary);
  color: var(--secondary-foreground);
}
.c-button--outline {
  border-color: var(--border);
  background-color: var(--background);
}
.c-button--outline:hover,
.c-button--outline[aria-expanded="true"] {
  background-color: var(--muted);
  color: var(--foreground);
}
/* 弱い操作 */
.c-button--ghost:hover,
.c-button--ghost[aria-expanded="true"] {
  background-color: var(--muted);
  color: var(--foreground);
}
/* 破壊的操作（削除・別人として確定） */
.c-button--destructive {
  background-color: color-mix(in oklab, var(--destructive) 10%, transparent);
  color: var(--destructive);
}
.c-button--destructive:hover {
  background-color: color-mix(in oklab, var(--destructive) 20%, transparent);
}
.c-button--destructive:focus-visible {
  border-color: color-mix(in oklab, var(--destructive) 40%, transparent);
  box-shadow: 0 0 0 var(--ring-w) color-mix(in oklab, var(--destructive) 20%, transparent);
}
/* 状態を切り替える強い操作（優先対応フラグ）。破壊的ではないので枠線で表す */
.c-button--warning {
  border-color: var(--color-warning-border);
  background-color: var(--color-warning-bg);
  color: var(--color-warning-fg);
}
.c-button--warning:hover {
  border-color: var(--color-warning-fg);
}
/* AI 機能の起動（DESIGN.md §11） */
.c-button--ai {
  background-color: var(--color-ai-fg);
  color: var(--color-white);
}
.c-button--ai:hover {
  background-color: color-mix(in oklab, var(--color-ai-fg) 90%, transparent);
}
/* 「追加」の空きスロット（＋契約を追加 / ＋現在の条件を保存） */
.c-button--dashed {
  border-style: dashed;
  border-color: var(--color-gray-300);
  background-color: var(--color-surface);
  color: var(--color-text-muted);
}
.c-button--dashed:hover {
  border-color: var(--primary);
  color: var(--primary);
}

/* ---- size ---- */
.c-button--xs {
  gap: calc(var(--spacing) * 1);
  height: calc(var(--spacing) * 6);   /* 24px */
  padding-inline: calc(var(--spacing) * 2);
  font-size: var(--text-xs);
}
.c-button--xs svg {
  width: calc(var(--spacing) * 3);
  height: calc(var(--spacing) * 3);
}
.c-button--sm {
  gap: calc(var(--spacing) * 1);
  height: calc(var(--spacing) * 7);   /* 28px */
  padding-inline: calc(var(--spacing) * 2.5);
  font-size: var(--text-sm);
}
.c-button--sm svg {
  width: calc(var(--spacing) * 3.5);
  height: calc(var(--spacing) * 3.5);
}
/* 主 CTA のみ h-9（§4-A） */
.c-button--lg {
  height: var(--control-h-standard);  /* 36px */
}
.c-button--icon {
  width: var(--control-h-compact);
  height: var(--control-h-compact);
  padding-inline: 0;
}
/* 置かれた枠（グリッドのセル・包み）いっぱいに伸ばす。**寸法の段ではない**ので size と併用する
   （顧客詳細②の「＋ 契約を追加」が契約カードと同じ高さの枠になる形。移植元 `h-auto w-full` の枠の中の `h-full`） */
.c-button--stretch {
  width: 100%;
  height: 100%;
}

/* ---- aria-disabled（RestrictedAction の見た目）----
 * **variant の後ろに置く**（同じ詳細度なら後勝ち。hover は :hover を足して詳細度でも勝つ）。
 *   - **opacity で薄めない。** gray-900 の 50% は白背景で AA(4.5:1) を割る（§10）。
 *     面を gray-100・文字を text-muted にする（button.tsx の実測 5.37:1）
 *   - **pointer-events: none も付けない。** 付けるとホバーで理由が出せなくなる */
.c-button[aria-disabled="true"],
.c-button[aria-disabled="true"]:hover {
  cursor: not-allowed;
  border-color: var(--border);
  background-color: var(--color-gray-100);
  color: var(--color-text-muted);
  box-shadow: none;
}
.c-button--dashed[aria-disabled="true"],
.c-button--dashed[aria-disabled="true"]:hover {
  border-color: var(--border);
}


/* ============================================================================
 * RestrictedAction（web/components/crm/restricted-action.tsx）
 *
 * 押せない操作の**唯一の見せ方**（§9 ⑥・A-1）。構造は webui/components/restricted_action.html。
 *   <span class="c-restricted" data-restricted-action>
 *     <button class="c-button …" type="button" aria-disabled="true" aria-describedby="ID">…</button>
 *     <span id="ID" class="c-restricted__reason" aria-hidden="true">理由</span>   ← 常に DOM にある
 *   </span>
 *
 * 理由は**閉じているあいだも読み上げ専用として DOM に在る**（aria-describedby の参照先を絶やさない）。
 * 吹き出しとして見せるのは **ホバーまたはフォーカスのあいだ**（:hover / :focus-within）。
 * **JS が読み込まれなくても、ポインタでもキーボードでも理由が見える。**
 * JS（restricted-action.js）は WCAG 2.2 1.4.13 の Dismissible を足す:
 * Esc で data-dismissed="true" を付けて隠し、離れる（blur / mouseleave）まで開き直さない。
 * ========================================================================== */
.c-restricted {
  position: relative;
  display: inline-flex;
}
/* 閉じている: sr-only と同じ宣言（base.css の .sr-only の写しではなく、状態で切り替えるためにここに持つ） */
.c-restricted__reason {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border-width: 0;
}
/* ↑ 1px / -1px は sr-only の定型（base.css の注記）。 */
.c-restricted:is(:hover, :focus-within):not([data-dismissed="true"]) .c-restricted__reason {
  top: 100%;
  left: 0;
  z-index: 40;
  width: max-content;
  max-width: var(--popover-w);
  height: auto;
  margin: calc(var(--spacing) * 1) 0 0;
  overflow: visible;
  clip-path: none;
  white-space: normal;
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface);
  padding: calc(var(--spacing) * 1) calc(var(--spacing) * 2);
  font-size: var(--text-sm);
  color: var(--color-text);
  box-shadow: var(--shadow-3);
}
/* ボタンと吹き出しの隙間（上の margin-top）を、吹き出し自身の見えない帯で覆う（WCAG 2.2 1.4.13 Hoverable）。
   帯は吹き出しの子なので、ポインタが帯の上にある間も包み（.c-restricted）の :hover が続き、
   ボタンから吹き出しへゆっくり動かしても途中で閉じない（a11y 監査 Med: ボタン下端＋1px で閉じていた）。
   高さは margin-top と枠線の和（隙間ちょうど。ボタンに重ねない） */
.c-restricted:is(:hover, :focus-within):not([data-dismissed="true"]) .c-restricted__reason::before {
  content: "";
  position: absolute;
  right: 0;
  bottom: 100%;
  left: 0;
  height: calc(var(--spacing) * 1 + var(--border-w));
}
/* 画面の右端に並ぶ操作は右寄せにしないとビューポートの外へはみ出す（align="end"） */
.c-restricted--end:is(:hover, :focus-within):not([data-dismissed="true"]) .c-restricted__reason {
  left: auto;
  right: 0;
}


/* ============================================================================
 * Badge（web/components/ui/badge.tsx）
 * ========================================================================== */
.c-badge {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  gap: calc(var(--spacing) * 1);
  width: fit-content;
  height: calc(var(--spacing) * 5); /* h-5 = 20px */
  overflow: hidden;
  border: var(--border-w) solid transparent;
  border-radius: var(--radius-sm); /* 元は shadcn の rounded-4xl（globals.css で 4px の別名） */
  padding: calc(var(--spacing) * 0.5) calc(var(--spacing) * 2);
  font-size: var(--text-xs);
  font-weight: 500;
  white-space: nowrap;
}
/* 流入ブランド。意味を持たない識別ラベルなので無彩色 */
.c-badge--brand {
  background-color: var(--color-gray-100);
  color: var(--color-gray-700);
  font-size: var(--text-2xs);
  font-weight: 600;
}
/* 法人マーク */
.c-badge--corp {
  background-color: var(--color-gray-900);
  color: var(--color-white);
  font-size: var(--text-2xs);
  font-weight: 700;
}
/* 警告（アラートの要約）。danger は「対応が要る」の意味 */
.c-badge--alert {
  border-color: var(--color-danger-border);
  background-color: var(--color-danger-bg);
  color: var(--color-danger-fg);
  font-size: var(--text-2xs);
  font-weight: 600;
}
/* 重複候補（強さ区分を併記。「強さ区分」の語は sr-only で必ず添える・§11-B） */
.c-badge--ai {
  border-color: var(--color-ai-border);
  background-color: var(--color-ai-bg);
  color: var(--color-ai-fg);
  font-size: var(--text-2xs);
  font-weight: 700;
}
/* オプション契約（✓付き） */
.c-badge--option {
  border-color: var(--border);
  background-color: var(--color-gray-50);
  color: var(--color-gray-700);
  font-size: var(--text-2xs);
  font-weight: 600;
}
/* 件数。面を持たず色は親から継承する。opacity で薄くしない（§10） */
.c-badge--count {
  background-color: transparent;
  padding-inline: calc(var(--spacing) * 1);
  font-size: var(--text-2xs);
  font-weight: 600;
}
/* 優先対応フラグ */
.c-badge--flag {
  background-color: transparent;
  padding-inline: calc(var(--spacing) * 1);
  color: var(--color-warning-fg);
  font-size: var(--text-2xs);
  font-weight: 700;
}
/* 未成年・高齢 */
.c-badge--caution {
  border-color: var(--color-warning-border);
  background-color: var(--color-warning-bg);
  color: var(--color-warning-fg);
  font-size: var(--text-2xs);
  font-weight: 700;
}


/* ============================================================================
 * Card（汎用の面）／ SectionCard ／ SummaryBox（web/components/crm/section-card.tsx）
 * ========================================================================== */
/* `rounded-lg border border-border bg-surface shadow-1 p-4`（ダッシュボードの KPI 等の頻出形） */
.c-card {
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-lg);
  background-color: var(--color-surface);
  padding: calc(var(--spacing) * 4);
  box-shadow: var(--shadow-1);
}
/* カードの見出し（見つからないときの本文 not_found.html の h1。移植元 `text-md font-semibold`） */
.c-card__title {
  font-size: var(--text-md);
  font-weight: 600;
}
.c-card--flush {
  padding: 0;
  box-shadow: none;
}
.c-card--ai {
  border-color: var(--color-ai-border);
}
/* 押せるカードだけ影を上げる（押せない数字を押せるように見せない） */
a.c-card:hover {
  box-shadow: var(--shadow-2);
}

.c-section-card {
  overflow: hidden;
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-lg);
  background-color: var(--color-surface);
  box-shadow: var(--shadow-1);
}
.c-section-card__head {
  display: flex;
  align-items: center;
  gap: calc(var(--spacing) * 2);
  border-bottom: var(--border-w) solid var(--border);
  background-color: var(--color-gray-50);
  padding: calc(var(--spacing) * 3) calc(var(--spacing) * 4);
  font-size: var(--text-md);
  font-weight: 600;
}
/* 見出し（h2）そのもの。番号・罫・文を横に並べる。右端の補助情報（__meta）は h2 の外の兄弟（section_card.html） */
.c-section-card__title {
  display: flex;
  align-items: center;
  gap: calc(var(--spacing) * 2);
  min-width: 0;
}
/* ①〜④ の番号バッジ */
.c-section-card__number {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: calc(var(--spacing) * 4);
  height: calc(var(--spacing) * 4);
  border-radius: var(--radius-sm);
  background-color: var(--color-gray-200);
  font-size: var(--text-2xs);
  font-weight: 700;
  color: var(--color-gray-700);
}
/* アクセント罫。色は**意味**を運ぶ（DESIGN.md §1-2） */
.c-section-card__bar {
  width: calc(var(--spacing) * 1);
  height: calc(var(--spacing) * 4);
  border-radius: var(--radius-sm);
  background-color: var(--color-accent-nontext);
}
.c-section-card--warning .c-section-card__bar { background-color: var(--color-warning-fg); }
.c-section-card--danger  .c-section-card__bar { background-color: var(--color-danger-fg); }
.c-section-card--info    .c-section-card__bar { background-color: var(--color-info-fg); }
.c-section-card--ai      .c-section-card__bar { background-color: var(--color-ai-fg); }
.c-section-card__meta {
  margin-left: auto;
  font-size: var(--text-sm);
  font-weight: 400;
  color: var(--color-text-muted);
}
.c-section-card__body {
  padding: calc(var(--spacing) * 4);
}
/* 中身をはみ出して描く区画（押せない操作の理由の吹き出しを切らない。section_card.html の open）。
   切り抜きをやめる代わりに、見出しの面の角を枠に合わせて丸める */
.c-section-card--open {
  overflow: visible;
}
.c-section-card--open .c-section-card__head {
  border-top-left-radius: var(--radius-lg);
  border-top-right-radius: var(--radius-lg);
}

.c-summary-box {
  display: flex;
  align-items: center;
  gap: calc(var(--spacing) * 4);
  border-radius: var(--radius-md);
  background-color: var(--color-primary-soft);
  padding: calc(var(--spacing) * 3) calc(var(--spacing) * 4);
}
.c-summary-box__label {
  font-size: var(--text-sm);
  font-weight: 600;
}
.c-summary-box__note {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.c-summary-box__value {
  margin-left: auto;
  font-size: var(--text-xl);
  font-weight: 700;
}


/* ============================================================================
 * DataTable（web/components/crm/data-table.tsx ／ .claude/rules/tables.md）
 *
 *   <div class="c-table-wrap">
 *     <table class="c-table" data-density="compact|standard">   ← 縦 padding は base.css の table[data-density]
 *       <thead class="c-table__head"><tr><th class="c-table__th" scope="col" aria-sort="…">
 *            <a class="c-table__sort" href="…">顧客番号</a></th>
 *       <tbody><tr class="c-table__row">（行全体を押せる行は c-table__row--link ＋ 本命のリンクに c-table__row-link）
 *            <td class="c-table__td c-table__td--num|--mono">
 *
 * **行高は table の data-density から決める**（Tailwind 版は <Tr density> と <table density> を
 * 別々に受けていた。1つの表で食い違う理由が無いので、表の属性1つに寄せた・報告済み）。
 * ========================================================================== */
/* 折り返さないセルの横溢れは表側で受ける（1280px 未満の横スクロール・§6） */
.c-table-wrap {
  width: 100%;
  overflow-x: auto;
}
.c-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}
.c-table__head {
  background-color: var(--color-gray-50);
  text-align: left;
  color: var(--color-text-muted);
}
.c-table__th {
  padding: calc(var(--spacing) * 2) calc(var(--spacing) * 3);
  font-weight: 600;
  white-space: nowrap;
}
/* ソート可能な見出しは**リンクで**並び替える（URL に載るので戻ったとき並び順が復元される・§1） */
.c-table__sort {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--spacing) * 1);
  font-weight: 600;
}
.c-table__sort:hover {
  color: var(--primary);
}
/* aria-sort の表示。記号は装飾なので読み上げない（`content: "…" / ""` の代替テキスト空）。
   状態そのものは th の aria-sort が支援技術に伝える */
.c-table__th[aria-sort] .c-table__sort::after {
  font-size: var(--text-2xs);
  content: "◆";
  content: "◆" / "";
}
.c-table__th[aria-sort="ascending"] .c-table__sort::after {
  content: "▲";
  content: "▲" / "";
}
.c-table__th[aria-sort="descending"] .c-table__sort::after {
  content: "▼";
  content: "▼" / "";
}
.c-table__th--num {
  text-align: right;
}
/* 長い見出しだけ折り返す（既定は折り返さない） */
.c-table__th--wrap {
  white-space: normal;
}
.c-table__row {
  border-top: var(--border-w) solid var(--border);
  height: var(--row-h-standard);
}
.c-table[data-density="compact"] .c-table__row {
  height: var(--row-h-compact);
}
/* コンパクトは**横の余白も詰める**（§6 の密度規約の表: コンパクト ＝ 横 `--space-2` / 縦 4px、
   標準 ＝ 横 `--space-3` / 縦 `--space-2`。縦は base.css の `table[data-density]`）。
   2026-09-16 まで行高と縦の余白しか効いておらず、§6 の横の欄が実装されていなかった。
   列の多い一覧（顧客DB一覧 11列・申込ビュー 9列）を 1280px に収める余地は、ここが素のまま 12px だと出ない
   （1列あたり 8px ＝ 11列で 88px。実測は e2e/geometry.spec.ts）。 */
.c-table[data-density="compact"] .c-table__th,
.c-table[data-density="compact"] .c-table__td {
  padding-inline: calc(var(--spacing) * 2);
}
.c-table__row:hover {
  background-color: var(--color-gray-100);
}
/* 行全体を詳細へのリンクにする行（TrLink）。**JS を使わない stretched link**:
   行内の本命リンク（`c-table__row-link`。顧客名など）の ::after を行いっぱいに広げ、行のどこを選んでも
   そのリンクを押したことにする（Enter で同じ遷移ができるのはリンクそのものだから・tables.md）。
   行内の他の操作（重複候補のバッジなど）は ::after より上に載せて、それぞれの行き先を保つ。
   **`title` を持つ要素（省略した住所・カナ・流入ブランド・アラート等）も ::after より上に載せる**。
   覆われると、ホバーで出るのが本命リンクの title（氏名）になり、省略した全文をマウスで読む手段が無くなる
   （正しさレビュー Med 2026-09-14。`e2e/geometry.spec.ts` が elementFromPoint で固定）。
   受け入れた不利益: 行の文字をドラッグで選べない（選ぶと遷移になる）。`title` を持つ要素の上だけは、押しても遷移しない
   （その要素の外、同じ行の他の場所では遷移する）。
   `title` を持つ要素が本命リンクの祖先（td や包み要素）なら載せない。載せると ::after の包含ブロックが行から
   その要素に縮み、「行のどこを押しても詳細」が黙って効かなくなる（正しさレビュー Low 2026-09-14）。
   `position: relative` を行に置く（表の行を包含ブロックにできるのは現行の Chromium / Firefox / WebKit） */
.c-table__row--link {
  position: relative;
}
.c-table__row--link:hover,
.c-table__row--link:has(.c-table__row-link:focus-visible) {
  background-color: var(--color-primary-soft);
}
.c-table__row-link::after {
  content: "";
  position: absolute;
  inset: 0;
}
.c-table__row--link :is(a, button, [title]:not(:has(.c-table__row-link))):not(.c-table__row-link) {
  position: relative;
  z-index: 1;
}
.c-table__td {
  padding: calc(var(--spacing) * 2) calc(var(--spacing) * 3);
  /* 折り返さない。折り返すと行高がばらついて縦の走査ができなくなる */
  white-space: nowrap;
}
/* 数量（金額・件数）。等幅＋桁揃え＋**右寄せ** */
.c-table__td--num {
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
/* 識別子（顧客番号・受付番号・電話番号・日付）。等幅＋桁揃えだが**左寄せのまま** */
.c-table__td--mono {
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
}
/* 自由記述など、切ると意味が欠けるセルだけ折り返す（既定は行高を揃えるため折り返さない） */
.c-table__td--wrap {
  white-space: normal;
}
/* 半画面に多くの列を収める表（顧客詳細③の7列。移植元 `[&_td]:px-2 [&_th]:px-2 text-xs`）。
   行高は data-density のまま、**横の余白と字の大きさだけ**詰める */
.c-table--tight {
  font-size: var(--text-xs);
}
.c-table--tight .c-table__th,
.c-table--tight .c-table__td {
  padding-inline: calc(var(--spacing) * 2);
}


/* ============================================================================
 * Chip（web/components/crm/chip.tsx）
 *
 * SSR では「押すと適用」「× で外す」はどちらも GET のリンク（<a>）になる。
 * 外したあとはページごと描き直されるので、Tailwind 版の「消える要素からフォーカスを逃がす」処理は要らない。
 * ========================================================================== */
.c-chip {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--spacing) * 2);
  border: var(--border-w) solid transparent;
  border-radius: var(--radius-sm);
  padding: calc(var(--spacing) * 1) calc(var(--spacing) * 3);
  font-size: var(--text-sm);
  font-weight: 600;
}
/* 保存検索（押すと適用） */
.c-chip--saved {
  background-color: var(--color-primary-soft);
  color: var(--color-teal-900);
}
/* 適用中のフィルタ（× 付き） */
.c-chip--filter {
  border-color: var(--color-info-border);
  background-color: var(--color-info-bg);
  color: var(--color-info-fg);
}
/* 追加の空きスロット */
.c-chip--dashed {
  border-style: dashed;
  border-color: var(--color-gray-300);
  background-color: var(--color-surface);
  color: var(--color-text-muted);
}
.c-chip__action {
  cursor: pointer;
}
/* いま開いている保存検索（chip.html の current）。色だけに頼らず下線も引く（§10） */
.c-chip--saved:has(> .c-chip__action[aria-current="true"]) {
  border-color: var(--color-accent-nontext);
}
.c-chip__action[aria-current="true"] {
  text-decoration-line: underline;
}
.c-chip__remove {
  position: relative;
  cursor: pointer;
  font-weight: 700;
  /* Tailwind 版の `opacity-70 hover:opacity-100` をそのまま移した（×印の弱め。文字列ではなく記号） */
  opacity: 0.7;
}
.c-chip__remove:hover {
  opacity: 1;
}
/* 実寸は小さいので、不可視のヒット領域を広げる（WCAG 2.5.8） */
.c-chip__remove::after {
  content: "";
  position: absolute;
  inset: calc(var(--spacing) * -2);
}


/* ============================================================================
 * SegmentedControl（web/components/crm/segmented-control.tsx）
 *
 * フォームも送信ボタンも持たない（移行計画 D13改）。選択肢の渡し方で2つの形がある（segmented_control.html）:
 *   ① ラジオ（呼ぶ側のフォームに入る。矢印キーでの選択移動はブラウザのラジオが持つ）
 *     <div class="c-segmented" role="radiogroup" aria-label="…">
 *       <label class="c-segmented__option"><input class="c-segmented__input" type="radio" …>
 *         <span class="c-segmented__label">すべて</span></label>
 *   ② リンク（選ばれている方に aria-current="true"。状態は属性で持つ）
 *     <div class="c-segmented" role="group" aria-label="…">
 *       <a class="c-segmented__link" href="…" aria-current="true">顧客ビュー</a>
 * ========================================================================== */
.c-segmented {
  display: inline-flex;
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface);
  padding: calc(var(--spacing) * 1);
}
.c-segmented__option {
  position: relative;
  display: inline-flex;
}
/* ラジオ自体は見せないが、フォーカスと選択は受け取る（display:none にしない） */
.c-segmented__input {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
  margin: 0;
}
.c-segmented__label,
.c-segmented__link {
  border-radius: var(--radius-sm);
  padding: calc(var(--spacing) * 1) calc(var(--spacing) * 3);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-text-muted);
  cursor: pointer;
  transition-property: color, background-color;
  transition-timing-function: var(--ease-standard);
  transition-duration: var(--duration-colors);
}
.c-segmented__link {
  text-decoration: none;
}
.c-segmented__option:hover .c-segmented__label,
.c-segmented__link:hover {
  background-color: var(--color-gray-100);
  color: var(--color-text);
}
.c-segmented__input:checked + .c-segmented__label,
.c-segmented__link[aria-current="true"] {
  background-color: var(--primary);
  color: var(--color-white);
}
/* 選択肢に添える件数（顧客DB一覧の顧客区分。2026-09-16）。**名前の一部として読まれる**（aria-hidden にしない） */
.c-segmented__count {
  margin-left: calc(var(--spacing) * 1);
  font-weight: 400;
}
/* 輪郭は見えている側（ラベル）に描く。入力は透明なので、そちらに描いても見えない */
/* 入力の誤り（選択肢に aria-invalid）。色だけで伝えない ＝ 文は呼ぶ側の fieldset が結ぶ */
.c-segmented:has(.c-segmented__input[aria-invalid="true"]) {
  border-color: var(--destructive);
}
.c-segmented__input:focus-visible + .c-segmented__label {
  outline: var(--focus-outline-w) solid var(--color-focus);
  outline-offset: var(--focus-outline-offset);
}


/* ============================================================================
 * ProductTabs（web/components/customers/product-tabs.tsx）
 *
 * role="tablist" のリンク列。確定は Enter（リンクの既定動作）。矢印・Home・End は tabs.js。
 * ========================================================================== */
.c-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--spacing) * 0.5);
  margin-bottom: calc(var(--spacing) * 4);
}
.c-tabs__tab {
  border-radius: var(--radius-md);
  padding: calc(var(--spacing) * 2) calc(var(--spacing) * 4);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-text-muted);
}
.c-tabs__tab:hover {
  background-color: var(--color-gray-100);
  color: var(--color-text);
}
.c-tabs__tab[aria-selected="true"],
.c-tabs__tab[aria-selected="true"]:hover {
  background-color: var(--primary);
  color: var(--color-white);
}
.c-tabs__count {
  margin-left: calc(var(--spacing) * 1);
}


/* ============================================================================
 * LoadError（web/components/crm/load-error.tsx）
 *
 * ④エラー（network / badRequest / server）と⑥権限なし（forbidden）で**見た目が違う**。
 * ⑥は不具合ではないので赤で描かない（中立な面）。
 * ========================================================================== */
.c-load-error {
  border: var(--border-w) solid var(--color-danger-border);
  border-radius: var(--radius-lg);
  background-color: var(--color-danger-bg);
  padding: calc(var(--spacing) * 4);
}
.c-load-error__title {
  font-size: var(--text-md);
  font-weight: 600;
  color: var(--color-danger-fg);
}
.c-load-error__message,
.c-load-error__hint,
.c-load-error__note {
  margin-top: calc(var(--spacing) * 2);
  font-size: var(--text-sm);
}
.c-load-error__message {
  color: var(--color-danger-fg);
}
.c-load-error__hint,
.c-load-error__note {
  color: var(--color-text-muted);
}
.c-load-error__actions {
  margin-top: calc(var(--spacing) * 3);
}
/* ⑥ 権限なし */
.c-load-error--forbidden {
  border-color: var(--border);
  background-color: var(--color-gray-50);
}
.c-load-error--forbidden .c-load-error__title {
  color: inherit;
}
.c-load-error--forbidden .c-load-error__message {
  color: inherit;
}


/* ============================================================================
 * EmptyState（web/components/crm/empty-state.tsx）。②空は必ず次の一手を置く
 * ========================================================================== */
.c-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--spacing) * 2);
  padding: calc(var(--spacing) * 12) calc(var(--spacing) * 4);
  text-align: center;
}
.c-empty__title {
  font-size: var(--text-sm);
  font-weight: 600;
}
.c-empty__description {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.c-empty__action {
  margin-top: calc(var(--spacing) * 2);
}


/* ============================================================================
 * StatusBadge（web/components/crm/status.tsx）
 *
 * 3つの**別レイヤー**を1つの部品に集める。語彙（キー⇄ラベル）はこのファイルに持たない ——
 * 持ち主は api/domain/contracts/status.py（申込）等の Python 側で、テンプレートは受け取って描くだけ。
 * ========================================================================== */
/* ---- 申込ステータスの段（キーで色を引く。**数詞を書かない** ＝ tokens.css の同じ節） ---- */
.c-status--entry {
  display: inline-block;
  border-radius: var(--radius-sm);
  padding: calc(var(--spacing) * 1) calc(var(--spacing) * 2);
  font-size: var(--text-2xs);
  font-weight: 700;
  white-space: nowrap;
}
.c-status--entry[data-status="applied"]  { background-color: var(--color-entry-applied-bg);  color: var(--color-entry-applied-fg); }
.c-status--entry[data-status="callfail"] { background-color: var(--color-entry-callfail-bg); color: var(--color-entry-callfail-fg); }
.c-status--entry[data-status="calldone"] { background-color: var(--color-entry-calldone-bg); color: var(--color-entry-calldone-fg); }
.c-status--entry[data-status="entered"]  { background-color: var(--color-entry-entered-bg);  color: var(--color-entry-entered-fg); }
.c-status--entry[data-status="workdate"] { background-color: var(--color-entry-workdate-bg); color: var(--color-entry-workdate-fg); }
.c-status--entry[data-status="opened"]   { background-color: var(--color-entry-opened-bg);   color: var(--color-entry-opened-fg); }
.c-status--entry[data-status="cxlreq"]   { background-color: var(--color-entry-cxlreq-bg);   color: var(--color-entry-cxlreq-fg); }
.c-status--entry[data-status="cxl"]      { background-color: var(--color-entry-cxl-bg);      color: var(--color-entry-cxl-fg); }

/* ---- 顧客状態5種。バッジではなくテキスト ---- */
.c-status--customer {
  font-size: var(--text-sm);
  font-weight: 600;
  white-space: nowrap;
}
.c-status--customer[data-status="active"]      { color: var(--color-cstatus-active); }
.c-status--customer[data-status="negotiating"] { color: var(--color-cstatus-negotiating); }
.c-status--customer[data-status="prospect"]    { color: var(--color-cstatus-prospect); }
.c-status--customer[data-status="untouched"]   { color: var(--color-cstatus-untouched); }
/* 解約は色だけに頼らず取り消し線を併用する（§10） */
.c-status--customer[data-status="cancelled"]   { color: var(--color-cstatus-cancelled); text-decoration-line: line-through; }

/* ---- 名寄せ候補の状態6種 ----
   **色は語の補助**（語は必ず一緒に出る・§10）。状態は日本語の語そのものが持ち主
   （api/customers/dup_views.py の STATUS_RULES）なので、修飾クラスは tone で受ける。
   語→tone の写像は Python 側（templatetag）に置き、ここに6語を写さない。
     未確認=danger ／ 確認中=info ／ 確定=primary ／ 同一と判定=success ／ 別人と判定=neutral ／ 保留=warning */
.c-status--dup {
  display: inline-block;
  border-radius: var(--radius-sm);
  padding: calc(var(--spacing) * 0.5) calc(var(--spacing) * 2);
  font-size: var(--text-2xs);
  font-weight: 700;
  white-space: nowrap;
}
.c-status--dup.c-status--tone-danger  { background-color: var(--color-danger-bg);    color: var(--color-danger-fg); }
.c-status--dup.c-status--tone-info    { background-color: var(--color-info-bg);      color: var(--color-info-fg); }
.c-status--dup.c-status--tone-primary { background-color: var(--color-primary-soft); color: var(--color-teal-900); }
.c-status--dup.c-status--tone-success { background-color: var(--color-success-bg);   color: var(--color-success-fg); }
.c-status--dup.c-status--tone-neutral { background-color: var(--color-gray-100);     color: var(--color-gray-600); }
.c-status--dup.c-status--tone-warning { background-color: var(--color-warning-bg);   color: var(--color-warning-fg); }
.c-status__count {
  margin-left: calc(var(--spacing) * 1);
}

/* ---- 語彙に無い値。空セルにせず生のまま出す。意味の分からない値に色を付けない ---- */
.c-status--unknown {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}


/* ============================================================================
 * ProductTag（web/components/crm/product-tag.tsx）。商材10色。必ず商材名のテキストを伴う
 * ========================================================================== */
.c-product-tag {
  display: inline-block;
  border-radius: var(--radius-sm);
  padding: calc(var(--spacing) * 1) calc(var(--spacing) * 2);
  font-size: var(--text-2xs);
  font-weight: 600;
  white-space: nowrap;
}
.c-product-tag[data-product="elec"]   { background-color: var(--color-product-elec-bg);   color: var(--color-product-elec-fg); }
.c-product-tag[data-product="gas"]    { background-color: var(--color-product-gas-bg);    color: var(--color-product-gas-fg); }
.c-product-tag[data-product="mobile"] { background-color: var(--color-product-mobile-bg); color: var(--color-product-mobile-fg); }
.c-product-tag[data-product="net"]    { background-color: var(--color-product-net-bg);    color: var(--color-product-net-fg); }
.c-product-tag[data-product="wifi"]   { background-color: var(--color-product-wifi-bg);   color: var(--color-product-wifi-fg); }
.c-product-tag[data-product="ws"]     { background-color: var(--color-product-ws-bg);     color: var(--color-product-ws-fg); }
.c-product-tag[data-product="check"]  { background-color: var(--color-product-check-bg);  color: var(--color-product-check-fg); }
.c-product-tag[data-product="ins"]    { background-color: var(--color-product-ins-bg);    color: var(--color-product-ins-fg); }
.c-product-tag[data-product="tv"]     { background-color: var(--color-product-tv-bg);     color: var(--color-product-tv-fg); }
.c-product-tag[data-product="estate"] { background-color: var(--color-product-estate-bg); color: var(--color-product-estate-fg); }


/* ============================================================================
 * AIPanel ／ AiLevelChip ／ MatchChip（web/components/crm/ai.tsx）
 * ========================================================================== */
.c-ai-panel {
  border: var(--border-w) solid var(--color-ai-border);
  border-radius: var(--radius-lg);
  background-color: var(--color-ai-bg);
  padding: calc(var(--spacing) * 4);
}
.c-ai-panel__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: calc(var(--spacing) * 3);
}
/* 「AI」の印。装飾ではなく「AI の出力である」という意味を運ぶ（§4-B R-5 の食い違いは報告済み） */
.c-ai-panel__mark {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: var(--control-h-compact);
  height: var(--control-h-compact);
  border-radius: var(--radius-md);
  background-color: var(--color-ai-fg);
  font-size: var(--text-2xs);
  font-weight: 700;
  color: var(--color-white);
}
.c-ai-panel__main {
  flex: 1 1 0%;
  min-width: 0;
}
.c-ai-panel__title {
  font-size: var(--text-md);
  font-weight: 600;
}
.c-ai-panel__meta {
  margin-top: calc(var(--spacing) * 1);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
/* `dev_notice`（2026-09-22・ux-critic Med①）。開発用の偽物クライアントの打ち消し文を、
 * 本文（12px/400・埋もれていた）から切り離して見出し直下に独立させる。警告トーンで、
 * 確度バッジ（右上）を見た視線がすぐ拾える位置に置く */
.c-ai-panel__dev-notice {
  display: inline-block;
  margin-top: calc(var(--spacing) * 1);
  border: var(--border-w) solid var(--color-warning-border);
  border-radius: var(--radius-sm);
  background-color: var(--color-warning-bg);
  padding: calc(var(--spacing) * 1) calc(var(--spacing) * 2);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--color-warning-fg);
}
.c-ai-panel__body {
  margin-top: calc(var(--spacing) * 1);
  font-size: var(--text-sm);
}
.c-ai-panel__level {
  flex-shrink: 0;
  align-self: center;
}
.c-ai-panel__actions {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: calc(var(--spacing) * 2);
}
/* `reasons_label`（2026-09-22・ux-critic High②）。`reasons` が「AIの根拠」ではなく
 * 「AIに送った材料」であるときの前置き（AIを使った名寄せデモのみ渡す） */
.c-ai-panel__reasons-label {
  margin-top: calc(var(--spacing) * 3);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-text-muted);
}
/* 根拠は常に展開（§11 G11）。畳まない */
.c-ai-panel__reasons {
  display: grid;
  gap: calc(var(--spacing) * 2);
  margin-top: calc(var(--spacing) * 3);
}
/* `reasons_label` が在るときは、その直下に詰める（見出し→内容の関係を保つ） */
.c-ai-panel__reasons-label + .c-ai-panel__reasons {
  margin-top: calc(var(--spacing) * 1);
}
@media (min-width: 48rem) {
  .c-ai-panel__reasons { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.c-ai-panel__reason {
  display: flex;
  align-items: flex-start;
  gap: calc(var(--spacing) * 2);
}
.c-ai-panel__reason .c-match {
  flex-shrink: 0;
  margin-top: calc(var(--spacing) * 0.5);
}
.c-ai-panel__reason-text {
  font-size: var(--text-sm);
}
.c-ai-panel__caution {
  margin-top: calc(var(--spacing) * 3);
  border: var(--border-w) solid var(--color-warning-border);
  border-radius: var(--radius-md);
  background-color: var(--color-warning-bg);
  padding: calc(var(--spacing) * 2) calc(var(--spacing) * 3);
  font-size: var(--text-sm);
  color: var(--color-warning-fg);
}
.c-ai-panel__caution b {
  font-weight: 600;
}
/* 却下したあとの1行（role="status"）。ai-panel.js が切り替える */
.c-ai-panel__dismissed {
  display: flex;
  align-items: center;
  gap: calc(var(--spacing) * 3);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* AIを使った名寄せデモ（AI_MERGE_DEMO・既定 off・社内検証用）の確度（%）。
 * 決定84の例外（決定195・DESIGN.md §11-B 2026-09-22 追記）——このデモに限り、
 * ai_panel.html の confidence_percent を渡したときだけ描く。**バーは持たない**（数値のみ）。
 *
 * **2026-09-22（ux-critic High②の実測）**: 以前は c-level--high と同じ2トークン
 * （--color-ai-bg / --color-ai-fg）を流用しており、隣の「強さ区分」チップと
 * 背景色・文字色・太さ・サイズが完全に同一で見分けが付かなかった。**塗り（c-level）に
 * 対して枠線のみ**で色・形を分けた。
 *
 * **2026-09-22（後刻・ux-critic Med＋a11y-auditor High の再指摘で色を作り直した）**:
 * ⑴ ux-critic: 枠線を --color-info-* に変えたことで、**§5-B「--ai は AI が生成した
 * 内容にのみ使う」の意味論が逆転**した——パネル全体（紫の枠・AI の印）は規則由来の根拠を
 * 含んだまま紫を名乗るのに、真に AI 由来の確度だけが紫でなくなっていた。
 * ⑵ a11y-auditor: **--color-info-border 自体がほぼ見えていなかった**（実測 3件とも
 * 3:1 未達 —— 塗り〈白〉↔パネル背景 1.11:1／枠線↔塗り 1.49:1／枠線↔パネル背景 1.34:1）。
 * **--color-ai-border（#d5c2f4）も同じ理由で不採用**（パネル背景に対し 1.47:1・実測）。
 * **白地＋--color-ai-fg の枠線・文字**にした（実測: --color-ai-fg ↔ パネル背景 7.64:1、
 * ↔ 白地 8.47:1。いずれも 3:1 を大きく超える）。**新しいトークンは作っていない**
 * （既存の --color-ai-fg・--radius-md を流用） */
.c-ai-panel__confidence {
  flex-shrink: 0;
  align-self: center;
  display: inline-flex;
  align-items: baseline;
  gap: calc(var(--spacing) * 1);
  border: var(--border-w) solid var(--color-ai-fg);
  border-radius: var(--radius-md);
  padding: calc(var(--spacing) * 1) calc(var(--spacing) * 3);
  background-color: var(--color-white);
  font-size: var(--text-sm);
  white-space: nowrap;
  color: var(--color-ai-fg);
}
.c-ai-panel__confidence .num {
  font-size: var(--text-md);
  font-weight: 700;
}

/* 強さ区分（高／中／低）。確度（%）とバーは持たない（決定 84・§11-B）。
 * **例外は AIPanel の confidence_percent（上の .c-ai-panel__confidence）だけ**
 * —— この .c-level 自体は確度を持たない・バーを持たないままである */
.c-level {
  display: inline-block;
  border-radius: var(--radius-sm);
  padding: calc(var(--spacing) * 0.5) calc(var(--spacing) * 2);
  font-size: var(--text-2xs);
  font-weight: 700;
  white-space: nowrap;
}
.c-level--lg {
  padding: calc(var(--spacing) * 1) calc(var(--spacing) * 3);
  font-size: var(--text-md);
}
.c-level--high { background-color: var(--color-ai-bg);      color: var(--color-ai-fg); }
.c-level--mid  { background-color: var(--color-warning-bg); color: var(--color-warning-fg); }
.c-level--low  { background-color: var(--color-gray-100);   color: var(--color-gray-600); }
.c-level-caption {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--spacing) * 1);
  text-align: center;
}
.c-level-caption__text {
  font-size: var(--text-2xs);
  color: var(--color-text-muted);
}

/* 突合・検知根拠の印。色を持つのは same / sim / diff の3値だけ。single / empty は無彩色の面（§5-B3 の分岐表） */
.c-match {
  display: inline-block;
  border-radius: var(--radius-sm);
  padding: calc(var(--spacing) * 0.5) calc(var(--spacing) * 2);
  font-size: var(--text-2xs);
  font-weight: 600;
}
.c-match--same   { background-color: var(--color-success-bg); color: var(--color-success-fg); }
.c-match--sim    { background-color: var(--color-warning-bg); color: var(--color-warning-fg); }
.c-match--diff   { background-color: var(--color-danger-bg);  color: var(--color-danger-fg); }
.c-match--single,
.c-match--empty  { background-color: var(--color-gray-100);   color: var(--color-gray-600); }


/* ============================================================================
 * Stepper（web/components/crm/stepper.tsx）
 * ========================================================================== */
.c-stepper {
  display: flex;
  flex-direction: column;
  gap: calc(var(--spacing) * 1);
}
.c-stepper__bar {
  display: flex;
  gap: calc(var(--spacing) * 1);
}
.c-stepper__seg {
  flex: 1 1 0%;
  height: calc(var(--spacing) * 1);
  border-radius: var(--radius-sm);
}
.c-stepper__seg--done { background-color: var(--color-accent-nontext); }
.c-stepper__seg--todo { background-color: var(--color-gray-200); }
.c-stepper__seg--warn { background-color: var(--color-danger-fg); }
/* 中止は未着手と明度が近いので斜線を重ねる（base.css の .stripe-cxl と併用する） */
.c-stepper__seg--cxl  { background-color: var(--color-gray-300); }
/* キャンセル申請中（**W-7** / 判断モック **D17**・2026-09-17 の第5束）。**確定（中止）と読み分ける** ——
 * 代理店が申し出ただけで、キャリアの確定まで 12日かかった例がある。
 * 色は申込ステータスのチップと同じ `--color-entry-cxlreq-fg`（同じ段に2つ目の色を作らない）。
 * **斜線は重ねない**（`.stripe-cxl` は「中止」の印で、テンプレートが `cxl` の段にだけ付ける）。 */
.c-stepper__seg--cxlreq { background-color: var(--color-entry-cxlreq-fg); }
/* **その段の記録があるか**（台帳 **Y-8** の確定 ＝ Wiki 意思決定の記録 **155**・利用者判断・2026-09-17）。
 * **完了数（`done` / `total`）は1つも変えていない** —— 塗りも「N/M 完了」も今までどおりで、
 * **記録の無い段だけを破線にする**（開通日だけが入った行は「5/5 完了」のまま、工事日確定が破線になる）。
 * **色を足さない**（DESIGN.md §10「色だけで意味を伝えない」）—— 段の状態の色は `--seg--*` がそのまま持ち、
 * ここは**形（実線／破線）だけ**を変える。`transparent` の側は段の色がそのまま透ける。
 *
 * **縞は `--color-surface`（白）。`--color-gray-400` から替えた**（2026-09-17 の a11y レビュー **High**）——
 * **WCAG 1.4.11 の 3:1 に届いていなかった**。実測（画面担当が相対輝度を計算し直した値）:
 *   gray-400 と done の下地 teal-600 … **1.52:1**（不可）／ gray-400 と todo の下地 gray-200 … **1.96:1**（不可）
 *   **白と teal-600 … 3.69:1**（可）／ 白と danger-fg … 6.70:1（可）／ gray-900 と danger-fg … 2.65:1（不可）
 * **印が付くのは `done` の段だけ**になった（`_MARKED_STATES`）ので、**下地は teal-600 だけ** ＝ **3.69:1** である。
 * **契約カードには段名も丸も無く、破線が唯一の視覚的な担い手**なので、ここが届かないと弱視の人に何も残らない
 * （`sr-only` は目に見えず、1.4.11 にテキスト代替の免除は無い）。
 * **新しいトークンは作っていない** —— `--color-surface` と `--stripe-w` の再利用（Y-3 の確定と同じ作法）。
 *
 * **`data-recordable` は選ばない** —— 「まだ記録がない」と「記録する欄が無い」の区別は**語**が持つ
 * （`.c-stepper__no-column`）。見た目の語彙は2つのままにする（3つ目の印を作らない ＝ Y-8 の細部 ⑵）。 */
.c-stepper__seg[data-recorded="no"] {
  background-image: repeating-linear-gradient(
    90deg,
    transparent 0 var(--stripe-w),
    var(--color-surface) var(--stripe-w) calc(var(--stripe-w) * 2)
  );
}
/* 段名（棒の下。**なぜその段なのか**を読めるようにする・2026-09-17 の UX レビュー Med）。
 * 各段は棒のセグメントと同じ `flex: 1 1 0%` で、名前が対応するセグメントの真下に来る。
 * 状態は**色ではなく濃さ**で持つ（済んだ段は本文色、これからの段は控えめな色）。 */
.c-stepper__stages {
  display: flex;
  gap: calc(var(--spacing) * 1);
  margin: 0;
  padding: 0;
  list-style: none;
}
/* **折り返しを許す**（2026-09-17 の a11y レビュー High ＝ WCAG 1.4.4 Resize text）。
 * それまで `word-break: keep-all` を敷いており、**箱が縮んでも段名が縮まず、外へ溢れて隣に重なった**
 * （実測: 1024px で 2px・640px で 40px。**640px は 1280px を 200% ズームしたときの CSS ビューポート**で、
 * そこでは「申込込確認電話完了エントリー完了…」と潰れて判読できない）。
 * **省略記号は使わない**（内容が欠ける）。`overflow-wrap: anywhere` も要る ——
 * 禁則で行頭に置けない「ー」があり（「エントリー完了」）、`word-break: normal` だけでは
 * 割れない2文字の塊が残る。 */
.c-stepper__stage {
  flex: 1 1 0%;
  min-width: 0;
  font-size: var(--text-2xs);
  line-height: var(--leading-head);
  color: var(--color-text-muted);
  word-break: normal;
  overflow-wrap: anywhere;
}
.c-stepper__stage[data-state="done"] {
  color: var(--color-text);
  font-weight: 600;
}
.c-stepper__stage[data-state="warn"] { color: var(--color-danger-fg); }
/* **キャンセル側の2段は段名の行でも描き分ける**（2026-09-17 の a11y レビュー Low）。
 * 棒（`__seg--cxlreq` / `__seg--cxl` ＋ `.stripe-cxl`）は3つを描き分けているのに、
 * 段名の行は `cxlreq` も `cxl` も `todo` も同じ見た目で、**情報が落ちていた**。
 * 申請中は棒と同じ色（申込ステータスのチップと同じ `--color-entry-cxlreq-fg`。新しい色を作らない）、
 * 確定は**取り消し線** ＝ 棒に重ねる斜線（`.stripe-cxl`）の文字版である。 */
.c-stepper__stage[data-state="cxlreq"] { color: var(--color-entry-cxlreq-fg); }
.c-stepper__stage[data-state="cxl"] { text-decoration: line-through; }
/* **その段の記録があるか**を段名の頭の印でも描く（同じ Y-8）。**塗り ＝ 記録あり／白抜き ＝ 記録なし**で、
 * **色は当てない**（`currentColor` ＝ 段の状態が既に持っている色をそのまま使う。§10 は**形**が担う）。
 * **`content: ""` の擬似要素**なので読み上げには乗らない —— 語は同じ `<li>` の `sr-only`
 * （`（完了・記録なし）`）が持ち、**二重に読まれない**。
 * **印が描けない段（キャンセル ＝ Y-5 未決・再現中）には `data-recorded` が付かない**ので、印も出ない。 */
.c-stepper__stage[data-recorded]::before {
  content: "";
  display: inline-block;
  width: calc(var(--spacing) * 2);
  height: calc(var(--spacing) * 2);
  margin-right: calc(var(--spacing) * 1);
  border-radius: var(--radius-sm); /* 8px の正方形なので丸になる */
  vertical-align: middle;
}
.c-stepper__stage[data-recorded="yes"]::before { background-color: currentColor; }
/* 白抜き（記録なし）。`box-sizing: border-box`（base.css）なので外寸は塗りと同じ。
 * **枠の太さは `--stripe-w`（2px）** —— 棒の縞と同じ幅で、`calc(var(--spacing) * 0.5)` は使わない
 * （`.claude/rules/ui-tokens.md` の端数の許しは**コントロールの寸法**に限られ、擬似要素の印は当たらない）。 */
.c-stepper__stage[data-recorded="no"]::before {
  border: var(--stripe-w) solid currentColor;
}
/* **記録する欄がそもそも無い**ことを言う語（段名の直下）。**印ではない** ——
 * 見た目の語彙は塗り／白抜きの2つのままで、ここは**語**が足りない分を埋める
 * （2026-09-17 の UX レビュー Med。読み上げにしか無く、晴眼の人には1文字も届いていなかった）。
 * **段名より従属**させる（`--color-text-muted`。大きさは親の `--text-2xs` を継ぐ）。
 * **システム全体で工事日確定の1段だけ**に出るので、常駐の説明文にはならない。 */
.c-stepper__no-column {
  display: block;
  color: var(--color-text-muted);
  font-weight: 400;
}
.c-stepper__caption {
  font-size: var(--text-2xs);
  color: var(--color-text-muted);
}
.c-stepper__exceptions {
  margin-left: calc(var(--spacing) * 2);
  font-weight: 600;
  color: var(--color-warning-fg);
}


/* ============================================================================
 * KeyValueList ／ KeyValue（web/components/crm/key-value.tsx）
 * ========================================================================== */
.c-kv {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: calc(var(--spacing) * 2) calc(var(--spacing) * 4);
  font-size: var(--text-sm);
}
.c-kv--cols-1 {
  grid-template-columns: repeat(1, minmax(0, 1fr));
}
.c-kv__item {
  display: flex;
  gap: calc(var(--spacing) * 2);
}
.c-kv__item--wide {
  grid-column: 1 / -1;
}
.c-kv__label {
  flex-shrink: 0;
  width: calc(var(--spacing) * 24); /* sm = 96px（項目名が短い） */
  color: var(--color-text-muted);
}
.c-kv--label-md .c-kv__label {
  width: calc(var(--spacing) * 32); /* md = 128px（「エントリー完了日」など長い） */
}
.c-kv__value {
  flex: 1 1 0%;
  min-width: 0;
  font-weight: 600;
  overflow-wrap: break-word;
}
.c-kv__value--warning { color: var(--color-warning-fg); }
.c-kv__value--danger  { color: var(--color-danger-fg); }
/* 値が空 → 「—」。tone は効かせない（空に警告色を付けない） */
.c-kv__value--empty,
.c-kv__value--empty.c-kv__value--warning,
.c-kv__value--empty.c-kv__value--danger {
  font-weight: 400;
  color: var(--color-text-muted);
}


/* ============================================================================
 * Timeline ／ TimelineItem（web/components/crm/timeline.tsx）
 * ========================================================================== */
.c-timeline {
  display: flex;
  flex-direction: column;
  font-size: var(--text-sm);
}
/* 監査ログ。件数が多く読み流す前提なので1段細く */
.c-timeline--audit {
  font-size: var(--text-xs);
}
.c-timeline__item {
  display: flex;
  gap: calc(var(--spacing) * 3);
  border-bottom: var(--border-w) solid var(--border);
  padding-block: calc(var(--spacing) * 2);
}
.c-timeline__item:last-child {
  border-bottom-width: 0;
}
.c-timeline__date {
  flex-shrink: 0;
  width: calc(var(--spacing) * 24);
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-muted);
}
.c-timeline__who {
  flex-shrink: 0;
  width: calc(var(--spacing) * 16);
  font-weight: 600;
  color: var(--primary);
}
.c-timeline__body {
  flex: 1 1 0%;
  min-width: 0;
  overflow-wrap: break-word;
}
/* 名寄せ由来の記録（§11） */
.c-timeline__item--ai .c-timeline__body {
  font-weight: 600;
  color: var(--color-ai-fg);
}


/* ============================================================================
 * Pagination（web/components/crm/pagination.tsx）
 * ========================================================================== */
.c-pagination {
  display: flex;
  justify-content: center;
  gap: calc(var(--spacing) * 1.5);
  margin-top: calc(var(--spacing) * 4);
}
.c-pagination__cell {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: calc(var(--spacing) * 7);
  height: calc(var(--spacing) * 7);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface);
  padding-inline: calc(var(--spacing) * 2);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
a.c-pagination__cell:hover {
  border-color: var(--primary);
  color: var(--primary);
}
/* 端で押せない ‹ › */
.c-pagination__cell--disabled {
  color: var(--color-text-disabled);
}
/* 省略の「…」 */
.c-pagination__cell--gap {
  border-color: transparent;
}
.c-pagination__cell[aria-current="page"],
.c-pagination__cell[aria-current="page"]:hover {
  border-color: var(--primary);
  background-color: var(--primary);
  font-weight: 700;
  color: var(--color-white);
}


/* ============================================================================
 * Popover（web/components/layout/topbar.tsx の Popover を <details> 基盤で）
 *
 *   <details class="c-popover" data-popover>
 *     <summary class="c-popover__trigger" aria-label="通知 3件">…</summary>
 *     <div class="c-popover__panel" role="dialog" aria-label="通知">
 *       <h2 class="c-popover__title">通知</h2> …
 *
 * 開閉は <details> が持つ（JS なしでも開ける）。Esc で閉じてフォーカスを summary へ戻す・
 * 外側を押すと閉じる、は popover.js。
 * ========================================================================== */
.c-popover {
  position: relative;
}
.c-popover__trigger {
  display: flex;
  align-items: center;
  justify-content: center;
  width: calc(var(--spacing) * 7);
  height: calc(var(--spacing) * 7);
  border-radius: var(--radius-md);
  color: var(--color-text-muted);
  cursor: pointer;
  list-style: none;
}
.c-popover__trigger::-webkit-details-marker {
  display: none;
}
.c-popover__trigger:hover {
  background-color: var(--color-gray-100);
  color: var(--color-text);
}
.c-popover__trigger svg {
  width: calc(var(--spacing) * 4);
  height: calc(var(--spacing) * 4);
}
.c-popover__panel {
  position: absolute;
  top: calc(var(--spacing) * 8);
  right: 0;
  z-index: 40;
  width: var(--popover-w);
  overflow: hidden;
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-lg);
  background-color: var(--color-surface);
  box-shadow: var(--shadow-3);
}
.c-popover__title {
  border-bottom: var(--border-w) solid var(--border);
  background-color: var(--color-gray-50);
  padding: calc(var(--spacing) * 2) calc(var(--spacing) * 4);
  font-size: var(--text-sm);
  font-weight: 600;
}
.c-popover__body {
  display: flex;
  flex-direction: column;
  gap: calc(var(--spacing) * 2);
  padding: calc(var(--spacing) * 4);
  font-size: var(--text-sm);
}
.c-popover__footer {
  border-top: var(--border-w) solid var(--border);
  padding: calc(var(--spacing) * 3);
}
.c-popover__list > li {
  border-bottom: var(--border-w) solid var(--border);
}
.c-popover__list > li:last-child {
  border-bottom-width: 0;
}
.c-popover__item {
  display: flex;
  gap: calc(var(--spacing) * 2);
  padding: calc(var(--spacing) * 3);
  font-size: var(--text-sm);
}
a.c-popover__item:hover {
  background-color: var(--color-gray-50);
}
/* 通知の見出し（移植元 `<b className="block">`）と、補足の薄い文（`text-text-muted`） */
.c-popover__item-title {
  display: block;
}
.c-popover__muted {
  color: var(--color-text-muted);
}
.c-popover__empty {
  padding: calc(var(--spacing) * 4);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* 重大度の点。**色だけで意味を伝えない**ので、語（sr-only など）を必ず添える */
.c-dot {
  flex-shrink: 0;
  width: calc(var(--spacing) * 2);
  height: calc(var(--spacing) * 2);
  margin-top: calc(var(--spacing) * 1);
  border-radius: var(--radius-sm);
  background-color: var(--color-gray-400);
}
/* 1行の文と中心を揃えて並べる点（ダッシュボードのリンクの行）。既定は複数行の文の1行目に揃える上余白を持つ */
.c-dot--centered { margin-top: 0; }
.c-dot--danger  { background-color: var(--color-danger-fg); }
.c-dot--warning { background-color: var(--color-warning-fg); }
.c-dot--info    { background-color: var(--color-info-fg); }
.c-dot--ai      { background-color: var(--color-ai-fg); }


/* ============================================================================
 * Input ／ Label ／ Select ／ Checkbox（web/components/ui/{input,label}.tsx・search-panel.tsx）
 * ラベルは項目の上。必須・任意を両方明示する（.claude/rules/forms.md）
 * ========================================================================== */
.c-field {
  display: flex;
  flex-direction: column;
  gap: calc(var(--spacing) * 1);
}
.c-label {
  display: flex;
  align-items: center;
  gap: calc(var(--spacing) * 2);
  font-size: var(--text-sm);
  font-weight: 500; /* Tailwind 版 `font-medium`。§5-C とのずれは報告済み */
  line-height: 1;
  user-select: none;
}
.c-label__required {
  font-size: var(--text-2xs);
  color: var(--color-danger-fg);
}
.c-label__optional {
  font-size: var(--text-2xs);
  color: var(--color-text-muted);
}
/* 錠（代理店のシートが正である間は編集できない欄・2026-09-20）。**必須・任意の位置に置き換わる。**
   **色は意味を持つときだけ**（§2）—— これは失敗でも危険でもないので、注意の色を当てず、
   面だけを一段だけ起こして「印である」ことを示す（欄そのものは `.c-input[readonly]` の面で描かれる）。 */
.c-label__locked {
  font-size: var(--text-2xs);
  color: var(--color-text-muted);
  background-color: var(--color-gray-100);
  border-radius: var(--radius-sm);
  padding: 0 calc(var(--spacing) * 1);
}
/* 欄のまとまり（ラジオ・チェックボックスの fieldset）。枠と余白を消し、格子の中で縮めるようにする（2026-09-16） */
fieldset.c-field {
  margin: 0;
  border: 0;
  padding: 0;
  min-width: 0;
}
legend.c-label { padding: 0; margin-bottom: calc(var(--spacing) * 1); }
/* 欄の縦並び（flex の column）の中でも、ラジオの切替は中身の幅のまま（行いっぱいに伸ばさない） */
.c-field > .c-segmented { align-self: flex-start; }
/* チェックボックスの並び（見込み商材。2026-09-16） */
.c-field__options {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--spacing) * 2) calc(var(--spacing) * 4);
}
.c-field__option {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--spacing) * 1.5);
  font-size: var(--text-sm);
  cursor: pointer;
}
.c-field__hint {
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}
.c-field__error {
  font-size: var(--text-xs);
  color: var(--color-danger-fg);
}

.c-input {
  width: 100%;
  min-width: 0;
  height: var(--control-h-compact);
  border: var(--border-w) solid var(--input);
  border-radius: var(--radius-md);
  background-color: transparent;
  padding: calc(var(--spacing) * 1) calc(var(--spacing) * 2.5);
  font-size: var(--text-base);
  transition-property: color, background-color, border-color, outline-color;
  transition-timing-function: var(--ease-standard);
  transition-duration: var(--duration-colors);
}
/* Tailwind 版は `text-base md:text-sm`。48rem 以上では 12px になる */
@media (min-width: 48rem) {
  .c-input { font-size: var(--text-sm); }
}
/* 複数行（備考・商談記録の内容。2026-09-16）。高さは中身と rows に任せ、縦だけ伸縮できる */
.c-input--multiline {
  height: auto;
  min-height: calc(var(--spacing) * 16);
  padding-block: calc(var(--spacing) * 2);
  line-height: 1.6;
  resize: vertical;
}
/* ファイル選択（CSV取込。2026-09-17）。ブラウザ既定のボタンが欄の中に入るので、
   高さは中身なりにする（--control-h-compact のままだと OS によってボタンが切れる） */
.c-input--file {
  height: auto;
  padding-block: calc(var(--spacing) * 2);
  font-size: var(--text-sm);
}
/* 読み取り専用（権限が無い）。値は読める（opacity で薄めない・§10）。面だけ変えて入力できないことを伝える。
   **セレクタは `[readonly]` 属性で書く**（2026-09-17・a11y M2）—— `:read-only` 擬似クラスは
   HTML の仕様で `input[type=file]` にも一致するので、`c-input--file`（CSV取込の**編集できる**欄）が
   「権限が無くて入力できない」面で描かれていた。属性で見れば、実際に `readonly` を付けた欄だけに当たる。 */
.c-input[readonly] {
  background-color: var(--color-gray-50);
}
/* 1行に他の欄と並べる入力（詳細条件の値。幅は中身なり・字は常に sm） */
.c-input--inline {
  width: auto;
  font-size: var(--text-sm);
}
.c-input::placeholder {
  color: var(--color-text-placeholder);
}
.c-input:focus-visible,
.c-select:focus-visible {
  border-color: var(--ring);
  box-shadow: 0 0 0 var(--ring-w) color-mix(in oklab, var(--ring) 50%, transparent);
}
/* ネイティブの `disabled`（readonly を持てない欄だけ。file / checkbox）。
   **`opacity` で薄めない**（§10。gray-900 の 50% は白背景で AA 4.5:1 を割る）——
   2026-09-17 に `opacity: 0.5` を文字色に替えた（a11y M4）。面と文字色だけで「触れない」を伝える。 */
.c-input:disabled {
  pointer-events: none;
  cursor: not-allowed;
  background-color: var(--color-gray-50);
  color: var(--color-text-muted);
}
/* 入力の誤り。aria-invalid="true" を付けると枠が赤くなる（色だけでなく近くに文を出す・forms.md） */
.c-input[aria-invalid="true"],
.c-select[aria-invalid="true"] {
  border-color: var(--destructive);
  box-shadow: 0 0 0 var(--ring-w) color-mix(in oklab, var(--destructive) 20%, transparent);
}

.c-select {
  height: var(--control-h-compact);
  border: var(--border-w) solid var(--color-border-input);
  border-radius: var(--radius-md);
  background-color: var(--color-surface);
  padding-inline: calc(var(--spacing) * 2);
  font-size: var(--text-sm);
}

/* チェックボックスはネイティブのまま。面の色だけを主色に寄せる */
.c-checkbox {
  flex-shrink: 0;
  width: calc(var(--spacing) * 4);
  height: calc(var(--spacing) * 4);
  accent-color: var(--primary);
}


/* ============================================================================
 * 注記の3種
 *
 *   c-sample-note … 「顧客DBの内容ではない」の印（web/app/dashboard/page.tsx の SampleNote）。
 *                   文の持ち主は SAMPLE_*_NOTE（web/lib/api.ts → 移植後は Python 側の定数）
 *   c-dummy-note  … DUMMY_DATA_NOTE の告知（サイドバー下部）。**覆わない**（e2e/geometry.spec.ts が実測）
 *   c-state-note  … 状態を再現中であることの注記（StateSwitcher の note）
 * ========================================================================== */
.c-sample-note {
  margin-top: calc(var(--spacing) * 2);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}
.c-dummy-note {
  margin-top: auto;
  border-top: var(--border-w) solid var(--border);
  padding: calc(var(--spacing) * 3);
  font-size: var(--text-2xs);
  color: var(--color-text-muted);
}


/* ============================================================================
 * StateSwitcher（web/components/crm/state-switcher.tsx）。**開発用**。DEBUG のときだけ描く
 * ========================================================================== */
.c-state-switcher {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(var(--spacing) * 2);
}
.c-state-switcher__label,
.c-state-note {
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}
.c-state-switcher__link {
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-sm);
  padding: calc(var(--spacing) * 1) calc(var(--spacing) * 2);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}
.c-state-switcher__link:hover {
  background-color: var(--color-gray-100);
}
/* 6状態の列は aria-current="page"、別軸（⑥閲覧・__masters 等）は aria-current="true" */
.c-state-switcher__link:is([aria-current="page"], [aria-current="true"]),
.c-state-switcher__link:is([aria-current="page"], [aria-current="true"]):hover {
  /* Tailwind 版の選択中は枠線を持たない（border クラスが無い）。枠の 1px ぶん小さくなる点も含めて移した */
  border-width: 0;
  background-color: var(--primary);
  font-weight: 600;
  color: var(--color-white);
}


/* ============================================================================
 * Alert（web/app/login/login-form.tsx の `role="alert"` の枠）
 * ========================================================================== */
.c-alert {
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-md);
  background-color: var(--color-gray-50);
  padding: calc(var(--spacing) * 2) calc(var(--spacing) * 3);
  font-size: var(--text-sm);
}
.c-alert--danger {
  border-color: var(--color-danger-border);
  background-color: var(--color-danger-bg);
  color: var(--color-danger-fg);
}
/* **2026-09-17 追加**（W-5 / 判断モック D01）。申込ステータスの「確認が必要」——
   **失敗ではない**（保存は通っている）が、放っておくと古い段のまま運用される。
   `--danger` と同じ強さで出すと、保存に失敗したかのように読める。 */
.c-alert--caution {
  border-color: var(--color-warning-border);
  background-color: var(--color-warning-bg);
  color: var(--color-warning-fg);
}

