/* =====================================================================
   Culminans シェルの共通スタイル（chaser の app.css から、シェル（レイアウト・ログイン・個人設定・
   ユーザー管理・メッセージ枠・アイコン）に関わる部分だけを抽出して移植したもの。
   モジュール固有のスタイルは各モジュールの wwwroot（_content/Culminans.Xxx/…）に置く。
   デザイントークン（--alt-*）はモジュールからも使ってよい（テーマは themes.css が上書きする）。
   ===================================================================== */

/* ===== デザイントークン（テーマ対応。themes.css が [data-theme] ごとに上書きする） =====
   ライトテーマの既定値。色を追加するときは、なるべく既存トークンを使い回すこと。 */
:root {
    /* 面（背景） */
    --alt-bg-body: #ffffff;          /* 本文エリアの背景 */
    --alt-bg-page: #f4f6f9;          /* 画面・パネルのうすい背景 */
    --alt-bg-subtle: #f7f9fc;        /* さらに薄い背景（ヘッダー行など） */
    --alt-bg-muted: #eef2f7;         /* ホバー・チップの背景 */
    --alt-surface: #ffffff;          /* カード・グリッドの面 */
    --alt-bg-primary: #ffffff;       /* サイドバー等の面（旧トークン。互換のため残す） */
    --alt-bg-secondary: #fafafa;

    /* 枠線 */
    --alt-border: #e3e8ef;
    --alt-border-strong: #cdd6e1;
    --alt-border-primary: #d4d4d4;
    --alt-border-secondary: #e5e5e5;

    /* 文字 */
    --alt-text-primary: #171717;
    --alt-text-body: #1f2933;
    --alt-heading: #2c3e50;
    --alt-text-strong: #3a4a5f;
    --alt-text-sub: #5b6b81;
    --alt-text-muted: #7a8ba6;
    --alt-text-secondary: #404040;
    --alt-text-secondary-hover: #262626;
    --alt-text-tertiary: #525252;
    --alt-text-placeholder: #737373;
    --alt-on-accent: #ffffff;        /* アクセント色・濃色の上に載せる文字 */
    --alt-tooltip-bg: #1f2933;       /* 絵だけのボタンの名札（2026-09-06） */
    --alt-tooltip-fg: #ffffff;

    /* アクセント（ブランド青） */
    --alt-brand: #1d4ed8;
    --alt-accent: #2c6fd9;
    --alt-accent-hover: #1a44c2;
    --alt-accent-weak: #4d7cc7;
    --alt-accent-soft: #eef4fd;      /* 選択・ホバーの薄青背景 */
    --alt-accent-soft-strong: #dbe8fb;
    --alt-nav-active-bg: var(--alt-accent-soft-strong);  /* サイドバーの現在位置。濃色サイドバーは themes.css で差し替える */
    --alt-nav-hover-bg: var(--alt-accent-soft);          /* 同・ホバー。現在位置より薄くして順位を付ける */
    --alt-nav-archived-bg: var(--alt-bg-muted);          /* 同・終わったもの（アーカイブ済み） */
    --alt-parent-issue-bg: #fdf9ec;  /* 親課題（子課題を持つ課題）のうす黄背景。選択の薄青と区別する */
    /* 横断検索で当たった語の光らせ方（ブラウザのページ内検索と同じ黄と橙。暗いテーマでも同じ色＝文字の色ごと決めて読めるようにする） */
    --alt-search-hit-bg: #ffe866;
    --alt-search-hit-current-bg: #ff9632;
    --alt-search-hit-text: #1a1a1a;

    /* 状態色 */
    --alt-danger: #d92c2c;
    --alt-danger-strong: #b00020;
    --alt-danger-text: #9b1c14;
    --alt-danger-bg: #fdf3f3;
    --alt-danger-border: #f0c2c2;
    --alt-success: #0b6b3a;
    --alt-success-text: #166534;
    --alt-success-bg: #f0faf4;
    --alt-success-border: #c2e6d2;
    --alt-warning-bg: #fff7e6;
    --alt-warning-border: #ffec99;
    --alt-warning-text: #8a6d00;
    /* 状態の札の色（2026-09-28・TEST1-250）。課題・やり取りの .alt-status-pill のほか、販売管理・ワークフロー・2 段階認証の札も使う（TEST1-251）＝値を変えると全部に効く。未対応は面のトークン（--alt-bg-muted）をそのまま使う */
    --alt-status-inprogress-bg: #dbeafe;
    --alt-status-inprogress-text: #1d4ed8;
    --alt-status-resolved-bg: #dcfce7;
    --alt-status-resolved-text: #15803d;
    --alt-status-closed-bg: #2f6f4f;
    --alt-status-closed-text: #ffffff;
    /* 販売管理・ワークフローの残りの札（TEST1-252）。値は置き換える前の直書きのまま＝ライトの見た目は変わらない。
       却下（赤）・差戻し（橙）・一部入金（黄）・下書き（灰・濃い字）・取消（灰・淡い字）・受付中（水色）・受注済などの途中の確定（紫） */
    --alt-status-rejected-bg: #fee2e2;
    --alt-status-rejected-text: #b91c1c;
    --alt-status-remanded-bg: #ffedd5;
    --alt-status-remanded-text: #c2410c;
    --alt-status-partial-bg: #fef3c7;
    --alt-status-partial-text: #b45309;
    --alt-status-draft-bg: #f3f4f6;
    --alt-status-draft-text: #374151;
    --alt-status-cancelled-bg: #f3f4f6;
    --alt-status-cancelled-text: #6b7280;
    --alt-status-accepting-bg: #e0f2fe;
    --alt-status-accepting-text: #0369a1;
    --alt-status-booked-bg: #ede9fe;
    --alt-status-booked-text: #6d28d9;
    /* お気に入りの★の選択中（2026-09-18）。明るい地にも暗い地にも乗る黄色なので、テーマごとに言い直さない。 */
    --alt-favorite: #f4b400;

    /* 既定のシンボル（リボンの C と竹ペンの星。2026-09-27 にブランドブックの採用ロゴへ改めた）。
       濃い地（ダーク・金碧珠・濃いカスタム色・アクセントのヘッダー）では白い C の版へ**差し替える**＝
       以前の brightness(0) invert(1) はラピスの濃淡と朱の星をまとめて白い塊にしてしまう
       （ブランドブック「濃い背景では白い C の版を使う」「星だけを別の色にしない」）。
       顧客のロゴ（Branding:LogoUrl）は BrandLogo が is-custom の印を付け、白抜きのフィルター（--alt-brand-custom-filter）はそちらにだけ効く。
       製品名が既定（Culminans）のときは、文字の代わりにリボンのワードマークを出す（BrandLogo の Wordmark）。
       **濃い地の場面は「いま使う絵」の 2 本（--alt-brand-symbol / --alt-brand-wordmark）を器の側で差し替える**＝
       シンボルとワードマークと顧客ロゴの白抜きが同じ規則で切り替わり、場面を足すときも 1 か所で済む。 */
    --alt-brand-symbol-on-light: url('img/culminans-symbol.svg');
    --alt-brand-symbol-on-dark: url('img/culminans-symbol-dark.svg');
    --alt-brand-wordmark-on-light: url('img/culminans-wordmark.svg');
    --alt-brand-wordmark-on-dark: url('img/culminans-wordmark-dark.svg');
    --alt-brand-symbol: var(--alt-brand-symbol-on-light);
    --alt-brand-wordmark: var(--alt-brand-wordmark-on-light);
    --alt-brand-custom-filter: none;

    /* ボタン */
    --alt-btn-primary-bg: #2c3e50;
    --alt-btn-primary-hover: #1f2d3a;

    /* 形状・影 */
    --alt-radius-sm: 6px;

    /* 押す・打つ部品の寸法（2026-09-10）。DevExpress の既定（SizeMode.Medium＝高さ 32px・角丸 4px）に素の input・select・
       枠つきの絵だけボタンを揃える＝ツールバーやフォームで隣に並んだとき上下と角が揃う。上限の幅は DevExpress のエディタと
       素の入力（.alt-input）が同じ値を読む＝片方だけ変えると同じフォームの中で右端が食い違う。
       **SizeMode.Small（24px）の一覧の操作列には触らない**（あちらは行の高さに合わせて意図して小さい）。 */
    --alt-control-height: 32px;
    --alt-control-radius: 4px;
    --alt-input-max: 360px;

    /* 画面の見出し（.page-title）の下の余白。見出しを行で包んで余白を行へ移す画面（Pm の PmProjectHead）も
       同じ値を読む＝写すと、ここを変えた日にその画面だけ古い余白のまま残る。 */
    --alt-page-title-gap: 0.9rem;

    /* 上部の帯（狭い画面の上部バーと、ヘッダーを持つレイアウトのヘッダー）の高さと、下のステータスバーの高さ。 */
    --alt-topbar-height: 56px;
    --alt-statusbar-height: 28px;

    /* ステータスバーの右上に浮かぶ「ページの先頭へ移動」（TEST1-149）の大きさと、画面の端・バーからの間。 */
    --alt-to-top-size: 40px;
    --alt-to-top-gap: 16px;
    /* 画面の下からバーとそのボタンの上までの高さ。**右下に浮かぶものを置く画面は、下端をこの 1 本で上へ逃がす**
       （Pm の課題一覧のウォッチ中パネル＝pm.css）＝置き方の式はここだけが持ち、使う側で組み直さない。
       --alt-sidebar-bottom を足すのは、フローティングではバーもその分だけ浮くため（layouts.css。ほかのレイアウトは 0）。 */
    --alt-to-top-clearance: calc(var(--alt-sidebar-bottom) + var(--alt-statusbar-height) + var(--alt-to-top-size) + var(--alt-to-top-gap) * 2);

    /* サイドバーが貼り付く上端と、下に空ける余白。既定は画面の端いっぱい。ヘッダーを持つレイアウト（layouts.css）が
       値を差し替える＝貼り付く位置と高さの式はここの 1 か所（.app-sidebar）だけで、レイアウトごとに書き直さない。 */
    --alt-sidebar-top: 0px;
    --alt-sidebar-bottom: 0px;

    /* 入力フォームの最大幅（2026-09-06・TEST1-61）。ダイアログ（.dialog-form）とページ直置きの
       入力（.alt-form-grid）が同じ値を読む＝どちらかだけ広い画面を作らない。A4 の紙面に収まる幅。 */
    --alt-form-max: 800px;
    /* カードの左右の余白（2026-09-23 に .alt-card から上げた）＝カードの幅の式（入力の上限＋余白＋枠線）を、
       カードの外に置いたボタン列も同じ 1 本の規則で読むため（.alt-card の「入力だけを持つカード」の規則）。 */
    --alt-card-pad: 1.25rem;
    --alt-radius-md: 8px;
    --alt-radius-xl: 12px;
    --alt-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.05);

    /* 浮かび上がる窓の影。**当てはまるのは「本文の上に重なって出る窓のうち、背後に実際に暗くする膜を
       持たないもの」**＝影だけが浮きを作る窓（膜を持つドロワーは下の .app-drawer のとおり別扱い）。
       **使う場所を並べない**＝窓を 1 つ足すたびにここへ書き足す契約になる（themes.css のテーマ名と同じ理由）。
       **1 本にまとめてある**＝以前は同じ綴りを複数か所へ写しており、暗色テーマの上書きが
       クラス名（.app-account-pop）に掛かっていたため、ほかの窓は暗いテーマでも薄い影のままだった
       （浮いて見えない。例外もログも出ない）。暗色は themes.css が同じ名前で強い値に差し替える
       ＝app.css が既定・themes.css が上書き、という --alt-shadow-xs と同じ流儀。 */
    --alt-shadow-pop: 0 8px 24px rgba(0, 0, 0, 0.14);

    /* サイドバーの幅。ドラッグで変更し、localStorage に記憶する（sidebar-resize.js）。
       値は <html> のインラインスタイルで上書きされる。 */
    --alt-sidebar-width: 220px;
    --alt-sidebar-width-min: 200px;
    --alt-sidebar-width-max: 480px;

    /* 横断検索の結果が吸着する幅（TEST1-101）。 */
    --alt-search-dock-width: 320px;

    /* AIに依頼のパネルが吸着する幅（TEST1-744）。入力画面を中に描くので検索の結果より広い。 */
    --alt-assist-dock-width: 420px;
}

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

/* 本文領域。ブラウザ幅にそのまま追随させる（一覧のグリッドを広い画面いっぱいに使うため）。
   以前は max-width: 1200px で中央寄せしていたが、ワイドモニタで左右が大きく余り、
   案件一覧の列が横スクロールに追いやられていたので上限を外した。 */
.container {
    margin: 1.75rem 0;
    padding: 0 1.5rem;
    width: 100%;
    box-sizing: border-box;
}

h1 { color: var(--alt-heading); }
h2 { color: var(--alt-heading); font-size: 1.15rem; margin-top: 1.5rem; }

/* 画面の見出し（全画面の <h1 class="page-title">）。ブラウザ既定の 2em は本文の中でいちばん大きな文字になり、
   カードの見出しやタブとの段差が付きすぎるので少し抑える（2026-09-10）。 */
.page-title {
    font-size: 1.55rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    margin: 0 0 var(--alt-page-title-gap);
}

#blazor-error-ui {
    display: none;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: var(--alt-warning-bg);
    padding: 0.6rem 1.25rem;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.9rem;
    top: 0.5rem;
}

/* ===== レイアウト（左サイドバー + 本文） ===== */
.app-shell {
    display: flex;
    align-items: stretch;
    min-height: calc(100vh / var(--alt-vz, 1));
}

.app-sidebar {
    flex: 0 0 var(--alt-sidebar-width);
    width: var(--alt-sidebar-width);
    /* 画面の高さに固定する（min-height ではない）。メニューが長くてもサイドバーは伸びず、
       はみ出す分は .app-tree の中だけでスクロールする＝本文とスクロールを分ける（2026-08-31 TEST1-48）。
       overflow は付けない＝アカウントのポップアップとフローティングメニューは
       サイドバーの外（left: calc(100% + 6px)）へ出るので、ここで切ると隠れる。
       上端と高さはトークンから組む（ヘッダーを持つレイアウトはトークンだけを差し替える。:root の doc）。 */
    height: calc(100vh / var(--alt-vz, 1) - var(--alt-sidebar-top) - var(--alt-sidebar-bottom));
    background: var(--alt-bg-primary);
    border-right: 1px solid var(--alt-border-secondary);
    padding: 20px 0;
    position: sticky;
    top: var(--alt-sidebar-top);
    align-self: stretch;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    box-sizing: border-box;
}

/* サイドバーの中身（ブランド・自分のアイコン・ベル・メニュー）。
   縦の flex にして余った高さをメニュー（.app-tree）へ渡す＝メニューだけがスクロールする。
   **下の .app-tree の指定と対で、通常幅のときだけ**＝狭い画面のドロワーはサイドバー自身がスクロールする作りで、
   ここで中身を縮めるとサイドバーが溢れなくなり、下のメニューに手が届かなくなる。 */
@media (min-width: 1025px) {
    .app-sidebar-main {
        display: flex;
        flex-direction: column;
        flex: 1;
        min-height: 0;
    }
}

/* サイドバー右端のつまみ（幅変更）。ダブルクリックで既定(220px)に戻る。 */
.app-sidebar-resizer {
    position: absolute;
    top: 0;
    right: -3px;
    width: 6px;
    height: 100%;
    z-index: 20;
    cursor: col-resize;
    background: transparent;
    touch-action: none;
}

/* モジュールが置く汎用のつまみ（Notes の目次の幅など）。置き方はモジュールが持ち、形と当てたときの色はここ 1 か所 */
.app-resizer {
    cursor: col-resize;
    touch-action: none;
    background: transparent;
}

.app-sidebar-resizer:hover,
.app-sidebar-resizer:focus-visible,
body.app-resizing .app-sidebar-resizer,
.app-list-dock-resizer:hover,
.app-list-dock-resizer:focus-visible,
body.app-resizing .app-list-dock-resizer,
.app-resizer:hover,
.app-resizer:focus-visible,
body.app-resizing .app-resizer {
    background: rgba(29, 78, 216, 0.35);
    outline: none;
}

/* ドラッグ中は本文を選択させない（クラス付与は sidebar-resize.js）。 */
body.app-resizing {
    cursor: col-resize;
    user-select: none;
}

.app-brand {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 20px;
    margin-bottom: 20px;
}

/* ブランドは正方形のシンボルと設定可能な製品名を横に並べる。 */
.brand-lockup {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    color: inherit;
}

.brand-product-name {
    min-width: 0;
    overflow: hidden;
    color: inherit;
    font-size: 15px;
    line-height: 22px;
    font-weight: 700;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 製品名が既定のときのワードマーク（リボンの Culminans）。viewBox は文字の外形に詰めてある（603×145）。
   文字そのものは読み上げ用に残し、見た目からだけ隠す（.visually-hidden）。 */
.brand-wordmark {
    flex: 0 0 auto;
    /* 下寄せ：シンボル（28px）の C の下端に文字の下端を揃える（Culminans に下へ伸びる字は無い） */
    align-self: flex-end;
    height: 22px;
    aspect-ratio: 603 / 145;
    background-image: var(--alt-brand-wordmark);
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
}

.app-brand-logo {
    display: inline-block;
    flex: 0 0 28px;
    width: 28px;
    height: 28px;
    background-image: var(--alt-brand-symbol);
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
}

.app-topbar-brand,
.app-sidebar-brand,
.app-mobile-brand {
    min-width: 0;
    color: var(--alt-text-primary);
    text-decoration: none;
}

.app-sidebar-brand {
    overflow: hidden;
}

/* DevExpress の DxTreeView（サイドバーのメニュー）。
   user-select: none は名前を押して開閉するときに、続けて押すとメニュー文字が
   選択反転しないようにするため（2026-08-10。当初はダブルクリック開閉のため）。 */
.app-tree {
    padding: 0 16px;
    overflow: hidden;
    user-select: none;
}

/* メニューだけを内側でスクロールさせる（2026-08-31 TEST1-48）。縦だけ開けるので、横は上の hidden のまま
   ＝下の white-space: nowrap と対。flex: 1 と min-height: 0 が無いと、中身の高さのまま伸びてサイドバーからはみ出す。
   **通常幅のときだけ**＝狭い画面（≦1024px）のサイドバーは幅固定のドロワーで、
   あちらは既にサイドバー自身がスクロールする（1 段のままにして、頼まれていない挙動を足さない）。 */
@media (min-width: 1025px) {
    .app-tree {
        flex: 1;
        min-height: 0;
        overflow-y: auto;
    }
}

/* サイドバーが狭くてもメニュー文字を折り返さない（Phase7）。
   DevExpress内部スタイル（CJKは単語中でも改行される）より優先させるため全要素に強制。
   はみ出しはクリップ（.app-tree の overflow:hidden）。 */
.app-tree,
.app-tree * {
    white-space: nowrap !important;
    word-break: keep-all !important;
    overflow-wrap: normal !important;
}

/* はみ出すノード文字は省略記号に（内部クラス名は推測。効かなくてもクリップは上記で担保） */
.app-tree .dxbl-text {
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

/* 階層のインデント。
   DxTreeView は展開アイコンの分だけ親の文字が右にずれるため、
   そのままだと子の方が左に見えてしまう。子側に余白を足して階層を揃える。
   もっと下げたい/戻したい場合は .alt-lv1 の padding-left を調整する。
   16px は子の開閉ボタンが親の文字の頭にそろう幅（2026-10-17・TEST1-740。40px では深く下がりすぎ、
   狭いサイドバーで子の名前がすぐ省略された）。 */
.app-tree .alt-lv0 {
    padding-left: 0;
}

.app-tree .alt-lv1 {
    padding-left: 16px;
}

/* 第1階層の並び替え（2026-08-31 TEST1-50。取り回しは wwwroot/js/nav-reorder.js）。
   掴めることはカーソルで見せる（ノードは DevExpress が描くので、DOM に印を足さずに済ませる）。
   DevExpress の内部指定に負けないよう、行の要素まで書いて特異度を上げる（§7 の現在位置の強調と同じ理由）。
   **通常幅のときだけ**＝JS も同じ幅でしか並べ替えを始めないので、狭い画面で掴めるように見せない。 */
@media (min-width: 1025px) {
    .app-tree li.alt-lv0 > div[class*="dxbl-"] {
        cursor: grab;
    }
}

.app-tree li.app-nav-dragging {
    opacity: 0.5;
}

/* 運んでいる間（クラス付与は nav-reorder.js）。つまみのドラッグ（body.app-resizing）と同じ作り。 */
body.app-nav-reordering {
    cursor: grabbing;
    user-select: none;
}

/* 落とし先の合図（このノードの手前／後ろ）。線は li の内側に引く＝配下の子ツリーごと囲まない。 */
.app-tree li.app-nav-drop-before > div[class*="dxbl-"] {
    box-shadow: inset 0 2px 0 0 var(--alt-accent);
}

.app-tree li.app-nav-drop-after > div[class*="dxbl-"] {
    box-shadow: inset 0 -2px 0 0 var(--alt-accent);
}

/* 第3階層（プロジェクト配下の 概要/課題/…、各グループの「設定」の枝の項目）。
   DxTreeView が階層分の余白（展開ボタン幅）を自前で付けるので、足すのは少しでよい
   （li の padding は入れ子で積み上がる＝第3階層は .alt-lv1 の 16px にこの 12px が重なる）。
   第3階層より深い項目も同じクラスで描く（NavMenu の Lv が lv3 で頭打ちにする）。 */
.app-tree .alt-lv2,
.app-tree .alt-lv3 {
    padding-left: 12px;
}

/* 終わったもの（アーカイブ済みのプロジェクトなど。NavMenuItem.Archived）。
   隠さずに淡く出す＝開けるが、動いているものと同じ濃さで並ぶと見分けられない。
   斜体は li に当てても DevExpress の内部指定に届かないので、テキスト要素へ直接当てる。
   **地色は下の「サイドバーのツリーの地色」に置いてある**＝DevExpress の既定を消す !important より
   後ろでないと、地色のほうが消える（2026-09-11）。 */
.app-tree .alt-nav-archived .alt-ico {
    opacity: 0.45;
}

li.alt-nav-archived > div .dxbl-text,
.app-flyout-item.alt-nav-archived {
    font-style: italic;
}

.app-flyout-item.alt-nav-archived {
    background: var(--alt-bg-muted);
    border-radius: var(--alt-radius-sm);
}

/* 項目の目印の色線（NavMenuItem.AccentColor。Pm のプロジェクトのヘッダーカラー）。
   色は項目ごとに違うので CSS クラスでは表せない＝NavMenu が --app-nav-accent に載せて渡す。
   ツリーは文字の直前（TextTemplate の中）、フローティングメニューは文字の手前の空要素。 */
.app-nav-accent {
    border-left: 3px solid var(--app-nav-accent);
    border-radius: 1px;
    padding-left: 6px;
}

.app-nav-accent-mark {
    flex: none;
    width: 3px;
    align-self: stretch;
    min-height: 1em;
    border-radius: 1px;
    background: var(--app-nav-accent);
    margin-left: -2px;
}

/* 画像アイコン（NavMenuItem.IconUrl が DxTreeViewNode.IconUrl に渡す img。Pm のプロジェクトアイコン）。
   DevExpress は大きさを指定しないので、そのままだと画像の原寸（100px）で出る。
   ほかのメニューアイコン（.alt-ico-sm）と同じ 16px に揃え、縦横比の違う画像でも崩れないよう cover で切り抜く。
   img.dxbl-image は DevExpress が生成する内部クラス（この img に自前の class を付けさせてもらえないための
   逃げ道）。版が上がって名前が変わると**サイドバーだけ原寸で出る**（CSS なので例外もログも出ない）ので、
   アイコンの見た目が急に大きくなったらここを疑うこと。フローティング側は自前の .app-flyout-ico。 */
.app-tree img.dxbl-image {
    width: 16px;
    height: 16px;
    border-radius: 4px;
    object-fit: cover;
}

/* 現在ページ・現在セクションのノード（DxTreeViewNode の CssClass で付与）。
   ツリーでは CssClass が li（＝子ツリーごと含む要素）に付くため、強調は「li 直下の行要素」
   （.dxbl-treeview-item-content）にだけ当てる。子ツリーは div ではない兄弟要素
   （dxbl-expandable-container）なので、この境界なら配下を巻き込まない。
   li 自身や子孫セレクタ（.alt-nav-active *）に当てると、グループが現在位置のときに
   配下の項目まで同じ色・太さになり、どの行が現在位置か分からなくなる（2026-08-24 実測）。
   太字は li に当てても DevExpress の内部指定に届かないので、テキスト要素へ直接当てる。 */
li.alt-nav-active > div {
    color: var(--alt-text-secondary-hover);
}

li.alt-nav-active > div .dxbl-text {
    font-weight: 600;
}

/* ---------- サイドバーのツリーの地色（2026-09-11） ----------
   DevExpress が既定で敷くホバーの薄いグレーを消して、テーマのトークンで塗り直す。消さないと、
   行にマウスを乗せるたびに灰色の帯が乗り、アクセント／フローティングのレイアウトでは
   現在位置のピルの上にも乗って、いま居る場所が灰色に覆われる。
   **内部クラス名に依存せず、ツリー配下の全要素に強制する**＝クラス名を当てにいくと、DevExpress の版が
   上がって名前が変わった日に黙って灰色が戻る（CSS なので例外もログも出ない）。
   :not(.dxbl-badge) は期限超過バッジ（赤）を残すため。落とし先の合図（app-nav-drop-before/after）は
   box-shadow なので巻き添えにならない。

   **色はトークンで持つ**（--alt-nav-hover-bg / --alt-nav-archived-bg / --alt-nav-active-bg。:root にある）
   ＝テーマごとの違いは themes.css の .app-sidebar でその 3 つを差し替えるだけで済み、下の選択子も
   順番も写さずに済む。以前はホバーと終わったものだけ濃色サイドバー側に規則ごと複製してあり、
   同じ色を 2 通りの書き方（トークンと直値）で持っていた。

   **順番が仕様**＝下の 3 つは詳細度が同じなので、入れ替えると症状が出る（どれも例外もログも出ない）。
   終わったものを透明化より前に置くと地色が !important に消され、ホバー・現在位置より後に置くと
   アーカイブ済みの行だけ光らない。現在位置をホバーより前に置くと、その行にマウスを乗せたとき化ける。
   ピル（アクセント／フローティング）はさらに後の layouts.css が !important で言い直す。 */
.app-tree [class*="dxbl-"]:not(.dxbl-badge) {
    background-color: transparent !important;
}

/* 角丸は状態によらず行 div へ 1 回だけ（地色が透明な行にも付くが見た目には出ない）。
   ピルにする形は layouts.css が 999px で言い直す。 */
.app-tree li[class*="dxbl-"] > div[class*="dxbl-"] {
    border-radius: var(--alt-radius-sm);
}

.app-tree li.alt-nav-archived > div[class*="dxbl-"] {
    background-color: var(--alt-nav-archived-bg) !important;
}

/* 敷くのは「li 直下の行要素」だけ＝li（dxbl-treeview-item）は子ツリーごと含むので、li に背景を付けると
   サブツリー全体が反転して見づらい（2026-08-10 実機フィードバック）。
   .dxbl-treeview-item-content は内部クラス名の推測なので、クラス名に依存しない構造セレクタも
   併記して保険にする（:hover は div 自身に当たったときのみ）。 */
.app-tree .dxbl-treeview-item-content:hover,
.app-tree li[class*="dxbl-"] > div:hover {
    background-color: var(--alt-nav-hover-bg) !important;
}

/* div に [class*="dxbl-"] を足してあるのは詳細度のため＝上の透明化はクラス 3 つで、素の
   `li.alt-nav-active > div`（クラス 1 つ）では !important 同士でも負けて何も塗られない
   （2026-08-24 実測。濃色サイドバーで強調が見えなかったのはこれが原因だった）。 */
.app-tree li.alt-nav-active > div[class*="dxbl-"] {
    background-color: var(--alt-nav-active-bg) !important;
}

/* ツリー以外（アイコンリストバー・フローティングメニュー）は要素全体を塗る。 */
:not(li).alt-nav-active {
    background: var(--alt-nav-active-bg);
    border-radius: var(--alt-radius-sm);
    font-weight: 600;
    color: var(--alt-text-secondary-hover);
}

/* Figma から書き出したアイコンSVG（wwwroot/icons/）。 */
.alt-ico {
    display: inline-block;
    width: 20px;
    height: 20px;
    background-repeat: no-repeat;
    background-position: center;
    background-size: 20px 20px;
    vertical-align: middle;
}

.alt-ico-home { background-image: url('icons/home-line.svg'); }
.alt-ico-star { background-image: url('icons/star-01.svg'); }

/* サイドメニューの子項目用アイコン（Phase7。少し小さく表示） */
.alt-ico-sm {
    width: 16px;
    height: 16px;
    background-size: 16px 16px;
}

.alt-ico-folder { background-image: url('icons/folder.svg'); }
.alt-ico-plus { background-image: url('icons/plus-circle.svg'); }
.alt-ico-eye { background-image: url('icons/eye.svg'); }
.alt-ico-board { background-image: url('icons/columns-03.svg'); }
.alt-ico-gantt { background-image: url('icons/gantt-bars.svg'); }
/* シフトのカレンダー（2026-10-02）。 */
.alt-ico-calendar { background-image: url('icons/calendar.svg'); }
.alt-ico-burndown { background-image: url('icons/trend-down.svg'); }
.alt-ico-wiki { background-image: url('icons/book-open.svg'); }
/* Pm の課題の一覧（2026-09-18）。プロジェクト配下の「課題一覧」が issues、横断の「課題（横断）」が list。
   **どちらもほかの名前と同じ画像だが名前を分ける**＝issues は master（Demo・様式・Shift の一覧・見出しの既定）と、
   list は table（Markdown の表・シフト表）と同じ絵で、意味が違うので片方の絵を替える日にもう片方まで替えたくない
   （操作列の絵と同じ理由）。issues はもとは file（file-04）で、使うのがここだけだったので絵ごと消した。
   **定義の無い名前は 16px の透明な枠になるだけ**で、例外もログも出ない＝list は 2026-08-27 に
   横断の一覧を足したときから Pm が名乗っていたのに定義が無く、絵の無い行がサイドバーに出ていた。 */
.alt-ico-issues { background-image: url('icons/rows-03.svg'); }
.alt-ico-list { background-image: url('icons/layout-grid-02.svg'); }
.alt-ico-users { background-image: url('icons/users-01.svg'); }
/* 組織のグループ（2026-10-10・NOTES-41）。ユーザー管理の絵（users-01＝2 人）と見分けるため、3 人の users-03（Share/icons の PNG）。 */
.alt-ico-users-03 { background-image: url('icons/users-03.png'); }
/* 共有メールボックス（2026-09-12）。macOS のメールと同じ形＝箱の口が V 字。
   単体は 1 つの受信箱（メニューの項目）、重なりは箱の集まり（モジュールの見出し＝「全受信」に当たる）。 */
.alt-ico-mailbox { background-image: url('icons/inbox-01.svg'); }
.alt-ico-mailboxes { background-image: url('icons/inbox-stack.svg'); }
/* 編集 edit と削除 delete（2026-09-05 に 2 つ同時に足し、2026-09-18 にここへ寄せた）。どちらも
   全モジュールのボタンと一覧の操作列が使う絵だが、借りる絵を探した先＝Markdown ツールバーの節に
   置かれていた。**同じ動詞の絵は 1 行だけ**＝足す前に `.alt-ico-` を grep して既にあるか見る。
   2 行あってもビルドも画面も通り、後ろが勝つので**片方を替えた日に何も変わらない**という形でだけ出る
   （編集は 2026-08-18 の pencil-01 と 2026-09-05 の edit-05 が 2 行あり、画面に出ていた edit-05 を残した）。 */
.alt-ico-edit { background-image: url('icons/edit-05.svg'); }
.alt-ico-delete { background-image: url('icons/delete.svg'); }
/* ごみ箱（消したものを置く場所。削除の操作の絵 alt-ico-delete とは別） */
.alt-ico-trash { background-image: url('icons/trash.svg'); }
/* コメントの引用（2026-08-08）。閉じ引用符「99」の形。16pxでも読み取れることを確認済み。 */
.alt-ico-quote { background-image: url('icons/quote.svg'); }
.alt-ico-window { background-image: url('icons/layout-top.svg'); } /* 簡易ビュー（カード/ウィンドウ風。Phase7） */

/* 入力欄の Markdown ツールバー（2026-08-28。Figma の alt-Template から書き出した Untitled UI のアイコン）。
   連番の箇条書きだけは元のセットに無いので、同じ書式（20x16・stroke 2）で自作した。 */
.alt-ico-bold { background-image: url('icons/bold-01.svg'); }
.alt-ico-italic { background-image: url('icons/italic-01.svg'); }
.alt-ico-strike { background-image: url('icons/type-strikethrough-01.svg'); }
.alt-ico-bullets { background-image: url('icons/dotpoints-01.svg'); }
.alt-ico-numbers { background-image: url('icons/list-numbered.svg'); }
.alt-ico-table { background-image: url('icons/layout-grid-02.svg'); }
.alt-ico-code { background-image: url('icons/brackets-ellipses.svg'); }
.alt-ico-link { background-image: url('icons/link-03.svg'); }

/*
    一覧（DxGrid・DxTreeList）の未読の行（受信ボックスのメール・文書データベースの文書。画面の CustomizeElement が付ける）。
    **行とセルの両方に当てる**＝DevExpress は tr ではなく td に font-weight を持っているので、
    tr だけを太字にしても見た目が変わらない。子選択子（>）にしないのは、
    版によって行と td のあいだに入れ物が挟まることがあるため（どちらも例外もログも出ない）。
*/
.alt-row-unread,
.alt-row-unread td {
    font-weight: 700 !important;
}

/* 一覧の操作列のアイコン（2026-09-05・TEST1-60）。**操作列のボタンは絵で揃える**ので、
   文字で並んでいた動詞のぶんだけ絵が要る。当てられる絵が既にあるもの（編集・削除・表示/非表示・
   リンク・割り当て）はそれを使い、無かった 5 つ（開く・複製・棄却・バーコード・取り下げ）は
   ほかと同じ書式（24x24・stroke 2・角丸）で足した。
   **同じ画像に別の名前を付けているのは意味が違うから**＝片方の絵を替える日に、もう片方まで
   替えたくない。この差分で 3 組ある＝admin（サイドバーの「管理」）と settings（行の設定を開く）、
   todo（Pm のメニュー）と check（確定・採用）、doc（Sales の伝票）と note（行のメモ）。 */
.alt-ico-open { background-image: url('icons/arrow-square-up-right.svg'); }
.alt-ico-copy { background-image: url('icons/copy-01.svg'); }
.alt-ico-close { background-image: url('icons/x-close.svg'); }
/* 横断検索（TEST1-101）。分離は「別の窓で開く」の絵、別ウィンドウは枠の中に小さな枠、
   吸着は右に枠のある割り付けの絵。 */
.alt-ico-search { background-image: url('icons/search-md.svg'); }
/* ステータスバーの表示倍率（2026-09-26。Untitled UI の zoom-out / zoom-in）。 */
.alt-ico-zoom-out { background-image: url('icons/zoom-out.svg'); }
.alt-ico-zoom-in { background-image: url('icons/zoom-in.svg'); }
.alt-ico-detach { background-image: url('icons/arrow-square-up-right.svg'); }
.alt-ico-popout { background-image: url('icons/picture-in-picture.svg'); }
.alt-ico-dock { background-image: url('icons/layout-right.svg'); }
/* 一覧を並べる入り切り（2026-09-29。DetailListControls。Untitled UI の columns-01＝中央で左右に割った枠）。 */
.alt-ico-split { background-image: url('icons/columns-01.svg'); }
.alt-ico-barcode { background-image: url('icons/barcode.svg'); }

.alt-ico-undo { background-image: url('icons/flip-backward.svg'); }
/* 版の履歴（2026-09-28。Pm の共有ファイル。Untitled UI の clock-rewind）。 */
.alt-ico-history { background-image: url('icons/clock-rewind.svg'); }
.alt-ico-check { background-image: url('icons/check-circle.svg'); }
.alt-ico-note { background-image: url('icons/file-05.svg'); }
.alt-ico-settings { background-image: url('icons/settings-01.svg'); }
.alt-ico-layout { background-image: url('icons/layout-top.svg'); }
.alt-ico-download { background-image: url('icons/file-download.svg'); }
.alt-ico-print { background-image: url('icons/printer.svg'); }
/* アーカイブとメールの署名・定型文（2026-09-21）。共有メールボックスの操作列が編集と削除の絵を借りていて、
   同じ行に同じ絵が 2 つずつ並んでいた。アーカイブは蓋付きの箱（package・folder は 16px で別の意味に読めた）、
   署名・定型文は文面の吹き出し（note とは分ける）。**mail-templates はメール専用**＝「テンプレート」は
   Forms・Workflow・Sales でも別の意味で使うので、汎用の名前にしない。 */
.alt-ico-archive { background-image: url('icons/archive.svg'); }
.alt-ico-mail-templates { background-image: url('icons/message-text-square-01.svg'); }
/* 迷惑メール（2026-10-03）。受信ボックスの「迷惑メール」のボタン。隣の「削除」（ごみ箱）と見分けるため禁止の印にした。 */
.alt-ico-spam { background-image: url('icons/slash-circle-01.svg'); }

/* 明細を編める表の並べ替え（2026-09-06・TEST1-60。Figma の alt-Template から）。
   **矢印ではなく山形**＝1 つ上・1 つ下へずらす操作で、行が飛んでいく矢印より近い。
   × は共通の close をそのまま使う。 */
.alt-ico-move-up { background-image: url('icons/chevron-up.svg'); }
.alt-ico-move-down { background-image: url('icons/chevron-down.svg'); }

/* ページの先頭へ移動（2026-09-18・TEST1-149）。**こちらは山形ではなく矢印**＝1 行ずらすのではなく
   先頭まで一度に飛ぶ操作なので、上の節の「行が飛んでいく矢印」がそのまま当てはまる。
   絵は arrow-left と同じ書式（24x24・stroke 2）で向きだけを変えて足した。 */
.alt-ico-to-top { background-image: url('icons/arrow-up.svg'); }

/* 操作が多すぎる一覧の「その他」（2026-09-06・TEST1-60）。**絵が 4 つを超えたら畳む**＝
   同じ大きさの絵が横に並ぶほど、どれが目当てか見分けるのに時間がかかる。
   残すのは「よく押すもの」だけで、残りはこの中へ入れる。 */
.alt-ico-more { background-image: url('icons/dots-horizontal.svg'); }

/* ボタンの絵（2026-09-10）。**動詞ごとに 1 つ**で、同じ動詞はどのモジュールでも同じ絵にする。
   付け方は `<DxButton IconCssClass="alt-ico alt-ico-sm alt-ico-xxx" …>`（Core の DialogButtons／GridToolbar／
   BackButton がこの表のとおりに付けており、各モジュールの定番の動詞（保存・キャンセル・追加・削除・編集・戻る・
   次へ・閉じる・印刷・確定・投稿）も同じ表で付けてある）。**新しい画面のボタンもこの表から選ぶ**＝
   同じ動詞に別の絵を当てると、押し慣れた絵が画面によって違う意味になる。
     保存 save ／ キャンセル・閉じる close ／ 追加・登録 add ／ 削除 delete ／ 編集 edit ／ 戻る back ／ 次へ next ／
     絞り込み filter ／ 表示項目 columns ／ 全て表示 refresh ／ 印刷 print ／ PDF download ／ 適用・確定 check ／
     投稿・送信 send ／ 開く open ／ 複製 copy ／ 書き出し export ／ その場で動き出す play-run（緑）／ アーカイブ archive
   **plus（丸つきの＋）はサイドバーの「新規◯◯」の行の絵**で、ボタンには使わない＝ボタンの「追加」は素の＋（add）。
   絵は Untitled UI の書式（24x24・stroke 2・角丸）。無かった 6 つ（save-01・plus・arrow-left・arrow-right・
   filter-lines・send-01）は同じ書式で足した。**columns は「表示項目」の意味で columns-03 を借りている**＝
   サイドバーの board（同じ絵）とは意味が違うので名前を分けてある（操作列の絵と同じ理由）。
   **この表が正**＝docs や部品のコメントには写さず、ここを指すだけにする。 */
.alt-ico-save { background-image: url('icons/save-01.svg'); }
.alt-ico-add { background-image: url('icons/plus.svg'); }
.alt-ico-back { background-image: url('icons/arrow-left.svg'); }
.alt-ico-next { background-image: url('icons/arrow-right.svg'); }
.alt-ico-filter { background-image: url('icons/filter-lines.svg'); }
.alt-ico-columns { background-image: url('icons/columns-03.svg'); }
.alt-ico-send { background-image: url('icons/send-01.svg'); }

/* DxButton の中の絵。DevExpress は IconCssClass を `<span class="dxbl-image …">` に載せ、文字との間隔を自前で持つが、
   その間隔は絵の大きさ（フォント基準）を前提にしている。背景画像の 16px に合わせて少しだけ空ける。 */
.dxbl-btn > .dxbl-image.alt-ico {
    flex: none;
    width: 16px;
    height: 16px;
    background-size: 16px 16px;
}

/* ワークフロー図の整列メニュー（2026-09-04・TEST1-55。Figma の alt-Template「Layout」から書き出した
   Untitled UI のアイコン）。**矢印つきの -01 系を採った**＝図形 2 つを並べた -02 系は、左揃え・中央・右揃えが
   16px では同じ絵に見えて選び分けられない。名前の horizontal / vertical は**寄せる向きではなく基準線の向き**
   （horizontal-centre は縦線へ左右から寄せる＝左右中央）なので、クラス名は画面の言葉に合わせてある。 */
.alt-ico-align-left { background-image: url('icons/align-left-01.svg'); }
.alt-ico-align-center-x { background-image: url('icons/align-horizontal-centre-01.svg'); }
.alt-ico-align-right { background-image: url('icons/align-right-01.svg'); }
.alt-ico-align-top { background-image: url('icons/align-top-01.svg'); }
.alt-ico-align-middle-y { background-image: url('icons/align-vertical-center-01.svg'); }
.alt-ico-align-bottom { background-image: url('icons/align-bottom-01.svg'); }
.alt-ico-distribute-x { background-image: url('icons/distribute-spacing-horizontal.svg'); }
.alt-ico-distribute-y { background-image: url('icons/distribute-spacing-vertical.svg'); }

/* 簡易ビューのツールバー（2026-08-28）。ウォッチ中は eye-off に差し替える＝押すと解除、が絵で読める。 */
.alt-ico-browser { background-image: url('icons/browser.svg'); }
.alt-ico-eye-off { background-image: url('icons/eye-off.svg'); }
.alt-ico-refresh { background-image: url('icons/refresh-cw-01.svg'); }
.alt-ico-attachment { background-image: url('icons/file-attachment-05.svg'); }

/* カスタムフォーム（2026-08-31。Figma の alt-Template から書き出した Untitled UI の code-browser）。
   画面から表を組み立てるモジュールなので、枠（browser）の中に山かっこが入った絵を当てる。
   もとは rows-03（alt-ico-master）で、ほかのモジュールの一覧と同じ絵だった。 */
.alt-ico-form { background-image: url('icons/code-browser.svg'); }

/* 入力欄の「添付」ボタン（2026-08-28）。クリップの形は簡易ビューの添付（file-attachment-05）と
   分けてある＝あちらは「この課題に付いているファイル」、こちらは「本文に添える」で意味が違う。 */
.alt-ico-paperclip { background-image: url('icons/paperclip.svg'); }

/* プライマリ（青）・デンジャー（赤）ボタン上のアイコンは白抜きに（アイコンSVGは黒ストロークのため。Phase7） */
.btn-primary .alt-ico,
.btn-danger .alt-ico,
.dxbl-btn-primary .alt-ico,
.dxbl-btn-danger .alt-ico {
    filter: invert(1);
}

/* ただしドロップダウンの項目は白抜きにしない（2026-09-04）。**DevExpress のメニュー項目は
   中身が dxbl-btn-primary クラスを持つ**（見た目は白地に黒文字なのに）ので、上の規則が誤爆して
   アイコンが白い線になり、白い背景の上で完全に見えなくなる。要素も背景画像も正しいまま
   色だけが消えるので、例外もログも出ない。
   **暗いテーマの反転（themes.css の html[data-theme="dark"] .alt-ico）はこれより詳細度が高いので残る**
   ＝暗い背景では白いままで正しい。打ち消したいのは上の 1 つだけなので、ここは !important にしないこと。 */
.dxbl-btn-dropdown-item .alt-ico {
    filter: none;
}

/* 枠だけのボタン（`RenderStyleMode.Outline`）に面を敷く（2026-09-12）。
   DevExpress の既定は背景が透明で、**背景の線画（motifs.css）を敷いたテーマでは柄が
   ボタンの中を通る**。押せるものに見えず、絵だけのボタンでは特に読み取れない。

   **DevExpress のテーマ変数を差し替える**（内部のクラス名を狙わない）＝あちらは
   ふつうの状態・ホバー・押下・無効でそれぞれ別の変数を読む作りなので、
   これ 1 本で「ふつうのときだけ」に当たる。実測で、変数を置くだけで白く塗れ、
   ホバーでは DevExpress の色に戻る。
   クラス名を `[class*=…]` で狙うと、状態を自分で除く必要があるうえ
   （無効なボタンまで有効に見える・トグルの押下は `:active` では外れない）、
   版が変わって名乗りが違えば黙って効かなくなる（docs/claude/pitfalls.md）。
   **枠と文字の色は触らない**＝危険・主要といった意味づけは DevExpress のままにしておく。 */
.dxbl-btn {
    --dxbl-btn-outline-bg: var(--alt-surface);
}
.alt-ico-data { background-image: url('icons/bar-chart-square-02.svg'); }
.alt-ico-master { background-image: url('icons/rows-03.svg'); }
/* パスワード変更（2026-09-12）。**伏字の入力欄の絵にした**＝それまでの settings-01 は歯車で、
   管理画面の設定と同じものが出ていた。 */
.alt-ico-password { background-image: url('icons/password-01.svg'); }
/* プロフィール（2026-09-12）。**一人の絵にした**＝users-01 は複数人で、
   ユーザー管理（ほかの人も含む一覧）と同じものが「自分のプロフィール」に出ていた。 */
.alt-ico-user { background-image: url('icons/user-01.svg'); }
/* 言語（2026-09-12）。**地球儀にした**＝それまでの rows-03 は「一覧」の絵で、
   ほかのモジュールの一覧と同じものが個人設定の「言語」に出ていた。 */
.alt-ico-globe { background-image: url('icons/globe-01.svg'); }
/* ログアウト（2026-09-12）。**ドアから出る絵にした**＝それまでの import-export は
   管理画面の「入出力」を指す絵で、データの出し入れと取り違える。 */
.alt-ico-logout { background-image: url('icons/log-out-01.svg'); }
/* Import/Export: ユーザー提供の cloud-download / cloud-upload を合成した自作アイコン（2026-08-07）。
   旧: upload-01.svg（上向き矢印のみで取込み側が表せていなかった）。 */
.alt-ico-transfer { background-image: url('icons/import-export.svg'); }
/* 詳細と一覧の左右の入れ替え（2026-09-26。Untitled UI の switch-horizontal-01。利用者の指定）。 */
.alt-ico-swap { background-image: url('icons/switch-horizontal-01.svg'); }
/* フォームのレコードの入出力（2026-09-02。CUL1-38。Untitled UI の upload-cloud-02 / download-cloud-02）。
   **1 つの絵（alt-ico-transfer）で兼ねない**＝あちらは管理画面の「入出力」という 1 つの機能を指すが、
   こちらは取り込みと書き出しが別のボタンとして並ぶので、向きの違う絵でないと押し分けられない。 */
.alt-ico-import { background-image: url('icons/upload-cloud-02.svg'); }
.alt-ico-export { background-image: url('icons/download-cloud-02.svg'); }
/* Figmaの「管理」はOpsgenieのブランドロゴ。単体で書き出せなかったため同じアイコンセットの歯車を使用。 */
.alt-ico-admin { background-image: url('icons/settings-01.svg'); }
/* 全体通知（Phase8。2026-08-11）。拡声器。既存アイコンセットに無かったため同じ線幅・角丸で自作。 */
.alt-ico-megaphone { background-image: url('icons/announcement-01.svg'); }
/* ---- 販売・購買・在庫の絵（2026-08-26。Figma の alt-Template / Icons から取得）----
   もとは filter-lines を請求、bar-chart を入金、rows-03 を在庫に当てていた＝手元にある絵で間に合わせた状態で、
   絵と意味が合っていなかった。売り買いで対応する伝票は同じ絵にする（見積と発注、請求と仕入請求）。 */
/* Slack 連携（本人のアカウント紐付け）。 */
.alt-ico-route { background-image: url('icons/route.svg'); }

/* Slack のマーク（単色）。Figma のセットには入っていないので Bootstrap Icons（MIT）から取り、
   ほかのアイコンと同じ 24x24 の枠に揃えてある。**塗りのアイコンなので線幅は合わせられない**
   ＝ロゴは形が決まっていて描き直せない（商標）。 */
.alt-ico-slack { background-image: url('icons/slack.svg'); }
/* 組織管理は dataflow-01 を 270 度回したもの（縦の階層図を横向きの組織図として使う）。SVG 側で回してあるので
   CSS の transform は要らない＝背景画像は transform で回せない。 */
.alt-ico-org { background-image: url('icons/dataflow-01-rotate270.svg'); }
/* 帳票レイアウト（用紙の四隅と余白）。 */
.alt-ico-layout-dots { background-image: url('icons/grid-dots-outer.svg'); }
/* プロジェクト管理（製図コンパス）。folder は配下の「プロジェクト」「ファイル」が使い続ける。 */
.alt-ico-compass { background-image: url('icons/compass.svg'); }
.alt-ico-bag { background-image: url('icons/shopping-bag-03.svg'); }
.alt-ico-cart { background-image: url('icons/shopping-cart-01.svg'); }
.alt-ico-doc { background-image: url('icons/file-05.svg'); }
.alt-ico-receipt { background-image: url('icons/receipt.svg'); }
.alt-ico-file-check { background-image: url('icons/file-check-02.svg'); }
.alt-ico-chart-breakout { background-image: url('icons/chart-breakout-square.svg'); }
.alt-ico-receipt-check { background-image: url('icons/receipt-check.svg'); }
.alt-ico-coins { background-image: url('icons/coins-hand.svg'); }
.alt-ico-package { background-image: url('icons/package.svg'); }
.alt-ico-package-check { background-image: url('icons/package-check.svg'); }
.alt-ico-package-plus { background-image: url('icons/package-plus.svg'); }
.alt-ico-clipboard-check { background-image: url('icons/clipboard-check.svg'); }
.alt-ico-database { background-image: url('icons/database-01.svg'); }
.alt-ico-tag { background-image: url('icons/tag-01.svg'); }

/* 情報（お知らせの既定。発信元のモジュールが分からないとき）。既存セットに無かったため自作。 */
.alt-ico-info { background-image: url('icons/info-circle.svg'); }
.alt-ico-ai { background-image: url('icons/stars-02.svg'); }
.alt-ico-todo { background-image: url('icons/check-circle.svg'); }
/* ワークフロー（Phase10。2026-08-12）。既存セットに無かったため同じ線幅・角丸で自作したフロー図。 */
.alt-ico-flow { background-image: url('icons/dataflow-03.svg'); }
/* 運用管理の台帳の操作（2026-09-10）。電源の起動／停止、解約（凍結）と再開。既存セットに無かったため
   同じ線幅・角丸で自作（Untitled UI の power-01 / pause-circle / play-circle の形）。 */
.alt-ico-power { background-image: url('icons/power-01.svg'); }
.alt-ico-pause { background-image: url('icons/pause-circle.svg'); }
.alt-ico-play { background-image: url('icons/play-circle.svg'); }

/* 実行（緑）＝押すとその場で動き出すもの（運用管理の「最新版配布」）。play と同じ絵だが、
   **色で意味を分ける**ので名前も分ける（columns と board が同じ絵で名前が違うのと同じ理由）。
   **マスクで塗る**のは background-image の SVG が色を継承しないため＝同じ技法の前例が
   .alt-notif-kind::before。暗いテーマの反転は themes.css 側で外してある（塗った緑まで反転するため） */
.alt-ico-play-run {
    background-color: var(--alt-success-text);
    -webkit-mask: url('icons/play-circle.svg') center / contain no-repeat;
    mask: url('icons/play-circle.svg') center / contain no-repeat;
}

/* 「自分のアイコン」の置き場（Phase7・2026-08-07 以降はアイコン1つだけを常駐させる）。
   パスワード変更・2段階認証・ログアウトはアイコンのポップアップから個人設定へ入る。
   2026-08-09: サイドバー最下部（.app-sidebar-footer）から、お知らせベルの上へ移動。 */
.app-sidebar-account {
    padding: 0 12px;
    margin-bottom: 10px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* ---- 常駐アカウントアイコン（AccountMenu.razor） ---- */
.app-account {
    position: relative;
    width: 100%;
}

.app-account-btn {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    box-sizing: border-box;
    padding: 8px;
    border: 1px solid var(--alt-border-secondary);
    border-radius: var(--alt-radius-xl);
    background: none;
    text-align: left;
    cursor: pointer;
}

.app-account-btn:hover,
.app-account.is-open .app-account-btn {
    background: var(--alt-bg-secondary);
}

.app-account-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.app-account-name {
    font-size: 14px;
    line-height: 20px;
    font-weight: 600;
    color: var(--alt-text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.app-account-role {
    font-size: 12px;
    line-height: 18px;
    color: var(--alt-text-tertiary);
    white-space: nowrap;
}

/* ショートカットのポップアップ。2026-08-09 にアカウントをサイドバー上部へ移したため
   下方向（top 基準）に開く（以前は最下部だったので上方向だった）。
   見た目はアイコンバーのフローティングメニュー(.app-flyout)と揃えている。 */
.app-account-pop {
    position: absolute;
    left: 0;
    top: calc(100% + 6px);
    z-index: 60;
    min-width: 220px;
    padding: 8px;
    background: var(--alt-bg-primary);
    border: 1px solid var(--alt-border-secondary);
    border-radius: var(--alt-radius-md);
    box-shadow: var(--alt-shadow-pop);
}

/* 見出しのフローティングのメニュー（.alt-float-title-items）も同じ項目を使う。**字体はここで継ぐ**＝ボタンは字体を継がない
   （アカウントの項目は .linklike でも継いでいるが、メニューの項目に .linklike を付けると隣り合う項目に余白が付く）。 */
.app-account-pop .app-flyout-item,
.alt-float-title-items .app-flyout-item {
    width: 100%;
    box-sizing: border-box;
    border: none;
    background: none;
    font-family: inherit;
    cursor: pointer;
    text-align: left;
}

.app-account-pop-sep {
    height: 1px;
    margin: 6px 2px;
    background: var(--alt-border-secondary);
}

/* ポップアップを本文より手前に出すため、サイドバー自体を持ち上げる。
   （position:sticky の .app-sidebar はスタッキングコンテキストを作るので、
     中の z-index だけ上げても DevExpress の sticky ヘッダー等に負ける。
     モバイルのドロワー(50)より低くしてあるので、狭い画面の挙動は変わらない） */
@media (min-width: 1025px) {
    .app-sidebar {
        z-index: 40;
    }
}

.app-body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    background: var(--alt-bg-primary);
}

/* 本文は余った高さを取る＝中身が短い画面でもステータスバーが下に着く。 */
.app-body > main.container {
    flex: 1 0 auto;
}

/* ===== フッター＝ステータスバー（2026-09-10。実体は Components/Layout/StatusBar） =====
   本文の下に貼り付く 1 行。左に版と環境、右に利用者と時刻。文字は小さく、地は薄い面で本文と区切る。
   狭い画面でも出す（高さ 28px）。フローティングではカードにする（layouts.css）。 */
.app-statusbar {
    position: sticky;
    bottom: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    gap: 14px;
    min-height: var(--alt-statusbar-height);
    padding: 0 14px;
    box-sizing: border-box;
    font-size: 0.76rem;
    line-height: 1.2;
    color: var(--alt-text-sub);
    background: var(--alt-bg-subtle);
    border-top: 1px solid var(--alt-border);
}

.app-statusbar-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}

.app-statusbar-product {
    font-weight: 600;
    color: var(--alt-text-strong);
}

.app-statusbar-version {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    color: var(--alt-text-muted);
}

/* **バーの幅が足りないときは製品名だけを縮めて「…」で切る**（2026-09-17）＝項目はどれも nowrap で縮まないので、
   幅が足りないと**どの画面もページごと横へスクロールした**（開発環境の 375px で 388px。実測）。
   製品名は顧客ごとの設定（`Branding:ProductName`）で長さが読めないので、幅の線で逃がすのではなく
   縮められる作りにする。版・環境・時刻は短く、切ると読めなくなるので縮めない。 */
.app-statusbar-brand,
.app-statusbar-product {
    min-width: 0;
}

.app-statusbar-product {
    overflow: hidden;
    text-overflow: ellipsis;
}

.app-statusbar-spacer {
    flex: 1;
}

/* 画面からのお知らせ（TEST1-134。書き込むのは wwwroot/js/status-message.js）。出すときだけ見える。
   **縮められる作りにする**＝製品名と同じ理由で、長い文言でもページを横へはみ出させない（項目の inline-flex だと
   文字が匿名の子になり「…」が効かないので、ここは block で切る）。 */
.app-statusbar-message {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--alt-text-strong);
    opacity: 0;
}

.app-statusbar-message.is-visible {
    opacity: 1;
}

/* 薄れて出て薄れて消える（動きを減らす設定のときは切り替えるだけ。`.app-to-top` と同じ流儀）。 */
@media (prefers-reduced-motion: no-preference) {
    .app-statusbar-message {
        transition: opacity 0.2s ease;
    }
}

.app-statusbar-clock {
    font-variant-numeric: tabular-nums;
}

/* 狭い画面では利用者を落とす（版・環境・時刻だけ）。 */
@media (max-width: 720px) {
    .app-statusbar-user {
        display: none;
    }
}

/* スマホの幅では時刻も落とす（2026-09-17）＝端末自身が画面の上に時刻を出しているので、
   その幅を製品名に回す（はみ出さないことは上の `.app-statusbar-brand` が守る。これは優先順位の判断）。
   **お知らせ（`.app-statusbar-message`）が出ているあいだは製品名も伏せる**（TEST1-134）
   ＝短い文でも入りきらず、途中で切れて読めない。版と環境は短いうえ、消すと画面の取り違えに効かなくなるので残す。 */
@media (max-width: 640px) {
    .app-statusbar-clock {
        display: none;
    }

    .app-statusbar:has(.app-statusbar-message.is-visible) .app-statusbar-product {
        display: none;
    }
}

/* ===== 表示倍率（2026-09-26。実体は StatusBar、当てる・覚えるのは wwwroot/js/zoom.js） =====
   − [100%] ＋ を 1 つのまとまりにし、右の区切り線（.app-statusbar-separator）でお問合せと分ける。
   ボタンは枠を持たず、当てたときだけ面を付ける（お問合せの枠付きの押しボタンと見分ける）。 */
.app-statusbar-zoom {
    display: inline-flex;
    align-items: center;
    gap: 2px;
}

.app-statusbar-zoom button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 22px;
    padding: 0 4px;
    font: inherit;
    color: var(--alt-text-strong);
    background: transparent;
    border: 0;
    border-radius: 4px;
    cursor: pointer;
}

.app-statusbar-zoom button:hover:not(:disabled) {
    background: var(--alt-bg-primary);
}

.app-statusbar-zoom button:disabled {
    cursor: default;
    opacity: 0.4;
}

/* 数字は桁が変わっても幅を動かさない（押すたびに ＋ の位置がずれない） */
.app-statusbar-zoom-value {
    min-width: 3.4em;
    font-variant-numeric: tabular-nums;
}

.app-statusbar-separator {
    align-self: center;
    width: 1px;
    height: 16px;
    background: var(--alt-border);
}

/* スマホの幅では出さない＝端末の拡大（2 本指）があり、バーの幅は製品名に回す（時刻と同じ判断）。 */
@media (max-width: 640px) {
    .app-statusbar-zoom,
    .app-statusbar-separator {
        display: none;
    }
}

/* ===== お問合せ（2026-09-25。実体は StatusBar、出し入れと撮影・送信は wwwroot/js/support-inquiry.js） =====
   バーの中のボタンは文字だけの小さな押しボタン（バーの文字の大きさのまま）。窓は <dialog> の showModal
   ＝最上位の層に出るので、バーの重なり順（30）やドロワーに影響されない。 */
.app-statusbar-support {
    padding: 2px 8px;
    font: inherit;
    color: var(--alt-text-strong);
    background: transparent;
    border: 1px solid var(--alt-border);
    border-radius: 4px;
    cursor: pointer;
}

.app-statusbar-support:hover {
    background: var(--alt-bg-primary);
}

.app-support-dialog {
    width: min(560px, calc(100vw / var(--alt-vz, 1) - 32px));
    max-height: calc(100vh / var(--alt-vz, 1) - 32px);
    padding: 20px;
    box-sizing: border-box;
    color: var(--alt-text-strong);
    background: var(--alt-bg-primary);
    border: 1px solid var(--alt-border);
    border-radius: 8px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.25);
}

.app-support-dialog::backdrop {
    background: rgba(0, 0, 0, 0.35);
}

.app-support-form {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin: 0;
}

.app-support-title {
    margin: 0;
    font-size: 1.1rem;
}

.app-support-lead,
.app-support-hint {
    margin: 0;
    font-size: 0.82rem;
    color: var(--alt-text-sub);
}

.app-support-kind {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 16px;
    margin: 0;
    padding: 0;
    border: none;
}

.app-support-kind legend,
.app-support-label {
    margin-bottom: 4px;
    font-size: 0.85rem;
    font-weight: 600;
}

.app-support-kind label {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    cursor: pointer;
}

.app-support-form textarea {
    width: 100%;
    box-sizing: border-box;
    padding: 6px 8px;
    font: inherit;
    color: inherit;
    background: var(--alt-bg-primary);
    border: 1px solid var(--alt-border);
    border-radius: 4px;
    resize: vertical;
}

.app-support-shot {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.app-support-shot-empty {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.app-support-shot-empty .app-support-hint {
    flex-basis: 100%;
}

/* 撮影の確認と、送れなかったときの「メールソフトで送る」。地と色は共通の .form-warn / .form-error（テーマに追従する）。
   ここで足すのは中の並べ方だけ。 */
.app-support-confirm,
.app-support-fallback {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: 0;
}

.app-support-confirm-title {
    margin: 0;
    font-weight: 600;
}

.app-support-preview img {
    display: block;
    max-width: 100%;
    max-height: 240px;
    object-fit: contain;
    border: 1px solid var(--alt-border);
    border-radius: 4px;
}

.app-support-preview .app-support-actions {
    margin-top: 6px;
}

/* hidden 属性を持つ段は、上の display 指定より優先して隠す。 */
.app-support-dialog [hidden] {
    display: none !important;
}

.app-support-error:empty {
    display: none;
}

.app-support-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 8px;
}

.app-support-footer {
    margin-top: 4px;
}

.app-support-btn {
    display: inline-flex;
    align-items: center;
    padding: 6px 14px;
    font: inherit;
    font-size: 0.88rem;
    color: var(--alt-text-strong);
    background: var(--alt-bg-primary);
    border: 1px solid var(--alt-border);
    border-radius: 4px;
    cursor: pointer;
}

.app-support-btn:hover {
    background: var(--alt-bg-subtle);
}

.app-support-btn.is-primary {
    color: #fff;
    background: var(--alt-btn-primary-bg);
    border-color: var(--alt-btn-primary-bg);
}

.app-support-btn.is-primary:hover {
    background: var(--alt-btn-primary-hover);
}

/* 送信中（無効にはしない＝support-inquiry.js の submit の doc）。 */
.app-support-btn[aria-disabled="true"] {
    opacity: 0.6;
    cursor: progress;
}


/* ===== ページの先頭へ移動（2026-09-18・TEST1-149。実体は StatusBar、出し入れは wwwroot/js/to-top.js） =====
   ステータスバーの右上に浮かぶ丸いボタン。**バーの子にして、バーの上端から測る**＝バーは 4 つのレイアウトすべてで
   画面の下に貼り付いている（フローティングでは下に余白のあるカード）ので、その位置をここで数え直さなくてよい。
   本文の列（.app-body）の中に居るので、サイドバーにも右端に吸着した横断検索のパネルにも重ならない。
   重なり順はバーのもの（30）を引き継ぐ＝ドロワーとその膜（40／50）・ポップアップより下。
   **浮かせた横断検索のパネル（50）・狭い画面のパネル（35）・トーストもこれより手前で、画面が低いと覆う（実測）が、それが意図**
   ＝どれも利用者が出した面か一時的な面で、ボタンより優先する（浮かせたパネルは掴んで動かせる）。
   **土台はハンバーガーやベルと同じ .app-nav-button**（中央寄せ・当てたときの地・フォーカス枠）で、ここは浮かせる分だけを足す
   ＝クラス 2 つで書くのは、後ろにある土台の枠なし・透明の地・角丸に勝つため（.alt-icon-btn-framed と同じ作法）。 */
.app-nav-button.app-to-top {
    position: absolute;
    right: var(--alt-to-top-gap);
    bottom: calc(100% + var(--alt-to-top-gap));
    width: var(--alt-to-top-size);
    height: var(--alt-to-top-size);
    background: var(--alt-surface);
    border: 1px solid var(--alt-border);
    border-radius: 50%;
    box-shadow: var(--alt-shadow-pop);
    /* 出していないあいだは visibility でも隠す＝opacity だけだと Tab で止まり、読み上げにも残る。 */
    opacity: 0;
    visibility: hidden;
}

.app-to-top.is-visible {
    opacity: 1;
    visibility: visible;
}

@media (prefers-reduced-motion: no-preference) {
    .app-to-top {
        transition: opacity 0.2s ease, visibility 0.2s;
    }
}

/* ボタンが出ているあいだだけ、本文の末尾にボタンの分の余白を足す＝一番下まで送ったとき、一覧のページャの
   右端（表示件数）をボタンが覆わない。**常には足さない**＝画面の高さにわずかに収まっていた画面に
   スクロールバーが出る。ボタンが出るのは先頭から離れたときだけなので、足す末尾は画面の外にあり、見えている行は動かない。
   フローティング（layouts.css）は本文の余白を言い直しているが、:has() の中の 3 つのクラスが詳細度に数えられるので
   こちらが勝つ＝レイアウトごとに書き直さない。 */
.app-body:has(> .app-statusbar > .app-to-top.is-visible) > main.container {
    padding-bottom: calc(var(--alt-to-top-size) + var(--alt-to-top-gap));
}

/* 押すとフォーカスを本文の先頭へ移す（to-top.js が一時的に tabindex を付ける）。本文は操作する部品ではないので枠は出さない。 */
.app-body > main.container:focus {
    outline: none;
}

/* ===== 画面の見出しのフローティング（2026-09-29・利用者の要望。帯を置いて出し入れするのは wwwroot/js/floating-title.js） =====
   見出しが上端より上へ出たら、本文の列の上端に見出しを 1 行で写した帯を浮かせる。右端の「…」で見出しの操作をメニューで出す。
   **上端はヘッダーの下**（--alt-sidebar-top＝サイドバーが貼り付く位置と同じ）。一覧や明細のタブの中（iframe）はヘッダーを描かないので 0。
   **0 にするのは帯の中の変数だけ**＝--alt-sidebar-top そのものを iframe の中で 0 にすると、フローティングの本文の最低の高さ
   （layouts.css）まで変わる。帯とメニューの高さはこの変数だけを見る（JS も帯の top を読むので、ここを変えれば揃う）。
   横の位置と幅は JS が本文の列に合わせて当てる。**帯は本文の枠（zoom を当てる main）の外**に居るので、表示倍率では大きくならない。
   重なり順はヘッダー（30）の下・本文の上。 */
.alt-float-title {
    --alt-float-title-top: var(--alt-sidebar-top);
    position: fixed;
    top: var(--alt-float-title-top);
    z-index: 28;
    display: flex;
    align-items: center;
    gap: 8px;
    box-sizing: border-box;
    min-height: 36px;
    padding: 3px 8px 3px 16px;
    background: var(--alt-surface);
    border-bottom: 1px solid var(--alt-border);
    box-shadow: var(--alt-shadow-xs);
    font-size: 0.86rem;
    line-height: 1.4;
    /* 出していないあいだは visibility でも隠す（.app-to-top と同じ理由）。Tab の順路からは JS が inert で外す。 */
    opacity: 0;
    visibility: hidden;
}

.alt-float-title.is-visible {
    opacity: 1;
    visibility: visible;
}

@media (prefers-reduced-motion: no-preference) {
    .alt-float-title {
        transition: opacity 0.15s ease, visibility 0.15s;
    }
}

html[data-alt-embed] .alt-float-title {
    --alt-float-title-top: 0px;
}

/* 見出しの写し。**1 行に収めて末尾を … で切る**（番号や種別のバッジは写したまま、行内に並ぶ）。 */
.alt-float-title-text {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-weight: 600;
    color: var(--alt-text-primary);
}

.alt-float-title-text > * {
    vertical-align: middle;
}

.alt-float-title-status {
    flex: none;
    font-size: 0.76rem;
    color: var(--alt-text-sub);
}

/* .alt-icon-btn が display を持つので、hidden の既定だけでは隠れない。 */
.alt-float-title-menu[hidden] {
    display: none;
}

/* 操作のメニュー。帯の右端から下へ開く。**見た目はアイコンバーのフローティングメニュー（.app-flyout）に揃える**
   （項目も .app-flyout-item。ボタンの素の見た目を消すのは .app-account-pop の項目と同じ規則）。長いときは画面の高さで止めて中をスクロールする。 */
.alt-float-title-items {
    position: absolute;
    top: calc(100% + 4px);
    right: 8px;
    min-width: 190px;
    max-height: calc(100vh / var(--alt-vz, 1) - var(--alt-float-title-top) - 80px);
    overflow-y: auto;
    padding: 8px;
    box-sizing: border-box;
    background: var(--alt-bg-primary);
    border: 1px solid var(--alt-border-secondary);
    border-radius: var(--alt-radius-md);
    box-shadow: var(--alt-shadow-pop);
}

.alt-float-title-items .app-flyout-item:disabled {
    opacity: 0.5;
    cursor: default;
}

/* 取り返しのつかない操作（削除）は本文のボタンと同じく赤で見分ける。 */
.alt-float-title-items .app-flyout-item.is-danger {
    color: var(--alt-danger-text);
}

/* ===== モジュール共通の画面部品（Sales/Pm/Workflow から使う。モジュールの CSS は互いに参照できないのでここに置く） ===== */
/* カード（見出し付きの枠）。**入力・一覧・説明のまとまり（カテゴリ）は必ずこれで括る**（2026-09-10 に体裁を整えた）。
   見出しは左に短いアクセントの帯を持ち、下に細い線を引く＝素の太字より「ここから 1 つのまとまり」が読める。
   影は薄く（--alt-shadow-xs）、暗いテーマでは themes.css の同じトークンが少し強くなる。 */
.alt-card { margin: 0 0 1rem; padding: 1rem var(--alt-card-pad); border: 1px solid var(--alt-border); border-radius: var(--alt-radius-md); background: var(--alt-surface); box-shadow: var(--alt-shadow-xs); box-sizing: border-box; }
.alt-card-title { display: flex; align-items: center; gap: 0.5rem; margin: 0 0 0.8rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--alt-border); font-size: 1rem; font-weight: 700; color: var(--alt-heading); }
.alt-card-title::before { content: ""; flex: none; width: 4px; height: 1em; border-radius: 2px; background: var(--alt-accent); }
/* 期限超過（期限日・納期・支払期限を過ぎたもの）は**どの画面でも赤の太字**（2026-09-17）。Pm・生産管理・販売が使う。
   **モジュールの CSS に写さない**＝写すと太さや色を変える日に全モジュールを回ることになり、実際に 3 か所の写しができかけた。
   色だけに頼らない印（生産管理の「!」など）は、それぞれのモジュールが自分の CSS に足す。 */
.alt-overdue { color: var(--alt-danger); font-weight: 700; }
/* 入力だけを持つカードは入力と同じ幅で止める（2026-09-10）＝入力（.alt-form-grid）は 800px で止まるのに
   枠だけが画面の端まで伸びると、右に空の面が残る。**一覧（DxGrid・table）を持つカードは対象外**＝
   あちらは幅いっぱいに使うもの。判定は :has() なので画面側は何も名乗らなくてよい（2 列に並べているだけの
   .alt-form-wide も入力ではないので外す）。幅＝入力の上限＋左右の余白＋枠線。
   **除外は開いた一覧**＝幅いっぱいに使う部品を新しく入れた（ピボット・チャート・スケジューラ）のに狭まったら、
   ここに足すか、そのカードに `alt-form-wide` を置く。
   **Pm の簡易ビューの窓の既定の幅と、課題詳細の本文のつまみの下限がこの上限を測る**
   （Culminans.Pm の js/pm-quickview.js・js/pm-body-width.js）。
   **入力を持たないカードが同じ幅を名乗るための印が `alt-form-card`**（2026-09-20・TEST1-152）＝
   `alt-form-wide`（外す側）と対になる入る側で、`:has()` で当たらないカードが「入力の欄と同じ幅で読ませたい」
   と名乗る（Pm の課題詳細の本文のカード。顔ぶれは Pm の Shared/IssueBodyWidth.cs）。
   **詳細画面はどれも Pm の課題詳細と同じ割り付けにする**（2026-09-26）＝入力と散文（本文・申請内容・メール・
   タイムライン・コメント欄）はこの幅、表（明細・グリッド・関連の並び・図）は全幅。散文の塊が `:has()` で
   当たらない画面（Workflow・生産・メールボックス・お知らせ）はこの印を名乗る。**例外は Pm の課題詳細**（2026-10-20）＝本文の列に挟まる
   関連の並び（属性・親子課題・依存関係・添付ファイル）も本文と同じ幅で止める（理由は Pm の Shared/IssueBodyWidth.cs）。**カードでない塊にも付けてよい**
   （ワークフローの申請詳細はカードを使わずに並べている）＝外側の端がカードの外側の端と揃う。**式を 2 か所に書かないための口**＝写すと上限を変えた日に
   片方だけが古い幅のまま残る。**この幅を JS から測るときは `max-width` の計算値を読む**
   （Pm の js/pm-body-width.js・js/pm-quickview.js）＝測り方を 2 通り持つと、この規則の当て方を変えた日に
   片方だけが黙って別の数字を返す（2026-09-21・TEST1-158）。**画面に無いカードの幅は、実物と同じ作りの
   見えない要素で測る**＝上の 2 本の枝は今は同じ上限だが、別の枝を名乗って測ると、除外リストを足した日に
   実物だけが広がっても気付けない。**変数から組み直さない**＝登録していないカスタムプロパティの計算値は
   `calc(800px + 1.25rem * 2 + 2px)` という文字列のままなので、`parseFloat` は左右の余白と枠線を落とした
   800 を拾う（NaN にならないので落とし先も通らない）。 */
.alt-card:has(> .alt-form-grid):not(:has(.dxbl-grid, table, .alt-form-wide)),
.alt-form-card,
.alt-card:has([data-alt-compact]):not(:has(:is(.dxbl-grid, .dxbl-treelist):not([data-alt-compact]), table:not(:is(.dxbl-grid, .dxbl-treelist) table), .alt-form-wide)),
.app-split-body > .dialog-buttons { max-width: calc(var(--alt-form-max) + var(--alt-card-pad) * 2 + 2px); }
/* 列の少ない一覧（データの列が 4 つ以下。2026-09-23）は入力の上限と同じ幅で止める。印は js/grid-compact.js が
   描画のあとの見出しを数えて付ける（列の選択や顧客モジュールの列で数が変わるため）。**一覧だけのカードも一緒に縮む**＝
   上の 3 本目の枝。一覧の外の広い表・チャート（alt-form-wide）を持つカードは縮めない。
   狭めたくない一覧は data-alt-compact-off を置く（祖先でもよい）。
   **ページ直下（カードの外）のボタン列も同じ幅で止める**＝上の 4 本目の枝。設定画面の「保存」はすべてのカードを送るので
   外に置くが、右寄せのまま幅いっぱいにすると、800px で止まったカードから離れた画面の右端に出る（販売・生産・
   ワークフローの設定、伝票の編集）。カードが幅いっぱいの画面でも入力の近くに来るだけで、離れはしない。 */
[data-alt-compact] { max-width: var(--alt-form-max); }
/* 2 列のフォームグリッド（alt-span2 で 2 列ぶち抜き。狭い画面では 1 列） */
/* 入力の並び（2 列）。**幅は --alt-form-max で止める**（2026-09-05・TEST1-61）＝ダイアログ
   （.dialog-form）と同じ上限を、ページに直に置いたフォーム（伝票の編集・各モジュールの設定画面）にも
   効かせる。ダイアログの中はもともとこれより狭いので、二重にかかっても何も変わらない。
   **入力ではなく表や数字を 2 列に並べるためにこの道具を借りている場所は alt-form-wide で外す**
   ＝この規則が見ているのは「2 列に並べる」というクラスであって「入力かどうか」ではないので、
   借りている側が自分で名乗る（alt-w-full と同じ流儀）。**表を並べる窓（.dialog-form）も同じ印で外す**
   （2026-09-17。見積明細テンプレートの窓は 1100px あるのに表が 800px で止まっていた）。窓の中の入力欄は
   .alt-form-grid が同じ上限で止めるので、入力の幅は変わらない。 */
.alt-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 14px; max-width: var(--alt-form-max); }
.alt-form-grid.alt-form-wide,
.dialog-form.alt-form-wide { max-width: none; }
.alt-form-grid > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
/* ファイル選択のボタン（FileAttachButton の label）は見出しではないので外す。:where で包むのは詳細度を元のまま保つため
   （上げると、この規則を後ろの規則で上書きしている画面の見出しの色と大きさが変わる）。 */
.alt-form-grid label:not(:where(.alt-file-btn)) { color: var(--alt-text-sub); font-size: 0.85rem; }
.alt-span2 { grid-column: span 2; }
/* 行の頭から始める（2026-10-05・TEST1-465）。対になる 2 つの欄（発注点と補充点など）の前の欄が奇数個のとき、
   対が行をまたいで割れるのを止める＝前の行の右が空く。1 列になる狭い画面では何も変わらない。 */
.alt-row-start { grid-column-start: 1; }
@media (max-width: 720px) {
    .alt-form-grid { grid-template-columns: 1fr; }
    .alt-span2 { grid-column: span 1; }
}
/* 詳細画面の見出し行（タイトル＋右寄せの操作ボタン） */
.wf-detail-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; flex-wrap: wrap; }
/* 詳細画面の操作ボタンの行（伝票・申請・課題・プロジェクト・入金・分析の 6 画面で共用）。
   **`flex-shrink: 0` を外した**（2026-09-12）＝あれは「この行は親の中で縮まない」という意味で、
   縮まない箱の中身は折り返す必要が生じないので、**隣に書いてある `flex-wrap: wrap` が
   一度も働いていなかった**。結果としてボタンが増えるたびに画面の外へ出ていた
   （例外もログも出ず、右端が切れるだけ）。外すと 6 画面とも 2 行目へ折り返す。 */
.wf-detail-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* 帳票の印刷プレビュー（Core の Components/ReportPreview）。ビューアは入れ物の高さいっぱいに広がるので、
   高さを持つのはこの入れ物。Core に wwwroot は無いので Core 部品の CSS はここに置く（CLAUDE.md §2）。 */
.report-preview { height: calc(78vh / var(--alt-vz, 1)); }

/* 帳票レイアウトのデザイナー（Pages/AdminReportLayouts）。プレビューと同じで、高さを持つのは入れ物のほう。
   デザイナーは道具箱と項目一覧を左右に置くので、プレビューより高さが要る。 */
.report-designer { height: calc(82vh / var(--alt-vz, 1)); }
/* 様式の選択。幅を決めないと DxComboBox が行いっぱいに伸びて、状態と操作が次の行へ落ちる。 */
.grid-toolbar .report-style-select { width: 260px; }

.logout-form {
    margin: 0;
}

/* ウィザードの歩（矢羽）。**Pm のリポジトリ連携と Forms の作成ウィザードが同じものを要求した**ので
   シェルへ移した（app.css に置くのは 2 つ以上のモジュールが使うものだけ）。
   いまどこにいるかは形と色で示す＝太字だけだと並んだうちのどれが現在なのか一目で分からない。 */
.alt-wizard-steps { display: flex; gap: 2px; flex-wrap: nowrap; margin-bottom: 8px; font-size: 0.9rem; list-style: none; padding: 0; }
.alt-wizard-steps > * {
    flex: 1 1 0;
    min-width: 0;
    padding: 6px 10px 6px 22px;
    background: var(--alt-bg-muted);
    color: var(--alt-text-muted);
    text-align: center;
    clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 50%, calc(100% - 12px) 100%, 0 100%, 12px 50%);
}
/* 端の矢は外側を切らない（最初の左と最後の右はまっすぐ）。 */
.alt-wizard-steps > *:first-child { padding-left: 10px; clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 50%, calc(100% - 12px) 100%, 0 100%); }
.alt-wizard-steps > *:last-child { clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, 12px 50%); }
.alt-wizard-steps .is-done { background: var(--alt-accent-soft-strong); color: var(--alt-text-strong); }
.alt-wizard-steps .is-active { background: var(--alt-accent); color: var(--alt-on-accent); font-weight: 600; }
/* 状態（is-active / is-done）を選ぶ規則は Core の WizardSteps。CSS と対にしてある
   ＝写すと、状態を 1 つ足したときにどれかの画面が取り残される。 */

.linklike {
    background: none;
    border: none;
    cursor: pointer;
    font: inherit;
}

/* 並んだリンク風ボタンのあいだの余白。**素の空白 1 つでは足りず**、一覧の操作列で
   「開く 設定 編集」が 1 続きの文に見える（2026-08-31 の指摘 CUL1-35）。
   ここ 1 か所に置く＝画面ごとに書くと、次に足した一覧が必ず取り残される。 */
.linklike + .linklike {
    margin-left: .75rem;
}

/* 処理中のリンク風ボタン（無効にはしない＝押している最中に disabled にするとフォーカスが隣へ飛ぶ。pitfalls.md）。
   押下は置く側が捨てる（いまの使い手は CounterpartyNoChoices だけ）。**シェルに置くのは意図して**＝aria-disabled は
   「押せない」を名乗る属性そのものなので、どのリンク風ボタンに付いても同じ見た目でよい（意味を名乗るクラスを別に作ると、
   aria-disabled だけ付けて見た目が変わらないボタンができる）。押下を捨てるのは CSS ではできないので、付ける側が必ず捨てること。 */
.linklike[aria-disabled="true"] {
    opacity: .6;
    cursor: progress;
}

/* 書き出しの形を選ぶドロップダウンの中身（Forms のレコード、シフト表）。**1 行 1 つで、折り返させない**
   ＝素の .dialog-form は幅なりに流れるので、「CSV (Shift_JIS)」が 2 行に割れたり 3 つが横一列になったりする
   （どちらも何行あるのか読み取りにくい）。幅を数字で決めないのは、言語で長さが変わるため。
   **2 つ目の要求者（シフト表の書き出し・2026-09-07）が出たのでモジュールから上げた**＝写すと、
   片方だけ間隔や折り返しを直した日に同じ見た目のメニューが 2 種類になる。 */
.export-menu {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: .35rem;
    white-space: nowrap;
}

/* **左の余白は打ち消す**＝上の `.linklike + .linklike` は<b>横に並ぶ</b>リンクのあいだを空けるためのもので、
   縦に積むここでは 2 つ目以降だけが右へずれる。縦の間隔は上の gap が持つ。 */
.export-menu .linklike + .linklike {
    margin-left: 0;
}

/* システムエリア（本文の 1 行目・2026-09-05・TEST1-61。実体は Components/Layout/SystemBar）。
   いまのモジュール（絵＋名前）とパンくずを 1 行に左寄せで並べる。
   **本文（main.container）の中に置く**＝画面の上へ貼り付けると、TEST1-48/50 で分けた
   「メインだけがスクロールする」作りの外に出ることになり、狭い画面では上部バー
   （.app-mobile-bar）と役割が二重になる。
   折り返しは許す＝モジュール名も項目名も翻訳で伸びるので、狭い画面で 1 行に押し込むと文字が切れる。 */
.app-systembar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .35rem;
    margin-bottom: .8rem;
    font-size: .85rem;
    color: var(--alt-text-sub);
}

.app-systembar a {
    color: inherit;
    text-decoration: none;
}

.app-systembar a:hover {
    color: var(--alt-text-primary);
    text-decoration: underline;
}

/* 絵＋名前（2026-09-06 に【】を外した）。空けたいのは絵と名前のあいだだけ。 */
.app-systembar-module {
    display: inline-flex;
    align-items: center;
    gap: .2rem;
    font-weight: 600;
    color: var(--alt-text-primary);
}

.app-systembar-sep {
    color: var(--alt-text-muted);
}

/* モジュールのタブ（本文の 2 行目・2026-09-06・TEST1-72。実体は Components/Layout/ModuleTabs）。
   2026-09-06 に Pm の .pm-tabs をここへ移して改名した＝タブの見た目を持つ CSS はほかに
   .acct-tab（個人設定）と .wf-tab（申請一覧）があるが、どちらも**同じ画面の中で表を切り替える**もの。
   こちらは**別の画面へ移る**帯なので、4 つ目を作らずシェルの 1 か所に置く。
   折り返しは許す（システムエリアと同じ理由＝項目名は翻訳で伸びる）。
   **Pm の簡易ビューがこの帯（と .app-topbar・.app-mobile-bar）の下端を測って窓を置く**（Culminans.Pm の js/pm-quickview.js）
   ＝名前を変えたらあちらも直す。直さないと窓が画面の上端に寄るだけで、例外もログも出ない。 */
.app-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
    border-bottom: 2px solid var(--alt-border);
    margin: 0 0 12px;
}

.app-tab {
    padding: 6px 14px;
    margin-bottom: -2px;
    border-bottom: 2px solid transparent;
    color: var(--alt-text-sub);
    text-decoration: none;
    font-weight: 500;
}

.app-tab:hover {
    color: var(--alt-text-strong);
    border-bottom-color: var(--alt-text-muted);
    text-decoration: none;
}

/* 現在位置の下線だけプロジェクトの色にする（--app-tab-accent はメニューの AccentColor 由来）。
   **文字色には使わない**＝色は自由に選べるので、淡い色を文字に当てると白地で読めなくなる
   （下線は 2px の帯なので淡くても体裁が崩れない）。 */
.app-tab.is-active {
    color: var(--alt-accent);
    border-bottom-color: var(--app-tab-accent, var(--alt-accent));
    font-weight: 600;
}

/* 右端に絵だけで置くタブ（NavMenuItem.TabAtEnd。ごみ箱など）。右端の操作（.app-tabs-actions）があればその左に並ぶ。 */
.app-tabs-end {
    display: inline-flex;
    align-items: flex-end;
    margin-left: auto;
}

.app-tabs-end + .app-tabs-actions {
    margin-left: 0;
}

.app-tab-icon {
    display: inline-flex;
    align-items: center;
    padding: 6px 10px;
}

/* 帯の右端の操作（詳細画面の「一覧を並べる」と左右の入れ替え。DetailListControls）。タブが折り返しても右端に寄る。 */
.app-tabs-actions {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;
    padding: 0 0 4px 12px;
}

/* ===== 狭い画面（iPad・スマホ）: ハンバーガーメニュー ===== */
/* 開閉の挙動（線をまたいだとき・キーボード・膜・リンク）は tools/ui-tests/nav-drawer.py で確かめる（TEST1-137）。 */

/* 開閉スイッチ本体は常に非表示（label[for] から操作する）。
   display:none にしても label 経由の切り替えと :checked セレクタは効く。 */
.app-nav-toggle {
    display: none;
}

/* ハンバーガーボタン（モバイル上部バーとサイドバーの折りたたみトグルで共用）。 */
.app-nav-button {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border: none;
    background: transparent;
    padding: 0;
    border-radius: var(--alt-radius-md);
    cursor: pointer;
}

.app-nav-button:hover {
    background: var(--alt-bg-secondary);
}

.app-nav-button:focus-visible {
    outline: 2px solid var(--alt-brand);
    outline-offset: 2px;
}

/* ハンバーガーのアイコン（中央の線 ＋ 疑似要素で上下の線）。 */
.app-nav-bars {
    position: relative;
}

.app-nav-bars,
.app-nav-bars::before,
.app-nav-bars::after {
    display: block;
    width: 20px;
    height: 2px;
    border-radius: 1px;
    background: var(--alt-text-primary);
}

.app-nav-bars::before,
.app-nav-bars::after {
    content: "";
    position: absolute;
    left: 0;
}

.app-nav-bars::before {
    top: -6px;
}

.app-nav-bars::after {
    top: 6px;
}

/* ヘッダー・上部バーの左端のまとまり（ハンバーガーとブランド）と右端のまとまり（ベルとアカウント）。
   並べ方は親の帯のまま＝間隔は親の gap を受け継ぐ。
   **右へ寄せるのは帯ごとに 1 つだけ**＝上部バーは右端の包み（下）、ヘッダーはパンくずの箱（flex: 1。狭い画面でも箱は残す
   ＝layouts.css）。2 つ置くと余りが半分ずつになり、あいだの部品が帯の中ほどに浮く。
   包みを置くのは、背景の線画を敷かない範囲を 1 つの箱で示すため（motifs.css の「線画を敷かない場所」）。 */
.app-topbar-lead,
.app-topbar-trail {
    display: flex;
    flex: none;
    align-items: center;
    gap: inherit;
}

.app-mobile-bar .app-topbar-trail {
    margin-left: auto;
}

/* 上部バーと背景の膜は広い画面では出さない。 */
.app-mobile-bar,
.app-nav-scrim {
    display: none;
}

@media (max-width: 1024px) {
    .app-shell {
        flex-direction: column;
    }

    /* 画面上部の細いバー。ここのハンバーガーでドロワーを開く。 */
    .app-mobile-bar {
        /* 余白・間隔・地色の名乗り（名前はヘッダーの .app-topbar と同じ。線画を敷かない場所＝motifs.css が読む）。 */
        --alt-bar-pad-start: 12px;
        --alt-bar-pad-end: 12px;
        --alt-bar-gap: 10px;
        --alt-bar-bg-start: var(--alt-bg-primary);
        --alt-bar-bg-end: var(--alt-bg-primary);
        display: flex;
        align-items: center;
        gap: var(--alt-bar-gap);
        position: sticky;
        top: 0;
        z-index: 30;
        height: var(--alt-topbar-height);
        padding: 0 var(--alt-bar-pad-end) 0 var(--alt-bar-pad-start);
        box-sizing: border-box;
        background: var(--alt-bar-bg-start);
        border-bottom: 1px solid var(--alt-border-secondary);
    }

    /* サイドバーは画面外に隠したドロワーにする（本文が下に押し出されないようにする）。 */
    .app-sidebar {
        position: fixed;
        top: 0;
        left: 0;
        z-index: 50;
        flex: none;
        width: min(300px, calc(85vw / var(--alt-vz, 1)));
        height: calc(100vh / var(--alt-vz, 1));
        min-height: 0;
        overflow-y: auto;
        transform: translateX(-100%);
        /* **--alt-shadow-pop に揃えない**＝ドロワーは下の .app-nav-scrim が実際に暗くするので、
           浮きを作っているのは膜のほう。影は装飾なので意図して大きめにしてある。 */
        box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
    }

    /* ドロワー時は幅を固定にするのでつまみは出さない。 */
    .app-sidebar-resizer {
        display: none;
    }

    .app-nav-toggle:checked ~ .app-sidebar {
        transform: translateX(0);
    }

    /* ドロワーを開いている間だけ背後を覆う膜。タップで閉じる。 */
    .app-nav-toggle:checked ~ .app-nav-scrim {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 40;
        background: rgba(0, 0, 0, 0.35);
    }

    /* ドロワー表示中は背後をスクロールさせない（クラス付与は nav-drawer.js）。 */
    body.app-nav-open {
        overflow: hidden;
    }

    .container {
        margin: 1rem 0;
        padding: 0 1rem;
    }
}

/* 開け閉めのスライドは、利用者が開け閉めした直後だけ（印の付け外しは nav-drawer.js。TEST1-116）。
   **.app-sidebar に常に付けない**＝画面幅がこの線をまたいでサイドバーがドロワーへ変わった瞬間にも滑り出し、
   その 0.2 秒のあいだパンくず・見出し・入力欄の左端がサイドバーに隠れる。動きを減らす設定では滑らせない。 */
@media (max-width: 1024px) and (prefers-reduced-motion: no-preference) {
    body.app-nav-animating .app-sidebar {
        transition: transform 0.2s ease;
    }
}

.app-error {
    border: 1px solid var(--alt-danger-border);
    background: var(--alt-danger-bg);
    border-radius: 6px;
    padding: 1rem 1.25rem;
    margin: 1rem 0;
}

.app-error h2 {
    color: var(--alt-danger-strong);
    margin-top: 0;
}

.app-error .app-error-type {
    color: #8a1020;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.85rem;
    margin: 0.25rem 0;
}

.app-error .app-error-message {
    white-space: pre-wrap;
    word-break: break-word;
    background: var(--alt-surface);
    border: 1px solid #efd6d6;
    border-radius: 4px;
    padding: 0.6rem 0.75rem;
    font-size: 0.85rem;
}

.app-error .reload {
    display: inline-block;
    margin-top: 0.5rem;
    color: var(--alt-danger-strong);
}

/* ===== ログイン画面（Figma: WebDemoSystem / Log in） ===== */
.login-page {
    display: flex;
    justify-content: center;
    padding: 96px 1rem 3rem;
}

.login-card {
    width: 360px;
    max-width: 100%;
    display: flex;
    flex-direction: column;
    gap: 32px;
}

.login-header {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    text-align: center;
}

/* ログイン画面では同じシンボルと製品名を大きく見せる。 */
.login-logo {
    display: inline-block;
    flex: 0 0 56px;
    width: 56px;
    height: 56px;
    background-image: var(--alt-brand-symbol);
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
}

.login-header > .brand-lockup {
    max-width: 100%;
}

.login-header .brand-product-name {
    font-size: 28px;
    line-height: 36px;
}

html[data-theme="dark"] {
    --alt-brand-symbol: var(--alt-brand-symbol-on-dark);
    --alt-brand-wordmark: var(--alt-brand-wordmark-on-dark);
    --alt-brand-custom-filter: brightness(0) invert(1);
}

.app-brand-logo.is-custom,
.login-logo.is-custom {
    filter: var(--alt-brand-custom-filter);
}

.login-title {
    margin: 0;
    font-size: 24px;
    line-height: 32px;
    font-weight: 600;
    color: var(--alt-text-primary);
}

.login-subtitle {
    margin: 0;
    font-size: 16px;
    line-height: 24px;
    color: var(--alt-text-tertiary);
}

.login-form {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

.field {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.field-label {
    font-size: 14px;
    line-height: 20px;
    font-weight: 500;
    color: var(--alt-text-secondary);
}

.field-input {
    width: 100%;
    box-sizing: border-box;
    padding: 10px 14px;
    border: 1px solid var(--alt-border-primary);
    border-radius: var(--alt-radius-md);
    box-shadow: var(--alt-shadow-xs);
    background: var(--alt-bg-primary);
    font-size: 16px;
    line-height: 24px;
    color: var(--alt-text-primary);
}

.field-input::placeholder {
    color: var(--alt-text-placeholder);
}

.field-input:focus {
    outline: none;
    border-color: var(--alt-brand);
    box-shadow: 0 0 0 3px rgba(29, 78, 216, 0.12);
}

/* パスワード欄と、伏せ字を外す目のボタン（2026-09-10）。入力欄を伸ばし、ボタンは右端に添える。
   **入力欄そのものは部品にしていない**＝SSR の InputText と対話モードの DxTextBox で作りが違うため
   （理由は PasswordToggle.razor の doc が正）。この箱は両方を同じ見た目に並べるためだけのもの。 */
.password-field {
    display: flex;
    align-items: center;
    gap: 6px;
}

.password-field > :first-child {
    flex: 1 1 auto;
    min-width: 0;
}


.field-error {
    color: var(--alt-danger-strong);
    font-size: 13px;
}

.login-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.login-remember {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 14px;
    line-height: 20px;
    font-weight: 500;
    color: var(--alt-text-secondary);
    cursor: pointer;
}

.login-checkbox {
    width: 16px;
    height: 16px;
    accent-color: var(--alt-brand);
}

.login-submit {
    width: 100%;
    padding: 10px 16px;
    border: none;
    border-radius: var(--alt-radius-md);
    background: var(--alt-brand);
    color: var(--alt-on-accent);
    font-size: 16px;
    line-height: 24px;
    font-weight: 600;
    box-shadow: var(--alt-shadow-xs);
    cursor: pointer;
}

.login-submit:hover {
    background: var(--alt-accent-hover);
}

.login-error {
    color: var(--alt-danger-strong);
    background: var(--alt-danger-bg);
    border: 1px solid var(--alt-danger-border);
    border-radius: 4px;
    padding: 0.5rem 0.75rem;
    font-size: 0.9rem;
}

/* 素の表（いま使っているのはダッシュボードのモジュール一覧だけ。ユーザー管理は DxGrid に移った）。
   **最小幅を持たせない**（2026-09-17）＝以前は 1024px 以下で min-width: 860px を持ち、.home-modules の
   max-width: 640px に勝って 375px・768px のページを 876px に広げていた。3 列の表は外せば 375px で収まる（実測）。 */

.user-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.92rem;
}

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

.user-table th {
    color: var(--alt-text-strong);
    font-weight: 600;
}

.user-table tr.row-inactive {
    color: var(--alt-text-muted);
    background: var(--alt-bg-subtle);
}

/* フィルタパネル（適用中の条件の表示）をグリッドの一番上に出す。

   DevExpress にパネル位置の設定が無いため、flex の order で並べ替えている。

   グリッド直下の子要素は実機で確認済み（上からの順）:
     dxbl-display-none ×3 / dxbl-grid-top-panel / dxbl-scroll-viewer
     / dxbl-grid-bottom-panel dxbl-pager-container / dxbl-grid-filter-panel
   つまりフィルタパネルは末尾の直下の子なので、order だけで先頭に移せる。

   **DevExpress の内部クラス名に依存する**ため、バージョンアップで効かなくなる可能性がある
   （効かない場合はパネルが従来どおり下に出るだけで、壊れはしない）。
   確認方法はブラウザのコンソールで:
     [...document.querySelector('.alt-grid').children].map(c => c.className)

   元に戻したい場合はこのブロックを削除すればよい。 */
.alt-grid {
    display: flex;
    flex-direction: column;
}

.alt-grid > .dxbl-grid-filter-panel {
    order: -1;
}

/* 一覧を横スクロールして端に当たっても、ブラウザの戻る・進む（トラックパッドの横スワイプ）を動かさない（2026-10-18 洋二さんの指示）。
   決まりは docs/claude/module-wiring.md の「横スクロールの器は、端でブラウザの戻る・進むを動かさない」＝自前の器は
   overflow-x を書いた規則の中に並べる。ここに集めるのは、自前の規則を持たない DevExpress の内部の要素だけ。
   DxGrid・DxTreeList で実際に横へスクロールするのは dxbl-scroll-viewer-content（2026-10-18 実測）。DxTreeList も外側の要素
   （dxbl-tree-list）に .dxbl-grid が付くので 1 つで両方に効く。サイドメニューの DxTreeView なども同じ要素を使うので、一覧の中に限る。
   DxPivotTable は外側の要素（dxbl-pivot-table）と中の dxbl-scroll-viewer-content の両方が横へスクロールする（2026-10-18 実測・375px）。
   **DevExpress の内部クラス名に依存する**＝版上げで名前が変わると戻る・進むが動くようになるだけで、ほかは壊れない。
   確認方法はブラウザのコンソールで（overflow-x が auto の要素が出て、overscrollBehaviorX が none なら効いている）:
     [...document.querySelectorAll('.dxbl-grid *, .dxbl-pivot-table, .dxbl-pivot-table *')].filter(e => /auto|scroll/.test(getComputedStyle(e).overflowX))
       .map(e => [e.className, getComputedStyle(e).overscrollBehaviorX]) */
.dxbl-grid .dxbl-scroll-viewer-content,
.dxbl-pivot-table,
.dxbl-pivot-table .dxbl-scroll-viewer-content {
    overscroll-behavior-x: none;
}

/* 一覧上のツールバー（フィルター作成、フィルター切替、表示リセット）。 */
/* 一覧の上に置くボタンの帯。**左に寄せる**（2026-09-06）＝右端に飛ばすと、表の左上から
   目を動かした先に何も無く、押すものを画面の端まで探しに行くことになる。
   フィルターの帯（`GridToolbar`）はこの下に来るので、押すものが左の縦一列に並ぶ。 */
.grid-toolbar {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start;
    /* 中身は上下中央（2026-09-10）。以前は要素ごとに align-self: center を書いていた＝ここ 1 か所に寄せた。 */
    align-items: center;
    gap: 0.5rem;
    margin: 0.5rem 0;
}

/* ---- サイドメニューの表示モード切替（デスクトップ） ----
   サイドバー上部のハンバーガー（.app-navmode-toggle）で
   「アイコンリストバー ⇄ ツリー表示」を切り替える（2026-08-07 ユーザー要望）。
   実体は幅の切替え（アイコン=64px / ツリー=直前の幅）で、処理は sidebar-resize.js。

   旧仕様の「サイドバーごと隠す折りたたみ」（html.app-nav-collapsed ＋左上の再表示ボタン）は
   アイコンリストバーが上位互換のため廃止した（関連の CSS/JS/マークアップも削除済み）。
   モバイル(≤1024px)は従来どおり上部バーのハンバーガーからドロワーを開く。 */
@media (max-width: 1024px) {
    .app-brand .app-navmode-toggle {
        display: none;
    }
}

/* ---- アイコンリストバー（2026-08-07 ユーザー要望） ----
   サイドバーを最小幅(200px)より狭くすると sidebar-resize.js が幅を 64px にスナップさせ、
   <html> に app-nav-icons を付ける。ここではその状態の見た目を定義する。
   DxTreeView（.app-tree）を細くするのではなく、専用の .app-iconbar に差し替える
   （DevExpress 内部の DOM に依存せず、幅が確実に収まるため）。
   幅を戻すにはつまみを右へドラッグ、またはつまみをダブルクリック（既定220px）。

   **アイコンモードの規則は必ず .app-sidebar の中に閉じること**（包みは .app-sidebar か、
   その名前で始まる .app-sidebar-account。.app-sidebar 自身が主語の行だけが例外）。
   **サイドバーの畳み方でヘッダーの見た目を変えない**。
   ブランド・アカウント・ベルの 3 つは、ヘッダーを持つレイアウト（layouts.css）ではサイドバーではなく
   ヘッダーに居る（MainLayout.razor の `HasTopbar` の分岐）。包みを書かずに `.app-bell` を直に綴ると
   詳細度 (0,2,1) がヘッダー側の `.app-topbar …` や `.app-bell.app-bell-compact`（どちらも (0,2,0)）に
   勝ち、サイドバーの姿がヘッダーへ漏れる。
   2026-09-11 に 3 つとも漏れていた＝ロゴが消え、ベルが帯の中心から 3px 上がり、
   個人設定のポップアップは画面の外へ出て見えなくなっていた（どれも例外もログも出ない）。

   **包みを 1 種類に揃えたのは、機械で確かめられる形にするため**＝
   `grep 'html\.app-nav-icons' app.css | grep -v '\.app-sidebar'` が空であること。
   .app-brand のようなサイドバー専用の包みでも塞げるが、それが専用なのは MainLayout.razor が
   いまそう分けているからにすぎない。ヘッダーのブランドへ同じクラスを足す整理で黙って戻る。 */

/* 通常幅のときはアイコンバーを出さない。 */
.app-iconbar {
    display: none;
}

/* アイコンモードはデスクトップ専用。狭い画面(≦1024px)ではサイドバーが幅固定のドロワーなので、
   localStorage にアイコン幅が残っていても従来のツリーを出す（折りたたみと同じ方針）。 */
@media (min-width: 1025px) {
    html.app-nav-icons .app-sidebar .app-tree {
        display: none;
    }

    /* アイコンモードのときだけサイドバーを本文と一緒に伸ばす（画面の高さに固定しない）。
       アイコンバーは下のとおり overflow を持てない＝中でスクロールできないので、
       高さを固定すると溢れたアイコンに手が届かなくなる（ツリー表示は .app-tree の中でスクロールする）。 */
    html.app-nav-icons .app-sidebar {
        height: auto;
        min-height: calc(100vh / var(--alt-vz, 1) - var(--alt-sidebar-top) - var(--alt-sidebar-bottom));
    }

    html.app-nav-icons .app-sidebar .app-iconbar {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 2px;
        padding: 0 4px;
        /* フローティングメニューが切り取られないよう overflow は付けない。
           グループ化したのでアイコンは数個しかなく、スクロールは不要。 */
    }
}

.app-iconbar-item {
    position: relative; /* 右上に重ねるバッジ（.todo-nav-badge）の基準 */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    /* バーの幅（72px）から左右の余白（4px ずつ）を引いた残り。名前を 1 行で置くために絵より広く取る。
       左右の内側の余白は 0＝名前に 64px を全部渡す（「ダッシュボード」が 2px ずつの余白で切れた。TEST1-593）。 */
    width: 64px;
    padding: 4px 0;
    flex: none;
    border: none;
    background: none;
    border-radius: var(--alt-radius-sm);
    text-decoration: none;
    color: inherit;
    cursor: pointer;
}

/* 絵の下に添えるモジュール名（2026-09-10）。「シフト管理」→「シフト」のように末尾の「管理」を
   落としたもの（落とすのは NavMenu.razor の ShortLabel）。
   **1 行で省略する**＝2 行に折り返すと項目ごとに高さが変わり、絵の縦の間隔が揃わない。
   **かなは詰めて組む**（palt）＝「ダッシュボード」「プロジェクト」の小さいかなと長音が詰まり、
   64px に収まる（Hiragino Sans で 69px → 62px。TEST1-593）。palt を持たないフォントでは詰まらない。
   それでも入りきらない名前（「共有メールボックス」）は末尾が切れるが、当てれば title で全体が出る。 */
.app-iconbar-label {
    max-width: 100%;
    font-feature-settings: "palt";
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 10px;
    line-height: 1.3;
    letter-spacing: -0.01em;
    color: var(--alt-text-tertiary);
}

.app-iconbar-item.alt-nav-active .app-iconbar-label {
    color: var(--alt-text-primary);
}

.app-iconbar-item:hover {
    background: var(--alt-bg-secondary);
}

/* フローティングメニューを開いているグループは押下状態に見せる。 */
.app-iconbar-item.is-open {
    background: var(--alt-bg-secondary);
    box-shadow: inset 0 0 0 1px var(--alt-border-primary);
}

/* アーカイブ済のお気に入りはツリー同様に淡く表示する。 */
.app-iconbar-item.is-archived .alt-ico {
    opacity: 0.45;
}

/* ---- TODOメニューの期限超過バッジ（2026-08-11 ユーザー要望) ----
   ツリー側は DevExpress の BadgeText（.dxbl-badge。TreeView は --dxbl-treeview-badge-* 変数で描画。
   テーマ既定は色が未定義＝透明なので、ここで赤ピルにする）、
   アイコンバー側は自前の .todo-nav-badge をアイコン右上に重ねる（狭幅時のベルバッジと同じ手法）。
   注意: themes.css の濃色サイドバーは dxbl-* の背景を !important で透明化するため、
   そちらは :not(.dxbl-badge) でバッジを除外している。 */
.app-tree .dxbl-badge {
    --dxbl-treeview-badge-bg: var(--alt-danger);
    --dxbl-treeview-badge-color: var(--alt-on-accent);
    --dxbl-treeview-badge-border-radius: 10px;
    --dxbl-treeview-badge-font-weight: 700;
    --dxbl-treeview-badge-font-size: 0.72rem;
}

.todo-nav-badge {
    position: absolute;
    top: 2px;
    right: 2px;
    background: var(--alt-danger);
    color: var(--alt-on-accent);
    border-radius: 10px;
    font-size: 0.65rem;
    font-weight: 700;
    line-height: 1.5;
    padding: 0 5px;
}

/* ---- フローティングメニュー（2026-08-07 ユーザー要望） ----
   アイコンバーのグループを押すと、そのアイコンの右横にメニューを出す。
   位置はグループ（position:relative）基準の absolute なので JS 不要。
   外側を押したときは透明の膜(.app-flyout-scrim)で閉じる。 */
/* フライアウトを本文より手前に出すための重なり順（2026-08-07 不具合修正）。

   position:sticky の .app-sidebar はそれ自体がスタッキングコンテキストを作るため、
   中の z-index をいくら上げても .app-body 側の位置指定要素（DevExpress グリッドの
   sticky ヘッダー等。DOM 順で後ろ）に負けてメニューが一覧の下に隔れていた。
   → サイドバー自体を持ち上げて解決する（下の html.app-nav-icons .app-sidebar）。

   膜(.app-flyout-scrim)=55 ＜ アイコンバー=58 ＜ フライアウト=60 の順。
   アイコンバーを膜より上にすることで、メニューを開いたまま別のグループを直接押せる。 */
.app-iconbar {
    position: relative;
    z-index: 58;
}

.app-iconbar-group {
    position: relative;
    display: flex;
    justify-content: center;
    width: 100%;
}

.app-flyout {
    position: absolute;
    left: calc(100% + 6px);
    top: 0;
    z-index: 60;
    min-width: 190px;
    max-width: 280px;
    max-height: calc(76vh / var(--alt-vz, 1));
    overflow-y: auto;
    padding: 8px;
    background: var(--alt-bg-primary);
    border: 1px solid var(--alt-border-secondary);
    border-radius: var(--alt-radius-md);
    box-shadow: var(--alt-shadow-pop);
}

.app-flyout-head {
    padding: 2px 8px 6px;
    font-size: 0.78rem;
    font-weight: 700;
    color: var(--alt-text-tertiary);
}

/* 見出しの氏名を個人設定へのリンクにした（2026-08-11）。見た目は見出しのまま、
   押せることが分かるようホバーで項目と同じ強調を付ける。 */
a.app-flyout-head-link {
    display: block;
    text-decoration: none;
    cursor: pointer;
}

a.app-flyout-head-link:hover {
    background: var(--alt-accent-soft);
    color: var(--alt-text-secondary-hover);
    border-radius: var(--alt-radius-sm);
}

.app-flyout-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    border-radius: var(--alt-radius-sm);
    color: var(--alt-text-secondary);
    text-decoration: none;
    font-size: 0.85rem;
    white-space: nowrap;
}

/* フローティングメニューの第2階層以降（プロジェクト配下・各グループの「設定」の枝の配下）。
   ツリーと違って開閉が無いので、インデントだけで親子を見せる。 */
.app-flyout-sub {
    padding-left: 24px;
}

/* 画像アイコン（NavMenuItem.IconUrl。Pm のプロジェクトアイコン）。
   .alt-ico-sm と同じ 16px に揃え、縦横比の違う画像でも崩れないよう cover で切り抜く。 */
.app-flyout-ico {
    flex: none;
    width: 16px;
    height: 16px;
    border-radius: 4px;
    object-fit: cover;
    background: var(--alt-bg-secondary);
}

/* 遷移先を持たない見出し（各グループの「設定」の枝・Pm の「お気に入り」）。押せないので反応も出さない（色はグループ見出しに合わせる）。 */
.app-flyout-subhead {
    color: var(--alt-text-tertiary);
    font-weight: 700;
    cursor: default;
}

.app-flyout-item:hover {
    background: var(--alt-bg-secondary);
    color: var(--alt-text-secondary-hover);
}

/* お気に入りの各機能（ボード・ガント等）は一段下げる。 */

.app-flyout-item.is-archived .alt-ico {
    opacity: 0.45;
}

/* プロジェクトごとの区切り。 */

/* 外側クリックを拾う透明の膜（メニューの下・本文の上）。 */
.app-flyout-scrim {
    position: fixed;
    inset: 0;
    z-index: 55;
    background: transparent;
}

/* アイコンモードでは文字が入らないので、ブランド名・ロゴを隠す。
   ハンバーガー（表示モード切替 .app-navmode-toggle）だけ残して中央に置く。
   これでアイコンモードからもワンタップでツリー表示に戻せる。

   Phase7（2026-08-07）: サイドバー下部の自分のアイコンはアイコンモードでも常駐させる。
   以前は「フッターごと隠す」割り切りだったため、アイコンモードからは
   パスワード変更・2段階認証・ログアウトに到達できなかった。
   アイコン1つ＋ポップアップに集約したことで、両モードで同じ導線が使える。 */
@media (min-width: 1025px) {
    html.app-nav-icons .app-sidebar .app-brand {
        justify-content: center;
        padding: 0 4px;
        gap: 0;
        margin-bottom: 12px;
    }

    html.app-nav-icons .app-sidebar .app-brand a,
    html.app-nav-icons .app-sidebar .app-brand-logo {
        display: none;
    }

    /* アイコンモードのアカウント: アイコンだけを中央に置き、名前とロールは隠す。
       ポップアップは（幅64pxに収まらないので）右横へ出す。包みが .app-sidebar-account なのは節の頭のとおりで、
       ここは漏れたときの出かたがいちばん重い＝`left: calc(100% + 6px)` がヘッダーの右端の外を指し、
       layouts.css の `left: auto; right: 0` には詳細度で勝つが `right` は over-constrained で捨てられるので、
       ポップアップは画面の外に立つ（押しても何も出ないように見える）。 */
    html.app-nav-icons .app-sidebar-account {
        padding: 0 4px;
        align-items: center;
    }

    html.app-nav-icons .app-sidebar-account .app-account-btn {
        width: 40px;
        height: 40px;
        /* 包み（.app-account）はポップアップの基準として幅いっぱいのままなので、
           絵より狭いボタンを自分で中央へ寄せる。これが無いと絵の列より 12px 左に立つ。 */
        margin: 0 auto;
        justify-content: center;
        padding: 0;
        gap: 0;
        border: none;
        border-radius: var(--alt-radius-sm);
    }

    html.app-nav-icons .app-sidebar-account .app-account-text {
        display: none;
    }

    html.app-nav-icons .app-sidebar-account .app-account-pop {
        left: calc(100% + 6px);
        top: 0;
    }

}

/* ==== メッセージ表示の共通スタイル（2026-08-11 ユーザー決定） ====
   各処理でメッセージを表示するときは、必ず次の3種の枠を使う:
     ・情報・完了報告          → <div class="form-info">  （青枠）
     ・バリデーション・エラー  → <div class="form-error"> （赤枠）
     ・警告（続行はできる注意）→ <div class="form-warn">  （黄枠）
   色はテーマのトークン／color-mix で作るので、ダーク・ピンクテーマにも追従する。

   枠を張れない場所（グリッドのセル・表の中・文の途中）に断りを出すときだけ、
   面を持たない <span class="form-error-inline"> を使う（下記）。 */

.form-info {
    margin: 0.4rem 0;
    padding: 0.5rem 0.8rem;
    border: 1px solid color-mix(in srgb, var(--alt-accent) 40%, transparent);
    border-radius: var(--alt-radius-sm);
    background: var(--alt-accent-soft);
    color: var(--alt-accent-hover);
    font-size: 0.9rem;
}


/* 操作の結果（上の form-info・form-error）を出す場所の高さを先に取っておく器。
   結果が出たり消えたりするたびに下の入力欄とボタンが上下すると、続けて押そうとした位置にボタンが無くなる
   （TEST1-555。プロジェクト設定のマスタのタブで「追加」が 54px 下へずれていた）。
   flow-root は中の枠の margin を器の外へ抜けさせないため（抜けると予約した高さと実際の高さが合わない）。
   高さは 1 行ぶんの枠（余白・罫線・上下の margin を含む）の実測値（2026-10-12 に 53.8px）を切り上げたもの。2 行に折り返す長いエラーのときだけは伸びる。 */
.form-feedback-slot {
    display: flow-root;
    min-height: 3.4rem;
}

.form-error {
    margin: 0.4rem 0;
    padding: 0.5rem 0.8rem;
    border: 1px solid var(--alt-danger-border);
    border-radius: var(--alt-radius-sm);
    background: var(--alt-danger-bg);
    color: var(--alt-danger-text);
    font-size: 0.9rem;
}

.form-warn {
    margin: 0.4rem 0;
    padding: 0.5rem 0.8rem;
    border: 1px solid color-mix(in srgb, #f9a825 50%, transparent);
    border-radius: var(--alt-radius-sm);
    background: color-mix(in srgb, #f9a825 14%, var(--alt-surface));
    color: color-mix(in srgb, #7a5200 75%, var(--alt-text-primary));
    font-size: 0.9rem;
}

/* 上の 3 種の「枠なし行内版」。面も余白も持たないので、グリッドのセル・表のセル・文の途中に置ける。
   **大きさは持たず、置かれた場所の文字に合わせる**＝グリッドのセルに 0.85rem を持ち込むと
   そのセルだけ行が伸びる（`SizeMode.Small` で 24px → 27px。2026-09-08 実測）。
   入力欄の直下に出す検証メッセージは .field-error（入力欄のスタイル群にある。あちらは独立した行なので
   大きさを持ってよい）。 */
.form-error-inline {
    color: var(--alt-danger-strong);
}

/* ポップアップ内の中身（自前ラッパー）は画面の高さを超えたらスクロールさせる。
   フォームは A4 の紙面に収まる幅で止める＝目が左右に振られず、印刷したときの見当も付く
   （ポップアップの中身も同じクラスだが、ポップアップの幅はこれより狭いので何も変わらない）。
   **上限は --alt-form-max**（2026-09-05・TEST1-61。もとは 820px）＝入力の欄はダイアログでも
   ページ直置きでも同じ幅で止める、という指定なので、値は 1 か所（:root）に置いて
   .alt-form-grid と共有する。

   **これは「自前ラッパーを画面の高さで切る」もので、窓そのものの本文には効かない**
   （2026-09-07・TEST1-89）＝`DxPopup` に `Height` を持たせた窓の中だけをスクロールさせたいときは、
   `BodyCssClass` で本文に名前を付けて当てる（docs/claude/pitfalls.md の DxPopup の項）。
   ここの 74vh は窓の高さと無関係なので、そちらに使うと窓の外にはみ出したまま効かない。

   **フォーカスの枠の逃げ場を内側に 4px 取り、同じだけ外へ押し出す**（2026-09-26）＝ボタンの枠は
   outline 2px ＋ offset 1px でボタンの外側 3px に描かれるが、overflow: auto はその外側を切るので、
   末尾の操作列（DialogButtons）の枠が下端と右端で欠けていた。負の外余白で打ち消すので中身の位置は変わらない。 */
.dialog-form,
.app-popup-scroll {
    max-height: calc(74vh / var(--alt-vz, 1));
    overflow: auto;
    padding: 4px;
    margin: -4px;
}

.dialog-form { max-width: var(--alt-form-max); }
/* 窓の操作列（DialogButtons）は、中身がスクロールしても窓の下端に貼り付ける（2026-10-05・TEST1-465）。
   スクロールするのは上の .dialog-form（74vh で切る）で、操作列はその中の末尾にあるため、項目の多い窓
   （商品・取引先の追加）では保存とキャンセルがスクロールしないと見えなかった。中身が収まる窓では何もしない。
   **.dialog-form の直下に限る**＝ページ直置きの操作列（.app-split-body の下など）は貼り付けない。
   **背景は窓の地の色で塗る**＝貼り付いた操作列の下を中身が流れるので、透けると文字が重なる。
   上の間隔は margin ではなく padding で取る（margin の帯は塗られず、そこから中身が透ける）。
   **下は 4px の逃げ場を自分で持つ**＝底に着くとボタンのフォーカスの枠（外側 3px）が .dialog-form の端で切れるので、内側に取る。
   **上の規則と違い、負の下余白で外へは押し出さない**（2026-10-14）＝sticky は .dialog-form の padding の内側の端までしか
   下がれないので、押し出した 4px だけ操作列が上へ戻され、スクロールしない窓でも直前の項目（備考のメモなど）の下の枠に
   重なって見切れていた。窓の下の余白はそのぶん 4px 増える。
   **貼り付く位置は -4px**（2026-10-15・TEST1-624）＝bottom: 0 だと sticky は .dialog-form の padding の内側の端で止まり、
   中身がスクロールする窓では操作列の下に padding の 4px の帯が塗られずに残って、流れる項目の文字が透けていた。
   -4px で padding の帯まで下げて塗る。中身が収まる窓では、操作列の元の位置がこの範囲の内側にあるので動かない
   （上の「直前の項目に重ならない」はそのまま保てる）。 */
.dialog-form > .dialog-buttons {
    position: sticky;
    bottom: -4px;
    z-index: 1;
    margin-top: 0;
    padding-top: 1rem;
    padding-bottom: 4px;
    background: var(--dxbl-popup-bg, var(--alt-surface));
}
/* ページに直置きした入力カードの操作列も、画面の下端（ステータスバーの上）に貼り付ける（2026-10-05・TEST1-473）。
   課題の編集・登録は項目が多く、幅 1400×高さ 900 の画面でも保存がスクロールしないと押せなかった。
   **印（alt-sticky-actions）を付けた操作列だけ**＝伝票の編集のように、操作列の下にも中身が続く画面まで貼り付けない。
   **カードの直下に置く**＝sticky は親の中でしか動かないので、カードの末尾にあれば、カードが画面に残っている間だけ下端に留まる。
   貼り付く高さはステータスバーと同じ式から出す（フローティングではバーが --alt-sidebar-bottom だけ浮く。layouts.css）。
   **左右はカードの余白まで塗る**＝貼り付いた操作列の下を中身が流れるので、余白の帯から文字が透けないようにする。
   下の 4px の逃げ場は窓の規則と同じ理由（ボタンのフォーカスの枠がステータスバーの下に隠れない）。
   **一覧の中（iframe）では画面の端に貼る**＝そこではステータスバーを描かないので、バーの高さだけ浮くと下から中身が透ける。 */
.alt-card > .dialog-buttons.alt-sticky-actions {
    position: sticky;
    bottom: calc(var(--alt-sidebar-bottom) + var(--alt-statusbar-height));
    z-index: 3;
    margin: 0 calc(-1 * var(--alt-card-pad)) -4px;
    padding: 1rem var(--alt-card-pad) 4px;
    background: var(--alt-surface);
}
html[data-alt-embed] .alt-card > .dialog-buttons.alt-sticky-actions { bottom: 0; }
/* 窓（DxPopup）の幅は、画面の幅から左右の余白を引いた値で止める（2026-09-17）。
   画面は `Width="min(560px, 96vw)"` のように書くが、DevExpress は窓の外側に余白（--dxbl-popup-margin＝28px）を
   足すので、375px の画面で 96vw の窓は 28〜388px になり右へ 13px はみ出していた（94vw でも 5px）。
   窓を包む dxbl-modal-root が横にスクロールし、閉じるボタンやキャンセルが端で切れる。
   **幅を指定した窓（dxbl-popup-fixed-width）だけに当てる**＝指定の無い窓は DevExpress が自分で収めており
   （576px 以上は --dxbl-popup-max-width、375px でも 28〜347px。実測）、上書きすると広い画面で窓が伸びる。
   **セレクタは DevExpress の `max-width: unset` の規則（テーマの core.min.css）の写し**＝版を上げたら同じ規則を探して
   揃えること。当たらなくなっても例外は出ず、黙ってはみ出しに戻る。詳細度は向こうと同じで、いまは app.css が後に読まれて
   勝つが、読み込み順に頼らないよう !important を付ける。
   上限が効くのは窓と左右の余白が画面に収まらないとき（＝はみ出していたとき）だけなので、収まっていた窓の見た目は変わらない。 */
.dxbl-modal > .dxbl-modal-root > .dxbl-popup.dxbl-popup-fixed-width {
    max-width: calc(100vw / var(--alt-vz, 1) - 2 * var(--dxbl-popup-margin, 28px)) !important;
}

/* 窓の本文と足元の余白（2026-10-10・DevExpress 26.1 への版上げ）。
   25.2 までは全画面に読んでいた帳票ビューアの CSS（dx-blazor-reporting-components.fluent.css）がこの規則を持っていて、
   ビューアの外の窓にも効いていた。どの窓もこの余白で組んであり、Pm の簡易ビューの幅の計算（pm.css の .pm-qv-scroll）も 16px を前提にしている。
   26.1 でビューアの規則がテーマの core.min.css へ移り、この 2 つはビューアの確認の窓だけに絞られたので、
   ここで言い直さないと全部の窓がテーマの値（本文 4px 24px・足元 12px 24px 24px）に変わる（例外もログも出ず、余白だけが変わる）。
   **セレクタは旧規則の写し**（クラス 6 つ）。!important は付けない＝窓ごとに自分のクラスで余白を持つ所（.pm-qv-scroll）が !important で勝てるように。 */
.dxbl-modal .dxbl-modal-root .dxbl-popup.dxbl-popup-adaptivity .dxbl-modal-content .dxbl-modal-body {
    padding: 16px 16px 8px 16px;
}
.dxbl-modal .dxbl-modal-root .dxbl-popup.dxbl-popup-adaptivity .dxbl-modal-content .dxbl-modal-footer {
    padding: 8px 16px 16px 16px;
}

/* 窓は見出しを掴んで動かせる（2026-09-26。決めごとは docs/claude/module-wiring.md の「窓はすべてマウスで動かせる」）ので、掴める見た目にする。
   DxPopup は AllowDrag を渡すと窓の要素に allow-drag の属性が付く（実測）。確認の窓（DxMessageBox）はその属性が付かず、
   動かすのは js/popup-drag.js なので、クラスで別に選ぶ。
   **`!important` が要る**（2026-09-07 に Pm の簡易ビューで実測。TEST1-89）＝DevExpress が `cursor: default` をクラス 5 つのセレクタで指定していて、
   クラスを重ねても勝てない。当たらなくても例外は出ず、動かせるのに掴める見た目が出ないだけになる。 */
dxbl-modal-dialog[allow-drag] .dxbl-popup-header,
dxbl-modal-dialog.dxbl-message-box .dxbl-popup-header {
    cursor: move !important;
}

/* ===== 入力の幅（全画面共通。2026-08-26） =====
   **入力は値にふさわしい大きさで止める**。列や画面いっぱいに伸ばすと、2 文字を選ぶだけの項目でも
   ドロップダウンのボタンが画面の端まで離れ、1 つ選ぶのに目と手が画面を横切ることになる。
   効かせるのは DevExpress のテキスト系エディタだけ＝テキスト・数値・日付・コンボはどれも
   .dxbl-text-edit を持つ（実測）。チェックボックス（.dxbl-checkbox）には触らない。
   長い文が入るメモ（.dxbl-memo-edit）と、名前がいくつも並ぶタグ入力（.dxbl-tag-box）は除く＝
   狭めると折り返しが増えるだけで読みにくくなる。
   **2 列ぶち抜き（alt-span2）の項目は対象にしない**＝住所・備考・説明のように、そこを選んだ時点で
   作者が「広く取る」と決めているもの。ここまで狭めると、いまより読みにくい画面ができてしまう。
   **既定は :where() で包んで詳細度を 0 にしてある**＝下の alt-w-* も、画面ごとの指定も、
   読み込み順に関係なく必ず勝つ。ここを普通のセレクタで書くと、細かく決めた個別の幅が
   黙って既定に上書きされる（例外もログも出ず、見た目だけで表に出る）。
   **欄とボタンを横に並べる行の直下も同じ上限**（2026-09-23）＝DevExpress の欄は既定で幅 100% なので、幅を決めていない欄が
   行いっぱいに伸び、隣のボタンが次の行の右端へ離れていた（部品表・工順の品目選択＝1300px、メンバー追加の役割、
   先行指図の選択）。並べる行は一覧の上のツールバー（.grid-toolbar）と、モジュールの横並び（Pm の .pm-inline＝
   シェルの画面も借りている・生産の .prod-dep-add）。**横並びの行を新しく作ったらここに足す**＝モジュールの CSS に
   同じ式を写すと、除外（メモ・タグ）を直した日に片方だけ古いまま残る。幅を名乗っている欄（.alt-keyword-box・.pm-date ほか）は
   詳細度で勝つので変わらない。 */
:where(.dialog-form, .alt-form-grid > div:not(.alt-span2), .grid-toolbar, .pm-inline, .prod-dep-add) > :where(.dxbl-text-edit:not(.dxbl-memo-edit):not(.dxbl-tag-box)) {
    max-width: var(--alt-input-max);
}

/* 素の入力欄（HTML の input・select）を DevExpress のエディタと同じ高さ・枠・角丸・上限にする（2026-09-10）。
   time／date のように DevExpress の部品が受けない型はモジュールが素の input で置いており、そこだけ高さが
   ブラウザ既定（約 22px）で隣の DxTextBox（32px）と揃っていなかった。
   **画面が名乗る**（`class="alt-input"`）＝先祖の形（.dialog-form の直下など）から入力欄を当てにいく規則は、
   置き場が 1 段深いだけで届かない（シフトの実績の time 欄がそうだった）のに、外れても例外もログも出ない。
   幅の上限はモジュールの指定（.shift-input-time の 140px）や alt-w-* が勝つ＝どちらも後に読まれる。
   ログイン画面の .field-input は別物（あちらは Figma の寸法）。 */
.alt-input {
    box-sizing: border-box;
    width: 100%;
    height: var(--alt-control-height);
    max-width: var(--alt-input-max);
    padding: 0 9px;
    border: 1px solid var(--alt-border-strong);
    border-radius: var(--alt-control-radius);
    background: var(--alt-surface);
    color: var(--alt-text-body);
    font: inherit;
    font-size: 14px;
    line-height: normal;
    box-shadow: none;
}

.alt-input:focus {
    outline: none;
    border-color: var(--alt-accent);
}

/* 値の性質で選ぶ幅。既定より狭めたい・広げたいものに付ける（どれを何にするかは各画面の doc が正）。 */
.alt-w-sm { max-width: 150px; }    /* 日付・時間・数量＝桁数が決まっている */
.alt-w-md { max-width: 220px; }    /* 区分・状態＝短い語を選ぶ */
.alt-w-lg { max-width: 320px; }    /* 氏名・マスタの名称が入る */
.alt-w-full { max-width: none; }   /* 件名・住所・URL＝長さが決まらないので止めない */


/* ダイアログの縦積みフォーム（ラベル＋入力を1列に並べる）。ファイル選択のボタンは外す（理由は .alt-form-grid label と同じ） */
.dialog-form > label:not(:where(.alt-file-btn)) {
    display: block;
    margin-top: 0.6rem;
    margin-bottom: 0.2rem;
    font-size: 0.85rem;
    color: var(--alt-text-sub);
}
.dialog-form > label:not(:where(.alt-file-btn)):first-child { margin-top: 0; }

/* 読み上げ専用テキスト（アイコンだけのボタンのラベル用）。 */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* ===== 2段階認証（Phase7） ===== */

/* コード入力画面下部の入力方法切替リンク */
.login-2fa-links {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: 16px;
    font-size: 0.85rem;
}

.login-2fa-links a {
    color: var(--alt-brand);
    text-decoration: none;
}

.login-2fa-links a:hover {
    text-decoration: underline;
}

/* 副ボタン（メールコード送信など） */

/* 設定画面: QRコードと手入力用キー */
.twofa-qr {
    display: block;
    width: 180px;
    height: 180px;
    margin: 8px auto;
    image-rendering: pixelated;
}

.twofa-key {
    display: block;
    text-align: center;
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-size: 0.85rem;
    letter-spacing: 0.06em;
    background: var(--alt-bg-secondary);
    border: 1px solid var(--alt-border-secondary);
    border-radius: var(--alt-radius-sm);
    padding: 6px 8px;
    margin: 4px 0 10px;
    word-break: break-all;
    user-select: all;
}

/* リカバリーコード一覧（表示は有効化直後・再生成時の1回のみ） */
.twofa-codes {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 4px 16px;
    list-style: none;
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    background: var(--alt-bg-secondary);
    border: 1px solid var(--alt-border-secondary);
    border-radius: var(--alt-radius-sm);
    padding: 10px 14px;
    margin: 8px 0;
}

.twofa-note {
    font-size: 0.82rem;
    color: var(--alt-text-tertiary);
    margin: 4px 0 10px;
}

.twofa-status {
    display: inline-block;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 0.82rem;
    font-weight: 600;
}

.twofa-status-on {
    background: var(--alt-status-resolved-bg);   /* 地だけ状態の札の緑を借りる（ダークで言い直される）。文字は成功の色のまま＝ライトの見た目を変えない */
    color: var(--alt-success-text);
}

.twofa-status-off {
    background: var(--alt-danger-bg);
    color: var(--alt-danger-text);   /* 地と同じくダークで言い直される。ライトは直書きだった #991b1b とほぼ同じ色 */
}

/* 設定画面の操作ボタン群（有効時） */
.twofa-actions {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 12px;
}

/* ===== ユーザーアイコン（アバター）と個人設定（Phase7。2026-08-07 ユーザー要望） ===== */

/* アイコン本体。画像は /user-icons/{userId} が返す（未登録なら頭文字のSVG）。
   縦横比の違う画像でも崩れないよう cover で切り抜く。 */
.app-avatar {
    display: inline-block;
    flex: none;
    object-fit: cover;
    background: var(--alt-bg-secondary);
    vertical-align: middle;
}

.app-avatar {
    border-radius: 50%;
}

/* UserId が分からない場合のイニシャル表示（画像リクエストを出さない版）。 */
.app-avatar-initial {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--alt-on-accent);
    font-weight: 600;
    line-height: 1;
}

/* ---- 個人設定画面 /account/settings ---- */

.acct-header {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px 16px;
    margin-bottom: 16px;
    border: 1px solid var(--alt-border-secondary);
    border-radius: var(--alt-radius-xl);
}

.acct-header-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1;
}

.acct-header-name {
    font-size: 1rem;
    font-weight: 700;
    color: var(--alt-text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
}

.acct-header-meta {
    font-size: 0.82rem;
    color: var(--alt-text-tertiary);
    word-break: break-all;
}

.acct-logout-form {
    margin: 0;
    flex: none;
}

.acct-logout {
    padding: 8px 16px;
    border: 1px solid var(--alt-border-primary);
    border-radius: var(--alt-radius-md);
    background: var(--alt-bg-secondary);
    color: var(--alt-text-secondary);
    font-size: 0.88rem;
    font-weight: 600;
    cursor: pointer;
}

.acct-logout:hover {
    background: var(--alt-bg-page);
}

/* タブ（querystring で切り替えるので、実体はただのリンク） */
.acct-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    border-bottom: 1px solid var(--alt-border-secondary);
    margin-bottom: 16px;
}

.acct-tab {
    padding: 8px 14px;
    border: 1px solid transparent;
    border-bottom: none;
    border-radius: var(--alt-radius-sm) var(--alt-radius-sm) 0 0;
    color: var(--alt-text-secondary);
    text-decoration: none;
    font-size: 0.9rem;
    font-weight: 600;
    margin-bottom: -1px;
}

.acct-tab:hover {
    background: var(--alt-bg-secondary);
}

.acct-tab.is-active {
    background: var(--alt-bg-primary);
    border-color: var(--alt-border-secondary);
    color: var(--alt-brand);
}

.acct-panel {
    max-width: 720px;
}

.acct-section {
    max-width: 720px;
    margin-bottom: 24px;
}

.acct-section-title {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 1.05rem;
    font-weight: 700;
    margin: 0 0 12px;
}

.acct-sub-title {
    font-size: 0.95rem;
    font-weight: 700;
    margin: 12px 0 6px;
}

.acct-form {
    display: flex;
    flex-direction: column;
    gap: 12px;
    max-width: 420px;
}

.acct-submit {
    align-self: flex-start;
    padding: 9px 20px;
    border: none;
    border-radius: var(--alt-radius-md);
    background: var(--alt-brand);
    color: var(--alt-on-accent);
    font-size: 0.92rem;
    font-weight: 600;
    box-shadow: var(--alt-shadow-xs);
    cursor: pointer;
}

.acct-submit:hover {
    background: var(--alt-accent-hover);
}

.acct-submit-secondary {
    background: var(--alt-bg-secondary);
    color: var(--alt-text-secondary);
    border: 1px solid var(--alt-border-primary);
}

.acct-submit-secondary:hover {
    background: var(--alt-bg-page);
}

.acct-status {
    color: var(--alt-success-text);
    background: var(--alt-success-bg);
    border: 1px solid var(--alt-success-border);
    border-radius: var(--alt-radius-sm);
    padding: 6px 10px;
    font-size: 0.86rem;
    margin: 0 0 10px;
}

.acct-error {
    color: var(--alt-danger-strong);
    background: var(--alt-danger-bg);
    border: 1px solid var(--alt-danger-border);
    border-radius: var(--alt-radius-sm);
    padding: 6px 10px;
    font-size: 0.86rem;
    margin: 0 0 10px;
}

.acct-hint {
    font-size: 0.8rem;
    color: var(--alt-text-tertiary);
    margin: 4px 0 0;
}

/* 3 行以上の説明文の畳み（2026-09-23。畳む・開くの判定と差し込みは js/hint-fold.js）。
   **畳んだ状態は最初の文（最初の。まで）だけ見せる**（2026-09-24）＝(?) だけにすると何の説明かが押すまで分からず、
   1 行で切ると文の途中で終わる。見せるのは js が差し込んだ写し（.alt-fold-lead）で、元の中身は見えない所へ落とす
   （元のノードは Blazor のものなので包めない）。
   文の終わりが取れない段落（写しが無い）は従来どおり 1 行で切る。見えているところのどこを押しても開く。
   絵は文字で描く（? と ▲）＝色が文字色に付いてくるので、テーマごとに絵を用意しなくてよい。
   読み上げ名はボタンの aria-label が持つので、描いた文字は代替テキストを空にして読ませない（content の "/ ''"）。 */
[data-alt-fold="closed"] {
    cursor: pointer;
}
[data-alt-fold="closed"]:not(:has(> .alt-fold-lead)) {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 1;
    overflow: hidden;
}
/* 写しを 1 行目（ボタン｜写し）に置き、元の地の文は高さ 0 の 2 行目以降へ落として段落の外で切る。
   文字の大きさは変えない＝0 にすると em で決まる段落の余白まで消え、畳んだ段落どうしが詰まる（実測）。
   元の要素の子（リンクなど）は display: none にする＝高さ 0 の行に落とすだけだとタブ移動で見えないリンクに入る */
[data-alt-fold="closed"]:has(> .alt-fold-lead) {
    display: grid;
    grid-template-columns: 1.7em minmax(0, 1fr);
    grid-template-rows: auto;
    grid-auto-rows: 0;
    align-items: start;
    overflow: hidden;
}
[data-alt-fold="closed"] > .alt-fold-toggle:has(+ .alt-fold-lead) { grid-area: 1 / 1; margin-top: 0.1em; }
[data-alt-fold="closed"] > .alt-fold-lead { grid-area: 1 / 2; display: block; }
[data-alt-fold="closed"]:has(> .alt-fold-lead) > :not(.alt-fold-toggle, .alt-fold-lead) { display: none !important; }
.alt-fold-lead { display: none; }
.alt-fold-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: 1.35em;
    height: 1.35em;
    margin: 0 0.35em 0 0;
    padding: 0;
    border: 1px solid currentColor;
    border-radius: 50%;
    background: transparent;
    color: var(--alt-accent);
    font: inherit;
    font-weight: 700;
    line-height: 1;
    vertical-align: text-bottom;
    cursor: pointer;
}
.alt-fold-toggle::before { content: "?" / ""; }
[data-alt-fold="open"] > .alt-fold-toggle { border-color: transparent; }
[data-alt-fold="open"] > .alt-fold-toggle::before { content: "▲" / ""; font-size: 0.8em; }
.alt-fold-toggle:focus-visible { outline: 2px solid var(--alt-accent); outline-offset: 2px; }

/* 入力できないカスタム項目の値（2026-08-30。フォームの式の列）。**入力欄と同じ高さに置く**＝
   ほかの項目と行がずれると、打てないことより先に「壊れている」と読まれる。
   点線にしているのは、空の入力欄との見分けが枠線の種類だけで付くため。 */
.alt-readonly-value {
    margin: 0;
    padding: .35rem .5rem;
    min-height: 2.25rem;
    border: 1px dashed var(--alt-border);
    border-radius: 6px;
    background: transparent;
}

/* 縦に並ぶ入力欄のあいだに置く「OR」の区切り（2026-08-28。機能権限の設定ダイアログ・ログイン画面の「パスキーでログイン」の上）。
   欄が上下に並ぶだけだと全部埋めないと成立しないように読めるので、
   どれか 1 つでよいことを欄と欄のあいだで伝える。文字は resx から渡す。 */
.alt-or-sep {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 12px 0 2px;
    color: var(--alt-text-tertiary);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
}

.alt-or-sep::before,
.alt-or-sep::after {
    content: "";
    flex: 1 1 auto;
    height: 1px;
    /* --alt-border はテーマによって背景とほぼ同じ色になり、線が見えない */
    background: var(--alt-border-strong);
}

.acct-readonly {
    margin: 0;
    padding: 8px 0;
    font-size: 0.92rem;
    color: var(--alt-text-secondary);
    word-break: break-all;
}

/* プロフィールタブのアイコン欄 */
.acct-avatar {
    display: flex;
    align-items: flex-start;
    gap: 20px;
    margin-bottom: 20px;
}

.acct-avatar-img {
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}

.acct-avatar-ops {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    min-width: 0;
}

/* 自作の線画の登録（テーマタブ。CustomMotifEditor）。枠ごとに見本・名前・ファイル選択を横に並べる。 */
.motif-custom {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-bottom: 16px;
}

.motif-custom-slot {
    display: flex;
    align-items: flex-start;
    gap: 16px;
}

.motif-custom-slot .motif-thumb {
    flex: 0 0 160px;
}

.motif-custom-ops {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    min-width: 0;
}

.motif-custom-name {
    font-weight: 600;
}

.motif-custom-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

@media (max-width: 640px) {
    .motif-custom-slot {
        flex-direction: column;
    }
}

/* メール通知タブ */

@media (max-width: 640px) {
    .acct-header {
        flex-wrap: wrap;
    }

    .acct-avatar {
        flex-direction: column;
    }
}

/* サイドバー常駐アカウントのアイコン（AccountMenu）。押せることが分かるよう薄い枠を付ける。 */
.app-account-avatar {
    box-shadow: 0 0 0 1px var(--alt-border-secondary);
}

/* ===== 個人設定「テーマ」タブ（2026-08-10） ===== */
.theme-pick {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    margin: 12px 0 18px;
}

.theme-card {
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 200px;
    padding: 12px;
    border: 2px solid var(--alt-border);
    border-radius: var(--alt-radius-md);
    background: var(--alt-surface);
    cursor: pointer;
}

.theme-card:hover {
    border-color: var(--alt-border-strong);
}

/* 選択中のカード。SSR タブなので JS ではなく :has() で追随させる（クリックで即時にハイライトが移る） */
.theme-card:has(input[type="radio"]:checked) {
    border-color: var(--alt-accent);
    background: var(--alt-accent-soft);
}

/* キーボード操作（矢印キーで選択）でも位置がわかるように */
.theme-card:focus-within {
    outline: 2px solid var(--alt-accent);
    outline-offset: 2px;
}

/* ラジオ本体は隠す（カード全体がラベル） */
.theme-card input[type="radio"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.theme-card-name {
    font-weight: 700;
    color: var(--alt-text-strong);
}

.theme-card-desc {
    font-size: 0.8rem;
    color: var(--alt-text-sub);
}

/* CSSだけで描くミニプレビュー（2026-09-10 にトークン参照へ寄せた）。
   **色は themes.css のテーマの定義そのもの**＝各テーマの選択子に .theme-thumb-{名前} が併記してあり、
   見本の箱にそのテーマのトークンが乗る。ここは「トークンをどこに塗るか」だけを持つ。
   ライトだけは themes.css にブロックが無い（app.css の :root が既定）ので、見本には値を書く＝
   書かないと、いま選んでいるテーマのトークンを継承して見本が本物と違う色になる。 */
.theme-thumb {
    display: flex;
    height: 72px;
    border-radius: var(--alt-radius-sm);
    border: 1px solid var(--alt-border);
    overflow: hidden;
    background: var(--alt-bg-page);
}

.theme-thumb-side { width: 26%; background: var(--alt-bg-primary); border-right: 1px solid var(--alt-border); }

.theme-thumb-main {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 8px;
}

.theme-thumb-bar { height: 8px; width: 60%; border-radius: 3px; background: var(--alt-accent); }
.theme-thumb-card { flex: 1; border-radius: 4px; background: var(--alt-surface); border: 1px solid var(--alt-border); }

.theme-thumb-light {
    --alt-bg-page: #f4f6f9;
    --alt-bg-primary: #ffffff;
    --alt-surface: #ffffff;
    --alt-border: #e3e8ef;
    --alt-accent: #2c6fd9;
}

/* サイドバーのカスタム配色（テーマタブ内。2026-08-10） */
.theme-side {
    margin: 4px 0 18px;
    padding: 12px;
    border: 1px solid var(--alt-border);
    border-radius: var(--alt-radius-md);
    background: var(--alt-bg-subtle);
}

.theme-side-check {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-right: 12px;
    font-weight: 600;
    color: var(--alt-text-strong);
    cursor: pointer;
}

/* 線画の濃さ（2026-09-25）。見出しと説明はほかの軸と同じ acct-sub-title／acct-hint で、ここは選択肢の並びだけ。 */
.motif-strength {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 24px;
    margin: 4px 0 10px;
}

.motif-strength-option {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
}

.theme-side-color {
    width: 48px;
    height: 28px;
    padding: 0;
    border: 1px solid var(--alt-border-strong);
    border-radius: var(--alt-radius-sm);
    background: var(--alt-surface);
    vertical-align: middle;
    cursor: pointer;
}

/* レイアウト（ヘッダーとサイドメニューの形）のミニプレビュー（2026-09-10）。**テーマの見本（ライト）の色と部品を
   そのまま使い**（.theme-thumb-light ＋ .theme-thumb-side／-main）、上の帯（ヘッダー）を足した格子にするだけ
   ＝色の直値をもう 1 組持たない。形の本体は wwwroot/layouts.css。 */
.layout-thumb {
    display: grid;
    grid-template-columns: 26% 1fr;
    grid-template-rows: 12px 1fr;
}

.layout-thumb .theme-thumb-side { width: auto; }   /* 幅は格子の列が決める */

.layout-thumb-top {
    grid-column: 1 / -1;
    background: #ffffff;
    border-bottom: 1px solid #e3e8ef;
}

/* 背景の線画（2026-09-10）。**名前 → 絵の表はここ 1 か所**＝<html data-motif> にも個人設定の見本
   （<span class="motif-thumb" data-motif="…">）にも同じ属性セレクタで当たる。敷く場所と濃さは wwwroot/motifs.css。
   **絵は 2 版**＝要の絵が濃い線（明るい面用。--alt-motif）と白線（アクセントのヘッダー・濃いサイドバー・ダーク用。
   --alt-motif-light）。どちらを使うかは motifs.css が面ごとに選ぶ。タイルは 400px（200px の区画 4 つで要の絵を市松に置く）。
   見本の基底は --alt-motif を none にしておく＝「なし」の見本が <html> の柄を継承して映さないため
   （同じ詳細度なので、属性の規則をこの後ろに置く）。 */
.motif-thumb {
    --alt-motif: none;
    background: var(--alt-surface) var(--alt-motif) center top / 200px repeat;
}

/* --alt-motif-header-y はヘッダーの帯（56px）に見せるタイルの高さ（負の値＝タイルをその分だけ上へずらす）。
   要の絵は枝（上の幹線）の下にぶら下がるものと上に乗るものがあり、高さが線画ごとに違う＝帯に収まる位置を線画が名乗る
   （2026-09-10。ぶどうが帯の下で切れていた）。値は生成した SVG の要の絵の縦の範囲から決めてある。 */
[data-motif="spring"] { --alt-motif: url('img/motifs/spring.svg'); --alt-motif-light: url('img/motifs/spring-light.svg'); --alt-motif-header-y: -36px; }
[data-motif="summer"] { --alt-motif: url('img/motifs/summer.svg'); --alt-motif-light: url('img/motifs/summer-light.svg'); --alt-motif-header-y: -14px; }
[data-motif="autumn"] { --alt-motif: url('img/motifs/autumn.svg'); --alt-motif-light: url('img/motifs/autumn-light.svg'); --alt-motif-header-y: -36px; }
[data-motif="winter"] { --alt-motif: url('img/motifs/winter.svg'); --alt-motif-light: url('img/motifs/winter-light.svg'); --alt-motif-header-y: -34px; }
[data-motif="modern"] { --alt-motif: url('img/motifs/modern.svg'); --alt-motif-light: url('img/motifs/modern-light.svg'); --alt-motif-header-y: -48px; }
[data-motif="sumi"] { --alt-motif: url('img/motifs/sumi.svg'); --alt-motif-light: url('img/motifs/sumi-light.svg'); --alt-motif-header-y: -140px; }
[data-motif="machine"] { --alt-motif: url('img/motifs/machine.svg'); --alt-motif-light: url('img/motifs/machine-light.svg'); --alt-motif-header-y: -22px; }
[data-motif="computer"] { --alt-motif: url('img/motifs/computer.svg'); --alt-motif-light: url('img/motifs/computer-light.svg'); --alt-motif-header-y: -19px; }
[data-motif="sweets"] { --alt-motif: url('img/motifs/sweets.svg'); --alt-motif-light: url('img/motifs/sweets-light.svg'); --alt-motif-header-y: 0px; }

/* 自作の線画（custom1／custom2。2026-09-24）。絵は人ごとに違うので表に書けず、<html> と見本の style が
   --alt-motif-custom／--alt-motif-custom-light で渡す（UserMotifService.Slot.CssVariables）。ここはそれを 2 版の変数へ繋ぐだけ。
   **インラインで --alt-motif を直接渡さない**＝motifs.css の html[data-theme="dark"] の差し替えにインラインが勝つ。
   **見本は絵の全体を枠に収める**（2026-09-27）＝原寸で敷くと 160×72 の枠には絵の上端しか映らず、写真のような大きな絵では
   紙の地しか見えないので、差し替えても前の絵と見分けがつかない（「上書きされていない」と見える）。 */
[data-motif^="custom"] { --alt-motif: var(--alt-motif-custom); --alt-motif-light: var(--alt-motif-custom-light); }
.motif-thumb[data-motif^="custom"] { background-size: contain; background-repeat: no-repeat; background-position: center; }

/* ダークテーマの見本は面が暗いので白線の版（本体の選び分けは motifs.css）。 */
html[data-theme="dark"] .motif-thumb[data-motif] { --alt-motif: var(--alt-motif-light); }

/* クラシック＝ヘッダー無し。サイドバーが上まで伸びる（行の高さ 0 と非表示の両方が要る＝片方だと 1px の下線が残る）。 */
.layout-thumb-classic { grid-template-rows: 0 1fr; }
.layout-thumb-classic .layout-thumb-top { display: none; }
.layout-thumb-classic .theme-thumb-side { grid-row: 1 / -1; }

/* アクセント＝ヘッダーがアクセント色のグラデーション。 */
.layout-thumb-accent .layout-thumb-top { background: linear-gradient(90deg, #2c6fd9, #1a44c2); border-bottom: none; }

/* フローティング＝どれも角丸のカードで浮く。 */
.layout-thumb-floating { padding: 4px; gap: 4px; }
.layout-thumb-floating .layout-thumb-top,
.layout-thumb-floating .theme-thumb-side,
.layout-thumb-floating .theme-thumb-card { border: none; border-radius: 4px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.14); }

/* ===== Culminans シェル追加分（chaser には無い、または既定に頼っていた小物） ===== */

/* 補足説明の小さな文字（一覧の注記など） */
.meta {
    color: var(--alt-text-sub);
    font-size: 0.85rem;
}

/* 件数・合否を短く言うピル（取り込みの下見の件数・機能権限のモード・IP 制限の状態）。
   形は重要度バッジ（.alt-annc-level）と同じだが、**規則は共有しない**＝あちらの 3 段は
   重要度（is-info / is-warning / is-critical）、こちらは合否（is-success / is-danger / is-warning）で、
   名前が重なるのは is-warning だけ。まとめると片方の段を足した日にもう片方に無い色が生える。
   色は状態トークンなので、テーマ（dark / kinpekishu / sakura ほか）に自動で追従する。

   **グリッドのセルにも入る**（FormImport・AdminPermissions の状態列）ので、
   **外形の高さを 15px に収める**（`line-height` を詰め、上下の padding を持たない）。
   DevExpress のセルは行内でいちばん背の高いものに合わせて伸びるので、ここを 21.8px にすると
   **バッジのある行だけ 24px → 30.8px** になる（`SizeMode.Small` で実測。2026-09-08）。
   `vertical-align` では直らない＝インラインボックスの高さがそのまま行の高さを決めるため。 */
.alt-badge {
    display: inline-block;
    font-size: 0.74rem;
    font-weight: 700;
    line-height: 1.1;
    padding: 0 8px;
    border-radius: 10px;
    white-space: nowrap;
    background: var(--alt-bg-muted);
    color: var(--alt-text-sub);
    border: 1px solid var(--alt-border);
}

.alt-badge.is-success { background: var(--alt-success-bg); color: var(--alt-success-text); border-color: var(--alt-success-border); }
.alt-badge.is-danger  { background: var(--alt-danger-bg);  color: var(--alt-danger-text);  border-color: var(--alt-danger-border); }
.alt-badge.is-warning { background: var(--alt-warning-bg); color: var(--alt-warning-text); border-color: var(--alt-warning-border); }

/* 状態の札と優先度の文字（2026-09-28・TEST1-250）。PM の課題とお問合せ管理のやり取りは同じ 4 状態・3 段の優先度を持つので、
   形と色はここ 1 か所に置く＝モジュールの CSS に写すと、片方の色を変えた日にもう片方だけ古い色で残る（例外もログも出ない）。
   クラスを組むのは Pm の IssueEnums と Mailbox の MailThreadStates。

   **高さ**: .alt-badge と違い line-height を詰めていない（外形 19px）。課題一覧（33px）・受信ボックス（39px）の行より低く、
   行を伸ばしていない（2026-09-28 に実測）。padding・font-size・line-height を変えるときは、両方の一覧の行の高さを測り直すこと
   （.alt-badge の注意と同じ理由＝DevExpress のセルは行内でいちばん背の高いものに合わせて伸びる）。 */
.alt-status-pill { display: inline-block; padding: 1px 10px; border-radius: 999px; font-size: 0.8rem; white-space: nowrap; }
.alt-status-pill.is-open { background: var(--alt-bg-muted); color: var(--alt-text-strong); }
.alt-status-pill.is-inprogress { background: var(--alt-status-inprogress-bg); color: var(--alt-status-inprogress-text); }
.alt-status-pill.is-resolved { background: var(--alt-status-resolved-bg); color: var(--alt-status-resolved-text); }
.alt-status-pill.is-closed { background: var(--alt-status-closed-bg); color: var(--alt-status-closed-text); }
.alt-prio-high { color: var(--alt-danger); font-weight: 600; }
.alt-prio-mid { color: var(--alt-text-muted); }
.alt-prio-low { color: var(--alt-accent); }

/* ダイアログ下部のボタン列（保存／キャンセル）。
   **幅が足りなければ列ごと折り返す**（2026-09-16）＝折り返さないとボタンのほうが縮み、
   日本語は 1 字ごとに改行できるので「配／置」のように縦に割れる（スマホの幅で 4 つ並べると起きた）。
   入りきる列には効かないので、ボタンが少ない窓の見た目は変わらない。 */
.dialog-buttons {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 0.5rem;
    margin-top: 1rem;
}

/* 「続けて登録」が通ったことをダイアログの中に出す文（操作列の左端）。
   画面上部のバナーは開いたままの窓に隠れて読めないので、押したボタンの隣に置く。 */
.dialog-buttons-info {
    margin-right: auto;
    align-self: center;
    color: var(--alt-accent-hover);
    font-size: 0.85rem;
}

/* Ctrl/Command + Enter で押されるボタンの印（.alt-submit ／ Shift つきは .alt-submit-continue）。
   **見た目は持たないので規則も無い**＝どのボタンが主かは RenderStyle が示しており、
   これは js/submit-shortcut.js だけが読む目印。**規約と理由はその冒頭の doc が正**。 */

/* ESC で押される「一覧へ戻る」ボタンの印（.alt-esc-back）。上と同じく**見た目は持たない**
   ＝付けるのは自前の確認（未保存の破棄）を持つ画面だけで、付けなければシェルが聞いて一覧へ戻す。
   **付けてよいのは本文に出るボタンだけ**（窓の中には置かない）。
   **規約と理由は js/esc-back.js の冒頭の doc が正**。 */

/* フローティングメニュー内の件数バッジ（項目文字の右に添える） */
.app-flyout-badge {
    margin-left: auto;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--alt-danger);
    color: var(--alt-on-accent);
    font-size: 0.7rem;
    line-height: 1.5;
}

/* ダッシュボードのモジュール一覧 */
.home-modules {
    max-width: 640px;
}
.home-modules code {
    font-size: 0.85em;
}

/* ===== 表示言語の切替（CultureSwitcher。ログイン画面下部・個人設定「言語」タブ） ===== */
.lang-switch {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 0;
}

.lang-switch-item {
    appearance: none;
    border: 1px solid var(--alt-border-strong);
    border-radius: 999px;
    background: var(--alt-surface);
    color: var(--alt-text-secondary);
    padding: 4px 14px;
    font: inherit;
    font-size: 0.85rem;
    line-height: 1.5;
    cursor: pointer;
}

.lang-switch-item:hover {
    background: var(--alt-bg-muted);
    color: var(--alt-text-primary);
}

.lang-switch-item.is-current {
    background: var(--alt-accent);
    border-color: var(--alt-accent);
    color: var(--alt-on-accent);
    cursor: default;
}

/* ログイン画面: カード下部に中央寄せで小さく */
.login-lang {
    justify-content: center;
    margin-top: 1.25rem;
}

/* パスワードのログインと「パスキーでログイン」の区切り（TEST1-808）。並びの間隔はフォームの gap が持つ */
.login-form .alt-or-sep {
    margin: 0;
}

/* 公開デモの入口（ログインの下。DemoLoginEndpoints）。ログインのボタンと並ぶので枠線の控えめな形にする */
.login-demo {
    margin-top: 1.25rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--alt-border);
    text-align: center;
}

.login-submit.is-outline {
    display: block;
    border: 1px solid var(--alt-brand);
    background: transparent;
    color: var(--alt-brand);
    text-align: center;
    text-decoration: none;
}

.login-submit.is-outline:hover {
    background: var(--alt-surface);
}

.login-demo-hint {
    margin: 0.5rem 0 0;
    color: var(--alt-text-muted);
    font-size: 0.85rem;
}


/* 個人設定「言語」タブ: 少し大きめのボタン */
.lang-switch-cards .lang-switch-item {
    padding: 8px 22px;
    font-size: 0.95rem;
}

/* ===== 組織管理（/admin/organization）・ユーザー管理の所属欄 ===== */
.org-sample-card {
    border: 1px solid var(--alt-border);
    border-radius: var(--alt-radius-md);
    background: var(--alt-bg-subtle);
    padding: 1rem 1.25rem;
    margin: 0.5rem 0 1.25rem;
    max-width: 640px;
}
.org-sample-title {
    margin: 0 0 0.5rem;
    font-size: 1.05rem;
}

/* ユーザー編集ダイアログの所属一覧 */
.app-userorg { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.app-userorg td { border-top: 1px solid var(--alt-border); padding: 4px 8px 4px 0; vertical-align: middle; }
.app-userorg td.name { width: 45%; }

/* 役職などの短い選択コンボ */
.app-status-select { width: 160px; }
.member-select { width: 260px; }

@media (max-width: 900px) {
    .dialog-form .app-status-select,
    .dialog-form .member-select,
    .grid-toolbar .member-select {
        width: 100% !important;
        max-width: 100%;
    }
    .app-userorg td.name { width: auto; }
    .app-userorg td { display: block; border-top: none; padding: 2px 0; }
    .app-userorg tr { display: block; border-top: 1px solid var(--alt-border); padding: 6px 0; }
}

/* ===== お知らせベル（サイドバー）とお知らせ一覧（chaser から移植） ===== */
.app-bell {
    display: flex; align-items: center; gap: 8px; position: relative;
    padding: 8px 14px; margin: 0 8px 4px; border-radius: 6px;
    color: var(--alt-text-secondary); text-decoration: none; font-size: 0.9rem;
}
.app-bell:hover { background: var(--alt-bg-secondary); color: var(--alt-text-secondary-hover); }
.app-bell-badge {
    background: var(--alt-danger); color: var(--alt-on-accent); border-radius: 10px;
    font-size: 0.72rem; font-weight: 700; padding: 1px 7px; margin-left: auto;
}

/* アイコンモードではベルはアイコンだけにし、未読バッジは右上に重ねる。
   **包みは .app-sidebar**（理由はアイコンリストバーの節）＝書かないとヘッダーの絵だけのベル
   （下の .app-bell-compact）にも当たり、右端へ寄せる margin と余白とバッジの位置を上書きする。 */
@media (min-width: 1025px) {
    html.app-nav-icons .app-sidebar .app-bell { justify-content: center; padding: 8px 0; margin: 0 4px 6px; }
    html.app-nav-icons .app-sidebar .app-bell-label { display: none; }
    html.app-nav-icons .app-sidebar .app-bell-badge { position: absolute; top: 2px; right: 6px; margin-left: 0; padding: 0 5px; font-size: 0.65rem; }
}

/* 狭い画面では上部バーの右端にもベルを出す（TEST1-90）。
   **サイドバーの中だけに置いておけない**＝狭い画面のサイドバーはドロワーで、閉じているあいだは
   `translateX(-100%)` で画面外にある。未読バッジが見えるのはメニューを開いたときだけになり、
   シフトの欠員の知らせ（朝の稼働直前に部署の担当者へ飛ぶ）に気づけない。

   **サイドバー側のベルは消さない**＝ドロワーを開いているあいだは覆いの膜（.app-nav-scrim・z-index 40）が
   上部バー（z-index 30）を覆うので、2 つが同時に押せる状態にはならない。消すと「お知らせ」の行が
   画面幅によってメニューから消えることになり、メニューの中身が広い画面と食い違う。

   **1 つの部品を 2 か所へ出すことはできない**＝`transform` を持つ祖先はその子孫の `position: fixed` の
   包含ブロックになるので、ドロワーの中のベルを `fixed` で画面外から救い出すことは原理的にできない
   （試して溶かさないように理由を残す）。だから同じ部品を 2 つ置き、見えるほうだけを CSS で整える。

   **代償は「2 つとも動く」こと**＝`display: none` は Blazor の描画を止めないので、広い画面でも
   未読件数の問い合わせ（索引が効いて実測 0.135ms）と LISTEN の購読が 1 本ずつ余分に走る。
   部品 2 つなら安いが、**3 つ目を足すときはこの行を「安いから足してよい」と読まないこと**
   ＝そのときは未読件数を回線で 1 つに集約する話になる。 */
/* 帯の中の「絵だけのベル」（.app-bell-compact。置く側が NotificationBell の CssClass で名乗る）。
   帯の高さは 56px しかないので、アイコンとバッジだけにする（文字を出すとサービス名が押し出される）。
   狭い画面の上部バーと、ヘッダーを持つレイアウトのヘッダー（layouts.css）が同じ 1 つを使う＝
   バッジの形を変える日に片方だけ直る、を作らない。
   **アイコンモード（min-width: 1025px の節）と揃えたのは 2 点だけ**＝ラベルを消すことと、バッジを
   右上のピルに重ねること。位置と余白は箱が違う（あちらは縦のカラム、こちらは 56px の帯）ので合わせていない。

   **大きさは .app-nav-button に任せる**（置く側が NotificationBell へ渡す）＝40px の当たり判定と
   フォーカス枠を隣のハンバーガーと同じ 1 か所から取る。ここで計算し直すと、あちらを 44px にした日に
   ベルだけが 40px で残り、指で押したときの空振りとしてだけ表に出る。
   ここに要るのは「.app-bell の余白を外す」だけ（右端へ寄せるのは包みの .app-topbar-trail の仕事）。 */
.app-bell.app-bell-compact {
    margin: 0;
    padding: 0;
}
.app-bell-compact .app-bell-label { display: none; }
.app-bell-compact .app-bell-badge {
    position: absolute; top: 0; right: 0; margin-left: 0; padding: 0 5px; font-size: 0.65rem;
}

/* ベルは `<a>` から `<button>` になった（2026-09-12。PC 幅ではポップアップを開くため＝
   ポップアップ起動系は href を外す。docs/claude/pitfalls.md）。
   **button の既定（枠・背景・字体）を外すのは `.linklike` に任せる**＝置く側が名乗る（NotificationBell）。
   ここで綴ると `button.app-bell`（詳細度 0,1,1）になり、上の `.app-bell` の字の大きさと
   `.app-nav-button` の 40px に勝ってしまう＝「大きさは .app-nav-button に任せる」が黙って外れる。

   **サイドバーのベルだけ全幅にする**＝`<a>` はブロックで親の幅いっぱいに伸びていたが button は内容の幅に縮み、
   `margin-left: auto` で右端へ寄る未読バッジがアイコンの真横に来る（例外もログも出ず見た目だけで表に出る）。
   **包みは .app-sidebar**（アイコンリストバーの節と同じ理由）＝帯の中の絵だけのベルは
   `.app-nav-button` が決める 40px のままでよく、ここで伸ばしてはいけない。 */
.app-sidebar .app-bell { width: 100%; }

/* ===== 自分のアイコンから垂れ下がるメニュー（.app-account-pop）の直し 2 つ（2026-09-12） =====

   **① 白いメニューの中では線画を反転しない。**
   アイコンを白抜きにする指定は 3 か所にある（アクセントのヘッダー＝layouts.css、
   金碧珠と濃色サイドバー＝themes.css）。どれも「濃い地に乗る黒い線画」のためのものだが、
   このメニューはその子孫でありながら**白地に出る**ので、当たると白い線画が白地に乗って消える
   （例外もログも出ず、アイコンが無いようにしか見えない）。
   **`!important` が要る**＝打ち消す相手が 2 つの css に分かれており、しかも layouts.css は
   クラシックでは読まれない＝「どちらか一方の後ろに置く」では片方に届かない。
   **ダークテーマは打ち消さない**＝あちらはメニューの地も暗いので、反転したままが正しい。

   **② 縦に並ぶメニューでは間隔を空けない。**
   `.linklike + .linklike` は**横に並ぶボタン**のための規則。テーマと言語を `<button class="linklike">`
   にしたことで初めて縦のメニューに当たり、言語だけが 12px 右へずれた（実測）。
   ログアウトは `<form>` に包まれていて隣接兄弟にならないので、これまで表に出ていなかった。 */
html:not([data-theme="dark"]) .app-account-pop .alt-ico {
    filter: none !important;
}
.app-account-pop .linklike + .linklike {
    margin-left: 0;
}

/* ===== PC 幅で開く窓（お知らせ・テーマ・言語。2026-09-12） =====
   中身はページと同じ部品なので、ここに要るのは「窓の中で縦に流す」ことだけ。
   **3 つの窓で 1 つの名前**＝余白を直す日に片方だけ足す・消すが起きない。
   窓の帯が題を持っているので、中のセクションの見出しは出さない（同じ言葉が 2 行並ぶ）。 */
.app-popup-body {
    overflow-y: auto;
    padding: 12px 16px 16px;
}
.app-popup-body .acct-section { margin: 0; }
.app-popup-body .acct-section-title { display: none; }

.app-notif-list { list-style: none; margin: 0; padding: 0; }
.app-notif-list li {
    display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap;
    border-top: 1px solid var(--alt-border); padding: 10px 8px; cursor: pointer;
}
.app-notif-list li:hover { background: var(--alt-bg-page); }
.app-notif-list li.unread { background: var(--alt-accent-soft); font-weight: 600; }
/* 種別チップは文字を持たないので、baseline 揃えの行では自分で中央に置く。 */
.app-notif-list .alt-notif-kind,
.app-notif-list .alt-notif-ico { align-self: center; }
.app-notif-list .body { color: var(--alt-text-sub); font-size: 0.85rem; }
.app-notif-list .time { margin-left: auto; color: var(--alt-text-muted); font-size: 0.82rem; white-space: nowrap; }

/* ===== 一覧画面の共通部品（chaser の課題一覧から移植。Workflow・Sales 等のモジュール一覧が共用する） ===== */

/* 絞り込みツールバー（表示対象・キーワード・保存条件・フィルター類を横一列に）。右端の grid-toolbar は入れ子で余白ゼロ。
   **単独でも当たる**（2026-09-08）＝`.grid-toolbar` と併せて使う箇所が 18、単独が 19 ある。
   単独の側は `alt-inline-label` や `alt-status-select` を中に置いており、どちらも flex のアイテムである前提の
   指定（`align-self` と幅）を持つので、当たっていないと**綴った幅が黙って効かない**。
   併用の側は `.grid-toolbar` が同じ値を持つので計算値は変わらない（実測で突き合わせた）。
   **この位置を動かさないこと**＝`margin-top` が `.grid-toolbar` の `margin` 一括指定に勝つのは、
   重みが同じで**あとに書いてある**からで、上へ移すと上下の余白が静かに変わる。 */
.alt-toolbar-row2 {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.25rem;
}
.grid-toolbar.alt-toolbar-row2 .toolbar-right { margin-left: auto; }
.grid-toolbar.alt-toolbar-row2 .toolbar-right .grid-toolbar { margin: 0; display: flex; align-items: center; gap: 8px; }
.alt-inline-label { color: var(--alt-text-sub); font-size: 0.85rem; white-space: nowrap; }
/* 幅は .alt-toolbar-row2 の中でも要る（単独の 4 か所が使う）。keyword-box と date-select は
   単独の中に 1 つも無いので広げない＝要求が出てから足す。 */
.grid-toolbar .alt-status-select,
.alt-toolbar-row2 .alt-status-select { width: 180px; }
.grid-toolbar .alt-keyword-box { width: 260px; }
/* 期間の日付欄（仕入・売上分析）。幅を決めないと DevExpress のエディタが行いっぱいに広がる。 */
.grid-toolbar .alt-date-select { width: 150px; }

/* キーワード検索の結果件数 */
.alt-keyword-note { margin: 0 0 6px; }

/* 保存済み検索条件のチップリスト。名前ボタン=適用（選択中はもう一度で解除） / × ボタン=条件の削除 */
.alt-filter-chips { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin: 2px 0 8px; }
.alt-filter-chip { display: inline-flex; align-items: center; border: 1px solid var(--alt-border); border-radius: 999px; background: var(--alt-surface); }
.alt-filter-chip:hover { border-color: var(--alt-text-muted); }
.alt-filter-chip.is-active { background: var(--alt-accent-soft); border-color: var(--alt-accent); }
.alt-filter-chip-name,
.alt-filter-chip-x { border: none; background: none; cursor: pointer; font-size: 0.85rem; line-height: 1.4; color: var(--alt-text-strong); padding: 2px 2px 2px 10px; }
.alt-filter-chip.is-active .alt-filter-chip-name { font-weight: 600; color: var(--alt-accent); }
/* × を出さないチップ（Pm の Wiki のタグ）。上の非対称な余白は × が右に来る前提なので、単独なら右も戻す。 */
.alt-filter-chip-name:only-child { padding-right: 10px; }
.alt-filter-chip-x { padding: 2px 8px 2px 2px; color: var(--alt-text-muted); }
.alt-filter-chip-x:hover { color: var(--alt-danger); }

/* 検索条件の保存ダイアログ「いま保存される内容」プレビュー */
.save-filter-preview { display: flex; flex-direction: column; gap: 4px; border: 1px solid var(--alt-border); border-radius: 6px; background: var(--alt-bg-subtle); padding: 8px 12px; font-size: 0.85rem; margin-top: 8px; }
.save-filter-preview-row { display: flex; gap: 8px; }
.save-filter-preview-label { min-width: 5.5em; flex-shrink: 0; color: var(--alt-text-sub); }

/* キーワードのヒット箇所の抜粋（件名セルの下に小さく表示） */
.alt-hit { margin-top: 2px; color: var(--alt-text-sub); font-size: 0.8rem; line-height: 1.4; white-space: normal; word-break: break-word; }
.alt-hit .alt-hit-label { color: var(--alt-text-muted); }
.alt-hit mark { background: var(--alt-warning-border); color: inherit; padding: 0 1px; border-radius: 2px; }

/* 一覧の行の高さの下限を全画面で 32px に揃える（2026-09-30・TEST1-255）。
   SizeMode.Small の行は、文字だけなら 24px（行送り 16px ＋ 上下の余白 4px）で、
   操作列の絵（.alt-grid-commands の 24px）が入ると 32px になる。操作列の有無で一覧ごとに行の高さが変わり、
   24px の一覧は押しづらく詰まって見えていた。TEST1-254 では在庫と生産管理の一覧にだけクラスで付けたが、
   同じ理由がほかの一覧にも当てはまるので、クラスをやめて全体の既定にした（DxGrid と DxTreeList は同じ表の作りを持つ）。
   **高さは最小として効く**（表のセルの height は下限）＝折り返しや大きな中身で高くなる行は潰さない。
   受信ボックス（.alt-mail-rows の余白で 40px）や SizeMode.Medium の一覧は、もともと 32px を超えるので変わらない。
   **2 行目からは 33px**＝セルは border-box で、2 行目からは上の罫線 1px が高さに入る（操作列のある行も 32 / 33 / 33…）。
   **余白の変数（mailbox.css の .alt-mail-rows の方式）にしない**＝操作列のある行まで 40px に伸びる。 */
.dxbl-grid-table > tbody > tr[data-visible-index] > td { height: 32px; }
.dxbl-grid-table > tbody > tr[data-visible-index]:not(:first-child) > td { height: 33px; }

/* 行タップで何かが開くグリッドはポインタカーソルを出す */
.alt-rowclick .dxbl-grid-table > tbody > tr:hover > td { cursor: pointer; }

/* 簡易ビューなどで開いている行（GridDefaults.CurrentRowCssClass。付け方は GridDefaults.HighlightCurrentRow の doc）。
   !important は DevExpress の行の背景に勝つため（pitfalls.md の「内部スタイルに勝つ」）。 */
.alt-current-row { background: var(--alt-accent-soft) !important; }

/* カスタム項目の入力欄（Core の CustomFieldInputs）。モジュールをまたいで同じ見た目にするのでシェルに置く。
   数値の入力は幅を決め打ちする（alt-inline のように伸ばすと、単位の文字が右端へ離れて読めなくなる）。 */
.alt-field-inline { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
/* 値なしを取る色の欄（Core の NullableColorInput）の「色を指定する」「色なし」。土台は .linklike（背景・枠・font）で、
   ここが足すのはテーマの色と下線だけ＝押せるボタンと分かるようにする（TEST1-406。黒い文字のままだと、
   横の「（未設定）」と見分けが付かなかった）。 */
.alt-color-toggle { padding: 0; color: var(--alt-brand); text-decoration: underline; }
.alt-check-list { display: flex; flex-wrap: wrap; gap: 4px 16px; padding: 4px 0; }

/* 入力欄＋補助（チェックボックス・注記）を横に並べる（AI 設定などの管理画面）。先頭の入力が伸びる。 */
.alt-inline { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; align-self: start; }
.alt-inline > :first-child { flex: 1 1 240px; }

/* ==================================================================
   全体通知（バナー・一覧・詳細）。chaser から移植。
   重要度の 3 段（is-info / is-warning / is-critical）は
   AnnouncementLevelExtensions.CssClass が返すもので、バナー・一覧・詳細で共用する。
   ================================================================== */

/* 本文最上部に積むバナー群 */
.alt-annc-banners {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 14px;
}

.alt-annc-banner {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 9px 12px;
    border: 1px solid var(--alt-border);
    border-left-width: 4px;
    border-radius: 6px;
    background: var(--alt-bg-page);
}

.alt-annc-banner.is-info { background: var(--alt-accent-soft); border-color: var(--alt-border-primary); border-left-color: var(--alt-accent); }
.alt-annc-banner.is-warning { background: var(--alt-warning-bg); border-color: var(--alt-warning-border); border-left-color: var(--alt-warning-text); }
.alt-annc-banner.is-critical { background: var(--alt-danger-bg); border-color: var(--alt-danger-border); border-left-color: var(--alt-danger); }

.alt-annc-banner-title { font-weight: 600; }
.alt-annc-banner-link { margin-left: auto; font-size: 0.85rem; white-space: nowrap; }

.alt-annc-banner-close {
    border: 0;
    background: none;
    cursor: pointer;
    color: var(--alt-text-secondary);
    font-size: 1.1rem;
    line-height: 1;
    padding: 2px 4px;
}

.alt-annc-banner-close:hover { color: var(--alt-text-primary); }

/* 重要度バッジ */
.alt-annc-level {
    font-size: 0.74rem;
    font-weight: 700;
    padding: 2px 8px;
    border-radius: 10px;
    white-space: nowrap;
    border: 1px solid transparent;
}

.alt-annc-level.is-info { background: var(--alt-accent-soft-strong); color: var(--alt-text-secondary); border-color: var(--alt-border-primary); }
.alt-annc-level.is-warning { background: var(--alt-warning-bg); color: var(--alt-warning-text); border-color: var(--alt-warning-border); }
.alt-annc-level.is-critical { background: var(--alt-danger-bg); color: var(--alt-danger-text); border-color: var(--alt-danger-border); }

/* 全体通知の一覧（/announcements） */
.alt-annc-list { list-style: none; margin: 0; padding: 0; }
.alt-annc-list li {
    display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap;
    border-top: 1px solid var(--alt-border); padding: 10px 8px; cursor: pointer;
}
.alt-annc-list li:hover { background: var(--alt-bg-page); }
/* 未読の下地はお知らせ一覧と同じ（既読はお知らせの行が持つので、ベルに乗せた全体通知にだけ付く）。 */
.alt-annc-list li.unread { background: var(--alt-accent-soft); }
.alt-annc-list .title { font-weight: 600; }
.alt-annc-list .time { margin-left: auto; color: var(--alt-text-tertiary); font-size: 0.82rem; white-space: nowrap; }

/* お知らせ・全体通知の行に置く「既読にする」。種別チップと同じ理由で、baseline 揃えの行では
   かたまりごと自分で中央に置く（大きさは .alt-grid-commands が持つ）。 */
.app-notif-list .alt-grid-commands,
.alt-annc-list .alt-grid-commands { align-self: center; }

.alt-annc-withdrawn { color: var(--alt-text-tertiary); font-size: 0.82rem; }

/* 全体通知の詳細（/announcements/{id}） */
.alt-annc-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.alt-annc-head .page-title { margin: 0; }
.alt-annc-body { margin: 14px 0 20px; }
/* 本文の画像だけの体裁（はみ出さない上限は Markdown の本文の共通の .alt-markdown img）。 */
.alt-annc-body img { border-radius: var(--alt-radius-sm); margin: 6px 0; }

/* 管理画面の「届け方」チェック群（縦積み） */
.annc-checks { display: flex; flex-direction: column; gap: 4px; }

/* ===== Markdown の本文（Core の MarkdownHelper.Render がこの class で包んで返す） =====
   **見た目はここ 1 か所**（2026-09-17）＝以前は Pm と全体通知が写しを持ち、表の直しが片方にだけ入った。
   置き場ごとの体裁（Pm の行の高さ・画像の拡大など）は外側の要素の class が持つ。
   **ここには置き場で変えたいもの（行の高さ・文字の大きさ）を書かない**＝包みは外側の要素の内側にあるので、
   ここに書いた継承する値は外側の class の値に必ず勝つ。中の要素を外側から直すときも、ここと同じプロパティを
   同じ詳細度で重ねない（勝ち負けが CSS の読み込み順で決まる）。
   `white-space: normal` は pre-wrap の中に置かれたときに Markdown の改行が二重になるのを打ち消す。
   `overflow-wrap: break-word` は長い URL 1 本でページが横に広がるのを防ぐ。
   **`contain: inline-size` は中身（下の表の `width: max-content`・長いコード行）に置き場の幅を決めさせない**＝
   幅が中身で決まる器（DxPopup の窓・グリッドの `1fr` の列）がその長さまで広がるのを止める。
   代わりに**置き場は幅を持つブロックにすること**（inline-block や横並びの flex の子だと幅が 0 に潰れる）。
   実測と、器の側で止める定型との使い分けは docs/claude/pitfalls.md の「max-width: 100% は…」。 */
.alt-markdown { white-space: normal; overflow-wrap: break-word; contain: inline-size; }
.alt-markdown p { margin: 0 0 8px; }
.alt-markdown pre { background: var(--alt-bg-page); border: 1px solid var(--alt-border); border-radius: var(--alt-radius-sm); padding: 10px; overflow-x: auto; }
.alt-markdown code { background: var(--alt-bg-page); border-radius: 4px; padding: 1px 4px; }
.alt-markdown pre code { background: none; padding: 0; }
/* 表は**収まらないときその場で横へスクロールさせる**＝素の table は列の最小幅より縮まず、
   スマホの幅では枠を突き抜けてページごと横に広がった（375px の画面で 629px。実測）。
   `display: block` にしてスクロールを表そのものに持たせる＝Markdig の出力の中に包む要素を足さずに済む。
   `width: max-content` で狭い表は中身なりの幅に戻す（block のままだと枠の右端まで伸びる）。
   **見せるだけの素の表（.alt-table。設定の一覧・取り込みの下見）も同じ規則を通す**（2026-09-17）＝空白の無い英字
   （項目名 `MachineSerialNumberForExport`・選択肢 `Red,Green,Blue`）は折り返せず、375px のひな型からフォームを作る画面で
   ページが 608px に広がった（1280px で測った 6 か所は表と列の幅が変更前と一致。実測）。Markdown の表と違って次の 2 つは持たない:
   枠線と余白（定義が無いまま使われてきたので、付けると広い画面の見た目が変わる）・contain: inline-size の包み
   （**置き場は幅を持つブロックにすること**。いまの置き場はすべて alt-card の直下。DxPopup の窓・flex の子・グリッドの 1fr の列に
   置くなら器の側で止める＝pitfalls.md の「max-width: 100% は…」）。 */
.alt-markdown table, .alt-table { display: block; width: max-content; max-width: 100%; overflow-x: auto; overscroll-behavior-x: none; }
.alt-markdown table { border-collapse: collapse; margin: 8px 0; }
.alt-markdown th, .alt-markdown td { border: 1px solid var(--alt-border-strong); padding: 4px 10px; }
/* スマホの幅ではセルに最小幅を付ける＝幅が足りないと列が最小幅まで縮み、日本語が**1 文字ずつ縦に折り返す**
   （375px で行の高さ 199px。5em で 80px。実測）。広い画面では付けない＝「1」だけの列まで広がる。 */
@media (max-width: 640px) { .alt-markdown th, .alt-markdown td { min-width: 5em; } }
/* .alt-table も 640px 以下で床を付ける（2026-09-17）＝375px の Import/Export で「区分」の列が 19px、ディスク使用量の見出しが
   27px まで潰れていた。**値は 3em で、Markdown の表の 5em より小さい**＝2 文字の値（区分・必須）が 1 行に収まる最小の幅。
   5em にすると番号だけの列や空の列まで 70px を取り、一括の中身の表でファイル名の列が狭まって表が 543 → 805px に伸び、
   表の中で横にも転がった。3em では 588px で転がらず、ディスク使用量 582 → 501px・単品 526 → 435px（いずれも 375px で実測）。 */
@media (max-width: 640px) { .alt-table th, .alt-table td { min-width: 3em; } }
.alt-markdown blockquote { border-left: 3px solid var(--alt-border-strong); margin: 8px 0; padding: 2px 12px; color: var(--alt-text-sub); }
/* 画像は枠からはみ出さない上限だけ。`height: auto` は `{height=…}`（Markdig の属性の記法）で高さを書かれた画像が
   上限で縮んだときに縦横比を崩さないため。 */
.alt-markdown img { max-width: 100%; height: auto; }

/* 一覧などから別画面へ渡す小さいリンク（「もっと見る」「一覧へ」） */
.alt-inline-link {
    font-size: 0.85rem;
    color: var(--alt-brand);
    text-decoration: none;
    white-space: nowrap;
}

.alt-inline-link:hover { text-decoration: underline; }

/* ボタンで描く同じ見た目のリンク（Core の IssueQuickViewLink＝押すとその場で課題の簡易ビューを開く）。
   枠・背景・字体は .linklike が外すので、ここは button の既定の余白だけを外して、アンカーのリンクと文字の位置を揃える。 */
button.alt-inline-link { padding: 0; }

/* ==================================================================
   ダッシュボード（/）。chaser から移植。
   中身はお知らせのダイジェストだけ（全体通知／お知らせの 2 枚）。
   モジュールの集計はここには入らない＝業務の入口はサイドバーの見出しが開く画面に揃えてある。
   主段と脇の 2 カラムはそちらのモジュールが持つ（使うのがモジュール 1 つだけになったため）。
   ================================================================== */

/* ---- お知らせのダイジェスト（全体通知／お知らせの 2 枚） ---- */
.dash-notices {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.8rem;
    margin-bottom: 1rem;
}

/* 狭い画面では 1 枚ずつ縦に積む。 */
@media (max-width: 900px) {
    .dash-notices { grid-template-columns: 1fr; }
}

/* グリッドの子は既定で min-width:auto＝中身の最小幅より縮まない。
   お知らせの件名は 1 行に収めて末尾を切る（.dash-notice-text）ので、
   これを入れないと長い件名がそのまま列を押し広げ、右のパネルが画面からはみ出す。 */
.dash-notices > * { min-width: 0; }

.dash-notice-panel { margin: 0; }

/* ダイジェストの見出し行（右端に「未読のみ」トグル） */
.dash-notice-head-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0;
}

.dash-notice-toggle {
    margin-left: auto;
    font-size: 0.8rem;
    font-weight: 400;
}

.dash-notice-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.3rem 0.2rem;
    border-bottom: 1px solid var(--alt-border);
    color: inherit;
    text-decoration: none;
    cursor: pointer;   /* href ではなく click で遷移する（既読にしてから飛ぶ）ので明示する */
}

.dash-notice-row:last-of-type { border-bottom: none; }
.dash-notice-row:hover { background: var(--alt-accent-soft); }
.dash-notice-row.is-unread .dash-notice-text { font-weight: 700; }

.dash-notice-text {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dash-notice-time {
    flex-shrink: 0;
    font-size: 0.8rem;
    color: var(--alt-text-tertiary);
}

.dash-notice-more {
    display: inline-block;
    margin-top: 0.3rem;
}

/* 全体通知の行は「見出し行＋本文プレビュー（3 行まで）」の 2 段 */
.dash-annc-row {
    flex-direction: column;
    align-items: stretch;
    gap: 0.15rem;
}

.dash-notice-head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
}

.dash-annc-preview {
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--alt-text-secondary);
    overflow-wrap: break-word;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    overflow: hidden;
}

/* ---- お知らせの行頭の絵（Components/Shared/NotificationKindBadge） ----
   2 種類ある。**出所**（承認依頼・お知らせ・全体通知）は発信元モジュールのアイコンを背景なしで出すだけなので
   既存の .alt-ico に乗る（濃色テーマの白抜きもそちらが持っている）。
   **状態**（完了・警告）だけがこの色付きチップで、**グリフは mask で塗る**
   ＝背景画像では SVG の色が黒に固定され、状態の色にも濃色テーマにも追随できない。
   mask なら currentColor を取るので、色の指定はチップ 1 か所で済む。 */
.alt-notif-ico { flex: none; }

.alt-notif-kind {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 22px;
    height: 22px;
    border-radius: 6px;
    background: var(--alt-accent-soft);
    color: var(--alt-text-secondary);
}

.alt-notif-kind::before {
    content: "";
    width: 14px;
    height: 14px;
    background-color: currentColor;
    -webkit-mask: var(--alt-notif-icon) center / 14px 14px no-repeat;
    mask: var(--alt-notif-icon) center / 14px 14px no-repeat;
}

.alt-notif-kind.is-completed {
    --alt-notif-icon: url('icons/check-circle.svg');
    background: var(--alt-success-bg);
    color: var(--alt-success-text);
}

.alt-notif-kind.is-warning {
    --alt-notif-icon: url('icons/alert-triangle.svg');
    background: var(--alt-warning-bg);
    color: var(--alt-warning-text);
}

/* ---- 対応が必要なもの（モジュールが名乗るダイジェスト） ----
   数字とリンクだけを受け取り、見せ方はここで決める（Core の IDashboardSummaryProvider）。
   幅に応じて 1〜4 列。カードの中身は「名前 …… 件数（＋金額）」の行を並べただけ。 */
.dash-panels-head { margin-top: 22px; }

.dash-panels {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 16px;
    align-items: start;
}

.dash-panel { margin: 0; padding: 14px 16px; }

.dash-panel-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 8px;
    font-size: 0.95rem;
    font-weight: 700;
}

.dash-panel-head a { color: inherit; text-decoration: none; }
.dash-panel-head a:hover { text-decoration: underline; }

/* 数字の行。行ごとリンクにして、押すとその数字を片付けられる画面へ飛ぶ。 */
.dash-stat {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    padding: 7px 2px;
    border-bottom: 1px solid var(--alt-border);
    text-decoration: none;
    color: inherit;
}

.dash-stat:last-of-type { border-bottom: none; }
.dash-stat:hover { background: var(--alt-accent-soft); }

.dash-stat-label { font-size: 0.88rem; color: var(--alt-text-secondary); }

.dash-stat-value { display: flex; align-items: baseline; gap: 8px; white-space: nowrap; }
.dash-stat-value .num { font-size: 1.25rem; font-weight: 700; line-height: 1.2; }
.dash-stat-value .amount { font-size: 0.82rem; color: var(--alt-text-secondary); }

/* 放っておくと困る度合い。色はシェルが決める（モジュールは強さだけを言う）。 */
.dash-stat.is-warn .num { color: var(--alt-warning-text); }
.dash-stat.is-danger .num { color: var(--alt-danger-text); }

/* 関連項目の並び（Workflow の関連課題・添付／Sales の関連チケット・添付）。
   **シェルに置く**＝2 つ以上のモジュールが使うため。モジュールのスタイルシートに置くと、
   そのモジュールを無効にした構成で別のモジュールの画面だけが崩れる（例外もログも出ない）。 */
.alt-related {
    margin-bottom: 16px;
}

.alt-related-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 3px 0;
    flex-wrap: wrap;
}

/* 置くのはボタンだけ（関連チケット・関連プロジェクト・添付ファイル）。ボタンは中身の幅で並び、狭い幅では折り返す。
   以前は先頭 2 つを flex: 1 で横いっぱいに伸ばしていた（選択欄とボタンを並べていた頃の名残）ため、
   ボタン 1 つの欄では 720px まで伸びていた（2026-10-17・TEST1-668 で外した）。 */
.alt-related-form {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
    margin-top: 8px;
    max-width: 720px;
}

/* 添付ファイルを選ぶボタン（Core の FileAttachButton。2026-10-06・TEST1-482 で Sales の .sales-file-btn から昇格）。
   体裁は DevExpress のボタンのクラス（dxbl-btn dxbl-btn-secondary）を label に着せて借り、ここではボタンにしか無い振る舞いだけを足す。
   input は .visually-hidden で見た目からだけ隠しているので、キーボードで届いたときの枠は label に出す。
   **DevExpress の内部のクラスを素の要素に着せている**＝版を上げたら、このボタンが隣の DxButton と同じ見た目かを確かめる。 */
.alt-file-btn { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.alt-file-btn:focus-within { outline: 2px solid var(--alt-accent); outline-offset: 2px; }
.alt-file-btn.is-disabled { opacity: 0.5; cursor: default; pointer-events: none; }

/* 絵だけのボタン（2026-09-05 に Pm の .pm-icon-btn から昇格）。
   要求したのが Pm（Markdown のツールバー・簡易ビュー）と Core の AnchorLinkButton
   （課題・申請・製造指図のタイムライン）の両方で、モジュール固有のものが 1 つも無い。
   **何が起きるかは必ず title と aria-label で伝える**＝絵だけにしない、が既存の約束。 */
/* 絵だけのボタン。**<a> にも着せる**（一覧の操作列でページごと移るもの）ので、
   下線と文字色はここで落とす＝リンクの体裁のまま絵を入れると、絵の下に線が残る。 */
.alt-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    background: none;
    border: 1px solid transparent;
    border-radius: var(--alt-radius-sm);
    color: inherit;
    text-decoration: none;
    cursor: pointer;
}

.alt-icon-btn:hover {
    background: var(--alt-bg-secondary);
    border-color: var(--alt-border);
}

/* 枠つき（GridCommandButton の Framed）。ツールバーに 1 つだけ置くときに使う
   ＝隣の DxButton が枠を持つので、絵だけ枠なしだと押せるものに見えない。
   一覧の操作列は行の中で静かにしていてほしいので、そちらは当てた時だけ枠が出る（既定）。 */
.alt-icon-btn-framed {
    border-color: var(--alt-border-strong);
    /* 隣に並ぶ DxButton と上下と角を揃える（2026-09-10）。値は :root の同じトークン。 */
    width: var(--alt-control-height);
    height: var(--alt-control-height);
    border-radius: var(--alt-control-radius);
    background: var(--alt-surface);
}

/* 開いているボタン（添付など）は押し込んで見せる＝もう一度押すと閉じる、が読める。
   **お気に入りの★は除く**＝黄色の塗りの星（下の規則）そのものが状態を示すので、地の色を重ねると星が沈む。
   当てたときの地は .alt-icon-btn:hover が敷くので、★もほかの絵のボタンと同じく押せるものに見える。 */
.alt-icon-btn.is-on:not(:has(> .alt-ico-star)) {
    background: var(--alt-bg-secondary);
    border-color: var(--alt-border);
}

/* お気に入りの★の選択中（2026-09-18・全画面共通＝プロジェクト一覧・概要・フォーム一覧）。
   **塗りつぶした黄色の星にする**＝押し込みの地の色だけでは付いているかが一目で読めない。
   線から塗りへ形も変わるので、色を見分けにくい人にも状態が伝わる。
   **色はマスクで塗る**＝background-image の SVG は色を継がない（.alt-ico-play-run と同じ技法。
   暗いテーマの反転は themes.css 側で外してある）。star-01-solid は star-01 の線を塗りにしたもので、
   **大きさは 100% 100%**＝線の星と同じく枠いっぱいに描き、付け外しで星の大きさが変わらないようにする。 */
.alt-icon-btn.is-on > .alt-ico-star {
    background-image: none;
    background-color: var(--alt-favorite);
    -webkit-mask: url('icons/star-01-solid.svg') center / 100% 100% no-repeat;
    mask: url('icons/star-01-solid.svg') center / 100% 100% no-repeat;
}

/* 一覧の操作列（コマンドボタン）の並び（2026-09-05・TEST1-60）。
   **規約は docs/claude/module-wiring.md の「一覧の操作列」が正**（列の位置・絵・幅の決め方）。
   ここが持つのは見た目の理由 2 つだけ:
   ・**折り返さない**＝2 段になると行の高さが行ごとに変わり、一覧の目が滑る
   ・**操作列の中だけボタンを 24px**＝既定の 28px は SizeMode.Small の行（約 30px）に入れると
     上下の余白が消えて窮屈になる
   幅（列そのもの）は `GridDefaults.CommandColumnWidth` が持つ＝ここの 24px と 2px を画面が暗算しない。 */
.alt-grid-commands {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: 2px;
}

/* 行の右端に置く操作（保存前の行を外す削除。2026-10-06・TEST1-483 で販売・ワークフロー・メールボックスの 3 か所を寄せた）。
   並べ替え（左端）から離すための印。margin-left: auto は行に余りがあるときしか押し出さないので、
   行が埋まったり折り返したりしても隣と詰まらないよう、左に余白を足して間隔を保つ。 */
.alt-grid-commands-end {
    margin-left: auto;
    padding-left: 24px;
}

.alt-grid-commands .alt-icon-btn,
.alt-key-title-copy {
    width: 24px;
    height: 24px;
}

/* 「その他」（`GridCommandMenu`）を隣の絵と同じ大きさ・同じ枠に揃える。
   **DevExpress のボタンの内側まで潰す**＝既定では余白と枠を持っていて、隣の絵より一回り大きく出る
   （§7「DevExpress の内部スタイルに勝つには !important が要る場面がある」）。 */
.alt-grid-commands .alt-grid-menu {
    width: 24px !important;
    height: 24px !important;
    min-width: 24px !important;
    padding: 0 !important;
    background: none !important;
    border: 1px solid transparent !important;
    border-radius: var(--alt-radius-sm) !important;
    color: inherit !important;
    box-shadow: none !important;
}

.alt-grid-commands .alt-grid-menu:hover {
    background: var(--alt-bg-secondary) !important;
    border-color: var(--alt-border) !important;
}

/* 開く向きの矢印は出さない＝隣の絵と大きさを揃えるため。**消すのは DevExpress が足す `<svg>` の方**
   （実測。`DxDropDownButton` は入れ子を作らず `<button>` そのものに CssClass が付き、
   絵のあとに `use href="…#dx-dropdown-down"` の svg を 1 枚置く）。 */
.alt-grid-commands .alt-grid-menu > svg.dxbl-image {
    display: none !important;
}

/* ===== ツールチップ（名札）＝アプリで 1 つの仕様（2026-09-27） =====
   **ツールチップと言ったらこれ 1 つ**。書き方は 2 通りで、どちらも同じ名札で出る。
     - 部品 `<Tooltip Text="…">…</Tooltip>`（Culminans.Core.Components。中身の要素に名札を付ける）
     - 属性 `data-alt-float-tip="…"`（ボタンなど 1 つの要素に直接付けるとき。部品の中身も同じ属性で描く）
   **ブラウザ標準の `title` も同じ名札で出す**（js/float-tip.js が当てている間だけ外して預かる）
   ＝DevExpress の部品が出す `title` もそろう。書き分けを覚えなくても、`title` を書けば同じ見た目になる。
   **ただし入力欄の▼・増減・クリアのボタンは DevExpress の既定の文言を出さず、欄の用途と操作を組んで出す**（TEST1-732。
   欄の説明は見出しの <label>・列見出しの <th> に data-alt-float-tip で付ける。決めごとは js/field-tip.js の冒頭）。
   **部品全体に使い方の説明を出すときは、包みに `data-alt-float-tip` と `data-alt-float-tip-cover` を並べる**（2026-10-17）
   ＝中のボタン（DevExpress の ×・▼）の既定の `title` より包みの説明を優先する（近いもの優先の例外。field-tip.js の文より先に拾う）。
   出し方は当てた瞬間（`title` のように 1 秒待たない）・キーボードで選んだときも出す・器の外（body 直下）に 1 枚だけ置いて
   `position: fixed` で貼る（overflow の器の端で切られない）・中身は複数行（改行はそのまま）。
   **位置を貼るのは js/float-tip.js、ここが持つのは見た目だけ**。
   **DevExpress Blazor には汎用のツールチップが無い**（25.2 で持っているのはグラフ・地図・スケジューラの専用品だけ）。
   読み上げは `aria-label` が担う（名札は目で読む人の補助＝aria-hidden）。
   以前あった CSS だけの名札（`data-alt-tip`・要素の中に ::after）は廃止した＝器の端で切られ、1 行しか出せなかった。 */
.alt-float-tip {
    position: fixed; left: 0; top: 0; z-index: 1200; display: none;
    width: max-content; max-width: 280px;
    padding: 3px 8px; border-radius: var(--alt-radius-sm);
    background: var(--alt-tooltip-bg); color: var(--alt-tooltip-fg);
    font-size: 12px; font-weight: normal; line-height: 1.5; text-align: left; white-space: pre-line;
    pointer-events: none;
}
.alt-float-tip.is-open { display: block; }

/* `<Tooltip>` の包み。**箱を作らない**（display: contents）＝中身の並び（flex の子・:first-child など）を変えない。
   名札の位置は中身の要素から測る（js/float-tip.js）。 */
.alt-tooltip { display: contents; }

/* 「コピーしました」の吹き出し。写したあと（`js/clipboard.js` が付け外しする `.is-copied` の間だけ）要素の横に出す。
   **当てていなくても出す**＝押した直後にカーソルを離しても、写せたことが読める。**名札（上）とは別物**＝
   当てたときの説明ではなく、押した結果の知らせ。見た目は名札に合わせる（色・大きさ・余白を直した日はここも直す）。
   **`.alt-copy-item` の吹き出しも同じルールで描く**＝写しを 2 つ持つと、片方が取り残される。位置だけはそれぞれのルールが持つ。
   **太さは戻す**＝置き場の太字を継ぐと、Mailbox のカードの見出しの中でだけ吹き出しが太字になる。 */
[data-alt-tip-copied] {
    position: relative;
}

[data-alt-tip-copied].is-copied::after,
.alt-copy-item > .alt-copied-notice {
    position: absolute;
    z-index: 1200;
    padding: 3px 8px;
    border-radius: var(--alt-radius-sm);
    background: var(--alt-tooltip-bg);
    color: var(--alt-tooltip-fg);
    font-size: 12px;
    font-weight: normal;
    line-height: 1.5;
    white-space: nowrap;
    pointer-events: none;
}

/* **横に出す**＝下は押した直後の矢印に隠れ、上は一覧の 1 行目でヘッダー行の下に潜る（実測）。 */
[data-alt-tip-copied].is-copied::after {
    content: attr(data-alt-tip-copied);
    left: calc(100% + 6px);
    top: 50%;
    transform: translateY(-50%);
}

/* 一覧の件名のセル（Core の KeyTitleCell・2026-09-17・TEST1-127）。件名の右端にコピーの絵を置き、
   **行に当てたとき・その行にフォーカスがあるとき・写した直後だけ見せる**。
   **絵はセルの右端に重ねて置き、件名の幅を取らない**＝以前は flex で絵の場所を空けたまま `visibility` で隠していて、
   見えていないときも 28px（絵 24px ＋ 間 4px）を取るので、列の幅に収まるはずの件名が**全部の行で**折り返していた
   （マニュアルの課題一覧・承認待ちの図で発覚）。重ねるので当てても件名は折り返し直らない。
   当てている間は件名の末尾が絵の下に隠れるので、絵に地の色を敷く（行の色に溶けないよう枠も付ける）。
   絵の大きさは操作列の規則（`.alt-grid-commands .alt-icon-btn`）に並べてある。 */
.alt-key-title {
    position: relative;
}

.alt-key-title-copy {
    position: absolute;
    top: 50%;
    right: 0;
    transform: translateY(-50%);
    visibility: hidden;
    background: var(--alt-surface);
    border-color: var(--alt-border);
}

/* **その行の直下のセルに限る**（`>` で繋ぐ）＝課題一覧の階層表示は子の行を親の行の中の入れ子の表で描くので、
   子孫セレクタだと外側の行に当てただけで子の行の絵が全部出る。部品はセルの直下に描かれる（実測）。 */
tr:hover > td > .alt-key-title > .alt-key-title-copy,
tr:focus-within > td > .alt-key-title > .alt-key-title-copy,
.alt-key-title-copy.is-copied {
    visibility: visible;
}

/* **「コピーしました」の吹き出しは左へ伸ばす**＝絵は件名の列の右端にあるので、右向きだと隣の列の上に出てしまう。
   `.alt-key-title` を前に足して吹き出しの規則より詳細度を高くしてある（置き場所に関係なく向きが勝つ）。 */
.alt-key-title .alt-key-title-copy[data-alt-tip-copied].is-copied::after {
    left: auto;
    right: calc(100% + 6px);
}

/* **「コピーしました」を出している間だけ、そのセルのはみ出しを許す**＝列を最小幅（160〜200px）まで縮めると、
   件名の上に左へ伸ばしても吹き出し（ja 約 123px・en 約 149px）がセルに収まらず切れる（実測）。
   常には開けない（件名が隣の列へ流れ出す）。件名は折り返すので吹き出しの間だけなら流れない。 */
td:has(> .alt-key-title > .alt-key-title-copy.is-copied) {
    overflow: visible !important;
}

/* 詳細画面の見出しに置く「番号・件名・リンク」のコピー（Core の CopyRefButtons。chaser から移植）。
   **枠のある小さなボタン**にしてあるのは chaser と同じ形＝見出しの操作行に並ぶので、
   リンク風の文字だと隣の DxButton と地続きに見えて押せるものが読めない。
   間隔は .linklike + .linklike と同じ .75rem（gap で取る）。 */
/* **隣のボタンと高さを揃える**（2026-09-12）＝`stretch` で行の高さいっぱいに伸ばす。
   32px を直書きしないのは、小さいボタンの列（簡易ビューの見出し）に置いたときに
   そこだけ大きくなるため。置き場が変わっても隣に合う。
   伸びるのは包み（.alt-copy-item）で、その中のボタンも既定の stretch で同じ高さになる。 */
.alt-copy-refs {
    display: inline-flex;
    align-items: stretch;
    gap: .75rem;
    margin-right: .75rem;
}

/* コピーのボタンと「コピーしました」の 1 組（全画面共通。2026-09-17）。
   **知らせはボタンの上に浮かせる吹き出し**＝以前は隣に文字で差し込んでいたので、出た拍子に後ろのボタンが
   横へずれ、狭い幅では行が 1 段増えたり、見出しの名前やボタンが縮んで折れたりした（実測）。浮かせれば並びは動かない。
   **吹き出しになるのはこの包みの中の知らせだけ**＝包みが位置の基準で、並んだ吹き出しを 1 つずつのボタンに付ける。
   包みの外の `.alt-copied-notice` は出し入れだけを共有する（KeyTitleCell の読み上げ専用の隠した知らせ）。
   **知らせはボタンのすぐ後ろ**（下の `.is-copied + …` が隣接で出すため）。
   使っているのは CopyRefButtons・AnchorLinkButton（Core）とユーザー管理の文面欄。
   **縮ませない**（`flex: none`）＝置き場の多くは flex の行で、既定では縮んで「コピー」が 2 行に折れる。 */
.alt-copy-item {
    position: relative;
    display: inline-flex;
    flex: none;
}

/* 吹き出しの位置。見た目は「コピーしました」の吹き出し（`[data-alt-tip-copied]`）と同じルールで描き、ここは位置だけを持つ。
   **上に出す**＝右へ伸ばすと、見出しの右寄せの操作行や窓の中では画面の外へ出る。
   下は押した直後の矢印に隠れる（実測）。
   **左端をボタンに揃える**＝真ん中に置くと、吹き出し（約 100px）がボタン（「ID」は 30px）より左へはみ出し、
   簡易ビューのように左端に置いたときに窓の端で切れうる。
   **切れる側だったときの向きは js/clipboard.js が出した瞬間に測って決める**（`.is-end`／`.is-below`）。
   置き場で決め打ちできない＝タイムラインの鎖ボタンは行の末尾にあるが、375px では行が折れて
   2 段目の行頭にも来る（実測）。右端揃えに固定すると今度は左で切れる。 */
.alt-copy-item > .alt-copied-notice {
    bottom: calc(100% + 6px);
    left: 0;
}

.alt-copy-item > .alt-copied-notice.is-end {
    left: auto;
    right: 0;
}

.alt-copy-item > .alt-copied-notice.is-below {
    bottom: auto;
    top: calc(100% + 6px);
}

/* 「コピーしました」の出し入れ（吹き出しも、KeyTitleCell の読み上げ専用の隠した知らせも）。
   js/clipboard.js が押された要素に .is-copied を付け外しする＝.NET 側に持たせると押すたびに回線を 1 往復する。 */
.alt-copied-notice {
    display: none;
}

.is-copied + .alt-copied-notice {
    display: block;
}

.alt-copy-btn {
    /* 伸びた高さの中で文字を真ん中に置く（伸ばすのは親の .alt-copy-item）。 */
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--alt-border-strong);
    border-radius: 4px;
    background: var(--alt-surface);
    color: var(--alt-text-strong);
    font-size: 0.72rem;
    font-weight: 700;
    padding: 2px 8px;
    line-height: 1.4;
    cursor: pointer;
}

.alt-copy-btn:hover {
    background: var(--alt-bg-muted);
    border-color: var(--alt-text-muted);
}

/* 登録を知らせる文面（ユーザー管理。メールで送らなかったときに出す）。
   見出しの行の右端にコピーのボタンを置き、値の欄はその下に全幅で置く。 */
/* ボタンと、その後ろに添える短い断り（前回のお知らせの日時など）を 1 行に並べる。 */
.alt-inline-row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.welcome-field-head {
    display: flex;
    align-items: baseline;
    gap: 8px;
}

.welcome-field-head > label {
    flex: 1 1 auto;
}

.welcome-body {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.8rem;
    line-height: 1.6;
    resize: vertical;
}

/* 行への直接リンクで飛んできたとき、その行を一瞬光らせて「ここ」と分かるようにする
   （Core の AnchorLinkButton・js/anchor-link.js と対。2026-09-05）。
   **光っている長さを決めるのはここだけ**＝JS はアニメーションの終わりを待ってクラスを外す。

   **地色を置き換えず、上に 1 枚重ねる**（2026-09-13・TEST1-107）。
   以前は要素そのものの background-color を動かしていたので、**背景色を持つ行に当てると
   2.5 秒のあいだ地色が消え、最後に透明まで下がってから元へ戻った**（色が一度抜けて見える）。
   地紋のテーマ（motifs.css がカードへ敷く background-image）も同じ理由で消えていた。

   **影（box-shadow: inset）で重ねる案は採れない**＝.alt-card は既に box-shadow を持っており、
   2.5 秒のあいだ影が消える。**いま直したのと同じ「要素が既に持つものを置き換える」形**になる。
   background-image も同じ理由で使えない（地紋のテーマが .alt-card に敷いている）。

   **isolation: isolate と z-index: -1 は対で要る**（2026-09-13 実測）。負の値の子が
   「その要素の背景より上・本文より下」へ入るのは、**その要素が積み重ねの文脈を作っているとき**だけ。
   position: relative だけでは文脈ができず、層はカードの背景より後ろへ回り込んで**見えなかった**
   （計算値は正しい色を返すので、実際に描かせるまで分からない）。
   文脈を作ると、地色も地紋も残ったまま黄色が乗り、文字は層より上に描かれるので濁らない。

   （印を付けるのは一覧の行とカードだけで、どちらも静的に置かれている。
     文脈が 2.5 秒だけできるので、その最中に開いている入れ子の浮き物があれば重なり順が変わり得る。） */
.alt-anchor-flash {
    position: relative;
    isolation: isolate;
}

.alt-anchor-flash::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    border-radius: inherit;
    animation: alt-anchor-flash 2.5s ease-out;
}

@keyframes alt-anchor-flash {
    0%, 40% { background-color: rgba(245, 210, 100, 0.4); }
    100% { background-color: transparent; }
}

/* ============================================================
   モジュール横断の検索（TEST1-101）
   ============================================================

   窓はヘッダー（クラシックではサイドバー）に 1 つ、結果は右端に吸着するパネルに出る。
   **押しても閉じない**＝行を押すと本文側だけが遷移し、パネルは残って次の候補を出したままにする。

   吸着は「列を 1 つ足す」でやる（覆いかぶせない）。クラシックは .app-shell が flex なので
   本文の隣に並ぶだけで済み、ヘッダーを持つ形は 2 列のグリッドなので layouts.css で 3 列目を足す。
   **どちらも .app-shell の直下に居ることが前提**（MainLayout の同名のコメント）。 */

/* 窓（虫眼鏡＋入力欄）と、その中の入力欄の包み。**並べ方は同じ**なので 1 か所で持つ。 */
.app-search-box,
.app-search-field {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

/* ヘッダーの中では真ん中のパンくずと取り合わないよう、伸びずに決まった幅を持つ。 */
.app-topbar .app-search-box { flex: 0 1 240px; }

/* サイドバー（クラシック）では幅いっぱい＝ベルと同じ扱い。 */
.app-sidebar .app-search-box { margin: 0 8px 8px; }

/* クラシックのサイドバーでは検索窓の右に更新ボタン（TEST1-625）を並べる。窓が余りを取り、ボタンは右端に残る
   （制限ユーザには窓が無いので、margin-left: auto でボタンだけが右へ寄る）。下の余白は窓（上の margin）とそろえる。 */
.app-sidebar-search { display: flex; align-items: center; }
.app-sidebar-search .app-search-box { flex: 1; }
.app-sidebar-search .app-sidebar-reload { margin: 0 8px 8px auto; }

/* 狭い画面（ドロワー）では上部バーに同じボタンがあり、アイコンリストバーでは幅に入らないので出さない。
   包み（.app-sidebar-search）を付けて詳細度を上げる＝後ろにある .app-nav-button の display に負けないため。
   アイコンリストバーの側は .app-sidebar で包む（アイコンリストバーの節の決めごと）。 */
@media (max-width: 1024px) {
    .app-sidebar-search .app-sidebar-reload { display: none; }
}

@media (min-width: 1025px) {
    html.app-nav-icons .app-sidebar :is(.app-sidebar-reload, .app-sidebar-assist) { display: none; }
}

/* 入力欄の包みだけが余りを取る。通常はそのまま横に並び、アイコンリストバーでは浮かぶ窓になる（下の節）。 */
.app-search-field { flex: 1; }

/* 開閉ボタンと膜はアイコンリストバーのときだけ出る＝既定では持たない。
   **既定を「出さない」にすること**＝出す側を既定にすると、ヘッダーを持つレイアウトにも
   虫眼鏡が 2 つ並ぶ（畳めないので押しても何も起きない）。 */
.app-search-toggle,
.app-search-scrim { display: none; }

/* 虫眼鏡は押せるボタン（Enter と同じ「探した」の合図）。既定の当たり判定より詰めて窓に寄せる。 */
.app-search-run { flex: none; padding: 2px; }

.app-search-box .alt-ico { flex: none; opacity: .7; }

.app-search-input { flex: 1; min-width: 0; }

/* ---- アイコンリストバーでは虫眼鏡だけを置く（2026-09-14） ----
   幅 72px に 240px の入力欄は入らず、それまでは窓が右へはみ出して切れていた
   （押せる部分が残るので壊れて見えず、値も打てるという形でしか表に出ない）。
   押すと入力欄が右横へ浮かぶ＝アカウントのポップアップ・フローティングメニューと同じ作り。

   **包みは .app-sidebar**（アイコンリストバーの節と同じ理由）＝書かないと、
   ヘッダーを持つレイアウトの検索窓まで虫眼鏡 1 つに畳まれる。
   **メディアクエリの中に閉じること**＝<html> の app-nav-icons は localStorage 由来で、
   狭い画面（≦1024px・サイドバーはドロワー）でも付いたまま。外に書くと、
   ドロワーを開いても入力欄が出てこない（例外もログも出ない）。 */
@media (min-width: 1025px) {
    html.app-nav-icons .app-sidebar .app-search-box {
        /* 浮かぶ入力欄（.app-search-field）の位置の基準。 */
        position: relative;
        justify-content: center;
        /* 絵の列（ベル・アイコンバー）と左右を揃える。 */
        margin: 0 4px 6px;
    }

    html.app-nav-icons .app-sidebar .app-search-toggle {
        display: inline-flex;
        width: 40px;
        height: 40px;
    }

    /* 閉じているあいだは持たない＝虫眼鏡だけが残る。 */
    html.app-nav-icons .app-sidebar .app-search-field { display: none; }

    /* 開いたら右横へ。見た目（角丸・影・重なり順）はフローティングメニュー（.app-flyout）と揃える。 */
    html.app-nav-icons .app-sidebar .app-search-box.is-open .app-search-field {
        display: flex;
        position: absolute;
        left: calc(100% + 6px);
        top: 0;
        z-index: 60;
        width: 260px;
        box-sizing: border-box;
        padding: 8px;
        background: var(--alt-bg-primary);
        border: 1px solid var(--alt-border-secondary);
        border-radius: var(--alt-radius-md);
        box-shadow: var(--alt-shadow-pop);
    }

    html.app-nav-icons .app-sidebar .app-search-scrim { display: block; }
}

/* ---- 狭い画面のヘッダーでも虫眼鏡だけを置く（2026-09-27） ----
   ヘッダーの帯に入力欄を並べると、ブランド・ベル・アカウントに押されて 32px ほどに詰まり、打った文字が読めない。
   押すと入力欄がヘッダーの下にダイアログとして出る（開閉・Enter で探して閉じる・Esc・外側を押して閉じるは
   アイコンリストバーと同じ部品の同じ仕組み＝GlobalSearchBox）。**包みは .app-topbar**＝クラシックの狭い画面では
   検索窓はドロワー（サイドバー）の中にあって幅が足りているので、畳まない。 */
@media (max-width: 1024px) {
    .app-topbar .app-search-box { flex: none; }

    .app-topbar .app-search-toggle {
        display: inline-flex;
        width: 40px;
        height: 40px;
    }

    .app-topbar .app-search-field { display: none; }

    /* ヘッダーの下に、左右の余白を残して横いっぱいに出す。見た目（角丸・影）はアイコンリストバーの浮かぶ窓と揃える。 */
    .app-topbar .app-search-box.is-open .app-search-field {
        display: flex;
        position: fixed;
        top: calc(var(--alt-topbar-height) + 8px);
        left: 12px;
        right: 12px;
        z-index: 60;
        box-sizing: border-box;
        padding: 12px;
        background: var(--alt-bg-primary);
        color: var(--alt-text-primary);
        border: 1px solid var(--alt-border-secondary);
        border-radius: var(--alt-radius-md);
        box-shadow: var(--alt-shadow-pop);
    }

    /* 開いているあいだはヘッダーごと結果のパネル（35）より上へ出す＝打つたびに結果が出るので、
       狭い画面のヘッダーの重なり順（30。layouts.css）のままだと、開いたパネルがダイアログに被って打てなくなる。 */
    .app-topbar:has(.app-search-box.is-open) { z-index: 60; }

    /* ダイアログらしく、うしろを少し暗くする（押すと閉じる膜。アイコンリストバーの膜は透明のまま）。 */
    .app-topbar .app-search-scrim {
        display: block;
        background: rgba(0, 0, 0, 0.25);
    }
}

/* ===== 右端に吸着するパネル ===== */

/* **外枠は「AIに依頼」のパネル（TEST1-744）と共有する**＝高さの式（2026-09-12 の実測で直した）・貼り付き・枠を 1 か所に置き、
   パネルごとに持つのは幅（--alt-dock-width）だけ。中身の並べ方はそれぞれの節。 */
.app-search-dock { --alt-dock-width: var(--alt-search-dock-width); }
.app-assist-dock { --alt-dock-width: var(--alt-assist-dock-width); }

:is(.app-search-dock, .app-assist-dock) {
    /* クラシック（.app-shell は flex）ではこの 1 行で右端の列になる。 */
    flex: 0 0 var(--alt-dock-width);
    width: var(--alt-dock-width);
    display: flex;
    flex-direction: column;
    /* 本文が長くてもパネルは画面に貼り付いたまま＝結果を見ながら本文だけを送れる。
       **高さは画面ぴったりに決め打つ**＝中身なりにすると、本文が長いときパネルの下に
       地が見えて「途中で切れた枠」に見える（max-height では伸び縮みして同じことが起きる）。 */
    position: sticky;
    top: var(--alt-sidebar-top);
    height: calc(100vh / var(--alt-vz, 1) - var(--alt-sidebar-top) - var(--alt-sidebar-bottom));
    box-sizing: border-box;
    background: var(--alt-surface);
    border-left: 1px solid var(--alt-border);
    z-index: 35;
}

.app-search-dock-head {
    flex: none;
    border-bottom: 1px solid var(--alt-border);
}

.app-search-dock-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    /* **横は切る**＝overflow-y だけを指定すると横は auto と同じ扱いになり、
       長い件名で横スクロールバーが 1 本出る（狭いパネルなので目立つ）。 */
    overflow-x: hidden;
}

/* 分離したとき＝列から外して浮かせる。枠と中身は吸着と同じもので、**印が 1 つ増えるだけ**。
   本文は全幅に戻り（下の :has() が 3 列目を足さなくなる）、パネルは右端の中ほどに浮く。
   ヘッダーには重ねない＝浮かせたあとも言葉を打ち直せるようにする。 */
.app-search-dock.is-floating {
    position: fixed;
    right: 16px;
    /* **ヘッダーの高さを数え直さない**＝サイドバーが貼り付く位置と同じトークンを読む
       （app.css が式を持ち layouts.css が値を渡す、という .app-sidebar の作法。
       クラシックには上のヘッダーが無いので、数え直すと理由のない空きができる）。 */
    top: calc(var(--alt-sidebar-top) + 16px);
    /* 大きさは縁と角のつまみで変えられる（search-dock.js が <html> の --alt-search-float-width／height に当てて覚える）。
       変えていなければ吸着と同じ幅・画面に収まる高さ。画面より大きくはしない。 */
    width: var(--alt-search-float-width, var(--alt-dock-width));
    height: var(--alt-search-float-height, min(680px, calc(100vh / var(--alt-vz, 1) - var(--alt-sidebar-top) - var(--alt-sidebar-bottom) - 32px)));
    max-width: calc(100vw - 16px);
    max-height: calc(100vh - 16px);
    border: 1px solid var(--alt-border);
    /* 角丸と影は浮かぶものの既定。 */
    border-radius: var(--alt-radius-md);
    box-shadow: var(--alt-shadow-pop);
    overflow: hidden;
    z-index: 50;
}

/* 大きさを変えるつまみ（search-dock.js）。**吸着は左の縁**（幅。変えた幅は <html> の --alt-search-dock-width＝吸着の列も同じ値を読む）、
   **浮かせたときは左右・下の縁と下の角**（幅と高さ）。パネルの内側の縁に重ねる（浮かせたパネルは overflow: hidden で外へ出すと掴めない）。
   形と当てたときの色は共通のつまみ（.app-resizer）で、ここは置き方と縁ごとのカーソルだけ（属性つきの選択子なので .app-resizer の col-resize に勝つ）。 */
.app-search-dock-resizer {
    position: absolute;
    z-index: 2;
}

/* 縁と角は「共通の規則」のすぐ後に「縁ごとの規則」を空行なしで続ける（tools/css-dup-selectors.py が 1 か所と数える書き方。
   空行で分けると同じ選択子を 2 か所で定義したことになり、ビルドが止まる＝2026-10-19 に止めた） */
.app-search-dock-resizer[data-dock-edge="w"],
.app-search-dock-resizer[data-dock-edge="e"] {
    top: 0;
    bottom: 0;
    width: 6px;
    cursor: col-resize;
}
.app-search-dock-resizer[data-dock-edge="w"] { left: 0; }
.app-search-dock-resizer[data-dock-edge="e"] { right: 0; }

.app-search-dock-resizer[data-dock-edge="s"] {
    left: 0;
    right: 0;
    bottom: 0;
    height: 6px;
    cursor: row-resize;
}

.app-search-dock-resizer[data-dock-edge="sw"],
.app-search-dock-resizer[data-dock-edge="se"] {
    bottom: 0;
    width: 14px;
    height: 14px;
    z-index: 3;
}
.app-search-dock-resizer[data-dock-edge="sw"] { left: 0; cursor: nesw-resize; }
.app-search-dock-resizer[data-dock-edge="se"] { right: 0; cursor: nwse-resize; }

/* 別ウィンドウへ出したとき（search-dock.js が DOM ごと移す）。
   移った先は窓 1 枚ぶんしかないので、位置も枠も持たずに広がるだけにする。
   **.app-shell から抜けるので吸着の列は自動で消える**（:has() が当たらなくなる）。 */
.app-search-dock.is-popped {
    position: static;
    width: 100%;
    height: calc(100vh / var(--alt-vz, 1));
    border: none;
    border-radius: 0;
    box-shadow: none;
}

/* ===== 見出し（吸着・分離で同じもの） ===== */

/* 見出しは 2 段（1 段目＝件数と操作、2 段目＝並べ方）。
   **1 段に詰めない**＝パネルは 320px しかなく、並べ方の選択肢が「まとまり順（中…」で切れる
   （選んでいるものが読めないと、並べ方を変えたのかどうか分からない）。 */
.app-search-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    padding: 8px 8px 8px 12px;
    min-width: 0;
}

.app-search-head-title { font-weight: 600; white-space: nowrap; }

.app-search-head-count {
    color: var(--alt-text-secondary);
    font-size: .85rem;
    white-space: nowrap;
}

/* 並べ方は 2 段目いっぱい（幅の指定ではなく改行で落とす＝ボタン 2 つを押しつぶさない）。 */
.app-search-order { flex: 1 0 100%; min-width: 0; }


/* 1 段目の右端にボタンを寄せる。 */
.app-search-head .alt-icon-btn:first-of-type { margin-left: auto; }

/* ===== 当たったもの ===== */

.app-search-list { padding: 4px 0 8px; }

.app-search-group {
    margin: 8px 0 2px;
    padding: 0 12px;
    font-size: .8rem;
    font-weight: 600;
    color: var(--alt-text-secondary);
}

/* 行はボタン（遷移するので href を付けない＝ポップアップ起動系と同じ理由ではなく、
   押しても窓が残ることを見た目で約束するため）。**幅いっぱい・左寄せ**は
   .linklike が外した button の既定を戻す分だけここで持つ。 */
.app-search-hit {
    display: block;
    width: 100%;
    text-align: left;
    padding: 6px 12px;
    border-radius: var(--alt-radius-sm);
}

.app-search-hit:hover { background: var(--alt-bg-secondary); }

/* 開いた画面で当たった語を光らせる（js/search-highlight.js。結果のパネルが開いているあいだだけ）。
   ::highlight は DOM を書き換えずに文字の範囲へ色を付ける＝Blazor の描き直しを壊さない。最初の 1 か所は橙（ページ内検索の「いまの位置」）。
   入力欄の中の文字は範囲を取れないので、値に語を含む欄そのものに印を付ける（DevExpress の欄の背景に勝つため !important）。 */
::highlight(culminans-search-hit) {
    background-color: var(--alt-search-hit-bg);
    color: var(--alt-search-hit-text);
}

::highlight(culminans-search-current) {
    background-color: var(--alt-search-hit-current-bg);
    color: var(--alt-search-hit-text);
}

input.alt-search-hit-field,
textarea.alt-search-hit-field {
    /* 欄全体を濃く塗ると大きな備考欄が一面の黄色になる＝薄く敷いて、橙の枠で「この欄に当たった」と示す。文字の色は欄のまま（テーマに従う） */
    background-color: color-mix(in srgb, var(--alt-search-hit-bg) 35%, transparent) !important;
    box-shadow: inset 0 0 0 2px var(--alt-search-hit-current-bg) !important;
}

.app-search-hit-head {
    display: flex;
    gap: 6px;
    font-size: .78rem;
    color: var(--alt-text-secondary);
}

/* 件名は 2 行で切る＝長い件名でパネルが読めなくなるのを防ぐ。 */
.app-search-hit-title {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* 注記の色と大きさは既存の .meta（2 つ持つとテーマを調整したときに片方が取り残される）。
   ここが持つのは余白だけ。 */
.app-search-note { margin: 8px 12px; }

/* さっき探したもの（回線の中だけ・最大 10 件）。押すと探し直さずに戻る。 */
.app-search-recent {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 6px;
    padding: 6px 12px 8px;
    border-bottom: 1px solid var(--alt-border);
}

.app-search-recent-label {
    flex: 1 0 100%;
    color: var(--alt-text-sub);
    font-size: .78rem;
}

.app-search-recent-item {
    max-width: 100%;
    padding: 2px 8px;
    border: 1px solid var(--alt-border);
    border-radius: 999px;
    font-size: .82rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.app-search-recent-item:hover { background: var(--alt-bg-secondary); }

.app-search-recent-clear {
    margin-left: auto;
    color: var(--alt-text-sub);
    font-size: .78rem;
}

/* 狭い画面では列を足さず覆いかぶせる（本文を押し縮めると両方読めなくなる）。
   ヘッダーの下から画面の下まで。

   **高さは式で書く**（`top` と `bottom` を両方置いて `height: auto` にしない）
   ＝2026-09-12 に実測で伸びず、中身ぶんの高さで止まった（下に地が見える）。
   `height` を直に与えると意図どおりになる。 */
@media (max-width: 1024px) {
    :is(.app-search-dock, .app-assist-dock) {
        position: fixed;
        top: var(--alt-topbar-height);
        right: 0;
        width: min(var(--alt-dock-width), calc(88vw / var(--alt-vz, 1)));
        height: calc(100vh / var(--alt-vz, 1) - var(--alt-topbar-height));
        box-shadow: var(--alt-shadow-pop);
    }
}

/* ===== 動詞の答え（Core の CommandReplyView。2026-10-17・TEST1-754） =====
   文・作ったもの・行・操作。Forms の連携ボタン・お問合せ管理の起票のダイアログと AIに依頼のパネルが同じ部品で描く
   ＝面ごとの CSS に写さない（写していた 3 か所は余白も折り返しも少しずつ違っていた）。
   **間隔は根の gap が持ち、子の余白は 0、根は外に余白を持たない**＝ダイアログ（.dialog-form＝ブロックの並び）にも
   AIに依頼の吹き出し（gap の並び）にも、器の側で打ち消さずに置ける（子が margin を持つと、gap の器で足し算になる）。
   長い語（URL・課題キーの並び）は折り返す＝狭いパネルで横スクロールを出さない。 */
.alt-command-reply { display: flex; flex-direction: column; gap: .5rem; min-width: 0; }

.alt-command-reply > * { margin: 0; }

.alt-command-reply-text { white-space: pre-line; overflow-wrap: anywhere; }

.alt-command-reply-outcome { overflow-wrap: anywhere; }

/* 行の本文も改行を保つ（Pm の課題を見せる答えは属性を改行で区切ってくる＝Slack では改行で出る）。 */
.alt-command-reply-lines { padding-left: 1.2rem; overflow-wrap: anywhere; white-space: pre-line; }

.alt-command-reply-lines li + li { margin-top: .25rem; }

/* 押せる操作の並び。AIに依頼の候補の動詞のボタン（部品の外）も同じ並びで出す。 */
.alt-command-reply-actions { display: flex; flex-wrap: wrap; gap: 6px; }

/* ===== AIに依頼（2026-10-17・TEST1-744） =====
   ヘッダーのボタン（AssistantButton）と右端に吸着するパネル（AssistantDock）。
   **吸着は横断検索の結果のパネルと同じ作法**（列を 1 つ足す。ヘッダーを持つ形は layouts.css で 3 列目）で、
   **同じ列を取り合うので、吸着しているのは常にどちらか 1 つ**（AssistantState が開くときにもう片方を閉じる）。
   **.app-shell の直下に居ることが前提**（MainLayout の同名のコメント）。 */

/* クラシックのサイドバーでは検索窓の右・更新ボタンの左。下の余白は窓とそろえる。
   アイコンリストバーでは更新ボタンと同じく出さない（更新ボタンの規則に並べてある）。 */
.app-sidebar-search .app-sidebar-assist { margin: 0 0 8px 0; }

/* 開いているあいだは押し込んで見せる（もう一度押すと閉じる）。 */
.app-assist-toggle.is-on { background: color-mix(in srgb, var(--alt-accent) 14%, transparent); }

/* 幅を変えるつまみ（左の縁。js/search-dock.js が <html> の --alt-assist-dock-width に当てる＝吸着の列も同じ値を読む）。
   パネルは sticky（狭い画面では fixed）なので、絶対配置の基準になる。 */
.app-assist-dock-resizer {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 6px;
    z-index: 2;
}

.app-assist-dock-head {
    flex: none;
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 8px 8px 12px;
    border-bottom: 1px solid var(--alt-border);
}

.app-assist-head-title { flex: 1; font-weight: 600; white-space: nowrap; }

/* **新しい発言を末尾に見せ続けるのに JS を使わない**＝包みを column-reverse にすると、
   スクロールが末尾に留まり、発言が増えても末尾が見えたままになる（中身は .app-assist-log の 1 つで、並びは通常の順）。 */
.app-assist-dock-body {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column-reverse;
    overflow-y: auto;
    overflow-x: hidden;
}

.app-assist-log {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 12px;
}

.app-assist-intro { margin: 0; }

.app-assist-msg {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 8px 10px;
    border-radius: var(--alt-radius-md);
    background: var(--alt-bg-subtle);
    min-width: 0;
}

.app-assist-msg.is-user {
    align-self: flex-end;
    max-width: 88%;
    background: color-mix(in srgb, var(--alt-accent) 12%, transparent);
}

.app-assist-msg.is-notice {
    border: 1px solid var(--alt-border);
    background: transparent;
}

.app-assist-msg-who { font-size: .75rem; color: var(--alt-text-sub); }

/* 本文は平文のまま描く（改行を保つ）。長い語は折り返す＝狭いパネルで横スクロールを出さない。 */
.app-assist-msg-text {
    margin: 0;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.app-assist-msg p { margin: 0; }

.app-assist-form {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 10px;
    border: 1px solid var(--alt-border);
    border-radius: var(--alt-radius-md);
}

.app-assist-form-title { margin: 0; font-size: 1rem; }

/* パネルは狭いので入力画面は 1 列にする（長文の 2 列ぶち抜きも 1 列のまま）。 */
.app-assist-form .alt-form-grid { grid-template-columns: minmax(0, 1fr); max-width: none; }
.app-assist-form .alt-form-grid .alt-span2 { grid-column: auto; }
.app-assist-form .dialog-buttons { margin-top: 0; }

.app-assist-thinking { margin: 0; }

.app-assist-dock-foot {
    flex: none;
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 8px 12px 12px;
    border-top: 1px solid var(--alt-border);
}

/* 入力欄の高さを変えるつまみ（入力欄の上の境目＝足の上の線に重ねる。上へ引くと高くなる）。
   形と当てたときの色は共通のつまみ（.app-resizer）で、向きのカーソルだけここで替える（後に書くので .app-resizer の col-resize に勝つ）。 */
.app-assist-input-resizer {
    position: absolute;
    top: -4px;
    left: 0;
    right: 0;
    height: 8px;
    cursor: row-resize;
    z-index: 2;
}

/* 高さは上の境目で変える（js/search-dock.js が <html> の --alt-assist-input-height に当てて覚える）。
   **右下の掴みは消す**＝掴み所が 2 つあると、片方で変えた高さ（要素に直に書かれる）がもう片方の値を上書きする。 */
/* **幅の上限は外す**＝共通の .alt-input は 1 行の欄の幅（--alt-input-max）で止めるので、パネルを広げても入力欄だけが左に残っていた。
   縦の余白も足す（.alt-input の余白は横だけで、textarea では 1 行目が上の枠に付く）。 */
.app-assist-input {
    width: 100%;
    max-width: none;
    padding: 6px 9px;
    box-sizing: border-box;
    resize: none;
    min-height: 4.5em;
    height: var(--alt-assist-input-height, auto);
}

.app-assist-foot-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }

/* 送った依頼の文の履歴（2026-10-20）。見出しの履歴のボタンから DxDropDown で開き、長いときは中でスクロールする。
   文は 2 行で畳む＝全文は選んで入力欄に戻してから読む。
   行のボタンの既定を外すのは .linklike、当てたときの色は横断検索の行（.app-search-hit）と同じ。 */
.app-assist-history {
    max-height: 360px;
    overflow-y: auto;
}
.app-assist-history-empty { margin: 0; padding: 8px 10px; }
.app-assist-history-item {
    display: flex;
    align-items: flex-start;
    gap: 4px;
    padding: 2px 4px 2px 0;
}
.app-assist-history-item + .app-assist-history-item { border-top: 1px solid var(--alt-border); }
.app-assist-history-use {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 6px 10px;
    color: inherit;
    text-align: left;
}
.app-assist-history-use:is(:hover, :focus-visible) { background: var(--alt-bg-secondary); }
.app-assist-history-text {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    white-space: pre-line;
    overflow-wrap: anywhere;
}

/* 画面の内容を材料にする札（TEST1-746）。件名が長いと 1 行に収まらないので折り返す。 */
.app-assist-context { font-size: 0.9em; overflow-wrap: anywhere; }

/* ===== 詳細画面の横に並べる一覧（2026-09-26） =====
   詳細画面が名乗った一覧の画面を iframe で描く（DetailListDock.razor。iframe の理由は Core の DetailListLink）。
   **分割するのはモジュールのタブより下だけ**（.app-split。MainLayout）＝タブは全幅のヘッダーのまま。
   本文が長くても一覧は画面に貼り付いたまま。幅はパネル自身が持つ（`--alt-list-dock-width` は DetailListDock が
   インラインで渡し、分割バーを動かすと js/detail-list.js が書き換える）。 */
.app-split {
    display: flex;
    align-items: flex-start;
    gap: 16px;
}

.app-split-main {
    flex: 1;
    min-width: 0;
}

.app-list-dock {
    flex: 0 0 var(--alt-list-dock-width);
    width: var(--alt-list-dock-width);
    /* 中は縦に積む（詳細のタブを移してきたときの帯 → 一覧 or 移したタブの画面）。 */
    flex-direction: column;
    /* 保存した幅が今の画面には広すぎるとき（広い画面で広げて、狭い画面で開いた）に詳細を潰さない。
       詳細の側に残す最低幅はパネルがインラインで渡す（DetailListState.DetailMinWidth。分割バーの JS も同じ値を読む）。 */
    max-width: calc(100% - var(--alt-list-dock-detail-min));
    display: flex;
    position: sticky;
    top: calc(var(--alt-sidebar-top) + 8px);
    height: calc(100vh / var(--alt-vz, 1) - var(--alt-sidebar-top) - var(--alt-sidebar-bottom) - 16px);
    box-sizing: border-box;
    background: var(--alt-surface);
    border: 1px solid var(--alt-border);
    border-radius: var(--alt-radius-md);
    z-index: 5;
}

/* 一覧から開いた画面のタブ（DetailTabs.razor）。1 つ目＝いま開いている画面（本文）、2 つ目から＝iframe。
   **ほかのタブを選んでいるあいだは本文を隠すだけ**（捨てない＝書きかけが残る）。 */
/* 帯（タブの並び＋見切れたときの一覧ボタン）。見切れた分は**横スクロールでも右上のボタンからでも**選べる（利用者の要望で両方）。 */
.alt-detail-tabs-bar {
    display: flex;
    align-items: flex-end;
    gap: 6px;
    margin-bottom: 10px;
    border-bottom: 1px solid var(--alt-border);
}

.alt-detail-tabs-strip {
    display: flex;
    flex: 1;
    min-width: 0;
    gap: 2px;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: none;
    /* **スクロールバーはタブの帯に当てているあいだだけ見せる**（利用者の要望）。消すのではなく色を透明にする
       ＝幅ごと消すと、当てた瞬間にバーの高さぶん帯が伸びてタブが上下に揺れる。 */
    scrollbar-width: thin;
    scrollbar-color: transparent transparent;
}

.alt-detail-tabs-bar:hover .alt-detail-tabs-strip {
    scrollbar-color: var(--alt-text-muted) transparent;
}

/* scrollbar-color を持たないブラウザ（Safari）向けの同じ出し分け。 */
.alt-detail-tabs-strip::-webkit-scrollbar {
    height: 6px;
}

.alt-detail-tabs-strip::-webkit-scrollbar-thumb {
    border-radius: 3px;
    background: transparent;
}

.alt-detail-tabs-bar:hover .alt-detail-tabs-strip::-webkit-scrollbar-thumb {
    background: var(--alt-text-muted);
}


/* 一覧ボタンは見切れたときだけ（印は js/detail-list.js の syncTabs）。 */
.alt-detail-tabs-more {
    display: none !important;
    margin-bottom: 4px;
}

.alt-detail-tabs-bar[data-overflow] .alt-detail-tabs-more {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    min-width: 28px;
    min-height: 26px;
}

/* ▼（下向きの三角）。文字色で描くので配色の切り替えに付いてくる。 */
.alt-detail-tabs-caret {
    width: 0;
    height: 0;
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    border-top: 6px solid currentColor;
}

.alt-detail-tab {
    flex: none;
    display: inline-flex;
    align-items: center;
    max-width: 16rem;
    padding: 0;
    border: 1px solid var(--alt-border);
    border-bottom: none;
    border-radius: var(--alt-radius-sm) var(--alt-radius-sm) 0 0;
    background: var(--alt-bg-secondary, transparent);
    color: var(--alt-text-sub);
    font-size: 0.85rem;
    cursor: pointer;
}

.alt-detail-tab-select {
    padding: 6px 12px;
    border: none;
    background: none;
    color: inherit;
    font: inherit;
    cursor: pointer;
    min-width: 0;
}

.alt-detail-tab.is-active {
    background: var(--alt-surface);
    color: var(--alt-heading);
    font-weight: 700;
    box-shadow: inset 0 2px 0 var(--alt-accent);
}

/* 上線はその画面のモジュールの色（TEST1-229。--alt-detail-tab-accent は DetailTabStrip がメニューの AccentColor から渡す）。
   選んでいるタブの青い上線（box-shadow）はこの線で置き換える＝2 本重ねると色が読めない。選んでいるかは地色と太字で分かる。 */
.alt-detail-tab.has-accent {
    border-top: 3px solid var(--alt-detail-tab-accent);
}

.alt-detail-tab.has-accent.is-active {
    box-shadow: none;
}

.alt-detail-tab-text {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.alt-detail-tab-close {
    display: inline-flex;
    padding: 4px 6px 4px 0;
    border: none;
    background: none;
    color: inherit;
    cursor: pointer;
}

.alt-detail-tab-frame {
    display: block;
    width: 100%;
    height: calc(100vh / var(--alt-vz, 1) - var(--alt-sidebar-top) - var(--alt-sidebar-bottom) - 80px);
    border: 0;
}

.app-split-main:has(> .alt-detail-tabs.is-extra-active) > .app-split-body {
    display: none;
}

/* ステータスバーの表示倍率（2026-09-26。変数を書くのは App.razor（保存済みの倍率）と wwwroot/js/zoom.js）。
   **メイン画面（本文の枠）だけに当てる**（利用者の要望）＝サイドメニュー・トップバー・ステータスバーは等倍のまま
   （倍率のボタンの位置が動くと、続けて押せなくなる）。モジュールのタブ・一覧のパネル・明細のタブは本文の枠の中なので一緒に拡大される。
   ブラウザの拡大（Ctrl／Cmd ＋）そのものはページから動かせないので、CSS の zoom で代える。
   **一覧のパネル・明細のタブ（iframe）の中では当てない**＝外の本文の枠ごと拡大されているので、当てると二重になる。

   **画面の高さ・幅（vh・vw）は --alt-vz で割り戻す**＝zoom の中では 100vh も倍率ぶん伸び、125% でページが縦に 25% 余分に伸びた（実測）。
   --alt-vz は**本文の枠だけが持つ**（ほかの要素は 1）ので、シェルの CSS（app.css・layouts.css）の vh・vw は
   `calc(100vh / var(--alt-vz, 1))` の形で書けば、本文の枠の中の要素だけが割り戻される（**新しく書くときもこの形**。
   素の 100vh を書いても例外は出ず、倍率を変えたときだけはみ出す）。DevExpress のテーマとモジュールの CSS の vh・vw は割り戻していない。
   DevExpress の一覧が倍率の中で列幅を取り違える件の補正は wwwroot/js/devexpress-zoom.js が正。
   倍率が 100% に戻ると、一覧の列幅も既定に戻す（Core の GridLayoutStore.ResetColumnWidths）。 */
html:not([data-alt-embed]) .app-body > main.container {
    --alt-vz: var(--alt-zoom, 1);
    zoom: var(--alt-vz);
}

.app-list-dock .alt-detail-tabs-bar {
    flex: none;
    margin: 6px 8px 0;
}

.app-list-dock[hidden],
.alt-detail-tabs[hidden],
.alt-detail-tab-frame[hidden],
.app-list-dock-tab-frame[hidden],
.app-list-dock-scroll[hidden] {
    display: none;
}

.app-list-dock-tab-frame {
    flex: 1;
    min-height: 0;
    width: 100%;
    border: 0;
}

/* タブのドラッグ（js/detail-list.js）。掴んでいるタブは薄く、落とす位置はそのタブの左端の線、
   一覧のパネルへ落とすときはパネルを点線で囲む。**掴んでいるあいだは iframe にポインタを渡さない**
   ＝iframe の上ではドラッグのイベントが中の文書へ行き、外の画面が落とす位置を受け取れない。 */
.alt-detail-tab.is-dragging {
    opacity: 0.5;
}

.alt-detail-tab.is-drop-before {
    box-shadow: inset 3px 0 0 var(--alt-accent);
}

.alt-detail-tabs-strip.is-drop-end {
    box-shadow: inset -3px 0 0 var(--alt-accent);
}

.app-list-dock[data-drop] {
    outline: 2px dashed var(--alt-accent);
    outline-offset: -2px;
}

/* 分割バーを掴んでいるあいだも同じ（一覧・タブのどの iframe に入っても pointerup を取りこぼさない）。
   確認の窓を掴んでいるあいだ（.app-popup-dragging。js/popup-drag.js）も同じで、こちらは文字も選ばせない。 */
body:is(.app-resizing, .app-tab-dragging, .app-popup-dragging) iframe {
    pointer-events: none;
}

body.app-popup-dragging {
    user-select: none;
}

/* 一覧を左に（利用者が入れ替えたとき）。つまみは詳細の側＝右端へ移る。 */
.app-list-dock.is-left {
    order: -1;
}

/* 詳細の側の端のつまみ（分割バー）。当てたときの色はサイドバーのつまみと同じ規則（.app-sidebar-resizer の節）。 */
.app-list-dock-resizer {
    position: absolute;
    top: 0;
    left: -11px;
    width: 6px;
    height: 100%;
    z-index: 2;
    cursor: col-resize;
    background: transparent;
    touch-action: none;
}

.app-list-dock.is-left .app-list-dock-resizer {
    left: auto;
    right: -11px;
}

/* **一覧は最低 800px の仮想幅**＝パネルが狭くても列を縮めず、パネルの下に横のスクロールバーを出す。
   縦のスクロールは iframe の中（一覧の画面そのもの）が持つ。 */
.app-list-dock-scroll {
    flex: 1;
    min-width: 0;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: none;
    border-radius: inherit;
}

.app-list-dock-frame {
    display: block;
    width: max(100%, 800px);
    height: 100%;
    border: 0;
}


/* 狭い画面（サイドバーがドロワーになる幅）では並べない＝本文と一覧の両方が読めなくなる。切り替えも出さない。 */
@media (max-width: 1024px) {
    .app-list-dock,
    .alt-detail-list-toggle {
        display: none !important;
    }
}

/* 一覧の中（iframe）ではシェルの枠を描かない（印は App.razor の先頭のスクリプトと js/detail-list.js）。
   **本文だけを残す**＝サイドバー・ヘッダー・システムエリア・タブ・お知らせの帯・ステータスバー・一覧と検索結果のパネル・詳細のタブ。
   一覧の中で一覧を並べる入れ子も作らない。 */
html[data-alt-embed] :is(.app-sidebar, .app-topbar, .app-mobile-bar, .app-nav-scrim, .app-systembar, nav.app-tabs,
    .alt-annc-banners, .app-statusbar, .app-list-dock, .app-search-dock, .app-assist-dock, .alt-detail-tabs) {
    display: none !important;
}

/* !important＝ヘッダーを持つ形は layouts.css（app.css より後に読む）が同じ詳細度で grid にする。 */
html[data-alt-embed] .app-shell {
    display: block !important;
    min-height: 0;
}

/* ===== バーコード・QR の読み取り欄の枠（Core の ScanField。2026-09-27） =====
   先頭にバーコードの絵を置き、ふつうの文字の欄と見分けられるようにする。決めごとは部品の doc が正。
   欄の幅は枠が持つ（欄は枠いっぱい）。padding-left の !important は、置いた側が padding をまとめ書きしても絵と文字が重ならないため
   （かんばんボードの読み取り欄がそう書いている）。 */
.alt-scan-field { position: relative; display: inline-block; vertical-align: middle; }
.alt-scan-field > .alt-scan-field-icon {
    position: absolute; left: 9px; top: 50%; transform: translateY(-50%);
    pointer-events: none; opacity: 0.7;
}
.alt-scan-field > input { padding-left: 34px !important; width: 100%; box-sizing: border-box; }

/* 作業者アプリの接続先の QR（/admin/app）。QR は画素のまま拡大しない（読み取りの誤りを増やさない） */
.app-connection { display: flex; gap: 24px; align-items: flex-start; flex-wrap: wrap; }
.app-connection-qr { width: 240px; height: 240px; image-rendering: pixelated; }
.app-connection-url { display: block; margin-top: 4px; word-break: break-all; }

/* 個人設定「アプリの端末」。日時と失効のボタンは折り返さない（端末名だけが折り返して幅を合わせる） */
.device-table th, .device-table td:not(:first-child) { white-space: nowrap; }

/* 時刻の入力（DxTimeEdit）のドロップダウンの「適用する」「閉じる」は絵にする（2026-10-07 洋二さんの指示）。
   時と分だけのドロップダウンは幅が狭く、文字のままだと縦に伸びる。読み上げ名と吹き出しは DevExpress が付ける
   aria-label／title が残るので、見出しの文字だけを消して絵を描く。絵は文字色で塗る（主ボタンの白抜きに合わせる） */
.dxbl-edit-dropdown:has(.dxbl-date-time-edit-time-roller) .dxbl-edit-dropdown-footer > .dxbl-btn-primary {
    --alt-dropdown-button-icon: url('icons/check-circle.svg');
}

.dxbl-edit-dropdown:has(.dxbl-date-time-edit-time-roller) .dxbl-edit-dropdown-footer > .dxbl-btn:last-child {
    --alt-dropdown-button-icon: url('icons/x-close.svg');
}

.dxbl-edit-dropdown:has(.dxbl-date-time-edit-time-roller) .dxbl-edit-dropdown-footer > .dxbl-btn:is(.dxbl-btn-primary, :last-child) .dxbl-btn-caption {
    display: inline-block;
    width: 1.1rem;
    height: 1.1rem;
    font-size: 0;
    background-color: currentColor;
    -webkit-mask: var(--alt-dropdown-button-icon) center / contain no-repeat;
    mask: var(--alt-dropdown-button-icon) center / contain no-repeat;
}

/* 日付を選ぶカレンダー（DxCalendar・DxDateEdit・DxDateRangePicker の落とし・予定表の日付の範囲）に週番号を出さない（2026-10-07 洋二さんの指示＝全モジュール）。
   DevExpress に週番号を消すパラメータは無い（WeekNumberRule は数え方だけ）ので、ここ 1 か所で隠す。
   部品はクラスではなく独自タグで選ぶ（pitfalls の「独自タグで選ぶ」）。見出しの行の先頭の空欄（週番号の列の見出し）も一緒に隠す */
dxbl-calendar .dxbl-calendar-week-number,
dxbl-calendar .dxbl-calendar-days-of-week > td {
    display: none;
}

/* ===== 添付の並びとドロップの枠（Core の AttachmentList・AttachmentInput。2026-10-07 に文書データベースから上げた＝予定表の添付も使う。NOTES-47） ===== */
/* 添付の並び（名前・大きさ・外すボタン。画像は縮小を前に出す）。 */
.alt-attachments {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .35rem;
}

.alt-attachment {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
}

.alt-attachment-thumbnail {
    max-width: 160px;
    max-height: 120px;
    border: 1px solid var(--alt-border, #d0d5dd);
    border-radius: 4px;
}

/* 縮小を押すとプレビューの窓が出る（ボタンの見た目は消して画像だけを見せる）。 */
.alt-attachment-preview-btn {
    padding: 0;
    border: 0;
    background: none;
    cursor: zoom-in;
    line-height: 0;
}

.alt-attachment-preview-btn:focus-visible {
    outline: 2px solid var(--alt-accent);
    outline-offset: 2px;
}

/* プレビューの窓の中の画像。画面に収まる大きさに縮める。 */
.alt-attachment-preview-body {
    text-align: center;
}

.alt-attachment-preview {
    max-width: 100%;
    max-height: calc(75vh / var(--alt-vz, 1));
    object-fit: contain;
}

.alt-attachment-preview-meta {
    margin: .6rem 0 0;
    display: flex;
    justify-content: center;
    gap: .6rem;
}

/* ドロップの枠（枠いっぱいに透明のファイル選択の欄を重ね、ドロップもクリックもその欄が受ける）。 */
.alt-file-drop {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-height: 4rem;
    padding: .75rem 1rem;
    border: 2px dashed var(--alt-border, #d0d5dd);
    border-radius: 6px;
    color: var(--alt-muted, #667085);
    text-align: center;
}

.alt-file-drop[data-dragging] {
    border-color: var(--alt-accent, #2b6cb0);
    background: color-mix(in srgb, var(--alt-accent, #2b6cb0) 8%, transparent);
}

.alt-file-drop:focus-within {
    outline: 2px solid var(--alt-accent);
    outline-offset: 2px;
}

.alt-file-drop.is-disabled {
    opacity: .5;
}

.alt-file-drop-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}

.alt-file-drop.is-disabled .alt-file-drop-input {
    cursor: default;
}

/* 入力欄や一覧の上に落とすとファイル選択の欄へ流し込む枠（data-file-drop＝js/file-drop.js）。ファイルを持って上にいるあいだだけ点線で囲む。
   枠の外へはみ出させない（内側に引く）＝一覧を包む枠では外側の線が隣と重なる。 */
[data-file-drop][data-dragging] {
    outline: 2px dashed var(--alt-accent);
    outline-offset: -2px;
    border-radius: 6px;
    background: var(--alt-accent-soft);
}

/* ウォッチ中（/watching）のウォッチ用メモ。本人専用の書き込みなので赤字で目立たせる（Pm の旧ウォッチ中と同じ見た目） */
.alt-watching-note { color: var(--alt-danger); font-size: 0.82rem; white-space: pre-wrap; word-break: break-word; }

/* ---- 個人 TODO（/todos。2026-10-11 に pm.css の .pm-todo-* から移した・TEST1-544）---- */
.alt-todo-target-current { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.alt-todo-add { display: flex; gap: 8px; margin-bottom: 1rem; max-width: 720px; }
.alt-todo-add .alt-todo-add-input { flex: 1; }
/* 任された TODO の本人を選ぶ欄（NOTES-109）。見出しと範囲は折り返さず、狭い画面では欄ごと折り返す */
.alt-todo-owner { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-bottom: 1rem; max-width: 720px; }
.alt-todo-owner > label, .alt-todo-owner > .meta { white-space: nowrap; }
.alt-todo-owner .alt-todo-owner-select { width: min(320px, 100%); }
.alt-todo-section { max-width: 860px; }
.alt-todo-done-head { cursor: pointer; user-select: none; }
.alt-todo-row { display: flex; align-items: flex-start; gap: 8px; padding: 5px 2px; border-bottom: 1px solid var(--alt-border); }
.alt-todo-row:last-child { border-bottom: none; }
.alt-todo-check { width: 16px; height: 16px; margin-top: 4px; cursor: pointer; flex-shrink: 0; }
.alt-todo-main { flex: 1; min-width: 0; }
.alt-todo-title-line { display: flex; align-items: center; gap: 8px; }
.alt-todo-title { cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.alt-todo-row.is-done .alt-todo-title { text-decoration: line-through; color: var(--alt-text-muted); }
.alt-todo-due { flex-shrink: 0; font-size: 0.8rem; color: var(--alt-text-muted); }
.alt-todo-due.alt-overdue { color: var(--alt-danger); }   /* 上の薄い色に勝たせる（.alt-overdue より詳細度が高い） */
.alt-todo-target { flex-shrink: 1; max-width: 18rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.85rem; text-decoration: none; }
.alt-todo-target:hover { text-decoration: underline; }
/* 操作（着手・編集・削除）は右端の 1 列。件名・期限・関連課題が縮み、操作は縮まない＝件名が長くても重ならない。 */
.alt-todo-actions { display: flex; align-items: center; gap: 6px; margin-left: auto; flex-shrink: 0; }
/* メモは最大 5 行まで表示（超えた分は省略。全文は編集ダイアログかツールチップで） */
.alt-todo-note { margin-top: 2px; font-size: 0.85rem; line-height: 1.5; color: var(--alt-text-secondary); white-space: pre-wrap; overflow-wrap: break-word; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 5; line-clamp: 5; overflow: hidden; cursor: pointer; }

/* 課題などのキーの札（pm.css の .pm-key と同じ見た目。シェルはモジュールの CSS を借りない＝そのモジュールが無効でも崩れない） */
.alt-todo-key { display: inline-block; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; background: var(--alt-bg-muted); border-radius: 4px; padding: 1px 6px; font-size: 0.85em; color: inherit; }
