@font-face{font-family:"Sarabun"; src:url("/static/vendor/fonts/Sarabun-Regular.ttf") format("truetype");
  font-weight:400; font-display:swap}
@font-face{font-family:"Sarabun"; src:url("/static/vendor/fonts/Sarabun-Medium.ttf") format("truetype");
  font-weight:500 600; font-display:swap}
@font-face{font-family:"Sarabun"; src:url("/static/vendor/fonts/Sarabun-Bold.ttf") format("truetype");
  font-weight:700; font-display:swap}

/* ══════════════════════════════════════════════════════════════════
   Design system 360TRUCK — ค่าชุดเดียวกับ adminv3.360truck.co
   รายละเอียดและเหตุผลของแต่ละค่าอยู่ใน DESIGN-SYSTEM.md

   หลักที่ยึด: สีสดใช้กับ "ป้ายเล็ก" · สีเข้มใช้กับ "ข้อความและงานพิมพ์"
   เพราะระบบนี้มีคำว่า "ไม่ผ่าน ห้ามใช้รถ" ที่ต้องอ่านออกทั้งบนจอและบนกระดาษ
   ══════════════════════════════════════════════════════════════════ */
:root{
  /* พื้นผิว — เทากลางแบบ adminv3 ไม่ใช่ขาวอมเขียวแบบเดิม */
  --paper:#EDF2F9; --surface:#FFFFFF; --sunk:#F2F3F3;
  /* ตัวอักษร */
  /* --ink3 เคยเป็น #8A8A8A ซึ่งอ่านบนพื้นหน้าสีเทา (--paper) ได้คอนทราสต์
     แค่ 2.92 — ต่ำกว่าเกณฑ์ขั้นต่ำ 4.5 ของข้อความปกติมาก · บรรทัดอธิบาย
     ใต้ชื่อหน้า (.sub) ใช้สีนี้อยู่ **ทุกหน้า** จึงเป็นข้อความที่อ่านยากที่สุด
     ในระบบทั้งที่เป็นข้อความที่บอกว่าหน้านี้คืออะไร
     #6A6A6A ได้ 4.57 บนพื้นหน้า · 5.41 บนการ์ด · 4.87 บนพื้นจม — ผ่านทั้งสาม */
  --ink:#262626; --ink2:#5A5A5A; --ink3:#6A6A6A;
  --line:#DCDDDD; --line2:#C6C7C7;
  /* แถบนำทาง — #292929 ของ adminv3 ไม่ใช่ดำสนิท */
  --nav:#292929; --nav-hover:#3A3A3A; --nav-ink:#C9CACA;

  /* สีแบรนด์ — **ดูดจากไฟล์โลโก้จริง ไม่ใช่จากภาพหน้าจอ**
     BIG-LOGO360TRUCK-original-Color.png ให้ค่า #D7E027 กับพิกเซล 88,320 จุด
     ของตัวโลโก้ · ค่าเดิม #D5DF31 มาจากการดูดสีจากภาพหน้าจอ adminv3 ซึ่งผ่าน
     การบีบอัดและโปรไฟล์สีของจอมาแล้ว จึงเพี้ยนไปเล็กน้อย */
  /* สีโลโก้ — ไม่เปลี่ยนตามโซน เพราะโลโก้ 360TRUCK เป็นสีเดียวเสมอ */
  --brandmark:#D7E027;

  /* ── สีนำของโซน ─────────────────────────────────────────────────
     ระบบนี้มีสองโซนตามที่ Design System กำหนด และ **ห้ามผสมกันในหน้าเดียว**
       carrier (ค่าตั้งต้น) — งานภายใน จัดการรถ คนขับ เอกสาร ผลตรวจ
       shipper              — งานลูกค้า และทุกหน้าที่ลูกค้าเห็น
     เปลี่ยนโซนที่ body[data-side] ที่เดียว (base.html เป็นคนกำหนดจาก URL)
     ทุกอย่างในหน้าจึงเปลี่ยนตามพร้อมกัน ไม่มีทางหลุดเป็นคนละสีในหน้าเดียว */
  /* 27 ก.ย. 2569 Sea สั่ง "สีฟ้าทำให้สดใสขึ้น ไม่หม่นหมอง" — จากฟ้าอมเทาเขียว
     (#258EA6 / #207C91 ความอิ่มสี 64%) เป็นฟ้าสด (อิ่มสี 93–100%) โทนเดียวกัน
     ทั้งชุด · ค่าเดิมเก็บไว้ใน DESIGN-SYSTEM.md เผื่อย้อนกลับ */
  --primary:#0891D4; --primary-light:#5CC6F2; --primary-hover:#0069B3;
  --primary-active:#005C9E; --primary-disabled:#A7D5EF;
  --on-primary:#FFFFFF; --primary-deep:#005FB8; --primary-wash:#E3F3FC;
  /* --primary ใช้เป็นเส้น ขอบ และแถบ ซึ่งเกณฑ์อยู่ที่ 3.0 (ได้ 3.49 บนขาว)
     แต่พื้นทึบที่มีตัวหนังสือวางอยู่ต้องถึง 4.5 — ฟ้าสดที่ยังให้ตัวขาวอ่านออก
     คือ #0077C8 ได้ 4.70 · ฟ้าที่สว่างกว่านี้ (#0EA5E9) ได้แค่ 2.77 ใช้กับปุ่มไม่ได้ */
  --primary-solid:#0077C8;
  /* ขีดเฉียงสามขีดจากโลโก้ — เครื่องหมายเดียวที่เป็นของ 360TRUCK จริง ๆ
     เก็บเป็นโทเคนเพื่อให้เปลี่ยนสีพร้อมแบรนด์ได้ที่เดียว */
  --streaks:url('data:image/svg+xml;utf8,\
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 16"><g fill="%23D7E027">\
<path d="M4 0h3L3 16H0z" opacity=".4"/><path d="M9.5 0h3L8.5 16h-3z" opacity=".7"/>\
<path d="M15 0h3l-4 16h-3z"/></g></svg>');
  /* โลโก้บนพื้นสว่าง ต่อท้ายขีดเฉียงของหัวข้อ (body[data-hlogo] h1) — ค่าจริงมาจาก base.html
     (style ของ <html> มีเลขรุ่นตามไฟล์ /branding/logo_light.png) · หน้าที่ไม่ตั้ง = ไม่มีรูป */
  --logo-light:none;

  /* สถานะ (เข้ม) — ใช้กับ "ข้อความ" และเอกสารที่พิมพ์ออกมา */
  /* ค่าเข้มเหล่านี้ไม่ใช่สีใหม่ — เป็นเฉดเข้มของสีสถานะชุดเดียวกันด้านล่าง
     ที่ลดความสว่างลงจนคอนทราสต์บนพื้นขาวถึง 4.5 ตามเกณฑ์ WCAG
     เกณฑ์ที่ใช้คือบน "พื้นอ่อนของตัวเอง" ไม่ใช่บนพื้นขาว เพราะชิปสถานะ
     วางบนพื้นอ่อนเสมอ ซึ่งเข้มกว่าขาว — ค่าที่พอดี 4.5 บนขาวจึงยังไม่ผ่านตรงนั้น
       Success #03AE50 → #027E3A   บนพื้นอ่อน 4.52  บนขาว 5.19
       Warning #FFC241 → #936400   บนพื้นอ่อน 4.58  บนขาว 5.17
       Danger  #D31D00 → #D11D00   บนพื้นอ่อน 4.51  บนขาว 5.40
       Info    #3787FF → #0060F0   บนพื้นอ่อน 4.55  บนขาว 5.34
     ระบบนี้มีคำว่า "ผ่าน / ไม่ผ่าน" เป็นสาระทั้งหมด อ่านไม่ออกคือใช้ไม่ได้ */
  --go:#027E3A; --go-wash:#E4F3EA;
  --watch:#936400; --watch-wash:#FDF0D4;
  --stop:#D11D00; --stop-wash:#FBE6E2;
  --info:#0060F0; --info-wash:#E4EEF9;

  /* สถานะ (สด) — ใช้กับ "ป้ายเล็ก" เท่านั้น ห้ามใช้กับข้อความยาว */
  --c-go:#03AE50; --c-watch:#FFC241; --c-stop:#D31D00;
  --c-info:#3787FF; --c-teal:#096F89;

  /* ระดับความเสี่ยงเส้นทาง "สูง" (RHA มี 4 ระดับ: สูงมาก=stop · สูง · ปานกลาง=watch · ต่ำ=go)
     ส้มเดียวกับป้ายระดับในเอกสาร (engine/build.py LEVELS) — หน้ามือถือของคนขับจึงเห็นสีเดียวกับกระดาษที่ถือ
     ตัวหนังสือบนพื้นอ่อนของตัวเองได้คอนทราสต์ 5.16 */
  --risk-high:#9C5220; --risk-high-wash:#FDF0E6; --c-risk-high:#C2571A;
  /* ตัวหนังสือบนพื้นแถบนำทาง (--nav) — ตัวหลัก · ตัวรองใช้ --nav-ink */
  --on-nav:#FFFFFF;
  /* ป้ายชื่อยี่ห้อรถบรรทุก (หมุดศูนย์บริการ · truckhelp.py) — ใช้เมื่อยังไม่อัปโหลดโลโก้จริงที่หน้าตั้งค่า
     สีโทนประจำยี่ห้อพอให้จำได้ ไม่ใช่สีโลโก้ทางการ · ตัวขาวบนพื้นทุกสีได้คอนทราสต์เกิน 5.8 */
  --tb-hino:#C8102E; --tb-isuzu:#C8102E; --tb-volvo:#1C355E; --tb-scania:#0B2A5B; --tb-ud:#4A4F55;
  /* กล้อง CCTV — ชมพูชุดเดียวกับแท็บ "กล้อง" ในแผงเหตุการณ์ · ชิป "กล้อง CCTV"/"ดูเฉพาะกล้อง" ตอนเปิดเป็นพื้นชมพูอ่อน
     (Sea 4 ต.ค. 2569: "เวลากดแล้วควรเป็นสีชมพูอ่อนไหม ให้ชัดเจน" — เดิมเทาบนเทา แยกไม่ออกว่าเปิดอยู่)
     ไม่ใช่สีสถานะ จึงไม่ปนกับ ผ่านไม่ได้/ระวัง · ตัวหนังสือบนพื้นอ่อนได้คอนทราสต์ 4.88 · ตัวขาวบนพื้นทึบ 5.87 */
  --cam:#C2185B; --cam-wash:#FCE4EC;

  --shadow:0 1px 2px rgba(0,0,0,.05), 0 8px 24px -16px rgba(0,0,0,.22);
  --shadow-2:0 2px 4px rgba(0,0,0,.06), 0 12px 28px -14px rgba(0,0,0,.28);
  --r:10px;                       /* มุมโค้งมาตรฐานของการ์ด */
  --display:"Sarabun","Noto Sans Thai","Segoe UI",system-ui,sans-serif;
  --body:"Sarabun","Noto Sans Thai",system-ui,sans-serif;
  /* ตัวเลข ทะเบียน ป้ายกำกับ — **Sarabun เหมือนกันทั้งระบบ**
     เดิมสั่งให้ใช้ฟอนต์ mono ของเครื่อง ซึ่งบนวินโดวส์คือ Consolas
     (ฟอนต์สำหรับเขียนโค้ด) ผลคือตัวเลข ทะเบียน ชิป และป้ายกำกับฟอร์ม
     ทั้งระบบเป็นคนละฟอนต์กับข้อความรอบ ๆ — หน้าจอครึ่งหนึ่งเป็นอีกแบบ
     เหตุผลเดิมคือ "อยากให้ตัวเลขกว้างเท่ากัน คอลัมน์จะได้ตรง" ซึ่งไม่ต้อง
     พึ่ง mono เลย เพราะ **ตัวเลข Sarabun กว้างเท่ากันทุกตัวอยู่แล้ว**
     (วัดจากไฟล์ฟอนต์: 550 / 555 / 565 หน่วยต่อ em ใน Regular/Medium/Bold) */
  --mono:"Sarabun","Noto Sans Thai",system-ui,sans-serif;
  /* เก็บ mono จริงไว้ให้ของที่ "ควรดูเป็นโค้ด" เท่านั้น — ชื่อไฟล์ คำสั่งที่ต้อง
     พิมพ์ สลักลิงก์ · พวกนี้ดูเป็นโค้ดแล้วช่วยให้อ่านถูก ไม่ใช่ความผิดพลาด */
  --code:ui-monospace,"Cascadia Mono",Consolas,"Sarabun",monospace;

  /* ── สเกลตัวอักษร (ปรับ 27 ก.ย. 2569 — Sea: "ไม่ต้อง follow design master
     ให้หาที่ดีกว่า" · ให้ glance ง่ายแต่ยังได้รายละเอียด) ──────────────────
     หลักที่ใช้: ระยะห่างระหว่างขั้นต้องต่างกันพอจะเห็นลำดับชั้นทันที
       · ตัวเลขสรุป/ชื่อหน้าใหญ่และหนา (สิ่งที่ตากวาดก่อน)
       · เนื้อตาราง/ปุ่ม 14px (ข้อมูลหลัก)
       · รายละเอียดรอง 12.5px สีจาง (อ่านเมื่อต้องการ)
     ของเดิม 16/17/15/14 ใกล้กันจนทุกบรรทัดดูสำคัญเท่ากัน และตัวรอง 12px สีเทาอ่อน
     อ่านยากบนภาษาไทยที่มีสระบนล่าง · ไม่ต่ำกว่า 11px ทุกที่ (ไทย 10px อ่านไม่ออกบนจอธรรมดา) */
  --t-small:11px;      /* ตัวเล็กสุด — จังหวัดบนป้ายทะเบียน ตัวนับเล็ก ๆ */
  --t-helper:12.5px;   /* รายละเอียดรอง ป้ายกำกับ หัวตาราง */
  --t-sub:13.5px;      /* บรรทัดอธิบายใต้ชื่อหน้า */
  --t-h6:14px;         /* เนื้อในตาราง ปุ่ม ช่องกรอก */
  --t-h5:15px;
  --t-body:15px;       /* เนื้อความหลัก */
  --t-h4:17px;         /* หัวการ์ด */
  --t-h3:19px;         /* หัวข้อย่อยในหน้า */
  --t-emphasis:21px;
  --t-h2:23px;
  --t-h1:26px;         /* ชื่อหน้า */
  --t-kpi:30px;        /* ตัวเลขบนการ์ดสรุป — สิ่งแรกที่ตาเจอ */
  --t-hero:40px;       /* ตัวเลขเด่นที่สุดของหน้า (คะแนนรับการตรวจ) */

  /* ไอคอนที่วาดจาก CSS (กล่องข้อความ แถบเตือน กล่องว่าง) — ใช้เป็น mask สีจึงตาม currentColor
     เส้นชุดเดียวกับ _icons.html (Lucide, ISC) */
  --m-alert:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>');
  --m-stop:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 16h.01"/><path d="M12 8v4"/><path d="M15.312 2a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586l-4.688-4.688A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2z"/></svg>');
  --m-ok:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>');
  --m-info:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>');
  --m-inbox:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 16 12 14 15 10 15 8 12 2 12"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/></svg>');
  --m-lock:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>');
  --m-chev:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>');
}

/* ══ โซน shipper — เมนูงานลูกค้า และทุกหน้าที่ลูกค้าเห็น ═══════════════
   ค่าตั้งต้นใน :root คือฝั่ง carrier · หน้าไหนที่ base.html ตั้ง
   data-side="shipper" จะสลับมาใช้ชุดนี้ทั้งหน้าพร้อมกัน
   ตัวอักษรบนปุ่มไลม์ต้องเป็นสีเข้ม ไม่ใช่สีขาว — ขาวบน #D5DF31
   ได้คอนทราสต์ 1.46 ซึ่งอ่านไม่ออก ส่วน #484848 ได้ 6.28 */
body[data-side="shipper"]{
  --primary:#D5DF31; --primary-light:#E7EC7B; --primary-hover:#C3CB1C;
  --primary-active:#ADB519; --primary-disabled:#EEF2AB;
  --on-primary:#484848; --primary-deep:#5A6111; --primary-wash:#F5F8D2;
  --primary-solid:#D5DF31;   /* ตัวหนังสือเข้มบนไลม์ได้ 6.28 อยู่แล้ว */
  --paper:#EBECEC; --ink:#484848;
}
*{box-sizing:border-box}
html,body{margin:0}
body{background:var(--paper); color:var(--ink); font-family:var(--body);
  font-size:var(--t-body); line-height:1.55; -webkit-font-smoothing:antialiased}

/* ── แถบบน ── */
.top{background:var(--nav); color:#fff; padding:0 18px; display:flex; align-items:center;
  gap:16px; min-height:54px; position:sticky; top:0; z-index:900}
/* โลโก้บนแถบนำทาง — เป็นรูปจริงจากหน้าตั้งค่า เปลี่ยนได้โดยไม่ต้องแก้โค้ด
   กำหนดความสูงตายตัวและปล่อยความกว้างอิสระ โลโก้สัดส่วนไหนก็ไม่เพี้ยน */
.top .mark{height:26px; width:auto; max-width:170px; display:block;
  object-fit:contain; flex-shrink:0}
.top nav{display:flex; gap:2px; flex:1; flex-wrap:wrap; align-items:center}
/* เมนูมีไอคอนทุกอัน (27 ก.ย. 2569) — กวาดตาหาหมวดจากรูปได้ก่อนอ่านคำ */
.top nav a{display:inline-flex; align-items:center; gap:6px; color:var(--nav-ink);
  text-decoration:none; font-size:var(--t-h6); padding:7px 10px; border-radius:7px;
  line-height:1.3; white-space:nowrap}
.top nav a > .ico{width:17px; height:17px; opacity:.9}
.top nav a > .ico.caret{width:13px; height:13px; margin-left:-3px; opacity:.6}
.top nav a:hover{background:var(--nav-hover); color:#fff}
.top nav a.on{background:var(--primary-solid); color:var(--on-primary); font-weight:700}
.top nav a.on > .ico{opacity:1}
.top .who{display:inline-flex; align-items:center; gap:5px; font-size:var(--t-helper);
  color:#8E8F8F; white-space:nowrap}
.top .who a{color:#8E8F8F}
/* ชื่อระบบข้างโลโก้ บนหน้าที่คนขับเห็น — คั่นด้วยเส้นไลม์บาง ๆ ของแบรนด์ */
.top .sysname{font-size:var(--t-helper); color:var(--nav-ink); font-weight:600;
  padding-left:11px; border-left:2px solid var(--brandmark); line-height:1.25}
/* จอมือถือ: แถบบนไม่ตรึง และเมนูเรียงเป็นแถวใต้โลโก้ — เดิมเมนูตัดบรรทัดเป็นคอลัมน์สูงครึ่งจอ
   แล้วตรึงค้างไว้บังเนื้อหาตอนเลื่อน (เห็นในภาพหน้าวางแผนเดินทางบนมือถือ 27 ก.ย. 2569) */
@media(max-width:700px){
  .top{position:static; flex-wrap:wrap; gap:4px 10px; padding:6px 12px}
  .top nav{order:3; flex-basis:100%; gap:2px}
  .top nav a{padding:5px 8px; font-size:13px}
  .top nav a > .ico{width:15px; height:15px}
}
/* ท้ายหน้าฝั่งคนขับ — บอกว่าลิงก์นี้เป็นของใคร และโทรหาใครได้ถ้ามีเรื่อง */
.pubfoot{max-width:640px; margin:26px auto 0; padding:14px 18px 22px;
  border-top:1px solid var(--line); color:var(--ink3); font-size:var(--t-helper);
  line-height:1.7; text-align:center}
.pubfoot a{color:var(--ink2); font-weight:600; white-space:nowrap}

.warnbar{background:var(--stop); color:#fff; padding:8px 18px; font-size:var(--t-helper);
  display:flex; gap:10px; align-items:center; line-height:1.5}
.warnbar > .ico{width:18px; height:18px; flex:none}
.warnbar b{font-weight:600}

.wrap{max-width:1400px; margin:0 auto; padding:18px}
/* หัวเรื่องเป็น Bold ไม่ใช่ Medium และบรรทัดแน่นกว่าเนื้อความ
   เดิมหัวเรื่องกับเนื้อความห่างกันแค่ครึ่งน้ำหนัก และใช้ line-height 1.62
   เท่ากันหมด หน้าจึงอ่านเป็นพืดเดียว ไม่มีลำดับชั้นให้ตากวาด
   **ไม่ใส่ letter-spacing กับภาษาไทย** — สระและวรรณยุกต์ลอยห่างจากตัวพยัญชนะ */
/* h1 มีขีดเฉียงสามขีดจากโลโก้นำหน้าเสมอ — เครื่องหมายเดียวในระบบที่เป็นของ
   360TRUCK เอง ไม่ใช่ของ framework ไหน · วาดจาก background ไม่ใช่ markup
   จึงขึ้นครบทุกหน้าโดยไม่ต้องแก้เทมเพลตสักไฟล์ */
/* ความสูงบรรทัด 1.3 ต่ำเกินไปสำหรับภาษาไทยที่ **ตัดบรรทัดได้**
   วัดจากไฟล์ฟอนต์: "ปื้" ยื่นขึ้นเหนือเส้นฐาน 1.25 เท่าของขนาดตัวอักษร
   และ "ฎู" ยื่นลงใต้เส้นฐาน 0.53 เท่า · ข้อความไทยทั่วไปต้องการอย่างน้อย
   1.33 บรรทัดจึงจะไม่ชนกัน · ชื่อหน้าภาษาไทยยาว ๆ ตัดบรรทัดได้เมื่อจอแคบ
   จึงต้องไม่ต่ำกว่า 1.4 (.plate และ .stat b ยังใช้ค่าต่ำได้เพราะ nowrap
   และมีแต่ตัวเลข จึงไม่มีบรรทัดที่สองให้ชน) */
h1{font-family:var(--display); font-size:var(--t-h1); line-height:1.4; margin:0 0 2px;
  font-weight:700; padding-left:28px; position:relative}
h1::before{content:""; position:absolute; left:0; top:.34em; width:18px; height:16px;
  background:var(--streaks) left center/18px 16px no-repeat}
/* ── โลโก้ 360TRUCK ต่อท้ายขีดเฉียง ── /// [โลโก้] │ ชื่อหน้า
   Sea 29 ก.ย. 2569: "หัวข้อทุกหัวข้อ หลังขีด 3 ขีด ตามด้วย logo 360TRUCK — เผื่อ cap ไปส่งลูกค้า"
   เป็นชั้นที่สองของ background ใน ::before เดิม จึงขึ้นทุกหน้าที่ใช้ base.html (body[data-hlogo])
   โดยไม่แก้เทมเพลตสักไฟล์ · หน้าคนขับ/ลิงก์แชร์ไม่ใช้ base.html และหัวหน้ามีโลโก้อยู่แล้ว จึงไม่ซ้ำ
   สูง 1em เท่าตัวอักษรหัวข้อ (หัวเล็ก โลโก้ก็เล็กตาม · ต่ำกว่านี้คำว่า TRUCK เล็กจนอ่านไม่ออกในภาพ cap)
   กว้าง = สูง × 2.506 = อัตราส่วนจริงของไฟล์
   **ห้ามบีบโลโก้** (selftest_brandmark เทียบเลขนี้กับไฟล์จริงทุกครั้ง) · ขีดคั่นบาง ๆ ให้อ่านเป็น
   "360TRUCK │ ชื่อหน้า" ไม่กลืนเป็นคำเดียว · พิมพ์ออกกระดาษก็ติด (print-color-adjust) */
body[data-hlogo] h1{--hl-h:1em; --hl-w:calc(var(--hl-h) * 2.506);
  padding-left:calc(26px + var(--hl-w) + .62em)}
body[data-hlogo] h1::before{top:calc((1.4em - var(--hl-h)) / 2); height:var(--hl-h);
  width:calc(26px + var(--hl-w) + .31em);
  background:var(--streaks) left center/18px 16px no-repeat,
    var(--logo-light) 26px center/auto 100% no-repeat,
    linear-gradient(var(--line2), var(--line2)) right center/1px 78% no-repeat;
  -webkit-print-color-adjust:exact; print-color-adjust:exact}
h2{font-family:var(--display); font-size:var(--t-h3); line-height:1.4; margin:26px 0 8px;
  font-weight:700}
h3{font-family:var(--display); line-height:1.4; font-weight:700}
.sub{color:var(--ink3); font-size:var(--t-sub); margin:0 0 16px; line-height:1.5}
a{color:var(--primary-deep)}
/* ชื่อไฟล์และคำสั่งที่ต้องพิมพ์ — พวกนี้ควรดูเป็นโค้ดจริง ๆ เพราะต้องพิมพ์ตาม
   ตัวต่อตัว · เดิมไม่มีกฎเลย จึงตกไปใช้ฟอนต์ mono ดิบของเบราว์เซอร์ */
code{font-family:var(--code); font-size:.92em; background:var(--sunk);
  border:1px solid var(--line); border-radius:3px; padding:1px 5px}
.warnbar code{background:rgba(0,0,0,.22); border-color:rgba(255,255,255,.22);
  color:#fff}

/* ── ปุ่ม ── */
/* ปุ่มหลักเป็นตัวหนา ไม่ใช่กึ่งหนา — ปุ่มคือสิ่งที่คนมองหาว่า "กดตรงไหน"
   ขอบล่างเข้มกว่าอีกนิดทำให้ปุ่มดูกดได้จริง ไม่ใช่สี่เหลี่ยมสีแบนที่วางทับหน้า */
.btn{display:inline-flex; align-items:center; justify-content:center; gap:6px;
  background:var(--primary-solid); color:var(--on-primary);
  border:1px solid var(--primary); border-bottom-color:var(--primary-active);
  font-family:var(--display); font-weight:700; font-size:var(--t-h6); line-height:1.35;
  padding:7px 14px; border-radius:7px; text-decoration:none; cursor:pointer; white-space:nowrap}
.btn:hover{filter:brightness(.96)}
.btn:active{transform:translateY(1px)}
/* เดิมมีวงโฟกัสแค่ช่องกรอก ปุ่มไม่มีเลย — คนที่ใช้แป้นพิมพ์จึงหลงว่าอยู่ตรงไหน */
.btn:focus-visible,.chip:focus-visible,.stat:focus-visible,a:focus-visible{
  outline:2px solid var(--primary-deep); outline-offset:2px; border-radius:4px}
.btn.ghost{background:transparent; color:var(--ink2); border-color:var(--line2);
  border-bottom-color:var(--line2); font-weight:600}
.btn.ghost:hover{background:var(--sunk); border-color:var(--ink3)}
.btn.danger{background:var(--stop); border-color:var(--stop);
  border-bottom-color:#8E1F13; color:#fff}
.btn.sm{padding:4px 10px; font-size:var(--t-helper); gap:5px}
.btn.sm .ico{width:14px; height:14px}
.row{display:flex; gap:8px; align-items:center; flex-wrap:wrap}
.spacer{flex:1}

/* ── ฟอร์ม ── */
/* ป้ายกำกับฟอร์มเป็นภาษาไทยเกือบทั้งหมด — **ห้ามใส่ letter-spacing กับไทย**
   เพราะสระบนล่างและวรรณยุกต์จะลอยห่างจากตัวพยัญชนะที่มันเกาะอยู่ อ่านแล้วสะดุด
   (เดิม .05em มาจากตอนที่ป้ายนี้ยังเป็นฟอนต์ mono ตัวพิมพ์ใหญ่แบบฝรั่ง) */
label{display:block; font-size:var(--t-helper); font-family:var(--mono); font-weight:600;
  letter-spacing:0; color:var(--ink2); margin-bottom:4px}
/* เดิมกฎนี้ระบุแค่ text/number/password — ช่องชนิดอื่นอย่าง date search file
   จึงตกไปใช้ค่าปริยายของเบราว์เซอร์ (13.33px) ซึ่งไม่มีอยู่ในสเกลของ
   Design System และวางอยู่ข้างช่อง text 14px ในแถวเดียวกัน เห็นชัดว่าไม่เท่ากัน
   ไล่ชนิดที่เป็น "ช่องกรอก" ให้ครบแทนการระบุทีละอัน */
input:not([type=checkbox]):not([type=radio]):not([type=color]):not([type=hidden]):not([type=range]):not([type=submit]):not([type=button]),
textarea,select{
  width:100%; padding:8px 10px; border:1px solid var(--line2); border-radius:7px;
  font-family:var(--body); font-size:var(--t-h6); background:var(--surface); color:var(--ink)}
input:focus,textarea:focus,select:focus{outline:2px solid var(--primary-deep); outline-offset:1px}
input[type=color]{width:52px; height:32px; padding:2px; border:1px solid var(--line2);
  border-radius:4px; background:var(--surface)}
textarea{min-height:64px; resize:vertical}
.field{margin-bottom:12px}
.field .hint{font-size:var(--t-helper); color:var(--ink3); margin-top:3px}
.grid{display:grid; gap:12px}
.g2{grid-template-columns:1fr 1fr}
.g3{grid-template-columns:1fr 1fr 1fr}
.g4{grid-template-columns:repeat(4,1fr)}
@media(max-width:820px){.g2,.g3,.g4{grid-template-columns:1fr}}

/* ── การ์ด ── */
.card{background:var(--surface); border:1px solid var(--line); border-radius:var(--r);
  padding:16px 18px; box-shadow:var(--shadow)}
.card+.card{margin-top:14px}

/* ── ชิป ── */
.chip{display:inline-flex; align-items:center; gap:4px; font-family:var(--mono);
  font-size:var(--t-helper); font-weight:600; line-height:1.45;
  letter-spacing:0; padding:3px 10px; border-radius:100px; border:1px solid transparent;
  text-decoration:none; white-space:nowrap}
.chip .ico{width:13px; height:13px}
.chip.go{background:var(--go-wash); color:var(--go); border-color:var(--go)}
.chip.watch{background:var(--watch-wash); color:var(--watch); border-color:var(--watch)}
.chip.stop{background:var(--stop-wash); color:var(--stop); border-color:var(--stop)}
.chip.lime{background:var(--primary-wash); color:var(--primary-deep); border-color:var(--primary-deep)}
.chip.mute{background:var(--sunk); color:var(--ink3); border-color:var(--line2)}
.chip.on{outline:2px solid var(--ink); outline-offset:1px}
/* บรรทัดสถานะแบบเงียบ — สถานะ "ปกติ" ที่ขึ้นเกือบทุกแถว (พร้อมใช้ · เอกสารครบ)
   ถ้าทุกแถวมีชิปเหมือนกันหมด ตาจะหาแถวที่มีปัญหาไม่เจอ · ปัญหาเท่านั้นที่ได้ชิปสี */
.qline{display:inline-flex; align-items:center; gap:5px; font-size:var(--t-helper);
  color:var(--ink3); white-space:nowrap}
.qline .ico{width:14px; height:14px}
.qline.go{color:var(--go)} .qline.warn{color:var(--watch)} .qline.bad{color:var(--stop)}
/* ตราตรวจสอบของผู้ให้บริการ — ไอคอนอย่างเดียว คำเต็มอยู่ใน title (ชี้เมาส์)
   และใน <i> ที่ซ่อนจากตาแต่โปรแกรมอ่านหน้าจออ่านได้ */
.vfy{display:inline-flex; vertical-align:-3px; margin:0 1px 0 3px; position:relative}
.vfy .ico{width:15px; height:15px}
.vfy.go{color:var(--go)} .vfy.watch{color:var(--watch)} .vfy.mute{color:var(--ink3)}
.vfy i{position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0);
  white-space:nowrap}
td.prov .chip.sm{vertical-align:1px}
td.prov .qline{margin-left:4px}
td.act{width:1%; white-space:nowrap; text-align:right}
/* ปุ่มไอคอนในแถวตาราง — ไม่ให้ดันแถวสูงกว่าบรรทัดข้อความ */
td.act .icb{height:26px; min-width:26px; padding:0 5px; margin:-3px 0}
td.act .icb .ico{width:15px; height:15px}

/* ── ป้ายสถานะทรงเม็ดยา — แบบเดียวกับ adminv3 ──────────────────────
   ใช้สีสดได้เพราะเป็นป้ายสั้น ๆ พื้นทึบ ตัวอักษรตัวหนา ไม่ใช่ข้อความยาว
   ข้อความยาวและเอกสารที่พิมพ์ออกกระดาษให้ใช้ --go/--watch/--stop แทน */
.sbadge{display:inline-flex; align-items:center; gap:4px; font-size:var(--t-helper);
  font-weight:700; line-height:1.7; padding:1px 10px; border-radius:20px; white-space:nowrap;
  color:#fff}
.sbadge .ico{width:13px; height:13px; stroke-width:2.4}
.sbadge.go{background:var(--c-go)}
.sbadge.watch{background:var(--c-watch); color:#3A2A00}
.sbadge.stop{background:var(--c-stop)}
.sbadge.info{background:var(--c-info)}
.sbadge.lime{background:var(--primary-solid); color:var(--on-primary)}
.sbadge.mute{background:var(--line2); color:var(--ink2)}
.pill{display:inline-block; font-size:var(--t-helper); font-family:var(--mono); padding:1px 7px;
  border-radius:100px; background:var(--sunk); color:var(--ink2)}

/* ── ทะเบียนรถ — ให้หน้าตาเป็น "แผ่นป้าย" ไม่ใช่ข้อความธรรมดา ────────
   ทะเบียนคือตัวตนของรถหนึ่งคัน คนหน้างานกวาดตาหาสิ่งนี้ก่อนเสมอ แต่ใน
   ตารางที่ทุกช่องน้ำหนักเท่ากัน มันจมหายไปกับพื้น · ทำเป็นกรอบป้ายจริง
   แล้วตาจะเจอทันทีโดยไม่ต้องอ่านหัวคอลัมน์ — และเป็นของที่มีแต่ระบบขนส่ง
   ถึงจะมี ไม่ใช่ component ที่หยิบมาจากชุดสำเร็จรูปไหน */
.plate{display:inline-flex; align-items:baseline; gap:6px; font-family:var(--display);
  font-weight:700; font-size:var(--t-h6); line-height:1.25; padding:2px 8px;
  border:1.5px solid var(--ink); border-radius:4px; background:var(--surface);
  color:var(--ink); text-decoration:none; white-space:nowrap}
.plate .pv{font-weight:400; font-size:var(--t-small); color:var(--ink2)}
a.plate:hover{background:var(--primary-solid); border-color:var(--on-primary)}
tr.off .plate{border-color:var(--line2); color:var(--ink3)}
/* สามตัวนี้ชื่อคล้ายกันแต่คนละหน้าที่ — อย่าสลับ
   .pill   แท็กข้อมูลสีจาง คู่คีย์-ค่า เช่น "จังหวัด → ตาก"
   .stat   กล่องตัวเลขสรุปบนหัวหน้ารายการ (ใช้คู่กับ .stats)
   .sbadge ป้ายสถานะสีสดทรงเม็ดยา เช่น "พร้อม" "ยังขาด" */

/* ── กล่องข้อความ ── */
.note{position:relative; border:1px solid var(--line); border-left:4px solid var(--watch);
  background:var(--watch-wash); border-radius:8px; padding:11px 15px 11px 44px; margin:12px 0;
  font-size:var(--t-h6); line-height:1.6}
/* ไอคอนตามชนิดของกล่อง — ระวัง/ห้าม/เรียบร้อย/ข้อมูล มองรูปก็รู้ก่อนอ่าน */
.note::before{content:""; position:absolute; left:14px; top:12px; width:19px; height:19px;
  background:var(--watch); -webkit-mask:var(--m-alert) center/contain no-repeat;
  mask:var(--m-alert) center/contain no-repeat}
.note.bad{border-left-color:var(--stop); background:var(--stop-wash)}
.note.bad::before{background:var(--stop); -webkit-mask-image:var(--m-stop); mask-image:var(--m-stop)}
.note.ok{border-left-color:var(--go); background:var(--go-wash)}
.note.ok::before{background:var(--go); -webkit-mask-image:var(--m-ok); mask-image:var(--m-ok)}
.note.lime{border-left-color:var(--primary-deep); background:var(--primary-wash)}
.note.lime::before{background:var(--primary-deep); -webkit-mask-image:var(--m-info); mask-image:var(--m-info)}
/* info = อธิบายวิธีทำงาน/ที่มาของตัวเลข (ไม่ต้องทำอะไร) · priv = ข้อมูลส่วนบุคคล/ภายใน
   แยกจากคำเตือนสีเหลือง เพราะถ้าทุกกล่องเป็นเหลือง คนจะเลิกอ่านคำเตือนจริง */
.note.info{border-left-color:var(--info); background:var(--info-wash)}
.note.info::before{background:var(--info); -webkit-mask-image:var(--m-info); mask-image:var(--m-info)}
.note.priv{border-left-color:var(--ink2); background:var(--sunk)}
.note.priv::before{background:var(--ink2); -webkit-mask-image:var(--m-lock); mask-image:var(--m-lock)}
/* แถบตัวกรองเสริมเหนือตาราง (เช่น เฉพาะที่วิ่งให้ลูกค้า) — ไม่ใช่คำเตือน จึงไม่ใช้ .note */
.fbar{background:var(--surface); border:1px solid var(--line); border-radius:var(--r);
  padding:8px 12px; margin:12px 0}
.fbar .fl{display:inline-flex; align-items:center; gap:6px; font-size:var(--t-h6);
  font-weight:600; color:var(--ink2); white-space:nowrap; margin:0}
.note p{margin:0 0 6px} .note p:last-child{margin:0}
.note ul{margin:6px 0 0; padding-left:20px}
/* หัวข้อในกล่องข้อความ — กล่องมีไอคอนนำอยู่แล้ว ไม่ต้องมีขีดของ .kicker ซ้ำ */
.note .kicker{padding-left:0} .note .kicker::before{display:none}
/* หัวข้อกำกับการ์ด — เดิมเป็น mono ตัวพิมพ์ใหญ่กางตัว ซึ่งเป็นสูตรของ
   แดชบอร์ดสำเร็จรูป และใช้กับภาษาไทยไม่ได้อยู่ดี (ไทยไม่มีตัวพิมพ์ใหญ่)
   ขีดไลม์สั้น ๆ นำหน้าแทน — ของแบรนด์แต่เงียบพอที่จะไม่แย่งความสนใจ
   **ขีดเฉียงสามขีดสงวนไว้ให้ชื่อหน้าเท่านั้น** ใช้ทุกที่เมื่อไรก็ไม่เหลือความหมาย */
.kicker{font-family:var(--mono); font-size:var(--t-h6); letter-spacing:0;
  font-weight:700; color:var(--ink); margin:0 0 8px; padding-left:13px;
  position:relative; line-height:1.45}
/* ขีดตั้ง ไม่ใช่ขีดนอน — ขีดนอนสั้น ๆ หน้าข้อความอ่านเป็นเครื่องหมายลบ */
.kicker::before{content:""; position:absolute; left:0; top:.25em; width:3px; height:1em;
  background:var(--primary-deep); border-radius:2px}
/* หัวการ์ดที่มีไอคอนนำ — ไอคอนบอกว่าการ์ดนี้เรื่องอะไร จึงไม่ต้องมีขีดตั้งอีก */
.kicker > .ico:first-child{width:17px; height:17px; margin:0 7px 0 0; vertical-align:-3px;
  color:var(--primary-deep)}
.kicker:has(> .ico:first-child){padding-left:0}
.kicker:has(> .ico:first-child)::before{display:none}

/* ── ตาราง ── */
.tw{overflow:auto; border:1px solid var(--line); border-radius:var(--r);
  background:var(--surface); box-shadow:var(--shadow)}
table{border-collapse:collapse; width:100%; font-size:var(--t-h6)}
/* หัวตารางต้องอ่านเป็น "หัว" จริง ๆ — เดิมพื้นเกือบขาว ตัวกึ่งหนา เส้นใต้บาง
   เท่าเส้นแถว ทำให้แถวแรกดูเหมือนข้อมูลแถวหนึ่ง ไม่ใช่ชื่อคอลัมน์ */
th{position:sticky; top:0; background:var(--sunk); text-align:left; font-family:var(--display);
  font-weight:700; font-size:var(--t-helper); color:var(--ink2); padding:10px 12px;
  border-bottom:1px solid var(--line2); white-space:nowrap; z-index:2}
tbody tr:hover{background:var(--primary-wash)}
/* ป้ายทะเบียนมีกรอบ จึงสูงกว่าข้อความเปล่าอยู่แล้ว — ลดระยะในช่องลงนิด
   เพื่อให้จำนวนแถวที่เห็นในหน้าจอเดียวเท่าเดิม */
td{padding:9px 12px; border-bottom:1px solid var(--line); vertical-align:top}
/* บรรทัดรองในช่องตาราง — เล็กและจางกว่าข้อมูลหลักชัด ๆ */
td small, td .dim, td .tag{font-size:var(--t-helper)}
tr:last-child td{border-bottom:none}
tr.off td{opacity:.5}
td.mono,.mono{font-family:var(--mono); font-size:var(--t-helper)}
.tw.tall{max-height:520px}

/* ── แผนที่ ── */
.split{display:grid; gap:14px; grid-template-columns:minmax(0,1.15fr) minmax(0,1fr)}
@media(max-width:1000px){.split{grid-template-columns:1fr}}
#map{height:560px; border:1px solid var(--line); border-radius:6px; background:var(--sunk)}
@media(max-width:1000px){#map{height:380px}}
.leaflet-container{font-family:var(--body)}
.mk{display:flex; align-items:center; justify-content:center; font-family:var(--mono);
  font-size:var(--t-helper); font-weight:700; color:var(--on-primary)}
.mk.rs{background:var(--primary-solid); border:1.5px solid var(--on-primary); border-radius:4px}
.mk.rso{background:var(--surface); color:var(--primary-solid); border:1.5px solid var(--primary-solid); border-radius:4px}
.mk.gs{background:var(--surface); color:var(--ink); border:1.5px solid var(--ink); border-radius:4px}
/* โลโก้ประเภทสถานที่ทรงกะทัดรัด (kindlogo.py เช่น วงกลม PT) = หมุดเป็นรูปโลโก้บนวงกลมขาว */
.mk.klogo{background:var(--surface); border-radius:50%; box-shadow:0 0 0 1.5px var(--surface), 0 1px 3px rgba(0,0,0,.45); overflow:hidden}
.mk.klogo img{width:86%; height:86%; object-fit:contain; display:block}
.mk.hz{width:0; height:0; background:none; border-left:9px solid transparent;
  border-right:9px solid transparent; border-bottom:16px solid var(--stop)}
.mk.hp{background:var(--go-wash); border:1.5px solid var(--go); border-radius:3px;
  color:var(--go); font-size:var(--t-h6); line-height:1}
/* อู่/รถยก/ร้านยาง = วงกลม · จุดขึ้น-ลงสินค้า = ข้าวหลามตัด — รูปทรงต่างจากสามแบบเดิม */
.mk.sv{background:var(--watch-wash); border:1.5px solid var(--watch); border-radius:50%;
  color:var(--watch)}
.mk.lp{background:var(--info); color:#fff; clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%);
  font-size:11px}
.mk .ico{width:13px; height:13px; stroke-width:2.4}
.mk.lp .ico{width:12px; height:12px}
.maphint{font-size:var(--t-helper); color:var(--ink3); margin-top:7px; line-height:1.6}

/* ── รายการผลลัพธ์ ── */
.hit{display:flex; gap:10px; padding:9px 2px; border-bottom:1px solid var(--line);
  align-items:flex-start}
.hit:last-child{border-bottom:none}
.hit .ic{flex:none; width:22px; height:22px; margin-top:2px; display:flex;
  align-items:center; justify-content:center; font-family:var(--mono); font-size:var(--t-helper);
  font-weight:700; border-radius:4px}
.ic.rs{background:var(--primary-solid); color:var(--on-primary); border:1.5px solid var(--on-primary)}
.ic.rso{background:var(--surface); color:var(--primary-solid); border:1.5px solid var(--primary-solid)}
.ic.gs{background:var(--surface); color:var(--ink); border:1.5px solid var(--ink)}
.pr .ic .ico{width:12px; height:12px}
.ic.hz{background:var(--stop-wash); color:var(--stop); border:1.5px solid var(--stop)}
.ic.hp{background:var(--go-wash); color:var(--go); border:1.5px solid var(--go)}
.ic.sv{background:var(--watch-wash); color:var(--watch); border:1.5px solid var(--watch); border-radius:50%}
.ic.lp{background:var(--info-wash); color:var(--info); border:1.5px solid var(--info)}
.hit .t{flex:1; min-width:0}
.hit .t b{font-weight:600; font-size:var(--t-h6)}
.hit .t .m{font-size:var(--t-helper); color:var(--ink3); display:block; line-height:1.5}
.hit .act{flex:none; display:flex; gap:5px; align-items:center}

.searchbar{display:flex; gap:8px; margin-bottom:10px; flex-wrap:wrap}
.searchbar input[type=text]{flex:1; min-width:180px}
.empty{padding:30px 10px 26px; text-align:center; color:var(--ink3); font-size:var(--t-h6)}
.empty::before, .blank.big::before{content:""; display:block; width:34px; height:34px;
  margin:0 auto 8px; background:var(--line2); -webkit-mask:var(--m-inbox) center/contain no-repeat;
  mask:var(--m-inbox) center/contain no-repeat}
.tag{font-family:var(--mono); font-size:var(--t-helper); color:var(--ink3)}
.tag.warn{color:#5b2fd6; font-weight:600}   /* ข้อมูลจำลอง (ตำแหน่งคนขับ) — สีเดียวกับหมุดม่วง */

/* ══════════════════════════════════════════════════════════════════
   เฟส 2 — ทะเบียนรถ · ทะเบียนคนขับ · หน้ารายคัน/รายคน
   ══════════════════════════════════════════════════════════════════ */

/* แถบสรุปตัวเลขบนหัวหน้ารายการ */
/* กล่องตัวเลขสรุป — align-items:flex-start ไม่ได้ เพราะบางหน้ามีการ์ดสูงกว่า
   อยู่ในแถวเดียวกัน (หน้ารับการตรวจมีการ์ดคะแนนสีเข้ม) กล่องจะเตี้ยลอยผิดที่
   จึงให้ยืดเท่ากันแต่ **จัดเนื้อหาไว้กลางแนวตั้ง** ไม่ใช่ปล่อยตัวเลขค้างบน
   แล้วเหลือช่องว่างใต้ป้ายครึ่งกล่องอย่างที่เป็นอยู่ */
.stats{display:flex; gap:10px; flex-wrap:wrap; margin-bottom:14px}
/* การ์ดตัวเลข (27 ก.ย. 2569): ตัวเลขใหญ่ · แถบสีซ้ายบอกความรุนแรง · ไอคอนมุมขวาบอกเรื่อง
   ไอคอนวางท้ายการ์ด (หลัง <span>) และจัดตำแหน่งด้วย CSS — ชุดทดสอบอ่านตัวเลขจาก <b><span> ติดกัน */
.stat{position:relative; overflow:hidden; background:var(--surface); border:1px solid var(--line);
  border-radius:var(--r); padding:11px 40px 11px 16px; min-width:128px; flex:0 1 auto;
  text-decoration:none; color:inherit; box-shadow:var(--shadow);
  display:flex; flex-direction:column; justify-content:center; transition:transform .12s, box-shadow .12s}
.stat::before{content:""; position:absolute; left:0; top:0; bottom:0; width:4px; background:var(--line2)}
.stat.bad::before{background:var(--stop)} .stat.warn::before{background:var(--c-watch)}
.stat.good::before{background:var(--c-go)} .stat.info::before{background:var(--info)}
.stat > .ico{position:absolute; right:12px; top:12px; width:20px; height:20px; color:var(--ink3)}
.stat.bad > .ico{color:var(--stop)} .stat.warn > .ico{color:var(--watch)}
.stat.good > .ico{color:var(--go)} .stat.info > .ico{color:var(--info)}
a.stat:hover{border-color:var(--line2); box-shadow:var(--shadow-2); transform:translateY(-1px)}
/* การ์ดที่กดได้ต้องดูออกว่ากดได้ แม้บนมือถือที่ไม่มี hover — ลูกศรจาง ๆ มุมขวาล่าง */
a.stat::after{content:""; position:absolute; right:11px; bottom:10px; width:14px; height:14px;
  background:var(--line2); -webkit-mask:var(--m-chev) center/contain no-repeat;
  mask:var(--m-chev) center/contain no-repeat}
a.stat:hover::after{background:var(--primary-deep)}
.stat.on{border-color:var(--ink); box-shadow:inset 0 0 0 1px var(--ink)}
/* ตัวเลขสรุปใหญ่ขึ้นและเป็น Sarabun Bold เหมือนทั้งระบบ
   เดิมเป็นฟอนต์ mono ของเครื่อง จึงเป็นคนละแบบอักษรกับคำอธิบายที่อยู่ใต้มันเอง */
.stat b{display:block; font-family:var(--display); font-size:var(--t-kpi); font-weight:700;
  line-height:1.15; letter-spacing:0; font-variant-numeric:tabular-nums}
.stat span{font-size:var(--t-helper); color:var(--ink2); font-weight:500; line-height:1.4;
  display:block; margin-top:2px}
.stat.bad b{color:var(--stop)} .stat.warn b{color:var(--watch)}
.stat.good b{color:var(--go)} .stat.info b{color:var(--info)}

/* ── รายการแจ้งเตือน (มาโคร alert_rows) ─────────────────────────────
   แถบซ้าย + สีกล่องไอคอน = ด่วนแค่ไหน · ไอคอน = เรื่องอะไร · ทั้งแถวกดได้
   เกินกำหนด แดง · ต้องทำ ฟ้า · ใกล้ครบกำหนด เหลือง · ควรดู เทา */
.alist{background:var(--surface); border:1px solid var(--line); border-radius:var(--r);
  box-shadow:var(--shadow); overflow:hidden}
.alist .ar{display:grid; grid-template-columns:38px 1fr auto; gap:0 14px; align-items:center;
  padding:11px 16px 11px 12px; border-top:1px solid var(--line); border-left:4px solid var(--line2);
  color:inherit; text-decoration:none}
.alist .ar:first-child{border-top:none}
.alist a.ar:hover{background:var(--primary-wash)}
.alist a.ar:hover .go{text-decoration:underline}
.alist .ic{width:38px; height:38px; border-radius:10px; display:grid; place-items:center;
  background:var(--sunk); color:var(--ink2)}
.alist .ic .ico{width:20px; height:20px}
.alist .bd{display:flex; flex-direction:column; gap:1px; min-width:0}
.alist .t{font-weight:700; font-size:var(--t-body); color:var(--ink); line-height:1.4}
.alist .d{font-size:var(--t-sub); color:var(--ink2); line-height:1.45}
.alist .mt{display:flex; flex-wrap:wrap; gap:2px 14px; align-items:center; margin-top:3px;
  font-size:var(--t-helper); color:var(--ink3)}
.alist .mt > span{display:inline-flex; align-items:center; gap:4px}
.alist .mt .ico{width:13px; height:13px}
.alist .lv{font-weight:700}
.alist .go{display:inline-flex; align-items:center; gap:2px; font-size:var(--t-helper);
  font-weight:600; color:var(--primary-deep); white-space:nowrap}
.alist .go .ico{width:15px; height:15px}
.alist .lv-over{border-left-color:var(--stop)}
.alist .lv-over .ic{background:var(--stop-wash); color:var(--stop)} .alist .lv-over .lv{color:var(--stop)}
.alist .lv-todo{border-left-color:var(--info)}
.alist .lv-todo .ic{background:var(--info-wash); color:var(--info)} .alist .lv-todo .lv{color:var(--info)}
.alist .lv-soon{border-left-color:var(--c-watch)}
.alist .lv-soon .ic{background:var(--watch-wash); color:var(--watch)} .alist .lv-soon .lv{color:var(--watch)}
@media (max-width:640px){
  .alist .ar{grid-template-columns:32px 1fr; gap:0 10px; padding:10px 12px 10px 10px}
  .alist .ic{width:32px; height:32px} .alist .ic .ico{width:17px; height:17px}
  .alist .go{grid-column:2; justify-self:start; margin-top:4px}}

/* ── หน้ารายคัน/รายคน ── */
.head{display:flex; gap:14px; align-items:flex-start; flex-wrap:wrap;
  margin-bottom:14px}
/* หน้ารายคัน — ป้ายทะเบียนใบใหญ่ เป็นสิ่งแรกที่ตาเจอ แบบเดียวกับที่เห็นบนรถ */
.head .plate{font-size:var(--t-h1); line-height:1.15; padding:4px 13px; border-width:2px;
  border-radius:5px; gap:9px}
.head .plate .pv{font-size:var(--t-body)}
.head .meta{color:var(--ink3); font-size:var(--t-helper)}
.cols{display:grid; gap:14px; grid-template-columns:minmax(0,1fr) minmax(0,340px)}
/* minmax(0,…) ไม่ใช่ 1fr — กันเนื้อหาที่ตัดบรรทัดไม่ได้ดันคอลัมน์จนล้นจอมือถือ/แผงด้านข้าง */
@media(max-width:1000px){.cols{grid-template-columns:minmax(0,1fr)}}

/* รายการเอกสารพร้อมวันหมดอายุ */
.docs{list-style:none; margin:0; padding:0}
.docs li{display:flex; gap:10px; align-items:baseline; padding:7px 0;
  border-bottom:1px solid var(--line)}
.docs li:last-child{border-bottom:none}
.docs .n{flex:none; width:112px; font-size:var(--t-helper); color:var(--ink2)}
.docs .d{flex:1; font-family:var(--mono); font-size:var(--t-helper)}
.docs .s{flex:none; font-size:var(--t-helper)}
.s-over{color:var(--stop); font-weight:600}
.s-soon{color:var(--watch); font-weight:600}
.s-ok{color:var(--ink3)}
.s-none{color:var(--ink3); font-style:italic}

/* แผงอ้างอิงไขว้ */
.xref{list-style:none; margin:0; padding:0}
.xref li{display:flex; gap:9px; align-items:baseline; padding:7px 0;
  border-bottom:1px solid var(--line)}
.xref li:last-child{border-bottom:none}
.xref a{font-weight:600; text-decoration:none}
.xref a:hover{text-decoration:underline}
.xref .t{flex:1; min-width:0}
.xref .t small{display:block; color:var(--ink3); font-size:var(--t-helper)}
.xref .n{flex:none; font-family:var(--mono); font-size:var(--t-helper); color:var(--ink3);
  text-align:right; white-space:nowrap}

/* กล่อง "ยังไม่มีข้อมูล" ที่อ่านรู้เรื่อง ไม่ใช่ตารางเปล่า */
.blank{border:1px dashed var(--line2); border-radius:var(--r); padding:16px;
  color:var(--ink3); font-size:var(--t-helper); background:var(--sunk); line-height:1.6}
.blank b{color:var(--ink2)}

/* ลิงก์และ QR */
.qrbox{display:flex; gap:14px; align-items:flex-start; flex-wrap:wrap}
.qrbox img{width:132px; height:132px; border:1px solid var(--line);
  border-radius:5px; background:#fff; padding:5px}
.linkurl{font-family:var(--code); font-size:var(--t-helper); word-break:break-all;
  background:var(--sunk); border:1px solid var(--line); border-radius:4px;
  padding:6px 8px; display:block; margin:5px 0}

/* แถวกลุ่มรวมชื่อ */
.mg{border:1px solid var(--line); border-radius:6px; background:var(--surface);
  padding:13px 15px; margin-bottom:10px}
.mg h3{margin:0 0 3px; font-size:var(--t-h5); font-family:var(--display)}
.mg .opts{display:flex; gap:8px; flex-wrap:wrap; margin:9px 0}
.mg label.opt{display:flex; gap:7px; align-items:baseline; border:1px solid var(--line2);
  border-radius:5px; padding:7px 11px; cursor:pointer; font-family:var(--body);
  font-size:var(--t-h6); color:var(--ink); letter-spacing:0; margin:0; background:var(--surface)}
.mg label.opt:hover{background:var(--sunk)}
.mg label.opt input{margin:0}
.mg label.opt .c{font-family:var(--mono); font-size:var(--t-helper); color:var(--ink3)}

/* ตารางที่เน้นตัวเลขให้เทียบกันง่าย */
td.num,th.num{text-align:right; font-family:var(--mono); font-size:var(--t-helper);
  white-space:nowrap}
.dim{color:var(--ink3)}

/* ══════════════════════════════════════════════════════════════════
   เฟส 3 — หน้าจอฝั่งคนขับ
   ออกแบบสำหรับ: มือเปื้อน · กลางแดด · สัญญาณอ่อน · ถือมือถือมือเดียว
   ปุ่มใหญ่กว่า 44px ทุกอัน · ตัวอักษรใหญ่กว่าหน้าแอดมิน · คอนทราสต์สูง
   ══════════════════════════════════════════════════════════════════ */
.dv{max-width:560px; margin:0 auto; padding:14px 14px 90px}
.dv h1{font-size:var(--t-emphasis); margin:0 0 2px}
.dv .who{background:var(--sunk); border:1px solid var(--line); border-radius:8px;
  padding:11px 13px; margin:12px 0; font-size:var(--t-h5); line-height:1.75}
.dv .who b{font-family:var(--mono); font-size:var(--t-body)}
.dv .who .lk{color:var(--ink3); font-size:var(--t-helper)}

.step{display:none}
.step.on{display:block}
.stepbar{display:flex; align-items:center; gap:9px; margin:16px 0 10px}
.stepbar .n{font-family:var(--mono); font-size:var(--t-helper); color:var(--ink3);
  white-space:nowrap}
.stepbar .t{font-family:var(--display); font-weight:600; font-size:var(--t-h4); flex:1}
.bar{height:5px; background:var(--sunk); border-radius:99px; overflow:hidden}
.bar i{display:block; height:100%; background:var(--primary-deep); border-radius:99px;
  transition:width .18s}

.q{border:1px solid var(--line); border-radius:9px; background:var(--surface);
  padding:12px 13px; margin-bottom:10px}
.q .lab{font-size:var(--t-h5); line-height:1.5; margin-bottom:9px}
.q .lab .cr{display:inline-block; font-family:var(--mono); font-size:var(--t-small);
  font-weight:700; color:var(--stop); border:1px solid var(--stop);
  border-radius:3px; padding:0 4px; margin-left:5px; vertical-align:2px}
.pick{display:flex; gap:8px}
.pick label{flex:1; margin:0; display:block}
.pick input{position:absolute; opacity:0; pointer-events:none}
.pick span{display:flex; align-items:center; justify-content:center; gap:6px; padding:13px 6px; border-radius:8px;
  border:1.5px solid var(--line2); background:var(--surface); font-size:var(--t-body);
  font-weight:600; font-family:var(--display); color:var(--ink2); cursor:pointer;
  letter-spacing:0; user-select:none}
.pick input:checked + span.ok{background:var(--go); border-color:var(--go); color:#fff}
.pick input:checked + span.bad{background:var(--stop); border-color:var(--stop); color:#fff}
.pick input:checked + span.na{background:var(--ink3); border-color:var(--ink3); color:#fff}
.pick span .ico{width:18px; height:18px; opacity:.55}
.pick span.ok .ico{color:var(--go)} .pick span.bad .ico{color:var(--stop)}
.pick input:checked + span .ico{opacity:1; color:currentColor}
.q textarea{margin-top:9px; font-size:var(--t-body); min-height:52px}
.q.answered{border-color:var(--line2)}
.q.bad{border-color:var(--stop); background:var(--stop-wash)}

.ph{border:1px dashed var(--line2); border-radius:9px; padding:12px 13px;
  margin-bottom:10px; background:var(--surface)}
.ph b{font-size:var(--t-body); display:block; margin-bottom:7px}
.ph input[type=file]{font-size:var(--t-h6); width:100%}
.ph.req b:after{content:" · ต้องมี"; color:var(--stop); font-size:var(--t-helper);
  font-weight:600}
/* บอกตรง ๆ ว่าติดตรงไหน — กรอบแดงเฉย ๆ คนขับกลางแดดมองไม่ออกว่าทำไมไปต่อไม่ได้ */
.needit{margin:7px 0 0; font-size:var(--t-h6); font-weight:600; color:var(--stop)}

/* ── ตัวเลือก ก ข ค ง ในแบบทดสอบความรู้ ──────────────────────────────
   ทั้งบรรทัดเป็นปุ่มกด ไม่ใช่วงกลมเล็ก ๆ — คนขับกดจากมือถือด้วยมือเปื้อน
   สูงอย่างน้อย 44px ตามเกณฑ์ขนาดเป้าสัมผัสขั้นต่ำ · ตัวอักษรกำกับอยู่ใน
   กล่องของตัวเอง ไม่ติดกับข้อความคำถาม และข้อความยาวย่อหน้าเข้าไม่มุดใต้ปุ่ม */
.opts{display:flex; flex-direction:column; gap:7px; margin-top:10px}
.opt{display:block; margin:0; cursor:pointer}
.opt input{position:absolute; opacity:0; pointer-events:none}
/* font-weight:400 ต้องเขียนไว้ — .opt เป็น <label> ซึ่งกฎกลางตั้งไว้ที่ 500
   ตัวเลือกทุกข้อจะหนาเท่ากันหมด แล้วข้อที่เลือกอยู่ก็ดูไม่ต่างจากข้อที่ไม่ได้เลือก */
.opt > span{display:flex; gap:10px; align-items:flex-start; min-height:44px;
  padding:11px 13px; border:1.5px solid var(--line2); border-radius:9px;
  background:var(--surface); font-family:var(--body); font-size:var(--t-body);
  font-weight:400; line-height:1.5; color:var(--ink); letter-spacing:0;
  text-transform:none}
.opt > span > i{flex:none; width:24px; height:24px; border-radius:50%;
  background:var(--sunk); border:1px solid var(--line2); font-style:normal;
  font-weight:700; font-size:var(--t-helper); line-height:22px; text-align:center;
  color:var(--ink2)}
.opt:hover > span{background:var(--sunk)}
.opt input:checked + span{border-color:var(--primary-deep); background:var(--primary-wash);
  font-weight:600}
.opt input:checked + span > i{background:var(--primary-solid); border-color:var(--on-primary);
  color:var(--on-primary)}
.opt input:focus-visible + span{outline:2px solid var(--primary-deep); outline-offset:2px}

/* หน้าเฉลยหลังส่ง — ต้องอ่านออกว่าอันไหนที่ตอบ อันไหนที่ถูก */
.qx{margin:6px 0 0; font-size:var(--t-h6); color:var(--stop)}
.qo{margin:4px 0 0; font-size:var(--t-h6); color:var(--go); font-weight:600}

.dvbtn{display:block; width:100%; padding:16px; border-radius:10px; border:none;
  background:var(--primary-solid); color:var(--on-primary); font-family:var(--display);
  font-weight:700; font-size:var(--t-h4); cursor:pointer; margin-top:6px}
.dvbtn.ghost{background:var(--surface); border:1.5px solid var(--line2);
  color:var(--ink2); font-weight:600}
.dvbtn:disabled{opacity:.45; cursor:not-allowed}
.navrow{display:flex; gap:9px; margin-top:14px}
.navrow .dvbtn{margin-top:0}

.consent{border:1px solid var(--line); border-radius:9px; padding:13px;
  background:var(--sunk); font-size:var(--t-h6); line-height:1.7; margin:14px 0}
.consent label{display:flex; gap:10px; align-items:flex-start; margin-top:11px;
  font-family:var(--body); font-size:var(--t-body); letter-spacing:0; color:var(--ink);
  text-transform:none}
.consent input{width:22px; height:22px; margin:1px 0 0; flex:none}

.draft{position:fixed; left:0; right:0; bottom:0; background:var(--nav); color:#fff;
  font-size:var(--t-helper); padding:9px 14px; text-align:center; z-index:80}
.draft b{color:var(--primary-light)}
.bigresult{border-radius:10px; padding:18px; text-align:center; margin:14px 0}
.bigresult.pass{background:var(--go-wash); border:1px solid var(--go); color:var(--go)}
.bigresult.defect{background:var(--watch-wash); border:1px solid var(--watch); color:var(--watch)}
.bigresult.fail{background:var(--stop-wash); border:1px solid var(--stop); color:var(--stop)}
.bigresult b{display:block; font-size:var(--t-h3); font-family:var(--display)}

/* ── คิวรอตรวจสอบ ── */
.qrow{display:flex; gap:11px; padding:11px 2px; border-bottom:1px solid var(--line);
  align-items:flex-start}
.qrow:last-child{border-bottom:none}
.qrow .t{flex:1; min-width:0}
.qrow .t b{font-size:var(--t-h6); font-family:var(--mono)}
.qrow .t .m{display:block; font-size:var(--t-helper); color:var(--ink3); line-height:1.55}
.qrow .act{flex:none; display:flex; gap:6px; align-items:center}
.qrow.hot{background:var(--stop-wash); border-radius:6px; padding-left:9px;
  padding-right:9px}
.qrow.warn{background:var(--watch-wash); border-radius:6px; padding-left:9px;
  padding-right:9px}
.thumbs{display:flex; gap:7px; flex-wrap:wrap; margin-top:8px}
.thumbs a{display:block; border:1px solid var(--line); border-radius:6px;
  overflow:hidden; background:var(--sunk)}
.thumbs img{display:block; width:118px; height:88px; object-fit:cover}
.thumbs .cap{font-size:var(--t-helper); color:var(--ink3); padding:3px 5px; text-align:center}

/* ── ตัวเลขบนเมนูแจ้งเตือน ─────────────────────────────────────── */
.top nav a b.dot{
  display:inline-block; min-width:17px; padding:0 5px; margin-left:3px;
  background:var(--c-stop); color:#fff; border-radius:9px;
  font-size:var(--t-helper); font-weight:700; line-height:17px; text-align:center;
  vertical-align:1px;
}

/* ── ตารางเล็กในการ์ด — คู่ ป้ายชื่อ/ค่า ────────────────────────── */
table.mini{width:100%; border-collapse:collapse; font-size:var(--t-h6)}
table.mini td{padding:6px 0; border-bottom:1px solid var(--line,#E8E8EA); vertical-align:top}
table.mini tr:last-child td{border-bottom:none}
table.mini td:first-child{color:var(--ink2); width:40%; padding-right:12px}
table.mini td.num{text-align:right; font-variant-numeric:tabular-nums}

/* ── แถบความคืบหน้า — งานที่กินเวลาเป็นนาทีต้องบอกว่าถึงไหนแล้ว ──
   คนละตัวกับ .bar ที่เป็นเส้นบางของ .stepbar โดยตั้งใจ ตัวนี้มีตัวเลข %
   กำกับ เพราะแถบเปล่า ๆ อ่านไม่ออกว่าคืบจริงหรือค้าง
   โครงสร้าง: <div class=pbar><span class=track><i></i></span><b>42%</b></div> */
.pbar{display:flex; align-items:center; gap:9px}
.pbar .track{flex:1; height:9px; border-radius:99px; background:var(--sunk);
  overflow:hidden; box-shadow:inset 0 0 0 1px rgba(0,0,0,.05)}
.pbar .track i{display:block; height:100%; min-width:3px; border-radius:99px;
  background:linear-gradient(90deg, var(--primary-deep), var(--primary));
  transition:width .35s ease-out}
.pbar b{font-family:var(--mono); font-size:var(--t-helper); color:var(--ink2);
  min-width:38px; text-align:right; font-variant-numeric:tabular-nums}
.pbar.sm .track{height:6px}
.pbar.sm b{font-size:var(--t-helper); min-width:32px}
/* ยังไม่รู้ว่าทั้งหมดมีเท่าไร — แถบวิ่งไปมาแทนที่จะโกหกเป็นตัวเลข */
.pbar.wait .track i{width:32%; animation:pslide 1.4s ease-in-out infinite}
@keyframes pslide{0%{margin-left:0}50%{margin-left:68%}100%{margin-left:0}}

/* ── ปุ่มหลายปุ่มในช่องตาราง ────────────────────────────────────── */
td.acts{white-space:nowrap}
td.acts .btn{margin-right:4px}
td.acts form{display:inline}

/* ── ป้ายที่กดได้ ───────────────────────────────────────────────── */
.chip.link{background:var(--primary-wash); color:var(--primary-deep);
  border-color:var(--primary-deep); text-decoration:none; cursor:pointer}
.chip.link:hover{background:var(--primary-solid); color:var(--on-primary)}
.chip.sm{font-size:var(--t-small); padding:1px 5px}

/* ── แกลเลอรีแผนที่ ─────────────────────────────────────────────── */
.mapgrid{display:grid; gap:12px;
  grid-template-columns:repeat(auto-fill,minmax(330px,1fr))}
.mapcard img{display:block; width:100%; height:auto; border-radius:7px;
  border:1px solid var(--line); background:#fff}
.mapcard:target{outline:2px solid var(--primary-deep); outline-offset:2px}
@media (max-width:620px){
  .mapgrid{grid-template-columns:1fr}
}

/* ── ปุ่ม i — เปิดคำอธิบายมาตรฐานของกิจกรรมนั้น ─────────────────── */
.ibtn{display:inline-flex; align-items:center; justify-content:center;
  width:16px; height:16px; margin-left:6px; border-radius:50%;
  border:1px solid var(--line2); background:var(--surface); color:var(--ink2);
  font-family:var(--display); font-size:var(--t-helper); font-weight:700; font-style:italic;
  line-height:1; text-decoration:none; vertical-align:1px}
.ibtn:hover{background:var(--primary-solid); border-color:var(--primary-deep);
  color:var(--on-primary)}

/* ── ตัวเลขรองในป้าย เช่น "โรงพยาบาล 86 · หมุด 8" ───────────────── */
.chip .sub2{opacity:.72; font-weight:400}

/* ── เมนูย่อยบนแถบนำทาง ──────────────────────────────────────────────
   CSS ล้วน ไม่ใช้ JavaScript · เปิดทั้งตอนเอาเมาส์ชี้และตอนกด Tab เข้าไป
   (:focus-within) จึงใช้ด้วยแป้นพิมพ์ได้ · ไม่ใช้ <details> เพราะต้องกด
   สองครั้งกว่าจะไปถึงลิงก์ และปิดเองไม่ได้เมื่อย้ายไปเมนูอื่น            */
.top nav .mi{position:relative; display:inline-block}
.top nav .mi > a i{font-style:normal; font-size:var(--t-small); opacity:.65; margin-left:1px}
.top nav .mi .sub{
  display:none; position:absolute; left:0; top:100%; min-width:240px;
  background:var(--nav); border:1px solid rgba(255,255,255,.14);
  border-radius:0 0 6px 6px; padding:5px; z-index:950;
  box-shadow:0 10px 26px rgba(0,0,0,.34);
}
.top nav .mi:hover .sub, .top nav .mi:focus-within .sub{display:block}
.top nav .mi .sub a{display:flex; gap:9px; align-items:center; padding:8px 11px;
  font-size:var(--t-h6); border-radius:6px; white-space:nowrap}
.top nav .mi .sub a .ico{width:16px; height:16px; opacity:.85}
.top nav .mi .sub a .ico.sm{width:13px; height:13px; margin-left:-4px; opacity:.6}

/* ── การ์ดลูกค้า (หน้างานลูกค้า) ─────────────────────────────────── */
.pgrid{display:grid; grid-template-columns:repeat(auto-fill, minmax(380px, 1fr)); gap:14px}
@media(max-width:520px){.pgrid{grid-template-columns:1fr}}
.pcard{background:var(--surface); border:1px solid var(--line); border-radius:var(--r);
  box-shadow:var(--shadow); padding:16px 18px; display:flex; flex-direction:column; gap:14px}
.pcard.off{opacity:.62}
.pcard .pc-h{display:flex; gap:12px; align-items:flex-start}
.pcard .pc-ic{width:42px; height:42px; border-radius:11px; flex:none; display:grid; place-items:center;
  background:var(--primary-wash); color:var(--primary-deep)}
.pcard .pc-ic .ico{width:22px; height:22px}
.pcard .pc-n{min-width:0}
.pcard .pc-n > a{font-size:var(--t-h3); font-weight:700; color:var(--ink); text-decoration:none;
  line-height:1.3}
.pcard .pc-n > a:hover{text-decoration:underline}
.pcard .pc-m{display:flex; gap:5px; align-items:center; flex-wrap:wrap; margin-top:3px;
  font-size:var(--t-helper); color:var(--ink3)}
.pcard .pc-m > .ico{width:13px; height:13px}
.pcard .pc-k{display:grid; grid-template-columns:repeat(4, 1fr); border:1px solid var(--line);
  border-radius:8px; overflow:hidden}
.pcard .pc-k > *{padding:8px 11px; border-left:1px solid var(--line); color:inherit;
  text-decoration:none; min-width:0}
.pcard .pc-k > :first-child{border-left:none}
.pcard .pc-k a:hover{background:var(--primary-wash)}
.pcard .pc-k b{display:block; font-size:var(--t-emphasis); font-weight:700; line-height:1.25;
  font-variant-numeric:tabular-nums}
.pcard .pc-k b small{font-size:var(--t-h6); font-weight:500; color:var(--ink3)}
.pcard .pc-k i{display:flex; gap:4px; align-items:center; font-style:normal;
  font-size:var(--t-helper); color:var(--ink2); white-space:nowrap}
.pcard .pc-k i .ico{width:13px; height:13px}
.pcard .pc-a{display:flex; gap:8px; flex-wrap:wrap}
@media(max-width:520px){
  .pcard .pc-k{grid-template-columns:repeat(2, 1fr)}
  .pcard .pc-k > :nth-child(3){border-left:none}
  .pcard .pc-k > :nth-child(n+3){border-top:1px solid var(--line)}}

/* ── แถบลูกค้า ───────────────────────────────────────────────────────
   อยู่เหนือเนื้อหาทุกหน้าที่อยู่ใต้ลูกค้า เพื่อให้รู้ตลอดว่า "ตัวเลขที่เห็น
   เป็นของใคร" — หน้าที่กรองอยู่แต่ไม่บอกว่ากรองอะไร คือหน้าที่อ่านผิดได้ */
.progbar{background:var(--surface); border:1px solid var(--line); box-shadow:var(--shadow);
  border-radius:var(--r); padding:10px 14px 0; margin-bottom:14px}
.progbar .who{display:flex; gap:9px; align-items:center; flex-wrap:wrap; margin-bottom:8px}
/* เดิม "ลูกค้า" เป็นตัวพิมพ์ใหญ่กางตัว — ใช้กับภาษาไทยไม่ได้ (ไทยไม่มีตัวพิมพ์ใหญ่ และกางแล้วสระลอย) */
.progbar .who .k{display:inline-flex; align-items:center; gap:5px; font-size:var(--t-helper);
  color:var(--ink3)}
.progbar .who .k .ico{width:15px; height:15px}
.progbar .who .nm{font-family:var(--display); font-size:var(--t-h3); font-weight:700;
  color:var(--ink); text-decoration:none; margin-right:4px}
.progbar .who .nm:hover{text-decoration:underline}
.progbar .tabs{display:flex; gap:2px; flex-wrap:wrap;
  border-top:1px solid var(--line); padding-top:4px}
.progbar .tabs a{display:inline-flex; align-items:center; gap:6px; font-size:var(--t-h6);
  padding:8px 11px 7px; border-radius:6px 6px 0 0; white-space:nowrap;
  color:var(--ink2); text-decoration:none; border-bottom:2.5px solid transparent}
.progbar .tabs a .ico{width:16px; height:16px; opacity:.7}
.progbar .tabs a:hover{background:var(--sunk); color:var(--ink)}
.progbar .tabs a.on{background:var(--primary-wash); color:var(--primary-deep);
  font-weight:600; border-bottom-color:var(--primary-deep)}
.progbar .tabs a.on .ico{opacity:1}

/* ── กล่องคำอธิบายรายข้อในตารางความพร้อม ─────────────────────────────
   ช่อง ✓ ! ✗ บอกว่า "ขาด" แต่ไม่บอกว่าขาดอะไรและต้องแนบอะไร · กดแล้วเปิด
   กล่องนี้ซึ่งมีเกณฑ์จริงของผู้ว่าจ้าง รายการที่ต้องแนบ และจุดที่ตกบ่อย
   ชื่อคลาสขึ้นต้น rq- ทั้งหมด เพราะเคยตั้งชื่อชนสไตล์กลางมาแล้วสองครั้ง */
button.chip.rq{font:inherit; font-family:var(--mono); font-size:var(--t-helper);
  font-weight:600; cursor:pointer; line-height:1.5}
button.chip.rq:hover{filter:brightness(.94)}

/* หัวและปุ่มอยู่กับที่ · เนื้อหาตรงกลางเลื่อนได้ — ไม่งั้นบนมือถือปุ่ม
   "ไปหน้าที่แนบเอกสาร" จะจมอยู่ใต้ย่อหน้ากฎหมาย ทั้งที่เป็นสิ่งที่คนกดมาทำ */
.rqbox{border:1px solid var(--line2); border-radius:var(--r); padding:20px 22px;
  max-width:620px; width:calc(100% - 28px); max-height:88vh;
  display:flex; flex-direction:column; background:var(--surface);
  color:var(--ink); box-shadow:0 18px 60px rgba(0,0,0,.28)}
/* display:flex ข้างบนชนะกฎของเบราว์เซอร์ที่ซ่อน <dialog> ตอนยังไม่เปิด
   (สไตล์ของเราชนะสไตล์ตั้งต้นเสมอ ไม่ว่าจะเจาะจงแค่ไหน) — กล่องเปล่าจึงค้าง
   อยู่ท้ายกระดานลูกค้าทุกหน้า พร้อมปุ่ม "ไปหน้าที่แนบเอกสาร" ที่กดไม่ได้
   ต้องสั่งซ่อนเองตรง ๆ · เจอตอนตรวจงาน 24 ก.ย. 2569 */
.rqbox:not([open]){display:none}
.rqbox::backdrop{background:rgba(28,28,28,.42)}
.rqbox h2{margin:0 0 4px; font-size:var(--t-h3); padding-left:0}
.rqbox h2::before{content:none}          /* ไม่ต้องมีขีดเฉียง — ไม่ใช่ชื่อหน้า */
.rqbox ul{margin:0; padding-left:19px}
.rqbox li{margin-bottom:5px; line-height:1.6}
.rqbox p{margin:0; line-height:1.68}
.rq-head{flex:none; padding-right:56px}  /* เว้นที่ให้ปุ่มปิดมุมขวาบน */
.rq-scroll{flex:1 1 auto; overflow-y:auto; min-height:0;
  padding-right:4px; margin-right:-4px}
.rq-foot{flex:none; padding-top:13px; margin-top:2px;
  border-top:1px solid var(--line)}
.rq-x{position:absolute; top:13px; right:14px; margin:0}

/* สถานะของแถวที่กดมา — ต้องอยู่บนสุดเพราะคนกดมาเพราะเห็นกากบาทของแถวนั้น */
.rq-now{border-radius:5px; padding:9px 12px; font-size:var(--t-h6); margin-bottom:14px;
  border-left:3px solid var(--line2); background:var(--sunk)}
.rq-now.ok{border-left-color:var(--go); background:var(--go-wash); color:var(--go)}
.rq-now.soon{border-left-color:var(--watch); background:var(--watch-wash); color:var(--watch)}
.rq-now.miss{border-left-color:var(--stop); background:var(--stop-wash); color:var(--stop)}

.rq-sec{margin-bottom:13px; font-size:var(--t-h6)}
.rq-sec.warn{border-left:3px solid var(--watch); background:var(--watch-wash);
  border-radius:4px; padding:10px 12px}
.rq-sec.pdpa{border-left:3px solid var(--info); background:var(--info-wash);
  border-radius:4px; padding:10px 12px}
.rq-h{font-weight:700; font-size:var(--t-helper); color:var(--ink2); margin:0 0 4px !important}
/* ข้อความที่ยกมาจากแบบประเมินตรงตัว — ทำให้เห็นชัดว่าเป็นคำของผู้ว่าจ้าง
   ไม่ใช่คำอธิบายของเรา เพราะสองอย่างนี้เถียงกันไม่ได้ในวันตรวจ */
.rq-quote{border-left:3px solid var(--primary); background:var(--primary-wash);
  border-radius:4px; padding:9px 12px}
@media(max-width:620px){
  .rqbox{padding:16px 15px}
  .rq-x{top:10px; right:11px}
  .rq-head{padding-right:52px}
}

/* ── เครื่องมือดูตัวอย่างและปิดบังข้อมูลก่อนอัปโหลด (mask.js) ─────────
   ขึ้นใต้ช่องแนบไฟล์ทุกช่องที่เขียน data-mask ไว้ · ซ่อนอยู่จนกว่าจะเลือกไฟล์
   เพราะฟอร์มที่รกตั้งแต่ยังไม่ได้เลือกอะไร ทำให้คนไม่กล้าแตะ */
/* ช่องแนบไฟล์ส่วนใหญ่อยู่ใน .row ซึ่งเป็น flex — ถ้าไม่บังคับให้ขึ้นบรรทัดใหม่
   เต็มความกว้าง เครื่องมือจะไปเบียดอยู่ข้างปุ่มจนใช้ลากกล่องไม่ได้ */
.blind{flex:1 0 100%; width:100%; margin-top:10px}
.blind-bar{display:flex; gap:7px; flex-wrap:wrap; align-items:center; margin-bottom:7px}
.blind-note{font-size:var(--t-helper); color:var(--ink2)}
.blind-stage{background:var(--sunk); border:1px solid var(--line);
  border-radius:var(--r); overflow:auto; max-height:52vh}
.blind-cv{display:block; max-width:100%; touch-action:none; cursor:crosshair}
.blind-pdf{display:block; width:100%; height:52vh; border:0}
.blind-hint{font-size:var(--t-helper); color:var(--ink2); margin:7px 0 0}
.blind-hint.warn{color:var(--stop); font-weight:600}

/* ── ฟอร์มจุดเสี่ยง: เลือกเส้นทางที่ผ่านจุดนี้ ───────────────────────── */
.corrs{display:grid; grid-template-columns:repeat(auto-fill,minmax(230px,1fr)); gap:4px 14px;
  max-height:220px; overflow:auto; border:1px solid var(--line); border-radius:var(--r);
  padding:8px 10px; background:var(--surface)}
.corr{display:flex; gap:7px; align-items:baseline; font-size:var(--t-h6); line-height:1.5;
  cursor:pointer}
.corr input{margin:0}

/* ── ชั้นน้ำท่วมบนแผนที่ทะเบียนสถานที่ ─────────────────────────────── */
.floodbar{display:flex; flex-wrap:wrap; gap:6px; align-items:center; margin:0 0 8px}
.floodbar .chip{cursor:pointer; font:inherit; font-size:var(--t-helper)}
.flstat{font-size:var(--t-helper); color:var(--ink2); line-height:1.5}
.flstat.bad{color:var(--stop)}
.flhits{margin:8px 0 0; font-size:var(--t-h6)}
.flhits li{margin-bottom:3px; line-height:1.5}

/* ══════════════════════════════════════════════════════════════════
   ไอคอนเส้น (templates/_icons.html) + ปุ่มไอคอน
   ทุกปุ่มไอคอนต้องมี title หรือข้อความกำกับ — ไอคอนเดี่ยว ๆ คนเดาความหมายไม่ออก
   ══════════════════════════════════════════════════════════════════ */
.ico{width:16px; height:16px; flex:none; stroke:currentColor; fill:none; stroke-width:2;
  stroke-linecap:round; stroke-linejoin:round; vertical-align:-3px}
.ico.sm{width:13px; height:13px; vertical-align:-2px}
.ico.lg{width:19px; height:19px}
.ico.xl{width:24px; height:24px}
.btn .ico{margin:0 0 0 -2px}
.icb{display:inline-flex; align-items:center; justify-content:center; gap:5px; min-width:28px;
  height:28px; padding:0 8px; border:1px solid var(--line2); border-radius:6px;
  background:var(--surface); color:var(--ink2); font:inherit; font-size:12px; font-weight:600;
  line-height:1; cursor:pointer; text-decoration:none; white-space:nowrap}
.icb:hover{border-color:var(--primary); color:var(--primary-deep); background:var(--primary-wash)}
.icb:disabled{opacity:.35; cursor:default; background:var(--surface); color:var(--ink3);
  border-color:var(--line2)}
.icb.on{background:var(--primary-solid); color:var(--on-primary); border-color:var(--primary-solid)}
/* display:inline-flex ด้านบนชนะแอตทริบิวต์ hidden — ปุ่ม ↻ ของชั้นที่ยังไม่เปิดเลยโผล่ค้าง (2 ต.ค. 2569: Sea กด ↻ ของ
   ชั้นทางหลวงตอนชั้นยังปิด แล้ววงหมุนค้างไม่ทำอะไร) · ปุ่ม 'แผนใหม่' ของแผนที่ยังไม่บันทึกก็เช่นกัน */
.icb[hidden]{display:none}
.icb.hot{background:var(--stop); color:var(--surface); border-color:var(--stop)}
.icb.danger:hover{border-color:var(--stop); color:var(--stop); background:var(--stop-wash)}
.icb.pri{background:var(--primary-solid); color:var(--on-primary); border-color:var(--primary-solid)}
.icb.pri:hover{background:var(--primary-hover)}
/* ช่องกรอกขนาดเล็ก — กฎกลางของช่องกรอกเจาะจงสูง ขนาดจึงต้อง !important */
.in-sm{padding:4px 8px !important; font-size:13px !important; min-height:30px}

/* ══════════════════════════════════════════════════════════════════
   หน้าทะเบียนสถานที่ + วางแผนเดินทาง (แผนที่ซ้าย · แผงขวาสลับได้)
   ══════════════════════════════════════════════════════════════════ */
.pl-head{display:flex; flex-wrap:wrap; align-items:center; gap:6px 8px; margin:0 0 8px}
.pl-head h1{font-size:var(--t-h3); margin:0}
.pl-head .pl-sub{font-size:var(--t-helper); color:var(--ink3)}
.pl-head .btn{padding:6px 12px; font-size:13px}
.pl-dd{position:relative}
.pl-dd > summary{list-style:none}
.pl-dd > summary::-webkit-details-marker{display:none}
.pl-dd-menu{position:absolute; right:0; top:calc(100% + 4px); z-index:900; min-width:210px;
  background:var(--surface); border:1px solid var(--line2); border-radius:8px;
  box-shadow:var(--shadow); padding:4px}
.pl-dd-menu a{display:flex; gap:8px; align-items:center; padding:7px 9px; border-radius:6px;
  color:var(--ink); text-decoration:none; font-size:13px}
.pl-dd-menu a:hover{background:var(--sunk)}
.pl-bar{display:flex; flex-wrap:wrap; align-items:center; gap:6px 14px; padding:6px 10px;
  margin:0 0 8px; background:var(--surface); border:1px solid var(--line); border-radius:var(--r)}
.pl-g{display:inline-flex; flex-wrap:wrap; align-items:center; gap:4px}
.pl-g > .lb{display:inline-flex; align-items:center; gap:4px; font-size:11px; font-weight:600;
  color:var(--ink3); margin-right:2px}
.pl-bar .tg{display:inline-flex; align-items:center; gap:5px; padding:2px 9px 2px 3px;
  border:1px solid var(--line2); border-radius:999px; background:var(--surface);
  color:var(--ink3); font-family:var(--body); font-size:12px; font-weight:500; line-height:1.55;
  text-decoration:none; cursor:pointer; outline:none; margin:0}
.pl-bar .tg .sw{width:17px; height:17px; border-radius:50%; display:inline-flex; flex:none;
  align-items:center; justify-content:center; font-size:10px; font-weight:700;
  background:var(--sunk); color:var(--ink3); border:1px solid var(--line2)}
.pl-bar .tg .sw .ico{width:11px; height:11px; stroke-width:2.4}
.pl-bar .tg small{font-size:11px; opacity:.85}
.pl-bar .tg:hover{border-color:var(--ink3); color:var(--ink2)}
/* ชิปศูนย์บริการยี่ห้อ — ป้ายยี่ห้อ 5 อันแทนไอคอน (จางตอนปิด) */
.pl-bar .tg.tg-brands{gap:3px; padding:2px 6px}
.pl-bar .tg.tg-brands:not(.on) .tbrand{opacity:.6}
.pl-bar .tg.on{color:var(--ink); background:var(--sunk); border-color:var(--ink3); outline:none}
.pl-bar .tg.on .sw{background:var(--ink2); color:var(--surface); border-color:var(--ink2)}
.pl-bar .tg.on[data-c=lime]{background:var(--primary-wash); border-color:var(--primary); color:var(--primary-deep)}
.pl-bar .tg.on[data-c=lime] .sw{background:var(--primary-solid); border-color:var(--primary-solid); color:var(--on-primary)}
.pl-bar .tg.on[data-c=stop]{background:var(--stop-wash); border-color:var(--stop); color:var(--stop)}
.pl-bar .tg.on[data-c=stop] .sw{background:var(--stop); border-color:var(--stop); color:var(--surface)}
.pl-bar .tg.on[data-c=go]{background:var(--go-wash); border-color:var(--go); color:var(--go)}
.pl-bar .tg.on[data-c=go] .sw{background:var(--go); border-color:var(--go); color:var(--surface)}
.pl-bar .tg.on[data-c=watch]{background:var(--watch-wash); border-color:var(--watch); color:var(--watch)}
.pl-bar .tg.on[data-c=watch] .sw{background:var(--watch); border-color:var(--watch); color:var(--surface)}
.pl-bar .tg.on[data-c=info]{background:var(--info-wash); border-color:var(--info); color:var(--info)}
.pl-bar .tg.on[data-c=info] .sw{background:var(--info); border-color:var(--info); color:var(--surface)}
.pl-bar .tg.on[data-c=mute]{background:var(--sunk); border-color:var(--ink3); color:var(--ink)}
.pl-bar .tg.on[data-c=pink]{background:var(--cam-wash); border-color:var(--cam); color:var(--cam)}
.pl-bar .tg.on[data-c=pink] .sw{background:var(--cam); border-color:var(--cam); color:var(--surface)}
/* จำนวน/ความพร้อมของชั้น ปภ./OSM บนชิป + ปุ่ม ↻ ท้ายกลุ่ม (Sea 29 ก.ย. 2569 — เดิมอยู่หัวแผงวางแผนเดินทาง) */
.pl-bar .tg .rn{font-size:11px; font-weight:600; color:var(--ink2); margin-left:1px; font-variant-numeric:tabular-nums}
.pl-bar .tg .rn.no{color:var(--ink3); font-weight:400}
.pl-bar .tg .rn.old{color:var(--watch)}
.pl-bar .tg .rn.bad{color:var(--stop)}
.pl-bar .tg .rn.run{color:var(--info)}
.pl-bar .tg.on .rn{color:inherit}
.pl-bar .icb.xs2{height:24px; padding:0 8px; font-size:12px; border-radius:999px}
.pl-bar .rfb{height:24px; min-width:24px; padding:0 4px; border-radius:999px}
.pl-bar .rfb.spin .ico{animation:tpspin 1s linear infinite}
.pl-bar .rfb:disabled{opacity:.75; cursor:progress}
.pl-bar .flag{display:inline-flex; align-items:center; gap:5px; font-size:12px; font-weight:600;
  color:var(--watch); text-decoration:none; border:1px dashed var(--watch); border-radius:999px;
  padding:2px 9px; background:var(--watch-wash)}
/* แถบสถานะชั้นข้อมูล — ชั้นละป้ายสั้นบรรทัดเดียว (Sea 4 ต.ค. 2569 "ทำอย่างไรไม่ให้รก" — เดิมเป็นย่อหน้ายาว 3 บรรทัด)
   ดึงไม่สำเร็จ = ป้ายแดง · ข้อมูลเก่า/บางแหล่งล่ม = ป้ายส้ม · กำลังดึง = วงหมุนหน้าป้าย
   ข้อความเต็ม = ชี้ที่ป้าย หรือกดป้าย/"รายละเอียด" → การ์ดลอยใต้แถบ (ไม่ดันแผนที่ลง) · กดที่อื่น/Esc = ปิด */
.pl-statw{position:relative}
.pl-stat{display:flex; flex-wrap:wrap; align-items:center; gap:4px 6px; margin:-4px 0 6px;
  font-size:11.5px; line-height:1.4; color:var(--ink2)}
.pl-stat[hidden], .pl-stat .st[hidden], .pl-stat .st-more[hidden], .pl-stat-full[hidden]{display:none}
.pl-stat .st{display:inline-flex; align-items:center; gap:5px; max-width:100%; min-width:0; padding:1px 8px;
  border:1px solid var(--line); border-radius:999px; background:var(--surface); color:var(--ink2);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; cursor:pointer; font-variant-numeric:tabular-nums}
.pl-stat .st:hover{border-color:var(--ink3); color:var(--ink)}
.pl-stat .st.st-warn{background:var(--watch-wash); border-color:var(--watch); color:var(--watch)}
.pl-stat .st.st-bad{background:var(--stop-wash); border-color:var(--stop); color:var(--stop)}
.pl-stat .st.st-busy::before{content:""; width:8px; height:8px; flex:none; border-radius:50%;
  border:1.5px solid currentColor; border-right-color:transparent; animation:tpspin 1s linear infinite}
.pl-stat .st-more{border:0; background:none; padding:1px 4px; margin:0; font:inherit; color:var(--primary-deep);
  cursor:pointer; white-space:nowrap}
.pl-stat .st-more:hover{text-decoration:underline}
.pl-stat-full{position:absolute; left:0; top:calc(100% - 2px); z-index:1100; width:min(760px, 100%);
  max-height:min(50vh, 380px); overflow:auto; padding:6px 12px; background:var(--surface);
  border:1px solid var(--line2); border-radius:8px; box-shadow:var(--shadow-2);
  font-size:12.5px; line-height:1.5; color:var(--ink2)}
.pl-stat-full p{margin:0; padding:5px 0; border-top:1px solid var(--line)}
.pl-stat-full p:first-child{border-top:0}
.pl-stat-full p.st-warn{color:var(--watch)}
.pl-stat-full p.st-bad{color:var(--stop)}
.pl-main{display:grid; grid-template-columns:minmax(0,1.45fr) minmax(360px,1fr); gap:10px;
  align-items:start}
.pl-mapwrap{position:relative}
/* --pl-top = ตำแหน่งจริงของแผนที่ (places.html วัดแล้วตั้งที่ <html>) → แผนที่และแผงข้างสูงพอดีจอเสมอ */
html{--pl-top:205px}
.pl-main #map{height:calc(100vh - var(--pl-top, 205px) - 14px); min-height:460px}
.pl-side{background:var(--surface); border:1px solid var(--line); border-radius:var(--r);
  height:calc(100vh - var(--pl-top, 205px) - 14px); min-height:460px; display:flex; flex-direction:column;
  overflow:hidden}
@media(max-width:1000px){
  .pl-main{grid-template-columns:1fr}
  .pl-main #map{height:380px; min-height:0}
  .pl-side{height:auto; min-height:0; overflow:visible}
}
.pl-pane{display:flex; flex-direction:column; flex:1; min-height:0}
.pl-pane[hidden]{display:none}
/* ── วางแผนเดินทาง: ช่องกรอก กับ ผล เป็นสองแผงข้างกัน (Sea 28 ก.ย. 2569) ─────────────
   "panel ที่ให้กรอก กับ panel รายละเอียด อยากให้อยู่ข้าง ๆ กันได้ไหม แยกกัน"
   จอกว้าง ≥ 1280: แผนที่ | ช่องกรอก | ผล · 1001–1279: แผนที่เต็มแถวด้านบน แล้วช่องกรอก | ผล ข้างกัน ·
   มือถือ: เรียงลงมา (แผงผลที่ยังว่างไม่แสดง) · แต่ละแผงเลื่อนในตัวเอง แก้ทางซ้ายเห็นผลทางขวาทันที */
.wrap.wide{max-width:1880px}
.pl-res[hidden]{display:none}
.pl-main.split{grid-template-columns:minmax(0,1.25fr) minmax(330px,380px) minmax(380px,1fr)}
.pl-res .pp-head{background:var(--primary-wash)}
.tp-empty{display:flex; flex-direction:column; align-items:center; justify-content:center; gap:6px;
  text-align:center; min-height:100%; padding:28px 30px; color:var(--ink3); font-size:12.5px; line-height:1.6}
.tp-empty[hidden]{display:none}
.tp-empty .ico{width:34px; height:34px; color:var(--line2); stroke-width:1.6}
.tp-empty b{color:var(--ink2); font-size:14px}
@media(max-width:1279px){
  .pl-main.split{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .pl-main.split .pl-mapwrap{grid-column:1 / -1}
  .pl-main.split #map{height:min(440px, 52vh); min-height:320px}
  .pl-main.split .pl-side{height:calc(100vh - 120px); min-height:420px}
}
@media(max-width:1000px){
  .pl-main.split{grid-template-columns:minmax(0,1fr)}
  .pl-main.split #map{height:380px; min-height:0}
  .pl-main.split .pl-side{height:auto; min-height:0}
  .pl-res.no-plan{display:none}
}
.pp-head{flex:none; display:flex; align-items:center; gap:6px; padding:7px 10px;
  border-bottom:1px solid var(--line); background:var(--surface)}
.pp-head b{font-size:14px}
.pp-body{flex:1; min-height:0; overflow:auto}
.pp-foot{flex:none; padding:5px 10px; border-top:1px solid var(--line); font-size:11.5px;
  color:var(--ink3); background:var(--sunk)}
.pl-note{margin:8px 10px 0; padding:6px 9px; font-size:12px; line-height:1.5;
  background:var(--watch-wash); border-left:3px solid var(--watch); border-radius:4px}
.pr{display:grid; grid-template-columns:20px minmax(0,1fr) auto; gap:8px; align-items:center;
  padding:5px 10px; border-bottom:1px solid var(--line); cursor:pointer}
.pr[hidden]{display:none}
.pr:hover{background:var(--sunk)}
.pr.sel{background:var(--primary-wash)}
.pr.off{opacity:.55}
.pr .ic{width:18px; height:18px; display:flex; align-items:center; justify-content:center;
  font-size:10px; font-weight:700; border-radius:4px}
.pr .t{min-width:0}
.pr .t b{display:block; font-size:13px; font-weight:600; line-height:1.35; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap}
.pr .t > span{display:block; font-size:11.5px; color:var(--ink3); line-height:1.4; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap}
.pr .t .np{display:inline; color:var(--watch); font-weight:600}
/* ชื่อ + โลโก้ประเภท (kind_chip) บรรทัดเดียว: ชื่อยาวถูกตัด โลโก้ไม่หาย */
.pr .t b.wl{display:flex; align-items:center; gap:5px; overflow:visible}
.pr .t b.wl .nm{min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.pr .t b.wl .klogo{flex:none; padding:1px 3px}
.pr .t b.wl .flogo{flex:none}
.pr .t b.wl .tbrand.img.flogo{padding:1px 3px}
.pr .a{display:flex; gap:4px}
.pr .a .icb{height:26px; min-width:26px; padding:0 6px}
/* เครื่องมือบนแผนที่ */
.mtool{display:flex; flex-direction:column; gap:5px}
.mtool button{display:flex; align-items:center; gap:6px; padding:6px 10px;
  border:1px solid var(--line2); border-radius:8px; background:var(--surface); color:var(--ink);
  font:inherit; font-size:12px; font-weight:600; line-height:1.2; cursor:pointer;
  box-shadow:0 1px 4px rgba(0,0,0,.18); white-space:nowrap}
.mtool button:hover{border-color:var(--primary); color:var(--primary-deep)}
.mtool button.on{background:var(--stop); color:var(--surface); border-color:var(--stop)}
.mtool button.on.pin{background:var(--primary-solid); border-color:var(--primary-solid)}
/* ── ตัวกรองรถ/ผู้ขนส่ง (static/fleetmap.js · Sea 28 ก.ย. 2569) — เรียงลงมาใต้ปุ่มเครื่องมือ
   ยังไม่ปักจุด = จาง (บอกว่าต้องปักก่อน) · ปักจุดเกิดเหตุ/จุดรับส่งแล้ว = ใช้ได้ทันที ── */
.mfleet{width:212px; background:var(--surface); border:1px solid var(--line2); border-radius:10px;
  box-shadow:0 1px 4px rgba(0,0,0,.18); font-size:12px; line-height:1.35; color:var(--ink); overflow:hidden}
.mfleet.off{opacity:.78}
.mf-h{display:flex; align-items:center; gap:6px; padding:6px 6px 6px 10px; background:var(--sunk);
  border-bottom:1px solid var(--line)}
.mfleet.shut .mf-h{border-bottom:0}
.mf-h b{font-weight:700}
.mf-h small{color:var(--ink3); font-size:11px; flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.mf-x{border:0; background:transparent; color:var(--ink2); cursor:pointer; padding:2px; display:flex}
.mf-busy{width:11px; height:11px; border:2px solid var(--primary-solid); border-right-color:transparent;
  border-radius:50%; animation:mfspin .8s linear infinite; flex:none}
@keyframes mfspin{to{transform:rotate(360deg)}}
.mf-b{padding:6px 8px 7px}
.mf-r{display:flex; align-items:center; gap:7px; padding:4px 2px; cursor:pointer; border-radius:6px}
.mf-r:hover{background:var(--sunk)}
.mf-r[aria-disabled]{cursor:default; color:var(--ink3)}
.mf-r[aria-disabled]:hover{background:none}
.mf-r input{margin:0; flex:none}
.mf-r .mf-l{flex:1; min-width:0; font-weight:600}
.mf-r .mf-l small{display:block; font-weight:400; font-size:10.5px; color:var(--ink3)}
.mf-r > b{font-variant-numeric:tabular-nums; color:var(--ink2); font-weight:700}
.mf-sw{width:20px; height:20px; flex:none; display:inline-flex; align-items:center; justify-content:center; border-radius:5px}
.mf-sw svg{width:14px; height:14px}
.mf-sw.k-base{background:var(--surface); color:var(--ink2); border:1.5px solid var(--ink2)}
.mf-sw.k-base .ico{width:12px; height:12px; stroke-width:2.4}
.mf-sw.k-empty{background:var(--go-wash); color:var(--go)}
.mf-sw.k-driver{background:var(--primary-wash); color:var(--primary-solid)}
.mf-sw path{fill:currentColor}
.mf-days{display:flex; flex-wrap:wrap; align-items:center; gap:4px; margin:6px 0 2px}
.mf-days span{font-size:11px; color:var(--ink3); width:100%}
.mf-days button{border:1px solid var(--line2); background:var(--surface); color:var(--ink2); border-radius:999px;
  padding:1px 7px; font:inherit; font-size:11px; cursor:pointer}
.mf-days button.on{background:var(--ink); border-color:var(--ink); color:var(--surface)}
.mf-days button:disabled{cursor:default; opacity:.6}
.mf-n{margin:5px 0 0; font-size:10.5px; color:var(--ink3); line-height:1.4}
.mf-n.warn{color:var(--watch)}
@media(max-width:560px){ .mfleet{width:180px} .mf-r .mf-l small{display:none} }
/* หมุดลูกศร: รถว่าง (เขียว) · คนขับ (ฟ้า) — หมุนตามทิศที่กำลังไป · จุดกลม = ไม่รู้ทิศ/ถึงแล้ว
   ข้อมูลที่ผ่านไปแล้ว (รถว่างที่หมดช่วงว่าง · งานที่ส่งแล้ว) จางลง · ยังไม่เริ่ม = โปร่ง */
.fm{width:24px; height:24px; display:flex; align-items:center; justify-content:center}
.fm svg{width:22px; height:22px; filter:drop-shadow(0 1px 1.5px rgba(0,0,0,.45)); transition:transform .2s}
.fm path{stroke:var(--surface); stroke-width:1.6; stroke-linejoin:round}
.fm.k-empty path{fill:var(--go)}
.fm.k-driver path{fill:var(--primary-solid)}
.fm.s-before path, .fm.s-soon path{fill:var(--surface)}
.fm.k-empty.s-before path, .fm.k-empty.s-soon path{stroke:var(--go); stroke-width:2.2}
.fm.k-driver.s-before path{stroke:var(--primary-solid); stroke-width:2.2}
.fm.s-past, .fm.s-arrived{opacity:.55}
.fm.dot i{width:12px; height:12px; border-radius:50%; border:2px solid var(--surface); box-shadow:0 1px 2px rgba(0,0,0,.45)}
.fm.k-empty.dot i{background:var(--go)}
.fm.k-driver.dot i{background:var(--primary-solid)}
.fm.dot.s-soon i, .fm.dot.s-before i{background:var(--surface); border-color:var(--go)}
.fm.k-driver.dot.s-before i{border-color:var(--primary-solid)}
/* คนขับจากข้อมูลจำลอง (driverlog_mock) — สีม่วง ไม่ให้สับสนกับพิกัดจริง */
.fm.k-driver.s-mock path{fill:#7c4dff; stroke-dasharray:3 2}
.fm.k-driver.dot.s-mock i{background:#7c4dff; border-style:dashed}
/* หมุดกลุ่ม: หลายรายการที่พิกัดตรงกันเป๊ะ (ฐานปัด ~1 กม. · คนขับระดับอำเภอ) — สัญลักษณ์ของชนิด + ตัวเลข
   กดแล้วกางออกเป็นวงรอบจุดจริง (fleetmap.js spread) · ตอนกางอยู่หมุดกลุ่มจางลง · เส้นโยงสีตามชนิด */
.fmg{position:relative; width:26px; height:26px; display:flex; align-items:center; justify-content:center; cursor:pointer}
.fmg .fmn{position:absolute; top:-8px; right:-11px; min-width:18px; height:18px; padding:0 4px; box-sizing:border-box;
  border-radius:9px; background:var(--ink); color:var(--surface); font:700 10.5px/15px var(--mono); text-align:center;
  border:1.5px solid var(--surface); box-shadow:0 1px 2px rgba(0,0,0,.4)}
.fmg.k-empty .fmn{background:var(--go)}
.fmg.k-driver .fmn{background:var(--primary-solid)}
.fmg::before{content:''; position:absolute; inset:-3px; border-radius:50%; border:1.5px dashed var(--ink3); opacity:.8}
.fmg.open{opacity:.5}
.fm-leg{stroke:var(--ink2)}
.fm-leg.k-empty{stroke:var(--go)}
.fm-leg.k-driver{stroke:var(--primary-solid)}
.mhint{position:absolute; top:50px; left:54px; z-index:800;
  display:flex; align-items:center; gap:8px; max-width:min(440px, calc(100% - 200px));
  background:var(--ink); color:var(--surface); font-size:12px; line-height:1.4;
  padding:6px 8px 6px 12px; border-radius:999px; box-shadow:0 2px 8px rgba(0,0,0,.3)}
.mhint[hidden]{display:none}
@media(max-width:560px){ .mhint.idle{display:none} }
.mhint button{border:0; background:transparent; color:var(--surface); cursor:pointer; padding:0 4px;
  font:inherit; opacity:.8}
.msearch{position:absolute; top:10px; left:54px; z-index:800; width:min(320px, calc(100% - 180px))}
.msearch .box{display:flex; align-items:center; gap:6px; background:var(--surface);
  border:1px solid var(--line2); border-radius:8px; padding:0 8px; box-shadow:0 1px 4px rgba(0,0,0,.18)}
.msearch .box input{border:0 !important; outline:none; padding:7px 0 !important; font-size:13px !important;
  background:transparent !important}
.msearch .box .ico{color:var(--ink3)}
.mmenu{min-width:210px}
.mmenu .hd{font-size:11px; color:var(--ink3); margin:0 0 4px}
.mmenu a{display:flex; align-items:center; gap:8px; padding:6px 6px; border-radius:6px;
  color:var(--ink); text-decoration:none; font-size:13px; font-weight:600}
.mmenu a small{display:block; font-weight:400; color:var(--ink3); font-size:11px}
.mmenu a:hover{background:var(--sunk)}
.mmenu a .ico{color:var(--primary-deep)}
.mmenu a.hot .ico{color:var(--stop)}
/* รายการคำแนะนำ (ค้นหา) */
.sug{border:1px solid var(--line2); border-radius:8px; background:var(--surface);
  box-shadow:var(--shadow); margin-top:4px; max-height:300px; overflow:auto; position:relative; z-index:850}
.sug[hidden]{display:none}
.sug .gh{font-size:10.5px; font-weight:700; color:var(--ink3); padding:5px 10px 2px;
  background:var(--sunk); position:sticky; top:0}
.sug .it{display:flex; gap:8px; align-items:flex-start; padding:6px 10px; cursor:pointer;
  border-top:1px solid var(--line); font-size:13px; line-height:1.35}
.sug .it:hover{background:var(--primary-wash)}
.sug .it .ico{margin-top:2px; color:var(--ink3)}
.sug .it small{display:block; color:var(--ink3); font-size:11px}
.sug .it .ap{color:var(--watch)}
.sug .none{padding:8px 10px; font-size:12px; color:var(--ink3)}
.sug .none.warn{color:var(--watch); background:var(--watch-wash); font-weight:600; line-height:1.5}
.sug .none .ico{vertical-align:-2px}
/* ── แผงวางแผนเดินทาง ── */
.tp-sec{padding:8px 10px}
.tp-sec + .tp-sec{border-top:1px solid var(--line)}
.tp-lbl{display:flex; align-items:center; gap:6px; font-size:11.5px; font-weight:700; color:var(--ink2);
  margin:0 0 5px}
.tp-lbl .spacer{flex:1}
.tp-lbl .tp-i{color:var(--ink3); cursor:help}
.tp-dt{display:flex; gap:4px}
.tp-dt input[type=date]{flex:1; min-width:0}
.tp-dt input[type=text]{width:58px !important; flex:none; text-align:center; font-weight:700}
.tp-row{display:grid; grid-template-columns:22px 64px minmax(0,1fr) auto; gap:5px; align-items:center;
  grid-template-areas:"no rl q acts" ". . sug sug" ". sub sub sub"; padding:4px 0}
.tp-row > .tp-no{grid-area:no} .tp-row > .rl{grid-area:rl} .tp-row > .q{grid-area:q}
.tp-row > .acts{grid-area:acts} .tp-row > .sugwrap{grid-area:sug} .tp-row > .sub{grid-area:sub}
@media(max-width:560px){
  .tp-row{grid-template-columns:22px 58px minmax(0,1fr) auto;
    grid-template-areas:"no rl q q" ". . sug sug" ". sub sub acts"}
  .tp-opts{grid-template-columns:1fr 1fr !important}
  .tp-opts > div:first-child{grid-column:1 / -1}
}
.tp-row + .tp-row{border-top:1px dashed var(--line)}
.tp-no{width:22px; height:22px; border-radius:50%; display:flex; align-items:center; justify-content:center;
  font-size:11px; font-weight:700; background:var(--primary-solid); color:var(--on-primary)}
.tp-no.drop{background:var(--ink); color:var(--surface)}
.tp-no.via{background:var(--ink3); color:var(--surface)}
.tp-row select{padding:3px 4px !important; font-size:12px !important; min-height:28px}
.tp-row .q{min-width:0}
.tp-row .acts{display:flex; gap:3px}
.tp-row .acts .icb{min-width:26px; height:26px; padding:0 5px}
.tp-row .sub{display:flex; flex-wrap:wrap; gap:4px 10px; align-items:center;
  font-size:11.5px; color:var(--ink3); margin:0}
.tp-row .sub input{width:58px !important; padding:2px 6px !important; font-size:12px !important; min-height:24px}
.tp-row .sub .ap{color:var(--watch); font-weight:600}
.tp-row .sub .ll{color:var(--ink3); font-variant-numeric:tabular-nums}
.tp-fl-load{display:inline-flex; align-items:center; gap:6px; color:var(--info); font-weight:600}
.tp-fl-note{color:var(--watch)}
.tp-dx-bad{color:var(--stop); font-weight:700}
.tp-fl-load .tp-busy{border-color:var(--info); border-right-color:transparent; margin-right:0}
/* ── กล่องสถานะน้ำท่วมกลางแผนที่ (28 ก.ย. 2569) ─────────────────────────
   Sea: "ตอนแรกนึกว่าไม่มีข้อมูล นึกว่า bug" — เดิมบอกความคืบหน้าแค่บรรทัดเล็กใต้แถบตัวกรอง
   ตอนนี้ขึ้นกลางแผนที่ตรงที่ตาดูอยู่ พร้อมแถบความคืบหน้าและเวลาที่เหลือ · ไม่บังการใช้แผนที่ */
.flov{position:absolute; z-index:1000; left:50%; top:92px; transform:translateX(-50%);
  width:min(440px, calc(100% - 24px)); background:var(--surface); border:1px solid var(--line);
  border-left:4px solid var(--info); border-radius:var(--r); box-shadow:var(--shadow-2);
  padding:11px 14px 12px; font-size:var(--t-sub); line-height:1.5}
.flov[hidden]{display:none}
.flov.ok{border-left-color:var(--c-go)} .flov.warn{border-left-color:var(--c-watch)}
.flov.bad{border-left-color:var(--stop)}
.flov .fo-h{display:flex; gap:8px; align-items:center}
.flov .fo-h b{flex:1; font-size:var(--t-h6)}
.flov .fo-ic{display:inline-flex; color:var(--info)}
.flov.ok .fo-ic{color:var(--go)} .flov.warn .fo-ic{color:var(--watch)} .flov.bad .fo-ic{color:var(--stop)}
.flov .fo-ic .ico{width:19px; height:19px}
.flov .fo-x{border:0; background:none; font-size:18px; line-height:1; color:var(--ink3); cursor:pointer;
  padding:0 2px}
.flov .fo-bar{height:7px; border-radius:5px; background:var(--sunk); overflow:hidden; margin:8px 0 6px}
.flov .fo-bar[hidden]{display:none}
.flov .fo-bar i{display:block; height:100%; width:3%; background:var(--info); border-radius:5px;
  transition:width .6s ease}
.flov .fo-bar.ind i{width:35%; animation:foind 1.3s ease-in-out infinite}
@keyframes foind{0%{transform:translateX(-100%)} 100%{transform:translateX(300%)}}
.flov .fo-d{color:var(--ink2)}
.flov .fo-a{display:flex; gap:6px; flex-wrap:wrap; margin-top:8px}
.flov .fo-a:empty{display:none}
.fo-spin{display:inline-block; width:17px; height:17px; border:2.5px solid var(--info);
  border-right-color:transparent; border-radius:50%; animation:tpspin .8s linear infinite}
/* ปุ่มชั้นน้ำท่วมที่กำลังดึงข้อมูล — หมุนให้เห็นว่ายังทำงานอยู่ */
/* กำลังดึงน้ำท่วม: ไอคอนในชิปกลายเป็นวงหมุน — เห็นชัดว่าระบบกำลังทำงาน */
#floodbar .tg.fl-busy .sw{animation:tpspin 1s linear infinite; border:2px solid currentColor;
  border-right-color:transparent; background:transparent}
#floodbar .tg.fl-busy .sw .ico{visibility:hidden}
.tp-row .sub a{font-size:11.5px}
.tp-row .sugwrap{position:relative; min-height:0}
.tp-row .sugwrap .sug{position:absolute; left:0; right:0; top:-3px; margin:0; z-index:900}
.tp-row.nopt .q{border-color:var(--watch) !important; background:var(--watch-wash) !important}
.tp-opts{display:grid; grid-template-columns:minmax(0,1.5fr) minmax(0,.7fr) minmax(0,.8fr); gap:6px}
.tp-opts label{display:block; font-size:11px; margin:0 0 2px; color:var(--ink3)}
.tp-go{display:flex; gap:8px; align-items:center; margin-top:8px}
.tp-go .btn{display:inline-flex; align-items:center}
.tp-alert{display:flex; gap:8px; align-items:flex-start; margin:8px 0 0; padding:8px 10px;
  border-radius:8px; font-size:12.5px; line-height:1.5; background:var(--stop-wash);
  border:1px solid var(--stop); color:var(--stop)}
.tp-alert.info{background:var(--info-wash); border-color:var(--info); color:var(--info)}
.tp-alert.warn{background:var(--watch-wash); border-color:var(--watch); color:var(--watch)}
.tp-alert[hidden]{display:none}
.tp-alert b{display:block}
.tp-busy{display:inline-block; width:14px; height:14px; border:2px solid var(--on-primary);
  border-right-color:transparent; border-radius:50%; animation:tpspin .8s linear infinite;
  vertical-align:-2px; margin-right:6px}
@keyframes tpspin{to{transform:rotate(360deg)}}
.tp-rules{font-size:11px; color:var(--ink3); line-height:1.5; margin:6px 0 0}
.tp-sum{display:grid; grid-template-columns:repeat(auto-fit,minmax(104px,1fr)); gap:5px}
.tp-sum div{background:var(--sunk); border-radius:6px; padding:5px 8px; min-width:0}
.tp-sum small{display:flex; gap:4px; align-items:center; font-size:10.5px; color:var(--ink3)}
.tp-sum b{display:block; font-size:14px; font-weight:700; white-space:nowrap; overflow:hidden;
  text-overflow:ellipsis}
.tp-note{font-size:11.5px; color:var(--ink3); line-height:1.5; margin:6px 0 0}
.tp-note.warn{color:var(--watch)}
.tp-card{border:1px solid var(--line2); border-left:5px solid var(--primary-solid);
  border-radius:8px; padding:7px 9px; background:var(--surface)}
.tp-card.drop{border-left-color:var(--ink)}
.tp-card.via{border-left-color:var(--ink3)}
.tp-ch{display:flex; gap:8px; align-items:flex-start; cursor:pointer}
.tp-ch .tp-no{width:24px; height:24px; font-size:12px; margin-top:1px}
.tp-cn{flex:1; min-width:0}
.tp-cn small{font-size:11px; color:var(--ink3); font-weight:600}
.tp-cn b{display:block; font-size:14px; line-height:1.3}
.tp-times{display:flex; flex-wrap:wrap; gap:4px 10px; align-items:center; margin:5px 0 0 32px;
  font-size:11.5px; color:var(--ink3)}
.tp-times label{display:inline-flex; gap:4px; align-items:center; white-space:nowrap; margin:0;
  font-family:var(--body); font-size:11.5px}
.tp-times input.tm{width:58px !important; padding:2px 4px !important; font-size:13px !important;
  font-weight:700; text-align:center; min-height:26px}
.tp-times input.dwn{width:52px !important; padding:2px 5px !important; font-size:12px !important;
  min-height:26px}
.tp-times input.anc{border:2px solid var(--primary-solid) !important; background:var(--primary-wash) !important;
  color:var(--primary-deep) !important}
.tp-times .ux{border:0; background:transparent; color:var(--primary-deep); cursor:pointer; padding:0 2px}
.tp-times .dd{font-weight:600; color:var(--ink2)}
.tp-info{margin:4px 0 0 32px; font-size:12px; color:var(--ink2); line-height:1.5}
.tp-info span+span:before{content:" · "; color:var(--ink3)}
.tp-rule{margin:4px 0 0 32px; font-size:11.5px; background:var(--sunk); border-radius:5px; padding:3px 7px}
.tp-w{display:flex; gap:5px; align-items:flex-start; margin:4px 0 0 32px; color:var(--watch);
  font-size:11.5px; font-weight:600; line-height:1.4}
.tp-leg{margin:0 0 0 11px; padding:5px 0 7px 18px; border-left:2px dotted var(--line2)}
.tp-lh{display:flex; gap:5px; align-items:center; font-size:11.5px; color:var(--ink2); font-weight:600}
.tp-lh small{font-weight:400; color:var(--ink3)}
.tp-rs{background:var(--primary-wash); border-radius:6px; padding:5px 8px; margin:5px 0}
.tp-rs.off{background:var(--watch-wash)}
/* พักที่ปั๊มน้ำมัน = จุดพักสำรอง (ช่วงที่ไม่มีจุดพักในเครือข่าย · 29 ก.ย. 2569) — พื้นเทา ไอคอนเข้ม */
.tp-rs.gas{background:var(--sunk)}
.tp-rs.gas .tp-ri{background:var(--ink)}
.tp-rh{display:flex; gap:7px; align-items:flex-start; cursor:pointer}
.tp-ri{width:20px; height:20px; border-radius:4px; background:var(--primary-solid); color:var(--on-primary);
  display:flex; align-items:center; justify-content:center; font-weight:700; flex:none; font-size:11px}
.tp-rs.off .tp-ri{background:var(--watch)}
.tp-rt{flex:1; min-width:0}
.tp-rt b{font-weight:600; font-size:12.5px; display:block}
.tp-rt small{display:block; color:var(--ink3); font-size:11px; line-height:1.45}
.tp-rs .tp-times, .tp-rs .tp-w{margin-left:27px}
.tp-ri .ico{width:14px; height:14px; stroke-width:2.4}
.tp-fyi{margin:4px 0 0; font-size:11.5px; color:var(--ink3)}
.tp-fyi summary{cursor:pointer; color:var(--ink2); padding:2px 0}
.tp-fyi .fc{display:inline-flex; flex-wrap:wrap; gap:2px 10px; vertical-align:top; margin-left:4px}
.tp-fyi .rg{color:var(--ink3); white-space:nowrap; font-variant-numeric:tabular-nums}
.tp-fyi .fc > span{display:inline-flex; align-items:center; gap:4px; white-space:nowrap}
.tp-fyi .fc .catb{vertical-align:0}
.tp-fyi ul{list-style:none; margin:3px 0 0; padding:0}
.tp-fyi li{display:flex; gap:7px; align-items:flex-start; padding:4px 2px; border-top:1px solid var(--line);
  cursor:pointer; line-height:1.45}
.tp-fyi li > .catb{margin-top:0}
.tp-fyi li .tx{flex:1; min-width:0}
.tp-fyi li:hover{background:var(--sunk)}
.tp-fyi li b{font-weight:600; color:var(--ink2)}
.tp-fyi .k{color:var(--ink3)}
/* กล้อง CCTV ที่เส้นทางผ่าน (Sea 6 ต.ค. 2569) — ตารางภาพท้ายกล่องข้อมูลประกอบของแต่ละช่วง (trip.js camGrid)
   ภาพ 16:9 โหลดจากต้นทางเฉพาะช่องที่เห็น · ยังไม่มา = ไอคอนกล้อง · โหลดไม่ขึ้น = "ไม่มีภาพ" · วิดีโออย่างเดียว = ▶ */
.tp-camh{display:flex; flex-wrap:wrap; align-items:center; gap:2px 5px; margin:6px 0 4px; padding-top:5px;
  border-top:1px solid var(--line); color:var(--ink2); font-weight:600}
.tp-camh small{font-weight:400; color:var(--ink3)}
.tp-camg{display:grid; grid-template-columns:repeat(auto-fill, minmax(112px, 1fr)); gap:8px 7px; margin:0 0 4px}
.tp-camt{display:flex; flex-direction:column; gap:1px; min-width:0; padding:3px; border-radius:7px; cursor:pointer; line-height:1.35}
.tp-camt:hover{background:var(--sunk)}
.tp-camt.sel{background:var(--primary-wash); box-shadow:inset 0 0 0 2px var(--primary-solid)}
.tp-camt .tp-th{width:100%; height:auto; aspect-ratio:16/9; margin-bottom:2px}
.tp-camt .tp-th .sgn{width:22px; height:22px}
.tp-camt .k{font-size:10.5px; font-variant-numeric:tabular-nums}
.tp-camt b{font-size:11.5px; font-weight:600; color:var(--ink2); display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
  overflow:hidden; overflow-wrap:anywhere}
.tp-camt small{font-size:10.5px; color:var(--ink3); white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.tp-camt.off .tp-th, .tp-camt.old .tp-th{opacity:.55; filter:grayscale(.85)}
.tp-camt.off b, .tp-camt.off small{color:var(--ink3)}
.tp-th.none{background:#0b0d10; border-color:#0b0d10}
.tp-th .pl{color:#fff; font-size:17px; line-height:1; opacity:.9}
.tp-th.wait::before{content:""; position:absolute; inset:0; background:linear-gradient(90deg, transparent, rgba(127,127,127,.18), transparent);
  background-size:200% 100%; animation:tpth 1.2s linear infinite}
@keyframes tpth{from{background-position:200% 0} to{background-position:-200% 0}}
@media (prefers-reduced-motion: reduce){ .tp-th.wait::before{animation:none} }
.tp-camt .tp-th.bad::after{content:"ไม่มีภาพ"; position:absolute; left:0; right:0; bottom:2px; text-align:center;
  font-size:10px; color:var(--ink3)}
.tp-dirty{color:var(--watch); font-weight:600}
/* เอกสาร Route Hazard จากแผนนี้ — แถวใต้ลิงก์แชร์ + กล่องถาม 3 ช่อง (Sea 29 ก.ย. 2569) · ชื่อคลาส tp-rha / tpd- ไม่ชนสไตล์กลาง */
.tp-rha{margin-top:8px; padding-top:8px; border-top:1px dashed var(--line2)}
.tp-rha-row{display:flex; flex-wrap:wrap; gap:5px 6px; align-items:center; font-size:12px}
.tp-rha-row > .ico{color:var(--primary-solid)}
.tp-rha-row .spacer{flex:1}
.tp-rha-no{font-family:var(--code); font-weight:700; font-size:12px}
.tp-rha-p{max-width:220px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.tpd{border:1px solid var(--line2); border-radius:var(--r); padding:18px 20px 16px; width:calc(100% - 28px);
  max-width:520px; background:var(--surface); color:var(--ink); box-shadow:0 18px 60px rgba(0,0,0,.28)}
.tpd::backdrop{background:rgba(28,28,28,.42)}
.tpd h3{display:flex; gap:7px; align-items:center; margin:0 34px 3px 0; font-size:var(--t-h4); line-height:1.35}
.tpd h3 .ico{color:var(--primary-solid)}
.tpd-x{position:absolute; top:12px; right:12px; margin:0}
.tpd-sub{margin:0 0 10px; font-size:12px; color:var(--ink3); line-height:1.55}
.tpd-sub b{color:var(--ink); font-family:var(--code)}
.tpd-f{display:flex; gap:6px; align-items:center; font-size:11.5px; font-weight:600; color:var(--ink2);
  margin:9px 0 3px; text-transform:none; letter-spacing:0}
.tpd input.in-sm{width:100%}
.tpd-note{margin:8px 0 0; font-size:11.5px; color:var(--ink3); line-height:1.5}
.tpd-note.warn{color:var(--watch)}
.tpd-note .ico{vertical-align:-2px}
.tpd-foot{display:flex; flex-wrap:wrap; gap:6px; align-items:center; margin-top:14px}
.tpd-foot .spacer{flex:1}
.tpd .pbar{margin-top:6px}
.tpd-ok{display:flex; gap:9px; align-items:flex-start; padding:10px 12px; border-radius:9px;
  background:var(--go-wash); border:1px solid var(--go); color:var(--go)}
.tpd-ok b{display:block; color:var(--go)}
.tpd-ok span{display:block; color:var(--ink2); font-size:12px; line-height:1.55; margin-top:2px}
.tp-share{display:flex; flex-wrap:wrap; gap:5px; align-items:center; margin-top:6px}
.tp-share input{flex:1; min-width:160px; font-family:var(--code) !important}
.tp-adm h4, .tp-help h4{font-size:12.5px; margin:10px 0 4px; display:flex; gap:5px; align-items:center}
.tp-adm .r2, .tp-help .r2{display:flex; gap:8px; padding:5px 0; border-bottom:1px solid var(--line);
  font-size:12.5px; align-items:flex-start}
.tp-adm .r2:last-child, .tp-help .r2:last-child{border-bottom:none}
.r2 .n{flex:1; min-width:0}
.r2 .n small{display:block; color:var(--ink3); font-size:11px; line-height:1.4}
.r2 .d{flex:none; font-size:11.5px; color:var(--ink2); text-align:right}
.tp-tel{font-weight:700; white-space:nowrap}
.tp-hot{display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:5px; margin:6px 0 8px}
.tp-hot a{display:flex; gap:6px; align-items:center; border:1px solid var(--line2); border-radius:8px;
  padding:5px 8px; text-decoration:none; color:var(--ink); background:var(--surface)}
.tp-hot a b{font-size:15px; color:var(--stop); display:block; line-height:1.25}
.tp-hot a small{color:var(--ink3); font-size:10.5px; line-height:1.3; display:block}
/* สายด่วนรอง (ยี่ห้อรถ · ประกันภัย) — เล็กกว่าเบอร์ฉุกเฉินหลัก ตัวเลขไม่แดง (ไม่ใช่หน่วยฉุกเฉินของรัฐ) */
.tp-hot.sub a{padding:4px 7px}
.tp-hot.sub a b{font-size:13px; color:var(--ink)}
.tp-hot.sub a small{font-size:10px}
.tp-more{margin:2px 0 6px}
.tp-more > summary{cursor:pointer; font-size:12px; font-weight:600; color:var(--ink2); padding:4px 0}
.tp-more > summary .ico{vertical-align:-2px; margin-right:3px}
/* ── กดแถว → โชว์บนแผนที่ (Sea 29 ก.ย. 2569: "ทำให้กดแล้ว โชว์ในแผนที่ให้เห็น") ──
   แถวที่มีพิกัดกดได้ทั้งแถว (ไอคอนเป้าท้ายแถวบอกว่ากดได้) · แถวที่เลือก = พื้นฟ้าอ่อน + แถบซ้าย
   หมุดที่เลือก = วงกะพริบรอบหมุด (.pk) — แผงเกิดเหตุสีแดง · แผนเดินทางสีหลัก · ปิดการเคลื่อนไหว = วงนิ่ง */
.tp-bs{cursor:pointer}
.tp-bs:hover{background:var(--sunk)}
.tp-adm .r2.go, .tp-help .r2.go{cursor:pointer; margin:0 -6px; padding-left:6px; padding-right:6px; border-radius:6px}
.tp-adm .r2.go:hover, .tp-help .r2.go:hover{background:var(--sunk)}
.r2 .go-i{flex:none; align-self:center; color:var(--line2); display:flex}
.r2 .go-i .ico{width:15px; height:15px}
.r2.go:hover .go-i{color:var(--primary-solid)}
.r2.sel, .tp-ch.sel, .tp-rh.sel, .tp-fyi li.sel{background:var(--primary-wash); box-shadow:inset 3px 0 0 var(--primary-solid)}
.r2.sel .go-i{color:var(--primary-solid)}
.tp-tap{display:flex; gap:5px; align-items:center}
.leaflet-marker-icon.pk::after{content:''; position:absolute; left:50%; top:50%; width:46px; height:46px; margin:-23px 0 0 -23px;
  box-sizing:border-box; border-radius:50%; border:3px solid var(--stop); pointer-events:none; animation:pkpulse 1.3s ease-out infinite}
.leaflet-marker-icon.pk.pk-plan::after{border-color:var(--primary-solid)}
@keyframes pkpulse{0%{transform:scale(.5); opacity:1} 100%{transform:scale(1.25); opacity:0}}
@media (prefers-reduced-motion: reduce){ .leaflet-marker-icon.pk::after{animation:none; transform:none; opacity:.9} }
/* ปุ่ม "กลับไปที่รายการ" มุมล่างซ้ายของแผนที่ — ขึ้นเฉพาะตอนที่หน้าเลื่อนขึ้นมาหาแผนที่ (จอแคบ) */
.mback{border:0; border-radius:999px; background:var(--ink); color:var(--surface); font:600 12.5px/1 var(--body);
  padding:8px 13px; box-shadow:0 2px 8px rgba(0,0,0,.35); cursor:pointer; display:inline-flex; gap:5px; align-items:center}
.mback[hidden]{display:none}
.mback .ico{width:14px; height:14px}
.r2 .n > .tbrand{margin-right:3px}
.tp-inner{border-left:3px solid var(--ink2); padding:2px 0 2px 8px; font-size:11px; color:var(--ink3); margin:4px 0 6px}
.mkr{display:flex; align-items:center; justify-content:center; font-family:var(--mono);
  font-weight:700; font-size:11px; border:1.5px solid var(--surface); box-shadow:0 1px 2px rgba(0,0,0,.35)}
.mkr.big{font-size:13px; border-width:3px; box-shadow:0 1px 4px rgba(0,0,0,.45)}
.mkr .ico{width:62%; height:62%; stroke-width:2.4}
/* ── ไอคอนประจำประเภทจุด (Sea 28 ก.ย. 2569: "จุดข้อมูลประกอบ ควรมีไอคอนด้วย")
   หมุดบนแผนที่ · แถวข้อมูลประกอบ · หัวข้อแผงเกิดเหตุ · ชิปตัวกรอง · ลิงก์แชร์/PDF ใช้ชุดเดียวกัน
   ไอคอนของแต่ละประเภทอยู่ที่ app/caticons.py (สำเนาใน trip.js) · สีและรูปทรงอยู่ที่นี่ที่เดียว
   วงกลม = จุดตามทาง/บริการ · สี่เหลี่ยมมน = หน่วยงาน/ที่พัก ── */
.catb{display:inline-flex; align-items:center; justify-content:center; flex:none; box-sizing:border-box;
  width:18px; height:18px; border-radius:50%; background:var(--sunk); color:var(--ink2); vertical-align:-4px}
.catb .ico{width:64%; height:64%; stroke-width:2.4}
.catb[data-k=Hazard]{background:var(--stop-wash); color:var(--stop)}
.catb[data-k=flood]{background:var(--info); color:var(--surface)}
.catb[data-k=roadx]{background:var(--stop); color:var(--surface); border-radius:4px}
.catb[data-k=roadw]{background:var(--watch); color:var(--surface); border-radius:4px}
.catb[data-k=rflood]{background:var(--info-wash); color:var(--info); border:1.5px solid var(--info)}
/* รายงานจากผู้ใช้/iTIC บน Longdo (ยังไม่ยืนยัน) = กรอบอำพันแบบโปร่ง มุมเหลี่ยม — ไม่ทึบเหมือนของหน่วยงาน */
.catb[data-k=lgev]{background:var(--surface); color:var(--watch); border-radius:4px; border:1.5px solid var(--watch)}
.catb[data-k=Hospital]{background:var(--go-wash); color:var(--go); border-radius:4px}
.catb[data-k=police]{background:var(--info-wash); color:var(--info); border-radius:4px}
.catb[data-k=Service]{background:var(--watch-wash); color:var(--watch)}
.catb[data-k=shelter]{background:var(--go-wash); color:var(--go)}
.catb[data-k=RestStopOpt]{background:var(--surface); color:var(--primary-solid); border-radius:4px; border:1.5px solid var(--primary-solid)}
.catb[data-k=rest], .catb[data-k=MaxCamp]{background:var(--primary-solid); color:var(--on-primary); border-radius:4px}
/* จุดพักทั่วไป (ไม่ใช่ PT Max Camp) = สี่เหลี่ยมมนแบบโปร่ง · ปั๊มน้ำมัน/พักที่ปั๊ม (จุดพักสำรอง) = กรอบเข้ม ไอคอนหัวจ่าย */
.catb[data-k=RestStop]{background:var(--surface); color:var(--primary-solid); border-radius:4px; border:1.5px solid var(--primary-solid)}
.catb[data-k=GasStation], .catb[data-k=gas]{background:var(--surface); color:var(--ink); border-radius:4px; border:1.5px solid var(--ink)}
.catb[data-k=restoff]{background:var(--watch); color:var(--on-primary); border-radius:4px}
.catb[data-k=night]{background:var(--ink2); color:var(--surface); border-radius:4px}
.catb[data-k=LoadPoint]{background:var(--info); color:var(--surface); border-radius:4px}
.catb[data-k=localgov]{background:var(--surface); color:var(--ink2); border-radius:4px; border:1.5px solid var(--ink3)}
.catb[data-k=ddpm]{background:var(--surface); color:var(--stop); border-radius:4px; border:1.5px solid var(--stop)}
.catb[data-k=truckfix]{background:var(--watch); color:var(--surface)}
.catb[data-k=tow]{background:var(--stop); color:var(--surface)}
.catb[data-k=tyre]{background:var(--info); color:var(--surface)}
.catb[data-k=carfix]{background:var(--surface); color:var(--ink2); border:1.5px solid var(--ink3)}
.catb[data-k=base]{background:var(--surface); color:var(--ink2); border-radius:4px; border:1.5px solid var(--ink2)}
.catb[data-k=empty]{background:var(--surface); color:var(--go); border:1.5px solid var(--go)}
/* บนแผนที่: ขอบขาวและเงาจาก .mkr ให้เห็นบนภาพแผนที่ทุกสี (แบบโปร่งใช้ขอบสีของตัวเองแทนขอบขาว) */
.mkr.catb{display:flex; vertical-align:baseline}
/* ── ศูนย์บริการตามยี่ห้อรถบรรทุก (truckhelp.py · Sea 28 ก.ย. 2569: "ถ้า location ศูนย์ ใส่เป็น logo ไปเลย")
   อัปโหลดโลโก้จริงที่หน้าตั้งค่าแล้ว = .tbrand.img (รูปบนพื้นขาว) · ยังไม่อัปโหลด = ป้ายชื่อยี่ห้อสีประจำยี่ห้อ
   หมุดบนแผนที่ (.tbm) กว้างตามชื่อ/รูป — วางกึ่งกลางที่จุดด้วย transform ไม่ต้องรู้ความกว้างล่วงหน้า ── */
.tbrand{display:inline-flex; align-items:center; justify-content:center; flex:none; box-sizing:border-box;
  height:18px; padding:0 .5em; border-radius:4px; font-family:var(--body); font-size:10px; font-weight:700;
  letter-spacing:.05em; line-height:1; white-space:nowrap; color:var(--on-nav); background:var(--ink2);
  vertical-align:-4px}
.tbrand[data-b=hino]{background:var(--tb-hino)}
.tbrand[data-b=isuzu]{background:var(--surface); color:var(--tb-isuzu); border:1.5px solid var(--tb-isuzu)}
.tbrand[data-b=volvo]{background:var(--tb-volvo)}
.tbrand[data-b=scania]{background:var(--tb-scania)}
.tbrand[data-b=ud]{background:var(--tb-ud)}
.tbrand.img{background:var(--surface); border:1px solid var(--line); padding:2px 4px}
.tbrand.img img{height:100%; width:auto; max-width:120px; display:block; object-fit:contain}
/* ── ระดับน้ำบนถนน/อุโมงค์ กทม. (bkkroad.py · 2 ต.ค. 2569) — หมุดบอกความลึก (ซม.) บนแผนที่ทะเบียนสถานที่
   ท่วม (> 10 ซม.) แดง · น้ำขังเล็กน้อย (5–10) เหลือง · แห้ง จุดเขียวเล็ก · ใช้งานไม่ได้/ค่าเก่า จุดเทา · อุโมงค์ = มุมเหลี่ยม ── */
.bkm{position:absolute; left:0; top:0; transform:translate(-50%,-50%); display:flex; align-items:center;
  justify-content:center; box-sizing:border-box; min-width:24px; height:18px; padding:0 4px; border-radius:9px;
  font-family:var(--mono); font-size:10px; font-weight:700; line-height:1; white-space:nowrap; cursor:pointer;
  color:var(--surface); background:var(--info); border:1.5px solid var(--surface); box-shadow:0 1px 2px rgba(0,0,0,.35)}
.bkm[data-l=flood]{background:var(--stop)}
.bkm[data-l=slight]{background:var(--watch)}
.bkm[data-l=dry]{min-width:0; width:11px; height:11px; padding:0; background:var(--go); opacity:.85}
.bkm[data-l=off], .bkm.old{min-width:0; width:11px; height:11px; padding:0; background:var(--ink3); opacity:.6}
.bkm.tun{border-radius:4px}
#bkbar .tg.fl-busy .sw, #dxbar .tg.fl-busy .sw{animation:tpspin 1s linear infinite; border:2px solid currentColor;
  border-right-color:transparent; background:transparent}
#bkbar .tg.fl-busy .sw .ico, #dxbar .tg.fl-busy .sw .ico{visibility:hidden}
.tbm{position:absolute; left:0; top:0; transform:translate(-50%,-50%); border-radius:5px;
  box-shadow:0 0 0 2px var(--surface), 0 1px 4px rgba(0,0,0,.45); cursor:pointer}
.tbm .tbrand{vertical-align:baseline; display:flex}
/* ── PT Max Camp ที่จุดพักบังคับ (ptmc.py · Sea 29 ก.ย. 2569: "กรณีถ้าพักบังคับ PT ให้ขึ้น logo PT Max camp ด้วย")
   อัปโหลดโลโก้ทางการที่หน้าตั้งค่าแล้ว = .tbrand.img · ยังไม่อัปโหลด = ป้ายชื่อสีของระบบ (สีเดียวกับหมุดจุดพัก
   ไม่ใช้สีประจำแบรนด์ — ระบบไม่เลียนแบบโลโก้ของใคร) · หมุด: ไอคอนเดิมตรงจุดจริง ป้ายติดด้านขวา */
.tbrand[data-b=ptmc]{background:var(--surface); color:var(--primary-deep); border:1.5px solid var(--primary-solid)}
.tbrand.ptmc{vertical-align:-3px; margin-left:2px}
/* ── ยี่ห้อปั๊มน้ำมัน (fuelbrand.py · Sea 4 ต.ค. 2569 "เพิ่มช่องยี่ห้อปั๊ม") — มีโลโก้ = .tbrand.img.flogo (รูปบนพื้นขาว)
   ยังไม่อัปโหลด = ป้ายชื่อยี่ห้อสีของระบบ (ขาว ขอบเข้ม แบบเดียวกับไอคอนปั๊ม) — ไม่ใช้สีประจำแบรนด์ ระบบไม่เลียนแบบโลโก้ของใคร */
.tbrand[data-b=fuel]{background:var(--surface); color:var(--ink); border:1.5px solid var(--ink); letter-spacing:.02em}
.tbrand.flogo{vertical-align:-3px; margin-left:2px}
.rmk{position:relative; width:22px; height:22px}
.rmk .rch{position:absolute; left:25px; top:50%; transform:translateY(-50%); display:flex; border-radius:4px;
  box-shadow:0 0 0 2px var(--surface), 0 1px 3px rgba(0,0,0,.4); cursor:pointer}
.rmk .rch .tbrand{display:flex; margin:0; vertical-align:baseline}

/* ══ แผงด้านข้าง (static/panel.js · Sea 28 ก.ย. 2569) ══════════════════════════
   ลิงก์ข้อมูลรายตัวเปิดเป็นแผงขวา · แผงใหม่ต่อทางขวา แผงเดิมเลื่อนไปซ้าย ไม่ทับกัน
   จอกว้างเห็นเต็ม 2 แผง แผงเก่ากว่าย่อเป็นแถบแคบ · มือถือทีละแผงเต็มจอ
   ชื่อคลาสขึ้นต้น pnl- ทั้งหมด (หน้าแนบหลักฐานมีคลาส .sp ของตัวเองอยู่แล้ว) */
html.in-pnl .top, html.in-pnl .warnbar{display:none}
html.in-pnl .wrap{padding:14px 16px 40px; max-width:none}
.pnl-dim{position:fixed; inset:0; z-index:2990; background:color-mix(in srgb, var(--ink) 16%, transparent);
  animation:pnlfade .14s ease-out}
.pnl-stack{--pnl-w:560px; --pnl-dw:760px; position:fixed; top:0; right:0; bottom:0; z-index:3000; display:flex;
  align-items:stretch; pointer-events:none}
.pnl-pane{pointer-events:auto; width:var(--pnl-w); display:flex; flex-direction:column; min-width:0;
  background:var(--surface); border-left:1px solid var(--line2);
  box-shadow:-12px 0 28px -16px color-mix(in srgb, var(--ink) 55%, transparent);
  animation:pnlin .18s ease-out}
.pnl-pane[hidden]{display:none}
.pnl-hd{flex:none; display:flex; gap:6px; align-items:center; padding:8px 10px 8px 14px;
  border-bottom:1px solid var(--line); background:var(--paper)}
.pnl-t{flex:1; min-width:0; font-weight:700; font-size:var(--t-h6); color:var(--ink);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.pnl-hd .icb{flex:none}
.pnl-hd .icb[hidden]{display:none}
.pnl-open span{margin-left:2px}
.pnl-body{flex:1; min-height:0; position:relative; background:var(--surface)}
.pnl-body iframe{position:absolute; inset:0; width:100%; height:100%; border:0; background:var(--surface)}
.pnl-load{position:absolute; top:0; left:0; right:0; height:3px; z-index:1; overflow:hidden;
  background:var(--primary-wash)}
.pnl-load::after{content:""; position:absolute; top:0; bottom:0; width:35%; background:var(--primary-solid);
  animation:pnlbar 1s ease-in-out infinite}
.pnl-ready .pnl-load{display:none}
/* แผงแบบเนื้อหา (กล่องคำอธิบายข้อบนกระดานงานลูกค้า) */
.pnl-html{overflow-y:auto; padding:16px 18px 24px}
.pnl-html h2{margin:0 0 4px; font-size:var(--t-h4); padding-left:0}
.pnl-html h2::before{content:none}
.pnl-html p{margin:0; line-height:1.68}
.pnl-html ul{margin:0; padding-left:19px}
.pnl-html li{margin-bottom:5px; line-height:1.6}
.pnl-html .rq-head{padding-right:0}
.pnl-html .rq-foot{position:sticky; bottom:-24px; background:var(--surface); padding:12px 0 6px;
  border-top:1px solid var(--line); display:flex; gap:8px; flex-wrap:wrap}
/* แผงเก่า (มีแผงใหม่ต่อทางขวามากกว่าที่จอแสดงได้) → แถบแคบตั้ง กดเพื่อกลับไปแผงนั้น */
.pnl-pane.pnl-doc{width:var(--pnl-dw, 760px)}
.pnl-pane.pnl-min{width:46px; cursor:pointer; animation:none}
.pnl-pane.pnl-min .pnl-body, .pnl-pane.pnl-min .pnl-hd > :not(.pnl-t){display:none}
.pnl-pane.pnl-min .pnl-hd{flex:1; writing-mode:vertical-rl; padding:14px 0; justify-content:flex-start;
  border-bottom:0; background:var(--sunk)}
.pnl-pane.pnl-min:hover .pnl-hd{background:var(--primary-wash)}
.pnl-pane.pnl-min .pnl-t{font-size:var(--t-helper); color:var(--ink2); max-height:calc(100vh - 40px)}
@keyframes pnlin{from{transform:translateX(28px); opacity:.35}}
@keyframes pnlfade{from{opacity:0}}
@keyframes pnlbar{0%{left:-35%} 100%{left:100%}}
@media (max-width:759px){
  .pnl-stack{left:0}
  .pnl-pane{width:100vw; border-left:0; box-shadow:none}
  .pnl-open span{display:none}
}
@media print{.pnl-dim, .pnl-stack{display:none !important}}
/* ── ช่องเลือกแบบค้นหาได้ + เพิ่มใหม่ (combo.js · ข้อมูลหลัก master.py · Sea 30 ก.ย. 2569) ── */
.cb{position:relative; display:block; width:100%}
.cb > input.cb-in{width:100%; padding-right:30px}
.searchbar > .cb, .row > .cb{flex:1 1 200px; width:auto; min-width:180px}   /* ช่องค้นหาในแถวปุ่ม (ไม่ดันปุ่มลงบรรทัดใหม่) */
.cb-tog{position:absolute; right:3px; top:50%; transform:translateY(-50%); border:0; background:none; padding:4px;
  line-height:0; color:var(--ink3); cursor:pointer; border-radius:6px}
.cb-tog:hover{background:var(--sunk); color:var(--ink)}
.cb-tog .ico{width:16px; height:16px}
.cb.off .cb-tog{display:none}
.cb-list{position:absolute; left:0; right:0; top:calc(100% + 3px); z-index:950; margin:0; padding:0; list-style:none;
  border:1px solid var(--line2); border-radius:8px; background:var(--surface); box-shadow:var(--shadow);
  max-height:290px; overflow:auto; min-width:220px; text-align:left}
.cb-list[hidden]{display:none}
.cb-it{padding:6px 10px; cursor:pointer; border-top:1px solid var(--line); font-size:13px; line-height:1.35}
.cb-it:first-child{border-top:0}
.cb-it .v{display:flex; align-items:center; gap:5px}
.cb-it small{display:block; color:var(--ink3); font-size:11px}
.cb-it mark{background:transparent; color:var(--primary-deep); padding:0; font-weight:inherit; text-decoration:underline}
.cb-it.act, .cb-it:hover{background:var(--primary-wash)}
.cb-add .v{color:var(--primary-deep); font-weight:700}
.cb-add .ico{width:14px; height:14px}
.cb-note{padding:7px 10px; font-size:12px; color:var(--ink3); border-top:1px solid var(--line)}
.cb-note:first-child{border-top:0}
.cb-note.bad{color:var(--stop); background:var(--stop-wash)}
.cb-note a{font-weight:600}
/* หน้าข้อมูลหลัก (master.html) */
.mst{display:grid; grid-template-columns:250px minmax(0,1fr); gap:14px; align-items:start}
.mst-k{display:flex; flex-direction:column; gap:1px; border:1px solid var(--line); border-radius:10px;
  background:var(--surface); padding:6px; position:sticky; top:70px}
.mst-g{font-size:11px; font-weight:700; color:var(--ink3); padding:8px 8px 3px}
.mst-k a{display:flex; justify-content:space-between; align-items:baseline; gap:6px; padding:5px 8px; border-radius:6px;
  color:var(--ink); text-decoration:none; font-size:13px}
.mst-k a:hover{background:var(--sunk)}
.mst-k a.on{background:var(--primary-wash); color:var(--primary-deep); font-weight:700}
.mst-k small{color:var(--ink3); font-family:var(--mono); font-size:11px; white-space:nowrap}
.mst-add{align-items:flex-end}
.mst-add label{display:flex; flex-direction:column; gap:3px; font-size:12px; color:var(--ink2)}
.mst-ren{gap:4px; flex-wrap:nowrap}
.mst-ren input{min-width:0}
.mst-t tr.mute td{color:var(--ink3)}
@media(max-width:800px){ .mst{grid-template-columns:1fr} .mst-k{position:static} }

/* ── ป้ายประเภทเหตุการณ์แบบป้ายจราจร (_signs.html · Sea 2 ต.ค. 2569 "เลียนแบบ icon ของ longdo") ──
   สีอยู่ในตัวป้าย ไม่ตามสีตัวอักษร · หมุดบนแผนที่มีเงาให้เห็นบนแผนที่สีอ่อน/เข้ม */
.sgn{display:inline-block; vertical-align:-4px; flex:none; overflow:visible}
.sgm{width:100%; height:100%; display:flex; align-items:center; justify-content:center;
  filter:drop-shadow(0 1px 1.5px rgba(0,0,0,.45))}
.sgm .sgn{width:100%; height:100%}
.pl-bar .tg .sw:has(.sgn){background:none; border:0}
.pl-bar .tg .sw .sgn{width:17px; height:17px}
.pl-bar .tg.on .sw:has(.sgn){background:none}
/* รูปที่ผู้รายงานแนบ (Longdo) — ภาพย่อ กดแล้วเปิดเต็ม · เปิดภาพไม่ได้ = ลิงก์ "เปิดรูป" */
.evimgs{display:flex; flex-wrap:wrap; gap:5px; margin:6px 0 3px}
.evimgs a{display:block; border-radius:6px; overflow:hidden; border:1px solid var(--line); background:var(--sunk)}
.evimgs img{display:block; width:128px; height:96px; object-fit:cover}
.evimgs a span{display:none; padding:4px 8px; font-size:12px}
.evimgs a.noimg span{display:block}
/* ป๊อปอัปกล้องบนแผนที่: จอเล่นวิดีโอสด (CamView.mount) ขนาดคงที่ 16:9 — ป๊อปอัปไม่ยืด/หดตอนวิดีโอขึ้น */
.campop-m{position:relative; width:260px; max-width:100%; aspect-ratio:16/9; margin:6px 0; border-radius:6px; overflow:hidden;
  background:#0b0d10; display:flex; align-items:center; justify-content:center}
.campop-m .camv-img, .campop-m .camv-vid{width:100%; height:100%; max-height:none; object-fit:contain}
.campop-m .camv-msg{padding:6px 10px; font-size:12px; line-height:1.45}
.campop-m .camv-msg .btn{margin-top:4px}
.campop-m .camv-wait{position:absolute; inset:0; display:flex; align-items:center; justify-content:center; pointer-events:none}
.campop-m .camv-at{left:6px; bottom:6px; font-size:10.5px; padding:1px 6px}
.campop-m .camv-at.top{top:6px; bottom:auto}
/* กล้องที่ต้นทางพักใช้งาน (longdocam.py ธง off) — หมุดและแถวในรายการจางลง */
.sgm.off{opacity:.45; filter:grayscale(1)}
.evr.cam.off{opacity:.62}
/* รูปตัวอย่างเล็กในรายการกล้อง (Sea 5 ต.ค. 2569) — โหลดเฉพาะแถวที่เห็น · ยังไม่มา/เปิดไม่ได้ = ไอคอนกล้องเดิม */
.evr.cam.th{grid-template-columns:76px minmax(0,1fr) auto}
.evth{width:76px; height:46px; border-radius:6px; background:var(--surface); border:1px solid var(--line);
  display:flex; align-items:center; justify-content:center; overflow:hidden; position:relative}
.evth img{position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:block}
.evth.bad::after{content:"ไม่มีภาพ"; position:absolute; left:0; right:0; bottom:1px; text-align:center;
  font-size:9.5px; color:var(--ink3)}
.evth.bad .sgn{margin-bottom:9px; opacity:.6}
.r2.th{align-items:center}
.tp-th{flex:none; width:64px; height:40px; border-radius:5px; background:var(--surface); border:1px solid var(--line);
  display:flex; align-items:center; justify-content:center; overflow:hidden; position:relative; cursor:zoom-in}
.tp-th img{position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:block}
.tp-th.bad{cursor:pointer}
.tp-th.bad .sgn{opacity:.55}
.tag.camoff{color:var(--ink3); font-weight:600}
/* หน้าต่างดูกล้อง (static/camview.js) */
.camv{position:fixed; inset:0; z-index:3000; background:rgba(10,14,20,.62); display:flex; align-items:center;
  justify-content:center; padding:16px}
.camv[hidden]{display:none}
.camv-card{width:min(760px, 100%); max-height:calc(100vh - 32px); overflow:auto; background:var(--surface);
  border-radius:12px; box-shadow:0 18px 50px rgba(0,0,0,.35); display:flex; flex-direction:column}
.camv-h{display:flex; align-items:center; gap:10px; padding:10px 12px; border-bottom:1px solid var(--line)}
.camv-h .sgn{width:26px; height:26px}
.camv-tt{flex:1; min-width:0; display:flex; flex-direction:column}
.camv-tt b{font-size:15px; line-height:1.35}
.camv-tt small{color:var(--ink3); font-size:12px}
.camv-x{border:0; background:none; font-size:24px; line-height:1; cursor:pointer; color:var(--ink2); padding:2px 6px}
.camv-m{position:relative; background:#0b0d10; min-height:240px; display:flex; align-items:center; justify-content:center}
.camv-img, .camv-vid{display:block; width:100%; max-height:62vh; object-fit:contain; background:#0b0d10}
.camv-msg{color:#e8eaed; padding:28px 18px; text-align:center; font-size:13.5px; line-height:1.6}
.camv-m .camv-wait{position:absolute; inset:0; display:flex; align-items:center; justify-content:center; pointer-events:none}
.camv-at{position:absolute; left:8px; bottom:8px; background:rgba(0,0,0,.6); color:#e8eaed; font-size:11.5px; padding:2px 8px; border-radius:6px; pointer-events:none}
.camv-at[hidden]{display:none}
.camv-at.top{top:8px; bottom:auto; background:rgba(160,30,30,.82)}
.camv-msg .btn.ghost{color:#e8eaed; border-color:rgba(255,255,255,.45); background:transparent}
.camv-b{display:flex; flex-wrap:wrap; gap:6px; padding:10px 12px 4px}
.camv-b .btn:disabled{opacity:.42; cursor:not-allowed}
.camv-f{padding:4px 12px 12px; font-size:11.5px; color:var(--ink3); line-height:1.5}
/* ── แผง "เหตุการณ์ล่าสุด" ข้างรายการสถานที่ (แบบ Longdo) ──
   จอกว้าง: แผนที่ | เหตุการณ์ | รายการ · 1001–1279: แผนที่เต็มแถว แล้วเหตุการณ์ | รายการ · มือถือ: เรียงลงมา */
.pl-ev{background:var(--surface); border:1px solid var(--line); border-radius:var(--r);
  height:calc(100vh - var(--pl-top, 205px) - 14px); min-height:460px; display:flex; flex-direction:column; overflow:hidden}
.pl-ev[hidden]{display:none}
.pl-main.ev{grid-template-columns:minmax(0,1.3fr) minmax(290px,340px) minmax(340px,1fr)}
@media(max-width:1279px){
  .pl-main.ev{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .pl-main.ev .pl-mapwrap{grid-column:1 / -1}
  .pl-main.ev #map{height:min(440px, 52vh); min-height:320px}
  .pl-main.ev .pl-ev, .pl-main.ev .pl-side{height:calc(100vh - 120px); min-height:420px}
}
@media(max-width:1000px){
  .pl-main.ev{grid-template-columns:minmax(0,1fr)}
  .pl-main.ev #map{height:380px; min-height:0}
  .pl-main.ev .pl-ev{height:420px}
  .pl-main.ev .pl-side{height:auto; min-height:0}
}
.ev-head .ev-n{color:var(--ink3); font-size:11.5px; margin-left:2px}
.ev-tabs{flex:none; display:flex; flex-wrap:wrap; gap:4px; padding:7px 8px; border-bottom:1px solid var(--line);
  background:var(--sunk)}
.evt{display:inline-flex; align-items:center; gap:4px; padding:2px 8px 2px 4px; border:1px solid var(--line2);
  border-radius:999px; background:var(--surface); font:500 11.5px/1.6 var(--body); color:var(--ink2); cursor:pointer}
.evt b{font-weight:600; color:var(--ink3); font-variant-numeric:tabular-nums}
.evt:hover{border-color:var(--ink3)}
.evt.on{border-color:var(--ink2); background:var(--ink2); color:var(--surface)}
.evt.on b{color:var(--surface)}
.evt.cam.on{border-color:var(--cam); background:var(--cam)}
.evr{display:grid; grid-template-columns:22px minmax(0,1fr) auto; gap:8px; align-items:center; padding:7px 10px;
  margin:6px 8px 0; border-radius:8px; background:var(--sunk); cursor:pointer; border:1px solid transparent}
.evr:hover{border-color:var(--line2)}
.evr .sgn{width:20px; height:20px}
.evr.t-stop{background:var(--stop-wash)}
.evr.t-fire{background:#fdebd9}
.evr.t-info{background:var(--info-wash)}
.evb{min-width:0; display:flex; flex-direction:column}
.evb b{font-size:12.5px; font-weight:500; line-height:1.4}
.evb small{font-size:11px; color:var(--ink3); line-height:1.35; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.evtm{display:inline-flex; align-items:center; gap:4px; font-size:11.5px; color:var(--ink2); white-space:nowrap;
  font-variant-numeric:tabular-nums}
.evtm .ico{width:13px; height:13px}
.ev-empty{padding:22px 14px; text-align:center; color:var(--ink3); font-size:12.5px; line-height:1.6}
.ev-foot{font-size:10.5px; line-height:1.45}
.pp-body#evlist{padding-bottom:8px}
.sgb{display:inline-flex; align-items:center; justify-content:center; flex:none}
/* ══ ที่มาของข้อมูล — ป้าย/โลโก้แหล่งข้อมูล (datasrc.py · static/datasrc.js · Sea 4 ต.ค. 2569
   "ข้อมูลเอามาจากไหน ในระบบเรา ให้มี credit พร้อม logo แหล่งข้อมูลด้วย")
   อัปโหลดโลโก้ทางการที่ ตั้งค่า › โลโก้แหล่งข้อมูล แล้ว = .dsrc.img (รูปบนพื้นขาว ตามสัดส่วนจริง)
   ยังไม่อัปโหลด = ป้ายชื่อแหล่งสีกลางของระบบ (ไม่ใช้สีประจำองค์กร — ระบบไม่เลียนแบบโลโก้ของใคร) ═══════════════ */
.dsrc{display:inline-flex; align-items:center; justify-content:center; flex:none; box-sizing:border-box;
  height:16px; padding:0 .55em; border-radius:4px; border:1px solid var(--line2); background:var(--surface);
  color:var(--ink2); font-family:var(--body); font-size:10px; font-weight:600; line-height:1; white-space:nowrap;
  vertical-align:-3px; -webkit-print-color-adjust:exact; print-color-adjust:exact}
.dsrc.img{padding:1px 3px; border-color:var(--line)}
.dsrc.img img{height:100%; width:auto; max-width:130px; display:block; object-fit:contain}
a.dsrc-a, .ms-a{text-decoration:none; display:inline-flex}
.dsrc-by{display:inline-flex; flex-wrap:wrap; align-items:center; gap:3px; vertical-align:middle}
.dsrc-by small{font-size:10.5px; color:var(--ink3); margin:0 1px}
/* เครดิตแบบย่อมุมขวาล่างของแผนที่ — Sea 4 ต.ค. 2569 "footer แผนที่ไม่ต้องใส่เครดิต เพราะกินเนื้อที่และบัง logo 360TRUCK"
   ซ่อนข้อความเครดิตยาวของ Leaflet · เหลือปุ่ม (i) + เครดิตแผนที่พื้นหลังบรรทัดเดียวตัวเล็ก · กดปุ่ม = การ์ดเครดิตครบทุกชั้น */
.leaflet-container.dsrc-on .leaflet-control-attribution{display:none !important}
.leaflet-control.mapsrc{position:relative; margin:0 6px 6px 0 !important; line-height:1.2; clear:none;
  -webkit-print-color-adjust:exact; print-color-adjust:exact}
.leaflet-control.mapsrc[hidden]{display:none !important}
.mapsrc .ms-row{display:flex; align-items:center; justify-content:flex-end; gap:5px}
.mapsrc .ms-i{flex:none; width:18px; height:18px; padding:0; border-radius:50%; border:1px solid var(--line2);
  background:rgba(255,255,255,.92); color:var(--ink2); font:italic 700 11px/16px Georgia,'Times New Roman',serif;
  cursor:pointer; box-shadow:0 1px 2px rgba(0,0,0,.18)}
.mapsrc .ms-i:hover, .mapsrc.open .ms-i{background:var(--ink); border-color:var(--ink); color:#fff}
.mapsrc .ms-base{font:500 10px/1.3 var(--body); color:var(--ink2); background:rgba(255,255,255,.75);
  padding:1px 5px; border-radius:3px; white-space:nowrap}
.mapsrc .ms-base:empty{display:none}
.mapsrc .ms-base a{color:inherit; text-decoration:none}
.mapsrc .ms-card{position:absolute; right:0; bottom:calc(100% + 6px); width:min(340px, 78vw); max-height:min(320px, 55vh);
  overflow:auto; padding:9px 11px; background:var(--surface); border:1px solid var(--line); border-radius:8px;
  box-shadow:0 6px 20px rgba(0,0,0,.18); font:400 11.5px/1.45 var(--body); color:var(--ink2); text-align:left}
.mapsrc .ms-card[hidden]{display:none}
.mapsrc .ms-h{display:block; margin-bottom:6px; font-size:12px; color:var(--ink)}
.mapsrc .ms-chips{display:flex; flex-wrap:wrap; gap:4px; margin-bottom:7px}
.mapsrc .ms-list{margin:0; padding-left:16px}
.mapsrc .ms-list li{margin:1px 0}
.mapsrc .ms-foot{display:block; margin-top:6px; font-size:10.5px; color:var(--ink3)}
.mapsrc .ms-foot a, .mapsrc .ms-list a{color:var(--ink2)}
.mapsrc .ms-pr{display:none}
@media print{ .mapsrc .ms-pr{display:inline} .mapsrc .ms-i, .mapsrc .ms-card{display:none !important} }
/* หน้าที่มาของข้อมูล (sources.html) */
.src-sum{display:flex; flex-wrap:wrap; gap:8px; align-items:center}
.src-sum a{text-decoration:none; display:inline-flex}
.srcc-h{display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin-bottom:8px}
.srcc-logo{display:inline-flex; gap:5px; align-items:center; min-width:60px}
.srcc-t{flex:1; min-width:200px; display:flex; flex-direction:column}
.srcc-t b{font-size:var(--t-h5); line-height:1.35}
.srcc-t small{color:var(--ink3); font-size:var(--t-helper)}
.srcc-d{display:grid; grid-template-columns:minmax(110px, 160px) minmax(0, 1fr); gap:6px 14px; margin:0; font-size:13.5px; line-height:1.55}
.srcc-d dt{color:var(--ink3); font-weight:600}
.srcc-d dd{margin:0; min-width:0; overflow-wrap:anywhere}
.srcc-d ul{margin:0; padding-left:18px}
@media(max-width:640px){ .srcc-d{grid-template-columns:minmax(0, 1fr)} .srcc-d dt{margin-top:6px} }
/* กล้องที่ POPNIX รวบรวมไว้ (popnixcam.py · 4 ต.ค. 2569) — ภาพนิ่งเก่าเกิน 60 นาที = หมุดจาง · กลุ่มกล้องหลายตัวในช่องเดียว
   = วงตัวเลข (กทม. มีกล้องเกือบ 1,500 ตัว — หมุดทุกตัวพร้อมกันทับกันจนกดไม่ได้) กดวงแล้วซูมเข้าไปที่กลุ่มนั้น */
.sgm.old{opacity:.55; filter:grayscale(.85)}
.evr.cam.old{opacity:.72}
.tag.camold{color:var(--watch); font-weight:600}
.camk{position:absolute; left:0; top:0; transform:translate(-50%,-50%); min-width:26px; height:26px; padding:0 6px;
  box-sizing:border-box; border-radius:13px; display:flex; align-items:center; justify-content:center; gap:3px;
  background:#C2185B; color:#fff; font:700 11px/1 var(--mono); border:2px solid #fff; box-shadow:0 1px 3px rgba(0,0,0,.4);
  cursor:pointer; white-space:nowrap}
.camk .sgn{width:13px; height:13px}
.campop-src{display:flex; flex-wrap:wrap; align-items:center; gap:4px; margin-top:2px}
.camv-f .dsrc-by{margin-right:4px}
/* ระดับน้ำคลอง/แม่น้ำ — หน้าแผนที่ทางการของ Longdo Water ฝังในหน้าต่าง (ระบบไม่ดึง/ไม่เก็บตัวเลขเอง) */
.lwv{position:fixed; inset:0; z-index:3000; background:rgba(10,14,20,.62); display:flex; align-items:center; justify-content:center; padding:16px}
.lwv[hidden]{display:none}
.lwv-card{width:min(980px, 100%); height:min(720px, calc(100vh - 32px)); background:var(--surface); border-radius:12px;
  box-shadow:0 18px 50px rgba(0,0,0,.35); display:flex; flex-direction:column; overflow:hidden}
.lwv-h{display:flex; align-items:center; gap:10px; padding:9px 12px; border-bottom:1px solid var(--line)}
.lwv-h b{flex:1; font-size:15px}
.lwv-f{width:100%; flex:1; border:0; background:var(--sunk)}
.lwv-n{padding:6px 12px 9px; font-size:11.5px; color:var(--ink3); line-height:1.5}
