/* ============================================================
   VAM Workflow — design system  ·  Apple "glass" minimal theme
   frosted glass surfaces + hairline borders + soft depth
   type: SF (บนเครื่อง Apple) / Bai Jamjuree (ภาษาไทย)
   ============================================================ */

:root {
  /*
   * บันไดขนาด — ทุกค่าขนาดในไฟล์นี้ต้องหยิบจากสามชุดข้างล่าง ห้ามเขียนตัวเลขลอย
   *
   * ก่อนจัด 2026-08-22 ไฟล์นี้มีขนาดตัวอักษร 34 ค่า มุมโค้ง 15 ค่า และปุ่ม 11 ความสูง
   * ที่ไม่ได้อ้างอิงอะไรเลย ผลคือปุ่มชนิดเดียวกันคนละหน้าสูงไม่เท่ากัน (เช่น
   * "เปิดงานใหม่" 36.4px กับ "เขียนใบลา" 44.9px) เพราะแต่ละหน้าเลือกคลาสกันเอง
   *
   * เพิ่มค่าใหม่เมื่อไหร่ ให้ถามก่อนว่าขั้นที่มีอยู่ใช้แทนไม่ได้จริงหรือ
   */

  /* ความสูงตัวควบคุม — ดูบล็อก "ตัวควบคุมทั้งหมดสูงเท่ากัน" */
  --control-h: 2.875rem;    /* 46px — ปุ่ม ช่องกรอก select ปฏิทิน ทุกตัวในฟอร์มและหัวเพจ */
  --control-h-bar: 2.5rem;  /* 40px — ปุ่มบนแถบบนสุด ซึ่งตั้งใจให้เตี้ยกว่า */
  --control-h-sm: 2rem;     /* 32px — ตัวย่อในตารางและแถบแบ่งหน้า */

  /* ขนาดตัวอักษร */
  --fs-3xl: 2.25rem;        /* 36px */
  --fs-2xl: 1.75rem;        /* 28px */
  --fs-xl: 1.375rem;        /* 22px */
  --fs-lg: 1.125rem;        /* 18px */
  --fs-md: 1rem;            /* 16px */
  --fs-base: 0.875rem;      /* 14px — เนื้อความ ช่องกรอก ปุ่ม */
  --fs-sm: 0.8125rem;       /* 13px */
  --fs-xs: 0.75rem;         /* 12px */
  --fs-2xs: 0.6875rem;      /* 11px */

  /* มุมโค้ง */
  --r-xs: 6px;
  --r-sm: 10px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 20px;
  --r-pill: 999px;

  --bg: #eef1f6;
  --ink: #1d1d1f;
  --ink-soft: #4b4b50;
  --ink-mute: #86868b;

  --accent: #0071e3;
  --accent-hover: #0077ed;
  --accent-press: #0060c8;

  --green: #248a3d;
  --green-bg: rgba(52, 199, 89, 0.16);
  --amber: #9a6400;
  --amber-bg: rgba(255, 159, 10, 0.18);
  --blue: #0068c9;
  --blue-bg: rgba(10, 132, 255, 0.15);
  --red: #d70015;
  --red-bg: rgba(255, 59, 48, 0.14);
  --gray-bg: rgba(60, 60, 67, 0.08);

  /* glass surfaces */
  --glass: rgba(255, 255, 255, 0.6);
  --glass-2: rgba(255, 255, 255, 0.72);
  --glass-line: rgba(255, 255, 255, 0.7);
  --hairline: rgba(0, 0, 0, 0.08);
  --blur: saturate(180%) blur(20px);

  --shadow: 0 6px 24px rgba(20, 23, 28, 0.08);
  --shadow-lg: 0 20px 60px rgba(20, 23, 28, 0.16);
  /* ชื่อเดิมที่กระจายอยู่ใน var() กว่า 30 ที่ — เก็บไว้เป็นนามแฝงของบันไดข้างบน */
  --radius: var(--r-lg);
  --radius-sm: var(--r-md);

  --sans: -apple-system, BlinkMacSystemFont, 'Bai Jamjuree', 'Segoe UI', system-ui, sans-serif;
  --serif: var(--sans);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: smooth; }

/* ซ่อนแถบเลื่อน (scrollbar) ของ browser ทั้งหมด — ใช้แถบความคืบหน้าด้านบนแทน
   (.scroll-progress ของหน้า และ .modal-progress ใน modal — ดู app.js) */
* { scrollbar-width: none; -ms-overflow-style: none; }
::-webkit-scrollbar { width: 0; height: 0; }
::-webkit-scrollbar-thumb, ::-webkit-scrollbar-track, ::-webkit-scrollbar-corner { background: transparent; }

/* ── แถบความคืบหน้าการเลื่อน ─────────────────────────────────── */

/* ของทั้งหน้า — ลอยติดขอบบนสุด เหนือแถบหัวข้อ แต่ต่ำกว่า modal */
.scroll-progress {
  position: fixed;
  inset: 0 0 auto 0;
  height: 3px;
  z-index: 100;
  pointer-events: none;
}
.scroll-progress i {
  display: block;
  height: 100%;
  width: 0;
  border-radius: 0 999px 999px 0;
  background: var(--accent);
}

/* ของ modal — เกาะขอบบนของกล่อง
   sticky ถูกจำกัดไม่ให้ออกนอก content box ของกล่อง จึงยกระยะขอบบนออก
   แล้วให้แถบเป็นเจ้าของพื้นที่นั้นแทน (คืนระยะห่างเดิมด้วย margin-bottom)
   ใช้ :has เพื่อให้กล่องที่ยังไม่มีแถบ (เช่นตอน JS ไม่ทำงาน) คงระยะขอบเดิมไว้ */
.modal-dialog:has(> .modal-progress) { padding-top: 0; }
.modal-progress {
  position: sticky;
  top: 0;
  z-index: 5;
  height: 3px;
  margin: 0 calc(-1 * var(--modal-pad-x)) calc(var(--modal-pad-y) - 3px);
  background: var(--hairline);
}
/* กล่องที่แยกหัว/เนื้อ/ปุ่มแล้ว ตัวเลื่อนคือ .modal-body แถบจึงย้ายไปอยู่ในนั้น
   และไม่ต้องหักระยะขอบบนของกล่อง เพราะหัวเรื่องเป็นเจ้าของพื้นที่นั้นอยู่แล้ว */
.modal-body > .modal-progress { margin: 0 calc(-1 * var(--modal-pad-x)) 0.6rem; }
/* เนื้อหาไม่ล้นกล่อง = ไม่ต้องมีแถบ แต่ต้องคง element ไว้ ไม่งั้นระยะขอบบนที่มันถืออยู่หายไปด้วย */
.modal-progress.is-idle { background: transparent; }
.modal-progress i {
  display: block;
  height: 100%;
  width: 0;
  border-radius: 0 999px 999px 0;
  background: var(--accent);
}

body {
  font-family: var(--sans);
  font-weight: 400;
  color: var(--ink);
  background: var(--bg);
  line-height: 1.6;
  font-size: var(--fs-base);
  letter-spacing: -0.01em;
  -webkit-font-smoothing: antialiased;
}
/* แสงสีจาง ๆ ให้ผิวกระจกมีอะไรให้เบลอ */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(38rem 38rem at 10% 6%, rgba(10, 132, 255, 0.10), transparent 60%),
    radial-gradient(36rem 36rem at 90% 10%, rgba(191, 90, 242, 0.10), transparent 60%),
    radial-gradient(40rem 40rem at 74% 94%, rgba(48, 209, 88, 0.08), transparent 62%),
    radial-gradient(34rem 34rem at 18% 96%, rgba(255, 159, 10, 0.07), transparent 60%);
}

h1, h2, h3, h4 {
  font-family: var(--serif);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.02em;
}

p { max-width: 66ch; }
a { color: inherit; }
img, svg { max-width: 100%; display: block; }
code { font-family: ui-monospace, 'SF Mono', Menlo, monospace; font-size: 0.85em; }
::selection { background: rgba(0, 113, 227, 0.18); }

/* ── utilities ─────────────────────────────────────────────── */

.container { max-width: 1160px; margin-inline: auto; padding-inline: clamp(1.25rem, 5vw, 3rem); }

.eyebrow {
  display: inline-block;
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.9rem;
}

/*
 * ปุ่ม — สูงเท่าช่องกรอกเสมอ และ <a> กับ <button> ต้องได้ความสูงเท่ากัน
 *
 * `line-height: 1` ไม่ใช่ของประดับ: ถ้าไม่ตั้ง <a class="btn"> จะรับ line-height
 * 1.6 จาก body ส่วน <button> ใช้ `normal` ของเบราว์เซอร์ ผลคือคลาสเดียวกันเป๊ะ
 * แต่สูงต่างกัน 5.1px ทุกคู่ (วัดจริง 2026-08-22: 44.9 vs 39.8) ซึ่งมองเห็นทันที
 * เพราะหลายหน้าวางลิงก์กับปุ่มไว้ติดกันในแถวเดียว
 *
 * min-height ผูกกับ --control-h ตัวเดียวกับช่องกรอก ปุ่มที่ยืนข้างช่องค้นหาหรือ
 * ตัวกรองจึงมีขอบล่างตรงกัน — เดิมเตี้ยกว่า 6px ทุกแถบเครื่องมือ
 */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  font-family: var(--sans);
  font-size: var(--fs-base);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.01em;
  min-height: var(--control-h);
  padding: 0.62rem 1.3rem;
  border-radius: var(--r-md);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  position: relative;
  transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease, transform 0.12s ease, box-shadow 0.2s ease;
}
.btn:active { transform: scale(0.98); }
.btn:focus-visible, a:focus-visible, button:focus-visible,
input:focus-visible, textarea:focus-visible, select:focus-visible, summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}
.btn-primary { background: var(--accent); color: #fff; }
.btn-primary:hover { background: var(--accent-hover); }
.btn-ghost { border-color: var(--hairline); color: var(--ink); background: rgba(255, 255, 255, 0.55); }
.btn-ghost:hover { border-color: rgba(0, 0, 0, 0.18); }
.btn-soft { background: rgba(255, 255, 255, 0.72); border-color: var(--hairline); color: var(--ink); }
.btn-soft:hover { background: #fff; }
.btn-danger { background: var(--red-bg); color: var(--red); }
.btn-danger:hover { background: var(--red); color: #fff; }
.btn-sm {
  min-height: var(--control-h-sm);
  padding: 0.42rem 0.9rem;
  font-size: var(--fs-sm);
  border-radius: var(--r-sm);
}
/* ปุ่มไอคอนเป็นจัตุรัสที่ด้านเท่าความสูงของปุ่มข้าง ๆ มัน — เดิม 34/30 ซึ่งไม่ตรงกับ
   ปุ่มตัวไหนเลย และเหลื่อมกับ .btn-sm อยู่ 1.4px ในทุกแถวของทุกตาราง */
.btn-icon {
  padding: 0;
  width: var(--control-h);
  height: var(--control-h);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.btn-icon.btn-sm { width: var(--control-h-sm); height: var(--control-h-sm); }
.btn-block { width: 100%; }

.btn.is-loading { color: transparent !important; pointer-events: none; }
.btn.is-loading::after {
  content: '';
  position: absolute;
  width: 1em; height: 1em;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  color: #fff;
  animation: spin 0.7s linear infinite;
}
.btn-ghost.is-loading::after, .btn-soft.is-loading::after, .btn-danger.is-loading::after { color: var(--ink); }

.link-btn { all: unset; cursor: pointer; color: var(--accent); text-decoration: underline; }

/* ── badges ────────────────────────────────────────────────── */

.badge {
  /* inline-flex ไม่ใช่ inline-block: ป้ายถูกยืดสูงได้เมื่ออยู่ในแถว flex
     (เช่นหัวเพจ) ตัวอักษรจึงต้องจัดกลางเองทั้งสองแกน ไม่ใช่พึ่ง padding */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* ไม่ตั้งจะรับ 1.6 จาก body มาเป็นช่องไฟส่วนเกิน — บทเรียนเดียวกับ .btn */
  line-height: 1;
  font-size: var(--fs-xs);
  font-weight: 500;
  padding: 0.2rem 0.66rem;
  border-radius: var(--r-pill);
  white-space: nowrap;
}
.badge-active, .badge-done, .badge-paid { background: var(--green-bg); color: var(--green); }
.badge-pending, .badge-draft { background: var(--amber-bg); color: var(--amber); }
.badge-shipped { background: var(--blue-bg); color: var(--blue); }
/* รายการเยี่ยมที่ไม่มีใบเซล — สีเดียวกับหมุด .activity-pin-dot.is-visit
   ใช้ชื่อของตัวเองแทนการยืม .badge-shipped ที่บังเอิญเป็นสีฟ้า เพราะคนอ่านโค้ด
   ควรเห็นว่าสีนี้ถูกเลือกมาให้ตรงกับหมุด ไม่ใช่ยืมชื่อของเรื่องอื่นมาใช้ */
.badge-visit { background: var(--blue-bg); color: var(--blue); }
/* สถานะเชิงลบ (ยกเลิก / สินค้าหมด / หยุด / ไม่พร้อม) → แดง */
.badge-out, .badge-cancelled, .badge-paused, .badge-inactive, .badge-failed, .badge-rejected { background: var(--red-bg); color: var(--red); }
/* สถานะกลาง ๆ ที่ยังคงเป็นสีเทา */
.badge-neutral { background: var(--gray-bg); color: var(--ink-mute); }
/* งานลับ — ใช้โทนอำพันเหมือนสถานะที่ต้องสะดุดตา แต่ไม่ใช่ความผิดพลาด (ไม่ใช่แดง)
   · ตัวแปรคู่นี้ถูกนิยามใหม่ในธีมมืดอยู่แล้ว ป้ายจึงอ่านออกทั้งสองธีม */
.badge-private { background: var(--amber-bg); color: var(--amber); gap: 0.25rem; }
/* .badge เป็น inline-flex — ไอคอนจะถูกยืดเต็มความสูงถ้าไม่ตรึงขนาดไว้ */
.badge-private .icon-svg { flex: none; }
/* [hidden] แพ้ display ที่มาจาก class (UA rule specificity ต่ำกว่า) — .badge เป็น
   inline-flex จึงต้องเขียนคู่ไว้เสมอ ไม่งั้นซ่อนด้วย hidden ไม่ติด */
.badge-private[hidden] { display: none; }

/* รายชื่อผู้มองเห็นงานลับ — ชื่อซ้ายและปุ่มถอนขวา อ่านเป็นแถวเดียวได้บนมือถือ */
.viewer-list { list-style: none; margin: 0.6rem 0 0; padding: 0; }
.viewer-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.3rem 0;
  border-bottom: 1px solid var(--hairline);
}
.viewer-list li:last-child { border-bottom: 0; }
.viewer-list form { margin: 0; }

/* ── spinner ───────────────────────────────────────────────── */

.spinner {
  display: inline-block;
  width: 2rem; height: 2rem;
  border-radius: 50%;
  border: 2.5px solid rgba(0, 113, 227, 0.2);
  border-top-color: var(--accent);
  animation: spin 0.8s linear infinite;
}
.spinner-box { display: grid; place-items: center; gap: 0.8rem; padding: 2.2rem 1rem; color: var(--ink-mute); }
.spinner-text { font-size: var(--fs-sm); }
@keyframes spin { to { transform: rotate(360deg); } }

/* ── loader overlay (opt-in) ───────────────────────────────── */

.loader-overlay {
  position: fixed;
  inset: 0;
  z-index: 190;
  display: grid;
  place-items: center;
  background: rgba(238, 241, 246, 0.6);
  backdrop-filter: blur(6px);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.25s ease, visibility 0.25s ease;
}
.loader-overlay.is-active { opacity: 1; visibility: visible; }

/* ============================================================
   Toast
   ============================================================ */

.toast-stack {
  position: fixed;
  top: 1.1rem;
  right: 1.1rem;
  z-index: 150;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  width: min(92vw, 360px);
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  padding: 0.8rem 0.95rem;
  border-radius: var(--r-md);
  background: var(--glass-2);
  backdrop-filter: var(--blur);
  border: 1px solid var(--glass-line);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transform: translateX(120%) scale(0.96);
  transition: opacity 0.42s cubic-bezier(0.22, 1, 0.36, 1),
              transform 0.42s cubic-bezier(0.22, 1, 0.36, 1);
}
.toast.is-shown { opacity: 1; transform: translateX(0) scale(1); }
.toast.is-leaving { opacity: 0; transform: translateX(120%) scale(0.96); }
.toast-icon {
  flex-shrink: 0;
  width: 1.35rem; height: 1.35rem;
  border-radius: 50%;
  display: grid; place-items: center;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: #fff;
  background: var(--green);
}
.toast-error .toast-icon { background: var(--red); }
.toast-info .toast-icon { background: var(--accent); }
/* warning — ใช้กับเรื่องที่ไม่ถึงกับล้มเหลว เช่น รูปบางใบอัปไม่ผ่าน */
.toast-warning .toast-icon { background: var(--amber); }
.toast-msg { flex: 1; font-size: var(--fs-base); line-height: 1.5; color: var(--ink); max-width: none; }
.toast-close {
  all: unset;
  cursor: pointer;
  font-size: var(--fs-lg);
  line-height: 1;
  color: var(--ink-mute);
  padding: 0 0.15rem;
  transition: color 0.2s ease;
}
.toast-close:hover { color: var(--ink); }

/* ============================================================
   Modal
   ============================================================ */

.modal {
  position: fixed;
  inset: 0;
  z-index: 160;
  display: grid;
  place-items: center;
  padding: 1.4rem;
}
.modal[hidden] { display: none; }
.modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(20, 23, 28, 0.28);
  backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity 0.3s ease;
}
.modal-dialog {
  /* ระยะขอบในเก็บเป็นตัวแปร เพราะ .modal-progress ต้องหักลบเพื่อยื่นไปชิดขอบกล่อง */
  --modal-pad-y: 1.7rem;
  --modal-pad-x: clamp(1.3rem, 4vw, 1.9rem);
  position: relative;
  width: min(100%, 540px);
  max-height: 88vh;
  overflow-y: auto;
  background: var(--glass-2);
  backdrop-filter: var(--blur);
  border: 1px solid var(--glass-line);
  border-radius: var(--r-xl);
  padding: var(--modal-pad-y) var(--modal-pad-x);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transform: translateY(14px) scale(0.97);
  transition: opacity 0.3s cubic-bezier(0.22, 1, 0.36, 1),
              transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}
/* ── ขนาดกล่อง ────────────────────────────────────────────────
   เดิมมีสองแบบ (540 กับ 660) กล่องยืนยันสั้น ๆ จึงกว้างเกินจำเป็น ส่วนฟอร์ม
   สองคอลัมน์ก็อึดอัดทุกใบ · `modal-wide` ของเดิมยังใช้ได้ เท่ากับ lg */
.modal-dialog.modal-sm { width: min(100%, 420px); }
.modal-dialog.modal-md { width: min(100%, 540px); }
.modal-dialog.modal-lg,
.modal-dialog.modal-wide { width: min(100%, 680px); }
.modal-dialog.modal-xl { width: min(100%, 900px); }

/* ── หัวกับแถวปุ่มอยู่นิ่ง มีแค่เนื้อที่เลื่อน ──────────────────────
   ของเดิมกล่องทั้งใบเป็นตัวเลื่อน หัวเรื่องกับปุ่มบันทึกจึงเลื่อนหายไปด้วย
   ฟอร์มยาว ๆ เลื่อนลงไปกรอกกลางฟอร์มแล้วไม่เห็นปุ่มบันทึก ต้องเลื่อนกลับขึ้น
   ไปหาทุกครั้ง · ตัวเลื่อนย้ายไปอยู่ที่ .modal-body แทน

   ใช้ :has เพื่อให้โมดัลที่ยังไม่มี .modal-body ทำงานแบบเดิมทุกประการ —
   ทางถอยนี้ทำให้ไม่ต้องแก้ทุกจุดในคอมมิตเดียวแล้วเสี่ยงพังพร้อมกันหมด */
.modal-dialog:has(> .modal-body) {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 0;
}
.modal-head { flex: 0 0 auto; padding: var(--modal-pad-y) var(--modal-pad-x) 0.85rem; }
.modal-body { flex: 1 1 auto; overflow-y: auto; padding: 0 var(--modal-pad-x) var(--modal-pad-y); }
.modal-dialog:has(> .modal-body) > .modal-foot {
  flex: 0 0 auto;
  margin-top: 0;
  padding: 0.9rem var(--modal-pad-x) var(--modal-pad-y);
  border-top: 1px solid var(--hairline);
}
/* แถวปุ่มนอกกล่องเลื่อนรับระยะล่างเอง เนื้อจึงไม่ต้องเว้นซ้ำ */
.modal-dialog:has(> .modal-foot) > .modal-body { padding-bottom: 0.2rem; }

/* แถวปุ่มที่อยู่ **ในฟอร์ม** ข้างใน (ปุ่ม submit ต้องอยู่ในฟอร์มเดียวกัน) ออกไป
   อยู่นอกกล่องเลื่อนไม่ได้ จึงให้เกาะก้นกล่องเลื่อนแทน · มี backdrop-filter ของ
   ตัวเองเพื่อให้เนื้อที่เลื่อนลอดใต้แถบเบลอ ไม่ใช่ทับกันอ่านไม่ออก */
.modal-body .modal-foot {
  position: sticky;
  bottom: 0;
  z-index: 3;
  margin: 1.1rem calc(-1 * var(--modal-pad-x)) 0;
  padding: 0.9rem var(--modal-pad-x) var(--modal-pad-y);
  background: var(--glass-2);
  backdrop-filter: var(--blur);
  border-top: 1px solid var(--hairline);
}
.modal-body:has(.modal-foot) { padding-bottom: 0; }

/* ── ฟอร์มในโมดัล: สองคอลัมน์บนจอกว้าง ────────────────────────
   .form-grid ปกติเป็น auto-fit ซึ่งในกล่อง lg/xl จะยัดได้ถึงสามคอลัมน์ แล้ว
   แต่ละช่องแคบจนอ่านค่าที่กรอกไปแล้วไม่ออก · ล็อกไว้ที่สองคอลัมน์พอดี
   ผูกกับ**ขนาดกล่อง** ไม่ใช่กับจอ — กล่อง sm/md ยังปล่อยให้ไหลเองตามเดิม */
@media (min-width: 720px) {
  .modal-lg > .modal-body .form-grid,
  .modal-wide > .modal-body .form-grid,
  .modal-xl > .modal-body .form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.modal.is-open .modal-backdrop { opacity: 1; }
.modal.is-open .modal-dialog { opacity: 1; transform: none; }
.modal-close {
  all: unset;
  position: absolute;
  top: 0.9rem; right: 1rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--control-h-sm);
  height: var(--control-h-sm);
  border-radius: var(--r-sm);
  font-size: var(--fs-xl);
  line-height: 1;
  color: var(--ink-mute);
  transition: color 0.2s ease, transform 0.2s ease;
}
.modal-close:hover { color: var(--ink); transform: rotate(90deg); }
.modal-dialog h2 { font-size: var(--fs-xl); margin-bottom: 0.3rem; }
.modal-dialog .modal-sub { color: var(--ink-mute); font-size: var(--fs-base); margin-bottom: 1.3rem; }
.modal-foot { display: flex; gap: 0.6rem; justify-content: flex-end; margin-top: 1.4rem; flex-wrap: wrap; }
.confirm-icon {
  width: 2.7rem; height: 2.7rem;
  border-radius: 50%;
  display: grid; place-items: center;
  background: var(--red-bg);
  color: var(--red);
  font-size: var(--fs-xl);
  font-weight: 600;
  margin-bottom: 0.9rem;
}

/* ============================================================
   Alert (inline)
   ============================================================ */

.alert {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  padding: 0.8rem 1rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--hairline);
  background: rgba(255, 255, 255, 0.6);
  font-size: var(--fs-base);
}
.alert p { max-width: none; }

/* กล่องแจ้งเตือนที่ตามหลังเนื้อหาอื่นต้องมีระยะห่าง — ไม่งั้นมันไปติดกับแถว
   หรือปุ่มด้านบนจนดูเหมือนเป็นก้อนเดียวกัน (แจ้งเข้ามา 2026-08-07)
   :not(:first-child) กันเคสที่กล่องเป็นตัวแรกในการ์ด ซึ่งไม่ควรมีช่องว่างบน */
.alert:not(:first-child) { margin-top: 1.1rem; }
.alert-icon {
  flex-shrink: 0;
  width: 1.3rem; height: 1.3rem;
  border-radius: 50%;
  display: grid; place-items: center;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: #fff;
}
.alert-success { background: var(--green-bg); border-color: transparent; }
.alert-success .alert-icon { background: var(--green); }
.alert-error { background: var(--red-bg); border-color: transparent; }
.alert-error .alert-icon { background: var(--red); }
.alert-warn { background: var(--amber-bg); border-color: transparent; }
.alert-warn .alert-icon { background: var(--amber); }
.alert-info { background: var(--blue-bg); border-color: transparent; }
.alert-info .alert-icon { background: var(--accent); }

/* ค่าที่อ่านอย่างเดียวในฟอร์ม (เช่นบริษัทของผู้เขียนใบลา) — วางแทนที่ช่องกรอก
   จึงต้องสูงเท่ากันเพื่อไม่ให้แถวในกริดเหลื่อม */
.form-static {
  margin: 0;
  padding: 0.6rem 0;
  font-weight: 600;
  line-height: 1.4;
}

/* ── form validation (แจ้งฟิลด์ที่ยังไม่กรอก/ไม่ถูกต้อง เป็นข้อความสีแดง
   ใต้ช่อง แทน bubble ค่าเริ่มต้นของ browser) ─────────────────── */
.field-error {
  display: block;
  flex-basis: 100%;
  margin-top: 0.35rem;
  font-size: var(--fs-xs);
  color: var(--red);
}

/* ============================================================
   หน้าร้านสาธารณะ (storefront)
   ============================================================ */

.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  transition: background-color 0.35s ease, box-shadow 0.35s ease, border-color 0.35s ease;
  border-bottom: 1px solid transparent;
}
.site-header.is-scrolled {
  background: var(--glass);
  backdrop-filter: var(--blur);
  border-bottom-color: var(--hairline);
}
.site-header .container { display: flex; align-items: center; justify-content: space-between; height: 4.2rem; }
.brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--serif);
  font-size: var(--fs-lg);
  font-weight: 600;
  text-decoration: none;
  letter-spacing: -0.02em;
}
/* โลโก้เป็นวงกลมพื้นโปร่งใส วางบนพื้นของธีมได้ทั้งสว่างและมืด
   flex-shrink: 0 กันโดนบีบตอนชื่อยาวจนดันพื้นที่ */
.brand-mark { width: 34px; height: 34px; flex-shrink: 0; object-fit: contain; }
.brand small {
  display: block;
  font-size: var(--fs-2xs);
  font-weight: 500;
  /* บรรทัดรองแอดมินพิมพ์เองได้ (2026-09-17) — ระยะ 0.28em เดิมตั้งไว้สำหรับคำว่า
     WORKFLOW พอเป็นภาษาไทย สระ/วรรณยุกต์ถูกถ่างแยกจากพยัญชนะจนอ่านไม่ออก */
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-mute);
}
.site-nav { display: flex; align-items: center; gap: clamp(1rem, 3vw, 1.9rem); }
.site-nav a { font-size: var(--fs-base); text-decoration: none; color: var(--ink-soft); transition: color 0.2s ease; }
.site-nav a:hover { color: var(--accent); }
.site-nav .nav-login {
  color: #fff; background: var(--accent);
  padding: 0.42rem 1rem; border-radius: var(--r-pill);
}
.site-nav .nav-login:hover { color: #fff; background: var(--accent-hover); }
.site-nav .nav-links { display: contents; }
.cart-pill { position: relative; display: inline-flex; align-items: center; gap: 0.35rem; }
.cart-count {
  min-width: 1.25rem; height: 1.25rem;
  padding: 0 0.32rem;
  border-radius: var(--r-pill);
  background: var(--accent);
  color: #fff;
  font-size: var(--fs-2xs);
  display: grid; place-items: center;
}
.cart-count.is-empty { background: var(--ink-mute); }
@media (max-width: 760px) { .site-nav .nav-links { display: none; } }

/* ── hero ──────────────────────────────────────────────────── */

.hero {
  min-height: 90svh;
  display: grid;
  place-items: center;
  position: relative;
  overflow: hidden;
  text-align: center;
}
.hero-inner { position: relative; padding: 8rem 1.5rem 4rem; max-width: 780px; }
.hero h1 { font-size: clamp(2.4rem, 6vw, 4rem); font-weight: 600; letter-spacing: -0.03em; }
.hero .hero-sub { margin: 1.2rem auto 2rem; color: var(--ink-soft); font-size: clamp(1rem, 2vw, 1.15rem); font-weight: 400; }
.hero .hero-cta { display: flex; gap: 0.8rem; justify-content: center; flex-wrap: wrap; }
.hero-badges { display: flex; gap: 1.4rem; justify-content: center; flex-wrap: wrap; margin-top: 2.6rem; font-size: var(--fs-sm); color: var(--ink-mute); }
.hero-badges span { display: inline-flex; align-items: center; gap: 0.4rem; }
.hero-badges b { color: var(--ink); font-weight: 600; }

/* ── sections ──────────────────────────────────────────────── */

.section { padding: clamp(4rem, 10vh, 6.5rem) 0; }
.section-head { max-width: 640px; margin-bottom: clamp(2rem, 5vh, 3rem); }
.section-head.center { margin-inline: auto; text-align: center; }
.section-head h2 { font-size: clamp(1.7rem, 3.6vw, 2.4rem); font-weight: 600; }
.section-head p { color: var(--ink-soft); margin-top: 0.7rem; }
.section-alt { position: relative; }
.section-alt::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: rgba(255, 255, 255, 0.45);
  border-block: 1px solid var(--hairline);
}

.reveal { opacity: 0; transform: translateY(20px); transition: opacity 0.6s ease, transform 0.6s ease; }
.reveal.is-visible { opacity: 1; transform: none; }

/* ── card (glass) ──────────────────────────────────────────── */

.card {
  background: rgba(255, 255, 255, 0.72);
  border: 1px solid var(--glass-line);
  border-radius: var(--radius);
  padding: 1.4rem 1.6rem;
  box-shadow: var(--shadow);
}
.card > h2 { font-size: var(--fs-lg); margin-bottom: 0.9rem; }
.card-narrow { max-width: 520px; }
.card-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1rem; flex-wrap: wrap; }
.card-head h2 { font-size: var(--fs-lg); }

/* ── categories ────────────────────────────────────────────── */

.category-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 1.1rem; }
.category {
  padding: 1.7rem 1.6rem;
  border-radius: var(--radius);
  border: 1px solid var(--glass-line);
  background: rgba(255, 255, 255, 0.7);
  box-shadow: var(--shadow);
  transition: transform 0.35s ease, box-shadow 0.35s ease;
}
.category:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); }
.category .swatch { width: 40px; height: 40px; border-radius: var(--r-md); margin-bottom: 1rem; }
.tone-sage .swatch { background: linear-gradient(140deg, #5ac8fa, #0071e3); }
.tone-terracotta .swatch { background: linear-gradient(140deg, #ffd60a, #ff9f0a); }
.tone-dusk .swatch { background: linear-gradient(140deg, #da8fff, #bf5af2); }
.tone-sand .swatch { background: linear-gradient(140deg, #66d19e, #34c759); }
.category h3 { font-size: var(--fs-lg); }
.category p { font-size: var(--fs-base); color: var(--ink-soft); margin-top: 0.4rem; }

/* ── product grid & card ───────────────────────────────────── */

.product-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 1.3rem; }
.product-card {
  display: flex;
  flex-direction: column;
  border-radius: var(--radius);
  border: 1px solid var(--glass-line);
  background: rgba(255, 255, 255, 0.78);
  overflow: hidden;
  box-shadow: var(--shadow);
  transition: transform 0.35s ease, box-shadow 0.35s ease;
}
.product-card:hover { transform: translateY(-5px); box-shadow: var(--shadow-lg); }
.product-photo {
  aspect-ratio: 4 / 3;
  position: relative;
  display: grid;
  place-items: center;
  font-family: var(--serif);
  font-size: var(--fs-3xl);
  font-weight: 600;
  color: #fff;
}
.product-photo .product-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.product-photo.ph-0 { background: linear-gradient(150deg, #5ac8fa, #0071e3); }
.product-photo.ph-1 { background: linear-gradient(150deg, #ffd60a, #ff9f0a); }
.product-photo.ph-2 { background: linear-gradient(150deg, #da8fff, #bf5af2); }
.product-photo.ph-3 { background: linear-gradient(150deg, #66d19e, #34c759); }
.product-tag {
  position: absolute;
  top: 0.6rem; left: 0.6rem;
  font-size: var(--fs-2xs);
  padding: 0.18rem 0.6rem;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.88);
  color: var(--ink-soft);
}
.product-body { padding: 1rem 1.1rem 1.2rem; display: flex; flex-direction: column; gap: 0.3rem; flex: 1; }
.product-body h3 { font-size: var(--fs-md); font-weight: 600; line-height: 1.4; }
.product-cat { font-size: var(--fs-2xs); letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-mute); }
.product-foot { display: flex; align-items: center; justify-content: space-between; margin-top: auto; padding-top: 0.8rem; }
.product-price { font-size: var(--fs-lg); font-weight: 600; }
.add-cart {
  all: unset;
  cursor: pointer;
  width: 2.1rem; height: 2.1rem;
  border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent);
  color: #fff;
  font-size: var(--fs-lg);
  transition: background-color 0.2s ease, transform 0.15s ease;
}
.add-cart:hover { background: var(--accent-hover); transform: scale(1.08); }

/* ── newsletter ────────────────────────────────────────────── */

.subscribe-panel {
  max-width: 640px;
  margin-inline: auto;
  text-align: center;
  padding: clamp(2.2rem, 5vw, 3.2rem);
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.72);
  border: 1px solid var(--glass-line);
  box-shadow: var(--shadow);
}
.subscribe-panel h2 { font-size: clamp(1.6rem, 3.6vw, 2.1rem); font-weight: 600; }
.subscribe-panel > p { margin: 0.8rem auto 1.6rem; color: var(--ink-soft); }
.subscribe-form { display: flex; gap: 0.6rem; max-width: 440px; margin-inline: auto; flex-wrap: wrap; }
.subscribe-form input { flex: 1; min-width: 200px; }

/* ── inputs ────────────────────────────────────────────────── */

input, textarea, select {
  font-family: var(--sans);
  font-size: var(--fs-base);
  font-weight: 400;
  color: var(--ink);
  width: 100%;
  padding: 0.62rem 0.9rem;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.7);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
textarea { resize: vertical; min-height: 5rem; line-height: 1.6; }

/*
 * ตัวควบคุมทั้งหมดสูงเท่ากัน
 *
 * ทุกตัวใช้ padding ชุดเดียวกันอยู่แล้ว แต่ความสูงจริงมาจากเนื้อข้างใน จึงออกมา
 * ไม่เท่ากัน: input 42px · select (cselect-trigger) 45px เพราะมีไอคอน chevron ·
 * ปฏิทิน 46px เพราะไอคอนใหญ่กว่า — ยืนอยู่ในแถวเดียวกันแล้วขอบล่างเหลื่อมกันทุกหน้า
 * ตรึงด้วย min-height ตัวเดียวจึงตรงกันหมดโดยไม่ต้องไล่แก้ padding ทีละตัว
 *
 * ยกเว้น: checkbox/radio/color มีขนาดของตัวเอง · file ถูกซ่อนอยู่ใต้โซนลากวาง
 *
 * ชื่อคลาสเขียนซ้ำสองครั้ง (.cselect-trigger.cselect-trigger) เพื่อให้ชนะ `all: unset`
 * ในกฎ .cselect-trigger ที่อยู่ถัดลงไปในไฟล์ ซึ่งล้าง min-height ทิ้งทั้งหมด —
 * วิธีเดียวกับที่ .datepicker-trigger.datepicker-trigger ใช้อยู่แล้ว
 */
input:not([type="checkbox"]):not([type="radio"]):not([type="color"]):not([type="file"]),
select,
.cselect-trigger.cselect-trigger,
.datepicker-trigger.datepicker-trigger {
  min-height: var(--control-h);
}

/* ตัวย่อในแถบแบ่งหน้าตั้งใจให้เล็กกว่าตัวเต็ม แต่ต้องเท่ากับปุ่ม .btn-sm ที่ยืนข้างมัน
   ในแถบเดียวกัน — เดิมปล่อย 0 แล้วได้ 30.8px ซึ่งไม่ตรงกับอะไรเลย */
.pagination .per-page select,
.pagination .per-page .cselect-trigger,
.pager-size select,
.pager-size .cselect-trigger { min-height: var(--control-h-sm); }
input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(0, 113, 227, 0.16);
}
label { font-size: var(--fs-sm); color: var(--ink-soft); display: block; margin-bottom: 0.3rem; }

/* select: ซ่อนลูกศร native แล้ววาดลูกศร (chevron) ของเราเองให้เข้าธีม */
select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  padding-right: 2.3rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' stroke='%2386868b' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.85rem center;
  background-size: 12px 8px;
  cursor: pointer;
}
select:hover { border-color: rgba(0, 0, 0, 0.18); }
select:focus {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' stroke='%230071e3' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
select option { color: var(--ink); }

/* ── custom select (แทน dropdown ค่าเริ่มต้นของ browser ด้วย UI ของเราเอง)
   <select> จริงถูกซ่อนไว้ (.cselect-native) แต่ยังส่งฟอร์มได้ / ถ้าปิด JS ก็ยัง
   ใช้ตัว native ที่จัดสไตล์ไว้ด้านบนแทน  เมนูถูกย้ายไปไว้ที่ body (portal) แล้ว
   วางตำแหน่งแบบ fixed จึงไม่โดน overflow ของตาราง/modal หรือ backdrop-filter ตัด */
.cselect { position: relative; width: 100%; }
.status-form .cselect, .pagination .per-page .cselect { width: auto; }
.cselect-native { display: none !important; }

.cselect-trigger {
  all: unset;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  width: 100%;
  font-family: var(--sans);
  font-size: var(--fs-base);
  color: var(--ink);
  padding: 0.62rem 0.9rem;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.7);
  cursor: pointer;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.cselect-trigger:hover { border-color: rgba(0, 0, 0, 0.18); }
.cselect-trigger:focus-visible,
.cselect.is-open .cselect-trigger {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(0, 113, 227, 0.16);
}
.cselect-value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cselect-caret {
  flex-shrink: 0;
  width: 12px;
  height: 8px;
  background: center / 12px 8px no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' stroke='%2386868b' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  transition: transform 0.2s ease;
}
.cselect.is-open .cselect-caret { transform: rotate(180deg); }

/* เวอร์ชันเล็กสำหรับที่แคบ ๆ (แถวตาราง / ตัวเลือกต่อหน้า) */
.status-form .cselect-trigger,
.pagination .per-page .cselect-trigger { padding: 0.34rem 0.6rem; font-size: var(--fs-xs); }

.cselect-menu {
  position: fixed;
  z-index: 250;
  max-height: 17rem;
  max-width: calc(100vw - 16px);
  /* คอลัมน์: ช่องค้นหาปักอยู่หัวเมนู ส่วนรายการด้านล่างเลื่อนเอง */
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0.32rem;
  background: var(--glass-2);
  backdrop-filter: var(--blur);
  border: 1px solid var(--glass-line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  pointer-events: none;
  /* visibility หน่วงไว้จนจางหายเสร็จตอนปิด แต่ตอนเปิดต้องเป็น visible ทันที (0s ไม่หน่วง)
     — ถ้าปล่อยให้ transition ค่อย ๆ เปลี่ยน ช่องค้นหาจะยังอยู่ในโซน hidden
     ในจังหวะที่โค้ดสั่ง focus() แล้วเบราว์เซอร์ปฏิเสธเงียบ ๆ */
  transition: opacity 0.16s ease, transform 0.16s ease, visibility 0s linear 0.16s;
}
.cselect-menu.is-shown {
  opacity: 1;
  visibility: visible;
  transform: none;
  pointer-events: auto;
  transition: opacity 0.16s ease, transform 0.16s ease, visibility 0s linear 0s;
}

/* ── ช่องค้นหาใน dropdown (โผล่เมื่อมีตัวเลือกเยอะ) ── */
.cselect-search { padding: 0.1rem 0.1rem 0.32rem; }
.cselect-search-input {
  width: 100%;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  background: var(--glass);
  color: var(--ink);
  font-size: var(--fs-sm);
  font-family: inherit;
}
.cselect-search-input:focus-visible { outline: none; border-color: var(--accent); }
/* ปุ่มกากบาทล้างค่าของ search ใน WebKit ทับกับขอบเมนูจนดูรก */
.cselect-search-input::-webkit-search-cancel-button { display: none; }

.cselect-list {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  /* กันการเลื่อนไหลต่อไปที่หน้าเพจเมื่อถึงหัว/ท้ายรายการ — บนมือถือการไหลต่อจะทำให้
     ตัวจัดการ scroll ปิดเมนูทิ้งกลางคัน */
  overscroll-behavior: contain;
  /* min-height:0 จำเป็นกับ flex item ที่ต้องเลื่อนเอง ไม่งั้นมันดันสูงจนล้นเมนู */
  min-height: 0;
}
.cselect-empty { padding: 0.6rem 0.65rem; font-size: var(--fs-sm); color: var(--ink-mute); }
.cselect-option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  padding: 0.5rem 0.65rem;
  border-radius: var(--r-sm);
  font-size: var(--fs-base);
  color: var(--ink-soft);
  cursor: pointer;
  white-space: nowrap;
}
/* หัวข้อกลุ่มใน dropdown (spec 2026-09-17) — กดไม่ได้ ลูกศรข้ามไปเอง เพราะไม่อยู่ใน options[] */
.cselect-group {
  padding: 0.5rem 0.75rem 0.2rem;
  font-size: var(--fs-2xs);
  font-weight: 600;
  color: var(--ink-mute);
  text-transform: none;
  cursor: default;
  pointer-events: none;
}
/* ตัวที่ถูกกรองออกต้องหายไปจริง — `display: flex` ข้างบนเป็น author rule จึงชนะ
   `[hidden] { display: none }` ของเบราว์เซอร์ที่เป็น UA rule ตัวกรองจึงตั้ง .hidden
   ให้ถูกต้องแต่ไม่มีอะไรหายไปสักตัว ต้องเขียนทับเองตรงนี้ */
.cselect-option[hidden], .cselect-empty[hidden] { display: none; }
.cselect-option.is-active { background: rgba(0, 0, 0, 0.05); color: var(--ink); }
.cselect-option[aria-selected="true"] { color: var(--accent); font-weight: 500; }
.cselect-option[aria-selected="true"]::after { content: '✓'; font-size: var(--fs-xs); }

/* ── file drop zone (ลากรูปมาวาง / คลิกเลือกไฟล์) ─────────────── */
.filedrop {
  position: relative;
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.85rem 1rem;
  border: 1.5px dashed var(--hairline);
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.45);
  cursor: pointer;
  transition: border-color 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease;
}
.filedrop:hover { border-color: rgba(0, 0, 0, 0.22); background: rgba(255, 255, 255, 0.62); }
.filedrop:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(0, 113, 227, 0.16); }
.filedrop.is-dragover {
  border-color: var(--accent);
  border-style: solid;
  background: rgba(0, 113, 227, 0.06);
  box-shadow: 0 0 0 3px rgba(0, 113, 227, 0.14);
}
/* ซ่อน input จริง แต่ยังโฟกัสด้วยคีย์บอร์ดได้ */
.filedrop input[type="file"] {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.filedrop .thumb { width: 56px; height: 56px; }
.filedrop-text { font-size: var(--fs-sm); color: var(--ink-soft); line-height: 1.45; min-width: 0; }
.filedrop-text strong { color: var(--ink); font-weight: 500; }
.filedrop-browse { color: var(--accent); font-weight: 500; }
.filedrop:hover .filedrop-browse { text-decoration: underline; text-underline-offset: 2px; }
.filedrop-text small { display: block; color: var(--ink-mute); font-size: var(--fs-xs); margin-top: 0.15rem; }
.filedrop-text .filedrop-name {
  display: block;
  margin-top: 0.15rem;
  color: var(--ink-soft);
  font-size: var(--fs-xs);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* แถบรูปที่เลือกไว้ก่อนกดส่ง — อยู่นอกโซนลากวาง ปุ่มลบจึงไม่ชนกับการคลิกเปิด dialog */
.filedrop-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0.6rem 0 0;
  padding: 0;
  list-style: none;
}
.filedrop-item {
  position: relative;
  width: 72px;
  height: 72px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  border: 1px solid var(--hairline);
  background: rgba(0, 0, 0, 0.03);
}
.filedrop-item img { width: 100%; height: 100%; object-fit: cover; display: block; }
.filedrop-remove {
  position: absolute;
  top: 2px; right: 2px;
  width: 20px; height: 20px;
  display: flex; align-items: center; justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  font-size: var(--fs-md);
  line-height: 1;
  cursor: pointer;
}
.filedrop-remove:hover { background: rgba(200, 30, 30, 0.9); }
.filedrop-remove:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.filedrop-add { border-style: dashed; background: none; }
.filedrop-add button {
  width: 100%; height: 100%;
  border: 0;
  background: none;
  color: var(--ink-mute);
  font-size: var(--fs-xl);
  line-height: 1;
  cursor: pointer;
}
.filedrop-add button:hover { color: var(--accent); }
.filedrop-summary {
  margin: 0.4rem 0 0;
  font-size: var(--fs-xs);
  color: var(--ink-mute);
}
.filedrop-summary.is-over { color: var(--red); font-weight: 500; }

/* ── คลิปวิดีโอ ─────────────────────────────────────────────── */

.video-list { display: grid; gap: 0.8rem; }
.video-item { max-width: 520px; margin: 0.5rem 0; }
.video-player {
  width: 100%;
  max-height: 60vh;
  border-radius: var(--r-md, 10px);
  background: #000;
  display: block;
}
/* กรอบ 16:9 กันหน้ากระตุกตอน iframe โหลดเสร็จ */
.video-embed { position: relative; padding-top: 56.25%; }
.video-embed iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: var(--r-md, 10px);
}
.video-state {
  margin: 0;
  padding: 0.55rem 0.7rem;
  border: 1px dashed var(--hairline);
  border-radius: var(--r-md, 10px);
  font-size: var(--fs-xs);
  color: var(--ink-mute);
}
.video-state-failed { color: var(--red); border-style: solid; }
.video-link { display: block; font-size: var(--fs-sm); text-decoration: none; }
.video-link-host { display: block; font-weight: 500; color: var(--ink); }
.video-link-url { display: block; color: var(--ink-mute); font-size: var(--fs-xs); word-break: break-all; }

/* ── เรียนถึง ───────────────────────────────────────────────── */

.refer-radio { display: inline-flex; align-items: center; gap: 0.35rem; margin-right: 1rem; }
/* รายชื่อยาวกว่าจอได้ — เลื่อนในกล่องตัวเอง ไม่ดันฟอร์มให้ยาวจนหาปุ่มส่งไม่เจอ */
.refer-people {
  list-style: none;
  margin: 0.4rem 0 0;
  padding: 0.3rem;
  max-height: 15rem;
  overflow-y: auto;
  border: 1px solid var(--hairline);
  border-radius: var(--r-md, 10px);
}
.refer-people li { padding: 0.15rem 0.2rem; }
.refer-people label { display: flex; align-items: center; gap: 0.45rem; cursor: pointer; }

/* กลุ่มผู้ใช้ (spec 2026-09-17) */
.group-add, .group-edit { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.group-add input[type="text"], .group-edit input[type="text"] { flex: 1 1 12rem; min-width: 0; }
.group-order { white-space: nowrap; }
.group-order form { display: inline-block; }
.group-badge { margin-left: 0.35rem; font-weight: 500; }
.group-picker { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem; margin: 0.25rem 0 0.5rem; }
.group-picker-label { font-size: var(--fs-2xs); color: var(--ink-mute); }
.group-picker [aria-pressed="true"] { background: var(--green-bg); color: var(--green); }
.person-group-head { font-size: var(--fs-2xs); font-weight: 600; color: var(--ink-mute); padding: 0.55rem 0.2rem 0.1rem; }
.perm-grid-head { grid-column: 1 / -1; }
.refer-empty { margin: 0.4rem 0 0; font-size: var(--fs-xs); color: var(--ink-mute); }
.refer-status { list-style: none; margin: 0.4rem 0 0; padding: 0; font-size: var(--fs-sm); }
.refer-status li { display: flex; align-items: center; gap: 0.35rem; flex-wrap: wrap; padding: 0.1rem 0; }
.refer-mark { font-size: var(--fs-xs); }
.refer-done { color: var(--green, #2e7d32); }
.refer-off { color: var(--ink-mute); }
.refer-wait { color: var(--ink-soft); }
.refer-note { color: var(--ink-soft); }
/* ฟอร์มถอนคำขออยู่ในบรรทัดเดียวกับชื่อ ไม่ขึ้นบรรทัดใหม่ให้รายการยืด */
.refer-revoke { display: inline; margin-left: 0.3rem; }

/* ── footer ────────────────────────────────────────────────── */

.site-footer {
  padding: 3rem 0 2.6rem;
  border-top: 1px solid var(--hairline);
  text-align: center;
  font-size: var(--fs-sm);
  color: var(--ink-mute);
}
.site-footer .brand { font-size: var(--fs-lg); }
.site-footer p { margin: 0.7rem auto 0; }

/* ============================================================
   หลังร้าน (dashboard)
   ============================================================ */

.app-shell { display: flex; min-height: 100svh; }

.app-sidebar {
  width: 244px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  padding: 1.4rem 0.9rem;
  background: var(--glass);
  backdrop-filter: var(--blur);
  border-right: 1px solid var(--hairline);
  position: sticky;
  top: 0;
  height: 100svh;
}
.app-sidebar .brand { padding: 0 0.8rem 1.2rem; }
.app-nav { display: grid; gap: 0.12rem; overflow-y: auto; }
.app-nav a {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0.55rem 0.8rem;
  border-radius: var(--r-sm);
  font-size: var(--fs-base);
  text-decoration: none;
  color: var(--ink-soft);
  transition: background-color 0.2s ease, color 0.2s ease;
}
.app-nav a:hover { background: rgba(0, 0, 0, 0.045); color: var(--ink); }
.app-nav a.is-active { background: var(--accent); color: #fff; }
.app-nav a.is-active .nav-glyph { opacity: 1; }
/* ไอคอนหน้าเมนู — inline SVG จาก components/icon.php (เดิมเป็นจุดกลมเปล่า ๆ) */
.app-nav .nav-glyph { flex-shrink: 0; opacity: 0.7; }
.app-nav .nav-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.app-nav .nav-section {
  font-size: var(--fs-2xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-mute);
  padding: 1rem 0.8rem 0.35rem;
}

/* ── หมวดในเมนูข้าง — ยุบ/กางด้วย <details> ล้วน ๆ ──────────────
   ทำงานได้แม้ JS ไม่ทำงาน · JS มีหน้าที่แค่จำว่าเครื่องนี้พับหมวดไหนไว้
   ระยะห่างระหว่างลิงก์ต้องตั้งเองที่นี่ เพราะลิงก์ที่อยู่ใน <details> ไม่ใช่
   ลูกของกริด .app-nav แล้ว จึงไม่ได้ gap ของกริดไปด้วย */
.nav-group > a { margin-top: 0.12rem; }
.nav-group > summary {
  display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
  cursor: pointer; list-style: none; -webkit-user-select: none; user-select: none;
  border-radius: var(--r-sm);
}
.nav-group > summary::-webkit-details-marker { display: none; }
.nav-group > summary:hover { color: var(--ink-soft); }
.nav-group > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.nav-chevron { flex-shrink: 0; opacity: 0.65; transition: transform 0.2s ease; }
.nav-group:not([open]) > summary .nav-chevron { transform: rotate(-90deg); }

/* ── เมนูย่อยชั้นสาม ─────────────────────────────────────────────
   หัวข้อหน้าตาเหมือน "ลิงก์เมนูที่มีลูกศร" ไม่ใช่หัวข้อหมวดตัวเล็กพิมพ์ใหญ่ —
   เพราะมันนั่งอยู่ในแถวเดียวกับลิงก์ ไม่ได้ลอยอยู่เหนือกลุ่มแบบหัวข้อหมวด
   จึงต้องล้างค่าที่ .nav-section ตั้งไว้สำหรับหัวข้อหมวด (uppercase · fs-2xs ·
   letter-spacing · padding บนหนา · space-between) ออกให้หมด */
.nav-subgroup > summary.nav-section {
  font-size: var(--fs-base);
  letter-spacing: normal;
  text-transform: none;
  color: var(--ink-soft);
  padding: 0.55rem 0.8rem;
  gap: 0.65rem;
  justify-content: flex-start;
}
.nav-subgroup > summary .nav-chevron { margin-left: auto; }
.nav-subgroup > summary:hover { background: rgba(0, 0, 0, 0.045); color: var(--ink); }
/* ลูกเยื้องเข้าไปให้ตรงกับข้อความของหัวข้อ ไม่ใช่กับไอคอน */
.nav-subgroup > a { padding-left: 2.15rem; }
.app-sidebar .sidebar-foot { margin-top: auto; padding-top: 1.2rem; }
.logout-form button {
  all: unset;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.55rem 0.7rem;
  border-radius: var(--r-sm);
  font-size: var(--fs-base);
  /* `all: unset` ล้าง line-height เป็น normal — ต้องตั้งคืนให้เท่ากับ
     .user-dropdown-list a ที่อยู่เหนือมันในเมนูเดียวกัน ไม่งั้นเตี้ยกว่าราว 5px
     ทั้งที่ padding และขนาดตัวอักษรเหมือนกันทุกค่า */
  line-height: 1.6;
  min-height: var(--control-h-bar);
  color: var(--red);
  cursor: pointer;
  transition: background-color 0.2s ease;
}
.logout-form button:hover { background: var(--red-bg); }

.app-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.app-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.85rem clamp(1.2rem, 4vw, 2.4rem);
  border-bottom: 1px solid var(--hairline);
  background: var(--glass);
  backdrop-filter: var(--blur);
  position: sticky;
  top: 0;
  z-index: 40;
}
.app-topbar h1 { font-size: var(--fs-xl); font-weight: 600; margin-right: auto; }
.user-menu { position: relative; }
/* สามตัวบนแถบบนสุด (.app-user · .theme-toggle · ปุ่มเมนูมือถือ) ตรึงความสูงเดียวกัน
   ที่ --control-h-bar — เดิม 42.9 / 38 / อื่น ๆ ยืนเรียงกันโดยขอบไม่ตรงสักคู่ */
.app-user {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  min-height: var(--control-h-bar);
  font-family: inherit;
  font-size: var(--fs-base);
  color: var(--ink-soft);
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.15rem 0.35rem 0.15rem 0.7rem;
  border-radius: var(--r-pill);
  transition: background-color 0.2s ease;
}
.app-user:hover { background: rgba(0, 0, 0, 0.05); }
/* รูปโปรไฟล์บนแถบบนเล็กกว่าที่อื่น เพื่อให้ปุ่มทั้งใบพอดี --control-h-bar */
.app-user .avatar { width: 32px; height: 32px; }
.avatar {
  width: 34px; height: 34px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent);
  color: #fff;
  font-size: var(--fs-md);
  font-weight: 600;
  flex-shrink: 0;
}
.avatar-lg { width: 42px; height: 42px; font-size: var(--fs-lg); }

.user-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 244px;
  background: #fff;
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  z-index: 60;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
}
.user-menu.is-open .user-dropdown { opacity: 1; visibility: visible; transform: none; }
.user-dropdown-head {
  display: flex;
  gap: 0.7rem;
  align-items: center;
  padding: 0.9rem 1rem;
  border-bottom: 1px solid var(--hairline);
}
.user-meta { display: grid; gap: 0.05rem; min-width: 0; }
.user-meta strong { font-size: var(--fs-base); }
.user-meta span { font-size: var(--fs-xs); color: var(--ink-mute); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.user-dropdown-list { display: grid; padding: 0.4rem; gap: 0.08rem; }
.user-dropdown-list a {
  display: flex;
  align-items: center;
  min-height: var(--control-h-bar);
  padding: 0.55rem 0.7rem;
  border-radius: var(--r-sm);
  font-size: var(--fs-base);
  text-decoration: none;
  color: var(--ink-soft);
  transition: background-color 0.2s ease, color 0.2s ease;
}
.user-dropdown-list a:hover { background: rgba(0, 0, 0, 0.05); color: var(--ink); }
.user-dropdown-foot { padding: 0.4rem; border-top: 1px solid var(--hairline); }
@media (max-width: 520px) { .app-user .user-name { display: none; } }
.app-content { padding: clamp(1.3rem, 3.5vw, 2.2rem); display: grid; gap: 1.3rem; align-content: start; }

.menu-toggle { display: none; }
@media (max-width: 860px) {
  .app-sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: 70;
    transform: translateX(-100%);
    transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1);
    box-shadow: var(--shadow-lg);
  }
  .app-shell.nav-open .app-sidebar { transform: none; }
  .menu-toggle { all: unset; display: grid; gap: 4px; cursor: pointer; padding: 0.5rem; }
  .menu-toggle span { width: 20px; height: 1.5px; background: var(--ink); border-radius: 2px; }
  .app-backdrop {
    position: fixed; inset: 0; z-index: 65;
    background: rgba(20, 23, 28, 0.3);
    opacity: 0; pointer-events: none;
    transition: opacity 0.3s ease;
  }
  .app-shell.nav-open .app-backdrop { opacity: 1; pointer-events: auto; }
}

/* ── stats ─────────────────────────────────────────────────── */

.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 1.1rem; }
.stat { position: relative; overflow: hidden; }
.stat .stat-label { font-size: var(--fs-xs); color: var(--ink-mute); }
.stat .stat-value { font-size: var(--fs-2xl); font-weight: 600; line-height: 1.25; margin: 0.25rem 0 0.1rem; letter-spacing: -0.03em; }
.stat .stat-hint { font-size: var(--fs-xs); color: var(--green); }
.stat .stat-mark { position: absolute; top: 1.1rem; right: 1.2rem; width: 9px; height: 9px; border-radius: 50%; background: var(--stat-tone, var(--accent)); }
/* สีประจำโทนของการ์ด — ประกาศที่เดียว ใช้ทั้งจุดกลมมุมขวาบนและกรอบของการ์ดที่กดได้
   จะได้ไม่มีวันเพี้ยนจากกัน */
.stat.tone-sage { --stat-tone: #34c759; }
.stat.tone-terracotta { --stat-tone: #ff9f0a; }
.stat.tone-dusk { --stat-tone: #bf5af2; }
.stat.tone-sand { --stat-tone: #0071e3; }

/* การ์ดที่กดได้ — กรอบสีเดียวกับจุดกลมประจำโทน ให้รู้ว่ากดได้ตั้งแต่แรกเห็น
   ไม่ต้องรอเอาเมาส์ไปชี้ (บนมือถือไม่มี hover ให้ชี้อยู่แล้ว)
   ความหนา 1.5px เท่าการ์ดเน้น เพื่อให้กรอบทุกใบในแถวเดียวกันหนาเท่ากัน */
a.stat { display: block; text-decoration: none; color: inherit; cursor: pointer;
  border: 1.5px solid var(--stat-tone, var(--accent));
  transition: transform 0.15s ease, box-shadow 0.15s ease; }
a.stat:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg); }
a.stat:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* การ์ดเน้น — เด่นด้วยขอบกับขนาดตัวเลข ไม่ใช้สีพื้นทึบเพราะอยู่บนสุดของหน้าที่เห็นทุกวัน */
.stat.is-featured { border: 1.5px solid var(--accent); }
.stat.is-featured .stat-value { font-size: var(--fs-3xl); color: var(--accent); }
.stat.is-featured .stat-label { color: var(--ink); font-weight: 500; }
.stat.is-featured .stat-hint { color: var(--accent); }

/* ── tables ────────────────────────────────────────────────── */

.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: var(--fs-base); }
thead { background: var(--gray-bg); }
th {
  text-align: left;
  font-weight: 600;
  font-size: var(--fs-2xs);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding: 0.65rem 0.85rem;
  border-bottom: 1px solid var(--hairline);
  white-space: nowrap;
}
th:first-child { border-top-left-radius: 10px; border-bottom-left-radius: 10px; }
th:last-child { border-top-right-radius: 10px; border-bottom-right-radius: 10px; }
td { padding: 0.7rem 0.85rem; border-bottom: 1px solid rgba(0, 0, 0, 0.05); vertical-align: middle; }
tbody tr:hover { background: rgba(0, 0, 0, 0.025); }
/*
 * ปุ่มเครื่องมือท้ายแถว — ต้องอยู่กึ่งกลางแนวตั้งเสมอไม่ว่าแถวจะสูงกี่บรรทัด
 *
 * ห้ามตั้ง display:flex ที่ตัว <td> เอง (ของเดิมตั้งไว้) เพราะเซลล์จะเลิกเป็น
 * table-cell แล้วเบราว์เซอร์ห่อด้วยเซลล์นิรนามที่จัดแนวแบบ baseline — vertical-align
 * ของ td ใช้ไม่ได้ ปุ่มจึงลอยไปติดขอบบนทันทีที่เนื้อหาในแถวยาวเกินหนึ่งบรรทัด
 * ใช้ inline-flex ที่ "ลูก" แทน เซลล์จึงยังเป็น table-cell ตามปกติ
 */
td.cell-actions { white-space: nowrap; vertical-align: middle; }
td.cell-actions > * { display: inline-flex; align-items: center; vertical-align: middle; }
td.cell-actions > * + * { margin-left: 0.4rem; }
.status-form { display: flex; gap: 0.35rem; align-items: center; }
.status-form select { width: auto; padding: 0.38rem 0.55rem; font-size: var(--fs-xs); }
.num { font-variant-numeric: tabular-nums; }

.thumb { width: 42px; height: 42px; border-radius: var(--r-sm); background-size: cover; background-position: center; flex-shrink: 0; }
.thumb-empty {
  display: grid; place-items: center;
  background: linear-gradient(140deg, #5ac8fa, #0071e3);
  color: #fff;
  font-weight: 600;
  font-size: var(--fs-lg);
}
.prod-cell { display: flex; align-items: center; gap: 0.7rem; }
.prod-cell .prod-name { font-weight: 500; color: var(--ink); }
.prod-cell .prod-sku { font-size: var(--fs-xs); color: var(--ink-mute); }

.meter { width: 96px; height: 5px; border-radius: var(--r-pill); background: rgba(0, 0, 0, 0.08); overflow: hidden; }
.meter i { display: block; height: 100%; border-radius: inherit; background: var(--accent); }
.meter.is-low i { background: var(--red); }
.w-0 { width: 0; } .w-10 { width: 10%; } .w-20 { width: 20%; } .w-30 { width: 30%; }
.w-40 { width: 40%; } .w-50 { width: 50%; } .w-60 { width: 60%; } .w-70 { width: 70%; }
.w-80 { width: 80%; } .w-90 { width: 90%; } .w-100 { width: 100%; }

/* ── activity feed ─────────────────────────────────────────── */

.feed { list-style: none; display: grid; gap: 0.1rem; }
.feed li {
  display: grid;
  grid-template-columns: 6rem 1fr auto auto;
  align-items: center;
  gap: 0.7rem;
  padding: 0.6rem 0.35rem;
  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
.feed li:last-child { border-bottom: none; }
.feed-code { font-variant-numeric: tabular-nums; color: var(--ink-mute); font-size: var(--fs-sm); }
.feed-total { font-weight: 600; }
.empty { color: var(--ink-mute); text-align: center; padding: 1.4rem; font-size: var(--fs-base); }

/* ── sales chart ───────────────────────────────────────────── */

.chart { display: flex; align-items: flex-end; gap: 0.6rem; height: 170px; padding-top: 1rem; }
.chart .bar { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 0.45rem; height: 100%; justify-content: flex-end; }
.chart .bar-fill {
  width: 100%;
  max-width: 40px;
  border-radius: 8px 8px 4px 4px;
  background: linear-gradient(180deg, #5ac8fa, #0071e3);
  transition: height 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}
.chart .bar:last-child .bar-fill { background: linear-gradient(180deg, #ffd60a, #ff9f0a); }
.chart .bar-label, .chart .bar-val { font-size: var(--fs-2xs); color: var(--ink-mute); }
.h-0 { height: 0; } .h-10 { height: 10%; } .h-20 { height: 20%; } .h-30 { height: 30%; }
.h-40 { height: 40%; } .h-50 { height: 50%; } .h-60 { height: 60%; } .h-70 { height: 70%; }
.h-80 { height: 80%; } .h-90 { height: 90%; } .h-100 { height: 100%; }

/* ── toolbar & pagination ──────────────────────────────────── */

.toolbar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.toolbar .search { max-width: 340px; flex: 1; }

/* ช่องค้นหา + ปุ่มค้นหา เป็นแถบเดียวกัน (input-group) ปุ่มเป็นสีหลัก + ไอคอนแว่นขยาย */
.search { display: flex; align-items: stretch; max-width: 380px; }
.search input[type="search"] { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.search input[type="search"]:focus { position: relative; z-index: 1; }
.search .search-btn {
  flex-shrink: 0;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  padding: 0 1rem;
  gap: 0;
}
.search .search-btn .icon-svg { display: block; }

/* ── ประวัติการค้นหา (dropdown แบบ Google, เก็บใน localStorage) ── */
.search-hist {
  position: fixed;
  z-index: 240;
  max-height: 18rem;
  overflow-y: auto;
  list-style: none;
  margin: 0;
  padding: 0.3rem;
  background: var(--glass-2);
  backdrop-filter: var(--blur);
  border: 1px solid var(--glass-line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  pointer-events: none;
  transition: opacity 0.16s ease, transform 0.16s ease, visibility 0.16s;
}
.search-hist.is-shown { opacity: 1; visibility: visible; transform: none; pointer-events: auto; }
.search-hist-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 0.55rem;
  border-radius: var(--r-sm);
  font-size: var(--fs-base);
  color: var(--ink-soft);
  cursor: pointer;
}
.search-hist-item.is-active, .search-hist-item:hover { background: rgba(0, 0, 0, 0.05); color: var(--ink); }
.sh-icon {
  flex-shrink: 0;
  width: 15px; height: 15px;
  background: center / 15px 15px no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='none' stroke='%2386868b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 3v5h5'/%3E%3Cpath d='M3.05 13A9 9 0 1 0 6 5.3L3 8'/%3E%3Cpath d='M12 7v5l3 2'/%3E%3C/svg%3E");
}
.sh-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sh-del {
  all: unset;
  flex-shrink: 0;
  width: 1.4rem; height: 1.4rem;
  display: grid; place-items: center;
  border-radius: var(--r-xs);
  font-size: var(--fs-md);
  line-height: 1;
  color: var(--ink-mute);
  cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease;
}
.sh-del:hover { color: var(--red); background: var(--red-bg); }
.search-hist-foot {
  margin-top: 0.25rem;
  padding: 0.5rem 0.55rem;
  border-top: 1px solid var(--hairline);
}
.search-hist-clear {
  all: unset;
  display: block;
  width: 100%;
  text-align: center;
  font-size: var(--fs-xs);
  color: var(--ink-mute);
  cursor: pointer;
  padding: 0.2rem;
  border-radius: var(--r-xs);
}
.search-hist-clear:hover { color: var(--red); background: var(--red-bg); }
.filter-tabs { display: flex; gap: 0.35rem; flex-wrap: wrap; }
.filter-tabs a {
  font-size: var(--fs-sm);
  padding: 0.35rem 0.85rem;
  border-radius: var(--r-pill);
  text-decoration: none;
  color: var(--ink-soft);
  border: 1px solid var(--hairline);
  transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
.filter-tabs a:hover { color: var(--ink); border-color: rgba(0, 0, 0, 0.18); }
.filter-tabs a.is-active { background: var(--accent); color: #fff; border-color: var(--accent); }

.pagination { display: flex; align-items: center; gap: 0.5rem; justify-content: flex-end; margin-top: 1.1rem; flex-wrap: wrap; }
.pagination .page-info { margin-right: auto; font-size: var(--fs-sm); color: var(--ink-mute); }
.pagination .per-page { display: inline-flex; align-items: center; gap: 0.45rem; font-size: var(--fs-xs); color: var(--ink-mute); }
.pagination .per-page select {
  width: auto;
  padding: 0.32rem 1.9rem 0.32rem 0.65rem;
  font-size: var(--fs-xs);
  background-position: right 0.55rem center;
}
.page-nav { display: inline-flex; align-items: center; gap: 0.3rem; flex-wrap: wrap; }
.pagination a, .pagination span.page-cur {
  min-width: 2rem;
  height: 2rem;
  padding: 0 0.55rem;
  display: inline-grid;
  place-items: center;
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  text-decoration: none;
  color: var(--ink-soft);
  border: 1px solid var(--hairline);
}
.pagination a:hover { color: var(--ink); background: rgba(0, 0, 0, 0.04); }
.pagination span.page-cur { background: var(--accent); color: #fff; border-color: var(--accent); }

/* ── forms (dashboard) ─────────────────────────────────────── */

.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 0.9rem 1.2rem; }
.form-grid .full { grid-column: 1 / -1; }

/* ฟอร์มยาว ๆ แบ่งเป็นกลุ่มมีหัวข้อ (เช่น modal เพิ่ม/แก้ไขผู้ใช้) */
/* ฟอร์มที่แบ่งหัวข้อย่อยแล้วใช้สองคอลัมน์ · auto-fit ยัดได้ถึงหกคอลัมน์บนการ์ด
   กว้าง ๆ แล้วแถวสุดท้ายของแต่ละหัวข้อจะเหลือที่ว่างเป็นหย่อม ๆ ดูเหมือนหน้าเสีย
   (เห็นชัดตอนแบ่งหัวข้อ เพราะช่องไม่ไหลข้ามหัวข้อไปเติมแถวให้เต็มอีกแล้ว) */
@media (min-width: 720px) {
  .form-section > .form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
form > .form-section:first-of-type { margin-top: 1rem; }
.form-section + .form-section { margin-top: 1.25rem; padding-top: 1.1rem; border-top: 1px solid var(--hairline); }
.form-section-title { font-size: var(--fs-sm); font-weight: 600; color: var(--ink-mute); margin-bottom: 0.7rem; }

/* สวิตช์ที่อยู่ในกริดร่วมกับช่องกรอก — label ข้างบนเหมือนกัน แล้วดัน
   ตัวสวิตช์ลงมาให้อยู่ระดับเดียวกับกล่อง input ของช่องข้าง ๆ */
.field-switch { display: flex; flex-direction: column; }
.field-switch .switch { align-self: flex-start; min-height: 42px; }

/* ── หน้ารายงาน ──────────────────────────────────────────────── */
.report-filters .form-actions { margin-top: 1rem; }
.report-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.report-table td[data-label="หัวข้อ"] { max-width: 28ch; }
.report-summary tfoot td { font-weight: 600; border-top: 1px solid var(--hairline); }

/* สวิตช์มุมมองของรายงานเซล — ลิงก์ที่หน้าตาเหมือนแท็บ (ไม่ใช่ฟอร์ม เพราะ
   withView() คงตัวกรองเดิมไว้ให้แล้ว ลิงก์จึงก๊อปส่งต่อได้ด้วย) */
.view-switch { display: flex; gap: 0.35rem; flex-wrap: wrap; margin-bottom: 1rem; }
.view-tab {
  padding: 0.45rem 0.9rem;
  border-radius: var(--r-pill);
  font-size: var(--fs-base);
  text-decoration: none;
  color: var(--ink-soft);
  background: var(--gray-bg);
}
.view-tab:hover { color: var(--ink); }
.view-tab.is-active { background: var(--accent); color: #fff; }

/* กล่องแผนที่ต้องมีความสูงจริงก่อน Leaflet จะวัดขนาดได้ถูก
   (Leaflet วัดตอนสร้างแล้วจำค่าไว้ — ดูคอมเมนต์ที่ app/views/pin/list.php) */
/* z-index: 0 กันชั้นข้างในของ Leaflet (สูงถึง 1000) ทะลุออกมาทับหัวเมนูที่อยู่ที่ 100
   — ปัญหาเดียวกับ .activity-map เจอจริง 2026-09-04 */
.report-map {
  height: 60vh;
  min-height: 320px;
  border-radius: var(--r-md);
  overflow: hidden;
  position: relative;
  z-index: 0;
}

/* ตัวเลขในตารางรายงานเซลชิดขวาให้เทียบกันได้ด้วยตา */
.sale-report-table .num { text-align: right; white-space: nowrap; }

/* ตารางรายงานใบลา — ตัวเลขชิดขวาให้เทียบกันได้ด้วยตา */
.leave-report-table .num { text-align: right; white-space: nowrap; }
.leave-report-table tfoot td { font-weight: 600; border-top: 1px solid var(--hairline); }
/* สิทธิคงเหลือติดลบ = อนุมัติเกินสิทธิ์ไปแล้ว ต้องสะดุดตา ไม่ใช่กลมกลืน */
.leave-report-table .is-over { color: var(--red); font-weight: 600; }

/* ธงสิทธิ์แบ่งเป็นสี่กลุ่มตามงาน — ซ้อนลงล่าง ไม่ใช่คอลัมน์ข้างกัน เพราะแต่ละกลุ่ม
   มีจำนวนธงไม่เท่ากัน (7/3/2/4) วางข้างกันแล้วกลุ่มสั้นทิ้งช่องว่างยาวเป็นหาง */
.perm-groups { display: flex; flex-direction: column; gap: 1rem; }

/* ระดับรองจาก .form-section-title — เล็กกว่าและมีเส้นคั่นบาง ๆ ให้เห็นขอบกลุ่ม */
.perm-group-title {
    font-size: var(--fs-sm); font-weight: 600; color: var(--ink-mute);
    margin-bottom: 0.55rem; padding-bottom: 0.3rem;
    border-bottom: 1px solid var(--hairline);
}

/* ธงสิทธิ์ — คอลัมน์ตายตัว ไม่ปล่อยให้ไหลตกบรรทัดตามความยาวข้อความ
   align-items: start คือตัวกันเหลื่อม — ช่องที่ข้อความยาวตกสองบรรทัดทำให้แถวสูงขึ้น
   ถ้าเพื่อนบ้านถูกจัดกึ่งกลางมันจะลอยตามลงมาด้วยทั้งที่ตัวเองมีบรรทัดเดียว

   **auto-fill ไม่ใช่ auto-fit** — ต่างกันตรงคอลัมน์ที่ไม่มีของอยู่: auto-fit ยุบทิ้ง
   แล้วเฉลี่ยที่ว่างให้ช่องที่เหลือ ส่วน auto-fill เก็บไว้เป็นที่ว่าง · กลุ่ม "เมนูเซล"
   มีแค่ 2 ช่อง พอ auto-fit ยุบคอลัมน์ที่สามทิ้ง สองช่องนั้นก็ยืดเป็นครึ่งความกว้าง
   แล้วช่องติ๊กไม่ตรงแนวกับกลุ่มอื่นที่มีสามคอลัมน์ (เจ้าของงานแจ้ง 2026-09-01) */
.perm-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(215px, 1fr)); gap: 0.55rem 1.2rem; align-items: start; }
.perm-grid .check-inline { margin-right: 0; display: flex; align-items: center; gap: 0.5rem; }

/* ธงที่ "ตำแหน่ง" คุมไว้ — เทาและกดไม่ได้ ไม่มีข้อความอธิบาย
   (เหตุผลของแต่ละธงอยู่ใน RolePermissions ในฐานะเอกสารของคนเขียนโค้ด) */
.check-inline.is-implied { color: var(--ink-mute); cursor: default; }
.check-inline.is-implied input { accent-color: var(--ink-mute); }
.form-actions { margin-top: 1.4rem; display: flex; gap: 0.6rem; flex-wrap: wrap; }

.order-head { margin-bottom: 1.1rem; }
.order-head .order-code { font-size: var(--fs-lg); font-weight: 600; margin-right: 0.6rem; }
.order-head p { color: var(--ink-mute); font-size: var(--fs-base); margin-top: 0.4rem; }
.order-total { text-align: right; margin-top: 0.9rem; font-size: var(--fs-md); }
.order-total strong { font-size: var(--fs-xl); font-weight: 600; margin-left: 0.4rem; }

/* ── showcase (UI kit) ─────────────────────────────────────── */

.page-intro { color: var(--ink-soft); font-size: var(--fs-md); max-width: 72ch; }
.ui-block { }
.ui-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1rem; flex-wrap: wrap; }
.ui-head h2 { font-size: var(--fs-lg); display: flex; align-items: center; gap: 0.6rem; }
.ui-head code {
  background: var(--gray-bg);
  padding: 0.25rem 0.6rem;
  border-radius: var(--r-xs);
  color: var(--ink-soft);
}
.ui-tag {
  font-size: var(--fs-2xs);
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--accent);
  background: var(--blue-bg);
  padding: 0.15rem 0.55rem;
  border-radius: var(--r-pill);
}
.ui-desc { color: var(--ink-mute); font-size: var(--fs-base); margin-bottom: 0.9rem; }
.ui-row { display: flex; gap: 0.6rem; flex-wrap: wrap; align-items: center; }
.ui-stack { display: grid; gap: 0.6rem; }
.ui-hr { border: none; border-top: 1px solid var(--hairline); margin: 1.3rem 0; }
.load-box { margin-top: 1rem; border: 1px solid var(--hairline); border-radius: var(--radius-sm); min-height: 90px; }
.ui-block .form-grid { margin-top: 0.2rem; }

/* ── auth ──────────────────────────────────────────────────── */

.auth-wrap { min-height: 100svh; display: grid; place-items: center; padding: 5rem 1.5rem 3rem; }
.auth-card {
  width: min(100%, 390px);
  padding: 2.4rem 2.2rem;
  border-radius: var(--r-xl);
  background: rgba(255, 255, 255, 0.78);
  border: 1px solid var(--glass-line);
  box-shadow: var(--shadow-lg);
}
.auth-logo { display: block; width: 96px; height: 96px; margin: 0 auto 1rem; object-fit: contain; }
.auth-card h1 { font-size: var(--fs-2xl); font-weight: 600; text-align: center; }
.auth-card .auth-sub { text-align: center; font-size: var(--fs-base); color: var(--ink-mute); margin: 0.4rem 0 1.6rem; }
.auth-card form { display: grid; gap: 0.9rem; }
.check-row { display: flex; align-items: center; gap: 0.5rem; font-size: var(--fs-sm); color: var(--ink-soft); }
.check-row input { width: auto; accent-color: var(--accent); }
.auth-card .btn { width: 100%; margin-top: 0.2rem; }
.auth-hint { text-align: center; font-size: var(--fs-xs); color: var(--ink-mute); margin-top: 0.9rem; }
.auth-back { display: block; text-align: center; margin-top: 1.3rem; font-size: var(--fs-sm); color: var(--ink-mute); }

/* ── error pages ───────────────────────────────────────────── */

.error-wrap { min-height: 100svh; display: grid; place-items: center; text-align: center; padding: 2rem; }
.error-wrap .code { font-size: clamp(3.6rem, 11vw, 6rem); font-weight: 700; color: var(--accent); line-height: 1.1; letter-spacing: -0.03em; }
.error-wrap h1 { font-size: var(--fs-xl); font-weight: 600; margin: 0.5rem 0 0.9rem; }
.error-wrap p { color: var(--ink-soft); margin-inline: auto; }
.error-wrap .btn { margin-top: 1.8rem; }

/* ── reduced motion ────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .reveal { opacity: 1; transform: none; }
  .spinner, .btn.is-loading::after { animation: spin 0.8s linear infinite !important; }
}

/* ============================================================
   Component library (ชุดเสริมตาม mvc-components-guide)
   ============================================================ */

/* icon */
.icon-svg { display: inline-block; vertical-align: -0.15em; flex-shrink: 0; }

/* link */
.link { color: var(--accent); text-decoration: none; }
.link:hover { text-decoration: underline; text-underline-offset: 2px; }
.link.is-active { font-weight: 600; }

/* breadcrumb */
.breadcrumb ol { list-style: none; display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; font-size: var(--fs-sm); color: var(--ink-mute); }
.breadcrumb li { display: inline-flex; align-items: center; gap: 0.4rem; }
.breadcrumb li:not(:first-child)::before { content: '/'; color: var(--ink-mute); opacity: 0.6; }
.breadcrumb a { color: var(--ink-soft); text-decoration: none; }
.breadcrumb a:hover { color: var(--accent); }
.breadcrumb [aria-current="page"] { color: var(--ink); }

/* page-header */
.page-header { margin-bottom: 1.4rem; }
.page-header-row { display: flex; align-items: flex-end; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin-top: 0.5rem; }
.page-title { font-size: var(--fs-xl); font-weight: 600; }
/* ชื่อรายการกับป้ายสถานะยืนแถวเดียวกัน · flex-wrap เผื่อชื่อยาวบนจอแคบ */
.page-title-row { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
/* ป้ายมาตรฐานตั้งขนาดไว้สำหรับช่องสถานะในตาราง (12px) ซึ่งเล็กเกินไปเมื่อมายืน
   ข้างหัวเรื่อง 22px — ขยายเฉพาะตำแหน่งนี้ ไม่แตะป้ายในตารางซึ่งทุกแถวใช้อยู่ */
.page-title-row .badge { font-size: var(--fs-base); padding: 0.4rem 0.9rem; }
.page-sub { color: var(--ink-mute); font-size: var(--fs-base); margin-top: 0.3rem; }
/* align-items ต้องมี — ค่าเริ่มต้นของ flex คือ stretch ซึ่งยืดป้ายสถานะให้สูง
   เท่าปุ่มข้าง ๆ แล้วตัวอักษรในป้ายไปเกาะขอบบน เห็นเป็น "ตัวหนังสือลอย" */
.page-header-actions { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }

/* tabs */
.tabs { display: flex; gap: 0.2rem; border-bottom: 1px solid var(--hairline); flex-wrap: wrap; }
.tab { padding: 0.6rem 0.95rem; font-size: var(--fs-base); color: var(--ink-soft); text-decoration: none; border-bottom: 2px solid transparent; margin-bottom: -1px; transition: color 0.2s ease, border-color 0.2s ease; }
.tab:hover { color: var(--ink); }
.tab.is-active { color: var(--accent); border-bottom-color: var(--accent); font-weight: 500; }
.tabs-pills { border-bottom: none; gap: 0.35rem; }
.tabs-pills .tab { border: 1px solid var(--hairline); border-radius: var(--r-pill); margin-bottom: 0; }
.tabs-pills .tab.is-active { background: var(--accent); color: #fff; border-color: var(--accent); }

/* ปุ่มที่สั่งซ่อนต้องหายจริง — .btn ตั้ง display: inline-flex ซึ่งชนะ
   `[hidden] { display: none }` ที่เป็น UA rule ของเบราว์เซอร์ (ปัญหาเดียวกับ
   .cselect-option ที่จดไว้ข้างบน) ไม่ประกาศตรงนี้ปุ่มจะโผล่ทั้งที่สั่งซ่อนแล้ว */
.btn[hidden] { display: none; }

/* นำเข้าทะเบียนลูกค้า — แถบความคืบหน้าและรายการขั้นตอน */
.import-progress { margin-top: 0.75rem; }
.import-progress .progress-fill { transition: width 0.35s ease; }
.import-steps { list-style: none; padding: 0; margin: 0.9rem 0 0; }
.import-steps li {
  padding: 0.28rem 0 0.28rem 1.5rem; position: relative;
  color: var(--ink-mute); font-size: var(--fs-base);
}
.import-steps li::before { content: '○'; position: absolute; left: 0.3rem; }
.import-steps li.is-doing { color: var(--ink); font-weight: 600; }
.import-steps li.is-doing::before { content: '▸'; color: var(--accent); }
.import-steps li.is-done { color: var(--ink-soft); }
.import-steps li.is-done::before { content: '✓'; color: var(--green); }
.import-warn { margin: 0.8rem 0 0; font-size: var(--fs-sm); color: var(--amber); }
.import-result { margin: 0.6rem 0; padding-left: 1.1rem; font-size: var(--fs-base); }
.import-result li { margin: 0.15rem 0; }
.import-result .flag-swatch { width: 14px; height: 14px; border-radius: var(--r-xs); margin-right: 0.3rem; }
.import-note { margin: 0.6rem 0 0; font-size: var(--fs-sm); color: var(--ink-soft); }

/* ช่องเลือกสี — สไตล์ input ทั่วไปของฟอร์มใส่ padding ราว 10px ทำให้ช่องสีเหลือ
   เป็นเส้นบางสูงไม่ถึง 8px มองไม่ออกว่าเป็นสีอะไร ต้องตั้งค่าเองทั้งชุด */
input[type="color"] {
  width: 100%; height: 42px; padding: 4px; cursor: pointer;
  border: 1px solid var(--hairline); border-radius: var(--radius-sm);
  background: var(--glass-2);
}
input[type="color"]:disabled { opacity: 0.4; cursor: not-allowed; }
input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
input[type="color"]::-webkit-color-swatch { border: none; border-radius: var(--r-xs); }

/* ป้ายกำกับลูกค้า — ตัวอย่างสีในหน้าจัดการป้าย */
.flag-swatch {
  display: inline-block; width: 26px; height: 26px; border-radius: var(--r-xs);
  border: 1px solid var(--hairline); vertical-align: middle;
}
.flag-swatch.is-none {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--gray-bg); color: var(--ink-mute); font-size: var(--fs-xs);
}

/* ชิปป้ายในตารางทะเบียนลูกค้า — พื้นสีตามสีจริงในไฟล์ Express
   สีมาจากข้อมูล จึงกำหนดผ่าน style ตรงแถว ไม่ใช่คลาสตายตัวในไฟล์นี้ */
.flag-chip {
  display: inline-block; padding: 0.12rem 0.5rem; margin: 0 0.2rem 0.2rem 0;
  border-radius: var(--r-pill); font-size: var(--fs-xs); line-height: 1.5;
  border: 1px solid var(--hairline); white-space: nowrap;
}
.flag-chip.is-plain { background: var(--gray-bg); color: var(--ink-soft); }

/* ช่องติ๊กป้ายในฟอร์มลูกค้า — คอลัมน์ตายตัวแบบเดียวกับ .perm-grid
   ป้ายมีสิบกว่าอัน ปล่อยให้ไหลตามความยาวชื่อจะได้แถวเบี้ยวไม่เท่ากัน */
/* fieldset ของเบราว์เซอร์มากับกรอบและ padding ในตัว ต้องล้างให้เหมือน .form-group
   ตัวอื่น ๆ ไม่งั้นบล็อกป้ายจะดูเป็นกล่องแปลกปลอมกลางฟอร์ม */
.flag-fieldset { border: 0; padding: 0; margin: 0; }
.flag-fieldset > legend { font-size: var(--fs-sm); color: var(--ink-soft); padding: 0; margin-bottom: 0.3rem; }
.flag-picker { display: grid; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); gap: 0.4rem 1.2rem; }
/* กริดสองคอลัมน์ในตัว label เอง: ช่องติ๊ก | ชิป — ข้อความกำกับลงไปอยู่ใต้ชิป
   ถ้าปล่อยให้อยู่บรรทัดเดียวกัน ป้ายที่มีคำเตือนจะดันชิปจนคอลัมน์ไม่ตรงกัน */
.flag-pick {
  margin-right: 0; cursor: pointer;
  display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 0 0.45rem;
}
.flag-pick .flag-chip { margin: 0; justify-self: start; }
.flag-pick-note { grid-column: 2; color: var(--ink-mute); font-size: var(--fs-2xs); }

/* กล่องผลค้นหาลูกค้าในฟอร์มเปิดงาน — ลอยใต้ช่อง "ชื่อลูกค้า"
   .form-group ที่ครอบอยู่ต้องเป็น position: relative ไม่งั้นกล่องจะไปเกาะขอบหน้า */
.form-group:has(> [data-customer-search]) { position: relative; }
.customer-suggest {
  position: absolute; z-index: 60; top: 100%; left: 0; right: 0; margin: 4px 0 0;
  max-height: 17rem; overflow-y: auto; padding: 0.3rem; list-style: none;
  background: var(--glass-2); backdrop-filter: var(--blur);
  border: 1px solid var(--glass-line); border-radius: var(--radius-sm); box-shadow: var(--shadow-lg);
}
.customer-suggest[hidden] { display: none; }
.customer-suggest li {
  padding: 0.5rem 0.65rem; border-radius: var(--r-sm); font-size: var(--fs-base);
  color: var(--ink-soft); cursor: pointer;
}
.customer-suggest li:hover { background: rgba(0, 0, 0, 0.05); color: var(--ink); }

/* dropdown-menu */
.dropdown { position: relative; display: inline-block; }
.dropdown-caret { transition: transform 0.2s ease; }
.dropdown.is-open .dropdown-caret { transform: rotate(180deg); }
.dropdown-menu {
  position: absolute; z-index: 60; top: calc(100% + 6px); left: 0; min-width: 190px;
  padding: 0.32rem; background: var(--glass-2); backdrop-filter: var(--blur);
  border: 1px solid var(--glass-line); border-radius: var(--radius-sm); box-shadow: var(--shadow-lg);
  opacity: 0; visibility: hidden; transform: translateY(-4px); pointer-events: none;
  transition: opacity 0.16s ease, transform 0.16s ease, visibility 0.16s;
}
.dropdown-menu-right { left: auto; right: 0; }
.dropdown.is-open .dropdown-menu { opacity: 1; visibility: visible; transform: none; pointer-events: auto; }
.dropdown-item { display: block; padding: 0.5rem 0.65rem; border-radius: var(--r-sm); font-size: var(--fs-base); color: var(--ink-soft); text-decoration: none; white-space: nowrap; }
.dropdown-item:hover { background: rgba(0, 0, 0, 0.05); color: var(--ink); }
.dropdown-item.is-danger { color: var(--red); }
.dropdown-item.is-danger:hover { background: var(--red-bg); }
.dropdown-sep { height: 1px; background: var(--hairline); margin: 0.3rem 0.1rem; }

/* card body / footer (card-head มีอยู่แล้ว) */
.card-head-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.card-body { color: var(--ink-soft); font-size: var(--fs-base); }
.card-foot { margin-top: 1rem; padding-top: 0.9rem; border-top: 1px solid var(--hairline); display: flex; gap: 0.6rem; justify-content: flex-end; flex-wrap: wrap; }

/* divider */
.divider { border: none; border-top: 1px solid var(--hairline); margin: 1.2rem 0; }
.divider-labelled { display: flex; align-items: center; gap: 0.8rem; color: var(--ink-mute); font-size: var(--fs-xs); }
.divider-labelled::before, .divider-labelled::after { content: ''; flex: 1; border-top: 1px solid var(--hairline); }
.divider-v { display: inline-block; width: 1px; align-self: stretch; min-height: 1em; background: var(--hairline); margin: 0 0.2rem; }

/* empty-state */
.empty-state { text-align: center; padding: 2.6rem 1.5rem; color: var(--ink-mute); }
.empty-state-icon { display: inline-grid; place-items: center; width: 3.2rem; height: 3.2rem; border-radius: 50%; background: var(--gray-bg); color: var(--ink-mute); margin-bottom: 0.9rem; }
.empty-state-title { color: var(--ink); font-weight: 500; }
.empty-state-msg { font-size: var(--fs-base); margin: 0.3rem auto 0; }
.empty-state-action { margin-top: 1.1rem; }

/* tag */
.tag { display: inline-flex; align-items: center; padding: 0.18rem 0.6rem; border-radius: var(--r-xs); font-size: var(--fs-xs); font-weight: 500; background: var(--gray-bg); color: var(--ink-soft); }
.tag-accent { background: var(--blue-bg); color: var(--accent); }
.tag-green { background: var(--green-bg); color: var(--green); }
.tag-amber { background: var(--amber-bg); color: var(--amber); }
.tag-red { background: var(--red-bg); color: var(--red); }

/* chip */
.chip { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.24rem 0.35rem 0.24rem 0.7rem; border-radius: var(--r-pill); font-size: var(--fs-xs); background: var(--gray-bg); color: var(--ink); }
.chip-remove { all: unset; cursor: pointer; width: 1.15rem; height: 1.15rem; display: grid; place-items: center; border-radius: 50%; color: var(--ink-mute); line-height: 1; }
.chip-remove:hover { background: var(--red); color: #fff; }

/* kbd */
.kbd-group { display: inline-flex; align-items: center; gap: 0.25rem; }
.kbd { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--fs-xs); padding: 0.1rem 0.4rem; border: 1px solid var(--hairline); border-bottom-width: 2px; border-radius: var(--r-xs); background: rgba(255, 255, 255, 0.7); color: var(--ink-soft); }
.kbd-plus { color: var(--ink-mute); font-size: var(--fs-2xs); }

/* status-indicator */
.status-ind { display: inline-flex; align-items: center; gap: 0.45rem; font-size: var(--fs-sm); color: var(--ink-soft); }
.status-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ink-mute); flex-shrink: 0; }
.status-green .status-dot { background: var(--green); }
.status-red .status-dot { background: var(--red); }
.status-amber .status-dot { background: var(--amber); }
.status-dot.is-pulse { box-shadow: 0 0 0 0 currentColor; animation: statusPulse 1.6s ease-out infinite; }
.status-green .status-dot.is-pulse { color: var(--green); }
.status-red .status-dot.is-pulse { color: var(--red); }
@keyframes statusPulse { 0% { box-shadow: 0 0 0 0 rgba(52, 199, 89, 0.5); } 100% { box-shadow: 0 0 0 7px transparent; } }

/* progress-bar */
.progress { display: flex; align-items: center; gap: 0.6rem; }
.progress-track { flex: 1; height: 7px; border-radius: var(--r-pill); background: rgba(0, 0, 0, 0.08); overflow: hidden; }
.progress-fill { display: block; height: 100%; border-radius: inherit; background: var(--accent); transition: width 0.3s ease; }
.progress-green .progress-fill { background: var(--green); }
.progress-amber .progress-fill { background: var(--amber); }
.progress-red .progress-fill { background: var(--red); }
.progress-pct { font-size: var(--fs-xs); color: var(--ink-mute); min-width: 2.4rem; text-align: right; }

/* tooltip (CSS ล้วน) */
.tooltip { position: relative; display: inline-flex; cursor: help; }
.tooltip-mark { width: 1.15rem; height: 1.15rem; display: grid; place-items: center; border-radius: 50%; background: var(--gray-bg); color: var(--ink-mute); font-size: var(--fs-2xs); font-weight: 600; }
.tooltip::after {
  content: attr(data-tooltip);
  position: absolute; bottom: calc(100% + 7px); left: 50%; transform: translateX(-50%) translateY(4px);
  background: var(--ink); color: #fff; font-size: var(--fs-xs); line-height: 1.4; white-space: nowrap;
  padding: 0.35rem 0.6rem; border-radius: var(--r-xs); box-shadow: var(--shadow);
  opacity: 0; pointer-events: none; transition: opacity 0.16s ease, transform 0.16s ease; z-index: 70;
}
.tooltip:hover::after, .tooltip:focus-visible::after { opacity: 1; transform: translateX(-50%) translateY(0); }
.tooltip-bottom::after { bottom: auto; top: calc(100% + 7px); transform: translateX(-50%) translateY(-4px); }
.tooltip-bottom:hover::after, .tooltip-bottom:focus-visible::after { transform: translateX(-50%) translateY(0); }

/* form-group / help / required */
.form-group { min-width: 0; }
.form-group .req { color: var(--red); }
.form-help { display: block; font-size: var(--fs-xs); color: var(--ink-mute); margin-top: 0.3rem; }
/* คำเตือนในฟอร์ม — ใช้ --amber ตัวเดียวกับ badge/toast ไม่ใช่สีของความผิดพลาด
   เพราะบันทึกได้อยู่ · [hidden] แพ้ display ที่มาจาก class ต้องเขียนคู่กันเสมอ */
.form-warn { color: var(--amber); font-weight: 600; }
.form-warn[hidden] { display: none; }

/* reset checkbox/radio ไม่ให้รับสไตล์ base input (กันอาการกระพริบ/ขนาดเด้งตอนติ๊ก) */
input[type="checkbox"], input[type="radio"] {
  width: auto;
  margin: 0;
  padding: 0;
  border: none;
  border-radius: 0;
  background: none;
  box-shadow: none;
  transition: none;
  accent-color: var(--accent);
  flex-shrink: 0;
}
input[type="checkbox"]:focus, input[type="radio"]:focus { box-shadow: none; }

/* checkbox / radio line */
.check-line { display: inline-flex; align-items: center; gap: 0.5rem; font-size: var(--fs-base); color: var(--ink-soft); cursor: pointer; }
.check-line input { accent-color: var(--accent); }
.radio-group { display: grid; gap: 0.5rem; }
.radio-group-label { font-size: var(--fs-sm); color: var(--ink-soft); }

/* switch */
.switch { display: inline-flex; align-items: center; gap: 0.6rem; cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch-track { position: relative; width: 40px; height: 23px; border-radius: var(--r-pill); background: rgba(0, 0, 0, 0.18); transition: background-color 0.2s ease; flex-shrink: 0; }
.switch-thumb { position: absolute; top: 2px; left: 2px; width: 19px; height: 19px; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25); transition: transform 0.2s ease; }
.switch input:checked + .switch-track { background: var(--accent); }
.switch input:checked + .switch-track .switch-thumb { transform: translateX(17px); }
.switch input:focus-visible + .switch-track { box-shadow: 0 0 0 3px rgba(0, 113, 227, 0.22); }
.switch-label { font-size: var(--fs-base); color: var(--ink-soft); }

/* copy-button */
.copy-btn.is-copied { color: var(--green); border-color: transparent; background: var(--green-bg); }

/* skeleton */
.skeleton { position: relative; overflow: hidden; background: rgba(0, 0, 0, 0.07); border-radius: var(--r-xs); display: block; }
.skeleton::after { content: ''; position: absolute; inset: 0; transform: translateX(-100%); background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.55), transparent); animation: shimmer 1.4s infinite; }
.skeleton-lines { display: grid; gap: 0.55rem; }
.skeleton-line { height: 0.8rem; }
.skeleton-thumb { height: 120px; border-radius: var(--radius-sm); margin-bottom: 0.6rem; }
.skeleton-avatar { width: 40px; height: 40px; border-radius: 50%; }
.skeleton-row { display: flex; align-items: center; gap: 0.7rem; }
.skeleton-card { display: block; }
@keyframes shimmer { 100% { transform: translateX(100%); } }

/* ── VAM Workflow: หน้างาน (jobs) ─────────────────────────────── */
.filter-bar { justify-content: flex-start; }
.filter-bar .form-group { min-width: 170px; margin: 0; }

.job-gallery { display: flex; flex-wrap: wrap; gap: 0.7rem; }
.job-gallery .thumb { width: 96px; height: 96px; object-fit: cover; border-radius: var(--radius-sm); }
.job-gallery-sm .thumb { width: 64px; height: 64px; }
.job-thumb { display: inline-block; line-height: 0; border-radius: var(--radius-sm); overflow: hidden; border: 1px solid var(--hairline); transition: transform 0.15s ease, box-shadow 0.15s ease; }
.job-thumb:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
.job-thumb-pick { display: inline-flex; flex-direction: column; gap: 0.4rem; align-items: center; }
.job-thumb-pick .check-row { font-size: var(--fs-xs); }

/* โลโก้บริษัทบนหน้าจัดการ — โลโก้จริงมีสัดส่วนไม่เท่ากัน จำกัดแค่ความสูง
   แล้วปล่อยความกว้างตามรูป ไม่งั้นโลโก้แนวนอนจะถูกบีบจนอ่านไม่ออก */
.company-logo-thumb { max-height: 34px; max-width: 120px; object-fit: contain; vertical-align: middle; }

/* ป้ายแทนรูปที่ไฟล์หายไปแล้ว (ผู้บุกรุกลบไฟล์ทั้งเซิร์ฟเวอร์ 2026-08-05)
   ห้ามพึ่งสีอย่างเดียว — ใบขออนุมัติถูกพิมพ์ขาวดำ เส้นประ ไอคอน และข้อความ
   ต้องบอกได้ครบด้วยตัวเอง */
.missing-image {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  border: 1px dashed var(--hairline);
  border-radius: var(--radius-sm);
  background: var(--glass-2);
  color: var(--muted);
  text-align: center;
  line-height: 1.25;
  box-sizing: border-box;
}
.missing-image svg { opacity: 0.65; }
.missing-image span { font-size: var(--fs-2xs); }
.missing-image--tile { width: 96px; height: 96px; padding: 0.4rem; }
.job-gallery-sm .missing-image--tile { width: 64px; height: 64px; }
.job-gallery-sm .missing-image--tile span { font-size: var(--fs-2xs); }
.job-gallery-sm .missing-image--tile svg { width: 18px; height: 18px; }
.missing-image--inline {
  flex-direction: row;
  gap: 0.4rem;
  padding: 0.3rem 0.6rem;
  min-height: 34px;
}
.missing-image--inline span { font-size: var(--fs-xs); }

.job-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 1rem; align-items: start; }
.job-action { border: 1px solid var(--hairline); border-radius: var(--radius-sm); padding: 0.9rem; background: var(--glass-2); }
/* หัวข้อประจำใบ — เดิมรู้ว่าใบไหนคือใบไหนได้จากข้อความบนปุ่มล่างสุดเท่านั้น */
.job-action-title {
  font-size: var(--fs-md);
  margin: -0.1rem 0 0.75rem;
  padding-bottom: 0.55rem;
  border-bottom: 1px solid var(--hairline);
}
.job-action .form-actions { margin-top: 0.8rem; }
.job-action .filedrop { margin-top: 0.4rem; }

.job-timeline { list-style: none; margin: 0; padding: 0; position: relative; }
.job-timeline::before { content: ""; position: absolute; left: 7px; top: 6px; bottom: 6px; width: 2px; background: var(--hairline); }
.job-timeline-item { position: relative; padding: 0 0 1.1rem 1.7rem; }
.job-timeline-item:last-child { padding-bottom: 0; }
.job-timeline-item::before { content: ""; position: absolute; left: 0; top: 5px; width: 12px; height: 12px; border-radius: 50%; background: var(--accent); border: 2px solid var(--bg); box-shadow: 0 0 0 1px var(--hairline); }
.job-timeline-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.job-timeline-meta { font-size: var(--fs-sm); color: var(--ink-soft, #777); margin-top: 0.15rem; }
.job-timeline-comment { margin: 0.35rem 0 0; padding: 0.5rem 0.7rem; background: var(--glass-2); border-radius: var(--radius-sm); border: 1px solid var(--hairline); }
.job-timeline .job-gallery { margin-top: 0.5rem; }
/* รายการที่เจ้าของลบแล้ว — จางลงและจุดบนเส้นเวลาเป็นสีกลาง เพื่อให้กวาดตาแล้ว
   ข้ามได้ แต่ยังเห็นว่าตรงนี้เคยมีอะไรอยู่ ลำดับเหตุการณ์จึงไม่ขาดตอน */
.job-timeline-item.is-removed { opacity: 0.62; }
.job-timeline-item.is-removed::before { background: var(--ink-mute); }
.job-timeline-item.is-removed .job-timeline-head strong { font-weight: 500; font-style: italic; }
.job-timeline-actions { margin-top: 0.5rem; }
/* ฟอร์มแก้ไขและประวัติการแก้ไข — พับด้วย details/summary ไม่ใช้ JS */
.job-timeline-edit, .job-timeline-edits { margin-top: 0.5rem; font-size: var(--fs-sm); }
.job-timeline-edit > summary, .job-timeline-edits > summary { cursor: pointer; color: var(--ink-mute); width: fit-content; }
.job-timeline-edit > summary:hover, .job-timeline-edits > summary:hover { color: var(--ink); }
.job-timeline-edit textarea { margin-top: 0.5rem; width: 100%; }
.job-timeline-edit .form-actions { margin-top: 0.6rem; }
.job-edit-history { list-style: none; margin: 0.5rem 0 0; padding: 0; display: grid; gap: 0.5rem; }
.job-edit-history > li { padding-left: 0.8rem; border-left: 2px solid var(--hairline); }
.job-edit-history p { margin: 0.15rem 0 0; white-space: pre-wrap; }

/* ── VAM Workflow: แจ้งเตือน + dashboard ─────────────────────── */
/* แถบเตือนว่าหน้านี้ทำรายการต่อไม่ได้แล้ว — ค้างบนสุดจนกว่าจะโหลดใหม่ */
.stale-banner { position: fixed; inset: 0 0 auto 0; z-index: 9999; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 0.75rem; padding: 0.7rem 1rem; background: var(--red, #c0392b); color: #fff; font-weight: 600; text-align: center; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25); }
.stale-banner .btn { background: #fff; color: var(--red, #c0392b); border-color: #fff; }

/* จุดแดงหน้ารหัสงาน — ถูกเรียนถึงแล้วยังไม่ได้เปิดดู · คู่กับ .sr-only เสมอ */
.row-dot { display: inline-block; width: 0.5rem; height: 0.5rem; margin-right: 0.4rem; vertical-align: 0.05rem; background: var(--red, #c0392b); border-radius: 50%; }
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }

.nav-badge { margin-left: auto; background: var(--red, #c0392b); color: #fff; font-size: var(--fs-2xs); font-weight: 600; padding: 0.1rem 0.45rem; border-radius: var(--r-pill); line-height: 1.4; }

.notif-list { list-style: none; margin: 0; padding: 0; }
.notif-item { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; padding: 0.7rem 0.8rem; border-bottom: 1px solid var(--hairline); border-radius: var(--radius-sm); }
.notif-item:last-child { border-bottom: none; }
.notif-item.is-unread { background: var(--glass-2); font-weight: 600; }
.notif-item a { text-decoration: none; color: inherit; }
.notif-item a:hover { text-decoration: underline; }
.notif-item small { white-space: nowrap; color: var(--ink-soft, #777); }

.status-summary { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.status-chip { display: inline-flex; align-items: center; gap: 0.45rem; padding: 0.35rem 0.6rem; border: 1px solid var(--hairline); border-radius: var(--r-pill); text-decoration: none; color: inherit; background: var(--glass-2); transition: transform 0.15s ease; }
.status-chip:hover { transform: translateY(-1px); }

/* ── VAM Workflow: admin ─────────────────────────────────────── */
.setup-steps { margin: 0.6rem 0 0.8rem 1.2rem; display: grid; gap: 0.35rem; }

/* ── Signature widget ─────────────────────────────────────────────── */
/* แท็บโหมดเซ็น — ยืมหน้าตาของ .tabs-pills ที่ใช้อยู่ทั่วระบบมาทั้งดุ้น
   เดิมเป็น segmented control พื้นเทาที่ยืดเต็มความกว้างกล่อง (flex: 1 1 0)
   พอฟอร์มใบลากว้างเต็มการ์ด แท็บที่เลือกจึงกลายเป็นแถบสีน้ำเงินยาวทั้งบรรทัด
   ไม่เหมือนอะไรในระบบเลย และไม่ตรงกับกระดานวาดข้างล่างที่กว้างแค่ 480px */
.sig-tabs { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-bottom: 0.6rem; }
.sig-tab {
  padding: 0.45rem 0.95rem;
  border: 1px solid var(--hairline); border-radius: var(--r-pill);
  background: transparent; color: var(--ink-soft);
  cursor: pointer; font: inherit; font-size: var(--fs-base); white-space: nowrap;
  transition: color 0.2s ease, background-color 0.2s ease, border-color 0.2s ease;
}
.sig-tab:hover { color: var(--ink); }
.sig-tab.is-active { background: var(--accent); color: #fff; border-color: var(--accent); font-weight: 500; }
/* กรอบเส้นประหนาเท่า .filedrop — สองกล่องนี้อยู่ติดกันในฟอร์มเดียวกัน */
.sig-canvas { display: block; width: 100%; max-width: 480px; height: auto; border: 1.5px dashed var(--hairline); border-radius: var(--radius-sm); touch-action: none; background: #fff; margin-bottom: 0.4rem; }
/* คำใบ้ใต้กระดานวาด — โทนเดียวกับ .filedrop-text ที่อยู่เหนือมันในฟอร์มเดียวกัน */
.sig-hint { display: block; max-width: 480px; margin: 0.1rem 0 0; font-size: var(--fs-sm); color: var(--ink-soft); }
/* แผงทั้งสองกว้างเท่ากระดานวาด ไม่ยืดเต็มการ์ด — ช่องพิมพ์ข้อความยาวคนละขนาด
   กับกระดานวาดทำให้สลับแท็บแล้วกล่องกระโดด */
.sig-panel { max-width: 480px; }
.sig-panel .form-group { margin: 0; }
.sig-progress { font-size: var(--fs-base); color: var(--ink-mute); margin: 0 0 0.75rem; }
.sig-record { margin-top: 0.4rem; }
.sig-image { max-height: 90px; border: 1px solid var(--hairline); border-radius: var(--r-xs); background: #fff; }
.sig-text { display: inline-block; padding: 0.35rem 0.7rem; border: 1px solid var(--hairline); border-radius: var(--r-xs); font-style: italic; }
.check-inline { display: inline-flex; align-items: center; gap: 0.4rem; margin-right: 1rem; }

/* ── หน้าปักหมุด (spec 2026-08-25) ─────────────────────────────── */
/* หน้าจอเดียวเต็มจอบนมือถือ — ไม่มีเมนู ไม่มีการ์ดซ้อน */
/* align-content ไม่ใช่ place-items — ฟอร์มตั้งชื่อเป็นลูกคนที่สองของกริด
   ถ้าใช้ place-items แถวจะกระจายเต็มความสูงจอ แล้วฟอร์มไปกองอยู่ก้นจอ */
.pin-screen {
  min-height: 100svh; display: grid; align-content: center; justify-items: center;
  gap: 0.5rem; padding: 1.5rem; text-align: center;
}
.pin-panel { display: grid; justify-items: center; gap: 0.75rem; max-width: 420px; width: 100%; }
/* display จาก class ชนะ `[hidden] { display: none }` ที่เป็น UA rule ของเบราว์เซอร์
   (กับดักเดียวกับ .btn[hidden] และ .modal[hidden]) — ไม่ใส่บรรทัดนี้ สี่สถานะ
   จะขึ้นพร้อมกันทั้งหมดตั้งแต่วินาทีแรก */
.pin-panel[hidden], .pin-name[hidden] { display: none; }
.pin-head { margin: 0; font-size: clamp(1.15rem, 5vw, 1.5rem); }
.pin-sub { margin: 0; color: var(--ink-soft); font-size: var(--fs-sm); }
.pin-time { margin: 0; font-size: clamp(2rem, 12vw, 3rem); font-weight: 600; line-height: 1; }

/* หมุดเต้น + วงกระเพื่อมสองชั้น */
.pin-pulse { position: relative; width: 96px; height: 96px; display: grid; place-items: center; }
.pin-pulse span { position: absolute; inset: 0; border-radius: 50%; background: var(--accent); opacity: 0.18; animation: pin-ripple 2s ease-out infinite; }
.pin-pulse span:nth-child(2) { animation-delay: 1s; }
.pin-pulse b { width: 22px; height: 22px; border-radius: 50%; background: var(--accent); animation: pin-beat 2s ease-in-out infinite; }
@keyframes pin-ripple { from { transform: scale(0.35); opacity: 0.32; } to { transform: scale(1); opacity: 0; } }
@keyframes pin-beat { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.18); } }

/* ติ๊กถูก — วงโตขึ้นก่อน แล้วเส้นวิ่งตาม */
.pin-check { width: 96px; height: 96px; }
.pin-check-ring { fill: none; stroke: #1a9e5f; stroke-width: 4; transform-origin: center; animation: pin-grow 0.35s ease-out both; }
.pin-check-mark {
  fill: none; stroke: #1a9e5f; stroke-width: 6; stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 56; stroke-dashoffset: 56; animation: pin-draw 0.4s 0.3s ease-out forwards;
}
@keyframes pin-grow { from { transform: scale(0.5); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes pin-draw { to { stroke-dashoffset: 0; } }

/* สถานะ "บันทึกไว้แล้ว" ต้องดูต่างจาก "เพิ่งบันทึก" ให้ชัด ไม่งั้นผู้ใช้จะคิดว่าปักซ้ำ */
.pin-check-known .pin-check-ring,
.pin-check-known .pin-check-mark { stroke: var(--accent); animation: none; stroke-dashoffset: 0; }

.pin-warn { color: #b7791f; }
.pin-manual { margin-top: 0.5rem; min-height: 48px; padding-inline: 2rem; }
.pin-name { display: grid; gap: 0.5rem; width: 100%; max-width: 420px; margin-top: 1.25rem; text-align: left; }
/* กล่องครอบช่องชื่อต้องเป็น relative เพราะ .customer-suggest วางตัวแบบ absolute */
.pin-name-field { position: relative; }
.pin-nag { color: #b7791f; }

/* ฟอร์มปุ่มเดียวในแถบหัวหน้า — ต้องไม่ดันปุ่มอื่นขึ้นบรรทัดใหม่
   form เป็น block ตามค่าเริ่มต้น ปุ่มลบจึงตกไปอยู่คนละบรรทัดกับปุ่มพิมพ์/แก้ไข */
.header-inline-form { display: inline-block; margin: 0; }

/* ── รายการหมุดย้อนหลัง (หน้า /pin/list) ────────────────────────
   หน้านี้ใช้ตารางแบบเดียวกับหน้ารายการอื่นทั้งหมด จึงเหลือแค่สองคลาสนี้
   ที่ตารางมาตรฐานไม่มีให้ — เคยมี .pin-log-* อีกชุดเต็มตอนที่หน้านี้ยังเป็น <ul>
   ของตัวเอง ถอดออกแล้วเพราะไม่มีอะไรใช้ */
.pin-log-coords { font-variant-numeric: tabular-nums; color: var(--ink-mute); }
.pin-log-unnamed { color: var(--ink-mute); font-style: italic; }

/* รายการหมุดในฟอร์มใบเซล */
.pin-list { list-style: none; margin: 0.5rem 0 0; padding: 0; display: grid; gap: 0.4rem; }
.pin-item {
  display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
  padding: 0.6rem 0.75rem; border: 1px solid var(--hairline); border-radius: var(--radius-sm); background: var(--glass-2);
}
.pin-item-main { display: grid; min-width: 0; text-align: left; }
.pin-item-main small { color: var(--ink-soft); font-size: var(--fs-xs); }

/* ── การ์ดสิทธิ์บนเครื่องนี้ (หน้าโปรไฟล์) ────────────────────── */
.perm-intro { margin: 0 0 0.9rem; font-size: var(--fs-sm); color: var(--ink-soft); line-height: 1.5; }
.perm-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
.perm-row {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem;
  padding: 0.75rem 0.9rem; border: 1px solid var(--hairline);
  border-radius: var(--radius-sm); background: var(--glass-2);
}
.perm-main { display: grid; gap: 0.15rem; min-width: 0; }
.perm-main small { color: var(--ink-soft); font-size: var(--fs-xs); line-height: 1.45; }
.perm-hint { color: #b7791f; }
/* display จาก class ชนะ `[hidden] { display: none }` ที่เป็น UA rule
   (กับดักเดียวกับ .btn[hidden] และ .modal[hidden]) */
.perm-hint[hidden] { display: none; }
.perm-side { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; }

@media (max-width: 640px) {
  .perm-row { flex-direction: column; align-items: stretch; }
  .perm-side { justify-content: space-between; }
}

/* ── Dark theme ───────────────────────────────────────────────── */
:root[data-theme="dark"] {
  --bg: #0c0e12;
  --ink: #f2f3f5;
  --ink-soft: #b9bcc2;
  --ink-mute: #7f838c;
  --accent: #0a84ff;
  --accent-hover: #409cff;
  --accent-press: #0071e3;
  --green: #30d158;
  --green-bg: rgba(48, 209, 88, 0.18);
  --amber: #ffd60a;
  --amber-bg: rgba(255, 214, 10, 0.16);
  --blue: #64d2ff;
  --blue-bg: rgba(100, 210, 255, 0.16);
  --red: #ff453a;
  --red-bg: rgba(255, 69, 58, 0.18);
  --gray-bg: rgba(255, 255, 255, 0.08);
  --glass: rgba(28, 30, 36, 0.6);
  --glass-2: rgba(30, 32, 39, 0.74);
  --glass-line: rgba(255, 255, 255, 0.08);
  --hairline: rgba(255, 255, 255, 0.12);
  --shadow: 0 6px 24px rgba(0, 0, 0, 0.4);
  --shadow-lg: 0 20px 60px rgba(0, 0, 0, 0.55);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    /* ทำซ้ำค่าเดียวกับ [data-theme="dark"] เพื่อให้ระบบมืดเป็นค่าเริ่มต้นเมื่อยังไม่เลือกเอง */
    --bg: #0c0e12; --ink: #f2f3f5; --ink-soft: #b9bcc2; --ink-mute: #7f838c;
    --accent: #0a84ff; --accent-hover: #409cff; --accent-press: #0071e3;
    --green: #30d158; --green-bg: rgba(48,209,88,0.18);
    --amber: #ffd60a; --amber-bg: rgba(255,214,10,0.16);
    --blue: #64d2ff; --blue-bg: rgba(100,210,255,0.16);
    --red: #ff453a; --red-bg: rgba(255,69,58,0.18);
    --gray-bg: rgba(255,255,255,0.08);
    --glass: rgba(28,30,36,0.6); --glass-2: rgba(30,32,39,0.74);
    --glass-line: rgba(255,255,255,0.08); --hairline: rgba(255,255,255,0.12);
    --shadow: 0 6px 24px rgba(0,0,0,0.4); --shadow-lg: 0 20px 60px rgba(0,0,0,0.55);
  }
}
/* ปุ่มสลับธีมในแถบบน */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--control-h-bar); height: var(--control-h-bar);
  border-radius: var(--r-pill); cursor: pointer;
  border: 1px solid var(--hairline); background: var(--glass); color: var(--ink);
  font-size: var(--fs-base);
  -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
}
.theme-toggle:hover { background: var(--glass-2); }

/* ── Dark theme: แก้สีที่ฮาร์ดโค้ดไว้สำหรับพื้นสว่าง ให้เข้ากับพื้นมืด ──────
   surface (การ์ด/อินพุต/เมนู/พื้นต่าง ๆ) ที่เดิมใช้ขาวทึบ → ใช้กระจกมืดแทน
   แถบเลื่อน (scrollbar) และ track ต่าง ๆ ที่เดิมใช้ดำ → ใช้ขาวโปร่งบาง ๆ */
:root[data-theme="dark"] .card,
:root[data-theme="dark"] .category,
:root[data-theme="dark"] .product-card,
:root[data-theme="dark"] .subscribe-panel,
:root[data-theme="dark"] .auth-card { background: var(--glass-2); }
:root[data-theme="dark"] .alert { background: var(--glass); }
:root[data-theme="dark"] input,
:root[data-theme="dark"] textarea,
:root[data-theme="dark"] select,
:root[data-theme="dark"] .cselect-trigger,
:root[data-theme="dark"] .kbd,
:root[data-theme="dark"] .filedrop { background: rgba(255, 255, 255, 0.06); }
:root[data-theme="dark"] .filedrop:hover { background: rgba(255, 255, 255, 0.1); }
:root[data-theme="dark"] .filedrop-item { background: rgba(255, 255, 255, 0.06); }
:root[data-theme="dark"] .btn-ghost,
:root[data-theme="dark"] .btn-soft { background: rgba(255, 255, 255, 0.08); }
:root[data-theme="dark"] .btn-soft:hover { background: rgba(255, 255, 255, 0.14); }
:root[data-theme="dark"] .btn-ghost:hover,
:root[data-theme="dark"] select:hover,
:root[data-theme="dark"] .cselect-trigger:hover,
:root[data-theme="dark"] .filedrop:hover { border-color: rgba(255, 255, 255, 0.24); }
:root[data-theme="dark"] .user-dropdown { background: rgba(28, 30, 36, 0.98); }
:root[data-theme="dark"] .section-alt::before { background: rgba(255, 255, 255, 0.03); }
:root[data-theme="dark"] .product-tag { background: rgba(0, 0, 0, 0.55); }
:root[data-theme="dark"] .switch-track,
:root[data-theme="dark"] .progress-track,
:root[data-theme="dark"] .meter { background: rgba(255, 255, 255, 0.14); }
:root[data-theme="dark"] .skeleton { background: rgba(255, 255, 255, 0.06); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .card,
  :root:not([data-theme="light"]) .category,
  :root:not([data-theme="light"]) .product-card,
  :root:not([data-theme="light"]) .subscribe-panel,
  :root:not([data-theme="light"]) .auth-card { background: var(--glass-2); }
  :root:not([data-theme="light"]) .alert { background: var(--glass); }
  :root:not([data-theme="light"]) input,
  :root:not([data-theme="light"]) textarea,
  :root:not([data-theme="light"]) select,
  :root:not([data-theme="light"]) .cselect-trigger,
  :root:not([data-theme="light"]) .kbd,
  :root:not([data-theme="light"]) .filedrop { background: rgba(255, 255, 255, 0.06); }
  :root:not([data-theme="light"]) .filedrop:hover { background: rgba(255, 255, 255, 0.1); }
  :root:not([data-theme="light"]) .filedrop-item { background: rgba(255, 255, 255, 0.06); }
  :root:not([data-theme="light"]) .btn-ghost,
  :root:not([data-theme="light"]) .btn-soft { background: rgba(255, 255, 255, 0.08); }
  :root:not([data-theme="light"]) .btn-soft:hover { background: rgba(255, 255, 255, 0.14); }
  :root:not([data-theme="light"]) .btn-ghost:hover,
  :root:not([data-theme="light"]) select:hover,
  :root:not([data-theme="light"]) .cselect-trigger:hover,
  :root:not([data-theme="light"]) .filedrop:hover { border-color: rgba(255, 255, 255, 0.24); }
  :root:not([data-theme="light"]) .user-dropdown { background: rgba(28, 30, 36, 0.98); }
  :root:not([data-theme="light"]) .section-alt::before { background: rgba(255, 255, 255, 0.03); }
  :root:not([data-theme="light"]) .product-tag { background: rgba(0, 0, 0, 0.55); }
  :root:not([data-theme="light"]) .switch-track,
  :root:not([data-theme="light"]) .progress-track,
  :root:not([data-theme="light"]) .meter { background: rgba(255, 255, 255, 0.14); }
  :root:not([data-theme="light"]) .skeleton { background: rgba(255, 255, 255, 0.06); }
}

/* ── Native color-scheme ให้ date picker / scrollbar / select ปรับตามธีม ── */
:root { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { color-scheme: dark; } }

/* ── List pager / date range (client-side lists) ─────────────────── */
/* ── Custom date picker ───────────────────────────────────────────── */
.datepicker { display: inline-flex; align-items: center; gap: 0.4rem; }
.datepicker-lead { font-size: var(--fs-base); color: var(--ink-soft); }
.datepicker-trigger.datepicker-trigger { width: auto; min-width: 148px; gap: 0.6rem; padding: 0.45rem 0.7rem; font-size: var(--fs-base); }
.datepicker-ic { flex-shrink: 0; display: inline-flex; color: var(--ink-mute); }
.datepicker-text { white-space: nowrap; }

/* ในฟอร์มที่เรียงเป็นกริด (ส่ง prop 'field' มา) ปฏิทินต้องกว้างเท่าช่องอื่นในแถว
   ไม่ใช่หดตามข้อความแบบตอนอยู่บนแถบกรอง — ไม่งั้นแถวเดียวกันขอบขวาไม่ตรงกัน */
.form-group > .datepicker { display: flex; width: 100%; }
.form-group > .datepicker .datepicker-trigger.datepicker-trigger {
  width: 100%;
  justify-content: space-between;
  padding: 0.6rem 0.75rem;
  font-size: var(--fs-base);
}
.datepop {
  position: fixed; z-index: 250; width: 17rem; max-width: calc(100vw - 16px); padding: 0.7rem;
  background: var(--glass-2); -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  border: 1px solid var(--glass-line); border-radius: var(--radius-sm); box-shadow: var(--shadow-lg);
  opacity: 0; visibility: hidden; transform: translateY(-4px); pointer-events: none;
  transition: opacity 0.16s ease, transform 0.16s ease, visibility 0.16s;
}
.datepop.is-shown { opacity: 1; visibility: visible; transform: none; pointer-events: auto; }
.datepop-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.5rem; }
.datepop-title { font-weight: 600; font-size: var(--fs-base); color: var(--ink); }
.datepop-nav { all: unset; cursor: pointer; width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center; border-radius: var(--r-xs); color: var(--ink-soft); font-size: var(--fs-lg); }
.datepop-nav:hover { background: var(--gray-bg); color: var(--ink); }
.datepop-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.datepop-dow { text-align: center; font-size: var(--fs-2xs); color: var(--ink-mute); padding: 0.2rem 0; }
.datepop-empty { aspect-ratio: 1; }
.datepop-day { all: unset; cursor: pointer; aspect-ratio: 1; display: flex; align-items: center; justify-content: center; border-radius: var(--r-xs); font-size: var(--fs-sm); color: var(--ink); }
.datepop-day:hover { background: var(--gray-bg); }
.datepop-day.is-today { box-shadow: inset 0 0 0 1px var(--accent); }
.datepop-day.is-selected { background: var(--accent); color: #fff; }
.datepop-day.is-disabled { opacity: 0.3; cursor: default; pointer-events: none; }
.list-pager { display: flex; align-items: center; gap: 1rem; justify-content: flex-end; flex-wrap: wrap; padding-top: 0.9rem; }
.pager-info { color: var(--ink-mute); font-size: var(--fs-base); margin-right: auto; }
.pager-size { display: inline-flex; align-items: center; gap: 0.4rem; color: var(--ink-soft); font-size: var(--fs-base); }
.pager-size select { padding: 0.35rem 0.5rem; border-radius: var(--r-xs); border: 1px solid var(--hairline); background: var(--glass); color: var(--ink); }
.pager-nav { display: inline-flex; gap: 0.4rem; }

/* จัดตัวกรอง client-side ให้อยู่บรรทัดเดียว ไม่กว้างเต็มแถว */
[data-list] .filter-bar { align-items: center; }
.list-search { flex: 1 1 240px; min-width: 200px; }
.list-search input[type="search"] { width: 100%; border-radius: var(--radius-sm); }
.filter-bar .form-group { min-width: 168px; }
.daterange-bar { display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem 0.8rem; margin-top: 0.85rem; padding-top: 0.85rem; border-top: 1px solid var(--hairline); }
.daterange-label { font-size: var(--fs-sm); color: var(--ink-soft); font-weight: 500; }

/* pagesize ใน pager เป็น cselect ให้เหมือน select อื่น ๆ */
.pager-size .cselect { width: auto; }
.pager-size .cselect-trigger { padding: 0.3rem 0.55rem; font-size: var(--fs-xs); min-width: 58px; }

/* การ์ดที่อยู่ใน data-list ให้เว้นระยะเท่ากับ layout (.app-content) */
[data-list] { display: grid; gap: 1.3rem; align-content: start; }

/* ── ส่วนเชื่อมต่อ LINE ในหน้าโปรไฟล์ ─────────────────────────────── */
.line-status { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.line-note { color: var(--ink-mute); font-size: var(--fs-base); margin-top: 0.5rem; }
.line-steps { margin: 0.6rem 0 0.2rem 1.2rem; display: grid; gap: 0.55rem; }
.line-cmd-row { display: inline-flex; align-items: center; gap: 0.4rem; margin-left: 0.3rem; flex-wrap: wrap; }
.line-cmd { padding: 0.25rem 0.6rem; border-radius: var(--r-xs); border: 1px solid var(--hairline); background: var(--gray-bg); font-family: ui-monospace, monospace; font-size: var(--fs-base); color: var(--ink); }

/* ── ฟอร์มที่ล็อกอ่านอย่างเดียวจนกว่าจะกด "แก้ไข" ──────────────────── */
.is-locked { background: var(--gray-bg); color: var(--ink-mute); cursor: default; }
.is-locked:focus { outline: none; border-color: var(--hairline); }

/* ── บันทึกกิจกรรม: diff ก่อน → หลัง ในตาราง log ─────────────────── */
.log-changes { margin-top: 0.35rem; font-size: var(--fs-sm); }
.log-changes > summary { cursor: pointer; color: var(--ink-mute); width: fit-content; }
.log-changes > summary:hover { color: var(--ink); }
.log-changes ul { margin: 0.4rem 0 0 0; padding: 0.5rem 0.7rem; list-style: none; display: grid; gap: 0.3rem; border-left: 2px solid var(--hairline); background: var(--gray-bg); border-radius: 0 8px 8px 0; }
.log-changes .log-field { color: var(--ink-mute); }
.log-changes del { color: var(--ink-mute); text-decoration: line-through; }
.log-changes ins { color: var(--ink); text-decoration: none; font-weight: 500; }

/* ============================================================
   ลายเซ็นเต็มจอ (ใช้บนมือถือ/แท็บเล็ต — ปุ่มเปิดถูกซ่อนบนเดสก์ท็อป)
   ============================================================ */

/* ข้อความที่แสดงเฉพาะมือถือ (เช่น ป้ายกำกับปุ่มไอคอนในตาราง) — ดูที่ @media ท้ายไฟล์ */
.only-mobile { display: none; }

.sig-expand { display: none; }
.sig-canvas-wrap { position: relative; max-width: 480px; }
.sig-tools { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.5rem; }

.sig-fs {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  padding: max(0.8rem, env(safe-area-inset-top)) 0.8rem calc(0.8rem + env(safe-area-inset-bottom));
  background: var(--bg);
  opacity: 0;
  transition: opacity 0.2s ease;
}
.sig-fs[hidden] { display: none; }
.sig-fs.is-open { opacity: 1; }
.sig-fs-head { display: flex; align-items: center; justify-content: space-between; gap: 0.8rem; }
.sig-fs-title { font-weight: 600; font-size: var(--fs-md); }
.sig-fs-hint { display: block; font-size: var(--fs-xs); color: var(--ink-mute); }
@media (orientation: landscape) { .sig-fs-hint { display: none; } }
.sig-fs-close {
  all: unset;
  cursor: pointer;
  flex-shrink: 0;
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border-radius: var(--r-pill);
  font-size: var(--fs-xl); line-height: 1;
  color: var(--ink-soft);
}
.sig-fs-close:hover { background: var(--gray-bg); color: var(--ink); }
.sig-fs-stage {
  position: relative;
  flex: 1;
  min-height: 0;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  background: #fff;
  overflow: hidden;
}
.sig-fs-canvas { position: absolute; inset: 0; width: 100%; height: 100%; touch-action: none; }
/* เส้นบรรทัดจาง ๆ ให้เซ็นตรง — เป็น element แยก จึงไม่ติดไปกับภาพที่บันทึก */
.sig-fs-baseline { position: absolute; left: 7%; right: 7%; bottom: 22%; border-bottom: 1px dashed rgba(0, 0, 0, 0.16); pointer-events: none; }
.sig-fs-foot { display: flex; gap: 0.6rem; }
.sig-fs-foot .btn { flex: 1; min-height: 48px; }
body.sig-fs-open { overflow: hidden; }

/* ============================================================
   Responsive — แท็บเล็ต/มือถือ
   ทุก rule ในส่วนนี้อยู่ใน @media (max-width: …) เท่านั้น
   เดสก์ท็อป (>860px) จึงแสดงผลเหมือนเดิมทุกอย่าง
   ============================================================ */

/* ── แท็บเล็ตลงมา (≤860px) — จุดเดียวกับที่ sidebar พับเป็น drawer ── */
@media (max-width: 860px) {
  .app-topbar { padding-top: max(0.85rem, env(safe-area-inset-top)); }
  .app-topbar h1 { font-size: var(--fs-lg); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
  .app-sidebar {
    padding-top: max(1.4rem, env(safe-area-inset-top));
    padding-bottom: max(1.4rem, env(safe-area-inset-bottom));
  }
  .menu-toggle { min-width: 44px; min-height: 44px; place-content: center; justify-items: center; }
  /* จอสัมผัส — เปิดพื้นที่เซ็นเต็มจอได้ */
  .sig-expand { display: inline-flex; }
}

/* ── มือถือ (≤640px) ─────────────────────────────────────────── */
@media (max-width: 640px) {
  html, body { overflow-x: clip; }
  * { -webkit-tap-highlight-color: transparent; }

  /* 16px คือขนาดต่ำสุดที่ iOS Safari ไม่ซูมหน้าจอตอนโฟกัสช่องกรอก */
  input, textarea, select, .cselect-trigger { font-size: 16px; }
  .status-form .cselect-trigger,
  .pagination .per-page .cselect-trigger,
  .pager-size .cselect-trigger { font-size: 16px; padding: 0.5rem 0.7rem; }
  .pager-size select, .pagination .per-page select { font-size: 16px; }

  .btn-sm { min-height: 42px; font-size: var(--fs-sm); padding: 0.5rem 1rem; }
  .btn-icon, .btn-icon.btn-sm { width: 44px; height: 44px; }
  .cselect-option { padding: 0.72rem 0.7rem; font-size: var(--fs-base); }
  .cselect-menu { max-height: 60svh; }
  .pagination a, .pagination span.page-cur { min-width: 42px; height: 42px; }
  .theme-toggle { width: var(--control-h-bar); height: var(--control-h-bar); }
  .sig-tab { min-height: 44px; }
  .modal-close, .toast-close { min-width: 40px; min-height: 40px; }

  .app-content { padding: 1rem; gap: 1rem; }
  .card { padding: 1.1rem 1rem; }
  .card-head { gap: 0.6rem; }
  .page-title { font-size: var(--fs-lg); }
  .page-header-row { align-items: stretch; }
  .page-header-actions { width: 100%; }
  .page-header-actions .btn { flex: 1 1 auto; }

  /* ── ปุ่ม "เพิ่มรายการใหม่" ลอยติดขอบล่างจอตลอด (เอื้อมถึงตลอดรายการยาว ๆ) ── */
  .page-add-action {
    position: fixed;
    left: 1rem;
    right: 1rem;
    bottom: calc(0.9rem + env(safe-area-inset-bottom));
    z-index: 45;
    min-height: 50px;
    font-size: var(--fs-md);
    box-shadow: var(--shadow-lg);
  }
  /* เว้นที่ท้ายหน้าไม่ให้ปุ่มลอยบังเนื้อหาแถวสุดท้าย */
  .app-content:has(.page-add-action) { padding-bottom: calc(3.9rem + env(safe-area-inset-bottom)); }

  /* ── ตาราง → การ์ดต่อแถว ──────────────────────────────────
     ซ่อน thead แล้วดึงชื่อคอลัมน์จาก data-label ของ td มาแสดงแทน */
  .table-wrap { overflow-x: visible; }
  .table-wrap table, .table-wrap tbody, .table-wrap tr, .table-wrap td { display: block; }
  .table-wrap thead { display: none; }
  /* ตัวกรอง/แบ่งหน้าฝั่งหน้าเว็บซ่อนแถวด้วย attribute hidden — ต้องชนะ display: block ข้างบน */
  .table-wrap tbody tr[hidden] { display: none; }

  .table-wrap tbody tr {
    border: 1px solid var(--hairline);
    border-radius: var(--radius-sm);
    background: var(--glass-2);
    padding: 0.85rem 0.9rem;
    margin-bottom: 0.7rem;
  }
  .table-wrap tbody tr:last-child { margin-bottom: 0; }
  .table-wrap tbody tr:hover { background: var(--glass-2); }

  .table-wrap td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.28rem 0;
    border-bottom: none;
    text-align: right;
    min-width: 0;
  }
  .table-wrap td::before {
    content: attr(data-label);
    flex: 0 0 auto;
    text-align: left;
    font-size: var(--fs-xs);
    color: var(--ink-mute);
  }
  .table-wrap td:not([data-label])::before { content: none; }

  /* คอลัมน์แรก = หัวการ์ด (ไม่มีป้ายกำกับ ตัวใหญ่ ชิดซ้าย) */
  .table-wrap td.cell-title {
    display: block;
    text-align: left;
    font-size: var(--fs-md);
    padding: 0 0 0.45rem;
  }
  .table-wrap td.cell-title::before { content: none; }

  /* ค่ายาว ๆ (ชื่องาน / รายละเอียด log) — ป้ายบรรทัดบน ค่าบรรทัดล่าง */
  .table-wrap td.cell-block { display: block; text-align: left; }
  .table-wrap td.cell-block::before { display: block; margin-bottom: 0.1rem; }

  /* แถวปุ่มไปอยู่ล่างสุดของการ์ด กว้างเต็มแถว */
  .table-wrap td.cell-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: 0.5rem;
    margin-top: 0.55rem;
    padding-top: 0.7rem;
    border-top: 1px solid var(--hairline);
    white-space: normal;
  }
  .table-wrap td.cell-actions::before { content: none; }
  /* ฟอร์มครอบปุ่มเดี่ยว — ให้ปุ่มข้างในเข้าไปเรียงใน flex ของ cell ได้เลย */
  .table-wrap td.cell-actions > form { display: contents; }
  .table-wrap td.cell-actions .btn { flex: 1 1 auto; }
  .table-wrap td.cell-actions .btn-icon { width: auto; padding: 0.5rem 1rem; gap: 0.45rem; }

  /* ตารางแบบ "หัวข้อ | ค่า" (ไม่มี thead) — เรียงหัวข้อบน ค่าล่าง ชิดซ้ายทั้งคู่ */
  .table-wrap .kv-table td { display: block; text-align: left; padding: 0; }
  .table-wrap .kv-table td:first-child { padding-bottom: 0.3rem; }
  .table-wrap .kv-table td:last-child { padding-bottom: 0.2rem; }

  /* ป้ายข้อความที่โผล่เฉพาะมือถือ (กำกับปุ่มไอคอนในตาราง) */
  .only-mobile { display: inline; }

  /* ── toolbar / ตัวกรอง / แบ่งหน้า ─────────────────────────
     [data-list] .filter-bar ต้องระบุด้วย ไม่งั้นกฎ align-items: center ของเดิม
     (specificity สูงกว่า) จะชนะ แล้วช่องกรองหดตามเนื้อหาแทนที่จะเต็มแถว */
  .toolbar, .filter-bar, .daterange-bar,
  [data-list] .filter-bar { flex-direction: column; align-items: stretch; gap: 0.6rem; }
  .toolbar .search, .search, .list-search, [data-list] .filter-bar .list-search { max-width: none; width: 100%; flex: 1 1 auto; }
  .filter-bar .form-group, .list-search { min-width: 0; }
  .filter-bar .cselect, .cselect { width: 100%; }
  .daterange-bar .datepicker { width: 100%; justify-content: space-between; gap: 0.6rem; }
  .datepicker-trigger.datepicker-trigger { flex: 1 1 auto; min-width: 0; }
  .datepicker-text { overflow: hidden; text-overflow: ellipsis; }
  .list-pager, .pagination { flex-direction: column; align-items: stretch; gap: 0.7rem; }
  .pager-info, .pagination .page-info { margin-right: 0; text-align: center; }
  .pager-size { justify-content: center; }
  .pager-nav { justify-content: space-between; }
  .pager-nav .btn { flex: 1 1 0; }
  .page-nav { justify-content: center; }

  /* ── ฟอร์ม ─────────────────────────────────────────────── */
  .form-actions { flex-direction: column; align-items: stretch; }
  .form-actions .btn { width: 100%; }
  .card-foot { flex-direction: column-reverse; }
  .card-foot .btn { width: 100%; }
  .filedrop { gap: 0.75rem; padding: 0.9rem; }

  /* ── modal → การ์ดลอยกึ่งกลาง เว้นขอบจอรอบด้าน ──────────────
     วางกึ่งกลางแทนชิดล่าง ไม่งั้นช่องว่างที่เหลือจะไปกองอยู่ด้านบนก้อนเดียว */
  .modal { padding: 0.75rem; place-items: center stretch; }
  .modal-dialog, .modal-dialog.modal-wide {
    --modal-pad-y: 1.4rem;
    --modal-pad-x: 1.15rem;
    width: 100%;
    max-width: none;
    max-height: calc(94svh - env(safe-area-inset-bottom));
    border-radius: var(--r-xl);
    transform: translateY(26px);
  }
  .modal-foot { flex-direction: column-reverse; }
  .modal-foot .btn { width: 100%; }

  .toast-stack { top: max(0.7rem, env(safe-area-inset-top)); left: 0.7rem; right: 0.7rem; width: auto; }

  /* ── หน้าภาพรวม / หน้างาน ───────────────────────────────── */
  .stat-grid { grid-template-columns: repeat(2, 1fr); gap: 0.7rem; }
  .stat .stat-value { font-size: var(--fs-xl); }
  .status-summary { gap: 0.45rem; }
  .status-chip { min-height: 40px; }

  .job-actions { grid-template-columns: 1fr; }
  .job-gallery { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; }
  .job-gallery .job-thumb { display: block; }
  .job-gallery .thumb { width: 100%; height: auto; aspect-ratio: 1; object-fit: cover; }
  .job-timeline-item { padding-left: 1.5rem; }
  .job-timeline-comment { padding: 0.55rem 0.65rem; }

  /* ── ลายเซ็น: พื้นที่วาดสูงขึ้นจากอัตราส่วน 480:180 เป็น 3:2 ── */
  /* แท็บสามใบต้องเรียงพอในแถวเดียวตั้งแต่จอ 320px — ย่อตัวอักษรตามความกว้างจอ
     แล้วให้แต่ละใบแบ่งความกว้างเท่ากัน ไม่งั้นใบสุดท้ายตกบรรทัดเดียวโดด ๆ */
  .sig-tab { flex: 1 1 0; min-width: 0; padding: 0.5rem 0.35rem; font-size: clamp(0.72rem, 3.4vw, 0.88rem); text-align: center; }
  .sig-canvas-wrap { max-width: none; }
  .sig-hint { max-width: none; }
  .sig-panel { max-width: none; }
  .sig-canvas { max-width: none; aspect-ratio: 3 / 2; }
  .sig-tools .btn { flex: 1 1 auto; }
  .sig-image { max-height: 120px; }

  .breadcrumb ol { font-size: var(--fs-xs); }
  .auth-wrap { padding: 3rem 1rem 2rem; }
  .auth-card { padding: 1.9rem 1.3rem; }
}

/* ── มือถือจอเล็ก (≤400px) ───────────────────────────────────── */
@media (max-width: 400px) {
  .stat-grid { grid-template-columns: 1fr; }
  .app-content { padding: 0.85rem; }
  .card { padding: 1rem 0.85rem; }
}

/* ── เครื่องมือจัดการฐานข้อมูล ────────────────────────────────
   ตารางในนี้เป็นข้อมูลดิบจากฐาน จำนวนคอลัมน์และความยาวค่าเดาไม่ได้
   จึงเน้นให้ "อ่านออกและเลื่อนดูได้" มากกว่าให้พอดีจอ */
.db-table { font-size: var(--fs-sm); }
.db-table th { white-space: nowrap; }
.db-table td { vertical-align: top; }

.db-null { color: var(--ink-mute); font-style: italic; }
.db-empty { color: var(--ink-mute); }
.db-masked { color: var(--ink-mute); letter-spacing: 0.12em; }
.db-value { font-variant-numeric: tabular-nums; }

/* ค่ายาว ๆ ตัดท้ายไว้ก่อน กดขยายดูเต็มได้ ไม่งั้นแถวเดียวดันตารางจนอ่านไม่ออก */
.db-long > summary { cursor: pointer; color: var(--ink-soft); }
.db-long[open] > summary { color: var(--ink-mute); margin-bottom: 0.25rem; }
.db-long[open] .db-value { display: block; white-space: pre-wrap; word-break: break-word; max-width: 40rem; }

.db-gate-status { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
  margin-bottom: 1rem; color: var(--ink-soft); font-size: var(--fs-base); }
.db-result-count { color: var(--ink-mute); font-size: var(--fs-sm); margin-bottom: 0.6rem; }

.db-history { list-style: none; display: flex; flex-direction: column; gap: 0.35rem; margin-top: 0.8rem; }
.db-history-item {
  width: 100%; text-align: left; padding: 0.45rem 0.6rem; border-radius: var(--radius-sm);
  border: 1px solid var(--hairline); background: var(--gray-bg); color: var(--ink-soft);
  font-family: ui-monospace, 'SFMono-Regular', Menlo, Consolas, monospace; font-size: var(--fs-sm);
  cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.db-history-item:hover { color: var(--ink); border-color: var(--accent); }

#dbSqlInput { font-family: ui-monospace, 'SFMono-Regular', Menlo, Consolas, monospace; }

/* บนจอที่ตารางยังเป็นตารางอยู่ (ไม่ได้แปลงเป็นการ์ด) ให้เลื่อนแนวนอนแทนการตัดคำ */
@media (min-width: 641px) {
  .db-table-wrap { overflow-x: auto; }
  .db-table td { white-space: nowrap; }
  .db-table td .db-long { white-space: normal; }
}

/* การ์ดสำรองฐานข้อมูล — หนึ่งแถวต่อหนึ่งก้อน แต่ละแถวมีฟอร์มของตัวเอง */
.backup-row {
  display: flex; gap: 1rem; align-items: center; justify-content: space-between;
  flex-wrap: wrap; padding: 0.75rem 0; border-bottom: 1px solid var(--hairline);
}
.backup-row:last-of-type { border-bottom: none; }
.backup-row p { margin: 0.2rem 0 0; }
.backup-row form { margin: 0; }
.backup-row .muted { opacity: 0.65; }

/* ── ช่องตั้งชื่อโฟลเดอร์ปลายทางบน Drive ─────────────────────── */
.drive-folder { margin-top: 1.1rem; padding-top: 1rem; border-top: 1px solid var(--hairline); }
.drive-folder-row { display: flex; gap: 0.6rem; flex-wrap: wrap; align-items: center; margin-top: 0.6rem; }
.drive-folder-row input { flex: 1 1 18rem; min-width: 0; }

/* ── ความคืบหน้าตอนส่งไฟล์สำรอง ─────────────────────────────── */
/* พื้นใช้ var(--glass) ไม่ใช่ขาวตายตัว — ตัวแปรนี้ถูกนิยามใหม่ในธีมมืด กล่องจึง
   ตามธีมเองโดยไม่ต้องเขียน override เพิ่ม (เขียนขาวตายตัวแล้วธีมมืดอ่านไม่ออก) */
.backup-progress { margin-top: 1rem; padding: 0.9rem 1rem; border-radius: var(--radius-sm);
  border: 1px solid var(--hairline); background: var(--glass); }
.backup-progress-head { display: flex; align-items: baseline; justify-content: space-between;
  gap: 0.8rem; flex-wrap: wrap; margin-bottom: 0.6rem; }
.backup-progress-head .muted { font-size: var(--fs-sm); color: var(--ink-mute); }
.backup-progress .line-note { margin-top: 0.45rem; }
/* เลขเปอร์เซ็นต์กว้างคงที่ ไม่งั้นแถบขยับซ้ายขวาตามจำนวนหลักตอนวิ่ง 9%->10% */
.backup-progress .progress-pct { min-width: 3rem; font-variant-numeric: tabular-nums; }

/* ── ชวนติดตั้งลงหน้าจอโฮม ─────────────────────────────────────
   เป็นแผ่นเลื่อนขึ้นจากขอบล่าง ไม่ใช่ modal เต็มจอ และ **ไม่มีฉากหลังบัง**
   โดยตั้งใจ — มันเป็นข้อเสนอ ไม่ใช่สิ่งที่ต้องตอบก่อนถึงจะทำงานต่อได้
   z-index ต่ำกว่า modal (160) เพื่อให้ modal ที่เปิดทีหลังทับมันได้ตามปกติ */

.install-prompt {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 150;
  padding: 0.9rem;
  /* กันโดนแถบท่าทางของ iPhone ทับ */
  padding-bottom: calc(0.9rem + env(safe-area-inset-bottom, 0px));
  animation: install-rise 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}
.install-prompt[hidden] { display: none; }

@keyframes install-rise {
  from { transform: translateY(110%); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}
/* เครื่องที่ตั้งค่าลดการเคลื่อนไหวไว้ ต้องไม่มีอะไรเลื่อน */
@media (prefers-reduced-motion: reduce) {
  .install-prompt { animation: none; }
}

.install-card {
  width: min(100%, 460px);
  margin: 0 auto;
  background: var(--glass-2);
  backdrop-filter: var(--blur);
  border: 1px solid var(--glass-line);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-lg);
  padding: 1.3rem 1.2rem 1rem;
  text-align: center;
}
.install-icon { display: block; width: 52px; height: 52px; margin: 0 auto 0.7rem; object-fit: contain; }
.install-card h2 { font-size: var(--fs-lg); font-weight: 600; }
.install-sub { font-size: var(--fs-sm); color: var(--ink-soft); margin: 0.35rem 0 1rem; }

.install-steps {
  text-align: start;
  margin: 0 0 1rem;
  padding-inline-start: 1.3rem;
  display: grid;
  gap: 0.45rem;
  font-size: var(--fs-sm);
  color: var(--ink-soft);
}
/* ไอคอนแชร์วางแทรกกลางประโยค ต้องนั่งบนเส้นฐานเดียวกับตัวหนังสือ */
.install-glyph {
  display: inline-flex;
  vertical-align: -3px;
  color: var(--accent);
}

/* หน้าขั้นตอนมีคำนำสั้น ๆ นำหน้าบ้าง — ชิดกับข้อความใต้หัวข้อมากไป */
.install-guide .install-sub { margin-top: 0.35rem; }

/* ช่องติ๊กเงียบ 7 วัน — มีผลเฉพาะตอนกด "ไม่" จึงจงใจให้เบากว่าปุ่ม
   แต่พื้นที่กดต้องใหญ่พอสำหรับนิ้วหัวแม่ — ทั้งแถวกดได้ ไม่ใช่เฉพาะกล่องสี่เหลี่ยมเล็ก ๆ */
.install-snooze {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin: 0 0 0.9rem;
  padding: 0.35rem;
  font-size: var(--fs-xs);
  color: var(--ink-mute);
  cursor: pointer;
}
.install-snooze input {
  width: 1.05rem;
  height: 1.05rem;
  accent-color: var(--accent);
  cursor: pointer;
}

.install-actions { display: flex; gap: 0.6rem; }
.install-actions .btn { flex: 1 1 0; }

/* ── แผนที่ปักหมุด ─────────────────────────────────────────────
   ความสูงคงที่โดยตั้งใจ — Leaflet วัดขนาดกล่องตอนสร้างแล้วจำค่านั้นไว้
   กล่องที่สูงตามเนื้อหาจะได้ 0px เพราะตอนนั้นยังไม่มีอะไรอยู่ข้างใน
   ผลคือแถบเทาบาง ๆ ที่กดอะไรไม่ได้ ไม่มี error ให้ตามเลย */
.map-field { display: grid; gap: 0.5rem; margin: 0.9rem 0; }
.map-label { font-size: var(--fs-sm); color: var(--ink-soft); }
.map-canvas {
  height: 260px;
  border-radius: var(--r-lg);
  border: 1px solid var(--glass-line);
  overflow: hidden;
  /* pane ของ Leaflet ตั้ง z-index สูงกันเอง (สูงสุด 700) ถ้าไม่ตั้งชั้นซ้อนของ
     ตัวเองไว้ที่นี่ แผนที่จะลอยทับ dropdown และ modal ของระบบ */
  z-index: 0;
  isolation: isolate;
}
.map-tools { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.map-coords { font-size: var(--fs-xs); color: var(--ink-mute); font-variant-numeric: tabular-nums; }

/* ── ช่องวางลิงก์/พิกัด ─────────────────────────────────────────
   flex ย้ายมาอยู่ที่กล่องครอบ ไม่ใช่ที่ input — สปินเนอร์วางทับมุมขวาด้วย
   position: absolute จึงต้องมีตัวตั้ง relative ที่กว้างเท่าช่องพอดี */
.map-paste-wrap { position: relative; flex: 1 1 12rem; min-width: 0; display: block; }
.map-paste { width: 100%; min-width: 0; padding-right: 2.2rem; }

.map-paste-spin {
  position: absolute;
  top: 50%;
  right: 0.65rem;
  width: 1rem;
  height: 1rem;
  margin-top: -0.5rem;
  border: 2px solid var(--glass-line);
  border-top-color: var(--accent);
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease;
}
.map-paste-spin.is-on { opacity: 1; animation: spin 0.8s linear infinite; }

.map-paste-status { font-size: var(--fs-xs); min-height: 1.1em; color: var(--ink-mute); }
.map-paste-status.is-busy { color: var(--accent); }
.map-paste-status.is-error { color: #d70015; }

/* หมุดที่เพิ่งอ่านออกต้องสะดุดตา — หมุดที่โผล่เงียบ ๆ กลางแผนที่ที่เพิ่งเลื่อน
   คนมองไม่ทันว่าอะไรเปลี่ยน

   **ห้ามแตะ transform** — Leaflet วางตำแหน่งหมุดด้วย transform: translate3d()
   บนธาตุตัวเดียวกันนี้ แอนิเมชันที่เขียนทับจะทำให้หมุดกระโดดไปมุมซ้ายบนของ
   แผนที่ระหว่างเล่น · opacity กับ filter ปลอดภัยเพราะ Leaflet ไม่ได้ใช้ */
@keyframes map-pin-flash {
  0%   { opacity: 0.2; filter: drop-shadow(0 0 0 rgba(0, 113, 227, 0.9)); }
  40%  { opacity: 1;   filter: drop-shadow(0 0 10px rgba(0, 113, 227, 0.95)); }
  100% { opacity: 1;   filter: drop-shadow(0 0 0 rgba(0, 113, 227, 0)); }
}
.leaflet-marker-icon.map-pin-flash { animation: map-pin-flash 0.85s ease-out; }

/* ── แนบตำแหน่งกับการอัปเดตงาน ─────────────────────────────────
   วางอยู่เหนือแถวปุ่มยืนยัน จงใจให้เบากว่าปุ่มหลัก — เป็นของแถม ไม่ใช่ขั้นที่ต้องทำ */
.check-in { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin: 0.6rem 0; }
.check-in-state { font-size: var(--fs-xs); color: var(--ink-mute); }

/* หมุดในไทม์ไลน์ — ข้อความระยะทางอ่านแล้วใช้ได้ทันที ต่างจากพิกัดดิบ */
.job-timeline-pin {
  display: inline-block;
  margin-top: 0.35rem;
  font-size: var(--fs-xs);
  color: var(--accent);
  text-decoration: none;
}
.job-timeline-pin::before { content: "F4CD"; margin-inline-end: 0.3rem; }
.job-timeline-pin:hover { text-decoration: underline; }

/* ลิงก์นำทางในตารางทะเบียน — บอกว่ารายนี้ปักหมุดแล้วในตัว ไม่ต้องมีคอลัมน์เพิ่ม */
.row-pin { margin-inline-start: 0.4rem; font-size: var(--fs-xs); color: var(--accent); text-decoration: none; }
.row-pin::before { content: "F4CD"; margin-inline-end: 0.2rem; }
.row-pin:hover { text-decoration: underline; }

/* ช่องตั้งชื่อทางลัด — โผล่เฉพาะเครื่องที่สั่งติดตั้งจากโค้ดได้ (ดู install-prompt.php) */
.install-name { display: grid; gap: 0.3rem; margin: 0 0 0.7rem; text-align: start; }
.install-name label { font-size: var(--fs-xs); color: var(--ink-soft); }
.install-name[hidden] { display: none; }

/* ── สรุปงานเซลรายบุคคล ────────────────────────────────────────
   แผนที่ต้องมี **ความสูงที่ระบุไว้** — Leaflet วัดกล่องตอนสร้างแล้วจำค่าไว้ และ
   วาดลงกล่องสูงศูนย์ได้โดยไม่ร้องอะไรเลย · เจอตอนเดินของจริง 2026-09-04
   แผนที่หายทั้งอันทั้งที่สคริปต์โหลดครบ จุดถูกอ่านครบ 6 จุด และ .leaflet-pane
   ถูกสร้างจริง วัดขนาดได้ 1606x0 */
.activity-map {
  height: 360px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  overflow: hidden;

  /* **สร้างขอบเขตการซ้อนของตัวเอง** — Leaflet ตั้ง z-index ข้างในไว้ถึง 1000
     (pane 400 · control 800-1000) ส่วนแถบหัวของแอปอยู่ที่ 100 · ไม่มีบรรทัดนี้
     ชั้นข้างในจะทะลุออกมาทับหัวเมนู (เจอจริง 2026-09-04) · position + z-index
     ทำให้ทุกอย่างข้างในเทียบกันเองเท่านั้น ไม่ไปแข่งกับของนอกกล่อง */
  position: relative;
  z-index: 0;
}

/* ── โหมดนำเสนอ ────────────────────────────────────────────────
   กล่องนี้คือสิ่งที่ถูกส่งเข้าเต็มจอ · นอกโหมดมันเป็นแค่กล่องธรรมดา */
.activity-stage { margin: 0 0 0.6rem; }

.activity-stage.is-presenting {
  display: grid;
  grid-template-columns: 1fr minmax(300px, 26rem);
  gap: 0;
  height: 100vh;
  margin: 0;
  background: var(--bg);
}
.activity-stage.is-presenting .activity-map {
  height: 100%;
  border: 0;
  border-radius: 0;
}

.activity-panel {
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-inline-start: 1px solid var(--hairline);
  background: var(--bg);
}
.activity-panel[hidden] { display: none; }

.activity-panel-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.6rem;
  padding: 0.8rem;
  border-bottom: 1px solid var(--hairline);
}
.activity-panel-head strong { display: block; font-size: var(--fs-md); }
.activity-panel-head span { font-size: var(--fs-xs); color: var(--ink-mute); }

.activity-panel-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 0.6rem; }

.activity-panel-item {
  display: flex;
  gap: 0.6rem;
  width: 100%;
  padding: 0.55rem;
  border: 0;
  border-radius: var(--r-md);
  background: transparent;
  text-align: start;
  cursor: pointer;
}
.activity-panel-item:hover { background: var(--gray-bg); }
.activity-panel-item-body { min-width: 0; }

.activity-panel-who { font-weight: 600; }
.activity-panel-meta { font-size: var(--fs-xs); color: var(--ink-mute); }
.activity-panel-nopin { font-size: var(--fs-xs); color: var(--ink-mute); font-style: italic; }
.activity-panel-action { font-size: var(--fs-sm); }

.activity-panel-back { margin-bottom: 0.6rem; }
.activity-panel-detail-head { padding-bottom: 0.5rem; margin-bottom: 0.5rem; border-bottom: 1px solid var(--hairline); }
.activity-panel-history { padding: 0.45rem 0; border-bottom: 1px solid var(--hairline); }
.activity-panel-history:last-child { border-bottom: 0; }

/* เลขบนหมุด — เลขเดียวกับที่กำกับบรรทัดในไทม์ไลน์ คนอ่านจะได้โยงกันได้ */
.activity-pin-dot {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border: 2px solid #fff;
  border-radius: 50%;
  box-shadow: 0 1px 3px rgb(0 0 0 / 35%);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
}

.activity-pin-dot.is-converted { background: var(--green); }
.activity-pin-dot.is-open      { background: var(--amber); }
.activity-pin-dot.is-closed    { background: var(--ink-mute); }
.activity-pin-dot.is-visit     { background: var(--blue); }

/* คำอธิบายสี — จุดกลมชุดเดียวกับหมุดบนแผนที่ แต่ไม่มีตัวเลข */
.activity-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1rem;
  list-style: none;
  margin: 0 0 0.7rem;
  padding: 0;
  font-size: var(--fs-xs);
  color: var(--ink-soft);
}
.activity-legend li { display: flex; align-items: center; gap: 0.35rem; }
.activity-legend .activity-pin-dot { width: 14px; height: 14px; border-width: 1px; }

.activity-missing { margin: 0 0 0.9rem; font-size: var(--fs-xs); color: var(--ink-mute); }

/* แถบสรุปหกตัว — ตัวเลขนำ คำอธิบายตาม */
.activity-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
}
.activity-summary li {
  flex: 1 1 7rem;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  font-size: var(--fs-xs);
  color: var(--ink-soft);
}
.activity-summary strong { display: block; font-size: var(--fs-lg); color: var(--ink); }

.activity-day { margin: 0 0 1.1rem; }
.activity-day-head {
  margin: 0 0 0.4rem;
  padding-bottom: 0.2rem;
  border-bottom: 1px solid var(--hairline);
  font-size: var(--fs-sm);
}

.activity-visit { display: flex; align-items: baseline; gap: 0.5rem; padding: 0.35rem 0; }

/* เลขบรรทัด — ตรงกับเลขหมุดบนแผนที่ */
.activity-n {
  flex: 0 0 1.4rem;
  height: 1.4rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--gray-bg);
  font-size: var(--fs-xs);
  font-weight: 700;
}
.activity-time { flex: 0 0 3rem; font-size: var(--fs-xs); color: var(--ink-mute); }
.activity-body { flex: 1 1 auto; min-width: 0; }
.activity-who { font-weight: 600; }
.activity-where { font-weight: 400; color: var(--ink-mute); }
.activity-what { font-size: var(--fs-xs); color: var(--ink-soft); }
.activity-note {
  margin: 0.25rem 0 0;
  padding-inline-start: 0.6rem;
  border-inline-start: 2px solid var(--hairline);
  font-size: var(--fs-xs);
  color: var(--ink-soft);
}
