:root{--p:#0ea5e9;--p-deep:#0369a1;--p-deeper:#025d8f;--pl:#e0f4ff;--g:#15803d;--gl:#e7f9f1;--a:#b45309;--al:#fff3e2;--r:#c0392b;--rl:#fdecec;--u:#64748b;--ul:#f1f5f9;--maint:#1d4ed8;--bg:#f3f8ff;--card:#fff;--bdr:#e3ecf5;--tx:#0f172a;--mu:#5b6b7c;--g-rgb:21,128,61;--r-rgb:192,57,43;--a-rgb:180,83,9;--sw:340px;--hh:56px;--nav-w:220px;--nav-w-c:64px;--r-sm:8px;--r-md:12px;--r-lg:16px;--r-pill:999px;--shadow-sm:0 1px 2px rgba(15,23,42,.05),0 6px 16px rgba(15,23,42,.05);--shadow-md:0 2px 4px rgba(15,23,42,.06),0 10px 26px rgba(15,23,42,.08);}
*{box-sizing:border-box;margin:0;padding:0;}
html,body{height:100%;overflow-x:hidden;font-family:'Anuphan',system-ui,sans-serif;background:var(--bg);color:var(--tx);font-size:15px;line-height:1.5;}
#app{display:flex;flex-direction:column;height:100dvh;overflow:hidden;}
#loginPage{position:fixed;inset:0;background:#0f172a;display:flex;align-items:center;justify-content:center;z-index:9999;}
.lbox{background:#fff;border-radius:var(--r-lg);padding:32px;width:340px;box-shadow:var(--shadow-md);}
.llogo{text-align:center;margin-bottom:20px;}
.llogo .ico{font-size:36px;background:var(--p);width:60px;height:60px;border-radius:var(--r-md);display:inline-flex;align-items:center;justify-content:center;margin-bottom:8px;}
.llogo h2{font-size:18px;font-weight:700;}.llogo p{font-size:12px;color:var(--mu);}
header{height:var(--hh);flex-shrink:0;background:linear-gradient(135deg,#024b74,#0369a1);color:#fff;display:flex;align-items:center;justify-content:space-between;padding:0 14px;z-index:1000;gap:8px;}
.nav-burger{display:none;background:none;border:none;color:#fff;font-size:19px;cursor:pointer;padding:4px 8px;flex-shrink:0;border-radius:var(--r-sm);}
.nav-burger:hover{background:rgba(255,255,255,.15);}
.logo{display:flex;align-items:center;gap:8px;white-space:nowrap;flex-shrink:0;}
.logo-icon{width:30px;height:30px;background:rgba(255,255,255,.18);border-radius:var(--r-md);display:flex;align-items:center;justify-content:center;font-size:16px;}
.logo h1{font-size:13px;font-weight:700;line-height:1.2;}.logo h1 small{font-size:10px;color:#e0f4ff;display:block;}
.uchip{display:flex;align-items:center;gap:6px;font-size:11px;color:#eaf6ff;flex-shrink:0;margin-left:auto;}
.rbadge{font-size:9px;font-weight:700;padding:2px 8px;border-radius:var(--r-pill);background:rgba(255,255,255,.2);color:#fff;}
/* Header controls. These used to carry their styling as inline attributes that _markLangButtons()
 * in i18n.js immediately overwrote with the login page's light-card palette — so the toggle
 * rendered as a solid white pill on the blue header. Styling lives here now and i18n.js only
 * toggles .on, which lets the header and the login card each get a palette that actually reads.
 * The logout button is outlined rather than translucent-filled: a white-alpha fill lightens the
 * header behind it and drags white label text down to ~4.1:1. */
.lang-switch{display:flex;border-radius:var(--r-sm);overflow:hidden;flex-shrink:0;border:1px solid var(--bdr);}
.lang-btn{font-size:10px;font-weight:700;padding:3px 8px;border:none;cursor:pointer;font-family:inherit;background:transparent;color:var(--tx);}
.lang-btn.on{background:var(--p-deep);color:#fff;}
header .lang-switch{border-color:rgba(255,255,255,.45);}
header .lang-btn{color:#fff;}
header .lang-btn.on{background:#fff;color:var(--p-deep);}
.hdr-btn{background:transparent;border:1px solid rgba(255,255,255,.5);border-radius:var(--r-sm);color:#fff;font-family:inherit;font-size:10px;font-weight:700;padding:4px 10px;cursor:pointer;}
.hdr-btn:hover{background:rgba(255,255,255,.16);}
/* ─── SHELL: sidebar nav + page content, sits below the slim topbar ─── */
.shell{flex:1;display:flex;overflow:hidden;position:relative;}
.nav-sidebar{width:var(--nav-w);flex-shrink:0;background:var(--card);border-right:1px solid var(--bdr);display:flex;flex-direction:column;transition:width .16s ease;overflow:hidden;}
.nav-sidebar.collapsed{width:var(--nav-w-c);}
.nav-scroll{flex:1;overflow-y:auto;overflow-x:hidden;padding:12px 10px;}
.nav-grp{font-size:10px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;color:var(--mu);margin:16px 10px 6px;white-space:nowrap;}
.nav-grp:first-child{margin-top:2px;}
.nav-sidebar.collapsed .nav-grp{opacity:0;height:0;margin:8px 0 0;overflow:hidden;}
.nav-item{display:flex;align-items:center;gap:10px;padding:9px 10px;border-radius:var(--r-sm);font-size:13px;font-weight:600;color:var(--tx);text-decoration:none;margin-bottom:2px;white-space:nowrap;overflow:hidden;}
.nav-item:hover{background:var(--bg);}
.nav-item.on{background:var(--pl);color:var(--p-deep);font-weight:700;}
.nav-ico{font-size:15px;flex-shrink:0;width:20px;text-align:center;}
.nav-tx{overflow:hidden;text-overflow:ellipsis;}
.nav-sidebar.collapsed .nav-tx{display:none;}
.nav-sidebar.collapsed .nav-item{justify-content:center;}
.nav-collapse-btn{display:flex;align-items:center;gap:8px;padding:12px 14px;border:none;border-top:1px solid var(--bdr);background:none;cursor:pointer;color:var(--mu);font-size:11px;font-weight:700;font-family:inherit;flex-shrink:0;}
.nav-collapse-btn:hover{color:var(--p);}
.nav-sidebar.collapsed .nav-collapse-btn{justify-content:center;}
.nav-sidebar.collapsed .nav-collapse-btn .nav-tx{display:none;}
.nav-sidebar.collapsed .nav-collapse-btn .nav-ico{transform:rotate(180deg);}
.nav-scrim{display:none;position:fixed;inset:0;background:rgba(15,23,42,.45);z-index:1400;}
.nav-scrim.show{display:block;}
.main-wrap{flex:1;display:flex;overflow:hidden;min-width:0;}
.sidebar{width:var(--sw);flex-shrink:0;background:var(--card);border-right:1px solid var(--bdr);overflow-y:auto;}
.sidebar-inner{padding:12px;}
.map-wrap{flex:1;position:relative;}#map{height:100%;width:100%;}
.tab-pg{flex:1;overflow-y:auto;padding:14px;display:none;}.tab-pg.on{display:block;}
.card{background:var(--card);border:1px solid var(--bdr);border-radius:var(--r-md);padding:12px;margin-bottom:10px;box-shadow:var(--shadow-sm);}
.sec{font-size:10px;font-weight:700;color:var(--mu);text-transform:uppercase;letter-spacing:.06em;margin:12px 0 7px;}
.badge{display:inline-block;font-size:10px;font-weight:700;padding:2px 8px;border-radius:var(--r-pill);margin-right:3px;}
.b-ok{background:var(--bg);color:var(--mu);}.b-due{background:var(--al);color:var(--a);}.b-done{background:var(--gl);color:var(--g);}.b-prog{background:var(--pl);color:var(--p-deep);}
.b-over{background:var(--rl);color:var(--r);}   /* เลยกำหนดรอบ PM — ใช้ในหน้าบันทึกงานของช่าง */
.dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:4px;flex-shrink:0;}
.dg{background:var(--g);}.dr{background:var(--r);}.da{background:var(--a);}.du{background:var(--u);}
.btn{background:var(--p-deep);color:#fff;border:none;border-radius:var(--r-sm);padding:8px 15px;font-size:12.5px;font-weight:700;cursor:pointer;font-family:inherit;transition:.12s;text-decoration:none;display:inline-block;box-shadow:0 3px 8px rgba(3,105,161,.26);}
.btn:hover{background:var(--p-deeper);}
.btn-s{background:var(--pl);border:1px solid transparent;border-radius:var(--r-sm);padding:6px 12px;font-size:11px;font-weight:700;cursor:pointer;color:var(--p-deep);font-family:inherit;text-decoration:none;display:inline-block;transition:.12s;}
.btn-s:hover{background:#cdeafd;}
.btn-s.win-active,.btn-s.win-active:hover{background:var(--p-deep);border-color:var(--p-deep);color:#fff;}
.btn-s:disabled{opacity:.4;cursor:not-allowed;}
.btn-s:disabled:hover{background:var(--pl);color:var(--p-deep);}
.btn-d{background:var(--rl);color:var(--r);border-color:transparent;}.btn-d:hover{background:#fbd9d9;}
.ibt{background:none;border:none;cursor:pointer;color:var(--mu);font-size:14px;padding:2px 5px;}
.ibt:hover{color:var(--r);}
input,select,textarea{width:100%;padding:8px 11px;border:1px solid var(--bdr);border-radius:var(--r-sm);font-size:13px;margin-bottom:7px;font-family:inherit;background:#fff;color:var(--tx);}
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--p);box-shadow:0 0 0 3px rgba(14,165,233,.14);}
label{font-size:11px;font-weight:700;color:var(--mu);display:block;margin-bottom:3px;text-transform:uppercase;letter-spacing:.05em;}
/* ─── FOCUS VISIBILITY ───
 * Nothing but text inputs used to show a focus ring, so keyboard/switch users had no way to tell
 * where they were. :focus-visible (not :focus) means pointer users never see a ring on click,
 * only keyboard traversal does. The two-tone ring (white inner + brand outer) stays legible on
 * both the light page background and the dark header / map overlays. */
/* NB: a plain selector list, not :where(...) — :where() carries zero specificity, so the
 * browser's own :focus-visible ring (white on a dark scheme) would win and the ring would vanish
 * against light cards. */
a:focus-visible,button:focus-visible,select:focus-visible,summary:focus-visible,
[tabindex]:focus-visible,.pill:focus-visible,.wtab:focus-visible,.nav-item:focus-visible,
.site-item:focus-visible,.sc-head:focus-visible,.pzone:focus-visible,.rsel-btn:focus-visible,
tr.st-row:focus-visible{
  outline:2px solid var(--p-deep);outline-offset:2px;border-radius:var(--r-sm);
}
/* White ring only where a control actually sits on a dark surface. Login's buttons are inside
 * the white .lbox card, so they keep the brand ring even though #loginPage behind them is dark. */
header a:focus-visible,header button:focus-visible,
#routeSelBar button:focus-visible,.map-wrap button:focus-visible{outline-color:#fff;}
input:focus-visible,select:focus-visible,textarea:focus-visible{outline:2px solid var(--p-deep);outline-offset:1px;}
/* Skip-link: first tab stop on every page, jumps past the nav into page content. */
.skip-link{position:absolute;left:-9999px;top:0;z-index:5000;background:var(--p-deep);color:#fff;padding:10px 16px;border-radius:0 0 var(--r-sm) 0;font-size:12px;font-weight:700;text-decoration:none;}
.skip-link:focus{left:0;}

/* ─── ROLE GATING ───
 * Privileged UI used to be hidden by JS *after* the /api/auth/me round-trip, so every page load
 * flashed the admin menu and edit buttons at viewers and ma_team before hiding them again — and
 * anything rendered into the DOM later (innerHTML) was never re-checked at all. Gating on a
 * #app[data-role] attribute instead means the markup starts hidden, reveals only once the role is
 * known, and covers dynamically-rendered nodes for free. requireAuth() sets the attribute. */
#app:not([data-role]) .admin-only,
#app:not([data-role]) .can-edit{display:none!important;}
#app[data-role]:not([data-role="admin"]) .admin-only{display:none!important;}
#app[data-role]:not([data-role="admin"]):not([data-role="technician"]) .can-edit{display:none!important;}
#app[data-role="ma_team"] .hide-ma-team{display:none!important;}

.row2{display:flex;gap:8px;}.row2>div{flex:1;}
.ov{position:fixed;inset:0;background:rgba(15,23,42,.5);display:flex;align-items:center;justify-content:center;z-index:3000;padding:14px;}
.modal{background:#fff;border-radius:var(--r-lg);padding:18px;width:100%;max-height:94dvh;overflow-y:auto;border:1px solid var(--bdr);box-shadow:var(--shadow-md);}
.modal-lg{max-width:700px;}.modal-md{max-width:560px;}.modal-sm{max-width:440px;}
.modal-title{font-size:15px;font-weight:700;margin-bottom:13px;}
.modal-foot{display:flex;justify-content:flex-end;gap:8px;margin-top:14px;border-top:1px solid var(--bdr);padding-top:12px;flex-wrap:wrap;}
/* ─── APP DIALOGS (uiAlert / uiConfirm / uiPrompt in core.js) ───
 * Replaces native alert()/confirm()/prompt(). Native dialogs sit outside the DOM, so the
 * MutationObserver translator in i18n.js could never reach them — every one of them stayed Thai
 * in English mode. These are ordinary .ov/.modal markup, so they translate, theme, and style
 * like the rest of the app, and a PIN can be a real type=password field instead of plain text. */
.dlg-msg{font-size:13px;line-height:1.6;white-space:pre-line;color:var(--tx);}
.dlg-sub{font-size:11.5px;line-height:1.55;color:var(--mu);margin-top:8px;}
.btn-danger{background:var(--r);color:#fff;box-shadow:0 3px 8px rgba(var(--r-rgb),.26);}
.btn-danger:hover{background:#a93226;}
.pills{display:flex;gap:5px;flex-wrap:wrap;margin-bottom:9px;}
.pill{border:1px solid var(--bdr);border-radius:var(--r-pill);padding:4px 12px;font-size:11px;cursor:pointer;background:#fff;font-weight:600;color:var(--mu);transition:.12s;}
.pill.on{background:var(--p-deep);color:#fff;border-color:var(--p-deep);}
.pill:hover:not(.on){border-color:var(--p);color:var(--p);}
.tbl-wrap{overflow-x:auto;}
table{width:100%;border-collapse:collapse;font-size:12px;}
th,td{padding:8px 10px;border-bottom:1px solid var(--bdr);text-align:left;vertical-align:middle;}
th{color:var(--mu);font-size:10px;text-transform:uppercase;background:var(--bg);font-weight:700;letter-spacing:.05em;}
tr:hover td{background:var(--bg);}
.stats{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:12px;}
.stat{background:var(--card);border:1px solid var(--bdr);border-radius:var(--r-md);padding:10px 14px;text-align:center;flex:1;min-width:80px;box-shadow:var(--shadow-sm);}
.stat b{font-size:20px;display:block;line-height:1;}.stat small{font-size:10px;color:var(--mu);display:block;margin-top:2px;}
.site-item{border:1px solid var(--bdr);border-radius:var(--r-md);padding:9px 11px;margin-bottom:7px;cursor:pointer;transition:.12s;}
.site-item:hover{border-color:var(--p);background:var(--bg);}.site-item.sel{border-color:var(--p);background:var(--pl);}
/* route cards */
.rc{background:var(--card);border:1px solid var(--bdr);border-radius:var(--r-md);overflow:hidden;margin-bottom:12px;box-shadow:var(--shadow-sm);}
.rbar{height:4px;background:var(--bdr);}.rfill{height:100%;transition:.3s;}
.rc-head{padding:12px 14px;display:flex;justify-content:space-between;align-items:flex-start;}
.rc-body{padding:0 14px 14px;}
.stop-row{display:flex;align-items:stretch;}
.stop-con{display:flex;flex-direction:column;align-items:center;width:22px;flex-shrink:0;}
.stop-line{width:2px;background:var(--bdr);flex:1;}
.stop-circ{width:18px;height:18px;border-radius:50%;border:2px solid var(--bdr);background:#fff;display:flex;align-items:center;justify-content:center;font-size:9px;font-weight:700;color:var(--mu);flex-shrink:0;}
.stop-circ.done{background:var(--g);border-color:var(--g);color:#fff;}
.stop-body{flex:1;padding:4px 0 10px 10px;}
.gml{display:inline-flex;align-items:center;gap:3px;color:var(--p-deep);font-size:10px;font-weight:700;text-decoration:none;background:var(--pl);padding:3px 8px;border-radius:var(--r-pill);}
.gml:hover{background:#cdeafd;}
/* work modal */
.wtabs{display:flex;border-bottom:2px solid var(--bdr);margin-bottom:12px;overflow-x:auto;}
.wtab{padding:7px 14px;font-size:12px;font-weight:700;cursor:pointer;color:var(--mu);border-bottom:2px solid transparent;margin-bottom:-2px;background:none;border-top:none;border-left:none;border-right:none;font-family:inherit;white-space:nowrap;}
.wtab.on{color:var(--p-deep);border-bottom-color:var(--p);}
.wpanel{display:none;}.wpanel.on{display:block;}
.chk-row{display:flex;align-items:center;gap:9px;padding:7px 9px;border:1px solid var(--bdr);border-radius:var(--r-sm);margin-bottom:5px;background:#fafcff;}
.chk-row input[type=checkbox]{width:15px;height:15px;cursor:pointer;accent-color:var(--p);flex-shrink:0;margin:0;}
.chk-row label{flex:1;cursor:pointer;margin:0;font-size:12px;font-weight:600;text-transform:none;letter-spacing:normal;}
.pzone{border:2px dashed var(--bdr);border-radius:var(--r-md);padding:18px;text-align:center;cursor:pointer;transition:.15s;background:#fafcff;}
.pzone:hover,.pzone.drag-over{border-color:var(--p);background:var(--pl);}
.pgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100px,100%),1fr));gap:8px;margin-top:10px;}
.pthumb{position:relative;aspect-ratio:1;border-radius:var(--r-sm);overflow:hidden;border:1px solid var(--bdr);}
.pthumb img{width:100%;height:100%;object-fit:cover;cursor:zoom-in;}
.pdel{position:absolute;top:2px;right:2px;background:rgba(15,23,42,.65);color:#fff;border:none;border-radius:50%;width:20px;height:20px;font-size:10px;cursor:pointer;display:flex;align-items:center;justify-content:center;}
.log-entry{border:1px solid var(--bdr);border-radius:var(--r-md);padding:12px;margin-bottom:10px;background:#fafcff;}
.log-photos{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px;}
.log-photo{width:64px;height:64px;border-radius:var(--r-sm);object-fit:cover;cursor:zoom-in;border:1px solid var(--bdr);}
.log-photo-wrap{display:inline-flex;flex-direction:column;align-items:center;gap:2px;}
.log-photo-cap{font-size:9px;color:var(--mu);text-align:center;max-width:66px;}
.mban{background:linear-gradient(135deg,#0369a1,#0ea5e9);color:#fff;border-radius:var(--r-md);padding:10px 12px;margin-bottom:10px;}
.mban-row{background:rgba(255,255,255,.14);border-radius:var(--r-sm);padding:7px 10px;margin-bottom:5px;font-size:11px;}
.mban-row b{display:block;font-size:12px;}
.rtaban{background:var(--r);color:#fff;border-radius:var(--r-md);padding:10px 12px;margin-bottom:10px;}
.rtaban-row{background:rgba(255,255,255,.15);border-radius:var(--r-sm);padding:7px 10px;margin-bottom:5px;font-size:11px;}
.rtaban-row b{display:block;font-size:12px;}
/* ═══ STATUS PAGE ═══ */
.st-summary{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:14px;}
.st-card{background:var(--card);border:1px solid var(--bdr);border-radius:var(--r-md);padding:12px 16px;text-align:center;flex:1;min-width:90px;box-shadow:var(--shadow-sm);}
.st-card b{font-size:24px;display:block;line-height:1.1;}.st-card small{font-size:10px;color:var(--mu);display:block;margin-top:2px;}
.sc{background:var(--card);border:1px solid var(--bdr);border-radius:var(--r-md);margin-bottom:8px;overflow:hidden;transition:.15s;box-shadow:var(--shadow-sm);}
.sc:hover{border-color:var(--p);}
.sc-head{padding:10px 14px;display:flex;justify-content:space-between;align-items:center;cursor:pointer;gap:8px;user-select:none;}
.sc-left{display:flex;align-items:center;gap:10px;flex:1;min-width:0;}
.sc-icon{width:32px;height:32px;border-radius:var(--r-md);display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;color:#fff;flex-shrink:0;}
.sc-body{border-top:1px solid var(--bdr);padding:10px 14px;display:none;}
.sc-body.open{display:block;}
/* timeline */
.tl-bars{display:flex;gap:1.5px;height:30px;align-items:flex-end;margin:6px 0;}
.tl-bar{flex:1;border-radius:2px;min-width:2px;cursor:pointer;transition:.1s;}
.tl-bar:hover{opacity:.75;transform:scaleY(1.1);transform-origin:bottom;}
.tl-bar.up{background:var(--g);}
.tl-bar.down{background:var(--r);}
.tl-bar.partial{background:var(--a);}
.tl-bar.unknown{background:var(--u);height:6px!important;}
.tl-label{display:flex;justify-content:space-between;font-size:9px;color:var(--mu);}
/* Compact status/MA layout */
.status-layout{display:grid;grid-template-columns:minmax(240px,320px) 1fr;gap:12px;align-items:start;margin-bottom:10px;}
/* Grid items default to min-width:auto, so the 680px-wide status table stretched .status-right
 * — and with it the whole grid — past the viewport, making the entire page scroll sideways on
 * a phone instead of just the table inside its own overflow-x:auto wrapper. min-width:0 lets
 * both columns shrink so that wrapper does its job. */
.status-left,.status-right{min-width:0;}
.status-left .card{padding:10px;}
/* In the narrow left rail the four summary cards used to flex-wrap 3-then-1, leaving one
 * stretched across its own row. A fixed 2x2 keeps them even now that the rail is short. */
.status-left .st-summary{display:grid;grid-template-columns:1fr 1fr;}
.status-left .st-card{min-width:0;}
.status-right #statusList{display:flex;flex-direction:column;gap:8px;}
.ma-demo-row{background:#fff;border:1px solid var(--bdr);border-radius:var(--r-sm);padding:8px;display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;font-size:13px;}
/* equipment row */
.eq-row{display:flex;align-items:center;justify-content:space-between;padding:7px 9px;border-radius:var(--r-sm);margin-bottom:4px;font-size:12px;background:#fafcff;border:1px solid var(--bdr);}
.eq-l{display:flex;align-items:center;gap:8px;}
.eq-dot{width:10px;height:10px;border-radius:50%;flex-shrink:0;animation:pulse 2s infinite;}
.eq-up{background:var(--g);box-shadow:0 0 0 0 rgba(var(--g-rgb),.4);}
.eq-dn{background:var(--r);animation:none;}
.eq-uk{background:var(--u);animation:none;}
@keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(var(--g-rgb),.4);}50%{box-shadow:0 0 0 5px rgba(var(--g-rgb),0);}}
.eq-name{font-weight:600;}.eq-ip{font-size:10px;color:var(--mu);font-family:'IBM Plex Mono',monospace;}
.eq-lat{font-size:11px;font-weight:600;}
/* status comparison table */
.status-toolbar{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:10px;}
.status-search{flex:1;min-width:160px;padding:8px 11px;border:1px solid var(--bdr);border-radius:var(--r-sm);font-size:13px;margin:0;}
.status-table-wrap{border:1px solid var(--bdr);border-radius:var(--r-md);overflow:hidden;overflow-x:auto;background:var(--card);box-shadow:var(--shadow-sm);}
table.status-table{width:100%;border-collapse:collapse;font-size:12.5px;min-width:680px;}
table.status-table th{text-align:left;font-size:10.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--mu);padding:9px 12px;border-bottom:1px solid var(--bdr);font-weight:700;cursor:pointer;user-select:none;white-space:nowrap;}
table.status-table th:hover{color:var(--tx);}
table.status-table th .arrow{opacity:.35;margin-left:3px;}
table.status-table td{padding:9px 12px;border-bottom:1px solid var(--bdr);vertical-align:middle;}
table.status-table tbody tr.st-row{cursor:pointer;}
table.status-table tbody tr.st-row:hover td{background:var(--bg);}
table.status-table tbody tr.st-row.open td{background:var(--bg);}
.st-name{font-weight:700;}
.st-bar-wrap{width:64px;height:5px;background:var(--bdr);flex-shrink:0;border-radius:99px;}
.st-bar{height:100%;border-radius:99px;}
.st-detail-row td{padding:0;border-bottom:1px solid var(--bdr);}
.st-detail{padding:12px 16px;background:var(--bg);}
/* utility grids */
.grid-auto-sm{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(140px,100%),1fr));gap:8px;}
.grid-auto-md{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:10px;}
/* Skeleton placeholders. Dashboard and Status previously rendered nothing at all until their
 * first fetch resolved, so a slow sweep looked like a broken page rather than a loading one. */
.skel{background:linear-gradient(90deg,var(--ul) 25%,#e8eef6 50%,var(--ul) 75%);background-size:400% 100%;animation:skelShimmer 1.4s ease-in-out infinite;border-radius:var(--r-sm);}
@keyframes skelShimmer{0%{background-position:100% 0;}100%{background-position:0 0;}}
@media (prefers-reduced-motion:reduce){.skel{animation:none;}}
/* dashboard */
.dash-summary{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(120px,100%),1fr));gap:10px;margin-bottom:18px;}
.dash-chip{font-size:11px;font-weight:700;padding:4px 10px;border-radius:var(--r-pill);display:inline-flex;align-items:center;gap:5px;}
.dash-row{display:grid;grid-template-columns:260px 1fr;gap:14px;align-items:start;}
.dash-donut-card{display:flex;flex-direction:column;align-items:center;}
.dash-legend{display:flex;flex-direction:column;gap:8px;width:100%;margin-top:14px;}
.dash-legend-row{display:flex;align-items:center;justify-content:space-between;font-size:12.5px;}
.dash-legend-row .sw{display:flex;align-items:center;gap:8px;}
.dash-legend-row .dot{width:9px;height:9px;flex-shrink:0;}
.dash-bar-rows{display:flex;flex-direction:column;gap:11px;}
.dash-bar-row{display:grid;grid-template-columns:170px 1fr 52px;align-items:center;gap:10px;font-size:12.5px;}
.dash-bar-name{display:flex;align-items:center;gap:7px;font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.dash-bar-sw{width:9px;height:9px;flex-shrink:0;}
.dash-bar-track{height:8px;background:var(--bg);position:relative;border-radius:99px;}
.dash-bar-fill2{height:100%;border-radius:99px;}
.dash-trend-svg{width:100%;height:180px;display:block;}
.dash-trend-axis{display:flex;justify-content:space-between;font-size:10px;color:var(--mu);margin-top:6px;}
@media (max-width:760px){.dash-row{grid-template-columns:1fr;}}
.skill-ref{margin-top:22px;background:var(--bg);border:1px dashed var(--bdr);border-radius:var(--r-md);padding:16px;}
.skill-ref-head{font-size:11px;font-weight:700;color:var(--mu);text-transform:uppercase;letter-spacing:.06em;margin-bottom:10px;}
.skill-ref-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(110px,100%),1fr));gap:8px;}
.skill-ref-grid .stat{background:#fff;}
/* ─── ตัวกรองประเภทบนหน้าแผนที่ (เลือกได้หลายประเภท) ───
 * ทำหน้าตาเหมือน <select> เดิมตอนพับอยู่ คนใช้จะได้ไม่รู้สึกว่าของย้ายที่ แต่กางแล้วเป็นรายการ
 * ติ๊กถูกพร้อมจำนวนจุดต่อประเภท — จำกัดความสูงแล้วให้เลื่อน เพราะบางระบบมีเกิน 15 ประเภท */
.tf-box{margin-bottom:8px;border:1px solid var(--bdr);border-radius:var(--r-sm);background:var(--card);}
.tf-box>summary{padding:7px 10px;font-size:13px;cursor:pointer;list-style:none;display:flex;align-items:center;justify-content:space-between;gap:6px;}
.tf-box>summary::-webkit-details-marker{display:none;}
.tf-box>summary::after{content:'▾';color:var(--mu);font-size:11px;flex-shrink:0;}
.tf-box[open]>summary{border-bottom:1px solid var(--bdr);font-weight:700;}
.tf-box[open]>summary::after{content:'▴';}
.tf-panel{padding:7px 8px;}
.tf-actions{display:flex;gap:5px;margin-bottom:6px;}
.tf-actions .btn-s{flex:1;font-size:10.5px;padding:4px 6px;}
#typeFilterList{max-height:210px;overflow-y:auto;}
.tf-row{display:flex;align-items:center;gap:7px;padding:4px 5px;border-radius:6px;cursor:pointer;font-size:12.5px;}
.tf-row:hover{background:var(--bg);}
.tf-row input{width:auto;margin:0;flex-shrink:0;}
.tf-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.tf-count{font-size:10.5px;color:var(--mu);background:var(--bg);border-radius:var(--r-pill);padding:1px 7px;flex-shrink:0;}
.tf-empty{font-size:11px;color:var(--mu);padding:6px 4px;}

/* ─── ใบ MA รอบ PM (หน้า /pm-doc) ───
 * จัดให้เหมือนแบบฟอร์มกระดาษของ DOH เพราะสุดท้ายต้องปริ้นส่ง — ช่องกรอกจึงกลมกลืนไปกับตาราง
 * ไม่ใช่กล่อง input ลอย ๆ และเวลาสั่งพิมพ์ ช่องกรอกจะกลายเป็นข้อความธรรมดาไม่มีกรอบเว็บติดไป */
.pmdoc-bar{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:8px;margin-bottom:10px;}
.pmdoc-progress{position:sticky;top:0;z-index:20;background:var(--card);border:1px solid var(--bdr);
  border-radius:var(--r-md);padding:8px 12px;display:flex;flex-wrap:wrap;gap:8px 18px;align-items:center;margin-bottom:10px;}
.pmdoc-progress .pill{display:flex;align-items:baseline;gap:6px;font-size:12px;color:var(--mu);}
.pmdoc-progress .pill b{font-size:14px;color:var(--tx);}
.pmdoc-progress .pill.done b{color:var(--g);}
.pmdoc-progress .pill.miss b{color:var(--r);}
.sheet{background:var(--card);border:1px solid var(--bdr);border-radius:var(--r-md);padding:14px 16px;margin-bottom:12px;box-shadow:var(--shadow-sm);}
.sheet-head{display:flex;justify-content:space-between;align-items:baseline;gap:10px;
  border-bottom:2px solid var(--tx);padding-bottom:6px;margin-bottom:10px;}
.sheet-head b{font-size:14.5px;}
.sheet-no{font-size:11px;color:var(--mu);}
.sheet table{border-collapse:collapse;width:100%;font-size:12.5px;}
.sheet td,.sheet th{border:1px solid var(--bdr);padding:4px 7px;vertical-align:middle;}
.sheet th{background:var(--bg);font-weight:700;text-align:center;font-size:11.5px;color:var(--mu);}
.sheet .lbl{background:var(--bg);font-weight:600;white-space:nowrap;}
.sheet .grp{background:var(--bg);font-weight:700;text-align:center;width:96px;}
.sheet .it-name{width:40%;}
.sheet .num{text-align:center;}
.sys-v{background:var(--pl);color:var(--p-deep);font-weight:600;}
.calc-v{background:var(--gl);color:var(--g);font-weight:700;text-align:center;}
.mid-band{text-align:center;font-weight:700;background:var(--bg);}
.sheet td.in{padding:2px 4px;}
.sheet td.in input,.sheet td.in select{width:100%;margin:0;padding:3px 6px;font-size:12.5px;
  border:1px solid transparent;background:transparent;border-radius:5px;}
.sheet td.in input:hover,.sheet td.in select:hover{border-color:var(--bdr);}
.sheet td.in input:focus,.sheet td.in select:focus{border-color:var(--p);background:var(--card);}
.other-in{display:none;margin-top:3px;}
.other-in.on{display:block;}
.unit-row{display:flex;align-items:center;gap:6px;}
.unit-row small{color:var(--mu);font-size:10.5px;white-space:nowrap;}
.calib-round{margin-bottom:16px;}
.calib-round h3{margin:0 0 6px;font-size:13px;font-weight:700;}
/* ช่องจราจรในตารางสอบเทียบเพิ่ม/ลบได้ ชื่อช่องจึงเป็นช่องพิมพ์ ไม่ใช่ข้อความตายตัว
 * เวลาพิมพ์เอกสารปุ่มเพิ่ม/ลบถูกซ่อนด้วย .no-print เหลือเฉพาะชื่อช่อง */
.lane-cell{white-space:nowrap;}
.lane-lbl{width:62px;padding:2px 4px;font-size:11px;font-weight:600;border:1px solid var(--bdr);
  border-radius:4px;background:var(--card);}
.lane-x{border:none;background:none;color:var(--r);font-size:11px;cursor:pointer;padding:0 2px;line-height:1;}
.lane-add{background:var(--bg);padding:3px 6px !important;}
.lane-add .btn-s{font-size:10.5px;padding:3px 8px;min-height:0;}
@media print{.lane-lbl{border:none;background:transparent;width:auto;}}
.calib-tbl{min-width:760px;}
@media(max-width:640px){
  /* หัวเอกสารมี 3 คู่ ป้าย/ค่า ต่อแถว ซึ่งไม่มีทางพอในจอ 375px — บนมือถือจับเป็นกริด 2 คอลัมน์
   * (ป้ายซ้าย ค่าขวา) แถวหนึ่งจึงกลายเป็น 3 บรรทัด อ่านได้ครบโดยไม่ต้องเลื่อนแนวนอน */
  .sheet .hdr-tbl tr{display:grid;grid-template-columns:minmax(92px,40%) 1fr;}
  .sheet .hdr-tbl td{border-top:none;}
  .sheet .hdr-tbl tr:first-child td:first-child,.sheet .hdr-tbl tr:first-child td:nth-child(2){border-top:1px solid var(--bdr);}
  .sheet .hdr-tbl td[colspan]{grid-column:2;}
  .sheet{padding:10px 11px;}
  .sheet .grp{width:64px;font-size:11px;}
  .sheet .it-name{width:auto;}
}
.sheet .shots{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:9px;}
.shot{border:1px solid var(--bdr);border-radius:var(--r-sm);padding:8px;display:flex;flex-direction:column;gap:6px;}
.shot-t{font-size:11.5px;font-weight:600;line-height:1.35;}
.shot-box{min-height:110px;display:grid;place-items:center;background:var(--bg);border-radius:6px;overflow:hidden;}
.shot-box img{width:100%;height:120px;object-fit:cover;cursor:zoom-in;}
.shot-act{display:flex;gap:5px;}
.shot-act .btn-s{flex:1;text-align:center;font-size:10.5px;padding:4px 6px;cursor:pointer;}
/* ─── แบบฟอร์ม LSE ───
 * ตารางเดียวจบ: ลำดับ / รายละเอียด / สถานะก่อน / สถานะหลัง / การปรับปรุงแก้ไข
 * แถวหัวกลุ่ม (1, 2) พื้นเทาเหมือนเอกสารต้นฉบับ */
.lse-tbl{width:100%;border-collapse:collapse;font-size:12px;}
.lse-tbl th,.lse-tbl td{border:1px solid var(--bdr);padding:5px 7px;vertical-align:middle;}
.lse-tbl th{background:var(--bg);font-size:11.5px;text-align:center;}
.lse-tbl td.lse-no{text-align:center;font-weight:700;color:var(--mu);white-space:nowrap;}
.lse-tbl tr.lse-grp td{background:#e8eef6;font-weight:700;}
.lse-tbl td.in input,.lse-tbl td.in select{width:100%;font-size:11.5px;padding:4px 6px;margin:0;}
.shot-cap{width:100%;font-size:11.5px;padding:4px 6px;}
.shot-add .shot-box{border:1px dashed var(--bdr);color:var(--p-deep);font-weight:700;}

@media print{
  .no-print,header,.nav-sidebar,.pmdoc-bar,.pmdoc-progress,.shot-act{display:none !important;}
  .tab-pg{overflow:visible !important;padding:0 !important;}
  .sheet{border:none;box-shadow:none;break-after:page;padding:0;margin:0;}
  .sheet td.in input,.sheet td.in select{border:none;background:transparent;appearance:none;padding:0;}
  .sys-v,.calc-v{background:#fff !important;color:#000 !important;}
  @page{size:A4 portrait;margin:12mm;}
}

@media(max-width:768px){
  /* แถบเครื่องมือหน้าตาราง PM มี 5 ตัวกรอง + 4 ปุ่ม พอ flex-wrap บนจอ 375px แล้วเรียงสะเปะสะปะ
   * (ช่องเลือกครึ่งแถวคู่กับปุ่ม) — บนมือถือจัดเป็นกริด 2 คอลัมน์ให้ขอบตรงกันทุกตัว */
  .ma-tools{display:grid !important;grid-template-columns:1fr 1fr;gap:6px;width:100%;}
  .ma-tools select{width:100% !important;margin:0 !important;}
  .ma-tools select:first-of-type{grid-column:1 / -1;}
  .ma-tools:has(select:nth-of-type(2):last-of-type) select{grid-column:1 / -1;}
  .ma-tools .btn,.ma-tools .btn-s{width:100%;text-align:center;}
  .stats .stat{min-width:calc(50% - 5px);}
  /* คอลัมน์ชื่อจุดที่ตรึงไว้กว้าง ~230px กินพื้นที่จอมือถือ (345px) เกือบหมด เหลือให้เห็นช่องรอบ
   * ไม่ถึงครึ่งช่อง — บีบให้แคบลงและตัดบรรทัดแทน เพื่อให้เลื่อนดูรอบ PM ได้จริง */
  .pm-matrix thead th:first-child,.pm-matrix tbody td:first-child{
    max-width:140px;white-space:normal;word-break:break-word;}
}
/* ─── ตารางกว้าง: ตรึงคอลัมน์แรกไว้ ───
 * ตาราง PM กว้าง ~1700px และใบ MA มีตารางสอบเทียบ 760px พอเลื่อนแนวนอนดูรอบท้าย ๆ หรือเลนหลัง
 * ชื่อจุด/ชื่อเลนจะหลุดออกนอกจอ อ่านแล้วไม่รู้ว่ากำลังดูแถวไหน — บนมือถือยิ่งชัด (จอ 375px
 * ต้องเลื่อน 5 หน้าจอ) จึงตรึงคอลัมน์แรกไว้กับที่ */
.pm-matrix thead th:first-child,.pm-matrix tbody td:first-child,
.calib-tbl thead th:first-child,.calib-tbl tbody td:first-child,
.calib-tbl tr>td:first-child,.calib-tbl tr>th:first-child{
  position:sticky;left:0;z-index:2;box-shadow:1px 0 0 var(--bdr);}
.pm-matrix tbody td:first-child{background:var(--card);}
.pm-matrix thead th:first-child{background:var(--bg);z-index:3;}
.pm-matrix tbody tr:hover td:first-child{background:var(--bg);}
.calib-tbl tbody td:first-child,.calib-tbl tr>td:first-child{background:var(--bg);}
.calib-tbl thead th:first-child,.calib-tbl tr>th:first-child{background:var(--bg);z-index:3;}
/* แถวคั่น "เกาะกลาง" และแถว "จำนวนรถมากกว่า 4 ล้อ" ใช้ช่องแรกแบบ colspan กินหลายคอลัมน์
 * ถ้าตรึงไว้ด้วย ข้อความที่จัดกลางช่องกว้างจะโดนตัดครึ่งตอนเลื่อน — แถวพวกนี้จึงไม่ตรึง */
.calib-tbl tr>td:first-child[colspan],.calib-tbl tr>th:first-child[colspan]{
  position:static;box-shadow:none;}

/* กล่องงาน PM ของจุด DOH ในหน้าบันทึกงานช่าง — แยกพื้นหลังให้เห็นชัดว่าคนละงานกับปุ่ม CM
 * ด้านล่าง (ใบ MA ตามรอบลง pm_records ส่วนบันทึกงานเข้าแก้ไขลง work_logs) */
.doh-pm{background:var(--pl);border:1px dashed rgba(14,165,233,.45);border-radius:var(--r-sm);
  padding:8px 10px;margin-bottom:8px;}
.doh-pm-t{font-size:11.5px;font-weight:700;color:var(--p-deep);}

/* ─── PM MATRIX (หน้า ตาราง MA) ───
 * One column per half-year round, so รอบ 1/รอบ 2 of every site line up vertically and a missed
 * round reads as a hole in the column. Cell state is carried by fill *and* by the glyph in
 * .pm-top (✓ / 🔧 / ⚠ / ✕ / ○) — colour alone would leave the "ไม่มีบันทึก" and "ผ่าน" cells
 * indistinguishable to anyone who can't separate red from green, and this grid is printed.
 * Fills reuse the shared status tokens (--gl/--g etc.) so the page stays in step with badges. */
.pm-matrix{min-width:920px;}
.pm-matrix th.pm-yr{text-align:center;border-left:1px solid var(--bdr);}
.pm-matrix td.pm-cell{border-left:1px solid var(--bdr);width:148px;padding:5px 6px;}
.pm-matrix .pm-now{background:rgba(14,165,233,.05);}
.pm-box{border:1px solid transparent;border-radius:var(--r-sm);padding:5px 8px;display:flex;flex-direction:column;line-height:1.35;}
.pm-top{font-size:11px;font-weight:700;white-space:nowrap;}
.pm-sub{font-size:10px;color:var(--mu);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.pm-done{background:var(--gl);border-color:rgba(var(--g-rgb),.28);}
.pm-done .pm-top{color:var(--g);}
.pm-repair,.pm-issue,.pm-soon{background:var(--al);border-color:rgba(var(--a-rgb),.32);}
.pm-repair .pm-top,.pm-issue .pm-top,.pm-soon .pm-top{color:var(--a);}
.pm-over{background:var(--rl);border-color:rgba(var(--r-rgb),.36);}
.pm-over .pm-top{color:var(--r);}
/* รอบที่จบไปก่อนจุดนี้ถูกสร้างในระบบ — ไม่ใช่ "ขาดรอบ" แต่แอดมินตามกรอกย้อนหลังได้ จึงต้องมีกล่อง
 * ให้กดปุ่มได้ ไม่ใช่ข้อความเปล่า ๆ เหมือนเดิม */
.pm-old{background:var(--bg);border:1px dashed var(--bdr);}
.pm-old .pm-top{color:var(--mu);}
/* ใบที่เปิดค้างไว้ระหว่างกรอก — ไม่ใช่ทั้ง "ทำแล้ว" และ "ยังไม่ได้ทำ" จึงใช้ขอบประแบบฟ้า */
.pm-draft{background:var(--pl);border:1px dashed rgba(14,165,233,.55);}
.pm-draft .pm-top{color:var(--p-deep);}
/* รอบปัจจุบันที่ยังมีเวลาเหลือ > 30 วัน — ฟ้า ไม่ใช่สีเตือน เพราะยังไม่ใช่ปัญหา */
.pm-open{background:var(--pl);border-color:rgba(14,165,233,.35);}
.pm-open .pm-top{color:var(--p-deep);}
.pm-miss{background:repeating-linear-gradient(135deg,transparent 0 6px,rgba(var(--r-rgb),.09) 6px 12px);border:1px dashed rgba(var(--r-rgb),.35);}
.pm-miss .pm-top{color:var(--r);}
.pm-plan{background:var(--bg);border:1px dashed var(--bdr);}
.pm-plan .pm-top{color:var(--mu);font-weight:600;}
.pm-na{color:var(--mu);font-size:11px;padding:5px 8px;}
.pm-cell.pm-out{opacity:.62;}
/* ปุ่มกรอกใบ PM ของรอบนั้น — อยู่ใต้ช่อง ไม่ใช่ในกล่องสถานะ จะได้ไม่ดูเหมือนเป็นส่วนหนึ่งของผล */
.pm-fill{display:block;width:100%;margin-top:4px;padding:3px 6px;font-family:inherit;font-size:10px;text-align:center;text-decoration:none;
  font-weight:700;border:1px dashed var(--bdr);border-radius:6px;background:transparent;color:var(--p-deep);cursor:pointer;}
.pm-fill:hover{background:var(--pl);border-style:solid;}
.pm-legend{display:flex;flex-wrap:wrap;gap:6px 14px;padding:10px 12px;border-top:1px solid var(--bdr);background:var(--bg);font-size:10.5px;color:var(--mu);}
.pm-legend span{display:flex;align-items:center;gap:5px;}
.pm-sw{width:12px;height:12px;border-radius:3px;border:1px solid var(--bdr);flex-shrink:0;}

/* ─── SETTINGS PAGE ───
 * The integration panels used to be stacked in the Status page's ~300px left rail, so each one
 * was squeezed into a column far narrower than its content wanted. On their own page they get a
 * responsive grid and room to breathe. */
.settings-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(340px,100%),1fr));gap:12px;align-items:start;}
.settings-grid>.card{margin-bottom:0;padding:14px;}
.settings-head{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:4px;}
.settings-hint{font-size:11px;color:var(--mu);line-height:1.5;margin-bottom:10px;}
/* tooltip */
#tip{position:fixed;background:#0f172a;color:#fff;font-size:10px;padding:4px 9px;border-radius:var(--r-sm);pointer-events:none;z-index:9999;display:none;white-space:nowrap;}
/* route select mode */
.rsel-btn{background:#fff;color:var(--tx);border:1px solid var(--bdr);border-radius:var(--r-sm);padding:7px 12px;font-size:12px;font-weight:700;cursor:pointer;white-space:nowrap;}
.rsel-btn.on{background:var(--p-deep);color:#fff;border-color:var(--p-deep);}
.leaflet-tooltip.rsel-num{background:#0f172a;color:#fff;border:2px solid #fff;border-radius:50%;font-size:11px;font-weight:800;padding:0;width:20px;height:20px;line-height:16px;text-align:center;}
.leaflet-tooltip.rsel-num::before{display:none;}
/* Sits above the toast (bottom:22px) rather than on top of it — both are bottom-centred, so at
 * 14px the route bar and any 'saved'/'error' toast landed in the same place. */
#routeSelBar{position:absolute;left:50%;bottom:74px;transform:translateX(-50%);z-index:1000;background:rgba(15,23,42,.92);color:#fff;border-radius:var(--r-md);padding:9px 12px;display:none;align-items:center;gap:9px;font-size:12px;max-width:92%;flex-wrap:wrap;justify-content:center;}
#routeSelBar b{color:#fff;}
/* map status stars: partial = yellow, all-down = blinking red */
.leaflet-div-icon.mk-star-wrap{background:transparent;border:none;}
.mk-star{font-size:24px;line-height:26px;text-align:center;text-shadow:0 0 2px #fff,0 0 4px #fff;filter:drop-shadow(0 1px 2px rgba(0,0,0,.45));}
.mk-star-yellow{color:#eab308;}
.mk-star-red{color:#dc2626;}
.mk-star-green{color:#16a34a;}
.mk-star-blink{animation:mkStarBlink .9s ease-in-out infinite;}
@keyframes mkStarBlink{0%,100%{opacity:1;}50%{opacity:.25;}}
.mk-star-sel .mk-star{outline:3px solid var(--p);outline-offset:1px;border-radius:50%;background:rgba(255,255,255,.9);}
/* misc */
#lb{position:fixed;inset:0;background:rgba(15,23,42,.9);display:none;align-items:center;justify-content:center;z-index:9000;cursor:zoom-out;}
#lb img{max-width:92vw;max-height:88vh;border-radius:var(--r-md);}
#lb-x{position:absolute;top:14px;right:18px;color:#fff;font-size:28px;cursor:pointer;}
#toast{position:fixed;bottom:22px;left:50%;transform:translateX(-50%);background:#0f172a;color:#fff;padding:10px 20px;border-radius:var(--r-pill);font-size:12px;z-index:9999;display:none;box-shadow:var(--shadow-md);}
.spin{display:inline-block;width:14px;height:14px;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:spin .6s linear infinite;vertical-align:middle;}
@keyframes spin{to{transform:rotate(360deg);}}
@media(max-width:1024px){
  :root{--sw:280px;}
  .status-layout{grid-template-columns:minmax(220px,260px) 1fr;}
}
@media(max-width:860px){
  .status-layout{grid-template-columns:1fr;}
}
@media(max-width:768px){
  :root{--sw:100%;}
  .nav-burger{display:block;}
  .nav-sidebar{position:fixed;top:0;bottom:0;left:0;width:250px!important;transform:translateX(-100%);transition:transform .2s ease;z-index:1500;box-shadow:var(--shadow-md);}
  .nav-sidebar.mobile-open{transform:translateX(0);}
  .nav-collapse-btn{display:none;}
  .main-wrap{flex-direction:column;}
  #tab-map{flex-direction:column;}
  .sidebar{width:100%;max-height:40dvh;border-right:none;border-bottom:1px solid var(--bdr);}
  .map-wrap{flex:1;min-height:220px;}
  /* บนมือถือแถบด้านบนสูงแค่ 40dvh ถ้ามีแผนเดินทางค้างอยู่หลายแผน การ์ดแผนจะกินพื้นที่จนหมด
   * ตัวกรองประเภท/ภาค และช่องค้นหาถูกดันตกจอ — จำกัดความสูงการ์ดแผนแล้วให้เลื่อนในตัวเอง */
  .mban{max-height:116px;overflow-y:auto;}
  /* คำแนะนำ "คลิกขวาที่จุดบนแผนที่" ใช้ไม่ได้บนจอสัมผัส จึงซ่อนเพื่อคืนพื้นที่ให้ตัวกรอง */
  .map-tip{display:none !important;}
  th,td{padding:6px 7px;font-size:11px;}
  .btn,.btn-s{min-height:38px;padding:8px 14px;}
  input,select,textarea{font-size:16px;padding:9px 11px;}
  .modal{padding:16px;}
}
/* ─── กล่องคำอธิบายสัญลักษณ์บนแผนที่ ───
 * เดิมเป็นกล่องเปิดค้าง บนจอมือถือกินพื้นที่แผนที่เกือบครึ่งจอ — ทำเป็น details ย่อ/ขยายได้
 * เปิดไว้บน PC ส่วนมือถือให้ย่อเองตั้งแต่แรก (JS ปิดให้ตอนโหลดถ้าจอแคบ) */
.map-legend{position:absolute;bottom:30px;left:10px;z-index:1000;background:rgba(255,255,255,.92);
  border-radius:var(--r-md);padding:8px 12px;font-size:11px;border:1px solid var(--bdr);max-width:62%;}
.map-legend>summary{font-weight:700;cursor:pointer;list-style:none;}
.map-legend>summary::-webkit-details-marker{display:none;}
.map-legend>summary::after{content:' ▾';color:var(--mu);}
.map-legend:not([open])>summary::after{content:' ▸';}
.map-legend[open]>summary{margin-bottom:4px;}
@media(max-width:768px){
  .map-legend{bottom:22px;font-size:10px;padding:6px 9px;max-width:56%;}
}
@media(max-width:480px){
  .logo h1 small{display:none;}
  header{padding:0 10px;}
  /* At 375px the header row (burger + wordmark + user + language + logout) overflowed by a few
   * pixels. The role badge is the one piece that carries no information the rest of the UI doesn't
   * already show — the visible menu items differ per role — so it goes first and the username,
   * which actually identifies the session, stays. */
  .uchip{gap:4px;}
  .uchip .rbadge{display:none;}
  #hUser{max-width:80px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
  .row2{flex-direction:column;gap:0;}
  .row2>div{width:100%;}
  .modal-foot{flex-direction:column-reverse;align-items:stretch;}
  .modal-foot .btn,.modal-foot .btn-s{width:100%;text-align:center;}
}
