/* FILE SINH RA LÚC BUILD từ Styles/knsoft-theme.css (đã gộp các @import) — KHÔNG sửa tay. */
/* ============================================================
   KNSoft ERP — Theme Entry Point
   Import thứ tự: variables trước, sau đó partials.
   Lúc build, target BundleThemeCss (KNSoft.Core.Blazor.csproj) thay các @import bằng nội dung
   file ⇒ wwwroot/knsoft-theme.css là MỘT file (App.razor link file đó). Sửa CSS ở Styles/.
   ============================================================ */

/* ---- _variables.css ---- */
/* ============================================================
   KNSoft ERP — Design Tokens
   Tất cả CSS custom properties cho toàn bộ ứng dụng.
   Không hardcode màu hoặc spacing ở nơi khác.
   ============================================================ */

:root {
    /* --- Layout ---
       ⚠️ KHÔNG có token --knsoft-sidebar-width nào ở đây, và đó là CHỦ Ý.
       Bề rộng sidebar do MudBlazor quản: <MudDrawer Variant="Responsive"> lấy chiều rộng từ
       LayoutProperties.DrawerWidthLeft của theme (260px, xem KNSoftMudTheme.cs) và MudBlazor
       tự phát thành --mud-drawer-width-left. Trước 2026-09-17 file này có khai
       --knsoft-sidebar-width: 260px + --knsoft-sidebar-mini-width: 56px, nhưng KHÔNG ai đọc
       hai biến đó — sửa chúng không đổi được gì mà lại tưởng là đổi được. Đã bỏ để không còn
       nguồn số thứ hai. Muốn đổi bề rộng sidebar → sửa DrawerWidthLeft trong KNSoftMudTheme.cs. */

    /* Chiều cao AppBar — DẪN XUẤT, không khai cứng.

       ⚠️ ĐỌC TRƯỚC KHI SỬA. Trước 2026-09-17 có BA con số mâu thuẫn:
         · KNSoftMudTheme.cs  AppbarHeight = "56px"  ⇒ MudBlazor phát --mud-appbar-height: 56px
         · file này           khai cứng 48px
         · _layout.css        ép .knsoft-appbar { height: 48px }
       AppBar trong MainLayout lại bật Dense="true" ⇒ MudBlazor vẽ nó cao
       calc(--mud-appbar-height - --mud-appbar-height/4) = 42px, và cũng dùng chính công thức
       ấy để đặt `top` cho drawer (xem .mud-appbar-dense ~ .mud-drawer-fixed trong MudBlazor.min.css).
       Ba nguồn lệch nhau nên mép trên drawer không khớp đáy appbar thật ⇒ hở khe vài pixel
       và sinh scrollbar dọc giả.

       Cách chốt (một nguồn sự thật duy nhất):
         1. MudAppBar KHÔNG bật Dense      → appbar cao đúng --mud-appbar-height
         2. KNSoftMudTheme.AppbarHeight    = 48px  (nguồn sự thật)
         3. biến này                       = var(--mud-appbar-height)  ← ở đây
       MudBlazor đặt `top: var(--mud-appbar-height)` cho drawer khi ClipMode=Always
       (rule .mud-drawer-fixed.mud-drawer-responsive.mud-drawer-clipped-always), nên cả hai
       phía cùng đọc một biến ⇒ không thể lệch. Muốn đổi chiều cao: sửa AppbarHeight trong
       KNSoftMudTheme.cs, KHÔNG sửa số ở đây.

       (Cố ý KHÔNG dùng công thức calc(--mud-appbar-height - .../4): công thức đó chỉ đúng khi
       appbar bật Dense. Bỏ Dense là appbar cao bằng đúng biến gốc.) */
    --knsoft-appbar-height: var(--mud-appbar-height, 48px);

    --knsoft-content-padding: 16px;
    --knsoft-content-padding-sm: 8px;

    /* --- Spacing Scale (align với MudBlazor spacing: 1 unit = 4px) --- */
    --knsoft-space-1: 4px;
    --knsoft-space-2: 8px;
    --knsoft-space-3: 12px;
    --knsoft-space-4: 16px;
    --knsoft-space-5: 20px;
    --knsoft-space-6: 24px;
    --knsoft-space-8: 32px;

    /* --- Border Radius --- */
    --knsoft-radius-sm: 4px;
    --knsoft-radius-md: 8px;
    --knsoft-radius-lg: 12px;
    --knsoft-radius-xl: 16px;

    /* --- Elevation (shadow) --- */
    --knsoft-shadow-card: 0 1px 4px rgba(0,0,0,.12);
    --knsoft-shadow-dialog: 0 8px 32px rgba(0,0,0,.18);

    /* --- Typography --- */
    --knsoft-font-size-xs: 0.75rem;
    --knsoft-font-size-sm: 0.875rem;
    --knsoft-font-size-md: 1rem;
    --knsoft-font-size-lg: 1.125rem;
    --knsoft-font-size-xl: 1.25rem;

    /* --- Z-Index Layers --- */
    --knsoft-z-drawer: 1200;
    --knsoft-z-appbar: 1100;
    --knsoft-z-dialog: 1300;
    --knsoft-z-snackbar: 1400;
    --knsoft-z-tooltip: 1500;

    /* --- DataGrid ---
       Tô nền header/hover dựa trên --mud-palette-text-primary thay vì màu đen đặc.
       Ở light mode text-primary là #1F2937 (đậm) ⇒ ra xám nhạt như cũ.
       Ở dark mode nó là #E8ECF1 (sáng)  ⇒ ra trắng mờ — đúng chiều.
       Nhờ vậy KHÔNG cần class .dark-mode nào: chỉ có MỘT nguồn sự thật là palette của
       MudBlazor, tự lật theo IsDarkMode.

       (Trước 2026-09-17: khai cứng rgba(0,0,0,.04) ở :root + override trong .dark-mode —
       nhưng KHÔNG nơi nào gắn class "dark-mode" vào DOM nên nhánh override là code chết,
       và header/hover lưới gần như vô hình khi bật chế độ tối.) */
    --knsoft-grid-header-bg: color-mix(in srgb, var(--mud-palette-text-primary) 5%, transparent);
    --knsoft-grid-row-hover-bg: color-mix(in srgb, var(--mud-palette-text-primary) 4%, transparent);
    --knsoft-grid-dense-row-height: 36px;

    /* --- Form --- */
    --knsoft-form-label-width: 160px;
    --knsoft-input-min-width: 120px;

    /* --- Card --- */
    --knsoft-card-padding: 16px;
    --knsoft-stat-card-min-width: 200px;
    --knsoft-stat-card-icon-size: 40px;

    /* --- Print --- */
    --knsoft-print-font-size: 12px;
    --knsoft-print-header-height: 60px;
}

/* KHÔNG cần khối override dark-mode ở đây.
   Mọi token ở trên đều suy ra từ --mud-palette-* (do MudThemeProvider sinh) nên tự lật
   theo IsDarkMode. Khối ".dark-mode" cũ đã bị xoá 2026-09-17: nó là code chết vì không
   nơi nào trong repo gắn class "dark-mode" vào DOM — grep toàn bộ *.razor/*.cs/*.cshtml
   chỉ ra duy nhất dòng khai báo nó. Ai cần override riêng cho dark mode thì dùng
   selector ".mud-theme-dark" (MudBlazor tự gắn) hoặc suy từ --mud-palette-* như trên. */

/* ---- _layout.css ---- */
/* ============================================================
   KNSoft ERP — Layout
   AppBar, Sidebar, Main content area.
   ============================================================ */

/* ----- Skip link (bàn phím / screen reader) ----- */
.knsoft-skip-link {
    position: absolute;
    left: var(--knsoft-space-3);
    top: -100px;
    z-index: calc(var(--knsoft-z-appbar) + 10);
    padding: var(--knsoft-space-2) var(--knsoft-space-3);
    background: var(--mud-palette-surface);
    color: var(--mud-palette-primary);
    border-radius: var(--knsoft-radius-sm);
    font-weight: 600;
    text-decoration: none;
}

.knsoft-skip-link:focus {
    top: var(--knsoft-space-2);
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 2px;
}

/* ----- AppBar ----- */
.knsoft-appbar {
    height: var(--knsoft-appbar-height);
    z-index: var(--knsoft-z-appbar);
    overflow: visible;
    border-bottom: 1px solid color-mix(in srgb, #000 18%, var(--mud-palette-appbar-background));
}

.knsoft-appbar .mud-button-root {
    text-transform: none;
}

.knsoft-appbar__icon-btn {
    color: inherit;
}

.knsoft-appbar__menu-btn {
    display: none;
}

/* ----- Top nav trên AppBar -----
   ≥1280px: mục cấp 1 trên thanh, mega panel khi bấm.
   Nhóm phẳng (Bán hàng, Kho) → 1 cột. Nhóm sâu (HRM, Báo cáo) → lưới cột.
   Mục dư vào "Thêm". */
.knsoft-topnav {
    position: relative;
    display: flex;
    align-items: stretch;
    flex: 1 1 auto;
    min-width: 0;
    height: 100%;
    /* KHÔNG hidden: dropdown mega là absolute bên trong ⇒ bị cắt. Số mục vừa chỗ do knsoft-theme.js đo (bindTopNav). */
    overflow: visible;
    margin-left: var(--knsoft-space-1);
}

.knsoft-topnav__slot {
    display: flex;
    align-items: stretch;
    flex: 0 0 auto;
}

/* Nút "Thêm" chỉ được render khi có mục bị dồn (MudTopNav.HasOverflow). */
.knsoft-topnav__more {
    flex: 0 0 auto;
}

/* Chỉ thanh menu được co lại khi thiếu chỗ (JS đo theo bề rộng nav); logo, ô tìm nhanh và cụm nút
   bên phải giữ nguyên kích thước — trước đây chúng co theo và bị bóp méo. */
.knsoft-appbar .knsoft-brand,
.knsoft-appbar .knsoft-quicknav-launcher,
.knsoft-appbar .knsoft-appbar__tools {
    flex-shrink: 0;
}

/* Wrapper nút + dropdown. Khi mở, z-index nâng cả cụm trong stacking context của AppBar;
   backdrop (0) và dropdown (1) cùng context ⇒ click link trúng <a>, click ngoài trúng backdrop.
   Wrapper là flex item nên z-index có hiệu lực cả khi position: static (biến thể --wide). */
.knsoft-topnav__item {
    position: relative;
    display: flex;
    align-items: stretch;
    height: 100%;
}

/* Mega nhiều cột: neo theo mép trái .knsoft-topnav thay vì theo nút ⇒ không tràn phải màn hình. */
.knsoft-topnav__item--wide {
    position: static;
}

.knsoft-topnav__item--open {
    z-index: 20;
}

.knsoft-topnav__btn {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    height: 100%;
    padding: 0 10px;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: var(--knsoft-font-size-sm);
    font-weight: 600;
    letter-spacing: .01em;
    white-space: nowrap;
    text-decoration: none;
    cursor: pointer;
}

.knsoft-topnav__btn:hover,
.knsoft-topnav__btn--open {
    background: rgba(255, 255, 255, .12);
}

/* Viền focus TRẮNG trên nền appbar xanh: màu cam (tertiary) chỉ đạt tương phản 2.29:1, gần như
   không thấy khi đi bằng Tab (WCAG 1.4.11 yêu cầu ≥ 3:1). Trắng trên #1B4B91 đạt 8.5:1. */
.knsoft-topnav__btn:focus-visible {
    outline: 2px solid #fff;
    outline-offset: -2px;
}

.knsoft-topnav__btn--active {
    background: rgba(255, 255, 255, .16);
    box-shadow: inset 0 -2px 0 var(--mud-palette-tertiary);
}

.knsoft-topnav__chevron {
    display: inline-flex;
    opacity: .8;
    margin-left: 1px;
    transition: transform .15s ease;
}

.knsoft-topnav__btn--open .knsoft-topnav__chevron {
    transform: rotate(180deg);
}

.knsoft-topnav__chevron .mud-icon-root {
    font-size: 18px;
}

/* ----- Mega menu dropdown (tự viết, không MudMenu/MudPopover) ----- */
.knsoft-megamenu__backdrop {
    position: fixed;
    inset: 0;
    z-index: 0;
    background: transparent;
    cursor: default;
}

.knsoft-megamenu__dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 1;
    margin-top: 2px;
    overflow: hidden;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--knsoft-radius-md);
    box-shadow: var(--knsoft-shadow-dialog);
    background: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
}

.knsoft-megamenu__dropdown--end {
    left: auto;
    right: 0;
}

.knsoft-megamenu__panel {
    display: grid;
    gap: var(--knsoft-space-2) var(--knsoft-space-3);
    padding: var(--knsoft-space-3);
    background: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
}

.knsoft-megamenu__panel--compact {
    grid-template-columns: 1fr;
    min-width: 240px;
    max-width: 300px;
}

.knsoft-megamenu__panel--wide {
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    min-width: min(560px, 88vw);
    max-width: min(960px, 92vw);
    max-height: min(70vh, 560px);
    overflow: auto;
}

.knsoft-megamenu__panel--stacked {
    display: flex;
    flex-direction: column;
    gap: var(--knsoft-space-3);
    padding: 0;
    min-width: 0;
}

.knsoft-megamenu__panel--more {
    min-width: min(640px, 90vw);
}

.knsoft-megamenu__col {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.knsoft-megamenu__heading {
    font-size: var(--knsoft-font-size-xs);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--mud-palette-text-secondary);
    padding: 6px 10px 4px;
}

.knsoft-megamenu__heading--module {
    font-size: var(--knsoft-font-size-sm);
    letter-spacing: .02em;
    text-transform: none;
    color: var(--mud-palette-text-primary);
    padding: 4px 10px 8px;
    border-bottom: 1px solid var(--mud-palette-divider);
    margin-bottom: 4px;
}

.knsoft-megamenu__link {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    min-height: 36px;
    padding: 6px 10px;
    border-radius: var(--knsoft-radius-sm);
    color: var(--mud-palette-text-primary);
    font-size: var(--knsoft-font-size-sm);
    text-decoration: none;
    cursor: pointer;
}

.knsoft-megamenu__link:hover {
    background: color-mix(in srgb, var(--mud-palette-primary) 8%, transparent);
}

.knsoft-megamenu__link--active {
    background: rgba(var(--mud-palette-primary-rgb), .12);
    font-weight: 600;
    color: var(--mud-palette-primary);
}

.knsoft-megamenu__link--disabled {
    opacity: .5;
    cursor: default;
    pointer-events: none;
}

.knsoft-megamenu__link:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: -2px;
}

.knsoft-megamenu__link .mud-icon-root {
    flex: 0 0 auto;
    font-size: 18px;
    opacity: .75;
}

/* Số mục hiển thị trên thanh: KHÔNG còn cố định theo breakpoint (nth-child 11/9/7 cũ) mà do
   knsoft-theme.js đo bề rộng thật rồi báo MudTopNav (xem bindTopNav). */

@media (max-width: 1279.95px) {
    .knsoft-appbar__menu-btn {
        display: inline-flex;
    }

    .knsoft-topnav {
        display: none;
    }
}

.knsoft-appbar__tools {
    display: flex;
    align-items: center;
    gap: 2px;
    margin-left: var(--knsoft-space-2);
}

.knsoft-brand {
    display: flex;
    align-items: center;
    height: 100%;
    margin-right: var(--knsoft-space-2);
    flex: 0 0 auto;
}

.knsoft-brand__logo {
    height: 32px;
    width: auto;
    display: block;
}

.knsoft-branch-switcher {
    max-width: 220px;
    color: inherit;
}

.knsoft-branch-switcher__name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 160px;
    display: inline-block;
    vertical-align: bottom;
}

.knsoft-branch-switcher--warn {
    max-width: 280px;
}

@media (max-width: 1100px) {
    .knsoft-branch-switcher__name {
        display: none;
    }
}

.knsoft-user-activator {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 2px 6px 2px 2px;
    border-radius: var(--knsoft-radius-md);
    cursor: pointer;
}

.knsoft-user-activator:hover {
    background: rgba(255, 255, 255, .12);
}

.knsoft-user-activator:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 1px;
}

/* Mọi nút icon/nút thường trên appbar: viền focus trắng thay cho viền xanh mặc định (vô hình trên nền xanh). */
.knsoft-appbar .mud-button-root:focus-visible,
.knsoft-appbar .mud-icon-button:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 1px;
}

.knsoft-user-activator__name {
    font-size: var(--knsoft-font-size-sm);
    font-weight: 600;
    max-width: 140px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

@media (max-width: 1279.95px) {
    .knsoft-user-activator__name {
        display: none;
    }

    .knsoft-user-activator {
        padding: 2px;
    }
}

.knsoft-user-menu__header {
    display: flex;
    align-items: center;
    gap: var(--knsoft-space-3);
    padding: var(--knsoft-space-3) var(--knsoft-space-4);
    min-width: 240px;
}

.knsoft-user-menu__identity {
    min-width: 0;
}

.knsoft-user-menu__logout {
    color: var(--mud-palette-error);
}

/* ----- Sidebar / Drawer (Temporary overlay, hamburger < 1280px) -----
   KHÔNG khai width ở đây: MudDrawer đặt --mud-drawer-width-left từ
   LayoutProperties.DrawerWidthLeft của theme (260px), rồi .mud-drawer--open dùng
   width: var(--mud-drawer-width, var(--mud-drawer-width-left)). Khai cứng ở đây sẽ
   đánh nhau với cơ chế đó khi đổi chiều rộng trong theme.

   🔴 z-index: trước 2026-09-17 dòng dưới ghi var(--knsoft-z-sidebar) — biến này
   KHÔNG hề được khai ở _variables.css (chỉ có --knsoft-z-drawer). CSS không hợp lệ
   nên z-index bị bỏ qua âm thầm, sidebar nằm dưới appbar. Nay dùng biến thật. */
.knsoft-sidebar {
    z-index: var(--knsoft-z-drawer);
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-gutter: stable;
    border-right: 1px solid var(--mud-palette-divider);
}

.knsoft-sidebar::-webkit-scrollbar {
    width: 6px;
}

.knsoft-sidebar::-webkit-scrollbar-thumb {
    background: rgba(var(--mud-palette-primary-rgb), .25);
    border-radius: var(--knsoft-radius-sm);
}

.knsoft-sidebar::-webkit-scrollbar-thumb:hover {
    background: rgba(var(--mud-palette-primary-rgb), .45);
}

.knsoft-sidebar::-webkit-scrollbar-track {
    background: transparent;
}

/* ----- Nav link styling -----
   Sidebar luôn hiện chữ (không còn chế độ thu về 56px chỉ hiện icon), nên đây là
   dịp chuẩn hoá luôn phần nhìn: mục cấp 1 đậm hơn, mục cấp 2 thụt vào và nhạt hơn,
   mục đang mở có vạch nhấn bên trái để mắt bám được vị trí trong menu nhiều cấp. */
.knsoft-sidebar .mud-nav-link-text {
    font-size: var(--knsoft-font-size-sm);
}

.knsoft-sidebar .mud-nav-link {
    position: relative;
    border-radius: var(--knsoft-radius-sm);
    margin: 1px 8px;
    min-height: 38px;
}

.knsoft-sidebar .mud-nav-link:hover {
    background: color-mix(in srgb, var(--mud-palette-primary) 8%, transparent);
}

.knsoft-sidebar .mud-nav-link:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: -2px;
}

/* Vạch nhấn bên trái cho mục đang được chọn — dùng ::before để không phải thêm markup */
.knsoft-sidebar .mud-nav-link.active::before {
    content: "";
    position: absolute;
    left: 0;
    top: 20%;
    bottom: 20%;
    width: 3px;
    border-radius: 0 var(--knsoft-radius-sm) var(--knsoft-radius-sm) 0;
    background: var(--mud-palette-primary);
}

.knsoft-sidebar .mud-nav-link.active {
    background: rgba(var(--mud-palette-primary-rgb), .12);
    font-weight: 600;
}

/* Mục cấp 1 là chính các MudNavGroup (Đơn hàng, Kho, Mua hàng…): tiêu đề đậm hơn
   để phân tầng rõ với các mục con nằm trong nhóm. */
.knsoft-sidebar .mud-nav-group > .mud-nav-link {
    font-weight: 600;
    color: var(--mud-palette-text-primary);
}

/* Mục con (cấp 2) thụt vào + nhạt hơn ⇒ nhìn ra ngay mình đang ở trong nhóm nào */
.knsoft-sidebar .mud-nav-group .mud-nav-group .mud-nav-link,
.knsoft-sidebar .mud-nav-group .mud-nav-link:not(.mud-nav-group > .mud-nav-link) {
    padding-left: 32px;
    color: var(--mud-palette-text-secondary);
}

.knsoft-sidebar .mud-nav-group .mud-nav-link:not(.mud-nav-group > .mud-nav-link):hover {
    color: var(--mud-palette-text-primary);
}

/* ----- Quick nav launcher (AppBar) + command palette (Ctrl+K) ----- */
.knsoft-quicknav-launcher {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 32px;
    margin: 0 var(--knsoft-space-2);
    padding: 0 10px 0 8px;
    max-width: 280px;
    min-width: 32px;
    border: 1px solid rgba(255, 255, 255, .35);
    border-radius: var(--knsoft-radius-md);
    background: rgba(255, 255, 255, .10);
    color: inherit;
    cursor: pointer;
    font: inherit;
}

.knsoft-quicknav-launcher:hover {
    border-color: rgba(255, 255, 255, .7);
    background: rgba(255, 255, 255, .16);
}

.knsoft-quicknav-launcher:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}

.knsoft-quicknav-launcher__text {
    flex: 1 1 auto;
    text-align: left;
    font-size: var(--knsoft-font-size-sm);
    opacity: .9;
    white-space: nowrap;
    overflow: hidden;
}

.knsoft-quicknav-launcher__kbd {
    font-size: var(--knsoft-font-size-xs);
    font-family: inherit;
    font-weight: 600;
    letter-spacing: .02em;
    padding: 1px 5px;
    border: 1px solid rgba(255, 255, 255, .35);
    border-radius: 4px;
    opacity: .8;
}

.mud-theme-dark .knsoft-quicknav-launcher {
    border-color: rgba(255, 255, 255, .18);
    background: rgba(255, 255, 255, .06);
}

@media (max-width: 960px) {
    .knsoft-quicknav-launcher__text,
    .knsoft-quicknav-launcher__kbd {
        display: none;
    }

    .knsoft-quicknav-launcher {
        width: 32px;
        max-width: 32px;
        padding: 0;
        justify-content: center;
        border-color: transparent;
        background: transparent;
    }
}

.knsoft-quicknav-palette {
    width: min(560px, calc(100vw - 32px));
    margin: 12vh auto 0;
    padding: var(--knsoft-space-3);
    background: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    border-radius: var(--knsoft-radius-lg);
    box-shadow: var(--knsoft-shadow-dialog);
    border: 1px solid var(--mud-palette-lines-default);
}

.knsoft-quicknav-palette__input {
    width: 100%;
}

/* Dropdown phải nằm trên overlay (ZIndex 1600), nếu không click chọn mục sẽ rơi xuống backdrop. */
.knsoft-quicknav-popover {
    z-index: 1700 !important;
}

.knsoft-quicknav-palette__hint {
    display: block;
    margin-top: var(--knsoft-space-2);
    padding: 0 2px;
}

/* ----- Page Toolbar (KNSoftPageToolbar) -----
   Dải nút hành động cấp trang, đặt ngay dưới PageHeader.
   Trước 2026-09-17 class này chỉ xuất hiện trong _print.css (để ẩn khi in) mà KHÔNG có
   rule hiển thị nào ⇒ component render ra đúng class nhưng không có style gì. */
.knsoft-page-toolbar {
    gap: var(--knsoft-space-2);
    margin-bottom: var(--knsoft-space-3);
    flex-wrap: wrap;
}

/* ----- Main Content ----- */
.knsoft-main-content {
    padding: 0;
    min-height: calc(100vh - var(--knsoft-appbar-height));
    /* [Migration T-REVIEW] Nền trang theo palette: MudThemeProvider 9 không tự gán nền body,
       thiếu dòng này chế độ tối chỉ tối ở bảng/thẻ còn nền trang vẫn sáng. */
    background: var(--mud-palette-background);
}

/* ----- Page Shell ----- */
.knsoft-page-shell {
    padding: var(--knsoft-content-padding);
    display: flex;
    flex-direction: column;
    gap: var(--knsoft-space-4);
    min-height: calc(100vh - var(--knsoft-appbar-height));
    outline: none;
}

.knsoft-status-page {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: min(60vh, 480px);
    padding: var(--knsoft-space-6) var(--knsoft-space-3);
}

.knsoft-status-page__card {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--knsoft-space-3);
    max-width: 420px;
    padding: var(--knsoft-space-8) var(--knsoft-space-6);
    background: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--knsoft-radius-lg);
}

.knsoft-status-page__icon-wrap {
    width: 64px;
    height: 64px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: color-mix(in srgb, var(--mud-palette-primary) 10%, transparent);
}

.knsoft-status-page__icon {
    font-size: 2rem;
    color: var(--mud-palette-primary);
}

.knsoft-status-page__title {
    margin: 0;
}

.knsoft-status-page__desc {
    color: var(--mud-palette-text-secondary);
    margin: 0;
}

@media (max-width: 600px) {
    .knsoft-page-shell {
        padding: var(--knsoft-content-padding-sm);
    }
}

/* ----- Page (legacy compat) ----- */
.knsoft-page {
    display: flex;
    flex-direction: column;
    gap: var(--knsoft-space-4);
}

/* ---- _pageheader.css ---- */
/* ============================================================
   KNSoft ERP — PageHeader
   Breadcrumb + tiêu đề + nhóm nút hành động. Dùng flexbox thật
   (không dùng MudSpacer) để tiêu đề và nhóm nút tự xuống dòng
   khi không đủ chỗ, thay vì tràn/vỡ khi thu nhỏ màn hình.
   ============================================================ */

.knsoft-pageheader {
    margin-bottom: var(--knsoft-space-4);
    padding-bottom: var(--knsoft-space-3);
    border-bottom: 1px solid var(--mud-palette-divider);
}

.knsoft-pageheader__breadcrumb {
    margin-bottom: var(--knsoft-space-1);
}

.knsoft-pageheader__breadcrumb .mud-breadcrumb-item {
    font-size: var(--knsoft-font-size-xs);
}

.knsoft-pageheader__heading {
    flex: 1 1 auto;
    min-width: 0;
}

.knsoft-pageheader__subtitle {
    display: block;
    margin-top: 2px;
    color: var(--mud-palette-text-secondary);
}

.knsoft-pageheader__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--knsoft-space-2) var(--knsoft-space-3);
    width: 100%;
}

.knsoft-pageheader__title {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.knsoft-pageheader__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--knsoft-space-2);
    flex: 0 0 auto;
}

.knsoft-pageheader__action-btn {
    white-space: nowrap;
}

/* Màn hình hẹp: tiêu đề xuống hàng riêng, nút chỉ hiện icon để không bao giờ vỡ hàng */
@media (max-width: 600px) {
    .knsoft-pageheader__title {
        white-space: normal;
        flex-basis: 100%;
    }

    .knsoft-pageheader__action-text {
        display: none;
    }

    .knsoft-pageheader__action-btn {
        min-width: 0;
        padding-left: var(--knsoft-space-2);
        padding-right: var(--knsoft-space-2);
    }
}

/* ---- _typography.css ---- */
/* ============================================================
   KNSoft ERP — Typography
   Page headings, labels, captions.
   ============================================================ */

/* ----- Page Title ----- */
.knsoft-page-title {
    font-size: var(--knsoft-font-size-xl);
    font-weight: 700;
    line-height: 1.3;
    margin: 0;
}

/* ----- Section Title -----
   Nguồn sự thật DUY NHẤT của .knsoft-section-title.

   🔴 Trước 2026-09-17 class này bị định nghĩa 2 lần: ở đây (letter-spacing .05em)
   và ở _card.css (.04em). Vì _card.css được @import SAU _typography.css nên bản
   .04em thắng — sửa ở file này không có tác dụng gì, và không có gì báo lỗi.
   Nay gộp về đây, giữ đúng giá trị đang hiển thị thật (.04em). */
.knsoft-section-title {
    font-size: var(--knsoft-font-size-sm);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--mud-palette-text-secondary);
}

/* ----- Label ----- */
.knsoft-label {
    font-size: var(--knsoft-font-size-xs);
    font-weight: 500;
    color: var(--mud-palette-text-secondary);
}

/* ----- Value (display) ----- */
.knsoft-value {
    font-size: var(--knsoft-font-size-md);
}

/* ----- Mono (code, serial, ID) ----- */
.knsoft-mono {
    font-family: 'Courier New', monospace;
    font-size: var(--knsoft-font-size-sm);
    letter-spacing: 0.03em;
}

/* ----- Truncate ----- */
.knsoft-truncate {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    max-width: 100%;
}

/* ----- Pre-line (giữ xuống dòng trong text nhiều dòng) ----- */
.knsoft-preline {
    white-space: pre-line;
}

/* ----- Diff values (lịch sử thay đổi) ----- */
.knsoft-old-value {
    color: var(--mud-palette-error-text);
}

.knsoft-new-value {
    color: var(--mud-palette-success-text);
}

.knsoft-middle-icon {
    vertical-align: middle;
}

/* ----- Status chip ----- */
.knsoft-status-chip {
    text-transform: none;
    font-size: 0.75rem;
}

/* ----- Utility tương thích kiểu Bootstrap -----
   App KHÔNG nạp Bootstrap, MudBlazor lại không có các class dưới đây, nhưng code các module vẫn dùng
   (w-100 ~50 chỗ, text-muted ~40, fw-bold ~20, align-items-center...). Trước 2026-11-12 chúng không có
   tác dụng gì: chữ "đậm" vẫn thường, flex không căn giữa dọc. Định nghĩa một lần ở đây cho mọi module.
   Code mới nên dùng class gốc MudBlazor (align-center, mud-width-full, mud-text-secondary). */
.w-100 { width: 100% !important; }
.align-items-center { align-items: center !important; }
.text-muted { color: var(--mud-palette-text-secondary) !important; }
.fw-normal { font-weight: 400 !important; }
.fw-medium { font-weight: 500 !important; }
.fw-semibold,
.font-weight-semibold { font-weight: 600 !important; }
.fw-bold { font-weight: 700 !important; }

/* ---- _card.css ---- */
/* ============================================================
   KNSoft ERP — Cards
   StatCard, InfoCard, DashboardCard.
   ============================================================ */

/* ----- Base Card ----- */
.knsoft-card {
    padding: var(--knsoft-card-padding);
    border-radius: var(--knsoft-radius-md);
    box-shadow: var(--knsoft-shadow-card);
}

/* ----- Stat Card ----- */
.knsoft-stat-card {
    min-width: var(--knsoft-stat-card-min-width);
    display: flex;
    align-items: center;
    gap: var(--knsoft-space-4);
    padding: var(--knsoft-card-padding);
}

.knsoft-stat-card__icon {
    width: var(--knsoft-stat-card-icon-size);
    height: var(--knsoft-stat-card-icon-size);
    border-radius: var(--knsoft-radius-md);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.knsoft-stat-card__value {
    font-size: var(--knsoft-font-size-xl);
    font-weight: 700;
    line-height: 1.2;
}

.knsoft-stat-card__label {
    font-size: var(--knsoft-font-size-xs);
    color: var(--mud-palette-text-secondary);
}

/* ----- Section ----- */
.knsoft-section {
    border-radius: var(--knsoft-radius-md);
}

/* .knsoft-section-title được định nghĩa ở _typography.css — nguồn sự thật duy nhất.
   Đã xoá bản trùng ở đây (2026-09-17): khai cùng class ở 2 file mà file này nạp sau
   khiến bản kia thành vô hiệu một cách âm thầm. */

/* ----- Dashboard Card Grid ----- */
.knsoft-stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(var(--knsoft-stat-card-min-width), 1fr));
    gap: var(--knsoft-space-4);
    margin-bottom: var(--knsoft-space-4);
}

/* ----- Empty state ----- */
.knsoft-empty-icon-wrap {
    width: 56px;
    height: 56px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: color-mix(in srgb, var(--mud-palette-primary) 8%, transparent);
}

.knsoft-empty-icon {
    font-size: 1.75rem;
    color: var(--mud-palette-primary);
    opacity: 0.7;
}

.knsoft-empty-title {
    color: var(--mud-palette-text-primary);
    font-weight: 600;
}

.knsoft-empty-sub {
    color: var(--mud-palette-text-secondary);
}

/* ----- Camera/video input ----- */
.knsoft-camera-video {
    width: 100%;
    max-height: 400px;
    background: #000;
    border-radius: var(--knsoft-radius-sm);
}

/* ----- Entity header (trang chi tiết khách hàng / đối tác) ----- */
.knsoft-entity-header-section {
    margin-bottom: var(--knsoft-space-3);
}

.knsoft-entity-header {
    display: flex;
    align-items: center;
    gap: var(--knsoft-space-4);
    flex-wrap: wrap;
}

.knsoft-entity-header__body {
    min-width: 0;
    flex: 1 1 220px;
}

.knsoft-entity-header__name {
    margin: 0;
    font-weight: 700;
    line-height: 1.3;
}

.knsoft-entity-header__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--knsoft-space-2);
    margin-top: var(--knsoft-space-1);
}

.knsoft-entity-header__facts {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--knsoft-space-4);
    margin-top: var(--knsoft-space-2);
}

.knsoft-entity-fact {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--mud-palette-text-secondary);
    font-size: var(--knsoft-font-size-sm);
    min-width: 0;
    max-width: 100%;
}

.knsoft-entity-fact .mud-icon-root {
    flex-shrink: 0;
}

.knsoft-summary-bar {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--knsoft-space-6);
    padding: var(--knsoft-space-3);
    margin-top: var(--knsoft-space-2);
    background: color-mix(in srgb, var(--mud-palette-primary) 6%, var(--mud-palette-surface));
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--knsoft-radius-sm);
}

.knsoft-list-identity {
    display: flex;
    align-items: center;
    gap: var(--knsoft-space-3);
    min-width: 0;
}

.knsoft-list-identity__text {
    min-width: 0;
    flex: 1 1 auto;
}

.knsoft-list-identity__name {
    display: block;
    font-weight: 600;
    line-height: 1.3;
}

.knsoft-row-inactive {
    opacity: 0.72;
}

.knsoft-merge-pick {
    border: 1px dashed var(--mud-palette-lines-default);
    border-radius: var(--knsoft-radius-md);
    padding: var(--knsoft-space-3);
    min-height: 132px;
    height: 100%;
    background: var(--mud-palette-surface);
}

.knsoft-merge-pick--filled {
    border-style: solid;
}

.knsoft-entity-tabs {
    background: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--knsoft-radius-md);
}

.knsoft-field {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.knsoft-field .knsoft-value {
    word-break: break-word;
}

/* ----- Image centering ----- */
.knsoft-image-center {
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
}

/* ---- _table.css ---- */
/* ============================================================
   KNSoft ERP — DataGrid / Table
   Styling bổ sung cho MudDataGrid.
   ============================================================ */

/* ----- Grid Container ----- */
/* KHÔNG đặt box-shadow ở đây: MudDataGrid bên trong đã có Elevation (mặc định 1) ⇒ thêm bóng ở
   wrapper là hai lớp bóng chồng nhau, viền grid đậm và lệch so với card khác. */
.knsoft-datagrid {
    border-radius: var(--knsoft-radius-md);
    overflow: hidden;
}

/* ----- Header ----- */
.knsoft-datagrid .mud-table-head .mud-table-cell {
    background-color: var(--knsoft-grid-header-bg);
    font-size: var(--knsoft-font-size-sm);
    font-weight: 600;
    white-space: nowrap;
}

/* ----- Dense Rows ----- */
.knsoft-datagrid.dense .mud-table-row {
    height: var(--knsoft-grid-dense-row-height);
}

/* ----- Row Hover ----- */
.knsoft-datagrid .mud-table-body .mud-table-row:hover {
    background-color: var(--knsoft-grid-row-hover-bg);
}

/* ----- Toolbar inside DataGrid ----- */
.knsoft-datagrid__toolbar {
    display: flex;
    align-items: center;
    gap: var(--knsoft-space-2);
    padding: var(--knsoft-space-2) var(--knsoft-space-3);
    border-bottom: 1px solid var(--mud-palette-lines-default);
    flex-wrap: wrap;
}

/* ----- Responsive: horizontal scroll on small screens ----- */
@media (max-width: 768px) {
    .knsoft-datagrid {
        overflow-x: auto;
    }
}

/* ----- Empty State inside grid ----- */
.knsoft-money {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    white-space: nowrap;
}

.knsoft-money--paid {
    color: var(--mud-palette-success);
}

.knsoft-money--debt {
    color: var(--mud-palette-error);
}

.knsoft-row-actions {
    display: flex;
    align-items: center;
    gap: 2px;
    white-space: nowrap;
    opacity: 0.72;
    transition: opacity 0.12s ease;
}

.knsoft-datagrid .mud-table-body .mud-table-row:hover .knsoft-row-actions,
.knsoft-datagrid .mud-table-body .mud-table-row:focus-within .knsoft-row-actions {
    opacity: 1;
}

.knsoft-row-actions .mud-button-root {
    min-width: 0;
    height: 28px;
    padding: 0 6px;
}

.knsoft-row-draft {
    background-color: color-mix(in srgb, var(--mud-palette-warning) 7%, transparent);
}

.knsoft-row-debt {
    background-color: color-mix(in srgb, var(--mud-palette-error) 5%, transparent);
}

.knsoft-bulkbar {
    display: flex;
    align-items: center;
    gap: var(--knsoft-space-2);
    padding: 6px 12px;
    margin: 0;
    background: color-mix(in srgb, var(--mud-palette-primary) 8%, var(--mud-palette-surface));
    border-bottom: 1px solid var(--mud-palette-divider);
    font-size: 0.875rem;
}

/* ----- Empty State inside grid ----- */
.knsoft-datagrid__empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: var(--knsoft-space-8);
    gap: var(--knsoft-space-3);
    color: var(--mud-palette-text-secondary);
}

.knsoft-grid-skeleton {
    padding: 8px 12px 16px;
}

.knsoft-grid-skeleton__row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--mud-palette-divider);
}

.knsoft-grid-skeleton__cell {
    height: 14px;
    flex: 0 0 auto;
}

.knsoft-grid-skeleton__cell--check {
    width: 18px;
    height: 18px;
    border-radius: 4px;
}

.knsoft-datagrid .sticky-left,
.knsoft-datagrid .sticky-right {
    background-color: var(--mud-palette-surface);
    z-index: 2;
}

.knsoft-datagrid .sticky-left {
    box-shadow: 4px 0 8px -4px rgba(15, 23, 42, 0.18);
}

.knsoft-datagrid .sticky-right {
    box-shadow: -4px 0 8px -4px rgba(15, 23, 42, 0.18);
}

.knsoft-datagrid .mud-table-head .sticky-left,
.knsoft-datagrid .mud-table-head .sticky-right {
    background-color: var(--knsoft-grid-header-bg);
    z-index: 4;
}

.knsoft-datagrid .mud-table-body .mud-table-row:hover .sticky-left,
.knsoft-datagrid .mud-table-body .mud-table-row:hover .sticky-right {
    background-color: var(--knsoft-grid-row-hover-bg);
}

.knsoft-datagrid .mud-table-body .mud-table-row.knsoft-row-debt .sticky-left,
.knsoft-datagrid .mud-table-body .mud-table-row.knsoft-row-debt .sticky-right {
    background-color: color-mix(in srgb, var(--mud-palette-error) 5%, var(--mud-palette-surface));
}

.knsoft-datagrid .mud-table-body .mud-table-row.knsoft-row-draft .sticky-left,
.knsoft-datagrid .mud-table-body .mud-table-row.knsoft-row-draft .sticky-right {
    background-color: color-mix(in srgb, var(--mud-palette-warning) 7%, var(--mud-palette-surface));
}

.knsoft-link-button {
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    color: var(--mud-palette-primary);
    cursor: pointer;
    font: inherit;
    text-align: left;
}

.knsoft-link-button:hover {
    text-decoration: underline;
}

.knsoft-peek-drawer.mud-drawer {
    display: flex;
    flex-direction: column;
    max-width: 100vw;
}

.knsoft-peek-drawer-body {
    flex: 1 1 auto;
    overflow-y: auto;
}

.knsoft-peek-drawer-footer {
    flex: 0 0 auto;
    border-top: 1px solid var(--mud-palette-lines-default);
}

@media (max-width: 600px) {
    .knsoft-peek-drawer.mud-drawer {
        width: 100vw !important;
    }
}

/* Compact pager — 40px, khớp AppBar/search row. */
.knsoft-datagrid .mud-table-pagination {
    min-height: 40px;
    overflow: hidden;
}

.knsoft-datagrid .mud-table-pagination-toolbar {
    min-height: 40px;
    height: 40px;
    padding: 0 8px;
    background: var(--mud-palette-surface);
    border-top: 1px solid var(--mud-palette-divider);
}

.knsoft-datagrid .mud-table-pagination .mud-input-control {
    margin-top: 0;
    margin-bottom: 0;
}

.knsoft-datagrid .mud-table-pagination-caption,
.knsoft-datagrid .mud-table-pagination .mud-typography {
    font-size: 0.8125rem;
}

.knsoft-datagrid .mud-table-pagination-actions .mud-button-root,
.knsoft-datagrid .mud-table-pagination-actions .mud-icon-button {
    width: 32px;
    height: 32px;
}

/* Màn hẹp: MudBlazor xuống dòng pager (ô số dòng / caption / nút trang) — bỏ chiều cao cố định 40px,
   nếu không hàng nút chuyển trang bị overflow:hidden cắt mất. */
@media (max-width: 600px) {
    .knsoft-datagrid .mud-table-pagination,
    .knsoft-datagrid .mud-table-pagination-toolbar {
        height: auto;
        overflow: visible;
        flex-wrap: wrap;
        padding-top: 4px;
        padding-bottom: 4px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .knsoft-row-actions {
        transition: none;
    }
}

/* [Migration T005-TEST-02] Cột đầu cố định cho MudTable thường (StockMatrixReport dùng class này; SOURCE dùng nhưng KHÔNG định nghĩa
   ⇒ cột "Mã hàng" trôi theo khi cuộn ngang). Cùng kiểu với .sticky-left của lưới dữ liệu. */
.knsoft-sticky-left {
    position: sticky;
    left: 0;
    z-index: 2;
    background-color: var(--mud-palette-surface);
    box-shadow: 4px 0 8px -4px rgba(15, 23, 42, 0.18);
}

.mud-table-head .knsoft-sticky-left {
    z-index: 4;
}

/* ---- _dialog.css ---- */
/* ============================================================
   KNSoft ERP — Dialog
   Chuẩn hóa MudDialog.
   ============================================================ */

/* ----- Default Widths ----- */
.knsoft-dialog-sm  { max-width: 480px;  width: 100%; }
.knsoft-dialog-md  { max-width: 720px;  width: 100%; }
.knsoft-dialog-lg  { max-width: 960px;  width: 100%; }
.knsoft-dialog-xl  { max-width: 1200px; width: 100%; }
.knsoft-dialog-full{ width: 98vw; max-width: 98vw; }

/* ----- Header ----- */
.knsoft-dialog .mud-dialog-title {
    font-size: var(--knsoft-font-size-lg);
    font-weight: 600;
    padding: var(--knsoft-space-4) var(--knsoft-space-6);
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

/* ----- Content ----- */
.knsoft-dialog .mud-dialog-content {
    padding: var(--knsoft-space-4) var(--knsoft-space-6);
}

/* ----- Actions (footer) — buttons right-aligned ----- */
.knsoft-dialog .mud-dialog-actions {
    padding: var(--knsoft-space-3) var(--knsoft-space-6);
    border-top: 1px solid var(--mud-palette-lines-default);
    justify-content: flex-end;
    gap: var(--knsoft-space-2);
}

/* ============================================================
   Chiều cao CỐ ĐỊNH cho dialog có tab / nội dung đổi kích thước
   ------------------------------------------------------------
   Vấn đề: .mud-dialog cao theo nội dung ⇒ dialog nhiều tab (DialogCustomerDetail 5 tab,
   DialogProductDetail…) nhảy chiều cao mỗi lần bấm tab, và nhảy lần nữa khi skeleton
   "đang tải" đổi sang nội dung thật. Chiều rộng không nhảy (BaseDialogOptions /
   StandardDialogOptions đều FullWidth=true ⇒ rộng = min(MaxWidth, 100% - 64px)).

   Cách sửa: khoá chiều cao theo cỡ dialog; phần thân tự cuộn bên trong.
   Áp dụng khi:
     (a) dialog đặt class knsoft-dialog-fixed trên <MudDialog Class="...">  — opt-in, dùng
         cho dialog có trạng thái loading trước khi hiện tab (nếu không, lúc tải vẫn nhảy);
     (b) TỰ ĐỘNG khi thân dialog có MudTabs là con trực tiếp.
   Không áp dụng cho dialog FullScreen.
   ============================================================ */

/* Chiều cao theo cỡ (đọc từ class width MudBlazor sinh ra). min(…dvh) để màn thấp vẫn vừa. */
.mud-dialog {
    --knsoft-dialog-fixed-height: min(80dvh, 720px);
}
.mud-dialog.mud-dialog-width-xs,
.mud-dialog.mud-dialog-width-sm {
    --knsoft-dialog-fixed-height: min(70dvh, 560px);
}
.mud-dialog.mud-dialog-width-lg,
.mud-dialog.mud-dialog-width-xl,
.mud-dialog.mud-dialog-width-xxl,
.mud-dialog.mud-dialog-width-false {
    --knsoft-dialog-fixed-height: min(85dvh, 860px);
}

/* Class Razor đặt trên <MudDialog Class> có thể nằm ở chính .mud-dialog hoặc phần tử con —
   bắt cả hai để không phụ thuộc chi tiết render của MudBlazor. */
.mud-dialog:not(.mud-dialog-fullscreen).knsoft-dialog-fixed,
.mud-dialog:not(.mud-dialog-fullscreen):has(.knsoft-dialog-fixed),
.mud-dialog:not(.mud-dialog-fullscreen):has(.mud-dialog-content > .mud-tabs) {
    height: var(--knsoft-dialog-fixed-height);
}

/* Thân dialog: thanh cuộn không làm nội dung co/giãn ngang khi tab ngắn ↔ tab dài. */
.mud-dialog:not(.mud-dialog-fullscreen).knsoft-dialog-fixed .mud-dialog-content,
.mud-dialog:not(.mud-dialog-fullscreen):has(.knsoft-dialog-fixed) .mud-dialog-content,
.mud-dialog:not(.mud-dialog-fullscreen):has(.mud-dialog-content > .mud-tabs) .mud-dialog-content {
    min-height: 0;
    scrollbar-gutter: stable;
}

/* Khi MudTabs là nội dung DUY NHẤT của thân: giữ thanh tab đứng yên, chỉ vùng panel cuộn.
   (Có khối khác cạnh MudTabs — vd DialogProductDetail có phần đầu — thì cả thân cuộn như thường.) */
.mud-dialog:not(.mud-dialog-fullscreen) .mud-dialog-content:has(> .mud-tabs:only-child) {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.mud-dialog:not(.mud-dialog-fullscreen) .mud-dialog-content > .mud-tabs:only-child {
    flex: 1 1 auto;
    min-height: 0;
}
.mud-dialog:not(.mud-dialog-fullscreen) .mud-dialog-content > .mud-tabs:only-child > .mud-tabs-panels {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    scrollbar-gutter: stable;
}

/* Trong dialog đã khoá chiều cao, khung cuộn riêng (vd EntityHistoryDialog, max-height 640px)
   thành cuộn lồng hai tầng và chừa khoảng trống dưới ⇒ để thân dialog cuộn thay. */
.mud-dialog.knsoft-dialog-fixed .knsoft-history-scroll,
.mud-dialog:has(.knsoft-dialog-fixed) .knsoft-history-scroll {
    max-height: none;
    overflow-y: visible;
}

/* ----- Loading Overlay inside Dialog ----- */
.knsoft-dialog__loading {
    position: absolute;
    inset: 0;
    background: color-mix(in srgb, var(--mud-palette-surface) 78%, transparent);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10;
    border-radius: var(--knsoft-radius-md);
}

.knsoft-loading-page {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--knsoft-space-3);
    min-height: 240px;
    padding: var(--knsoft-space-8);
}

/* ============================================================
   Dialogs/Base/BaseDialog.razor — khung dialog dùng chung
   ============================================================ */

/* Thân dialog cần position:relative để MudOverlay Absolute="true" của chế độ IsBusy
   phủ đúng phạm vi thân (mặc định overlay absolute sẽ bám viewport/dialog gần nhất
   có position — thiếu dòng này thì lớp mờ trùm cả trang, không chỉ trong dialog). */
.knsoft-base-dialog .mud-dialog-content {
    position: relative;
}

/* Vùng nhận bàn phím (Esc = đóng, Ctrl+Enter = lưu) — cần focus được nhưng KHÔNG
   được vẽ viền focus, vì đây là vùng bao ngoài chứ không phải control người dùng bấm. */
.knsoft-base-dialog-body {
    outline: none;
}

/* Khi IsBusy: nội dung vẫn hiện dưới lớp mờ nhưng không bấm được.
   pointer-events:none chặn tương tác; opacity làm nó lùi lại phía sau về mặt thị giác
   để nổi bật vòng xoay tiến trình. */
.knsoft-base-dialog-disabled {
    pointer-events: none;
    opacity: .6;
    transition: opacity .15s ease;
}

/* ============================================================
   Dialogs/Picker/BasePickerDialog.razor
   ============================================================ */

.knsoft-picker-list {
    /* Danh sách ứng viên dài (chọn khách hàng, serial…) — cuộn trong dialog thay vì
       đẩy dialog cao mãi. max-height do markup đặt 420px, ở đây chỉ lo phần nhìn. */
    border-radius: var(--knsoft-radius-sm);
}

/* Một dòng ứng viên. Border trong suốt để khi hover/được chọn không nhảy layout
   (nếu dùng border khi-selected thì dòng sẽ dày lên 1px và cả danh sách giật). */
.knsoft-picker-item {
    cursor: pointer;
    border-radius: var(--knsoft-radius-sm);
    border: 1px solid transparent;
    transition: background-color .15s ease, border-color .15s ease;
}

.knsoft-picker-item:hover {
    background-color: var(--mud-palette-action-default-hover);
    border-color: var(--mud-palette-lines-default);
}

/* Dòng đang chọn: dùng viền + nền nhấn thay vì chỉ đổi elevation, vì elevation
   trong danh sách dày rất khó nhận ra. */
.knsoft-picker-item.mud-theme-primary {
    border-color: var(--mud-palette-primary);
    background-color: rgba(var(--mud-palette-primary-rgb), .08);
}

/* ============================================================
   Dialogs/Components/LoadingDialog.razor
   ============================================================ */

/* Dialog chờ không có nút và không có tiêu đề ⇒ MudBlazor vẫn chừa padding mặc định
   khá lớn ở đầu/cuối. Thu lại cho gọn để hộp chờ đúng bằng nội dung. */
.knsoft-loading-dialog .mud-dialog-content {
    padding: var(--knsoft-space-2) var(--knsoft-space-4);
}

/* Không cho bấm ra ngoài để đóng trong lúc đang chờ: chặn luôn tương tác với nền. */
.knsoft-loading-dialog .mud-dialog-title {
    display: none;
}

/* ----- Khung nội dung có thể cuộn ----- */
.knsoft-history-scroll {
    max-height: min(70vh, 640px);
    overflow-y: auto;
}

/* ----- Khung PDF trong dialog ----- */
.knsoft-pdf-frame {
    width: 100%;
    height: 75vh;
}

/* ----- Text lỗi nhiều dòng ----- */
.knsoft-error-text {
    white-space: pre-line;
    max-height: 320px;
    overflow-y: auto;
    display: block;
}

/* ----- Overlay chặn tương tác khi đang tải ----- */
.knsoft-loading-blocked {
    pointer-events: none;
}

/* ---- _form.css ---- */
/* ============================================================
   KNSoft ERP — Forms
   FormContainer, FormSection, FormRow, FormActions.
   ============================================================ */

/* ----- Form Container ----- */
.knsoft-form {
    display: flex;
    flex-direction: column;
    gap: var(--knsoft-space-6);
}

/* ----- Form Section ----- */
.knsoft-form-section {
    display: flex;
    flex-direction: column;
    gap: var(--knsoft-space-4);
}

.knsoft-form-section__title {
    font-size: var(--knsoft-font-size-sm);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--mud-palette-text-secondary);
    padding-bottom: var(--knsoft-space-2);
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

/* ----- Form Row — responsive columns ----- */
.knsoft-form-row {
    display: grid;
    gap: var(--knsoft-space-4);
    align-items: start;
}

.knsoft-form-row--cols-1 { grid-template-columns: 1fr; }
.knsoft-form-row--cols-2 { grid-template-columns: repeat(2, 1fr); }
.knsoft-form-row--cols-3 { grid-template-columns: repeat(3, 1fr); }
.knsoft-form-row--cols-4 { grid-template-columns: repeat(4, 1fr); }

@media (max-width: 768px) {
    .knsoft-form-row--cols-2,
    .knsoft-form-row--cols-3,
    .knsoft-form-row--cols-4 {
        grid-template-columns: 1fr;
    }
}

@media (min-width: 769px) and (max-width: 1024px) {
    .knsoft-form-row--cols-4 { grid-template-columns: repeat(2, 1fr); }
    .knsoft-form-row--cols-3 { grid-template-columns: repeat(2, 1fr); }
}

/* ----- Form Actions ----- */
.knsoft-form__actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--knsoft-space-2);
    padding-top: var(--knsoft-space-4);
    border-top: 1px solid var(--mud-palette-lines-default);
    flex-wrap: wrap;
}

/* ----- Required field indicator ----- */
.knsoft-required::after {
    content: " *";
    color: var(--mud-palette-error);
}

/* ----- Quantity stepper (KNSoftQuantityStepper) ----- */
.qty-stepper {
    display: inline-flex;
    align-items: center;
    height: 36px;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 18px;
    overflow: hidden;
    background: var(--mud-palette-surface);
}

.qty-stepper__btn.mud-icon-button {
    width: 36px;
    height: 36px;
    border-radius: 0;
    padding: 0;
}

.qty-stepper__btn.mud-icon-button:hover {
    background: var(--mud-palette-action-default-hover);
}

.qty-stepper__input {
    width: 48px;
    flex-shrink: 0;
}

.qty-stepper__input .mud-input {
    min-height: 36px;
}

.qty-stepper__input .mud-input-slot {
    padding: 0;
}

.qty-stepper__input input {
    text-align: center;
    font-weight: 600;
    padding: 0;
}

.qty-stepper__hint {
    font-size: var(--knsoft-font-size-xs); /* tối thiểu 12px cho dễ đọc */
    line-height: 1.2;
    color: var(--mud-palette-text-secondary);
    margin-top: 2px;
}

.knsoft-file-picker__upload {
    position: relative;
    display: inline-flex;
    cursor: pointer;
}

.knsoft-file-picker__native {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
    width: 100%;
    height: 100%;
}

/* ---- _animation.css ---- */
/* ============================================================
   KNSoft ERP — Animations & Transitions
   ============================================================ */

/* ----- Fade In ----- */
@keyframes knsoft-fadeIn {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: translateY(0); }
}

.knsoft-fade-in {
    animation: knsoft-fadeIn 0.2s ease forwards;
}

/* ----- Slide In from Right ----- */
@keyframes knsoft-slideInRight {
    from { opacity: 0; transform: translateX(16px); }
    to   { opacity: 1; transform: translateX(0); }
}

.knsoft-slide-in-right {
    animation: knsoft-slideInRight 0.2s ease forwards;
}

/* ----- Pulse (loading indicator) ----- */
@keyframes knsoft-pulse {
    0%, 100% { opacity: 1; }
    50%       { opacity: 0.4; }
}

.knsoft-pulse {
    animation: knsoft-pulse 1.5s ease-in-out infinite;
}

/* ----- Skeleton shimmer ----- */
@keyframes knsoft-shimmer {
    0%   { background-position: -200% 0; }
    100% { background-position: 200% 0; }
}

.knsoft-skeleton {
    background: linear-gradient(
        90deg,
        color-mix(in srgb, var(--mud-palette-text-primary) 6%, transparent) 25%,
        color-mix(in srgb, var(--mud-palette-text-primary) 12%, transparent) 50%,
        color-mix(in srgb, var(--mud-palette-text-primary) 6%, transparent) 75%
    );
    background-size: 200% 100%;
    animation: knsoft-shimmer 1.4s ease infinite;
    border-radius: var(--knsoft-radius-sm);
}

/* ----- Standard transitions ----- */
.knsoft-transition {
    transition: all 0.2s ease;
}

/* ---- _searchdrawer.css ---- */
/* KNSoftSearchPanel: thanh trigger gọn (thay MudExpansionPanel cũ) + Drawer chứa field lọc. */

.knsoft-search-panel {
    margin-bottom: 0;
}

.knsoft-search-trigger {
    display: flex;
    align-items: center;
    cursor: pointer;
    min-height: 40px;
    margin-bottom: var(--knsoft-space-2);
    border-radius: var(--knsoft-radius-md);
    border: 1px solid var(--mud-palette-lines-default);
    background-color: var(--mud-palette-surface);
    transition: background-color 0.15s ease;
}

/* ----- QuickFilter: một dải lọc sát lưới, không card lồng ô Outlined -----
   Trước đây padding 12/16 + border + shadow tạo "hòn đảo" tách khỏi lưới
   và viền đôi với MudTextField Outlined bên trong. */
.knsoft-search-panel:has(.knsoft-search-quickbar) {
    background-color: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--knsoft-radius-md);
}

.knsoft-search-quickbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--knsoft-space-2);
    padding: 6px 8px;
    margin: 0;
    background: transparent;
    border: none;
    border-radius: 0;
    box-shadow: none;
}

.knsoft-search-quick-filter {
    flex: 1 1 220px;
    min-width: 220px;
}

.knsoft-search-quick-filter .mud-input-control {
    margin-top: 0;
    margin-bottom: 0;
}

/* Helper rỗng của MudTextField chiếm ~19px dưới ô — bỏ để hàng nút khớp cao. */
.knsoft-search-quick-filter .mud-input-control-helper-container {
    display: none;
}

/* Bỏ viền Outlined lồng trong thanh: nền nhạt, focus mới hiện 1px primary. */
.knsoft-search-quick-filter .mud-input-outlined {
    background-color: var(--mud-palette-background-grey, rgba(15, 23, 42, 0.04));
    border-radius: var(--knsoft-radius-sm);
}

.knsoft-search-quick-filter .mud-input-outlined .mud-input-outlined-border {
    border-color: transparent !important;
}

.knsoft-search-quick-filter .mud-input:hover .mud-input-outlined-border {
    border-color: transparent !important;
}

.knsoft-search-quick-filter .mud-input:focus-within .mud-input-outlined-border {
    border-color: var(--mud-palette-primary) !important;
    border-width: 1px !important;
}

.knsoft-search-quick-actions {
    display: flex;
    align-items: center;
    gap: var(--knsoft-space-1);
    flex: 0 0 auto;
    flex-wrap: wrap;
}

.knsoft-search-pills {
    display: flex;
    align-items: center;
    gap: var(--knsoft-space-1);
    flex-wrap: wrap;
}

.knsoft-filter-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 36px;
    padding: 0 12px;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 999px;
    background: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    font-size: 0.8125rem;
    line-height: 1;
    cursor: pointer;
    white-space: nowrap;
    transition: border-color 0.12s ease, background-color 0.12s ease, color 0.12s ease;
}

.knsoft-filter-pill:hover {
    border-color: var(--mud-palette-primary);
}

@media (prefers-reduced-motion: reduce) {
    .knsoft-filter-pill {
        transition: none;
    }
}

.knsoft-filter-pill--on {
    border-color: var(--mud-palette-primary);
    background: color-mix(in srgb, var(--mud-palette-primary) 12%, var(--mud-palette-surface));
    color: var(--mud-palette-primary);
    font-weight: 600;
}

.knsoft-search-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--knsoft-space-2);
    padding: 0 8px 8px;
}

.knsoft-search-chips:not(:has(*)) {
    display: none;
    padding: 0;
}

.knsoft-search-chips__clear {
    margin-left: auto;
}

.knsoft-search-quickbar .mud-button {
    height: 36px;
    min-height: 36px;
}

.knsoft-search-quickbar .mud-chip {
    height: 20px;
    min-height: 20px;
}

/* Dính thanh lọc vào KNSoftDataGrid kế bên thành một mặt. */
.knsoft-search-panel:has(.knsoft-search-quickbar):has(+ .knsoft-datagrid) {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
    border-bottom-color: var(--mud-palette-divider);
}

.knsoft-search-panel:has(.knsoft-search-quickbar) + .knsoft-datagrid {
    border-top-left-radius: 0;
    border-top-right-radius: 0;
    box-shadow: var(--knsoft-shadow-card);
}

.knsoft-search-panel:has(.knsoft-search-quickbar) + .knsoft-datagrid .mud-paper {
    border-top-left-radius: 0;
    border-top-right-radius: 0;
    box-shadow: none;
}

.knsoft-search-panel:has(.knsoft-search-quickbar) + .knsoft-datagrid .knsoft-datagrid__toolbar {
    padding: 2px 8px;
    min-height: 0;
    border-bottom: none;
}

.knsoft-search-trigger:hover,
.knsoft-search-trigger:focus-visible {
    background-color: var(--mud-palette-action-default-hover);
    outline: none;
}

.knsoft-search-drawer.mud-drawer {
    display: flex;
    flex-direction: column;
    max-width: 100vw;
}

/* Inside the 420px drawer, MudGrid items use viewport-based breakpoints (md-3/4, sm-4)
   that shrink fields to ~100-140px — labels wrap, date pickers overflow.
   Force full-width items inside the drawer: 2 classes > 1 class, so this wins
   over .mud-grid-item-md-3/4/sm-4. */
.knsoft-search-drawer .mud-grid-item {
    max-width: 100%;
    flex-basis: 100%;
}

.knsoft-search-drawer-body {
    flex: 1 1 auto;
    overflow-y: auto;
}

.knsoft-search-drawer-footer {
    flex: 0 0 auto;
    border-top: 1px solid var(--mud-palette-lines-default);
}

@media (max-width: 600px) {
    .knsoft-search-drawer.mud-drawer {
        width: 100vw !important;
    }
}

/* ---- _print.css ---- */
/* ============================================================
   KNSoft ERP — Print Layout
   ============================================================ */

@media print {
    /* Ẩn navigation, sidebar, toolbar */
    .mud-appbar,
    .mud-drawer,
    .knsoft-page-toolbar,
    .knsoft-search-panel,
    .mud-snackbar-location,
    .no-print {
        display: none !important;
    }

    /* Reset main content */
    .mud-main-content {
        padding: 0 !important;
        margin: 0 !important;
    }

    body {
        font-size: var(--knsoft-print-font-size);
        background: white;
        color: black;
    }

    /* Đảm bảo table không bị cắt qua trang */
    table {
        page-break-inside: auto;
    }
    tr {
        page-break-inside: avoid;
        page-break-after: auto;
    }

    /* Print header */
    .knsoft-print-header {
        height: var(--knsoft-print-header-height);
        display: flex;
        align-items: center;
        justify-content: space-between;
        border-bottom: 2px solid black;
        margin-bottom: 16px;
        padding-bottom: 8px;
    }
}


/* ----- Utility overrides (không thuộc MudBlazor) ----- */

/* Remove uppercase từ tất cả MudButton trong app */
.mud-button-root {
    text-transform: none;
}

/* ----- Chuyển động mượt cho các thành phần tương tác -----
   MudBlazor mặc định đổi màu/trạng thái tức thì (0ms), tạo cảm giác "giật".
   Thêm transition ngắn (150-180ms) cho các thuộc tính hay đổi khi hover/focus/click. */
.mud-button-root,
.mud-icon-button,
.mud-chip,
.mud-input-control,
.mud-nav-link,
.mud-table-row,
.mud-list-item,
.mud-tab {
    transition: background-color .15s ease, color .15s ease, border-color .15s ease,
                box-shadow .18s ease, transform .1s ease;
}

.mud-button-root:active,
.mud-icon-button:active {
    transform: scale(0.97);
}

@media (prefers-reduced-motion: reduce) {
    .mud-button-root:active,
    .mud-icon-button:active,
    a.knsoft-stat-card:hover,
    .knsoft-card[data-clickable="true"]:hover {
        transform: none;
    }

    .mud-popover,
    .mud-dialog {
        animation: none;
    }
}

.mud-button-root:focus-visible,
.mud-icon-button:focus-visible,
.mud-nav-link:focus-visible,
.mud-list-item:focus-visible,
.mud-input-control:focus-within .mud-input-outlined-border {
    outline: 2px solid color-mix(in srgb, var(--mud-palette-primary) 70%, white);
    outline-offset: 1px;
}

/* Card/Paper: hover nâng nhẹ cho khối có thể tương tác (stat card, list card) */
.knsoft-card,
.knsoft-stat-card,
.mud-card {
    transition: box-shadow .2s ease, transform .2s ease;
}

a.knsoft-stat-card:hover,
.knsoft-card[data-clickable="true"]:hover {
    box-shadow: var(--knsoft-shadow-dialog);
    transform: translateY(-2px);
}

/* Dropdown/menu/dialog xuất hiện mượt hơn thay vì bật tức thì */
.mud-popover,
.mud-dialog {
    animation: knsoft-fadeIn .16s ease forwards;
}

/* Chuẩn hóa scrollbar — 10px: app nhiều bảng cuộn ngang/dọc, 6px quá mảnh để kéo bằng chuột.
   scrollbar-width/color cho Firefox (không hiểu ::-webkit-scrollbar). */
html {
    scrollbar-width: thin;
    scrollbar-color: var(--mud-palette-gray-dark) transparent;
}
::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}
::-webkit-scrollbar-track {
    background: transparent;
}
::-webkit-scrollbar-thumb {
    background: var(--mud-palette-lines-inputs);
    border-radius: 5px;
    border: 2px solid transparent;
    background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover {
    background: var(--mud-palette-gray-dark);
}
