﻿/* PNT_CRM - style nền dùng chung (MudBlazor lo phần component) */

html, body {
    margin: 0;
    height: 100%;
}

/* Viền phân tách nhẹ cho appbar + drawer (theme nền trắng) */
.pnt-appbar {
    border-bottom: 1px solid #E0E6EB;
}

.pnt-drawer {
    border-right: 1px solid #E0E6EB;
}

.pnt-navmenu .mud-nav-link {
    font-size: 14px;
}

.pnt-nut-user:hover {
    background: rgba(21, 101, 192, 0.06);
}

/* ============================================================
   APPBAR — khối logo + người dùng
   MudBlazor ép .mud-toolbar cao CỨNG (52,5px dưới 600px / 60px từ 600px),
   nên mọi nội dung dài phải tự cắt: cấm xuống dòng + overflow:hidden,
   nếu không chữ tràn ra ngoài nền appbar (lỗi đã gặp trên điện thoại).
   ============================================================ */
.pnt-appbar .mud-toolbar {
    overflow: hidden;
}

.pnt-logo {
    height: 38px;
    flex: 0 0 auto;
}

.pnt-nut-user {
    min-width: 0;
}

.pnt-user-chu {
    min-width: 0;
    text-align: left;
    line-height: 1.15;
}

.pnt-ten-user {
    font-size: 13.5px;
    font-weight: 600;
}

.pnt-vaitro-user {
    font-size: 11.5px;
    color: var(--mud-palette-text-secondary);
}

.pnt-user-chu .pnt-ten-user,
.pnt-user-chu .pnt-vaitro-user {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Chip vai trò viết tắt — ngược với .pnt-user-chu: CHỈ hiện khi màn hẹp */
.pnt-vaitro-ngan {
    display: none;
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
    white-space: nowrap;
    padding: 3px 6px;
    border-radius: 10px;
    color: var(--mud-palette-primary);
    background: rgba(21, 101, 192, 0.10);
}

/* Tên đầy đủ lặp lại ở đầu menu xổ xuống — chỉ dùng khi màn hẹp đã ẩn chữ trên appbar */
.pnt-user-dau-menu {
    display: none;
    padding: 8px 16px 10px 16px;
    border-bottom: 1px solid var(--mud-palette-divider);
    line-height: 1.25;
    max-width: 240px;
}

/* ============================================================
   NỘI DUNG CHÍNH
   Chừa đúng chiều cao appbar THẬT của từng cỡ màn (MudBlazor đổi theo
   breakpoint) + khoảng thở. Trước đây đặt cứng 80px nên trên điện thoại
   thừa ~27px trong khi appbar chỉ cao 52,5px.
   ============================================================ */
.pnt-noi-dung {
    padding-left: 20px;
    padding-right: 20px;
    padding-bottom: 20px;
    padding-top: calc(var(--mud-appbar-height) - var(--mud-appbar-height) / 8 + 20px);
}

@media (min-width: 0px) and (orientation: landscape) {
    .pnt-noi-dung {
        padding-top: calc(var(--mud-appbar-height) - var(--mud-appbar-height) / 4 + 20px);
    }
}

@media (min-width: 600px) {
    .pnt-noi-dung {
        padding-top: calc(var(--mud-appbar-height) + 20px);
    }
}

/* ============================================================
   MÀN HẸP (điện thoại / tablet dọc) — dưới breakpoint Md của drawer
   ============================================================ */

/* Đầu drawer (logo + nút đóng): chỉ có trên màn hẹp, vì ở đó drawer phủ kín
   appbar nên nút hamburger không bấm được nữa. */
.pnt-drawer-dau {
    display: none;
}

/* ⚠️ 959px / 599px là ĐÚNG con số MudBlazor.min.css dùng (drawer overlay: max-width 959px;
   chiều cao appbar: min-width 600px). Đặt lệch (vd 959.98px) sinh dải zoom lẻ mà 2 hệ rule
   bất đồng → drawer phủ appbar nhưng KHÔNG có lớp phủ mờ. Đổi số ở đây thì phải đổi cả
   Breakpoint của MudDrawer và MudHidden trong MainLayout.razor. */
@media (max-width: 959px) {
    /* Drawer trên mobile là lớp phủ dạng modal → phải phủ TOÀN màn hình.
       Mặc định ClipMode.Always của MudBlazor đẩy nó xuống dưới appbar ở MỌI cỡ màn
       (rule .mud-drawer-clipped-always không có media query), khiến appbar bị scrim
       phủ mờ còn drawer thì hụt một khoảng phía trên. */
    .pnt-drawer.mud-drawer-fixed.mud-drawer-responsive.mud-drawer-clipped-always {
        top: 0 !important;
        height: 100% !important;
        border-right: none;
    }

    /* sticky: menu dài hơn màn hình, cuộn xuống vẫn phải với tới được nút đóng */
    .pnt-drawer-dau {
        display: flex;
        align-items: center;
        gap: 8px;
        padding: 8px 16px 8px 16px;
        border-bottom: 1px solid #E0E6EB;
        flex: 0 0 auto;
        position: sticky;
        top: 0;
        z-index: 1;
        background: var(--mud-palette-drawer-background);
    }

    /* vùng chạm tối thiểu 44px theo chuẩn cảm ứng */
    .pnt-drawer-dau .mud-icon-button {
        min-width: 44px;
        min-height: 44px;
    }

    /* Vùng chạm đạt chuẩn ngón tay */
    .pnt-navmenu .mud-nav-link,
    .pnt-nut-user {
        min-height: 44px;
    }
}

@media (max-width: 599px) {
    /* ---- Dialog: MudBlazor chừa 64px lề + 24px padding mỗi bên → máy 360px chỉ còn
       248px nội dung. Thu lề còn 16px và padding còn 12px → 320px (rộng thêm ~29%). ---- */
    .mud-dialog-width-full {
        width: calc(100% - 16px);
    }

    .mud-dialog-width-false,
    .mud-dialog-width-xs,
    .mud-dialog-width-sm,
    .mud-dialog-width-md,
    .mud-dialog-width-lg,
    .mud-dialog-width-xl,
    .mud-dialog-width-xxl {
        max-width: calc(100% - 16px);
    }

    .mud-dialog:not(.mud-dialog-fullscreen) {
        max-height: calc(100% - 16px);
    }

    .mud-dialog .mud-dialog-title {
        padding: 12px 16px;
    }

    .mud-dialog .mud-dialog-title:has(.mud-button-close) {
        padding-inline-end: 52px;
    }

    .mud-dialog .mud-dialog-content {
        padding: 8px 12px;
    }

    .mud-dialog .mud-dialog-actions {
        padding: 8px 12px;
    }

    .pnt-logo {
        height: 30px;
    }

    /* Không đủ chỗ cho tên + vai trò cạnh logo → giữ avatar + chip vai trò viết tắt,
       tên đầy đủ dời vào menu xổ xuống */
    .pnt-user-chu {
        display: none;
    }

    .pnt-vaitro-ngan {
        display: inline-block;
    }

    .pnt-user-dau-menu {
        display: block;
    }

    .pnt-nut-user {
        padding-left: 4px !important;
        padding-right: 4px !important;
    }

    .pnt-noi-dung {
        padding-left: 10px;
        padding-right: 10px;
    }

    /* ⚠️ Quy tắc mobile cho BẢNG không đặt ở đây — rule gốc .bang-khong-xuong-dong nằm
       PHÍA DƯỚI trong file, cùng độ đặc hiệu nên sẽ ghi đè ngược. Xem khối
       "BẢNG TRÊN ĐIỆN THOẠI" đặt ngay sau phần bảng ở cuối file. */

    /* ---- Thanh bộ lọc: các ô đang bị ghim width/max-width cứng bằng px (chuẩn desktop)
       → trên điện thoại cho giãn hết bề ngang thay vì xuống dòng lởm chởm.
       CHỈ nhắm các control NHẬP LIỆU: MudSwitch / MudChip / nút cùng hàng phải giữ nguyên.
       (Có ô dùng max-width chứ không phải width nên cần cả max-width: none.) ---- */
    .pnt-thanh-loc > .mud-input-control,
    .pnt-thanh-loc > .mud-select,
    .pnt-thanh-loc > .mud-autocomplete,
    .pnt-thanh-loc > .mud-picker {
        flex: 1 1 100%;
    }

    /* ⚠️ MudBlazor đổ tham số Style xuống các phần tử KHÁC NHAU tùy component:
       MudTextField → gốc là .mud-input-control, width nằm ở .mud-input BÊN TRONG;
       MudSelect    → gốc là .mud-select, width lại nằm ở .mud-input-control LỒNG BÊN TRONG.
       Vì vậy phải dùng bộ chọn HẬU DUỆ, không phải con trực tiếp, mới nới được cả hai kiểu. */
    .pnt-thanh-loc .mud-input-control,
    .pnt-thanh-loc .mud-select,
    .pnt-thanh-loc .mud-autocomplete,
    .pnt-thanh-loc .mud-picker,
    .pnt-thanh-loc .mud-input {
        width: 100% !important;
        max-width: none !important;
    }
}

/* Máy rất hẹp: form 2 cột trong dialog chỉ còn ~150px/cột (ngày, tiền, tỉ giá đều không đọc nổi)
   → mọi ô xuống 1 cột. CHỈ áp trong dialog, lưới ngoài trang giữ nguyên bố cục tác giả đã chọn. */
@media (max-width: 479px) {
    .mud-dialog .mud-grid-item[class*="mud-grid-item-xs-"] {
        max-width: 100%;
        flex-basis: 100%;
    }
}

/* ============================================================
   CHUẨN INPUT TOÀN HỆ THỐNG (user chốt 15/08/2026):
   MỌI ô nhập cùng loại phải cùng 1 style ở mọi chức năng —
   cỡ chữ 13px cho ô nhập + nhãn + placeholder + item dropdown.
   KHÔNG style cỡ chữ input lẻ tẻ theo từng trang nữa.
   ============================================================ */
.mud-input-root,
.mud-input-root input,
.mud-input-root textarea,
.mud-input-label,
.mud-input-label-inputcontrol,
.mud-input-root input::placeholder {
    font-size: 13px !important;
}

/* Chữ trong danh sách chọn của dropdown/autocomplete đồng bộ với ô input */
.mud-popover .mud-list-item-text .mud-typography {
    font-size: 13px !important;
}

/* ---------- NGOẠI LỆ DUY NHẤT của chuẩn 13px: iOS màn nhỏ (user chốt 15/08) ----------
   Safari trên iPhone tự phóng to cả trang khi focus ô nhập có cỡ chữ < 16px → trang sinh
   cuộn ngang, appbar và nút hamburger bị đẩy ra ngoài tầm nhìn. Không có cách tắt bằng CSS;
   chặn bằng maximum-scale=1 thì cấm luôn zoom bằng ngón tay (hại người dùng khiếm thị).
   Nên nâng 16px ĐÚNG ở nhóm máy bị lỗi — class .pnt-ios-nho do pntCrm.danhDauIosNho() gắn.
   Chỉ nâng phần TỰ GÕ ĐƯỢC (input/textarea/select); nhãn + item dropdown vẫn 13px. */
html.pnt-ios-nho .mud-input-root,
html.pnt-ios-nho .mud-input-root input,
html.pnt-ios-nho .mud-input-root textarea,
html.pnt-ios-nho .mud-input-root select,
html.pnt-ios-nho .mud-input-root input::placeholder,
html.pnt-ios-nho .dn-nhom input {
    font-size: 16px !important;
}

/* Bảng Excel render trong modal xem file (SheetJS sheet_to_html) */
.xem-xlsx table {
    border-collapse: collapse;
    font-size: 12px;
}

.xem-xlsx td {
    border: 1px solid #E0E6EB;
    padding: 2px 8px;
    white-space: nowrap;
}

/* Xem file Word .docx (docx-preview render vào .xem-docx — user yêu cầu 17/08 tối).
   Thư viện tự phát sinh <section class="docx"> mô phỏng TRANG giấy: nền xám quanh trang,
   trang trắng có bóng đổ cho ra dáng Word; ép max-width để trang A4 không tràn ngang modal. */
.xem-docx {
    background: #F1F3F5;
    padding: 12px 0;
}

.xem-docx .docx-wrapper {
    background: transparent;
    padding: 0;
}

.xem-docx section.docx {
    background: #FFFFFF;
    box-shadow: 0 1px 6px rgba(0, 0, 0, .18);
    margin: 0 auto 12px;
    max-width: 100%;
}

/* Ảnh/bảng trong tài liệu không được đẩy rộng quá khung modal */
.xem-docx img {
    max-width: 100%;
    height: auto;
}

.xem-docx table {
    max-width: 100%;
}

/* Sửa nhanh inline bảng DKCP (user chốt 17/08 tối): mọi ô nhập nằm TRÊN 1 HÀNG.
   Dòng thiếu người thụ hưởng theo nhóm (Chi hướng dẫn→HDV, nhóm khác→NCC) tô VÀNG + không cho lưu. */
.dkcp-dong-sua > td {
    vertical-align: middle;
    white-space: nowrap;
}

/* BÓP PADDING Ô XUỐNG TỐI THIỂU (user chốt 20/08: "giảm tối đa padding để tất cả các cột nằm trong
   1 màn hình") — đây là khoản ăn diện tích LỚN NHẤT của bảng sửa nhanh, không phải bề ngang ô nhập.
   ⚠️ 2 điều đã đo được 20/08, đừng làm lại kiểu cũ:
   (1) Rule `.dkcp-dong-sua > td { padding: 4px 6px }` (1 class + 1 thẻ) THUA rule dense của MudBlazor
       nên padding THỰC TẾ vẫn là `6px 16px` = 32px/ô × 19 ô ≈ 608px mỗi hàng. Phải nhắc tới class
       bảng của MudBlazor mới đè được — cùng cách đã dùng cho .dkcp-la-ttcp ở cuối file.
   (2) Phải bóp CẢ hàng tiêu đề (th): bề ngang cột do ô RỘNG NHẤT quyết định, bóp mỗi td mà để th
       nguyên 16px thì bảng không hẹp đi được bao nhiêu. */
.mud-simple-table table tr.dkcp-dong-sua > td,
.mud-table table tr.dkcp-dong-sua > td,
.mud-simple-table table tr.dkcp-tieude-sua > th,
.mud-table table tr.dkcp-tieude-sua > th,
/* 🔴 VÁ 05/09: hàng KHÓA (DkcpDongKhoa — mục đã có phiếu đã thanh toán) cũng nằm trong bảng sửa nhanh
   nên phải bóp y hệt. Thiếu 2 selector này thì hàng khóa rơi về padding dense của MudBlazor (6px 16px):
   mỗi ô rộng thêm 26px × 18 cột ⇒ bảng vượt mốc 1.586px và CUỘN NGANG trở lại — đúng thứ user đã bắt bỏ. */
.mud-simple-table table tr.dkcp-dong-khoa > td,
.mud-table table tr.dkcp-dong-khoa > td {
    padding: 2px 3px;
}

/* Hàng khóa dùng chung bảng `bang-khong-xuong-dong` (nowrap) nên 2 ô CHỮ TỰ DO phải ghim bề ngang,
   không thì cột kéo theo chuỗi dài nhất (DB dev có 27 mục ghi chú >120 ký tự, dài nhất 335). */
.mud-simple-table table tr.dkcp-dong-khoa > td.dkcp-o-chu,
.mud-table table tr.dkcp-dong-khoa > td.dkcp-o-chu {
    max-width: 100px;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ===================== SỬA NHANH DKCP NHÌN NHƯ BẢNG THƯỜNG (user chốt 21/08) =====================
   Yêu cầu: "làm dạng table như hệ thống cũ, đỡ tốn diện tích và dễ nhìn hơn".
   Bản cũ mỗi ô là một KHUNG Outlined + nhãn nổi ⇒ 18 khung trên 1 hàng, rối mắt và tốn cả bề ngang
   lẫn chiều cao. Nay ô nhập dùng Variant.Text + BỎ nhãn (tên cột đã có ở hàng tiêu đề) và ẩn luôn
   gạch chân mặc định ⇒ chữ nằm thẳng trong ô bảng như một dòng dữ liệu bình thường.
   Vẫn phải cho người dùng biết ô GÕ ĐƯỢC: rê chuột vào dòng thì hiện gạch chân mờ, ô đang gõ thì
   có nền nhạt + gạch xanh (gạch xanh là :after sẵn có của MudBlazor, không cần khai lại).
   ⚠️ Lớp mang gạch chân là `.mud-input-underline` (không phải `.mud-input-text`) — đo DOM thật
   20/08: class đầy đủ là "mud-input mud-input-text mud-input-underline …". */
tr.dkcp-dong-sua .mud-input.mud-input-underline:before {
    border-bottom-color: transparent;
}

tr.dkcp-dong-sua:hover .mud-input.mud-input-underline:before {
    border-bottom-color: var(--mud-palette-lines-inputs);
}

tr.dkcp-dong-sua .mud-input.mud-focused {
    background: var(--mud-palette-action-default-hover);
}

/* Không còn nhãn nổi thì bỏ luôn khoảng chừa cho nó — hàng thấp hẳn xuống.
   ⭐ 04/10: bỏ CẢ vế dưới — Margin.Dense của MudBlazor là `margin: 4px 0`, bản cũ chỉ gỡ vế trên nên 4px
   dưới còn lại đẩy cả ô nhập LÊN 2px so với chữ ô thường cùng hàng (xem khối "CHỮ Ô NHẬP THẲNG HÀNG"). */
tr.dkcp-dong-sua .mud-input-control {
    margin-top: 0;
    margin-bottom: 0;
}

/* ----- 4 chỉnh nhỏ theo phản hồi user 21/08 -----
   (a) Tên cột nhỏ hơn chữ trong ô (12px so với 13px) — hàng tiêu đề là nhãn, không phải dữ liệu;
   (b) hàng tiêu đề PHẢI có đường kẻ dọc như hàng dữ liệu: MudBlazor chỉ kẻ cho `td`, `th` để trống
       (đo 21/08: th border-right = 0px, td = 1px) nên nhìn như tên cột trôi tự do phía trên bảng;
   (c) chữ trong ô hạ về 13px cho khớp cỡ chữ của ô nhập (mặc định body1 = 14px, to hơn ô nhập);
   (d) mọi ô DỮ LIỆU căn lề TRÁI — 3 cột tiền đã bỏ text-align:right ở markup.
       ⭐ 28/09: riêng HÀNG TIÊU ĐỀ nay CĂN GIỮA theo luật toàn app (khối "TIÊU ĐỀ BẢNG — CĂN GIỮA
       TOÀN APP" bên dưới) — hàng tiêu đề của bảng này nằm trong <thead> nên bị áp; ô nhập vẫn trái
       nên dáng bảng phẳng giữ nguyên. Đừng "sửa lại" cho khớp câu (d) cũ. */
/* ⚠️ Cỡ chữ PHẢI nhắc tên class bảng của MudBlazor mới đè được: rule của họ là
   `.mud-simple-table table * tr > th` (1 class + 3 thẻ) nên `tr.dkcp-tieude-sua > th` (1 class +
   2 thẻ) THUA — đo 21/08: khai 12px mà chữ vẫn ra 14px, trong khi border-right cùng khối lại ăn
   (vì MudBlazor không khai border cho th). Viền để ở rule ngắn cũng được, cỡ chữ thì không. */
.mud-simple-table table tr.dkcp-tieude-sua > th,
.mud-table table tr.dkcp-tieude-sua > th {
    font-size: 12px;
}

tr.dkcp-tieude-sua > th {
    border-right: 1px solid var(--mud-palette-table-lines);
}

tr.dkcp-tieude-sua > th:last-child {
    border-right: none;
}

/* ⭐ 04/10 (user gửi ảnh bảng Sửa nhanh trên trang booking: "các ô input bị lệch cỡ chữ và padding so
   với những ô khoá"): HÀNG KHÓA (DkcpDongKhoa, có từ 05/09) chưa từng được hạ như câu (c) ⇒ rơi về
   body2 14px của MudBlazor trong khi ô nhập ngay hàng dưới 13px (đo 04/10 trên /booking/1799). */
.mud-simple-table table tr.dkcp-dong-sua > td,
.mud-table table tr.dkcp-dong-sua > td,
.mud-simple-table table tr.dkcp-dong-khoa > td,
.mud-table table tr.dkcp-dong-khoa > td {
    font-size: 13px;
}

/* MudText trong hàng sửa (ô "Tiền" khi đơn vị tiền bị khóa) tự mang body2 14px trên chính nó — không
   ăn cỡ của ô ⇒ "VNĐ" to hơn cả hàng. Cho ăn theo ô. */
tr.dkcp-dong-sua > td > .mud-typography {
    font-size: inherit;
    line-height: inherit;
}

tr.dkcp-dong-sua > td {
    /* Chặn icon/nút trong ô tràn sang cột bên cạnh — biểu tượng lịch từng lấn ~9px sang cột "Số lần",
       nhìn như icon của cột khác (user báo 21/08: "các icon đang lệch hết khỏi các cell của nó"). */
    overflow: hidden;
}

/* Dấu × (bỏ dòng) cuối hàng + dấu × xóa giá trị trong ô: thu nhỏ cho hợp bảng dày đặc */
tr.dkcp-dong-sua .mud-icon-button {
    padding: 1px;
}

/* ⚠️ Thu nút icon xong PHẢI khai lại bề ngang KHUNG CHỨA nó: MudBlazor không tính lại
   `.mud-input-adornment` theo nút đã thu, khung teo còn 8px trong khi nút vẫn 20px ⇒ nút THÒI RA
   ~8px sang cột bên cạnh (đo 21/08: ô "Thời gian" hết ở 997px mà nút lịch nằm 985→1005).
   Đây chính là "icon lệch khỏi cell" user báo. */
tr.dkcp-dong-sua .mud-input-adornment {
    min-width: 20px;
    justify-content: flex-end;
    margin-left: 2px;
}

/* ⚠️ THỦ PHẠM CHÍNH của "icon lệch khỏi cell": MudBlazor đặt `margin-right: -12px` cho nút trong ô
   nhập — âm 12px là để bù đúng phần padding 12-14px của kiểu Outlined, cho icon thẳng mép khung.
   Bảng phẳng này đã hạ padding về 4px nên margin âm đó đẩy nút LÒI HẲN ra ngoài ô (đo 21/08: ô
   "Thời gian" hết ở 997px mà nút lịch nằm 985→1005). Trả margin về 0. */
tr.dkcp-dong-sua .mud-input-adornment .mud-icon-button {
    margin-right: 0;
}

tr.dkcp-dong-sua .mud-icon-button .mud-icon-root {
    font-size: 1.05rem;
}

/* PADDING BÊN TRONG Ô NHẬP (user chốt 20/08: "giảm tối đa padding ở các ô input").
   MudBlazor cho thẻ <input> padding 14px MỖI BÊN — đo 20/08: ô "Số lần" rộng 46px thì 28px là
   padding, chỉ còn 18px cho con số nên "1.00" bị cắt cụt. Hạ xuống 4px là trả lại ~20px/ô × 14 ô
   nhập ≈ 280px cho cả hàng, mà số liệu thì đọc được đầy đủ.
   ⚠️ Chỉ áp TRONG bảng sửa nhanh — form thường vẫn giữ padding chuẩn của dự án.
   ===== CHỮ Ô NHẬP THẲNG HÀNG Ô KHÓA (⭐ 04/10, cùng lượt báo ở khối cỡ chữ phía trên) =====
   (1) TRÁI 0 (không còn 4px): chữ ô nhập bắt đầu ĐÚNG chỗ chữ ô thường — cùng padding ô 3px — thay vì
       thụt vào thêm 4px (đo 04/10: chữ ô nhập cách mép ô 7px, ô khóa / tên cột 3px). Đây cũng là dáng
       chuẩn của Variant.Text (MudBlazor để 0 hai bên). Phải GIỮ 4px bên phải: ngăn chữ với ▾ · × · lịch.
   (2) TRÊN = DƯỚI = 4px (Dense của MudBlazor là 3px trên / 7px dưới): chữ nằm giữa ô như chữ ô thường
       cùng hàng — bản cũ cộng với 4px margin-bottom ở trên làm chữ ô nhập cao hơn ~4px. 4px là padding y
       chuẩn ô nhập toàn app (28/08). Thắng rule dense (0,3,1) của MudBlazor nhờ app.css nạp SAU. */
tr.dkcp-dong-sua .mud-input .mud-input-slot,
tr.dkcp-dong-sua .mud-input-control .mud-input-slot,
tr.dkcp-tieude-sua .mud-input .mud-input-slot {
    padding-left: 0;
    padding-right: 4px;
    padding-top: 4px;
    padding-bottom: 4px;
}

/* Nút icon trong ô nhập (mũi tên xổ · dấu × · biểu tượng lịch) mặc định chiếm 36px. Hạ xuống ~24px
   để phần CHỮ/SỐ có thêm chỗ mà cột KHÔNG phải rộng thêm — vd ô ngày: 54px chữ (cắt mất năm) lên
   ~74px (đủ "20/08/2026"). Vùng chạm vẫn ~24px, chấp nhận được với thao tác chuột trên bảng nhập. */
tr.dkcp-dong-sua .mud-input-adornment .mud-icon-button {
    padding: 1px;
}

tr.dkcp-dong-sua .mud-input-adornment .mud-icon-root {
    font-size: 1.15rem;
}

/* Cột "co giãn" (o-co-gian) có SÀN min-width:220px cho bảng xem thường — trong chế độ sửa thì cái
   sàn đó là khoản phí vô ích: ô nhập NCC/HDV chỉ rộng 138px mà cột vẫn bị giữ 220px (đo 20/08).
   Hạ sàn về 0, GIỮ width:100% để khi bảng đã vừa màn hình thì cột này vẫn hút hết khoảng trống
   thừa (đúng nguyên tắc "đúng 1 cột co giãn" của dự án, chỉ bỏ phần sàn).
   🔴 14/09: HÀNG KHÓA (dkcp-dong-khoa — mục đã có phiếu đã thanh toán) nằm CHUNG bảng với hàng nhập nên
   phải bỏ sàn y hệt: bề ngang cột do ô rộng nhất quyết định, 1 hàng khóa còn giữ 220px là cả cột
   NCC/HDV bị kéo lên 220px. Đo 14/09 trên /booking/1799/chi-phi-du-kien ở viewport 1900: bảng
   scrollWidth 1570 > khung 1566 ⇒ CUỘN NGANG 4px; gỡ sàn thì còn 1566, hết cuộn. (0,2,2) thắng cả rule
   gốc (0,2,1) lẫn khối mobile — không cần !important. */
tr.dkcp-tieude-sua th.o-co-gian,
tr.dkcp-dong-sua td.o-co-gian,
tr.dkcp-dong-khoa td.o-co-gian {
    min-width: 0;
}

.dkcp-dong-loi > td {
    background: #FFF8E1;
}

.dkcp-dong-loi > td:first-child {
    box-shadow: inset 3px 0 0 var(--mud-palette-warning);
}

/* Chip trạng thái booking (TrangThaiBookingChip) */
.ttb-chip {
    display: inline-block;
    font-size: 12px;
    font-weight: 600;
    padding: 2px 10px;
    border-radius: 12px;
    white-space: nowrap;
}

/* Bảng dữ liệu: ô KHÔNG xuống dòng — bảng rộng thì cuộn ngang (đặt overflow-x:auto ở wrapper).
   Mỗi bảng đặt class o-co-gian cho ĐÚNG 1 cột nội dung: cột đó hấp thụ hết khoảng trống thừa
   (hết cảnh trống hoác sau cột cuối) và được phép xuống dòng khi text dài. */
.bang-khong-xuong-dong th,
.bang-khong-xuong-dong td {
    white-space: nowrap;
}

.bang-khong-xuong-dong th.o-co-gian,
.bang-khong-xuong-dong td.o-co-gian {
    white-space: normal;
    width: 100%;
    min-width: 220px;
}

/* MudTable có Breakpoint sẽ chuyển sang chế độ THẺ DỌC ("Nhãn ——— Giá trị") dưới
   ngưỡng của nó. Quy tắc nowrap ở trên phá nát chế độ này (mỗi thẻ rộng hơn màn hình),
   nên trong chế độ thẻ phải trả lại quyền xuống dòng.
   ⚠️ Ngưỡng phải khớp ĐÚNG với MudBlazor.min.css — mỗi lớp một số KHÁC NHAU:
   .mud-xs-table 600px · .mud-sm-table 960px · .mud-md-table 1280px (lg 1920px, chưa dùng).
   Bảng cuộn ngang thông thường (MudSimpleTable) KHÔNG bị ảnh hưởng bởi khối này. */
@media (max-width: 600px) {
    .mud-xs-table.bang-khong-xuong-dong .mud-table-cell { white-space: normal; }
    .mud-xs-table.bang-khong-xuong-dong .mud-table-cell.o-co-gian { width: auto; min-width: 0; }
}

@media (max-width: 960px) {
    .mud-sm-table.bang-khong-xuong-dong .mud-table-cell { white-space: normal; }
    .mud-sm-table.bang-khong-xuong-dong .mud-table-cell.o-co-gian { width: auto; min-width: 0; }
}

@media (max-width: 1280px) {
    .mud-md-table.bang-khong-xuong-dong .mud-table-cell { white-space: normal; }
    .mud-md-table.bang-khong-xuong-dong .mud-table-cell.o-co-gian { width: auto; min-width: 0; }
}

/* ============================================================
   BẢNG TRÊN ĐIỆN THOẠI
   PHẢI nằm SAU khối .bang-khong-xuong-dong ở trên: cùng độ đặc hiệu nên
   rule nào đứng sau thì thắng (đặt ở khối @media phía đầu file sẽ bị ghi đè ngược).
   Giữ nguyên nguyên tắc "không xuống dòng, cuộn ngang" — chỉ hạ sàn cột co giãn
   (220 → 150px) và thu padding ô để lọt thêm 1-2 cột trong khung ~300px.
   ============================================================ */
@media (max-width: 599px) {
    .bang-khong-xuong-dong th.o-co-gian,
    .bang-khong-xuong-dong td.o-co-gian {
        min-width: 150px;
    }

    .bang-khong-xuong-dong th,
    .bang-khong-xuong-dong td {
        padding-left: 8px !important;
        padding-right: 8px !important;
    }

    /* Ghim cột định danh (mã) khi cuộn ngang — CHỈ bảng gắn thêm class pnt-ghim-cot,
       tức bảng có cột ĐẦU là mã ngắn. ⚠️ Selector phải chừa tfoot: dòng tổng dùng
       colspan, ghim vào sẽ kéo cả ô gộp đi theo và vỡ hàng.
       Dùng box-shadow thay border vì .mud-simple-table đặt border-collapse:collapse
       (viền của ô sticky sẽ bị nuốt). */
    .pnt-ghim-cot thead tr > th:first-child,
    .pnt-ghim-cot tbody tr > td:first-child {
        position: sticky;
        left: 0;
        z-index: 1;
        background: var(--mud-palette-surface);
        box-shadow: 1px 0 0 var(--mud-palette-lines-default);
    }

    .pnt-ghim-cot thead tr > th:first-child {
        z-index: 2;
    }
}

/* ============================================================
   CĂN LỀ BẢNG — MỌI Ô CĂN TRÁI TOÀN APP (user chốt 04/10/2026 kèm ảnh /so-thu-chi, nguyên văn:
   "ở tất cả các cột, tên cột không căn giữa nữa mà căn trái, các cell cũng thống nhất căn trái"
   + chọn "Toàn app — thay luật 28/09" ở hộp hỏi phạm vi).
   THAY luật 28/09 "tên các cột ở tất cả các bảng phải thống nhất căn giữa" (tiêu đề giữa, ô dữ liệu
   giữ lề cũ nên tiền nép phải). Nay MỌI ô của MỌI bảng — tiêu đề (thead th), ô dữ liệu (tbody),
   hàng tổng (tfoot) — căn TRÁI, KỂ CẢ cột tiền: số tiền thẳng mép trái với tiêu đề cột của nó.
   Cùng đợt đã gỡ sạch text-align nội tuyến trên <td>/<MudTd> (192 chỗ, 41 file), "text-align:right"
   trong 6 hàm style của ô tiền và 2 rule .stc-cot-tien ⇒ markup không còn nói dối; màn mới CẤM gõ
   lại text-align vào th/td (vô tác dụng + gây hiểu nhầm khi grep).
   ⚠️ !important CỐ Ý, đừng gỡ (cùng lý do bản 28/09): style NỘI TUYẾN thắng mọi rule stylesheet trừ
   !important — thiếu nó, một Style="text-align:right" gõ thêm ở màn mới phá luật âm thầm (không có
   cảnh báo build, chỉ lộ khi nhìn bằng mắt). Nó cũng thắng 2 rule căn giữa có sẵn, nên 2 chỗ đó vào lề
   trái theo luật "mọi ô": ".mud-table-empty-row{text-align:center}" của MudBlazor (câu "không có dữ
   liệu" của MudTable) và ".bcc-bang th, .bcc-bang td" (Bảng chấm công, đã gỡ text-align ở đó).
   Độ đặc hiệu (phòng khi ai đó gỡ !important) — TÍNH CẢ :not(): ".mud-table td:not(.pnt-tu-can)" =
   (0,2,1) thắng ".mud-table-cell" (0,1,0), ".mud-table-empty-row" (0,1,0) và ".mud-simple-table table
   * tr th" (0,1,3) — cột lớp so trước cột thẻ; app.css còn nạp SAU MudBlazor.min.css.
   Chế độ thẻ dọc (Breakpoint) vô can: MudBlazor 9.8 tự đặt ".mud-xs-table .mud-table-cell{display:flex;
   justify-content:space-between;text-align:start !important}" — nhãn trái, giá trị phải là do flex.
   ⚠️ KHÔNG khai thêm padding/width/background/position ở đây: 3 nhóm th sticky
   (.bcc-bang thead th · .pnt-ghim-cot th:first-child · .pnt-ds-cuon thead th) và 36 th
   rỗng ghim width đang phụ thuộc chúng.
   ------------------------------------------------------------
   Lối thoát CÓ CHỦ ĐÍCH: ô (th hoặc td) khai thêm class `pnt-tu-can` thì rule này KHÔNG áp (nằm trong
   `:not()`, không phải một rule ghi đè) ⇒ ô đó theo căn lề nó tự khai. Hiện KHÔNG chỗ nào dùng — muốn
   lệch chuẩn phải hỏi user trước (DECISIONS §9). Thay cho `pnt-th-tu-can` của bản 28/09 (chỉ áp th).
   ⚠️ ĐỪNG làm lối thoát bằng `text-align: revert` — `revert` quay về UA stylesheet mà UA quy định
   `th { text-align: center }`, tức lối thoát đó VÔ TÁC DỤNG (đã thử và bỏ 28/09). */
.mud-table th:not(.pnt-tu-can),
.mud-table td:not(.pnt-tu-can),
.mud-table-root th:not(.pnt-tu-can),
.mud-table-root td:not(.pnt-tu-can),
.mud-simple-table table th:not(.pnt-tu-can),
.mud-simple-table table td:not(.pnt-tu-can),
table.bcc-bang th:not(.pnt-tu-can),
table.bcc-bang td:not(.pnt-tu-can) {
    text-align: left !important;
}

/* ============================================================
   CỘT TIỀN — KHÔNG BAO GIỜ XUỐNG DÒNG (user chốt 28/09/2026:
   "cột nào liên quan đến tiền không được để xuống dòng")
   Nền chung đã có: mọi bảng có tiền đều mang .bang-khong-xuong-dong nên td/th vốn nowrap.
   Class này dành cho 2 ca mà nền chung KHÔNG đỡ được:
     (a) cột tiền lỡ mang .o-co-gian (o-co-gian = white-space:normal để hút chỗ thừa);
     (b) bảng chạy chế độ thẻ dọc (.mud-xs/sm/md-table) — 3 khối @media ở trên CỐ Ý trả
         white-space về normal cho thẻ dọc, (0,3,0), nên rule ở đây khai (0,4,0) để thắng.
   Đặt class cho CẢ th LẪN td của cột đó (cùng khuôn .tdf-sotien / .ktg-sotien sẵn có).
   Nơi đang dùng: KhachTtTheoKyForm (ca a — cột "Đã trả" mang o-co-gian) · QuyetToanHdv
   (ca b — 3 cột tiền của bảng có Breakpoint.Sm). Màn mới có cột tiền rơi vào 2 ca đó thì gắn class,
   đừng rải white-space:nowrap lẻ vào từng helper style.
   ⚠️ PHẢI nằm SAU khối .bang-khong-xuong-dong và SAU 3 khối @media thẻ dọc — cùng độ
   đặc hiệu thì rule đứng sau mới thắng. */
.bang-khong-xuong-dong th.pnt-cot-tien,
.bang-khong-xuong-dong td.pnt-cot-tien,
.mud-xs-table.bang-khong-xuong-dong .mud-table-cell.pnt-cot-tien,
.mud-sm-table.bang-khong-xuong-dong .mud-table-cell.pnt-cot-tien,
.mud-md-table.bang-khong-xuong-dong .mud-table-cell.pnt-cot-tien {
    white-space: nowrap;
}

/* Ô tiền NHIỀU DÒNG (mỗi loại tiền / mỗi vế một dòng) — GOM toàn bộ nội dung ô vào MỘT phần tử
   mang class này. 🔴 Bắt buộc khi bảng có Breakpoint: ở chế độ thẻ dọc MudBlazor đặt
   `.mud-xs|sm|md-table .mud-table-cell { display:flex; justify-content:space-between }` ⇒ nhiều
   `<span class="d-block">` RỜI NHAU trong ô biến thành các FLEX ITEM và nằm NGANG cạnh nhau
   (`display:block` bị blockify vô hiệu trên flex item), chữ tràn khỏi thẻ thay vì xuống dòng.
   Gom lại thì cả khối là 1 flex item, bên trong các dòng xếp dọc y như ở desktop.
   Đo 28/09 trên /quyet-toan-hdv — đây là lỗi bản vá cùng ngày TỰ GÂY ra rồi vá lại. */
.pnt-o-tien-nhieu {
    display: block;
}

/* ============================================================
   Ô CHỌN ẢNH / FILE DẠNG GỌN — component Shared/OChonAnh.razor (user báo 18/08:
   cặp "nút full-width + dòng preview riêng" của ChonFile ăn 2 dòng mỗi file, form HDV
   3 file thành 4 dòng trống hoác). 1 ô = 1 khối cao 56px: thumbnail + trạng thái + 2 nút
   nhỏ, xếp được 3 ô trên 1 hàng. ChonFile giữ nguyên cho các form cũ.
   ============================================================ */
.ocanh {
    min-width: 0;
}

.ocanh-nhan {
    display: block;
    font-size: 12px;
    color: var(--mud-palette-text-secondary);
    margin-bottom: 2px;
}

.ocanh-than {
    display: flex;
    align-items: center;
    /* 05/09: gap 8→6px, thumbnail 44→40px, nút icon 30→24px — form HDV nay xếp 4 ô trên 1 hàng
       (user chốt) nên mỗi ô chỉ còn 193px; 3 con số này trả lại ~26px cho TÊN FILE, đúng 3 đòn bẩy
       đã dùng cho bảng sửa nhanh DKCP 20/08. Tên đầy đủ vẫn xem được qua title (hover) + nút 🔍. */
    gap: 6px;
    height: 56px;
    padding: 4px 4px 4px 6px;
    /* ⚠️ Biến viền input của MudBlazor là lines-inputS (số nhiều) — viết thiếu "s" thì cả khai báo
       border bị coi là invalid và ô MẤT HẲN VIỀN (đã dính 18/08). */
    border: 1px solid var(--mud-palette-lines-inputs, var(--mud-palette-lines-default));
    border-radius: var(--mud-default-borderradius);
    background: var(--mud-palette-surface);
    transition: border-color .15s;
}

.ocanh-than:hover {
    border-color: var(--mud-palette-primary);
}

/* Vùng bấm để chọn/đổi file: thumbnail + chữ trạng thái */
.ocanh-vung-chon {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 1 1 auto;
    min-width: 0;
    cursor: pointer;
}

.ocanh-hinh {
    width: 40px;
    height: 40px;
    flex: 0 0 40px;
    object-fit: cover;
    border-radius: 6px;
    border: 1px solid var(--mud-palette-lines-default);
    background: var(--mud-palette-background-grey);
}

/* Khung giữ chỗ khi chưa có ảnh / file không phải ảnh */
.ocanh-hinh-trong {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--mud-palette-text-disabled);
}

.ocanh-chu {
    font-size: 13px;
    line-height: 1.25;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

/* Ô CHỌN ẢNH Ở HÀNG 4 Ô (form HDV, chỉ khi màn ≥960px thật sự xếp 4 ô/hàng): cột còn 183px nên
   thumbnail 40px + 2 nút + gap ăn hết, tên file chỉ còn 59px ≈ 6 ký tự (đo 05/09). Thu tiếp
   thumbnail, bỏ dòng phụ và cho tên file XUỐNG 2 DÒNG — thân ô vẫn đúng 56px (2 dòng × 16px).
   Dưới 960px hàng này về 2 ô/hàng nên KHÔNG áp, ô rộng rãi thì hiện đủ dòng phụ như mọi form khác. */
@media (min-width: 960px) {
    .ocanh-hep .ocanh-than {
        gap: 4px;
    }

    .ocanh-hep .ocanh-hinh {
        width: 36px;
        height: 36px;
        flex: 0 0 36px;
    }

    .ocanh-hep .ocanh-chu-phu {
        display: none;
    }

    .ocanh-hep .ocanh-chu {
        white-space: normal;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
    }
}

/* Nút 🔍 / 🗑 trong ô: thu vùng bấm để nhường chỗ cho tên file (vẫn ≥24px, chạm được) */
.ocanh-than .mud-icon-button {
    padding: 3px;
}

.ocanh-chu-phu {
    display: block;
    font-size: 11px;
    color: var(--mud-palette-text-secondary);
}

/* Ô NHẬP CHỮ ĐỨNG CÙNG HÀNG VỚI Ô CHỌN ẢNH (user chốt 05/09, kèm ảnh: "để ô input và 3 nút này
   thành 1 hàng, padding để bằng nhau" — form HDV có ô "Tên / ID wechat" đứng cạnh 3 ô ảnh/file).
   Khung ngoài vẫn là .ocanh-than nên viền · bo góc · chiều cao 56px · hover GIỐNG HỆT 3 ô kia;
   bên trong là MudTextField Variant.Text đã gỡ gạch chân, còn nhãn thì nằm ngoài ở .ocanh-nhan.
   ⚠️ Đây là NGOẠI LỆ CÓ CHỦ ĐÍCH của chuẩn chiều cao ô 30px (--pnt-cao-o): ở hàng này ô nhập phải
   bằng ô chọn ảnh mới thẳng, không phải bằng ô nhập của các hàng trên. Đừng "sửa cho đúng chuẩn". */
.ocanh-than-nhap {
    padding-left: 10px;
    padding-right: 10px;
}

.ocanh-than-nhap:focus-within {
    border-color: var(--mud-palette-primary);
}

/* Ô bị khóa (đã có ảnh QR) — làm mờ cả khung để thấy ngay vì sao không gõ được */
.ocanh-than-nhap:has(input:disabled) {
    background: var(--mud-palette-background-grey);
}

.ocanh-than-nhap .mud-input {
    height: 100%;
    margin-top: 0;
}

/* Variant.Text mang gạch chân ở .mud-input-underline (KHÔNG phải .mud-input-text) */
.ocanh-than-nhap .mud-input-underline:before,
.ocanh-than-nhap .mud-input-underline:after {
    display: none;
}

h1:focus {
    outline: none;
}

/* ===================== MÀN CHỜ LÚC TẢI TRANG (từ 25/08, khi tắt prerender) =====================
   HTML đầu tiên không còn nội dung trang (xem ghi chú trong App.razor) → lấp bằng nền trắng cho tới
   khi circuit gắn xong; js/man-cho.js (file riêng, tem ?v=) gỡ nó ngay khi Blazor chèn MARKER app
   thật (#pnt-goc / .mud-layout) vào body.
   ⚠️ Các quyết định sau sự cố "load 15s" + review đối kháng (25/08):
   (1) logo + vạch chạy CHỜ 0,35s mới hiện — tải nhanh (localhost ~100ms) thì chỉ thấy nền trắng
       thoáng qua, không bị "nháy logo" ở mọi lần chuyển trang; tải chậm mới thấy chỉ báo;
   (2) lối thoát CSS = 12s (khớp setTimeout của man-cho.js) — CỐ Ý KHÔNG ngắn: tem ?v= đã triệt ca
       "script lệch phiên bản" nên fallback gần như chỉ kích hoạt ở ca TẢI CHẬM THẬT (4G yếu,
       staging xa); cắt ở 4s là để lộ TRANG TRẮNG đúng lúc người dùng cần chỉ báo nhất (review bắt);
   (3) giây thứ 8 hiện dòng "tải lâu bất thường…" ngay trong màn chờ — ca kẹt thật có chỉ dẫn F5
       thay vì đứng im. */
#pnt-man-cho {
    position: fixed;
    inset: 0;
    z-index: 4000;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 18px;
    background: #fff;
    animation: pnt-man-cho-bo-cuoc 0s linear 12s forwards;
}

#pnt-man-cho img {
    height: 44px;
    opacity: 0;
    animation: pnt-man-cho-hien .2s ease .35s forwards;
}

.pnt-man-cho-vach {
    width: 180px;
    height: 3px;
    border-radius: 2px;
    background: #E3F2FD;
    overflow: hidden;
    opacity: 0;
    animation: pnt-man-cho-hien .2s ease .35s forwards;
}

.pnt-man-cho-vach span {
    display: block;
    width: 40%;
    height: 100%;
    border-radius: 2px;
    background: #1565c0;
    animation: pnt-man-cho-chay 1.1s ease-in-out infinite;
}

/* Chỉ dẫn khi kẹt thật — ẩn tới giây thứ 8 mới hiện (bình thường màn chờ đã bị gỡ từ lâu) */
.pnt-man-cho-loi {
    max-width: 340px;
    text-align: center;
    font-family: "Segoe UI", Roboto, Arial, sans-serif;
    font-size: 13px;
    line-height: 1.5;
    color: #78909c;
    opacity: 0;
    animation: pnt-man-cho-hien .3s ease 8s forwards;
}

@keyframes pnt-man-cho-chay {
    0% { transform: translateX(-100%); }
    100% { transform: translateX(250%); }
}

@keyframes pnt-man-cho-hien {
    to { opacity: .9; }
}

@keyframes pnt-man-cho-bo-cuoc {
    to { opacity: 0; visibility: hidden; }
}

/* ⚠️ visibility KHÔNG được nằm ngoài transition (review 25/08): khai `visibility: hidden` trần thì
   nó áp TỨC THÌ ngay khi thêm class — phần tử biến mất từ frame đầu, hiệu ứng mờ 0,2s chạy trên
   phần tử đã vô hình (cắt PHỤT, đúng cái "nháy" đang cố tránh). Dùng pointer-events cho click
   xuyên qua ngay; el.remove() sau 250ms trong man-cho.js lo phần gỡ hẳn. */
.pnt-man-cho-tat {
    /* opacity đặt ở CHA nên nhân xuống toàn khối — các con (logo/vạch/chỉ dẫn) mờ theo dù chúng
       đang mang animation opacity riêng (animation của chúng chỉ set opacity CỦA CHÍNH CHÚNG) */
    opacity: 0;
    pointer-events: none;
    transition: opacity .2s ease;
}

/* Trang lỗi Blazor mặc định */
#blazor-error-ui {
    background: #b32121;
    color: #fff;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 3000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}

/* ===== Trang đăng nhập (SSR, không dùng MudBlazor interactive) ===== */
.dn-nen {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, #0d47a1 0%, #1565c0 45%, #1e88e5 100%);
    font-family: "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    padding: 16px;
}

.dn-the {
    background: #fff;
    border-radius: 14px;
    box-shadow: 0 12px 40px rgba(13, 71, 161, 0.35);
    padding: 40px 36px 32px 36px;
    width: 100%;
    max-width: 400px;
    box-sizing: border-box;
}

.dn-logo {
    text-align: center;
    margin-bottom: 6px;
    font-size: 30px;
    font-weight: 700;
    color: #0d47a1;
    letter-spacing: 1px;
}

.dn-phu-de {
    text-align: center;
    color: #78909c;
    margin: 0 0 26px 0;
    font-size: 14.5px;
}

.dn-nhom {
    margin-bottom: 16px;
}

.dn-nhom label {
    display: block;
    font-size: 13.5px;
    font-weight: 600;
    color: #37474f;
    margin-bottom: 6px;
}

.dn-nhom input {
    width: 100%;
    box-sizing: border-box;
    padding: 11px 13px;
    border: 1px solid #cfd8dc;
    border-radius: 8px;
    font-size: 15px;
    outline: none;
    transition: border-color .15s, box-shadow .15s;
}

.dn-nhom input:focus {
    border-color: #1565c0;
    box-shadow: 0 0 0 3px rgba(21, 101, 192, 0.15);
}

.dn-ghi-nho {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13.5px;
    color: #37474f;
    margin-bottom: 4px;
    cursor: pointer;
    user-select: none;
}

.dn-ghi-nho input {
    width: 16px;
    height: 16px;
    accent-color: #1565c0;
    cursor: pointer;
}

.dn-nut {
    width: 100%;
    padding: 12px;
    margin-top: 6px;
    background: #1565c0;
    color: #fff;
    font-size: 15.5px;
    font-weight: 600;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    transition: background .15s;
}

.dn-nut:hover { background: #0d47a1; }

.dn-nut:disabled {
    background: #90a4ae;
    cursor: default;
}

.dn-loi {
    display: none;
    background: #ffebee;
    color: #b71c1c;
    border: 1px solid #ef9a9a;
    border-radius: 8px;
    padding: 10px 13px;
    font-size: 14px;
    margin-bottom: 16px;
}

.dn-chu-thich {
    text-align: center;
    color: #90a4ae;
    font-size: 12.5px;
    margin-top: 22px;
}

/* ===================== THÔNG BÁO (GĐ2, 18/08) =====================
   Panel chuông kiểu Facebook + danh sách dùng chung cho trang /thong-bao.
   ⚠️ Khối @media của phần này đặt ở CUỐI, SAU các rule gốc bên trên — trong dự án đã dính 3 lần
   lỗi "quy tắc mobile bị rule gốc ở cuối file đè ngược" (xem ghi chú giữa file). */

.pnt-tb-nut {
    display: flex;
    align-items: center;
    justify-content: center;
    /* Vùng chạm >= 44px theo chuẩn mobile của dự án */
    min-width: 44px;
    height: 44px;
    border-radius: 50%;
    cursor: pointer;
}

.pnt-tb-nut:hover {
    background: rgba(255, 255, 255, .14);
}

.pnt-tb-popover {
    /* Panel có chiều cao trần; phần danh sách bên trong mới cuộn */
    max-width: 96vw;
}

.pnt-tb-panel {
    width: 380px;
    max-width: 96vw;
    display: flex;
    flex-direction: column;
}

.pnt-tb-dau {
    display: flex;
    align-items: center;
    padding: 10px 8px 6px 16px;
}

.pnt-tb-tieude {
    font-size: 18px;
    font-weight: 700;
}

.pnt-tb-tab {
    display: flex;
    gap: 8px;
    padding: 4px 12px 10px;
    flex-wrap: wrap;
}

/* Viên thuốc (pill) — CỐ Ý không dùng MudTabs: MudTabs tính sai bề rộng khi nằm trong popover */
.pnt-tb-pill {
    border: none;
    background: transparent;
    color: var(--mud-palette-text-secondary);
    font-size: 13px;
    font-weight: 600;
    padding: 6px 14px;
    border-radius: 999px;
    cursor: pointer;
    font-family: inherit;
}

.pnt-tb-pill:hover {
    background: var(--mud-palette-action-default-hover);
}

.pnt-tb-pill-chon {
    background: var(--mud-palette-primary-hover);
    color: var(--mud-palette-primary);
}

.pnt-tb-ds {
    max-height: 55vh;
    overflow-y: auto;
}

.pnt-tb-dong {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 14px;
    cursor: pointer;
    border-top: 1px solid var(--mud-palette-divider);
}

.pnt-tb-dong:first-child {
    border-top: none;
}

.pnt-tb-dong:hover {
    background: var(--mud-palette-action-default-hover);
}

/* Dòng CHƯA XEM: nền nhạt + chữ đậm hơn (như Facebook) */
.pnt-tb-chua-xem {
    background: var(--mud-palette-primary-hover);
}

.pnt-tb-icon {
    margin-top: 2px;
    flex: 0 0 auto;
}

.pnt-tb-chu {
    min-width: 0;   /* cho phép chữ dài xuống dòng thay vì đội rộng panel */
    flex: 1 1 auto;
}

.pnt-tb-tt {
    font-size: 13.5px;
    font-weight: 600;
    overflow-wrap: anywhere;
}

.pnt-tb-nd {
    font-size: 12.5px;
    color: var(--mud-palette-text-secondary);
    overflow-wrap: anywhere;
}

.pnt-tb-gio {
    font-size: 12px;
    color: var(--mud-palette-text-secondary);
    margin-top: 2px;
}

.pnt-tb-cham {
    flex: 0 0 auto;
    width: 10px;
    height: 10px;
    margin-top: 6px;
    border-radius: 50%;
    background: var(--mud-palette-primary);
}

.pnt-tb-chan {
    border-top: 1px solid var(--mud-palette-divider);
}

.pnt-tb-rong {
    padding: 28px 16px;
    text-align: center;
    font-size: 13px;
    color: var(--mud-palette-text-secondary);
}

/* Bản dùng trên TRANG /thong-bao (rộng hơn panel, dòng thoáng hơn) */
.pnt-tb-dong-trang {
    padding: 12px 16px;
}

@media (max-width: 599px) {
    /* Panel gần full-width trên điện thoại, KHÔNG được tràn ngang */
    .pnt-tb-panel {
        width: calc(100vw - 24px);
    }

    .pnt-tb-ds {
        max-height: 60vh;
    }

    /* Appbar dưới 600px cao CỨNG 52,5px → nút chuông phải vừa khít, không đội cao toolbar */
    .pnt-tb-nut {
        min-width: 40px;
        height: 40px;
    }
}

/* Dòng tiêu đề NHÓM trong dropdown lọc hạng mục thông báo (item Disabled — không chọn được) */
.pnt-tb-nhom-dau {
    font-weight: 700;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--mud-palette-primary);
}

/* ===================== TRANG CHỦ: section theo bộ phận + ô lối tắt =====================
   User chốt 20/08: chia rõ section theo bộ phận (như app cũ) và ô to gấp đôi bản trước.
   Danh sách chức năng nằm ở Components/Shared/ChucNangHeThong.cs (chung với menu trái). */
.pnt-tc-nhom {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 12px 4px;
    font-weight: 700;
    font-size: 14px;
    letter-spacing: .06em;
    color: var(--mud-palette-text-secondary);
}

.pnt-loi-tat {
    transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}

.pnt-loi-tat:hover {
    border-color: var(--mud-palette-primary);
    box-shadow: 0 2px 10px rgba(0, 0, 0, .10);
    transform: translateY(-2px);
}

@media (max-width: 599.98px) {
    /* Ô to gấp đôi ăn hết màn điện thoại → thu lại vừa phải, vẫn to hơn bản cũ */
    .pnt-loi-tat {
        padding: 16px !important;
    }

    .pnt-loi-tat .mud-icon-root {
        font-size: 44px !important;
    }
}

/* ===================== CỘT THÁNG bên trái màn danh sách (Shared/SidebarThang.razor) =====
   Dựng lại thói quen app cũ (user chốt 20/08): "All" + từng tháng kèm số lượng. Cùng hình thức
   với sidebar tháng của màn DKCP/TTCP (.dkcp-thang) nhưng ở đây là component DÙNG CHUNG. */
.pnt-sb-hop {
    max-height: 75vh;
    overflow-y: auto;
}

.pnt-sb-thang {
    padding: 6px 10px;
    border-radius: 6px;
    cursor: pointer;
    margin-bottom: 2px;
    user-select: none;
}

.pnt-sb-thang:not(.pnt-sb-thang-chon):hover {
    background: var(--mud-palette-action-default-hover);
}

.pnt-sb-thang-chon {
    background: var(--mud-palette-primary);
    color: var(--mud-palette-primary-text);
}

.pnt-sb-ten {
    font-weight: 700;
}

.pnt-sb-phu {
    font-size: 12px;
}

/* Dòng TIỀN trong nút tháng (user chốt 25/08: ghi tổng còn nợ VNĐ/RMB/USD ngay trong nút).
   Đậm hơn dòng đếm mục để mắt bắt được ngay con số; KHÔNG cho xuống dòng vì số và đơn vị phải
   dính liền (luật "tiền không bao giờ wrap" 15/08) — cột hẹp thì cắt bằng "…", rê chuột xem đủ. */
.pnt-sb-tien {
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

@media (max-width: 959.98px) {
    /* Dưới breakpoint drawer: cột tháng nằm TRÊN bảng → giới hạn cao để không đẩy bảng khuất tầm.
       ⚠️ Vì thế .pnt-sb-hop KHÔNG được đặt max-height bằng inline Style ở component (inline thắng
       stylesheet, khối @media này sẽ vô hiệu). */
    .pnt-sb-hop {
        max-height: 34vh;
    }
}

/* ===================== KHUNG DANH SÁCH CUỘN ĐƯỢC + KÉO GIÃN =====================
   User chốt 20/08: section rút gọn (loại có nút "Xem toàn bộ") KHÔNG hiện cứng 5 dòng nữa — trong
   khung có đủ mục, người dùng CUỘN CHUỘT xem tiếp và KÉO GÓC DƯỚI BÊN PHẢI để mở rộng khung.

   CÁCH DÙNG: gắn class `pnt-ds-cuon` lên CHÍNH component bảng (MudSimpleTable/MudTable) hoặc lên
   1 div bọc danh sách không phải bảng.

   ⚠️ MudSimpleTable/MudTable render 2 lớp: div.mud-table (nhận Class) > div.mud-table-container > table,
   và LỚP TRONG vốn đã overflow:auto. Nếu đặt max-height ở LỚP NGOÀI thì lớp trong cứ cao lên, thanh
   cuộn nằm ở ngoài và `position:sticky` của thead tính theo lớp trong (không cuộn dọc) ⇒ MẤT tên cột
   khi cuộn. Vì vậy mọi thuộc tính cuộn/kéo đặt vào ĐÚNG .mud-table-container. Với MudTable, pager nằm
   NGOÀI container nên không bị cuộn theo — đúng ý. */
.pnt-ds-cuon > .mud-table-container,
.pnt-ds-cuon:not(.mud-table) {
    max-height: 292px;   /* ~5 dòng + hàng tiêu đề: giữ nguyên cảm giác "xem gọn" cũ */
    min-height: 96px;
    overflow: auto;
    resize: vertical;    /* tay kéo chỉ hiện khi overflow != visible */
}

/* ⚠️ resize KÉO được nhưng bị max-height KẸP LẠI: trình duyệt ghi `height` inline khi kéo, mà
   max-height trong stylesheet vẫn thắng ⇒ khung không cao lên nổi (đo được 292px → 292px).
   Khi đã có height inline (tức người dùng ĐÃ kéo) thì bỏ trần, chỉ chặn ở 85vh cho khỏi tràn màn. */
.pnt-ds-cuon > .mud-table-container[style*="height"],
.pnt-ds-cuon:not(.mud-table)[style*="height"] {
    max-height: 85vh;
}

/* Tay kéo mặc định của trình duyệt rất mờ — tô đậm cho người dùng nhận ra là kéo được */
.pnt-ds-cuon > .mud-table-container::-webkit-resizer,
.pnt-ds-cuon:not(.mud-table)::-webkit-resizer {
    background: var(--mud-palette-action-disabled);
    border-radius: 2px;
}

/* Chế độ nhập liệu (vd "Sửa nhanh" của DKCP): mỗi hàng cao ~56px thay vì ~34px → nới khung, không
   thì đang gõ chỉ thấy 4 dòng. */
.pnt-ds-cuon-cao > .mud-table-container,
.pnt-ds-cuon-cao:not(.mud-table) {
    max-height: 60vh;
}

/* Dòng TỔNG ở tfoot phải GHIM ĐÁY khung, không thì cuộn vài dòng là mất số tổng (bảng TTCP theo
   tháng ở hồ sơ NCC có dòng "Tất cả") */
.pnt-ds-cuon tfoot td,
.pnt-ds-cuon tfoot th {
    position: sticky;
    bottom: 0;
    z-index: 2;
    background: var(--mud-palette-surface);
    box-shadow: inset 0 1px 0 var(--mud-palette-lines-default);
}

/* Ghim hàng tiêu đề khi cuộn — không có thì cuộn tới dòng 20 là quên cột nào là cột nào */
.pnt-ds-cuon thead th {
    position: sticky;
    top: 0;
    z-index: 3;
    background: var(--mud-palette-surface);
    /* border-collapse của .mud-simple-table làm MẤT viền dưới khi th sticky → vẽ lại bằng shadow
       (cùng cách .pnt-ghim-cot đang dùng cho cột ghim) */
    box-shadow: inset 0 -1px 0 var(--mud-palette-lines-default);
}

@media (max-width: 959.98px) {
    /* MudTable có Breakpoint đổ thành THẺ DỌC dưới 960px: 1 bản ghi cao gấp ~4 lần 1 dòng bảng
       nên nới khung để vẫn thấy được vài bản ghi; người dùng kéo thêm nếu muốn. */
    .pnt-ds-cuon > .mud-table-container,
    .pnt-ds-cuon:not(.mud-table) {
        max-height: 420px;
    }
}

/* ===================== MỤC DKCP ĐÃ THÀNH THỰC TẾ CHI PHÍ =====================
   User chốt 20/08: mục đã được tính vào TTCP (tức có phiếu ĐNTT ĐÃ THANH TOÁN phân bổ vào) thì chữ
   chuyển XANH LỤC + ĐẬM; chưa thì để đen như cũ. Chỉ là dấu hiệu nhìn — không đổi dữ liệu, không
   chặn thao tác gì (TTCP vẫn là số DẪN XUẤT, xem ThucTeChiPhiService).
   ⚠️ 2 ô "Đã thanh toán" (xanh) và "Còn nợ" (đỏ) có màu inline riêng nên vẫn giữ màu của chúng —
   cố ý, vì đó là màu mang nghĩa số liệu. */
/* ⚠️ MudBlazor có rule `.mud-simple-table table * tr > td { font-weight: var(--mud-typography-body2-weight) }`
   thắng selector 1 lớp → phải đủ 2 class mới đè được phần in đậm (màu thì không bị đè). */
tr.dkcp-la-ttcp > td {
    color: var(--mud-palette-success);
}

.mud-simple-table table tr.dkcp-la-ttcp > td,
.mud-table table tr.dkcp-la-ttcp > td {
    color: var(--mud-palette-success);
    font-weight: 600;
}

/* Link tên NCC/HDV trong dòng đó cũng XANH LỤC theo cả dòng (user chốt 20/08: "1 dòng 2 màu chữ
   loạn quá" — link để nguyên xanh dương thì mỗi dòng có 2 màu).
   ⚠️ Phải nhắc tới class của MudBlazor (.mud-link / .mud-typography): rule `tr.dkcp-la-ttcp > td a`
   chỉ có 1 class nên THUA `.mud-link.mud-primary-text` 2 class — đó là lý do lần trước link vẫn xanh. */
tr.dkcp-la-ttcp > td a.mud-link,
tr.dkcp-la-ttcp > td a.mud-typography,
tr.dkcp-la-ttcp > td .mud-chip .mud-chip-content {
    /* !important là BẮT BUỘC ở đây (hiếm khi dùng trong dự án): class tiện ích màu chữ của MudBlazor
       `.mud-primary-text` khai `color: … !important`, không có !important thì specificity cao mấy
       cũng thua — đo được 20/08: link vẫn xanh dương trong khi cả dòng đã xanh lục. */
    color: var(--mud-palette-success) !important;
}

/* Số "Đã thanh toán" (xanh) và "Còn nợ" (đỏ) đặt màu INLINE nên vẫn thắng — cố ý giữ nguyên vì đó
   là màu mang nghĩa số liệu, KHÔNG phải màu trang trí của dòng. */

/* ===================== DANH SÁCH XỔ: CẮT CHỮ THAY VÌ NONG SANG NGANG =====================
   User chốt 20/08 (từ ô Tour Code của Quick Booking): nhãn ghép "mã booking đầu — tour code
   (N booking)" dài hơn ô nhập nên với RelativeWidth="DropdownWidth.Adaptive" (min-width = bề ngang
   ô, còn lại nong theo nội dung) danh sách tự bè sang ngang, tràn đè cả nội dung trang.
   Cách chữa gồm ĐỦ 2 vế — thiếu vế nào cũng hỏng:
     (1) ô nhập đổi sang RelativeWidth="DropdownWidth.Relative" (bó đúng bề ngang ô);
     (2) DÒNG trong danh sách phải bọc <div class="pnt-cat-chu" title="…"> để CẮT + "…".
   Chỉ làm (1) mà quên (2) thì MudBlazor bẻ dòng, chữ rớt DỌC từng ký tự (đúng cảnh báo đã ghi
   trong CLAUDE.md — đó là lý do 20/08 cả dự án để Adaptive).
   ⚠️ ĐỪNG chữa bằng cách chặn trần bề ngang qua CSS: với Adaptive, MudBlazor ghi THẲNG
   style="max-width: none" lên thẻ popover (đo 20/08) nên rule max-width trong file này thua sạch,
   trừ khi dùng !important — mà chặn trần cũng KHÔNG hết bè: popover rộng hơn ô thì MudBlazor vẫn
   lật sang trái (overflow-flip) rồi đè lên nội dung. Bó bằng ô (Relative) mới dứt điểm. */
.pnt-xo-cat-chu .mud-list-item { overflow: hidden; }

/* MudBlazor đã cho .mud-list-item-text { min-width: 0 } nên con bên trong co lại được;
   khai lại cho chắc, phòng khi ItemTemplate lồng thêm 1 lớp nữa. */
.pnt-xo-cat-chu .mud-list-item-text,
.pnt-xo-cat-chu .mud-list-item-text > * { min-width: 0; }

/* 1 dòng chữ bị cắt + "…" — dùng SPAN trong ItemTemplate (MudListItem bọc ChildContent trong <p>,
   thẻ khối trong <p> bị trình duyệt đẩy ra ngoài), display:block dưới đây lo phần còn lại.
   LUÔN kèm title="…" để rê chuột xem đủ chữ. */
.pnt-cat-chu {
    display: block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ===================== DÒNG TRỐNG CỦA "SỬA NHANH" BẢNG DKCP =====================
   User chốt 20/08: bật sửa nhanh là mỗi nhóm dịch vụ dựng sẵn 5 dòng trống (+ nút "Thêm dòng"
   cạnh tên nhóm) để gõ thẳng thành mục mới. Tô nền rất nhạt cho phân biệt với mục ĐANG CÓ —
   nhạt thôi, vì dòng đã gõ mà thiếu NCC/HDV còn phải nhường chỗ cho nền vàng .dkcp-dong-loi.
   ⚠️ Phải dùng :not(.dkcp-dong-loi) chứ ĐỪNG viết rule đè rồi "background: unset" — unset là
   TRONG SUỐT, không phải "quay về rule vàng" (cascade chọn khai báo thắng theo từng thuộc tính,
   nó không rơi ngược xuống rule ít điểm hơn). Đúng mẫu :not() đã dùng cho .lb-chip. */
tr.dkcp-dong-moi:not(.dkcp-dong-loi) > td {
    background: var(--mud-palette-background-grey);
}

/* ===================== CỘT LỌC BÊN TRÁI THU GỌN ĐƯỢC (user chốt 21/08) =====================
   "Chỗ nào có phần menu bên trái thì làm 1 nút toggle ẩn như menu chính."
   Dùng qua component Shared/CotTrai.razor — 8 màn dùng chung.
   ⚠️ MẤU CHỐT: ô NỘI DUNG bên phải KHÔNG phải sửa gì. Khi thu gọn, cột trái mang class
   .pnt-cot-trai-thu và rule anh-em dưới đây cho ô kế tiếp trong lưới giãn ra chiếm chỗ trống.
   Nhờ vậy không phải đụng vào lưới của từng trang, và trang cũng không cần vẽ lại khi bấm nút. */
.pnt-cot-trai-thu {
    flex: 0 0 auto;
    width: auto;
    max-width: none;
}

.pnt-cot-trai-thu ~ .mud-grid-item {
    flex-grow: 1;
    max-width: none;
}

/* ===================== THANH BỘ LỌC: CÁC Ô PHẢI NẰM SÁT NHAU (user chốt 25/08) =====================
   Bug: mọi ô trong `.pnt-thanh-loc` bị GIÃN ĐỀU ra hết bề ngang thanh lọc, chừa những khoảng trống
   80-150px giữa các ô trong khi ô nhập bên trong vẫn đúng bề ngang đã khai.
   Nguyên nhân (đo trong MudBlazor.min.css): gốc của MudTextField là `.mud-input-control { flex: 1 1 auto }`
   và gốc của MudSelect là `.mud-select { flex-grow: 1 }` — tức MỌI ô đều là flex item BIẾT GIÃN. Tham số
   `Style="width:240px"` lại rơi xuống phần tử BÊN TRONG (xem ghi chú "MudBlazor đổ Style xuống phần tử
   khác nhau" ở khối mobile phía trên), nên phần giãn thừa nằm ở lớp ngoài dưới dạng khoảng trắng.
   ⚠️ Đặt trong @media (min-width:600px): khối mobile ở ĐẦU file cố ý cho các ô giãn full-width, mà 2 rule
   cùng độ đặc hiệu thì rule ĐỨNG SAU thắng — không bọc media là phá luôn bản mobile.
   ⚠️ Mọi ô trong thanh lọc PHẢI có bề ngang tự khai (Style width hoặc div bọc ngoài — đã rà đủ 15 màn
   ngày 25/08); ô không khai gì sẽ co về bề ngang mặc định của thẻ input. */
@media (min-width: 600px) {
    .pnt-thanh-loc > .mud-input-control,
    .pnt-thanh-loc > .mud-select,
    .pnt-thanh-loc > .mud-autocomplete,
    .pnt-thanh-loc > .mud-picker {
        flex: 0 0 auto;
    }
}

/* ===================== KHOẢNG CÁCH TRONG DIALOG (user chốt 25/08) =====================
   Dialog chỉ còn bóp KHOẢNG CÁCH GIỮA các ô (margin hàng + spacing lưới + đệm tiêu đề), KHÔNG bóp
   chiều cao bản thân ô nữa — user chốt lại đợt 3: *"tăng padding y của tất cả các ô input trong toàn
   bộ form của app"* ⇒ chiều cao ô do khối "CHIỀU CAO Ô NHẬP + NÚT" ở cuối file lo, dùng chung cho cả
   trang lẫn modal (nguyên tắc "1 style cho 1 loại ô" của dự án).
   ⚠️ MudBlazor dựng lưới bằng margin ÂM ở container + padding ở từng ô ⇒ sửa spacing phải sửa CẢ HAI,
   lệch nhau là lưới thò ra ngoài mép dialog. */
.mud-dialog .mud-input-control.mud-input-control-margin-dense {
    margin: 2px 0;
}

.mud-dialog .mud-input-control.mud-input-control-margin-dense.mud-input-outlined-with-label {
    margin-top: 6px;
    margin-bottom: 2px;
}

/* Lưới trong dialog: khoảng cách giữa các ô hạ 1 bậc (Spacing="2" = 8px → 5px, "3" = 12px → 7px).
   MudBlazor dựng lưới bằng margin ÂM ở container + padding ở từng ô ⇒ phải sửa CẢ HAI, lệch nhau là
   lưới thò ra ngoài mép dialog. */
.mud-dialog .mud-grid.mud-grid-spacing-xs-2 {
    margin: -5px;
    width: calc(100% + 10px);
}

.mud-dialog .mud-grid.mud-grid-spacing-xs-2 > .mud-grid-item {
    padding: 5px;
}

.mud-dialog .mud-grid.mud-grid-spacing-xs-3 {
    margin: -7px;
    width: calc(100% + 14px);
}

.mud-dialog .mud-grid.mud-grid-spacing-xs-3 > .mud-grid-item {
    padding: 7px;
}

/* Tiêu đề dialog: 16px → 12px (chữ tiêu đề đã đủ nổi, không cần đệm dày).
   ⚠️ Bọc @media min-width:600px: khối mobile ở đầu file đã bóp còn chặt hơn (12px 16px / 8px 12px),
   rule này đứng SAU nên không bọc là nới ngược lại trên điện thoại. */
@media (min-width: 600px) {
    .mud-dialog .mud-dialog-title {
        padding: 12px 20px;
    }

    .mud-dialog .mud-dialog-content {
        padding: 8px 20px;
    }
}

/* Nút thu gọn nằm trên HÀNG RIÊNG, canh phải, ngay phía trên nội dung cột.
   ⚠️ Bản đầu cho nút ĐÈ lên nội dung bằng margin âm cho đỡ tốn chỗ — hỏng: nó nằm đúng trên tab
   tháng đang chọn (nền xanh, icon trắng nên gần như tàng hình) và che mất vùng bấm của tab đó. */
.pnt-cot-trai-nut {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 2px;
    line-height: 0;
}

/* ===================== CHIỀU CAO Ô NHẬP + NÚT (user chốt 25/08 — đợt 3) =====================
   3 yêu cầu user gộp trong một câu: *"để tất cả các nút bằng cỡ ô input, tăng padding y của tất cả
   các ô input trong toàn bộ form của app, giảm độ rộng của tất cả các form modal"*.
   Số đo THẬT trước khi sửa (đo bằng Playwright): ô ngoài trang cao 40px · ô trong dialog 32px (rule
   bóp của đợt 2 — đã gỡ) · nút Filled 37px · nút chọn file 40px ⇒ nút và ô không bao giờ bằng nhau.
   Nay tất cả quy về MỘT chiều cao chuẩn `--pnt-cao-o` = 44px (cũng đúng cỡ vùng chạm tối thiểu).
   ⚠️ 4 điều PHẢI nhớ khi đụng lại:
   (1) NHÃN nổi kiểu Outlined đặt bằng transform CỨNG, phải canh lại theo chiều cao ô — công thức
       rút ra từ số đo: `translateY = (cao ô − 20)/2 + 2` (ô 40px→12px là giá trị gốc MudBlazor,
       ô 44px→14px). Sai số này không gây lỗi build, chỉ làm nhãn tụt khỏi giữa ô.
   (2) TEXTAREA có `mask-image` che đúng phần padding-top để chữ không lòi lên nhãn — đổi padding mà
       quên mask là CẮT MẤT dòng chữ đầu.
   (3) Ô nhập TRONG BẢNG giữ nguyên cỡ gọn (6,5px) — bảng nhập liệu của TaoDnttForm/KhachTtGopForm/
       QuyetToanHdvForm có hàng chục ô một màn, cao 44px là bảng dài gấp rưỡi. Nút trong bảng cũng vậy.
   (4) Nút: chỉ nhắm nút HÀNH ĐỘNG. Phải chừa icon button (nút X của dialog, mũi tên phân trang, nút
       lịch trong ô), MudNavLink, item trong menu và tab — chúng cũng mang class `mud-button-root`. */
/* ⚠️⚠️ CHUẨN ĐỔI LẠI 28/08 (user chốt, xem ảnh thanh nút đầu trang booking): *"như này là đẹp, tôi
   muốn tất cả các nút trong app theo 1 quy chuẩn padding như này, kể cả các ô input padding y cũng
   chỉ để thế thôi"*. Số đo lúc user chốt: nút thật có **padding y 3–4px** (chỉ cao 44px vì bị
   `min-height: 44px` của đợt 25/08 ép ra), còn ô nhập padding y **12,5px** — gấp 3 lần nút.
   ⇒ Nay QUY VỀ MỘT: padding y = 4px cho CẢ nút lẫn ô nhập, và BỎ ép min-height 44px.
   Hệ quả: nút + ô nhập cùng cao ~30px (thay 44px), form/thanh lọc/dialog gọn hẳn.
   🔴 Chuẩn 25/08 ("mọi nút bằng cỡ ô nhập, 44px") ĐÃ BỊ THAY bởi chốt này — đừng khôi phục 44px.
   Cái GIỮ LẠI của 25/08: nút vẫn bằng cỡ ô nhập (nay cùng ~30px), vẫn chừa icon button/NavLink/
   item menu/tab/nút trong bảng, và bề ngang modal vẫn theo số đo.
   ⚠️ 3 thứ ĐI KÈM chiều cao ô, sai là lộ ngay (bài học 25/08): (1) NHÃN NỔI Outlined đặt bằng
   transform CỨNG — công thức `translateY = (cao ô − 20)/2 + 2`, ô 30px ⇒ 7px; (2) TEXTAREA có
   `mask-image` che đúng phần padding-top, đổi padding mà quên mask là CẮT MẤT dòng chữ đầu;
   (3) ô trong BẢNG nay bằng ô ngoài trang (cùng 4px) nên rule riêng cho bảng chỉ còn giữ cho
   textarea/nhãn — bảng không còn "gọn hơn" nữa vì chuẩn chung đã gọn. */
/* 2 CHUẨN chiều cao + 1 biến "đang hiệu lực tại vùng này".
   `--pnt-cao-o` KHÔNG phải hằng số: nó mang giá trị của chuẩn 1 ở mặc định, và được đặt lại thành
   chuẩn 2 bên trong `.pnt-thanh-loc`/`.pnt-o-cao` (xem khối CHUẨN 2 bên dưới). Nhờ vậy chỗ nào ĐÃ
   viết `var(--pnt-cao-o)` — kể cả inline style của `Shared/ChonFile.razor` mà stylesheet không đè
   nổi — tự đi theo chuẩn của vùng chứa nó, không phải sửa từng nơi. */
:root {
    --pnt-cao-o-nho: 30px;
    --pnt-cao-o-lon: 36px;
    --pnt-cao-o: var(--pnt-cao-o-nho);
    /* LỀ của một ô nhập Outlined+Dense CÓ NHÃN — chép từ MudBlazor
       (`.mud-input-control.mud-input-control-margin-dense.mud-input-outlined-with-label`).
       Thứ gì đứng CẠNH ô mà không phải ô (nút chọn file, icon chú thích) phải mượn đúng 2 số này
       mới thẳng hàng. Trong dialog, khối "KHOẢNG CÁCH TRONG DIALOG" hạ ô xuống 6px/2px ⇒ biến được
       đặt lại ở `.mud-dialog` ngay dưới, chỗ dùng không phải biết mình đang ở đâu. */
    --pnt-le-tren-o: 8px;
    --pnt-le-duoi-o: 4px;
}

.mud-dialog {
    --pnt-le-tren-o: 6px;
    --pnt-le-duoi-o: 2px;
}

/* Ô Outlined + Dense: padding y 4px — BẰNG ĐÚNG padding y của nút (user chốt 28/08) */
.mud-input > input.mud-input-root-outlined.mud-input-root-margin-dense,
div.mud-input-slot.mud-input-root-outlined.mud-input-root-margin-dense {
    padding-top: 4px;
    padding-bottom: 4px;
}

/* SÀN chiều cao ô = đúng sàn của nút (--pnt-cao-o): padding 4px cho ra ô 27px, nút 30px ⇒ đặt cạnh
   nhau trong cùng một hàng sẽ so le 3px. Sàn này kéo cả hai về 30px mà KHÔNG đổi padding (đúng chữ
   user: "padding y cũng chỉ để thế thôi"). Textarea nhiều dòng không bị cản vì đây là min-height. */
.mud-input.mud-input-outlined.mud-input-margin-dense {
    min-height: var(--pnt-cao-o);
}

.mud-input > textarea.mud-input-root-outlined.mud-input-root-margin-dense {
    padding-top: 4px;
    padding-bottom: 4px;
    mask-image: linear-gradient(to bottom, transparent 4px, black 4px);
}

.mud-input-label-outlined.mud-input-label-margin-dense {
    transform: translate(14px, 7px) scale(1);
}

/* Ô trong BẢNG: nay CÙNG 4px với ô ngoài trang (chuẩn chung đã gọn hơn cỡ bảng cũ 6,5px) —
   giữ rule để mask/nhãn của bảng không rơi lại giá trị mặc định MudBlazor */
table .mud-input > input.mud-input-root-outlined.mud-input-root-margin-dense,
table div.mud-input-slot.mud-input-root-outlined.mud-input-root-margin-dense {
    padding-top: 4px;
    padding-bottom: 4px;
}

table .mud-input > textarea.mud-input-root-outlined.mud-input-root-margin-dense {
    padding-top: 4px;
    padding-bottom: 4px;
    mask-image: linear-gradient(to bottom, transparent 4px, black 4px);
}

table .mud-input-label-outlined.mud-input-label-margin-dense {
    transform: translate(14px, 7px) scale(1);
}

/* NÚT hành động: 1 QUY CHUẨN PADDING cho toàn app (user chốt 28/08) — padding y 4px · ngang 10px,
   không ép chiều cao nữa (min-height chỉ còn là SÀN 30px = đúng cỡ ô nhập, để nút chữ ngắn không
   teo hơn ô). */
/* ⚠️ Bọc từng :not() trong :where() để độ đặc hiệu chỉ còn (0,1,0) — nếu viết :not() trần thì rule
   này nặng (0,5,0) và ĐÈ luôn rule chừa "table .mud-button-root" bên dưới (0,1,1): đo được nút trong
   bảng /quyet-toan-hdv nhảy lên 44px kéo hàng bảng từ ~50px lên 57px. */
.mud-button-root:where(:not(.mud-icon-button)):where(:not(.mud-nav-link)):where(:not(.mud-list-item)):where(:not(.mud-tab)):where(:not(.mud-button-close)) {
    min-height: var(--pnt-cao-o);
    padding-top: 4px;
    padding-bottom: 4px;
    padding-left: 10px;
    padding-right: 10px;
}

/* Nút trong bảng + nút trong ô nhập (adornment · mũi tên tăng-giảm của ô số) giữ nguyên cỡ nhỏ.
   ⚠️ `.mud-input-numeric-spin` = 2 mũi tên của MudNumericField, cao ~15px và NẰM TRONG ô — kéo chúng
   lên cỡ nút là ô số phình gấp đôi. Đo 28/08 thấy chúng lọt vào phép đo "nút cao 30px" nên ghi rõ ở
   đây để lần sau khỏi tưởng là lỗi. */
table .mud-button-root,
.mud-input-adornment .mud-button-root,
.mud-input-numeric-spin .mud-button-root,
.mud-table-pagination .mud-button-root {
    min-height: 0;
}

/* MŨI TÊN TĂNG-GIẢM CỦA Ô SỐ: ẨN TOÀN APP (user chốt 04/10 trên ảnh 2 ô Tỉ giá / Số tiền của form ĐNTT
   ngoài booking — *"xoá mũi tên ở 2 ô input này đi"*, rồi chọn phạm vi TOÀN APP).
   Vì sao ẩn 1 chỗ bằng CSS chứ không rải `HideSpinButtons="true"` lên từng ô: app có 51 ô số ở 21 file,
   18 ô đã khai sẵn thuộc tính đó từ các đợt trước (ô trong bảng, DkcpDongSua, TaoDnttForm) còn 33 ô thì
   chưa ⇒ sửa lẻ vừa dễ sót vừa trái luật "một chuẩn ô nhập cho TOÀN APP, cấm style lẻ theo trang"
   (user chốt 15/08 + 28/08). Khai ở đây thì ô số của form MỚI tự theo chuẩn, không phải nhớ.
   ⚠️ Khối `min-height: 0` ngay trên VẪN CÒN TÁC DỤNG (nút adornment + nút trong bảng), đừng gộp vào đây.
   ⚠️ Thuộc tính `HideSpinButtons` của 18 ô cũ CỐ Ý không gỡ — gỡ là đổi 18 file mà kết quả y hệt.
   ⚠️ Phím ↑/↓ vẫn tăng-giảm được (hành vi gốc của `input[type=number]`) — chỉ 2 nút mũi tên biến mất.
   🔴 PHẢI khai CẢ selector 3 lớp: MudBlazor bày 2 mũi tên bằng
      `.mud-input-control.mud-input-number-control .mud-input-numeric-spin{display:inline-flex}` = (0,3,0),
      nên bản đầu 04/10 chỉ viết `.mud-input-numeric-spin{display:none}` (0,1,0) THUA — E2E cùng ngày đo
      `display: flex`, mũi tên vẫn nguyên dù file CSS đã tới trình duyệt. Vế (0,1,0) giữ lại để phòng ô số
      nằm ngoài ngữ cảnh `mud-input-number-control`. (Cùng họ bẫy với `:where()` của khối nút 25/08.) */
.mud-input-numeric-spin,
.mud-input-control.mud-input-number-control .mud-input-numeric-spin {
    display: none;
}

/* DÒNG "+ THÊM MỚI" ở đầu danh sách xổ của `Shared/OChonHoacThem.razor` (user chốt 04/10) — phải NHÌN
   RA NGAY là lệnh, không phải một mục dữ liệu, nên tô màu chính + chữ đậm hơn mục thường.
   ⚠️ Phải là `inline-flex`: MudListItem bọc nội dung trong `<p>` nên thẻ KHỐI bị đẩy ra ngoài (bẫy 20/08),
      còn `inline` thì icon và chữ không căn giữa theo nhau. */
.pnt-them-moi {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--mud-palette-primary);
    font-weight: 500;
}

/* NÚT CHỌN FILE (`Shared/ChonFile.razor`) — phải THẲNG HÀNG với ô nhập đứng cạnh (user báo 01/10:
   nút UNC và ô Ghi chú của form Chi phí khác lệch nhau làm vỡ giao diện). Đo được lúc đó: nút
   [565,9 … 600,4] cao 34,5px cạnh ô Ghi chú [563,9 … 593,9] cao 30px ⇒ lệch mép trên 2px, mép dưới
   6,5px. HAI nguyên nhân độc lập, phải vá cả hai:
   (a) LỀ — ô Outlined+Dense CÓ NHÃN lấy lề từ MudBlazor `margin-top:8px; margin-bottom:4px`, nhưng
       TRONG dialog app.css hạ xuống 6px/2px (khối "KHOẢNG CÁCH TRONG DIALOG"). Nút ChonFile ghim
       cứng 8px nên đúng ngoài trang mà thấp hơn ô 2px trong mọi dialog ⇒ tách theo ngữ cảnh ở đây.
   (b) LINE BOX — MudBlazor cho nút `line-height: 1.75 × .875rem = 24,5px` trong khi ô nhập chỉ có
       line box 19px ⇒ nút nở quá sàn `min-height` đúng 4,5px. Khối CHUẨN 2 bên dưới đã vá đúng bệnh
       này bằng `line-height: 19px`; chuẩn 1 chưa có, nên vá tại chỗ cho riêng nút file.
   ⚠️ 19px là line box của ô nhập, ĐÚNG CHO CẢ 2 CHUẨN: chuẩn 1 ⇒ 2 + 8 + max(19, icon 20) = 30px;
      chuẩn 2 ⇒ 2 + 15 + max(19, icon đã hạ 18) = 36px — vừa khít `--pnt-cao-o` của từng vùng.
   ⚠️ Icon StartIcon 20px là thứ quyết định chiều cao ở chuẩn 1 (20 > 19) — hạ nó là nút tụt dưới ô. */
.pnt-nut-file {
    margin-top: var(--pnt-le-tren-o);
    margin-bottom: var(--pnt-le-duoi-o);
    line-height: 19px;
}

/* Biến thể 1 DÒNG (user 04/10: *"nút đính kèm phải cùng size với ô input để dòng không bị vỡ"*).
   `min-height` của khối trên là CỐ Ý (ghi chú 25/08 ở ChonFile.razor): nhãn dài trong cột hẹp xuống
   2 dòng thì nút phải nở ra, không thì chữ lòi khỏi viền. Nhưng nút nở = cao hơn ô nhập cùng hàng
   ⇒ vỡ dòng lưới (đo 04/10 ở NgoaiBookingForm cột sm=4 dialog Small: "FILE ĐÍNH KÈM" ~120px > ~113px
   chỗ chữ khả dụng ⇒ 2 dòng, nút 44px cạnh ô 30px). Khi gọi với `MotDong="true"`, nút GHIM đúng
   `--pnt-cao-o` và cấm xuống dòng.
   ⚠️ Chỉ dùng kèm NHÃN NGẮN: nowrap + `overflow:hidden` sẵn có của `.mud-button-root` sẽ CẮT CỨNG
      chữ thừa (MudBlazor 9 không bọc ChildContent trong span nên không ellipsis được). */
.pnt-nut-file-1dong {
    height: var(--pnt-cao-o);
    white-space: nowrap;
}

/* Ô nhập TRONG BẢNG không khai `Label` (dáng "bảng phẳng" 21/08: tên cột nằm ở hàng tiêu đề, ô dùng
   aria-label) nên lề của chúng là nhánh ĐỐI XỨNG `margin: 4px 0` của MudBlazor — trong dialog app.css
   hạ còn `2px 0`, đúng bằng `--pnt-le-duoi-o`. Mượn lề của ô CÓ NHÃN ở đây là nút tụt 2px so với ô
   cùng hàng (đo 01/10 ở TaoDnttForm và KhachTtGopForm, td căn giữa nên lệch chia đôi). */
table .pnt-nut-file {
    margin-top: var(--pnt-le-duoi-o);
}

/* Ô nhập + icon chú thích (i) đứng cạnh — thay HelperText dài dưới ô (user chốt 01/10: *"dòng 'chỉ
   hiện nguồn tiền…' cũng đang làm form bị xấu, thay vì thế làm 1 nút tooltip kiểu chữ (i)"*).
   Lý do không dùng `Adornment="Adornment.End"`: MudSelect đã có mũi tên xổ + nút ✕ của Clearable,
   nhồi icon thứ ba vào trong ô là chen chỗ của chữ (bẫy "ô chọn hẹp hơn ô text 73px").
   ⚠️ Bề ngang phải cho ô co được: MudTextField gốc là `.mud-input-control { flex: 1 1 auto }` còn
   MudSelect là `.mud-select { flex-grow: 1 }` — khai cả hai + `min-width: 0` để chữ dài không nong
   ô ra khỏi cột lưới. */
.pnt-o-chu-thich {
    display: flex;
    align-items: flex-start;
    gap: 2px;
    position: relative;
}

    .pnt-o-chu-thich > .mud-input-control,
    .pnt-o-chu-thich > .mud-select,
    .pnt-o-chu-thich > .mud-autocomplete,
    .pnt-o-chu-thich > .mud-picker {
        flex: 1 1 auto;
        min-width: 0;
    }

/* Nút (i): style TỰ THÂN, không phụ thuộc div bọc — quên bọc `pnt-o-chu-thich` thì nút vẫn đúng cỡ,
   chỉ mất phần căn dọc. `pnt-icon-chu-thich` nằm trên THẺ BỌC của MudTooltip (RootClass), nên cỡ
   icon phải nhắm vào trong. 22px = 2px đệm + icon 18px: vừa đúng khe trống bên phải ô (xem dưới). */
.pnt-icon-chu-thich {
    flex: 0 0 auto;
    color: var(--mud-palette-text-secondary);
}

    .pnt-icon-chu-thich .mud-icon-button {
        padding: 3px;
        color: inherit;
    }

    .pnt-icon-chu-thich .mud-icon-root {
        font-size: 18px;
        display: block;
    }

/* Câu chú thích ngắn nhưng tooltip của MudBlazor không tự ghìm bề ngang: ở mép phải màn hẹp nó bị
   kẹp lại thành CỘT CHỮ DỌC (đo 01/10 @390px: 58px × 7 dòng, dính mép phải). Ghìm trần + mở sang
   TRÁI (Placement.Left ở ChuThichO) là hết. */
.pnt-tooltip-chu-thich {
    max-width: 240px;
}

/* ≥600px: TREO nút (i) RA NGOÀI mép ô để ô giữ nguyên 100% bề ngang — để nó trong luồng flex thì
   riêng ô có chú thích hụt ~24px so với mọi ô khác, nhìn ra ngay thành "mép phải lởm chởm" (đo 01/10:
   Nguồn chi right=978 trong khi Diễn giải/Ghi chú right=998).
   🔴 KHE TRỐNG CHỈ CÓ 20px — ĐO, ĐỪNG TÍNH NHẨM: mép phải ô = 998, mép phải dialog = 1018. Bản đầu
   cộng nhầm padding của ô lưới vào (25px) nên nút 22px treo ở -24px LÒI 4px ra ngoài viền dialog.
   Nay nút thu còn 18px (icon 18 + padding 0) và treo ở -19px ⇒ chiếm [999 … 1017]: cách ô 1px, cách
   viền 1px. Đổi cỡ icon hay padding dialog thì PHẢI đo lại 2 số này.
   ⚠️ Chỉ dùng cho ô ở CỘT PHẢI hoặc ô full-width; đặt ở cột trái thì nút treo đè sang cột bên cạnh.
   <600px giữ nút trong luồng (khe còn hẹp hơn) — ô lúc đó full-width nên hụt 24px không đáng kể, và
   giữ được vùng chạm 24px cho ngón tay. */
@media (min-width: 600px) {
    .pnt-o-chu-thich > .mud-input-control,
    .pnt-o-chu-thich > .mud-select,
    .pnt-o-chu-thich > .mud-autocomplete,
    .pnt-o-chu-thich > .mud-picker {
        flex: 1 1 100%;
    }

    .pnt-o-chu-thich > .pnt-icon-chu-thich {
        position: absolute;
        right: -19px;
        top: calc((var(--pnt-cao-o) - 18px) / 2 + var(--pnt-le-tren-o));
    }

        .pnt-o-chu-thich > .pnt-icon-chu-thich .mud-icon-button {
            padding: 0;
        }

    /* Ô ở CỘT TRÁI của lưới: bên phải nó là cột khác, chỉ cách đúng gap lưới (10px) ⇒ treo nút ra
       ngoài là ĐÈ sang ô bên cạnh. Thêm `pnt-chu-thich-trong` để nút nằm trong luồng — ô hẹp đi ~24px,
       đổi lại không đè gì; vẫn gọn hơn hẳn HelperText (chiếm ~40px chiều cao và đẩy cả hàng lưới).
       Ô ở cột PHẢI hoặc full-width thì KHÔNG khai class này, để nút treo ra ngoài giữ ô nguyên cỡ. */
    .pnt-o-chu-thich.pnt-chu-thich-trong > .mud-input-control,
    .pnt-o-chu-thich.pnt-chu-thich-trong > .mud-select,
    .pnt-o-chu-thich.pnt-chu-thich-trong > .mud-autocomplete,
    .pnt-o-chu-thich.pnt-chu-thich-trong > .mud-picker {
        flex: 1 1 auto;
    }

    .pnt-o-chu-thich.pnt-chu-thich-trong > .pnt-icon-chu-thich {
        position: static;
        margin-top: calc((var(--pnt-cao-o) - 24px) / 2 + var(--pnt-le-tren-o));
    }

        .pnt-o-chu-thich.pnt-chu-thich-trong > .pnt-icon-chu-thich .mud-icon-button {
            padding: 3px;
        }
}

@media (max-width: 599.98px) {
    /* Trong luồng ⇒ phải tự căn tâm theo Ô (khối còn mang lề trên) */
    .pnt-o-chu-thich > .pnt-icon-chu-thich {
        margin-top: calc((var(--pnt-cao-o) - 24px) / 2 + var(--pnt-le-tren-o));
    }
}

/* ===================== HÀNG CĂN GIỮA CÓ Ô NGÀY: DÒNG LỖI KHÔNG KÉO TỤT CẢ HÀNG (03/10 — việc 1) =====================
   ONgay GIỮ chữ sai kèm dòng lỗi "Ngày không hợp lệ…" dưới ô (ô 170px gãy 3 dòng ⇒ cao thêm 62,7px). Hàng flex/MudGrid căn
   GIỮA (align-center) thì mọi thứ khác CÙNG dòng flex tụt theo nửa phần đó (đo 03/10 ChiTietNcc: ChonFile, ô kia, nút tụt 31,4px).
   Khuôn QuyetToanHdvForm (align-start CỐ ĐỊNH + margin-top) chỉ đúng khi mọi thứ luôn chung MỘT dòng flex. Hàng xuống dòng thì
   KHÔNG: thứ đứng MỘT MÌNH trên dòng được align-center đặt sát mép trên, đứng cạnh ô thì được căn giữa — một margin-top cố định
   không cho ra cả hai. Đo 03/10: ChiTietNcc ở 1536px (thẻ hợp đồng nửa màn, hàng 578px) nút "Tải hợp đồng" xuống dòng 2 một
   mình ⇒ margin-top cố định làm nút tụt 6px NGAY CẢ KHI KHÔNG LỖI; lưới PhienHachToanDialog dưới 600px tách nhiều dòng, ô hết lệch.
   ⇒ CHỈ khi hàng ĐANG CÓ dòng lỗi (`:has`) mới chuyển căn đầu; lúc bình thường không rule nào ở đây khớp ⇒ bố cục giữ nguyên
   tuyệt đối ở mọi bề ngang (mô phỏng 03/10 chèn đúng CSS này + class qua DOM: lệch 0px ở ChiTietNcc 1920/1536/1366/390px và
   PhienHachToanDialog 1536/560/390px). MudBlazor CHỈ vẽ `.mud-input-control-helper-container` khi ô có Error/HelperText/Counter
   ⇒ hàng có ô khai HelperText sẽ căn đầu THƯỜNG TRỰC — đừng gắn class cho hàng đó.
   Cách dùng: hàng gắn `pnt-hang-giu-khi-loi` + khai `--pnt-bu-lech` = độ lệch align-center đang cho thứ đứng cạnh ô lúc bình
   thường; thứ đó gắn `pnt-bu-lech` (mọi bề ngang) hoặc `pnt-bu-lech-sm` (chỉ ≥600px — ô MudGrid chỉ chung dòng với nút từ sm).
   Thứ cao nhất dòng (ô ngày, ChonFile) vốn nằm sát mép trên ⇒ không gắn gì.
   ⚠️ Lệch CHẤP NHẬN: lúc có lỗi, nút đứng một mình ở dòng dưới (ChiTietNcc 1536px) cũng nhận margin-top ⇒ thấp hơn lúc thường
   6px — chỉ trong lúc có lỗi, và dòng đó vốn đã bị dòng lỗi phía trên đẩy xuống. */
.pnt-hang-giu-khi-loi:has(.mud-input-control-helper-container) {
    align-items: flex-start !important; /* đè `.align-center` (MudBlazor khai !important) */
}

.pnt-hang-giu-khi-loi:has(.mud-input-control-helper-container) > .pnt-bu-lech {
    margin-top: var(--pnt-bu-lech, 0px);
}

@media (min-width: 600px) {
    .pnt-hang-giu-khi-loi:has(.mud-input-control-helper-container) > .pnt-bu-lech-sm {
        margin-top: var(--pnt-bu-lech, 0px);
    }
}

/* ===================== Ô NGÀY GÕ SAI: CHỈ VIỀN ĐỎ, KHÔNG DÒNG CHỮ (user chốt 04/10) =====================
   *"khi nhập ngày sai không cần 1 dòng warning ở dưới mà chỉ cần outline đỏ là người dùng tự biết"* ⇒ bản dịch
   Converter_InvalidDateTime để RỖNG (Shared/MudTiengViet.cs). Nhưng MudInputControl 9.8 vẫn dựng khung dòng chữ
   (.mud-input-control-helper-container, margin-top 3px) bọc một <div class="me-auto"> rỗng ⇒ ô cao thêm 3px mỗi lần gõ sai
   (đo 04/10: 36 → 39px) — thanh lọc / hàng form giật xuống. Ẩn khung khi bên trong CHỈ có đúng một .me-auto rỗng: ô có chữ
   lỗi khác (Required, "Ngày kết thúc phải ≥…"), HelperText hay bộ đếm ký tự KHÔNG khớp nên giữ nguyên.
   Khối "HÀNG CĂN GIỮA CÓ Ô NGÀY" ngay trên vẫn khớp khung đã ẩn (:has không phân biệt display) ⇒ hàng chuyển căn đầu + bù
   --pnt-bu-lech — cách bù đó cho ra ĐÚNG vị trí lúc bình thường nên hàng không xê dịch. Trình duyệt chưa có :has() thì chỉ
   còn giật 3px như trước — không hỏng gì. */
.mud-input-control-helper-container:has(> .mud-input-helper-text > .me-auto:empty:only-child) {
    display: none;
}

/* Dòng "Thêm mới" ở ĐẦU danh sách xổ (ô Loại chi phí của form Chi phí khác — user chốt 01/10).
   Xanh lá = màu success của theme, KHÔNG ghim mã màu. Dòng này là một item thật của danh sách nên
   bấm được + đi được bằng bàn phím; `inline-flex` vì ItemTemplate bắt buộc trả <span>. */
.pnt-muc-them-moi {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--mud-palette-success);
    font-weight: 500;
}

    /* Lúc ô còn trống, dòng này chỉ là CÂU HƯỚNG DẪN (MudBlazor đặt pointer-events:none cho item tắt).
       GIỮ MÀU XANH LÁ (user chốt "option đầu là Thêm mới màu xanh lá cây" — đổi sang xám là mất dấu
       hiệu nhận ra nó) nhưng làm NHẠT + bỏ chữ đậm, để không mời bấm một dòng chưa bấm được.
       ⚠️ MudBlazor tự ép `color: rgba(0,0,0,.26)` cho item tắt nên phải khai lại màu, không để inherit. */
    .mud-list-item-disabled .pnt-muc-them-moi {
        color: var(--mud-palette-success);
        opacity: .55;
        font-weight: 400;
    }

/* ===================== CHUẨN 2: Ô "CHỮ NẰM GIỮA Ô" + NÚT ĐỨNG CẠNH (user chốt 28/08) =====================
   Yêu cầu nguyên văn: *"những nút ở những phần sau tăng thêm padding y (thêm 1 chuẩn cho những ô input,
   những ô này có placeholder chữ nên padding y cần thêm, và những nút đứng cạnh nó cần thêm padding y
   để chiều cao ngang với ô input mà nó đứng cạnh)"* — kèm ảnh 8 vùng: thanh lọc/tìm kiếm của các màn
   danh sách (booking · ĐNTT · NCC · khách hàng · HDV · report) và khối chọn của Quick Booking.

   ⚠️ "Ô có placeholder chữ" ở đây KHÔNG chỉ là ô khai Placeholder. Đo 28/08 cho thấy phần lớn là
   MudSelect/MudAutocomplete CÓ `Label` nhưng CHƯA CÓ GIÁ TRỊ — nhãn khi đó chưa "shrink" lên viền mà
   nằm GIỮA ô y như placeholder. Vì vậy đừng nhắm bằng thuộc tính Placeholder; nhắm theo VÙNG.

   Vì sao phải nhắm theo VÙNG chứ không theo từng ô: một thanh lọc luôn trộn ô đã-có-giá-trị (nhãn nổi
   lên viền) với ô chưa-chọn (nhãn giữa ô) — nâng riêng loại sau là hàng ô cao thấp so le, xấu hơn.

   Số đo lấy chuẩn: chữ trong ô chiếm 19px (line-height), chuẩn 1 cho ô 30px ⇒ chỉ còn ~5px trống mỗi
   bên. Chuẩn 2 lấy padding y 7,5px ⇒ ô 7,5 + 19 + 7,5 + 2 (viền) = 36px, trống mỗi bên 7,5px.
   Cách dùng: vùng nào cần thì gắn `pnt-thanh-loc` (thanh lọc/tìm kiếm màn danh sách — đã có sẵn ở 20
   màn) HOẶC `pnt-o-cao` (vùng không phải thanh lọc, vd khối chọn Tour Code của Quick Booking).
   ⚠️ Đổi 36px thì phải sửa THEO 2 thứ: nhãn nổi `translateY = (cao ô − 20)/2 + 2` (36px ⇒ 10px) và
   padding y của ô cho khớp sàn, kẻo nhãn tụt khỏi giữa ô. Ô trong BẢNG và ô trong DIALOG NHẬP LIỆU
   cố ý KHÔNG theo chuẩn này — ở đó ô đã có giá trị nên 30px vẫn đọc tốt và bảng cần gọn. */
/* Đặt lại biến "chiều cao đang hiệu lực" cho cả vùng — mọi thứ dùng var(--pnt-cao-o) bên trong
   (kể cả inline style của ChonFile) tự lên chuẩn 2 mà không cần đè độ đặc hiệu. */
.pnt-thanh-loc,
.pnt-o-cao {
    --pnt-cao-o: var(--pnt-cao-o-lon);
}

/* …trừ BẢNG nằm trong vùng: bảng nhập liệu cần gọn, trả về chuẩn 1 */
.pnt-thanh-loc table,
.pnt-o-cao table {
    --pnt-cao-o: var(--pnt-cao-o-nho);
}

.pnt-thanh-loc .mud-input > input.mud-input-root-outlined.mud-input-root-margin-dense,
.pnt-thanh-loc div.mud-input-slot.mud-input-root-outlined.mud-input-root-margin-dense,
.pnt-o-cao .mud-input > input.mud-input-root-outlined.mud-input-root-margin-dense,
.pnt-o-cao div.mud-input-slot.mud-input-root-outlined.mud-input-root-margin-dense {
    padding-top: 7.5px;
    padding-bottom: 7.5px;
}

.pnt-thanh-loc .mud-input.mud-input-outlined.mud-input-margin-dense,
.pnt-o-cao .mud-input.mud-input-outlined.mud-input-margin-dense {
    min-height: var(--pnt-cao-o-lon);
}

.pnt-thanh-loc .mud-input-label-outlined.mud-input-label-margin-dense,
.pnt-o-cao .mud-input-label-outlined.mud-input-label-margin-dense {
    transform: translate(14px, 10px) scale(1);
}

/* Nút đứng cùng vùng: cao BẰNG ô để không so le (chính là vế thứ 2 user yêu cầu).
   Nút "TẠO BOOKING" của Quick Booking đo được 34px cạnh ô 30px — lệch 4px, thấy rõ trong ảnh.
   ⚠️ Cùng padding y CHƯA đủ để bằng nhau: MudBlazor cho nút `line-height: 1.75` theo cỡ chữ của
   từng Size, nên nút Size.Large (chữ 15px) có nội dung cao 26px trong khi ô chỉ 19px — đo lần đầu
   ra nút 41px cạnh ô 36px, lệch còn NẶNG HƠN trước. Phải ép line-height nút = đúng 19px của ô:
   7,5 + 19 + 7,5 = 34px, cộng viền của kiểu Outlined thành 36px, và sàn kéo nút Filled (không viền)
   lên đúng 36px ⇒ mọi cỡ nút và mọi ô trong vùng cùng một chiều cao. */
.pnt-thanh-loc .mud-button-root:where(:not(.mud-icon-button)):where(:not(.mud-nav-link)):where(:not(.mud-list-item)):where(:not(.mud-tab)):where(:not(.mud-button-close)),
.pnt-o-cao .mud-button-root:where(:not(.mud-icon-button)):where(:not(.mud-nav-link)):where(:not(.mud-list-item)):where(:not(.mud-tab)):where(:not(.mud-button-close)) {
    min-height: var(--pnt-cao-o-lon);
    padding-top: 7.5px;
    padding-bottom: 7.5px;
    line-height: 19px;
}

/* Icon trong nút cao 20px, hơn dòng chữ 19px ⇒ nút CÓ icon đo ra 37px cạnh ô 36px. Hạ 18px để mọi
   nút trong vùng khít đúng 36px (đo được: "Xem nguồn tiền", "Chọn file HĐ"). Chừa nút icon-only —
   ở đó icon LÀ nội dung, thu nhỏ là mất cân đối với nút × / nút lịch nằm trong ô. */
.pnt-thanh-loc .mud-button-root:where(:not(.mud-icon-button)) .mud-icon-root,
.pnt-o-cao .mud-button-root:where(:not(.mud-icon-button)) .mud-icon-root {
    font-size: 18px;
}

/* Chừa lại nút NẰM TRONG ô nhập / trong bảng của chính vùng đó — kéo chúng lên 36px là ô phình gấp đôi.
   ⚠️ Phải khai LẠI ở đây: rule chừa chung phía trên chỉ nặng (0,1,1) nên thua rule vùng (0,2,0). */
.pnt-thanh-loc .mud-input-adornment .mud-button-root,
.pnt-thanh-loc .mud-input-numeric-spin .mud-button-root,
.pnt-thanh-loc table .mud-button-root,
.pnt-o-cao .mud-input-adornment .mud-button-root,
.pnt-o-cao .mud-input-numeric-spin .mud-button-root,
.pnt-o-cao table .mud-button-root {
    min-height: 0;
    padding-top: 4px;
    padding-bottom: 4px;
}

/* Ô nhập trong BẢNG nằm trong vùng (vd bảng tick của KhachTtTheoKyForm) giữ cỡ gọn của chuẩn 1 */
.pnt-thanh-loc table .mud-input.mud-input-outlined.mud-input-margin-dense,
.pnt-o-cao table .mud-input.mud-input-outlined.mud-input-margin-dense {
    min-height: var(--pnt-cao-o);
}

.pnt-thanh-loc table .mud-input > input.mud-input-root-outlined.mud-input-root-margin-dense,
.pnt-thanh-loc table div.mud-input-slot.mud-input-root-outlined.mud-input-root-margin-dense,
.pnt-o-cao table .mud-input > input.mud-input-root-outlined.mud-input-root-margin-dense,
.pnt-o-cao table div.mud-input-slot.mud-input-root-outlined.mud-input-root-margin-dense {
    padding-top: 4px;
    padding-bottom: 4px;
}

.pnt-thanh-loc table .mud-input-label-outlined.mud-input-label-margin-dense,
.pnt-o-cao table .mud-input-label-outlined.mud-input-label-margin-dense {
    transform: translate(14px, 7px) scale(1);
}

/* ===================== THANH NÚT THAO TÁC GỌN (user chốt 28/08) =====================
   *"khi tick dkcp, các nút thu nhỏ lại để có thể đứng cùng 1 dòng, hạn chế xuống dòng kiểu này
   làm xấu giao diện"*. Tick mục làm thanh mọc thêm 2–4 nút (Tạo ĐNTT · Đánh dấu theo dõi công nợ ·
   Ứng HDV · Bỏ ứng HDV) nên hàng nút vỡ xuống 2 dòng, đội cao đầu section và NHẢY LAYOUT ngay lúc
   người dùng đang tick — bảng tụt xuống dưới con trỏ.
   Thu NGANG: padding ngang 10→6px · chữ 13→12px · icon 24→16px · khoảng icon–chữ 8→4px · gap 8→4px.
   ⚠️ CHIỀU CAO + padding y KHÔNG khai ở đây nữa (28/08, sau khi user chốt "1 quy chuẩn padding"):
   nó lấy đúng chuẩn chung phía trên (padding y 4px, sàn 30px). Đây chỉ còn là bài toán BỀ NGANG cho
   thanh có nhiều nút — đo ở màn 1536px, 7 nút phải vừa 1 hàng.
   ⚠️ Vẫn để `flex-wrap` ở div: màn rất hẹp/booking có tiêu đề dài thì cho xuống dòng còn hơn cuộn ngang. */
div.pnt-nut-gon {
    gap: 4px;
}

.pnt-nut-gon .mud-button-root:where(:not(.mud-icon-button)) {
    padding-left: 6px;
    padding-right: 6px;
    font-size: 12px;
}

.pnt-nut-gon .mud-button-root .mud-icon-root {
    font-size: 16px;
}

.pnt-nut-gon .mud-button-icon-start {
    margin-right: 4px;
    margin-left: 0;
}

.pnt-nut-gon .mud-button-icon-end {
    margin-left: 4px;
    margin-right: 0;
}

/* ===================== BỀ NGANG FORM MODAL (user chốt 25/08 — đợt 3) =====================
   "Giảm độ rộng của tất cả các form modal" — sửa 1 chỗ ở đây thay vì đi sửa 36 call site
   `new DialogOptions{MaxWidth=…}` (dễ sót, và trước đó đã dính đúng cảnh 5 call site tự khai).
   Large 1280→1040 · Medium 960→800 · Small 600→500 · ExtraLarge 1920→1400. Bóp qua cỡ dialog ⇒ cột lưới hẹp lại và ô vẫn
   LẤP ĐẦY cột, mép ô thẳng hàng — khác hẳn cách kẹp max-width lên từng ô (đã thử, user báo "vỡ nát").
   Cỡ chọn theo SỐ ĐO bề rộng tối thiểu của nội dung (ép dialog hẹp rồi đọc `table.scrollWidth`),
   không phải cảm tính — xem số cụ thể ở rule ExtraLarge bên dưới.
   ⚠️ Bọc @media min-width:600px — khối mobile ở đầu file đã cho dialog rộng gần hết màn. */
@media (min-width: 600px) {
    .mud-dialog-width-lg {
        max-width: 1040px;
    }

    .mud-dialog-width-md {
        max-width: 800px;
    }

    .mud-dialog-width-sm {
        max-width: 500px;
    }

    /* ExtraLarge (1920px) cũng bị thu — user chỉ vào form Khách thanh toán và nói "vẫn quá to".
       Cỡ 1400px chọn theo SỐ ĐO, không phải cảm tính: bảng rộng nhất trong nhóm này là bảng nhập
       của TaoDnttForm, ép dialog hẹp lại rồi đo `table.scrollWidth` ra **1297px** ⇒ 1400 − 40px đệm
       = 1360 vẫn đủ, không đẩy bảng sang cuộn ngang. Bảng khác: QuyetToanHdvForm 999px (vừa Large
       1040), KhachTtTheoKyForm 754px (vừa Medium 800 — form này đã hạ Large→Medium ở call site). */
    .mud-dialog-width-xl {
        max-width: 1400px;
    }
}


/* ===================== AVATAR BẤM-ĐƯỢC (12/09) — Shared/AnhDaiDien.razor =====================
   Ảnh đại diện NV/HDV nay bấm mở modal xem cỡ lớn ⇒ phải BÁO cho người dùng là bấm được:
   con trỏ tay + vòng sáng khi rê chuột (chỉ khi CÓ ảnh — chữ cái đầu không bấm được nên
   component không gắn class này). inline-flex để không phá hàng flex "avatar + tên" ở 2 màn
   danh sách; border-radius 50% cho vòng sáng ôm đúng hình tròn của MudAvatar. */
.pnt-anh-bam {
    display: inline-flex;
    border-radius: 50%;
    cursor: pointer;
    transition: box-shadow .15s;
}

.pnt-anh-bam:hover {
    box-shadow: 0 0 0 2px var(--mud-palette-primary);
}


/* ============ TRẦN CHIỀU CAO PHẦN XEM FILE (12/09) — Shared/XemFileDialog.razor ============
   Trước 12/09 mỗi nhánh tự ghim vh riêng (ảnh 75vh · PDF 75vh · Excel 70vh · Word 72vh). Từ khi
   chân dialog LUÔN có (nút "Tải về"), modal đội thêm ~51px mà trần vh không đổi ⇒ ĐO ĐƯỢC 12/09:
   viewport 657px (laptop 1366×768 THẬT, đã trừ thanh trình duyệt) ảnh cao 493px nhét trong khung
   491px, viewport 585px ảnh 439px trong khung 419px — ảnh BỊ CẮT ĐÁY và mọc thanh cuộn, đúng thứ
   mà "bấm ảnh xem cỡ lớn" định tránh. Áp cho CẢ 17 call site của XemFileDialog, không riêng avatar.
   Công thức: MudBlazor cho `.mud-dialog { max-height: 100dvh − chiều cao appbar }` (60px, ChuDe.cs),
   trừ tiếp tiêu đề 56 + chân 51 + padding 16 ⇒ chỗ thật còn 100dvh − 183px; lấy 200px để dư 17px.
   Mobile: tiêu đề xuống 2 dòng (đo 88px) và dialog lấy `100% − 16px` nên phải trừ nhiều hơn.
   🔴 ĐỔI chân dialog (thêm/bớt nút, đổi cỡ nút) thì PHẢI ĐO LẠI 2 con số này. */
:root {
    --pnt-cao-xem-file: calc(100dvh - 200px);
}

@media (max-width: 599.98px) {
    :root {
        --pnt-cao-xem-file: calc(100dvh - 240px);
    }
}

/* Ảnh trong modal xem file. Mất file trong kho (đo 12/09: 39/335 ảnh HDV, và phần lớn UNC phiếu
   app cũ) thì hiện câu giải thích thay cho ô trống trơn — class `pnt-anh-hong` do listener pha
   CAPTURE trong pnt.js gắn, KHÔNG dùng onerror nội tuyến (CSP script-src 'self' chặn). */
.pnt-xem-anh img.pnt-anh-kho {
    max-height: var(--pnt-cao-xem-file);
    object-fit: contain;
}

.pnt-xem-anh .pnt-anh-thieu {
    display: none;
}

.pnt-xem-anh img.pnt-anh-hong {
    display: none;
}

.pnt-xem-anh img.pnt-anh-hong + .pnt-anh-thieu {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 32px 8px;
    text-align: center;
}

/* ============================================================
   ẢNH KHO FILE HỎNG — ThongTinAnh + OChonAnh (vá 14/09, rà 07/09 #40)
   Cùng cơ chế với .pnt-xem-anh ở trên: pnt.js (listener pha CAPTURE) gắn `pnt-anh-hong` cho <img
   class="pnt-anh-kho"> bị 404, CSS ẩn ảnh vỡ và bật khối giữ chỗ đứng NGAY SAU nó. 2 component này
   trước đây dùng onerror NỘI TUYẾN — CSP script-src 'self' chặn nên chưa bao giờ chạy (đo 07/09:
   20/245 QR wechat + 39/335 ảnh HDV mất file hiện ảnh vỡ). ⚠️ Thẻ img/khối giữ chỗ KHÔNG được mang
   style nội tuyến: inline thắng stylesheet nên `display:none` ở đây sẽ vô hiệu.
   ============================================================ */

/* --- ThongTinAnh (trang chi tiết HDV): thumbnail 96×96, khối giữ chỗ ĐÚNG 96×96 để lưới không xê dịch,
   và BẤM ĐƯỢC (mở XemFileDialog — modal in nguyên đường dẫn để nhờ quản trị tải lại). --- */
.pnt-tta {
    margin-top: 2px;
}

.pnt-tta-hinh {
    display: block;
    width: 96px;
    height: 96px;
    object-fit: cover;
    border-radius: 8px;
    border: 1px solid var(--mud-palette-lines-default);
    cursor: pointer;
}

.pnt-tta .pnt-anh-thieu {
    display: none;
}

.pnt-tta img.pnt-anh-hong {
    display: none;
}

.pnt-tta img.pnt-anh-hong + .pnt-anh-thieu {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    width: 96px;
    height: 96px;
    box-sizing: border-box;
    padding: 6px;
    border: 1px dashed var(--mud-palette-lines-default);
    border-radius: 8px;
    background: var(--mud-palette-background-grey);
    color: var(--mud-palette-text-secondary);
    font-size: 11px;
    line-height: 1.25;
    text-align: center;
    cursor: pointer;
}

/* --- OChonAnh (ô chọn ảnh 56px trong form): khung BrokenImage thay thumbnail + đổi dòng phụ.
   img · .ocanh-hinh-hong · .ocanh-chu là con TRỰC TIẾP của .ocanh-vung-chon (Razor @if không sinh
   thẻ bọc) nên chọn được bằng `+` / `~`. --- */
.ocanh-vung-chon .ocanh-hinh-hong {
    display: none;
}

.ocanh-vung-chon img.pnt-anh-hong {
    display: none;
}

.ocanh-vung-chon img.pnt-anh-hong + .ocanh-hinh-hong {
    display: flex;
    color: var(--mud-palette-warning);
}

.ocanh-vung-chon .ocanh-chu-phu-hong {
    display: none;
}

.ocanh-vung-chon img.pnt-anh-hong ~ .ocanh-chu .ocanh-chu-phu-thuong {
    display: none;
}

.ocanh-vung-chon img.pnt-anh-hong ~ .ocanh-chu .ocanh-chu-phu-hong {
    display: block;
    color: var(--mud-palette-warning-text);
}

/* Hàng 4 ô (ocanh-hep, chỉ ≥960px) vốn ẨN dòng phụ để thân ô giữ 56px — rule cũ
   `.ocanh-hep .ocanh-chu-phu` chỉ (0,2,0) sẽ THUA selector bật dòng hỏng (0,4,1) ở trên, ô ảnh hỏng
   sẽ phồng quá 56px và vỡ hàng 4 ô vừa căn. Override BẮT BUỘC, đừng gỡ. */
@media (min-width: 960px) {
    .ocanh-hep .ocanh-vung-chon img.pnt-anh-hong ~ .ocanh-chu .ocanh-chu-phu-hong {
        display: none;
    }
}

/* ===================== SỔ THU CHI v2 (trang tài khoản /so-thu-chi/{id}) =====================
   2 class nhỏ dùng riêng cho SoThuChiTaiKhoan.razor; mọi thứ khác dùng class sẵn có
   (pnt-o-cao · bang-khong-xuong-dong · o-co-gian · ttb-chip). */

/* Hàng bấm được ở tab Theo kì + tab Thu về đâu / Chi qua đâu (bấm → tab Sổ chi tiết) */
.stc-hang-bam {
    cursor: pointer;
}

/* Ô Diễn giải của sổ chi tiết: cắt 2 dòng rồi "…", có title xem đủ — line-clamp đặt ở DIV bên
   trong ô (max-width trên td không ghìm được cột ở table-layout auto; DIV mới ghìm được). */
.stc-dien-giai {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    white-space: normal;
    max-width: 420px;
    min-width: 160px;
    line-height: 1.35;
}

/* Tên tài khoản ở màn danh sách /so-thu-chi (user chốt 26/09: "cột tên tài khoản quá to, thu nhỏ lại, có thể để
   tên 2 dòng"): ghim CỐ ĐỊNH 230px, xuống 2 dòng rồi "…", title xem đủ tên. Đo 26/09: tên dài nhất 506px nằm 1 dòng
   kéo cột lên 538px ⇒ bảng 1820px trong khung 1568px (màn 1868) phải cuộn ngang. 230 (không phải 250) là số chốt sau khi
   gọn cả bảng (.stc-ds-tk bên dưới) để vừa khung 1194px của màn 1494px ngay cả khi cột tiền mang số hàng chục tỷ.
   ⚠️ min-width PHẢI bằng max-width: bảng có cột o-co-gian (Ngân hàng, width:100%) hút hết chỗ nên để min thấp là cột tên
   bị bóp về đúng mức min (đo: min 140px ⇒ cột 172px, 5 tên dài bị cắt dù bảng còn chỗ).
   line-clamp đặt ở DIV bên trong ô (cùng lý do .stc-dien-giai). */
.stc-ten-tk {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    white-space: normal;
    overflow-wrap: anywhere;
    width: 230px;
    line-height: 1.35;
}

/* Bảng danh sách tài khoản /so-thu-chi GỌN CHO VỪA 1 MÀN (user chốt 26/09: "đỡ phải cuộn ngang"). Đo trước khi gọn:
   bảng 1564px (đã thu cột tên) trong khung 1194px ở màn 1494px (= 1868 phóng 125%, đúng máy user). Lề ô 16 → 10px,
   tiêu đề được xuống dòng, sàn o-co-gian (Cảnh báo) hạ về 0 để cột cuối chỉ hút chỗ THỪA chứ không đội bề ngang bảng.
   Selector phải nhắc .mud-simple-table + thead/tbody mới thắng rule dense của MudBlazor (bài học bảng Sửa nhanh DKCP). */
.mud-simple-table.stc-ds-tk table thead tr > th,
.mud-simple-table.stc-ds-tk table tbody tr > td {
    /* 16 → 10px (26/09). ⚠️ ĐỪNG hạ xuống 8px nữa: bản 28/09 từng hạ 8px chỉ để mua 32px cho bảng
       vừa khung 1194px, nhưng user chốt LẠI 28/09 *"không nhất thiết phải ép về khớp 1 màn hình,
       có thể cuộn được"* ⇒ ưu tiên chữ thoáng, bảng cuộn ngang là chấp nhận được. */
    padding-left: 10px;
    padding-right: 10px;
}
/* Tiêu đề KHÔNG xuống dòng — mỗi tên cột nằm gọn 1 dòng (user chốt 28/09 cho phép cuộn ngang).
   Bản 26/09 cố ý cho tiêu đề xuống dòng để bóp bảng cho vừa 1 màn; nay bỏ hẳn, vì đúng thứ user
   chê trong ảnh là tiêu đề bị bẻ ("Vào tháng"/"này", "Ngày nhập"/"quỹ").
   Bỏ `white-space: normal` là đủ — nền chung .bang-khong-xuong-dong th đã nowrap. */
.mud-simple-table.stc-ds-tk table thead tr > th {
    vertical-align: bottom;
}
/* 3 CỘT TIỀN (Số dư hiện tại · Vào tháng này · Ra tháng này) — user chốt 28/09:
   "kéo dài cột vào/ra tháng này ra vì những cột liên quan đến tiền cần khoảng to như phần
   số dư hiện tại để tránh ngắt dòng" + "cột nào liên quan đến tiền không được để xuống dòng".
   140px = SÀN CHUNG cho cả 3 cột — đó là thứ kéo "Vào/Ra tháng này" (giá trị thường chỉ "0 ₫"
   ⇒ cột co về 107px) lên ngang cột Số dư. Số đo 28/09 (lề ô 10px mỗi bên): chuỗi dài nhất cột
   Số dư "-10.862.290.114 ₫" = 122 + 20 = 142; tiêu đề "Vào tháng này" nowrap = 93 + 20 = 113.
   🔴 min-width là SÀN, KHÔNG phải ép bằng nhau: table-layout:auto không có cơ chế ép 3 cột bằng
   nhau, và ở bảng này nội dung vốn lệch (Số dư là số hàng chục tỷ, Vào/Ra thường là "0 ₫").
   Tiền có PHẦN THẬP PHÂN (từ 26/09 in tới 10 số lẻ, KHÔNG làm tròn) thì cột tự nong — đo 28/09
   với 1 phiếu 2.580.645,1612903226 ₫ trên DB dev: cột Số dư 223px, bảng vượt khung ⇒ cuộn ngang.
   Đó là CHẤP NHẬN ĐƯỢC: user chốt 28/09 "không nhất thiết phải ép về khớp 1 màn hình, có thể
   cuộn được" — đừng "sửa" bằng cách làm tròn hiển thị hay cho tiền xuống dòng.
   Đặt cho CẢ th LẪN td (cùng khuôn .tdf-sotien/.ktg-sotien): chỉ đặt ở th thì ô dữ liệu vẫn
   kéo cột hẹp lại khi giá trị chỉ là "0 ₫". */
.mud-simple-table.stc-ds-tk table thead tr > th.stc-cot-tien,
.mud-simple-table.stc-ds-tk table tbody tr > td.stc-cot-tien {
    min-width: 140px;
    white-space: nowrap;
}
.bang-khong-xuong-dong.stc-ds-tk th.o-co-gian,
.bang-khong-xuong-dong.stc-ds-tk td.o-co-gian {
    min-width: 0;
}
/* Ngân hàng dưới STK: chữ nhỏ mờ, tối đa 2 dòng rồi "…" (tên chi nhánh Vietcombank dài 52 ký tự) */
.stc-ngan-hang {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    white-space: normal;
    width: 180px;
    font-size: 12px;
    line-height: 1.3;
    color: var(--mud-palette-text-secondary);
}

/* ===================== SỔ THU CHI v2 — MÀN TỔNG HỢP /so-thu-chi (04/10/2026, docs/SO_THU_CHI_V2.md mục 15.5) =====================
   Bảng tổng hợp theo kì (STT · Nội dung · Thu · Chi · Tồn · Ghi chú) + Chi tiết số dư + bảng dòng xổ dưới hàng hạng mục.
   Dùng lại .stc-hang-bam · .stc-dien-giai · .bang-khong-xuong-dong · .o-co-gian; MỌI ô (tiêu đề + dữ liệu, kể cả tiền) căn
   TRÁI theo luật toàn app 04/10 (KHÔNG gõ text-align vào th/td). Trang không cuộn ngang ở 390px: bảng cuộn TRONG khung .stc-cuon. */
.stc-cuon {
    overflow-x: auto;
    max-width: 100%;
}
.mud-simple-table.stc-tong-hop table thead tr > th,
.mud-simple-table.stc-tong-hop table tbody tr > td {
    padding-left: 10px;
    padding-right: 10px;
}
/* Cột tiền: nowrap + sàn chung (cùng số đo 140px của .stc-ds-tk); căn lề theo luật toàn app (trái — 04/10 bỏ text-align:right) */
.mud-simple-table.stc-tong-hop table thead tr > th.stc-cot-tien,
.mud-simple-table.stc-tong-hop table tbody tr > td.stc-cot-tien {
    min-width: 140px;
    white-space: nowrap;
}
/* Hàng Dư đầu kỳ / Số dư cuối kì: đậm; hàng Tổng: đậm + nền xám nhẹ (cùng nếp hàng tổng nhóm của bảng cũ) */
.mud-simple-table.stc-tong-hop table tbody tr.stc-hang-dam > td {
    font-weight: 700;
}
.mud-simple-table.stc-tong-hop table tbody tr.stc-hang-tong > td {
    font-weight: 700;
    background: var(--mud-palette-background-gray);
}
/* Hàng con xổ dưới hạng mục: ô ôm trọn bảng dòng, nền xám nhẹ để tách khỏi hàng cha; hover của bảng cha không đổi màu nó */
.mud-simple-table.stc-tong-hop table tbody tr.stc-hang-con > td {
    padding: 0 0 8px 28px;
    background: var(--mud-palette-background-gray);
    white-space: normal;
}
.mud-simple-table.stc-tong-hop table tbody tr.stc-hang-con:hover > td {
    background: var(--mud-palette-background-gray);
}
/* Khung cuộn của bảng con KHÔNG góp min-content vào bảng ngoài (bảng ngoài table-layout:auto khi chưa kéo cột): thiếu rule này
   thì kéo giãn 1 cột bảng con (bảng con đóng băng có min-width = Σ cột) làm cột Nội dung của bảng NGOÀI nở đúng dx (rà 04/10).
   width:0 + min-width:100% = đóng góp 0 vào bề ngang tối thiểu, bề ngang thật vẫn = ô ⇒ bảng con cuộn trong khung riêng. */
.mud-simple-table.stc-tong-hop table tbody tr.stc-hang-con > td > .stc-cuon {
    width: 0;
    min-width: 100%;
}
/* Bảng dòng bên trong: chữ nhỏ hơn 1 nấc, cột tiền sàn thấp hơn (chỉ có số, không có tổng chục tỷ của cả khối) */
.mud-simple-table.stc-bang-con {
    font-size: 12.5px;
}
.mud-simple-table.stc-bang-con table thead tr > th.stc-cot-tien,
.mud-simple-table.stc-bang-con table tbody tr > td.stc-cot-tien {
    min-width: 120px;
    white-space: nowrap;
}
/* Mũi tên xổ/gấp đứng trước tên hạng mục; chữ phụ (số dòng, ngày của tiêu đề cột) nhỏ mờ */
.stc-mui-ten {
    vertical-align: -4px;
    margin-right: 2px;
    color: var(--mud-palette-text-secondary);
}
.stc-phu {
    font-size: 11.5px;
    font-weight: 400;
    color: var(--mud-palette-text-secondary);
}
/* Nút "Xem toàn bộ" cuối ô Nội dung của hàng hạng mục (04/10): MudButton Small cao ~30px, hàng dense chỉ ~31px ⇒ lề âm
   trên/dưới để nút KHÔNG nong cao hàng (16+ hàng/bảng — đo 04/10: hàng có nút = hàng không nút); chữ không xuống dòng khi
   cột Nội dung bị kéo hẹp. */
.stc-nut-xem {
    margin-top: -5px;
    margin-bottom: -5px;
    white-space: nowrap;
}

/* ============================================================
   KÉO ĐỔI ĐỘ RỘNG CỘT — js/keo-cot.js (04/10/2026)
   JS gắn <span class="pnt-keo-cot"> vào cuối mỗi th của HÀNG TIÊU ĐỀ ĐẦU; lần kéo đầu
   "đóng băng" bảng: class pnt-keo-cot-co-dinh + biến --pnt-keo-w (từng th) / --pnt-keo-min
   (table). Mọi thuộc tính thật nằm Ở ĐÂY và đọc qua biến, JS không ghi width inline — nhờ vậy
   khối @media chế độ thẻ dọc (mud-xs/sm/md-table) phía dưới TẮT được toàn bộ bằng CSS.
   !important là cố ý: chế độ đóng băng phải thắng mọi width/min-width của từng bảng
   (.o-co-gian width:100% · .stc-cot-tien min-width · Style inline trên MudTh…); thắng
   được chúng thì mới điều khiển được bề ngang từng cột.
   Luật & bẫy: docs/architecture/frontend.md › "KÉO ĐỔI ĐỘ RỘNG CỘT".
   ============================================================ */
/* th được định vị để tay kéo (absolute) bám theo — ĐẶC HIỆU THẤP (0,0,3) là cố ý: rule sticky theo @media
   (.pnt-ghim-cot thead tr > th:first-child dưới 600px · .pnt-ds-cuon thead th) đặc hiệu (0,1,x) phải thắng, và
   th phải tự đổi theo @media khi xoay màn/bật tắt "Xem toàn bộ". Bản đầu 04/10 ghi inline position:relative bằng JS:
   inline thắng @media ⇒ th cột ghim mất ghim khi thu màn, tay kéo lạc thành dải 7px cao cả trang khi nới màn (rà 04/10). */
:where(table.pnt-keo-cot-bang) > thead > tr > th {
    position: relative;
}

.pnt-keo-cot {
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    width: 7px;
    cursor: col-resize;
    touch-action: none;
    user-select: none;
    z-index: 3;
}

.pnt-keo-cot::after {
    content: '';
    position: absolute;
    top: 20%;
    bottom: 20%;
    right: 2px;
    width: 2px;
    border-radius: 1px;
    background: var(--mud-palette-primary);
    opacity: 0;
    transition: opacity .12s, top .12s, bottom .12s;
}

.pnt-keo-cot:hover::after,
.pnt-keo-cot.pnt-keo-cot-dang::after {
    opacity: .75;
    top: 0;
    bottom: 0;
}

/* Đang kéo: con trỏ + cấm bôi đen trên toàn trang (chuột đi ra ngoài th vẫn đúng con trỏ) */
body.pnt-dang-keo-cot,
body.pnt-dang-keo-cot * {
    cursor: col-resize !important;
    user-select: none !important;
}

/* Bảng ĐÃ ĐÓNG BĂNG: fixed + đầy khung + min-width theo Σ bề ngang MỌI cột (luật kéo 04/10 chiều: giãn ĐẨY các cột sau,
   thu KÉO chúng lên, co tới khung thì cột ngay sau ăn phần trống). Đúng 1 cột width:auto ăn phần DƯ khi Σ < khung: lúc nghỉ
   là cột hút, lúc kéo là cột NGAY SAU cột đang kéo (cột cuối: chính nó) — keo-cot.js đổi qua biến --pnt-keo-w = auto.
   min-width = max(--pnt-keo-min, min(--pnt-keo-tong, --pnt-keo-dan + 100%)): lúc nghỉ --pnt-keo-min = Σ với cột hút ở SÀN TỰ
   NHIÊN b (220 / nội dung không gãy được), --pnt-keo-tong = Σ SỐ LƯU (không gồm phần nở bảo vệ — 2.3: cột khác nở bảo vệ thì
   cột hút nhường phần dư trước khi bảng tràn), --pnt-keo-dan = Σ số lưu − bề ngang khung lúc bấm c ⇒ khung CO dưới c
   (mở menu trái, màn hẹp hơn, thanh cuộn dọc hiện) thì cột hút TRẢ phần nở, không nhỏ hơn b; khung NỞ trên c thì bảng =
   max(khung, Σ) — phần tràn cũ giảm dần, cột hút chỉ ăn khi bảng đã vừa khung. Bản 2.1 không có trần Σ: bảng vốn tràn mà nới
   khung thì cột hút phình đúng phần nở, tràn giữ nguyên. Lúc kéo / bảng không co giãn theo khung: 2 biến sau không đặt ⇒
   min(0px, …) ≤ 0, min-width = Σ.
   Biến tùy biến DI TRUYỀN: bảng con lồng trong ô của bảng đã đóng băng (hàng xổ /so-thu-chi) ăn biến của bảng cha — kéo +10px
   một cột bảng con là bảng con nở 400–640px (rà 04/10, bản 2.1) ⇒ đặt lại = initial ở đây (giá trị JS ghi inline vẫn thắng). */
table.pnt-keo-cot-co-dinh {
    --pnt-keo-min: initial;
    --pnt-keo-tong: initial;
    --pnt-keo-dan: initial;
    --pnt-keo-rong: initial;
    table-layout: fixed !important;
    width: 100% !important;
    min-width: max(var(--pnt-keo-min, 0px), min(var(--pnt-keo-tong, 0px), calc(var(--pnt-keo-dan, -100000px) + 100%))) !important;
}

/* Bảng vốn hẹp hơn khung lúc đóng băng (không đầy khung): bề ngang = max(sàn bảng lúc đóng băng, Σ) — JS tính sẵn vào
   --pnt-keo-rong; co tới sàn đó thì cột auto ăn phần trống y như bảng đầy khung. */
table.pnt-keo-cot-co-dinh.pnt-keo-cot-rong-tu {
    width: var(--pnt-keo-rong, var(--pnt-keo-min, auto)) !important;
}

table.pnt-keo-cot-co-dinh > thead > tr > th {
    width: var(--pnt-keo-w, auto) !important;
    min-width: 0 !important;
    max-width: none !important;
    box-sizing: border-box;
}

/* Ô cố định bề ngang: chữ XUỐNG DÒNG thay vì cắt "…" (user chốt 04/10 kèm ảnh cột "Mã booki…": "khi kéo nhỏ cột thì
   thay vì ellipsis hãy để word wrap"). Mặc định chỉ gãy ở DẤU CÁCH (overflow-wrap:normal): từ dài hơn cột thì TRÀN ⇒ lượt bảo
   vệ của keo-cot.js đo tràn và nở cột cho vừa — bảng sinh đôi / trang sau nhận bề ngang hẹp hơn chữ của nó không bị bẻ giữa từ
   (bản 2.1 để anywhere cho mọi ô: "Công tác phí" thành "Côn/g/tác/phí", "21/09/2026" thành "21/09/202/6" — rà 04/10).
   Tiêu đề cũng chỉ gãy ở dấu cách (anywhere làm tiêu đề gãy TỪNG CHỮ CÁI — "Người thụ hưởng/Nội dung" cao 474px ở bản đầu).
   overflow:hidden chỉ còn là lưới an toàn. Bản đầu 04/10 dùng text-overflow:ellipsis — đã bỏ theo yêu cầu user, đừng khôi phục. */
table.pnt-keo-cot-co-dinh > thead > tr > th,
table.pnt-keo-cot-co-dinh > tbody > tr > td,
table.pnt-keo-cot-co-dinh > tbody > tr > th,
table.pnt-keo-cot-co-dinh > tfoot > tr > td,
table.pnt-keo-cot-co-dinh > tfoot > tr > th {
    overflow: hidden;
    white-space: normal;
    overflow-wrap: normal;
}

/* Cột người dùng đã THU (keo-cot.js đánh dấu data-pnt-be trên từng ô của cột; cột đang kéo mang tạm suốt lượt kéo): chữ được
   gãy GIỮA TỪ — kéo hẹp cột mã thì mã dài không dấu cách (STRESS29_A01_ND01) gãy thay vì tràn. Không áp tiêu đề. */
table.pnt-keo-cot-co-dinh > tbody > tr > td[data-pnt-be],
table.pnt-keo-cot-co-dinh > tbody > tr > th[data-pnt-be],
table.pnt-keo-cot-co-dinh > tfoot > tr > td[data-pnt-be],
table.pnt-keo-cot-co-dinh > tfoot > tr > th[data-pnt-be] {
    overflow-wrap: anywhere;
}

/* Ô NGÀY/GIỜ (data-pnt-tu): chỉ gãy ở DẤU CÁCH kể cả ở cột đã thu — "21/09/2026 14:30" xuống 2 dòng được, số không bị bẻ. */
table.pnt-keo-cot-co-dinh > tbody > tr > td[data-pnt-tu],
table.pnt-keo-cot-co-dinh > tbody > tr > th[data-pnt-tu],
table.pnt-keo-cot-co-dinh > tfoot > tr > td[data-pnt-tu],
table.pnt-keo-cot-co-dinh > tfoot > tr > th[data-pnt-tu] {
    overflow-wrap: normal;
}

/* Style="white-space:nowrap" NỘI TUYẾN trên ô (MudTd "Thời gian" /lich-su-chinh-sua, "Sửa lần cuối" /kho-file) hoặc DIV con
   trực tiếp (tên NV/HDV kèm ảnh): nội tuyến thắng mọi rule thường ⇒ cột kéo không thu được px nào (rà 04/10). Bảng ĐÃ KÉO: cho
   xuống dòng ở dấu cách. SPAN nowrap giữ nguyên (cụm chip + icon, số tiền). Ô số, ô tiền, nút, chip vẫn 1 dòng nhờ các rule
   !important bên dưới (đặc hiệu cao hơn). */
table.pnt-keo-cot-co-dinh > tbody > tr > td[style*="nowrap"],
table.pnt-keo-cot-co-dinh > tbody > tr > td > div[style*="nowrap"],
table.pnt-keo-cot-co-dinh > tfoot > tr > td[style*="nowrap"],
table.pnt-keo-cot-co-dinh > tfoot > tr > td > div[style*="nowrap"] {
    white-space: normal !important;
}

/* Ô SỐ / TIỀN / % do keo-cot.js đánh dấu data-pnt-so (chữ khớp MAU_SO — cả số trần không nhóm nghìn "1162", "-70354,5%"; kể
   cả ô nhiều dòng tiền) — GIỮ 1 DÒNG: số bị bẻ giữa chừng là đọc sai tiền (luật 28/09). Số dài hơn bề ngang cột thì TRÀN
   (không gãy) ⇒ lượt bảo vệ đo tràn và nở cột cho vừa. !important + đặc hiệu (0,2,4)/(0,3,4) thắng rule nội tuyến ở trên. */
table.pnt-keo-cot-co-dinh > tbody > tr > td[data-pnt-so],
table.pnt-keo-cot-co-dinh > tbody > tr > td[data-pnt-so] > [style*="nowrap"],
table.pnt-keo-cot-co-dinh > tfoot > tr > td[data-pnt-so],
table.pnt-keo-cot-co-dinh > tfoot > tr > td[data-pnt-so] > [style*="nowrap"] {
    white-space: nowrap !important;
    overflow-wrap: normal;
}

/* Ô TIỀN đánh dấu class vẫn KHÔNG xuống dòng (luật user 28/09 "cột tiền không được xuống dòng") — keo-cot.js không cho
   bóp chúng dưới bề ngang nội dung nên cũng không bị cắt. Selector lặp đủ chuỗi tổ tiên cho đặc hiệu (0,2,4) > rule
   xuống dòng (0,1,4); !important thắng rule nội tuyến. Ô tiền KHÔNG có class được keo-cot.js nhận dạng theo chữ. */
table.pnt-keo-cot-co-dinh > tbody > tr > td.pnt-cot-tien,
table.pnt-keo-cot-co-dinh > tbody > tr > td.stc-cot-tien,
table.pnt-keo-cot-co-dinh > thead > tr > th.pnt-cot-tien,
table.pnt-keo-cot-co-dinh > thead > tr > th.stc-cot-tien,
table.pnt-keo-cot-co-dinh > tfoot > tr > td.pnt-cot-tien,
table.pnt-keo-cot-co-dinh > tfoot > tr > td.stc-cot-tien {
    white-space: nowrap !important;
    overflow-wrap: normal;
}

/* Nút + chip trong bảng đã đóng băng GIỮ 1 DÒNG (thứ không gãy được) ⇒ ép cột hẹp thì chúng TRÀN, keo-cot.js đo tràn để đặt
   sàn kéo / nở cột bảo vệ. Nhãn nút mà được gãy thì nút bị bẻ 2–3 dòng khi kéo hẹp. Ô "chữ + nút" (cột Nội dung /so-thu-chi
   có nút Xem toàn bộ) vẫn hẹp được tới chữ gãy hết — sàn = nút + phần chữ không gãy được. Lớp nhân đôi = đặc hiệu (0,3,1),
   thắng rule nowrap nội tuyến (0,2,5) khi nút/chip là div con mang Style nowrap. */
table.pnt-keo-cot-co-dinh .mud-button-root.mud-button-root,
table.pnt-keo-cot-co-dinh .mud-chip.mud-chip,
table.pnt-keo-cot-co-dinh .ttb-chip.ttb-chip {
    white-space: nowrap !important;
}

/* MudChip mặc định max-width:100% (MudBlazor) — ô bị ép hẹp thì chip CO theo ô thay vì TRÀN: chip bấm được (overflow:hidden)
   tự cắt chữ bên trong ("01/10/202", "Ứng 1"), ô chỉ "tràn" đúng 8px lề chip ⇒ sàn kéo / lượt bảo vệ không thấy bề ngang thật,
   còn lượt bảo vệ thì nở 8px sau mỗi lần thả (rà 04/10, bản 2.1). Bỏ kẹp ⇒ chip lòi ra như nút, đo tràn bắt được. */
table.pnt-keo-cot-co-dinh .mud-chip {
    max-width: none;
    flex-shrink: 0;
}

/* Phần tử TỰ CẮT chữ trong ô — kẹp dòng (-webkit-line-clamp: .stc-dien-giai sổ chi tiết, .dsb-kh-noi "Khách hàng" /booking,
   .uh-cat-2-dong dialog ứng HDV, div Style line-clamp tên NCC ở trang booking / dialog DNTT…) và 1 dòng + "…" (.pnt-cat-chu ví
   /chuyen-tien-noi-bo) — trong bảng ĐÃ KÉO: bề ngang do người dùng đặt ⇒ xuống dòng ĐỦ, không giấu chữ (user 04/10: "thay vì
   ellipsis hãy để word wrap"). Chúng CO theo ô nên keo-cot.js đo tràn không thấy (kẹp dòng giấu theo chiều DỌC, "…" cắt bên trong
   phần tử) — rà 04/10. !important để thắng Style nội tuyến. Chỉ ô của CHÍNH bảng (>): bảng con trong hàng xổ chỉ đổi khi chính
   nó được kéo. Phần tử mới kiểu này trong ô bảng: thêm class vào đây. */
table.pnt-keo-cot-co-dinh > tbody > tr > td > [style*="line-clamp"],
table.pnt-keo-cot-co-dinh > tbody > tr > td > .stc-dien-giai,
table.pnt-keo-cot-co-dinh > tbody > tr > td > .dsb-kh-noi,
table.pnt-keo-cot-co-dinh > tbody > tr > td > .uh-cat-2-dong,
table.pnt-keo-cot-co-dinh > tbody > tr > td > .pnt-cat-chu {
    display: block !important;
    -webkit-line-clamp: unset !important;
    overflow: visible !important;
    text-overflow: clip !important;
    white-space: normal !important;
    min-width: 0 !important;
    max-width: none !important;
}

/* Chế độ THẺ DỌC của MudTable (Breakpoint) — thead ẩn, mỗi ô thành 1 dòng: tắt hẳn đóng băng,
   không thì min-width hàng nghìn px ép điện thoại cuộn ngang. Ngưỡng khớp MudBlazor.min.css. overflow-wrap:normal: bảng đã
   đóng băng sang thẻ dọc mà giữ anywhere là "60" ở /booking bị bẻ thành "6/0" (rà 04/10). */
@media (max-width: 600px) {
    .mud-xs-table table.pnt-keo-cot-co-dinh { table-layout: auto !important; width: 100% !important; min-width: 0 !important; }
    .mud-xs-table table.pnt-keo-cot-co-dinh > thead > tr > th { width: auto !important; }
    .mud-xs-table table.pnt-keo-cot-co-dinh > tbody > tr > td { overflow: visible; overflow-wrap: normal; }
}

@media (max-width: 960px) {
    .mud-sm-table table.pnt-keo-cot-co-dinh { table-layout: auto !important; width: 100% !important; min-width: 0 !important; }
    .mud-sm-table table.pnt-keo-cot-co-dinh > thead > tr > th { width: auto !important; }
    .mud-sm-table table.pnt-keo-cot-co-dinh > tbody > tr > td { overflow: visible; overflow-wrap: normal; }
}

@media (max-width: 1280px) {
    .mud-md-table table.pnt-keo-cot-co-dinh { table-layout: auto !important; width: 100% !important; min-width: 0 !important; }
    .mud-md-table table.pnt-keo-cot-co-dinh > thead > tr > th { width: auto !important; }
    .mud-md-table table.pnt-keo-cot-co-dinh > tbody > tr > td { overflow: visible; overflow-wrap: normal; }
}

/* ============================================================
   ĐƯỜNG KẺ DỌC GIỮA CÁC CỘT — TOÀN APP (user chốt 04/10/2026, nguyên văn:
   "các cột cần có đường kẻ ngăn", kèm ảnh /booking)
   Trước đó chỉ 25 file section khai Bordered="true" (MudBlazor kẻ tbody, KHÔNG kẻ thead
   của MudSimpleTable), còn mọi bảng danh sách (MudTable ServerData) không kẻ ⇒ lệch nhau.
   Nay kẻ ở 1 chỗ cho cả thead · tbody · tfoot của MudTable + MudSimpleTable, màu đúng
   đường kẻ ngang (--mud-palette-table-lines), ô CUỐI hàng không kẻ (bảng đã có viền ngoài).
   Ô colspan (hàng "Không có dữ liệu", hàng loading, hàng con) là ô cuối nên cũng không kẻ.
   Bảng đã khai Bordered giữ nguyên (cùng giá trị). Bảng chấm công .bcc-bang tự có viền riêng.
   Độ đặc hiệu (0,2,2) — thua rule gốc Bordered (0,5,x) nhưng cùng giá trị nên vô hại;
   chế độ THẺ DỌC (Breakpoint: ô thành dòng flex) phải TẮT kẻ dọc, khối @media bên dưới
   (0,3,0) thắng — đặt SAU rule chính, đừng dời.
   ============================================================ */
.mud-table-root thead th:not(:last-child),
.mud-table-root tbody td:not(:last-child),
.mud-table-root tbody th:not(:last-child),
.mud-table-root tfoot td:not(:last-child),
.mud-table-root tfoot th:not(:last-child),
.mud-simple-table table thead th:not(:last-child),
.mud-simple-table table tbody td:not(:last-child),
.mud-simple-table table tbody th:not(:last-child),
.mud-simple-table table tfoot td:not(:last-child),
.mud-simple-table table tfoot th:not(:last-child) {
    border-right: 1px solid var(--mud-palette-table-lines);
}

@media (max-width: 600px) {
    .mud-xs-table .mud-table-root .mud-table-cell { border-right: none; }
}

@media (max-width: 960px) {
    .mud-sm-table .mud-table-root .mud-table-cell { border-right: none; }
}

@media (max-width: 1280px) {
    .mud-md-table .mud-table-root .mud-table-cell { border-right: none; }
}

/* ===================== MÀN DANH MỤC Khoản thu / Chi phí khác (04/10) — Pages/TaiChinh/DanhMucThuChiKhac.razor =====
   2 ô tổng BẤM ĐƯỢC "Tất cả" · "Chưa có danh mục" đứng trên bảng danh mục (user: bấm module ra danh sách các khoản,
   có 1 phần riêng cho dòng chưa chia danh mục). Viền cam = còn dòng chưa có danh mục. Dòng tiền KHÔNG xuống dòng
   (luật tiền 15/08) — hẹp thì cắt "…", rê chuột xem đủ (title). */
.pnt-dm-o {
    flex: 1 1 280px;
    max-width: 460px;
    cursor: pointer;
    user-select: none;
}

.pnt-dm-o:hover {
    background: var(--mud-palette-action-default-hover);
}

.pnt-dm-o:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 2px;
}

.pnt-dm-o-canh {
    border-color: var(--mud-palette-warning) !important;
}

.pnt-dm-o-tien {
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
