/* ============================================================================
 * FVJAPAN CRM — レイアウト（アプリシェル・ページの骨格・グリッド）
 *
 * 命名: `l-` 接頭辞（layout）。部品は components.css の `c-`。
 * 出典: web/components/layout/{app-shell,sidebar,topbar}.tsx と各 page.tsx の Tailwind クラス。
 * 寸法は docs/DESIGN.md §6（--sidebar-w 216px / --topbar-h 52px / --popover-w 320px）。
 *
 * **ブレークポイントだけは変数にできない**（CSS 変数は @media の条件に使えない）。
 * Tailwind v4 の既定値をそのまま rem で書く: sm = 40rem / md = 48rem / xl = 80rem。
 * 16px 基準で 640 / 768 / 1280px にあたる。xl が docs/DESIGN.md §6 の「最小想定幅 1280px」と同じ値である。
 * ========================================================================== */

/* ---- アプリシェル（AppShell）--------------------------------------------- */
.l-shell {
  position: relative;
  display: flex;
  min-height: 100vh;
}

/* サイドバー（Sidebar）。幅は --sidebar-w。スクロールしても残る */
.l-sidebar {
  position: sticky;
  top: 0;
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  width: var(--sidebar-w);
  height: 100vh;
  border-right: var(--border-w) solid var(--border);
  background-color: var(--color-surface);
}

.l-sidebar__brand {
  display: block;
  border-bottom: var(--border-w) solid var(--border);
  padding: calc(var(--spacing) * 4);
}
.l-sidebar__brand:hover {
  background-color: var(--color-gray-50);
}
.l-sidebar__brand-name {
  display: block;
  font-size: var(--text-lg);
  font-weight: 700;
  color: var(--color-teal-900);
}
.l-sidebar__brand-name-sub {
  color: var(--color-text);
}
.l-sidebar__brand-caption {
  display: block;
  font-size: var(--text-2xs);
  color: var(--color-text-muted);
}

.l-sidebar__nav {
  display: flex;
  flex-direction: column;
  gap: calc(var(--spacing) * 1);
  padding: calc(var(--spacing) * 2);
}

/* ナビ項目。現在地はサーバーがパスを見て aria-current="page" を付ける（e2e の DOM 契約） */
.l-sidebar__link {
  display: flex;
  align-items: center;
  gap: calc(var(--spacing) * 3);
  border-radius: var(--radius-md);
  padding: calc(var(--spacing) * 2) calc(var(--spacing) * 3);
  font-size: var(--text-base);
  font-weight: 600;
  color: var(--color-text-muted);
}
.l-sidebar__link:hover {
  background-color: var(--color-gray-100);
  color: var(--color-text);
}
.l-sidebar__link[aria-current="page"] {
  background-color: var(--color-primary-soft);
  color: var(--color-teal-900);
}
.l-sidebar__icon {
  flex-shrink: 0;
  width: calc(var(--spacing) * 4);
  height: calc(var(--spacing) * 4);
  color: var(--color-accent-nontext);
}
.l-sidebar__link-note {
  margin-left: calc(var(--spacing) * 1);
  font-size: var(--text-2xs);
  font-weight: 400;
}
.l-sidebar__badge {
  margin-left: auto;
}

/* Phase2 の区分名。<h2> にしない（見出し階層が本文の h1 より先に始まるため。sidebar.tsx の注記） */
.l-sidebar__group-label {
  padding: calc(var(--spacing) * 3) calc(var(--spacing) * 3) calc(var(--spacing) * 1);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: var(--tracking-wide);
  color: var(--color-text-muted);
}
.l-sidebar__group {
  display: flex;
  flex-direction: column;
  gap: calc(var(--spacing) * 1);
}
/* 予定の項目（リンクではない普通の文）。gray-400 まで薄くしない（2.43:1 で読めなくなる・§10） */
.l-sidebar__planned {
  display: flex;
  align-items: center;
  gap: calc(var(--spacing) * 3);
  border-radius: var(--radius-md);
  padding: calc(var(--spacing) * 2) calc(var(--spacing) * 3);
  font-size: var(--text-base);
  font-weight: 400;
  color: var(--color-text-muted);
  cursor: default;
}
.l-sidebar__planned .l-sidebar__icon {
  color: inherit;
}

/* 本文側の列（トップバー＋main） */
.l-shell__body {
  display: flex;
  flex: 1 1 0%;
  flex-direction: column;
  min-width: 0;
}

/* ---- トップバー（Topbar）------------------------------------------------- */
.l-topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: calc(var(--spacing) * 4);
  height: var(--topbar-h);
  border-bottom: var(--border-w) solid var(--border);
  background-color: var(--color-surface);
  padding-inline: calc(var(--spacing) * 6);
}

.l-breadcrumb {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.l-breadcrumb__list,
.l-breadcrumb__item {
  display: flex;
  align-items: center;
  gap: calc(var(--spacing) * 2);
}
.l-breadcrumb__current {
  font-size: var(--text-base);
  font-weight: 700;
  color: var(--color-text);
}

.l-topbar__actions {
  display: flex;
  align-items: center;
  gap: calc(var(--spacing) * 3);
  margin-left: auto;
}
/* 操作中テナント（F-61・決定205・決定208・2026-09-23）。#topbar-tenant-name は e2e の手掛かり */
.l-topbar__tenant {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-text);
}
.l-topbar__tenant-switch {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  text-decoration-line: underline;
  text-decoration-color: transparent;
}
.l-topbar__tenant-switch:hover,
.l-topbar__tenant-switch:focus-visible {
  text-decoration-color: currentColor;
}
/* #topbar-user-name は e2e がこの1要素だけを見る手掛かり（DOM 契約） */
.l-topbar__user {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.l-topbar__avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: calc(var(--spacing) * 7);
  height: calc(var(--spacing) * 7);
  border-radius: 50%; /* Tailwind `rounded-full`。正方形を円にする定型で、角丸3段の外 */
  background-color: var(--primary);
  font-size: var(--text-sm);
  font-weight: 700;
  color: var(--color-white);
}
/* 通知ボタンの件数 */
.l-topbar__bell {
  position: relative;
}
.l-topbar__bell-count {
  position: absolute;
  top: calc(var(--spacing) * -2);
  right: calc(var(--spacing) * -2);
  border-radius: var(--radius-sm);
  background-color: var(--color-danger-fg);
  padding-inline: calc(var(--spacing) * 1);
  font-size: var(--text-2xs);
  font-weight: 700;
  color: var(--color-white);
}

/* ---- 本文 ------------------------------------------------------------------
   id="main-content" はスキップリンクの行き先（e2e の DOM 契約）。 */
.l-main {
  flex: 1 1 0%;
  padding: calc(var(--spacing) * 6);
}

/* ============================================================================
 * 1280px（docs/DESIGN.md §6「最小想定幅」）の扱い
 *
 * **Tailwind 版は min-width を一切設定していない**（web/ を 1280 で grep して、画面の骨格には0件。
 * 出てくるのは customer-table / entry-table / search-panel の「1280px に収める」注記だけ）。
 * §6 の「それ未満では横スクロールを許容し、レイアウトを崩さない」は、
 * 各表の横スクロール（.c-table-wrap）と e2e/geometry.spec.ts の実測で担保されていた。
 * **ここでも min-width は足さない**（足すとスマホ閲覧（要件の非機能）の見え方が変わり、
 * それは移植ではなく仕様変更になる）。
 * ========================================================================== */

/* ---- ページの骨格 ----------------------------------------------------------
   <main> と余白はシェル側が持つ。ページの中で <main> を重ねない（landmark が2つになる）。 */
.l-page {
  display: flex;
  flex-direction: column;
  gap: calc(var(--spacing) * 4);
  width: 100%;
}

/* 見出し帯（h1 ＋ StateSwitcher 等） */
.l-page-header {
  display: flex;
  flex-direction: column;
  gap: calc(var(--spacing) * 2);
}
.l-page-title {
  font-size: var(--text-lg);
  font-weight: 600;
}
.l-page-title__sub {
  font-size: var(--text-sm);
  font-weight: 400;
  color: var(--color-text-muted);
}

/* 顧客詳細の見出しカード（web/app/customers/[id]/page.tsx の <header>） */
.l-detail-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(var(--spacing) * 4);
  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);
}
.l-detail-header__title {
  display: flex;
  align-items: center;
  gap: calc(var(--spacing) * 2);
  font-size: var(--text-lg);
  font-weight: 600;
}
.l-detail-header__meta {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.l-detail-header__tags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(var(--spacing) * 2);
}
.l-detail-header__actions {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: calc(var(--spacing) * 2);
  margin-left: auto;
}

/* 顧客詳細の4象限。**分割しない**（DESIGN.md §1-1「1画面で顧客の全体像」）。
   Tailwind 版は `grid grid-cols-2 gap-4` でブレークポイントを持たない */
.l-quadrants {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: calc(var(--spacing) * 4);
}

/* ダッシュボードの KPI 列（`grid gap-4 sm:grid-cols-2 xl:grid-cols-4`） */
.l-grid-kpi {
  display: grid;
  gap: calc(var(--spacing) * 4);
}
@media (min-width: 40rem) {
  .l-grid-kpi { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 80rem) {
  /* **枚数に依存しない**（2026-09-28）: 1行にカードの数だけ等幅の列を作る。本番で出所の無い
     「アラートあり顧客」を描かないと3枚になり（`views/dashboard.py` の `unsourced_visible`）、
     `repeat(4, …)` 固定では右に空きが残った */
  .l-grid-kpi { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); }
}

/* ダッシュボードの2段組（`grid gap-4 xl:grid-cols-2`） */
.l-grid-halves {
  display: grid;
  gap: calc(var(--spacing) * 4);
}
@media (min-width: 80rem) {
  .l-grid-halves { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* カードの並び（名寄せ一覧の `grid gap-4 md:grid-cols-2 xl:grid-cols-4`・見本の md:2 列） */
.l-grid-cards {
  display: grid;
  gap: calc(var(--spacing) * 4);
}
@media (min-width: 48rem) {
  .l-grid-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 80rem) {
  .l-grid-cards--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* ---- 汎用の並び（Tailwind の `flex flex-wrap items-center gap-N` の頻出形）----
   画面ごとに BEM を起こすほどでもない並びのために、gap を段で持つ。値はスケール内だけ。 */
.l-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(var(--spacing) * 2);
}
.l-row--gap-1 { gap: calc(var(--spacing) * 1); }
.l-row--gap-3 { gap: calc(var(--spacing) * 3); }
.l-row--gap-4 { gap: calc(var(--spacing) * 4); }
.l-row--gap-6 { gap: calc(var(--spacing) * 6); }
.l-stack {
  display: flex;
  flex-direction: column;
  gap: calc(var(--spacing) * 2);
}
.l-stack--gap-1 { gap: calc(var(--spacing) * 1); }
.l-stack--gap-3 { gap: calc(var(--spacing) * 3); }
.l-stack--gap-4 { gap: calc(var(--spacing) * 4); }
.l-row--end { justify-content: flex-end; }
.l-push-end { margin-left: auto; }

/* ---- 汎用の小道具（**画面をまたいで使う1行の型はここに1つだけ**）----------------------
   2026-09-14 の構造レビュー Med で、画面 CSS（screens/*.css）に同じ名前で中身の違う小道具
   （`.s-muted` が顧客画面では色だけ、ダッシュボードでは色＋字の大きさ）ができていたのを寄せた。
   **画面 CSS に汎用の小道具を作らない**（`api/tests/test_webui.py` の画面 CSS の検査が、画面の接頭辞の無い
   クラスと画面同士の名前の重複を落とす）。値はトークンだけ。
   **部品（`c-`）の見た目を上書きしない** —— このファイルは components.css より先に読むので、同じ詳細度では
   部品の宣言が勝つ。部品に要る差は components.css の修飾（`c-*--*`）で作る。 */
.l-mt-1 { margin-top: calc(var(--spacing) * 1); }
.l-mt-2 { margin-top: calc(var(--spacing) * 2); }
.l-mt-3 { margin-top: calc(var(--spacing) * 3); }
.l-mt-4 { margin-top: calc(var(--spacing) * 4); }
.l-block { display: block; }
.l-min0 { min-width: 0; }
.l-grow { flex: 1 1 0%; min-width: 0; }
.l-fill { width: 100%; }
/* 折り返し（表のセルは既定で折り返さない ＝ c-table__td。長い見出し・自由記述だけ折り返す） */
.l-wrap { white-space: normal; }
.l-nowrap { flex-wrap: nowrap; white-space: nowrap; }
/* グリッドの全列にまたがる（顧客詳細の下段の履歴・監査ログ） */
.l-span-all { grid-column: 1 / -1; }
/* 文字の色と太さ（**意味は語で運ぶ**。色だけで状態を伝えない・§10） */
.l-text { color: var(--color-text); }
.l-text-muted { color: var(--color-text-muted); }
.l-text-sm { font-size: var(--text-sm); }
.l-text-xs { font-size: var(--text-xs); }
.l-text-strong { font-weight: 600; }
.l-text-warning { color: var(--color-warning-fg); }
.l-text-danger { font-weight: 600; color: var(--color-danger-fg); }
.l-text-info { color: var(--color-info-fg); }
/* 補足の1行（小さく・薄く） */
.l-caption { font-size: var(--text-xs); color: var(--color-text-muted); }
/* 表の中の本文リンク（下線はホバーだけ） */
.l-link:hover { text-decoration-line: underline; }

/* ---- 見本ページ（/design）の骨格。業務画面では使わない ------------------------
   `mx-auto flex w-full max-w-6xl flex-col gap-8 p-6`。max-w-6xl は Tailwind v4 で 72rem。 */
.l-showcase {
  display: flex;
  flex-direction: column;
  gap: calc(var(--spacing) * 8);
  width: 100%;
  max-width: var(--width-showcase);
  margin-inline: auto;
  padding: calc(var(--spacing) * 6);
}
.l-showcase__header {
  display: flex;
  flex-direction: column;
  gap: calc(var(--spacing) * 1);
}
.l-showcase__row {
  display: flex;
  flex-direction: column;
  gap: calc(var(--spacing) * 3);
}
.l-showcase__row-head {
  display: flex;
  flex-direction: column;
  gap: calc(var(--spacing) * 1);
  border-bottom: var(--border-w) solid var(--border);
  padding-bottom: calc(var(--spacing) * 2);
}
.l-showcase__row-title {
  font-size: var(--text-md);
  font-weight: 600;
}
.l-showcase__row-note {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
/* 見本1つぶん（**どれが何の見本か画面から読める**ようにする・2026-09-17 の UX / a11y レビュー Low。
 * それまで進捗バーが5本並んで、違いを説明する文がテンプレートのコメントにしか無かった）。 */
.l-showcase__sample {
  display: flex;
  flex-direction: column;
  gap: calc(var(--spacing) * 2);
}
.l-showcase__sample-name {
  font-size: var(--text-2xs);
  color: var(--color-text-muted);
}
/* フォームの見本の幅（`max-w-md` = 28rem） */
.l-showcase__narrow {
  max-width: var(--width-form);
}
/* サイドバー下部の告知（margin-top: auto で下に寄る）を見本の中で再現する枠 */
.l-showcase__frame {
  display: flex;
  flex-direction: column;
  min-height: calc(var(--spacing) * 24);
}

/* ============================================================================
 * ログイン（web/app/login/page.tsx ＋ login-form.tsx）。シェル外。
 * 背景は**単色**（モックのグラデーションは §8 AI スロップ禁止リストに当たるので落とした・移植元の注記）
 * ========================================================================== */
.l-login {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(var(--spacing) * 6);
  min-height: 100vh;
  background-color: var(--color-teal-900);
  padding: calc(var(--spacing) * 6);
}
.l-login__card {
  width: 100%;
  max-width: var(--width-form);
  border-radius: var(--radius-lg);
  background-color: var(--color-surface);
  padding: calc(var(--spacing) * 8);
  box-shadow: var(--shadow-4);
}
/* ブランドは**見出しではない**（`<h1>` は画面の目的。a11y 監査 Med・2026-09-16）。装飾の1行として小さく置く */
.l-login__brand {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-text-muted);
}
.l-login__brand-mark {
  color: var(--primary);
}
.l-login__title {
  margin-top: calc(var(--spacing) * 1);
  font-size: var(--text-xl);
  font-weight: 700;
}
.l-login__caption {
  margin-top: calc(var(--spacing) * 1);
  margin-bottom: calc(var(--spacing) * 6);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.l-login__form {
  display: flex;
  flex-direction: column;
  gap: calc(var(--spacing) * 4);
}
.l-login__submit {
  width: 100%;
  margin-top: calc(var(--spacing) * 2);
}
/* 確認コードの画面（`login_code.html`）の副次の操作（再送・やり直し）。主 CTA の下に弱く並べる */
.l-login__aside {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: calc(var(--spacing) * 2);
  margin-top: calc(var(--spacing) * 4);
}
/* 再送のフォーム。待ちのあいだは、ボタンの下に理由（「あとN秒で再送できます。」）を出す */
.l-login__resend {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: calc(var(--spacing) * 1);
}
.l-login__resend-wait {
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}
/* 「届かないときは迷惑メールフォルダも」。**常設の1文**（失敗していなくても出る・UX レビュー Low） */
.l-login__hint {
  margin-top: calc(var(--spacing) * 3);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}
.l-login__footer {
  margin-top: calc(var(--spacing) * 6);
  border-top: var(--border-w) solid var(--border);
  padding-top: calc(var(--spacing) * 4);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}
.l-login__footer b {
  font-weight: 600;
}
.l-login__dev {
  width: 100%;
  max-width: var(--width-form);
  border-radius: var(--radius-lg);
  background-color: var(--color-surface);
  padding: calc(var(--spacing) * 3);
}
/* 開発用に出す確認コード（2026-09-18）。**製品の UI に見せない** —— 前後の行は状態切替と同じ
   `c-state-note`（小さい・控えめ）で、目立つのはコードの数字だけにする。
   数字は `--font-num`（`num`）で桁を読み違えにくくし、`<code>` に入れて選択しやすくする */
.l-login__dev-code {
  display: flex;
  align-items: baseline;
  gap: calc(var(--spacing) * 2);
  padding-top: calc(var(--spacing) * 1);
  padding-bottom: calc(var(--spacing) * 1);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.l-login__dev-code code {
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-sm);
  background-color: var(--color-gray-50);
  padding: calc(var(--spacing) * 1) calc(var(--spacing) * 2);
  font-size: var(--text-lg);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  color: var(--color-text);
  user-select: all; /* 1回の選択で6桁が丸ごと選べる（Computer Use・手の両方で読み取りやすい） */
}

/* ---- エラー画面（404 / 500 / CSRF）。シェル無しのときだけ中央の枠に入れる ---- */
.l-error-standalone {
  max-width: var(--width-prose);
  margin: calc(var(--spacing) * 12) auto;
  padding: calc(var(--spacing) * 6);
}
