/* /Components/Layout/NavMenu.razor.rz.scp.css */
/* NavMenu scoped styles — MudBlazor handles all nav styling */
/* File giữ trống — tránh conflict với MudNavMenu */
/* /Components/Layout/ReconnectModal.razor.rz.scp.css */
.components-reconnect-first-attempt-visible[b-cikjptsonh],
.components-reconnect-repeated-attempt-visible[b-cikjptsonh],
.components-reconnect-failed-visible[b-cikjptsonh],
.components-pause-visible[b-cikjptsonh],
.components-resume-failed-visible[b-cikjptsonh],
.components-rejoining-animation[b-cikjptsonh] {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible[b-cikjptsonh],
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation[b-cikjptsonh],
#components-reconnect-modal.components-reconnect-paused .components-pause-visible[b-cikjptsonh],
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible[b-cikjptsonh],
#components-reconnect-modal.components-reconnect-retrying[b-cikjptsonh],
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible[b-cikjptsonh],
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation[b-cikjptsonh],
#components-reconnect-modal.components-reconnect-failed[b-cikjptsonh],
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible[b-cikjptsonh] {
    display: block;
}


#components-reconnect-modal[b-cikjptsonh] {
    background-color: white;
    width: 20rem;
    margin: 20vh auto;
    padding: 2rem;
    border: 0;
    border-radius: 0.5rem;
    box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
    animation: components-reconnect-modal-fadeOutOpacity-b-cikjptsonh 0.5s both;
    &[open]

{
    animation: components-reconnect-modal-slideUp-b-cikjptsonh 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity-b-cikjptsonh 0.5s ease-in-out 0.3s;
    animation-fill-mode: both;
}

}

#components-reconnect-modal[b-cikjptsonh]::backdrop {
    background-color: rgba(0, 0, 0, 0.4);
    animation: components-reconnect-modal-fadeInOpacity-b-cikjptsonh 0.5s ease-in-out;
    opacity: 1;
}

@keyframes components-reconnect-modal-slideUp-b-cikjptsonh {
    0% {
        transform: translateY(30px) scale(0.95);
    }

    100% {
        transform: translateY(0);
    }
}

@keyframes components-reconnect-modal-fadeInOpacity-b-cikjptsonh {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes components-reconnect-modal-fadeOutOpacity-b-cikjptsonh {
    0% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

.components-reconnect-container[b-cikjptsonh] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

#components-reconnect-modal p[b-cikjptsonh] {
    margin: 0;
    text-align: center;
}

#components-reconnect-modal button[b-cikjptsonh] {
    border: 0;
    background-color: #6b9ed2;
    color: white;
    padding: 4px 24px;
    border-radius: 4px;
}

    #components-reconnect-modal button:hover[b-cikjptsonh] {
        background-color: #3b6ea2;
    }

    #components-reconnect-modal button:active[b-cikjptsonh] {
        background-color: #6b9ed2;
    }

.components-rejoining-animation[b-cikjptsonh] {
    position: relative;
    width: 80px;
    height: 80px;
}

    .components-rejoining-animation div[b-cikjptsonh] {
        position: absolute;
        border: 3px solid #0087ff;
        opacity: 1;
        border-radius: 50%;
        animation: components-rejoining-animation-b-cikjptsonh 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
    }

        .components-rejoining-animation div:nth-child(2)[b-cikjptsonh] {
            animation-delay: -0.5s;
        }

@keyframes components-rejoining-animation-b-cikjptsonh {
    0% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    4.9% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    5% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 1;
    }

    100% {
        top: 0px;
        left: 0px;
        width: 80px;
        height: 80px;
        opacity: 0;
    }
}
/* /Components/Pages/Admin/ReportSettingsPage.razor.rz.scp.css */
/* Fix: BadgeData trên MudTabPanel bị cắt bởi overflow:hidden của MudTabs toolbar.
   Dùng ::deep để pierce vào MudBlazor internal markup từ scoped CSS.
   + thêm padding-right vào tab để badge có chỗ position absolute không tràn header. */

[b-zti1243kcs] .mud-tabs-toolbar {
    overflow: visible !important;
}

[b-zti1243kcs] .mud-tabs-tabbar-inner {
    overflow: visible !important;
}

[b-zti1243kcs] .mud-tab {
    overflow: visible !important;
    padding-right: 28px;
}

[b-zti1243kcs] .mud-tab .mud-badge-wrapper,
[b-zti1243kcs] .mud-tab .mud-badge {
    overflow: visible !important;
}
/* /Components/Pages/Energy/EnergyCostDashboardPage.razor.rz.scp.css */
/* ══════════════════════════════════════════════════════════════
   Energy Cost Dashboard — Premium Dark-Friendly Design
   All colors use MudBlazor CSS variables for dark mode compat
   ══════════════════════════════════════════════════════════════ */

/* ── Page Header ── */
.cost-dashboard-header[b-kakkyf2piv] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
    margin-bottom: 24px;
}
.cost-dashboard-title[b-kakkyf2piv] {
    display: flex;
    align-items: center;
    gap: 10px;
}
.cost-dashboard-title-text[b-kakkyf2piv] {
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--mud-palette-text-primary);
}
.cost-dashboard-subtitle[b-kakkyf2piv] {
    font-size: 0.85rem;
    color: var(--mud-palette-text-secondary);
}

/* ── KPI Cards Grid ── */
.kpi-grid[b-kakkyf2piv] {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 16px;
    margin-bottom: 24px;
}
@@media (max-width: 1200px) { .kpi-grid[b-kakkyf2piv] { grid-template-columns: repeat(3, 1fr); } }
@@media (max-width: 768px) { .kpi-grid[b-kakkyf2piv] { grid-template-columns: repeat(2, 1fr); } }

.kpi-card[b-kakkyf2piv] {
    position: relative;
    border-radius: 12px;
    padding: 20px;
    overflow: hidden;
    background: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-lines-default);
    transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.kpi-card:hover[b-kakkyf2piv] {
    transform: translateY(-3px);
    box-shadow: 0 8px 24px rgba(0,0,0,0.18);
}
.kpi-card[b-kakkyf2piv]::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
}
.kpi-card.kpi-today[b-kakkyf2piv]::before    { background: linear-gradient(90deg, #FF9800, #FFB74D); }
.kpi-card.kpi-mtd[b-kakkyf2piv]::before      { background: linear-gradient(90deg, #2196F3, #64B5F6); }
.kpi-card.kpi-kwh[b-kakkyf2piv]::before      { background: linear-gradient(90deg, #4CAF50, #81C784); }
.kpi-card.kpi-avg[b-kakkyf2piv]::before      { background: linear-gradient(90deg, #9C27B0, #CE93D8); }
.kpi-card.kpi-budget[b-kakkyf2piv]::before   { background: linear-gradient(90deg, #00BCD4, #4DD0E1); }

.kpi-icon-wrap[b-kakkyf2piv] {
    width: 44px;
    height: 44px;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 12px;
}
.kpi-today .kpi-icon-wrap[b-kakkyf2piv]    { background: rgba(255,152,0,0.12); }
.kpi-mtd .kpi-icon-wrap[b-kakkyf2piv]      { background: rgba(33,150,243,0.12); }
.kpi-kwh .kpi-icon-wrap[b-kakkyf2piv]      { background: rgba(76,175,80,0.12); }
.kpi-avg .kpi-icon-wrap[b-kakkyf2piv]      { background: rgba(156,39,176,0.12); }
.kpi-budget .kpi-icon-wrap[b-kakkyf2piv]   { background: rgba(0,188,212,0.12); }

.kpi-value[b-kakkyf2piv] {
    font-size: 1.75rem;
    font-weight: 800;
    font-family: 'Roboto Mono', 'Consolas', monospace;
    color: var(--mud-palette-text-primary);
    line-height: 1.2;
    margin-bottom: 4px;
}
.kpi-label[b-kakkyf2piv] {
    font-size: 0.78rem;
    font-weight: 500;
    color: var(--mud-palette-text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.kpi-sub[b-kakkyf2piv] {
    font-size: 0.72rem;
    color: var(--mud-palette-text-disabled);
    margin-top: 6px;
}

/* ── Chart Panels ── */
.charts-row[b-kakkyf2piv] {
    display: grid;
    grid-template-columns: 1fr 1.5fr;
    gap: 16px;
    margin-bottom: 24px;
}
@@media (max-width: 960px) { .charts-row[b-kakkyf2piv] { grid-template-columns: 1fr; } }

.chart-panel[b-kakkyf2piv] {
    border-radius: 12px;
    padding: 20px 24px;
    background: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-lines-default);
}
.chart-panel-title[b-kakkyf2piv] {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--mud-palette-text-primary);
    margin-bottom: 16px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

/* ── Budget Section ── */
.budget-panel[b-kakkyf2piv] {
    border-radius: 12px;
    padding: 20px 24px;
    background: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-lines-default);
}

.budget-summary-grid[b-kakkyf2piv] {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
    margin-top: 16px;
}
@@media (max-width: 768px) { .budget-summary-grid[b-kakkyf2piv] { grid-template-columns: repeat(2, 1fr); } }

.budget-summary-item[b-kakkyf2piv] {
    text-align: center;
    padding: 14px 8px;
    border-radius: 10px;
    background: var(--mud-palette-background);
    border: 1px solid var(--mud-palette-lines-default);
}
.budget-summary-value[b-kakkyf2piv] {
    font-size: 1.1rem;
    font-weight: 700;
    font-family: 'Roboto Mono', monospace;
    color: var(--mud-palette-text-primary);
}
.budget-summary-label[b-kakkyf2piv] {
    font-size: 0.72rem;
    color: var(--mud-palette-text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    margin-top: 4px;
}

/* ── Empty State ── */
.empty-state[b-kakkyf2piv] {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 48px 24px;
    gap: 8px;
}
/* /Components/Pages/Energy/EnergyDashboardConfigPanel.razor.rz.scp.css */
/* Bố cục 2 cột — mirror `.mdc-split` của MachineDashboardConfigPanel (cùng khuôn trang quản lý:
   trái danh sách, phải thuộc tính của mục đang chọn). Cột trái hẹp cố định vì nó chỉ chứa
   tên + mã điểm đo; cột phải nhận phần còn lại để bảng 20 ô + thẻ xem trước đủ chỗ. */
.edc-split[b-2jzbtz58h9] {
    display: grid;
    /* 364px — cùng số với bản Machine: cột trái cũng mang tay nắm kéo + ô tick "hiện trên
       dashboard" nên tên bị bóp nếu hẹp hơn. */
    grid-template-columns: minmax(0, 364px) minmax(0, 1fr);
    gap: 12px;
    align-items: start;
}

/* Panel dính theo màn khi danh sách điểm đo dài — 88px = chiều cao app bar + lề. */
.edc-props[b-2jzbtz58h9] {
    position: sticky;
    top: 88px;
}

/* Một mục trong danh sách chọn phạm vi. Dùng list dọc click-chọn thay radio: radio render inline
   nên danh sách nhảy chung một hàng khi hẹp (bài học HostNetworkConfigDialog). */
.edc-item[b-2jzbtz58h9] {
    display: flex;
    align-items: center;
    padding: 6px 8px;
    border-radius: 4px;
    cursor: pointer;
    border-left: 3px solid transparent;
}

.edc-item:hover[b-2jzbtz58h9] {
    background: var(--mud-palette-action-default-hover);
}

/* ĐANG CHỌN — viền trái đậm + nền. ⛔ Đây là affordance của "đang chọn", đừng mượn nó để phân
   tầng cha/con (bài học GenericDeviceManagerPage 2026-08-13). */
.edc-item-selected[b-2jzbtz58h9] {
    border-left-color: var(--mud-palette-primary);
    background: var(--mud-palette-action-default-hover);
}

@media (max-width: 1279.98px) {
    .edc-split[b-2jzbtz58h9] { grid-template-columns: minmax(0, 1fr); }
    .edc-props[b-2jzbtz58h9] { position: static; }
}
/* /Components/Pages/Energy/EnergyDashboardPage.razor.rz.scp.css */
/* ── Energy Dashboard — Fixed viewport + Fixed card size ──
   Same pattern as MachineDashboard: flex column fills main-content,
   fixed card 380×260, JS ResizeObserver → pageSize.
*/

.dashboard-root[b-kcqp9jqz42] {
    height: calc(100vh - 64px); /* AppBar: 64px */
    display: flex;
    flex-direction: column;
    padding: 8px 12px;
    overflow: hidden;
    gap: 8px;
}

.dashboard-summary[b-kcqp9jqz42] {
    flex: 0 0 auto;
    margin-bottom: 0 !important;
}

.dashboard-root[b-kcqp9jqz42]  .dashboard-toolbar,
.dashboard-root > .mud-alert[b-kcqp9jqz42],
.dashboard-root > .mud-progress-linear[b-kcqp9jqz42] {
    flex: 0 0 auto;
}

/* ── Device grid: fixed card size, center-aligned ── */
.energy-device-grid[b-kcqp9jqz42] {
    /* Chuẩn theo Machine: bề rộng card = --card-w (400px) — đồng bộ 3 dashboard (Đợt 2026-06-10). */
    --card-w: 400px;
    flex: 1 1 auto;
    display: grid;
    /* Responsive (mobile): màn ≥W giữ cột cố định W (desktop Y NGUYÊN),
       màn <W cột co về 100% (full-width, hết cắt cụt). KHÔNG cần @media. */
    grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--card-w)), var(--card-w)));
    grid-auto-rows: max-content;
    gap: 12px;
    justify-content: center;
    align-content: start;
    overflow: hidden;
    min-height: 0;
}

.energy-device-grid[b-kcqp9jqz42]  .device-card {
    height: 100%;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
/* /Components/Pages/Generic/DeviceProfileForm.razor.rz.scp.css */
/* Hai bảng của form (chỉ số 10 cột + điểm điều khiển 7 cột) nằm trong vùng thuộc tính hẹp.
   Lề ô mặc định của MudSimpleTable Dense là 6px 16px, tức 32px BỀ NGANG mỗi ô — 10 cột
   là ~320px chỉ để trống, đủ đẩy bảng sang cuộn ngang. Bóp còn 12px/ô.

   ⚠️ Bậc chọn lọc phải THẮNG rule gốc `.mud-simple-table.mud-table-dense * tr td{padding:6px 16px}`
   (2 class + 2 element). Ở đây 2 class + 2 element + thuộc tính scope Blazor tự thêm vào `td`
   → hơn đúng một bậc. Hạ xuống `td { }` trơn là "rule nạp mà không ăn".

   KHÔNG đụng chiều cao ô nhập (Margin.Dense = 40px): đó là chuẩn vùng chạm
   (Responsive-Layout-Standard §8.2, tối thiểu 36px trên màn HMI/tablet). */
.mud-simple-table.mud-table-dense tr td[b-i3x4v9wx9u],
.mud-simple-table.mud-table-dense tr th[b-i3x4v9wx9u] {
    padding: 3px 6px;
}

/* Khối danh tính đóng khung, tách hẳn khỏi vùng tab — trước đó hai phần trôi liền nhau nên
   nhìn không ra đâu là danh tính profile, đâu là nội dung của tab đang mở.
   Bo góc hợp lệ vì viền ĐỦ 4 CẠNH (luật repo: viền hở cạnh thì không bo góc). */
.prof-identity[b-i3x4v9wx9u] {
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
    padding: 8px 12px;
    margin-bottom: 12px;
}

/* Chống NHẢY chiều cao khi đổi tab. Ba tab cao khác nhau rất xa (profile 12 chỉ số: tab Chỉ số
   ~630px, tab Điểm điều khiển ~170px) nên `min-height` như TaskDetailDialog chỉ giảm chứ không
   hết — phải CỐ ĐỊNH chiều cao vùng panel rồi cho cuộn bên trong. Được thêm: tab Chỉ số không
   còn vươn dài vô tận theo số dòng.
   ::deep vì .mud-tabs-panels do MudTabs render, CSS scoped không chạm thẳng tới được. */
.prof-tabs[b-i3x4v9wx9u]  .mud-tabs-panels {
    height: 420px;
    overflow-y: auto;
}

/* Màn hẹp: trả về tự nhiên — hộp cuộn lồng trong trang đang cuộn là rất khó dùng trên điện thoại
   (mirror cách TaskDetailDialog bỏ height cứng ở mobile). */
@media (max-width: 600px) {
    .prof-tabs[b-i3x4v9wx9u]  .mud-tabs-panels {
        height: auto;
        overflow-y: visible;
    }
}

/* ── Ô "Màu" của bảng quy tắc (tab DASHBOARD) ──────────────────────────────────────────────
   Icon bảng màu ĐỒNG THỜI là ô xem trước: tô nó bằng đúng màu đang chọn thì không cần thêm
   chấm màu bên cạnh. Màu đi vào qua biến --rule-color đặt inline trên .rule-color-cell.
   Chọn .mud-icon-root chung (không neo vào .mud-input-adornment-start) vì trong ô này chỉ có
   MỘT icon — neo hẹp mà MudBlazor đổi tên class là rule im lặng không ăn. */
.rule-color-cell[b-i3x4v9wx9u]  .mud-icon-root {
    color: var(--rule-color, currentColor);
}

/* Bóp bề ngang ô nhập — "#d40808" + icon vừa trong 124px, để rộng hơn là chiếm chỗ vô ích.
   ⚠️ SIẾT Ở .mud-input-control, TUYỆT ĐỐI KHÔNG siết gốc .mud-picker (tức không đặt Style/width
   thẳng lên MudColorPicker): gốc chứa CẢ ô nhập LẪN thân bảng màu, siết ở đó là bảng chọn bị ép
   thành dải dọc vài chục pixel, không bấm được (đã dính 2026-08-13). .mud-input-control chỉ bọc
   ô nhập nên an toàn. */
.rule-color-cell[b-i3x4v9wx9u]  .mud-input-control {
    width: 124px;
}
/* /Components/Pages/Generic/GenericDashboardPage.razor.rz.scp.css */
/* Grid card Generic — khuôn chung 3 dashboard: card cố định 400px, auto-fill, căn giữa.
   Responsive-by-construction: ≥400px giữ cột cố định, <400px co full-width. */
.generic-device-grid[b-zavtmaqimg] {
    --card-w: 400px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--card-w)), var(--card-w)));
    grid-auto-rows: max-content;
    gap: 12px;
    justify-content: center;
    align-content: start;
}

.generic-device-grid[b-zavtmaqimg]  .device-card {
    height: 100%;
}
/* /Components/Pages/Generic/GenericDeviceManagerPage.razor.rz.scp.css */
/* Bố cục 2 cột: danh sách loại thiết bị (trái) + vùng thuộc tính gắn cố định (phải).
   Vùng phải THAY hộp thoại Sửa — xem và sửa đều diễn ra tại chỗ.
   Bề rộng cột phải cố định (kéo co giãn để sau); align-items:start để 2 cột không bị
   kéo cao bằng nhau khi danh sách dài. */
.mgr-split[b-a9rw84vss9] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 728px);
    gap: 12px;
    align-items: start;
}

/* Panel dính theo màn khi cuộn danh sách dài — 88px = chiều cao app bar + lề. */
.mgr-props[b-a9rw84vss9] {
    position: sticky;
    top: 88px;
}

/* Màn hẹp: xếp dọc, panel về sau danh sách và bỏ dính (dính trên màn ngắn che mất nội dung).
   Ngưỡng nâng theo bề rộng panel: panel 728px mà vẫn chia 2 cột ở 1280px thì trừ menu trái
   xong danh sách chỉ còn ~300px — chật hơn cả lúc chưa tách cột. */
@media (max-width: 1439.98px) {
    .mgr-split[b-a9rw84vss9] { grid-template-columns: minmax(0, 1fr); }
    .mgr-props[b-a9rw84vss9] { position: static; }
}

/* Bảng điểm đo nằm TRONG một Profile — thụt vào + đường dẫn hướng bên trái để nhìn phát
   biết đang ở tầng nào. Trước đó hai tầng nói cùng ngôn ngữ hình (tên đậm + chip + dãy nút
   icon) nên rất dễ nhầm, nhất là khi mọi Profile đều mở sẵn.

   ⚠️ CỐ Ý KHÔNG dùng viền trái ĐẬM + nền ở đây: cặp đó đã dành cho `.mgr-row-selected`
   (trạng thái ĐANG CHỌN). Dùng lại cùng ngôn ngữ hình là giết mất dấu hiệu chọn — đúng lỗi
   mà mục này đang đi chữa. Đường ở đây mảnh 1px, màu lines, không nền. */
.mgr-points[b-a9rw84vss9] {
    margin-left: 12px;
    padding-left: 12px;
    border-left: 1px solid var(--mud-palette-lines-default);
}

/* Dòng loại thiết bị đang chọn — viền trái đậm, KHÔNG bo góc (rule repo: bo góc chỉ khi
   có viền đủ 4 cạnh). */
[b-a9rw84vss9] .mgr-row-selected {
    border-left: 3px solid var(--mud-palette-primary);
    border-radius: 0;
    background: var(--mud-palette-action-default-hover);
}
/* /Components/Pages/IoT/EquipmentTreePage.razor.rz.scp.css */
/* Bố cục 2 cột (mirror khuôn /generic/devices): CÂY (trái, bề rộng cố định) + NÚT ĐANG CHỌN (phải,
   giãn). Ngược chiều với trang Generic (danh sách giãn, thuộc tính cố định) vì ở đây cột phải
   chứa 3 tab danh sách lá — nó mới là thứ cần chỗ. align-items:start để 2 cột không bị kéo cao
   bằng nhau khi một bên dài. */
.eqt-split[b-is4watpwe7] {
    display: grid;
    grid-template-columns: minmax(0, 364px) minmax(0, 1fr);
    gap: 12px;
    align-items: start;
}

/* Panel phải dính theo màn khi cây dài — 88px = chiều cao app bar + lề. */
.eqt-props[b-is4watpwe7] {
    position: sticky;
    top: 88px;
}

/* Màn hẹp: xếp dọc, cây trước, panel sau, bỏ dính (dính trên màn ngắn che mất nội dung).
   Mốc = breakpoint `lg` của MudBlazor (Responsive-Layout-Standard §1.2: media query custom phải đồng bộ
   6 breakpoint, không tự chế số) — dưới 1280 trừ drawer thì cột phải còn ~300px, xếp dọc là đúng. */
@media (max-width: 1279.98px) {
    .eqt-split[b-is4watpwe7] { grid-template-columns: minmax(0, 1fr); }
    .eqt-props[b-is4watpwe7] { position: static; }
}

/* Mã (Code/Path) — monospace để mắt tách "mã" khỏi "tên" ngay trong một dòng.
   ::deep vì class này gắn lên MudText (component con — root không mang scope); tổ tiên .eqt-split
   là div thuần có scope nên `[scope] .mono` khớp cả <td class="mono"> lẫn <p> của MudText. */
[b-is4watpwe7] .mono {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: .8em;
}
/* /Components/Pages/IoT/NodeMonitorPage.razor.rz.scp.css */
/* Giám sát theo cụm (ADR-009 chặng 3c). Dải KPI + thẻ nút con + 2 cột dưới.
   Không phải màn kiosk tự xoay trang như 3 dashboard theo trục — trang này đọc từ trên xuống,
   nên KHÔNG dùng --card-w / auto-pagination. */

/* Dải KPI: tự xuống hàng, mỗi ô tối thiểu 180px. */
.nm-kpis[b-k60ofmgjo7] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 180px), 1fr));
    gap: 12px;
}

.nm-kpi[b-k60ofmgjo7] {
    padding: 12px 14px;
}

/* Thẻ nút con — cùng cỡ, xếp theo dòng (thứ tự DisplayOrder = dòng chảy / dây chuyền). */
.nm-children[b-k60ofmgjo7] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr));
    gap: 12px;
}

.nm-card[b-k60ofmgjo7] {
    padding: 12px;
    cursor: pointer;
    transition: box-shadow .15s, transform .15s;
}

.nm-card:hover[b-k60ofmgjo7] {
    box-shadow: var(--mud-elevation-6);
    transform: translateY(-1px);
}

.nm-card-head[b-k60ofmgjo7] {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    margin-bottom: 4px;
}

.nm-card-title[b-k60ofmgjo7] {
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Ô chỉ số: nhãn nhỏ trên, số dưới — 2 cột cho thẻ, tự dàn cho khối lá. */
.nm-metrics[b-k60ofmgjo7] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 92px), 1fr));
    gap: 4px 10px;
}

.nm-metric[b-k60ofmgjo7] {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.nm-metric-label[b-k60ofmgjo7] {
    font-size: .7rem;
    opacity: .7;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.nm-metric-value[b-k60ofmgjo7] {
    font-size: .95rem;
    font-weight: 600;
    white-space: nowrap;
}

/* Hàng máy rút gọn trong thẻ nút con. */
.nm-machines[b-k60ofmgjo7] {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 10px;
    margin-top: 8px;
    font-size: .78rem;
}

.nm-machine[b-k60ofmgjo7] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    white-space: nowrap;
}

/* Chấm trạng thái — dùng chung cho nút, máy, lá. Màu lấy từ palette Mud để theo sáng/tối. */
.nm-dot[b-k60ofmgjo7] {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    flex: 0 0 auto;
    background: var(--mud-palette-text-disabled);
}

.nm-ok[b-k60ofmgjo7] { background: var(--mud-palette-success); }
.nm-warning[b-k60ofmgjo7] { background: var(--mud-palette-warning); }
.nm-alarm[b-k60ofmgjo7] { background: var(--mud-palette-error); }
.nm-offline[b-k60ofmgjo7] { background: var(--mud-palette-text-disabled); }
.nm-unknown[b-k60ofmgjo7] { background: var(--mud-palette-info); opacity: .6; }

/* Hai cột dưới: cảnh báo | lá trực tiếp. Màn hẹp thì xếp dọc (mốc lg của MudBlazor). */
.nm-split[b-k60ofmgjo7] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 12px;
    align-items: start;
}

@media (max-width: 1279.98px) {
    .nm-split[b-k60ofmgjo7] { grid-template-columns: minmax(0, 1fr); }
}

/* Dòng lá gắn trực tiếp vào nút. */
.nm-leaf[b-k60ofmgjo7] {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 0;
    border-bottom: 1px solid var(--mud-palette-lines-default);
    min-width: 0;
}

.nm-leaf:last-child[b-k60ofmgjo7] { border-bottom: none; }

.nm-leaf-generic[b-k60ofmgjo7] { flex-direction: column; align-items: stretch; }

.nm-leaf-name[b-k60ofmgjo7] {
    opacity: .75;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Khung 2 cột: CÂY điều hướng (trái, dính theo màn) + nội dung (phải).
   Cây là thứ cắt số lần bấm: từ bất kỳ cụm nào nhảy thẳng sang cụm khác 1 lần bấm,
   không phải quay-lại-rồi-bấm-tiếp. Dưới lg cây ẩn (d-none d-lg-block) → ô chọn cụm trên đầu thay thế. */
.nm-shell[b-k60ofmgjo7] {
    display: grid;
    grid-template-columns: minmax(240px, 300px) minmax(0, 1fr);
    gap: 12px;
    align-items: start;
}

.nm-tree[b-k60ofmgjo7] {
    position: sticky;
    top: 88px;
    max-height: calc(100vh - 108px);
    overflow: auto;
}

@media (max-width: 1279.98px) {
    .nm-shell[b-k60ofmgjo7] { grid-template-columns: minmax(0, 1fr); }
}
/* /Components/Pages/Machines/MachineDashboardConfigPanel.razor.rz.scp.css */
/* Bố cục 2 cột — mirror `.mgr-split` của GenericDeviceManagerPage (cùng khuôn trang quản lý:
   trái danh sách, phải thuộc tính của mục đang chọn). Cột trái hẹp cố định vì nó chỉ chứa
   tên + mã máy; cột phải nhận phần còn lại để bảng 15 ô + thẻ xem trước đủ chỗ. */
.mdc-split[b-n60rue7hah] {
    display: grid;
    /* 364px = 280 cũ + 30% (user chốt 2026-08-15): cột máy nay mang thêm tay nắm kéo + ô tick
       "hiện trên dashboard" nên tên máy bị bóp còn quá hẹp. */
    grid-template-columns: minmax(0, 364px) minmax(0, 1fr);
    gap: 12px;
    align-items: start;
}

/* Panel dính theo màn khi danh sách máy dài — 88px = chiều cao app bar + lề (số của .mgr-props). */
.mdc-props[b-n60rue7hah] {
    position: sticky;
    top: 88px;
}

/* Một mục trong danh sách chọn phạm vi. Dùng list dọc click-chọn thay radio: radio render inline
   nên danh sách 2 mục nhảy chung một hàng khi hẹp (bài học HostNetworkConfigDialog). */
.mdc-item[b-n60rue7hah] {
    display: flex;
    align-items: center;
    padding: 6px 8px;
    border-radius: 4px;
    cursor: pointer;
    border-left: 3px solid transparent;
}

.mdc-item:hover[b-n60rue7hah] {
    background: var(--mud-palette-action-default-hover);
}

/* ĐANG CHỌN — viền trái đậm + nền, y ngôn ngữ hình của `.mgr-row-selected` bên Generic. */
.mdc-item-selected[b-n60rue7hah] {
    border-left-color: var(--mud-palette-primary);
    background: var(--mud-palette-action-default-hover);
}

@media (max-width: 1279.98px) {
    .mdc-split[b-n60rue7hah] { grid-template-columns: minmax(0, 1fr); }
    .mdc-props[b-n60rue7hah] { position: static; }
}
/* /Components/Pages/Machines/MachineDashboardPage.razor.rz.scp.css */
/* ── Machine Dashboard — Fixed viewport + Fixed card size ──
   Layout: flex column fills main-content area (MudContainer max-width/padding
   neutralized in app.css via body:has(.dashboard-root) selector).
   Device grid: fixed card size 380×260. JS ResizeObserver measures grid area
   → computes cols × rows → sets pageSize. Extra cards paginate via rotate.
*/

.dashboard-root[b-hhqy29ms99] {
    height: calc(100vh - 64px); /* AppBar: 64px */
    display: flex;
    flex-direction: column;
    padding: 8px 12px;
    overflow: hidden;
    gap: 8px;
}

.dashboard-summary[b-hhqy29ms99] {
    flex: 0 0 auto;
    margin-bottom: 0 !important;
}

.dashboard-root[b-hhqy29ms99]  .dashboard-toolbar,
.dashboard-root > .mud-alert[b-hhqy29ms99],
.dashboard-root > .mud-progress-linear[b-hhqy29ms99] {
    flex: 0 0 auto;
}

/* ── Device grid: fixed card size, center-aligned ── */
.machine-device-grid[b-hhqy29ms99] {
    /* Tiêu chuẩn cũ (Đợt 2026-06-10): card RỘNG CỐ ĐỊNH --card-w, KHÔNG stretch — căn giữa,
       dư thì thành lề 2 bên (đúng kích thước thiết kế, không bị to khi ẩn menu / màn rộng). Gap 12px.
       Giữ 2 cải tiến tốt: CAO max-content (card khít nội dung, hết trống đáy) + JS tự tính cols/rows.
       JS đọc --card-w cho số cột; cao tự đo .device-card.

       ⚠️ Bề rộng lấy từ BIẾN CHUNG --ft-machine-card-w (app.css) chứ không gõ số ở đây: khung
       "Xem trước" trong tab Cấu hình dashboard phải rộng ĐÚNG BẰNG ô lưới này, hai nơi gõ số rời
       nhau thì sớm muộn lệch và xem trước lại nói dối (đúng lỗi user báo 2026-08-15).
       480px = 400 cũ + 20% (user chốt 2026-08-15: thẻ máy nay mang tới 15 ô cấu hình được, rộng
       hơn thì chữ đỡ cắt). CỐ Ý chỉ đổi dashboard MÁY — Energy/Water/Generic giữ 400px vì nội
       dung thẻ ít hơn hẳn; câu "đồng bộ 3 dashboard" của Đợt 2026-06-10 tới đây hết hiệu lực. */
    --card-w: var(--ft-machine-card-w, 480px);
    flex: 1 1 auto;
    display: grid;
    /* Responsive (mobile): minmax(min(100%, W), W) → màn ≥W giữ cột cố định W (desktop Y NGUYÊN),
       màn <W thì cột co về 100% (full-width, hết tràn/cắt cụt 2 bên). KHÔNG cần @media. */
    grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--card-w)), var(--card-w)));
    grid-auto-rows: max-content;
    gap: 12px;
    justify-content: center;
    align-content: start;
    overflow: hidden;
    min-height: 0; /* flex quirk — allow shrink */
}

/* Card inside slot: fill the 380×260 cell; no internal scroll */
.machine-device-grid[b-hhqy29ms99]  .device-card {
    height: 100%;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
/* /Components/Pages/Production/OeeConfigPanel.razor.rz.scp.css */
/* Hàng thống kê "Tình trạng sẵn sàng" (2026-08-28).
   Đây là phần tử do CHÍNH component render (div/span) nên dùng class thường — KHÔNG ::deep
   (::deep chỉ dành cho phần tử do component KHÁC render; đặt nhầm là selector không match). */

.stat-row[b-gty010vag7] {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    padding: 6px 0;
    border-bottom: 1px solid var(--mud-palette-lines-default);
    font-size: .875rem;
}

.stats > .stat-row:last-child[b-gty010vag7] {
    border-bottom: none;
}

.stat-val[b-gty010vag7] {
    font-weight: 600;
    white-space: nowrap;
}

/* Danh sách ca — ca ĐANG chạy tô nền nhạt (cùng ngôn ngữ hình với list chọn của EquipmentTreePage,
   KHÔNG dùng viền-trái-đậm: viền đậm là dấu hiệu "đang chọn", không phải "đang chạy"). */
.shift-row[b-gty010vag7] {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 5px 8px;
    border-radius: 6px;
    font-size: .8125rem;
}

.shift-row + .shift-row[b-gty010vag7] {
    margin-top: 2px;
}

.shift-row.active[b-gty010vag7] {
    background: var(--mud-palette-primary-hover);
}

.shift-name[b-gty010vag7] {
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.shift-time[b-gty010vag7] {
    color: var(--mud-palette-text-secondary);
    white-space: nowrap;
}
/* /Components/Pages/Production/OeeExplainDialog.razor.rz.scp.css */
/* Khối 3 dòng dẫn xuất (PPT / Operating Time / Good Pieces) — tách nền để đọc như phần
   "= ... = ..." in đậm giữa 2 nhóm bảng của bản gốc oee.com. */
.derived[b-n3ang9q3nw] {
    background: var(--mud-palette-background-grey);
    border-radius: 6px;
    padding: 10px 12px;
    font-size: .8125rem;
    line-height: 1.9;
}
/* /Components/Pages/Scada/ScadaConfigSection.razor.rz.scp.css */
/* Tiêu đề vùng: cùng ngôn ngữ chữ HOA-nhỏ của .scada-card-title trên canvas, nhưng là chrome của FORM
   nên cỡ cố định (không cqh) + kẻ chân theo palette Mud để đúng ở cả light/dark. */
.scfg-title[b-gaz0fqa31a] {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    opacity: 0.6;
    padding-bottom: 3px;
    margin-bottom: 6px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

/* "Không áp dụng cho loại đối tượng này" — mờ, nghiêng, KHÔNG phải control. */
.scfg-na[b-gaz0fqa31a] {
    opacity: 0.45;
    font-size: 12px;
    font-style: italic;
    padding: 0 0 2px;
}

/* Thân vùng = lưới 2 cột TỰ XẾP: control chảy vào 2 cột khi dialog rộng, tự co 1 cột khi hẹp
   (min(100%, 340px) để không tràn ngang màn nhỏ). auto-FILL chứ không auto-fit: vùng chỉ có 1 control
   (vd Nhận dạng chỉ có Nhãn) vẫn giữ 2 track ⇒ control nằm nửa trái, không phình full-width trở lại. */
.scfg-body[b-gaz0fqa31a] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr));
    gap: 10px 14px;
    align-items: start;
}

/* Chú thích + cảnh báo là CÂU VĂN — chiếm trọn hàng, không chen nửa cột với control.
   ::deep vì các phần tử này do MudBlazor render (không mang scope attribute); grid-column chỉ có tác dụng
   với grid item (con trực tiếp) — khớp đúng phần tử nằm sâu hơn thì thuộc tính trơ, vô hại. Item của
   dropdown render ở popover (portal, ngoài .scfg-body) nên không bị vạ lây. */
.scfg-body[b-gaz0fqa31a]  .mud-typography-caption {
    grid-column: 1 / -1;
    margin: 0;
}
.scfg-body[b-gaz0fqa31a]  .mud-alert {
    grid-column: 1 / -1;
}

/* Biến thể DENSE — vùng toàn control ngắn (ô số, ô màu hex, công tắc): ô ~140px → 6 ô một hàng trên dialog
   Medium (user chốt 2026-08-24 — bản 180px/5 ô vẫn bị chê rộng). 140px vừa khít ô màu (ô vuông màu + mã hex
   7 ký tự + nút mở bảng chọn); màn hẹp lưới tự co còn ít cột hơn nên không tràn. Ô số dư chút nhưng ĐỀU
   nhau — đều quan trọng hơn khít từng ô. */
.scfg-body.scfg-dense[b-gaz0fqa31a] {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 140px), 1fr));
    gap: 8px 12px;
}

/* Biến thể STACK — khối editor phức tạp (series chart, SVG binding, upload ảnh…): xếp DỌC thuần,
   không vào lưới — các hàng editor tự lo bố cục ngang của chúng, lưới 2 cột sẽ bóp vỡ. */
.scfg-body.scfg-stack[b-gaz0fqa31a] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
/* /Components/Shared/AuthBrandHeader.razor.rz.scp.css */
.auth-brand[b-eda1ef3g9y] {
    position: fixed;
    top: 20px;
    left: 28px;
    z-index: 2;
    pointer-events: none; /* click xuyên qua, không block element bên dưới */
    user-select: none;
}

.auth-brand-tagline[b-eda1ef3g9y] {
    font-size: 0.9rem;
    letter-spacing: 0.22em;
    color: var(--mud-palette-text-primary);
    opacity: 0.75;
    text-transform: uppercase;
    font-weight: 300;
    font-family: "Roboto", "Helvetica Neue", Arial, sans-serif;
}

/* Mobile <480px: gọn lại */
@media (max-width: 480px) {
    .auth-brand[b-eda1ef3g9y] {
        top: 12px;
        left: 14px;
    }
    .auth-brand-tagline[b-eda1ef3g9y] {
        font-size: 0.7rem;
        letter-spacing: 0.14em;
    }
}
/* /Components/Shared/AuthSceneBackground.razor.rz.scp.css */
/* Scene root — fixed full viewport, dưới mọi foreground content */
.scene[b-r2fovm5ffx] {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    overflow: hidden;

    /* Light mode default: tone xám trắng neutral (CAD blueprint clean),
       không đụng brand xanh lá #2E7D32, card MudPaper trắng nổi rõ */
    --scene-bg-1:       #F5F7FA;
    --scene-bg-2:       #EAEEF2;
    --scene-bg-3:       #DDE2E8;
    --scene-grid-line:  #B0BEC5;
    --scene-grid-dot:   #90A4AE;
    --scene-line:       #455A64;
    --scene-dim:        #607D8B;
    --scene-shape-fill: #EAEEF2;
    --scene-dot:        #607D8B;

    /* Background color fallback (lúc loading SVG) */
    background-color: var(--scene-bg-2);
    transition: background-color 0.3s ease;
}

/* Dark mode: tone đen-tím match MudPaper dark #1E1E2D (cùng hue, card login tan vào BG).
   Line giữ cyan #00a8ff để nổi bật trên nền đen. */
.scene.scene-dark[b-r2fovm5ffx] {
    --scene-bg-1:       #08080E;
    --scene-bg-2:       #0E0E16;
    --scene-bg-3:       #050508;
    --scene-grid-line:  #1F2740;
    --scene-grid-dot:   #2A3550;
    --scene-line:       #3F94C2;
    --scene-dim:        #1565C0;
    --scene-shape-fill: #0E0E16;
    --scene-dot:        #2A78A8;

    background-color: var(--scene-bg-1);
}

/* SVG inline fill viewport như background-size: cover */
.scene-svg[b-r2fovm5ffx] {
    width: 100%;
    height: 100%;
    display: block;
}
/* /Components/Shared/EnergyCard.razor.rz.scp.css */
/* ── Card ── */
.device-card[b-938skgbs4k] {
    background: var(--mud-palette-surface);
    border-radius: 8px;
    overflow: hidden;
    border: 1px solid var(--mud-palette-lines-default);
    transition: transform 0.15s, box-shadow 0.15s;
}
.device-card:hover[b-938skgbs4k] {
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
/* Offline state: keep full opacity — status color + header class differentiate.
   Values show "--" via FormatValue when null. */
.device-offline[b-938skgbs4k] {
    /* no opacity dim — was 0.5, removed per UX feedback */
}
.device-alarm[b-938skgbs4k] {
    border-color: #F44336;
    box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);
}

/* ── Header: 1 dòng duy nhất ── */
.device-header[b-938skgbs4k] {
    display: flex;
    align-items: center;
    padding: 5px 14px;
    gap: 8px;
    min-height: 0;
}
.device-header-info[b-938skgbs4k] {
    display: flex;
    align-items: baseline;
    gap: 8px;
    min-width: 0;
    flex: 1;
}
.device-name[b-938skgbs4k] {
    font-weight: 700;
    font-size: 1rem;
    color: #fff;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex-shrink: 0;
}
.device-location[b-938skgbs4k] {
    font-size: 0.82rem;
    color: rgba(255,255,255,0.7);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}
.device-status-dot[b-938skgbs4k] {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
}

/* ── Status variants (semantic colors — công nghiệp, giữ cố định) ── */
.status-running[b-938skgbs4k] { background: #2e7d32; }
.status-running .device-status-dot[b-938skgbs4k] {
    background: #fff;
    box-shadow: 0 0 5px rgba(255,255,255,0.6);
    animation: pulse-dot-b-938skgbs4k 1.5s infinite;
}
.status-idle[b-938skgbs4k] { background: #ef6c00; }
.status-idle .device-status-dot[b-938skgbs4k] { background: #fff3e0; }
.status-alarm[b-938skgbs4k] { background: #c62828; }
.status-alarm .device-status-dot[b-938skgbs4k] {
    background: #fff;
    box-shadow: 0 0 5px rgba(255,255,255,0.6);
    animation: pulse-dot-b-938skgbs4k 0.8s infinite;
}
.status-offline[b-938skgbs4k] { background: #90a4ae; }
.status-offline .device-status-dot[b-938skgbs4k] { background: #cfd8dc; }

@keyframes pulse-dot-b-938skgbs4k {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.5; }
}

/* ── Body ── */
.device-body[b-938skgbs4k] {
    padding: 6px 12px 6px;
}

/* ── Metrics Grid 2x3 ── */
.metrics-grid[b-938skgbs4k] {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
}
.metric-item[b-938skgbs4k] {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    padding: 4px 10px;
    border-radius: 4px;
    background: var(--mud-palette-background-gray);
}
/* Ô đặt chỗ mờ (Cách B) — nền trong + nét đứt + mờ → rõ là "chừa sẵn", KHÁC ô thật (nền đặc) */
.metric-placeholder[b-938skgbs4k] {
    background: transparent;
    border: 1px dashed var(--mud-palette-lines-default);
    opacity: 0.5;
}
.metric-placeholder .metric-value[b-938skgbs4k] {
    color: var(--mud-palette-text-disabled);
}
.metric-item.highlight[b-938skgbs4k] {
    background: color-mix(in srgb, var(--mud-palette-success) 12%, var(--mud-palette-surface));
}
.metric-label[b-938skgbs4k] {
    font-size: 0.8rem;
    color: var(--mud-palette-text-secondary);
    white-space: nowrap;
}
.metric-value[b-938skgbs4k] {
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--mud-palette-primary);
    font-family: 'Roboto Mono', 'Consolas', monospace;
}
.metric-item.highlight .metric-value[b-938skgbs4k] {
    color: var(--mud-palette-success);
}
.metric-item.metric-alarm[b-938skgbs4k] {
    background: color-mix(in srgb, #F44336 15%, var(--mud-palette-surface));
    border-left: 3px solid #F44336;
}
.metric-item.metric-alarm .metric-value[b-938skgbs4k] {
    color: #F44336;
    animation: blink-value-b-938skgbs4k 1.5s infinite;
}
@keyframes blink-value-b-938skgbs4k {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.6; }
}

/* ── Timestamp ── */
.device-timestamp[b-938skgbs4k] {
    text-align: center;
    font-size: 0.7rem;
    color: var(--mud-palette-text-disabled);
    margin-top: 8px;
    line-height: 1;
}

.device-nodata[b-938skgbs4k] {
    text-align: center;
    color: var(--mud-palette-text-disabled);
    padding: 24px 0;
    font-size: 0.9rem;
}
/* /Components/Shared/FtTablePager.razor.rz.scp.css */
/* Dropdown số dòng/trang — gọn, nhẹ cho cân đối với hàng phân trang (2026-06-28).
   Dùng Variant.Text (không viền) + cỡ chữ nhỏ. ::deep để chạm DOM nội bộ MudSelect. */
.ft-table-pager[b-6ulhp7pvh8]  .ft-pager-select .mud-input-control {
    font-size: 0.8125rem;
}
/* /Components/Shared/GenericCard.razor.rz.scp.css */
/* Card Generic — dùng chung visual .device-card với EnergyCard/MachineCard (đồng bộ 3 dashboard). */

/* ── Card ── */
.device-card[b-xxqjftn3de] {
    background: var(--mud-palette-surface);
    border-radius: 8px;
    overflow: hidden;
    border: 1px solid var(--mud-palette-lines-default);
    transition: transform 0.15s, box-shadow 0.15s;
    height: 100%;
    display: flex;
    flex-direction: column;
}
.device-card:hover[b-xxqjftn3de] {
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
.device-offline[b-xxqjftn3de] { /* giữ full opacity — status color phân biệt */ }
.device-alarm[b-xxqjftn3de] {
    border-color: #F44336;
    box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);
}

/* ── Header ── */
.device-header[b-xxqjftn3de] {
    display: flex;
    align-items: center;
    padding: 5px 14px;
    gap: 8px;
    min-height: 0;
}
.device-header-info[b-xxqjftn3de] {
    display: flex;
    align-items: baseline;
    gap: 8px;
    min-width: 0;
    flex: 1;
}
.device-name[b-xxqjftn3de] {
    font-weight: 700;
    font-size: 1rem;
    color: #fff;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex-shrink: 0;
    max-width: 60%;
}
.device-location[b-xxqjftn3de] {
    font-size: 0.82rem;
    color: rgba(255,255,255,0.7);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}
.device-status-dot[b-xxqjftn3de] {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
}

/* ── Status variants ── */
.status-running[b-xxqjftn3de] { background: #2e7d32; }
.status-running .device-status-dot[b-xxqjftn3de] {
    background: #fff;
    box-shadow: 0 0 5px rgba(255,255,255,0.6);
    animation: pulse-dot-b-xxqjftn3de 1.5s infinite;
}
.status-idle[b-xxqjftn3de] { background: #ef6c00; }
.status-idle .device-status-dot[b-xxqjftn3de] { background: #fff3e0; }
.status-alarm[b-xxqjftn3de] { background: #c62828; }
.status-alarm .device-status-dot[b-xxqjftn3de] {
    background: #fff;
    box-shadow: 0 0 5px rgba(255,255,255,0.6);
    animation: pulse-dot-b-xxqjftn3de 0.8s infinite;
}
.status-offline[b-xxqjftn3de] { background: #90a4ae; }
.status-offline .device-status-dot[b-xxqjftn3de] { background: #cfd8dc; }

@keyframes pulse-dot-b-xxqjftn3de {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.5; }
}

/* ── Body ── */
.device-body[b-xxqjftn3de] {
    padding: 6px 12px 6px;
    flex: 1;
}

/* ── Metrics grid động ── */
.metrics-grid[b-xxqjftn3de] {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
}
.metric-item[b-xxqjftn3de] {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    padding: 4px 10px;
    border-radius: 4px;
    background: var(--mud-palette-background-gray);
    min-width: 0;
}
.metric-label[b-xxqjftn3de] {
    font-size: 0.78rem;
    color: var(--mud-palette-text-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}

/* Quy tắc màu tô chữ qua style inline nên thắng .metric-value; khi ô đang báo động thì FieldColor()
   trả null (không phát inline) → rule .metric-alarm giữ nguyên tác dụng.
   ⚠️ Nền ô do đối tượng "Ô chứa giá trị" lo — .metric-alarm vẫn phải thắng, xem FieldColor(). */
.metric-value[b-xxqjftn3de] {
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--mud-palette-primary);
    font-family: 'Roboto Mono', 'Consolas', monospace;
    white-space: nowrap;
    flex-shrink: 0;
    padding-left: 6px;
}
.metric-item.metric-alarm[b-xxqjftn3de] {
    background: color-mix(in srgb, #F44336 15%, var(--mud-palette-surface));
    border-left: 3px solid #F44336;
}
.metric-item.metric-alarm .metric-value[b-xxqjftn3de] {
    color: #F44336;
    animation: blink-value-b-xxqjftn3de 1.5s infinite;
}
@keyframes blink-value-b-xxqjftn3de {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.6; }
}

/* ── Timestamp + no-data ── */
.device-timestamp[b-xxqjftn3de] {
    text-align: center;
    font-size: 0.7rem;
    color: var(--mud-palette-text-disabled);
    margin-top: 8px;
    line-height: 1;
}
.device-nodata[b-xxqjftn3de] {
    text-align: center;
    color: var(--mud-palette-text-disabled);
    padding: 24px 0;
    font-size: 0.9rem;
}
/* /Components/Shared/MachineCard.razor.rz.scp.css */
/* ── Card ── */
.device-card[b-wid7xjqbjx] {
    background: var(--mud-palette-surface);
    border-radius: 8px;
    overflow: hidden;
    border: 1px solid var(--mud-palette-lines-default);
    transition: transform 0.15s, box-shadow 0.15s;
}
.device-card:hover[b-wid7xjqbjx] {
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
/* Offline state: keep full opacity — only the header bar color + status badge
   differentiate. Values show "--" via FormatDecimal/FormatInt when null. */
.device-offline[b-wid7xjqbjx] {
    /* no opacity dim — was 0.5, removed per UX feedback */
}

/* ── Header: 1 line ── */
.device-header[b-wid7xjqbjx] {
    display: flex;
    align-items: center;
    padding: 3px 12px;
    gap: 6px;
    min-height: 0;
}
.device-header-info[b-wid7xjqbjx] {
    display: flex;
    align-items: baseline;
    gap: 6px;
    min-width: 0;
    flex: 1;
}
.device-name[b-wid7xjqbjx] {
    font-weight: 700;
    font-size: 0.9rem;
    color: #fff;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex-shrink: 0;
}
.device-location[b-wid7xjqbjx] {
    font-size: 0.78rem;
    color: rgba(255,255,255,0.7);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}
.device-status-badge[b-wid7xjqbjx] {
    font-size: 0.68rem;
    font-weight: 600;
    color: #fff;
    background: rgba(255,255,255,0.2);
    padding: 1px 6px;
    border-radius: 10px;
    white-space: nowrap;
    flex-shrink: 0;
}

/* ── Body ── */
.device-body[b-wid7xjqbjx] {
    padding: 6px 10px 6px;
}

/* ── ACTUAL vs PLAN row ── */
.actual-plan-row[b-wid7xjqbjx] {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
    margin-bottom: 3px;
}
.actual-box[b-wid7xjqbjx], .plan-box[b-wid7xjqbjx] {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 4px 4px;
    border-radius: 6px;
}
.actual-box[b-wid7xjqbjx] { background: color-mix(in srgb, var(--mud-palette-success) 12%, var(--mud-palette-surface)); }
.plan-box[b-wid7xjqbjx] { background: color-mix(in srgb, var(--mud-palette-error) 12%, var(--mud-palette-surface)); }
.actual-box .big-number[b-wid7xjqbjx] {
    color: var(--mud-palette-success);
    font-size: 1.4rem;
    font-weight: 800;
    font-family: 'Roboto Mono', 'Consolas', monospace;
    line-height: 1.1;
}
.plan-box .big-number[b-wid7xjqbjx] {
    color: var(--mud-palette-error);
    font-size: 1.4rem;
    font-weight: 800;
    font-family: 'Roboto Mono', 'Consolas', monospace;
    line-height: 1.1;
}
.box-label[b-wid7xjqbjx] {
    font-size: 0.68rem;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary);
    letter-spacing: 0.5px;
}

/* ── Time row ── */
.time-row[b-wid7xjqbjx] {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 4px;
    margin-bottom: 2px;
}
.time-item[b-wid7xjqbjx] {
    display: flex;
    align-items: center;
    gap: 3px;
    padding: 2px 6px;
    border-radius: 4px;
    background: var(--mud-palette-background-gray);
    font-size: 0.75rem;
}
.time-label[b-wid7xjqbjx] {
    flex: 1;
    font-size: 0.7rem;
    color: var(--mud-palette-text-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.time-value[b-wid7xjqbjx] {
    font-weight: 700;
    font-family: 'Roboto Mono', 'Consolas', monospace;
    color: var(--mud-palette-primary);
    font-size: 0.82rem;
}

/* ── Sensors row ── */
.sensors-row[b-wid7xjqbjx] {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 4px;
}
.sensor-item[b-wid7xjqbjx] {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 3px 2px;
    border-radius: 4px;
    background: var(--mud-palette-background-gray);
}
.sensor-label[b-wid7xjqbjx] {
    font-size: 0.62rem;
    color: var(--mud-palette-text-disabled);
    text-transform: uppercase;
    letter-spacing: 0.3px;
}
.sensor-value[b-wid7xjqbjx] {
    font-size: 0.92rem;
    font-weight: 700;
    font-family: 'Roboto Mono', 'Consolas', monospace;
    color: var(--mud-palette-text-primary);
    line-height: 1.2;
}

/* ── Actions row ── khe chia đều, nút chiếm hết khe (xem comment trong .razor).
   grid-template-columns đặt INLINE ở markup vì số khe tính theo cấu hình từng máy. */
.card-actions[b-wid7xjqbjx] {
    display: grid;
    gap: 4px;
    margin-top: 4px;
}
.card-actions .action-slot[b-wid7xjqbjx] {
    display: flex;
}
/* ::deep vì .mud-button-root do MudButton render (component con, scoped CSS không chạm được).
   width:100% → bề rộng theo KHE, không theo độ dài nhãn ("Gọi" và "Xử lý" cùng rộng).
   min-height 36px = mức touch-bump repo đang dùng cho ô thao tác bảng; trước đây nút để
   min-height:0 + padding 2px nên vùng bấm quá nhỏ trên màn HMI. */
.card-actions[b-wid7xjqbjx]  .mud-button-root {
    width: 100%;
    min-width: 0;
    min-height: 36px;
    font-size: 0.72rem;
    padding: 2px 4px;
}

/* ── Timestamp ── */
.device-timestamp[b-wid7xjqbjx] {
    text-align: center;
    font-size: 0.65rem;
    color: var(--mud-palette-text-disabled);
    margin-top: 4px;
    line-height: 1;
}

.device-nodata[b-wid7xjqbjx] {
    text-align: center;
    color: var(--mud-palette-text-disabled);
    padding: 16px 0;
    font-size: 0.85rem;
}

/* ── Temperature warnings ── */
.temp-warn[b-wid7xjqbjx] {
    color: #ef6c00 !important;
}
.temp-high[b-wid7xjqbjx] {
    color: #d32f2f !important;
}

/* ── Andon badge pulsing animation ── */
.andon-badge-pulse[b-wid7xjqbjx] {
    animation: andon-pulse-b-wid7xjqbjx 1.5s ease-in-out infinite;
}
@keyframes andon-pulse-b-wid7xjqbjx {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.5; }
}

/* ── Andon MỞ (Gọi/Đến) → cả thanh header nháy, thấy được từ xa trong xưởng ──
   `steps(1)` = nháy DỨT KHOÁT như đèn andon thật, KHÔNG fade mượt: chuyển màu mềm nhìn từ xa
   gần như không nhận ra. 1.1s/nhịp — đủ chậm để không chói mắt cả ca, đủ nhanh để đập vào mắt.
   ⚠️ Keyframes THẮNG style inline trong cascade (tầng animation nằm trên author-normal) nên
   background-color inline của header không cần đụng tới; 2 màu truyền qua CSS var vì
   keyframes không đọc được giá trị inline. */
.device-header.andon-header-alert[b-wid7xjqbjx] {
    animation: andon-header-alert-b-wid7xjqbjx 1.1s steps(1, end) infinite;
}
@keyframes andon-header-alert-b-wid7xjqbjx {
    0%, 49%   { background-color: var(--andon-color); }
    50%, 100% { background-color: var(--status-color); }
}

/* Người bật "giảm chuyển động" (hoặc màn hình bị say chuyển động): KHÔNG bỏ cảnh báo — đây là
   tín hiệu gọi người, bỏ nháy mà không thay gì khác là mất luôn cảnh báo. Thay bằng nền Andon
   TĨNH + viền dày: vẫn nổi bật, không chuyển động. */
@media (prefers-reduced-motion: reduce) {
    .device-header.andon-header-alert[b-wid7xjqbjx] {
        animation: none;
        background-color: var(--andon-color) !important;
        box-shadow: inset 0 -3px 0 rgba(255, 255, 255, 0.85);
    }
    .andon-badge-pulse[b-wid7xjqbjx] {
        animation: none;
    }
}
/* /Components/Shared/ParamLabelEditor.razor.rz.scp.css */
/* Thẻ xem trước căn GIỮA cột phải — nó rộng cố định 480px, để lệch trái thì cột phải trông hụt
   một bên khi màn rộng.

   ⛔ KHÔNG `::deep` cho class đặt trên phần tử của CHÍNH component này. Blazor biên dịch
   `::deep X` thành `[b-scope] X`, tức đòi X có TỔ TIÊN mang scope attribute; mà phần tử viết
   trong markup của component đã tự mang scope, còn tổ tiên nó (div do MudItem/MudGrid render)
   thì KHÔNG ⇒ selector không khớp gì cả và cả khối rule rơi vào hư không — build vẫn xanh, chỉ
   nhìn màn hình mới biết (đã cắn thật 2026-08-15 với khu quy tắc màu). `::deep` chỉ dành cho
   phần tử do component KHÁC render (xem rule cuối file). */
.mpl-preview[b-47sgpuj3hl] {
    margin-inline: auto;
}

/* ⛔ Siết bề rộng ô nhập của MudColorPicker Ở ĐÂY, KHÔNG đặt Style lên component: style bám gốc
   picker (bao cả bảng chọn màu) sẽ ép bảng màu thành dải dọc không bấm được — bài học Generic
   2026-08-13. `.mud-input-control` chỉ bọc ô nhập, không bọc popover.

   ⚠️ KHÔNG viết `::deep .mpl-xxx .mud-picker …` — kèm class của phần tử-mình vào trước là dính
   đúng cái bẫy ở trên (nó thành `[b-scope] .mpl-xxx …`, đòi .mpl-xxx là CON của phần tử mang
   scope). Để trần `.mud-picker` là khớp, và an toàn vì component này chỉ có một MudColorPicker. */
[b-47sgpuj3hl] .mud-picker .mud-input-control {
    min-width: 0;
}
