﻿body {
    background-color: #f4f6f9;
}

/* ===== Trang đăng nhập ===== */
.login-body {
    background: linear-gradient(135deg, #0d6efd 0%, #0a3d91 100%);
    min-height: 100vh;
}

.login-wrapper {
    min-height: 100vh;
}

.login-card {
    width: 100%;
    max-width: 420px;
    border-radius: 1rem;
}

/* ===== Thẻ thống kê Dashboard ===== */
.stat-card {
    border-radius: 1rem;
}

.stat-card-link {
    transition: transform .15s ease, box-shadow .15s ease;
    cursor: pointer;
}

.stat-card-link:hover {
    transform: translateY(-3px);
    box-shadow: 0 .5rem 1rem rgba(0,0,0,.12) !important;
}

.stat-icon {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.25rem;
    margin-bottom: .5rem;
}

.stat-value {
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1.2;
}

.stat-label {
    color: #6c757d;
    font-size: .8rem;
}

/* =========================================================================
   Trang vừa đúng một màn hình
   -------------------------------------------------------------------------
   Trang bản đồ không được có thanh cuộn dọc. Cách làm: biến thân trang thành
   một cột co giãn cao đúng bằng màn hình, rồi để một phần tử duy nhất
   (.md-co-gian) nuốt hết chỗ còn thừa.

   Vì sao không đặt chiều cao bản đồ bằng vh: thanh điều hướng, thanh công cụ
   và hai hàng chú giải cao bao nhiêu là do cỡ chữ và bề rộng cửa sổ quyết định,
   không phải hằng số. Mọi con số vh đoán trước đều sai ở một cỡ màn hình nào đó
   — hoặc thừa ra thanh cuộn, hoặc chừa một dải trống dưới đáy.

   dvh (dynamic viewport height) là để trên điện thoại: thanh địa chỉ của trình
   duyệt trượt ra/vào làm 100vh lớn hơn phần thực sự nhìn thấy.
   ========================================================================= */
body.trang-mot-man-hinh {
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

/* min-height:0 là bắt buộc. Mặc định một flex item không co nhỏ hơn nội dung của nó,
   nên thiếu dòng này thì bản đồ vẫn đẩy trang dài ra đúng như cũ. */
body.trang-mot-man-hinh > main {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* Chân trang chỉ có dòng bản quyền, không đáng đổi lấy một thanh cuộn. */
body.trang-mot-man-hinh > footer {
    display: none;
}

/* Mọi khối trong <main> giữ nguyên chiều cao tự nhiên của nó... */
body.trang-mot-man-hinh > main > * {
    flex: 0 0 auto;
}

/* ...trừ đúng một khối được đánh dấu .md-co-gian: nó nuốt hết chỗ còn thừa,
   và cũng là khối duy nhất chịu co lại khi khung chi tiết mở ra. */
body.trang-mot-man-hinh .md-co-gian {
    flex: 1 1 auto;
    min-height: 180px;   /* cửa sổ quá thấp thì thà cắt bớt chú giải còn hơn để bản đồ biến mất */
    display: flex;
}

/* ===== Bản đồ ===== */
.map-container {
    flex: 1 1 auto;
    height: 100%;
    width: 100%;
    border-radius: .5rem;
    overflow: hidden;
}

.legend-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
}

/* ===== Nhãn tên tủ hiện thường trực trên bản đồ (map.js: bindTooltip) ===== */
.leaflet-tooltip.nhan-tu {
    background: rgba(255, 255, 255, .92);
    border: 1px solid rgba(0, 0, 0, .18);
    border-radius: 4px;
    padding: 1px 5px;
    font-size: .7rem;
    font-weight: 600;
    color: #1f2933;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .18);
    white-space: nowrap;
    pointer-events: none;   /* bấm xuyên qua nhãn để vẫn chọn được marker bên dưới */
}
/* Bỏ mũi nhọn mặc định của tooltip Leaflet cho nhãn gọn. */
.leaflet-tooltip.nhan-tu::before {
    display: none;
}
/* Thu nhỏ xa -> ẩn nhãn (map.js gắn lớp này lên khung bản đồ theo mức phóng). */
.an-nhan-tu .leaflet-tooltip.nhan-tu {
    display: none;
}

/* Mẫu đường cáp trong chú giải: nét liền (cáp treo) / nét đứt (cáp ngầm). */
.legend-line {
    display: inline-block;
    width: 22px;
    height: 0;
    border-top: 3px solid #e67e22;   /* cùng màu đường cáp trên bản đồ */
    vertical-align: middle;
}
.legend-line-dash {
    border-top-style: dashed;
}

/* ===== Thanh nhắc "Cài app ra màn hình chính" (pwa-install.js) ===== */
.pwa-nhac {
    position: fixed;
    left: 12px;
    right: 12px;
    bottom: 12px;
    z-index: 2000;
    display: none;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    background: #fff;
    border: 1px solid #dee2e6;
    border-radius: 12px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, .18);
    transform: translateY(120%);
    transition: transform .25s ease;
}
.pwa-nhac.hien {
    display: flex;
    transform: translateY(0);
}
.pwa-nhac-icon {
    width: 40px;
    height: 40px;
    border-radius: 9px;
    flex: 0 0 auto;
}
.pwa-nhac-chu {
    flex: 1 1 auto;
    min-width: 0;
}
.pwa-nhac-tieude {
    font-weight: 600;
    font-size: .92rem;
}
.pwa-nhac-phu {
    font-size: .78rem;
    color: #6c757d;
}
.pwa-nhac-nut {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 4px;
}
@media (min-width: 768px) {
    .pwa-nhac {
        left: auto;
        right: 16px;
        bottom: 16px;
        max-width: 440px;
    }
}
@media print {
    .pwa-nhac { display: none !important; }
}

/* ===== Ô chọn có tìm kiếm (Tom Select) =====
   Khung của Tom Select không tự chừa chỗ cho mũi tên -> với chữ dài (vd "-- Tất cả
   khu vực --") mũi tên ĐÈ LÊN chữ. Chừa lề phải để chữ và mũi tên không dính nhau. */
.ts-wrapper.single .ts-control { padding-right: 2.1rem !important; }

/* Ô chọn có tìm kiếm: chữ dài PHẢI cắt bớt chứ không được xuống dòng.
   Ô chọn thường của trình duyệt không bao giờ xuống dòng, còn ô này thì có —
   gặp tên dài như "Tủ mô phỏng Ngô Quyền" là ô cao gấp đôi, lệch hẳn so với
   ô bên cạnh (đo được: 52px so với 32px). */
.ts-wrapper.single .ts-control > .item {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

/* Biểu tượng bóng đèn (chỉ dùng ở chế độ "Chỉnh vị trí"). Bình thường đèn vẽ thành chấm
   tròn nhỏ trên canvas — xem nodeChamStyle() trong map.js. */
.marker-offline i,
.marker-on100 i,
.marker-dimmed i,
.marker-fault i,
.marker-off i {
    /* Nhỏ lại: một tuyến vài chục đèn mà biểu tượng to thì chúng chồng lên nhau, nhìn rối hơn
       cả không có biểu tượng. Cỡ này vẫn phân biệt được dáng (bóng đèn / ô vuông / tấm pin). */
    font-size: .85rem;
    text-shadow: 0 0 2px #fff, 0 0 2px #fff;
}

/* Mất kết nối - xám */
.marker-offline i {
    color: #6c757d;
}

/* Bật 100% - xanh dương */
.marker-on100 i {
    color: #0d6efd;
}

/* Đang tiết giảm năng lượng - xanh dương nhạt hơn */
.marker-dimmed i {
    color: #74b9ff;
}

/* Có kết nối, đang bật nhưng mất dòng (đèn không sáng) - vàng */
.marker-fault i {
    color: #f1c40f;
}

/* Có kết nối nhưng đã tắt (Cắt) - bình thường, màu tối để phân biệt với "mất kết nối" */
.marker-off i {
    color: #2c3e50;
}

/* Điểm Tủ điều khiển trên bản đồ - SVG tủ điện vẽ tay.
   Màu thân tủ do JavaScript quyết định theo trạng thái đóng/cắt (xem map.js). */
.marker-cabinet svg {
    filter: drop-shadow(0 2px 2px rgba(0,0,0,.25));
}

/* Tủ vừa nhận lệnh nhưng thiết bị CHƯA báo trạng thái mới về.
   Marker đã đổi sang màu của lệnh vừa gửi, nhấp nháy để nói rõ: đây là điều mong đợi,
   chưa phải điều đã xác nhận. Hết nhấp nháy khi thiết bị báo về đúng chế độ đó. */
.marker-cabinet-pending svg {
    animation: cho-xac-nhan 1s ease-in-out infinite;
}

@keyframes cho-xac-nhan {
    0%, 100% { filter: drop-shadow(0 2px 2px rgba(0,0,0,.25)); opacity: 1; }
    50%      { filter: drop-shadow(0 0 6px #f1c40f); opacity: .65; }
}


/* Người dùng bật "giảm chuyển động" trong hệ điều hành thì không nhấp nháy nữa. */
@media (prefers-reduced-motion: reduce) {
    .marker-cabinet-pending svg {
        animation: none;
        filter: drop-shadow(0 0 5px #f1c40f);
    }
}

/* ===== Menu chuột phải dùng chung (Tủ / Đèn) ===== */
.scada-context-menu {
    position: fixed;
    /* Thấp hơn z-index của modal Bootstrap (1050-1055) để hộp thoại xác nhận / chi tiết
       luôn hiện TRÊN menu chuột phải, không bị menu che mất hoặc hiện ra phía sau. */
    z-index: 1040;
    background: #fff;
    border-radius: .5rem;
    box-shadow: 0 .5rem 1.5rem rgba(0,0,0,.25);
    min-width: 220px;
    padding: .35rem 0;
    max-height: 70vh;
    overflow-y: auto;
}

.scada-context-menu-item {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    padding: .5rem .9rem;
    font-size: .9rem;
    color: #212529;
    cursor: pointer;
}

.scada-context-menu-item:hover:not(.disabled) {
    background-color: #f0f4ff;
}

.scada-context-menu-item.disabled {
    color: #adb5bd;
    cursor: default;
}

.scada-context-menu-sep {
    height: 1px;
    background: #e9ecef;
    margin: .3rem 0;
}

.cabinet-node-list {
    max-height: 220px;
    overflow-y: auto;
}

.cabinet-node-row {
    border-radius: .35rem;
    cursor: context-menu;
}

.cabinet-node-row:hover {
    background-color: #f8f9fa;
}

/* ===== Toast thông báo góc màn hình ===== */
.scada-toast {
    position: fixed;
    right: 20px;
    bottom: 20px;
    z-index: 3000;
    min-width: 240px;
    max-width: 360px;
    padding: .75rem 1rem;
    border-radius: .5rem;
    color: #fff;
    font-size: .9rem;
    box-shadow: 0 .5rem 1.5rem rgba(0,0,0,.25);
    opacity: 0;
    transform: translateY(10px);
    transition: opacity .2s ease, transform .2s ease;
    pointer-events: none;
}

.scada-toast.show {
    opacity: 1;
    transform: translateY(0);
}

.scada-toast-success { background-color: #198754; }
.scada-toast-error { background-color: #dc3545; }

/* ===== Modal Chi tiết Tủ (4 khối theo đặc tả) ===== */
.cabinet-card-header {
    cursor: pointer;
}

.cabinet-section-title {
    font-weight: 700;
    border-bottom: 2px solid #e9ecef;
    padding-bottom: .35rem;
    margin-top: 1.25rem;
    margin-bottom: .75rem;
    color: #0d6efd;
}

.cabinet-section-title:first-of-type {
    margin-top: 0;
}

.cabinet-info-box {
    background: #f8f9fa;
    border-radius: .5rem;
    padding: .5rem .75rem;
    height: 100%;
}

.cabinet-info-box .label {
    font-size: .75rem;
    color: #6c757d;
}

.cabinet-info-box .value {
    font-weight: 600;
}

/* ===== Khối "Lịch biểu hiện tại" trong hộp thoại đặt lịch =====
   Mỗi mốc là một viên: giờ in đậm, mũi tên, rồi việc sẽ xảy ra. Xếp ngang và tự xuống dòng,
   nên 5 mốc của tủ hay 9 mốc của đèn đều gọn trong vài dòng, không đẩy bảng nhập xuống dưới. */
.lich-khung {
    background: #f2f7fd;
    border: 1px solid rgba(42,120,214,.20);
    border-radius: .5rem;
    padding: .6rem .75rem;
}

.lich-tieu-de {
    font-size: .8rem;
    font-weight: 600;
    color: #1c5cab;
    margin-bottom: .5rem;
}

.lich-danh-sach {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem;
}

.lich-moc {
    display: inline-flex;
    align-items: center;
    background: #fff;
    border: 1px solid rgba(11,11,11,.10);
    border-radius: 999px;
    padding: .18rem .6rem;
    font-size: .82rem;
    white-space: nowrap;
}

.lich-gio {
    font-weight: 700;
    color: #0b0b0b;
    /* Chữ số đều bề ngang thì cột giờ thẳng hàng dù là 1 hay 11. */
    font-variant-numeric: tabular-nums;
}

.lich-mo-ta { color: #52514e; }

.lich-chu-thich {
    font-size: .72rem;
    color: #6c757d;
    margin-top: .5rem;
}

/* =====================================================================
   BẢNG (dùng chung mọi trang): kẻ vạch dọc phân tách từng ô + căn giữa.

   Ô nào cần căn khác thì dùng lớp tiện ích của Bootstrap (.text-start /
   .text-end / .text-center) — các lớp đó có !important nên luôn thắng
   quy tắc ở đây (ví dụ cột nút thao tác đang dùng .text-end vẫn dạt phải).
   ===================================================================== */
.table > :not(caption) > * > th,
.table > :not(caption) > * > td {
    /* Kẻ ĐỦ BỐN PHÍA từng ô -> bảng thành lưới kín, in ra mới ra hình cái bảng.
       Trước đây chỉ kẻ bên PHẢI mỗi ô: nhìn trên màn hình còn tạm, nhưng in ra thì mép trên,
       mép dưới, mép trái và mép phải của bảng đều HỞ TOANG. */
    border: 1px solid #dee2e6;
    text-align: center;
    vertical-align: middle;
}

/* Viền ngoài của cả bảng — đậm hơn một chút cho ra dáng cái khung. */
.table {
    border: 1px solid #dee2e6;
}
.table > :not(caption) > * > th:last-child,
.table > :not(caption) > * > td:last-child {
    border-right: 0;   /* mép phải bảng đã có viền, không kẻ thêm cho thừa */
}

/* Liên kết trong bảng: bỏ gạch chân cho bảng đỡ rối; vẫn giữ màu xanh để biết bấm được,
   và chỉ gạch chân khi rê chuột vào. */
.table a {
    text-decoration: none;
}
.table a:hover {
    text-decoration: underline;
}

@media print {
    /* In ra giấy: vạch dọc đậm hơn cho rõ. */
    .table > :not(caption) > * > th,
    .table > :not(caption) > * > td {
        border-right: 1px solid #999 !important;
    }
    .table > :not(caption) > * > th:last-child,
    .table > :not(caption) > * > td:last-child {
        border-right: 0 !important;
    }
}

/* ===== Mũi tên sắp xếp cột (table-sort.js) ===== */
.js-sort thead th .th-arrow {
    font-size: .75rem;
    color: #adb5bd;
    user-select: none;
}
.js-sort thead th[data-dir] .th-arrow {
    color: #0d6efd;   /* cột đang sắp: mũi tên đậm màu */
}
.js-sort thead th:hover {
    background-color: #eef2ff;
}

/* ===== Modal xác nhận gửi lệnh ===== */
.result-box {
    min-height: 1.2em;
}

/* ===== Phân tầng z-index cho các hộp thoại lồng nhau =====
   cabinetDetailModal (mặc định Bootstrap ~1055) là tầng gốc.
   nodeListModal mở TỪ TRONG cabinetDetailModal -> phải hiện TRÊN.
   confirmSendModal mở TỪ TRONG cả 2 cái trên (tầng xác nhận cuối) -> phải hiện TRÊN CÙNG.
   Bootstrap gán z-index giống nhau cho mọi modal theo mặc định nên cần ép riêng như dưới đây,
   không phụ thuộc modal nào được thêm vào HTML trước/sau. */
#nodeListModal {
    z-index: 1075;
}

#nodeScheduleModal, #nodesScheduleBulkModal {
    z-index: 1080;
}

#quickAddModal, #quickAddGroupModal {
    z-index: 1085;
}

#confirmSendModal {
    z-index: 1095;
}

/* Lớp phủ mờ (backdrop) của các modal mở sau cũng phải ăn theo, không thì vẫn bị modal gốc che dấu.
   Thứ tự lồng nhau tối đa: cabinetDetailModal(1055) -> nodeListModal(1075) ->
   nodeScheduleModal(1080) -> confirmSendModal(1095) */
.modal-backdrop ~ .modal-backdrop {
    z-index: 1070;
}

.modal-backdrop ~ .modal-backdrop ~ .modal-backdrop {
    z-index: 1078;
}

.modal-backdrop ~ .modal-backdrop ~ .modal-backdrop ~ .modal-backdrop {
    z-index: 1090;
}

/* =========================================================================
   Khung chi tiết dưới bản đồ
   -------------------------------------------------------------------------
   Mắt đọc từ trái sang phải theo đúng thứ tự người dùng cần:
   "cái gì" (định danh) -> "đang thế nào" (số liệu) -> "làm gì" (điều khiển).
   Không lồng bảng trong bảng. Số liệu quan trọng hiện dạng thẻ, đọc được từ xa
   khi đang giới thiệu cho khách.
   ========================================================================= */
.md-panel {
    position: relative;
    margin-top: .5rem;
    background: #fff;
    border: 1px solid rgba(11,11,11,.08);
    border-radius: .75rem;
    box-shadow: 0 2px 10px rgba(11,11,11,.06);
    overflow: hidden;
}

/* Vạch màu trạng thái ở mép trái, JS đổi background theo tủ. */
.md-stripe {
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 4px;
    background: #c3c2b7;
}

/* ---------- Đầu khung ---------- */
.md-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    padding: .35rem .6rem .35rem .8rem;
    border-bottom: 1px solid rgba(11,11,11,.07);
    background: #fbfbfa;
}

.md-head-left { display: flex; align-items: center; gap: .6rem; min-width: 0; }

.md-avatar {
    flex: 0 0 auto;
    width: 24px; height: 24px;
    display: grid; place-items: center;
    border-radius: 50%;
    background: #eef1f4;
    color: #52514e;
    font-size: .72rem;
}

.md-titles { display: flex; flex-direction: column; min-width: 0; line-height: 1.15; }

.md-name {
    font-weight: 650;
    font-size: .86rem;
    color: #0b0b0b;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.md-sub {
    font-size: .72rem;
    color: #898781;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Nhãn trạng thái: viền + chữ cùng màu, KHÔNG tô nền đặc. Nền đặc ở cỡ chữ này
   khiến chữ trắng trên xanh nhạt gần như không đọc được. */
.md-state {
    flex: 0 0 auto;
    font-size: .72rem;
    font-weight: 600;
    padding: .12rem .5rem;
    border-radius: 999px;
    border: 1px solid currentColor;
    white-space: nowrap;
}

.md-head-right { display: flex; gap: .25rem; flex: 0 0 auto; }

.md-icon-btn {
    width: 24px; height: 24px;
    display: grid; place-items: center;
    border: 1px solid rgba(11,11,11,.12);
    border-radius: .4rem;
    background: #fff;
    color: #52514e;
    font-size: .75rem;
    cursor: pointer;
}
.md-icon-btn:hover { background: #f2f2f0; }

/* ---------- Thân khung: 3 cột ---------- */
.md-body {
    display: grid;
    /* Thứ tự cột: Điều khiển | Thông số | Thông tin.
       Cột THÔNG SỐ hẹp hơn hai cột kia: nó chỉ có 4 ô số ngắn (227.06 V, 0.007 A...), để rộng
       thì mỗi ô toàn khoảng trắng. Chỗ tiết kiệm được nhường cho Điều khiển và Thông tin —
       hai cột chứa chữ dài (tên nút, địa chỉ, toạ độ). */
    grid-template-columns: minmax(240px, 1.1fr) minmax(200px, .8fr) minmax(220px, 1.1fr);

    /* Khung chi tiết nằm DƯỚI bản đồ và đẩy bản đồ co lại -> mỗi centimet của khung là một
       centimet bản đồ bị mất. Nhưng nếu chặn theo tỉ lệ màn hình (32vh như trước) thì màn hình
       thấp lại bị cuộn trong khung, còn màn hình cao thì khung phình ra vô ích.
       Chặn theo KHOẢNG: không bao giờ thấp hơn 170px (đủ chứa hết nội dung, khỏi cuộn) và
       không bao giờ cao quá 210px (khỏi ăn hết bản đồ). */
    max-height: clamp(170px, 22vh, 210px);
    overflow-y: auto;
}

.md-col { padding: .45rem .6rem; min-width: 0; }
.md-col + .md-col { border-left: 1px solid rgba(11,11,11,.07); }
/* Lề trái áp cho CỘT ĐẦU TIÊN, dù đó là cột nào — trước đây gắn cứng vào cột Thông tin,
   nên đổi thứ tự một cái là lề trái đi theo cột đó, cột đầu dính sát mép khung. */
.md-body > .md-col:first-child { padding-left: .8rem; }

@media (max-width: 1199.98px) {
    .md-body { grid-template-columns: 1fr 1fr; }
    .md-col-actions { grid-column: 1 / -1; border-left: 0; border-top: 1px solid rgba(11,11,11,.07); }
}
@media (max-width: 767.98px) {
    .md-body { grid-template-columns: 1fr; }
    .md-col + .md-col { border-left: 0; border-top: 1px solid rgba(11,11,11,.07); }
}

.md-section {
    font-size: .62rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: #898781;
    margin-bottom: .25rem;
}
.md-block + .md-block { margin-top: .5rem; }

/* ---------- Cột 1: danh sách nhãn / giá trị ---------- */
.md-list { display: flex; flex-direction: column; }

.md-row {
    display: flex;
    justify-content: space-between;
    gap: .75rem;
    padding: .12rem 0;
    font-size: .74rem;
    border-bottom: 1px solid rgba(11,11,11,.05);
}
.md-row:last-child { border-bottom: 0; }

.md-key { color: #898781; white-space: nowrap; }
.md-val {
    font-weight: 600; color: #0b0b0b; text-align: right;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---------- Cột 2: thẻ số liệu ---------- */
.md-tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: .3rem; }
.md-tiles-2 { grid-template-columns: repeat(2, 1fr); }

.md-tile {
    background: #f7f8f9;
    border: 1px solid rgba(11,11,11,.06);
    border-radius: .45rem;
    padding: .25rem .3rem;
    text-align: center;
    min-width: 0;
}
.md-tile-name  { font-size: .6rem; color: #898781; text-transform: uppercase; letter-spacing: .03em; }
.md-tile-big   { font-size: .9rem; font-weight: 650; color: #0b0b0b; line-height: 1.25; }
/* Dòng dưới (dòng điện) đọc ngang hàng với dòng trên (điện áp): cùng cỡ chữ, cùng độ đậm.
   Cả hai đều là số đo người vận hành cần, không cái nào là chú thích của cái nào. */
.md-tile-small { font-size: .9rem; font-weight: 650; color: #0b0b0b; line-height: 1.25; }
.md-tile-unit  { font-size: .68rem; color: #898781; font-weight: 400; }

/* Thẻ mức tiết giảm của đèn: cùng cỡ mọi thẻ khác, chỉ tô xanh cho nổi. */
.md-tile-dim {
    background: #eaf2fd;
    border-color: rgba(42,120,214,.28);
}
.md-tile-dim .md-tile-big { color: #1c5cab; }

/* Con số quan trọng gói trong MỘT DÒNG (trước là khối lớn + thanh tiến trình, cao ~70px). */
.md-strong {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .5rem;
    margin-top: .3rem;
    padding: .25rem .4rem;
    background: #eaf2fd;
    border: 1px solid rgba(42,120,214,.22);
    border-radius: .45rem;
}
.md-strong-name  { font-size: .66rem; color: #52514e; }
.md-strong-value { font-size: .9rem; font-weight: 650; color: #1c5cab; white-space: nowrap; }

.md-seg { display: grid; grid-template-columns: repeat(4, 1fr); gap: .25rem; }
.md-seg .md-act {
    font-size: .72rem;
    padding: .28rem .2rem;
    border-radius: .4rem;
    border: 1px solid rgba(11,11,11,.14);
    background: #fff;
    color: #0b0b0b;
    cursor: pointer;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.md-seg .md-act:hover { background: #f2f2f0; }

/* Chế độ tủ đang chạy: tô nền màu tương ứng để biết ngay đang ở đâu. */
.md-seg .md-act.dang-chay { color: #fff; border-color: transparent; font-weight: 600; }

.md-btns { display: flex; flex-wrap: wrap; gap: .25rem; }
.md-btns .md-act {
    font-size: .72rem;
    padding: .25rem .5rem;
    border-radius: .4rem;
    border: 1px solid rgba(11,11,11,.14);
    background: #fff;
    color: #0b0b0b;
    cursor: pointer;
}
.md-btns .md-act:hover { background: #f2f2f0; }
.md-act[disabled] { opacity: .55; cursor: default; }

/* Nút "Chỉ đường" là thẻ <a> (mở Google Maps) nhưng phải trông y hệt các nút tác vụ khác. */
.md-btns a.md-act {
    display: inline-flex;
    align-items: center;
    text-decoration: none;
}

.md-inline { display: flex; gap: .3rem; align-items: center; }
.md-inline select,
.md-rename input {
    font-size: .78rem; padding: .2rem .45rem;
    border: 1px solid rgba(11,11,11,.14); border-radius: .4rem;
    background: #fff; color: #0b0b0b;
}
.md-rename { display: flex; gap: .3rem; }
.md-rename input { flex: 1 1 auto; min-width: 0; }

.md-foot { font-size: .72rem; }
.md-foot:not(:empty) { padding: .4rem .85rem .5rem 1.1rem; }

/* ---------- Chế độ tối ---------- (theo NÚT trong app: data-theme. App luôn đặt data-theme lúc tải,
   theo lựa chọn đã lưu hoặc theo hệ điều hành, nên chỉ cần một điều kiện duy nhất này.) */
:root[data-theme="dark"] .md-panel { background: #1a1a19; border-color: rgba(255,255,255,.1); }
:root[data-theme="dark"] .md-head  { background: #202020; border-bottom-color: rgba(255,255,255,.08); }
:root[data-theme="dark"] .md-name,
:root[data-theme="dark"] .md-val,
:root[data-theme="dark"] .md-tile-big,
:root[data-theme="dark"] .md-tile-small { color: #fff; }
:root[data-theme="dark"] .md-avatar { background: #2c2c2a; color: #c3c2b7; }
:root[data-theme="dark"] .md-col + .md-col { border-left-color: rgba(255,255,255,.08); }
:root[data-theme="dark"] .md-row { border-bottom-color: rgba(255,255,255,.06); }
:root[data-theme="dark"] .md-tile { background: #202020; border-color: rgba(255,255,255,.07); }
:root[data-theme="dark"] .md-icon-btn,
:root[data-theme="dark"] .md-seg .md-act,
:root[data-theme="dark"] .md-btns .md-act,
:root[data-theme="dark"] .md-rename input,
:root[data-theme="dark"] .md-inline select {
    background: #202020; color: #e8e8e6; border-color: rgba(255,255,255,.14);
}
:root[data-theme="dark"] .md-strong    { background: #14273c; border-color: rgba(57,135,229,.35); }
:root[data-theme="dark"] .md-strong-value { color: #86b6ef; }
:root[data-theme="dark"] .md-tile-dim  { background: #14273c; border-color: rgba(57,135,229,.35); }
:root[data-theme="dark"] .md-tile-dim .md-tile-big { color: #86b6ef; }

/* ===== Thẻ tủ điều khiển (trang Điều khiển) =====
   Thu gọn để mỗi hàng chứa được nhiều tủ hơn. Vẫn giữ vùng bấm đủ lớn cho ngón tay. */
.cabinet-card {
    border-radius: .6rem;
}

.cabinet-card-title {
    font-size: .95rem;
    font-weight: 600;
    line-height: 1.2;
}

.cabinet-card .badge {
    font-size: .68rem;
    padding: .25em .45em;
}

.cabinet-phase-table {
    font-size: .78rem;
}

.cabinet-phase-table th,
.cabinet-phase-table td {
    padding: .15rem .3rem;
}

/* Trên điện thoại, 2 tủ mỗi hàng nên chữ phải nhỏ thêm một nấc để không vỡ. */
@media (max-width: 575.98px) {
    .cabinet-card-title { font-size: .85rem; }
    .cabinet-phase-table { font-size: .72rem; }
}

/* ===== Thanh điều hướng =====
   Có tới 9 mục menu cộng thương hiệu và khu vực tài khoản. Với cỡ chữ mặc định của Bootstrap
   (1rem) và khoảng đệm rộng, tổng chiều rộng vượt quá màn hình nên chữ bị ngắt xuống dòng
   giữa chừng ("Tổng / quan", "Điều / khiển"). Thu nhỏ chữ, thu hẹp khoảng đệm và cấm ngắt dòng. */
.navbar-brand.fw-bold {
    font-size: 1.05rem;
}

.navbar .nav-link {
    font-size: .875rem;
    padding-left: .55rem;
    padding-right: .55rem;
    white-space: nowrap;   /* thà tràn ngang còn hơn vỡ chữ làm hai dòng */
}

.navbar .nav-link i {
    font-size: .85em;      /* biểu tượng theo cỡ chữ, không lấn át nhãn */
}

/* Khu vực tài khoản (tên đăng nhập + nút Đăng xuất) cũng phải gọn tương ứng. */
.navbar .navbar-account,
.navbar .btn {
    font-size: .875rem;
    white-space: nowrap;
}

/* Vẫn ở dạng thanh ngang nhưng chưa thật rộng (1200px-1699px): siết thêm một nấc.
   Dưới 1200px thanh đã thu về nút menu (navbar-expand-xl) nên không cần xử lý.

   ⚠ NGƯỠNG TRÊN đã nâng 1499 -> 1699. Lý do: thanh menu nay có 12 mục (ghi chú cũ nói 9 mục là đã
   lạc hậu) cộng thêm nút chọn ngôn ngữ. Nhãn tiếng Việt dài hơn tiếng Anh khá nhiều ("Điều khiển"
   vs "Control", "Phân quyền" vs "Permissions"), nên ở bản tiếng Việt thanh menu tràn và ĐẨY NÚT
   "ĐĂNG XUẤT" KHUẤT KHỎI MÀN HÌNH — người dùng không thoát ra được. */
@media (min-width: 1200px) and (max-width: 1699px) {
    .navbar .nav-link {
        font-size: .8rem;
        padding-left: .4rem;
        padding-right: .4rem;
    }

    .navbar-brand.fw-bold {
        font-size: .95rem;
    }
}

/* Dưới 1500px (laptop 1366 / 1440 — cỡ màn rất phổ biến): giấu BIỂU TƯỢNG của các mục menu, chỉ
   giữ chữ. 12 mục × ~20px biểu tượng = tiết kiệm khoảng 240px, đủ để cả thanh vừa màn hình.
   Giữ chữ bỏ biểu tượng chứ không làm ngược lại: chữ mới là thứ người dùng đọc để biết bấm vào đâu. */
@media (min-width: 1200px) and (max-width: 1499px) {
    .navbar .navbar-nav .nav-link i { display: none; }
    .navbar .nav-link { padding-left: .35rem; padding-right: .35rem; }
}

/* Dưới 1600px: giấu TÊN người dùng, chỉ giữ biểu tượng. Tên tài khoản là thứ ít cần nhất trên
   thanh (đã biết mình là ai), trong khi nút "Đăng xuất" thì luôn phải bấm được. Rê chuột vào
   biểu tượng vẫn xem được tên. */
@media (max-width: 1599px) {
    .navbar .navbar-account .ten-tk { display: none; }
}

/* ===== Responsive tinh chỉnh cho điện thoại ===== */
@media (max-width: 576px) {
    .stat-value {
        font-size: 1.3rem;
    }

    .navbar-brand {
        font-size: 1rem;
    }

    .table-responsive {
        font-size: .85rem;
        -webkit-overflow-scrolling: touch;   /* cuộn ngang mượt trên iOS */
    }
}


/* ==========================================================================
   Căn LỀ TRÁI cho các Ô DỮ LIỆU chứa văn bản dài (tên thiết bị, địa chỉ).

   Quy tắc chung của bảng là căn giữa — hợp với số liệu, nhưng tên và địa chỉ
   căn giữa thì nhìn nhấp nhô, khó dò mắt theo cột. Class .td-trai ghi đè cho
   đúng những ô đó.

   CHỈ ÁP CHO <td>, KHÔNG áp cho <th>:
   Trước đây quy tắc này áp cho cả hai, nên tiêu đề của mấy cột đó cũng bị kéo
   sang trái trong khi mọi tiêu đề khác vẫn căn giữa -> hàng tiêu đề nhấp nhô,
   chỗ cao chỗ thấp, nhìn như bảng bị lỗi. Tiêu đề là NHÃN CỦA CẢ CỘT nên luôn
   căn giữa; còn dữ liệu bên dưới muốn căn trái là chuyện của dữ liệu.
   ========================================================================== */
.table > :not(caption) > * > td.td-trai {
    text-align: left;
}


/* ==========================================================================
   IN DANH SÁCH (Danh sách tủ / Danh sách điểm sáng)
   Khi in, chỉ giữ lại tiêu đề và bảng dữ liệu. Ẩn menu, ô tìm kiếm, các nút
   thao tác và cột chứa nút — in ra giấy không ai bấm được nút, để lại chỉ
   tốn giấy và làm bảng vỡ cột.
   ========================================================================== */
@media print {
    /* ----------------------------------------------------------------------
       BỎ TIÊU ĐỀ / CHÂN TRANG MẶC ĐỊNH CỦA TRÌNH DUYỆT
       (ngày giờ ở góc trái, địa chỉ web "geotech.iotlighting.vn/Node" ở góc phải,
       số trang ở chân...). Những dòng đó do TRÌNH DUYỆT tự thêm và nằm trong phần
       LỀ của trang giấy. Đặt lề trang = 0 thì trình duyệt không còn chỗ vẽ chúng
       -> biến mất hoàn toàn, không phụ thuộc người dùng có tắt "Headers and footers"
       trong hộp thoại in hay không.

       Bù lại lề bằng padding của <main> để chữ không sát mép giấy. Đặt lề 0 cũng cho
       vùng in RỘNG HƠN nên nội dung dồn gọn hơn -> bớt bị tràn sang một trang trắng.
       ---------------------------------------------------------------------- */
    /* IN SẠCH: KHÔNG có ngày giờ (góc trái) và địa chỉ web -> đặt LỀ GIẤY = 0 để trình duyệt không còn
       chỗ tự in mấy dòng đó (không cần người dùng tự tắt gì cả).
       LỀ VĂN BẢN (trên 20 · dưới 20 · trái 30 · phải 15 mm) được tạo bằng:
         - trái/phải + trên(trang 1): padding của <body>;
         - trên(trang 2,3...) và dưới(mọi trang): CHÈN DÒNG TRỐNG vào <thead>/<tfoot> của bảng (JS ở
           _Layout). thead/tfoot tự LẶP mỗi trang nên thành lề đều; dòng trống dùng border-style:hidden
           nên KHÔNG có đường kẻ 2 bên (giống dấu enter/khoảng trắng của Word). */
    @page { margin: 0; }
    html, body { margin: 0 !important; height: auto !important; }
    /* Lề văn bản: trên 20 · phải 15 · dưới 0 (lề dưới do dòng trống tfoot lo, tránh cộng dồn) · trái 30 mm.
       Trái/phải/trên(trang 1) do padding body; trên(trang 2+) và dưới(mọi trang) do dòng trống thead/tfoot. */
    body { padding: 20mm 15mm 0 30mm !important; }
    main.container-fluid { padding: 0 !important; }
    .tieu-de-in { margin-top: 0 !important; margin-bottom: .4rem !important; }

    /* Huy hiệu cảnh báo "x sự cố" ở góc: KHÔNG in ra giấy. */
    #thanhCanhBao, .gd-thanh-canh-bao { display: none !important; }

    /* TRANG TRẮNG CUỐI: bỏ khoảng thừa dưới phần tử cuối để không đẩy sang trang mới. */
    main > *:last-child { margin-bottom: 0 !important; }
    .card, .table { margin-bottom: 0 !important; }
    footer { display: none !important; }

    /* ----------------------------------------------------------------------
       LỖI ĐÃ SỬA — IN RA BỊ "NHẢY Ô":

       Bản cũ có dòng   th[data-nosort] { display: none }
       Nó ẩn TIÊU ĐỀ của mọi cột không sắp xếp được (cột "#", cột nút...) NHƯNG
       KHÔNG ẩn các Ô DỮ LIỆU của cột đó. Tiêu đề mất một ô, thân bảng vẫn đủ ô
       -> toàn bảng TRƯỢT một cột: số thứ tự rơi vào cột "Loại", tên rơi vào cột
       "Mã"... Mọi báo cáo đều sai.

       NGUYÊN TẮC: ẩn một cột thì phải ẩn CẢ tiêu đề LẪN ô dữ liệu của nó. Cách
       duy nhất an toàn là đánh dấu bằng class .no-print / .khong-in đặt trên CẢ
       <th> lẫn <td>. TUYỆT ĐỐI không ẩn cột dựa theo thuộc tính chỉ có ở <th>.
       ---------------------------------------------------------------------- */
    .khong-in,
    .no-print,
    nav.navbar,
    footer,
    .btn {
        display: none !important;
    }

    /* Ô TÍCH CHỌN khi in: ẩn HẲN cả cột (mọi bảng đều có ô chọn) — bản in không cần chọn gì.
       AN TOÀN, KHÔNG TRƯỢT Ô: ẩn CẢ <th> (ô "chọn tất cả") LẪN <td> (ô tích từng dòng) của
       ĐÚNG cột đó. Mọi bảng trong web đều để ô chọn-tất-cả là <th> chứa checkbox và ô từng dòng
       là <td> chứa checkbox, nên hai selector dưới luôn khớp thành CẶP -> mất trọn một cột, cân đối. */
    table thead th:has(> input[type="checkbox"]),
    table tbody td:has(> input[type="checkbox"]) {
        display: none !important;
    }

    /* Dự phòng cho trình duyệt cũ KHÔNG hỗ trợ :has -> rule trên bị bỏ qua, dùng cách cũ:
       ẩn phần tử bên trong nhưng GIỮ nguyên số cột (ô trống, không trượt). */
    .xh-check,
    #xhCheckAll,
    .ahl-check,
    .bh-check,
    .bt-check,
    .tc-check,
    .form-check-input {
        visibility: hidden !important;
    }

    .card { border: none !important; box-shadow: none !important; }
    .table { font-size: 11pt; }

    /* Mũi tên sắp xếp ⇅ in ra vô nghĩa, nhưng chỉ ẩn CHỮ, không ẩn cả ô. */
    .th-arrow { display: none !important; }

    /* Tiêu đề in: tên trang + ngày in. Cỡ chữ BẰNG chữ trong bảng và IN ĐẬM — tiêu đề bé hơn
       nội dung thì nhìn như chú thích, không ra tiêu đề. */
    .tieu-de-in {
        display: block !important;
        text-align: center;
        margin-bottom: .5rem;
    }
    .tieu-de-in-ten {
        font-size: 15pt;
        font-weight: 700;
    }
    .tieu-de-in-ngay {
        font-size: 10pt;
        color: #444;
    }

    /* Máy in thường bỏ màu nền và làm nhạt đường kẻ -> ép giữ lưới, nếu không bảng in ra trống
       trơn không thấy ô nào.
       CHỈ kẻ Ô (th/td) — KHÔNG kẻ viền thẻ <table>. Vì khi bảng dài xuống nhiều trang, viền của thẻ
       table chạy DỌC suốt chiều cao bảng ở mỗi trang, rơi cả vào vùng DÒNG TRỐNG (lề) thành 2 đường
       kẻ 2 bên. Bỏ viền table thì lề in ra sạch; lưới bảng vẫn đủ nhờ viền của các ô ngoài cùng. */
    .table > :not(caption) > * > th,
    .table > :not(caption) > * > td {
        border: 1px solid #666 !important;
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }
    .table { border: 0 !important; }

    .card { border: none !important; box-shadow: none !important; }
}

/* Bình thường không hiện dòng tiêu đề dành riêng cho bản in. */
.tieu-de-in { display: none; }


/* ==========================================================================
   THANH MENU: LÀM CHỮ VÀ BIỂU TƯỢNG NÉT HẲN

   Hai nguyên nhân khiến thanh menu nhìn mờ như vỡ ảnh:

   1. Bootstrap "navbar-dark" để chữ ở độ đục CHỈ 0.55 (--bs-navbar-color:
      rgba(255,255,255,.55)). Chữ trắng mờ hơn nửa trên nền xanh -> xám xịt,
      đọc mỏi mắt. Kéo lên gần trắng hẳn.

   2. Trình duyệt mặc định khử răng cưa kiểu subpixel. Kiểu đó tốt cho chữ ĐEN
      trên nền TRẮNG, nhưng với chữ SÁNG trên nền TỐI thì nó làm nét chữ dày
      bệt ra, trông nhoè. Chuyển sang antialiased (khử răng cưa theo mức xám)
      cho riêng thanh menu -> nét đanh lại.
   ========================================================================== */
.navbar.bg-primary {
    --bs-navbar-color: rgba(255, 255, 255, .92);
    --bs-navbar-hover-color: #fff;
    --bs-navbar-active-color: #fff;
    --bs-navbar-brand-color: #fff;
    --bs-navbar-brand-hover-color: #fff;

    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}

.navbar.bg-primary .nav-link,
.navbar.bg-primary .navbar-brand,
.navbar.bg-primary .navbar-account,
.navbar.bg-primary .btn {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Chữ menu hơi đậm lên một nấc: ở cỡ nhỏ (.875rem) nét mảnh dễ bị "loãng". */
.navbar.bg-primary .nav-link {
    font-weight: 500;
}

/* Biểu tượng Font Awesome cũng phải khử răng cưa, nếu không rìa icon lởm chởm. */
.navbar.bg-primary .nav-link i,
.navbar.bg-primary .navbar-brand i,
.navbar.bg-primary .btn i {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    opacity: 1;          /* không để icon mờ hơn chữ */
}

/* Đang ở trang nào thì mục đó nổi hẳn lên, khỏi phải dò. */
.navbar.bg-primary .nav-link:hover,
.navbar.bg-primary .nav-link:focus {
    color: #fff;
}


/* ==========================================================================
   BẢN ĐỒ: DẤU HIỆU "ĐANG CHỌN"

   Bấm vào một tủ (hoặc một chấm đèn) giữa hàng trăm cái giống hệt nhau mà không
   có dấu gì thì không biết mình đang xem cái nào — phải dò theo tên ở khung chi
   tiết. Đánh dấu rõ ràng ngay trên bản đồ.

   Chấm ĐÈN đang chọn được phóng to + viền đỏ (làm trong map.js, vì chấm vẽ trên
   canvas nên CSS không với tới). Còn TỦ là biểu tượng HTML nên đánh dấu bằng CSS.
   ========================================================================== */
.leaflet-marker-icon.dang-chon {
    filter: drop-shadow(0 0 6px #ff1744) drop-shadow(0 0 2px #ff1744);
    z-index: 1000 !important;
}

.leaflet-marker-icon.dang-chon::after {
    content: '';
    position: absolute;
    inset: -6px;
    border: 2px solid #ff1744;
    border-radius: 50%;
    animation: chon-nhay 1.2s ease-out infinite;
    pointer-events: none;
}

@keyframes chon-nhay {
    0%   { transform: scale(.85); opacity: 1; }
    100% { transform: scale(1.35); opacity: 0; }
}


/* ==========================================================================
   BẢN ĐỒ: TRẠM BIẾN ÁP
   Trạm là NGUỒN CẤP cho các tủ, nên vẽ khác hẳn tủ và đèn: biểu tượng tia sét
   trong khung vuông vàng — nhìn phát biết ngay đâu là điểm cấp nguồn.
   ========================================================================== */
.marker-tram {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    background: #ffc107;
    color: #1a1a1a;
    border: 2px solid #fff;
    border-radius: .35rem;
    box-shadow: 0 2px 6px rgba(0,0,0,.35);
    font-size: 15px;
}

/* Popup thông tin trạm */
.md-pop { min-width: 210px; }
.md-pop-head {
    border-bottom: 1px solid #dee2e6;
    padding-bottom: .3rem;
    margin-bottom: .35rem;
}
.md-pop-row {
    display: flex;
    justify-content: space-between;
    gap: .75rem;
    font-size: .82rem;
    padding: .1rem 0;
}
.md-pop-row span { color: #6c757d; }


/* ==========================================================================
   POPUP THIẾT BỊ TRÊN BẢN ĐỒ

   LỖI ĐÃ SỬA: trước đây để "width: auto" cho popup, Leaflet co nó lại theo nội
   dung hẹp nhất -> popup teo còn hơn trăm pixel, chữ vỡ từng từ ("Trạm / biến /
   áp 01"), các ô số liệu tụt xuống hai dòng. Nay ẤN ĐỊNH chiều rộng cố định.
   ========================================================================== */
.mp-popup .leaflet-popup-content-wrapper {
    border-radius: .5rem;
    padding: 0;
    overflow: hidden;
    box-shadow: 0 4px 16px rgba(0,0,0,.16);
}
/* Chiều rộng CỐ ĐỊNH — đây là mấu chốt, thiếu nó là popup tự bóp lại. */
.mp-popup .leaflet-popup-content {
    margin: 0;
    width: 268px !important;
}

.mp {
    font-size: .78rem;
    /* Không bao giờ cắt chữ giữa từ. */
    word-break: normal;
    overflow-wrap: break-word;
}

/* ----- Đầu ----- */
.mp-dau {
    border-left: 3px solid #6c757d;
    background: #f8f9fa;
    padding: .4rem .55rem .35rem;
}
.mp-ten { font-weight: 650; font-size: .86rem; line-height: 1.25; }
.mp-phu { color: #9aa0a6; font-size: .68rem; line-height: 1.3; margin-top: .05rem; }
.mp-tt {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    margin-top: .25rem;
    font-size: .7rem;
    font-weight: 600;
}
.mp-tt i { width: .42rem; height: .42rem; border-radius: 50%; flex: 0 0 auto; }

.mp-than { padding: .45rem .55rem .55rem; }

/* ----- Ô số liệu ----- */
.mp-o { display: grid; gap: .28rem; margin-bottom: .35rem; }
.mp-o-item {
    background: #f8f9fa;
    border: 1px solid #eceef1;
    border-radius: .3rem;
    padding: .2rem .1rem;
    text-align: center;
    min-width: 0;                /* cho phép ô co, nhưng nội dung một dòng */
}
.mp-o-nhan { font-size: .62rem; color: #9aa0a6; line-height: 1.1; }
.mp-o-so {
    font-size: .8rem;
    font-weight: 650;
    line-height: 1.3;
    white-space: nowrap;         /* "0 V" KHÔNG được tách hai dòng */
}
.mp-o-so span { font-size: .6rem; font-weight: 500; color: #9aa0a6; margin-left: .1rem; }

.mp-tong { font-size: .74rem; color: #6c757d; text-align: center; padding: .1rem 0 .2rem; }

/* ----- Cáp nối tới ----- */
.mp-cap { display: grid; gap: .3rem; margin-top: .2rem; }
.mp-cap-dong {
    border-left: 2px solid #e9ecef;
    padding-left: .4rem;
}
.mp-cap-dau {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: .4rem;
}
.mp-cap-ten {
    font-size: .76rem;
    font-weight: 600;
    line-height: 1.3;
    min-width: 0;                /* tên dài thì xuống dòng, KHÔNG đẩy vỡ số mét */
}
.mp-cap-m {
    color: #9aa0a6;
    font-size: .68rem;
    white-space: nowrap;         /* "183 m" luôn nằm một dòng */
    flex: 0 0 auto;
}
.mp-cap-nhan { font-size: .66rem; color: #868e96; line-height: 1.35; margin-top: .05rem; }

/* ----- Nút ----- */
.mp-nut {
    display: block;
    margin-top: .5rem;
    text-align: center;
    background: #0d6efd;
    color: #fff !important;
    border-radius: .3rem;
    padding: .28rem .4rem;
    font-size: .74rem;
    font-weight: 600;
    white-space: nowrap;
    text-decoration: none !important;
}
.mp-nut:hover { background: #0b5ed7; }
.mp-mo { color: #adb5bd; font-size: .72rem; }


/* ==========================================================================
   THANH ĐIỀU HƯỚNG — CHỐNG TRÀN, MẤT CHỮ

   Thanh có 12 mục. Cộng cả thương hiệu và khối tài khoản thì cần ~1540px, trong khi
   Windows hầu như luôn đặt tỉ lệ hiển thị 125% — màn 1920 thật ra chỉ còn ~1536px.
   Vừa đủ hụt: mục cuối ("Đăng xuất") bị cắt cụt.

   Hai bậc thu gọn, cắt cái ÍT THÔNG TIN NHẤT trước:
   ========================================================================== */

/* Bậc 1 — mọi cỡ màn rộng: siết khoảng đệm hai bên mỗi mục.
   Khoảng trắng không mang thông tin gì, cắt trước tiên. */
@media (min-width: 1200px) {
    .navbar-nav .nav-link {
        padding-left: .35rem;
        padding-right: .35rem;
    }
}

/* Bậc 2 — màn hẹp (1200-1400px): bỏ biểu tượng, GIỮ CHỮ.
   Chữ mới là thứ người dùng đọc; biểu tượng chỉ trang trí. Thà mất biểu tượng còn hơn
   mất chữ, hoặc dồn hết vào nút ba gạch khiến mọi thao tác đều tốn thêm một cú bấm. */
@media (min-width: 1200px) and (max-width: 1399.98px) {
    #mainNav > .navbar-nav > .nav-item > .nav-link > i {
        display: none;
    }
    /* Tên tài khoản cũng bỏ được — đăng nhập rồi thì ai cũng biết mình là ai. */
    .navbar-account {
        display: none;
    }
}


/* ==========================================================================
   Ô CHỌN GỌN (tab Tuyến cáp)

   Mặc định Bootstrap cho mọi ô chọn rộng 100% ô chứa nó, nên một ô chỉ đựng chữ
   "Cáp Treo" cũng bị kéo dài bằng cả cột — nhìn thùng thình, mắt phải chạy rất xa
   từ nhãn tới giá trị.

   width: auto -> trình duyệt tự đo ô chọn theo LỰA CHỌN DÀI NHẤT trong nó. Tên tủ
   hay tên điểm sáng nào dài thì ô đó tự giãn vừa đủ; ngắn thì co lại.
   Chặn trên 340px để một cái tên lỡ tay đặt quá dài không đẩy vỡ cả hàng.
   ========================================================================== */
.o-gon {
    width: auto !important;
    min-width: 130px;

    /* Trần 460px: đủ cho một tên điểm sáng dài kiểu "CS05-14 ngã tư Hùng Vương kéo dài"
       hiện TRỌN VẸN. Để 340px thì tên dài bị cắt cụt — vẫn phải mở ra mới đọc được, mất
       đúng cái lợi của việc cho ô tự giãn. */
    max-width: 460px;
}


/* ==========================================================================
   CHÚ GIẢI BẢN ĐỒ — càng thấp càng tốt.

   Trang bản đồ cao đúng MỘT màn hình: mỗi pixel chú giải chiếm là một pixel bản
   đồ mất đi. Chú giải chỉ để tra màu, không phải thứ phải đọc kỹ, nên cho chữ
   nhỏ và các chấm màu nhỏ lại.
   ========================================================================== */
.chu-giai {
    font-size: .7rem;
    line-height: 1.25;
    row-gap: .15rem !important;
}

.chu-giai .legend-dot {
    width: 8px;
    height: 8px;
}

.chu-giai .vr {
    min-height: 14px;
    opacity: .25;
}


/* Hộp thoại xác nhận gửi lệnh: giữ nguyên các dấu xuống dòng trong nội dung.
   Mặc định HTML gộp mọi khoảng trắng thành một dấu cách, nên câu thứ hai bị dính
   đuôi câu thứ nhất thành một khối chữ dài, đọc lướt không ra ý. */
#confirmSendMessage {
    white-space: pre-line;
}


/* ==========================================================================
   THANH MENU — MÀU XANH CỔ VỊT + DẤU "ĐANG Ở TRANG NÀY"
   ========================================================================== */

/* Bootstrap gán bg-primary = xanh dương. Ghi đè ngay tại thanh menu, KHÔNG đổi biến
   --bs-primary toàn cục: biến đó còn dùng cho nút bấm, huy hiệu, viền ô nhập... đổi hết
   thì cả phần mềm biến màu, kể cả những chỗ không hề muốn đổi. */
.navbar.bg-primary {
    background-color: #0f6b6b !important;   /* xanh cổ vịt */
}

/* Mục ĐANG MỞ: nền sáng hơn + chữ trắng hẳn + gạch chân dưới đáy thanh.
   Chỉ đổi màu chữ thì trên nền xanh đậm gần như không nhận ra. */
.navbar-dark .navbar-nav .nav-link.active {
    color: #fff !important;
    font-weight: 600;
    background-color: rgba(255, 255, 255, .16);
    border-radius: .35rem;
    box-shadow: inset 0 -3px 0 #ffffff;
}

/* Rê chuột qua mục khác: sáng nhẹ, đủ biết bấm được nhưng không nhầm với mục đang mở. */
.navbar-dark .navbar-nav .nav-link:hover {
    background-color: rgba(255, 255, 255, .08);
    border-radius: .35rem;
}


/* ==========================================================================
   MÀU CHỦ ĐẠO: XANH CỔ VỊT (thay xanh dương của Bootstrap)

   Ghi đè qua BIẾN của Bootstrap, không đi sửa từng lớp một: Bootstrap 5.3 dựng nút, huy hiệu,
   ô tích... từ các biến này, nên đổi ở đây là đổi được TẤT CẢ, kể cả những chỗ sau này mới thêm.
   Sửa tay từng lớp thì kiểu gì cũng sót, và mỗi lần thêm nút mới lại phải nhớ sửa.
   ========================================================================== */
:root {
    --scada-chinh: #0f6b6b;          /* xanh cổ vịt */
    --scada-chinh-dam: #0b5252;      /* khi rê chuột / đang bấm */
    --scada-chinh-nhat: #e6f2f2;     /* nền nhạt */

    --bs-primary: #0f6b6b;
    --bs-primary-rgb: 15, 107, 107;
    --bs-link-color: #0f6b6b;
    --bs-link-hover-color: #0b5252;
    --bs-link-color-rgb: 15, 107, 107;
    --bs-link-hover-color-rgb: 11, 82, 82;
}

/* Nút nền đặc */
.btn-primary {
    --bs-btn-bg: var(--scada-chinh);
    --bs-btn-border-color: var(--scada-chinh);
    --bs-btn-hover-bg: var(--scada-chinh-dam);
    --bs-btn-hover-border-color: var(--scada-chinh-dam);
    --bs-btn-active-bg: var(--scada-chinh-dam);
    --bs-btn-active-border-color: var(--scada-chinh-dam);
    --bs-btn-disabled-bg: var(--scada-chinh);
    --bs-btn-disabled-border-color: var(--scada-chinh);
}

/* Nút khung mờ */
.btn-outline-primary {
    --bs-btn-color: var(--scada-chinh);
    --bs-btn-border-color: var(--scada-chinh);
    --bs-btn-hover-bg: var(--scada-chinh);
    --bs-btn-hover-border-color: var(--scada-chinh);
    --bs-btn-active-bg: var(--scada-chinh);
    --bs-btn-active-border-color: var(--scada-chinh);
    --bs-btn-disabled-color: var(--scada-chinh);
    --bs-btn-disabled-border-color: var(--scada-chinh);
}

.text-primary { color: var(--scada-chinh) !important; }
.bg-primary   { background-color: var(--scada-chinh) !important; }
.border-primary { border-color: var(--scada-chinh) !important; }
.badge.bg-primary { background-color: var(--scada-chinh) !important; }
.progress-bar { background-color: var(--scada-chinh); }
.spinner-border.text-primary { color: var(--scada-chinh) !important; }

/* Ô tích / ô chọn tròn khi được tích */
.form-check-input:checked {
    background-color: var(--scada-chinh);
    border-color: var(--scada-chinh);
}

/* Viền sáng khi đang gõ vào ô nhập */
.form-control:focus,
.form-select:focus,
.form-check-input:focus {
    border-color: var(--scada-chinh);
    box-shadow: 0 0 0 .2rem rgba(15, 107, 107, .2);
}

/* Thẻ tab đang mở (trang Khu vực, Quản lý vật tư) */
.nav-tabs .nav-link.active { color: var(--scada-chinh); }
.nav-pills .nav-link.active { background-color: var(--scada-chinh); }

/* Dòng bảng đang được chọn */
.table-primary { --bs-table-bg: var(--scada-chinh-nhat); }


/* ==========================================================================
   TIÊU ĐỀ TRANG — vừa tầm với thanh công cụ

   Bootstrap để h3 = 1.75rem. Cạnh ô tìm kiếm và các nút cỡ nhỏ (btn-sm), chữ đó to lồ lộ,
   hàng trên cùng nhìn mất cân: một bên chữ đại tự, một bên nút bé xíu.
   ========================================================================== */
main h3 {
    font-size: 1.35rem;
    font-weight: 600;
}

/* Biểu tượng đứng cạnh tiêu đề cũng phải nhỏ theo, không thì nó to hơn cả chữ. */
main h3 > i {
    font-size: 1.15rem;
}


/* ==========================================================================
   NHỮNG CHỖ BOOTSTRAP CÒN SÓT MÀU XANH DƯƠNG

   Đổi --bs-primary chưa đủ: Bootstrap 5.3 dựng menu thả xuống, phân trang, danh sách...
   từ BỘ BIẾN RIÊNG của từng thành phần, mà mấy biến đó gán CỨNG mã màu xanh dương.
   ========================================================================== */
.dropdown-menu {
    --bs-dropdown-link-active-bg: var(--scada-chinh);
    --bs-dropdown-link-hover-bg: var(--scada-chinh-nhat);
    --bs-dropdown-link-hover-color: var(--scada-chinh);
}

.pagination { --bs-pagination-active-bg: var(--scada-chinh); --bs-pagination-active-border-color: var(--scada-chinh); }
.page-link { color: var(--scada-chinh); }

.list-group { --bs-list-group-active-bg: var(--scada-chinh); --bs-list-group-active-border-color: var(--scada-chinh); }
.accordion { --bs-accordion-active-color: var(--scada-chinh); --bs-accordion-btn-focus-border-color: var(--scada-chinh); }
.nav-tabs { --bs-nav-tabs-link-active-color: var(--scada-chinh); }

.form-check-input:checked { background-color: var(--scada-chinh); border-color: var(--scada-chinh); }
.form-range::-webkit-slider-thumb { background-color: var(--scada-chinh); }
.link-primary { color: var(--scada-chinh) !important; }
.btn-link { --bs-btn-color: var(--scada-chinh); --bs-btn-hover-color: var(--scada-chinh-dam); }

/* ==========================================================================
   CỘT SỐ THỨ TỰ "#" TRONG BẢNG — ĐẾM BẰNG CSS
   Trước đây JS chèn thêm một ô vào TỪNG DÒNG sau khi trang đã hiện: bảng 5000
   dòng mất ~470 ms và người dùng thấy cả bảng bị đẩy thêm một cột.
   Nay máy chủ render sẵn ô rỗng <td class="o-stt">, số do CSS tự đếm — không
   tốn gì, không xê dịch. Lọc/sắp xếp cũng tự đánh số lại: dòng bị ẩn
   (display:none) thì CSS không đếm, nên số luôn liền mạch theo dòng đang thấy.
   ========================================================================== */
table.js-sort tbody { counter-reset: stt; }
table.js-sort tbody > tr { counter-increment: stt; }
td.o-stt::before { content: counter(stt); }

/* ==========================================================================
   BẢNG DANH SÁCH DÀI: BỀ RỘNG CỘT CỐ ĐỊNH
   Mặc định trình duyệt tự đo bề rộng cột theo TOÀN BỘ số dòng. Bảng 5000 dòng
   thì trong lúc tải nó phải đo đi đo lại, các cột cứ dồn qua dồn lại — đúng
   cảm giác "trang tự sắp xếp căn chỉnh lại" mà người dùng phản ánh.
   Đặt bề rộng cột sẵn (theo TỈ LỆ % nên màn hình nào cũng vừa) thì trình duyệt
   khỏi phải đo: cột đứng yên ngay từ dòng đầu tiên.
   Vẫn cho chữ xuống dòng như cũ, KHÔNG cắt bớt chữ.
   ========================================================================== */
table.bang-cot-co-dinh { table-layout: fixed; width: 100%; }

/* ==========================================================================
   HỘP THOẠI (MODAL): GỌN LẠI CHO VỪA MÀN HÌNH
   Hộp thoại "Sửa tủ" cao tới 820px — màn hình laptop mở lên là tràn xuống dưới,
   phải cuộn mới thấy nút Lưu. Các hộp thoại khác cũng chung một kiểu nên gom
   vào đây sửa MỘT LẦN cho tất cả (41 hộp thoại), khỏi sửa tay từng cái.
   Chỉ áp TRONG hộp thoại — biểu mẫu và thanh lọc ngoài trang giữ nguyên cỡ cũ.
   ========================================================================== */
.modal .form-label            { font-size: .8rem; margin-bottom: .12rem; }
/* :not(.ts-wrapper) — ô chọn có tìm kiếm giữ nguyên class form-select trên KHUNG BỌC,
   không loại trừ thì phần đệm cộng dồn hai lần, ô cao vống lên lệch hẳn ô bên cạnh. */
.modal .form-control:not(.ts-wrapper),
.modal .form-select:not(.ts-wrapper)  { padding: .28rem .6rem; font-size: .9rem; min-height: 34px; }

/* Ô CHỌN phải chừa chỗ bên phải cho MŨI TÊN — Bootstrap để 2.25rem, dòng trên rút xuống .6rem
   nên mũi tên đè lên chữ. Ô rộng thì không thấy (chữ ngắn hơn ô), nhưng ô co theo nội dung
   (vd ô "Cắt" trong bảng điểm sáng) thì đè hẳn lên chữ. */
.modal .form-select:not(.ts-wrapper)  { padding-right: 2rem; }
.modal .input-group .btn      { padding: .28rem .55rem; }
.modal .row.g-3               { --bs-gutter-y: .55rem; }
.modal .modal-body            { padding: .75rem 1rem; }
.modal textarea.form-control  { min-height: 48px; }
.modal .form-check-label      { font-size: .9rem; }
.modal .form-text             { font-size: .75rem; margin-top: .1rem; }

/* Ô chọn có tìm kiếm (Tom Select) phải gọn THEO cho khớp với ô thường,
   nếu không hai ô cạnh nhau sẽ so le nhau. */
/* Ô chọn có tìm kiếm dựng bằng nhiều lớp thẻ nên chiều cao KHÔNG tính ra được như ô thường
   (đo thực tế: cùng đệm mà vẫn cao hơn 3,5px). Ép thẳng về đúng một chiều cao và căn giữa
   theo chiều dọc — cách duy nhất bảo đảm hai ô đứng cạnh nhau không so le. */
.modal .ts-wrapper.single .ts-control {
    height: 34px !important;
    min-height: 34px !important;
    padding-top: 0 !important;
    padding-bottom: 0 !important;
    padding-left: .6rem !important;
    align-items: center;
    font-size: .9rem;
}
.modal .ts-wrapper.single .ts-control { padding-right: 2.1rem !important; }
.modal .modal-header          { padding: .6rem 1rem; }
.modal .modal-footer          { padding: .5rem 1rem; }
.modal .modal-title           { font-size: 1.05rem; }

/* ==========================================================================
   HÀNG BẢNG GỌN LẠI
   Đệm dọc mặc định của Bootstrap là .5rem trên/dưới, cộng thêm chữ xuống dòng
   ở cột hẹp là hàng cao vống lên, nhìn thưa thớt và phải cuộn nhiều.
   Rút còn .32rem — vừa đủ ôm chữ, đọc vẫn thoáng mà mỗi hàng bớt được ~6px;
   danh sách 30 dòng là bớt gần 200px phải cuộn.
   ========================================================================== */
.table > :not(caption) > * > * { padding-top: .32rem; padding-bottom: .32rem; }

/* Nút thao tác trong bảng: nhỏ gọn lại cho vừa ô, ba nút vẫn đủ chỗ. */
.table td .btn-sm { --bs-btn-padding-y: .12rem; --bs-btn-padding-x: .4rem; }

/* ==========================================================================
   CỠ CHỮ TRONG BẢNG
   Trước đây bảng dùng cỡ chữ nền 16px — TO NHẤT trong các thành phần, trong khi
   nút trong bảng 14px, ô trong hộp thoại 14,4px. Bảng vì thế lệch tông, hàng cao
   và tên dài hay bị xuống dòng.
   Hạ về 14px (.875rem) cho bằng nút trong bảng: hàng thấp thêm vài pixel, chữ
   ngắn lại ~12% nên tên tủ dài đỡ phải xuống dòng.
   ========================================================================== */
.table { font-size: .875rem; }

/* Hộp thoại "Danh sách điểm sáng" của TỦ NĂNG LƯỢNG MẶT TRỜI: có thêm 4 cột đo
   (U, I, P, cos φ) nên modal-xl chật — nới rộng gần hết bề ngang màn hình.
   Tủ điện lưới vẫn dùng modal-xl như cũ. */
.modal-dialog.hop-thoai-rong { max-width: 96vw; }

/* Bảng "Danh sách điểm sáng" trong hộp thoại điều khiển: TIÊU ĐỀ KHÔNG XUỐNG DÒNG.
   Tiêu đề dài như "Giá trị tiết giảm (%)" bị bẻ hai dòng làm hàng tiêu đề cao gấp đôi.
   Cột nào hẹp hơn tiêu đề thì trình duyệt tự nới ra cho vừa. */
#nodeListModal thead th { white-space: nowrap; }

/* ===== Màn GIÁM SÁT trạng thái hiện tại ===== */
/* Dải tổng quan: mỗi ô là một nút lọc nhanh. Ô đang chọn viền xanh nổi bật. */
.tk-chip { transition: box-shadow .15s, transform .15s; cursor: pointer; }
.tk-chip:hover { transform: translateY(-2px); box-shadow: 0 .4rem 1rem rgba(0,0,0,.12) !important; }
.tk-chip.active { outline: 2px solid var(--bs-primary); outline-offset: -2px; }
/* Ô "Mất kết nối" khi có lỗi: viền đỏ nhắc mắt. */
.tk-chip.co-loi { outline: 2px solid var(--bs-danger); outline-offset: -2px; }
/* Hàng thiết bị đang mất kết nối: nền đỏ nhạt cho dễ nhận. */
tr.hang-mat-kn > td { background-color: rgba(220, 53, 69, .06); }

/* ==========================================================================
   DẢI TỔNG QUAN GIÁM SÁT — gọn, thấp, XẾP MỘT HÀNG.

   Vì sao KHÔNG dùng lớp lưới row-cols-* của Bootstrap: nó chỉ có tới 6 cột, mà
   trang Giám sát tủ có 8 ô -> luôn bị bẻ xuống hai hàng, chiếm chỗ và rối mắt.
   Lưới CSS với grid-auto-flow:column tự xếp HẾT các ô vào MỘT hàng, bao nhiêu ô
   cũng được — nên trang tủ (8 ô) và trang điểm sáng (5 ô) dùng chung một luật,
   sau này thêm bớt ô cũng không phải sửa CSS.
   ========================================================================== */
.dai-tong-quan {
    display: grid;
    grid-auto-flow: column;                  /* mọi ô nằm trên MỘT hàng */
    grid-auto-columns: minmax(0, 1fr);       /* chia đều; minmax(0,…) cho ô co được */
    gap: .3rem;
    max-width: 900px;
}
.dai-tong-quan .tk-chip { padding: .2rem .15rem !important; }
.dai-tong-quan .tk-chip > div:first-child { font-size: .95rem !important; line-height: 1.1; }   /* con số */
.dai-tong-quan .tk-chip > div:last-child  { font-size: .62rem !important; line-height: 1.15; }  /* nhãn */

/* Màn hẹp: một hàng 8 ô thì chữ bé không đọc nổi -> cho xuống dòng, 4 ô rồi 2 ô. */
@media (max-width: 991.98px) {
    .dai-tong-quan { grid-auto-flow: row; grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (max-width: 575.98px) {
    .dai-tong-quan { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Ô đo U/I của tủ: đường kẻ dọc phân chia Điện áp | Dòng điện, chạy HẾT chiều cao ô. */
td.o-do { padding: 0 !important; height: 1px; }          /* height:1px là "mồi" để con cao 100% ô */
td.o-do > .do-vi { height: 100%; display: flex; align-items: stretch; }
td.o-do .do-vi > span {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: .25rem .3rem;
    white-space: nowrap;
}
td.o-do .do-vi > span:first-child { border-right: 1px solid var(--bs-border-color); }  /* kẻ mờ như viền ô khác */

/* ==========================================================================
   MÀN HÌNH HẸP — bảng nhiều cột KHÔNG bị đè chữ.

   Bề rộng cột khai bằng PHẦN TRĂM (width:19%, 12%...) cộng với table-layout:fixed
   chỉ hợp lý khi màn hình đủ rộng. Màn hẹp thì 12% của 800px chỉ còn ~96px, chữ
   dài hơn ô mà table-layout:fixed KHÔNG cho ô nở ra -> chữ tràn đè lên cột bên
   cạnh (badge "Đóng cả 2 khởi" đè lên số điện áp).

   NGƯỠNG: trước đây để 576px nên CHỈ điện thoại dựng đứng mới được sửa. Điện thoại
   QUAY NGANG rộng ~800-950px và MÁY TÍNH BẢNG ~768-1024px đều lọt lưới -> vẫn đè
   chữ. Nay nâng lên 1199.98px: mọi thứ hẹp hơn màn hình máy tính đều dùng bố cục
   tự co + cuộn ngang.

   Đặt Ở CUỐI FILE và dùng !important vì rule gốc "table.bang-cot-co-dinh {
   table-layout: fixed }" nằm phía trên; nếu để media query ở trên nó thì bị
   ghi đè ngược -> cột vẫn fixed, chữ tràn chồng nhau (đúng lỗi đã gặp).
   Giữ đủ mọi cột, không giấu dữ liệu — chỉ CUỘN NGANG trong .table-responsive.
   ========================================================================== */
@media (max-width: 1199.98px) {
    table.bang-cot-co-dinh {
        table-layout: auto !important;
        width: auto !important;
        min-width: 100% !important;
    }
    table.bang-cot-co-dinh th,
    table.bang-cot-co-dinh td {
        white-space: nowrap !important;
        overflow: visible !important;
    }

    /* CỘT TÊN (tủ / điểm sáng) ĐƯỢC XUỐNG DÒNG.
       Tên tủ là thứ dài nhất bảng ("Tủ Quốc Lộ 2 (Đối diện Ủy Ban)"); ép một dòng
       thì phải kéo ngang rất xa mới thấy hết các cột số. Cho nó gói 2-3 dòng thì
       bảng hẹp lại hẳn, đọc trên điện thoại/máy tính bảng dễ hơn nhiều. Các cột SỐ
       vẫn giữ một dòng vì "236.3 V" mà tách đôi thì đọc rất khó. */
    table.bang-cot-co-dinh th.td-trai,
    table.bang-cot-co-dinh td.td-trai {
        white-space: normal !important;
        min-width: 8rem;
        max-width: 14rem;
    }

    /* Cho các ô có khoảng thở, tránh số dính sát nhau khi cuộn. */
    table.bang-cot-co-dinh th,
    table.bang-cot-co-dinh td:not(.o-do) {
        padding-left: .5rem !important;
        padding-right: .5rem !important;
    }
    /* Ô đo U/I của tủ: bỏ mẹo height:1px để không méo khi table auto. */
    table.bang-cot-co-dinh td.o-do { height: auto !important; }
}

/* ===== TRỢ LÝ AI — hộp chat nổi góc phải dưới ===== */
.tro-ly-nut {
    /* Đặt CAO HƠN badge cảnh báo sự cố (#thanhCanhBao ở bottom:18px) để không che nó. */
    position: fixed; right: 18px; bottom: 74px; z-index: 1080;
    width: 40px; height: 40px; border-radius: 50%;
    background: var(--bs-primary); color: #fff;
    display: flex; align-items: center; justify-content: center;
    font-size: 1.05rem; cursor: grab;
    box-shadow: 0 .3rem .7rem rgba(0,0,0,.25);
    transition: transform .15s;
    touch-action: none;   /* để kéo được trên cảm ứng (không cuộn trang khi kéo nút) */
}
.tro-ly-nut:hover { transform: scale(1.1); }
.tro-ly-nut:active { cursor: grabbing; }
/* Nút ẩn nhỏ ở góc nút nổi — hiện khi rê chuột (điện thoại thì luôn hiện). */
.tro-ly-an-nut {
    position: absolute; top: -6px; right: -6px; width: 18px; height: 18px; padding: 0;
    border: none; border-radius: 50%; background: var(--bs-secondary); color: #fff;
    font-size: 13px; line-height: 1; cursor: pointer; display: none;
    align-items: center; justify-content: center; box-shadow: 0 1px 3px rgba(0,0,0,.3);
}
.tro-ly-nut:hover .tro-ly-an-nut { display: flex; }
@media (hover: none) { .tro-ly-nut .tro-ly-an-nut { display: flex; } }
/* Nút ẩn trên tiêu đề hộp chat. */
.tro-ly-dau-nut {
    background: transparent; border: none; color: #fff; opacity: .85;
    cursor: pointer; padding: 0 2px; font-size: .95rem; line-height: 1;
}
.tro-ly-dau-nut:hover { opacity: 1; }
.tro-ly-khung {
    position: fixed; right: 18px; bottom: 18px; z-index: 1081;
    width: 360px; max-width: calc(100vw - 24px);
    height: 500px; max-height: calc(100vh - 90px);
    display: flex; flex-direction: column;
    background: var(--bs-body-bg); border: 1px solid var(--bs-border-color);
    border-radius: 12px; overflow: hidden;
    box-shadow: 0 .6rem 1.6rem rgba(0,0,0,.3);
}
.tro-ly-dau {
    background: var(--bs-primary); color: #fff;
    padding: .6rem .8rem; font-weight: 600;
    display: flex; align-items: center; justify-content: space-between;
}
/* min-height:0 BẮT BUỘC: ô flex mặc định không co nhỏ hơn nội dung -> thiếu nó thì câu trả lời dài
   làm vùng tin nở ra, overflow-y không có gì để cuộn (vuốt không được). Thêm cuộn mượt + không kéo lây trang. */
.tro-ly-tin { flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; padding: .7rem; background: var(--bs-tertiary-bg); }
.tl-dong { max-width: 85%; padding: .45rem .7rem; border-radius: 12px; margin-bottom: .5rem; font-size: .9rem; line-height: 1.4; word-wrap: break-word; }
.tl-ai  { background: var(--bs-body-bg); border: 1px solid var(--bs-border-color); margin-right: auto; border-bottom-left-radius: 3px; }
.tl-toi { background: var(--bs-primary); color: #fff; margin-left: auto; border-bottom-right-radius: 3px; }
.tro-ly-nhap { display: flex; gap: .4rem; padding: .55rem; border-top: 1px solid var(--bs-border-color); background: var(--bs-body-bg); }
/* Ô nhập lấy phần còn lại bằng flex-basis 0 (KHÔNG dùng width:100% -> không đẩy nút ra ngoài);
   nút gửi giữ nguyên kích thước. Nhờ vậy nút gửi LUÔN hiện, không bị cắt kể cả trên điện thoại. */
.tro-ly-nhap .form-control { flex: 1 1 0; width: auto; min-width: 0; }
.tro-ly-nhap .btn { flex: 0 0 auto; }
@media (max-width: 576px) {
    /* Điện thoại: gọn lại (không chiếm cả màn), neo đáy. dvh co theo thanh trình duyệt;
       khi bàn phím bật thì JS (VisualViewport) chỉnh lại để ô nhập + nút gửi luôn hiện. */
    .tro-ly-khung {
        left: 8px; right: 8px; width: auto;
        top: auto; bottom: 8px;
        height: 60dvh; max-height: 60dvh;
    }
    .tro-ly-dau { padding: .5rem .7rem; }
    .tl-dong { font-size: .88rem; }
    /* Chừa mép dưới máy có "tai thỏ"/thanh cử chỉ để không che nút gửi. */
    .tro-ly-nhap { padding: .5rem; padding-bottom: calc(.5rem + env(safe-area-inset-bottom, 0px)); }
    /* QUAN TRỌNG: cỡ chữ ô nhập >= 16px để iOS KHÔNG tự phóng to cả trang khi chạm vào gõ. */
    .tro-ly-nhap .form-control { font-size: 16px; }
}

/* Nút câu hỏi nhanh trong trợ lý */
.tl-chips { display: flex; flex-wrap: wrap; gap: .35rem; margin-bottom: .5rem; }
.tl-chip {
    border: 1px solid var(--bs-primary); color: var(--bs-primary); background: var(--bs-body-bg);
    border-radius: 14px; padding: .25rem .6rem; font-size: .82rem; cursor: pointer; line-height: 1.2;
}
.tl-chip:hover { background: var(--bs-primary); color: #fff; }

/* ===== PHIẾU BẢO TRÌ IN RA GIẤY (giao nhân viên cầm đi sửa) ===== */
.phieu-in { max-width: 900px; margin: 0 auto; color: #000; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.phieu-in .pi-donvi { font-weight: 600; text-transform: uppercase; font-size: .9rem; }
.phieu-in .pi-tieude { font-size: 1.6rem; font-weight: 700; letter-spacing: .4px; margin-top: .15rem; }
.phieu-in .pi-so { margin-top: .3rem; font-size: .95rem; }
.phieu-in .pi-thongtin { width: 100%; border-collapse: collapse; }
.phieu-in .pi-thongtin td { border: 1px solid #666; padding: .35rem .55rem; font-size: .93rem; vertical-align: top; }
.phieu-in .pi-thongtin td:nth-child(odd) { background: #f3f3f3; font-weight: 600; white-space: nowrap; }
.phieu-in .pi-nhan { font-weight: 600; }
/* KHÔNG dùng !important cho ô bảng: dòng-trống-tạo-lề khi in (border-style:hidden inline) phải
   thắng được, nếu không sẽ có kẻ ngang trong vùng lề lúc in nhiều trang. */
/* table-layout:fixed + tự xuống dòng: bảng KHÔNG bao giờ rộng quá khổ giấy nên viền phải không bị cắt khi in. */
.phieu-in .pi-bang { table-layout: fixed; width: 100%; }
.phieu-in .pi-bang th, .phieu-in .pi-bang td { border: 1px solid #666; vertical-align: top; font-size: .93rem; word-break: break-word; overflow-wrap: anywhere; }
.phieu-in .pi-bang thead th { background: #e9ecef; text-align: center; }
.phieu-in .pi-viet { height: 44px; }
.phieu-in .pi-kyten { display: flex; justify-content: space-around; margin-top: 1rem; text-align: center; }
.phieu-in .pi-ky { width: 30%; }
.phieu-in .pi-ky > div:first-child { font-weight: 600; }
.phieu-in .pi-ky-ghichu { font-style: italic; font-size: .85rem; }
.phieu-in .pi-ky::after { content: ""; display: block; height: 66px; }   /* chừa chỗ ký tên */

/* ===== BẢNG LỊCH SỬ (giám sát) — canh đẹp: tiêu đề gọn 1 dòng, số liệu canh giữa ===== */
.bang-lich-su thead th { vertical-align: middle; text-align: center; font-size: .85rem; line-height: 1.15; white-space: nowrap; }
.bang-lich-su thead th.text-start { text-align: left; }
.bang-lich-su tbody td { text-align: center; font-variant-numeric: tabular-nums; }
.bang-lich-su tbody td.td-trai { text-align: left; }
