/* ══════════════════════════════════════════════════════════════════════════
   app.mobile.css — Design tokens cho Mobile UI (iOS Premium / Glass)
   Nguồn: Mobile.Prototype/styles/tokens.css (giữ giá trị 1:1).
   Chỉ chứa TOKEN dùng chung; style từng trang đặt ở {Page}.mobile.css,
   component dùng chung đặt ở file CSS riêng của component.

   AN TOÀN DESKTOP: các tên biến dưới đây (--color-*, --primary, --surface,
   --radius*, --grad-*, --glass-*, ...) đã được kiểm tra KHÔNG trùng với
   wwwroot/css/app.css và KHÔNG trùng namespace --mud-* của MudBlazor, nên đặt
   ở :root không ảnh hưởng desktop (chỉ có hiệu lực ở nơi .Mobile component
   tham chiếu tới). Giữ đúng tên như prototype để tái dùng được CSS component
   của prototype khi dựng từng trang.
   ══════════════════════════════════════════════════════════════════════════ */
:root {

  /* ── 1. COLOR — Brand ─────────────────────────────────────────────── */
  --color-primary:        #594AE2;   /* Mud Primary (UviWash purple) */
  --color-primary-light:  #7B6BF0;   /* hero gradient start */
  --color-primary-dark:   #4A3BD4;   /* pressed / text on tint */
  --color-primary-soft:   #ECEAFB;   /* tint surface (~8% primary) */
  --color-primary-tint:   rgba(89,74,226,.12);  /* avatar / icon chip tint */
  --color-accent:         #F59E0B;   /* logo amber — use sparingly */

  /* ── COLOR — Semantic / status (color = meaning) ──────────────────── */
  --color-success:        #00C853;   --color-success-soft: #E3F8EC;
  --color-info:           #2196F3;   --color-info-soft:    #E6F2FD;
  --color-warning:        #FB8C00;   --color-warning-soft: #FFF2E0;
  --color-danger:         #F44336;   --color-danger-soft:  #FEEAE9;
  --color-neutral:        #757575;

  /* ── COLOR — Extended accents ─────────────────────────────────────── */
  --color-teal:   #009688;   --color-pink:  #E91E63;   --color-indigo: #3F51B5;
  --color-cyan:   #00BCD4;   --color-amber: #FFB300;

  /* ── COLOR — Surfaces ─────────────────────────────────────────────── */
  --color-background:     #E8E6F4;   /* app backdrop behind phone frame */
  --color-canvas:         #F4F2FB;   /* tonal screen canvas */
  --color-surface-sunken: #FAFAFC;   /* total rows / inset panels */
  --color-card:           #FFFFFF;
  --color-avatar-bg:      #EDEDF4;
  --color-avatar-fg:      #616161;

  /* ── COLOR — Text ─────────────────────────────────────────────────── */
  --color-text-primary:   rgba(0,0,0,.87);
  --color-text-secondary: rgba(0,0,0,.60);
  --color-text-muted:     rgba(0,0,0,.38);
  --color-text-on-brand:  #FFFFFF;

  /* ── COLOR — Lines & borders ──────────────────────────────────────── */
  --color-border:    #E2DFEE;
  --color-line:      #ECEAF3;
  --color-hairline:  rgba(60,60,67,.16);

  /* ── COLOR — Gradients (focal use only) ───────────────────────────── */
  --grad-hero:  linear-gradient(135deg, #7B6BF0 0%, #4A3BD4 100%);
  --grad-blue:  linear-gradient(140deg, #42A5F5 0%, #1E6FE0 100%);
  --grad-green: linear-gradient(140deg, #2BD46E 0%, #00A045 100%);

  /* ── COLOR — Glass (frosted chrome) ───────────────────────────────── */
  --glass-bg:        rgba(255,255,255,.72);
  --glass-bg-strong: rgba(255,255,255,.86);
  --glass-border:    rgba(255,255,255,.55);
  --glass-blur:      blur(22px) saturate(180%);
  --glass-shadow:    0 8px 30px rgba(28,27,46,.16);

  /* ── 2. TYPOGRAPHY ────────────────────────────────────────────────── */
  --font-ui:    "Roboto", sans-serif;
  /* Số/mã đơn dùng chung Roboto với UI (bỏ Roboto Mono) — biến giữ nguyên tên để không phải sửa nơi tham chiếu. */
  --font-mono:  "Roboto", sans-serif;
  --font-brand: "Audiowide", cursive;

  /* Typography scale — chuẩn hóa 2026-07 (xem Maintainability.md): thay cho ~26 giá trị px rải rác
     trước đây (nhiều mức nửa-pixel gần giống nhau). Đặt tên/role theo mapping đã audit:
     2xs=badge rất nhỏ · xs=caption/meta phụ · sm=metadata/phụ đề/thời gian · base=nội dung thân/label
     · md=tên khách-dịch vụ/nội dung nhấn nhẹ · lg=số tiền/card title · xl=summary value ·
     2xl=hero value · display=số hiển thị đặc biệt.

     Cập nhật 2026-07: bám Apple HIG (Dynamic Type cỡ "Large") vì user báo font đọc thấy nhỏ trên
     iPhone thật (1 CSS px ≈ 1 pt ở tầng layout). 3 tầng nhỏ (11/12/13) vốn đã khớp Caption2/Caption1/
     Footnote nên GIỮ; nâng đúng 3 tầng dùng nhiều đang thấp hơn Apple 1-2px:
       base 15 = Subheadline · md 17 = Body/Headline · lg 20 = Title 3 ·
       xl 22 = Title 2 · 2xl 28 = Title 1 · display 34 = Large Title.
     Toàn bộ đã token-hoá nên đổi 1 chỗ này là cả hệ thống theo. */
  --font-size-2xs:     11px;
  --font-size-xs:      12px;
  --font-size-sm:      13px;
  --font-size-base:    15px;
  --font-size-md:      17px;
  --font-size-lg:      20px;
  --font-size-xl:      22px;
  --font-size-2xl:     28px;
  --font-size-display: 34px;

  --fw-regular:  400;
  --fw-medium:   500;
  --fw-semibold: 600;
  --fw-bold:     700;
  --fw-heavy:    800;

  --lh-tight:  1.15;   --lh-snug: 1.3;   --lh-normal: 1.45;
  --ls-tight: -0.02em; --ls-normal: 0;   --ls-wide: 0.04em;

  /* ── 3. SPACING (4px base) ────────────────────────────────────────── */
  --space-1: 4px;   --space-2: 8px;   --space-3: 12px;  --space-4: 16px;
  --space-5: 20px;  --space-6: 24px;  --space-8: 32px;  --space-10: 40px;
  --space-12: 48px;

  --pad-card:       14px;
  --pad-screen:     var(--space-4);
  --gap-list:       10px;
  --nav-clearance:  110px;
  --touch-min:      44px;

  /* ── 4. RADIUS ────────────────────────────────────────────────────── */
  --radius-xs:   8px;
  --radius-sm:   10px;
  --radius-md:   14px;
  --radius-lg:   18px;
  --radius-xl:   22px;
  --radius-pill: 999px;

  /* ── 5. SHADOW (soft ink-purple elevation) ────────────────────────── */
  --shadow-sm:  0 4px 16px rgba(46,40,90,.08);
  --shadow-md:  0 8px 28px rgba(46,40,90,.12);
  --shadow-lg:  0 12px 40px rgba(46,40,90,.20);
  --shadow-fab: 0 10px 24px rgba(89,74,226,.40);
  --shadow-hero: inset 0 1px 0 rgba(255,255,255,.28), 0 16px 34px rgba(82,70,224,.34);
  --shadow-appbar-soft: 0 6px 20px rgba(46,40,90,.10);
  --shadow-menu: 0 5px 5px -3px rgba(0,0,0,.2), 0 8px 10px 1px rgba(0,0,0,.14), 0 3px 14px 2px rgba(0,0,0,.12);

  /* ── 6. MOTION & Z-INDEX ──────────────────────────────────────────── */
  --ease-ios:  cubic-bezier(.32,.72,.25,1);
  --ease-rise: cubic-bezier(.22,1,.36,1);
  --dur-fast: .14s;  --dur-base: .22s;  --dur-slow: .3s;
  --z-fab: 25;  --z-nav: 26;  --z-header: 30;  --z-sheet: 41;  --z-datepicker: 55;  --z-toast: 60;

  /* ══════════════════════════════════════════════════════════════════
     LEGACY ALIASES — giữ để CSS component copy từ prototype vẫn resolve.
     ══════════════════════════════════════════════════════════════════ */
  --primary:         var(--color-primary);
  --primary-dark:    var(--color-primary-dark);
  --primary-soft:    var(--color-primary-soft);
  --primary-grad:    var(--color-primary);
  --accent:          var(--color-accent);

  --surface:         var(--color-canvas);
  --card:            var(--color-card);
  --text:            var(--color-text-primary);
  --text-2:          var(--color-text-secondary);
  --text-3:          var(--color-text-muted);
  --line:            var(--color-line);
  --border:          var(--color-border);
  --avatar-bg:       var(--color-avatar-bg);
  --avatar-fg:       var(--color-avatar-fg);

  --green:           var(--color-success);   --green-soft:  var(--color-success-soft);
  --blue:            var(--color-info);       --blue-soft:   var(--color-info-soft);
  --orange:          var(--color-warning);    --orange-soft: var(--color-warning-soft);
  --red:             var(--color-danger);     --red-soft:    var(--color-danger-soft);
  --slate:           var(--color-neutral);

  --blue-grad:       var(--grad-blue);

  --r-xl:            var(--radius-xl);
  --radius:          var(--radius-lg);
  --r-md:            var(--radius-md);
  --r-sm:            var(--radius-sm);
  --r-pill:          var(--radius-pill);

  --shadow-card:     var(--shadow-sm);
  --shadow-card2:    var(--shadow-md);
  --shadow-pop:      var(--shadow-lg);
  --shadow-appbar:   var(--glass-shadow);
}

/* ══════════════════════════════════════════════════════════════════════════
   Ẩn/hiện TopNav và BottomNav theo bề rộng màn hình.
   Ngưỡng <= 1280px được coi là mobile, đồng bộ với cơ chế IsSmallDevice của các trang.
   Trên desktop (> 1280px), giao diện giữ nguyên: hiện TopNav, ẩn thanh điều hướng dưới.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 1280px) {
  /* Khoá cứng html/body — trước đây 2 phần tử này không hề bị giới hạn chiều cao/overflow, nên
     dù mọi shell bên trong (.main-content, .xxx-m) đã đúng 100dvh + overflow:hidden, root vẫn có
     thể "tràn" vài px (vd phần tử position:fixed tính lố vào scrollable-overflow của initial
     containing block) và lộ thanh cuộn NGOÀI CÙNG của trình duyệt — thanh này kéo TOÀN BỘ trang
     (kể cả header-zone/topnav, vốn đứng ngoài mọi vùng cuộn nội bộ) trôi theo khi cuộn, không thể
     fix bằng cách sửa .main-content/.xxx-m vì chúng không phải là nơi sinh ra thanh cuộn đó.
     .main-content đã là vùng cuộn DUY NHẤT được thiết kế cho toàn bộ mobile UI — khoá html/body
     tuyệt đối không cuộn để đảm bảo topnav luôn cố định. */
  html, body {
    height: 100%;
    overflow: hidden;
  }

  /* Ẩn TopNav của desktop; mobile dùng app bar riêng từng trang kết hợp thanh điều hướng dưới */
  #navbar { display: none !important; }

  /* .main-content là vùng cuộn chính trên mobile: đặt chiều cao cố định 100dvh và tự cuộn.
     Nhờ đó app bar dùng position: sticky bám đúng mép trên, đồng thời tạo một scroll-container
     ổn định để JS lắng nghe sự kiện cuộn. Ghi đè min-height/overflow từ app.css trong phạm vi mobile.
     Ẩn thanh cuộn (scrollbar-width/-webkit-scrollbar) — dùng chung 1 quy ước với mọi vùng cuộn khác
     trong app (.ov-scroll, .list, .cb-scroll...); trước đây thiếu nên các trang dùng pattern "đơn
     giản" (không có shell riêng, .main-content tự cuộn cả trang — vd Options.razor) lộ thanh cuộn
     mặc định của trình duyệt, không đồng bộ với phần còn lại của app. */
  .main-content {
    height: 100dvh !important;
    min-height: 0 !important;
    max-height: 100dvh !important;
    overflow-y: auto !important;
    overflow-x: hidden;
    scrollbar-width: none;
  }
  .main-content::-webkit-scrollbar {
    display: none;
  }

  /* Không giới hạn max-width: mỗi trang tự quyết định bố cục theo bề rộng thực tế
     (IsSmallDevice), không cần ép về khung điện thoại cố định. */
  .app-shell-body {
    width: 100%;
    /* Chừa khoảng trống ở đáy cho thanh điều hướng dưới cố định */
    padding-bottom: var(--nav-clearance, 110px);
  }

  /* Trang tự quản chiều cao (shell = 100dvh; overflow:hidden; .list/.cb-scroll cuộn nội bộ) thì
     .app-shell-body KHÔNG được có padding-bottom: nếu còn 110px thì tổng chiều cao trong
     .main-content = 100dvh + 110px -> .main-content sinh scroll ngoài, kéo cả shell (gồm app bar
     .header-zone) trôi lên khi cuộn (app bar không còn dính đỉnh). Khoảng trống cho bottom nav do
     padding-bottom của .list/.cb-scroll từng trang đảm nhận. MỌI shell mới theo pattern này PHẢI
     thêm class vào danh sách :has() dưới đây. */
  .app-shell-body:has(.bills-m, .cashbook-m, .rrd-m, .oinc-m, .oexp-m, .rcv-m, .rpt-m, .fd-m, .ov-m, .ince-m, .inced-m, .cust-m, .debt-m, .pts-m, .custd-m, .svc-m, .imps-m, .impc-m, .svcd-m, .bank-m, .bankd-m, .shop-m, .shopd-m, .unit-m, .unitd-m, .rack-m, .rackd-m, .status-m, .statusd-m, .lyl-m, .log-m, .perm-m, .pt-m, .chpwd-m, .newbill-m) {
    padding-bottom: 0;
  }

  /* Shell "tự quản chiều cao" (flex column phủ 100dvh, header đứng ngoài vùng cuộn) — 35 trang mobile
     đều tự lặp lại y hệt 4 dòng này trong .razor.css riêng, chỉ khác tên class. Gộp về đây, danh sách
     class trùng với :has() ở trên (bổ sung .impc-m — trước đây bị bỏ sót khỏi :has() nên ImpCustomer
     dư padding-bottom 110px so với các trang shell khác, đã vá luôn cùng lúc). */
  .bills-m, .cashbook-m, .rrd-m, .oinc-m, .oexp-m, .rcv-m, .rpt-m, .fd-m, .ov-m, .ince-m, .inced-m,
  .cust-m, .debt-m, .pts-m, .custd-m, .svc-m, .imps-m, .impc-m, .svcd-m, .bank-m, .bankd-m, .shop-m,
  .shopd-m, .unit-m, .unitd-m, .rack-m, .rackd-m, .status-m, .statusd-m, .lyl-m, .log-m, .perm-m,
  .pt-m, .chpwd-m, .newbill-m {
    display: flex;
    flex-direction: column;
    height: 100dvh;
    overflow: hidden;
  }

  /* NewBill: nội dung form thường ngắn hơn 100dvh (chưa thêm dịch vụ/khách) nên .newbill-scroll
     KHÔNG có gì để cuộn — lúc đó thao tác vuốt/lăn có thể "chain" (dội biên) lên .main-content,
     kéo trôi cả .newbill-m (gồm header-zone, vốn đứng ngoài .newbill-scroll) lên theo dù về lý
     thuyết .main-content không có nội dung tràn. Khoá cứng overflow ở đây để .main-content không
     bao giờ tự cuộn khi NewBill đang active — mọi cuộn chỉ xảy ra trong .newbill-scroll. */
  .main-content:has(.newbill-m) {
    overflow: hidden !important;
  }
}

@media (min-width: 1281px) {
  /* Ẩn thanh điều hướng dưới trên desktop */
  .bottomnav { display: none !important; }

  /* Khôi phục padding của "container-fluid p-2" (Bootstrap) mà MainLayout.razor dùng
     trước khi đổi sang class app-shell-body — thiếu rule này khiến nội dung desktop
     dính sát TopNav và các lưới/table mất padding quanh. */
  .app-shell-body {
    padding: .5rem;
  }
}

/* ══════════════════════════════════════════════════════════════════════════
   Các lớp dùng chung cho mọi trang mobile.

   Đặt ở phạm vi toàn cục (không scoped) vì phần lớn các lớp này gắn trên component
   MudBlazor (MudPaper/MudList/MudListItem/MudAvatar/MudIcon); phần tử do MudBlazor
   render không mang scope-attribute nên CSS isolation không áp được trực tiếp. Ở phạm vi
   toàn cục thì lớp áp thẳng, không cần combinator ::deep.

   Toàn bộ bọc trong @media (max-width:1280px) để không ảnh hưởng giao diện desktop.
   File nạp sau bootstrap.min.css nên các rule dưới ghi đè được .card của bootstrap.

   Cách dùng: đặt lớp trực tiếp lên component MudBlazor, ví dụ:
     <MudPaper Class="card card--grouped">
       <MudList Class="settings-list">
         <MudListItem Class="settings-row"><div class="settings-row__content">…
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 1280px) {

  /* ── Toast/Snackbar — theo Mobile.Prototype (.toast trong styles.css): nổi giữa, dạng viên
     thuốc kính mờ, phía TRÊN thanh điều hướng dưới — thay vì hộp chữ nhật rộng ở góc trên như
     mặc định MudBlazor/desktop. App.razor đổi PositionClass sang BottomCenter cho mobile, ở đây
     chỉ còn phần hình dạng/kích thước/vị trí. GIỮ NGUYÊN màu theo Severity (.mud-alert-filled-*)
     — không ép về 1 màu tối như prototype, vì prototype không có khái niệm nhiều mức độ
     (success/error/warning) như app thật, đổi màu sẽ mất tín hiệu quan trọng đang dùng khắp app.
     LƯU Ý DOM thật: MudBlazor 7 gắn class màu (.mud-alert-filled-*) THẲNG lên .mud-snackbar,
     KHÔNG có phần tử .mud-alert lồng bên trong như bản cũ/tài liệu — style hình dạng phải áp
     trực tiếp lên .mud-snackbar, không được reset background/box-shadow của nó về rỗng (đã từng
     làm toast biến mất hoàn toàn vì trong suốt - xem lại DOM qua devtools trước khi sửa lần sau). */
  #mud-snackbar-container.mud-snackbar-location-bottom-center {
    bottom: calc(var(--nav-clearance, 110px) + env(safe-area-inset-bottom) + 10px);
    margin-top: 0;
  }
  .mud-snackbar-location-bottom-center .mud-snackbar {
    min-width: 0;
    max-width: calc(100vw - 48px);
    width: max-content;
    margin: 6px auto 0;
    border-radius: var(--radius-pill);
    padding: 11px 20px;
    font-size: var(--font-size-sm);
    font-weight: 400;
    box-shadow: var(--shadow-lg);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
  }
  /* Prototype không có nút đóng tay (toast tự ẩn) — ẩn nút X mặc định của MudBlazor để giữ
     đúng dáng viên thuốc gọn, không bị cộm 1 góc. */
  .mud-snackbar-location-bottom-center .mud-snackbar-content-action {
    display: none;
  }

  /* ── Thẻ (card) và các biến thể ── */
  .card {
    background: var(--color-card);
    border-radius: var(--radius-lg);   /* 18px */
    box-shadow: var(--shadow-sm);
    padding: var(--pad-card);          /* 14px */
  }

  .card--interactive {
    cursor: pointer;
    transition: transform var(--dur-fast) var(--ease-ios), box-shadow var(--dur-fast);
  }
  .card--interactive:active {
    transform: scale(.99);
    box-shadow: var(--shadow-md);
  }

  /* iOS grouped table card: rows bên trong, không padding ngoài */
  .card--grouped {
    padding: 0;
    overflow: hidden;
    box-shadow: var(--shadow-md);
  }

  .card--raised  { box-shadow: var(--shadow-md); }
  .card--compact { border-radius: var(--radius-md); }
  .card--flat    { box-shadow: none; background: var(--color-surface-sunken); }

  /* Hero card (nền gradient tím, chữ trắng) — dùng cho số dư/tổng quan nổi bật
     (vd .cb-balance ở FinancialReport). Tương đương .card--hero của prototype
     (Mobile.Prototype/styles/components/card.css), giữ nguyên hiệu ứng ring + glow góc. */
  .card--hero {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    border-radius: var(--radius-xl);
    background: var(--grad-hero);
    color: var(--color-text-on-brand);
    box-shadow: var(--shadow-hero);
  }
  .card--hero::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -2;
    pointer-events: none;
    background: radial-gradient(140% 120% at 100% 50%, rgba(255,255,255,.18) 0%, transparent 42%);
  }
  .card--hero::before {
    content: '';
    position: absolute;
    z-index: -1;
    top: 50%; right: -34px; transform: translateY(-50%);
    width: 240px; height: 240px; border-radius: 50%;
    pointer-events: none;
    background: repeating-radial-gradient(circle, rgba(255,255,255,.13) 0 1.5px, transparent 1.5px 34px);
    -webkit-mask-image: radial-gradient(circle, #000 58%, transparent 76%);
            mask-image: radial-gradient(circle, #000 58%, transparent 76%);
  }

  /* ── Nhãn nhóm ── */
  .group-label {
    font-size: var(--font-size-base);
    font-weight: 700;
    color: var(--text-3);
    letter-spacing: .02em;
    padding: 0 6px 7px;
    margin-top: 4px;
  }

  /* ── Hàng danh sách kiểu grouped list (dùng lại cho: cài đặt, dịch vụ, sổ quỹ, bộ lọc…) ── */
  .settings-list,
  .settings-list .mud-list {
    padding: 0;
    background: transparent;
  }
  /* Loại bỏ padding và min-height mặc định của MudList/MudListItem để kiểm soát chiều cao hàng.
     border-bottom:none — huỷ vạch chấm (dotted) mà app.css áp global cho MỌI .mud-list-item-gutters
     (kiểu desktop); trên mobile vạch chấm đó CHỒNG với hairline .settings-row::before -> DOUBLE vạch.
     Bỏ nó đi, chỉ giữ hairline mảnh nhẹ (iOS). Desktop không ảnh hưởng vì rule này nằm trong @media. */
  .settings-list .mud-list-item,
  .settings-list .mud-list-item-gutters {
    min-height: 0;
    padding: 0;
    border-bottom: none !important;
  }
  .settings-list .mud-list-item-text { margin: 0; }

  .settings-row {
    position: relative;
    width: 100%;
    min-height: 0;
    text-decoration: none;
    --list-inset: 53px;
  }
  .settings-row:active { background: rgba(28, 27, 46, .045); }

  /* hairline iOS giữa 2 row liên tiếp. Dùng height:1px + transform:scaleY(.5) thay vì
     height:.5px trực tiếp: ở DPR lẻ (vd 1.75x) một box cao .5px bị làm tròn/anti-alias
     thành vệt mờ loang màu; scaleY sau khi layout xong ở bước compositing nên nét luôn
     sắc dù DPR bao nhiêu -> đúng kiểu "hairline" sắc mảnh của iOS thay vì mờ nhòe. */
  .settings-row + .settings-row::before {
    content: '';
    position: absolute;
    top: 0;
    left: var(--list-inset, 53px);
    right: 0;
    height: 1px;
    background: var(--color-hairline);
    transform: scaleY(.5);
    transform-origin: 0 0;
  }

  .settings-row__content {
    display: flex;
    align-items: center;
    gap: 13px;
    width: 100%;
    padding: 12px 14px;
  }
  .settings-row__content--center {
    justify-content: center;
    gap: 8px;
  }

  .settings-icon {
    flex: none;
    width: 32px;
    height: 32px;
    border-radius: var(--r-sm);   /* 10px */
    display: grid;
    place-items: center;
  }
  .settings-icon .mud-icon-root { font-size: 18px; }

  .settings-label {
    flex: 1;
    min-width: 0;
    font-size: var(--font-size-md);
    font-weight: 500;
    color: var(--text);
    line-height: var(--lh-snug);
  }
  .settings-value {
    flex: none;
    font-size: var(--font-size-base);
    color: var(--text-3);
    margin-right: 2px;
  }
  .settings-chev {
    flex: none;
    color: var(--text-3);
    font-size: 20px;
  }

  /* ── Ô nền màu cho icon (dùng chung cho hàng danh sách và action sheet) ── */
  .ic-violet { background: rgba(89,74,226,.12);  color: var(--primary); }
  .ic-blue   { background: rgba(33,150,243,.12); color: var(--blue); }
  .ic-green  { background: rgba(0,200,83,.13);   color: var(--green); }
  .ic-teal   { background: rgba(0,150,136,.12);  color: #009688; }
  .ic-orange { background: rgba(251,140,0,.13);  color: var(--orange); }
  .ic-pink   { background: rgba(233,30,99,.12);  color: #E91E63; }
  .ic-indigo { background: rgba(63,81,181,.12);  color: #3F51B5; }
  .ic-red    { background: rgba(244,67,54,.11);  color: var(--red); }
  .ic-gray   { background: rgba(117,117,117,.13); color: var(--slate); }
  .ic-amber  { background: rgba(255,179,0,.16);  color: #FFB300; }
  .ic-cyan   { background: rgba(0,188,212,.12);  color: #00BCD4; }

  /* Màu chữ theo ngữ nghĩa (Index.Mobile.razor's .stat-value đã dùng các tên này nhưng chưa từng
     có CSS định nghĩa — bổ sung tại đây để khớp đúng token đã có, không tạo màu mới). */
  .u-text-primary { color: var(--primary); }
  .u-text-info    { color: var(--blue); }
  .u-text-warning { color: var(--orange); }
  .u-text-success { color: var(--green); }
  .u-text-danger  { color: var(--red); }

  /* Hàng hành động phá hủy (vd "Xoá phiếu") -> nhãn đỏ, icon vẫn giữ nền .ic-red riêng */
  .settings-row.danger .settings-label { color: var(--red); }

  /* Hàng bị KHOÁ (không có quyền xem) — vẫn hiển thị để người dùng biết tính năng tồn tại nhưng
     làm mờ, vô hiệu tương tác (không điều hướng) và hiện icon ổ khoá thay chevron. */
  .settings-row--locked { pointer-events: none; }
  .settings-row--locked .settings-icon { filter: grayscale(1); opacity: .5; }
  .settings-row--locked .settings-label { color: var(--text-3); font-weight: 400; }
  .settings-row--locked .settings-lock { color: var(--text-3); font-size: 17px; opacity: .85; }

  /* Biến thể "hàng không icon" của .settings-row__content (Banks/Racks/Units/Status — không có icon
     vuông dẫn đầu nên lề trái/phải và cách bố cục khác nhóm settings-row chuẩn). 4 trang định nghĩa
     GẦN giống nhau (không giống hệt: gap 10-13px, padding-top 13-14px, Status canh trên vì 2 dòng) —
     chỉ gộp đúng phần THẬT SỰ giống nhau (display/width/lề trái-phải/cursor) ở đây, mỗi trang vẫn giữ
     riêng phần khác biệt thật (align-items/gap/padding-top-bottom) trong CSS scoped của mình. Padding
     tách longhand trái/phải (không dùng shorthand "padding") để không đụng padding-top/bottom riêng
     từng trang đặt sau, tránh lệ thuộc thứ tự nạp CSS giữa 2 rule. */
  .bank-m .bank-row,
  .rack-m .rack-row,
  .unit-m .unit-row__content,
  .status-m .st-row__content {
    display: flex;
    width: 100%;
    padding-left: 16px;
    padding-right: 16px;
    cursor: pointer;
  }

  /* MudMenuItem trong dropdown app bar (Bills.razor) render qua MudPopoverProvider,
     portal ra ngoài cây DOM của component -> CSS scoped của Bills.razor.css không
     áp dụng được, phải đặt global ở đây. Reset padding/margin mặc định của
     MudListItem để chiều cao hàng khớp .settings-row__content. */
  .menu-item.mud-list-item { padding: 0; min-height: 0; }
  .menu-item .mud-list-item-text { margin: 0; }
  .menu-item .settings-label { font-size: var(--font-size-base); }

  /* ── App bar (topnav) dùng chung cho mọi trang mobile có header riêng (Bills, FinancialReport…).
     Trang tự bọc trong 1 shell flex-column (vd .bills-m) với height:100dvh;overflow:hidden;
     .header-zone {flex:0 0 auto} để header không co giãn, phần còn lại (.list/.cb-scroll…) tự cuộn. ── */
  .header-zone {
    flex: 0 0 auto;
    z-index: var(--z-header);
    background: transparent;
    padding-bottom: 0;
  }
  .topnav {
    position: relative;
    z-index: 2;
    display: flex; align-items: center; gap: 4px;
    padding: max(env(safe-area-inset-top), 7px) 8px 9px 6px;
    background: var(--glass-bg);
    -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
    color: var(--text);
    border-bottom: 1px solid var(--glass-border);
    box-shadow: 0 6px 20px rgba(46,40,90,.10);
  }
  .topnav-actions { flex: none; display: flex; gap: 2px; align-items: center; }
  .topnav-title.t {
    flex: 1; min-width: 0; margin: 0 0 0 4px;
    font-size: var(--font-size-lg); font-weight: 500; line-height: var(--lh-tight); color: var(--text);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .nav-icon-btn {
    width: 36px !important; height: 36px !important;
    color: var(--text) !important;
  }
  .nav-icon-btn:active { background: rgba(0,0,0,.06); }
  /* MudMenu Class="nav-icon-btn" đặt class này lên DIV bọc ngoài (.mud-menu), không phải lên chính
     <button> kích hoạt bên trong -> nút thật giữ kích thước mặc định KHÔNG vuông (26×36px) của
     MudBlazor cho icon button Size.Small, border-radius:50% trên khung không vuông thành hình bầu
     dục thay vì tròn khi bấm/hover. Ép lại đúng 36×36 trên chính nút thật. */
  .nav-icon-btn.mud-menu .mud-icon-button-size-small {
    width: 36px !important; height: 36px !important;
  }

  /* ── Bottom sheet dùng chung (overlay + slide từ dưới lên) — Bills, FinancialReport…
     Không dùng MudDrawer vì app không có <MudLayout> -> drawer không position:fixed
     đúng (xem memory mudblazor-mobile-gotchas). Container là phần tử HTML thuần do
     từng trang tự viết -> không cần ::deep dù global. ── */
  .sheet-backdrop {
    position: fixed; inset: 0; background: rgba(18,16,40,.45);
    opacity: 0; pointer-events: none;
    transition: opacity .22s ease; z-index: calc(var(--z-sheet) - 1);
  }
  .sheet-backdrop.open { opacity: 1; pointer-events: auto; }
  .sheet,
  .flt-sheet {
    position: fixed;
    /* --kb-inset: chiều cao bàn phím iOS (do _appscript.mobile.js đo qua visualViewport, mặc định
       0). Đẩy `bottom` lên bằng chiều cao bàn phím để field trong sheet không bị bàn phím che —
       phần tử position:fixed;bottom:0 vốn ghim đáy layout viewport = nằm dưới bàn phím trên iOS. */
    bottom: var(--kb-inset, 0px); left: 0; right: 0;
    transform: translateY(105%);
    background: var(--card);
    /* QA #1: bo góc theo đúng tỷ lệ card chuẩn (--radius-lg, 18px) thay vì --r-xl (22px) — không
       đổi biến --r-xl vì token này còn dùng cho .quick-tile (Index.Mobile.razor.css), không liên
       quan đến sheet. */
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    transition: transform .26s cubic-bezier(.32,.72,.25,1); z-index: var(--z-sheet);
    box-shadow: var(--shadow-pop);
  }
  /* Không padding trái/phải: nội dung (sheet-head/sheet-list) tự lo padding riêng, để nền
     trạng thái :active của hàng list vươn tới sát mép thật của sheet (không còn viền chết
     xung quanh không phản hồi khi chạm/rê chuột). */
  .sheet { padding: 8px 0 calc(14px + env(safe-area-inset-bottom)); }
  .flt-sheet {
    padding: 8px 16px calc(24px + env(safe-area-inset-bottom));
    /* Khi bàn phím mở (--kb-inset > 0) sheet đã được đẩy lên; siết max-height trừ đi chiều cao bàn
       phím để đỉnh sheet không tràn khỏi màn hình, phần dư cuộn nội bộ (overflow-y:auto). */
    max-height: calc(92dvh - var(--kb-inset, 0px)); overflow-y: auto;
  }
  .sheet.open,
  .flt-sheet.open { transform: translateY(0); }
  .sheet-grip {
    width: 38px; height: 4px; border-radius: 2px;
    background: var(--line); margin: 4px auto 10px;
  }

  /* ── MudList dùng trong action sheet (sheet-list/settings-row) — reset padding/min-height
     mặc định của MudListItem để .settings-row__content tự kiểm soát chiều cao hàng. Trước đây
     chỉ định nghĩa scoped trong Bills.razor.css (".bills-m ::deep .sheet-list") nên các trang
     khác dùng lại cùng pattern (Customers, CustomerDebtDetail, IncomeExpense) không thấy reset
     này, khiến padding mặc định của MudListItem cộng dồn với padding của settings-row__content,
     hàng cao hơn hẳn so với Bills. Promote lên global để mọi consumer đều đúng. ── */
  .sheet-list { padding: 0; }
  /* border-bottom:none — cùng lý do như .settings-list: huỷ vạch chấm global của app.css để không bị
     DOUBLE với hairline .settings-row::before. Sheet chỉ còn 1 hairline mảnh nhẹ giữa các hàng. */
  .sheet-list .mud-list-item,
  .sheet-list .mud-list-item-gutters { min-height: 0; padding: 0; border-bottom: none !important; }
  .sheet-list .mud-list-item-text { margin: 0; }
  /* Trong bottom sheet (action sheet), vạch kẻ trải DƯỚI cả icon (thụt 14px = mép trái nội dung) thay
     vì thụt qua icon như grouped-list (53px) — đúng kiểu action sheet iOS + tránh cảm giác "mất vạch ở
     chỗ có icon". Ghi đè --list-inset để hairline .settings-row::before đọc; áp cho cả hàng lẫn HR. */
  .sheet-list .settings-row { --list-inset: 14px; }
  /* Vạch ngăn hành động phá huỷ (Xoá): PHẢI dựng bằng đúng kỹ thuật hairline (height:1px + nền màu +
     scaleY(.5)) như .settings-row::before, KHÔNG dùng border của MudDivider — MudBlazor gán sẵn
     `.mud-divider { opacity:.25 }` mặc định, cộng với border-color đã trong suốt (rgba .16) khiến vạch
     này mờ hơn hẳn (≈0.04 alpha thực tế) so với các hairline khác dù cùng border-color. border:none +
     opacity:1 để loại 2 lớp làm mờ đó, rồi vẽ lại y hệt bằng background+transform cho khớp 100%. */
  .sheet-divider.mud-divider {
    border: none;
    opacity: 1;
    height: 1px;
    background: var(--color-hairline);
    transform: scaleY(.5);
    transform-origin: 0 0;
    margin: 2px 0 2px 14px;
  }

  /* ── avatar tròn dùng chung (thẻ danh sách + sheet-head) — trước đây chỉ định nghĩa shape đầy đủ
     trong Bills.razor.css (".bills-m .avatar"), các trang khác dùng div/MudAvatar Class="avatar"
     trực tiếp nên không thấy shape/nền, chỉ hiện chữ trần không có vòng tròn. ── */
  .avatar {
    flex: none; width: 44px; height: 44px; border-radius: 50%;
    display: grid; place-items: center;
    background: var(--avatar-bg); color: var(--avatar-fg);
    font-size: var(--font-size-lg); font-weight: 700;
  }

  /* ── sheet-head (avatar + tên/mã trong action sheet) — dùng chung Bills, IncomeExpense.
     Trước đây scoped trong Bills.razor.css (".bills-m .sheet-head") nên IncomeExpense.razor
     (component khác) không thấy style -> avatar/tên rớt xuống dòng theo block mặc định. ── */
  .sheet-head {
    display: flex; align-items: center; gap: 11px;
    /* padding trái/phải khớp .settings-row__content (14px) để avatar thẳng hàng với icon
       của các hàng bên dưới — cùng 1 mức thụt lề tính từ mép sheet. */
    padding: 2px 14px 12px; border-bottom: 1px solid var(--line); margin-bottom: 6px;
  }
  .sheet-head .avatar { width: 38px; height: 38px; font-size: var(--font-size-md); }
  .sheet-head .nm { font-size: var(--font-size-md); font-weight: 700; color: var(--text); }
  .sheet-head .cd {
    font-family: var(--font-mono); font-weight: 500;
    font-size: var(--font-size-xs); color: var(--text-3); margin-top: 1px;
  }

  /* Pattern dùng chung: MudDatePicker đặt trong 1 sheet có transform (.sheet/.flt-sheet/.bsheet…)
     bị giam overlay dialog vì transform tạo containing block cho position:fixed (CSS spec) —
     dialog co lại đúng bằng kích thước sheet thay vì phủ viewport, ngày cuối tháng bị cắt mất.
     Fix: đặt <MudDatePicker> NGOÀI sheet (vd cuối shell mobile), gắn Class="df-mud" để giấu
     KHUNG INPUT hiển thị (không set opacity:0 lên .mud-picker gốc vì overlay/calendar là con,
     sẽ bị trong suốt theo); z-index cao hơn mọi sheet để overlay luôn nổi lên trên. Trong sheet,
     hiển thị 1 field readonly (button/MudTextField) bấm gọi picker.OpenAsync() qua @ref. */
  .df-mud { position: fixed; top: 0; left: 0; width: 0; height: 0; overflow: visible; z-index: var(--z-datepicker); }
  .df-mud .mud-input-control { display: none; }

  /* Field "Từ ngày/Đến ngày" hiển thị trong sheet filter — card viền tím, label xám nhỏ + giá trị đậm
     bên dưới (không phải MudTextField chuẩn). Đi kèm .df-mud: bấm field gọi picker.OpenAsync() qua @ref.
     Dùng chung cho mọi trang report có filter "Theo tùy chọn" (FinancialChart, RevenueReportDetail,
     OtherIncome, OtherExpenses, FinancialReport…). */
  .daterow { display: flex; gap: 10px; padding: 8px 4px 4px; }
  /* Trong filter sheet, .daterow chứa 2 MudTextField Outlined (không phải card .datefield như
     FinancialChart bsheet). Bỏ padding để 2 field ngày canh đúng mép trái/phải với các control
     full-width khác (Cửa hàng/Thời gian/Nhân viên) và để MudStack gap 4px lo khoảng cách dọc đều
     nhau — padding cũ (8px trên/4px dưới + 4px hai bên) làm dòng ngày thụt vào và lệch nhịp dọc. */
  .flt-sheet .daterow { padding: 0; gap: 8px; }
  .datefield {
    flex: 1; border: 1px solid var(--border); border-radius: var(--r-md); padding: 4px 12px;
    position: relative; cursor: pointer; background: var(--card);
    box-shadow: var(--shadow-card);
    transition: border-color .15s ease, box-shadow .15s ease;
  }
  .datefield .dl { font-size: var(--font-size-xs); color: var(--text-3); }
  .datefield .dv { font-size: var(--font-size-md); font-weight: 600; margin-top: 2px; color: var(--text); }
  /* Viền chỉ đổi màu primary khi tương tác (hover/nhấn) — giống hệt hover của MudSelect/MudAutocomplete
     bên trên — để field ngày đồng nhất với các control khác lúc nghỉ (trước đây select luôn có
     màu primary do nhầm áp dụng cho mọi trạng thái, khiến field ngày nổi bật khác biệt cả lúc không
     tương tác). */
  .datefield:hover, .datefield:active {
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(89,74,226,.14), var(--shadow-card);
  }

  /* MudTextField/MudSelect/MudAutocomplete Variant="Filled" trong filter sheet (Mã phiếu/Cửa hàng/
     Thời gian/Nhân viên/Khách hàng...) — cùng pattern "kính mờ" đã áp cho .auth-fields (Login.razor):
     nền trong suốt kiểu kính mờ + viền mềm bo tròn đều 4 góc + đổ bóng nhẹ (--shadow-card), bỏ gạch
     chân Material gốc. Nền sheet là var(--card) (trắng đặc, không phải gradient như trang auth) nên
     tint kính đổi sang xám rất nhạt (var(--surface)) thay vì trắng-mờ, để vẫn nổi khối trên nền trắng. */
  .flt-sheet .mud-input-filled {
    background: transparent !important;
    border: 1px solid #e2dfeecc;
    border-radius: var(--r-md) !important;
    box-shadow: var(--shadow-card);
    transition: border-color .15s ease, box-shadow .15s ease;
  }
  .flt-sheet .mud-input-underline::before,
  .flt-sheet .mud-input-underline::after {
    display: none;
  }
  .flt-sheet .mud-input-control:focus-within .mud-input-filled {
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(89,74,226,.14), var(--shadow-card);
  }

  /* Nút hành động chính trong filter sheet (vd "LỌC") — gắn lên MudButton, global nên
     không cần ::deep dù component MudBlazor. Mặc định (Bills, ReceivableReport…) vẫn giữ nút
     gradient đậm; riêng trong .flt-sheet đồng bộ về style nhạt giống nút "Áp dụng" (.bsheet-apply)
     vì cùng là hành động xác nhận bộ lọc trong 1 sheet. */
  .btn-primary {
    border-radius: var(--radius) !important;
    background: var(--grad-hero) !important; color: #fff;
    font-size: var(--font-size-md); font-weight: 600;
    letter-spacing: .04em; text-transform: uppercase; padding: 15px !important;
    box-shadow: 0 8px 20px rgba(74,59,212,.30);
    margin-top: 28px;
  }
  .flt-sheet .btn-primary {
    background: var(--primary-soft) !important;
    color: var(--primary) !important;
    box-shadow: none !important;
    border-radius: var(--r-md) !important;
    padding: 12px !important;
    transition: background .15s ease, color .15s ease, box-shadow .15s ease;
  }
  .flt-sheet .btn-primary:active { background: #DEDCF8 !important; }
  /* Người dùng đã đổi giá trị field nào đó trong sheet (so với lúc mở sheet) -> trả về đúng màu
     primary đậm mặc định (giống .btn-primary gốc) để báo hiệu "có thay đổi, bấm để áp dụng". */
  .flt-sheet .btn-primary.active {
    background: var(--grad-hero) !important;
    color: #fff !important;
    box-shadow: 0 8px 20px rgba(74,59,212,.30) !important;
  }
  .flt-sheet .btn-primary.active:active { background: var(--grad-hero) !important; }

  /* QA #6: chuẩn nút submit dùng chung — lấy nguyên style hiện tại của ShopDetail.razor (pill bo
     tròn hoàn toàn, màu primary phẳng mặc định của MudBlazor, không uppercase/letter-spacing/shadow
     riêng như .btn-primary ở trên — 2 class khác mục đích, .btn-primary vẫn giữ nguyên chỗ đang dùng
     đúng như Bills "LỌC"). Global nên không cần ::deep dù gắn lên MudButton. */
  .btn-mobile-pill.mud-button-root {
    border-radius: 50rem !important;
  }

  /* Thanh chứa nút submit ghim đáy vùng cuộn form (ShopDetail/CustomerDetail/ServiceDetail/BankDetail/
     RackDetail/StatusDetail/UnitDetail/IncomeExpenseDetail...) — trước đây mỗi trang tự định nghĩa
     lại 1 class riêng (vd .shopd-submit/.custd-submit) với nội dung lẽ ra phải giống hệt nhau, dễ
     lệch khi sửa 1 nơi quên sửa nơi khác (đã gặp thật: ServiceDetail/UnitDetail thiếu dòng
     background gradient so với 6 trang còn lại). Gộp về 1 class dùng chung, tên trung tính không
     gắn theo trang cụ thể. */
  .form-submit-bar {
    position: sticky;
    bottom: 0;
    margin-top: var(--space-8);
    padding: 12px 0 4px;
  }

  /* MudRadio "Xem chi tiết thu theo…" (RevenueReportDetail) — bootstrap border-1/rounded-3 trên
     component cho border-style mặc định lạ (không phải solid); ép lại solid + đồng bộ màu/bo góc
     với các control khác trong sheet. Viền đổi màu primary khi đang chọn, giống .datefield active.
     MudStack Spacing="1" thực chất tạo gap 4px (class "gap-1" của Bootstrap) giữa các field, KHÔNG
     phải 8px — margin "m-1" (4px mọi phía) của radio cộng dồn 2 chiều giữa 2 radio thành 8px, gấp đôi
     gap chuẩn. Ép lại margin rõ ràng (dưới 4px, item cuối bỏ margin) để khớp đúng nhịp 4px toàn sheet. */
  .flt-sheet .mud-radio.border-1 {
    border-style: solid !important;
    border-width: 1px !important;
    border-color: var(--border) !important;
    border-radius: var(--r-md) !important;
    box-shadow: var(--shadow-card);
    transition: border-color .15s ease, box-shadow .15s ease;
    margin: 0 0 4px !important;
  }
  .flt-sheet .mud-radio.border-1:last-child { margin-bottom: 0 !important; }
  .flt-sheet .mud-radio.border-1:has(.mud-checked) {
    border-color: var(--primary) !important;
    box-shadow: 0 0 0 3px rgba(89,74,226,.14), var(--shadow-card);
  }

  /* ── Segment pill (MudToggleGroup) — dùng ở Cashbook (Tất cả/Tiền mặt/Chuyển khoản) và
     RevenueReportDetail. Global nên áp thẳng lên MudToggleGroup/MudToggleItem, không cần ::deep. ── */
  .seg.mud-toggle-group {
    display: flex; gap: 4px; margin: 8px 14px 0; padding: 6px;
    background: var(--surface);
    border-radius: 999px;
  }
  .seg .mud-toggle-item {
    flex: 1; justify-content: center; text-align: center;
    font-size: var(--font-size-base); font-weight: 600; letter-spacing: .03em; text-transform: uppercase;
    color: var(--text-2); padding: 9px 4px !important; margin: 0 !important;
    border-radius: 999px !important;
    transition: background .2s, color .2s, box-shadow .2s;
  }
  .seg .mud-toggle-item.mud-toggle-item-selected {
    background: var(--grad-hero); color: #fff;
    box-shadow: 0 4px 12px rgba(74,59,212,.30);
  }

  /* ── Tab gạch dưới dùng chung (CustomerDebtDetail: Công nợ/Lịch sử; DlgCustomerHistory: 3 tab).
     Trước đây chỉ scoped trong CustomerDebtDetail.razor.css, promote lên global vì đã có consumer
     thứ 2 — dialog không có shell class riêng nên bắt buộc phải global mới dùng lại được. ── */
  .utabs { display: flex; background: var(--card); border-bottom: 1px solid var(--line); }
  .utab {
    flex: 1; position: relative; display: flex; align-items: center; justify-content: center; gap: 7px;
    border: none; background: none; font-family: inherit; font-size: var(--font-size-base); font-weight: 600;
    letter-spacing: .02em; text-transform: uppercase; color: var(--text-2); padding: 12px 0 13px; cursor: pointer;
  }
  /* .utab giờ là MudButton (trước là <button> thô) -> display:contents cho .mud-button-label để
     icon+text tham gia thẳng vào flex justify-content:center của thẻ cha. */
  .utab .mud-button-label { display: contents; }
  .utab.active { color: var(--primary); }
  .utab.active::after {
    content: ''; position: absolute; left: 50%; bottom: -1px; transform: translateX(-50%);
    width: 80%; height: 3px; border-radius: 3px 3px 0 0; background: var(--primary);
  }

  /* ── MudDialog (DlgBillInfo/DlgCustomerHistory/DlgBillDetail/MessageBox...) — .mud-dialog gốc
     (app.css) không set border-radius nên mặc định vuông thô. Bo tròn cho mềm mại hơn ở mobile;
     overflow:hidden để nội dung/title bar không tràn ra ngoài góc bo. ── */
  .mud-dialog { border-radius: 20px !important; overflow: hidden; }

  /* ── FAB (nút "+" nổi góc dưới phải) — dùng chung cho mọi trang danh sách có nút thêm mới
     (Bills, IncomeExpense, Customers...). Trước đây chỉ scoped trong Bills.razor.css nên các trang
     khác dùng lại Class="fab" không có position:fixed -> nút nằm lẫn trong luồng tài liệu, bị đẩy
     xuống cuối danh sách và khuất sau bottom-nav, coi như "biến mất" khỏi màn hình. ── */
  .fab {
    position: fixed; right: 20px;
    bottom: calc(78px + env(safe-area-inset-bottom));
    width: 58px !important; height: 58px !important;
    background: var(--grad-hero) !important; color: #fff;
    box-shadow: var(--shadow-fab); z-index: var(--z-fab);
    transition: transform .14s cubic-bezier(.32,.72,.25,1),
                bottom .25s ease, box-shadow .14s ease;
  }
  .fab:active { transform: scale(.95); }

  /* ── Search xổ xuống dưới app bar (MudTextField Variant.Text, bỏ underline) — dùng ở Bills,
     RevenueReportDetail. Global nên áp thẳng lên MudTextField/MudIconButton, không cần ::deep. ── */
  .search-collapse {
    max-height: 0; overflow: hidden;
    transition: max-height .28s cubic-bezier(.32,.72,.25,1),
                padding .28s cubic-bezier(.32,.72,.25,1);
  }
  .search-collapse.open { max-height: 72px; padding-bottom: 10px; }
  .search {
    margin: 10px 14px 0;
    display: flex; align-items: center; gap: 6px;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--r-md); padding: 2px 6px 2px 12px;
    box-shadow: var(--shadow-card);
    transition: border-color .15s ease, box-shadow .15s ease;
  }
  .search:focus-within {
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(89,74,226,.14), var(--shadow-card);
  }
  .search-field { flex: 1; min-width: 0; margin: 0; }
  /* Bỏ underline mặc định vì .search đã là pill có viền */
  .search-field .mud-input.mud-input-text::before,
  .search-field .mud-input.mud-input-text::after {
    border: none !important; content: none !important;
  }
  .search-field .mud-input-slot { padding-top: 4px; padding-bottom: 4px; }
  .search-field .mud-input-adornment-start .mud-icon-root { color: var(--text-2); }

  /* ── HeroBalanceCard.Mobile.razor (số dư/tổng quan nổi bật, nền .card--hero) ── */
  .hero-balance { padding: 20px; display: flex; align-items: center; gap: 14px; }
  .hero-balance-ic {
    flex: none; width: 46px; height: 46px; border-radius: 50%;
    background: rgba(255,255,255,.18);
    display: grid; place-items: center;
  }
  .hero-balance-ic .mud-icon-root { width: 24px; height: 24px; font-size: 24px; }
  .hero-balance-label { font-size: var(--font-size-base); opacity: .9; }
  .hero-balance-value { font-size: var(--font-size-2xl); font-weight: 800; letter-spacing: -.02em; margin-top: 5px; line-height: 1; }
  .hero-balance-value .u { font-size: var(--font-size-md); font-weight: 700; opacity: .85; }
  /* Khối label+value co giãn (flex:1) để badge đếm (.hero-balance-cnt, tuỳ chọn) đứng vừa bên phải —
     promote từ FinancialDetail.razor.css/ReceivableReport.razor.css (định nghĩa giống hệt nhau). */
  .hero-balance-main { flex: 1; min-width: 0; }
  /* Badge đếm số phiếu bên phải hero (FinancialDetail "Tổng nợ", ReceivableReport "Tổng tiền chưa thu") —
     promote từ 2 file trên, trước đây định nghĩa CSS giống hệt nhau chỉ khác tên class. */
  .hero-balance-cnt {
    flex: none; align-self: flex-start; font-size: var(--font-size-base); font-weight: 700;
    background: rgba(255,255,255,.16); padding: 5px 11px; border-radius: 999px; color: #fff;
  }
  /* Skeleton lúc tải (bar trắng-mờ hợp nền gradient tím) — dùng chung cho mọi .hero-balance, không
     riêng trang nào. Trước đây FinancialReport/FinancialDetail/ReceivableReport tự lặp lại quy tắc
     tô màu skeleton này 3 lần với 3 tên selector khác nhau (cb-hero-skel/fd-debt-total/unpd-total). */
  .hero-balance-skelv { margin-top: 5px; }
  .hero-balance-skelcnt { flex: none; align-self: flex-start; border-radius: 999px; }
  .hero-balance .mud-skeleton { background-color: rgba(255, 255, 255, .22); border-radius: 6px; }
  .hero-balance .mud-skeleton-wave::after {
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .3), transparent);
  }

  /* ── 2 mini card song song (vd Tổng thu / Tổng chi trong kỳ) — dùng ở FinancialReport, IncomeExpense.
     .cb-mini PHẢI set flex-direction:row rõ ràng — nếu không, bootstrap .card (flex-direction:column)
     thắng thế (element vẫn khớp cả 2 selector, nhưng chỉ 1 rule set flex-direction) -> icon rớt lên
     trên, chữ xuống dưới, căn giữa (bug, đã sửa — trước đây tưởng nhầm là chủ ý). */
  .cb-duo { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin: 12px 0 22px; }
  .cb-mini { padding: 13px; display: flex; flex-direction: row; align-items: center; gap: 11px; }
  .cb-mini > div { flex: 1; min-width: 0; }
  .cb-mini-ic {
    flex: none; width: 38px; height: 38px; border-radius: 50%;
    display: grid; place-items: center; color: #fff;
  }
  .cb-mini-ic .mud-icon-root { width: 19px; height: 19px; font-size: 19px; }
  .cb-mini .lbl { font-size: var(--font-size-xs); color: var(--text-2); }
  .cb-mini .val { font-size: var(--font-size-lg); font-weight: 800; margin-top: 3px; line-height: 1; }

  /* ── Dòng hiển thị phiên bản ở chân trang ── */
  .app-ver {
    text-align: center;
    font-size: var(--font-size-sm);
    color: var(--text-3);
    margin-top: 16px;
  }

  /* ── Trạng thái danh sách rỗng (Banks/Racks/Units/Status/Shops/Services/Customers/
     CustomerDebtDetail/CustomerPointHistory) — 9 trang tự lặp lại y hệt CSS này, chỉ khác tên
     class riêng của từng trang; gộp về đây, giữ nguyên tên class cũ trên markup (không đổi .razor). ── */
  .unit-m .unit-empty, .status-m .status-empty, .svc-m .svc-empty, .shop-m .shop-empty,
  .debt-m .cust-empty, .rack-m .rack-empty, .pts-m .cust-empty, .cust-m .cust-empty,
  .bank-m .bank-empty {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
    padding: 60px 24px; text-align: center; color: var(--text-3);
  }

  /* ══════════════════════════════════════════════════════════════════════
     REPORT CARD PRIMITIVES — dùng chung cho nhóm trang báo cáo mobile
     (RevenueReportDetail .rrd-m / ReceivableReport .rcv-m / OtherIncome .oinc-m /
      OtherExpenses .oexp-m). Trước đây port lặp trong từng *.razor.css; đã promote lên
     global sau đợt rà soát vì đủ ≥3–4 trang dùng (xem Plans/ReceivableReport.md mục 12 +
     Plans/MobileLessonsLearned.md mục 10). Global nên áp thẳng, KHÔNG cần ::deep.
     AN TOÀN với Bills/Home: các class ordr- / incd- / pd-row / pts-listhead / day- / cust-
     KHÔNG xuất hiện ở trang khác; .status base trùng y hệt .bills-m .status (Bills thêm
     cursor:pointer + scoped nên vẫn thắng); biến thể màu .status.new/.cash… là dot-chain,
     KHÔNG khớp .status--* (BEM) của Bills/Home. Phần delta riêng trang (màu tiền, accordion,
     hero, skeleton, empty, margin .incd-note, override day-card của rcv) vẫn để scoped.
     ══════════════════════════════════════════════════════════════════════ */

  /* Hiệu ứng mờ->rõ khi card lọt khung nhìn (JS bindCardReveal gắn class .card-pop). QA #3: đổi
     từ zoom-in (scale) sang fade thuần (chỉ opacity), giữ nguyên cơ chế trigger. Bills giữ keyframe
     riêng bills-card-in vì skeleton của Bills cũng dùng nó — không gộp vào đây.
     Cập nhật: bỏ easing bounce cubic-bezier(.34,1.56,.64,1) (overshoot làm opacity vọt lên sớm ->
     cảm giác "pop nhanh/giật") sang ease-out dịu (.22,1,.36,1). Chống giật khi cuộn nhanh chủ yếu
     nhờ rootMargin pre-warm trong _appscript.mobile.js (card fade xong TRƯỚC khi vào tầm mắt), nên
     ở đây chỉ cần fade mượt vừa phải, không cần kéo dài quá thành ì. */
  @keyframes card-in {
    from { opacity: 0; }
    to   { opacity: 1; }
  }
  .card-pop { animation: card-in .8s cubic-bezier(.22,1,.36,1) both; }
  @media (prefers-reduced-motion: reduce) { .card-pop { animation: none; } }

  /* Khối tổng/hero + bộ lọc + dòng đếm phía trên danh sách card — đặt NGOÀI .list (sibling,
     flex:0 0 auto) để đứng yên khi cuộn, chỉ .list (card) cuộn. Padding ngang + top ở đây thay
     cho phần .list từng đảm nhận (nay .list bỏ padding-top, xem override trong từng *.razor.css). */
  .list-subhead { flex: 0 0 auto; padding: 14px 14px 0; }

  /* Tiêu đề nhóm danh sách (Theo ngày / Theo khách hàng…). .cb-note (FinancialReport) gộp chung vào
     đây vì trước đây tự khai báo lại y hệt 3 thuộc tính này thay vì dùng chung class. */
  .pts-listhead { display: flex; align-items: center; gap: 9px; justify-content: flex-start; margin: 2px 0 12px; }
  .pts-listhead .t, .cb-note { font-size: var(--font-size-base); font-weight: 700; color: var(--text-3); }
  .pts-listhead .cnt { font-size: var(--font-size-base); color: var(--text-3); font-weight: 600; margin-left: auto; }
  .pts-listhead .cnt-skel { margin-left: auto; border-radius: 5px; }   /* skeleton thay cho số đếm lúc loading */

  /* 3 thẻ lọc tổng theo hình thức (RevenueReportDetail / OtherIncome / OtherExpenses) */
  .incd-filters { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 14px; }
  .incd-filt {
    /* display:block bắt buộc: MudBlazor.min.css có "button{display:inline-flex}" áp lên mọi <button> */
    display: block;
    background: var(--card); border: 2px solid transparent; border-radius: var(--r-md); box-shadow: var(--shadow-card);
    padding: 11px 8px; text-align: center; cursor: pointer; font-family: inherit;
    transition: border-color .15s ease, box-shadow .15s ease, transform .14s cubic-bezier(.32,.72,.25,1);
  }
  .incd-filt:active { transform: scale(.97); }
  .incd-filt.on { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(89,74,226,.12), var(--shadow-card); }
  .incd-filt .l { display: block; font-size: var(--font-size-xs); font-weight: 600; color: var(--text-3); text-transform: uppercase; letter-spacing: .02em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .incd-filt .v { display: block; font-size: var(--font-size-base); font-weight: 800; margin-top: 5px; letter-spacing: -.01em; }
  .incd-skelv { margin: 5px auto 0; }   /* skeleton số tiền, căn giữa khớp margin-top:5px của .v */
  .incd-filt.all .v  { color: var(--primary); }
  .incd-filt.cash .v { color: var(--green); }
  .incd-filt.bank .v { color: var(--blue); }
  /* .incd-filt giờ là MudButton (trước là <button> thô) — reset text-transform mặc định của MudButton
     (uppercase) để không ảnh hưởng .v khi có chữ. .l/.v vẫn display:block nên không cần display:contents
     cho .mud-button-label (khác .ince-cat/.opt vốn cần flex-row). */
  .incd-filt { text-transform: none !important; }

  /* Hàng chi tiết trong panel mở rộng (Mã phiếu / Nhân viên / Ngày…) */
  .pd-row { display: flex; justify-content: space-between; align-items: center; gap: 12px; font-size: var(--font-size-base); color: var(--text-2); padding: 3px 0; }
  /* Nhãn (span) mặc định flex-shrink:1 -> khi giá trị (b) quá dài (vd "Đã thanh toán trước (Chuyển
     khoản)") sẽ bị co lại và XUỐNG DÒNG thay vì để giá trị tự wrap. Khoá nhãn 1 dòng cố định, để
     phần co giãn + wrap thuộc về giá trị bên phải. */
  .pd-row > span:first-child { flex: none; white-space: nowrap; }
  .pd-row b { flex: 1 1 auto; min-width: 0; color: var(--text); font-weight: 700; text-align: right; }
  .pd-row b.code { font-family: var(--font-mono); font-weight: 700; font-size: var(--font-size-base); }

  /* Thẻ thông tin phiếu chung (info-card) — dùng ở IncomeExpense, dự phòng SystemLogs sau này
     (Mobile.Prototype/styles.css ghi chú đây là pattern dùng chung 2 màn). Không có accordion/click
     mở rộng — phần .info-card-detail luôn hiển thị sẵn, chỉ nút "..." (.info-card-menu) mở action sheet. */
  .info-card { margin-bottom: 12px; }   /* shell -> .card.card--raised */
  .info-card-top { display: flex; align-items: center; gap: 8px; }
  /* CHUẨN chung cho TIÊU ĐỀ card thông tin phiếu (16px / 800 / --text) — dùng chung cho mọi trang:
     IncomeExpense, OtherIncome/OtherExpenses (.oth-item), CompPromotion, SystemLogs.
     KHÔNG định nghĩa lại font tiêu đề ở CSS scoped từng trang — gắn thẳng class info-card-name này
     vào markup để đồng nhất. */
  .info-card-name { flex: 1; min-width: 0; font-size: var(--font-size-md); font-weight: 800; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* Chip mã phiếu dạng "pill" (nền tím nhạt, font mono) — promote từ CustomerPointHistory.razor.css
     lên đây vì DlgCustomerHistory dùng lại y hệt (bấm vào để mở DlgBillInfo, đồng bộ hình thức). */
  .pts-code {
    display: inline-block; font-family: var(--font-mono); font-size: var(--font-size-sm); font-weight: 600;
    color: var(--primary-dark); background: var(--primary-soft); padding: 4px 11px; border-radius: 999px;
    cursor: pointer;
  }
  .info-card-badge { flex: none; font-size: var(--font-size-2xs); font-weight: 700; letter-spacing: .03em; text-transform: uppercase; padding: 4px 10px; border-radius: 999px; background: var(--surface); color: var(--text-2); }
  .info-card-badge.thu { background: var(--green-soft, rgba(0,200,83,.12)); color: var(--green); }
  .info-card-badge.chi { background: var(--orange-soft, rgba(251,140,0,.13)); color: var(--orange); }
  .info-card-menu { flex: none; width: 30px; height: 30px; margin-right: -6px; border: none; background: none; color: var(--text-2); font-size: 18px; cursor: pointer; border-radius: 8px; display: grid; place-items: center; }
  .info-card-menu:active { background: var(--surface); }
  /* CHUẨN chung cho "meta row" (người tạo/nhận + thời gian) của mọi card thông tin phiếu:
     text 13px / var(--text-2) / weight 400, icon 14px / var(--text-3). OtherIncome/OtherExpenses
     dùng chung class .oth-meta ở trên, không định nghĩa riêng nữa. */
  .info-card-time { display: flex; align-items: center; gap: 6px; margin-top: 11px; font-size: var(--font-size-sm); color: var(--text-2); }
  .info-card-time .mud-icon-root { flex: none; font-size: 14px; color: var(--text-3); }
  .info-card-time span + .mud-icon-root { margin-left: 10px; }   /* khoảng cách giữa người nộp/nhận và icon giờ */
  /* QA #4 + #13: tăng padding-top cho thoáng hơn (dùng chung nên sửa 1 chỗ lợi cả Customers lẫn
     IncomeExpense — 2 trang duy nhất dùng info-card-detail). */
  .info-card-detail { margin-top: 13px; background: var(--surface); border-radius: var(--r-md); padding: 8px 14px; }
  .info-card-detail .pd-row.hl b { color: var(--text); font-size: var(--font-size-md); }
  .info-card-detail .pd-row.hl b.thu { color: var(--green); }
  .info-card-detail .pd-row.hl b.chi { color: var(--orange); }

  /* Card "phiếu thu khác/chi khác" dùng chung (OtherIncome + OtherExpenses) — 2 trang này trước đây
     định nghĩa CSS giống hệt nhau 100% (chỉ khác tên class oinc- và oexp- + màu tiền), gộp về đây
     dùng chung 1 bộ tên oth-; màu tiền dùng lại đúng quy ước .thu/.chi đã có ở info-card-detail
     phía trên (không tạo tên modifier mới). Lưu ý: không được để dấu sao rồi ngay sau đó là dấu
     gạch chéo trong comment CSS (kể cả cách nhau bởi 1 class name) vì cặp ký tự đó đóng comment
     sớm, làm hỏng rule ngay sau — đã gặp bug thật ở đây (viết ".oinc-*" rồi "/.oexp-*" liền nhau). */
  .oth-item { margin-bottom: var(--gap-list); }
  .oth-top { display: flex; align-items: center; gap: 9px; }
  .oth-top .status { flex: none; margin-left: auto; }
  .oth-meta { display: flex; align-items: center; gap: 6px; margin-top: 11px; font-size: var(--font-size-sm); color: var(--text-2); }
  .oth-meta > svg { flex: none; color: var(--text-3); width: 14px; height: 14px; font-size: 14px; }
  .oth-meta .who { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .oth-meta .when { margin-left: auto; flex: none; display: flex; align-items: center; gap: 5px; color: var(--text-2); font-size: var(--font-size-sm); white-space: nowrap; }
  .oth-meta .when svg { flex: none; color: var(--text-3); width: 14px; height: 14px; font-size: 14px; }
  .oth-detail { margin-top: 11px; background: var(--surface); border-radius: var(--r-md); padding: 4px 14px; }
  .oth-detail .pd-row.hl b.oth-amt { font-family: inherit; }
  .oth-detail .pd-row.hl b.oth-amt.thu { color: var(--green); }
  .oth-detail .pd-row.hl b.oth-amt.chi { color: var(--orange); }
  .oth-skel { cursor: default; }
  .oth-skel:active { transform: none; }
  .oth-empty {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
    padding: 60px 24px; text-align: center; color: var(--text-3);
  }

  /* Chip danh mục "Các khoản Thu/Chi" (lọc = Tất cả) — dùng ở IncomeExpense.
     flex-direction:row PHẢI khai rõ (giống .cb-mini) — nếu không, bootstrap .card
     (flex-direction:column) thắng thế vì .ince-cat chỉ set display:flex. */
  .ince-cat { display: flex; flex-direction: row; align-items: center; gap: 12px; width: 100%; text-align: left; padding: 13px 14px; margin-bottom: 12px; }   /* shell -> .card.card--interactive */
  .ince-cat .ic { flex: none; width: 40px; height: 40px; border-radius: var(--r-sm); background: var(--primary-soft); color: var(--primary); display: grid; place-items: center; }
  .ince-cat .m { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
  .ince-cat .m .lbl { font-size: var(--font-size-base); font-weight: 700; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .ince-cat .m .v { font-size: var(--font-size-xs); font-weight: 500; color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .ince-cat.active { box-shadow: 0 0 0 2px var(--primary), var(--shadow-card); }
  .cb-mini.active { box-shadow: 0 0 0 2px var(--primary), var(--shadow-card); }
  /* .ince-cat/.cb-mini giờ là MudButton (trước là <button> thô) — MudButton bọc nội dung trong
     .mud-button-label, phá layout flex-row đặt trực tiếp trên .ince-cat/.cb-mini. display:contents để
     icon/label bên trong tham gia thẳng vào flex của thẻ cha, không thêm 1 tầng box. */
  .ince-cat .mud-button-label,
  .cb-mini .mud-button-label { display: contents; }
  .ince-cat, .cb-mini { text-transform: none !important; }

  /* Ghi chú / Tặng lần giặt — margin dọc để scoped riêng từng trang (vị trí đặt khác nhau) */
  .incd-note { display: flex; align-items: flex-start; gap: 8px; font-size: var(--font-size-base); line-height: 1.4; color: var(--text-2); margin-top: 8px; }
  .incd-note svg, .incd-note .mud-icon-root { flex: none; margin-top: 2px; color: var(--text-3); }
  .incd-note span { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .incd-note.is-alert { align-items: center; gap: 5px; font-size: var(--font-size-sm); font-weight: var(--fw-medium); color: var(--text-2); }
  .incd-note.is-alert svg, .incd-note.is-alert .mud-icon-root { margin-top: 0; color: var(--red); }
  /* Ghi chú ở ĐÁY card (sau ordr-headbot) — vạch phân cách + đệm đáy 14px. DÙNG CHUNG 3 report
     (rcv/rrd/fd); trước đây scoped y hệt ở từng .razor.css nên gộp về đây. ordr-item có padding:0 nên
     dùng padding-bottom (không margin) để note không lọt ra ngoài card khi là phần tử cuối. */
  .incd-note-bottom { margin: 0 14px; padding: 12px 0 14px; border-top: 1px solid var(--line); }
  /* MudIcon (thay SVG thuần) không tự co theo attribute width/height HTML -> ép size 14px giữ nguyên
     kích thước gốc cho mọi icon note/due/paid dùng chung (incd-note, ordr-due, ordr-paid, cust-foot .ca). */
  .incd-note .mud-icon-root, .ordr-due .mud-icon-root, .ordr-paid .mud-icon-root, .cust-foot .ca .mud-icon-root {
    width: 14px; height: 14px; font-size: 14px;
  }

  /* Badge trạng thái — base + biến thể màu. Base trùng .bills-m .status (Bills thêm cursor).
     Màu đơn hàng khớp Tools.cs (_statusColorMap); .cash/.bank là hình thức thanh toán.
     cursor:pointer: chip giờ mở DlgBillInfo khi bấm (RevenueReportDetail/ReceivableReport/
     FinancialDetail), có @onclick:stopPropagation riêng để không kích hoạt toggle-expand của row cha. */
  .status {
    flex: none; font-size: var(--font-size-xs); font-weight: var(--fw-semibold);
    padding: 3px 9px; border-radius: var(--radius-pill); cursor: pointer;
    display: inline-flex; align-items: center; gap: 3px;
  }
  .status.new       { background: var(--orange-soft);  color: var(--orange); }  /* Đơn mới = Warning */
  .status.washing   { background: var(--primary-soft); color: var(--primary); } /* Đang giặt = Primary */
  .status.done      { background: var(--blue-soft);    color: var(--blue); }    /* Giặt xong = Info */
  .status.delivered { background: var(--green-soft);   color: var(--green); }   /* Giao khách = Success */
  .status.debt      { background: var(--red-soft);     color: var(--red); }     /* Khách nợ = Error */
  .status.cash { background: var(--green-soft); color: var(--green); }          /* Hình thức: Tiền mặt */
  .status.bank { background: var(--blue-soft);  color: var(--blue); }           /* Hình thức: Chuyển khoản */

  /* Biến thể tên class kiểu BEM (status--new...) — Bills.razor/Index.Mobile.razor dùng cách đặt tên
     này (khác dot-chain .status.new của Report ở trên) nhưng phải cùng 1 màu chuẩn Tools.cs
     (_statusColorMap) như nhau. Trước đây Bills tự định nghĩa riêng (đã lệch "Giao khách" thành xám)
     và Trang chủ tự định nghĩa riêng khác nữa (đã lệch "Đang giặt"/"Giặt xong" đảo màu nhau) — gộp về
     đây 1 nguồn duy nhất, promote từ Bills.razor.css/Index.Mobile.razor.css. */
  .status--new       { background: var(--orange-soft);  color: var(--orange); }
  .status--washing   { background: var(--primary-soft); color: var(--primary); }
  .status--done      { background: var(--blue-soft);    color: var(--blue); }
  .status--delivered { background: var(--green-soft);   color: var(--green); }
  .status--debt      { background: var(--red-soft);     color: var(--red); }

  /* Dòng "thời gian/hẹn trả" dùng chung (Bills .pickup, Trang chủ .recent-time) — promote từ
     Bills.razor.css để dùng chung 1 định nghĩa thay vì mỗi trang tự lặp lại. */
  .pickup {
    display: flex; align-items: center; gap: 6px; min-width: 0;
    font-size: var(--font-size-sm); font-weight: 600; color: var(--text-2);
  }
  .pickup.urgent { color: var(--red); font-weight: 600; }
  .pickup .mud-icon-root { flex: none; color: var(--text-3); width: 14px; height: 14px; font-size: 14px; }
  .pickup.urgent .mud-icon-root { color: var(--red); }
  .pickup span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

  /* Order card (RevenueReportDetail + ReceivableReport). Phần accordion day/cust
     (day-chev, .day-card.open, .pr, .cust-card .ordr-detail) chỉ RevenueReportDetail có
     nên để scoped riêng; rcv override day-card sang cursor:default cũng scoped. */
  .ordr-item, .day-card, .cust-card {
    background: var(--color-card); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
    margin-bottom: var(--gap-list); cursor: pointer; transition: transform var(--dur-fast) var(--ease-ios);
  }
  .ordr-item:active, .day-card:active, .cust-card:active { transform: scale(.99); }
  .ordr-item.collapsible { padding: 0; }
  .ordr-headtop { display: flex; align-items: center; gap: 11px; padding: var(--pad-card) var(--pad-card) 0; }
  .ordr-av { flex: none; width: 42px; height: 42px; border-radius: 50%; background: var(--color-avatar-bg); color: var(--color-avatar-fg); display: grid; place-items: center; font-size: var(--font-size-md); font-weight: 700; }
  .ordr-id { flex: 1; min-width: 0; }
  .ordr-cust { font-size: var(--font-size-base); font-weight: 800; letter-spacing: .03em; text-transform: uppercase; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* SĐT khách trong order-card: nâng riêng lên base(14) thay vì sm(13) như các meta khác — số điện
     thoại cần đọc chính xác từng ký tự (khác vai trò "lướt qua" của label thông thường). */
  .ordr-phone { font-size: var(--font-size-base); color: var(--text-3); margin-top: 3px; }
  .ordr-headtop .status { flex: none; }
  /* align-items:flex-end -> số tiền (.ordr-amt-lg) căn đáy, thẳng hàng với dòng cuối của
     .ordr-leftcol (.ordr-due) kể cả khi leftcol có thêm dòng KM (.ordr-promo) làm cột cao lên. */
  .ordr-headbot { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--space-2); padding: var(--space-3) var(--pad-card) var(--pad-card); }
  /* Cột trái hàng đáy đơn (đã thanh toán trước + hạn/ngày thu) — dùng chung RevenueReportDetail
     lẫn Bills (trước đây Bills tự định nghĩa ".pickup-col"/".paidline" gần như trùng lặp 100%,
     chỉ khác icon Check/CheckCircle và cách tô màu Color="Color.Success" thay vì token --green —
     gộp về đây để 2 nơi luôn khớp nhau, tránh lệch icon/màu lần nữa). */
  .ordr-leftcol { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
  .ordr-paid { display: inline-flex; align-items: center; gap: 5px; font-size: var(--font-size-sm); font-weight: var(--fw-medium); color: var(--text-2); white-space: nowrap; }
  .ordr-paid svg, .ordr-paid .mud-icon-root { flex: none; color: var(--green); }
  .ordr-due { display: flex; align-items: center; gap: 6px; min-width: 0; font-size: var(--font-size-sm); font-weight: var(--fw-medium); color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .ordr-due svg, .ordr-due .mud-icon-root { flex: none; color: var(--text-3); }
  /* Địa chỉ khách hàng — đứng trên cùng trong .ordr-leftcol (trước ordr-paid/ordr-due). Dùng chung
     FinancialDetail/RevenueReportDetail/ReceivableReport. Sao y hệt style .ordr-due (1 dòng ellipsis,
     không xuống dòng — giữ card cao ổn định cho Virtualize ItemSize cố định), chỉ đổi icon sang
     LocationOn và tăng size icon lên 16px: hình ghim có nhiều khoảng trống trong khung 24x24 hơn
     hình tròn đồng hồ, cùng 14px sẽ trông nhỏ hơn hẳn icon ordr-due xếp ngay bên dưới. */
  .ordr-addr { display: flex; align-items: center; gap: 6px; min-width: 0; font-size: var(--font-size-sm); font-weight: var(--fw-medium); color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .ordr-addr svg, .ordr-addr .mud-icon-root { flex: none; color: var(--text-3); width: 16px; height: 16px; font-size: 16px; }
  /* Dòng khuyến mãi trong nhóm info card (trên "ngày hẹn trả") — icon quà đỏ, đồng kích thước
     với icon "Hẹn trả"/pickup cùng nhóm (14px). */
  .ordr-promo { display: flex; align-items: center; gap: 6px; min-width: 0; font-size: var(--font-size-sm); font-weight: var(--fw-medium); color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .ordr-promo svg, .ordr-promo .mud-icon-root { flex: none; color: var(--red) !important; fill: var(--red) !important; width: 14px; height: 14px; font-size: 14px; }
  .ordr-amt-lg { flex: none; margin-left: auto; font-size: var(--font-size-lg); font-weight: 800; color: var(--text); }
  .ordr-amt-lg.zero { color: var(--text-3); }
  .ordr-detail { background: var(--surface); border-radius: var(--r-md); }
  /* Panel chi tiết bill (report) — đồng bộ pattern Bills: hiện/ẩn tức thời bằng display (không dùng
     max-height vì số dòng thay đổi nhiều, dễ bị cắt/lệch nhịp animation). Gom đầy đủ thông tin đơn.
     Khi mở: ẩn phần tóm tắt (ordr-headbot: địa chỉ/KM/ngày/tiền) + ghi chú thu gọn (incd-note-bottom),
     chỉ giữ headtop (tên/SĐT/chip trạng thái). */
  .ordr-item.collapsible .ordr-detail { display: none; margin: var(--space-3) var(--pad-card) 0; padding: 6px 12px; }
  /* Khi mở, .ordr-headbot (vốn mang padding-bottom) bị ẩn -> bù padding-bottom cho article để panel
     không dính sát đáy card. Không đặt margin-bottom trên panel: article padding:0 + không có
     border/padding đáy nên margin-bottom của con sẽ bị margin-collapsing lọt ra NGOÀI card (vô dụng). */
  .ordr-item.collapsible.open { padding-bottom: var(--pad-card); }
  .ordr-item.collapsible.open .ordr-detail { display: block; }
  .ordr-item.collapsible.open .ordr-headbot,
  .ordr-item.collapsible.open .incd-note-bottom { display: none; }
  /* Nội dung panel chi tiết — DÙNG CHUNG Bills (card.bill ordr-detail) + report (ordr-item ordr-detail):
     dòng Tổng cộng nổi bật (gạch đứt + số primary), dòng hẹn gấp tô đỏ, ghi chú trong panel. Trước đây
     trùng ở Bills.razor.css lẫn đây -> gộp về generic ordr-detail. day-card/cust-card dùng .pr (không có
     pd-row.hl/pd-note) và DlgCustomerHistory dùng info-card-detail nên không bị dính. */
  .ordr-detail .pd-row.hl { margin-top: 4px; padding-top: 6px; border-top: 1px dashed var(--border); }
  .ordr-detail .pd-row.hl b { color: var(--primary); font-size: var(--font-size-md); }
  .ordr-detail .pd-row.due-urgent b { color: var(--red); }
  .ordr-detail .pd-note { display: flex; align-items: flex-start; gap: 6px; margin-top: 6px; padding-top: 8px; border-top: 1px dashed var(--border); font-size: var(--font-size-base); line-height: var(--lh-normal); color: var(--text-2); }
  .ordr-detail .pd-note svg,
  .ordr-detail .pd-note .mud-icon-root { flex: none; margin-top: 2px; width: 15px; height: 15px; font-size: 15px; color: var(--text-3); }
  .ordr-detail .pd-note.is-alert svg,
  .ordr-detail .pd-note.is-alert .mud-icon-root { color: var(--red); }
  .day-card { padding: 0; }
  .day-row-head { display: flex; align-items: center; gap: 10px; padding: var(--pad-card); }
  .day-left { flex: 1; min-width: 0; }
  .day-date { font-size: var(--font-size-base); font-weight: 700; color: var(--text); }
  .day-sub { font-size: var(--font-size-sm); color: var(--text-3); margin-top: 2px; }
  .day-amt { flex: none; font-size: var(--font-size-md); font-weight: 800; color: var(--text); }
  .day-amt.zero { color: var(--text-3); font-weight: 500; }
  .cust-card { padding: var(--pad-card); }
  .cust-head { display: flex; align-items: center; gap: 11px; }
  .cust-head .ordr-id { flex: 1; min-width: 0; }
  .cust-money { flex: none; text-align: right; }
  .cust-amt { font-size: var(--font-size-lg); font-weight: 800; color: var(--text); letter-spacing: -.01em; }
  .cust-amt.zero { color: var(--text-3); }
  .cust-cnt { font-size: var(--font-size-sm); color: var(--text-3); margin-top: 3px; }
  .cust-foot { margin-top: 9px; padding-top: 11px; border-top: 1px solid var(--line); display: flex; flex-direction: column; gap: 6px; }
  .cust-foot .ca { display: flex; align-items: center; gap: 6px; font-size: var(--font-size-base); color: var(--text-2); }
  .cust-foot .ca svg, .cust-foot .ca .mud-icon-root { flex: none; color: var(--text-3); }

  /* Accordion "Theo ngày/Theo khách hàng" (chevron xoay + panel breakdown tiền mặt/chuyển khoản) —
     promote từ RevenueReportDetail.razor.css/FinancialDetail.razor.css (2 file định nghĩa giống hệt
     nhau 100%, chỉ khác prefix .rrd-m/.fd-m) về đây để dùng chung 1 nguồn duy nhất. */
  .day-chev { flex: none; color: var(--text-3); transition: transform var(--dur-base) var(--ease-ios); }
  .day-card.open .day-chev { transform: rotate(90deg); }
  .day-card .ordr-detail { margin: 0 var(--pad-card); max-height: 0; opacity: 0; overflow: hidden; padding: 0 12px;
    transition: max-height var(--dur-slow) var(--ease-ios), opacity var(--dur-base) ease, margin-top var(--dur-slow) ease, padding var(--dur-slow) ease; }
  .day-card.open .ordr-detail { max-height: 100px; opacity: 1; margin: 0 var(--pad-card) var(--pad-card); padding: 2px 12px; }
  .day-card .ordr-detail .pr,
  .cust-card .ordr-detail .pr { display: flex; align-items: center; gap: 8px; font-size: var(--font-size-base); color: var(--text-2); padding: 6px 0; }
  .day-card .ordr-detail .pr .l,
  .cust-card .ordr-detail .pr .l { flex: 1; min-width: 0; }
  .day-card .ordr-detail .pr .c,
  .cust-card .ordr-detail .pr .c { flex: none; width: 56px; color: var(--text-3); font-size: var(--font-size-sm); text-align: center; }
  .day-card .ordr-detail .pr b,
  .cust-card .ordr-detail .pr b { flex: none; width: 80px; color: var(--text); font-weight: 700; text-align: right; }
  .cust-card .ordr-detail { margin-top: 0; max-height: 0; opacity: 0; overflow: hidden; padding: 0 12px; border-radius: var(--r-md); background: var(--surface);
    transition: max-height var(--dur-slow) var(--ease-ios), opacity var(--dur-base) ease, margin-top var(--dur-slow) ease, padding var(--dur-slow) ease; }
  .cust-card.open .ordr-detail { max-height: 100px; opacity: 1; margin-top: 9px; padding: 2px 12px; }

  /* ── Trang xác thực (Login/ForgotPassword/ResetPassword) — full-bleed kiểu app gốc:
     không thẻ nổi, nội dung nằm trực tiếp trên nền gradient sẵn có của <body> (app.css),
     logo lớn dạng hero, field Variant="Variant.Filled" (MudTextField/MudSelect).
     Dùng chung cho cả 3 trang nên đặt ở đây thay vì lặp lại trong từng {Page}.razor.css. ── */

  /* Wrapper của AnnonymousLayout là "container-fluid p-2" + inline min-height:100vh. Với con
     .auth-m cao 100dvh, padding p-2 (8px trên+dưới) cộng dồn khiến tổng = 100dvh + 16px > viewport
     -> sinh thanh cuộn dọc thừa đúng 16px. Vô hiệu padding + min-height:100vh của wrapper CHỈ ở
     trang auth (chỉ khớp khi có .auth-m, tức mobile login/forgot/reset) để chỉ 100dvh của .auth-m
     quyết định chiều cao. !important đè được cả min-height inline (inline không phải !important). */
  .container-fluid:has(.auth-m) {
    padding: 0 !important;
    min-height: 0 !important;
  }

  .auth-m {
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    padding: max(env(safe-area-inset-top), 24px) 24px calc(20px + env(safe-area-inset-bottom));
  }
  .auth-m.auth-center { align-items: center; justify-content: center; text-align: center; gap: 14px; }
  /* Màn thông báo (Đã gửi mail / Đổi mật khẩu thành công): canh giữa NGANG như .auth-center nhưng
     neo TRÊN (không justify-content:center) — nội dung ngắn nên auth-center làm nó lơ lửng giữa
     khoảng trắng mênh mông phía dưới, cảm giác trống trải/không tự nhiên trên màn hình dài. */
  .auth-m.auth-top { align-items: center; justify-content: flex-start; text-align: center; gap: 14px; }

  .auth-topnav { display: flex; align-items: center; gap: 4px; margin: -8px -10px 20px; }
  .auth-topnav .t { font-size: var(--font-size-md); font-weight: 700; color: var(--text); }

  /* Bố trí logo giữ nguyên như bản gốc: avatar "U" + "viwash" nằm NGANG cùng dòng (không xếp
     dọc), slogan/subtitle xuống dòng dưới — chỉ thêm khoảng cách trên/dưới cho vừa màn hình mobile,
     không đổi kích thước/kiểu chữ so với desktop. */
  .auth-hero { text-align: center; margin: 24px 0 32px; }

  .auth-fields { display: flex; flex-direction: column; gap: 2px; }
  .auth-forgot { display: flex; justify-content: flex-end; margin: 6px 2px 4px; }

  /* Field Variant="Variant.Filled" mặc định MudBlazor: hộp nền xám phẳng (rgba(0,0,0,.09)), chỉ bo
     2 góc trên (đúng spec Material Filled input) + gạch chân dưới — không hợp phong cách "mềm mại,
     bóng bẩy" của trang auth (full-bleed trên nền gradient, không thẻ nổi). Đổi thành nền trong suốt
     (gradient trắng mờ kiểu kính mờ, vẫn thấy nền gradient phía sau) + viền mềm bo tròn đều 4 góc +
     đổ bóng nhẹ (tái dùng --shadow-card, cùng công thức với .incd-filt đã dùng), bỏ hẳn gạch chân
     Material gốc (::before/::after của .mud-input-underline). */
  .auth-fields .mud-input-filled {
    background: linear-gradient(180deg, rgba(255,255,255,.32), rgba(255,255,255,.10)) !important;
    border: 1.5px solid rgba(255,255,255,.55);
    border-radius: var(--r-md) !important;
    box-shadow: var(--shadow-card);
    transition: border-color .15s ease, box-shadow .15s ease;
  }
  .auth-fields .mud-input-underline::before,
  .auth-fields .mud-input-underline::after {
    display: none;
  }
  .auth-fields .mud-input-control:focus-within .mud-input-filled {
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(89,74,226,.16), var(--shadow-card);
  }

  .auth-submit.mud-button-root {
    border-radius: var(--r-pill) !important;
    height: 52px;
    font-size: var(--font-size-md);
    font-weight: 700;
    text-transform: none;
    box-shadow: 0 10px 24px rgba(74,59,212,.28);
    margin-top: 14px;
  }

  .auth-hotline { display: flex; justify-content: center; margin-top: 24px; }

  .auth-note {
    font-size: var(--font-size-sm);
    color: var(--text-2);
    line-height: 1.5;
    text-align: center;
    background: var(--surface);
    border-radius: var(--r-md);
    padding: 14px 16px;
  }
}

