html {
  font-size: 14px;
}

@media (min-width: 768px) {
  html {
    font-size: 16px;
  }
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

html {
  position: relative;
  min-height: 100%;
}

body {
  margin-bottom: 60px;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
  color: var(--bs-secondary-color);
  text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
  text-align: start;
}

/* ===== Trợ lý AI chatbot — phong cách Messenger ===== */
.chatbot-overlay { display: none; } /* Messenger không dùng lớp phủ tối */

.chatbot-panel {
  position: fixed;
  bottom: 20px;
  right: 20px;
  width: 340px;
  max-width: calc(100vw - 24px);
  height: 520px;
  max-height: calc(100vh - 90px);
  display: flex;
  flex-direction: column;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, .22);
  z-index: 1080;
  overflow: hidden;
  font-size: 14px;
  /* Hiệu ứng bung ra từ góc dưới-phải kiểu Messenger */
  transform: scale(.5);
  transform-origin: bottom right;
  opacity: 0;
  visibility: hidden;
  transition: transform .18s ease, opacity .18s ease, visibility .18s ease;
}
.chatbot-panel.open { transform: scale(1); opacity: 1; visibility: visible; }
.chatbot-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  background: linear-gradient(90deg, #0a7cff, #0064e0);
  color: #fff;
  font-weight: 600;
  font-size: 15px;
  flex-shrink: 0;
}
.chatbot-header .chatbot-avatar {
  width: 34px; height: 34px; border-radius: 50%;
  background: rgba(255, 255, 255, .22);
  display: flex; align-items: center; justify-content: center;
  font-size: 16px; flex-shrink: 0;
}
.chatbot-header .chatbot-title { display: flex; flex-direction: column; line-height: 1.15; }
.chatbot-header .chatbot-title small { font-weight: 400; font-size: 11px; opacity: .9; }
.chatbot-header .chatbot-online { color: #31d863; font-size: 8px; vertical-align: middle; }
.chatbot-header .chatbot-close { margin-left: auto; }
.chatbot-close {
  background: none;
  border: none;
  color: #fff;
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
}
.chatbot-messages {
  flex: 1;
  overflow-y: auto;
  padding: 12px 12px 6px;
  background: #fff;
}
.chatbot-msg { margin-bottom: 10px; display: flex; }
.chatbot-msg.user { justify-content: flex-end; }
.chatbot-bubble {
  max-width: 78%;
  padding: 8px 12px;
  border-radius: 18px;
  line-height: 1.4;
  word-wrap: break-word;
  overflow-wrap: anywhere;
}
.chatbot-msg.user .chatbot-bubble {
  background: #0a7cff;
  color: #fff;
  border-radius: 18px 18px 4px 18px;
}
.chatbot-msg.bot .chatbot-bubble {
  background: #e9ebee;
  color: #050505;
  border-radius: 18px 18px 18px 4px;
}
.chatbot-bubble p { margin: 0 0 6px; }
.chatbot-bubble p:last-child { margin: 0; }
.chatbot-bubble ul, .chatbot-bubble ol { margin: 4px 0; padding-left: 20px; }
.chatbot-bubble pre {
  background: #f0f0f0;
  padding: 8px;
  border-radius: 6px;
  overflow-x: auto;
}
.chatbot-bubble code { font-size: .9em; }
.chatbot-typing { font-style: italic; color: #888; }
.chatbot-input {
  display: flex;
  gap: 8px;
  align-items: flex-end;
  padding: 10px 12px;
  border-top: 1px solid #eef0f2;
  background: #fff;
}
.chatbot-input textarea {
  flex: 1;
  resize: none;
  border: none;
  border-radius: 20px;
  background: #f0f2f5;
  padding: 9px 14px;
  max-height: 120px;
  outline: none;
  font-size: 14px;
  line-height: 1.3;
}
.chatbot-send {
  background: none;
  color: #0a7cff;
  border: none;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  cursor: pointer;
  font-size: 17px;
  flex-shrink: 0;
  transition: background .15s ease;
}
.chatbot-send:hover { background: #eaf3ff; }
.chatbot-send:disabled { opacity: .45; cursor: not-allowed; background: none; }
@media (max-width: 480px) {
  .chatbot-panel { width: 100vw; }
}

/* Footer luôn nằm đáy: cho phần nội dung giãn đầy chiều cao của .app-body (flex column).
   Giữ cả 2 selector: .app-body > .app-content là cấu trúc THẬT của layout; rule .main-content
   của theme (.app-content .content-wrapper .main-content) lo phần bên trong. */
.app-body > .app-content { flex: 1 1 auto; }
.app-body > .main-content { flex: 1 1 auto; }

/* ============================================================================
   LƯỚI AN TOÀN — sidebar phải cuộn được trên điện thoại
   ----------------------------------------------------------------------------
   Theme cố ý TẮT slimscroll trên mobile để dùng cuộn native (smartApp.js:107-125:
   `if (!mobileOperator()) {...} else { BODY.classList.add('no-slimscroll') }`), và CSS
   `body:not(.no-slimscroll) .custom-scroll { overflow: hidden }` chỉ nhả cuộn khi class
   no-slimscroll CÓ MẶT trên <body>.

   Nhưng dòng đó nằm SAU `document.querySelector('.main-content').classList.add(...)` trong
   CÙNG handler DOMContentLoaded và theme KHÔNG guard null → layout nào thiếu .main-content sẽ
   ném TypeError → no-slimscroll không bao giờ được thêm → `.custom-scroll` giữ overflow:hidden
   → trên mobile `.app-sidebar` là position:fixed/top:0/bottom:0 nên menu bị CẮT CỨNG, không
   cuộn được (đo thật 2026-07-16: nav scrollHeight 1037px trong clientHeight 601px).

   Gốc rễ đã vá bằng cách bọc .main-content trong 3 layout. Rule dưới là lưới an toàn: cưỡng
   bức cuộn native trên mobile kể cả khi JS theme lại chết vì lý do khác. KHÔNG sửa file theme
   (quy tắc dự án) — chỉ ghi đè từ site.css. */
@media only screen and (max-width: 991.98px) {
  .app-sidebar .primary-nav.custom-scroll,
  body:not(.no-slimscroll) .app-sidebar .primary-nav.custom-scroll {
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
  }
  /* Bản thân sidebar cũng cho cuộn (mobile theme đặt position:fixed; top:0; bottom:0). */
  .app-sidebar { overflow-y: auto; -webkit-overflow-scrolling: touch; }
}

/* ============================================================================
   nl-notify — popup thông báo sau submit (thay cho alert alert-success/danger/info
   render inline trong view). Xem wwwroot/Scripts/nlnotify.js + Views/Shared/_NotifyPopup.cshtml.
   Namespace riêng: .nl-notify-* — KHÔNG đụng file gốc smartadminNew.
   ============================================================================ */
.nl-notify-overlay {
  position: fixed;
  inset: 0;
  z-index: 20000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(15, 23, 42, 0.55);
  opacity: 0;
  transition: opacity .18s ease;
}
.nl-notify-overlay.nl-notify-show { opacity: 1; }

.nl-notify-box {
  width: 100%;
  max-width: 380px;
  background: #ffffff;
  color: #1f2937;
  border-radius: 14px;
  padding: 30px 28px 22px;
  text-align: center;
  box-shadow: 0 20px 50px rgba(0, 0, 0, .25);
  transform: scale(.92) translateY(8px);
  transition: transform .18s ease;
}
.nl-notify-overlay.nl-notify-show .nl-notify-box {
  transform: scale(1) translateY(0);
}

.nl-notify-icon {
  width: 64px;
  height: 64px;
  margin: 0 auto 14px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 30px;
  font-weight: 700;
  line-height: 1;
}
.nl-notify-success .nl-notify-icon { background: #e6f7ee; color: #16a34a; }
.nl-notify-error .nl-notify-icon   { background: #fdecec; color: #dc2626; }
.nl-notify-info .nl-notify-icon    { background: #e8f1ff; color: #2563eb; }

.nl-notify-message {
  font-size: 15px;
  line-height: 1.5;
  margin-bottom: 22px;
  white-space: pre-line;
  word-break: break-word;
}

.nl-notify-close-btn {
  border: none;
  border-radius: 8px;
  padding: 8px 30px;
  font-size: 14px;
  font-weight: 600;
  color: #fff;
  cursor: pointer;
  background: #6b7280;
  transition: background .15s ease;
}
.nl-notify-success .nl-notify-close-btn { background: #16a34a; }
.nl-notify-success .nl-notify-close-btn:hover { background: #15803d; }
.nl-notify-error .nl-notify-close-btn { background: #dc2626; }
.nl-notify-error .nl-notify-close-btn:hover { background: #b91c1c; }
.nl-notify-info .nl-notify-close-btn { background: #2563eb; }
.nl-notify-info .nl-notify-close-btn:hover { background: #1d4ed8; }

/* Dark mode: theme toggle của smartadminNew set data-bs-theme trên <html> (saveloadscript.js) */
:root[data-bs-theme="dark"] .nl-notify-overlay,
[data-theme="dark"] .nl-notify-overlay {
  background: rgba(0, 0, 0, .65);
}
:root[data-bs-theme="dark"] .nl-notify-box,
[data-theme="dark"] .nl-notify-box {
  background: #1e293b;
  color: #e5e7eb;
  box-shadow: 0 20px 50px rgba(0, 0, 0, .5);
}
:root[data-bs-theme="dark"] .nl-notify-close-btn,
[data-theme="dark"] .nl-notify-close-btn {
  color: #fff;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-bs-theme="light"]):not([data-theme="light"]) .nl-notify-box {
    background: #1e293b;
    color: #e5e7eb;
  }
  :root:not([data-bs-theme="light"]):not([data-theme="light"]) .nl-notify-overlay {
    background: rgba(0, 0, 0, .65);
  }
}
/* ===================== Ký số (kyso) — dialog xem + chọn vị trí ký ===================== */
.kyso-modal .modal-body { display: flex; flex-direction: column; }
.kyso-viewer {
  background: #525659;
  overflow: auto;
  padding: 16px 0;
  min-height: 55vh;
  max-height: 70vh;
}
.kyso-page {
  position: relative;
  margin: 0 auto 16px auto;
  background: #fff;
  box-shadow: 0 2px 10px rgba(0,0,0,.5);
  cursor: crosshair;
}
.kyso-page canvas { display: block; }
.kyso-sigbox {
  position: absolute;
  border: 2px dashed #0a7cff;
  background: rgba(10,124,255,.12);
  box-sizing: border-box;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; color: #0a7cff; font-weight: 600;
  pointer-events: none;
}
.kyso-toolbar { background: #f7f8fa; }
.kyso-hint { background: #eef5ff; }
@media (prefers-color-scheme: dark) {
  :root:not([data-bs-theme="light"]):not([data-theme="light"]) .kyso-toolbar { background: #1e293b; }
  :root:not([data-bs-theme="light"]):not([data-theme="light"]) .kyso-hint { background: #17233b; }
}

/* ============================================================
   nldash — Dashboard đơn vị (plan dashboard-don-vi, P0)
   Linh kiện: Views/Shared/NlDash/_*.cshtml + Scripts/nldashboard.js

   🔑 NGUYÊN TẮC (rà lại 2026-08-04): chỉ giữ ở đây thứ THEME KHÔNG CÓ.
   Đã bỏ 9 nhóm rule vì smartadminNew đã lo sẵn — dùng thẳng utility của theme:
     .nldash-delta            → .opacity-90
     .nldash-feed-item        → .list-group.list-group-flush > .list-group-item
     .nldash-info-row/-list   → .list-group-flush + .d-flex.justify-content-between
     .nldash-info-label       → .fs-b (.8125rem = 13px)
     .nldash-info-value       → .fw-700.text-end
     .nldash-info-ico         → .position-absolute.pos-right.pos-bottom.opacity-15.pe-none.fa-3x
     .nldash-chart-wrap       → .position-relative.w-100
     .nldash-cell-bar chiều cao → .progress-sm (8px)
     .nldash-table cỡ chữ/padding → .table-sm của theme (.825rem / .25rem — CHẶT HƠN bản viết tay)
   Kèm lợi ích thật: đường kẻ list-group lấy từ var(--bs-list-group-border-color) nên
   TỰ đúng ở chế độ tối ⇒ xoá được luôn 2 rule [data-bs-theme="dark"] phải bảo trì tay.
   ============================================================ */
.nldash-panel .panel-content { padding: 1rem; } /* theme cho :first-child .625rem — dashboard cần thoáng hơn */

/* Ô biểu tượng tròn đầu dòng feed: theme không có utility kích thước cố định 30px */
.nldash-ico-o { width: 30px; height: 30px; display: inline-flex; align-items: center; justify-content: center; border-radius: .5rem; flex: 0 0 auto; }

/* Tiêu đề phân nhóm giữa các dải widget — theme không có component tương đương */
.nldash-section-title { display: flex; align-items: center; gap: .5rem; margin: 1.5rem 0 .9rem; padding-left: .6rem; border-left: 4px solid #2E74B5; font-size: 1.05rem; font-weight: 700; }
.nldash-section-title i { color: #2E74B5; }

/* Panel hẹp: tiêu đề được xuống dòng gọn thay vì bị nút "Chi tiết" ép thành cột chữ dọc.
   Nút toolbar tách xuống dòng riêng khi không đủ chỗ (flex-wrap). Theme mặc định nowrap. */
.nldash-panel .panel-hdr { flex-wrap: wrap; row-gap: .25rem; }
.nldash-panel .panel-hdr h2 { white-space: normal; line-height: 1.3; min-width: 0; flex: 1 1 auto; }
.nldash-panel .panel-toolbar { flex: 0 0 auto; }
/* Cột đầu bảng không bị ép hẹp tới mức bẻ chữ theo chiều dọc (bài học "hub chật" 2026-07-16) */
.nldash-panel .nldash-table td:first-child { min-width: 96px; }

/* Bề ngang tối thiểu — theme chỉ có utility bề ngang theo % / auto, không có min-width px */
.nldash-cell-progress { min-width: 70px; }
.nldash-cell-bar { min-width: 24px; }
.nldash-picker { min-width: 260px; }
.nldash-filter .form-select { min-width: 120px; }

/* =============================================================================
   Modal bcommand (#myModal) responsive + đồng bộ nút — vá 2026-07-17
   Lỗi (đo THẬT browser 390px + ảnh chụp): modal-dialog width CỨNG 800px,
   max-width:none => tràn phải 410px trên điện thoại. Footer justify-content:
   flex-end => hàng nút dồn về x≈800 (ngoài màn hình) => NÚT PHẢI (Đóng/Lưu/Xóa)
   BỊ MẤT, chỉ nút trái bấm được. (transform-25% ban đầu nghi ngờ -> ĐO LOẠI: none.)
   KHÔNG sửa file theme; chỉ thêm lưới an toàn ở site.css.
   ============================================================================= */
@media (max-width: 991.98px) {
    /* Ép modal vừa khung điện thoại: bỏ width cứng 800px + dock lệch trái 25%,
       về full-screen từ mép trái. Selector kèm `.modal` để thắng specificity của
       theme `.modal.fade .modal-dialog-start` (0,3,0) — nếu chỉ `#myModal .x` thì
       transform:none KHÔNG thắng translate(-25%) của theme (đã đo THẬT: modal lệch
       trái 97px, mép trái cắt ngoài màn). Cần cả -webkit-transform + left/right. */
    #myModal.modal .modal-dialog,
    #myModal.modal .modal-dialog-start,
    #myModal.modal .modal-dialog-end,
    #kyso-modal.modal .modal-dialog {
        width: 100% !important;
        max-width: 100vw !important;
        margin: 0 !important;
        left: 0 !important;
        right: auto !important;
        transform: none !important;
        -webkit-transform: none !important;
    }
    #myModal .modal-content,
    #kyso-modal .modal-content { max-width: 100vw; border-radius: 0; }
}

/* Đồng bộ hàng nút modal về BÊN TRÁI (chốt: modal dock-start neo trái => nút
   trái luôn trong tầm ngón cái mobile). Khảo sát 606 view có nút modal:
   91 view kiểu cũ đã để nút trong <div> căn TRÁI; 512 view mới dùng
   `.d-flex.justify-content-end` (nút PHẢI) + 6 view `.modal-footer` (mặc định
   flex-end). Kéo 2 nhóm phải về trái cho nhất quán — an toàn vì trong modal,
   `.justify-content-end` CHỈ dùng cho hàng nút (đã verify: mọi chỗ là
   `<div class="d-flex justify-content-end gap-2">` bọc nút submit/dismiss). */
#myModal .modal-footer,
#myModal .justify-content-end { justify-content: flex-start !important; }

/* ============================================================================
   LƯỚI AN TOÀN RESPONSIVE BẢNG (mobile) — 2026-07-18
   Chuẩn dự án: MỌI bảng phải bọc `<div class="table-responsive">` (theme-guide
   dòng 162-166). Bảng `.dt-basic-example` do DataTables (responsive:true) tự lo.
   Rule này là LƯỚI AN TOÀN cho bảng `.table` KHÔNG phải DataTable mà LỠ quên bọc
   .table-responsive: trên điện thoại cho cuộn ngang thay vì phá vỡ layout trang.
   - `:not(.dataTable)` bỏ qua bảng DataTables đã init (theme tự thêm class này).
   - Rule reset trả bảng ĐÃ bọc .table-responsive về display:table (div cha đã lo
     cuộn) => KHÔNG đổi hành vi 204 bảng đã bọc đúng chuẩn. KHÔNG sửa file theme.
   ============================================================================ */
@media (max-width: 991.98px) {
  .app-content table.table:not(.dataTable) {
    display: block;
    width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .app-content .table-responsive > table.table:not(.dataTable) {
    display: table;
  }
}

/* ============================================================================
   HEADER + SIDEBAR CỐ ĐỊNH (fixed) khi cuộn — user yêu cầu 2026-07-19
   `<html>` 3 layout area gắn `set-header-fixed set-nav-fixed` → theme cho sidebar
   position:fixed + overflow-y:auto (đứng yên, cuộn menu riêng khi dài) + header fixed.
   Header của theme fixed đúng ở TF nhưng ở Admin/KhachSan lại ra `static` (cùng markup
   .app-header, KHÔNG file CSS nào override — nguyên nhân chưa rõ). site.css nạp CUỐI ở
   cả 3 layout nên rule dưới ép header cố định ĐỒNG NHẤT (header+sidebar cùng đứng yên,
   nội dung cuộn ở giữa = mẫu admin dashboard chuẩn). KHÔNG sửa file theme.
   Chỉ áp desktop (≥992px); mobile sidebar là off-canvas riêng, không đụng.
   ============================================================================ */
@media (min-width: 992px) {
  .set-header-fixed .app-header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1035;
  }
}

/* ============================================================================
   HỘP THƯ (HopThu) — khôi phục chuỗi chiều cao khi .layout-trimmed bị LỒNG
   trong lớp bọc .main-content của layout (vá 2026-07-19).
   Layout bọc @RenderBody() trong .main-content (bắt buộc — DOM contract của
   smartApp.js, vá 2026-07-16). Nhưng HopThu.cshtml là trang DUY NHẤT dùng mẫu
   "trimmed layout" của theme: tự mang .main-content.layout-trimmed và theme
   yêu cầu nó là CON TRỰC TIẾP của .content-wrapper:
   - .app-content .content-wrapper .main-content { flex:1 1 auto } chỉ có tác
     dụng khi cha là flex — lớp bọc là block ⇒ flex vô hiệu ⇒ vùng danh sách
     thư (flex-grow-1 > position-absolute + overflow-y-auto) cao 0px, thư bị
     cắt cụt dù server render đủ.
   - .content-wrapper:has(>.layout-trimmed){padding:0} không còn khớp ⇒ viền
     trắng thừa quanh khung thư.
   2 rule dưới vá cả 2 (đo thật headless 1280×800: vùng thư 0px → ~519px).
   ============================================================================ */
.content-wrapper > .main-content:has(> .layout-trimmed) {
  display: flex;
  flex-direction: column;
}
.content-wrapper:has(.layout-trimmed) {
  padding: 0 !important;
}

/* ============================================================
   pq-tree — Cây phân quyền (màn /Admin/PhanQuyenCay/Cay)
   Namespace riêng .pq-* — KHÔNG đụng file theme smartadminNew.
   ============================================================ */
.pq-tree { border: 1px solid rgba(0,0,0,.12); border-radius: .35rem; padding: .5rem; max-height: 62vh; overflow: auto; }
.pq-node.pq-an { display: none; }
.pq-row { display: flex; align-items: center; gap: .4rem; padding: 2px 4px; border-radius: .25rem; }
.pq-row:hover { background: rgba(0,0,0,.045); }
.pq-toggle { cursor: pointer; width: 16px; display: inline-block; text-align: center; user-select: none; opacity: .7; }
.pq-toggle-empty { width: 16px; display: inline-block; }
.pq-ten { display: flex; align-items: center; gap: .35rem; margin: 0; cursor: pointer; flex: 1 1 auto; min-width: 0; }
.pq-ten > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pq-badge { font-size: 10px; }
.pq-actions { display: flex; gap: .55rem; flex: 0 0 auto; }
.pq-act { display: flex; align-items: center; gap: .2rem; margin: 0; font-size: 12px; cursor: pointer; white-space: nowrap; }
.pq-act-locked { opacity: .55; cursor: not-allowed; }
/* Thừa hưởng từ nhóm: mờ nhẹ để phân biệt với cấp thẳng, nhưng VẪN bấm được
   (bỏ tick = chặn riêng đối tượng đó). */
.pq-act-ke { opacity: .72; }
/* Đang bị chặn riêng — gạch ngang + đỏ để nhìn là biết đây không phải "chưa cấp". */
.pq-act-chan { opacity: 1; color: #d9534f; text-decoration: line-through; }
.pq-nguon { font-size: 10px; color: #888; }
.pq-children.pq-hidden { display: none; }
.pq-node.pq-khop > .pq-row { background: rgba(255, 193, 7, .22); }

@media (max-width: 767.98px) {
    .pq-row { flex-wrap: wrap; }
    .pq-actions { width: 100%; padding-left: 22px; flex-wrap: wrap; }
}

/* ===================== nlpjax — điều hướng không tải lại trang ===================== */
/* Chỉ báo "đang tải" khi chuyển màn bằng PJAX. Không có nó thì click sidebar xong
   màn hình đứng im vài trăm ms, người dùng tưởng bấm hụt và bấm lại. */
body.nlpjax-dangtai .main-content {
    opacity: .55;
    transition: opacity .12s linear;
    pointer-events: none;   /* chặn bấm chồng khi đang tải */
}

body.nlpjax-dangtai::after {
    content: "";
    position: fixed;
    top: 0; left: 0;
    height: 3px;
    width: 100%;
    z-index: 2000;
    background: linear-gradient(90deg, #198754 0%, #34d399 50%, #198754 100%);
    background-size: 40% 100%;
    background-repeat: no-repeat;
    animation: nlpjax-chay 900ms ease-in-out infinite;
}

@keyframes nlpjax-chay {
    0%   { background-position: -40% 0; }
    100% { background-position: 140% 0; }
}
