/* ==========================================================================
   THINKSMART PORTAL — trang công ty (home / login / videos)
   Token copy từ style.css §1 — ĐỔI TOKEN Ở CẢ HAI FILE để đồng bộ với Tool.
   Khác biệt chủ đích với tool: body CUỘN ĐƯỢC (trang nội dung, không phải app).
   Accent theo khu vực (structure = information): Học = teal, Tool = violet,
   Forum = amber — trùng hệ --cat-* sẵn có của tool.
   ========================================================================== */

:root {
  --brand-50:  #F5F2FF;
  --brand-100: #ECE6FE;
  --brand-200: #D8CCFD;
  --brand-300: #B9A3FA;
  --brand-400: #9670F4;
  --brand-500: #7C3AED;
  --brand-600: #6D28D9;
  --brand-700: #5B21B6;
  --brand-800: #4F00CA;
  --brand-900: #3A0E7A;

  --brand:          var(--brand-600);
  --brand-hover:    var(--brand-500);
  --brand-active:   var(--brand-700);
  --brand-contrast: #FFFFFF;
  --brand-soft:     var(--brand-50);
  --brand-soft-2:   var(--brand-100);
  --brand-ring:     rgba(109, 40, 217, 0.28);

  --gradient-brand: linear-gradient(135deg, #7C3AED 0%, #5B21B6 100%);
  --gradient-hero:  linear-gradient(135deg, #3B0764 0%, #6D28D9 50%, #7C3AED 100%);

  --glass-bg: rgba(255, 255, 255, 0.78);
  --glass-border: rgba(109, 40, 217, 0.14);
  --glass-blur: 24px;
  --glass-shadow: 0 12px 36px rgba(17, 20, 32, 0.08), 0 4px 12px rgba(109, 40, 217, 0.06);

  --app-bg:    #F4F5F8;
  --surface:   #FFFFFF;
  --surface-2: #FBFBFD;
  --surface-3: #F1F2F6;
  --header-bg: rgba(255, 255, 255, 0.88);

  --text:   #111420;
  --text-2: #565E70;
  --text-3: #667085;
  --text-on-brand: #FFFFFF;

  --border:        #E6E8EF;
  --border-strong: #D5D9E3;
  --divider:       #EEF0F4;

  --success: #15A34A;  --success-soft: #E7F7EE;
  --warning: #C2740B;  --warning-soft: #FBF1E2;
  --danger:  #DC2626;  --danger-soft:  #FCECEC;

  /* Accent khu vực portal (map từ --cat-* của tool) */
  --area-learn: #0E9488;  --area-learn-soft: rgba(14, 148, 136, 0.10);
  --area-tool:  var(--brand-600);  --area-tool-soft: var(--brand-50);
  --area-forum: #C2740B;  --area-forum-soft: rgba(194, 116, 11, 0.10);

  --font-sans: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, sans-serif;
  --font-mono: ui-monospace, 'SFMono-Regular', Menlo, monospace;

  --fs-2xs: 10.5px;
  --fs-xs: 11.5px;
  --fs-sm: 12.5px;
  --fs-base: 14px;
  --fs-md: 15px;
  --fs-lg: 17px;
  --fs-xl: 20px;

  --r-xs: 6px;
  --r-sm: 8px;
  --r-md: 10px;
  --r-lg: 14px;
  --r-xl: 20px;   /* trùng độ bo của rail + topbar để mọi thẻ lớn cùng một ngôn ngữ */
  --r-pill: 999px;

  --shadow-xs: 0 1px 2px rgba(17, 20, 32, 0.05);
  --shadow-sm: 0 1px 3px rgba(17, 20, 32, 0.08), 0 1px 2px rgba(17, 20, 32, 0.04);
  --shadow-md: 0 6px 16px rgba(17, 20, 32, 0.08), 0 2px 6px rgba(17, 20, 32, 0.04);
  --shadow-lg: 0 20px 48px rgba(17, 20, 32, 0.16), 0 6px 14px rgba(17, 20, 32, 0.08);
  --shadow-brand: 0 8px 24px rgba(109, 40, 217, 0.35);

  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur: 180ms;

  --header-height: 64px;
  --content-max: 1080px;

  --scroll-thumb: rgba(17, 20, 32, 0.16);
  --scroll-thumb-hover: rgba(17, 20, 32, 0.28);
}

body.dark-theme {
  --brand:        var(--brand-400);
  --brand-hover:  #A98BF6;
  --brand-active: var(--brand-500);
  --brand-soft:   rgba(139, 92, 246, 0.14);
  --brand-soft-2: rgba(139, 92, 246, 0.22);
  --brand-ring:   rgba(150, 112, 244, 0.38);

  --app-bg:    #0B0D14;
  --surface:   #14161F;
  --surface-2: #171A25;
  --surface-3: #1F2331;
  --header-bg: #101219;

  --text:   #F1F3F8;
  --text-2: #A7AEC0;
  --text-3: #8B93A8;

  --border:        rgba(255, 255, 255, 0.09);
  --border-strong: rgba(255, 255, 255, 0.16);
  --divider:       rgba(255, 255, 255, 0.06);

  --success-soft: rgba(21, 163, 74, 0.14);
  --warning-soft: rgba(194, 116, 11, 0.16);
  --danger-soft:  rgba(220, 38, 38, 0.16);

  --area-learn: #2DD4BF;  --area-learn-soft: rgba(45, 212, 191, 0.12);
  --area-tool:  var(--brand-400);  --area-tool-soft: rgba(139, 92, 246, 0.14);
  --area-forum: #FBBF24;  --area-forum-soft: rgba(251, 191, 36, 0.12);

  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.45), 0 1px 2px rgba(0, 0, 0, 0.35);
  --shadow-md: 0 8px 22px rgba(0, 0, 0, 0.5), 0 2px 6px rgba(0, 0, 0, 0.4);
  --shadow-lg: 0 22px 48px rgba(0, 0, 0, 0.6), 0 8px 14px rgba(0, 0, 0, 0.45);
  --shadow-brand: 0 6px 18px rgba(124, 58, 237, 0.45);

  --scroll-thumb: rgba(255, 255, 255, 0.14);
  --scroll-thumb-hover: rgba(255, 255, 255, 0.26);
}

/* --------------------------------------------------------------------------
   BASE — portal cuộn dọc bình thường
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  font-family: var(--font-sans);
  background-color: var(--app-bg);
  color: var(--text);
  min-height: 100dvh;
  font-size: var(--fs-base);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overscroll-behavior-y: contain;
  display: flex;
  flex-direction: column;
}

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--scroll-thumb); border-radius: var(--r-pill); }
::-webkit-scrollbar-thumb:hover { background: var(--scroll-thumb-hover); }
::-webkit-scrollbar-track { background: transparent; }

:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: var(--r-xs); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0ms !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
  }
  html { scroll-behavior: auto; }
}

a { color: var(--brand); text-decoration: none; }
button { font-family: inherit; cursor: pointer; }

/* Hover mềm toàn cục: mọi phần tử tương tác đều có transition cơ bản, không còn
   trạng thái "bật" đột ngột. :where() = specificity 0 nên transition riêng đã
   tinh chỉnh của từng component (sidebar, stat-card, modal…) luôn thắng rule này. */
:where(a, button, input, select, textarea,
       .user-chip, .chip, .member-row, .mini-row, .stat-card, .video-card, .area-card, .seg-count, .badge) {
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              transform var(--dur) var(--ease), opacity var(--dur) var(--ease);
}

/* --------------------------------------------------------------------------
   BUTTONS (đồng bộ look với tool)
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  /* 38px trên DESKTOP, 44px trên mobile (override cuối file). Quy tắc chạm 44px
     là dành cho ngón tay; chuột chính xác hơn nên desktop để gọn cho đỡ nặng nề.
     TRÙNG số với style.css — đổi thì đổi cả hai. */
  min-height: 38px; padding: 0 16px;
  border-radius: var(--r-md);
  font-size: var(--fs-base); font-weight: 600;
  border: 1px solid transparent;
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn-primary { background-color: var(--brand); color: var(--text-on-brand); box-shadow: var(--shadow-brand); }
.btn-primary:hover { background-color: var(--brand-hover); }
.btn-primary:disabled { opacity: 0.55; cursor: not-allowed; box-shadow: none; }
.btn-secondary {
  background-color: var(--surface); color: var(--text);
  border-color: var(--border-strong);
}
.btn-secondary:hover { border-color: var(--brand); color: var(--brand); }
.btn-danger { background-color: transparent; color: var(--danger); border-color: transparent; }
.btn-danger:hover { background-color: var(--danger-soft); }

/* Hai biến thể VIỀN cho việc phá huỷ (thêm 22/07 cho thanh thao tác hàng loạt).
   Vì sao không dùng .btn-danger cũ ở đó: nó không viền, nhìn như một đường link
   lạc giữa các nút có viền → đó chính là cái "rối" chủ tool thấy. Có viền thì nó
   vẫn là NÚT, chỉ khác MÀU để báo mức độ nguy hiểm — hình dạng nói "bấm được",
   màu nói "cẩn thận". Tách hai mức: cam = đảo ngược được, đỏ = mất dữ liệu. */
/* ⚠️ KHÔNG dùng thẳng token --warning/--danger cho chữ: đo 22/07 ra
   --warning #C2740B trên nền nút trắng = 3.62 và --danger trên nền TỐI = 3.73,
   đều dưới 4.5. Dùng bộ màu đã kiểm ở bảng So sánh cho nhất quán toàn app. */
.btn-warn-outline {
  background-color: transparent; color: #96590A; border-color: #96590A;
}
.btn-warn-outline:hover { background-color: var(--warning-soft); }
.btn-danger-outline {
  background-color: transparent; color: #B91C1C; border-color: #B91C1C;
}
.btn-danger-outline:hover { background-color: var(--danger-soft); }
body.dark-theme .btn-warn-outline   { color: #E9A23B; border-color: #E9A23B; }
body.dark-theme .btn-danger-outline { color: #F87171; border-color: #F87171; }
/* "Bỏ chọn" là lối thoát, không phải hành động ngang hàng → nhẹ nhất, không viền */
.btn-ghost {
  background-color: transparent; color: var(--text-3); border-color: transparent;
}
.btn-ghost:hover { background-color: var(--surface-3); color: var(--text); }
.btn-block { width: 100%; }

.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: var(--r-md);
  background: transparent; border: 1px solid transparent; color: var(--text-2);
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.icon-btn:hover { background-color: var(--surface-3); color: var(--text); }

/* --------------------------------------------------------------------------
   PORTAL HEADER
   -------------------------------------------------------------------------- */
.portal-header {
  position: sticky; top: 0; z-index: 100;
  height: var(--header-height);
  background-color: var(--header-bg);
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 16px;
  padding: 0 clamp(14px, 4vw, 32px);
  padding-left: max(clamp(14px, 4vw, 32px), env(safe-area-inset-left, 0px));
  padding-right: max(clamp(14px, 4vw, 32px), env(safe-area-inset-right, 0px));
}
.portal-brand { display: flex; align-items: center; gap: 10px; color: var(--text); }
.portal-brand .logo-icon {
  width: 38px; height: 38px; border-radius: var(--r-md);
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--brand-600), var(--brand-800));
  color: #fff; flex-shrink: 0;
}
.portal-brand b { font-size: var(--fs-md); font-weight: 800; letter-spacing: -0.2px; }
.portal-brand span { color: var(--text-3); font-size: var(--fs-md); font-weight: 600; }

.portal-nav { display: flex; align-items: center; gap: 4px; margin-left: 8px; }
.portal-nav a {
  display: inline-flex; align-items: center; gap: 7px;
  min-height: 40px; padding: 0 14px; border-radius: var(--r-md);
  color: var(--text-2); font-weight: 600; font-size: var(--fs-base);
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.portal-nav a:hover { background-color: var(--surface-3); color: var(--text); }
.portal-nav a.active { background-color: var(--brand-soft); color: var(--brand); }
.portal-nav .nav-soon {
  font-size: var(--fs-2xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px;
  background: var(--warning-soft); color: var(--warning);
  padding: 2px 7px; border-radius: var(--r-pill);
}

.portal-header .header-spacer { flex: 1; }

.user-chip {
  display: inline-flex; align-items: center; gap: 9px;
  min-height: 40px; padding: 0 12px 0 6px;
  border-radius: var(--r-pill); border: 1px solid var(--border);
  background: var(--surface); color: var(--text);
  font-weight: 600; font-size: var(--fs-sm);
}
.user-chip:hover { border-color: var(--border-strong); }
.user-chip .avatar {
  width: 30px; height: 30px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--brand-soft-2); color: var(--brand);
  font-size: var(--fs-xs); font-weight: 800; text-transform: uppercase;
}

.user-menu {
  position: absolute; top: calc(var(--header-height) - 8px); right: clamp(14px, 4vw, 32px);
  min-width: 220px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-lg);
  padding: 6px; z-index: 200;
  display: none;
}
.user-menu.open { display: block; }
.user-menu .menu-id { padding: 10px 12px; border-bottom: 1px solid var(--divider); margin-bottom: 6px; }
.user-menu .menu-id b { display: block; font-size: var(--fs-base); }
.user-menu .menu-id span { color: var(--text-3); font-size: var(--fs-xs); word-break: break-all; }
.user-menu .menu-role {
  display: inline-block; margin-top: 6px;
  font-size: var(--fs-2xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px;
  background: var(--brand-soft); color: var(--brand);
  padding: 2px 8px; border-radius: var(--r-pill);
}
.user-menu button {
  width: 100%; text-align: left;
  padding: 10px 12px; border: none; background: none;
  border-radius: var(--r-sm); color: var(--danger);
  font-size: var(--fs-base); font-weight: 600;
}
.user-menu button:hover { background: var(--danger-soft); }

/* --------------------------------------------------------------------------
   LAYOUT KHUNG NỘI DUNG
   -------------------------------------------------------------------------- */
.portal-main {
  flex: 1; width: 100%;
  max-width: var(--content-max);
  margin: 0 auto;
  padding: clamp(20px, 4vw, 40px) clamp(14px, 4vw, 32px) 56px;
}

.portal-footer {
  border-top: 1px solid var(--divider);
  padding: 16px clamp(14px, 4vw, 32px);
  padding-bottom: max(16px, env(safe-area-inset-bottom, 0px));
  display: flex; align-items: center; gap: 10px;
  color: var(--text-3); font-size: var(--fs-xs);
}
.portal-footer .version-badge {
  background-color: var(--brand-soft); color: var(--brand);
  padding: 2px 8px; border-radius: var(--r-pill);
  font-size: var(--fs-2xs); font-weight: 700; font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------------
   HOME — hero + 3 cánh cửa
   -------------------------------------------------------------------------- */
.home-hero { padding: clamp(8px, 2vw, 24px) 0 clamp(24px, 4vw, 40px); }
.home-hero .eyebrow {
  font-size: var(--fs-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 1.2px;
  color: var(--brand);
}
.home-hero h1 {
  font-size: clamp(26px, 4.5vw, 40px);
  font-weight: 800; letter-spacing: -0.8px; line-height: 1.15;
  margin-top: 8px;
}
.home-hero p { margin-top: 10px; color: var(--text-2); font-size: var(--fs-md); max-width: 56ch; }

.area-grid {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.area-card {
  --area: var(--brand); --area-soft: var(--brand-soft);
  position: relative;
  display: flex; flex-direction: column; gap: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: 22px 22px 20px;
  box-shadow: var(--shadow-sm);
  color: var(--text);
  overflow: hidden;
  transition: transform var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.area-card::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 4px;
  background: var(--area);
}
.area-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: var(--border-strong); }
.area-card .area-icon {
  width: 44px; height: 44px; border-radius: var(--r-md);
  display: flex; align-items: center; justify-content: center;
  background: var(--area-soft); color: var(--area);
}
.area-card h2 { font-size: var(--fs-lg); font-weight: 800; letter-spacing: -0.2px; }
.area-card p { color: var(--text-2); font-size: var(--fs-base); flex: 1; }
.area-card .area-go {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--area); font-weight: 700; font-size: var(--fs-sm);
}
.area-card.is-learn { --area: var(--area-learn); --area-soft: var(--area-learn-soft); }
.area-card.is-tool  { --area: var(--area-tool);  --area-soft: var(--area-tool-soft); }
.area-card.is-forum { --area: var(--area-forum); --area-soft: var(--area-forum-soft); }
.area-card.is-disabled { opacity: 0.75; }
.area-card.is-disabled:hover { transform: none; box-shadow: var(--shadow-sm); }

/* --------------------------------------------------------------------------
   BANNER trạng thái (chưa cấu hình / chờ duyệt / lỗi)
   -------------------------------------------------------------------------- */
.notice {
  display: flex; gap: 10px; align-items: flex-start;
  border-radius: var(--r-lg); border: 1px solid var(--border);
  padding: 14px 16px; margin-bottom: 20px;
  font-size: var(--fs-base);
}
.notice b { font-weight: 700; }
/* ⚠️ .notice là FLEX: con TRỰC TIẾP của nó phải đúng 2 thẻ (<span> icon + <div> chữ).
   Nhét chuỗi có <b> vào innerHTML là mỗi mẩu chữ thành một cột hẹp — xem veKetQua()
   trong members.js. Đừng bỏ .notice > div đi. */
.notice > div { min-width: 0; }

/* Khối "thông tin đăng nhập" trong ô kết quả — nhãn trái, giá trị bên phải,
   để admin đọc rồi gửi cho người mới. */
.cred-box { display: grid; gap: 6px; margin: 10px 0 12px; }
.cred-box > div { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.cred-box span { flex: 0 0 74px; font-size: var(--fs-sm); font-weight: 700; color: var(--text-2); }
.cred-box code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--fs-sm); background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: 3px 8px; word-break: break-all;
}
.notice.warn { background: var(--warning-soft); border-color: transparent; color: var(--text); }
.notice.error { background: var(--danger-soft); border-color: transparent; }
.notice.info { background: var(--brand-soft); border-color: transparent; }

/* --------------------------------------------------------------------------
   AUTH (login / đăng ký)
   -------------------------------------------------------------------------- */
.auth-wrap {
  flex: 1; display: flex; align-items: center; justify-content: center;
  padding: 24px 14px 48px;
}
.auth-card {
  width: 100%; max-width: 420px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-xl); box-shadow: var(--shadow-md);
  padding: 28px 26px;
}
.auth-card .auth-logo { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; }
.auth-card h1 { font-size: var(--fs-xl); font-weight: 800; letter-spacing: -0.3px; margin-bottom: 4px; }
.auth-card .auth-sub { color: var(--text-3); font-size: var(--fs-sm); margin-bottom: 18px; }

.auth-tabs {
  display: grid; grid-template-columns: 1fr 1fr; gap: 4px;
  background: var(--surface-3); border-radius: var(--r-md); padding: 4px;
  margin-bottom: 18px;
}
.auth-tabs button {
  min-height: 38px; border: none; border-radius: var(--r-sm);
  background: transparent; color: var(--text-2);
  font-size: var(--fs-base); font-weight: 700;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.auth-tabs button.active { background: var(--surface); color: var(--text); box-shadow: var(--shadow-xs); }

.field { margin-bottom: 14px; }
.field label { display: block; font-size: var(--fs-sm); font-weight: 700; color: var(--text-2); margin-bottom: 6px; }
.field input {
  width: 100%; min-height: 44px;
  background-color: var(--surface-2);
  border: 1px solid var(--border); border-radius: var(--r-md);
  color: var(--text); padding: 10px 14px;
  font-size: 16px; /* chống iOS auto-zoom */
  font-family: inherit;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.field input::placeholder { color: var(--text-3); }
/* Dòng nhắc dưới ô nhập — chỉ hiện khi có hậu quả người dùng cần biết trước
   (vd. đổi email đăng nhập thì người kia phải dùng email mới).
   Màu lấy đúng bộ đã đo ở .btn-warn-outline (#96590A / #E9A23B), KHÔNG dùng
   thẳng token --warning: đo 22/07 nó chỉ đạt 3.62 trên nền sáng. */
.field-hint { margin: 6px 0 0; font-size: var(--fs-xs); line-height: 1.45; color: #96590A; }
body.dark-theme .field-hint { color: #E9A23B; }
.field-hint[hidden] { display: none; }
.field input:hover { border-color: var(--border-strong); }
.field input:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-ring); background: var(--surface); }

.auth-msg { min-height: 20px; font-size: var(--fs-sm); margin: 2px 0 12px; }
.auth-msg.error { color: var(--danger); }
.auth-msg.ok { color: var(--success); }

/* --------------------------------------------------------------------------
   VIDEOS
   -------------------------------------------------------------------------- */
.page-head { display: flex; align-items: flex-end; gap: 14px; flex-wrap: wrap; margin-bottom: 18px; }
.page-head .page-title h1 {
  font-size: clamp(22px, 3.5vw, 30px); font-weight: 800; letter-spacing: -0.5px;
  display: flex; align-items: center; gap: 10px;
}
.page-head .page-title h1 .page-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--area-learn); }
.page-head .page-title p { color: var(--text-3); font-size: var(--fs-sm); margin-top: 4px; }
.page-head .head-spacer { flex: 1; }

.chip-row { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 20px; }
.chip {
  min-height: 36px; padding: 0 14px;
  border-radius: var(--r-pill); border: 1px solid var(--border);
  background: var(--surface); color: var(--text-2);
  font-size: var(--fs-sm); font-weight: 700;
  transition: all var(--dur) var(--ease);
}
.chip:hover { border-color: var(--area-learn); color: var(--area-learn); }
.chip.active { background: var(--area-learn); border-color: var(--area-learn); color: #fff; }

.video-grid {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
}
.video-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); overflow: hidden;
  box-shadow: var(--shadow-xs);
  display: flex; flex-direction: column;
  transition: transform var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease);
}
.video-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.video-thumb {
  position: relative; aspect-ratio: 16 / 9;
  background: var(--surface-3);
  display: flex; align-items: center; justify-content: center;
  color: var(--text-3);
  cursor: pointer; border: none; padding: 0; width: 100%;
}
.video-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.video-thumb .play-badge {
  position: absolute; inset: 0; margin: auto;
  width: 52px; height: 52px; border-radius: 50%;
  background: rgba(17, 20, 32, 0.62); color: #fff;
  display: flex; align-items: center; justify-content: center;
  transition: transform var(--dur) var(--ease-out), background-color var(--dur) var(--ease);
}
.video-thumb:hover .play-badge { transform: scale(1.08); background: var(--area-learn); }
.video-thumb .src-tag {
  position: absolute; left: 10px; bottom: 10px;
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: 0.4px;
  background: rgba(17, 20, 32, 0.72); color: #fff;
  padding: 3px 8px; border-radius: var(--r-pill);
}
.video-body { padding: 14px 16px 16px; display: flex; flex-direction: column; gap: 6px; flex: 1; }
.video-body .video-cat { font-size: var(--fs-2xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.8px; color: var(--area-learn); }
.video-body h3 { font-size: var(--fs-base); font-weight: 700; line-height: 1.35; }
.video-body p { color: var(--text-3); font-size: var(--fs-sm); flex: 1; }
.video-admin-row { display: flex; gap: 6px; margin-top: 8px; }
.video-admin-row button {
  font-size: var(--fs-xs); font-weight: 700;
  border: 1px solid var(--border); background: var(--surface);
  border-radius: var(--r-sm); padding: 6px 10px; min-height: 32px;
  color: var(--text-2);
}
.video-admin-row button:hover { border-color: var(--brand); color: var(--brand); }
.video-admin-row button.del:hover { border-color: var(--danger); color: var(--danger); background: var(--danger-soft); }

.empty-state {
  border: 1px dashed var(--border-strong); border-radius: var(--r-xl);
  padding: 48px 24px; text-align: center; color: var(--text-3);
}
.empty-state b { display: block; color: var(--text-2); font-size: var(--fs-md); margin-bottom: 6px; }

/* --------------------------------------------------------------------------
   MODAL (player + form admin) — mở ĐỒNG BỘ (lesson: không rAF)
   -------------------------------------------------------------------------- */
.modal-backdrop {
  position: fixed; inset: 0; z-index: 500;
  background: rgba(11, 13, 20, 0.62);
  display: flex; align-items: center; justify-content: center;
  padding: 18px;
  opacity: 0; pointer-events: none;
  transition: opacity var(--dur) var(--ease);
}
.modal-backdrop.open { opacity: 1; pointer-events: auto; }
.modal {
  width: 100%; max-width: 880px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-xl); box-shadow: var(--shadow-lg);
  transform: translateY(10px) scale(0.98);
  transition: transform var(--dur) var(--ease-out);
  max-height: calc(100dvh - 36px); overflow: auto;
}
.modal-backdrop.open .modal { transform: none; }
.modal.modal-sm { max-width: 460px; }
.modal-head {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 18px; border-bottom: 1px solid var(--divider);
  position: sticky; top: 0; background: var(--surface); z-index: 1;
}
.modal-head h2 { font-size: var(--fs-md); font-weight: 800; flex: 1; }
.modal-body { padding: 18px; }
.player-frame { aspect-ratio: 16 / 9; width: 100%; background: #000; border: none; display: block; border-radius: var(--r-md); }
.modal-actions { display: flex; justify-content: flex-end; gap: 10px; padding: 0 18px 18px; }

/* --------------------------------------------------------------------------
   QUẢN LÝ THÀNH VIÊN (/members)
   -------------------------------------------------------------------------- */
.btn-sm { min-height: 32px; padding: 0 12px; font-size: var(--fs-sm); }

/* Mỗi khối nội dung là một THẺ bo góc (kiểu dashboard card) —
   dòng bên trong là list phân cách hairline, không phải hộp lồng hộp. */
.seg {
  margin-bottom: 20px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-xl); box-shadow: var(--shadow-xs);
  padding: 18px 22px 12px;
}
.seg-head { display: flex; align-items: center; gap: 10px; margin: 0 0 8px; }
.seg-head h2 { font-size: var(--fs-md); font-weight: 800; letter-spacing: -0.2px; }
.seg-count {
  min-width: 24px; height: 22px; padding: 0 8px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill); font-size: var(--fs-xs); font-weight: 800;
  background: var(--surface-3); color: var(--text-2); font-variant-numeric: tabular-nums;
}
.seg-count.warn { background: var(--warning-soft); color: var(--warning); }

/* --- Bảng thành viên: lưới 6 cột -------------------------------------------
   CHỈ .member-table định nghĩa chiều rộng cột; hàng tiêu đề, danh sách và từng
   hàng đều là `subgrid` ăn theo nó. BẮT BUỘC phải vậy: nếu mỗi hàng tự dựng lưới
   riêng thì cột "Thao tác" (số nút đổi theo trạng thái + quyền) sẽ kéo co các cột
   còn lại lệch nhau mỗi hàng — đã đo, lệch tới 70px.
   Hệ quả: đừng thêm padding/border TRÁI-PHẢI cho .member-head/.member-list/
   .member-row — nó làm subgrid thụt vào và lệch lại. Padding dọc thì vô hại. */
.member-table {
  display: grid;
  grid-template-columns:
    28px                    /* Ô chọn (checkbox) */
    minmax(190px, 2fr)      /* Thành viên (avatar + tên + email) */
    minmax(96px,  0.9fr)    /* Phòng ban */
    minmax(92px,  0.8fr)    /* Quyền */
    minmax(124px, 1fr)      /* Trạng thái */
    minmax(96px,  0.8fr)    /* Tham gia */
    minmax(180px, auto);    /* Thao tác */
  column-gap: 12px;
}
.member-head, .member-list, .member-row {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
}
.member-list { row-gap: 0; }

.member-head {
  align-items: center;
  /* ⚠️ KHÔNG đặt `position: sticky` cho hàng này.
     Bản 22/07 từng cho nó dính (để cuộn 51 người vẫn thấy tên cột) → thành TẦNG DÍNH
     THỨ BA sau `.topbar` và `.bulk-bar`, và lật trang là ba tầng đè lên mấy hàng đầu.
     Phân trang 12 hàng/trang đã bỏ hẳn việc phải cuộn danh sách, nên hàng tiêu đề
     dính vừa thừa vừa đẻ lỗi. Ít tầng dính = ít lỗi chồng lấn. */
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-2xs); font-weight: 800; letter-spacing: 0.6px;
  text-transform: uppercase; color: var(--text-3);
}
.member-head .ta-right { text-align: right; }

.member-row {
  position: relative;
  align-items: center;
  background: transparent; border: none;
  border-top: 1px solid var(--divider);
  /* 13px -> 9px (chủ tool 22/07: "scroll bị dài"). Với 51 người, riêng phần đệm
     dọc đã chiếm ~400px chiều cao vô ích. */
  padding: 9px 0;
  box-shadow: none;
  transition: background-color var(--dur) var(--ease);
}
.member-row:first-child { border-top: none; }
/* Thanh chỉ dấu bên trái. position:absolute → KHÔNG thành một ô của subgrid,
   nên không phá bố cục 6 cột (xem ghi chú lưới ở trên). */
.member-row::before {
  content: ''; position: absolute; left: -10px; top: 4px; bottom: 4px;
  width: 3px; border-radius: 3px; background: transparent;
  transition: background-color var(--dur) var(--ease);
}
.member-row:hover { background: var(--surface-2); }
/* "Hàng của bạn" chỉ là thông tin, KHÔNG phải trạng thái thao tác → chỉ một vạch
   nhạt, không tô nền. Cột cuối đã có chữ "Bạn" nói rõ rồi. */
.member-row.is-me { background: transparent; }
.member-row.is-me::before { background: var(--brand-300); }
.member-row.is-me:hover { background: var(--surface-2); }

/* Cột 1: avatar + danh tính đi liền nhau thành một khối */
.member-row .m-user { display: flex; align-items: center; gap: 10px; min-width: 0; }
.member-row .m-avatar {
  /* 40 -> 32px: avatar là chữ cái đầu, không phải ảnh — 32px vẫn đọc rõ mà cắt
     được 8px mỗi hàng. Đây là thứ QUYẾT ĐỊNH chiều cao hàng, không phải cỡ chữ. */
  width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--brand-soft-2); color: var(--brand);
  font-size: var(--fs-sm); font-weight: 800;
}
/* ⚠️ THỨ QUYẾT ĐỊNH CHIỀU CAO HÀNG LÀ KHỐI NÀY, KHÔNG PHẢI AVATAR.
   Đo 22/07: hàng cao 60px thì riêng khối tên+email đã 40px — vì hai dòng này không
   khai line-height nên ăn 1.55 của body (14×1.55 + 12.5×1.55 ≈ 41px). Thu avatar
   40→32 gần như vô ích vì avatar không phải chỗ cao nhất.
   Đặt line-height chặt cho ĐÚNG hai dòng này mới cắt được chiều cao thật. */
.member-row .m-id { min-width: 0; }
.member-row .m-id b {
  display: block; font-size: var(--fs-base); font-weight: 700;
  line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.member-row .m-id span {
  display: block; color: var(--text-3); font-size: var(--fs-sm);
  line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Các ô còn lại: căn trái đồng loạt để mắt rà dọc theo cột */
.member-row .m-cell { min-width: 0; display: flex; align-items: center; line-height: 1.3; }
.member-row .m-date { color: var(--text-3); font-size: var(--fs-xs); white-space: nowrap; }
.member-row .m-empty { color: var(--text-3); font-size: var(--fs-sm); }
.member-row .member-actions {
  display: flex; align-items: center; justify-content: flex-end;
  gap: 8px; flex-wrap: wrap;
}
.member-row .m-self { color: var(--text-3); font-size: var(--fs-xs); font-weight: 700; padding-right: 4px; }

/* --- Thao tác trên hàng: 1 hành động chính + menu "⋯" -----------------------
   Trước đây bày 4 nút cạnh nhau trộn 3 kiểu (nút viền, chữ đỏ, nút đặc) nên rối
   và cột bị kéo rộng (chủ tool 21/07). Giờ chỉ hiện việc hay dùng nhất, phần
   còn lại nằm trong menu — cột gọn và mắt biết ngay phải bấm gì. */
.m-more-wrap { position: relative; display: inline-flex; }
.m-more {
  width: 32px; height: 32px; border-radius: var(--r-sm);
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 1px solid var(--border); color: var(--text-2);
  cursor: pointer; font-size: 16px; line-height: 1;
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.m-more:hover { background: var(--surface-3); border-color: var(--border-strong); color: var(--text); }
.m-menu {
  display: none; position: absolute; right: 0; top: calc(100% + 6px); z-index: 70;
  min-width: 186px; padding: 6px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow-lg);
}
.m-menu.open { display: block; }
.m-menu button {
  display: flex; align-items: center; width: 100%; gap: 8px;
  padding: 9px 10px; border: none; background: transparent; border-radius: var(--r-sm);
  font: inherit; font-size: var(--fs-sm); font-weight: 600; color: var(--text-2);
  text-align: left; cursor: pointer; white-space: nowrap;
}
.m-menu button:hover { background: var(--surface-3); color: var(--text); }
.m-menu button.is-danger { color: var(--danger); }
.m-menu button.is-danger:hover { background: var(--danger-soft); }
.m-menu .m-menu-sep { height: 1px; margin: 5px 4px; background: var(--divider); }

/* Ô chọn (dropdown) — portal.css trước giờ chỉ có style cho input, chưa có select.
   Bám theo đúng .field input để hai loại ô nhìn như một. */
.select-field {
  width: 100%;
  /* Khớp .field input để hai loại ô "nhìn như một": cùng cao 44, cùng bo --r-md,
     cùng cỡ chữ 16px (16px cũng chống iOS auto-zoom như ô nhập). */
  min-height: 44px; padding: 0 12px;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2); color: var(--text);
  font-family: inherit; font-size: 16px; font-weight: 500;
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.select-field:hover { border-color: var(--border-strong); }
.select-field:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-ring); background: var(--surface); }

/* --- Chọn nhiều thành viên + thao tác hàng loạt --------------------------- */
.m-check { display: flex; align-items: center; justify-content: center; }
.m-check input[type="checkbox"] {
  width: 17px; height: 17px; cursor: pointer; accent-color: var(--brand); margin: 0;
}
/* Đang chọn để thao tác hàng loạt — trạng thái MẠNH NHẤT trong ba, và phải thắng
   .is-me (một người vừa là mình vừa đang được chọn thì phải thấy là "đang chọn").
   box-shadow ngang để mảng nền thở ra hai bên mà KHÔNG thêm padding (padding ngang
   làm lệch subgrid — xem ghi chú lưới ở trên). */
.member-row.is-picked,
.member-row.is-picked:hover,
.member-row.is-me.is-picked { background: var(--brand-soft); }
.member-row.is-picked::before,
.member-row.is-me.is-picked::before { background: var(--brand); }
.member-row.is-picked { box-shadow: -10px 0 0 var(--brand-soft), 10px 0 0 var(--brand-soft); }

/* Thanh thao tác hàng loạt — chỉ hiện khi có người được chọn. position sticky
   để cuộn danh sách dài vẫn thấy; KHÔNG dùng fixed (che mất dải chân trang). */
/* Thanh công cụ danh sách (22/07/2026): LUÔN hiện vì nó chứa ô TÌM.
   Trước đây cả thanh `display:none` khi chưa chọn ai — giờ chỉ nhóm nút hàng loạt
   mới ẩn/hiện, còn ô tìm phải luôn ở đó. Viền đổi màu khi có người được chọn để
   vẫn giữ tín hiệu "đang ở chế độ thao tác hàng loạt". */
.bulk-bar {
  display: flex;
  position: sticky; top: calc(var(--header-height) + 16px); z-index: 60;
  align-items: center; gap: 12px; flex-wrap: wrap;
  margin-bottom: 14px; padding: 10px 14px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-sm);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
/* Ô TÌM đã chuyển lên .ms-head (16/09/2026) nên thanh này chỉ còn nhóm nút hàng
   loạt → chưa chọn ai thì ẨN HẲN, không để lại một thanh viền rỗng. */
.bulk-bar:not(.open) { display: none; }
.bulk-bar.open { border-color: var(--brand-ring); box-shadow: var(--shadow-md); }
.bulk-actions { display: none; }
.bulk-bar.open .bulk-actions {
  display: flex; flex: 1; align-items: center; gap: 12px; flex-wrap: wrap;
}
.bulk-bar .bulk-count {
  font-weight: 800; font-size: var(--fs-sm); color: var(--brand-700);
  background: var(--brand-soft); padding: 5px 11px; border-radius: var(--r-pill);
  white-space: nowrap;
}
/* Đẩy nhóm phá huỷ sang phải, tách hẳn khỏi nhóm việc thường — để không ai
   với tay bấm "Xoá" theo quán tính khi đang nhắm "Đổi phòng ban". */
body.dark-theme .bulk-bar .bulk-count { color: #C4B5FD; }
.bulk-bar .bulk-sep { flex: 1; min-width: 12px; }
/* Số người thực sự bị tác động, hiện ngay trong nút khi khác tổng đang chọn */
.bulk-n:empty { display: none; }
.bulk-n {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; margin-left: 7px; padding: 0 5px;
  border-radius: var(--r-pill);
  font-size: var(--fs-2xs); font-weight: 800; line-height: 1;
}
/* Màu huy hiệu ĐẢO theo nền nút: nền huy hiệu = màu nhấn của nút, chữ = màu nền nút.
   ⚠️ ĐỪNG viết `background: currentColor; color: var(--surface)` trên CÙNG một rule —
   `currentColor` lấy `color` của CHÍNH phần tử đó, tức lấy luôn cái vừa ghi đè ở dòng
   dưới → nền trùng chữ, huy hiệu thành một cục đặc không đọc được (đo ra tỉ lệ 1.00).
   Cách đúng: nút khai `--acc`, huy hiệu đọc `--acc`. Rõ ràng và không phụ thuộc thứ tự. */
.btn-secondary      { --acc: var(--brand); }
.btn-warn-outline   { --acc: #96590A; }
.btn-danger-outline { --acc: #B91C1C; }
body.dark-theme .btn-warn-outline   { --acc: #E9A23B; }
body.dark-theme .btn-danger-outline { --acc: #F87171; }
.bulk-n { background: var(--acc, var(--brand)); color: var(--surface); }
/* Nút primary nền đã đặc → huy hiệu phải đảo: nền sáng, chữ tím đậm */
.btn-primary .bulk-n { background: var(--text-on-brand); color: var(--brand-700); }

/* Ô tìm thành viên */
.mem-search {
  position: relative; display: flex; align-items: center;
  flex: 0 1 320px; min-width: 200px;
}
.mem-search > svg {
  position: absolute; left: 11px; width: 16px; height: 16px;
  color: var(--text-3); pointer-events: none;
}
.mem-search input {
  width: 100%; padding: 9px 34px 9px 34px;
  font: inherit; font-size: var(--fs-sm);
  color: var(--text); background: var(--surface-2);
  border: 1px solid var(--border); border-radius: var(--r-md);
  transition: border-color var(--dur) var(--ease), background-color var(--dur) var(--ease);
}
.mem-search input::placeholder { color: var(--text-3); }
.mem-search input:focus {
  outline: none; background: var(--surface);
  border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-ring);
}
/* Nút X mặc định của type="search" trên Chrome — ẩn đi, dùng nút của mình cho
   đồng bộ 2 theme và để bắt được sự kiện. */
.mem-search input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
.mem-search button {
  position: absolute; right: 6px;
  display: none; align-items: center; justify-content: center;
  width: 22px; height: 22px; padding: 0;
  border: none; border-radius: 50%;
  background: var(--surface-3); color: var(--text-2); cursor: pointer;
}
.mem-search button svg { width: 12px; height: 12px; }
.mem-search button:hover { background: var(--danger-soft); color: var(--danger); }
.mem-hit { font-size: var(--fs-sm); font-weight: 700; color: var(--text-3); white-space: nowrap; }

/* --- Thanh lật trang (22/07: chủ tool "phải scroll", xin chuyển sang lật trang) --- */
.pager {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 14px 0 2px;
}
.pager-info { font-size: var(--fs-sm); color: var(--text-3); font-variant-numeric: tabular-nums; }
.pager-sep { flex: 1; }
.pager-cham { color: var(--text-3); padding: 0 2px; user-select: none; }
.pager-nut {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 34px; height: 34px; padding: 0 8px;
  border: 1px solid var(--border-strong); border-radius: var(--r-md);
  background: var(--surface); color: var(--text);
  font: inherit; font-size: var(--fs-sm); font-weight: 700;
  font-variant-numeric: tabular-nums; cursor: pointer;
  transition: border-color var(--dur) var(--ease), background-color var(--dur) var(--ease),
              color var(--dur) var(--ease);
}
.pager-nut svg { width: 16px; height: 16px; }
.pager-nut:hover:not(:disabled) { border-color: var(--brand); color: var(--brand); }
.pager-nut:disabled { opacity: 0.4; cursor: not-allowed; }
/* Trang đang xem: nền đặc, không chỉ đổi màu chữ — phải nhìn phát là biết đang ở đâu */
.pager-nut.dang-xem {
  background: var(--brand); border-color: var(--brand); color: var(--text-on-brand);
  cursor: default;
}
.pager-nut.dang-xem:hover { color: var(--text-on-brand); }

/* Bố cục 2 cột trang Quản lý thành viên (chủ tool 21/07):
   trái = danh sách người, phải = các con số tổng hợp.
   Cột phải hẹp và DÍNH theo cuộn để lúc rà danh sách dài vẫn thấy tổng quan. */
.members-layout {
  display: grid; gap: 16px;
  grid-template-columns: minmax(0, 1fr) 312px;   /* rộng ra từ 260 (chủ tool 21/07) */
  align-items: start;
}
.members-main { min-width: 0; }   /* min-width:0 bắt buộc, thiếu là bảng đẩy cột phải tràn */
.members-side {
  display: flex; flex-direction: column; gap: 12px;
  position: sticky; top: calc(var(--header-height) + 16px);
}
/* Màn hẹp: xếp dọc, số liệu lên trước cho thấy ngay bức tranh chung */
@media (max-width: 1100px) {
  .members-layout { grid-template-columns: 1fr; }
  /* Khối tổng quan lên trên danh sách; 3 hàng trải ngang cho đỡ cao */
  .members-side { position: static; order: -1; }
  .ms-panel { padding-bottom: 14px; }
  .ms-panel .ms-row {
    display: inline-flex; width: calc(33.333% - 4px);
    flex-direction: column; align-items: flex-start; gap: 4px;
    border-top: none; padding: 12px 0 0;
  }
}
/* MỘT khối duy nhất chứa cả 3 con số (chủ tool 21/07 — trước là 3 thẻ rời).
   Mỗi hàng: nhãn bên trái, số bên phải; ngăn nhau bằng vạch mảnh chứ không
   phải hộp lồng hộp — cùng ngôn ngữ với .seg của bảng thành viên. */
.ms-panel {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-xl); box-shadow: var(--shadow-xs);
  padding: 14px 16px 4px;
}
.ms-panel-head {
  font-size: var(--fs-2xs); font-weight: 800; letter-spacing: 0.6px;
  text-transform: uppercase; color: var(--text-3);
  padding-bottom: 10px; border-bottom: 1px solid var(--border);
}
.ms-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 13px 0;
  border-top: 1px solid var(--divider);
}
/* Hàng ngay sau tiêu đề: bỏ vạch trên, nếu không sẽ CHỒNG với border-bottom
   của .ms-panel-head thành hai vạch. Không dùng :first-of-type — nó khớp vào
   .ms-panel-head (cùng là thẻ div) chứ không phải hàng đầu tiên. */
.ms-panel-head + .ms-row { border-top: none; }
.ms-row .ms-label {
  font-size: var(--fs-sm); font-weight: 600; color: var(--text-2);
}
.ms-row .ms-value {
  font-size: var(--fs-xl); font-weight: 800; letter-spacing: -0.5px;
  line-height: 1; font-variant-numeric: tabular-nums; color: var(--text);
}
/* Dùng bộ màu đã đo đạt AA (giống bảng So sánh / thanh thao tác), KHÔNG dùng thẳng
   token --warning/--danger: đo 22/07 ra 3.62 và 3.73 trên nền trắng, dưới ngưỡng 4.5. */
.ms-row .ms-value.is-warn   { color: #96590A; }
.ms-row .ms-value.is-ok     { color: var(--success); }
.ms-row .ms-value.is-danger { color: #B91C1C; }
body.dark-theme .ms-row .ms-value.is-warn   { color: #E9A23B; }
body.dark-theme .ms-row .ms-value.is-danger { color: #F87171; }

/* Tiêu đề nhóm phụ trong khối tổng quan ("Theo phòng ban") */
.ms-panel-head.ms-sub { margin-top: 6px; padding-top: 12px; border-top: 1px solid var(--border); border-bottom: none; }

/* Hàng phòng ban BẤM ĐƯỢC để lọc danh sách — phải trông như bấm được, không
   phải chỉ là con số. Hàng đang lọc được tô nền để biết bộ lọc còn bật. */
/* ⚠️ NGUYÊN TẮC TRẠNG THÁI (chốt 21/07/2026 sau khi chủ tool báo "chọn/hover xấu"):
   KHÔNG tô một mảng màu đặc kín cả hàng. Hàng ở đây rất rộng (hàng phòng ban, hàng
   thành viên), mảng màu kín biến nó thành một khối nặng át hết nội dung bên trong.
   Thay bằng THANH CHỈ DẤU BÊN TRÁI + nền nhạt hơn hẳn.
   Và ba trạng thái phải KHÁC CẤP ĐỘ nhau, đừng dùng chung một màu:
     hover      → nhẹ nhất, chỉ báo "chuột đang ở đây"
     đang chọn  → đậm nhất, vì nó đổi việc đang làm (bộ lọc / thao tác hàng loạt)
     "là bạn"   → chỉ là thông tin, phải NHẸ NHẤT trong ba, đã có chữ "Bạn" rồi */
.ms-dept {
  position: relative;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; padding: 10px 8px; margin: 0 -8px;
  background: transparent; border: none; border-radius: var(--r-sm);
  font: inherit; color: inherit; cursor: pointer; text-align: left;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
/* Thanh chỉ dấu: position absolute nên KHÔNG chiếm ô nào trong layout cha */
.ms-dept::before {
  content: ''; position: absolute; left: 0; top: 50%;
  width: 3px; height: 0; border-radius: 0 3px 3px 0;
  background: var(--brand); transform: translateY(-50%);
  transition: height var(--dur) var(--ease);
}
.ms-dept:hover { background: var(--surface-2); }
.ms-dept:hover::before { height: 14px; }
.ms-dept:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.ms-dept .msd-name { font-size: var(--fs-sm); font-weight: 600; color: var(--text-2); }
.ms-dept .msd-count {
  min-width: 24px; height: 22px; padding: 0 8px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill); background: var(--surface-3); color: var(--text-2);
  font-size: var(--fs-xs); font-weight: 800; font-variant-numeric: tabular-nums;
}
.ms-dept.is-on { background: var(--brand-soft); }
.ms-dept.is-on::before { height: calc(100% - 10px); }
.ms-dept.is-on .msd-name { color: var(--brand); font-weight: 800; }
/* Badge nền BRAND ĐẶC trên nền đã tô nhạt là hai lớp màu chồng nhau, nhìn nặng.
   Nhạt lại, để "đậm" dồn vào thanh chỉ dấu — một điểm nhấn thôi. */
.ms-dept.is-on .msd-count { background: var(--brand-soft-2); color: var(--brand); }

/* Dải báo "đang lọc" trên đầu danh sách bên trái */
.filter-bar {
  display: none; align-items: center; gap: 10px;
  margin-bottom: 14px; padding: 10px 14px;
  background: var(--brand-soft); border: 1px solid var(--brand-ring);
  border-radius: var(--r-lg);
  font-size: var(--fs-sm); font-weight: 600; color: var(--text);
}
.filter-bar.open { display: flex; }
.filter-bar .fb-sep { flex: 1; }

/* --- Đang tải: phản hồi TẠI CHỖ, không chen banner làm xê dịch bố cục ------
   Bảng mờ + khoá thao tác trong lúc chờ; kích thước không đổi nên không giật. */
.is-loading .member-table { opacity: 0.5; pointer-events: none; }
.member-table { transition: opacity 0.18s var(--ease); }

/* Khung xương cho lần tải đầu (bảng còn trống, không có gì để làm mờ) */
.sk {
  display: block; border-radius: var(--r-sm);
  background: var(--surface-3);
  animation: sk-pulse 1.4s ease-in-out infinite;
}
.sk-avatar { width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0; }
.sk-line { height: 11px; width: 74%; margin: 4px 0; }
.sk-line.short { width: 46%; }
.sk-pill { height: 18px; width: 76px; border-radius: var(--r-pill); }
.sk-btn { height: 30px; width: 104px; margin-left: auto; }
@keyframes sk-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }

.badge {
  display: inline-flex; align-items: center;
  font-size: var(--fs-2xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px;
  padding: 3px 9px; border-radius: var(--r-pill); white-space: nowrap;
}
.badge.role-super  { background: var(--brand); color: #fff; }
.badge.role-admin  { background: var(--brand-soft); color: var(--brand); }
.badge.role-user   { background: var(--surface-3); color: var(--text-2); }
.badge.st-approved,
.badge.st-active   { background: var(--success-soft); color: var(--success); }
.badge.st-pending  { background: var(--warning-soft); color: var(--warning); }
.badge.st-suspended{ background: var(--danger-soft); color: var(--danger); }

/* Chip phòng ban trong hàng thành viên */
.m-dept {
  display: inline-flex; align-items: center;
  font-size: var(--fs-2xs); font-weight: 700;
  padding: 3px 9px; border-radius: var(--r-pill); white-space: nowrap;
  background: var(--area-learn-soft); color: var(--area-learn);
}

/* --------------------------------------------------------------------------
   RESPONSIVE
   -------------------------------------------------------------------------- */
@media (max-width: 720px) {
  .portal-nav a .nav-text-optional { display: none; }
  .portal-brand span { display: none; }
  .user-chip .chip-name { display: none; }
  .user-chip { padding-right: 6px; }
}

/* Hẹp hơn 900px: bảng 6 cột không nhét vừa → mỗi thành viên thành một THẺ,
   từng thuộc tính xuống dòng riêng kèm nhãn (data-label) vì hàng tiêu đề đã ẩn. */
@media (max-width: 900px) {
  .member-head { display: none; }
  /* Ngón tay cần 44px — desktop để 38/32 cho gọn, mobile trả về ngưỡng chạm.
     Quy tắc 2 sổ bài học: 44px là cho MOBILE, desktop được nhỏ hơn. */
  .btn { min-height: 44px; }
  .btn-sm { min-height: 40px; }
  .icon-btn { width: 44px; height: 44px; }

  /* Nút "↻ Tải lại" ẨN trên điện thoại (chủ tool 22/07: *"trên iPhone không cần
     nút này, người ta trượt lên là tự động load"*). Đúng: vuốt-để-tải-lại của
     Safari/Chrome nạp lại trang, mà nạp lại trang thì `load()` chạy luôn — nút
     này chỉ lặp lại một cử chỉ hệ điều hành đã có. Thanh tiêu đề mobile lại
     chật, để nút vào là chữ vỡ hai dòng ("↻ / Tải lại" — xem ảnh chụp 22/07).
     ⚠️ ẨN bằng CSS chứ KHÔNG xoá khỏi HTML: members.js còn đổi nhãn nút này
     thành "Đang tải…" (hàm báo trạng thái nạp) — xoá đi là chạm vào null. */
  #btn-refresh { display: none; }

  /* Bỏ subgrid, mỗi thành viên xếp dọc thành một thẻ */
  .member-table { display: block; }
  .member-list { display: block; }
  /* Ô tick nằm CÙNG HÀNG với avatar + tên, không phải một hàng riêng.
     Trước đây thẻ xếp dọc 1 cột nên `.m-check` thành một dòng của chính nó →
     dấu tick lơ lửng giữa thẻ, không dính vào ai (chủ tool 22/07: "vô duyên").
     Ô tick là thuộc tính CỦA NGƯỜI ĐÓ nên phải đứng cạnh danh tính người đó.
     2 cột: [tick | nội dung], mọi ô còn lại kéo hết bề ngang. */
  .member-row {
    grid-template-columns: auto minmax(0, 1fr);
    gap: 8px 10px;
    padding: 14px 0;
    align-items: start;
  }
  .member-row .m-check {
    grid-column: 1; grid-row: 1;
    display: flex; align-items: center; justify-content: center;
    /* Ngón tay: ô tick mặc định chỉ ~16px. Nới vùng chạm bằng min-width/height
       thay vì phóng to chính cái ô (phóng to trông thô). */
    min-width: 30px; min-height: 34px;
  }
  .member-row .m-check .m-pick { width: 20px; height: 20px; }
  .member-row .m-user { grid-column: 2; grid-row: 1; }
  .member-row .m-cell,
  .member-row .member-actions { grid-column: 1 / -1; }
  .member-row .m-cell::before {
    content: attr(data-label) ':';
    flex: 0 0 92px;
    color: var(--text-3); font-size: var(--fs-2xs); font-weight: 800;
    letter-spacing: 0.5px; text-transform: uppercase;
  }
  .member-row .m-user { padding-bottom: 4px; }
  .member-row .m-id span { white-space: normal; word-break: break-word; }
  .member-row .member-actions { justify-content: flex-start; padding-top: 4px; }
  /* Chạm bằng ngón tay: nút thao tác đủ 44px (btn-sm desktop chỉ 36px) */
  .member-row .member-actions .btn { min-height: 44px; }
}

/* ==========================================================================
   APP SHELL — dashboard nội bộ (sidebar trái + topbar). Trang chủ portal.
   Giữ bản sắc Thinksmart: brand tím, không "AI-look". Điểm nhấn duy nhất =
   thẻ hành động gradient (CTA chính). Mọi thứ quanh nó giữ trầm.
   ===========================
/* ======================================================================
   SIDEBAR — Soft Cascade
   Khung mở êm; logo, icon và chữ theo sau theo nhịp ngắn. Chuyển động chỉ
   mô tả trạng thái mở/đóng, không chạy lặp để tránh gây xao nhãng.
   ====================================================================== */

.sidebar {
  position: fixed;
  /* Sát mép hơn (8px thay vì 12px) để rail, header và nội dung nằm gần nhau,
     đọc thành một khối thay vì 3 vùng rời. Đổi số này phải đổi luôn
     .app-shell padding-left (8 + 64 + 8 = 80) và .tool-shell bên style.css. */
  /* Rail CAO ĐÚNG BẰNG NỘI DUNG và căn giữa dọc (chủ tool 21/07: menu ít mục,
     kéo cao full màn nhìn dài và trống). max-height để phòng khi thêm nhiều mục;
     mobile tự khai lại top/bottom/transform nên drawer không bị ảnh hưởng. */
  left: 8px; top: 50%; bottom: auto;
  transform: translateY(-50%);
  max-height: calc(100vh - 16px);
  max-height: calc(100dvh - 16px);
  width: 64px; flex-shrink: 0;
  height: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  display: flex; flex-direction: column;
  padding: 14px 10px;
  z-index: 200;
  overflow: hidden;
  /* KHÔNG dùng backdrop-filter ở đây: nền --surface là màu ĐẶC nên blur vô hình,
     nhưng vẫn bắt GPU re-blur mỗi frame khi animate width → nguồn giật chính. */
  box-shadow: 0 4px 20px rgba(17, 20, 32, 0.08), 0 1px 4px rgba(17, 20, 32, 0.04);
  will-change: width;
  /* Thu gọn: ease chuẩn mềm cả 2 đầu — không dừng phựt. */
  transition: width 0.34s cubic-bezier(0.4, 0, 0.2, 1),
              box-shadow 0.28s ease,
              border-color 0.2s ease;
}
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) {
  width: 240px;
  border-color: var(--brand-ring);
  box-shadow: 0 12px 40px rgba(17, 20, 32, 0.12), 0 4px 16px rgba(109, 40, 217, 0.08);
  /* Bung: phản hồi tức thì (bỏ delay), decelerate dài để đáp êm. */
  transition: width 0.5s cubic-bezier(0.25, 1, 0.3, 1),
              box-shadow 0.4s ease,
              border-color 0.24s ease;
}

/* Logo giữ chuyển động nhỏ để thương hiệu ổn định, không bị "nhảy". */
.sidebar-brand {
  display: flex; align-items: center; gap: 12px;
  padding: 2px 2px 18px; color: var(--text); text-decoration: none;
  white-space: nowrap; overflow: hidden;
  margin-bottom: 4px;
}
.sidebar-brand .logo-icon {
  width: 40px; height: 40px; border-radius: var(--r-md); flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--brand-600), var(--brand-800)); color: #fff;
  box-shadow: 0 4px 14px rgba(109, 40, 217, 0.35);
  will-change: transform, box-shadow;
  transform: scale(0.97);
  transition: transform 0.24s cubic-bezier(0.4, 0, 1, 1), box-shadow 0.24s ease;
}
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-brand .logo-icon {
  transform: translateX(1px) scale(1.04) rotate(-2deg);
  box-shadow: 0 6px 18px rgba(109, 40, 217, 0.42);
  transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1) 0.06s,
              box-shadow 0.3s ease 0.06s;
}

/* Brand text: wipe + slide, xuất hiện sau khi khung bắt đầu mở.
   :not(.logo-icon) BẮT BUỘC — ô logo cũng là <span> con trực tiếp của brand,
   thiếu nó thì logo bị ẩn luôn lúc rail thu gọn, đầu rail trống hoác. */
.sidebar-brand > span:not(.logo-icon) {
  display: inline-flex; align-items: baseline; gap: 4px;
  opacity: 0; visibility: hidden;
  transform: translateX(-8px);
  clip-path: inset(0 100% 0 0 round 2px);
  will-change: opacity, transform, clip-path;
  transition: opacity 0.14s ease, transform 0.16s ease,
              clip-path 0.16s ease, visibility 0s linear 0.16s;
}
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-brand > span:not(.logo-icon) {
  opacity: 1; visibility: visible;
  transform: translateX(0);
  clip-path: inset(0 0 0 0 round 2px);
  transition: opacity 0.28s ease-out 0.08s,
              transform 0.32s cubic-bezier(0.22, 1, 0.36, 1) 0.08s,
              clip-path 0.32s cubic-bezier(0.22, 1, 0.36, 1) 0.08s,
              visibility 0s linear 0s;
}
.sidebar-brand b { font-size: var(--fs-md); font-weight: 800; letter-spacing: -0.2px; color: var(--text); }
.sidebar-brand span span { color: var(--text-3); font-weight: 600; font-size: var(--fs-sm); }

/* --- Nav items --- */
.sidebar-nav { display: flex; flex-direction: column; gap: 4px; margin-top: 8px;
  /* Khe hở trước vạch ngăn của .sidebar-foot. Mục nav đang chọn có bóng đổ tím
     `0 8px 24px rgba(109,40,217,.35)` toả XUỐNG; vạch ngăn màu --divider rất nhạt
     nằm cách đúng 0px nên bị bóng phủ mất. Chỉ lộ ở trang /members — trang DUY NHẤT
     mà mục cuối cùng của nav đang active — nên nhìn như hai trang không đồng nhất.
     12px đủ để vạch nằm ngoài vùng đậm của bóng. (chủ tool phát hiện 22/07) */
  margin-bottom: 16px;
}
.sidebar-nav a {
  display: flex; align-items: center; gap: 12px;
  min-height: 44px; padding: 0 12.5px; border-radius: var(--r-md);
  color: var(--text-2); font-weight: 600; font-size: var(--fs-base);
  white-space: nowrap; overflow: hidden;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease),
              transform 0.2s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.2s var(--ease);
}
.sidebar-nav a svg {
  width: 19px; height: 19px; flex-shrink: 0;
  opacity: 0.82;
  transform: scale(0.96);
  transition: opacity 0.22s ease, transform 0.26s cubic-bezier(0.22, 1, 0.36, 1), color 0.2s ease;
}
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-nav a svg,
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-foot button svg {
  opacity: 1;
  transform: translateX(1px) scale(1.03);
}
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-nav a:nth-child(1) svg { transition-delay: 0.06s; }
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-nav a:nth-child(2) svg { transition-delay: 0.1s; }
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-nav a:nth-child(3) svg { transition-delay: 0.14s; }
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-nav a:nth-child(4) svg { transition-delay: 0.18s; }
.sidebar-nav a:hover { background: var(--surface-3); color: var(--text); transform: translateX(2px); }
.sidebar-nav a:hover svg { transform: translateX(1px) scale(1.09); color: var(--brand); transition-delay: 0s; }
.sidebar-nav a.active { background: var(--gradient-brand); color: #fff; box-shadow: var(--shadow-brand); }
.sidebar-nav a.active svg { color: #fff; opacity: 1; }
.sidebar-nav a.active:hover { transform: translateX(1px); }

/* Nav text: wipe + slide reveal, theo nhịp 40ms mỗi mục. */
.sidebar .nav-text {
  opacity: 0; visibility: hidden;
  transform: translateX(-8px);
  clip-path: inset(0 100% 0 0 round 2px);
  white-space: nowrap;
  will-change: opacity, transform, clip-path;
  transition: opacity 0.14s ease, transform 0.16s ease,
              clip-path 0.16s ease, visibility 0s linear 0.16s;
}
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .nav-text {
  opacity: 1; visibility: visible;
  transform: translateX(0);
  clip-path: inset(0 0 0 0 round 2px);
  transition: opacity 0.26s ease-out,
              transform 0.3s cubic-bezier(0.22, 1, 0.36, 1),
              clip-path 0.3s cubic-bezier(0.22, 1, 0.36, 1),
              visibility 0s linear 0s;
}

.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-nav a:nth-child(1) .nav-text { transition-delay: 0.1s; }
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-nav a:nth-child(2) .nav-text { transition-delay: 0.14s; }
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-nav a:nth-child(3) .nav-text { transition-delay: 0.18s; }
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-nav a:nth-child(4) .nav-text { transition-delay: 0.22s; }

/* Badge: scale pop sau khi text xuất hiện */
.sidebar-nav a .nav-badge {
  margin-left: auto; min-width: 20px; height: 20px; padding: 0 6px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill); font-size: var(--fs-2xs); font-weight: 800;
  background: var(--warning-soft); color: var(--warning); font-variant-numeric: tabular-nums;
  opacity: 0; transform: scale(0.5);
  transition: opacity 0.2s ease, transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-nav a .nav-badge { opacity: 1; transform: scale(1); }
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-nav a:nth-child(1) .nav-badge { transition-delay: 0.18s; }
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-nav a:nth-child(2) .nav-badge { transition-delay: 0.22s; }
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-nav a:nth-child(3) .nav-badge { transition-delay: 0.26s; }
.sidebar-nav a.active .nav-badge { background: rgba(255,255,255,0.22); color: #fff; }

/* --- Sidebar footer --- */
.sidebar-foot {
  margin-top: auto; display: flex; flex-direction: column; gap: 4px;
  padding-top: 10px;
  /* --border-strong chứ KHÔNG --divider: mục nav đang chọn có bóng tím toả xuống
     (`0 8px 24px`, vùng đậm tới ~14px). Vạch #EEF0F4 nằm dưới lớp tím đó là mất
     hút — chỉ lộ ở trang /members nên nhìn như 2 trang không đồng nhất.
     Nới khe lên 16px (ở .sidebar-nav) VÀ đậm vạch lên, cần cả hai. */
  border-top: 1px solid var(--border-strong);
}
.sidebar-foot button {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  min-height: 44px; padding: 0 12.5px; border: none; background: transparent;
  border-radius: var(--r-md); color: var(--text-2); font-weight: 600; font-size: var(--fs-base);
  cursor: pointer; white-space: nowrap; overflow: hidden;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease),
              transform 0.2s cubic-bezier(0.22, 1, 0.36, 1);
}
.sidebar-foot button svg {
  width: 19px; height: 19px; flex-shrink: 0;
  opacity: 0.82;
  transform: scale(0.96);
  transition: opacity 0.22s ease, transform 0.26s cubic-bezier(0.22, 1, 0.36, 1), color 0.2s ease;
}
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-foot button:nth-child(1) svg { transition-delay: 0.2s; }
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-foot button:nth-child(2) svg { transition-delay: 0.24s; }
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-foot button:nth-child(3) svg { transition-delay: 0.28s; }
.sidebar-foot button:hover { background: var(--surface-3); color: var(--text); transform: translateX(2px); }
.sidebar-foot button:hover svg { transform: translateX(1px) scale(1.08); transition-delay: 0s; }
.sidebar-foot button:first-child:hover svg { transform: rotate(-8deg) scale(1.06); }
.sidebar-foot button.logout:hover svg { transform: translateX(2px) scale(1.06); }
.sidebar-foot button.logout:hover { background: var(--danger-soft); color: var(--danger); }
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-foot button:nth-child(1) .nav-text { transition-delay: 0.24s; }
.sidebar:is(:hover, :has(.sidebar-nav a:focus-visible)) .sidebar-foot button:nth-child(2) .nav-text { transition-delay: 0.28s; }

.sidebar-backdrop {
  position: fixed; inset: 0; z-index: 85; background: rgba(11, 13, 20, 0.5);
  opacity: 0; pointer-events: none; transition: opacity var(--dur) var(--ease);
}
.sidebar-backdrop.open { opacity: 1; pointer-events: auto; }

/* ---- Cột nội dung ---- */
/* Khung shell: padding-left 92px né rail nổi (left 12 + rộng 64 + 16 khe) —
   TRÙNG số với .tool-shell bên style.css. Rule gốc này bắt buộc phải có:
   thiếu nó nội dung chui xuống dưới rail (đã dính 1 lần). */
/* padding-left = 8 (khe trái) + 64 (rail) + 8 (khe phải) — TRÙNG số với .tool-shell bên style.css.
   Thêm 8px trên/phải/dưới để topbar + nội dung "nổi" thụt vào đúng bằng rail. */
.app-shell { display: flex; min-height: 100vh; min-height: 100dvh; padding: 8px 8px 8px 80px; }
.app-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* Topbar = thẻ NỔI bo tròn, cùng ngôn ngữ với rail (bo 20px, viền, bóng).
   top: 8px để khi cuộn nó dính đúng ngang mép trên của rail, không trồi ra ngoài. */
.topbar {
  position: sticky; top: 8px; z-index: 80;
  min-height: var(--header-height);
  display: flex; align-items: center; gap: 14px;
  padding: 14px clamp(16px, 3vw, 28px);
  background: var(--header-bg);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border: 1px solid var(--border);
  border-radius: 20px;
  box-shadow: 0 4px 20px rgba(17, 20, 32, 0.08), 0 1px 4px rgba(17, 20, 32, 0.04);
}
.menu-toggle { display: none; }
.topbar-greeting h1 { font-size: clamp(20px, 2.4vw, 26px); font-weight: 800; letter-spacing: -0.5px; line-height: 1.15; }
.topbar-greeting p { color: var(--text-3); font-size: var(--fs-sm); margin-top: 3px; }
.topbar .spacer { flex: 1; }

/* Chip tài khoản — viên bo tròn có định hình, không trơ trên nền nữa */
.topbar-user {
  display: flex; align-items: center; gap: 11px;
  padding: 5px 15px 5px 5px;
  border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--surface); box-shadow: var(--shadow-xs);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.topbar-user:hover { border-color: var(--border-strong); box-shadow: var(--shadow-sm); transform: translateY(-1px); }
.topbar-user .avatar {
  width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--gradient-brand); color: #fff;
  font-size: var(--fs-md); font-weight: 800; text-transform: uppercase;
  box-shadow: 0 3px 10px rgba(109, 40, 217, 0.30);
}
.topbar-user .tu-id { line-height: 1.2; }
.topbar-user .tu-id b { display: block; font-size: var(--fs-sm); font-weight: 800; letter-spacing: -0.1px; }
.topbar-user .tu-id span {
  display: inline-block; margin-top: 3px;
  font-size: var(--fs-2xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--brand); background: var(--brand-soft);
  padding: 1px 8px; border-radius: var(--r-pill);
}

/* KHÔNG giới hạn max-width: nội dung phải trải đúng bằng .topbar phía trên,
   nếu không trên màn rộng header dài tới mép còn nội dung hụt ~700px → nhìn rời rạc.
   KHÔNG padding ngang: thẻ nội dung phải thẳng CẠNH với thẻ topbar (cả hai cùng
   là thẻ nổi) — khoảng thở hai bên đã do .app-shell lo. */
.dash { flex: 1; width: 100%; padding: 12px 0 40px; }

/* Trong lúc GSAP chạy hiệu ứng xuất hiện: tắt CSS transition của vùng đang tween.
   Nếu để nguyên, `transition: transform .25s` của .stat-card sẽ nội suy TỪNG LẦN
   GSAP ghi transform (mỗi khung hình) → chuyển động trễ và giật một cái lúc kết thúc.
   Class do animations.js bật/tắt. */
body.is-entering .topbar-greeting, body.is-entering .topbar-greeting *,
body.is-entering .stat-row, body.is-entering .stat-row *,
body.is-entering .dash-grid, body.is-entering .dash-grid * {
  transition: none !important;
}

/* Màn chặn toàn trang khi guard không xác minh được hồ sơ (auth.js → blockPage).
   Phủ kín để nội dung phía sau không dùng được, nhưng KHÔNG đăng xuất người dùng. */
.auth-block {
  position: fixed; inset: 0; z-index: 9999;
  display: flex; align-items: center; justify-content: center;
  padding: 20px; background: var(--app-bg);
}
.auth-block-card {
  width: 100%; max-width: 420px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-xl); box-shadow: var(--shadow-lg); padding: 22px;
}
.auth-block-card .notice { margin-bottom: 14px; }

/* ---- Tactile Click Feedback & Card Micro-Interactions ---- */
button:active, .btn:active, .icon-btn:active, .sidebar-nav a:active, .sidebar-foot button:active, .stat-card:active, .area-card:active {
  transform: scale(0.97) !important;
}

/* ---- Thẻ số liệu ---- */
.stat-row { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(196px, 1fr)); margin-bottom: 16px; }
.stat-card {
  display: flex; align-items: center; gap: 14px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: 16px 18px; box-shadow: var(--shadow-xs);
  transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.25s ease, border-color 0.25s ease;
  cursor: pointer;
}
.stat-card:hover {
  transform: translateY(-3px);
  border-color: var(--brand-300);
  box-shadow: 0 8px 24px rgba(17, 20, 32, 0.08);
}
.stat-card:hover .st-icon {
  transform: scale(1.1);
}
.stat-card .st-icon {
  width: 46px; height: 46px; border-radius: var(--r-md); flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.stat-card .st-icon svg { width: 22px; height: 22px; }
.stat-card .st-label { color: var(--text-3); font-size: var(--fs-sm); font-weight: 600; }
.stat-card .st-value { font-size: var(--fs-xl); font-weight: 800; letter-spacing: -0.5px; line-height: 1.1; margin-top: 2px; font-variant-numeric: tabular-nums; }
.st-icon.v-violet { background: var(--brand-soft); color: var(--brand); }
.st-icon.v-teal   { background: var(--area-learn-soft); color: var(--area-learn); }
.st-icon.v-amber  { background: var(--area-forum-soft); color: var(--area-forum); }
.st-icon.v-rose   { background: var(--danger-soft); color: var(--danger); }

/* ---- Lưới: thẻ hành động (signature) + panel ---- */
.dash-grid { display: grid; gap: 16px; grid-template-columns: 1.4fr 1fr; }

.hero-action {
  position: relative; overflow: hidden;
  border-radius: var(--r-xl); padding: 32px; min-height: 220px; color: #fff;
  background: var(--gradient-hero);
  box-shadow: 0 16px 44px rgba(109, 40, 217, 0.38);
  border: 1px solid rgba(255, 255, 255, 0.18);
  display: flex; flex-direction: column; gap: 14px;
}
.hero-action::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(circle at 85% 15%, rgba(255, 255, 255, 0.22), transparent 65%);
  pointer-events: none;
}
.hero-action .ha-eyebrow {
  font-size: var(--fs-2xs); font-weight: 800; text-transform: uppercase; letter-spacing: 1.2px;
  background: rgba(255, 255, 255, 0.18); color: #fff; align-self: flex-start;
  padding: 4px 12px; border-radius: var(--r-pill); border: 1px solid rgba(255, 255, 255, 0.25);
}
.hero-action h2 { font-size: clamp(20px, 2.4vw, 26px); font-weight: 800; letter-spacing: -0.4px; position: relative; }
.hero-action p { color: rgba(255,255,255,0.88); font-size: var(--fs-base); max-width: 42ch; flex: 1; position: relative; }
.hero-action .btn-white {
  align-self: flex-start; background: #fff; color: var(--brand-800);
  min-height: 46px; padding: 0 22px; border-radius: var(--r-md);
  font-weight: 700; font-size: var(--fs-base); box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15); position: relative;
  display: inline-flex; align-items: center; gap: 10px;
  transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.25s ease;
}
.hero-action .btn-white svg {
  transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.hero-action .btn-white:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.25);
}
.hero-action .btn-white:hover svg {
  transform: translateX(4px);
}

.panel { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-xl); padding: 20px 22px; box-shadow: var(--shadow-sm); }
.panel-head { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
.panel-head h2 { font-size: var(--fs-md); font-weight: 800; letter-spacing: -0.2px; }
.panel-head .panel-link { margin-left: auto; font-size: var(--fs-sm); font-weight: 700; color: var(--brand); }

.mini-list { display: flex; flex-direction: column; }
/* Là thẻ <a> (bấm vào hàng → /members) nên phải tự bỏ gạch chân + trả màu chữ */
.mini-row {
  display: flex; align-items: center; gap: 12px; padding: 11px 8px; margin: 0 -8px;
  border-radius: var(--r-md); border-top: 1px solid var(--divider);
  text-decoration: none; color: inherit; cursor: pointer;
}
.mini-row:first-child { border-top: none; }
.mini-row:hover { background: var(--surface-2); }
.mini-row:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.mini-row .avatar {
  width: 36px; height: 36px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--brand-soft-2); color: var(--brand); font-size: var(--fs-sm); font-weight: 800; text-transform: uppercase;
}
.mini-row .mr-id { flex: 1; min-width: 0; }
.mini-row .mr-id b { display: block; font-size: var(--fs-sm); font-weight: 700; }
.mini-row .mr-id span { display: block; color: var(--text-3); font-size: var(--fs-xs); word-break: break-all; }
.mini-row .mr-when { color: var(--text-3); font-size: var(--fs-xs); white-space: nowrap; }
.panel .empty-mini { color: var(--text-3); font-size: var(--fs-sm); padding: 18px 0 6px; text-align: center; }

/* ---- Responsive dashboard ---- */
@media (max-width: 900px) {
  .dash-grid { grid-template-columns: 1fr; }
  .app-shell { padding: 8px; }   /* mobile: rail thành drawer nên bỏ chừa 80px */
  .sidebar {
    left: 8px; top: 8px; bottom: 8px;
    transform: translateX(calc(-100% - 16px));  /* 8px khe + đủ giấu bóng đổ */
    transition: transform 0.38s cubic-bezier(0.16, 1, 0.3, 1); box-shadow: var(--shadow-lg);
    width: 236px !important;
    padding: 16px 12px !important;
  }
  .sidebar .sidebar-brand > span:not(.logo-icon) { opacity: 1 !important; visibility: visible !important; transform: translateX(0) !important; clip-path: inset(0 0 0 0) !important; }
  .sidebar .nav-text { opacity: 1 !important; visibility: visible !important; transform: translateX(0) !important; clip-path: inset(0 0 0 0) !important; }
  .sidebar .sidebar-nav a .nav-badge { opacity: 1 !important; transform: scale(1) !important; }
  .sidebar.open { transform: translateX(0); }
  .menu-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: 42px; height: 42px; border-radius: var(--r-md);
    background: var(--surface); border: 1px solid var(--border); color: var(--text-2);
  }
  .menu-toggle:hover { color: var(--text); }
}
@media (min-width: 901px) {
  .sidebar-backdrop { display: none; }
}
@media (max-width: 520px) {
  .topbar-user .tu-id { display: none; }
}

/* ==========================================================================
   RAIL — HIỆU ỨNG + CHUYỂN TRANG (21/07/2026, theo yêu cầu chủ tool)
   Khối này ĐƯỢC CHÉP SANG style.css (đổi .sidebar → .portal-sidebar).
   Sửa ở đây thì sửa cả hai — hai file đang là bản sao của nhau.
   ========================================================================== */

/* Góc quay của vệt sáng chạy viền. Phải khai bằng @property thì mới nội suy
   được (biến CSS thường không animate). */
@property --rail-angle {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}

/* Chuyển trang: fade + nhích nhẹ thay vì chớp trắng rồi giật.
   PHẢI để ngoài @media — @view-transition không hợp lệ khi lồng trong đó.
   Chỉ chạy khi CẢ HAI trang cùng khai báo (portal.css + style.css đều có). */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: tst-page-out 0.16s ease both; }
::view-transition-new(root) { animation: tst-page-in 0.30s cubic-bezier(0.22, 1, 0.36, 1) both; }
@keyframes tst-page-out { to { opacity: 0; } }
@keyframes tst-page-in  { from { opacity: 0; transform: translateY(8px); } }

/* Vươn dài ra rồi đáp về đúng chiều cao. translateY(-50%) phải có trong MỌI
   khung hình, nếu không rail mất căn giữa trong lúc chạy. */
/* KHÔNG dùng scaleY: nó BÓP MÉO icon và chữ trong lúc chạy — chủ tool thấy
   "giật" khi F5 (21/07). clip-path lộ dần từ giữa ra: khung trông như dài ra
   mà nội dung bên trong không hề biến dạng. */
@keyframes tst-rail-enter {
  0%   { opacity: 0; clip-path: inset(42% 0 42% 0 round 20px); }
  100% { opacity: 1; clip-path: inset(0 0 0 0 round 20px); }
}
@keyframes tst-rail-trace { to { --rail-angle: 360deg; } }

/* Desktop-only: mobile rail là drawer, tối nền + vệt chạy ở đó là thừa. */
@media (min-width: 901px) {
  /* 1. Hover rail → tối nền cho mắt dồn vào menu.
     Dùng body::after nên KHÔNG phải thêm thẻ vào 5 file HTML, và không bị
     overflow:hidden của rail cắt mất. z-index 150 = trên topbar (80), dưới rail (200). */
  body::after {
    content: '';
    position: fixed; inset: 0; z-index: 150;
    background: rgba(11, 13, 20, 0.38);
    opacity: 0; pointer-events: none;
    transition: opacity 0.32s var(--ease);
  }
  body:has(.sidebar:hover)::after,
  body:has(.sidebar:focus-within)::after { opacity: 1; }

  /* 2. Chạy 1 lần lúc vào trang */
  .sidebar { animation: tst-rail-enter 0.62s cubic-bezier(0.22, 1, 0.36, 1) both; }

  /* 3. Vệt sáng chạy quanh viền khi hover.
     inset: 0 và bo 19px (không phải -1px/21px) vì rail có overflow:hidden —
     đặt âm sẽ bị cắt mất; vệt chạy sát mép TRONG của viền. */
  .sidebar::before {
    content: '';
    position: absolute; inset: 0; z-index: 1;
    border-radius: 19px;
    padding: 1.5px;
    background: conic-gradient(from var(--rail-angle),
                transparent 0deg, var(--brand) 45deg, var(--brand-400) 75deg, transparent 120deg);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
            mask-composite: exclude;
    opacity: 0; pointer-events: none;
    transition: opacity 0.28s var(--ease);
  }
  .sidebar:is(:hover, :focus-within)::before {
    opacity: 1;
    animation: tst-rail-trace 2.4s linear infinite;
  }
}

/* ============================================================================
   ĐO LƯỜNG SỬ DỤNG (N1, 23/07/2026) — tab + thẻ số + biểu đồ + bảng theo người.
   Chỉ hiện ở /members cho super_admin. Toàn token → theme tối tự đúng.
   ============================================================================ */

/* Tab chuyển Thành viên / Đo lường — mượn dáng .auth-tabs, hug nội dung */
.ms-tabs {
  display: inline-flex; gap: 4px; margin-bottom: 16px;
  background: var(--surface-3); border-radius: var(--r-md); padding: 4px;
}
.ms-tab {
  min-height: 34px; padding: 0 16px; border: none; background: transparent;
  border-radius: var(--r-sm); cursor: pointer;
  font-family: inherit; font-size: var(--fs-sm); font-weight: 600; color: var(--text-2);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.ms-tab:hover { color: var(--text); }
.ms-tab.is-on { background: var(--surface); color: var(--text); box-shadow: var(--shadow-xs); }

/* Hàng đầu: ô TÌM (trái) + tabs (phải) trên MỘT dòng (chủ tool 16/09/2026).
   Trước đây tabs và ô tìm xếp hai hàng chồng nhau; gộp lại cho gọn, cuộn đỡ "dồn cục".
   Tabs bám SÁT MÉP PHẢI ngoài cùng — thẳng mép phải cột "Tổng quan" và thẳng mép phải
   thẻ .topbar phía trên (chủ tool chốt 16/09/2026; bản đầu chừa 328px để dừng ở mép
   bảng, anh yêu cầu đẩy ra sát mép). ĐỪNG thêm lại padding-right.
   flex-wrap để màn hẹp thì tabs tự xuống hàng, không bóp méo ô tìm. */
.ms-head {
  display: flex; align-items: center; gap: 12px 16px; flex-wrap: wrap;
  margin-bottom: 16px;
}
.ms-head .ms-tabs { margin-bottom: 0; margin-left: auto; }   /* đẩy tabs sang mép phải */

/* Dải số liệu — MỘT nguồn duy nhất, đổi theo khoảng đang chọn (gọn 27/07).
   Thay cho 4 thẻ "Hôm nay" (3 dòng chữ, số 30px) + danh sách "Trong khoảng này"
   ở cột phải: hai chỗ cùng tên chỉ số khác khoảng thời gian → đọc dễ nhầm. */
.usage-stats {
  display: grid; gap: 10px; grid-template-columns: repeat(3, minmax(0, 1fr));
  margin-bottom: 12px;
}
.ustat {
  display: flex; flex-direction: column; gap: 2px; min-width: 0;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: 10px 14px; box-shadow: var(--shadow-xs);
}
.ustat-k {
  font-size: var(--fs-xs); font-weight: 700; color: var(--text-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ustat-v { font-size: 22px; font-weight: 800; color: var(--text); line-height: 1.15; font-variant-numeric: tabular-nums; }
.ustat-v.is-ok { color: var(--success); }
/* Ô "Tải về" bấm được → popup chi tiết (giữ hành vi cũ của .ms-row-btn) */
.ustat-btn { font: inherit; text-align: left; cursor: pointer; transition: border-color var(--dur) var(--ease); }
.ustat-btn:hover { border-color: var(--brand); }
.ustat-btn:hover .ms-row-more { color: var(--brand); transform: translateX(2px); }
.ustat-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* Khối biểu đồ + bảng */
.usage-block {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-xl); padding: 14px 16px; box-shadow: var(--shadow-xs);
  margin-bottom: 12px;
}
/* ☠️ TIÊU ĐỀ VÀ CHÚ THÍCH KHÔNG ĐƯỢC NHÉT CHUNG MỘT HÀNG (chủ tool 31/07 khoanh đỏ
   cả 3 khối). Chú thích ở đây dài 3–4 mệnh đề ("2/7 – 31/7 · 30 ngày · áp dụng cho cả
   trang · chưa có số liệu trước 23/7") — bám sát ngay sau tiêu đề thì tiêu đề mất hết
   trọng lượng, mắt không tách được đâu là TÊN KHỐI đâu là ghi chú.
   `flex-wrap: wrap` cũ không cứu được: chú thích vẫn vừa một dòng nên không bao giờ
   xuống, chỉ kéo dài ra thôi. Cho nó xuống dòng riêng, LUÔN LUÔN. */
.usage-block-head { display: block; margin-bottom: 10px; }
.usage-block-head h2 { font-size: var(--fs-md); font-weight: 800; letter-spacing: -0.2px; }
.usage-hint { display: block; margin-top: 3px; font-size: var(--fs-sm); color: var(--text-3); line-height: 1.45; }

/* Biểu đồ cột 14 ngày (thuần CSS, không thư viện) */
.usage-chart { display: flex; align-items: stretch; gap: 6px; height: 132px; }
.uc-col { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 6px; }
.uc-barwrap { flex: 1; width: 100%; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; }
.uc-n { font-size: var(--fs-xs); font-weight: 700; color: var(--text-2); font-variant-numeric: tabular-nums; margin-bottom: 3px; min-height: 14px; }
/* Bề rộng thanh: 66% quá mảnh khi khoảng dài (đo 31/07: 30 ngày → thanh 11px, cao 136px,
   tỉ lệ 12,3:1 — nhìn như cây kim). 82% + khe co theo số cột (members.js đặt `gap`) cho
   thanh dày lên mà không phải hạ chiều cao biểu đồ. `max-width` giữ nguyên để khoảng
   NGẮN (7 ngày) không phình thành mấy khối chữ nhật to. */
.uc-bar {
  /* Trần bề rộng do members.js đặt theo SỐ CỘT (`--uc-bar-max`): ít cột thì cho thanh
     dày hẳn, nhiều cột thì siết lại. 34px là mức dùng khi JS chưa kịp đặt. */
  width: 82%; max-width: var(--uc-bar-max, 34px); min-height: 3px;
  background: var(--gradient-brand); border-radius: 4px 4px 0 0;
  transition: height var(--dur) var(--ease);
}
/* Ngày 0 người KHÔNG còn vẽ thanh nào (members.js bỏ hẳn phần tử) — trước đây là
   `min-height: 3px` màu xám, thành 21 gạch nhiễu ở đáy. Giữ luật ở đây phòng nơi khác
   còn gắn class này. */
.uc-bar.is-zero { display: none; }
.uc-x { font-size: var(--fs-xs); color: var(--text-3); font-variant-numeric: tabular-nums; }

/* ---- KHỐI "CÔNG CỤ TRA CỨU" — Tính tuổi & Tính phí (12/08/2026) ----------------
   ☠️ GỌN LẠI ngay trong ngày (chủ tool: "chỗ này em làm gọn lại cho anh được không").
   Bản đầu xếp DỌC — hai thẻ số, rồi biểu đồ, rồi dải nút — cao ~570px mà phần lớn là
   mảng trắng: hệ đo lường mới có 2 ngày số liệu, biểu đồ vẫn kéo hết chiều ngang nên
   hai cặp cột lạc lõng giữa khoảng không.
   Nay chia HAI CỘT: số bên trái, biểu đồ bên phải, cao bằng nhau. */
.ucc-grid { display: grid; grid-template-columns: minmax(250px, 300px) 1fr; gap: 16px; align-items: stretch; }
@media (max-width: 860px) { .ucc-grid { grid-template-columns: 1fr; } }
.ucc-right { display: flex; flex-direction: column; min-width: 0; }
/* Dòng "Số liệu từ …" bám ĐÁY cột phải để hai cột luôn kết thúc bằng nhau. */
.ucc-note { margin-top: auto; text-align: right; }

/* Tiêu đề + dải nút 30/60 CÙNG MỘT HÀNG. Bản trước để nút thành hàng riêng dưới biểu
   đồ — ăn trọn ~44px chỉ để chứa hai cái nút, mà chủ tool đã bảo làm gọn hai lần. */
.ucc-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.ucc-title { min-width: 0; }
.ucc-head .usage-presets { flex: none; }

/* ☠️ ĐO RỒI MỚI BIẾT SIẾT CHỖ NÀO. Bản trước tôi dời dải nút lên đầu khối cho gọn —
   đo lại thì chiều cao KHÔNG ĐỔI (308px). Vì cột trái (hai thẻ số xếp dọc, 107px mỗi
   thẻ = 225px) mới là thứ quyết định chiều cao; biểu đồ chỉ giãn ra cho bằng.
   Nên chỗ phải siết là THẺ SỐ, không phải dải nút. */
.ucc-stats { display: grid; grid-template-columns: 1fr; gap: 8px; align-content: start; }
@media (max-width: 860px) { .ucc-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .ucc-stats { grid-template-columns: 1fr; } }
.ucc-stat { border: 1px solid var(--border); border-radius: var(--r-md); padding: 8px 11px; background: var(--surface-2); }
.ucc-stat-head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 2px; }
.ucc-dot { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.ucc-tinhtuoi .ucc-dot { background: var(--brand); }
.ucc-tinhphi  .ucc-dot { background: #f0a02c; }
.ucc-name { font-weight: 700; font-size: var(--fs-sm); color: var(--text); }
/* Nấc phát hành đứng NGAY CẠNH TÊN, không nhét xuống cuối: nó là thứ quyết định cách
   đọc con số bên dưới ("0 lượt sale" vì chưa mở, chứ không phải vì sale chê). */
.ucc-nac { font-size: var(--fs-xs); color: var(--text-3); background: var(--surface-3);
           border-radius: 999px; padding: 2px 8px; white-space: nowrap; }
.ucc-nac.is-warn { color: #8a5a00; background: #fff4e0; }
/* Con số và "N người dùng tới" nằm CÙNG MỘT DÒNG — bản đầu tách hai dòng, cao thêm
   mà không nói thêm gì. Cỡ 26px vẫn là thứ đập vào mắt đầu tiên trong thẻ. */
.ucc-big { font-size: 22px; font-weight: 800; line-height: 1.2; color: var(--text);
           font-variant-numeric: tabular-nums; display: flex; align-items: baseline;
           gap: 5px; flex-wrap: wrap; }
.ucc-unit { font-size: var(--fs-sm); font-weight: 600; color: var(--text-3); }
.ucc-sub { font-size: var(--fs-xs); color: var(--text-3); font-weight: 500; }
/* Không còn vạch kẻ + khoảng đệm riêng: dòng này đã khác hẳn về cỡ chữ và màu, thêm
   vạch chỉ tốn 12px chiều cao mà không nói thêm gì. */
.ucc-sale { font-size: var(--fs-xs); color: var(--text-2); margin-top: 3px; }
.ucc-sale.is-muted { color: var(--text-3); font-style: italic; }
.ucc-sale b { color: var(--text); font-variant-numeric: tabular-nums; }

/* Cao co theo cột phải, có TRẦN để khối không phình ra khi cửa sổ rộng. */
.ucc-chart { height: auto; flex: 1 1 auto; min-height: 112px; max-height: 168px; }
/* ☠️ TRẦN BỀ RỘNG CHO MỖI CỘT. `.uc-col { flex: 1 1 0 }` chia đều cả chiều ngang, nên
   khoảng mới có 2 ngày số liệu thì hai cặp cột bị kéo giãn ra hai đầu, ở giữa là một
   mảng trắng khổng lồ — đúng cái chủ tool chê 12/08. Có trần thì cột không phình ra.
   ⚠️ CHỈ có trần thôi thì CHƯA ĐỦ: đo được cụm cột dồn về trái, chừa 1.070px trắng bên
   phải — mới là DỜI mảng trắng chứ chưa xoá. Phải CĂN GIỮA cụm nữa (members.js còn đặt
   sàn 10 cột để cụm không quá nhỏ). */
.ucc-chart { justify-content: center; }
.ucc-chart .uc-col { max-width: 58px; }

/* Hai thanh đứng CẠNH nhau trong một ngày (không chồng lên nhau): chồng thì không đọc
   được từng công cụ, mà câu hỏi của chủ tool là so hai công cụ với nhau. */
.ucc-barwrap { width: 100%; }
.ucc-pair { display: flex; align-items: flex-end; justify-content: center; gap: 2px;
            width: 100%; height: 100%; }
.ucc-pair .uc-bar { width: 46%; max-width: 16px; }
.ucc-bar-a { background: var(--gradient-brand); }
.ucc-bar-b { background: linear-gradient(180deg, #ffc266, #f0a02c); }
.dark-theme .ucc-nac.is-warn { color: #ffce7a; background: rgba(240, 160, 44, .16); }

/* Bảng theo người — 7 cột. Tên tiếng Anh và Phòng ban có CỘT RIÊNG (27/07): dán chúng
   sau tên thì tên dài ngắn khác nhau kéo chúng lệch mỗi hàng một chỗ, mắt không dóng
   được — chủ tool gọi là "rối". Mọi cột trừ cột tên đều CỐ ĐỊNH px vì giá trị luôn ngắn
   ("Henry", "Sale", "7 giờ trước", "3"); chỗ dư dồn hết cho cột tên. */
/* Bảy cột này chứa toàn giá trị ngắn ("Sale", "3 giờ trước", "11"). Trước 31/07 phải đặt
   `max-width: 1240px` để bảng khỏi kéo full 1850px làm mọi cột thừa chỗ. NAY KHÔNG CẦN
   NỮA: mảng trắng bên phải đã được thanh "đang online" lấp vào (xem .usage-grid-nguoi),
   nên bảng cứ đầy cột trái của lưới. */

/* ---- Bảng "Theo từng người" + thanh ĐANG ONLINE nằm cạnh nhau (chủ tool 31/07) ----
   Gom hai thứ cùng nói về CON NGƯỜI về một chỗ, và lấp đúng khoảng trắng bên phải bảng. */
.usage-grid-nguoi {
  display: grid; grid-template-columns: minmax(0, 1fr) 300px;
  gap: 12px; align-items: start;
}
.usage-grid-nguoi > .usage-block { margin-bottom: 0; }
.usage-side-online { display: flex; flex-direction: column; gap: 8px; }
.usage-side-online .usage-bar { margin-bottom: 0; }

/* ☠️ Ở cột 300px, cứ `flex-direction: column` là 5 mẩu rơi thành 5 dòng rời rạc
   (chấm · số · chữ · chip · link) — chủ tool 31/07: "thiết kế lại cho đẹp".
   Dựng lại thành THẺ THỐNG KÊ bằng grid-area, KHÔNG đụng HTML:
       ● ĐANG ONLINE       ← nhãn nhỏ, chữ hoa
       2                   ← con số là nhân vật chính
       🔧 Tool 1  🏠 Trang chính 1
       ─────────────────
                Chi tiết › */
.usage-side-online .online-bar {
  display: grid; align-items: center; gap: 6px 8px; padding: 16px;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas:
    "dot   nhan"
    "so    so"
    "chip  chip"
    "them  them";
}
.usage-side-online .online-dot        { grid-area: dot; }
.usage-side-online .online-bar-label  {
  grid-area: nhan; font-size: var(--fs-xs); font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.6px; color: var(--text-3);
}
/* Con số là thứ người ta liếc vào để biết ngay → to, không nhốt trong viên thuốc nữa. */
.usage-side-online .online-count {
  grid-area: so; justify-self: start; padding: 0; min-width: 0; height: auto;
  background: none; color: var(--success);
  font-size: 34px; font-weight: 800; line-height: 1.1; letter-spacing: -1px;
}
/* DẠNG CỘT (chủ tool 31/07): mỗi vị trí một dòng, tên trái — số phải. Các con số dóng
   thẳng một mép nên liếc là so được ngay; chip nằm ngang thì số trôi theo độ dài tên. */
.usage-side-online .online-breakdown {
  grid-area: chip; margin-top: 2px;
  flex-direction: column; align-items: stretch; gap: 4px; width: 100%;
}
.usage-side-online .online-chip {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  border-radius: var(--r-sm); padding: 7px 10px; font-size: var(--fs-sm);
}
.usage-side-online .oc-k { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.usage-side-online .oc-v { font-weight: 800; font-variant-numeric: tabular-nums; }
.usage-side-online .online-bar-more  {
  grid-area: them; justify-self: end; margin-left: 0; margin-top: 6px;
  padding-top: 10px; border-top: 1px solid var(--divider); width: 100%; text-align: right;
}
/* Màn hẹp: hai khối xếp chồng → thanh online trở về dạng NGANG như cũ. */
@media (max-width: 1100px) {
  .usage-grid-nguoi { grid-template-columns: 1fr; }
  .usage-side-online .online-bar {
    display: flex; flex-direction: row; align-items: center; gap: 8px 10px; padding: 12px 14px;
  }
  .usage-side-online .online-count {
    font-size: var(--fs-md); padding: 0 8px; min-width: 26px; height: 24px;
    background: var(--success-soft); border-radius: 999px; letter-spacing: 0;
  }
  .usage-side-online .online-bar-label { font-size: var(--fs-sm); text-transform: none; letter-spacing: 0; color: var(--text-2); }
  .usage-side-online .online-bar-more { margin-left: auto; border-top: none; padding-top: 0; margin-top: 0; width: auto; }
  .usage-side-online .online-breakdown { flex-direction: row; align-items: center; width: auto; gap: 6px; }
  .usage-side-online .online-chip { display: inline-flex; gap: 5px; padding: 3px 9px; font-size: var(--fs-xs); }
}
.usage-thead, .usage-row {
  display: grid;
  /* ☠️ CŨ: `minmax(0, 1fr)` cho cột Thành viên + 6 cột px CỐ ĐỊNH → toàn bộ chỗ dư dồn
     HẾT vào cột tên. Ở màn 1850px, cột tên thành ~1150px trong khi tên chỉ chiếm ~150px:
     gần 1000px trắng giữa tên và "Tên tiếng Anh", mắt phải nhảy qua một khoảng trống lớn
     mới đọc được dòng tiếp (chủ tool 31/07: "hơi có vấn đề ở việc sắp xếp cột").
     NAY: 4 cột chữ cùng co giãn theo `fr` nên chỗ dư chia đều, không cột nào phình.
     Hai cột số + Phòng ban giữ px vì giá trị luôn ngắn ("Sale", "11", "0"). */
  grid-template-columns:
    minmax(180px, 1.5fr)   /* Thành viên     */
    minmax(120px, 1fr)     /* Tên tiếng Anh  */
    92px                   /* Phòng ban      */
    minmax(118px, 1fr)     /* Đăng nhập cuối */
    minmax(118px, 1fr)     /* Mở tool cuối   */
    84px                   /* Lần mở         */
    84px;                  /* Lần tải        */
  gap: 12px; align-items: center;
}
.usage-row .ur-en, .usage-row .ur-pb { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ur-trong { color: var(--text-3); }
/* Cột "Lần tải" = tín hiệu dùng THẬT → làm nổi (chủ tool 23/07), và từ 31/07 BẤM ĐƯỢC
   để xem người đó đã tải gì. Phải nhìn ra là bấm được: gạch chân mờ + đổi nền khi rê. */
.usage-row .ur-dl { font-weight: 800; color: var(--brand); }
.ur-dl-btn {
  border: none; background: transparent; font: inherit; font-weight: 800;
  color: var(--brand); cursor: pointer; padding: 2px 7px; border-radius: var(--r-sm);
  text-decoration: underline; text-decoration-style: dotted; text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, var(--brand) 45%, transparent);
}
.ur-dl-btn:hover { background: var(--brand-soft); text-decoration-color: var(--brand); }
.ur-dl-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.usage-thead {
  padding: 0 12px 8px; font-size: var(--fs-xs); font-weight: 700; color: var(--text-3);
  text-transform: uppercase; letter-spacing: 0.4px; border-bottom: 1px solid var(--divider);
}
.usage-thead .ta-right, .usage-row .ta-right { text-align: right; }
.usage-row {
  padding: 8px 12px; border-bottom: 1px solid var(--divider);
  font-size: var(--fs-sm); color: var(--text-2); font-variant-numeric: tabular-nums;
}
.usage-row:last-child { border-bottom: none; }
.usage-row .ur-name {
  font-weight: 600; color: var(--text);
  min-width: 0; display: flex; align-items: center; gap: 8px;
}
/* Tên co lại và cắt bằng "…" — chip phòng ban KHÔNG được co (flex: 0 0 auto) */
.ur-nm { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Tên tiếng Anh (suy từ email công ty) — phụ hoạ cho tên tiếng Việt, KHÔNG to ngang
   tên chính. Không bọc nền để mắt không đọc nhầm thành chip. */
.ur-en { font-size: var(--fs-sm); font-weight: 600; color: var(--brand); }
.ur-never { color: var(--text-3); font-style: italic; }

/* Mobile ≤760px: bảng theo người xếp dọc như thẻ (giống .member-row) */
@media (max-width: 760px) {
  .usage-thead { display: none; }
  .usage-row {
    grid-template-columns: 1fr; gap: 6px;
    border: 1px solid var(--border); border-radius: var(--r-md);
    padding: 12px 14px; margin-bottom: 10px;
  }
  .usage-row > span { display: flex; justify-content: space-between; gap: 12px; text-align: right; }
  .usage-row > span::before {
    content: attr(data-label); color: var(--text-3); font-weight: 600;
    font-size: var(--fs-xs); text-align: left; flex: 0 0 auto;
  }
  .usage-row .ur-nm { white-space: normal; }
  /* Tên + chip phòng ban là MỘT cụm → đẩy cả cụm sang phải, không để space-between
     bắn chip ra xa tên (hàng có 3 con: nhãn ::before, tên, chip). */
  .usage-row .ur-name::before { margin-right: auto; }
  .usage-row .ta-right { text-align: right; }
}

/* Hàng điều khiển: đang online (trái) + chọn khoảng ngày (phải) trên CÙNG một dòng.
   Trước 27/07 hộp chọn ngày là cột phải 300px chạy suốt trang → hết nội dung ở ~2/3,
   phần còn lại là khoảng trắng. Bỏ cột đó, biểu đồ/bảng lấy lại toàn bộ bề ngang. */
.usage-bar { display: flex; align-items: center; gap: 10px 14px; flex-wrap: wrap; margin-bottom: 12px; }
/* ☠️ Override `width: auto` này có từ hồi `.usage-bar` chứa HAI thứ (thanh online +
   hộp chọn ngày) nằm cạnh nhau. Ngày 27/07 hộp chọn ngày dời vào khối biểu đồ, nhưng
   dòng này ở lại → thanh online co thành một viên thuốc nhỏ chơ vơ góc trái, bỏ trống
   3/4 hàng (chủ tool 31/07 khoanh đỏ). Trả về full width như `.online-bar` gốc.
   → Bài học: gỡ một phần tử ra khỏi container thì phải rà lại CSS viết CHO container đó. */
.usage-bar .online-bar { padding: 10px 14px; }
.usage-bar .online-bar-more { margin-left: auto; }
/* Bộ chọn khoảng: dòng cuối TRONG khối biểu đồ (27/07). Đặt cạnh thứ nó điều khiển,
   và lấp đúng vùng trống mà chủ tool chỉ ra. Có vạch ngăn để không dính vào cột. */
.usage-filter {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  justify-content: space-between;
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--divider);
}
.up-sep { color: var(--text-3); font-weight: 700; margin: 0 -2px; }
.up-inline { display: inline-flex; align-items: center; gap: 6px; }
.up-inline input[type="date"] {
  min-height: 36px; padding: 0 10px;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2); color: var(--text);
  font-family: inherit; font-size: var(--fs-sm); cursor: pointer;
  color-scheme: light;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
body.dark-theme .up-inline input[type="date"] { color-scheme: dark; }
.up-inline input[type="date"]:hover { border-color: var(--border-strong); }
.up-inline input[type="date"]:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-ring); background: var(--surface); }
/* Preset nằm ngang nên KHÔNG giãn đều nữa (cột 300px cũ mới cần flex:1 → vỡ 3+1 hàng) */
/* ---- TAB "KHOÁ MỤC" (31/07/2026) — Super Admin tự khoá từng phần của Tool ----
   Một hàng = một mục. Trạng thái đọc được ngay từ MÀU + chữ, không phải suy từ nhãn nút. */
.khoa-list { display: flex; flex-direction: column; gap: 8px; }
.khoa-row {
  /* MỘT HÀNG DUY NHẤT (chủ tool 10/08/2026). Bốn cột, mỗi cột trả lời một câu:
     tên mục | ai được thấy | đang mở hay khoá | nút đổi.
     Cột nấc để `auto` chứ không cố định: ba nút có bề rộng theo chữ, ghim cứng là
     hoặc cắt chữ hoặc thừa chỗ. Cột trạng thái + nút thì ghim để 7 hàng dóng thẳng
     một mép — đó là thứ khiến danh sách đọc được bằng cách liếc dọc. */
  display: grid; grid-template-columns: minmax(0, 1fr) auto 92px 96px;
  gap: 14px; align-items: center;
  padding: 12px 16px; border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface);
}
.khoa-row.is-locked { background: var(--warning-soft); border-color: transparent; }
.khoa-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.khoa-info b { color: var(--text); font-weight: 700; }
.khoa-info span {
  font-size: var(--fs-sm); color: var(--text-3);
  /* Mô tả dài không được đẩy dải nút sang phải — cắt bằng ba chấm, hover xem đủ. */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Màu chữ trạng thái lấy bộ đã đo đạt AA (#96590A) — KHÔNG dùng thẳng --warning (3.62). */
.khoa-trangthai { font-size: var(--fs-sm); font-weight: 700; color: var(--text-3); text-align: right; }
.khoa-row.is-locked .khoa-trangthai { color: #96590A; }
body.dark-theme .khoa-row.is-locked .khoa-trangthai { color: #E9A23B; }
.khoa-row .btn { justify-self: end; width: 100%; }

/* ---- NẤC PHÁT HÀNH (10/08/2026) — "tính năng mới build dưới quyền super admin" ----
   Nằm CÙNG HÀNG với công tắc Khoá từ 10/08. Hai thứ vẫn trả lời hai câu khác nhau
   ("ai được thấy" vs "có đang tạm đóng không") nên phải giữ khoảng cách + căn cột
   rõ ràng; gộp hàng KHÔNG có nghĩa là để chúng dính nhau. */
.khoa-nac-nut { display: inline-flex; border: 1px solid var(--border); border-radius: var(--r-sm); overflow: hidden; }
.khoa-nac-o {
  padding: 6px 12px; font: inherit; font-size: var(--fs-sm); font-weight: 600;
  color: var(--text-2); background: var(--surface); border: 0; cursor: pointer;
  border-right: 1px solid var(--border); white-space: nowrap;
}
.khoa-nac-o:last-child { border-right: 0; }
.khoa-nac-o:hover { background: var(--surface-3); color: var(--text); }
.khoa-nac-o.dang-chon { background: var(--brand); color: #fff; font-weight: 700; }
/* Mục chưa có dòng trên Supabase — nói thẳng, đừng vẽ nấc giả rồi để bấm vào không ăn */
.khoa-nac-thieu { font-size: var(--fs-xs); color: #96590A; font-weight: 600; white-space: nowrap; }
body.dark-theme .khoa-nac-thieu { color: #E9A23B; }
/* Mục chưa phát hành: viền trái nổi màu brand để lướt mắt là thấy "cái này đang xây" */
.khoa-row.dang-xay { box-shadow: inset 3px 0 0 var(--brand); }

/* Ô lời nhắn trải hết bề ngang ở hàng dưới — chỉ hiện khi mục đang khoá. */
.khoa-nhan { grid-column: 1 / -1; display: flex; flex-direction: column; gap: 4px; margin-top: 4px; }
.khoa-nhan label { font-size: var(--fs-xs); font-weight: 700; color: var(--text-3); }
.khoa-nhan input {
  width: 100%; height: 38px; padding: 0 12px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface); color: var(--text); font: inherit; font-size: var(--fs-sm);
}
.khoa-nhan input:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-ring); }
/* Màn hẹp: một hàng không còn đủ chỗ → xuống dòng, nhưng vẫn giữ đúng thứ tự đọc. */
@media (max-width: 900px) {
  .khoa-row { grid-template-columns: minmax(0, 1fr) auto; }
  .khoa-trangthai { grid-column: 1; text-align: left; }
  .khoa-row .btn { justify-self: end; width: auto; }
}
@media (max-width: 560px) {
  .khoa-row { grid-template-columns: 1fr; }
  .khoa-trangthai { text-align: left; }
  .khoa-row .btn { justify-self: stretch; width: 100%; }
}

.usage-presets { display: flex; gap: 6px; flex-wrap: wrap; }
/* Mốc ĐANG XEM. Bỏ hai ô ngày rồi thì đây là chỉ báo duy nhất, phải đọc được ngay
   mà không cần hover hay nhớ mình vừa bấm gì. */
.usage-presets .btn.is-on {
  background: var(--brand); border-color: var(--brand); color: #fff; font-weight: 700;
}
.usage-presets .btn.is-on:hover { background: var(--brand); border-color: var(--brand); }
/* Dòng giải thích ngay dưới dải mốc — chỉ hiện khi khoảng chọn RỘNG HƠN số liệu đang có,
   tức là lúc bấm mốc khác mà biểu đồ không đổi. Im lặng khi mọi thứ bình thường. */
.usage-range-note {
  margin: 8px 0 0; font-size: var(--fs-sm); line-height: 1.5; color: var(--text-3);
}
.usage-range-note[hidden] { display: none; }

/* Biểu đồ | Top mẫu nằm ngang hàng. align-items:start để khối thấp không bị kéo cao
   theo khối cao — mỗi khối giữ đúng chiều cao nội dung của nó. */
/* align-items để MẶC ĐỊNH (stretch): hai khối luôn cao BẰNG NHAU. Dùng `start` thì
   khối biểu đồ giữ nguyên chiều cao nội dung → đáy cột trái hụt so với cột phải,
   đẻ ra một mảng trắng to (đo được 195px) — chủ tool 27/07: "phần này trống nhìn kỳ". */
.usage-grid {
  display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  gap: 12px; margin-bottom: 12px;
}
.usage-grid .usage-block { margin-bottom: 0; display: flex; flex-direction: column; }
/* Biểu đồ ĂN HẾT chiều cao còn thừa của khối thay vì cố định px → cột trái luôn đầy,
   và biểu đồ càng cao càng dễ đọc. min-height để lúc "Top" ngắn thì cột cũng không bẹp.
   Về 1 cột (≤1100px) trả lại 132px cố định, vì lúc đó cao thêm là trang dài thêm thật. */
@media (min-width: 1101px) {
  /* ☠️ `flex: 1` không có TRẦN thì biểu đồ bị cột "Top mẫu" bên phải kéo cao tuỳ ý.
     Đo 31/07 ở bề ngang thật: vùng vẽ cao 420px trong khi thanh chỉ rộng 31px →
     tỉ lệ 12,7:1, nhìn như cây kim (chủ tool: "biểu đồ kiểu gì đâu, xấu quá").
     Trần 260px đưa tỉ lệ về 7,6:1. Cao thêm nữa KHÔNG đọc ra thêm gì — chỉ kéo dài
     cùng một hình dạng. */
  .usage-grid .usage-chart { height: auto; flex: 1 1 auto; min-height: 160px; max-height: 260px; }
  /* Có trần rồi thì phần dư phải đi đâu đó: đẩy bộ chọn ngày xuống đáy để cột trái
     vẫn đầy. Không có dòng này là hở một mảng trắng dưới đáy — đúng lỗi chủ tool đã
     chê ngày 27/07 ("phần này trống nhìn kỳ"). */
  .usage-grid .usage-filter { margin-top: auto; }
}

/* Dòng "Tải về" bấm được (mở popup chi tiết) — trông như .ms-row nhưng là button */
.ms-row-btn {
  width: 100%; border: none; background: transparent; font: inherit; text-align: left;
  cursor: pointer; border-radius: var(--r-sm);
}
.ms-row-btn:hover { background: var(--surface-3); }
.ms-row-btn:hover .ms-row-more { color: var(--brand); transform: translateX(2px); }
.ms-row-more { color: var(--text-3); font-weight: 800; display: inline-block; transition: transform var(--dur) var(--ease), color var(--dur) var(--ease); }

/* Popup "Chi tiết tải về" — ô tìm + danh sách gộp theo người (27/07) */
/* Dòng giải thích vì sao lượt cũ chưa có ảnh — rỗng thì biến mất hẳn, không chừa chỗ */
.dl-note { font-size: var(--fs-xs); color: var(--text-3); margin-bottom: 10px; line-height: 1.5; }
.dl-note:empty { display: none; }
.dl-search { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.dl-search .mem-search { flex: 1 1 auto; }
.dl-hit { font-size: var(--fs-xs); color: var(--text-3); white-space: nowrap; }

/* Một người = một dòng bấm được; danh sách lượt tải của họ nằm trong .dl-per-body */
.dl-group { border-bottom: 1px solid var(--divider); }
.dl-group:last-child { border-bottom: none; }
/* Hàng người: GRID cột cố định, không phải flex (27/07). Flex thì tên dài ngắn khác
   nhau đẩy "tên tiếng Anh" và "N lượt" lệch mỗi hàng một chỗ → chủ tool gọi là rối. */
.dl-per {
  width: 100%; display: grid; align-items: center; gap: 10px;
  /* Cột cuối phải là px CỐ ĐỊNH, KHÔNG được max-content: mỗi .dl-per là một lưới riêng,
     mà "gần nhất 7 giờ trước" ngắn hơn "gần nhất 3 ngày trước" → max-content cho ra bề
     rộng khác nhau ở từng hàng, kéo lệch tất cả cột phía trước (đo được 5 mép khác nhau). */
  /* Cùng lỗi với bảng "Theo từng người": cột tên `1fr` nuốt hết chỗ dư nên tên cách
     "tên tiếng Anh" một khoảng trắng lớn. Cho cột tên và cột tên-tiếng-Anh cùng co giãn.
     Cột cuối vẫn PHẢI là px cố định (xem ghi chú ngay trên). */
  /* KHÔNG dùng `fr` ở đây: hễ có fr là cột tên nuốt sạch chỗ dư (đo 31/07: cột tên 551px
     cho một cái tên 95px → 456px trắng ngay sau tên). Đặt trần px cho từng cột thì tổng
     nhỏ hơn bề ngang popup, phần dư dồn ra RÌA PHẢI — mắt bỏ qua được, thay vì phải nhảy
     qua một khoảng trắng nằm giữa hai thông tin liền nhau. */
  grid-template-columns: 14px minmax(150px, 260px) minmax(110px, 190px) 48px 130px;
  padding: 10px 8px; border: none; background: transparent; font: inherit;
  text-align: left; cursor: pointer; border-radius: var(--r-sm);
}
.dl-per:hover { background: var(--surface-2); }
.dl-per:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.dl-per-caret {
  flex: 0 0 auto; color: var(--text-3); font-weight: 800; width: 12px;
  transition: transform var(--dur) var(--ease), color var(--dur) var(--ease);
}
.dl-per.is-open .dl-per-caret { transform: rotate(90deg); color: var(--brand); }
.dl-per-name { font-weight: 600; color: var(--text); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dl-per-en {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: var(--fs-sm); font-weight: 600; color: var(--brand);
}
/* Chip chỉ còn CON SỐ (bỏ chữ "lượt" lặp ở mọi hàng) → cho nó tròn đều, canh giữa. */
.dl-per-n {
  justify-self: start; font-size: var(--fs-xs); font-weight: 800;
  background: var(--brand-soft); color: var(--brand); border-radius: 999px;
  min-width: 26px; padding: 3px 8px; text-align: center; font-variant-numeric: tabular-nums;
}
.dl-per-when { justify-self: end; font-size: var(--fs-xs); color: var(--text-3); white-space: nowrap; }
.dl-per-body { padding: 0 8px 8px 30px; }

/* Hàng lượt tải (trong nhóm) — bỏ cột "Thành viên" vì đã nằm ở dòng người bên trên */
.dl-row {
  display: grid; grid-template-columns: minmax(0, 1fr) 110px 44px;
  gap: 12px; align-items: center;
}
/* 👁 xem "sale đã điền gì" + khối chi tiết bung ra */
.dl-eye { border: none; background: transparent; cursor: pointer; font-size: 15px; line-height: 1; padding: 4px 6px; border-radius: var(--r-sm); opacity: 0.7; }
.dl-eye:hover, .dl-eye.is-open { opacity: 1; background: var(--surface-3); }
.dl-eye-empty { color: var(--text-3); }
.dl-detail {
  margin: 2px 6px 10px; padding: 10px 12px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-md);
  display: block;
}
/* Bảng giá trị đã điền: 2 cột như cũ, nhưng nay là phần PHỤ nằm dưới ảnh (27/07) */
.dl-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 18px; }
.dl-fields.is-phu { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--divider); }
.dl-fields-head {
  grid-column: 1 / -1; font-size: var(--fs-xs); font-weight: 700;
  color: var(--text-3); text-transform: uppercase; letter-spacing: .4px;
}
/* Ảnh bản đã tải — thứ chính khi bấm 👁 */
.dl-anh { display: flex; justify-content: center; }
.dl-anh img {
  max-width: 100%; height: auto; display: block;
  border: 1px solid var(--border); border-radius: var(--r-sm); background: #fff;
}
.dl-anh-cho { font-size: var(--fs-sm); color: var(--text-3); padding: 14px 0; text-align: center; }
/* 🔑 BẮT BUỘC: `display:grid` ở trên là SELECTOR CLASS nên THẮNG `[hidden]` của trình
   duyệt (chỉ là selector thuộc tính). Thiếu dòng này thì mọi khối chi tiết luôn mở
   sẵn và bấm 👁 không đổi gì trên màn hình — đúng lỗi chủ tool báo 27/07. */
.dl-detail[hidden], .dl-per-body[hidden] { display: none; }
.dl-f { display: flex; justify-content: space-between; gap: 10px; font-size: var(--fs-sm); border-bottom: 1px solid var(--divider); padding-bottom: 4px; min-width: 0; }
.dl-f-k { color: var(--text-3); flex: 0 0 auto; }
.dl-f-v { color: var(--text); font-weight: 600; text-align: right; min-width: 0; word-break: break-word; }
@media (max-width: 640px) { .dl-fields { grid-template-columns: 1fr; } }
/* .dl-thead đã bỏ 27/07: danh sách gộp theo người thì một hàng tiêu đề chung
   không còn khớp với cấu trúc nữa (mỗi nhóm có danh sách riêng). */
.dl-row .ta-right { text-align: right; }
.dl-row {
  padding: 7px 6px; border-bottom: 1px solid var(--divider);
  font-size: var(--fs-sm); color: var(--text-2);
}
.dl-item:last-child .dl-row { border-bottom: none; }
.dl-row .dl-what { min-width: 0; word-break: break-word; color: var(--text); }
#dl-rows { max-height: 52vh; overflow: auto; }

/* ---- XEM BẢN ĐÃ TẢI: panel TRÁI, không bung xuống dưới (chủ tool 31/07) ----------
   Cũ: bấm 👁 là ảnh proposal cao ~1000px chen vào GIỮA danh sách, đẩy mọi thứ bên dưới
   đi xa và làm mất chỗ đang đọc. Nay ảnh ra một cột riêng, danh sách đứng yên. */
.dl-main { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; align-items: start; }
.dl-main.has-preview { grid-template-columns: 420px minmax(0, 1fr); }
.dl-preview {
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2); overflow: hidden;
  position: sticky; top: 0;
}
.dl-preview[hidden] { display: none; }
.dl-preview-head {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-bottom: 1px solid var(--divider);
  font-size: var(--fs-sm); background: var(--surface);
}
.dl-preview-head b { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text); }
.dl-preview-body { max-height: 52vh; overflow: auto; padding: 12px; }
.dl-preview-body .dl-anh { margin: 0 0 10px; }
.dl-preview-body .dl-anh img { width: 100%; height: auto; display: block; border-radius: var(--r-sm); }

/* Màn hẹp: quay lại xếp chồng — panel nằm TRÊN danh sách, vẫn không chen vào giữa. */
@media (max-width: 900px) {
  .dl-main.has-preview { grid-template-columns: 1fr; }
  .dl-preview { position: static; }
  .dl-preview-body { max-height: 40vh; }
}

@media (max-width: 640px) {
  .dl-row {
    grid-template-columns: 1fr; gap: 4px;
    border: 1px solid var(--border); border-radius: var(--r-md); padding: 10px 12px; margin-bottom: 8px;
  }
  .dl-row > span { display: flex; justify-content: space-between; gap: 12px; text-align: right; }
  .dl-row > span::before { content: attr(data-label); color: var(--text-3); font-weight: 600; font-size: var(--fs-xs); text-align: left; }
  .dl-row .ta-right { text-align: right; }
  .dl-per-body { padding-left: 12px; }
  .dl-search { flex-wrap: wrap; }
}

/* Màn hẹp: dải số liệu tự xuống hàng, biểu đồ/top mẫu về 1 cột, thanh lọc trải rộng */
@media (max-width: 1100px) {
  .usage-stats { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
  .usage-grid { grid-template-columns: 1fr; }
}
@media (max-width: 760px) {
  .usage-bar .online-bar { width: 100%; }
  .usage-filter { margin-left: 0; width: 100%; }
  .usage-presets { flex: 1 1 100%; }
  .usage-presets .btn { flex: 1 1 auto; }
}

/* ── ĐANG ONLINE (N3) — thanh tóm tắt (bấm → modal chi tiết) ────────── */
.online-bar {
  display: flex; align-items: center; gap: 8px 10px; flex-wrap: wrap; width: 100%;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); padding: 12px 14px; cursor: pointer;
  text-align: left; font: inherit; color: var(--text);
  transition: border-color .15s, background .15s, box-shadow .15s;
}
.online-bar:hover { border-color: var(--brand); background: var(--surface-2); box-shadow: var(--shadow-xs); }
.online-bar:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.online-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 26px; height: 24px; padding: 0 8px;
  background: var(--success-soft); color: var(--success);
  border-radius: 999px; font-size: var(--fs-md); font-weight: 800;
}
.online-bar-label { font-weight: 700; color: var(--text-2); font-size: var(--fs-sm); }
.online-breakdown { display: flex; flex-wrap: wrap; gap: 6px; min-width: 0; }
.online-chip {
  font-size: var(--fs-xs); font-weight: 700; color: var(--text-2);
  background: var(--surface-3); border-radius: 999px; padding: 3px 9px; white-space: nowrap;
}
.online-chip.on-chip-tool { background: var(--brand-soft); color: var(--brand); }
.online-bar-more { margin-left: auto; color: var(--brand); font-weight: 700; font-size: var(--fs-sm); white-space: nowrap; }
.online-hint { color: var(--danger); font-size: var(--fs-xs); display: block; margin-top: 6px; }
.online-hint:empty { display: none; }
.online-dot {
  width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto;
  background: var(--success); animation: online-pulse 2s ease-out infinite;
}
.online-dot-sm { width: 7px; height: 7px; animation: none; }
@keyframes online-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(21, 163, 74, 0.45); }
  70%  { box-shadow: 0 0 0 6px rgba(21, 163, 74, 0); }
  100% { box-shadow: 0 0 0 0 rgba(21, 163, 74, 0); }
}
@media (prefers-reduced-motion: reduce) { .online-dot { animation: none; } }
.online-list { display: flex; flex-direction: column; }
.online-item {
  display: grid; grid-template-columns: 12px minmax(0, 1fr) auto auto;
  align-items: center; gap: 10px; padding: 8px 4px;
  border-bottom: 1px solid var(--divider); font-size: var(--fs-sm);
}
.online-item:last-child { border-bottom: none; }
.online-item.is-tool .online-where { font-weight: 800; }
#online-detail-rows { max-height: 52vh; overflow: auto; }   /* 100 người vẫn cuộn gọn, header modal đứng yên */
.online-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; color: var(--text); }
.online-dept { color: var(--text-3); font-weight: 500; }
.online-where { color: var(--brand); font-weight: 700; font-size: var(--fs-xs); white-space: nowrap; }
.online-ago { color: var(--text-3); font-size: var(--fs-xs); white-space: nowrap; text-align: right; }
.online-empty { color: var(--text-3); font-size: var(--fs-sm); padding: 10px 4px 2px; }
@media (max-width: 640px) {
  .online-item { grid-template-columns: 10px minmax(0, 1fr) auto; }
  .online-where { display: none; }
}

/* ── TOP MẪU / BROCHURE (N2) — leaderboard lượt 'view' ─────────────── */
.usage-top { display: flex; flex-direction: column; }
.top-row {
  display: grid; grid-template-columns: 26px minmax(0, 1.3fr) minmax(60px, 1fr) 34px;
  align-items: center; gap: 10px; padding: 6px 2px;
  border-bottom: 1px solid var(--divider);
}
.top-row:last-child { border-bottom: none; }
.top-rank {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 6px; flex: 0 0 auto;
  background: var(--surface-3); color: var(--text-2);
  font-size: var(--fs-xs); font-weight: 800;
}
.top-rank.is-top { background: var(--brand-soft-2); color: var(--brand); }
.top-name {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-weight: 600; color: var(--text); font-size: var(--fs-sm);
  display: flex; align-items: center; gap: 8px;
}
/* Nhãn loại: gọi ĐÚNG TÊN SẢN PHẨM (Proposal / Brochure / Name Card / So sánh) —
   chủ tool 27/07. Bỏ text-transform: viết hoa toàn bộ làm tên riêng khó đọc hơn. */
.top-tag {
  flex: 0 0 auto; font-size: 11px; font-weight: 800; letter-spacing: .01em;
  padding: 2px 7px; border-radius: 5px; white-space: nowrap;
}
.top-tag-mau { background: var(--brand-soft); color: var(--brand); }          /* Proposal */
.top-tag-doc { background: var(--surface-3); color: var(--text-2); }          /* Brochure */
/* Màu chữ lấy từ bộ ĐÃ ĐO ĐẠT AA (xem ghi chú ở .btn-warn-outline), không dùng
   thẳng token --warning (đo 22/07 chỉ 3.62 trên nền sáng). */
.top-tag-nc { background: var(--warning-soft); color: #96590A; }              /* Name Card */
.top-tag-ss { background: var(--success-soft); color: var(--success); }       /* Bảng so sánh */
/* Công cụ tra cứu (Age / Quote) — không sinh ra bản vẽ nào, phải khác Proposal */
.top-tag-cc { background: var(--info-soft, var(--surface-3)); color: var(--info, var(--text-2)); }
body.dark-theme .top-tag-nc { color: #E9A23B; }
.top-barwrap { height: 8px; background: var(--surface-3); border-radius: 999px; overflow: hidden; min-width: 0; }
.top-bar { display: block; height: 100%; background: var(--brand); border-radius: 999px; }
.top-n { text-align: right; font-weight: 800; color: var(--text); font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
@media (max-width: 640px) {
  .top-row { grid-template-columns: 24px minmax(0, 1fr) 30px; }
  .top-barwrap { display: none; }
}


/* ---- TỪNG LƯỢT TÍNH TUỔI (18/08/2026) -------------------------------------
   Bảng phẳng, mới nhất trên cùng. KHÔNG gộp theo người như bảng Tải về: câu hỏi
   của chủ tool là "sale nào chạy và chạy CÁI GÌ", gộp lại là phải bấm thêm một
   lần mới thấy cái gì. Cuộn trong khung để khối không đẩy dài cả trang. */
/* Nằm trong popup (18/08) — không còn viền trên/khoảng đệm của bản nhúng trong khối. */
.uct { margin-top: 4px; }
.uct-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.uct-title { font-size: var(--fs-sm); font-weight: 700; color: var(--text); margin: 0; }
.uct-dem { font-weight: 500; color: var(--text-3); }
.uct-tim { margin-left: auto; min-width: 180px; padding: 5px 10px; font-size: var(--fs-sm);
           border: 1px solid var(--border); border-radius: var(--r-sm);
           background: var(--surface); color: var(--text); }
.uct-bang { max-height: 56vh; overflow-y: auto; }
/* Năm cột cố định px cho phần giá trị (luôn ngắn: "09/02/1990", "36", "3 giờ trước"),
   chỗ dư dồn hết cho cột tên — cùng luật đã dùng ở bảng "Theo từng người". */
.uct-row { display: grid; grid-template-columns: minmax(120px, 1fr) 108px 92px 108px 96px;
           gap: 8px; align-items: center; padding: 6px 8px; border-radius: var(--r-sm);
           font-size: var(--fs-sm); }
.uct-row + .uct-row { border-top: 1px solid var(--border); }
.uct-row.is-head { font-size: var(--fs-xs); color: var(--text-3); font-weight: 600;
                   position: sticky; top: 0; background: var(--surface); z-index: 1;
                   border-bottom: 1px solid var(--border); }
.uct-row:not(.is-head):hover { background: var(--surface-2); }
.uct-ten { font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.uct-vai { font-size: var(--fs-xs); color: var(--text-3); font-weight: 500; margin-left: 5px; }
.uct-num { font-variant-numeric: tabular-nums; color: var(--text-2); }
.uct-bh { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--text); }
/* Sắp nhảy bậc phí trong 30 ngày — sale cần chốt trước mốc đó (cùng luật màu với
   ô "Ngày tăng tuổi" trong chính công cụ Tính tuổi). */
.uct-gan { color: #8a5a00; font-weight: 600; }
.dark-theme .uct-gan { color: #ffce7a; }
.uct-luc { color: var(--text-3); text-align: right; }
.uct-trong { font-size: var(--fs-sm); color: var(--text-3); margin: 6px 2px; }
@media (max-width: 760px) {
  .uct-row { grid-template-columns: 1fr 96px 72px; }
  .uct-row > .uct-ngaytang, .uct-row > .uct-luc { display: none; }
}
