/*
 * Design token จาก UI mockups สำหรับระบบอนุมัติ/design_handoff_attendance/README.md
 * ค่าสี ระยะ และขนาดตัวอักษรเป็นค่าตั้งใจทั้งหมด ห้ามเปลี่ยนโดยไม่ดู mockup ก่อน
 *
 * โครงหน้า (4 ก.ย. 2569 — ออกแบบใหม่ตามคำสั่งเจ้าของโครงการ "เมนูใช้ง่าย มือถือก็ได้ คอมก็ได้"):
 *   PC ≥ 900px : แถบเมนูซ้ายถาวร (.side) + หัวหน้า (.app-head) + เนื้อหา (.page)
 *   มือถือ      : หัวหน้าแบบย่อ + เนื้อหา + แถบเมนูล่าง (.bottom-nav)
 *   แท็บภายในหน้า (.page-tabs) ทำงานเหมือนกันทั้งสองจอ
 */
:root {
  --primary: #0e6b57;
  --primary-dark: #0a4f41;
  --primary-darker: #093f34;
  --bg-page: #f6f5f1;
  --bg-muted: #f1efe9;
  --surface: #ffffff;
  --border: rgba(0, 0, 0, 0.07);
  /* ขอบของช่องที่ "กดได้" — เส้น 0.07 จางเกินไป ดรอปดาวน์เลยดูเหมือนข้อความธรรมดา (พบ 8 ก.ย. 2569) */
  --border-input: rgba(0, 0, 0, 0.24);
  --text: #1c2a26;
  /* คอนทราสต์ต้องผ่านเกณฑ์อ่านออกกลางแดด (WCAG AA 4.5:1) — ค่าเดิม .5/.4 ได้แค่ 4.1:1 และ 2.9:1 */
  --text-muted: rgba(0, 0, 0, 0.62);
  --text-faint: rgba(0, 0, 0, 0.55);

  --success-bg: #dff0e9;
  --success-bg-soft: #e9f3ef;
  --success-text: #0a4f41;
  /* บันไดสีของ "ความสาย" — ยิ่งแดงยิ่งมีผลจริง ความหมายนี้คงที่ทั้งระบบ ห้ามใช้สื่อความอื่น
     เหลือง = ยังไม่ตัดสิน (รอตรวจ · อนุมาน) · ส้ม = บันทึกไว้แต่ยังไม่นับ (เฝ้าระวังเวรผลัด · ไม่พบสแกนออก)
     แดง = สายที่นับเข้ามาตรการแล้ว (เจ้าของโครงการ 9 ก.ย. 2569 "เปลี่ยนสายเป็นสีแดง") */
  --warn-bg: #fdf3dd;
  --warn-text: #8a5a08;
  --warn2-bg: #fce8d8;
  --warn2-text: #a05412;
  --info-bg: #e3ecf7;
  --info-text: #2b5c96;
  --danger-bg: #fdeaea;
  --danger-text: #a83232;
  --danger-line: #edb5b5;

  /* สีเฉพาะปฏิทิน — ช่องกว้างราว 40px บนมือถือ และ "สี" เป็นช่องทางเดียวที่บอกสถานะ
     สีป้ายพาสเทลของหน้าอื่นจึงใช้ไม่ได้ที่นี่ (เจ้าของโครงการ 9 ก.ย. 2569: "แทบไม่ต่างเลย บอกยากมาก")
     ไล่น้ำหนักตามสิ่งที่ต้องเห็นก่อน: สายทางการ = ทึบที่สุด · ที่ยังไม่สรุป = สด · ไม่มีเรื่องต้องดู = จาง
     เขียว "ตรงเวลา" ตั้งใจให้เบา — เป็นสถานะที่ดี ไม่ต้องแย่งสายตา
     ทุกคู่ผ่าน WCAG AA 4.5:1 · "สายทางการ" เป็นช่องเดียวที่ตัวเลขเป็นสีขาว จึงหาเจอโดยไม่ต้องเทียบสี */
  --cal-plain-bg: var(--bg-muted);
  --cal-ontime-bg: #bfe3d3;
  --cal-ontime-fg: #0a4f41;
  --cal-late-bg: #c93b3b;
  --cal-late-fg: #ffffff;
  --cal-watch-bg: #f9c78a;
  --cal-watch-fg: #7a3d05;
  --cal-pending-bg: #fbe7a2;
  --cal-pending-fg: #6b4708;
  --cal-pending-line: #c08c1c;
  --cal-leave-bg: #b9d3f2;
  --cal-leave-fg: #1d4d84;
  --cal-off-bg: #e5e2d9;
  --accent-dashed: #d9a53f;

  --radius-card: 13px;
  --radius-ctl: 9px;
  --radius-badge: 5px;
  --shadow-card: 0 2px 8px rgba(0, 0, 0, 0.06);
  --shadow-btn: 0 3px 8px rgba(14, 107, 87, 0.3);

  --font-head: 'Anuphan', 'Sarabun', system-ui, sans-serif;
  --font-body: 'Sarabun', system-ui, sans-serif;

  --side-w: 232px;
}

* { box-sizing: border-box; }

/* ให้ hidden ชนะ display ของ class เสมอ — ไม่งั้น .card-exception{display:flex} จะโผล่ทั้งที่ซ่อนไว้ */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg-page);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 12.5px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, .num { font-family: var(--font-head); margin: 0; }

/* ══ โครงหน้าร่วม (app shell) ═══════════════════════════════════════════ */
.app { display: flex; min-height: 100dvh; }

.brand-mark {
  width: 30px; height: 30px; border-radius: 9px; background: var(--primary);
  display: grid; place-items: center; color: #fff; flex: none;
}
.brand-mark svg { width: 62%; height: 62%; }

/* แถบเมนูซ้าย (PC) */
.side {
  width: var(--side-w); flex: none; background: var(--surface); border-right: 1px solid var(--border);
  position: sticky; top: 0; height: 100dvh; display: flex; flex-direction: column; gap: 12px; padding: 18px 14px 16px;
}
.side-brand { display: flex; align-items: center; gap: 10px; padding: 2px 6px 8px; font-family: var(--font-head); font-weight: 700; font-size: 14px; line-height: 1.2; }
.side-brand small { display: block; font-weight: 500; color: var(--text-muted); font-size: 11px; margin-top: 2px; }
.side-user { display: flex; gap: 10px; align-items: center; padding: 10px; border-radius: 12px; background: var(--bg-muted); text-decoration: none; color: inherit; }
.side-user:hover { background: #e8e5dd; }
.side-user .avatar { width: 38px; height: 38px; }
.side-user-text { min-width: 0; }
.side-user-name { display: block; font-family: var(--font-head); font-weight: 700; font-size: 13px; line-height: 1.25; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.side-user-role { display: block; font-size: 11px; color: var(--text-muted); margin-top: 2px; }
.side-nav { display: flex; flex-direction: column; gap: 3px; }
.nav-item {
  display: flex; align-items: center; gap: 11px; width: 100%; padding: 10px 12px; border-radius: 10px;
  text-decoration: none; color: var(--text); font-family: var(--font-head); font-weight: 600; font-size: 13px;
  border: 0; background: none; cursor: pointer; text-align: left;
}
.nav-item:hover { background: var(--bg-muted); }
.nav-item.is-active { background: var(--success-bg-soft); color: var(--primary-dark); }
.nav-ico { width: 18px; height: 18px; flex: none; color: var(--text-muted); display: inline-grid; place-items: center; }
.nav-ico svg { width: 18px; height: 18px; }
.nav-item.is-active .nav-ico { color: var(--primary); }
.side-foot { margin-top: auto; display: flex; flex-direction: column; gap: 6px; }
.side-foot .nav-item { color: var(--text-muted); }
.side-ver { font-size: 10.5px; color: var(--text-faint); padding: 0 6px; }
/* เลขเวอร์ชันกดได้ → ประวัติการปรับปรุง (shell.js showReleaseHistory) — หน้าตาเหมือนข้อความ ไม่ใช่ปุ่มโดด ๆ */
.side-ver-btn { all: unset; cursor: pointer; text-decoration: underline dotted; text-underline-offset: 2px; }
.side-ver-btn:hover, .side-ver-btn:focus-visible { color: var(--text-muted); outline: none; }

/* พื้นที่หลัก + หัวหน้า */
.app-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.app-head {
  position: sticky; top: 0; z-index: 10;
  background: rgba(246, 245, 241, 0.94); backdrop-filter: blur(8px); border-bottom: 1px solid var(--border);
  padding: 14px 28px; display: flex; align-items: center; gap: 14px;
}
.app-head .brand-mini { display: none; }
.app-head-title { flex: 1; min-width: 0; }
.app-head h1 { font-size: 19px; font-weight: 700; line-height: 1.25; }
.app-head-sub { font-size: 12px; color: var(--text-muted); margin-top: 1px; }
.app-head-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.app-head .back-link { margin-bottom: 0; }
.avatar {
  width: 34px; height: 34px; border-radius: 50%; background: var(--success-bg-soft);
  color: var(--primary-dark); display: grid; place-items: center;
  font-family: var(--font-head); font-weight: 700; font-size: 12px; flex: none; text-decoration: none;
}

.page { max-width: 1180px; width: 100%; margin: 0 auto; padding: 20px 28px 60px; }
.bottom-nav { display: none; }

/* แถบสถานะความสดของข้อมูล — ใต้หัวหน้าทุกหน้า (shell.js renderDataStatus)
   บรรทัดเดียว (~30px) กดแล้วคลี่รายละเอียด — เจ้าของโครงการเลือกแบบนี้ 6 ก.ย. 2569 เพราะแบบ 4 บรรทัดกินที่บนมือถือ */
.data-status {
  font-size: 12px; color: var(--text-muted); border-radius: 10px;
  background: var(--success-bg-soft); margin-bottom: 12px;
}
.data-status b { color: var(--primary-dark); font-family: var(--font-head); }
.data-status.is-warn { background: var(--warn-bg); color: var(--warn-text); }
.data-status.is-warn b { color: inherit; }
/* แถวบน = ปุ่มทั้งแถว (มือถือแตะง่าย) · แบบ is-static = ไม่มีอะไรให้คลี่ (กำลังโหลด / ยังไม่มีข้อมูล) */
.ds-row {
  display: flex; align-items: center; gap: 8px; width: 100%; min-height: 30px;
  padding: 5px 10px 5px 12px; background: none; border: 0; border-radius: 10px;
  color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.ds-row.is-static { cursor: default; }
.ds-row:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.ds-text { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds-stale { font-weight: 600; }
.ds-ico { width: 16px; height: 16px; display: inline-grid; place-items: center; color: var(--primary); flex: none; }
.ds-ico svg { width: 16px; height: 16px; }
.data-status.is-warn .ds-ico { color: var(--warn-text); }
.ds-caret { width: 16px; height: 16px; flex: none; display: inline-grid; place-items: center; opacity: 0.7; transition: transform 0.15s; }
.ds-caret svg { width: 16px; height: 16px; }
.data-status.is-open .ds-caret { transform: rotate(180deg); }
/* รายละเอียดที่คลี่ — จัดชิดข้อความของแถวบน (เว้นไอคอน) */
.ds-detail { display: none; flex-direction: column; gap: 3px; padding: 0 12px 9px 36px; line-height: 1.5; }
.data-status.is-open .ds-detail { display: flex; }
.ds-detail [data-help] { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.ds-link { font-family: var(--font-head); font-weight: 600; color: var(--primary); text-decoration: none; white-space: nowrap; }
.ds-row .ds-link { margin-left: auto; }
.ds-detail .ds-link { align-self: flex-start; margin-top: 3px; }
.data-status.is-warn .ds-link { color: var(--warn-text); text-decoration: underline; }

/* แท็บภายในหน้า — segmented control ทำงานเหมือนกันทั้งมือถือและ PC */
.page-tabs {
  display: flex; gap: 4px; background: var(--bg-muted); padding: 4px; border-radius: 12px;
  width: max-content; max-width: 100%; overflow-x: auto; scrollbar-width: none; margin-bottom: 14px;
}
.page-tabs::-webkit-scrollbar { display: none; }
.page-tab {
  border: 0; background: none; font-family: var(--font-head); font-weight: 600; font-size: 12.5px;
  padding: 8px 14px; border-radius: 9px; color: var(--text-muted); cursor: pointer; white-space: nowrap; text-decoration: none;
  display: inline-flex; align-items: center; gap: 6px;
}
.page-tab[aria-selected='true'] { background: var(--surface); color: var(--primary-dark); box-shadow: var(--shadow-card); }
.page-tab:hover:not([aria-selected='true']) { color: var(--text); }

/* มือถือ */
@media (max-width: 899px) {
  .side { display: none; }
  .app-head { padding: 10px 14px; gap: 10px; }
  .app-head .brand-mini { display: grid; width: 32px; height: 32px; }
  .app-head h1 { font-size: 15px; }
  .app-head-sub { font-size: 11px; }
  /* มือถือมีเมนูล่างแล้ว ปุ่มย้อนกลับในหัวหน้าเปลืองที่จนชื่อหน้าตกบรรทัด */
  .app-head .back-link { display: none !important; }
  .mob-hide { display: none !important; }
  .app-head .badge-round { padding: 3px 8px; font-size: 11px; }
  .app-head-actions { gap: 6px; }
  .page { padding: 14px 12px calc(84px + env(safe-area-inset-bottom)); }
  .bottom-nav {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
    background: var(--surface); border-top: 1px solid var(--border);
    padding: 6px 4px calc(6px + env(safe-area-inset-bottom)); justify-content: space-around;
  }
  .bottom-nav a {
    flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px; min-width: 0;
    text-decoration: none; color: var(--text-muted); font-family: var(--font-head); font-weight: 600; font-size: 10.5px;
    padding: 4px 2px; border-radius: 10px;
    /* ผู้ดูแลระบบที่เป็นผู้บริหารด้วยมีเมนูถึง 7 ช่อง — ป้ายยาวต้องตัดท้าย ไม่ใช่ดันแถบเสียรูป */
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .bottom-nav .nav-ico, .bottom-nav .nav-ico svg { width: 22px; height: 22px; }
  /* บัญชีที่เป็นทั้งผู้บริหารและผู้ดูแลระบบมีเมนูถึง 9 ช่อง — ที่ 375px เหลือช่องละ 41px
     ป้าย 6 ตัวอักษร ("ภาพรวม" "ทะเบียน") ที่ 10.5px กว้างเกินจนชนช่องข้าง ๆ จึงย่อลงเมื่อเมนูแน่น
     (นับพี่น้องด้วย :nth-last-child — ไม่ต้องพึ่ง JS และไม่กระทบเมนูสั้นของเจ้าหน้าที่ทั่วไป) */
  .bottom-nav a:first-child:nth-last-child(n+8),
  .bottom-nav a:first-child:nth-last-child(n+8) ~ a { font-size: 9px; gap: 2px; padding: 4px 0; }
  .bottom-nav a:first-child:nth-last-child(n+8) .nav-ico,
  .bottom-nav a:first-child:nth-last-child(n+8) ~ a .nav-ico,
  .bottom-nav a:first-child:nth-last-child(n+8) .nav-ico svg,
  .bottom-nav a:first-child:nth-last-child(n+8) ~ a .nav-ico svg { width: 20px; height: 20px; }
  .bottom-nav a.is-active { color: var(--primary); }
  .bottom-nav a.is-active .nav-ico { color: var(--primary); }
  .card { padding: 13px; }
}

/* ══ โครงหน้าย่อย ════════════════════════════════════════════════════════ */
.split { display: grid; grid-template-columns: 340px 1fr; gap: 16px; align-items: start; }
@media (max-width: 899px) { .split { grid-template-columns: 1fr; } }
/* grid item มี min-width:auto โดยปริยาย — ตารางกว้างจะดันทั้งหน้าให้เกิน viewport บนมือถือ */
.split > *, .two-col > * { min-width: 0; }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: 16px;
}
.card + .card { margin-top: 14px; }
.card-title { font-size: 14.5px; font-weight: 600; font-family: var(--font-head); }
.card-sub { font-size: 11.5px; color: var(--text-muted); margin-top: 2px; }
.stack { display: flex; flex-direction: column; gap: 12px; }
.stack > .card { margin: 0; }

/* ── ปุ่ม ─────────────────────────────────────────────────────────────── */
.btn {
  font-family: var(--font-head); font-size: 12.5px; font-weight: 600;
  border-radius: var(--radius-ctl); border: 1px solid transparent;
  padding: 8px 14px; cursor: pointer; background: var(--bg-muted); color: var(--text);
  transition: background 0.12s, color 0.12s; text-decoration: none; display: inline-block;
}
.btn:hover:not(:disabled) { background: #e8e5dd; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-primary { background: var(--primary); color: #fff; box-shadow: var(--shadow-btn); }
.btn-primary:hover:not(:disabled) { background: var(--primary-dark); }
.btn-sm { padding: 6px 10px; font-size: 11.5px; }

/* ── ป้ายสถานะ ───────────────────────────────────────────────────────── */
.badge {
  display: inline-block; padding: 2.5px 8px; border-radius: var(--radius-badge);
  font-size: 10.5px; font-weight: 700; font-family: var(--font-head); white-space: nowrap;
}
/* ป้ายที่ข้อความยาว (เช่น ชื่อกลุ่มเวลา + ช่วงเวลา) ให้ตัดบรรทัดในกรอบ ไม่ล้นการ์ด */
.badge-wrap { white-space: normal; line-height: 1.35; max-width: 100%; }
.badge-ok { background: var(--success-bg); color: var(--success-text); }
/* "อนุมาน" และ "รอตรวจ" ใช้สีเดียวกันโดยตั้งใจ — สื่อว่ายังไม่ใช่ข้อสรุป */
.badge-warn { background: var(--warn-bg); color: var(--warn-text); }
.badge-warn2 { background: var(--warn2-bg); color: var(--warn2-text); }
.badge-info { background: var(--info-bg); color: var(--info-text); }
.badge-danger { background: var(--danger-bg); color: var(--danger-text); }
/* ป้ายที่กดอ่านคำอธิบายได้ — help.js ผูกให้เองเมื่อ .badge เขียน data-help ไว้ (v1.5.5)
   เส้นประใต้ข้อความเป็นสัญญาณเดียวที่บอกว่ากดได้ ไม่เพิ่มปุ่มเพราะป้ายมีหลายสิบใบต่อหน้า */
.badge-help { cursor: help; text-decoration: underline dotted currentColor; text-underline-offset: 2px; }
.badge-help:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.badge-role {
  background: var(--bg-muted); color: var(--text-muted);
  padding: 2px 8px; border-radius: var(--radius-badge); font-size: 10.5px; font-weight: 600;
}

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  border: 0; cursor: pointer; font-family: var(--font-head); font-weight: 600;
  font-size: 11.5px; padding: 5px 12px; border-radius: 20px;
  background: var(--bg-muted); color: var(--text-muted);
}
.chip[aria-pressed='true'] { outline: 2px solid currentColor; outline-offset: -2px; }
.chip-warn { background: var(--warn-bg); color: var(--warn-text); }
.chip-warn2 { background: var(--warn2-bg); color: var(--warn2-text); }
.chip-info { background: var(--info-bg); color: var(--info-text); }
.chip-danger { background: var(--danger-bg); color: var(--danger-text); }

/* ── dropzone ────────────────────────────────────────────────────────── */
.dropzone {
  border: 2px dashed rgba(14, 107, 87, 0.4);
  border-radius: var(--radius-card);
  background: var(--surface);
  padding: 30px 18px; text-align: center; transition: background 0.15s, border-color 0.15s;
}
.dropzone.is-over { background: var(--success-bg-soft); border-color: var(--primary); }
.dropzone-icon {
  width: 52px; height: 52px; margin: 0 auto 12px; border-radius: 14px;
  background: var(--success-bg-soft); color: var(--primary);
  display: grid; place-items: center;
}
.dropzone h2 { font-size: 15px; font-weight: 700; }
.dropzone p { color: var(--text-muted); font-size: 11.5px; margin: 6px 0 14px; }

/* ── แถวสรุป ─────────────────────────────────────────────────────────── */
.stat { display: flex; justify-content: space-between; align-items: baseline; padding: 5px 0; }
.stat-label { color: var(--text-muted); font-size: 12px; }
.stat-value { font-family: var(--font-head); font-weight: 700; font-size: 15px; }
.stat-value.ok { color: var(--primary); }
.stat-value.warn { color: var(--warn2-text); }
.stat-value.muted { color: var(--text-muted); }

.stackbar { display: flex; height: 8px; border-radius: 4px; overflow: hidden; background: var(--bg-muted); margin-top: 10px; }
.stackbar > span { display: block; height: 100%; }

/* ── ตาราง ───────────────────────────────────────────────────────────── */
.table { width: 100%; border-collapse: collapse; }
.table th {
  text-align: left; font-family: var(--font-head); font-weight: 600; font-size: 11.5px;
  color: var(--text-muted); padding: 10px 12px; border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.table td { padding: 12px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.table tbody tr:hover { background: #faf9f6; }
.table tbody tr:last-child td { border-bottom: 0; }
.table-wrap { overflow-x: auto; }
.cell-name { font-weight: 600; }
.cell-muted { color: var(--text-muted); font-size: 11.5px; }
.row-actions { display: flex; gap: 6px; justify-content: flex-end; flex-wrap: wrap; }

/* รายการสรุปข้อความยาว ๆ (หน้าประกาศ) — หัวข้อหนา ตามด้วยคำอธิบาย อ่านง่ายบนมือถือ */
.plain-list { list-style: none; display: flex; flex-direction: column; gap: 7px; margin-top: 8px; font-size: 12.5px; line-height: 1.65; }
.plain-list li { padding-left: 13px; position: relative; color: var(--text-muted); }
.plain-list li::before { content: ''; position: absolute; left: 0; top: 8px; width: 5px; height: 5px; border-radius: 50%; background: var(--primary); }
.plain-list b { color: var(--text); }

/* ตารางบนมือถือกลายเป็นการ์ดรายแถว — แต่ละช่องมีป้ายชื่อคอลัมน์ (data-label) */
@media (max-width: 899px) {
  .table-cards thead { display: none; }
  .table-cards, .table-cards tbody, .table-cards tr, .table-cards td { display: block; width: 100%; }
  .table-cards tr { border: 1px solid var(--border); border-radius: 12px; margin: 10px 12px; padding: 10px 12px; background: var(--surface); }
  .table-cards tr:hover { background: var(--surface); }
  .table-cards td { border: 0; padding: 5px 0; }
  .table-cards td[data-label]::before { content: attr(data-label); display: block; font-family: var(--font-head); font-size: 10.5px; color: var(--text-muted); font-weight: 600; margin-bottom: 2px; }
  .table-cards td.empty { text-align: center; }
  .table-cards .row-actions { justify-content: flex-start; }
}

/* ── สถานะพิเศษ ──────────────────────────────────────────────────────── */
.empty { text-align: center; padding: 40px 16px; color: var(--text-muted); }
.notice {
  border-radius: var(--radius-ctl); padding: 10px 13px; font-size: 12px; margin-bottom: 12px;
}
.notice-error { background: var(--danger-bg); color: var(--danger-text); }
.notice-ok { background: var(--success-bg); color: var(--success-text); }
.notice-warn { background: var(--warn-bg); color: var(--warn-text); }
.notice-info { background: var(--info-bg); color: var(--info-text); }

.spinner {
  width: 15px; height: 15px; border: 2px solid rgba(255, 255, 255, 0.4);
  border-top-color: #fff; border-radius: 50%; display: inline-block;
  animation: spin 0.7s linear infinite; vertical-align: -2px;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ══ หน้าเจ้าหน้าที่ (/me) ═══════════════════════════════════════════════ */
.me-grid { display: flex; flex-direction: column; gap: 12px; }
.me-grid > .card { margin: 0; }
.area-score > * { min-width: 0; }
/* 900–1279px: สองคอลัมน์ · ประวัติเต็มความกว้างข้างล่าง
   เดิมยัดสามคอลัมน์ตั้งแต่ 900px ทำให้คอลัมน์ประวัติเหลือ ~200px แล้วบรรทัด
   "เข้า 07:43 → ออก 16:02" หักบรรทัดทีละคำ อ่านไม่ออก (พบบนจอ ~1080px 7 ก.ย. 2569) */
@media (min-width: 900px) {
  .me-grid {
    display: grid; gap: 16px; align-items: start;
    grid-template-columns: 340px minmax(0, 1fr);
    grid-template-rows: auto auto auto auto auto auto;
    grid-template-areas:
      "status status"
      "notice notice"
      "score  cal"
      "kpi    cal"
      "exc    cal"
      "hist   hist";
  }
  .me-grid > .data-status { grid-area: status; margin-bottom: 0; }
  .me-grid > #pageNotice { grid-area: notice; }
  .me-grid > .area-score { grid-area: score; }
  .me-grid > .area-kpi { grid-area: kpi; }
  .me-grid > .area-cal { grid-area: cal; }
  .me-grid > .area-hist { grid-area: hist; }
  .me-grid > .area-exc { grid-area: exc; }
  .me-grid > .area-boundary { grid-area: boundary; }
  .me-grid .card { padding: 18px; }
  /* การ์ดตรวจรอยต่อเวรเต็มความกว้างใต้แถบแจ้งผล — มีแถวนี้เฉพาะตอนการ์ดโผล่ (me.js ใส่ .has-boundary)
     ไม่งั้นแถวว่างยังกิน gap 16px ทุกครั้งที่ไม่มีรายการ */
  .me-grid.has-boundary {
    grid-template-rows: auto auto auto auto auto auto auto;
    grid-template-areas:
      "status   status"
      "notice   notice"
      "boundary boundary"
      "score    cal"
      "kpi      cal"
      "exc      cal"
      "hist     hist";
  }
}

/* ≥1280px: กว้างพอให้ประวัติอยู่คอลัมน์ขวาได้จริง (ต้องเหลือให้คอลัมน์นี้ ≥ 300px)
   แถวสุดท้าย (pad) เปล่าในคอลัมน์ซ้าย ไว้ซับความสูงส่วนเกินจากปฏิทิน/ประวัติที่ยาวกว่า
   ไม่งั้น grid จะยืดแถว score/kpi/exc ให้สูงตาม แล้วการ์ดหล่นเกาะหัวแถว เกิดช่องว่างใหญ่ */
@media (min-width: 1280px) {
  .me-grid {
    grid-template-columns: 340px minmax(380px, 460px) minmax(300px, 1fr);
    grid-template-rows: auto auto auto auto auto 1fr;
    grid-template-areas:
      "status status status"
      "notice notice notice"
      "score  cal    hist"
      "kpi    cal    hist"
      "exc    cal    hist"
      "pad    cal    hist";
  }
  /* ต้องประกาศซ้ำในช่วงนี้ — กฎ .has-boundary ของช่วง 900px เฉพาะเจาะจงกว่า .me-grid จะชนะแม้จอกว้าง */
  .me-grid.has-boundary {
    grid-template-rows: auto auto auto auto auto auto 1fr;
    grid-template-areas:
      "status   status   status"
      "notice   notice   notice"
      "boundary boundary boundary"
      "score    cal      hist"
      "kpi      cal      hist"
      "exc      cal      hist"
      "pad      cal      hist";
  }
}

/* การ์ดตรวจรอยต่อเวร (v1.7.13 · me.js renderBoundary) — หนึ่งรายการ = คำถามหนึ่งข้อ + ปุ่มตอบสองปุ่ม */
.card-boundary { border-color: rgba(43, 92, 150, 0.3); }
.boundary-item { border-top: 1px solid var(--border); margin-top: 10px; padding-top: 10px; }
.boundary-item .boundary-when { font-weight: 600; font-size: 13.5px; }
.boundary-item .boundary-ctx { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
.boundary-item .boundary-q { font-size: 13.5px; margin-top: 6px; color: var(--info-text); font-weight: 600; }
.boundary-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.boundary-actions .btn { flex: 1 1 140px; }

/* วงแหวนคะแนน conic-gradient 76px */
.ring {
  width: 76px; height: 76px; border-radius: 50%; flex: none; display: grid; place-items: center;
  background: conic-gradient(var(--primary) calc(var(--pct, 0) * 1%), var(--bg-muted) 0);
}
.ring > span {
  width: 60px; height: 60px; border-radius: 50%; background: var(--surface);
  display: grid; place-items: center; font-family: var(--font-head); font-weight: 700;
  font-size: 26px; color: var(--primary);
}
/*
 * ยังมีวันทำการที่ไม่มีสแกนและยังไม่ชี้แจง — คะแนนยังไม่สมบูรณ์
 * จึงใช้เขียวจางแทนเขียวเข้ม ไม่ใช้ opacity กับทั้งวง (ตัวเลขข้างในจะจางไปด้วยจนอ่านยาก)
 */
.ring.is-provisional { background: conic-gradient(var(--success-bg) calc(var(--pct, 0) * 1%), var(--bg-muted) 0); }
.ring.is-provisional > span { color: var(--text-muted); }

.pair { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.pair > .card { margin: 0; }
.kpi-label { font-size: 12px; color: var(--text-muted); font-weight: 600; }
.kpi-num { font-family: var(--font-head); font-weight: 700; font-size: 28px; line-height: 1.15; margin-top: 2px; }
.kpi-num small { font-size: 14px; font-weight: 600; margin-left: 2px; }
.kpi-note { font-size: 11px; color: var(--text-muted); margin-top: 3px; }
.card-soft { background: var(--success-bg-soft); border-color: transparent; }
.card-soft .kpi-num { color: var(--primary-dark); }

/* ปฏิทินเดือน — สีแต่ละสถานะตรง mockup 1b */
.cal { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; }
.cal-dow { text-align: center; font-size: 10.5px; color: var(--text-muted); padding-bottom: 2px; }
.cal-cell {
  aspect-ratio: 1; border-radius: 8px; display: grid; place-items: center;
  font-family: var(--font-head); font-weight: 600; font-size: 12.5px;
  border: 1.5px solid transparent; background: var(--cal-plain-bg); color: var(--text-faint);
}
.cal-cell.on_time { background: var(--cal-ontime-bg); color: var(--cal-ontime-fg); }
/* สายที่นับเข้ามาตรการแล้ว = แดงทึบ ตัวเลขขาว · สายที่ยังไม่นับ (เวรผลัดก่อนวันเริ่มนับ · ยังไม่ระบุกลุ่มเวลา) = ส้ม
   ห้ามยุบสองอันนี้เป็นสีเดียว — ตอนนี้ความสายของคนเวรผลัดทั้งโรงพยาบาลยังไม่นับจนถึง 1 ต.ค. 2569 */
.cal-cell.late { background: var(--cal-late-bg); color: var(--cal-late-fg); font-weight: 700; }
.cal-cell.late_watch { background: var(--cal-watch-bg); color: var(--cal-watch-fg); }
.cal-cell.pending { background: var(--cal-pending-bg); color: var(--cal-pending-fg); border-style: dashed; border-color: var(--cal-pending-line); }
.cal-cell.leave { background: var(--cal-leave-bg); color: var(--cal-leave-fg); }
.cal-cell.today { background: var(--primary); color: #fff; }
.cal-cell.future { background: transparent; border-color: var(--border); }
/* วันที่ผ่านมาแล้วแต่ยังไม่นำเข้าข้อมูล — ต้องไม่ดูเหมือน "ไม่มา" */
.cal-cell.nodata { background: transparent; border: 1.5px dashed rgba(0, 0, 0, 0.14); color: var(--text-faint); }
/* ข้อมูลมาถึงแล้วแต่ยังไม่ครบทั้งวัน ("ยังไม่ปิดวัน") — จางเหมือน .nodata เพราะยังไม่มีอะไรให้ทำเหมือนกัน
   แยกคลาสไว้เพื่อให้เปลี่ยนทีหลังได้โดยไม่กระทบ "ยังไม่นำเข้าข้อมูล" ซึ่งคนละเรื่องกัน */
.cal-cell.notclosed { background: transparent; border: 1.5px dashed rgba(0, 0, 0, 0.14); color: var(--text-faint); }

/* บรรทัดบอกสถานะที่ไม่ต้องทำอะไร (เช่น "ยังไม่ปิดวัน") — จางกว่า card-sub ปกติ ไม่แย่งสายตากับงานที่ต้องกด */
.is-muted-note { color: var(--text-faint); font-style: italic; }
/* วันทำการที่ไม่มีสแกนเลย และยังไม่มีใครตรวจ — ว่างเปล่าแต่มีเรื่องต้องทำ จึงเป็นกรอบประสีเหลือง ไม่ใช่พื้นทึบ
   ต่างจาก .nodata (ประจาง = ยังไม่นำเข้า) และ .pending (พื้นเหลือง = มีช่วงงานแต่ติดธง) */
.cal-cell.noscan { background: transparent; border: 1.5px dashed var(--cal-pending-line); color: var(--cal-pending-fg); }
/* วันหยุดของคนเวลาตายตัว (เสาร์ อาทิตย์ วันหยุดราชการ) — เงียบ ไม่เตือน ไม่ประ */
.cal-cell.holiday { background: var(--cal-off-bg); border-color: transparent; color: var(--text-faint); }
.cal-cell.blank { background: transparent; }
.cal-cell.has-data { cursor: pointer; }
.cal-cell.has-data:active { transform: scale(0.94); }
.legend { display: flex; flex-wrap: wrap; gap: 10px; font-size: 10.5px; color: var(--text-muted); margin-top: 10px; }
.legend i { display: inline-block; width: 11px; height: 11px; border-radius: 3px; margin-right: 4px; vertical-align: -1px; border: 1.5px solid transparent; }

/* แถว "ชื่อที่จับคู่ไม่ได้" ในหน้านำเข้าไฟล์ — ปุ่มข้อเสนอตกบรรทัดเองเมื่อชื่อยาว */
.unmatched-row { display: flex; gap: 10px; padding: 10px 2px; border-bottom: 1px solid var(--border); }
.unmatched-row:last-child { border-bottom: 0; }
.unmatched-row .row-actions { justify-content: flex-start; }

/* รายการประวัติการสแกนรายวัน */
/* flex + wrap (ไม่ใช่ grid 3 คอลัมน์ตายตัว) — คอลัมน์แคบลงเมื่อไร ป้ายสถานะจะตกลงบรรทัดใหม่
   แทนที่จะบีบข้อความเวลาให้หักทีละคำ (พบบนจอ ~1080px 7 ก.ย. 2569) */
.hist-row {
  display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: center;
  padding: 10px 4px; border-bottom: 1px solid var(--border); transition: background 0.3s;
}
.hist-row > .hist-date { flex: none; width: 44px; }
.hist-row > .hist-body { flex: 1 1 190px; }
/* ทุกอย่างที่เหลือ (ป้ายสถานะ · ปุ่มชี้แจง) ชิดขวาเสมอ แล้วตกบรรทัดใหม่เองเมื่อที่ไม่พอ */
.hist-row > :not(.hist-date):not(.hist-body) { margin-left: auto; flex: none; }
/* "เข้า 07:43" กับ "ออก 16:02" ต้องไม่ถูกหักกลางวลี — หักได้เฉพาะตรงลูกศร */
.hist-times > .nw { white-space: nowrap; }
.hist-row:last-child { border-bottom: 0; }
.hist-row.is-flash { background: var(--warn-bg); }
.hist-date { text-align: center; line-height: 1.1; }
.hist-date b { display: block; font-family: var(--font-head); font-size: 17px; }
.hist-date span { font-size: 10px; color: var(--text-muted); }
.hist-body { min-width: 0; }
.hist-times { font-family: var(--font-head); font-weight: 600; font-size: 13px; }
.hist-meta { font-size: 11px; color: var(--text-muted); margin-top: 2px; }

/* การ์ดชี้แจง exception */
.card-exception { background: #fffbf0; border-color: rgba(217, 165, 63, 0.4); display: flex; gap: 12px; align-items: center; }
/* การ์ดแนะนำของใหม่ช่วงเริ่มใช้ — ขึ้นเฉพาะตอนมีรายการค้างจริง แล้วหายเองเมื่อเคลียร์หมด (ไม่ใช่ประกาศถาวร) */
.card-intro { background: var(--success-bg-soft); border-color: rgba(14, 107, 87, 0.3); margin-bottom: 12px; }
.card-intro .intro-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; flex-wrap: wrap; }
.card-intro ul { margin: 8px 0 0; padding-left: 18px; font-size: 12.5px; line-height: 1.55; }
.card-intro li { margin-bottom: 2px; }
.exc-icon { width: 40px; height: 40px; border-radius: 11px; background: var(--warn-bg); color: var(--warn-text); display: grid; place-items: center; flex: none; }

/* ══ หน้าทีม (/team) ═══════════════════════════════════════════════════ */
.team-grid { display: flex; flex-direction: column; gap: 12px; }
/* ค้นหา/กรองลูกทีม */
.team-filters { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.search-input {
  flex: 1; min-width: 160px; padding: 9px 12px; font: inherit; font-size: 13px;
  border: 1px solid var(--border); border-radius: var(--radius-ctl); background: var(--surface); color: var(--text);
}
.search-input:focus { outline: none; border-color: rgba(14, 107, 87, 0.35); box-shadow: 0 0 0 1.5px rgba(14, 107, 87, 0.35); }
/**
 * ดรอปดาวน์ในหน้า (กลุ่มงาน · งาน · เดือน) — ต้องดูออกทันทีว่ากดเลือกได้
 * (เจ้าของโครงการ 8 ก.ย. 2569: "บางทีมองไม่ออกเลยว่าเลือกได้")
 * วาดลูกศรเองด้วย background-image เพราะลูกศรของระบบบางเครื่อง (iOS/Android) แทบมองไม่เห็น
 * ห้ามใช้ `background:` แบบย่อทับ ไม่งั้นลูกศรหาย
 */
.sel-inline {
  appearance: none; -webkit-appearance: none;
  padding: 9px 32px 9px 11px; min-height: 38px;
  font: inherit; font-size: 12.5px; font-weight: 600;
  border: 1px solid var(--border-input); border-radius: var(--radius-ctl);
  background-color: var(--surface); color: var(--text); max-width: 100%; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230a4f41' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center; background-size: 14px;
}
.sel-inline:hover { border-color: var(--primary); }
.sel-inline:focus-visible { outline: none; border-color: var(--primary); box-shadow: 0 0 0 2px rgba(14, 107, 87, 0.28); }
/** ป้ายหน้าดรอปดาวน์ — บอกว่าแถวนี้คือตัวเลือก ไม่ใช่หัวข้อ */
.sel-label { font-size: 11.5px; font-weight: 600; color: var(--text-muted); align-self: center; }
.chips { display: flex; gap: 6px; flex-wrap: wrap; }
/**
 * "ยังไม่ปิดวัน" เหนือรายการลูกทีม — เป็นคำอธิบายว่าทำไมบางวันยังว่าง ไม่ใช่งานที่ต้องกด
 * ใช้สีข้อมูล (ฟ้า) เท่านั้น · ห้ามใช้เหลือง เพราะทั้งระบบเหลือง = "รอตรวจ/ยังไม่นับ"
 * (v1.6.7 — ของเดิมเป็นตัวเอียงสีจาง เจ้าของโครงการอ่านผ่านตลอด)
 */
.day-open-note {
  display: flex; align-items: center; gap: 8px; padding: 9px 12px; border-radius: 10px;
  background: var(--info-bg); color: var(--info-text);
  font-size: 12.5px; font-weight: 600; line-height: 1.5;
}
.day-open-note .don-ico { flex: none; display: inline-grid; place-items: center; }
.day-open-note .don-ico svg { width: 17px; height: 17px; }
.day-open-note .help-dot { border-color: currentColor; color: inherit; }
.team-col { min-width: 0; display: flex; flex-direction: column; gap: 12px; }
#memberList { display: grid; gap: 10px; }
#memberList > .card { margin: 0; }
#certifySection { display: flex; flex-direction: column; gap: 12px; }
#certifySection > .card { margin: 0; }
.team-aside > .card { margin: 0; }
@media (min-width: 900px) {
  .team-grid { display: grid; grid-template-columns: 1fr 340px; gap: 16px; align-items: start; }
  #memberList { grid-template-columns: repeat(2, 1fr); gap: 12px; }
  #memberList > .card-sub, #memberList > .day-open-note { grid-column: 1 / -1; }
  /* PC: แผนภาพเวลาอยู่คอลัมน์ขวาเสมอ แท็บ "ภาพรวมเวลา" จึงไม่ต้องมี */
  .team-aside { position: sticky; top: 76px; }
  .team-aside[hidden] { display: block !important; }
  .page-tab.pc-hide { display: none; }
}
.badge-round { background: var(--warn2-bg); color: var(--warn2-text); border-radius: 20px; padding: 4px 11px; font-family: var(--font-head); font-weight: 700; font-size: 12px; white-space: nowrap; }
.member { display: flex; gap: 11px; align-items: center; flex-wrap: wrap; }
.member.is-pending { border-color: rgba(217, 165, 63, 0.5); }
.member .scan-wrap { width: 100%; margin-top: -2px; }
.member-body { flex: 1; min-width: 0; }
.member-name { font-family: var(--font-head); font-weight: 700; font-size: 14px; }
.member-status { font-size: 11.5px; color: var(--text-muted); margin-top: 1px; }
.member-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 10px; width: 100%; }
.member-actions .btn { padding: 10px 8px; }
/* ข้อความบอกเหตุเหนือปุ่มตัดสิน (เช่น ครึ่งวันเช้าที่ไม่มีแตะช่วงเช้า) — กินเต็มแถวของกริดสองคอลัมน์ */
.member-actions .member-note { grid-column: 1 / -1; font-size: 13px; line-height: 1.45; color: var(--warn-text); background: var(--warn-bg); border-radius: 8px; padding: 8px 10px; }

/* รอบรับรองรายสัปดาห์ — สถิติ 5 ช่อง · รายการที่ขวางการรับรอง · คำชี้แจง */
.cert-stats { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; margin-top: 12px; }
/* จอ 360px หาร 5 ช่องได้ช่องละ ~57px แต่ป้าย "สายทางการ" ยาวเกิน ล้นทับช่องข้าง ๆ */
@media (max-width: 480px) { .cert-stats { grid-template-columns: repeat(3, 1fr); } }
.cert-stat { background: var(--bg-muted); border-radius: 10px; padding: 8px 4px; text-align: center; min-width: 0; overflow-wrap: anywhere; }
.cert-stat b { display: block; font-family: var(--font-head); font-size: 17px; font-weight: 700; }
.cert-stat span { font-size: 10.5px; color: var(--text-muted); }
.cert-stat.is-warn { background: var(--warn-bg); color: var(--warn-text); }
.cert-stat.is-warn2 { background: var(--warn2-bg); color: var(--warn2-text); }
.cert-stat.is-danger { background: var(--danger-bg); color: var(--danger-text); }
.cert-stat.is-ok { background: var(--success-bg); color: var(--success-text); }
.cert-stat.is-warn span, .cert-stat.is-warn2 span, .cert-stat.is-danger span, .cert-stat.is-ok span { color: inherit; opacity: 0.8; }
.cert-blocker { display: flex; justify-content: space-between; align-items: center; gap: 8px; padding: 8px 0; border-top: 1px solid var(--border); font-size: 13px; }
.cert-done { display: flex; gap: 10px; align-items: flex-start; margin-top: 12px; font-size: 13px; }
.cert-note { font-size: 12.5px; color: var(--text-muted); margin-top: 10px; padding: 8px 10px; background: var(--bg-muted); border-radius: 8px; }
.cert-list { display: flex; flex-direction: column; margin-top: 8px; }
.cert-dept { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; background: none; border: 0; border-top: 1px solid var(--border); padding: 10px 2px; font: inherit; cursor: pointer; color: inherit; }
.cert-dept:hover { background: var(--bg-muted); }
.exc-row { border-top: 1px solid var(--border); padding: 10px 0 4px; margin-top: 8px; }
.exc-reason { font-size: 12.5px; margin-top: 6px; line-height: 1.5; }
.dlg-msg { white-space: pre-line; }

/* สแกนดิบทุกครั้ง — ปุ่มขยายในประวัติและการ์ดลูกทีม */
.scan-toggle { background: none; border: 0; padding: 2px 0; margin-top: 3px; color: var(--primary); font: inherit; font-size: 11.5px; font-weight: 600; cursor: pointer; }
.scan-list { margin-top: 4px; padding: 6px 10px; border-left: 2px solid var(--border); font-size: 12px; color: var(--text-muted); display: flex; flex-direction: column; gap: 3px; }
.scan-list .scan-item.is-used { color: var(--text); }
.scan-list .scan-date { font-weight: 600; color: var(--text); margin-top: 4px; }
.scan-list .scan-date:first-child { margin-top: 0; }
/* เจ้าตัวระบุความหมายของแตะเอง (v1.7.8) — ปุ่มเล็กท้ายบรรทัด · แตะที่ระบุว่าไม่นับขีดฆ่าให้เห็น */
.scan-list .scan-item.is-ignored > b { text-decoration: line-through; opacity: .7; }
.scan-list .scan-declare { font-size: 11px; padding: 1px 8px; line-height: 1.5; vertical-align: middle; margin-left: 4px; }
.scan-list .scan-item { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 4px; }
/* แถวควบคุมของแผง "ดูสแกน" — ปุ่มสัปดาห์/เดือน + ดรอปดาวน์เลือกเดือน (v1.6.10)
   ดรอปดาวน์ย่อส่วนลงให้สูงพอ ๆ กับชิป ไม่งั้นชิปถูกยืดตามความสูง 38px ของ .sel-inline */
.scan-controls { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 6px 0 2px; }
.scan-controls .scan-month { min-height: 28px; padding: 4px 30px 4px 9px; font-size: 12px; background-size: 13px; }
/* สรุปรายวันของแผง "ดูสแกนทั้งเดือน" (v1.6.5) — ทั้งเดือนแบบไล่ทุกการแตะยาว 60–120 บรรทัด
   ย่อเหลือวันละบรรทัด แตะวันไหนจึงคลี่การแตะดิบของวันนั้น */
.scan-day {
  /* wrap: วันที่มีทั้งป้ายเวรดึกและป้ายเตือน ยาวเกินจอมือถือ — ให้ขึ้นบรรทัดใหม่ทั้งชิ้น ไม่ใช่หักกลางคำ */
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 2px 8px; width: 100%; padding: 3px 0;
  background: none; border: 0; color: var(--text); font: inherit; font-size: 12px; text-align: left; cursor: pointer;
}
.scan-day:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 6px; }
.scan-day > b { flex: none; min-width: 56px; font-weight: 600; }
.scan-day .sd-time { font-variant-numeric: tabular-nums; }
.scan-day .sd-note { color: var(--text-muted); font-size: 11px; }
.scan-day .sd-warn { color: var(--warn-text); font-size: 11px; }
.scan-day .sd-caret { margin-left: auto; flex: none; color: var(--text-faint); font-size: 10px; }
.scan-day-detail { display: flex; flex-direction: column; gap: 3px; padding: 2px 0 6px 12px; }

/* heatmap วัน × ช่วงเวลา — สเกลเขียว 5 ระดับ */
.heat { display: grid; grid-template-columns: 26px repeat(6, 1fr); gap: 3px; align-items: center; margin-top: 10px; }
.heat-h { font-size: 10px; color: var(--text-muted); text-align: center; }
.heat-d { font-size: 11px; color: var(--text-muted); }
.heat-c {
  height: 26px; border-radius: 5px; background: #eaf2ee; border: 0; padding: 0; cursor: pointer;
  font-family: var(--font-head); font-size: 10.5px; font-weight: 700; color: #16261f;
}
.heat-c:hover, .heat-c:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.heat-c[data-l='1'] { background: #cde4da; }
.heat-c[data-l='2'] { background: #9ecbb9; }
.heat-c[data-l='2'] { color: #10201a; }
.heat-c[data-l='3'] { background: #5aa48b; color: #fff; }
.heat-c[data-l='4'] { background: #0e6b57; color: #fff; }

/* ══ ตารางเวรจริงจากการสแกน (/team แท็บ "ตารางเวรจริง" · การ์ดกำลังคนใน /director) ═══
   เป็นตารางจริง ๆ ห้ามพับเป็นการ์ดบนมือถือ (คน × วัน ต้องเห็นเป็นกริด) — ให้เลื่อนซ้ายขวาแทน
   คอลัมน์ชื่อตรึงซ้ายไว้ เลื่อนดูวันแล้วยังรู้ว่าแถวไหนเป็นใคร                                    */
.roster-ward { margin-top: 12px; }
.roster-ward-title { font-family: var(--font-head); font-weight: 700; font-size: 12.5px; color: var(--primary-dark); margin: 0 0 4px; }
.roster { border-collapse: separate; border-spacing: 0; width: 100%; font-size: 11px; }
.roster th, .roster td { padding: 5px 6px; border-bottom: 1px solid var(--border); vertical-align: top; white-space: nowrap; }
.roster th { font-family: var(--font-head); font-weight: 600; font-size: 10.5px; color: var(--text-muted); text-align: center; background: var(--surface); }
.roster th:first-child, .roster td:first-child {
  position: sticky; left: 0; z-index: 1; background: var(--surface); text-align: left;
  font-weight: 600; max-width: 150px; overflow: hidden; text-overflow: ellipsis; box-shadow: 1px 0 0 var(--border);
}
.roster th.is-weekend { color: var(--warn-text); }
.roster td { text-align: center; min-width: 64px; }
/* เป็นบล็อก (flex) ไม่ใช่ inline — คนที่ขึ้นสองเวรในวันเดียวต้องเห็นซ้อนกันเป็นสองบรรทัด ไม่ใช่ต่อกันในบรรทัดเดียว */
.roster-cell { display: flex; flex-direction: column; align-items: center; gap: 1px; width: max-content; margin: 0 auto; padding: 2px 5px; border-radius: 6px; background: var(--success-bg-soft); }
.roster-cell + .roster-cell { margin-top: 3px; }
.roster-cell b { font-family: var(--font-head); font-size: 12px; color: var(--primary-dark); }
.roster-cell small { font-size: 9.5px; color: var(--text-muted); }
.roster-cell.is-unknown { background: var(--warn-bg); }
.roster-cell.is-unknown b { color: var(--warn-text); }
.roster-cell.is-open { border: 1px dashed var(--accent-dashed); }
.roster-cell.is-late b { color: var(--danger-text); }
/* สายที่ยังไม่นับ — ตัวเลขยังเป็นส้ม ไม่ใช่แดง (ดูบันไดสีที่ :root) */
.roster-cell.is-late-watch b { color: var(--warn2-text); }
/* ตารางเวรรายงาน: คนเวลาตายตัว — ท (วันทำการ) พื้นเรียบ · OT (สแกนแยกนอกเวลา/วันหยุด) พื้นม่วงอ่อน · ✓ ชี้แจงแล้ว */
.roster-cell.is-work { background: var(--surface); border: 1px solid var(--border); }
.roster-cell.is-ot { background: #eeedfe; }
.roster-cell.is-ot b { color: #3c3489; }
.roster-cell.is-explained b { color: var(--primary-dark); }
.roster tr.roster-block td { text-align: left; font-family: var(--font-head); font-weight: 600; font-size: 10.5px; color: var(--text-muted); background: var(--surface); }
.roster td.roster-total { text-align: left; font-size: 10.5px; color: var(--text-muted); }
.roster-filters .sel-inline { max-width: 260px; }
.roster-cov th, .roster-cov td { text-align: center; white-space: nowrap; }
.roster-cov th:first-child, .roster-cov td:first-child { text-align: left; }
.roster-cov td.is-thin { color: var(--warn-text); font-weight: 700; }
/* วันทำการที่ไม่มีสแกนและยังไม่มีใครตรวจ — เครื่องหมายเบา ๆ ในช่องว่าง ไม่ใช่การตัดสินว่าขาดงาน */
.roster-noscan { display: block; font-size: 9.5px; color: var(--warn-text); opacity: 0.85; }
/* วันที่ยังไม่ปิดวัน — "–" จาง ๆ บอกว่ายังไม่รู้ ไม่ใช่ 0 ชั่วโมง (ดู help.js คีย์ dayNotClosed) */
.roster-pending { display: block; font-size: 12px; color: var(--text-faint); }
.roster-foot { margin: 6px 2px 0; font-size: 11px; }

/* ══ หน้า ผอ. (/director) ═══════════════════════════════════════════════ */
.kpi-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 16px; }
.kpi-grid > .card { margin: 0; }
/* หน้าภาพรวมของ ผอ. มีการ์ด 5 ใบ — ให้อยู่แถวเดียวบนจอกว้าง ไม่ให้เหลือใบเดียวลอยแถวที่สอง */
.kpi-grid.kpi-5 { grid-template-columns: repeat(5, 1fr); }
@media (max-width: 899px) { .kpi-grid, .kpi-grid.kpi-5 { grid-template-columns: repeat(2, 1fr); gap: 10px; } }
.kpi-card .kpi-num { font-size: 30px; }
/* การ์ด KPI กดได้ → แผงรายละเอียดแยกกลุ่มงาน (มุมขวามีลูกศรบอกว่ากดได้) */
.kpi-card[data-kpi] { cursor: pointer; position: relative; transition: box-shadow 0.12s, transform 0.12s; user-select: none; }
.kpi-card[data-kpi]::after { content: '›'; position: absolute; right: 13px; top: 8px; font-size: 18px; color: var(--text-faint); font-family: var(--font-head); }
.kpi-card[data-kpi]:hover { box-shadow: 0 4px 14px rgba(0, 0, 0, 0.09); }
.kpi-card[data-kpi]:active { transform: scale(0.985); }
.kpi-card[aria-pressed='true'] { outline: 2px solid var(--primary); outline-offset: 1px; }
.kpi-card[aria-pressed='true']::after { content: '▾'; color: var(--primary); }
#drill { margin: 0 0 16px; }
.drill-row { display: flex; align-items: center; gap: 12px; padding: 9px 0; border-top: 1px solid var(--border); font-size: 12.5px; }
.drill-row:first-child { border-top: 0; }
.drill-name { flex: 1; min-width: 0; }
.drill-track { height: 6px; background: var(--bg-muted); border-radius: 3px; margin-top: 5px; overflow: hidden; max-width: 320px; }
.drill-fill { height: 100%; background: var(--primary); border-radius: 3px; }
.drill-val { font-family: var(--font-head); font-weight: 700; font-size: 13.5px; min-width: 64px; text-align: right; white-space: nowrap; }
.drill-val.is-warn { color: var(--warn2-text); }
.drill-val.is-danger { color: var(--danger-text); }
.kpi-up { color: var(--primary); font-weight: 600; }
.kpi-down { color: var(--warn2-text); font-weight: 600; }
/* ใบ "รอตรวจ" แยกสีจากใบอื่น — สื่อว่ายังไม่ใช่ข้อสรุป (mockup 1d) */
.kpi-pending { background: #fffbf0; border-color: rgba(217, 165, 63, 0.45); }
.kpi-pending .kpi-num { color: var(--warn-text); }

.two-col { display: grid; grid-template-columns: 1fr 340px; gap: 16px; align-items: start; }
/* แท็บ "เทียบกลุ่มงาน" — กราฟเต็มความกว้าง คอลัมน์ขวาซ่อน */
.two-col.is-focus { grid-template-columns: 1fr; }
.two-col.is-focus .bars { grid-template-columns: minmax(140px, 260px) 1fr 52px; }
@media (max-width: 899px) { .two-col { grid-template-columns: 1fr; } .two-col.is-focus .bars { grid-template-columns: minmax(96px, 150px) 1fr 44px; } }

/* bar chart อัตราตรงเวลารายกลุ่มงาน */
.bars { display: grid; grid-template-columns: minmax(96px, 150px) 1fr 44px; gap: 8px 12px; align-items: center; margin-top: 12px; }
.bar-label { font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bar-label a { color: inherit; text-decoration: none; }
.bar-label a:hover { color: var(--primary); text-decoration: underline; }
.bar-track { height: 18px; background: var(--bg-muted); border-radius: 5px; overflow: hidden; }
.bar-fill { height: 100%; border-radius: 5px; background: var(--primary); }
/* ลาย stripe = อนุมาน (รอตารางเวร) — ห้ามใช้ทึบกับกลุ่มที่ยังไม่มีตัวเลขทางการ */
.bar-fill.inferred { background: repeating-linear-gradient(45deg, #d9a53f 0 4px, #f3dfae 4px 8px); }
.bar-pct { font-family: var(--font-head); font-weight: 700; font-size: 12.5px; text-align: right; color: var(--primary); }
.bar-pct.inferred { color: var(--warn-text); }
.bar-legend { display: flex; gap: 14px; font-size: 11px; color: var(--text-muted); margin-top: 12px; }
.bar-legend i { display: inline-block; width: 22px; height: 10px; border-radius: 3px; margin-right: 5px; vertical-align: -1px; background: var(--primary); }
.bar-legend i.inferred { background: repeating-linear-gradient(45deg, #d9a53f 0 4px, #f3dfae 4px 8px); }

/* sparkline */
.spark { width: 100%; height: 64px; display: block; margin-top: 8px; }
.spark-axis { display: flex; justify-content: space-between; font-size: 10px; color: var(--text-muted); margin-top: 4px; }
.spark-week { background: none; border: 0; padding: 4px 6px; font: inherit; color: inherit; cursor: pointer; border-radius: 6px; }
.spark-week:hover, .spark-week:focus-visible { background: var(--bg-muted); color: var(--text); outline: none; }

/* แจ้งเตือน */
.alert-list { display: flex; flex-direction: column; gap: 10px; margin-top: 10px; }
.alert { display: flex; gap: 10px; align-items: flex-start; font-size: 12px; }
.alert i { width: 8px; height: 8px; border-radius: 50%; margin-top: 6px; flex: none; background: var(--accent-dashed); }
.alert i.high { background: var(--warn2-text); }
.alert .cell-muted { display: block; }

/* ปุ่ม ‹ › เลื่อนช่วงเวลา — เดือน (หัวหน้าจอ) และสัปดาห์ (ในการ์ด) ใช้หน้าตาเดียวกัน */
.month-nav, .week-nav { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-muted); }
.month-nav button, .week-nav button { border: 0; background: none; cursor: pointer; font-size: 16px; color: var(--text-muted); padding: 2px 6px; }
.week-nav { flex: none; }
/* สุดทางแล้ว (ไม่มีข้อมูลถัดไป) — ยังเห็นอยู่แต่บอกว่ากดไม่ได้ ไม่ใช่หายไปเฉย ๆ */
.month-nav button:disabled, .week-nav button:disabled { opacity: .3; cursor: default; }

/* ปุ่มย้อนกลับ — หัวหน้าทุกหน้าที่ไม่ใช่หน้าหลักของบทบาท */
.back-link {
  display: inline-flex; align-items: center; gap: 4px; text-decoration: none;
  font-family: var(--font-head); font-weight: 600; font-size: 12.5px;
  padding: 6px 12px 6px 9px; border-radius: 20px;
  background: var(--bg-muted); color: var(--text-muted); white-space: nowrap;
}
.back-link:hover { background: #e8e5dd; color: var(--text); }

/* กรอบไฮไลต์ชั่วคราวเมื่อแท็บเลื่อนไปยังการ์ด (เช่น "เทียบกลุ่มงาน") */
/* ข้อความลอยเหนือเมนูล่าง — ผลของปุ่มต้องเห็นตรงที่ผู้ใช้อยู่ ไม่ใช่เฉพาะยอดหน้า */
.toast-box {
  position: fixed; left: 12px; right: 12px; z-index: 60; display: flex; flex-direction: column; gap: 8px;
  bottom: calc(84px + env(safe-area-inset-bottom)); pointer-events: none; align-items: center;
}
@media (min-width: 900px) { .toast-box { left: auto; right: 20px; bottom: 20px; align-items: flex-end; } }
.toast {
  max-width: min(520px, 100%); padding: 11px 15px; border-radius: 12px; font-size: 13px; line-height: 1.45;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.16); opacity: 1; transition: opacity 0.35s, transform 0.35s;
  background: var(--text); color: #fff;
}
.toast-ok { background: var(--primary-dark); }
.toast-error { background: #8c2f2f; }
.toast-warn { background: #8a5a08; }
.toast.is-out { opacity: 0; transform: translateY(6px); }
#inferredNote.is-flash { background: var(--warn-bg); color: var(--warn-text); border-radius: 8px; padding: 6px 8px; }

/* ══ กล่องโต้ตอบ (dialog.js) แทน prompt/confirm ═══════════════════════════ */
.dlg {
  border: 0; border-radius: var(--radius-card); box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
  padding: 0; width: min(92vw, 420px); background: var(--surface); color: var(--text);
  font-family: var(--font-body);
}
.dlg::backdrop { background: rgba(28, 42, 38, 0.45); }
.dlg-form { padding: 18px 18px 16px; display: flex; flex-direction: column; gap: 12px; }
.dlg-title { font-size: 15px; font-weight: 700; font-family: var(--font-head); }
.dlg-msg { margin: -4px 0 0; font-size: 12.5px; color: var(--text-muted); line-height: 1.6; }
.dlg-field { display: flex; flex-direction: column; gap: 5px; }
.dlg-check { flex-direction: row; align-items: center; gap: 8px; }
.dlg-label { font-size: 12px; font-weight: 600; }
.dlg-hint { font-size: 11px; color: var(--text-muted); }
/* ช่องกรอก — ใช้ทั้งในกล่องโต้ตอบ (.dlg-input) และในฟอร์มบนหน้า (.form-input) หน้าตาเดียวกันที่เดียว */
.dlg-input, .form-input {
  width: 100%; padding: 10px 12px; font-family: var(--font-body); font-size: 14px;
  border: 1px solid var(--border-input); border-radius: var(--radius-ctl); background: var(--bg-page); color: var(--text);
}
.dlg-input:focus, .form-input:focus { outline: none; border-color: rgba(14, 107, 87, 0.35); box-shadow: 0 0 0 1.5px rgba(14, 107, 87, 0.35); background: var(--surface); }
textarea.form-input { resize: vertical; min-height: 96px; line-height: 1.55; }
/* iOS ซูมหน้าเองเมื่อแตะช่องกรอกที่ตัวอักษรเล็กกว่า 16px แล้วไม่ซูมกลับ · ปุ่ม "ระบุเอง" ต้องกดด้วยนิ้วได้ */
@media (max-width: 899px) {
  .dlg-input, .form-input, .search-input, .sel-inline { font-size: 16px; }
  .scan-list .scan-declare { font-size: 12px; padding: 5px 10px; }
}
/* สัปดาห์ก่อนหน้าที่ยังมีรายการค้าง (หน้าทีม) */
.backlog-weeks { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 8px; }
.dlg-error { background: var(--danger-bg); color: var(--danger-text); padding: 8px 11px; border-radius: var(--radius-ctl); font-size: 12px; }
.dlg-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 4px; }
.dlg-actions .btn { padding: 10px 16px; }
/* ประกาศการปรับปรุง (dialog.js askRelease · release-notes.js) — กล่องกว้างกว่าปกติเล็กน้อย เลื่อนอ่านได้ถ้าหลายรุ่น */
.dlg-form.rn { max-height: 80vh; overflow-y: auto; gap: 8px; }
.rn-ver { font-size: 11px; font-weight: 700; color: var(--text-muted); margin-top: 4px; letter-spacing: 0.2px; }
.rn-head { font-size: 13.5px; font-weight: 700; }
.rn-list { margin: 0; padding-left: 18px; font-size: 12.5px; line-height: 1.6; display: flex; flex-direction: column; gap: 6px; }
.rn-if { margin-top: 2px; }
.rn-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.rn-bar b { flex: 1 1 240px; font-weight: 600; }

/* ══ คำอธิบายศัพท์ (help.js) ══════════════════════════════════════════════
   ทำเป็นปุ่มกดแทน tooltip แบบชี้เมาส์ เพราะผู้ใช้ส่วนใหญ่เปิดจากมือถือ
   ขนาดปุ่มขั้นต่ำ 22px เพื่อให้แตะติดโดยไม่ดันความสูงของหัวตาราง          */
.help-dot {
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; min-width: 15px; margin-left: 5px; padding: 0;
  border: 1px solid var(--border); border-radius: 50%; background: transparent;
  color: var(--text-muted); font-family: var(--font-head); font-size: 10px; font-weight: 700;
  line-height: 1; cursor: pointer; vertical-align: middle; position: relative;
}
/* พื้นที่แตะจริงกว้างกว่าที่เห็น — นิ้วโดนง่ายขึ้นโดยหน้าตาไม่เปลี่ยน */
.help-dot::after { content: ''; position: absolute; inset: -6px; }
.help-dot:hover, .help-dot:focus-visible { border-color: var(--primary); color: var(--primary); background: var(--success-bg); }
.help-dot:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }

.help-link {
  border: 0; background: transparent; padding: 0; margin-left: 8px;
  color: var(--primary); font-family: var(--font-body); font-size: 11.5px; font-weight: 600;
  text-decoration: underline; text-underline-offset: 2px; cursor: pointer; white-space: nowrap;
}
.help-link:hover, .help-link:focus-visible { color: var(--text); }

.help-sheet { display: flex; flex-direction: column; gap: 6px; max-height: 62vh; overflow-y: auto; margin: -4px -2px 0; padding: 0 2px; }
.help-sheet details { border: 1px solid var(--border); border-radius: var(--radius-ctl); background: var(--bg-page); }
.help-sheet summary {
  padding: 9px 11px; font-family: var(--font-head); font-size: 12.5px; font-weight: 600;
  cursor: pointer; list-style: none;
}
.help-sheet summary::-webkit-details-marker { display: none; }
.help-sheet summary::after { content: '+'; float: right; color: var(--text-muted); font-weight: 400; font-size: 15px; line-height: 1; }
.help-sheet details[open] summary::after { content: '2'; }
.help-sheet details[open] summary { border-bottom: 1px solid var(--border); }
.help-sheet p { margin: 0; padding: 9px 11px 11px; font-size: 12px; color: var(--text-muted); line-height: 1.65; }
.btn-danger { background: var(--danger-text); box-shadow: none; color: #fff; }
.btn-danger:hover:not(:disabled) { background: #8a2626; }

/* ปุ่มโหลดเพิ่มท้ายตาราง */
.load-more { display: block; width: 100%; padding: 12px; border: 0; border-top: 1px solid var(--border); background: var(--bg-page); cursor: pointer; font-family: var(--font-head); font-weight: 600; font-size: 12.5px; color: var(--primary); }
.load-more:hover { background: var(--bg-muted); }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ══ แจ้งปัญหา (/issue) ══════════════════════════════════════════════════ */
/* บริบทที่ระบบแนบให้เอง — บอกให้ผู้ใช้รู้ว่าอะไรถูกส่งไปด้วย ไม่ใช่เก็บเงียบ ๆ */
.issue-ctx { margin-top: 14px; font-size: 11.5px; color: var(--text-muted); background: var(--bg-muted); border-radius: 8px; padding: 8px 10px; line-height: 1.6; }
.issue-row { padding: 10px 0; border-top: 1px solid var(--border); }
.issue-row:first-child { border-top: 0; }
.card.issue-row { border-top: 0; padding: 13px 15px; margin-bottom: 10px; }
.issue-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.issue-kind { font-family: var(--font-head); font-weight: 700; font-size: 13.5px; }
.issue-who { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
/* คำพูดของผู้แจ้ง — คงการขึ้นบรรทัดที่เขาพิมพ์มา และตัดคำยาวไม่ให้ดันการ์ด */
.issue-body { margin: 6px 0; font-size: 13.5px; line-height: 1.6; white-space: pre-wrap; overflow-wrap: anywhere; }
.issue-ua { font-size: 10.5px; white-space: pre-wrap; overflow-wrap: anywhere; }
/* คำตอบของผู้พัฒนา — ท่อนที่คนแจ้งรอดู ต้องเด่นกว่าข้อความของตัวเอง */
.issue-reply { margin-top: 8px; padding: 8px 10px; border-radius: 8px; background: var(--success-bg-soft); font-size: 12.5px; line-height: 1.6; white-space: pre-wrap; }
.issue-reply b { font-family: var(--font-head); color: var(--primary-dark); display: block; margin-bottom: 2px; }
/* แนบภาพหน้าจอ — ตัวอย่างภาพต้องเล็กพอที่ฟอร์มไม่ยาวขึ้นจนหาปุ่มส่งไม่เจอบนมือถือ */
.issue-photo-pick { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.issue-photo-pick .btn { cursor: pointer; }
.issue-photo { display: block; max-width: 100%; max-height: 220px; border-radius: 8px; border: 1px solid var(--border); margin: 8px 0 6px; }
.issue-photo-link { display: inline-block; text-decoration: none; }
/* คำเตือนเรื่องชื่อคนอื่นในภาพ — ต้องอ่านเจอก่อนกดเลือกภาพ ไม่ใช่หลังส่ง */
.issue-photo-warn { line-height: 1.55; }
/* ปุ่มตัดสินในการ์ดเรื่องแจ้ง — 3 ปุ่มยาวไม่เท่ากัน ใช้แถวเรียงชิดซ้าย ไม่ใช่ตาราง 2 ช่องแบบการ์ดลูกทีม */
.issue-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
/* ตัวเลขเรื่องใหม่บนเมนู */
.nav-count { margin-left: auto; }
.bottom-nav .nav-count { margin: 0; position: absolute; top: 0; left: 50%; transform: translateX(4px); padding: 1px 5px; font-size: 9.5px; }
.bottom-nav a { position: relative; }

/* ══ แบบฟอร์มในหน้าประกาศ (/policy) ═══════════════════════════════════════ */
/* ชื่อ + คำอธิบายซ้าย ปุ่มขวา · จอแคบปุ่มลงไปบรรทัดล่างเอง ไม่บีบชื่อจนอ่านไม่ออก */
.form-row { display: flex; justify-content: space-between; align-items: center; gap: 10px 14px; flex-wrap: wrap; padding: 10px 0; border-top: 1px solid var(--border); }
.form-row:first-child { border-top: 0; }
.form-row-text { flex: 1 1 260px; min-width: 0; }
.form-row-title { font-family: var(--font-head); font-weight: 700; font-size: 14px; }
.form-row-actions { display: flex; gap: 8px; flex-wrap: wrap; }
