/* ---- block 1 ---- */

  :root{
    /* โทนเดียวกับ monitor.div6.net — พื้นหลังเทาอมน้ำเงิน ไม่ขาวโพลน
       ตัวอักษรน้ำเงินเข้ม อ่านสบาย ยังคงพาสเทลไว้ที่จุดเน้นเท่านั้น */
    /* โทนทางการ: กรมท่า/เทาน้ำเงิน เน้นสีเฉพาะจุดที่สื่อความหมาย (สถานะ) เท่านั้น */
    --ink:#1e2740;--sub:#6b7793;--faint:#98a2ba;--line:#e4e9f2;--card:#ffffff;
    --bg:#eef1f6;--soft:#f4f6fb;
    --green:#2f8f63;--red:#c94a4a;--yellow:#c08a2a;--violet:#5a5f8f;--blue:#3f5488;
    --pri:#3d4a72;
    --gradA:linear-gradient(135deg,#2e3854,#414d75);
    --shadow:0 8px 24px rgba(34,42,68,.09);--shadow-sm:0 2px 8px rgba(34,42,68,.06);
  }
  *{box-sizing:border-box;-webkit-tap-highlight-color:transparent;margin:0}
  /* กันเลื่อนซ้าย-ขวา — แต่ 'hidden' ทำให้ body กลายเป็นกล่องเลื่อนเอง แล้ว position:sticky
     ทุกตัวในหน้า (หัวหน้า .page-head.stick, แถบข้าง) ตายหมด
     'clip' คลิปเหมือนกันแต่ไม่สร้างกล่องเลื่อน → sticky กลับมาทำงาน (ถอยไป hidden ถ้าเบราว์เซอร์เก่า) */
  html,body{overflow-x:hidden}
  @supports (overflow:clip){html,body{overflow-x:clip}}
  body{font-family:"Sarabun","SF Pro Text",system-ui,"Segoe UI",sans-serif;color:var(--ink);background:var(--bg);min-height:100vh;font-size:14px}
  /* ปุ่มแบบ chip — กดค้าง = เปิดใช้งาน (ใช้บนหัวหน้าต่างดูสด) */
  .chipbar{display:flex;gap:8px;margin-left:auto;align-items:center}
  .chip{border:1px solid rgba(255,255,255,.35);background:rgba(255,255,255,.14);color:#fff;
        border-radius:999px;padding:6px 13px;font-size:12px;font-weight:700;cursor:pointer;
        font-family:inherit;line-height:1;transition:.15s;white-space:nowrap}
  .chip:hover{background:rgba(255,255,255,.26)}
  .chip.on{background:#fff;color:var(--pri);border-color:#fff;box-shadow:0 2px 10px rgba(0,0,0,.15)}
  .chip.off{opacity:.72}
  /* chip บนพื้นขาว (ใต้ภาพในหน้ากล้องเดี่ยว) */
  .chip.dark{border-color:var(--line);background:var(--soft);color:var(--sub)}
  .chip.dark:hover{background:#e9edf6}
  .chip.dark.on{background:var(--pri);color:#fff;border-color:var(--pri)}
  h1,h2,h3,h4{margin:0}.muted{color:var(--sub)}.tiny{font-size:12px}.red{color:var(--red)!important;font-weight:700}.hidden{display:none!important}
  /* login/splash */
  .center{min-height:100vh;display:grid;place-items:center;padding:20px;background:linear-gradient(160deg,#e9edf5,#eef1f6 55%,#e8ecf4)}
  .logincard{background:#fff;border-radius:24px;box-shadow:var(--shadow);padding:34px 30px;width:100%;max-width:400px;text-align:center}
  .logo{width:78px;height:78px;border-radius:22px;background:var(--gradA);display:grid;place-items:center;font-size:36px;box-shadow:var(--shadow-sm);margin:0 auto}
  .b1{font-size:24px;font-weight:800;letter-spacing:1px;margin-top:14px}.b2{font-size:13px;font-weight:800;letter-spacing:5px;color:var(--sub)}
  /* โลโก้บริษัท (Logo_1diao) — เต็มใบตอน splash/login, เฉพาะลายก้นหอยตอน sidebar */
  .brand-img{display:block;margin:0 auto;width:116px;max-width:46%;height:auto}
  .logo-row .brand-img{width:40px;height:40px;object-fit:contain;margin:0}
  .brand-co{font-size:14px;font-weight:800;color:var(--pri);letter-spacing:.2px;margin-top:10px}
  .copyfoot{text-align:center;color:var(--faint);font-size:11px;letter-spacing:.2px;padding:24px 12px calc(env(safe-area-inset-bottom) + 16px)}
  input.f{width:100%;border:1px solid var(--line);border-radius:14px;padding:14px 15px;font-size:15px;margin-top:12px;font-family:inherit}
  .btn{border:0;border-radius:13px;padding:12px 18px;font-weight:800;font-size:14px;cursor:pointer;box-shadow:var(--shadow-sm)}
  .btn.p{background:var(--gradA);color:#fff}.btn.g{background:#fff;color:var(--ink);border:1px solid var(--line)}
  .encmodal{position:fixed;inset:0;background:rgba(22,18,32,.5);display:none;align-items:center;justify-content:center;z-index:9999;padding:16px}
  .encmodal.on{display:flex}
  .encbox{background:var(--card,#fff);color:var(--ink);border-radius:18px;max-width:540px;width:100%;max-height:88vh;overflow:auto;padding:20px 22px;box-shadow:0 24px 70px rgba(0,0,0,.32)}
  .encbox h3{font-size:16.5px;margin:0}
  .enc-tbl{width:100%;border-collapse:collapse;font-size:13px;margin:10px 0}
  .enc-tbl th{color:var(--muted,#8b8698);font-weight:700;font-size:11px;text-transform:uppercase;letter-spacing:.5px;text-align:left;padding:5px 8px;border-bottom:1px solid var(--line)}
  .enc-tbl td{padding:6px 8px;border-bottom:1px solid var(--line);vertical-align:top;font-size:13px}
  .enc-arrow{color:var(--muted,#8b8698);text-align:center;width:24px}
  /* ปุ่มเลือกบังคับ H.265 ต่อสตรีม (น้ำเงิน=เปิด) */
  .h265row{display:flex;gap:8px;flex-wrap:wrap;margin:11px 0 4px}
  .h265chip{display:inline-flex;align-items:center;gap:7px;border-radius:999px;padding:8px 14px;
    font-size:12.5px;font-weight:800;cursor:pointer;border:1.5px solid var(--line);background:#fff;
    color:var(--sub);user-select:none}
  .h265chip .dot{width:9px;height:9px;border-radius:50%;border:2px solid currentColor}
  .h265chip.on{background:var(--k1);border-color:var(--k1);color:#fff}
  .h265chip.on .dot{background:#fff;border-color:#fff}
  .encspin{width:26px;height:26px;border:3px solid var(--line);border-top-color:var(--pri,#8b5cf6);border-radius:50%;animation:encsp 0.8s linear infinite}
  @keyframes encsp{to{transform:rotate(360deg)}}
  /* iOS Safari รอดูว่าเป็น "แตะสองที" หรือ "รูดนิ้ว" ก่อนจะยอมส่งการกดให้เว็บ
     ทำให้กดแล้วรู้สึกหน่วง โดยเฉพาะตอนเพิ่งเลื่อนจอเสร็จ
     manipulation = บอกไปเลยว่าองค์ประกอบนี้ไม่มีท่าซูม/แตะสองที ส่งการกดมาได้ทันที */
  .card,.btn,.chip,.eyebtn,.mclose,.scanbtn,nav a,[data-cid]{touch-action:manipulation}
  .btn.r{background:var(--red);color:#fff}   /* งานที่ย้อนกลับไม่ได้ เช่น ลบบัญชีบนเครื่อง */
  .btn.full{width:100%;padding:15px;margin-top:16px;font-size:16px}
  .foot{color:var(--faint);font-size:12px;margin-top:20px}
  /* shell */
  .shell{display:flex;min-height:100vh}
  .sidebar{width:246px;flex:0 0 auto;background:#fff;border-right:1px solid var(--line);padding:22px 16px;display:flex;flex-direction:column;position:sticky;top:0;height:100vh}
  .logo-row{display:flex;align-items:center;gap:12px;margin-bottom:24px;padding:0 6px}
  .logo-row .logo{width:44px;height:44px;border-radius:13px;font-size:20px}
  .logo-row .b1{font-size:15px;letter-spacing:.5px}.logo-row .b2{font-size:9.5px;letter-spacing:3px}
  .nav a{display:flex;align-items:center;gap:12px;padding:12px 14px;border-radius:13px;color:var(--sub);font-weight:700;font-size:14.5px;cursor:pointer;margin-bottom:4px}
  .nav a .ic{font-size:18px;width:22px;text-align:center}
  .nav a.on{background:var(--gradA);color:#fff}.nav a:hover:not(.on){background:var(--soft)}
  .side-user{margin-top:auto;display:flex;align-items:center;gap:10px;padding:10px;border-radius:13px;background:var(--soft);cursor:pointer}
  .side-user .av{width:36px;height:36px;border-radius:11px;background:var(--gradA);display:grid;place-items:center;color:#fff;font-weight:800}
  /* ปุ่มบัญชี (มุมขวาบน) — โผล่เฉพาะมือถือ ที่ sidebar ถูกยุบเป็นแถบล่าง */
  .acctbtn{display:none}
  main{flex:1;min-width:0;padding:26px 30px 60px}
  .page-head{display:flex;align-items:center;gap:16px;margin-bottom:22px;flex-wrap:wrap}
  .page-head h1{font-size:20px;font-weight:800;letter-spacing:-.2px}
  .page-head.stick{position:sticky;top:0;z-index:35;background:var(--bg);padding-top:14px;margin-top:-14px;padding-bottom:12px}
  .searchbox{position:relative;flex:0 1 340px;min-width:200px}
  .searchbox .si{position:absolute;left:13px;top:50%;transform:translateY(-50%);font-size:13px;pointer-events:none;opacity:.6}
  .searchbox input{width:100%;border:1px solid var(--line);background:#fff;border-radius:13px;padding:11px 38px 11px 34px;font-size:14px;box-shadow:var(--shadow-sm)}
  .searchbox input:focus{outline:none;border-color:var(--pri)}
  .searchbox .sx{position:absolute;right:9px;top:50%;transform:translateY(-50%);border:0;background:#e2e7f2;color:#6a6480;width:22px;height:22px;border-radius:50%;cursor:pointer;font-size:11px;display:grid;place-items:center}
  .searchbox .sx:hover{background:#ccd5e6}
  /* ---- แถบชิปกรองไซต์ ----
     แถวเดียว เลื่อนแนวนอนบนมือถือ (ไซต์ 60+ ใบ ต้องหาไซต์ที่มีปัญหาให้เจอเร็ว)
     ซ่อน scrollbar แต่ยังปัดได้ — บนมือถือแถบเลื่อนกินที่และดูรก */
  .fbar{display:flex;align-items:center;gap:7px;overflow-x:auto;padding:2px 0 4px;
        scrollbar-width:none;-ms-overflow-style:none;width:100%}
  .fbar::-webkit-scrollbar{display:none}
  .fchip{flex:0 0 auto;display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line);
         background:#fff;color:var(--sub);font-size:12px;font-weight:700;padding:6px 12px;
         border-radius:99px;cursor:pointer;white-space:nowrap;transition:background .12s,border-color .12s,color .12s}
  .fchip:hover{border-color:#c9d2e4}
  .fchip i{font-style:normal;font-size:11px;font-weight:800;opacity:.65;font-variant-numeric:tabular-nums}
  .fchip.on{background:var(--pri);border-color:var(--pri);color:#fff}
  .fchip.on i{opacity:.9}
  /* ชิปที่ไม่มีไซต์เข้าเงื่อนไข — หรี่ลงและกดไม่ได้ ดีกว่าซ่อนหาย เพราะยังบอกได้ว่า "ไม่มีเลย" */
  .fchip.zero{opacity:.4;cursor:default;pointer-events:none}
  .fchip.warn.on{background:var(--red);border-color:var(--red)}
  /* var(--yellow) ตรงๆ กับตัวอักษรขาวได้ contrast แค่ 3.0 (ต่ำกว่าเกณฑ์ 4.5)
     จึงใช้เฉดเข้มขึ้นเฉพาะตอนชิปติด — ยังเป็นสีเหลืองชุดเดียวกัน แต่อ่านออก */
  .fchip.soft.on{background:#94681c;border-color:#94681c}
  .fclear{flex:0 0 auto;border:0;background:#e2e7f2;color:#5b6480;border-radius:99px;
          font-size:12px;font-weight:800;padding:6px 12px;cursor:pointer;white-space:nowrap}
  .fclear:hover{background:#ccd5e6}
  /* บอกเสมอว่ากำลังกรองอยู่ + เหลือกี่ไซต์จากทั้งหมด
     กันเข้าใจผิดว่า "ไซต์หายไปไหน" ซึ่งเป็นความสับสนที่เกิดง่ายที่สุดของฟีเจอร์นี้ */
  .fnote{margin:-6px 0 14px;font-size:12px;font-weight:700;color:var(--pri)}
  /* ช่องค้นหาหลักของหน้าฐานข้อมูล — ตัวใหญ่ เห็นชัด เป็นจุดสังเกตของหน้า */
  /* ---- กล่องค้นหา/ช่องกรอกทั่วไป (.search) ----
     เดิมคลาสนี้ถูกใช้อยู่ 5 ที่แต่ "ไม่เคยมี CSS" เลย -> เบราว์เซอร์วาดเป็นช่องเปล่า ๆ
     ตัวเล็กและหน้าตาไม่เข้ากับหน้าอื่น (ที่เห็นชัดสุดคือช่องค้นหาไซต์ของ UniFi) */
  .search{width:100%;border:1.5px solid var(--line);background:var(--card);color:var(--ink);
    border-radius:13px;padding:13px 14px;font-family:inherit;font-size:16px;font-weight:600;
    box-shadow:var(--shadow-sm);transition:border-color .15s,box-shadow .15s}
  .search::placeholder{font-weight:500;color:var(--faint)}
  .search:focus{outline:none;border-color:var(--pri);box-shadow:0 0 0 4px rgba(139,92,246,.13)}
  select.search{cursor:pointer}
  .bigsearch{position:relative;margin-bottom:14px}
  .bigsearch .si{position:absolute;left:18px;top:50%;transform:translateY(-50%);font-size:20px;pointer-events:none;opacity:.55}
  .bigsearch input{width:100%;border:2px solid var(--line);background:#fff;border-radius:16px;
    padding:18px 46px 18px 52px;font-size:16px;font-weight:600;box-shadow:var(--shadow-sm);transition:border-color .15s,box-shadow .15s}
  .bigsearch input::placeholder{font-weight:500;color:var(--faint)}
  .bigsearch input:focus{outline:none;border-color:var(--pri);box-shadow:0 0 0 4px rgba(139,92,246,.13)}
  .bigsearch .sx{position:absolute;right:14px;top:50%;transform:translateY(-50%);border:0;background:#e2e7f2;
    color:#6a6480;width:26px;height:26px;border-radius:50%;cursor:pointer;font-size:13px;display:grid;place-items:center}
  .bigsearch .sx:hover{background:#ccd5e6}
  .dbrow{cursor:pointer}
  .dbrow:hover{background:var(--soft)}
  .dbsn{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12.5px;letter-spacing:.2px}
  /* กล่องนำเข้า QR จาก DMSS */
  .qrzone{display:flex;align-items:center;gap:12px;padding:13px 15px;margin-bottom:14px;cursor:pointer;
    border:2px dashed var(--line);border-radius:14px;background:var(--soft);transition:border-color .15s,background .15s}
  .qrzone:hover,.qrzone.drag{border-color:var(--pri);background:rgba(139,92,246,.06)}
  .qrzone .qz-ic{font-size:22px;opacity:.6;line-height:1}
  .sugg{position:absolute;top:calc(100% + 6px);left:0;right:0;background:#fff;border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow);z-index:60;display:none;max-height:320px;overflow:auto}
  .sugg.on{display:block}
  .sugg .sg{padding:10px 14px;cursor:pointer;font-size:13.5px;display:flex;align-items:center;gap:8px;border-bottom:1px solid var(--soft)}
  .sugg .sg:last-child{border-bottom:0}.sugg .sg:hover{background:var(--soft)}.sugg .sg.none{cursor:default;color:var(--sub)}
  .spacer{margin-left:auto}
  /* site grid */
  .grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px}
  .card{background:var(--card);border-radius:18px;box-shadow:var(--shadow-sm);border:1px solid var(--line)}
  /* หน้าแรกมีการ์ด 50+ ใบ แต่ละใบมีองค์ประกอบย่อยสิบกว่าชิ้น = ต้นไม้การแสดงผลใหญ่มาก
     content-visibility:auto บอกเบราว์เซอร์ว่า "ใบที่ยังไม่เลื่อนมาถึง ไม่ต้องคำนวณ/ไม่ต้องวาด"
     ทุกครั้งที่มีอะไรเปลี่ยน (เปิดหน้าต่างทับ · รีเฟรชการ์ด · เลื่อนจอ) เบราว์เซอร์จะทำงาน
     เฉพาะใบที่เห็นบนจอจริง ๆ ไม่ใช่ทั้ง 52 ใบ
     contain-intrinsic-size บอกความสูงโดยประมาณไว้ก่อน แถบเลื่อนจึงไม่กระโดด */
  .site{padding:18px;cursor:pointer;transition:transform .12s,box-shadow .12s;
        content-visibility:auto;contain-intrinsic-size:auto 168px}
  .site:hover{transform:translateY(-2px);box-shadow:var(--shadow)}
  .site-top{display:flex;align-items:center;gap:12px;margin-bottom:12px}
  .site .av{width:46px;height:46px;border-radius:14px;display:grid;place-items:center;font-size:22px;background:linear-gradient(135deg,#e9edf6,#e0e6f1)}
  .site .nm{font-weight:700;font-size:15px}.site .sub{color:var(--faint);font-size:12px;margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .sub.hit{font-size:11.5px;margin-top:1px}
  .sg .sub.hit{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .kpi-mini{display:flex;gap:8px}.kpi-mini .k{flex:1;background:var(--soft);border-radius:11px;padding:8px;text-align:center}
  .kpi-mini .k b{display:block;font-size:15px;font-weight:800}.kpi-mini .k span{font-size:10.5px;color:var(--sub)}
  .foot{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-top:12px;font-size:12px}
  .dot{width:9px;height:9px;border-radius:99px;display:inline-block;margin-right:5px;vertical-align:middle}
  .dot.g{background:var(--green)}.dot.y{background:var(--yellow)}.dot.r{background:var(--red)}.dot.x{background:#c9c4d6}
  .badge{font-size:11px;font-weight:700;padding:3px 9px;border-radius:99px;white-space:nowrap}
  .badge.g{background:#e4f4ec;color:#23855a}.badge.y{background:#fbf1de;color:#a9791f}.badge.r{background:#fbe7e7;color:#c33f3f}.badge.x{background:#eaeef6;color:var(--sub)}
  /* monitoring */
  .kpirow{display:grid;grid-template-columns:1.5fr 1fr 1fr 1fr;gap:16px;margin-bottom:20px}
  .kpi{background:#fff;border-radius:18px;padding:16px 18px;box-shadow:var(--shadow-sm);border:1px solid var(--line);display:flex;align-items:center;gap:14px;min-height:84px}
  .kpi b{font-size:24px;font-weight:800;display:block;line-height:1.05}.kpi span{color:var(--sub);font-size:12.5px}
  /* ใช้ flex + justify/align แยกกัน (ไม่ใช้ place-items ซึ่งบางเบราว์เซอร์ไม่รองรับ
     ทำให้ไอคอนไปกองมุมซ้ายบน) และล็อกความกว้างด้วย flex-basis ไม่ให้ถูกบีบ */
  .kico{width:48px;height:48px;min-width:48px;border-radius:14px;font-size:22px;
        display:flex!important;align-items:center!important;justify-content:center!important;
        flex:0 0 48px}
  .kico.blue{background:linear-gradient(135deg,#dfe6f7,#d5deee)}.kico.yellow{background:linear-gradient(135deg,#f1ecdf,#e6dcc2)}.kico.green{background:linear-gradient(135deg,#e2ede6,#cadfd2)}
  .kpi.avail{gap:16px}
  .ring{width:84px;height:84px;border-radius:50%;flex:0 0 auto;display:grid;place-items:center;background:conic-gradient(var(--green) calc(var(--p)*1%),#eee 0)}
  .ring i{width:64px;height:64px;border-radius:50%;background:#fff;display:grid;place-items:center;font-size:17px;font-weight:800;font-style:normal}
  /* ===== Monitoring dashboard ===== */
  .hero{display:grid;grid-template-columns:1.6fr 1fr 1fr 1fr;gap:16px;margin-bottom:18px}
  .hcard{background:var(--card);border:1px solid var(--line);border-radius:16px;
         padding:16px 18px;box-shadow:var(--shadow-sm);min-height:132px;
         display:flex;flex-direction:column;gap:8px}
  .hero-main{flex-direction:row;align-items:center;gap:18px}
  .hcard .hl{font-size:11.5px;font-weight:700;color:var(--sub);letter-spacing:.3px;
             text-transform:uppercase}
  .hcard .hv{font-size:14px;font-weight:700;margin-top:2px}
  .hcard .hnum{font-size:30px;font-weight:800;line-height:1.05}
  .hcard .hnum small{font-size:13px;font-weight:700;color:var(--sub);margin-left:5px}
  /* แถบสัดส่วนแบบ stacked */
  .sbar{display:flex;height:8px;border-radius:99px;overflow:hidden;background:var(--line)}
  .sbar>i{display:block;height:100%}
  .sbar>i.g{background:var(--green)}.sbar>i.y{background:var(--yellow)}
  .sbar>i.r{background:var(--red)}.sbar>i.x{background:#c6cddc}
  .skey{display:flex;flex-wrap:wrap;gap:12px;font-size:11.5px;color:var(--sub);margin-top:2px}
  .skey b{color:var(--ink);font-weight:800;margin-left:3px}
  .skey .dot{width:8px;height:8px;margin-right:4px}
  .connwrap{display:flex;align-items:center;gap:14px;margin-top:2px}
  .connwrap>div:first-child{flex:0 0 auto;line-height:0}
  .legend.sm{min-width:0;gap:3px;flex:1}.legend.sm .lg{font-size:11px}
  /* heatmap ไซต์ */
  .heat{display:flex;flex-wrap:wrap;gap:8px}
  .heat .ht{border-radius:11px;padding:9px 12px;cursor:pointer;border:1px solid var(--line);
            background:var(--soft);transition:.15s;min-width:104px;flex:0 0 auto}
  .heat .ht:hover{transform:translateY(-2px);box-shadow:var(--shadow-sm)}
  .heat .ht .n{font-size:12px;font-weight:700;white-space:nowrap;overflow:hidden;
               text-overflow:ellipsis;max-width:180px}
  .heat .ht .m{font-size:10.5px;color:var(--sub);margin-top:2px}
  .heat .ht.g{background:#e8f2ec;border-color:#cfe3d8}
  .heat .ht.y{background:#fbf3e2;border-color:#eddfc2}
  .heat .ht.r{background:#fbeaea;border-color:#efd2d2}
  .heat .ht.x{background:var(--soft)}
  .hint{font-size:11px;color:var(--sub);font-weight:500;display:flex;align-items:center;gap:6px}
  .hint .sw{width:10px;height:10px;border-radius:3px;display:inline-block;margin-left:6px}
  .hint .sw.g{background:#a9d3bd}.hint .sw.y{background:#e6ce97}
  .hint .sw.r{background:#e3aeae}.hint .sw.x{background:#ccd3e0}
  /* แถวกราฟแท่งแนวนอน */
  .hbar{display:flex;align-items:center;gap:10px;padding:7px 2px;cursor:pointer;border-radius:9px}
  .hbar:hover{background:var(--soft)}
  .hbar .nm{width:150px;flex:0 0 auto;font-size:12.5px;font-weight:600;white-space:nowrap;
            overflow:hidden;text-overflow:ellipsis}
  .hbar .tr{flex:1;height:9px;background:var(--line);border-radius:99px;overflow:hidden}
  .hbar .tr>i{display:block;height:100%;border-radius:99px}
  .hbar .vl{width:74px;text-align:right;font-size:12px;font-weight:700;flex:0 0 auto}
  .mon-cols2{display:grid;grid-template-columns:1fr 1fr;gap:20px;margin-bottom:20px;align-items:start}
  .panel h3{display:flex;align-items:center;gap:8px}
  .mon-cols{display:grid;grid-template-columns:1fr 1.5fr;gap:20px;align-items:start}
  /* หน้าผู้ดูแลระบบ: ผู้ใช้ (กว้าง) + ถังขยะ (แคบ) แถวบน, audit log เต็มความกว้างแถวล่าง */
  .admin-grid{display:grid;grid-template-columns:1.5fr 1fr;gap:20px;align-items:start;margin-bottom:20px}
  /* ===== หน้าผู้ดูแลระบบ (จัดใหม่) =====
     แถบข้ามหมวดด้านบน + หัวข้อหมวด + การ์ดสิทธิ์รวมแบบแท็บ
     หมายเหตุ: กล่องสิทธิ์ทั้ง 4 ใบ (ad-pgperm/ad-uniperm/ad-mtperm/ad-acperm)
     ยังเป็นกล่องเดิม ฟังก์ชันเดิมทุกอย่าง เปลี่ยนแค่วิธีเปิด/ปิด */
  .adcols{display:grid;grid-template-columns:1fr 1fr;gap:20px;align-items:start;margin-bottom:20px}
  .adjump{display:flex;gap:8px;flex-wrap:wrap;position:sticky;top:0;z-index:6;
    background:var(--bg,#f5f6f8);padding:10px 0 12px;margin-bottom:4px}
  .adjump button{border:1px solid var(--line);background:var(--card,#fff);color:var(--sub);
    border-radius:99px;padding:7px 14px;font-size:13px;font-weight:600;cursor:pointer;
    font-family:inherit;white-space:nowrap}
  .adjump button:hover{border-color:var(--pri);color:var(--pri)}
  .adsec-h{display:flex;align-items:center;gap:10px;margin:22px 0 12px;font-size:13px;
    font-weight:800;color:var(--sub);letter-spacing:.02em}
  .adsec-h i{font-style:normal;width:22px;height:22px;border-radius:99px;background:var(--pri);
    color:#fff;font-size:12px;display:flex;align-items:center;justify-content:center;flex:0 0 auto}
  .adsec-h span{flex:1;height:1px;background:var(--line)}
  .adtabs{display:flex;gap:6px;flex-wrap:wrap;border-bottom:1px solid var(--line);
    margin:0 -18px 0;padding:0 18px}
  .adtabs button{border:0;background:none;color:var(--sub);font-family:inherit;font-size:13px;
    font-weight:700;padding:9px 12px;cursor:pointer;border-bottom:2px solid transparent;
    margin-bottom:-1px;white-space:nowrap}
  .adtabs button:hover{color:var(--pri)}
  .adtabs button.on{color:var(--pri);border-bottom-color:var(--pri)}
  .adtab-desc{padding:12px 0 2px;line-height:1.55}
  .panel h3 .cnt{margin-left:auto;font-size:12px;font-weight:700;color:var(--sub);background:var(--soft);border-radius:99px;padding:2px 11px;min-width:22px;text-align:center}
  .audit-bar{display:flex;gap:8px;margin-bottom:14px;align-items:center;flex-wrap:wrap}
  /* ===== การ์ด "อุปกรณ์ในระบบ" =====
     กล้อง / NVR / HDD เดิมเป็นการ์ดแยก 3 ใบ ทำให้แถวนี้ดูกระจัดกระจาย
     และบนมือถือกลายเป็น 3 กล่องซ้อนกันยาวเหยียด
     ตอนนี้รวมเป็นการ์ดเดียว แบ่งเป็น 3 ช่องด้วยเส้นบาง ๆ
     ทุกช่องใช้กริดเดียวกัน (ไอคอน / ตัวเลข / ลูกศร) ตัวเลขจึงตรงแนวกันทั้งสามช่อง */
  /* margin ติดลบ + padding ในตัว = ขอบซ้ายของไอคอนตรงกับหัวข้อการ์ดพอดี
     ส่วนพื้นที่ hover ยังเว้นจากขอบการ์ด ไม่ดูล้น */
  .devgrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));margin:4px -8px -6px}
  /* จอใหญ่ไม่ต้องมีลูกศร — 3 ช่องแยกกันชัดอยู่แล้ว และลูกศรจะไปลอยห่างข้อความครึ่งช่อง
     จอเล็กที่เรียงเป็นรายการเต็มความกว้าง ลูกศรถึงจะมีความหมาย (บอกว่ากดเข้าไปได้) */
  .devitem{display:grid;grid-template-columns:46px minmax(0,1fr);gap:13px;
           align-items:center;padding:12px 8px;border:0;background:none;
           font:inherit;color:inherit;text-align:left;cursor:pointer;border-radius:12px;
           transition:background .15s}
  .devitem:hover{background:var(--soft)}
  .devitem+.devitem{border-left:1px solid var(--line);border-radius:12px}
  .devitem .ar{display:none}
  .devitem .dv{min-width:0}
  /* ตัวเลขกับหน่วยอยู่บรรทัดเดียวกัน — อ่านเป็นประโยคเดียว "1,376 กล้อง" */
  .devitem .n{font-size:26px;font-weight:800;letter-spacing:-.8px;line-height:1.05}
  .devitem .u{font-size:12.5px;font-weight:700;color:var(--sub);margin-left:6px}
  .devitem .sub{display:block;font-size:11.5px;color:var(--faint);font-weight:600;margin-top:3px;
                white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .devitem .dtop{display:block;font-style:normal;font-size:11px;line-height:1.35;color:var(--faint);
                 margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .devitem .dtop b{font-weight:800;color:var(--sub)}
  .devitem .ar{color:var(--faint);font-size:19px;justify-self:end}
  .kico.cam{background:linear-gradient(135deg,#e8ecf4,#dbe2ef)}.kico.nvr{background:linear-gradient(135deg,#dfe6f7,#d5deee)}.kico.hdd{background:linear-gradient(135deg,#eceef4,#dfe3ee)}
  /* ใช้ SVG แทน emoji ในการ์ดอุปกรณ์ — emoji แต่ละตัวมี metric ไม่เท่ากัน
     ทำให้จัดกึ่งกลางไม่ตรงสักที (ปัญหาไอคอนกล้องเอียงซ้าย) */
  .kico svg{width:24px;height:24px;display:block;color:var(--pri);stroke-linecap:round;stroke-linejoin:round}
  .devitem .kico{width:46px;height:46px;min-width:46px}
  @media(max-width:760px){
    /* มือถือ: เรียงลงมา เส้นแบ่งเปลี่ยนเป็นแนวนอน — บีบ 3 ช่องบนจอ 360px แล้วตัวเลขล้น */
    .devgrid{grid-template-columns:1fr;margin:4px -6px -6px}
    .devitem+.devitem{border-left:0;border-top:1px solid var(--line);border-radius:0}
    .devitem{grid-template-columns:46px minmax(0,1fr) 12px;padding:13px 10px;min-height:44px}
    .devitem .ar{display:block}
  }
  .donut-wrap{display:flex;align-items:center;gap:22px;flex-wrap:wrap;background:var(--soft);border-radius:16px;padding:18px;margin-bottom:16px}
  .donut{width:150px;height:150px;border-radius:50%;flex:0 0 auto;position:relative}
  .donut::after{content:"";position:absolute;inset:26px;background:var(--soft);border-radius:50%}
  .donut .dc{position:absolute;inset:0;display:grid;place-content:center;text-align:center;z-index:1}.donut .dc b{font-size:22px;font-weight:800;display:block;line-height:1}.donut .dc span{font-size:11px;color:var(--sub)}
  .legend{flex:1;min-width:180px;display:flex;flex-direction:column;gap:7px}
  .legend .lg{display:flex;align-items:center;gap:8px;font-size:12.5px}.legend .lg i{width:11px;height:11px;border-radius:3px;flex:0 0 auto}.legend .lg .ln{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.legend .lg .lc{font-weight:800}
  .inv-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px;margin-top:20px}
  .invsum{display:flex;align-items:baseline;gap:8px;margin-bottom:12px}.invsum b{font-size:22px;font-weight:800}.invsum span{color:var(--sub);font-size:12px}
  .invrow{display:flex;align-items:center;gap:10px;padding:9px 11px;border-radius:12px;cursor:pointer;transition:.12s}.invrow:hover{background:var(--soft)}
  .invrow .ip{flex:1;min-width:0}.invrow .ip .nm{font-size:13px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .invrow .bar{height:6px;background:#eee;border-radius:4px;margin-top:4px;overflow:hidden}.invrow .bar>i{display:block;height:100%;background:linear-gradient(90deg,var(--pri),#8792b8);border-radius:4px}
  .invrow .ct{font-weight:900;font-size:16px;flex:0 0 auto}.invrow .ct span{font-size:11px;color:var(--sub);font-weight:600;margin-left:2px}
  .invrow .ar{color:var(--faint);flex:0 0 auto}
  .panel{background:#fff;border-radius:18px;padding:18px;box-shadow:var(--shadow-sm);border:1px solid var(--line)}
  .panel h3{font-size:14px;margin-bottom:14px}
  /* การเข้ารหัสรายกลุ่ม — บรรทัดละกลุ่ม ตัวเล็ก ชิดขวาเหมือนค่าอื่นในตารางคู่คีย์-ค่า */
  .encg{text-align:right;line-height:1.45;font-size:11.5px}
  .encg b{font-weight:800;font-size:12px}
  .encg span{color:var(--faint)}
  .prob{display:flex;align-items:center;gap:12px;padding:12px;border-radius:13px;cursor:pointer;border-left:4px solid var(--yellow);background:var(--soft);margin-bottom:10px}
  .prob.red{border-left-color:var(--red)}.prob .nm{font-weight:800;font-size:14px}.prob .m{color:var(--faint);font-size:12px}
  .prob .cnt{margin-left:auto;text-align:center}.prob .cnt b{font-size:19px;color:var(--red);font-weight:900}.prob .cnt span{font-size:10px;color:var(--faint);display:block}
  table{width:100%;border-collapse:collapse}
  th{text-align:left;font-size:12px;color:var(--faint);font-weight:700;padding:8px 10px;border-bottom:1px solid var(--line)}
  td{padding:11px 10px;border-bottom:1px solid #f4f1f8;font-size:13.5px}
  tbody tr{cursor:pointer}tbody tr:hover td{background:var(--soft)}
  select.role{border:1px solid var(--line);border-radius:9px;padding:6px;font-family:inherit}
  /* modal */
  /* overscroll-behavior:contain = ห้ามการเลื่อนในหน้าต่างนี้ 'ไหลต่อ' ไปเลื่อนหน้าเว็บข้างหลัง
     บน iOS การเลื่อนสองชั้นพร้อมกันทำให้ Safari สับสน หรี่ timer และดองการกดไว้เป็นวินาที
     ซึ่งตรงกับที่วัดได้ว่าตอนค้างมีเหตุการณ์เลื่อนจอนับพันครั้ง */
  .ov{position:fixed;inset:0;background:rgba(45,35,65,.5);backdrop-filter:blur(4px);z-index:60;display:none;align-items:center;justify-content:center;padding:24px;overscroll-behavior:contain}
  .ov.on{display:flex}
  #ov-inv{z-index:64}#ov-cam{z-index:70}#lbox{z-index:80}
  /* หน้าต่างที่ "เปิดซ้อนบนหน้าต่างอื่น" ต้องยกลำดับชั้นให้สูงกว่า
     (element พวกนี้อยู่ก่อน ov-detail ใน DOM ถ้า z-index เท่ากันจะไปอยู่ด้านหลัง — เคยเจอมาแล้ว) */
  /* ⚠ กฎสำคัญ: หน้าต่างที่ถูกประกาศ "ก่อน" #ov-detail ใน HTML (ov-qrwarn, ov-dmss,
     ov-vault, ov-account) ถ้า z-index เท่ากันจะไปอยู่ "ด้านหลัง" หน้ารายละเอียดไซต์
     เพราะเบราว์เซอร์วางตัวที่มาทีหลังไว้บน -> ทุกตัวในกลุ่มนี้ต้องยกลำดับชั้นเสมอ
     เพิ่มหน้าต่างใหม่ตรงนั้นเมื่อไหร่ อย่าลืมใส่ id ลงบรรทัดล่างนี้ด้วย */
  #ov-qrwarn,#ov-account,#ov-dmss{z-index:76}
  #ov-vault{z-index:90}          /* ประตูรหัสทีม — ต้องอยู่บนสุดเสมอ */
  .ov.on .modal{animation:pop .19s cubic-bezier(.2,.9,.3,1.3)}
  @keyframes pop{from{transform:scale(.9);opacity:0}to{transform:scale(1);opacity:1}}
  .modal{background:#fff;border-radius:22px;box-shadow:var(--shadow);width:100%;max-width:760px;max-height:90vh;overflow:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch}
  .modal.wide{max-width:1040px}
  /* z-index ต้องสูงกว่าข้อความบนภาพกล้อง (.lcell .lt/.lb = 3) ไม่งั้นเลื่อนแล้วซ้อนแถบหัว */
  .mhead{position:sticky;top:0;background:linear-gradient(120deg,#2e3854,#414d75);color:#fff;padding:18px 22px;display:flex;align-items:center;gap:14px;z-index:20;box-shadow:0 2px 12px rgba(20,26,48,.18)}
  .mhead .av{width:48px;height:48px;border-radius:14px;background:rgba(255,255,255,.2);display:grid;place-items:center;font-size:24px}
  .mhead h2{font-size:20px}.mhead .s{opacity:.9;font-size:13px}
  /* ให้ส่วนชื่อ (ไม่ใช่ไอคอน) หดได้ + ตัด ... เพื่อคืนที่ให้ปุ่มด้านขวา (เช่น "ถ่ายใหม่") ไม่ตกบรรทัด */
  .mhead>div:not(.av){flex:1;min-width:0}
  .mhead h2,.mhead .s{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .mclose{margin-left:auto;background:rgba(255,255,255,.2);border:0;color:#fff;width:38px;height:38px;border-radius:12px;font-size:18px;cursor:pointer}
  .mbody{padding:22px 24px}
  /* หน้าต่างที่เนื้อหาเป็นรายการยาว ๆ: ทำให้มี "ตัวเลื่อนชั้นเดียว" เท่านั้น
     .modal เป็นกล่อง flex แนวตั้งที่ไม่เลื่อนเอง · .mhead ตรึงอยู่ · .mbody เลื่อน
     min-height:0 จำเป็น ไม่งั้น flex item จะไม่ยอมหดจนเกิด overflow ให้เลื่อน      */
  .modal.mfit{display:flex;flex-direction:column;overflow:hidden}
  /* overflow-x:hidden สำคัญ — พอตั้ง overflow-y:auto แกน x จะกลายเป็น auto ตามไปเอง
     ทำให้เอานิ้วลากหน้าต่างไปซ้ายขวาได้ ทั้งที่ไม่ควรเลื่อนแนวนอนเลย */
  .modal.mfit>.mbody{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;
    -webkit-overflow-scrolling:touch;overscroll-behavior:contain}
  .modal.mfit>.mhead{flex:0 0 auto}
  .cols2{display:grid;grid-template-columns:1fr 1fr;gap:16px}
  .kv{display:flex;justify-content:space-between;gap:12px;padding:11px 0;border-bottom:1px solid var(--line)}.kv:last-child{border-bottom:0}
  .kv .k{color:var(--sub);font-size:13.5px}.kv .v{font-weight:700;font-family:ui-monospace,monospace;text-align:right;word-break:break-all}
  .sec{border:1px solid var(--line);border-radius:14px;padding:16px;margin-bottom:14px}
  .sec h4{font-size:12px;color:var(--faint);text-transform:uppercase;letter-spacing:.4px;margin-bottom:10px}
  .cam{display:flex;align-items:center;gap:12px;padding:10px 0;border-bottom:1px solid var(--line)}.cam:last-child{border-bottom:0}
  .cam .ci{width:38px;height:38px;border-radius:11px;background:var(--soft);display:grid;place-items:center}
  .cam .cn{font-weight:700;font-size:14px}.cam .cm{color:var(--faint);font-size:12px}.cam .cs{margin-left:auto;font-size:12px;font-weight:700}
  .mact{display:flex;gap:10px;margin-bottom:16px;align-items:center}
  .iconbtn{width:40px;height:40px;border-radius:12px;border:1px solid var(--line);background:#fff;cursor:pointer;font-size:17px;display:grid;place-items:center;transition:.14s;flex:0 0 auto;color:var(--sub)}
  .iconbtn:hover{background:var(--soft);border-color:#dbe2ee}
  .iconbtn.del:hover{background:#fdf0f0;border-color:#f0cccc;color:var(--red)}
  .mback{border:0;background:var(--soft);width:34px;height:34px;border-radius:11px;cursor:pointer;font-size:24px;line-height:1;color:var(--sub);flex:0 0 auto;display:grid;place-items:center;padding-bottom:3px}
  .mback:hover{background:#dfe4f0;color:var(--ink)}
  .warr-ok{color:var(--green);font-weight:800}.warr-bad{color:var(--red);font-weight:800}
  .album-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}
  .album-grid img{width:100%;aspect-ratio:1;object-fit:cover;border-radius:11px;cursor:zoom-in;background:#eee}
  .album-grid .thumb{position:relative}
  .imdel{position:absolute;top:4px;right:4px;width:22px;height:22px;border-radius:50%;border:0;
    background:rgba(0,0,0,.55);color:#fff;font-size:13px;line-height:1;cursor:pointer;
    display:grid;place-items:center;padding:0}
  .imdel:hover{background:var(--red)}
  .eyebtn{border:0;background:none;padding:2px;width:26px;height:26px;border-radius:7px;cursor:pointer;color:#8a8594;display:inline-grid;place-items:center}
  .eyebtn:hover{color:var(--ink);background:var(--soft)}.eyebtn svg{display:block}
  .cam.click{cursor:pointer;border-radius:10px;padding:10px 8px}.cam.click:hover{background:var(--soft)}
  .lbox{position:fixed;inset:0;background:rgba(10,8,20,.92);z-index:80;display:none;align-items:center;justify-content:center}
  .lbox.on{display:flex}
  .lbox img{max-width:90vw;max-height:76vh;border-radius:12px;box-shadow:0 20px 60px rgba(0,0,0,.5)}
  /* แถบข้อมูลใต้ภาพ (ใช้ตอนดู snapshot รายช่อง: ชื่อกล้อง / IP / รุ่น / SN / เวลาถ่าย) */
  .lbinfo{position:absolute;bottom:46px;left:14px;right:14px;text-align:center;color:#fff;
    font-size:12.5px;line-height:1.55;text-shadow:0 1px 8px rgba(0,0,0,.9)}
  .lbinfo b{font-size:14.5px}
  .lbinfo .dim{color:rgba(255,255,255,.75)}
  .lbnav{position:absolute;top:50%;transform:translateY(-50%);background:rgba(255,255,255,.15);border:0;color:#fff;width:52px;height:52px;border-radius:50%;font-size:26px;cursor:pointer}
  .lbnav.prev{left:20px}.lbnav.next{right:20px}
  .lbclose{position:absolute;top:20px;right:24px;background:rgba(255,255,255,.15);border:0;color:#fff;width:44px;height:44px;border-radius:12px;font-size:20px;cursor:pointer}
  .lbcount{position:absolute;bottom:24px;left:0;right:0;text-align:center;color:#fff;font-size:14px}
  .lgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}
  .lcell{aspect-ratio:16/9;border-radius:14px;background:#0b0b12;position:relative;overflow:hidden;display:grid;place-items:center;color:#8ea;font-size:12px}
  .lcell iframe,.lcell video-stream{position:absolute;inset:0;width:100%;height:100%;border:0;z-index:0}
  .lcell video-stream video{width:100%;height:100%;object-fit:contain;background:#000}
  .lcell.down{background:linear-gradient(135deg,#3a1f28,#4a2733);color:#f2a}
  /* ป้ายบนภาพ: พื้นดำจาง อ่านง่ายกว่าเงาข้อความ และดูเรียบกว่า
     z-index ต้องต่ำกว่าแถบหัว modal (20) เสมอ */
  .lcell .lt{position:absolute;left:7px;top:7px;z-index:3;font-size:11px;font-weight:700;
             color:#fff;display:flex;gap:5px;align-items:center;
             background:rgba(15,20,35,.62);padding:3px 8px;border-radius:7px;
             backdrop-filter:blur(3px);max-width:calc(100% - 14px);
             white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .lcell .lb{position:absolute;left:7px;right:7px;bottom:7px;z-index:3;font-size:10.5px;
             color:#e7ebf3;background:rgba(15,20,35,.55);padding:3px 8px;border-radius:7px;
             backdrop-filter:blur(3px);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  /* ===== ดูสด multi-cam (mv) — เต็มจอ เลียนแบบ DMSS : 1/4/9/16 · double-tap · ปัดเปลี่ยนหน้า · หมุนจอ ===== */
  #ov-live{position:fixed;inset:0;background:var(--bg);z-index:70;display:none;flex-direction:column}
  #ov-live.on{display:flex}
  .mv-head{background:var(--gradA);color:#fff;padding:calc(env(safe-area-inset-top) + 12px) 14px 12px;display:flex;align-items:center;gap:10px;flex:0 0 auto}
  .mv-head .av{width:34px;height:34px;border-radius:10px;background:rgba(255,255,255,.16);display:flex;align-items:center;justify-content:center;font-size:17px}
  .mv-head h2{margin:0;font-size:15px;font-weight:800}
  .mv-head .s{font-size:11px;opacity:.82}
  .mv-head .x{margin-left:auto;background:rgba(255,255,255,.18);border:0;color:#fff;width:31px;height:31px;border-radius:10px;font-size:14px}
  /* กรอบวิดีโอเป็น 16/9 -> ทุกช่องในกริด (2x2, 3x3, 4x4) ได้สัดส่วน 16:9 เท่ากรอบเสมอ
     = ตรงกับภาพกล้อง ไม่เหลือขอบดำ (ของเดิม 1/1 ทำให้ช่องเป็นจัตุรัส ภาพ 16:9 เลยมีขอบดำบน-ล่างเยอะ) */
  #mv-varea{position:relative;background:#000;overflow:hidden;touch-action:pan-y;flex:0 0 auto;width:100%;aspect-ratio:16/9;max-height:62vh}
  body.mv-single #mv-varea{aspect-ratio:16/9;max-height:none}
  #mv-grid{display:grid;gap:2px;width:100%;height:100%;background:#000}
  .mv-cell{position:relative;background:#12151d;overflow:hidden;display:flex;align-items:center;justify-content:center}
  /* pointer-events:none = ปล่อยให้ touch ทะลุไปที่ cell/varea (ตัวเล่นดัก gesture ไว้) */
  .mv-cell video-stream,.mv-cell video,.mv-cell iframe{width:100%;height:100%;object-fit:contain;border:0;display:block;pointer-events:none}
  /* sub stream ของ Dahua = D1 (704x576) ที่บีบภาพ 16:9 เต็มเฟรมลงมา (anamorphic)
     ยืดกลับเต็มกรอบ 16:9 = ได้สัดส่วนจริงคืนมา ไม่เสียมุมภาพ (แบบเดียวกับ DMSS/SmartPSS)
     ส่วน main เป็น 16:9 อยู่แล้ว จึงใช้ contain (พอดีเป๊ะ ไม่ต้องยืด) */
  .mv-cell[data-kind="sub"] video-stream,.mv-cell[data-kind="sub"] video,
  .mv-cell[data-kind="sub"] iframe{object-fit:fill}
  /* โหมด "เต็มช่อง": ขยายภาพจนเต็มกรอบแล้วตัดขอบส่วนเกิน (สำหรับกล้องที่ไม่ใช่ 16:9 เช่น 4:3)
     ปุ่มสลับอยู่บนแถบควบคุมวิดีโอ · จำค่าไว้ใน localStorage */
  body.v-fill .mv-cell video-stream,body.v-fill .mv-cell video,body.v-fill .mv-cell iframe,
  body.v-fill #pb-video video-stream,body.v-fill #pb-video video,body.v-fill #pb-video iframe{object-fit:cover}
  /* touch-action:manipulation = ตัดดีเลย์รอ double-tap-zoom ของ Safari ออก แตะแล้วติดทันที
     44px = ขนาดเป้าแตะขั้นต่ำตามแนวทางของ Apple (เดิม 38px เล็กกว่าเกณฑ์) */
  .mv-parrow{position:absolute;top:50%;transform:translateY(-50%);width:44px;height:44px;border-radius:50%;background:rgba(0,0,0,.42);border:0;display:flex;align-items:center;justify-content:center;z-index:6;transition:opacity .35s;touch-action:manipulation;-webkit-tap-highlight-color:transparent}
  .mv-parrow svg{width:20px;height:20px;fill:#fff}
  .mv-parrow.l{left:8px}.mv-parrow.r{right:8px}
  .mv-parrow.faded{opacity:0;pointer-events:none}
  /* ***** อย่าย้ายลูกศรกลับไปชิดขอบจอในโหมดเต็มจอ *****
     iOS Safari กินการแตะที่ "ขอบซ้าย/ขวาของจอ" ไปทำ swipe back/forward ของเบราว์เซอร์
     ตอนดูปกติ #mv-varea ถูกเว้นขอบอยู่แล้ว ลูกศรที่ left:8px จึงไม่โดน
     แต่พอเต็มจอ/immersive/หมุนจอ varea กว้างเท่าจอพอดี -> ลูกศรไปนั่งในเขตนั้น = แตะไม่ติด
     (เคสจริง 7 ส.ค. 69: กดปุ่มรูปจอคอมแล้วปุ่ม < > กดไม่ได้บน iPhone)
     ต้องดันเข้ามาให้พ้นเขต + เผื่อ safe-area ของรอยบากตอนหมุนจอ
     แถบล่าง .mv-vov เผื่อ safe-area-inset-bottom ไว้แล้วด้วยเหตุผลเดียวกัน */
  body.mv-purefs .mv-parrow.l,body.mv-rot .mv-parrow.l,body.mv-land .mv-parrow.l,
  #ov-live:fullscreen .mv-parrow.l,#ov-live:-webkit-full-screen .mv-parrow.l{left:calc(env(safe-area-inset-left) + 34px)}
  body.mv-purefs .mv-parrow.r,body.mv-rot .mv-parrow.r,body.mv-land .mv-parrow.r,
  #ov-live:fullscreen .mv-parrow.r,#ov-live:-webkit-full-screen .mv-parrow.r{right:calc(env(safe-area-inset-right) + 34px)}
  .mv-cell .cn{position:absolute;left:6px;top:5px;z-index:2;font-size:10px;font-weight:800;color:#eef1f8;text-shadow:0 1px 3px rgba(0,0,0,.7)}
  .mv-cell .ph{color:#46506a;font-size:11px}
  .mv-cell.empty{background:#0e1119}
  .mv-vov{position:absolute;left:0;right:0;bottom:0;display:flex;align-items:center;gap:14px;padding:8px 12px calc(env(safe-area-inset-bottom) + 8px);background:linear-gradient(0deg,rgba(0,0,0,.55),transparent);z-index:3}
  .mv-vov button{background:transparent;border:0;color:#fff;font-size:13px;font-weight:800;display:flex;align-items:center;gap:5px;text-shadow:0 1px 3px rgba(0,0,0,.6)}
  .mv-vov button svg{width:22px;height:22px;fill:#fff;filter:drop-shadow(0 1px 3px rgba(0,0,0,.6))}
  .mv-pdots{position:absolute;left:50%;top:9px;transform:translateX(-50%);display:flex;gap:5px;z-index:3}
  .mv-pdots i{width:6px;height:6px;border-radius:50%;background:rgba(255,255,255,.45)}
  .mv-pdots i.on{background:#fff;width:15px;border-radius:4px}
  /* แผงวินิจฉัยการเชื่อมต่อ — ใช้ตอบว่า "ภาพกระตุกเพราะอะไร" ด้วยตัวเลขจริง
     ไม่ใช่การเดา: บอกว่าใช้ WebRTC หรือ MSE, วิ่งผ่าน UDP หรือ TCP, บิตเรต,
     แพ็กเก็ตหาย, เฟรมที่ค้าง — ตัวเลขพวกนี้ชี้ต้นเหตุได้ทันทีว่าอยู่ที่เน็ตหรือที่เครื่อง */
  .mv-netbox{position:absolute;top:10px;left:10px;z-index:8;max-width:min(88%,340px);
    background:rgba(10,14,28,.82);color:#e8edf8;font-size:11.5px;line-height:1.65;
    padding:9px 11px;border-radius:11px;backdrop-filter:blur(6px);
    font-variant-numeric:tabular-nums;white-space:pre-wrap;pointer-events:none}
  .mv-netbox b{color:#fff}
  .mv-netbox .bad{color:#ff8f8f}
  .mv-netbox .warn{color:#ffce6b}
  .mv-netbox .ok{color:#7ee08a}
  .mv-hint{position:absolute;left:50%;bottom:50px;transform:translateX(-50%);background:rgba(0,0,0,.5);color:#fff;font-size:11px;padding:5px 12px;border-radius:20px;z-index:3;pointer-events:none;transition:.3s;opacity:.9;text-align:center;max-width:88%}
  .mv-lctrl{background:#fff;border-top:1px solid var(--line);padding:11px 13px calc(env(safe-area-inset-bottom) + 11px);display:flex;align-items:center;gap:10px;flex:0 0 auto}
  .mv-laybar{display:flex;gap:6px}
  .mv-lay{width:36px;height:36px;border:1px solid var(--line);background:#fff;border-radius:10px;display:grid;gap:2px;padding:6px;box-shadow:var(--shadow-sm)}
  .mv-lay.on{border-color:var(--pri);background:#eef1fb;box-shadow:0 0 0 2px rgba(61,74,114,.14)}
  .mv-lay i{background:#b9c2d8;border-radius:2px}
  .mv-lay.on i{background:var(--pri)}
  .mv-lay.l1{grid-template:1fr/1fr}.mv-lay.l4{grid-template:repeat(2,1fr)/repeat(2,1fr)}
  .mv-lay.l9{grid-template:repeat(3,1fr)/repeat(3,1fr)}.mv-lay.l16{grid-template:repeat(4,1fr)/repeat(4,1fr)}
  .mv-cbtn{background:#fff;border:1px solid var(--line);color:var(--pri);border-radius:10px;padding:8px 12px;font-size:12px;font-weight:800;box-shadow:var(--shadow-sm)}
  .mv-cbtn.on{background:var(--pri);border-color:var(--pri);color:#fff}
  /* หมุนแนวนอน (CSS-rotate) — กล่อง 100vh×100vw หมุน 90° จากกึ่งกลาง = เต็มจอพอดี */
  body.mv-rot{overflow:hidden}
  body.mv-rot #ov-live{position:fixed;top:50%;left:50%;width:100vh;height:100vw;transform:translate(-50%,-50%) rotate(90deg)}
  body.mv-rot #mv-varea{flex:1 1 auto;max-height:none!important;aspect-ratio:auto!important}
  /* หมุนแล้ว = เหลือแต่วิดีโอ + overlay คุมค่า (ซ่อนหัว/แถบเลย์เอาต์ ไม่ให้ทับกัน) */
  body.mv-rot .mv-head,body.mv-rot .mv-lctrl{display:none}
  /* บนคอม/จอกว้าง — varea ยืดเต็มพื้นที่ที่เหลือ (ใช้พื้นที่เต็มจอ) */
  @media(min-width:760px){#mv-varea{flex:1 1 auto;width:100%;max-width:none;max-height:none;aspect-ratio:auto}}
  /* เต็มจอจริง (native fullscreen) — วิดีโอเต็มหน้าจอแบบ YouTube: ซ่อนหัว, varea ยืดเต็ม */
  #ov-live:fullscreen,#ov-live:-webkit-full-screen{background:#000}
  /* เต็มจอ = เหลือแต่วิดีโอ + overlay คุมค่า (ซ่อนหัว/แถบเลย์เอาต์/แท็บ ไม่ให้ของเว็บปน/ทับกัน) */
  #ov-live:fullscreen .mv-head,#ov-live:-webkit-full-screen .mv-head,
  #ov-live:fullscreen .mv-lctrl,#ov-live:-webkit-full-screen .mv-lctrl{display:none}
  #ov-live:fullscreen #mv-varea,#ov-live:-webkit-full-screen #mv-varea{flex:1 1 auto;width:100%;max-width:none;max-height:none;aspect-ratio:auto}
  /* iOS: เต็มจอในโหมดหมุน (ล็อก orientation จริงไม่ได้) = ซ่อน chrome ให้วิดีโอเต็มตามแนวที่หมุนอยู่ */
  body.mv-purefs .mv-head,body.mv-purefs .mv-lctrl{display:none}
  body.mv-purefs #mv-varea{flex:1 1 auto;width:100%;max-width:none;max-height:none;aspect-ratio:auto}
  /* หมุนเครื่องจริง (physical landscape) -> เต็มจอแนวนอนตามที่ OS หมุนให้ (ไม่ transform = ทิศถูกเสมอ) + โชว์ overlay คุมค่า */
  body.mv-land{overflow:hidden}
  body.mv-land .mv-head,body.mv-land .mv-lctrl{display:none}
  body.mv-land #mv-varea{flex:1 1 auto;width:100%;max-width:none;max-height:none;aspect-ratio:auto}
  /* ===== ดูย้อนหลัง (pb) — เต็มจอ เลียนแบบ DMSS: timeline ซูมได้ + ปฏิทินจุด + overlay controls ===== */
  #ov-pb{position:fixed;inset:0;background:var(--bg);z-index:70;display:none;flex-direction:column}
  #ov-pb.on{display:flex}
  .pb-head{background:var(--gradA);color:#fff;padding:calc(env(safe-area-inset-top) + 12px) 14px 12px;display:flex;align-items:center;gap:11px;flex:0 0 auto}
  .pb-head .av{width:34px;height:34px;border-radius:10px;background:rgba(255,255,255,.16);display:flex;align-items:center;justify-content:center;font-size:17px}
  .pb-head h2{margin:0;font-size:15px;font-weight:800}
  .pb-head .s{font-size:11px;opacity:.82}
  .pb-head .x{margin-left:auto;background:rgba(255,255,255,.18);border:0;color:#fff;width:31px;height:31px;border-radius:10px;font-size:14px}
  #pb-scroll{flex:1 1 auto;overflow:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch}
  #pb-video{position:relative;background:#0b0d14;aspect-ratio:16/9;overflow:hidden;width:100%}
  #pb-video video-stream,#pb-video video,#pb-video iframe{width:100%;height:100%;object-fit:contain;border:0;display:block;pointer-events:none}
  .pb-vcenter{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#5a647d;font-size:12.5px;text-align:center;line-height:1.7;padding:20px}
  .pb-vts{position:absolute;right:11px;top:9px;color:#eef1f8;font-size:10.5px;font-weight:600;font-variant-numeric:tabular-nums;text-shadow:0 1px 3px rgba(0,0,0,.7);z-index:3}
  .pb-camname{position:absolute;left:12px;bottom:34px;color:#eef1f8;font-size:11px;font-weight:800;text-shadow:0 1px 3px rgba(0,0,0,.7);z-index:3}
  .pb-ovc-c{position:absolute;left:50%;top:48%;transform:translate(-50%,-50%);display:flex;align-items:center;gap:30px;z-index:3;transition:opacity .3s}
  .pb-ovc-bottom,.pb-camname{transition:opacity .35s}
  /* overlay ควบคุมจาง/โผล่ตามการแตะ (ซ่อนเองใน 3 วิ) */
  #pb-video.pb-hidec .pb-ovc-c,#pb-video.pb-hidec .pb-ovc-bottom,#pb-video.pb-hidec .pb-camname{opacity:0;pointer-events:none}
  .pb-ovc-skip{position:relative;background:transparent;border:0;width:44px;height:44px;display:flex;align-items:center;justify-content:center}
  .pb-ovc-skip svg{width:36px;height:36px;fill:#fff;filter:drop-shadow(0 1px 3px rgba(0,0,0,.5))}
  .pb-ovc-skip em{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:9px;font-weight:800;font-style:normal;color:#fff;margin-top:2px}
  .pb-ovc-play{background:transparent;border:0;width:52px;height:52px;display:flex;align-items:center;justify-content:center}
  .pb-ovc-play svg{width:42px;height:42px;fill:#fff;filter:drop-shadow(0 1px 4px rgba(0,0,0,.5))}
  .pb-ovc-bottom{position:absolute;left:0;right:0;bottom:8px;display:flex;align-items:center;gap:16px;padding:0 13px;z-index:3}
  .pb-ovc-b{background:transparent;border:0;color:#fff;display:flex;align-items:center;gap:5px;font-size:13px;font-weight:800;text-shadow:0 1px 3px rgba(0,0,0,.5)}
  .pb-ovc-b svg{width:22px;height:22px;fill:#fff;filter:drop-shadow(0 1px 3px rgba(0,0,0,.5))}
  .pb-body{padding:12px 13px 22px;max-width:760px;margin:0 auto}
  .pb-toolbar{display:flex;background:#fff;border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow-sm);padding:5px;margin-bottom:12px}
  .pb-toolbar button{flex:1;border:0;background:transparent;padding:11px 0;display:flex;align-items:center;justify-content:center;color:var(--pri)}
  .pb-toolbar button svg{width:21px;height:21px;fill:currentColor}
  .pb-toolbar button.cut{color:var(--red)}
  .pb-daterow{display:flex;align-items:center;gap:9px;margin-bottom:12px}
  .pb-datechip{display:flex;align-items:center;background:#fff;border:1px solid var(--line);border-radius:11px;box-shadow:var(--shadow-sm);overflow:hidden;flex:0 0 auto}
  .pb-datechip .dnav{border:0;background:transparent;color:var(--pri);font-size:16px;padding:8px 12px;font-weight:800}
  .pb-datechip .dv{font-size:13.5px;font-weight:800;padding:6px 6px;min-width:96px;text-align:center;cursor:pointer}
  .pb-dicon{border:1px solid var(--line);background:#fff;border-radius:11px;width:38px;height:38px;display:flex;align-items:center;justify-content:center;box-shadow:var(--shadow-sm);color:var(--pri)}
  .pb-chdrop{margin-left:auto;border:1px solid var(--line);background:#fff;border-radius:11px;padding:9px 12px;font-size:12.5px;font-weight:800;color:var(--pri);box-shadow:var(--shadow-sm)}
  /* ช่องยาวเกิน = ตัดชื่อช่องให้แคบลง (ellipsis) ไม่ให้ไปดันวันที่ */
  #pb-chsel{flex:0 1 auto;max-width:44%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .pb-daterow{min-width:0}
  .pb-now{text-align:center;margin:2px 0 9px}
  .pb-now b{display:inline-block;background:#fff;border:1px solid var(--line);border-radius:20px;padding:6px 16px;font-size:15px;font-weight:800;font-variant-numeric:tabular-nums;color:var(--ink);box-shadow:var(--shadow-sm)}
  .pb-tlcard{background:#fff;border:1px solid var(--line);border-radius:15px;padding:12px;margin-bottom:13px;box-shadow:var(--shadow-sm)}
  #pb-tl{width:100%;height:76px;display:block;border-radius:10px;background:#e9edf5;touch-action:none;cursor:ew-resize}
  .pb-zoomrow{display:flex;align-items:center;gap:7px;margin-top:10px}
  .pb-zoomrow .zt{font-size:11px;color:var(--faint)}
  .pb-zchips{display:flex;gap:5px;margin-left:auto}
  .pb-zc{border:1px solid var(--line);background:#fff;font-size:11px;font-weight:800;color:var(--sub);padding:5px 10px;border-radius:9px}
  .pb-zc.on{background:var(--pri);color:#fff;border-color:var(--pri)}
  .pb-hint{text-align:center;font-size:10.5px;color:var(--faint);margin-top:8px;line-height:1.5}
  .pb-cut{background:#fff;border:1px solid var(--line);border-radius:16px;box-shadow:var(--shadow-sm);padding:13px 14px;margin-bottom:12px}
  .pb-cut b.h{font-size:14px}
  .pb-cut .row{display:flex;align-items:center;gap:9px;margin:11px 0 0}
  .pb-cut .row .lb{font-size:12px;color:var(--sub);font-weight:700;flex:0 0 auto;min-width:34px}
  .pb-split{font-size:11px;color:var(--yellow);background:rgba(192,138,42,.1);border:1px solid rgba(192,138,42,.3);border-radius:10px;padding:8px 11px;margin-top:10px;line-height:1.6}
  .pb-split.bad{color:var(--red);background:rgba(201,74,74,.1);border-color:rgba(201,74,74,.35)}
  /* ***** ช่องเลือกเวลาตัดคลิป — อย่าเปลี่ยนกลับไปเป็น datetime-local *****
     <input type="datetime-local" step="1"> ใช้ไม่ได้กับงานนี้:
       • iOS ไม่มีวงล้อ "วินาที" ให้เลือกเลย (step=1 ไม่มีผลกับวงล้อของ Safari)
         = ตัดคลิปให้ตรงวินาทีบนมือถือไม่ได้ ซึ่งเป็นเครื่องที่ใช้งานจริงมากที่สุด
       • บนคอมต้องพิมพ์ตัวเลขเอง ช้าและพิมพ์ผิดง่าย
     และอย่าแยกเป็น dropdown หลายช่องด้วย — เคยลองแล้ว กดทีละช่องเสียจังหวะ
     ของจริงคือ "แผ่นเดียว" กดปุ่มขึ้นมาแล้วเลือกวันจากปฏิทิน + หมุนเลข ชม./นาที/วินาที
     ในหน้าเดียวจบ เหมือนตัวเลือกเวลาของ iOS แต่เพิ่มวินาทีเข้ามา (ดู #pb-tp) */
  .pb-cut .tbtn{flex:1;min-width:0;display:flex;align-items:center;gap:9px;
    border:1px solid var(--line);border-radius:11px;background:#fff;color:var(--ink);
    font-family:inherit;font-size:14.5px;font-weight:800;padding:9px 12px;min-height:42px;
    text-align:left;cursor:pointer}
  .pb-cut .tbtn:hover{border-color:#c9d2e4}
  .pb-cut .tbtn .dt{color:var(--sub);font-weight:700;font-size:13px}
  .pb-cut .tbtn .tm{font-variant-numeric:tabular-nums;letter-spacing:.3px}
  .pb-cut .tbtn .cv{margin-left:auto;color:var(--faint);font-size:12px}

  /* ---- แผ่นเลือกวัน+เวลา (ปฏิทิน + วงล้อ ชม./นาที/วินาที) ---- */
  #pb-tp{position:fixed;inset:0;background:rgba(20,26,45,.55);z-index:82;display:none;
    align-items:flex-end;justify-content:center}
  #pb-tp.on{display:flex}
  /* แผ่นนี้ต้องเลื่อนได้แค่แนวตั้ง — ไม่งั้นเอานิ้วดันแล้วทั้งแผ่นไถลซ้าย/ขวาได้
     ทั้งที่ไม่มีอะไรให้ดูทางนั้น (overflow:auto เดิมเปิดทั้งสองแกน) */
  #pb-tp .pb-calbox{max-height:94vh;overflow-y:auto;overflow-x:hidden;
    overscroll-behavior:contain;touch-action:pan-y}
  .tp-title{display:flex;align-items:baseline;gap:10px;padding:6px 2px 2px}
  .tp-title b{font-size:15px}
  .tp-title span{margin-left:auto;font-size:13.5px;font-weight:800;color:var(--pri);
    font-variant-numeric:tabular-nums}
  .tp-sec{margin-top:12px;border-top:1px solid var(--line);padding-top:10px}
  .tp-lbl{display:flex;gap:8px;justify-content:center}
  .tp-lbl span{flex:1;max-width:96px;text-align:center;font-size:11px;font-weight:700;color:var(--faint)}
  /* วงล้อ: ใช้ scroll-snap ของเบราว์เซอร์ ไม่เขียน physics เอง
     -> ได้แรงเฉื่อยแบบเนทีฟบน iOS และล้อเมาส์ใช้ได้บนคอม โดยไม่ต้องมีโค้ดแยกสองทาง */
  .tp-wheels{position:relative;display:flex;gap:8px;justify-content:center;margin-top:4px;
    touch-action:pan-y}
  .tp-band{position:absolute;left:0;right:0;top:calc(50% - 19px);height:38px;border-radius:11px;
    background:var(--soft);border:1px solid var(--line);pointer-events:none;z-index:0}
  /* touch-action:pan-y = นิ้วบนวงล้อทำได้อย่างเดียวคือเลื่อนขึ้น-ลง
     ตัดการไถลซ้าย/ขวา และตัด swipe-back ของเบราว์เซอร์ที่เผลอไปโดนตอนดันนิ้วเฉียง
     overflow-x:hidden ซ้ำอีกชั้น เผื่อเบราว์เซอร์ที่ยังไม่รู้จัก touch-action */
  .tp-w{position:relative;z-index:1;flex:1;max-width:96px;height:190px;
    overflow-y:auto;overflow-x:hidden;touch-action:pan-y;
    scroll-snap-type:y mandatory;-webkit-overflow-scrolling:touch;
    scrollbar-width:none;-ms-overflow-style:none;text-align:center;overscroll-behavior:contain}
  .tp-w::-webkit-scrollbar{display:none}
  /* ตัวเว้นหัว/ท้ายวงล้อ = (ความสูงวงล้อ - ความสูงบรรทัด)/2 เพื่อให้เลือกได้ถึงตัวแรก/ตัวสุดท้าย
     ค่าที่นี่เป็นแค่ค่าตั้งต้นกันกระตุก — ของจริง JS คำนวณให้ตอนเปิดแผ่น (pbTpFit)
     เคยเขียนตายตัวไว้ทั้ง CSS และ JS แล้วพอมี @media เปลี่ยนความสูงวงล้อ
     สองที่หลุดจากกัน ตัวเลขที่เลือกเลยไม่ตรงกลางแถบ — อย่ากลับไปผูกค่าตายอีก */
  .tp-w .sp{height:76px}
  .tp-w b{display:block;height:38px;line-height:38px;scroll-snap-align:center;
    font-size:19px;font-weight:700;color:var(--faint);font-variant-numeric:tabular-nums;
    transition:color .1s,font-size .1s;cursor:pointer;overflow:hidden}
  /* เน้นเลขที่เลือกด้วยขนาดตัวอักษร ไม่ใช่ transform:scale
     scale ทำให้กล่องกว้างเกินคอลัมน์ -> เกิดพื้นที่เลื่อนแนวนอน 7px ค้างอยู่
     ซึ่งคือต้นเหตุที่เอานิ้วดันแล้ววงล้อไถลซ้าย/ขวาได้ (ความสูงบรรทัดคงที่ 38px จึงไม่กระทบตำแหน่ง) */
  .tp-w b.on{color:var(--ink);font-weight:800;font-size:23px}
  /* ปุ่มตกลง/ยกเลิกต้องเห็นเสมอ — แผ่นนี้มีทั้งปฏิทินและวงล้อ บนจอเตี้ยจะยาวเกินจอ
     ถ้าไม่ปักไว้ล่าง ผู้ใช้ต้องเลื่อนลงไปหาปุ่มยืนยัน ซึ่งคือปุ่มที่ต้องกดทุกครั้ง */
  .tp-acts{position:sticky;bottom:0;display:flex;gap:9px;margin-top:10px;padding:10px 0 2px;
    background:#fff;box-shadow:0 -8px 10px -8px rgba(20,26,45,.18)}
  .tp-acts .btn{flex:1}
  /* ช่องวันในแผ่นนี้เตี้ยกว่าปฏิทินหลัก (ไม่บังคับจัตุรัส) เพราะต้องแบ่งที่ให้วงล้อด้วย */
  #pb-tp .pb-cal-d{aspect-ratio:auto;padding:6px 0;min-height:34px}
  #pb-tp .pb-cal-legend{margin-top:9px}
  @media(max-height:740px){.tp-w{height:152px}
    #pb-tp .pb-cal-d{padding:3px 0;min-height:29px;font-size:12px}}
  .pb-jobs{margin-top:10px}
  .pb-job{border:1px solid var(--line);border-radius:11px;padding:9px 11px;margin-top:8px;font-size:12px;background:var(--soft)}
  .pb-job .jf{display:flex;gap:8px;align-items:center;padding:3px 0;border-top:1px solid var(--line);margin-top:5px}
  .pb-job a{color:var(--pri);font-weight:800;text-decoration:none}
  /* calendar popup */
  #pb-cal{position:fixed;inset:0;background:rgba(20,26,45,.55);z-index:80;display:none;align-items:flex-end;justify-content:center}
  #pb-cal.on{display:flex}
  .pb-calbox{background:#fff;border-radius:20px 20px 0 0;width:100%;max-width:440px;padding:8px 15px calc(env(safe-area-inset-bottom) + 18px);box-shadow:0 -8px 24px rgba(20,26,45,.2)}
  .pb-cal-h{display:flex;align-items:center;justify-content:space-between;margin:10px 0}
  .pb-cal-h b{font-size:14px}
  .pb-cal-nav{border:0;background:var(--soft);width:32px;height:32px;border-radius:9px;color:var(--pri);font-size:16px}
  .pb-cal-w{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;font-size:10.5px;color:var(--faint);text-align:center;margin-bottom:5px}
  .pb-cal-g{display:grid;grid-template-columns:repeat(7,1fr);gap:3px}
  .pb-cal-d{aspect-ratio:1;border-radius:9px;display:flex;flex-direction:column;align-items:center;justify-content:center;font-size:12.5px;font-weight:600;color:var(--ink);background:var(--soft)}
  .pb-cal-d.mut{color:var(--faint);opacity:.4;background:transparent}
  .pb-cal-d .rec{width:5px;height:5px;border-radius:50%;background:var(--green);margin-top:3px}
  .pb-cal-d.sel{background:var(--pri);color:#fff}
  .pb-cal-d.sel .rec{background:#fff}
  .pb-cal-legend{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--sub);margin-top:12px}
  .pb-cal-legend .rec{width:6px;height:6px;border-radius:50%;background:var(--green);display:inline-block}
  /* rotate/fullscreen (ใช้ซ้ำแนวเดียวกับดูสด) */
  body.pb-rot{overflow:hidden}
  body.pb-rot #ov-pb{position:fixed;top:50%;left:50%;width:100vh;height:100vw;transform:translate(-50%,-50%) rotate(90deg)}
  body.pb-rot #pb-scroll{overflow:hidden}
  body.pb-rot #pb-video{aspect-ratio:auto;height:100%}
  body.pb-rot .pb-head,body.pb-rot .pb-body{display:none}
  body.pb-purefs .pb-head,body.pb-purefs .pb-body{display:none}
  body.pb-purefs #pb-video{aspect-ratio:auto;height:100%}
  body.pb-purefs #pb-scroll{overflow:hidden;display:flex}
  /* หมุนเครื่องจริง (physical landscape) สำหรับย้อนหลัง */
  body.pb-land{overflow:hidden}
  body.pb-land .pb-head,body.pb-land .pb-body{display:none}
  body.pb-land #pb-video{aspect-ratio:auto;height:100%}
  body.pb-land #pb-scroll{overflow:hidden;display:flex}
  #ov-pb:fullscreen,#ov-pb:-webkit-full-screen{background:#000}
  #ov-pb:fullscreen .pb-head,#ov-pb:fullscreen .pb-body,#ov-pb:-webkit-full-screen .pb-head,#ov-pb:-webkit-full-screen .pb-body{display:none}
  #ov-pb:fullscreen #pb-scroll,#ov-pb:-webkit-full-screen #pb-scroll{display:flex;overflow:hidden}
  #ov-pb:fullscreen #pb-video,#ov-pb:-webkit-full-screen #pb-video{aspect-ratio:auto;flex:1 1 auto;height:100%}
  /* ===== แท็บล่างร่วม ดูสด | ดูย้อนหลัง (รวมเป็นหน้าเดียวแบบ DMSS) ===== */
  .cam-tabs{display:flex;background:#fff;border-top:1px solid var(--line);flex:0 0 auto;padding-bottom:env(safe-area-inset-bottom);box-shadow:0 -2px 10px rgba(34,42,68,.05)}
  .cam-tabs button{flex:1;border:0;background:transparent;color:var(--sub);font-size:13px;font-weight:800;padding:12px 0 13px;position:relative}
  .cam-tabs button.on{color:var(--pri)}
  .cam-tabs button.on::after{content:"";position:absolute;left:50%;bottom:6px;transform:translateX(-50%);width:26px;height:3px;border-radius:2px;background:var(--pri)}
  /* หมุนจอ/เต็มจอ = ซ่อนแท็บ ให้วิดีโอเต็ม */
  body.mv-rot .cam-tabs,body.mv-purefs .cam-tabs,body.pb-rot .cam-tabs,body.pb-purefs .cam-tabs,body.mv-land .cam-tabs,body.pb-land .cam-tabs{display:none}
  #ov-live:fullscreen .cam-tabs,#ov-live:-webkit-full-screen .cam-tabs,#ov-pb:fullscreen .cam-tabs,#ov-pb:-webkit-full-screen .cam-tabs{display:none}
  .field{margin-bottom:12px}.field label{font-size:13px;color:var(--sub);font-weight:700;display:block;margin-bottom:5px}
  .field input,.field select,.field textarea{width:100%;border:1px solid var(--line);border-radius:12px;padding:11px;font-size:15px;font-family:inherit}
  /* ช่อง input ที่มีปุ่มสแกนกล้องต่อท้าย */
  .inputbtn{display:flex;gap:8px}.inputbtn input{flex:1;min-width:0}
  .scanbtn{flex:0 0 auto;width:46px;border:1px solid var(--line);border-radius:12px;background:var(--soft);
    font-size:19px;line-height:1;cursor:pointer;display:grid;place-items:center;transition:background .15s,border-color .15s}
  .scanbtn:hover{background:rgba(139,92,246,.08);border-color:var(--pri)}
  .row2f{display:flex;gap:10px}.row2f>*{flex:1}
  /* auto-refresh: อัปเดตเฉพาะชิ้นที่เปลี่ยน + ไฮไลต์นุ่ม ๆ (ไม่กระตุก ไม่เด้ง scroll) */
  @keyframes fxUpd{0%{background:rgba(139,92,246,.16)}100%{background:transparent}}
  @keyframes fxIn{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
  @keyframes fxOut{to{opacity:0;transform:scale(.97)}}
  @keyframes fxNum{0%{color:var(--pri,#8b5cf6);transform:scale(1.12)}100%{color:inherit;transform:none}}
  .fx-upd{animation:fxUpd 1.5s ease-out}
  .fx-in{animation:fxIn .32s ease-out}
  .fx-out{animation:fxOut .24s ease-in forwards;pointer-events:none}
  .fx-num{animation:fxNum 1s ease-out;display:inline-block}
  @media(prefers-reduced-motion:reduce){.fx-upd,.fx-in,.fx-out,.fx-num{animation:none}}
  .live-dot{width:7px;height:7px;border-radius:99px;background:var(--green);display:inline-block;margin-right:6px;animation:pulse 2s infinite}
  /* ตัวหมุนบอกว่ากำลังทำงานอยู่ (ใช้ตอนสั่งสร้างบัญชีที่ NVR ซึ่งใช้เวลาหลายสิบวินาที) */
  .spin{width:16px;height:16px;flex:0 0 auto;border-radius:50%;border:2px solid var(--line);
        border-top-color:var(--pri);display:inline-block;animation:spin .8s linear infinite}
  @keyframes spin{to{transform:rotate(360deg)}}
  /* แถบสถานะบริการฝั่ง Agent */
  .svcbar{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px}
  .svc{display:flex;align-items:center;gap:7px;padding:7px 12px;border:1px solid var(--line);
       border-radius:10px;background:var(--card);font-size:12.5px;white-space:nowrap}
  .svc i{width:8px;height:8px;border-radius:99px;flex:none;background:var(--sub)}
  .svc.up i{background:var(--green)}
  .svc.down i{background:var(--red)}
  .svc.down{border-color:var(--red);background:color-mix(in srgb,var(--red) 7%,var(--card))}
  .svc b{font-weight:600}
  .svc small{color:var(--sub)}
  @keyframes pulse{0%,100%{opacity:1}50%{opacity:.25}}
  .toast{position:fixed;left:50%;bottom:26px;transform:translateX(-50%) translateY(60px);background:#2b2740;color:#fff;padding:12px 20px;border-radius:14px;font-size:14px;z-index:250;opacity:0;transition:.3s;max-width:90%}
  .toast.on{opacity:1;transform:translateX(-50%)}.toast.err{background:#c0304f}
  @media(max-width:820px){
    .shell{flex-direction:column}
    /* แถบเมนูล่างมือถือ: ทุกปุ่มกว้างเท่ากัน (flex:1) กระจายเต็มความกว้าง กึ่งกลางเป๊ะ
       ปุ่มที่เลือกใช้ "เปลี่ยนสี" แทนกล่องทึบใหญ่ ๆ (เดิมทำให้ดูเอียง ไม่สมส่วน) */
    .sidebar{width:100%;height:auto;position:fixed;bottom:0;top:auto;flex-direction:row;
      padding:6px 4px calc(4px + env(safe-area-inset-bottom));border-right:0;border-top:1px solid var(--line);z-index:40}
    .logo-row,.side-user,.sidebar .copyfoot{display:none}
    .acctbtn{display:grid;place-items:center;position:fixed;top:9px;right:12px;z-index:45;
      width:38px;height:38px;border-radius:50%;background:var(--gradA);color:#fff;font-weight:800;font-size:15px;border:0;box-shadow:var(--shadow-sm);cursor:pointer}
    .page-head{padding-right:46px}   /* เว้นที่ให้ปุ่มบัญชีมุมขวาบน ไม่ให้ทับหัวข้อ */
    .nav{display:flex;gap:0;width:100%}
    .nav a{position:relative;flex:1;min-width:0;flex-direction:column;justify-content:center;align-items:center;
      gap:3px;font-size:10px;font-weight:700;padding:7px 2px 5px;margin:0;min-height:52px;line-height:1.1;border-radius:14px}
    .nav a .ic{font-size:23px;width:auto;line-height:1}
    .nav a .lb{width:100%;height:23px;display:flex;align-items:center;justify-content:center;text-align:center}
    /* ปุ่มที่เลือกอยู่: พื้นหลังไฮไลต์ + ตัวอักษรสีหลัก + แถบเล็กด้านบน = เห็นชัดว่าเลือกอันไหน */
    .nav a.on{background:rgba(61,74,114,.13);color:var(--pri);font-weight:800}
    .nav a.on .ic{transform:scale(1.08)}
    .nav a.on::before{content:"";position:absolute;top:3px;left:50%;transform:translateX(-50%);
      width:26px;height:3px;border-radius:99px;background:var(--pri)}
    main{padding:18px 16px 90px}
    .kpirow{grid-template-columns:1fr 1fr}.kpi.avail{grid-column:span 2}
    .mon-cols,.cols2,.lgrid,.inv-grid,.mon-cols2,.admin-grid,.adcols{grid-template-columns:1fr}
    .hero{grid-template-columns:1fr 1fr;gap:12px}
    .hero .hero-main{grid-column:span 2}
    .hcard{min-height:0;padding:14px}
    .hcard .hnum{font-size:24px}
    .heat .ht{min-width:calc(50% - 4px);width:auto!important;flex:1 1 calc(50% - 4px)}
    .hbar .nm{width:110px;font-size:12px}.hbar .vl{width:64px;font-size:11.5px}
    /* ปุ่มในหน้าข้อมูลไซต์: แถวเดียว ไม่ตัดคำ ไม่ล้น */
    .mact{gap:8px;flex-wrap:wrap}
    /* ปุ่มหลัก (ดูสด/ภาพ snapshot) อยู่บรรทัดแรก แสดงข้อความเต็มไม่ตัดคำ */
    .mact .btn{flex:1 1 auto;min-width:0;padding:11px 8px;font-size:13px;white-space:nowrap}
    /* spacer เต็มบรรทัด (ห้ามหด) ดันปุ่มแก้ไข/ลบ ลงบรรทัดใหม่ แล้วชิดขวา */
    .mact .spacer{flex:0 0 100%;height:0;margin:0;display:block}
    .mact .spacer+.iconbtn{margin-left:auto}
    .mact .iconbtn{width:42px;height:42px;flex:0 0 42px}
    /* หัว modal บนจอแคบ: ชื่อไซต์ยาวไม่ดันปุ่มตก */
    .mhead{padding:14px 16px;gap:10px}
    .mhead h2{font-size:16px;line-height:1.25}
    .mhead .s{font-size:11px}
    .mhead .av{width:38px;height:38px;font-size:18px;flex:0 0 38px}
    .chipbar{gap:6px}.chip{padding:6px 10px;font-size:11px}
    .kpi{padding:14px;gap:11px;min-height:74px}.kico{width:42px;height:42px;min-width:42px;flex:0 0 42px;font-size:19px}
    .kpi b{font-size:23px}.kpi span{font-size:11.5px}
    .kpi.avail{gap:12px}.ring{width:66px;height:66px}.ring i{width:50px;height:50px;font-size:15px}
    .album-grid{grid-template-columns:repeat(3,1fr)}
    /* iOS/Safari: backdrop-filter บนพื้นที่เต็มจอ ต้อง rasterize การ์ดทั้งหน้าใหม่ทุกเฟรม
       -> เปิด/ปิด modal หน่วงมาก บนมือถือจึงใช้พื้นหลังทึบแทน (ไม่เบลอ) เร็วขึ้นชัดเจน */
    .ov{padding:14px;backdrop-filter:none;-webkit-backdrop-filter:none;background:rgba(45,35,65,.62)}
    .ov.on .modal{animation:none}         /* ตัดอนิเมชันบนมือถือ — คอมโพสิตซ้ำโดยไม่จำเป็น */
    .modal{max-width:100%;max-height:92vh;border-radius:22px}
    .row2f{flex-direction:column;gap:14px}
    .panel{overflow-x:auto;-webkit-overflow-scrolling:touch}
    .panel table{min-width:460px}
    th,td{padding:9px 8px;font-size:12.5px}
  }
  /* ตารางสถานะกล้องรายช่อง (Image QC) ในหน้ารายละเอียดไซต์ */
  .chtbl{display:flex;flex-direction:column}
  .chrow{display:flex;align-items:center;gap:10px;padding:10px 8px;border-bottom:1px solid var(--line);cursor:pointer;border-radius:8px}
  .chrow:last-child{border-bottom:0}.chrow:hover{background:var(--soft)}
  .chrow .cnm{flex:1;min-width:0}.chrow .cnm b{font-weight:800}
  .chrow .cnm .sub{font-size:11px;color:var(--faint)}
  .chrow .cnm .rsn{font-size:11px;margin-top:1px}
  /* ชิปการเชื่อมต่อ + บรรทัดเตือนบนการ์ดไซต์ */
  .cchip{font-size:10.5px;font-weight:800;padding:2px 10px;border-radius:99px;letter-spacing:.2px}
  /* สีแยกตามประเภทการเชื่อมต่อ (โทนเย็น ไม่ชนกับสีสถานะ เขียว/เหลือง/แดง) */
  .cchip.cc-p2p{background:#e7edfb;color:#3a56b0}       /* P2P — น้ำเงิน */
  .cchip.cc-direct{background:#efe7f8;color:#7048a8}    /* Direct — ม่วง */
  .cchip.cc-cgi{background:#ddeef1;color:#227e8a}       /* CGI — เขียวอมฟ้า */
  .cchip.cc-sdk{background:#f0e8dd;color:#8a6b3a}       /* SDK — น้ำตาลทอง */
  .cwarn{margin-top:9px;font-size:11.5px;color:var(--red);font-weight:600}
  /* เตือนระดับรอง (เวลาไม่ตรง / NTP ปิด) — เหลือง เพื่อไม่ให้ดูเท่ากับ 'ออฟไลน์' */
  .cwarn .w2{color:var(--yellow)}
  /* หน้าภาพรวม */
  .ov-kpi{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:20px}
  @media(max-width:820px){.ov-kpi{grid-template-columns:repeat(2,1fr)}}
  .ov-cols{display:grid;grid-template-columns:1.3fr 1fr;gap:20px;align-items:start}
  @media(max-width:820px){.ov-cols{grid-template-columns:1fr}}
  /* ===== ภาพรวมโฉมใหม่: กราฟย้อนหลัง + หน้า Services ===== */
  :root{--cgood:#0ca30c;--cwarn:#fab219;--ccrit:#d03b3b;--cs1:#2a78d6}
  /* ---- กราฟการใช้งานฐานข้อมูล (หน้า Services) ----
     สองสีนี้ผ่านการตรวจ colorblind-safe แล้ว (ΔE 26.2 protan · 27.2 tritan
     ทั้งโหมดสว่างและมืด) อย่าเปลี่ยนเป็นสีอื่นโดยไม่ตรวจซ้ำ
     และอย่าใช้สีเดียวกับ --cgood/--ccrit ซึ่งจองไว้สื่อ "สถานะ" ไม่ใช่ "ชุดข้อมูล" */
  :root{--dbu1:#2a78d6;--dbu2:#b5561f}
  .dbu-head{display:flex;align-items:center;gap:10px;margin-bottom:12px}
  .dbu-range{display:flex;gap:6px}
  .dbu-range button{font:600 12px system-ui;padding:5px 11px;border:1px solid var(--line);
    background:var(--card);color:var(--sub);border-radius:999px;cursor:pointer}
  .dbu-range button.on{background:var(--ink);color:#fff;border-color:var(--ink)}
  .dbu-kpi{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;margin-bottom:14px}
  .dbu-charts{display:grid;grid-template-columns:1fr 1fr;gap:18px}
  @media(max-width:820px){.dbu-charts{grid-template-columns:1fr}}
  .dbu-fig{margin:0}
  .dbu-fig figcaption{display:flex;flex-direction:column;gap:2px;margin-bottom:8px}
  .dbu-plot{position:relative;height:190px}
  .dbu-plot svg{display:block;width:100%;height:100%;overflow:visible}
  .dbu-plot .gl{stroke:var(--line);stroke-width:1}
  .dbu-plot .ax{fill:var(--faint);font:11px system-ui}
  .dbu-plot .ln{fill:none;stroke-width:2;stroke-linejoin:round;stroke-linecap:round}
  .dbu-plot .hit{fill:transparent}
  .dbu-plot .cross{stroke:var(--faint);stroke-width:1;stroke-dasharray:3 3;opacity:0}
  .dbu-plot .dot{r:4;stroke:var(--card);stroke-width:2;opacity:0}
  .dbu-tip{position:absolute;pointer-events:none;opacity:0;transition:opacity .08s;
    background:var(--ink);color:#fff;font:12px/1.5 system-ui;padding:7px 10px;
    border-radius:9px;white-space:nowrap;z-index:5;transform:translate(-50%,-115%)}
  .dbu-tip b{font-weight:700}
  .dbu-empty{display:flex;align-items:center;justify-content:center;height:100%;
    color:var(--faint);font:13px system-ui;text-align:center;line-height:1.7;padding:0 14px}
  .dbu-legend{display:flex;gap:16px;margin-top:8px;font:12px system-ui;color:var(--sub)}
  .dbu-legend i{display:inline-block;width:14px;height:3px;border-radius:2px;
    vertical-align:middle;margin-right:6px}
  .tseg{display:flex;gap:3px;background:var(--soft);border-radius:999px;padding:3px;font-weight:500}
  /* min-height 32px = เกณฑ์ขั้นต่ำของจุดที่ต้องแตะบนมือถือ (เดิมสูง 28px แตะพลาดง่าย) */
  .tseg button{border:0;background:transparent;font-size:11.5px;font-weight:800;color:var(--sub);
    padding:6px 12px;border-radius:999px;min-height:32px;cursor:pointer;font-family:inherit}
  .tseg button.on{background:#fff;color:var(--ink);box-shadow:var(--shadow-sm)}
  .clegend{display:flex;gap:14px;align-items:center;flex-wrap:wrap;font-size:11.5px;color:var(--sub);margin-top:8px}
  .clegend i{width:9px;height:9px;border-radius:3px;display:inline-block;margin-right:5px;vertical-align:-1px}
  .ctip{position:fixed;pointer-events:none;background:#141a30;color:#fff;font-size:11.5px;padding:7px 10px;border-radius:9px;opacity:0;transition:opacity .12s;z-index:90;line-height:1.6;white-space:nowrap;box-shadow:0 6px 18px rgba(0,0,0,.25)}
  .hbar{display:flex;align-items:center;gap:9px;margin:8px 0;font-size:12.5px}
  .hbar .nm{width:38%;max-width:170px;color:var(--sub);font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .hbar .tr{flex:1;height:9px;background:var(--soft);border-radius:5px;overflow:hidden;display:block}
  .hbar .fl{display:block;height:100%;border-radius:5px}
  .hbar .n{width:58px;text-align:right;font-weight:800;font-variant-numeric:tabular-nums}
  .alltbl{background:#fff;border:1px solid var(--line);border-radius:16px;box-shadow:var(--shadow-sm);margin-top:16px;overflow:hidden}
  .alltbl summary{padding:14px 16px;font-weight:800;font-size:14px;cursor:pointer;list-style:none;display:flex;align-items:center;gap:8px}
  .alltbl summary::-webkit-details-marker{display:none}
  .alltbl summary::after{content:"▾";margin-left:auto;color:var(--faint)}
  .alltbl[open] summary::after{content:"▴"}
  .alltbl .tblwrap{padding:0 16px 16px}
  .tblwrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
  .tblwrap table{min-width:520px}
  .svcgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(288px,1fr));gap:14px}
  .scard{background:#fff;border:1px solid var(--line);border-radius:16px;padding:15px;box-shadow:var(--shadow-sm)}
  .scard.down{border-color:rgba(208,59,59,.45);background:linear-gradient(#fff,rgba(208,59,59,.05))}
  .scard .top{display:flex;align-items:center;gap:10px}
  .scard .ic{width:36px;height:36px;border-radius:11px;display:grid;place-items:center;font-size:17px;background:var(--soft);flex:0 0 auto}
  .scard h4{font-size:14px;margin:0}
  .scard .st{margin-left:auto;font-size:11px;font-weight:800;white-space:nowrap}
  .scard .st.up{color:#0a7d0a}.scard .st.dn{color:var(--ccrit)}
  .scard .sub{font-size:11px;color:var(--faint);margin-top:4px}
  .scard .meta{font-size:12px;color:var(--sub);line-height:1.85;margin-top:9px}
  .scard .meta b{color:var(--ink)}
  #svc-kpi .kv{white-space:nowrap}
  .upbar{display:flex;gap:1.5px;height:26px;align-items:stretch;margin-top:11px}
  .upbar i{flex:1;border-radius:2px;background:var(--cgood);min-width:1px}
  .upbar i.part{background:linear-gradient(to top,var(--ccrit) 0,var(--ccrit) var(--d),var(--cgood) var(--d))}
  .upbar i.dn{background:var(--ccrit)}
  .upbar i.unk{background:#e4e9f2}
  .upfoot{display:flex;align-items:center;gap:5px;font-size:11px;color:var(--faint);margin-top:6px;white-space:nowrap}
  /* แถว 2: การ์ดอุปกรณ์ (กล้อง/NVR/HDD) + แผง donut การเชื่อมต่อ — กริดเดียวทั้งแถว
     ใช้ display:contents ดึงการ์ด 3 ใบขึ้นมาเป็นสมาชิกกริดโดยตรง
     ทุกใบจึงอยู่แถวเดียวกันและสูงเท่ากันเอง (stretch) ไม่มีช่องว่างค้างเหมือนแบบ 2 คอลัมน์ซ้อน
     min-width:0 ทุกใบ — กันชื่อรุ่นยาว ๆ ดันคอลัมน์จนล้นไปทับการ์ดข้าง ๆ */

  /* ====================================================================
     หน้าภาพรวมโฉมใหม่ (ส.ค. 69) — ออกแบบจากจอมือถือก่อน แล้วค่อยขยายขึ้นจอใหญ่
     กฎที่ยึดไว้ทั้งหน้า:
       1. ไม่มี scroll ซ้อน scroll บนมือถือ (นิ้วไปโดนแล้วหน้าไม่เลื่อน)
       2. ทุกจุดที่แตะได้สูงอย่างน้อย 32px (ปุ่มจริง 38-44px)
       3. ของสำคัญห้ามอยู่หลังการเลื่อนแนวนอน — คนไม่รู้ว่ามีของซ่อนอยู่
       4. tooltip หนีขอบจอเอง ไม่งั้นบนมือถือจะโดนตัดหาย
     ==================================================================== */
  /* ชุดสี "ประเภทการเชื่อมต่อ" — ตรวจ colorblind-safe แล้วด้วย validate_palette
     (ΔE ต่ำสุดสายตาปกติ 18.8 · protan 12.0) ห้ามเปลี่ยนโดยไม่ตรวจซ้ำ
     ของเดิม P2P #3a56b0 กับ Direct #7048a8 ห่างกันแค่ 1.9 ในโหมด protan = แยกไม่ออก */
  :root{--k1:#1f6fe0;--k2:#00a0a0;--k3:#7d3fd6;--k4:#cf2f8f}
  .ovw-kpi{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:14px}
  .ovk{background:var(--card);border:1px solid var(--line);border-radius:16px;
    padding:13px 14px;box-shadow:var(--shadow-sm);position:relative;overflow:hidden;
    min-height:44px;transition:transform .12s}
  .ovk:active{transform:scale(.985)}
  .ovk::before{content:"";position:absolute;inset:0 auto 0 0;width:4px;background:var(--a)}
  .ovk .top{display:flex;align-items:center;gap:8px;margin-bottom:6px}
  .ovk .ic{width:30px;height:30px;border-radius:9px;display:grid;place-items:center;
    font-size:15px;background:var(--soft);flex:none}
  .ovk .lb{font-size:12px;font-weight:700;color:var(--sub);line-height:1.25}
  .ovk .val{font-size:27px;font-weight:800;letter-spacing:-1.1px;line-height:1.05}
  .ovk .val small{font-size:14px;color:var(--faint);font-weight:700}
  .ovk .spark{height:28px;margin:5px 0 3px}
  .ovk .spark svg{width:100%;height:100%;display:block;overflow:visible}
  .ovk .ft{display:flex;justify-content:space-between;gap:6px;font-size:11px;color:var(--faint)}
  .ovk .ft b{color:var(--a);font-weight:800}
  .ovw-grid{display:grid;grid-template-columns:1.05fr 1.05fr 1fr;gap:14px;margin-bottom:14px}
  .ovw-grid .panel{margin:0}
  .ovw-tall{grid-row:span 2}
  .ovw-wide{grid-column:span 2}
  .ph{display:flex;align-items:center;gap:8px;margin-bottom:3px;min-height:26px;flex-wrap:wrap}
  /* ป้าย LIVE — จุดเขียวกระพริบอยู่ในป้ายเลย ไม่ใช่จุดลอย ๆ ข้างหัวข้อ
     วงกระพริบใช้ box-shadow ที่ขยายออกแล้วจาง จึงไม่ดันเลย์เอาต์ให้ขยับ */
  .livebadge{display:inline-flex;align-items:center;gap:6px;font-size:10.5px;font-weight:800;
    letter-spacing:.6px;color:#237350;background:rgba(47,143,99,.10);
    border:1px solid rgba(47,143,99,.24);border-radius:999px;padding:3px 9px 3px 7px;
    white-space:nowrap}
  .livebadge i{width:7px;height:7px;border-radius:50%;background:var(--green);flex:none;
    animation:livedot 1.7s cubic-bezier(.3,0,.2,1) infinite}
  @keyframes livedot{
    0%{box-shadow:0 0 0 0 rgba(47,143,99,.6)}
    70%{box-shadow:0 0 0 7px rgba(47,143,99,0)}
    100%{box-shadow:0 0 0 0 rgba(47,143,99,0)}
  }
  @media(prefers-reduced-motion:reduce){.livebadge i{animation:none}}
  #ovw-fnote b{color:var(--red);font-weight:800}
  /* margin:0 สำคัญ — .panel h3 มี margin-bottom:14px ติดมา
     ในแถว flex ที่ align-items:center ระบบจัดกึ่งกลาง "กล่องรวม margin"
     h3 จึงลอยขึ้นครึ่งหนึ่งของ margin (7px) เทียบกับป้าย LIVE ที่ไม่มี margin
     = อาการ "LIVE อยู่ต่ำกว่าหัวข้อ" ทั้งที่ตั้ง align-items:center ไว้แล้ว */
  .ph h3{font-size:15px;font-weight:800;letter-spacing:-.2px;margin:0}
  .ovw-hint{font-size:11.5px;color:var(--faint);margin-bottom:13px;line-height:1.55}
  .rng{font-size:11.5px;color:var(--faint);font-weight:700}
  /* ---- วงแหวน + รายการสถานะ ---- */
  .availrow{display:flex;gap:16px;align-items:center;flex-wrap:wrap}
  .ovring{width:100px;height:100px;flex:none;position:relative}
  .ovring svg{width:100%;height:100%;transform:rotate(-90deg)}
  .ovring .rc{position:absolute;inset:0;display:grid;place-content:center;text-align:center}
  .ovring b{font-size:20px;font-weight:800;letter-spacing:-.5px;display:block;line-height:1.1}
  .ovring span{font-size:10.5px;color:var(--faint)}
  .statlist{flex:1;min-width:168px;display:flex;flex-direction:column;gap:8px}
  .stq{display:grid;grid-template-columns:12px 1fr auto;gap:9px;align-items:center;
    padding:3px 0;border-radius:8px;transition:background .12s}
  .stq:hover{background:var(--soft)}
  .stq .sw{width:11px;height:11px;border-radius:3px}
  .stq .nm{font-size:12.5px;font-weight:600}
  .stq .track{height:7px;border-radius:99px;background:var(--line);overflow:hidden;margin-top:4px}
  .stq .track i{display:block;height:100%;border-radius:99px;transition:width .5s cubic-bezier(.4,0,.2,1)}
  .stq .n{font-size:14px;font-weight:800;text-align:right;min-width:42px}
  .stq .n em{font-style:normal;font-size:11px;color:var(--faint);font-weight:600;display:block}
  /* ---- donut แบบชี้ได้ ---- */
  .dwrap{display:flex;gap:16px;align-items:center;flex-wrap:wrap}
  .dbox{width:132px;height:132px;flex:none;position:relative}
  .dbox svg{width:100%;height:100%;transform:rotate(-90deg)}
  /* stroke-width 9 บนรัศมี 15.9 — ถ้าหนากว่านี้ขอบในจะหักเป็นเหลี่ยมให้เห็น */
  .dbox circle{fill:none;stroke-width:9;cursor:pointer;transition:stroke-width .15s,opacity .15s}
  .dbox circle.dim{opacity:.25}
  .dbox circle.hot{stroke-width:12.5}
  .dc{position:absolute;inset:0;display:grid;place-content:center;text-align:center;pointer-events:none}
  .dc b{font-size:21px;font-weight:800;display:block;line-height:1;letter-spacing:-.5px}
  .dc span{font-size:10.5px;color:var(--faint);display:block;margin-top:2px}
  .dlegend{flex:1;min-width:158px;display:flex;flex-direction:column;gap:2px}
  .dlegend div{display:flex;align-items:center;gap:8px;font-size:12.5px;padding:6px 8px;
    border-radius:9px;cursor:pointer;transition:background .12s;min-height:32px}
  .dlegend div:hover,.dlegend div.on{background:var(--soft)}
  .dlegend i{width:11px;height:11px;border-radius:3px;flex:none}
  .dlegend b{margin-left:auto;font-weight:800}
  .dlegend em{font-style:normal;color:var(--faint);font-size:11px;min-width:34px;text-align:right}
  /* ---- แท่งสัดส่วน 100% (Codec / การเชื่อมต่อ) ในการ์ดสถานะ ---- */
  .ovsplit{display:flex;flex-direction:column;gap:13px;flex:1;min-width:180px}
  .ovsp .sh{display:flex;justify-content:space-between;align-items:baseline;font-size:12px;margin-bottom:5px}
  .ovsp .sh b{font-weight:700;color:var(--ink)}
  .ovsp .sh span{color:var(--faint);font-size:11px}
  .ovsbar{height:15px;border-radius:8px;overflow:hidden;display:flex;gap:2px;background:var(--soft)}
  .ovsbar i{height:100%;display:block;min-width:2px;transition:width .5s cubic-bezier(.4,0,.2,1)}
  .ovsleg{display:flex;gap:12px;flex-wrap:wrap;margin-top:7px}
  .ovsleg span{display:flex;align-items:center;gap:6px;font-size:11.5px;color:var(--sub)}
  .ovsleg i{width:10px;height:10px;border-radius:3px;flex:none}
  /* ---- การบันทึกย้อนหลัง: แถบสัดส่วนเดียวไล่เฉด + แดง=ต่ำกว่าเกณฑ์ ---- */
  .rethbar{height:22px;border-radius:11px;overflow:hidden;display:flex;gap:2px;background:var(--soft);margin-top:4px}
  .rethbar i{height:100%;display:block;min-width:3px;transition:width .45s cubic-bezier(.4,0,.2,1)}
  .rethleg{display:flex;gap:12px 14px;flex-wrap:wrap;margin-top:11px}
  .rethleg span{display:flex;align-items:center;gap:6px;font-size:11.5px;color:var(--sub)}
  .rethleg i{width:10px;height:10px;border-radius:3px;flex:none}
  .rethleg b{color:var(--ink);font-weight:700}
  /* ---- KPI: ชิปเปลี่ยนแปลงมีทิศ ---- */
  .ovk .ft .chg{font-weight:800}
  .ovk .ft .chg.up{color:var(--green)}.ovk .ft .chg.down{color:var(--red)}.ovk .ft .chg.flat{color:var(--faint)}
  /* ---- ฟีดเหตุการณ์ ---- */
  /* ไล่จางท้ายรายการ = บอกว่ายังมีต่อ ถ้าตัดตรง ๆ จะดูเหมือนเรนเดอร์พัง */
  .feedbox{position:relative}
  .feedbox::after{content:"";position:absolute;left:0;right:0;bottom:0;height:34px;
    pointer-events:none;border-radius:0 0 12px 12px;
    background:linear-gradient(to bottom,rgba(255,255,255,0),var(--card))}
  .feed{max-height:512px;overflow:auto;margin:0 -3px;padding:0 3px 12px;
    -webkit-overflow-scrolling:touch;overscroll-behavior:contain}
  /* ---- แต่ละรายการ = จุดบนเส้นเวลา ----
     ซ้ายเป็นจุดกลมสีตามความรุนแรง มีเส้นตั้งลากต่อกันเป็นไทม์ไลน์
     ขวาเป็นคำสถานะ (สีเดียวกับจุด) + เวลา — อ่านจากซ้ายไปขวาได้ในบรรทัดเดียว */
  .fitem{position:relative;display:grid;grid-template-columns:20px minmax(0,1fr) auto;
    gap:11px;padding:9px 4px 9px 2px;align-items:start;border-radius:10px}
  .fitem.tap{cursor:pointer}
  .fitem.tap:hover{background:var(--soft)}
  /* เส้นเวลา: ลากจากจุดนี้ลงไปหาจุดถัดไป — รายการสุดท้ายไม่ต้องมี */
  .fitem::before{content:"";position:absolute;left:11px;top:26px;bottom:-9px;
    width:2px;background:var(--line);border-radius:2px}
  .fitem:last-child::before{display:none}
  .fdot{width:20px;height:20px;border-radius:50%;background:var(--card);
    border:2.5px solid var(--c);display:grid;place-items:center;position:relative;z-index:1}
  .fdot::after{content:"";width:7px;height:7px;border-radius:50%;background:var(--c)}
  /* รายการล่าสุดกระพริบ เพื่อให้สะดุดตาว่า "เพิ่งเกิดเมื่อกี้"
     ใช้ box-shadow ขยายวงแทนการเปลี่ยนขนาดจุด — ไม่ดันเลย์เอาต์ให้ขยับ
     สีวงใช้ตัวแปร --cg ที่ JS ใส่มาเป็น rgba ของสีเดียวกับจุด */
  .fitem.new .fdot{animation:fpulse 1.9s cubic-bezier(.3,0,.2,1) infinite}
  @keyframes fpulse{
    0%{box-shadow:0 0 0 0 var(--cg)}
    65%{box-shadow:0 0 0 11px transparent}
    100%{box-shadow:0 0 0 0 transparent}
  }
  @media(prefers-reduced-motion:reduce){.fitem.new .fdot{animation:none}}
  .fitem .t1{font-size:12.5px;font-weight:800;line-height:1.4}
  .fitem .t2{font-size:11.5px;color:var(--sub);margin-top:2px;line-height:1.45;
    overflow-wrap:anywhere}
  .fitem .fr{text-align:right;white-space:nowrap;padding-top:1px}
  .fitem .fs{font-size:11.5px;font-weight:800;color:var(--c);display:block;line-height:1.4}
  .fitem .fw{font-size:10.5px;color:var(--faint);display:block;margin-top:1px}
  /* ป้ายเล็กหลังชื่อไซต์ (เช่น CH8) — ตัวเลขช่องต้องอ่านออกทันทีโดยไม่ต้องกวาดตาหา */
  .fchip2{display:inline-block;font-size:10.5px;font-weight:800;padding:1px 7px;
    border-radius:999px;background:var(--soft);color:var(--sub);
    border:1px solid var(--line);margin-left:6px;vertical-align:1px}
  /* รูปแนบในรายการฟีด (บันทึกของช่าง) */
  .fthumbs{display:flex;gap:6px;margin-top:6px;flex-wrap:wrap}
  .fthumb{width:52px;height:52px;object-fit:cover;border-radius:8px;cursor:zoom-in;
    border:1px solid var(--line);background:#eee}
  .fdel{display:block;margin-top:5px;font-size:11px;color:var(--faint);background:none;border:0;
    cursor:pointer;padding:2px 0;font-family:inherit}
  .fdel:hover{color:var(--red)}
  .fedit{display:block;margin-top:5px;font-size:11px;color:var(--faint);background:none;border:0;
    cursor:pointer;padding:2px 0;font-family:inherit}
  .fedit:hover{color:var(--blue)}
  /* ปุ่มแก้ไข+ลบ อยู่บรรทัดเดียว ชิดขวา ไม่กินหลายบรรทัด */
  .factions{display:flex;gap:14px;justify-content:flex-end;align-items:center;margin-top:5px}
  .factions .fedit,.factions .fdel{display:inline;margin:0;padding:0}
  /* ฟอร์มเพิ่มบันทึกของช่าง */
  .dlf{width:100%;border:1px solid var(--line);border-radius:14px;padding:12px 14px;font-size:15px;
    margin-top:8px;font-family:inherit;background:#fff;color:var(--ink)}
  .dllbl{font-size:12px;color:var(--faint);font-weight:800;margin-top:14px;display:block}
  #ovw-feedmore{display:none;width:100%;margin-top:10px;padding:11px;font-size:13.5px}
  /* ---- แท่งจัดอันดับ ---- */
  .rank{display:flex;flex-direction:column;gap:3px}
  .rk{display:grid;grid-template-columns:1fr auto;gap:3px 10px;padding:7px 8px;
    border-radius:10px;cursor:pointer;transition:background .12s;min-height:44px;align-content:center}
  .rk:hover{background:var(--soft)}
  .rk .nm{font-size:12.5px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .rk .v{font-size:12.5px;font-weight:800;white-space:nowrap}
  .rk .v s{text-decoration:none;color:var(--faint);font-weight:600}
  .rk .tr{grid-column:1/-1;height:9px;border-radius:99px;background:var(--line);overflow:hidden}
  .rk .tr i{display:block;height:100%;border-radius:99px;
    transition:width .6s cubic-bezier(.4,0,.2,1),filter .12s}
  .rk:hover .tr i{filter:brightness(1.12)}
  /* ---- กราฟย้อนหลังแบบเส้น ---- */
  /* touch-action:pan-y = ลากนิ้วบนกราฟแล้วหน้ายังเลื่อนได้ตามปกติ
     ถ้าไม่ใส่ นิ้วที่บังเอิญเริ่มบนกราฟจะเลื่อนหน้าไม่ได้เลย */
  .ovchart{height:150px;position:relative;touch-action:pan-y}
  .ovchart svg{width:100%;height:100%;display:block;overflow:visible}
  .ovchart .gl{stroke:var(--line);stroke-width:1}
  .ovchart .ax{fill:var(--faint);font-size:10px}
  .ovchart .ln{fill:none;stroke-width:2.2;stroke-linejoin:round;stroke-linecap:round}
  .ovchart .cx{stroke:var(--faint);stroke-width:1;stroke-dasharray:3 3;opacity:0}
  .ovchart .pt{r:4.5;stroke:var(--card);stroke-width:2.5;opacity:0}
  .ovchart .empty{position:absolute;inset:0;display:flex;align-items:center;
    justify-content:center;color:var(--faint);font-size:12px;pointer-events:none;text-align:center}
  /* ---- tooltip กลางของหน้าภาพรวม ---- */
  .ovtip{position:fixed;z-index:60;pointer-events:none;opacity:0;transition:opacity .1s;
    background:var(--ink);color:#fff;font-size:12px;line-height:1.5;padding:8px 11px;
    border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.22);max-width:230px;left:0;top:0}
  .ovtip .tv{font-weight:800;font-size:13.5px}
  .ovtip .tr2{display:flex;align-items:center;gap:7px;margin-top:3px}
  .ovtip .tr2 i{width:12px;height:2.5px;border-radius:2px;flex:none}
  .ovtip .tr2 s{text-decoration:none;opacity:.75;margin-left:auto}
  @media(max-width:1080px){
    .ovw-grid{grid-template-columns:1fr 1fr}
    .ovw-tall{grid-row:auto}
    .ovw-wide{grid-column:span 2}
  }
  @media(max-width:760px){
    .ovw-grid{grid-template-columns:1fr;gap:12px}
    .ovw-wide{grid-column:auto}
    /* KPI 2x2 อ่านง่ายกว่าเลื่อนแนวนอน — เห็นครบ 4 ใบโดยไม่ต้องรู้ว่ามีของซ่อนอยู่ */
    .ovw-kpi{grid-template-columns:1fr 1fr;gap:10px}
    .ovk{padding:11px 12px;border-radius:14px}
    .ovk .val{font-size:23px}
    .ovk .val small{font-size:12.5px}
    .ovk .lb{font-size:11px}
    .ovk .ic{width:26px;height:26px;font-size:13px;border-radius:8px}
    .ovk .spark{height:22px}
    .ovk .ft{font-size:10px;flex-direction:column;gap:1px}
    /* วงแหวนกับ donut วางกลาง แล้วรายการลงมาข้างล่าง — บีบข้างกันบนจอ 360px ไม่พอ */
    .availrow,.dwrap{flex-direction:column;align-items:stretch;gap:14px}
    .ovring,.dbox{align-self:center}
    .statlist,.dlegend{min-width:0}
    /* มือถือ: เลิกใช้ scroll ซ้อน แสดง 5 รายการพอ แล้วให้กดขยายเอง */
    .feed{max-height:none;overflow:visible}
    .feed .fitem:nth-child(n+6){display:none}
    .feed.all .fitem{display:grid}
    /* ย่ออยู่ = รายการที่ 5 คือตัวสุดท้ายที่มองเห็น เส้นเวลาต้องจบตรงนั้น
       (:last-child ใช้ไม่ได้ เพราะรายการที่ 6+ ยังอยู่ใน DOM แค่ถูกซ่อน) */
    .feed:not(.all) .fitem:nth-child(5)::before{display:none}
    .feedbox::after{display:none}
    #ovw-feedmore.canmore{display:block}
    .ovchart{height:138px}
    .ovtip{max-width:min(230px,calc(100vw - 24px))}
  }
  @media(max-width:400px){.ovk .val{font-size:21px}.rk .nm{font-size:12px}}
  /* ไทม์ไลน์ต่อไซต์ (ท้าย modal): เลื่อนดูในกล่องตัวเอง แสดงครบทุกรายการทั้งบนมือถือ
     ไม่ยืมกฎ "โชว์ 5 รายการ" ของฟีดหน้าภาพรวม */
  .sfeed{max-height:360px;overflow:auto}
  @media(max-width:760px){.sfeed{max-height:300px;overflow:auto}
    .sfeed .fitem:nth-child(n+6){display:grid}
    .sfeed:not(.all) .fitem:nth-child(5)::before{display:block}}
  /* ===== UniFi Monitor (หน้าเครือข่าย · อ่านอย่างเดียว) ===== */
  .uni-bar{display:flex;align-items:center;gap:10px;margin-bottom:10px;flex-wrap:wrap}
  /* ---- แถบปุ่มของหน้า UniFi ----
     เดิมปุ่มทั้งหมดอยู่ใน flex เดียวกันแล้วปล่อยให้ wrap เอง -> บนมือถือได้ 3+2 ปุ่ม
     ความกว้างไม่เท่ากัน ดูกระจัดกระจายและไม่รู้ว่าปุ่มไหนพวกเดียวกัน
     ตอนนี้แบ่งเป็น 2 หมวดชัดเจน และใช้ grid ให้ทุกปุ่มในหมวดกว้างเท่ากันเสมอ */
  .uni-acts{display:flex;flex-direction:column;gap:10px;margin-bottom:14px}
  /* จอกว้าง: จำกัดความกว้างปุ่มไว้ ไม่ให้ยืดเต็มจอจนดูโหว่ · จอแคบ: 2 คอลัมน์เต็มความกว้าง */
  .uagrp{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,220px));gap:8px}
  .uagrp[data-g="cfg"]{padding-top:10px;border-top:1px solid var(--line)}
  .ualb{grid-column:1/-1;font-size:10.5px;font-weight:800;letter-spacing:.4px;
    text-transform:uppercase;color:var(--faint);margin-bottom:-2px}
  .uact{display:inline-flex;align-items:center;justify-content:center;gap:7px;
    font-family:inherit;font-size:13.5px;font-weight:700;cursor:pointer;
    padding:11px 12px;border-radius:12px;border:1.5px solid var(--line);
    background:var(--card);color:var(--ink);transition:.12s;min-width:0}
  .uact i{font-style:normal;font-size:15px;line-height:1;flex:0 0 auto}
  .uact span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .uact:hover{border-color:var(--pri);color:var(--pri)}
  .uact:active{transform:translateY(1px)}
  .uact.pri{background:var(--pri);border-color:var(--pri);color:#fff}
  .uact.pri:hover{filter:brightness(1.06);color:#fff}
  .uawhen{text-align:right}
  /* ปุ่มไอคอนข้างช่องเลือกไซต์ — สูงเท่ากล่องเลือกไซต์พอดี จะได้อยู่ในแนวเดียวกัน */
  /* ปุ่มไอคอนกลม ๆ สืบ padding:12px 18px มาจาก .btn ซึ่งกินพื้นที่ในกล่อง 44px จนเหลือ
     ที่ให้ตัวไอคอนแค่ 8px (ไฟล์นี้ตั้ง box-sizing:border-box ทั้งหมด) ไอคอนจึงล้นแล้วเบี้ยว
     วัดได้ว่าเยื้องไปทางขวา 5px บนจอมือถือ · ล้าง padding แล้วจัดกึ่งกลางด้วย grid
     ให้ตรงทั้งสองแกน ไม่ว่าเบราว์เซอร์จะหยิบฟอนต์สำรองตัวไหนมาวาดไอคอน */
  .uicb{flex:0 0 auto;width:46px;height:46px;border-radius:14px;cursor:pointer;
    border:1.5px solid var(--line);background:var(--card);color:var(--sub);
    font-size:19px;line-height:1;font-family:inherit;transition:.12s;
    padding:0;display:grid;place-items:center}
  .uicb:hover{border-color:var(--pri);color:var(--pri)}
  .uicb:active{transform:rotate(90deg)}
  @media(max-width:760px){
    .uagrp{grid-template-columns:repeat(2,1fr)}
    /* ปุ่มสุดท้ายที่เหลือโดดอยู่คนเดียวในแถว ให้กินเต็มความกว้าง จะได้ไม่ดูขาดครึ่ง
       (ตัวป้ายหมวดนับเป็นลูกที่ 1 ปุ่มจึงเริ่มที่ 2 -> เหลือเศษเมื่อลูกสุดท้ายเป็นเลขคู่) */
    .uagrp[data-g="cfg"] .uact:last-child:nth-child(even){grid-column:1/-1}
    .uagrp[data-g="do"] .uact:only-child{grid-column:1/-1}
    .uact{font-size:13px;padding:12px 10px}
    .uawhen{text-align:left}
  }
  .uni-sel{display:none}
  /* ปุ่มเลือกไซต์ — ของเดิมเป็น <select> เล็กจนเหลือแต่ลูกศรบนมือถือ จนไม่รู้ว่ากดอะไรได้ */
  .usb{display:flex;align-items:center;gap:10px;font-family:inherit;text-align:left;cursor:pointer;
    background:var(--card);border:1.5px solid var(--line);border-radius:14px;padding:8px 12px;
    box-shadow:var(--shadow-sm);min-width:240px;max-width:100%;transition:.14s}
  .usb:hover{border-color:var(--pri);box-shadow:0 3px 10px rgba(0,0,0,.09)}
  .usb:active{transform:scale(.985)}
  .usb-ic{flex:0 0 auto;width:30px;height:30px;border-radius:9px;background:var(--soft);
    display:flex;align-items:center;justify-content:center;font-size:15px}
  .usb-t{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:1px}
  .usb-lb{font-size:10.5px;font-weight:700;color:var(--faint);text-transform:uppercase;letter-spacing:.4px;line-height:1.2}
  .usb-nm{font-size:15px;font-weight:800;color:var(--ink);line-height:1.25;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .usb-ar{flex:0 0 auto;font-size:11px;color:var(--faint);font-weight:800}
  .usb-n{flex:0 0 auto;font-size:11px;font-weight:800;color:var(--sub);background:var(--soft);
    border-radius:999px;padding:2px 8px}
  /* รายการไซต์ในหน้าต่างเลือก */
  .uspk-s{position:sticky;top:-22px;background:var(--card);padding:22px 0 10px;margin-top:-22px;z-index:2}
  /* เดิมลิสต์นี้เป็น "ตัวเลื่อนซ้อนใน .modal ที่เลื่อนได้อยู่แล้ว" -> บนมือถือนิ้วมักไปโดน
     ตัวนอกจับไว้ ทำให้รู้สึกว่าเลื่อนรายการไม่ได้ ตอนนี้ให้ .mbody เป็นตัวเลื่อนตัวเดียว
     (ดู .modal.mfit ด้านล่าง) ลิสต์จึงไม่ต้องมี max-height/overflow ของตัวเอง */
  .uspk-l{display:flex;flex-direction:column;gap:4px}
  .uspk-i{display:flex;align-items:center;gap:10px;padding:11px 12px;border-radius:11px;cursor:pointer;
    border:1px solid transparent;font-size:14.5px;color:var(--ink);text-align:left;background:none;
    font-family:inherit;width:100%;transition:.1s}
  .uspk-i:hover{background:var(--soft)}
  .uspk-i.on{background:rgba(59,130,246,.10);border-color:var(--pri);font-weight:800}
  .uspk-i b{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:inherit}
  .uspk-i .k{flex:0 0 auto;font-size:11px;color:var(--faint)}
  .uspk-e{padding:22px 6px;text-align:center;color:var(--faint);font-size:13.5px}
  @media(max-width:760px){.usb{width:100%;min-width:0;padding:10px 12px}.usb-nm{font-size:16px}
    /* ในแถบเลือกไซต์ ปุ่มต้องหดให้ปุ่มรีเฟรชอยู่ข้าง ๆ ได้ ไม่ใช่กินเต็มบรรทัดจนดันตกไปแถวล่าง */
    .uni-bar .usb{width:auto;flex:1 1 auto}
    .uni-bar{flex-wrap:nowrap}
    .uicb{width:44px;height:44px}
    /* หัวหน้าต่างรายละเอียดมีปุ่มไอคอนถึง 4 ปุ่ม (รีสตาร์ท/แก้ไข/ลบ/ปิด)
       ถ้าไม่ย่อ ชื่อไซต์จะเหลือที่ไม่กี่ตัวอักษรแล้วโดนตัดทิ้ง */
    .mhead{gap:10px;padding:14px 14px}
    .mhead .mclose{width:34px;height:34px;font-size:15px;border-radius:10px}
    .mhead .av{width:40px;height:40px;font-size:20px;border-radius:12px}}
  /* รีสตาร์ท NVR เป็นคำสั่งที่กระทบงานจริง (กล้องหลุด บันทึกหยุด) — ให้ต่างจากปุ่มอื่นเล็กน้อย
     จะได้ไม่กดพลาดเพราะอยู่ติดกับปุ่มลบ (มีหน้าต่างยืนยันอีกชั้นอยู่แล้ว) */
  #d-reboot{background:rgba(255,255,255,.14);box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.45)}
  /* แท็บเพิ่มขึ้นเรื่อย ๆ (ตอนนี้ 5-6 อัน) จอแคบจะล้นขอบ -> ให้เลื่อนแนวนอนได้แทนที่จะตัดทิ้ง */
  .uni-tabs{display:flex;gap:6px;background:var(--soft);border:1px solid var(--line);border-radius:12px;
    padding:4px;margin-bottom:16px;width:max-content;max-width:100%;overflow-x:auto;
    -webkit-overflow-scrolling:touch;scrollbar-width:none}
  .uni-tabs::-webkit-scrollbar{display:none}
  .uni-tabs button{font-family:inherit;font-size:13px;font-weight:700;color:var(--sub);background:transparent;border:0;border-radius:9px;padding:8px 16px;cursor:pointer;transition:.15s;white-space:nowrap;flex:0 0 auto}
  @media(max-width:560px){.uni-tabs button{padding:8px 12px;font-size:12.5px}}
  .uni-tabs button.on{background:var(--card);color:var(--ink);box-shadow:var(--shadow-sm)}
  .uni-srch{display:flex;align-items:center;gap:8px;background:var(--card);border:1px solid var(--line);border-radius:12px;padding:0 12px;margin-bottom:14px;box-shadow:var(--shadow-sm)}
  .uni-srch .si{font-size:14px;color:var(--faint);flex:0 0 auto}
  .uni-srch input{flex:1;min-width:0;border:0;background:transparent;font-family:inherit;font-size:13.5px;color:var(--ink);padding:11px 0;outline:none}
  .uni-srch .sx{border:0;background:var(--soft);color:var(--sub);width:24px;height:24px;border-radius:7px;cursor:pointer;flex:0 0 auto;font-size:12px}
  .umcli .c2.cconn{color:var(--ink);font-weight:600;margin-top:2px}
  .uni-kpis{display:grid;grid-template-columns:repeat(2,1fr);gap:12px;margin-bottom:16px}
  .uni-kpi{background:var(--card);border:1px solid var(--line);border-radius:16px;padding:14px 16px;box-shadow:var(--shadow-sm)}
  .uni-kpi b{font-size:23px;font-weight:800;display:block;line-height:1.1}
  .uni-kpi span{color:var(--sub);font-size:12px}
  .uni-sec{background:var(--card);border:1px solid var(--line);border-radius:16px;padding:16px 18px;box-shadow:var(--shadow-sm);margin-bottom:14px}
  .uni-sec h4{font-size:11.5px;color:var(--faint);text-transform:uppercase;letter-spacing:.4px;margin-bottom:12px;font-weight:800}
  .uni-health{display:flex;gap:22px;flex-wrap:wrap;font-size:13px;align-items:center}
  .uni-health .hc{display:flex;align-items:center;gap:7px}
  .uni-health b{color:var(--ink)}
  .uni-tbl{width:100%;border-collapse:collapse;font-size:13px}
  .uni-tbl th{color:var(--faint);font-size:10.5px;text-transform:uppercase;letter-spacing:.4px;text-align:left;padding:7px 8px;border-bottom:1px solid var(--line);white-space:nowrap}
  .uni-tbl td{padding:9px 8px;border-bottom:1px solid var(--line);vertical-align:middle}
  .uni-tbl tr:last-child td{border-bottom:0}
  .uni-tbl .nm2{font-weight:700}
  .uni-tbl .sub2{font-size:11px;color:var(--sub);margin-top:1px}
  .u-dot{width:9px;height:9px;border-radius:50%;flex:0 0 auto;display:inline-block}
  .u-dot.g{background:var(--green)}.u-dot.y{background:var(--yellow)}.u-dot.r{background:var(--red)}.u-dot.x{background:#c6cddc}
  .u-pill{display:inline-block;font-size:10.5px;font-weight:800;padding:2px 9px;border-radius:999px;white-space:nowrap}
  .u-pill.g{background:#e4f4ec;color:#23855a}.u-pill.r{background:#fbe7e7;color:#c33f3f}.u-pill.y{background:#fbf1dc;color:#a9781f}
  .u-pill.b{background:#e2f4fb;color:#1080ad}
  /* ตารางสถิติการบันทึก: หัวคอลัมน์กึ่งกลาง + คอลัมน์ตัวเลขกึ่งกลาง */
  .rec-tbl th{text-align:center;vertical-align:middle}
  .rec-tbl td.c,.rec-tbl th.c{text-align:center;white-space:nowrap}
  /* ป้ายประเภทไซต์ (IP / Analog / Analog+IP) */
  .styp{display:inline-block;font-size:10px;font-weight:700;padding:2px 8px;border-radius:999px;white-space:nowrap}
  .styp.ip{background:#e6eefc;color:#2b5fc4}
  .styp.ana{background:#fdeede;color:#b06a1f}
  .styp.mix{background:#efe7fb;color:#6d3bc0}
  .u-bar{height:6px;background:var(--line);border-radius:99px;overflow:hidden;width:74px;display:inline-block;vertical-align:middle}
  .u-bar>i{display:block;height:100%;background:var(--blue)}
  .uni-empty{color:var(--sub);padding:26px;text-align:center;font-size:13px}
  /* desktop = ตาราง · mobile = การ์ดจอเดียว */
  .uni-desk{display:block}.uni-mob{display:none}.uni-msort{display:none}
  .udc{display:flex;align-items:center;gap:12px;padding:12px 4px;border-bottom:1px solid var(--line);cursor:pointer}
  .udc:last-child{border-bottom:0}.udc:active{background:var(--soft)}
  .udic{width:40px;height:40px;border-radius:50%;background:var(--soft);display:flex;align-items:center;justify-content:center;font-size:17px;flex:0 0 auto;border:2px solid #c6cddc}
  .udic.g{border-color:var(--green)}.udic.r{border-color:var(--red)}.udic.y{border-color:var(--yellow)}.udic.x{border-color:#c6cddc}
  .udmid{flex:1;min-width:0}
  /* ชื่ออุปกรณ์ต้องเห็นครบ: ตัวเล็กลงแต่ยังหนา + ยาวเกินขึ้นบรรทัดใหม่ได้ (ไม่ตัด …) */
  .udn{font-size:13px;font-weight:700;line-height:1.3;white-space:normal;overflow-wrap:anywhere;word-break:break-word}
  .udsub{font-size:12px;color:var(--sub);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:2px}
  .udr{text-align:right;flex:0 0 auto;min-width:56px}
  .uplbl{font-size:13px;font-weight:800;white-space:nowrap}
  /* เลข Mbps ต่อท้ายสัญลักษณ์ uplink (FE/GbE) — เดิมมีแต่ในตารางเดสก์ท็อป จอมือถือเลยไม่เห็นความเร็วจริง */
  .upsp{display:block;font-size:11px;font-weight:700;color:var(--sub);margin-top:1px;letter-spacing:.2px}
  .uplbl.g{color:var(--green)}.uplbl.y{color:#b8860b}.uplbl.m{color:var(--sub)}.uplbl.b{color:var(--blue)}
  .udip{font-size:11.5px;color:var(--sub);margin-top:2px}
  .udc .u-dot{margin-left:2px}
  .uni-msort{align-items:center;gap:8px;margin-bottom:10px}
  .uni-msort span{font-size:12px;color:var(--sub);flex:0 0 auto}
  .uni-msort select{flex:1;min-width:0;font-family:inherit;font-size:13px;font-weight:600;border:1px solid var(--line);border-radius:9px;padding:8px 10px;background:var(--card);color:var(--ink)}
  .uni-msort button{border:1px solid var(--line);background:var(--card);border-radius:9px;width:40px;height:36px;font-size:13px;cursor:pointer;color:var(--blue);flex:0 0 auto}
  /* dashboard: gauge สัญญาณ + band bar (ให้ดูเหมือน app จริง) */
  .uni-gauge{position:relative;height:14px;border-radius:99px;background:linear-gradient(90deg,#c94a4a 0%,#e8a54a 30%,#e6d24a 45%,#7bc47f 62%,#2f8f63 100%)}
  .uni-gauge .gdots{position:absolute;inset:0}
  .uni-gauge .gdots>i{position:absolute;top:50%;width:7px;height:7px;margin:-3.5px 0 0 -3.5px;border-radius:50%;background:#fff;box-shadow:0 0 0 1.5px rgba(30,39,64,.35)}
  .uni-gauge .gavg{position:absolute;top:-4px;width:3px;height:22px;margin-left:-1.5px;background:var(--ink);border-radius:2px;box-shadow:0 0 0 2px var(--card)}
  .uni-gscale{display:flex;justify-content:space-between;margin-top:5px;font-size:10.5px;color:var(--faint)}
  .uni-bandbar{display:flex;height:12px;border-radius:99px;overflow:hidden;background:var(--line)}
  .uni-bandbar>div{height:100%}
  .uni-bandleg{display:flex;gap:14px;flex-wrap:wrap;margin-top:8px;font-size:12px;color:var(--sub)}
  .uni-bandleg span{display:flex;align-items:center;gap:6px}
  .uni-bandleg i{width:10px;height:10px;border-radius:3px}
  @media(max-width:760px){.uni-desk{display:none}.uni-mob{display:block}.uni-msort{display:flex}}
  .uni-logo{height:30px;width:auto;vertical-align:middle;display:inline-block}
  /* หัวหน้า UniFi: ชื่อไซต์ที่เปิดอยู่ วางใต้ "สถานะเครือข่าย UniFi" (เห็นชัดบนมือถือ) */
  /* flex-basis 0 — ไม่งั้นชื่อไซต์ยาว ๆ จะดัน uni-htxt ตกไปบรรทัดใหม่ แถบหัวสูงเกินจำเป็นบนมือถือ */
  .uni-htxt{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1 1 0}
  .uni-cursite{display:none;align-items:center;gap:6px;min-width:0;font-size:13px;font-weight:800;
    color:var(--pri);line-height:1.25}
  .uni-cursite.on{display:flex}
  .uni-cursite i{flex:0 0 auto;width:7px;height:7px;border-radius:50%;background:#98a2b3;
    box-shadow:0 0 0 3px rgba(152,162,179,.16);transition:background .2s,box-shadow .2s}
  .uni-cursite.st-g i{background:var(--green);box-shadow:0 0 0 3px rgba(47,143,99,.16)}
  .uni-cursite.st-y i{background:#e0a12c;box-shadow:0 0 0 3px rgba(224,161,44,.20)}
  .uni-cursite.st-r i{background:var(--red);box-shadow:0 0 0 3px rgba(201,74,74,.20)}
  .uni-cursite b{font-weight:800;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
  /* ── หัวหน้าที่ตรึงไว้: บีบให้เตี้ยลงเมื่อเลื่อนจอ ─────────────────────────
     หน้า CCTV เดิมกิน 295px บนมือถือ = 38% ของจอ (หัวข้อ/ค้นหา/ปุ่ม/ตัวกรอง 4 แถว)
     พอเลื่อนลง JS จะใส่ .cond ให้ .page-head.stick ทุกอัน แล้วซ่อนของที่ไม่จำเป็น
     ตอนกำลังไล่อ่านรายการ (ชื่อหน้า + ป้ายอัปเดตอัตโนมัติ) เหลือแต่ค้นหา+ตัวกรอง */
  .page-head.stick{transition:padding .15s ease}
  .page-head.stick.cond{padding-top:9px;margin-top:-9px;padding-bottom:7px;margin-bottom:12px;
    box-shadow:0 6px 14px -12px rgba(34,42,68,.55)}
  .page-head.stick.cond>h1{font-size:16px}
  @media(max-width:820px){
    /* เลื่อนแล้ว: ซ่อนชื่อหน้าเฉพาะหน้าที่หัวสูงจริง (CCTV, ฐานข้อมูล) — แถบเมนูล่าง
       ไฮไลต์หน้าที่อยู่ให้อยู่แล้ว · หน้าอื่นหัวเตี้ยอยู่แล้ว ซ่อนไปจะเหลือแถบเปล่า ๆ */
    #v-cctv .page-head.stick.cond>h1,
    #v-db .page-head.stick.cond>h1,
    .page-head.stick.cond .hide-cond{display:none}
    .page-head.stick.cond{margin-bottom:10px}

    /* หน้า CCTV: จัดใหม่เหลือ 2 แถว — [ค้นหา + ปุ่มไอคอน] / [ตัวกรอง] */
    #v-cctv .page-head{gap:9px;row-gap:9px}
    #v-cctv .page-head>h1{flex:1 1 100%;font-size:18px}
    #v-cctv .page-head .searchbox{flex:1 1 120px;min-width:0}
    #v-cctv .page-head .spacer,
    #v-cctv .page-head #last-sync{display:none}   /* ป้าย "อัปเดตอัตโนมัติ" ไม่จำเป็นบนจอแคบ */
    /* ปุ่มกลายเป็นไอคอนสี่เหลี่ยม 42px — ช่องค้นหา+2 ปุ่ม อยู่แถวเดียวได้แม้จอ 360px */
    #v-cctv .page-head .btn{flex:0 0 42px;width:42px;height:42px;padding:0;font-size:17px;
      display:inline-flex;align-items:center;justify-content:center}
    #v-cctv .page-head .btn .lbl{display:none}    /* เหลือแต่ ↻ กับ + */
    #v-cctv .fbar{padding-top:0}
    #v-cctv .fchip{padding:5px 11px}
  }
  /* ── รายการ WiFi (แท็บ WiFi ของหน้า UniFi) ───────────────────────────── */
  .wlist{display:flex;flex-direction:column;gap:9px}
  .wrow{display:flex;align-items:center;gap:12px;border:1px solid var(--line);background:#fff;
    border-radius:14px;padding:12px 14px;cursor:pointer;transition:border-color .12s,box-shadow .12s}
  .wrow:hover{border-color:#c9d2e4;box-shadow:var(--shadow-sm)}
  .wrow.off{background:var(--soft);opacity:.72}
  .wic{flex:0 0 auto;font-size:20px;line-height:1}
  .wmid{min-width:0;flex:1}
  .wn{font-weight:800;font-size:15px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .wsub{font-size:12px;color:var(--sub);margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .wtag{margin-top:5px;display:flex;gap:5px;flex-wrap:wrap;min-width:0;overflow:hidden}
  .wtag .u-pill{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .wst{flex:0 0 auto;display:flex;flex-direction:column;align-items:flex-end;gap:5px}
  .wcli{font-size:12px;font-weight:800;color:var(--faint);white-space:nowrap}
  .wcli.on{color:var(--pri)}
  .wfhead{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
  .wfhead .wft{flex:1 1 auto;min-width:0}
  .wfhb{display:flex;gap:6px;flex:0 0 auto;margin-left:auto}
  .wfhb .btn{padding:6px 12px;font-size:12px;white-space:nowrap}
  @media(max-width:560px){
    /* จอแคบ: ดันปุ่มลงมาเป็นแถวของตัวเอง แล้วเฉลี่ยความกว้าง — รายการ SSID จะได้เต็มความกว้างจอ */
    .wfhb{width:100%;margin-left:0}
    .wfhb .btn{flex:1 1 auto;padding:8px 6px;font-size:12px}
  }
  .wfgact{flex-direction:row;align-items:center}
  .wfgact .btn{padding:6px 10px;font-size:12px}
  /* กล่องติ๊กเลือกกลุ่ม/AP ในฟอร์ม WiFi — จำกัดความสูงไว้ ไม่ให้ modal ยาวเกินจอมือถือ */
  .wfpick{display:flex;flex-direction:column;gap:7px;max-height:210px;overflow:auto;
    border:1px solid var(--line);border-radius:12px;padding:11px;margin-bottom:12px;background:var(--soft)}
  .wfdel{margin-top:18px;padding-top:14px;border-top:1px solid var(--line);text-align:right}
  @media(max-width:560px){
    .uni-sec .wlist{min-width:0}
    .wrow{padding:11px 12px;gap:10px}
    .wic{font-size:17px}
    .wn{font-size:14.5px}
    .wsub{white-space:normal}          /* ชื่อเครือข่าย/ย่านความถี่ ตัดบรรทัดได้ ดีกว่าโดนตัดด้วย ... */
    .wst{gap:4px}
  }
  /* ฟอร์มแก้ไข WiFi */
  .wfl{display:block;font-size:13px;color:var(--sub);font-weight:700;margin:0 0 5px}
  .wfi{width:100%;border:1px solid var(--line);border-radius:12px;padding:11px;font-size:15px;
    font-family:inherit;margin-bottom:12px;background:#fff}
  .wfpw{display:flex;gap:8px;align-items:flex-start}
  .wfpw .wfi{flex:1}
  .wfpw .btn{flex:0 0 auto;padding:11px 14px}
  .wfrow{display:flex;gap:14px;flex-wrap:wrap;margin-bottom:12px}
  /* ===== ปุ่มส่งออกไฟล์ (มุมบนของหน้าบัญชี) =====
     เล็กพอให้ไม่แย่งสายตาจากตัวเลขในหน้า แต่ยังกดโดนง่ายบนมือถือ (สูง 30px) */
  /* ปุ่มเดียว ไอคอนอย่างเดียว อยู่แถวเดียวกับตัวเลือกเดือน
     เดิมเป็นสองปุ่ม (PDF / Excel) กินความกว้างจนชื่อเดือนแบบเต็มไม่มีที่อยู่
     กดแล้วค่อยเลือกว่าจะเอาไฟล์แบบไหน — เมนูเล็ก ๆ ลอยใต้ปุ่ม */
  .ac-exp{position:relative;flex:0 0 auto}
  .ac-expb{width:42px;height:42px;border-radius:12px;cursor:pointer;
    border:1.5px solid var(--line);background:var(--card);color:var(--sub);
    font-family:inherit;font-size:17px;font-weight:800;line-height:1;
    display:inline-flex;align-items:center;justify-content:center;transition:.12s;
    box-shadow:var(--shadow-sm)}
  .ac-expb:hover:not(:disabled){border-color:var(--pri);color:var(--pri)}
  .ac-expb:disabled{opacity:.5;cursor:default}
  .ac-expb.busy{border-color:var(--yellow);color:var(--ink)}
  .ac-expb.on{border-color:var(--pri);color:var(--pri)}
  /* ===== หน้าต่างส่งออกไฟล์ (#ov-acexp) =====
     เคยทำเป็นเมนูลอยใต้ปุ่ม แต่การสร้างไฟล์ใช้เวลา 5-10 วิ ซึ่งเมนูปิดไปตั้งแต่ตอนกดแล้ว
     ผู้ใช้จึงไม่เห็นว่าอะไรกำลังเกิดขึ้น — ย้ายมาเป็นหน้าต่างซ้อน เลือกและดูความคืบหน้าที่เดียวกัน */
  #ov-acexp{z-index:78}
  #ov-acsrc{z-index:84}   /* ต้องอยู่เหนือ #ov-acadd (60) เพราะเปิดซ้อนบนฟอร์ม */
  .acx-opt{display:flex;align-items:center;gap:13px;width:100%;padding:15px 14px;
    margin-bottom:10px;border:1.5px solid var(--line);border-radius:16px;
    background:var(--card);cursor:pointer;font-family:inherit;text-align:left;transition:.12s}
  .acx-opt:last-child{margin-bottom:0}
  .acx-opt:hover{border-color:var(--pri);background:var(--soft)}
  .acx-opt:disabled{opacity:.5;cursor:default}
  .acx-opt .ic{font-size:24px;flex:0 0 auto;line-height:1}
  .acx-opt .tx{flex:1 1 auto;min-width:0}
  .acx-opt .tx b{display:block;font-size:15px;font-weight:800;color:var(--ink)}
  .acx-opt .tx i{display:block;font-style:normal;font-size:11.5px;font-weight:600;
    color:var(--faint);margin-top:2px;line-height:1.5}
  .acx-opt .go{flex:0 0 auto;color:var(--faint);font-size:20px;font-weight:800}
  .acx-state{text-align:center;padding:16px 6px 4px}
  /* ใช้ keyframe acsspin ตัวเดียวกับหน้าบันทึก — วงเดียวหมุนยาว ไม่ได้สร้างใหม่ทุกเฟรม */
  .acx-spin{width:44px;height:44px;margin:0 auto 14px;border-radius:50%;
    border:3.5px solid var(--line);border-top-color:var(--pri);
    animation:acsspin .9s linear infinite}
  .acx-big{font-size:40px;line-height:1;margin-bottom:10px}
  .acx-t{font-size:15px;font-weight:800;color:var(--ink)}
  .acx-s{font-size:12.5px;font-weight:600;color:var(--sub);margin-top:6px;
    line-height:1.6;word-break:break-word}
  /* ป้ายบอกว่าเดือนนี้ดูได้อย่างเดียว — อยู่ใต้ตัวเลือกเดือน ไม่ใช่ลอยกลางหน้า */
  .ac-ro{margin-bottom:12px;padding:10px 13px;border-radius:12px;
    background:rgba(230,206,151,.16);border:1.5px solid rgba(230,206,151,.55);
    font-size:12px;font-weight:700;color:var(--ink);line-height:1.5}
  /* ===== สวิตช์เปิด/ปิด (ใช้ที่การ์ดแจ้งเตือน Telegram ของบัญชี) =====
     ทำเป็นปุ่มจริง ไม่ใช่ checkbox เพราะต้องกดแล้วยิงเซิร์ฟเวอร์ทันที
     และต้องโชว์สถานะ "กำลังบันทึก" ได้ ระหว่างนั้นห้ามกดซ้ำ */
  .tgsw{display:flex;align-items:center;gap:13px;padding:13px 15px;border-radius:14px;
    border:1.5px solid var(--line);background:var(--soft);margin-bottom:10px}
  .tgsw:last-child{margin-bottom:0}
  .tgsw-txt{flex:1;min-width:0}
  .tgsw-t{font-size:14px;font-weight:800;color:var(--ink);line-height:1.35}
  .tgsw-s{font-size:11.5px;color:var(--sub);margin-top:3px;line-height:1.5}
  .tgsw-b{flex:0 0 auto;width:52px;height:30px;border-radius:15px;border:none;padding:0;
    background:#ccd3e0;cursor:pointer;position:relative;transition:background .16s;
    font-family:inherit}
  .tgsw-b::after{content:'';position:absolute;top:3px;left:3px;width:24px;height:24px;
    border-radius:50%;background:#fff;transition:transform .16s;
    box-shadow:0 1px 3px rgba(30,38,60,.35)}
  .tgsw-b.on{background:var(--green)}
  .tgsw-b.on::after{transform:translateX(22px)}
  .tgsw-b:disabled{opacity:.55;cursor:default}
  .tgsw-b.busy{background:var(--yellow)}
  .wchk{display:inline-flex;align-items:center;gap:7px;font-size:14px;font-weight:700;cursor:pointer}
  .wchk input{width:17px;height:17px;accent-color:var(--pri)}
  .wfact{display:flex;gap:10px;justify-content:flex-end;margin-top:18px;
    border-top:1px solid var(--line);padding-top:16px}
  @media(max-width:820px){.wfact .btn{flex:1}.wfrow{gap:10px}}
  /* หัวหน้า UniFi ตรึงไว้ด้านบน — เลื่อนดูอุปกรณ์ยาว ๆ ก็ยังรู้ว่าอยู่ไซต์ไหน */
  .uni-head{margin-bottom:14px;box-shadow:0 6px 14px -12px rgba(34,42,68,.55)}
  @media(max-width:760px){
    .uni-head{gap:11px;padding-top:10px;margin-top:-10px;padding-bottom:8px;margin-bottom:11px}
    .uni-head .uni-logo{height:24px}
    .uni-head .s{font-size:12px;color:var(--sub)}
    .uni-cursite{font-size:12.5px}
  }
  .nav-logo{height:17px;width:auto;vertical-align:middle;display:inline-block;filter:grayscale(.1)}
  .uni-tbl tr.clk{cursor:pointer}
  .uni-tbl tr.clk:hover{background:var(--soft)}
  .uni-tbl th.srt{cursor:pointer;user-select:none;white-space:nowrap}
  .uni-tbl th.srt:hover{color:var(--sub)}
  .uni-tbl th .sar{color:var(--blue);font-size:9px}
  /* ไอคอนหน้าชื่ออุปกรณ์ในตาราง desktop (ให้เหมือนการ์ดมือถือ) */
  .uni-tbl .nmrow{display:flex;align-items:center;gap:10px}
  .uni-tbl .nmtx{min-width:0}
  .uti{width:30px;height:30px;border-radius:8px;background:var(--soft);display:flex;align-items:center;justify-content:center;flex:0 0 auto;border:1.5px solid #c6cddc}
  .uti.g{border-color:var(--green)}.uti.r{border-color:var(--red)}.uti.y{border-color:var(--yellow)}.uti.x{border-color:#c6cddc}
  .uti svg,.udic svg,.umh .ic svg,.umcli .d svg{display:block}
  /* รูปจริงของรุ่นอุปกรณ์ — ไอคอนเส้นเป็น fallback รออยู่ข้างหลัง พอรูปโหลดขึ้นถึงซ่อน
     (รูปเป็น PNG พื้นโปร่ง ถ้าไม่ซ่อนจะเห็นทะลุเป็นภาพซ้อนกัน) */
  .udpicw{position:relative;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto}
  .udpicw.ok svg{visibility:hidden}
  .udpic{position:absolute;left:0;top:0;width:100%;height:100%;object-fit:contain;display:block;
    /* อุปกรณ์ UniFi ส่วนใหญ่สีขาว วางบนพื้นอ่อนแล้วแทบไม่เห็นขอบ —
       ซ้อนเงาสองชั้น: ชั้นแรกตีเส้นขอบให้คม ชั้นสองเป็นเงาใต้ตัวให้ดูลอยขึ้นมา */
    filter:drop-shadow(0 0 .6px rgba(28,38,66,.55)) drop-shadow(0 1.5px 2px rgba(28,38,66,.30))
           saturate(1.06) contrast(1.05)}
  .udic,.uti{background:#e7ebf3}
  .umh .ic{background:#e7ebf3}
  /* เปิด Locate ค้างอยู่ = วงแหวนน้ำเงินกะพริบ ให้รู้ว่าไฟที่ตัวเครื่องยังกระพริบอยู่ ลืมปิดจะเห็นทันที */
  @keyframes uniLoc{
    0%,100%{border-color:#1f6fe0;box-shadow:0 0 0 0 rgba(31,111,224,.5)}
    55%    {border-color:#8ab6f7;box-shadow:0 0 0 5px rgba(31,111,224,0)}
  }
  .udic.loc,.uti.loc,.umh .ic.loc{border:2px solid #1f6fe0;animation:uniLoc 1.15s ease-in-out infinite}
  .uti.loc{border-width:1.5px}
  @media(prefers-reduced-motion:reduce){
    .udic.loc,.uti.loc,.umh .ic.loc{animation:none;box-shadow:0 0 0 3px rgba(31,111,224,.28)}
  }
  /* ปุ่มกรองประเภทอุปกรณ์ (AP / Switch / ฯลฯ) */
  .uni-dfil{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px}
  .uni-dfil button{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line);background:var(--card);color:var(--sub);
    border-radius:99px;padding:6px 12px;font-family:inherit;font-size:12.5px;font-weight:700;cursor:pointer;line-height:1.2}
  .uni-dfil button:hover{background:var(--soft)}
  .uni-dfil button.on{background:var(--blue);border-color:var(--blue);color:#fff}
  .uni-dfil button .n{font-size:11px;font-weight:800;opacity:.85}
  .uni-dfil button.on .n{opacity:1}
  /* modal รายละเอียดอุปกรณ์/client */
  .uni-modal{position:fixed;inset:0;z-index:120;background:rgba(20,26,45,.5);backdrop-filter:blur(2px);
    display:flex;align-items:center;justify-content:center;padding:18px}
  .uni-modal-card{position:relative;background:var(--card);border:1px solid var(--line);border-radius:18px;
    box-shadow:0 24px 60px rgba(20,26,45,.28);width:min(560px,100%);max-height:88vh;overflow:auto;padding:20px 22px;overscroll-behavior:contain}
  .uni-modal-x{position:absolute;top:12px;right:14px;border:0;background:var(--soft);color:var(--sub);
    width:30px;height:30px;border-radius:9px;cursor:pointer;font-size:14px;line-height:1;font-family:inherit}
  .uni-modal-x:hover{background:#e9edf6;color:var(--ink)}
  /* modal อุปกรณ์ UniFi: ปุ่มปิดติดบนถาวร + เนื้อหาเลื่อนแยก (iOS ปิดได้โดยไม่ต้องเลื่อนขึ้นบน) */
  #uni-modal .uni-modal-card{padding:0;overflow:hidden;display:flex;flex-direction:column;max-height:88svh}
  #uni-modal .uni-topbar{flex:0 0 auto;display:flex;justify-content:flex-end;padding:9px 12px 4px;background:var(--card);border-radius:18px 18px 0 0}
  #uni-modal .uni-topbar .uni-modal-x{position:static;top:auto;right:auto}
  #uni-modal #uni-modal-body{flex:1 1 auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;padding:0 22px 20px}
  @media(max-width:760px){#uni-modal #uni-modal-body{padding:0 14px 16px}}
  .umh{display:flex;align-items:center;gap:12px;margin-bottom:4px;padding-right:34px}
  .umh .ic{width:38px;height:38px;border-radius:11px;background:var(--soft);display:flex;align-items:center;justify-content:center;font-size:19px;flex:0 0 auto}
  .umh .t{font-size:17px;font-weight:800;line-height:1.15}
  .umh .s2{font-size:12px;color:var(--sub);margin-top:1px}
  .umsec{margin-top:16px}
  .umsec h5{font-size:10.5px;color:var(--faint);text-transform:uppercase;letter-spacing:.4px;font-weight:800;margin-bottom:8px}
  .umdl{display:grid;grid-template-columns:auto 1fr;gap:6px 16px;font-size:13px}
  .umdl .k{color:var(--sub)}
  .umdl .v{color:var(--ink);font-weight:600;text-align:right;word-break:break-word}
  .umradio{display:flex;gap:10px;flex-wrap:wrap}
  .umradio .rc{flex:1 1 140px;border:1px solid var(--line);border-radius:12px;padding:9px 12px;background:var(--soft)}
  .umradio .rc b{font-size:13px}.umradio .rc .m{font-size:11.5px;color:var(--sub);margin-top:3px;line-height:1.5}
  .umchips{display:flex;gap:6px;flex-wrap:wrap}
  .umchips span{background:var(--soft);border:1px solid var(--line);border-radius:8px;padding:3px 9px;font-size:12px;font-weight:600}
  /* ปุ่มสั่งงานอุปกรณ์ UniFi (Locate / Reboot / Power-cycle) */
  .umacts{display:flex;gap:8px;flex-wrap:wrap;margin:12px 0 2px}
  .umbtn{display:inline-flex;align-items:center;gap:7px;font-family:inherit;font-size:13px;font-weight:700;
    border:1px solid var(--line);background:var(--card);color:var(--ink);border-radius:11px;padding:8px 14px;cursor:pointer;
    transition:transform .14s ease,box-shadow .14s ease,background .14s,border-color .14s,color .14s;-webkit-tap-highlight-color:transparent}
  .umbtn svg{display:block;flex:0 0 auto}
  .umbtn:hover{background:var(--soft);transform:translateY(-1px);box-shadow:0 4px 12px rgba(20,26,45,.10)}
  .umbtn:active{transform:translateY(0) scale(.97)}
  .umbtn:disabled{opacity:.6;cursor:default;transform:none;box-shadow:none}
  .umbtn.act-reboot:hover .ic-reboot{animation:uspin .9s linear infinite}
  /* เมนูเพิ่มเติม — เก็บคำสั่งที่ใช้ไม่บ่อยไว้ข้างใน แถบปุ่มจะได้เหลือแถวเดียว */
  .ummore{position:relative;display:inline-flex}
  .umbtn.act-more.hot::after{content:'';position:absolute;top:5px;right:6px;width:7px;height:7px;
    border-radius:50%;background:#e8a317;box-shadow:0 0 0 2px var(--card)}
  .umbtn.act-more{position:relative}
  .ummenu{display:none;position:absolute;top:calc(100% + 6px);right:0;z-index:6;min-width:238px;
    background:var(--card);border:1px solid var(--line);border-radius:14px;padding:6px;
    box-shadow:0 14px 34px rgba(20,26,45,.20)}
  .ummore.on .ummenu{display:block}
  .ummenu button{display:flex;align-items:center;gap:10px;width:100%;text-align:left;font-family:inherit;
    font-size:13.5px;font-weight:600;color:var(--ink);background:none;border:0;border-radius:10px;
    padding:10px 11px;cursor:pointer;-webkit-tap-highlight-color:transparent}
  .ummenu button:hover{background:var(--soft)}
  .ummenu button.dg{color:var(--red)}
  .ummenu button.dg:hover{background:#fdecec}
  .ummenu svg{flex:0 0 auto;opacity:.75}
  .ummenu .new{margin-left:auto;font-style:normal;font-size:10.5px;font-weight:800;color:#8a6d12;
    background:#fbedc0;border-radius:6px;padding:2px 6px}
  .ummenu .sep{display:block;height:1px;background:var(--line);margin:5px 8px}
  .usshv{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12.5px;word-break:break-all}
  /* แท็บคลื่น — แถบเทียบจำนวนเพื่อนบ้านต่อช่อง */
  .rfl{display:flex;flex-direction:column;gap:5px}
  .rfrow{display:flex;align-items:center;gap:10px}
  .rfrow.me .rfch{color:var(--pri);font-weight:800}
  .rfch{flex:0 0 62px;font-size:12.5px;font-weight:700;color:var(--sub)}
  .rfch i{font-style:normal;font-size:10px;background:#dbeafe;color:#1c4784;border-radius:5px;padding:1px 4px;margin-left:3px}
  .rfbar{position:relative;flex:1;height:14px;border-radius:5px;background:var(--line);overflow:hidden}
  .rfbar i{position:absolute;left:0;top:0;bottom:0;border-radius:5px}
  .rfbar i.all{background:#c3cde0}
  .rfbar i.st{background:#e8730a}
  .rfn{flex:0 0 74px;text-align:right;font-size:12px;color:var(--sub)}
  .rfn b{color:#c25c06}
  /* แถบแจ้งเวอร์ชันใหม่ — ลอยเหนือแถบเมนูล่าง แต่ต่ำกว่ากล่องยืนยัน (240) และ toast (250) */
  .verbar{position:fixed;left:50%;bottom:calc(env(safe-area-inset-bottom,0px) + 84px);
    transform:translateX(-50%) translateY(14px);z-index:235;display:flex;align-items:center;gap:9px;
    background:#1f6fe0;color:#fff;border-radius:14px;padding:11px 14px;cursor:pointer;font-size:13px;
    box-shadow:0 12px 30px rgba(20,50,110,.34);opacity:0;transition:opacity .25s ease,transform .25s ease;
    max-width:calc(100% - 28px)}
  .verbar.on{opacity:1;transform:translateX(-50%) translateY(0)}
  .verbar b{font-weight:800}
  .verbar .t{opacity:.85;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .verbar .d{width:8px;height:8px;border-radius:50%;background:#fff;flex:0 0 auto;
    animation:uniLoc 1.4s ease-in-out infinite}
  .verbar .x{border:0;background:rgba(255,255,255,.18);color:#fff;width:24px;height:24px;
    border-radius:8px;cursor:pointer;flex:0 0 auto;font-size:12px;line-height:1}
  @media(min-width:861px){.verbar{bottom:26px}}
  .rftip{margin-top:12px;background:#eaf6ee;border:1px solid #c6e5d3;color:#1c5637;
    border-radius:12px;padding:10px 12px;font-size:13px;line-height:1.55}
  .hleg i.a{background:#c3cde0}.hleg i.s{background:#e8730a}
  .umbtn.act-power:hover .ic-power{animation:uspin 1.1s linear infinite}
  .umbtn.danger{color:#c9403f;border-color:#f0cccc;background:var(--card)}
  .umbtn.danger:hover{background:#fdeeee;box-shadow:0 4px 12px rgba(201,64,63,.16)}
  .umbtn.sm{padding:6px 11px;font-size:12px;border-radius:9px}
  /* Locate active — ปุ่มเรืองแสง + ไอคอนกระพริบ (จำลอง LED จริง) */
  .umbtn.on{background:#fff7e0;border-color:#e8c34a;color:#8a6d12;animation:uniGlow 1.6s ease-in-out infinite}
  .umbtn.on svg{animation:uniBlink 1s steps(1,end) infinite}
  @keyframes uniGlow{0%,100%{box-shadow:0 0 0 0 rgba(232,195,74,0)}50%{box-shadow:0 0 0 4px rgba(232,195,74,.28)}}
  @keyframes uniBlink{0%,50%{opacity:1}51%,100%{opacity:.25}}
  @keyframes uspin{to{transform:rotate(360deg)}}
  .uspin{transform-origin:center;animation:uspin .8s linear infinite}
  .umbtn.loading{opacity:.9}
  .umports{margin-top:12px;border-top:1px dashed var(--line);padding-top:9px}
  .umports-h{font-size:11px;color:var(--faint);font-weight:800;text-transform:uppercase;letter-spacing:.3px;margin-bottom:7px}
  .umport{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:7px 0;border-bottom:1px solid var(--line)}
  .umport:last-child{border-bottom:0}
  .umport-i{min-width:0;font-size:12.5px}
  /* กล่องยืนยันสวย ๆ (แทน confirm ของเบราว์เซอร์) */
  /* modal ที่ถูกเปิด "ต่อจาก" หน้ารายละเอียดอุปกรณ์ (#uni-modal z-index:120) ต้องอยู่เหนือกว่า */
  #ov-ucfg,#ov-uperm,#ov-unet,#ov-usite,#ov-ublk{z-index:140}
  /* กล่องยืนยันต้องอยู่บนสุดของ UI เสมอ (แผงอัพเฟิร์มแวร์ .uupg-ov อยู่ 210 เคยบังกล่อง "หยุดการอัพ?")
     เหลือแค่ toast (250) ที่สูงกว่า เพราะต้องอ่านออกแม้ตอนมีกล่องยืนยันเปิดอยู่ */
  .uask-ov{position:fixed;inset:0;z-index:240;background:rgba(18,24,42,.46);backdrop-filter:blur(3px);
    display:flex;align-items:center;justify-content:center;padding:20px;opacity:0;transition:opacity .2s ease}
  .uask-ov.on{opacity:1}
  .uask{background:var(--card);border:1px solid var(--line);border-radius:20px;box-shadow:0 24px 70px rgba(20,26,45,.34);
    width:min(400px,100%);padding:22px 22px 18px;text-align:center;opacity:0;transform:translateY(10px) scale(.96);
    transition:transform .22s cubic-bezier(.2,.9,.3,1.2),opacity .2s}
  .uask-ov.on .uask{transform:none;opacity:1}
  .uask-ic{width:56px;height:56px;border-radius:50%;margin:0 auto 12px;display:flex;align-items:center;justify-content:center;background:#eef2fb;color:#2b5fc4}
  .uask.danger .uask-ic{background:#fdeaea;color:#c9403f}
  .uask-t{font-size:17px;font-weight:800;margin-bottom:8px}
  .uask-b{font-size:13px;color:var(--sub);line-height:1.55}
  .uask-b p{margin:9px 0 0}
  .uask-dev{display:flex;align-items:center;gap:9px;justify-content:center;text-align:left;background:var(--soft);
    border:1px solid var(--line);border-radius:12px;padding:9px 12px;margin:8px 0 2px;font-weight:700;color:var(--ink)}
  .uask.danger .uask-dev{color:#a5322f}
  .uask-port{font-size:14px;color:var(--ink);margin-bottom:2px}
  .uask-warn{background:#fdf3e2;border:1px solid #f0d9a8;color:#8a5a12;border-radius:10px;padding:8px 10px;margin-top:10px;font-size:12px;font-weight:600}
  .uask-acts{display:flex;gap:10px;margin-top:16px}
  .uask-btn{flex:1;font-family:inherit;font-size:14px;font-weight:800;border-radius:12px;padding:11px;cursor:pointer;border:1px solid var(--line);transition:.14s}
  .uask-btn.cancel{background:var(--card);color:var(--sub)}
  .uask-btn.cancel:hover{background:var(--soft)}
  .uask-btn.ok{background:var(--blue);border-color:var(--blue);color:#fff}
  .uask-btn.ok:hover{filter:brightness(1.06)}
  .uask.danger .uask-btn.ok{background:#d24b48;border-color:#d24b48}
  /* ปุ่มอัพเฟิร์มแวร์ (device modal) */
  .umbtn.act-upgrade{color:#0f7a4d;border-color:#bfe6d0;background:var(--card)}
  .umbtn.act-upgrade:hover{background:#e9f8f0;box-shadow:0 4px 12px rgba(15,122,77,.16)}
  /* แถบเชิญอัพทั้งไซต์ (dev tab) */
  .uupg-bar{display:flex;align-items:center;gap:11px;flex-wrap:wrap;margin:0 0 12px;padding:11px 14px;
    background:linear-gradient(180deg,#fffdf4,#fff8e6);border:1px solid #ecdca2;border-radius:13px}
  .uupg-bar .ui{width:34px;height:34px;flex:0 0 auto;border-radius:10px;display:flex;align-items:center;justify-content:center;background:#fbedc0;color:#8a6d12}
  .uupg-bar .tx{flex:1 1 200px;min-width:0}
  .uupg-bar .tx b{display:block;font-size:13.5px;color:#7a5f10}
  .uupg-bar .tx span{font-size:12px;color:#9a8330}
  .uupg-bar .go{font-family:inherit;font-size:13px;font-weight:800;border:1px solid #d9b840;background:#f4c430;color:#5a4708;
    border-radius:11px;padding:9px 15px;cursor:pointer;display:inline-flex;align-items:center;gap:7px;transition:.14s}
  .uupg-bar .go:hover{filter:brightness(1.04);transform:translateY(-1px);box-shadow:0 5px 14px rgba(180,140,20,.24)}
  .uupg-bar .go:active{transform:translateY(0) scale(.98)}
  /* แบนเนอร์ "รอรับเข้า" ใช้โทนฟ้า ไม่ให้สับสนกับแบนเนอร์เฟิร์มแวร์สีเหลือง */
  .uupg-bar.adopt{background:#eaf2ff;border-color:#bcd3f5}
  .uupg-bar.adopt .ui{background:#d3e3fb;color:#1f4f96}
  .uupg-bar.adopt .tx b{color:#1c4784}
  .uupg-bar.adopt .tx span{color:#5b7ba8;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block}
  .uupg-bar.adopt .go{background:#2f6fd0;border-color:#2a63ba;color:#fff}
  .umbtn.act-adopt{border-color:#bcd3f5;background:#eaf2ff;color:#1c4784}
  .umbtn.act-rename,.umbtn.act-move,.umbtn.act-prov,.umbtn.act-cfg{border-color:var(--line)}
  /* ---- แท็บประวัติ ---- */
  .hstats{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:14px}
  .hstats>div{background:var(--soft);border-radius:12px;padding:10px 12px;min-width:0}
  .hstats .k{display:block;font-size:11px;color:var(--faint);margin-bottom:3px}
  .hstats b{font-size:17px;font-weight:800}
  .hstats b.bad{color:var(--red)}
  @media(max-width:560px){.hstats{grid-template-columns:repeat(2,1fr)}.hstats b{font-size:15px}}
  .hcard{border:1px solid var(--line);border-radius:14px;padding:12px 12px 6px;margin-bottom:12px;background:#fff}
  .hhead{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;margin-bottom:4px}
  .hhead b{font-size:13.5px}
  .hplot{position:relative}
  .hsvg{display:block;width:100%;height:auto;overflow:visible}
  /* เส้นชี้ + ป้ายค่าเวลาเอาเมาส์/นิ้วลากบนกราฟ */
  .hcur{position:absolute;top:4px;bottom:26px;width:1px;background:var(--sub);opacity:.5;display:none;pointer-events:none}
  .htip{position:absolute;top:0;display:none;pointer-events:none;background:#2b2740;color:#fff;
    border-radius:9px;padding:5px 9px;font-size:11.5px;line-height:1.45;white-space:nowrap;box-shadow:0 6px 18px rgba(20,20,40,.25)}
  .htip b{display:block;font-weight:700;opacity:.75;font-size:10.5px}
  .hap{padding:10px 0;border-bottom:1px solid var(--line)}
  .hap:last-of-type{border-bottom:0}
  .hapt{display:flex;align-items:center;gap:8px;margin-bottom:6px}
  .hapt b{font-size:13.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1}
  .hupbar{position:relative;height:14px;border-radius:5px;overflow:hidden;background:var(--line)}
  .hupbar i{position:absolute;top:0;bottom:0}
  .hupbar i.g{background:var(--green)}
  .hupbar i.r{background:var(--red)}
  .hupbar i.x{background:#dfe4ec}
  .hapd{font-size:11.5px;color:var(--red);margin-top:5px;line-height:1.5}
  .hleg{display:flex;gap:14px;flex-wrap:wrap;font-size:11.5px;color:var(--sub);margin-bottom:10px}
  .hleg span{display:flex;align-items:center;gap:5px}
  .hleg i{width:11px;height:11px;border-radius:3px;display:inline-block}
  .hleg i.g{background:var(--green)}.hleg i.r{background:var(--red)}.hleg i.x{background:#dfe4ec}
  /* กล่องตั้งค่าอุปกรณ์ */
  .ucfg{border:1px solid var(--line);border-radius:14px;padding:13px 14px;margin-bottom:12px;background:#fff}
  .ucfg h5{margin:0 0 10px;font-size:12px;color:var(--faint);text-transform:uppercase;letter-spacing:.4px;font-weight:800}
  .ucfg2{display:grid;grid-template-columns:1fr 1fr;gap:10px}
  .ucfg3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px}
  @media(max-width:520px){.ucfg2,.ucfg3{grid-template-columns:1fr}}
  .ucfgr{border-top:1px dashed var(--line);padding-top:11px;margin-top:11px}
  .ucfgr:first-of-type{border-top:0;padding-top:0;margin-top:0}
  .ucfgt{font-weight:800;font-size:13.5px;margin-bottom:7px}
  /* สิทธิ์ของฉัน */
  .upmine{font-size:13.5px;background:var(--soft);border-radius:12px;padding:11px 13px;margin-bottom:12px}
  .upgrp{margin-bottom:14px}
  .upgrp h5{margin:0 0 7px;font-size:11.5px;color:var(--faint);text-transform:uppercase;letter-spacing:.4px;font-weight:800}
  .uprow{display:flex;gap:9px;align-items:flex-start;font-size:13px;padding:4px 0;color:var(--sub)}
  .uprow.on{color:var(--ink)}
  .upi{flex:0 0 auto;width:17px;text-align:center;font-weight:800;color:var(--faint)}
  .uprow.on .upi{color:var(--green)}
  /* สิทธิ์ในหน้าผู้ดูแลระบบ — เป็นรายการ ไม่ใช่ตาราง จึงไม่ล้นจอมือถือ */
  .upwrap{margin-top:14px;border-top:1px solid var(--line);padding-top:6px}
  .uplg{font-weight:800;font-size:11.5px;color:var(--sub);text-transform:uppercase;letter-spacing:.4px;
    background:var(--soft);border-radius:8px;padding:7px 10px;margin:14px 0 4px}
  .uplr{display:flex;align-items:center;gap:10px;padding:8px 2px;border-bottom:1px solid var(--line)}
  .upll{flex:1 1 auto;min-width:0;font-size:13px;color:var(--ink);line-height:1.45}
  .uplc{flex:0 0 auto;display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}
  .upck{display:inline-flex;align-items:center;gap:6px;cursor:pointer;user-select:none;
    border:1px solid var(--line);border-radius:999px;padding:5px 10px;font-size:12px;color:var(--sub);
    background:var(--card);white-space:nowrap;transition:.12s}
  .upck input{width:15px;height:15px;cursor:pointer;margin:0;flex:0 0 auto}
  .upck.on{border-color:var(--green);color:var(--green);background:rgba(34,197,94,.10);font-weight:700}
  .upck.fix{cursor:not-allowed;opacity:.6}
  .upck.fix input{cursor:not-allowed}
  /* ชื่อเดิมคือ .upbar แต่ไปทับกราฟแท่ง uptime หน้า Services (.upbar ที่ตั้ง height:26px)
     พอถูกทับ แท่งกราฟสูงเป็นศูนย์แล้วหายทั้งแถว — เปลี่ยนชื่อให้ไม่ชนกัน */
  .upsvbar{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-top:14px}
  @media(max-width:560px){
    .uplr{flex-direction:column;align-items:stretch;gap:7px;padding:10px 2px}
    .upll{font-weight:600}
    .uplc{justify-content:flex-start}
    .upck{flex:1 1 auto;justify-content:center;padding:7px 8px}
    .upsvbar .btn{flex:1 1 100%}
  }
  /* บันทึกเหตุการณ์จาก controller */
  .evrow{display:flex;gap:10px;align-items:flex-start;padding:9px 2px;border-bottom:1px solid var(--line)}
  .evrow:last-child{border-bottom:0}
  .evi{flex:0 0 auto;width:24px;height:24px;border-radius:7px;display:flex;align-items:center;
    justify-content:center;font-size:12px;background:var(--soft)}
  .evi.dn{background:rgba(201,74,74,.13)}
  .evi.up{background:rgba(47,143,99,.14)}
  .evi.ad{background:rgba(59,130,246,.13)}
  .evi.wa{background:rgba(224,161,44,.16)}
  .evb{flex:1 1 auto;min-width:0}
  .evt1{font-size:13.5px;color:var(--ink);line-height:1.45;word-break:break-word}
  .evt1 b{font-weight:800}
  .evt2{font-size:11.5px;color:var(--faint);margin-top:2px}
  .evtm{flex:0 0 auto;font-size:11.5px;color:var(--faint);white-space:nowrap;padding-top:2px}
  .evempty{padding:18px 4px;text-align:center;color:var(--faint);font-size:13px}
  .evrow.tap{cursor:pointer}
  .evrow.tap:hover{background:var(--soft)}
  .evdev{color:var(--pri);font-weight:700;text-decoration:underline;text-underline-offset:2px}
  /* แถบบอกว่ากำลังกรองดูอุปกรณ์ตัวไหนอยู่ */
  .evfil{display:flex;align-items:center;gap:8px;flex-wrap:wrap;background:rgba(59,130,246,.09);
    border:1px solid var(--pri);border-radius:11px;padding:8px 11px;margin:2px 0 10px;font-size:13px}
  .evfil b{font-weight:800;color:var(--ink)}
  .evfil .x{margin-left:auto;cursor:pointer;font-weight:800;color:var(--pri);
    border:1px solid var(--pri);border-radius:999px;padding:2px 10px;font-size:12px;background:var(--card)}
  .evpick{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:8px}
  .evpick button{font-family:inherit;font-size:12px;font-weight:700;border:1px solid var(--line);
    border-radius:999px;padding:5px 11px;background:var(--card);color:var(--sub);cursor:pointer;max-width:100%;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .evpick button.on{border-color:var(--pri);color:var(--pri);background:rgba(59,130,246,.10)}
  .evpick button .n{opacity:.65;font-weight:600}
  .hapev{margin-top:6px;display:flex;flex-wrap:wrap;gap:5px}
  .hapev span{font-size:11px;border-radius:999px;padding:2px 8px;background:var(--soft);color:var(--sub);white-space:nowrap}
  .hapev span.dn{background:rgba(201,74,74,.12);color:var(--red);font-weight:700}
  .hapev span.up{background:rgba(47,143,99,.13);color:var(--green);font-weight:700}
  @media(max-width:560px){.evtm{font-size:11px}.evt1{font-size:13px}}
  /* ===== แท็บเครือข่าย (MikroTik) ===== */
  .mtgw{display:flex;align-items:center;gap:12px;flex-wrap:wrap;background:var(--card);
    border:1px solid var(--line);border-radius:14px;padding:12px 14px;margin-bottom:12px;box-shadow:var(--shadow-sm)}
  .mtgw .nm{font-weight:800;font-size:14.5px;color:var(--ink)}
  .mtgw .ad{font-size:12px;color:var(--faint)}
  .mtgw .sp{margin-left:auto;display:flex;gap:14px;flex-wrap:wrap;align-items:center}
  .mtgw .kv{text-align:center}
  .mtgw .kv b{display:block;font-size:17px;font-weight:800;line-height:1.15}
  .mtgw .kv span{font-size:10.5px;color:var(--faint);text-transform:uppercase;letter-spacing:.3px}
  .mtgw .kv.g b{color:var(--green)} .mtgw .kv.r b{color:var(--red)} .mtgw .kv.y b{color:#e0a12c}
  .mtgw.bad{border-color:var(--red);background:rgba(201,74,74,.05)}
  .mtrow{display:flex;align-items:center;gap:10px;padding:9px 4px;border-bottom:1px solid var(--line);font-size:13.5px}
  .mtrow:last-child{border-bottom:0}
  .mtdot{flex:0 0 auto;width:9px;height:9px;border-radius:50%;background:#98a2b3}
  .mtdot.up{background:var(--green);box-shadow:0 0 0 3px rgba(47,143,99,.15)}
  .mtdot.down{background:var(--red);box-shadow:0 0 0 3px rgba(201,74,74,.16)}
  .mtnm{flex:1 1 auto;min-width:0;font-weight:700;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .mtsub{font-size:11.5px;color:var(--faint);font-weight:400}
  .mtt{flex:0 0 auto;font-size:12px;color:var(--sub);white-space:nowrap}
  .mtt.bad{color:var(--red);font-weight:700}
  .mtbadge{flex:0 0 auto;font-size:10.5px;font-weight:800;border-radius:999px;padding:2px 8px;white-space:nowrap}
  .mtbadge.dup{background:rgba(224,161,44,.18);color:#a06c0d}
  .mtbadge.old{background:var(--soft);color:var(--faint)}
  .mtbadge.ok{background:rgba(47,143,99,.15);color:var(--green)}
  .mtbadge.no{background:rgba(201,74,74,.13);color:var(--red)}
  .mtbadge.wait{background:var(--soft);color:var(--sub)}
  .mtbadge.hid{background:rgba(120,80,180,.15);color:#6b46c1}
  .mtzap{flex:0 0 auto;border:1px solid var(--line);background:var(--card);color:var(--sub);
    border-radius:9px;padding:3px 8px;font-size:12px;line-height:1.5;cursor:pointer}
  .mtzap:hover{border-color:var(--ink);color:var(--ink)}
  .mtzap[disabled]{opacity:.5;cursor:default}
  .mtrow.hid{background:repeating-linear-gradient(135deg,transparent,transparent 7px,rgba(120,80,180,.05) 7px,rgba(120,80,180,.05) 14px)}
  .mtrow.click{cursor:pointer}
  .mtrow.click:hover{background:var(--soft)}
  .mtgo{flex:0 0 auto;color:var(--faint);font-size:15px;line-height:1}
  /* ---- หน้ารายละเอียดเราเตอร์ ---- */
  .mtd-tabs{display:flex;gap:6px;flex-wrap:wrap;margin:2px 0 12px}
  .mtd-tabs button{border:1px solid var(--line);background:var(--card);color:var(--sub);
    border-radius:999px;padding:6px 13px;font-size:12.5px;font-weight:700;cursor:pointer}
  .mtd-tabs button.on{background:var(--ink);color:#fff;border-color:var(--ink)}
  .mtd-kpi{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px;margin-bottom:12px}
  .mtd-kpi .b{background:var(--soft);border-radius:12px;padding:9px 11px}
  .mtd-kpi .b b{display:block;font-size:15px;font-weight:800;line-height:1.25;word-break:break-word}
  .mtd-kpi .b span{font-size:10.5px;color:var(--faint);text-transform:uppercase;letter-spacing:.3px}
  /* ---- ตารางข้อมูลเครื่องแบบกะทัดรัด: ป้ายเล็ก ค่าไม่ตัวโต ----
     ของเดิมใช้บล็อกตัวใหญ่ ทำให้ชื่อรุ่นยาว ๆ ดูล้นและแย่งความสนใจเกินจำเป็น */
  .mtd-inf{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:2px 18px;margin-bottom:12px}
  .mtd-inf div{display:flex;gap:10px;align-items:baseline;padding:5px 0;border-bottom:1px solid var(--line);min-width:0}
  .mtd-inf span{font-size:11px;color:var(--faint);font-weight:700;flex:0 0 88px}
  .mtd-inf b{font-size:12.5px;font-weight:600;color:var(--ink);min-width:0;word-break:break-word}
  .mtd-upd{display:flex;gap:9px;align-items:flex-start;background:rgba(224,161,44,.1);
    border:1px solid rgba(224,161,44,.5);border-radius:11px;padding:9px 12px;margin-bottom:12px;
    font-size:12.5px;line-height:1.55;color:var(--sub)}
  .mtd-upd b{color:#a06c0d}
  .mtd-stale{display:flex;gap:9px;align-items:flex-start;background:var(--soft);
    border:1px solid var(--line);border-radius:11px;padding:9px 12px;margin-bottom:12px;
    font-size:12.5px;line-height:1.55;color:var(--sub)}
  .mtd-stale b{color:var(--ink)}
  /* ---- ตารางพอร์ต ---- */
  .mtp{width:100%;border-collapse:collapse;font-size:12.5px}
  .mtp th{text-align:left;font-size:10.5px;color:var(--faint);text-transform:uppercase;
    letter-spacing:.3px;padding:6px 8px;border-bottom:1px solid var(--line);white-space:nowrap}
  .mtp td{padding:7px 8px;border-bottom:1px solid var(--line);vertical-align:middle}
  .mtp tr:last-child td{border-bottom:0}
  .mtp .nm{font-weight:700}
  .mtp .sp{font-variant-numeric:tabular-nums;white-space:nowrap;font-size:12px}
  .mtp .sp i{font-style:normal;color:var(--faint);margin-right:3px}
  .mtp .up{background:rgba(47,143,99,.13);color:var(--green);border-radius:999px;
    padding:2px 8px;font-size:10px;font-weight:800;white-space:nowrap}
  .mtpsw{border:1px solid var(--line);background:var(--card);color:var(--sub);border-radius:8px;
    padding:4px 9px;font-size:11.5px;font-weight:700;cursor:pointer;white-space:nowrap}
  .mtpsw:hover{border-color:var(--ink);color:var(--ink)}
  .mtpsw.off{color:var(--red);border-color:rgba(201,74,74,.4)}
  .mtpsw[disabled]{opacity:.45;cursor:default}
  .mtprow{cursor:pointer}
  .mtprow:hover{background:var(--soft)}
  .mtprow.op{background:var(--soft)}
  .mtprow .ar{color:var(--faint);margin-left:6px;font-size:10px}
  .mtpdet td{padding:0 0 12px;border-bottom:1px solid var(--line)}
  .mtpx{background:var(--soft);border-radius:12px;padding:12px 14px}
  .mtpl{display:flex;gap:9px;align-items:center;flex-wrap:wrap;font-size:12.5px;
    padding-bottom:10px;margin-bottom:10px;border-bottom:1px solid var(--line)}
  .mtpl b{font-size:13.5px;font-weight:800;color:var(--sub)}
  .mtpl.on b{color:var(--green)} .mtpl.off b{color:var(--red)}
  .mtpl span{background:var(--card);border:1px solid var(--line);border-radius:999px;
    padding:2px 9px;font-size:11px;font-weight:700;color:var(--sub);white-space:nowrap}
  .mtpl span.w{border-color:#e0a12c;color:#a06c0d}
  .mtpl span.u{border-color:rgba(47,143,99,.5);color:var(--green)}
  .mtpspd{display:grid;grid-template-columns:1fr 1fr;gap:9px}
  .mtpspd div{background:var(--card);border:1px solid var(--line);border-radius:11px;padding:8px 11px}
  .mtpspd i{display:block;font-style:normal;font-size:10.5px;color:var(--faint);font-weight:700}
  .mtpspd b{display:block;font-size:15px;font-weight:800;line-height:1.3;font-variant-numeric:tabular-nums}
  .mtpspd span{font-size:10.5px;color:var(--faint)}
  .mtpx .mtd-inf{margin-bottom:0}
  /* ---- ภาพรวมไซต์ ---- */
  .avrow{display:flex;align-items:center;gap:10px;padding:9px 4px;border-bottom:1px solid var(--line);font-size:13px}
  .avrow:last-child{border-bottom:0}
  .avnm{flex:1 1 auto;min-width:0;font-weight:700;color:var(--ink);
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .avc{flex:0 0 auto;width:118px;text-align:left;padding-left:10px;border-left:2px solid var(--line)}
  .avc b{display:block;font-size:10.5px;font-weight:800;letter-spacing:.3px;color:var(--faint);text-transform:uppercase}
  .avc span{display:block;font-size:11.5px;color:var(--sub);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .avc.ok{border-left-color:var(--green)} .avc.ok b{color:var(--green)}
  .avc.no{border-left-color:var(--red)} .avc.no b{color:var(--red)} .avc.no span{color:var(--red);font-weight:700}
  .avc.warn{border-left-color:#e0a12c} .avc.warn b{color:#a06c0d}
  .avc.na{opacity:.45}
  .avgo{flex:0 0 auto;display:flex;gap:4px}
  .avgo button{border:1px solid var(--line);background:var(--card);color:var(--faint);
    border-radius:8px;padding:4px;line-height:0;cursor:pointer}
  .avgo button svg{width:14px;height:14px}
  .avgo button:hover{border-color:var(--ink);color:var(--ink)}
  .avrow.bad{background:rgba(201,74,74,.04)}
  @media(max-width:760px){
    .avrow{flex-wrap:wrap;gap:7px}
    .avnm{flex:1 1 100%}
    .avc{width:auto;flex:1 1 30%;min-width:96px}
    .avgo{flex:1 1 100%;justify-content:flex-end}
  }
  /* ---- ไทม์ไลน์เหตุการณ์ ---- */
  .evday{font-size:11px;font-weight:800;color:var(--faint);text-transform:uppercase;
    letter-spacing:.3px;margin:14px 0 5px;padding-bottom:4px;border-bottom:1px solid var(--line)}
  .evday:first-child{margin-top:0}
  .evrow{display:flex;align-items:flex-start;gap:9px;padding:7px 2px;font-size:12.5px}
  .evi{flex:0 0 auto;width:20px;height:20px;border-radius:7px;display:flex;align-items:center;
    justify-content:center;font-size:11px;font-weight:800;background:var(--soft);color:var(--faint)}
  .evi.ok{background:rgba(47,143,99,.14);color:var(--green)}
  .evi.no{background:rgba(201,74,74,.13);color:var(--red)}
  .evi.warn{background:rgba(224,161,44,.16);color:#a06c0d}
  .evt{flex:0 0 auto;width:42px;color:var(--faint);font-size:11.5px;font-variant-numeric:tabular-nums;padding-top:2px}
  .evx{flex:1 1 auto;min-width:0;line-height:1.5}
  .evd{display:block;font-size:11.5px;color:var(--sub)}
  .evb{flex:0 0 auto;border:0;background:transparent;color:var(--faint);cursor:pointer;font-size:16px;line-height:1;padding:0 2px}
  .evb:hover{color:var(--ink)}
  /* ---- วิเคราะห์ปัญหา ----
     งานนี้ผู้ใช้ต้องนั่งรอ 5-15 วินาที ภาพเคลื่อนไหวจึงไม่ใช่ของประดับ
     แต่คือตัวบอกว่า "ระบบยังทำงานอยู่ และตอนนี้กำลังตรวจอะไร"
     ทุก animation มีทางปิดผ่าน prefers-reduced-motion                     */
  .dghero{position:relative;overflow:hidden;border-radius:16px;padding:15px 17px 14px;
    margin-bottom:14px;background:linear-gradient(135deg,rgba(91,124,250,.10),rgba(72,201,138,.08));
    border:1px solid var(--line)}
  .dghero::after{content:"";position:absolute;inset:0;pointer-events:none;
    background:linear-gradient(100deg,transparent 30%,rgba(255,255,255,.35) 50%,transparent 70%);
    transform:translateX(-100%);animation:dgsweep 2.1s ease-in-out infinite}
  .dghero.fin::after{animation:none;opacity:0}
  @keyframes dgsweep{to{transform:translateX(100%)}}
  .dghrow{display:flex;align-items:center;gap:14px}
  .dgring{flex:0 0 auto;width:54px;height:54px;position:relative}
  .dgring svg{width:54px;height:54px;transform:rotate(-90deg);display:block}
  .dgring circle{fill:none;stroke-width:5;stroke-linecap:round}
  .dgring .bg{stroke:var(--line)}
  .dgring .fg{stroke:var(--green);transition:stroke-dashoffset .5s cubic-bezier(.4,0,.2,1),stroke .4s}
  .dgring.warn .fg{stroke:#e0a12c} .dgring.bad .fg{stroke:var(--red)}
  .dgrnum{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
    font-size:12.5px;font-weight:800;color:var(--ink);font-variant-numeric:tabular-nums}
  .dghtx{min-width:0;flex:1 1 auto}
  .dghtx b{display:block;font-size:14px;font-weight:800;color:var(--ink);line-height:1.4}
  .dghtx span{display:block;font-size:11.5px;color:var(--sub);line-height:1.55;margin-top:2px}
  .dgpct{display:none}
  .dgsteps{display:flex;flex-direction:column;gap:2px}
  .dgstep{display:flex;gap:12px;align-items:flex-start;padding:10px 10px;border-radius:12px;
    transition:background .3s,opacity .3s,transform .3s;opacity:1;position:relative}
  .dgstep.wait{opacity:.38}
  .dgstep.run{background:var(--soft)}
  .dgstep.run::before{content:"";position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:3px;
    background:var(--green);animation:dgpulse 1.1s ease-in-out infinite}
  @keyframes dgpulse{0%,100%{opacity:.35;transform:scaleY(.6)}50%{opacity:1;transform:scaleY(1)}}
  .dgstep.hit{animation:dgpop .42s cubic-bezier(.34,1.56,.64,1)}
  @keyframes dgpop{0%{transform:translateY(5px);opacity:.3}100%{transform:none;opacity:1}}
  .dgnm{font-size:13px;font-weight:700;color:var(--ink);line-height:1.4}
  .dgln{font-size:11.5px;color:var(--sub);line-height:1.55;margin-top:2px;white-space:pre-line}
  .dgstep.wait .dgln{color:var(--faint)}
  .dgdot{flex:0 0 auto;width:20px;height:20px;border-radius:50%;margin-top:1px;background:var(--line);
    display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:900;color:#fff}
  .dgdot.ok{background:var(--green)} .dgdot.warn{background:#e0a12c}
  .dgdot.bad{background:var(--red)}
  .dgdot.skip{background:transparent;border:2px dashed var(--line);color:var(--faint);font-size:10px}
  .dgdot.wait{background:transparent;border:2px solid var(--line)}
  .dgspin{flex:0 0 auto;width:20px;height:20px;margin-top:1px;border-radius:50%;
    border:2px solid var(--line);border-top-color:var(--green);animation:dgsp .7s linear infinite}
  @keyframes dgsp{to{transform:rotate(360deg)}}
  .dgsum{border:1px solid var(--line);border-radius:16px;padding:15px 17px;margin-top:16px;background:var(--soft);
    animation:dgrise .45s cubic-bezier(.34,1.3,.64,1)}
  @keyframes dgrise{0%{transform:translateY(10px);opacity:0}100%{transform:none;opacity:1}}
  .dgsum.ok{border-color:rgba(47,143,99,.5);background:rgba(47,143,99,.06)}
  .dgsum.warn{border-color:rgba(224,161,44,.55);background:rgba(224,161,44,.07)}
  .dgsum.bad{border-color:rgba(201,74,74,.5);background:rgba(201,74,74,.05)}
  .dgh{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-bottom:7px}
  .dgh b{font-size:15.5px;font-weight:800;color:var(--ink);line-height:1.4;flex:1 1 200px;min-width:0}
  .dgv{font-size:11px;font-weight:800;letter-spacing:.3px;white-space:nowrap;color:#fff;
    border-radius:999px;padding:4px 11px;background:var(--faint)}
  .dgv.ok{background:var(--green)} .dgv.warn{background:#c88a12}
  .dgv.bad{background:var(--red)} .dgv.off{background:#98a2b3}
  .dgwhy{font-size:12.5px;line-height:1.7;color:var(--sub)}
  .dgact{margin-top:12px;font-size:12.5px;line-height:1.7}
  .dgact b{display:block;font-size:11px;color:var(--faint);text-transform:uppercase;letter-spacing:.3px;margin-bottom:5px}
  .dgact ol{margin:0;padding-left:20px}
  .dgact li{margin-bottom:3px;color:var(--sub)}
  .dgfind{display:flex;flex-direction:column;gap:7px}
  /* หัวข้อหมวดของข้อสังเกต — เบากว่าหัวเรื่องหลัก แต่หนักพอให้ตาจับได้ว่าขึ้นหมวดใหม่ */
  .dgsec{display:flex;align-items:baseline;gap:8px;margin:13px 2px 7px;
    font-size:12.5px;font-weight:800;color:var(--ink)}
  .dgsec:first-of-type{margin-top:2px}
  .dgsec .n{font-size:11px;font-weight:700;color:var(--faint)}
  .dgf{display:flex;gap:10px;align-items:flex-start;font-size:12.5px;line-height:1.65;color:var(--sub);
    background:var(--card);border:1px solid var(--line);border-radius:11px;padding:9px 11px;
    white-space:pre-line;border-left-width:3px;animation:dgrise .35s ease both}
  .dgf span{flex:0 0 auto;width:7px;height:7px;border-radius:50%;margin-top:7px;background:var(--faint)}
  .dgf.warn{border-left-color:#e0a12c} .dgf.warn span{background:#e0a12c}
  .dgf.bad{border-left-color:var(--red)} .dgf.bad span{background:var(--red)}
  .dgf.info{border-left-color:var(--pri,#5b7cfa)} .dgf.info span{background:var(--pri,#5b7cfa)}
  .dgf.ok{border-left-color:var(--green)} .dgf.ok span{background:var(--green)}
  /* ---- iOS ซูมหน้าจอเองตอนกดช่องกรอก ----
     Safari บน iPhone จะซูมเข้าอัตโนมัติถ้าช่องที่โฟกัส "ตัวอักษรเล็กกว่า 16px"
     ทางแก้ที่เจอบ่อยคือใส่ maximum-scale=1 / user-scalable=no ใน viewport
     แต่แบบนั้น "ผู้ใช้จะซูมเองไม่ได้เลย" ซึ่งเสียการเข้าถึงไปทั้งแอป
     -> แก้ที่ต้นเหตุแทน: บังคับช่องกรอกทุกชนิดเป็น 16px เฉพาะเครื่องที่ใช้นิ้ว
     ซูมด้วยสองนิ้วยังทำได้ตามปกติ มีแค่การซูมอัตโนมัติที่หายไป */
  @media (hover:none) and (pointer:coarse){
    input:not([type=checkbox]):not([type=radio]):not([type=range]),
    select, textarea{font-size:16px !important}
  }
  @media (prefers-reduced-motion:reduce){
    .dgspin{animation-duration:2s}
    .dghero::after,.dgstep.run::before{animation:none}
    .dgstep.hit,.dgsum,.dgf{animation:none}
  }
  .mtd-tbl{width:100%;border-collapse:collapse;font-size:12.5px}
  .mtd-tbl th{text-align:left;font-size:10.5px;color:var(--faint);text-transform:uppercase;
    letter-spacing:.3px;padding:6px 8px;border-bottom:1px solid var(--line);white-space:nowrap}
  .mtd-tbl td{padding:7px 8px;border-bottom:1px solid var(--line);vertical-align:top}
  .mtd-tbl tr:last-child td{border-bottom:0}
  .mtd-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
  .mtd-st{width:8px;height:8px;border-radius:50%;display:inline-block;background:#98a2b3}
  .mtd-st.on{background:var(--green)} .mtd-st.off{background:var(--red)}
  .mtd-h{font-size:11.5px;color:var(--faint);text-transform:uppercase;letter-spacing:.4px;
    font-weight:800;margin:0 0 8px}
  .mtd-note{background:var(--soft);border-radius:12px;padding:11px 13px;font-size:12.5px;
    color:var(--sub);line-height:1.65;margin-bottom:12px}
  .mtd-mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}
  .mtping{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:10px}
  .mtping input{flex:1 1 180px;min-width:0;border:1px solid var(--line);border-radius:10px;
    padding:9px 11px;font:inherit;font-size:13px;background:var(--card);color:var(--ink)}
  /* ---- จับคู่ไซต์ข้ามระบบ ---- */
  .mtlrow{border:1px solid var(--line);border-radius:14px;padding:11px 13px;margin-bottom:9px;background:var(--card)}
  .mtlrow .hd{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:13.5px}
  .mtlrow .hd .spacer{flex:1 1 auto}
  .mtlrow .hd .btn{padding:5px 11px;font-size:12px}
  .mtlrow .ch{display:flex;gap:7px;flex-wrap:wrap;margin-top:9px;align-items:center}
  .mtlchip{border:1px solid;border-radius:999px;padding:3px 10px;font-size:11.5px;font-weight:700;white-space:nowrap}
  .mtlchip .x{margin-left:6px;cursor:pointer;opacity:.65;font-weight:900}
  .mtlchip .x:hover{opacity:1}
  .mtlsc{font-size:11px;color:var(--faint);font-weight:700}
  /* ---- แผนผังเส้นทางจริง: อุปกรณ์ → เราเตอร์ไซต์ → เน็ต → เซิร์ฟเวอร์ ----
     ไอคอนเป็นลายเส้นชุดเดียวกับเมนูหลัก และเส้นไหลใช้แสงวิ่งนุ่ม ๆ ไม่ใช่จุดแข็ง ๆ */
  .nch{border:1px solid var(--line);border-radius:14px;background:var(--card);
    padding:10px 12px 8px;margin:0 0 10px}
  .nch-top{display:flex;align-items:center;gap:8px}
  /* padding-top เผื่อ badge ที่ยื่นพ้นขอบไอคอน — overflow-x:auto ทำให้แนวตั้งถูกตัดด้วย
     ถ้าไม่เผื่อไว้ ตัวเลขจะโดนเฉือนหัว (เจอจริงบนมือถือ) */
  .nch-r{display:flex;align-items:stretch;flex:1 1 auto;min-width:0;overflow-x:auto;
    -webkit-overflow-scrolling:touch;scrollbar-width:none;padding:8px 3px 0}
  .nch-r::-webkit-scrollbar{display:none}
  .nch-c{flex:0 0 auto;width:62px;display:flex;flex-direction:column;align-items:center;gap:4px}
  .nch-c.two{width:82px}
  .nch-st{display:flex;gap:14px;align-items:flex-start;justify-content:center;flex:1 1 auto}
  /* ไอคอนอุปกรณ์วางเรียงข้างกัน แต่ละตัวมีป้ายชื่อของตัวเอง —
     เดิมวางซ้อนบนล่าง ทำให้ badge ของตัวล่างไปทับตัวบน อ่านไม่ออกโดยเฉพาะบนมือถือ */
  .nch-one{display:flex;flex-direction:column;align-items:center;gap:3px}
  .nch-n{position:relative;width:32px;height:32px;border-radius:11px;display:flex;
    align-items:center;justify-content:center;border:1.5px solid var(--line);
    background:var(--soft);color:var(--faint);transition:border-color .25s,color .25s}
  .nch-n.sm{width:26px;height:26px;border-radius:9px}
  .nch-n svg{width:17px;height:17px;display:block}
  .nch-n.sm svg{width:14px;height:14px}
  .nch-n.ok{border-color:rgba(47,143,99,.45);color:var(--green);background:rgba(47,143,99,.07)}
  .nch-n.bad{border-color:var(--red);color:var(--red);background:rgba(201,74,74,.08)}
  .nch-t{font-size:9px;color:var(--faint);line-height:1.2;font-weight:700;text-align:center;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
  .nch-b{position:absolute;top:-7px;right:-6px;min-width:16px;height:16px;border-radius:99px;
    font-size:9.5px;font-weight:800;line-height:16px;text-align:center;padding:0 5px;
    background:#e0a12c;color:#fff;box-shadow:0 0 0 2px var(--card);letter-spacing:-.2px;
    white-space:nowrap;box-sizing:border-box}
  .nch-b.r{background:var(--red)}
  .nch-t2{font-size:8.5px;color:var(--faint);font-weight:700;line-height:1;white-space:nowrap}
  /* เส้นเชื่อม: รางบาง ๆ + แสงวิ่งผ่านแบบไล่ระดับ (นุ่มกว่าจุดวิ่ง) */
  .nch-l{flex:1 1 auto;min-width:26px;position:relative;align-self:flex-start;margin-top:14px;height:3px}
  .nch-l .tr{position:absolute;left:-3px;right:-3px;top:0;height:3px;border-radius:3px;
    background:var(--line);overflow:hidden}
  .nch-l.ok .tr{background:rgba(47,143,99,.22)}
  .nch-l.bad .tr{background:transparent;
    background-image:linear-gradient(90deg,var(--red) 0 5px,transparent 5px 10px);background-size:10px 3px}
  .nch-l.ok .tr:after{content:'';position:absolute;top:0;left:-45%;width:45%;height:100%;
    background:linear-gradient(90deg,transparent,var(--green),transparent);
    animation:nchglow 2.6s cubic-bezier(.4,0,.35,1) infinite}
  @keyframes nchglow{0%{left:-45%}100%{left:100%}}
  @media (prefers-reduced-motion:reduce){.nch-l.ok .tr:after{animation:none;left:28%}}
  /* แถวปุ่มข้ามระบบ — อยู่ "นอก" กล่องแผนผัง จะได้ไม่ทับเส้นทางที่วาดไว้ */
  .nchgo{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin:8px 0 2px}
  .nchgo-l{font-size:10.5px;font-weight:800;letter-spacing:.3px;text-transform:uppercase;
    color:var(--faint);margin-right:2px}
  .nchgo button{display:inline-flex;align-items:center;gap:6px;font-family:inherit;
    font-size:12px;font-weight:700;color:var(--sub);cursor:pointer;
    border:1px solid var(--line);background:var(--card);border-radius:999px;padding:5px 11px 5px 9px;
    transition:border-color .18s,color .18s}
  .nchgo button svg{width:15px;height:15px;flex:0 0 auto}
  .nchgo button:hover{border-color:var(--pri);color:var(--pri)}
  .nch-v{font-size:11.5px;line-height:1.45;color:var(--sub);margin-top:8px;
    padding-top:6px;border-top:1px dashed var(--line)}
  .nch-v b{color:var(--ink)}
  .nch-v .dot{display:inline-block;width:6px;height:6px;border-radius:50%;
    background:var(--green);margin-right:6px;vertical-align:1px}
  .nch.warn{border-color:rgba(224,161,44,.55)}
  .nch.warn .nch-v b{color:#a06c0d} .nch.warn .nch-v .dot{background:#e0a12c}
  .nch.bad{border-color:rgba(201,74,74,.55)}
  .nch.bad .nch-v b{color:var(--red)} .nch.bad .nch-v .dot{background:var(--red)}
  .mtlsc.no{color:var(--faint);font-weight:400;font-style:italic}
  .mtlf{margin-bottom:11px}
  .mtlf label{display:block;font-size:11.5px;color:var(--faint);font-weight:800;
    text-transform:uppercase;letter-spacing:.3px;margin-bottom:5px}
  .mtlf input,.mtlf select{width:100%;border:1px solid var(--line);border-radius:10px;
    padding:9px 11px;font:inherit;font-size:13px;background:var(--card);color:var(--ink)}
  .mtlpick{position:relative}
  .mtlopts{display:none;position:absolute;left:0;right:0;top:calc(100% + 4px);z-index:5;
    max-height:190px;overflow-y:auto;-webkit-overflow-scrolling:touch;
    border:1px solid var(--line);border-radius:10px;background:var(--card);
    box-shadow:var(--shadow);padding:4px}
  .mtlopts.on{display:block}
  .mtlopt{display:block;width:100%;text-align:left;border:0;background:transparent;color:var(--ink);
    font:inherit;font-size:13px;padding:8px 10px;border-radius:8px;cursor:pointer}
  .mtlopt:hover{background:var(--soft)}
  .mtlopt.hide{display:none}
  .mtlnone{padding:9px 10px;font-size:12px;color:var(--faint)}
  @media(max-width:560px){
    .mtrow{flex-wrap:wrap;gap:6px}
    .mtnm{flex:1 1 100%;order:1}.mtdot{order:0}.mtt{order:2}.mtbadge{order:3}
    .mtgw .sp{margin-left:0;width:100%;justify-content:space-between;gap:8px}
  }
  .uask-list{margin:0 0 10px;padding-left:18px;font-size:13px;line-height:1.7}
  /* รายการในกล่องยืนยัน */
  .uupg-list{margin-top:10px;max-height:210px;overflow-y:auto;border:1px solid var(--line);border-radius:11px;background:var(--soft)}
  .uupg-li{display:flex;align-items:center;gap:9px;padding:7px 11px;border-bottom:1px solid var(--line);font-size:12.5px}
  .uupg-li:last-child{border-bottom:none}
  .uupg-li .n{flex:0 0 auto;width:20px;height:20px;border-radius:6px;background:var(--card);border:1px solid var(--line);
    display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:800;color:var(--sub)}
  .uupg-li .nm{flex:1;font-weight:700;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .uupg-li .ver{font-size:11px;color:var(--faint);font-family:var(--mono,monospace)}
  /* แผงความคืบหน้า (overlay) */
  .uupg-ov{position:fixed;inset:0;z-index:210;background:rgba(18,24,42,.46);backdrop-filter:blur(3px);
    display:flex;align-items:center;justify-content:center;padding:18px;opacity:0;transition:opacity .18s}
  .uupg-ov.on{opacity:1}
  .uupg{background:var(--card);border:1px solid var(--line);border-radius:18px;box-shadow:0 24px 70px rgba(20,26,45,.34);
    width:min(460px,96vw);max-height:88vh;display:flex;flex-direction:column;transform:translateY(10px);transition:transform .2s}
  .uupg-ov.on .uupg{transform:none}
  .uupg-h{display:flex;align-items:center;gap:9px;padding:15px 17px;border-bottom:1px solid var(--line);color:var(--ink);font-size:15px}
  .uupg-h b{flex:1}
  .uupg-count{font-size:12.5px;font-weight:800;color:var(--sub);background:var(--soft);border-radius:9px;padding:3px 9px}
  .uupg-body{overflow-y:auto;padding:9px;display:flex;flex-direction:column;gap:5px}
  .uupg-step{display:flex;align-items:center;gap:10px;padding:9px 11px;border-radius:11px;border:1px solid transparent;transition:.16s}
  .uupg-step .st-ic{flex:0 0 auto;width:22px;height:22px;border-radius:7px;background:var(--soft);border:1px solid var(--line);
    display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:800;color:var(--sub)}
  .uupg-step .st-ty{flex:0 0 auto;display:flex}
  .uupg-step .st-tx{flex:1;min-width:0}
  .uupg-step .st-nm{font-size:13px;font-weight:700;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .uupg-step .st-ms{font-size:11.5px;color:var(--faint)}
  .uupg-step .st-badge{flex:0 0 auto;font-size:11px;font-weight:800;color:var(--sub);background:var(--soft);border-radius:8px;padding:3px 8px}
  .uupg-step.cur{background:#fff8e6;border-color:#ecdca2}
  .uupg-step.cur .st-badge{background:#f4c430;color:#5a4708}
  .uupg-step.cur .st-ic{background:#f4c430;border-color:#d9b840;color:#5a4708;animation:uniGlow 1.6s ease-in-out infinite}
  .uupg-step.done{background:#eefaf2;border-color:#c6ead5}
  .uupg-step.done .st-badge{background:#20a463;color:#fff}
  .uupg-step.err{background:#fdeeee;border-color:#f0cccc}
  .uupg-step.err .st-badge{background:#d24b48;color:#fff}
  .uupg-f{display:flex;align-items:center;gap:10px;padding:12px 15px;border-top:1px solid var(--line)}
  .uupg-f .tiny{flex:1}
  #uupg-stop{flex:0 0 auto;font-family:inherit;font-size:13px;font-weight:800;border-radius:11px;padding:9px 15px;cursor:pointer;
    border:1px solid var(--line);background:var(--card);color:var(--sub);transition:.14s}
  #uupg-stop:hover{background:var(--soft)}
  #uupg-stop.ok{background:var(--blue);border-color:var(--blue);color:#fff}
  .uupg-min{flex:0 0 auto;width:28px;height:28px;border-radius:8px;border:1px solid var(--line);background:var(--card);
    color:var(--sub);font-size:17px;font-weight:800;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:.14s}
  .uupg-min:hover{background:var(--soft)}
  /* ย่อ: ไม่บังจอ ใช้งานหน้าอื่นต่อได้ ลอยมุมขวาล่าง */
  .uupg-ov.min{background:transparent;backdrop-filter:none;pointer-events:none;align-items:flex-end;justify-content:flex-end;padding:16px}
  .uupg-ov.min .uupg{pointer-events:auto;width:min(320px,92vw);transform:none;box-shadow:0 14px 40px rgba(20,26,45,.3)}
  .uupg-ov.min .uupg-body{display:none}
  .uupg-ov.min .uupg-h{cursor:pointer}
  .uupg-ov.min .uupg-cur{display:block}
  .uupg-cur{display:none;font-size:11.5px;color:var(--faint);padding:0 15px 11px;margin-top:-4px}
  #uupg-close{flex:0 0 auto;font-family:inherit;font-size:13px;font-weight:800;border-radius:11px;padding:9px 14px;cursor:pointer;
    border:1px solid var(--line);background:var(--card);color:var(--sub);transition:.14s}
  #uupg-close:hover{background:var(--soft)}
  .uupg-gw{flex:0 0 auto;font-family:inherit;font-size:13px;font-weight:800;border-radius:11px;padding:9px 14px;cursor:pointer;
    border:1px solid #d9b840;background:#f4c430;color:#5a4708;display:inline-flex;align-items:center;gap:6px;transition:.14s}
  .uupg-gw:hover{filter:brightness(1.05);transform:translateY(-1px)}
  .uupg-f{flex-wrap:wrap}
  /* pill ลอยมุมขวาล่าง เมื่อซ่อนแผงแต่งานยังวิ่ง */
  .uupg-pill{position:fixed;right:16px;bottom:16px;z-index:180;display:flex;align-items:center;gap:8px;cursor:pointer;
    background:linear-gradient(180deg,#fffdf4,#fff2cc);border:1px solid #ecdca2;color:#7a5f10;font-size:12.5px;font-weight:800;
    border-radius:999px;padding:9px 15px;box-shadow:0 8px 22px rgba(180,140,20,.28);opacity:0;transform:translateY(8px);transition:.2s}
  .uupg-pill.on{opacity:1;transform:none}
  .uupg-pill:hover{filter:brightness(1.03);transform:translateY(-1px)}
  .uupg-pill svg{color:#8a6d12}
  /* Port map — แผงพอร์ต Switch แบบ interactive */
  /* แผงพอร์ตแบบหน้าเครื่องจริง — 2 แถวเรียงตามคอลัมน์ (พอร์ต 1 บน · 2 ล่าง · 3 บน ...) */
  .uportmap-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;padding:1px 0 2px}
  .uportmap{display:grid;grid-auto-flow:column;grid-template-rows:repeat(2,1fr);gap:5px;
    padding:11px 12px;background:linear-gradient(180deg,#eef1f7,#e4e8f1);border:1px solid var(--line);border-radius:12px;width:max-content;min-width:100%}
  /* ตัวคั่นช่องว่างก่อนกลุ่มพอร์ต SFP — อยู่ในกรอบเดียวกัน เลื่อนเป็นชุดเดียว */
  .uport-sep{grid-row:1 / 3;width:16px;align-self:stretch;position:relative}
  .uport-sep:before{content:'';position:absolute;top:3px;bottom:3px;left:50%;width:2px;transform:translateX(-1px);
    background:repeating-linear-gradient(180deg,#c2c9d8 0 4px,transparent 4px 8px);border-radius:2px}
  .uport-t{width:31px;height:29px;border-radius:5px;border:1.5px solid #cdd4e2;background:#fff;position:relative;cursor:pointer;
    display:flex;align-items:center;justify-content:center;padding:0;font-family:inherit;
    transition:transform .12s ease,box-shadow .12s ease}
  .uport-t .pnum{font-size:12px;font-weight:800;color:var(--faint)}
  .uport-t:hover{transform:translateY(-2px);box-shadow:0 6px 15px rgba(20,26,45,.2);z-index:1}
  .uport-t:active{transform:scale(.93)}
  .uport-t.up{border-color:var(--pc);box-shadow:inset 0 -3px 0 var(--pc)}
  .uport-t.up .pnum{color:var(--ink)}
  .uport-t.up:hover{box-shadow:inset 0 -3px 0 var(--pc),0 6px 15px rgba(20,26,45,.2)}
  .uport-t.down{background:#f4f6fa}
  .uport-t.off{background:repeating-linear-gradient(45deg,#f0f2f7,#f0f2f7 3px,#e2e6ef 3px,#e2e6ef 6px);border-color:#dfe3ec}
  .uport-t.sfp{border-style:dashed;width:40px;background:linear-gradient(180deg,#fbfcfe,#eef1f7)}
  .uport-t.sfp .pnum{font-size:11px}
  .uport-t.uplink{outline:2px solid #7aa8f0;outline-offset:1px}
  .uport-t .pbolt{position:absolute;top:-2px;right:-1px;font-size:9px;line-height:1;filter:drop-shadow(0 0 1px #fff)}
  .uport-t .pup{position:absolute;top:0;left:2px;font-size:9px;font-weight:900;color:#2b5fc4;line-height:1}
  .uportlg{display:flex;gap:9px 12px;flex-wrap:wrap;align-items:center;margin-top:9px;font-size:11px;color:var(--sub)}
  .uportlg span{display:inline-flex;align-items:center;gap:5px}
  .uportlg i.lg{width:13px;height:8px;border-radius:2px;display:inline-block}
  /* ตั้ง VLAN หลายพอร์ต (admin) — ปุ่มพอร์ตในโหมดเลือก */
  .uport-t.pv-sel{background:#1f6fe0;border-color:#1f6fe0;box-shadow:none}
  .uport-t.pv-sel .pnum{color:#fff}
  .uport-t.pv-lock{cursor:not-allowed;opacity:.45}
  .uport-t.pv-lock:hover{transform:none;box-shadow:none}
  .pvseg{display:flex;gap:6px;margin-bottom:12px;flex-wrap:wrap}
  .pvseg button{flex:1 1 140px;border:1.5px solid var(--line);background:var(--card);border-radius:11px;padding:10px 12px;
    font-family:inherit;font-size:13px;font-weight:700;color:var(--sub);cursor:pointer;text-align:left}
  .pvseg button small{display:block;font-weight:500;font-size:11.5px;color:var(--faint);margin-top:2px}
  .pvseg button.on{border-color:#1f6fe0;background:#eaf2ff;color:#1c4784}
  .pvnets{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:6px;margin-bottom:12px}
  .pvnets label{display:flex;align-items:center;gap:8px;border:1px solid var(--line);border-radius:10px;padding:8px 10px;font-size:13px;cursor:pointer;background:var(--card)}
  .pvnets label.dis{opacity:.45;cursor:not-allowed}
  .pvnets input{width:16px;height:16px;flex:none}
  .pvnets .vid{margin-left:auto;font-size:11px;font-weight:800;color:var(--faint);white-space:nowrap}
  .pvsum{background:var(--soft);border:1px solid var(--line);border-radius:10px;padding:9px 11px;font-size:12.5px;line-height:1.55;margin-bottom:10px}
  .pvsum b{color:var(--ink)}
  .pvbar{display:flex;gap:6px;flex-wrap:wrap;margin:9px 0 2px}
  /* sparkline ประสิทธิภาพ */
  .uspk{display:flex;align-items:center;gap:10px;margin:7px 0}
  /* เคยชื่อ .uspk-l ซึ่งชนกับ "รายการไซต์ในหน้าต่างเลือก" ที่ประกาศไว้ก่อนหน้า
     (คลาสเดียวกันคนละที่ = กฎท้ายไฟล์ไปทับกฎแรกทีละ property โดยไม่มีใครรู้ตัว)
     ผลคือรายการไซต์ได้ flex-basis 92px / justify-content / ขนาดตัวอักษรของ sparkline ติดไปด้วย
     -> ตั้งชื่อใหม่ให้ไม่ซ้ำ อาการเดียวกับที่เคยเจอกับ .upbar มาแล้ว                     */
  .uspkg-l{flex:0 0 92px;font-size:12px;color:var(--sub);display:flex;justify-content:space-between;align-items:baseline}
  .uspkg-l b{color:var(--ink);font-size:13px}
  .uspk-svg{flex:1;height:30px;min-width:0}
  .umeter{margin:9px 0}
  .umeter .ml{display:flex;justify-content:space-between;align-items:baseline;font-size:12.5px;color:var(--sub)}
  .umeter .ml b{font-weight:700;color:var(--ink)}
  .umbar{height:7px;background:var(--line);border-radius:99px;overflow:hidden;margin-top:5px}
  .umbar>i{display:block;height:100%;border-radius:99px;transition:width .3s}
  .umcli{display:flex;flex-direction:column;gap:2px}
  .umcli .ci{display:flex;align-items:center;gap:10px;padding:8px 6px;border-radius:9px;cursor:pointer}
  .umcli .ci:hover{background:var(--soft)}
  .umcli .d{width:24px;height:24px;border-radius:7px;display:flex;align-items:center;justify-content:center;font-size:12px;background:var(--soft);flex:0 0 auto}
  .umcli .cn{flex:1;min-width:0}
  .umcli .c1{font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .umcli .c2{font-size:11px;color:var(--sub)}
  .umcli .cm{font-size:11.5px;color:var(--sub);text-align:right;white-space:nowrap;flex:0 0 auto}
  .ulnk{color:var(--blue);cursor:pointer;font-weight:700}
  .ulnk:hover{text-decoration:underline}
  .umsw{margin-top:10px;max-height:52vh;overflow:auto}
  .swr{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 4px;border-bottom:1px solid var(--line)}
  .swr:last-child{border-bottom:0}
  .swr .sn{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}
  .sn-name{font-size:13.5px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .sn-alias{font-family:inherit;font-size:12.5px;border:1px solid var(--line);border-radius:8px;padding:6px 9px;background:var(--card);color:var(--ink);width:100%;box-sizing:border-box}
  .sn-alias:focus{outline:none;border-color:var(--blue)}
  .ctrl-tag{display:inline-block;font-size:10px;font-weight:800;color:var(--sub);background:var(--soft);border:1px solid var(--line);border-radius:6px;padding:1px 6px;vertical-align:middle}
  .uni-cerr{background:#fbf1dc;border:1px solid #e8d9b0;color:#a9781f;border-radius:10px;padding:9px 12px;font-size:12.5px;margin-top:10px}
  .usw{position:relative;display:inline-block;width:40px;height:23px;flex:0 0 auto;cursor:pointer}
  .usw input{opacity:0;width:0;height:0;position:absolute}
  .usl{position:absolute;inset:0;background:#c6cddc;border-radius:99px;transition:.2s}
  .usl:before{content:"";position:absolute;height:17px;width:17px;left:3px;top:3px;background:#fff;border-radius:50%;transition:.2s;box-shadow:0 1px 3px rgba(0,0,0,.2)}
  .usw input:checked+.usl{background:var(--green)}
  .usw input:checked+.usl:before{transform:translateX(17px)}
  /* recording-stats */
  .rec-bar{display:flex;align-items:center;gap:10px;margin:12px 0 8px;flex-wrap:wrap}
  .rec-fams{display:flex;gap:6px;flex-wrap:wrap;background:var(--soft);border:1px solid var(--line);border-radius:11px;padding:4px}
  .rec-fams button{font-family:inherit;font-size:12.5px;font-weight:700;color:var(--sub);background:transparent;border:0;border-radius:8px;padding:6px 12px;cursor:pointer;white-space:nowrap}
  .rec-fams button.on{background:var(--card);color:var(--ink);box-shadow:var(--shadow-sm)}
  .rec-chart{width:100%;overflow:hidden}
  .rec-chart svg{display:block}
  /* legend = ชิปกดได้: กดเพื่อ "โฟกัส" ไซต์เดียว (ตัวอื่นจาง) กดซ้ำ = ล้าง */
  .rec-leg{display:flex;gap:6px;flex-wrap:wrap;margin-top:10px;align-items:center}
  .rec-leg .rlg{display:inline-flex;align-items:center;gap:6px;font-family:inherit;font-size:11.5px;font-weight:600;
    color:var(--sub);background:var(--soft);border:1px solid var(--line);border-radius:99px;padding:4px 10px;cursor:pointer;
    max-width:200px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .rec-leg .rlg i{width:10px;height:10px;border-radius:3px;flex:0 0 auto}
  .rec-leg .rlg:hover{background:#fff;border-color:#c6cddc}
  .rec-leg .rlg.on{background:var(--blue);border-color:var(--blue);color:#fff}
  .rec-leg .rlg.clr{background:transparent;border-style:dashed;font-weight:700}
  .rec-leg-hint{font-size:11px;color:var(--faint);margin-top:6px}
  .rec-fc-note{font-size:12px;color:var(--sub);background:var(--soft);border:1px solid var(--line);
    border-radius:10px;padding:8px 12px;margin-bottom:10px;line-height:1.5}
  /* การ์ด modal สถิติ: ปกติ ~900px · กดขยาย = เกือบเต็มจอ (ยังเป็น modal) */
  .rec-card{width:min(900px,100%)}
  .rec-card.big{width:min(1400px,96vw)}
  /* iOS fix: การ์ดเป็น flex คอลัมน์ · แถบปุ่มติดบน (ไม่เลื่อนหาย) · เนื้อหาเลื่อนแยก
     ใช้ id-scope กัน .uni-modal-card / media query มาทับ */
  #rec-modal .rec-card{padding:0;overflow:hidden;display:flex;flex-direction:column;max-height:88svh}
  #rec-modal .rec-card.big{max-height:94svh}
  #rec-modal .rec-topbar{flex:0 0 auto;display:flex;justify-content:flex-end;align-items:center;gap:8px;
    padding:9px 12px 4px;background:var(--card);border-radius:18px 18px 0 0}
  #rec-modal #rec-body{flex:1 1 auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;
    overscroll-behavior:contain;padding:0 22px 20px}
  @media(max-width:760px){#rec-modal #rec-body{padding:0 14px 16px}}
  .rec-expand{position:static;border:0;background:var(--soft);color:var(--sub);
    width:30px;height:30px;border-radius:9px;cursor:pointer;font-size:15px;line-height:1;font-family:inherit;flex:0 0 auto}
  .rec-expand:hover{background:#e9edf6;color:var(--ink)}
  #rec-modal .rec-topbar .uni-modal-x{position:static;top:auto;right:auto;flex:0 0 auto}
  @media(max-width:760px){.rec-expand{display:none}}
  .rec-enc{display:inline-flex;gap:3px;flex-wrap:wrap;max-width:230px}
  .rec-enc .u-pill{font-size:10px;padding:2px 7px}
  .rec-mgr{display:flex;align-items:center;gap:10px;padding:8px 4px;border-bottom:1px solid var(--line)}
  .rec-mgr:last-child{border-bottom:0}
  .rec-mgn{flex:1;min-width:0;font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .rec-mgd,.rec-mgb{font-family:inherit;font-size:12.5px;border:1px solid var(--line);border-radius:8px;padding:5px 8px;background:var(--card);color:var(--ink)}
  .rec-mgd{width:140px}.rec-mgb{width:92px}
  .rec-mgd:disabled,.rec-mgb:disabled{background:var(--soft);color:var(--faint)}
  @media(max-width:760px){.rec-mgn{font-size:12px}.rec-mgd{width:120px}.rec-mgb{width:74px}}
  @media(max-width:760px){.uni-kpis{grid-template-columns:repeat(2,1fr)}
    .uni-sec{padding:13px 12px;overflow-x:auto}
    .uni-modal{padding:0;align-items:flex-end}.uni-modal-card{width:100%;max-height:92vh;border-radius:18px 18px 0 0}}

/* ---- block 2 id="theme-refresh" ---- */

/* ============ Theme refresh (SaaS look) — override เท่านั้น ไม่แตะ layout/HTML/logic ============ */
:root{
  --gradA:linear-gradient(135deg,#16a34a 0%,#2563eb 100%);
  --shadow:0 14px 34px rgba(31,42,60,.11),0 3px 10px rgba(31,42,60,.05);
  --shadow-sm:0 6px 20px rgba(31,42,60,.06);
  --bg:#e9edf4;
  --green:#22c55e;--red:#ef4444;--yellow:#f59e0b;
}
/* การ์ด/พาเนล: โค้งขึ้น ขอบจางลง เงานุ่มขึ้น */
.panel{border-radius:20px;border-color:#edf1f7}
.card{border-radius:20px}
/* nav active = gradient เขียว→น้ำเงินสด + เรืองแสงนิดๆ */
.nav a.on{box-shadow:0 8px 18px rgba(37,99,235,.28)}
/* ไอคอนเมนู = เส้น SVG ทันสมัย (แทน emoji) */
.nav a .ic{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px}
.nav a .ic svg{width:21px;height:21px;display:block}
.nav a.on .ic svg{stroke-width:2}
@media(max-width:820px){.nav a .ic{width:26px;height:24px}.nav a .ic svg{width:23px;height:23px}}
.logo-row .logo,.side-user .av{background:var(--gradA)}
.sidebar{border-right:1px solid #edf1f7}
/* hover ยกการ์ด KPI นิดๆ (เฉพาะเมาส์) */
@media(hover:hover){
  .ovw-kpi>*{transition:transform .16s ease,box-shadow .16s ease}
  .ovw-kpi>*:hover{transform:translateY(-2px);box-shadow:var(--shadow)}
}
/* KPI: การ์ดโค้งขึ้น · ชิปไอคอนเป็นสีอ่อนตามสีการ์ด · แถบ accent เรืองนุ่ม */
.ovk{border-radius:20px}
.ovk .ic{border-radius:11px;color:var(--a)}
@supports (background:color-mix(in srgb,red,white)){ .ovk .ic{background:color-mix(in srgb,var(--a) 13%,#fff)} }
.ovk::before{border-radius:20px 0 0 20px}
/* จัดลำดับหน้าภาพรวมแบบ v4: KPI → อุปกรณ์ → กริดหลัก → แถวล่าง → ตาราง */
#v-overview{display:flex;flex-direction:column}
#v-overview>*{order:7}
#v-overview>.page-head{order:0}
#v-overview>.ovw-kpi{order:1}
#ov-devpanel{order:2}
#v-overview>.ovw-grid{order:3}
#ov-lower{order:4}
/* แถวล่าง: main (ซ้าย, ยืด) + rail การ์ด sparkline (ขวา, เรียงแนวตั้ง) */
.ov-lower{display:flex;gap:14px;margin-bottom:16px;align-items:stretch}
.ov-lmain{flex:1;min-width:0;display:flex;flex-direction:column;gap:14px}
.ov-lrow{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.ov-lrow>.panel{margin:0;min-width:0}
.ov-lrail{width:312px;flex:none;display:flex;flex-direction:column;gap:14px}
.ov-lrail>.panel{margin:0}
@media(max-width:1100px){.ov-lrail{width:264px}}
@media(max-width:820px){
  .ov-lower{flex-direction:column;gap:12px}
  .ov-lrail{width:auto}
  .ov-lrow{grid-template-columns:1fr;gap:12px}
}
/* การ์ด sparkline ไล่เฉด */
.panel.spk{padding:15px 16px 8px}
.spkval{display:flex;align-items:baseline;gap:8px;margin:2px 0 0}
.spkval b{font-size:23px;font-weight:800;letter-spacing:-.5px}
.spkchg{font-size:12px;font-weight:800}
.spkbox{height:60px;margin-top:4px}
.spkbox svg{width:100%;height:100%;display:block;overflow:visible}
/* กราฟแท่งรายวัน */
.dbarbox{display:flex;align-items:flex-end;gap:6px;height:180px;padding-top:8px}
.dbarcol{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;height:100%;gap:6px;min-width:0}
.dbarcol .dn{font-size:12px;font-weight:800;color:var(--sub)}
.dbarcol .db{width:100%;max-width:34px;border-radius:8px 8px 0 0;min-height:3px;
  background:linear-gradient(180deg,#60a5fa,#93c5fd);transition:height .4s cubic-bezier(.4,0,.2,1)}
.dbarcol .db.hot{background:linear-gradient(180deg,#f2645f,#f59e0b)}
.dbarcol .dl{font-size:10px;color:var(--faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
@media(max-width:820px){
  .dbarbox{height:150px;gap:4px}
}
/* histogram บันทึกย้อนหลัง */
.rethbars{display:flex;align-items:flex-end;gap:12px;height:160px;padding-top:6px}
.rethcol{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;height:100%;gap:7px}
.rethcol .rn{font-size:15px;font-weight:800}
.rethcol .rbar{width:100%;max-width:56px;border-radius:9px 9px 0 0;min-height:4px;transition:height .35s ease}
.rethcol .rlb{font-size:10.5px;color:var(--faint);white-space:nowrap}
/* avatar ตัวอักษรแทนรูป (v4) */
.av.av-letter{display:grid;place-items:center;font-weight:800;font-size:18px;color:#fff;text-transform:uppercase;line-height:1}
/* avatar ตัวอักษรในตารางทุกไซต์ (เล็ก อยู่หน้าชื่อ เหมือนหน้า CCTV) */
.mon-site{display:flex;align-items:center;gap:8px;min-width:0}
.mon-site .av.av-letter{width:24px;height:24px;min-width:24px;border-radius:7px;font-size:12px;flex:none}
.mon-site b{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* ป้าย "ข้อมูลแช่แข็ง" — ไซต์ที่เคยมอนิเตอร์แล้วปิด (โชว์ค่าล่าสุด ไม่อัปเดต) */
.frozen-banner{display:flex;align-items:flex-start;gap:8px;margin:0 0 12px;padding:9px 12px;border-radius:11px;
  background:#eef1f7;border:1px solid #d7deea;color:#4a5570;font-size:12px;line-height:1.5}
.frozen-banner b{color:#2b3450;font-weight:700}
.frozen-banner .ic{flex:none;font-size:14px;line-height:1.2}
.card.site{border-radius:20px}
/* จุดสถานะมุมขวาบนการ์ดไซต์ (v4) */
.sdot-c{width:10px;height:10px;border-radius:50%;flex:none;margin-left:8px;margin-top:4px;align-self:flex-start}
/* Admin: audit log แบบ list + avatar ตัวอักษร + pill (v4) */
.auditlist{display:flex;flex-direction:column}
.ali{display:flex;align-items:center;gap:11px;padding:10px 2px;border-bottom:1px solid var(--line)}
.ali:last-child{border-bottom:none}
.ali .av{width:34px;height:34px;min-width:34px;border-radius:11px;font-size:13px;flex:none}
.ali .amid{flex:1;min-width:0}
.ali .amid .nm{font-weight:700;font-size:13px;line-height:1.35}
.ali .asub{font-size:11px;color:var(--sub);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.apill{margin-left:auto;font-size:11px;font-weight:700;padding:4px 11px;border-radius:20px;white-space:nowrap;flex:none}
.apill.red{background:#fee2e2;color:#b91c1c}.apill.amber{background:#fef3c7;color:#b45309}
.apill.green{background:#dcfce7;color:#15803d}.apill.blue{background:#dbeafe;color:#1d4ed8}.apill.gray{background:#eef1f5;color:#556}
/* Services: KPI การ์ดโค้ง+ยกตอน hover ให้เข้าชุด v4 */
#svc-kpi .kcard{border-radius:16px}
@media(hover:hover){#svc-kpi .kcard{transition:transform .16s ease,box-shadow .16s ease}#svc-kpi .kcard:hover{transform:translateY(-2px);box-shadow:var(--shadow)}}

/* ===== v4 pass: modal ข้อมูลไซต์ (CSS ล้วน — ไม่แตะ JS/โครงสร้าง/ทัช) ===== */
.modal{border-radius:24px}
/* หัว modal ใช้เฉดเขียว→น้ำเงินของธีม (เดิมเป็นกรมท่า) ให้เข้าชุด nav/หน้าอื่น */
.mhead{background:linear-gradient(120deg,#16a34a 0%,#2563eb 100%);padding:18px 22px}
.mhead .av{background:rgba(255,255,255,.22);border-radius:13px}
.mhead h2{font-weight:800;letter-spacing:-.2px}
.mclose{background:rgba(255,255,255,.18);border-radius:11px;transition:background .15s}
@media(hover:hover){.mclose:hover{background:rgba(255,255,255,.32)}}
/* section การ์ดในโมดัล: ขอบจางลง โค้งขึ้น เงานุ่ม หัวข้ออ่านง่ายขึ้น */
.sec{border-color:#edf1f7;border-radius:16px;box-shadow:var(--shadow-sm)}
.sec h4{color:var(--sub);font-weight:800;letter-spacing:.5px}
/* ปุ่มแถว action โค้งเข้าชุด */
.mact .btn{border-radius:12px}
/* Services: แถบ uptime 24 ชม. ให้สวยขึ้น (สูงขึ้น·โค้ง·ไล่เฉด) — คงตรรกะเดิม */
.upbar{gap:2px;height:30px}
.upbar i{border-radius:3px}
.upbar i:not(.dn):not(.unk):not(.part){background:linear-gradient(180deg,#34d17e,#1f9d57)}
.upbar i.dn{background:linear-gradient(180deg,#f2645f,#d03b3b)}
.upbar i.unk{background:#e8edf4}
/* แถบสัดส่วน (hbar) กลม+ไล่เฉด */
.hbar .tr{height:10px;border-radius:99px}
.hbar .fl,.hbar .tr>i{border-radius:99px}
/* pill/badge โค้งนุ่มขึ้นทั้งระบบ */
.badge{border-radius:9px}

/* ===== v4 pass: UniFi KPI — ชิปไอคอน + เลขใหญ่ + sparkline ไล่เฉด (แบบ v4) ===== */
.uni-kpi{position:relative;border-radius:18px;padding:14px 15px 8px;overflow:hidden}
.uni-kpi .ic{position:absolute;top:12px;right:12px;width:31px;height:31px;border-radius:10px;display:grid;place-items:center;font-size:14px;line-height:1}
.uni-kpi .lab{font-size:11.5px;font-weight:700;color:var(--sub);padding-right:38px;line-height:1.3}
.uni-kpi .knum{font-size:24px;font-weight:800;letter-spacing:-.5px;margin:4px 0 2px;line-height:1.1}
.uni-kpi .kchg{font-size:12px;font-weight:700;margin-left:7px;letter-spacing:0}
.uni-kpi .knum .of{font-size:16px;font-weight:700;color:var(--faint);letter-spacing:0}
.uni-kpi .kunit{font-size:12px;font-weight:700;color:var(--sub);margin-left:7px;letter-spacing:0}
.uni-kpi .ktag{display:inline-block;font-size:11px;font-weight:800;letter-spacing:.2px;
  padding:2px 8px;border-radius:999px;background:var(--soft);color:var(--sub);margin-top:2px}
.uni-kpi .ktag.bad{background:rgba(201,74,74,.12);color:var(--red)}
.uni-kpi .kbar{display:flex;gap:2px;height:6px;border-radius:99px;overflow:hidden;
  background:var(--line);margin-top:9px}
.uni-kpi .kbar i{display:block;height:100%;border-radius:99px}
/* ยังไม่มีข้อมูลพอวาดกราฟ -> ยุบพื้นที่ทิ้ง ไม่ให้การ์ดมีที่ว่างค้างอยู่ก้นใบ */
.uni-kpi .uspk:empty{height:0;margin:0}
.uni-kpi .uspk{height:32px;margin-top:2px}
.uni-kpi .uspk svg{width:100%;height:100%;display:block;overflow:visible}

/* ===== บัญชีค่าใช้จ่าย (v-acct) — prefix .ac- ทั้งหมด =====
   หมายเหตุ: ธีมนี้ใช้ตัวแปร --sub / --faint  *** ไม่มี --muted *** เขียนผิดแล้วตัวอักษรจะจางหาย */
.ac-bar{display:flex;gap:8px;align-items:center;margin-bottom:14px;flex-wrap:wrap}
.ac-msel{flex:1;min-width:0;padding:11px 13px;font-size:15px;text-overflow:ellipsis}
/* เคยต้องให้ตกบรรทัดบนมือถือ เพราะปุ่มส่งออกสองปุ่มกินที่จนชื่อเดือนเต็มโดนตัด
   พอยุบเหลือปุ่มไอคอนเดียว (42px) ก็อยู่แถวเดียวกันได้สบายแล้ว — เลิก wrap */
/* ชื่อเดือนแบบเต็มยาวกว่าเดิมมาก (สิงหาคม-กันยายน 2569) ที่ 16px/มือถือ 390px
   ตัวหนังสือจะโดนลูกศรของ select ทับท้าย — ลดลงมาหนึ่งขั้นแล้วยังอ่านสบาย */
.ac-kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;margin-bottom:14px}
/* ===== ใครเป็นคนจ่าย — สัดส่วน Beer / Boat =====
   สองสีนี้คือคู่เดียวกับที่หน้า PVE ใช้ ผ่านการตรวจตาบอดสีมาแล้ว (ΔE 29 protan)
   และมีตัวเลข % กำกับทุกตัว = ไม่ได้สื่อด้วยสีอย่างเดียว */
.ac-who{background:var(--card);border:1px solid var(--line);border-radius:16px;
  padding:13px 15px 14px;box-shadow:var(--shadow-sm);margin-bottom:12px}
.ac-who .h{font-size:11.5px;font-weight:800;color:var(--sub);margin-bottom:9px}
.ac-who .h b{color:var(--ink);font-weight:800}
.ac-sbar{display:flex;gap:2px;height:11px;border-radius:99px;overflow:hidden;
  background:rgba(125,135,165,.13)}
.ac-sbar i{display:block;height:100%;border-radius:99px;width:0;
  transition:width .75s cubic-bezier(.22,1,.36,1)}
.ac-slg{display:flex;flex-wrap:wrap;gap:8px 18px;margin-top:11px}
.ac-slg>div{display:flex;align-items:center;gap:7px;font-size:12.5px}
.ac-slg .dot{width:10px;height:10px;border-radius:3px;flex:0 0 auto}
.ac-slg .nm{color:var(--sub);font-weight:700}
.ac-slg .vl{color:var(--ink);font-weight:800}
.ac-slg .pc{color:var(--faint);font-weight:800;font-size:11.5px}
/* ===== ปุ่มเปิดกราฟหมวด ===== */
.ac-catbtn{display:flex;align-items:center;justify-content:space-between;gap:10px;
  width:100%;margin-bottom:16px;padding:13px 15px;font-weight:800;text-align:left}
.ac-catbtn-r{color:var(--sub);font-weight:700;font-size:12.5px}
/* ปุ่มเพิ่มรายการ — ไล่สีค่อย ๆ วิ่ง ให้เด่นกว่าปุ่มอื่นในหน้า
   ใช้ background-position ขยับ ไม่ใช่ animate ตัว gradient (เบรนเดอร์ทำงานน้อยกว่ามาก)
   สีชุดนี้คือคู่ที่ตรวจตาบอดสีผ่านแล้ว + เขียวของธีม */
.ac-addbtn{display:block;width:100%;margin-bottom:14px;padding:14px;border:0;border-radius:14px;
  font-family:inherit;font-size:15px;font-weight:800;color:#fff;cursor:pointer;
  background:linear-gradient(100deg,#2f80ed,#2f8f63,#e8710a,#2f80ed);
  background-size:300% 100%;animation:acflow 9s linear infinite;
  box-shadow:0 6px 18px rgba(47,128,237,.28)}
.ac-addbtn:active{transform:scale(.985)}
/* ป้าย "ระบบไม่พร้อม" — ทั้งหน้านี้พิงบน n8n ถ้าบันทึกไม่ได้ต้องบอกก่อนกรอก
   ไม่ใช่ให้กรอกเสร็จแล้วเพิ่งรู้ว่าเสียเที่ยว */
.ac-down{display:block;margin-bottom:14px;padding:12px 14px;border-radius:14px;
  border:1px solid rgba(201,74,74,.45);background:rgba(201,74,74,.09)}
.ac-down .t{font-size:13.5px;font-weight:800;color:var(--red);line-height:1.5}
.ac-down .d{font-size:11.5px;font-weight:700;color:var(--sub);margin-top:5px;line-height:1.55}
.ac-down .r{display:inline-block;margin-top:9px;padding:7px 13px;border-radius:10px;border:0;
  font-family:inherit;font-size:12px;font-weight:800;cursor:pointer;
  background:rgba(201,74,74,.16);color:var(--red)}
.ac-down .r[disabled]{opacity:.55;cursor:default}
.ac-down .btns{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
.ac-down .btns .r{margin-top:0}
.ac-down .go{display:inline-block;padding:7px 13px;border-radius:10px;text-decoration:none;
  font-size:12px;font-weight:800;background:var(--pri);color:#fff}
.ac-addbtn[disabled]{opacity:.45;cursor:default;animation:none;transform:none}
@keyframes acflow{0%{background-position:0% 50%}100%{background-position:300% 50%}}
@media (prefers-reduced-motion:reduce){
  .ac-addbtn{animation:none;background:linear-gradient(100deg,#2f80ed,#2f8f63)}
}
/* ===== ฟอร์มเพิ่มรายการ ===== */
/* ระยะห่าง: ป้ายชื่อควรอยู่ใกล้ "ช่องของตัวเอง" มากกว่าช่องด้านบน
   ไม่งั้นสายตาจับคู่ผิด — บนมากกว่าล่างประมาณ 3 เท่า กำลังอ่านสบาย */
.acf-l{display:block;font-size:12.5px;font-weight:800;color:var(--sub);
  margin:20px 0 7px;letter-spacing:.1px}
/* ห้ามใส่กฎ first-child ที่ตั้ง margin-top เป็น 0 ให้ .acf-l — ป้ายตัวแรกของฟอร์มมีกล่องสลิปนำหน้าอยู่แล้ว
   ไม่เคยเป็น first-child จริง ตัวที่โดนคือป้ายแรกใน #acf-admin-fields / #acf-boat-fields
   ทำให้ช่องไฟตรงนั้นหดเหลือ 2px ไม่เท่าที่อื่น (เคยพลาดมาแล้วครั้งหนึ่ง) */
.acf-f{position:relative;margin-bottom:2px}
/* กล่องสลิป: ยังว่างอยู่ก็ไม่ต้องสูง แต่พอมีรูปแล้วให้ใหญ่พอจะอ่านตัวเลขบนสลิปได้จริง
   ตัวเลขบนสลิปมือถือเล็กมาก ถ้าย่อเกินไปต้องกดเปิดดูอีกทีทุกครั้ง */
.acf-slip{border:1.5px dashed var(--line);border-radius:16px;background:rgba(125,135,165,.06);
  display:grid;place-items:center;min-height:120px;cursor:pointer;overflow:hidden;padding:6px}
.acf-slip.has{padding:4px;border-style:solid}
.acf-slip-empty{display:grid;place-items:center;gap:8px;font-size:30px;color:var(--faint);padding:22px}
.acf-slip-empty span{font-size:12.5px;font-weight:700}
.acf-preview{max-width:100%;max-height:48vh;border-radius:11px;display:block}
.acf-slipbar{display:flex;align-items:center;gap:10px;margin-top:8px}
.acf-num{font-variant-numeric:tabular-nums}
/* iOS ให้ input[type=date] มีความกว้างขั้นต่ำของตัวเอง แล้วดันล้นขอบขวาของ modal
   ต้องปิด appearance + บังคับ min-width:0 ไม่งั้น width:100% เอาไม่อยู่ */
#ov-acadd input.search{max-width:100%;min-width:0;-webkit-appearance:none;appearance:none}
#acf-date{display:block;width:100%;max-width:100%;min-width:0;text-align:left}
#acf-date::-webkit-date-and-time-value{text-align:left;margin:0}
#acf-date::-webkit-calendar-picker-indicator{margin-left:auto}
/* กันเหนียวอีกชั้น — ลูกทุกตัวในตัวฟอร์มห้ามกว้างเกินกล่อง ไม่ว่าเบราว์เซอร์ไหน */
#ov-acadd .mbody>*{max-width:100%}
/* ===== ช่องที่ AI กรอกให้ = เหลือง + กากบาทล้างค่า =====
   เหลือง = "ยังไม่มีคนยืนยัน" พอผู้ใช้พิมพ์ทับหรือกดล้าง ถือว่ารับรองแล้ว สีหาย */
.acf-f input.acf-auto{background:rgba(240,180,20,.13);border-color:rgba(200,140,10,.55)}
.acf-f input.acf-auto:focus{border-color:var(--pri)}
.acf-x{position:absolute;right:8px;top:50%;transform:translateY(-50%);
  width:30px;height:30px;border:0;border-radius:50%;cursor:pointer;
  background:rgba(125,135,165,.16);color:var(--sub);font-size:13px;font-weight:800;
  font-family:inherit;line-height:1;display:grid;place-items:center;padding:0}
.acf-x:active{background:rgba(125,135,165,.3)}
.acf-f input.acf-auto ~ .acf-x{background:rgba(200,140,10,.22);color:#8a6100}
/* เผื่อที่ให้ปุ่มกากบาท ไม่ให้ตัวหนังสือวิ่งไปอยู่ใต้ปุ่ม
   ใช้คลาสจาก JS ไม่ใช้ :has() — Safari เก่ายังไม่รองรับ พลาดแล้วมองไม่เห็นจากเครื่องนี้ */
.acf-f.hasx input.search{padding-right:44px}
.acf-hint{font-size:11.5px;color:var(--faint);margin:6px 2px 0;line-height:1.5}
/* ===== ระหว่างบันทึก: เช็คลิสต์ขั้นตอน =====
   บันทึกพร้อมรูปวัดจริงแล้วใช้เวลา 10-15 วิบนเน็ตมือถือ (ฝั่ง n8n อย่างเดียว 7.5-8.7 วิ)
   ปล่อยให้จอนิ่ง ๆ นานขนาดนั้น ผู้ใช้จะกดซ้ำหรือปิดหน้าไปเลย
   *** ขั้นที่รู้ % จริงมีแค่ "ส่งข้อมูลขึ้นเซิร์ฟเวอร์" (อ่านจาก XHR upload progress) ***
   ขั้นที่รู้ไม่ได้จะหมุนค้างพร้อมนับวินาที ไม่ทำแถบปลอมวิ่งเอง — เน็ตช้าจริงแถบปลอมจะวิ่งไปสุด
   แล้วค้าง ซึ่งหลอกตาและแย่กว่าไม่มีแถบ */
/* ===== ระหว่างบันทึก: ไทม์ไลน์ขั้นตอน =====
   พื้นใช้ var(--card) ซึ่งเป็นสีพื้นของ modal เองและสลับตามธีมอยู่แล้ว
   (ตอนแรกเขียน rgba ตายตัวสองชุดแล้วครอบด้วย :root:not([data-theme="light"])
    ซึ่งติดตลอดเมื่อไม่มี data-theme → โหมดสว่างได้พื้นเข้มแต่ตัวหนังสือเข้ม อ่านไม่ออก) */
/* ตอนบันทึก เราซ่อนฟอร์มแล้วโชว์ชั้นนี้แทน (ไม่ใช่วางทับ)
   ทำแบบ absolute ทับไว้ modal จะสูงเท่าฟอร์มเดิมตลอด เหลือพื้นที่โบ๋เยอะ
   วางเป็นเนื้อหาปกติแล้วซ่อน .mbody แทน ความสูง modal จึงหุบมาพอดีกับ 4 ขั้น
   ฟอร์มแค่ถูกซ่อน ไม่ได้ถูกลบ ค่าที่กรอกไว้ยังอยู่ครบ พลาดแล้วกลับมาแก้ต่อได้ทันที */
.acs-ov{padding:20px;display:grid;place-items:center;animation:acsin .2s ease-out}
@keyframes acsin{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.modal.acs-busy>.mbody{display:none}
.acs-card{width:100%;max-width:320px}

/* ---- แถบเปิด: สลิปอยู่ซ้าย ชีตอยู่ขวา มีเส้นทางวิ่งระหว่างกัน ----
   ให้สลิปเป็นตัวเอก "ตั้งแต่ต้น" ไม่ใช่โผล่มาแค่ตอนจบ
   ช่วงรอจะได้มีอะไรให้มองที่สื่อความว่า "ของชิ้นนี้กำลังเดินทางไปลงชีต" */
.acs-hero{display:flex;align-items:center;gap:10px;margin-bottom:18px}
.acs-slip{flex:0 0 auto;width:52px;height:66px;border-radius:9px;object-fit:cover;
  background:rgba(125,135,165,.1);border:1px solid var(--line);
  display:grid;place-items:center;font-size:24px;position:relative;z-index:2}
.acs-path{flex:1;height:2px;border-radius:2px;position:relative;overflow:hidden;
  background:rgba(125,135,165,.2)}
.acs-path>i{position:absolute;inset:0;
  background:linear-gradient(90deg,transparent,var(--pri),transparent);
  background-size:55% 100%;background-repeat:no-repeat;
  animation:acsrun 1.3s linear infinite}
@keyframes acsrun{0%{background-position:-60% 0}100%{background-position:160% 0}}
.acs-dest{flex:0 0 auto;width:48px;height:48px;border-radius:13px;display:grid;place-items:center;
  background:rgba(47,143,99,.12);border:1.5px solid rgba(47,143,99,.4);position:relative}
.acs-dest svg{width:24px;height:24px;display:block}
.acs-dest .bdg{position:absolute;right:-5px;bottom:-5px;width:21px;height:21px;border-radius:50%;
  background:var(--green);color:#fff;font-size:11px;font-weight:800;display:grid;place-items:center;
  border:2px solid var(--card);opacity:0;transform:scale(.4)}
.acs-dest.hit{animation:acspop .45s ease-out}
.acs-dest.hit .bdg{animation:acsbdg .3s .18s ease-out forwards}
@keyframes acspop{0%,100%{transform:scale(1)}45%{transform:scale(1.14)}}
@keyframes acsbdg{to{opacity:1;transform:scale(1)}}
/* สลิปบินไปลงชีต — ระยะทางส่งมาเป็น --fx ตอนรันจริง ไม่เดาความกว้างไว้ล่วงหน้า */
.acs-slip.fly{animation:acsfly .85s cubic-bezier(.5,-0.1,.35,1) forwards}
@keyframes acsfly{
  0%  {transform:translateX(0) scale(1) rotate(0);opacity:1}
  70% {transform:translateX(calc(var(--fx) * .82)) scale(.42) rotate(7deg);opacity:1}
  100%{transform:translateX(var(--fx)) scale(.12) rotate(0);opacity:0}
}

/* ---- แถบรวม 4 ช่อง บอกภาพรวมในแวบเดียว ---- */
.acs-seg{display:flex;gap:4px;margin-bottom:15px}
.acs-seg>i{flex:1;height:3px;border-radius:99px;background:rgba(125,135,165,.2);transition:.25s}
.acs-seg>i.on{background:var(--green)}
.acs-seg>i.now{background:var(--pri)}
.acs-seg>i.bad{background:var(--red)}

/* ---- ไทม์ไลน์ ---- */
.acs-step{display:flex;gap:12px;align-items:flex-start;position:relative;padding-bottom:13px}
/* เส้นเชื่อมระหว่างวง — ตัวที่ทำให้อ่านเป็น "ขั้นตอนต่อเนื่อง" ไม่ใช่รายการสี่บรรทัด */
.acs-step:not(:last-child)::before{content:'';position:absolute;left:10px;top:24px;bottom:1px;
  width:2px;border-radius:2px;background:rgba(125,135,165,.22)}
.acs-step.done:not(:last-child)::before{background:var(--green);opacity:.45}
.acs-ic{flex:0 0 auto;width:22px;height:22px;border-radius:50%;display:grid;place-items:center;
  font-size:10.5px;font-weight:800;background:rgba(125,135,165,.14);color:var(--faint);
  position:relative;z-index:1;box-shadow:0 0 0 3px var(--card)}
.acs-step.done .acs-ic{background:var(--green);color:#fff}
.acs-step.fail .acs-ic{background:var(--red);color:#fff}
.acs-step.act .acs-ic{background:transparent;color:transparent;
  border:2px solid rgba(47,128,237,.22);border-top-color:var(--pri);
  /* .9s กำลังดี — .7s ดูรีบไปหน่อยกับวงเล็ก 22px
     (แต่ตัวที่ทำให้ "หมุนแล้วเด้งกลับ" คือการ re-render ไม่ใช่ความเร็ว ดู acsDraw) */
  animation:acsspin .9s linear infinite}
@keyframes acsspin{to{transform:rotate(360deg)}}
.acs-tx{min-width:0;flex:1;padding-top:1px}
.acs-t{font-size:13px;font-weight:700;color:var(--faint);line-height:1.4}
.acs-step.act .acs-t{color:var(--ink);font-weight:800}
.acs-step.done .acs-t{color:var(--sub)}
.acs-step.fail .acs-t{color:var(--red);font-weight:800}
.acs-n{font-size:11px;font-weight:700;color:var(--faint);margin-top:3px;line-height:1.45;
  font-variant-numeric:tabular-nums}
.acs-step.fail .acs-n{color:var(--red)}
.acs-bar{height:4px;border-radius:99px;background:rgba(125,135,165,.18);margin-top:6px;overflow:hidden}
.acs-bar>i{display:block;height:100%;background:var(--pri);border-radius:99px;
  transition:width .18s linear}
.acs-foot{font-size:11px;font-weight:700;color:var(--faint);text-align:center;
  margin-top:3px;font-variant-numeric:tabular-nums}
.acs-done{font-size:14.5px;font-weight:800;color:var(--green);text-align:center;margin-top:4px}
@media (prefers-reduced-motion:reduce){
  .acs-ov{animation:none}
  .acs-step.act .acs-ic{animation:none;border-top-color:var(--pri)}
  .acs-path>i{animation:none;background:var(--pri);opacity:.5}
  .acs-slip.fly{animation:none;opacity:0}
  .acs-dest.hit{animation:none}
  .acs-dest.hit .bdg{animation:none;opacity:1;transform:scale(1)}
}
/* ===== ตอน AI กำลังอ่านบิล ===== */
.acf-slip{position:relative}
.acf-spin{position:absolute;inset:0;display:grid;place-items:center;gap:10px;
  background:rgba(12,16,28,.55);backdrop-filter:blur(2px);border-radius:14px;z-index:3}
.acf-spin .ring{width:42px;height:42px;border-radius:50%;
  border:3.5px solid rgba(255,255,255,.28);border-top-color:#fff;animation:acspin .85s linear infinite}
.acf-spin .txt{font-size:12.5px;font-weight:800;color:#fff;text-shadow:0 1px 3px rgba(0,0,0,.5)}
@keyframes acspin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){ .acf-spin .ring{animation-duration:2.4s} }
.acf-ai{margin:10px 0 0;padding:9px 11px;border-radius:11px;font-size:12.5px;font-weight:700;
  background:rgba(47,128,237,.10);color:var(--ink);line-height:1.5}
.acf-ai b{color:#2f80ed}
.acf-ai.warn{background:rgba(232,113,10,.12)}
.acf-ai.warn b{color:#e8710a}
/* อ่านบิลไม่ออกจริง ๆ = แดง ไม่ใช่ส้ม เพราะต้องกรอกเองทั้งหมด ไม่ใช่แค่ตรวจซ้ำ */
.acf-ai.bad{background:rgba(201,74,74,.12);color:var(--red)}
.acf-ai.bad b{color:var(--red)}
/* ===== ปุ่มแก้ไขในหน้ารายละเอียด ===== */
.acd-edit{display:block;width:100%;margin-top:16px;padding:13px;border:0;border-radius:13px;
  font-family:inherit;font-size:14.5px;font-weight:800;color:#fff;cursor:pointer;
  background:linear-gradient(100deg,#2f80ed,#2f8f63)}
.acd-edit:active{transform:scale(.985)}
/* ปุ่มลบ: เส้นขอบแดง ไม่ใช่พื้นแดงทึบ — อยู่ใต้ปุ่มแก้ไขซึ่งเป็นปุ่มที่ควรกดบ่อยกว่า
   ปุ่มทำลายข้อมูลไม่ควรเด่นกว่าปุ่มปลอดภัยที่อยู่ข้างกัน นิ้วจะได้ไม่ไปผิดปุ่ม */
.acd-del{display:block;width:100%;margin-top:9px;padding:12px;border-radius:13px;
  border:1.5px solid rgba(201,74,74,.5);background:transparent;
  font-family:inherit;font-size:13.5px;font-weight:800;color:var(--red);cursor:pointer}
.acd-del:active{transform:scale(.985);background:rgba(201,74,74,.1)}
.acd-del[disabled]{opacity:.55;cursor:default;transform:none}
.acf-err{margin-top:12px;padding:10px 12px;border-radius:11px;font-size:13px;font-weight:700;
  background:rgba(201,74,74,.1);color:var(--red)}
/* ===== วันที่หลุดเดือนที่เปิดอยู่ =====
   แดงใต้ช่องทันทีตอนกรอก + ขอบช่องแดง + ปิดปุ่มบันทึกไปพร้อมกัน
   ดีกว่าปล่อยให้กรอกครบแล้วค่อยเด้ง error ตอนกด เพราะตอนนั้นผู้ใช้ไม่รู้ว่าช่องไหนผิด */
.acf-dwarn{margin:7px 2px 0;font-size:12.5px;font-weight:700;color:var(--red);line-height:1.5}
.acf-bad{border-color:var(--red)!important;box-shadow:0 0 0 2px rgba(201,74,74,.15)}
/* ===== สมุดบันทึกการใช้งาน ===== */
.acaud-f{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px}
.acaud-f .search{flex:1 1 130px;min-width:0;padding:9px 11px;font-size:13px}
.acaud-cnt{font-size:11.5px;font-weight:800;color:var(--sub);margin:0 2px 10px}
.acaud-i{background:var(--card);border:1px solid var(--line);border-radius:13px;
  padding:11px 13px;margin-bottom:9px;box-shadow:var(--shadow-sm)}
.acaud-h{display:flex;align-items:center;gap:8px;margin-bottom:6px}
.acaud-b{flex:0 0 auto;padding:2px 8px;border-radius:7px;font-size:11px;font-weight:800;color:#fff}
.acaud-b.ok{background:#2f8f63}.acaud-b.ed{background:#2f80ed}.acaud-b.rm{background:var(--red)}
.acaud-b.ex{background:var(--sub)}.acaud-b.st{background:#e8710a}
.acaud-t{font-size:11.5px;font-weight:700;color:var(--sub);margin-left:auto}
.acaud-s{font-size:13px;font-weight:700;color:var(--ink);line-height:1.5;word-break:break-word}
.acaud-m{font-size:11px;color:var(--faint);margin-top:4px;word-break:break-all}
.acaud-d{margin-top:8px;padding:8px 10px;border-radius:9px;background:var(--bg2,rgba(127,127,127,.08));
  font-size:12px;line-height:1.7;color:var(--ink);word-break:break-word}
.acaud-d s{color:var(--faint)}
.acaud-d em{font-style:normal;font-weight:800}
.acaud-d .ar{color:var(--sub)}
.acaud-empty{padding:26px 12px;text-align:center;font-size:13px;color:var(--sub)}
.acaud-empty.bad{color:var(--red);font-weight:700}
/* ===== รายการแนะนำตอนพิมพ์ ===== */
.acf-ac{position:relative}
.acf-suglist{position:absolute;left:0;right:0;top:calc(100% + 4px);z-index:5;
  background:var(--card);border:1px solid var(--line);border-radius:12px;
  box-shadow:var(--shadow);overflow-x:hidden;overflow-y:auto;max-height:42vh;
  -webkit-overflow-scrolling:touch;overscroll-behavior:contain}
.acf-suglist button{display:block;width:100%;text-align:left;background:none;border:0;
  padding:10px 13px;font-family:inherit;font-size:14px;font-weight:600;color:var(--ink);cursor:pointer}
.acf-suglist button+button{border-top:1px solid var(--line)}
.acf-suglist button:active{background:rgba(125,135,165,.12)}
/* ===== กราฟแท่งในหน้าหมวด =====
   ค่าใช้จ่ายเป็นตัวชี้วัดเดียว แยกตามหมวด = ซีรีส์เดียว -> ใช้สีเดียวพอ ไม่ต้องมี legend
   ป้ายตัวเลขติดทุกแท่งอยู่แล้ว จึงอ่านได้โดยไม่ต้องพึ่งสี */
.accat-hero{display:flex;align-items:baseline;gap:9px;margin-bottom:16px}
.accat-hero .n{font-size:31px;font-weight:800;letter-spacing:-.7px;line-height:1}
.accat-hero .u{font-size:12.5px;font-weight:700;color:var(--sub)}
.accat-row{margin-bottom:13px}
.accat-top{display:flex;align-items:baseline;gap:8px;margin-bottom:5px}
.accat-top .l{font-size:13px;font-weight:700;color:var(--ink)}
.accat-top .c{font-size:11px;font-weight:700;color:var(--faint)}
.accat-top .v{margin-left:auto;font-size:13.5px;font-weight:800;color:var(--ink)}
.accat-top .p{font-size:11.5px;font-weight:800;color:var(--sub);min-width:38px;text-align:right}
.accat-track{height:9px;border-radius:99px;background:rgba(125,135,165,.13);overflow:hidden}
.accat-fill{display:block;height:100%;width:0;border-radius:99px;
  transition:width .85s cubic-bezier(.22,1,.36,1)}
.accat-row:hover .accat-fill{filter:brightness(1.08)}
.accat-foot{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-top:18px;
  padding-top:15px;border-top:1px solid var(--line)}
.accat-foot div{text-align:center}
.accat-foot .l{font-size:11px;font-weight:700;color:var(--sub);line-height:1.3}
.accat-foot .v{font-size:16px;font-weight:800;color:var(--ink);margin-top:3px}
@media (prefers-reduced-motion:reduce){
  .ac-sbar i,.accat-fill{transition:none}
}
.ac-daygrp{margin-top:15px}
.ac-daygrp:first-child{margin-top:4px}
.ac-dayhd{display:flex;align-items:center;gap:8px;font-size:12px;font-weight:800;color:var(--sub);
  padding:0 2px 7px;border-bottom:1px solid var(--line)}
.ac-dayhd .n{margin-left:auto;font-weight:700;color:var(--faint)}
.ac-row{display:flex;align-items:center;gap:11px;padding:11px 2px;border-bottom:1px solid var(--line)}
.ac-row:last-child{border-bottom:0}
.ac-ic{position:relative;flex:0 0 auto;width:40px;height:40px;border-radius:11px;display:grid;
  place-items:center;font-size:15px;background:rgba(125,135,165,.1);overflow:hidden}
.ac-ic img{width:100%;height:100%;object-fit:cover;display:block}
/* ไอคอนมุมล่างขวาของรูป — รายจ่ายใช้ไอคอนหมวด · รับเงิน/โอนระหว่างทีมใช้ไอคอนประเภท */
.ac-ic .bdg{position:absolute;right:-2px;bottom:-2px;width:18px;height:18px;border-radius:6px;
  display:grid;place-items:center;font-size:10px;background:var(--card);
  box-shadow:0 0 0 1.5px var(--card)}
.ac-row{cursor:pointer;-webkit-tap-highlight-color:transparent}
.ac-row:active{background:rgba(125,135,165,.07)}
.ac-chev{flex:0 0 auto;color:var(--faint);font-size:15px;margin-left:2px}
/* --- กล่องรายละเอียด --- */
/* กรอบรูปต้องมีตั้งแต่ยังไม่โหลด — เดิม <img> ไม่มีความสูงจนกว่ารูปจะมา
   หน้าต่างเลยดูเหมือนว่าง ๆ แล้วรูปค่อยกระโดดเข้ามาดันเนื้อหาลง
   ตั้งความสูงขั้นต่ำไว้ก่อน + แถบไล่แสงวิ่ง บอกว่ากำลังโหลดอยู่ */
.acd-imgwrap{position:relative;display:block;margin-bottom:14px;border-radius:14px;
  border:1px solid var(--line);overflow:hidden;background:rgba(125,135,165,.08)}
.acd-imgwrap.ld{min-height:210px}
.acd-img{display:block;width:100%;max-height:42vh;object-fit:contain}
.acd-imgwrap.ld .acd-img{opacity:0}
.acd-imgwrap .hint{position:absolute;right:8px;bottom:8px;font-size:10.5px;font-weight:800;
  color:#fff;background:rgba(20,24,35,.62);border-radius:7px;padding:3px 7px;pointer-events:none}
.acd-imgwrap.ld .hint{display:none}
/* ชั้นโหลด: แถบแสงวิ่ง + วงหมุน + ตัวหนังสือ */
.acd-ldr{position:absolute;inset:0;display:grid;place-items:center;gap:9px;
  align-content:center;pointer-events:none}
.acd-imgwrap:not(.ld) .acd-ldr{display:none}
.acd-ldr::before{content:'';position:absolute;inset:0;
  background:linear-gradient(100deg,rgba(125,135,165,.05) 30%,rgba(125,135,165,.18) 50%,rgba(125,135,165,.05) 70%);
  background-size:220% 100%;animation:acdshim 1.25s linear infinite}
.acd-ldr .ring{position:relative;width:34px;height:34px;border-radius:50%;
  border:3px solid rgba(125,135,165,.28);border-top-color:var(--sub);animation:acspin .85s linear infinite}
.acd-ldr .tx{position:relative;font-size:11.5px;font-weight:800;color:var(--sub)}
@keyframes acdshim{0%{background-position:130% 0}100%{background-position:-30% 0}}
@media (prefers-reduced-motion:reduce){
  .acd-ldr::before{animation:none}
  .acd-ldr .ring{animation-duration:2.4s}
}
.acd-imgbad{padding:22px 12px;text-align:center;color:var(--sub);font-size:12.5px;font-weight:700}
.acd-amt{font-size:30px;font-weight:800;letter-spacing:-.6px;margin-bottom:14px;line-height:1.1}
.acd-amt.in{color:var(--green)} .acd-amt.out{color:var(--red)} .acd-amt.tf{color:var(--ink)}
.acd-kv{display:flex;gap:12px;padding:9px 0;border-bottom:1px solid var(--line);font-size:13.5px}
.acd-kv:last-child{border-bottom:0}
.acd-kv .k{flex:0 0 96px;color:var(--sub);font-weight:700}
.acd-kv .v{flex:1;min-width:0;color:var(--ink);font-weight:600;word-break:break-word}
.acd-none{padding:20px;text-align:center;color:var(--sub);font-size:13px;
  border:1px dashed var(--line);border-radius:14px;margin-bottom:14px}
.ac-mid{flex:1;min-width:0}
.ac-it{font-weight:700;font-size:14px;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ac-sub{font-size:12px;color:var(--sub);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:2px}
.ac-amt{flex:0 0 auto;font-weight:800;font-size:14.5px;white-space:nowrap;letter-spacing:-.2px}
.ac-amt.in{color:var(--green)}
.ac-amt.out{color:var(--red)}
.ac-amt.tf{color:var(--faint)}
.ac-own{display:inline-flex;align-items:center;gap:4px;font-size:10.5px;font-weight:800;
  margin-right:6px;letter-spacing:.2px;vertical-align:1px}
.ac-own i{width:7px;height:7px;border-radius:99px;display:block;flex:0 0 auto}
/* สีคู่เดียวกับแถบ "ใครเป็นคนจ่าย" ด้านบน ผ่านการตรวจตาบอดสีมาแล้ว
   และมีชื่อกำกับทุกตัว ไม่ได้สื่อด้วยสีอย่างเดียว */
.ac-own.beer{color:#2f80ed} .ac-own.beer i{background:#2f80ed}
.ac-own.boat{color:#e8710a} .ac-own.boat i{background:#e8710a}
/* ---- ช่องค้นหา + ปุ่มตัวกรองในปุ่มเดียว ---- */
.ac-srch{position:relative}
.ac-srch .search{padding-right:54px}
.ac-fbtn{position:absolute;right:7px;top:50%;transform:translateY(-50%);width:38px;height:38px;
  border-radius:11px;border:1px solid var(--line);background:var(--card);color:var(--sub);
  display:grid;place-items:center;cursor:pointer;padding:0}
.ac-fbtn:active{transform:translateY(-50%) scale(.94)}
.ac-fbtn.on{border-color:var(--pri);color:var(--pri);background:rgba(61,74,114,.07)}
.ac-fbtn .n{position:absolute;top:-6px;right:-6px;min-width:17px;height:17px;border-radius:99px;
  background:var(--pri);color:#fff;font-size:10px;font-weight:800;display:grid;place-items:center;padding:0 4px}
.ac-fmenu{position:absolute;right:0;top:calc(100% + 7px);z-index:40;min-width:216px;
  background:var(--card);border:1px solid var(--line);border-radius:14px;
  box-shadow:var(--shadow);padding:6px}
.ac-fmenu button{display:flex;align-items:center;gap:9px;width:100%;border:0;background:none;
  padding:9px 10px;border-radius:10px;font-family:inherit;font-size:13px;font-weight:700;
  color:var(--ink);cursor:pointer;text-align:left}
.ac-fmenu button:active{background:rgba(125,135,165,.12)}
.ac-fmenu .gl{font-size:10.5px;font-weight:800;color:var(--faint);padding:7px 10px 3px}
.ac-fmenu .dot{width:9px;height:9px;border-radius:99px;flex:0 0 auto}
.ac-fmenu .ck{margin-left:auto;color:var(--pri);font-weight:900;font-size:14px}
.ac-fmenu .sep{height:1px;background:var(--line);margin:5px 2px}
.ac-fmenu .off{color:var(--sub);font-weight:800}
.ac-fchips{display:flex;flex-wrap:wrap;gap:6px;margin:10px 0 0}
/* ⚠️ คลาสที่ตั้ง display เองจะ "ทับ" [hidden] ของเบราว์เซอร์ (UA stylesheet ศักดิ์ต่ำกว่า)
   ถ้าไม่เขียนบรรทัดนี้ ป้ายจำนวนตัวกรองจะโผล่เลข 0 ทั้งที่ยังไม่ได้เลือกอะไรเลย */
.ac-fbtn .n[hidden],.ac-fchips[hidden],.ac-fmenu[hidden]{display:none!important}
.ac-fchips span{display:inline-flex;align-items:center;gap:6px;font-size:11px;font-weight:800;
  border:1px solid var(--line);border-radius:99px;padding:4px 10px;color:var(--sub);cursor:pointer}
.ac-fchips span b{color:var(--faint);font-weight:900}
.ac-tag{display:inline-block;font-size:10.5px;font-weight:800;color:var(--faint);
  border:1px solid var(--line);border-radius:6px;padding:0 5px;margin-left:5px;vertical-align:1px}
.ac-tag.bot{color:var(--blue);border-color:var(--blue);opacity:.75}
.ac-empty{padding:26px 8px;text-align:center;color:var(--sub);font-size:13px}
@media(max-width:760px){
  /* 5 ใบบนกริด 2 คอลัมน์ = มีใบโดดเดี่ยวเสมอ — ให้ "คงเหลือรวม" กินเต็มแถวเป็นตัวเด่น
     แล้วที่เหลือ 4 ใบลงตัวพอดี 2 แถว · หมวดหมู่ใช้ทริกใบสุดท้ายกินเต็มถ้าจำนวนเป็นคี่ */
  .ac-kpis{grid-template-columns:repeat(2,1fr)}
  .ac-kpis .uni-kpi:first-child{grid-column:1/-1}
  .ac-kpis .uni-kpi:first-child .knum{font-size:29px}
  .ac-cats{grid-template-columns:repeat(2,1fr)}
  .ac-cats .ac-cat:last-child:nth-child(odd){grid-column:1/-1}
}
@media(hover:hover){.uni-kpi{transition:transform .16s ease,box-shadow .16s ease}.uni-kpi:hover{transform:translateY(-2px);box-shadow:var(--shadow)}}
/* ===== v4 pass: port faceplate = ช่องสี่เหลี่ยมสีทึบ (เขียว=เชื่อมต่อ · น้ำเงิน=PoE · เทา=ว่าง) ===== */
.uportmap{gap:6px}
.uport-t{width:39px;height:39px;border-radius:8px;border:0;background:#e5e9f0;box-shadow:none}
.uport-t .pnum{font-size:12.5px;color:#8a94a6}
/* สีทึบ = ความเร็ว (var(--pc) จาก _uniSpeedColor) · PoE ดูจากไอคอน ⚡ · ว่าง=เทา */
.uport-t.up{background:var(--pc);border:0;box-shadow:none}
.uport-t.up .pnum{color:#fff}
.uport-t.down{background:#eef1f5;border:0}
.uport-t.down .pnum{color:#aab4c0}
.uport-t.off{background:repeating-linear-gradient(45deg,#eef1f5,#eef1f5 4px,#e2e6ef 4px,#e2e6ef 8px);border:0}
.uport-t.off .pnum{color:#b3bcc9}
.uport-t.sfp{width:46px;border:0;border-radius:8px;background:#e5e9f0}
.uport-t.sfp.up{background:var(--pc)}
.uport-t.uplink{outline:2px solid #1e3a8a;outline-offset:1px}
.uport-t.up:hover,.uport-t.down:hover,.uport-t.off:hover{box-shadow:0 6px 15px rgba(20,26,45,.2)}
.uport-t .pbolt{top:1px;right:1px;filter:drop-shadow(0 0 1px rgba(0,0,0,.55))}
.uport-t .pup{top:1px;left:2px;color:#fff}

/* ===== v4 pass: หน้าภาพรวม ให้เหมือน mockup v4 ===== */
/* KPI: ชิปไอคอนลอยมุมขวาบน (ลายเซ็นของ v4) เลขใหญ่ขึ้น เส้น spark เต็มความกว้าง */
.ovk{position:relative;padding:15px 15px 10px}
.ovk .top{display:block;margin-bottom:0}
.ovk .ic{position:absolute;top:13px;right:13px;width:33px;height:33px;border-radius:10px;font-size:15px;margin:0}
.ovk .lb{font-size:11.5px;font-weight:700;color:var(--sub);padding-right:42px;line-height:1.3}
.ovk .val{font-size:26px;margin:5px 0 2px}
.ovk .spark{height:32px;margin:3px 0 5px}
.ovk .ft{font-size:11px}
/* devstrip: ไอคอนไล่เฉดสดแบบ v4 (กล้อง=ม่วง · NVR=ฟ้า · HDD=เขียว) ไอคอนขาว */
.devitem .kico.cam{background:linear-gradient(135deg,#a78bfa,#7c3aed)}
.devitem .kico.nvr{background:linear-gradient(135deg,#38bdf8,#2563eb)}
.devitem .kico.hdd{background:linear-gradient(135deg,#22c55e,#12a594)}
.devitem .kico svg{color:#fff}
.devitem .n{font-size:24px}
/* ต้องตรวจสอบ: avatar ตัวอักษรสีแทน emoji (ตามที่ขอ "ใช้ตัวอักษรแทนรูป") */
.prob{border-radius:16px;padding:13px 14px}
.prob .av{width:40px;height:40px;min-width:40px;border-radius:12px;font-size:18px}
.prob .nm{font-size:13.5px}
/* วงแหวน/โดนัท: เส้นหนานุ่มขึ้นเล็กน้อยให้ดูเต็มแบบ v4 */
.ovring b{font-size:21px}
.dbox b{font-size:22px}
/* วงแหวนซ้อน 3 ชั้น — เลขกลางต้องพอดีรูตรงกลาง ไม่ล้นทับวง */
.ovring-multi{width:138px;height:138px}
.ovring-multi .rc{padding:0 4px}
.ovring-multi b{font-size:17.5px;letter-spacing:-.4px;line-height:1.05}
.ovring-multi span{font-size:9px;line-height:1.15;display:block;white-space:nowrap}
@media(max-width:820px){.ovring-multi{width:126px;height:126px}.ovring-multi b{font-size:16px}}
/* การ์ดหลักในกริด: เงานุ่ม โค้งเท่ากันทั้งหน้า */
.ovw-grid .panel{border-radius:18px}

/* ---- block 3 ---- */

.pve-tile{background:var(--soft);border:1px solid var(--line);border-radius:16px;padding:12px 14px}
.pve-chart{position:relative;width:100%}
.pve-legend{display:flex;flex-wrap:wrap;gap:4px}
.pve-cross{position:absolute;top:0;bottom:0;width:1px;background:var(--sub);opacity:.45;display:none;pointer-events:none}
.pve-tip{position:absolute;top:6px;display:none;pointer-events:none;background:var(--card,#fff);border:1px solid var(--line);border-radius:10px;padding:7px 10px;font-size:12px;box-shadow:var(--shadow-sm);z-index:5;min-width:130px}
.pve-tf{display:inline-flex;gap:4px;background:var(--soft);border:1px solid var(--line);border-radius:10px;padding:3px}
.pve-tf-chip{font-size:12px;padding:4px 10px;border-radius:8px;cursor:pointer;color:var(--sub);font-weight:700}
.pve-tf-chip.on{background:var(--pri,#2563eb);color:#fff}
.pve-badge{font-size:10.5px;font-weight:800;padding:2px 6px;border-radius:6px;background:var(--line);color:var(--sub)}
.pve-badge-vm{background:rgba(79,70,229,.14);color:#4f46e5}
.pve-badge-ct{background:rgba(13,148,136,.16);color:#0d9488}
.pve-tag{font-size:10px;font-weight:700;padding:1px 6px;border-radius:6px;white-space:nowrap;display:inline-block;vertical-align:middle;margin-left:3px}
.pve-alert-chip{display:inline-flex;align-items:center;gap:6px;padding:6px 11px;border-radius:9px;font-size:12.5px;font-weight:700}
.pve-grow{display:flex;align-items:center;gap:10px;padding:9px 6px;border-bottom:1px solid var(--line);cursor:pointer;border-radius:8px;transition:background .12s}
.pve-grow:hover{background:var(--soft)}
.pve-grow{align-items:center}
.pgL{flex:1 1 auto;min-width:0;line-height:1.45}
.pgDot{display:inline-block;width:9px;height:9px;border-radius:50%;vertical-align:middle;margin-right:7px}
.pgL .pve-badge{vertical-align:middle}
.pgNm{font-weight:700;vertical-align:middle;margin-left:2px}
.pgL .pve-tag{vertical-align:middle}
.pgR{display:flex;align-items:center;gap:12px;flex:none}
.pgRam{width:120px}.pgRamT{text-align:right;margin-top:2px;font-variant-numeric:tabular-nums}
.pgCpu{width:44px;text-align:right;font-variant-numeric:tabular-nums}
.pgUp{width:70px;text-align:right}
@media(max-width:640px){.pve-grow{flex-wrap:wrap;gap:6px 10px;align-items:flex-start}.pgR{flex:1 1 100%;justify-content:space-between;gap:14px;padding-left:0;margin-top:2px}.pgRam{flex:1 1 auto;width:auto;min-width:0}.pgCpu,.pgUp{flex:none}}
.pve-ov{position:fixed;inset:0;background:rgba(15,23,42,.5);z-index:9999;display:flex;align-items:flex-start;justify-content:center;padding:24px 16px;overflow:auto}
.pve-card{background:var(--card,#fff);border:1px solid var(--line);border-radius:18px;max-width:580px;width:100%;max-height:90vh;overflow:auto;padding:18px;box-shadow:var(--shadow)}
.pve-cfg-h{font-size:12px;font-weight:800;color:var(--sub);text-transform:uppercase;letter-spacing:.03em;margin:14px 0 3px}
