/* ==== Culminans.Shift: シフト管理の画面スタイル（全画面に読み込む） ====
   フォームグリッド・カードはシェルの app.css（alt-form-grid / alt-span2 / alt-card / alt-card-title）を使う。
   **クラス名は shift- で始める**＝モジュールの CSS は登録順にまとめて読み込まれるので、
   ほかのモジュールと同じ名前を使うとどちらが勝つかが順番まかせになる（§7 の落とし穴）。 */

/* 打刻端末の「アプリに組み付け」（組み付けの QR コードを出す。2026-10-20）。もとはシェルの link（鎖）で、
   何が出るのか分からなかったので QR コードの絵にした。Obsidian の MELab/Share/icons の qr-code-02（48px）。
   暗いテーマの反転は themes.css の .alt-ico がまとめて掛ける（予定表の PNG と同じ）。 */
.alt-ico-qr-code { background-image: url('icons/qr-code.png'); }

.shift-readonly { padding: 4px 0; min-height: 1.6em; }
/* 従業員の詳細の見出しの行（氏名の横にログイン ID）。**見出しの下の余白は行へ移す**＝h1 に残すと、
   文字の並びの基準線が余白ごと測られてログイン ID が上へずれる（Pm の .pm-project-title と同じ）。 */
.shift-member-title { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; margin-bottom: var(--alt-page-title-gap); }
.shift-member-title > .page-title { margin-bottom: 0; }
.shift-input-num { max-width: 120px; }
.shift-input-code { max-width: 160px; }
.shift-input-date { max-width: 180px; }
.shift-input-coord { max-width: 180px; }   /* 緯度・経度（-123.456789 が入る幅） */

/* 地図の器（拠点の「地図から選択」）。**高さは指定が要る**＝Google Maps は器の高さが 0 だと何も描かない。
   画面の高さに合わせて縮む（スマホの横向きでボタンが隠れない）。 */
.shift-map { height: min(60vh, 460px); width: 100%; border: 1px solid var(--alt-border); border-radius: 4px; }
.shift-input-time { max-width: 140px; }
.shift-color-input { width: 48px; height: 30px; padding: 0; border: 1px solid var(--alt-border); border-radius: 4px; background: none; }

.shift-badge {
  display: inline-block; padding: 1px 8px; border-radius: 10px; font-size: 0.8rem; line-height: 1.5;
  white-space: nowrap;
}
.shift-badge.sm { padding: 0 6px; font-size: 0.72rem; }
/* スキルのタグを並べる（従業員の一覧とシフト表の簡易ビュー）。**隙間は CSS で持つ**＝Razor の
   `<text> </text>` は空白だけだと出力されず、タグがくっついて読めない（2026-09-07 に実測）。 */
.shift-skill-list { display: inline-flex; flex-wrap: wrap; gap: 4px; }

/* 勤務区分のプルダウンの選択肢（タグ ＋ 名前）。タグと文字の縦位置を揃えるだけ。 */
.shift-pattern-option { display: inline-flex; align-items: center; gap: 6px; }

/* 勤務区分の絞り込み（DxTagBox）。**幅の下限が要る**＝選んだタグが 1 つも無いと入力欄が中身の幅まで
   潰れ、「すべての勤務区分」の文字が「す…」になる（DxComboBox と違い、入力欄の幅が中身で決まる）。 */
.shift-pattern-filter { min-width: 240px; max-width: 360px; }

/* 「自分のシフト」のメモ。**押す的は列の幅いっぱい**＝スマホではこの列に 2〜3 文字ぶんしか残らず、
   小さいボタンだと押しにくい。書いたメモは折り返して読めるようにする（開かないと読めないと、書いたことを忘れる）。 */
.shift-note-btn { width: 100%; min-width: 6em; }
/* ボタンの下の頭出し。**1 行に収める**＝行の高さを揃えたいので、はみ出したぶんは点で示す
   （全文は title と、開いた窓で読める）。 */
.shift-note-preview {
  margin-top: 2px; font-size: 0.78rem; color: var(--alt-text-sub);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.shift-note-preview.is-empty { color: var(--alt-text-muted); }
.shift-note-input { width: 100%; }

/* ==== シフト表（従業員 × 日付の格子） ====
   素の table で描く＝マスは「区分のタグ 1 つ」で、グリッドに要る並べ替えや幅の保存より
   横にスクロールしても氏名の列が残ることのほうが要る。 */
/* **表は画面幅へ引き伸ばさない**（2026-09-16・洋二さんの指示）＝列は中身の幅で、枠も表に沿わせる（fit-content）。
   引き伸ばすと表示する日数が少ないときに余った幅が氏名の列と日付の列へ配られて間延びする（3 日表示で氏名の列が 631px）。
   幅が足りないときは枠の中で横にスクロールする（max-width）。 */
/* 枠は時間の見方（.shift-hours-wrap）と 1 つの規則で持つ＝同じ画面で見方を切り替える 2 つなので、写すと片方だけ直る。
   **地色は面の色**（2026-09-29）＝マスは地色を持たないので、敷かないと背景の線画が透ける。
   2 つに写していたころは時間の見方にだけ地色があり、日の見方のマスから線画が透けていた。 */
.shift-roster-wrap, .shift-hours-wrap { overflow: auto; overscroll-behavior-x: none; max-height: calc(100vh - 260px); border: 1px solid var(--alt-border); border-radius: 6px; background: var(--alt-surface); }
.shift-roster-wrap { width: fit-content; max-width: 100%; }
.shift-roster { border-collapse: separate; border-spacing: 0; font-size: 0.85rem; }
.shift-roster th, .shift-roster td {
  border-right: 1px solid var(--alt-bg-muted); border-bottom: 1px solid var(--alt-bg-muted);
  padding: 2px 4px; text-align: center; white-space: nowrap; vertical-align: middle;
}
.shift-roster thead th { position: sticky; top: 0; z-index: 3; background: var(--alt-bg-subtle); font-weight: 600; font-size: 0.78rem; }
.shift-roster th.shift-name, .shift-roster td.shift-name {
  position: sticky; left: 0; z-index: 2; text-align: left; background: var(--alt-surface);
  min-width: 160px; border-right: 1px solid var(--alt-border);
}
.shift-roster thead th.shift-name { z-index: 4; background: var(--alt-bg-subtle); }
.shift-roster td.shift-name .meta { display: block; font-size: 0.72rem; }
/* 週の頭は左の線を濃く（週の境が読めるように）。 */
.shift-roster th.week, .shift-roster td.week { border-left: 2px solid var(--alt-border-strong); }
/* 休業日・出られない曜日は薄く塗る（色だけに頼らず見出しに名前も出す）。 */
.shift-roster th.holiday { color: var(--alt-danger); }
.shift-roster td.off { background: var(--alt-bg-muted); }
.shift-roster td.unavailable { background: rgba(220, 90, 80, 0.12); }
.shift-roster td.preferred { background: rgba(80, 160, 90, 0.12); }
/* 本人からの申し出がある印（左上）。地色を持たないメモだけの日も、ここで存在が見える。
   位置は左上＝右下は「＋」、タグの右上は「予」で埋まっている。td.cell が position: relative を持つ。 */
.shift-roster td.cell > .shift-cell-availability {
  position: absolute; top: 0; left: 1px; font-size: 0.6rem; line-height: 1;
  color: var(--alt-text-muted); pointer-events: none;
}
.shift-roster td.today { background-color: rgba(77, 124, 199, 0.10); }
/* 今日の列の見出し。**貼り付く見出しは透けさせない**＝半透明を敷くと、上の
   .shift-roster thead th の不透明な地色を上書きしてしまい、下を流れる本文の数字が
   日付に重なって見える（2026-09-07 実測）。色は地色に重ねて不透明のまま濃くする。 */
.shift-roster th.today { background-image: linear-gradient(rgba(77, 124, 199, 0.10), rgba(77, 124, 199, 0.10)); }
/* マスのホバーの枠（編集できる人だけ）。**マスそのものは押しても開かない**＝新しく置く入口は右下の「＋」（.shift-cell-add）。
   position: relative は「＋」の置き場所の基準。 */
.shift-roster td.cell { position: relative; min-width: 56px; }
/* マスの名札は共通の data-alt-float-tip（見た目は app.css の .alt-float-tip、位置は Web の js/float-tip.js）。
   2026-09-26 に生産計画表が 2 つ目の要求者になったので Shift から上げた。 */

.shift-roster td.cell:hover { outline: 2px solid var(--alt-primary, #4d7cc7); outline-offset: -2px; }
.shift-roster td.cell.readonly:hover { outline: none; }
/* 空きから新しく置く入口＝マス（時間の見方は日の区切り）のホバーで右下に出る小さな四角いボタン（2026-09-15）。
   マス全体を押せる形にしていたときは、タグ（既存の行）と空き（新規）のどちらを押したかで開く窓が変わり、
   どちらの窓が出るのか読めなかった。**タッチ端末（hover が無い）では常に出す**＝ホバーできないと入口が無くなる。
   キーボードで来たときも出す（:focus-visible）。z-index は時間の見方で帯の上に出すため
   （日の見方では貼り付く氏名の列＝z-index 2 より下なので、横に転がしても氏名に重ならない）。
   **形（枠・地・中央寄せ）は Core の .alt-icon-btn-framed を重ねる**＝ここが持つのは位置・大きさ・ホバーで出す仕掛けだけ。
   **クラス 2 つで当てる**＝あちらの枠つきは大きさを操作の高さに揃えるので、1 つだと読み込みの順番しだいで大きさが負ける。 */
.alt-icon-btn.shift-cell-add {
  position: absolute; right: 2px; bottom: 2px; z-index: 1; width: 20px; height: 20px; border-radius: 3px;
  opacity: 0; transition: opacity 0.1s;
}
.shift-roster td.cell:hover .shift-cell-add, .shift-hours-slot:hover .shift-cell-add, .alt-icon-btn.shift-cell-add:focus-visible { opacity: 1; }
@media (hover: none) { .alt-icon-btn.shift-cell-add { opacity: 1; } }
/* 状態の印（タグの上に小さく）。欠員は赤枠で目立たせる。 */
.shift-cell-vacant .shift-badge { outline: 2px solid var(--alt-danger); outline-offset: 1px; }
.shift-cell-planned .shift-badge { opacity: 0.75; border: 1px dashed rgba(0, 0, 0, 0.35); }
/* 仮確定（2026-09-16）＝本人の確認待ち。予定と同じく点線の枠で「まだ決まっていない」を示し、右上の「仮」で予定と見分ける。
   **薄くしない**＝確認を待っているだけで、担当者の中では配ったシフト（予定より確定に近い）。 */
.shift-cell-pendingconfirmation .shift-badge { border: 1px dashed rgba(0, 0, 0, 0.45); }
/* 予定のタグには右上に印を出す（2026-09-07・TEST1-79）。点線の枠だけでは確定と見分けられない
   ＝区分の色が濃いと枠が背景に沈み、薄いと枠そのものが見えない。
   **箱の形を持つのは状態のクラスではなく .shift-cell-badge**＝状態のクラスに padding を持たせると、
   プランの確定で予定が一斉に確定へ動いた瞬間にマスの幅が縮んで盤面が横にずれる
   （この表は table-layout: auto なので中身の幅がそのまま列の幅になる）。
   印の地は区分の色から独立させる（不透明な地＋枠）＝タグの色は人が自由に選ぶので、透かすと読めなくなる。
   **印は 1 文字**＝場所は padding-right で外に空けており、印がタグへ食い込む幅（印の幅 − 12px）が
   `.shift-badge.sm` の左右の余白（6px）を超えると区分のコードの末尾が隠れる
   （実測 2026-09-07: `予` 16.8px＝食い込み 4.8px／`P` 13.8px＝食い込み 1.8px。
   直す前は `MIDNIGHT` が `MIDNIGH` に見えていた）。**Roster_PlannedMark を 2 文字にすると破れる**
   ＝長いコードの列だけ末尾が欠け、例外もログも出ない。
   inline-block は印の `top` の起点を行のストラットではなくタグの箱にするため（外すと 0.5px 下がる）。 */
/* 押すと編集の窓が開くので、当てたら指差しにする（2026-09-16）。プランから見た正式な行（foreign）は押せないので戻す。 */
.shift-cell-badge { position: relative; display: inline-block; padding-right: 12px; cursor: pointer; }
.shift-cell-badge.shift-cell-foreign { cursor: default; }
.shift-cell-planned-mark {
  position: absolute; top: -2px; right: 0; font-size: 0.55rem; line-height: 1; padding: 1px 3px;
  border: 1px solid var(--alt-border-strong); border-radius: 6px;
  background: var(--alt-surface); color: var(--alt-text-sub);
}
.shift-cell-covered .shift-badge, .shift-cell-cancelled .shift-badge { opacity: 0.4; text-decoration: line-through; }
.shift-cell-absent .shift-badge, .shift-cal-block.shift-cell-absent { opacity: 0.6; border: 1px solid var(--alt-danger); }
/* マスの中の小さい添え字は 2 つ＝下の印（.shift-cell-mark）と、タグの横の時間帯（.shift-cell-time。
   2026-09-07・TEST1-82。「時間帯を出す」を立てているあいだだけ）。**大きさと色は一緒に決める**
   ＝片方だけ直すと、同じマスの中で横と下の文字が食い違う。折り返しは .shift-roster td の
   nowrap を継ぐ（どちらもこの表の中でしか使わないので、あちらに任せてよい）。 */
.shift-cell-mark, .shift-cell-time { font-size: 0.65rem; color: var(--alt-text-sub); }
.shift-cell-mark { display: block; line-height: 1.1; }
.shift-cell-time { margin-left: 4px; }
/* 本人が伝えた休みのピル（AM・PM・時刻指定・早退・全休。2026-09-16・TEST1-126）。
   **マスの中ではタグの横に小さく**＝行を増やさない（下の印は block で、混ぜると盤面が縦にずれる）。
   **全休だけ危険色**＝行そのものが欠員（代替の手配が要る側）で、半日だけ抜ける話と重さが違う。 */
.shift-leave-pill {
  display: inline-block; margin-left: 3px; padding: 0 5px; border-radius: 999px; vertical-align: middle;
  font-size: 0.6rem; font-weight: 600; line-height: 1.5; white-space: nowrap;
  background: var(--alt-warning-bg); color: var(--alt-warning-text); border: 1px solid var(--alt-warning-border);
}
.shift-leave-pill.is-full { background: var(--alt-danger-bg); color: var(--alt-danger-text); border-color: var(--alt-danger-border); }
/* 自分のシフトはスマホで読む画面なので一回り大きく、時刻は横に並べる。 */
.shift-my .shift-leave-pill { font-size: 0.75rem; margin-left: 6px; }
.shift-leave-range { margin-left: 4px; }
/* 割り当ての窓の休暇連絡の取消（伝えた休みのピルと取り消すボタンを 1 行に）。 */
.shift-leave-cancel { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }

/* 時刻を上書きしたマスは太字にする＝「時間帯を出す」を立てているあいだは全マスに時刻が並ぶので、
   例外（区分の時間帯と違うマス）が埋もれる。立てていないときはそもそも上書きのマスにしか出ない。 */
.shift-cell-time.is-override { font-weight: 600; color: var(--alt-text-strong); }

/* 充足の行（必要人数 vs 埋まっている人数）。段階は容量との比で色を決める。 */
.shift-roster tr.coverage td { font-size: 0.75rem; }
.shift-roster tr.coverage td.shift-name { font-weight: 600; }
.shift-cov-ok { background: var(--alt-success-bg, rgba(80, 160, 90, 0.15)); }
.shift-cov-short { background: var(--alt-danger-bg, rgba(220, 90, 80, 0.18)); font-weight: 600; }
.shift-cov-over { background: var(--alt-warning-bg, rgba(230, 170, 60, 0.18)); }
.shift-cov-none { color: var(--alt-text-muted); }
/* 充足のマスの「OK」と、部署名・区分のタグのまとめ（2026-10-16。理由は ShiftRoster の CoverageLine の doc）。
   ピルの形と青は共通の状態の札（app.css の .alt-status-pill.is-inprogress）で、ここは小さいマスに合わせて詰めるだけ。
   多すぎるマスの赤は LoadClass の over に乗せる（判定を画面に写さない）。 */
.shift-roster tr.coverage .alt-status-pill { margin-right: 4px; padding: 0 6px; line-height: 1.5; font-size: 0.68rem; font-weight: 700; }
.shift-roster td.shift-cov-over .alt-status-pill { background: var(--alt-danger-bg); color: var(--alt-danger-text); }
/* 繰り返しの頭は**透明にするだけ**（visibility: hidden にしない）＝幅を残しつつ読み上げには残す（どの部署・区分の行かが読める）。
   当てても名札が出ないよう、マウスは素通りさせる。 */
.shift-cov-repeat { opacity: 0; pointer-events: none; }
.shift-cov-anyone { color: var(--alt-text-muted); font-weight: 400; }
/* 先頭の行は見出しのすぐ下なので引かない。 */
.shift-roster tr.coverage.is-dept-start:not(:first-child) td { border-top: 2px solid var(--alt-border-strong); }
/* 同じ部署の中の区分の切れ目（2026-10-19。理由は ShiftRoster の CoverageLine の doc）。
   部署の切れ目（2px）より細い線で段を分ける。--alt-border は明るいテーマでマスの罫線と見分けが付かないので strong を使う。 */
.shift-roster tr.coverage.is-pattern-start td { border-top: 1px solid var(--alt-border-strong); }

/* 足りないマスは押すと埋められる（2026-09-11）。押せるのは置ける人だけなので、
   カーソルと枠もそのときだけ付ける（ShiftRoster の fillable が同じ式を見る）。 */
.shift-roster tr.coverage td.is-fillable { cursor: pointer; }
.shift-roster tr.coverage td.is-fillable:hover { outline: 2px solid var(--alt-danger); outline-offset: -2px; }

/* 氏名の右隣の勤怠スコアの輪（2026-09-16）。**部品ではなく円錐グラデーションで描く**
   ＝この列は行の数だけ描かれる（150 名なら 150 個）ので、グラフの部品を並べると描き直しのたびに重い。
   値は `--shift-score`（0〜100）で受け、真ん中を地色で抜いてドーナツにする。数字はツールチップ（data-alt-float-tip）に出す。
   色は上限の線と同じ区切り＝ふだんはプライマリ、75% 以下は注意、50% 以下は赤。 */
.shift-score-mini {
  /* **当たり判定は輪より大きく**＝18px の丸は狙いにくいので、外側に余白を持たせて名札を出しやすくする
     （見た目の大きさは背景の丸のまま＝padding は背景を広げないよう background-clip で切る）。 */
  display: inline-block; width: 18px; height: 18px; border-radius: 50%; margin-left: 4px; vertical-align: middle;
  position: relative; flex: none; cursor: help;
  /* **真上（12 時）から時計回り**（conic-gradient の既定の向き）＝0% と 100% の境が真上に来る。
     **欠けは白抜き**＝地色ではなく白で、輪郭が消えないように細い枠を付ける。 */
  background: conic-gradient(from 0deg, var(--shift-score-color, var(--alt-primary, #4d7cc7))
    calc(var(--shift-score, 100) * 1%), #fff 0);
  box-shadow: inset 0 0 0 1px var(--alt-border);
}
/* 穴は ::before で描く（真ん中を地色で抜いてドーナツにする）。 */
.shift-score-mini::before {
  content: ""; position: absolute; inset: 5px; border-radius: 50%; background: var(--alt-surface);
}
.shift-score-mini.is-mid { --shift-score-color: var(--alt-warning, #d9a441); }
.shift-score-mini.is-low { --shift-score-color: var(--alt-danger); }

/* 勤怠スコアのドーナツ（2026-09-16。氏名を押した窓の中。シフトを編集できる人にだけ出る）。
   **数字は輪の中央に重ねる**＝ドーナツの穴に置くことで、凡例を出さずに何の割合かが読める。 */
.shift-score-body { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
/* **輪の大きさはここだけ**（グラフ側は 100% で受ける）＝2 か所に書くと、片方だけ動かしたときに中央の数字がずれる。 */
.shift-score-chart { position: relative; width: 140px; height: 140px; }
.shift-score-value {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: 1.6rem; font-weight: 700; pointer-events: none;
}
.shift-score-value .unit { font-size: 0.9rem; font-weight: 600; margin-left: 2px; }
.shift-score-facts { display: flex; flex-direction: column; gap: 4px; }
.shift-score-cap { color: var(--alt-danger); font-weight: 600; }

/* 赤い丸みのボタン 2 つ（2026-09-16）＝不足のある日の日付と、未確定が残っている人の印。
   **共通のぶんは 1 か所**（枠・丸み・当てたときの反転）で、違うのは地色と字送りだけ。 */
.shift-danger-pill {
  border: 1px solid var(--alt-danger); border-radius: 999px; line-height: 1.3; cursor: pointer;
}
.shift-danger-pill:hover { background: var(--alt-danger); color: #fff; }
/* 不足のある日の日付＝クリックで自動の割り当て、右クリックで手動充当の窓。
   出すのは置ける人のときだけ（ShiftRoster の ShortDays が同じ式を見る）。
   **字は見出しのまま**（font: inherit）＝不足の日だけ大きさが変わると、日付の列がずれて見える。 */
.shift-day-pill { background: var(--alt-danger-bg, rgba(220, 90, 80, 0.18)); color: inherit; font: inherit; padding: 0 8px; }
/* 未確定（確定にできる予定）が残っている人の印＝赤い「！」。押すと「シフト確定」の窓が開く。
   **残っていない人には出さない**ので、出ていること自体が「まだ確定していない」の合図になる。 */
.shift-confirm-alert {
  background: var(--alt-surface); color: var(--alt-danger);
  font-size: 0.72rem; font-weight: 700; padding: 0 6px; margin-left: 4px;
}
/* 埋める窓（枠の見出し・不足の数・強制配置の印・選んだ行）。 */
.shift-fill-slot { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin: 0 0 4px; }
.shift-fill-short { color: var(--alt-danger); font-weight: 600; }
.shift-fill-force { color: var(--alt-warning, #b7791f); margin-left: 6px; }
.shift-candidates tr.is-picked { background: var(--alt-bg-subtle); }
/* 行のどこを押しても選べる表（充当の窓。2026-09-16）＝押せる行にだけ指の形を出す。 */
.shift-candidates tr.is-clickable { cursor: pointer; }
/* 割り当ての窓の「状態を変更」のボタン＝左寄せで折り返す（操作列の .dialog-buttons は右寄せなので使わない）。 */
.shift-status-buttons { display: flex; flex-wrap: wrap; gap: 0.5rem 0.75rem; margin-top: 0.5rem; }
/* 組（確定・欠員｜出勤・欠勤｜予定・取消）。2 つ目からは左に区切り線を引く。 */
.shift-status-group { display: flex; gap: 0.5rem; }
.shift-status-group + .shift-status-group { border-left: 1px solid var(--alt-border-strong); padding-left: 0.75rem; }
/* シフト表の「すべて展開する／すべて折りたたむ」＝文言が入れ替わっても幅を変えない（右の「出力」がずれないように）。 */
.shift-toggle-all { min-width: 9.5em; }
/* 状態で使えない部品（2026-09-16。印は Models/ShiftUnavailable）。PC の幅では押せない状態で残して並びを保ち（人は位置で覚える）、
   スマホ・タブレットの幅（1024px 以下＝サイドメニューが引き出しになる線。viewport.js と同じ）では隠す。
   DevExpress の部品は自分の display を持つので !important で勝つ。 */
@media (max-width: 1024px) {
    .shift-unavailable { display: none !important; }
    /* 組の区切り線は、見えている組の 2 つ目から引き直す（隠れた組のぶん線がずれないように）。 */
    .shift-status-group + .shift-status-group { border-left: none; padding-left: 0; }
    .shift-status-group:not(.shift-unavailable) ~ .shift-status-group:not(.shift-unavailable) { border-left: 1px solid var(--alt-border-strong); padding-left: 0.75rem; }
}
/* 充当の窓の操作列＝「確定にする」を「割り当てる」の左に並べる（Core の操作列の部品はそのまま中に置く）。 */
.shift-fill-actions { display: flex; align-items: center; justify-content: flex-end; gap: 0.5rem; margin-top: 1rem; }
.shift-fill-actions .dialog-buttons { margin-top: 0; }

/* 部署のタブ（シフト表。2026-09-11）。プランがその部署を受け持っているあいだは押させない
   ＝止めているのは画面側（ChangeDepartmentTabAsync）で、ここは「触れないと分かる見た目」だけ。 */
.shift-dept-tabs { margin-bottom: 8px; }
.shift-dept-tabs.is-locked { opacity: 0.6; pointer-events: none; }

/* 部署の見出しの行（部署でまとめたとき。2026-09-11）。塊の切れ目が読めるよう充足の行より濃く塗る。
   **氏名の列にも同じ地色を当てる**＝あの列は左に貼り付いていて自分の地色を持つので、
   行にだけ塗ると見出しの左端 1 列だけ色が違う。 */
.shift-roster tr.shift-group td { background: var(--alt-bg-muted); font-weight: 600; border-top: 2px solid var(--alt-border-strong); }
.shift-roster tr.shift-group td.shift-name { background: var(--alt-bg-muted); font-size: 0.85rem; }
/* 畳む・広げるボタン（実体はボタン・見た目はただの見出し＝土台の .linklike から下線と色を戻す）。 */
.shift-group-toggle { padding: 0; color: inherit; text-decoration: none; font-weight: 600; }
.shift-group-toggle:hover { text-decoration: underline; }
.shift-group-caret { display: inline-block; width: 1em; color: var(--alt-text-muted); }

/* ==== 当日の表（スマホでも読める縦の一覧） ==== */
.shift-today-nav { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
/* 押せないボタンの理由を出すための包み（不活性の button はブラウザによってホバーを拾わず、
   ボタン自身に付けても出ない）。並びを崩さないよう、ボタンと同じ大きさの箱にする。
   名札そのものは Web の js/float-tip.js が貼る（data-alt-float-tip）。 */
.shift-btn-hint { display: inline-flex; }
/* **押せないボタンの上ではボタンに当てさせない**（2026-09-16）＝名札は当たった先から親を辿って探すので、
   ボタンがホバーを飲むブラウザでは包みに届かず、理由が出ないまま黙って消える（`title` はブラウザが
   親を辿るので今まで表に出ていなかった）。**押せるときは通さない**＝クリックが要る。 */
.shift-btn-hint > button:disabled { pointer-events: none; }
.shift-today-dept { margin-bottom: 14px; }
.shift-today-dept h2 { font-size: 1rem; margin: 8px 0 4px; }
.shift-today-pattern { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; padding: 4px 0; border-bottom: 1px solid var(--alt-bg-muted); }
.shift-today-pattern .label { min-width: 140px; font-weight: 600; }
.shift-today-person { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: 6px; background: var(--alt-bg-subtle); }
.shift-today-person.vacant { background: rgba(220, 90, 80, 0.15); border: 1px solid var(--alt-danger); }
.shift-today-person.planned { border: 1px dashed var(--alt-border-strong); }
.shift-today-person.me { outline: 2px solid var(--alt-primary, #4d7cc7); }
.shift-today-cov { font-size: 0.78rem; color: var(--alt-text-sub); }
.shift-today-cov.short { color: var(--alt-danger); font-weight: 600; }

/* ==== 自分のシフト ==== */
/* スマホでは 6 列が入りきらないので、**枠の中で横に転がす**（シフト表と同じ作法）。
   min-width を置かないと列が均等に潰れ、メモの欄が 2〜3 文字ぶん（実測 30px）になって押せない。 */
.shift-my-wrap { overflow-x: auto; overscroll-behavior-x: none; }
.shift-my { width: 100%; min-width: 620px; border-collapse: collapse; font-size: 0.9rem; }
.shift-my th, .shift-my td { padding: 6px 8px; border-bottom: 1px solid var(--alt-border); text-align: left; vertical-align: middle; }
.shift-my tr.off td { color: var(--alt-text-muted); }
.shift-my tr.today td { background-color: rgba(77, 124, 199, 0.10); }

/* ==== 代替候補・警告 ==== */
.shift-candidates { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
.shift-candidates th, .shift-candidates td { padding: 4px 6px; border-bottom: 1px solid var(--alt-border); text-align: left; vertical-align: top; }

/* 必要人数の窓（プランから見る）。表そのものは .shift-candidates（窓の中の小さい表の共通の形）を
   そのまま使い、ここに置くのは差だけ。**縦に伸ばすのは表だけ**＝窓ごと伸ばすと案内と閉じるボタンまで
   流れて、行を読みながら閉じられなくなる。DxPopup の中身に当てる名前は BodyCssClass で付ける（§7）。 */
.shift-plan-reqs-body { max-height: 84vh; }
/* 入力フォームの幅の上限（--alt-form-max＝800px）は、窓が alt-form-wide を名乗って外す（app.css。上限のままだと
   窓が 1152px あっても中身が 800px で止まり、いちばん右の「適用日数」が横スクロールの外に出る）。
   ここで外すのは高さの上限だけ＝下の枠が自分でスクロールするので、二重にすると入れ子のスクロールになる。 */
.shift-plan-reqs-body .dialog-form { max-height: none; overflow: visible; }
.shift-plan-reqs-scroll { overflow: auto; overscroll-behavior-x: none; max-height: 60vh; border: 1px solid var(--alt-border); border-radius: 4px; }
/* 見出しは貼り付ける（行が多いので、スクロールすると何の列か分からなくなる）。 */
.shift-plan-reqs-scroll thead th { position: sticky; top: 0; z-index: 1; background: var(--alt-bg-subtle); }
/* **どの列も折り返さない**＝折り返させると「月 火 水 木 金」や「フォークリフト」が縦に積まれて
   行の高さが数倍になり、19 行が画面に収まらなくなる。はみ出したぶんは上の枠の中で横に流す
   （枠を付ける前は窓そのものからはみ出して、いちばん右の「適用日数」が読めなかった）。 */
.shift-plan-reqs-scroll th, .shift-plan-reqs-scroll td { white-space: nowrap; }
.shift-plan-reqs-cmd .dxbl-btn { margin-right: 4px; }
/* 適用されない行は薄く出す（消さない＝「なぜ適用されないのか」を期間と曜日の欄から読めるように）。 */
.shift-plan-reqs-scroll tr.is-idle { opacity: 0.55; }
.shift-plan-reqs-off { color: var(--alt-text-muted); }
.shift-plan-reqs-add { display: flex; align-items: center; gap: 12px; margin-top: 8px; }
/* 改行を活かす（理由や警告は 1 行 1 件で組み立てて渡ってくる）。割り当てのダイアログと
   「自分のシフト」も同じ札を使うので、ここから外さないこと。
   **文字列をそのまま入れる札だけに使う**＝中に部品（RenderFragment）を入れる札に付けると、
   Razor が札の中に書く改行と字下げまで行として出る（2026-09-11 に叩き台の結果の上へ空行が 2 本出た）。
   そちらは .shift-notice を使う。 */
.shift-warnings { white-space: pre-wrap; font-size: 0.85rem; }
/* 折りたためる札（シフト表）。**札そのものは pre-wrap にしない**＝改行を活かすのは本文だけ。 */
.shift-notice { font-size: 0.85rem; }
/* 長い文言は 30 行ぶんの枠に収める（叩き台の結果は埋まらなかった枠を全部並べるので数百行になる）。
   枠の中は転がせて、ボタンで枠ごと外せる。行数は ShiftRoster.NoticeLines と揃えること。 */
.shift-notice-body { white-space: pre-wrap; }
.shift-notice-body.is-clipped { max-height: calc(30 * 1.5em); overflow: auto; }
/* 文の中に置くボタン（見た目はリンク・実体はボタン）。**土台は app.css の .linklike**（背景・枠・font）で、
   ここが足すのは詰めと色と下線だけ。宣言を 2 つに分けると片方だけ色や下線が動いて見た目が食い違う。
   **色はテーマの変数から取る**＝ここに書いてあった --alt-primary はどこにも定義がなく、
   フォールバックの固定色が常に効いていた（テーマを変えても追従しない。2026-09-07 に気付いた）。 */
.shift-notice-toggle, .shift-name-link {
  padding: 0; text-align: left; color: var(--alt-brand); text-decoration: underline;
}
.shift-notice-toggle { margin-top: 6px; }
/* 時間の見方の氏名は縦並びの flex の子なので、伸ばさない（押せる範囲を氏名の幅に留める）。 */
.shift-name-link { align-self: flex-start; }
/* 氏名と「シフトを確定」の印の 1 行（日の見方の表と時間の見方の両方に効く）。
   **大きさはシェルの行の中の版（.alt-grid-commands .alt-icon-btn）と同じ 24px**＝3 つ目の寸法を作らない。
   **上下の負の余白で行の高さを文字に任せる**＝24px の箱がそのまま行の高さに入ると、日の見方は全行が伸び、
   時間の見方は 40px の行（.shift-hours-row）から部署名がはみ出す。 */
.shift-name-line .alt-icon-btn { width: 24px; height: 24px; margin: -4px 0 -4px 4px; vertical-align: middle; }
.shift-reasons { font-size: 0.78rem; color: var(--alt-text-sub); }

/* タイムライン（Production と同じ見た目） */
.shift-timeline { list-style: none; padding: 0; margin: 0; }
.shift-timeline li { padding: 6px 0; border-bottom: 1px solid var(--alt-bg-muted); font-size: 0.88rem; }
.shift-timeline .who { color: var(--alt-text-sub); font-size: 0.78rem; margin-right: 6px; }
.shift-timeline .change { display: block; }
/* 本人の連絡メモ（履歴の先頭に固定）。出来事の行と見分けが付くよう左に線を引く＝日時の代わりに見出しを出すので、
   同じ見た目だと「日時の抜けた記録」に見える。 */
.shift-timeline li.is-contact { border-left: 3px solid var(--alt-primary, #4d7cc7); padding-left: 8px; }

.shift-inline-form { display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-end; }
.shift-inline-form > div { display: flex; flex-direction: column; }
.shift-inline-form label { font-size: 0.78rem; color: var(--alt-text-sub); }
.shift-actual-form { align-items: center; gap: 4px; margin: 2px 0; }
/* 従業員の詳細の IC カードの登録のしかた（手動・打刻端末・登録アプリ）を 1 つずつ枠で囲む（2026-10-04）。 */
.shift-card-method { margin-top: 12px; padding: 10px 12px; border: 1px solid var(--alt-border); border-radius: var(--alt-radius-sm); }
.shift-card-method-title { margin-bottom: 6px; font-size: 0.85rem; font-weight: 700; color: var(--alt-heading); }
.shift-card-method > :last-child { margin-bottom: 0; }
.shift-overtime { color: var(--alt-danger); font-weight: 600; }

/* ==== 時間軸（日 × 24 時間の帯）。位置は ShiftRoster.razor の定数（HourWidth）で決め、CSS は寸法を持たない。 ==== */
/* 枠（.shift-hours-wrap）はシフト表の .shift-roster-wrap と 1 つの規則で持つ（上のシフト表の節）。 */
.shift-hours-canvas { position: relative; min-width: 100%; }
.shift-hours-row { display: flex; height: 40px; border-bottom: 1px solid var(--alt-bg-muted); }
.shift-hours-row.shift-hours-head { position: sticky; top: 0; z-index: 5; height: 34px; background: var(--alt-bg-subtle); border-bottom: 1px solid var(--alt-border); }
.shift-hours-name {
  position: sticky; left: 0; z-index: 4; width: 160px; min-width: 160px; max-width: 160px;
  display: flex; flex-direction: column; justify-content: center; padding: 0 8px; font-size: 0.85rem;
  background: var(--alt-surface); border-right: 1px solid var(--alt-border); overflow: hidden; white-space: nowrap;
}
.shift-hours-name .meta { font-size: 0.72rem; }
.shift-hours-head .shift-hours-name { background: var(--alt-bg-subtle); }
.shift-hours-tl { position: relative; flex: none; width: var(--shift-hours-width); }
/* 日の区切り（「＋」のホバーの受け皿）。帯より先に描くので、帯の上ではホバーにならない。 */
.shift-hours-slot { position: absolute; top: 0; bottom: 0; }
.shift-hours-day {
  position: absolute; top: 0; height: 18px; line-height: 18px; padding-left: 4px; font-size: 0.78rem; font-weight: 600;
  border-left: 2px solid var(--alt-border-strong); box-sizing: border-box; overflow: hidden; white-space: nowrap;
}
.shift-hours-day.holiday { color: var(--alt-danger); }
.shift-hours-day.today { background: rgba(77, 124, 199, 0.15); }
.shift-hours-tick { position: absolute; top: 18px; height: 16px; font-size: 0.65rem; color: var(--alt-text-muted); border-left: 1px dashed var(--alt-bg-muted); padding-left: 2px; }
.shift-hours-off { position: absolute; top: 0; bottom: 0; background: var(--alt-bg-muted); opacity: 0.6; pointer-events: none; }
.shift-hours-bar {
  position: absolute; box-sizing: border-box; border-radius: 3px; font-size: 0.7rem; line-height: 16px; padding: 0 4px;
  overflow: hidden; white-space: nowrap; cursor: pointer;
}
.shift-hours-bar.planned { top: 4px; height: 16px; }
/* カレンダーの帯（.shift-cal-block）も同じ見た目＝状態の見た目を 2 系統に分けない。 */
.shift-hours-bar.planned.shift-cell-planned, .shift-cal-block.shift-cell-planned { opacity: 0.7; border: 1px dashed rgba(0, 0, 0, 0.4); }
.shift-hours-bar.planned.shift-cell-pendingconfirmation, .shift-cal-block.shift-cell-pendingconfirmation { border: 1px dashed rgba(0, 0, 0, 0.5); }
.shift-hours-bar.planned.shift-cell-vacant { outline: 2px solid var(--alt-danger); }
.shift-cal-block.shift-cell-vacant { outline: 2px solid var(--alt-danger); outline-offset: -2px; }
/* 補充済み（全休を伝えて代替が付いた本人の行。カレンダーの「自分」だけに並ぶ）＝勤務しない行なので薄くする。
   月のマスのタグは上の .shift-cell-covered .shift-badge が打ち消し線を引く。 */
.shift-cal-block.shift-cell-covered { opacity: 0.55; }
.shift-hours-bar.actual { top: 24px; height: 10px; background: rgba(80, 120, 160, 0.55); }
.shift-hours-bar.overtime { top: 24px; height: 10px; background: var(--alt-danger); pointer-events: none; }

/* 代替の仮登録（本人の承認待ち）＝点線の枠と「仮」の見た目。 */
.shift-cell-tentative .shift-badge { outline: 2px dotted var(--alt-warning-border, #d9a441); outline-offset: 1px; }
.shift-hours-bar.planned.shift-cell-tentative, .shift-cal-block.shift-cell-tentative { outline: 2px dotted var(--alt-warning-border, #d9a441); opacity: 0.85; }
.shift-tentative-actions { display: inline-flex; gap: 6px; margin-left: 6px; }
/* 大きめ（承認する・辞退する）＝スマホで指で押す画面。押し間違えないよう間隔も広げる。
   折り返しを許すのは、狭い幅で 2 つ並ぶと画面からはみ出すため。 */
.shift-tentative-actions.lg { display: inline-flex; flex-wrap: wrap; gap: 12px; margin-left: 0; }
.shift-tentative-actions.lg .dxbl-btn { min-width: 128px; min-height: 44px; font-size: 1rem; font-weight: 600; }

/* 本人の承認待ち・本日のシフト（当日のシフトとシフトサマリー）。1 件を 1 行に、狭い幅では縦に積む。 */
.shift-today-mine-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; padding: 6px 0;
  border-bottom: 1px solid var(--alt-bg-muted);
}
.shift-today-mine-row:last-of-type { border-bottom: none; }

/* 実績を読むだけで出すとき（制限ユーザ）。入力欄と同じ高さに揃えて、行の高さが変わらないようにする。 */
.shift-actual-text { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; min-height: 30px; margin: 2px 0; }

/* ==== 出勤・退勤（ダッシュボードの先頭とシフトサマリーの先頭）。大きく・間隔を広く＝スマホで指で押す。 ==== */
.shift-clock { margin: 4px 0 16px; padding: 12px; border: 1px solid var(--alt-border); border-radius: 8px; background: var(--alt-surface); }
.shift-clock-buttons { display: flex; flex-wrap: wrap; gap: 24px; justify-content: center; }
.shift-clock-btn {
  min-width: 160px; min-height: 64px; padding: 12px 28px; font-size: 1.25rem; font-weight: 700; border-radius: 12px;
  border: 2px solid transparent; cursor: pointer; color: #fff;
}
.shift-clock-btn.in { background: #2f8f5b; }
.shift-clock-btn.out { background: #c9573d; }
.shift-clock-btn:disabled { opacity: 0.6; cursor: default; }
.shift-clock-btn:hover:not(:disabled) { filter: brightness(1.08); }
.shift-clock-state { display: flex; flex-wrap: wrap; gap: 16px; justify-content: center; margin-top: 10px; font-size: 0.95rem; }
.shift-clock-warn {
  margin-top: 8px; padding: 8px 12px; border-radius: 6px; font-weight: 600;
  background: var(--alt-warning-bg, rgba(230, 170, 60, 0.18)); border: 1px solid var(--alt-warning-border, #d9a441);
}

/* ==== シフト表の右クリックのメニュー（セット・取り消し・詳細）。押した位置に固定で出し、外を押すと閉じる。 ==== */
.shift-context-backdrop { position: fixed; inset: 0; z-index: 50; }
/* 押した位置に出すが、画面の右・下からはみ出す分だけ戻す（2026-09-11。下のほうの行で右クリックすると
   メニューが画面の外に出て見えなかった）。

   **大きさはメニュー自身が名乗る**＝translate の 100% は自分の境界ボックスに解決されるので、
   高さも幅も測らずに済む。**画面側で見積もって渡さない**＝ここの詰め（padding・行の高さ）と
   C# の計算式という同じ決めごとが 2 か所になり、片方だけ直る。
   **JS で style を書き換えるのも不可**＝次の描き直しで画面が持っている位置に戻り、メニューが跳ねる。 */
.shift-context {
  position: fixed; z-index: 51; min-width: 240px; max-height: 70vh; overflow: auto; padding: 6px;
  left: var(--shift-menu-x); top: var(--shift-menu-y);
  transform: translate(min(0px, calc(100vw - 8px - var(--shift-menu-x) - 100%)),
                       min(0px, calc(100vh - 8px - var(--shift-menu-y) - 100%)));
  background: var(--alt-surface); border: 1px solid var(--alt-border); border-radius: 8px; box-shadow: 0 6px 24px rgba(0, 0, 0, 0.18);
}
.shift-context-title { font-weight: 600; padding: 4px 8px 6px; border-bottom: 1px solid var(--alt-bg-muted); margin-bottom: 4px; }
.shift-context-label { font-size: 0.72rem; color: var(--alt-text-sub); padding: 6px 8px 2px; }
.shift-context-item {
  display: flex; align-items: center; gap: 6px; width: 100%; text-align: left; padding: 6px 8px; border: 0; border-radius: 6px;
  background: none; color: inherit; font: inherit; cursor: pointer;
}
.shift-context-item:hover:not(:disabled) { background: var(--alt-bg-subtle); }
.shift-context-item.danger { color: var(--alt-danger); }
.shift-context-item:disabled { opacity: 0.5; cursor: default; }
.shift-context-sep { border-top: 1px solid var(--alt-bg-muted); margin: 4px 0; }

/* ==== 勤怠管理表 ==== */
.shift-sheet-head { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 8px; align-items: baseline; }
.shift-sheet-status { background: var(--alt-bg-subtle); }
/* 表は器（.shift-sheet-scroll）に入れる＝セルは折り返さないので、列の合計が本文より広いと
   器の無い表はページごと横へ広げる（375px で 710px。2026-09-17 実測）。自分のシフト（.shift-my-wrap）と同じ作法。 */
.shift-sheet-scroll { overflow-x: auto; overscroll-behavior-x: none; }
.shift-sheet { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.shift-sheet th, .shift-sheet td { padding: 3px 6px; border-bottom: 1px solid var(--alt-bg-muted); text-align: left; white-space: nowrap; }
/* **メモだけは折り返す**＝長さの決まらない文なので、折り返さないと 30 字のメモ 1 件で 1280px の画面でも
   表が器を突き抜ける（2026-09-17 実測）。折り返しも最小幅も中身の行（div）に置く＝空の日の列まで広げない
   （td に置くとメモの無い月も 768px で横に転がる）。 */
.shift-sheet-note > div { white-space: normal; min-width: 10em; }
.shift-sheet th { color: var(--alt-text-sub); font-weight: 600; font-size: 0.78rem; }
.shift-sheet tr.holiday td:first-child { color: var(--alt-danger); }
.shift-sheet tr.empty td { color: var(--alt-text-muted); }
.shift-sheet td.overtime { color: var(--alt-danger); font-weight: 600; }
.shift-sheet tfoot td { border-top: 2px solid var(--alt-border-strong); }

/* ==== マスタのひな型（Shared/ShiftTemplatePicker） ==== */
.shift-template-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.shift-template-list li { display: flex; align-items: center; gap: 8px; padding: 4px 6px; border-radius: 6px; }
.shift-template-list li:hover { background: var(--alt-bg-subtle); }
/* 登録済みは薄く出す（消さない＝何が同梱されているかは見えていたほうがよい）。 */
.shift-template-list li.is-taken { opacity: 0.55; }

/* ==== シフト-プラン（シフト表の下書き。TEST1-59） ==== */
.shift-plan-bar { padding: 6px 8px; border-radius: 8px; background: var(--alt-bg-subtle); }
/* 体裁は勤怠管理表の状態バッジ（.shift-sheet-status）と同じ。地の色だけ違う。 */
.shift-sheet-status, .shift-plan-state { font-weight: 600; padding: 2px 10px; border-radius: 6px; }
.shift-plan-state { background: var(--alt-warning-bg, rgba(230, 170, 60, 0.18)); }
.shift-sheet-status.approved, .shift-plan-state.is-confirmed { background: var(--alt-success-bg, rgba(80, 160, 90, 0.2)); }
/* 仮確定中は黄色（2026-09-16・洋二さんの指示）＝下書きの淡い地と見分ける。本人の回答を待っている表で、そのまま確定と読まれないように。 */
.shift-plan-state.is-pending { background: var(--shift-pending-bg); color: var(--shift-pending-text); }
/* プランの状態は「シフト-プラン」の見出しの右隣（2026-09-15）。見出しの行に収まる大きさにし、状態と日時のあいだを空ける。 */
.shift-plan-label-line { display: flex; align-items: center; gap: 8px; }
.shift-plan-label-line > label { margin-bottom: 0; }
.shift-plan-label-line .shift-plan-state { font-size: 0.75rem; padding: 0 8px; }
.shift-plan-label-line .shift-plan-state .meta { margin-left: 6px; }
/* 表の左上の「確定表／下書き表」のカプセル。色は帯の状態と同じクラスから借り、形だけ丸くする（見出しの行に収まる大きさ）。 */
.shift-table-kind { display: inline-block; border-radius: 999px; font-size: 0.78rem; white-space: nowrap; }
/* プランを開いているときの正式なシフト表の行＝文脈として見せるが触らせない（薄く・破線で囲う）。 */
.shift-cell-foreign { opacity: 0.45; }
.shift-cell-foreign .shift-badge { border: 1px dashed currentColor; }

/* ==== 打刻端末（/shift/kiosk）。サイドバーの無い専用レイアウトの中身。
       文字は遠くから読む前提で大きく、押す・触る場所は入力欄 1 つだけ。 ==== */
.shift-kiosk-shell { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 16px; }
.shift-kiosk { display: flex; flex-direction: column; align-items: center; gap: 24px; width: min(720px, 100%); text-align: center; }
.shift-kiosk-clock { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.shift-kiosk-clock .time { font-size: clamp(3.5rem, 14vw, 6rem); font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.shift-kiosk-clock .date { font-size: clamp(1rem, 3vw, 1.4rem); color: var(--alt-text-sub); }
.shift-kiosk-form { display: flex; flex-direction: column; align-items: center; gap: 8px; width: 100%; }
.shift-kiosk-form label { font-size: clamp(1.1rem, 3.5vw, 1.6rem); font-weight: 600; }
/* 伏せ字なので中身は読めない。幅を持たせるのは「入っている」ことが見えるようにするため。
   入力欄と結果の枠は**背景を持つので文字色も自分で持つ**＝打刻画面の表示で背景色を変えると面の文字色（is-custom）が受け継がれ、
   明るい枠の上で白い文字になって読めなかった（2026-09-29 に stg で見た）。枠の背景も半透明の予備を置かない（濃い背景が透ける）。 */
.shift-kiosk-input { width: min(420px, 90%); padding: 12px 16px; font-size: 1.4rem; text-align: center; letter-spacing: 0.3em; border: 2px solid var(--alt-border-strong); border-radius: 10px; background: var(--alt-bg-subtle); color: var(--alt-text-body); }
.shift-kiosk-input:focus { outline: 3px solid var(--alt-accent); outline-offset: 2px; }
.shift-kiosk-result { display: flex; flex-direction: column; align-items: center; gap: 6px; width: 100%; padding: 16px; border-radius: 12px; color: var(--alt-text-body); }
.shift-kiosk-result.ok { background: var(--alt-success-bg); }
.shift-kiosk-result.ng { background: var(--alt-warning-bg); }
.shift-kiosk-result .name { font-size: clamp(1.6rem, 6vw, 2.6rem); font-weight: 700; }
.shift-kiosk-result .kind { font-size: clamp(1.2rem, 4vw, 1.8rem); font-weight: 600; }
.shift-kiosk-result .message { font-size: clamp(0.95rem, 2.5vw, 1.15rem); }
.shift-kiosk-device { color: var(--alt-text-muted); font-size: 0.9rem; }
.shift-kiosk-fatal { max-width: 640px; margin: 0 auto; padding: 24px; text-align: center; }

/* 打刻端末の NFC（Android の内蔵リーダー）。許可がまだのときのボタンと、その下の案内。
   **打刻の入力欄とは別の塊にする**＝この画面はフォーカスが入力欄から離れないことを守っており、
   フォーカスを取る部品を同じ枠に入れない（ShiftKiosk.razor の doc が正）。 */
.shift-kiosk-nfc-setup { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.shift-kiosk-nfc { padding: 10px 20px; font-size: 1.05rem; font-weight: 600; border-radius: 8px; border: 2px solid var(--alt-accent); background: var(--alt-bg-subtle); color: var(--alt-accent); cursor: pointer; }
.shift-kiosk-nfc:hover { background: var(--alt-accent-soft); }

/* 打刻画面の表示（2026-09-29。ShiftKioskAppearance）。**面は画面全体を覆い、背景色はここにだけ敷く**＝レイアウトの器（shift-kiosk-shell）は触らない。
   背景色を変えたときだけ is-custom が付き、文字色はサーバーが背景から決めた色（HexColor.ForegroundOn）に揃える。 */
.shift-kiosk-stage { position: fixed; inset: 0; display: flex; align-items: center; justify-content: center; padding: 16px; overflow: auto; }
.shift-kiosk-stage.is-custom { background: var(--shift-kiosk-bg); color: var(--shift-kiosk-fg); }
.shift-kiosk-stage.is-custom .shift-kiosk-clock .date,
.shift-kiosk-stage.is-custom .shift-kiosk-device,
.shift-kiosk-stage.is-custom .meta { color: inherit; opacity: 0.75; }
/* 濃い背景では製品のロゴを白い版へ差し替える（app.css の html[data-theme="dark"] と同じ 3 本）。 */
.shift-kiosk-stage.is-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); }
/* 淡い背景では明るい地用の版へ戻す＝ダークテーマ（html[data-theme="dark"]）が白い版にしたままだと、淡い地に白いロゴが乗って見えなくなる。 */
.shift-kiosk-stage.is-custom:not(.is-dark) { --alt-brand-symbol: var(--alt-brand-symbol-on-light); --alt-brand-wordmark: var(--alt-brand-wordmark-on-light); --alt-brand-custom-filter: none; }
.shift-kiosk-brand { position: absolute; top: 24px; left: 24px; }
.shift-kiosk-brand .app-brand-logo { flex-basis: 40px; width: 40px; height: 40px; }
.shift-kiosk-brand .brand-wordmark { height: 30px; }
.shift-kiosk-brand .brand-product-name { font-size: 1.4rem; line-height: 40px; }
/* 会社のロゴ。左は画面の左側に置き、時計と案内文は中央のまま（重ならないよう中身の幅を詰める）。中央は日付と案内文の間。 */
.shift-kiosk-company-logo { object-fit: contain; }
.shift-kiosk-company-logo.is-left { position: absolute; left: 4vw; top: 50%; transform: translateY(-50%); width: 24vw; max-height: 55vh; }
.shift-kiosk-company-logo.is-center { max-width: min(480px, 70%); max-height: 18vh; }
.shift-kiosk-stage.has-left-logo .shift-kiosk { width: min(560px, 44vw); }
/* 読み取り位置の枠。**ロゴより手前**（画面の中でも後ろに描く）。クリックは下の入力欄へ通す。
   位置は列挙の名前の data-at（KioskReadPosition）、大きさはサーバーの割合の変数（KioskReadSizeRatios＝アプリと同じ値）。 */
.shift-kiosk-reader { position: absolute; width: var(--shift-kiosk-read-w, 30vw); height: var(--shift-kiosk-read-h, 30vh); display: flex; align-items: center; justify-content: center; padding: 8px; text-align: center; border: 4px dashed var(--alt-accent); border-radius: 16px; font-size: 1.1rem; font-weight: 700; color: var(--alt-accent); background: color-mix(in srgb, var(--alt-accent) 8%, transparent); pointer-events: none; }
/* 背景色を変えたときは文字色で描く（アクセントの色は濃い背景に沈む）。 */
.shift-kiosk-stage.is-custom .shift-kiosk-reader { color: inherit; border-color: currentColor; background: color-mix(in srgb, currentColor 10%, transparent); }
/* **時計に重ねない**＝Web は時計の位置を測れないので、時計の幅（半分で約 9rem）と高さを見込んだ上限で抑える。
   左右の列は幅を、上と中央の列は高さを抑え、中央は時計の下から始める（アプリは実際の位置を測って縮める）。
   上限は低い・狭い画面で 0 以下になり枠が消える（上の真ん中は高さ約 400px 以下・左右の列は幅約 380px 以下）ので、案内文が収まる下限（高さ 4rem・幅 6rem＝折り返す）を持たせる。その大きさでは時計に掛かるが、枠が消えるよりよい。 */
.shift-kiosk-reader:is([data-at="TopLeft"], [data-at="Left"], [data-at="BottomLeft"], [data-at="TopRight"], [data-at="Right"], [data-at="BottomRight"]) { max-width: max(calc(50vw - 9rem - 48px), 6rem); }
.shift-kiosk-reader[data-at="TopLeft"] { top: 24px; left: 24px; }
.shift-kiosk-reader[data-at="Top"] { top: 24px; left: 50%; transform: translateX(-50%); max-height: max(calc(50vh - 11rem - 24px), 4rem); }
.shift-kiosk-reader[data-at="TopRight"] { top: 24px; right: 24px; }
.shift-kiosk-reader[data-at="Left"] { top: 50%; left: 24px; transform: translateY(-50%); }
.shift-kiosk-reader[data-at="Center"] { top: calc(50% + 1rem); left: 50%; transform: translateX(-50%); max-height: calc(50vh - 2rem); }
.shift-kiosk-reader[data-at="Right"] { top: 50%; right: 24px; transform: translateY(-50%); }
.shift-kiosk-reader[data-at="BottomLeft"] { bottom: 24px; left: 24px; }
.shift-kiosk-reader[data-at="Bottom"] { bottom: 24px; left: 50%; transform: translateX(-50%); }
.shift-kiosk-reader[data-at="BottomRight"] { bottom: 24px; right: 24px; }
/* 管理画面のロゴの見本。 */
.shift-kiosk-logo-preview { display: flex; align-items: center; gap: 12px; margin-bottom: 6px; }
.shift-kiosk-logo-preview img { max-height: 64px; max-width: 240px; }

/* ---- テーマで変わる色（:root と暗色テーマは 1 か所ずつ＝CSS の重複検査が 2 か所目を止める） ---- */
/* 仮確定中のカプセルの黄色（2026-09-16）＝暗色テーマでは地を沈め、文字を明るくする（黄色の地に白い文字は読めない）。
   カレンダーの土曜の青＝暗色テーマで明るくする（ライトの #2f6fb5 は暗い見出しの地の上で 3:1 を割る。
   暗色の値は見出しの 3 つの地＝--alt-bg-subtle・--alt-surface・今日の列の淡い青のどれの上でも 4.5:1 を超える）。 */
:root { --shift-pending-bg: #ffe066; --shift-pending-text: #4d3b00; --shift-cal-sat: #2f6fb5; }
html[data-theme="dark"] { --shift-pending-bg: #6b5a12; --shift-pending-text: #ffe8a3; --shift-cal-sat: #6b9ae8; }

/* ---- 仮確定（2026-09-16） ---- */
/* 自分のシフト・担当シフトの上の札＝期日までに回答するシフト。見落とされると期日で設定どおりに処理されるので、警告の地で目立たせる。 */
.shift-pending-card { background: var(--alt-warning-bg); border-color: var(--alt-warning-border); }
.shift-pending-all { margin: 8px 0; }
/* 仮確定の窓の条件（期日・対象・期日切れの扱い）。3 行を読み比べるので箇条書きの記号は残す。 */
.shift-pending-terms { margin: 4px 0 8px 1.2em; padding: 0; font-size: 0.85rem; }

/* 打刻端末の組み付け（/shift/kiosk/devices）。QR は画素のまま拡大し、番号は手で打てるよう大きく等幅で出す */
.kiosk-pair { display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center; }
.kiosk-pair-qr { width: 220px; height: 220px; image-rendering: pixelated; }
.kiosk-pair-code { font-size: 2rem; font-weight: 700; letter-spacing: 0.2em; font-family: ui-monospace, monospace; }

/* 打刻の修正申請（TEST1-358）。「自分のシフト」の行に添える申請中・前回の結果と、申請の一覧の理由の列。 */
.shift-correction-state {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
    margin: 2px 0 4px;
}

/* 申請の一覧のセルは折り返さない（「09:02–18:05」や氏名が途中で割れると読み違える）。幅が足りなければ表ごと横に送る
   （器の .shift-my-wrap）。折り返すのは人が書いた文（理由・コメント）だけ＝長さが決まっていない。 */
.shift-corrections td {
    white-space: nowrap;
}

.shift-corrections .shift-correction-reason,
.shift-corrections .shift-correction-note {
    min-width: 12em;
    max-width: 24em;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* ==== シフトのカレンダー（/shift/calendar。2026-10-02） ====
   月 → 週 → 日をダブルクリックで掘り下げる。**ダブルクリックを受けるマス・列は文字を選ばせない**（user-select: none）
   ＝選べると、ダブルクリックのたびに日付や氏名が選択されて青く光る。
   帯の位置と高さは C# が style で渡す（1 時間＝--shift-cal-hour）＝ここは寸法を持たない（シフト表の時間の見方と同じ約束）。
   **編集できない人は器に .readonly**（予定・氏名を押せる見た目にしない。要素ごとに付けない）。 */
.shift-cal-toolbar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 8px 16px; margin-bottom: 8px;
}
.shift-cal-nav { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.shift-cal-title { margin-left: 8px; font-size: 1.1rem; font-weight: 600; white-space: nowrap; }
.shift-cal-switches { display: flex; flex-wrap: wrap; gap: 12px; }
.shift-cal-switches .dialog-buttons { margin-top: 0; }

/* 日付（月のマスの数字・週の列の見出し）。1 回押すと日の見方＝タッチ端末の入口。土台は app.css の .linklike。 */
.shift-cal-date { padding: 0 6px; border-radius: 12px; min-width: 24px; font-weight: 600; color: inherit; }
.shift-cal-date:hover, .shift-cal-date:focus-visible { background: var(--alt-bg-muted); }
.shift-cal-cell.today .shift-cal-date { background: var(--alt-accent); color: var(--alt-on-accent); }
/* 日付の色は見出しにだけ付ける（列そのものに付けると、列の中の氏名まで赤・青になる）。土曜の青はテーマで変わる（--shift-cal-sat。「テーマで変わる色」の節）。 */
.shift-cal-dow.sun, .shift-cal-cell-head.sun, .shift-cal-col-head.sun { color: var(--alt-danger); }
.shift-cal-dow.sat, .shift-cal-cell-head.sat, .shift-cal-col-head.sat { color: var(--shift-cal-sat); }

/* 月の見方。7 列の格子で、マスの高さは中身に合わせて伸びる（区分が多い日だけ高くなる）。 */
.shift-cal-month {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  border-top: 1px solid var(--alt-border); border-left: 1px solid var(--alt-border); background: var(--alt-surface);
}
.shift-cal-dow {
  padding: 4px; text-align: center; font-size: 0.78rem; font-weight: 600; background: var(--alt-bg-subtle);
  border-right: 1px solid var(--alt-border); border-bottom: 1px solid var(--alt-border);
}
.shift-cal-cell {
  min-height: 96px; padding: 2px 4px 4px; overflow: hidden; user-select: none;
  border-right: 1px solid var(--alt-border); border-bottom: 1px solid var(--alt-border);
}
.shift-cal-cell.outside { background: var(--alt-bg-subtle); color: var(--alt-text-muted); }
.shift-cal-cell-head { display: flex; align-items: center; gap: 4px; margin-bottom: 2px; min-width: 0; }
.shift-cal-holiday { font-size: 0.68rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.shift-cal-count { display: flex; align-items: center; gap: 4px; font-size: 0.78rem; line-height: 1.5; white-space: nowrap; }
.shift-cal-count.short > span { color: var(--alt-danger); font-weight: 600; }

/* 押せる予定（月の自分の予定・週のまとまりの氏名）。縦に全幅で並ぶボタンなので .linklike は使わない
   （.linklike + .linklike の左の余白で 2 つ目以降が右へずれる）。 */
.shift-cal-chip, .shift-cal-person {
  width: 100%; border: 0; background: none; font: inherit; font-size: 0.75rem; text-align: left; color: inherit;
  cursor: pointer; white-space: nowrap; overflow: hidden;
}
.shift-cal-chip { display: flex; align-items: center; gap: 4px; margin: 1px 0; padding: 1px 2px; border-radius: 4px; }
.shift-cal-person { display: block; padding: 0 2px; border-radius: 3px; text-overflow: ellipsis; }
.shift-cal-chip:hover, .shift-cal-person:hover { background: var(--alt-bg-muted); }
/* 編集できない人には押せる見た目にしない。ただし本人が取り消せる休み（.cancelable）は押せる＝押すと休暇連絡の取り消しの確認。 */
.readonly .shift-cal-chip:not(.cancelable), .readonly .shift-cal-person, .readonly .shift-cal-block.person:not(.cancelable) { cursor: default; }
.readonly .shift-cal-chip:not(.cancelable):hover, .readonly .shift-cal-person:hover { background: none; }
/* 月のマスの予定は時刻が省略で縮む＝休みのピルは縮めない（種類が読めなくなる）。 */
.shift-cal-chip .shift-leave-pill { flex-shrink: 0; }
.shift-cal-chip-time { color: var(--alt-text-sub); overflow: hidden; text-overflow: ellipsis; }

/* 週・日の見方（縦の時間軸）。1 行目＝角と列の見出し、2 行目＝時刻の目盛りと列。
   列が多い（全員の日の見方＝1 人 1 列）ときは器ごと横に送り、目盛りは左に貼り付ける。 */
.shift-cal-time-wrap { overflow-x: auto; overscroll-behavior-x: none; border: 1px solid var(--alt-border); background: var(--alt-surface); }
.shift-cal-time {
  --shift-cal-col-min: 120px;
  display: grid; grid-template-columns: 52px repeat(var(--shift-cal-cols), minmax(var(--shift-cal-col-min), 1fr));
}
.shift-cal-time.people { --shift-cal-col-min: 104px; }
.shift-cal-time-corner, .shift-cal-axis { position: sticky; left: 0; z-index: 3; background: var(--alt-surface); }
.shift-cal-time-corner { background: var(--alt-bg-subtle); border-bottom: 1px solid var(--alt-border-strong); }
.shift-cal-col-head {
  padding: 4px; text-align: center; font-size: 0.8rem; background: var(--alt-bg-subtle);
  border-left: 1px solid var(--alt-border); border-bottom: 1px solid var(--alt-border-strong);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.shift-cal-col-head.today, .shift-cal-col-head.mine { background-image: linear-gradient(rgba(77, 124, 199, 0.12), rgba(77, 124, 199, 0.12)); }
.shift-cal-col-title { font-weight: 600; }
.shift-cal-col-sub { display: block; font-size: 0.68rem; color: var(--alt-text-sub); overflow: hidden; text-overflow: ellipsis; }
.shift-cal-hour { position: absolute; right: 4px; font-size: 0.7rem; line-height: 1; padding-top: 2px; color: var(--alt-text-sub); }
/* 時刻の線は列の背景のくり返し（列 × 時間の数だけ要素を作らない。全員の日の見方は 1 人 1 列で数十列になる）。 */
.shift-cal-col {
  position: relative; border-left: 1px solid var(--alt-border); user-select: none;
  background-image: repeating-linear-gradient(to bottom,
    transparent 0, transparent calc(var(--shift-cal-hour) - 1px),
    var(--alt-border) calc(var(--shift-cal-hour) - 1px), var(--alt-border) var(--shift-cal-hour));
}
.shift-cal-col.today { background-color: rgba(77, 124, 199, 0.05); }

/* 帯。人 1 人ぶん（.person）は区分の色で塗り、区分ごとのまとまり（.group）は地を白にして氏名を並べる。
   状態の見た目（予定・仮確定・仮登録・欠員・欠勤）はシフト表の帯・タグの規則に並べてある（上の .shift-hours-bar と .shift-cell-*）。 */
.shift-cal-block {
  position: absolute; z-index: 1; box-sizing: border-box; padding: 2px 4px; overflow: hidden;
  border-radius: 4px; font-size: 0.75rem; line-height: 1.3;
}
.shift-cal-block.person { cursor: pointer; box-shadow: 0 0 0 1px var(--alt-surface); }
.shift-cal-block.group { overflow-y: auto; background: var(--alt-surface); border: 1px solid; border-left-width: 4px; }
.shift-cal-block-title {
  display: flex; align-items: center; gap: 4px; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.shift-cal-block-sub { font-size: 0.68rem; opacity: 0.85; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 実績の細い線（帯の左端に重ねる）。 */
.shift-cal-actual {
  position: absolute; z-index: 2; width: 4px; border-radius: 2px;
  background: var(--alt-text-primary, #1f2937); pointer-events: none;
}
.shift-cal-person.shift-cell-vacant, .shift-cal-person.shift-cell-absent { color: var(--alt-danger); text-decoration: line-through; }
.shift-cal-person.shift-cell-planned, .shift-cal-person.shift-cell-tentative,
.shift-cal-person.shift-cell-pendingconfirmation { font-style: italic; color: var(--alt-text-sub); }
.shift-cal-person-time { margin-left: 4px; font-size: 0.65rem; color: var(--alt-text-sub); }
