/* Copyrights Hub — CMS layout riêng, dựa trên tokens.css + components.css của bản giao thiết kế. */
html, body { height: 100%; }
body { overflow: hidden; }
#app { height: 100vh; width: 100vw; }

.ch-shell { display: flex; height: 100vh; width: 100vw; background: var(--bg-page); }
.ch-sidebar { width: var(--sidebar-w-admin); flex: 0 0 var(--sidebar-w-admin); display: flex; flex-direction: column; justify-content: space-between; }
.ch-sidebar__nav { display: flex; flex-direction: column; gap: 2px; overflow-y: auto; flex: 1; }
.ch-sidebar__section { color: var(--cta); font-weight: 700; }
.ch-brand { display: flex; align-items: center; gap: 10px; padding: 4px 8px 18px; }
.ch-brand__mark { width: 30px; height: 30px; color: var(--text-head); flex: 0 0 30px; }
.ch-brand__mark svg { width: 100%; height: 100%; display: block; }
.ch-brand__name { font-family: var(--font-display); font-weight: 700; color: var(--text-head); font-size: var(--text-md); }
.ch-sidebar__footer { display: flex; flex-direction: column; gap: 10px; padding-top: 14px; border-top: 1px solid var(--border); }
.ch-sidebar__user { display: flex; align-items: center; gap: 10px; padding: 4px; }
.ch-avatar { width: 34px; height: 34px; border-radius: 999px; background: var(--bg-tint); color: var(--cta); display: flex; align-items: center; justify-content: center; font-weight: 700; font-family: var(--font-display); }
.ch-sidebar__uname { color: var(--text-head); font-size: var(--text-sm); font-weight: 600; }

.ch-main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.ch-topbar__actions { display: flex; gap: 10px; align-items: center; }
.ch-content { flex: 1; overflow-y: auto; padding: 22px 26px 40px; display: flex; flex-direction: column; gap: 18px; }
/* Bổ sung 2026-09-20: bug flexbox kinh điển — không có dòng này, các thẻ con (.ch-card/
   .ch-table/...) bị CO LẠI (flex-shrink mặc định = 1) để vừa khít .ch-content thay vì được
   phép cao hơn khung rồi cuộn — nội dung dài (vd D06 89 bài, không phân trang) bị ẩn mất phần
   dưới mà KHÔNG có thanh cuộn nào hoạt động. flex-shrink: 0 buộc mỗi thẻ con giữ đúng chiều cao
   tự nhiên của nó, để .ch-content (overflow-y: auto ở trên) cuộn đúng như thiết kế. */
.ch-content > * { flex-shrink: 0; }

/* ---------- Trạng thái ---------- */
.ch-skel-wrap { display: flex; flex-direction: column; gap: 10px; }
.ch-skel { height: 52px; border-radius: 12px; background: var(--bg-elev); animation: ch-pulse 1.2s ease-in-out infinite; }
@keyframes ch-pulse { 0%,100% { opacity: 1; } 50% { opacity: .55; } }
.ch-state-card { align-items: center; text-align: center; padding: 40px 20px; gap: 12px; }
.ch-state-icon { width: 44px; height: 44px; border-radius: 999px; background: var(--bg-elev); display: flex; align-items: center; justify-content: center; color: var(--text-dim); }
.ch-state-icon i { width: 22px; height: 22px; }

/* ---------- Toast ---------- */
.ch-toast-host { position: fixed; right: 22px; bottom: 22px; display: flex; flex-direction: column; gap: 8px; z-index: 999; }
.ch-toast { background: var(--bg-card); border: 1px solid var(--border-strong); color: var(--text-head);
  padding: 12px 16px; border-radius: 10px; font-size: var(--text-md); box-shadow: var(--shadow-lg);
  opacity: 0; transform: translateY(8px); transition: opacity .2s ease-out, transform .2s ease-out; }
.ch-toast--in { opacity: 1; transform: translateY(0); }
.ch-toast--ok { border-color: var(--ok); }
.ch-toast--danger { border-color: var(--danger); }

/* ---------- Mất mạng ---------- */
.ch-offline-bar { background: var(--bg-tint); color: var(--warn); padding: 8px 16px; font-size: var(--text-sm); text-align: center; }

/* ---------- Modal ---------- */
.ch-modal-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,.6); display: flex; align-items: center; justify-content: center; z-index: 1000; }
.ch-modal { background: var(--bg-card); border: 1px solid var(--border-strong); border-radius: var(--r-lg);
  padding: 24px; width: 520px; max-width: 92vw; max-height: 86vh; overflow-y: auto; box-shadow: var(--shadow-lg); }
.ch-modal--wide { width: 920px; }
.ch-modal__title { font-family: var(--font-display); font-weight: 700; color: var(--text-head); font-size: var(--text-xl); margin-bottom: 14px; }
/* CÔNG TẮC ON/OFF kiểu iPhone — chủ dự án 29/10/2026: *"1 cột tính năng, 1 cột có dấu on/off
   màu xanh là bật, chuyển sang off thì không hiển thị màu gì, như trên iphone cho dễ hình
   dung"*. Bảng quyền cũ có 3 cột (Mặc định · Ghi đè · ô chọn 3 lựa chọn) — người đọc phải tự
   ghép "mặc định Có + ghi đè Cấm" mới ra câu trả lời thật, và rất dễ ghép ngược. */
/* 29/10/2026 — thu nhỏ theo yêu cầu chủ dự án ("nút cấp quyền to quá"). 38×22 là cỡ công tắc
   quen mắt trên iOS thu về khổ bảng; núm 16px vẫn đủ to để bấm trúng trên điện thoại (vùng bấm
   thật là cả thẻ <label>, không chỉ cái núm). */
.ch-switch { position: relative; display: inline-block; width: 38px; height: 22px; flex-shrink: 0; }
.ch-switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; z-index: 2; }
.ch-switch__track { position: absolute; inset: 0; border-radius: 999px; background: var(--bg-elev);
  border: 1px solid var(--border); transition: background .2s, border-color .2s; }
.ch-switch__knob { position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%;
  background: var(--text-muted); transition: transform .2s, background .2s; }
.ch-switch input:checked ~ .ch-switch__track { background: var(--ok, #2ecc71); border-color: var(--ok, #2ecc71); }
.ch-switch input:checked ~ .ch-switch__knob { transform: translateX(16px); background: #fff; }
.ch-switch input:disabled { cursor: progress; }
.ch-switch input:disabled ~ .ch-switch__track { opacity: .5; }
.ch-switch input:focus-visible ~ .ch-switch__track { outline: 2px solid var(--cta); outline-offset: 2px; }

/* 🔴 29/10/2026 — `.ch-note` bị DÙNG Ở 20+ CHỖ MÀ CHƯA BAO GIỜ CÓ TRONG CSS.
   Mọi khối "nói rõ hậu quả trước khi bấm" của kho này đều mang lớp đó — kể cả mấy khối cảnh
   báo viết `style="border-color:var(--warn)"`, tức là đặt MÀU cho một cái viền KHÔNG TỒN TẠI
   nên chẳng ai thấy cảnh báo. Thêm đúng một lần ở đây là cả 20+ chỗ cùng hiện. */
.ch-note { background: var(--bg-tint); border: 1px solid var(--border); border-left-width: 3px;
  border-radius: var(--r-sm, 8px); padding: 10px 12px; color: var(--text);
  font-size: var(--text-sm); line-height: 1.55; }
.ch-note b { color: var(--text-head); }
/* Ô nhập TIỀN: căn phải cho dễ soát số, dùng ở hợp đồng đối tác (dt01). */
.ch-tien { text-align: right; font-variant-numeric: tabular-nums; }

/* 🔴 29/10/2026 — chủ dự án: *"dấu X to trên góc trái là gì? nhìn hiển thị như bị lỗi"*.
   `.ch-modal__head`, `.ch-modal__body` và `.ch-icon-btn` được 4 màn dùng (hộp Phân quyền ·
   D08 Chọn bài · D03 chi tiết · Đang phát) nhưng **CHƯA BAO GIỜ CÓ TRONG CSS** — nên trình
   duyệt vẽ nút đóng bằng kiểu mặc định: một ô vuông trắng viền xám to đùng, rơi xuống dòng
   dưới tiêu đề vì cái đầu không hề được đặt flex. Nhìn đúng như hộp thoại bị vỡ.
   Thêm ở đây (không sửa từng màn) để cả 4 chỗ thẳng hàng một lượt. */
.ch-modal__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
  font-family: var(--font-display); font-weight: 700; color: var(--text-head);
  font-size: var(--text-xl); margin-bottom: 14px; }
.ch-modal__body { min-width: 0; }
.ch-icon-btn { flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0; border-radius: var(--r-sm, 8px);
  background: transparent; border: 1px solid var(--border); color: var(--text);
  cursor: pointer; transition: background .15s, color .15s, border-color .15s; }
.ch-icon-btn:hover { background: var(--bg-tint); color: var(--text-head); border-color: var(--border-strong); }
.ch-icon-btn i, .ch-icon-btn svg { width: 16px; height: 16px; }

.ch-modal__actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }

/* ---------- Login ---------- */
.ch-login-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; background: var(--grad-hero); }
.ch-login-card { width: 400px; max-width: 92vw; background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--r-lg); padding: 34px; box-shadow: var(--shadow-lg); }
.ch-login-card__logo { width: 56px; height: 56px; color: var(--text-head); margin-bottom: 18px; filter: drop-shadow(var(--shadow-cta)); }
.ch-login-card__logo svg { width: 100%; height: 100%; display: block; }

/* ---------- Cấu trúc chung ---------- */
.ch-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.ch-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.ch-grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.ch-grid-5 { display: grid; grid-template-columns: repeat(5, 1fr); gap: 16px; }
.ch-stat { display: flex; flex-direction: column; gap: 6px; }
.ch-stat__value { font-family: var(--font-mono); font-size: var(--text-3xl); color: var(--text-head); }
.ch-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.ch-toolbar__left { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ch-search { display: flex; align-items: center; gap: 8px; background: var(--bg-card); border: 1px solid var(--border-strong); border-radius: var(--r-md); padding: 0 12px; height: 40px; min-width: 220px; }
.ch-search input { background: transparent; border: none; outline: none; color: var(--text-head); font-family: var(--font-sans); font-size: var(--text-md); width: 100%; }
.ch-search i { color: var(--text-hint); width: 16px; height: 16px; }

.ch-subtabs { border-radius: var(--r-md); }
.ch-subtabs__item { cursor: pointer; }

/* ---------- Bảng cột theo ngữ cảnh (đặt qua inline style grid-template-columns) ---------- */
.ch-table__head > *, .ch-table__row > * { display: flex; align-items: center; gap: 6px; }
.ch-row-link { cursor: pointer; }
.ch-row-link:hover { background: rgba(255,255,255,0.03); }
.ch-chevron { color: var(--text-dim); margin-left: auto; }

/* Ô nghe thử trong bảng kho nhạc — bổ sung 2026-10-05.
   🔴 `.ch-table__row > *` có `padding: 11px 12px` + `overflow: hidden`, nên một cột 40px chỉ còn
   16px dùng được: nút nghe bị cắt mất, chủ dự án báo "bị che khuất khó nhìn". Ô này phải tự nới
   padding và cho phép tràn. */
.ch-o-nghe { padding: 6px 6px !important; overflow: visible !important; justify-content: center; }
.ch-nut-nghe { width: 30px; height: 30px; padding: 0 !important; display: inline-flex;
  align-items: center; justify-content: center; border-radius: 50%; font-size: 13px; line-height: 1; }
.ch-nut-nghe[data-tt="phat"] { background: var(--accent); color: #1a1208; border-color: var(--accent); }
.ch-nut-nghe[data-tt="loi"] { background: rgba(220,70,70,.18); border-color: rgba(220,70,70,.55); color: #ff9a9a; }

.ch-input--err { border-color: var(--danger) !important; }
.ch-form { display: flex; flex-direction: column; gap: 14px; }
.ch-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }

/* ---------- Wizard D05-01 ---------- */
.ch-steps { display: flex; gap: 8px; }
.ch-step { flex: 1; padding: 10px 12px; border-radius: var(--r-md); background: var(--bg-card); border: 1px solid var(--border); font-size: var(--text-sm); color: var(--text-muted); }
.ch-step--on { border-color: var(--border-brand); color: var(--text-head); background: var(--bg-tint); font-weight: 600; }
.ch-step--done { color: var(--ok); }
.ch-dropzone { border: 1.5px dashed var(--border-strong); border-radius: var(--r-lg); padding: 40px; text-align: center; color: var(--text-muted); cursor: pointer; }
.ch-dropzone:hover { border-color: var(--border-brand); }

/* scroll thanh mảnh */
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 6px; }
::-webkit-scrollbar-track { background: transparent; }

/* ============================================================
   MÀN HẸP / MÀN DỌC — bổ sung 2026-09-24
   Trước đây cả app chỉ có ĐÚNG MỘT luật co giãn: <=1100px thì bóp menu trái còn 64px và
   ẩn hết chữ. Nhưng index.html lại ghim cứng width=1440 nên luật đó KHÔNG BAO GIỜ chạy
   trên điện thoại/máy tính bảng thật — chỉ chạy khi thu nhỏ cửa sổ trên máy tính. Kết quả:
   điện thoại dựng đứng thu nhỏ còn 26%, máy tính bảng dựng đứng bị cắt mất thẻ bên phải
   (xem docs/BIENBAN-soat-giao-dien-3-cap-va-man-doc-20260924.md).

   Nay: bỏ ghim 1440 (index.html) + thay dãy biểu tượng trụi chữ bằng NGĂN KÉO mở bằng nút ☰.

   🔴 BÀI HỌC 22/09 PHẢI GIỮ: TUYỆT ĐỐI KHÔNG ẩn .ch-label ở phạm vi toàn app. .ch-label là
   nhãn của MỌI ô nhập trong cả 9 màn (vd "Mã kết nối máy phát"), không phải chỉ 2 dòng phụ
   đề trong sidebar. Lần trước ẩn nhầm nên khách báo "không thấy mã để ghép máy phát".
   Khối dưới đây KHÔNG ẩn chữ của bất kỳ thứ gì — ngăn kéo hiện đủ chữ như trên máy tính.
   ============================================================ */

/* Nút ☰ và nền mờ: mặc định (máy tính) không hiện, chỉ bật trong các luật màn hẹp bên dưới. */
.ch-burger, .ch-nav-close { display: none; }
.ch-burger, .ch-nav-close {
  align-items: center; justify-content: center;
  width: 42px; height: 42px; flex: 0 0 42px;
  border-radius: var(--r-md); border: 1px solid var(--border-strong);
  background: transparent; color: var(--text-head); cursor: pointer;
}
.ch-burger:hover, .ch-nav-close:hover { background: rgba(255,255,255,0.05); }
.ch-burger:focus-visible, .ch-nav-close:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.ch-nav-backdrop { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.55); z-index: 1099; }
.ch-nav-backdrop--hien { display: block; }
.ch-topbar__left { display: flex; align-items: center; gap: 12px; min-width: 0; }
.ch-topbar__titles { min-width: 0; }
.ch-topbar__titles .ch-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------- <=1100px: máy tính bảng dựng đứng, cửa sổ hẹp ---------- */
@media (max-width: 1100px) {
  .ch-burger { display: inline-flex; }
  .ch-nav-close { display: inline-flex; margin-left: auto; }

  /* Menu trái rời khỏi dòng chảy, trượt ra khi bấm ☰ (không còn bóp còn 64px trụi chữ). */
  .ch-sidebar {
    position: fixed; top: 0; bottom: 0; left: 0; z-index: 1100;
    width: 274px; flex: 0 0 274px;
    transform: translateX(-100%);
    transition: transform .22s ease-out;
    overflow-y: auto;
  }
  .ch-sidebar--mo { transform: translateX(0); box-shadow: var(--shadow-lg); }

  /* Thanh trên: cho phép cao thêm + xuống dòng, thay vì cắt mất nút bên phải. */
  .ch-topbar { height: auto; min-height: var(--topbar-h); flex: 0 0 auto; flex-wrap: wrap; gap: 10px; padding: 10px 16px; }

  .ch-content { padding: 18px 16px 32px; }

  /* Lưới thẻ: 4-5 cột trên máy tính xuống còn 2 cột cho vừa bề ngang. */
  /* minmax(0,...) chứ không phải 1fr: xem ghi chú ở khối <=700px bên dưới. */
  .ch-grid-3, .ch-grid-4, .ch-grid-5 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* Bảng nhiều cột: cho cuộn ngang TRONG TỪNG BẢNG, chứ không đẩy cả trang rộng ra. */
  .ch-table { overflow-x: auto; }
  .ch-table__head, .ch-table__row { min-width: 640px; }

  .ch-toast-host { left: 16px; right: 16px; bottom: 16px; }

  /* 🔴 Hàng ngang dựng bằng inline style `display:flex` (rất nhiều màn dùng: 3 nút Tạm dừng/
     Phát/Bỏ qua ở "Đang phát", ô "Tên bài" + "Ca sĩ" + nút "+ Thêm" ở "Yêu cầu nhạc"...).
     Mặc định `flex-wrap: nowrap` + `min-width: auto` của ô nhập làm cả hàng KHÔNG co lại
     được: đo thật trên máy 375px thấy nút "+ Thêm" nằm ở 452px, tức lòi ra ngoài 77px và bị
     CẮT ÂM THẦM (body có overflow:hidden nên không có thanh cuộn nào báo cho người dùng biết).
     Sửa một luật chung ở đây thay vì vá từng màn — màn viết sau cũng tự đúng. Hàng nào vẫn
     đủ chỗ thì `wrap` không làm gì cả, nên không ảnh hưởng máy tính. */
  .ch-content div[style*="display:flex"] { flex-wrap: wrap; }
  .ch-content .ch-input { min-width: 0; }
}

/* ---------- <=700px: điện thoại dựng đứng ---------- */
@media (max-width: 700px) {
  .ch-sidebar { width: 86vw; flex-basis: 86vw; max-width: 320px; }
  .ch-crumb { display: none; }            /* thanh trên quá chật, bỏ dòng đường dẫn nhỏ */
  .ch-topbar { padding: 10px 12px; }
  .ch-content { padding: 14px 12px 28px; gap: 14px; }

  /* 🔴 minmax(0, 1fr) CHỨ KHÔNG PHẢI 1fr. `1fr` nghĩa là minmax(auto, 1fr), mà `auto` lấy
     min-content làm CẬN DƯỚI — nên chỉ cần một hàng nút không xuống dòng là ô lưới phình to
     hơn màn hình, kéo cả thẻ rộng 378px trên máy 375px. Trang KHÔNG cuộn ngang (body có
     overflow:hidden) nên phần thừa bị CẮT ÂM THẦM, không ai thấy. Đo thật ở màn "Đang phát"
     của tài khoản cấp Khu vực 24/09. minmax(0, 1fr) bỏ cận dưới đó đi. */
  .ch-grid-2, .ch-grid-3, .ch-grid-4, .ch-grid-5 { grid-template-columns: minmax(0, 1fr); }
  .ch-form-row { grid-template-columns: 1fr; }

  .ch-search { min-width: 0; width: 100%; }
  .ch-toolbar, .ch-toolbar__left { width: 100%; }
  .ch-steps { flex-wrap: wrap; }
  .ch-step { flex: 1 1 45%; }
  .ch-dropzone { padding: 24px 14px; }
  .ch-modal { padding: 18px; }
}
