:root {
  --bg: #f5f6f8;
  --panel: #ffffff;
  --border: #e3e6ec;
  --text: #1c2230;
  --text-muted: #6b7280;
  --accent: #6b7fd7;
  --accent-2: #4fb0a5;
  --good: #2f9e6e;
  --warn: #c98a1f;
  --bad: #d0554a;
  --sidebar-bg: #171b2b;
  --sidebar-text: #c7cbe0;
  --sidebar-active: #2a3050;
  --radius: 10px;
  --shadow: 0 1px 2px rgba(20,22,40,0.06), 0 1px 8px rgba(20,22,40,0.04);
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
}

.app-shell { display: flex; min-height: 100vh; }

.sidebar {
  width: 248px;
  flex: none;
  background: var(--sidebar-bg);
  color: var(--sidebar-text);
  display: flex;
  flex-direction: column;
  padding: 18px 12px;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}
/* bản 98: nút hamburger (topbar) + lớp phủ nền tối sau sidebar - CHỈ dùng trên mobile, ẩn mặc định
   ở đây (PC/tablet rộng không có 2 thứ này). Xem media query mobile bên dưới cho phần "hiện ra". */
.menu-toggle, .sidebar-backdrop { display: none; }
.brand {
  display: flex; align-items: center; gap: 10px; padding: 6px 8px 18px;
  text-decoration: none; cursor: pointer; border-radius: 8px;
  transition: opacity .15s ease;
}
/* bản 97: khối brand giờ là link về "/overview" (Tổng quan chung) - thêm hover nhe de bao cho
   Amont biet bam duoc, khong doi bo cuc/mau sac san co cua brand-title/brand-sub. */
.brand:hover { opacity: 0.8; }
.brand-mark {
  width: 36px; height: 36px; border-radius: 8px;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: #fff; display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 13px;
  overflow: hidden; /* bản 77: bo tron dung goc khi anh logo (nen trang, vuong) phu kin ben trong */
}
/* bản 77: logo that (public/favicon.png) thay cho chu "ATK" cu - phu kin toan bo khung co san,
   khong keo meo hinh (object-fit: cover, anh goc da la hinh vuong nen thuc te khong bi cat gi). */
.brand-mark img { width: 100%; height: 100%; object-fit: cover; display: block; }
.brand-title { font-weight: 700; font-size: 13.5px; color: #fff; }
.brand-sub { font-size: 11px; color: #9096b5; margin-top: 1px; }

.nav-group { margin-bottom: 14px; }
/* bản 91: Amont báo "cần đường kẻ mờ (divider) hoặc khoảng cách rõ ràng giữa các khối sàn" (Tổng
   quan/Shopee/TikTok Shop/Hệ thống trong sidebar) để tránh nhầm đang thao tác ở sàn nào. Chỉ áp
   dụng border-top cho các khối SAU khối đầu tiên (:not(:first-child), tương đương "* + *" dùng
   selector con) - khối đầu tiên (Tổng quan) không cần viền phía trên nó (không có gì phía trên để
   ngăn cách). Dùng lại ĐÚNG màu #262c47 đã có sẵn ở .sidebar-footer (viền phân cách cuối sidebar) -
   giữ nhất quán 1 màu viền duy nhất trong toàn bộ sidebar, không thêm biến CSS mới. */
.nav-group:not(:first-child) { padding-top: 14px; border-top: 1px solid #262c47; }
.nav-group-label {
  display: flex; align-items: center; gap: 6px;
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
  color: #767ca0; padding: 6px 10px 4px;
}
/* bản 91: icon nhận diện thương hiệu (SHOPEE_NAV_ICON/TIKTOK_NAV_ICON - lib/render.js), CHỈ đặt
   trước TÊN NHÓM (Amont chốt qua AskUserQuestion, không lặp lại ở từng mục menu con). flex: none
   để icon không bị co lại khi tên nhóm dài; svg display:block để tránh khoảng trắng thừa dưới ảnh
   (hành vi mặc định của <svg> giống <img>, vốn là inline). */
.nav-group-icon { flex: none; display: inline-flex; }
.nav-group-icon svg { display: block; }
.nav-link {
  display: block; padding: 7px 10px; border-radius: 7px;
  color: var(--sidebar-text); text-decoration: none; font-size: 13.5px;
  margin-bottom: 1px;
}
.nav-link:hover { background: #1f2540; color: #fff; }
.nav-link.active { background: var(--sidebar-active); color: #fff; font-weight: 600; }

.sidebar-footer { margin-top: auto; padding: 10px 8px 0; border-top: 1px solid #262c47; }
.version-tag { font-size: 10.5px; color: #5a6088; padding: 8px 2px 2px; letter-spacing: .02em; }
.user-chip { display: flex; align-items: center; justify-content: space-between; padding: 8px 2px; font-size: 12.5px; }
.user-email { color: #dfe1f0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 140px; }
.role-badge { font-size: 10px; padding: 2px 6px; border-radius: 999px; background: #2a3050; color: #b9c0ea; }
.role-badge.role-admin { background: #3b2f57; color: #d8c6ff; }
.btn-link { background: none; border: none; color: #9096b5; font-size: 12.5px; cursor: pointer; padding: 2px; }
.btn-link:hover { color: #fff; }

.main { flex: 1; min-width: 0; }
.topbar {
  background: var(--panel); border-bottom: 1px solid var(--border);
  padding: 18px 28px; position: sticky; top: 0; z-index: 5;
  display: flex; align-items: center; gap: 12px;
}
.topbar h1 { margin: 0; font-size: 19px; }
/* bản 48: Amont phản ánh "vẫn đang còn trống nửa trang" - trước đây max-width: 1280px CHẶN CỨNG
   vùng nội dung chính lại 1280px dù màn hình rộng hơn nhiều (vd 1920px, sau khi trừ 248px sidebar
   còn ~1672px khả dụng) -> để trống 1 dải trắng bên phải không dùng tới, trong khi bảng dữ liệu
   (nhiều cột: Đơn hàng, Sản phẩm...) và stat-grid đều có thể tận dụng thêm chỗ để hiện nhiều hơn,
   đỡ phải cuộn ngang. Bỏ hẳn max-width - nội dung giờ giãn hết chiều rộng còn lại sau sidebar
   (.main đã có flex: 1 từ trước) trên MỌI kích thước màn hình, không giới hạn cứng nữa. */
.content { padding: 24px 28px 60px; position: relative; }

/* bản 95: hiệu ứng "đang tải" (skeleton/shimmer) khi bấm lọc/tìm kiếm/sắp xếp/phân trang - Amont báo
   "đứng hình trắng trang" trong lúc chờ server render trang mới (app KHÔNG dùng AJAX/SPA, mỗi lần
   lọc là 1 lần điều hướng GET thật - xem initPageLoadingOverlay()/triggerPageLoadingOverlay() ở
   public/app.js). Dùng CHUNG 1 lớp phủ GENERIC trên NGUYÊN khối .content (không dựng skeleton riêng
   theo hình dạng từng loại nội dung - thẻ số liệu/biểu đồ/bảng...) để áp dụng đồng loạt được cho MỌI
   trang mà không cần biết trước hình dạng cụ thể của từng trang (Amont chốt qua AskUserQuestion).
   `position: relative` ở .content phía trên để 2 lớp phủ dưới đây (position: absolute) phủ đúng
   kín NGUYÊN khối .content của trang hiện tại, không lan ra ngoài. `pointer-events: none` để tránh
   bấm/submit lại lần 2 trong lúc đang chờ điều hướng (JS đã tự gỡ lớp phủ sau tối đa 8 giây dù trang
   không điều hướng đi được, xem safety timer trong triggerPageLoadingOverlay() - không lo bị kẹt). */
.content.is-navigating { pointer-events: none; user-select: none; }
.content.is-navigating::after {
  content: ''; position: absolute; inset: 0; z-index: 60;
  background: rgba(245,246,248,.55); backdrop-filter: blur(1px);
}
.content.is-navigating::before {
  content: ''; position: absolute; inset: 0; z-index: 61;
  background: linear-gradient(100deg, transparent 30%, rgba(255,255,255,.7) 45%, rgba(255,255,255,.7) 55%, transparent 70%);
  background-size: 200% 100%;
  animation: atk-loading-shimmer 1.15s ease-in-out infinite;
}
@keyframes atk-loading-shimmer {
  0% { background-position: 140% 0; }
  100% { background-position: -40% 0; }
}
/* Amont/thiết bị bật "giảm chuyển động" (accessibility) - vẫn giữ lớp phủ mờ báo hiệu đang tải,
   chỉ bỏ hiệu ứng vệt sáng CHẠY (chuyển động liên tục) để tránh khó chịu/chóng mặt. */
@media (prefers-reduced-motion: reduce) {
  .content.is-navigating::before { animation: none; background-position: 50% 0; }
}

.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px; margin-bottom: 22px; }
.stat-card { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px 16px; box-shadow: var(--shadow); }
.stat-label { font-size: 12px; color: var(--text-muted); margin-bottom: 6px; }
.stat-value { font-size: 21px; font-weight: 700; letter-spacing: -0.01em; }
.stat-sub { font-size: 11.5px; color: var(--text-muted); margin-top: 4px; }
.stat-card.tone-good .stat-value { color: var(--good); }
.stat-card.tone-bad .stat-value { color: var(--bad); }
/* bản 90: mức cảnh báo THỨ 3 (vàng) cho "Tỉ lệ hoàn" cao bất thường - Amont chốt 2 ngưỡng
   (≥10% -> đỏ/tone-bad có sẵn, ≥5% -> vàng/tone-warn mới) qua AskUserQuestion. Dùng --warn co san
   trong :root (truoc gio chua co class stat-card nao dung toi). */
.stat-card.tone-warn .stat-value { color: var(--warn); }

.panel { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); margin-bottom: 20px; }
.panel-head { display: flex; align-items: center; justify-content: space-between; padding: 14px 18px; border-bottom: 1px solid var(--border); }
.panel-head h2 { margin: 0; font-size: 14.5px; }
.panel-body { padding: 16px 18px; }

.table-wrap { overflow-x: auto; }
/* table-layout bat dau la auto (co dinh dang browser tu can theo noi dung) - app.js do lai
   chieu rong tung cot sau khi trang tai xong roi doi sang fixed + colgroup, de cot co the
   keo gian tay ma khong bi giat layout luc chuyen doi. */
.data-table { width: 100%; border-collapse: collapse; font-size: 13px; }
/* bản 84: Amont báo "cân lại các tiêu đề với nội dung cột thẳng nhau" (tiêu đề cột lệch so với
   dữ liệu bên dưới) ở trang Affiliate (TikTok Shop). Đọc lib/render.js's table() + CSS này thì thấy
   nguyên nhân THẬT: <th> đang có padding-right 14px trong khi <td> chỉ có 10px (lệch 4px) - phần dư
   4px đó là do "tay kéo giãn cột" (.col-resize-handle, xem bên dưới) được thêm SAU này, cần chỗ để
   không đè lên chữ. Với CỘT canh phải (align:'right' - hầu hết là số: GMV/Số đơn/Chi phí/ROI/Ads
   Spend), chữ tiêu đề dồn sát theo padding-right của <th> còn số liệu dồn sát theo padding-right của
   <td> -> lệch đúng 4px, nhìn thấy rõ tiêu đề "trôi" sang trái so với cột số bên dưới. Cột canh trái
   không bị ảnh hưởng (padding-left 2 bên vốn đã bằng nhau, đều 10px). SỬA: cho <th> dùng ĐÚNG
   padding 2 bên như <td> (10px) - tay kéo giãn cột (rộng 7px, dán sát mép phải) vẫn đủ chỗ nằm gọn
   trong 10px padding-right mới, không đè lên chữ. */
.data-table th { text-align: left; font-weight: 600; color: var(--text-muted); font-size: 11.5px; text-transform: uppercase; letter-spacing: .03em; padding: 8px 10px; border-bottom: 1px solid var(--border); white-space: nowrap; position: relative; }
.data-table td { padding: 9px 10px; border-bottom: 1px solid #eef0f4; white-space: nowrap; }
/* Cot mac dinh gioi han chieu rong toi da - tranh 1 cot chu dai (vd tieu de video) keo ca
   bang trai rong man hinh, day cac cot khac ra ngoai/mat can. Chu bi cat "…", xem full qua
   title tooltip (app.js tu gan) hoac keo rong cot ra. */
.data-table th, .data-table td { max-width: 340px; overflow: hidden; text-overflow: ellipsis; }
.data-table tr:hover td { background: #fafbfe; }
.ta-right { text-align: right; }

.table-filter-bar { margin-bottom: 8px; }
.table-filter-input {
  border: 1px solid var(--border); border-radius: 7px; padding: 6px 10px; font-size: 12.5px;
  background: #fff; color: var(--text); width: 260px; max-width: 100%;
}
.th-sortable { cursor: pointer; user-select: none; }
.th-sortable:hover { color: var(--text); }
/* bản 78: Amont báo tiêu đề cột bảng (Mã đơn/Ngày đặt/...) đang hiện MÀU XANH giống link - do
   lib/render.js bọc chữ tiêu đề cột có thể sắp xếp trong the <a href="..."> (chuyển trang qua URL
   ?sort=...), mà trình duyệt tự tô màu xanh mặc định cho <a> chưa có CSS riêng, đè mất màu xám
   var(--text-muted) đã đặt sẵn ở `.data-table th`. Amont chốt: xanh CHỈ dùng cho link thật, tiêu đề
   cột phải đen/xám như chữ thường -> cho <a> này ăn theo đúng màu chữ cha (.th-sortable, đang xám;
   hover sang đen nhờ dòng ngay trên) thay vì màu xanh mặc định của trình duyệt. */
.th-sortable a { color: inherit; text-decoration: none; }
.sort-arrow { display: inline-block; width: 10px; margin-left: 3px; opacity: .35; }
/* bản 84 (bổ sung): với cột canh phải, lib/render.js's table() giờ đặt mũi tên TRƯỚC chữ tiêu đề
   (để chữ mới là phần chạm sát mép phải, thẳng hàng với số liệu - xem giải thích đầy đủ ở
   render.js) - margin-left 3px phía trên vì vậy hết tác dụng (không còn đứng giữa chữ và mũi tên
   nữa, mà đứng trước mũi tên/đầu ô). Đổi sang margin-right 3px CHỈ cho trường hợp này để giữ đúng
   khoảng cách nhỏ giữa mũi tên và chữ (giờ mũi tên đứng trước, cần margin bên PHẢI của nó). */
.ta-right.th-sortable .sort-arrow { margin-left: 0; margin-right: 3px; }
.th-sortable.sorted-asc .sort-arrow::after { content: '▲'; opacity: 1; }
.th-sortable.sorted-desc .sort-arrow::after { content: '▼'; opacity: 1; }
.th-sortable:not(.sorted-asc):not(.sorted-desc) .sort-arrow::after { content: '↕'; }

/* Tay keo gian/thu nho cot - app.js gan 1 the span nay vao cuoi moi <th>. */
.col-resize-handle {
  position: absolute; top: 0; right: 0; bottom: 0; width: 7px;
  cursor: col-resize; user-select: none; touch-action: none;
  border-right: 2px solid transparent;
}
.col-resize-handle:hover, .col-resize-handle.is-resizing { border-right-color: var(--accent); }
body.col-resizing { cursor: col-resize !important; }
body.col-resizing * { user-select: none !important; }

.empty-state { color: var(--text-muted); font-size: 13px; padding: 18px 4px; }

.chart-label { font-size: 12px; fill: var(--text-muted); }
.chart-value { font-size: 12px; fill: var(--text); font-weight: 600; }
.bar-chart { display: block; }

.donut-wrap { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
.donut-legend { font-size: 13px; }
.legend-row { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.legend-dot { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }

/* bản 43: stat-card dạng checkbox (toggleStatCard() - lib/render.js) - tick/bỏ tick ẩn/hiện biểu
   đồ tương ứng, viền + nền phủ nhạt theo --chart-color khi đang tick (khác 3 thẻ statCard() thường
   ở bên cạnh không có ô tick). */
.toggle-stat-card {
  position: relative; overflow: hidden; cursor: pointer; padding-left: 42px; display: block; user-select: none;
}
.toggle-stat-card input[type="checkbox"] { position: absolute; opacity: 0; width: 0; height: 0; }
.toggle-stat-card .toggle-check {
  position: absolute; left: 16px; top: 18px; width: 17px; height: 17px; border-radius: 4px;
  border: 1.5px solid var(--border); background: #fff; box-sizing: border-box;
}
.toggle-stat-card.is-checked::before {
  content: ''; position: absolute; inset: 0; background: var(--chart-color, var(--accent)); opacity: .07; pointer-events: none;
}
.toggle-stat-card.is-checked { border-color: var(--chart-color, var(--accent)); }
.toggle-stat-card.is-checked .toggle-check { background: var(--chart-color, var(--accent)); border-color: var(--chart-color, var(--accent)); }
.toggle-stat-card.is-checked .toggle-check::after {
  content: ''; position: absolute; left: 5px; top: 1px; width: 5px; height: 9px;
  border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.toggle-stat-card:focus-within .toggle-check { outline: 2px solid var(--chart-color, var(--accent)); outline-offset: 1px; }

/* bản 43: bieu do duong theo ngay (lineChart() - lib/render.js) - 2 the xep canh nhau (small
   multiples: Chi phi/Don hang RIENG, khong dung 1 bieu do 2 truc Y - xem ghi chu day du o
   lib/render.js's lineChart()). */
.line-chart-grid { display: grid; grid-template-columns: 1fr; gap: 16px; margin-top: 14px; }
@media (min-width: 880px) { .line-chart-grid { grid-template-columns: 1fr 1fr; } }
.line-chart-card { border: 1px solid var(--border); border-radius: var(--radius); padding: 14px 14px 4px; }
.line-chart-card-title { font-size: 12.5px; font-weight: 600; color: var(--text); margin-bottom: 4px; }
.line-chart-wrap { position: relative; }
.line-chart-svg { display: block; }
.chart-gridline { stroke: var(--border); stroke-width: 1; }
.chart-axis-label { font-size: 10px; fill: var(--text-muted); }
.chart-area { fill: var(--chart-color, var(--accent)); opacity: .1; stroke: none; }
.chart-line { fill: none; stroke: var(--chart-color, var(--accent)); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.chart-end-dot { fill: var(--chart-color, var(--accent)); stroke: #fff; stroke-width: 2; }
.chart-end-label { font-size: 11.5px; font-weight: 700; fill: var(--text); }
.chart-crosshair { stroke: var(--border); stroke-width: 1; }
.chart-hover-dot { fill: var(--chart-color, var(--accent)); stroke: #fff; stroke-width: 2; }
.chart-tooltip-bg { fill: #1c2230; }
.chart-tooltip-date { fill: #c7cbe0; font-size: 10px; }
.chart-tooltip-value { fill: #fff; font-size: 12px; font-weight: 700; }
.chart-hit-area { cursor: crosshair; }

.tier-badge { font-size: 11px; padding: 3px 8px; border-radius: 999px; font-weight: 600; }
.tier-top { background: #dff3e8; color: #1f7a4d; }
.tier-good { background: #e4f0e0; color: #3f7a2f; }
.tier-normal { background: #eef0f4; color: #555b6e; }
.tier-warning { background: #fdf1de; color: #a2650f; }
.tier-low { background: #fbe4e1; color: #a83a2e; }

.tag-badge { font-size: 11px; padding: 3px 8px; border-radius: 999px; font-weight: 600; }
.tag-good { background: #dff3e8; color: #1f7a4d; }
.tag-normal { background: #eef0f4; color: #555b6e; }
.tag-low { background: #fbe4e1; color: #a83a2e; }

.filters { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; align-items: flex-end; }
.field { display: flex; flex-direction: column; gap: 4px; font-size: 12.5px; }
.field label { color: var(--text-muted); }

/* Bo loc trang thai kieu checkbox (chon 1 hoac nhieu o) - dung o cac trang Don hang. */
.checkbox-group { display: flex; flex-wrap: wrap; gap: 6px; max-width: 520px; }
.checkbox-chip {
  display: inline-flex; align-items: center; gap: 5px; font-size: 12.5px; color: var(--text);
  border: 1px solid var(--border); border-radius: 999px; padding: 4px 10px 4px 8px;
  background: #fff; cursor: pointer; user-select: none; white-space: nowrap;
}
.checkbox-chip:has(input:checked), .checkbox-chip.chip-checked { border-color: var(--accent); background: rgba(107,127,215,.08); color: var(--accent); }
.checkbox-chip input { margin: 0; }

/* bản 28: nut "Đồng bộ ngay" TikTok Shop API - 2 lua chon pham vi (Toan thoi gian / Chon khoang
   thoi gian), o ngay ban dau chi hien khi chon "Chon khoang thoi gian" - dung :has() (giong
   .checkbox-chip o tren, da dung tu truoc) thay vi them JS moi cho don gian. */
.sync-scope-choices { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
.sync-range-fields { display: none; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.sync-scope-form:has(input[name="scope"][value="range"]:checked) .sync-range-fields { display: flex; }

/* Dong tong o duoi bang (vd trang Don hang: tong so don + tong tien theo bo loc, tinh tren
   toan bo ket qua chu khong chi 200 dong dang hien). */
.table-total-bar {
  margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--border);
  font-size: 13px; color: var(--text-muted);
}
.table-total-bar strong { color: var(--text); font-weight: 700; }

/* bản 92: Amont báo cụm bộ lọc ngày + nút chọn nhanh "bị đặt lơ lửng... không chung một khung
   chứa (Container)" - bọc NGUYÊN form .data-toggle-bar trong div này (xem dateRangeFilterBar(),
   lib/render.js) để có 1 nền/viền/bo góc THỐNG NHẤT cho toàn bộ cụm (2 ô ngày, nút chọn nhanh,
   checkbox Huỷ/Hoàn, nút Lọc/Xoá lọc, icon tooltip) thay vì để rời rạc trực tiếp trên nền trang.
   Dùng lại ĐÚNG bộ token màu/bóng đổ đã có sẵn (--panel/--border/--radius/--shadow, giống
   .panel/.stat-card) để nhất quán với phần còn lại của giao diện, không tạo màu mới. */
.date-filter-card {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 14px 16px; margin-bottom: 16px;
}

/* Cong tac "Khong tinh don Huy/Hoan" (excludeCancelledToggle o lib/render.js) - dat dau trang
   Overview/San pham, submit lai qua GET ngay khi tick (xem initAutoSubmitCheckboxes).
   bản 92: bỏ margin-bottom cũ (16px) - giờ nằm bên TRONG .date-filter-card ở trên, khoảng cách với
   nội dung phía dưới đã do padding/margin của chính .date-filter-card đảm nhận, để margin-bottom cũ
   ở đây sẽ tạo khoảng trống thừa BÊN TRONG khung (dưới hàng nút, phía trên viền dưới của card). */
.data-toggle-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
/* bản 90: KHÔNG còn dùng để in đoạn chú thích dài trực tiếp trên trang nữa (đã chuyển vào
   .help-tooltip-box, xem bên dưới) - giữ lại class này phòng khi có chỗ khác còn tham chiếu, không
   ai dùng thì cũng không hại gì (dead CSS, không hiện ra sai chỗ nào). */
.data-toggle-note { font-size: 12px; color: var(--text-muted); max-width: 640px; }

/* bản 90: icon "?" trợ giúp dạng tooltip (helpTooltip() - lib/render.js), thay cho đoạn chú thích
   dài .data-toggle-note cũ luôn hiện sẵn trên trang - Amont báo đoạn cũ "chiếm nhiều diện tích đầu
   trang". Dùng CSS-only :hover/:focus-within (KHÔNG JS) - `tabindex="0"` trên .help-tooltip để bàn
   phím (Tab) cũng mở được, không chỉ chuột. */
.help-tooltip { position: relative; display: inline-flex; margin-left: 4px; vertical-align: middle; }
.help-tooltip-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: 50%;
  background: #eef0f4; color: var(--text-muted);
  font-size: 11.5px; font-weight: 700; cursor: help; user-select: none;
}
.help-tooltip:hover .help-tooltip-icon, .help-tooltip:focus-within .help-tooltip-icon,
.help-tooltip:focus .help-tooltip-icon { background: var(--accent); color: #fff; }
.help-tooltip-box {
  position: absolute; z-index: 20; left: 0; top: calc(100% + 8px);
  width: 360px; max-width: min(360px, 80vw);
  background: #1c2230; color: #e4e6f0; font-size: 12px; line-height: 1.5;
  border-radius: 8px; padding: 10px 12px; box-shadow: var(--shadow);
  opacity: 0; visibility: hidden; transform: translateY(-4px);
  transition: opacity .12s ease, transform .12s ease;
  pointer-events: none;
}
.help-tooltip:hover .help-tooltip-box, .help-tooltip:focus-within .help-tooltip-box,
.help-tooltip:focus .help-tooltip-box { opacity: 1; visibility: visible; transform: translateY(0); }

/* bản 93: bộ chọn khoảng ngày kiểu gộp gọn (dateRangeFilterBar()/initDateRangePicker() - thay hẳn
   2 <input type="date"> lộ + hàng nút ngang của bản 90) - Amont gửi ảnh mẫu 1 ô hiển thị "từ - đến"
   + icon lịch, bấm mở dropdown gồm cột trái nút chọn nhanh DỌC + bên phải lịch 2 tháng. Dùng lại
   ĐÚNG token màu/bo góc/bóng đổ đã có sẵn (--panel/--border/--radius/--shadow/--accent) để nhất
   quán với phần còn lại của giao diện, không thêm màu thương hiệu riêng như ảnh mẫu gốc (ảnh mẫu
   là giao diện của Ads Manager, không phải app này). */
.date-range-picker { position: relative; }
.date-range-trigger-group {
  display: inline-flex; align-items: stretch; border: 1px solid var(--border); border-radius: 7px;
  background: #fff; overflow: hidden;
}
.date-range-trigger {
  display: inline-flex; align-items: center; gap: 7px; background: none; border: none;
  padding: 7px 10px; font-size: 13px; color: var(--text); cursor: pointer; white-space: nowrap;
}
.date-range-trigger:hover { background: #f7f8fb; }
.date-range-trigger svg { flex: none; color: var(--text-muted); }
.date-range-clear {
  display: inline-flex; align-items: center; justify-content: center; width: 30px;
  border-left: 1px solid var(--border); color: var(--text-muted); font-size: 15px; line-height: 1;
  text-decoration: none; cursor: pointer;
}
.date-range-clear:hover { background: #f7f8fb; color: var(--text); }

/* Khung dropdown - dùng thuộc tính HTML `hidden` (JS bật/tắt qua `.hidden = true/false`) để
   ẩn/hiện. bản 93 hotfix (LỖI THẬT Amont báo: dropdown tự hiện sẵn dù chưa bấm mở) - trước đây có
   đặt thẳng `display: flex` trên chính class `.date-range-popover`: CSS của TRANG (author) luôn
   thắng CSS MẶC ĐỊNH của trình duyệt cho thuộc tính `hidden` (`display: none`), dù độ ưu tiên
   (specificity) ngang nhau, vì stylesheet của trang có "nguồn gốc" (origin) được ưu tiên cao hơn
   stylesheet mặc định trình duyệt - kết quả là `hidden` bị vô hiệu hoàn toàn, dropdown LUÔN hiện.
   Sửa: chỉ khai báo `display: flex` khi KHÔNG có `hidden` (`:not([hidden])`) - khi có `hidden` thì
   không còn khai báo `display` nào của trang đè lên `display: none` mặc định nữa. */
.date-range-popover {
  position: absolute; z-index: 25; top: calc(100% + 6px); left: 0;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 10px; gap: 4px;
}
.date-range-popover:not([hidden]) { display: flex; }
.date-range-presets {
  display: flex; flex-direction: column; gap: 2px; min-width: 128px; flex: none;
  padding-right: 10px; margin-right: 6px; border-right: 1px solid var(--border);
}
.date-range-preset-btn {
  background: none; border: none; text-align: left; padding: 7px 8px; border-radius: 6px;
  font-size: 12.5px; color: var(--text); cursor: pointer; white-space: nowrap;
}
.date-range-preset-btn:hover { background: #f0f1f5; }

.date-range-calendars { display: flex; flex-direction: column; gap: 6px; }
.cal-nav { display: flex; align-items: center; gap: 2px; margin-bottom: 2px; }
.cal-nav-spacer { flex: 1; }
.cal-nav-btn {
  background: none; border: none; width: 24px; height: 24px; border-radius: 6px;
  color: var(--text-muted); font-size: 13px; cursor: pointer; display: inline-flex;
  align-items: center; justify-content: center;
}
.cal-nav-btn:hover { background: #f0f1f5; color: var(--text); }
.cal-grids { display: flex; gap: 18px; }
.cal-month { display: flex; flex-direction: column; min-width: 208px; }
.cal-month-title { text-align: center; font-size: 12.5px; font-weight: 600; color: var(--text); margin-bottom: 6px; }
.cal-weekdays {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; margin-bottom: 2px;
  font-size: 11px; color: var(--text-muted); text-align: center;
}
.cal-days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cal-day {
  background: none; border: none; border-radius: 6px; padding: 0; height: 28px;
  font-size: 12.5px; color: var(--text); cursor: pointer;
}
.cal-day:hover { background: #f0f1f5; }
.cal-day.other-month { color: #c3c6d4; }
.cal-day.is-today { box-shadow: inset 0 0 0 1px var(--accent); }
.cal-day.is-in-range, .cal-day.is-hover-preview { background: rgba(107,127,215,.12); border-radius: 0; }
.cal-day.is-range-start, .cal-day.is-range-end {
  background: var(--accent); color: #fff; font-weight: 700;
}
.cal-day.is-range-start.is-range-end { border-radius: 6px; }
.cal-day.is-range-start:not(.is-range-end) { border-radius: 6px 0 0 6px; }
.cal-day.is-range-end:not(.is-range-start) { border-radius: 0 6px 6px 0; }
/* bản 93 hotfix: preview MỜ khi mới chọn ngày đầu, đang rê chuột qua ô khác (xem dayClasses() và
   listener mouseover trên calendarsWrap trong app.js) - ô đang rê TỚI tô đậm hơn is-in-range 1 chút
   để phân biệt rõ "đây là điểm SẼ dừng nếu bấm", nhưng vẫn nhạt hơn hẳn is-range-start/is-range-end
   THẬT (chưa bấm/chưa xác nhận nên chưa dùng màu --accent đặc như ngày đã chọn thật). */
.cal-day.is-hover-start, .cal-day.is-hover-end { background: rgba(107,127,215,.32); color: var(--text); font-weight: 600; }
.cal-day.is-hover-start { border-radius: 6px 0 0 6px; }
.cal-day.is-hover-end { border-radius: 0 6px 6px 0; }

/* Thanh chon so dong/trang duoi moi bang dai (table() tu render, xem PAGE_SIZE_OPTIONS). */
.table-pagination-bar {
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px;
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); font-size: 12.5px;
}
.page-size-label { display: flex; align-items: center; gap: 6px; color: var(--text-muted); }
.page-size-select {
  border: 1px solid var(--border); border-radius: 6px; padding: 3px 6px; font-size: 12.5px;
  background: #fff; color: var(--text);
}
.page-nav { display: flex; align-items: center; gap: 8px; }
.page-nav .btn { padding: 4px 10px; font-size: 12.5px; }
.page-nav .btn:disabled { opacity: .4; cursor: not-allowed; }
.page-info { color: var(--text-muted); min-width: 120px; text-align: center; }
.field input, .field select {
  border: 1px solid var(--border); border-radius: 7px; padding: 7px 9px; font-size: 13px; background: #fff; color: var(--text);
}
.btn {
  background: var(--accent); color: #fff; border: none; border-radius: 7px;
  padding: 8px 14px; font-size: 13px; font-weight: 600; cursor: pointer;
}
.btn:hover { filter: brightness(0.95); }
.btn.secondary { background: #eef0f4; color: var(--text); }
/* bản 86: nut "Xoá sạch dữ liệu này" (trang Nhập dữ liệu) - tô ĐỎ (dùng var(--bad) co san) de
   khong lan voi cac nut thuong khac tren trang, giup Amont nhan biet ngay day la hanh dong KHONG
   THE HOAN TAC truoc khi bam. */
.btn.danger { background: var(--bad); color: #fff; }

.pipeline-note { font-size: 12.5px; color: var(--text-muted); margin-top: 10px; line-height: 1.5; }

.breadcrumb { font-size: 12.5px; color: var(--text-muted); margin-bottom: 10px; }
.breadcrumb a { color: var(--accent); text-decoration: none; }

/* bản 65: thanh chuyển tab "Product GMV Max" / "LIVE GMV Max" trên trang GMV Max TikTok
   (gmvMaxTabBar() trong routes/tiktok.js) - mô phỏng đúng 2 tab của TikTok Ads Manager thật. */
.subtab-bar { display: flex; gap: 4px; margin-bottom: 16px; border-bottom: 1px solid var(--border); }
.subtab-link {
  padding: 8px 14px; font-size: 13px; font-weight: 600; color: var(--text-muted);
  text-decoration: none; border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.subtab-link:hover { color: var(--text); }
.subtab-link.active { color: var(--accent); border-bottom-color: var(--accent); }

.callout { background: #f3f5fb; border: 1px solid #dfe3f2; border-radius: 8px; padding: 12px 14px; font-size: 12.5px; color: #40456a; margin-bottom: 16px; }
/* bản 99: Amont báo các khối ".callout" (giải thích/nguồn số liệu, rải rác nhiều trang Shopee/
   TikTok Shop) làm rối giao diện - thu gọn thành 1 nút nhỏ ".callout-toggle" bấm mới hiện, JS chèn
   nút này ngay TRƯỚC mỗi ".callout" lúc tải trang (initCallouts(), public/app.js) - không sửa gì ở
   18 chỗ tạo ra ".callout" trong routes/tiktok.js, routes/shopee.js. ".callout-collapsed" ẩn hẳn
   (display:none, KHÔNG dùng max-height vì nội dung dài ngắn khác nhau nhiều chỗ) - JS gỡ class này
   khi bấm nút, thêm lại khi bấm nút lần nữa. Nếu JS lỗi/tắt thì callout vẫn hiện đủ như cũ (không
   mất thông tin, chỉ mất khả năng thu gọn) vì class "callout-collapsed" chỉ được JS thêm vào lúc
   chạy, không có sẵn trong HTML gốc từ server. */
.callout-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  background: #eef0f4; border: 1px solid var(--border); color: var(--text-muted);
  font-size: 12px; font-weight: 600; padding: 6px 12px; border-radius: 999px;
  cursor: pointer; margin-bottom: 10px;
}
.callout-toggle:hover { background: #e4e7ee; color: var(--text); }
.callout.callout-collapsed { display: none; }

/* Trang dang nhap */
.auth-body { display: flex; align-items: center; justify-content: center; min-height: 100vh; background: var(--sidebar-bg); }
.auth-card { background: #fff; border-radius: 14px; padding: 32px 30px; width: 340px; max-width: 90vw; box-shadow: 0 20px 60px rgba(0,0,0,0.35); }
.auth-title { font-size: 17px; text-align: center; margin: 0 0 18px; }
.auth-form .field { margin-bottom: 12px; width: 100%; }
.auth-form input { width: 100%; }
.auth-error { background: #fbe4e1; color: #a83a2e; font-size: 12.5px; padding: 8px 10px; border-radius: 7px; margin-bottom: 12px; }
.auth-hint { font-size: 11.5px; color: var(--text-muted); text-align: center; margin-top: 14px; line-height: 1.5; }

.upload-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
/* bản 98: thay kiểu "xếp chồng" cũ (sidebar full danh sách đẩy nội dung xuống, xem giải thích đầy
   đủ ở layout(), lib/render.js) bằng menu ẩn/hiện (off-canvas) chuẩn cho mobile - sidebar mặc định
   trượt ra NGOÀI màn hình (translateX(-100%)), chỉ trượt vào khi có class "sidebar-open" trên
   <body> (bật/tắt bởi initMobileSidebar(), public/app.js, khi bấm nút hamburger/lớp phủ nền/phím
   Esc). .sidebar đổi sang position:fixed nên KHÔNG còn chiếm chỗ trong hàng flex của .app-shell -
   .main (flex:1) tự động giãn hết chiều rộng màn hình, không cần đổi .app-shell sang cột dọc nữa. */
@media (max-width: 900px) {
  .upload-grid { grid-template-columns: 1fr; }

  .menu-toggle {
    display: inline-flex; flex-direction: column; justify-content: center; align-items: center;
    gap: 4px; width: 34px; height: 34px; flex: none; margin: -6px 0;
    border: none; background: none; padding: 0; border-radius: 7px; cursor: pointer;
  }
  .menu-toggle:hover { background: #eef0f4; }
  .menu-toggle span { display: block; width: 19px; height: 2px; border-radius: 2px; background: var(--text); }

  .sidebar {
    position: fixed; top: 0; left: 0; height: 100%; width: 82vw; max-width: 300px;
    transform: translateX(-100%); transition: transform .22s ease; z-index: 71;
    box-shadow: 10px 0 28px rgba(15,17,30,0.28);
  }
  body.sidebar-open .sidebar { transform: translateX(0); }

  .sidebar-backdrop {
    display: block; position: fixed; inset: 0; background: rgba(15,17,30,0.45);
    opacity: 0; pointer-events: none; transition: opacity .2s ease; z-index: 70;
  }
  body.sidebar-open .sidebar-backdrop { opacity: 1; pointer-events: auto; }

  /* Khoá cuộn trang chính trong lúc menu đang mở, tránh cuộn "xuyên" qua lớp phủ nền. */
  body.sidebar-open { overflow: hidden; }

  .topbar { padding: 14px 16px; }
  .topbar h1 { font-size: 16.5px; }
  .content { padding: 16px 16px 48px; }
}

/* bản 72: Bộ lọc dạng "drawer" trượt từ phải (Phương án B - Amont duyệt qua mockup) - trang Đơn
   hàng TikTok Shop + Shopee. Xem lib/render.js's filterDrawerShell()/serverSearchAndPageSizeFieldsExternal()/
   filterDrawerOpenButton() cho markup, public/app.js's initFilterDrawers() cho JS mở/đóng. */
.filters-toolbar { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 6px; }
.drawer-overlay {
  position: fixed; inset: 0; background: rgba(20,22,40,0.35); opacity: 0; pointer-events: none;
  transition: opacity .2s ease; z-index: 40;
}
.drawer-overlay.open { opacity: 1; pointer-events: auto; }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: 340px; max-width: 90vw;
  background: var(--panel); box-shadow: -8px 0 24px rgba(20,22,40,0.16);
  transform: translateX(100%); transition: transform .22s ease; z-index: 41;
  display: flex; flex-direction: column;
}
.drawer.open { transform: translateX(0); }
.drawer-head {
  display: flex; align-items: center; justify-content: space-between; padding: 14px 18px;
  border-bottom: 1px solid var(--border); flex: none;
}
.drawer-head strong { font-size: 14.5px; }
.drawer-close { background: none; border: none; font-size: 16px; line-height: 1; color: var(--text-muted); cursor: pointer; padding: 4px 6px; border-radius: 6px; }
.drawer-close:hover { color: var(--text); background: #f0f1f5; }
.drawer-body { padding: 16px 18px; overflow-y: auto; flex: 1; display: flex; flex-direction: column; gap: 14px; }
.drawer-body .field { width: 100%; }
.drawer-body .checkbox-group { max-width: none; }
.drawer-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 14px 18px; border-top: 1px solid var(--border); flex: none;
}
