:root {
  /* ink & surface — violet-tinted neutrals, not flat gray */
  --ink: #221530;
  --ink-soft: #6b5c82;
  --paper: #fdfcfe;
  --white: #ffffff;
  --border: #e3d9f0;
  --border-strong: #cdb9ea;

  /* brand purple, depth scale */
  --volt-50: #f6f1fb;
  --volt-100: #ece0f8;
  --volt-300: #a877d6;
  --volt-500: #57298c;
  --volt-700: #38185c;
  --volt-900: #200f38;

  /* legacy aliases kept so every existing rule still resolves */
  --pea-purple: var(--volt-500);
  --pea-purple-dark: var(--volt-700);
  --pea-purple-light: var(--volt-300);
  --pea-purple-tint: var(--volt-50);

  --danger: #b23a3a;
  --danger-tint: #fbeaea;
  --success: #2f7d52;
  --success-tint: #eaf6ef;
  --warning: #9a6a12;
  --warning-tint: #fbf1e0;
  --info: #2f5f8a;
  --info-tint: #e8f1fb;

  /* ความสูงของ .topbar -- ใช้คำนวณตำแหน่ง sticky ของแถบซ้ายและแผงขวา
     ถ้าวันหนึ่งความสูงแถบบนเปลี่ยน แก้ที่นี่ที่เดียว */
  --topbar-h: 65px;

  /* ระยะขอบซ้าย/ขวาของ .requests-content -- เก็บเป็นตัวแปรเพราะกลุ่มคำร้อง
     ต้องหักลบระยะนี้ออกเพื่อกางเต็มความกว้าง ถ้าค่าสองที่ไม่ตรงกันจะเห็นเป็น
     ขอบเบี้ยวทันที */
  --content-pad-x: 36px;

  --shadow: 0 16px 36px rgba(32, 15, 56, 0.14);
  --shadow-sm: 0 2px 10px rgba(32, 15, 56, 0.08);
  --radius: 14px;

  --font-display: "Chakra Petch", "Segoe UI", sans-serif;
  --font-body: "Sarabun", "Segoe UI", sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, monospace;
}

* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
  min-height: 100vh;
  min-height: 100dvh;
}

body {
  font-family: var(--font-body);
  background: var(--paper);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}

button, input, select, textarea {
  font-family: inherit;
}

h1, h2, .brand-mark, .topbar-title, .service-title,
.requests-content-heading h2, .placeholder-card h2 {
  font-family: var(--font-display);
}

a {
  color: var(--volt-500);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

:focus-visible {
  outline: 2px solid var(--volt-500);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition-duration: 0.001ms !important;
    animation-duration: 0.001ms !important;
  }
}

/* ===== Signature: circuit-trace rule =====
   A short filled bar standing in for a plain hairline above section
   headings — a trace-line motif appropriate to a power utility, kept
   inside the white/purple palette rather than introducing a new hue. */
.home-heading::before,
.requests-content-heading::before {
  content: "";
  display: block;
  width: 32px;
  height: 3px;
  border-radius: 2px;
  margin-bottom: 14px;
  background: var(--volt-500);
}

.home-heading::before {
  margin-left: auto;
  margin-right: auto;
}

/* ===== Buttons ===== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: none;
  border-radius: 10px;
  padding: 12px 20px;
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s ease, box-shadow 0.15s ease, transform 0.05s ease;
}

.btn[hidden] {
  display: none;
}

/* Press feedback: every button darkens a step and sinks slightly, so a tap
   is acknowledged even before whatever it triggered finishes. Applied to
   plain <button>s too, not just .btn -- the card actions, mode toggles and
   row controls are all real buttons and should answer a press the same way. */
.btn:active,
button:active {
  transform: translateY(1px);
}

.btn-primary {
  background: var(--volt-500);
  color: var(--white);
  box-shadow: var(--shadow-sm);
}

.btn-primary:hover {
  background: var(--volt-700);
  box-shadow: 0 0 0 4px var(--volt-100);
}

.btn-primary:active {
  background: var(--volt-900);
  box-shadow: none;
}

.btn-ghost:active,
.btn-icon:active {
  background: var(--volt-100);
}

/* A button disabled mid-action is working, not unavailable: keep it in brand
   colour at reduced strength with a wait cursor, so it reads as "busy" rather
   than "you cannot press this". setBusy() swaps the label to match. */
.btn:disabled {
  opacity: 0.72;
  cursor: progress;
  transform: none;
  box-shadow: none;
}

/* ปุ่มสลับที่ "ติดอยู่" (เช่น "งานของฉัน") -- ต้องเห็นชัดว่ากำลังกรองอยู่
   ไม่งั้นรายการที่สั้นลงจะดูเหมือนข้อมูลหาย ไม่ใช่ตัวกรองที่เปิดค้างไว้ */
.btn-ghost.active {
  background: var(--volt-50);
  border-color: var(--volt-500);
  color: var(--volt-700);
}

/* บรรทัดคิวรอสำรวจบนการ์ด -- เน้นกว่าบรรทัด meta อื่นเล็กน้อยเพราะเป็นตัวเลข
   ที่คนเปิดการ์ดมาหาโดยตรงเวลาลูกค้าโทรถามว่า "อีกกี่คิว" */
.request-meta-queue {
  color: var(--volt-700);
  font-weight: 600;
}

.btn:disabled:hover {
  background: var(--volt-500);
  box-shadow: none;
}

.btn-ghost:disabled:hover {
  background: transparent;
}

.btn-block {
  width: 100%;
}

.btn-ghost {
  background: transparent;
  color: var(--volt-500);
  border: 1px solid var(--border);
}

.btn-ghost:hover {
  background: var(--volt-50);
  border-color: var(--border-strong);
}

.btn-icon {
  padding: 10px;
  border-radius: 50%;
}

.btn-icon svg {
  width: 18px;
  height: 18px;
}

/* ===== Auth views ===== */
.auth-view {
  min-height: 100vh;
  min-height: 100dvh;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  position: relative;
  overflow: hidden;
  background: var(--paper);
}

.auth-view[hidden] {
  display: none;
}

/* Faint transmission-grid backdrop instead of a generic gradient blob */
.auth-view::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--volt-100) 1px, transparent 1px),
    linear-gradient(90deg, var(--volt-100) 1px, transparent 1px);
  background-size: 56px 56px;
  -webkit-mask-image: radial-gradient(circle at 50% 20%, #000 0%, transparent 70%);
  mask-image: radial-gradient(circle at 50% 20%, #000 0%, transparent 70%);
  opacity: 0.55;
  pointer-events: none;
}

.auth-card {
  position: relative;
  width: 100%;
  max-width: 400px;
  background: var(--white);
  border: 1px solid var(--border);
  border-top: 3px solid var(--volt-500);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 36px 32px 28px;
}

.brand {
  text-align: center;
  margin-bottom: 28px;
}

.brand-mark {
  width: 56px;
  height: 56px;
  margin: 0 auto 14px;
  border-radius: 14px;
  background: linear-gradient(135deg, var(--volt-500) 0%, var(--volt-300) 100%);
  color: var(--white);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 20px;
  letter-spacing: 0.5px;
  box-shadow: var(--shadow-sm);
}

.brand-mark.small {
  width: 36px;
  height: 36px;
  font-size: 14px;
  margin: 0;
}

.brand h1 {
  margin: 0 0 6px;
  font-size: 23px;
  font-weight: 600;
  color: var(--volt-700);
}

.brand-sub {
  margin: 0;
  font-size: 13.5px;
  color: var(--ink-soft);
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* #requestForm carries this class and is hidden two ways -- for a request
   type with no form yet (so only the placeholder shows) and after a batch
   save (so only the result panel shows). Without this override neither
   worked: the form stayed on screen underneath both. */
.auth-form[hidden] {
  display: none;
}

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

.field[hidden] {
  display: none;
}

.field-hint {
  margin: -2px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-soft);
}

.field-row {
  display: flex;
  gap: 16px;
}

/* ตั้ง display ไว้ตายตัวด้านบน จึงต้องมีบรรทัดนี้ ไม่งั้น hidden ไม่มีผล --
   #extApprovalField (เลขที่/วันที่อนุมัติ) ใช้คลาสนี้และถูกซ่อน/แสดงตามสถานะ
   ดู Gotcha ใน CLAUDE.md */
.field-row[hidden] {
  display: none;
}

/* ช่องเบอร์โทร + ปุ่มโทรออก (tel: link ธรรมดา ใช้ได้จริงเฉพาะเปิดผ่านมือถือ) */
.field-input-row {
  display: flex;
  gap: 8px;
  align-items: center;
}

.field-input-row input,
/* สถานะงานของฟอร์มขอใช้ไฟฟ้าอยู่แถวเดียวกับปุ่มสร้างคำร้องขยายเขตฯ -- ดรอปดาวน์
   ต้องยืดกินที่ว่างเหมือน input ไม่งั้นมันจะหดเหลือเท่าข้อความที่ยาวที่สุดในลิสต์ */
.field-input-row select {
  flex: 1;
  min-width: 0;
}

/* ปุ่มที่อยู่ข้างช่องกรอกในแถวเดียวกัน -- ห้ามตัดบรรทัด ไม่งั้นความสูงของแถวจะ
   กระโดดจนดรอปดาวน์ข้าง ๆ ดูเบี้ยว */
.btn-inline {
  white-space: nowrap;
  flex: 0 0 auto;
}

.field-row > .field {
  flex: 1;
  min-width: 0;
}

.field label {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--ink);
}

.field input,
.field select,
.field textarea {
  padding: 11px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 14.5px;
  font-family: inherit;
  /* ไม่ตั้งไว้แต่เดิมเลยตกไปใช้ line-height เริ่มต้นของเบราว์เซอร์ (~1.15) ซึ่ง
     แคบเกินไปสำหรับสระบน-ล่างของภาษาไทย (อุ/อู/สระบน/วรรณยุกต์) -- กล่อง input
     สูงพอดีเนื้อบรรทัดแคบ ๆ นั้น ส่วนที่ยื่นเกินขึ้นบน-ลงล่างของตัวอักษรจึงโดน
     ตัดขอบกล่องไปเงียบ ๆ (เห็นชัดกับ "นายณัฐวุฒิ" ที่สระอุหายไปครึ่งหนึ่ง)
     1.5 ให้พื้นที่พอสำหรับสระซ้อนสองชั้น ตรงกับ line-height ของข้อความเนื้อหา
     ที่ใช้อยู่แล้วในไฟล์นี้ */
  line-height: 1.5;
  color: var(--ink);
  background: var(--white);
  outline: none;
  resize: vertical;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  border-color: var(--volt-300);
  box-shadow: 0 0 0 3px var(--volt-100);
}

.field input.invalid {
  border-color: var(--danger);
}

.field select:disabled,
.field input:disabled,
.field input[readonly] {
  background: var(--volt-50);
  color: var(--ink-soft);
  cursor: not-allowed;
}

.field-section {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding-top: 16px;
  border-top: 1px dashed var(--border);
}

/* ตั้ง display ไว้ตายตัวด้านบน จึงต้องมีบรรทัดนี้ ไม่งั้น hidden ไม่มีผลเลย
   -- #extPlanSection (แนบแผนผัง) เคยโผล่ตั้งแต่หน้าเพิ่มคำร้องเพราะขาดตรงนี้
   ดู Gotcha ใน CLAUDE.md */
.field-section[hidden] {
  display: none;
}

.field-section-label {
  font-family: var(--font-display);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--volt-700);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.checkbox-field {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  color: var(--ink);
  cursor: pointer;
  user-select: none;
}

.checkbox-field input {
  width: 16px;
  height: 16px;
  accent-color: var(--volt-500);
  cursor: pointer;
}

.form-error {
  margin: -4px 0 0;
  padding: 10px 12px;
  background: var(--danger-tint);
  color: var(--danger);
  border-radius: 8px;
  font-size: 13px;
}

.form-success {
  margin: -4px 0 0;
  padding: 10px 12px;
  background: var(--success-tint);
  color: var(--success);
  border-radius: 8px;
  font-size: 13px;
}

.auth-switch {
  text-align: center;
  margin: 22px 0 0;
  font-size: 13.5px;
  color: var(--ink-soft);
}

.track-result {
  margin-top: 20px;
  padding: 18px 20px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--volt-50);
}

.track-result-details {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.track-result-details > div {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: 13.5px;
}

.track-result-details dt {
  color: var(--ink-soft);
}

.track-result-details dd {
  margin: 0;
  font-weight: 500;
  color: var(--ink);
  text-align: right;
}

.track-result-details > div.plain {
  justify-content: flex-start;
}

.track-result-details > div.plain dd {
  text-align: left;
  font-weight: 400;
}

.track-payment {
  margin-top: 18px;
  padding: 16px 18px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--white);
}

.track-payment-heading {
  margin: 0 0 12px;
  font-weight: 600;
  font-size: 14px;
  color: var(--volt-700);
}

.track-slip {
  margin-top: 18px;
  padding: 16px 18px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--white);
}

.track-slip img {
  display: block;
  width: 100%;
  max-width: 320px;
  margin: 0 0 16px;
  border-radius: 8px;
  border: 1px solid var(--border);
}

/* Same [hidden]-vs-display gotcha as everywhere else that toggles hidden on
   an element whose class sets an unconditional display -- without this, a
   request with no slip yet still showed whatever slip image was loaded from
   the previous lookup, since setting .hidden = true had no visible effect. */
.track-slip img[hidden] {
  display: none;
}

.track-slip form {
  margin-top: 0;
}

/* ===== Boot overlay ===== */
.boot-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: var(--paper);
}

.boot-overlay[hidden] {
  display: none;
}

.boot-card {
  text-align: center;
}

.boot-card .brand-mark {
  margin: 0 auto 16px;
}

.boot-text {
  margin: 0;
  font-size: 14px;
  color: var(--ink-soft);
}

.boot-error {
  margin-top: 18px;
  color: var(--danger);
}

.boot-error p {
  margin: 0 0 6px;
  font-size: 14px;
  font-weight: 600;
}

.boot-error-hint {
  font-weight: 400 !important;
  color: var(--ink-soft);
  margin-bottom: 16px !important;
}

/* ===== Popup modal ===== */
.modal-overlay {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(32, 15, 56, 0.5);
  z-index: 100;
}

.modal-overlay[hidden] {
  display: none;
}

/* เตือนก่อนออกจากระบบอัตโนมัติ -- ต้องอยู่เหนือ modal อื่นที่อาจเปิดค้างไว้ */
.idle-warn-overlay {
  z-index: 300;
}

.modal-card {
  width: 100%;
  max-width: 340px;
  background: var(--white);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 32px 28px 28px;
  text-align: center;
}

.modal-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  margin: 0 auto 16px;
  border-radius: 999px;
  background: var(--success-tint);
  color: var(--success);
}

.modal-icon svg {
  width: 26px;
  height: 26px;
}

.modal-card h3 {
  margin: 0 0 6px;
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 600;
  color: var(--volt-700);
}

.modal-card p {
  margin: 0 0 22px;
  font-size: 14px;
  color: var(--ink-soft);
}

/* ===== App shell ===== */
.app-view {
  min-height: 100vh;
  min-height: 100dvh;
  width: 100%;
  background: var(--paper);
}

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 28px;
  border-bottom: 1px solid var(--border);
  background: var(--white);
  position: sticky;
  top: 0;
  z-index: 10;
}

.topbar-brand {
  display: flex;
  align-items: center;
  gap: 12px;
}

.topbar-title {
  font-weight: 600;
  font-size: 17px;
  letter-spacing: 0.2px;
  color: var(--volt-700);
}

.topbar-user {
  display: flex;
  align-items: center;
  gap: 14px;
}

.user-greeting {
  font-size: 13.5px;
  color: var(--ink-soft);
}

/* ===== Home ===== */
.home-main {
  max-width: 1040px;
  margin: 0 auto;
  padding: 48px 28px 64px;
}

.home-heading {
  text-align: center;
  margin-bottom: 40px;
}

.home-heading h2 {
  margin: 0 0 10px;
  font-size: 27px;
  font-weight: 600;
  color: var(--volt-700);
}

.home-heading p {
  margin: 0;
  color: var(--ink-soft);
  font-size: 14.5px;
}

.service-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}

.service-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 14px;
  text-align: left;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  border-top: 3px solid var(--volt-100);
  padding: 28px 24px;
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}

.service-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow);
  border-color: var(--border);
  border-top-color: var(--volt-500);
}

.service-icon {
  width: 52px;
  height: 52px;
  border-radius: 12px;
  background: var(--volt-50);
  color: var(--volt-500);
  display: flex;
  align-items: center;
  justify-content: center;
}

.service-icon svg {
  width: 26px;
  height: 26px;
}

.service-title {
  font-size: 16.5px;
  font-weight: 600;
  color: var(--ink);
}

.service-desc {
  font-size: 13px;
  color: var(--ink-soft);
  line-height: 1.5;
}

/* ===== Placeholder service page ===== */
.placeholder-main {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 60px 24px;
  min-height: calc(100vh - var(--topbar-h));
  min-height: calc(100dvh - var(--topbar-h));
}

.placeholder-card {
  max-width: 460px;
  width: 100%;
  text-align: center;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 44px 36px;
}

.placeholder-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  margin: 0 auto 18px;
  border-radius: 16px;
  background: var(--volt-50);
  color: var(--volt-500);
}

.placeholder-icon svg {
  width: 32px;
  height: 32px;
}

.placeholder-card h2 {
  margin: 0 0 8px;
  font-weight: 600;
  color: var(--volt-700);
  font-size: 21px;
}

.placeholder-desc {
  margin: 0 0 18px;
  color: var(--ink);
  font-size: 14.5px;
}

.placeholder-note {
  margin: 0 0 24px;
  color: var(--ink-soft);
  font-size: 13px;
  line-height: 1.6;
}

/* รายการลิงก์ของการ์ด (เช่น Google Sheet ของแผนก) -- เป็นแถวแยกทีละอัน ไม่ใช่
   ปุ่มเดียว เพราะบางการ์ดจะมีมากกว่าหนึ่งลิงก์ในอนาคต (SERVICES[key].links) */
.service-links {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0 0 18px;
  text-align: left;
}

.service-link-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--ink);
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.service-link-item:hover {
  border-color: var(--volt-300);
  background: var(--volt-50);
}

/* ทั้งสามคลาสนี้ประกาศ display แบบไม่มีเงื่อนไข และทั้งสามถูกสลับด้วยแอตทริบิวต์
   hidden จริง (#serviceLinks/#serviceGallery ใน event listener ของ .service-card,
   #extendListSheetLink ใน setWorkKind) -- ไม่มี override นี้ display ข้างบนชนะ
   กฎ [hidden] { display: none } ของเบราว์เซอร์ที่ specificity เท่ากัน แล้วซ่อน
   ไม่ลงเงียบ ๆ เจอตอนกวาดตรวจตามวิธีในหัวข้อ Gotcha ของ CLAUDE.md */
.service-links[hidden],
.service-gallery[hidden],
.service-link-item[hidden] { display: none; }

.service-link-item svg {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  color: var(--volt-500);
}

.service-link-item span {
  flex: 1;
}

/* หน้ารายการงานขอใช้ไฟฟ้า/ขยายเขตฯ แบ่งเป็น 2 คอลัมน์: แถบซ้าย .work-list-side
   (มีแค่ลิงก์ Google Sheet ของขอใช้ไฟฟ้า) กับ .work-main (เนื้อหารายการเดิม)
   ดู index.html สำหรับ markup และ setWorkKind() ใน app.js สำหรับการซ่อน/โชว์
   แถบซ้ายตามประเภทงาน -- ไม่ใส่ display ที่ไม่มีเงื่อนไขให้ .work-list-side จึงไม่
   ต้องมี [hidden] override (ดู Gotcha ใน CLAUDE.md) */
.work-list-layout {
  display: flex;
  align-items: flex-start;
  gap: 24px;
}

.work-list-side {
  flex: 0 0 260px;
  padding: 28px 0 0 28px;
}

/* ใช้ .service-link-item ตัวเดิมแต่นอกกล่อง .service-links (คนละหน้า, คนละ
   parent) -- ในคอลัมน์ซ้ายนี้ให้กว้างเต็มคอลัมน์แทนที่จะหดตามเนื้อหา */
.work-list-side .work-sheet-link {
  width: 100%;
}

/* .service-link-item ตั้ง display: flex แบบไม่มีเงื่อนไข -- ลิงก์นี้ถูกซ่อนด้วย
   [hidden] ตอนดูงานขยายเขตฯ (ยังไม่มีลิงก์ของประเภทนี้) จึงต้อง override ไม่งั้น
   [hidden] จะไม่มีผลเลย (ดู Gotcha ใน CLAUDE.md) */
.work-sheet-link[hidden] {
  display: none;
}

/* .work-main เดิมกึ่งกลางตัวเองด้วย margin: 0 auto (ยังใช้แบบนั้นในหน้าประมาณการ)
   แต่ในเลย์เอาต์ 2 คอลัมน์นี้ต้องเป็นคอลัมน์ขวาที่ยืดเต็มพื้นที่ที่เหลือแทน */
.work-list-layout .work-main {
  max-width: none;
  margin: 0;
  min-width: 0;
  flex: 1;
}

/* โบรชัวร์ของการ์ดที่มีรูป (เช่นงานธุรกิจเสริม) -- การ์ดปกติกว้างแค่ 460px
   ซึ่งแคบเกินไปสำหรับภาพโบรชัวร์แนวตั้ง จึงขยายเฉพาะตอนที่มีรูปจริงอยู่ข้างใน
   ด้วย :has() แทนการเพิ่มคลาสแยกจาก JS -- กว้างเท่าฟอร์มคำร้อง (720px) ซึ่งเผื่อ
   พอสำหรับภาพสัดส่วนตั้งโดยไม่ล้นจอมือถือ (ยังมี max-width: 100% ที่ img กันไว้) */
.placeholder-card:has(.service-gallery:not([hidden])) {
  max-width: 720px;
}

.service-gallery {
  display: flex;
  flex-direction: column;
  gap: 24px;
  margin: 0 0 24px;
  text-align: left;
}

.service-gallery img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--border);
  border-radius: 12px;
}

/* ===== Requests workspace ===== */
.requests-layout {
  display: flex;
  align-items: flex-start;
  min-height: calc(100vh - var(--topbar-h));
  min-height: calc(100dvh - var(--topbar-h));
}

.requests-sidebar {
  width: 240px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 20px 12px;
  border-right: 1px solid var(--border);
  background: var(--white);

  /* ล็อกแถบแท็บไว้ ไม่ให้ไหลหายไปตอนเลื่อนอ่านรายการหรือกรอกฟอร์มยาว ๆ
     ต้องเป็น flex-start ไม่ใช่ stretch: ถ้ายืดเต็มความสูงของ layout อยู่แล้ว
     มันจะไม่เหลือระยะให้ "ติด" เลย sticky ก็ไม่มีผลอะไร
     ความสูงเท่าจอพอดี พร้อม overflow ของตัวเอง เผื่อวันหน้ามีแท็บมากจนเกินจอ */
  align-self: flex-start;
  position: sticky;
  top: var(--topbar-h);
  height: calc(100vh - var(--topbar-h));
  height: calc(100dvh - var(--topbar-h));
  overflow-y: auto;
}

.requests-nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  text-align: left;
  background: transparent;
  border: none;
  border-left: 2px solid transparent;
  border-radius: 0 10px 10px 0;
  padding: 11px 14px;
  font-size: 14px;
  font-family: inherit;
  color: var(--ink);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

/* ต้องมี -- .requests-nav-item ตั้ง display: flex ไว้ ซึ่งชนะกฎ [hidden] ของ
   เบราว์เซอร์ (ดู Gotcha ใน CLAUDE.md) หน้างานขอใช้ไฟฟ้าซ่อนแท็บแนบแผนผัง/
   ภาพหน้างาน/ประมาณการ ด้วย hidden ถ้าไม่มีกฎนี้แท็บจะยังโผล่อยู่ครบ */
.requests-nav-item[hidden] {
  display: none;
}

.requests-nav-item svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  color: var(--volt-500);
  transition: color 0.15s ease;
}

.nav-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  margin-left: auto;
  border-radius: 999px;
  background: var(--danger);
  color: var(--white);
  font-size: 11px;
  font-weight: 600;
  flex-shrink: 0;
}

/* updateTabBadges() hides a badge at zero; without this it stayed on screen
   showing "0" instead of disappearing. */
.nav-badge[hidden] {
  display: none;
}

.requests-nav-item:hover {
  background: var(--volt-50);
}

.requests-nav-item.active {
  background: var(--volt-50);
  border-left-color: var(--volt-500);
  color: var(--volt-700);
  font-weight: 500;
}

.requests-nav-item.active svg {
  color: var(--volt-500);
}

.requests-content {
  flex: 1;
  min-width: 0;
  padding: 32px 36px 48px;
}

.requests-content-heading {
  margin-bottom: 20px;
  padding-bottom: 14px;
}

.requests-content-heading h2 {
  margin: 0 0 4px;
  font-weight: 600;
  font-size: 21px;
  color: var(--volt-700);
}

.requests-content-heading p {
  margin: 0;
  font-size: 13.5px;
  color: var(--ink-soft);
}

.requests-content-heading-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

.requests-content-heading-row .btn {
  flex-shrink: 0;
}

/* Edit form: fields on the left, audit panel as its own right-hand column
   so a growing status trail never pushes the form down */
.form-layout {
  display: flex;
  align-items: flex-start;
  gap: 32px;
}

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

.form-side {
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: 400px;
  flex-shrink: 0;
  padding: 18px 20px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--white);

  /* แผงยาวเท่าคอลัมน์ฟอร์ม คือลงไปสุดที่ปุ่มบันทึกพอดี แล้วค่อยเลื่อนในแผงเอง
     ถ้าประวัติสถานะกับคอมเมนต์ยาวเกินกว่านั้น (ตามที่เจ้าของงานสั่ง)

     เดิมแผงนี้ถูกล็อกให้ลอยตามจอ (position: sticky) ซึ่งบังคับให้ความสูงถูกจำกัด
     ไว้ที่ "เท่าหน้าจอ" ไม่ใช่ "เท่าฟอร์ม" -- เนื้อหาจึงถูกตัดให้เลื่อนตั้งแต่ยัง
     ไม่ถึงครึ่งฟอร์ม สองอย่างนี้เลือกได้อย่างเดียว: กล่องที่สูงเท่าคอนเทนเนอร์
     ไม่เหลือระยะให้เลื่อนตัวเอง sticky จึงไม่ทำงาน (กับดักเดียวกับที่
     .requests-sidebar ต้องเลิกใช้ align-self: stretch เพื่อให้ sticky ทำงาน)

     ผลที่แลกไป: เลื่อนหน้าลงไปกรอกช่องล่าง ๆ แล้วแผงจะเลื่อนหายขึ้นไปด้วย
     ไม่ลอยค้างให้เห็นสถานะตลอดเหมือนเดิม */
  align-self: stretch;
  overflow-y: auto;
}

/* กล่องรับแผงในหน้ารายละเอียดขอขยายเขตฯ -- ต้องสูงเท่าคอลัมน์ฟอร์มเหมือนกัน
   ไม่งั้น align-self: stretch ของ .form-side จะยืดได้แค่เท่ากล่องนี้ ซึ่งสูงเท่า
   เนื้อหาตัวเอง เพราะสิ่งที่ flex container เห็นคือกล่องห่อ ไม่ใช่ตัวแผง --
   กับดักเดียวกับที่ทำให้ order: -1 บนจอแคบไม่มีผลจนต้องเพิ่มคลาสนี้ขึ้นมา */
.form-meta-slot {
  align-self: stretch;
  display: flex;
}

.form-side[hidden] {
  display: none;
}

.form-side .form-meta-line {
  margin: 0;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-soft);
}

/* การ์ดสรุปคำร้อง -- ออกแบบมาเพื่อ "แคปหน้าจอแล้วส่งต่อได้เลย" เวลาลูกค้าโทรมา
   ตามงาน จึงยกเป็นกล่องพื้นสีอ่อนมีขอบชัด ครอปภาพได้ตรงกรอบโดยไม่ติดของรอบข้าง
   และมีชื่อประเภทคำร้องกำกับอยู่ในกล่อง เพราะพอภาพหลุดไปอยู่ในแชทแล้ว
   จะไม่เหลืออะไรบอกว่านี่คือคำร้องประเภทไหน

   เป็นคอลัมน์กลางของ .form-layout ระหว่างฟอร์มกับแผงประวัติ -- ที่ว่างตรงนี้มีอยู่แล้ว
   บนจอกว้าง เพราะ .request-form ถูกจำกัดไว้ที่ 480px ส่วน .form-main เป็น flex: 1
   ที่เหลือจึงว่างเปล่ามาแต่ไหนแต่ไร

   sticky เหมือนแผงขวา ไม่ใช่เพื่อความสวย -- ฟอร์มขอขยายเขตฯ ยาวมาก เลื่อนไปสักพัก
   จะจำไม่ได้ว่ากำลังแก้คำร้องใบไหน การ์ดที่ติดตาไปด้วยจึงทำหน้าที่เป็นป้ายบอกใบงาน */
.req-summary {
  width: 340px;
  flex-shrink: 0;
  padding: 14px 16px 16px;
  border: 1px solid var(--volt-100);
  border-radius: 12px;
  background: var(--volt-50);
  position: sticky;
  top: calc(var(--topbar-h) + 16px);
}

/* สถานะที่สอง: จอไม่กว้างพอจะมีคอลัมน์กลาง การ์ดถูกย้ายเข้าไปอยู่บนสุดของแผงขวา
   เหนือประวัติสถานะ (placeSummaryCard ใน app.js เป็นคนย้าย) แยกสองสถานะด้วย
   "พ่อแม่เป็นใคร" ไม่ต้องสลับคลาสให้มีสองที่ที่ต้องตรงกัน -- ในแผงขวาการ์ดกว้าง
   เต็มแผงและไม่ sticky เพราะมันเลื่อนอยู่ในแผงที่ยาวเท่าฟอร์มอยู่แล้ว ไม่ใช่
   สิ่งที่ควรลอยค้างทับเนื้อหาอื่นในแผงเดียวกัน */
.form-side > .req-summary {
  width: auto;
  position: static;
}

.req-summary[hidden] {
  display: none;
}

.req-summary-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.req-summary-head[hidden] {
  display: none;
}

.req-summary-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 13.5px;
  font-weight: 600;
  color: var(--volt-700);
}

/* ปุ่มคัดลอกเป็นเครื่องมือของเจ้าหน้าที่ ไม่ใช่เนื้อหาที่ต้องการให้ติดไปในภาพ
   จึงทำให้เล็กและจางกว่าปุ่มปกติ ไม่ให้แย่งสายตาในภาพที่แคปไป */
.req-summary-copy {
  flex-shrink: 0;
  padding: 4px 10px;
  border-radius: 8px;
  background: var(--white);
  font-size: 11.5px;
  color: var(--ink-soft);
}

.req-summary-type {
  margin: 3px 0 12px;
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--volt-900);
}

/* กริดสองคอลัมน์ ไม่ใช่ flex ทีละแถว -- ค่าทุกบรรทัดจะได้เริ่มตรงกันเป็นแนวเดียว
   ซึ่งอ่านง่ายกว่ามากในภาพนิ่งที่ผู้อ่านเลื่อนดูหรือกดขยายทีละส่วนไม่ได้ */
.req-summary-list {
  display: grid;
  grid-template-columns: 104px minmax(0, 1fr);
  gap: 9px 12px;
  margin: 0;
  align-items: baseline;
}

.req-summary-list[hidden] {
  display: none;
}

.req-summary-list dt {
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--ink-soft);
}

.req-summary-list dd {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink);
  /* ที่อยู่และชื่อลูกค้ายาวได้ไม่จำกัด -- ให้ตัดขึ้นบรรทัดใหม่แทนที่จะดันกล่องกว้างออก */
  overflow-wrap: anywhere;
}

.req-summary-list dd .request-badge {
  font-size: 12.5px;
  padding: 3px 10px;
}

/* เลขที่คำร้องและวันที่เป็นค่าที่คนอ่านออกเสียงตามหรือพิมพ์ตาม ฟอนต์โมโนช่วยให้
   ตัวเลขที่หน้าตาคล้ายกันไม่กลืนกัน -- เหตุผลเดียวกับที่ใช้ที่อื่นในระบบ */
.req-summary-mono {
  font-family: var(--font-mono);
  font-size: 13px;
}

/* เบอร์โทรกับพิกัดกดได้จริง (tel: / นำทางบน Google Maps) -- ผู้รับผิดชอบมักเปิดการ์ดนี้
   ตอนอยู่หน้างานบนมือถือ ทำเป็นเส้นใต้จาง ๆ ไม่ใช่ลิงก์สีน้ำเงินเต็มตัว เพราะในภาพที่
   แคปไปมันควรอ่านเป็นข้อมูลบรรทัดหนึ่งเหมือนบรรทัดอื่น ไม่ใช่ปุ่มที่กดในภาพไม่ได้ */
.req-summary-link {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--border-strong);
  text-underline-offset: 3px;
}

.req-summary-link:hover {
  color: var(--volt-500);
  text-decoration-color: var(--volt-300);
}

/* Status trail: oldest at the top, most recent change at the bottom */
.status-history {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* Status, name and time always share one line -- the name is the only part
   allowed to truncate, so the pill and timestamp stay fully readable. */
.status-stamp {
  display: flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}

.status-stamp .request-badge {
  flex-shrink: 0;
  font-size: 12.5px;
  padding: 3px 10px;
}

.status-stamp-by {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 11.5px;
  color: var(--ink-soft);
}

/* Work-log comments -- their own stream under the status trail, not mixed
   into it: each carries its own author and timestamp. */
.side-comments {
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

.side-comments-heading {
  margin: 0 0 10px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--volt-700);
}

.comment-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.comment-list:not(:empty) {
  margin-bottom: 14px;
}

.comment-item {
  padding-left: 10px;
  border-left: 2px solid var(--volt-100);
}

.comment-text {
  font-size: 13px;
  color: var(--ink);
  line-height: 1.55;
  white-space: pre-wrap;
}

.comment-by {
  margin-top: 2px;
  font-size: 11.5px;
  color: var(--ink-soft);
}

.side-comments textarea {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 13px;
  font-family: inherit;
  color: var(--ink);
  background: var(--white);
  outline: none;
  resize: vertical;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.side-comments textarea:focus {
  border-color: var(--volt-300);
  box-shadow: 0 0 0 3px var(--volt-100);
}

.side-comments .btn {
  margin-top: 10px;
  padding: 9px 16px;
  font-size: 13.5px;
}

.side-comments .form-error {
  margin: 8px 0 0;
}

.requests-search {
  margin-top: 16px;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.requests-search input {
  width: 100%;
  max-width: 360px;
  flex: 1;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 14px;
  font-family: inherit;
  color: var(--ink);
  background: var(--white);
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.requests-search input:focus {
  border-color: var(--volt-300);
  box-shadow: 0 0 0 3px var(--volt-100);
}

/* กรองด้วยช่วงวันที่รับคำร้อง (งานขอใช้ไฟฟ้า/งานขยายเขตฯ) -- แถวเดียวกัน
   label+input คู่ละสอง แล้วปุ่มล้างท้ายแถว ห่อบรรทัดได้บนจอแคบเหมือน .requests-search */
.requests-date-filter {
  margin-top: 12px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 10px;
  font-size: 13.5px;
  color: var(--ink-soft);
}

.requests-date-filter input[type="date"] {
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 13.5px;
  font-family: inherit;
  color: var(--ink);
  background: var(--white);
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.requests-date-filter input[type="date"]:focus {
  border-color: var(--volt-300);
  box-shadow: 0 0 0 3px var(--volt-100);
}

.requests-date-filter .btn {
  padding: 6px 12px;
  font-size: 13px;
}

/* กล่องสรุปเหนือรายการคำร้อง -- จำนวนคำร้องแยกตามสถานะ และ Input/Output ของช่วง
   วันที่ที่เลือก (ดู renderRequestsSummary ใน app.js) ไม่ใส่ display แบบไม่มี
   เงื่อนไขให้ตัวนอก เพราะมันถูกซ่อนด้วย [hidden] (ดู Gotcha ใน CLAUDE.md) */
.requests-summary {
  margin-top: 14px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--paper);
}

.requests-summary-counts {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.requests-summary-item {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 13px;
  background: var(--white);
  border: 1px solid var(--border);
}

.requests-summary-item strong {
  font-family: var(--font-mono);
  font-size: 14px;
}

/* เป็น <button> จริง กดแล้วกระโดดไปกลุ่มสถานะนั้น (ดู jumpToStatusGroup) --
   ต้องล้างสไตล์ปุ่มของเบราว์เซอร์ทิ้งเพื่อให้หน้าตาเหมือนป้ายเดิมทุกอย่าง */
.requests-summary-item {
  cursor: pointer;
  font-family: inherit;
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}

.requests-summary-item:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.requests-summary-item:active { transform: none; }

/* สถานะที่ยังไม่มีคำร้องเลย -- คงไว้ในที่เดิมแต่จางลง เพราะคนกดโดยจำตำแหน่ง
   ป้ายที่หายไปทำให้ทุกป้ายหลังจากนั้นเลื่อน (เหตุผลเดียวกับชิปในหน้าคิวงาน) */
.requests-summary-item.is-empty { opacity: 0.45; }

/* กะพริบกลุ่มที่เพิ่งถูกกระโดดมา -- ไม่งั้นพอเลื่อนถึงแล้วไม่มีอะไรบอกว่า
   "ตรงนี้แหละ" โดยเฉพาะตอนกลุ่มอยู่กลางรายการยาว ๆ */
.status-group.is-jumped {
  animation: statusGroupFlash 1.6s ease;
}

@keyframes statusGroupFlash {
  0%, 100% { background: transparent; }
  15% { background: var(--volt-50); }
}

/* ใช้โทนสีเดียวกับป้ายสถานะบนการ์ด (JOB_STATUS_TONE) เพื่อให้กวาดตาหาสถานะ
   เดียวกันเจอทั้งในกล่องสรุปและในรายการ */
.requests-summary-item.tone-warning { border-color: var(--warning); color: var(--warning); }
.requests-summary-item.tone-success { border-color: var(--success); color: var(--success); }
.requests-summary-item.tone-danger { border-color: var(--danger); color: var(--danger); }
.requests-summary-item.tone-info { border-color: var(--info); color: var(--info); }

.requests-summary-io {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px 18px;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}

.requests-summary-io-item {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  font-size: 13.5px;
  color: var(--ink-soft);
}

.requests-summary-io-item strong {
  font-family: var(--font-mono);
  font-size: 18px;
  color: var(--volt-700);
}

/* Inprogress = งานค้าง (เหลือง) / Output = ทำแล้ว (เขียว) -- สีเดียวกับป้ายสถานะ */
.requests-summary-io-item.tone-warning strong { color: var(--warning); }
.requests-summary-io-item.tone-success strong { color: var(--success); }

.requests-summary-range {
  font-size: 12.5px;
  color: var(--ink-soft);
  margin-left: auto;
}

/* สลับทิศทางเรียง (วันที่รับคำร้อง แล้วเลขที่คำร้อง) -- ปุ่มเดียวสลับสองสถานะ
   แทนที่จะเป็นคู่ปุ่มแบบ .requests-mode-btn เพราะมีแค่สองทิศทางให้เลือก
   ไม่ใช่สามโหมดขึ้นไปแบบ รอส่ง/ประวัติการส่ง */
.requests-sort-btn {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--white);
  color: var(--ink);
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
  flex-shrink: 0;
}

.requests-sort-btn:hover {
  border-color: var(--volt-300);
  color: var(--volt-700);
}

.requests-sort-icon {
  font-family: var(--font-mono);
  transition: transform 0.15s ease;
}

/* กด = กำลังเรียงเก่า-ใหม่ (aria-pressed="true") -- ลูกศรพลิกหัวแทนการวาดไอคอนสองชุด */
.requests-sort-btn[aria-pressed="true"] .requests-sort-icon {
  transform: rotate(180deg);
}

.requests-count {
  font-family: var(--font-mono);
  color: var(--ink-soft);
}

.request-form {
  max-width: 480px;
}

.request-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.request-card {
  position: relative;
  border: 1px solid var(--border);
  border-left: 3px solid var(--volt-500);
  border-radius: 0 12px 12px 0;
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--white);
  transition: box-shadow 0.15s ease, border-color 0.15s ease;
}

.request-card.has-card-actions {
  padding-bottom: 56px;
}

.request-card:hover {
  box-shadow: var(--shadow-sm);
  border-color: var(--border-strong);
}

.request-card-clickable {
  cursor: pointer;
}

.request-card-clickable:hover {
  box-shadow: var(--shadow);
  border-color: var(--volt-300);
}

/* Type reads as a depth of the same brand purple, not a new hue */
.request-card[data-type="power"] {
  border-left-color: var(--volt-500);
}

.request-card[data-type="payment"] {
  border-left-color: var(--volt-100);
}

.request-card[data-type="general"] {
  border-left-color: var(--volt-300);
}

.request-card[data-type="extend"] {
  border-left-color: var(--volt-700);
}

.request-card[data-type="deposit"] {
  border-left-color: var(--volt-900);
}

.request-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.request-badges {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.request-badge {
  display: inline-flex;
  align-items: center;
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 14.5px;
  font-weight: 500;
  white-space: nowrap;
}

.request-badge-id {
  background: var(--volt-50);
  color: var(--volt-700);
}

.request-badge-purpose {
  background: var(--info-tint);
  color: var(--info);
}

.request-badge-status.tone-warning {
  background: var(--warning-tint);
  color: var(--warning);
}

.request-badge-status.tone-success {
  background: var(--success-tint);
  color: var(--success);
}

.request-badge-status.tone-danger {
  background: var(--danger-tint);
  color: var(--danger);
}

.request-badge-status.tone-info {
  background: var(--info-tint);
  color: var(--info);
}

/* ===== งานขอขยายเขตระบบจำหน่ายไฟฟ้า (โมดูลปฏิบัติงาน) ===== */
.work-main {
  max-width: 1100px;
  margin: 0 auto;
  padding: 28px 28px 64px;
}

/* ชิปกรองสถานะ -- ทุกสถานะอยู่ครบเสมอและอยู่ตำแหน่งเดิมเสมอ ถึงจะเป็นศูนย์
   (ชิปที่หายไปเวลาเป็นศูนย์ทำให้ชิปอื่นขยับ ปุ่มที่จำตำแหน่งไว้เลยกดผิด) */
.status-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 14px;
}

.status-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 14px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--white);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 14px;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.status-chip:hover {
  border-color: var(--volt-300);
  background: var(--volt-50);
}

.status-chip.active {
  background: var(--volt-500);
  border-color: var(--volt-500);
  color: var(--white);
}

/* สถานะที่ยังไม่มีงานอยู่เลย -- จางลงแต่ยังกดได้ เพื่อยืนยันด้วยตาว่าว่างจริง */
.status-chip.is-empty {
  opacity: 0.5;
}

/* ชิปที่ไม่ได้เป็นแค่มุมมองหนึ่ง แต่เป็น "งานที่กำลังจะเสียหาย" (ใกล้หมดกำหนด
   ยืนราคา) -- ต้องสะดุดตาตั้งแต่ยังไม่กด และเฉพาะตอนที่มีงานค้างอยู่จริง
   ตอนถูกเลือกอยู่ปล่อยให้ .active ทาสีแบรนด์ทับตามเดิม จะได้รู้ว่ากดค้างไว้ */
.status-chip.is-alert:not(.active) {
  border-color: var(--danger);
  color: var(--danger);
  background: var(--danger-tint);
}

.status-chip.is-alert:not(.active) .status-chip-count {
  background: var(--danger);
  color: var(--white);
}

.status-chip-count {
  font-family: var(--font-mono);
  font-size: 12.5px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--volt-50);
  color: var(--volt-700);
}

.status-chip.active .status-chip-count {
  background: rgba(255, 255, 255, 0.22);
  color: var(--white);
}

/* แถบจ่ายงาน -- ติดขอบล่างจอไว้ เพราะเลือกงานเสร็จแล้วมักอยู่ท้ายรายการยาว ๆ
   พอดี ไม่ควรต้องเลื่อนกลับขึ้นไปกดปุ่ม */
.assign-bar {
  position: sticky;
  bottom: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 16px;
  padding: 14px 18px;
  border: 1px solid var(--volt-300);
  border-radius: 12px;
  background: var(--white);
  box-shadow: var(--shadow);
}

/* .assign-bar ตั้ง display: flex ไว้ตายตัว จึงต้องมีบรรทัดนี้ ไม่งั้น hidden
   ไม่มีผลเลย (ดู Gotcha ใน CLAUDE.md) */
.assign-bar[hidden] {
  display: none;
}

.assign-bar-count {
  font-weight: 600;
  color: var(--volt-700);
}

.assign-bar-field {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  color: var(--ink-soft);
}

/* ดรอปดาวน์เลือกผู้รับผิดชอบ -- ใช้ลูกศรที่วาดเองแบบเดียวกับตารางประมาณการ
   แทนลูกศรดีฟอลต์ของเบราว์เซอร์ ซึ่งหน้าตาต่างกันไปทุกเครื่องและดูเป็นคนละหน้า
   กับที่เหลือ นี่คือช่องที่หัวหน้าใช้บ่อยที่สุดในหน้านี้ จึงให้ที่ยืนเต็มที่ */
.assign-bar-field select {
  min-width: 260px;
  padding: 9px 34px 9px 12px;
  border: 1px solid var(--border);
  border-radius: 9px;
  font-family: inherit;
  font-size: 14px;
  color: var(--ink);
  background-color: var(--white);
  background-image: linear-gradient(45deg, transparent 50%, var(--volt-500) 50%),
                    linear-gradient(135deg, var(--volt-500) 50%, transparent 50%);
  background-position: right 15px center, right 10px center;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.assign-bar-field select:hover {
  border-color: var(--border-strong);
}

.assign-bar-field select:focus {
  border-color: var(--volt-300);
  box-shadow: 0 0 0 3px var(--volt-100);
}

/* แผนผังที่แนบไว้ -- หลายไฟล์ได้ แต่ละใบมีภาพตัวอย่างของตัวเอง */
.plan-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 12px;
}

.plan-list:empty {
  display: none;
}

.plan-item {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--paper);
}

/* ตัวอย่างแผนผัง (ไฟล์ภาพ หรือหน้าแรกของ PDF) */
.plan-preview {
  width: 100%;
  height: 200px;
  object-fit: contain;
  border-radius: 8px;
  background: var(--white);
}

/* ตั้ง display ไว้ในกฎด้านบน จึงต้องกันไว้ (ดู Gotcha ใน CLAUDE.md) */
.plan-preview[hidden] {
  display: none;
}

.plan-item-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-size: 12.5px;
}

.plan-item-when {
  color: var(--ink-soft);
}

/* ===== ภาพหน้างาน ===== */
.photo-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

.photo-slot {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--paper);
}

.photo-slot-label {
  margin: 0;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--volt-700);
}

.photo-slot img {
  width: 100%;
  max-height: 220px;
  object-fit: contain;
  border-radius: 8px;
  background: var(--white);
}

/* ตั้ง display ไว้ตายตัวด้านบน จึงต้องมีบรรทัดนี้ (ดู Gotcha ใน CLAUDE.md) */
.photo-slot img[hidden] {
  display: none;
}

@media (max-width: 700px) {
  .photo-grid {
    grid-template-columns: 1fr;
  }
}

/* ===== หน้าประมาณการ ===== */
.estimate-context {
  margin-bottom: 6px;
}

.estimate-context-wbs {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 15px;
  font-weight: 600;
  color: var(--volt-700);
}

.estimate-context-sub {
  margin: 2px 0 0;
  font-size: 13.5px;
  color: var(--ink-soft);
}

/* เตือนว่ายังไม่ได้บันทึก -- อยู่ข้างปุ่มบันทึกบนแถบบน จะได้เห็นตลอดทุกชั้น */
.estimate-dirty {
  font-size: 13px;
  color: var(--warning);
  font-weight: 600;
}

.estimate-crumbs {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin: 14px 0 18px;
  font-size: 13.5px;
}

.estimate-crumb {
  border: none;
  background: transparent;
  padding: 2px 4px;
  font-family: var(--font-body);
  font-size: 13.5px;
  color: var(--volt-500);
  cursor: pointer;
  border-radius: 6px;
}

.estimate-crumb:hover {
  background: var(--volt-50);
}

/* ชั้นสุดท้ายเป็น <span> ไม่ใช่ปุ่ม -- กดกลับไปที่ตัวเองไม่ได้ */
span.estimate-crumb {
  color: var(--ink);
  font-weight: 600;
  cursor: default;
}

.estimate-crumb-sep {
  color: var(--ink-soft);
}

.estimate-pane-head h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 20px;
  color: var(--volt-700);
}

.estimate-cards {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 14px 0 18px;
}

.estimate-card {
  display: flex;
  align-items: stretch;
  gap: 8px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--volt-500);
  border-radius: 0 12px 12px 0;
  background: var(--white);
}

.estimate-card-open {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 14px 16px;
  border: none;
  background: transparent;
  text-align: left;
  cursor: pointer;
  border-radius: 0 12px 12px 0;
}

.estimate-card-open:hover {
  background: var(--volt-50);
}

.estimate-card-title {
  font-size: 15.5px;
  font-weight: 600;
  color: var(--ink);
}

.estimate-card-meta {
  font-size: 13px;
  color: var(--ink-soft);
}

/* แถวเพิ่มแผนก/งานย่อย -- ช่องกรอกกับปุ่มอยู่บรรทัดเดียวกัน */
.estimate-add-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  padding: 14px;
  border: 1px dashed var(--border-strong);
  border-radius: 12px;
  background: var(--paper);
}

.estimate-add-row input,
.estimate-add-row select {
  flex: 1;
  min-width: 160px;
  padding: 11px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-family: inherit;
  font-size: 14.5px;
  color: var(--ink);
  background: var(--white);
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.estimate-add-row input:focus,
.estimate-add-row select:focus {
  border-color: var(--volt-300);
  box-shadow: 0 0 0 3px var(--volt-100);
}

/* ===== ใบประมาณการ ===== */
.estimate-head {
  display: grid;
  grid-template-columns: 2fr 1.4fr 1fr;
  gap: 16px;
  margin-bottom: 14px;
}

/* ซ่อนระหว่างแก้ไขชุดเซ็ตพัสดุโดยตรง (openKitEditor ใน app.js) -- display: grid
   ข้างบนไม่มีเงื่อนไข จึงต้องมี override นี้ไม่งั้น [hidden] จะไม่มีผลเลย (ดู
   Gotcha ใน CLAUDE.md) */
.estimate-head[hidden] {
  display: none;
}

/* ตารางกว้างกว่าคอลัมน์ฟอร์มแน่นอน -- ให้เลื่อนแนวนอนในกรอบของตัวเอง ไม่ใช่
   ทำให้ทั้งหน้าเลื่อนได้ (กติกาเดียวกับตารางกว้างที่อื่นในโปรเจกต์นี้) */
.estimate-scroll {
  overflow-x: auto;
}

.estimate-table {
  min-width: 880px;
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}

.estimate-row {
  display: grid;
  grid-template-columns: 44px 108px minmax(240px, 1fr) 150px 72px 72px 72px 40px;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-top: 1px solid var(--border);
}

.estimate-row:first-child {
  border-top: none;
}

/* สลับสีแถวอ่อน ๆ -- ตารางกว้าง ตาต้องกวาดตามแถวให้ไม่หลุด */
#estRows .estimate-row:nth-child(even) {
  background: var(--paper);
}

#estRows .estimate-row:focus-within {
  background: var(--volt-50);
}

.estimate-head-row {
  background: var(--volt-50);
  font-weight: 600;
  font-size: 12.5px;
  letter-spacing: 0.3px;
  color: var(--volt-700);
  text-align: center;
  border-bottom: 1px solid var(--border);
}

/* หัวคอลัมน์ Description ชิดซ้ายให้ตรงกับข้อความในช่อง */
.estimate-head-row span:nth-child(2) {
  text-align: left;
}

/* ช่องกรอกในตารางใช้หน้าตาเดียวกับช่องกรอกทั้งเว็บ แค่ย่อระยะขอบลงให้พอดีแถว
   -- ตารางที่ใช้ช่องกรอกหน้าตาดีฟอลต์ของเบราว์เซอร์จะดูเป็นคนละหน้ากับที่เหลือ */
.estimate-row input,
.estimate-row select {
  width: 100%;
  min-width: 0;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-family: inherit;
  font-size: 13.5px;
  color: var(--ink);
  background: var(--white);
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.estimate-row input:hover:not([readonly]),
.estimate-row select:hover {
  border-color: var(--border-strong);
}

.estimate-row input:focus,
.estimate-row select:focus {
  border-color: var(--volt-300);
  box-shadow: 0 0 0 3px var(--volt-100);
}

/* ลูกศรของ <select> วาดเอง เพื่อให้เหมือนกันทุกเบราว์เซอร์และไม่กินที่ */
.estimate-row select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 26px;
  background-image: linear-gradient(45deg, transparent 50%, var(--volt-500) 50%),
                    linear-gradient(135deg, var(--volt-500) 50%, transparent 50%);
  background-position: right 12px center, right 7px center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  cursor: pointer;
}


/* ---------- แผงเลือกพัสดุของใบประมาณการ ---------- */

/* แผงชุดเซ็ตพัสดุ -- วางเหนือแผงเลือกทีละตัว และทำให้ดูเป็นคนละก้อนกันชัด ๆ
   ด้วยเส้นคั่นด้านล่าง ไม่งั้นดรอปดาวน์สองอันที่อยู่ติดกันจะดูเหมือนแผงเดียวกัน
   แล้วคนจะสับสนว่า "ชุดเซ็ต" กับ "กลุ่ม" ต่างกันตรงไหน */
.est-kits {
  padding-bottom: 18px;
  margin-bottom: 18px;
  border-bottom: 1px solid var(--border);
}

.est-kits-row {
  display: flex;
  align-items: end;
  flex-wrap: wrap;
  gap: 12px;
}

.est-kits-row[hidden] {
  display: none;
}

.est-kits-pick {
  flex: 1 1 320px;
  min-width: 0;
}

.est-kits-pick select {
  width: 100%;
}

.est-kits .field-hint,
.est-kits .form-error {
  margin: 10px 0 0;
}

.est-kit-save {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: 12px;
  margin-top: 14px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--volt-50);
}

.est-kit-save[hidden] {
  display: none;
}

.est-kit-save .batch-toolbar {
  grid-column: 1 / -1;
}

@media (max-width: 700px) {
  .est-kit-save {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ไฮไลต์แถวที่เพิ่งเปลี่ยนจากการเพิ่มชุดเซ็ต -- เพิ่มทีเดียวสิบสี่รายการแล้วบางตัว
   ถูกรวมเข้ากับแถวเดิมเงียบ ๆ คือกรณีที่คนกดไม่รู้ว่าเกิดอะไรขึ้น แล้วกดซ้ำ
   สีคนละสีระหว่าง "แถวใหม่" กับ "ถูกบวกเพิ่ม" เพราะสองอย่างนี้ต้องแยกออกจากกันให้ได้ */
.estimate-row.is-kit-new {
  background: var(--success-tint);
}

.estimate-row.is-kit-merged {
  background: var(--warning-tint);
}

/* การเลือกพัสดุเกิดที่นี่ที่เดียว ตารางด้านล่างมีแต่ของที่เพิ่มแล้ว -- แผงจึงถูก
   ยกออกมาเป็นกล่องของตัวเองให้ต่างจากตาราง ไม่ใช่แถวหนึ่งในตารางเดียวกัน */
.est-picker {
  margin: 18px 0 14px;
  padding: 16px 18px 18px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--paper);
}

.est-picker-title {
  margin: 0 0 14px;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 600;
  color: var(--volt-700);
}

.est-picker-grid {
  display: grid;
  grid-template-columns: minmax(150px, 1fr) 150px minmax(260px, 2.2fr) repeat(3, 92px);
  gap: 12px;
  align-items: end;
}

.est-picker-item input,
.est-picker-key input {
  width: 100%;
}

/* ---------- กล่องรายการแนะนำของช่องรหัสพัสดุ/รายการพัสดุ ----------
   เขียนเองแทน <datalist> ของเบราว์เซอร์ ซึ่งตัดชื่อพัสดุยาวทิ้งและปรับหน้าตาไม่ได้
   ชื่อที่ต่างกันแค่ท้ายชื่อ (ขนาดสาย ขนาดหม้อแปลง) จึงเลือกผิดตัวได้ง่าย */
.est-picker-key,
.est-picker-item {
  position: relative;
}

.est-suggest {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 40;
  width: 100%;
  /* ช่องรหัสพัสดุแคบแค่ 150px -- กล่องต้องกว้างพอให้อ่านชื่อเต็มได้ จึงลอยทับ
     คอลัมน์ข้าง ๆ ได้ แต่ห้ามกว้างเกินจอบนมือถือ */
  min-width: min(480px, calc(100vw - 32px));
  max-height: 340px;
  overflow-y: auto;
  margin: 0;
  padding: 4px;
  list-style: none;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 12px 28px rgba(34, 21, 48, 0.16);
}

/* ใส่ไว้ตามกติกา [hidden] ของโปรเจกต์ (ดู Gotcha ใน CLAUDE.md) -- กล่องนี้สลับ
   ด้วย hidden ตลอดเวลา ถ้าวันหนึ่งมีคนเติม display ให้มัน จะได้ไม่ค้างเปิด */
.est-suggest[hidden] {
  display: none;
}

.est-suggest-option {
  display: grid;
  grid-template-columns: minmax(84px, auto) 1fr;
  column-gap: 12px;
  row-gap: 2px;
  padding: 8px 10px;
  border-radius: 8px;
  cursor: pointer;
}

.est-suggest-option.is-active {
  background: var(--volt-50);
}

/* ตัวที่เลือกค้างไว้อยู่แล้ว -- เปิดกล่องใหม่เพื่อเปลี่ยนตัว ต้องเห็นว่าตอนนี้เลือกตัวไหน */
.est-suggest-option.is-picked .est-suggest-desc {
  font-weight: 600;
  color: var(--volt-700);
}

.est-suggest-key {
  font-family: var(--font-mono);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--volt-700);
  white-space: nowrap;
}

/* ชื่อเต็มเสมอ -- ขึ้นบรรทัดใหม่ได้ ไม่ตัดท้าย ซึ่งคือเหตุผลเดียวที่กล่องนี้มีอยู่ */
.est-suggest-desc {
  min-width: 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.est-suggest-group {
  grid-column: 2;
  font-size: 12px;
  color: var(--ink-soft);
  overflow-wrap: anywhere;
}

.est-suggest-empty,
.est-suggest-more {
  padding: 8px 10px;
  font-size: 12.5px;
  color: var(--ink-soft);
  cursor: default;
}

.est-suggest-more {
  border-top: 1px solid var(--border);
}

/* ฟอนต์โมโนไว้เพราะเป็นรหัส -- แต่สีต้องเหมือนช่องกรอกอื่นทุกช่อง
   พื้นม่วงอ่อน + cursor: default เป็นหน้าตาของช่องอ่านอย่างเดียว (ตอนที่ช่องนี้
   ยังเป็น readonly) พอพิมพ์ค้นได้แล้วยังคงสีนั้นไว้ คนจะเข้าใจว่ากรอกไม่ได้ */
.est-picker-key input {
  font-family: var(--font-mono);
  font-size: 13px;
}

.est-picker-qty input {
  text-align: right;
}

/* เลขจำนวนพิมพ์เองเสมอ ลูกศรขึ้นลงของเบราว์เซอร์กินที่และกดโดนโดยไม่ตั้งใจ */
.est-picker-qty input::-webkit-outer-spin-button,
.est-picker-qty input::-webkit-inner-spin-button {
  appearance: none;
  -webkit-appearance: none;
  margin: 0;
}

.est-picker-qty input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}

.est-picker-add {
  width: 100%;
  margin-top: 14px;
}

/* ข้อความ "รวมจำนวนเข้ากับรายการเดิมแล้ว" ใช้กล่องเดียวกับ error แต่ไม่ใช่ error
   -- เป็นการยืนยันว่าเกิดอะไรขึ้น จึงต้องอ่านออกว่าเป็นคนละเรื่องกับความผิดพลาด */
.est-picker .form-error.is-notice {
  color: var(--volt-700);
  background: var(--volt-50);
  border-color: var(--volt-100);
}

/* ---------- เซลล์ที่เลือกมาแล้ว แสดงเป็นข้อความ ไม่ใช่ช่องกรอก ---------- */
.estimate-cell-key {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--volt-700);
}

/* ชื่อพัสดุต้องขึ้นครบเสมอ -- ตัดขึ้นบรรทัดใหม่ในช่องของตัวเอง min-width: 0 กัน
   ไม่ให้ช่องกริดขยายตามข้อความยาวจนดันคอลัมน์ข้าง ๆ หรือโดน .estimate-table
   (overflow: hidden) ตัดทิ้ง และ overflow-wrap ใช้กับข้อความยาวที่ไม่มีเว้นวรรค */
.estimate-cell-desc {
  min-width: 0;
  font-size: 13.5px;
  color: var(--ink);
  line-height: 1.4;
  overflow-wrap: anywhere;
}

/* กลุ่มเคยตัดท้ายเป็น "…" -- ชื่อกลุ่มยาวจึงอ่านไม่ครบ ให้ขึ้นบรรทัดใหม่แทน */
.estimate-cell-group {
  min-width: 0;
  font-size: 12.5px;
  color: var(--ink-soft);
  line-height: 1.4;
  overflow-wrap: anywhere;
}

.est-picker-full {
  margin: 12px 0 0;
  padding: 8px 12px;
  border-radius: 8px;
  background: var(--volt-50);
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--volt-700);
  overflow-wrap: anywhere;
}

.estimate-empty {
  margin: 0;
  padding: 26px 16px;
  text-align: center;
  font-size: 13.5px;
  color: var(--ink-soft);
}

/* .estimate-empty ไม่ได้ตั้ง display ตายตัว จึงไม่ต้องมี [hidden] override
   (ดูหมายเหตุเรื่อง hidden vs display ใน CLAUDE.md) */

@media (max-width: 900px) {
  .est-picker-grid {
    grid-template-columns: 1fr 1fr 1fr;
  }

  .est-picker-item {
    grid-column: 1 / -1;
  }
}

.estimate-no {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--ink-soft);
  text-align: center;
}

/* KeyCode ไม่ได้กรอกเอง -- มาจากรายการที่เลือกเสมอ จึงทำให้อ่านออกว่าเป็นค่าที่
   ระบบเติมให้ ไม่ใช่ช่องว่างที่รอให้พิมพ์ */
.estimate-keycode {
  font-family: var(--font-mono);
  font-size: 12.5px;
  background: var(--paper);
  color: var(--ink-soft);
  cursor: default;
}

/* ปุ่มเพิ่ม/ลดของช่องตัวเลขกินที่ในแถวแคบ และไม่มีใครใช้กับจำนวนพัสดุ */
.estimate-qty {
  font-family: var(--font-mono);
  text-align: center;
  -moz-appearance: textfield;
  appearance: textfield;
}

.estimate-qty::-webkit-outer-spin-button,
.estimate-qty::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.estimate-remove {
  border: none;
  background: transparent;
  color: var(--ink-soft);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  border-radius: 8px;
  padding: 4px;
}

.estimate-remove:hover {
  background: var(--danger-tint);
  color: var(--danger);
}

@media (max-width: 700px) {
  .estimate-head {
    grid-template-columns: 1fr;
  }
}

/* ===== จัดกลุ่มงานตามสถานะ (ย่อ/ขยายได้) ===== */
.status-group {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--white);
  overflow: hidden;
}

.status-group-head {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 12px 16px;
  border: none;
  background: var(--volt-50);
  text-align: left;
  cursor: pointer;
}

.status-group-head:hover {
  background: var(--volt-100);
}

/* ลูกศรหมุนลงเมื่อกางอยู่ -- บอกสถานะย่อ/ขยายโดยไม่ต้องมีข้อความ */
.status-group-caret {
  flex: none;
  width: 0;
  height: 0;
  border-left: 6px solid var(--volt-500);
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  transform: rotate(90deg);
  transition: transform 0.15s ease;
}

.status-group.is-collapsed .status-group-caret {
  transform: rotate(0deg);
}

.status-group-count {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--ink-soft);
}

.status-group-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
}

.status-group-body[hidden] {
  display: none;
}

/* ===== งานในมือของแต่ละคน (หัวหน้างาน) ===== */
.person-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--volt-500);
  border-radius: 0 12px 12px 0;
  background: var(--white);
  text-align: left;
  cursor: pointer;
}

.person-card:hover {
  background: var(--volt-50);
}

.person-card.is-mine {
  border-left-color: var(--warning);
}

.person-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.person-card-name {
  font-size: 15.5px;
  font-weight: 600;
  color: var(--ink);
}

.person-card-total {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--volt-700);
}

/* สรุปว่ากองงานของคนนี้ค้างอยู่ขั้นไหนบ้าง โดยไม่ต้องกดเข้าไปดู */
.person-card-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.person-card-chips .request-badge {
  font-size: 12.5px;
  padding: 2px 10px;
}

/* ===== คิวรอสำรวจ แยกเป็นของแต่ละคน ===== */
.queue-group {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--white);
  overflow: hidden;
}

/* คิวของตัวเองอยู่บนสุดอยู่แล้ว ขีดซ้ายหนาเป็นตัวย้ำอีกชั้นว่าอันไหนของเรา */
.queue-group.is-mine {
  border-left: 3px solid var(--volt-500);
}

.queue-group-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  background: var(--volt-50);
  border-bottom: 1px solid var(--border);
}

.queue-group-name {
  font-weight: 600;
  color: var(--volt-700);
}

.queue-group-count {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--ink-soft);
}

.queue-item {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 12px 16px;
  border: none;
  border-top: 1px solid var(--border);
  background: var(--white);
  text-align: left;
  cursor: pointer;
}

.queue-item:first-of-type {
  border-top: none;
}

.queue-item:hover {
  background: var(--volt-50);
}

/* เลขคิวเป็นตัวเลขเดี่ยว ๆ ตัวใหญ่ อ่านได้จากระยะไกลว่าใครคิวไหน */
.queue-pos {
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--volt-500);
  color: var(--white);
  font-family: var(--font-mono);
  font-size: 15px;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* คิวที่ 1 ของทุกคน = งานที่ต้องลงพื้นที่ก่อน ทำให้เด่นกว่าคิวถัด ๆ ไป */
.queue-item:first-of-type .queue-pos {
  background: var(--warning);
}

.queue-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.queue-title {
  font-size: 15px;
  font-weight: 500;
  color: var(--ink);
}

.queue-meta {
  font-size: 13px;
  color: var(--ink-soft);
}

/* บรรทัดผู้รับผิดชอบบนการ์ดงาน */
.work-assignee {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--volt-700);
}

.work-assignee.is-unassigned {
  color: var(--warning);
}

/* บรรทัดกำหนดยืนราคาบนการ์ดงานขยายเขตฯ และข้อความใต้ช่องวันหมดกำหนดในฟอร์ม
   -- ใช้สีเดียวกันทั้งสองที่ผ่าน .tone-text-* เพื่อให้ "แดง = เลยกำหนด" อ่าน
   เหมือนกันทุกหน้าจอ ตัวหนาเพราะมันคือบรรทัดที่ต้องสะดุดตากว่าบรรทัดอื่นบนการ์ด */
.quote-deadline {
  font-weight: 600;
}

.request-date {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--ink-soft);
}

.request-name {
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
}

.request-meta {
  font-size: 13.5px;
  color: var(--ink-soft);
  line-height: 1.65;
}

/* สีตามความเร่งด่วนของข้อความล้วน (ไม่ใช่ป้าย badge ที่มีพื้นหลังของตัวเอง)
   -- ใช้กับบรรทัดกำหนดยืนราคาบนการ์ดและข้อความใต้ช่องวันหมดกำหนดในฟอร์ม
   ต้องอยู่ "หลัง" .request-meta/.field-hint ที่กำหนดสีไว้แล้ว ไม่งั้นโดนทับ */
.tone-text-success { color: var(--success); }
.tone-text-warning { color: var(--warning); }
.tone-text-danger { color: var(--danger); }
.tone-text-info { color: var(--ink-soft); }

.request-empty {
  text-align: center;
  padding: 48px 24px;
  color: var(--ink-soft);
  font-size: 14px;
  border: 1px dashed var(--border-strong);
  border-radius: 12px;
}

.request-card-actions {
  position: absolute;
  right: 20px;
  bottom: 16px;
  display: flex;
  gap: 8px;
}

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

/* ===== Batch request entry ===== */
.form-divider {
  height: 1px;
  background: var(--border);
  border: none;
  margin: 8px 0 0;
}

.batch-heading {
  font-family: var(--font-display);
  font-size: 16px;
  color: var(--volt-700);
  margin: 0;
}

/* เดิมเป็นย่อหน้าเดียวยาวติดกันจนอ่านไม่ออกว่ามีกี่เรื่อง -- แยกเป็นข้อ ๆ
   เรื่องละบรรทัด */
.batch-hint {
  margin: -8px 0 0;
  padding-left: 20px;
  font-size: 13px;
  color: var(--ink-soft);
  line-height: 1.85;
}

.batch-hint li {
  margin-bottom: 2px;
}

.batch-hint strong {
  color: var(--ink);
  font-weight: 600;
}

.batch-toolbar {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.batch-toolbar[hidden] {
  display: none;
}

/* กลุ่มคำร้องกางเต็มความกว้างของพื้นที่เนื้อหา โดยหักระยะขอบของ
   .requests-content ออกทั้งสองข้าง -- แต่ละใบมีช่องกรอกครบทุกช่อง จึงต้องการ
   ความกว้างมากกว่าฟอร์มตั้งต้นด้านบนที่เป็นสองคอลัมน์ */
.batch-rows {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-left: calc(var(--content-pad-x) * -1);
  margin-right: calc(var(--content-pad-x) * -1);
  padding-left: var(--content-pad-x);
  padding-right: var(--content-pad-x);
}

.batch-row {
  border: 1px solid var(--border);
  border-left: 3px solid var(--volt-300);
  border-radius: var(--radius);
  background: var(--white);
  padding: 16px 18px;
}

.batch-row-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.batch-row-title {
  font-family: var(--font-display);
  font-size: 14.5px;
  font-weight: 600;
  color: var(--volt-700);
}

/* ทุกช่องของคำร้องหนึ่งใบเรียงเป็นกริดที่ยืดตามความกว้างจริง -- auto-fill ทำให้
   จอกว้างได้หลายคอลัมน์ จอแคบลดเองโดยไม่ต้องมี breakpoint ของตัวเอง */
.batch-row-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 12px 14px;
  align-items: start;
}

.batch-row-grid .field[hidden] {
  display: none;
}

/* ป้ายกำกับในแถวกลุ่มเล็กกว่าฟอร์มหลัก เพราะมีจำนวนมากกว่ามากในพื้นที่เท่ากัน */
.batch-row-grid label {
  font-size: 12px;
}

.batch-row-grid input,
.batch-row-grid select,
.batch-row-grid textarea {
  padding: 8px 10px;
  font-size: 13.5px;
}

.batch-remove-btn {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 5px 12px;
  background: transparent;
  color: var(--ink-soft);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}

.batch-remove-btn:hover {
  background: var(--danger-tint);
  border-color: var(--danger);
  color: var(--danger);
}

.batch-result {
  padding: 28px 26px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--success);
  border-radius: var(--radius);
  background: var(--white);
}

.batch-result[hidden] {
  display: none;
}

.batch-result h3 {
  font-family: var(--font-display);
  margin: 0 0 8px;
  color: var(--ink);
}

.batch-result p {
  margin: 0 0 20px;
  color: var(--ink-soft);
  font-size: 14px;
  line-height: 1.7;
}

.batch-result-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

/* ===== Meter tab: รอส่ง / ประวัติการส่ง toggle ===== */
.requests-modes {
  display: flex;
  gap: 6px;
  margin-top: 14px;
  padding: 4px;
  background: var(--volt-50);
  border: 1px solid var(--border);
  border-radius: 10px;
  width: fit-content;
}

.requests-modes[hidden] {
  display: none;
}

.requests-mode-btn {
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  padding: 7px 16px;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
}

.requests-mode-btn:hover {
  color: var(--volt-700);
}

.requests-mode-btn.active {
  background: var(--white);
  color: var(--volt-700);
  font-weight: 600;
  box-shadow: var(--shadow-sm);
}

.dispatch-meta-people {
  font-family: var(--font-mono);
  font-size: 12.5px;
}

/* Inline action that reads as a link but is a real button, since it acts on
   the page rather than navigating anywhere. */
.link-btn {
  font: inherit;
  padding: 0;
  border: none;
  background: none;
  color: var(--volt-500);
  text-decoration: underline;
  cursor: pointer;
}

.link-btn:hover {
  color: var(--volt-700);
}

.request-card.has-card-select {
  padding-left: 46px;
}

.request-card-select {
  position: absolute;
  left: 16px;
  top: 18px;
  display: flex;
  cursor: pointer;
}

.request-card-select input {
  width: 18px;
  height: 18px;
  margin: 0;
  accent-color: var(--volt-500);
  cursor: pointer;
}

.request-card-action-btn {
  padding: 6px 12px;
  font-size: 12.5px;
}

/* ===== Responsive =====
   Breakpoints, widest first:
   1100px — sidebar + 480px form + 400px audit panel stop fitting side by side
   1024px — iPad landscape: narrower sidebar buys back content width
    860px — iPad portrait / large phones: sidebar becomes a scrolling tab bar
    640px — phones: single column everywhere, tighter gutters */

@media (max-width: 1100px) {
  .form-layout {
    flex-direction: column;
  }

  .form-side {
    width: 100%;
    order: -1;

    /* จอแคบวางแผงไว้เหนือฟอร์ม ปล่อยให้ไหลตามเนื้อหาไปเลย ไม่ต้องยืดให้เท่า
       ฟอร์มและไม่ต้องมีแถบเลื่อนของตัวเอง */
    align-self: auto;
    overflow-y: visible;
  }

  /* หน้ารายละเอียดขอขยายเขตฯ ห่อแผงไว้อีกชั้น (#extendPaneMeta) เพราะแผงเป็นโหนด
     ที่ถูกย้ายไปมาระหว่างสองหน้า -- order ที่ให้ .form-side จึงไม่มีผลกับการเรียงใน
     .form-layout เพราะลูกที่แท้จริงคือกล่องห่อ ไม่ใช่ตัวแผง ผลคือบนมือถือ สรุปคำร้อง
     ประวัติสถานะ และคอมเมนต์ไปกองอยู่ "ใต้" ฟอร์มที่ยาวมาก ต่างจากคำร้องขอใช้ไฟฟ้า
     ที่แผงเป็นลูกโดยตรงและขึ้นก่อนฟอร์มอยู่แล้ว ต้องสั่งที่กล่องห่อด้วยจึงจะตรงกัน

     การ์ดสรุปก็มาด้วยกันเอง เพราะบนจอแคบ placeSummaryCard() ย้ายมันเข้าไปอยู่
     บนสุดของแผงนี้อยู่แล้ว (ดู min-width: 1640px ใน app.js) */
  .form-meta-slot {
    width: 100%;
    order: -1;
  }
}

@media (max-width: 1024px) {
  /* จอแคบวางแถบลิงก์ไว้เหนือรายการงานแทนที่จะเป็นคอลัมน์ซ้าย -- 260px คงที่
     บีบเนื้อหารายการแคบเกินไปบนจอเล็ก */
  .work-list-layout {
    flex-direction: column;
    gap: 0;
  }

  .work-list-side {
    flex-basis: auto;
    width: 100%;
    /* ซ้าย/ขวาตาม padding ของ .work-main (28px) เสมอ จะได้ชิดกับเนื้อหารายการ
       ด้านล่างพอดีตอนวางซ้อนกันแนวตั้ง */
    padding: 16px 28px 0;
  }

  .requests-sidebar {
    width: 200px;
    padding: 20px 8px;
  }

  .requests-nav-item {
    font-size: 13.5px;
    padding: 10px 12px;
  }

  .requests-content {
    --content-pad-x: 24px;
    padding: 28px 24px 40px;
  }
}

@media (max-width: 860px) {
  .service-grid {
    grid-template-columns: 1fr;
  }

  .requests-layout {
    flex-direction: column;
  }

  /* Six tabs won't stack on a phone, so scroll them sideways instead of
     wrapping into a tall block that pushes the list off-screen. */
  .requests-sidebar {
    width: 100%;
    flex-direction: row;
    flex-wrap: nowrap;
    gap: 4px;
    padding: 8px 12px;
    border-right: none;
    border-bottom: 1px solid var(--border);
    -webkit-overflow-scrolling: touch;

    /* ยังล็อกอยู่ แต่เป็นแถบแนวนอนใต้แถบบน ไม่ใช่คอลัมน์สูงเต็มจอ
       ความสูงต้องกลับเป็น auto ไม่งั้นแถบแท็บจะสูงเท่าจอทั้งจอ */
    height: auto;
    align-self: stretch;
    z-index: 5;
    overflow-x: auto;
    overflow-y: hidden;
  }

  .requests-nav-item {
    flex-shrink: 0;
    white-space: nowrap;
    border-left: none;
    border-bottom: 2px solid transparent;
    border-radius: 8px;
  }

  .requests-nav-item.active {
    border-left-color: transparent;
    border-bottom-color: var(--volt-500);
  }

  .nav-badge {
    margin-left: 2px;
  }

  /* iOS zooms the whole page when a focused input is under 16px. */
  .field input,
  .field select,
  .field textarea,
  .requests-search input,
  .side-comments textarea {
    font-size: 16px;
  }
}

@media (max-width: 640px) {
  .field-row {
    flex-direction: column;
  }

  .auth-view {
    padding: 24px 16px;
  }

  .auth-card {
    padding: 28px 22px 22px;
  }

  .topbar {
    padding: 12px 16px;
  }

  .user-greeting {
    max-width: 38vw;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .home-main {
    padding: 32px 18px 48px;
  }

  .requests-content {
    --content-pad-x: 16px;
    padding: 24px 16px 40px;
  }

  .requests-content-heading-row .btn {
    width: 100%;
  }

  .request-card {
    padding: 16px 16px;
  }

  .request-card-actions {
    right: 16px;
  }

  .form-side {
    padding: 16px;
  }

  /* The one-line status stamp can't hold a pill, a name and a timestamp on a
     phone-width panel -- let it wrap rather than overflow. */
  .status-stamp {
    flex-wrap: wrap;
    white-space: normal;
  }
}

/* ===== qr.html — staff QR-label printing tool ===== */

.qr-page {
  max-width: 920px;
  margin: 0 auto;
  padding: 40px 20px;
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: 24px;
  align-items: start;
}

/* Without this the single card stays on screen (and on the printed page)
   behind the batch label sheet, because the unconditional `display: grid`
   above outranks the UA's [hidden] rule. Same gotcha as .auth-view/.field/
   .btn/.track-slip img -- see CLAUDE.md. */
.qr-page[hidden] {
  display: none;
}

@media (max-width: 720px) {
  .qr-page {
    grid-template-columns: 1fr;
  }
}

.qr-card,
.qr-side {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

.qr-card {
  padding: 36px 32px 28px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 16px;
  border-top: 3px solid var(--volt-500);
}

.qr-brand {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: 0.06em;
  color: var(--volt-700);
  text-transform: uppercase;
}

.qr-card h1 {
  font-size: 1.5rem;
  line-height: 1.3;
  margin: 0;
  color: var(--ink);
}

.qr-lede {
  margin: -6px 0 4px;
  color: var(--ink-soft);
  font-size: 0.95rem;
  max-width: 34ch;
}

.qr-frame {
  background: #ffffff;
  padding: 16px;
  border-radius: 12px;
  border: 1px solid var(--border);
}

.qr-frame canvas,
.qr-frame img {
  display: block;
  image-rendering: pixelated;
}

.qr-tracking-line {
  font-family: var(--font-mono);
  font-size: 0.95rem;
  color: var(--ink);
  margin: 2px 0 0;
}

.qr-blank {
  display: inline-block;
  min-width: 11ch;
  border-bottom: 1.5px solid var(--ink-soft);
  padding: 0 2px 1px;
  font-weight: 600;
  color: var(--volt-700);
}

.qr-side {
  padding: 28px 26px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.qr-scan-hint {
  font-size: 0.85rem;
  color: var(--ink-soft);
  margin: -4px 0 0;
}

.qr-hint {
  font-size: 0.78rem;
  color: var(--ink-soft);
  line-height: 1.5;
  margin: 4px 0 0;
}

.qr-note {
  font-size: 0.78rem;
  color: var(--ink-soft);
  line-height: 1.6;
  margin: 0;
}

.copy-feedback {
  font-size: 0.8rem;
  color: var(--volt-700);
  text-align: center;
  min-height: 1.2em;
  margin: -8px 0 0;
}

@media print {
  body {
    background: #fff;
  }
  .qr-side {
    display: none;
  }
  .qr-page {
    display: block;
    max-width: none;
    padding: 0;
  }
  .qr-card {
    box-shadow: none;
    border: none;
    padding: 10mm;
  }
}


/* ปุ่มคำสั่งฉุกเฉินของผู้ดูแลระบบบน topbar -- ยังเป็นปุ่ม ghost เหมือนปุ่มข้างกัน
   (ไม่ใช่ปุ่มทึบ) เพราะไม่ควรเด่นกว่างานประจำวัน แต่ย้อมเป็นโทนอันตรายเพื่อไม่ให้
   กดสลับกับ "ออกจากระบบ" ที่อยู่ติดกัน ซึ่งผลลัพธ์ต่างกันคนละเรื่อง */
.btn-danger-ghost {
  color: var(--danger);
  border-color: var(--danger);
}

.btn-danger-ghost:hover {
  background: var(--danger-tint);
  color: var(--danger);
}

/* ==========================================================================
   Account view (เปลี่ยนรหัสผ่าน / ตั้งรหัสผ่านชั่วคราว)
   ========================================================================== */

/* แยกส่วนของผู้ดูแลระบบออกจากฟอร์มด้านบนให้ชัด -- สองฟอร์มนี้ทำคนละเรื่องกัน
   (รหัสของตัวเอง กับรหัสของคนอื่น) การเผลอกรอกผิดฟอร์มมีราคาแพง */
.admin-panel {
  margin-top: 28px;
  padding-top: 24px;
  border-top: 1px dashed var(--border-strong);
}

/* ไม่ได้ตั้ง display ไว้ จึงยังไม่จำเป็นตอนนี้ แต่ใส่กันไว้ตามกฎ [hidden] ของ
   โปรเจกต์ เผื่อวันหลังมีคนเติม display: flex/grid ให้คลาสนี้แล้วซ่อนไม่ลง */
.admin-panel[hidden],
.temp-password[hidden] {
  display: none;
}

.admin-panel-title {
  margin: 0 0 6px;
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 600;
  color: var(--danger);
}

.admin-panel-hint {
  margin: 0 0 16px;
  font-size: 13px;
  line-height: 1.75;
  color: var(--ink-soft);
}

.temp-password {
  margin-top: 18px;
  padding: 16px 18px;
  background: var(--warning-tint);
  border: 1px solid var(--warning);
  border-radius: 10px;
  text-align: center;
}

.temp-password-label {
  margin: 0 0 10px;
  font-size: 13px;
  color: var(--ink-soft);
}

.temp-password-label span {
  font-weight: 600;
  color: var(--ink);
}

/* mono + user-select: all -- รหัสนี้ต้องถูกอ่านออกเสียงหรือคัดลอกให้ถูกทุกตัว
   ฟอนต์ที่แยก 0/O และ 1/l ได้จึงสำคัญพอ ๆ กับการคัดลอกได้ในคลิกเดียว */
.temp-password-value {
  margin: 0 0 12px;
  font-family: var(--font-mono);
  font-size: 22px;
  font-weight: 600;
  letter-spacing: 2px;
  color: var(--ink);
  user-select: all;
  word-break: break-all;
}

.temp-password-warn {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--warning);
}

/* คำอธิบายกลาง ๆ ที่ไม่ใช่ทั้ง error และ success -- ใช้กับข้อความบังคับเปลี่ยน
   รหัสผ่านชั่วคราว ซึ่งไม่ใช่ความผิดพลาดของผู้ใช้ แต่ก็ผ่านไปเฉย ๆ ไม่ได้ */
.form-notice {
  margin: 0 0 18px;
  padding: 12px 14px;
  border-radius: 10px;
  background: var(--warning-tint);
  border-left: 3px solid var(--warning);
  color: var(--warning);
  font-size: 13.5px;
  line-height: 1.75;
}

/* หน้ายืนยันตัวตน 2 ขั้นตอน (ผู้ดูแลระบบ) -- QR ต้องมีพื้นขาวเสมอ แอปสแกนพื้นเข้มไม่ติด */
.mfa-enroll {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-bottom: 18px;
}

.mfa-enroll[hidden] {
  display: none;
}

.mfa-enroll .form-notice {
  align-self: stretch;
}

.mfa-enroll .field-hint {
  margin: 10px 0 4px;
}

.mfa-qr {
  width: 200px;
  height: 200px;
  padding: 8px;
  border-radius: 10px;
  background: #fff;
  border: 1px solid var(--border);
}

.mfa-secret {
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 1px;
  word-break: break-all;
  text-align: center;
  user-select: all;
}

/* "เปลี่ยนรหัสผ่านเรียบร้อยแล้ว กรุณากรอกรหัสอีกครั้ง" ยืมกล่อง error -- ไม่ใช่ความผิดพลาด */
#mfaView .form-error.is-notice {
  background: var(--success-tint);
  color: var(--success);
}

#mfaCode {
  font-family: var(--font-mono);
  font-size: 20px;
  letter-spacing: 6px;
  text-align: center;
}

/* ทั้งสองคลาสนี้ถูกสลับด้วย hidden -- ยังไม่ได้ตั้ง display จึงยังไม่จำเป็น
   แต่ใส่ตามกฎของโปรเจกต์ เผื่อวันหลังมีคนเติม display ให้แล้วซ่อนไม่ลง */
.form-notice[hidden],
.auth-switch[hidden] {
  display: none;
}

/* ปุ่มที่ "กำลังทำงานอยู่" ต้องดูต่างจากปุ่ม "กดไม่ได้" -- .btn:disabled ทำให้จาง
   ลงอย่างเดียว ซึ่งสื่อว่าใช้ไม่ได้ ไม่ได้สื่อว่ากำลังรออยู่ คนละความหมายกัน
   สำหรับคนที่เพิ่งกดบันทึกแล้วกำลังรอผล */
.btn.is-busy,
.btn.is-busy:hover {
  opacity: 1;
  background: var(--volt-300);
  border-color: var(--volt-300);
  color: var(--white);
  cursor: progress;
  box-shadow: none;
  animation: btn-busy-pulse 1.15s ease-in-out infinite;
}

@keyframes btn-busy-pulse {
  0%, 100% { background: var(--volt-300); }
  50%      { background: var(--volt-500); }
}

/* เคารพการตั้งค่าของผู้ใช้ที่ขอให้ลดการเคลื่อนไหว -- ยังเปลี่ยนโทนสีให้เห็นอยู่
   แค่ไม่กะพริบ */
@media (prefers-reduced-motion: reduce) {
  .btn.is-busy,
  .btn.is-busy:hover {
    animation: none;
  }
}

/* ==========================================================================
   ย่อ/ขยายคำร้องในกลุ่ม -- เวลามีหลายใบ การกางทุกใบพร้อมกันทำให้หน้ายาวจน
   เลื่อนหาไม่เจอ
   ========================================================================== */

/* กฎ [hidden] ที่ขาดไม่ได้: .batch-row-grid ตั้ง display: grid แบบไม่มีเงื่อนไข
   ซึ่งชนะกฎ [hidden] { display: none } ของเบราว์เซอร์เพราะ specificity เท่ากัน
   ถ้าไม่มีบรรทัดนี้ การตั้ง .hidden = true จะไม่เกิดอะไรขึ้นเลย และเป็นความผิด
   พลาดที่เงียบสนิท (เกิดมาแล้วห้าครั้งในโปรเจกต์นี้ ดูหัวข้อ Gotcha) */
.batch-row-grid[hidden] {
  display: none;
}

.batch-toggle-btn {
  flex-shrink: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 4px 12px;
  background: var(--white);
  color: var(--volt-500);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}

.batch-toggle-btn:hover {
  background: var(--volt-50);
  border-color: var(--volt-300);
}

/* ชื่อใบกดได้ด้วย -- เป้าที่ใหญ่กว่าปุ่มเล็ก ๆ สำหรับการกระทำที่ทำบ่อย */
.batch-row-title {
  cursor: pointer;
  user-select: none;
}

/* สรุปย่อ ๆ ตอนย่อ: ถ้าเหลือแต่ "คำร้องที่ 3" ก็ไม่รู้ว่าใบไหนเป็นใบไหน
   กินพื้นที่ที่เหลือทั้งหมด และตัดด้วย ... เมื่อยาวเกิน แทนที่จะดันปุ่มลบตกบรรทัด */
.batch-row-summary {
  flex: 1;
  min-width: 0;
  font-size: 13px;
  color: var(--ink-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.batch-row.is-collapsed {
  padding: 10px 18px;
  background: var(--volt-50);
}

.batch-row.is-collapsed .batch-row-head {
  margin-bottom: 0;
}

/* ===== qr.html: เลขที่คำร้องหลายใบบนการ์ดเดียว (คำร้องกลุ่ม) ===== */

/* auto-fit เพื่อให้กลุ่มเล็กเรียงแถวเดียว กลุ่มใหญ่พับเป็นหลายคอลัมน์เอง
   โดยไม่ต้องมี breakpoint ของตัวเอง */
.qr-tracking-many {
  align-self: stretch;
  margin-top: 2px;
}

.qr-tracking-many[hidden] {
  display: none;
}

.qr-tracking-many-label {
  margin: 0 0 6px;
  font-size: 0.9rem;
  color: var(--ink);
}

.qr-tracking-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: 6px 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.qr-tracking-list[hidden] {
  display: none;
}

.qr-tracking-list li {
  font-family: var(--font-mono);
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--volt-700);
  text-align: center;
  padding: 4px 6px;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
}

/* เบอร์ติดต่อของเคาน์เตอร์ -- อยู่ใน .qr-card จึงติดไปกับกระดาษที่พิมพ์ออกมา
   คนที่สแกนแล้วติดขัดต้องมีที่ให้โทรถามบนแผ่นเดียวกัน */
.qr-contact {
  align-self: stretch;
  margin: 10px 0 0;
  padding-top: 10px;
  border-top: 1px solid var(--border);
  font-size: 0.85rem;
  text-align: center;
  color: var(--ink);
}

/* ===== track.html: ค่าธรรมเนียมตอนรอชำระเงิน ===== */

/* กฎ [hidden] ที่ขาดไม่ได้: .track-result-details > div ตั้ง display: flex ไว้
   ซึ่งชนะกฎ [hidden] ของเบราว์เซอร์เพราะ specificity เท่ากัน ถ้าไม่มีบรรทัดนี้
   แถวค่าธรรมเนียมจะโผล่ตลอดแม้ตอนที่ไม่มีค่าให้แสดง (ดูหัวข้อ Gotcha) */
.track-result-details > div[hidden] {
  display: none;
}

/* ยอดเงินคือสิ่งที่คนอ่านหน้านี้กำลังมองหาก่อนไปโอน จึงเน้นให้เห็นชัดกว่าแถวอื่น */
.track-fee {
  font-family: var(--font-mono);
  font-weight: 600;
  color: var(--volt-700);
}

/* ข้อความบอกว่าต้องติดต่อใครต่อ เมื่อคำร้องอยู่ในสถานะที่งานไปอยู่กับแผนกอื่นแล้ว
   ใช้โทน info เพราะเป็นข้อมูลที่ช่วยได้ ไม่ใช่คำเตือนหรือข้อผิดพลาด */
.track-status-note {
  margin: 14px 0 0;
  padding: 11px 14px;
  border-radius: 10px;
  border-left: 3px solid var(--info);
  background: var(--info-tint);
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--ink);
}

/* ข้อความติดต่อตามสถานะแยกเป็นสองบรรทัดเสมอ: บรรทัดแรกบอกว่าจะติดตามเรื่องอะไร
   บรรทัดที่สองคือเบอร์และแผนก -- แยกด้วย element ไม่ใช่ปล่อยให้ตัดบรรทัดตาม
   ความกว้างจอ เบอร์โทรจึงไม่มีทางถูกตัดคาบรรทัด */
.track-status-note-line {
  display: block;
}

.track-status-note-contact {
  margin-top: 2px;
  font-weight: 600;
}

/* ===== รหัสเชิญสำหรับสมัครสมาชิก (ผู้ดูแลระบบ) ===== */

.invite-status {
  margin: 0 0 12px;
  font-size: 13px;
  line-height: 1.7;
  color: var(--ink-soft);
}

.invite-code-box {
  margin: 0 0 14px;
  padding: 14px 16px;
  border-radius: 10px;
  background: var(--volt-50);
  border: 1px solid var(--volt-300);
  text-align: center;
}

/* .invite-code-box ไม่ได้ตั้ง display จึงยังไม่จำเป็น แต่ใส่ตามกฎ [hidden] ของ
   โปรเจกต์ เผื่อวันหลังมีคนเติม display ให้แล้วซ่อนไม่ลง (เคยพลาดมาห้าครั้ง) */
.invite-code-box[hidden] {
  display: none;
}

/* mono + user-select: all -- รหัสนี้ต้องอ่านออกเสียงหรือคัดลอกให้ถูกทุกตัว
   ฟอนต์ที่แยก 0/O และ 1/l ได้จึงสำคัญพอกับการเลือกได้ในคลิกเดียว */
.invite-code-value {
  margin: 0 0 6px;
  font-family: var(--font-mono);
  font-size: 26px;
  font-weight: 600;
  letter-spacing: 4px;
  color: var(--volt-700);
  user-select: all;
}

.invite-countdown {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--warning);
}

/* หน้าติดตามสถานะกว้างกว่าการ์ดเข้าสู่ระบบเล็กน้อย -- มีทั้งรายการผลลัพธ์
   บัญชีโอนเงิน และข้อความติดต่อ ซึ่งยาวกว่าฟอร์มสองช่องของหน้าเข้าสู่ระบบมาก */
.track-card {
  max-width: 480px;
}

/* เบอร์โทรและชื่อแผนกในวงเล็บห้ามถูกตัดกลางก้อน -- ที่จอแคบให้ขึ้นบรรทัดใหม่
   ทั้งก้อนแทน จะได้ไม่มีวงเล็บปิดห้อยอยู่บรรทัดเดียวโดด ๆ */
.track-status-note-part {
  white-space: nowrap;
}

/* ===== ปุ่มย้อนกลับมุมซ้ายบน (หน้าที่ไม่มีแถบบน) ===== */

/* หน้าแบบการ์ด (สมัครสมาชิก / บัญชีของฉัน / พิมพ์ QR) ไม่มี .topbar ให้วางปุ่ม
   จึงลอยไว้มุมเดียวกับปุ่มย้อนกลับของหน้าที่มีแถบบน เพื่อให้เป็นตำแหน่งเดียวกัน
   ทั้งระบบ ไม่ใช่สองความเคยชิน

   จุดยึดต่างกันสองแบบ และทั้งคู่ได้ผลเหมือนกัน: ใน index.html ปุ่มอยู่ใน
   .auth-view ซึ่งเป็น position: relative อยู่แล้ว จึงยึดกับ view นั้น
   ส่วนใน qr.html ปุ่มเป็นลูกของ body ตรง ๆ (.qr-page ไม่ได้เป็น relative)
   จึงยึดกับตัวหน้าเอง ซึ่งเป็นมุมเดียวกันพอดี */
.view-back-btn {
  position: absolute;
  top: 20px;
  left: 20px;
  z-index: 2;
  background: var(--white);
  text-decoration: none;
}

/* ปุ่มนี้เป็นของหน้าจอเท่านั้น ไม่ใช่ของกระดาษที่ลูกค้าถือกลับ */
@media print {
  .view-back-btn {
    display: none;
  }
}

@media (max-width: 640px) {
  .view-back-btn {
    top: 12px;
    left: 12px;
  }
}

/* ปุ่มย้อนกลับเหนือหัวข้อฟอร์มคำร้อง -- ชิดซ้ายบนของพื้นที่เนื้อหา ตำแหน่งเดียว
   กับปุ่มย้อนกลับของหน้าอื่น ดึงเข้าซ้ายและขึ้นบนเล็กน้อยให้เกาะขอบ ไม่ลอยกลาง */
.form-back-btn {
  /* .btn เป็น inline-flex และ <h2> ที่ตามมาเป็น block ปุ่มจึงอยู่บรรทัดของตัวเอง
     ชิดซ้ายอยู่แล้ว ไม่ต้องใช้ align-self (หัวข้อนี้ไม่ใช่ flex container) */
  margin: -4px 0 10px -10px;
  padding: 6px 10px;
  font-size: 13.5px;
}

/* ผู้สมัครรออนุมัติ (แผงของผู้ดูแลระบบในหน้าบัญชีของฉัน) */
.applicant-list { display: flex; flex-direction: column; gap: 10px; margin-top: 8px; }
.applicant-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap; padding: 10px 12px;
  border: 1px solid var(--volt-100); border-radius: 10px;
}
.applicant-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.applicant-info span { color: var(--ink-soft); font-size: 0.875rem; overflow-wrap: anywhere; }

/* ================================================================ โมดูลงานใหม่
   โบรชัวร์ธุรกิจเสริม / งานเสนอราคา / ระบบรับฟังเสียงของลูกค้า (PEA-VOC)
   ทั้งสามใช้โครงหน้าเดียวกับหน้ารายการคำร้อง (.work-main / .request-card /
   .status-chip) ส่วนที่เพิ่มตรงนี้คือชิ้นที่ไม่มีของเดิมให้ใช้จริง ๆ เท่านั้น */

/* ---------------------------------------------------------------- โบรชัวร์ */
.brochure-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 20px;
  margin-top: 20px;
}

.brochure-card {
  display: flex;
  flex-direction: column;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 14px;
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}

.brochure-thumb {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 200px;
  background: var(--volt-50);
}

.brochure-thumb img {
  width: 100%;
  height: 220px;
  object-fit: cover;
  cursor: zoom-in;
  display: block;
}

.brochure-thumb.is-empty {
  color: var(--muted);
  font-size: 14px;
}

.brochure-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 16px;
}

.brochure-body h3 { margin: 0; font-size: 16px; }

.brochure-desc {
  margin: 0;
  color: var(--muted);
  font-size: 14px;
  /* คำอธิบายยาวไม่ควรดันการ์ดให้สูงไม่เท่ากันทั้งแถว */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.brochure-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: auto;
}

.brochure-edit-images {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 12px 0;
}

.brochure-edit-image {
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: center;
}

.brochure-edit-image img {
  width: 120px;
  height: 120px;
  object-fit: cover;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--volt-50);
}

.brochure-viewer-image {
  display: block;
  width: 100%;
  max-height: 70vh;
  object-fit: contain;
  margin: 12px 0;
  border-radius: 8px;
  background: var(--volt-50);
}

/* รูปโบรชัวร์เต็มใบอ่านไม่ออกในกล่องกว้าง 420px ของ .modal-card เดิม */
.modal-card-wide {
  max-width: 720px;
  width: min(720px, calc(100vw - 32px));
  max-height: calc(100vh - 48px);
  overflow-y: auto;
}

.modal-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 20px;
}

/* ------------------------------------------------------------ งานเสนอราคา */
.field-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.field-section-head h3 { margin: 0; font-size: 16px; }

.form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 24px;
}

/* ================================================================ เมนูซ้ายย่อ/ขยาย
   ปุ่มถูกแทรกด้วย JS ที่หัวของทุก .requests-sidebar (ดู applySidebarCollapsed)
   ย่อแล้วเหลือแต่ไอคอน ชื่อเมนูยังเห็นได้จาก title ตอนชี้ */
.requests-sidebar { transition: width 0.15s ease; }

.sidebar-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  align-self: flex-end;
  margin-bottom: 6px;
  padding: 6px 10px;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--ink-soft);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}

.sidebar-toggle:hover { background: var(--volt-50); color: var(--volt-700); }
.sidebar-toggle svg { width: 18px; height: 18px; flex-shrink: 0; }

.requests-sidebar.is-collapsed {
  width: 64px;
  padding-left: 8px;
  padding-right: 8px;
}

.requests-sidebar.is-collapsed .nav-label,
.requests-sidebar.is-collapsed .sidebar-toggle-label { display: none; }

.requests-sidebar.is-collapsed .sidebar-toggle { align-self: center; }

.requests-sidebar.is-collapsed .requests-nav-item {
  position: relative;
  justify-content: center;
  padding: 11px 0;
}

/* ตัวเลขแจ้งเตือนเกาะมุมไอคอนแทน เพราะไม่มีที่ว่างข้างชื่อเมนูแล้ว */
.requests-sidebar.is-collapsed .nav-badge {
  position: absolute;
  top: 3px;
  right: 3px;
  margin: 0;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  font-size: 10px;
}

/* จอแคบเมนูเป็นแถบแนวนอนอยู่แล้ว ย่อไม่มีความหมาย -- ซ่อนปุ่มและแสดงเต็มเสมอ */
@media (max-width: 860px) {
  .sidebar-toggle { display: none; }
  .requests-sidebar.is-collapsed { width: 100%; padding: 8px 12px; }
  .requests-sidebar.is-collapsed .nav-label { display: inline; }
  .requests-sidebar.is-collapsed .requests-nav-item { justify-content: flex-start; padding: 10px 12px; }
  .requests-sidebar.is-collapsed .nav-badge {
    position: static; min-width: 20px; height: 20px; padding: 0 6px; font-size: 11px; margin-left: 2px;
  }
}

/* ================================================================ ใบเสนอราคา
   หน้ากระดาษ A4 ตาม "แบบที่ 1 หนังสือภายนอกภาษาไทย" ของระเบียบงานสารบรรณ กฟภ.
   ขนาดทุกตัวเป็น mm/cm/pt จริง ไม่ใช่ px -- หน้าจอกับกระดาษที่พิมพ์ออกมาจึง
   ตรงกันทั้งระยะขอบ ระยะย่อหน้า และการตัดบรรทัด (ฟอร์มพิมพ์ใช้ stylesheet
   ไฟล์นี้ไฟล์เดียวกัน ดู printQuotation ใน app.js)

   ฟอนต์ฝังมากับเว็บ (assets/fonts) ไม่พึ่งเครื่องที่เปิด -- TH Sarabun New คือ
   ฟอนต์มาตรฐานหนังสือราชการ ส่วน TH SarabunIT๙ หน้าตาเหมือนกันทุกตัวอักษร
   ต่างแค่วาดเลข 0-9 เป็นเลขไทย ๐-๙ ติ๊ก "เลขไทย" = สลับไปใช้ฟอนต์นี้ทั้งหน้า
   ไม่ต้องแปลงข้อความจริง ข้อมูลที่บันทึกยังเป็นเลขอารบิกเสมอ ค้นหาได้ตามปกติ */
@font-face { font-family: "QuoSarabun"; src: url("assets/fonts/THSarabunNew.ttf") format("truetype"); font-weight: 400; font-display: block; }
@font-face { font-family: "QuoSarabun"; src: url("assets/fonts/THSarabunNew-Bold.ttf") format("truetype"); font-weight: 700; font-display: block; }
@font-face { font-family: "QuoSarabunIT9"; src: url("assets/fonts/THSarabunIT9.ttf") format("truetype"); font-weight: 400; font-display: block; }
@font-face { font-family: "QuoSarabunIT9"; src: url("assets/fonts/THSarabunIT9-Bold.ttf") format("truetype"); font-weight: 700; font-display: block; }

/* แถบเครื่องมือเหนือกระดาษ -- ติดอยู่บนสุดตอนเลื่อนอ่านเอกสารยาว ๆ */
.quo-editor-bar {
  position: sticky;
  top: var(--topbar-h);
  z-index: 4;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  padding: 12px 0;
  background: var(--paper);
  border-bottom: 1px solid var(--border);
}

.quo-editor-title { flex: 1; min-width: 180px; }
.quo-editor-title h2 { margin: 0; font-size: 20px; }
.quo-editor-title p { margin: 2px 0 0; }

.quo-editor-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.quo-bar-field { display: inline-flex; align-items: center; gap: 6px; font-size: 14px; }
.quo-bar-field select { font: inherit; padding: 6px 8px; border-radius: 8px; border: 1px solid var(--border); background: var(--white); }
.quo-bar-field[hidden] { display: none; }
.quo-bar-check { margin: 0; }

.quo-dirty {
  font-size: 13px;
  font-weight: 600;
  color: var(--warning);
}
.quo-dirty[hidden] { display: none; }

.quo-editor-hint { margin: 10px 0 0; }

/* พื้นเทาให้กระดาษขาวลอยเด่นเหมือนหน้าจอ Word -- สองคอลัมน์: กระดาษแก้ไข |
   ตัวอย่างหน้าพิมพ์ กระดาษแก้ไขเลื่อนแนวนอนได้บนจอแคบแทนการย่อ (ย่อแล้วตัด
   บรรทัดไม่ตรงกับที่พิมพ์ออกมา) ส่วนตัวอย่างย่อได้ เพราะจัดหน้าที่ขนาดจริงเสมอ */
.quo-workspace {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: 20px;
  margin: 16px -28px 0;
  padding: 24px 28px 40px;
  background: #e9e6ef;
}

.quo-paper-wrap {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 100%;
  overflow-x: auto;
}

/* แถบเครื่องมือของเนื้อเอกสาร (เพิ่มแถว, รายการราคา, VAT, อ้างถึง...) -- อยู่นอก
   กระดาษ เพื่อให้บนกระดาษมีแต่สิ่งที่จะพิมพ์ หน้าบนจอจึงตรงกับหน้าที่พิมพ์ */
.quo-doc-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  margin-top: 12px;
  font-size: 13px;
}
.quo-doc-tools .btn { padding: 6px 12px; font-size: 13px; }
.quo-doc-tools .checkbox-field { margin: 0; }
.quo-doc-tools-sep { width: 1px; height: 22px; background: var(--border); }
.quo-page-count { margin-left: auto; font-weight: 600; color: var(--volt-700); }

.quo-paper {
  --qd-indent: 2.5cm;
  position: relative;
  box-sizing: border-box;
  width: 210mm;
  min-height: 297mm;
  margin: 0 auto;
  /* บน 1.5 / ขวา 2 / ล่าง 2 / ซ้าย 3 ซม. ตามแบบที่ 1 */
  padding: 15mm 20mm 20mm 30mm;
  background-color: #fff;
  box-shadow: 0 4px 18px rgba(34, 21, 48, 0.18);
  color: #000;
  font-family: "QuoSarabun", "TH Sarabun New", "TH SarabunPSK", Sarabun, sans-serif;
  font-size: 16pt;
  line-height: 1.15;
}

.quo-paper.is-thai-digits {
  font-family: "QuoSarabunIT9", "TH SarabunIT๙", "QuoSarabun", Sarabun, sans-serif;
}

.quo-paper p { margin: 0; }

/* ช่องที่แก้ได้ -- กรอบประจาง ๆ ให้รู้ว่าคลิกได้ ชี้แล้วเข้มขึ้น กำลังพิมพ์เป็นกรอบทึบ */
.qf {
  outline: 1px dashed #d4c8ea;
  outline-offset: 1px;
  border-radius: 2px;
  min-width: 1.5em;
  cursor: text;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.qf:hover { outline-color: #a78bda; }
.qf:focus { outline: 1.5px solid #7c4dbf; background: #faf7ff; }
.qf:empty::before {
  content: attr(data-placeholder);
  color: #a79fb5;
  pointer-events: none;
}
/* ช่องบรรทัดเดียวที่อยู่กลางประโยค ต้องเป็น inline-block ถึงจะคลิกได้ตอนว่าง */
span.qf { display: inline-block; vertical-align: top; }

.qd-urgency {
  position: absolute;
  top: 25mm;
  left: 80mm;
  min-width: 30mm;
  color: #d10000;
  font-size: 32pt;
  font-weight: 700;
  line-height: 1;
}
.qd-urgency:empty::before { font-size: 14pt; font-weight: 400; }

/* ตรา + ชื่อหน่วยงาน สูง 3.5 ซม. (1.5 ถึง 5 ซม. จากขอบบน ตามแบบที่ 1) */
.qd-head { height: 35mm; }
.qd-seal { display: block; height: 35mm; width: auto; }

.qd-refrow {
  display: flex;
  align-items: flex-start;
  gap: 8mm;
  margin-top: 6pt;
}
.qd-ref { flex: 1; }
.qd-gap2 { display: inline-block; width: 0.6em; }
/* หน่วยงานเจ้าของหนังสือเริ่มที่ราว 13 ซม. จากขอบซ้ายกระดาษ */
.qd-sender { width: 60mm; flex-shrink: 0; }

/* วันที่เริ่มที่กึ่งกลางพื้นที่พิมพ์ */
.qd-date { margin-top: 12pt; padding-left: 50%; }

.qd-line {
  display: flex;
  align-items: flex-start;
  gap: 1.1em;
  margin-top: 6pt;
}
.qd-date + .qd-line { margin-top: 12pt; }
.qd-label { flex-shrink: 0; }
.qd-fill { flex: 1; }

/* จัดแบบ "กระจายแบบไทย" ของ Word: เว้นวรรคที่พิมพ์ต้องอยู่ครบ (pre-wrap -- ปกติ HTML
   ยุบหลายช่องเป็นช่องเดียว เคาะ spacebar ดันคำลงบรรทัดใหม่จึงไม่ได้ผล) บรรทัดที่ถูก
   ดันขาดจะกระจายตัวอักษรเต็มบรรทัด (inter-character) บรรทัดสุดท้ายชิดซ้ายตามปกติ */
.qd-para {
  margin-top: 6pt;
  text-indent: var(--qd-indent);
  white-space: pre-wrap;
  text-align: justify;
  text-justify: inter-character;
  text-align-last: left;
}
.qd-para > div + div { margin-top: 6pt; }
.qd-para-first { margin-top: 12pt; }
/* placeholder ไม่ต้องย่อหน้า -- ไม่งั้นข้อความแนะนำโดนดันไปกลางบรรทัด */
.qd-para:empty { text-indent: 0; }

/* ---------------------------------------------------------------- ตาราง */
.qd-table {
  width: 100%;
  margin-top: 8pt;
  border-collapse: collapse;
  table-layout: fixed;
  font-size: 14pt;
  line-height: 1.1;
}
.qd-col-no { width: 13mm; }
.qd-col-price { width: 25mm; }
.qd-col-qty { width: 16mm; }
.qd-col-amount { width: 27mm; }
.qd-table th,
.qd-table td {
  border: 0.75pt solid #000;
  padding: 1.5pt 4pt;
  vertical-align: top;
}
.qd-table th {
  background: #dbe5f1;
  font-weight: 700;
  text-align: center;
  vertical-align: middle;
}
.qd-table tbody tr { break-inside: avoid; }
.qd-table td.qd-no { text-align: center; }
.qd-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.qd-table td.qd-center { text-align: center; }
.qd-table tfoot td { font-weight: 700; }
.qd-sum-label { text-align: center; }
.qd-table td .qf { display: block; outline-offset: -1px; min-height: 1.1em; }
.qd-row { position: relative; }
/* ปุ่มลบแถวอยู่นอกตาราง (ในขอบซ้ายของกระดาษ) ไม่เบียดคอลัมน์ */
.qd-row-del {
  position: absolute;
  left: -9mm;
  top: 1pt;
  width: 7mm;
  height: 7mm;
  padding: 0;
  border: 1px solid #e2c6c6;
  border-radius: 50%;
  background: #fff;
  color: #b42318;
  font: 700 12px/1 system-ui, sans-serif;
  cursor: pointer;
  opacity: 0.35;
}
.qd-row:hover .qd-row-del,
.qd-row-del:focus { opacity: 1; }
.qd-table-empty td { text-align: center; color: #a79fb5; font-size: 13pt; }

/* ---------------------------------------------------------------- ลงท้าย */
.qd-signoff { break-inside: avoid; }
.qd-closing { margin-top: 12pt; padding-left: 50%; }
.qd-sign {
  margin-left: 30%;
  width: 54%;
  text-align: center;
}
/* ที่ว่างลงลายมือชื่อ ~4 บรรทัดตามแบบ ("4 Enter") */
.qd-sign-space { height: 2.6cm; }
.qd-sign .qf { display: block; }

/* ส่วนราชการเจ้าของเรื่อง อยู่ใต้ตำแหน่ง "4 Enter" ตามแบบ (เจ้าของระบบยืนยัน 2026-09-29)
   หนึ่ง Enter = หนึ่งบรรทัดเนื้อความ (1.15em ของ 16 pt) 4 บรรทัด ≈ 2.6 ซม. -- นับแบบเดียว
   กับ .qd-sign-space ปรับรายใบได้จากแถบเครื่องมือ (#quoOwnerGap -> --qd-owner-lines
   ตั้งบนตัว element เอง จึงติดไปกับ outerHTML ตอนพิมพ์ด้วย) 0 = ติดบรรทัดตำแหน่ง */
.qd-owner { margin-top: calc(var(--qd-owner-lines, 4) * 1.15em); width: 70%; }

/* ---------------------------------------------------------------- รายการ/แท็บ */
.quo-template-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.quo-template-actions .btn { padding: 6px 12px; font-size: 13px; }

/* ตารางรายการราคา (แท็บ "รายการราคา") -- แก้ในตารางได้ทันที กดบันทึกทีละแถว */
.price-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  font-size: 14px;
}
.price-table th,
.price-table td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  text-align: left;
  vertical-align: middle;
}
.price-table th { background: var(--volt-50); font-weight: 600; color: var(--volt-700); }
.price-table input {
  width: 100%;
  box-sizing: border-box;
  padding: 6px 8px;
  border: 1px solid transparent;
  border-radius: 6px;
  font: inherit;
  background: transparent;
}
.price-table input:hover { border-color: var(--border); }
.price-table input:focus { border-color: var(--volt-500); background: var(--white); outline: none; }
.price-table .price-col-price input { text-align: right; font-variant-numeric: tabular-nums; }

/* ชื่อรายการ -- <textarea> ขยายสูงอัตโนมัติแทน <input> บรรทัดเดียว (ดู
   autosizeTextarea() ใน app.js) เพราะชื่อรายการยาวเดิมถูกตัด เห็นแค่ต้นบรรทัด
   resize ปิดไว้เพราะความสูงคุมโดยสคริปต์อยู่แล้ว ลากเองจะขัดกัน */
.price-table textarea.price-name-input {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: 6px 8px;
  border: 1px solid transparent;
  border-radius: 6px;
  font: inherit;
  line-height: 1.35;
  background: transparent;
  resize: none;
  overflow: hidden;
}
.price-table textarea.price-name-input:hover { border-color: var(--border); }
.price-table textarea.price-name-input:focus { border-color: var(--volt-500); background: var(--white); outline: none; }
.price-table .price-col-cat { width: 20%; }
.price-table .price-col-price { width: 15%; }
.price-table .price-col-actions { width: 150px; white-space: nowrap; text-align: right; }
.price-table .price-col-actions .btn { padding: 5px 10px; font-size: 13px; }
.price-row-dirty { background: #fffbeb; }
.price-group-row td {
  background: #f4f1f9;
  font-weight: 600;
  color: var(--ink-soft);
  font-size: 13px;
}

/* ตัวเลือกรายการราคาในหน้าต่างเลือก */
.quo-price-search {
  width: 100%;
  box-sizing: border-box;
  margin: 10px 0;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font: inherit;
}
.quo-price-list {
  max-height: 55vh;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 10px;
}
.quo-price-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
  font-size: 14px;
}
.quo-price-item:last-child { border-bottom: none; }
.quo-price-item-name { flex: 1; }
.quo-price-item-cat { display: block; color: var(--ink-soft); font-size: 12px; }
.quo-price-item-price { font-variant-numeric: tabular-nums; white-space: nowrap; }
.quo-price-item .btn { padding: 5px 10px; font-size: 13px; }
.quo-price-group {
  padding: 6px 12px;
  background: #f4f1f9;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink-soft);
}

/* ---------------------------------------------------------------- พิมพ์
   หน้าต่างพิมพ์ใช้ stylesheet นี้ไฟล์เดียวกัน (body.quo-print-body) และจัดหน้าเอง
   ทีละแผ่น (paginateQuotation ใน app.js) -- แต่ละ .qp-sheet คือกระดาษ A4 หนึ่งแผ่น
   พอดี ขอบกระดาษอยู่ใน padding ของแผ่น @page จึงตั้งขอบเป็น 0 (named page
   "quosheet" -- ไม่ไปกระทบการพิมพ์หน้าอื่นของแอป)

   หน้าที่ 2 ขึ้นไป: "- ๒ -" กลางบน แล้วบรรทัดถัดมาเว้นก่อน 6 pt ตามแบบหนังสือราชการ
   ทุกหน้าที่ยังไม่จบ: คำต่อ "/คำแรก ๆ ของหน้าถัดไป..." มุมล่างขวา */
body.quo-print-body {
  margin: 0;
  padding: 24px 0;
  background: #e9e6ef;
  font-family: var(--font-body);
}
.quo-print-toolbar {
  width: 210mm;
  margin: 0 auto 16px;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 12px;
}
.qp-status { font-size: 14px; color: var(--ink-soft); }

.qp-sheet.quo-paper {
  display: flex;
  flex-direction: column;
  height: 297mm;
  min-height: 0;
  margin: 0 auto 24px;
  background-image: none;
  overflow: hidden;
  page: quosheet;
  break-after: page;
}
.qp-sheet.quo-paper:last-child { break-after: auto; }

.qp-pageno {
  text-align: center;
  flex-shrink: 0;
}

/* พื้นที่เนื้อหาของแผ่น -- เว้นท้ายไว้หนึ่งบรรทัดสำหรับคำต่อ (9 มม.) */
.qp-body {
  flex: 1;
  min-height: 0;
  margin-bottom: 9mm;
}
/* ก้อนแรกของแผ่นไม่มีระยะบน -- หน้า 2+ ได้ระยะ 6 pt จากเลขหน้าแทน */
.qp-body > :first-child { margin-top: 0; }
.qp-pageno + .qp-body { margin-top: 6pt; }

.qp-cont {
  position: absolute;
  right: 20mm;
  bottom: 20mm;
  line-height: 9mm;
}

/* ย่อหน้าที่ถูกตัดข้ามหน้า: ส่วนแรกเกลี่ยบรรทัดสุดท้ายเต็มบรรทัด ส่วนที่ต่อไม่ย่อหน้าซ้ำ */
.qp-split-head { text-align-last: justify; }
.qp-split-tail { text-indent: 0; }
/* ส่วนต่อของช่องย่อหน้าที่ถูกตัดตรงข้อความเปล่า -- ย่อหน้าถัด ๆ ไปยังต้องย่อ 2.5 ซม. */
.qd-para.qp-split-tail > div { text-indent: var(--qd-indent); }

@page quosheet {
  size: A4;
  margin: 0;
}

@media print {
  body.quo-print-body { padding: 0; background: #fff; }
  .quo-print-toolbar { display: none; }
  .qp-sheet.quo-paper {
    margin: 0;
    box-shadow: none;
  }
}

/* ================================================================ รอยต่อหน้าบนกระดาษแก้ไข
   paginateQuoPaper แทรก .qd-gap ตรงบรรทัดที่เลยท้ายหน้า -- ความสูงของแต่ละส่วนต้องตรง
   กับ .qp-sheet ตอนพิมพ์ (ท้ายเนื้อหา 268 มม. / คำต่อ 9 / ขอบล่าง 20 / ขอบบน 15 /
   เลขหน้า 1 บรรทัด / เว้น 6 pt) บรรทัดหลังรอยต่อจึงอยู่ตำแหน่งเดียวกับบนกระดาษจริง */
.qd-gap {
  display: block;
  text-indent: 0;
  text-align: left;
  /* รอยต่อที่ตกกลางย่อหน้าจะรับค่าจาก .qd-para -- ต้องคืนสองค่านี้ ไม่งั้นคำต่อ
     (ชิดขวา) กับเลขหน้า (กึ่งกลาง) ถูก text-align-last: left ดึงไปชิดซ้าย และ
     pre-wrap จะแสดงช่องว่างในโครงรอยต่อจนความสูงหน้าคลาดจากกระดาษจริง */
  text-align-last: auto;
  white-space: normal;
  font-size: 16pt;
  font-weight: 400;
  line-height: 1.15;
  user-select: none;
  cursor: default;
}
/* รอยต่อกลางย่อหน้า -- กินเต็มบรรทัด ดันข้อความที่เหลือลงบรรทัดถัดไป (หน้าถัดไป) */
.qd-gap-inline {
  display: inline-block;
  width: 100%;
  vertical-align: top;
}
.qd-gap > span { display: block; }
.qd-gap-cont { height: 9mm; line-height: 9mm; text-align: right; }
.qd-gap-bottom { height: 20mm; }
/* ช่องเทาระหว่างแผ่น -- กว้างเต็มกระดาษ (ยื่นออกไปทับขอบซ้าย 30 / ขวา 20 มม.) */
.qd-gap-band {
  height: 10mm;
  width: 210mm;
  margin-left: -30mm;
  background: #e9e6ef;
  box-shadow: inset 0 7px 6px -6px rgba(34, 21, 48, 0.28), inset 0 -7px 6px -6px rgba(34, 21, 48, 0.28);
}
.qd-gap-top { height: 15mm; }
.qd-gap-pageno { text-align: center; }
.qd-gap-after { height: 6pt; }
/* บรรทัดแรกของหน้าใหม่ไม่มีระยะบนของตัวเอง -- ใช้ 6 pt หลังเลขหน้าแทน (เหมือนตอนพิมพ์) */
.qd-gap + * { margin-top: 0 !important; }

/* คำต่อท้ายหน้าแก้ได้ */
.qd-cont {
  display: inline-block;
  min-width: 3em;
  padding: 0 2px;
  outline: 1px dashed #d4c8ea;
  outline-offset: 1px;
  cursor: text;
  user-select: text;
}
.qd-cont:hover { outline-color: #a78bda; }
.qd-cont:focus { outline: 1.5px solid #7c4dbf; background: #faf7ff; }

/* ตาราง: แถวรอยต่อไม่มีเส้น, หัวตารางซ้ำต้นหน้าใหม่ */
.qd-table tr.qd-gap-row > td.qd-gap-cell {
  padding: 0;
  border: none;
}
.qd-table tr.qd-gap-head > th {
  background: #dbe5f1;
  font-weight: 700;
  text-align: center;
  vertical-align: middle;
}

/* อ้างถึง / สิ่งที่ส่งมาด้วย ที่ยังว่าง -- ซ่อน (ไม่กินบรรทัด) จนกว่าจะกดเพิ่มจากแถบเครื่องมือ */
.qd-line.qd-off { display: none; }

/* ============================================================================
   งวดราคาอุปกรณ์/ค่าแรง + เครื่องคำนวณราคา EV Charger วงจรที่ 2
   (งานธุรกิจเสริม -> แท็บ "ราคาและค่าแรง" / "คำนวณราคา EV Charger")
   ============================================================================ */

/* ---- รายการงวดราคา (บนสุดของแท็บ "ราคาและค่าแรง") -------------------------- */
.book-section-head {
  margin: 28px 0 10px;
  font-size: 15px;
  color: var(--ink-soft);
  border-top: 1px solid var(--border);
  padding-top: 20px;
}
.book-list-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
}
.book-list-head h3 { margin: 0; font-size: 16px; }

.book-card {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 16px;
  padding: 14px 16px;
  margin-bottom: 10px;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 12px;
}
.book-card.is-current { border-color: var(--volt-300); background: var(--volt-50); }
.book-card-info { min-width: 0; }
.book-card-name {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  color: var(--ink);
}
.book-card-meta { margin-top: 3px; font-size: 13px; color: var(--ink-soft); }
.book-card-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.book-card-actions .btn { padding: 6px 12px; font-size: 13px; }

/* ---- หน้าแก้ไขงวดราคา (#priceBookMode) ------------------------------------- */
.book-meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 14px;
  margin: 16px 0 24px;
}

.book-rates {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 24px;
  margin-bottom: 28px;
}
.book-rates h3 { margin: 0 0 10px; font-size: 15px; }
.book-overhead { max-width: 420px; margin-bottom: 12px; }
.book-labour-table th:first-child, .book-labour-table td:first-child { width: 90px; }
.book-tier-table .price-col-price { width: 45%; }

.book-items-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 8px 0 10px;
}
.book-items-head h3 { margin: 0; font-size: 15px; }
.book-items-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.book-items-tools input[type="search"] {
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font: inherit;
  min-width: 200px;
}
.book-items-tools .btn { padding: 6px 12px; font-size: 13px; }
.book-item-table .book-col-unit { width: 90px; }
.book-item-table .book-col-brand { width: 130px; }

.price-paste-input {
  width: 100%;
  box-sizing: border-box;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font: inherit;
  font-family: var(--font-mono, monospace);
  font-size: 13px;
  resize: vertical;
}

/* ---- เครื่องคำนวณราคา EV Charger (#evCalcMode) ----------------------------- */
.ev-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 24px;
  align-items: start;
}
@media (max-width: 960px) {
  .ev-layout { grid-template-columns: 1fr; }
}

.ev-setup {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 14px;
  margin-bottom: 18px;
}

.ev-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 16px;
  margin-bottom: 12px;
}
.ev-toolbar input[type="search"] {
  flex: 1;
  min-width: 200px;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font: inherit;
}
.ev-toolbar .checkbox-field { margin: 0; white-space: nowrap; }
.ev-picked-count { font-size: 13px; font-weight: 600; color: var(--volt-700); white-space: nowrap; }

.ev-items {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--white);
  overflow: hidden;
}
/* หัวหมวด -- ปุ่มย่อ/ขยาย ไม่ใช่แค่ป้ายชื่อ เริ่มต้นย่อทุกหมวดยกเว้นหมวดแรก
   (ดู resetEvGroupCollapse() ใน app.js) เพราะงวดหนึ่งมีอุปกรณ์เป็นสิบหมวด
   เปิดมาเห็นเต็มหน้าจอทันทีจะหาของที่ต้องการยากกว่าไล่เปิดทีละหมวด */
.ev-group {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  margin: 0;
  padding: 8px 14px;
  background: var(--volt-50);
  border: none;
  border-bottom: 1px solid var(--border);
  border-top: 1px solid var(--border);
  color: var(--volt-700);
  font: inherit;
  font-weight: 600;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}
.ev-group:hover { background: var(--volt-100); }
.ev-group:first-child { border-top: none; }
.ev-group-arrow {
  flex: none;
  display: inline-block;
  font-size: 11px;
  transition: transform 0.15s ease;
}
.ev-group.is-collapsed .ev-group-arrow { transform: rotate(-90deg); }
.ev-group-label { flex: 1; min-width: 0; }
.ev-group-count {
  flex: none;
  font-weight: 400;
  font-size: 12px;
  color: var(--ink-soft);
}

.ev-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 140px 130px 100px;
  gap: 10px;
  align-items: center;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
}
.ev-item:last-child { border-bottom: none; }
.ev-item.is-picked { background: var(--volt-50); }
.ev-item-name { min-width: 0; overflow-wrap: break-word; }
.ev-item-brand {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  color: var(--ink-soft);
}
.ev-item-price {
  font-size: 13px;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.ev-item-qty { display: flex; align-items: center; gap: 4px; justify-content: center; }
.ev-step {
  width: 26px;
  height: 26px;
  flex: none;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--white);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  color: var(--volt-700);
}
.ev-step:hover { border-color: var(--volt-300); background: var(--volt-50); }
.ev-qty-input {
  width: 48px;
  text-align: center;
  padding: 5px 4px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font: inherit;
  font-variant-numeric: tabular-nums;
}
.ev-item-amount {
  text-align: right;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--volt-700);
  min-height: 1em;
}
@media (max-width: 640px) {
  .ev-item { grid-template-columns: 1fr; row-gap: 6px; }
  .ev-item-price, .ev-item-amount { text-align: left; }
  .ev-item-qty { justify-content: flex-start; }
}

.ev-summary {
  position: sticky;
  top: calc(var(--topbar-h) + 12px);
  padding: 16px;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 12px;
}
.ev-summary h3 { margin: 0 0 12px; font-size: 15px; }
.ev-summary-list {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 6px 10px;
  margin: 0;
}
.ev-summary-list dt { color: var(--ink-soft); font-size: 13px; }
.ev-summary-list dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }
.ev-summary-hint { display: block; font-size: 11px; color: var(--ink-soft); }
.ev-summary-list dt.is-sub, .ev-summary-list dd.is-sub {
  padding-top: 6px;
  margin-top: 4px;
  border-top: 1px dashed var(--border);
  font-weight: 600;
}
.ev-summary-list dt.is-say, .ev-summary-list dd.is-say {
  padding-top: 8px;
  margin-top: 6px;
  border-top: 1px solid var(--border);
  font-weight: 700;
  color: var(--volt-700);
}
.ev-summary-list dt.is-grand, .ev-summary-list dd.is-grand {
  padding-top: 8px;
  margin-top: 6px;
  border-top: 2px solid var(--volt-500);
  font-weight: 700;
  font-size: 16px;
  color: var(--volt-700);
}

/* ---------------------------- คำนวณราคาอุปกรณ์ป้องกัน (ติดตั้ง / รื้อถอน) ---
   ใช้โครงเดียวกับเครื่องคำนวณ EV (.ev-layout / .ev-item / .ev-summary) ต่างกันที่
   แต่ละแถวต้องบอกด้วยว่าราคาที่ใช้มาจากทางไหน (ประมาณการ กฟภ. หรือราคาสืบ) */
.protect-maintenance {
  margin: 0 0 14px;
  padding: 10px 14px;
  background: var(--warning-tint);
  border: 1px solid var(--warning);
  border-radius: 10px;
}

.protect-item .ev-item-price { line-height: 1.3; }
.protect-src {
  display: block;
  margin-top: 2px;
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-soft);
}
.ev-item.is-picked .protect-src { color: var(--volt-700); }

/* แถวที่ยังไม่มีทั้งราคาประมาณการและราคาสืบ -- ใส่จำนวนไม่ได้จนกว่าจะมีราคา */
.ev-item.protect-no-price { opacity: 0.6; }
.ev-item.protect-no-price .protect-src { color: var(--danger); }

.protect-period-pick {
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font: inherit;
  background: var(--white);
}

/* คอลัมน์ราคาทั้งสี่ของตารางนี้ใช้ความกว้างคงที่แทน 15% ของ .price-table --
   สี่ช่องรวมกันกิน 60% จนคอลัมน์ "รายการ" เหลือแคบเกินกว่าจะอ่านชื่อเต็มได้
   ชื่อรายการเป็นข้อความยาวที่สุดในตาราง จึงให้มันกินพื้นที่ที่เหลือทั้งหมด */
.protect-table { table-layout: fixed; }
.protect-table .protect-col-code { width: 120px; }
.protect-table .price-col-price { width: 104px; }
.protect-table .protect-col-survey { width: 180px; text-align: right; }
.protect-table .price-col-actions { width: 132px; }
.protect-table .protect-net {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--volt-700);
  text-align: right;
}
/* ปุ่มราคาสืบมีทั้งราคาและวันที่ -- ยอมให้ตัดบรรทัดได้ ดีกว่าล้นออกนอกคอลัมน์
   เพราะตารางนี้เป็น table-layout: fixed ความกว้างคอลัมน์ไม่ขยายตามเนื้อหา */
.protect-survey-btn {
  width: 100%;
  padding: 6px 8px;
  font-size: 13px;
  line-height: 1.3;
  text-align: center;
}
.protect-col-date { width: 160px; }

/* แถวราคาสืบที่ระบบใช้จริง (วันที่ใหม่สุด) -- ประวัติเก่ายังอยู่ครบแต่ไม่ถูกใช้ */
.protect-survey-latest { background: var(--success-tint); }
.protect-survey-latest td:first-child::after {
  content: " (ใช้ราคานี้)";
  font-size: 12px;
  color: var(--success);
  font-weight: 600;
}

/* ============================================================ งานของฉัน ===
   รวมงานจากทุกโมดูลมาหน้าเดียว -- ใช้โครงเดียวกับหน้างานอื่น (.requests-layout /
   .requests-sidebar) ส่วนที่เพิ่มคือชิ้นที่ไม่มีของเดิมให้ใช้ */
.mywork-section-head {
  margin: 24px 0 10px;
  font-size: 15px;
  color: var(--ink-soft);
}
.mywork-attention .mywork-section-head:first-child { margin-top: 0; }

/* ① งานที่ต้องสะกิด -- แถวเดียวจบ อ่านจากซ้ายไปขวาได้ทันทีว่างานอะไร สถานะไหน
      และทำไมถึงขึ้นมาอยู่ตรงนี้ */
.mywork-attention-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  margin-bottom: 8px;
  padding: 12px 14px;
  background: var(--white);
  border: 1px solid var(--border);
  border-left: 4px solid var(--warning);
  border-radius: 10px;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.mywork-attention-row:hover { border-color: var(--volt-300); background: var(--volt-50); }
.mywork-attention-row.is-urgent { border-left-color: var(--danger); }
.mywork-attention-main { flex: 1; min-width: 0; }
.mywork-attention-title { font-weight: 600; color: var(--ink); }
.mywork-attention-meta { margin-top: 2px; font-size: 13px; color: var(--ink-soft); }
.mywork-reason {
  flex: none;
  font-size: 13px;
  font-weight: 600;
  color: var(--warning);
  white-space: nowrap;
}
.mywork-attention-row.is-urgent .mywork-reason { color: var(--danger); }

/* ② การ์ดนับจำนวนต่อประเภทงาน */
.mywork-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px;
  margin-top: 20px;
}
.mywork-tile {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 16px;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 12px;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.mywork-tile:hover { border-color: var(--volt-300); background: var(--volt-50); }
.mywork-tile strong { font-size: 26px; color: var(--volt-700); line-height: 1; }
.mywork-tile span { font-size: 13px; color: var(--ink-soft); }

/* ③ คิวรอสำรวจ */
.mywork-queue-row {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  margin-bottom: 6px;
  padding: 8px 12px;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 8px;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.mywork-queue-row:hover { border-color: var(--volt-300); }
.mywork-queue-no {
  flex: none;
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--volt-500);
  color: var(--white);
  font-size: 12px;
  font-weight: 700;
}

/* แถวงานทั่วไป -- ใช้ทั้งหน้างานในมือ ที่ฉันเพิ่งแตะ และตารางทีม */
.mywork-status-group { margin-bottom: 14px; }
.mywork-status-group > .request-badge { margin-bottom: 6px; }
.mywork-job-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  margin-bottom: 4px;
  padding: 8px 12px;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 8px;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.mywork-job-row:hover { border-color: var(--volt-300); background: var(--volt-50); }
/* งานที่ไม่คืบหน้าเกินจำนวนวันที่ตั้งไว้ -- เห็นได้จากการไล่สายตาลงมาโดยไม่ต้องอ่านเลข */
.mywork-job-row.is-stale { border-left: 4px solid var(--warning); }
.mywork-job-name { min-width: 0; overflow-wrap: break-word; }
.mywork-job-age {
  flex: none;
  font-size: 12px;
  color: var(--ink-soft);
  white-space: nowrap;
}

/* ④ ตาราง Work Load ของทีม */
.mywork-team-table { margin-bottom: 12px; }
.mywork-team-table .mywork-num { width: 110px; text-align: right; font-variant-numeric: tabular-nums; }
.mywork-team-table td.mywork-total { font-weight: 700; color: var(--volt-700); }
.mywork-team-table td.mywork-stale { font-weight: 700; color: var(--danger); }
.mywork-team-row.is-me { background: var(--volt-50); }
.mywork-team-row.is-unassigned { background: var(--warning-tint); }
.mywork-person-btn {
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  font-weight: 600;
  color: var(--volt-700);
  text-align: left;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}
/* แถบสัดส่วนภาระ -- เทียบกันด้วยสายตาเร็วกว่าอ่านตัวเลขทีละช่อง */
.mywork-load-bar {
  height: 4px;
  margin-top: 6px;
  border-radius: 2px;
  background: var(--volt-100);
  overflow: hidden;
}
.mywork-load-bar span {
  display: block;
  height: 100%;
  background: var(--volt-500);
}
.mywork-person-detail { background: var(--paper); }

/* ============================================================ ลูกค้า (CRM) ===
   สามชั้น: ลูกค้า -> สถานที่ (CA) -> ผู้ติดต่อ ใช้โครงหน้าเดียวกับหน้างานอื่น
   ส่วนที่เพิ่มคือการ์ดลูกค้า/สถานที่ และตารางที่แก้ในแถวได้ */
.crm-list { display: flex; flex-direction: column; gap: 10px; }

.crm-card,
.crm-site-card {
  display: block;
  width: 100%;
  padding: 14px 16px;
  background: var(--white);
  border: 1px solid var(--border);
  border-left: 4px solid var(--volt-300);
  border-radius: 12px;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.crm-card:hover,
.crm-site-card:hover { border-color: var(--volt-500); background: var(--volt-50); }
.crm-site-card { border-left-color: var(--info); margin-bottom: 10px; }

.crm-card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.crm-card-name { font-weight: 600; color: var(--ink); }
.crm-card-meta { margin-top: 4px; font-size: 13px; color: var(--ink-soft); }

.crm-form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 14px;
  margin: 18px 0 8px;
}
/* ที่อยู่กับหมายเหตุกินเต็มแถว -- เป็นข้อความหลายบรรทัด ไม่ใช่ช่องสั้น ๆ */
.crm-field-wide { grid-column: 1 / -1; }
.crm-solar-grid { margin-top: 12px; }

.crm-section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 28px 0 8px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}
.crm-section-head h3 { margin: 0; font-size: 16px; }

/* ตารางผู้ติดต่อ/หม้อแปลง/EV -- ความกว้างคงที่เหมือนตารางรายการอุปกรณ์ป้องกัน
   เพื่อไม่ให้ช่องข้อความยาวเบียดช่องอื่นจนอ่านไม่ออก */
.crm-contact-table,
.crm-tx-table,
.crm-ev-table { table-layout: fixed; margin-bottom: 8px; }
.crm-contact-table .crm-col-sm,
.crm-tx-table .crm-col-sm,
.crm-ev-table .crm-col-sm { width: 140px; }
.crm-contact-table .crm-col-xs,
.crm-tx-table .crm-col-xs,
.crm-ev-table .crm-col-xs { width: 84px; }
.crm-contact-table .price-col-actions,
.crm-tx-table .price-col-actions,
.crm-ev-table .price-col-actions { width: 80px; }
.crm-center { text-align: center; }
.crm-contact-table select {
  width: 100%;
  box-sizing: border-box;
  padding: 6px 8px;
  border: 1px solid transparent;
  border-radius: 6px;
  font: inherit;
  background: transparent;
}
.crm-contact-table select:hover { border-color: var(--border); }
.crm-contact-table select:focus { border-color: var(--volt-500); background: var(--white); outline: none; }

.crm-sites { margin-top: 4px; }

/* ------------------------------- CRM เฟส 2: งานบริการ / ประกัน / รอบบำรุงรักษา */
.crm-tabs { margin-bottom: 4px; }
.crm-jobs { margin-top: 4px; }

.crm-job-card {
  display: block;
  width: 100%;
  margin-bottom: 10px;
  padding: 14px 16px;
  background: var(--white);
  border: 1px solid var(--border);
  border-left: 4px solid var(--success);
  border-radius: 12px;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.crm-job-card:hover { border-color: var(--volt-500); background: var(--volt-50); }
/* ผลการตรวจคือสิ่งที่คนอ่านย้อนหลังจริง ๆ -- ให้เห็นบนการ์ดเลยโดยไม่ต้องเปิดเข้าไป */
.crm-job-findings {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--border);
  font-size: 13px;
  color: var(--ink-soft);
  white-space: pre-wrap;
}

/* ------------------------------------ CRM เฟส 3: โอกาสขาย + อัตราปิดการขาย */
.crm-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px;
  margin-bottom: 20px;
}
.crm-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 14px 16px;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 12px;
}
.crm-stat strong { font-size: 24px; line-height: 1.1; color: var(--volt-700); }
.crm-stat span { font-size: 13px; color: var(--ink); }
.crm-stat small { font-size: 12px; color: var(--ink-soft); }

/* แถวโอกาสขายใช้โครงเดียวกับแถว "ต้องทำก่อน" ของหน้างานของฉัน ต่างกันที่มี
   ป้ายขั้นตอนกับมูลค่าอยู่ท้ายแถว */
.crm-opp-row { border-left-color: var(--info); }
.crm-opp-amount {
  min-width: 120px;
  text-align: right;
  color: var(--volt-700);
  font-variant-numeric: tabular-nums;
}

/* ------------------- CRM เฟส 4: ไทม์ไลน์การติดต่อ / PDPA / รายงาน --------- */
.crm-activities { margin-top: 4px; }

.crm-act-card {
  display: block;
  width: 100%;
  margin-bottom: 10px;
  padding: 14px 16px;
  background: var(--white);
  border: 1px solid var(--border);
  border-left: 4px solid var(--volt-300);
  border-radius: 12px;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.crm-act-card:hover { border-color: var(--volt-500); background: var(--volt-50); }
/* งานติดตามที่เลยกำหนดต้องเห็นจากการไล่สายตา ไม่ต้องอ่านทุกบรรทัด */
.crm-act-card.is-overdue { border-left-color: var(--danger); }
.crm-act-who { font-size: 13px; color: var(--ink-soft); }
.crm-act-summary { margin-top: 6px; white-space: pre-wrap; }
.crm-act-next {
  margin-top: 8px;
  padding: 6px 10px;
  background: var(--warning-tint);
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--warning);
}
.crm-act-next.is-done {
  background: var(--success-tint);
  color: var(--success);
  font-weight: 400;
  text-decoration: line-through;
}
.crm-act-by { margin-top: 6px; font-size: 12px; color: var(--ink-soft); }

/* กราฟแท่งรายได้รายเดือน -- อ่านสัดส่วนด้วยสายตาได้เร็วกว่าไล่อ่านตัวเลข */
.crm-month-chart { margin-bottom: 8px; }
.crm-month-row {
  display: grid;
  grid-template-columns: 52px 1fr 160px;
  align-items: center;
  gap: 10px;
  margin-bottom: 4px;
}
.crm-month-label { font-size: 13px; color: var(--ink-soft); }
.crm-month-bar {
  height: 18px;
  background: var(--volt-50);
  border-radius: 4px;
  overflow: hidden;
}
.crm-month-bar span { display: block; height: 100%; background: var(--volt-500); }
.crm-month-value {
  text-align: right;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.crm-report-table { margin-bottom: 8px; }
.crm-report-table td:first-child { overflow-wrap: break-word; }

/* ======================================================= งานมอบหมายอื่น ๆ ===
   เรื่องที่ ผจก. แทงลงมา แล้วหัวหน้าจ่ายต่อ -- ใช้โครงหน้าเดียวกับหน้างานอื่น
   (.requests-layout / .requests-sidebar) ส่วนที่เพิ่มคือการ์ดงานกับแผงขวา */
.assign-card {
  display: block;
  width: 100%;
  margin-bottom: 10px;
  padding: 14px 16px;
  background: var(--white);
  border: 1px solid var(--border);
  border-left: 4px solid var(--volt-300);
  border-radius: 12px;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.assign-card:hover { border-color: var(--volt-500); background: var(--volt-50); }
/* เลยกำหนดแล้วต้องเห็นจากการไล่สายตา ไม่ต้องอ่านวันที่ทุกใบ */
.assign-card.is-overdue { border-left-color: var(--danger); }
.assign-card-note {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--border);
  font-size: 13px;
  color: var(--ink-soft);
  white-space: pre-wrap;
}

/* ฟอร์มสองคอลัมน์: เนื้อเรื่องซ้าย / ผู้รับผิดชอบ-ประวัติ-บันทึก ขวา
   แผงขวาไม่ sticky เพราะสูงเท่าฟอร์มอยู่แล้ว (ดูเหตุผลเดียวกันที่ .form-side
   ของฟอร์มคำร้อง -- element ที่สูงเท่าคอนเทนเนอร์ไม่มีระยะให้ stick) */
.assign-layout {
  display: flex;
  align-items: flex-start;
  gap: 24px;
  margin-top: 16px;
}
.assign-main { flex: 1; min-width: 0; }
.assign-side {
  flex: none;
  width: 340px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
@media (max-width: 1100px) {
  .assign-layout { flex-direction: column; }
  .assign-side { width: 100%; }
}

.assign-panel {
  padding: 14px 16px;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 12px;
}
.assign-panel h3 { margin: 0 0 10px; font-size: 15px; }
.assign-panel textarea {
  width: 100%;
  box-sizing: border-box;
  margin-top: 8px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font: inherit;
  resize: vertical;
}
.assign-panel .btn { margin-top: 8px; }
.assign-assignee { margin: 0 0 8px; font-weight: 600; color: var(--ink); }

.assign-comment {
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
  font-size: 14px;
  white-space: pre-wrap;
}
.assign-comment:last-child { border-bottom: none; }

/* ------------------------------------------------------------ ยกเลิกสมุดคุม */
/* เล่มที่ยกเลิกแล้วยังอยู่ในประวัติ -- จางลงและขอบซ้ายเป็นสีอันตราย ให้แยกออกจาก
   เล่มที่ใช้ได้ทันทีโดยไม่ต้องอ่านป้าย แต่ยังอ่านชื่อลูกค้าได้ครบ */
.request-card.dispatch-voided {
  border-left-color: var(--danger);
  background: var(--paper);
}

.request-card.dispatch-voided .request-name {
  color: var(--ink-soft);
  text-decoration: line-through;
  text-decoration-color: var(--danger);
}

.dispatch-void-line {
  margin-top: 6px;
  color: var(--danger);
}

.dispatch-void-notice {
  margin: 0 0 16px;
  background: var(--success-tint);
  border-left-color: var(--success);
  color: var(--success);
}

/* .modal-card จัดกึ่งกลางทุกอย่าง -- กล่องนี้เป็นรายการกับฟอร์ม อ่านชิดซ้ายดีกว่า */
.void-dispatch-card {
  text-align: left;
}

.modal-card .void-dispatch-summary {
  margin: 0 0 16px;
  line-height: 1.7;
}

.void-dispatch-group {
  margin-bottom: 14px;
}

.void-dispatch-group[hidden] {
  display: none;
}

.modal-card .void-dispatch-label {
  margin: 0 0 6px;
  font-weight: 600;
  color: var(--ink);
}

.modal-card .void-dispatch-label-warn {
  color: var(--warning);
}

.void-dispatch-list {
  margin: 0;
  padding: 8px 12px 8px 30px;
  max-height: 180px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 13.5px;
  line-height: 1.7;
}

.void-dispatch-why {
  color: var(--ink-soft);
}

.void-dispatch-ack {
  margin: 4px 0 0;
  align-items: flex-start;
}

.void-dispatch-ack input {
  flex-shrink: 0;
  margin-top: 3px;
}

/* ------------------------------------------------------------ เสนอราคาผ่าน CRM */
/* .crm-section-head ตั้ง display: flex -- หัวข้อประวัติการเสนอราคาของสถานที่ถูกซ่อน
   ด้วย hidden ตอนเป็นสถานที่ใหม่ จึงต้องมีตัวกันนี้ (ดูกฎ [hidden] ใน CLAUDE.md) */
.crm-section-head[hidden] {
  display: none;
}

.crm-quote-lookup {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px;
  margin-bottom: 8px;
}

.crm-quote-lookup .field {
  flex: 1 1 240px;
  margin: 0;
}

.crm-quote-card {
  text-align: left;
}

.modal-card .crm-quote-customer {
  margin: 0 0 14px;
  font-weight: 600;
  color: var(--ink);
}

.modal-card .crm-quote-history {
  margin: 0 0 14px;
  font-size: 13px;
  color: var(--ink-soft);
}

.modal-card .crm-quote-label {
  margin: 0 0 8px;
  font-weight: 600;
  color: var(--ink);
}

.crm-quote-recs {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.crm-quote-rec {
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--white);
}

.crm-quote-rec.is-top {
  border-left: 4px solid var(--success);
}

.crm-quote-source {
  color: var(--volt-700);
}

.crm-quote-recent {
  color: var(--warning);
}

.crm-quote-rec-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 10px;
}

.quo-link-info {
  margin: 0 0 12px;
  padding: 8px 12px;
  border-radius: 8px;
  background: var(--volt-50);
  color: var(--volt-700);
  font-size: 13.5px;
  line-height: 1.6;
}

.quo-link-info[hidden] {
  display: none;
}
