/* Truyện Nói — giao diện rewrite (React PWA). Mobile-first, tối giản, dễ đọc. */
:root {
  --bg: #0f1220;
  --bg-soft: #171b2e;
  --card: #1c2138;
  --card-2: #232a47;
  --line: #2b3357;
  --text: #e8eaf2;
  --muted: #9aa3c4;
  --brand: #5b8def;
  --brand-2: #8b5cf6;
  --free: #34d399;
  --paid: #fbbf24;
  --danger: #f87171;
  --radius: 16px;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  background: radial-gradient(1200px 600px at 50% -10%, #1a1f38 0%, var(--bg) 60%);
  color: var(--text);
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}
.wrap { width: 100%; max-width: 960px; margin: 0 auto; padding: 0 16px; }
.boot { text-align: center; padding: 48px 16px; color: var(--muted); }
.boot-error { max-width: 32rem; margin: 72px auto; padding: 24px; text-align: center; color: var(--text); }
.boot-error h1 { font-size: 1.25rem; }
.boot-error button { margin-top: 12px; padding: 10px 16px; border: 0; border-radius: 8px; background: var(--brand); color: #fff; font: inherit; }
.boot.error { color: var(--danger); }

/* =========================================================================
 * HEADER — BỐ CỤC "MẪU 4" (việc #031722, sếp chọn qua Telegram 01/08/2026)
 * Điều hướng nằm ở RAIL DỌC bên trái, chia 3 nhóm Khám phá / Của tôi / Quản trị;
 * thanh trên cùng chỉ còn ô tìm kiếm (kiểu mẫu 2) + chuông + tài khoản.
 * Khổ hẹp (< 900px): rail ẩn, bấm ☰ thì trượt ra dạng drawer phủ lên nội dung.
 *
 * Viết theo lối mobile-first như phần còn lại của file: mặc định = khổ hẹp,
 * `@media (min-width: 900px)` mới bật cột dọc. Mốc 900px chọn theo bề ngang thật:
 * rail 232px + cột nội dung 960px cần ~1200px mới thoải mái, nhưng từ 900px trở lên
 * rail vẫn còn chỗ mà không bóp nội dung quá hẹp.
 * ========================================================================= */
/* App iOS (vỏ Capacitor, ios.contentInset=never — #011606): WebView vẽ tràn dưới tai thỏ/Dynamic Island,
   web tự chừa vùng an toàn bằng env(). Trình duyệt thường env() = 0 nên không đổi gì. */
.app {
  min-height: 100vh;
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
  padding-bottom: env(safe-area-inset-bottom);
}
.rail-main { min-width: 0; }

.site-header {
  position: sticky; top: 0; z-index: 10;
  background: rgba(15, 18, 32, 0.9);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
  padding-top: env(safe-area-inset-top);
}
/* Khổ hẹp: hàng 1 = logo + chuông/tài khoản, hàng 2 = ☰ + ô tìm kiếm CHUNG 1 hàng.
   (#222037, sếp duyệt qua Telegram 02/08: dời ☰ xuống chung hàng với ô tìm thay vì nằm ở
   hàng 1 với logo — CHỈ đổi vị trí bằng `order`/dòng ngắt ảo, không đổi DOM/hành vi.) */
.header-inner { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding-top: 8px; padding-bottom: 8px; }
.brand { font-weight: 800; font-size: 20px; text-decoration: none; color: var(--text); display: inline-flex; align-items: center; gap: 6px; }
.brand span { background: linear-gradient(90deg, var(--brand), var(--brand-2)); -webkit-background-clip: text; background-clip: text; color: transparent; }
.header-brand { order: 1; }
.header-right { display: flex; align-items: center; gap: 8px; margin-left: auto; order: 2; }
/* Dòng ngắt ảo (#222037): pseudo-element rỗng làm flex item order:3, ép 2 phần tử order 4/5
   (☰ + ô tìm) xuống hàng riêng mà KHÔNG cần thêm div bọc nào trong App.js. Vô hiệu ở ≥900px
   (xem media query dưới) vì khổ đó ☰ đã ẩn hẳn, rail dọc thay hẳn vai trò điều hướng. */
.header-inner::after { content: ''; order: 3; flex-basis: 100%; }
.nav-burger {
  order: 4;
  flex: none; cursor: pointer; border: 1px solid var(--line); background: var(--bg-soft); color: var(--text);
  font-size: 18px; line-height: 1; padding: 7px 11px; border-radius: 10px; font-family: inherit;
}
.nav-burger:hover { border-color: var(--brand); }

/* Rail dọc — dùng chung cho cột cố định (máy tính) và drawer (khổ hẹp) */
.site-rail {
  display: none; background: #12162a; border-right: 1px solid var(--line);
  padding: max(16px, env(safe-area-inset-top)) 12px max(16px, env(safe-area-inset-bottom));
}
.rail-brand { font-size: 18px; padding: 0 8px 14px; }
.rail-nav { display: flex; flex-direction: column; gap: 2px; }
.rail-group { font-size: 10.5px; letter-spacing: 1px; color: #6d76a0; font-weight: 800; padding: 14px 8px 5px; }
.rail-link {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 10px; border-radius: 10px; font-size: 14px; font-weight: 600;
  color: var(--muted); text-decoration: none;
}
.rail-link:hover { color: var(--text); background: var(--bg-soft); }
.rail-btn { border: 0; cursor: pointer; background: transparent; font-family: inherit; }
.rail-active {
  color: #fff;
  background: linear-gradient(90deg, rgba(91, 141, 239, .22), rgba(139, 92, 246, .18));
  box-shadow: inset 0 0 0 1px rgba(91, 141, 239, .35);
}

/* #134631: lối vào widget Trợ năng trong menu ☰ — CHỈ khổ hẹp (<900px, cùng mốc bật ☰) và
   CHỈ khi spot-fix-init.js đã khởi tạo widget xong (lớp `tro-nang-san` trên <html>). Khổ máy
   tính vẫn dùng nút nổi ✎ như cũ nên mục này ẩn hẳn ở đó. Chấm đỏ "có câu trả lời mới" của
   nút nổi (đã ẩn ở điện thoại) chuyển sang nút ☰ + mục menu qua lớp `tro-nang-co-tin`. */
.rail-tro-nang { display: none; }
.tro-nang-cham {
  display: none; flex: none; margin-left: auto;
  width: 9px; height: 9px; border-radius: 50%; background: #ff3b30;
}
@media (max-width: 899px) {
  .tro-nang-san div.rail-tro-nang { display: block; }
  .tro-nang-san button.rail-tro-nang { display: flex; }
  .tro-nang-co-tin .tro-nang-cham { display: inline-block; }
  .nav-burger { position: relative; }
  .tro-nang-co-tin .nav-burger::after {
    content: ''; position: absolute; top: -3px; right: -3px;
    width: 10px; height: 10px; border-radius: 50%; background: #ff3b30;
    border: 2px solid var(--bg);
  }
}

/* Khổ hẹp + đang mở ☰: chính khối rail đó biến thành drawer phủ LÊN nội dung (position: fixed)
   — không đẩy bố cục, không gây cuộn ngang. */
.rail-scrim { position: fixed; inset: 0; z-index: 40; background: rgba(4, 6, 14, .6); }
.site-rail.rail-open {
  display: block; position: fixed; top: 0; left: 0; bottom: 0; z-index: 41;
  width: 264px; max-width: 84vw; overflow-y: auto;
  box-shadow: 24px 0 60px rgba(0, 0, 0, .55);
}

/* Ô tìm kiếm trên header — kiểu dáng lấy theo "mẫu 2" (#031722). order:5 = đứng sau ☰ (order:4)
   trên cùng hàng 2 ở khổ hẹp (#222037); flex:1 1 auto để lấp hết phần còn lại của hàng đó. */
.hsearch {
  order: 5; flex: 1 1 auto;
  display: flex; align-items: center; gap: 8px;
  background: var(--bg-soft); border: 1px solid var(--line); border-radius: 12px; padding: 0 12px;
}
.hsearch:focus-within { border-color: var(--brand); }
.hsearch-icon { flex: none; font-size: 14px; line-height: 1; }
.hsearch-input {
  flex: 1; min-width: 0; border: 0; background: transparent; color: var(--text);
  font-family: inherit; font-size: 16px; /* 16px: iOS không tự phóng to khi chạm ô nhập */
  padding: 9px 0;
}
.hsearch-input:focus { outline: none; }
.hsearch-input::placeholder { color: var(--muted); }
/* Bảng kết quả neo vào `.header-inner` (xem BẢN VÁ #024508 phía dưới) để không bao giờ
   trải ngược ra ngoài mép màn hình khi thanh header xuống dòng. */
.hsearch-panel {
  position: absolute; top: calc(100% + 8px); left: 16px; z-index: 30;
  width: 520px; max-width: calc(100% - 32px); /* 16px = padding của `.wrap` → mép panel thẳng cột nội dung */
  background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 6px;
  box-shadow: 0 18px 40px rgba(0, 0, 0, .45);
  max-height: 70vh; overflow-y: auto;
}
.hsearch-empty { color: var(--muted); text-align: center; padding: 14px; margin: 0; font-size: 14px; }
.hsearch-item {
  width: 100%; display: flex; align-items: center; gap: 10px; text-align: left; cursor: pointer;
  background: transparent; border: none; color: var(--text); padding: 10px; border-radius: 8px;
}
.hsearch-item:hover { background: var(--bg-soft); }
.hsearch-cover { font-size: 22px; flex: none; }
.hsearch-text { display: flex; flex-direction: column; flex: 1; min-width: 0; font-size: 13px; }
.hsearch-text b { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hsearch-author { color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hsearch-item .area-tag { flex: none; font-size: 11px; }

@media (min-width: 900px) {
  .app { display: flex; align-items: flex-start; }
  .rail-main { flex: 1; }
  /* Rail dính theo màn hình: menu dài vẫn cuộn được riêng, không kéo theo nội dung.
     Kể cả khi state drawer còn đang mở (vừa xoay ngang / kéo rộng cửa sổ) thì ở khổ này
     rail phải quay về cột dọc bình thường, không được kẹt ở dạng drawer phủ màn hình. */
  .site-rail, .site-rail.rail-open {
    display: block; flex: none; position: sticky; top: 0; left: auto; bottom: auto;
    width: 232px; max-width: none; height: 100vh; overflow-y: auto; box-shadow: none; z-index: auto;
  }
  .rail-scrim { display: none; }
  .nav-burger, .header-brand { display: none; }
  .header-inner { flex-wrap: nowrap; height: 60px; padding-top: 0; padding-bottom: 0; }
  .header-inner::after { content: none; } /* #222037: bỏ dòng ngắt ảo — rail dọc đã thay ☰ */
  .hsearch { order: 0; flex: 1 1 auto; max-width: 420px; }
}

.main { padding: 24px 16px 64px; }
.site-footer { border-top: 1px solid var(--line); color: var(--muted); font-size: 13px; padding: 20px 0 40px; text-align: center; }

.section-title { font-size: 20px; margin: 8px 0 16px; }
.section-sub { color: var(--muted); margin: -8px 0 20px; }
.loading, .error { text-align: center; color: var(--muted); padding: 32px 0; }
.error { color: var(--danger); }
/* #162353: khối lỗi tải dữ liệu dùng chung (ui.js LoiTaiDuLieu) — câu dễ hiểu + nút "Thử lại". */
.load-error { display: flex; flex-direction: column; align-items: center; padding-bottom: 24px; }
.load-error .error { padding-bottom: 12px; }

/* Danh sách (US-1) */
.reco { margin-bottom: 32px; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; }
.card {
  text-align: left; cursor: pointer; color: var(--text);
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 16px; display: flex; flex-direction: column; gap: 6px; transition: transform .12s, border-color .12s;
}
.card:hover { transform: translateY(-3px); border-color: var(--brand); }
.card-top { display: flex; align-items: center; justify-content: space-between; }
.cover { font-size: 34px; line-height: 1; }
/* US-80 (AC-80.4): ảnh bìa thật trong card danh sách — kích thước gần đúng chỗ emoji cũ chiếm
   (font-size 34px), không phá layout .card-top (flex hàng ngang với badge). */
.cover-img { width: 44px; height: 44px; border-radius: 10px; object-fit: cover; flex: none; display: block; }
.badge { font-size: 12px; font-weight: 700; padding: 4px 10px; border-radius: 999px; }
.badge-free { background: rgba(52, 211, 153, .15); color: var(--free); }
.badge-paid { background: rgba(251, 191, 36, .15); color: var(--paid); }
/* #213045: badge báo truyện có Nghe (TTS tự động) ngay ở card/trang chi tiết — trước đây phải
   mở hẳn 1 chương mới thấy trình phát audio (ChapterAudioPlayer.js). */
.badge-tts { background: rgba(129, 140, 248, .18); color: var(--brand, #818cf8); }
/* US-55 (AC-55.2/AC-55.4): nhãn tác phẩm tham khảo nội bộ — chỉ Admin mới thấy.
   Cho phép xuống dòng + tự co chữ để đọc trọn vẹn cả trên di động lẫn desktop, không tràn
   ra ngoài thẻ và không che nội dung khác. */
.badge-reference {
  background: rgba(129, 140, 248, .18); color: #c7d2fe; border: 1px solid rgba(129, 140, 248, .5);
  white-space: normal; overflow-wrap: anywhere; line-height: 1.35; text-align: left; max-width: 100%;
}
.card-top .badge-reference { flex: 0 1 auto; margin-left: 8px; }
.badge-reference-full { display: inline-block; }
/* #115101 (US-63): khối "Sắp ra mắt" trong trang Truyện chữ.
   Thẻ dùng lại .card cho đồng bộ giao diện, nhưng .card mặc định là thẻ BẤM ĐƯỢC (con trỏ tay,
   nhấc lên khi rê chuột) — truyện CHƯA xuất bản thì bấm vào không có gì để mở, nên phải trả
   con trỏ/hiệu ứng về trạng thái tĩnh, tránh hứa hẹn thao tác không tồn tại. */
.upcoming { margin-bottom: 32px; }
.upcoming-card { cursor: default; }
.upcoming-card:hover { transform: none; border-color: var(--line); }
.upcoming-card.upcoming-open { cursor: pointer; }
.upcoming-card.upcoming-open:hover { transform: translateY(-3px); border-color: var(--brand); }
.upcoming-card .card-desc { display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
.upcoming-card .card-meta { gap: 8px; flex-wrap: wrap; }
.badge-upcoming { background: rgba(91, 141, 239, .18); color: #b9ccff; border: 1px solid rgba(91, 141, 239, .5); }
/* #171708 (US-66): khu vực duyệt truyện ngay trên thẻ "Sắp ra mắt". CHỈ Admin mới có DOM này —
   khối được dựng theo dữ liệu `/api/admin/story-approvals`, không phải ẩn/hiện bằng CSS (khách
   thường xem mã nguồn trang cũng không thấy gì). Viền tím = cùng ngôn ngữ với .admin-mode-bar. */
.upcoming-admin-bar {
  background: rgba(129, 140, 248, .12); border: 1px solid rgba(129, 140, 248, .4);
  border-radius: 12px; padding: 12px 14px; margin-bottom: 14px; display: grid; gap: 10px;
}
.upcoming-admin-notice { margin: 0; font-size: 13px; line-height: 1.5; color: #c7f9d9; }
.upcoming-admin {
  margin-top: 12px; padding-top: 12px; border-top: 1px dashed rgba(129, 140, 248, .5);
  display: grid; gap: 8px; cursor: default;
}
.upcoming-admin-head { margin: 0; font-size: 12px; font-weight: 700; color: #c7d2fe; }
.upcoming-admin-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.upcoming-admin-box {
  background: var(--bg-soft); border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 12px; display: grid; gap: 8px; font-size: 13px; line-height: 1.5;
}
.upcoming-admin-hint { color: var(--muted); font-size: 12px; line-height: 1.5; margin: 0; }
.upcoming-admin-error {
  margin: 0; padding: 8px 10px; border-radius: 10px; font-size: 13px; line-height: 1.5;
  background: rgba(248, 113, 113, .12); color: var(--danger);
}
.upcoming-admin-note {
  background: var(--card); border: 1px solid var(--line); border-radius: 10px; color: var(--text);
  padding: 8px 10px; font: inherit; font-size: 14px; resize: vertical;
}
.upcoming-admin-text {
  background: var(--bg-soft); border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 12px; margin: 0; max-height: 320px; overflow: auto; font-size: 13px; line-height: 1.6;
}
/* US-55: dải báo "đang ở chế độ Admin" — để Admin không phải đoán vì sao mình thấy thêm nội dung. */
.admin-mode-bar {
  background: rgba(129, 140, 248, .16); border-bottom: 1px solid rgba(129, 140, 248, .45);
  color: #dbe1ff; font-size: 13px; line-height: 1.5; padding: 8px 0;
}
.admin-mode-bar a { color: #c7d2fe; }
.admin-reference { max-width: 960px; }
.admin-reference h1 { margin-top: 0; }
.admin-reference-warning { background: rgba(251, 191, 36, .12); border: 1px solid rgba(251, 191, 36, .32); color: #fde68a; border-radius: 10px; padding: 10px 12px; line-height: 1.5; }
/* #173440: cột lưới minmax(0, 1fr) + ngắt chữ dài (đường dẫn trong "Thể loại") — trước đây 1 dòng
   thể loại chứa URL dài kéo cả lưới rộng 397px, trang #/thu-vien-tai-ve ở 390px rộng 413px. */
.reference-list { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
.reference-item, .reference-content { background: var(--bg-soft); border: 1px solid var(--line); border-radius: 12px; padding: 14px; }
.reference-item h2, .reference-content h2 { font-size: 16px; margin: 0 0 8px; overflow-wrap: anywhere; }
.reference-item p { color: var(--muted); font-size: 14px; line-height: 1.5; overflow-wrap: anywhere; }
.reference-item p b { color: var(--text); }
.reference-item a { color: #c7d2fe; overflow-wrap: anywhere; }
.reference-files { margin-top: 12px; }
.reference-file-buttons { display: flex; flex-wrap: wrap; gap: 8px; }
.reference-content { margin-top: 18px; }
.reference-content pre { white-space: pre-wrap; overflow-wrap: anywhere; max-height: 60vh; overflow: auto; margin: 0; color: var(--text); font: 14px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace; }
.read-aloud { margin: 12px 0 16px; padding: 14px; border: 1px solid rgba(91, 141, 239, .45); border-radius: 12px; background: rgba(91, 141, 239, .08); }
.read-aloud h3 { margin: 0 0 6px; font-size: 16px; }
.read-aloud-actions { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0; }
.read-aloud-seek { display: flex; flex-direction: column; gap: 6px; color: var(--muted); font-size: 14px; }
.read-aloud-seek input { width: 100%; accent-color: var(--brand); }
.read-aloud-progress, .read-aloud-unavailable { margin: 8px 0 0; color: var(--muted); font-size: 14px; }
.downloaded-detail-listen { margin: 16px 0; }
.downloaded-library { max-width: 960px; }
.downloaded-library h1 { margin-top: 0; }
.library-count { color: var(--free); font-weight: 700; margin: 0 0 16px; }
.public-reference { background: var(--card); }
.public-reference-content { background: var(--card); }
.public-reference-content h1 { font-size: 19px; overflow-wrap: anywhere; }
.public-reference-content pre { max-height: none; font-family: Georgia, "Times New Roman", serif; font-size: 17px; line-height: 1.85; }
.downloaded-library-promo { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 0 0 24px; padding: 18px; border: 1px solid rgba(91, 141, 239, .65); border-radius: var(--radius); background: linear-gradient(120deg, rgba(91, 141, 239, .18), rgba(139, 92, 246, .16)); }
.downloaded-library-promo h2 { margin: 0 0 5px; font-size: 19px; }
.downloaded-library-promo p { margin: 0; color: #d6dcf5; line-height: 1.5; }
.card-title { font-size: 17px; margin: 4px 0 0; }
.card-author { color: var(--muted); font-size: 13px; margin: 0; }
.card-desc { color: #c4cbe6; font-size: 13px; margin: 4px 0 0; line-height: 1.45; }
.card-price { margin: 8px 0 0; font-weight: 700; color: var(--paid); }
.card-price.free { color: var(--free); }

/* Nút */
.btn { cursor: pointer; border: 1px solid var(--line); background: var(--card-2); color: var(--text); padding: 10px 16px; border-radius: 12px; font-weight: 700; font-size: 14px; }
.btn:hover { border-color: var(--brand); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn-primary { background: linear-gradient(90deg, var(--brand), var(--brand-2)); border: none; color: #fff; }
.btn-secondary { background: var(--card-2); }
.btn-back { background: transparent; margin-bottom: 16px; }

/* Chi tiết */
.detail { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 20px; }
.detail-head { display: flex; align-items: center; gap: 16px; }
.detail-cover { font-size: 48px; }
.detail-title { margin: 0; font-size: 22px; }
.detail-author { margin: 4px 0 0; color: var(--muted); }
/* US-225934-01/#132201: tên giọng đọc, ngay dưới tác giả */
.detail-narrator { margin: 2px 0 0; color: var(--muted); font-size: 14px; }
.detail-desc { color: #c4cbe6; line-height: 1.6; margin: 16px 0; }
/* US-225934-02/#132201: thẻ thể loại */
.badge-genre { background: rgba(139, 92, 246, .16); color: #ddd6fe; border: 1px solid rgba(139, 92, 246, .45); }

/* #170710: đầu trang chi tiết tác phẩm On Audio (WorkDetail.js) theo ảnh mẫu 2 sếp gửi — lớp
   riêng, KHÔNG dùng chung .detail-title/.detail-cover (StoryDetail.js/ComicDetail.js vẫn cần
   giữ nguyên bố cục cũ của các trang đó). */
.detail-topbar { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.detail-title-top { flex: 1; margin: 0; font-size: 20px; }
.icon-btn-plain {
  flex: none; width: 36px; height: 36px; border-radius: 50%; border: none; background: transparent;
  color: var(--text); font-size: 18px; cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.icon-btn-plain:hover { background: var(--card-2); }
/* #134854 (Spot Fix): nút "Báo nội dung" đầu trang chi tiết (StoryDetail.js/WorkDetail.js) — thay
   icon ⚠️ vàng không nhãn. Chữ + màu trung tính (--muted/--line), KHÔNG dùng vàng/đỏ cảnh báo;
   nowrap để tiêu đề dài xuống dòng chứ không bóp méo nút ở khổ 390px. */
.detail-report-btn {
  flex: none; min-height: 32px; padding: 4px 10px; border-radius: 999px;
  border: 1px solid var(--line); background: transparent; color: var(--muted);
  font-size: 13px; line-height: 1.2; white-space: nowrap; cursor: pointer;
}
/* Hover chỉ cho thiết bị có chuột — trên điện thoại hover "dính" lại sau khi chạm. */
@media (hover: hover) {
  .detail-report-btn:hover { background: var(--card-2); color: var(--text); }
}
/* #182341/US-79 (AC-79.4): nền phẳng var(--card-2) → gradient tối phía sau emoji, bớt cảm giác
   "khung rỗng" trong lúc chưa có ảnh bìa thật (US-80 Phần A, cơ chế ảnh thật riêng). */
.detail-cover-box {
  flex: none; width: 120px; height: 120px; border-radius: 14px;
  background: radial-gradient(120% 120% at 30% 15%, rgba(91, 141, 239, .35) 0%, rgba(35, 42, 71, .9) 45%, rgba(15, 18, 32, .95) 100%);
  border: 1px solid var(--line); display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.detail-cover-box .detail-cover { font-size: 64px; }
/* US-80 (AC-80.4): tác phẩm có ảnh bìa thật → phủ kín khung, giữ đúng kích thước/bo góc cũ. */
.detail-cover-box .detail-cover-img { width: 100%; height: 100%; object-fit: cover; }
.detail-info { flex: 1; min-width: 0; }
.detail-meta-line { margin: 4px 0; color: var(--muted); font-size: 14px; line-height: 1.5; }
.detail-summary-box {
  margin: 16px 0; padding: 12px 14px; border: 1px solid var(--line); border-radius: 12px;
  background: var(--bg-soft); color: #c4cbe6; line-height: 1.6; font-size: 14px;
}

/* Player + điều khiển (US-2/5/6/8/9) */
/* #182341/US-79 (AC-79.1): nền phẳng cũ → nền tối mờ ảo có chiều sâu như ảnh mẫu sếp gửi. Chưa
   có kho ảnh bìa thật cho mọi tác phẩm nên dùng gradient tối cố định (không phụ thuộc ảnh/emoji
   từng tác phẩm) thay vì blur ảnh — vẫn tạo cảm giác có hậu cảnh/chiều sâu sau icon/transport. */
.player {
  display: flex; flex-direction: column; gap: 16px;
  padding: 18px; border-radius: 20px;
  background:
    radial-gradient(120% 140% at 50% -20%, rgba(91, 141, 239, .22) 0%, rgba(15, 18, 32, 0) 60%),
    linear-gradient(180deg, rgba(20, 24, 42, .92) 0%, rgba(11, 13, 24, .96) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04), 0 20px 40px rgba(0, 0, 0, .35);
}
/* US-80 (AC-80.5): tác phẩm ĐÃ có ảnh bìa thật → dùng chính ảnh đó làm nguồn blur thay cho
   gradient cố định ở trên (gradient vẫn là nền .player, chỉ bị lớp ảnh mờ này phủ lên trên khi
   có). Chưa có ảnh vẫn giữ nguyên gradient AC-79.1 cũ, không đổi gì. */
.player-has-cover { position: relative; overflow: hidden; }
.player-cover-bg {
  position: absolute; inset: -20px; z-index: 0;
  background-size: cover; background-position: center;
  filter: blur(30px) brightness(.45) saturate(1.15);
  transform: scale(1.1);
}
/* Đưa mọi nội dung THẬT của Player lên trên lớp ảnh mờ (xem giải thích thứ tự vẽ CSS ở
   Player.js) — position:relative không đổi layout flex hiện có, chỉ đổi thứ tự vẽ. */
.player-has-cover > *:not(.player-cover-bg) { position: relative; z-index: 1; }
.audio { width: 100%; margin-top: 8px; }
/* #155821: audio nguồn phát ẩn của Player.js — chỉ dùng UI tuỳ chỉnh, không hiện controls gốc.
   display:none KHÔNG dùng ở đây (một số engine mobile tạm dừng phát audio display:none). */
.audio-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
.resume-note { margin: 0; color: var(--free); font-size: 14px; background: rgba(52,211,153,.1); padding: 8px 12px; border-radius: 10px; }
.control-row { display: flex; flex-direction: column; gap: 8px; padding-top: 12px; border-top: 1px dashed var(--line); }
.control-label { font-weight: 700; font-size: 14px; color: var(--muted); }
.speed-group, .voice-group, .sleep-group, .sleep-active, .offline-box { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.chip { cursor: pointer; border: 1px solid var(--line); background: var(--bg-soft); color: var(--text); padding: 7px 14px; border-radius: 999px; font-weight: 600; font-size: 14px; }
.chip:hover { border-color: var(--brand); }
.chip-active { background: linear-gradient(90deg, var(--brand), var(--brand-2)); border-color: transparent; color: #fff; }
.chip:disabled { opacity: .4; cursor: not-allowed; }
.chip:disabled:hover { border-color: var(--line); }
/* #105618: nút -/+ đổi tốc độ phát, nhãn giá trị giữ chiều rộng cố định để không nhảy layout
   khi giá trị đổi từ 1 sang 2 chữ số nguyên (vd 0,95x -> 4,00x). */
.speed-value { min-width: 60px; text-align: center; font-weight: 700; font-size: 14px; }
.sleep-countdown { font-weight: 700; color: var(--paid); }
.offline-ok { color: var(--free); font-weight: 700; }
.offline-err { color: var(--danger); font-size: 13px; }
.control-hint { color: var(--muted); font-size: 13px; }
.dl-progress { display: flex; align-items: center; gap: 10px; width: 100%; }
.dl-bar { flex: 1; height: 8px; background: var(--bg-soft); border-radius: 999px; overflow: hidden; }
.dl-fill { height: 100%; background: linear-gradient(90deg, var(--brand), var(--brand-2)); transition: width .15s; }

/* #185758: icon SVG chuyên nghiệp (Icon.js, họ Material Symbols/MUI) thay emoji trong icon-circle/
   play-big/skip-circle — kích thước ăn theo font-size của khung cha (như emoji cũ), màu ăn theo
   color kế thừa (var(--text) mặc định). */
.ui-icon { width: 1em; height: 1em; display: block; }
/* #024252/US-82: tách fill theo spec.type (Icon.js) — trước đây rule chung fill:currentColor đè
   fill="none" của icon outline, khiến outline hiện đặc/liền khối thay vì rỗng-ruột-viền-mảnh. */
.ui-icon--filled { fill: currentColor; }
.ui-icon--outline { fill: none; }

/* #170710: hàng icon trên cùng (VIP/Tải truyện/Bình luận/Yêu thích/Hẹn giờ/Cài đặt) theo ảnh
   mẫu sếp gửi — icon tròn viền mảnh + nhãn dưới, bấm được dù chức năng chưa làm xong thật
   (xem showNotice() trong Player.js). */
.icon-row { display: flex; justify-content: space-between; gap: 6px; flex-wrap: wrap; }
.icon-btn {
  display: flex; flex-direction: column; align-items: center; gap: 6px; flex: 1 1 0; min-width: 64px;
  background: transparent; border: none; color: var(--text); cursor: pointer; padding: 4px; font: inherit;
}
/* #182341/US-79 (AC-79.2): viền xám phẳng → viền sáng có glow như ảnh mẫu (icon/nhãn/thứ tự/
   hành vi bấm giữ nguyên, chỉ đổi màu viền + thêm box-shadow lan toả). */
.icon-circle {
  width: 44px; height: 44px; border-radius: 50%; border: 1.5px solid rgba(232, 234, 242, .38);
  display: flex; align-items: center; justify-content: center; font-size: 19px; background: var(--bg-soft);
  box-shadow: 0 0 10px rgba(91, 141, 239, .25);
}
.icon-btn:hover .icon-circle { border-color: var(--brand); box-shadow: 0 0 16px rgba(91, 141, 239, .55); }
.icon-label { font-size: 12px; color: var(--muted); text-align: center; }

/* AC-79.11/79.12 (#001050, khôi phục — bản gốc mất khi đổi bộ icon Kiểu 6 #202128 ghi đè lại
   style .icon-btn mà không giữ lại phần này): Bình luận/Yêu thích/Tải truyện-ở-Reader.js chỉ
   hiện toast "đang phát triển" khi bấm (chưa có tính năng thật) — SVG icon giờ trông y hệt các
   icon đã hoạt động thật nên cần tín hiệu thị giác riêng để khách không kỳ vọng nhầm. Giảm
   opacity icon+nhãn còn ~55% (hover 75%), KHÔNG ẩn/khoá nút (vẫn bấm được, vẫn hiện toast như
   cũ, đúng lệnh sếp "không để nút chết" — Player.js:478-481). Tự tắt khi có dữ liệu/tính năng
   thật (Player.js quyết định gắn/không gắn class này, xem icon-comment/icon-favorite/icon-download). */
.icon-btn-soon { opacity: .55; }
.icon-btn-soon:hover { opacity: .75; }

/* #175422: mobile ≤420px — 6 icon bị bẻ 2 hàng lệch (4+2, không canh giữa) vì min-width 64px
   không đủ chỗ. Thu nhỏ icon/khoảng cách để giữ ĐÚNG 1 hàng ngang như ảnh mẫu gốc (sếp thích
   bố cục gọn của bản desktop), không đụng kích thước desktop ở trên. */
@media (max-width: 420px) {
  .icon-row { flex-wrap: nowrap; gap: 2px; }
  .icon-btn { min-width: 0; flex: 1 1 0; gap: 4px; padding: 2px; }
  .icon-circle { width: 36px; height: 36px; font-size: 16px; }
  .icon-label { font-size: 10px; }
}

/* #191916/AC-79.5: bug #175422 tái xuất hiện ở thẻ Admin hẹp (UpcomingStories.js, `.grid`
   `repeat(auto-fill, minmax(240px, 1fr))` → thẻ chỉ ~260-350px ở bố cục nhiều cột) — bản vá cũ
   ở trên chỉ chặn theo VIEWPORT width nên thẻ hẹp ở viewport rộng (desktop/tablet) vẫn lọt qua,
   icon-row vẫn bẻ 4+2. Dùng container query theo đúng BỀ RỘNG KHUNG CHỨA thật (`.upcoming-card`)
   thay vì viewport, áp cùng 1 kiểu thu nhỏ đã có — hoạt động độc lập, không thay/xoá rule viewport
   ở trên (rule đó vẫn cần cho các nơi khác dùng .icon-row không nằm trong khung hẹp cố định). */
.upcoming-card { container-type: inline-size; container-name: upcoming-card; }
@container upcoming-card (max-width: 420px) {
  .upcoming-card .icon-row { flex-wrap: nowrap; gap: 2px; }
  .upcoming-card .icon-btn { min-width: 0; flex: 1 1 0; gap: 4px; padding: 2px; }
  .upcoming-card .icon-circle { width: 36px; height: 36px; font-size: 16px; }
  .upcoming-card .icon-label { font-size: 10px; }
}
.player-notice {
  margin: 0; text-align: center; font-size: 13px; font-weight: 600; color: var(--text);
  background: var(--card-2); border: 1px solid var(--line); border-radius: 10px; padding: 8px 12px;
}
/* AC-79.22 (#213749): toast trong luồng DOM (giữa .icon-row/.seek-row) đẩy lệch .seek-row/nút
   Play mỗi lần hiện/ẩn. Bọc .icon-row + toast trong .player-notice-anchor (Player.js) và neo toast
   bằng position:absolute NGAY DƯỚI .icon-row (top:100%) thay vì giữa nguyên khối .player — tránh
   toast trùm lên nút Play khi control-row/panel Cài đặt mở làm .player cao hơn. Chỉ che phần
   .seek-row phía dưới (đúng ý AC "nổi trên .icon-row/.seek-row"), không chiếm chỗ trong luồng flex
   nên .seek-row/nút Play không xê dịch. Nội dung/thời gian tự tắt/trigger giữ nguyên. */
.player-notice-anchor { position: relative; }
/* AC-79.23 (#222301): margin-top:16px ở đây chỉ còn là giá trị KHỞI ĐẦU/dự phòng — Player.js đo
   khoảng trống thật giữa đáy khung này và đỉnh nút Play (.play-big) mỗi khi toast đổi kích thước
   (kể cả khi nội dung xuống 2 dòng ở mobile hẹp) và ghi đè margin-top bằng inline style để đáy
   toast không bao giờ vượt đỉnh nút Play. Không xoá quy tắc này — vẫn là giá trị áp dụng trước khi
   JS kịp đo (useLayoutEffect) và là giá trị mặc định khi còn đủ chỗ. */
.player-notice-anchor > .player-notice {
  position: absolute; top: 100%; left: 0; right: 0; margin-top: 16px;
  z-index: 5; box-shadow: 0 10px 26px rgba(0, 0, 0, .4);
}

/* US-79 Phần C (AC-79.6/79.7, lệnh sếp #192057/#192229/#192453) — CHỈ WorkDetail.js, CHỈ mobile
   ≤420px. `.wd-root` là lớp riêng gắn ở WorkDetail.js (không đụng `.detail`/`.detail-head`/
   `.detail-info` dùng chung với StoryDetail.js/ComicDetail.js). AC-79.8/79.9/79.10 (style hoá
   `.icon-circle`/`.play-big`/`.skip-circle`/`.wd-progress-bar` khi Player nhúng gọn trong
   `.wd-root.wd-has-player`) đã SIÊU VIỆT bởi US-81 (#024627): Player ở WorkDetail.js (chế độ
   `work`/nhiều tập) nay LUÔN là màn "Đang phát" toàn màn hình riêng (`.now-playing`, không còn
   nằm trong `.wd-root`) — các rule cũ đó không còn phần tử nào để khớp, đã xoá. AC-79.7 (khối 5
   dòng chữ mô tả ẩn/hiện qua icon "ⓘ") là tính năng RIÊNG của trang WorkDetail, không liên quan
   Player nhúng hay toàn màn hình — vẫn giữ nguyên dưới đây. */
@media (max-width: 420px) {
  .wd-root .detail-head { flex-wrap: wrap; }
  .wd-root .detail-info { display: none; width: 100%; }
  .wd-root .detail-info.wd-info-open { display: block; margin-top: 10px; }
  .wd-root .wd-info-toggle { display: flex; }
}

/* AC-79.7: nút "ⓘ xem thêm thông tin" — mặc định ẩn (chỉ hiện ở mobile qua rule trên). */
.wd-info-toggle { display: none; }
/* AC-79.9: thanh tiến trình mảnh sát đáy vùng Player full-bleed — mặc định ẩn (chỉ hiện ở mobile
   qua rule trên), tái dùng nowSec/durationSec của chính Player.js, không bắt buộc bấm/kéo được. */
.wd-progress-bar {
  display: none; position: absolute; left: 16px; right: 16px; bottom: 8px; height: 3px;
  border-radius: 999px; background: var(--line); overflow: hidden;
}
.wd-progress-fill { height: 100%; background: var(--danger); }
/* AC-79.10: badge tròn nhỏ nền đỏ — mặc định ẩn (chỉ hiện khi có commentCount thật VÀ ở đúng
   .wd-root, xem rule mobile ở trên). */
.icon-badge {
  display: none; align-items: center; justify-content: center;
  position: absolute; top: -4px; right: -4px; min-width: 16px; height: 16px; padding: 0 3px;
  border-radius: 999px; background: var(--danger); color: #fff; font-size: 10px; font-weight: 700;
  line-height: 1;
}

/* US-79 Phần D (AC-79.15→79.19, #192330/#192905): hàng phụ chuyển chương/tập, THÊM MỚI ngay dưới
   `.transport-row` — dùng ở CẢ Reader.js (chương) và WorkDetail.js (tập), không riêng mobile, viền
   mảnh trong suốt đồng nhất `.icon-circle`/`.skip-circle` mới (AC-79.16), KHÔNG thay thế nút tua
   ±15s/Play (Phần E #192453 nhấn mạnh lại: giữ đủ 2 hàng nút tách biệt). */
.chapter-nav-row { display: flex; align-items: center; justify-content: center; gap: 16px; }
.chapter-nav-btn {
  display: flex; align-items: center; gap: 6px; background: transparent;
  border: 1.5px solid rgba(232, 234, 242, .38); border-radius: 999px; color: var(--text);
  padding: 6px 14px; font-size: 13px; font-weight: 600; cursor: pointer;
  box-shadow: 0 0 10px rgba(91, 141, 239, .25);
}
.chapter-nav-btn:hover:not(:disabled) { border-color: var(--brand); box-shadow: 0 0 16px rgba(91, 141, 239, .55); }
.chapter-nav-btn:disabled { opacity: .4; cursor: not-allowed; }
.chapter-nav-btn .ui-icon { width: 18px; height: 18px; }

/* #170710: thanh tua kéo/bấm được, 2 mốc thời gian 2 đầu. */
.seek-row { display: flex; align-items: center; gap: 12px; }
.seek-time { font-variant-numeric: tabular-nums; color: var(--muted); font-weight: 600; font-size: 14px; flex: none; }
.seek-track {
  position: relative; flex: 1; height: 20px; display: flex; align-items: center; cursor: pointer;
  touch-action: none;
}
.seek-track::before {
  content: ''; position: absolute; left: 0; right: 0; height: 4px; border-radius: 999px; background: var(--line);
}
.seek-fill { position: absolute; left: 0; height: 4px; border-radius: 999px; background: var(--danger); pointer-events: none; }
.seek-thumb {
  position: absolute; width: 14px; height: 14px; border-radius: 50%; background: var(--danger);
  transform: translateX(-50%); pointer-events: none; box-shadow: 0 0 0 3px rgba(248,113,113,.25);
}

/* US-225934-08/#132201/#170710: tua lùi/Play lớn/tua tới cùng hàng, nhãn current/total riêng
   dưới hàng nút (thanh tua ở trên đã hiện 2 mốc thời gian đầu/cuối, xem .seek-row). */
.transport-row { display: flex; align-items: center; justify-content: center; gap: 24px; }
/* #182341/US-79 (AC-79.2): nút Play to + glow theo đúng độ sáng ảnh mẫu (viền/quầng sáng quanh
   nút, không đổi kích thước/vị trí/hành vi bấm). */
.play-big {
  width: 64px; height: 64px; border-radius: 50%; font-size: 24px; display: flex; align-items: center;
  justify-content: center; padding: 0; flex: none; box-shadow: 0 0 20px rgba(91, 141, 239, .55);
}
/* #192134: trạng thái loading của nút Play — CHIẾM ĐÚNG vị trí icon Play/Pause (không đổi
   kích thước/vị trí nút), `disabled` (JS) khoá click thật; `is-loading` chỉ lo phần nhìn. Tái
   dùng animation `chapter-audio-spin` đã có sẵn (US-75, xem `.chapter-audio-loading` bên dưới)
   thay vì định nghĩa animation trùng lặp. */
.play-big.is-loading { cursor: not-allowed; opacity: .82; box-shadow: none; }
.play-big .play-spinner {
  width: 0.95em; height: 0.95em; border-radius: 50%; flex: none;
  border: 0.14em solid rgba(255, 255, 255, .4); border-top-color: #fff;
  animation: chapter-audio-spin 0.8s linear infinite;
}
/* #162214 (lần đầu nghe TTS — % THẬT trên nút Play, không phải animation giả): vòng tròn tiến độ
   vẽ bằng conic-gradient đọc biến CSS `--pct` (0-99, JS set qua style, xem Player.js `ttsDisplayPct`
   trong controlsEl) — trắng phủ dần theo chiều kim đồng hồ trên nền mờ, số % ở giữa. KHÔNG dùng
   `disabled` cho trạng thái này (khác `.is-loading`) nên giữ nguyên con trỏ/opacity bình thường,
   chỉ đổi box-shadow nhẹ để phân biệt "đang bận" mà vẫn bấm được (xem `togglePlay`/
   `ttsAutoPlayOnReadyRef` — bấm lúc này ghi Ý ĐỊNH tự phát khi xong, không phải no-op). */
.play-big.is-tts-preparing { box-shadow: 0 0 14px rgba(91, 141, 239, .35); }
.play-progress {
  position: relative; width: 100%; height: 100%; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: conic-gradient(#fff calc(var(--pct, 0) * 1%), rgba(255, 255, 255, .22) 0);
}
.play-progress::before {
  content: ''; position: absolute; inset: 5px; border-radius: 50%; background: var(--brand, #5b8def);
}
.play-progress-pct {
  position: relative; font-size: 12px; font-weight: 700; color: #fff; font-variant-numeric: tabular-nums;
}
.play-progress-pct::after { content: '%'; font-size: 9px; margin-left: 1px; }
/* Chưa có mốc % thật nào (chương 1 đoạn, hoặc chưa kịp có mốc đầu) — vòng quay đều mờ, KHÔNG có số
   (thà không có % còn hơn bịa số), tái dùng animation `chapter-audio-spin` như `.play-spinner`. */
.play-progress-indeterminate {
  background: none; border: 0.14em solid rgba(255, 255, 255, .35); border-top-color: #fff;
  width: 0.95em; height: 0.95em;
  animation: chapter-audio-spin 0.8s linear infinite;
}
.play-progress-indeterminate::before { content: none; }
.skip-circle {
  width: 48px; height: 48px; border-radius: 50%; font-size: 18px; display: flex; align-items: center;
  justify-content: center; padding: 0; flex: none; background: transparent; border: 1.5px solid rgba(232, 234, 242, .38);
  box-shadow: 0 0 10px rgba(91, 141, 239, .25);
}
.skip-circle:hover { border-color: var(--brand); box-shadow: 0 0 16px rgba(91, 141, 239, .55); }
/* AC-79.20 (#214335): nhãn "15s" dưới 2 nút tua ±15s, CHỈ mobile ≤420px — label ở vị trí
   absolute (top:100%, ngoài luồng) nên KHÔNG cộng chiều cao vào .skip-btn-wrap, do đó không đổi
   kích thước/vị trí thật của .skip-circle/.play-big trong .transport-row. Font-size/màu/canh giữa
   lấy đúng theo `.icon-label` ở mobile ≤420px (dòng ~378) để đồng bộ kiểu chữ với nhãn 6 icon hàng
   trên. */
.skip-btn-wrap { position: relative; display: flex; flex: none; }
.skip-label { display: none; }
@media (max-width: 420px) {
  .skip-label {
    display: block; position: absolute; left: 50%; top: 100%; transform: translateX(-50%);
    margin-top: 4px; font-size: 10px; color: var(--muted); text-align: center; white-space: nowrap;
  }
}
.time-label { display: block; text-align: center; font-variant-numeric: tabular-nums; color: var(--muted); font-weight: 600; }
.settings-panel { display: flex; flex-direction: column; gap: 4px; }
.popover { border: 1px solid var(--line); border-radius: 12px; padding: 4px 12px 12px; background: var(--card-2); }

/* US-81 (#024627, AC-81.1→81.15): màn "Đang phát" (Now Playing) TOÀN MÀN HÌNH cho khách nghe thật
   (WorkDetail.js chế độ work/nhiều tập, Reader.js chế độ chương) — khớp mockup Kiểu 6 (Opus,
   phong-ban/ky-thuat/nhan-su/194108-mockup-kieu-6-opus/kieu-6-opus.html). CHỈ áp dụng nhánh Player
   KHÔNG dùng `src` override (Admin UpcomingStories.js/admin.js giữ nguyên `.player` nhúng gọn cũ ở
   trên, xem `if (src)` trong Player.js — "Ngoài phạm vi" US-81 nói rõ mockup mô tả trải nghiệm
   khách, không phải màn Admin). `position: fixed` phủ kín viewport ngay tại vị trí Player được
   mount trong cây DOM — không cần đổi route/state ở WorkDetail.js/Reader.js, trang bên dưới vẫn
   mounted nguyên vẹn phía sau, giữ đủ state khi khách thu nhỏ (xem `.now-playing-minimized`). */
.now-playing {
  position: fixed; inset: 0; z-index: 60;
  display: flex; flex-direction: column; gap: 14px;
  padding: max(14px, env(safe-area-inset-top)) 18px max(14px, env(safe-area-inset-bottom));
  background: #08080a;
  background-image: radial-gradient(900px 600px at 50% -10%, #1a1013 0%, #08080a 60%);
  color: var(--text);
  overflow-y: auto;
}
/* AC-81.1/81.2: mũi tên xuống chỉ THU NHỎ (đưa khách về đúng trang WorkDetail/Reader bên dưới,
   nguyên state) — KHÔNG display:none lên tổ tiên của <audio> (xem chú thích `.audio-hidden`: một
   số engine mobile có thể tạm dừng phát audio khi tổ tiên display:none), chỉ trượt hẳn ra ngoài
   viewport + tắt tương tác/đọc màn hình, audio vẫn phát tiếp bình thường. */
.now-playing-minimized {
  transform: translateY(100%);
  pointer-events: none;
  visibility: hidden;
}

/* AC-81.19 (#034428): lối bấm tối thiểu để mở lại `.now-playing` sau khi Thu nhỏ ở chế độ `work`
   (WorkDetail.js, tác phẩm 1 file) — trước đây trang dưới không có cách nào mở lại Player đang
   phát ngầm. Render ngay trong Player.js (không phải WorkDetail.js/Reader.js) nên chỉ tồn tại khi
   Player đang mounted trên đúng trang đang đứng — KHÔNG phải mini-player nổi toàn app (ngoài
   phạm vi US-81), biến mất khi khách rời hẳn trang (Player unmount).
   US-83 (AC-83.1→83.8, #114425, lệnh sếp trực tiếp): `minimized` nay mặc định `true` lúc mount
   (Player.js:159) nên thanh này là trạng thái MẶC ĐỊNH hiển thị, không còn là lối thoát phụ khi đã
   Thu nhỏ. Theo đó vị trí đổi từ "nổi cố định đáy màn hình" (`position: fixed`) sang "nhúng trong
   luồng DOM bình thường" ngay tại vị trí Player được mount trong cây component (đầu trang chi tiết
   — WorkDetail.js/Reader.js), cuộn theo trang, không che nội dung bên dưới. Quyết định BA: US-83
   THAY THẾ HẲN kiểu định vị cũ, không giữ song song 2 kiểu mini cho cùng 1 luồng. */
/* #171232 (13/08/2026, lệnh sếp trực tiếp qua Telegram, ảnh 20260813-165955-731598338.jpg): mini
   trước đây chỉ 1 dòng tên (`.np-mini-reopen-text`/`-title`/`-hint` cũ) — nay giữ ĐẦY ĐỦ badge
   chương/tên tác phẩm+chương/6 nút chức năng/thanh tua/cụm điều khiển, đổi từ khối flex-row 1 hàng
   sang card flex-column: `.np-mini-head` (hàng bấm-để-mở-lại cũ, giữ nguyên bố cục art/tên/chevron)
   + quickbar/seek-row/np-controls/popover TÁI SỬ DỤNG nguyên class của màn đầy đủ (xem Player.js
   quickbarEl/seekRowEl/controlsEl/settingsPanelEl) — chỉ thu nhỏ kích thước cho vừa khối card hẹp
   hơn full-bleed toàn màn hình, không đổi hành vi/handler. */
.np-mini-reopen {
  display: flex; flex-direction: column; gap: 12px; width: 100%;
  margin: 0 0 16px; padding: 10px 12px 14px; border-radius: 14px; border: 1px solid rgba(255, 255, 255, .1);
  background: rgba(20, 18, 20, .92); backdrop-filter: blur(10px);
  box-shadow: 0 6px 16px rgba(0, 0, 0, .3);
  color: var(--text); font: inherit;
}
.np-mini-head { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; cursor: pointer; }
.np-mini-art {
  flex: none; width: 36px; height: 36px; border-radius: 9px; background-size: cover; background-position: center;
  background-color: rgba(255, 255, 255, .08);
  display: flex; align-items: center; justify-content: center; color: #fff;
}
.np-mini-art .ui-icon { width: 18px; height: 18px; }
.np-mini-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.np-mini-info .np-badge { align-self: flex-start; height: 18px; padding: 0 7px; font-size: 9px; }
.np-mini-title { font-size: 12.5px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.np-mini-subtitle { font-size: 10.5px; font-style: normal; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* US-83 (AC-83.5): trước US-81.19 xoay 180deg (trỏ lên, hợp vị trí đáy màn); nay mini nhúng ở
   đầu trang nên bỏ xoay — chevron trỏ xuống đúng tinh thần "bấm để mở rộng" thông thường. */
.np-mini-reopen-chevron { flex: none; width: 18px; height: 18px; color: var(--muted); }

/* #171232: thu nhỏ khoảng đệm/kích thước nút của quickbar/thanh tua/cụm điều khiển KHI nằm trong
   card mini (hẹp hơn `.now-playing` full-bleed) — chỉ đổi kích thước hiển thị, không đổi class/
   handler nên hành vi giống hệt màn đầy đủ. */
.np-mini-reopen .np-quickbar { gap: 2px; }
.np-mini-reopen .np-qi-label { font-size: 8.5px; }
.np-mini-reopen .seek-row { gap: 8px; }
.np-mini-reopen .np-controls { gap: 10px; }
.np-mini-reopen .play-big { width: 52px; height: 52px; font-size: 20px; }
.np-mini-reopen .skip-circle { width: 40px; height: 40px; font-size: 16px; }
.np-mini-reopen .np-chap-btn .ui-icon { width: 21px; height: 21px; }
/* #162214: dòng "đang chuẩn bị lần đầu" hiện trong card mini hẹp hơn `.now-playing` — chỉnh cỡ chữ
   nhỏ lại cho vừa (giữ nguyên `.chapter-audio-loading` gốc/spinner cho màn đầy đủ). */
.np-mini-reopen .tts-preparing-msg { font-size: 11.5px; }
@media (max-width: 360px) {
  .np-mini-reopen .np-controls { gap: 6px; }
  .np-mini-reopen .play-big { width: 46px; height: 46px; }
  .np-mini-reopen .skip-circle { width: 36px; height: 36px; }
}

.np-topbar { display: flex; align-items: center; justify-content: space-between; flex: none; }
.np-icon-btn {
  width: 38px; height: 38px; border-radius: 50%; border: 0; background: transparent; color: #fff;
  display: flex; align-items: center; justify-content: center; cursor: pointer; flex: none;
}
.np-icon-btn:hover { background: rgba(255, 255, 255, .08); }
.np-icon-btn .ui-icon { width: 22px; height: 22px; }
.np-cap { font-size: 11px; letter-spacing: 1.6px; text-transform: uppercase; color: var(--muted); font-weight: 700; }

/* US-71 (#211030, dev-advance #205343 câu 2): cụm 2 nút phải trong .np-topbar (Car Mode + "..."),
   giữ .np-topbar đúng 3 con flex space-between — không thêm nút thứ 4 rời rạc làm giãn bố cục. */
.np-topbar-actions { display: flex; align-items: center; gap: 4px; }

/* US-71 (#211030, Amendment #204720): UI tối giản Car Mode, lồng trong .now-playing (không phải
   overlay riêng như nhánh cũ app/010657) — mọi class tiền tố np-car-* để không rò rỉ ra màn khác.
   Cảnh báo đặt trong luồng bình thường phía TRÊN cụm nút to (KHÔNG position:absolute — file này đã
   2 lần vá chuyện đè lên nút phát: AC-73.2/AC-79.22, không tạo cái thứ ba). */
.np-car { display: flex; flex-direction: column; align-items: center; gap: 20px; padding: 12px 0 4px; }
.np-car-warning {
  margin: 0; width: 100%; text-align: center; font-size: 14px; font-weight: 600;
  color: var(--paid); background: rgba(251, 191, 36, .12); border-radius: 10px; padding: 10px 14px;
}
.np-car-actions { display: flex; align-items: center; justify-content: center; gap: 28px; }
/* Vùng chạm >=44x44px (AC bàn phím/trình đọc màn hình) — nút to hơn skip-circle/play-big thường
   vì Car Mode ưu tiên nhìn liếc khi di chuyển. */
.np-car-btn {
  width: 64px; height: 64px; min-width: 44px; min-height: 44px; border-radius: 50%; font-size: 24px;
  display: flex; align-items: center; justify-content: center; padding: 0; flex: none;
}
.np-car-btn-play { width: 84px; height: 84px; font-size: 32px; box-shadow: 0 0 20px rgba(91, 141, 239, .55); }
.np-car-note { margin: 0; color: var(--free); font-size: 14px; background: rgba(52, 211, 153, .1); padding: 8px 12px; border-radius: 10px; text-align: center; }
.np-car-exit {
  cursor: pointer; border: 1px solid var(--line); background: transparent; color: var(--muted);
  padding: 10px 20px; min-height: 44px; border-radius: 12px; font-weight: 700; font-size: 14px;
  display: flex; align-items: center; justify-content: center;
}
.np-car-exit:hover { border-color: var(--brand); color: var(--text); }

/* AC-81.4/81.6: ảnh bìa full-bleed — nền gradient mặc định (giống `.player` cũ) làm fallback khi
   chưa có coverImage (US-80); có coverImage thì Player.js ghi đè background-image qua inline
   style, phủ lên gradient. AC-81.5: badge chương + tiêu đề đè lên đáy ảnh qua `.np-scrim`. */
.np-cover {
  position: relative; flex: none; width: 100%; aspect-ratio: 5 / 4; max-height: 46vh;
  border-radius: 22px; overflow: hidden; background-size: cover; background-position: center;
  background-color: transparent;
  background-image:
    radial-gradient(120% 140% at 50% -20%, rgba(91, 141, 239, .22) 0%, rgba(15, 18, 32, 0) 60%),
    linear-gradient(180deg, rgba(20, 24, 42, .92) 0%, rgba(11, 13, 24, .96) 100%);
  box-shadow: 0 22px 44px rgba(0, 0, 0, .45);
}
.np-scrim {
  position: absolute; left: 0; right: 0; bottom: 0; height: 62%;
  background: linear-gradient(to top, rgba(6, 6, 8, .94) 6%, rgba(6, 6, 8, .72) 34%, rgba(6, 6, 8, 0) 100%);
}
.np-meta { position: absolute; left: 18px; right: 18px; bottom: 16px; }
.np-badge {
  display: inline-flex; align-items: center; gap: 6px; height: 24px; padding: 0 10px;
  border-radius: 999px; background: rgba(248, 113, 113, .16); border: 1px solid rgba(248, 113, 113, .42);
  color: #ffb4b4; font-size: 10.5px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase;
}
.np-badge-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--danger); box-shadow: 0 0 8px var(--danger); }
.np-title { margin: 10px 0 4px; font-size: 24px; line-height: 1.2; font-weight: 800; letter-spacing: -.3px; text-shadow: 0 2px 18px rgba(0, 0, 0, .6); }
.np-subtitle { margin: 0; font-size: 12.5px; color: #c9c3c0; font-weight: 500; }

/* AC-81.7→81.10: hàng 6 icon tiện ích có nhãn chữ (Đăng ký/Tải truyện/Bình luận/Yêu thích/Hẹn
   giờ/Cài đặt) — lớp riêng `.np-*`, KHÔNG đụng `.icon-row`/`.icon-btn`/`.icon-circle` dùng chung
   với UpcomingStories.js (Admin, xem `.upcoming-card .icon-row`). */
/* #162353: `minmax(0, 1fr)` thay cho `1fr` — cột `1fr` không co nhỏ hơn nhãn chữ (nowrap) nên
   6 cột luôn đòi ≥282px; ở khổ ≤375px card mini hẹp hơn thế → hàng nút tràn khỏi card, và ở
   ≤320px đẩy cả trang #/work/<id>, #/story/<id>/c/<chương> giãn ngang 332px. */
.np-quickbar { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 4px; flex: none; }
.np-qi {
  background: none; border: 0; padding: 4px; cursor: pointer; color: var(--muted);
  display: flex; flex-direction: column; align-items: center; gap: 6px; font: inherit;
  min-width: 0;
}
/* #162353: điện thoại hẹp hơn 390px — bỏ đệm ngang của từng nút để 6 nhãn vừa 1 hàng (360/375px);
   dưới 370px (294/320/360px) xếp 2 hàng × 3 nút, CẢ card mini lẫn màn "Đang phát" toàn màn hình —
   đo thật: 360px card mini ô chỉ còn 42px, nhãn "Tải truyện" vẫn lố 1px; toàn màn hình 294/320px
   nhãn 9.5px lố sang ô bên. 2 hàng cho nút to hơn, dễ chạm hơn là ép 6 nút. */
@media (max-width: 389px) {
  .np-qi { padding: 4px 0; }
}
@media (max-width: 369px) {
  .np-quickbar { grid-template-columns: repeat(3, minmax(0, 1fr)); row-gap: 10px; }
}
.np-qi-box { position: relative; width: 26px; height: 26px; display: flex; align-items: center; justify-content: center; }
.np-qi-box .ui-icon { width: 22px; height: 22px; }
.np-qi-label { font-size: 9.5px; font-weight: 600; color: var(--muted); white-space: nowrap; }
.np-qi:hover { color: #fff; }
.np-qi:hover .np-qi-label { color: var(--text); }
/* AC-79.11/79.12 (giữ nguyên): tín hiệu thị giác riêng cho icon chưa có chức năng thật. */
.np-qi-soon { opacity: .55; }
.np-qi-soon:hover { opacity: .75; }
/* AC-81.18: nhãn chữ luôn hiển thị (kể cả chạm tay di động) báo icon Bình luận/Yêu thích chưa
   hoạt động — `title` tooltip không hiện khi chạm tay nên không đủ, cần thêm nhãn thấy được. */
.np-qi-soon-tag {
  margin-top: -2px; font-size: 8px; font-weight: 700; color: var(--paid); letter-spacing: .1px;
  white-space: nowrap; line-height: 1;
}
/* #134508 (góp ý Spot Fix 275dcc83, máy tính): nhãn 6 nút trình nghe 8.5–9.5px quá nhỏ trên màn
   rộng — nâng cỡ chữ từ 720px trở lên (mỗi ô quickbar lúc đó ≥ ~90px, đủ chỗ cho "Tải truyện").
   Điện thoại giữ nguyên kích thước cũ (6 ô trên 1 hàng ở 390px đã sát chỗ, xem #175422). */
@media (min-width: 720px) {
  .np-qi-label,
  .np-mini-reopen .np-qi-label { font-size: 12.5px; }
  .np-qi-soon-tag { font-size: 10.5px; }
}
.np-qi-badge {
  position: absolute; top: -5px; right: -9px; min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: 9px; background: var(--danger); color: #fff; font-size: 9.5px; font-weight: 800;
  line-height: 16px; text-align: center; box-shadow: 0 0 0 2.5px #08080a;
}
/* AC-81.8/81.9: popover Tải truyện/Hẹn giờ tách khỏi Cài đặt — tái dùng `.popover` nền/viền sẵn
   có, chỉ bỏ margin-top mặc định (không cần cách xa quickbar như toast .player-notice). */
.np-popover { margin: 0 0 4px; }

/* Bảng trồi từ đáy (BottomSheet.js) cho Cài đặt / Hẹn giờ / Tải truyện của trình nghe — giống bảng "Thêm"
   của OSS: nền tối mờ, bảng bo góc trên trồi lên, không đẩy nội dung trang xuống. */
.bottom-sheet-bg {
  position: fixed; inset: 0; z-index: 80; background: rgba(0, 0, 0, .45);
  animation: bottom-sheet-fade .18s ease-out;
}
.bottom-sheet {
  position: absolute; left: 0; right: 0; bottom: 0; max-height: calc(100% - env(safe-area-inset-top, 0px) - 44px);
  display: flex; flex-direction: column;
  background: var(--card); border-top: 1px solid var(--line); border-radius: 18px 18px 0 0;
  box-shadow: 0 -14px 34px rgba(0, 0, 0, .5); color: var(--text);
  animation: bottom-sheet-up .26s cubic-bezier(.2, .8, .2, 1);
}
.bottom-sheet-grabber { flex: none; width: 40px; height: 5px; border-radius: 5px; background: var(--line); margin: 8px auto 2px; }
.bottom-sheet-drag { flex: none; touch-action: none; cursor: grab; }
.bottom-sheet-head { flex: none; display: flex; align-items: center; justify-content: space-between; padding: 2px 8px 4px 18px; }
.bottom-sheet-title { font-size: 15px; font-weight: 700; }
.bottom-sheet-body {
  flex: 0 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch; padding: 0 18px max(18px, env(safe-area-inset-bottom));
}
@keyframes bottom-sheet-up { from { transform: translateY(100%); } to { transform: none; } }
@keyframes bottom-sheet-fade { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .bottom-sheet, .bottom-sheet-bg { animation: none; } }
/* Hẹn giờ/Tải truyện: tiêu đề bảng đã ghi tên — ẩn nhãn trùng ở dòng đầu bên trong. */
.np-sheet-panel:not(.settings-panel) > .control-row:first-child > .control-label { display: none; }

/* AC-81.12/81.13/81.14: gộp Chương trước/Tua lùi/Play/Tua tới/Chương sau vào 1 hàng. */
.np-controls { display: flex; align-items: center; justify-content: center; gap: 14px; flex: none; }
.np-chap-btn {
  background: transparent; border: 0; color: var(--text); cursor: pointer; padding: 8px;
  display: flex; align-items: center; justify-content: center; flex: none;
}
.np-chap-btn .ui-icon { width: 25px; height: 25px; }
.np-chap-btn:disabled { opacity: .35; cursor: not-allowed; }
.np-play { box-shadow: 0 10px 26px rgba(248, 113, 113, .42), inset 0 1px 0 rgba(255, 255, 255, .28); }

/* AC-81.15: thanh thông tin dưới cùng — tốc độ / tên+thời lượng còn lại / danh sách. */
.np-bottombar { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex: none; margin-top: auto; }
.np-pill {
  height: 32px; padding: 0 13px; border-radius: 16px; border: 1px solid var(--line);
  background: rgba(255, 255, 255, .04); color: var(--text); font-size: 11.5px; font-weight: 700;
  letter-spacing: .2px; display: flex; align-items: center; gap: 6px; cursor: pointer; flex: none;
}
.np-pill:hover { border-color: var(--brand); background: rgba(255, 255, 255, .09); }
.np-pill-icon .ui-icon { width: 17px; height: 17px; }
.np-now { text-align: center; flex: 1; min-width: 0; padding: 0 8px; }
.np-now b { display: block; font-size: 11.5px; font-weight: 700; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.np-now i { display: block; font-style: normal; font-size: 9.5px; color: var(--muted); margin-top: 2px; }
/* #161210 (Kiểm thử #155155): nút nổi Trợ năng ✎ (#spot-fix-launcher, widget dùng chung — con trực
   tiếp của <body>, 52x52, fixed right:24px bottom:24px khi innerWidth > 820, xem positionStyleFor()
   trong spot-fix.js) đè ĐÚNG nút danh sách chương [np-list] ở góc phải thanh đáy: đo thật 1440x900
   np-list @1377,854 45x32, elementFromPoint tại tâm nút trả về ✎. Chừa chỗ ở PHÍA APP, không đụng
   widget dùng chung 4 mảng: 66px = 24 (lề widget) + 52 (nút) + 8 (khe) − 18 (padding .now-playing).
   Bù y hệt 66px sau nút tốc độ để .np-now (flex:1) vẫn căn giữa thẳng cụm nút phát. Ngưỡng 821px
   khớp ngưỡng "hẹp" của widget (<=820 thì ✎ nâng lên bottom 100px, không đè thanh đáy). `:has()`
   để chỉ chừa chỗ khi ✎ đang HIỆN: widget không nạp được (offline/chặn mạng) hoặc ✎ bị ẩn
   (setLauncherVisible(false) đặt style display:none — spot-fix-init.js #134631 ẩn ở < 900px) thì
   bố cục giữ nguyên như cũ. */
@media (min-width: 821px) {
  body:has(> #spot-fix-launcher:not([style*="display: none"])) .np-bottombar > .np-pill:first-child,
  body:has(> #spot-fix-launcher:not([style*="display: none"])) .np-bottombar > .np-pill:last-child { margin-right: 66px; }
}

/* US-73 (AC-73.1/73.2/73.6/73.7): panel/sheet trượt lên mở nhanh Đánh giá & Bình luận ngay trong
   Player — nhúng bên trong .now-playing (position:fixed sẵn, xem trên) nên chỉ cần position:
   absolute + inset ngang/dưới; "top" gán inline qua JS (Player.js đo đáy .np-controls bằng
   getBoundingClientRect, KHÔNG đoán % cố định) để đảm bảo KHÔNG BAO GIỜ đè lên cụm nút điều khiển
   phát (Play/Pause, tua ±15s, Chương trước/sau) ở bất kỳ khổ màn hình nào — cụm nút đó vẫn nằm
   trong luồng DOM phía trên sheet, luôn nhìn thấy và bấm được nguyên vẹn. */
.np-comments-sheet {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 65;
  display: flex; flex-direction: column;
  background: rgba(14, 13, 16, .97); backdrop-filter: blur(14px);
  border-top: 1px solid rgba(255, 255, 255, .12);
  border-radius: 20px 20px 0 0;
  box-shadow: 0 -14px 34px rgba(0, 0, 0, .5);
}
.np-comments-sheet-head {
  display: flex; align-items: center; justify-content: space-between; flex: none;
  padding: 12px 8px 12px 18px; border-bottom: 1px solid rgba(255, 255, 255, .08);
}
.np-comments-sheet-title { font-size: 14px; font-weight: 700; color: var(--text); }
/* AC-73.7: cuộn riêng bên trong sheet (không cuộn cả .now-playing), không tràn ngang trên di
   động — .reviews/.review-form/.review-text bên dưới đã có white-space/box-sizing chuẩn sẵn. */
.np-comments-sheet-body {
  flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch;
  padding: 4px 18px max(18px, env(safe-area-inset-bottom));
}
/* Sheet đã tự có nền/viền/bo góc riêng — bỏ padding/nền/viền mặc định của .panel để không lồng 2
   lớp khung, giữ nguyên phần markup/logic .reviews dùng chung với StoryDetail.js. */
.np-comments-sheet-body .reviews { margin: 0; padding: 0; border: 0; background: none; }
/* #205912: `.np-comments-sheet-head` ở trên đã có tiêu đề "Đánh giá & Bình luận" — ẩn tiêu đề `h3`
   lặp lại bên trong (ReviewsPanel.js dùng chung với StoryDetail.js, nơi KHÔNG có head riêng nên vẫn
   cần title) để đỡ tốn thêm ~44px chiều cao vốn đã chật trong panel mở nhanh của Player. */
.np-comments-sheet-body .reviews .section-title { display: none; }

/* US-225934-03/US-225934-07/#132201: danh sách tập */
.episode-summary { display: flex; gap: 10px; flex-wrap: wrap; color: var(--muted); font-weight: 700; margin-bottom: 10px; }
.episode-items { list-style: none; margin: 0 0 16px; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.episode-item {
  width: 100%; display: flex; align-items: center; gap: 12px; text-align: left; cursor: pointer;
  border: 1px solid var(--line); background: var(--bg-soft); color: var(--text); border-radius: 12px;
  padding: 10px 12px; font: inherit;
}
.episode-item:hover:not(:disabled) { border-color: var(--brand); }
.episode-item-active { border-color: var(--brand); background: rgba(91, 141, 239, .12); }
.episode-item-locked { opacity: .6; cursor: not-allowed; }
.episode-thumb { font-size: 26px; flex: none; width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; background: rgba(255,255,255,.04); border-radius: 10px; }
.episode-info { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.episode-title { font-weight: 700; }
.episode-meta { display: flex; gap: 10px; flex-wrap: wrap; font-size: 13px; color: var(--muted); }

/* Khoá trả phí (US-3) */
.lock-box { text-align: center; padding: 28px 16px; background: var(--bg-soft); border: 1px dashed var(--line); border-radius: var(--radius); margin-top: 12px; }
.lock-icon { font-size: 44px; }
.lock-title { font-weight: 800; font-size: 18px; margin: 8px 0; }
.lock-text { color: var(--muted); max-width: 460px; margin: 0 auto 12px; line-height: 1.5; }
.lock-price { font-size: 22px; font-weight: 800; color: var(--paid); margin-bottom: 16px; }
.pay-slot { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.pay-hint { color: var(--muted); font-size: 13px; margin: 0; }

/* Gói hội viên (US-7) */
.plan-notice { background: rgba(139, 92, 246, .15); color: #c4b5fd; border: 1px solid var(--brand-2); padding: 12px 16px; border-radius: 12px; margin-bottom: 16px; font-weight: 700; text-align: center; }
.plan-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; }
.plan-card { position: relative; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 20px; display: flex; flex-direction: column; gap: 12px; }
.plan-highlight { border-color: var(--brand-2); box-shadow: 0 0 0 1px var(--brand-2) inset; }
.plan-tag { position: absolute; top: -10px; right: 16px; background: linear-gradient(90deg, var(--brand), var(--brand-2)); color: #fff; font-size: 12px; font-weight: 700; padding: 3px 10px; border-radius: 999px; }
.plan-name { margin: 0; font-size: 18px; }
.plan-price b { font-size: 24px; } .plan-price span { color: var(--muted); }
.plan-benefits { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 6px; color: #c4cbe6; font-size: 14px; }
.plan-card .btn { margin-top: auto; }

/* =========================================================================
 * MẢNG TRUYỆN CHỮ (US-12 → US-25)
 * ========================================================================= */

.genre-tag { color: var(--brand); font-weight: 600; }
.empty-note { color: var(--muted); text-align: center; padding: 24px 0; }
.panel { margin-bottom: 28px; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 16px 18px; }

.stories-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.card-meta { display: flex; align-items: center; justify-content: space-between; margin-top: 8px; font-size: 13px; color: var(--muted); }
.card-meta .card-price { margin: 0; }

/* US-18: tìm kiếm */
.search-box { margin: 8px 0 20px; }
.search-input {
  width: 100%; padding: 12px 16px; font-size: 15px; color: var(--text);
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
}
.search-input:focus { outline: none; border-color: var(--brand); }

/* US-19: mới cập nhật */
.update-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.update-item { width: 100%; display: flex; align-items: center; gap: 12px; text-align: left; cursor: pointer;
  background: transparent; border: none; color: var(--text); padding: 10px 8px; border-radius: 10px; }
.update-item:hover { background: var(--bg-soft); }
.update-cover { font-size: 26px; }
.update-text { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.update-text b { font-size: 14px; }
.update-chap { color: var(--muted); font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.update-time { color: var(--muted); font-size: 12px; white-space: nowrap; }

/* US-24: xếp hạng */
.rank-list { list-style: none; margin: 0; padding: 0; counter-reset: r; display: flex; flex-direction: column; gap: 4px; }
.rank-item { width: 100%; display: flex; align-items: center; gap: 12px; text-align: left; cursor: pointer;
  background: transparent; border: none; color: var(--text); padding: 8px; border-radius: 10px; }
.rank-item:hover { background: var(--bg-soft); }
.rank-no { width: 26px; height: 26px; flex: none; display: grid; place-items: center; border-radius: 8px;
  background: var(--card-2); font-weight: 800; font-size: 13px; }
.rank-no-1 { background: linear-gradient(135deg, #fbbf24, #f59e0b); color: #1a1a1a; }
.rank-no-2 { background: linear-gradient(135deg, #cbd5e1, #94a3b8); color: #1a1a1a; }
.rank-no-3 { background: linear-gradient(135deg, #d9a066, #b45309); color: #1a1a1a; }
.rank-cover { font-size: 22px; }
.rank-title { flex: 1; font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rank-views { color: var(--muted); font-size: 13px; white-space: nowrap; }

/* Chi tiết truyện: badge + actions */
.detail-badges { display: flex; align-items: center; gap: 10px; margin-top: 8px; flex-wrap: wrap; }
.rating-avg { color: var(--paid); font-weight: 700; font-size: 14px; }
.detail-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-top: 16px; }
/* #135127: hàng nút chính "Đọc từ đầu / Đọc tiếp chương X" + "Nghe" — to, nổi bật, đứng trên
   hàng Theo dõi/Tải offline. Chữ trong nút KHÔNG bẻ dòng: đủ chỗ thì 2 nút cùng hàng (nút Đọc rộng
   hơn), không đủ (vd "Đọc tiếp chương 100" ở 390px) thì nút Nghe xuống hàng riêng, mỗi nút rộng hết khung. */
.detail-cta { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 16px; }
.detail-cta .btn { min-height: 52px; font-size: 16px; border-radius: 14px; padding: 12px 18px; white-space: nowrap; }
.detail-cta-read { flex: 2 1 auto; }
.detail-cta-listen { flex: 1 1 auto; }

/* US-13/US-16: mục lục */
.toc-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 8px; }
.chapter-ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.chapter-row { width: 100%; display: flex; align-items: center; gap: 12px; text-align: left; cursor: pointer;
  background: transparent; border: none; border-top: 1px solid var(--line); color: var(--text); padding: 13px 6px; }
.chapter-ul li:first-child .chapter-row { border-top: none; }
.chapter-row:hover { background: var(--bg-soft); }
.chapter-index { width: 30px; height: 30px; flex: none; display: grid; place-items: center; border-radius: 8px;
  background: var(--card-2); font-weight: 700; font-size: 13px; color: var(--muted); }
.chapter-name { flex: 1; font-size: 15px; min-width: 0; }
.chap-status { font-size: 12px; font-weight: 700; white-space: nowrap; padding: 3px 8px; border-radius: 999px; }
.st-read { color: var(--free); background: rgba(52,211,153,.12); }
.st-reading { color: var(--brand); background: rgba(91,141,239,.14); }
.st-unread { color: var(--muted); }

/* US-88 (#182526): tải audio offline theo từng chương ngay từ mục lục */
.chapter-li { display: flex; align-items: center; gap: 6px; border-top: 1px solid var(--line); }
.chapter-ul li:first-child.chapter-li { border-top: none; }
.chapter-li .chapter-row { flex: 1; width: auto; border-top: none; }
.chap-dl { flex: none; display: flex; align-items: center; gap: 6px; padding-right: 6px; }
.chap-dl-btn { background: transparent; border: 1px solid var(--line); border-radius: 8px; cursor: pointer;
  font-size: 15px; line-height: 1; padding: 6px 8px; color: var(--muted); }
.chap-dl-btn:hover { background: var(--bg-soft); border-color: var(--brand); }
.chap-dl-on { border-color: var(--free); color: var(--free); }
.chap-dl-pct { font-size: 12px; color: var(--brand); font-weight: 700; }
.chap-dl-err { color: var(--danger); font-weight: 700; }
.toc-offline-note { margin: 4px 0 10px; font-size: 13px; color: var(--muted); }
.offline-note { display: block; width: 100%; margin-top: 6px; font-size: 13px; color: var(--muted); }

/* US-21: đánh giá & bình luận */
.review-form { display: flex; flex-direction: column; gap: 10px; margin-bottom: 18px; }
.star-pick { display: flex; gap: 4px; }
.star { background: transparent; border: none; cursor: pointer; font-size: 26px; line-height: 1; color: var(--line); padding: 0; }
.star-on { color: var(--paid); }
.review-name, .review-text {
  width: 100%; padding: 10px 12px; font-size: 14px; color: var(--text);
  background: var(--bg-soft); border: 1px solid var(--line); border-radius: 10px; font-family: inherit;
}
.review-text { min-height: 72px; resize: vertical; }
.review-name:focus, .review-text:focus { outline: none; border-color: var(--brand); }
.review-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.review-item { background: var(--bg-soft); border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; }
.review-item-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.review-stars { color: var(--paid); font-size: 14px; letter-spacing: 1px; }
.review-item-text { margin: 6px 0 0; color: #c4cbe6; font-size: 14px; line-height: 1.5; white-space: pre-wrap; }
/* US-69: xoá/sửa bình luận-đánh giá của chính mình */
.review-item-owner-actions { display: flex; gap: 8px; margin-top: 8px; }
.review-item-editing { display: flex; flex-direction: column; gap: 8px; }
.review-item-actions { display: flex; gap: 8px; }
.review-confirm-box {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 8px;
  padding: 8px 10px; background: rgba(255,255,255,0.04); border: 1px solid var(--line); border-radius: 8px;
  font-size: 13px; color: #c4cbe6;
}

/* =========================================================================
 * TRÌNH ĐỌC (US-14/15/16/20)
 * ========================================================================= */
.reader-topbar { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.reader-topbar .btn-back { margin-bottom: 0; }

.read-settings { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 14px 16px; margin-bottom: 14px; display: flex; flex-direction: column; gap: 12px; }
.rs-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.rs-label { font-weight: 700; font-size: 13px; color: var(--muted); width: 72px; flex: none; }
.rs-group { display: flex; gap: 8px; flex-wrap: wrap; }

/* Vùng đọc — nền/chữ đổi theo US-20 (áp riêng cho khung đọc, không đổi cả app) */
.reader { border-radius: var(--radius); border: 1px solid var(--line); padding: 22px; transition: background .15s, color .15s; }
.reader-head { border-bottom: 1px solid rgba(128,128,128,.25); padding-bottom: 12px; margin-bottom: 16px; }
.reader-story { margin: 0; font-size: 13px; opacity: .7; }
.reader-chapter-title { margin: 6px 0 0; font-size: 20px; }
.chapter-content p { margin: 0 0 1.1em; line-height: 1.85; }
.chapter-content { line-height: 1.85; }
/* #143512: sếp phản ánh nội dung chữ kéo dài cả trang, cuộn hết trang mới đọc tiếp — kiểu Cuộn dọc
   (mode-scroll) nay giới hạn chiều cao khung, cuộn NGAY TRONG khung (kiểu Lật trang giữ nguyên,
   đã có scroll nội bộ riêng qua `.reader-pager`). */
.reader.mode-scroll .chapter-content {
  max-height: 60vh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding-right: 8px;
}

/* #134508 (góp ý Spot Fix 275dcc83): độ rộng dòng (Cài đặt đọc → Độ rộng). Giới hạn đặt trên TỪNG
   đoạn <p> (không phải `.chapter-content`) để khung cuộn + thanh cuộn vẫn nằm sát mép khung đọc,
   chỉ cột chữ thu vào giữa. Đơn vị em theo cỡ chữ của chính đoạn văn → số chữ/dòng giữ nguyên khi
   đổi A-/A/A+. Đo thật ở 1440x900 (font hệ thống, tiếng Việt): Vừa ≈ 70 chữ/dòng, Hẹp ≈ 60.
   Rộng = không giới hạn (như trước #134508). Khung hẹp hơn giới hạn (điện thoại) thì không đổi gì. */
.reader.rw-medium .chapter-content p { max-width: 32em; margin-left: auto; margin-right: auto; }
.reader.rw-narrow .chapter-content p { max-width: 27.5em; margin-left: auto; margin-right: auto; }
/* Điện thoại/khung hẹp: cột chữ vốn đã ngắn (~39 chữ/dòng ở 390px) nên bấm Hẹp/Vừa/Rộng không đổi
   gì — ẩn dòng này đi cho khỏi thành nút "chết". */
@media (max-width: 719px) {
  .rs-row-width { display: none; }
}

/* Cỡ chữ (US-20) */
.reader.fs-small .chapter-content { font-size: 15px; }
.reader.fs-medium .chapter-content { font-size: 17px; }
.reader.fs-large .chapter-content { font-size: 21px; }

/* Màu nền (US-20) */
.reader.theme-light { background: #fbfbf7; color: #1c1c1c; border-color: #e5e5dc; }
.reader.theme-dark { background: #14161f; color: #d6dae6; border-color: #2b3357; }
.reader.theme-sepia { background: #f4ecd8; color: #4a3b28; border-color: #e2d5b8; }

/* Kiểu lật trang (US-20) */
.reader-pager { height: 60vh; overflow: hidden; }

/* US-87 (#152547) "Vừa nghe vừa đọc": tô sáng từ đang đọc. Chỉ đổi màu chữ đang active, không đổi
   layout (không padding/margin riêng) — tránh chữ "nhảy" theo nhịp mỗi lần đổi từ active. */
.tts-word-active {
  background: rgba(255, 213, 79, .55);
  border-radius: 3px;
  transition: background .1s ease-out;
}
.reader.theme-dark .tts-word-active { background: rgba(255, 213, 79, .35); color: #fff; }
/* #171921: audio player hiện THÊM phía trên văn bản cho truyện có TTS (không còn thay thế). US-81
   (#024627): Player ở Reader.js nay là màn "Đang phát" toàn màn hình (`.now-playing`, position:
   fixed, ngoài luồng flex của `.reader`) — hết cần bù margin-bottom giữa Player/văn bản như bản
   nhúng gọn cũ. */
/* US-75: "Đang tải…" khi audio TTS chưa readyState sẵn sàng phát — nhỏ gọn, không dùng .loading
   (dành cho thay cả trang) để không che khuất nhóm nút tốc độ phát bên dưới (AC-75.5). Portage
   từ .chapter-audio-loading cũ lúc gộp #170303 — giữ nguyên tên lớp/data-testid cho kịch bản kiểm
   thử tự động đã có. */
.chapter-audio-loading { display: flex; align-items: center; gap: 8px; margin: 0; font-size: 13px; color: var(--muted); }
.chapter-audio-loading::before {
  content: ''; width: 12px; height: 12px; border-radius: 50%; flex: none;
  border: 2px solid var(--line); border-top-color: var(--muted);
  animation: chapter-audio-spin 0.8s linear infinite;
}
@keyframes chapter-audio-spin { to { transform: rotate(360deg); } }
.page-nav { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 14px; }
.page-indicator { font-weight: 700; font-size: 14px; color: var(--muted); }

/* Điều hướng chương (US-14) */
.chapter-nav { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 18px; }
.nav-spacer { flex: 1; }
.nav-end { color: var(--muted); font-weight: 700; }
/* #171921: dính đáy màn hình khi cuộn — sếp phát hiện nút "Chương sau" ở tít dưới cùng, phải
   cuộn hết chương dài mới thấy. Sticky (không phải fixed) để vẫn nằm trong luồng bố cục, không
   cần padding bù cho nội dung phía trên; tự nhiên dừng dính khi tới cuối trang (không che chân
   trang/nav khác). */
.chapter-nav-sticky {
  position: sticky; bottom: 0; z-index: 5;
  background: rgba(15, 18, 32, 0.92);
  backdrop-filter: blur(8px);
  border-top: 1px solid var(--line);
  padding: 10px 4px;
  margin-left: -4px; margin-right: -4px;
}

/* ===== MẢNG TRUYỆN TRANH (US-29 → US-41) ===== */

/* Thẻ bộ truyện + ảnh bìa (US-29) */
.comic-card { padding-top: 0; overflow: hidden; }
.comic-cover-wrap { position: relative; margin: -14px -14px 10px; background: var(--bg-soft); }
.comic-cover { display: block; width: 100%; aspect-ratio: 2 / 3; object-fit: cover; }
.comic-badge { position: absolute; top: 10px; right: 10px; }
.comic-detail-cover { width: 96px; border-radius: 12px; border: 1px solid var(--line); flex: none; }

/* Bộ lọc thể loại (US-39) */
.genre-filter { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 18px; }

/* Lịch cập nhật truyện tranh (US-53/US-54) */
.comics-head-actions { display: flex; gap: 10px; flex-wrap: wrap; }
/* 8 tab CỐ ĐỊNH: cho tự xuống dòng để màn hình hẹp vẫn thấy + bấm được đủ 8 (AC-53.6),
   không dùng cuộn ngang (tab khuất ngoài mép dễ bị bỏ sót khi thao tác). */
.schedule-tabs { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 14px; }
.tab-today { font-size: 12px; opacity: 0.85; }
.schedule-sort { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 18px; }
.schedule-sort-label { color: var(--muted); font-size: 14px; font-weight: 600; }
.chip-sm { padding: 5px 12px; font-size: 13px; }

/* Ngày phát hành tập trong danh sách tập (US-30) */
.ep-date { display: block; color: var(--muted); font-size: 12px; margin-top: 2px; }

/* Trình đọc cuộn dọc liên tục kiểu webtoon (US-31) */
.comic-reader-head { margin: 4px 0 12px; }
.comic-strip {
  display: flex; flex-direction: column;
  background: #000;
  border-radius: 12px;
  overflow: hidden;
  /* Ảnh phải nối tiếp NHAU LIỀN MẠCH — không khe hở giữa các khung. */
  line-height: 0;
}
.comic-page { display: block; width: 100%; height: auto; }
.comic-end { display: flex; align-items: center; gap: 12px; margin: 18px 0 4px; }
.comic-end-line { flex: 1; height: 1px; background: var(--line); }
.comic-end-text { color: var(--muted); font-weight: 700; font-size: 14px; white-space: nowrap; }
.comic-offline-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }

/* Ủng hộ tác giả — tipping (US-42) */
.comic-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 10px; }
.btn-tip { background: linear-gradient(90deg, #f6b93b, #f7d774); color: #2b2114; font-weight: 800; }
.tip-total { color: var(--muted); font-size: 13px; }
.tip-overlay {
  position: fixed; inset: 0; z-index: 50;
  display: flex; align-items: center; justify-content: center; padding: 20px;
  background: rgba(6, 8, 18, 0.72);
}
.tip-box {
  width: 100%; max-width: 420px;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 22px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}
.tip-title { margin: 0 0 8px; font-size: 19px; }
.tip-sub { margin: 0 0 16px; color: var(--muted); font-size: 14px; line-height: 1.5; }
.tip-amounts { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 18px; }
.tip-amount { font-weight: 700; }
.tip-actions { display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap; }
.comic-actions-end { margin: 16px 0 4px; justify-content: center; }
.tip-thanks { text-align: center; }
.tip-heart { font-size: 52px; line-height: 1; margin-bottom: 8px; }

/* Thẻ thư viện truyện tranh có thêm nút Bỏ theo dõi (US-34) */
.lib-card-wrap { display: flex; flex-direction: column; cursor: default; }
.lib-card-wrap:hover { transform: none; border-color: var(--line); }
.lib-card-open {
  all: unset; display: block; cursor: pointer; box-sizing: border-box;
  margin: 0 -14px; padding: 0 14px;
}
.lib-unfollow { margin-top: 12px; align-self: flex-start; }

@media (max-width: 520px) {
  .grid, .plan-grid { grid-template-columns: 1fr; }
  .stories-head { flex-direction: column; }
  /* AC-53.6: khung di động — tab hẹp lại cho 8 tab xuống dòng gọn, chữ KHÔNG bị cắt/chồng. */
  .schedule-tabs .chip { padding: 7px 11px; font-size: 13px; }
  .schedule-tabs .tab-today { font-size: 11px; }
  .comics-head-actions { width: 100%; }
  .comics-head-actions .btn { flex: 1; }
  .reader { padding: 16px; }
  .reader-pager { height: 64vh; }
  .reader.mode-scroll .chapter-content { max-height: 64vh; }
  /* US-31: khung tranh full chiều ngang màn hình, không cần zoom mới đọc được. */
  .comic-strip { border-radius: 0; margin-left: -16px; margin-right: -16px; }
  .comic-detail-cover { width: 72px; }
}

/* =========================================================================
 * TÀI KHOẢN KHÁCH HÀNG (US-43 → US-48) — mobile-first, khu tài khoản ở góc header.
 * ======================================================================= */
.acc-guest { display: flex; gap: 6px; align-items: center; }
.btn-mini {
  cursor: pointer; border: 1px solid var(--line); background: var(--bg-soft); color: var(--text);
  padding: 7px 12px; border-radius: 999px; font-weight: 700; font-size: 13px; white-space: nowrap;
}
.btn-mini:hover { border-color: var(--brand); }
.btn-mini-primary { background: linear-gradient(90deg, var(--brand), var(--brand-2)); border-color: transparent; color: #fff; }

.acc-wrap { position: relative; }
.acc-chip {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer; max-width: 150px;
  border: 1px solid var(--line); background: var(--bg-soft); color: var(--text);
  padding: 5px 12px 5px 5px; border-radius: 999px; font-weight: 700; font-size: 13px;
}
.acc-chip:hover { border-color: var(--brand); }
.acc-avatar {
  width: 26px; height: 26px; flex: none; border-radius: 999px; display: grid; place-items: center;
  background: linear-gradient(135deg, var(--brand), var(--brand-2)); color: #fff; font-size: 13px;
}
.acc-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.acc-menu {
  position: absolute; top: 115%; right: 0; width: 240px; max-width: 85vw; z-index: 30;
  background: var(--card); border: 1px solid var(--line); border-radius: 14px; overflow: hidden;
  box-shadow: 0 18px 40px rgba(0, 0, 0, .45);
}
.acc-menu-email { padding: 10px 14px; font-size: 12px; color: var(--muted); border-bottom: 1px solid var(--line); word-break: break-all; }
.acc-menu-item {
  width: 100%; text-align: left; cursor: pointer; background: transparent; border: none;
  color: var(--text); padding: 12px 14px; font-size: 14px; font-weight: 600;
}
.acc-menu-item:hover { background: var(--bg-soft); }
.acc-menu-logout { color: var(--danger); border-top: 1px solid var(--line); }

/* -------------------------------------------------------------------------
 * BẢN VÁ #024508 — menu thả xuống của 🔔 chuông và avatar bị TRÀN RA NGOÀI MÉP
 * TRÁI màn hình (sếp báo "dropdown bị che", thấy khung tối trống).
 *
 * Nguyên nhân: 2 menu này neo `right: 0` vào CHÍNH CÁI NÚT của nó. Khi `.nav`
 * xuống dòng (nhiều mục, nhất là lúc đang ở chế độ Admin), nút chuông/avatar rơi
 * xuống đầu hàng mới — tức sát MÉP TRÁI — nên menu rộng 240–280px trải ngược về
 * bên trái và lọt ra ngoài màn hình. Đo được: 390px lọt 242px, 768px lọt 32px.
 * KHÔNG phải lỗi z-index, và KHÔNG chỉ xảy ra ở màn hình hẹp (phụ thuộc chỗ
 * xuống dòng), nên không vá bằng media query theo bề ngang.
 *
 * Cách vá: bỏ mốc neo ở từng nút, neo cả 2 menu vào `.header-inner` — khối này
 * luôn trải đúng bề ngang cột nội dung của header ở MỌI khổ màn hình, nên menu
 * luôn nằm gọn bên trong và thả xuống ngay dưới header.
 * ---------------------------------------------------------------------- */
.header-inner { position: relative; }
.acc-wrap { position: static; }
.acc-menu {
  top: calc(100% + 8px); right: 0; left: auto; max-width: calc(100% - 8px);
}

/* Màn đăng nhập / đăng ký */
.auth-wrap { max-width: 420px; margin: 0 auto; }
.auth-tabs { display: flex; gap: 6px; margin-bottom: 16px; }
.auth-tab {
  flex: 1; cursor: pointer; border: 1px solid var(--line); background: var(--bg-soft);
  color: var(--muted); padding: 11px 12px; border-radius: 12px; font-weight: 700; font-size: 14px;
}
.auth-tab-on { background: var(--card-2); color: var(--text); border-color: var(--brand); }
.auth-card { display: flex; flex-direction: column; gap: 12px; }
.auth-title { margin: 0; font-size: 20px; }
.auth-sub { margin: 0; color: var(--muted); font-size: 14px; }
.auth-error { margin: 0; padding: 10px 12px; border-radius: 10px; font-size: 14px; background: rgba(248, 113, 113, .12); color: var(--danger); }
.auth-notice { margin: 0; padding: 10px 12px; border-radius: 10px; font-size: 14px; background: rgba(52, 211, 153, .12); color: var(--free); }
.auth-hint { margin: 0; color: var(--muted); font-size: 13px; line-height: 1.5; }
.field { display: flex; flex-direction: column; gap: 6px; font-size: 13px; color: var(--muted); font-weight: 600; }
.field input {
  background: var(--bg-soft); border: 1px solid var(--line); border-radius: 12px; color: var(--text);
  padding: 12px 14px; font-size: 16px; /* 16px: iOS không tự phóng to khi chạm ô nhập */
}
.field input:focus { outline: none; border-color: var(--brand); }
.auth-submit { margin-top: 4px; padding: 13px 16px; }
.auth-divider { display: flex; align-items: center; gap: 10px; color: var(--muted); font-size: 12px; }
.auth-divider::before, .auth-divider::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.btn-google {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px; text-decoration: none;
  background: #fff; color: #1f2430; border: 1px solid #dadce0; padding: 12px 16px; border-radius: 12px;
  font-weight: 700; font-size: 14px;
}
.btn-google:hover { border-color: #b9bec7; }
.btn-google-off { opacity: .55; cursor: not-allowed; }
.google-icon { flex: none; }

/* Trang Tài khoản của tôi */
.account-card { display: flex; flex-direction: column; gap: 12px; }
.account-row { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; font-size: 14px; }
.account-label { color: var(--muted); font-weight: 600; }
.account-muted { color: var(--muted); font-size: 14px; }
.badge-plan { background: rgba(91, 141, 239, .18); color: var(--brand); }
.account-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 4px; }
.btn-danger { background: rgba(248, 113, 113, .14); border-color: rgba(248, 113, 113, .4); color: var(--danger); }
.genre-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.genre-list li { display: flex; justify-content: space-between; align-items: center; gap: 10px; }
.genre-hits { color: var(--muted); font-size: 13px; }

/* Trang Lịch sử của tôi */
.history-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.history-row {
  width: 100%; display: flex; align-items: center; gap: 12px; text-align: left; cursor: pointer;
  background: var(--card); border: 1px solid var(--line); border-radius: 14px; padding: 12px 14px; color: var(--text);
}
.history-row:hover { border-color: var(--brand); }
.history-cover { font-size: 26px; flex: none; }
.history-main { flex: 1; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.history-title { font-size: 15px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.history-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 12px; }
.area-tag { padding: 3px 8px; border-radius: 999px; font-weight: 700; background: var(--bg-soft); color: var(--muted); }
.area-audio { color: var(--brand); }
.area-story { color: var(--free); }
.area-comic { color: var(--paid); }
.history-progress { color: var(--muted); }
.history-time { color: var(--muted); }

/* Sưu tập của tôi (US-72, việc #142250) */
.btn-sm { padding: 6px 10px; font-size: 12px; }
.collection-create { display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; }
.collection-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.collection-row {
  display: flex; align-items: center; gap: 10px;
  background: var(--card); border: 1px solid var(--line); border-radius: 14px; padding: 10px 14px;
}
.collection-open {
  flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px;
  text-align: left; background: none; border: none; color: var(--text); cursor: pointer; padding: 0;
}
.collection-open:hover .collection-name { color: var(--brand); }
.collection-name { font-size: 15px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.collection-meta { color: var(--muted); font-size: 12px; }
.collection-row-actions { display: flex; gap: 6px; flex: none; }
.collection-edit-input { flex: 1; min-width: 0; }
.collection-item-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.collection-item-row {
  display: flex; align-items: center; gap: 10px;
  background: var(--card); border: 1px solid var(--line); border-radius: 14px; padding: 10px 14px;
}
.collection-item-open {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 12px;
  text-align: left; background: none; border: none; color: var(--text); cursor: pointer; padding: 0;
}
.collection-item-open:hover .history-title { color: var(--brand); }

/* Modal "Thêm vào sưu tập" */
.add-to-collection { margin: 14px 0; }
.modal-overlay {
  position: fixed; inset: 0; background: rgba(0, 0, 0, 0.6);
  display: flex; align-items: center; justify-content: center; padding: 16px; z-index: 60;
}
.modal-box {
  width: 100%; max-width: 420px; max-height: 80vh; overflow-y: auto;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px;
}
.modal-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.modal-head h3 { margin: 0; font-size: 16px; }
.modal-close {
  background: none; border: none; color: var(--muted); font-size: 18px; line-height: 1; cursor: pointer; padding: 4px;
}
.modal-close:hover { color: var(--text); }
.collection-check-list { list-style: none; margin: 0 0 12px; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.collection-check { display: flex; align-items: center; gap: 8px; cursor: pointer; }
.collection-new-form { display: flex; gap: 8px; margin-bottom: 12px; }
.collection-new-form input { flex: 1; min-width: 0; }
.modal-done { width: 100%; }

/* Gói hội viên: trạng thái + hộp xác nhận (US-47) */
.plan-status { margin-bottom: 14px; }
.confirm-box { display: flex; flex-direction: column; gap: 8px; }
.confirm-box p { margin: 0; font-size: 14px; }
.confirm-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 4px; }

@media (max-width: 520px) {
  .acc-name { display: none; } /* màn hình hẹp: chỉ còn chữ cái đầu, chừa chỗ cho nav */
  .acc-chip { max-width: none; padding: 5px; }
  .btn-mini { padding: 7px 10px; font-size: 12px; }
  .downloaded-library-promo { align-items: flex-start; flex-direction: column; }
}

/* =========================================================================
 * US-51 / US-52 — LIÊN KẾT BẢN NGHE ↔ BẢN ĐỌC (việc #030754)
 * Mobile-first: mặc định xếp DỌC (nút trên, mô tả dưới) để nút không bao giờ bị bóp hẹp hay
 * tràn ra ngoài ở khung nhìn di động; từ tablet trở lên mới xếp ngang cho gọn (AC-51.4).
 * ======================================================================= */
.format-switch {
  display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
  margin: 14px 0; padding: 12px 14px;
  border: 1px solid var(--line); border-radius: 12px; background: var(--bg-soft);
}
.format-switch-btn { width: 100%; text-align: center; }
.format-switch-note {
  font-size: 13px; color: var(--muted); line-height: 1.45;
  /* Tên tác phẩm dài không được đẩy vỡ khung ở màn hình hẹp. */
  overflow-wrap: anywhere; min-width: 0;
}
.format-switch-note b { color: var(--text); }

.jump-note {
  margin: 0 0 12px; font-size: 14px; line-height: 1.5;
  color: var(--brand-2); background: rgba(129, 140, 248, .12);
  padding: 8px 12px; border-radius: 10px; overflow-wrap: anywhere;
}

/* Tablet/iPad trở lên: nút + mô tả nằm cùng hàng, nút co theo nội dung. */
@media (min-width: 600px) {
  .format-switch { flex-direction: row; align-items: center; gap: 14px; }
  .format-switch-btn { width: auto; flex: none; }
}
